using GlobalClassLib; using ONDServer.Map; using PacketLib; namespace ONDServer.Enemies; public class MareEnemy : Enemy { public override string Name{ get; } = "Mare"; public override int TypeId{ get; } = (int)EnemyType.MARE; public override bool BlocksTile{ get; set; } = true; private MarePathfinder pathfinder; private MovementOpportunity movementOpportunity; public ServerPlayer Target{ get; set; } public MareEnemy(int difficulty) : base(difficulty) { pathfinder = new MarePathfinder(this, 1); if (Server.P1.state.power > Server.P2.state.power){ Target = Server.P2; } else if(Server.P1.state.power < Server.P2.state.power){ Target = Server.P1; } else{ Target = new Random().Next(2) == 0 ? Server.P1 : Server.P2; } movementOpportunity = new MovementOpportunity(5000); SetDifficulty(difficulty); } public override void Reset() { pathfinder.TakenPath.Clear(); Target = Server.OtherPlayer(Target); Pathfinder.Decision decision = pathfinder.DecideNext(MapManager.Get(Target.state.officeTileId)); if (decision.type == Pathfinder.Decision.MoveType){ Location = decision.nextTile!; } Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);; } public override void SetDifficulty(int difficulty) { Difficulty = difficulty; movementOpportunity.MovementChance = ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10)); } public override void Spawn(MapTile location) { base.Spawn(location); // stopwatch.Start(); movementOpportunity.Start(); pathfinder.TakenPath.Add(Location); Server.SendUpdateToAll([GameEvent.ENEMY_SPAWN(TypeId, Id, Difficulty, Location.Id)]); } public override void Update() { base.Update(); if (movementOpportunity.CheckAndRoll()){ if (Location.Owner != null && Location.Lit){ Attack(Location.Owner); } Pathfinder.Decision decision = pathfinder.DecideNext(MapManager.Get(Target.state.officeTileId)); switch (decision.type){ case Pathfinder.Decision.MoveType: Location = decision.nextTile!; Server.SendUpdateToAll([GameEvent.ENEMY_MOVEMENT(Id, Location.Id)]); Console.WriteLine($"Enemy {TypeId} ({Name}) moving to {Location.PositionAsString})"); break; case Pathfinder.Decision.AttackType: Attack(decision.attackTarget!); break; case Pathfinder.Decision.ResetType: Reset(); break; case Pathfinder.Decision.WaitType: break; } } } private class MarePathfinder : RoamingPathfinder { // private Random random = new(); public MarePathfinder(Enemy enemy, int tolerance) : base(enemy, tolerance) { this.tolerance = tolerance; AdditionalConnectorFilter = c => c.Type != ConnectorType.VENT; } // public override Decision DecideNext(MapTile goal) { // Dictionary distances = Crawl(goal); // // List closerTiles = GetNeighbours(Enemy.Location, // c => !c.Blocked || c.Type == ConnectorType.DOOR_OFFICE, // t => distances.ContainsKey(t) && distances[t] <= distances[Enemy.Location] + tolerance); // if (closerTiles.Contains(goal)){ // if (Enemy.Location.GetConnector(goal)!.Blocked){ // return Decision.Reset(); // } // // return Decision.Attack(((MareEnemy)Enemy).Target); // } // // if (closerTiles.Count != 0 && closerTiles.All(t => takenPath.Contains(t))){ // takenPath.Clear(); // return DecideNext(goal); // } // closerTiles.RemoveAll(t => takenPath.Contains(t)); // // closerTiles.ForEach(t => distances[t] += Enemy.Location.GetConnector(t)!.Value); // double roll = random.NextDouble() * closerTiles.Sum(t => 1.0 / distances[t]); // foreach (var tile in closerTiles){ // if (roll <= 1.0 / distances[tile]){ // takenPath.Add(tile); // return Decision.Move(tile); // } // roll -= 1.0 / distances[tile]; // } // // return Decision.Wait(); // } } }