Kain2030

Perfect Evade - 0.99.7b

Jul 26th, 2013
321
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 59.26 KB | None | 0 0
  1. require "MapPosition"
  2. --[[
  3.     Perfect Evade 0.99.7b by Husky
  4.     ========================================================================
  5.  
  6.     This script enables you to evade nearly all skillshots by simply moving
  7.     your champion out of the way. While evading it will move just the required
  8.     distance and choose the best path so you will hardly notice the script.
  9.     It will automatically resume your last command so that it seamlessly fits
  10.     to any playstyle. Other scripts that modify your movement will work with
  11.     this script (like Orbwalker).
  12.  
  13.     Supported Enemy Champions (current version):
  14.     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  15.  
  16.     Lux (without ultimate)
  17.     Nidalee
  18.     Kennen
  19.     Amumu
  20.     Lee Sin
  21.     Morgana
  22.     Ezreal
  23.     Ahri
  24.     Olaf
  25.     Leona
  26.     Karthus
  27.     Chogath
  28.     Blitzcrank
  29.     Anivia
  30.     Zyra
  31.     Gragas
  32.     Nautilus
  33.     Urgot
  34.  
  35.     Changelog
  36.     ~~~~~~~~~
  37.  
  38.     0.98 (beta)     - automatically evades all skillshots (only line skillshots atm and only a few champions - all champions will be supported in version 1.0)
  39.                     - works even when you click spam
  40.                     - continues your last order (attack/movement) after finishing the evasion
  41.                     - optimized path finding makes you take the best evasion path
  42.                     - allows you to change your direction while evading if there is enough time to reach your new destination
  43.                     - works for predicted spells that are not directly cast to your position
  44.  
  45.     0.99 (beta)     - added support for circular skillshots
  46.                     - added evasion for shots from bushes
  47.                     - added smoothing to make the evasion look more legit
  48.  
  49.     0.99.1 (beta)   - reworked to fully utilize the 2D Geometry library
  50.                     - dodging is disabled now if your champion is dead
  51.                     - added more champions
  52.                     - removed a bug with circular spells ignoring the spell delay (champ went back into the dangerous area too early)
  53.                     - removed a bug that made you dodge spells of teammates
  54.  
  55.     0.99.2 (beta)   - removed a bug in the path finding algorithm, that made you take the wrong path and go into the wrong direction when dodging linear skill shots (back to the enemy or not the shortest path)
  56.                     - removed a bug that made you go back into circular skill shots befor the spell has ended
  57.                     - after evading a circular skillshot you will instantly start to approach your destination through walking "around" the dangerous area
  58.                     - modified the script to work vor non-vip users with some limitations: doesnt continue attacks after an evasion but continues the movement; doesn't evade if another script takes control over your movement - like sida's auto carry
  59.                     - draws the path of linear skillshots and projectiles now
  60.                     - added more champions
  61.  
  62.     0.99.3 (beta)   - fixed a few problems that made the game bugsplat
  63.                     - removed a bug that made you take the wrong path when evading while auto attacking creeps or champions with a ranged champion
  64.                     - the script will now continue spell casts after an evasion
  65.                     - fixed a problem with walking back to you starting location when casting a spell while evading
  66.                     - fixed a bug that made you go back into the dangerous area when casting a spell
  67.                     - fixed a few errors in the champion database
  68.                     - fixed a bug that made you stop to attack the tower after an evasion
  69.                     - skillshots from bushes can not be disabled anymore since the bugsplats got fixed and get always dodged now
  70.                     - while channeling spells like katarina ultimate, dodging is disabled (will be enabled again if the incoming skillshot is a cc that would abort your channeling anyway [in a later version of the script])
  71.  
  72.     0.99.4 (beta)   - fixed a problem with mundos axes not getting determined correctly
  73.                     - updated the script to work with the new version of Bot of Legends
  74.  
  75.     0.99.5 (beta)   - fixed a bug that stopped dodging when recalling
  76.                     - if the script isnt able to dodge a spell it doesn't try it anymore (better team fights)
  77.                     - added a way to enable/disable doding and drawing of skillshots ingame (by using allclass menu <press shift>)
  78.                     - script uses the Packet library now, to faster address packet changes in the future
  79.                     - the script doesnt require any additional libraries anymore
  80.     0.99.7 (beta)   - MapPosition support, vayne Q dodge, more champs
  81.  
  82. ]]
  83.  
  84. -- Config ----------------------------------------------------------------------
  85. local isVayne = false
  86.  
  87. local evadeBuffer = 10 -- expand the dangerous area (safer evades in laggy situations)
  88. local moveBuffer = 25 -- additional movement distance (champions stop a few pixels before their destination)
  89. local smoothing = 0 -- make movements smoother by moving further between evasion phases
  90. local mapPosition = MapPosition()
  91. _G.evade = 0
  92. SEARCH_RADIUS = 50
  93. K1 = SEARCH_RADIUS*math.cos(2*math.pi / 3)
  94. K2 = SEARCH_RADIUS*math.sin(2*math.pi / 3)
  95. K3 = SEARCH_RADIUS*math.cos(4*math.pi / 3)
  96. K4 = SEARCH_RADIUS*math.sin(4*math.pi / 3)
  97.  
  98. if myHero.charName == "Vayne" then
  99.     isVayne = true
  100.     smoothing = 70
  101. end
  102.  
  103. champions = {
  104.     ["Lux"] = {charName = "Lux", skillshots = {
  105.         ["Light Binding"] =  {name = "Light Binding", spellName = "LuxLightBinding", spellDelay = 250, projectileName = "LuxLightBinding_mis.troy", projectileSpeed = 1200, range = 1300, radius = 80, type = "line", cc = "true"},
  106.     }},
  107.     ["Nidalee"] = {charName = "Nidalee", skillshots = {
  108.         ["Javelin Toss"] = {name = "Javelin Toss", spellName = "JavelinToss", spellDelay = 100, projectileName = "nidalee_javelinToss_mis.troy", projectileSpeed = 1300, range = 1500, radius = 60, type = "line", cc = "false"}
  109.     }},
  110.     ["Kennen"] = {charName = "Kennen", skillshots = {
  111.         ["Thundering Shuriken"] = {name = "Thundering Shuriken", spellName = "KennenShurikenHurlMissile1", spellDelay = 180, projectileName = "kennen_ts_mis.troy", projectileSpeed = 1640, range = 1050, radius = 53, type = "line", cc = "false"}
  112.     }},
  113.     ["Amumu"] = {charName = "Amumu", skillshots = {
  114.         ["Bandage Toss"] = {name = "Bandage Toss", spellName = "BandageToss", spellDelay = 250, projectileName = "Bandage_beam.troy", projectileSpeed = 2000, range = 1100, radius = 80, type = "line", cc = "true"}
  115.     }},
  116.     ["Lee Sin"] = {charName = "LeeSin", skillshots = {
  117.         ["Sonic Wave"] = {name = "Sonic Wave", spellName = "BlindMonkQOne", spellDelay = 250, projectileName = "blindMonk_Q_mis_01.troy", projectileSpeed = 1800, range = 1100, radius = 60, type = "line", cc = "false"}
  118.     }},
  119.     ["Morgana"] = {charName = "Morgana", skillshots = {
  120.         ["Dark Binding"] = {name = "Dark Binding", spellName = "DarkBindingMissile", spellDelay = 250, projectileName = "DarkBinding_mis.troy", projectileSpeed = 1200, range = 1300, radius = 70, type = "line", cc = "true"}
  121.     }},
  122.     ["Ezreal"] = {charName = "Ezreal", skillshots = {
  123.         ["Mystic Shot"]             = {name = "Mystic Shot",      spellName = "EzrealMysticShotMissile",      spellDelay = 250,  projectileName = "Ezreal_mysticshot_mis.troy",  projectileSpeed = 1975, range = 1200,  radius = 80,  type = "line", cc = "false"},
  124.         ["Trueshot Barrage"]        = {name = "Trueshot Barrage", spellName = "EzrealTrueshotBarrage",        spellDelay = 1000, projectileName = "Ezreal_TrueShot_mis.troy",    projectileSpeed = 1990, range = 20000, radius = 250, type = "line", cc = "false"},
  125.         ["Mystic Shot (Pulsefire)"] = {name = "Mystic Shot",      spellName = "EzrealMysticShotPulseMissile", spellDelay = 250,  projectileName = "Ezreal_mysticshot_mis.troy",  projectileSpeed = 1975, range = 1200,  radius = 80,  type = "line", cc = "false"}
  126.     }},
  127.     ["Ahri"] = {charName = "Ahri", skillshots = {
  128.         ["Orb of Deception"] = {name = "Orb of Deception", spellName = "AhriOrbofDeception", spellDelay = 250, projectileName = "Ahri_Orb_mis.troy",   projectileSpeed = 1660, range = 1000, radius = 50, type = "line", cc = "false"},
  129.         ["Charm"]            = {name = "Charm",            spellName = "AhriSeduce",         spellDelay = 250, projectileName = "Ahri_Charm_mis.troy", projectileSpeed = 1535, range = 1000, radius = 50, type = "line", cc = "true"}
  130.     }},
  131.     ["Leona"] = {charName = "Leona", skillshots = {
  132.         ["Zenith Blade"] = {name = "Zenith Blade", spellName = "LeonaZenithBladeMissile", spellDelay = 250, projectileName = "Leona_ZenithBlade_mis.troy", projectileSpeed = 2000, range = 900, radius = 90, type = "line", cc = "true"}
  133.     }},
  134.  
  135.     ["Chogath"] = {charName = "Chogath", skillshots = {
  136.         ["Rupture"] = {name = "Rupture", spellName = "Rupture", spellDelay = 290, projectileName = "rupture_cas_01_red_team.troy", projectileSpeed = 900, range = 950, radius = 190, type = "circular", cc = "true"}
  137.     }},
  138.     ["Blitzcrank"] = {charName = "Blitzcrank", skillshots = {
  139.         ["Rocket Grab"] = {name = "Rocket Grab", spellName = "RocketGrabMissile", spellDelay = 125, projectileName = "FistGrab_mis.troy", projectileSpeed = 1800, range = 1050, radius = 70, type = "line", cc = "true"}
  140.     }},
  141.     ["Anivia"] = {charName = "Anivia", skillshots = {
  142.         ["Flash Frost"] = {name = "Flash Frost", spellName = "FlashFrostSpell", spellDelay = 250, projectileName = "Cryo_FlashFrost_mis.troy", projectileSpeed = 850, range = 1100, radius = 110, type = "line", cc = "true"}
  143.     }},
  144.     ["Zyra"] = {charName = "Zyra", skillshots = {
  145.         ["Grasping Roots"] = {name = "Grasping Roots", spellName = "ZyraGraspingRoots", spellDelay = 250, projectileName = "Zyra_E_sequence_impact.troy", projectileSpeed = 1150, range = 1150, radius = 70,  type = "line", cc = "true"},
  146.         ["Zyra Passive Death"] = {name = "Zyra Passive", spellName = "ZyraPassiveDeathMissile", spellDelay = 250, projectileName = "zyra_passive_plant_mis_fire.troy", projectileSpeed = 1900, range = 1474, radius = 70,  type = "line", cc = "false"},
  147.     }},
  148.     ["Nautilus"] = {charName = "Nautilus", skillshots = {
  149.         ["Dredge Line"] = {name = "Dredge Line", spellName = "NautilusAnchorDragMissile", spellDelay = 250, projectileName = "Nautilus_Q_mis.troy", projectileSpeed = 1965, range = 1075, radius = 60, type = "line", cc = "true"}
  150.     }},
  151.     --["Urgot"] = {charName = "Urgot", skillshots = {
  152.     --    ["Plasma Grenade"] = {name = "Plasma Grenade", spellName = "UrgotPlasmaGrenade", spellDelay = 250, projectileName = "UrgotPlasmaGrenade_mis.troy", projectileSpeed = 1440, range = 850,  radius = 180, type = "line", cc = "false"},
  153.     --}},
  154.  
  155.     ["Caitlyn"] = {charName = "Caitlyn", skillshots = {
  156.         ["Piltover Peacemaker"] = {name = "Piltover Peacemaker", spellName = "CaitlynPiltoverPeacemaker", spellDelay = 625, projectileName = "caitlyn_Q_mis.troy", projectileSpeed = 2150, range = 1300, radius = 60, type = "line", cc = "false"}
  157.     }},
  158.     ["Mundo"] = {charName = "DrMundo", skillshots = {
  159.         ["Infected Cleaver"] = {name = "Infected Cleaver", spellName = "InfectedCleaverMissile", spellDelay = 250, projectileName = "dr_mundo_infected_cleaver_mis.troy", projectileSpeed = 1975, range = 1050, radius = 70, type = "line", cc = "false"}
  160.     }},
  161.     ["Brand"] = {charName = "Brand", skillshots = {
  162.         ["Brand Missile"] = {name = "BrandBlazeMissile", spellName = "BrandBlazeMissile", spellDelay = 250, projectileName = "BrandBlaze_mis.troy", projectileSpeed = 1565, range = 1100, radius = 50, type = "line", cc = "false"},
  163.     }},
  164.     ["Corki"] = {charName = "Corki", skillshots = {
  165.         ["Missile Barrage small"] = {name = "Missile Barrage small", spellName = "MissileBarrageMissile", spellDelay = 175, projectileName = "corki_MissleBarrage_mis.troy", projectileSpeed = 1950, range = 1250, radius = 50, type = "line", cc = "false"},
  166.         ["Missile Barrage big"] = {name = "Missile Barrage big", spellName = "MissileBarrageMissile2", spellDelay = 175, projectileName = "corki_MissleBarrage_DD_mis.troy", projectileSpeed = 1950, range = 1250, radius = 50, type = "line", cc = "false"}
  167.     }},
  168.     ["Swain"] = {charName = "Swain", skillshots = {
  169.         ["Nevermove"] = {name = "Nevermove", spellName = "SwainShadowGrasp", spellDelay = 250, projectileName = "swain_shadowGrasp_transform.troy", projectileSpeed = 1000, range = 900, radius = 180, type = "circular", cc = "false"}
  170.     }},
  171.     ["Ashe"] = {charName = "Ashe", skillshots = {
  172.         ["Enchanted Arrow"] = {name = "Enchanted Arrow", spellName = "EnchantedCrystalArrow", spellDelay = 125, projectileName = "EnchantedCrystalArrow_mis.troy", projectileSpeed = 1600, range = 25000, radius = 130, type="line", cc = "true"}
  173.     }},
  174.     ["KogMaw"] = {charName = "KogMaw", skillshots = {
  175.         ["Living Artillery"] = {name = "Living Artillery", spellName = "KogMawLivingArtillery", spellDelay = 250, projectileName = "KogMawLivingArtillery_cas_green.troy", projectileSpeed = 1050, range = 2200, radius = 180, type="circular", cc = "false"}
  176.     }},
  177.     ["KhaZix"] = {charName = "KhaZix", skillshots = {
  178.         ["KhaZix W Missile"] = {name = "KhaZix W Enhanced", spellName = "KhaZixW", spellDelay = 250, projectileName = "Khazix_W_mis.troy", projectileSpeed = 1700, range = 1025, radius = 70, type="line", cc = "false"},
  179.     }},
  180.     ["Zed"] = {charName = "Zed", skillshots = {
  181.         ["ZedShuriken"] = {name = "ZedShuriken", spellName = "ZedShuriken", spellDelay = 0, projectileName = "Zed_Q_Mis.troy", projectileSpeed = 1700, range = 925, radius = 50, type="line", cc = "false"}
  182.     }},
  183.     ["Leblanc"] = {charName = "Leblanc", skillshots = {
  184.         ["Ethereal Chains"] = {name = "Ethereal Chains", spellName = "LeblancSoulShackle", spellDelay = 250, projectileName = "leBlanc_shackle_mis.troy", projectileSpeed = 1585, range = 960, radius = 50, type = "line", cc = "true"},
  185.         ["Ethereal Chains R"] = {name = "Ethereal Chains R", spellName = "LeblancSoulShackleM", spellDelay = 250, projectileName = "leBlanc_shackle_mis_ult.troy", projectileSpeed = 1585, range = 960, radius = 50, type = "line", cc = "true"},
  186.     }},
  187.     ["Elise"] = {charName = "Elise", skillshots = {
  188.         ["Cocoon"] = {name = "Cocoon", spellName = "EliseHumanE", spellDelay = 250, projectileName = "Elise_human_E_mis.troy", projectileSpeed = 1450, range = 1100, radius = 70, type="line", cc = "true"}
  189.     }},
  190.     ["Lulu"] = {charName = "Lulu", skillshots = {
  191.         ["luluQ1"] = {name = "luluQ1", spellName = "LuluQMissile", spellDelay = 100, projectileName = "Lulu_Q_Mis.troy", projectileSpeed = 1450, range = 1000, radius = 50, type="line", cc = "false"},
  192.         ["luluQ2"] = {name = "luluQ2", spellName = "LuluQ", spellDelay = 250, projectileName = "Lulu_Q_Mis.troy", projectileSpeed = 1375, range = 1000, radius = 50, type="line", cc = "false"}
  193.     }},
  194.     ["Thresh"] = {charName = "Thresh", skillshots = {
  195.         --        ["ThreshQ"] = {name = "ThreshQ", spellName = "ThreshQMissile",  spellDelay = 500, projectileName = "Thresh_Q_whip_beam.troy", projectileSpeed = 1900, range = 1100, radius = 70, type="line"},
  196.         --        ["ThreshQ"] = {name = "ThreshQ", spellName = "ThreshQMissile2", spellDelay = 500, projectileName = "Thresh_Q_whip_beam.troy", projectileSpeed = 1900, range = 1100, radius = 70, type="line"},
  197.         --        ["ThreshQ"] = {name = "ThreshQ", spellName = "ThreshQInternal", spellDelay = 500, projectileName = "Thresh_Q_whip_beam.troy", projectileSpeed = 1900, range = 1100, radius = 70, type="line"},
  198.         ["ThreshQ"] = {name = "ThreshQ", spellName = "ThreshQ", spellDelay = 500, projectileName = "Thresh_Q_whip_beam.troy", projectileSpeed = 1900, range = 1100, radius = 70, type="line", cc = "true"}
  199.     }},
  200.     ["Shen"] = {charName = "Shen", skillshots = {
  201.         ["ShadowDash"] = {name = "ShadowDash", spellName = "ShenShadowDash", spellDelay = 125, projectileName = "shen_shadowDash_mis.troy", projectileSpeed = 2000, range = 575, radius = 50, type="line", cc = "true"}
  202.     }},
  203.     ["Quinn"] = {charName = "Quinn", skillshots = {
  204.         ["QuinnQ"] = {name = "QuinnQ", spellName = "QuinnQ", spellDelay = 100, projectileName = "Quinn_Q_missile.troy", projectileSpeed = 1550, range = 1050, radius = 80, type="line", cc = "true"}
  205.     }},
  206.     ["Jayce"] = {charName = "Jayce", skillshots = {
  207.         ["JayceShockBlastCharged"] = {name = "JayceShockBlastCharged", spellName = "JayceShockBlast", spellDelay = 100, projectileName = "JayceOrbLightningCharged.troy", projectileSpeed = 2350, range = 2000, radius = 70, type="line", cc = "false"},   
  208.     }},
  209.     ["Nami"] = {charName = "Nami", skillshots = {
  210.         ["NamiQ"] = {name = "NamiQ", spellName = "NamiQ", spellDelay = 700, projectileName = "Nami_Q_mis.troy", projectileSpeed = math.huge, range = 875, radius = 225, type="circular", cc = "true"},    
  211.     }},  
  212. }
  213.  
  214. -- Globals ---------------------------------------------------------------------
  215.  
  216. evading             = false
  217. allowCustomMovement = true
  218. captureMovements    = true
  219. lastMovement        = {}
  220. possibleTargets     = {}
  221. detectedSkillshots  = {}
  222. moveKeyPressed      = false
  223. packageApiAvailable = false
  224.  
  225. nCount = 0
  226.  
  227. -- Code ------------------------------------------------------------------------
  228.  
  229. function getTarget(targetId)
  230.     if targetId ~= 0 and targetId ~= nil then
  231.         for i = 1, heroManager.iCount, 1 do
  232.             object = heroManager:GetHero(i)
  233.             if object ~= nil and object.valid and object.networkID == lastMovement.targetId then
  234.                 return object
  235.             end
  236.         end
  237.  
  238.         for i,object in ipairs(possibleTargets) do
  239.             if object == nil or not object.valid or object.dead then
  240.                 table.remove(possibleTargets, i)
  241.                 i = i - 1
  242.             elseif object.networkID == lastMovement.targetId then
  243.                 return object
  244.             end
  245.         end
  246.     end
  247.  
  248.     return nil
  249. end
  250.  
  251. function getLastMovementDestination()
  252.     if lastMovement.type == 3 then
  253.         heroPosition = Point(myHero.x, myHero.z)
  254.  
  255.         target = getTarget(lastMovement.targetId)
  256.         if target ~= nil then
  257.             targetPosition = Point(target.x, target.z)
  258.  
  259.             local attackRange = (myHero.range + GetDistance(myHero.minBBox, myHero.maxBBox) / 2 + GetDistance(target.minBBox, target.maxBBox) / 2)
  260.  
  261.             if attackRange <= heroPosition:distance(targetPosition) then
  262.                 return targetPosition + (heroPosition - targetPosition):normalized() * attackRange
  263.             else
  264.                 return heroPosition
  265.             end
  266.         else
  267.             return heroPosition
  268.         end
  269.     elseif lastMovement.type == 7 then
  270.         heroPosition = Point(myHero.x, myHero.z)
  271.  
  272.         target = getTarget(lastMovement.targetId)
  273.         if target ~= nil then
  274.             targetPosition = Point(target.x, target.z)
  275.  
  276.             local castRange = myHero:GetSpellData(lastMovement.spellId).range
  277.  
  278.             if castRange <= heroPosition:distance(targetPosition) then
  279.                 return targetPosition + (heroPosition - targetPosition):normalized() * castRange
  280.             else
  281.                 return heroPosition
  282.             end
  283.         else
  284.             local castRange = myHero:GetSpellData(lastMovement.spellId).range
  285.  
  286.             if castRange <= heroPosition:distance(lastMovement.destination) then
  287.                 return lastMovement.destination + (heroPosition - lastMovement.destination):normalized() * castRange
  288.             else
  289.                 return heroPosition
  290.             end
  291.         end
  292.     else
  293.         return lastMovement.destination
  294.     end
  295. end
  296.  
  297. function OnLoad()
  298.     for i = 1, objManager.maxObjects, 1 do
  299.         local object = objManager:getObject(i)
  300.         if object ~= nil and (object.type == "obj_AI_Minion" or object.type == "obj_AI_Turret") and object.team ~= myHero.team then
  301.             table.insert(possibleTargets, object)
  302.         end
  303.     end
  304.  
  305.     hitboxSize = GetDistance(myHero.minBBox, myHero.maxBBox)
  306.  
  307.     lastMovement = {
  308.         destination = Point(myHero.x, myHero.z),
  309.         moveCommand = Point(myHero.x, myHero.z),
  310.         type = 2,
  311.         targetId = nil,
  312.         spellId = nil,
  313.         approachedPoint = nil
  314.     }
  315.  
  316.     PerfectEvadeConfig = scriptConfig("Perfect Evade", "perfectEvade")
  317.     PerfectEvadeConfig:addParam("dodgeEnabled", "Dodge Skillshots", SCRIPT_PARAM_ONOFF, true)
  318.     PerfectEvadeConfig:addParam("drawEnabled", "Draw Skillshots", SCRIPT_PARAM_ONOFF, true)
  319.     PerfectEvadeConfig:addParam("dodgeCC", "Dodge CC only", SCRIPT_PARAM_ONKEYDOWN, false, 32)
  320.     PerfectEvadeConfig:permaShow("dodgeEnabled")
  321.  
  322.     PerfectEvadeConfig.dodgeEnabled = true
  323.  
  324.     PrintChat(" >> Good Evade 0.99.7 loaded")
  325. end
  326.  
  327. function OnSendPacket(p)
  328.     packageApiAvailable = true
  329.  
  330.     local packet = Packet(p)
  331.     if packet:get('name') == 'S_MOVE' then
  332.         if packet:get('sourceNetworkId') == myHero.networkID then
  333.             if captureMovements then
  334.                 lastMovement.destination = Point(packet:get('x'), packet:get('y'))
  335.                 lastMovement.type = packet:get('type')
  336.                 lastMovement.targetId = packet:get('targetNetworkId')
  337.  
  338.                 if evading then
  339.                     for i, detectedSkillshot in ipairs(detectedSkillshots) do
  340.                         if detectedSkillshot.evading and inDangerousArea(detectedSkillshot, Point(myHero.x, myHero.z)) then
  341.                             dodgeSkillshot(detectedSkillshot)
  342.                             break
  343.                         end
  344.                     end
  345.                 end
  346.             end
  347.  
  348.             if not allowCustomMovement then
  349.                 packet:block()
  350.             end
  351.         end
  352.     elseif packet:get('name') == 'S_CAST' then
  353.         if captureMovements then
  354.             lastMovement.spellId = packet:get('spellId')
  355.             lastMovement.type = 7
  356.             lastMovement.targetId = packet:get('targetNetworkId')
  357.             lastMovement.destination = Point(packet:get('toX'), packet:get('toY'))
  358.  
  359.             if evading then
  360.                 for i, detectedSkillshot in ipairs(detectedSkillshots) do
  361.                     if detectedSkillshot.evading and inDangerousArea(detectedSkillshot, Point(myHero.x, myHero.z)) then
  362.                         dodgeSkillshot(detectedSkillshot)
  363.                         break
  364.                     end
  365.                 end
  366.             end
  367.         end
  368.  
  369.         if not allowCustomMovement then
  370.             packet:block()
  371.         end
  372.     end
  373. end
  374.  
  375. function OnWndMsg(msg,key)
  376.     if not packageApiAvailable then
  377.     if (msg == WM_RBUTTONDOWN) or (msg == WM_RBUTTONUP) or (msg == WM_MOUSEMOVE and moveKeyPressed) then
  378.         if captureMovements then
  379.             lastMovement.destination = Point(mousePos.x, mousePos.z)
  380.             lastMovement.type = 2
  381.             lastMovement.targetId = nil
  382.  
  383.             if evading then
  384.                 for i, detectedSkillshot in ipairs(detectedSkillshots) do
  385.                     if detectedSkillshot.evading and inDangerousArea(detectedSkillshot, Point(myHero.x, myHero.z)) then
  386.                         dodgeSkillshot(detectedSkillshot)
  387.                         break
  388.                     end
  389.                 end
  390.             end
  391.         end
  392.  
  393.         if not allowCustomMovement then
  394.             myHero:MoveTo(lastMovement.moveCommand.x, lastMovement.moveCommand.y)
  395.         else
  396.             lastMovement.moveCommand = Point(mousePos.x, mousePos.z)
  397.         end
  398.     end
  399.  
  400.     if msg == WM_RBUTTONDOWN then
  401.         moveKeyPressed = true
  402.     elseif msg == WM_RBUTTONUP then
  403.         moveKeyPressed = false
  404.     end
  405.     end
  406. end
  407.  
  408. function getSideOfLine(linePoint1, linePoint2, point)
  409.     result = ((linePoint2.x - linePoint1.x) * (point.y - linePoint1.y) - (linePoint2.y - linePoint1.y) * (point.x - linePoint1.x))
  410.     if result < 0 then
  411.         return -1
  412.     elseif result > 0 then
  413.         return 1
  414.     else
  415.         return 0
  416.     end
  417. end
  418.  
  419. function dodgeSkillshot(skillshot)
  420.     --lag temp fix
  421.     if GetDistance(skillshot.startPosition) < 200 then return end
  422.  
  423.     if PerfectEvadeConfig.dodgeEnabled and not myHero.dead and (myHero.casting == 0 or lastMovement.spellId == RECALL) then
  424.         -- if PerfectEvadeConfig.dodgeCC and skillshot.skillshot.cc == "true" then -- space pressed
  425.             -- if skillshot.skillshot.type == "line" then
  426.                 -- dodgeLineShot(skillshot)
  427.             -- else
  428.                 -- dodgeCircularShot(skillshot)
  429.             -- end     
  430.  
  431.         if not PerfectEvadeConfig.dodgeCC or (isVayne and myHero:CanUseSpell(_Q) == READY) then -- def mode, space not pressed
  432.             if skillshot.skillshot.type == "line" then
  433.                 dodgeLineShot(skillshot)
  434.             else
  435.                 dodgeCircularShot(skillshot)
  436.             end
  437.         end
  438.     end
  439. end
  440.  
  441. function dodgeCircularShot(skillshot)
  442.     skillshot.evading = true
  443.  
  444.     heroPosition = Point(myHero.x, myHero.z)
  445.  
  446.     moveableDistance = myHero.ms * math.max(skillshot.endTick - GetTickCount() - GetLatency(), 0) / 1000
  447.     evadeRadius = skillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer + moveBuffer
  448.  
  449.     safeTarget = skillshot.endPosition + (heroPosition - skillshot.endPosition):normalized() * evadeRadius
  450.  
  451.     if getLastMovementDestination():distance(skillshot.endPosition) <= evadeRadius then
  452.         closestTarget = skillshot.endPosition + (getLastMovementDestination() - skillshot.endPosition):normalized() * evadeRadius
  453.     else
  454.         closestTarget = nil
  455.     end
  456.        
  457.     lineDistance = Line(heroPosition, getLastMovementDestination()):distance(skillshot.endPosition)
  458.     directionTarget = heroPosition + (getLastMovementDestination() - heroPosition):normalized() * (math.sqrt(heroPosition:distance(skillshot.endPosition)^2 - lineDistance^2) + math.sqrt(evadeRadius^2 - lineDistance^2))
  459.     if directionTarget:distance(skillshot.endPosition) >= evadeRadius + 1 then
  460.         directionTarget = heroPosition + (getLastMovementDestination() - heroPosition):normalized() * (math.sqrt(evadeRadius^2 - lineDistance^2) - math.sqrt(heroPosition:distance(skillshot.endPosition)^2 - lineDistance^2))
  461.     end
  462.  
  463.     possibleMovementTargets = {}
  464.     intersectionPoints = Circle(skillshot.endPosition, evadeRadius):intersectionPoints(Circle(heroPosition, moveableDistance))
  465.     if #intersectionPoints == 2 then
  466.         leftTarget = intersectionPoints[1]
  467.         rightTarget = intersectionPoints[2]
  468.  
  469.         local theta = ((-skillshot.endPosition + leftTarget):polar() - (-skillshot.endPosition + rightTarget):polar()) % 360
  470.         if ((theta >= 180 and getSideOfLine(skillshot.endPosition, leftTarget, directionTarget) == getSideOfLine(skillshot.endPosition, leftTarget, heroPosition) and getSideOfLine(skillshot.endPosition, rightTarget, directionTarget) == getSideOfLine(skillshot.endPosition, rightTarget, heroPosition)) or (theta <= 180 and (getSideOfLine(skillshot.endPosition, leftTarget, directionTarget) == getSideOfLine(skillshot.endPosition, leftTarget, heroPosition) or getSideOfLine(skillshot.endPosition, rightTarget, directionTarget) == getSideOfLine(skillshot.endPosition, rightTarget, heroPosition)))) then
  471.             table.insert(possibleMovementTargets, directionTarget)
  472.         end
  473.  
  474.         if closestTarget ~= nil and ((theta >= 180 and getSideOfLine(skillshot.endPosition, leftTarget, closestTarget) == getSideOfLine(skillshot.endPosition, leftTarget, heroPosition) and getSideOfLine(skillshot.endPosition, rightTarget, closestTarget) == getSideOfLine(skillshot.endPosition, rightTarget, heroPosition)) or (theta <= 180 and (getSideOfLine(skillshot.endPosition, leftTarget, closestTarget) == getSideOfLine(skillshot.endPosition, leftTarget, heroPosition) or getSideOfLine(skillshot.endPosition, rightTarget, closestTarget) == getSideOfLine(skillshot.endPosition, rightTarget, heroPosition)))) then
  475.             table.insert(possibleMovementTargets, closestTarget)
  476.         end
  477.  
  478.         table.insert(possibleMovementTargets, safeTarget)
  479.         table.insert(possibleMovementTargets, leftTarget)
  480.         table.insert(possibleMovementTargets, rightTarget)
  481.     else
  482.         if skillshot.skillshot.radius <= moveableDistance then
  483.             table.insert(possibleMovementTargets, closestTarget)
  484.             table.insert(possibleMovementTargets, directionTarget)
  485.             table.insert(possibleMovementTargets, safeTarget)
  486.         end
  487.     end
  488.  
  489.     closestPoint = findBestDirectionOld(getLastMovementDestination(), possibleMovementTargets)
  490.     if closestPoint ~= nil then
  491.         closestPoint = closestPoint + (closestPoint - heroPosition):normalized() * smoothing
  492.         evadeTo(closestPoint.x, closestPoint.y)
  493.     else
  494.         if not evading then
  495.             -- CAN NOT EVADE - STILL TRY IT
  496.             PrintChat("Evade move 666")
  497.             if isVayne and myHero:CanUseSpell(_Q) == READY then
  498.                 safeTarget = safeTarget + (safeTarget - heroPosition):normalized() * smoothing
  499.                 evadeTo(safeTarget.x, safeTarget.y)
  500.             end
  501.         end
  502.     end
  503. end
  504.  
  505. function InsideTheWall(evadeTestPoint)
  506.     nCount = nCount + 1
  507.     p0 = Point(myHero.x, myHero.z)
  508.     p1 = Point(evadeTestPoint.x + SEARCH_RADIUS, evadeTestPoint.y)
  509.     p2 = Point(evadeTestPoint.x + K1, evadeTestPoint.y + K2)
  510.     p3 = Point(evadeTestPoint.x + K3, evadeTestPoint.y + K4)
  511.     InsideTheWall1 = mapPosition:intersectsWall( p1 )
  512.     InsideTheWall2 = mapPosition:intersectsWall( p2 )
  513.     InsideTheWall3 = mapPosition:intersectsWall( p3 )
  514.     if not InsideTheWall1 and not InsideTheWall2 and not InsideTheWall3 then
  515.         return false
  516.     else
  517.         return true
  518.     end
  519. end
  520.  
  521. function dodgeLineShot(skillshot)
  522.     skillshot.evading = true
  523.  
  524.     heroPosition = Point(myHero.x, myHero.z)
  525.  
  526.     skillshotLine = Line(skillshot.startPosition, skillshot.endPosition)
  527.     distanceFromSkillshotPath = skillshotLine:distance(heroPosition)
  528.     evadeDistance = skillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer + moveBuffer
  529.  
  530.     normalVector = Point(skillshot.directionVector.y, -skillshot.directionVector.x):normalized()
  531.     nessecaryMoveWidth = evadeDistance - distanceFromSkillshotPath
  532.  
  533.     evadeTo1 = heroPosition + normalVector * nessecaryMoveWidth
  534.     evadeTo2 = heroPosition - normalVector * nessecaryMoveWidth
  535.     if skillshotLine:distance(evadeTo1) >= skillshotLine:distance(evadeTo2) then
  536.         longitudinalApproachLength = calculateLongitudinalApproachLength(skillshot, nessecaryMoveWidth)
  537.         if longitudinalApproachLength >= 0 then
  538.             evadeToTarget1 = evadeTo1 - skillshot.directionVector * longitudinalApproachLength
  539.         end
  540.  
  541.         longitudinalApproachLength = calculateLongitudinalApproachLength(skillshot, evadeDistance + distanceFromSkillshotPath)
  542.         if longitudinalApproachLength >= 0 then
  543.             evadeToTarget2 = heroPosition - normalVector * (evadeDistance + distanceFromSkillshotPath) - skillshot.directionVector * longitudinalApproachLength
  544.         end
  545.  
  546.         longitudinalRetreatLength = calculateLongitudinalRetreatLength(skillshot, nessecaryMoveWidth)
  547.         if longitudinalRetreatLength >= 0 then
  548.             evadeToTarget3 = evadeTo1 + skillshot.directionVector * longitudinalRetreatLength
  549.         end
  550.  
  551.         longitudinalRetreatLength = calculateLongitudinalRetreatLength(skillshot, evadeDistance + distanceFromSkillshotPath)
  552.         if longitudinalRetreatLength >= 0 then
  553.             evadeToTarget4 = heroPosition - normalVector * (evadeDistance + distanceFromSkillshotPath) + skillshot.directionVector * longitudinalRetreatLength
  554.         end
  555.  
  556.         safeTarget = evadeTo1
  557.  
  558.         closestPoint = getLastMovementDestination() + normalVector * (evadeDistance - skillshotLine:distance(getLastMovementDestination()))
  559.         closestPoint2 = getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) + normalVector * evadeDistance
  560.  
  561.     else
  562.         longitudinalApproachLength = calculateLongitudinalApproachLength(skillshot, nessecaryMoveWidth)
  563.         if longitudinalApproachLength >= 0 then
  564.             evadeToTarget1 = evadeTo2 - skillshot.directionVector * longitudinalApproachLength
  565.         end
  566.  
  567.         longitudinalApproachLength = calculateLongitudinalApproachLength(skillshot, evadeDistance + distanceFromSkillshotPath)
  568.         if longitudinalApproachLength >= 0 then
  569.             evadeToTarget2 = heroPosition + normalVector * (evadeDistance + distanceFromSkillshotPath) - skillshot.directionVector * longitudinalApproachLength
  570.         end
  571.  
  572.         longitudinalRetreatLength = calculateLongitudinalRetreatLength(skillshot, nessecaryMoveWidth)
  573.         if longitudinalRetreatLength >= 0 then
  574.             evadeToTarget3 = evadeTo2 + skillshot.directionVector * longitudinalRetreatLength
  575.         end
  576.  
  577.         longitudinalRetreatLength = calculateLongitudinalRetreatLength(skillshot, evadeDistance + distanceFromSkillshotPath)
  578.         if longitudinalRetreatLength >= 0 then
  579.             evadeToTarget4 = heroPosition + normalVector * (evadeDistance + distanceFromSkillshotPath) + skillshot.directionVector * longitudinalRetreatLength
  580.         end
  581.  
  582.         safeTarget = evadeTo2
  583.  
  584.         closestPoint = getLastMovementDestination() - normalVector * (evadeDistance - skillshotLine:distance(getLastMovementDestination()))
  585.         closestPoint2 = getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) - normalVector * evadeDistance
  586.     end
  587.  
  588.     if skillshotLine:distance(getLastMovementDestination()) <= evadeDistance then
  589.         directionTarget = findBestDirection(getLastMovementDestination(), {closestPoint, closestPoint2, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) - normalVector * evadeDistance, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) + normalVector * evadeDistance})
  590.     else
  591.         if getSideOfLine(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) == getSideOfLine(skillshot.startPosition, skillshot.endPosition, heroPosition) then
  592.             if skillshotLine:distance(heroPosition) <= skillshotLine:distance(getLastMovementDestination()) then
  593.                 directionTarget = heroPosition + (getLastMovementDestination()-heroPosition):normalized() * ((evadeDistance - distanceFromSkillshotPath) * heroPosition:distance(getLastMovementDestination())) / (skillshotLine:distance(getLastMovementDestination()) - distanceFromSkillshotPath)
  594.             else
  595.                 directionTarget = heroPosition + (getLastMovementDestination()-heroPosition):normalized() * ((evadeDistance + distanceFromSkillshotPath) * heroPosition:distance(getLastMovementDestination())) / (distanceFromSkillshotPath - skillshotLine:distance(getLastMovementDestination()))
  596.             end
  597.         else
  598.             directionTarget = heroPosition + (getLastMovementDestination() - heroPosition):normalized() * (evadeDistance + distanceFromSkillshotPath) * heroPosition:distance(getLastMovementDestination()) / (skillshotLine:distance(getLastMovementDestination()) + distanceFromSkillshotPath)
  599.         end
  600.     end
  601.  
  602.     evadeTarget = nil
  603.     if directionTarget and ((evadeToTarget1 ~= nil and evadeToTarget3 ~= nil and Line(evadeToTarget1, evadeToTarget3):distance(directionTarget) <= 1 and getSideOfLine(evadeToTarget1, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget1), directionTarget) ~= getSideOfLine(evadeToTarget3, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget3), directionTarget)) or (evadeToTarget2 ~= nil and evadeToTarget4 ~= nil and Line(evadeToTarget2, evadeToTarget4):distance(directionTarget) <= 1 and getSideOfLine(evadeToTarget2, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget2), directionTarget) ~= getSideOfLine(evadeToTarget4, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget4), directionTarget)) or (evadeToTarget1 ~= nil and evadeToTarget3 == nil and getSideOfLine(heroPosition, evadeToTarget1, skillshot.startPosition) ~= getSideOfLine(heroPosition, evadeToTarget1, directionTarget)) or (evadeToTarget2 ~= nil and evadeToTarget4 == nil and getSideOfLine(heroPosition, evadeToTarget2, skillshot.startPosition) ~= getSideOfLine(heroPosition, evadeToTarget2, directionTarget))) then
  604.         evadeTarget = directionTarget
  605.     else
  606.         possibleMovementTargets = {}
  607.  
  608.         if (evadeToTarget1 ~= nil and evadeToTarget3 ~= nil and Line(evadeToTarget1, evadeToTarget3):distance(closestPoint2) <= 1 and getSideOfLine(evadeToTarget1, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget1), closestPoint2) ~= getSideOfLine(evadeToTarget3, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget3), closestPoint2)) or (evadeToTarget2 ~= nil and evadeToTarget4 ~= nil and Line(evadeToTarget2, evadeToTarget4):distance(closestPoint2) <= 1 and getSideOfLine(evadeToTarget2, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget2), closestPoint2) ~= getSideOfLine(evadeToTarget4, getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, evadeToTarget4), closestPoint2)) or (evadeToTarget1 ~= nil and evadeToTarget3 == nil and getSideOfLine(heroPosition, evadeToTarget1, skillshot.startPosition) ~= getSideOfLine(heroPosition, evadeToTarget1, closestPoint2)) or (evadeToTarget2 ~= nil and evadeToTarget4 == nil and getSideOfLine(heroPosition, evadeToTarget2, skillshot.startPosition) ~= getSideOfLine(heroPosition, evadeToTarget2, closestPoint2)) then
  609.             table.insert(possibleMovementTargets, closestPoint2)
  610.         end
  611.  
  612.         if evadeToTarget1 ~= nil then
  613.             table.insert(possibleMovementTargets, evadeToTarget1)
  614.         end
  615.        
  616.         if evadeToTarget2 ~= nil then
  617.             table.insert(possibleMovementTargets, evadeToTarget2)
  618.         end
  619.        
  620.         if evadeToTarget3 ~= nil then
  621.             table.insert(possibleMovementTargets, evadeToTarget3)
  622.         end
  623.  
  624.         if evadeToTarget4 ~= nil then
  625.             table.insert(possibleMovementTargets, evadeToTarget4)
  626.         end
  627.  
  628.         evadeTarget = findBestDirection(getLastMovementDestination(), possibleMovementTargets)
  629.     end
  630.  
  631.     -- try to evade until spellshields are implemented -- TEMPORARY OVERRIDE !!!
  632.     if evadeTarget == nil then
  633.         --evadeTarget = safeTarget
  634.     end
  635.  
  636.     if evadeTarget ~= nil then
  637.         if getSideOfLine(skillshot.startPosition, skillshot.endPosition, evadeTarget) == getSideOfLine(skillshot.startPosition, skillshot.endPosition, getLastMovementDestination()) and skillshotLine:distance(getLastMovementDestination()) > evadeDistance then
  638.             pathDirectionVector = (evadeTarget - heroPosition)
  639.             if getSideOfLine(skillshot.startPosition, skillshot.endPosition, heroPosition) == getSideOfLine(skillshot.startPosition, skillshot.endPosition, evadeTarget) then
  640.                 evadeTarget = evadeTarget + pathDirectionVector:normalized() * (pathDirectionVector:len() + smoothing / (evadeDistance - distanceFromSkillshotPath) * pathDirectionVector:len())
  641.             else
  642.                 evadeTarget = evadeTarget + pathDirectionVector:normalized() * (pathDirectionVector:len() + smoothing / (evadeDistance + distanceFromSkillshotPath) * pathDirectionVector:len())
  643.             end
  644.         end
  645.         evadeTo(evadeTarget.x, evadeTarget.y)
  646.     else
  647.         -- USE SPELLSHIELDS AND ABILITES TO EVADE
  648.     end
  649. end
  650.  
  651. function findBestDirectionOld(referencePoint, possiblePoints)
  652.     closestPoint = nil
  653.     closestDistance = nil
  654.     for i, point in ipairs(possiblePoints) do
  655.         if point ~= nil then
  656.             distance = point:distance(referencePoint)
  657.             if (closestDistance == nil or distance <= closestDistance) then
  658.                 closestDistance = distance
  659.                 closestPoint = point
  660.             end
  661.         end
  662.     end
  663.     return closestPoint
  664. end
  665.  
  666. function findBestDirection(referencePoint, possiblePoints)
  667.     closestPoint = nil
  668.     closestDistance = nil
  669.     for i, point in ipairs(possiblePoints) do
  670.         if point ~= nil then
  671.             distance = point:distance(referencePoint)
  672.             if (closestDistance == nil or distance <= closestDistance) and not InsideTheWall(point) then
  673.                 closestDistance = distance
  674.                 closestPoint = point
  675.             end
  676.         end
  677.     end
  678.     return closestPoint
  679. end
  680.  
  681. function calculateLongitudinalApproachLength(skillshot, d)
  682.     v1 = skillshot.skillshot.projectileSpeed
  683.     v2 = myHero.ms
  684.     longitudinalDistance = math.max(skillshotPosition(skillshot, GetTickCount()):distance(getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, Point(myHero.x, myHero.z))) - hitboxSize / 2 - skillshot.skillshot.radius, 0)  + v1 * math.max(skillshot.startTick - GetTickCount(), 0) / 1000
  685.  
  686.     preResult = -d^2 * v1^4 + d^2 * v2^2 * v1^2 + longitudinalDistance^2 * v2^2 * v1^2
  687.     if preResult >= 0 then
  688.         result = (math.sqrt(preResult) - longitudinalDistance * v2^2) / (v1^2 - v2^2)
  689.         if result >= 0 then
  690.             return result
  691.         end
  692.     end
  693.  
  694.     return -1
  695. end
  696.  
  697. function calculateLongitudinalRetreatLength(skillshot, d)
  698.     v1 = skillshot.skillshot.projectileSpeed
  699.     v2 = myHero.ms
  700.     longitudinalDistance = math.max(skillshotPosition(skillshot, GetTickCount()):distance(getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, Point(myHero.x, myHero.z))) - hitboxSize / 2 - skillshot.skillshot.radius, 0) + v1 * math.max(skillshot.startTick - GetTickCount(), 0) / 1000
  701.  
  702.     preResult = -d^2 * v1^4 + d^2 * v2^2 * v1^2 + longitudinalDistance^2 * v2^2 * v1^2
  703.     if preResult >= 0 then
  704.         result = (math.sqrt(preResult) + longitudinalDistance * v2^2) / (v1^2 - v2^2)
  705.         if result >= 0 then
  706.             return result
  707.         end
  708.     end
  709.  
  710.     return -1
  711. end
  712.  
  713. function inDangerousArea(skillshot, coordinate)
  714.     if skillshot.skillshot.type == "line" then
  715.         return inRange(skillshot, coordinate) and not skillshotHasPassed(skillshot, coordinate) and Line(skillshot.startPosition, skillshot.endPosition):distance(coordinate) < (skillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer) and coordinate:distance(skillshot.startPosition + skillshot.directionVector) <= coordinate:distance(skillshot.startPosition - skillshot.directionVector)
  716.     else
  717.         return coordinate:distance(skillshot.endPosition) <= skillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer
  718.     end
  719. end
  720.  
  721. function inRange(skillshot, coordinate)
  722.     return getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, coordinate):distance(skillshot.startPosition) <= skillshot.skillshot.range
  723. end
  724.  
  725. function OnCreateObj(object)
  726.     if object ~= nil and (object.type == "obj_AI_Minion" or object.type == "obj_AI_Turret") and object.team ~= myHero.team then
  727.         table.insert(possibleTargets, object)
  728.     elseif object.team ~= myHero.team then
  729.         for i, skillShotChampion in pairs(champions) do
  730.             for i, skillshot in pairs(skillShotChampion.skillshots) do
  731.                 if skillshot.projectileName == object.name then
  732.                     for i, detectedSkillshot in ipairs(detectedSkillshots) do
  733.                         if detectedSkillshot.skillshot.projectileName == skillshot.projectileName then
  734.                             return
  735.                         end
  736.                     end
  737.  
  738.                     for i = 1, heroManager.iCount, 1 do
  739.                         currentHero = heroManager:GetHero(i)
  740.                         if currentHero.team == myHero.team and skillShotChampion.charName == currentHero.charName then
  741.                             return
  742.                         end
  743.                     end
  744.  
  745.                     startPosition = Point(object.x, object.z)
  746.                     if skillshot.type == "line" then
  747.                         skillshotToAdd = {object = object, startPosition = startPosition, endPosition = nil, directionVector = nil, startTick = GetTickCount(), endTick = GetTickCount() + skillshot.range/skillshot.projectileSpeed*1000, skillshot = skillshot, evading = false}
  748.                     else
  749.                         endPosition = Point(object.x, object.z)
  750.                         table.insert(detectedSkillshots, {startPosition = startPosition, endPosition = endPosition, directionVector = (endPosition - startPosition):normalized(), startTick = GetTickCount() + skillshot.spellDelay, endTick = GetTickCount() + skillshot.spellDelay + skillshot.projectileSpeed, skillshot = skillshot, evading = false})
  751.                     end
  752.  
  753.                     return
  754.                 end
  755.             end
  756.         end
  757.     end
  758. end
  759.  
  760. function OnProcessSpell(object, spell)
  761.     if lastMovement.type == 7 and myHero.team == object.team and object.name == myHero.name then
  762.         lastMovement.type = 3
  763.     end
  764.  
  765.     if not myHero.dead and object.team ~= myHero.team then
  766.         for i, skillShotChampion in pairs(champions) do
  767.             if skillShotChampion.charName == object.charName then
  768.                 for i, skillshot in pairs(skillShotChampion.skillshots) do
  769.                     if skillshot.spellName == spell.name then
  770.                         startPosition = Point(object.x, object.z)
  771.                         endPosition = Point(spell.endPos.x, spell.endPos.z)
  772.                         directionVector = (endPosition - startPosition):normalized()
  773.                         if skillshot.type == "line" then
  774.                             table.insert(detectedSkillshots, {startPosition = startPosition, endPosition = startPosition + directionVector * skillshot.range, directionVector = directionVector, startTick = GetTickCount() + skillshot.spellDelay, endTick = GetTickCount() + skillshot.spellDelay + skillshot.range/skillshot.projectileSpeed*1000, skillshot = skillshot, evading = false})
  775.                         else
  776.                             table.insert(detectedSkillshots, {startPosition = startPosition, endPosition = endPosition, directionVector = directionVector, startTick = GetTickCount() + skillshot.spellDelay, endTick = GetTickCount() + skillshot.spellDelay + skillshot.projectileSpeed, skillshot = skillshot, evading = false})
  777.                         end
  778.                         return
  779.                     end
  780.                 end
  781.             end
  782.         end
  783.     end
  784. end
  785.  
  786. function skillshotPosition(skillshot, tickCount)
  787.     if skillshot.skillshot.type == "line" then
  788.         return skillshot.startPosition + skillshot.directionVector * math.max(tickCount - skillshot.startTick, 0) * skillshot.skillshot.projectileSpeed / 1000
  789.     else
  790.         return skillshot.endPosition
  791.     end
  792. end
  793.  
  794. function skillshotHasPassed(skillshot, coordinate)
  795.     footOfPerpendicular = getPerpendicularFootpoint(skillshot.startPosition, skillshot.endPosition, coordinate)
  796.     currentSkillshotPosition = skillshotPosition(skillshot, GetTickCount() - 2 * GetLatency())
  797.  
  798.     return (getSideOfLine(coordinate, footOfPerpendicular, currentSkillshotPosition) ~= getSideOfLine(coordinate, footOfPerpendicular, skillshot.startPosition)) and currentSkillshotPosition:distance(footOfPerpendicular) >= ((skillshot.skillshot.radius + hitboxSize / 2))
  799. end
  800.  
  801. function getPerpendicularFootpoint(linePoint1, linePoint2, point)
  802.     distanceFromLine = Line(linePoint1, linePoint2):distance(point)
  803.     directionVector = (linePoint2 - linePoint1):normalized()
  804.  
  805.     footOfPerpendicular = point + Point(-directionVector.y, directionVector.x) * distanceFromLine
  806.     if Line(linePoint1, linePoint2):distance(footOfPerpendicular) > distanceFromLine then
  807.         footOfPerpendicular = point - Point(-directionVector.y, directionVector.x) * distanceFromLine
  808.     end
  809.  
  810.     return footOfPerpendicular
  811. end
  812.  
  813. function OnTick()
  814.     if skillshotToAdd ~= nil and skillshotToAdd.object ~= nil and skillshotToAdd.object.valid and (GetTickCount() - skillshotToAdd.startTick) >= GetLatency() then
  815.         skillshotToAdd.directionVector = (Point(skillshotToAdd.object.x, skillshotToAdd.object.z) - skillshotToAdd.startPosition):normalized()
  816.         skillshotToAdd.endPosition = skillshotToAdd.startPosition + skillshotToAdd.directionVector * skillshotToAdd.skillshot.range
  817.  
  818.         table.insert(detectedSkillshots, skillshotToAdd)
  819.  
  820.         skillshotToAdd = nil
  821.     end
  822.  
  823.     heroPosition = Point(myHero.x, myHero.z)
  824.     for i, detectedSkillshot in ipairs(detectedSkillshots) do
  825.         if detectedSkillshot.endTick <= GetTickCount() then
  826.             table.remove(detectedSkillshots, i)
  827.             i = i-1
  828.             if detectedSkillshot.evading then
  829.                 continueMovement(detectedSkillshot)
  830.             end
  831.         else
  832.             if evading then
  833.                 if detectedSkillshot.evading and not inDangerousArea(detectedSkillshot, heroPosition) then
  834.                     if detectedSkillshot.skillshot.type == "line" then
  835.                         -- SKILLSHOT PASSED
  836.                         if skillshotHasPassed(detectedSkillshot, heroPosition) then
  837.                             continueMovement(detectedSkillshot)
  838.  
  839.                         -- DESTINATION SAFE
  840.                         elseif not inDangerousArea(detectedSkillshot, getLastMovementDestination()) and (getSideOfLine(detectedSkillshot.startPosition, detectedSkillshot.endPosition, heroPosition) == getSideOfLine(detectedSkillshot.startPosition, detectedSkillshot.endPosition, getLastMovementDestination())) then
  841.                             continueMovement(detectedSkillshot)
  842.  
  843.                         -- OUT OF RANGE
  844.                         elseif not inRange(detectedSkillshot, heroPosition) and not inRange(detectedSkillshot, getLastMovementDestination()) then
  845.                             continueMovement(detectedSkillshot)
  846.  
  847.                         -- APPROACH TARGET
  848.                         else
  849.                             if lastMovement.approachedPoint ~= getLastMovementDestination() then
  850.                                 footpoint = getPerpendicularFootpoint(detectedSkillshot.startPosition, detectedSkillshot.endPosition, getLastMovementDestination())
  851.                                 closestSafePoint = footpoint + Point(-detectedSkillshot.directionVector.y, detectedSkillshot.directionVector.x) * (detectedSkillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer + moveBuffer)
  852.                                 if (getSideOfLine(detectedSkillshot.startPosition, detectedSkillshot.endPosition, heroPosition) ~= getSideOfLine(detectedSkillshot.startPosition, detectedSkillshot.endPosition, closestSafePoint)) then
  853.                                     closestSafePoint = footpoint - Point(-detectedSkillshot.directionVector.y, detectedSkillshot.directionVector.x) * (detectedSkillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer + moveBuffer)
  854.                                 end
  855.  
  856.                                 captureMovements = false
  857.                                 allowCustomMovement = true
  858.                                 myHero:MoveTo(closestSafePoint.x, closestSafePoint.y)
  859.                                 lastMovement.moveCommand = Point(closestSafePoint.x, closestSafePoint.y)
  860.                                 allowCustomMovement = false
  861.                                 captureMovements = true
  862.  
  863.                                 lastMovement.approachedPoint = getLastMovementDestination()
  864.                             end
  865.                         end
  866.                     else
  867.                         evadeRadius = detectedSkillshot.skillshot.radius + hitboxSize / 2 + evadeBuffer + moveBuffer
  868.                         directionVector = (heroPosition - detectedSkillshot.endPosition):normalized()
  869.                         tangentDirectionVector = Point(-directionVector.y, directionVector.x)
  870.                         movementTargetSideOfLine = getSideOfLine(heroPosition, heroPosition + tangentDirectionVector, getLastMovementDestination())
  871.                         skillshotSideOfLine = getSideOfLine(heroPosition, heroPosition + tangentDirectionVector, detectedSkillshot.endPosition)
  872.                        
  873.                         -- DESTINATION SAFE
  874.                         if movementTargetSideOfLine == 0 or movementTargetSideOfLine ~= skillshotSideOfLine then
  875.                             continueMovement(detectedSkillshot)
  876.                         else
  877.                             if getLastMovementDestination():distance(detectedSkillshot.endPosition) <= evadeRadius then
  878.                                 closestTarget = detectedSkillshot.endPosition + (getLastMovementDestination() - detectedSkillshot.endPosition):normalized() * evadeRadius
  879.                             else
  880.                                 closestTarget = nil
  881.                             end
  882.  
  883.                             dx = detectedSkillshot.endPosition.x - heroPosition.x
  884.                             dy = detectedSkillshot.endPosition.y - heroPosition.y
  885.                             D_squared = dx * dx + dy * dy
  886.                             if D_squared < evadeRadius * evadeRadius then
  887.                                 safePoint1 = heroPosition - tangentDirectionVector * (evadeRadius / 2 + smoothing)
  888.                                 safePoint2 = heroPosition + tangentDirectionVector * (evadeRadius / 2 + smoothing)
  889.                             else
  890.                                 intersectionPoints = Circle(detectedSkillshot.endPosition, evadeRadius):intersectionPoints(Circle(heroPosition, math.sqrt(D_squared - evadeRadius * evadeRadius)))
  891.                                 if #intersectionPoints == 2 then
  892.                                     safePoint1 = heroPosition - (heroPosition - intersectionPoints[1]):normalized() * (evadeRadius / 2 + smoothing)
  893.                                     safePoint2 = heroPosition - (heroPosition - intersectionPoints[2]):normalized() * (evadeRadius / 2 + smoothing)
  894.                                 else
  895.                                     safePoint1 = heroPosition - tangentDirectionVector * (evadeRadius / 2 + smoothing)
  896.                                     safePoint2 = heroPosition + tangentDirectionVector * (evadeRadius / 2 + smoothing)
  897.                                 end
  898.                             end
  899.  
  900.                             local theta = ((-detectedSkillshot.endPosition + safePoint2):polar() - (-detectedSkillshot.endPosition + safePoint1):polar()) % 360
  901.                             if closestTarget ~= nil and (
  902.                                 (
  903.                                     theta < 180 and (
  904.                                         getSideOfLine(detectedSkillshot.endPosition, safePoint2, closestTarget) == getSideOfLine(detectedSkillshot.endPosition, safePoint2, heroPosition) and
  905.                                         getSideOfLine(detectedSkillshot.endPosition, safePoint1, closestTarget) == getSideOfLine(detectedSkillshot.endPosition, safePoint1, heroPosition)
  906.                                     )
  907.                                 ) or (
  908.                                     theta > 180 and (
  909.                                         getSideOfLine(detectedSkillshot.endPosition, safePoint2, closestTarget) == getSideOfLine(detectedSkillshot.endPosition, safePoint2, heroPosition) or
  910.                                         getSideOfLine(detectedSkillshot.endPosition, safePoint1, closestTarget) == getSideOfLine(detectedSkillshot.endPosition, safePoint1, heroPosition)
  911.                                     )
  912.                                 )
  913.                             ) then
  914.                                 possibleMovementTargets = {closestTarget, safePoint1, safePoint2}
  915.                             else
  916.                                 possibleMovementTargets = {safePoint1, safePoint2}
  917.                             end
  918.  
  919.                             closestPoint = findBestDirection(getLastMovementDestination(), possibleMovementTargets)
  920.                             if closestPoint ~= nil then
  921.                                 captureMovements = false
  922.                                 allowCustomMovement = true
  923.                                 myHero:MoveTo(closestPoint.x, closestPoint.y)
  924.                                 lastMovement.moveCommand = Point(closestPoint.x, closestPoint.y)
  925.                                 allowCustomMovement = false
  926.                                 captureMovements = true
  927.                             end
  928.                         end
  929.                     end
  930.                 end
  931.             elseif inDangerousArea(detectedSkillshot, heroPosition) then
  932.                 dodgeSkillshot(detectedSkillshot)
  933.             end
  934.         end
  935.     end
  936. end
  937.  
  938. function evadeTo(x, y)
  939.     evadePoint = Point(x, y)
  940.     if isVayne and  myHero:CanUseSpell(_Q) == READY then
  941.         CastSpell(_Q, x, y)
  942.     end
  943.     allowCustomMovement = true
  944.     captureMovements = false
  945.     myHero:MoveTo(0, 0)
  946.     myHero:MoveTo(x, y)
  947.     lastMovement.moveCommand = Point(x, y)
  948.     captureMovements = true
  949.     allowCustomMovement = false
  950.     evading = true
  951.     _G.evade = 1
  952.     evadingTick = GetTickCount()
  953. end
  954.  
  955. function continueMovement(skillshot)
  956.     if evading then
  957.         skillshot.evading = false
  958.         lastMovement.approachedPoint = nil
  959.         allowCustomMovement = true
  960.         evading = false
  961.         _G.evade = 0
  962.         if lastMovement.type == 2 then
  963.             captureMovements = false
  964.             myHero:MoveTo(0, 0)
  965.             myHero:MoveTo(getLastMovementDestination().x, getLastMovementDestination().y)
  966.             captureMovements = true
  967.         elseif lastMovement.type == 3 then
  968.             target = getTarget(lastMovement.targetId)
  969.  
  970.             if target ~= nil then
  971.                 captureMovements = false
  972.                 myHero:Attack(target)
  973.                 captureMovements = true
  974.             else
  975.                 captureMovements = false
  976.                 myHero:MoveTo(myHero.x, myHero.z)
  977.                 captureMovements = true
  978.             end
  979.         elseif lastMovement.type == 10 then
  980.             myHero:HoldPosition()
  981.         elseif lastMovement.type == 7 then
  982.             if myHero.userdataObject ~= nil and myHero.userdataObject:CanUseSpell(lastMovement.spellId) then
  983.                 target = getTarget(lastMovement.targetId)
  984.                 if target ~= nil then
  985.                     CastSpell(lastMovement.spellId, target)
  986.                 else
  987.                     CastSpell(lastMovement.spellId, lastMovement.destination.x, lastMovement.destination.y)
  988.                 end
  989.             end
  990.             lastMovement.type = 3
  991.         end
  992.     end
  993. end
  994.  
  995. function OnDraw()
  996.     if PerfectEvadeConfig.drawEnabled then
  997.         for i, detectedSkillshot in ipairs(detectedSkillshots) do
  998.             skillshotPos = skillshotPosition(detectedSkillshot, GetTickCount())
  999.  
  1000.             if detectedSkillshot.skillshot.type == "line" then
  1001.                 directionVector = detectedSkillshot.endPosition - detectedSkillshot.startPosition
  1002.                 DrawArrow(D3DXVECTOR3(detectedSkillshot.startPosition.x, myHero.y, detectedSkillshot.startPosition.y), D3DXVECTOR3(directionVector.x, myHero.y, directionVector.y), detectedSkillshot.startPosition:distance(detectedSkillshot.endPosition) + 170, detectedSkillshot.skillshot.radius, -10000000000000000000000, RGBA(255,255,255,0))
  1003.  
  1004.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius + 10, 0x00FF00)
  1005.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius, 0xFFFFFF)
  1006.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius - 10, 0xFFFFFF)
  1007.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius - 20, 0xFFFFFF)
  1008.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius - 30, 0xFFFFFF)
  1009.             else
  1010.                 DrawCircle(skillshotPos.x, myHero.y, skillshotPos.y, detectedSkillshot.skillshot.radius, 0x00FF00)
  1011.             end
  1012.         end
  1013.     end
  1014. end
Advertisement
Add Comment
Please, Sign In to add comment