Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] (PR#4331) Bug in cm.c
Home

[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 <=