/// <inheritdoc/> public void RemoveObject(ILocateable obj) { if (obj is IHasBucketInformation bucketInfo) { bucketInfo.CurrentBucket = null; } if (!this.Map[obj.X, obj.Y].Remove(obj)) { return; } if (obj is IBucketMapObserver observingPlayer) { foreach (var bucket in observingPlayer.ObservingBuckets) { bucket.ItemAdded -= observingPlayer.LocateableAdded; bucket.ItemRemoved -= observingPlayer.LocateableRemoved; } // TODO: Check if this is really neccessary. It may be that the client automatically removes all objects when you change a map or go back to character select if (observingPlayer.ObservingBuckets.Any(b => b.Count > 0)) { observingPlayer.LocateablesOutOfScope(observingPlayer.ObservingBuckets.SelectMany(o => o)); } observingPlayer.ObservingBuckets.Clear(); } }
/// <summary> /// Adds the locateable to the map. /// </summary> /// <param name="locateable">The locateable object.</param> public void Add(ILocateable locateable) { switch (locateable) { case DroppedItem droppedItem: droppedItem.Id = (ushort)this.dropIdGenerator.GetId(); Log.DebugFormat("{0}: Added drop {1}, {2}", this.Definition, droppedItem.Id, droppedItem.Item); break; case Player player: player.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added player {1}, {2}, ", this.Definition, player.Id, player); Interlocked.Increment(ref this.playerCount); break; case NonPlayerCharacter npc: npc.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added npc {1}, {2}", this.Definition, npc.Id, npc.Definition.Designation); break; case ISupportIdUpdate idUpdate: idUpdate.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added {1}", this.Definition, locateable); break; default: throw new ArgumentException($"Adding an object of type {locateable.GetType()} is not supported."); } this.objectsInMap.Add(locateable.Id, locateable); this.areaOfInterestManager.AddObject(locateable); this.ObjectAdded?.Invoke(this, new GameMapEventArgs(this, locateable)); }
/// <summary> /// Adds the locateable to the map. /// </summary> /// <param name="locateable">The locateable object.</param> public void Add(ILocateable locateable) { switch (locateable) { case DroppedItem droppedItem: droppedItem.Id = (ushort)this.dropIdGenerator.GetId(); break; case DroppedMoney droppedMoney: droppedMoney.Id = (ushort)this.dropIdGenerator.GetId(); break; case Player player: player.Id = (ushort)this.objectIdGenerator.GetId(); Interlocked.Increment(ref this.playerCount); break; case NonPlayerCharacter npc: npc.Id = (ushort)this.objectIdGenerator.GetId(); break; case ISupportIdUpdate idUpdate: idUpdate.Id = (ushort)this.objectIdGenerator.GetId(); break; default: throw new ArgumentException($"Adding an object of type {locateable.GetType()} is not supported."); } this.objectsInMap.Add(locateable.Id, locateable); this.areaOfInterestManager.AddObject(locateable); this.ObjectAdded?.Invoke(this, new GameMapEventArgs(this, locateable)); }
/// <inheritdoc/> public void ObjectMoved(ILocateable obj, MoveType type) { if (type == MoveType.Instant) { this.connection.Send(new byte[] { 0xC1, 0x08, (byte)PacketType.Teleport, obj.Id.GetHighByte(), obj.Id.GetLowByte(), obj.X, obj.Y, 0 }); } else { IList <Direction> steps = null; var supportWalk = obj as ISupportWalk; if (supportWalk != null) { steps = supportWalk.NextDirections.Select(d => d.Direction).ToList(); } var stepsSize = (steps?.Count / 2) + 1 ?? 1; byte[] walkPacket = new byte[7 + stepsSize]; walkPacket.SetValues <byte>(0xC1, (byte)walkPacket.Length, (byte)PacketType.Walk, obj.Id.GetHighByte(), obj.Id.GetLowByte(), supportWalk?.WalkTarget.X ?? obj.X, supportWalk?.WalkTarget.Y ?? obj.Y); if (steps != null) { for (int step = 0; step < steps.Count; step += 2) { var index = 7 + (step / 2); var firstStep = steps[step]; var secondStep = steps.Count > step + 2 ? steps[step + 2] : Direction.Undefined; walkPacket[index] = (byte)((int)firstStep << 4 | (int)secondStep); } } this.connection.Send(walkPacket); } }
/// <inheritdoc/> public void ObjectMoved(ILocateable movedObject, MoveType moveType) { Point targetPoint = movedObject.Position; object steps = null; int walkDelay = 0; if (movedObject is ISupportWalk walker && moveType == MoveType.Walk) { targetPoint = walker.WalkTarget; walkDelay = (int)walker.StepDelay.TotalMilliseconds; Span <WalkingStep> walkingSteps = new WalkingStep[16]; var stepCount = walker.GetSteps(walkingSteps); var walkSteps = walkingSteps.Slice(0, stepCount).ToArray().Select(step => new { x = step.To.X, y = step.To.Y, direction = step.Direction }).ToList(); var lastStep = walkSteps.LastOrDefault(); if (lastStep != null) { var lastPoint = new Point(lastStep.x, lastStep.y); var lastDirection = lastPoint.GetDirectionTo(targetPoint); if (lastDirection != Direction.Undefined) { walkSteps.Add(new { x = targetPoint.X, y = targetPoint.Y, direction = lastDirection }); } } steps = walkSteps; } this.clientProxy.SendAsync("ObjectMoved", movedObject.Id, targetPoint.X, targetPoint.Y, moveType, walkDelay, steps); }
/// <summary> /// Gets the distance to the specified coordinates. /// </summary> /// <param name="objectFrom">The object from which the distance is calculated.</param> /// <param name="x">The x coordinate of the point to which the distance is calculated.</param> /// <param name="y">The y coordinate of the point to which the distance is calculated.</param> /// <returns>The distance between this and the specified coordinates.</returns> public static double GetDistanceTo(this ILocateable objectFrom, byte x, byte y) { return (Math.Sqrt( Math.Pow(objectFrom.X - x, 2) + Math.Pow(objectFrom.Y - y, 2))); }
/// <summary> /// Adds the locateable to the map. /// </summary> /// <param name="locateable">The locateable object.</param> public void Add(ILocateable locateable) { if (locateable is DroppedItem droppedItem) { droppedItem.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added drop {1}, {2}", this.Definition, droppedItem.Id, droppedItem.Item); } if (locateable is Player player) { player.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added player {1}, {2}, ", this.Definition, player.Id, player); Interlocked.Increment(ref this.playerCount); this.stateObserver?.PlayerCountChanged(this.MapId, this.playerCount); } if (locateable is NonPlayerCharacter npc) { npc.Id = (ushort)this.objectIdGenerator.GetId(); Log.DebugFormat("{0}: Added npc {1}, {2}", this.Definition, npc.Id, npc.Definition.Designation); } this.objectsInMap.Add(locateable.Id, locateable); this.areaOfInterestManager.AddObject(locateable); this.ObjectAdded?.Invoke(this, new GameMapEventArgs(this, locateable)); }
/// <inheritdoc/> public void RemoveObject(ILocateable obj) { if (obj is IHasBucketInformation bucketInfo) { bucketInfo.OldBucket = this.Map[obj.X, obj.Y]; bucketInfo.NewBucket = null; } if (!this.Map[obj.X, obj.Y].Remove(obj)) { return; } if (obj is IBucketMapObserver observingPlayer) { foreach (var bucket in observingPlayer.ObservingBuckets) { bucket.ItemAdded -= observingPlayer.LocateableAdded; bucket.ItemRemoved -= observingPlayer.LocateableRemoved; } if (observingPlayer.ObservingBuckets.Any(b => b.Count > 0)) { observingPlayer.LocateablesOutOfScope(observingPlayer.ObservingBuckets.SelectMany(o => o)); } observingPlayer.ObservingBuckets.Clear(); } }
/// <summary> /// An object moved on the map. /// </summary> /// <param name="sender">The sender.</param> /// <param name="movedObject">The moved object.</param> /// <param name="moveType">Type of the move.</param> public void ObjectMoved(WorldObserverToHubAdapter sender, ILocateable movedObject, MoveType moveType) { byte x, y; object steps = null; int walkDelay = 0; if (movedObject is ISupportWalk walkable && moveType == MoveType.Walk) { x = walkable.WalkTarget.X; y = walkable.WalkTarget.Y; walkDelay = (int)walkable.StepDelay.TotalMilliseconds; var walkSteps = walkable.NextDirections.Select(step => new { x = step.To.Y, y = step.To.Y, direction = step.Direction }).ToList(); // TODO: Can errors happen here when NextDirection changes in the meantime? var lastStep = walkable.NextDirections.LastOrDefault(); if (!Equals(lastStep, default(WalkingStep))) { var lastDirection = lastStep.To.GetDirectionTo(walkable.WalkTarget); if (lastDirection != Direction.Undefined) { walkSteps.Add(new { x, y, direction = lastDirection }); } } steps = walkSteps; }
/// <inheritdoc/> /// <remarks> /// This needs to take into account, that the <see cref="Walker"/> might change the <see cref="ILocateable.X"/> and <see cref="ILocateable.Y"/>, /// but not updating the buckets. So accessing the bucket of the current coordinates might not be the current bucket! /// </remarks> public void RemoveObject(ILocateable obj) { if (obj is IHasBucketInformation bucketInfo) { // we remove the object from all known buckets and set old/new bucket to null bucketInfo.NewBucket?.Remove(obj); bucketInfo.OldBucket?.Remove(obj); bucketInfo.OldBucket = null; bucketInfo.NewBucket = null; } else { this.Map[obj.X, obj.Y].Remove(obj); } if (obj is IBucketMapObserver observingPlayer) { foreach (var bucket in observingPlayer.ObservingBuckets) { bucket.ItemAdded -= observingPlayer.LocateableAdded; bucket.ItemRemoved -= observingPlayer.LocateableRemoved; } if (observingPlayer.ObservingBuckets.Any(b => b.Count > 0)) { observingPlayer.LocateablesOutOfScope(observingPlayer.ObservingBuckets.SelectMany(o => o)); } observingPlayer.ObservingBuckets.Clear(); } }
/// <summary> /// Returns wether the given location has the given terrain characteristics /// </summary> public bool IsTerrain(ILocateable loc, Terrain terrain) { switch (terrain) { case Terrain.InEnemyRange: return(this.EnemyAttackMap.HasDangerousPiratesInAttackRange(loc)); case Terrain.EnemyLocation: // check for a current enemy Pirate p = this.GetPirateOn(loc); if (p != null && p.Owner != Owner.Me) { return(true); } // check for an enemy spawning p = this.GetPirateSpawnOn(loc); if (p != null && p.TurnsToRevive == 1 && p.Owner != Owner.Me) { return(true); } // else, there is no enemy there return(false); case Terrain.CurrentTreasureLocation: return(this.GetTreasuresOn(loc).Count > 0); default: return(false); } }
/// <summary> /// Returns a list of pirates that are within attack range of "loc", and their state is "state" /// </summary> public List <Pirate> GetPiratesInAttackRange(ILocateable loc, PirateState state) { if (!this.map.InMap(loc)) { return(null); } return(new List <Pirate>(this.attackRangeMap[loc.GetLocation().Row, loc.GetLocation().Collumn, (int)state])); }
/// <summary> /// Tries to add a taken location to the ResourcesPack /// </summary> /// <returns>Was the addition successful</returns> public bool AddTakenLocation(ILocateable l) { if (l == null || l.GetLocation() == null) { return(false); } return(this.takenLocations.Add(l.GetLocation())); }
//////////Methods////////// /// <summary> /// Creates a new sail command /// </summary> /// <param name="pirate">The pirate that will sail</param> /// <param name="immediateDestionation">The IMMEDIATE destination of the pirate</param> public SailCommand(Pirate pirate, ILocateable immediateDestionation) : base(pirate) { this.Pirate = pirate; this.ImmediateDestination = immediateDestionation.GetLocation(); this.distance = Game.ManhattanDistance(this.Pirate, this.ImmediateDestination); }
/// <summary> /// Tries to add a freed-up location to the ResourcesPack /// </summary> /// <returns>Was the addition successful</returns> public bool AddFreedLocation(ILocateable l) { if (l == null || l.GetLocation() == null) { return(false); } return(this.freedUpLocations.Add(l.GetLocation())); }
/// <summary> /// Returns wether the location given is inside the map /// </summary> public bool InMap(ILocateable l) { Location loc = l.GetLocation(); return(loc.Row >= 0 && loc.Row < this.Rows && loc.Collumn >= 0 && loc.Collumn < this.Collumns); }
/// <summary> /// Returns wether there are pirates whose state is "state", that are in attack range of "loc" /// </summary> public bool HasPiratesInAttackRange(ILocateable loc, PirateState state) { if (!this.map.InMap(loc)) { return(false); } return(this.attackRangeMap[loc.GetLocation().Row, loc.GetLocation().Collumn, (int)state].Count > 0); }
/// <summary> /// Removes the locateable from the map. /// </summary> /// <param name="locateable">The locateable.</param> public void Remove(ILocateable locateable) { if (this.objectsInMap.Remove(locateable.Id) && locateable.Id != 0 && locateable is DroppedItem) { this.freeDropIds.Add(locateable.Id); } this.areaOfInterestManager.RemoveObject(locateable); }
/// <summary> /// Returns a list of all the pirates which have one of the "states" given, ordered by their manhattan distance to "location" /// </summary> public List <Pirate> GetClosestPirates(ILocateable location, params PirateState[] states) { if (location == null || location.GetLocation() == null) { return(new List <Pirate>()); } return(this.GetPirates(states).OrderBy(pirate => Map.ManhattanDistance(pirate, location)).ToList()); }
/// <summary> /// Returns a list of pirates that actually CAN attack, that are in attack range of loc /// </summary> public List <Pirate> GetDangerousPiratesInAttackRange(ILocateable loc) { if (!this.map.InMap(loc)) { return(null); } return(this.attackRangeMap[loc.GetLocation().Row, loc.GetLocation().Collumn, (int)PirateState.Free].FindAll(p => p.CanAttack)); }
/// <summary> /// Returns if the given locations are in (euclidean) range of each other /// </summary> public static bool InEuclideanRange(ILocateable a, ILocateable b, double range) { if (a == null || a.GetLocation() == null || b == null || b.GetLocation() == null) { return(false); } return(Map.EuclideanDistance(a, b) <= range); }
/// <summary> /// Creates a map object for the given locateable object. /// </summary> /// <param name="locateable">The locateable object.</param> /// <returns>The created map object.</returns> public static MapObject CreateMapObject(this ILocateable locateable) { return(new MapObject { Direction = (locateable as IRotatable)?.Rotation ?? default, Id = locateable.Id, MapId = locateable.CurrentMap?.MapId ?? 0, Name = locateable.ToString() ?? string.Empty, X = locateable.Position.X, Y = locateable.Position.Y, });
//////////Methods////////// /// <summary> /// Creates a new treasure with the parameters given. /// carryingPirate can be null. /// </summary> public Treasure(int id, ILocateable location, TreasureState state, Pirate carryingPirate, int value) { this.Id = id; this.InitialLocation = location.GetLocation(); this.location = this.InitialLocation; this.state = state; this.carryingPirate = carryingPirate; this.Value = value; this.nativeObject = null; }
/// <summary> /// Determines whether the object is at the safezone of his current map. /// </summary> /// <param name="obj">The object.</param> /// <returns>True, if it is on the safezone of his current map; Otherwise, false.</returns> public static bool IsAtSafezone(this ILocateable obj) { var map = obj.CurrentMap; if (map == null) { return(true); } return(map.Terrain.SafezoneMap[obj.X, obj.Y]); }
/// <summary> /// Returns a list of neighbors in-map of the location given, that are away from the location as specified /// </summary> public List <Location> GetNeighbors(ILocateable l, int manhattanDistance) { if (l == null || l.GetLocation() == null || manhattanDistance < 0 || manhattanDistance >= this.neighbors.GetLength(2) || !this.InMap(l)) { return(null); } return(new List <Location> (this.neighbors[l.GetLocation().Row, l.GetLocation().Collumn, manhattanDistance])); }
/// <summary> /// Returns the treasure whose initial location is on the location given, or null if one does not exist /// </summary> public Treasure GetTreasureSpawnOn(ILocateable loc) { if (loc == null) { return(null); } if (this.treasuresSpawnOnMap.ContainsKey(loc.GetLocation())) { return(this.treasuresSpawnOnMap[loc.GetLocation()]); } return(null); }
/// <summary> /// Returns the pirate whose initial location is on the location given, or null if one does not exist /// </summary> public Pirate GetPirateSpawnOn(ILocateable loc) { if (loc == null) { return(null); } if (this.piratesSpawnOnMap.ContainsKey(loc.GetLocation())) { return(this.piratesSpawnOnMap[loc.GetLocation()]); } return(null); }
/// <summary> /// Returns the treasures which are on the location given /// </summary> public List <Treasure> GetTreasuresOn(ILocateable loc) { if (loc == null) { return(null); } if (this.treasuresOnMap.ContainsKey(loc.GetLocation())) { return(this.treasuresOnMap[loc.GetLocation()]); } return(new List <Treasure>()); }
/// <inheritdoc/> public void ObjectMoved(ILocateable obj, MoveType type) { var objectId = obj.GetId(this.player); if (type == MoveType.Instant) { this.connection.Send(new byte[] { 0xC1, 0x08, (byte)PacketType.Teleport, objectId.GetHighByte(), objectId.GetLowByte(), obj.X, obj.Y, 0 }); } else { IList <Direction> steps = null; var x = obj.X; var y = obj.Y; Direction rotation = Direction.Undefined; if (obj is ISupportWalk supportWalk) { if (this.SendWalkDirections) { steps = supportWalk.NextDirections.Select(d => d.Direction).ToList(); // The last one is the rotation rotation = steps.LastOrDefault(); steps.RemoveAt(steps.Count - 1); } if (obj is IRotateable rotateable) { rotation = rotateable.Rotation.RotateLeft(); } x = supportWalk.WalkTarget.X; y = supportWalk.WalkTarget.Y; } var stepsSize = (steps?.Count / 2) + 2 ?? 1; byte[] walkPacket = new byte[7 + stepsSize]; walkPacket.SetValues <byte>(0xC1, (byte)walkPacket.Length, (byte)PacketType.Walk, objectId.GetHighByte(), objectId.GetLowByte(), x, y, (byte)((steps?.Count ?? 0) | ((byte)rotation) << 4)); if (steps != null) { walkPacket[7] = (byte)((int)steps.First() << 4 | (int)steps.Count); for (int i = 0; i < steps.Count; i += 2) { var index = 8 + (i / 2); var firstStep = steps[i]; var secondStep = steps.Count > i + 2 ? steps[i + 2] : Direction.Undefined; walkPacket[index] = (byte)((int)firstStep << 4 | (int)secondStep); } } this.connection.Send(walkPacket); } }
/// <inheritdoc/> public void AddObject(ILocateable obj) { this.Map[obj.X, obj.Y].Add(obj); if (obj is IHasBucketInformation bucketInfo) { bucketInfo.CurrentBucket = this.Map[obj.X, obj.Y]; } if (obj is IBucketMapObserver observingPlayer) { this.UpdateObservingBuckets(obj.X, obj.Y, observingPlayer); } }