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

Attached patch makes tile_special_type_iterate skip
over S_FORTRESS and S_AIRBASE in order to facilitate
the transition of base types out of specials (as
mentioned in PR#40184).

Any code that depended on the base special values
being in the iteration has also been updated; there
should be no change in behaviour if I have not made
any mistakes.

In the future when bases really are removed from
enum tile_special_type, all of the added base/special
transition code can be made inert by simply having
base_get_tile_special_type always return S_LAST.

I have also written the code with the future feature
of more than one base type being allowed per tile in
mind. This should be possible (since indeed it was
allowed to have a fortress and an airbase on the same
tile before), but I will start a new ticket for this
issue later.


----------------------------------------------------------------------
よろしくやるのは気持ちいいですね
diff --git a/client/packhand.c b/client/packhand.c
index c97bc71..9a900fe 100644
--- a/client/packhand.c
+++ b/client/packhand.c
@@ -2242,6 +2242,24 @@ void handle_tile_info(struct packet_tile_info *packet)
     }
   } tile_special_type_iterate_end;
 
+  base_type_iterate(pbase) {
+    int spe = base_get_tile_special_type(pbase);
+    if (!(0 <= spe && spe < S_LAST)) {
+      continue;
+    }
+    if (packet->special[spe]) {
+      if (!tile_has_base(ptile, pbase)) {
+        tile_add_base(ptile, pbase);
+        tile_changed = TRUE;
+      }
+    } else {
+      if (tile_has_base(ptile, pbase)) {
+        tile_remove_base(ptile, pbase);
+        tile_changed = TRUE;
+      }
+    }
+  } base_type_iterate_end;
+
   tile_changed = tile_changed || (tile_resource(ptile) != presource);
 
   /* always called after setting terrain */
diff --git a/common/base.c b/common/base.c
index 884bd22..bb3f8e0 100644
--- a/common/base.c
+++ b/common/base.c
@@ -265,3 +265,29 @@ struct base_type *get_base_by_gui_type(enum base_gui_type type,
 
   return NULL;
 }
+
+/**************************************************************************
+  Returns the value from enum tile_special_type that corresponds to this
+  base type or S_LAST if no such value exists.
+
+  NB: This function should only be used temporarily while the old "special"
+  base code is transitioned to the new generalized bases. Once S_FORTRESS
+  and S_AIRBASE are removed from specials, this function should also be
+  removed.
+**************************************************************************/
+int base_get_tile_special_type(const struct base_type *pbase)
+{
+  if (!pbase) {
+    return S_LAST;
+  }
+
+  if (base_number(pbase) == BASE_FORTRESS) {
+    return S_FORTRESS;
+  }
+  
+  if (base_number(pbase) == BASE_AIRBASE) {
+    return S_AIRBASE;
+  }
+
+  return S_LAST;
+}
diff --git a/common/base.h b/common/base.h
index ba38a5c..a6e5f3c 100644
--- a/common/base.h
+++ b/common/base.h
@@ -66,7 +66,11 @@ Base_type_id base_index(const struct base_type *pbase);
 Base_type_id base_number(const struct base_type *pbase);
 
 struct base_type *base_by_number(const Base_type_id id);
+
+/* Compatibility functions for the old "special"
+ * type bases which are being phased out. */
 struct base_type *base_of_bv_special(bv_special spe);
+int base_get_tile_special_type(const struct base_type *pbase);
 
 const char *base_rule_name(const struct base_type *pbase);
 const char *base_name_translation(struct base_type *pbase);
diff --git a/common/terrain.c b/common/terrain.c
index d7d4e6f..eec85f5 100644
--- a/common/terrain.c
+++ b/common/terrain.c
@@ -547,6 +547,7 @@ static const char *tile_special_type_names[] =
 ****************************************************************************/
 enum tile_special_type find_special_by_rule_name(const char *name)
 {
+  int spe;
   assert(ARRAY_SIZE(tile_special_type_names) == S_LAST);
 
   tile_special_type_iterate(i) {
@@ -555,6 +556,16 @@ enum tile_special_type find_special_by_rule_name(const char *name)
     }
   } tile_special_type_iterate_end;
 
+  base_type_iterate(pbase) {
+    spe = base_get_tile_special_type(pbase);
+    if (!(0 <= spe && spe < S_LAST)) {
+      continue;
+    }
+    if (0 == strcmp(tile_special_type_names[spe], name)) {
+      return spe;
+    }
+  } base_type_iterate_end;
+
   return S_LAST;
 }
 
diff --git a/common/terrain.h b/common/terrain.h
index 7e80403..8fdfe0f 100644
--- a/common/terrain.h
+++ b/common/terrain.h
@@ -55,13 +55,19 @@ extern enum tile_special_type infrastructure_specials[];
 
 BV_DEFINE(bv_special, S_LAST_PLUS);
 
-#define tile_special_type_iterate(special)				    \
-{									    \
-  enum tile_special_type special = 0;					    \
-  for (; special < S_LAST; special++) {
-
-#define tile_special_type_iterate_end					    \
-  }									    \
+/* NB: This does not include S_FORTRESS and S_AIRBASE.
+ * You must use base_type_iterate and related accessors
+ * in base.h for those. */
+#define tile_special_type_iterate(special)                                 \
+{                                                                          \
+  enum tile_special_type special = 0;                                      \
+  for (; special < S_LAST; special++) {                                    \
+    if (special == S_FORTRESS || special == S_AIRBASE) {                   \
+      continue;                                                            \
+    }
+    
+#define tile_special_type_iterate_end                                      \
+  }                                                                        \
 }
 
 /* === */
diff --git a/common/tile.c b/common/tile.c
index ac4f476..84d8e6c 100644
--- a/common/tile.c
+++ b/common/tile.c
@@ -171,10 +171,16 @@ void tile_add_base(struct tile *ptile, const struct base_type *pbase)
 /****************************************************************************
   Removes base from tile if such exist
 ****************************************************************************/
-void tile_remove_base(struct tile *ptile)
+void tile_remove_base(struct tile *ptile, const struct base_type *pbase)
 {
-  tile_clear_special(ptile, S_FORTRESS);
-  tile_clear_special(ptile, S_AIRBASE);
+  int spe;
+  
+  spe = base_get_tile_special_type(pbase);
+  if (!(0 <= spe && spe < S_LAST)) {
+    return;
+  }
+
+  tile_clear_special(ptile, spe);
 }
 
 /****************************************************************************
@@ -697,3 +703,19 @@ const char *tile_get_info_text(const struct tile *ptile, int linebreaks)
 
   return s;
 }
+
+/****************************************************************************
+  Returns TRUE if the given tile has a base of given type on it.
+****************************************************************************/
+bool tile_has_base(const struct tile *ptile, const struct base_type *pbase)
+{
+  struct base_type *bt;
+  
+  if (!ptile) {
+    return FALSE;
+  }
+
+  bt = tile_get_base(ptile);
+
+  return bt == pbase;
+}
diff --git a/common/tile.h b/common/tile.h
index e2a0a8d..a795a8e 100644
--- a/common/tile.h
+++ b/common/tile.h
@@ -97,8 +97,9 @@ void tile_clear_all_specials(struct tile *ptile);
 
 /* Bases map onto specials */
 struct base_type *tile_get_base(const struct tile *ptile);
+bool tile_has_base(const struct tile *ptile, const struct base_type *pbase);
 void tile_add_base(struct tile *ptile, const struct base_type *pbase);
-void tile_remove_base(struct tile *ptile);
+void tile_remove_base(struct tile *ptile, const struct base_type *pbase);
 bool tile_has_base_flag(const struct tile *ptile, enum base_flag_id flag);
 bool tile_has_base_flag_for_unit(const struct tile *ptile,
                                  const struct unit_type *punittype,
diff --git a/server/citytools.c b/server/citytools.c
index 8683c49..b182621 100644
--- a/server/citytools.c
+++ b/server/citytools.c
@@ -1096,7 +1096,7 @@ void create_city(struct player *pplayer, struct tile *ptile,
 
   /* If base acted as a watchtower, put vision back to normal */
   if (pbase) {
-    tile_remove_base(ptile);
+    tile_remove_base(ptile, pbase);
     unit_list_refresh_vision(ptile->units);
   }
 
diff --git a/server/maphand.c b/server/maphand.c
index 48a37dc..123c3ae 100644
--- a/server/maphand.c
+++ b/server/maphand.c
@@ -359,6 +359,8 @@ void map_regenerate_water(void)
 }
 
 static void player_tile_init(struct tile *ptile, struct player *pplayer);
+static bool player_tile_has_base(struct player_tile *plrtile,
+                                 struct base_type *pbase);
 static void give_tile_info_from_player_to_player(struct player *pfrom,
 						 struct player *pdest,
 						 struct tile *ptile);
@@ -700,6 +702,14 @@ void send_tile_info(struct conn_list *dest, struct tile *ptile,
 	info.special[spe] = BV_ISSET(ptile->special, spe);
       } tile_special_type_iterate_end;
 
+      base_type_iterate(pbase) {
+        int spe = base_get_tile_special_type(pbase);
+        if (!(0 <= spe && spe < S_LAST)) {
+          continue;
+        }
+        info.special[spe] = tile_has_base(ptile, pbase);
+      } base_type_iterate_end;
+
       send_packet_tile_info(pconn, &info);
     } else if (pplayer && map_is_known(ptile, pplayer)
 	       && map_get_seen(ptile, pplayer, V_MAIN) == 0) {
@@ -723,6 +733,14 @@ void send_tile_info(struct conn_list *dest, struct tile *ptile,
 	info.special[spe] = BV_ISSET(plrtile->special, spe);
       } tile_special_type_iterate_end;
 
+      base_type_iterate(pbase) {
+        int spe = base_get_tile_special_type(pbase);
+        if (!(0 <= spe && spe < S_LAST)) {
+          continue;
+        }
+        info.special[spe] = player_tile_has_base(plrtile, pbase);
+      } base_type_iterate_end;
+
       send_packet_tile_info(pconn, &info);
     } else if (send_unknown) {
       info.known = TILE_UNKNOWN;
@@ -737,6 +755,14 @@ void send_tile_info(struct conn_list *dest, struct tile *ptile,
         info.special[spe] = FALSE;
       } tile_special_type_iterate_end;
 
+      base_type_iterate(pbase) {
+        int spe = base_get_tile_special_type(pbase);
+        if (!(0 <= spe && spe < S_LAST)) {
+          continue;
+        }
+        info.special[spe] = FALSE;
+      } base_type_iterate_end;
+
       send_packet_tile_info(pconn, &info);
     }
   }
@@ -2114,3 +2140,24 @@ void vision_clear_sight(struct vision *vision)
   vision_change_sight(vision, V_INVIS, -1);
   vision_change_sight(vision, V_MAIN, -1);
 }
+
+/****************************************************************************
+  Returns TRUE if the given player tile has a base of the given type.
+****************************************************************************/
+static bool player_tile_has_base(struct player_tile *plrtile,
+                                 struct base_type *pbase)
+{
+  int spe;
+
+  if (!plrtile) {
+    return FALSE;
+  }
+
+  spe = base_get_tile_special_type(pbase);
+
+  if (!(0 <= spe && spe < S_LAST)) {
+    return FALSE;
+  }
+
+  return contains_special(plrtile->special, spe);
+}
diff --git a/server/savegame.c b/server/savegame.c
index 13d3410..f7a8a1e 100644
--- a/server/savegame.c
+++ b/server/savegame.c
@@ -4533,12 +4533,23 @@ void game_save(struct section_file *file, const char *save_reason)
   }
   {
     const char **modname;
+    int spe;
 
     /* Save specials order */
     modname = fc_calloc(S_LAST, sizeof(*modname));
+
     tile_special_type_iterate(j) {
       modname[j] = special_rule_name(j);
     } tile_special_type_iterate_end;
+
+    base_type_iterate(pbase) {
+      spe = base_get_tile_special_type(pbase);
+      if (!(0 <= spe && spe < S_LAST)) {
+        continue;
+      }
+      modname[spe] = special_rule_name(spe);
+    } base_type_iterate_end;
+
     secfile_insert_str_vec(file, modname, S_LAST,
 			   "savefile.specials");
     free(modname);
diff --git a/server/unittools.c b/server/unittools.c
index 49f4c34..fcc1d08 100644
--- a/server/unittools.c
+++ b/server/unittools.c
@@ -715,13 +715,16 @@ static void update_unit_activity(struct unit *punit)
   case ACTIVITY_PILLAGE:
     if (punit->activity_target == S_LAST) { /* case for old save files */
       if (punit->activity_count >= 1) {
-	enum tile_special_type what
-	  = get_preferred_pillage(get_tile_infrastructure_set(ptile, NULL),
-                                  tile_get_base(ptile));
+        struct base_type *pbase;
+        enum tile_special_type what;
+
+        pbase = tile_get_base(ptile);
+        what = get_preferred_pillage(get_tile_infrastructure_set(ptile, NULL),
+                                     pbase);
 
 	if (what != S_LAST) {
           if (what == S_PILLAGE_BASE) {
-            tile_remove_base(ptile);
+            tile_remove_base(ptile, pbase);
           } else {
             tile_clear_special(ptile, what);
           }
@@ -739,7 +742,7 @@ static void update_unit_activity(struct unit *punit)
       enum tile_special_type what_pillaged = punit->activity_target;
 
       if (what_pillaged == S_PILLAGE_BASE) {
-        tile_remove_base(ptile);
+        tile_remove_base(ptile, tile_get_base(ptile));
       } else {
         tile_clear_special(ptile, what_pillaged);
       }
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to