Author: sveinung Date: Fri Jul 10 15:18:53 2015 New Revision: 29211 URL: http://svn.gna.org/viewcvs/freeciv?rev=29211&view=rev Log: Don't transfer dying units to other players.
Transferring a dying GameLoss unit will kill the player he is transferred to rather than the player who owned it when it was killed. I think this happened to the reporter of bug #23676. The gameloss_style was Loot. A Leader (a GameLoss unit) was inside a city. The Leader was killed. The city where the Leader was located was transferred to his killer as part of the Loot. If the dying Leader is transferred with the city he is inside the killer will loose the game while the player the Leader used to belong to lives on without the vulnerability of having a Leader. Reported anonymously See bug #23676 Modified: trunk/common/unit.c trunk/common/unit.h trunk/server/citytools.c trunk/server/unittools.c Modified: trunk/common/unit.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/unit.c?rev=29211&r1=29210&r2=29211&view=diff ============================================================================== --- trunk/common/unit.c (original) +++ trunk/common/unit.c Fri Jul 10 15:18:53 2015 @@ -1769,6 +1769,8 @@ if (is_server()) { punit->server.debug = FALSE; punit->server.birth_turn = game.info.turn; + + punit->server.dying = FALSE; 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=29211&r1=29210&r2=29211&view=diff ============================================================================== --- trunk/common/unit.h (original) +++ trunk/common/unit.h Fri Jul 10 15:18:53 2015 @@ -202,6 +202,9 @@ time_t action_timestamp; int action_turn; struct unit_move_data *moving; + + /* The unit is in the process of dying. */ + bool dying; } server; }; }; Modified: trunk/server/citytools.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/citytools.c?rev=29211&r1=29210&r2=29211&view=diff ============================================================================== --- trunk/server/citytools.c (original) +++ trunk/server/citytools.c Fri Jul 10 15:18:53 2015 @@ -579,6 +579,12 @@ struct player *from_player = unit_owner(punit); struct player *to_player = city_owner(tocity); + /* Transfering a dying GameLoss unit as part of the loot for + * killing it caused gna bug #23676. */ + fc_assert_ret_msg(!punit->server.dying, + "Tried to transfer the dying unit %d.", + punit->id); + if (from_player == to_player) { log_verbose("Changed homecity of %s %s to %s", nation_rule_name(nation_of_player(from_player)), @@ -677,6 +683,15 @@ * Only relevant if we are transferring to another player. */ if (pplayer != pvictim) { unit_list_iterate_safe((ptile)->units, vunit) { + if (vunit->server.dying) { + /* Don't transfer or bounce a dying unit. It will soon be gone + * anyway. + * + * Transfering a dying GameLoss unit as part of the loot for + * killing it caused gna bug #23676. */ + continue; + } + /* Don't transfer units already owned by new city-owner --wegge */ if (unit_owner(vunit) == pvictim) { /* vunit may die during transfer_unit(). @@ -702,6 +717,16 @@ cities or maybe destroyed */ unit_list_iterate_safe(units, vunit) { struct city *new_home_city = tile_city(unit_tile(vunit)); + + if (vunit->server.dying) { + /* Don't transfer or destroy a dying unit. It will soon be gone + * anyway. + * + * Transfering a dying GameLoss unit as part of the loot for + * killing it caused gna bug #23676. */ + continue; + } + if (new_home_city && new_home_city != exclude_city && city_owner(new_home_city) == unit_owner(vunit)) { /* unit is in another city: make that the new homecity, @@ -734,6 +759,11 @@ #ifdef DEBUG unit_list_iterate(pcity->units_supported, punit) { + if (punit->server.dying) { + /* Leave the dying alone. */ + continue; + } + fc_assert(punit->homecity == pcity->id); fc_assert(unit_owner(punit) == pplayer); } unit_list_iterate_end; @@ -1536,7 +1566,8 @@ if (new_home_city && new_home_city != pcity - && city_owner(new_home_city) == powner) { + && city_owner(new_home_city) == powner + && !punit->server.dying) { transfer_unit(punit, new_home_city, TRUE); } } unit_list_iterate_safe_end; Modified: trunk/server/unittools.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/unittools.c?rev=29211&r1=29210&r2=29211&view=diff ============================================================================== --- trunk/server/unittools.c (original) +++ trunk/server/unittools.c Fri Jul 10 15:18:53 2015 @@ -1588,6 +1588,9 @@ struct unit *ptrans; struct player *pplayer = unit_owner(punit); + /* The unit is doomed. */ + punit->server.dying = TRUE; + #ifdef DEBUG unit_list_iterate(ptile->units, pcargo) { fc_assert(unit_transport_get(pcargo) != punit); @@ -1720,6 +1723,9 @@ struct unit_list *imperiled = unit_list_new(); struct unit_list *unsaved = unit_list_new(); struct unit *ptrans = unit_transport_get(punit); + + /* The unit is doomed. */ + punit->server.dying = TRUE; /* Remove unit itself from its transport */ if (ptrans != NULL) { @@ -1978,6 +1984,9 @@ sz_strlcpy(pkiller_link, unit_link(pkiller)); sz_strlcpy(punit_link, unit_tile_link(punit)); + + /* The unit is doomed. */ + punit->server.dying = TRUE; if ((game.info.gameloss_style & GAMELOSS_STYLE_LOOT) && unit_has_type_flag(punit, UTYF_GAMELOSS)) { _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits