Exemplo n.º 1
0
        bool CanRush(AWizard self, ACombatUnit opp)
        {
            var wizard = opp as AWizard;
            var minion = opp as AMinion;

            if (wizard != null)
            {
                if (wizard.IsBesieded)
                {
                    return(true);
                }

                if (wizard.Life <= self.MagicMissileDamage)
                {
                    return(true);
                }
                if (self.Life <= wizard.MagicMissileDamage)
                {
                    return(false);
                }

                if (self.Life >= wizard.Life + 3 * self.MagicMissileDamage)
                {
                    return(true);
                }
            }
            else if (minion != null)
            {
                if (minion.Life <= self.MagicMissileDamage)
                {
                    return(true);
                }
            }
            return(false);
        }
Exemplo n.º 2
0
 public bool CheckProjectileCantDodge(AProjectile proj, ACombatUnit opp)
 {
     return((opp is AWizard ? Utility.Range(-Math.PI / 2, Math.PI / 2, 6) : new[] { 0.0 }).All(changeAngle =>
     {
         var path = proj.Emulate(opp, changeAngle);
         return path.Any(x => x.State == AProjectile.ProjectilePathState.Shot && x.Target.Faction != Faction);
     }));
 }
Exemplo n.º 3
0
        WizardPath GoAgainst(ACombatUnit to)
        {
            TimerStart();
            var ret = _goAround(to, true);

            TimerEndLog("Dijkstra", 1);
            return(ret);
        }
Exemplo n.º 4
0
 private static int _targetImportance(ACombatUnit unit)
 {
     if (unit is AWizard)
     {
         return(3);
     }
     if (unit is ABuilding)
     {
         return(2);
     }
     return(1);
 }
Exemplo n.º 5
0
 public AProjectile(ACombatUnit self, double castAngle, ProjectileType type)
 {
     Type              = type;
     Speed             = Const.ProjectileInfo[(int)type].Speed;
     Radius            = Const.ProjectileInfo[(int)type].Radius;
     X                 = self.X;
     Y                 = self.Y;
     SpeedX            = Math.Cos(self.Angle + castAngle) * Speed;
     SpeedY            = Math.Sin(self.Angle + castAngle) * Speed;
     RemainingDistance = self.CastRange;
     OwnerUnitId       = self.Id;
     Faction           = self.Faction;
     SetupDamage(self);
 }
Exemplo n.º 6
0
        protected ACombatUnit(ACombatUnit unit) : base(unit)
        {
            IsTeammate  = unit.IsTeammate;
            Life        = unit.Life;
            MaxLife     = unit.MaxLife;
            VisionRange = unit.VisionRange;
            CastRange   = unit.CastRange;
            RemainingActionCooldownTicks = unit.RemainingActionCooldownTicks;

            RemainingHastened  = unit.RemainingHastened;
            RemainingEmpowered = unit.RemainingEmpowered;
            RemainingFrozen    = unit.RemainingFrozen;
            RemainingShielded  = unit.RemainingShielded;
            IsBurning          = unit.IsBurning;
        }
Exemplo n.º 7
0
        public ACombatUnit Select(ACombatUnit unit)
        {
            if (_minionsSelectionsCache.ContainsKey(unit.Id))
            {
                return(_minionsSelectionsCache[unit.Id]);
            }

            var res = unit.SelectTarget(_combats);

            if (EnableMinionsCache && unit is AMinion)
            {
                _minionsSelectionsCache[unit.Id] = res;
            }
            return(res);
        }
Exemplo n.º 8
0
        public static double GetFireballDamage(AProjectile proj, ACombatUnit unit) // без учета сколько жизней осталось
        {
            var    dist   = proj.GetDistanceTo(unit) - unit.Radius;
            double damage = 0;

            if (dist <= MyStrategy.Game.FireballExplosionMaxDamageRange)
            {
                damage += proj.Damage;
            }
            else if (dist <= MyStrategy.Game.FireballExplosionMinDamageRange)
            {
                var ratio = 1 - (dist - MyStrategy.Game.FireballExplosionMaxDamageRange) / (MyStrategy.Game.FireballExplosionMinDamageRange - MyStrategy.Game.FireballExplosionMaxDamageRange);
                damage += ratio * (proj.Damage - proj.MinDamage) + proj.MinDamage;
            }
            return(damage);
        }
Exemplo n.º 9
0
 public static ACombatUnit CloneCombat(ACombatUnit combat)
 {
     if (combat is AWizard)
     {
         return(new AWizard(combat as AWizard));
     }
     if (combat is ABuilding)
     {
         return(new ABuilding(combat as ABuilding));
     }
     if (combat is AOrc)
     {
         return(new AOrc(combat as AOrc));
     }
     if (combat is AFetish)
     {
         return(new AFetish(combat as AFetish));
     }
     throw new Exception("unknown combat type");
 }
Exemplo n.º 10
0
        static double GetCombatPriority(AWizard self, ACombatUnit unit)
        {
            // чем меньше - тем важнее стрелять в него первого
            var res = unit.Life;

            if (unit is AWizard)
            {
                res /= 4;
                if ((unit as AWizard).IsBesieded)
                {
                    res /= 4;
                }
                res -= 50;
            }
            var dist = self.GetDistanceTo(unit);

            if (dist <= Game.StaffRange + unit.Radius + 10)
            {
                res -= 60;
                res += Math.Log(dist);
            }
            return(res);
        }
Exemplo n.º 11
0
        public override ACombatUnit SelectTarget(ACombatUnit[] candidates)
        {
            var accessible = candidates
                             .Where(x => x.Faction != Faction.Neutral && x.Faction != Faction && x.IsAlive && GetDistanceTo2(x) <= Geom.Sqr(CastRange))
                             .ToArray();

            ACombatUnit sel = null;

            foreach (var x in accessible)
            {
                if (x.Life > Damage)
                {
                    if (sel == null || x.Life < sel.Life || Utility.Equals(x.Life, sel.Life) && x.Id == MyStrategy.Self.Id)
                    {
                        sel = x;
                    }
                }
            }

            if (sel != null)
            {
                return(sel);
            }

            foreach (var x in accessible)
            {
                if (x.Life <= Damage)
                {
                    if (sel == null || x.Life > sel.Life || Utility.Equals(x.Life, sel.Life) && x.Id == MyStrategy.Self.Id)
                    {
                        sel = x;
                    }
                }
            }

            return(sel);
        }
Exemplo n.º 12
0
        public void SetupDamage(ACombatUnit unit)
        {
            var self = unit as AWizard;

            switch (Type)
            {
            case ProjectileType.Fireball:
                Damage    = self.FireballMaxDamage;
                MinDamage = self.FireballMinDamage;
                break;

            case ProjectileType.MagicMissile:
                Damage = self.MagicMissileDamage;
                break;

            case ProjectileType.FrostBolt:
                Damage = self.FrostBoltDamage;
                break;

            case ProjectileType.Dart:
                Damage = MyStrategy.Game.DartDirectDamage;
                break;
            }
        }
Exemplo n.º 13
0
        MovingInfo _findCastTarget(AWizard self, ProjectileType projectileType)
        {
            var actionType = Utility.GetActionByProjectileType(projectileType);

            var move = new FinalMove(new Move());

            if (self.RemainingActionCooldownTicks > 0 ||
                self.RemainingCooldownTicksByAction[(int)actionType] > 0 ||
                self.Mana < Const.ProjectileInfo[(int)projectileType].ManaCost ||
                !self.IsActionAvailable(actionType)
                )
            {
                return(new MovingInfo(null, int.MaxValue, move));
            }

            var angles = new List <double>();

            foreach (var x in OpponentCombats)
            {
                var distTo = self.GetDistanceTo(x);
                if (distTo > self.CastRange + x.Radius + Const.ProjectileInfo[(int)projectileType].DamageRadius + 3)
                {
                    continue;
                }

                var angleTo = self.GetAngleTo(x);
                if (Math.Abs(angleTo) > Math.PI / 3)
                {
                    continue;
                }

                var deltaAngle = Math.Atan2(x.Radius, distTo);
                angles.AddRange(new[] { angleTo, angleTo + deltaAngle, angleTo - deltaAngle }.Where(a => Math.Abs(a) <= Game.StaffSector / 2));
            }
            if (angles.Count > 0)
            {
                angles.AddRange(Utility.Range(-Game.StaffSector / 2, Game.StaffSector / 2, 16));
            }

            ACombatUnit selTarget = null;
            double
                selMinDist   = 0,
                selMaxDist   = self.CastRange + 20,
                selCastAngle = 0,
                selMaxDamage = 0;

            if (projectileType == ProjectileType.Fireball)
            {
                var maxDamage = 0.0;
                var maxBurned = 0;

                foreach (var angle in angles)
                {
                    var proj = new AProjectile(new AWizard(self), angle, projectileType);
                    var path = EmulateProjectileWithNearest(proj);
                    for (var i = 0; i < path.Count; i++)
                    {
                        var seg = path[i];

                        if (_isFireballGoodSeg(self, seg))
                        {
                            if (seg.OpponentBurned > maxBurned ||
                                seg.OpponentBurned == maxBurned && seg.OpponentDamage > maxDamage
                                //|| seg.OpponentBurned == maxBurned && Utility.Equals(seg.OpponentDamage, maxDamage)
                                //TODO: combare by angle and priority
                                )
                            {
                                maxBurned    = seg.OpponentBurned;
                                maxDamage    = seg.OpponentDamage;
                                selCastAngle = angle;
                                selMinDist   = selMaxDist = seg.StartDistance;
                                selTarget    = seg.Target;
                                selMaxDamage = seg.OpponentDamage;
                            }
                        }
                    }
                }
            }
            else
            {
                double
                    selPriority = int.MaxValue,
                    selAngleTo  = 0;

                foreach (var angle in angles)
                {
                    var proj = new AProjectile(new AWizard(self), angle, projectileType);
                    var path = EmulateProjectileWithNearest(proj);
                    for (var i = 0; i < path.Count; i++)
                    {
                        if (path[i].State == AProjectile.ProjectilePathState.Free)
                        {
                            continue;
                        }

                        // TODO: если можно убить нескольких, убивать того, у кого больше жизней
                        var combat = path[i].Target;
                        if (!combat.IsAssailable)
                        {
                            continue;
                        }

                        var myAngle  = self.Angle + angle;
                        var hisAngle = self.Angle + self.GetAngleTo(combat);
                        var angleTo  = Geom.GetAngleBetween(myAngle, hisAngle);

                        var priority = GetCombatPriority(self, combat);
                        if (combat.IsOpponent &&
                            (priority < selPriority || Utility.Equals(priority, selPriority) && angleTo < selAngleTo) &&
                            self.CheckProjectileCantDodge(proj, Combats.FirstOrDefault(x => x.Id == combat.Id))
                            )
                        {
                            selTarget    = combat;
                            selCastAngle = angle;
                            selAngleTo   = angleTo;
                            selMinDist   = i == 0 ||
                                           path[i - 1].State == AProjectile.ProjectilePathState.Free &&
                                           path[i - 1].Length < 40
                                ? path[i].StartDistance - 1
                                : path[i].StartDistance - 20;
                            selMaxDist = i >= path.Count - 2
                                ? (self.CastRange + 500)
                                : (path[i + 1].EndDistance + path[i].EndDistance) / 2;
                            selPriority  = priority;
                            selMaxDamage = path[i].OpponentDamage;
                        }
                    }
                }
            }
            if (selTarget == null)
            {
                return(new MovingInfo(null, int.MaxValue, move));
            }

            move.Action          = actionType;
            move.MinCastDistance = selMinDist;
            move.MaxCastDistance = selMaxDist;
            move.CastAngle       = selCastAngle;
#if DEBUG
            _lastProjectileTick   = World.TickIndex;
            _lastProjectilePoints = new[]
            {
                self + Point.ByAngle(self.Angle + selCastAngle) * selMinDist,
                self + Point.ByAngle(self.Angle + selCastAngle) * Math.Min(Self.CastRange, selMaxDist),
            };
#endif
            return(new MovingInfo(selTarget, 0, move)
            {
                Damage = selMaxDamage, TargetId = selTarget.Id
            });
        }
Exemplo n.º 14
0
 public static bool IsBase(ACombatUnit unit)
 {
     return(unit is ABuilding && ((ABuilding)unit).IsBase);
 }
Exemplo n.º 15
0
        WizardPath _goAround(ACombatUnit target, bool goAgainst)
        {
            var my              = new AWizard(ASelf);
            var selLane         = Utility.IsBase(target) ? MessagesObserver.GetLane() : RoadsHelper.GetLane(target);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var buildings = new List <ABuilding>();

            if (nearestBuilding.GetDistanceTo(my) > nearestBuilding.VisionRange)
            {
                buildings.Add(nearestBuilding);
            }
            if (target.IsOpponent && target.Id != nearestBuilding.Id && target is ABuilding)
            {
                buildings.Add((ABuilding)target);
            }

            var threshold = Self.CastRange - 200;

            if (ASelf.GetDistanceTo(target) < Self.CastRange || !goAgainst)
            {
                threshold = 0;
            }

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если с неё можно стрелять
                var dist2 = pos.GetDistanceTo2(target);
                if (dist2 < Geom.Sqr(Self.CastRange) && dist2 > Geom.Sqr(threshold))
                {
                    var distToLine = RoadsHelper.Roads.Where(seg => seg.LaneType == selLane).Min(seg => seg.GetDistanceTo(pos));

                    if (distToLine < 200 &&
                        (!goAgainst || BuildingsObserver.MyBase.GetDistanceTo2(pos) < BuildingsObserver.MyBase.GetDistanceTo2(target)) &&
                        TreesObserver.Trees
                        .Where(x => x.GetDistanceTo2(pos) < Geom.Sqr(Self.CastRange))
                        .All(x => !Geom.SegmentCircleIntersects(pos, target, x, x.Radius + Game.MagicMissileRadius))
                        )
                    {
                        return(DijkstraStopStatus.TakeAndStop);
                    }
                }
                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(buildings, selLane)).FirstOrDefault();

            if (path == null && my.GetDistanceTo(target) - my.Radius - target.Radius <= 1)
            {
                path = new WizardPath {
                    my
                }
            }
            ;                                 // из-за эпсилон, если стою близко у цели, то он как бы с ней пересекается, но это не так
            if (path == null || path.Count == 0)
            {
                return(null);
            }

            if (path.Count == 1)
            {
                FinalMove.Turn = my.GetAngleTo(target);
                return(null);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange)) //???
                .ToArray();

            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);

            var nextPoint     = path[1];
            var nextNextPoint = path.Count > 2 ? path[2] : target;

            FinalMove.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < Self.VisionRange * 1.2 ? nextNextPoint : nextPoint);

            var nextTree = path.GetNearestTree();

            CutTreesInPath(nextTree, FinalMove);
#if DEBUG
            Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Blue, 3 });
#endif
            return(path);
        }

        void CutTreesInPath(ATree nextTree, FinalMove move)
        {
            if (nextTree == null)
            {
                return;
            }
            var my = new AWizard(ASelf);

            var angleTo = my.GetAngleTo(nextTree);

            if (my.GetDistanceTo(nextTree) < my.VisionRange && Math.Abs(angleTo) > Game.StaffSector / 2)
            {
                move.MoveTo(null, nextTree);
            }

            if (my.RemainingActionCooldownTicks == 0 && Math.Abs(angleTo) <= Game.StaffSector / 2)
            {
                if (my.GetDistanceTo(nextTree) <= Game.StaffRange + nextTree.Radius && my.RemainingStaffCooldownTicks == 0)
                {
                    move.Action = ActionType.Staff;
                }
                else if (my.GetDistanceTo(nextTree) <= my.CastRange + nextTree.Radius && my.RemainingMagicMissileCooldownTicks == 0)
                {
                    move.Action          = ActionType.MagicMissile;
                    move.CastAngle       = angleTo;
                    move.MinCastDistance = Math.Min(my.CastRange - 1, my.GetDistanceTo(nextTree));
                }
            }
        }

        MovingInfo GoToBonus()
        {
            TimerStart();
            var ret = _goToBonus();

            TimerEndLog("GoToBonus", 1);
            return(ret);
        }

        bool _skipBonusCond(ABonus bonus)
        {
            var oppFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsOpponent && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (oppFirst == null || ASelf.GetDistanceTo(oppFirst) <= oppFirst.CastRange)
            {
                return(true);
            }

            var myFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsTeammate && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (myFirst == null || OpponentWizards.Any(x => x.GetDistanceTo(myFirst) <= myFirst.Radius))
            {
                return(true);
            }

            // TODO
            return(false);
        }

        ABonus SelectBonus(AWizard self)
        {
            var bonus = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo2(self));

            if (bonus.RemainingAppearanceTicks > MagicConst.GoToBonusMaxTicks + MagicConst.BonusTimeReserve)
            {
                return(null);
            }

            if (self.GetDistanceTo(BuildingsObserver.OpponentBase) < BuildingsObserver.OpponentBase.CastRange * 1.4)
            {
                return(null);
            }

            if (Game.IsSkillsEnabled && _skipBonusCond(bonus))
            {
                return(null);
            }

            return(bonus);
        }

        MovingInfo _goToBonus()
        {
            var bonus         = SelectBonus(ASelf);
            var selMovingInfo = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));

            if (bonus == null)
            {
                return(selMovingInfo);
            }

            if (Const.IsFinal)
            {
                var teammates = MyWizards
                                .Where(x => x.Id != ASelf.Id)
                                .Where(x =>
                {
                    var b = SelectBonus(x);
                    return(b != null && b.Id == bonus.Id);
                })
                                .ToArray();
                if (teammates.Any(x => ASelf.GetDistanceTo(bonus) > x.GetDistanceTo(bonus)))
                {
                    return(selMovingInfo);
                }
            }

            var my = new AWizard(ASelf);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если бонус совсем близко
                if (pos.GetDistanceTo2(bonus) < Geom.Sqr(bonus.Radius + Self.Radius + 35))
                {
                    return(DijkstraStopStatus.TakeAndStop);
                }

                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(new [] { nearestBuilding }, MessagesObserver.GetLane())).FirstOrDefault();

            if (path == null)
            {
                GoDirect(bonus, selMovingInfo.Move);
                selMovingInfo.Target = bonus;
                return(selMovingInfo);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange))
                .ToArray();

            path.Add(bonus);
            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);


            var time = (int)(path.GetLength() / my.MaxForwardSpeed);

            if (time < MagicConst.GoToBonusMaxTicks)
            {
                selMovingInfo.Time = time;

                var nextPoint     = path[1];
                var nextNextPoint = path.Count > 2 ? path[2] : nextPoint;
                selMovingInfo.Move = new FinalMove(new Move());
                selMovingInfo.Move.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < my.Radius + 20 ? nextNextPoint : nextPoint);
                selMovingInfo.Target = nextPoint;

                var nextTree = path.GetNearestTree();
                CutTreesInPath(nextTree, selMovingInfo.Move);
            }

            if (selMovingInfo.Time <= bonus.RemainingAppearanceTicks - MagicConst.BonusTimeReserve)
            {
                selMovingInfo.Target = null;
            }
#if DEBUG
            if (selMovingInfo.Target != null)
            {
                Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Red, 3 });
            }
#endif
            return(selMovingInfo);
        }
Exemplo n.º 16
0
        private List <ProjectilePathSegment> _emulate(ACombatUnit[] nearestUnits, double wizardsChangeAngle, TargetsSelector minionsTargetsSelector)
        {
            if (Type != ProjectileType.MagicMissile && Type != ProjectileType.FrostBolt && Type != ProjectileType.Fireball)
            {
                throw new Exception("Unsupported projectile type " + Type);
            }

            // NOTE: nearestUnits уже склонированы
            // NOTE: nearestUnits и они же в minionsTargetsSelector - одни и те же instance

            var list              = new List <ProjectilePathSegment>();
            var projectile        = new AProjectile(this);
            var owner             = nearestUnits.FirstOrDefault(x => x.Id == OwnerUnitId);
            var nearestCandidates = nearestUnits.Where(x => x.Id != OwnerUnitId).ToArray();

            while (projectile.Exists)
            {
                projectile.Move(proj =>
                {
                    if (Type == ProjectileType.Fireball)
                    {
                        double selfDamage = 0;
                        double oppDamage  = 0;
                        var selfBurned    = 0;
                        var oppBurned     = 0;
                        var selfDeads     = 0;
                        var oppDeads      = 0;

                        ACombatUnit importantTarget = null;

                        foreach (var unit in nearestCandidates)
                        {
                            var damage = GetFireballDamage(proj, unit);

                            if (damage > 0)
                            {
                                var deads = 0;
                                if (damage >= unit.Life - Const.Eps)
                                {
                                    // killed
                                    deads++;
                                    damage = unit.Life;
                                }

                                if (unit.Faction == proj.Faction)
                                {
                                    if (unit is AWizard)
                                    {
                                        selfDamage += damage;
                                        selfBurned++;
                                        selfDeads += deads;
                                    }
                                }
                                else if (Utility.HasConflicts(proj, unit))
                                {
                                    oppDamage += damage;
                                    oppBurned++;
                                    oppDeads += deads;
                                    if (importantTarget == null || _targetImportance(unit) > _targetImportance(importantTarget))
                                    {
                                        importantTarget = unit;
                                    }
                                }
                            }
                        }
                        if (owner != null)
                        {
                            var damage = GetFireballDamage(proj, owner);
                            if (damage > 0)
                            {
                                selfBurned++;
                                if (damage >= owner.Life - Const.Eps)
                                {
                                    // killed
                                    selfDamage += owner.Life;
                                    selfDeads++;
                                }
                                else
                                {
                                    selfDamage += damage;
                                }
                            }
                        }
                        list.Add(new ProjectilePathSegment
                        {
                            StartDistance      = list.Count == 0 ? 0 : list.Last().EndDistance,
                            EndDistance        = list.Count == 0 ? 0 : list.Last().EndDistance,
                            OpponentDamage     = oppDamage,
                            SelfDamage         = selfDamage,
                            OpponentDeadsCount = oppDeads,
                            SelfDeadsCount     = selfDeads,
                            State          = (selfDamage + oppDamage < Const.Eps) ? ProjectilePathState.Free : ProjectilePathState.Fireball,
                            OpponentBurned = oppBurned,
                            SelfBurned     = selfBurned,
                            Target         = importantTarget,
                        });
                    }
                    else
                    {
                        var inter = proj.GetFirstIntersection(nearestCandidates);

                        if (inter != null)
                        {
                            if (list.Count == 0 || list.Last().State != ProjectilePathState.Shot)
                            {
                                var opp = inter as ACombatUnit;
                                list.Add(new ProjectilePathSegment
                                {
                                    StartDistance  = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    EndDistance    = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    State          = ProjectilePathState.Shot,
                                    Target         = Utility.CloneCombat(opp),
                                    SelfDamage     = proj.Faction == inter.Faction ? Math.Min(opp.Life, Damage) : 0,
                                    OpponentDamage = Utility.HasConflicts(proj, opp) ? Math.Min(opp.Life, Damage) : 0,
                                });
                            }
                        }
                        else
                        {
                            if (list.Count == 0 || list.Last().State != ProjectilePathState.Free)
                            {
                                list.Add(new ProjectilePathSegment
                                {
                                    StartDistance = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    EndDistance   = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    State         = ProjectilePathState.Free,
                                });
                            }
                        }
                    }
                    list.Last().EndDistance += proj.Speed / proj.MicroTicks;

                    return(true);
                });
                foreach (var unit in nearestCandidates)
                {
                    if (unit is AWizard)
                    {
                        var wizard = unit as AWizard;
                        var dir    = (wizard - this).RotateClockwise(wizardsChangeAngle) + wizard; // вдоль снаряда
                        wizard.MoveTo(dir, null, w =>
                        {
                            var tree = TreesObserver.GetNearestTree(w);
                            return((tree == null || !w.IntersectsWith(tree)) && wizard.GetFirstIntersection(nearestCandidates) == null);
                        });
                    }
                    else if (unit is AMinion)
                    {
                        var target = minionsTargetsSelector.Select(unit);
                        unit.EthalonMove(target);
                    }
                }
            }
            return(list);
        }
Exemplo n.º 17
0
 public List <ProjectilePathSegment> Emulate(ACombatUnit target, double wizardsChangeAngle)
 {
     target = Utility.CloneCombat(target);
     // NOTE: target и он же в minionsTargetsSelector - разные instance. Этим можно пренебречь
     return(_emulate(new [] { target }, wizardsChangeAngle, MyStrategy.MinionsTargetsSelector /*TODO: HACK*/));
 }