Complete.Org: Mailing Lists: Archives: freeciv-dev: November 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: Fri, 19 Nov 2004 00:51:42 -0800
Reply-to: rt@xxxxxxxxxxx

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

Here is an updated gen-specialists patch.  With the changes to CM this
is rather simpler now (still not intended to be applied though).

jason

Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.121
diff -u -r1.121 advdomestic.c
--- ai/advdomestic.c    20 Oct 2004 18:20:53 -0000      1.121
+++ ai/advdomestic.c    19 Nov 2004 07:34:00 -0000
@@ -39,6 +39,43 @@
 
 #include "advdomestic.h"
 
+
+/**************************************************************************
+  Return the number of "entertainers".
+
+  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_entertainers(struct city *pcity)
+{
+  int elvis = 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_lux >= 2) {
+      elvis += pcity->specialists[i];
+    }
+  } specialist_type_iterate_end;
+
+  return elvis;
+}
+
+/**************************************************************************
+  Return the number of "non-entertainiers".  See get_num_entertainers().
+**************************************************************************/
+int get_num_nonentertainers(struct city *pcity)
+{
+  return city_specialists(pcity) - get_num_entertainers(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 +186,7 @@
   Unit_Type_id unit_type;
   /* Food surplus assuming that workers and elvii are already accounted for
    * and properly balanced. */
-  int est_food = pcity->food_surplus
-                 + 2 * pcity->specialists[SP_SCIENTIST]
-                 + 2 * pcity->specialists[SP_TAXMAN];
+  int est_food = pcity->food_surplus + 2 * get_num_nonentertainers(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    19 Nov 2004 07:34:00 -0000
@@ -17,6 +17,9 @@
 
 struct ai_choice;
 
+int get_num_entertainers(struct city *pcity);
+int get_num_nonentertainers(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.177
diff -u -r1.177 aicity.c
--- ai/aicity.c 31 Oct 2004 21:52:20 -0000      1.177
+++ ai/aicity.c 19 Nov 2004 07:34:00 -0000
@@ -272,18 +272,18 @@
             /* TODO */
             break;
          case EFT_NO_UNHAPPY:
-            v += (pcity->specialists[SP_ELVIS] + pcity->ppl_unhappy[4]) * 20;
+            v += (get_num_entertainers(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_entertainers(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_entertainers(pcity),
                        amount) * 20;
               v += MIN(amount, 5) * c;
            }
@@ -1062,7 +1062,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/cityrepdata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/cityrepdata.c,v
retrieving revision 1.39
diff -u -r1.39 cityrepdata.c
--- client/cityrepdata.c        30 Sep 2004 17:14:37 -0000      1.39
+++ client/cityrepdata.c        19 Nov 2004 07:34:01 -0000
@@ -112,6 +112,7 @@
   return specialists_string(pcity->specialists);
 }
 
+#if 0
 static const char *cr_entry_entertainers(const struct city *pcity)
 {
   static char buf[8];
@@ -132,6 +133,7 @@
   my_snprintf(buf, sizeof(buf), "%2d", pcity->specialists[SP_TAXMAN]);
   return buf;
 }
+#endif
 
 static const char *cr_entry_attack(const struct city *pcity)
 {
@@ -432,12 +434,14 @@
     N_("?entertainers/scientists/taxmen:E/S/T"),
     N_("Entertainers, Scientists, Taxmen"),
     FUNC_TAG(specialists) },
+#if 0
   { FALSE, 2, 1, NULL, N_("?Entertainers:E"), N_("Entertainers"),
     FUNC_TAG(entertainers) },
   { FALSE, 2, 1, NULL, N_("?Scientists:S"), N_("Scientists"),
     FUNC_TAG(scientists) },
   { FALSE, 2, 1, NULL, N_("?Taxmen:T"), N_("Taxmen"),
     FUNC_TAG(taxmen) },
+#endif
   { FALSE, 8, 1, N_("Best"), N_("attack"),
     N_("Best attacking units"), FUNC_TAG(attack)},
   { FALSE, 8, 1, N_("Best"), N_("defense"),
Index: client/cityrepdata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/cityrepdata.h,v
retrieving revision 1.12
diff -u -r1.12 cityrepdata.h
--- client/cityrepdata.h        30 Sep 2004 17:14:37 -0000      1.12
+++ client/cityrepdata.h        19 Nov 2004 07:34:01 -0000
@@ -18,7 +18,7 @@
 #include "fc_types.h"
 
 /* Number of city report columns: have to set this manually now... */
-#define NUM_CREPORT_COLS 33
+#define NUM_CREPORT_COLS 30
 
 struct city_report_spec {
   bool show;                   /* modify this to customize */
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.420
diff -u -r1.420 packhand.c
--- client/packhand.c   15 Nov 2004 18:16:14 -0000      1.420
+++ client/packhand.c   19 Nov 2004 07:34:02 -0000
@@ -2622,10 +2622,15 @@
 {
   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) {
     sz_strlcpy(game.rgame.specialists[sp].name, packet->specialist_name[sp]);
     game.rgame.specialists[sp].min_size = packet->specialist_min_size[sp];
-    game.rgame.specialists[sp].bonus = packet->specialist_bonus[sp];
+    game.rgame.specialists[sp].bonus_sci = packet->specialist_bonus_sci[sp];
+    game.rgame.specialists[sp].bonus_tax = packet->specialist_bonus_tax[sp];
+    game.rgame.specialists[sp].bonus_lux = packet->specialist_bonus_lux[sp];
   } specialist_type_iterate_end;
   tilespec_setup_specialist_types();
 
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.90
diff -u -r1.90 tilespec.h
--- client/tilespec.h   7 Oct 2004 19:15:19 -0000       1.90
+++ client/tilespec.h   19 Nov 2004 07:34:02 -0000
@@ -166,7 +166,7 @@
      * sprites, as defined by the tileset. */
     int count;
     struct Sprite *sprite[MAX_NUM_CITIZEN_SPRITES];
-  } citizen[NUM_TILES_CITIZEN], specialist[SP_COUNT];
+  } citizen[NUM_TILES_CITIZEN], specialist[MAX_NUM_SPECIALISTS];
   struct {
     struct Sprite
       *solar_panels,
Index: client/agents/cma_core.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/agents/cma_core.c,v
retrieving revision 1.64
diff -u -r1.64 cma_core.c
--- client/agents/cma_core.c    29 Sep 2004 02:24:19 -0000      1.64
+++ client/agents/cma_core.c    19 Nov 2004 07:34:02 -0000
@@ -104,9 +104,10 @@
 
   T(disorder);
   T(happy);
-  T(specialists[SP_ELVIS]);
-  T(specialists[SP_SCIENTIST]);
-  T(specialists[SP_TAXMAN]);
+
+  specialist_type_iterate(sp) {
+    T(specialists[sp]);
+  } specialist_type_iterate_end;
 
   for (stat = 0; stat < NUM_STATS; stat++) {
     T(surplus[stat]);
@@ -194,7 +195,7 @@
 static bool apply_result_on_server(struct city *pcity,
                                   const struct cm_result *const result)
 {
-  int first_request_id = 0, last_request_id = 0, i, sp;
+  int first_request_id = 0, last_request_id = 0, i;
   struct cm_result current_state;
   bool success;
 
@@ -233,24 +234,27 @@
     }
   } my_city_map_iterate_end;
 
-  /* Change the excess non-elvis specialists to elvises. */
-  assert(SP_ELVIS == 0);
-  for (sp = 1; sp < SP_COUNT; sp++) {
+  /* Change the excess non-default specialists to default. */
+  specialist_type_iterate(sp) {
+    if (sp == DEFAULT_SPECIALIST) {
+      continue;
+    }
     for (i = 0; i < pcity->specialists[sp] - result->specialists[sp]; i++) {
       freelog(APPLY_RESULT_LOG_LEVEL, "Change specialist from %d to %d.",
-             sp, SP_ELVIS);
-      last_request_id = city_change_specialist(pcity, sp, SP_ELVIS);
+             sp, DEFAULT_SPECIALIST);
+      last_request_id = city_change_specialist(pcity,
+                                              sp, DEFAULT_SPECIALIST);
       if (first_request_id == 0) {
        first_request_id = last_request_id;
       }
     }
-  }
+  } specialist_type_iterate_end;
 
   /* now all surplus people are enterainers */
 
   /* Set workers */
-  /* FIXME: This code assumes that any toggled worker will turn into an
-   * elvis! */
+  /* FIXME: This code assumes that any toggled worker will turn into a
+   * DEFAULT_SPECIALIST! */
   my_city_map_iterate(pcity, x, y) {
     if (result->worker_positions_used[x][y] &&
        pcity->city_map[x][y] != C_TILE_WORKER) {
@@ -263,19 +267,22 @@
     }
   } my_city_map_iterate_end;
 
-  /* Set all specialists except SP_ELVIS (all the unchanged ones remain
-   * as elvises). */
-  assert(SP_ELVIS == 0);
-  for (sp = 1; sp < SP_COUNT; sp++) {
+  /* Set all specialists except DEFAULT_SPECIALIST (all the unchanged
+   * ones remain as DEFAULT_SPECIALIST). */
+  specialist_type_iterate(sp) {
+    if (sp == DEFAULT_SPECIALIST) {
+      continue;
+    }
     for (i = 0; i < result->specialists[sp] - pcity->specialists[sp]; i++) {
       freelog(APPLY_RESULT_LOG_LEVEL, "Changing specialist from %d to %d.",
-             SP_ELVIS, sp);
-      last_request_id = city_change_specialist(pcity, SP_ELVIS, sp);
+             DEFAULT_SPECIALIST, sp);
+      last_request_id = city_change_specialist(pcity,
+                                              DEFAULT_SPECIALIST, sp);
       if (first_request_id == 0) {
        first_request_id = last_request_id;
       }
     }
-  }
+  } specialist_type_iterate_end;
 
   if (last_request_id == 0 || ALWAYS_APPLY_AT_SERVER) {
       /*
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.255
diff -u -r1.255 city.c
--- common/city.c       17 Nov 2004 19:21:14 -0000      1.255
+++ common/city.c       19 Nov 2004 07:34:02 -0000
@@ -1676,12 +1676,15 @@
   get_tax_income(city_owner(pcity), pcity->trade_prod, &pcity->science_total, 
                  &pcity->luxury_total, &pcity->tax_total);
 
-  pcity->luxury_total += (pcity->specialists[SP_ELVIS]
-                         * game.rgame.specialists[SP_ELVIS].bonus);
-  pcity->science_total += (pcity->specialists[SP_SCIENTIST]
-                          * game.rgame.specialists[SP_SCIENTIST].bonus);
-  pcity->tax_total += (pcity->specialists[SP_TAXMAN]
-                       * game.rgame.specialists[SP_TAXMAN].bonus);
+  specialist_type_iterate(sp) {
+    pcity->luxury_total
+      += pcity->specialists[sp] * game.rgame.specialists[sp].bonus_lux;
+    pcity->science_total
+      += pcity->specialists[sp] * game.rgame.specialists[sp].bonus_sci;
+    pcity->tax_total
+      += pcity->specialists[sp] * game.rgame.specialists[sp].bonus_tax;
+  } specialist_type_iterate_end;
+
   pcity->tax_total += get_city_tithes_bonus(pcity);
 }
 
@@ -2273,6 +2276,57 @@
 }
 
 /**************************************************************************
+  Return the best science specialist available in the game.
+**************************************************************************/
+Specialist_type_id best_science_specialist(void)
+{
+  int best = DEFAULT_SPECIALIST, val = -1;
+
+  specialist_type_iterate(i) {
+    if (game.rgame.specialists[i].bonus_sci > val) {
+      best = i;
+      val = game.rgame.specialists[i].bonus_sci;
+    }
+  } specialist_type_iterate_end;
+
+  return best;
+}
+
+/**************************************************************************
+  Return the best tax specialist available in the game.
+**************************************************************************/
+Specialist_type_id best_tax_specialist(void)
+{
+  int best = DEFAULT_SPECIALIST, val = -1;
+
+  specialist_type_iterate(i) {
+    if (game.rgame.specialists[i].bonus_tax > val) {
+      best = i;
+      val = game.rgame.specialists[i].bonus_tax;
+    }
+  } specialist_type_iterate_end;
+
+  return best;
+}
+
+/**************************************************************************
+  Return the best luxury specialist available in the game.
+**************************************************************************/
+Specialist_type_id best_luxury_specialist(void)
+{
+  int best = DEFAULT_SPECIALIST, val = -1;
+
+  specialist_type_iterate(i) {
+    if (game.rgame.specialists[i].bonus_lux > val) {
+      best = i;
+      val = game.rgame.specialists[i].bonus_lux;
+    }
+  } specialist_type_iterate_end;
+
+  return best;
+}
+
+/**************************************************************************
   Return a string showing the number of specialists in the array.
 
   For instance with a city with (0,3,1) specialists call
@@ -2284,7 +2338,7 @@
 const char *specialists_string(const int *specialists)
 {
   size_t len = 0;
-  static char buf[5 * SP_COUNT];
+  static char buf[5 * MAX_NUM_SPECIALISTS];
 
   specialist_type_iterate(sp) {
     char *separator = (len == 0) ? "" : "/";
@@ -2401,7 +2455,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.166
diff -u -r1.166 city.h
--- common/city.h       10 Nov 2004 17:01:59 -0000      1.166
+++ common/city.h       19 Nov 2004 07:34:02 -0000
@@ -22,10 +22,6 @@
   TYPE_UNIT, TYPE_NORMAL_IMPROVEMENT, TYPE_WONDER
 };
 
-enum specialist_type {
-  SP_ELVIS, SP_SCIENTIST, SP_TAXMAN, SP_COUNT
-};
-
 enum city_tile_type {
   C_TILE_EMPTY, C_TILE_WORKER, C_TILE_UNAVAILABLE
 };
@@ -79,6 +75,9 @@
  */
 #define MAX_CITY_SIZE                                  100
 
+/* Maximum number of specialist types. */
+#define MAX_NUM_SPECIALISTS 20
+
 /*
  * Iterate a city map.  This iterates over all city positions in the
  * city map (i.e., positions that are workable by the city) in unspecified
@@ -232,7 +231,7 @@
   int ppl_happy[5], ppl_content[5], ppl_unhappy[5], ppl_angry[5];
 
   /* Specialists */
-  int specialists[SP_COUNT];
+  int specialists[MAX_NUM_SPECIALISTS];
 
   /* trade routes */
   int trade[NUM_TRADEROUTES], trade_value[NUM_TRADEROUTES];
@@ -500,6 +499,9 @@
 int city_corruption(const struct city *pcity, int trade);
 int city_waste(const struct city *pcity, int shields);
 int city_specialists(const struct city *pcity);                 /* 
elv+tax+scie */
+Specialist_type_id best_science_specialist(void);
+Specialist_type_id best_tax_specialist(void);
+Specialist_type_id best_luxury_specialist(void);
 const char *specialists_string(const int *specialists);
 int get_city_tax_bonus(const struct city *pcity);
 int get_city_luxury_bonus(const struct city *pcity);
Index: common/fc_types.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/fc_types.h,v
retrieving revision 1.8
diff -u -r1.8 fc_types.h
--- common/fc_types.h   13 Sep 2004 15:54:51 -0000      1.8
+++ common/fc_types.h   19 Nov 2004 07:34:02 -0000
@@ -20,7 +20,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;
 
 struct city;
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.190
diff -u -r1.190 game.c
--- common/game.c       13 Nov 2004 08:34:17 -0000      1.190
+++ common/game.c       19 Nov 2004 07:34:02 -0000
@@ -70,13 +70,16 @@
 **************************************************************************/
 int total_player_citizens(struct player *pplayer)
 {
-  return (pplayer->score.happy
-         +pplayer->score.content
-         +pplayer->score.unhappy
-         +pplayer->score.angry
-         +pplayer->score.scientists
-         +pplayer->score.elvis
-         +pplayer->score.taxmen);
+  int count = (pplayer->score.happy
+              +pplayer->score.content
+              +pplayer->score.unhappy
+              +pplayer->score.angry), sp;
+
+  for (sp = 0; sp < SP_COUNT; sp++) {
+    count += pplayer->score.specialists[sp];
+  }
+
+  return count;
 }
 
 /**************************************************************************
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.155
diff -u -r1.155 game.h
--- common/game.h       4 Nov 2004 06:20:54 -0000       1.155
+++ common/game.h       19 Nov 2004 07:34:03 -0000
@@ -193,10 +193,15 @@
 
   /* values from game.ruleset */
   struct {
-    struct {
+    struct specialist_type {
       char name[MAX_LEN_NAME];
-      int min_size, bonus;
-    } specialists[SP_COUNT];
+      int min_size;
+      int bonus_sci, bonus_tax, bonus_lux;
+    } specialists[MAX_NUM_SPECIALISTS];
+#define DEFAULT_SPECIALIST game.rgame.default_specialist
+#define SP_COUNT game.rgame.num_specialist_types
+    int default_specialist, num_specialist_types;
+
     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.59
diff -u -r1.59 packets.def
--- common/packets.def  16 Nov 2004 18:09:46 -0000      1.59
+++ common/packets.def  19 Nov 2004 07:34:03 -0000
@@ -395,7 +395,7 @@
 
   UINT8 ppl_happy[5], ppl_content[5], ppl_unhappy[5], ppl_angry[5];
 
-  UINT8 specialists[SP_COUNT];
+  UINT8 specialists[MAX_NUM_SPECIALISTS];
 
   UINT16 food_prod, shield_prod, trade_prod;
   SINT16 food_surplus, shield_surplus, tile_trade;
@@ -971,9 +971,12 @@
 end
 
 PACKET_RULESET_GAME=97;sc,lsend
-  STRING specialist_name[SP_COUNT][MAX_LEN_NAME];
-  UINT8 specialist_min_size[SP_COUNT];
-  UINT8 specialist_bonus[SP_COUNT];
+  UINT8 default_specialist, num_specialist_types;
+  STRING 
specialist_name[MAX_NUM_SPECIALISTS:num_specialist_types][MAX_LEN_NAME];
+  UINT8 specialist_min_size[MAX_NUM_SPECIALISTS:num_specialist_types];
+  UINT8 specialist_bonus_sci[MAX_NUM_SPECIALISTS:num_specialist_types];
+  UINT8 specialist_bonus_tax[MAX_NUM_SPECIALISTS:num_specialist_types];
+  UINT8 specialist_bonus_lux[MAX_NUM_SPECIALISTS:num_specialist_types];
   BOOL changable_tax;
   UINT8 forced_science;
   UINT8 forced_luxury;
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.132
diff -u -r1.132 player.h
--- common/player.h     17 Nov 2004 16:59:07 -0000      1.132
+++ common/player.h     19 Nov 2004 07:34:03 -0000
@@ -104,9 +104,7 @@
   int content;
   int unhappy;
   int angry;
-  int taxmen;
-  int scientists;
-  int elvis;
+  int specialists[MAX_NUM_SPECIALISTS];
   int wonders;
   int techs;
   int techout;
Index: common/aicore/cm.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.c,v
retrieving revision 1.44
diff -u -r1.44 cm.c
--- common/aicore/cm.c  19 Nov 2004 02:31:35 -0000      1.44
+++ common/aicore/cm.c  19 Nov 2004 07:34:03 -0000
@@ -174,7 +174,7 @@
   int production[NUM_STATS];
   double estimated_fitness; /* weighted sum of production */
   bool is_specialist;
-  enum specialist_type spec; /* valid only if is_specialist */
+  Specialist_type_id spec; /* valid only if is_specialist */
   struct tile_vector tiles;  /* valid only if !is_specialist */
   struct tile_type_vector better_types;
   struct tile_type_vector worse_types;
@@ -918,19 +918,7 @@
 
 /*
  * Add the specialist types to the lattice.
- * This structure is necessary for now because each specialist
- * creates only one type of production and we need to map
- * indices from specialist_type to cm_stat.
  */
-struct spec_stat_pair {
-  enum specialist_type spec;
-  enum cm_stat stat;
-};
-const static struct spec_stat_pair pairs[SP_COUNT] =  {
-  { SP_ELVIS, LUXURY },
-  { SP_SCIENTIST, SCIENCE },
-  { SP_TAXMAN, GOLD }
-};
 
 /****************************************************************************
   Create lattice nodes for each type of specialist.  This adds a new
@@ -947,14 +935,13 @@
   /* for each specialist type, create a tile_type that has as production
    * the bonus for the specialist (if the city is allowed to use it) */
   specialist_type_iterate(i) {
-    if (city_can_use_specialist(pcity, pairs[i].spec)) {
-      type.spec = pairs[i].spec;
-      type.production[pairs[i].stat]
-        = game.rgame.specialists[pairs[i].spec].bonus;
+    if (city_can_use_specialist(pcity, i)) {
+      type.spec = i;
+      type.production[SCIENCE] = game.rgame.specialists[i].bonus_sci;
+      type.production[GOLD] = game.rgame.specialists[i].bonus_tax;
+      type.production[LUXURY] = game.rgame.specialists[i].bonus_lux;
 
       tile_type_lattice_add(lattice, &type, 0, 0);
-
-      type.production[pairs[i].stat] = 0;
     }
   } specialist_type_iterate_end;
 }
@@ -2112,10 +2099,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: common/aicore/cm.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.h,v
retrieving revision 1.10
diff -u -r1.10 cm.h
--- common/aicore/cm.h  22 Jul 2004 15:20:47 -0000      1.10
+++ common/aicore/cm.h  19 Nov 2004 07:34:03 -0000
@@ -49,7 +49,7 @@
   int surplus[NUM_STATS];
 
   bool worker_positions_used[CITY_MAP_SIZE][CITY_MAP_SIZE];
-  int specialists[SP_COUNT];
+  int specialists[MAX_NUM_SPECIALISTS];
 };
 
 void cm_init(void);
Index: data/default/cities.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/cities.ruleset,v
retrieving revision 1.11
diff -u -r1.11 cities.ruleset
--- data/default/cities.ruleset 9 Jun 2004 04:39:13 -0000       1.11
+++ data/default/cities.ruleset 19 Nov 2004 07:34:03 -0000
@@ -21,14 +21,13 @@
 ; the city is of a certain size.
 [specialist]
 
-; Changing the order or names of specialists will break things
 types = "elvis", "scientist", "taxman"
 elvis_min_size = 0
-elvis_base_bonus = 2
+elvis_bonus_lux = 2
 scientist_min_size = 5
-scientist_base_bonus = 3
+scientist_bonus_sci = 3
 taxman_min_size = 5
-taxman_base_bonus = 3
+taxman_bonus_tax = 3
 
 changable_tax = 1
 ;forced_science = 0
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   19 Nov 2004 07:34:04 -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.279
diff -u -r1.279 citytools.c
--- server/citytools.c  10 Nov 2004 17:02:00 -0000      1.279
+++ server/citytools.c  19 Nov 2004 07:34:04 -0000
@@ -1575,9 +1575,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];
@@ -2032,7 +2032,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.273
diff -u -r1.273 cityturn.c
--- server/cityturn.c   17 Nov 2004 19:21:14 -0000      1.273
+++ server/cityturn.c   19 Nov 2004 07:34:04 -0000
@@ -384,6 +384,8 @@
 **************************************************************************/
 bool city_reduce_size(struct city *pcity, int pop_loss)
 {
+  int i;
+
   if (pop_loss == 0) {
     return TRUE;
   }
@@ -401,16 +403,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) {
@@ -456,6 +457,8 @@
   bool have_square;
   int savings_pct = granary_savings(pcity), new_food;
   bool rapture_grow = city_rapture_grow(pcity); /* check before size increase! 
*/
+  int best_sci = best_science_specialist();
+  int best_tax = best_tax_specialist();
 
   if (!city_can_grow_to(pcity, pcity->size + 1)) { /* need improvement */
     if (get_current_construction_bonus(pcity, EFT_SIZE_ADJ) > 0) {
@@ -494,18 +497,17 @@
       have_square = TRUE;
     }
   } city_map_iterate_end;
-  if (((pcity->food_surplus >= 2) || !have_square)  &&  pcity->size >= 5  &&
-      (is_city_option_set(pcity, CITYO_NEW_EINSTEIN) || 
-       is_city_option_set(pcity, CITYO_NEW_TAXMAN))) {
-
-    if (is_city_option_set(pcity, CITYO_NEW_EINSTEIN)) {
-      pcity->specialists[SP_SCIENTIST]++;
-    } else { /* now pcity->city_options & (1<<CITYO_NEW_TAXMAN) is true */
-      pcity->specialists[SP_TAXMAN]++;
-    }
 
+  if ((pcity->food_surplus >= 2 || !have_square)
+      && is_city_option_set(pcity, CITYO_NEW_EINSTEIN)
+      && city_can_use_specialist(pcity, best_sci)) {
+    pcity->specialists[best_sci]++;
+  } else if ((pcity->food_surplus >= 2 || !have_square)
+            && is_city_option_set(pcity, CITYO_NEW_TAXMAN)
+            && city_can_use_specialist(pcity, best_tax)) {
+    pcity->specialists[best_tax]++;
   } else {
-    pcity->specialists[SP_TAXMAN]++; /* or else city is !sane */
+    pcity->specialists[DEFAULT_SPECIALIST]++; /* or else city is !sane */
     auto_arrange_workers(pcity);
   }
 
Index: server/report.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/report.c,v
retrieving revision 1.54
diff -u -r1.54 report.c
--- server/report.c     4 Sep 2004 20:36:10 -0000       1.54
+++ server/report.c     19 Nov 2004 07:34:05 -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.taxmen;
-}
+  int i, count = 0;
 
-static int get_scientists(struct player *pplayer)
-{
-  return pplayer->score.scientists;
-}
+  for (i = 0; i < SP_COUNT; i++) {
+    count += pplayer->score.specialists[i];
+  }
 
-static int get_elvis(struct player *pplayer)
-{
-  return pplayer->score.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.200
diff -u -r1.200 ruleset.c
--- server/ruleset.c    17 Nov 2004 19:21:14 -0000      1.200
+++ server/ruleset.c    19 Nov 2004 07:34:06 -0000
@@ -2546,11 +2546,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];
@@ -2558,10 +2553,21 @@
     sz_strlcpy(game.rgame.specialists[i].name, name);
     game.rgame.specialists[i].min_size
       = secfile_lookup_int(file, "specialist.%s_min_size", name);
-    game.rgame.specialists[i].bonus
-      = secfile_lookup_int(file, "specialist.%s_base_bonus", name);
-    
+
+    game.rgame.specialists[i].bonus_sci
+      = secfile_lookup_int_default(file, 0, "specialist.%s_bonus_sci", name);
+    game.rgame.specialists[i].bonus_tax
+      = secfile_lookup_int_default(file, 0, "specialist.%s_bonus_tax", name);
+    game.rgame.specialists[i].bonus_lux
+      = secfile_lookup_int_default(file, 0, "specialist.%s_bonus_lux", name);
+
+    if (game.rgame.specialists[i].min_size == 0
+       && game.rgame.default_specialist == -1) {
+      game.rgame.default_specialist = i;
+    }
   }
+  assert(game.rgame.default_specialist != -1);
+  game.rgame.num_specialist_types = nval;
   free(specialist_names);
 
   game.rgame.changable_tax = 
@@ -2577,11 +2583,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 */
 
@@ -3148,10 +3149,14 @@
   int i;
   struct packet_ruleset_game misc_p;
 
+  misc_p.num_specialist_types = game.rgame.num_specialist_types;
+  misc_p.default_specialist = game.rgame.default_specialist;
   specialist_type_iterate(sp) {
     sz_strlcpy(misc_p.specialist_name[sp], game.rgame.specialists[sp].name);
     misc_p.specialist_min_size[sp] = game.rgame.specialists[sp].min_size;
-    misc_p.specialist_bonus[sp] = game.rgame.specialists[sp].bonus;
+    misc_p.specialist_bonus_sci[sp] = game.rgame.specialists[sp].bonus_sci;
+    misc_p.specialist_bonus_tax[sp] = game.rgame.specialists[sp].bonus_tax;
+    misc_p.specialist_bonus_lux[sp] = game.rgame.specialists[sp].bonus_lux;
   } specialist_type_iterate_end;
   misc_p.changable_tax = game.rgame.changable_tax;
   misc_p.forced_science = game.rgame.forced_science;
Index: server/sanitycheck.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/sanitycheck.c,v
retrieving revision 1.54
diff -u -r1.54 sanitycheck.c
--- server/sanitycheck.c        30 Oct 2004 11:46:11 -0000      1.54
+++ server/sanitycheck.c        19 Nov 2004 07:34:06 -0000
@@ -242,9 +242,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.206
diff -u -r1.206 savegame.c
--- server/savegame.c   17 Nov 2004 19:21:14 -0000      1.206
+++ server/savegame.c   19 Nov 2004 07:34:06 -0000
@@ -2100,7 +2100,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);
@@ -2987,7 +2987,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/score.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/score.c,v
retrieving revision 1.8
diff -u -r1.8 score.c
--- server/score.c      29 Sep 2004 02:24:24 -0000      1.8
+++ server/score.c      19 Nov 2004 07:34:06 -0000
@@ -375,9 +375,9 @@
   pplayer->score.content = 0;
   pplayer->score.unhappy = 0;
   pplayer->score.angry = 0;
-  pplayer->score.taxmen = 0;
-  pplayer->score.scientists = 0;
-  pplayer->score.elvis = 0;
+  specialist_type_iterate(sp) {
+    pplayer->score.specialists[sp] = 0;
+  } specialist_type_iterate_end;
   pplayer->score.wonders = 0;
   pplayer->score.techs = 0;
   pplayer->score.techout = 0;
@@ -406,9 +406,9 @@
     pplayer->score.content += pcity->ppl_content[4];
     pplayer->score.unhappy += pcity->ppl_unhappy[4];
     pplayer->score.angry += pcity->ppl_angry[4];
-    pplayer->score.taxmen += pcity->specialists[SP_TAXMAN];
-    pplayer->score.scientists += pcity->specialists[SP_SCIENTIST];
-    pplayer->score.elvis += pcity->specialists[SP_ELVIS];
+    specialist_type_iterate(sp) {
+      pplayer->score.specialists[sp] += pcity->specialists[sp];
+    } specialist_type_iterate_end;
     pplayer->score.population += city_population(pcity);
     pplayer->score.cities++;
     pplayer->score.pollution += pcity->pollution;
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.312
diff -u -r1.312 unithand.c
--- server/unithand.c   18 Nov 2004 04:17:58 -0000      1.312
+++ server/unithand.c   19 Nov 2004 07:34:07 -0000
@@ -436,7 +436,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]
  • [Freeciv-Dev] (PR#8877) patch: design for generalized specialists, Jason Short <=