/// <summary> /// All the players at a certain position /// </summary> /// <param name="position">The tile to search</param> /// <returns>All the players at a certain position</returns> public IEnumerable<int> PlayersAtPosition(Tile position) { foreach (int player in _playerPositions.Keys) { if (_playerPositions[player] == position) { yield return player; } } }
private int SummarizeState(Tile tile) { int HashCode = tile.X * 200 ^ tile.Y * 1000 ^ (tile.EffectiveLightLevel > 0 ? tile.ImageName : String.Empty).GetHashCode() ^ Math.Min(tile.EffectiveLightLevel, 10) * 5000 ^ (tile.IsRevealed ? 1 : 2); return HashCode; }
private void ScrollTileToCenter(Tile tile) { int x = tile.X * MapInfo.GridConfig.TileWidth; int y = tile.Y * MapInfo.GridConfig.TileHeight; x -= Parent.ClientSize.Width / 2; y -= Parent.ClientSize.Height / 2; if (Parent is Panel) { ((Panel)Parent).AutoScrollPosition = new Point(x, y); } }
/// <summary> /// Moves a player token and any light source at the players current location, to a new location /// </summary> /// <param name="player">The player to be moved</param> /// <param name="destination">The tile to move the player to</param> public void MovePlayer(int player, Tile destination) { Contract.Requires(destination != null); int lightSource = 0; Tile old = null; if (_playerPositions.TryGetValue(player, out old) && old != null) { bool stillPresent = false; foreach (int p in _playerPositions.Keys) { if (_playerPositions[p] == old && p != player) { stillPresent = true; } } old.IsPlayerPresent = stillPresent; lightSource = old.LightSource; old.LightSource = 0; } _playerPositions[player] = destination; destination.IsPlayerPresent = true; destination.LightSource = Math.Max(lightSource, destination.LightSource); }
private void DoAction(Tile tile, Tile nearest, ClickAction action) { Contract.Requires(tile != null); if (MapInfo == null) { return; } switch (action) { case ClickAction.ToggleWallBlocksLOS: if (nearest == null) { return; } if (tile.NoLOSBetweenTiles.Contains(nearest)) { tile.NoLOSBetweenTiles.Remove(nearest); nearest.NoLOSBetweenTiles.Remove(tile); } else { tile.NoLOSBetweenTiles.Remove(nearest); nearest.NoLOSBetweenTiles.Remove(tile); tile.NoLOSBetweenTiles.Add(nearest); nearest.NoLOSBetweenTiles.Add(tile); } break; case ClickAction.ToggleSecret: if (!tile.HasSecret) { return; } bool newState = !tile.IsRevealed; foreach (Tile t in tile.Search(5, false, (t => t.HasSecret && t.IsRevealed != newState)).Flatten()) { t.IsRevealed = newState; } break; case ClickAction.MovePlayerMarker1: Tile start = MapInfo.PositionOfPlayer(1); if (start != null) { bool animate = AnimatePlayerMovement; IEnumerable<Tile> path = start.FindShortestPath(tile); if (path != null) { int count = 0; foreach (Tile step in path) { count++; if (count % 2 != 0 && !animate) { continue; } if (animate) { PlayerFollowingPath.Enqueue(step); } else { MapInfo.MovePlayer(1, step); MapInfo.RecalculateLightAndLineOfSight(true); } } } if (!animate || path == null) { MapInfo.MovePlayer(1, tile); } } else { MapInfo.MovePlayer(1, tile); } ScrollTileToCenter(tile); break; case ClickAction.MovePlayerMarker2: MapInfo.MovePlayer(2, tile); break; case ClickAction.MovePlayerMarker3: MapInfo.MovePlayer(3, tile); break; case ClickAction.ToggleLightCustom: tile.LightSource = tile.LightSource == CustomLightLevel ? 0 : CustomLightLevel; break; case ClickAction.ToggleLight100: tile.LightSource = tile.LightSource == 20 ? 0 : 20; break; case ClickAction.ToggleLight50: tile.LightSource = tile.LightSource == 10 ? 0 : 10; break; case ClickAction.ToggleLight10: tile.LightSource = tile.LightSource == 5 ? 0 : 5; break; default: //do nothing break; } MapInfo.RecalculateLightAndLineOfSight(); Refresh(); }
private AllBorders DrawTileIcon(Tile tile, Graphics g, Rectangle r) { Contract.Requires(tile != null); Contract.Requires(g != null); Contract.Requires(r != null); AllBorders borderInfo = new AllBorders(); borderInfo.noAdjacent = CompareTileBorders(tile); borderInfo.top = borderInfo.noAdjacent; borderInfo.left = borderInfo.noAdjacent; borderInfo.right = borderInfo.noAdjacent; borderInfo.bottom = borderInfo.noAdjacent; borderInfo.r = r; int tx = tile.X; int ty = tile.Y; foreach (Tile t in tile.AdjacentTiles) { if (t == null) { continue; } BorderDesc border = CompareTileBorders(tile, t); if (tx == t.X) { if (t.Y == ty - 1) { borderInfo.top = border; } else if (t.Y == ty + 1) { borderInfo.bottom = border; } } else if (ty == t.Y) { if (t.X == tx - 1) { borderInfo.left = border; } else if (t.X == tx + 1) { borderInfo.right = border; } } } if (!WallEditMode) { if (tile.HasSecret) { if (tile.IsRevealed && _secretRevealedIcon != null) { g.DrawImage(_secretRevealedIcon, r); } else if (!tile.IsRevealed && _secretHiddenIcon != null) { g.DrawImage(_secretHiddenIcon, r); } } if (tile.IsPlayerPresent) { int first = Math.Max(1, MapInfo.PlayersAtPosition(tile).FirstOrDefault()); first = Math.Min(LineOfSightIcons.Count, first); first -= 1; g.DrawImage(LineOfSightIcons[first], r); } if (tile.LightSource > 0) { int lastLevel = _lightLevels.FirstOrDefault(); foreach (int level in _lightLevels) { if (level <= tile.LightSource) { lastLevel = level; } } Image icon; if (_lightIcons.TryGetValue(lastLevel, out icon)) { g.DrawImage(icon, r); } } int alpha = (int)((double)(10 - tile.LightLevel) / 10 * 255 * .5); alpha = Math.Min(255, Math.Max(0, alpha)); using (Brush lightBrush = new SolidBrush(Color.FromArgb(alpha, Color.Black))) { g.FillRectangle(lightBrush, r); } } return borderInfo; }
private bool HasLOS(Tile target, IDictionary<int, Tile> tiles) { int tx = target.X; int ty = target.Y; int cx = X; int cy = Y; if (cx == tx && cy == ty) { return true; } double wiggle = 0.25; bool los = false; los |= CheckLine(cx, cy, tx, ty, tiles); los |= CheckLine(cx - wiggle, cy, tx, ty, tiles); los |= CheckLine(cx + wiggle, cy, tx, ty, tiles); los |= CheckLine(cx, cy - wiggle, tx, ty, tiles); los |= CheckLine(cx, cy + wiggle, tx, ty, tiles); return los; }
private static BorderDesc CompareTileBorders(Tile current, Tile neighbor = null) { Contract.Requires(current != null); BorderDesc result = new BorderDesc(); if (neighbor == null) { result.IsLightBorder = current.LightLevel >= 5; result.IsSecretHiddenBorder = current.HasSecret && !current.IsRevealed; result.IsSecretRevealedBorder = current.HasSecret && current.IsRevealed; } else { result.IsLightBorder = current.LightLevel >= 5 && neighbor.LightLevel < 5; result.IsSecretHiddenBorder = (current.HasSecret && !current.IsRevealed) && (!neighbor.HasSecret || neighbor.IsRevealed); result.IsSecretRevealedBorder = (current.HasSecret && current.IsRevealed) && (!neighbor.HasSecret || !neighbor.IsRevealed); result.IsBlocksLOSBorder = current.NoLOSBetweenTiles.Contains(neighbor); } return result; }
public IEnumerable<Tile> FindShortestPath(Tile other) { if (other == null) { return null; } int totaldist = DistanceWalking(other); if (totaldist == -1) { return null; } List<Tile> pathToFollow = new List<Tile>(); Tile current = this; Tile nextTile = current; while (true) { int lowestWalking = int.MaxValue; int lowestManhattan = int.MaxValue; foreach (Tile tile in current.AdjacentTiles) { if (current.NoLOSBetweenTiles.Contains(tile)) { continue; } if (pathToFollow.Contains(tile)) { continue; } int distW = tile.DistanceWalking(other); int distM = tile.DistanceManhattan(other); if (distW == -1) { continue; } if (distW <= lowestWalking) { if (distW != lowestWalking || distM < lowestManhattan) { lowestWalking = distW; lowestManhattan = distM; nextTile = tile; } } } pathToFollow.Add(current); if (nextTile == null) { return null; } if (current == other) { return pathToFollow; } current = nextTile; nextTile = null; } }
/// <summary> /// Returns the walking distance between two tiles without going outside the specified path /// </summary> /// <param name="other"></param> /// <param name="path">if null will use a default stepped search</param> /// <returns>Returns the walking distance between two tiles without going outside the specified path or -1 if the two tiles do not have any path between them</returns> public int DistanceWalking(Tile other, IEnumerable<IEnumerable<Tile>> path = null) { if (other == null) { return -1; } if (path == null) { return DistanceWalking(other, Search()); } int stepCounter = 0; foreach (IEnumerable<Tile> step in path) { if (step != null && step.Contains(other)) { return stepCounter; } stepCounter++; } return -1; }
/// <summary> /// Returns the distance between two tiles based on their coordinates using manhattan style (diagonal movement not allowed) /// </summary> /// <param name="other"></param> /// <returns>the distance between two tiles based on their coordinates using manhattan style (diagonal movement not allowed)</returns> public int DistanceManhattan(Tile other) { Contract.Requires(other != null); Contract.Ensures(Contract.Result<int>() >= 0); return Util.Abs(X - other.X) + Util.Abs(Y - other.Y); }
/** * Analyzes an section of an image to determine it's properties. * Specifcally if it is empty, if the two layers differ, and it generates a name that can be used to sufficiently uniquely identify a tile */ private static Tile AnalyzeImageTile(Bitmap publicLayer, Bitmap secretLayer, Rectangle rect, DirectoryInfo saveTiles, int borderWidth) { Contract.Requires(publicLayer != null); Contract.Requires(rect.Width > 0); Contract.Requires(rect.Height > 0); Contract.Requires(rect.Left >= 0); Contract.Requires(rect.Top >= 0); Rectangle innerRect = new Rectangle(rect.X + borderWidth, rect.Y + borderWidth, rect.Width - borderWidth * 2, rect.Height - borderWidth * 2); if (innerRect.Left < 0 || innerRect.Top < 0) { throw new CodeContractsException(); } Tile result = new Tile(); byte[] publicBytes = null; byte[] secretBytes = null; publicBytes = getBytes(publicLayer, innerRect); if (secretLayer != null && secretLayer != publicLayer) { secretBytes = getBytes(secretLayer, innerRect); } else { secretBytes = publicBytes; } if (publicBytes == null) { throw new CodeContractsException(); } int size = publicBytes.Length; bool PAllZero = true; bool PAllFF = true; bool SAllZero = true; bool SAllFF = true; bool AllSame = true; for (int i = 0; i < size; i++) { if (publicBytes[i] != 0) { PAllZero = false; } if (publicBytes[i] != 255) { PAllFF = false; } } if (secretBytes != null) { if (size > secretBytes.Length) { throw new CodeContractsException(); } for (int i = 0; i < size; i++) { if (secretBytes[i] != 0) { SAllZero = false; } if (secretBytes[i] != 255) { SAllFF = false; } if (publicBytes[i] != secretBytes[i]) { AllSame = false; } } } //re-fetch image with wider borders innerRect = new Rectangle(rect.X + (borderWidth - 1), rect.Y + (borderWidth - 1), rect.Width - (borderWidth - 1) * 2, rect.Height - (borderWidth - 1) * 2); publicBytes = getBytes(publicLayer, innerRect); if (secretLayer != null && secretLayer != publicLayer) { secretBytes = getBytes(secretLayer, innerRect); } else { secretBytes = publicBytes; } String pName = makeName(publicBytes) + ".png"; String sName = secretBytes != null ? makeName(secretBytes) + ".png" : pName; result.HasSecret = !AllSame; result.IsEmptyPublic = PAllZero || PAllFF; result.IsEmptySecret = SAllZero || SAllFF; result.ImageNamePublic = pName; result.ImageNameSecret = sName; if (saveTiles != null && !result.IsAlwaysEmpty) { String pFileName = Path.Combine(saveTiles.FullName, pName); String sFileName = Path.Combine(saveTiles.FullName, sName); if (String.IsNullOrWhiteSpace(pFileName) || String.IsNullOrWhiteSpace(sFileName)) { throw new CodeContractsException("This should never be called because I appended a literal string to both pName and sName"); } SaveTile(publicLayer, rect, pFileName); if (!AllSame && secretLayer != null) { SaveTile(secretLayer, rect, sFileName); } } return result; }
public static MapInfo Deserialize(Stream stream, DirectoryInfo tileFolder, bool isCompressed = true) { Contract.Requires(stream != null); Contract.Requires(tileFolder != null); if (!tileFolder.Exists) { tileFolder.Create(); } foreach (FileInfo tile in tileFolder.GetFiles()) { tile.Delete(); } MapInfoSerializeContainer container; if (isCompressed) { using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Decompress)) { container = Serializer.Deserialize<MapInfoSerializeContainer>(ds); } } else { container = Serializer.Deserialize<MapInfoSerializeContainer>(stream); } foreach (String tile in container.TileImages.Keys) { using (FileStream ts = new FileStream(Path.Combine(tileFolder.FullName, tile), FileMode.Create)) { byte[] bytes = container.TileImages[tile]; ts.Write(bytes, 0, bytes.Length); } } MapInfo map = new MapInfo(); map.TileFolder = tileFolder; map.GridConfig.TileWidth = container.Grid.Width; map.GridConfig.TileHeight = container.Grid.Height; map.GridConfig.TileOffsetX = container.Grid.OffsetX; map.GridConfig.TileOffsetY = container.Grid.OffsetY; map.GridConfig.TileBorder = container.Grid.Border; map.PublicImage = LoadImage(container.PublicImage); map.SecretImage = LoadImage(container.SecretImage); Dictionary<MapInfoSerializeContainer.TileClass, Tile> convertedTiles = new Dictionary<MapInfoSerializeContainer.TileClass, Tile>(); if (container.Tiles != null) { foreach (MapInfoSerializeContainer.TileClass serializedTile in container.Tiles) { Tile tile = new Tile(); tile.X = serializedTile.X; tile.Y = serializedTile.Y; tile.IsEmptyPublic = serializedTile.EmptyPublic; tile.IsEmptySecret = serializedTile.EmptySecret; tile.HasSecret = serializedTile.HasSecret; tile.IsRevealed = serializedTile.IsRevealed; tile.ImageNamePublic = serializedTile.NamePublic; tile.ImageNameSecret = serializedTile.NameSecret; tile.LightLevel = serializedTile.LightLevel; tile.LightSource = serializedTile.LightSource; convertedTiles.Add(serializedTile, tile); map.Tiles.Add(tile); } foreach (MapInfoSerializeContainer.TileClass serializedTile in container.Tiles) { if (serializedTile.Adjacent == null) { continue; } Tile tile = convertedTiles[serializedTile]; foreach (MapInfoSerializeContainer.TileClass adjacent in serializedTile.Adjacent) { tile.AdjacentTiles.Add(convertedTiles[adjacent]); } if (serializedTile.NoLOS != null) { foreach (MapInfoSerializeContainer.TileClass noLOS in serializedTile.NoLOS) { tile.NoLOSBetweenTiles.Add(convertedTiles[noLOS]); } } } } int playerNum = 1; if (container.PlayerPositions != null) { foreach (MapInfoSerializeContainer.TileClass position in container.PlayerPositions) { map.MovePlayer(playerNum++, convertedTiles[position]); } } return map; }