[Freeciv-Dev] (PR#8877) RFC: design for generalized specialists
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients: ; |
Subject: |
[Freeciv-Dev] (PR#8877) RFC: design for generalized specialists |
From: |
"Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx> |
Date: |
Tue, 15 Jun 2004 20:27:51 -0700 |
Reply-to: |
rt@xxxxxxxxxxx |
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8877 >
> [jdorje - Sun May 30 23:35:53 2004]:
> The attached patch is a proof-of-concept for this. All needed changes
> are made so that all specialist info is loaded from the ruleset.
> Autogames seem to be unchanged, and (surprisingly) the runtime is not
> impacted either (I could be wrong on this though, it's easy to make a
> mistake when running autogames).
And an updated patch.
jason
Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.109
diff -u -r1.109 advdomestic.c
--- ai/advdomestic.c 27 May 2004 22:14:17 -0000 1.109
+++ ai/advdomestic.c 16 Jun 2004 03:26:16 -0000
@@ -190,6 +190,27 @@
return best;
}
+static int get_num_entertainers(struct city *pcity)
+{
+ int elvis = 0, i;
+
+ /* 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. */
+ for (i = 0; i < SP_COUNT; i++) {
+ if (game.rgame.specialists[i].bonus_lux >= 2) {
+ elvis += pcity->specialists[i];
+ }
+ }
+
+ return elvis;
+}
+
+static int get_num_nonentertainers(struct city *pcity)
+{
+ return city_specialists(pcity) - get_num_entertainers(pcity);
+}
+
/**************************************************************************
Returns the value (desire to build it) of the improvement for keeping
of order in the city.
@@ -211,8 +232,7 @@
{
/* How much one rebeling citizen counts - 16 is debatable value */
#define SADVAL 16
- /* Number of elvises in the city */
- int elvis = pcity->specialists[SP_ELVIS];
+ int elvis = get_num_entertainers(pcity);
/* Raw number of unhappy people */
int sad = pcity->ppl_unhappy[0];
/* Final number of content people */
@@ -246,9 +266,11 @@
* re: Chapel -- Syela */
while (happy > 0) { happy--; value += SADVAL; }
+#if 0
freelog(LOG_DEBUG, "%s: %d elvis %d sad %d content %d size %d val",
pcity->name, pcity->specialists[SP_ELVIS], pcity->ppl_unhappy[4],
pcity->ppl_content[4], pcity->size, value);
+#endif
return value;
#undef SADVAL
@@ -407,7 +429,7 @@
struct player *pplayer = city_owner(pcity);
int bar, est_food, food, grana, hunger, needpower;
int tprod, prod, sci, tax, t, val, wwtv;
- int j, k;
+ int j, k, sp;
int values[B_LAST];
int nplayers = game.nplayers
- team_count_members_alive(pplayer->team);
@@ -426,9 +448,7 @@
sci = 0;
}
- est_food = (2 * pcity->specialists[SP_SCIENTIST]
- + 2 * pcity->specialists[SP_TAXMAN]
- + pcity->food_surplus);
+ est_food = (2 * get_num_nonentertainers(pcity) + pcity->food_surplus);
prod =
(pcity->shield_prod * SHIELD_WEIGHTING * 100) / city_shield_bonus(pcity);
needpower = (city_got_building(pcity, B_MFG) ? 2 :
@@ -445,9 +465,7 @@
grana = food_weighting(grana + 1);
hunger = 1;
j = (pcity->size * 2) + settler_eats(pcity) - pcity->food_prod;
- if (j >= 0
- && pcity->specialists[SP_SCIENTIST] <= 0
- && pcity->specialists[SP_TAXMAN] <= 0) {
+ if (j >= 0 && get_num_nonentertainers(pcity) == 0) {
hunger += j + 1;
}
@@ -533,8 +551,22 @@
case B_MARKETPLACE:
case B_BANK:
case B_STOCK:
- values[id] = (tax + 3 * pcity->specialists[SP_TAXMAN]
- + pcity->specialists[SP_ELVIS] * wwtv) / 2;
+ values[id] = tax; /* +50% to taxes */
+
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ /* +50% to taxmen. */
+ values[id] += (pcity->specialists[sp]
+ * game.rgame.specialists[sp].bonus_tax);
+
+ /* +50% to luxuries => converted to workers. That's 1 more
+ * worker per 4 luxuries. */
+ values[id] += (pcity->specialists[sp]
+ * game.rgame.specialists[sp].bonus_lux
+ * wwtv) / 2;
+ }
+
+ /* Bonus is 50% */
+ values[id] /= 2;
break;
case B_SUPERHIGHWAYS:
values[id] = road_trade(pcity) * t;
@@ -956,9 +988,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/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.155
diff -u -r1.155 aicity.c
--- ai/aicity.c 27 May 2004 22:14:17 -0000 1.155
+++ ai/aicity.c 16 Jun 2004 03:26:16 -0000
@@ -700,7 +700,7 @@
is_valid = map_to_city_map(&city_map_x, &city_map_y, acity, x, y);
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/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.36
diff -u -r1.36 citydlg_common.c
--- client/citydlg_common.c 13 Jun 2004 16:53:34 -0000 1.36
+++ client/citydlg_common.c 16 Jun 2004 03:26:16 -0000
@@ -363,32 +363,29 @@
citizens (use MAX_CITY_SIZE to be on the safe side).
**************************************************************************/
void get_city_citizen_types(struct city *pcity, int index,
- enum citizen_type *citizens)
+ struct citizen_type *citizens)
{
- int i = 0, n;
+ int i = 0, n, sp;
assert(index >= 0 && index < 5);
for (n = 0; n < pcity->ppl_happy[index]; n++, i++) {
- citizens[i] = CITIZEN_HAPPY;
+ citizens[i].type = CITIZEN_HAPPY;
}
for (n = 0; n < pcity->ppl_content[index]; n++, i++) {
- citizens[i] = CITIZEN_CONTENT;
+ citizens[i].type = CITIZEN_CONTENT;
}
for (n = 0; n < pcity->ppl_unhappy[index]; n++, i++) {
- citizens[i] = CITIZEN_UNHAPPY;
+ citizens[i].type = CITIZEN_UNHAPPY;
}
for (n = 0; n < pcity->ppl_angry[index]; n++, i++) {
- citizens[i] = CITIZEN_ANGRY;
+ citizens[i].type = CITIZEN_ANGRY;
}
- for (n = 0; n < pcity->specialists[SP_ELVIS]; n++, i++) {
- citizens[i] = CITIZEN_ELVIS;
- }
- for (n = 0; n < pcity->specialists[SP_SCIENTIST]; n++, i++) {
- citizens[i] = CITIZEN_SCIENTIST;
- }
- for (n = 0; n < pcity->specialists[SP_TAXMAN]; n++, i++) {
- citizens[i] = CITIZEN_TAXMAN;
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ for (n = 0; n < pcity->specialists[sp]; n++, i++) {
+ citizens[i].type = CITIZEN_SPECIALIST;
+ citizens[i].spec_type = sp;
+ }
}
assert(i == pcity->size);
@@ -399,8 +396,8 @@
**************************************************************************/
void city_rotate_specialist(struct city *pcity, int citizen_index)
{
- enum citizen_type citizens[MAX_CITY_SIZE];
- enum specialist_type from, to;
+ struct citizen_type citizens[MAX_CITY_SIZE];
+ int from, to;
if (citizen_index < 0 || citizen_index >= pcity->size) {
return;
@@ -408,19 +405,10 @@
get_city_citizen_types(pcity, 4, citizens);
- switch (citizens[citizen_index]) {
- case CITIZEN_ELVIS:
- from = SP_ELVIS;
- break;
- case CITIZEN_SCIENTIST:
- from = SP_SCIENTIST;
- break;
- case CITIZEN_TAXMAN:
- from = SP_TAXMAN;
- break;
- default:
+ if (citizens[citizen_index].type != CITIZEN_SPECIALIST) {
return;
}
+ from = citizens[citizen_index].spec_type;
/* Loop through all specialists in order until we find a usable one
* (or run out of choices). */
@@ -550,8 +538,7 @@
/**************************************************************************
Change a specialist in the given city. Return the request ID.
**************************************************************************/
-int city_change_specialist(struct city *pcity, enum specialist_type from,
- enum specialist_type to)
+int city_change_specialist(struct city *pcity, int from, int to)
{
return dsend_packet_city_change_specialist(&aconnection, pcity->id, from,
to);
Index: client/citydlg_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.h,v
retrieving revision 1.20
diff -u -r1.20 citydlg_common.h
--- client/citydlg_common.h 4 Apr 2004 14:49:10 -0000 1.20
+++ client/citydlg_common.h 16 Jun 2004 03:26:16 -0000
@@ -23,15 +23,16 @@
struct city;
struct canvas;
-enum citizen_type {
- CITIZEN_ELVIS,
- CITIZEN_SCIENTIST,
- CITIZEN_TAXMAN,
- CITIZEN_CONTENT,
- CITIZEN_HAPPY,
- CITIZEN_UNHAPPY,
- CITIZEN_ANGRY,
- CITIZEN_LAST
+struct citizen_type {
+ enum {
+ CITIZEN_SPECIALIST,
+ CITIZEN_CONTENT,
+ CITIZEN_HAPPY,
+ CITIZEN_UNHAPPY,
+ CITIZEN_ANGRY,
+ CITIZEN_LAST
+ } type;
+ int spec_type;
};
int get_citydlg_canvas_width(void);
@@ -53,7 +54,7 @@
bool is_unit, struct city *pcity);
void get_city_citizen_types(struct city *pcity, int index,
- enum citizen_type *citizens);
+ struct citizen_type *citizens);
void city_rotate_specialist(struct city *pcity, int citizen_index);
void activate_all_units(int map_x, int map_y);
@@ -64,8 +65,7 @@
void city_set_queue(struct city *pcity, struct worklist *pqueue);
int city_sell_improvement(struct city *pcity, Impr_Type_id sell_id);
int city_buy_production(struct city *pcity);
-int city_change_specialist(struct city *pcity, enum specialist_type from,
- enum specialist_type to);
+int city_change_specialist(struct city *pcity, int from, int to);
int city_toggle_worker(struct city *pcity, int city_x, int city_y);
int city_rename(struct city *pcity, const char *name);
Index: client/cityrepdata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/cityrepdata.c,v
retrieving revision 1.33
diff -u -r1.33 cityrepdata.c
--- client/cityrepdata.c 27 May 2004 22:14:18 -0000 1.33
+++ client/cityrepdata.c 16 Jun 2004 03:26:16 -0000
@@ -115,13 +115,20 @@
static char *cr_entry_specialists(struct city *pcity)
{
static char buf[32];
- my_snprintf(buf, sizeof(buf), "%d/%d/%d",
- pcity->specialists[SP_ELVIS],
- pcity->specialists[SP_SCIENTIST],
- pcity->specialists[SP_TAXMAN]);
+ int i;
+
+ buf[0] = '\0';
+ for (i = 0; i < SP_COUNT; i++) {
+ if (i != 0) {
+ sz_strlcat(buf, "/");
+ }
+ my_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "%d", pcity->specialists[i]);
+ }
return buf;
}
+#if 0
static char *cr_entry_entertainers(struct city *pcity)
{
static char buf[8];
@@ -142,6 +149,7 @@
my_snprintf(buf, sizeof(buf), "%2d", pcity->specialists[SP_TAXMAN]);
return buf;
}
+#endif
static char *cr_entry_attack(struct city *pcity)
{
@@ -442,12 +450,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.9
diff -u -r1.9 cityrepdata.h
--- client/cityrepdata.h 4 Feb 2003 22:13:27 -0000 1.9
+++ client/cityrepdata.h 16 Jun 2004 03:26:16 -0000
@@ -21,7 +21,7 @@
#define REPORT_CITYNAME_ABBREV 15
/* 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.380
diff -u -r1.380 packhand.c
--- client/packhand.c 12 Jun 2004 17:42:27 -0000 1.380
+++ client/packhand.c 16 Jun 2004 03:26:17 -0000
@@ -2701,11 +2701,17 @@
{
int i;
+ game.rgame.num_specialist_types = packet->num_specialist_types;
+ game.rgame.default_specialist = packet->default_specialist;
for (i = 0; i < SP_COUNT; i++) {
sz_strlcpy(game.rgame.specialists[i].name, packet->specialist_name[i]);
game.rgame.specialists[i].min_size = packet->specialist_min_size[i];
- game.rgame.specialists[i].bonus = packet->specialist_bonus[i];
+ game.rgame.specialists[i].bonus_sci = packet->specialist_bonus_sci[i];
+ game.rgame.specialists[i].bonus_tax = packet->specialist_bonus_tax[i];
+ game.rgame.specialists[i].bonus_lux = packet->specialist_bonus_lux[i];
}
+ tilespec_setup_citizen_types();
+
game.rgame.changable_tax = packet->changable_tax;
game.rgame.forced_science = packet->forced_science;
game.rgame.forced_luxury = packet->forced_luxury;
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.174
diff -u -r1.174 tilespec.c
--- client/tilespec.c 6 Jun 2004 06:09:46 -0000 1.174
+++ client/tilespec.c 16 Jun 2004 03:26:17 -0000
@@ -897,17 +897,13 @@
/**********************************************************************
Returns a text name for the citizen, as used in the tileset.
***********************************************************************/
-static const char *get_citizen_name(enum citizen_type citizen)
+static const char *get_citizen_name(struct citizen_type citizen)
{
/* These strings are used in reading the tileset. Do not
* translate. */
- switch (citizen) {
- case CITIZEN_ELVIS:
- return "entertainer";
- case CITIZEN_SCIENTIST:
- return "scientist";
- case CITIZEN_TAXMAN:
- return "tax_collector";
+ switch (citizen.type) {
+ case CITIZEN_SPECIALIST:
+ return game.rgame.specialists[citizen.spec_type].name;
case CITIZEN_HAPPY:
return "happy";
case CITIZEN_CONTENT:
@@ -917,7 +913,7 @@
case CITIZEN_ANGRY:
return "angry";
default:
- die("unknown citizen type %d", (int) citizen);
+ die("unknown citizen type %d", (int) citizen.type);
}
return NULL;
}
@@ -958,6 +954,50 @@
#define SET_SPRITE_OPT(field, tag) \
sprites.field = load_sprite(tag)
+void tilespec_setup_citizen_types(void)
+{
+ int i, j;
+ char buffer[512];
+
+ /* Load the citizen sprite graphics. */
+ for (i = 0; i < NUM_TILES_CITIZEN + SP_COUNT; i++) {
+ struct citizen_type c;
+
+ if (i >= NUM_TILES_CITIZEN) {
+ c.type = CITIZEN_SPECIALIST;
+ c.spec_type = i - NUM_TILES_CITIZEN;
+ } else {
+ c.type = i;
+ if (i == CITIZEN_SPECIALIST) {
+ continue;
+ }
+ }
+
+ my_snprintf(buffer, sizeof(buffer), "citizen.%s", get_citizen_name(c));
+ sprites.citizen[i].sprite[0] = load_sprite(buffer);
+ if (sprites.citizen[i].sprite[0]) {
+ /*
+ * If this form exists, use it as the only sprite. This allows
+ * backwards compatability with tilesets that use e.g.,
+ * citizen.entertainer.
+ */
+ sprites.citizen[i].count = 1;
+ continue;
+ }
+
+ for (j = 0; j < NUM_TILES_CITIZEN; j++) {
+ my_snprintf(buffer, sizeof(buffer), "citizen.%s_%d",
+ get_citizen_name(c), j);
+ sprites.citizen[i].sprite[j] = load_sprite(buffer);
+ if (!sprites.citizen[i].sprite[j]) {
+ break;
+ }
+ }
+ sprites.citizen[i].count = j;
+ assert(j > 0);
+ }
+}
+
/**********************************************************************
Initialize 'sprites' structure based on hardwired tags which
freeciv always requires.
@@ -966,7 +1006,7 @@
{
char buffer[512];
const char dir_char[] = "nsew";
- int i, j;
+ int i;
assert(sprite_hash != NULL);
@@ -988,36 +1028,11 @@
SET_SPRITE(dither_tile, "t.dither_tile");
}
+ tilespec_setup_citizen_types();
SET_SPRITE(tax_luxury, "s.tax_luxury");
SET_SPRITE(tax_science, "s.tax_science");
SET_SPRITE(tax_gold, "s.tax_gold");
- /* Load the citizen sprite graphics. */
- for (i = 0; i < NUM_TILES_CITIZEN; i++) {
- my_snprintf(buffer, sizeof(buffer), "citizen.%s", get_citizen_name(i));
- sprites.citizen[i].sprite[0] = load_sprite(buffer);
- if (sprites.citizen[i].sprite[0]) {
- /*
- * If this form exists, use it as the only sprite. This allows
- * backwards compatability with tilesets that use e.g.,
- * citizen.entertainer.
- */
- sprites.citizen[i].count = 1;
- continue;
- }
-
- for (j = 0; j < NUM_TILES_CITIZEN; j++) {
- my_snprintf(buffer, sizeof(buffer), "citizen.%s_%d",
- get_citizen_name(i), j);
- sprites.citizen[i].sprite[j] = load_sprite(buffer);
- if (!sprites.citizen[i].sprite[j]) {
- break;
- }
- }
- sprites.citizen[i].count = j;
- assert(j > 0);
- }
-
SET_SPRITE(spaceship.solar_panels, "spaceship.solar_panels");
SET_SPRITE(spaceship.life_support, "spaceship.life_support");
SET_SPRITE(spaceship.habitation, "spaceship.habitation");
@@ -2636,12 +2651,20 @@
value indicates there is no city; i.e., the sprite is just being
used as a picture).
**************************************************************************/
-struct Sprite *get_citizen_sprite(enum citizen_type type, int citizen_index,
+struct Sprite *get_citizen_sprite(struct citizen_type type,
+ int citizen_index,
struct city *pcity)
{
- assert(type >= 0 && type < NUM_TILES_CITIZEN);
- citizen_index %= sprites.citizen[type].count;
- return sprites.citizen[type].sprite[citizen_index];
+ int i;
+
+ if (type.type == CITIZEN_SPECIALIST) {
+ i = NUM_TILES_CITIZEN + type.spec_type;
+ } else {
+ i = type.type;
+ }
+ assert(i >= 0 && i < NUM_TILES_CITIZEN + SP_COUNT);
+ citizen_index %= sprites.citizen[i].count;
+ return sprites.citizen[i].sprite[citizen_index];
}
/**************************************************************************
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.70
diff -u -r1.70 tilespec.h
--- client/tilespec.h 6 Jun 2004 06:09:46 -0000 1.70
+++ client/tilespec.h 16 Jun 2004 03:26:17 -0000
@@ -54,6 +54,7 @@
void tilespec_reread(const char *tileset_name);
void tilespec_reread_callback(struct client_option *option);
+void tilespec_setup_citizen_types(void);
void tilespec_setup_unit_type(int id);
void tilespec_setup_impr_type(int id);
void tilespec_setup_tech_type(int id);
@@ -159,7 +160,7 @@
* sprites, as defined by the tileset. */
int count;
struct Sprite *sprite[MAX_NUM_CITIZEN_SPRITES];
- } citizen[NUM_TILES_CITIZEN];
+ } citizen[NUM_TILES_CITIZEN + MAX_NUM_SPECIALISTS - 1];
struct {
struct Sprite
*solar_panels,
@@ -253,7 +254,7 @@
extern struct named_sprites sprites;
-struct Sprite *get_citizen_sprite(enum citizen_type type, int citizen_index,
+struct Sprite *get_citizen_sprite(struct citizen_type type, int citizen_index,
struct city *pcity);
/* full pathnames: */
Index: client/agents/cma_core.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/agents/cma_core.c,v
retrieving revision 1.53
diff -u -r1.53 cma_core.c
--- client/agents/cma_core.c 29 May 2004 20:34:31 -0000 1.53
+++ client/agents/cma_core.c 16 Jun 2004 03:26:17 -0000
@@ -103,6 +103,18 @@
return worker;
}
+static int count_specialist(struct city *pcity,
+ const struct cm_result *const result)
+{
+ int count = 0, sp;
+
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ count += result->specialists[sp];
+ }
+
+ return count;
+}
+
#define T(x) if (result1->x != result2->x) { \
freelog(RESULTS_ARE_EQUAL_LOG_LEVEL, #x); \
return FALSE; }
@@ -115,11 +127,14 @@
const struct cm_result *const result1,
const struct cm_result *const result2)
{
+ int sp;
+
T(disorder);
T(happy);
- T(specialists[SP_ELVIS]);
- T(specialists[SP_SCIENTIST]);
- T(specialists[SP_TAXMAN]);
+
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ T(specialists[sp]);
+ }
T(production[FOOD]);
T(production[SHIELD]);
@@ -156,11 +171,13 @@
{
freelog(LOG_NORMAL, "print_city(city='%s'(id=%d))",
pcity->name, pcity->id);
+#if 0
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]);
+#endif
freelog(LOG_NORMAL, " workers at:");
my_city_map_iterate(pcity, x, y) {
if (pcity->city_map[x][y] == C_TILE_WORKER) {
@@ -188,7 +205,7 @@
static void print_result(struct city *pcity,
const struct cm_result *const result)
{
- int y, i, worker = count_worker(pcity, result);
+ int y, i;
freelog(LOG_NORMAL, "print_result(result=%p)", result);
freelog(LOG_NORMAL,
@@ -223,10 +240,12 @@
freelog(LOG_NORMAL, "print_result: %s", line);
}
+#if 0
freelog(LOG_NORMAL,
"print_result: people: W/E/S/T %d/%d/%d/%d",
- worker, result->specialists[SP_ELVIS],
+ count_worker(pcity, result), result->specialists[SP_ELVIS],
result->specialists[SP_SCIENTIST], result->specialists[SP_TAXMAN]);
+#endif
for (i = 0; i < NUM_STATS; i++) {
freelog(LOG_NORMAL,
@@ -269,7 +288,7 @@
static void get_current_as_result(struct city *pcity,
struct cm_result *result)
{
- int worker = 0, i;
+ int worker = 0, i, specialists = 0;
memset(result->worker_positions_used, 0,
sizeof(result->worker_positions_used));
@@ -284,11 +303,10 @@
for (i = 0; i < SP_COUNT; i++) {
result->specialists[i] = pcity->specialists[i];
+ specialists += pcity->specialists[i];
}
- assert(worker + result->specialists[SP_ELVIS]
- + result->specialists[SP_SCIENTIST]
- + result->specialists[SP_TAXMAN] == pcity->size);
+ assert(worker + specialists == pcity->size);
result->found_a_valid = TRUE;
@@ -352,10 +370,7 @@
/* Do checks */
worker = count_worker(pcity, result);
- if (pcity->size !=
- (worker + result->specialists[SP_ELVIS]
- + result->specialists[SP_SCIENTIST]
- + result->specialists[SP_TAXMAN])) {
+ if (pcity->size != (worker + count_specialist(pcity, result))) {
print_city(pcity);
print_result(pcity, result);
assert(0);
@@ -372,11 +387,13 @@
}
} 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). */
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp == DEFAULT_SPECIALIST) {
+ continue;
+ }
for (i = 0; i < pcity->specialists[sp] - result->specialists[sp]; i++) {
- last_request_id = city_change_specialist(pcity, sp, SP_ELVIS);
+ last_request_id = city_change_specialist(pcity, sp, DEFAULT_SPECIALIST);
if (first_request_id == 0) {
first_request_id = last_request_id;
}
@@ -386,8 +403,8 @@
/* 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) {
@@ -399,12 +416,14 @@
}
} 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). */
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp == DEFAULT_SPECIALIST) {
+ continue;
+ }
for (i = 0; i < result->specialists[sp] - pcity->specialists[sp]; i++) {
- last_request_id = city_change_specialist(pcity, SP_ELVIS, sp);
+ last_request_id = city_change_specialist(pcity, DEFAULT_SPECIALIST, sp);
if (first_request_id == 0) {
first_request_id = last_request_id;
}
Index: client/agents/cma_fec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/agents/cma_fec.c,v
retrieving revision 1.20
diff -u -r1.20 cma_fec.c
--- client/agents/cma_fec.c 29 May 2004 20:34:31 -0000 1.20
+++ client/agents/cma_fec.c 16 Jun 2004 03:26:18 -0000
@@ -359,6 +359,7 @@
my_snprintf(buf[5], BUFFER_SIZE, "%3d(%+3d)",
result->production[SCIENCE], result->surplus[SCIENCE]);
+#if 0
my_snprintf(buf[6], BUFFER_SIZE, "%d/%d/%d/%d%s",
pcity->size -
(result->specialists[SP_ELVIS]
@@ -368,6 +369,9 @@
result->specialists[SP_SCIENTIST],
result->specialists[SP_TAXMAN],
result->happy ? _(" happy") : "");
+#else
+ my_snprintf(buf[6], BUFFER_SIZE, "FIXME");
+#endif
my_snprintf(buf[7], BUFFER_SIZE, "%s",
get_city_growth_string(pcity, result->surplus[FOOD]));
Index: client/gui-gtk-2.0/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/citydlg.c,v
retrieving revision 1.88
diff -u -r1.88 citydlg.c
--- client/gui-gtk-2.0/citydlg.c 24 May 2004 13:00:51 -0000 1.88
+++ client/gui-gtk-2.0/citydlg.c 16 Jun 2004 03:26:19 -0000
@@ -1262,7 +1262,7 @@
{
int i, width;
struct city *pcity = pdialog->pcity;
- enum citizen_type citizens[MAX_CITY_SIZE];
+ struct citizen_type citizens[MAX_CITY_SIZE];
/* If there is not enough space we stack the icons. We draw from left to */
/* right. width is how far we go to the right for each drawn pixmap. The */
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.c,v
retrieving revision 1.73
diff -u -r1.73 gui_main.c
--- client/gui-gtk-2.0/gui_main.c 6 Jun 2004 06:00:08 -0000 1.73
+++ client/gui-gtk-2.0/gui_main.c 16 Jun 2004 03:26:19 -0000
@@ -671,7 +671,8 @@
int i;
struct Sprite *sprite;
GtkCellRenderer *rend;
-
+ struct citizen_type c;
+
main_tips = gtk_tooltips_new();
/* the window is divided into two panes. "top" and "message window" */
@@ -803,6 +804,9 @@
gtk_container_add(GTK_CONTAINER(ebox), table2);
for (i = 0; i < 10; i++) {
+ c.type = CITIZEN_SPECIALIST;
+ c.spec_type = 0;
+
ebox = gtk_event_box_new();
gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK);
@@ -811,8 +815,12 @@
g_signal_connect(ebox, "button_press_event",
G_CALLBACK(taxrates_callback), GINT_TO_POINTER(i));
- sprite = i < 5 ? sprites.tax_science : sprites.tax_gold;
+#if 0
+ sprite = get_citizen_sprite(c, i, NULL);
econ_label[i] = gtk_image_new_from_pixmap(sprite->pixmap, sprite->mask);
+#endif
+ /* FIXME: use different tags (not the specialists) for these graphics. */
+ econ_label[i] = gtk_image_new();
gtk_container_add(GTK_CONTAINER(ebox), econ_label[i]);
}
@@ -820,7 +828,8 @@
bulb_label = gtk_image_new_from_pixmap(sprites.bulb[0]->pixmap, NULL);
sun_label = gtk_image_new_from_pixmap(sprites.warming[0]->pixmap, NULL);
flake_label = gtk_image_new_from_pixmap(sprites.cooling[0]->pixmap, NULL);
- sprite = get_citizen_sprite(CITIZEN_UNHAPPY, 0, NULL);
+ c.type = CITIZEN_UNHAPPY;
+ sprite = get_citizen_sprite(c, 0, NULL);
government_label = gtk_image_new_from_pixmap(sprite->pixmap, sprite->mask);
for (i = 0; i < 4; i++) {
Index: client/gui-gtk-2.0/happiness.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/happiness.c,v
retrieving revision 1.12
diff -u -r1.12 happiness.c
--- client/gui-gtk-2.0/happiness.c 5 May 2004 20:39:15 -0000 1.12
+++ client/gui-gtk-2.0/happiness.c 16 Jun 2004 03:26:19 -0000
@@ -153,7 +153,7 @@
static void refresh_pixcomm(GtkPixcomm *dst, struct city *pcity, int index)
{
int i;
- enum citizen_type citizens[MAX_CITY_SIZE];
+ struct citizen_type citizens[MAX_CITY_SIZE];
int num_citizens = pcity->size;
int offset = MIN(SMALL_TILE_WIDTH, PIXCOMM_WIDTH / num_citizens);
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.129
diff -u -r1.129 mapview.c
--- client/gui-gtk-2.0/mapview.c 10 Jun 2004 01:04:53 -0000 1.129
+++ client/gui-gtk-2.0/mapview.c 16 Jun 2004 03:26:19 -0000
@@ -124,6 +124,31 @@
{
int d;
int sol, flake;
+ int lux_specialist = DEFAULT_SPECIALIST,
+ sci_specialist = DEFAULT_SPECIALIST,
+ tax_specialist = DEFAULT_SPECIALIST;
+
+ {
+ /* The tileset should specify different tags for science, luxury,
+ * and tax percentage sprites. Instead we just guess the best
+ * specialist to use the sprite from. */
+ int max_lux = -1, max_sci = -1, max_tax = -1, i;
+
+ for (i = 0; i < SP_COUNT; i++) {
+ if (game.rgame.specialists[i].bonus_lux > max_lux) {
+ max_lux = game.rgame.specialists[i].bonus_lux;
+ lux_specialist = i;
+ }
+ if (game.rgame.specialists[i].bonus_sci > max_sci) {
+ max_sci = game.rgame.specialists[i].bonus_sci;
+ sci_specialist = i;
+ }
+ if (game.rgame.specialists[i].bonus_tax > max_tax) {
+ max_tax = game.rgame.specialists[i].bonus_tax;
+ tax_specialist = i;
+ }
+ }
+ }
gtk_frame_set_label(GTK_FRAME(main_frame_civ_name),
get_nation_name(game.player_ptr->nation));
@@ -250,7 +275,8 @@
if (game.government_count==0) {
/* not sure what to do here */
- gov_sprite = get_citizen_sprite(CITIZEN_UNHAPPY, 0, NULL);
+ struct citizen_type c = {CITIZEN_UNHAPPY};
+ gov_sprite = get_citizen_sprite(c, 0, NULL);
} else {
gov_sprite = get_government(gov)->sprite;
}
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.169
diff -u -r1.169 capstr.c
--- common/capstr.c 12 Jun 2004 17:42:27 -0000 1.169
+++ common/capstr.c 16 Jun 2004 03:26:19 -0000
@@ -77,7 +77,7 @@
#define CAPABILITY "+1.14.delta +last_turns_shield_surplus veteran +orders " \
"+starter +union +iso_maps +big_map_size +orders2client " \
"+change_production +tilespec1 +no_earth +trans " \
- "+want_hack invasions bombard +killstack2 spec +spec2 " \
+ "+want_hack invasions bombard +killstack2 spec +spec3 " \
"+city_map"
/* "+1.14.delta" is the new delta protocol for 1.14.0-dev.
@@ -121,7 +121,7 @@
*
* "spec" is configurable specialists
*
- * "spec2" is semi-configurable specialists in an array
+ * "spec3" is configurable specialists in an array
*
* "city_map" means the city_map is sent as an array instead of a bitfield.
*/
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.220
diff -u -r1.220 city.c
--- common/city.c 16 Jun 2004 03:01:02 -0000 1.220
+++ common/city.c 16 Jun 2004 03:26:19 -0000
@@ -537,8 +537,7 @@
/****************************************************************************
Returns TRUE iff if the given city can use this kind of specialist.
****************************************************************************/
-bool city_can_use_specialist(const struct city *pcity,
- enum specialist_type type)
+bool city_can_use_specialist(const struct city *pcity, int type)
{
return pcity->size >= game.rgame.specialists[type].min_size;
}
@@ -1814,6 +1813,7 @@
int sci_rest, tax_rest, lux_rest;
struct player *pplayer = city_owner(pcity);
int sci_rate, lux_rate, tax_rate;
+ int i;
if (game.rgame.changable_tax) {
sci_rate = pplayer->economic.science;
@@ -1908,17 +1908,15 @@
assert(sci + tax + lux == pcity->trade_prod);
+ for (i = 0; i < game.rgame.num_specialist_types; i++) {
+ lux += pcity->specialists[i] * game.rgame.specialists[i].bonus_lux;
+ sci += pcity->specialists[i] * game.rgame.specialists[i].bonus_sci;
+ tax += pcity->specialists[i] * game.rgame.specialists[i].bonus_tax;
+ }
+
pcity->science_total = sci;
- pcity->tax_total = tax;
+ pcity->tax_total = tax + get_city_tithes_bonus(pcity);
pcity->luxury_total = lux;
-
- 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)
- + get_city_tithes_bonus(pcity));
}
/**************************************************************************
@@ -2503,13 +2501,55 @@
{
int count = 0, i;
- for (i = 0; i < SP_COUNT; i++) {
+ for (i = 0; i < game.rgame.num_specialist_types; i++) {
count += pcity->specialists[i];
}
return count;
}
+int best_science_specialist(void)
+{
+ int best = DEFAULT_SPECIALIST, val = -1, i;
+
+ for (i = 0; i < SP_COUNT; i++) {
+ if (game.rgame.specialists[i].bonus_sci > val) {
+ best = i;
+ val = game.rgame.specialists[i].bonus_sci;
+ }
+ }
+
+ return best;
+}
+
+int best_tax_specialist(void)
+{
+ int best = DEFAULT_SPECIALIST, val = -1, i;
+
+ for (i = 0; i < SP_COUNT; i++) {
+ if (game.rgame.specialists[i].bonus_tax > val) {
+ best = i;
+ val = game.rgame.specialists[i].bonus_tax;
+ }
+ }
+
+ return best;
+}
+
+int best_luxury_specialist(void)
+{
+ int best = DEFAULT_SPECIALIST, val = -1, i;
+
+ for (i = 0; i < SP_COUNT; i++) {
+ if (game.rgame.specialists[i].bonus_lux > val) {
+ best = i;
+ val = game.rgame.specialists[i].bonus_lux;
+ }
+ }
+
+ return best;
+}
+
/**************************************************************************
Return the power (pacifying effect) of temples in the city.
**************************************************************************/
@@ -2657,10 +2697,10 @@
pcity->y = y;
sz_strlcpy(pcity->name, name);
pcity->size = 1;
- for (i = 0; i < SP_COUNT; i++) {
+ for (i = 0; i < game.rgame.num_specialist_types; i++) {
pcity->specialists[i] = 0;
}
- 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.149
diff -u -r1.149 city.h
--- common/city.h 14 Jun 2004 23:43:08 -0000 1.149
+++ common/city.h 16 Jun 2004 03:26:19 -0000
@@ -25,10 +25,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
};
@@ -82,6 +78,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
@@ -228,7 +227,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];
@@ -363,7 +362,7 @@
bool can_build_unit(const struct city *pcity, Unit_Type_id id);
bool can_build_unit_direct(const struct city *pcity, Unit_Type_id id);
bool can_eventually_build_unit(const struct city *pcity, Unit_Type_id id);
-bool city_can_use_specialist(const struct city *pcity, enum specialist_type
type);
+bool city_can_use_specialist(const struct city *pcity, int type);
bool city_got_building(const struct city *pcity, Impr_Type_id id);
bool city_affected_by_wonder(const struct city *pcity, Impr_Type_id id);
bool city_got_effect(const struct city *pcity, Impr_Type_id id);
@@ -479,6 +478,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 */
+int best_science_specialist(void);
+int best_tax_specialist(void);
+int best_luxury_specialist(void);
int get_temple_power(const struct city *pcity);
int get_cathedral_power(const struct city *pcity);
int get_colosseum_power(const struct city *pcity);
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.180
diff -u -r1.180 game.c
--- common/game.c 18 May 2004 16:29:30 -0000 1.180
+++ common/game.c 16 Jun 2004 03:26:20 -0000
@@ -73,13 +73,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.142
diff -u -r1.142 game.h
--- common/game.h 9 Jun 2004 04:39:12 -0000 1.142
+++ common/game.h 16 Jun 2004 03:26:20 -0000
@@ -186,10 +186,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.29
diff -u -r1.29 packets.def
--- common/packets.def 12 Jun 2004 17:42:27 -0000 1.29
+++ common/packets.def 16 Jun 2004 03:26:20 -0000
@@ -161,7 +161,7 @@
type EVENT = sint16(enum event_type)
type TERRAIN = uint8(enum tile_terrain_type)
type SPECIAL = uint16(enum tile_special_type)
-type SPECIALIST = uint8(enum specialist_type)
+type SPECIALIST = uint8(int)
type DIPLOMAT_ACTION = uint8(enum diplomat_actions)
type CMDLEVEL = uint8(enum cmdlevel_id)
type PLACE_TYPE = uint8(enum spaceship_place_type)
@@ -386,7 +386,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;
@@ -961,9 +961,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; add-cap(spec)
UINT8 forced_science; add-cap(spec)
UINT8 forced_luxury; add-cap(spec)
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.115
diff -u -r1.115 player.h
--- common/player.h 23 Apr 2004 22:58:06 -0000 1.115
+++ common/player.h 16 Jun 2004 03:26:20 -0000
@@ -103,9 +103,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.26
diff -u -r1.26 cm.c
--- common/aicore/cm.c 16 Jun 2004 03:01:02 -0000 1.26
+++ common/aicore/cm.c 16 Jun 2004 03:26:20 -0000
@@ -147,28 +147,9 @@
#define SHOW_TIME_STATS FALSE
#define DISABLE_CACHE3 FALSE
-#define NUM_SPECIALISTS_ROLES 3
#define MAX_FIELDS_USED (CITY_TILES - 1)
#define MAX_COMBINATIONS 150
-/*
- * Maps (trade, taxmen) -> (gold_production, gold_surplus)
- * Maps (trade, entertainers) -> (luxury_production, luxury_surplus)
- * Maps (trade, scientists) -> (science_production, science_surplus)
- * Maps (luxury, workers) -> (city_is_in_disorder, city_is_happy)
- */
-static struct {
- int allocated_trade, allocated_size, allocated_luxury;
-
- struct secondary_stat {
- bool is_valid;
- short int production, surplus;
- } *secondary_stats;
- struct city_status {
- bool is_valid, disorder, happy;
- } *city_status;
-} cache2;
-
/*
* Contains all combinations. Caches all the data about a city across
* multiple cm_query_result calls about the same city.
@@ -179,7 +160,9 @@
struct {
struct combination {
bool is_valid;
- int max_scientists, max_taxmen, worker;
+ int worker;
+ int max_specialists[MAX_NUM_SPECIALISTS];
+ int cache1_size;
int production2[NUM_PRIMARY_STATS];
enum city_tile_type worker_positions[CITY_MAP_SIZE][CITY_MAP_SIZE];
@@ -203,7 +186,7 @@
int queries;
struct cache_stats {
int hits, misses;
- } cache1, cache2, cache3;
+ } cache1, cache3;
} stats;
/*
@@ -226,6 +209,9 @@
} city_map_checked_iterate_end; \
}
+/* The specialist with best luxury production. */
+static int best_entertainer;
+
/****************************************************************************
* implementation of utility functions (these are relatively independent
* of the algorithms used)
@@ -301,6 +287,17 @@
return TRUE;
}
+static int get_num_specialists(const struct cm_result *const result)
+{
+ int i, count = 0;
+
+ for (i = 0; i < game.rgame.num_specialist_types; i++) {
+ count += result->specialists[i];
+ }
+
+ return count;
+}
+
/****************************************************************************
Returns TRUE iff is the result has the required surplus and the city
isn't in disorder and the city is happy if this is required.
@@ -311,8 +308,7 @@
int i;
if (!parameter->allow_specialists
- && (result->specialists[SP_ELVIS] + result->specialists[SP_SCIENTIST]
- + result->specialists[SP_TAXMAN]) >
+ && (get_num_specialists(result)) >
MAX(0,cache3.pcity->size - cache3.fields_available_total)) {
return FALSE;
}
@@ -340,11 +336,13 @@
{
freelog(LOG_NORMAL, "print_city(city='%s'(id=%d))",
pcity->name, pcity->id);
+#if 0
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]);
+#endif
freelog(LOG_NORMAL, " workers at:");
my_city_map_iterate(pcity, x, y) {
if (pcity->city_map[x][y] == C_TILE_WORKER) {
@@ -372,7 +370,7 @@
static void print_result(struct city *pcity,
const struct cm_result *const result)
{
- int y, i, worker = count_worker(pcity, result);
+ int y, i;
freelog(LOG_NORMAL, "print_result(result=%p)", result);
freelog(LOG_NORMAL,
@@ -407,11 +405,13 @@
freelog(LOG_NORMAL, "print_result: %s", line);
}
+#if 0
freelog(LOG_NORMAL,
"print_result: people: W/E/S/T %d/%d/%d/%d",
- worker, result->specialists[SP_ELVIS],
+ count_worker(pcity, result), result->specialists[SP_ELVIS],
result->specialists[SP_SCIENTIST],
result->specialists[SP_TAXMAN]);
+#endif
for (i = 0; i < NUM_STATS; i++) {
freelog(LOG_NORMAL,
@@ -470,108 +470,6 @@
}
/****************************************************************************
- Wraps the array access to cache2.secondary_stats.
-*****************************************************************************/
-static struct secondary_stat *get_secondary_stat(int trade, int specialists,
- enum specialist_type
- specialist_type)
-{
- freelog(LOG_DEBUG, "second: trade=%d spec=%d type=%d", trade, specialists,
- specialist_type);
-
- assert(trade >= 0 && trade < cache2.allocated_trade);
- assert(specialists >= 0 && specialists < cache2.allocated_size);
-
- return &cache2.secondary_stats[NUM_SPECIALISTS_ROLES *
- (cache2.allocated_size * trade +
- specialists) + specialist_type];
-}
-
-/****************************************************************************
- Wraps the array access to cache2.city_status.
-*****************************************************************************/
-static struct city_status *get_city_status(int luxury, int workers)
-{
- freelog(LOG_DEBUG, "status: lux=%d worker=%d", luxury, workers);
-
- assert(luxury >=0 && luxury < cache2.allocated_luxury);
- assert(workers >= 0 && workers < cache2.allocated_size);
-
- return &cache2.city_status[cache2.allocated_size * luxury + workers];
-}
-
-/****************************************************************************
- Update the cache2 according to the filled out result. If the info is
- already in the cache check that the two match.
-*****************************************************************************/
-static void update_cache2(struct city *pcity,
- const struct cm_result *const result)
-{
- struct secondary_stat *p;
- struct city_status *q;
-
- /*
- * Science is set to 0 if the city is unhappy/in disorder. See
- * unhappy_city_check.
- */
- if (!result->disorder) {
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_SCIENTIST],
- SP_SCIENTIST);
- if (!p->is_valid) {
- p->production = result->production[SCIENCE];
- p->surplus = result->surplus[SCIENCE];
- p->is_valid = TRUE;
- } else {
- assert(p->production == result->production[SCIENCE] &&
- p->surplus == result->surplus[SCIENCE]);
- }
- }
-
- /*
- * Gold is set to 0 if the city is unhappy/in disorder. See
- * unhappy_city_check.
- */
- if (!result->disorder) {
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_TAXMAN],
- SP_TAXMAN);
- if (!p->is_valid && !result->disorder) {
- p->production = result->production[GOLD];
- p->surplus = result->surplus[GOLD];
- p->is_valid = TRUE;
- } else {
- assert(p->production == result->production[GOLD] &&
- p->surplus == result->surplus[GOLD]);
- }
- }
-
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_ELVIS],
- SP_ELVIS);
- if (!p->is_valid) {
- p->production = result->production[LUXURY];
- p->surplus = result->surplus[LUXURY];
- p->is_valid = TRUE;
- } else {
- if (!result->disorder) {
- assert(p->production == result->production[LUXURY] &&
- p->surplus == result->surplus[LUXURY]);
- }
- }
-
- q = get_city_status(result->production[LUXURY],
- count_worker(pcity, result));
- if (!q->is_valid) {
- q->disorder = result->disorder;
- q->happy = result->happy;
- q->is_valid = TRUE;
- } else {
- assert(q->disorder == result->disorder && q->happy == result->happy);
- }
-}
-
-/****************************************************************************
...
*****************************************************************************/
static void clear_cache(void)
@@ -598,17 +496,14 @@
static void real_fill_out_result(struct city *pcity,
struct cm_result *result)
{
- int worker = count_worker(pcity, result);
+ int worker = count_worker(pcity, result), sp;
struct city backup;
freelog(LOG_DEBUG, "real_fill_out_result(city='%s'(%d))", pcity->name,
pcity->id);
/* Do checks */
- if (pcity->size !=
- (worker + result->specialists[SP_ELVIS]
- + result->specialists[SP_SCIENTIST]
- + result->specialists[SP_TAXMAN])) {
+ if (pcity->size != (worker + get_num_specialists(result))) {
print_city(pcity);
print_result(pcity, result);
assert(0);
@@ -630,9 +525,9 @@
}
} my_city_map_iterate_end;
- pcity->specialists[SP_ELVIS] = result->specialists[SP_ELVIS];
- pcity->specialists[SP_SCIENTIST] = result->specialists[SP_SCIENTIST];
- pcity->specialists[SP_TAXMAN] = result->specialists[SP_TAXMAN];
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ pcity->specialists[sp] = result->specialists[sp];
+ }
/* Do a local recalculation of the city */
generic_city_refresh(pcity, FALSE, NULL);
@@ -642,6 +537,7 @@
/* Restore */
memcpy(pcity, &backup, sizeof(struct city));
+#if 0
freelog(LOG_DEBUG, "xyz: w=%d e=%d s=%d t=%d trade=%d "
"sci=%d lux=%d tax=%d dis=%s happy=%s",
count_worker(pcity, result), result->specialists[SP_ELVIS],
@@ -651,7 +547,7 @@
result->production[LUXURY],
result->production[GOLD],
result->disorder ? "yes" : "no", result->happy ? "yes" : "no");
- update_cache2(pcity, result);
+#endif
}
/****************************************************************************
@@ -751,7 +647,6 @@
#if SHOW_CACHE_STATS
report_one_cache_stat(&stats.cache1, "CACHE1");
- report_one_cache_stat(&stats.cache2, "CACHE2");
report_one_cache_stat(&stats.cache3, "CACHE3");
#endif
}
@@ -760,16 +655,34 @@
algorithmic functions
*****************************************************************************/
+static int combination_spec_index(struct combination *combination,
+ int *specialists)
+{
+ int sp, index = 0;
+
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp == best_entertainer) {
+ continue;
+ }
+
+ index *= combination->max_specialists[sp] + 1;
+ index += specialists[sp];
+ }
+
+ return index;
+}
+
/****************************************************************************
Frontend cache for real_fill_out_result. This method tries to avoid
calling real_fill_out_result by all means.
*****************************************************************************/
static void fill_out_result(struct city *pcity, struct cm_result *result,
struct combination *base_combination,
- int scientists, int taxmen)
+ int *specialists)
{
struct cm_result *slot;
- bool got_all;
+ int sp;
+ bool all_zero = TRUE;
assert(base_combination->is_valid);
@@ -777,23 +690,42 @@
* First try to get a filled out result from cache1 or from the
* all_entertainer result.
*/
- if (scientists == 0 && taxmen == 0) {
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp != best_entertainer
+ && specialists[sp] != 0) {
+ /* I used to call combination_spec_index up above. Then if all
+ * the specialists were zero the index would be zero. Duh. But
+ * in some cases (with all 0's) the max_specialists fields are not
+ * filled out. This
+ * causes valgrind to give a spurious error. Of course 0 times and
+ * unknown value is 0, but valgrind thinks it is unknown.
+ *
+ * So, to make debugging easier I just do the check manually. */
+ all_zero = FALSE;
+ break;
+ }
+ }
+ if (all_zero) {
slot = &base_combination->all_entertainer;
} else {
- assert(scientists <= base_combination->max_scientists);
- assert(taxmen <= base_combination->max_taxmen);
+ int index = combination_spec_index(base_combination, specialists);
+
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp == best_entertainer) continue;
+ assert(specialists[sp] <= base_combination->max_specialists[sp]);
+ }
assert(base_combination->cache1 != NULL);
assert(base_combination->all_entertainer.found_a_valid);
- slot = &base_combination->cache1[scientists *
- (base_combination->max_taxmen + 1) +
- taxmen];
+ slot = &base_combination->cache1[index];
}
+#if 0
freelog(LOG_DEBUG,
"fill_out_result(base_comb=%p (w=%d), scientists=%d, taxmen=%d) %s",
base_combination, base_combination->worker, scientists,
taxmen, slot->found_a_valid ? "CACHED" : "unknown");
+#endif
if (slot->found_a_valid) {
/* Cache1 contains the result */
@@ -808,89 +740,21 @@
(base_combination->worker_positions[x][y] == C_TILE_WORKER);
} my_city_map_iterate_end;
- result->specialists[SP_SCIENTIST] = scientists;
- result->specialists[SP_TAXMAN] = taxmen;
- result->specialists[SP_ELVIS] =
- pcity->size - (base_combination->worker + scientists + taxmen);
+ result->specialists[best_entertainer]
+ = pcity->size - base_combination->worker;
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ if (sp == best_entertainer) continue;
+ result->specialists[sp] = specialists[sp];
+ result->specialists[best_entertainer] -= specialists[sp];
+ }
+
+#if 0
freelog(LOG_DEBUG,
"fill_out_result(city='%s'(%d), entrt.s=%d, scien.s=%d, taxmen=%d)",
pcity->name, pcity->id, result->specialists[SP_ELVIS],
result->specialists[SP_SCIENTIST], result->specialists[SP_TAXMAN]);
-
- /* try to fill result from cache2 */
- if (!base_combination->all_entertainer.found_a_valid) {
- got_all = FALSE;
- } else {
- struct secondary_stat *p;
- struct city_status *q;
- int i;
-
- got_all = TRUE;
-
- /*
- * fill out the primary stats that are known from the
- * all_entertainer result
- */
- for (i = 0; i < NUM_PRIMARY_STATS; i++) {
- result->production[i] =
- base_combination->all_entertainer.production[i];
- result->surplus[i] = base_combination->all_entertainer.surplus[i];
- }
-
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_SCIENTIST],
- SP_SCIENTIST);
- if (!p->is_valid) {
- got_all = FALSE;
- } else {
- result->production[SCIENCE] = p->production;
- result->surplus[SCIENCE] = p->surplus;
- }
-
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_TAXMAN],
- SP_TAXMAN);
- if (!p->is_valid) {
- got_all = FALSE;
- } else {
- result->production[GOLD] = p->production;
- result->surplus[GOLD] = p->surplus;
- }
-
- p = get_secondary_stat(result->production[TRADE],
- result->specialists[SP_ELVIS],
- SP_ELVIS);
- if (!p->is_valid) {
- got_all = FALSE;
- } else {
- result->production[LUXURY] = p->production;
- result->surplus[LUXURY] = p->surplus;
- }
-
- q = get_city_status(result->production[LUXURY],
- base_combination->worker);
- if (!q->is_valid) {
- got_all = FALSE;
- } else {
- result->disorder = q->disorder;
- result->happy = q->happy;
- }
- }
-
- if (got_all) {
- /*
- * All secondary stats and the city status have been filled from
- * cache2.
- */
-
- stats.cache2.hits++;
- memcpy(slot, result, sizeof(struct cm_result));
- slot->found_a_valid = TRUE;
- return;
- }
-
- stats.cache2.misses++;
+#endif
/*
* Result can't be constructed from caches. Do the slow
@@ -1061,86 +925,6 @@
}
/****************************************************************************
- Expand the secondary_stats and city_status fields of cache2 if this
- is necessary. For this the function tries to estimate the upper limit
- of trade and luxury. It will also invalidate cache2.
-*****************************************************************************/
-static void ensure_invalid_cache2(struct city *pcity, int total_tile_trade)
-{
- bool change_size = FALSE;
- int backup,i, luxury, total_trade = total_tile_trade;
-
- /* Hack since trade_between_cities accesses pcity->tile_trade */
- backup = pcity->tile_trade;
- pcity->tile_trade = total_tile_trade;
- for (i = 0; i < NUM_TRADEROUTES; i++) {
- struct city *pc2 = find_city_by_id(pcity->trade[i]);
-
- total_trade += trade_between_cities(pcity, pc2);
- }
- pcity->tile_trade = backup;
-
- /*
- * Estimate an upper limit for the luxury. We assume that the player
- * has set the luxury rate to 100%. There are two extremal cases: all
- * citizen are entertainers (yielding a luxury of "(pcity->size * 2
- * * get_city_tax_bonus(pcity))/100" = A) or all citizen are
- * working on tiles and the resulting trade is converted to luxury
- * (yielding a luxury of "(total_trade * get_city_tax_bonus(pcity))
- * / 100" = B) . We can't use MAX(A, B) since there may be cases in
- * between them which are better than these two exremal cases. So we
- * use A+B as upper limit.
- */
- luxury =
- ((pcity->size * 2 + total_trade) * get_city_tax_bonus(pcity)) / 100;
-
- /* +1 because we want to index from 0 to pcity->size inclusive */
- if (pcity->size + 1 > cache2.allocated_size) {
- cache2.allocated_size = pcity->size + 1;
- change_size = TRUE;
- }
-
- if (total_trade + 1 > cache2.allocated_trade) {
- cache2.allocated_trade = total_trade + 1;
- change_size = TRUE;
- }
-
- if (luxury + 1 > cache2.allocated_luxury) {
- cache2.allocated_luxury = luxury + 1;
- change_size = TRUE;
- }
-
- if (change_size) {
- freelog(LOG_DEBUG,
- "CM: expanding cache2 to size=%d, trade=%d, luxury=%d",
- cache2.allocated_size, cache2.allocated_trade,
- cache2.allocated_luxury);
- if (cache2.secondary_stats) {
- free(cache2.secondary_stats);
- cache2.secondary_stats = NULL;
- }
- cache2.secondary_stats =
- fc_malloc(cache2.allocated_trade * cache2.allocated_size *
- NUM_SPECIALISTS_ROLES * sizeof(struct secondary_stat));
-
- if (cache2.city_status) {
- free(cache2.city_status);
- cache2.city_status = NULL;
- }
- cache2.city_status =
- fc_malloc(cache2.allocated_luxury * cache2.allocated_size *
- sizeof(struct city_status));
- }
-
- /* Make cache2 invalid */
- memset(cache2.secondary_stats, 0,
- cache2.allocated_trade * cache2.allocated_size *
- NUM_SPECIALISTS_ROLES * sizeof(struct secondary_stat));
- memset(cache2.city_status, 0,
- cache2.allocated_luxury * cache2.allocated_size *
- sizeof(struct city_status));
-}
-/****************************************************************************
Setup. Adds the root combination (the combination which doesn't use
any worker but the production of the city center). Incrementaly calls
expand_cache3.
@@ -1219,8 +1003,6 @@
for (i = 1; i <= MIN(cache3.fields_available_total, pcity->size); i++) {
expand_cache3(pcity, i, &tile_stats);
}
-
- ensure_invalid_cache2(pcity, total_tile_trade);
}
/****************************************************************************
@@ -1234,28 +1016,35 @@
int *best_minor_fitness)
{
int worker = base_combination->worker;
- int specialists = pcity->size - worker;
- int scientists, taxmen;
+ int num_specialists = pcity->size - worker;
+ int index;
if (!base_combination->cache1) {
/* setup cache1 */
- int i, items;
+ int i, items = 1, sp;
- if (city_can_use_specialist(pcity, SP_SCIENTIST)) {
- base_combination->max_scientists = specialists;
- } else {
- base_combination->max_scientists = 0;
- }
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ int max;
- if (city_can_use_specialist(pcity, SP_TAXMAN)) {
- base_combination->max_taxmen = specialists;
- } else {
- base_combination->max_taxmen = 0;
+ if (sp == best_entertainer) {
+ base_combination->max_specialists[sp] = num_specialists;
+ assert(city_can_use_specialist(pcity, sp));
+ continue;
+ }
+
+ if (city_can_use_specialist(pcity, sp)) {
+ max = num_specialists;
+ } else {
+ max = 0;
+ }
+
+ base_combination->max_specialists[sp] = max;
+ items *= (max + 1);
}
- items = (base_combination->max_scientists + 1) *
- (base_combination->max_taxmen + 1);
+
+ base_combination->cache1_size = items;
base_combination->cache1 =
fc_malloc(sizeof(struct cm_result) * items);
for (i = 0; i < items; i++) {
@@ -1265,54 +1054,75 @@
best_result->found_a_valid = FALSE;
- for (scientists = 0;
- scientists <= base_combination->max_scientists; scientists++) {
- for (taxmen = 0;
- taxmen <= base_combination->max_taxmen - scientists; taxmen++) {
- int major_fitness, minor_fitness;
- struct cm_result result;
+ for (index = 0; index < base_combination->cache1_size; index++) {
+ int specialists[SP_COUNT], sp, count = 0, myindex = index;
+ int major_fitness, minor_fitness;
+ struct cm_result result;
+
+ for (sp = SP_COUNT - 1; sp >= 0; sp--) {
+ /* This loop is the inverse of combination_spec_index(). */
+ int max = base_combination->max_specialists[sp] + 1;
- freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
- " optimize_people: using (W/E/S/T) %d/%d/%d/%d",
- worker, pcity->size - (worker + scientists + taxmen),
- scientists, taxmen);
+ if (sp == best_entertainer) {
+ continue;
+ }
+ if (max == 0) {
+ specialists[sp] = 0;
+ continue;
+ }
- fill_out_result(pcity, &result, base_combination, scientists,
- taxmen);
+ specialists[sp] = myindex % max;
+ myindex /= max;
- freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
- " optimize_people: got extra=(tax=%d, luxury=%d, "
- "science=%d)",
- result.surplus[GOLD] - parameter->minimal_surplus[GOLD],
- result.surplus[LUXURY] -
- parameter->minimal_surplus[LUXURY],
- result.surplus[SCIENCE] -
- parameter->minimal_surplus[SCIENCE]);
+ count += specialists[sp];
+ }
+ if (count > num_specialists) {
+ /* FIXME: cache1 is much bigger than it needs to be! */
+ continue;
+ }
+ specialists[best_entertainer] = num_specialists - count;
- if (!is_valid_result(parameter, &result)) {
- freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
- " optimize_people: doesn't have enough surplus or disorder");
- continue;
- }
+#if 0
+ freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
+ " optimize_people: using (W/E/S/T) %d/%d/%d/%d",
+ worker, pcity->size - (worker + scientists + taxmen),
+ scientists, taxmen);
+#endif
+
+ fill_out_result(pcity, &result, base_combination, specialists);
- calc_fitness(pcity, parameter, &result, &major_fitness,
- &minor_fitness);
+ freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
+ " optimize_people: got extra=(tax=%d, luxury=%d, "
+ "science=%d)",
+ result.surplus[GOLD] - parameter->minimal_surplus[GOLD],
+ result.surplus[LUXURY] -
+ parameter->minimal_surplus[LUXURY],
+ result.surplus[SCIENCE] -
+ parameter->minimal_surplus[SCIENCE]);
+ if (!is_valid_result(parameter, &result)) {
freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
- " optimize_people: fitness=(%d,%d)", major_fitness,
- minor_fitness);
+ " optimize_people: doesn't have enough surplus or disorder");
+ continue;
+ }
- result.found_a_valid = TRUE;
- if (!best_result->found_a_valid
- || ((major_fitness > *best_major_fitness)
- || (major_fitness == *best_major_fitness
- && minor_fitness > *best_minor_fitness))) {
- memcpy(best_result, &result, sizeof(struct cm_result));
- *best_major_fitness = major_fitness;
- *best_minor_fitness = minor_fitness;
- }
- } /* for taxmen */
- } /* for scientists */
+ calc_fitness(pcity, parameter, &result, &major_fitness,
+ &minor_fitness);
+
+ freelog(FIND_BEST_SPECIALIST_ARRANGEMENT_LOG_LEVEL,
+ " optimize_people: fitness=(%d,%d)", major_fitness,
+ minor_fitness);
+
+ result.found_a_valid = TRUE;
+ if (!best_result->found_a_valid
+ || ((major_fitness > *best_major_fitness)
+ || (major_fitness == *best_major_fitness
+ && minor_fitness > *best_minor_fitness))) {
+ memcpy(best_result, &result, sizeof(struct cm_result));
+ *best_major_fitness = major_fitness;
+ *best_minor_fitness = minor_fitness;
+ }
+ }
}
/****************************************************************************
@@ -1344,6 +1154,7 @@
&cache3.results[fields_used].combinations[i];
int stat, major_fitness, minor_fitness;
struct cm_result result;
+ int specialists[SP_COUNT], sp;
if (!current->is_valid) {
continue;
@@ -1352,7 +1163,13 @@
freelog(OPTIMIZE_FINAL_LOG_LEVEL2, " trying combination %d", i);
/* this will set the all_entertainer result */
- fill_out_result(pcity, &result, current, 0, 0);
+ // memset(specialists, 0, sizeof(specialists));
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ specialists[sp] = 0;
+ }
+ /* FIXME: although specialists[i] == 0 max_specialists[i] has not
+ * been filled out. Is this a bug? At the least it's risky... */
+ fill_out_result(pcity, &result, current, specialists);
/*
* Check. The actual production can be bigger because of city
@@ -1451,15 +1268,6 @@
free_timer(stats.wall_timer);
stats.wall_timer = NULL;
- free(cache2.secondary_stats);
- cache2.secondary_stats = NULL;
-
- free(cache2.city_status);
- cache2.city_status = NULL;
-
- cache2.allocated_size = 0;
- cache2.allocated_trade = 0;
- cache2.allocated_luxury = 0;
clear_cache();
}
Index: common/aicore/cm.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.h,v
retrieving revision 1.6
diff -u -r1.6 cm.h
--- common/aicore/cm.h 16 Jun 2004 03:01:02 -0000 1.6
+++ common/aicore/cm.h 16 Jun 2004 03:26:20 -0000
@@ -57,7 +57,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 16 Jun 2004 03:26:20 -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: data/misc/small.spec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/misc/small.spec,v
retrieving revision 1.6
diff -u -r1.6 small.spec
--- data/misc/small.spec 11 Jun 2004 16:59:18 -0000 1.6
+++ data/misc/small.spec 16 Jun 2004 03:26:21 -0000
@@ -76,9 +76,9 @@
; Citizen icons:
- 0, 23, "citizen.entertainer"
+ 0, 23, "citizen.elvis"
0, 24, "citizen.scientist"
- 0, 25, "citizen.tax_collector"
+ 0, 25, "citizen.taxman"
0, 26, "citizen.content_0"
0, 27, "citizen.content_1"
0, 28, "citizen.happy_0"
Index: server/cityhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityhand.c,v
retrieving revision 1.132
diff -u -r1.132 cityhand.c
--- server/cityhand.c 2 Jun 2004 22:54:15 -0000 1.132
+++ server/cityhand.c 16 Jun 2004 03:26:21 -0000
@@ -63,8 +63,7 @@
...
**************************************************************************/
void handle_city_change_specialist(struct player *pplayer, int city_id,
- enum specialist_type from,
- enum specialist_type to)
+ int from, int to)
{
struct city *pcity = player_find_city_by_id(pplayer, city_id);
@@ -106,7 +105,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.261
diff -u -r1.261 citytools.c
--- server/citytools.c 14 Jun 2004 23:43:08 -0000 1.261
+++ server/citytools.c 16 Jun 2004 03:26:21 -0000
@@ -1687,9 +1687,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];
+ for (i = 0; i < SP_COUNT; i++) {
+ packet->specialists[i] = pcity->specialists[i];
+ }
for (i = 0; i < NUM_TRADEROUTES; i++) {
packet->trade[i]=pcity->trade[i];
packet->trade_value[i]=pcity->trade_value[i];
@@ -2148,7 +2148,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.249
diff -u -r1.249 cityturn.c
--- server/cityturn.c 29 May 2004 20:34:31 -0000 1.249
+++ server/cityturn.c 16 Jun 2004 03:26:21 -0000
@@ -376,6 +376,8 @@
**************************************************************************/
bool city_reduce_size(struct city *pcity, int pop_loss)
{
+ int i;
+
if (pop_loss == 0) {
return TRUE;
}
@@ -394,16 +396,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) {
@@ -437,6 +438,7 @@
bool has_granary = city_got_effect(pcity, B_GRANARY);
bool rapture_grow = city_rapture_grow(pcity); /* check before size increase!
*/
int new_food;
+ int best_sci = best_science_specialist(), best_tax = best_tax_specialist();
if (!city_got_building(pcity, B_AQUEDUCT)
&& pcity->size>=game.aqueduct_size) {/* need aqueduct */
@@ -497,18 +499,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)
+ && pcity->size >= game.rgame.specialists[best_sci].min_size) {
+ pcity->specialists[best_sci]++;
+ } else if ((pcity->food_surplus >= 2 || !have_square)
+ && is_city_option_set(pcity, CITYO_NEW_TAXMAN)
+ && pcity->size >= game.rgame.specialists[best_tax].min_size) {
+ 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.50
diff -u -r1.50 report.c
--- server/report.c 11 May 2004 17:59:34 -0000 1.50
+++ server/report.c 16 Jun 2004 03:26:22 -0000
@@ -496,19 +496,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)
@@ -902,9 +898,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.175
diff -u -r1.175 ruleset.c
--- server/ruleset.c 9 Jun 2004 04:39:13 -0000 1.175
+++ server/ruleset.c 16 Jun 2004 03:26:22 -0000
@@ -2496,11 +2496,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];
@@ -2508,10 +2503,20 @@
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;
game.rgame.changable_tax =
secfile_lookup_bool_default(file, TRUE, "specialist.changable_tax");
@@ -2526,11 +2531,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 */
@@ -3100,9 +3100,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;
for (i = 0; i < SP_COUNT; i++) {
+ sz_strlcpy(misc_p.specialist_name[i], game.rgame.specialists[i].name);
misc_p.specialist_min_size[i] = game.rgame.specialists[i].min_size;
- misc_p.specialist_bonus[i] = game.rgame.specialists[i].bonus;
+ misc_p.specialist_bonus_sci[i] = game.rgame.specialists[i].bonus_sci;
+ misc_p.specialist_bonus_tax[i] = game.rgame.specialists[i].bonus_tax;
+ misc_p.specialist_bonus_lux[i] = game.rgame.specialists[i].bonus_lux;
}
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.42
diff -u -r1.42 sanitycheck.c
--- server/sanitycheck.c 28 May 2004 06:47:10 -0000 1.42
+++ server/sanitycheck.c 16 Jun 2004 03:26:22 -0000
@@ -227,9 +227,12 @@
}
} city_map_iterate_end;
if (workers + city_specialists(pcity) != pcity->size + 1) {
+ die("%s is illegal", pcity->name);
+#if 0
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);
+#endif
}
}
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.159
diff -u -r1.159 savegame.c
--- server/savegame.c 12 Jun 2004 17:42:28 -0000 1.159
+++ server/savegame.c 16 Jun 2004 03:26:23 -0000
@@ -1058,7 +1058,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);
@@ -1964,7 +1964,7 @@
int map_x, map_y;
bool is_real;
- 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.5
diff -u -r1.5 score.c
--- server/score.c 27 May 2004 22:14:19 -0000 1.5
+++ server/score.c 16 Jun 2004 03:26:23 -0000
@@ -376,16 +376,16 @@
int civ_score(struct player *pplayer)
{
struct city *pcity;
- int landarea, settledarea;
+ int landarea, settledarea, sp;
static struct claim_map cmap = { NULL, NULL, NULL,NULL };
pplayer->score.happy = 0;
pplayer->score.content = 0;
pplayer->score.unhappy = 0;
pplayer->score.angry = 0;
- pplayer->score.taxmen = 0;
- pplayer->score.scientists = 0;
- pplayer->score.elvis = 0;
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ pplayer->score.specialists[sp] = 0;
+ }
pplayer->score.wonders = 0;
pplayer->score.techs = 0;
pplayer->score.techout = 0;
@@ -408,13 +408,15 @@
}
city_list_iterate(pplayer->cities, pcity) {
+ int sp;
+
pplayer->score.happy += pcity->ppl_happy[4];
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];
+ for (sp = 0; sp < SP_COUNT; sp++) {
+ pplayer->score.specialists[sp] += pcity->specialists[sp];
+ }
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.299
diff -u -r1.299 unithand.c
--- server/unithand.c 27 May 2004 22:14:19 -0000 1.299
+++ server/unithand.c 16 Jun 2004 03:26:23 -0000
@@ -479,7 +479,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);
|
|