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; } } } }
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)); } } } } }
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; }
/// <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; }
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)); }