public async Task<GameRoom> StartGameAsync(HubCallerContext context) { var gameRoom = new GameRoom(context); // gameRoom.Towers = gameRoom.Towers.Union(TestingConstants.Maze).ToList(); // TODO remove test code this.scaleoutService.Subscribe(Persist.GameRoom, gameRoom.Id, context); this.scaleoutService.Store(Persist.GameRoom, gameRoom.Id, gameRoom); return gameRoom; }
public void RemoveMobsAtEnding(Mob mob, GameRoom room, GameRound round) { if (Point.IsNear(mob.CurrentLocation, mob.EndingLocation, 0.5)) { foreach (var player in room.Players) { if (mob.EndingLocation.X == player.EndingLocation.X && mob.EndingLocation.Y == player.EndingLocation.Y) { player.CurrentLife -= 1; round.Mobs.Remove(mob); this.scaleoutService.Store(Persist.GameRoom, room.Id, room); break; } } } }
public void UpdateMobLocation(Mob mob, GameRoom room, GameRound round) { var span = DateTime.UtcNow.Subtract(mob.LastUpdated); if (span.Milliseconds > 0) { var next = mob.Path?.FirstOrDefault(); if(next != null && Point.IsNear(mob.CurrentLocation, next, 0.1)) { mob.Path = mob.Path.Skip(1); next = mob.Path?.FirstOrDefault(); } if(mob.Path == null || next == null) { next = this.CalculateMobPath(mob, room); } if (next != null) { var moveSpeed = mob.CurrentSpeed; // Adjust mob speed for slow effects if ((mob.Status as IDictionary<string, object>)?.ContainsKey("slow") ?? false) { moveSpeed = (int)(moveSpeed * (double)mob.Status.slow.speed); if (DateTime.UtcNow > (DateTime)mob.Status.slow.remaining) { var status = (IDictionary<string, object>)mob.Status; status.Remove("slow"); } } mob.CurrentLocation = Point.TrackTo(mob.CurrentLocation, next, (span.TotalMilliseconds * moveSpeed / Constants.GameSpeed)); // mob.Path = path?.ToList(); // Debugging } else { Console.WriteLine("No valid path found for mob"); mob.CurrentLocation = new Point(mob.EndingLocation.X, mob.EndingLocation.Y); } mob.LastUpdated = DateTime.UtcNow; } }
public void TickDots(Mob mob, GameRoom room, GameRound round) { if((mob.Status as IDictionary<string, object>)?.ContainsKey("dot") ?? false) { var span = DateTime.UtcNow.Subtract((DateTime)mob.Status.dot.lastUpdated); if(span.TotalMilliseconds > 500) { mob.Health -= (int)mob.Status.dot.damage; mob.Status.dot.lastUpdated = DateTime.UtcNow; if(DateTime.UtcNow > (DateTime)mob.Status.dot.remaining) { (mob.Status as IDictionary<string, object>).Remove("dot"); } if(mob.Health <= 0) { round.Mobs.Remove(mob); } } } }
public void UpdateProjectiles(GameRoom room, GameRound round) { foreach (var tower in room.Towers.Values) { if (tower.Damage > 0 && tower.ReadyAt <= DateTime.UtcNow) { foreach (Mob mob in round.Mobs) { if (Point.IsNear(tower.Location, mob.CurrentLocation, tower.Range)) { round.Projectiles.Add(new Projectile(tower, mob)); tower.ReadyAt = DateTime.UtcNow.AddMilliseconds(tower.Speed); // TODO: Should have a Game constant scale modifier here break; } } } } foreach(Projectile projectile in round.Projectiles.Reverse()) { var span = DateTime.UtcNow.Subtract(projectile.LastUpdated); projectile.Location = Point.TrackTo(projectile.Location, projectile.Target.CurrentLocation, (span.Milliseconds * (projectile.Speed / Constants.GameSpeed))); if (Point.IsNear(projectile.Location, projectile.Target.CurrentLocation, 0.1)) // projectile.Location.X == projectile.Target.CurrentLocation) { TowerType towerType; switch(projectile.TowerType) { case Constants.TowerList.Slowing: towerType = GameDataUtils.GetTowerTypeFromTowerList(projectile.TowerType); projectile.Target.Status.slow = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(towerType.Effects.slow)); projectile.Target.Status.slow.remaining = DateTime.UtcNow.AddMilliseconds((int)towerType.Effects.slow.duration); break; case Constants.TowerList.Dot: towerType = GameDataUtils.GetTowerTypeFromTowerList(projectile.TowerType); projectile.Target.Status.dot = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(towerType.Effects.dot)); if(!((projectile.Target.Status.dot as IDictionary<string, object>)?.ContainsKey("lastUpdated") ?? false)) { projectile.Target.Status.dot.lastUpdated = DateTime.UtcNow; } projectile.Target.Status.dot.remaining = DateTime.UtcNow.AddMilliseconds((int)towerType.Effects.dot.duration); break; default: // No-op break; } var abilities = projectile.Target.Type.Abilities; var damage = projectile.Damage; // Stoneskin game mechanic if (abilities?.Stoneskin.HasValue == true) { damage -= abilities.Stoneskin.Value; } // Evasion game mechanic if (abilities?.Evasion.HasValue == true) { var roll = random.Value.Next(100); if(roll < abilities.Evasion.Value) { damage = 0; } } projectile.Target.Health -= Math.Max(damage, 0); round.Projectiles.Remove(projectile); if (projectile.Target.Health <= 0) { // Fracture game mechanic if(abilities?.Fracture != null) { for (var i = 0; i < abilities.Fracture.Count; i++) { round.Mobs.Add(new Mob() { Type = projectile.Target.Type.Abilities.Fracture.Shard, CurrentLocation = new Point(projectile.Target.CurrentLocation), EndingLocation = new Point(projectile.Target.EndingLocation), Health = projectile.Target.Type.Abilities.Fracture.Shard.StartingHealth, CurrentSpeed = projectile.Target.Type.Abilities.Fracture.Shard.MoveSpeed }); } } // Avenger game mechanic if(abilities?.Avenger != null) { var range = projectile.Target.Type.Abilities.Avenger.Range; foreach(var mob in round.Mobs.Reverse()) { if(Point.IsNear(projectile.Target.CurrentLocation, mob.CurrentLocation, range)) { mob.CurrentSpeed *= (1 + projectile.Target.Type.Abilities.Avenger.Bonus); } } } round.Mobs.Remove(projectile.Target); } } projectile.LastUpdated = DateTime.UtcNow; } }
public GamePoint(GameRoom gameRoom, Point p) : this(gameRoom, (int)p.X, (int)p.Y) { }
public GamePoint(GameRoom gameRoom, double x, double y) : base(Math.Max(Math.Min(x, Constants.MapSize), 0), Math.Max(Math.Min(y, Constants.MapSize), 0)) { this.GameRoom = gameRoom; }
private GamePoint CalculateMobPath(Mob mob, GameRoom room) { var path = this.pathingService.FindPath<GamePoint>(new GamePoint(room, mob.CurrentLocation), new GamePoint(room, mob.EndingLocation), (p1, p2) => { // Euclidian Squared heuristic var dx = p1.X - p2.X; var dy = p1.Y - p2.Y; if (dx > 0) { dx += 1; } if (dy > 0) { dy += 1; } return Math.Sqrt(dx * dx + dy * dy); }, (p) => { // Euclidian squared heuristic estimate var dx = p.X - mob.EndingLocation.X; var dy = p.Y - mob.EndingLocation.Y; return dx * dx + dy * dy; }); mob.Path = path?.Reverse().Skip(1); return mob.Path?.FirstOrDefault(); }