/// <summary> /// The end radius. /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <returns> /// The <see cref="float" />. /// </returns> public static float EndRadius(this Ability ability) { var data = ability.CommonProperties(); if (data == null) { return ability.GetRadius(); } var radius = ability.GetAbilityData(data.EndWidth); return radius > 0 ? radius : ability.GetRadius(); }
/// <summary> /// The travel distance. /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <returns> /// The <see cref="float" />. /// </returns> public static float TravelDistance(this Ability ability) { var data = ability.CommonProperties(); if (data == null) { return ability.GetCastRange(); } var distance = ability.GetAbilityData(data.Distance); return distance > 0 ? distance : ability.GetCastRange(); }
/// <summary> /// Uses prediction to cast given skill shot ability /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="sourcePosition"> /// The source Position. /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <param name="soulRing"> /// The soul Ring. /// </param> /// <param name="otherTargets"> /// Targets which are supposed to be hit by AOE Skill Shot /// </param> /// <returns> /// returns true in case of successful cast /// </returns> public static bool CastSkillShot( this Ability ability, Unit target, Vector3 sourcePosition, string abilityName = null, Ability soulRing = null, List<Unit> otherTargets = null) { if (ability == null || !ability.IsValid) { return false; } if (target == null || !target.IsValid) { return false; } if (!Utils.SleepCheck("CastSkillshot" + ability.Handle)) { return false; } var name = abilityName ?? ability.StoredName(); var owner = ability.Owner as Unit; var position = sourcePosition; var delay = ability.GetHitDelay(target, name); var data = ability.CommonProperties(); // delay += data.AdditionalDelay; if (target.IsInvul() && !Utils.ChainStun(target, delay, null, false)) { return false; } var xyz = ability.GetPrediction(target, abilityName: name); if (otherTargets != null) { var avPosX = otherTargets.Average(x => ability.GetPrediction(x, abilityName: name).X); var avPosY = otherTargets.Average(x => ability.GetPrediction(x, abilityName: name).Y); xyz = (xyz + new Vector3(avPosX, avPosY, 0)) / 2; } var radius = ability.GetRadius(name); var range = ability.TravelDistance(); if (data.AllyBlock) { if ( Creeps.All.Any( x => x.IsValid && x.IsAlive && x.Team == owner.Team && x.Distance2D(xyz) <= range && x.Distance2D(owner) < owner.Distance2D(target) && x.Position.ToVector2().DistanceToLineSegment(sourcePosition.ToVector2(), xyz.ToVector2()) <= radius + x.HullRadius)) { return false; } if ( Heroes.GetByTeam(owner.Team) .Any( hero => hero.IsAlive && !hero.Equals(owner) && !hero.Equals(target) && hero.Distance2D(xyz) <= range && hero.Distance2D(owner) < owner.Distance2D(target) && hero.Position.ToVector2() .DistanceToLineSegment(sourcePosition.ToVector2(), xyz.ToVector2()) <= radius + hero.HullRadius)) { return false; } } if (data.EnemyBlock) { if ( Creeps.All.Any( x => x.IsValid && x.IsAlive && x.Team != owner.Team && x.Distance2D(xyz) <= range && x.Distance2D(owner) < owner.Distance2D(target) && x.Position.ToVector2().DistanceToLineSegment(sourcePosition.ToVector2(), xyz.ToVector2()) <= radius + x.HullRadius)) { return false; } if ( Heroes.GetByTeam(owner.GetEnemyTeam()) .Any( hero => hero.IsAlive && !hero.Equals(target) && hero.Distance2D(xyz) <= range && hero.Distance2D(owner) < owner.Distance2D(target) && hero.Position.ToVector2() .DistanceToLineSegment(sourcePosition.ToVector2(), xyz.ToVector2()) <= radius + hero.HullRadius)) { return false; } } var speed = ability.GetProjectileSpeed(name); var distanceXyz = xyz.Distance2D(position); var lion = name == "lion_impale" ? ability.GetAbilityData("length_buffer") : 0; if (!(distanceXyz <= range + radius + lion + target.HullRadius)) { return false; } if (distanceXyz > range) { xyz = xyz - position; xyz /= xyz.Length(); xyz *= range; xyz += position; } // Console.WriteLine(ability.GetCastRange() + " " + radius); if (name.StartsWith("nevermore_shadowraze")) { xyz = Prediction.SkillShotXYZ( owner, target, (float)((delay + (float)owner.GetTurnTime(xyz)) * 1000), speed, radius); // Console.WriteLine(distanceXyz + " " + range + " " + radius); if (distanceXyz < range + radius && distanceXyz > range - radius) { if (owner.GetTurnTime(xyz) > 0.01) { owner.Move((owner.Position - xyz) * 25 / distanceXyz + xyz); owner.Stop(); } else { ability.UseAbility(); } return true; } return false; } if (name == "invoker_ice_wall" && distanceXyz - 50 > 200 && distanceXyz - 50 < 610) { var mepred = (position - target.Position) * 50 / position.Distance2D(target) + target.Position; var v1 = xyz.X - mepred.X; var v2 = xyz.Y - mepred.Y; var a = Math.Acos(175 / xyz.Distance(mepred)); var x1 = v1 * Math.Cos(a) - v2 * Math.Sin(a); var y1 = v2 * Math.Cos(a) + v1 * Math.Sin(a); var b = Math.Sqrt(x1 * x1 + y1 * y1); var k1 = x1 * 50 / b; var k2 = y1 * 50 / b; var vec1 = new Vector3((float)(k1 + mepred.X), (float)(k2 + mepred.Y), mepred.Z); if (vec1.Distance2D(mepred) > 0) { owner.Move(mepred); owner.Move(vec1, true); ability.UseAbility(true); return true; } return false; } if (ability.ManaCost > 0 && soulRing.CanBeCasted()) { soulRing.UseAbility(); } ability.UseAbility(xyz); return true; }
/// <summary> /// The is slow. /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <returns> /// The <see cref="bool" />. /// </returns> public static bool IsSlow(this Ability ability) { var data = ability.CommonProperties(); return data != null && data.IsSlow; }
/// <summary> /// The pierces magic immunity. /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <returns> /// The <see cref="bool" />. /// </returns> public static bool PiercesMagicImmunity(this Ability ability) { var data = ability.CommonProperties(); return data != null && data.MagicImmunityPierce; }
/// <summary> /// The is manaburn. /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <returns> /// The <see cref="bool" />. /// </returns> public static bool IsManaburn(this Ability ability) { var data = ability.CommonProperties(); return data != null && data.ManaBurn; }
/// <summary> /// Checks if given ability can be used /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="target"> /// The target. /// </param> /// <returns> /// returns true in case ability can be used /// </returns> public static bool CanBeCasted(this Ability ability, Unit target) { if (ability == null || !ability.IsValid) { return false; } if (target == null || !target.IsValid) { return false; } if (!target.IsValidTarget()) { return false; } var canBeCasted = ability.CanBeCasted(); if (!target.IsMagicImmune()) { return canBeCasted; } var data = ability.CommonProperties(); return data == null ? canBeCasted : data.MagicImmunityPierce; }
/// <summary> /// Returns impact radius of given ability /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <returns> /// The <see cref="float" />. /// </returns> public static float GetRadius(this Ability ability, string abilityName = null) { if (ability == null || !ability.IsValid) { return 0; } var name = abilityName ?? ability.StoredName(); float radius; if (radiusDictionary.TryGetValue(name + " " + ability.Level, out radius)) { return radius; } var data = ability.CommonProperties(); if (data == null) { radius = 0; radiusDictionary.Add(name + " " + ability.Level, radius); return radius; } if (data.Width != null) { radius = ability.GetAbilityData(data.Width, abilityName: name); radiusDictionary.Add(name + " " + ability.Level, radius); return radius; } if (data.StringRadius != null) { radius = ability.GetAbilityData(data.StringRadius, abilityName: name); radiusDictionary.Add(name + " " + ability.Level, radius); return radius; } if (data.Radius > 0) { radius = data.Radius; radiusDictionary.Add(name + " " + ability.Level, radius); return radius; } if (!data.IsBuff) { return radius; } radius = (ability.Owner as Hero).GetAttackRange() + 150; radiusDictionary.Add(name + " " + ability.Level, radius); return radius; }
/// <summary> /// Returns projectile speed of the ability /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="abilityLevel"> /// The ability Level. /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <returns> /// The <see cref="float"/>. /// </returns> public static float GetProjectileSpeed(this Ability ability, uint abilityLevel, string abilityName = null) { if (ability == null || !ability.IsValid) { return 0; } var level = abilityLevel != 0 ? abilityLevel : ability.Level; var name = abilityName ?? ability.StoredName(); float speed; if (speedDictionary.TryGetValue(name + " " + level, out speed)) { return speed; } var data = ability.CommonProperties(); if (data == null) { speed = float.MaxValue; speedDictionary.Add(name + " " + level, speed); return speed; } if (data.Speed == null) { return speed; } speed = ability.GetAbilityData(data.Speed, abilityName: name); speedDictionary.Add(name + " " + level, speed); return speed; }
/// <summary> /// Returns prediction for given target after given ability hit delay /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="customDelay"> /// enter your custom delay /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <returns> /// The <see cref="Vector3" />. /// </returns> public static Vector3 GetPrediction( this Ability ability, Unit target, double customDelay = 0, string abilityName = null) { if (ability == null || !ability.IsValid) { return new Vector3(); } if (target == null || !target.IsValid) { return new Vector3(); } var name = abilityName ?? ability.StoredName(); var data = ability.CommonProperties(); var owner = ability.Owner as Unit; var delay = ability.GetCastDelay(owner as Hero, target, true, abilityName: name, useChannel: true); if (data != null) { delay += data.AdditionalDelay; } var speed = ability.GetProjectileSpeed(name); var radius = ability.GetRadius(name); Vector3 xyz; if (speed > 0 && speed < 6000) { xyz = Prediction.SkillShotXYZ( owner, target, (float)((delay + owner.GetTurnTime(target.Position)) * 1000), speed, radius); if (!ability.IsAbilityBehavior(AbilityBehavior.NoTarget, name)) { xyz = Prediction.SkillShotXYZ( owner, target, (float)((delay + (float)owner.GetTurnTime(xyz)) * 1000), speed, radius); } } else { xyz = Prediction.PredictedXYZ(target, (float)(delay * 1000)); } return xyz; }
/// <summary> /// Checks all aspects and returns full delay before target gets hit by given ability /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <returns> /// The <see cref="double" />. /// </returns> public static double GetHitDelay(this Ability ability, Unit target, string abilityName = null) { if (ability == null || !ability.IsValid) { return 0; } if (target == null || !target.IsValid) { return 0; } var name = abilityName ?? ability.StoredName(); var owner = ability.Owner as Unit; var n = name + owner.StoredName() + target.StoredName(); double storedDelay; var found = hitDelayDictionary.TryGetValue(n, out storedDelay); if (!found) { hitDelayDictionary.Add(n, 0); } if (found && !Utils.SleepCheck(n)) { return storedDelay; } var data = ability.CommonProperties(); var delay = ability.GetCastDelay(owner as Hero, target, true, abilityName: name); if (data != null) { delay += data.AdditionalDelay; } var speed = ability.GetProjectileSpeed(name); var radius = ability.GetRadius(name); if (!ability.IsAbilityBehavior(AbilityBehavior.NoTarget, name) && speed < 6000 && speed > 0) { var xyz = ability.GetPrediction(target, abilityName: name); delay += Math.Max((int)(owner.Distance2D(xyz) - radius / 2), 100) / speed; } if (name == "tinker_heat_seeking_missile") { var xyz = ability.GetPrediction(target, abilityName: name); delay += Math.Max(owner.Distance2D(xyz), 100) / speed; } hitDelayDictionary[n] = delay; Utils.Sleep(40, n); return delay; }
/// <summary> /// Returns cast range of ability, if ability is NonTargeted it will return its radius! /// </summary> /// <param name="ability"> /// The ability. /// </param> /// <param name="abilityName"> /// The ability Name. /// </param> /// <returns> /// The <see cref="float" />. /// </returns> public static float GetCastRange(this Ability ability, string abilityName = null) { if (ability == null || !ability.IsValid) { return 0; } var name = abilityName ?? ability.StoredName(); var owner = ability.Owner; var n = name + owner.Handle; if (castRangeDictionary.ContainsKey(n) && !Utils.SleepCheck("Common.GetCastRange." + n)) { return castRangeDictionary[n]; } if (name == "templar_assassin_meld") { return (ability.Owner as Unit).GetAttackRange() + 50; } var data = ability.CommonProperties(); if (!ability.IsAbilityBehavior(AbilityBehavior.NoTarget, name)) { var castRange = (float)ability.CastRange; var bonusRange = 0f; if (data != null && data.RealCastRange != null) { castRange = ability.GetAbilityData(data.RealCastRange, abilityName: name); } if (castRange <= 0) { castRange = 999999; } var hero = owner as Hero; if (hero != null && name == "dragon_knight_dragon_tail" && hero.HasModifier("modifier_dragon_knight_dragon_form")) { bonusRange = 250; } else if (hero != null && name == "beastmaster_primal_roar" && hero.AghanimState()) { bonusRange = 350; } var aetherLens = hero != null ? hero.FindItem("item_aether_lens", true) : null; if (aetherLens != null) { bonusRange += aetherLens.GetAbilityData("cast_range_bonus"); } if (!castRangeDictionary.ContainsKey(n)) { castRangeDictionary.Add(n, castRange + bonusRange); Utils.Sleep(5000, "Common.GetCastRange." + n); } else { castRangeDictionary[n] = castRange + bonusRange; Utils.Sleep(5000, "Common.GetCastRange." + n); } return castRange + bonusRange; } float radius; if (data == null) { return ability.CastRange; } if (ability.StoredName() == "earthshaker_enchant_totem" && (owner as Hero).AghanimState()) { radius = ability.GetAbilityData("scepter_distance") + 100; } else if (!data.FakeCastRange) { radius = ability.GetRadius(name); } else { radius = ability.GetAbilityData(data.RealCastRange, abilityName: name); } if (!castRangeDictionary.ContainsKey(n)) { castRangeDictionary.Add(n, radius); Utils.Sleep(5000, "Common.GetCastRange." + n); } else { castRangeDictionary[n] = radius; Utils.Sleep(5000, "Common.GetCastRange." + n); } return radius; }