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

William Allen Simpson wrote:
> Anyway, this shows my solution is on the right track.  The tile will
> point to the dummy for owner information; they will always be the same.
> 
Sadly, unless I'm able to think of some other method in the future, my
solution requires a packet change.  Oh well, it will have to be 2.2.*
only.  In the meantime, I've checked in the intermediate step that
directly fixes the bug as reported.  The destroyed city is no longer in
the player's city list.

Committed S2_1 revision 13919.
Committed S2_2 revision 13920.
Committed trunk revision 13921.

Awaiting verification before closing....

Final S2_2 changes for posterity (a bit different from S2_1, same as trunk):


Index: server/citytools.c
===================================================================
--- server/citytools.c  (revision 13919)
+++ server/citytools.c  (working copy)
@@ -483,7 +483,7 @@
     return 0;
   }
 
-  if (get_unittype_bonus(pcity->owner, pcity->tile, punittype,
+  if (get_unittype_bonus(city_owner(pcity), pcity->tile, punittype,
                         EFT_VETERAN_BUILD) > 0) {
     return 1;
   }
@@ -1380,22 +1380,17 @@
 }
 
 /**************************************************************************
-This fills out a package from a players dumb_city.
+  This fills out a package from a player's vision_base.
 **************************************************************************/
 static void package_dumb_city(struct player* pplayer, struct tile *ptile,
                              struct packet_city_short_info *packet)
 {
-  struct player_tile *pdtile = map_get_player_tile(ptile, pplayer);
-  struct dumb_city *pdcity = pdtile->city;
+  struct vision_base *pdcity = map_get_player_base(ptile, pplayer);
   struct city *pcity = tile_get_city(ptile);
 
-  packet->id = pdcity->id;
-  if (ptile->owner) {
-    /* Use tile owner information not city owner information. */
-    packet->owner = player_number(ptile->owner);
-  } else {
-    packet->owner = player_number(pdcity->owner);
-  }
+  packet->id = pdcity->identity;
+  packet->owner = player_number(vision_owner(pdcity));
+
   packet->x = ptile->x;
   packet->y = ptile->y;
   sz_strlcpy(packet->name, pdcity->name);
@@ -1452,14 +1447,14 @@
 **************************************************************************/
 static void broadcast_city_info(struct city *pcity)
 {
-  struct player *powner = city_owner(pcity);
   struct packet_city_info packet;
   struct packet_city_short_info sc_pack;
+  struct player *powner = city_owner(pcity);
 
   /* Send to everyone who can see the city. */
   players_iterate(pplayer) {
     if (can_player_see_city_internals(pplayer, pcity)) {
-      if (!nocity_send || pplayer != city_owner(pcity)) {
+      if (!nocity_send || pplayer != powner) {
        update_dumb_city(powner, pcity);
        package_city(pcity, &packet, FALSE);
        lsend_packet_city_info(powner->connections, &packet);
@@ -1499,7 +1494,7 @@
       continue;
     }
     whole_map_iterate(ptile) {
-      if (!pplayer || map_get_player_tile(ptile, pplayer)->city) {
+      if (!pplayer || NULL != map_get_player_city(ptile, pplayer)) {
        send_city_info_at_tile(pplayer, pconn->self, NULL, ptile);
       }
     } whole_map_iterate_end;
@@ -1569,16 +1564,16 @@
 void send_city_info_at_tile(struct player *pviewer, struct conn_list *dest,
                            struct city *pcity, struct tile *ptile)
 {
-  struct player *powner = NULL;
   struct packet_city_info packet;
   struct packet_city_short_info sc_pack;
-  struct dumb_city *pdcity;
+  struct player *powner = NULL;
 
-  if (!pcity)
+  if (!pcity) {
     pcity = tile_get_city(ptile);
-  if (pcity)
+  }
+  if (pcity) {
     powner = city_owner(pcity);
-
+  }
   if (powner && powner == pviewer) {
     /* send info to owner */
     /* This case implies powner non-NULL which means pcity non-NULL */
@@ -1590,8 +1585,7 @@
       package_city(pcity, &packet, FALSE);
       lsend_packet_city_info(dest, &packet);
     }
-  }
-  else {
+  } else {
     /* send info to non-owner */
     if (!pviewer) {    /* observer */
       if (pcity) {
@@ -1610,8 +1604,7 @@
          lsend_packet_city_short_info(dest, &sc_pack);
        }
       } else {                 /* not seen; send old info */
-       pdcity = map_get_player_tile(ptile, pviewer)->city;
-       if (pdcity) {
+       if (NULL != map_get_player_base(ptile, pviewer)) {
          package_dumb_city(pviewer, ptile, &sc_pack);
          lsend_packet_city_short_info(dest, &sc_pack);
        }
@@ -1629,7 +1622,7 @@
   int x, y, i;
 
   packet->id=pcity->id;
-  packet->owner = player_number(pcity->owner);
+  packet->owner = player_number(city_owner(pcity));
   packet->x = pcity->tile->x;
   packet->y = pcity->tile->y;
   sz_strlcpy(packet->name, pcity->name);
@@ -1715,16 +1708,15 @@
 **************************************************************************/
 bool update_dumb_city(struct player *pplayer, struct city *pcity)
 {
-  struct player_tile *plrtile = map_get_player_tile(pcity->tile,
-                                                   pplayer);
-  struct dumb_city *pdcity = plrtile->city;
+  bv_imprs improvements;
+  struct player_tile *plrtile = map_get_player_tile(pcity->tile, pplayer);
+  struct vision_base *pdcity = plrtile->vision_source;
   /* pcity->occupied isn't used at the server, so we go straight to the
    * unit list to check the occupied status. */
-  bool occupied =
-    (unit_list_size(pcity->tile->units) > 0);
+  bool occupied = (unit_list_size(pcity->tile->units) > 0);
   bool walls = city_got_citywalls(pcity);
-  bool happy = city_happy(pcity), unhappy = city_unhappy(pcity);
-  bv_imprs improvements;
+  bool happy = city_happy(pcity);
+  bool unhappy = city_unhappy(pcity);
 
   BV_CLR_ALL(improvements);
   improvement_iterate(pimprove) {
@@ -1735,27 +1727,27 @@
   } improvement_iterate_end;
 
   if (pdcity
-      && pdcity->id == pcity->id
+      && pdcity->identity == pcity->id
       && strcmp(pdcity->name, pcity->name) == 0
       && pdcity->size == pcity->size
       && pdcity->occupied == occupied
       && pdcity->walls == walls
       && pdcity->happy == happy
       && pdcity->unhappy == unhappy
-      && pdcity->owner == pcity->owner
+      && pdcity->owner == city_owner(pcity)
       && BV_ARE_EQUAL(pdcity->improvements, improvements)) {
     return FALSE;
   }
 
-  if (!plrtile->city) {
-    pdcity = plrtile->city = fc_malloc(sizeof(*pdcity));
-    plrtile->city->id = pcity->id;
+  if (NULL == pdcity) {
+    pdcity = plrtile->vision_source = fc_calloc(1, sizeof(*pdcity));
+    pdcity->identity = pcity->id;
   }
-  if (pdcity->id != pcity->id) {
+  if (pdcity->identity != pcity->id) {
     freelog(LOG_ERROR, "Trying to update old city (wrong ID)"
            " at %i,%i for player %s",
            pcity->tile->x, pcity->tile->y, pplayer->name);
-    pdcity->id = pcity->id;   /* ?? */
+    pdcity->identity = pcity->id;   /* ?? */
   }
   sz_strlcpy(pdcity->name, pcity->name);
   pdcity->size = pcity->size;
@@ -1763,7 +1755,8 @@
   pdcity->walls = walls;
   pdcity->happy = happy;
   pdcity->unhappy = unhappy;
-  pdcity->owner = pcity->owner;
+  pdcity->owner = city_owner(pcity);
+  pdcity->location = pcity->tile;
   pdcity->improvements = improvements;
 
   return TRUE;
@@ -1774,15 +1767,15 @@
 **************************************************************************/
 void reality_check_city(struct player *pplayer,struct tile *ptile)
 {
-  struct city *pcity;
-  struct dumb_city *pdcity = map_get_player_tile(ptile, pplayer)->city;
+  struct city *pcity = tile_get_city(ptile);
+  struct player_tile *playtile = map_get_player_tile(ptile, pplayer);
+  struct vision_base *pdcity = playtile->vision_source;
 
   if (pdcity) {
-    pcity = ptile->city;
-    if (!pcity || (pcity && pcity->id != pdcity->id)) {
-      dlsend_packet_city_remove(pplayer->connections, pdcity->id);
+    if (!pcity || pcity->id != pdcity->identity) {
+      dlsend_packet_city_remove(pplayer->connections, pdcity->identity);
+      playtile->vision_source = NULL;
       free(pdcity);
-      map_get_player_tile(ptile, pplayer)->city = NULL;
     }
   }
 }
@@ -1990,7 +1983,7 @@
     return FALSE;
   }
 
-  if (ptile->owner && ptile->owner != pcity->owner) {
+  if (tile_owner(ptile) && tile_owner(ptile) != city_owner(pcity)) {
     return FALSE;
   }
 
Index: server/maphand.c
===================================================================
--- server/maphand.c    (revision 13919)
+++ server/maphand.c    (working copy)
@@ -605,7 +605,7 @@
 
   info.x = ptile->x;
   info.y = ptile->y;
-  info.owner = ptile->owner ? player_number(ptile->owner) : 
MAP_TILE_OWNER_NULL;
+  info.owner = tile_owner(ptile) ? player_number(tile_owner(ptile)) : 
MAP_TILE_OWNER_NULL;
   if (ptile->spec_sprite) {
     sz_strlcpy(info.spec_sprite, ptile->spec_sprite);
   } else {
@@ -1101,8 +1101,8 @@
   whole_map_iterate(ptile) {
     struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
 
-    if (plrtile->city) {
-      free(plrtile->city);
+    if (plrtile->vision_source) {
+      free(plrtile->vision_source);
     }
   } whole_map_iterate_end;
 
@@ -1111,18 +1111,17 @@
 }
 
 /***************************************************************
-We need to use use fogofwar_old here, so the player's tiles get
-in the same state as the other players' tiles.
+  We need to use fogofwar_old here, so the player's tiles get
+  in the same state as the other players' tiles.
 ***************************************************************/
 static void player_tile_init(struct tile *ptile, struct player *pplayer)
 {
-  struct player_tile *plrtile =
-    map_get_player_tile(ptile, pplayer);
+  struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
 
   plrtile->terrain = T_UNKNOWN;
   clear_all_specials(&plrtile->special);
   plrtile->resource = NULL;
-  plrtile->city = NULL;
+  plrtile->vision_source = NULL;
 
   vision_layer_iterate(v) {
     plrtile->seen_count[v] = 0;
@@ -1142,6 +1141,30 @@
 }
 
 /****************************************************************************
+  ...
+****************************************************************************/
+struct vision_base *map_get_player_base(const struct tile *ptile,
+                                       const struct player *pplayer)
+{
+  return map_get_player_tile(ptile, pplayer)->vision_source;
+}
+
+/****************************************************************************
+  ...
+****************************************************************************/
+struct vision_base *map_get_player_city(const struct tile *ptile,
+                                       const struct player *pplayer)
+{
+  struct player_tile *playtile = map_get_player_tile(ptile, pplayer);
+  struct vision_base *vision_source = playtile->vision_source;
+
+  if (vision_source && ptile == vision_source->location) {
+    return vision_source;
+  }
+  return NULL;
+}
+
+/****************************************************************************
   Players' information of tiles is tracked so that fogged area can be kept
   consistent even when the client disconnects.  This function returns the
   player tile information for the given tile and player.
@@ -1245,23 +1268,25 @@
        
       /* update and send city knowledge */
       /* remove outdated cities */
-      if (dest_tile->city) {
-       if (!from_tile->city) {
+      if (dest_tile->vision_source) {
+       if (!from_tile->vision_source) {
          /* As the city was gone on the newer from_tile
             it will be removed by this function */
          reality_check_city(pdest, ptile);
        } else /* We have a dest_city. update */
-         if (from_tile->city->id != dest_tile->city->id)
+         if (from_tile->vision_source->identity
+          != dest_tile->vision_source->identity)
            /* As the city was gone on the newer from_tile
               it will be removed by this function */
            reality_check_city(pdest, ptile);
       }
       /* Set and send new city info */
-      if (from_tile->city) {
-       if (!dest_tile->city) {
-         dest_tile->city = fc_malloc(sizeof(*dest_tile->city));
+      if (from_tile->vision_source) {
+       if (!dest_tile->vision_source) {
+         dest_tile->vision_source = fc_calloc(1, 
sizeof(*dest_tile->vision_source));
        }
-       *dest_tile->city = *from_tile->city;
+       /* struct assignment copy */
+       *dest_tile->vision_source = *from_tile->vision_source;
        send_city_info_at_tile(pdest, pdest->connections, NULL, ptile);
       }
 
@@ -1720,9 +1745,9 @@
 
   /* First transfer ownership for sources that have changed hands. */
   whole_map_iterate(ptile) {
-    if (ptile->owner 
+    if (tile_owner(ptile) 
         && ptile->owner_source
-        && ptile->owner_source->owner != ptile->owner
+        && ptile->owner_source->owner != tile_owner(ptile)
         && (ptile->owner_source->city
             || tile_has_base_flag(ptile->owner_source,
                                   BF_CLAIM_TERRITORY))) {
@@ -1735,8 +1760,8 @@
   /* Second transfer ownership to city closer than current source 
    * but with the same owner. */
   whole_map_iterate(ptile) {
-    if (ptile->owner) {
-      city_list_iterate(ptile->owner->cities, pcity) {
+    if (tile_owner(ptile)) {
+      city_list_iterate(tile_owner(ptile)->cities, pcity) {
         int r_curr, r_city = sq_map_distance(ptile, pcity->tile);
         int max_range = tile_border_range(pcity->tile);
 
@@ -1750,7 +1775,7 @@
         /* Transfer tile to city if closer than current source */
         if (r_curr > r_city && max_range >= r_city) {
           freelog(LOG_DEBUG, "%s's %s(%d,%d) acquired tile (%d,%d) from "
-                  "(%d,%d)", ptile->owner->name, pcity->name, pcity->tile->x, 
+                  "(%d,%d)", tile_owner(ptile)->name, pcity->name, 
pcity->tile->x, 
                   pcity->tile->y, ptile->x, ptile->y, ptile->owner_source->x, 
                   ptile->owner_source->y);
           ptile->owner_source = pcity->tile;
@@ -1761,10 +1786,10 @@
 
   /* Third remove undue ownership. */
   whole_map_iterate(ptile) {
-    if (ptile->owner
+    if (tile_owner(ptile)
         && (!ptile->owner_source
-            || !ptile->owner->is_alive
-            || ptile->owner != ptile->owner_source->owner
+            || !tile_owner(ptile)->is_alive
+            || tile_owner(ptile) != ptile->owner_source->owner
             || (!ptile->owner_source->city
                 && !tile_has_base_flag(ptile->owner_source,
                                        BF_CLAIM_TERRITORY)))) {
@@ -1777,7 +1802,7 @@
    * grab one circle each turn as long as we have range left
    * to better visually display expansion. */
   whole_map_iterate(ptile) {
-    if (ptile->owner
+    if (tile_owner(ptile)
         && (ptile->city
             || tile_has_base_flag(ptile, BF_CLAIM_TERRITORY))) {
       /* We have an ownership source */
@@ -1792,7 +1817,7 @@
       circle_dxyr_iterate(ptile, range, atile, dx, dy, dist) {
         if (expand_range > dist) {
           unit_list_iterate(atile->units, punit) {
-            if (!pplayers_allied(unit_owner(punit), ptile->owner)) {
+            if (!pplayers_allied(unit_owner(punit), tile_owner(ptile))) {
               /* We cannot expand borders further when enemy units are
                * standing in the way. */
               expand_range = dist - 1;
@@ -1800,8 +1825,8 @@
           } unit_list_iterate_end;
         }
         if (found_unclaimed > dist
-            && atile->owner == NULL
-            && map_is_known(atile, ptile->owner)
+            && tile_owner(atile) == NULL
+            && map_is_known(atile, tile_owner(ptile))
             && (!is_ocean(atile->terrain)
                 || is_claimable_ocean(atile, ptile))) {
           found_unclaimed = dist;
@@ -1814,13 +1839,13 @@
         if (dist > expand_range || dist > found_unclaimed) {
           continue; /* only expand one extra circle radius each turn */
         }
-        if (map_is_known(atile, ptile->owner)
-            && atile->owner == NULL
+        if (map_is_known(atile, tile_owner(ptile))
+            && tile_owner(atile) == NULL
             && ((!is_ocean(atile->terrain) 
                  && atile->continent == ptile->continent)
                 || (is_ocean(atile->terrain)
                     && is_claimable_ocean(atile, ptile)))) {
-          map_claim_ownership(atile, ptile->owner, ptile);
+          map_claim_ownership(atile, tile_owner(ptile), ptile);
           atile->owner_source = ptile;
           if (game.info.happyborders > 0) {
             add_unique_homecities(cities_to_refresh, atile);
Index: server/maphand.h
===================================================================
--- server/maphand.h    (revision 13919)
+++ server/maphand.h    (working copy)
@@ -25,31 +25,38 @@
 struct section_file;
 struct conn_list;
 
-struct dumb_city{
-  /* Values in this struct are copied using a memcpy, so don't put any
-   * pointers in here. */
-  int id;
+/* This is copied in really_give_tile_info_from_player_to_player(),
+ * so be careful with pointers!
+ */
+#define VISION_BASE_RUIN (0)
+
+struct vision_base {
+  struct tile *location;               /* Cannot be NULL */
+  struct player *owner;                        /* May be NULL, always check! */
+
+  int identity;                                /* city/unit >= 100 */
   bool occupied;
   bool walls;
   bool happy, unhappy;
-  char name[MAX_LEN_NAME];
   unsigned short size;
-  struct player *owner; /* City owner - cannot be NULL. */
 
   bv_imprs improvements;
+  char name[MAX_LEN_NAME];
 };
 
+
 struct player_tile {
-  struct terrain *terrain; /* May be NULL for unknown tiles. */
+  struct vision_base *vision_source;   /* NULL for no base */
+  struct resource *resource;           /* NULL for no resource */
+  struct terrain *terrain;             /* NULL for unknown tiles */
   bv_special special;
-  struct resource *resource;
-  unsigned short seen_count[V_COUNT];
-  unsigned short own_seen[V_COUNT];
+
   /* If you build a city with an unknown square within city radius
      the square stays unknown. However, we still have to keep count
      of the seen points, so they are kept in here. When the tile
      then becomes known they are moved to seen. */
-  struct dumb_city* city;
+  unsigned short own_seen[V_COUNT];
+  unsigned short seen_count[V_COUNT];
   short last_updated;
 };
 
@@ -85,6 +92,13 @@
 
 void player_map_allocate(struct player *pplayer);
 void player_map_free(struct player *pplayer);
+
+#define tile_owner(v) (v)->owner
+#define vision_owner(v) (v)->owner
+struct vision_base *map_get_player_base(const struct tile *ptile,
+                                       const struct player *pplayer);
+struct vision_base *map_get_player_city(const struct tile *ptile,
+                                       const struct player *pplayer);
 struct player_tile *map_get_player_tile(const struct tile *ptile,
                                        const struct player *pplayer);
 bool update_player_tile_knowledge(struct player *pplayer,struct tile *ptile);
@@ -140,7 +154,7 @@
   visible.  For instance to move a unit:
 
     old_vision = punit->server.vision;
-    punit->server.vision = vision_new(punit->owner, dest_tile);
+    punit->server.vision = vision_new(unit_owner(punit), dest_tile);
     vision_change_sight(punit->server.vision,
                         get_unit_vision_at(punit, dest_tile));
 
Index: server/unittools.c
===================================================================
--- server/unittools.c  (revision 13919)
+++ server/unittools.c  (working copy)
@@ -150,7 +150,7 @@
       || unit_has_type_flag(punit, F_NO_VETERAN)) {
     return FALSE;
   } else {
-    int mod = 100 + get_unittype_bonus(punit->owner, punit->tile,
+    int mod = 100 + get_unittype_bonus(unit_owner(punit), punit->tile,
                                       unit_type(punit), EFT_VETERAN_COMBAT);
 
     /* The modification is tacked on as a multiplier to the base chance.
@@ -709,7 +709,7 @@
       } unit_list_iterate_end;
       update_tile_knowledge(ptile);
       
-      ai_incident_pillage(unit_owner(punit), ptile->owner);
+      ai_incident_pillage(unit_owner(punit), tile_owner(ptile));
       
       /* Change vision if effects have changed. */
       unit_list_refresh_vision(ptile->units);
@@ -951,13 +951,13 @@
     if (is_ocean(ptile->terrain)) {
       continue;
     }
-    if (ptile->city)
+    if (tile_get_city(ptile))
       continue;
     if (unit_list_size(ptile->units) > 0)
       continue;
 
     /* City has not changed hands yet; see place_partisans(). */
-    value = get_virtual_defense_power(NULL, u_type, pcity->owner,
+    value = get_virtual_defense_power(NULL, u_type, city_owner(pcity),
                                      ptile, FALSE, 0);
     value *= 10;
 
@@ -1009,7 +1009,7 @@
   int partisans;
 
   if (num_role_units(L_PARTISAN) <= 0
-      || pcity->original != pcity->owner
+      || pcity->original != city_owner(pcity)
       || get_city_bonus(pcity, EFT_INSPIRE_PARTISANS) <= 0) {
     return;
   }
@@ -1032,7 +1032,7 @@
 {
   int a = 0, d, db;
   struct player *pplayer = unit_owner(punit);
-  struct city *pcity = ptile->city;
+  struct city *pcity = tile_get_city(ptile);
 
   if (pcity && pplayers_allied(city_owner(pcity), unit_owner(punit))
       && !is_non_allied_unit_tile(ptile, pplayer)) {
@@ -1078,7 +1078,7 @@
 {
   struct tile *src_tile = punit->tile, *dst_tile = pcity->tile;
 
-  if (pcity->owner == punit->owner){
+  if (city_owner(pcity) == unit_owner(punit)){
     freelog(LOG_VERBOSE, "Teleported %s's %s from (%d, %d) to %s",
            unit_owner(punit)->name,
            unit_rule_name(punit),
@@ -1134,8 +1134,9 @@
 {
   unit_list_iterate_safe(pplayer->units, punit) {
     struct tile *ptile = punit->tile;
+    struct city *pcity = tile_get_city(ptile);
 
-    if (ptile->city && !pplayers_allied(city_owner(ptile->city), pplayer)) {
+    if (NULL != pcity && !pplayers_allied(city_owner(pcity), pplayer)) {
       bounce_unit(punit, verbose);
     }
   } unit_list_iterate_safe_end;    
@@ -1612,59 +1613,59 @@
 **************************************************************************/
 void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
 {
-  struct player *pplayer   = unit_owner(punit);
-  struct player *destroyer = unit_owner(pkiller);
-  const char *loc_str = get_location_str_in(pplayer, punit->tile);
+  struct player *pvictim = unit_owner(punit);
+  struct player *pvictor = unit_owner(pkiller);
+  const char *loc_str = get_location_str_in(pvictim, punit->tile);
   int ransom, unitcount = 0;
   
   /* barbarian leader ransom hack */
-  if( is_barbarian(pplayer) && unit_has_type_role(punit, L_BARBARIAN_LEADER)
+  if( is_barbarian(pvictim) && unit_has_type_role(punit, L_BARBARIAN_LEADER)
       && (unit_list_size(punit->tile->units) == 1)
       && uclass_has_flag(unit_class(pkiller), UCF_COLLECT_RANSOM)) {
     /* Occupying units can collect ransom if leader is alone in the tile */
-    ransom = (pplayer->economic.gold >= game.info.ransom_gold) 
-             ? game.info.ransom_gold : pplayer->economic.gold;
-    notify_player(destroyer, pkiller->tile, E_UNIT_WIN_ATT,
+    ransom = (pvictim->economic.gold >= game.info.ransom_gold) 
+             ? game.info.ransom_gold : pvictim->economic.gold;
+    notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
                     _("Barbarian leader captured, %d gold ransom paid."),
                      ransom);
-    destroyer->economic.gold += ransom;
-    pplayer->economic.gold -= ransom;
-    send_player_info(destroyer, NULL);   /* let me see my new gold :-) */
+    pvictor->economic.gold += ransom;
+    pvictim->economic.gold -= ransom;
+    send_player_info(pvictor, NULL);   /* let me see my new gold :-) */
     unitcount = 1;
   }
 
   if (unitcount == 0) {
     unit_list_iterate(punit->tile->units, vunit)
-      if (pplayers_at_war(unit_owner(pkiller), unit_owner(vunit)))
+      if (pplayers_at_war(pvictor, unit_owner(vunit)))
        unitcount++;
     unit_list_iterate_end;
   }
 
   if (!is_stack_vulnerable(punit->tile) || unitcount == 1) {
     if (vet) {
-      notify_player(unit_owner(pkiller), pkiller->tile, E_UNIT_WIN_ATT,
+      notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
                    _("Your attacking %s succeeded"
                      " against %s's %s%s and became more experienced!"),
                    unit_name_translation(pkiller),
-                   unit_owner(punit)->name,
+                   pvictim->name,
                    unit_name_translation(punit),
-                   get_location_str_at(unit_owner(pkiller),
+                   get_location_str_at(pvictor,
                                        punit->tile));
     } else {
-      notify_player(unit_owner(pkiller), pkiller->tile, E_UNIT_WIN_ATT,
+      notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
                    _("Your attacking %s succeeded against %s's %s%s!"),
                    unit_name_translation(pkiller),
-                   unit_owner(punit)->name,
+                   pvictim->name,
                    unit_name_translation(punit),
-                   get_location_str_at(unit_owner(pkiller),
+                   get_location_str_at(pvictor,
                                        punit->tile));
     }
-    notify_player(pplayer, punit->tile, E_UNIT_LOST,
-                    _("%s lost to an attack by %s's %s%s."),
-                    unit_name_translation(punit),
-                    destroyer->name,
-                    unit_name_translation(pkiller),
-                    loc_str);
+    notify_player(pvictim, punit->tile, E_UNIT_LOST,
+                 _("%s lost to an attack by %s's %s%s."),
+                 unit_name_translation(punit),
+                 pvictor->name,
+                 unit_name_translation(pkiller),
+                 loc_str);
 
     wipe_unit(punit);
   } else { /* unitcount > 1 */
@@ -1682,40 +1683,41 @@
 
     /* count killed units */
     unit_list_iterate(punit->tile->units, vunit) {
-      if (pplayers_at_war(unit_owner(pkiller), unit_owner(vunit))) {
-       num_killed[player_index(vunit->owner)]++;
+      struct player *vplayer = unit_owner(vunit);
+      if (pplayers_at_war(pvictor, vplayer)) {
+       num_killed[player_index(vplayer)]++;
        if (vunit != punit) {
-         other_killed[player_index(vunit->owner)] = vunit;
-         other_killed[player_index(destroyer)] = vunit;
+         other_killed[player_index(vplayer)] = vunit;
+         other_killed[player_index(pvictor)] = vunit;
        }
       }
     } unit_list_iterate_end;
 
     /* Inform the destroyer: lots of different cases here! */
     if (vet) {
-      notify_player(unit_owner(pkiller), pkiller->tile, E_UNIT_WIN_ATT,
+      notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
                    PL_("Your attacking %s succeeded against %s's %s "
                        "(and %d other unit)%s and became more experienced!",
                        "Your attacking %s succeeded against %s's %s "
                        "(and %d other units)%s and became more experienced!",
                        unitcount - 1),
                    unit_name_translation(pkiller),
-                   unit_owner(punit)->name,
+                   pvictim->name,
                    unit_name_translation(punit),
                    unitcount - 1,
-                   get_location_str_at(unit_owner(pkiller),
+                   get_location_str_at(pvictor,
                                        punit->tile));
     } else {
-      notify_player(unit_owner(pkiller), pkiller->tile, E_UNIT_WIN_ATT,
+      notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
                    PL_("Your attacking %s succeeded against %s's %s "
                        "(and %d other unit)%s!",
                        "Your attacking %s succeeded against %s's %s "
                        "(and %d other units)%s!", unitcount - 1),
                    unit_name_translation(pkiller),
-                   unit_owner(punit)->name,
+                   pvictim->name,
                    unit_name_translation(punit),
                    unitcount - 1,
-                   get_location_str_at(unit_owner(pkiller),
+                   get_location_str_at(pvictor,
                                        punit->tile));
     }
 
@@ -1727,14 +1729,14 @@
      * they all are. */
     for (i = 0; i<MAX_NUM_PLAYERS+MAX_NUM_BARBARIANS; i++) {
       if (num_killed[i] == 1) {
-       if (i == player_index(punit->owner)) {
+       if (i == player_index(pvictim)) {
          assert(other_killed[i] == NULL);
          notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
                        /* TRANS: "Cannon lost to an attack from John's
                         * Destroyer." */
                        _("%s lost to an attack from %s's %s."),
                        unit_name_translation(punit),
-                       destroyer->name,
+                       pvictor->name,
                        unit_name_translation(pkiller));
        } else {
          assert(other_killed[i] != punit);
@@ -1743,13 +1745,13 @@
                         * attacked Mark's Musketeers." */
                        _("%s lost when %s's %s attacked %s's %s."),
                        unit_name_translation(other_killed[i]),
-                       destroyer->name,
+                       pvictor->name,
                        unit_name_translation(pkiller),
-                       punit->owner->name,
+                       pvictim->name,
                        unit_name_translation(punit));
        }
       } else if (num_killed[i] > 1) {
-       if (i == player_index(punit->owner)) {
+       if (i == player_index(pvictim)) {
          int others = num_killed[i] - 1;
 
          if (others == 1) {
@@ -1759,7 +1761,7 @@
                          _("%s (and %s) lost to an attack from %s's %s."),
                          unit_name_translation(punit),
                          unit_name_translation(other_killed[i]),
-                         destroyer->name,
+                         pvictor->name,
                          unit_name_translation(pkiller));
          } else {
            notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
@@ -1772,7 +1774,7 @@
                              "from %s's %s.", others),
                          unit_name_translation(punit),
                          others,
-                         destroyer->name,
+                         pvictor->name,
                          unit_name_translation(pkiller));
          }
        } else {
@@ -1784,9 +1786,9 @@
                            "%d units lost when %s's %s attacked %s's %s.",
                            num_killed[i]),
                        num_killed[i],
-                       destroyer->name,
+                       pvictor->name,
                        unit_name_translation(pkiller),
-                       punit->owner->name,
+                       pvictim->name,
                        unit_name_translation(punit));
        }
       }
@@ -1794,7 +1796,7 @@
 
     /* remove the units */
     unit_list_iterate_safe(punit->tile->units, punit2) {
-      if (pplayers_at_war(unit_owner(pkiller), unit_owner(punit2))) {
+      if (pplayers_at_war(pvictor, unit_owner(punit2))) {
        wipe_unit(punit2);
       }
     } unit_list_iterate_safe_end;
@@ -1808,7 +1810,7 @@
 void package_unit(struct unit *punit, struct packet_unit_info *packet)
 {
   packet->id = punit->id;
-  packet->owner = player_number(punit->owner);
+  packet->owner = player_number(unit_owner(punit));
   packet->x = punit->tile->x;
   packet->y = punit->tile->y;
   packet->homecity = punit->homecity;
@@ -1887,7 +1889,7 @@
   packet->info_city_id = info_city_id;
 
   packet->id = punit->id;
-  packet->owner = player_number(punit->owner);
+  packet->owner = player_number(unit_owner(punit));
   packet->x = punit->tile->x;
   packet->y = punit->tile->y;
   packet->veteran = punit->veteran;
@@ -1961,7 +1963,7 @@
     struct player *pplayer = pconn->player;
 
     /* Be careful to consider all cases where pplayer is NULL... */
-    if ((!pplayer && pconn->observer) || pplayer == punit->owner) {
+    if ((!pplayer && pconn->observer) || pplayer == unit_owner(punit)) {
       send_packet_unit_info(pconn, &info);
     } else if (pplayer) {
       bool see_in_old;
@@ -2092,10 +2094,10 @@
 **************************************************************************/
 void do_nuclear_explosion(struct player *pplayer, struct tile *ptile)
 {
-  if (ptile->owner) {
-    ai_incident_nuclear(pplayer, ptile->owner);
-  } else if (ptile->city) {
-    ai_incident_nuclear(pplayer, city_owner(ptile->city));
+  if (tile_owner(ptile)) {
+    ai_incident_nuclear(pplayer, tile_owner(ptile));
+  } else if (tile_get_city(ptile)) {
+    ai_incident_nuclear(pplayer, city_owner(tile_get_city(ptile)));
   } else {
     ai_incident_nuclear(pplayer, NULL);
   }
@@ -2182,8 +2184,8 @@
   }
 
   if (map_is_known_and_seen(ptile, pplayer, V_MAIN)
-      && ((ptile->city
-         && pplayers_non_attack(pplayer, city_owner(ptile->city)))
+      && ((tile_get_city(ptile)
+         && pplayers_non_attack(pplayer, city_owner(tile_get_city(ptile))))
       || is_non_attack_unit_tile(ptile, pplayer))) {
     notify_player(pplayer, ptile, E_BAD_COMMAND,
                      _("Cannot attack unless you declare war first."));
@@ -2214,7 +2216,7 @@
     return TRUE;
   }
 
-  if ((ptile->city && pplayers_non_attack(pplayer, city_owner(ptile->city)))
+  if ((tile_get_city(ptile) && pplayers_non_attack(pplayer, 
city_owner(tile_get_city(ptile))))
       || is_non_allied_unit_tile(ptile, pplayer)) {
     map_show_circle(pplayer, ptile, unit_type(punit)->vision_radius_sq);
     maybe_make_contact(ptile, pplayer);
@@ -2413,7 +2415,7 @@
     double threshold = 0.25;
     struct tile *ptile = penemy->tile;
 
-    if (ptile->city && unit_list_size(ptile->units) == 1) {
+    if (tile_get_city(ptile) && unit_list_size(ptile->units) == 1) {
       /* Don't leave city defenseless */
       threshold = 0.90;
     }
@@ -2511,7 +2513,7 @@
          && ppatrol->orders.vigilant) {
        if (maybe_cancel_patrol_due_to_enemy(ppatrol)) {
          cancel_orders(ppatrol, "  stopping because of nearby enemy");
-         notify_player(ppatrol->owner, ppatrol->tile, E_UNIT_ORDERS,
+         notify_player(unit_owner(ppatrol), ppatrol->tile, E_UNIT_ORDERS,
                        _("Orders for %s aborted after enemy movement was "
                          "spotted."),
                        unit_name_translation(ppatrol));
@@ -2556,7 +2558,7 @@
     tocity = tile_get_city(dst_tile);
 
     if (tocity) { /* entering a city */
-      if (tocity->owner == punit->owner) {
+      if (city_owner(tocity) == unit_owner(punit)) {
        if (tocity != homecity) {
          city_refresh(tocity);
          send_city_info(pplayer, tocity);
@@ -2571,7 +2573,7 @@
       if (homecity) {
        refresh_homecity = TRUE;
       }
-      if (fromcity != homecity && fromcity->owner == punit->owner) {
+      if (fromcity != homecity && city_owner(fromcity) == unit_owner(punit)) {
        city_refresh(fromcity);
        send_city_info(pplayer, fromcity);
       }
@@ -2579,7 +2581,7 @@
 
     /* entering/leaving a fortress or friendly territory */
     if (homecity) {
-      if ((game.info.happyborders > 0 && src_tile->owner != dst_tile->owner)
+      if ((game.info.happyborders > 0 && tile_owner(src_tile) != 
tile_owner(dst_tile))
           ||
          (tile_has_base_flag_for_unit(dst_tile,
                                        unit_type(punit),
@@ -2677,7 +2679,7 @@
     /* Insert them again. */
     unit_list_iterate(cargo_units, pcargo) {
       struct vision *old_vision = pcargo->server.vision;
-      struct vision *new_vision = vision_new(pcargo->owner, pdesttile);
+      struct vision *new_vision = vision_new(unit_owner(pcargo), pdesttile);
 
       pcargo->server.vision = new_vision;
       vision_layer_iterate(v) {
@@ -2712,7 +2714,7 @@
      move */
 
   /* Enhance vision if unit steps into a fortress */
-  new_vision = vision_new(punit->owner, pdesttile);
+  new_vision = vision_new(unit_owner(punit), pdesttile);
   punit->server.vision = new_vision;
   vision_layer_iterate(v) {
     vision_change_sight(new_vision, v,
@@ -2724,7 +2726,7 @@
   /* Claim ownership of fortress? */
   if (tile_has_base_flag_for_unit(pdesttile, unit_type(punit),
                                   BF_CLAIM_TERRITORY)
-      && (!pdesttile->owner || pplayers_at_war(pdesttile->owner, pplayer))) {
+      && (!tile_owner(pdesttile) || pplayers_at_war(tile_owner(pdesttile), 
pplayer))) {
     map_claim_ownership(pdesttile, pplayer, pdesttile);
   }
 
@@ -2879,8 +2881,8 @@
 static bool maybe_cancel_goto_due_to_enemy(struct unit *punit, 
                                            struct tile *ptile)
 {
-  return (is_non_allied_unit_tile(ptile, punit->owner) 
-         || is_non_allied_city_tile(ptile, punit->owner));
+  return (is_non_allied_unit_tile(ptile, unit_owner(punit)) 
+         || is_non_allied_city_tile(ptile, unit_owner(punit)));
 }
 
 /**************************************************************************
@@ -2896,12 +2898,11 @@
   struct player *pplayer = unit_owner(punit);
 
   circle_iterate(punit->tile, radius_sq, ptile) {
-    struct unit *penemy =
-       is_non_allied_unit_tile(ptile, pplayer);
-    struct dumb_city *pdcity = map_get_player_tile(ptile, pplayer)->city;
+    struct unit *penemy = is_non_allied_unit_tile(ptile, pplayer);
+    struct vision_base *pdcity = map_get_player_base(ptile, pplayer);
 
     if ((penemy && can_player_see_unit(pplayer, penemy))
-       || (pdcity && !pplayers_allied(pplayer, pdcity->owner)
+       || (pdcity && !pplayers_allied(pplayer, vision_owner(pdcity))
            && pdcity->occupied)) {
       cancel = TRUE;
       break;
@@ -3196,7 +3197,7 @@
                       enum vision_layer vlayer)
 {
   const int base = (unit_type(punit)->vision_radius_sq
-                   + get_unittype_bonus(punit->owner, ptile, unit_type(punit),
+                   + get_unittype_bonus(unit_owner(punit), ptile, 
unit_type(punit),
                                         EFT_UNIT_VISION_RADIUS_SQ));
   switch (vlayer) {
   case V_MAIN:
Index: server/savegame.c
===================================================================
--- server/savegame.c   (revision 13919)
+++ server/savegame.c   (working copy)
@@ -1093,10 +1093,10 @@
         char token[TOKEN_SIZE];
         struct tile *ptile = native_pos_to_tile(x, y);
 
-        if (ptile->owner == NULL) {
+        if (tile_owner(ptile) == NULL) {
           strcpy(token, "-");
         } else {
-          my_snprintf(token, sizeof(token), "%d", player_number(ptile->owner));
+          my_snprintf(token, sizeof(token), "%d", 
player_number(tile_owner(ptile)));
         }
         strcat(line, token);
         if (x + 1 < map.xsize) {
@@ -1742,7 +1742,7 @@
     }
 
     /* allocate the unit's contribution to fog of war */
-    punit->server.vision = vision_new(punit->owner, punit->tile);
+    punit->server.vision = vision_new(unit_owner(punit), punit->tile);
     unit_refresh_vision(punit);
     /* NOTE: There used to be some map_set_known calls here.  These were
      * unneeded since unfogging the tile when the unit sees it will
@@ -2196,7 +2196,7 @@
     pcity = create_city_virtual(plr, ptile,
                       secfile_lookup_str(file, "player%d.c%d.name", plrno, i));
     ptile->owner_source = pcity->tile;
-    tile_set_owner(ptile, pcity->owner);
+    tile_set_owner(ptile, city_owner(pcity));
 
     pcity->id=secfile_lookup_int(file, "player%d.c%d.id", plrno, i);
     alloc_id(pcity->id);
@@ -2404,7 +2404,7 @@
     }
     
     /* adding the cities contribution to fog-of-war */
-    pcity->server.vision = vision_new(pcity->owner, pcity->tile);
+    pcity->server.vision = vision_new(city_owner(pcity), pcity->tile);
     vision_reveal_tiles(pcity->server.vision, game.info.city_reveal_tiles);
     city_refresh_vision(pcity);
 
@@ -2707,20 +2707,27 @@
 
     {
       int j;
-      struct dumb_city *pdcity;
       i = secfile_lookup_int(file, "player%d.total_ncities", plrno);
       for (j = 0; j < i; j++) {
        int nat_x, nat_y;
-       struct tile *ptile;
        int k, id;
        const char *p;
+       struct tile *ptile;
+       struct vision_base *pdcity = fc_calloc(1, sizeof(*pdcity));
 
+       pdcity->identity = secfile_lookup_int(file, "player%d.dc%d.id", plrno, 
j);
+       if (VISION_BASE_RUIN >= pdcity->identity) {
+         freelog(LOG_ERROR, "[player%d] dc%d has invalid id (%d); skipping.",
+                 plrno, j, pdcity->identity);
+         free(pdcity);
+         continue;
+       }
+
        nat_x = secfile_lookup_int(file, "player%d.dc%d.x", plrno, j);
        nat_y = secfile_lookup_int(file, "player%d.dc%d.y", plrno, j);
        ptile = native_pos_to_tile(nat_x, nat_y);
+       pdcity->location = ptile;
 
-       pdcity = fc_malloc(sizeof(*pdcity));
-       pdcity->id = secfile_lookup_int(file, "player%d.dc%d.id", plrno, j);
        sz_strlcpy(pdcity->name, secfile_lookup_str(file, "player%d.dc%d.name", 
plrno, j));
        pdcity->size = secfile_lookup_int(file, "player%d.dc%d.size", plrno, j);
        pdcity->occupied = secfile_lookup_bool_default(file, FALSE,
@@ -2731,8 +2738,15 @@
                                        "player%d.dc%d.happy", plrno, j);
        pdcity->unhappy = secfile_lookup_bool_default(file, FALSE,
                                        "player%d.dc%d.unhappy", plrno, j);
+
        id = secfile_lookup_int(file, "player%d.dc%d.owner", plrno, j);
        pdcity->owner = player_by_number(id);
+       if (NULL == pdcity->owner) {
+         freelog(LOG_ERROR, "[player%d] dc%d has invalid owner (%d); 
skipping.",
+                 plrno, j, id);
+         free(pdcity);
+         continue;
+       }
 
        /* Initialise list of improvements */
        BV_CLR_ALL(pdcity->improvements);
@@ -2753,8 +2767,8 @@
          }
        }
 
-       map_get_player_tile(ptile, plr)->city = pdcity;
-       alloc_id(pdcity->id);
+       map_get_player_tile(ptile, plr)->vision_source = pdcity;
+       alloc_id(pdcity->identity);
       }
     }
 
@@ -3310,16 +3324,17 @@
                         bin2ascii_hex(map_get_player_tile
                                       (ptile, plr)->last_updated, 3));
 
-    if (TRUE) {
-      struct dumb_city *pdcity;
+    {
+      struct vision_base *pdcity;
       char impr_buf[MAX_NUM_ITEMS + 1];
 
       i = 0;
       
       whole_map_iterate(ptile) {
-       if ((pdcity = map_get_player_tile(ptile, plr)->city)) {
-         secfile_insert_int(file, pdcity->id, "player%d.dc%d.id", plrno,
-                            i);
+       if (NULL != (pdcity = map_get_player_base(ptile, plr))
+        && VISION_BASE_RUIN < pdcity->identity) {
+         secfile_insert_int(file, pdcity->identity, "player%d.dc%d.id",
+                            plrno, i);
          secfile_insert_int(file, ptile->nat_x,
                             "player%d.dc%d.x", plrno, i);
          secfile_insert_int(file, ptile->nat_y,
@@ -3328,8 +3343,6 @@
                             plrno, i);
          secfile_insert_int(file, pdcity->size, "player%d.dc%d.size",
                             plrno, i);
-         secfile_insert_bool(file, FALSE,
-                             "player%d.dc%d.has_walls", plrno, i);
          secfile_insert_bool(file, pdcity->occupied,
                              "player%d.dc%d.occupied", plrno, i);
           secfile_insert_bool(file, pdcity->walls,
@@ -4257,13 +4270,12 @@
   }
   {
     const char **modname;
-    enum tile_special_type j;
 
     /* Save specials order */
     modname = fc_calloc(S_LAST, sizeof(*modname));
-    for (j = 0; j < S_LAST; j++) {
+    tile_special_type_iterate(j) {
       modname[j] = special_rule_name(j);
-    }
+    } tile_special_type_iterate_end;
     secfile_insert_str_vec(file, modname, S_LAST,
                           "savefile.specials");
     free(modname);
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to