Author: sveinung
Date: Fri Jul 10 15:28:39 2015
New Revision: 29213

URL: http://svn.gna.org/viewcvs/freeciv?rev=29213&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:
    branches/S2_6/common/unit.c
    branches/S2_6/common/unit.h
    branches/S2_6/server/citytools.c
    branches/S2_6/server/unittools.c

Modified: branches/S2_6/common/unit.c
URL: 
http://svn.gna.org/viewcvs/freeciv/branches/S2_6/common/unit.c?rev=29213&r1=29212&r2=29213&view=diff
==============================================================================
--- branches/S2_6/common/unit.c (original)
+++ branches/S2_6/common/unit.c Fri Jul 10 15:28:39 2015
@@ -1778,6 +1778,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: branches/S2_6/common/unit.h
URL: 
http://svn.gna.org/viewcvs/freeciv/branches/S2_6/common/unit.h?rev=29213&r1=29212&r2=29213&view=diff
==============================================================================
--- branches/S2_6/common/unit.h (original)
+++ branches/S2_6/common/unit.h Fri Jul 10 15:28:39 2015
@@ -205,6 +205,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: branches/S2_6/server/citytools.c
URL: 
http://svn.gna.org/viewcvs/freeciv/branches/S2_6/server/citytools.c?rev=29213&r1=29212&r2=29213&view=diff
==============================================================================
--- branches/S2_6/server/citytools.c    (original)
+++ branches/S2_6/server/citytools.c    Fri Jul 10 15:28:39 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;
@@ -1530,7 +1560,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: branches/S2_6/server/unittools.c
URL: 
http://svn.gna.org/viewcvs/freeciv/branches/S2_6/server/unittools.c?rev=29213&r1=29212&r2=29213&view=diff
==============================================================================
--- branches/S2_6/server/unittools.c    (original)
+++ branches/S2_6/server/unittools.c    Fri Jul 10 15:28:39 2015
@@ -1579,6 +1579,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);
@@ -1711,6 +1714,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) {
@@ -1969,6 +1975,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

Reply via email to