tileLen() public method

public tileLen ( ) : int
return int
 public override void apply(Sim g)
 {
     if (player.mapHack) return;
     // remove visibility from specified tiles
     for (int i = 0; i < tiles.Count; i++) {
         if (tiles[i].playerVisLatest(player) && !tiles[i].playerDirectVisLatest(player)) {
             tiles[i].playerVis[player.id].Add(time);
             player.unseenTiles++;
         } else {
             tiles[i] = null;
         }
     }
     // add events to remove visibility from surrounding tiles
     foreach (Tile tile in tiles) {
         if (tile != null) {
             for (int tX = Math.Max(0, tile.x - 1); tX <= Math.Min(g.tileLen() - 1, tile.x + 1); tX++) {
                 for (int tY = Math.Max(0, tile.y - 1); tY <= Math.Min(g.tileLen() - 1, tile.y + 1); tY++) {
                     if ((tX != tile.x || tY != tile.y) && g.tiles[tX, tY].playerVisLatest(player)) {
                         // ISSUE #29: lose visibility in a circle instead of a square
                         g.tiles[tX, tY].playerVisRemove(player, time + (1 << FP.precision) / g.maxSpeed);
                     }
                 }
             }
         }
     }
     if (Sim.enableNonLivePaths) {
         // check if a tile stopped being exclusive to this player, or became exclusive to another player
         Tile prevTile = null;
         foreach (Tile tile in tiles) {
             if (tile != null) {
                 int tXMax = Math.Min(g.tileLen() - 1, tile.x + g.tileVisRadius());
                 int tYMax = Math.Min(g.tileLen() - 1, tile.y + g.tileVisRadius());
                 for (int tX = Math.Max(0, tile.x - g.tileVisRadius()); tX <= tXMax; tX++) {
                     for (int tY = Math.Max(0, tile.y - g.tileVisRadius()); tY <= tYMax; tY++) {
                         if (g.inVis(tX - tile.x, tY - tile.y) && (prevTile == null || !g.inVis(tX - prevTile.x, tY - prevTile.y))) {
                             foreach (Player player2 in g.players) {
                                 if (player2 == player && g.tiles[tX, tY].exclusiveLatest(player2)) {
                                     g.tiles[tX, tY].exclusiveRemove(player2, time);
                                 } else if (player2 != player && !g.tiles[tX, tY].exclusiveLatest(player2) && g.tiles[tX, tY].calcExclusive(player2)) {
                                     g.tiles[tX, tY].exclusiveAdd(player2, time);
                                 }
                             }
                         }
                     }
                 }
                 prevTile = tile;
             }
         }
     }
 }
Ejemplo n.º 2
0
 public override void apply(Sim g)
 {
     if (tile.exclusiveLatest (unit.player) && !Waypoint.active (tile.waypointLatest (unit))
         && ((prev != null && prev == prev.tile.waypointLatest (unit))
             || (start != null && start.Last().segment().units.Contains(unit) && start.Last().segmentUnit().unseenAfter(start.Last().time)))) {
         // add waypoint to specified tile
         Waypoint waypoint = tile.waypointAdd (unit, time, prev, start);
         // add events to add waypoints to surrounding tiles
         for (int tX = Math.Max (0, tile.x - 1); tX <= Math.Min (g.tileLen () - 1, tile.x + 1); tX++) {
             for (int tY = Math.Max (0, tile.y - 1); tY <= Math.Min (g.tileLen () - 1, tile.y + 1); tY++) {
                 if (tX != tile.x || tY != tile.y) {
                     g.events.addEvt (new WaypointAddEvt(time + new FP.Vector(tX - tile.x << FP.precision, tY - tile.y << FP.precision).length() / unit.type.speed,
                         unit, g.tiles[tX, tY], waypoint, null));
                 }
             }
         }
     }
 }
Ejemplo n.º 3
0
 public override void apply(Sim g)
 {
     if (!g.players[player].mapHack && mapHack) {
         for (int tX = 0; tX < g.tileLen (); tX++) {
             for (int tY = 0; tY < g.tileLen (); tY++) {
                 if (!g.tiles[tX, tY].playerVisLatest (g.players[player])) {
                     g.tiles[tX, tY].playerVis[player].Add (time);
                 }
             }
         }
         g.players[player].unseenTiles = 0;
         for (int tX = 0; tX < g.tileLen (); tX++) {
             for (int tY = 0; tY < g.tileLen (); tY++) {
                 bool exclusiveOld = g.tiles[tX, tY].exclusiveLatest (g.players[player]);
                 bool exclusiveNew = g.tiles[tX, tY].calcExclusive (g.players[player]);
                 if (!exclusiveOld && exclusiveNew) {
                     g.tiles[tX, tY].exclusiveAdd(g.players[player], time);
                 } else if (exclusiveOld && !exclusiveNew) {
                     g.tiles[tX, tY].exclusiveRemove(g.players[player], time);
                 }
             }
         }
     } else if (g.players[player].mapHack && !mapHack) {
         for (int tX = 0; tX < g.tileLen (); tX++) {
             for (int tY = 0; tY < g.tileLen (); tY++) {
                 g.tiles[tX, tY].playerVisRemove (g.players[player], time);
             }
         }
     }
     g.players[player].mapHack = mapHack;
 }
Ejemplo n.º 4
0
 /// <summary>
 /// loads scenario from json file and returns whether successful
 /// </summary>
 private bool scnOpen(string path, int user, bool multiplayer)
 {
     Hashtable json;
     ArrayList jsonA;
     bool b = false;
     // ISSUE #17: in multiplayer games, host should load file & send data to other players, otherwise json double parsing may not match
     if (!File.Exists(path)) return false;
     json = (Hashtable)Procurios.Public.JSON.JsonDecode(File.ReadAllText(path), ref b);
     if (!b) return false;
     // base scenario
     g = new Sim {
         // not stored in scenario file
         selUser = user,
         networkView = multiplayer ? networkView : null,
         events = new List<SimEvt>(),
         cmdPending = new List<SimEvt>(),
         checksum = 0,
         synced = true,
         timeSim = 0,
         timeUpdateEvt = long.MinValue,
         maxSpeed = 0,
         deleteLines = new List<MoveLine>(),
         keepLines = new List<MoveLine>(),
         alternatePaths = new List<Path>(),
         // stored in scenario file
         mapSize = jsonFP(json, "mapSize"),
         updateInterval = (long)jsonDouble(json, "updateInterval"),
         tileInterval = (long)jsonDouble (json, "tileInterval"),
         visRadius = jsonFP(json, "visRadius"),
         camSpeed = jsonFP(json, "camSpeed"),
         zoom = (float)jsonDouble(json, "zoom"),
         zoomMin = (float)jsonDouble(json, "zoomMin"),
         zoomMax = (float)jsonDouble(json, "zoomMax"),
         zoomSpeed = (float)jsonDouble (json, "zoomSpeed"),
         zoomMouseWheelSpeed = (float)jsonDouble (json, "zoomMouseWheelSpeed"),
         uiBarHeight = (float)jsonDouble (json, "uiBarHeight"),
         healthBarSize = jsonVector2(json, "healthBarSize"),
         healthBarYOffset = (float)jsonDouble(json, "healthBarYOffset"),
         stackRadius = jsonFP(json, "stackRadius"),
         stackRotSpeed = (float)jsonDouble(json, "stackRotSpeed"),
         backCol = jsonColor(json, "backCol"),
         borderCol = jsonColor(json, "borderCol"),
         noVisCol = jsonColor(json, "noVisCol"),
         playerVisCol = jsonColor(json, "playerVisCol"),
         unitVisCol = jsonColor(json, "unitVisCol"),
         exclusiveCol = jsonColor(json, "exclusiveCol"),
         waypointCol = jsonColor (json, "waypointCol"),
         pathCol = jsonColor(json, "pathCol"),
         healthBarBackCol = jsonColor(json, "healthBarBackCol"),
         healthBarFullCol = jsonColor(json, "healthBarFullCol"),
         healthBarEmptyCol = jsonColor(json, "healthBarEmptyCol"),
         rscNames = new string[0],
         players = new Player[0],
         unitT = new UnitType[0],
         units = new List<Unit>(),
         paths = new List<Path>(),
     };
     if (g.updateInterval > 0) g.events.addEvt(new UpdateEvt(0));
     if (g.tileInterval > 0) g.events.addEvt (new TileUpdateEvt(0));
     g.camPos = jsonFPVector(json, "camPos", new FP.Vector(g.mapSize / 2, g.mapSize / 2));
     // resources
     jsonA = jsonArray(json, "resources");
     if (jsonA != null) {
         foreach (string rscName in jsonA) {
             Array.Resize(ref g.rscNames, g.rscNames.Length + 1);
             g.rscNames[g.rscNames.Length - 1] = rscName;
         }
     }
     // players
     jsonA = jsonArray(json, "players");
     if (jsonA != null) {
         foreach (Hashtable jsonO in jsonA) {
             Hashtable jsonO2 = jsonObject(jsonO, "startRsc");
             Player player = new Player {
                 g = this.g,
                 id = g.players.Length,
                 name = jsonString(jsonO, "name"),
                 isUser = jsonBool(jsonO, "isUser"),
                 user = (int)jsonDouble(jsonO, "user"),
                 populationLimit = (int)jsonDouble (jsonO, "populationLimit", -1),
                 startRsc = new long[g.rscNames.Length],
                 mapHack = jsonBool (jsonO, "mapHack"),
                 hasNonLivePaths = false,
                 timeGoLiveFailedAttempt = long.MinValue,
                 goLiveStackPaths = new Dictionary<int, HashSet<Path>>(),
                 unseenTiles = g.tileLen () * g.tileLen (),
             };
             for (int i = 0; i < g.rscNames.Length; i++) {
                 player.startRsc[i] = (jsonO2 != null) ? jsonFP(jsonO2, g.rscNames[i]) : 0;
             }
             Array.Resize(ref g.players, g.players.Length + 1);
             g.players[g.players.Length - 1] = player;
         }
         foreach (Hashtable jsonO in jsonA) {
             ArrayList jsonA2 = jsonArray(jsonO, "canAttack");
             Player player = g.playerNamed(jsonString(jsonO, "name"));
             player.canAttack = new bool[g.players.Length];
             for (int i = 0; i < g.players.Length; i++) {
                 player.canAttack[i] = false;
             }
             if (jsonA2 != null) {
                 foreach (string s in jsonA2) {
                     if (g.playerNamed(s) != null) {
                         player.canAttack[g.playerNamed(s).id] = true;
                     }
                 }
             }
         }
         foreach (Player player in g.players) {
             player.immutable = player.calcImmutable();
         }
     }
     // unit types
     jsonA = jsonArray(json, "unitTypes");
     if (jsonA != null) {
         foreach (Hashtable jsonO in jsonA) {
             Hashtable jsonO2 = jsonObject(jsonO, "rscCost");
             Hashtable jsonO3 = jsonObject(jsonO, "rscCollectRate");
             UnitType unitT = new UnitType {
                 id = g.unitT.Length,
                 name = jsonString(jsonO, "name"),
                 imgPath = jsonString(jsonO, "imgPath"),
                 imgOffset = jsonFPVector (jsonO, "imgOffset"),
                 imgHalfHeight = jsonFP (jsonO, "imgHalfHeight"),
                 maxHealth = (int)jsonDouble(jsonO, "maxHealth"),
                 speed = jsonFP(jsonO, "speed"),
                 reload = (long)jsonDouble(jsonO, "reload"),
                 range = jsonFP(jsonO, "range"),
                 tightFormationSpacing = jsonFP(jsonO, "tightFormationSpacing"),
                 seePrecedence = (int)jsonDouble (jsonO, "seePrecedence"),
                 makeUnitMinDist = jsonFP(jsonO, "makeUnitMinDist"),
                 makeUnitMaxDist = jsonFP(jsonO, "makeUnitMaxDist"),
                 makePathMinDist = jsonFP(jsonO, "makePathMinDist"),
                 makePathMaxDist = jsonFP(jsonO, "makePathMaxDist"),
                 rscCost = new long[g.rscNames.Length],
                 rscCollectRate = new long[g.rscNames.Length],
             };
             unitT.selMinPos = jsonFPVector (jsonO, "selMinPos", new FP.Vector(unitT.imgOffset.x - unitT.imgHalfHeight, unitT.imgOffset.y - unitT.imgHalfHeight));
             unitT.selMaxPos = jsonFPVector (jsonO, "selMaxPos", new FP.Vector(unitT.imgOffset.x + unitT.imgHalfHeight, unitT.imgOffset.y + unitT.imgHalfHeight));
             unitT.laserPos = jsonFPVector (jsonO, "laserPos", unitT.imgOffset);
             if (unitT.speed > g.maxSpeed) g.maxSpeed = unitT.speed;
             for (int i = 0; i < g.rscNames.Length; i++) {
                 unitT.rscCost[i] = (jsonO2 != null) ? jsonFP(jsonO2, g.rscNames[i]) : 0;
                 unitT.rscCollectRate[i] = (jsonO3 != null) ? jsonFP(jsonO3, g.rscNames[i]) : 0;
             }
             Array.Resize(ref g.unitT, g.unitT.Length + 1);
             g.unitT[g.unitT.Length - 1] = unitT;
         }
         foreach (Hashtable jsonO in jsonA) {
             Hashtable jsonO2 = jsonObject(jsonO, "damage");
             ArrayList jsonA2 = jsonArray(jsonO, "canMake");
             UnitType unitT = g.unitTypeNamed(jsonString(jsonO, "name"));
             unitT.makeOnUnitT = g.unitTypeNamed(jsonString(jsonO, "makeOnUnitT"));
             unitT.damage = new int[g.unitT.Length];
             for (int i = 0; i < g.unitT.Length; i++) {
                 unitT.damage[i] = (jsonO2 != null) ? (int)jsonDouble(jsonO2, g.unitT[i].name) : 0;
             }
             unitT.canMake = new bool[g.unitT.Length];
             for (int i = 0; i < g.unitT.Length; i++) {
                 unitT.canMake[i] = false;
             }
             if (jsonA2 != null) {
                 foreach (string s in jsonA2) {
                     if (g.unitTypeNamed(s) != null) {
                         unitT.canMake[g.unitTypeNamed(s).id] = true;
                     }
                 }
             }
         }
     }
     // tiles
     g.tiles = new Tile[g.tileLen(), g.tileLen()];
     for (int i = 0; i < g.tileLen(); i++) {
         for (int j = 0; j < g.tileLen(); j++) {
             g.tiles[i, j] = new Tile(g, i, j);
         }
     }
     foreach (Player player in g.players) {
         if (player.mapHack) {
             player.mapHack = false;
             new MapHackCmdEvt(g.timeSim, player.id, true).apply (g);
         }
     }
     // units
     jsonA = jsonArray(json, "units");
     if (jsonA != null) {
         foreach (Hashtable jsonO in jsonA) {
             if (g.playerNamed(jsonString(jsonO, "player")) != null) {
                 ArrayList jsonA2 = jsonArray (jsonO, "types");
                 List<Unit> units = new List<Unit>();
                 if (jsonA2 != null) {
                     foreach (string type in jsonA2) {
                         if (g.unitTypeNamed(type) != null) {
                             Unit unit = new Unit(g, g.units.Count, g.unitTypeNamed(type), g.playerNamed(jsonString(jsonO, "player")));
                             g.units.Add (unit);
                             units.Add (unit);
                         }
                     }
                 }
                 FP.Vector startPos = jsonFPVector(jsonO, "startPos", new FP.Vector((long)(UnityEngine.Random.value * g.mapSize), (long)(UnityEngine.Random.value * g.mapSize)));
                 g.paths.Add (new Path(g, g.paths.Count, units, (long)jsonDouble(jsonO, "startTime"), startPos, false, int.MaxValue, g.tileAt(startPos).x, g.tileAt(startPos).y));
             }
         }
     }
     g.nRootPaths = g.paths.Count;
     // start game
     loadUI ();
     g.timeGame = 0;
     timeSpeedChg = (long)(Time.time * 1000) - 1000;
     timeNow = (long)(Time.time * 1000);
     return true;
 }
Ejemplo n.º 5
0
 public override void apply(Sim g)
 {
     bool anyoneMoved = false;
     foreach (Path path in g.paths) {
         int tXPrev, tYPrev;
         if (path.timeSimPast == long.MaxValue && path.tileX != Sim.offMap && path.updateTilePos(time, out tXPrev, out tYPrev)) {
             anyoneMoved = true;
             int exclusiveMinX = g.tileLen() - 1;
             int exclusiveMaxX = 0;
             int exclusiveMinY = g.tileLen() - 1;
             int exclusiveMaxY = 0;
             // add path to visibility tiles
             for (int tX = Math.Max (0, path.tileX - g.tileVisRadius()); tX <= Math.Min (g.tileLen () - 1, path.tileX + g.tileVisRadius()); tX++) {
                 for (int tY = Math.Max (0, path.tileY - g.tileVisRadius()); tY <= Math.Min (g.tileLen () - 1, path.tileY + g.tileVisRadius()); tY++) {
                     if (!g.inVis(tX - tXPrev, tY - tYPrev) && g.inVis(tX - path.tileX, tY - path.tileY)) {
                         if (!g.tiles[tX, tY].playerVisLatest(path.player)) {
                             // make tile visible to this player
                             g.tiles[tX, tY].playerVis[path.player.id].Add(time);
                             path.player.unseenTiles--;
                             if (Sim.enableNonLivePaths) {
                                 if (tX < exclusiveMinX) exclusiveMinX = tX;
                                 if (tX > exclusiveMaxX) exclusiveMaxX = tX;
                                 if (tY < exclusiveMinY) exclusiveMinY = tY;
                                 if (tY > exclusiveMaxY) exclusiveMaxY = tY;
                             }
                         }
                         // check if this tile stopped being exclusive to another player
                         if (Sim.enableNonLivePaths && !path.player.immutable) {
                             foreach (Player player in g.players) {
                                 if (player != path.player && g.tiles[tX, tY].exclusiveLatest(player)) {
                                     g.tiles[tX, tY].exclusiveRemove(player, time);
                                 }
                             }
                         }
                     }
                 }
             }
             // remove path from visibility tiles
             for (int tX = Math.Max (0, tXPrev - g.tileVisRadius()); tX <= Math.Min (g.tileLen () - 1, tXPrev + g.tileVisRadius()); tX++) {
                 for (int tY = Math.Max (0, tYPrev - g.tileVisRadius()); tY <= Math.Min (g.tileLen () - 1, tYPrev + g.tileVisRadius()); tY++) {
                     if (g.inVis(tX - tXPrev, tY - tYPrev) && !g.inVis(tX - path.tileX, tY - path.tileY)) {
                         // check if player can't directly see this tile anymore
                         if (g.tiles[tX, tY].playerVisLatest(path.player) && !g.tiles[tX, tY].playerDirectVisLatest(path.player)) {
                             long timePlayerVis = long.MaxValue;
                             // find lowest time that surrounding tiles lost visibility
                             for (int tX2 = Math.Max(0, tX - 1); tX2 <= Math.Min(g.tileLen() - 1, tX + 1); tX2++) {
                                 for (int tY2 = Math.Max(0, tY - 1); tY2 <= Math.Min(g.tileLen() - 1, tY + 1); tY2++) {
                                     if ((tX2 != tX || tY2 != tY) && !g.tiles[tX2, tY2].playerVisLatest(path.player)) {
                                         if (g.tiles[tX2, tY2].playerVis[path.player.id].Count == 0) {
                                             timePlayerVis = long.MinValue;
                                         } else if (g.tiles[tX2, tY2].playerVis[path.player.id].Last () < timePlayerVis) {
                                             timePlayerVis = g.tiles[tX2, tY2].playerVis[path.player.id].Last ();
                                         }
                                     }
                                 }
                             }
                             // if player can't see all neighboring tiles, they won't be able to tell if another player's unit moves into this tile
                             // so remove this tile's visibility for this player
                             if (timePlayerVis != long.MaxValue) {
                                 timePlayerVis = Math.Max(time, timePlayerVis + (1 << FP.precision) / g.maxSpeed); // ISSUE #29: lose visibility in a circle instead of a square
                                 g.tiles[tX, tY].playerVisRemove(path.player, timePlayerVis);
                             }
                         }
                         // check if this tile became exclusive to a player using map hack
                         if (Sim.enableNonLivePaths && !path.player.immutable) {
                             foreach (Player player in g.players) {
                                 if (player != path.player && player.mapHack && !g.tiles[tX, tY].exclusiveLatest (player) && g.tiles[tX, tY].calcExclusive (player)) {
                                     g.tiles[tX, tY].exclusiveAdd(player, time);
                                 }
                             }
                         }
                     }
                 }
             }
             if (Sim.enableNonLivePaths) {
                 // apply PlayerVisRemoveEvts that occur immediately
                 foreach (SimEvt evt in g.events) {
                     if (evt.time > time) break;
                     if (evt is PlayerVisRemoveEvt) {
                         PlayerVisRemoveEvt visEvt = evt as PlayerVisRemoveEvt;
                         if (visEvt.player == path.player) {
                             visEvt.apply (g);
                             g.events.Remove (evt);
                             break;
                         }
                     }
                 }
                 // check if tiles became exclusive to this player
                 exclusiveMinX = Math.Max(0, exclusiveMinX - g.tileVisRadius());
                 exclusiveMaxX = Math.Min(g.tileLen() - 1, exclusiveMaxX + g.tileVisRadius());
                 exclusiveMinY = Math.Max(0, exclusiveMinY - g.tileVisRadius());
                 exclusiveMaxY = Math.Min(g.tileLen() - 1, exclusiveMaxY + g.tileVisRadius());
                 for (int tX = exclusiveMinX; tX <= exclusiveMaxX; tX++) {
                     for (int tY = exclusiveMinY; tY <= exclusiveMaxY; tY++) {
                         if (!g.tiles[tX, tY].exclusiveLatest(path.player) && g.tiles[tX, tY].calcExclusive(path.player)) {
                             g.tiles[tX, tY].exclusiveAdd(path.player, time);
                         }
                     }
                 }
                 // add waypoints for units
                 foreach (Unit unit in path.segmentWhen (time).units) {
                     unit.addWaypoint (time, path);
                 }
             }
             if (tXPrev >= 0 && tXPrev < g.tileLen() && tYPrev >= 0 && tYPrev < g.tileLen()) {
                 // if this path moved out of another player's direct visibility, remove that player's visibility here
                 if (path.tileX >= 0 && path.tileX < g.tileLen() && path.tileY >= 0 && path.tileY < g.tileLen()) {
                     if (!path.player.immutable) {
                         foreach (Player player in g.players) {
                             if (player != path.player && g.tiles[tXPrev, tYPrev].playerDirectVisLatest(player) && !g.tiles[path.tileX, path.tileY].playerDirectVisLatest(player)) {
                                 for (int tX = Math.Max(0, path.tileX - 1); tX <= Math.Min(g.tileLen() - 1, path.tileX + 1); tX++) {
                                     for (int tY = Math.Max(0, path.tileY - 1); tY <= Math.Min(g.tileLen() - 1, path.tileY + 1); tY++) {
                                         // ISSUE #30: perhaps use more accurate time at tiles other than (path.tileX, path.tileY)
                                         g.tiles[tX, tY].playerVisRemove(player, time);
                                     }
                                 }
                             }
                         }
                     }
                 }
                 // if this player can no longer directly see another player's path, remove this player's visibility there
                 foreach (int i in g.tiles[tXPrev, tYPrev].pathVis.Keys) {
                     Tile iTile = g.paths[i].tileWhen (time);
                     if (g.paths[i].player != path.player && !g.paths[i].player.immutable && g.paths[i].segments.Last ().units.Count > 0
                         && g.inVis(iTile.x - tXPrev, iTile.y - tYPrev) && !iTile.playerDirectVisLatest(path.player)) {
                         for (int tX = Math.Max(0, iTile.x - 1); tX <= Math.Min(g.tileLen() - 1, iTile.x + 1); tX++) {
                             for (int tY = Math.Max(0, iTile.y - 1); tY <= Math.Min(g.tileLen() - 1, iTile.y + 1); tY++) {
                                 // ISSUE #30: perhaps use more accurate time at tiles other than (paths[i].tileX, paths[i].tileY)
                                 g.tiles[tX, tY].playerVisRemove(path.player, time);
                             }
                         }
                     }
                 }
             }
         }
     }
     if (anyoneMoved) {
         // update which paths are known to be unseen
         foreach (Path path in g.paths) {
             if (path.tileX >= 0 && path.tileX < g.tileLen() && path.tileY >= 0 && path.tileY < g.tileLen()) {
                 if (!path.segments.Last ().unseen && g.tiles[path.tileX, path.tileY].exclusiveLatest(path.player)) {
                     // path is now unseen
                     Segment segment = path.insertSegment(time);
                     segment.unseen = true;
                     foreach (Unit unit in segment.units) {
                         unit.addWaypoint (time, path);
                     }
                 } else if (path.segments.Last ().unseen && !g.tiles[path.tileX, path.tileY].exclusiveLatest(path.player)) {
                     // path is now seen
                     Segment segment = path.insertSegment(time);
                     foreach (Unit unit in segment.units.OrderByDescending (u => u.type.seePrecedence)) {
                         if (segment.units.Count <= path.nSeeUnits) break;
                         new SegmentUnit(segment, unit).delete ();
                     }
                     path.nSeeUnits = int.MaxValue;
                     if (!g.deleteOtherPaths (segment.segmentUnits(), false, true)) throw new SystemException("failed to delete other paths of seen path");
                     segment.unseen = false;
                     foreach (Unit unit in segment.units) {
                         unit.clearWaypoints (time);
                     }
                 }
             }
         }
     }
     g.events.addEvt (new TileUpdateEvt(time + g.tileInterval));
 }