public static bool InSkillShot(this Vector2 position, Spell spell, float radius, bool predictCollision = true) { if (spell.SpellType == SpellType.Line) { var spellPos = spell.CurrentSpellPosition; var spellEndPos = predictCollision ? spell.GetSpellEndPosition() : spell.EndPos; var projection = position.ProjectOn(spellPos, spellEndPos); return(projection.IsOnSegment && projection.SegmentPoint.Distance(position) <= spell.Radius + radius); } if (spell.SpellType == SpellType.Circular) { if (spell.Info.SpellName == "VeigarEventHorizon") { return(position.Distance(spell.EndPos) <= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius && position.Distance(spell.EndPos) >= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius - 125); } if (spell.Info.SpellName == "DariusCleave") { return(position.Distance(spell.EndPos) <= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius && position.Distance(spell.EndPos) >= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius - 220); } return(position.Distance(spell.EndPos) <= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius); } if (spell.SpellType == SpellType.Arc) { if (position.IsLeftOfLineSegment(spell.StartPos, spell.EndPos)) { return(false); } var spellRange = spell.StartPos.Distance(spell.EndPos); var midPoint = spell.StartPos + spell.Direction * (spellRange / 2); return(position.Distance(midPoint) <= spell.Radius + radius - ObjectCache.MyHeroCache.BoundingRadius); } if (spell.SpellType == SpellType.Cone) { return(!position.IsLeftOfLineSegment(spell.CnStart, spell.CnLeft) && !position.IsLeftOfLineSegment(spell.CnLeft, spell.CnRight) && !position.IsLeftOfLineSegment(spell.CnRight, spell.CnStart)); } return(false); }
public static float GetClosestDistanceApproach(Spell spell, Vector2 pos, float speed, float delay, Vector2 heroPos, float extraDist) { var walkDir = (pos - heroPos).Normalized(); switch (spell.SpellType) { case SpellType.Line when spell.Info.ProjectileSpeed != float.MaxValue: { var spellPos = spell.GetCurrentSpellPosition(true, delay); var spellEndPos = spell.GetSpellEndPosition(); var extendedPos = pos.ExtendDir(walkDir, ObjectCache.MyHeroCache.BoundingRadius + speed * delay / 1000); var cpa2 = MathUtils.GetCollisionDistanceEx(heroPos, walkDir * speed, ObjectCache.MyHeroCache.BoundingRadius, spellPos, spell.Direction * spell.Info.ProjectileSpeed, spell.Radius + extraDist, out var cHeroPos, out var cSpellPos); var cHeroPosProjection = cHeroPos.ProjectOn(heroPos, extendedPos); var cSpellPosProjection = cSpellPos.ProjectOn(spellPos, spellEndPos); if (cSpellPosProjection.IsOnSegment && cHeroPosProjection.IsOnSegment && cpa2 != float.MaxValue) { return(0); } var cpa = MathUtilsCpa.CPAPointsEx(heroPos, walkDir * speed, spellPos, spell.Direction * spell.Info.ProjectileSpeed, pos, spellEndPos, out cHeroPos, out cSpellPos); cHeroPosProjection = cHeroPos.ProjectOn(heroPos, extendedPos); cSpellPosProjection = cSpellPos.ProjectOn(spellPos, spellEndPos); var checkDist = ObjectCache.MyHeroCache.BoundingRadius + spell.Radius + extraDist; if (cSpellPosProjection.IsOnSegment && cHeroPosProjection.IsOnSegment) { return(Math.Max(0, cpa - checkDist)); } return(checkDist); //return MathUtils.ClosestTimeOfApproach(heroPos, walkDir * speed, spellPos, spell.Orientation * spell.info.projectileSpeed); } case SpellType.Line when spell.Info.ProjectileSpeed == float.MaxValue: { var spellHitTime = Math.Max(0, spell.EndTime - Environment.TickCount - delay); //extraDelay var walkRange = heroPos.Distance(pos); var predictedRange = speed * (spellHitTime / 1000); var tHeroPos = heroPos + walkDir * Math.Min(predictedRange, walkRange); //Hero predicted pos var projection = tHeroPos.ProjectOn(spell.StartPos, spell.EndPos); return(Math.Max(0, tHeroPos.Distance(projection.SegmentPoint) - (spell.Radius + ObjectCache.MyHeroCache.BoundingRadius + extraDist))); //+ dodgeBuffer } case SpellType.Circular: { var spellHitTime = Math.Max(0, spell.EndTime - Environment.TickCount - delay); //extraDelay var walkRange = heroPos.Distance(pos); var predictedRange = speed * (spellHitTime / 1000); var tHeroPos = heroPos + walkDir * Math.Min(predictedRange, walkRange); //Hero predicted pos switch (spell.Info.SpellName) { case "VeigarEventHorizon": { const int wallRadius = 65; var midRadius = spell.Radius - wallRadius; if (spellHitTime == 0) { return(0); } return(tHeroPos.Distance(spell.EndPos) >= spell.Radius ? Math.Max(0, tHeroPos.Distance(spell.EndPos) - midRadius - wallRadius) : Math.Max(0, midRadius - tHeroPos.Distance(spell.EndPos) - wallRadius)); } case "DariusCleave": { const int wallRadius = 115; var midRadius = spell.Radius - wallRadius; if (spellHitTime == 0) { return(0); } return(tHeroPos.Distance(spell.EndPos) >= spell.Radius ? Math.Max(0, tHeroPos.Distance(spell.EndPos) - midRadius - wallRadius) : Math.Max(0, midRadius - tHeroPos.Distance(spell.EndPos) - wallRadius)); } } var closestDist = Math.Max(0, tHeroPos.Distance(spell.EndPos) - (spell.Radius + extraDist)); if (spell.Info.ExtraEndTime > 0 && closestDist != 0) { var remainingTime = Math.Max(0, spell.EndTime + spell.Info.ExtraEndTime - Environment.TickCount - delay); var predictedRange2 = speed * (remainingTime / 1000); var tHeroPos2 = heroPos + walkDir * Math.Min(predictedRange2, walkRange); if (CheckMoveToDirection(tHeroPos, tHeroPos2)) { return(0); } } else { return(closestDist); } break; } case SpellType.Arc: { var spellPos = spell.GetCurrentSpellPosition(true, delay); var spellEndPos = spell.GetSpellEndPosition(); var pDir = spell.Direction.Perpendicular(); spellPos = spellPos - pDir * spell.Radius / 2; spellEndPos = spellEndPos - pDir * spell.Radius / 2; var extendedPos = pos.ExtendDir(walkDir, ObjectCache.MyHeroCache.BoundingRadius); var cpa = MathUtilsCpa.CPAPointsEx(heroPos, walkDir * speed, spellPos, spell.Direction * spell.Info.ProjectileSpeed, pos, spellEndPos, out var cHeroPos, out var cSpellPos); var cHeroPosProjection = cHeroPos.ProjectOn(heroPos, extendedPos); var cSpellPosProjection = cSpellPos.ProjectOn(spellPos, spellEndPos); var checkDist = spell.Radius + extraDist; if (cHeroPos.InSkillShot(spell, ObjectCache.MyHeroCache.BoundingRadius)) { if (cSpellPosProjection.IsOnSegment && cHeroPosProjection.IsOnSegment) { return(Math.Max(0, cpa - checkDist)); } return(checkDist); } break; } case SpellType.Cone: { var spellHitTime = Math.Max(0, spell.EndTime - Environment.TickCount - delay); //extraDelay var walkRange = heroPos.Distance(pos); var predictedRange = speed * (spellHitTime / 1000); var tHeroPos = heroPos + walkDir * Math.Min(predictedRange, walkRange); //Hero predicted pos var sides = new[] { heroPos.ProjectOn(spell.CnStart, spell.CnLeft).SegmentPoint, heroPos.ProjectOn(spell.CnLeft, spell.CnRight).SegmentPoint, heroPos.ProjectOn(spell.CnRight, spell.CnStart).SegmentPoint }; var p = sides.OrderBy(x => x.Distance(x)).First(); return(Math.Max(0, tHeroPos.Distance(p) - (spell.Radius + ObjectCache.MyHeroCache.BoundingRadius + extraDist))); } } return(1); }