From 1cfbe4c142ebef46375b9832c05319f38f6b364f Mon Sep 17 00:00:00 2001 From: Ilkka Virta Date: Sun, 1 Nov 2020 12:47:33 +0200 Subject: [PATCH] Fix buildings being sold unexpectedly with gold_upkeep_style "Mixed". gold_upkeep_style "Mixed" paid both units and buildings during city processing, instead of only paying units at the end as described in the ruleset file comments. This could lead to the nation going in deficit and selling buildings even with the city and whole nation showing positive surplus. Fix this by collecting the unit upkeeps after each city and only pay them in lump after all cities are done. There should be no visible effect for upkeep styles "City" and "Nation". --- server/cityturn.c | 92 +++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/server/cityturn.c b/server/cityturn.c index 020cbab00a..e4c0f29b7b 100644 --- a/server/cityturn.c +++ b/server/cityturn.c @@ -550,6 +550,8 @@ void update_city_activities(struct player *pplayer) if (n > 0) { struct city *cities[n]; int i = 0, r; + int nation_unit_upkeep = 0; + int nation_impr_upkeep = 0; city_list_iterate(pplayer->cities, pcity) { int ci; @@ -574,39 +576,51 @@ void update_city_activities(struct player *pplayer) cities[i++] = pcity; } city_list_iterate_end; - /* How gold upkeep is handled depends on the setting - * 'game.info.gold_upkeep_style': - * GOLD_UPKEEP_CITY: Each city tries to balance its upkeep individually - * (this is done in update_city_activity()). - * GOLD_UPKEEP_MIXED: Each city tries to balance its upkeep for - * buildings individually; the upkeep for units is - * paid by the nation. - * GOLD_UPKEEP_NATION: The nation as a whole balances the treasury. If - * the treasury is not balance units and buildings - * are sold. */ - /* Iterate over cities in a random order. */ while (i > 0) { r = fc_rand(i); /* update unit upkeep */ city_units_upkeep(cities[r]); update_city_activity(cities[r]); + + /* used based on 'gold_upkeep_style', see below */ + nation_unit_upkeep += city_total_unit_gold_upkeep(cities[r]); + nation_impr_upkeep += city_total_impr_gold_upkeep(cities[r]); + cities[r] = cities[--i]; } - if (pplayer->economic.gold < 0) { - switch (game.info.gold_upkeep_style) { - case GOLD_UPKEEP_CITY: - break; - case GOLD_UPKEEP_MIXED: - /* Nation pays for units. */ + /* How gold upkeep is handled depends on the setting + * 'game.info.gold_upkeep_style': + * GOLD_UPKEEP_CITY: Each city tries to balance its upkeep individually + * (this is done in update_city_activity()). + * GOLD_UPKEEP_MIXED: Each city tries to balance its upkeep for + * buildings individually; the upkeep for units is + * paid by the nation. + * GOLD_UPKEEP_NATION: The nation as a whole balances the treasury. If + * the treasury is not balanced units and buildings + * are sold. + */ + + switch (game.info.gold_upkeep_style) { + case GOLD_UPKEEP_CITY: + /* Cities already handled all upkeep costs. */ + break; + case GOLD_UPKEEP_MIXED: + /* Nation pays for units, cities already paid buildings */ + pplayer->economic.gold -= nation_unit_upkeep; + if (pplayer->economic.gold < 0) { player_balance_treasury_units(pplayer); - break; - case GOLD_UPKEEP_NATION: - /* Nation pays for units and buildings. */ + } + break; + case GOLD_UPKEEP_NATION: + /* Nation pays for units and buildings. */ + pplayer->economic.gold -= nation_unit_upkeep; + pplayer->economic.gold -= nation_impr_upkeep; + if (pplayer->economic.gold < 0) { player_balance_treasury_units_and_buildings(pplayer); - break; } + break; } /* Should not happen. */ @@ -3045,28 +3059,36 @@ static void update_city_activity(struct city *pcity) pcity->airlift = city_airlift_max(pcity); update_bulbs(pplayer, pcity->prod[O_SCIENCE], FALSE); - /* Update the treasury. */ - pplayer->economic.gold += pcity->prod[O_GOLD]; - pplayer->economic.gold -= city_total_impr_gold_upkeep(pcity); - pplayer->economic.gold -= city_total_unit_gold_upkeep(pcity); + /* Update the treasury, paying upkeeps and checking running out + * of gold based on the ruleset setting 'game.info.gold_upkeep_style': + * GOLD_UPKEEP_CITY: Cities pay for buildings and units and deficit + * is checked right here. + * GOLD_UPKEEP_MIXED: Cities pay only for buildings; the nation pays + * for units after all cities are processed. + * GOLD_UPKEEP_NATION: The nation pays for buildings and units + * only after all cities are processed. + * + * city_support() in city.c sets pcity->usage[O_GOLD] (and hence + * ->surplus[O_GOLD]) according to the setting. + */ + pplayer->economic.gold += pcity->surplus[O_GOLD]; if (pplayer->economic.gold < 0) { - /* Not enough gold - we have to sell some buildings, and if that - * is not enough, disband units with gold upkeep, taking into - * account the setting of 'game.info.gold_upkeep_style': - * GOLD_UPKEEP_CITY: Cities pay for buildings and units. - * GOLD_UPKEEP_MIXED: Cities pay only for buildings; the nation pays - * for units. - * GOLD_UPKEEP_NATION: The nation pays for buildings and units. */ switch (game.info.gold_upkeep_style) { case GOLD_UPKEEP_CITY: - case GOLD_UPKEEP_MIXED: - if (!city_balance_treasury_buildings(pcity) - && game.info.gold_upkeep_style == GOLD_UPKEEP_CITY) { + /* Out of money while paying buildings and units, sell first + * and disband if that didn't help */ + if (!city_balance_treasury_buildings(pcity)) { city_balance_treasury_units(pcity); } + break; + case GOLD_UPKEEP_MIXED: + /* Out of money while paying for buildings, sell some. */ + city_balance_treasury_buildings(pcity); break; case GOLD_UPKEEP_NATION: + /* This shouldn't be possible since all upkeeps are paid later. */ + fc_assert(FALSE); break; } } -- 2.20.1