Author: sveinung Date: Thu Dec 3 12:43:14 2015 New Revision: 30852 URL: http://svn.gna.org/viewcvs/freeciv?rev=30852&view=rev Log: Fix unit removal collateral damage negative gold
A player's gold is supposed to be positive during the turn. The gold upkeep payment starts with paying the unit gold upkeep. If the gold becomes negative a list of units with gold upkeep is generated. A unit on the list is removed ("sold") and its gold upkeep returned until the amount of gold becomes acceptable ("balanced"). An action auto performer rule caused by missing upkeep can kill other units as collateral damage. (Example: "Explode Nuclear") A unit killed as collateral damage can be on the list of units that are missing upkeep. Pay back the gold upkeep of collateral damage units the game considers to sell to balance the player's gold. This avoids the collateral damage causing negative gold. Store the payed gold upkeep for a unit so the correct gold upkeep is payed back. This avoids a reduction of the current amount of upkeep causing negative gold. See bug #24132 Modified: trunk/common/unit.c trunk/common/unit.h trunk/server/cityturn.c Modified: trunk/common/unit.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/unit.c?rev=30852&r1=30851&r2=30852&view=diff ============================================================================== --- trunk/common/unit.c (original) +++ trunk/common/unit.c Thu Dec 3 12:43:14 2015 @@ -1758,6 +1758,9 @@ punit->server.dying = FALSE; punit->server.removal_callback = NULL; + + memset(punit->server.upkeep_payed, 0, + O_LAST * sizeof(*punit->server.upkeep_payed)); punit->server.ord_map = 0; punit->server.ord_city = 0; Modified: trunk/common/unit.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/unit.h?rev=30852&r1=30851&r2=30852&view=diff ============================================================================== --- trunk/common/unit.h (original) +++ trunk/common/unit.h Thu Dec 3 12:43:14 2015 @@ -215,6 +215,9 @@ /* Call back to run on unit removal. */ void (*removal_callback)(struct unit *punit); + + /* The upkeep that actually was payed. */ + int upkeep_payed[O_LAST]; } server; }; }; Modified: trunk/server/cityturn.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/cityturn.c?rev=30852&r1=30851&r2=30852&view=diff ============================================================================== --- trunk/server/cityturn.c (original) +++ trunk/server/cityturn.c Thu Dec 3 12:43:14 2015 @@ -2492,8 +2492,19 @@ **************************************************************************/ static void uk_rem_gold_callback(struct unit *punit) { + int gold_upkeep; + /* Remove the unit from uk_rem_gold. */ unit_list_remove(uk_rem_gold, punit); + + gold_upkeep = punit->server.upkeep_payed[O_GOLD]; + + /* All units in uk_rem_gold should have gold upkeep! */ + fc_assert_ret_msg(gold_upkeep > 0, "%s has %d gold upkeep", + unit_rule_name(punit), gold_upkeep); + + /* Get the upkeep gold back. */ + unit_owner(punit)->economic.gold += gold_upkeep; } /************************************************************************** @@ -2538,7 +2549,7 @@ struct unit_list *punitlist) { struct unit *punit; - int gold_upkeep, r; + int r; struct unit_list *cargo; fc_assert_ret_val(pplayer != NULL, FALSE); @@ -2575,11 +2586,6 @@ unit_list_destroy(cargo); - gold_upkeep = punit->upkeep[O_GOLD]; - - /* All units in punitlist should have gold upkeep! */ - fc_assert_ret_val(gold_upkeep > 0, NULL); - { const char *punit_link = unit_tile_link(punit); const char *punit_logname = unit_name_translation(punit); @@ -2588,15 +2594,15 @@ if (upkeep_kill_unit(punit, O_GOLD, ULR_SOLD, game.info.muuk_gold_wipe)) { unit_list_remove(punitlist, punit); + + /* The gold was payed back when the unit removal made + * uk_rem_gold_callback() run as the unit's removal call back. */ notify_player(pplayer, utile, E_UNIT_LOST_MISC, ftc_server, _("Not enough gold. %s disbanded."), punit_link); log_debug("%s: unit sold (%s)", player_name(pplayer), punit_logname); - - /* Get the upkeep gold back. */ - pplayer->economic.gold += gold_upkeep; } else { /* Not able to get rid of punit */ return NULL; @@ -3047,6 +3053,11 @@ 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); + + /* Remember how much gold upkeep each unit was payed. */ + unit_list_iterate(pcity->units_supported, punit) { + punit->server.upkeep_payed[O_GOLD] = punit->upkeep[O_GOLD]; + } unit_list_iterate_end; if (pplayer->economic.gold < 0) { /* Not enough gold - we have to sell some buildings, and if that _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits