Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2003:
[Freeciv-Dev] Re: (PR#4645) Silent Hunter and Sonar code.
Home

[Freeciv-Dev] Re: (PR#4645) Silent Hunter and Sonar code.

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#4645) Silent Hunter and Sonar code.
From: "Rafa³ Bursig" <bursig@xxxxxxxxx>
Date: Thu, 24 Jul 2003 05:08:53 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Dnia 2003.07.23 16:13, Per I. Mathisen napisa³(a):
> 
> On Tue, 22 Jul 2003, Rafa³ Bursig wrote:
> > Secundo: This will make sub and destroyer units usefull again, as I
> > know current we have problem with it.
> 
> Actually, subs should be quite useful in the cvs version already. 
> They have been upgraded rather much. In fact, I do _not_ think that 
> further invisibility rules is going to make the sub much better. 
> Attack and movement are much more important, the major disadvantage 
> with of is that they cannot attack land targets.
> 
and what you got :
- attack stronger that battelship
- fast like cruiser
- can carry missels
- cost like Destroyer

this is best ship in game and is avilable before others

> > Secundo: what happen when you try enter on tile with one ally unit
> and one at_peace unit (you know about this unit) ?
> 
> It is not allowed.
> 
and SH should not allow it.

> > > Finally, the AI will have to see these units with its
> omniscience.
> > > Otherwise a lot of AI code must be rewritten.
> > > But that removes muchof the point of adding them in the first
> > > place, since they cannot beused for single-player. (The same is
> > > already the case for F_PARTIAL_INVIS, BTW, but I plan to fix that
> one
> > > day. That won't be hard.)
> > hmm... why it can be use with single-player ?
> > you can always use it agians AI.
> 
> No, my point is: The AI can see all invisible units. So this new
> ability will not work against the AI.
> 
> > > The concepts are interesting, but I do not think we should be
> > > introducing them at this time. We have enough code-breaking
> > > patches queued up for the nextrelease as it is.
> 
> > I know about it and I plan this change after our primary 1.15
> changes :)
> 
> Well, for the record, I am against the switching of attack and 
> defense feature. I would like total invisibility to go in some time 
> in the future, but not 1.15 and not as any high priority. They should 
> also be called F_INVIS and F_SEE_INVIS, I think, to be more general.
this wont switch any parms only normal SH units will auto attack any 
'finder' units and I don't care what will be the names.
But you have right we have much work with primary 1.15 code then I'm 
stop working on SH now.

Now I sent my last devel version of this code , it has many bugs but 
some nice ideas too then please look on it.

Rafal
diff -u -r freeciv/client/clinet.c fc/client/clinet.c
--- freeciv/client/clinet.c     Thu Jul 10 13:36:39 2003
+++ fc/client/clinet.c  Wed Jul 23 17:37:12 2003
@@ -217,6 +217,8 @@
   /* call gui-dependent stuff in gui_main.c */
   add_net_input(aconnection.sock);
 
+  aconnection.player = game.player_ptr;
+  
   /* now send join_request package */
 
   sz_strlcpy(req.short_name, username);
diff -u -r freeciv/client/control.c fc/client/control.c
--- freeciv/client/control.c    Thu Jul 24 12:24:09 2003
+++ fc/client/control.c Wed Jul 23 18:08:30 2003
@@ -1247,8 +1225,8 @@
 **************************************************************************/
 void do_move_unit(struct unit *punit, struct packet_unit_info *pinfo)
 {
-  int x, y;
-  bool was_teleported;
+  int x, y, vision_range;
+  bool was_teleported, sonar;
   
   was_teleported=!is_tiles_adjacent(punit->x, punit->y, pinfo->x, pinfo->y);
   x=punit->x;
@@ -1261,20 +1239,23 @@
 
   unit_list_unlink(&map_get_tile(x, y)->units, punit);
 
-  if(!pinfo->carried)
+  if (!pinfo->carried) {
     refresh_tile_mapcanvas(x, y, FALSE);
+  }
   
-  if(game.player_idx==punit->owner && punit->activity!=ACTIVITY_GOTO && 
+  if (game.player_idx==punit->owner && punit->activity!=ACTIVITY_GOTO && 
      auto_center_on_unit && punit->activity!=ACTIVITY_SENTRY &&
-     !tile_visible_and_not_on_border_mapcanvas(pinfo->x, pinfo->y))
+     !tile_visible_and_not_on_border_mapcanvas(pinfo->x, pinfo->y)) {
     center_tile_mapcanvas(pinfo->x, pinfo->y);
+  }
 
-  if(!pinfo->carried && !was_teleported) {
+  if (!pinfo->carried && !was_teleported) {
     int dx, dy;
 
     map_distance_vector(&dx, &dy, punit->x, punit->y, pinfo->x, pinfo->y);
-    if(smooth_move_units)
+    if (smooth_move_units) {
       move_unit_map_canvas(punit, x, y, dx, dy);
+    }
     refresh_tile_mapcanvas(x, y, FALSE);
   }
     
@@ -1284,10 +1265,16 @@
   punit->hp=pinfo->hp;
   unit_list_insert(&map_get_tile(punit->x, punit->y)->units, punit);
 
-  square_iterate(punit->x, punit->y, 2, x, y) {
+  vision_range = get_unit_vision_range(punit);
+  sonar = unit_flag(punit, F_SONAR);
+  square_iterate(punit->x, punit->y, vision_range, x, y) {
     bool refresh = FALSE;
+    if (x == punit->x && y == punit->y) {
+      continue;
+    }
     unit_list_iterate(map_get_tile(x, y)->units, pu) {
-      if (unit_flag(pu, F_PARTIAL_INVIS)) {
+      if (unit_flag(pu, F_PARTIAL_INVIS)
+        || (sonar && unit_flag(pu, F_SILENT_HUNTER))) {
        refresh = TRUE;
        goto out;
       }
@@ -1298,10 +1285,13 @@
     }
   } square_iterate_end;
   
-  if(!pinfo->carried && tile_get_known(punit->x,punit->y) == TILE_KNOWN)
+  if (!pinfo->carried && tile_get_known(punit->x, punit->y) == TILE_KNOWN) {
     refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
+  }
 
-  if(get_unit_in_focus()==punit) update_menus();
+  if (get_unit_in_focus()==punit) {
+    update_menus();
+  }
 }
 
 /**************************************************************************
diff -u -r freeciv/client/packhand.c fc/client/packhand.c
--- freeciv/client/packhand.c   Thu Jul 24 12:24:10 2003
+++ fc/client/packhand.c        Wed Jul 23 16:03:57 2003
@@ -981,8 +981,7 @@
       moved = TRUE;
       
       if(tile_get_known(packet->x, packet->y) == TILE_KNOWN
-         && player_can_see_unit_at_location(game.player_ptr, punit, 
-                                            packet->x, packet->y)) {
+       && TEST_BIT(packet->seen, game.player_ptr->player_no)) {
        do_move_unit(punit, packet);
        update_unit_focus();
       }
@@ -1090,6 +1089,16 @@
     }
   }
 
+  /* initialize client side unit 'seen' parm. */
+  players_iterate(pplayer) {
+    if(pplayer == unit_owner(punit)) {
+      continue;
+    }
+    punit->seen |=
+               COND_SET_BIT(pplayers_allied(unit_owner(punit), pplayer),
+                                                       pplayer->player_no);
+  } players_iterate_end
+    
   if (punit && punit == get_unit_in_focus()) {
     update_unit_info_label(punit);
   } else if (get_unit_in_focus()
diff -u -r freeciv/common/packets.c fc/common/packets.c
--- freeciv/common/packets.c    Thu Jul 24 12:24:14 2003
+++ fc/common/packets.c Wed Jul 23 17:03:04 2003
@@ -1265,7 +1259,8 @@
 
   dio_put_uint16(&dout, req->id);
   dio_put_uint8(&dout, req->owner);
-  pack = (COND_SET_BIT(req->carried, 3) |
+  pack = (COND_SET_BIT(TEST_BIT(req->seen, pc->player->player_no), 2) |
+         COND_SET_BIT(req->carried, 3) |
          COND_SET_BIT(req->veteran, 4) |
          COND_SET_BIT(req->ai, 5) |
          COND_SET_BIT(req->paradropped, 6) |
@@ -1543,7 +1538,8 @@
   dio_get_uint16(&din, &packet->id);
   dio_get_uint8(&din, &packet->owner);
   dio_get_uint8(&din, &pack);
-
+  
+  packet->seen = COND_SET_BIT(TEST_BIT(pack, 2), pc->player->player_no);
   packet->carried = TEST_BIT(pack, 3);
   packet->veteran = TEST_BIT(pack, 4);
   packet->ai = TEST_BIT(pack, 5);
diff -u -r freeciv/common/packets.h fc/common/packets.h
--- freeciv/common/packets.h    Thu Jul 24 12:24:14 2003
+++ fc/common/packets.h Wed Jul 23 15:53:51 2003
@@ -307,6 +307,7 @@
   int owner;
   int x, y;
   bool veteran;
+  unsigned int seen;
   int homecity;
   int type;
   int movesleft;
@@ -317,10 +318,10 @@
   int upkeep;
   int upkeep_food;
   int upkeep_gold;
-  bool ai;
   int fuel;
   int goto_dest_x, goto_dest_y;
   enum tile_special_type activity_target;
+  bool ai;
   bool paradropped;
   bool connecting;
   /* in packet only, not in unit struct */
diff -u -r freeciv/common/player.c fc/common/player.c
--- freeciv/common/player.c     Mon Jul  7 18:58:17 2003
+++ fc/common/player.c  Wed Jul 23 16:17:11 2003
@@ -214,44 +214,12 @@
 }
 
 /***************************************************************
-  Returns TRUE iff the player can see the unit at (x,y), i.e. if 
-  the unit is not invisible or if it is adjacent to one of our 
-  cities or units.  No map visibility check here! The unit does 
-  not have to be at (x,y)! 
-  Allied units and cities can be used for sub hunting. 
-***************************************************************/
-bool player_can_see_unit_at_location(struct player *pplayer, 
-                                     struct unit *punit, 
-                                     int x, int y)
-{
-  if (pplayers_allied(unit_owner(punit), pplayer)
-      || !is_hiding_unit(punit)) {
-    return TRUE;
-  }
-
-  /* Search for units/cities that might be able to see the sub/missile */
-  adjc_iterate(x, y, x1, y1) {
-    struct city *pcity = map_get_city(x1, y1);
-    unit_list_iterate(map_get_tile(x1, y1)->units, punit2) {
-      if (pplayers_allied(unit_owner(punit2), pplayer)) {
-       return TRUE;
-      }
-    } unit_list_iterate_end;
-
-    if (pcity && pplayers_allied(city_owner(pcity), pplayer)) {
-      return TRUE;
-    }
-  } adjc_iterate_end;
-
-  return FALSE;
-}
-
-/***************************************************************
-  Same thing as above only the location is the unit's current one.
+  Returns TRUE if the player can see the unit, it check units
+  knowledge obout it.
 ***************************************************************/
 bool player_can_see_unit(struct player *pplayer, struct unit *punit)
 {
-  return player_can_see_unit_at_location(pplayer, punit, punit->x, punit->y);
+  return TEST_BIT(punit->seen, pplayer->player_no);
 }
 
 /***************************************************************
diff -u -r freeciv/common/player.h fc/common/player.h
--- freeciv/common/player.h     Sun Jun  1 09:52:16 2003
+++ fc/common/player.h  Wed Jul 23 16:17:17 2003
@@ -221,9 +221,6 @@
 bool player_has_embassy(struct player *pplayer, struct player *pplayer2);
 
 bool player_can_see_unit(struct player *pplayer, struct unit *punit);
-bool player_can_see_unit_at_location(struct player *pplayer, 
-                                     struct unit *punit, 
-                                     int x, int y);
 
 bool player_owns_city(struct player *pplayer, struct city *pcity);
 
diff -u -r freeciv/common/unit.c fc/common/unit.c
--- freeciv/common/unit.c       Mon Jul 21 17:05:11 2003
+++ fc/common/unit.c    Wed Jul 23 14:25:32 2003
@@ -400,10 +400,13 @@
 **************************************************************************/
 bool is_hiding_unit(struct unit *punit)
 {
-  struct unit *transporter = find_unit_by_id(punit->transported_by);
+  struct unit *transporter;
 
   return (unit_flag(punit, F_PARTIAL_INVIS)
-         || (transporter && unit_flag(transporter, F_PARTIAL_INVIS)));
+         || unit_flag(punit, F_SILENT_HUNTER)
+        || ((transporter = find_unit_by_id(punit->transported_by))
+            && (unit_flag(transporter, F_PARTIAL_INVIS)
+                 || unit_flag(transporter, F_SILENT_HUNTER))));
 }
 
 /**************************************************************************
@@ -1477,7 +1479,7 @@
   punit->ord_map = 0;
   punit->ord_city = 0;
   set_unit_activity(punit, ACTIVITY_IDLE);
-
+  punit->seen = (1u << (pplayer->player_no));
   return punit;
 }
 
@@ -1494,3 +1496,26 @@
   }
   free(punit);
 }
+
+/**************************************************************************
+  Get real unit vision range.
+**************************************************************************/
+int get_unit_vision_range(struct unit *punit)
+{
+  int base_vision = unit_type(punit)->vision_range;
+  
+  assert(base_vision > 0);
+    
+  if (map_has_special(punit->x, punit->y, S_FORTRESS)
+     && is_ground_unit(punit)
+     && player_knows_techs_with_flag(unit_owner(punit), TF_WATCHTOWER))
+  {
+    assert(game.watchtower_vision > 0);
+    assert(game.watchtower_extra_vision >= 0);
+    return MAX(base_vision,
+            MAX(game.watchtower_vision,
+                base_vision + game.watchtower_extra_vision));
+  }
+  
+  return base_vision;
+}
diff -u -r freeciv/common/unit.h fc/common/unit.h
--- freeciv/common/unit.h       Thu Jul 17 20:27:19 2003
+++ fc/common/unit.h    Wed Jul 23 12:09:24 2003
@@ -118,9 +118,12 @@
   int upkeep;
   int upkeep_food;
   int upkeep_gold;
-  bool foul;
   int fuel;
   int bribe_cost;
+  bool foul;
+  bool moved;
+  bool paradropped;
+  bool connecting;
   struct unit_ai ai;
   enum unit_activity activity;
   struct {
@@ -133,10 +136,8 @@
   int ord_map, ord_city;
   /* ord_map and ord_city are the order index of this unit in tile.units
      and city.units_supported; they are only used for save/reload */
-  bool moved;
-  bool paradropped;
-  bool connecting;
   int transported_by;
+  unsigned int seen;   /* A bitvector on the server side, Player_no is index */
   struct goto_route *pgr;
 };
 
@@ -284,4 +285,5 @@
                                  Unit_Type_id type, bool make_veteran);
 void destroy_unit_virtual(struct unit *punit);
 
+int get_unit_vision_range(struct unit *punit);
 #endif  /* FC__UNIT_H */
diff -u -r freeciv/common/unittype.c fc/common/unittype.c
--- freeciv/common/unittype.c   Fri Apr 11 13:17:16 2003
+++ fc/common/unittype.c        Wed Jul 23 17:27:58 2003
@@ -45,7 +45,7 @@
   "AEGIS", "Fighter", "Marines", "Partial_Invis", "Settlers", "Diplomat",
   "Trireme", "Nuclear", "Spy", "Transform", "Paratroopers",
   "Airbase", "Cities", "IgTired", "Missile_Carrier", "No_Land_Attack",
-  "AddToCity", "Fanatic"
+  "AddToCity", "Fanatic", "Silent_Hunter", "Sonar"
 };
 static const char *role_names[] = {
   "FirstBuild", "Explorer", "Hut", "HutTech", "Partisan",
diff -u -r freeciv/common/unittype.h fc/common/unittype.h
--- freeciv/common/unittype.h   Thu Jul  3 10:58:11 2003
+++ fc/common/unittype.h        Mon Jul 21 18:33:47 2003
@@ -93,7 +93,7 @@
   F_AEGIS,       
   F_FIGHTER,     
   F_MARINES,     
-  F_PARTIAL_INVIS,    /* Invisibile except when adjacent (Submarine) */   
+  F_PARTIAL_INVIS,    /* Invisibile except when adjacent (Stealth) */   
   F_SETTLERS,         /* Does not include ability to found cities */
   F_DIPLOMAT,    
   F_TRIREME,          /* Trireme sinking effect */
@@ -109,8 +109,13 @@
   F_ADD_TO_CITY,      /* unit can add to city population */
   F_FANATIC,          /* Only Fundamentalist government can build
                         these units */
+  F_SILENT_HUNTER,    /* like F_PARTIAL_INVIS but Invisibile untill enemy
+                         enter on unit( start combat (attack) this unit)
+                         or find by sonnar (Submarine) */
+  F_SONAR,           /* Can detect F_SILENT_HUNTERs (Destroyer/Heli) */
   F_LAST
 };
+
 #define F_MAX 64
 
 /* Unit "roles": these are similar to unit flags but differ in that
diff -u -r freeciv/data/default/units.ruleset fc/data/default/units.ruleset
--- freeciv/data/default/units.ruleset  Tue Jun 17 02:11:32 2003
+++ fc/data/default/units.ruleset       Tue Jul 22 11:04:22 2003
@@ -1026,7 +1026,7 @@
 uk_shield     = 1
 uk_food       = 0
 uk_gold       = 0
-flags         = "FieldUnit", "OneAttack"
+flags         = "FieldUnit", "OneAttack", "Sonar"
 roles         = ""
 helptext      = _("\
 The Helicopter is a very powerful unit, as it can both fly and\
@@ -1264,7 +1264,7 @@
 uk_shield     = 1
 uk_food       = 0
 uk_gold       = 0
-flags         = ""
+flags         = "Sonar"
 roles         = ""
 helptext      = _("\
 TIP:  A very fast unit, which is very useful for hunting down enemy\
@@ -1380,7 +1380,7 @@
 uk_shield     = 1
 uk_food       = 0
 uk_gold       = 0
-flags         = "Partial_Invis", 
+flags         = "Silent_Hunter", 
                "Missile_Carrier", "No_Land_Attack"
 roles         = ""
 helptext      = _("\
diff -u -r freeciv/server/maphand.c fc/server/maphand.c
--- freeciv/server/maphand.c    Thu Jul 24 12:24:19 2003
+++ fc/server/maphand.c Wed Jul 23 12:21:22 2003
@@ -686,17 +675,9 @@
 **************************************************************************/
 void remove_unit_sight_points(struct unit *punit)
 {
-  int x = punit->x, y = punit->y;
-  struct player *pplayer = unit_owner(punit);
-
   freelog(LOG_DEBUG, "Removing unit sight points at  %i,%i", punit->x,
          punit->y);
-
-  if (map_has_special(punit->x, punit->y, S_FORTRESS)
-      && unit_profits_of_watchtower(punit))
-    fog_area(pplayer, x, y, get_watchtower_vision(punit));
-  else
-    fog_area(pplayer, x, y, unit_type(punit)->vision_range);
+  fog_area(unit_owner(punit), punit->x, punit->y, 
get_unit_vision_range(punit));
 }
 
 /**************************************************************************
diff -u -r freeciv/server/unithand.c fc/server/unithand.c
--- freeciv/server/unithand.c   Sun Jul 20 23:16:01 2003
+++ fc/server/unithand.c        Wed Jul 23 17:13:05 2003
@@ -927,7 +927,7 @@
 {
   struct player *pplayer = unit_owner(punit);
   struct tile *pdesttile = map_get_tile(dest_x, dest_y);
-  struct unit *pdefender = get_defender(punit, dest_x, dest_y);
+  struct unit *pdefender = NULL;
   struct city *pcity = pdesttile->city;
 
   if (!is_normal_map_pos(dest_x, dest_y)) {
@@ -996,7 +996,32 @@
       return FALSE;
     }
   }
-
+  
+  /* are there any units that player have no idea about it *
+  if(unit_list_size(&pdesttile->units)
+    && !unit_list_size(&map_get_player_tile(dest_x, dest_y, pplayer)->units)
+    && (pdefender = get_attacker(punit, dest_x, dest_y))
+    && unit_flag(pdefender, F_SILENT_HUNTER)) {
+      
+    send_unit_info(pplayer, pdefender);
+    if (pplayers_at_war(unit_owner(punit), unit_owner(pdefender))
+       && can_unit_attack_unit_at_tile(pdefender, punit, punit->x, punit->y)) {
+      notify_player_ex(pplayer, pdefender->x, pdefender->y, E_NOEVENT,
+                      _("Game: %s's %s attack our %s"),
+                      unit_owner(pdefender)->name,
+                      get_unit_type(pdefender->type)->name,
+                      get_unit_type(punit->type)->name);
+      handle_unit_attack_request(pdefender, punit);
+    } else {
+      notify_player_ex(pplayer, pdefender->x, pdefender->y, E_NOEVENT,
+                      _("Game: Our %s found %s's %s"),
+                       get_unit_type(punit->type)->name, 
unit_owner(pdefender)->name,
+                      get_unit_type(pdefender->type)->name);
+    }
+    return FALSE;
+  }
+  */
+  pdefender = get_defender(punit, dest_x, dest_y);
   /*** Try to attack if there is an enemy unit on the target tile ***/
   if (pdefender
       && pplayers_at_war(unit_owner(punit), unit_owner(pdefender))) {
diff -u -r freeciv/server/unittools.c fc/server/unittools.c
--- freeciv/server/unittools.c  Mon Jul 21 17:05:11 2003
+++ fc/server/unittools.c       Wed Jul 23 18:30:08 2003
@@ -71,7 +71,9 @@
                                                        struct unit *punit2);
 static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit);
 static int hp_gain_coord(struct unit *punit);
-
+static void update_unit_seen_status(struct unit *punit);
+static void unit_search_hidden_units(struct unit *punit);
+  
 /**************************************************************************
   returns a unit type with a given role, use -1 if you don't want a tech 
   role. Always try tech role and only if not available, return role unit.
@@ -1419,15 +1421,10 @@
 void upgrade_unit(struct unit *punit, Unit_Type_id to_unit)
 {
   struct player *pplayer = unit_owner(punit);
-  int range;
-
+  
   /* save old vision range */
-  if (map_has_special(punit->x, punit->y, S_FORTRESS)
-      && unit_profits_of_watchtower(punit))
-    range = get_watchtower_vision(punit);
-  else
-    range = unit_type(punit)->vision_range;
-
+  int range = get_unit_vision_range(punit);
+  
   /* Scale HP and MP, rounding down.  Be careful with integer arithmetic,
    * and don't kill the unit. */
   punit->hp = MAX(punit->hp * get_unit_type(to_unit)->hp
@@ -1439,13 +1436,7 @@
   punit->type = to_unit;
 
   /* apply new vision range */
-  if (map_has_special(punit->x, punit->y, S_FORTRESS)
-      && unit_profits_of_watchtower(punit))
-    unfog_area(pplayer, punit->x, punit->y, get_watchtower_vision(punit));
-  else
-    unfog_area(pplayer, punit->x, punit->y,
-              get_unit_type(to_unit)->vision_range);
-
+  unfog_area(pplayer, punit->x, punit->y, get_unit_vision_range(punit));
   fog_area(pplayer,punit->x,punit->y,range);
 
   send_unit_info(NULL, punit);
@@ -1516,13 +1507,17 @@
     send_city_info(pplayer, pcity);
   }
 
-  if (map_has_special(x, y, S_FORTRESS)
-      && unit_profits_of_watchtower(punit)) {
-    unfog_area(pplayer, punit->x, punit->y, get_watchtower_vision(punit));
-  } else {
-    unfog_area(pplayer, x, y, unit_type(punit)->vision_range);
-  }
-
+  players_iterate(pplayer) {
+    if(pplayer == unit_owner(punit)) {
+      continue;
+    }
+    punit->seen |=
+               COND_SET_BIT(pplayers_allied(unit_owner(punit), pplayer),
+                                                       pplayer->player_no);
+  } players_iterate_end
+  
+  unfog_area(pplayer, punit->x, punit->y, get_unit_vision_range(punit));
+  
   send_unit_info(NULL, punit);
   maybe_make_contact(x, y, unit_owner(punit));
   wakeup_neighbor_sentries(punit);
@@ -1766,7 +1761,7 @@
 
   /* a 16-bit unsigned number, never zero */
   if (new_serial_num) {
-    serial_num = (serial_num + 1) & 0xFFFF;
+    serial_num = (serial_num + 1) & MAX_UINT16;
     if (serial_num == 0)
       serial_num++;
   }
@@ -1803,34 +1798,73 @@
   packet->packet_use = packet_use;
   packet->info_city_id = info_city_id;
   packet->serial_num = serial_num;
+  packet->seen = punit->seen;
 }
 
-/**************************************************************************
-  A helper function for send_info_to_onlookers below.  
+/***************************************************************
   Checks if a unit can be seen by pplayer at (x,y).
   A player can see a unit if he:
-  (a) can see the tile AND
-  (b) can see the unit at the tile (i.e. unit not invisible at this tile) AND
-  (c) the unit is not in an unallied city
-
-  TODO: the name is confusingly similar to player_can_see_unit_at_location
-  But we need to rename p_c_s_u_a_t because it is really 
-  is_unit_visible_to_player_at.
-**************************************************************************/
-static bool can_player_see_unit_at(struct player *pplayer, struct unit *punit,
-                                   int x, int y)
+  (a) unit isn't transported (cargo) AND
+  (b) can see the tile AND
+  (c) can see the unit at the tile (i.e. unit not invisible at this tile) AND
+  (d) the unit is not in an unallied city
+
+  The unit does not have to be at (x,y) ! 
+  Allied units and cities can be used for sub hunting. 
+***************************************************************/
+static bool can_player_see_unit_at_location(struct player *pplayer, 
+                                     struct unit *punit, 
+                                     int x, int y)
 {
+  bool silent;
+  struct tile *ptile;
+    
   if (!pplayer) {
-    freelog(LOG_ERROR, "NULL pointer in can_player_see_unit_at");
+    freelog(LOG_ERROR, "NULL pointer in can_player_see_unit_at_location");
     return FALSE;
-  } else {
-    bool see_tile = map_get_known_and_seen(x, y, pplayer);
-    bool see_unit = player_can_see_unit_at_location(pplayer, punit, x, y);
-    bool not_in_city = (pplayers_allied(unit_owner(punit), pplayer)
-                       || !map_get_city(x, y));
-
-    return (see_tile && see_unit && not_in_city);
   }
+  
+  silent = pplayers_allied(unit_owner(punit), pplayer);
+  if((!silent && punit->transported_by != -1)
+     || !map_get_known_and_seen(x, y, pplayer)) {
+    return FALSE;
+  }  
+  if (silent || !is_hiding_unit(punit) || !map_get_city(x, y)) {
+    return TRUE;
+  }
+  
+  /*
+   * Search for units/cities that might be able to see the sub/missile 
+   * I hardcoded 2 here as max unit vision range becouse :
+   *  - I can make 2 checks in one loop (cities and units)
+   *  - It is impossible to determine max vision range of units that
+   *   might be able to see the sub/missile.
+   */
+  silent = unit_flag(punit, F_SILENT_HUNTER);
+  square_iterate(x, y, 2, x1, y1) {
+    if ((x ==  x1 && y == y1) || !map_get_known_and_seen(x1, y1, pplayer)) {
+      continue;
+    }
+    
+    ptile = map_get_tile(x1, y1);
+      
+    /* Note: This will check tiles not belong to city map too ! */  
+    if (ptile->city && pplayers_allied(city_owner(ptile->city), pplayer)) {
+      return TRUE;
+    }
+    
+    unit_list_iterate(ptile->units, punit2) {
+      if (pplayers_allied(unit_owner(punit2), pplayer)
+        && (!silent || (silent && unit_flag(punit2, F_SONAR)))
+         && (map_distance(x, y, punit2->x, punit2->y) <=
+                               get_unit_vision_range(punit2))) {
+       return TRUE;
+      }
+    } unit_list_iterate_end;
+    
+  } square_iterate_end;
+
+  return FALSE;
 }
 
 /**************************************************************************
@@ -1852,12 +1886,11 @@
 
   conn_list_iterate(*dest, pconn) {
     struct player *pplayer = pconn->player;
-    bool see_pos =
-       can_player_see_unit_at(pplayer, punit, punit->x, punit->y);
+    bool see_pos = player_can_see_unit(pplayer, punit);
     bool see_xy = see_pos;
 
     if (!same_pos(x, y, punit->x, punit->y)) {
-      see_xy = can_player_see_unit_at(pplayer, punit, x, y);
+      see_xy = can_player_see_unit_at_location(pplayer, punit, x, y);
     }
     if ((!pplayer && pconn->observer) || see_pos || see_xy) {
       send_packet_unit_info(pconn, &info);
@@ -1884,6 +1917,30 @@
 void send_all_known_units(struct conn_list *dest)
 {
   int p;
+    
+  for(p=0; p<game.nplayers; p++) { /* rebuild players units visions */
+    struct player *pplayer = &game.players[p];
+    
+    unit_list_iterate(pplayer->units, punit) {
+      int vision_range = get_unit_vision_range(punit);
+      bool sonar = unit_flag(punit, F_SONAR);
+      square_iterate(punit->x, punit->y, vision_range, x, y) {
+        if ((x == punit->x && y == punit->y)
+           || !map_get_known_and_seen(x, y, pplayer)) {
+          continue;
+        }
+        unit_list_iterate(map_get_tile(x, y)->units, punit2) {
+         if (!pplayers_allied(unit_owner(punit2), pplayer)
+            && (punit2->transported_by != -1
+                || unit_flag(punit2, F_PARTIAL_INVIS)
+                || (sonar && unit_flag(punit2, F_SILENT_HUNTER)))) {
+           continue;      
+         }
+         punit2->seen |= (1u << pplayer->player_no);
+       } unit_list_iterate_end;
+      } square_iterate_end;
+    } unit_list_iterate_end;
+  }
   
   conn_list_do_buffer(dest);
   conn_list_iterate(*dest, pconn) {
@@ -1908,11 +1965,6 @@
   flush_packets();
 }
 
-
-
-
-
-
 /**************************************************************************
 For all units which are transported by the given unit and that are
 currently idle, sentry them.
@@ -2610,15 +2662,9 @@
      wake them up if the punit is farther away than 3. */
   square_iterate(punit->x, punit->y, 3, x, y) {
     unit_list_iterate(map_get_tile(x, y)->units, penemy) {
-      int range;
+      int range = get_unit_vision_range(penemy);
       enum unit_move_type move_type = unit_type(penemy)->move_type;
       enum tile_terrain_type terrain = map_get_terrain(x, y);
-
-      if (map_has_special(x, y, S_FORTRESS)
-         && unit_profits_of_watchtower(penemy))
-       range = get_watchtower_vision(penemy);
-      else
-       range = unit_type(penemy)->vision_range;
       
       if (!pplayers_allied(unit_owner(punit), unit_owner(penemy))
          && penemy->activity == ACTIVITY_SENTRY
@@ -2762,6 +2808,56 @@
 }
 
 /**************************************************************************
+  ...
+**************************************************************************/
+static void update_unit_seen_status(struct unit *punit)
+{
+  punit->seen = (1u << (unit_owner(punit)->player_no));
+  players_iterate(pplayer) {
+    if(pplayer == unit_owner(punit)) {
+      continue;
+    }
+    punit->seen |=
+             COND_SET_BIT(can_player_see_unit_at_location(pplayer, punit,
+                                   punit->x, punit->y), pplayer->player_no);
+  } players_iterate_end
+}
+
+/**************************************************************************
+  Search hidden unit in unit vision range.
+**************************************************************************/
+static void unit_search_hidden_units(struct unit *punit)
+{
+  int range = get_unit_vision_range(punit);
+  bool sonar = unit_flag(punit, F_SONAR);
+  
+  /* searach in unit vision range */
+  square_iterate(punit->x, punit->y, range, x, y) {
+    struct tile *ptile = map_get_tile(x, y);
+      
+    if (ptile->city || (x == punit->x && y == punit->y)) {
+      continue;
+    }
+    unit_list_iterate(ptile->units, punit2) {
+      if (unit_flag(punit2, F_PARTIAL_INVIS)
+        || (sonar && unit_flag(punit2, F_SILENT_HUNTER))) {
+       /* punit2 seen by punit owner and all his ally */
+       punit2->seen |= (1u << (unit_owner(punit)->player_no));
+        players_iterate(pplayer) {
+          if(pplayer == unit_owner(punit)) {
+           continue;
+          }
+          punit2->seen |=
+               COND_SET_BIT(pplayers_allied(unit_owner(punit), pplayer),
+                                                       pplayer->player_no);
+        } players_iterate_end
+      }
+    } unit_list_iterate_end;
+  } square_iterate_end;
+  
+}
+
+/**************************************************************************
 Moves a unit. No checks whatsoever! This is meant as a practical function
 for other functions, like do_airline, which do the checking themselves.
 If you move a unit you should always use this function, as it also sets the
@@ -2844,6 +2940,7 @@
 
       unit_list_insert(&pdesttile->units, pcargo);
       check_unit_activity(pcargo);
+      update_unit_seen_status(pcargo);
       send_unit_info_to_onlookers(NULL, pcargo, src_x, src_y, TRUE);
       fog_area(unit_owner(pcargo), src_x, src_y, 
unit_type(pcargo)->vision_range);
       handle_unit_move_consequences(pcargo, src_x, src_y, dest_x, dest_y);
@@ -2873,7 +2970,9 @@
   punit->moves_left = MAX(0, punit->moves_left - move_cost);
   unit_list_insert(&pdesttile->units, punit);
   check_unit_activity(punit);
-
+  update_unit_seen_status(punit);
+  unit_search_hidden_units(punit);
+    
   /* set activity to sentry if boarding a ship unless the unit is just 
    * passing through the ship on its way somewhere else.  If the unit is
    * GOTOing and the ship isn't the final destination, then don't go
@@ -2931,13 +3030,7 @@
 static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit)
 {
   bool cancel = FALSE;
-  int range;
-
-  if (map_has_special(punit->x, punit->y, S_FORTRESS)
-      && unit_profits_of_watchtower(punit))
-    range = get_watchtower_vision(punit);
-  else
-    range = unit_type(punit)->vision_range;
+  int range = get_unit_vision_range(punit);
   
   square_iterate(punit->x, punit->y, range, x, y) {
     struct unit *penemy =

[Prev in Thread] Current Thread [Next in Thread]