Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2005:
[Freeciv-Dev] (PR#14356) use fog-of-war for submarines
Home

[Freeciv-Dev] (PR#14356) use fog-of-war for submarines

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#14356) use fog-of-war for submarines
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 16 Oct 2005 20:11:28 -0700
Reply-to: bugs@xxxxxxxxxxx

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

This patch changes the vision code yet again.  Now multiple vision 
layers are supported.  Each vision object provides independent vision on 
each layer.

There are two layers.  V_MAIN provides all the functionality of current 
fog; it lets you see tiles, cities, and units.  The second layer is 
V_INVIS - this layer provides vision of F_PARTIAL_INVIS 
(submarine/hiding) units only.

Each layer has separate fog arrays that are kept updated.  Each vision 
source must have at least as much MAIN sight as it has INVIS sight, 
since only MAIN sight provides vision on tiles and cities.

This patch...needs a lot of testing.  It has the potential to provide 
faster and more stable revealing/concealing of submarines, since instead 
of complex reveal/conceal loops for *each unit* we just track the fog 
per-tile.  However there is a fairly high possibility of bugs in the 
patch itself.

Also it includes a behavior change: cities provide INVIS vision out to 
their full range.  This provides a substantial benefit to using city 
vision effects!  I'm not positive this is a good change but it certainly 
demonstrates the flexibility of the new system (it is possible to have 
sub-hunters, i.e. destroyers, that have full INVIS vision).

-jason

Index: server/gotohand.c
===================================================================
--- server/gotohand.c   (revision 11148)
+++ server/gotohand.c   (working copy)
@@ -1239,7 +1239,7 @@
     return TRUE;
   }
 
-  if (!(omni || map_is_known_and_seen(ptile, pplayer))) {
+  if (!(omni || map_is_known_and_seen(ptile, pplayer, V_MAIN))) {
     /* The destination is in unknown -- assume sane */
     return TRUE;
   }
@@ -1459,7 +1459,7 @@
 
   /* If the tile's fogged we again (may) assume it's safe. */
   if (ai_handicap(pplayer, H_FOG) &&
-      !map_is_known_and_seen(ptile, pplayer)) {
+      !map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
     return AIR_ASSUMES_FOGGED_SAFE;
   }
 
Index: server/citytools.c
===================================================================
--- server/citytools.c  (revision 11148)
+++ server/citytools.c  (working copy)
@@ -798,7 +798,10 @@
   give_citymap_from_player_to_player(pcity, pgiver, ptaker);
   old_vision = pcity->server.vision;
   pcity->server.vision = vision_new(ptaker, pcity->tile, FALSE);
-  vision_change_sight(pcity->server.vision, vision_get_sight(old_vision));
+  vision_layer_iterate(v) {
+    vision_change_sight(pcity->server.vision, v,
+                       vision_get_sight(old_vision, v));
+  } vision_layer_iterate_end;
 
   sz_strlcpy(old_city_name, pcity->name);
   if (game.info.allowed_city_names == 1
@@ -1146,7 +1149,7 @@
   map_update_borders_city_destroyed(ptile);
 
   players_iterate(other_player) {
-    if (map_is_known_and_seen(ptile, other_player)) {
+    if (map_is_known_and_seen(ptile, other_player, V_MAIN)) {
       reality_check_city(other_player, ptile);
     }
   } players_iterate_end;
@@ -1364,7 +1367,7 @@
 void refresh_dumb_city(struct city *pcity)
 {
   players_iterate(pplayer) {
-    if (map_is_known_and_seen(pcity->tile, pplayer)
+    if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)
        || player_has_traderoute_with_city(pplayer, pcity)) {
       if (update_dumb_city(pplayer, pcity)) {
        struct packet_city_short_info packet;
@@ -1406,7 +1409,7 @@
        lsend_packet_city_info(powner->connections, &packet);
       }
     } else {
-      if (map_is_known_and_seen(pcity->tile, pplayer)
+      if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)
          || player_has_traderoute_with_city(pplayer, pcity)) {
        update_dumb_city(pplayer, pcity);
        package_dumb_city(pplayer, pcity->tile, &sc_pack);
@@ -1544,7 +1547,7 @@
        /* Without the conditional we'd have an infinite loop here. */
        map_show_tile(pviewer, ptile);
       }
-      if (map_is_known_and_seen(ptile, pviewer)) {
+      if (map_is_known_and_seen(ptile, pviewer, V_MAIN)) {
        if (pcity) {            /* it's there and we see it; update and send */
          update_dumb_city(pviewer, pcity);
          package_dumb_city(pviewer, ptile, &sc_pack);
@@ -2139,6 +2142,9 @@
 ****************************************************************************/
 void city_refresh_vision(struct city *pcity)
 {
-  vision_change_sight(pcity->server.vision,
-                     get_city_bonus(pcity, EFT_CITY_VISION_RADIUS_SQ));
+  int radius_sq = get_city_bonus(pcity, EFT_CITY_VISION_RADIUS_SQ);
+
+  vision_layer_iterate(v) {
+    vision_change_sight(pcity->server.vision, v, radius_sq);
+  } vision_layer_iterate_end;
 }
Index: server/barbarian.c
===================================================================
--- server/barbarian.c  (revision 11148)
+++ server/barbarian.c  (working copy)
@@ -475,7 +475,7 @@
     notify_player(victim, utile, E_UPRISING,
                     _("Native unrest near %s led by %s."), pc->name,
                     barbarians->name);
-  } else if (map_is_known_and_seen(utile, victim)) {
+  } else if (map_is_known_and_seen(utile, victim, V_MAIN)) {
     notify_player(victim, utile, E_UPRISING,
                     _("Sea raiders seen near %s!"), pc->name);
   }
Index: server/maphand.c
===================================================================
--- server/maphand.c    (revision 11148)
+++ server/maphand.c    (working copy)
@@ -193,11 +193,14 @@
 static void give_tile_info_from_player_to_player(struct player *pfrom,
                                                 struct player *pdest,
                                                 struct tile *ptile);
-static void shared_vision_change_seen(struct tile *ptile, struct player 
*pplayer, int change);
+static void shared_vision_change_seen(struct tile *ptile,
+                                     struct player *pplayer, int change,
+                                     enum vision_layer vlayer);
 static int map_get_seen(const struct tile *ptile,
-                       const struct player *pplayer);
+                       const struct player *pplayer,
+                       enum vision_layer vlayer);
 static void map_change_own_seen(struct tile *ptile, struct player *pplayer,
-                               int change);
+                               int change, enum vision_layer vlayer);
 
 /**************************************************************************
 Used only in global_warming() and nuclear_winter() below.
@@ -475,7 +478,7 @@
     if (!pplayer && !pconn->observer) {
       continue;
     }
-    if (!pplayer || map_is_known_and_seen(ptile, pplayer)) {
+    if (!pplayer || map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
       info.known = TILE_KNOWN;
       info.type = ptile->terrain->index;
       for (spe = 0; spe < S_LAST; spe++) {
@@ -484,7 +487,7 @@
       info.continent = ptile->continent;
       send_packet_tile_info(pconn, &info);
     } else if (pplayer && map_is_known(ptile, pplayer)
-              && map_get_seen(ptile, pplayer) == 0) {
+              && map_get_seen(ptile, pplayer, V_MAIN) == 0) {
       struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
 
       info.known = TILE_KNOWN_FOGGED;
@@ -500,52 +503,21 @@
 }
 
 /****************************************************************************
-  Checks for hidden units around (x,y).  Such units can be invisible even
-  on a KNOWN_AND_SEEN tile, so unfogging might not reveal them.
+  Assumption: Each unit type is visible on only one layer.
 ****************************************************************************/
-void reveal_hidden_units(struct player *pplayer, struct tile *ptile)
+static bool unit_is_visible_on_layer(const struct unit *punit,
+                                    enum vision_layer vlayer)
 {
-  adjc_iterate(ptile, tile1) {
-    unit_list_iterate(tile1->units, punit) {
-      if (is_hiding_unit(punit)) {
-        /* send_unit_info will check whether it is visible */
-        send_unit_info(pplayer, punit);
-      }
-    } unit_list_iterate_end;
-  } adjc_iterate_end;
+  return XOR(vlayer == V_MAIN, is_hiding_unit(punit));
 }
 
 /****************************************************************************
-  Checks for hidden units around (x,y).  Such units can be invisible even
-  on a KNOWN_AND_SEEN tile, so fogging might not hide them.
-
-  Note, this must be called after the unit/vision source at ptile has
-  been removed, unlike remove_unit_sight_points.
-****************************************************************************/
-void conceal_hidden_units(struct player *pplayer, struct tile *ptile)
-{
-  /* Remove vision of submarines.  This is extremely ugly and inefficient. */
-  adjc_iterate(ptile, tile1) {
-    unit_list_iterate(tile1->units, phidden_unit) {
-      if (phidden_unit->transported_by == -1
-         && is_hiding_unit(phidden_unit)) {
-       players_iterate(pplayer2) {
-         if ((pplayer2 == pplayer || really_gives_vision(pplayer, pplayer2))
-             && !can_player_see_unit(pplayer2, phidden_unit)) {
-           unit_goes_out_of_sight(pplayer2, phidden_unit);
-         }
-       } players_iterate_end;
-      }
-    } unit_list_iterate_end;
-  } adjc_iterate_end;
-}
-
-/****************************************************************************
   This is a backend function that marks a tile as unfogged.  Call this when
   map_unfog_tile adds the first point of visibility to the tile, or when
   shared vision changes cause a tile to become unfogged.
 ****************************************************************************/
-static void really_unfog_tile(struct player *pplayer, struct tile *ptile)
+static void really_unfog_tile(struct player *pplayer, struct tile *ptile,
+                             enum vision_layer vlayer)
 {
   struct city *pcity;
   bool old_known = map_is_known(ptile, pplayer);
@@ -554,33 +526,43 @@
 
   map_set_known(ptile, pplayer);
 
-  /* send info about the tile itself 
-   * It has to be sent first because the client needs correct
-   * continent number before it can handle following packets
-   */
-  update_player_tile_knowledge(pplayer, ptile);
-  send_tile_info(pplayer->connections, ptile);
+  if (vlayer == V_MAIN) {
+    /* send info about the tile itself 
+     * It has to be sent first because the client needs correct
+     * continent number before it can handle following packets
+     */
+    update_player_tile_knowledge(pplayer, ptile);
+    send_tile_info(pplayer->connections, ptile);
+    /* NOTE: because the V_INVIS case doesn't fall into this if statement,
+     * changes to V_INVIS fogging won't send a new info packet to the client
+     * and the client's tile_seen[V_INVIS] bitfield may end up being out
+     * of date. */
+  }
 
   /* discover units */
-  unit_list_iterate(ptile->units, punit)
-    send_unit_info(pplayer, punit);
-  unit_list_iterate_end;
+  unit_list_iterate(ptile->units, punit) {
+    if (unit_is_visible_on_layer(punit, vlayer)) {
+      send_unit_info(pplayer, punit);
+    }
+  } unit_list_iterate_end;
 
-  /* discover cities */ 
-  reality_check_city(pplayer, ptile);
-  if ((pcity=tile_get_city(ptile)))
-    send_city_info(pplayer, pcity);
+  if (vlayer == V_MAIN) {
+    /* discover cities */ 
+    reality_check_city(pplayer, ptile);
+    if ((pcity=tile_get_city(ptile)))
+      send_city_info(pplayer, pcity);
 
-  /* If the tile was not known before we need to refresh the cities that
-     can use the tile. */
-  if (!old_known) {
-    map_city_radius_iterate(ptile, tile1) {
-      pcity = tile_get_city(tile1);
-      if (pcity && city_owner(pcity) == pplayer) {
-       update_city_tile_status_map(pcity, ptile);
-      }
-    } map_city_radius_iterate_end;
-    sync_cities();
+    /* If the tile was not known before we need to refresh the cities that
+       can use the tile. */
+    if (!old_known) {
+      map_city_radius_iterate(ptile, tile1) {
+       pcity = tile_get_city(tile1);
+       if (pcity && city_owner(pcity) == pplayer) {
+         update_city_tile_status_map(pcity, ptile);
+       }
+      } map_city_radius_iterate_end;
+      sync_cities();
+    }
   }
 }
 
@@ -590,10 +572,11 @@
   function multiple times.
 ****************************************************************************/
 static void map_unfog_tile(struct player *pplayer, struct tile *ptile,
-                          bool can_reveal_tiles)
+                          bool can_reveal_tiles,
+                          enum vision_layer vlayer)
 {
   /* Increase seen count. */
-  shared_vision_change_seen(ptile, pplayer, +1);
+  shared_vision_change_seen(ptile, pplayer, +1, vlayer);
 
   /* And then give the vision.  Did the tile just become visible?
    * Then send info about units and cities and the tile itself. */
@@ -602,8 +585,8 @@
       bool known = map_is_known(ptile, pplayer2);
 
       if ((!known && can_reveal_tiles)
-         || (known && map_get_seen(ptile, pplayer2) == 1)) {
-       really_unfog_tile(pplayer2, ptile);
+         || (known && map_get_seen(ptile, pplayer2, vlayer) == 1)) {
+       really_unfog_tile(pplayer2, ptile, vlayer);
       }
     }
   } players_iterate_end;
@@ -614,19 +597,24 @@
   map_fog_tile removes the last point of visibility from the tile, or when
   shared vision changes cause a tile to become fogged.
 ****************************************************************************/
-static void really_fog_tile(struct player *pplayer, struct tile *ptile)
+static void really_fog_tile(struct player *pplayer, struct tile *ptile,
+                           enum vision_layer vlayer)
 {
   freelog(LOG_DEBUG, "Fogging %i,%i. Previous fog: %i.",
-         TILE_XY(ptile), map_get_seen(ptile, pplayer));
+         TILE_XY(ptile), map_get_seen(ptile, pplayer, vlayer));
  
-  assert(map_get_seen(ptile, pplayer) == 0);
+  assert(map_get_seen(ptile, pplayer, vlayer) == 0);
 
   unit_list_iterate(ptile->units, punit)
-    unit_goes_out_of_sight(pplayer,punit);
+    if (unit_is_visible_on_layer(punit, vlayer)) {
+      unit_goes_out_of_sight(pplayer,punit);
+    }
   unit_list_iterate_end;  
 
-  update_player_tile_last_seen(pplayer, ptile);
-  send_tile_info(pplayer->connections, ptile);
+  if (vlayer == V_MAIN) {
+    update_player_tile_last_seen(pplayer, ptile);
+    send_tile_info(pplayer->connections, ptile);
+  }
 }
 
 /**************************************************************************
@@ -634,15 +622,16 @@
   NULL.  The caller may wish to buffer_shared_vision if calling this
   function multiple times.
 **************************************************************************/
-static void map_fog_tile(struct player *pplayer, struct tile *ptile)
+static void map_fog_tile(struct player *pplayer, struct tile *ptile,
+                        enum vision_layer vlayer)
 {
-  shared_vision_change_seen(ptile, pplayer, -1);
+  shared_vision_change_seen(ptile, pplayer, -1, vlayer);
 
   if (map_is_known(ptile, pplayer)) {
     players_iterate(pplayer2) {
       if (pplayer2 == pplayer || really_gives_vision(pplayer, pplayer2)) {
-       if (map_get_seen(ptile, pplayer2) == 0) {
-         really_fog_tile(pplayer2, ptile);
+       if (map_get_seen(ptile, pplayer2, vlayer) == 0) {
+         really_fog_tile(pplayer2, ptile, vlayer);
        }
       }
     } players_iterate_end;
@@ -666,14 +655,16 @@
 /**************************************************************************
 ...
 **************************************************************************/
-static void shared_vision_change_seen(struct tile *ptile, struct player 
*pplayer, int change)
+static void shared_vision_change_seen(struct tile *ptile,
+                                     struct player *pplayer, int change,
+                                     enum vision_layer vlayer)
 {
-  map_change_seen(ptile, pplayer, change);
-  map_change_own_seen(ptile, pplayer, change);
+  map_change_seen(ptile, pplayer, change, vlayer);
+  map_change_own_seen(ptile, pplayer, change, vlayer);
 
   players_iterate(pplayer2) {
     if (really_gives_vision(pplayer, pplayer2))
-      map_change_seen(ptile, pplayer2, change);
+      map_change_seen(ptile, pplayer2, change, vlayer);
   } players_iterate_end;
 }
 
@@ -682,7 +673,8 @@
 **************************************************************************/
 static void map_refog_circle(struct player *pplayer, struct tile *ptile,
                             int old_radius_sq, int new_radius_sq,
-                            bool can_reveal_tiles)
+                            bool can_reveal_tiles,
+                            enum vision_layer vlayer)
 {
   if (old_radius_sq != new_radius_sq) {
     int max_radius = MAX(old_radius_sq, new_radius_sq);
@@ -693,9 +685,9 @@
     buffer_shared_vision(pplayer);
     circle_dxyr_iterate(ptile, max_radius, tile1, dx, dy, dr) {
       if (dr > old_radius_sq && dr <= new_radius_sq) {
-       map_unfog_tile(pplayer, tile1, can_reveal_tiles);
+       map_unfog_tile(pplayer, tile1, can_reveal_tiles, vlayer);
       } else if (dr > new_radius_sq && dr <= old_radius_sq) {
-       map_fog_tile(pplayer, tile1);
+       map_fog_tile(pplayer, tile1, vlayer);
       }
     } circle_dxyr_iterate_end;
     unbuffer_shared_vision(pplayer);
@@ -722,7 +714,7 @@
       struct city *pcity;
       bool old_known = map_is_known(ptile, pplayer);
 
-      if (!map_is_known_and_seen(ptile, pplayer)) {
+      if (!map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
        map_set_known(ptile, pplayer);
 
        /* as the tile may be fogged send_tile_info won't always do this for us 
*/
@@ -739,11 +731,15 @@
          send_city_info(pplayer, pcity);
        }
 
-       if (map_get_seen(ptile, pplayer) != 0) {
-         unit_list_iterate(ptile->units, punit)
-           send_unit_info(pplayer, punit);
-         unit_list_iterate_end;
-       }
+       vision_layer_iterate(v) {
+         if (map_get_seen(ptile, pplayer, v) != 0) {
+           unit_list_iterate(ptile->units, punit)
+             if (unit_is_visible_on_layer(punit, v)) {
+               send_unit_info(pplayer, punit);
+             }
+           unit_list_iterate_end;
+         }
+       } vision_layer_iterate_end;
 
        /* If the tile was not known before we need to refresh the cities that
           can use the tile. */
@@ -805,12 +801,13 @@
 /***************************************************************
 ...
 ***************************************************************/
-bool map_is_known_and_seen(const struct tile *ptile, struct player *pplayer)
+bool map_is_known_and_seen(const struct tile *ptile, struct player *pplayer,
+                          enum vision_layer vlayer)
 {
-  assert(BV_ISSET(ptile->tile_seen, pplayer->player_no)
-        == (map_get_player_tile(ptile, pplayer)->seen_count > 0));
+  assert(BV_ISSET(ptile->tile_seen[vlayer], pplayer->player_no)
+        == (map_get_player_tile(ptile, pplayer)->seen_count[vlayer] > 0));
   return (BV_ISSET(ptile->tile_known, pplayer->player_no)
-         && BV_ISSET(ptile->tile_seen, pplayer->player_no));
+         && BV_ISSET(ptile->tile_seen[vlayer], pplayer->player_no));
 }
 
 /****************************************************************************
@@ -821,49 +818,52 @@
   this case the tile is unknown (but map_get_seen will still return TRUE).
 ****************************************************************************/
 static int map_get_seen(const struct tile *ptile,
-                       const struct player *pplayer)
+                       const struct player *pplayer,
+                       enum vision_layer vlayer)
 {
-  assert(BV_ISSET(ptile->tile_seen, pplayer->player_no)
-        == (map_get_player_tile(ptile, pplayer)->seen_count > 0));
-  return map_get_player_tile(ptile, pplayer)->seen_count;
+  assert(BV_ISSET(ptile->tile_seen[vlayer], pplayer->player_no)
+        == (map_get_player_tile(ptile, pplayer)->seen_count[vlayer] > 0));
+  return map_get_player_tile(ptile, pplayer)->seen_count[vlayer];
 }
 
 /***************************************************************
 ...
 ***************************************************************/
-void map_change_seen(struct tile *ptile, struct player *pplayer, int change)
+void map_change_seen(struct tile *ptile, struct player *pplayer, int change,
+                    enum vision_layer vlayer)
 {
   struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
 
-  assert(0 <= change || -change <= plrtile->seen_count); /* else underflow */
+  /* assert to avoid underflow */
+  assert(0 <= change || -change <= plrtile->seen_count[vlayer]);
 
-  plrtile->seen_count += change;
-  if (plrtile->seen_count != 0) {
-    BV_SET(ptile->tile_seen, pplayer->player_no);
+  plrtile->seen_count[vlayer] += change;
+  if (plrtile->seen_count[vlayer] != 0) {
+    BV_SET(ptile->tile_seen[vlayer], pplayer->player_no);
   } else {
-    BV_CLR(ptile->tile_seen, pplayer->player_no);
+    BV_CLR(ptile->tile_seen[vlayer], pplayer->player_no);
   }
   freelog(LOG_DEBUG, "%d,%d, p: %d, change %d, result %d\n", TILE_XY(ptile),
-         pplayer->player_no, change, plrtile->seen_count);
+         pplayer->player_no, change, plrtile->seen_count[vlayer]);
 }
 
 /***************************************************************
 ...
 ***************************************************************/
-static int map_get_own_seen(struct tile *ptile, struct player *pplayer)
+static int map_get_own_seen(struct tile *ptile, struct player *pplayer,
+                           enum vision_layer vlayer)
 {
-  int own_seen = map_get_player_tile(ptile, pplayer)->own_seen;
-
-  return own_seen;
+  return map_get_player_tile(ptile, pplayer)->own_seen[vlayer];
 }
 
 /***************************************************************
 ...
 ***************************************************************/
 static void map_change_own_seen(struct tile *ptile, struct player *pplayer,
-                               int change)
+                               int change,
+                               enum vision_layer vlayer)
 {
-  map_get_player_tile(ptile, pplayer)->own_seen += change;
+  map_get_player_tile(ptile, pplayer)->own_seen[vlayer] += change;
 }
 
 /***************************************************************
@@ -892,7 +892,9 @@
   buffer_shared_vision(pplayer);
 
   whole_map_iterate(ptile) {
-    map_unfog_tile(pplayer, ptile, TRUE);
+    vision_layer_iterate(v) {
+      map_unfog_tile(pplayer, ptile, TRUE, v);
+    } vision_layer_iterate_end;
   } whole_map_iterate_end;
 
   unbuffer_shared_vision(pplayer);
@@ -955,17 +957,21 @@
   BV_CLR_ALL(plrtile->special);
   plrtile->city = NULL;
 
-  plrtile->seen_count = 0;
-  BV_CLR(ptile->tile_seen, pplayer->player_no);
+  vision_layer_iterate(v) {
+    plrtile->seen_count[v] = 0;
+    BV_CLR(ptile->tile_seen[v], pplayer->player_no);
+  } vision_layer_iterate_end
   if (!game.fogofwar_old) {
-    plrtile->seen_count = 1;
+    plrtile->seen_count[V_MAIN] = 1;
     if (map_is_known(ptile, pplayer)) {
-      BV_SET(ptile->tile_seen, pplayer->player_no);
+      BV_SET(ptile->tile_seen[V_MAIN], pplayer->player_no);
     }
   }
 
   plrtile->last_updated = GAME_START_YEAR;
-  plrtile->own_seen = plrtile->seen_count;
+  vision_layer_iterate(v) {
+    plrtile->own_seen[v] = plrtile->seen_count[v];
+  } vision_layer_iterate_end;
 }
 
 /****************************************************************************
@@ -1012,7 +1018,7 @@
 {
   /* Players */
   players_iterate(pplayer) {
-    if (map_is_known_and_seen(ptile, pplayer)) {
+    if (map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
       if (update_player_tile_knowledge(pplayer, ptile)) {
         send_tile_info(pplayer->connections, ptile);
       }
@@ -1044,7 +1050,7 @@
                                                        struct tile *ptile)
 {
   struct player_tile *from_tile, *dest_tile;
-  if (!map_is_known_and_seen(ptile, pdest)) {
+  if (!map_is_known_and_seen(ptile, pdest, V_MAIN)) {
     /* I can just hear people scream as they try to comprehend this if :).
      * Let me try in words:
      * 1) if the tile is seen by pfrom the info is sent to pdest
@@ -1052,7 +1058,7 @@
      * 2) if the tile is known by pfrom AND (he has more recent info
      *     OR it is not known by pdest)
      */
-    if (map_is_known_and_seen(ptile, pfrom)
+    if (map_is_known_and_seen(ptile, pfrom, V_MAIN)
        || (map_is_known(ptile, pfrom)
            && (((map_get_player_tile(ptile, pfrom)->last_updated
                 > map_get_player_tile(ptile, pdest)->last_updated))
@@ -1182,14 +1188,17 @@
        freelog(LOG_DEBUG, "really giving shared vision from %s to %s\n",
               pplayer->name, pplayer2->name);
        whole_map_iterate(ptile) {
-         int change = map_get_own_seen(ptile, pplayer);
-         if (change != 0) {
-           map_change_seen(ptile, pplayer2, change);
-           if (map_get_seen(ptile, pplayer2) == change
-               && map_is_known(ptile, pplayer)) {
-             really_unfog_tile(pplayer2, ptile);
+         vision_layer_iterate(v) {
+           int change = map_get_own_seen(ptile, pplayer, v);
+
+           if (change != 0) {
+             map_change_seen(ptile, pplayer2, change, v);
+             if (map_get_seen(ptile, pplayer2, v) == change
+                 && map_is_known(ptile, pplayer)) {
+               really_unfog_tile(pplayer2, ptile, v);
+             }
            }
-         }
+         } vision_layer_iterate_end;
        } whole_map_iterate_end;
 
        /* squares that are not seen, but which pfrom may have more recent
@@ -1236,12 +1245,15 @@
        freelog(LOG_DEBUG, "really removing shared vision from %s to %s\n",
               pplayer->name, pplayer2->name);
        whole_map_iterate(ptile) {
-         int change = map_get_own_seen(ptile, pplayer);
-         if (change > 0) {
-           map_change_seen(ptile, pplayer2, -change);
-           if (map_get_seen(ptile, pplayer2) == 0)
-             really_fog_tile(pplayer2, ptile);
-         }
+         vision_layer_iterate(v) {
+           int change = map_get_own_seen(ptile, pplayer, v);
+
+           if (change > 0) {
+             map_change_seen(ptile, pplayer2, -change, v);
+             if (map_get_seen(ptile, pplayer2, v) == 0)
+               really_fog_tile(pplayer2, ptile, v);
+           }
+         } vision_layer_iterate_end;
        } whole_map_iterate_end;
       }
     } players_iterate_end;
@@ -1260,7 +1272,7 @@
 {
   buffer_shared_vision(pplayer);
   whole_map_iterate(ptile) {
-    map_fog_tile(pplayer, ptile);
+    map_fog_tile(pplayer, ptile, V_MAIN);
   } whole_map_iterate_end;
   unbuffer_shared_vision(pplayer);
 }
@@ -1282,7 +1294,7 @@
 {
   buffer_shared_vision(pplayer);
   whole_map_iterate(ptile) {
-    map_unfog_tile(pplayer, ptile, FALSE);
+    map_unfog_tile(pplayer, ptile, FALSE, V_MAIN);
   } whole_map_iterate_end;
   unbuffer_shared_vision(pplayer);
 }
@@ -1695,7 +1707,7 @@
   bool can_reveal_tiles;
 
   /* The radius of the vision source. */
-  int radius_sq;
+  int radius_sq[V_COUNT];
 };
 
 /****************************************************************************
@@ -1711,7 +1723,9 @@
   vision->player = pplayer;
   vision->tile = ptile;
   vision->can_reveal_tiles = can_reveal_tiles;
-  vision->radius_sq = -1;
+  vision_layer_iterate(v) {
+    vision->radius_sq[v] = -1;
+  } vision_layer_iterate_end;
 
   return vision;
 }
@@ -1721,9 +1735,9 @@
 
   See documentation in maphand.h.
 ****************************************************************************/
-int vision_get_sight(const struct vision *vision)
+int vision_get_sight(const struct vision *vision, enum vision_layer vlayer)
 {
-  return vision->radius_sq;
+  return vision->radius_sq[vlayer];
 }
 
 /****************************************************************************
@@ -1732,22 +1746,28 @@
 
   See documentation in maphand.h.
 ****************************************************************************/
-void vision_change_sight(struct vision *vision, int radius_sq)
+void vision_change_sight(struct vision *vision, enum vision_layer vlayer,
+                        int radius_sq)
 {
   map_refog_circle(vision->player, vision->tile,
-                  vision->radius_sq, radius_sq,
-                  vision->can_reveal_tiles);
-  vision->radius_sq = radius_sq;
+                  vision->radius_sq[vlayer], radius_sq,
+                  vision->can_reveal_tiles, vlayer);
+  vision->radius_sq[vlayer] = radius_sq;
+
+  assert(vision->radius_sq[V_MAIN] >= vision->radius_sq[V_INVIS]);
 }
 
 /****************************************************************************
-  Clear all sight poitns from this vision source.
+  Clear all sight points from this vision source.
 
   See documentation in maphand.h.
 ****************************************************************************/
 void vision_clear_sight(struct vision *vision)
 {
-  vision_change_sight(vision, -1);
+  /* We don't use vision_layer_iterate because we have to go in reverse
+   * order. */
+  vision_change_sight(vision, V_INVIS, -1);
+  vision_change_sight(vision, V_MAIN, -1);
 }
 
 /****************************************************************************
@@ -1757,6 +1777,7 @@
 ****************************************************************************/
 void vision_free(struct vision *vision)
 {
-  assert(server_state != RUN_GAME_STATE || vision->radius_sq < 0);
+  assert(server_state != RUN_GAME_STATE || vision->radius_sq[V_MAIN] < 0);
+  assert(server_state != RUN_GAME_STATE || vision->radius_sq[V_INVIS] < 0);
   free(vision);
 }
Index: server/maphand.h
===================================================================
--- server/maphand.h    (revision 11148)
+++ server/maphand.h    (working copy)
@@ -39,8 +39,8 @@
 struct player_tile {
   struct terrain *terrain; /* May be NULL for unknown tiles. */
   bv_special special;
-  unsigned short seen_count;
-  unsigned short own_seen;
+  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
@@ -59,8 +59,6 @@
                                        struct player *pfrom, struct player 
*pdest);
 void send_all_known_tiles(struct conn_list *dest);
 void send_tile_info(struct conn_list *dest, struct tile *ptile);
-void reveal_hidden_units(struct player *pplayer, struct tile *ptile);
-void conceal_hidden_units(struct player *pplayer, struct tile *ptile);
 void upgrade_city_rails(struct player *pplayer, bool discovery);
 void send_map_info(struct conn_list *dest);
 
@@ -69,8 +67,10 @@
                     struct tile *ptile, int radius_sq);
 void map_show_all(struct player *pplayer);
 
-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);
+bool map_is_known_and_seen(const struct tile *ptile, struct player *pplayer,
+                          enum vision_layer vlayer);
+void map_change_seen(struct tile *ptile, struct player *pplayer, int change,
+                    enum vision_layer vlayer);
 bool map_is_known(const struct tile *ptile, const struct player *pplayer);
 void map_set_known(struct tile *ptile, struct player *pplayer);
 void map_clear_known(struct tile *ptile, struct player *pplayer);
@@ -151,8 +151,9 @@
 struct vision;
 struct vision *vision_new(struct player *pplayer, struct tile *ptile,
                          bool can_reveal_tiles);
-int vision_get_sight(const struct vision *vision);
-void vision_change_sight(struct vision *vision, int radius_sq);
+int vision_get_sight(const struct vision *vision, enum vision_layer vlayer);
+void vision_change_sight(struct vision *vision, enum vision_layer vlayer,
+                        int radius_sq);
 void vision_clear_sight(struct vision *vision);
 void vision_free(struct vision *vision);
 
Index: server/diplhand.c
===================================================================
--- server/diplhand.c   (revision 11148)
+++ server/diplhand.c   (working copy)
@@ -587,7 +587,7 @@
     if (type == CLAUSE_CITY) {
       struct city *pcity = find_city_by_id(value);
 
-      if (pcity && !map_is_known_and_seen(pcity->tile, pother))
+      if (pcity && !map_is_known_and_seen(pcity->tile, pother, V_MAIN))
        give_citymap_from_player_to_player(pcity, pplayer, pother);
     }
 
Index: server/unittools.c
===================================================================
--- server/unittools.c  (revision 11148)
+++ server/unittools.c  (working copy)
@@ -1027,7 +1027,7 @@
 
   adjc_iterate(ptile, ptile1) {
     if (ai_handicap(pplayer, H_FOG)
-       && !map_is_known_and_seen(ptile1, unit_owner(punit))) {
+       && !map_is_known_and_seen(ptile1, unit_owner(punit), V_MAIN)) {
       /* We cannot see danger at (ptile1) => assume there is none */
       continue;
     }
@@ -1179,7 +1179,7 @@
      * candidates.  This solution just tells the client to drop all such
      * units.  If any of these are unknown to the client the client will
      * just ignore them. */
-    if (map_is_known_and_seen(punit->tile, pplayer) &&
+    if (map_is_known_and_seen(punit->tile, pplayer, V_MAIN) &&
         !can_player_see_unit(pplayer, punit)) {
       unit_goes_out_of_sight(pplayer, punit);
     }
@@ -1189,7 +1189,7 @@
     /* The player used to know what units were in these cities.  Now that he
      * doesn't, he needs to get a new short city packet updating the
      * occupied status. */
-    if (map_is_known_and_seen(pcity->tile, pplayer)) {
+    if (map_is_known_and_seen(pcity->tile, pplayer, V_MAIN)) {
       send_city_info(pplayer, pcity);
     }
   } city_list_iterate_end;
@@ -1365,7 +1365,6 @@
   struct city *pcity = tile_get_city(punit->tile);
   struct city *phomecity = find_city_by_id(punit->homecity);
   struct tile *unit_tile = punit->tile;
-  struct player *unitowner = unit_owner(punit);
 
 #ifndef NDEBUG
   unit_list_iterate(punit->tile->units, pcargo) {
@@ -1383,7 +1382,7 @@
   }
 
   players_iterate(pplayer) {
-    if (map_is_known_and_seen(unit_tile, pplayer)) {
+    if (can_player_see_unit(pplayer, punit)) {
       dlsend_packet_unit_remove(pplayer->connections, punit->id);
     }
   } players_iterate_end;
@@ -1407,9 +1406,6 @@
   game_remove_unit(punit);
   punit = NULL;
 
-  /* Hide any submarines that are no longer visible. */
-  conceal_hidden_units(unitowner, unit_tile);
-
   /* This unit may have blocked tiles of adjacent cities. Update them. */
   map_city_radius_iterate(unit_tile, ptile1) {
     struct city *pcity = tile_get_city(ptile1);
@@ -1925,8 +1921,7 @@
     for(p=0; p<game.info.nplayers; p++) { /* send the players units */
       struct player *unitowner = &game.players[p];
       unit_list_iterate(unitowner->units, punit) {
-       if (!pplayer
-           || map_is_known_and_seen(punit->tile, pplayer)) {
+       if (!pplayer || can_player_see_unit(pplayer, punit)) {
          send_unit_info_to_onlookers(pconn->self, punit,
                                      punit->tile, FALSE);
        }
@@ -2089,7 +2084,7 @@
     return FALSE;
   }
 
-  if (map_is_known_and_seen(ptile, pplayer)
+  if (map_is_known_and_seen(ptile, pplayer, V_MAIN)
       && ((ptile->city
          && pplayers_non_attack(pplayer, city_owner(ptile->city)))
       || is_non_attack_unit_tile(ptile, pplayer))) {
@@ -2494,7 +2489,7 @@
      wake them up if the punit is farther away than 3. */
   square_iterate(punit->tile, 3, ptile) {
     unit_list_iterate(ptile->units, penemy) {
-      int radius_sq = get_unit_vision_at(penemy, penemy->tile);
+      int radius_sq = get_unit_vision_at(penemy, penemy->tile, V_MAIN);
       enum unit_move_type move_type = unit_type(penemy)->move_type;
       struct terrain *pterrain = tile_get_terrain(ptile);
 
@@ -2680,8 +2675,10 @@
       struct vision *old_vision = pcargo->server.vision;
 
       pcargo->server.vision = vision_new(pcargo->owner, pdesttile, TRUE);
-      vision_change_sight(pcargo->server.vision,
-                         get_unit_vision_at(pcargo, pdesttile));
+      vision_layer_iterate(v) {
+       vision_change_sight(pcargo->server.vision, v,
+                           get_unit_vision_at(pcargo, pdesttile, v));
+      } vision_layer_iterate_end;
 
       /* Silently free orders since they won't be applicable anymore. */
       free_unit_orders(pcargo);
@@ -2709,8 +2706,10 @@
 
   /* Enhance vision if unit steps into a fortress */
   punit->server.vision = vision_new(punit->owner, pdesttile, TRUE);
-  vision_change_sight(punit->server.vision,
-                     get_unit_vision_at(punit, pdesttile));
+  vision_layer_iterate(v) {
+    vision_change_sight(punit->server.vision, v,
+                       get_unit_vision_at(punit, pdesttile, v));
+  } vision_layer_iterate_end;
 
   unit_list_unlink(psrctile->units, punit);
   punit->tile = pdesttile;
@@ -2784,11 +2783,6 @@
     refresh_dumb_city(pcity);
   }
 
-  /* The hidden units might not have been previously revealed 
-   * because when we did the unfogging, the unit was still 
-   * at (src_x, src_y) */
-  reveal_hidden_units(pplayer, pdesttile);
-
   vision_clear_sight(old_vision);
   vision_free(old_vision);
 
@@ -2883,7 +2877,7 @@
 static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit)
 {
   bool cancel = FALSE;
-  int radius_sq = get_unit_vision_at(punit, punit->tile);
+  int radius_sq = get_unit_vision_at(punit, punit->tile, V_MAIN);
   struct player *pplayer = unit_owner(punit);
 
   circle_iterate(punit->tile, radius_sq, ptile) {
@@ -3172,11 +3166,23 @@
   Note that vision MUST be independent of transported_by for this to work
   properly.
 ****************************************************************************/
-int get_unit_vision_at(struct unit *punit, struct tile *ptile)
+int get_unit_vision_at(struct unit *punit, struct tile *ptile,
+                      enum vision_layer vlayer)
 {
-  return (punit->type->vision_radius_sq
-         + get_unittype_bonus(punit->owner, ptile, punit->type,
-                              EFT_UNIT_VISION_RADIUS_SQ));
+  const int base = (punit->type->vision_radius_sq
+                   + get_unittype_bonus(punit->owner, ptile, punit->type,
+                                        EFT_UNIT_VISION_RADIUS_SQ));
+  switch (vlayer) {
+  case V_MAIN:
+    return base;
+  case V_INVIS:
+    return MIN(base, 2);
+  case V_COUNT:
+    break;
+  }
+
+  assert(0);
+  return 0;
 }
 
 /****************************************************************************
@@ -3187,8 +3193,12 @@
 ****************************************************************************/
 void unit_refresh_vision(struct unit *punit)
 {
-  vision_change_sight(punit->server.vision,
-                     get_unit_vision_at(punit, punit->tile));
+  vision_layer_iterate(v) {
+    /* This requires two calls to get_unit_vision_at...it could be
+     * optimized. */
+    vision_change_sight(punit->server.vision, v,
+                       get_unit_vision_at(punit, punit->tile, v));
+  } vision_layer_iterate_end;
 }
 
 /****************************************************************************
Index: server/sanitycheck.c
===================================================================
--- server/sanitycheck.c        (revision 11148)
+++ server/sanitycheck.c        (working copy)
@@ -86,17 +86,26 @@
   whole_map_iterate(ptile) {
     players_iterate(pplayer) {
       struct player_tile *plr_tile = map_get_player_tile(ptile, pplayer);
-      /* underflow of unsigned int */
-      SANITY_CHECK(plr_tile->seen_count < 60000);
-      SANITY_CHECK(plr_tile->own_seen < 60000);
 
-      if (plr_tile->seen_count > 0) {
-       SANITY_CHECK(BV_ISSET(ptile->tile_seen, pplayer->player_no));
-      } else {
-       SANITY_CHECK(!BV_ISSET(ptile->tile_seen, pplayer->player_no));
-      }
+      vision_layer_iterate(v) {
+       /* underflow of unsigned int */
+       SANITY_CHECK(plr_tile->seen_count[v] < 60000);
+       SANITY_CHECK(plr_tile->own_seen[v] < 60000);
 
-      SANITY_CHECK(plr_tile->own_seen <= plr_tile->seen_count);
+       if (plr_tile->seen_count[v] > 0) {
+         SANITY_CHECK(BV_ISSET(ptile->tile_seen[v], pplayer->player_no));
+       } else {
+         SANITY_CHECK(!BV_ISSET(ptile->tile_seen[v], pplayer->player_no));
+       }
+
+       SANITY_CHECK(plr_tile->own_seen[v] <= plr_tile->seen_count[v]);
+      } vision_layer_iterate_end;
+
+      /* Lots of server bits depend on this. */
+      SANITY_CHECK(plr_tile->seen_count[V_INVIS]
+                  <= plr_tile->seen_count[V_MAIN]);
+      SANITY_CHECK(plr_tile->own_seen[V_INVIS]
+                  <= plr_tile->own_seen[V_MAIN]);
     } players_iterate_end;
   } whole_map_iterate_end;
 
Index: server/unittools.h
===================================================================
--- server/unittools.h  (revision 11148)
+++ server/unittools.h  (working copy)
@@ -46,7 +46,8 @@
 void resolve_unit_stacks(struct player *pplayer, struct player *aplayer,
                          bool verbose);
 void remove_allied_visibility(struct player* pplayer, struct player* aplayer);
-int get_unit_vision_at(struct unit *punit, struct tile *ptile);
+int get_unit_vision_at(struct unit *punit, struct tile *ptile,
+                      enum vision_layer vlayer);
 void unit_refresh_vision(struct unit *punit);
 void unit_list_refresh_vision(struct unit_list *punitlist);
 void pay_for_units(struct player *pplayer, struct city *pcity);
Index: server/unithand.c
===================================================================
--- server/unithand.c   (revision 11148)
+++ server/unithand.c   (working copy)
@@ -289,7 +289,6 @@
   if (old_owner != new_owner) {
     vision_clear_sight(punit->server.vision);
     vision_free(punit->server.vision);
-    conceal_hidden_units(old_owner, punit->tile);
 
     ai_reinit(punit);
 
@@ -299,7 +298,6 @@
 
     punit->server.vision = vision_new(new_owner, punit->tile, TRUE);
     unit_refresh_vision(punit);
-    reveal_hidden_units(new_owner, punit->tile);
   }
 
   punit->homecity = new_pcity->id;
@@ -623,8 +621,10 @@
   package_short_unit(pdefender, &unit_def_short_packet, FALSE,
                     UNIT_INFO_IDENTITY, 0);
   players_iterate(other_player) {
-    if (map_is_known_and_seen(pattacker->tile, other_player)
-       || map_is_known_and_seen(pdefender->tile, other_player)) {
+    /* NOTE: this means the player can see combat between submarines even
+     * if neither sub is visible.  See similar comment in send_combat. */
+    if (map_is_known_and_seen(pattacker->tile, other_player, V_MAIN)
+       || map_is_known_and_seen(pdefender->tile, other_player, V_MAIN)) {
       if (!can_player_see_unit(other_player, pattacker)) {
        assert(other_player != pattacker->owner);
        lsend_packet_unit_short_info(other_player->connections,
@@ -655,8 +655,10 @@
   combat.make_winner_veteran=veteran;
 
   players_iterate(other_player) {
-    if (map_is_known_and_seen(pattacker->tile, other_player)
-       || map_is_known_and_seen(pdefender->tile, other_player)) {
+    /* NOTE: this means the player can see combat between submarines even
+     * if neither sub is visible.  See similar comment in see_combat. */
+    if (map_is_known_and_seen(pattacker->tile, other_player, V_MAIN)
+       || map_is_known_and_seen(pdefender->tile, other_player, V_MAIN)) {
       lsend_packet_unit_combat_info(other_player->connections, &combat);
 
       /* 
Index: server/savegame.c
===================================================================
--- server/savegame.c   (revision 11148)
+++ server/savegame.c   (working copy)
@@ -2271,9 +2271,7 @@
   int i;
 
   if (!plr->is_alive)
-    whole_map_iterate(ptile) {
-      map_change_seen(ptile, plr, +1);
-    } whole_map_iterate_end;
+    map_know_and_see_all(plr);
 
   /* load map if:
      1) it from a fog of war build
@@ -2382,7 +2380,7 @@
     /* This shouldn't be neccesary if the savegame was consistent, but there
        is a bug in some pre-1.11 savegames. Anyway, it can't hurt */
     whole_map_iterate(ptile) {
-      if (map_is_known_and_seen(ptile, plr)) {
+      if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
        update_player_tile_knowledge(plr, ptile);
        reality_check_city(plr, ptile);
        if (tile_get_city(ptile)) {
Index: common/tile.c
===================================================================
--- common/tile.c       (revision 11148)
+++ common/tile.c       (working copy)
@@ -150,7 +150,7 @@
 {
   if (!BV_ISSET(ptile->tile_known, pplayer->player_no)) {
     return TILE_UNKNOWN;
-  } else if (!BV_ISSET(ptile->tile_seen, pplayer->player_no)) {
+  } else if (!BV_ISSET(ptile->tile_seen[V_MAIN], pplayer->player_no)) {
     return TILE_KNOWN_FOGGED;
   } else {
     return TILE_KNOWN;
Index: common/tile.h
===================================================================
--- common/tile.h       (revision 11148)
+++ common/tile.h       (working copy)
@@ -32,7 +32,7 @@
   bv_special special;
   struct city *city;        /* city standing on the tile, NULL if none */
   struct unit_list *units;
-  bv_player tile_known, tile_seen;
+  bv_player tile_known, tile_seen[V_COUNT];
   struct city *worked;      /* city working tile, or NULL if none */
   Continent_id continent;
   struct player *owner;     /* Player owning this tile, or NULL. */
Index: common/fc_types.h
===================================================================
--- common/fc_types.h   (revision 11148)
+++ common/fc_types.h   (working copy)
@@ -71,6 +71,14 @@
   SSET_LAST
 };
 
+/* Invariants: V_MAIN vision ranges must always be more than V_INVIS
+ * ranges. */
+enum vision_layer {
+  V_MAIN,
+  V_INVIS,
+  V_COUNT
+};
+
 enum output_type_id {
   O_FOOD, O_SHIELD, O_TRADE, O_GOLD, O_LUXURY, O_SCIENCE, O_LAST
 };
Index: common/player.c
===================================================================
--- common/player.c     (revision 11148)
+++ common/player.c     (working copy)
@@ -290,19 +290,8 @@
     return TRUE;
   }
 
-  /* Hiding units may only be seen by adjacent allied units or cities. */
-  /* FIXME: shouldn't a check for shared vision be done here? */
-  adjc_iterate(ptile, ptile1) {
-    struct city *pcity = tile_get_city(ptile1);
-    if (pcity && pplayers_allied(city_owner(pcity), pplayer)) {
-      return TRUE;
-    }  
-    unit_list_iterate(ptile1->units, punit2) {
-      if (pplayers_allied(unit_owner(punit2), pplayer)) {
-       return TRUE;
-      }
-    } unit_list_iterate_end;
-  } adjc_iterate_end;
+  /* Hiding units are only seen by the V_INVIS fog layer. */
+  return BV_ISSET(ptile->tile_seen[V_INVIS], pplayer->player_no);
 
   return FALSE;
 }
Index: common/map.c
===================================================================
--- common/map.c        (revision 11148)
+++ common/map.c        (working copy)
@@ -269,7 +269,9 @@
   ptile->terrain  = T_UNKNOWN;
   BV_CLR_ALL(ptile->special);
   BV_CLR_ALL(ptile->tile_known);
-  BV_CLR_ALL(ptile->tile_seen);
+  vision_layer_iterate(v) {
+    BV_CLR_ALL(ptile->tile_seen[v]);
+  } vision_layer_iterate_end;
   ptile->continent = 0;
   ptile->city     = NULL;
   ptile->units    = unit_list_new();
Index: common/map.h
===================================================================
--- common/map.h        (revision 11148)
+++ common/map.h        (working copy)
@@ -257,6 +257,16 @@
 
 extern struct terrain_misc terrain_control;
 
+#define vision_layer_iterate(vision)                                       \
+  {                                                                        \
+    enum vision_layer vision;                                              \
+                                                                           \
+  for (vision = 0; vision < V_COUNT; vision++) {
+
+#define vision_layer_iterate_end                                           \
+  }                                                                        \
+}
+
 /* This iterates outwards from the starting point. Every tile within max_dist
  * will show up exactly once, in an outward (based on real map distance)
  * order.  The returned values are always real and are normalized.  The
Index: ai/aiair.c
===================================================================
--- ai/aiair.c  (revision 11148)
+++ ai/aiair.c  (working copy)
@@ -191,7 +191,7 @@
       continue;
     }
     if (ai_handicap(pplayer, H_FOG) 
-        && !map_is_known_and_seen(tile1, pplayer)) {
+        && !map_is_known_and_seen(tile1, pplayer, V_MAIN)) {
       /* The tile is fogged */
       continue;
     }
Index: ai/aiunit.c
===================================================================
--- ai/aiunit.c (revision 11148)
+++ ai/aiunit.c (working copy)
@@ -632,7 +632,7 @@
     }
 
     if (ai_handicap(pplayer, H_TARGETS) 
-        && !map_is_known_and_seen(pos.tile, pplayer)) {
+        && !map_is_known_and_seen(pos.tile, pplayer, V_MAIN)) {
       /* The target is under fog of war */
       continue;
     }
Index: client/packhand.c
===================================================================
--- client/packhand.c   (revision 11148)
+++ client/packhand.c   (working copy)
@@ -1928,11 +1928,15 @@
   }
   if (game.player_ptr) {
     BV_CLR(ptile->tile_known, game.info.player_idx);
-    BV_CLR(ptile->tile_seen, game.info.player_idx);
+    vision_layer_iterate(v) {
+      BV_CLR(ptile->tile_seen[v], game.info.player_idx);
+    } vision_layer_iterate_end;
     switch (packet->known) {
     case TILE_KNOWN:
       BV_SET(ptile->tile_known, game.info.player_idx);
-      BV_SET(ptile->tile_seen, game.info.player_idx);
+      vision_layer_iterate(v) {
+       BV_SET(ptile->tile_seen[v], game.info.player_idx);
+      } vision_layer_iterate_end;
       break;
     case TILE_KNOWN_FOGGED:
       BV_SET(ptile->tile_known, game.info.player_idx);

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#14356) use fog-of-war for submarines, Jason Short <=