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

Attached patch adds {create,destroy}_tile_virtual to allow
the use of virtual tiles in the same manner as virtual units
and cities. It also adds helper functions to check whether
a given unit or city is virtual (i.e. is a valid pointer
but does not have an ID of any unit/city in the game).

The virtual tile funtions are useful for certain operations
of the editor which I am now working on (a copy and paste
tool), and more importantly for cleaning up all of the
direct modification abuse of tiles. I mean code that does

  old = tile_get_foo(ptile);
  tile_set_foo(ptile, something_else);
  calculate_some_value(ptile);
  tile_set_foo(ptile, old);

which is prone to induce bugs when someone adds or removes
side-effects from any of the called functions but does not
update all of the occurences of that sequence of calls.


-----------------------------------------------------------------------
酔っていながらヨーヨーの運転することは懲役八日の罰だよ。
diff --git a/common/city.c b/common/city.c
index dda23bd..cafe810 100644
--- a/common/city.c
+++ b/common/city.c
@@ -2617,3 +2617,19 @@ bool city_exist(int id)
 
   return FALSE;
 }
+
+/**************************************************************************
+  Return TRUE if the city is a virtual city. That is, it is a valid city
+  pointer but does not correspond to a city that exists in the game.
+
+  NB: A return value of FALSE implies that either the pointer is NULL or
+  that the city exists in the game.
+**************************************************************************/
+bool city_is_virtual(const struct city *pcity)
+{
+  if (!pcity) {
+    return FALSE;
+  }
+
+  return pcity != game_find_city_by_number(pcity->id);
+}
diff --git a/common/city.h b/common/city.h
index f87a3a0..6fef23f 100644
--- a/common/city.h
+++ b/common/city.h
@@ -629,6 +629,7 @@ bool city_built_last_turn(const struct city *pcity);
 struct city *create_city_virtual(struct player *pplayer,
 				 struct tile *ptile, const char *name);
 void destroy_city_virtual(struct city *pcity);
+bool city_is_virtual(const struct city *pcity);
 
 /* misc */
 bool is_city_option_set(const struct city *pcity, enum city_options option);
diff --git a/common/tile.c b/common/tile.c
index 5a7b580..cad4c4c 100644
--- a/common/tile.c
+++ b/common/tile.c
@@ -664,3 +664,54 @@ bool tile_has_base(const struct tile *ptile, const struct base_type *pbase)
 {
   return BV_ISSET(ptile->bases, base_index(pbase));
 }
+
+/****************************************************************************
+  Returns a completely blank virtual tile (except for the unit list
+  vtile->units, which is created for you). Be sure to call virtual_tile_free
+  on it when it is no longer needed.
+****************************************************************************/
+struct tile *create_tile_virtual(void)
+{
+  struct tile *vtile;
+
+  vtile = fc_calloc(1, sizeof(*vtile));
+  vtile->units = unit_list_new();
+
+  return vtile;
+}
+
+/****************************************************************************
+  Frees all memory used by the virtual tile, including freeing virtual
+  units in the tile's unit list and the virtual city on this tile if one
+  exists.
+
+  NB: Do not call this on real tiles!
+****************************************************************************/
+void destroy_tile_virtual(struct tile *vtile)
+{
+  struct city *vcity;
+
+  if (!vtile) {
+    return;
+  }
+
+  if (vtile->units) {
+    unit_list_iterate(vtile->units, vunit) {
+      if (unit_is_virtual(vunit)) {
+        destroy_unit_virtual(vunit);
+      }
+    } unit_list_iterate_end;
+    unit_list_free(vtile->units);
+    vtile->units = NULL;
+  }
+
+  vcity = tile_city(vtile);
+  if (vcity) {
+    if (city_is_virtual(vcity)) {
+      destroy_city_virtual(vcity);
+    }
+    tile_set_worked(vtile, NULL);
+  }
+
+  free(vtile);
+}
diff --git a/common/tile.h b/common/tile.h
index 71db75d..93e7a5d 100644
--- a/common/tile.h
+++ b/common/tile.h
@@ -129,4 +129,8 @@ bool tile_apply_activity(struct tile *ptile, Activity_type_id act);
 #define TILE_LB_RESOURCE_POLL    (1 << 2)
 const char *tile_get_info_text(const struct tile *ptile, int linebreaks);
 
+/* Virtual tiles are tiles that do not exist on the game map. */
+struct tile *create_tile_virtual(void);
+void destroy_tile_virtual(struct tile *vtile);
+
 #endif /* FC__TILE_H */
diff --git a/common/unit.c b/common/unit.c
index 79fc0f3..f772d73 100644
--- a/common/unit.c
+++ b/common/unit.c
@@ -1599,3 +1599,19 @@ bool unit_alive(int id)
 
   return FALSE;
 }
+
+/**************************************************************************
+  Return TRUE if this is a valid unit pointer but does not correspond to
+  any unit that exists in the game.
+
+  NB: A return value of FALSE implies that either the pointer is NULL or
+  that the unit exists in the game.
+**************************************************************************/
+bool unit_is_virtual(const struct unit *punit)
+{
+  if (!punit) {
+    return FALSE;
+  }
+
+  return punit != game_find_unit_by_number(punit->id);
+}
diff --git a/common/unit.h b/common/unit.h
index 088650c..26c0d4a 100644
--- a/common/unit.h
+++ b/common/unit.h
@@ -315,6 +315,7 @@ struct unit *create_unit_virtual(struct player *pplayer, struct city *pcity,
                                  struct unit_type *punittype,
 				 int veteran_level);
 void destroy_unit_virtual(struct unit *punit);
+bool unit_is_virtual(const struct unit *punit);
 void free_unit_orders(struct unit *punit);
 
 int get_transporter_occupancy(const struct unit *ptrans);
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to