Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2005:
[Freeciv-Dev] (PR#14277) unitclass req and merge of defend types
Home

[Freeciv-Dev] (PR#14277) unitclass req and merge of defend types

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#14277) unitclass req and merge of defend types
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 11 Oct 2005 22:17:18 -0700
Reply-to: bugs@xxxxxxxxxxx

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

This patch:

1.  Adds a new req type, unitclass.

2.  Merges the defend types (Sea_Defend, etc.) into one effect 
Defend_Bonus (which of course uses the unitclass req).  The AI changes 
here are...tricky.

3.  Includes my reworking of the defensive buildings so that they are 
all sequential.

This isn't ready for committing.  It should probably be split into 3 
separate patches.

-jason

Index: doc/README.effects
===================================================================
--- doc/README.effects  (revision 11108)
+++ doc/README.effects  (working copy)
@@ -88,6 +88,9 @@
 
 "Incite_Cost_Pct" - increases revolt cost by AMOUNT percent
 
+"Defend_Bonus"  - Increases defensive bonuses of units.  Any unit requirements
+                  on this effect will be applied to the _attacking_ unit.
+
 "Size_Adj"      - Increases maximum city size by AMOUNT
 
 "Size_Unlimit" - Removes maximum city size limitation
Index: server/gotohand.c
===================================================================
--- server/gotohand.c   (revision 11108)
+++ server/gotohand.c   (working copy)
@@ -1017,12 +1017,9 @@
      */
     defence_multiplier = 2;
     if (pcity) {
-      /* This isn't very accurate. */
-      defence_multiplier += (get_city_bonus(pcity, EFT_LAND_DEFEND)
-                            + get_city_bonus(pcity, EFT_MISSILE_DEFEND)
-                            + get_city_bonus(pcity, EFT_AIR_DEFEND)
-                            + get_city_bonus(pcity, EFT_SEA_DEFEND)) / 100;
+      defence_multiplier += get_city_bonus(pcity, EFT_DEFEND_BONUS) / 100;
     }
+    defence_multiplier = MAX(1, defence_multiplier); /* no division by 0 */
 
     /* 
      * Find the best ally unit at the target tile.
Index: server/cityturn.c
===================================================================
--- server/cityturn.c   (revision 11108)
+++ server/cityturn.c   (working copy)
@@ -793,6 +793,7 @@
              break;
            case REQ_UNITTYPE:
            case REQ_UNITFLAG:
+           case REQ_UNITCLASS:
            case REQ_OUTPUTTYPE:
            case REQ_SPECIALIST:
              /* Will only happen with a bogus ruleset. */
Index: data/civ2/effects.ruleset
===================================================================
--- data/civ2/effects.ruleset   (revision 11108)
+++ data/civ2/effects.ruleset   (working copy)
@@ -535,11 +535,12 @@
     }
 
 [effect_city_walls]
-name   = "Land_Defend"
+name   = "Defend_Bonus"
 value  = 200
 reqs   =
     { "type", "name", "range"
       "Building", "City Walls", "City"
+      "UnitClass", "Land", "Local"
     }
 nreqs  =
     { "type", "name", "range"
@@ -555,11 +556,12 @@
     }
 
 [effect_coastal_defense]
-name   = "Sea_Defend"
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
       "Building", "Coastal Defense", "City"
+      "UnitClass", "Sea", "Local"
     }
 
 [effect_colosseum]
@@ -932,11 +934,12 @@
     }
 
 [effect_sam_battery]
-name   = "Air_Defend"
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
       "Building", "SAM Battery", "City"
+      "UnitClass", "Air", "Local"
     }
 
 [effect_sdi_defense]
@@ -948,11 +951,12 @@
     }
 
 [effect_sdi_defense_1]
-name   = "Missile_Defend"
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
       "Building", "SDI Defense", "City"
+      "UnitClass", "Missile", "Local"
     }
 
 [effect_sewer_system]
@@ -1122,11 +1126,12 @@
     }
 
 [effect_great_wall]
-name   = "Land_Defend"
+name   = "Defend_Bonus"
 value  = 200
 reqs   =
     { "type", "name", "range"
       "Building", "Great Wall", "Player"
+      "UnitClass", "Land", "Local"
     }
 
 [effect_great_wall_1]
Index: data/default/effects.ruleset
===================================================================
--- data/default/effects.ruleset        (revision 11108)
+++ data/default/effects.ruleset        (working copy)
@@ -534,8 +534,8 @@
     }
 
 [effect_city_walls]
-name   = "Land_Defend"
-value  = 200
+name   = "Defend_Bonus"
+value  = 100
 reqs   =
     { "type", "name", "range"
       "Building", "City Walls", "City"
@@ -553,12 +553,12 @@
       "Building", "City Walls", "City"
     }
 
-[effect_coastal_defense]
-name   = "Sea_Defend"
+[effect_city_fortress]
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
-      "Building", "Coastal Defense", "City"
+      "Building", "City Fortress", "City"
     }
 
 [effect_colosseum]
@@ -961,28 +961,28 @@
       "OutputType", "Science", "Local"
     }
 
-[effect_sam_battery]
-name   = "Air_Defend"
+[effect_rocket_defense]
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
-      "Building", "SAM Battery", "City"
+      "Building", "Rocket Defense", "City"
     }
 
-[effect_sdi_defense]
+[effect_laser_defense]
 name   = "Nuke_Proof"
 value  = 100
 reqs   =
     { "type", "name", "range"
-      "Building", "SDI Defense", "City"
+      "Building", "Laser Defense", "City"
     }
 
-[effect_sdi_defense_1]
-name   = "Missile_Defend"
+[effect_laser_defense_1]
+name   = "Defend_Bonus"
 value  = 100
 reqs   =
     { "type", "name", "range"
-      "Building", "SDI Defense", "City"
+      "Building", "Laser Defense", "City"
     }
 
 [effect_sewer_system]
@@ -1184,8 +1184,8 @@
     }
 
 [effect_great_wall]
-name   = "Land_Defend"
-value  = 200
+name   = "Defend_Bonus"
+value  = 50
 reqs   =
     { "type", "name", "range"
       "Building", "Great Wall", "Player"
Index: data/default/buildings.ruleset
===================================================================
--- data/default/buildings.ruleset      (revision 11108)
+++ data/default/buildings.ruleset      (working copy)
@@ -216,38 +216,36 @@
 graphic        = "b.city_walls"
 graphic_alt    = "-"
 obsolete_by    = "None"
-build_cost     = 60
-upkeep         = 0
+build_cost     = 30
+upkeep         = 1
 sabotage       = 50
 sound          = "b_city_walls"
 sound_alt      = "b_generic"
 helptext       = _("\
-City Walls make it easier to defend a city.  They triple the defence\
- strength of units within the city against ground and helicopter\
- units.  They are ineffective against airborne and sea units as well\
- as Howitzers.  City Walls also prevent the loss of population which\
- occurs when a defending unit is destroyed by a land unit.\
+City Walls make it easier to defend a city.  They double the defence\
+ strength of units within the city against all attacks, and prevent\
+ the city from losing population when it is attacked.\
 ")
 
-[building_coastal_defense]
-name           = _("Coastal Defense")
+[building_city_fortress]
+name           = _("City Fortress")
 genus          = "Improvement"
+flags          = "VisibleByOthers"
 reqs   =
     { "type", "name", "range"
       "Tech", "Metallurgy", "Player"
-      "Terrain", "Ocean", "Adjacent"
     }
-graphic        = "b.coastal_defense"
-graphic_alt    = "-"
+graphic                = "b.city_fortress"
+graphic_alt    = "b.coastal_defense"
 obsolete_by    = "None"
 build_cost     = 60
-upkeep         = 1
+upkeep         = 2
 sabotage       = 100
-sound          = "b_coastal_defense"
-sound_alt      = "b_generic"
+sound          = "b_city_fortress"
+sound_alt      = "b_city_walls"
 helptext       = _("\
-Increases the defence strength of units within a city by a factor\
- of 2 when defending against bombardments from enemy ships.\
+Increases the defence strength of units within a city by 100%.\
+ Cumulative with city walls.
 ")
 
 [building_colosseum]
@@ -682,46 +680,50 @@
  the science production of a city by 450%.\
 ")
 
-[building_sam_battery]
-name           = _("SAM Battery")
+[building_rocket_defense]
+name           = _("Rocket Defense")
 genus          = "Improvement"
+flags          = "VisibleByOthers"
 reqs   =
     { "type", "name", "range"
       "Tech", "Rocketry", "Player"
     }
-graphic        = "b.sam_battery"
-graphic_alt    = "-"
+graphic                = "b.rocket_defenses"
+graphic_alt    = "b.sam_battery"
 obsolete_by    = "None"
-build_cost     = 70
-upkeep         = 2
+build_cost     = 90
+upkeep         = 3
 sabotage       = 100
-sound          = "b_sam_battery"
-sound_alt      = "b_generic"
+sound          = "b_rocket_defense"
+sound_alt      = "b_city_walls"
 helptext       = _("\
-Doubles the defense of all units inside the city when attacked by\
- non-nuclear air units.\
+Increases the defence strength of units within a city by 100%.\
+ Cumulative with city walls and city fortress.
 ")
 
-[building_sdi_defense]
-name           = _("SDI Defense")
+[building_laser_defense]
+name           = _("Laser Defense")
 genus          = "Improvement"
+flags          = "VisibleByOthers"
 reqs   =
     { "type", "name", "range"
       "Tech", "Laser", "Player"
     }
+graphic        = "b.laser_defense"
 graphic        = "b.sdi_defense"
-graphic_alt    = "-"
 obsolete_by    = "None"
-build_cost     = 140
+build_cost     = 120
 upkeep         = 4
 sabotage       = 100
-sound          = "b_sdi_defense"
-sound_alt      = "b_generic"
+sound          = "b_laser_defense"
+sound_alt      = "b_city_walls"
 helptext       = _("\
-Protects a city from attacks from Nuclear units.  Nuclear attacks\
- simply have no effect on the city.  Also, doubles defence against\
- non-nuclear missiles.\
+Increases the defence strength of units within a city by 100%.\
+ Cumulative with city walls, city fortress, and rocket defense. Also\
+ protects against nuclear attacks.\
 ")
+
+
 ; NOTE:
 ; Civ2 does not document the "Unit_Defend"/"Missile" aspect; does it apply or 
not?
 
@@ -1115,14 +1117,15 @@
     }
 graphic        = "b.great_wall"
 graphic_alt    = "-"
-obsolete_by    = "Metallurgy"
+obsolete_by    = "None"
 build_cost     = 300
 upkeep         = 0
 sabotage       = 0
 sound          = "w_great_wall"
 sound_alt      = "w_generic"
 helptext       = _("\
-Works as a City Wall in all your cities.\
+Adds +50%% to defensive strength of units in cities (cumulative with
+ City Walls).\
 ")
 ; NOTE:
 ; Civ2 also doubles attack -vs- barbs,
Index: common/combat.c
===================================================================
--- common/combat.c     (revision 11108)
+++ common/combat.c     (working copy)
@@ -259,7 +259,8 @@
 
   if (unit_flag(attacker, F_BADWALLATTACKER)
       && pcity 
-      && get_city_bonus(pcity, EFT_LAND_DEFEND) > 0) {
+      && get_city_unittype_bonus(pcity, attacker->type,
+                                EFT_DEFEND_BONUS) > 0) {
     *att_fp = 1;
   }
 
@@ -451,26 +452,12 @@
        (is_air_unittype(att_type) || is_heli_unittype(att_type))) {
       defensepower *= 5;
     }
-         
-    if (is_air_unittype(att_type) && pcity) {
-      if ((mod = get_city_bonus(pcity, EFT_AIR_DEFEND)) > 0) {
-       defensepower = defensepower * (100 + mod) / 100;
-      }
-      if ((mod = get_city_bonus(pcity, EFT_MISSILE_DEFEND)) > 0
-         && unit_type_flag(att_type, F_MISSILE)) {
-       defensepower = defensepower * (100 + mod) / 100;
-      }
-    } else if (is_sailing_unittype(att_type) && pcity) {
-      if ((mod = get_city_bonus(pcity, EFT_SEA_DEFEND)) > 0) {
-       defensepower = defensepower * (100 + mod) / 100;
-      }
+
+    if (!unit_type_flag(att_type, F_IGWALL)) {
+      /* This applies even if pcity is NULL. */
+      mod = 100 + get_city_unittype_bonus(pcity, att_type, EFT_DEFEND_BONUS);
+      defensepower = MAX(0, defensepower * mod / 100);
     }
-    if (!unit_type_flag(att_type, F_IGWALL)
-       && (is_ground_unittype(att_type) || is_heli_unittype(att_type))
-        && pcity
-        && (mod = get_city_bonus(pcity, EFT_LAND_DEFEND)) > 0) {
-      defensepower = defensepower * (100 + mod) / 100;
-    }
 
     if (unit_type_flag(att_type, F_FIGHTER) && is_heli_unittype(def_type)) {
       defensepower /= 2;
Index: common/city.c
===================================================================
--- common/city.c       (revision 11108)
+++ common/city.c       (working copy)
@@ -971,7 +971,7 @@
 **************************************************************************/
 bool city_got_citywalls(const struct city *pcity)
 {
-  return (get_city_bonus(pcity, EFT_LAND_DEFEND) > 0);
+  return (get_city_bonus(pcity, EFT_DEFEND_BONUS) > 0);
 }
 
 /**************************************************************************
Index: common/capstr.c
===================================================================
--- common/capstr.c     (revision 11108)
+++ common/capstr.c     (working copy)
@@ -82,7 +82,7 @@
  *     as long as possible.  We want to maintain network compatibility with
  *     the stable branch for as long as possible.
  */
-#define CAPABILITY "+Freeciv.Devel.2005.Oct.4"
+#define CAPABILITY "+Freeciv.Devel.2005.Oct.11"
 
 void init_our_capability(void)
 {
Index: common/effects.c
===================================================================
--- common/effects.c    (revision 11108)
+++ common/effects.c    (working copy)
@@ -95,10 +95,7 @@
   "Land_Regen",
   "Sea_Regen",
   "Air_Regen",
-  "Land_Defend",
-  "Sea_Defend",
-  "Air_Defend",
-  "Missile_Defend",
+  "Defend_Bonus",
   "No_Incite",
   "Gain_AI_Love",
   "Slow_Down_Timeline",
@@ -544,14 +541,14 @@
                        const struct city *target_city,
                        const struct impr_type *target_building,
                        const struct tile *target_tile,
-                       const struct unit *target_unit,
+                       const struct unit_type *target_unittype,
                        const struct output_type *target_output,
                        const struct specialist *target_specialist,
                        const struct effect *peffect)
 {
   requirement_list_iterate(peffect->nreqs, preq) {
     if (is_req_active(target_player, target_city, target_building,
-                     target_tile, target_unit, target_output,
+                     target_tile, target_unittype, target_output,
                      target_specialist,
                      preq)) {
       return TRUE;
@@ -569,14 +566,14 @@
                              const struct city *target_city,
                              const struct impr_type *target_building,
                              const struct tile *target_tile,
-                             const struct unit *target_unit,
+                             const struct unit_type *target_unittype,
                              const struct output_type *target_output,
                              const struct specialist *target_specialist,
                              const struct effect *peffect)
 {
   requirement_list_iterate(peffect->reqs, preq) {
     if (!is_req_active(target_player, target_city, target_building,
-                      target_tile, target_unit, target_output,
+                      target_tile, target_unittype, target_output,
                       target_specialist,
                       preq)) {
       return FALSE;
@@ -598,17 +595,17 @@
                             const struct city *target_city,
                             const struct impr_type *target_building,
                             const struct tile *target_tile,
-                            const struct unit *target_unit,
+                            const struct unit_type *target_unittype,
                             const struct output_type *target_output,
                             const struct specialist *target_specialist,
                             const struct effect *peffect)
 {
   return is_effect_enabled(target_player, target_city, target_building,
-                          target_tile, target_unit, target_output,
+                          target_tile, target_unittype, target_output,
                           target_specialist,
                           peffect)
     && !is_effect_disabled(target_player, target_city, target_building,
-                          target_tile, target_unit, target_output,
+                          target_tile, target_unittype, target_output,
                           target_specialist,
                           peffect);
 }
@@ -629,13 +626,13 @@
                      const struct city *target_city,
                      const struct impr_type *target_building,
                      const struct tile *target_tile,
-                     const struct unit *target_unit,
+                     const struct unit_type *target_unittype,
                      const struct output_type *target_output,
                      const struct specialist *target_specialist,
                      Impr_type_id source, const struct effect *peffect)
 {
   if (is_effect_disabled(target_player, target_city, target_building,
-                        target_tile, target_unit, target_output,
+                        target_tile, target_unittype, target_output,
                         target_specialist,
                         peffect)) {
     return FALSE;
@@ -646,7 +643,7 @@
       continue;
     }
     if (!is_req_active(target_player, target_city, target_building,
-                      target_tile, target_unit, target_output,
+                      target_tile, target_unittype, target_output,
                       target_specialist,
                       preq)) {
       return FALSE;
@@ -705,7 +702,7 @@
                                    const struct city *target_city,
                                    const struct impr_type *target_building,
                                    const struct tile *target_tile,
-                                   const struct unit *target_unit,
+                                   const struct unit_type *target_unittype,
                                    const struct output_type *target_output,
                                    const struct specialist *target_specialist,
                                    enum effect_type effect_type)
@@ -716,7 +713,7 @@
   effect_list_iterate(get_effects(effect_type), peffect) {
     /* For each effect, see if it is active. */
     if (is_effect_active(target_player, target_city, target_building,
-                        target_tile, target_unit, target_output,
+                        target_tile, target_unittype, target_output,
                         target_specialist,
                         peffect)) {
       /* And if so add on the value. */
@@ -829,6 +826,28 @@
 }
 
 /**************************************************************************
+  Returns the effect bonus that applies at a city for a given unittype.
+
+  For instance with EFT_DEFEND_BONUS the attacker's unittype and the
+  defending city should be passed in.  Slightly counter-intuitive!
+  See doc/README.effects to see how the unittype applies for each effect
+  here.
+**************************************************************************/
+int get_city_unittype_bonus(const struct city *pcity,
+                           const struct unit_type *punittype,
+                           enum effect_type effect_type)
+{
+  struct player *pplayer = pcity ? pcity->owner : NULL;
+  struct tile *ptile = pcity ? pcity->tile : NULL;
+
+  /* pcity may be NULL. */
+  assert(punittype != NULL);
+  return get_target_bonus_effects(NULL,
+                                 pplayer, pcity, NULL, ptile,
+                                 punittype, NULL, NULL, effect_type);
+}
+
+/**************************************************************************
   Returns the effect bonus at a building.
 **************************************************************************/
 int get_unit_bonus(const struct unit *punit, enum effect_type effect_type)
@@ -836,7 +855,7 @@
   assert(punit != NULL);
   return get_target_bonus_effects(NULL,
                                  unit_owner(punit), NULL, NULL,
-                                 NULL, punit, NULL, NULL,
+                                 NULL, punit->type, NULL, NULL,
                                  effect_type);
 }
 
Index: common/effects.h
===================================================================
--- common/effects.h    (revision 11108)
+++ common/effects.h    (working copy)
@@ -83,10 +83,7 @@
   EFT_LAND_REGEN,
   EFT_SEA_REGEN,
   EFT_AIR_REGEN,
-  EFT_LAND_DEFEND,
-  EFT_SEA_DEFEND,
-  EFT_AIR_DEFEND,
-  EFT_MISSILE_DEFEND,
+  EFT_DEFEND_BONUS,
   EFT_NO_INCITE,
   EFT_GAIN_AI_LOVE,
   EFT_SLOW_DOWN_TIMELINE,
@@ -161,7 +158,7 @@
                      const struct city *target_pcity,
                      const struct impr_type *target_building,
                      const struct tile *target_tile,
-                     const struct unit *target_unit,
+                     const struct unit_type *target_unittype,
                      const struct output_type *target_output,
                      const struct specialist *target_specialist,
                      Impr_type_id source, const struct effect *effect);
@@ -182,6 +179,9 @@
                               enum effect_type effect_type);
 int get_building_bonus(const struct city *pcity, Impr_type_id building,
                       enum effect_type effect_type);
+int get_city_unittype_bonus(const struct city *pcity,
+                           const struct unit_type *punittype,
+                           enum effect_type effect_type);
 int get_unit_bonus(const struct unit *punit, enum effect_type effect_type);
 
 /* miscellaneous auxiliary effects functions */
@@ -190,7 +190,7 @@
                        const struct city *target_city,
                        const struct impr_type *target_building,
                        const struct tile *target_tile,
-                       const struct unit *target_unit,
+                       const struct unit_type *target_unittype,
                        const struct output_type *target_output,
                        const struct specialist *target_specialist,
                        const struct effect *peffect);
Index: common/requirements.c
===================================================================
--- common/requirements.c       (revision 11108)
+++ common/requirements.c       (working copy)
@@ -38,6 +38,7 @@
   "Nation",
   "UnitType",
   "UnitFlag",
+  "UnitClass",
   "OutputType",
   "Specialist",
   "MinSize"
@@ -150,6 +151,12 @@
       return source;
     }
     break;
+  case REQ_UNITCLASS:
+    source.value.unitclass = unit_class_from_str(value);
+    if (source.value.unitclass) {
+      return source;
+    }
+    break;
   case REQ_OUTPUTTYPE:
     source.value.outputtype = find_output_type_by_identifier(value);
     if (source.value.outputtype != O_LAST) {
@@ -213,6 +220,9 @@
   case REQ_UNITFLAG:
     source.value.unitflag = value;
     return source;
+  case REQ_UNITCLASS:
+    source.value.unitclass = unit_class_get_by_id(value);
+    return source;
   case REQ_OUTPUTTYPE:
     source.value.outputtype = value;
     return source;
@@ -269,6 +279,9 @@
   case REQ_UNITFLAG:
     *value = source->value.unitflag;
     return;
+  case REQ_UNITCLASS:
+    *value = source->value.unitclass->id;
+    return;
   case REQ_OUTPUTTYPE:
     *value = source->value.outputtype;
     return;
@@ -315,6 +328,7 @@
     case REQ_TERRAIN:
     case REQ_UNITTYPE:
     case REQ_UNITFLAG:
+    case REQ_UNITCLASS:
     case REQ_OUTPUTTYPE:
     case REQ_SPECIALIST:
       req.range = REQ_RANGE_LOCAL;
@@ -362,6 +376,7 @@
     break;
   case REQ_UNITTYPE:
   case REQ_UNITFLAG:
+  case REQ_UNITCLASS:
   case REQ_OUTPUTTYPE:
   case REQ_SPECIALIST:
     invalid = (req.range != REQ_RANGE_LOCAL);
@@ -712,29 +727,40 @@
 /****************************************************************************
   Is there a unit of the given type within range of the target?
 ****************************************************************************/
-static bool is_unittype_in_range(const struct unit *target_unit,
+static bool is_unittype_in_range(const struct unit_type *target_unittype,
                                 enum req_range range, bool survives,
                                 struct unit_type *punittype)
 {
   return (range == REQ_RANGE_LOCAL
-         && target_unit
-         && punittype
-         && target_unit->type == punittype);
+         && target_unittype
+         && target_unittype == punittype);
 }
 
 /****************************************************************************
   Is there a unit with the given flag within range of the target?
 ****************************************************************************/
-static bool is_unitflag_in_range(const struct unit *target_unit,
+static bool is_unitflag_in_range(const struct unit_type *target_unittype,
                                 enum req_range range, bool survives,
                                 enum unit_flag_id unitflag)
 {
   return (range == REQ_RANGE_LOCAL
-         && target_unit
-         && unit_flag(target_unit, unitflag));
+         && target_unittype
+         && unit_type_flag(target_unittype, unitflag));
 }
 
 /****************************************************************************
+  Is there a unit with the given flag within range of the target?
+****************************************************************************/
+static bool is_unitclass_in_range(const struct unit_type *target_unittype,
+                                 enum req_range range, bool survives,
+                                 struct unit_class *pclass)
+{
+  return (range == REQ_RANGE_LOCAL
+         && target_unittype
+         && target_unittype->class == pclass);
+}
+
+/****************************************************************************
   Checks the requirement to see if it is active on the given target.
 
   target gives the type of the target
@@ -749,7 +775,7 @@
                   const struct city *target_city,
                   const struct impr_type *target_building,
                   const struct tile *target_tile,
-                  const struct unit *target_unit,
+                  const struct unit_type *target_unittype,
                   const struct output_type *target_output,
                   const struct specialist *target_specialist,
                   const struct requirement *req)
@@ -798,15 +824,20 @@
                              req->source.value.nation);
     break;
   case REQ_UNITTYPE:
-    eval = is_unittype_in_range(target_unit,
+    eval = is_unittype_in_range(target_unittype,
                                req->range, req->survives,
                                req->source.value.unittype);
     break;
   case REQ_UNITFLAG:
-    eval = is_unitflag_in_range(target_unit,
+    eval = is_unitflag_in_range(target_unittype,
                                req->range, req->survives,
                                req->source.value.unitflag);
     break;
+  case REQ_UNITCLASS:
+    eval = is_unitclass_in_range(target_unittype,
+                                req->range, req->survives,
+                                req->source.value.unitclass);
+    break;
   case REQ_OUTPUTTYPE:
     eval = (target_output
            && target_output->index == req->source.value.outputtype);
@@ -847,14 +878,14 @@
                     const struct city *target_city,
                     const struct impr_type *target_building,
                     const struct tile *target_tile,
-                    const struct unit *target_unit,
+                    const struct unit_type *target_unittype,
                     const struct output_type *target_output,
                     const struct specialist *target_specialist,
                     const struct requirement_vector *reqs)
 {
   requirement_vector_iterate(reqs, preq) {
     if (!is_req_active(target_player, target_city, target_building,
-                      target_tile, target_unit, target_output,
+                      target_tile, target_unittype, target_output,
                       target_specialist,
                       preq)) {
       return FALSE;
@@ -887,6 +918,7 @@
   case REQ_MINSIZE:
   case REQ_UNITTYPE: /* Not sure about this one */
   case REQ_UNITFLAG: /* Not sure about this one */
+  case REQ_UNITCLASS: /* Not sure about this one */
     return FALSE;
   case REQ_SPECIAL:
   case REQ_TERRAIN:
@@ -931,6 +963,8 @@
     return psource1->value.unittype == psource2->value.unittype;
   case REQ_UNITFLAG:
     return psource1->value.unitflag == psource2->value.unitflag;
+  case REQ_UNITCLASS:
+    return psource1->value.unitclass == psource2->value.unitclass;
   case REQ_OUTPUTTYPE:
     return psource1->value.outputtype == psource2->value.outputtype;
   case REQ_SPECIALIST:
@@ -981,6 +1015,10 @@
     cat_snprintf(buf, bufsz, _("%s units"),
                 get_unit_flag_name(psource->value.unitflag));
     break;
+  case REQ_UNITCLASS:
+    cat_snprintf(buf, bufsz, _("%s units"),
+                unit_class_name(psource->value.unitclass));
+    break;
   case REQ_OUTPUTTYPE:
     mystrlcat(buf, get_output_name(psource->value.outputtype), bufsz);
     break;
Index: common/requirements.h
===================================================================
--- common/requirements.h       (revision 11108)
+++ common/requirements.h       (working copy)
@@ -31,6 +31,7 @@
   REQ_NATION,
   REQ_UNITTYPE,
   REQ_UNITFLAG,
+  REQ_UNITCLASS,
   REQ_OUTPUTTYPE,
   REQ_SPECIALIST,
   REQ_MINSIZE, /* Minimum size: at city range means city size */
@@ -62,6 +63,7 @@
     struct nation_type *nation;         /* source nation type */
     struct unit_type *unittype;         /* source unittype */
     enum unit_flag_id unitflag;         /* source unit flag */
+    struct unit_class *unitclass;       /* source unit class */
     Output_type_id outputtype;          /* source output type */
     Specialist_type_id specialist;      /* specialist type */
     int minsize;                        /* source minsize type */
@@ -117,7 +119,7 @@
                   const struct city *target_city,
                   const struct impr_type *target_building,
                   const struct tile *target_tile,
-                  const struct unit *target_unit,
+                  const struct unit_type *target_unittype,
                   const struct output_type *target_output,
                   const struct specialist *target_specialist,
                   const struct requirement *req);
@@ -125,7 +127,7 @@
                     const struct city *target_city,
                     const struct impr_type *target_building,
                     const struct tile *target_tile,
-                    const struct unit *target_unit,
+                    const struct unit_type *target_unittype,
                     const struct output_type *target_output,
                     const struct specialist *target_specialist,
                     const struct requirement_vector *reqs);
Index: ai/advdiplomacy.c
===================================================================
--- ai/advdiplomacy.c   (revision 11108)
+++ ai/advdiplomacy.c   (working copy)
@@ -652,8 +652,7 @@
     want += pcity->size * 20;
     want += pcity->surplus[O_SHIELD] * 8;
     want += pcity->surplus[O_TRADE] * 6;
-    fear += get_city_bonus(pcity, EFT_LAND_DEFEND);
-    fear += get_city_bonus(pcity, EFT_SEA_DEFEND);
+    fear += get_city_bonus(pcity, EFT_DEFEND_BONUS);
     built_impr_iterate(pcity, id) {
       want += impr_build_shield_cost(id);
       if (is_great_wonder(id)) {
Index: ai/aicity.c
===================================================================
--- ai/aicity.c (revision 11108)
+++ ai/aicity.c (working copy)
@@ -573,7 +573,7 @@
            v *= 4;
          }
          break;
-       case EFT_SEA_DEFEND:
+       case EFT_DEFEND_BONUS:
          if (ai_handicap(pplayer, H_DEFENSIVE)) {
            v += amount / 10; /* make AI slow */
          }
@@ -591,34 +591,16 @@
            } adjc_iterate_end;
          }
          v += (amount/20 + ai->threats.invasions - 1) * c; /* for wonder */
-         if (capital && ai->threats.invasions) {
-           v += amount; /* defend capital! */
-         }
-         break;
-       case EFT_AIR_DEFEND:
-         if (ai_handicap(pplayer, H_DEFENSIVE)) {
-           v += amount / 15; /* make AI slow */
-         }
-         v += (ai->threats.air && ai->threats.continent[ptile->continent]) 
-           ? amount/10 * 5 + amount/10 * c : c;
-         break;
-       case EFT_MISSILE_DEFEND:
-         if (ai->threats.missile
-             && (ai->threats.continent[ptile->continent] || capital)) {
-           v += amount/10 * 5 + (amount/10 - 1) * c;
-         }
-         break;
-       case EFT_LAND_DEFEND:
-         if (ai_handicap(pplayer, H_DEFENSIVE)) {
-           v += amount / 10; /* make AI slow */
-         }
          if (ai->threats.continent[ptile->continent]
              || capital
              || (ai->threats.invasions
-               && is_water_adjacent_to_tile(pcity->tile))) {
-           v += amount / (!ai->threats.igwall ? (15 - capital * 5) : 15);
+                 && is_water_adjacent_to_tile(pcity->tile))) {
+           if (ai->threats.continent[ptile->continent]) {
+             v += amount;
+           } else {
+             v += amount / (!ai->threats.igwall ? (15 - capital * 5) : 15);
+           }
          }
-         v += (1 + ai->threats.invasions + !ai->threats.igwall) * c;
          break;
        case EFT_NO_INCITE:
          if (get_city_bonus(pcity, EFT_NO_INCITE) <= 0) {
@@ -1062,7 +1044,7 @@
 {
   impr_type_iterate(id) {
     if (can_city_sell_building(pcity, id)
-       && !building_has_effect(id, EFT_LAND_DEFEND)) {
+       && !building_has_effect(id, EFT_DEFEND_BONUS)) {
 /* selling walls to buy defenders is counterproductive -- Syela */
       really_handle_city_sell(pplayer, pcity, id);
       break;
@@ -1356,7 +1338,7 @@
 
   built_impr_iterate(pcity, i) {
     if(can_city_sell_building(pcity, i) 
-       && !building_has_effect(i, EFT_LAND_DEFEND)
+       && !building_has_effect(i, EFT_DEFEND_BONUS)
              /* selling city walls is really, really dumb -- Syela */
        && (is_building_replaced(pcity, i)
           || building_unwanted(city_owner(pcity), i))) {
Index: ai/advmilitary.c
===================================================================
--- ai/advmilitary.c    (revision 11108)
+++ ai/advmilitary.c    (working copy)
@@ -326,6 +326,7 @@
 {
   unsigned int danger;
   bool sailing;
+  int mod;
 
   if (unit_flag(punit, F_NO_LAND_ATTACK)) return 0;
 
@@ -335,12 +336,8 @@
   }
 
   danger = unit_att_rating(punit);
-  if (sailing && get_city_bonus(pcity, EFT_SEA_DEFEND) > 0) {
-    danger /= 2;
-  }
-  if (is_air_unit(punit) && get_city_bonus(pcity, EFT_AIR_DEFEND) > 0) {
-    danger /= 2;
-  }
+  mod = 100 + get_city_unittype_bonus(pcity, punit->type, EFT_DEFEND_BONUS);
+  danger = danger * 100 / MAX(mod, 1);
 
   return danger;
 }
@@ -453,7 +450,7 @@
 static unsigned int assess_danger(struct city *pcity)
 {
   int i;
-  int danger[5], defender[4];
+  int danger[5], defender;
   struct player *pplayer = city_owner(pcity);
   bool pikemen = FALSE;
   unsigned int urgency = 0;
@@ -572,30 +569,12 @@
 
   /* HACK: This needs changing if multiple improvements provide
    * this effect. */
-  defender[0] = ai_find_source_building(pplayer, EFT_LAND_DEFEND);
-  defender[1] = ai_find_source_building(pplayer, EFT_SEA_DEFEND);
-  defender[2] = ai_find_source_building(pplayer, EFT_AIR_DEFEND);
-  defender[3] = ai_find_source_building(pplayer, EFT_MISSILE_DEFEND);
+  defender = ai_find_source_building(pplayer, EFT_DEFEND_BONUS);
 
-  if (defender[0] != B_LAST) {
-    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[0]],
-       urgency, danger[1], assess_defense(pcity));
+  if (defender != B_LAST) {
+    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender],
+       urgency, danger[1], assess_defense_igwall(pcity));
   }
-  if (defender[1] != B_LAST) {
-    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[1]],
-       urgency, danger[2], 
-       assess_defense_igwall(pcity));
-  }
-  if (defender[2] != B_LAST) {
-    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[2]],
-       urgency, danger[3], 
-       assess_defense_igwall(pcity));
-  }
-  if (defender[3] != B_LAST) {
-    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[3]],
-       urgency, danger[4], 
-       assess_defense_igwall(pcity));
-  }
 
   pcity->ai.danger = danger[0];
   pcity->ai.urgency = urgency;
@@ -1290,7 +1269,7 @@
   /* Otherwise no need to defend yet */
   if (pcity->ai.danger != 0) { 
     int num_defenders = unit_list_size(ptile->units);
-    int land_id, sea_id, air_id, danger;
+    int wall_id, danger;
 
     /* First determine the danger.  It is measured in percents of our 
      * defensive strength, capped at 200 + urgency */
@@ -1322,55 +1301,25 @@
 
     /* HACK: This needs changing if multiple improvements provide
      * this effect. */
-    land_id = ai_find_source_building(pplayer, EFT_LAND_DEFEND);
-    sea_id = ai_find_source_building(pplayer, EFT_SEA_DEFEND);
-    air_id = ai_find_source_building(pplayer, EFT_AIR_DEFEND);
+    wall_id = ai_find_source_building(pplayer, EFT_DEFEND_BONUS);
 
-    if (land_id != B_LAST
-       && pcity->ai.building_want[land_id] != 0 && our_def != 0 
-        && can_build_improvement(pcity, land_id)
+    if (wall_id != B_LAST
+       && pcity->ai.building_want[wall_id] != 0 && our_def != 0 
+        && can_build_improvement(pcity, wall_id)
         && (danger < 101 || num_defenders > 1
             || (pcity->ai.grave_danger == 0 
                 && pplayer->economic.gold > (80 - pcity->shield_stock) * 2)) 
         && ai_fuzzy(pplayer, TRUE)) {
       /* NB: great wall is under domestic */
-      choice->choice = land_id;
+      choice->choice = wall_id;
       /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[land_id];
+      choice->want = pcity->ai.building_want[wall_id];
       if (urgency == 0 && choice->want > 100) {
         choice->want = 100;
       }
       choice->type = CT_BUILDING;
-      CITY_LOG(LOG_DEBUG, pcity, "m_a_c_d wants land defense building with %d",
+      CITY_LOG(LOG_DEBUG, pcity, "m_a_c_d wants defense building with %d",
                choice->want);
-    } else if (sea_id != B_LAST
-              && pcity->ai.building_want[sea_id] != 0 && our_def != 0 
-               && can_build_improvement(pcity, sea_id) 
-               && (danger < 101 || num_defenders > 1) 
-               && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = sea_id;
-      /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[sea_id];
-      if (urgency == 0 && choice->want > 100) {
-        choice->want = 100;
-      }
-      choice->type = CT_BUILDING;
-      CITY_LOG(LOG_DEBUG, pcity, "m_a_c_d wants sea defense building with %d",
-               choice->want);
-    } else if (air_id != B_LAST
-              && pcity->ai.building_want[air_id] != 0 && our_def != 0 
-               && can_build_improvement(pcity, air_id) 
-               && (danger < 101 || num_defenders > 1) 
-               && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = air_id;
-      /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[air_id];
-      if (urgency == 0 && choice->want > 100) {
-        choice->want = 100;
-      }
-      choice->type = CT_BUILDING;
-      CITY_LOG(LOG_DEBUG, pcity, "m_a_c_d wants air defense building with %d",
-               choice->want);
     } else if (danger > 0 && num_defenders <= urgency) {
       /* Consider building defensive units units */
       process_defender_want(pplayer, pcity, danger, choice);
Index: client/helpdata.c
===================================================================
--- client/helpdata.c   (revision 11108)
+++ client/helpdata.c   (working copy)
@@ -192,6 +192,10 @@
     cat_snprintf(buf, bufsz, _("Only applies to %s units.\n\n"),
                 get_unit_flag_name(req->source.value.unitflag));
     return;
+  case REQ_UNITCLASS:
+    cat_snprintf(buf, bufsz, _("Only applies to %s units.\n\n"),
+                unit_class_name(req->source.value.unitclass));
+    return;
   case REQ_OUTPUTTYPE:
     cat_snprintf(buf, bufsz, _("Applies only to %s.\n\n"),
                 get_output_name(req->source.value.outputtype));

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