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

> [book - Mon Jan 12 01:51:02 2009]:
> 
> The attached patch changes the function bounce_unit() to move a
> unit to a random tile a maximum of two tiles away from its
> current position, chosen from a list of tiles where the unit
> can survive (can_unit_survive_at_tile()) and that is not
> currently occupied by a non-ally unit or city. If no such tiles
> exist, then the unit is disbanded.

Version 2 adds a clarifying comment for the 'tiles' array
declaration and TRANS comments for the somewhat vague notify
messages.


-----------------------------------------------------------------------
私の大切な靴下を絶対に譲れません!
diff --git a/server/unittools.c b/server/unittools.c
index 8576975..d485f81 100644
--- a/server/unittools.c
+++ b/server/unittools.c
@@ -1143,25 +1143,61 @@ bool teleport_unit_to_city(struct unit *punit, struct city *pcity,
 }
 
 /**************************************************************************
-  Teleport or remove a unit due to stack conflict.
+  Move or remove a unit due to stack conflicts. This function will try to
+  find a random safe tile within a two tile distance of the unit's current
+  tile and move the unit there. If no tiles are found, the unit is
+  disbanded. If 'verbose' is TRUE, a message is sent to the unit owner
+  regarding what happened.
 **************************************************************************/
 void bounce_unit(struct unit *punit, bool verbose)
 {
-  struct player *pplayer = unit_owner(punit);
-  struct city *pcity = find_closest_owned_city(pplayer, punit->tile,
-                                               is_sailing_unit(punit), NULL);
+  struct player *pplayer;
+  struct tile *punit_tile;
+  int count = 0;
+
+  /* I assume that there are no topologies that have more than
+   * (2d + 1)^2 tiles in the "square" of "radius" d. */
+  const int DIST = 2;
+  struct tile *tiles[(2 * DIST + 1) * (2 * DIST + 1)];
+
+  if (!punit) {
+    return;
+  }
+
+  pplayer = unit_owner(punit);
+  punit_tile = unit_tile(punit);
+
+  square_iterate(punit_tile, DIST, ptile) {
+    if (count >= ARRAY_SIZE(tiles)) {
+      break;
+    }
+    if (can_unit_survive_at_tile(punit, ptile)
+        && !is_non_allied_city_tile(ptile, pplayer)
+        && !is_non_allied_unit_tile(ptile, pplayer)) {
+      tiles[count++] = ptile;
+    }
+  } square_iterate_end;
+
+  if (count > 0) {
+    struct tile *ptile = tiles[myrand(count)];
 
-  if (pcity && can_unit_exist_at_tile(punit, pcity->tile)) {
-    (void) teleport_unit_to_city(punit, pcity, 0, verbose);
-  } else {
-    /* remove it */
     if (verbose) {
-      notify_player(unit_owner(punit), punit->tile, E_UNIT_LOST_MISC,
-		       _("Disbanded your %s."),
-		       unit_name_translation(punit));
+      /* TRANS: A unit is moved to resolve stack conflicts. */
+      notify_player(pplayer, ptile, E_UNIT_RELOCATED, _("Moved your %s."),
+                    unit_name_translation(punit));
     }
-    wipe_unit(punit);
+    move_unit(punit, ptile, 0);
+    return;
+  }
+
+  /* Didn't find a place to bounce the unit, just disband it. */
+  if (verbose) {
+    /* TRANS: A unit is disbanded to resolve stack conflicts. */
+    notify_player(pplayer, punit_tile, E_UNIT_LOST_MISC,
+                  _("Disbanded your %s."),
+                  unit_name_translation(punit));
   }
+  wipe_unit(punit);
 }
 
 
diff --git a/server/unittools.c b/server/unittools.c
index 455a9bb..3f3e27f 100644
--- a/server/unittools.c
+++ b/server/unittools.c
@@ -1024,25 +1024,61 @@ bool teleport_unit_to_city(struct unit *punit, struct city *pcity,
 }
 
 /**************************************************************************
-  Teleport or remove a unit due to stack conflict.
+  Move or remove a unit due to stack conflicts. This function will try to
+  find a random safe tile within a two tile distance of the unit's current
+  tile and move the unit there. If no tiles are found, the unit is
+  disbanded. If 'verbose' is TRUE, a message is sent to the unit owner
+  regarding what happened.
 **************************************************************************/
 void bounce_unit(struct unit *punit, bool verbose)
 {
-  struct player *pplayer = unit_owner(punit);
-  struct city *pcity = find_closest_owned_city(pplayer, punit->tile,
-                                               is_sailing_unit(punit), NULL);
+  struct player *pplayer;
+  struct tile *punit_tile;
+  int count = 0;
+
+  /* I assume that there are no topologies that have more than
+   * (2d + 1)^2 tiles in the "square" of "radius" d. */
+  const int DIST = 2;
+  struct tile *tiles[(2 * DIST + 1) * (2 * DIST + 1)];
+
+  if (!punit) {
+    return;
+  }
+
+  pplayer = unit_owner(punit);
+  punit_tile = punit->tile;
+
+  square_iterate(punit_tile, DIST, ptile) {
+    if (count >= ARRAY_SIZE(tiles)) {
+      break;
+    }
+    if (can_unit_survive_at_tile(punit, ptile)
+        && !is_non_allied_city_tile(ptile, pplayer)
+        && !is_non_allied_unit_tile(ptile, pplayer)) {
+      tiles[count++] = ptile;
+    }
+  } square_iterate_end;
+
+  if (count > 0) {
+    struct tile *ptile = tiles[myrand(count)];
 
-  if (pcity && can_unit_exist_at_tile(punit, pcity->tile)) {
-    (void) teleport_unit_to_city(punit, pcity, 0, verbose);
-  } else {
-    /* remove it */
     if (verbose) {
-      notify_player(unit_owner(punit), punit->tile, E_UNIT_LOST,
-		       _("Disbanded your %s."),
-		       unit_name_translation(punit));
+      /* TRANS: A unit is moved to resolve stack conflicts. */
+      notify_player(pplayer, ptile, E_UNIT_RELOCATED, _("Moved your %s."),
+                    unit_name_translation(punit));
     }
-    wipe_unit(punit);
+    move_unit(punit, ptile, 0);
+    return;
+  }
+
+  /* Didn't find a place to bounce the unit, just disband it. */
+  if (verbose) {
+    /* TRANS: A unit is disbanded to resolve stack conflicts. */
+    notify_player(pplayer, punit_tile, E_UNIT_LOST,
+                  _("Disbanded your %s."),
+                  unit_name_translation(punit));
   }
+  wipe_unit(punit);
 }
 
 
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to