Complete.Org: Mailing Lists: Archives: freeciv-ai: September 2003:
[freeciv-ai] Re: Use CM in server (PR#4335)
Home

[freeciv-ai] Re: Use CM in server (PR#4335)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: per@xxxxxxxxxxx
Subject: [freeciv-ai] Re: Use CM in server (PR#4335)
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxx>
Date: Sat, 20 Sep 2003 11:30:55 -0700
Reply-to: rt@xxxxxxxxxxxxxx

On Tue, 16 Sep 2003, Per I. Mathisen wrote:

> This version implements allow_disorder option in CM, makes the server put
> human cities in disorder rather than cause units to be disbanded, and
> updates the patch to current CVS.
> 
> Trivia: Adds 148 lines, removes 402.

Looks good.  I added a couple of comments and fixed a bug where "add to 
city" caused sanity check failure.  Simply put the new citizens to be 
taxmen, as elsewhere.

I think it's ready.

G.

Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.142
diff -u -r1.142 aicity.c
--- ai/aicity.c 2003/07/14 22:40:05     1.142
+++ ai/aicity.c 2003/09/20 18:26:07
@@ -700,188 +700,11 @@
 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));
-}
-
-/**************************************************************************
   This function tries desperately to save a city from going under by
   revolt or starvation of food or resources. We do this by taking
   over resources held by nearby cities and disbanding units.
@@ -919,8 +742,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);
@@ -934,9 +757,6 @@
     }
   } map_city_radius_iterate_end;
   auto_arrange_workers(pcity);
-  if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE)) {
-    ai_scientists_taxmen(pcity);
-  }
 
   if (!CITY_EMERGENCY(pcity)) {
     freelog(LOG_EMERGENCY, "Emergency in %s resolved", pcity->name);
@@ -954,7 +774,6 @@
       /* 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;
 
@@ -971,9 +790,6 @@
     /* 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.19
diff -u -r1.19 aicity.h
--- ai/aicity.h 2003/07/14 11:34:53     1.19
+++ ai/aicity.h 2003/09/20 18:26:07
@@ -28,9 +28,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);
 
 enum ai_city_task { AICITY_NONE, AICITY_TECH, AICITY_TAX, AICITY_PROD};
 /* These are not used (well, except AICITY_NONE)  --dwp */
Index: ai/aihand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v
retrieving revision 1.86
diff -u -r1.86 aihand.c
--- ai/aihand.c 2003/09/19 10:00:18     1.86
+++ ai/aihand.c 2003/09/20 18:26:07
@@ -201,9 +201,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);
@@ -244,9 +241,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: client/agents/cma_fec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/agents/cma_fec.c,v
retrieving revision 1.15
diff -u -r1.15 cma_fec.c
--- client/agents/cma_fec.c     2003/04/04 15:47:46     1.15
+++ client/agents/cma_fec.c     2003/09/20 18:26:07
@@ -130,6 +130,7 @@
 
       dest->happy_factor = 1;
       dest->require_happy = FALSE;
+      dest->allow_disorder = FALSE;
       dest->factor_target = FT_SURPLUS;
 
       cmafec_set_fe_parameter(pcity, dest);
Index: common/aicore/cm.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.c,v
retrieving revision 1.9
diff -u -r1.9 cm.c
--- common/aicore/cm.c  2003/09/19 15:39:57     1.9
+++ common/aicore/cm.c  2003/09/20 18:26:07
@@ -322,7 +322,7 @@
 {
   int i;
 
-  if (result->disorder) {
+  if (!parameter->allow_disorder && result->disorder) {
     return FALSE;
   }
   if (parameter->require_happy && !result->happy) {
@@ -1531,6 +1531,9 @@
     }
   }
   if (p1->require_happy != p2->require_happy) {
+    return FALSE;
+  }
+  if (p1->allow_disorder != p2->allow_disorder) {
     return FALSE;
   }
   if (p1->factor_target != p2->factor_target) {
Index: common/aicore/cm.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/cm.h,v
retrieving revision 1.1
diff -u -r1.1 cm.h
--- common/aicore/cm.h  2002/12/22 17:59:11     1.1
+++ common/aicore/cm.h  2003/09/20 18:26:08
@@ -40,6 +40,7 @@
 struct cm_parameter {
   int minimal_surplus[NUM_STATS];
   bool require_happy;
+  bool allow_disorder;
 
   enum factor_target factor_target;
 
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/09/20 18:26:08
@@ -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.232
diff -u -r1.232 citytools.c
--- server/citytools.c  2003/09/09 15:55:52     1.232
+++ server/citytools.c  2003/09/20 18:26:09
@@ -953,6 +953,7 @@
     build_free_palace(pgiver, pcity->name);
   }
 
+  sanity_check_city(pcity);
   sync_cities();
 }
 
@@ -1058,6 +1059,7 @@
       send_city_info(city_owner(home), home);
     }
   } unit_list_iterate_end;
+  sanity_check_city(pcity);
 }
 
 /**************************************************************************
@@ -2034,7 +2036,8 @@
   case C_TILE_WORKER:
     if (!is_available) {
       server_set_tile_city(pcity, city_x, city_y, C_TILE_UNAVAILABLE);
-      add_adjust_workers(pcity); /* will place the displaced */
+      pcity->ppl_elvis++; /* 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.222
diff -u -r1.222 cityturn.c
--- server/cityturn.c   2003/09/09 15:55:52     1.222
+++ server/cityturn.c   2003/09/20 18:26:09
@@ -45,8 +45,12 @@
 #include "unittools.h"
 #include "unithand.h"
 
+#include "cm.h"
+
 #include "advdomestic.h"
 #include "aicity.h"
+#include "aidata.h"
+#include "ailog.h"
 #include "aitools.h"           /* for ai_advisor_choose_building/ai_choice */
 
 #include "cityturn.h"
@@ -69,17 +73,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);
-
 /**************************************************************************
 ...
 **************************************************************************/
@@ -142,173 +141,113 @@
   } city_list_iterate_end;
 }
 
-/**************************************************************************
-You need to call sync_cities for the affected cities to be synced with the
-client.
-**************************************************************************/
-static void worker_loop(struct city *pcity, int *foodneed,
-                       int *prodneed, int *workers)
-{
-  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);
-  }
-}
-
 /**************************************************************************
-You need to call sync_cities for the affected cities to be synced with the
-client.
+  Hard check that the numbers of city workers/specialists add up.
 **************************************************************************/
-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 so that the affected cities are 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;
+  struct player *pplayer = city_owner(pcity);
+  struct ai_data *ai = ai_data_get(pplayer);
 
-  city_map_iterate(x, y) {
-    if (get_worker_city(pcity, x, y) == C_TILE_WORKER
-       && !is_city_center(x, y))
+  sanity_check_city(pcity);
+  cm_clear_cache(pcity);
+
+  cmp.require_happy = FALSE;
+  cmp.allow_disorder = FALSE;
+  cmp.factor_target = FT_SURPLUS;
+
+  /* WAGs. These are set for both AI and humans.
+   * FIXME: Adjust & remove kludges */
+  cmp.factor[FOOD] = ai->food_priority - 9;
+  cmp.factor[SHIELD] = ai->shield_priority - 7;
+  cmp.factor[TRADE] = 10;
+  cmp.factor[GOLD] = ai->gold_priority - 11;
+  cmp.factor[LUXURY] = ai->luxury_priority;
+  cmp.factor[SCIENCE] = ai->science_priority + 3;
+  cmp.happy_factor = ai->happy_priority - 1;
+
+  cmp.minimal_surplus[FOOD] = 1;
+  cmp.minimal_surplus[SHIELD] = 1;
+  cmp.minimal_surplus[TRADE] = 0;
+  cmp.minimal_surplus[GOLD] = 0;
+  cmp.minimal_surplus[LUXURY] = 0;
+  cmp.minimal_surplus[SCIENCE] = 0;
+
+  cm_query_result(pcity, &cmp, &cmr);
+
+  if (!cmr.found_a_valid) {
+    cmp.minimal_surplus[FOOD] = 0;
+    cmp.minimal_surplus[SHIELD] = 0;
+    cmp.minimal_surplus[GOLD] = -20;
+    cm_query_result(pcity, &cmp, &cmr);
+  }
+
+  if (!cmr.found_a_valid) {
+    if (!pplayer->ai.control) {
+      /* For human players: Try very hard to avoid negative
+       * production, even allow disorder. */
+      cmp.allow_disorder = TRUE;
+    }
+    cmp.minimal_surplus[FOOD] = -(pcity->food_stock);
+    cmp.minimal_surplus[TRADE] = -20;
+    cm_query_result(pcity, &cmp, &cmr);
+  }
+
+  if (!cmr.found_a_valid) {
+    CITY_LOG(LOG_DEBUG, pcity, "emergency 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.allow_disorder = TRUE;
+
+    cm_query_result(pcity, &cmp, &cmr);
+
+    assert(cmr.found_a_valid);
+  }
+
+  /* Now apply results */
+  city_map_checked_iterate(pcity->x, pcity->y, x, y, mapx, mapy) {
+    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_checked_iterate_end;
+  pcity->ppl_elvis = cmr.entertainers;
+  pcity->ppl_scientist = cmr.scientists;
+  pcity->ppl_taxman = cmr.taxmen;
+
+  sanity_check_city(pcity);
 
   city_refresh(pcity);
 }
@@ -431,6 +370,10 @@
 **************************************************************************/
 bool city_reduce_size(struct city *pcity, int pop_loss)
 {
+  if (pop_loss == 0) {
+    return TRUE;
+  }
+
   if (pcity->size <= pop_loss) {
     remove_city_from_minimap(pcity->x, pcity->y);
     remove_city(pcity);
@@ -438,17 +381,16 @@
   }
   pcity->size -= pop_loss;
 
-  /*
-   * Cap the food stock at the new granary size.
-   */
+  /* Cap the food stock at the new granary size. */
   if (pcity->food_stock > city_granary_size(pcity->size)) {
     pcity->food_stock = city_granary_size(pcity->size);
   }
 
+  /* First try to kill off the specialists */
   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);
@@ -462,10 +404,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);
   return TRUE;
 }
 
@@ -550,18 +502,16 @@
     }
 
   } else {
-    add_adjust_workers(pcity);
+    pcity->ppl_taxman++; /* or else city is !sane */
+    auto_arrange_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();
 }
 
@@ -1224,28 +1174,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();
-  }
-}
-
-/**************************************************************************
   Returns the cost to incite a city. This depends on the size of the city,
   the number of happy, unhappy and angry citizens, whether it is
   celebrating, how close it is to the capital, how many units it has and
@@ -1373,12 +1301,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.30
diff -u -r1.30 cityturn.h
--- server/cityturn.h   2003/09/09 15:55:52     1.30
+++ server/cityturn.h   2003/09/20 18:26:09
@@ -21,11 +21,12 @@
 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 */
 
 void auto_arrange_workers(struct city *pcity); /* will arrange the workers */
-void add_adjust_workers(struct city *pcity);   /* will add workers */
 
 bool city_reduce_size(struct city *pcity, int pop_loss);
 void send_global_city_turn_notifications(struct conn_list *dest);
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.137
diff -u -r1.137 srv_main.c
--- server/srv_main.c   2003/09/19 10:00:18     1.137
+++ server/srv_main.c   2003/09/20 18:26:10
@@ -92,6 +92,8 @@
 #include "unithand.h"
 #include "unittools.h"
 
+#include "cm.h"
+
 #include "advdiplomacy.h"
 #include "advmilitary.h"
 #include "aidata.h"
@@ -1584,6 +1586,7 @@
 
   /* Run server loop */
   while (TRUE) {
+    cm_init(); /* initialize CM */
     srv_loop();
     if (game.timeout == -1) {
       server_quit();
@@ -1805,6 +1808,7 @@
 **************************************************************************/
 void server_game_free()
 {
+  cm_free();
   players_iterate(pplayer) {
     player_map_free(pplayer);
   } players_iterate_end;
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.271
diff -u -r1.271 unithand.c
--- server/unithand.c   2003/09/19 14:16:56     1.271
+++ server/unithand.c   2003/09/20 18:26:10
@@ -542,7 +542,9 @@
 
   assert(unit_pop_value(punit->type) > 0);
   pcity->size += unit_pop_value(punit->type);
-  add_adjust_workers(pcity);
+  /* Make the new people something, otherwise city fails the checks */
+  pcity->ppl_taxman += unit_pop_value(punit->type);
+  auto_arrange_workers(pcity);
   wipe_unit(punit);
   send_city_info(NULL, pcity);
   notify_player_ex(pplayer, pcity->x, pcity->y, E_NOEVENT,

[Prev in Thread] Current Thread [Next in Thread]
  • [freeciv-ai] Re: Use CM in server (PR#4335), Gregory Berkolaiko <=