Beispiel #1
0
 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;
             }
         }
     }
 }
Beispiel #2
0
        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;
            }
        }
Beispiel #3
0
        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);
                    }
                }
            }
        }
Beispiel #4
0
        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;
            }
        }
Beispiel #5
0
        public async Task<bool> ProcessRoundAsync(string roomId)
        {
            var currentRound = this.scaleoutService.Get(Persist.GameRound, roomId) as GameRound;

            if(currentRound == null)
            {
                currentRound = new GameRound()
                {
                    Mobs = new List<Mob>(),
                    Projectiles = new List<Projectile>(),
                    RemainingMobs = Constants.RoundSize
                };

                this.scaleoutService.Store(Persist.GameRound, roomId, currentRound);

                // Move
                new Thread(async () =>
                {
                    int frame = 0;
                    GameRoom room = this.scaleoutService.Get(Persist.GameRoom, roomId) as GameRoom;
                    var startTime = DateTime.UtcNow;
                    var endTime = startTime.AddMinutes(60);

                    var round = this.scaleoutService.Get(Persist.GameRound, roomId) as GameRound;
                    if (round != null)
                    {

                        while (round.Mobs.Count > 0 || round.RemainingMobs > 0)
                        {
                            if (DateTime.UtcNow > endTime)
                            {
                                return; // Prevents runaway threads
                            }
                            
                            lock (room)
                            {
                                round = this.scaleoutService.Get(Persist.GameRound, roomId) as GameRound;

                                foreach (var mob in round.Mobs.Reverse()) // Iterate every mob
                                {
                                    this.mobMovementService.RemoveMobsAtEnding(mob, room, round);
                                    this.mobMovementService.UpdateMobLocation(mob, room, round);
                                    this.towerProjectileService.TickDots(mob, room, round);
                                }

                                // Iterates towers and projectile count
                                this.towerProjectileService.UpdateProjectiles(room, round);

                                this.scaleoutService.Store(Persist.GameRound, roomId, round);
                            }

                            frame++;

                            if(frame > 30)
                            {
                                frame = 0; // frame zero occurs roughly once a second, used for updates that don't need to occur as often
                            }
                            Thread.Sleep(30); // Makes ~30 FPS
                        }
                        
                        lock (room)
                        {
                            round.Projectiles.Clear();
                            this.scaleoutService.Store(Persist.GameRound, roomId, round);
                        }
                        await this.scaleoutService.Remove(Persist.GameRound, roomId);
                    }
                    else
                    {
                        Debug.WriteLine("Mob spawning thread ended early.");
                        return;
                    }
                }).Start();

                // Spawn mobs
                new Thread(() =>
                {
                   var totalMobs = currentRound.RemainingMobs; // snapshot of total count

                   for(int i = 0; i < totalMobs; i++)
                    {
                        GameRoom room = this.scaleoutService.Get(Persist.GameRoom, roomId) as GameRoom;
                        lock(room)
                        {
                            var round = this.scaleoutService.Get(Persist.GameRound, roomId) as GameRound;
                            for(var j = 0; j < room.Players.Count; j++)
                            {
                                round.Mobs.Add(new Mob()
                                {
                                    Health = Constants.MobTypes[0].StartingHealth,
                                    Type = Constants.MobTypes[0],
                                    CurrentLocation = room.Players[j].StartingLocation,
                                    EndingLocation = room.Players[j].EndingLocation,
                                    CurrentSpeed = Constants.MobTypes[0].MoveSpeed
                                });
                            }
                            round.RemainingMobs--;
                        }

                        Thread.Sleep(Constants.RoundPauseMs);
                    }
                }).Start();

                return true;
            }
            return false;
        }