Exemple #1
0
        void _rushTo(AWizard self, AWizard opp)
        {
            // TODO: check angle

            if (self.CanUseFrostBolt() &&
                self.GetDistanceTo(opp) <= Game.WizardCastRange + opp.Radius)
            {
                opp.ApplyMagicalDamage(self.FrostBoltDamage);
                opp.RemainingFrozen = Game.FrozenDurationTicks;
                self.RemainingFrostBoltCooldownTicks = Game.FrostBoltCooldownTicks;
                self.RemainingActionCooldownTicks    = Game.WizardActionCooldownTicks;
            }

            if (self.CanUseStaff() &&
                self.GetDistanceTo(opp) <= Game.StaffRange + opp.Radius)
            {
                opp.ApplyDamage(self.StaffDamage);
                self.RemainingStaffCooldownTicks  = Game.StaffCooldownTicks;
                self.RemainingActionCooldownTicks = Game.WizardActionCooldownTicks;
            }

            if (self.CanUseMagicMissile() &&
                self.GetDistanceTo(opp) <= Game.WizardCastRange + opp.Radius)
            {
                opp.ApplyMagicalDamage(self.MagicMissileDamage);
                self.RemainingMagicMissileCooldownTicks = self.MmSkillLevel == 5 ? 0 : Game.MagicMissileCooldownTicks;
                self.RemainingActionCooldownTicks       = Game.WizardActionCooldownTicks;
            }

            if (self.GetDistanceTo(opp) > Game.StaffRange + opp.Radius)
            {
                self.MoveTo(opp, opp);
            }
            self.SkipTick();
        }
Exemple #2
0
        bool TryPreDodgeProjectile()
        {
            const int preTicks = 18;
            var       opp      = OpponentWizards
                                 .OrderBy(x => x.GetDistanceTo2(ASelf))
                                 .FirstOrDefault(x =>
                                                 Math.Min(x.RemainingActionCooldownTicks, x.RemainingMagicMissileCooldownTicks) <= preTicks &&
                                                 x.GetDistanceTo(ASelf) <= x.CastRange + ASelf.Radius + Game.MagicMissileRadius + 7 &&
                                                 Math.Abs(x.GetAngleTo(ASelf)) <= Game.StaffSector /* /2*/
                                                 );

            if (opp == null)
            {
                return(false);
            }

            if (Math.Abs(ASelf.GetAngleTo(opp)) < Math.PI / 2 && ASelf.GetDistanceTo(opp) > 500)
            {
                var    obstacles     = Combats.Where(x => x.Id != Self.Id && x.GetDistanceTo(ASelf) < 300).ToArray();
                var    selSign       = 0;
                double selPriority   = int.MaxValue;
                var    requiredAngle = ASelf.GetDistanceTo(opp) <= opp.CastRange + ASelf.Radius
                    ? Math.PI - 2 * ASelf.MaxTurnAngle - 0.001
                    : Math.PI / 2;

                for (var sign = -1; sign <= 1; sign += 2)
                {
                    var my       = new AWizard(ASelf);
                    var priority = 0.0;
                    while (Math.Abs(my.GetAngleTo(opp)) < requiredAngle)
                    {
                        my.Angle += sign * my.MaxTurnAngle;
                        priority += 0.1;
                    }
                    for (var i = 0; i < 15; i++)
                    {
                        if (!my.MoveTo(my + Point.ByAngle(my.Angle), null, w => !CheckIntersectionsAndTress(w, obstacles)))
                        {
                            break;
                        }
                        priority--;
                    }
                    if (priority < selPriority)
                    {
                        selPriority = priority;
                        selSign     = sign;
                    }
                }

                FinalMove.Turn = selSign * 10;
                return(true);
            }
            return(false);
        }
Exemple #3
0
        MovingInfo FindTreeTarget(AWizard self)
        {
            var   res       = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));
            var   trees     = TreesObserver.Trees.Where(t => self.GetDistanceTo(t) <= Game.StaffRange + t.Radius).ToArray();
            var   minTicks  = int.MaxValue;
            ATree selTarget = null;

            foreach (var tree in trees)
            {
                var my    = new AWizard(self);
                var ticks = 0;
                while (Math.Abs(my.GetAngleTo(tree)) > Game.StaffSector / 2)
                {
                    my.MoveTo(null, tree);
                    ticks++;
                }
                if (ticks < minTicks && my.CanStaffAttack(tree))
                {
                    minTicks  = ticks;
                    selTarget = tree;
                }
            }

            if (selTarget == null)
            {
                return(res);
            }

            res.Time     = minTicks;
            res.Target   = selTarget;
            res.TargetId = selTarget.Id;
            if (minTicks == 0)
            {
                res.Move.Action = ActionType.Staff;
            }
            else
            {
                res.Move.MoveTo(null, selTarget);
            }

            return(res);
        }
Exemple #4
0
        MovingInfo _findCastTarget2(AWizard self, Point moveTo, ProjectileType projectileType)
        {
            var move = new FinalMove(new Move());

            if (projectileType == ProjectileType.MagicMissile)
            {
                AUnit  mmSelTarget      = null;
                Point  mmSelFirstMoveTo = null;
                var    mmMinTicks       = int.MaxValue;
                double mmMinPriority    = int.MaxValue;

                foreach (var opp in OpponentCombats)
                {
                    if (self.GetDistanceTo2(opp) > Geom.Sqr(self.CastRange + opp.Radius + 40) || !opp.IsAssailable)
                    {
                        continue;
                    }

                    var nearest = Combats
                                  .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(Math.Max(x.VisionRange, self.VisionRange) * 1.3))
                                  .Select(Utility.CloneCombat)
                                  .ToArray();

                    var targetsSelector = new TargetsSelector(nearest)
                    {
                        EnableMinionsCache = true
                    };

                    var nearstOpponents = nearest
                                          .Where(x => x.IsOpponent)
                                          .ToArray();

                    var canHitNow = opp.EthalonCanHit(self, checkCooldown: !(opp is AWizard));

                    var ticks = 0;
                    var my    = nearest.FirstOrDefault(x => x.Id == self.Id) as AWizard;
                    var his   = nearest.FirstOrDefault(x => x.Id == opp.Id);
                    if (my == null || his == null)
                    {
                        continue;
                    }

                    Point firstMoveTo  = null;
                    var   buildingsHit = false;
                    while (!my.EthalonCanCastMagicMissile(his, checkCooldown: false))
                    {
                        if (ticks > 40)
                        {
                            break;
                        }

                        var m = moveTo;
                        var stopIfCannotMove = true;
                        if (m == null && my.EthalonCanCastMagicMissile(his, checkCooldown: false, checkAngle: false))
                        {
                            stopIfCannotMove = false;
                            m = my + (my - his);
                            var tmp = new AWizard(my);
                            tmp.MoveTo(m, his, w => !CheckIntersectionsAndTress(w, nearest));

                            if (EstimateDanger(my, false) <= EstimateDanger(tmp, false))
                            {
                                m = null;
                            }
                        }
                        if (m == null)
                        {
                            m = his;
                        }

                        if (ticks == 0)
                        {
                            firstMoveTo = m;
                        }

                        if (!my.MoveTo(m, his, w => !CheckIntersectionsAndTress(w, nearest)) && Utility.PointsEqual(m, his) && stopIfCannotMove)
                        {
                            break;
                        }

                        foreach (var x in nearest)
                        {
                            if (x.Id == my.Id)
                            {
                                continue;
                            }
                            var tar = targetsSelector.Select(x);
                            buildingsHit = buildingsHit ||
                                           (x.IsOpponent && x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my));

                            if (x.IsOpponent)
                            {
                                x.EthalonMove(tar ?? my);
                            }
                            else if (tar != null)
                            {
                                x.EthalonMove(tar);
                            }
                            else
                            {
                                x.SkipTick();
                            }
                        }
                        ticks++;
                    }

                    if (his is AWizard && (his as AWizard).IsBesieded)
                    {
                        ticks -= 15; // чтобы дать больше приоритета визарду
                    }
                    var priority = GetCombatPriority(self, his);
                    if (ticks < mmMinTicks || ticks == mmMinTicks && priority < mmMinPriority)
                    {
                        if (my.EthalonCanCastMagicMissile(his))
                        {
                            if (nearstOpponents.All(x =>
                            {
                                if (canHitNow && x.Id == opp.Id) // он и так доставал
                                {
                                    return(true);
                                }

                                if (!x.EthalonCanHit(my) && (!(x is ABuilding) || !buildingsHit))
                                {
                                    return(true);
                                }

                                if (his.Id == x.Id && CanRush(my, x))
                                {
                                    return(true);
                                }

                                var target = targetsSelector.Select(x);
                                if (target != null && target.Id != my.Id)
                                {
                                    return(true);
                                }

                                return(false);
                            })
                                )
                            {
                                mmMinTicks       = ticks;
                                mmMinPriority    = priority;
                                mmSelTarget      = opp;
                                mmSelFirstMoveTo = firstMoveTo;
                            }
                        }
                    }
                }


                if (mmSelTarget != null)
                {
                    mmMinTicks = Math.Max(0, mmMinTicks);
                    move.MoveTo(moveTo ?? mmSelFirstMoveTo, mmSelTarget);
                    return(new MovingInfo(mmSelTarget, mmMinTicks, move)
                    {
                        TargetId = mmSelTarget.Id
                    });
                }
            }


            const int walkLimit = 9;

            if (projectileType == ProjectileType.Fireball && self.FireballSkillLevel == 5 && Math.Max(self.RemainingActionCooldownTicks, self.RemainingFireballCooldownTicks) <= walkLimit)
            {
                var   fbMaxDamage = 0.0;
                Point fbSelTarget = null;
                var   fbMinTicks  = int.MaxValue;

                foreach (var ang in Utility.Range(-Game.StaffSector, Game.StaffSector, 10))
                {
                    var nearest = Combats
                                  .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(Math.Max(x.VisionRange, self.VisionRange) * 1.3))
                                  .Select(Utility.CloneCombat)
                                  .ToArray();

                    var targetsSelector = new TargetsSelector(nearest)
                    {
                        EnableMinionsCache = true
                    };

                    var ticks = 0;
                    var my    = nearest.FirstOrDefault(x => x.Id == self.Id) as AWizard;
                    var dir   = my + Point.ByAngle(my.Angle + ang) * 1000;

                    while (ticks <= walkLimit)
                    {
                        if (my.CanUseFireball())
                        {
                            var proj = new AProjectile(my, 0, ProjectileType.Fireball);
                            var path = proj.Emulate(nearest, 0.0);

                            var damage =
                                path.Where(x => _isFireballGoodSeg(my, x))
                                .Select(x => x.OpponentDamage)
                                .DefaultIfEmpty(0)
                                .Max();
                            if (damage > fbMaxDamage)
                            {
                                fbMaxDamage = damage;
                                fbSelTarget = dir;
                                fbMinTicks  = ticks;
                            }
                        }

                        foreach (var x in nearest)
                        {
                            if (x.Id == my.Id)
                            {
                                continue;
                            }

                            if (x is AMinion)
                            {
                                x.EthalonMove(targetsSelector.Select(x));
                            }
                            else
                            {
                                x.SkipTick();
                            }
                        }

                        if (!my.MoveTo(dir, dir, w => !CheckIntersectionsAndTress(w, nearest)))
                        {
                            break;
                        }

                        if (nearest.Any(x => x.IsOpponent && x is ABuilding && x.EthalonCanHit(my) && targetsSelector.Select(x) == my))
                        {
                            break;
                        }
                        ticks++;
                    }
                }


                if (fbSelTarget != null)
                {
                    move.MoveTo(fbSelTarget, fbSelTarget);
                    return(new MovingInfo(fbSelTarget, fbMinTicks, move)
                    {
                        Damage = fbMaxDamage
                    });
                }
            }

            return(new MovingInfo(null, int.MaxValue, move));
        }
Exemple #5
0
        MovingInfo FindBonusTarget(AWizard self)
        {
            var   minTime   = int.MaxValue;
            var   selGo     = 0;
            Point selMoveTo = null;

            foreach (var _bonus in BonusesObserver.Bonuses)
            {
                if (_bonus.GetDistanceTo(self) - self.Radius - _bonus.Radius > Game.StaffRange * 3)
                {
                    continue;
                }
                if (_bonus.RemainingAppearanceTicks > 60)
                {
                    continue;
                }

                var nearest = Combats
                              .Where(x => x.Id != self.Id && self.GetDistanceTo2(x) < Geom.Sqr(self.VisionRange))
                              .ToArray();

                foreach (var angle in Utility.Range(self.Angle, Math.PI * 2 + self.Angle, 24, false))
                {
                    var bonus  = new ABonus(_bonus);
                    var my     = new AWizard(self);
                    var moveTo = my + Point.ByAngle(angle) * self.VisionRange;
                    int time   = 0;
                    int go     = 0;
                    while (my.GetDistanceTo(bonus) > my.Radius + bonus.Radius && time < 60)
                    {
                        if (!my.MoveTo(moveTo, null, w => !CheckIntersectionsAndTress(w, nearest)))
                        {
                            break;
                        }
                        var wait = !bonus.Exists;
                        bonus.SkipTick();
                        time++;
                        if (my.GetDistanceTo(bonus) <= my.Radius + bonus.Radius)
                        {
                            while (!bonus.Exists)
                            {
                                bonus.SkipTick();
                                time++;
                            }
                            if (wait)
                            {
                                time++;
                            }

                            if (time < minTime)
                            {
                                minTime   = time;
                                selMoveTo = moveTo;
                                selGo     = go;
                            }
                            break;
                        }
                        go++;
                    }
                }
            }
            var moving = new MovingInfo(selMoveTo, minTime, new FinalMove(new Move()));

            if (selMoveTo != null)
            {
                if (minTime == 1 || selGo > 0)
                {
                    moving.Move.MoveTo(selMoveTo, null);
                }
                else
                {
                    moving.Target = self;
                }
            }
            return(moving);
        }
Exemple #6
0
        MovingInfo FindUltimateTarget(AWizard self)
        {
            var ret = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));

            const int threshold = 29;
            var       minTicks  = int.MaxValue;
            AWizard   selTarget = null;
            var       selAction = ActionType.None;

            foreach (var action in new[] { ActionType.Haste, ActionType.Shield })
            {
                if (action == ActionType.Haste && self.HasteSkillLevel < 5 ||
                    action == ActionType.Shield && self.ShieldSkillLevel < 5
                    )
                {
                    continue;
                }

                var teammates = MyWizards
                                .Where(x => x.Id != self.Id &&
                                       self.GetDistanceTo(x) <= self.CastRange &&
                                       x.RemainingStatusByAction(action) <= threshold
                                       ).
                                ToArray();

                foreach (var teammate in teammates)
                {
                    var ticks = 0;
                    var my    = new AWizard(self);
                    while (Math.Abs(my.GetAngleTo(teammate)) > Game.StaffSector / 2)
                    {
                        ticks++;
                        my.MoveTo(null, teammate);
                    }
                    if (ticks < minTicks && my.CanCastUltimate(action, teammate))
                    {
                        minTicks  = ticks;
                        selTarget = teammate;
                        selAction = action;
                    }
                }

                if (selTarget == null &&
                    teammates.Length == 0 &&
                    self.RemainingStatusByAction(action) <= threshold &&
                    self.CanUseUltimate(action)
                    )
                {
                    minTicks  = 100;
                    selTarget = self;
                    selAction = action;
                }
            }

            if (selTarget == null)
            {
                return(ret);
            }

            ret.Target   = selTarget;
            ret.TargetId = selTarget.Id;
            ret.Time     = minTicks;

            if (self.CanCastUltimate(selAction, selTarget))
            {
                ret.Move.Action         = selAction;
                ret.Move.StatusTargetId = selTarget.Id;
            }
            else
            {
                ret.Move.MoveTo(null, selTarget);
            }

            return(ret);
        }
Exemple #7
0
        bool _tryDodgeProjectile()
        {
            var   obstacles = Combats.Where(x => x.Id != Self.Id && x.GetDistanceTo(ASelf) < 300).ToArray();
            var   minTicks  = int.MaxValue;
            var   minDamage = 1000.0;
            Point selMoveTo = null;
            Point selTurnTo = null;

            foreach (var doTurn in new[] { false, true })
            {
                foreach (var angle in Utility.Range(0, Math.PI * 2, 40, false))
                {
                    if (minTicks == 0 && minDamage < Const.Eps) // ничего не грозит
                    {
                        break;
                    }

                    var ticks    = 0;
                    var my       = new AWizard(ASelf);
                    var bonus    = new ABonus(BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo(Self)));
                    var moveTo   = my + Point.ByAngle(angle) * 1000;
                    var turnTo   = doTurn ? moveTo : null;
                    var myStates = new List <AWizard> {
                        new AWizard(my)
                    };

                    while (ticks < ProjectilesCheckTicks)
                    {
                        var totalDamage = _getProjectilesDamage(myStates);

                        if (Utility.Less(totalDamage, minDamage) ||
                            Utility.Equals(totalDamage, minDamage) && ticks < minTicks)
                        {
                            minTicks  = ticks;
                            minDamage = totalDamage;
                            selMoveTo = moveTo;
                            selTurnTo = turnTo;
                        }

                        bonus.SkipTick();
                        my.MoveTo(moveTo, turnTo, w =>
                        {
                            if (CheckIntersectionsAndTress(w, obstacles))
                            {
                                return(false);
                            }
                            if (bonus.RemainingAppearanceTicks < 15 && bonus.IntersectsWith(w))
                            {
                                return(false);
                            }
                            return(true);
                        });
                        myStates.Add(new AWizard(my));

                        ticks++;
                    }
                }
            }
            if (minTicks == 0 || minTicks == int.MaxValue) // нет необходимости уворачиваться
            {
                return(false);
            }

            if (selTurnTo != null || Math.Abs(ASelf.GetAngleTo(selMoveTo)) < Math.PI / 2)
            {
                FinalMove.Turn = 0;
            }
            FinalMove.MoveTo(selMoveTo, selTurnTo);
            return(true);
        }