<URL: http://bugs.freeciv.org/Ticket/Display.html?id=39829 >

Per I. Mathisen wrote:
> That should not be the problem. These are just two different ways of
> counting the same citizens. A citizen has two properties - its kind
> (worker or specialist type) and attitude (happy, unhappy, angry,
> celebrating, content) - and you need to count both, but separately.
> 
Maybe it shouldn't be a problem, but it is....  The citydlg_common.c
code counts the attitude numbers, adds the specialists (which apparently
aren't included in the attitude), and assert(i == pcity->size) fails.

So, the virtual city fails the test.  I've found that the short_info
packet sets the CITIZEN_CONTENT to city->size, so I'm doing that now,
leaving the default specialist at zero.

I've instrumented the player_load, and the packhand, and still cannot
figure out how the bad attitude numbers are passed.

I also cannot figure out why the player0 client thinks that the city
belongs to it.  The save game says that player0 thinks the city belongs
to player5.

Something really odd is going on.

Anyway, I've written code to eliminate the need for the assert().
The function now returns the number of entries.  The callers use this
instead of city->size.  A LOG_ERROR is generated.  That gives the
ability to test without crashing.

The LOG_ERROR says:

1: get_city_citizen_types() 0 citizens not equal 2 city size in "Ibadan".

Comparing the S2_1 code with S2_2 code, found a parameter error on a
for (miscounts the number of sprites).  But since the define was always 5
instead of the correct 6, it didn't hurt anything.

Other than that, I've not seen any bugs remotely related to this.  I've
done a pile of defines (instead of numbers) to make the code clearer,
and backported some S2_2 code to make testing comparisons easier.

Index: server/score.c
===================================================================
--- server/score.c      (revision 13910)
+++ server/score.c      (working copy)
@@ -259,10 +259,10 @@
   city_list_iterate(pplayer->cities, pcity) {
     int bonus;
 
-    pplayer->score.happy += pcity->ppl_happy[4];
-    pplayer->score.content += pcity->ppl_content[4];
-    pplayer->score.unhappy += pcity->ppl_unhappy[4];
-    pplayer->score.angry += pcity->ppl_angry[4];
+    pplayer->score.happy += pcity->feel[CITIZEN_HAPPY][FEELING_FINAL];
+    pplayer->score.content += pcity->feel[CITIZEN_CONTENT][FEELING_FINAL];
+    pplayer->score.unhappy += pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL];
+    pplayer->score.angry += pcity->feel[CITIZEN_ANGRY][FEELING_FINAL];
     specialist_type_iterate(sp) {
       pplayer->score.specialists[sp] += pcity->specialists[sp];
     } specialist_type_iterate_end;
Index: server/citytools.c
===================================================================
--- server/citytools.c  (revision 13910)
+++ server/citytools.c  (working copy)
@@ -1627,17 +1627,18 @@
   sz_strlcpy(packet->name, pcity->name);
 
   packet->size=pcity->size;
-  for (i=0;i<5;i++) {
-    packet->ppl_happy[i]=pcity->ppl_happy[i];
-    packet->ppl_content[i]=pcity->ppl_content[i];
-    packet->ppl_unhappy[i]=pcity->ppl_unhappy[i];
-    packet->ppl_angry[i]=pcity->ppl_angry[i];
+  for (i = 0; i < FEELING_LAST; i++) {
+    packet->ppl_happy[i] = pcity->feel[CITIZEN_HAPPY][i];
+    packet->ppl_content[i] = pcity->feel[CITIZEN_CONTENT][i];
+    packet->ppl_unhappy[i] = pcity->feel[CITIZEN_UNHAPPY][i];
+    packet->ppl_angry[i] = pcity->feel[CITIZEN_ANGRY][i];
   }
-  /* The number of data in specilists[] array */
+  /* The number of data in specialists[] array */
   packet->specialists_size = SP_COUNT;
   specialist_type_iterate(sp) {
     packet->specialists[sp] = pcity->specialists[sp];
   } specialist_type_iterate_end;
+
   for (i = 0; i < NUM_TRADEROUTES; i++) {
     packet->trade[i]=pcity->trade[i];
     packet->trade_value[i]=pcity->trade_value[i];
Index: server/cityturn.c
===================================================================
--- server/cityturn.c   (revision 13910)
+++ server/cityturn.c   (working copy)
@@ -1401,9 +1401,9 @@
   }
 
   size = MAX(1, pcity->size
-                + pcity->ppl_happy[4]
-                - pcity->ppl_unhappy[4]
-                - pcity->ppl_angry[4] * 3);
+                + pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]
+                - pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]
+                - pcity->feel[CITIZEN_ANGRY][FEELING_FINAL] * 3);
   cost *= size;
   cost *= game.info.incite_total_factor;
   cost = cost / (dist + 3);
Index: server/savegame.c
===================================================================
--- server/savegame.c   (revision 13910)
+++ server/savegame.c   (working copy)
@@ -2242,11 +2242,12 @@
 
   for (i = 0; i < ncities; i++) { /* read the cities */
     struct city *pcity;
+    const char *name;
+    int id, k;
+    int citizens = 0;
     int nat_x = secfile_lookup_int(file, "player%d.c%d.x", plrno, i);
     int nat_y = secfile_lookup_int(file, "player%d.c%d.y", plrno, i);
     struct tile *ptile = native_pos_to_tile(nat_x, nat_y);
-    const char* name;
-    int id, k;
 
     pcity = create_city_virtual(plr, ptile,
                       secfile_lookup_str(file, "player%d.c%d.name", plrno, i));
@@ -2270,6 +2271,7 @@
     pcity->steal=secfile_lookup_int(file, "player%d.c%d.steal", plrno, i);
 
     specialist_type_iterate(sp) {
+      citizens +=
       pcity->specialists[sp]
        = secfile_lookup_int(file, "player%d.c%d.n%s", plrno, i,
                             get_specialist(sp)->name);
@@ -2413,36 +2415,60 @@
     p=secfile_lookup_str(file, "player%d.c%d.workers", plrno, i);
     for(y=0; y<CITY_MAP_SIZE; y++) {
       for(x=0; x<CITY_MAP_SIZE; x++) {
-       pcity->city_map[x][y] =
-           is_valid_city_coords(x, y) ? C_TILE_EMPTY : C_TILE_UNAVAILABLE;
+        bool valid = is_valid_city_coords(x, y);
+       pcity->city_map[x][y] = valid ? C_TILE_EMPTY : C_TILE_UNAVAILABLE;
+
        if (*p == '0') {
-         set_worker_city(pcity, x, y,
-                         city_map_to_map(pcity, x, y) ?
-                         C_TILE_EMPTY : C_TILE_UNAVAILABLE);
+         if (!valid) {
+           /* oops, inconsistent savegame; minimal fix: */
+           freelog(LOG_VERBOSE, "Invalid workers '%c' for %s (%d,%d), "
+                   "ignoring", *p, pcity->name, x, y);
+         } else {
+           set_worker_city(pcity, x, y,
+                           NULL != city_map_to_map(pcity, x, y)
+                           ? C_TILE_EMPTY : C_TILE_UNAVAILABLE);
+         }
        } else if (*p=='1') {
          struct tile *ptile;
-
-         ptile = city_map_to_map(pcity, x, y);
-
-         if (ptile->worked) {
+         if (!valid) {
            /* oops, inconsistent savegame; minimal fix: */
+           freelog(LOG_VERBOSE, "Invalid workers '%c' for %s (%d,%d), "
+                   "ignoring", *p, pcity->name, x, y);
+         } else if (NULL == (ptile = city_map_to_map(pcity, x, y))
+                 || ptile->worked) {
+           /* oops, inconsistent savegame; minimal fix: */
            freelog(LOG_VERBOSE, "Inconsistent worked for %s (%d,%d), "
                    "converting to specialist", pcity->name, x, y);
            pcity->specialists[DEFAULT_SPECIALIST]++;
            set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
+           citizens++;
          } else {
            set_worker_city(pcity, x, y, C_TILE_WORKER);
+           citizens++;
          }
-       } else {
-         assert(*p == '2');
-         if (is_valid_city_coords(x, y)) {
+       } else if (*p == '2') {
+         if (valid) {
            set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
          }
          assert(pcity->city_map[x][y] == C_TILE_UNAVAILABLE);
+       } else {
+          freelog(LOG_VERBOSE, "Invalid workers '%c' for %s (%d,%d), "
+                  "ignoring", *p, pcity->name, x, y);
        }
         p++;
       }
     }
+    /* center tile worker isn't counted in city size */
+    if (citizens > 1) {
+      citizens--;
+    }
+    if (citizens != pcity->size) {
+      freelog(LOG_ERROR, "player_load()"
+              " %d citizens not equal %d city size in \"%s\".",
+              citizens,
+              pcity->size,
+              pcity->name);
+    }
 
     /* Initialise list of improvements with City- and Building-wide
        equiv_ranges */
@@ -3456,19 +3482,17 @@
     case C_TILE_EMPTY:
       if (!res) {
        set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
-       freelog(LOG_DEBUG, "unavailable tile marked as empty!");
+       freelog(LOG_VERBOSE, "unavailable tile marked as empty!");
       }
       break;
     case C_TILE_WORKER:
       if (!res) {
-       struct tile *ptile;
+       struct tile *ptile= city_map_to_map(pcity, x, y);
 
        pcity->specialists[DEFAULT_SPECIALIST]++;
        set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE);
-       freelog(LOG_DEBUG, "Worked tile was unavailable!");
+       freelog(LOG_VERBOSE, "Worked tile was unavailable!");
 
-       ptile = city_map_to_map(pcity, x, y);
-
        map_city_radius_iterate(ptile, tile2) {
          struct city *pcity2 = tile_get_city(tile2);
          if (pcity2)
@@ -3479,7 +3503,7 @@
     case C_TILE_UNAVAILABLE:
       if (res) {
        set_worker_city(pcity, x, y, C_TILE_EMPTY);
-       freelog(LOG_DEBUG, "Empty tile Marked as unavailable!");
+       freelog(LOG_VERBOSE, "Empty tile marked as unavailable!");
       }
       break;
     }
Index: common/city.c
===================================================================
--- common/city.c       (revision 13910)
+++ common/city.c       (working copy)
@@ -1010,9 +1010,9 @@
 **************************************************************************/
 bool city_happy(const struct city *pcity)
 {
-  return (pcity->ppl_happy[4] >= (pcity->size + 1) / 2
-         && pcity->ppl_unhappy[4] == 0
-          && pcity->ppl_angry[4] == 0
+  return (pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] >= (pcity->size + 1) / 2
+         && pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] == 0
+          && pcity->feel[CITIZEN_ANGRY][FEELING_FINAL] == 0
           && pcity->size >= game.info.celebratesize);
 }
 
@@ -1022,8 +1022,8 @@
 **************************************************************************/
 bool city_unhappy(const struct city *pcity)
 {
-  return (pcity->ppl_happy[4] <
-         pcity->ppl_unhappy[4] + 2 * pcity->ppl_angry[4]);
+  return (pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] <
+         pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + 2 * 
pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
 }
 
 /**************************************************************************
@@ -1627,10 +1627,10 @@
 **************************************************************************/
 static void happy_copy(struct city *pcity, int i)
 {
-  pcity->ppl_angry[i + 1] = pcity->ppl_angry[i];
-  pcity->ppl_unhappy[i + 1] = pcity->ppl_unhappy[i];
-  pcity->ppl_content[i + 1] = pcity->ppl_content[i];
-  pcity->ppl_happy[i + 1] = pcity->ppl_happy[i];
+  pcity->feel[CITIZEN_ANGRY][i + 1] = pcity->feel[CITIZEN_ANGRY][i];
+  pcity->feel[CITIZEN_UNHAPPY][i + 1] = pcity->feel[CITIZEN_UNHAPPY][i];
+  pcity->feel[CITIZEN_CONTENT][i + 1] = pcity->feel[CITIZEN_CONTENT][i];
+  pcity->feel[CITIZEN_HAPPY][i + 1] = pcity->feel[CITIZEN_HAPPY][i];
 }
 
 /**************************************************************************
@@ -1728,8 +1728,11 @@
 
   happy_copy(pcity, 0);
 
-  citizen_luxury_happy(pcity, &x, &pcity->ppl_angry[1], 
&pcity->ppl_unhappy[1], 
-                       &pcity->ppl_happy[1], &pcity->ppl_content[1]);
+  citizen_luxury_happy(pcity, &x,
+                       &pcity->feel[CITIZEN_ANGRY][FEELING_LUXURY],
+                       &pcity->feel[CITIZEN_UNHAPPY][FEELING_LUXURY],
+                       &pcity->feel[CITIZEN_HAPPY][FEELING_LUXURY],
+                       &pcity->feel[CITIZEN_CONTENT][FEELING_LUXURY]);
 }
 
 /**************************************************************************
@@ -1758,7 +1761,7 @@
   Make citizens happy/unhappy due to units.
 
   This function requires that pcity->martial_law and
-  pcity->unit_happy_cost have already been set in city_support.
+  pcity->unit_happy_cost have already been set in city_support().
 **************************************************************************/
 static inline void citizen_happy_units(struct city *pcity, int *happy,
                                        int *content, int *unhappy,
@@ -2102,7 +2105,7 @@
   places.
 
   A full refresh updates all cached data: including but not limited to
-  ppl_happy[], surplus[], waste[], citizen_base[], usage[], trade[],
+  feel[CITIZEN_HAPPY][], surplus[], waste[], citizen_base[], usage[], trade[],
   bonus[], and tile_output[].
 
   A partial refresh will not update tile_output[] or bonus[].  These two
@@ -2131,24 +2134,30 @@
   add_specialist_output(pcity, pcity->citizen_base);
 
   set_city_production(pcity);
-  citizen_base_mood(pplayer, city_specialists(pcity), &pcity->ppl_happy[0], 
-                    &pcity->ppl_content[0], &pcity->ppl_unhappy[0], 
-                    &pcity->ppl_angry[0], pcity->size);
+  citizen_base_mood(pplayer, city_specialists(pcity),
+                    &pcity->feel[CITIZEN_HAPPY][FEELING_BASE],
+                    &pcity->feel[CITIZEN_CONTENT][FEELING_BASE],
+                    &pcity->feel[CITIZEN_UNHAPPY][FEELING_BASE],
+                    &pcity->feel[CITIZEN_ANGRY][FEELING_BASE],
+                    pcity->size);
   pcity->pollution = city_pollution(pcity, pcity->prod[O_SHIELD]);
   citizen_happy_luxury(pcity); /* with our new found luxuries */
   happy_copy(pcity, 1);
-  citizen_content_buildings(pcity, &pcity->ppl_content[2], 
-                            &pcity->ppl_unhappy[2], &pcity->ppl_angry[2]);
+  citizen_content_buildings(pcity, 
&pcity->feel[CITIZEN_CONTENT][FEELING_EFFECT], 
+                            &pcity->feel[CITIZEN_UNHAPPY][FEELING_EFFECT],
+                            &pcity->feel[CITIZEN_ANGRY][FEELING_EFFECT]);
   happy_copy(pcity, 2);
   /* Martial law & unrest from units */
-  citizen_happy_units(pcity, &pcity->ppl_happy[3],
-                      &pcity->ppl_content[3], &pcity->ppl_unhappy[3], 
-                      &pcity->ppl_angry[3]);
+  citizen_happy_units(pcity, &pcity->feel[CITIZEN_HAPPY][FEELING_MARTIAL],
+                      &pcity->feel[CITIZEN_CONTENT][FEELING_MARTIAL],
+                      &pcity->feel[CITIZEN_UNHAPPY][FEELING_MARTIAL], 
+                      &pcity->feel[CITIZEN_ANGRY][FEELING_MARTIAL]);
   happy_copy(pcity, 3);
   /* Building (including wonder) happiness effects */
-  citizen_happy_wonders(pcity, &pcity->ppl_happy[4],
-                      &pcity->ppl_content[4], &pcity->ppl_unhappy[4],
-                      &pcity->ppl_angry[4]);
+  citizen_happy_wonders(pcity, &pcity->feel[CITIZEN_HAPPY][FEELING_FINAL],
+                      &pcity->feel[CITIZEN_CONTENT][FEELING_FINAL],
+                      &pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL],
+                      &pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
   unhappy_city_check(pcity);
   set_surpluses(pcity);
 
@@ -2371,25 +2380,28 @@
                                 struct tile *ptile, const char *name)
 {
   int i;
-  struct city *pcity;
+  struct city *pcity = fc_calloc(1, sizeof(*pcity));
 
-  pcity = fc_malloc(sizeof(*pcity));
-
   pcity->id = 0;
   assert(pplayer != NULL); /* No unowned cities! */
+  pcity->original = pplayer;
   pcity->owner = pplayer;
   pcity->tile = ptile;
   sz_strlcpy(pcity->name, name);
   pcity->size = 1;
+#if 0
+  /* some zero variables not compiled, but left for searching */
   memset(pcity->tile_output, 0, sizeof(pcity->tile_output));
   specialist_type_iterate(sp) {
     pcity->specialists[sp] = 0;
   } specialist_type_iterate_end;
-  pcity->specialists[DEFAULT_SPECIALIST] = 1;
-  pcity->ppl_happy[4] = 0;
-  pcity->ppl_content[4] = 1;
-  pcity->ppl_unhappy[4] = 0;
-  pcity->ppl_angry[4] = 0;
+  pcity->specialists[DEFAULT_SPECIALIST] = 0;
+  pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] = 0;
+#endif
+  pcity->feel[CITIZEN_CONTENT][FEELING_FINAL] = pcity->size;
+#if 0
+  pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] = 0;
+  pcity->feel[CITIZEN_ANGRY][FEELING_FINAL] = 0;
   pcity->was_happy = FALSE;
   pcity->steal = 0;
   for (i = 0; i < NUM_TRADEROUTES; i++) {
@@ -2397,7 +2409,7 @@
   }
   pcity->food_stock = 0;
   pcity->shield_stock = 0;
-  pcity->original = pplayer;
+#endif
 
   /* Initialise improvements list */
   for (i = 0; i < ARRAY_SIZE(pcity->improvements); i++) {
@@ -2464,6 +2476,8 @@
   pcity->ai.founder_want = 0; /* calculating this is really expensive */
   pcity->ai.next_founder_want_recalc = 0; /* turns to recalc found_want */
   pcity->ai.trade_want = 1; /* we always want some */
+#if 0
+  /* some zero variables not compiled, but left for searching */
   memset(pcity->ai.building_want, 0, sizeof(pcity->ai.building_want));
   pcity->ai.danger = 0;
   pcity->ai.urgency = 0;
@@ -2481,6 +2495,7 @@
         O_COUNT * sizeof(*pcity->unhappy_penalty));
   memset(pcity->prod, 0, O_COUNT * sizeof(*pcity->prod));
   memset(pcity->citizen_base, 0, O_COUNT * sizeof(*pcity->citizen_base));
+#endif
   output_type_iterate(o) {
     pcity->bonus[o] = 100;
   } output_type_iterate_end;
Index: common/city.h
===================================================================
--- common/city.h       (revision 13910)
+++ common/city.h       (working copy)
@@ -198,6 +198,26 @@
   int next_recalc; /* Only recalc every Nth turn */
 };
 
+enum citizen_category {
+  CITIZEN_HAPPY,
+  CITIZEN_CONTENT,
+  CITIZEN_UNHAPPY,
+  CITIZEN_ANGRY,
+  CITIZEN_LAST,
+  CITIZEN_SPECIALIST = CITIZEN_LAST,
+};
+
+/* changing this order will break network compatibility,
+ * and clients that don't use the symbols. */
+enum citizen_feeling {
+  FEELING_BASE,                /* before any of the modifiers below */
+  FEELING_LUXURY,      /* after luxury */
+  FEELING_EFFECT,      /* after building effects */
+  FEELING_MARTIAL,     /* after units enforce martial order */
+  FEELING_FINAL,       /* after wonders (final result) */
+  FEELING_LAST
+};
+
 struct city {
   int id;
   struct player *owner; /* Cannot be NULL. */
@@ -207,23 +227,17 @@
   /* the people */
   int size;
 
-  /* Tile output, regardless of if the tile is actually worked. */
-  unsigned char tile_output[CITY_MAP_SIZE][CITY_MAP_SIZE][O_MAX];
+  int feel[CITIZEN_LAST][FEELING_LAST];
 
-  /* How the citizens feel:
-     ppl_*[0] is distribution before any of the modifiers below.
-     ppl_*[1] is distribution after luxury.
-     ppl_*[2] is distribution after after building effects.
-     ppl_*[3] is distribution after units enfored martial order.
-     ppl_*[4] is distribution after wonders. (final result.) */
-  int ppl_happy[5], ppl_content[5], ppl_unhappy[5], ppl_angry[5];
-
   /* Specialists */
   int specialists[SP_MAX];
 
   /* trade routes */
   int trade[NUM_TRADEROUTES], trade_value[NUM_TRADEROUTES];
 
+  /* Tile output, regardless of if the tile is actually worked. */
+  unsigned char tile_output[CITY_MAP_SIZE][CITY_MAP_SIZE][O_MAX];
+
   /* the productions */
   int surplus[O_MAX]; /* Final surplus in each category. */
   int waste[O_MAX]; /* Waste/corruption in each category. */
Index: ai/aicity.c
===================================================================
--- ai/aicity.c (revision 13910)
+++ ai/aicity.c (working copy)
@@ -123,9 +123,9 @@
            + pcity->prod[O_LUXURY] * ai->luxury_priority
            + pcity->prod[O_GOLD] * ai->gold_priority
            + pcity->prod[O_SCIENCE] * ai->science_priority
-           + pcity->ppl_happy[4] * ai->happy_priority
-           - pcity->ppl_unhappy[4] * ai->unhappy_priority
-           - pcity->ppl_angry[4] * ai->angry_priority
+           + pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] * ai->happy_priority
+           - pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] * ai->unhappy_priority
+           - pcity->feel[CITIZEN_ANGRY][FEELING_FINAL] * ai->angry_priority
            - pcity->pollution * ai->pollution_priority);
 
   if (pcity->surplus[O_FOOD] < 0 || pcity->surplus[O_SHIELD] < 0) {
@@ -377,7 +377,7 @@
          v += c * amount / 100;
          break;
        case EFT_MAKE_HAPPY:
-         v += (get_entertainers(pcity) + pcity->ppl_unhappy[4]) * 5 * amount;
+         v += (get_entertainers(pcity) + 
pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]) * 5 * amount;
           if (city_list_size(pplayer->cities)
                 > game.info.cityfactor 
                   + get_player_bonus(pplayer, EFT_EMPIRE_SIZE_MOD)) {
@@ -389,14 +389,14 @@
          /* TODO */
          break;
        case EFT_NO_UNHAPPY:
-         v += (get_entertainers(pcity) + pcity->ppl_unhappy[4]) * 30;
+         v += (get_entertainers(pcity) + 
pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]) * 30;
          break;
        case EFT_FORCE_CONTENT:
        case EFT_MAKE_CONTENT:
          if (get_city_bonus(pcity, EFT_NO_UNHAPPY) <= 0) {
             int factor = 2;
 
-           v += MIN(amount, pcity->ppl_unhappy[4] + get_entertainers(pcity)) * 
35;
+           v += MIN(amount, pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + 
get_entertainers(pcity)) * 35;
 
             /* Try to build wonders to offset empire size unhappiness */
             if (city_list_size(pplayer->cities) 
@@ -413,14 +413,14 @@
          break;
        case EFT_MAKE_CONTENT_MIL_PER:
           if (get_city_bonus(pcity, EFT_NO_UNHAPPY) <= 0) {
-           v += MIN(pcity->ppl_unhappy[4] + get_entertainers(pcity),
+           v += MIN(pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + 
get_entertainers(pcity),
                     amount) * 25;
            v += MIN(amount, 5) * c;
          }
          break;
        case EFT_MAKE_CONTENT_MIL:
           if (get_city_bonus(pcity, EFT_NO_UNHAPPY) <= 0) {
-           v += pcity->ppl_unhappy[4] * amount
+           v += pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] * amount
              * MAX(unit_list_size(pcity->units_supported), 0) * 2;
            v += c * MAX(amount + 2, 1);
          }
@@ -1410,8 +1410,10 @@
   freelog(LOG_EMERGENCY,
           "Emergency in %s (%s, angry%d, unhap%d food%d, prod%d)",
           pcity->name, city_unhappy(pcity) ? "unhappy" : "content",
-          pcity->ppl_angry[4], pcity->ppl_unhappy[4],
-          pcity->surplus[O_FOOD], pcity->surplus[O_SHIELD]);
+          pcity->feel[CITIZEN_ANGRY][FEELING_FINAL],
+          pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL],
+          pcity->surplus[O_FOOD],
+          pcity->surplus[O_SHIELD]);
 
   minilist = city_list_new();
   map_city_radius_iterate(pcity->tile, ptile) {
Index: ai/advmilitary.c
===================================================================
--- ai/advmilitary.c    (revision 13910)
+++ ai/advmilitary.c    (working copy)
@@ -1385,7 +1385,7 @@
   } /* ok, don't need to defend */
 
   if (pcity->surplus[O_SHIELD] <= 0 
-      || pcity->ppl_unhappy[4] > pcity->ppl_unhappy[2]
+      || pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] > 
pcity->feel[CITIZEN_UNHAPPY][FEELING_EFFECT]
       || pcity->id == ai->wonder_city) {
     /* Things we consider below are not life-saving so we don't want to 
      * build them if our populace doesn't feel like it */
Index: client/citydlg_common.c
===================================================================
--- client/citydlg_common.c     (revision 13910)
+++ client/citydlg_common.c     (working copy)
@@ -506,22 +506,22 @@
   happiness).  "citizens" should be an array large enough to hold all
   citizens (use MAX_CITY_SIZE to be on the safe side).
 **************************************************************************/
-void get_city_citizen_types(struct city *pcity, int index,
-                           struct citizen_type *citizens)
+int get_city_citizen_types(struct city *pcity, enum citizen_feeling index,
+                          struct citizen_type *citizens)
 {
   int i = 0, n;
-  assert(index >= 0 && index < 5);
+  assert(index >= 0 && index < FEELING_LAST);
 
-  for (n = 0; n < pcity->ppl_happy[index]; n++, i++) {
+  for (n = 0; n < pcity->feel[CITIZEN_HAPPY][index]; n++, i++) {
     citizens[i].type = CITIZEN_HAPPY;
   }
-  for (n = 0; n < pcity->ppl_content[index]; n++, i++) {
+  for (n = 0; n < pcity->feel[CITIZEN_CONTENT][index]; n++, i++) {
     citizens[i].type = CITIZEN_CONTENT;
   }
-  for (n = 0; n < pcity->ppl_unhappy[index]; n++, i++) {
+  for (n = 0; n < pcity->feel[CITIZEN_UNHAPPY][index]; n++, i++) {
     citizens[i].type = CITIZEN_UNHAPPY;
   }
-  for (n = 0; n < pcity->ppl_angry[index]; n++, i++) {
+  for (n = 0; n < pcity->feel[CITIZEN_ANGRY][index]; n++, i++) {
     citizens[i].type = CITIZEN_ANGRY;
   }
 
@@ -532,7 +532,15 @@
     }
   } specialist_type_iterate_end;
 
-  assert(i == pcity->size);
+  if (pcity->size != i) {
+    freelog(LOG_ERROR, "get_city_citizen_types()"
+            " %d citizens not equal %d city size in \"%s\".",
+            i,
+            pcity->size,
+            pcity->name);
+  }
+//  assert(i == pcity->size);
+  return i;
 }
 
 /**************************************************************************
@@ -542,16 +550,12 @@
 {
   struct citizen_type citizens[MAX_CITY_SIZE];
   Specialist_type_id from, to;
+  int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, citizens);
 
-  if (citizen_index < 0 || citizen_index >= pcity->size) {
+  if (citizen_index < 0 || citizen_index >= num_citizens
+   || citizens[citizen_index].type != CITIZEN_SPECIALIST) {
     return;
   }
-
-  get_city_citizen_types(pcity, 4, citizens);
-
-  if (citizens[citizen_index].type != CITIZEN_SPECIALIST) {
-    return;
-  }
   from = citizens[citizen_index].spec_type;
 
   /* Loop through all specialists in order until we find a usable one
Index: client/cityrepdata.c
===================================================================
--- client/cityrepdata.c        (revision 13910)
+++ client/cityrepdata.c        (working copy)
@@ -80,9 +80,11 @@
                                    const void *data)
 {
   static char buf[32];
-  my_snprintf(buf, sizeof(buf), "%d/%d/%d/%d", pcity->ppl_happy[4],
-             pcity->ppl_content[4], pcity->ppl_unhappy[4],
-             pcity->ppl_angry[4]);
+  my_snprintf(buf, sizeof(buf), "%d/%d/%d/%d",
+             pcity->feel[CITIZEN_HAPPY][FEELING_FINAL],
+             pcity->feel[CITIZEN_CONTENT][FEELING_FINAL],
+             pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL],
+             pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
   return buf;
 }
 
@@ -90,7 +92,7 @@
                                  const void *data)
 {
   static char buf[8];
-  my_snprintf(buf, sizeof(buf), "%2d", pcity->ppl_happy[4]);
+  my_snprintf(buf, sizeof(buf), "%2d", 
pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]);
   return buf;
 }
 
@@ -98,7 +100,7 @@
                                    const void *data)
 {
   static char buf[8];
-  my_snprintf(buf, sizeof(buf), "%2d", pcity->ppl_content[4]);
+  my_snprintf(buf, sizeof(buf), "%2d", 
pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]);
   return buf;
 }
 
@@ -106,7 +108,7 @@
                                    const void *data)
 {
   static char buf[8];
-  my_snprintf(buf, sizeof(buf), "%2d", pcity->ppl_unhappy[4]);
+  my_snprintf(buf, sizeof(buf), "%2d", 
pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]);
   return buf;
 }
 
@@ -114,7 +116,7 @@
                                  const void *data)
 {
   static char buf[8];
-  my_snprintf(buf, sizeof(buf), "%2d", pcity->ppl_angry[4]);
+  my_snprintf(buf, sizeof(buf), "%2d", 
pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
   return buf;
 }
 
Index: client/citydlg_common.h
===================================================================
--- client/citydlg_common.h     (revision 13910)
+++ client/citydlg_common.h     (working copy)
@@ -17,21 +17,12 @@
 #include <stddef.h>            /* size_t */
 
 #include "shared.h"            /* bool type */
-
-#include "city.h"              /* Specialist_type_id */
 #include "fc_types.h"
 
+#include "city.h"
+
 struct canvas;
 
-enum citizen_category {
-  CITIZEN_SPECIALIST,
-  CITIZEN_CONTENT,
-  CITIZEN_HAPPY,
-  CITIZEN_UNHAPPY,
-  CITIZEN_ANGRY,
-  CITIZEN_LAST
-};
-
 struct citizen_type {
   enum citizen_category type;
   Specialist_type_id spec_type;
@@ -63,8 +54,8 @@
 void get_city_dialog_pollution_text(const struct city *pcity,
                                    char *buffer, size_t bufsz);
 
-void get_city_citizen_types(struct city *pcity, int index,
-                           struct citizen_type *citizens);
+int get_city_citizen_types(struct city *pcity, enum citizen_feeling index,
+                          struct citizen_type *citizens);
 void city_rotate_specialist(struct city *pcity, int citizen_index);
 
 void activate_all_units(struct tile *ptile);
Index: client/gui-gtk-2.0/citydlg.c
===================================================================
--- client/gui-gtk-2.0/citydlg.c        (revision 13910)
+++ client/gui-gtk-2.0/citydlg.c        (working copy)
@@ -1340,19 +1340,20 @@
 *****************************************************************/
 static void city_dialog_update_citizens(struct city_dialog *pdialog)
 {
+  struct citizen_type citizens[MAX_CITY_SIZE];
   int i, width;
   struct city *pcity = pdialog->pcity;
-  struct citizen_type citizens[MAX_CITY_SIZE];
+  int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, citizens);
 
   /* If there is not enough space we stack the icons. We draw from left to */
   /* right. width is how far we go to the right for each drawn pixmap. The */
   /* last icon is always drawn in full, and so has reserved                */
-  /* tileset_small_sprite_width(tileset) pixels.                               
               */
+  /* tileset_small_sprite_width(tileset) pixels.                           */
 
-  if (pcity->size > 1) {
+  if (num_citizens > 1) {
     width = MIN(tileset_small_sprite_width(tileset),
                ((NUM_CITIZENS_SHOWN - 1) * 
tileset_small_sprite_width(tileset)) /
-               (pcity->size - 1));
+               (num_citizens - 1));
   } else {
     width = tileset_small_sprite_width(tileset);
   }
@@ -1361,9 +1362,7 @@
   gtk_pixcomm_freeze(GTK_PIXCOMM(pdialog->citizen_pixmap));
   gtk_pixcomm_clear(GTK_PIXCOMM(pdialog->citizen_pixmap));
 
-  get_city_citizen_types(pcity, 4, citizens);
-
-  for (i = 0; i < pcity->size; i++) {
+  for (i = 0; i < num_citizens; i++) {
     gtk_pixcomm_copyto(GTK_PIXCOMM(pdialog->citizen_pixmap),
                       get_citizen_sprite(tileset, citizens[i], i, pcity),
                       i * width, 0);
Index: client/gui-gtk-2.0/happiness.c
===================================================================
--- client/gui-gtk-2.0/happiness.c      (revision 13910)
+++ client/gui-gtk-2.0/happiness.c      (working copy)
@@ -158,13 +158,11 @@
 **************************************************************************/
 static void refresh_pixcomm(GtkPixcomm *dst, struct city *pcity, int index)
 {
-  int i;
   struct citizen_type citizens[MAX_CITY_SIZE];
-  int num_citizens = pcity->size;
+  int i;
+  int num_citizens = get_city_citizen_types(pcity, index, citizens);
   int offset = MIN(tileset_small_sprite_width(tileset), PIXCOMM_WIDTH / 
num_citizens);
 
-  get_city_citizen_types(pcity, index, citizens);
-
   gtk_pixcomm_freeze(dst);
   gtk_pixcomm_clear(dst);
 
@@ -182,7 +180,6 @@
 void refresh_happiness_dialog(struct city *pcity)
 {
   int i;
-
   struct happiness_dialog *pdialog = get_happiness_dialog(pcity);
 
   for (i = 0; i < 5; i++) {
Index: client/gui-xaw/citydlg.c
===================================================================
--- client/gui-xaw/citydlg.c    (revision 13910)
+++ client/gui-xaw/citydlg.c    (working copy)
@@ -1532,13 +1532,12 @@
 *****************************************************************/
 void city_dialog_update_citizens(struct city_dialog *pdialog)
 {
+  struct citizen_type citizens[MAX_CITY_SIZE];
   int i;
   struct city *pcity=pdialog->pcity;
-  struct citizen_type citizens[MAX_CITY_SIZE];
+  int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, citizens);
 
-  get_city_citizen_types(pcity, 4, citizens);
-
-  for (i = 0; i < pcity->size && i < pdialog->num_citizens_shown; i++) {
+  for (i = 0; i < num_citizens && i < pdialog->num_citizens_shown; i++) {
     xaw_set_bitmap(pdialog->citizen_labels[i],
                   get_citizen_pixmap(citizens[i], i, pcity));
 
@@ -1549,7 +1548,7 @@
     XtSetSensitive(pdialog->citizen_labels[i], TRUE);
   }
 
-  if (i >= pdialog->num_citizens_shown && i < pcity->size) {
+  if (i >= pdialog->num_citizens_shown && i < num_citizens) {
     i = pdialog->num_citizens_shown - 1;
     /* FIXME: what about the mask? */
     xaw_set_bitmap(pdialog->citizen_labels[i], 
get_arrow_sprite(tileset)->pixmap);
Index: client/gui-win32/citydlg.c
===================================================================
--- client/gui-win32/citydlg.c  (revision 13910)
+++ client/gui-win32/citydlg.c  (working copy)
@@ -506,19 +506,15 @@
 
 void city_dialog_update_citizens(HDC hdc,struct city_dialog *pdialog)
 {
-  HDC hdcsrc;
+  struct citizen_type citizens[MAX_CITY_SIZE];
   int i;
-  struct city *pcity=pdialog->pcity;
   RECT rc;
-  HBITMAP oldbit;
-  struct citizen_type citizens[MAX_CITY_SIZE];
+  struct city *pcity=pdialog->pcity;
+  int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, citizens);
+  HDC hdcsrc = CreateCompatibleDC(NULL);
+  HBITMAP oldbit = SelectObject(hdcsrc,pdialog->citizen_bmp);
 
-  hdcsrc = CreateCompatibleDC(NULL);
-  oldbit=SelectObject(hdcsrc,pdialog->citizen_bmp);
-
-  get_city_citizen_types(pcity, 4, citizens);
-
-  for (i = 0; i < pcity->size && i < NUM_CITIZENS_SHOWN; i++) {
+  for (i = 0; i < num_citizens && i < NUM_CITIZENS_SHOWN; i++) {
       draw_sprite(get_citizen_sprite(tileset, citizens[i], i, pcity), hdcsrc,
                  tileset_small_sprite_width(tileset) * i, 0);
   }
Index: client/gui-win32/happiness.c
===================================================================
--- client/gui-win32/happiness.c        (revision 13910)
+++ client/gui-win32/happiness.c        (working copy)
@@ -289,25 +289,22 @@
 static void refresh_happiness_bitmap(HBITMAP bmp,
                                     struct city *pcity, int index)
 {
-  HDC hdc;
-  HBITMAP old;
+  struct citizen_type citizens[MAX_CITY_SIZE];
   RECT rc;
   int i;
-  struct citizen_type citizens[MAX_CITY_SIZE];
-  int num_citizens = pcity->size;
+  int num_citizens = get_city_citizen_types(pcity, index, citizens);
   int pix_width = HAPPINESS_PIX_WIDTH * tileset_small_sprite_width(tileset);
   int offset = MIN(tileset_small_sprite_width(tileset), pix_width / 
num_citizens);
   /* int true_pix_width = (num_citizens - 1) * offset + 
tileset_small_sprite_width(tileset); */
-  hdc=CreateCompatibleDC(NULL);
-  old=SelectObject(hdc,bmp);
+  HDC hdc = CreateCompatibleDC(NULL);
+  HBITMAP old=SelectObject(hdc,bmp);
+
   rc.left=0;
   rc.top=0;
   rc.right=pix_width;
   rc.bottom=tileset_small_sprite_height(tileset);
   FillRect(hdc,&rc,(HBRUSH)GetClassLong(root_window,GCL_HBRBACKGROUND));
 
-  get_city_citizen_types(pcity, index, citizens);
-
   for (i = 0; i < num_citizens; i++) {
     draw_sprite(get_citizen_sprite(tileset, citizens[i], i, pcity),
                hdc, i * offset, 0);
Index: client/packhand.c
===================================================================
--- client/packhand.c   (revision 13910)
+++ client/packhand.c   (working copy)
@@ -461,17 +461,31 @@
   pcity->tile = map_pos_to_tile(packet->x, packet->y);
   sz_strlcpy(pcity->name, packet->name);
   
-  pcity->size = packet->size;
-  for (i = 0; i < 5; i++) {
-    pcity->ppl_happy[i] = packet->ppl_happy[i];
-    pcity->ppl_content[i] = packet->ppl_content[i];
-    pcity->ppl_unhappy[i] = packet->ppl_unhappy[i];
-    pcity->ppl_angry[i] = packet->ppl_angry[i];
+  /* check data */
+  pcity->size = 0;
+  for (i = 0; i < FEELING_LAST; i++) {
+    pcity->feel[CITIZEN_HAPPY][i] = packet->ppl_happy[i];
+    pcity->feel[CITIZEN_CONTENT][i] = packet->ppl_content[i];
+    pcity->feel[CITIZEN_UNHAPPY][i] = packet->ppl_unhappy[i];
+    pcity->feel[CITIZEN_ANGRY][i] = packet->ppl_angry[i];
   }
+  for (i = 0; i < CITIZEN_LAST; i++) {
+    pcity->size += pcity->feel[i][FEELING_FINAL];
+  }
   specialist_type_iterate(sp) {
+    pcity->size +=
     pcity->specialists[sp] = packet->specialists[sp];
   } specialist_type_iterate_end;
 
+  if (pcity->size != packet->size) {
+    freelog(LOG_ERROR, "handle_city_info()"
+            " %d citizens not equal %d city size in \"%s\".",
+            pcity->size,
+            packet->size,
+            pcity->name);
+    pcity->size = packet->size;
+  }
+
   pcity->city_options = packet->city_options;
 
   for (i = 0; i < NUM_TRADEROUTES; i++) {
@@ -730,16 +744,16 @@
   pcity->client.happy = packet->happy;
   pcity->client.unhappy = packet->unhappy;
 
-  pcity->ppl_happy[4] = 0;
-  pcity->ppl_content[4] = 0;
-  pcity->ppl_unhappy[4] = 0;
-  pcity->ppl_angry[4] = 0;
+  pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] = 0;
+  pcity->feel[CITIZEN_CONTENT][FEELING_FINAL] = 0;
+  pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] = 0;
+  pcity->feel[CITIZEN_ANGRY][FEELING_FINAL] = 0;
   if (packet->happy) {
-    pcity->ppl_happy[4] = pcity->size;
+    pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] = pcity->size;
   } else if (packet->unhappy) {
-    pcity->ppl_unhappy[4] = pcity->size;
+    pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] = pcity->size;
   } else {
-    pcity->ppl_content[4] = pcity->size;
+    pcity->feel[CITIZEN_CONTENT][FEELING_FINAL] = pcity->size;
   }
 
   if (city_is_new) {
Index: client/gui-sdl/citydlg.c
===================================================================
--- client/gui-sdl/citydlg.c    (revision 13910)
+++ client/gui-sdl/citydlg.c    (working copy)
@@ -2051,8 +2051,8 @@
   FREESURFACE(pSurf);
   FREESTRING16(pStr);
 
-  count = (pCity->ppl_happy[4] + pCity->ppl_content[4]
-          + pCity->ppl_unhappy[4] + pCity->ppl_angry[4]
+  count = (pCity->feel[CITIZEN_HAPPY][FEELING_FINAL] + 
pCity->feel[CITIZEN_CONTENT][FEELING_FINAL]
+          + pCity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + 
pCity->feel[CITIZEN_ANGRY][FEELING_FINAL]
           + pCity->specialists[SP_ELVIS] + pCity->specialists[SP_SCIENTIST]
           + pCity->specialists[SP_TAXMAN]);
 
@@ -2062,11 +2062,11 @@
     step = pIcons->pMale_Happy->w;
   }
 
-  for (j = 0; j < 5; j++) {
-    if (j == 0 || pCity->ppl_happy[j - 1] != pCity->ppl_happy[j]
-       || pCity->ppl_content[j - 1] != pCity->ppl_content[j]
-       || pCity->ppl_unhappy[j - 1] != pCity->ppl_unhappy[j]
-       || pCity->ppl_angry[j - 1] != pCity->ppl_angry[j]) {
+  for (j = 0; j < FEELING_LAST; j++) {
+    if (j == 0 || pCity->feel[CITIZEN_HAPPY][j - 1] != 
pCity->feel[CITIZEN_HAPPY][j]
+       || pCity->feel[CITIZEN_CONTENT][j - 1] != 
pCity->feel[CITIZEN_CONTENT][j]
+       || pCity->feel[CITIZEN_UNHAPPY][j - 1] != 
pCity->feel[CITIZEN_UNHAPPY][j]
+       || pCity->feel[CITIZEN_ANGRY][j - 1] != pCity->feel[CITIZEN_ANGRY][j]) {
 
       if (j != 0) {
        putline(pCityWindow->dst->surface, dest.x, dest.y, dest.x + 
adj_size(176), dest.y,
@@ -2074,9 +2074,9 @@
        dest.y += adj_size(5);
       }
 
-      if (pCity->ppl_happy[j]) {
+      if (pCity->feel[CITIZEN_HAPPY][j]) {
        pSurf = pIcons->pMale_Happy;
-       for (i = 0; i < pCity->ppl_happy[j]; i++) {
+       for (i = 0; i < pCity->feel[CITIZEN_HAPPY][j]; i++) {
          alphablit(pSurf, NULL, pCityWindow->dst->surface, &dest);
          dest.x += step;
          if (pSurf == pIcons->pMale_Happy) {
@@ -2087,9 +2087,9 @@
        }
       }
 
-      if (pCity->ppl_content[j]) {
+      if (pCity->feel[CITIZEN_CONTENT][j]) {
        pSurf = pIcons->pMale_Content;
-       for (i = 0; i < pCity->ppl_content[j]; i++) {
+       for (i = 0; i < pCity->feel[CITIZEN_CONTENT][j]; i++) {
          alphablit(pSurf, NULL, pCityWindow->dst->surface, &dest);
          dest.x += step;
          if (pSurf == pIcons->pMale_Content) {
@@ -2100,9 +2100,9 @@
        }
       }
 
-      if (pCity->ppl_unhappy[j]) {
+      if (pCity->feel[CITIZEN_UNHAPPY][j]) {
        pSurf = pIcons->pMale_Unhappy;
-       for (i = 0; i < pCity->ppl_unhappy[j]; i++) {
+       for (i = 0; i < pCity->feel[CITIZEN_UNHAPPY][j]; i++) {
          alphablit(pSurf, NULL, pCityWindow->dst->surface, &dest);
          dest.x += step;
          if (pSurf == pIcons->pMale_Unhappy) {
@@ -2113,9 +2113,9 @@
        }
       }
 
-      if (pCity->ppl_angry[j]) {
+      if (pCity->feel[CITIZEN_ANGRY][j]) {
        pSurf = pIcons->pMale_Angry;
-       for (i = 0; i < pCity->ppl_angry[j]; i++) {
+       for (i = 0; i < pCity->feel[CITIZEN_ANGRY][j]; i++) {
          alphablit(pSurf, NULL, pCityWindow->dst->surface, &dest);
          dest.x += step;
          if (pSurf == pIcons->pMale_Angry) {
@@ -3340,8 +3340,8 @@
   /* count != 0 */
   /* ==================================================== */
   /* Draw Citizens */
-  count = (pCity->ppl_happy[4] + pCity->ppl_content[4]
-          + pCity->ppl_unhappy[4] + pCity->ppl_angry[4]
+  count = (pCity->feel[CITIZEN_HAPPY][FEELING_FINAL] + 
pCity->feel[CITIZEN_CONTENT][FEELING_FINAL]
+          + pCity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + 
pCity->feel[CITIZEN_ANGRY][FEELING_FINAL]
           + pCity->specialists[SP_ELVIS] + pCity->specialists[SP_SCIENTIST]
           + pCity->specialists[SP_TAXMAN]);
 
@@ -3358,8 +3358,8 @@
 
   FREESURFACE(pBuf);
   
-  if (pCity->ppl_happy[4]) {
-    for (i = 0; i < pCity->ppl_happy[4]; i++) {
+  if (pCity->feel[CITIZEN_HAPPY][FEELING_FINAL]) {
+    for (i = 0; i < pCity->feel[CITIZEN_HAPPY][FEELING_FINAL]; i++) {
       pBuf = adj_surf(get_citizen_surface(CITIZEN_HAPPY, i));
       
       alphablit(pBuf, NULL, pWindow->dst->surface, &dest);
@@ -3368,8 +3368,8 @@
     }
   }
 
-  if (pCity->ppl_content[4]) {
-    for (i = 0; i < pCity->ppl_content[4]; i++) {
+  if (pCity->feel[CITIZEN_CONTENT][FEELING_FINAL]) {
+    for (i = 0; i < pCity->feel[CITIZEN_CONTENT][FEELING_FINAL]; i++) {
       pBuf = adj_surf(get_citizen_surface(CITIZEN_CONTENT, i));
       
       alphablit(pBuf, NULL, pWindow->dst->surface, &dest);
@@ -3378,8 +3378,8 @@
     }
   }
 
-  if (pCity->ppl_unhappy[4]) {
-    for (i = 0; i < pCity->ppl_unhappy[4]; i++) {
+  if (pCity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]) {
+    for (i = 0; i < pCity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]; i++) {
       pBuf = adj_surf(get_citizen_surface(CITIZEN_UNHAPPY, i));
       
       alphablit(pBuf, NULL, pWindow->dst->surface, &dest);
@@ -3388,8 +3388,8 @@
     }
   }
 
-  if (pCity->ppl_angry[4]) {
-    for (i = 0; i < pCity->ppl_angry[4]; i++) {
+  if (pCity->feel[CITIZEN_ANGRY][FEELING_FINAL]) {
+    for (i = 0; i < pCity->feel[CITIZEN_ANGRY][FEELING_FINAL]; i++) {
       pBuf = adj_surf(get_citizen_surface(CITIZEN_ANGRY, i));
       alphablit(pBuf, NULL, pWindow->dst->surface, &dest);
       dest.x += step;
Index: client/gui-mui/citydlg.c
===================================================================
--- client/gui-mui/citydlg.c    (revision 13910)
+++ client/gui-mui/citydlg.c    (working copy)
@@ -1841,9 +1841,10 @@
 *****************************************************************/
 static void city_dialog_update_citizens(struct city_dialog *pdialog)
 {
+  struct citizen_type citizens[MAX_CITY_SIZE];
   int i;
   struct city *pcity = pdialog->pcity;
-  struct citizen_type citizens[MAX_CITY_SIZE];
+  int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, citizens);
 
   DoMethod(pdialog->citizen_group, MUIM_Group_InitChange);
   if (pdialog->citizen2_group)
@@ -1855,9 +1856,7 @@
   pdialog->citizen2_group = HGroup, GroupSpacing(0), End;
 
   /* Get a list of the citizens. */
-  get_city_citizen_types(pcity, 4, citizens);
-
-  for (i = 0; i < pcity->size; i++) {
+  for (i = 0; i < num_citizens; i++) {
     Object *o = MakeSprite(get_citizen_sprite(tileset, citizens[i], i, pcity));
 
     if (o) {
@@ -2258,15 +2257,13 @@
   /* the citizen's */
   for(i=0;i<5;i++)
   {
-    int j;
-    int num_citizens = pcity->size;
     struct citizen_type citizens[MAX_CITY_SIZE];
+    int j;
+    int num_citizens = get_city_citizen_types(pcity, i, citizens);;
 
     DoMethod(pdialog->happiness_citizen_group[i],MUIM_Group_InitChange);
     DisposeAllChilds(pdialog->happiness_citizen_group[i]);
 
-    get_city_citizen_types(pcity, i, citizens);
-
     for (j = 0; j < num_citizens; j++) {
       Object *obj;
 
Index: client/tilespec.c
===================================================================
--- client/tilespec.c   (revision 13910)
+++ client/tilespec.c   (working copy)
@@ -1646,13 +1646,11 @@
 /**********************************************************************
   Returns a text name for the citizen, as used in the tileset.
 ***********************************************************************/
-static const char *get_citizen_name(struct citizen_type citizen)
+static const char *get_citizen_name(enum citizen_category citizen)
 {
   /* These strings are used in reading the tileset.  Do not
    * translate. */
-  switch (citizen.type) {
-  case CITIZEN_SPECIALIST:
-    return get_specialist(citizen.spec_type)->name;
+  switch (citizen) {
   case CITIZEN_HAPPY:
     return "happy";
   case CITIZEN_CONTENT:
@@ -1661,10 +1659,10 @@
     return "unhappy";
   case CITIZEN_ANGRY:
     return "angry";
-  case CITIZEN_LAST:
+  default:
     break;
   }
-  die("unknown citizen type %d", (int) citizen.type);
+  die("unknown citizen type %d", (int) citizen);
   return NULL;
 }
 
@@ -1855,12 +1853,11 @@
 void tileset_setup_specialist_type(struct tileset *t, Specialist_type_id id)
 {
   /* Load the specialist sprite graphics. */
-  struct citizen_type c = {.type = CITIZEN_SPECIALIST, .spec_type = id};
-  const char *name = get_citizen_name(c);
   char buffer[512];
   int j;
+  const char *name = get_specialist(id)->name;
 
-  for (j = 0; j < NUM_TILES_CITIZEN; j++) {
+  for (j = 0; j < MAX_NUM_CITIZEN_SPRITES; j++) {
     my_snprintf(buffer, sizeof(buffer), "specialist.%s_%d", name, j);
     t->sprites.specialist[id].sprite[j] = load_sprite(t, buffer);
     if (!t->sprites.specialist[id].sprite[j]) {
@@ -1882,16 +1879,11 @@
   int i, j;
   char buffer[512];
 
-  /* Load the citizen sprite graphics. */
-  for (i = 0; i < NUM_TILES_CITIZEN; i++) {
-    struct citizen_type c = {.type = i};
-    const char *name = get_citizen_name(c);
+  /* Load the citizen sprite graphics, no specialist. */
+  for (i = 0; i < CITIZEN_LAST; i++) {
+    const char *name = get_citizen_name(i);
 
-    if (i == CITIZEN_SPECIALIST) {
-      continue; /* Handled separately. */
-    }
-
-    for (j = 0; j < NUM_TILES_CITIZEN; j++) {
+    for (j = 0; j < MAX_NUM_CITIZEN_SPRITES; j++) {
       my_snprintf(buffer, sizeof(buffer), "citizen.%s_%d", name, j);
       t->sprites.citizen[i].sprite[j] = load_sprite(t, buffer);
       if (!t->sprites.citizen[i].sprite[j]) {
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to