public void consolidatePops() { if (allPopUnits.Count > 14) //get some small pop and merge it into bigger { PopUnit popToMerge = getRandomPop((x) => x.getPopulation() < Options.PopSizeConsolidationLimit); //PopUnit popToMerge = getSmallerPop((x) => x.getPopulation() < Options.PopSizeConsolidationLimit); if (popToMerge != null) { PopUnit targetPop = this.getBiggerPop(x => x.isStateCulture() == popToMerge.isStateCulture() && x.popType == popToMerge.popType && x != popToMerge); if (targetPop != null) { targetPop.mergeIn(popToMerge); } } } }
public static void simulate() { if (haveToStepSimulation) { haveToStepSimulation = false; } Date.Simulate(); if (Game.devMode) { Debug.Log("New date! - " + Date.Today); } // strongly before PrepareForNewTick AllMarkets.PerformAction(x => x.simulatePriceChangeBasingOnLastTurnData()); // rise event on day passed // DayPassed?.Invoke(World.Get, EventArgs.Empty); var @event = DayPassed; if (@event != null) // check for subscribers { @event(World.Get, EventArgs.Empty); //fires event for all subscribers } // should be before PrepareForNewTick cause PrepareForNewTick hires dead workers on factories //calcBattles(); // includes workforce balancing // and sets statistics to zero. Should go after price calculation prepareForNewTick(); // big PRODUCE circle foreach (Country country in World.AllExistingCountries()) { foreach (Province province in country.AllProvinces) { foreach (var producer in province.AllProducers) { producer.produce(); } } } // big CONCUME circle foreach (Country country in World.AllExistingCountries()) { country.consumeNeeds(); if (country.economy == Economy.PlannedEconomy) { //consume in PE order foreach (Factory factory in country.Provinces.AllFactories) { factory.consumeNeeds(); } if (country.Science.IsInvented(Invention.ProfessionalArmy)) { foreach (var item in country.Provinces.AllPops.Where(x => x.Type == PopType.Soldiers)) { item.consumeNeeds(); } } foreach (var item in country.Provinces.AllPops.Where(x => x.Type == PopType.Workers)) { item.consumeNeeds(); } foreach (var item in country.Provinces.AllPops.Where(x => x.Type == PopType.Farmers)) { item.consumeNeeds(); } foreach (var item in country.Provinces.AllPops.Where(x => x.Type == PopType.Tribesmen)) { item.consumeNeeds(); } } else //consume in regular order { foreach (Province province in country.AllProvinces)//Province.allProvinces) { foreach (Factory factory in province.AllFactories) { factory.consumeNeeds(); } foreach (PopUnit pop in province.AllPops) { //That placed here to avoid issues with Aristocrats and Clerics //Otherwise Aristocrats starts to consume BEFORE they get all what they should if (country.serfdom == Serfdom.SerfdomAllowed || country.serfdom == Serfdom.Brutal) { if (pop.shouldPayAristocratTax()) { pop.payTaxToAllAristocrats(); } } } foreach (PopUnit pop in province.AllPops) { pop.consumeNeeds(); } } } } //force DSB recalculation. Helped with precise calculation of DSB & how much money seller should get //AllMarkets.PerformAction(x => ////x.ForceDSBRecalculation() //x.getDemandSupplyBalance(null, true) //); if (Game.logMarket) { //Money res = new Money(0m); //foreach (var product in Product.getAll()) // res.Add(Country.market.getCost(Country.market.getMarketSupply(product, true)).Copy().Multiply((decimal)Country.market.getDemandSupplyBalance(product, false)) // ); //if (!Country.market.moneyIncomeThisTurn.IsEqual(res)) //{ // Debug.Log("Market income: " + Country.market.moneyIncomeThisTurn + " total: " + Country.market.Cash); // Debug.Log("Should pay: " + res); //} } // big AFTER all and get money for sold circle foreach (Country country in World.AllExistingCountries()) { Market.GiveMoneyForSoldProduct(country); foreach (Province province in country.AllProvinces)//Province.allProvinces) { foreach (Factory factory in province.AllFactories) { if (country.economy == Economy.PlannedEconomy) { if (country.isAI() && factory.IsClosed && !factory.isBuilding()) { Rand.Call(() => factory.open(country, false), Options.howOftenCheckForFactoryReopenning); } } else { Market.GiveMoneyForSoldProduct(factory); factory.paySalary(); // workers get gold or food here factory.ChangeSalary(); factory.payDividend(); // also pays taxes inside factory.CloseUnprofitable(); factory.ownership.CalcMarketPrice(); Rand.Call(() => { factory.ownership.SellLowMarginShares(); }, 20); } } province.DestroyAllMarkedfactories(); // get pop's income section: foreach (PopUnit pop in province.AllPops) { if (pop.Type == PopType.Workers) { pop.LearnByWork(); } if (pop.canSellProducts()) { Market.GiveMoneyForSoldProduct(pop); } if (country.Science.IsInvented(Invention.ProfessionalArmy) && country.economy != Economy.PlannedEconomy) // don't need salary with PE { var soldier = pop as Soldiers; if (soldier != null) { soldier.takePayCheck(); } } pop.takeUnemploymentSubsidies(); pop.TakeUBISubsidies(); pop.TakePovertyAid();// should be least //because income come only after consuming, and only after FULL consumption //if (pop.canTrade() && pop.hasToPayGovernmentTaxes()) // POps who can't trade will pay tax BEFORE consumption, not after // Otherwise pops who can't trade avoid tax // pop.Country.TakeIncomeTax(pop, pop.moneyIncomethisTurn, pop.Type.isPoorStrata());//pop.payTaxes(); pop.calcLoyalty(); if (Rand.Chance(Options.PopPopulationChangeChance)) { pop.Growth(); } if (Rand.Chance(Options.PopPopulationChangeChance)) { pop.Promote(); } if (pop.needsFulfilled.isSmallerOrEqual(Options.PopNeedsEscapingLimit)) { if (Rand.Chance(Options.PopPopulationChangeChance)) { pop.ChangeLife(pop.GetAllPossibleDemotions().Where(x => x.Value.isBiggerThan(pop.needsFulfilled, Options.PopNeedsEscapingBarrier)).MaxBy(x => x.Value.get()).Key, Options.PopDemotingSpeed); } } if (Rand.Chance(Options.PopPopulationChangeChance)) { pop.ChangeLife(pop.GetAllPossibleMigrations().Where(x => x.Value.isBiggerThan(pop.needsFulfilled, Options.PopNeedsEscapingBarrier)).MaxBy(x => x.Value.get()).Key, Options.PopMigrationSpeed); } if (Rand.Chance(Options.PopPopulationChangeChance)) { pop.Assimilate(); } } } } //investments circle. Needs to be separate, otherwise cashed investments can conflict foreach (Country country in World.AllExistingCountries()) { foreach (var province in country.AllProvinces) { foreach (var pop in province.AllPops) { if (country.economy != Economy.PlannedEconomy) { Rand.Call(() => pop.invest(), Options.PopInvestRate); } } if (country.isAI()) { country.invest(province); } //if (Rand.random2.Next(3) == 0) // province.consolidatePops(); province.RemoveDeadPops(); foreach (PopUnit pop in PopUnit.PopListToAddToGeneralList) { PopUnit targetToMerge = pop.Province.getSimilarPopUnit(pop); if (targetToMerge == null) { pop.Province.RegisterPop(pop); } else { targetToMerge.mergeIn(pop); } } PopUnit.PopListToAddToGeneralList.Clear(); province.simulate(); province.BalanceEmployableWorkForce(); } country.simulate(); if (country.isAI()) { country.AIThink(); } } }
internal static void simulate() { if (Game.haveToStepSimulation) { Game.haveToStepSimulation = false; } date.AddTick(1); // strongly before PrepareForNewTick Game.market.simulatePriceChangeBasingOnLastTurnData(); // should be before PrepareForNewTick cause PrepareForNewTick hires dead workers on factories Game.calcBattles(); // includes workforce balancing // and sets statistics to zero. Should go after price calculation prepareForNewTick(); // big PRODUCE circle foreach (Country country in Country.getAllExisting()) { foreach (Province province in country.ownedProvinces) { foreach (var producer in province.getAllProducers()) { producer.produce(); } } } // big CONCUME circle foreach (Country country in Country.getAllExisting()) { country.consumeNeeds(); if (country.economy.getValue() == Economy.PlannedEconomy) { //consume in PE order foreach (Factory factory in country.getAllFactories()) { factory.consumeNeeds(); } if (country.Invented(Invention.ProfessionalArmy)) { foreach (var item in country.getAllPopUnits(PopType.Soldiers)) { item.consumeNeeds(); } } foreach (var item in country.getAllPopUnits(PopType.Workers)) { item.consumeNeeds(); } foreach (var item in country.getAllPopUnits(PopType.Farmers)) { item.consumeNeeds(); } foreach (var item in country.getAllPopUnits(PopType.Tribesmen)) { item.consumeNeeds(); } } else //consume in regular order { foreach (Province province in country.ownedProvinces)//Province.allProvinces) { foreach (Factory factory in province.getAllFactories()) { factory.consumeNeeds(); } foreach (PopUnit pop in province.allPopUnits) { //That placed here to avoid issues with Aristocrats and Clerics //Otherwise Aristocrats starts to consume BEFORE they get all what they should if (country.serfdom.getValue() == Serfdom.Allowed || country.serfdom.getValue() == Serfdom.Brutal) { if (pop.shouldPayAristocratTax()) { pop.payTaxToAllAristocrats(); } } } foreach (PopUnit pop in province.allPopUnits) { pop.consumeNeeds(); } } } } // big AFTER all circle foreach (Country country in Country.getAllExisting()) { country.getMoneyForSoldProduct(); foreach (Province province in country.ownedProvinces)//Province.allProvinces) { foreach (Factory factory in province.getAllFactories()) { if (country.economy.getValue() == Economy.PlannedEconomy) { factory.OpenFactoriesPE(); } else { factory.getMoneyForSoldProduct(); factory.ChangeSalary(); factory.paySalary(); // workers get gold or food here factory.payDividend(); // also pays taxes inside factory.CloseUnprofitable(); factory.ownership.CalcMarketPrice(); Rand.Call(() => { factory.ownership.SellLowMarginShares(); }, 20); } } province.DestroyAllMarkedfactories(); // get pop's income section: foreach (PopUnit pop in province.allPopUnits) { if (pop.canSellProducts()) { pop.getMoneyForSoldProduct(); } pop.takeUnemploymentSubsidies(); if (country.Invented(Invention.ProfessionalArmy) && country.economy.getValue() != Economy.PlannedEconomy) // don't need salary with PE { var soldier = pop as Soldiers; if (soldier != null) { soldier.takePayCheck(); } } //because income come only after consuming, and only after FULL consumption //if (pop.canTrade() && pop.hasToPayGovernmentTaxes()) // POps who can't trade will pay tax BEFORE consumption, not after // Otherwise pops who can't trade avoid tax // pop.GetCountry().TakeIncomeTax(pop, pop.moneyIncomethisTurn, pop.popType.isPoorStrata());//pop.payTaxes(); pop.calcLoyalty(); //if (Game.Random.Next(10) == 1) { pop.calcGrowth(); pop.calcPromotions(); if (pop.needsFulfilled.isSmallerThan(Options.PopNeedsEscapingLimit)) { pop.EscapeForBetterLife(x => x.HasJobsFor(pop.popType, province)); } pop.calcAssimilations(); } if (country.economy.getValue() != Economy.PlannedEconomy) { Rand.Call(() => pop.invest(), Options.PopInvestRate); } } if (country.isAI()) { country.invest(province); } //if (Game.random.Next(3) == 0) // province.consolidatePops(); foreach (PopUnit pop in PopUnit.PopListToAddToGeneralList) { PopUnit targetToMerge = pop.GetProvince().getSimilarPopUnit(pop); if (targetToMerge == null) { pop.GetProvince().allPopUnits.Add(pop); } else { targetToMerge.mergeIn(pop); } } province.allPopUnits.RemoveAll(x => !x.isAlive()); PopUnit.PopListToAddToGeneralList.Clear(); province.simulate(); } country.simulate(); if (country.isAI()) { country.AIThink(); } } }