public bool _ethalonCanCastMagicMissile(ACircularUnit opp, bool checkCooldown) { var distTo = GetDistanceTo(opp); if (distTo > CastRange + opp.Radius + MyStrategy.Game.MagicMissileRadius) { return(false); } var angleTo = GetAngleTo(opp); var deltaAngle = Math.Atan2(opp.Radius, distTo); var angles = new[] { angleTo, angleTo + deltaAngle, angleTo - deltaAngle }; foreach (var angle in angles) { if (Math.Abs(angle) > MyStrategy.Game.StaffSector / 2) { continue; } var proj = new AProjectile(this, angle, ProjectileType.MagicMissile); if (CheckProjectileCantDodge(proj, opp as ACombatUnit)) { return(true); } } return(false); }
static Cell FindNearestCell(ACircularUnit my) { double ds = Const.MapSize / GridSize; var I = (int)(my.X / ds + Const.Eps); var J = (int)(my.Y / ds + Const.Eps); int seldI = int.MaxValue, seldJ = int.MaxValue; double minDist = int.MaxValue; var obstacles = _obstacles .Concat(BuildingsObserver.Buildings) .Concat(TreesObserver.Trees) .ToArray(); for (var di = 0; di < 2; di++) { for (var dj = 0; dj < 2; dj++) { var dst = WizardPath.GetSegmentWeight(_points[I + di, J + dj], my, true); if (dst < minDist && obstacles.All(ob => !Geom.SegmentCircleIntersects(my, _points[I + di, J + dj], ob, ob.Radius + my.Radius + MagicConst.RadiusAdditionalEpsilon)) ) { minDist = dst; seldI = di; seldJ = dj; } } } if (seldI == int.MaxValue) { return(null); } return(new Cell(I + seldI, J + seldJ)); }
public override void EthalonMove(ACircularUnit target) { var isFrozen = RemainingFrozen > 0; SkipTick(); if (isFrozen) { return; } if (target == null) { X += Math.Cos(Angle) * MyStrategy.Game.MinionSpeed; Y += Math.Sin(Angle) * MyStrategy.Game.MinionSpeed; } else { var angleTo = GetAngleTo(target); if (GetDistanceTo2(target) > Geom.Sqr(this is AOrc ? MyStrategy.Game.OrcWoodcutterAttackRange + target.Radius : MyStrategy.Game.FetishBlowdartAttackRange + target.Radius + MyStrategy.Game.DartRadius)) { X += Math.Cos(Angle + angleTo) * MyStrategy.Game.MinionSpeed; Y += Math.Sin(Angle + angleTo) * MyStrategy.Game.MinionSpeed; } Angle += Utility.EnsureInterval(angleTo, MyStrategy.Game.MinionMaxTurnAngle); } }
public override bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true) { if (CanStaffAttack(target, checkCooldown)) { return(true); } return(EthalonCanCastMagicMissile(target, checkCooldown)); }
public double GetDistanceToCircle(ACircularUnit circle) { var distToCenter = GetDistanceTo(circle); if (distToCenter <= circle.Radius) { return(0); } return(distToCenter - circle.Radius); }
public bool CanStaffAttack(ACircularUnit unit, bool checkCooldown = true) { if (!CanUseStaff(checkCooldown)) { return(false); } if (GetDistanceTo2(unit) > Geom.Sqr(MyStrategy.Game.StaffRange + unit.Radius)) { return(false); } if (Math.Abs(GetAngleTo(unit)) > MyStrategy.Game.StaffSector / 2) { return(false); } return(true); }
public override bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true) { if (RemainingFrozen > 0) { return(false); } if (checkCooldown && RemainingActionCooldownTicks > 0) { return(false); } var angleTo = GetAngleTo(target); if (Math.Abs(angleTo) > MyStrategy.Game.OrcWoodcutterAttackSector / 2) { return(false); } return(GetDistanceTo2(target) <= Geom.Sqr(MyStrategy.Game.OrcWoodcutterAttackRange + target.Radius)); }
public bool EthalonCanCastMagicMissile(ACircularUnit opp, bool checkCooldown = true, bool checkAngle = true) { if (!CanUseMagicMissile(checkCooldown)) { return(false); } var tmp = Angle; if (!checkAngle) { Angle += GetAngleTo(opp); // поворачиваем, чтобы угол до цели был 0 } var ret = _ethalonCanCastMagicMissile(opp, checkCooldown); if (!checkAngle) { Angle = tmp; } return(ret); }
public override void EthalonMove(ACircularUnit target) { MoveTo(target, target, w => !w.IntersectsWith(target)); }
public override bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true) { return((!checkCooldown || RemainingActionCooldownTicks == 0) && GetDistanceTo2(target) <= Geom.Sqr(CastRange)); }
public override void EthalonMove(ACircularUnit target) { SkipTick(); }
MovingInfo _findStaffTarget(AWizard self) { var potentialColliders = Combats .Where(x => x.Id != self.Id && self.GetDistanceTo2(x) < Geom.Sqr(Game.StaffRange * 6)) .ToArray(); int minTicks = int.MaxValue; var move = new FinalMove(new Move()); var attacked = self.GetStaffAttacked(potentialColliders).Cast <ACombatUnit>().ToArray(); ACircularUnit selTarget = attacked.FirstOrDefault(x => x.IsOpponent); if (selTarget != null) // если уже можно бить { move.Action = ActionType.Staff; return(new MovingInfo(selTarget, 0, move)); } if (self.MmSkillLevel == 5) { // т.к. стрелять можно без задержки // возможно, нужно сделать исключение, если прокачан посох return(new MovingInfo(null, int.MaxValue, move)); } Point selMoveTo = null; foreach (var opp in OpponentCombats) { var dist = self.GetDistanceTo(opp); if (dist > Game.StaffRange * 5 || !opp.IsAssailable) { continue; } var range = opp.Radius + Game.StaffRange; foreach (var delta in new[] { -range, -range / 2, 0, range / 2, range }) { var angle = Math.Atan2(delta, dist); var moveTo = self + (opp - self).Normalized().RotateClockwise(angle) * self.VisionRange; var nearstCombats = Combats .Where(x => x.GetDistanceTo(self) <= Math.Max(x.VisionRange, self.VisionRange) * 1.2) .Select(Utility.CloneCombat) .ToArray(); var targetsSelector = new TargetsSelector(nearstCombats) { EnableMinionsCache = true }; var nearstOpponents = nearstCombats.Where(x => x.IsOpponent).ToArray(); var my = nearstCombats.FirstOrDefault(x => x.Id == self.Id) as AWizard; var his = nearstCombats.FirstOrDefault(x => x.Id == opp.Id); var allowRush = opp is AFetish || opp is AWizard; var canHitNow = opp.EthalonCanHit(self, checkCooldown: !allowRush); var ticks = 0; var ok = true; var buildingsHit = false; while (ticks < (allowRush ? 65 : 35) && my.GetDistanceTo2(his) > Geom.Sqr(Game.StaffRange + his.Radius)) { foreach (var x in nearstOpponents) // свои как-бы стоят на месте { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); x.EthalonMove(tar ?? my); } if (!my.MoveTo(moveTo, his, w => !CheckIntersectionsAndTress(w, potentialColliders))) { ok = false; break; } ticks++; } if (ok && !(opp is AOrc)) { while (Math.Abs(my.GetAngleTo(his)) > Game.StaffSector / 2) { my.MoveTo(null, his); foreach (var x in nearstOpponents) { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); x.EthalonMove(tar ?? my); } ticks++; } } Func <ACombatUnit, bool> check = x => { if ((opp is AWizard) && (opp as AWizard).IsBesieded && !(x is ABuilding)) { return(true); } if (canHitNow && x.Id == opp.Id) // он и так доставал { return(true); } if (!x.EthalonCanHit(my) && (!(x is ABuilding) || !buildingsHit)) { return(true); } if (his.Id == x.Id && my.StaffDamage >= his.Life) { return(true); } var target = targetsSelector.Select(x); if (target != null && target.Id != my.Id) { return(true); } return(false); }; if (opp is AWizard) { ticks -= 5; if ((opp as AWizard).IsBesieded) { ticks -= 10; } } if (ok && ticks < minTicks) { if (my.CanStaffAttack(his)) { if (nearstOpponents.All(check)) { // успею-ли я вернуться обратно while (my.GetDistanceTo(self) > my.MaxForwardSpeed)//TODO:HACK { my.MoveTo(self, null); foreach (var x in nearstOpponents) { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); if (tar != null) { x.EthalonMove(tar); } else { x.SkipTick(); } } } if (nearstOpponents.All(check)) { selTarget = opp; selMoveTo = moveTo; minTicks = ticks; } } } } } } if (selTarget != null) { bool angleOk = Math.Abs(self.GetAngleTo(selTarget)) <= Game.StaffSector / 2, distOk = self.GetDistanceTo2(selTarget) <= Geom.Sqr(Game.StaffRange + selTarget.Radius); if (!distOk) { move.MoveTo(selMoveTo, selTarget); } else if (!angleOk) { move.MoveTo(null, selTarget); } } return(new MovingInfo(selTarget, Math.Max(0, minTicks), move)); }
public virtual bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true) { throw new NotImplementedException(); }
public virtual void EthalonMove(ACircularUnit target) { throw new NotImplementedException(); }
public virtual bool IntersectsWith(ACircularUnit unit) { // если касаются, то false return(GetDistanceTo2(unit) < Geom.Sqr(Radius + unit.Radius)); }
public ACircularUnit(ACircularUnit unit) : base(unit) { Radius = unit.Radius; }