protected IFighterAction GetSkillMove(IBattlefield battlefield, IFighterStats target, IEnumerable <EngineRoundTick> roundTicks, EngineCalculationValues calculationValues)
        {
            var desiredSkill = 50F.Chance() ?
                               SkillFinder.GetMaxDamageSkill(this, SkillFinder.ExcludeSkillsOnCooldown(this, Skills, roundTicks), calculationValues) :
                               SkillFinder.GetMaxRangeSkill(this, SkillFinder.ExcludeSkillsOnCooldown(this, Skills, roundTicks), calculationValues);

            // reduce skill distance by 0.15F to compensate rounding differences
            var distance = (desiredSkill?.Range ?? 1.5F) - 0.15F;

            return(new Move()
            {
                Actor = this,
                NextPosition = PathFinder.GetPathToEnemy(this, target, distance, battlefield),
            });
        }
        public virtual IFighterAction GetFighterAction(
            IEnumerable <IFighterStats> visibleFighters,
            IBattlefield battlefield,
            IEnumerable <EngineRoundTick> roundTicks,
            EngineCalculationValues calculationValues)
        {
            var roam = new Move()
            {
                Actor        = this,
                NextPosition = PathFinder.GetRoamingPath(this, battlefield),
            };

            // Better not attack team members
            var visibleEnemies = visibleFighters
                                 .Where(o => o.Team == null || o.Team != Team);

            if (!visibleEnemies.Any())
            {
                // if this fighter can't see any enemy he roams
                return(roam);
            }

            var target = TargetFinder.GetTarget(visibleEnemies, this);
            var skill  = SkillFinder.GetSkill(this, target, SkillFinder.ExcludeSkillsOnCooldown(this, Skills, roundTicks), calculationValues);

            if (skill == null)
            {
                return(GetSkillMove(battlefield, target, roundTicks, calculationValues));
            }

            return(new Attack()
            {
                Actor = this,
                Skill = skill,
                Target = target,
            });
        }
        public override IFighterAction GetFighterAction(
            IEnumerable <IFighterStats> visibleFighters,
            IBattlefield battlefield,
            IEnumerable <EngineRoundTick> roundTicks,
            EngineCalculationValues calculationValues)
        {
            var visibleEnemies = visibleFighters
                                 .Where(o => o.Team == null || o.Team != Team);

            if (!visibleEnemies.Any())
            {
                return(new Move()
                {
                    Actor = this,
                    NextPosition = PathFinder.GetRoamingPath(this, battlefield),
                });
            }

            SetMaxHealth(roundTicks);

            var healthPercent = this.HealthRemaining(calculationValues) / (double)maxHealth;

            if (healthPercent <= 0.4)
            {
                var healskill = SkillFinder.GetHealSkill(this, Skills, roundTicks, calculationValues);
                if (healskill != null)
                {
                    return(new Heal()
                    {
                        Actor = this,
                        Target = this,
                        Skill = healskill,
                    });
                }
            }

            var intels = intelligenceProvider.GetIntels(this, roundTicks, calculationValues, visibleEnemies);

            var attackers = visibleEnemies.Where(o => intels.Where(i => i.LastTarget == Id).Select(i => i.Id).Contains(o.Id));

            if (attackers.Count() >= 2)
            {
                return(new Move()
                {
                    Actor = this,
                    NextPosition = PathFinder.GetEscapePath(this, attackers, battlefield),
                });
            }

            var bestTarget = intels
                             .OrderByDescending(o => o.LastTarget == Id)
                             .ThenByDescending(o => o.IsInRange)
                             .ThenByDescending(o => o.IsStunned)
                             .ThenByDescending(o => o.IsHealingReduced)
                             .ThenBy(o => o.HealthPercent)
                             .ThenByDescending(o => o.LastRoundHealSkillUsed)
                             .ThenBy(o => o.OtherFightersNearby)
                             .FirstOrDefault();

            IFighterStats target = visibleEnemies.First(o => o.Id == bestTarget.Id);

            var skill = SkillFinder.GetSkill(this, target, SkillFinder.ExcludeSkillsOnCooldown(this, Skills, roundTicks), calculationValues);

            if (skill == null)
            {
                return(GetSkillMove(battlefield, target, roundTicks, calculationValues));
            }

            return(new Attack()
            {
                Actor = this,
                Skill = skill,
                Target = target,
            });
        }