Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] (PR#2581) Layers Patch
Home

[Freeciv-Dev] (PR#2581) Layers Patch

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: raahul_da_man@xxxxxxxxx
Subject: [Freeciv-Dev] (PR#2581) Layers Patch
From: "Juhani Heino" <juhani.heino@xxxxxxxxxx>
Date: Tue, 20 May 2003 05:52:53 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Check this thoroughly. Raahul's original patch was good help
but I made this up mostly by myself, and I may have overlooked
something important.

I enclose a savegame you can experiment with. Connect as sanas
and sanas2, or take the human players as you like. Near city
Opole there are a submarine and a carrier quite overloaded,
and lots of transports and other stuff.

If and when this is committed, I'll follow up with updated
help text.

can_unit_attack_unit_at_tile()  contradicts its comment 4:
marines can't attack a sea tile. If the comment is valid,
that statement and my layer_priority() must be changed.

I had to remove
assert(ground_unit_transporter_capacity(x, y, pplayer) >= 0);
in sanitycheck.c  (don't worry, it isn't in the patch) because
three units were left in ocean after conquest of a city.
transfer_city_units()  in  citytools.c
is faulty, I think - it won't remove or teleport cargo of a
ship it destroys. But that is out of this scope. I just hope
that I didn't introduce any error that gets unnoticed hereby.

I changed get_defender logic a little. The multiplier was too
big - now it SURE fits into int, no matter what platform. And
if unit_def is 0, as often is against eg subs, old code chose
transport to defend because its build_cost was lower than
cruiser's... so I made defense_rating more important. It's
conceivable that unit_def can be skipped altogether, but I
guess we should change this thoroughly later. No idea now.

I moved  *_carrier_capacity  functions to more logical place
in  unit.c

An autogame reported PF error for Umar's Barbarian Leader. I
guess it's OK for a player to have a barbarian unit (probably
taken from conquered city), but if not, somebody could look at it.

Some suggestions. These may have been discussed earlier, but
you are welcome to take them to larger audience if you like.
- Should ships be prevented from attacking ground units from
harbour? I know they can shoot volleys over roofs, but still...
- When a city is conquered, would it be more natural that its
units now absent would survive and take another homecity? That
would also bypass the "stranded" feature mentioned above.
-- 
Juhani Heino
Finnish translator
--- ai/aitools.c.orig   Sun May 18 19:08:44 2003
+++ ai/aitools.c        Sun May 18 19:45:33 2003
@@ -415,6 +415,12 @@
   if (is_stack_vulnerable(pdef->x, pdef->y)) {
     /* lotsa people die */
     unit_list_iterate(map_get_tile(pdef->x, pdef->y)->units, aunit) {
+      /* 3rd row: on sea, cargo would be lost anyway */
+      if (game.rgame.layered_combat
+          && !is_same_layer(pdef, aunit)
+          && (!is_sailing_unit(pdef) || is_sailing_unit(aunit))) {
+        continue;
+      }
       victim_cost += unit_type(aunit)->build_cost;
     } unit_list_iterate_end;
   } else {
--- client/packhand.c.orig      Sat May 17 14:32:03 2003
+++ client/packhand.c   Sat May 17 14:39:25 2003
@@ -2337,6 +2337,7 @@
   game.rgame.min_dist_bw_cities = packet->min_dist_bw_cities;
   game.rgame.init_vis_radius_sq = packet->init_vis_radius_sq;
   game.rgame.hut_overflight = packet->hut_overflight;
+  game.rgame.layered_combat = packet->layered_combat;
   game.rgame.pillage_select = packet->pillage_select;
   game.rgame.nuke_contamination = packet->nuke_contamination;
   game.rgame.granary_food_ini = packet->granary_food_ini;
--- common/combat.c.orig        Sat May 17 16:18:26 2003
+++ common/combat.c     Tue May 20 12:42:44 2003
@@ -449,14 +449,63 @@
 }
 
 /**************************************************************************
+ In layered combat, gives the target priority. If this defender can't
+ be attacked at all, it gets 0. The battle will be on the layer with
+ the biggest number, see get_defender below.
+ Note that this allows a strafing attack: a fighter can wipe out
+ the planes on carrier (if AEGIS isn't there). If you want to
+ change this, set fighter value to 15 instead of 30.
+ Ships are preferred a little because they are generally easier
+ targets from air and this also prevents cargo from defending.
+ If you change this function, remember missiles. They must target
+ sea or land units, ain't no Sidewinders   8-)
+ Here it's assumed that helicopters can be attacked only by fighters
+ (cities are a different case for all air units), that's how I read
+ the help text.  --Juhani
+**************************************************************************/
+int layer_priority(struct unit *attacker, struct unit *defender)
+{
+  if (is_air_unit(defender) || is_heli_unit(defender)) {
+    if (unit_flag(attacker, F_FIGHTER)) {
+      return 30;
+    }
+    return 0;
+  }
+  if (is_ground_unit(defender)) {
+    if (unit_flag(attacker, F_NO_LAND_ATTACK)) {
+      return 0;
+    }
+    if (is_ground_unit(attacker)) {
+      return 30;
+    }
+    return 10;
+  }
+  if (is_sailing_unit(defender)) {
+    if (is_sailing_unit(attacker)) {
+      return 30;
+    }
+    if (is_ground_unit(attacker)) {
+      return 0;
+    }
+    if (unit_flag(defender, F_AEGIS)) {
+      return 40;
+    }
+    return 20;
+  }
+  freelog(LOG_ERROR, "layer_priority bug: probably a new movetype");
+  assert(FALSE);
+}
+
+/**************************************************************************
 Finds the best defender on the square, given an attacker.
 
-This is simply done by calling win_chance with all the possible defenders
-in turn.
-This functions could be improved to take the value of the unit into
-account. It currently uses build cost as a modifier in case the chances of
-2 units are identical, but this is crude as build cost does not neccesarily
-have anything to do with the value of a unit.
+This is done by calling win_chance with all the possible defenders
+in turn, but even without layered combat the most natural units
+are preferred, eg ships will defend against ships.
+This function could be improved to take the value of the unit into
+account. It currently uses build cost as a modifier in case the
+chances of 2 units are identical, but this is crude as build cost
+does not necessarily have anything to do with the value of a unit.
 It would be nice if the function was a bit more fuzzy about prioritizing,
 making it able to fx choose a 1a/9d unit over a 10a/10d unit. It should
 also be able to spare units without full hp's to some extend, as these
@@ -466,28 +515,38 @@
 {
   struct unit *bestdef = NULL;
   int bestvalue = -1, count = 0, best_cost = 0, rating_of_best = 0;
+  int priority = 0;
   struct player *att_owner = unit_owner(attacker);
+  bool change;
+  int build_cost, defense_rating, unit_def;
 
   unit_list_iterate(map_get_tile(x, y)->units, defender) {
+    freelog(LOG_DEBUG, "get_defender considering %s",
+                       unit_name(defender->type));
     if (pplayers_allied(att_owner, unit_owner(defender)))
       continue;
-    count++;
     if (unit_can_defend_here(defender)) {
-      bool change = FALSE;
-      int build_cost = unit_type(defender)->build_cost;
-      int defense_rating = get_defense_rating(attacker, defender);
+      if (game.rgame.layered_combat
+          && layer_priority(attacker,defender) < priority) {
+        continue;
+      }
+      count++;
+      change = FALSE;
+      build_cost = unit_type(defender)->build_cost;
+      defense_rating = get_defense_rating(attacker, defender);
 
-      /* This will make units roughly evenly good defenders look alike. */
-      int unit_def = (int) (100000 * (1 - unit_win_chance(attacker, 
defender)));
+      unit_def = (int) (30000 * (1 - unit_win_chance(attacker, defender)));
       assert(unit_def >= 0);
 
-      if (unit_def > bestvalue) {
+      if (layer_priority(attacker, defender) > priority) {
+        change = TRUE;
+      } else if (unit_def > bestvalue) {
        change = TRUE;
       } else if (unit_def == bestvalue) {
-       if (build_cost < best_cost) {
+       if (rating_of_best < defense_rating) {
          change = TRUE;
-       } else if (build_cost == best_cost) {
-         if (rating_of_best < defense_rating) {        
+       } else if (rating_of_best == defense_rating) {
+         if (build_cost < best_cost) { 
            change = TRUE;
          }
        }
@@ -498,6 +557,11 @@
        bestdef = defender;
        best_cost = build_cost;
        rating_of_best = defense_rating;
+        priority = layer_priority(attacker, defender);
+        freelog(LOG_DEBUG, "get_defender preferring so far %s "
+                "with unit_def=%i layer=%i def_rating=%i",
+                unit_name(defender->type), unit_def,
+                priority, defense_rating);
       }
     }
   } unit_list_iterate_end;
@@ -512,6 +576,13 @@
             unit_type(punit)->name, unit_list_size(&ptile->units), 
             get_terrain_name(ptile->terrain), x, y);
     assert(FALSE);
+  }
+
+  /* regardless of layered combat, this means there were no
+   * suitable targets - but in city anything counts */
+
+  if (priority == 0 && !map_get_city(x, y)) {
+    return NULL;
   }
 
   return bestdef;
--- common/combat.h.orig        Sat May 17 19:08:21 2003
+++ common/combat.h     Sat May 17 20:16:27 2003
@@ -48,6 +48,7 @@
 int get_virtual_defense_power(Unit_Type_id att_type, Unit_Type_id def_type,
                              int x, int y, bool fortified, bool veteran);
 int get_total_attack_power(struct unit *attacker, struct unit *defender);
+int layer_priority(struct unit *attacker, struct unit *defender);
 
 struct unit *get_defender(struct unit *attacker, int x, int y);
 struct unit *get_attacker(struct unit *defender, int x, int y);
--- common/game.h.orig  Sat May 17 16:17:04 2003
+++ common/game.h       Sat May 17 14:48:30 2003
@@ -187,6 +187,7 @@
     int min_dist_bw_cities;
     int init_vis_radius_sq;
     int hut_overflight;
+    bool layered_combat;
     bool pillage_select;
     int nuke_contamination;
     int granary_food_ini;
--- common/packets.c.orig       Sat May 17 16:17:21 2003
+++ common/packets.c    Sat May 17 14:52:36 2003
@@ -2748,6 +2748,7 @@
   dio_put_uint8(&dout, packet->min_dist_bw_cities);
   dio_put_uint8(&dout, packet->init_vis_radius_sq);
   dio_put_uint8(&dout, packet->hut_overflight);
+  dio_put_bool8(&dout, packet->layered_combat);
   dio_put_bool8(&dout, packet->pillage_select);
   dio_put_uint8(&dout, packet->nuke_contamination);
   dio_put_uint8(&dout, packet->granary_food_ini);
@@ -2773,6 +2774,7 @@
   dio_get_uint8(&din, &packet->min_dist_bw_cities);
   dio_get_uint8(&din, &packet->init_vis_radius_sq);
   dio_get_uint8(&din, &packet->hut_overflight);
+  dio_get_bool8(&din, &packet->layered_combat);
   dio_get_bool8(&din, &packet->pillage_select);
   dio_get_uint8(&din, &packet->nuke_contamination);
   dio_get_uint8(&din, &packet->granary_food_ini);
--- common/packets.h.orig       Sat May 17 16:17:37 2003
+++ common/packets.h    Sat May 17 14:56:26 2003
@@ -819,6 +819,7 @@
   int min_dist_bw_cities;
   int init_vis_radius_sq;
   int hut_overflight;
+  bool layered_combat;
   bool pillage_select;
   int nuke_contamination;
   int granary_food_ini;
--- common/unit.c.orig  Sat May 17 16:18:40 2003
+++ common/unit.c       Tue May 20 00:27:53 2003
@@ -261,6 +261,90 @@
 }
 
 /**************************************************************************
+Returns the number of free spaces for missiles. Can be 0 or negative.
+**************************************************************************/
+int missile_carrier_capacity(int x, int y, struct player *pplayer,
+                            bool count_units_with_extra_fuel)
+{
+  struct tile *ptile = map_get_tile(x, y);
+  int misonly = 0;
+  int airall = 0;
+  int totalcap;
+
+  unit_list_iterate(map_get_tile(x, y)->units, punit) {
+    if (unit_owner(punit) == pplayer) {
+      if (unit_flag(punit, F_CARRIER)
+         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
+       airall += get_transporter_capacity(punit);
+       continue;
+      }
+      if (unit_flag(punit, F_MISSILE_CARRIER)
+         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
+       misonly += get_transporter_capacity(punit);
+       continue;
+      }
+      /* Don't count units which have enough fuel (>1) */
+      if (is_air_unit(punit)
+         && (count_units_with_extra_fuel || punit->fuel <= 1)) {
+       if (unit_flag(punit, F_MISSILE))
+         misonly--;
+       else
+         airall--;
+      }
+    }
+  }
+  unit_list_iterate_end;
+
+  if (airall < 0)
+    airall = 0;
+
+  totalcap = airall + misonly;
+
+  return totalcap;
+}
+
+/**************************************************************************
+Returns the number of free spaces for airunits (includes missiles).
+Can be 0 or negative.
+**************************************************************************/
+int airunit_carrier_capacity(int x, int y, struct player *pplayer,
+                            bool count_units_with_extra_fuel)
+{
+  struct tile *ptile = map_get_tile(x, y);
+  int misonly = 0;
+  int airall = 0;
+
+  unit_list_iterate(map_get_tile(x, y)->units, punit) {
+    if (unit_owner(punit) == pplayer) {
+      if (unit_flag(punit, F_CARRIER)
+         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
+       airall += get_transporter_capacity(punit);
+       continue;
+      }
+      if (unit_flag(punit, F_MISSILE_CARRIER)
+         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
+       misonly += get_transporter_capacity(punit);
+       continue;
+      }
+      /* Don't count units which have enough fuel (>1) */
+      if (is_air_unit(punit)
+         && (count_units_with_extra_fuel || punit->fuel <= 1)) {
+       if (unit_flag(punit, F_MISSILE))
+         misonly--;
+       else
+         airall--;
+      }
+    }
+  }
+  unit_list_iterate_end;
+
+  if (misonly < 0)
+    airall += misonly;
+
+  return airall;
+}
+
+/**************************************************************************
 Returns the number of free spaces for ground units. Can be 0 or negative.
 **************************************************************************/
 int ground_unit_transporter_capacity(int x, int y, struct player *pplayer)
@@ -308,6 +392,15 @@
 bool is_air_units_transport(struct unit *punit)
 {
   return (get_transporter_capacity(punit) > 0
+         && unit_flag(punit, F_CARRIER));
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+bool is_missile_transport(struct unit *punit)
+{
+  return (get_transporter_capacity(punit) > 0
          && (unit_flag(punit, F_MISSILE_CARRIER)
              || unit_flag(punit, F_CARRIER)));
 }
@@ -345,6 +438,18 @@
 }
 
 /**************************************************************************
+  Do the units belong in the same layer?  (air, land, sea)
+**************************************************************************/
+bool is_same_layer(struct unit *punit, struct unit *aunit)
+{
+  if ((is_heli_unit(punit) && is_air_unit(aunit))
+      || (is_heli_unit(aunit) && is_air_unit(punit))) {
+    return TRUE;
+  }
+  return (unit_type(punit)->move_type == unit_type(aunit)->move_type);
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 bool is_military_unit(struct unit *punit)
@@ -993,90 +1098,6 @@
 struct player *unit_owner(struct unit *punit)
 {
   return (&game.players[punit->owner]);
-}
-
-/**************************************************************************
-Returns the number of free spaces for missiles. Can be 0 or negative.
-**************************************************************************/
-int missile_carrier_capacity(int x, int y, struct player *pplayer,
-                            bool count_units_with_extra_fuel)
-{
-  struct tile *ptile = map_get_tile(x, y);
-  int misonly = 0;
-  int airall = 0;
-  int totalcap;
-
-  unit_list_iterate(map_get_tile(x, y)->units, punit) {
-    if (unit_owner(punit) == pplayer) {
-      if (unit_flag(punit, F_CARRIER)
-         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
-       airall += get_transporter_capacity(punit);
-       continue;
-      }
-      if (unit_flag(punit, F_MISSILE_CARRIER)
-         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
-       misonly += get_transporter_capacity(punit);
-       continue;
-      }
-      /* Don't count units which have enough fuel (>1) */
-      if (is_air_unit(punit)
-         && (count_units_with_extra_fuel || punit->fuel <= 1)) {
-       if (unit_flag(punit, F_MISSILE))
-         misonly--;
-       else
-         airall--;
-      }
-    }
-  }
-  unit_list_iterate_end;
-
-  if (airall < 0)
-    airall = 0;
-
-  totalcap = airall + misonly;
-
-  return totalcap;
-}
-
-/**************************************************************************
-Returns the number of free spaces for airunits (includes missiles).
-Can be 0 or negative.
-**************************************************************************/
-int airunit_carrier_capacity(int x, int y, struct player *pplayer,
-                            bool count_units_with_extra_fuel)
-{
-  struct tile *ptile = map_get_tile(x, y);
-  int misonly = 0;
-  int airall = 0;
-
-  unit_list_iterate(map_get_tile(x, y)->units, punit) {
-    if (unit_owner(punit) == pplayer) {
-      if (unit_flag(punit, F_CARRIER)
-         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
-       airall += get_transporter_capacity(punit);
-       continue;
-      }
-      if (unit_flag(punit, F_MISSILE_CARRIER)
-         && !(is_ground_unit(punit) && is_ocean(ptile->terrain))) {
-       misonly += get_transporter_capacity(punit);
-       continue;
-      }
-      /* Don't count units which have enough fuel (>1) */
-      if (is_air_unit(punit)
-         && (count_units_with_extra_fuel || punit->fuel <= 1)) {
-       if (unit_flag(punit, F_MISSILE))
-         misonly--;
-       else
-         airall--;
-      }
-    }
-  }
-  unit_list_iterate_end;
-
-  if (misonly < 0)
-    airall += misonly;
-
-  return airall;
 }
 
 /**************************************************************************
--- common/unit.h.orig  Sat May 17 16:18:53 2003
+++ common/unit.h       Tue May 20 00:28:10 2003
@@ -216,6 +216,7 @@
 bool is_air_unit(struct unit *punit);
 bool is_heli_unit(struct unit *punit);
 bool is_ground_unit(struct unit *punit);
+bool is_same_layer(struct unit *punit, struct unit *aunit);
 bool can_unit_add_to_city (struct unit *punit);
 bool can_unit_build_city (struct unit *punit);
 bool can_unit_add_or_build_city (struct unit *punit);
@@ -227,6 +228,7 @@
 int get_transporter_capacity(struct unit *punit);
 bool is_ground_units_transport(struct unit *punit);
 bool is_air_units_transport(struct unit *punit);
+bool is_missile_transport(struct unit *punit);
 int missile_carrier_capacity(int x, int y, struct player *pplayer,
                             bool count_units_with_extra_fuel);
 int airunit_carrier_capacity(int x, int y, struct player *pplayer,
--- data/default/game.ruleset.orig      Sat May 17 16:17:52 2003
+++ data/default/game.ruleset   Tue May 20 03:47:43 2003
@@ -34,6 +34,13 @@
 ;   "Frighten" - Tribe frightened and disbands; hut disappears.
 hut_overflight         = "Frighten"
 
+; Whether only units of a single layer (air, land, sea) are
+; destroyed when the defender loses. For example, a fighter
+; attacks bombers on a square that has also enemy land units.
+; Even if the bombers are destroyed, the land units remain
+; intact. If this was disabled, they would die too.
+layered_combat          = 1
+
 ; Whether player gets to select which terrain improvement to pillage.
 pillage_select         = 1
 
--- server/ruleset.c.orig       Sat May 17 16:18:12 2003
+++ server/ruleset.c    Sat May 17 15:25:26 2003
@@ -2366,8 +2366,11 @@
     game.rgame.hut_overflight = OVERFLIGHT_FRIGHTEN;
   }
 
+  game.rgame.layered_combat = 
+    secfile_lookup_bool(&file, "civstyle.layered_combat" );
+
   game.rgame.pillage_select =
-      secfile_lookup_bool(&file, "civstyle.pillage_select");
+    secfile_lookup_bool(&file, "civstyle.pillage_select");
 
   sval = secfile_lookup_str(&file, "civstyle.nuke_contamination" );
   if (mystrcasecmp(sval, "Pollution") == 0) {
@@ -2771,6 +2774,7 @@
   misc_p.min_dist_bw_cities = game.rgame.min_dist_bw_cities;
   misc_p.init_vis_radius_sq = game.rgame.init_vis_radius_sq;
   misc_p.hut_overflight = game.rgame.hut_overflight;
+  misc_p.layered_combat = game.rgame.layered_combat;
   misc_p.pillage_select = game.rgame.pillage_select;
   misc_p.nuke_contamination = game.rgame.nuke_contamination;
   misc_p.granary_food_ini = game.rgame.granary_food_ini;
--- server/unithand.c.orig      Mon May 19 01:33:45 2003
+++ server/unithand.c   Tue May 20 01:23:38 2003
@@ -1038,10 +1038,15 @@
     return TRUE;
   } /* End attack case */
  
-  /* There are no players we are at war with at desttile. But if there
+  /* There are no units we can reach at desttile. But if there
      is a unit we have a treaty!=alliance with we can't move there */
   pdefender = is_non_allied_unit_tile(pdesttile, unit_owner(punit));
   if (pdefender) {
+    if (!can_unit_attack_tile(punit, dest_x , dest_y)) {
+      notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
+                      _("Game: You can't attack there."));
+      return FALSE;
+    }
     notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
                     _("Game: No war declared against %s, cannot attack."),
                     unit_owner(pdefender)->name);
--- server/unittools.c.orig     Sat May 17 16:19:10 2003
+++ server/unittools.c  Tue May 20 11:34:19 2003
@@ -1662,20 +1662,38 @@
                         bool wipe_cargo)
 {
   /* No need to remove air units as they can still fly away */
-  if (is_ground_units_transport(punit)
+
+  /* I disagree: now that I'm implementing layered combat, that
+   * would mean planes escaping unscathed from destroyed carrier.
+   * Helpfile hints otherwise, so I'll include air units. Use
+   * wipe_cargo value FALSE if the situation is different.  --Juhani  */
+
+  bool air = is_air_units_transport(punit);
+  bool ground = is_ground_units_transport(punit);
+  bool missile = is_missile_transport(punit);
+
+  if ((air || ground || missile)
       && is_ocean(map_get_terrain(punit->x, punit->y))
       && wipe_cargo) {
     int x = punit->x;
     int y = punit->y;
 
-    int capacity =
-       ground_unit_transporter_capacity(x, y, unit_owner(punit));
+    int capacity;
+    if (air) {
+      capacity = airunit_carrier_capacity(x, y, unit_owner(punit), TRUE);
+    } else if (missile) {
+      capacity = missile_carrier_capacity(x, y, unit_owner(punit), TRUE);
+    } else {
+      capacity = ground_unit_transporter_capacity(x, y, unit_owner(punit));
+    }
     capacity -= get_transporter_capacity(punit);
 
     unit_list_iterate(map_get_tile(x, y)->units, pcargo) {
       if (capacity >= 0)
        break;
-      if (is_ground_unit(pcargo)) {
+      if ((ground && is_ground_unit(pcargo))
+          || (air && is_air_unit(pcargo))
+          || (missile && unit_flag(pcargo, F_MISSILE))) {
        if (iter && ((struct unit*)ITERATOR_PTR((*iter))) == pcargo) {
          freelog(LOG_DEBUG, "iterating over %s in wipe_unit_safe",
                  unit_name(pcargo->type));
@@ -1725,6 +1743,7 @@
   char *loc_str = get_location_str_in(pplayer, punit->x, punit->y);
   int num_killed[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
   int ransom, unitcount = 0;
+  struct unit *original = punit;
   
   /* barbarian leader ransom hack */
   if( is_barbarian(pplayer) && unit_has_role(punit->type, L_BARBARIAN_LEADER)
@@ -1741,13 +1760,15 @@
   }
 
   if (unitcount == 0) {
-    unit_list_iterate(map_get_tile(punit->x, punit->y)->units, vunit)
+    unit_list_iterate(map_get_tile(punit->x, punit->y)->units, vunit) {
+      if (game.rgame.layered_combat && !is_same_layer(original, vunit))
+        continue;
       if (pplayers_at_war(unit_owner(pkiller), unit_owner(vunit)))
        unitcount++;
-    unit_list_iterate_end;
+    } unit_list_iterate_end;
   }
 
-  if (!is_stack_vulnerable(punit->x,punit->y) || unitcount == 1) {
+  if (!is_stack_vulnerable(punit->x, punit->y) || unitcount == 1) {
     notify_player_ex(pplayer, punit->x, punit->y, E_UNIT_LOST,
                     _("Game: %s lost to an attack by %s's %s%s."),
                     unit_type(punit)->name, destroyer->name,
@@ -1768,10 +1789,12 @@
     }
 
     /* count killed units */
-    unit_list_iterate((map_get_tile(punit->x ,punit->y)->units), vunit)
+    unit_list_iterate((map_get_tile(punit->x ,punit->y)->units), vunit) {
+      if (game.rgame.layered_combat && !is_same_layer(original, vunit))
+        continue;
       if (pplayers_at_war(unit_owner(pkiller), unit_owner(vunit)))
        num_killed[vunit->owner]++;
-    unit_list_iterate_end;
+    } unit_list_iterate_end;
 
     /* inform the owners */
     for (i = 0; i<MAX_NUM_PLAYERS+MAX_NUM_BARBARIANS; i++) {
@@ -1789,6 +1812,8 @@
 
     /* remove the units */
     unit_list_iterate(map_get_tile(punit->x, punit->y)->units, punit2) {
+      if (game.rgame.layered_combat && !is_same_layer(original, punit2))
+        continue;
       if (pplayers_at_war(unit_owner(pkiller), unit_owner(punit2))) {
        notify_player_ex(unit_owner(punit2), 
                         punit2->x, punit2->y, E_UNIT_LOST,
@@ -1800,10 +1825,15 @@
                get_nation_name_plural(unit_owner(punit2)->nation),
                unit_type(punit2)->name,
                get_nation_name_plural(destroyer->nation));
-       wipe_unit_spec_safe(punit2, NULL, FALSE);
+        if (original != punit2) {
+          /* myiter was recommended in HACKING and indeed it avoided
+           * a segfault I got with the previous code */
+          wipe_unit_spec_safe(punit2, &myiter, TRUE);
+        }
       }
-    }
-    unit_list_iterate_end;
+    } unit_list_iterate_end;
+    /* Finally remove the original loser - couldn't do it in iteration */
+    wipe_unit(original);
   }
 }
 
@@ -2481,7 +2511,8 @@
     }
     return;
     /*** Allocate air and missile units ***/
-  } else if (is_air_units_transport(ptrans)) {
+  } else if (is_air_units_transport(ptrans)
+             || is_missile_transport(ptrans)) {
     struct player_tile *plrtile =
        map_get_player_tile(x, y, unit_owner(ptrans));
     bool is_refuel_point =
@@ -2489,8 +2520,8 @@
        || (contains_special(plrtile->special, S_AIRBASE)
            && !is_non_allied_unit_tile(map_get_tile(x, y),
                                        unit_owner(ptrans)));
-    bool missiles_only = unit_flag(ptrans, F_MISSILE_CARRIER)
-      && !unit_flag(ptrans, F_CARRIER);
+    bool missiles_only = is_missile_transport(ptrans)
+                         && !unit_flag(ptrans, F_CARRIER);
 
     /* Make sure we can transport the units marked as being transported by 
ptrans */
     unit_list_iterate(ptile->units, pcargo) {

[Prev in Thread] Current Thread [Next in Thread]