public bool ShouldWait() { var attackCalc = (int)(Player.AttackDelay * 1000 * LaneClearWaitTimeMod); return (MinionListAA.Any( minion => HealthPrediction.LaneClearHealthPrediction(minion, attackCalc, FarmDelay) <= Player.GetAutoAttackDamage(minion))); }
private bool ShouldWaitUnderTurret(Obj_AI_Minion noneKillableMinion) { var attackCalc = (int)(Player.AttackDelay * 1000 + (Player.IsMelee ? Player.AttackCastDelay * 1000 : Player.AttackCastDelay * 1000 + 1000 * (Player.AttackRange + 2 * Player.BoundingRadius) / Player.BasicAttack.MissileSpeed)); return (MinionListAA.Any(minion => (noneKillableMinion != null ? noneKillableMinion.NetworkId != minion.NetworkId : true) && HealthPrediction.LaneClearHealthPrediction(minion, attackCalc, FarmDelay) <= Player.GetAutoAttackDamage(minion))); }
public virtual AttackableUnit GetTarget() { AttackableUnit result = null; var mode = ActiveMode; if ((mode == OrbwalkingMode.Mixed || mode == OrbwalkingMode.LaneClear) && !true) { var target = TargetSelector.GetTarget(-1, DamageType.Physical); if (target != null && InAutoAttackRange(target)) { return(target); } } /*Killable Minion*/ if (mode == OrbwalkingMode.LaneClear || mode == OrbwalkingMode.Mixed || mode == OrbwalkingMode.LastHit || mode == OrbwalkingMode.Freeze) { var MinionList = Cache.GetMinions(Player.Position, 0, MinionTeam.NotAlly).OrderBy(minion => HealthPrediction.GetHealthPrediction(minion, 1000)); foreach (var minion in MinionList) { if (minion.Team != GameObjectTeam.Neutral) { if (!ShouldAttackMinion(minion)) { continue; } var t = (int)(Player.AttackCastDelay * 1000) - 100 + Game.Ping / 2 + 1000 * (int)Math.Max(0, Player.Distance(minion) - Player.BoundingRadius) / (int)GetMyProjectileSpeed(); if (mode == OrbwalkingMode.Freeze) { t += 200 + Game.Ping / 2; } var predHealth = HealthPrediction.GetHealthPrediction(minion, t, FarmDelay); var damage = Player.GetAutoAttackDamage(minion, true); var killable = predHealth <= damage; if (mode == OrbwalkingMode.Freeze) { if (minion.Health < 50 || predHealth <= 50) { return(minion); } } else { if (killable && predHealth > 0) { return(minion); } } } else if (minion.Health < 2 && true && minion.CharData.BaseSkinName == "gangplankbarrel" && minion.IsHPBarRendered) { return(minion); } } } //Forced target if (_forcedTarget.IsValidTarget() && InAutoAttackRange(_forcedTarget)) { return(_forcedTarget); } /* turrets / inhibitors / nexus */ if ((mode == OrbwalkingMode.LaneClear || mode == OrbwalkingMode.Mixed) && (!true || !MinionListAA.Any())) { /* turrets */ foreach (var turret in ObjectManager.Get <Obj_AI_Turret>().Where(t => t.IsValidTarget() && InAutoAttackRange(t))) { return(turret); } /* inhibitor */ foreach (var turret in ObjectManager.Get <Obj_BarracksDampener>().Where(t => t.IsValidTarget() && InAutoAttackRange(t))) { return(turret); } /* nexus */ foreach (var nexus in ObjectManager.Get <Obj_HQ>().Where(t => t.IsValidTarget() && InAutoAttackRange(t))) { return(nexus); } } /*Champions*/ if (mode != OrbwalkingMode.LastHit) { var target = TargetSelector.GetTarget(-1, DamageType.Physical); if (target.IsValidTarget() && InAutoAttackRange(target)) { return(target); } } /*Jungle minions*/ if (mode == OrbwalkingMode.LaneClear || mode == OrbwalkingMode.Mixed) { var jminions = Cache.GetMinions(Player.Position, 0, MinionTeam.Neutral); result = false ? jminions.MinOrDefault(mob => mob.MaxHealth) : jminions.MaxOrDefault(mob => mob.MaxHealth); if (result != null) { return(result); } } /* UnderTurret Farming */ if (mode == OrbwalkingMode.LaneClear || mode == OrbwalkingMode.Mixed || mode == OrbwalkingMode.LastHit || mode == OrbwalkingMode.Freeze) { var closestTower = ObjectManager.Get <Obj_AI_Turret>() .MinOrDefault(t => t.IsAlly && !t.IsDead ? Player.Distance(t, true) : float.MaxValue); if (closestTower != null && Player.Distance(closestTower, true) < 1500 * 1500) { Obj_AI_Minion farmUnderTurretMinion = null; Obj_AI_Minion noneKillableMinion = null; // return all the minions underturret in auto attack range var minions = MinionListAA.Where(minion => closestTower.Distance(minion, true) < 900 * 900) .OrderByDescending(minion => minion.CharData.BaseSkinName.Contains("Siege")) .ThenBy(minion => minion.CharData.BaseSkinName.Contains("Super")) .ThenByDescending(minion => minion.MaxHealth) .ThenByDescending(minion => minion.Health); if (minions.Any()) { // get the turret aggro minion var turretMinion = minions.FirstOrDefault( minion => minion is Obj_AI_Minion && HealthPrediction.HasTurretAggro(minion as Obj_AI_Minion)); if (turretMinion != null) { var hpLeftBeforeDie = 0; var hpLeft = 0; var turretAttackCount = 0; var turretStarTick = HealthPrediction.TurretAggroStartTick( turretMinion as Obj_AI_Minion); // from healthprediction (don't blame me :S) var turretLandTick = turretStarTick + (int)(closestTower.AttackCastDelay * 1000) + 1000 * Math.Max( 0, (int) (turretMinion.Distance(closestTower) - closestTower.BoundingRadius)) / (int)(closestTower.BasicAttack.MissileSpeed + 70); // calculate the HP before try to balance it for (float i = turretLandTick + 50; i < turretLandTick + 10 * closestTower.AttackDelay * 1000 + 50; i = i + closestTower.AttackDelay * 1000) { var time = (int)i - Utils.GameTimeTickCount + Game.Ping / 2; var predHP = (int) HealthPrediction.LaneClearHealthPrediction( turretMinion, time > 0 ? time : 0); if (predHP > 0) { hpLeft = predHP; turretAttackCount += 1; continue; } hpLeftBeforeDie = hpLeft; hpLeft = 0; break; } // calculate the hits is needed and possibilty to balance if (hpLeft == 0 && turretAttackCount != 0 && hpLeftBeforeDie != 0) { var damage = (int)Player.GetAutoAttackDamage(turretMinion, true); var hits = hpLeftBeforeDie / damage; var timeBeforeDie = turretLandTick + (turretAttackCount + 1) * (int)(closestTower.AttackDelay * 1000) - Utils.GameTimeTickCount; var timeUntilAttackReady = LastAATick + (int)(Player.AttackDelay * 1000) > Utils.GameTimeTickCount + Game.Ping / 2 + 25 ? LastAATick + (int)(Player.AttackDelay * 1000) - (Utils.GameTimeTickCount + Game.Ping / 2 + 25) : 0; var timeToLandAttack = Player.IsMelee ? Player.AttackCastDelay * 1000 : Player.AttackCastDelay * 1000 + 1000 * Math.Max(0, turretMinion.Distance(Player) - Player.BoundingRadius) / Player.BasicAttack.MissileSpeed; if (hits >= 1 && hits * Player.AttackDelay * 1000 + timeUntilAttackReady + timeToLandAttack < timeBeforeDie) { farmUnderTurretMinion = turretMinion as Obj_AI_Minion; } else if (hits >= 1 && hits * Player.AttackDelay * 1000 + timeUntilAttackReady + timeToLandAttack > timeBeforeDie) { noneKillableMinion = turretMinion as Obj_AI_Minion; } } else if (hpLeft == 0 && turretAttackCount == 0 && hpLeftBeforeDie == 0) { noneKillableMinion = turretMinion as Obj_AI_Minion; } // should wait before attacking a minion. if (ShouldWaitUnderTurret(noneKillableMinion)) { return(null); } if (farmUnderTurretMinion != null) { return(farmUnderTurretMinion); } // balance other minions foreach (var minion in minions.Where( x => x.NetworkId != turretMinion.NetworkId && x is Obj_AI_Minion && !HealthPrediction.HasMinionAggro(x as Obj_AI_Minion))) { var playerDamage = (int)Player.GetAutoAttackDamage(minion); var turretDamage = (int)closestTower.GetAutoAttackDamage(minion, true); var leftHP = (int)minion.Health % turretDamage; if (leftHP > playerDamage) { return(minion); } } // late game var lastminion = minions.LastOrDefault(x => x.NetworkId != turretMinion.NetworkId && x is Obj_AI_Minion && !HealthPrediction.HasMinionAggro(x as Obj_AI_Minion)); if (lastminion != null && minions.Count() >= 2) { if (1f / Player.AttackDelay >= 1f && (int)(turretAttackCount * closestTower.AttackDelay / Player.AttackDelay) * Player.GetAutoAttackDamage(lastminion) > lastminion.Health) { return(lastminion); } if (minions.Count() >= 5 && 1f / Player.AttackDelay >= 1.2) { return(lastminion); } } } else { if (ShouldWaitUnderTurret(noneKillableMinion)) { return(null); } // balance other minions foreach (var minion in minions.Where( x => x is Obj_AI_Minion && !HealthPrediction.HasMinionAggro(x as Obj_AI_Minion)) ) { if (closestTower != null) { var playerDamage = (int)Player.GetAutoAttackDamage(minion); var turretDamage = (int)closestTower.GetAutoAttackDamage(minion, true); var leftHP = (int)minion.Health % turretDamage; if (leftHP > playerDamage) { return(minion); } } } //late game var lastminion = minions .LastOrDefault(x => x is Obj_AI_Minion && !HealthPrediction.HasMinionAggro(x as Obj_AI_Minion)); if (lastminion != null && minions.Count() >= 2) { if (minions.Count() >= 5 && 1f / Player.AttackDelay >= 1.2) { return(lastminion); } } } return(null); } } } /*Lane Clear minions*/ if (mode == OrbwalkingMode.LaneClear) { if (!ShouldWait()) { if (_prevMinion.IsValidTarget() && InAutoAttackRange(_prevMinion)) { var predHealth = HealthPrediction.LaneClearHealthPrediction( _prevMinion, (int)(Player.AttackDelay * 1000 * LaneClearWaitTimeMod), FarmDelay); if (predHealth >= 2 * Player.GetAutoAttackDamage(_prevMinion) || Math.Abs(predHealth - _prevMinion.Health) < float.Epsilon) { return(_prevMinion); } } result = (from minion in MinionListAA.Where( minion => ShouldAttackMinion(minion, false)) let predHealth = HealthPrediction.LaneClearHealthPrediction( minion, (int)(Player.AttackDelay * 1000 * LaneClearWaitTimeMod), FarmDelay) where predHealth >= 2 * Player.GetAutoAttackDamage(minion) || Math.Abs(predHealth - minion.Health) < float.Epsilon select minion).MaxOrDefault( m => m.Health); if (result != null) { _prevMinion = (Obj_AI_Minion)result; } } } return(result); }