public static bool ShouldAttack(this Elf e, GameObject target) { var possibleAttackers = LocationFinder.GetPossibleAttackers(e); // the damage to the target is the damage by the elf and the suffocation damage int damageToTarget = e.AttackMultiplier + target.GetSuffocationPerTurn(); int turnsToKillTarget = (int)System.Math.Ceiling(1.0 * target.CurrentHealth / damageToTarget); // the damage done to the elf can be different every turn int health = e.CurrentHealth; for (int i = 0; i < turnsToKillTarget; i++) { foreach (var attacker in possibleAttackers) { if (attacker.CurrentHealth <= attacker.GetSuffocationPerTurn() * i) { continue; } health -= attacker.GetAttackMultiplier(); } } System.Console.WriteLine($"{health}:{turnsToKillTarget}:{target.Type}:{possibleAttackers.Count}"); // if the number of turns to kill the target are smaller then the number of turns to kill the elf // then elf will win the fight return(health == e.CurrentHealth || health >= GameState.Game.ElfMaxHealth / 2 || (target is Elf && health >= 0)); }
/// <summary> /// returns the target the elf should go and attack. exceptions are ignored /// </summary> /// <param name="e"> elf object </param> /// <param name="exceptions"></param> /// <returns></returns> public static GameObject GetMoveTarget(this Elf e, params GameObject[] exceptions) { IEnumerable <GameObject> allTargets = ((GameObject[])GameState.Game.GetEnemyPortals()) .Concat(GameState.Game.GetEnemyManaFountains()) .Concat(GameState.EnemyLivingElves); return((from target in allTargets let attackLocation = e.GetAttackLocation(target) where !exceptions.Contains(target) && (!(target is Elf) || target.CurrentHealth <= e.CurrentHealth) orderby LocationFinder.GetPossibleAttackers(e, attackLocation, exceptions: target).Count, e.Distance(attackLocation), target is Portal ? target.Distance(GameState.MyCastle) : int.MaxValue, target is ManaFountain ? 0 : 1, target.CurrentHealth select target).FirstOrDefault()); }
/// <summary> /// Returns true if it is safe to stay at the current location. /// Exceptions are ignored /// </summary> /// <param name="obj"></param> /// <param name="turns"></param> /// <param name="exceptions"></param> /// <returns></returns> public static bool SafeNotToMove(this GameObject obj, int turns = 1, params GameObject[] exceptions) { if (turns == 1) { return(LocationFinder.GetPossibleAttackers(obj, exceptions: exceptions).Count == 0); } int health = obj.CurrentHealth; int size = 0; if (obj is Building b) { size = b.Size; } var enemies = GameState.EnemyLivingElves.Cast <GameObject>() .Concat(GameState.EnemyLivingIceTrolls.Where(troll => troll.GetTarget().Equals(obj))).ToList(); var locations = GameState.EnemyLivingElves.Cast <GameObject>() .Concat(GameState.EnemyLivingIceTrolls) .ToDictionary(g => g, g => g.Location); // we simulate the turns for (int turn = 1; turn <= turns; turn++) { var enemiesToRemove = new List <GameObject>(); foreach (var enemy in enemies) { if (locations[enemy].InRange(obj, enemy.GetAttackRange() + size)) { health -= enemy.GetAttackMultiplier(); } else { locations[enemy] = locations[enemy].Towards(obj, enemy.GetMaxSpeed()); } if (enemy.CurrentHealth - enemy.GetSuffocationPerTurn() * turn <= 0) { enemiesToRemove.Add(enemy); } } enemies.RemoveAll(enemiesToRemove.Contains); } return(health > 0 && obj.CurrentHealth - health <= obj.MaxHealth / 2); }
public static void MoveToCastle(Elf e) { Location attackLocation = GameState.EnemyCastle.Location.Towards(e, e.AttackRange + GameState.EnemyCastle.Size); if (e.Location.Equals(attackLocation)) { if (e.ShouldAttack(GameState.EnemyCastle)) { e.Attack(GameState.EnemyCastle); return; } var target = e.GetAttackTarget(); if (target is Elf && LocationFinder.GetPossibleAttackers(e, exceptions: target).Count == 0) { e.Attack(target); return; } } e.MoveSafely(attackLocation); }