public IEnumerable<Actor> GetUnitsAt(CPos a, SubCell sub) { if (!map.IsInMap(a)) yield break; for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell)) yield return i.actor; }
public bool AnyUnitsAt(CPos a, SubCell sub) { for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) if (i.subCell == sub || i.subCell == SubCell.FullCell) return true; return false; }
public SubCell? FreeSubCell(CPos a) { if (!HasFreeSubCell(a)) return null; return new[]{ SubCell.TopLeft, SubCell.TopRight, SubCell.Center, SubCell.BottomLeft, SubCell.BottomRight }.First(b => !AnyUnitsAt(a,b)); }
public IEnumerable<Actor> GetUnitsAt(CPos a) { if (!map.IsInMap(a)) yield break; for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) if (!i.actor.Destroyed) yield return i.actor; }
public static PathSearch FromPoint(World world, MobileInfo mi, Actor self, CPos from, CPos target, bool checkForBlocked) { var search = new PathSearch(world, mi, self) { Heuristic = DefaultEstimator(target), CheckForBlocked = checkForBlocked }; search.AddInitialCell(from); return search; }
Order(string orderString, Actor subject, Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation) { this.OrderString = orderString; this.Subject = subject; this.TargetActor = targetActor; this.TargetLocation = targetLocation; this.TargetString = targetString; this.Queued = queued; this.ExtraLocation = extraLocation; }
Order(string orderString, Actor subject, Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation, uint extraData) { OrderString = orderString; Subject = subject; TargetActor = targetActor; TargetLocation = targetLocation; TargetString = targetString; Queued = queued; ExtraLocation = extraLocation; ExtraData = extraData; }
public static Func<CPos, int> DefaultEstimator(CPos destination) { return here => { var diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y)); var straight = Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y); // HACK: this relies on fp and cell-size assumptions. var h = (3400 * diag / 24) + 100 * (straight - (2 * diag)); return (int)(h * 1.001); }; }
public static PathSearch FromPoints(World world, MobileInfo mi, Actor self, IEnumerable<CPos> froms, CPos target, bool checkForBlocked) { var search = new PathSearch(world, mi, self) { Heuristic = DefaultEstimator(target), CheckForBlocked = checkForBlocked }; foreach (var sl in froms) search.AddInitialCell(sl); return search; }
public CPos ChooseClosestEdgeCell(CPos pos) { var mpos = pos.ToMPos(this); var horizontalBound = ((mpos.U - Bounds.Left) < Bounds.Width / 2) ? Bounds.Left : Bounds.Right; var verticalBound = ((mpos.V - Bounds.Top) < Bounds.Height / 2) ? Bounds.Top : Bounds.Bottom; var distX = Math.Abs(horizontalBound - mpos.U); var distY = Math.Abs(verticalBound - mpos.V); return distX < distY ? new MPos(horizontalBound, mpos.V).ToCPos(this) : new MPos(mpos.U, verticalBound).ToCPos(this); }
public bool Contains(CPos cell) { return Contains(cell.ToMPos(this)); }
public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml, Action <MapPreview> parseMetadata = null) { var newData = innerData.Clone(); newData.Status = status; newData.Class = MapClassification.Remote; if (status == MapStatus.DownloadAvailable) { try { var r = FieldLoader.Load <RemoteMapData>(yaml); // Map download has been disabled server side if (!r.downloading) { newData.Status = MapStatus.Unavailable; return; } newData.Title = r.title; newData.Categories = r.categories; newData.Author = r.author; newData.PlayerCount = r.players; newData.Bounds = r.bounds; newData.TileSet = r.tileset; var spawns = new CPos[r.spawnpoints.Length / 2]; for (var j = 0; j < r.spawnpoints.Length; j += 2) { spawns[j / 2] = new CPos(r.spawnpoints[j], r.spawnpoints[j + 1]); } newData.SpawnPoints = spawns; newData.GridType = r.map_grid_type; newData.Preview = new Bitmap(new MemoryStream(Convert.FromBase64String(r.minimap))); var playersString = Encoding.UTF8.GetString(Convert.FromBase64String(r.players_block)); newData.Players = new MapPlayers(MiniYaml.FromString(playersString)); newData.SetRulesetGenerator(modData, () => { var rulesString = Encoding.UTF8.GetString(Convert.FromBase64String(r.rules)); var rulesYaml = new MiniYaml("", MiniYaml.FromString(rulesString)).ToDictionary(); var ruleDefinitions = LoadRuleSection(rulesYaml, "Rules"); var weaponDefinitions = LoadRuleSection(rulesYaml, "Weapons"); var voiceDefinitions = LoadRuleSection(rulesYaml, "Voices"); var musicDefinitions = LoadRuleSection(rulesYaml, "Music"); var notificationDefinitions = LoadRuleSection(rulesYaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(rulesYaml, "Sequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return(Pair.New(rules, flagged)); }); } catch (Exception) { } // Commit updated data before running the callbacks innerData = newData; if (innerData.Preview != null) { cache.CacheMinimap(this); } if (parseMetadata != null) { parseMetadata(this); } } // Update the status and class unconditionally innerData = newData; }
public WPos CenterOfCell(CPos cell) { if (TileShape == TileShape.Rectangle) return new WPos(1024 * cell.X + 512, 1024 * cell.Y + 512, 0); // Convert from diamond cell position (x, y) to world position (u, v): // (a) Consider the relationships: // - Center of origin cell is (512, 512) // - +x adds (512, 512) to world pos // - +y adds (-512, 512) to world pos // (b) Therefore: // - ax + by adds (a - b) * 512 + 512 to u // - ax + by adds (a + b) * 512 + 512 to v var z = Contains(cell) ? 512 * MapHeight.Value[cell] : 0; return new WPos(512 * (cell.X - cell.Y), 512 * (cell.X + cell.Y + 1), z); }
public CPos Clamp(CPos cell) { var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1); return MapToCell(TileShape, CellToMap(TileShape, cell).Clamp(bounds)); }
public bool AnyUnitsAt(CPos a) { return influence[ a.X, a.Y ] != null; }
public static Order Deserialize(World world, BinaryReader r) { try { var type = (OrderType)r.ReadByte(); switch (type) { case OrderType.Fields: { var order = r.ReadString(); var flags = (OrderFields)r.ReadByte(); Actor subject = null; if (flags.HasField(OrderFields.Subject)) { var subjectId = r.ReadUInt32(); if (world != null) { TryGetActorFromUInt(world, subjectId, out subject); } } var target = Target.Invalid; if (flags.HasField(OrderFields.Target)) { switch ((TargetType)r.ReadByte()) { case TargetType.Actor: { Actor targetActor; if (world != null && TryGetActorFromUInt(world, r.ReadUInt32(), out targetActor)) { target = Target.FromActor(targetActor); } break; } case TargetType.FrozenActor: { var playerActorID = r.ReadUInt32(); var frozenActorID = r.ReadUInt32(); Actor playerActor; if (world == null || !TryGetActorFromUInt(world, playerActorID, out playerActor)) { break; } if (playerActor.Owner.FrozenActorLayer == null) { break; } var frozen = playerActor.Owner.FrozenActorLayer.FromID(frozenActorID); if (frozen != null) { target = Target.FromFrozenActor(frozen); } break; } case TargetType.Terrain: { if (flags.HasField(OrderFields.TargetIsCell)) { var cell = new CPos(r.ReadInt32()); var subCell = (SubCell)r.ReadByte(); if (world != null) { target = Target.FromCell(world, cell, subCell); } } else { var pos = new WPos(r.ReadInt32(), r.ReadInt32(), r.ReadInt32()); target = Target.FromPos(pos); } break; } } } var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null; var queued = flags.HasField(OrderFields.Queued); Actor[] extraActors = null; if (flags.HasField(OrderFields.ExtraActors)) { var count = r.ReadInt32(); if (world != null) { extraActors = Exts.MakeArray(count, _ => world.GetActorById(r.ReadUInt32())); } else { r.ReadBytes(4 * count); } } var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32()) : CPos.Zero; var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0; if (world == null) { return(new Order(order, null, target, targetString, queued, extraActors, extraLocation, extraData)); } if (subject == null && flags.HasField(OrderFields.Subject)) { return(null); } return(new Order(order, subject, target, targetString, queued, extraActors, extraLocation, extraData)); } case OrderType.Handshake: { var name = r.ReadString(); var targetString = r.ReadString(); return(new Order(name, null, false) { Type = OrderType.Handshake, TargetString = targetString }); } default: { Log.Write("debug", "Received unknown order with type {0}", type); return(null); } } } catch (Exception e) { Log.Write("debug", "Caught exception while processing order"); Log.Write("debug", e.ToString()); // HACK: this can hopefully go away in the future Game.Debug("Ignoring malformed order that would have crashed the game"); Game.Debug("Please file a bug report and include the replay from this match"); return(null); } }
public bool IsInMap(CPos xy) { return IsInMap(xy.X, xy.Y); }
public static IEnumerable <Actor> FindActorsInBox(this World world, CPos tl, CPos br) { // TODO: Support diamond boxes for isometric maps? return(world.FindActorsInBox(tl.TopLeft, br.BottomRight)); }
Order(string orderString, Actor subject, Target target, string targetString, bool queued, Actor[] extraActors, CPos extraLocation, uint extraData) { OrderString = orderString ?? ""; Subject = subject; Target = target; TargetString = targetString; Queued = queued; ExtraActors = extraActors; ExtraLocation = extraLocation; ExtraData = extraData; }
public static CPos ClampToWorld(this World world, CPos xy) { var r = world.Map.Bounds; return(xy.Clamp(new Rectangle(r.X, r.Y, r.Width - 1, r.Height - 1))); }
public static TerrainTypeInfo GetTerrainInfo(this World world, CPos cell) { return(world.TileSet.Terrain[world.GetTerrainType(cell)]); }
public static string GetTerrainType(this World world, CPos cell) { var custom = world.Map.CustomTerrain[cell.X, cell.Y]; return(custom ?? world.TileSet.GetTerrainType(world.Map.MapTiles.Value[cell.X, cell.Y])); }
// Both ranges are inclusive because everything that calls it is designed for maxRange being inclusive: // it rounds the actual distance up to the next integer so that this call // will return any cells that intersect with the requested range circle. // The returned positions are sorted by distance from the center. public IEnumerable<CPos> FindTilesInAnnulus(CPos center, int minRange, int maxRange) { if (maxRange < minRange) throw new ArgumentOutOfRangeException("maxRange", "Maximum range is less than the minimum range."); if (maxRange > TilesByDistance.Length) throw new ArgumentOutOfRangeException("maxRange", "The requested range ({0}) exceeds the maximum allowed ({1})".F(maxRange, MaxTilesInCircleRange)); for (var i = minRange; i <= maxRange; i++) { foreach (var offset in TilesByDistance[i]) { var t = offset + center; if (Contains(t)) yield return t; } } }
public CPos ChooseClosestEdgeCell(CPos cell) { return(ChooseClosestEdgeCell(cell.ToMPos(TileShape)).ToCPos(TileShape)); }
public byte GetTerrainIndex(CPos cell) { var uv = cell.ToMPos(this); var custom = CustomTerrain[uv]; return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]); }
public Player(World world, Session.Client client, PlayerReference pr, MersenneTwister playerRandom) { World = world; InternalName = pr.Name; PlayerReference = pr; inMissionMap = world.Map.Visibility.HasFlag(MapVisibility.MissionSelector); // Real player or host-created bot if (client != null) { ClientIndex = client.Index; Color = client.Color; PlayerName = ResolvePlayerName(client, world.LobbyInfo.Clients, world.Map.Rules.Actors["player"].TraitInfos <IBotInfo>()); BotType = client.Bot; Faction = ResolveFaction(world, client.Faction, playerRandom, !pr.LockFaction); DisplayFaction = ResolveDisplayFaction(world, client.Faction); var assignSpawnPoints = world.WorldActor.TraitOrDefault <IAssignSpawnPoints>(); HomeLocation = assignSpawnPoints?.AssignHomeLocation(world, client, playerRandom) ?? pr.HomeLocation; SpawnPoint = assignSpawnPoints?.SpawnPointForPlayer(this) ?? client.SpawnPoint; DisplaySpawnPoint = client.SpawnPoint; } else { // Map player ClientIndex = 0; // Owned by the host (TODO: fix this) Color = pr.Color; PlayerName = pr.Name; NonCombatant = pr.NonCombatant; Playable = pr.Playable; spectating = pr.Spectating; BotType = pr.Bot; Faction = ResolveFaction(world, pr.Faction, playerRandom, false); DisplayFaction = ResolveDisplayFaction(world, pr.Faction); HomeLocation = pr.HomeLocation; SpawnPoint = DisplaySpawnPoint = 0; } if (!spectating) { PlayerMask = new LongBitSet <PlayerBitMask>(InternalName); } // Set this property before running any Created callbacks on the player actor IsBot = BotType != null; // Special case handling is required for the Player actor: // Since Actor.Created would be called before PlayerActor is assigned here // querying player traits in INotifyCreated.Created would crash. // Therefore assign the uninitialized actor and run the Created callbacks // by calling Initialize ourselves. var playerActorType = world.Type == WorldType.Editor ? EditorPlayerActorType : PlayerActorType; PlayerActor = new Actor(world, playerActorType, new TypeDictionary { new OwnerInit(this) }); PlayerActor.Initialize(true); Shroud = PlayerActor.Trait <Shroud>(); FrozenActorLayer = PlayerActor.TraitOrDefault <FrozenActorLayer>(); // Enable the bot logic on the host if (IsBot && Game.IsHost) { var logic = PlayerActor.TraitsImplementing <IBot>().FirstOrDefault(b => b.Info.Type == BotType); if (logic == null) { Log.Write("debug", "Invalid bot type: {0}", BotType); } else { logic.Activate(this); } } stanceColors.Self = ChromeMetrics.Get <Color>("PlayerStanceColorSelf"); stanceColors.Allies = ChromeMetrics.Get <Color>("PlayerStanceColorAllies"); stanceColors.Enemies = ChromeMetrics.Get <Color>("PlayerStanceColorEnemies"); stanceColors.Neutrals = ChromeMetrics.Get <Color>("PlayerStanceColorNeutrals"); unlockRenderPlayer = PlayerActor.TraitsImplementing <IUnlocksRenderPlayer>().ToArray(); }
public int FacingBetween(CPos cell, CPos towards, int fallbackfacing) { return(Traits.Util.GetFacing(CenterOfCell(towards) - CenterOfCell(cell), fallbackfacing)); }
public bool FogObscures(CPos p) { return(RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p)); }
public bool HasFreeSubCell(CPos a) { if (!AnyUnitsAt(a)) return true; return new[]{ SubCell.TopLeft, SubCell.TopRight, SubCell.Center, SubCell.BottomLeft, SubCell.BottomRight }.Any(b => !AnyUnitsAt(a,b)); }
public bool ShroudObscures(CPos p) { return(RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p)); }
// Resolve an array index from cell coordinates int Index(CPos cell) { var uv = Map.CellToMap(Shape, cell); return(uv.Y * Size.Width + uv.X); }
public static int HashCPos(CPos i2) { return(((i2.X * 5) ^ (i2.Y * 3)) / 4); }
Order(string orderString, Actor subject, Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation, uint extraData) { this.OrderString = orderString; this.Subject = subject; this.TargetActor = targetActor; this.TargetLocation = targetLocation; this.TargetString = targetString; this.Queued = queued; this.ExtraLocation = extraLocation; this.ExtraData = extraData; }
public CPos Clamp(CPos cell) { return(Clamp(cell.ToMPos(this)).ToCPos(this)); }
public WPos CenterOfSubCell(CPos cell, SubCell subCell) { var index = (int)subCell; if (index >= 0 && index <= SubCellOffsets.Length) return CenterOfCell(cell) + SubCellOffsets[index]; return CenterOfCell(cell); }
public PathSearch FromPoint(CPos from) { AddInitialCell(from); return this; }
public CPos Clamp(CPos cell) { var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1); return cell.ToMPos(this).Clamp(bounds).ToCPos(this); }
public TerrainTypeInfo GetTerrainInfo(CPos cell) { return(cachedTileSet.Value[GetTerrainIndex(cell)]); }
public int FacingBetween(CPos cell, CPos towards, int fallbackfacing) { return Traits.Util.GetFacing(CenterOfCell(towards) - CenterOfCell(cell), fallbackfacing); }
// Resolve an array index from cell coordinates int Index(CPos cell) { return(Index(cell.ToMPos(Shape))); }
public IEnumerable<CPos> FindTilesInCircle(CPos center, int maxRange) { return FindTilesInAnnulus(center, 0, maxRange); }
public void FixOpenAreas(Ruleset rules) { var r = new Random(); var tileset = rules.TileSets[Tileset]; for (var j = Bounds.Top; j < Bounds.Bottom; j++) { for (var i = Bounds.Left; i < Bounds.Right; i++) { var cell = new CPos(i, j); var type = MapTiles.Value[cell].Type; var index = MapTiles.Value[cell].Index; if (!tileset.Templates.ContainsKey(type)) { Console.WriteLine("Unknown Tile ID {0}".F(type)); continue; } var template = tileset.Templates[type]; if (!template.PickAny) continue; index = (byte)r.Next(0, template.TilesCount); MapTiles.Value[cell] = new TerrainTile(type, index); } } }
public TerrainTypeInfo GetTerrainInfo(CPos cell) { return cachedTileSet.Value[GetTerrainIndex(cell)]; }
public int GetTerrainIndex(CPos cell) { var custom = CustomTerrain[cell]; return custom != -1 ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[cell]); }
public static CPos Max(CPos a, CPos b) { return new CPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public IEnumerable <CPos> FindTilesInCircle(CPos center, int maxRange, bool allowOutsideBounds = false) { return(FindTilesInAnnulus(center, 0, maxRange, allowOutsideBounds)); }
public void AddInitialCell(CPos location) { if (!self.World.Map.Contains(location)) return; CellInfo[location] = new CellInfo(0, location, false); Queue.Add(new PathDistance(Heuristic(location), location)); }
public static CPos MapToCell(TileShape shape, CPos map) { if (shape == TileShape.Rectangle) return map; // Convert from rectangular map position to diamond cell position // - The staggered rows make this fiddly (hint: draw a diagram!) // (a) Consider the relationships: // - +1u (even -> odd) adds (1, -1) to (x, y) // - +1v (even -> odd) adds (1, 0) to (x, y) // - +1v (odd -> even) adds (0, 1) to (x, y) // (b) Therefore: // - au + 2bv adds (a + b) to (x, y) // - a correction factor is added if v is odd var offset = (map.Y & 1) == 1 ? 1 : 0; var y = (map.Y - offset) / 2 - map.X; var x = map.Y - y; return new CPos(x, y); }
public static CPos CellToMap(TileShape shape, CPos cell) { if (shape == TileShape.Rectangle) return cell; // Convert from diamond cell (x, y) position to rectangular map position (u, v) // - The staggered rows make this fiddly (hint: draw a diagram!) // (a) Consider the relationships: // - +1x (even -> odd) adds (0, 1) to (u, v) // - +1x (odd -> even) adds (1, 1) to (u, v) // - +1y (even -> odd) adds (-1, 1) to (u, v) // - +1y (odd -> even) adds (0, 1) to (u, v) // (b) Therefore: // - ax + by adds (a - b)/2 to u (only even increments count) // - ax + by adds a + b to v var u = (cell.X - cell.Y) / 2; var v = cell.X + cell.Y; return new CPos(u, v); }
public bool IsInMap(CPos xy) { return(IsInMap(xy.X, xy.Y)); }