Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2004:
[Freeciv-Dev] (PR#8877) patch: design for generalized specialists
Home

[Freeciv-Dev] (PR#8877) patch: design for generalized specialists

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#8877) patch: design for generalized specialists
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 4 Dec 2004 21:23:11 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=8877 >

Here's an updated gen-specialists patch.

It's now down to a manageable size!

-jason

Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.122
diff -u -r1.122 advdomestic.c
--- ai/advdomestic.c    30 Nov 2004 08:37:01 -0000      1.122
+++ ai/advdomestic.c    5 Dec 2004 05:21:44 -0000
@@ -39,6 +39,45 @@
 
 #include "advdomestic.h"
 
+/**************************************************************************
+  Return the number of "providers".  This is the number of specialists
+  who provide at least 2 of the given output type.
+
+  The AI assumes that for any specialist that provides 2 luxury, if we
+  can get 2 luxury from some other source it allows the specialist to
+  become a worker.  The benefits from an extra worker are weighed against
+  the losses from acquiring the two extra luxury.
+
+  This is a very bad model if the abilities of specialists are changed.
+  But as long as the civ2 model of specialists is used it will continue
+  to work okay.
+**************************************************************************/
+int get_num_providers(Output_type_id otype,
+                     const struct city *pcity)
+{
+  int providers = 0;
+
+  /* Count all luxury-producing specialists.  We "estimate" that for every
+   * extra citizen made content one of these can be put to work elsewhere.
+   * This calculation should be improved. */
+  specialist_type_iterate(i) {
+    if (game.rgame.specialists[i].bonus[otype] >= 2) {
+      providers += pcity->specialists[i];
+    }
+  } specialist_type_iterate_end;
+
+  return providers;
+}
+
+/**************************************************************************
+  Return the number of "non-providers".  See get_num_providers().
+**************************************************************************/
+int get_num_nonproviders(Output_type_id otype,
+                        const struct city *pcity)
+{
+  return city_specialists(pcity) - get_num_providers(otype, pcity);
+}
+
 /***************************************************************************
  * Evaluate the need for units (like caravans) that aid wonder construction.
  * If another city is building wonder and needs help but pplayer is not
@@ -149,9 +188,8 @@
   Unit_Type_id unit_type;
   /* Food surplus assuming that workers and elvii are already accounted for
    * and properly balanced. */
-  int est_food = pcity->surplus[O_FOOD]
-                 + 2 * pcity->specialists[SP_SCIENTIST]
-                 + 2 * pcity->specialists[SP_TAXMAN];
+  int est_food = (pcity->surplus[O_FOOD]
+                 + 2 * get_num_nonproviders(O_LUXURY, pcity));
 
   init_choice(choice);
 
Index: ai/advdomestic.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.h,v
retrieving revision 1.8
diff -u -r1.8 advdomestic.h
--- ai/advdomestic.h    13 Sep 2004 15:54:49 -0000      1.8
+++ ai/advdomestic.h    5 Dec 2004 05:21:44 -0000
@@ -17,6 +17,9 @@
 
 struct ai_choice;
 
+int get_num_providers(Output_type_id otype, const struct city *pcity);
+int get_num_nonproviders(Output_type_id otype, const struct city *pcity);
+
 void ai_eval_threat_init(struct player *pplayer);
 void ai_eval_threat_done(struct player *pplayer);
 void domestic_advisor_choose_build(struct player *pplayer, struct city *pcity,
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.178
diff -u -r1.178 aicity.c
--- ai/aicity.c 30 Nov 2004 08:37:02 -0000      1.178
+++ ai/aicity.c 5 Dec 2004 05:21:45 -0000
@@ -272,18 +272,21 @@
             /* TODO */
             break;
          case EFT_NO_UNHAPPY:
-            v += (pcity->specialists[SP_ELVIS] + pcity->ppl_unhappy[4]) * 20;
+            v += (get_num_providers(O_LUXURY, pcity)
+                 + pcity->ppl_unhappy[4]) * 20;
             break;
          case EFT_FORCE_CONTENT:
            if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
-             v += (pcity->ppl_unhappy[4] + pcity->specialists[SP_ELVIS]) * 20;
+             v += (pcity->ppl_unhappy[4]
+                   + get_num_providers(O_LUXURY, pcity)) * 20;
              v += 5 * c;
            }
            break;
          case EFT_MAKE_CONTENT_MIL_PER:
          case EFT_MAKE_CONTENT:
            if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
-              v += MIN(pcity->ppl_unhappy[4] + pcity->specialists[SP_ELVIS],
+              v += MIN(pcity->ppl_unhappy[4]
+                      + get_num_providers(O_LUXURY, pcity),
                        amount) * 20;
               v += MIN(amount, 5) * c;
            }
@@ -1062,7 +1065,7 @@
       is_valid = map_to_city_map(&city_map_x, &city_map_y, acity, ptile);
       assert(is_valid);
       server_remove_worker_city(acity, city_map_x, city_map_y);
-      acity->specialists[SP_ELVIS]++;
+      acity->specialists[DEFAULT_SPECIALIST]++;
       if (!city_list_find_id(&minilist, acity->id)) {
        city_list_insert(&minilist, acity);
       }
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.433
diff -u -r1.433 packhand.c
--- client/packhand.c   4 Dec 2004 10:42:12 -0000       1.433
+++ client/packhand.c   5 Dec 2004 05:21:46 -0000
@@ -2644,6 +2644,9 @@
 {
   int i;
 
+  /* Must set num_specialist_types before iterating over them. */
+  game.rgame.num_specialist_types = packet->num_specialist_types;
+  game.rgame.default_specialist = packet->default_specialist;
   specialist_type_iterate(sp) {
     int *bonus = game.rgame.specialists[sp].bonus;
 
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.269
diff -u -r1.269 city.c
--- common/city.c       5 Dec 2004 04:20:10 -0000       1.269
+++ common/city.c       5 Dec 2004 05:21:46 -0000
@@ -41,7 +41,6 @@
 
 int city_tiles;
 const Output_type_id num_output_types = O_LAST;
-const Specialist_type_id num_specialist_types = SP_LAST;
 
 /**************************************************************************
   Return TRUE if the given city coordinate pair is "valid"; that is, if it
@@ -2483,7 +2482,7 @@
   specialist_type_iterate(sp) {
     pcity->specialists[sp] = 0;
   } specialist_type_iterate_end;
-  pcity->specialists[SP_ELVIS] = 1;
+  pcity->specialists[DEFAULT_SPECIALIST] = 1;
   pcity->ppl_happy[4] = 0;
   pcity->ppl_content[4] = 1;
   pcity->ppl_unhappy[4] = 0;
Index: common/city.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.h,v
retrieving revision 1.175
diff -u -r1.175 city.h
--- common/city.h       5 Dec 2004 04:20:10 -0000       1.175
+++ common/city.h       5 Dec 2004 05:21:46 -0000
@@ -335,7 +335,6 @@
 
 extern struct citystyle *city_styles;
 extern const Output_type_id num_output_types;
-extern const Specialist_type_id num_specialist_types;
 
 /* get 'struct city_list' and related functions: */
 #define SPECLIST_TAG city
Index: common/fc_types.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/fc_types.h,v
retrieving revision 1.11
diff -u -r1.11 fc_types.h
--- common/fc_types.h   3 Dec 2004 09:39:40 -0000       1.11
+++ common/fc_types.h   5 Dec 2004 05:21:47 -0000
@@ -21,12 +21,6 @@
  * Nothing in this file should require anything else from the common/
  * directory! */
 
-enum specialist_type {
-  SP_ELVIS, SP_SCIENTIST, SP_TAXMAN, SP_LAST
-};
-#define SP_COUNT num_specialist_types
-#define SP_MAX SP_LAST /* Changing this breaks network compatibility. */
-
 enum output_type {
   O_FOOD, O_SHIELD, O_TRADE, O_GOLD, O_LUXURY, O_SCIENCE, O_LAST
 };
@@ -35,7 +29,7 @@
 
 typedef signed short Continent_id;
 typedef int Terrain_type_id;
-typedef enum specialist_type Specialist_type_id;
+typedef int Specialist_type_id;
 typedef int Impr_Type_id;
 typedef enum output_type Output_type_id;
 
@@ -45,4 +39,6 @@
 struct tile;
 struct unit;
 
+#define SP_MAX 20
+
 #endif /* FC__FC_TYPES_H */
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.163
diff -u -r1.163 game.h
--- common/game.h       3 Dec 2004 09:39:40 -0000       1.163
+++ common/game.h       5 Dec 2004 05:21:47 -0000
@@ -193,13 +193,17 @@
 
   /* values from game.ruleset */
   struct {
+#define SP_MAX 20 /* Changing this breaks network compatibility. */
+    int num_specialist_types;
+    int default_specialist;
     struct specialist {
       char name[MAX_LEN_NAME];
       char short_name[MAX_LEN_NAME];
       int min_size;
       int bonus[O_MAX];
     } specialists[SP_MAX];
-#define DEFAULT_SPECIALIST SP_ELVIS
+#define SP_COUNT game.rgame.num_specialist_types
+#define DEFAULT_SPECIALIST game.rgame.default_specialist
     bool changable_tax;
     int forced_science; /* only relevant if !changable_tax */
     int forced_luxury;
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.65
diff -u -r1.65 packets.def
--- common/packets.def  4 Dec 2004 10:42:12 -0000       1.65
+++ common/packets.def  5 Dec 2004 05:21:47 -0000
@@ -969,6 +969,7 @@
 end
 
 PACKET_RULESET_GAME=97;sc,lsend
+  UINT8 default_specialist, num_specialist_types;
   STRING specialist_name[SP_MAX][MAX_LEN_NAME];
   STRING specialist_short_name[SP_MAX][MAX_LEN_NAME];
   UINT8 specialist_min_size[SP_MAX];
Index: common/aicore/cm.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.c,v
retrieving revision 1.50
diff -u -r1.50 cm.c
--- common/aicore/cm.c  2 Dec 2004 10:20:30 -0000       1.50
+++ common/aicore/cm.c  5 Dec 2004 05:21:47 -0000
@@ -2053,10 +2053,8 @@
   freelog(LOG_NORMAL, "print_city(city='%s'(id=%d))",
           pcity->name, pcity->id);
   freelog(LOG_NORMAL,
-          "  size=%d, entertainers=%d, scientists=%d, taxmen=%d",
-          pcity->size, pcity->specialists[SP_ELVIS],
-          pcity->specialists[SP_SCIENTIST],
-          pcity->specialists[SP_TAXMAN]);
+          "  size=%d, specialists=%s",
+          pcity->size, specialists_string(pcity->specialists));
   freelog(LOG_NORMAL, "  workers at:");
   my_city_map_iterate(pcity, x, y) {
     if (pcity->city_map[x][y] == C_TILE_WORKER) {
Index: server/cityhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityhand.c,v
retrieving revision 1.137
diff -u -r1.137 cityhand.c
--- server/cityhand.c   29 Sep 2004 02:24:23 -0000      1.137
+++ server/cityhand.c   5 Dec 2004 05:21:48 -0000
@@ -106,7 +106,7 @@
   }
   if (is_worker_here(pcity, worker_x, worker_y)) {
     server_remove_worker_city(pcity, worker_x, worker_y);
-    pcity->specialists[SP_ELVIS]++;
+    pcity->specialists[DEFAULT_SPECIALIST]++;
     city_refresh(pcity);
     sync_cities();
   } else {
Index: server/citytools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/citytools.c,v
retrieving revision 1.284
diff -u -r1.284 citytools.c
--- server/citytools.c  3 Dec 2004 23:00:02 -0000       1.284
+++ server/citytools.c  5 Dec 2004 05:21:48 -0000
@@ -1539,9 +1539,9 @@
     packet->ppl_unhappy[i]=pcity->ppl_unhappy[i];
     packet->ppl_angry[i]=pcity->ppl_angry[i];
   }
-  packet->specialists[SP_ELVIS] = pcity->specialists[SP_ELVIS];
-  packet->specialists[SP_SCIENTIST] = pcity->specialists[SP_SCIENTIST];
-  packet->specialists[SP_TAXMAN] = pcity->specialists[SP_TAXMAN];
+  specialist_type_iterate(sp) {
+    packet->specialists[sp] = pcity->specialists[sp];
+  } specialist_type_iterate_end;
   for (i = 0; i < NUM_TRADEROUTES; i++) {
     packet->trade[i]=pcity->trade[i];
     packet->trade_value[i]=pcity->trade_value[i];
@@ -1996,7 +1996,7 @@
   case C_TILE_WORKER:
     if (!is_available) {
       server_set_tile_city(pcity, city_x, city_y, C_TILE_UNAVAILABLE);
-      pcity->specialists[SP_ELVIS]++; /* keep city sanity */
+      pcity->specialists[DEFAULT_SPECIALIST]++; /* keep city sanity */
       auto_arrange_workers(pcity); /* will place the displaced */
       city_refresh(pcity);
       send_city_info(NULL, pcity);
Index: server/cityturn.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityturn.c,v
retrieving revision 1.278
diff -u -r1.278 cityturn.c
--- server/cityturn.c   5 Dec 2004 04:20:11 -0000       1.278
+++ server/cityturn.c   5 Dec 2004 05:21:48 -0000
@@ -386,6 +386,8 @@
 **************************************************************************/
 bool city_reduce_size(struct city *pcity, int pop_loss)
 {
+  int i;
+
   if (pop_loss == 0) {
     return TRUE;
   }
@@ -403,16 +405,15 @@
 
   /* First try to kill off the specialists */
   while (pop_loss > 0 && city_specialists(pcity) > 0) {
-    if (pcity->specialists[SP_TAXMAN] > 0) {
-      pcity->specialists[SP_TAXMAN]--;
-    } else if (pcity->specialists[SP_SCIENTIST] > 0) {
-      pcity->specialists[SP_SCIENTIST]--;
-    } else {
-      assert(pcity->specialists[SP_ELVIS] > 0);
-      pcity->specialists[SP_ELVIS]--; 
+    for (i = SP_COUNT - 1; i >= 0; i--) {
+      if (pcity->specialists[i] > 0) {
+       pcity->specialists[i]--;
+       pop_loss--;
+       break;
+      }
     }
-    pop_loss--;
   }
+  assert(pop_loss == 0 || city_specialists(pcity) == 0);
 
   /* we consumed all the pop_loss in specialists */
   if (pop_loss == 0) {
Index: server/report.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/report.c,v
retrieving revision 1.56
diff -u -r1.56 report.c
--- server/report.c     30 Nov 2004 02:08:22 -0000      1.56
+++ server/report.c     5 Dec 2004 05:21:49 -0000
@@ -492,19 +492,15 @@
   return pplayer->score.unhappy;
 }
 
-static int get_taxmen(struct player *pplayer)
+static int get_specialists(struct player *pplayer)
 {
-  return pplayer->score.specialists[SP_TAXMAN];
-}
+  int i, count = 0;
 
-static int get_scientists(struct player *pplayer)
-{
-  return pplayer->score.specialists[SP_SCIENTIST];
-}
+  for (i = 0; i < SP_COUNT; i++) {
+    count += pplayer->score.specialists[i];
+  }
 
-static int get_elvis(struct player *pplayer)
-{
-  return pplayer->score.specialists[SP_ELVIS];
+  return count;
 }
 
 static int get_gov(struct player *pplayer)
@@ -901,9 +897,7 @@
     {"happypop",        get_happypop},
     {"contentpop",      get_contentpop},
     {"unhappypop",      get_unhappypop},
-    {"taxmen",          get_taxmen},
-    {"scientists",      get_scientists},
-    {"elvis",           get_elvis},
+    {"specialists",     get_specialists},
     {"gov",             get_gov},
     {"corruption",      get_corruption} /* new 1.11.5 tags end here */
   };
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.210
diff -u -r1.210 ruleset.c
--- server/ruleset.c    4 Dec 2004 10:42:13 -0000       1.210
+++ server/ruleset.c    5 Dec 2004 05:21:49 -0000
@@ -2535,11 +2535,6 @@
 
   /* Specialist options */
   specialist_names = secfile_lookup_str_vec(file, &nval, "specialist.types");
-  if (nval != SP_COUNT) {
-    freelog(LOG_FATAL, "There must be exactly %d types of specialist.",
-           SP_COUNT);
-    exit(EXIT_FAILURE);
-  }
 
   for (i = 0; i < nval; i++) {
     const char *name = specialist_names[i], *short_name;
@@ -2558,7 +2553,17 @@
                                            "specialist.%s_bonus_%s",
                                            name, get_output_identifier(o));
     } output_type_iterate_end;
+    if (game.rgame.specialists[i].min_size == 0
+       && game.rgame.default_specialist == -1) {
+      game.rgame.default_specialist = i;
+    }
   }
+  if (game.rgame.default_specialist == -1) {
+    freelog(LOG_FATAL, "You must give a min_size of 0 for at least one "
+           "specialist type (in %s).", filename);
+    exit(EXIT_FAILURE);
+  }
+  game.rgame.num_specialist_types = nval;
   free(specialist_names);
 
   game.rgame.changable_tax = 
@@ -2574,11 +2579,6 @@
     freelog(LOG_FATAL, "Forced taxes do not add up in ruleset!");
     exit(EXIT_FAILURE);
   }
-  if (game.rgame.specialists[SP_ELVIS].min_size > 0) {
-    freelog(LOG_FATAL, "Elvises must be available without a "
-           "city size restriction!");
-    exit(EXIT_FAILURE);
-  }
 
   /* City Parameters */
 
@@ -3142,6 +3142,8 @@
   int i;
   struct packet_ruleset_game misc_p;
 
+  misc_p.num_specialist_types = SP_COUNT;
+  misc_p.default_specialist = DEFAULT_SPECIALIST;
   specialist_type_iterate(sp) {
     int *bonus = game.rgame.specialists[sp].bonus;
 
Index: server/sanitycheck.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/sanitycheck.c,v
retrieving revision 1.55
diff -u -r1.55 sanitycheck.c
--- server/sanitycheck.c        22 Nov 2004 07:12:39 -0000      1.55
+++ server/sanitycheck.c        5 Dec 2004 05:21:49 -0000
@@ -258,9 +258,9 @@
     }
   } city_map_iterate_end;
   if (workers + city_specialists(pcity) != pcity->size + 1) {
-    die("%s is illegal (size%d w%d e%d t%d s%d) in %s line %d",
-        pcity->name, pcity->size, workers, pcity->specialists[SP_ELVIS],
-        pcity->specialists[SP_TAXMAN], pcity->specialists[SP_SCIENTIST], file, 
line);
+    die("%s is illegal (size%d w%d s%s) in %s line %d",
+        pcity->name, pcity->size, workers,
+       specialists_string(pcity->specialists), file, line);
   }
 }
 
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.210
diff -u -r1.210 savegame.c
--- server/savegame.c   30 Nov 2004 08:37:03 -0000      1.210
+++ server/savegame.c   5 Dec 2004 05:21:50 -0000
@@ -2107,7 +2107,7 @@
            /* oops, inconsistent savegame; minimal fix: */
            freelog(LOG_VERBOSE, "Inconsistent worked for %s (%d,%d), "
                    "converting to elvis", pcity->name, x, y);
-           pcity->specialists[SP_ELVIS]++;
+           pcity->specialists[DEFAULT_SPECIALIST]++;
            set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
          } else {
            set_worker_city(pcity, x, y, C_TILE_WORKER);
@@ -3009,7 +3009,7 @@
       if (!res) {
        struct tile *ptile;
 
-       pcity->specialists[SP_ELVIS]++;
+       pcity->specialists[DEFAULT_SPECIALIST]++;
        set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
        freelog(LOG_DEBUG, "Worked tile was unavailable!");
 
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.316
diff -u -r1.316 unithand.c
--- server/unithand.c   4 Dec 2004 04:44:08 -0000       1.316
+++ server/unithand.c   5 Dec 2004 05:21:50 -0000
@@ -455,7 +455,7 @@
   assert(unit_pop_value(punit->type) > 0);
   pcity->size += unit_pop_value(punit->type);
   /* Make the new people something, otherwise city fails the checks */
-  pcity->specialists[SP_TAXMAN] += unit_pop_value(punit->type);
+  pcity->specialists[DEFAULT_SPECIALIST] += unit_pop_value(punit->type);
   auto_arrange_workers(pcity);
   wipe_unit(punit);
   send_city_info(NULL, pcity);

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