local version = "1.51" --[[ Ahri - the Nine-Tailed Fox Author: Draconis Version: 1.51 Copyright 2016 Dependency: Standalone --]] if myHero.charName ~= "Ahri" then return end require 'HPrediction' ------------------------------------------------------ -- Callbacks ------------------------------------------------------ function OnLoad() print("Ahri - the Nine-Tailed Fox: Good luck and have fun!") Variables() Menu() end function OnTick() ComboKey = Settings.combo.comboKey HarassKey = Settings.harass.harassKey JungleClearKey = Settings.jungle.jungleKey LaneClearKey = Settings.lane.laneKey if ComboKey then Combo(Target) end if HarassKey then Harass(Target) end if JungleClearKey then JungleClear() end if LaneClearKey then LaneClear() end if Settings.ks.killSteal then KillSteal() end Checks() end function OnDraw() if not myHero.dead and not Settings.drawing.mDraw then if SkillQ.ready and Settings.drawing.qDraw then DrawCircle(myHero.x, myHero.y, myHero.z, SkillQ.range, RGB(Settings.drawing.qColor[2], Settings.drawing.qColor[3], Settings.drawing.qColor[4])) end if SkillW.ready and Settings.drawing.wDraw then DrawCircle(myHero.x, myHero.y, myHero.z, SkillW.range, RGB(Settings.drawing.wColor[2], Settings.drawing.wColor[3], Settings.drawing.wColor[4])) end if SkillE.ready and Settings.drawing.eDraw then DrawCircle(myHero.x, myHero.y, myHero.z, SkillE.range, RGB(Settings.drawing.eColor[2], Settings.drawing.eColor[3], Settings.drawing.eColor[4])) end if SkillR.ready and Settings.drawing.rDraw then DrawCircle(myHero.x, myHero.y, myHero.z, SkillR.range, RGB(Settings.drawing.rColor[2], Settings.drawing.rColor[3], Settings.drawing.rColor[4])) end if Settings.drawing.myHero then DrawCircle(myHero.x, myHero.y, myHero.z, TrueRange(), RGB(Settings.drawing.myColor[2], Settings.drawing.myColor[3], Settings.drawing.myColor[4])) end if Settings.drawing.Target and Target ~= nil then DrawCircle(Target.x, Target.y, Target.z, 80, ARGB(255, 10, 255, 10)) end if Settings.drawing.Text then Calculation() end end end ------------------------------------------------------ -- Functions ------------------------------------------------------ function Combo(unit) if ValidTarget(unit) and unit ~= nil and unit.type == myHero.type then if Settings.combo.comboMode == 1 then if Settings.combo.useR then CastR(unit) end CastE(unit) CastQ(unit) CastW(unit) else CastE(unit) CastQ(unit) CastW(unit) end end end function Harass(unit) if ValidTarget(unit) and unit ~= nil and unit.type == myHero.type and not IsMyManaLow() then if Settings.harass.useQ then CastQ(unit) end if Settings.harass.useE then CastE(unit) end if Settings.harass.useW then CastW(unit) end end end function LaneClear() enemyMinions:update() if LaneClearKey then for i, minion in pairs(enemyMinions.objects) do if ValidTarget(minion) and minion ~= nil then if Settings.lane.laneQ and GetDistance(minion) <= SkillQ.range and SkillQ.ready then local BestPos, BestHit = GetBestLineFarmPosition(SkillQ.range, SkillQ.width, enemyMinions.objects) if BestPos ~= nil then CastSpell(_Q, BestPos.x, BestPos.z) end end if Settings.lane.laneW and GetDistance(minion) <= SkillW.range and SkillW.ready then CastSpell(_W) end end end end end function JungleClear() if Settings.jungle.jungleKey then jungleMinions:update() for i, JungleMob in pairs(jungleMinions.objects) do if JungleMob ~= nil and JungleMob.health > 1 then if Settings.jungle.jungleQ and GetDistance(JungleMob) <= SkillQ.range and SkillQ.ready then CastSpell(_Q, JungleMob.x, JungleMob.z) end if Settings.jungle.jungleW and GetDistance(JungleMob) <= SkillW.range and SkillW.ready then CastSpell(_W) end end end end end function CastQ(unit) if unit ~= nil and GetDistance(unit) <= SkillQ.range and SkillQ.ready then local CastPosition, HitChance = HPred:GetPredict(HPred.Presets["Ahri"]["Q"], unit, myHero) if CastPosition and HitChance >= 1.6 then CastSpell(_Q, CastPosition.x, CastPosition.z) end end end function CastE(unit) if unit ~= nil and GetDistance(unit) <= SkillE.range and SkillE.ready then local CastPosition, HitChance = HPred:GetPredict(HPred.Presets["Ahri"]["E"], unit, myHero) if CastPosition and HitChance >= 1.6 then CastSpell(_E, CastPosition.x, CastPosition.z) end end end function CastW(unit) if unit ~= nil and SkillW.ready and GetDistance(unit) <= SkillW.range then CastSpell(_W) end end function CastR(unit) if unit ~= nil then if SkillR.ready and GetDistance(unit) <= SkillQ.range and Settings.combo.useR == 1 then local Mouse = Vector(myHero) + 400 * (Vector(mousePos) - Vector(myHero)):normalized() CastSpell(_R, Mouse.x, Mouse.z) elseif SkillR.ready and GetDistance(unit) <= SkillQ.range and Settings.combo.useR == 2 then CastSpell(_R, unit.x, unit.z) elseif Settings.combo.useR == 3 then return end end end function KillSteal() for _, enemy in ipairs(GetEnemyHeroes()) do if ValidTarget(enemy) and enemy.visible then local qDmg = getDmg("Q", enemy, myHero) local eDmg = getDmg("E", enemy, myHero) if enemy.health <= qDmg then CastQ(enemy) elseif enemy.health <= (qDmg + eDmg) then CastE(enemy) CastQ(enemy) elseif enemy.health <= eDmg then CastE(enemy) end if Settings.ks.autoIgnite then AutoIgnite(enemy) end end end end function Calculation() for _, enemy in ipairs(GetEnemyHeroes()) do if ValidTarget(enemy) and enemy.visible then local qDmg = getDmg("Q", enemy, myHero) local wDmg = getDmg("W", enemy, myHero) local eDmg = getDmg("E", enemy, myHero) local iDmg = getDmg("IGNITE", enemy, myHero) if enemy.health <= qDmg then DrawText3D(tostring("Killable: Q"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= qDmg + wDmg then DrawText3D(tostring("Killable: Q > W"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= eDmg then DrawText3D(tostring("Killable: E"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= (qDmg + eDmg) then DrawText3D(tostring("Killable: E > Q"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= (wDmg + eDmg) then DrawText3D(tostring("Killable: E > W"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= (qDmg + eDmg + wDmg) then DrawText3D(tostring("Killable: E > Q > W"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) elseif enemy.health <= (qDmg + eDmg + wDmg + iDmg) then DrawText3D(tostring("Killable: E > Q > W > IGNITE"), enemy.x, enemy.y, enemy.z, 16, ARGB(255, 10, 255, 10), true) end end end end function AutoIgnite(unit) if ValidTarget(unit, Ignite.range) and unit.health <= 50 + (20 * myHero.level) then if Ignite.ready then CastSpell(Ignite.slot, unit) end end end ------------------------------------------------------ -- Checks, menu & stuff ------------------------------------------------------ function Checks() SkillQ.ready = (myHero:CanUseSpell(_Q) == READY) SkillW.ready = (myHero:CanUseSpell(_W) == READY) SkillE.ready = (myHero:CanUseSpell(_E) == READY) SkillR.ready = (myHero:CanUseSpell(_R) == READY) if myHero:GetSpellData(SUMMONER_1).name:find(Ignite.name) then Ignite.slot = SUMMONER_1 elseif myHero:GetSpellData(SUMMONER_2).name:find(Ignite.name) then Ignite.slot = SUMMONER_2 end Ignite.ready = (Ignite.slot ~= nil and myHero:CanUseSpell(Ignite.slot) == READY) TargetSelector:update() Target = GetCustomTarget() if Settings.drawing.lfc.lfc then _G.DrawCircle = DrawCircle2 else _G.DrawCircle = _G.oldDrawCircle end if Settings.combo.comboSwitch and Settings.combo.comboMode == 1 then Settings.combo.comboMode = 2 elseif not Settings.combo.comboSwitch and Settings.combo.comboMode == 2 then Settings.combo.comboMode = 1 end end function IsMyManaLow() if myHero.mana < (myHero.maxMana * ( Settings.harass.harassMana / 100)) then return true else return false end end function Menu() Settings = scriptConfig("Ahri - the Nine-Tailed Fox "..version.."", "DraconisAhri") Settings:addSubMenu("["..myHero.charName.."] - Combo Settings", "combo") Settings.combo:addParam("comboKey", "Combo Key", SCRIPT_PARAM_ONKEYDOWN, false, 32) Settings.combo:addParam("comboSwitch", "Combo Switch", SCRIPT_PARAM_ONKEYTOGGLE, false, GetKey("A")) Settings.combo:addParam("comboMode", "Combo Mode", SCRIPT_PARAM_LIST, 1, { "REQW", "EQW"}) Settings.combo:addParam("useR", "Use "..SkillR.name.." (R) in Combo", SCRIPT_PARAM_LIST, 1, { "To mouse", "Toward enemy", "Don't use"}) Settings.combo:permaShow("comboKey") Settings.combo:permaShow("comboMode") Settings:addSubMenu("["..myHero.charName.."] - Harass Settings", "harass") Settings.harass:addParam("harassKey", "Harass Key", SCRIPT_PARAM_ONKEYDOWN, false, GetKey("C")) Settings.harass:addParam("useQ", "Use "..SkillQ.name.." (Q) in Harass", SCRIPT_PARAM_ONOFF, true) Settings.harass:addParam("useW", "Use "..SkillW.name.." (W) in Harass", SCRIPT_PARAM_ONOFF, false) Settings.harass:addParam("useE", "Use "..SkillE.name.." (E) in Harass", SCRIPT_PARAM_ONOFF, true) Settings.harass:addParam("harassMana", "Min. Mana Percent: ", SCRIPT_PARAM_SLICE, 50, 0, 100, 0) Settings.harass:permaShow("harassKey") Settings:addSubMenu("["..myHero.charName.."] - Lane Clear Settings", "lane") Settings.lane:addParam("laneKey", "Lane Clear Key", SCRIPT_PARAM_ONKEYDOWN, false, GetKey("V")) Settings.lane:addParam("laneQ", "Clear with "..SkillQ.name.." (Q)", SCRIPT_PARAM_ONOFF, true) Settings.lane:addParam("laneW", "Clear with "..SkillW.name.." (W)", SCRIPT_PARAM_ONOFF, true) Settings.lane:permaShow("laneKey") Settings:addSubMenu("["..myHero.charName.."] - Jungle Clear Settings", "jungle") Settings.jungle:addParam("jungleKey", "Jungle Clear Key", SCRIPT_PARAM_ONKEYDOWN, false, GetKey("V")) Settings.jungle:addParam("jungleQ", "Clear with "..SkillQ.name.." (Q)", SCRIPT_PARAM_ONOFF, true) Settings.jungle:addParam("jungleW", "Clear with "..SkillW.name.." (W)", SCRIPT_PARAM_ONOFF, true) Settings.jungle:permaShow("jungleKey") Settings:addSubMenu("["..myHero.charName.."] - KillSteal Settings", "ks") Settings.ks:addParam("killSteal", "Use Smart Kill Steal", SCRIPT_PARAM_ONOFF, true) Settings.ks:addParam("autoIgnite", "Auto Ignite", SCRIPT_PARAM_ONOFF, true) Settings.ks:permaShow("killSteal") Settings:addSubMenu("["..myHero.charName.."] - Draw Settings", "drawing") Settings.drawing:addParam("mDraw", "Disable All Range Draws", SCRIPT_PARAM_ONOFF, false) Settings.drawing:addParam("Target", "Draw Circle on Target", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("Text", "Draw Text on Target", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("myHero", "Draw My Range", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("myColor", "Draw My Range Color", SCRIPT_PARAM_COLOR, {255, 255, 255, 255}) Settings.drawing:addParam("qDraw", "Draw "..SkillQ.name.." (Q) Range", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("qColor", "Draw "..SkillQ.name.." (Q) Color", SCRIPT_PARAM_COLOR, {255, 255, 255, 255}) Settings.drawing:addParam("wDraw", "Draw "..SkillW.name.." (W) Range", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("wColor", "Draw "..SkillW.name.." (W) Color", SCRIPT_PARAM_COLOR, {255, 255, 255, 255}) Settings.drawing:addParam("eDraw", "Draw "..SkillE.name.." (E) Range", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("eColor", "Draw "..SkillE.name.." (E) Color", SCRIPT_PARAM_COLOR, {255, 255, 255, 255}) Settings.drawing:addParam("rDraw", "Draw "..SkillR.name.." (R) Range", SCRIPT_PARAM_ONOFF, true) Settings.drawing:addParam("rColor", "Draw "..SkillR.name.." (R) Color", SCRIPT_PARAM_COLOR, {255, 255, 255, 255}) Settings.drawing:addSubMenu("Lag Free Circles", "lfc") Settings.drawing.lfc:addParam("lfc", "Lag Free Circles", SCRIPT_PARAM_ONOFF, false) Settings.drawing.lfc:addParam("CL", "Quality", 4, 75, 75, 2000, 0) Settings.drawing.lfc:addParam("Width", "Width", 4, 1, 1, 10, 0) Settings:addSubMenu("["..myHero.charName.."] - Orbwalking Settings", "Orbwalking") if _G.Reborn_Loaded ~= nil then Settings.Orbwalking:addParam("Info", "Default orbwalker disabled", SCRIPT_PARAM_INFO, "") else NebelwolfisOrbWalkerClass(Settings.Orbwalking) end TargetSelector = TargetSelector(TARGET_LESS_CAST, SkillE.range, DAMAGE_MAGIC, true) TargetSelector.name = "Ahri" Settings:addTS(TargetSelector) end function Variables() SkillQ = { name = "Orb of Deception", range = 840, delay = 0.25, speed = 1600, width = 90, ready = false } SkillW = { name = "Fox-Fire", range = 800, delay = nil, speed = nil, width = nil, ready = false } SkillE = { name = "Charm", range = 975, delay = 0.25, speed = 1500, width = 100, ready = false } SkillR = { name = "Spirit Rush", range = 550, delay = nil, speed = nil, width = nil, ready = false } Ignite = { name = "SummonerDot", range = 600, slot = nil } enemyMinions = minionManager(MINION_ENEMY, SkillQ.range, myHero, MINION_SORT_HEALTH_ASC) jungleMinions = minionManager(MINION_JUNGLE, SkillQ.range, myHero, MINION_SORT_MAXHEALTH_DEC) HPred = HPrediction() if _G.Reborn_Loaded == nil then require("Nebelwolfi's Orb Walker") end JungleMobs = {} JungleFocusMobs = {} if GetGame().map.shortName == "twistedTreeline" then TwistedTreeline = true else TwistedTreeline = false end _G.oldDrawCircle = rawget(_G, 'DrawCircle') _G.DrawCircle = DrawCircle2 end function TrueRange() return myHero.range + GetDistance(myHero, myHero.minBBox) end -- Trees function GetCustomTarget() TargetSelector:update() if _G.MMA_Target and _G.MMA_Target.type == myHero.type then return _G.MMA_Target end --if _G.AutoCarry and _G.AutoCarry.Crosshair and _G.AutoCarry.Attack_Crosshair and _G.AutoCarry.Attack_Crosshair.target and _G.AutoCarry.Attack_Crosshair.target.type == myHero.type then return _G.AutoCarry.Attack_Crosshair.target end return TargetSelector.target end function GetBestLineFarmPosition(range, width, objects) local BestPos local BestHit = 0 for i, object in ipairs(objects) do local EndPos = Vector(myHero.pos) + range * (Vector(object) - Vector(myHero.pos)):normalized() local hit = CountObjectsOnLineSegment(myHero.pos, EndPos, width, objects) if hit > BestHit then BestHit = hit BestPos = Vector(object) if BestHit == #objects then break end end end return BestPos, BestHit end function CountObjectsOnLineSegment(StartPos, EndPos, width, objects) local n = 0 for i, object in ipairs(objects) do local pointSegment, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(StartPos, EndPos, object) if isOnSegment and GetDistanceSqr(pointSegment, object) < width * width then n = n + 1 end end return n end -- Barasia, vadash, viseversa function DrawCircleNextLvl(x, y, z, radius, width, color, chordlength) radius = radius or 300 quality = math.max(8,round(180/math.deg((math.asin((chordlength/(2*radius))))))) quality = 2 * math.pi / quality radius = radius*.92 local points = {} for theta = 0, 2 * math.pi + quality, quality do local c = WorldToScreen(D3DXVECTOR3(x + radius * math.cos(theta), y, z - radius * math.sin(theta))) points[#points + 1] = D3DXVECTOR2(c.x, c.y) end DrawLines2(points, width or 1, color or 4294967295) end function round(num) if num >= 0 then return math.floor(num+.5) else return math.ceil(num-.5) end end function DrawCircle2(x, y, z, radius, color) local vPos1 = Vector(x, y, z) local vPos2 = Vector(cameraPos.x, cameraPos.y, cameraPos.z) local tPos = vPos1 - (vPos1 - vPos2):normalized() * radius local sPos = WorldToScreen(D3DXVECTOR3(tPos.x, tPos.y, tPos.z)) if OnScreen({ x = sPos.x, y = sPos.y }, { x = sPos.x, y = sPos.y }) then DrawCircleNextLvl(x, y, z, radius, Settings.drawing.lfc.Width, color, Settings.drawing.lfc.CL) end end