Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2005:
[Freeciv-Dev] (PR#14248) Radar station
Home

[Freeciv-Dev] (PR#14248) Radar station

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: sayenko@xxxxxxxxx
Subject: [Freeciv-Dev] (PR#14248) Radar station
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 12 Oct 2005 00:43:19 -0700
Reply-to: bugs@xxxxxxxxxxx

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

Nice patch.  However, I believe it's very buggy.

1.  When changing vision range, you can't fog then unfog.  This
temporarily fogs some tiles that were previously seen which occasionally
breaks things.  The solution for watchtower is to unfog then fog (ugly).

2.  When fogging, you can't assume that the previous vision range was
the correct one.  If vision range is controlled by effects, then it may
change when any req changes...potentially even if a unit moves into and
out of a city.

This is a patch that should be bug-free.  I reworked the vision system
significantly.  Now each city has a value pcity->server.vision_radius_sq
that holds the currently unfogged radius.  unfog_city_area can be called
more than once because it checks the old vision radius so it only unfogs
(or fogs) changed tiles.  Thus all we have to do is call unfog_city_area
from time to time and we keep an updated vision range.  There may be
minor bugs where the vision isn't updated immediately but it should
never get out of sync.

Also I generalized the system of circular vision.  Next I will try to
apply this to units.

Next I changed the effect slightly.  Instead of working on the radius it
works on the radius_sq.  This gives just as much control (if you fiddle
with the effects enough) but has the potential to give more control
(like the new borders system where one tile is claimed per
turn...increasing the value by 5 will show about 5 more tiles).

Finally I changed the data part of the patch.  This part shouldn't be
committed (yet) but is just a demo.  City walls increase the vision
radius sq by 5 (increasing the radius from 2 to 3).  Airport increases
the radius_sq by an additional 7 (with city walls, taking you from 2 to
3).  I didn't want to mess with great wall so I just made that give an
extra 1 vision radius (but this probably is pretty useless).

With the exception of the data bits I believe this is an exceptionally
good patch and should be committed shortly.

-jason

Index: server/citytools.c
===================================================================
--- server/citytools.c  (revision 11108)
+++ server/citytools.c  (working copy)
@@ -795,7 +795,8 @@
   } built_impr_iterate_end;
 
   give_citymap_from_player_to_player(pcity, pgiver, ptaker);
-  map_unfog_pseudo_city_area(ptaker, pcity->tile);
+  map_refog_circle(ptaker, pcity->tile,
+                  -1, pcity->server.vision_radius_sq, TRUE);
 
   sz_strlcpy(old_city_name, pcity->name);
   if (game.info.allowed_city_names == 1
@@ -903,7 +904,8 @@
     update_tile_knowledge(pcity->tile);
   }
 
-  map_fog_pseudo_city_area(pgiver, pcity->tile);
+  map_refog_circle(pgiver, pcity->tile,
+                  pcity->server.vision_radius_sq, -1, TRUE);
 
   /* Build a new palace for free if the player lost her capital and
      savepalace is on. */
@@ -965,7 +967,7 @@
   }
 
   /* Before arranging workers to show unknown land */
-  map_unfog_pseudo_city_area(pplayer, ptile);
+  map_unfog_city_area(pcity);
 
   tile_set_city(ptile, pcity);
 
@@ -1054,6 +1056,7 @@
   struct tile *ptile = pcity->tile;
   bv_imprs had_small_wonders;
   char *city_name = mystrdup(pcity->name);
+  int old_vision_range;
 
   BV_CLR_ALL(had_small_wonders);
   built_impr_iterate(pcity, i) {
@@ -1139,6 +1142,8 @@
      alive in the client. As the number of removed cities is small the leak is
      acceptable. */
 
+  old_vision_range = pcity->server.vision_radius_sq;
+  pcity->server.vision_radius_sq = -1;
   game_remove_city(pcity);
   map_update_borders_city_destroyed(ptile);
 
@@ -1148,7 +1153,7 @@
     }
   } players_iterate_end;
 
-  map_fog_pseudo_city_area(pplayer, ptile);
+  map_refog_circle(pplayer, ptile, old_vision_range, -1, TRUE);
 
   /* Update available tiles in adjacent cities. */
   map_city_radius_iterate(ptile, tile1) {
@@ -1801,6 +1806,10 @@
      * the spaceship is lost. */
     spaceship_lost(owner);
   }
+
+  /* Re-update the city's visible area.  This updates fog if the vision
+   * range increases or decreases. */
+  map_unfog_city_area(pcity);
 }
 
 /**************************************************************************
Index: server/cityturn.c
===================================================================
--- server/cityturn.c   (revision 11108)
+++ server/cityturn.c   (working copy)
@@ -1120,6 +1120,9 @@
                       API_TYPE_BUILDING_TYPE, get_improvement_type(id),
                       API_TYPE_CITY, pcity);
 
+    /* Call this function since some buildings may change the
+     * the vision range of a city */
+    map_unfog_city_area(pcity);
 
     if ((mod = get_current_construction_bonus(pcity, EFT_GIVE_IMM_TECH))) {
       int i;
Index: server/maphand.c
===================================================================
--- server/maphand.c    (revision 11108)
+++ server/maphand.c    (working copy)
@@ -736,25 +736,36 @@
 **************************************************************************/
 void map_fog_city_area(struct city *pcity)
 {
-  if (!pcity) {
+  if (pcity) {
+    map_refog_circle(city_owner(pcity), pcity->tile,
+                    pcity->server.vision_radius_sq, -1, TRUE);
+    pcity->server.vision_radius_sq = -1;
+  } else {
     freelog(LOG_ERROR, "Attempting to fog non-existent city");
-    return;
   }
-
-  map_fog_pseudo_city_area(city_owner(pcity), pcity->tile);
 }
 
 /**************************************************************************
-...
+  Unfogs the area visible by the city.  Unlike other unfog functions this
+  one may be called multiple times in a row without any penalty.  Basically
+  it should be called any time the city's vision range may have changed.
 **************************************************************************/
 void map_unfog_city_area(struct city *pcity)
 {
-  if (!pcity) {
+  if (pcity) {
+    int radius_sq = (CITY_MAP_RADIUS_SQ
+                    + get_city_bonus(pcity, EFT_CITY_VISION_RADIUS_SQ));
+
+    freelog(LOG_NORMAL, "Radius: %d (%d)", CITY_MAP_RADIUS_SQ, radius_sq);
+    if (radius_sq != pcity->server.vision_radius_sq) {
+      map_refog_circle(city_owner(pcity), pcity->tile,
+                      pcity->server.vision_radius_sq, radius_sq, TRUE);
+      pcity->server.vision_radius_sq = radius_sq;
+    }
+  } else {
     freelog(LOG_ERROR, "Attempting to unfog non-existent city");
     return;
   }
-
-  map_unfog_pseudo_city_area(city_owner(pcity), pcity->tile);
 }
 
 /**************************************************************************
@@ -774,36 +785,30 @@
 /**************************************************************************
 There doesn't have to be a city.
 **************************************************************************/
-void map_unfog_pseudo_city_area(struct player *pplayer, struct tile *ptile)
+void map_refog_circle(struct player *pplayer, struct tile *ptile,
+                     int old_radius_sq, int new_radius_sq, bool pseudo)
 {
-  freelog(LOG_DEBUG, "Unfogging city area at %i,%i", TILE_XY(ptile));
+  int max_radius = MAX(old_radius_sq, new_radius_sq);
 
-  buffer_shared_vision(pplayer);
-  map_city_radius_iterate(ptile, tile1) {
-    if (map_is_known(tile1, pplayer)) {
-      unfog_area(pplayer, tile1, 0);
-    } else {
-      increment_pending_seen(pplayer, tile1);
-    }
-  } map_city_radius_iterate_end;
-  unbuffer_shared_vision(pplayer);
-}
+  freelog(LOG_DEBUG, "Refogging circle at %d,%d from %d to %d",
+         TILE_XY(ptile), old_radius_sq, new_radius_sq);
 
-/**************************************************************************
-There doesn't have to be a city.
-**************************************************************************/
-void map_fog_pseudo_city_area(struct player *pplayer, struct tile *ptile)
-{
-  freelog(LOG_DEBUG, "Fogging city area at %i,%i", TILE_XY(ptile));
-
   buffer_shared_vision(pplayer);
-  map_city_radius_iterate(ptile, tile1) {
-    if (map_is_known(tile1, pplayer)) {
-      fog_area(pplayer, tile1, 0);
-    } else {
-      decrement_pending_seen(pplayer, tile1);
+  full_circle_iterate(ptile, max_radius, tile1, dx, dy, dr) {
+    if (dr > old_radius_sq && dr <= new_radius_sq) {
+      if (!pseudo || map_is_known(tile1, pplayer)) {
+       unfog_area(pplayer, tile1, 0);
+      } else {
+       increment_pending_seen(pplayer, tile1);
+      }
+    } else if (dr > new_radius_sq && dr < old_radius_sq) {
+      if (!pseudo || map_is_known(tile1, pplayer)) {
+       fog_area(pplayer, tile1, 0);
+      } else {
+       decrement_pending_seen(pplayer, tile1);
+      }
     }
-  } map_city_radius_iterate_end;
+  } circle_iterate_end;
   unbuffer_shared_vision(pplayer);
 }
 
Index: server/maphand.h
===================================================================
--- server/maphand.h    (revision 11108)
+++ server/maphand.h    (working copy)
@@ -71,8 +71,8 @@
 void map_unfog_city_area(struct city *pcity);
 void remove_unit_sight_points(struct unit *punit);
 void show_area(struct player *pplayer,struct tile *ptile, int len);
-void map_unfog_pseudo_city_area(struct player *pplayer, struct tile *ptile);
-void map_fog_pseudo_city_area(struct player *pplayer, struct tile *ptile);
+void map_refog_circle(struct player *pplayer, struct tile *ptile,
+                     int old_radius_sq, int new_radius_sq, bool pseudo);
 
 bool map_is_known_and_seen(const struct tile *ptile, struct player *pplayer);
 void map_change_seen(struct tile *ptile, struct player *pplayer, int change);
Index: server/savegame.c
===================================================================
--- server/savegame.c   (revision 11108)
+++ server/savegame.c   (working copy)
@@ -2134,7 +2134,7 @@
     }
     
     /* adding the cities contribution to fog-of-war */
-    map_unfog_pseudo_city_area(&game.players[plrno], pcity->tile);
+    map_unfog_city_area(pcity);
 
     pcity->units_supported = unit_list_new();
 
Index: data/default/effects.ruleset
===================================================================
--- data/default/effects.ruleset        (revision 11108)
+++ data/default/effects.ruleset        (working copy)
@@ -398,6 +398,14 @@
       "Building", "Airport", "City"
     }
 
+[effect_airport_vision]
+name    = "City_Vision_Radius_Sq"
+value   = 7
+reqs    =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
 [effect_airport_1]
 name   = "Air_Regen"
 value  = 1
@@ -540,9 +548,13 @@
     { "type", "name", "range"
       "Building", "City Walls", "City"
     }
-nreqs  =
+
+[effect_city_walls_vision]
+name    = "City_Vision_Radius_Sq"
+value   = 5
+reqs    =
     { "type", "name", "range"
-      "Building", "Great Wall", "Player"
+      "Building", "City Walls", "City"
     }
 
 [effect_city_walls_1]
@@ -1185,12 +1197,20 @@
 
 [effect_great_wall]
 name   = "Land_Defend"
-value  = 200
+value  = 50
 reqs   =
     { "type", "name", "range"
       "Building", "Great Wall", "Player"
     }
 
+[effect_great_wall_vision]
+name    = "City_Vision_Radius_Sq"
+value   = 1
+reqs    =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
 [effect_great_wall_1]
 name   = "Unit_No_Lose_Pop"
 value  = 1
Index: data/default/buildings.ruleset
===================================================================
--- data/default/buildings.ruleset      (revision 11108)
+++ data/default/buildings.ruleset      (working copy)
@@ -65,6 +65,8 @@
  Airlifting instantly transports the unit from one city to another\
  and will use all of the unit's movement points.  A unit must have\
  some movement points left to be airlifted.\
+\n\n\
+The airport also increases vision range in a city significantly.\
 ")
 
 [building_aqueduct]
@@ -227,6 +229,7 @@
  units.  They are ineffective against airborne and sea units as well\
  as Howitzers.  City Walls also prevent the loss of population which\
  occurs when a defending unit is destroyed by a land unit.\
+ City Walls also increase the vision range of a city.\
 ")
 
 [building_coastal_defense]
@@ -1122,7 +1125,8 @@
 sound          = "w_great_wall"
 sound_alt      = "w_generic"
 helptext       = _("\
-Works as a City Wall in all your cities.\
+Increases defense against ground units by 50%% in all cities, cumulative
+ with City Walls.  Also increases vision range slightly in all cities.
 ")
 ; NOTE:
 ; Civ2 also doubles attack -vs- barbs,
Index: common/city.c
===================================================================
--- common/city.c       (revision 11108)
+++ common/city.c       (working copy)
@@ -83,7 +83,7 @@
    * This diagram is for rectangular topologies only.  But this is taken
    * care of inside map_vector_to_sq_distance so it works for all topologies.
    */
-  return (CITY_MAP_RADIUS * CITY_MAP_RADIUS + 1 >= dist);
+  return dist <= CITY_MAP_RADIUS_SQ;
 }
 
 /**************************************************************************
@@ -2461,6 +2461,7 @@
 
   pcity->server.workers_frozen = 0;
   pcity->server.needs_arrange = FALSE;
+  pcity->server.vision_radius_sq = -1; /* No vision. */
 
   pcity->ai.founder_want = 0; /* calculating this is really expensive */
   pcity->ai.next_founder_want_recalc = 0; /* turns to recalc found_want */
Index: common/city.h
===================================================================
--- common/city.h       (revision 11108)
+++ common/city.h       (working copy)
@@ -42,6 +42,9 @@
 /* Changing this requires updating CITY_TILES and network capabilities. */
 #define CITY_MAP_RADIUS 2
 
+/* The city includes all tiles dx^2 + dy^2 <= CITY_MAP_RADIUS_SQ */
+#define CITY_MAP_RADIUS_SQ (CITY_MAP_RADIUS * CITY_MAP_RADIUS + 1)
+
 /* Diameter of the workable city area.  Some places harcdode this number. */
 #define CITY_MAP_SIZE (CITY_MAP_RADIUS * 2 + 1) 
 
@@ -290,6 +293,9 @@
     /* If set, workers need to be arranged when the city is unfrozen.  Only
      * set inside auto_arrange_workers. */
     bool needs_arrange;
+
+    /* The vision radius that is currently unfogged. */
+    int vision_radius_sq;
   } server;
 
   int turn_founded;            /* In which turn was the city founded? */
Index: common/effects.c
===================================================================
--- common/effects.c    (revision 11108)
+++ common/effects.c    (working copy)
@@ -95,6 +95,7 @@
   "Land_Regen",
   "Sea_Regen",
   "Air_Regen",
+  "City_Vision_Radius_Sq",
   "Land_Defend",
   "Sea_Defend",
   "Air_Defend",
Index: common/effects.h
===================================================================
--- common/effects.h    (revision 11108)
+++ common/effects.h    (working copy)
@@ -83,6 +83,7 @@
   EFT_LAND_REGEN,
   EFT_SEA_REGEN,
   EFT_AIR_REGEN,
+  EFT_CITY_VISION_RADIUS_SQ,
   EFT_LAND_DEFEND,
   EFT_SEA_DEFEND,
   EFT_AIR_DEFEND,
Index: common/game.c
===================================================================
--- common/game.c       (revision 11108)
+++ common/game.c       (working copy)
@@ -159,6 +159,8 @@
           get_nation_name(city_owner(pcity)->nation), pcity->tile->x,
          pcity->tile->y);
 
+  assert(pcity->server.vision_radius_sq < 0); /* Otherwise vision fails. */
+
   city_map_checked_iterate(pcity->tile, x, y, map_tile) {
     set_worker_city(pcity, x, y, C_TILE_EMPTY);
   } city_map_checked_iterate_end;
Index: common/map.h
===================================================================
--- common/map.h        (revision 11108)
+++ common/map.h        (working copy)
@@ -322,17 +322,27 @@
  * positions will be automatically discarded. 
  */
 #define circle_iterate(center_tile, sq_radius, tile_itr)                   \
-{                                                                           \
-  int _sq_radius = (sq_radius);                                                
    \
-  int _cr_radius = (int)sqrt((double)_sq_radius);                          \
-  square_dxy_iterate(center_tile, _cr_radius, tile_itr, _dx, _dy) {        \
-    if (map_vector_to_sq_distance(_dx, _dy) <= _sq_radius) {
+  full_circle_iterate(center_tile, sq_radius, tile_itr, _dx, _dy, _dr)
 
 #define circle_iterate_end                                                  \
-    }                                                                       \
-  } square_dxy_iterate_end;                                                 \
-}                                                                             
+  full_circle_iterate_end
 
+#define full_circle_iterate(center_tile, sq_radius,                        \
+                           tile_itr, dx, dy, dr)                           \
+{                                                                          \
+  const int _sq_radius = (sq_radius);                                      \
+  const int _cr_radius = (int)sqrt((double)_sq_radius);                        
    \
+                                                                           \
+  square_dxy_iterate(center_tile, _cr_radius, tile_itr, dx, dy) {          \
+    const int dr = map_vector_to_sq_distance(dx, dy);                      \
+                                                                           \
+    if (dr <= _sq_radius) {
+
+#define full_circle_iterate_end                                                
    \
+    }                                                                      \
+  } square_dxy_iterate_end;                                                \
+}
+
 /* Iterate through all map positions adjacent to the given center map
  * position, with normalization.  The order of positions is unspecified. */
 #define adjc_iterate(center_tile, itr_tile)                                \
Index: ai/aicity.c
===================================================================
--- ai/aicity.c (revision 11108)
+++ ai/aicity.c (working copy)
@@ -347,6 +347,13 @@
       case EFT_NO_DIPLOMACY:
          break;
 
+      case EFT_CITY_VISION_RADIUS_SQ:
+       /* Wild guess.  "Amount" is the number of tiles (on average) that
+        * will be revealed by the effect.  Note that with an omniscient
+        * AI this effect is actually not useful at all. */
+       v += c * amount;
+       break;
+
       case EFT_SLOW_DOWN_TIMELINE:
        /* AI doesn't care about these. */
        break;

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#14248) Radar station, Jason Short <=