Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.97
diff -u -r1.97 advmilitary.c
--- ai/advmilitary.c	2002/03/06 10:05:31	1.97
+++ ai/advmilitary.c	2002/03/06 14:44:12
@@ -593,12 +593,7 @@
       } else if (real_map_distance(pcity->x, pcity->y, x, y) * SINGLE_MOVE <= m) c = 1;
       else c = real_map_distance(pcity->x, pcity->y, x, y) * SINGLE_MOVE * q / m;
 
-      m = get_virtual_defense_power(i, n, x, y);
-      m *= unit_types[n].hp * unit_types[n].firepower;
-      if (vet) m *= 1.5;
-      m /= 30;
-      m *= m;
-      d = m;
+      d = unit_vulnerability_virtual2(i, n, x, y, FALSE, vet, FALSE, 0);
 
       if (unit_types[i].move_type == LAND_MOVING && acity &&
           c > (player_knows_improvement_tech(city_owner(acity),
@@ -733,12 +728,10 @@
       else c = real_map_distance(myunit->x, myunit->y, acity->x, acity->y) * SINGLE_MOVE / m;
 
       n = ai_choose_defender_versus(acity, v);
-      m = get_virtual_defense_power(v, n, x, y);
-      m *= unit_types[n].hp * unit_types[n].firepower;
-      if (do_make_unit_veteran(acity, n)) m *= 1.5;
-      m /= 30;
       if (c > 1) {
-        d = m * m;
+	d = unit_vulnerability_virtual2(v, n, x, y, FALSE,
+					do_make_unit_veteran(acity, n),
+					FALSE, 0);
         b = unit_types[n].build_cost + 40;
         vet = do_make_unit_veteran(acity, n);
       } else {
@@ -751,14 +744,10 @@
 Yet, somehow, this line existed, and remained here for months, bugging the AI
 tech progression beyond all description.  Only when adding the override code
 did I realize the magnitude of my transgression.  How despicable. -- Syela */
-        m = get_virtual_defense_power(v, pdef->type, x, y);
-        if (pdef->veteran) m *= 1.5; /* with real defenders, this must be before * hp -- Syela */
-	m *= (myunit->id != 0 ? pdef->hp : unit_type(pdef)->hp) *
-	    unit_type(pdef)->firepower;
-/*        m /= (pdef->veteran ? 20 : 30);  -- led to rounding errors.  Duh! -- Syela */
-        m /= 30;
-        if (d < m * m) {
-          d = m * m;
+	m = unit_vulnerability_virtual2(v, pdef->type, x, y, FALSE,
+					pdef->veteran, myunit->id, pdef->hp);
+        if (d < m) {
+          d = m;
           b = unit_type(pdef)->build_cost + 40; 
           vet = pdef->veteran;
           n = pdef->type; /* and not before, or heinous things occur!! */
@@ -793,17 +782,9 @@
       c = ((dist + m - 1) / m);
 
       n = pdef->type;
-      m = get_virtual_defense_power(v, n, x, y);
-      if (pdef->veteran) m += m / 2;
-      if (pdef->activity == ACTIVITY_FORTIFIED) m += m / 2;
-/* attempting to recreate the rounding errors in get_total_defense_power -- Syela */
-
-      m *= (myunit->id != 0 ? pdef->hp : unit_types[n].hp) * unit_types[n].firepower;
-/* let this be the LAST discrepancy!  How horribly many there have been! -- Syela */
-/*     m /= (pdef->veteran ? 20 : 30);*/
-      m /= 30;
-      m *= m;
-      d = m;
+      d = unit_vulnerability_virtual2(v, n, x, y,
+				      pdef->activity == ACTIVITY_FORTIFIED,
+				      pdef->veteran, myunit->id, pdef->hp);
       vet = pdef->veteran;
     } /* end dealing with units */
 
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.107
diff -u -r1.107 aicity.c
--- ai/aicity.c	2002/03/06 10:05:31	1.107
+++ ai/aicity.c	2002/03/06 14:44:13
@@ -305,12 +305,11 @@
 static int ai_city_defender_value(struct city *pcity, Unit_Type_id a_type,
                                   Unit_Type_id d_type)
 {
-  int m;
-  m = get_virtual_defense_power(a_type, d_type, pcity->x, pcity->y);
-  if (do_make_unit_veteran(pcity, d_type)) m *= 1.5;
-  m *= unit_types[d_type].hp * unit_types[d_type].firepower;
-  m /= 30;
-  return (m * m);
+  int m = unit_vulnerability_virtual2(a_type, d_type, pcity->x,
+				      pcity->y, FALSE,
+				      do_make_unit_veteran(pcity, d_type),
+				      FALSE, 0);
+  return m;
 }
 #endif
 
@@ -632,7 +631,7 @@
     if (!is_ai_simple_military(i)) continue;
     m = unit_types[i].move_type;
     if (can_build_unit(pcity, i) && (m == LAND_MOVING || m == SEA_MOVING)) {
-      j = get_virtual_defense_power(v, i, pcity->x, pcity->y);
+      j = get_virtual_defense_power(v, i, pcity->x, pcity->y, FALSE, FALSE);
       if (j > best || (j == best && get_unit_type(i)->build_cost <=
                                get_unit_type(bestid)->build_cost)) {
         best = j;
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.185
diff -u -r1.185 aiunit.c
--- ai/aiunit.c	2002/03/06 05:28:19	1.185
+++ ai/aiunit.c	2002/03/06 14:44:15
@@ -588,21 +588,33 @@
 
 int unit_vulnerability_basic(struct unit *punit, struct unit *pdef)
 {
-  int v;
-
-  v = get_total_defense_power(punit, pdef) *
-      (punit->id != 0 ? pdef->hp : unit_type(pdef)->hp) *
-      unit_type(pdef)->firepower / 30;
-
-  return(v);
+  return (get_total_defense_power(punit, pdef) *
+	  (punit->id != 0 ? pdef->hp : unit_type(pdef)->hp) *
+	  unit_type(pdef)->firepower / POWER_DIVIDER);
 }
 
 int unit_vulnerability_virtual(struct unit *punit)
 {
-  int v;
-  v = unit_type(punit)->defense_strength *
-      (punit->veteran ? 15 : 10) * punit->hp / 30;
-  return(v * v);
+  int v = base_get_defense_power(punit) * punit->hp / POWER_DIVIDER;
+
+  return v * v;
+}
+
+/**************************************************************************
+  See get_virtual_defense_power for the arguments att_type, def_type,
+  x, y, fortified and veteran. If use_alternative_hp is FALSE the
+  (maximum) hps of the given unit type is used. If use_alternative_hp
+  is TRUE the given alternative_hp value is used.
+**************************************************************************/
+int unit_vulnerability_virtual2(Unit_Type_id att_type, Unit_Type_id def_type,
+				int x, int y, bool fortified, bool veteran,
+				bool use_alternative_hp, int alternative_hp)
+{
+  int v = (get_virtual_defense_power(att_type, def_type, x, y, fortified,
+				     veteran) *
+	   (use_alternative_hp ? alternative_hp : unit_types[def_type].
+	    hp) * unit_types[def_type].firepower / POWER_DIVIDER);
+  return v * v;
 }
 
 int unit_vulnerability(struct unit *punit, struct unit *pdef)
@@ -790,14 +802,13 @@
 	continue;
       if (!can_unit_attack_unit_at_tile(aunit, pdef, pdef->x, pdef->y))
 	continue;
-      d =
-	  get_virtual_defense_power(aunit->type, pdef->type, pdef->x,
-				    pdef->y);
+      d = get_virtual_defense_power(aunit->type, pdef->type, pdef->x,
+				    pdef->y, FALSE, FALSE);
       if (d == 0)
 	return TRUE;		/* Thanks, Markus -- Syela */
       cur = unit_belligerence_primitive(aunit) *
 	  get_virtual_defense_power(punit->type, pdef->type, pdef->x,
-				    pdef->y) / d;
+				    pdef->y, FALSE, FALSE) / d;
       if (cur > val && ai_fuzzy(unit_owner(punit), TRUE))
 	return FALSE;
     }
@@ -1109,11 +1120,9 @@
     freelog(LOG_DEBUG,
 	    "%s@(%d,%d) looking for bodyguard, d_val=%d, my_val=%d",
 	    unit_type(punit)->name, punit->x, punit->y, d_val,
-	    (punit->hp * (punit->veteran ? 15 : 10)
-	     * unit_type(punit)->defense_strength));
+	    (punit->hp * base_get_defense_power(punit)));
     ptile = map_get_tile(punit->x, punit->y);
-    if (d_val >= punit->hp * (punit->veteran ? 15 : 10) *
-                unit_type(punit)->defense_strength) {
+    if (d_val >= punit->hp * base_get_defense_power(punit)) {
 /*      if (!unit_list_find(&pplayer->units, punit->ai.bodyguard))      Ugggggh */
       if (!unit_list_find(&ptile->units, punit->ai.bodyguard))
         punit->ai.bodyguard = -1;
@@ -1553,10 +1562,11 @@
 		    * SINGLE_MOVE) / m;
           if (c > 1) {
             n = ai_choose_defender_versus(acity, punit->type);
-            v = get_virtual_defense_power(punit->type, n, acity->x, acity->y) *
-                unit_types[n].hp * unit_types[n].firepower *
-                (do_make_unit_veteran(acity, n) ? 1.5 : 1.0) / 30;
-            if (v * v >= d) { d = v * v; b = unit_types[n].build_cost + 40; }
+	    v = unit_vulnerability_virtual2(punit->type, n, acity->x,
+					    acity->y, FALSE,
+					    do_make_unit_veteran(acity, n),
+					    FALSE, 0);
+            if (v >= d) { d = v; b = unit_types[n].build_cost + 40; }
           } /* let's hope this works! */
           if (!is_ground_unit(punit) && !is_heli_unit(punit) &&
               !TEST_BIT(acity->ai.invasion, 0)) b -= 40; /* boats can't conquer cities */
Index: ai/aiunit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.h,v
retrieving revision 1.32
diff -u -r1.32 aiunit.h
--- ai/aiunit.h	2002/03/01 14:07:29	1.32
+++ ai/aiunit.h	2002/03/06 14:44:15
@@ -48,6 +48,9 @@
 int unit_belligerence(struct unit *punit);
 int unit_vulnerability_basic(struct unit *punit, struct unit *pdef);
 int unit_vulnerability_virtual(struct unit *punit);
+int unit_vulnerability_virtual2(Unit_Type_id att_type, Unit_Type_id def_type,
+				int x, int y, bool fortified, bool veteran,
+				bool use_alternative_hp, int alternative_hp);
 int unit_vulnerability(struct unit *punit, struct unit *pdef);
 int kill_desire(int benefit, int attack, int loss, int vuln, int attack_count);
 int military_amortize(int value, int delay, int build_cost);
Index: common/combat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v
retrieving revision 1.20
diff -u -r1.20 combat.c
--- common/combat.c	2002/03/01 14:07:30	1.20
+++ common/combat.c	2002/03/06 14:44:19
@@ -266,27 +266,29 @@
 }
 
 /**************************************************************************
-  returns the defense power, modified by terrain and veteran status
+  Returns the defense power, modified by veteran status.
 **************************************************************************/
-int get_defense_power(struct unit *punit)
+int base_get_defense_power(struct unit *punit)
 {
-  int power;
-  enum tile_terrain_type terra;
-  int db;
-
-  if (!punit || punit->type<0 || punit->type>=U_LAST
-      || punit->type>=game.num_unit_types)
-    abort();
-  power = unit_type(punit)->defense_strength * POWER_FACTOR;
+  int power = unit_type(punit)->defense_strength * POWER_FACTOR;
   if (punit->veteran) {
-    power *= 3;
-    power /= 2;
+    power = (power * 3) / 2;
   }
-  terra=map_get_terrain(punit->x, punit->y);
-  db = get_tile_type(terra)->defense_bonus;
-  if (map_has_special(punit->x, punit->y, S_RIVER))
+  return power;
+}
+
+/**************************************************************************
+  Returns the defense power, modified by terrain and veteran status.
+**************************************************************************/
+int get_defense_power(struct unit *punit)
+{
+  int db, power = base_get_defense_power(punit);
+
+  db = get_tile_type(map_get_terrain(punit->x, punit->y))->defense_bonus;
+  if (map_has_special(punit->x, punit->y, S_RIVER)) {
     db += (db * terrain_control.river_defense_bonus) / 100;
-  power=(power*db)/10;
+  }
+  power = (power * db) / 10;
 
   return power;
 }
@@ -302,81 +304,95 @@
   return attackpower;
 }
 
-/***************************************************************************
- Like get_virtual_defense_power, but don't include most of the modifications.
- (For calls which used to be g_v_d_p(U_HOWITZER,...))
- Specifically, include:
- unit def, terrain effect, fortress effect, ground unit in city effect
-***************************************************************************/
-int get_simple_defense_power(Unit_Type_id d_type, int x, int y)
+/**************************************************************************
+ Return an increased defensepower. Effects which increase the
+ defensepower are:
+  - unit type effects (horse vs pikemen for example)
+  - defender in a fortress
+  - fortified defender
+
+May be called with a non-existing att_type to avoid any unit type
+effects.
+**************************************************************************/
+static int defence_multiplication(Unit_Type_id att_type,
+				  Unit_Type_id def_type, int x, int y,
+				  int defensepower, bool fortified)
 {
-  int defensepower=unit_types[d_type].defense_strength;
   struct city *pcity = map_get_city(x, y);
-  enum tile_terrain_type t = map_get_terrain(x, y);
-  int db;
 
-  if (unit_types[d_type].move_type == LAND_MOVING && t == T_OCEAN) return 0;
-/* I had this dorky bug where transports with mech inf aboard would go next
-to enemy ships thinking the mech inf would defend them adequately. -- Syela */
+  if (unit_type_exists(att_type)) {
+    if (unit_type_flag(def_type, F_PIKEMEN)
+	&& unit_type_flag(att_type, F_HORSE)) {
+      defensepower *= 2;
+    }
+
+    if (unit_type_flag(def_type, F_AEGIS) &&
+	(is_air_unittype(att_type) || is_heli_unittype(att_type))) {
+      defensepower *= 5;
+    }
+
+    if (is_air_unittype(att_type) && pcity) {
+      if (city_got_building(pcity, B_SAM)) {
+	defensepower *= 2;
+      }
+      if (city_got_building(pcity, B_SDI)
+	  && unit_type_flag(att_type, F_MISSILE)) {
+	defensepower *= 2;
+      }
+    } else if (is_water_unit(att_type) && pcity) {
+      if (city_got_building(pcity, B_COASTAL)) {
+	defensepower *= 2;
+      }
+    }
+    if (!unit_type_flag(att_type, F_IGWALL)
+	&& (is_ground_unittype(att_type) || is_heli_unittype(att_type)
+	    || (improvement_variant(B_CITY) == 1
+		&& is_water_unit(att_type))) && pcity
+	&& city_got_citywalls(pcity)) {
+      defensepower *= 3;
+    }
+  }
 
-  db = get_tile_type(t)->defense_bonus;
-  if (map_has_special(x, y, S_RIVER))
-    db += (db * terrain_control.river_defense_bonus) / 100;
-  defensepower *= db;
+  if (map_has_special(x, y, S_FORTRESS) && !pcity) {
+    defensepower +=
+	(defensepower * terrain_control.fortress_defense_bonus) / 100;
+  }
 
-  if (map_has_special(x, y, S_FORTRESS) && !pcity)
-    defensepower+=(defensepower*terrain_control.fortress_defense_bonus)/100;
-  if (pcity && unit_types[d_type].move_type == LAND_MOVING)
-    defensepower*=1.5;
+  if ((pcity || fortified) && is_ground_unittype(def_type)) {
+    defensepower = (defensepower * 3) / 2;
+  }
 
   return defensepower;
 }
 
 /**************************************************************************
-...
+ May be called with a non-existing att_type to avoid any effects which
+ depend on the attacker.
 **************************************************************************/
-int get_virtual_defense_power(Unit_Type_id a_type, Unit_Type_id d_type, int x, int y)
+int get_virtual_defense_power(Unit_Type_id att_type, Unit_Type_id def_type,
+			      int x, int y, bool fortified, bool veteran)
 {
-  int defensepower=unit_types[d_type].defense_strength;
-  enum unit_move_type m_type = unit_types[a_type].move_type;
-  struct city *pcity = map_get_city(x, y);
+  int defensepower = unit_types[def_type].defense_strength;
   enum tile_terrain_type t = map_get_terrain(x, y);
   int db;
 
-  if (unit_types[d_type].move_type == LAND_MOVING && t == T_OCEAN) return 0;
-/* I had this dorky bug where transports with mech inf aboard would go next
-to enemy ships thinking the mech inf would defend them adequately. -- Syela */
+  if (unit_types[def_type].move_type == LAND_MOVING && t == T_OCEAN) {
+    /* Ground units on ship doesn't defend. */
+    return 0;
+  }
 
   db = get_tile_type(t)->defense_bonus;
-  if (map_has_special(x, y, S_RIVER))
+  if (map_has_special(x, y, S_RIVER)) {
     db += (db * terrain_control.river_defense_bonus) / 100;
+  }
   defensepower *= db;
 
-  if (unit_type_flag(d_type, F_PIKEMEN) && unit_type_flag(a_type, F_HORSE)) 
-    defensepower*=2;
-  if (unit_type_flag(d_type, F_AEGIS) &&
-       (m_type == AIR_MOVING || m_type == HELI_MOVING)) defensepower*=5;
-  if (m_type == AIR_MOVING && pcity) {
-    if (city_got_building(pcity, B_SAM))
-      defensepower*=2;
-    if (city_got_building(pcity, B_SDI) && unit_type_flag(a_type, F_MISSILE))
-      defensepower*=2;
-  } else if (m_type == SEA_MOVING && pcity) {
-    if (city_got_building(pcity, B_COASTAL))
-      defensepower*=2;
-  }
-  if (!unit_type_flag(a_type, F_IGWALL)
-      && (m_type == LAND_MOVING || m_type == HELI_MOVING
-	  || (improvement_variant(B_CITY)==1 && m_type == SEA_MOVING))
-      && pcity && city_got_citywalls(pcity)) {
-    defensepower*=3;
-  }
-  if (map_has_special(x, y, S_FORTRESS) && !pcity)
-    defensepower+=(defensepower*terrain_control.fortress_defense_bonus)/100;
-  if (pcity && unit_types[d_type].move_type == LAND_MOVING)
-    defensepower*=1.5;
+  if (veteran) {
+    defensepower = (defensepower * 3) / 2;
+  }
 
-  return defensepower;
+  return defence_multiplication(att_type, def_type, x, y, defensepower,
+				fortified);
 }
 
 /***************************************************************************
@@ -386,33 +402,10 @@
 ***************************************************************************/
 int get_total_defense_power(struct unit *attacker, struct unit *defender)
 {
-  int defensepower=get_defense_power(defender);
-  if (unit_flag(defender, F_PIKEMEN) && unit_flag(attacker, F_HORSE)) 
-    defensepower*=2;
-  if (unit_flag(defender, F_AEGIS)
-      && (is_air_unit(attacker) || is_heli_unit(attacker)))
-    defensepower *= 5;
-  if (is_air_unit(attacker)) {
-    if (unit_behind_sam(defender))
-      defensepower*=2;
-    if (unit_behind_sdi(defender) && unit_flag(attacker, F_MISSILE))
-      defensepower*=2;
-  } else if (is_sailing_unit(attacker)) {
-    if (unit_behind_coastal(defender))
-      defensepower*=2;
-  }
-  if (!unit_really_ignores_citywalls(attacker)
-      && unit_behind_walls(defender)) 
-    defensepower*=3;
-  if (unit_on_fortress(defender) && 
-      !map_get_city(defender->x, defender->y)) 
-    defensepower*=2;
-  if ((defender->activity == ACTIVITY_FORTIFIED || 
-       map_get_city(defender->x, defender->y)) && 
-      is_ground_unit(defender))
-    defensepower*=1.5;
-
-  return defensepower;
+  return defence_multiplication(attacker->type, defender->type,
+				defender->x, defender->y,
+				get_defense_power(defender),
+				defender->activity == ACTIVITY_FORTIFIED);
 }
 
 /**************************************************************************
Index: common/combat.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/combat.h,v
retrieving revision 1.5
diff -u -r1.5 combat.h
--- common/combat.h	2002/03/01 14:07:31	1.5
+++ common/combat.h	2002/03/06 14:44:19
@@ -43,10 +43,11 @@
 
 int get_attack_power(struct unit *punit);
 int base_get_attack_power(Unit_Type_id type, bool veteran, int moves_left);
+int base_get_defense_power(struct unit *punit);
 int get_defense_power(struct unit *punit);
 int get_total_defense_power(struct unit *attacker, struct unit *defender);
-int get_simple_defense_power(Unit_Type_id d_type, int x, int y);
-int get_virtual_defense_power(Unit_Type_id a_type, Unit_Type_id d_type, int x, int y);
+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);
 
 struct unit *get_defender(struct unit *attacker, int x, int y);
Index: server/gotohand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
retrieving revision 1.141
diff -u -r1.141 gotohand.c
--- server/gotohand.c	2002/02/27 11:12:50	1.141
+++ server/gotohand.c	2002/03/06 14:44:21
@@ -888,7 +888,7 @@
 			    const int dest_x, const int dest_y)
 {
 #define UNIT_DEFENSE(punit, x, y, defence_multiplier) \
-  ((get_simple_defense_power((punit)->type, (x), (y)) * \
+  ((get_virtual_defense_power(U_LAST, (punit)->type, (x), (y), FALSE, FALSE) *\
     (defence_multiplier)) / 2)
 
 #define UNIT_RATING(punit, x, y, defence_multiplier) \
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.165
diff -u -r1.165 unittools.c
--- server/unittools.c	2002/03/05 15:46:28	1.165
+++ server/unittools.c	2002/03/06 14:44:23
@@ -1276,7 +1276,7 @@
       continue;
     if (unit_list_size(&ptile->units) > 0)
       continue;
-    value = get_simple_defense_power(u_type, x1, y1);
+    value = get_virtual_defense_power(U_LAST, u_type, x1, y1, FALSE, FALSE);
     value *= 10;
 
     if (ptile->continent != map_get_continent(pcity->x, pcity->y))