[Freeciv-Dev] (PR#4331) Bug in cm.c
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients: ; |
Subject: |
[Freeciv-Dev] (PR#4331) Bug in cm.c |
From: |
"Per I. Mathisen" <per@xxxxxxxxxxx> |
Date: |
Fri, 30 May 2003 14:57:24 -0700 |
Reply-to: |
rt@xxxxxxxxxxxxxx |
I am trying to add support for CM in server now, and I'm getting
buggered by a hard to find bug in cm.c. Raimar, please help out.
Sometimes, when creating a city, cm_query_result() returns a valid result
that makes use of a tile that is neither worked nor empty (ie
unavailable). This should never happen, but it does.
I added the attached patch to the code to prove it. Run the attached
autogame for quite a while and it should show up:
civserver: cm.c:1461: cm_query_result: Forutsetningen (assertion)
«pcity->city_map[x][y] == C_TILE_EMPTY || pcity->city_map[x][y] ==
C_TILE_WORKER» feilet.
#0 0xffffe002 in ?? ()
#1 0x42028b93 in abort () from /lib/tls/libc.so.6
#2 0x42020f95 in __assert_fail () from /lib/tls/libc.so.6
#3 0x080ca3c2 in cm_query_result (pcity=0x909c1c8, parameter=0xbffff300,
result=0xbffff2a0) at cm.c:1465
#4 0x080646c5 in auto_arrange_workers (pcity=0x909c1c8) at cityturn.c:200
#5 0x080621a0 in create_city (pplayer=0x8201e2c, x=72, y=1,
name=0x909c4a8 "\234?\t\t\234?\t\t") at citytools.c:1000
#6 0x08055cc6 in city_build (pplayer=0x8201e2c, punit=0x90354b8,
name=0xbffff430 "Garwa") at unithand.c:571
#7 0x08055d44 in handle_unit_build_city (pplayer=0x8201e2c,
req=0xbffff420)
at unithand.c:591
#8 0x0808de71 in ai_do_build_city (pplayer=0x8201e2c, punit=0x0)
at settlers.c:71
#9 0x080910c1 in auto_settler_findwork (pplayer=0x8201e2c,
punit=0x90354b8)
at settlers.c:1329
#10 0x0809149c in auto_settlers_player (pplayer=0x8201e2c) at
settlers.c:1403
- Per
create a
create b
hard
set savet 0
set barbarians 0
set hut 0
set endy 2000
set timeout -1
set seed 2344999
set randseed 236114
start
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.140
diff -u -r1.140 aicity.c
--- ai/aicity.c 2003/05/30 18:50:59 1.140
+++ ai/aicity.c 2003/05/30 21:55:50
@@ -55,6 +55,7 @@
#include "aicity.h"
+static void resolve_city_emergency(struct player *pplayer, struct city *pcity);
static void ai_manage_city(struct player *pplayer, struct city *pcity);
/**************************************************************************
@@ -509,6 +510,12 @@
pplayer->ai.maxbuycost = 0;
city_list_iterate(pplayer->cities, pcity)
+sanity_check_city(pcity);
+ if (CITY_EMERGENCY(pcity)) {
+ /* Fix critical shortages or unhappiness */
+ resolve_city_emergency(pplayer, pcity);
+ }
+ sanity_check_city(pcity);
ai_manage_city(pplayer, pcity);
city_list_iterate_end;
@@ -525,10 +532,12 @@
/* seacost may have been munged if we found a boat, but if we found a boat
we don't rely on the seamap being current since we will recalculate. -- Syela
*/
+sanity_check_city(pcity);
city_list_iterate_end;
city_list_iterate(pplayer->cities, pcity)
ai_city_choose_build(pplayer, pcity);
+sanity_check_city(pcity);
city_list_iterate_end;
ai_spend_gold(pplayer);
@@ -696,185 +705,8 @@
static void ai_manage_city(struct player *pplayer, struct city *pcity)
{
auto_arrange_workers(pcity);
- if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE))
- ai_scientists_taxmen(pcity);
ai_sell_obsolete_buildings(pcity);
sync_cities();
-/* ai_city_choose_build(pplayer, pcity); -- moved by Syela */
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-static int ai_find_elvis_pos(struct city *pcity, int *xp, int *yp)
-{
- struct government *g = get_gov_pcity(pcity);
- int foodneed, prodneed, luxneed, pwr, e, worst_value = 0;
-
- foodneed=(pcity->size *2) + settler_eats(pcity);
- foodneed -= pcity->food_prod; /* much more robust now -- Syela */
- prodneed = 0;
- prodneed -= pcity->shield_prod;
- luxneed = 2 * (2 * pcity->ppl_angry[4] + pcity->ppl_unhappy[4] -
- pcity->ppl_happy[4]);
- pwr = 2 * city_tax_bonus(pcity) / 100;
- e = (luxneed + pwr - 1) / pwr;
- if (e > 1) {
- foodneed += (e - 1) * 2;
- prodneed += (e - 1);
- } /* not as good as elvising all at once, but should be adequate */
-
- unit_list_iterate(pcity->units_supported, punit)
- prodneed += utype_shield_cost(unit_type(punit), g);
- unit_list_iterate_end;
-
- prodneed -= citygov_free_shield(pcity, g);
-
- *xp = 0;
- *yp = 0;
- city_map_iterate(x, y) {
- if (is_city_center(x, y))
- continue;
- if (get_worker_city(pcity, x, y) == C_TILE_WORKER) {
- int value = city_tile_value(pcity, x, y,
- foodneed + city_get_food_tile(x, y, pcity),
- prodneed + city_get_shields_tile(x, y,
- pcity));
-
- if ((*xp == 0 && *yp == 0) || value < worst_value) {
- *xp = x;
- *yp = y;
- worst_value = value;
- }
- }
- } city_map_iterate_end;
- if (*xp == 0 && *yp == 0) return 0;
- foodneed += city_get_food_tile(*xp, *yp, pcity);
- prodneed += city_get_shields_tile(*xp, *yp, pcity);
- if (e > 1) {
- foodneed -= (e - 1) * 2; /* forgetting these two lines */
- prodneed -= (e - 1); /* led to remarkable idiocy -- Syela */
- }
- if (foodneed > pcity->food_stock) {
- freelog(LOG_DEBUG,
- "No elvis_pos in %s - would create famine.", pcity->name);
- return 0; /* Bad time to Elvis */
- }
- if (prodneed > 0) {
- freelog(LOG_DEBUG,
- "No elvis_pos in %s - would fail-to-upkeep.", pcity->name);
- return 0; /* Bad time to Elvis */
- }
- return(city_tile_value(pcity, *xp, *yp, foodneed, prodneed));
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-int ai_make_elvis(struct city *pcity)
-{
- int xp, yp, val;
- if ((val = ai_find_elvis_pos(pcity, &xp, &yp)) != 0) {
- server_remove_worker_city(pcity, xp, yp);
- pcity->ppl_elvis++;
- city_refresh(pcity); /* this lets us call ai_make_elvis in luxury routine
*/
- return val; /* much more useful! */
- } else
- return 0;
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-static void make_elvises(struct city *pcity)
-{
- int xp, yp, elviscost;
- pcity->ppl_elvis += (pcity->ppl_taxman + pcity->ppl_scientist);
- pcity->ppl_taxman = 0;
- pcity->ppl_scientist = 0;
- city_refresh(pcity);
-
- while (TRUE) {
- if ((elviscost = ai_find_elvis_pos(pcity, &xp, &yp)) != 0) {
- int food = city_get_food_tile(xp, yp, pcity);
-
- if (food > pcity->food_surplus)
- break;
- if (food == pcity->food_surplus && city_happy(pcity))
- break; /* scientists don't party */
- if (elviscost >= 24) /* doesn't matter if we wtbb or not! */
- break; /* no benefit here! */
- server_remove_worker_city(pcity, xp, yp);
- pcity->ppl_elvis++;
- city_refresh(pcity);
- } else
- break;
- }
-
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-static void make_taxmen(struct city *pcity)
-{
- while (!city_unhappy(pcity) && pcity->ppl_elvis > 0) {
- pcity->ppl_taxman++;
- pcity->ppl_elvis--;
- city_refresh(pcity);
- }
- if (city_unhappy(pcity)) {
- pcity->ppl_taxman--;
- pcity->ppl_elvis++;
- city_refresh(pcity);
- }
-
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-static void make_scientists(struct city *pcity)
-{
- make_taxmen(pcity); /* reuse the code */
- pcity->ppl_scientist = pcity->ppl_taxman;
- pcity->ppl_taxman = 0;
-}
-
-/**************************************************************************
- we prefer science, but if both is 0 we prefer $
- (out of research goal situation)
-**************************************************************************/
-void ai_scientists_taxmen(struct city *pcity)
-{
- int science_bonus, tax_bonus;
- make_elvises(pcity);
- if (pcity->ppl_elvis == 0 || city_unhappy(pcity))
- return;
- tax_bonus = city_tax_bonus(pcity);
- science_bonus = city_science_bonus(pcity);
-
- if (tax_bonus > science_bonus || ai_wants_no_science(city_owner(pcity))) {
- make_taxmen(pcity);
- } else {
- make_scientists(pcity);
- }
-
- sync_cities();
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-bool ai_fix_unhappy(struct city *pcity)
-{
- if (!city_unhappy(pcity))
- return TRUE;
- while (city_unhappy(pcity)) {
- if(ai_make_elvis(pcity) == 0) break;
-/* city_refresh(pcity); moved into ai_make_elvis for utility --
Syela */
- }
- return (!city_unhappy(pcity));
}
/**************************************************************************
@@ -896,9 +728,9 @@
Syela is wrong. It happens quite too often, mostly due to unhappiness.
Also, most of the time we are unable to resolve the situation.
**************************************************************************/
-void emergency_reallocate_workers(struct player *pplayer, struct city *pcity)
+static void resolve_city_emergency(struct player *pplayer, struct city *pcity)
#define LOG_EMERGENCY LOG_DEBUG
-{
+{
struct city_list minilist;
char report[500];
@@ -916,8 +748,8 @@
if (acity && acity != pcity && acity->owner == pcity->owner) {
if (same_pos(acity->x, acity->y, x, y)) {
- /* can't stop working city center */
- continue;
+ /* can't stop working city center */
+ continue;
}
freelog(LOG_DEBUG, "%s taking over %s's square in (%d, %d)",
pcity->name, acity->name, x, y);
@@ -931,14 +763,6 @@
}
} map_city_radius_iterate_end;
auto_arrange_workers(pcity);
- if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE)) {
- ai_scientists_taxmen(pcity);
- }
- if (pcity->shield_surplus >= 0 && !city_unhappy(pcity)
- && pcity->food_stock + pcity->food_surplus >= 0) {
- freelog(LOG_EMERGENCY, "%s resolved without disbanding", report);
- goto cleanup;
- }
unit_list_iterate(pcity->units_supported, punit) {
if (city_unhappy(pcity)
@@ -951,25 +775,19 @@
/* in rare cases the _safe might be needed? --dwp */
handle_unit_disband_safe(pplayer, &pack, &myiter);
city_refresh(pcity);
- (void) ai_fix_unhappy(pcity);
}
} unit_list_iterate_end;
- if (pcity->shield_surplus >= 0 && !city_unhappy(pcity)
- && pcity->food_stock + pcity->food_surplus >= 0) {
- freelog(LOG_EMERGENCY, "%s resolved by disbanding unit(s)", report);
- } else {
+ if (CITY_EMERGENCY(pcity)) {
freelog(LOG_EMERGENCY, "%s remains unresolved", report);
+ } else {
+ freelog(LOG_EMERGENCY, "%s resolved by disbanding unit(s)", report);
}
- cleanup:
city_list_iterate(minilist, acity) {
/* otherwise food total and stuff was wrong. -- Syela */
city_refresh(acity);
auto_arrange_workers(pcity);
- if (ai_fix_unhappy(acity) && ai_fuzzy(pplayer, TRUE)) {
- ai_scientists_taxmen(acity);
- }
} city_list_iterate_end;
sync_cities();
Index: ai/aicity.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.h,v
retrieving revision 1.18
diff -u -r1.18 aicity.h
--- ai/aicity.h 2002/12/21 11:44:00 1.18
+++ ai/aicity.h 2003/05/30 21:55:50
@@ -15,6 +15,10 @@
#include "unit.h" /* enum unit_move_type */
+#define CITY_EMERGENCY(pcity) \
+ (pcity->shield_surplus < 0 || city_unhappy(pcity) \
+ || pcity->food_stock + pcity->food_surplus < 0) \
+
struct player;
struct city;
struct ai_choice;
@@ -28,10 +32,6 @@
Unit_Type_id ai_choose_defender_by_type(struct city *pcity,
enum unit_move_type which);
Unit_Type_id ai_choose_defender(struct city *pcity);
-int ai_make_elvis(struct city *pcity);
-void ai_scientists_taxmen(struct city *pcity);
-bool ai_fix_unhappy(struct city *pcity);
-void emergency_reallocate_workers(struct player *pplayer, struct city *pcity);
enum ai_city_task { AICITY_NONE, AICITY_TECH, AICITY_TAX, AICITY_PROD};
/* These are not used (well, except AICITY_NONE) --dwp */
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.16
diff -u -r1.16 aidata.c
--- ai/aidata.c 2003/05/29 13:44:38 1.16
+++ ai/aidata.c 2003/05/30 21:55:50
@@ -253,8 +253,13 @@
* are all WAGs. */
ai->food_priority = FOOD_WEIGHTING;
ai->shield_priority = SHIELD_WEIGHTING;
- ai->luxury_priority = 1;
- ai->science_priority = TRADE_WEIGHTING;
+ if (ai_wants_no_science(pplayer)) {
+ ai->luxury_priority = 1;
+ ai->science_priority = TRADE_WEIGHTING;
+ } else {
+ ai->luxury_priority = TRADE_WEIGHTING;
+ ai->science_priority = 1;
+ }
ai->gold_priority = TRADE_WEIGHTING;
ai->happy_priority = 1;
ai->unhappy_priority = TRADE_WEIGHTING; /* danger */
Index: ai/aihand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v
retrieving revision 1.82
diff -u -r1.82 aihand.c
--- ai/aihand.c 2003/05/15 16:02:00 1.82
+++ ai/aihand.c 2003/05/30 21:55:50
@@ -77,232 +77,53 @@
}
/**************************************************************************
-.. Set tax/science/luxury rates. Tax Rates > 40 indicates a crisis.
- total rewrite by Syela
+ Set tax/science/luxury rates.
+
+ TODO: Audit the use of pplayer->ai.maxbuycost in the code elsewhere,
+ then add support for it here.
+
+ TODO: Add support for rapture, needs to be coordinated for entire
+ empire.
**************************************************************************/
static void ai_manage_taxes(struct player *pplayer)
{
- struct government *g = get_gov_pplayer(pplayer);
- int gnow = pplayer->economic.gold;
- int trade = 0, m, n, i, expense = 0, tot;
- int waste[40]; /* waste with N elvises */
- int elvises[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int hhjj[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int cities = 0;
- struct packet_unit_request pack;
- struct city *incity; /* stay a while, until the night is over */
- struct unit *defender;
- int maxrate = 10;
-
- if (ai_handicap(pplayer, H_RATES))
- maxrate = get_government_max_rate(pplayer->government) / 10;
-
- pplayer->economic.science += pplayer->economic.luxury;
-/* without the above line, auto_arrange does strange things we must avoid --
Syela */
- pplayer->economic.luxury = 0;
+ int trade = 0, expense = 0;
+ int maxrate = get_government_max_rate(pplayer->government);
+
city_list_iterate(pplayer->cities, pcity)
- cities++;
- pcity->ppl_elvis = 0; pcity->ppl_taxman = 0; pcity->ppl_scientist = 0;
- add_adjust_workers(pcity); /* less wasteful than auto_arrange, required */
- city_refresh(pcity);
trade += pcity->trade_prod * city_tax_bonus(pcity) / 100;
- freelog(LOG_DEBUG, "%s has %d trade.", pcity->name, pcity->trade_prod);
built_impr_iterate(pcity, id) {
expense += improvement_upkeep(pcity, id);
} built_impr_iterate_end;
-
city_list_iterate_end;
-
pplayer->ai.est_upkeep = expense;
- if (trade == 0) { /* can't return right away - thanks for the evidence, Muzz
*/
- city_list_iterate(pplayer->cities, pcity)
- if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE))
- ai_scientists_taxmen(pcity);
- city_list_iterate_end;
- return; /* damn division by zero! */
- }
-
- pplayer->economic.luxury = 0;
-
- city_list_iterate(pplayer->cities, pcity) {
-
- /* this code must be ABOVE the elvises[] if SIMPLISTIC is off */
- freelog(LOG_DEBUG, "Does %s want to be bigger? %d",
- pcity->name, wants_to_be_bigger(pcity));
- if (government_has_flag(g, G_RAPTURE_CITY_GROWTH)
- && pcity->size >= g->rapture_size && pcity->food_surplus > 0
- && pcity->ppl_unhappy[4] == 0 && pcity->ppl_angry[4] == 0
- && wants_to_be_bigger(pcity) && ai_fuzzy(pplayer, TRUE)) {
- freelog(LOG_DEBUG, "%d happy people in %s",
- pcity->ppl_happy[4], pcity->name);
- n = ((pcity->size/2) - pcity->ppl_happy[4]) * 20;
- if (n > pcity->ppl_content[1] * 20) n += (n - pcity->ppl_content[1] *
20);
- m = ((((city_got_effect(pcity, B_GRANARY) ? 3 : 2) *
- city_granary_size(pcity->size))/2) -
- pcity->food_stock) * food_weighting(pcity->size);
- freelog(LOG_DEBUG, "Checking HHJJ for %s, m = %d", pcity->name, m);
- tot = 0;
- for (i = 0; i <= 10; i++) {
- if (pcity->trade_prod * i * city_tax_bonus(pcity) >= n * 100) {
- if (tot == 0) freelog(LOG_DEBUG, "%s celebrates at %d.",
- pcity->name, i * 10);
- hhjj[i] += (pcity->was_happy ? m : m/2);
- tot++;
- }
- }
- } /* hhjj[i] is (we think) the desirability of partying with lux = 10 * i
*/
-/* end elevated code block */
-
- /* need this much lux */
- n = (2 * pcity->ppl_angry[4] + pcity->ppl_unhappy[4] -
- pcity->ppl_happy[4]) * 20;
-
-/* this could be an unholy CPU glutton; it's only really useful when we need
- lots of luxury, like with pcity->size = 12 and only a temple */
-
- memset(waste, 0, sizeof(waste));
- tot = pcity->food_prod * food_weighting(pcity->size) +
- pcity->trade_prod * pcity->ai.trade_want +
- pcity->shield_prod * SHIELD_WEIGHTING;
-
- for (i = 1; i <= pcity->size; i++) {
- m = ai_make_elvis(pcity);
- if (m != 0) {
- waste[i] = waste[i-1] + m;
- } else {
- while (i <= pcity->size) {
- waste[i++] = tot;
- }
- break;
- }
- }
- for (i = 0; i <= 10; i++) {
- m = ((n * 100 - pcity->trade_prod * city_tax_bonus(pcity) * i + 1999) /
2000);
- if (m >= 0) elvises[i] += waste[m];
- }
- }
- city_list_iterate_end;
-
- for (i = 0; i <= 10; i++) elvises[i] += (trade * i) / 10 * TRADE_WEIGHTING;
- /* elvises[i] is the production + income lost to elvises with lux = i * 10 */
- n = 0; /* default to 0 lux */
- for (i = 1; i <= maxrate; i++) if (elvises[i] < elvises[n]) n = i;
- /* two thousand zero zero party over it's out of time */
- for (i = 0; i <= 10; i++) {
- hhjj[i] -= (trade * i) / 10 * TRADE_WEIGHTING; /* hhjj is now our bonus */
- freelog(LOG_DEBUG, "hhjj[%d] = %d for %s.", i, hhjj[i], pplayer->name);
- }
-
- m = n; /* storing the lux we really need */
- pplayer->economic.luxury = n * 10; /* temporary */
-
-/* Less-intelligent previous versions of the follow equation purged. -- Syela
*/
- n = ((expense - gnow + cities + pplayer->ai.maxbuycost) * 10 + trade - 1) /
trade;
- if (n < 0) n = 0;
- while (n > maxrate) n--; /* Better to cheat on lux than on tax -- Syela */
- if (m > 10 - n) m = 10 - n;
-
- freelog(LOG_DEBUG, "%s has %d trade and %d expense."
- " Min lux = %d, tax = %d", pplayer->name, trade, expense, m, n);
-
-/* Peter Schaefer points out (among other things) that in pathological cases
-(like expense == 468) the AI will try to celebrate with m = 10 and then abort
*/
-
- /* want to max the hhjj */
- for (i = m; i <= maxrate && i <= 10 - n; i++)
- if (hhjj[i] > hhjj[m] && (trade * (10 - i) >= expense * 10)) m = i;
-/* if the lux rate necessary to celebrate cannot be maintained, don't bother */
- pplayer->economic.luxury = 10 * m;
-
if (ai_wants_no_science(pplayer)) {
- pplayer->economic.tax = 100 - pplayer->economic.luxury;
- while (pplayer->economic.tax > maxrate * 10) {
- pplayer->economic.tax -= 10;
- pplayer->economic.luxury += 10;
+ pplayer->economic.tax = maxrate;
+ pplayer->economic.luxury = MIN(100 - pplayer->economic.tax, maxrate);
+ pplayer->economic.science = 100 - pplayer->economic.tax
+ - pplayer->economic.luxury;
+ } else {
+ if (pplayer->economic.gold >= ai_gold_reserve(pplayer)) {
+ pplayer->economic.science = maxrate; /* Max research */
+ } else {
+ pplayer->economic.science = maxrate / 2; /* Refill tresury */
}
- } else { /* have to balance things logically */
-/* if we need 50 gold and we have trade = 100, need 50 % tax (n = 5) */
-/* n = ((ai_gold_reserve(pplayer) - gnow - expense) ... I hate typos. --
Syela */
- n = ((ai_gold_reserve(pplayer) - gnow + expense + cities) * 20 + (trade*2)
- 1) / (trade*2);
-/* same bug here as above, caused us not to afford city walls we needed. --
Syela */
- if (n < 0) n = 0; /* shouldn't allow 0 tax? */
- while (n > 10 - (pplayer->economic.luxury / 10) || n > maxrate) n--;
- pplayer->economic.tax = 10 * n;
- }
-
-/* once we have tech_want established, can compare it to cash want here --
Syela */
- pplayer->economic.science = 100 - pplayer->economic.tax -
pplayer->economic.luxury;
- while (pplayer->economic.science > maxrate * 10) {
- pplayer->economic.tax += 10;
- pplayer->economic.science -= 10;
+ pplayer->economic.tax = MIN(100 - pplayer->economic.science, maxrate);
+ pplayer->economic.luxury = 100 - pplayer->economic.tax
+ - pplayer->economic.science;
+ /* Now adjust to get enough money to pay for expenses */
+ while (trade / 100 * pplayer->economic.tax < expense
+ && pplayer->economic.science > 10
+ && pplayer->economic.tax < maxrate) {
+ pplayer->economic.tax += 10;
+ pplayer->economic.science -= 10;
+ }
}
-
- city_list_iterate(pplayer->cities, pcity)
- pcity->ppl_elvis = 0;
- city_refresh(pcity);
- add_adjust_workers(pcity);
- city_refresh(pcity);
- if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE))
- ai_scientists_taxmen(pcity);
- if (pcity->shield_surplus < 0 || city_unhappy(pcity) ||
- pcity->food_stock + pcity->food_surplus < 0)
- emergency_reallocate_workers(pplayer, pcity);
- if (pcity->shield_surplus < 0) {
- defender = NULL;
- unit_list_iterate(pcity->units_supported, punit)
- incity = map_get_city(punit->x, punit->y);
- if (incity && pcity->shield_surplus < 0) {
- /* Note that disbanding here is automatically safe (we don't
- * need to use handle_unit_disband_safe()), because the unit is
- * in a city, so there are no passengers to get disbanded. --dwp
- */
- if (incity == pcity) {
- if (defender) {
- if (unit_def_rating_basic(punit) <
- unit_def_rating_basic(defender)) {
- freelog(LOG_VERBOSE, "Disbanding %s in %s",
- unit_type(punit)->name, pcity->name);
- pack.unit_id = punit->id;
- handle_unit_disband(pplayer, &pack);
- city_refresh(pcity);
- } else {
- freelog(LOG_VERBOSE, "Disbanding %s in %s",
- unit_type(defender)->name, pcity->name);
- pack.unit_id = defender->id;
- handle_unit_disband(pplayer, &pack);
- city_refresh(pcity);
- defender = punit;
- }
- } else defender = punit;
- } else if (incity->shield_surplus > 0) {
- pack.unit_id = punit->id;
- pack.city_id = incity->id;
- handle_unit_change_homecity(pplayer, &pack);
- city_refresh(pcity);
- freelog(LOG_VERBOSE, "Reassigning %s from %s to %s",
- unit_type(punit)->name, pcity->name, incity->name);
- }
- } /* end if */
- unit_list_iterate_end;
- if (pcity->shield_surplus < 0) {
- unit_list_iterate(pcity->units_supported, punit)
- if (punit != defender && pcity->shield_surplus < 0) {
- /* the defender MUST NOT be disbanded! -- Syela */
- freelog(LOG_VERBOSE, "Disbanding %s's %s",
- pcity->name, unit_type(punit)->name);
- pack.unit_id = punit->id;
- handle_unit_disband_safe(pplayer, &pack, &myiter);
- city_refresh(pcity);
- }
- unit_list_iterate_end;
- }
- } /* end if we can't meet payroll */
- /* FIXME: this shouldn't be here, but in the server... */
- send_city_info(city_owner(pcity), pcity);
- city_list_iterate_end;
-
- sync_cities();
+ freelog(LOG_NORMAL, "%s sc%d lux%d tax%d exp%d inc%d",
+ pplayer->name, pplayer->economic.science,
+ pplayer->economic.luxury, pplayer->economic.tax,
+ expense, trade / 100 * pplayer->economic.tax);
}
/**************************************************************************
@@ -348,9 +169,6 @@
city_list_iterate(pplayer->cities, acity) {
generic_city_refresh(acity, TRUE, NULL);
auto_arrange_workers(acity);
- if (ai_fix_unhappy(acity)) {
- ai_scientists_taxmen(acity);
- }
} city_list_iterate_end;
city_list_iterate(pplayer->cities, pcity) {
val += ai_eval_calc_city(pcity, ai);
@@ -391,9 +209,6 @@
city_list_iterate(pplayer->cities, acity) {
generic_city_refresh(acity, FALSE, NULL);
auto_arrange_workers(acity);
- if (ai_fix_unhappy(acity)) {
- ai_scientists_taxmen(acity);
- }
} city_list_iterate_end;
ai->govt_reeval = CLIP(5, city_list_size(&pplayer->cities), 20);
}
Index: common/aicore/cm.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.c,v
retrieving revision 1.8
diff -u -r1.8 cm.c
--- common/aicore/cm.c 2003/05/13 07:04:28 1.8
+++ common/aicore/cm.c 2003/05/30 21:55:53
@@ -1457,6 +1457,15 @@
cm_clear_cache(pcity);
}
report_stats();
+
+ if (result->found_a_valid) {
+ city_map_iterate(x, y) {
+ if (result->worker_positions_used[x][y]) {
+ assert(pcity->city_map[x][y] == C_TILE_EMPTY
+ || pcity->city_map[x][y] == C_TILE_WORKER);
+ }
+ } city_map_iterate_end;
+ }
}
/****************************************************************************
Index: server/cityhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityhand.c,v
retrieving revision 1.122
diff -u -r1.122 cityhand.c
--- server/cityhand.c 2003/05/05 12:11:13 1.122
+++ server/cityhand.c 2003/05/30 21:55:53
@@ -112,6 +112,7 @@
break;
}
+ sanity_check_city(pcity);
city_refresh(pcity);
send_city_info(pplayer, pcity);
}
@@ -141,6 +142,7 @@
notify_player_ex(pplayer, pcity->x, pcity->y, E_NOEVENT,
_("Game: You don't have a worker here."));
}
+ sanity_check_city(pcity);
}
/**************************************************************************
@@ -180,6 +182,7 @@
else
pcity->ppl_taxman--;
+ sanity_check_city(pcity);
city_refresh(pcity);
sync_cities();
}
@@ -374,6 +377,7 @@
change_build_target(pplayer, pcity, preq->build_id,
preq->is_build_id_unit_id, E_NOEVENT);
+ sanity_check_city(pcity);
city_refresh(pcity);
send_city_info(pplayer, pcity);
}
Index: server/citytools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/citytools.c,v
retrieving revision 1.218
diff -u -r1.218 citytools.c
--- server/citytools.c 2003/05/06 05:06:07 1.218
+++ server/citytools.c 2003/05/30 21:55:53
@@ -942,6 +942,7 @@
build_free_palace(pgiver, pcity->name);
}
+ sanity_check_city(pcity);
sync_cities();
}
@@ -1034,6 +1035,8 @@
if (!can_unit_continue_current_activity(punit))
handle_unit_activity_request(punit, ACTIVITY_IDLE);
} unit_list_iterate_end;
+
+ sanity_check_city(pcity);
}
/**************************************************************************
@@ -1945,6 +1948,7 @@
case C_TILE_WORKER:
if (!is_available) {
server_set_tile_city(pcity, city_x, city_y, C_TILE_UNAVAILABLE);
+ pcity->ppl_elvis++; /* keep city sanity */
add_adjust_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.213
diff -u -r1.213 cityturn.c
--- server/cityturn.c 2003/05/28 21:26:18 1.213
+++ server/cityturn.c 2003/05/30 21:55:53
@@ -43,8 +43,11 @@
#include "srv_main.h"
#include "unittools.h"
+#include "cm.h"
+
#include "advdomestic.h"
#include "aicity.h"
+#include "ailog.h"
#include "aitools.h" /* for ai_advisor_choose_building/ai_choice */
#include "cityturn.h"
@@ -67,17 +70,12 @@
static void obsolete_building_test(struct city *pcity, int b1, int b2);
static void pay_for_buildings(struct player *pplayer, struct city *pcity);
-static void sanity_check_city(struct city *pcity);
-
static bool disband_city(struct city *pcity);
static void define_orig_production_values(struct city *pcity);
static void update_city_activity(struct player *pplayer, struct city *pcity);
static void nullify_caravan_and_disband_plus(struct city *pcity);
-static void worker_loop(struct city *pcity, int *foodneed,
- int *prodneed, int *workers);
-
static void advisor_choose_build(struct player *pplayer, struct city *pcity);
/**************************************************************************
@@ -143,173 +141,98 @@
}
/**************************************************************************
-You need to call sync_cities for the affected cities to be synced with the
-client.
+ ... TODO: remove
**************************************************************************/
-static void worker_loop(struct city *pcity, int *foodneed,
- int *prodneed, int *workers)
+void add_adjust_workers(struct city *pcity)
{
- int bx, by, best, cur;
- int conflict[5][5];
- int e, pwr, luxneed = 0; /* I should have thought of this earlier, it is so
simple */
-
- city_refresh(pcity);
- luxneed = 2 * (2 * pcity->ppl_angry[4] + pcity->ppl_unhappy[4] -
- pcity->ppl_happy[4]);
- pwr = (2 * city_tax_bonus(pcity)) / 100;
- luxneed += pwr * pcity->ppl_elvis;
- if (luxneed < 0) luxneed = 0;
-
- e = (luxneed + pwr - 1) / pwr;
- if (e > (*workers - 1)) e = *workers - 1; /* stops the repeated emergencies.
-- Syela */
-
-/* If I were real clever, I would optimize trade by luxneed and tax_bonus --
Syela */
-
- *foodneed -= 2 * (*workers - 1 - e);
- *prodneed -= (*workers - 1 - e);
-
- freelog(LOG_DEBUG, "%s, %d workers, %d luxneed, %d e",
- pcity->name, *workers, luxneed, e);
- freelog(LOG_DEBUG, "%s, a4 %d u4 %d h4 %d pwr %d elv %d",
- pcity->name, pcity->ppl_angry[4], pcity->ppl_unhappy[4],
- pcity->ppl_happy[4], pwr, pcity->ppl_elvis);
-
- if (city_happy(pcity) && wants_to_be_bigger(pcity) && pcity->size > 4)
- *foodneed += 1;
-
- freelog(LOG_DEBUG, "%s, foodneed %d prodneed %d",
- pcity->name, *foodneed, *prodneed);
-
- /* better than nothing, not as good as a global worker allocation -- Syela */
- memset(conflict, 0, sizeof(conflict));
- city_map_checked_iterate(pcity->x, pcity->y, cx, cy, mx, my) {
- conflict[cx][cy] = -1 - minimap[mx][my];
- } city_map_checked_iterate_end;
-
- do {
- /* try to work near the city */
- bx = 0;
- by = 0;
- best = 0;
-
- city_map_iterate_outwards(x, y) {
- if (can_place_worker_here(pcity, x, y)
- && city_can_work_tile(pcity, x, y)) {
- cur = city_tile_value(pcity,x,y,*foodneed,*prodneed) - conflict[x][y];
- if (cur > best) {
- bx = x;
- by = y;
- best = cur;
- }
- }
- } city_map_iterate_outwards_end;
- if (bx != 0 || by != 0) {
- server_set_worker_city(pcity, bx, by);
- (*workers)--; /* amazing what this did with no parens! -- Syela */
- *foodneed -= city_get_food_tile(bx,by,pcity) - 2;
- *prodneed -= city_get_shields_tile(bx,by,pcity) - 1;
- }
- } while(*workers != 0 && (bx != 0 || by != 0));
- *foodneed += 2 * (*workers - 1 - e);
- *prodneed += (*workers - 1 - e);
- if (*prodneed > 0) {
- freelog(LOG_DEBUG, "Ignored prodneed? in %s (%d)",
- pcity->name, *prodneed);
- }
+ auto_arrange_workers(pcity);
}
/**************************************************************************
-You need to call sync_cities for the affected cities to be synced with the
-client.
+ Hard check
+
+ TODO: make conditional on DEBUG define
**************************************************************************/
-void add_adjust_workers(struct city *pcity)
+void sanity_check_city(struct city *pcity)
{
- int workers=pcity->size;
- int iswork=0;
- int toplace;
- int foodneed;
- int prodneed = 0;
+ int worker = 0;
city_map_iterate(x, y) {
- if (get_worker_city(pcity, x, y)==C_TILE_WORKER)
- iswork++;
+ if (get_worker_city(pcity, x, y) == C_TILE_WORKER) {
+ worker++;
+ }
} city_map_iterate_end;
- iswork--; /* City center */
-
- if (iswork+city_specialists(pcity)>workers) {
- freelog(LOG_ERROR, "Encountered an inconsistency in "
- "add_adjust_workers() for city %s", pcity->name);
- auto_arrange_workers(pcity);
- sync_cities();
- return;
+ if (worker + city_specialists(pcity) != pcity->size + 1) {
+ die("%s is illegal (size%d w%d e%d t%d s%d)",
+ pcity->name, pcity->size, worker, pcity->ppl_elvis,
+ pcity->ppl_taxman, pcity->ppl_scientist);
}
-
- if (iswork + city_specialists(pcity) == workers) {
- return;
- }
-
- toplace = workers-(iswork+city_specialists(pcity));
- foodneed = -pcity->food_surplus;
- prodneed = -pcity->shield_surplus;
-
- worker_loop(pcity, &foodneed, &prodneed, &toplace);
-
- pcity->ppl_elvis+=toplace;
- return;
}
/**************************************************************************
-You need to call sync_cities for the affected cities to be synced with the
-client.
+ You need to call sync_cities for the affected cities to be synced with
+ the client.
**************************************************************************/
void auto_arrange_workers(struct city *pcity)
{
- struct government *g = get_gov_pcity(pcity);
- int workers = pcity->size;
- int taxwanted,sciwanted;
- int foodneed, prodneed;
+ struct cm_parameter cmp;
+ struct cm_result cmr;
+
+ sanity_check_city(pcity);
+
+ cmp.minimal_surplus[FOOD] = 0;
+ cmp.minimal_surplus[SHIELD] = 0;
+ cmp.minimal_surplus[TRADE] = 0;
+ cmp.minimal_surplus[GOLD] = 0; /* -5 */
+ cmp.minimal_surplus[LUXURY] = 0;
+ cmp.minimal_surplus[SCIENCE] = 0;
+ cmp.require_happy = FALSE;
+ cmp.factor_target = FT_SURPLUS;
+ cmp.factor[FOOD] = 10;
+ cmp.factor[SHIELD] = 5;
+ cmp.factor[TRADE] = 5;
+ cmp.factor[GOLD] = 1;
+ cmp.factor[LUXURY] = 1;
+ cmp.factor[SCIENCE] = 15;
+ cmp.happy_factor = 0;
+
+ cm_clear_cache(pcity);
+ cm_query_result(pcity, &cmp, &cmr);
+
+ if (!cmr.found_a_valid) {
+ CITY_LOG(LOG_NORMAL, pcity, "non-optimal management");
+ cmp.minimal_surplus[FOOD] = -20;
+ cmp.minimal_surplus[SHIELD] = -20;
+ cmp.minimal_surplus[TRADE] = -20;
+ cmp.minimal_surplus[GOLD] = -20;
+ cmp.minimal_surplus[LUXURY] = -20;
+ cmp.minimal_surplus[SCIENCE] = -20;
+ cmp.require_happy = FALSE;
+
+ cm_query_result(pcity, &cmp, &cmr);
+
+ assert(cmr.found_a_valid);
+ }
+ /* Now apply results */
city_map_iterate(x, y) {
- if (get_worker_city(pcity, x, y) == C_TILE_WORKER
- && !is_city_center(x, y))
+ if (pcity->city_map[x][y] == C_TILE_WORKER
+ && !cmr.worker_positions_used[x][y]
+ && !is_city_center(x, y)) {
server_remove_worker_city(pcity, x, y);
- } city_map_iterate_end;
-
- foodneed=(pcity->size *2 -city_get_food_tile(2,2, pcity)) +
settler_eats(pcity);
- prodneed = 0;
- prodneed -= city_get_shields_tile(2,2,pcity);
- prodneed -= citygov_free_shield(pcity, g);
-
- unit_list_iterate(pcity->units_supported, this_unit) {
- int shield_cost = utype_shield_cost(unit_type(this_unit), g);
- if (shield_cost > 0) {
- prodneed += shield_cost;
}
- }
- unit_list_iterate_end;
-
- taxwanted=pcity->ppl_taxman;
- sciwanted=pcity->ppl_scientist;
- pcity->ppl_taxman=0;
- pcity->ppl_scientist=0;
- pcity->ppl_elvis=0;
-
- worker_loop(pcity, &foodneed, &prodneed, &workers);
-
- while (workers > 0 && (taxwanted > 0 || sciwanted > 0)) {
- if (taxwanted > 0) {
- workers--;
- pcity->ppl_taxman++;
- taxwanted--;
- }
- if (sciwanted > 0 && workers > 0) {
- workers--;
- pcity->ppl_scientist++;
- sciwanted--;
+ if (pcity->city_map[x][y] != C_TILE_WORKER
+ && cmr.worker_positions_used[x][y]
+ && !is_city_center(x, y)) {
+ server_set_worker_city(pcity, x, y);
}
- }
- pcity->ppl_elvis=workers;
+ } city_map_iterate_end;
+ pcity->ppl_elvis = cmr.entertainers;
+ pcity->ppl_scientist = cmr.scientists;
+ pcity->ppl_taxman = cmr.taxmen;
+ sanity_check_city(pcity);
+
city_refresh(pcity);
}
@@ -428,6 +351,10 @@
**************************************************************************/
void city_reduce_size(struct city *pcity, int pop_loss)
{
+ if (pop_loss == 0) {
+ return;
+ }
+
if (pcity->size <= pop_loss) {
remove_city_from_minimap(pcity->x, pcity->y);
remove_city(pcity);
@@ -443,9 +370,9 @@
}
while (pop_loss > 0 && city_specialists(pcity) > 0) {
- if(pcity->ppl_taxman > 0) {
+ if (pcity->ppl_taxman > 0) {
pcity->ppl_taxman--;
- } else if(pcity->ppl_scientist > 0) {
+ } else if (pcity->ppl_scientist > 0) {
pcity->ppl_scientist--;
} else {
assert(pcity->ppl_elvis > 0);
@@ -459,9 +386,20 @@
city_refresh(pcity);
send_city_info(city_owner(pcity), pcity);
} else {
+ /* Take it out on workers */
+ city_map_iterate(x, y) {
+ if (get_worker_city(pcity, x, y) == C_TILE_WORKER
+ && !is_city_center(x, y) && pop_loss > 0) {
+ server_remove_worker_city(pcity, x, y);
+ pop_loss--;
+ }
+ } city_map_iterate_end;
+ /* Then rearrange workers */
+ assert(pop_loss == 0);
auto_arrange_workers(pcity);
sync_cities();
}
+ sanity_check_city(pcity);
}
/**************************************************************************
@@ -545,18 +483,16 @@
}
} else {
+ pcity->ppl_taxman++; /* or else city is !sane */
add_adjust_workers(pcity);
}
city_refresh(pcity);
- if (powner->ai.control) /* don't know if we need this -- Syela */
- if (ai_fix_unhappy(pcity))
- ai_scientists_taxmen(pcity);
-
notify_player_ex(powner, pcity->x, pcity->y, E_CITY_GROWTH,
_("Game: %s grows to size %d."), pcity->name, pcity->size);
+ sanity_check_city(pcity);
sync_cities();
}
@@ -1165,28 +1101,6 @@
}
/**************************************************************************
-...
-**************************************************************************/
-static void sanity_check_city(struct city *pcity)
-{
- int size=pcity->size;
- int iswork=0;
- city_map_iterate(x, y) {
- if (get_worker_city(pcity, x, y)==C_TILE_WORKER)
- iswork++;
- } city_map_iterate_end;
- iswork--;
- if (iswork+city_specialists(pcity)!=size) {
- freelog(LOG_ERROR,
- "%s is bugged: size:%d workers:%d elvis: %d tax:%d sci:%d",
- pcity->name, size, iswork, pcity->ppl_elvis,
- pcity->ppl_taxman, pcity->ppl_scientist);
- auto_arrange_workers(pcity);
- sync_cities();
- }
-}
-
-/**************************************************************************
Sets the incite_revolt_cost field in the given city.
**************************************************************************/
int city_incite_cost(struct player *pplayer, struct city *pcity)
@@ -1272,12 +1186,6 @@
struct government *g = get_gov_pcity(pcity);
city_refresh(pcity);
-
- /* the AI often has widespread disorder when the Gardens or Oracle
- become obsolete. This is a quick hack to prevent this. 980805 -- Syela
*/
- while (pplayer->ai.control && city_unhappy(pcity)) {
- if (ai_make_elvis(pcity) == 0) break;
- } /* putting this lower in the routine would basically be cheating. -- Syela
*/
/* reporting of celebrations rewritten, copying the treatment of disorder
below,
with the added rapture rounds count. 991219 -- Jing */
Index: server/cityturn.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityturn.h,v
retrieving revision 1.28
diff -u -r1.28 cityturn.h
--- server/cityturn.h 2002/12/18 17:36:20 1.28
+++ server/cityturn.h 2003/05/30 21:55:53
@@ -21,6 +21,8 @@
struct unit;
struct conn_list;
+void sanity_check_city(struct city *pcity);
+
void city_refresh(struct city *pcity); /* call if city has changed */
void global_city_refresh(struct player *pplayer); /* tax/govt changed */
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.127
diff -u -r1.127 srv_main.c
--- server/srv_main.c 2003/05/15 16:02:00 1.127
+++ server/srv_main.c 2003/05/30 21:55:53
@@ -91,6 +91,8 @@
#include "unithand.h"
#include "unittools.h"
+#include "cm.h"
+
#include "advmilitary.h"
#include "aidata.h"
#include "aihand.h"
@@ -176,6 +178,9 @@
/* initialize teams */
team_init();
+ /* initialize CM */
+ cm_init();
+
/* mark as initialized */
has_been_srv_init = TRUE;
@@ -1793,6 +1798,7 @@
**************************************************************************/
void server_game_free()
{
+ cm_free();
players_iterate(pplayer) {
player_map_free(pplayer);
} players_iterate_end;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Freeciv-Dev] (PR#4331) Bug in cm.c,
Per I. Mathisen <=
|
|