Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2006:
[Freeciv-Dev] (PR#18380) [Patch] Rewrite wipe_unit()
Home

[Freeciv-Dev] (PR#18380) [Patch] Rewrite wipe_unit()

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#18380) [Patch] Rewrite wipe_unit()
From: "Marko Lindqvist" <cazfi74@xxxxxxxxx>
Date: Fri, 7 Jul 2006 11:13:53 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=18380 >


  #13384 requires changes to wipe_unit() logic. This patch implements those.
  Now we iterate through all drowning units and search for transport for 
each. If free transport is found, put unit in to the transport. If not, 
unit is destroyed.

  Largely untested.


  - ML

diff -Nurd -X.diff_ignore freeciv/common/movement.c freeciv/common/movement.c
--- freeciv/common/movement.c   2006-07-07 19:52:06.812500000 +0300
+++ freeciv/common/movement.c   2006-07-07 21:10:48.328125000 +0300
@@ -26,6 +26,7 @@
 #include "map.h"
 #include "movement.h"
 #include "unit.h"
+#include "unitlist.h"
 #include "unittype.h"
 #include "terrain.h"
 
@@ -486,3 +487,20 @@
   }
   return MOVETYPE_LAST;
 }
+
+/**************************************************************************
+  Search transport suitable for given unit from tile. It has to have
+  free space in it.
+**************************************************************************/
+struct unit *find_transport_from_tile(struct unit *punit, struct tile *ptile)
+{
+  unit_list_iterate(ptile->units, ptransport) {
+    if (get_transporter_capacity(ptransport) > 
get_transporter_occupancy(ptransport)
+        && can_unit_transport(ptransport, punit)
+        && is_native_terrain(unit_type(ptransport), ptile->terrain)) {
+      return ptransport;
+    }
+  } unit_list_iterate_end;
+
+  return NULL;
+}
diff -Nurd -X.diff_ignore freeciv/common/movement.h freeciv/common/movement.h
--- freeciv/common/movement.h   2006-07-07 19:40:15.359375000 +0300
+++ freeciv/common/movement.h   2006-07-07 20:39:38.578125000 +0300
@@ -49,6 +49,7 @@
                                             const struct tile *dst_tile,
                                             bool igzoc);
 bool can_unit_transport(const struct unit *transporter, const struct unit 
*transported);
+struct unit *find_transport_from_tile(struct unit *punit, struct tile *ptile);
 
 enum unit_move_type move_type_from_str(const char *s);
 
diff -Nurd -X.diff_ignore freeciv/server/unittools.c freeciv/server/unittools.c
--- freeciv/server/unittools.c  2006-07-07 19:42:12.421875000 +0300
+++ freeciv/server/unittools.c  2006-07-07 20:45:45.062500000 +0300
@@ -1416,15 +1416,29 @@
 }
 
 /**************************************************************************
+  Handle units destroyed when their transport is destroyed
+**************************************************************************/
+static void unit_lost_with_transport(const struct player *pplayer,
+                                     struct unit *pcargo,
+                                     const struct unit_type *ptransport)
+{
+  notify_player(pplayer, pcargo->tile, E_UNIT_LOST,
+                _("%s lost when %s was lost."),
+                unit_type(pcargo)->name,
+                ptransport->name);
+  server_remove_unit(pcargo);
+}
+
+/**************************************************************************
   Remove the unit, and passengers if it is a carrying any. Remove the 
   _minimum_ number, eg there could be another boat on the square.
 **************************************************************************/
 void wipe_unit(struct unit *punit)
 {
-  bool wipe_cargo = TRUE; /* This used to be a function parameter. */
   struct tile *ptile = punit->tile;
   struct player *pplayer = unit_owner(punit);
   struct unit_type *ptype = unit_type(punit);
+  int drowning = 0;
 
   /* First pull all units off of the transporter. */
   if (get_transporter_capacity(punit) > 0) {
@@ -1436,6 +1450,9 @@
        /* Could use unload_unit_from_transporter here, but that would
         * call send_unit_info for the transporter unnecessarily. */
        pull_unit_from_transporter(pcargo, punit);
+        if (!can_unit_exist_at_tile(pcargo, ptile)) {
+          drowning++;
+        }
        if (pcargo->activity == ACTIVITY_SENTRY) {
          /* Activate sentried units - like planes on a disbanded carrier.
           * Note this will activate ground units even if they just change
@@ -1447,79 +1464,65 @@
     } unit_list_iterate_end;
   }
 
-  /* No need to wipe the cargo unless it's a ground transporter. */
-  wipe_cargo &= is_ground_units_transport(punit);
-
   /* Now remove the unit. */
   server_remove_unit(punit);
 
-  /* Finally reassign, bounce, or destroy all ground units at this location.
-   * There's no need to worry about air units; they can fly away. */
-  if (wipe_cargo
-      && is_ocean(tile_get_terrain(ptile))
-      && !tile_get_city(ptile)) {
+  /* Finally reassign, bounce, or destroy all units that cannot exist at this
+   * location without transport. */
+  if (drowning) {
     struct city *pcity = NULL;
-    int capacity = ground_unit_transporter_capacity(ptile, pplayer);
 
-    /* Get rid of excess standard units. */
-    if (capacity < 0) {
-      unit_list_iterate_safe(ptile->units, pcargo) {
-       if (is_ground_unit(pcargo)
-           && pcargo->transported_by == -1
-           && !unit_flag(pcargo, F_UNDISBANDABLE)
-           && !unit_flag(pcargo, F_GAMELOSS)) {
-         server_remove_unit(pcargo);
-         if (++capacity >= 0) {
-           break;
-         }
-       }
-      } unit_list_iterate_safe_end;
-    }
-
-    /* Get rid of excess undisbandable/gameloss units. */
-    if (capacity < 0) {
-      unit_list_iterate_safe(ptile->units, pcargo) {
-       if (is_ground_unit(pcargo) && pcargo->transported_by == -1) {
+    /* First save undisbandable and gameloss units */
+    unit_list_iterate_safe(ptile->units, pcargo) {
+      if (pcargo->transported_by == -1
+          && !can_unit_exist_at_tile(pcargo, ptile)
+          && (unit_flag(pcargo, F_UNDISBANDABLE) || unit_flag(pcargo, 
F_GAMELOSS))) {
+        struct unit *ptransport = find_transport_from_tile(pcargo, ptile);
+        if (ptransport != NULL) {
+          put_unit_onto_transporter(pcargo, ptransport);
+        } else {
          if (unit_flag(pcargo, F_UNDISBANDABLE)) {
            pcity = find_closest_owned_city(unit_owner(pcargo),
                                            pcargo->tile, TRUE, NULL);
            if (pcity && teleport_unit_to_city(pcargo, pcity, 0, FALSE)) {
              notify_player(pplayer, ptile, E_UNIT_RELOCATED,
-                              _("%s escaped the destruction of %s, and "
-                                "fled to %s."), unit_type(pcargo)->name,
-                              ptype->name, pcity->name);
+                            _("%s escaped the destruction of %s, and "
+                              "fled to %s."), unit_type(pcargo)->name,
+                            ptype->name, pcity->name);
            }
-         }
-         if (!unit_flag(pcargo, F_UNDISBANDABLE) || !pcity) {
-           notify_player(pplayer, ptile, E_UNIT_LOST,
-                            _("%s lost when %s was lost."),
-                            unit_type(pcargo)->name,
-                            ptype->name);
-           server_remove_unit(pcargo);
-         }
-         if (++capacity >= 0) {
-           break;
-         }
-       }
-      } unit_list_iterate_safe_end;
-    }
+          }
+          if (!unit_flag(pcargo, F_UNDISBANDABLE) || !pcity) {
+            unit_lost_with_transport(pplayer, pcargo, ptype);
+          }
+        }
 
-    /* Reassign existing units.  This is an O(n^2) operation as written. */
-    unit_list_iterate(ptile->units, ptrans) {
-      if (is_ground_units_transport(ptrans)) {
-       int occupancy = get_transporter_occupancy(ptrans);
+        drowning--;
+        if (!drowning) {
+          break;
+        }
+      }
+    } unit_list_iterate_safe_end;
+  }
 
-       unit_list_iterate(ptile->units, pcargo) {
-         if (occupancy >= get_transporter_capacity(ptrans)) {
-           break;
-         }
-         if (is_ground_unit(pcargo) && pcargo->transported_by == -1) {
-           put_unit_onto_transporter(pcargo, ptrans);
-           occupancy++;
-         }
-       } unit_list_iterate_end;
+  /* Then other units */
+  if (drowning) {
+    unit_list_iterate_safe(ptile->units, pcargo) {
+      if (pcargo->transported_by == -1
+          && !can_unit_exist_at_tile(pcargo, ptile)) {
+        struct unit *ptransport = find_transport_from_tile(pcargo, ptile);
+
+        if (ptransport != NULL) {
+          put_unit_onto_transporter(pcargo, ptransport);
+        } else {
+          unit_lost_with_transport(pplayer, pcargo, ptype);
+        }
+
+        drowning--;
+        if (!drowning) {
+          break;
+        }
       }
-    } unit_list_iterate_end;
+    } unit_list_iterate_safe_end;
   }
 }
 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#18380) [Patch] Rewrite wipe_unit(), Marko Lindqvist <=