Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2004:
[Freeciv-Dev] (PR#11672) unit reqs
Home

[Freeciv-Dev] (PR#11672) unit reqs

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#11672) unit reqs
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 23 Dec 2004 15:53:08 -0800
Reply-to: bugs@xxxxxxxxxxx

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

Here is a priliminary and incomplete patch that adds reqs 
(requirements.h) for units.  The reqs replace the tech_req, gov_req, and 
bldg_req.

For the core code this is easy.  But for the AI this kind of design 
doesn't work so well.  Most AI code assumes that a unit has just one 
req, so if the unit has a certain want that want can be transferred 
directly to the req.  My code in this patch divides the want among 
several tech reqs but doesn't work well with mixed reqs.  I think we 
want something like:

   void assign_desire_for_reqs(struct requirement *reqs, int desire)
   {
     int count = 0;

     req_iterate(reqs) {
       if (!is_req_active(..., req)) {
         count++;
       }
     } req_iterate_end;
     req_iterate(reqs) {
       if (!is_req_active(..., req)) {
         switch (req.type) {
         case REQ_TECH:
           tech_want[req->value.tech] += desire / count;
           break;
         case REQ_BUILDING:
           building_want[req->value.building] += desire / count;
           break;
         /* etc, etc. */
         }
       }
     } req_iterate_end;
   }

but this is rather complicated since we need to account for the req's 
range and rarity.  As an example we can't really assign a want to a 
terrain req since the AI doesn't know how to satisfy a terrain req: 
instead we should realize that this simply cannot be met.  This is 
additionally a problem since reqs are recursive.  We can assign a desire 
to a building required to build a unit, but if that building requires a 
tech we can't get or a terrain we can't make, then the desire is simply 
lost.  This is the correct thing to do so long as we don't spend effort 
meeting the other requirements.

-jason

Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.124
diff -u -r1.124 advdomestic.c
--- ai/advdomestic.c    10 Dec 2004 21:19:20 -0000      1.124
+++ ai/advdomestic.c    23 Dec 2004 22:27:08 -0000
@@ -126,10 +126,16 @@
           ai_choose_role_unit(pplayer, pcity, choice, F_HELP_WONDER, dist / 2);
         }
       } else {
-        int tech_req = get_unit_type(unit_type)->tech_requirement;
+       int i;
+       struct unit_type *ut = get_unit_type(unit_type);
 
-        /* XXX (FIXME): Had to add the scientist guess here too. -- Syela */
-        pplayer->ai.tech_want[tech_req] += want;
+       for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+         /* FIXME: add wants for other types of reqs. */
+         if (ut->req[i].type == REQ_TECH
+             && ut->req[i].range == REQ_RANGE_PLAYER) {
+           pplayer->ai.tech_want[ut->req[i].value.tech] += want;
+         }
+       }
       }
     }
   } city_list_iterate_end;
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.182
diff -u -r1.182 advmilitary.c
--- ai/advmilitary.c    19 Dec 2004 19:44:39 -0000      1.182
+++ ai/advmilitary.c    23 Dec 2004 22:27:09 -0000
@@ -655,6 +655,48 @@
 }
 
 /************************************************************************** 
+  Return the number of unknown techs required to meet the given reqs.
+  The reqs value is an array of size MAX_NUM_REQS.
+**************************************************************************/
+static int num_unknown_techs_for_reqs(const struct player *pplayer,
+                                     const struct requirement *reqs)
+{
+  int i, tech_dist = 0;
+
+  for (i = 0; i < MAX_NUM_REQS && reqs[i].type != REQ_NONE; i++) {
+    /* This only counts tech reqs; it doesn't recurse into other reqs.  It
+     * will double-count if there is more than one req. */
+    if (reqs[i].type == REQ_TECH) {
+      Tech_Type_id tech = reqs[i].value.tech;
+
+      tech_dist += num_unknown_techs_for_goal(pplayer, tech);
+    }
+  }
+
+  return tech_dist;
+}
+
+/************************************************************************** 
+  Return the number of bulbs required to meet techs in the given reqs.
+  The reqs value is an array of size MAX_NUM_REQS.
+**************************************************************************/
+static int num_unknown_bulbs_for_reqs(const struct player *pplayer,
+                                     const struct requirement *reqs)
+{
+  int i, tech_cost = 0;
+
+  for (i = 0; i < MAX_NUM_REQS && reqs[i].type != REQ_NONE; i++) {
+    if (reqs[i].type == REQ_TECH) {
+      Tech_Type_id tech = reqs[i].value.tech;
+
+      tech_cost += total_bulbs_required_for_goal(pplayer, tech);
+    }
+  }
+
+  return tech_cost;
+}
+
+/************************************************************************** 
   What would be the best defender for that city? Records the best defender 
   type in choice. Also sets the technology want for the units we can't 
   build yet.
@@ -676,8 +718,8 @@
       int move_type = unit_types[unit_type].move_type;
     
       /* How many technologies away it is? */
-      int tech_dist = num_unknown_techs_for_goal(pplayer,
-                        unit_types[unit_type].tech_requirement);
+      int tech_dist = num_unknown_techs_for_reqs(pplayer,
+                               get_unit_type(unit_type)->req);
 
       /* How much we want the unit? */
       int desire = ai_unit_defence_desirability(unit_type);
@@ -708,17 +750,16 @@
           best_unit_type = unit_type;
         }
         
-      } else if (tech_dist > 0 && (shore || move_type == LAND_MOVING)
-                 && unit_types[unit_type].tech_requirement != A_LAST) {
+      } else if (tech_dist > 0 && (shore || move_type == LAND_MOVING)) {
         /* We first need to develop the tech required by the unit... */
+       int tech_cost = num_unknown_bulbs_for_reqs(pplayer,
+                                       get_unit_type(unit_type)->req);
 
         /* Cost (shield equivalent) of gaining these techs. */
         /* FIXME? Katvrr advises that this should be weighted more heavily in
          * big danger. */
-        int tech_cost = total_bulbs_required_for_goal(pplayer,
-                          unit_types[unit_type].tech_requirement) / 4
-                        / city_list_size(&pplayer->cities);
-        
+       tech_cost /= (4 * city_list_size(&pplayer->cities));
+
         /* Contrary to the above, we don't care if walls are actually built 
          * - we're looking into the future now. */
         if (move_type == LAND_MOVING) {
@@ -743,15 +784,30 @@
   /* Update tech_want for appropriate techs for units we want to build. */
   simple_ai_unit_type_iterate (unit_type) {
     if (tech_desire[unit_type] > 0) {
-      Tech_Type_id tech_req = unit_types[unit_type].tech_requirement;
+      int count = 0, i;
+      struct unit_type *ut = get_unit_type(unit_type);
       int desire = tech_desire[unit_type]
                    * unit_build_shield_cost(best_unit_type) / best;
+
+      /* Divide the desire among all tech reqs.  FIXME: we should account
+       * for non-tech reqs as well. */
+      for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+       if (ut->req[i].type == REQ_TECH) {
+         count++;
+       }
+      }
+      assert(count > 0);
+      for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+       if (ut->req[i].type == REQ_TECH) {
+         Tech_Type_id tech_req = ut->req[i].value.tech;
+
+         pplayer->ai.tech_want[tech_req] += desire / count;
       
-      pplayer->ai.tech_want[tech_req] += desire;
-      
-      freelog(LOG_DEBUG, "%s wants %s for defense with desire %d <%d>",
-              pcity->name, get_tech_name(pplayer, tech_req), desire,
-              tech_desire[unit_type]);
+         freelog(LOG_DEBUG, "%s wants %s for defense with desire %d <%d>",
+                 pcity->name, get_tech_name(pplayer, tech_req), desire,
+                 tech_desire[unit_type]);
+       }
+      }
     }
   } simple_ai_unit_type_iterate_end;
   
@@ -808,18 +864,11 @@
   }
 
   simple_ai_unit_type_iterate (unit_type) {
-    Tech_Type_id tech_req = unit_types[unit_type].tech_requirement;
     int move_type = unit_types[unit_type].move_type;
-    int tech_dist;
-    
-    if (tech_req != A_LAST) {
-      tech_dist = num_unknown_techs_for_goal(pplayer, tech_req);
-    } else {
-      tech_dist = 0;
-    }
+    struct unit_type *ut = get_unit_type(unit_type);
+    int tech_dist = num_unknown_techs_for_reqs(pplayer, ut->req);
     
     if ((move_type == LAND_MOVING || (move_type == SEA_MOVING && shore))
-        && tech_req != A_LAST
         && (tech_dist > 0 
             || unit_types[unit_type].obsoleted_by == U_NOT_OBSOLETED
             || !can_build_unit_direct(pcity, 
@@ -832,9 +881,9 @@
       /* Cost (shield equivalent) of gaining these techs. */
       /* FIXME? Katvrr advises that this should be weighted more heavily in big
        * danger. */
-      int tech_cost = total_bulbs_required_for_goal(pplayer,
-                        unit_types[unit_type].tech_requirement) / 4
-                      / city_list_size(&pplayer->cities);
+      struct unit_type *ut = get_unit_type(unit_type);
+      int tech_cost = (num_unknown_bulbs_for_reqs(pplayer, ut->req)
+                      / (4 * city_list_size(&pplayer->cities)));
       int move_rate = unit_types[unit_type].move_rate;
       int move_time;
       int bcost_balanced = build_cost_balanced(unit_type);
@@ -919,15 +968,32 @@
       
       if (want > 0) {
         if (tech_dist > 0) {
-          /* This is a future unit, tell the scientist how much we need it */
-          pplayer->ai.tech_want[tech_req] += want;
-          
-          CITY_LOG(LOG_DEBUG, pcity, "wants %s to build %s to punish 
%s@(%d,%d)"
-                   " with desire %d", get_tech_name(pplayer, tech_req), 
-                   unit_name(unit_type), (acity ? acity->name : "enemy"),
-                   TILE_XY(ptile), want);
+         int i, count = 0;
 
-        } else if (want > best_choice->want) {
+         /* Divide the desire among all tech reqs.  FIXME: we should account
+          * for non-tech reqs as well. */
+         for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+           if (ut->req[i].type == REQ_TECH) {
+             count++;
+           }
+         }
+         assert(count > 0);
+         for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+           if (ut->req[i].type == REQ_TECH) {
+             Tech_Type_id tech_req = ut->req[i].value.tech;
+
+             /* This is a future unit -
+              * tell the scientist how much we need it */
+             pplayer->ai.tech_want[tech_req] += want / count;
+
+             CITY_LOG(LOG_DEBUG, pcity,
+                      "wants %s to build %s to punish %s@(%d,%d)"
+                      " with desire %d", get_tech_name(pplayer, tech_req), 
+                      unit_name(unit_type), (acity ? acity->name : "enemy"),
+                      TILE_XY(ptile), want);
+           }
+         }
+       } else if (want > best_choice->want) {
           if (can_build_unit(pcity, unit_type)) {
             /* This is a real unit and we really want it */
 
@@ -940,22 +1006,33 @@
             best_choice->choice = unit_type;
             best_choice->want = want;
             best_choice->type = CT_ATTACKER;
-          } else if (can_build_improvement(pcity,
-                            get_unit_type(unit_type)->impr_requirement)) {
-           /* Building this unit requires a specific type of improvement.
-            * So we build this improvement instead.  This may not be the
-            * best behavior. */
-            Impr_Type_id id = get_unit_type(unit_type)->impr_requirement;
-
-            CITY_LOG(LOG_DEBUG, pcity, "building %s to build %s",
-                     get_improvement_type(id)->name,
-                     get_unit_type(unit_type)->name);
-            best_choice->choice = id;
-            best_choice->want = want;
-            best_choice->type = CT_BUILDING;
           } else {
-           /* This should never happen? */
-         }
+           struct unit_type *ut = get_unit_type(unit_type);
+           int i;
+
+           for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE;
+                i++) {
+             if (ut->req[i].type == REQ_BUILDING
+                 && !is_req_active(TARGET_CITY, city_owner(pcity), pcity,
+                                   B_LAST, NULL, &ut->req[i])) {
+               /* Building this unit requires a specific type of
+                * improvement. So we build this improvement instead.  This
+                * may not be the best behavior. */
+               Impr_Type_id id = ut->req[i].value.building;
+
+               if (can_build_improvement(pcity, id)) {
+
+                 CITY_LOG(LOG_DEBUG, pcity, "building %s to build %s",
+                          get_improvement_type(id)->name,
+                          get_unit_type(unit_type)->name);
+                 best_choice->choice = id;
+                 best_choice->want = want;
+                 best_choice->type = CT_BUILDING;
+                 break;
+               }
+             }
+           }
+         } /* if can_build_unit ... else ... */
         }
       }
     }
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.187
diff -u -r1.187 aicity.c
--- ai/aicity.c 21 Dec 2004 04:18:53 -0000      1.187
+++ ai/aicity.c 23 Dec 2004 22:27:09 -0000
@@ -661,9 +661,22 @@
   /* Choose among those made available through other civ's research */
   for(i = 0; i < num_role_units(L_BARBARIAN_BUILD_TECH); i++) {
     Unit_Type_id iunit = get_role_unit(L_BARBARIAN_BUILD_TECH, i);
+    int j;
+    struct unit_type *ut = get_unit_type(iunit);
+    bool missing_tech = FALSE;
 
-    if (game.global_advances[get_unit_type(iunit)->tech_requirement] != 0
-       && get_unit_type(iunit)->attack_strength > bestattack) {
+    if (get_unit_type(iunit)->attack_strength <= bestattack) {
+      continue;
+    }
+    for (j = 0; j < MAX_NUM_REQS; j++) {
+      if (ut->req[i].type == REQ_TECH
+         && !game.global_advances[ut->req[i].value.tech]) {
+       missing_tech = TRUE;
+       break;
+      }
+    }
+
+    if (!missing_tech) {
       bestunit = iunit;
       bestattack = get_unit_type(iunit)->attack_strength;
     }
Index: ai/aidiplomat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidiplomat.c,v
retrieving revision 1.43
diff -u -r1.43 aidiplomat.c
--- ai/aidiplomat.c     19 Dec 2004 19:44:39 -0000      1.43
+++ ai/aidiplomat.c     23 Dec 2004 22:27:09 -0000
@@ -115,13 +115,21 @@
        choice->type = CT_DEFENDER;
        choice->choice = u;
     } else if (num_role_units(F_DIPLOMAT) > 0) {
+      struct unit_type *ut;
+      int i;
+
       /* We don't know diplomats yet... */
       freelog(LOG_DIPLOMAT_BUILD,
               "A defensive diplomat is wanted badly in city %s.", pcity->name);
       u = get_role_unit(F_DIPLOMAT, 0);
+      ut = get_unit_type(u);
       /* 3000 is a just a large number, but not hillariously large as the
          previously used one. This is important for diplomacy later - Per */
-      pplayer->ai.tech_want[get_unit_type(u)->tech_requirement] += 3000;
+      for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+       if (ut->req[i].type == REQ_TECH) {
+         pplayer->ai.tech_want[ut->req[i].value.tech] += 3000;
+       }
+      }
     }
   }
 }
Index: ai/aisettler.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aisettler.c,v
retrieving revision 1.14
diff -u -r1.14 aisettler.c
--- ai/aisettler.c      9 Dec 2004 21:27:48 -0000       1.14
+++ ai/aisettler.c      23 Dec 2004 22:27:10 -0000
@@ -587,9 +587,16 @@
       if (boattype == U_LAST) {
         /* Sea travel not possible yet. Bump tech want for ferries. */
         Unit_Type_id boattype = get_role_unit(L_FERRYBOAT, 0);
-        Tech_Type_id tech_req = unit_types[boattype].tech_requirement;
+       struct unit_type *ut = get_unit_type(boattype);
+       int i;
 
-        pplayer->ai.tech_want[tech_req] += FERRY_TECH_WANT;
+       for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+         if (ut->req[i].type == REQ_TECH) {
+           Tech_Type_id tech_req = ut->req[i].value.tech;
+
+           pplayer->ai.tech_want[tech_req] += FERRY_TECH_WANT;
+         }
+       }
         return;
       }
       ferry = create_unit_virtual(pplayer, NULL, boattype, 0);
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.342
diff -u -r1.342 aiunit.c
--- ai/aiunit.c 20 Dec 2004 23:50:58 -0000      1.342
+++ ai/aiunit.c 23 Dec 2004 22:27:10 -0000
@@ -2235,9 +2235,17 @@
       return iunit;
     } else {
       /* careful; might be unable to build for non-tech reason... */
-      itech = get_unit_type(iunit)->tech_requirement;
-      if (get_invention(pplayer, itech) != TECH_KNOWN) {
-       pplayer->ai.tech_want[itech] += want;
+      int j;
+      struct unit_type *ut = get_unit_type(iunit);
+
+      for (j = 0; j < MAX_NUM_REQS && ut->req[j].type != REQ_NONE; j++) {
+       if (ut->req[j].type == REQ_TECH) {
+         itech = ut->req[i].value.tech;
+
+         if (get_invention(pplayer, itech) != TECH_KNOWN) {
+           pplayer->ai.tech_want[itech] += want;
+         }
+       }
       }
     }
   }
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.455
diff -u -r1.455 packhand.c
--- client/packhand.c   21 Dec 2004 03:36:18 -0000      1.455
+++ client/packhand.c   23 Dec 2004 22:27:11 -0000
@@ -2154,9 +2154,10 @@
   u->attack_strength    = p->attack_strength;
   u->defense_strength   = p->defense_strength;
   u->move_rate          = p->move_rate;
-  u->tech_requirement   = p->tech_requirement;
-  u->impr_requirement   = p->impr_requirement;
-  u->gov_requirement    = p->gov_requirement;
+  for (i = 0; i < MAX_NUM_REQS; i++) {
+    u->req[i] = req_from_values(p->req_type[i], p->req_range[i],
+                               p->req_survives[i], p->req_value[i]);
+  }
   u->vision_range       = p->vision_range;
   u->transport_capacity = p->transport_capacity;
   u->hp                 = p->hp;
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.292
diff -u -r1.292 city.c
--- common/city.c       21 Dec 2004 20:06:27 -0000      1.292
+++ common/city.c       23 Dec 2004 22:27:11 -0000
@@ -470,17 +470,22 @@
 **************************************************************************/
 bool can_build_unit_direct(const struct city *pcity, Unit_Type_id id)
 {
-  Impr_Type_id impr_req;
+  struct unit_type *ut;
+  int i;
 
   if (!can_player_build_unit_direct(city_owner(pcity), id)) {
     return FALSE;
   }
 
   /* Check to see if the unit has a building requirement. */
-  impr_req = get_unit_type(id)->impr_requirement;
-  assert(impr_req <= B_LAST && impr_req >= 0);
-  if (impr_req != B_LAST && !city_got_building(pcity, impr_req)) {
-    return FALSE;
+  ut = get_unit_type(id);
+  for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+    /* Reqs with >= player range are checked earlier. */
+    if (ut->req[i].range < REQ_RANGE_PLAYER
+       && !is_req_active(TARGET_CITY, city_owner(pcity), pcity, B_LAST,
+                         NULL, &ut->req[i])) {
+      return FALSE;
+    }
   }
 
   /* You can't build naval units inland. */
Index: common/fc_types.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/fc_types.h,v
retrieving revision 1.12
diff -u -r1.12 fc_types.h
--- common/fc_types.h   16 Dec 2004 20:37:49 -0000      1.12
+++ common/fc_types.h   23 Dec 2004 22:27:11 -0000
@@ -41,4 +41,6 @@
 
 #define SP_MAX 20
 
+#define MAX_NUM_REQS 2
+
 #endif /* FC__FC_TYPES_H */
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.85
diff -u -r1.85 packets.def
--- common/packets.def  21 Dec 2004 03:36:18 -0000      1.85
+++ common/packets.def  23 Dec 2004 22:27:11 -0000
@@ -939,9 +939,10 @@
   UINT8 attack_strength;
   UINT8 defense_strength;
   UINT8 move_rate;
-  TECH tech_requirement;
-  UINT8 impr_requirement;
-  GOVERNMENT gov_requirement;
+  REQ_TYPE req_type[MAX_NUM_REQS];
+  REQ_RANGE req_range[MAX_NUM_REQS];
+  BOOL req_survives[MAX_NUM_REQS];
+  SINT16 req_value[MAX_NUM_REQS];
   UINT8 vision_range;
   UINT8 transport_capacity;
   UINT8 hp;
Index: common/unittype.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.c,v
retrieving revision 1.47
diff -u -r1.47 unittype.c
--- common/unittype.c   8 Dec 2004 14:36:22 -0000       1.47
+++ common/unittype.c   23 Dec 2004 22:27:13 -0000
@@ -444,8 +444,8 @@
 **************************************************************************/
 bool can_player_build_unit_direct(struct player *p, Unit_Type_id id)
 {
-  Impr_Type_id impr_req;
-  Tech_Type_id tech_req;
+  struct unit_type *ut;
+  int i;
 
   CHECK_UNIT_TYPE(id);
   if (unit_type_flag(id, F_NUCLEAR)
@@ -454,16 +454,20 @@
   if (unit_type_flag(id, F_NOBUILD)) {
     return FALSE;
   }
-  if (unit_types[id].gov_requirement != G_MAGIC
-      && unit_types[id].gov_requirement != p->government) {
-    return FALSE;
-  }
   if (unit_type_flag(id, F_FANATIC)
       && !government_has_flag(get_gov_pplayer(p), G_FANATIC_TROOPS)) {
     return FALSE;
   }
-  if (get_invention(p,unit_types[id].tech_requirement)!=TECH_KNOWN)
-    return FALSE;
+
+  ut = get_unit_type(id);
+  for (i = 0; i < MAX_NUM_REQS && ut->req[i].type != REQ_NONE; i++) {
+    /* Reqs with < player range are checked later. */
+    if (ut->req[i].range >= REQ_RANGE_PLAYER
+       && !is_req_active(TARGET_PLAYER, p, NULL, B_LAST, NULL,
+                         &ut->req[i])) {
+      return FALSE;
+    }
+  }
   if (unit_type_flag(id, F_UNIQUE)) {
     /* FIXME: This could be slow if we have lots of units. We could
      * consider keeping an array of unittypes updated with this info 
@@ -475,15 +479,6 @@
     } unit_list_iterate_end;
   }
 
-  /* If the unit has a building requirement, we check to see if the player
-   * can build that building.  Note that individual cities may not have
-   * that building, so they still may not be able to build the unit. */
-  impr_req = unit_types[id].impr_requirement;
-  tech_req = get_improvement_type(impr_req)->tech_req;
-  if (impr_req != B_LAST && get_invention(p, tech_req) != TECH_KNOWN) {
-    return FALSE;
-  }
-
   return TRUE;
 }
 
Index: common/unittype.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.h,v
retrieving revision 1.38
diff -u -r1.38 unittype.h
--- common/unittype.h   8 Dec 2004 14:36:22 -0000       1.38
+++ common/unittype.h   23 Dec 2004 22:27:13 -0000
@@ -16,6 +16,7 @@
 #include "shared.h"
 
 #include "fc_types.h"
+#include "requirements.h"
 
 struct Sprite;                 /* opaque; client-gui specific */
 
@@ -189,9 +190,7 @@
   int attack_strength;
   int defense_strength;
   int move_rate;
-  int tech_requirement;
-  int impr_requirement;                /* should be Impr_Type_id */
-  int gov_requirement;
+  struct requirement req[MAX_NUM_REQS];
   int vision_range;
   int transport_capacity;
   int hp;
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.224
diff -u -r1.224 ruleset.c
--- server/ruleset.c    21 Dec 2004 03:36:19 -0000      1.224
+++ server/ruleset.c    23 Dec 2004 22:27:14 -0000
@@ -876,18 +876,31 @@
     free(def_vblist);
   }
 
-  /* Tech and Gov requirements */  
+  /* Requirements. */
   unit_type_iterate(i) {
+    int r;
+
     u = &unit_types[i];
-    u->tech_requirement = lookup_tech(file, sec[i], "tech_req",
-                                     TRUE, filename, u->name);
-    if (section_file_lookup(file, "%s.gov_req", sec[i])) {
-      char tmp[200] = "\0";
-      mystrlcat(tmp, sec[i], 200);
-      mystrlcat(tmp, ".gov_req", 200);
-      u->gov_requirement = lookup_government(file, tmp, filename);
-    } else {
-      u->gov_requirement = G_MAGIC; /* no requirement */
+    for (r = 0; r < MAX_NUM_REQS; r++) {
+      const char *type
+       = secfile_lookup_str_default(file, NULL, "%s.req%d.type", sec[i], r);
+      const char *range
+       = secfile_lookup_str_default(file, "", "%s.req%d.range", sec[i], r);
+      bool survives
+       = secfile_lookup_bool_default(file, FALSE, "%s.req%d.survives",
+                                     sec[i], r);
+      const char *value
+       = secfile_lookup_str_default(file, "", "%s.req%d.value", sec[i], r);
+      struct requirement req = req_from_str(type, range, survives, value);
+
+      if (req.type == REQ_LAST) {
+       freelog(LOG_ERROR,
+               "Unit %s has unknoqn req: \"%s\" \"%s\" \"%s\" %d (%s)",
+               sec[i], type, range, value, survives, filename);
+       req.type = REQ_NONE;
+      }
+
+      u->req[i] = req;
     }
   } unit_type_iterate_end;
   
@@ -901,10 +914,6 @@
   unit_type_iterate(i) {
     u = &unit_types[i];
 
-    u->impr_requirement =
-      find_improvement_by_name(secfile_lookup_str_default(file, "None", 
-                                       "%s.impr_req", sec[i]));
-
     sval = secfile_lookup_str(file, "%s.move_type", sec[i]);
     ival = unit_move_type_from_str(sval);
     if (ival==0) {
@@ -1024,17 +1033,6 @@
   lookup_tech_list(file, "u_specials", "partisan_req",
                   game.rtech.partisan_req, filename);
 
-  /* Some more consistency checking: */
-  unit_type_iterate(i) {
-    u = &unit_types[i];
-    if (!tech_exists(u->tech_requirement)) {
-      freelog(LOG_ERROR,
-             "unit_type \"%s\" depends on removed tech \"%s\" (%s)",
-             u->name, advances[u->tech_requirement].name, filename);
-      u->tech_requirement = A_LAST;
-    }
-  } unit_type_iterate_end;
-
   /* Setup roles and flags pre-calcs: */
   role_unit_precalcs();
      
@@ -1095,10 +1093,20 @@
   for(i=0; i<num_role_units(L_FERRYBOAT); i++) {
     j = get_role_unit(L_FERRYBOAT,i);
     if (!unit_type_flag(j, F_TRIREME)) {
-      j = get_unit_type(j)->tech_requirement;
-      freelog(LOG_DEBUG, "nav tech is %s", advances[j].name);
-      game.rtech.nav = j;
-      break;
+      int r;
+      struct unit_type *ut = get_unit_type(j);
+
+      for (r = 0; r < MAX_NUM_REQS && ut->req[r].type != REQ_NONE; r++) {
+       if (ut->req[r].type == REQ_TECH) {
+         j = ut->req[r].value.tech;
+         freelog(LOG_DEBUG, "nav tech is %s", advances[j].name);
+         game.rtech.nav = j;
+         break;
+       }
+      }
+      if (game.rtech.nav != A_LAST) {
+       break;
+      }
     }
   }
 
@@ -1107,9 +1115,18 @@
   if (num_role_units(L_PARTISAN)==0) {
     game.rtech.u_partisan = A_LAST;
   } else {
+    struct unit_type *ut;
+    int r;
+
     j = get_role_unit(L_PARTISAN, 0);
-    j = game.rtech.u_partisan = get_unit_type(j)->tech_requirement;
-    freelog(LOG_DEBUG, "partisan tech is %s", advances[j].name);
+    ut = get_unit_type(j);
+    for (r = 0; r < MAX_NUM_REQS && ut->req[r].type != REQ_NONE; r++) {
+      if (ut->req[r].type == REQ_TECH) {
+       j = game.rtech.u_partisan = ut->req[r].value.tech;
+       freelog(LOG_DEBUG, "partisan tech is %s", advances[j].name);
+       break;
+      }
+    }
   }
 
   update_simple_ai_types();
@@ -2755,9 +2772,16 @@
     packet.attack_strength = u->attack_strength;
     packet.defense_strength = u->defense_strength;
     packet.move_rate = u->move_rate;
-    packet.tech_requirement = u->tech_requirement;
-    packet.impr_requirement = u->impr_requirement;
-    packet.gov_requirement = u->gov_requirement;
+    for (i = 0; i < MAX_NUM_REQS; i++) {
+      int type, range, value;
+      bool survives;
+
+      req_get_values(&u->req[i], &type, &range, &survives, &value);
+      packet.req_type[i] = type;
+      packet.req_range[i] = range;
+      packet.req_survives[i] = survives;
+      packet.req_value[i] = value;
+    }
     packet.vision_range = u->vision_range;
     packet.transport_capacity = u->transport_capacity;
     packet.hp = u->hp;
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.314
diff -u -r1.314 unittools.c
--- server/unittools.c  16 Dec 2004 23:18:48 -0000      1.314
+++ server/unittools.c  23 Dec 2004 22:27:15 -0000
@@ -95,12 +95,22 @@
 int find_a_unit_type(int role, int role_tech)
 {
   int which[U_LAST];
-  int i, num=0;
+  int i, num=0, r;
 
   if (role_tech != -1) {
     for(i=0; i<num_role_units(role_tech); i++) {
       int iunit = get_role_unit(role_tech, i);
-      if (game.global_advances[get_unit_type(iunit)->tech_requirement] >= 2) {
+      struct unit_type *ut = get_unit_type(iunit);
+      bool missing_tech = FALSE;
+
+      for (r = 0; r < MAX_NUM_REQS && ut->req[r].type != REQ_NONE; r++) {
+       if (ut->req[r].type == REQ_TECH
+           && game.global_advances[ut->req[r].value.tech] < 2) {
+         missing_tech = TRUE;
+         break;
+       }
+      }
+      if (!missing_tech) {
        which[num++] = iunit;
       }
     }

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#11672) unit reqs, Jason Short <=