if myHero.charName ~= 'Caitlyn' then return end
--~~~~~~ General Localizations
local pi, pi2, sin, cos, huge, sqrt, ceil = math.pi, 2*math.pi, math.sin, math.cos, math.huge, math.sqrt, math.floor
local clock = os.clock
local pairs, ipairs = pairs, ipairs
local insert, remove = table.insert, table.remove
local TEAM_ALLY, TEAM_ENEMY
local function Normalize(x,z)
local length = sqrt(x * x + z * z)
return { ['x'] = x / length, ['z'] = z / length, }
end
local function NormalizeX(v1, v2, length)
x, z = v1.x - v2.x, v1.z - v2.z
local nLength = sqrt(x * x + z * z)
return { ['x'] = v2.x + ((x / nLength) * length), ['z'] = v2.z + ((z / nLength) * length)}
end
local function Print(text, isError)
if isError then
print('[PewCaitlyn] '..text..'')
return
end
print('[PewCaitlyn] '..text..'')
end
--~~~~~~End Localizations
AddLoadCallback(function()
if not FileExist(LIB_PATH..'/HPrediction.lua') then
ScriptUpdate(
0,
true,
'raw.githubusercontent.com',
'/BolHTTF/BoL/master/HTTF/Version/HPrediction.version',
'/BolHTTF/BoL/master/HTTF/Common/HPrediction.lua',
LIB_PATH..'/HPrediction.lua',
function() Print('HPrediction Download Complete. Please reload.') end,
function() return end,
function() Print('HPrediction cannot be found, downloading now...') end,
function() Print('There was an error downloading HPrediction.') end
)
return
end
if FileExist(LIB_PATH..'PewPacketLib.lua') then require('PewPacketLib') end
if FileExist(LIB_PATH..'FHPrediction.lua') then require('FHPrediction') end
require 'HPrediction'
local isLoaded, loadTime = false, clock()
AddTickCallback(function()
if _Pewalk and not isLoaded then
TEAM_ALLY, TEAM_ENEMY = myHero.team, 300 - myHero.team
Caitlyn()
isLoaded = true
elseif loadTime + 5 < clock() and not isLoaded then
Print('Pewalk is required!', true)
isLoaded = true
end
end)
end)
class 'Caitlyn'
function Caitlyn:__init()
local version = 3.8
ScriptUpdate(
version,
true,
'raw.githubusercontent.com',
'/PewPewPew2/BoL/master/Versions/PewCaitlyn.version',
'/PewPewPew2/BoL/master/PewCaitlyn.lua',
SCRIPT_PATH.._ENV.FILE_NAME,
function() Print('Update Complete, please reload.') end,
function() Print('Latest version loaded v'..('%.1f'):format(version)..'.') end,
function() Print('Update availabe, please wait..') end,
function() Print('There was an error during update.') end
)
self.OnSpells = {
['Crowstorm'] = function(endPos)
if self.Menu.W.Crowstorm then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = endPos.x, ['z'] = endPos.z, },
['endTime'] = clock() + 1.5,
}
end
end,
['PantheonRJump'] = function(endPos)
if self.Menu.W.Skyfall then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = endPos.x, ['z'] = endPos.z, },
['endTime'] = clock() + 2.5,
}
end
end,
['gate'] = function(endPos)
if self.Menu.W.Gate then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = endPos.x, ['z'] = endPos.z, },
['endTime'] = clock() + 1.5,
}
end
end,
}
self.OnBuff = {
['Channels'] = {
['aatroxpassivedeath'] = true,
['rebirth'] = true,
['bardrstasis'] = true,
['lissandrarself'] = true,
['pantheonesound'] = true,
['PantheonRJump'] = true,
['summonerteleport'] = true,
['zhonyasringshield'] = true,
['galioidolofdurand'] = true,
['missfortunebulletsound'] = true,
['alzaharnethergraspsound'] = true,
['infiniteduresssound'] = true,
['VelkozR'] = true,
['ReapTheWhirlwind'] = true,
['katarinarsound'] = true,
['fearmonger_marker'] = true,
['AbsoluteZero'] = true,
['Meditate'] = true,
['ShenStandUnited'] = true,
},
['Shields'] = {
['vipassivebuff'] = true,
['summonerbarrier'] = true,
['ironstylusbuff'] = true,
['itemseraphsembrace'] = true,
['srturretsecondaryshielde'] = true,
['azireshield'] = true,
['evelynnrshield'] = true,
['jarvanivgoldenaegis'] = true,
['eyeofthestorm'] = true,
['lulufaerieshield'] = true,
['karmasolkimshield'] = true,
['luxprismaticwaveshield'] = true,
['udyrturtleactivation'] = true,
['shenfeint'] = true,
['skarnerexoskeleton'] = true,
['orianaghost'] = true,
['rumbleshieldbuff'] = true,
['threshwshield'] = true,
['dianashield'] = true,
['viktorpowertransfer'] = true,
['rivenfeint'] = true,
['sonawshield'] = true,
['sionwshieldstacks'] = true,
['urgotterrorcapacitoractive2'] = true,
['nautiluspiercinggazeshield'] = true,
['blindmonkwoneshield'] = true,
['shenstandunitedshield'] = true,
['yasuopassivemsshieldon'] = true,
},
['DamageMods'] = {
['ferocioushowl'] = function(source) return 0.3 end,
['garenw'] = function(source) return 0.7 end,
['maokaidrain3defense'] = function(source) return 0.8 end,
['galioidolofdurand'] = function(source) return 0.5 end,
['vladimirhemoplaguedebuff'] = function(source) return 1.12 end,
['gragaswself'] = function(source) return 0.92 - (source:GetSpellData(1).level * 0.02) end,
['meditate'] = function(source) return 0.55 - (source:GetSpellData(1).level * 0.05) end,
['braumshieldbuff'] = function(source) return 0.725 - (source:GetSpellData(2).level * 0.025) end,
},
['CrowdControl'] = { [5] = 'Stun', [11] = 'Snare', [24] = 'Suppresion', [29] = 'KnockUp', },
}
self.OnObject = {
['Cupcake Trap'] = function(o)
if o.team == myHero.team then
self.W.Timers[#self.W.Timers + 1] = {
['obj'] = o,
['endTime'] = clock() + 90,
}
end
end,
['LifeAura.troy'] = function(o)
if self.Menu.W.Revive then
for i, hero in ipairs(self.Enemies) do
if GetDistanceSqr(hero, o) == 0 then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = hero.x, ['z'] = hero.z, },
['endTime'] = clock() + 4,
}
return
end
end
end
end,
['GateMarker_red.troy'] = function(o)
if self.Menu.W.bGate then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = o.x, ['z'] = o.z, },
['endTime'] = clock() + 1.5,
}
return
end
end,
['global_ss_teleport_target_red.troy'] = function(o)
if self.Menu.W.Teleport then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = o.x, ['z'] = o.z, },
['endTime'] = clock() + 1.5,
}
return
end
end,
}
self.W = {
['Timers'] = {},
['Active'] = {},
}
self.Enemies = {}
self.Dashing = {}
self.LastCtrl = 0
self.AllowECast = {x=0,z=0}
self.PreventSpam = 0
self.IsFirstKeyDown = true
self.DT = 0
for i=1, objManager.maxObjects do
local o = objManager:getObject(i)
if o and o.type == 'obj_SpawnPoint' and o.team == myHero.team then
self.SpawnPos = o
break
end
end
for i=1, heroManager.iCount do
local h = heroManager:getHero(i)
if h.team ~= TEAM_ALLY then
self.Enemies[#self.Enemies + 1] = h
end
end
self:CreateMenu()
if FileExist(LIB_PATH..'PewPacketLib.lua') then self.Packets = GetLoseVisionPacketData() end
self.HP = HPrediction()
self.HP_Q = HPSkillshot({type = 'DelayLine', delay = 0.625, range = 1300, width = 180, speed = 2200})
self.HP_E = HPSkillshot({type = 'DelayLine', delay = 0.125, range = 800, width = 140, speed = 1600})
if FHPrediction then
self.FH_Q = {range = 1300,speed = 2200,delay = 0.625,radius = 90,type = SkillShotType.SkillshotMissileLine,}
end
AddTickCallback(function() self:Tick() end)
AddCreateObjCallback(function(o) self:CreateObj(o) end)
AddDrawCallback(function() self:Draw() end)
AddApplyBuffCallback(function(...) self:ApplyBuff(...) end)
AddProcessSpellCallback(function(...) self:ProcessSpell(...) end)
AddCastSpellCallback(function(...) self:CastSpell(...) end)
AddNewPathCallback(function(...) self:NewPath(...) end)
AddMsgCallback(function(...) self:WndMsg(...) end)
if self.Packets then AddRecvPacketCallback2(function(p) self:RecvPacket(p) end) end
end
function Caitlyn:ApplyBuff(source, unit, buff)
if unit and unit.valid and unit.type == 'AIHeroClient' and unit.team == TEAM_ENEMY then
if self.OnBuff.CrowdControl[buff.type] and self.Menu.W.CrowdControl then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = unit.x, ['z'] = unit.z, },
['endTime'] = clock() + (buff.endTime - buff.startTime),
}
end
if self.OnBuff.Channels[buff.name] and self.Menu.W.Channel then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = unit.x, ['z'] = unit.z, },
['endTime'] = clock() + (buff.endTime - buff.startTime),
}
end
end
end
function Caitlyn:AntiGapClose()
for i=#self.Dashing, 1, -1 do
local d = self.Dashing[i]
if d.endTime > clock() then
if d.unit.valid then
local isValid = d.unit.bTargetable and d.unit.bInvulnerable == 0
if self.Menu.E.Dash and self.eReady then
local point, onLine = self:GetLinePoint(d.startPos.x, d.startPos.z, d.endPos.x, d.endPos.z, myHero.x, myHero.z)
local onLine = onLine and GetDistanceSqr(point) < 40000
if onLine or GetDistanceSqr(d.endPos) < 90000 then
if GetDistanceSqr(d.startPos, d.endPos) < GetDistanceSqr(d.startPos, myHero) then
local remainingTime = d.endTime - clock()
local wTime = .125 + (GetDistance(d.endPos) / 1600) + (GetLatency() * .0005)
local moveTime = wTime - remainingTime
if moveTime > 0 and (isValid or (d.unit.charName=='Fizz' and d.speed>750 and d.speed<850)) then
local moveDistance = moveTime * d.unit.ms
if moveDistance < 70 + d.unit.boundingRadius then
self.AllowECast = {x=d.endPos.x, z=d.endPos.z}
CastSpell(_E, d.endPos.x, d.endPos.z)
local wPos = NormalizeX(d.endPos, myHero, 200)
DelayAction(function()
CastSpell(_W, wPos.x, wPos.z)
end, .2)
end
elseif moveTime > -wTime and isValid then
self.AllowECast = {x=d.endPos.x, z=d.endPos.z}
CastSpell(_E, d.endPos.x, d.endPos.z)
local wPos = NormalizeX(d.endPos, myHero, 200)
DelayAction(function()
CastSpell(_W, wPos.x, wPos.z)
end, .2)
end
elseif onLine then
local remainingTime = (GetDistance(d.startPos) - myHero.boundingRadius) / d.speed
if remainingTime > .125 + (GetLatency() * .0005) then
self.AllowECast = {x=d.startPos.x, z=d.startPos.z}
CastSpell(_E, d.startPos.x, d.startPos.z)
local wPos = NormalizeX(d.startPos, myHero, 200)
DelayAction(function()
CastSpell(_W, wPos.x, wPos.z)
end, .2)
end
end
end
end
end
else
table.remove(self.Dashing, i)
end
end
end
function Caitlyn:CalcArmor(target)
local baseArmor = target.armor-target.bonusArmor
return 100 / (100 + (((target.bonusArmor * myHero.bonusArmorPenPercent) + baseArmor) * myHero.armorPenPercent) - ((myHero.lethality * .4) + ((myHero.lethality * .6) * (myHero.level / 18))))
end
function Caitlyn:CastSpell(iSlot,startPos,endPos,target)
if iSlot == _E and not self.Menu.E.NeverBlock then
if ceil(self.AllowECast.x)~=ceil(endPos.x) or ceil(self.AllowECast.z)~=ceil(endPos.z) then
BlockSpell()
end
elseif iSlot == _W then
self.PreventSpam = clock() + 5
end
end
function Caitlyn:CheckDamage()
local qData = myHero:GetSpellData(_Q)
local critChance, totalDamage, qCd, critDamage = myHero.critChance, myHero.totalDamage, qData.cd, 2 --HaveItem(3031) and 2.5 or 2
local aaAttackCount, qAttackCount = (myHero.attackSpeed * 0.625) * (qCd + 1), ((myHero.attackSpeed * 0.625)) * qCd
local function aaDamage(speed)
local passiveChance = speed / ceil(7.13 - (myHero.level/6))
local damageSum = ((speed - passiveChance) * totalDamage) + (passiveChance * (totalDamage * 1.5))
return ((1 - critChance) * damageSum) + (critChance * (damageSum * critDamage))
end
return aaDamage(aaAttackCount) < aaDamage(qAttackCount) + ((qData.level * 40) - 20) + (1.3 * totalDamage)
end
function Caitlyn:CreateMenu()
self.Menu = scriptConfig('PewCaitlyn', 'Caitlyn')
self.Menu:addSubMenu('Piltover Peacemaker', 'Q')
self.Menu.Q:addParam('info', '---Farming---', SCRIPT_PARAM_INFO, '')
self.Menu.Q:addParam('LastHit', 'Use for Last Hits', SCRIPT_PARAM_ONOFF, true)
self.Menu.Q:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.Q:addParam('info', '---Combat---', SCRIPT_PARAM_INFO, '')
self.Menu.Q:addParam('Carry', 'Use in Carry Mode', SCRIPT_PARAM_ONOFF, true)
self.Menu.Q:addParam('Mixed', 'Harass in Mixed Mode', SCRIPT_PARAM_ONOFF, true)
self.Menu.Q:addParam('Clear', 'Harass in Clear Mode', SCRIPT_PARAM_ONOFF, true)
self.Menu.Q:addParam('Method', 'Peacemaker Control Method', SCRIPT_PARAM_LIST, 1, { 'Calculated', 'Toggle', })
self.Menu.Q:addParam('Toggle', 'Manual Control Key', SCRIPT_PARAM_ONKEYTOGGLE, true, string.byte('G'))
local MenuCheck = 0
AddTickCallback(function()
if self.Menu.Q.Method ~= MenuCheck then
for k, v in ipairs(self.Menu.Q._param) do
if v.var == 'Toggle' then
if self.Menu.Q.Method == 1 then
v.pType, v.text, self.Menu.Q.Toggle = 5, 'Internally Calculating Q Usage', ''
else
v.pType, v.text, self.Menu.Q.Toggle = 3, 'Manual Control Key', true
end
end
end
MenuCheck = self.Menu.Q.Method
end
end)
self.Menu.Q:addParam('HitChance2', 'Cast HitChance [3==Highest]', SCRIPT_PARAM_SLICE, 0.2, 0, 2, 2)
self.Menu.Q:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.Q:addParam('info', '---Miscellaneous---', SCRIPT_PARAM_INFO, '')
self.Menu.Q:addParam('Mana', 'Always Save Mana for E', SCRIPT_PARAM_ONOFF, true)
self.Menu.Q:addParam('Draw', 'Draw Peacemaker Range', SCRIPT_PARAM_LIST, 1, { 'Low FPS', 'Normal', 'None', })
self.Menu:addSubMenu('Yordle Snap Trap', 'W')
self.Menu.W:addParam('info', '---Keys---', SCRIPT_PARAM_INFO, '')
_Pewalk.AddMenuHeader('---Keys---')
self.Menu.W:addParam('Line', 'Line Cast', SCRIPT_PARAM_ONKEYDOWN, false, ('Z'):byte())
self.Menu.W:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.W:addParam('info', '---Combat---', SCRIPT_PARAM_INFO, '')
self.Menu.W:addParam('Path', 'Cast on Target Path', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('Channel', 'Trap Channel Spells', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('CrowdControl', 'Trap Crowd Control', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('Revive', 'Trap Revives (GA / Chronoshift)', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('Teleport', 'Trap Teleports', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('Vision', 'Trap on Lose Vision (Grass)', SCRIPT_PARAM_ONOFF, true)
for i=1, heroManager.iCount do
local h = heroManager:getHero(i)
if h and h.team == TEAM_ENEMY then
if h.charName == 'FiddleSticks' then
self.Menu.W:addParam('Crowstorm', 'Trap Crowstorm', SCRIPT_PARAM_ONOFF, true)
elseif h.charName == 'Pantheon' then
self.Menu.W:addParam('Skyfall', 'Trap Grand Skyfall', SCRIPT_PARAM_ONOFF, true)
elseif h.charName == 'TwistedFate' then
self.Menu.W:addParam('Gate', 'Trap Destiny', SCRIPT_PARAM_ONOFF, true)
end
end
end
self.Menu.W:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.W:addParam('info', '---Miscellaneous---', SCRIPT_PARAM_INFO, '')
self.Menu.W:addParam('Mana', 'Always Save Mana for E', SCRIPT_PARAM_ONOFF, true)
self.Menu.W:addParam('Draw', 'Draw Active Trap Timers', SCRIPT_PARAM_ONOFF, true)
self.Menu:addSubMenu('90 Caliber Net', 'E')
self.Menu.E:addParam('info', '---Keys---', SCRIPT_PARAM_INFO, '')
self.Menu.E:addParam('Mouse', 'Net To Mouse', SCRIPT_PARAM_ONKEYDOWN, false, ('E'):byte())
self.Menu.E:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.E:addParam('info', '---Farming---', SCRIPT_PARAM_INFO, '')
self.Menu.E:addParam('LastHit', 'Use for Last Hits', SCRIPT_PARAM_ONOFF, false)
self.Menu.E:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.E:addParam('info', '---Miscellaneous---', SCRIPT_PARAM_INFO, '')
self.Menu.E:addParam('Dash', 'Anti Gap Close', SCRIPT_PARAM_ONOFF, true)
self.Menu.E:addParam('NeverBlock', 'Never block E Casts', SCRIPT_PARAM_ONOFF, false)
self.Menu.E:addParam('Block', 'Block Failed Wall Jumps', SCRIPT_PARAM_ONOFF, true)
self.Menu.E:addParam('MinimumBlock', 'Do Not Block if Will Jump This Far', SCRIPT_PARAM_SLICE, 350, 20, 490)
self.Menu:addSubMenu('Ace in the Hole', 'R')
self.Menu.R:addParam('info', '---Keys---', SCRIPT_PARAM_INFO, '')
self.Menu.R:addParam('Key', 'Kill Key', SCRIPT_PARAM_ONKEYDOWN, false, ('R'):byte())
self.Menu.R:addParam('space', '', SCRIPT_PARAM_INFO, '')
self.Menu.R:addParam('info', '---Miscellaneous---', SCRIPT_PARAM_INFO, '')
self.Menu.R:addParam('CrossHair', 'Draw Can Kill Alert', SCRIPT_PARAM_ONOFF, true)
self.Menu.R:addParam('Line', 'Draw Line to Killable Character', SCRIPT_PARAM_ONOFF, true)
self.Menu.R:addParam('Indicator', 'Draw Health Remaining Indicator', SCRIPT_PARAM_ONOFF, true)
self.Menu.R:addParam('Auto', 'Use Automatically', SCRIPT_PARAM_ONOFF, false)
self.Menu:addParam('Combo', 'W - E - Q Combo', SCRIPT_PARAM_ONKEYDOWN, false, ('T'):byte())
self.Menu:addParam('Prediction2', 'Prediction Selection', SCRIPT_PARAM_LIST, 1, {'HPrediction', FHPrediction and 'FHPrediction' or 'FHPrediction not found!',})
end
function Caitlyn:CreateObj(o)
if o.valid then
if self.OnObject[o.name] then
self.OnObject[o.name](o)
elseif o.name:find('Pantheon') and o.name:find('indicator_red.troy') and self.Menu.W.bSkyfall then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = o.x, ['z'] = o.z, },
['endTime'] = clock() + 1.5,
}
end
end
end
function Caitlyn:WndMsg(m ,k)
if m==257 then
for _, v in pairs(self.Menu.W._param) do
if v.var=='Line' and v.key==k then
if self.DrawLineCast then
self.CastWLine = {Vector(self.DrawLineCast), delay=0, init=clock()+.25, y=self.DrawLineCast.y}
local dist = math.min(GetDistance(self.DrawLineCast, mousePos), 150*myHero:GetSpellData(_W).stacks-150)
for i=150, dist, 150 do
self.CastWLine[#self.CastWLine+1] = NormalizeX(mousePos, self.DrawLineCast, i)
end
self.DrawLineCast = nil
end
self.IsFirstKeyDown=true
end
end
elseif m==256 and self.DrawLineCast==nil and self.wReady and self.IsFirstKeyDown then
for _, v in pairs(self.Menu.W._param) do
if v.var=='Line' and v.key==k then
self.IsFirstKeyDown = false
self.DrawLineCast = Vector(mousePos)
end
end
elseif m==WM_RBUTTONDOWN then
self.DrawLineCast = nil
end
end
function Caitlyn:Draw()
if self.DrawLineCast then
DrawCircle3D(self.DrawLineCast.x,self.DrawLineCast.y,self.DrawLineCast.z,50,2,0xFFFF0000)
local dist = math.min(GetDistance(self.DrawLineCast, mousePos), 150*myHero:GetSpellData(_W).stacks-150)
for i=150, dist, 150 do
local p = NormalizeX(mousePos, self.DrawLineCast, i)
DrawCircle3D(p.x,self.DrawLineCast.y,p.z,50,2,0xFFFF0000)
end
elseif self.CastWLine and self.CastWLine[1] then
for i, p in ipairs(self.CastWLine) do
DrawCircle3D(p.x,self.CastWLine.y,p.z,50,2,0xFF0000FF)
end
if self.CastWLine.delay 100
end
end
else
for i, enemy in ipairs(self.Enemies) do
if _Pewalk.ValidTarget(enemy) then
local Center = GetUnitHPBarPos(enemy)
if Center.x > -100 and Center.x < WINDOW_W+100 and Center.y > -100 and Center.y < WINDOW_H+100 then
local off = GetUnitHPBarOffset(enemy)
local y=Center.y + (off.y * 53) + 2
local xOff = ({['AniviaEgg'] = -0.1,['Darius'] = -0.05,['Renekton'] = -0.05,['Sion'] = -0.05,['Thresh'] = -0.03,})[enemy.charName]
local x = Center.x + ((xOff or 0) * 140) - 66
local rmn = enemy.health - self:RDamage(enemy)
DrawLine(x + ((enemy.health / enemy.maxHealth) * 104),y, x+(((rmn > 0 and rmn or 0) / enemy.maxHealth) * 104),y,9, GetDistance(enemy) < range and 0x78FF7D00 or 0x78FFFFFF)
end
end
end
end
end
end
function Caitlyn:GetLinePoint(ax, ay, bx, by, cx, cy)
local rL = ((cx - ax) * (bx - ax) + (cy - ay) * (by - ay)) / ((bx - ax) ^ 2 + (by - ay) ^ 2)
return { x = ax + rL * (bx - ax), z = ay + rL * (by - ay) }, (rL < 0 and 0 or (rL > 1 and 1 or rL)) == rL
end
function Caitlyn:GetPrediction(unit, hitchance)
if self.Menu.Prediction2==2 then
if FHPrediction then
local CastPos, HitChance = FHPrediction.GetPrediction(self.FH_Q, unit, myHero)
return CastPos and HitChance >= hitchance, CastPos
else
self.Menu.Prediction2 = 1
end
end
local CastPos, HitChance = self.HP:GetPredict(self.HP_Q, unit, myHero)
return CastPos and HitChance >= hitchance, CastPos
end
function Caitlyn:GetUltRange()
return (500 * myHero:GetSpellData(_R).level) + 1500
end
function Caitlyn:MinionPrediction(unit, delay, width, speed, from)
local Waypoints = {{ ['x'] = unit.x, ['z'] = unit.z, }}
local pathPotential = unit.ms * ((GetDistance(from, unit) / speed) + delay)
if unit.hasMovePath then
for i = unit.pathIndex, unit.pathCount do
local p = unit:GetPath(i)
Waypoints[#Waypoints+1] = { ['x'] = p.x, ['z'] = p.z, }
end
else
return Waypoints[1], Waypoints, 2
end
for i = 1, #Waypoints - 1 do
local CurrentDistance = GetDistance(Waypoints[i], Waypoints[i + 1])
if pathPotential < CurrentDistance then
return NormalizeX(Waypoints[i + 1], Waypoints[i], pathPotential), Waypoints, 2
elseif i == (#Waypoints - 1) then
return Waypoints[i + 1], Waypoints, 1
end
pathPotential = pathPotential - CurrentDistance
end
end
function Caitlyn:NewPath(unit,startPos,endPos,isDash,dashSpeed,dashGravity,dashDistance)
if unit.valid and unit.type == 'AIHeroClient' and unit.team~=myHero.team and isDash and GetDistanceSqr(startPos, endPos) > 30625 then
if not self.DashExceptions then
self.DashExceptions = {
Aatrox = function(unit, speed) return speed<100 end,
Alistar = function(unit, speed) return true end,
Ahri = function(unit, speed) return unit:GetSpellData(_R).currentCd > 10 end,
AurelionSol = function(unit, speed) return speed==600 end,
Azir = function(unit, speed) return speed==1700 end,
Ekko = function(unit, speed) return speed>1100 and speed<1200 end,
Fizz = function(unit, speed) return speed>1000 and speed<1150 end,
Gnar = function(unit, speed) return speed>850 and speed<950 and unit:GetSpellData(_E).cd-unit:GetSpellData(_E).currentCd<0.5 end,
Hecarim = function(unit, speed) return true end,
Kalista = function(unit, speed) return speed>700 and speed<900 end,
Leblanc = function(unit, speed) return speed==1600 end,
Quinn = function(unit, speed) return speed==2500 end,
Renekton = function(unit, speed) return speed>1050 and speed<1150 and unit:GetSpellData(_E).cd-unit:GetSpellData(_E).currentCd<0.5 end,
Riven = function(unit, speed) return speed<1150 end,
Yasuo = function(unit, speed) return true end,
}
end
if self.DashExceptions[unit.charName] and self.DashExceptions[unit.charName](unit, dashSpeed) then return end
table.insert(self.Dashing, {
startTime = clock(),
speed = dashSpeed,
startPos = Vector(unit.x, unit.y, unit.z),
endPos = Vector(endPos),
endTime = clock() + (GetDistance(startPos, endPos) / dashSpeed),
range = GetDistanceSqr(startPos, endPos),
unit = unit,
})
self:AntiGapClose()
end
end
function Caitlyn:ProcessSpell(u, s)
if u.valid and u.type == 'AIHeroClient' then
if u.team == TEAM_ENEMY and self.OnSpells[s.name] then
self.OnSpells[s.name](s.endPos)
elseif u.isMe and s.name=='CaitlynYordleTrap' and self.CastWLine and self.CastWLine[1] then
table.remove(self.CastWLine, 1)
end
end
end
function Caitlyn:RDamage(unit)
local baseDmg = ((225 * myHero:GetSpellData(_R).level) + (myHero.addDamage * 2)) * self:CalcArmor(unit)
for _, buff in ipairs(_Pewalk.GetBuffs(unit)) do
if self.OnBuff.DamageMods[buff.name] and buff.endT > clock() + 1 then
baseDmg = baseDmg * self.OnBuff.DamageMods[buff.name]
end
end
return baseDmg --/ baseHP
end
function Caitlyn:RecvPacket(p)
if p.header == self.Packets.Header and self.Menu.W.Vision then
p.pos=self.Packets.Pos
local o = objManager:GetObjectByNetworkId(p:DecodeF())
if o and o.valid and o.type == 'AIHeroClient' and o.team == TEAM_ENEMY then
if o.endPath and not o.dead and o.health / o.maxHealth < 0.4 and IsWallOfGrass(D3DXVECTOR3(o.endPath.x,o.endPath.y,o.endPath.z)) then
self.W.Active[#self.W.Active + 1] = {
['pos'] = { ['x'] = o.endPath.x, ['z'] = o.endPath.z, },
['endTime'] = clock() + 1,
}
end
end
end
end
function Caitlyn:Tick()
self.KillDraw = nil
self.qReady = myHero:CanUseSpell(_Q) == READY
self.wReady = myHero:CanUseSpell(_W) == READY
self.eReady = myHero:CanUseSpell(_E) == READY
self.rReady = myHero:CanUseSpell(_R) == READY
local OM = _Pewalk.GetActiveMode()
if OM.Carry then
if not self.CarryTimer then
self.CarryTimer = clock()
end
else
self.CarryTimer = nil
end
self:AntiGapClose()
if self.Combo then
if self.Combo.Time > clock() then
if self.Combo.UseQ then
local CastPos = self.HP:GetPredict(self.HP_Q, self.Combo.target, Vector(self.Combo.startPos.x, myHero.y, self.Combo.startPos.z))
if CastPos then
CastSpellEx(_Q, CastPos.x, CastPos.z)
self.Combo = self.qReady and self.Combo or nil
end
else
local CastPos = self.HP:GetPredict(self.HP_E, self.Combo.target, Vector(self.Combo.startPos.x, myHero.y, self.Combo.startPos.z))
if CastPos then
self.AllowECast = {x=CastPos.x, z=CastPos.z}
CastSpellEx(_E, CastPos.x, CastPos.z)
self.Combo.UseQ = self.eReady==false
end
end
else
self.Combo = nil
end
return
end
if self.eReady and self.Menu.Combo and not self.Combo then --self.qReady and
local target, shortestDist = nil, huge
for i, e in ipairs(self.Enemies) do
if _Pewalk.ValidTarget(e) then
local dist = GetDistanceSqr(e)
if dist < 640000 then
if not target or shortestDist>dist then
target, shortestDist = e, dist
end
end
end
end
if target then
local bCast, CastPos = self:GetPrediction(target, 0.25)
if CastPos and GetDistanceSqr(CastPos) < 640000 and _Pewalk.GetCollision(target, CastPos, {length=800, width=80, delay=0.125}, myHero) then
self.Combo = {
['Time'] = clock() + 1,
['startPos'] = {['x']=myHero.x, ['z'] = myHero.z,},
['dashPos'] = NormalizeX(CastPos, myHero, -390),
['target'] = target,
}
if myHero.mana > 95 then
CastSpell(_W, CastPos.x, CastPos.z)
end
return
end
end
end
if Evade then return end
if self.qReady and not self.Menu.Combo then
if _Pewalk.CanMove() then
if not self.Menu.Q.Mana or (myHero.mana - ((myHero:GetSpellData(_Q).level * 10) + 40)) > 75 then
local c1 = OM.Carry and self.Menu.Q.Carry and self.CarryTimer and self.CarryTimer + 1 < clock()
local c2 = OM.Mixed and self.Menu.Q.Mixed and not _Pewalk.WaitForMinion()
local c3 = OM.LaneClear and self.Menu.Q.Clear and not _Pewalk.WaitForMinion()
if c1 or c2 or c3 then
local c4 = self.Menu.Q.Method == 1 and self:CheckDamage()
local c5 = self.Menu.Q.Method == 2 and self.Menu.Q.Toggle
if c4 or c5 then
local target = _Pewalk.GetTarget(1300)
if target then
local bCast, castPos = self:GetPrediction(target, self.Menu.Q.HitChance2)
if bCast then
CastSpell(_Q, castPos.x, castPos.z)
return
end
end
end
end
if (OM.Farm or OM.Clear) and self.Menu.Q.LastHit then
local d = function()
local qLvl = myHero:GetSpellData(_Q).level
return (30.15 * qLvl) - 13.4 + ((0.804 + (qLvl * 0.067)) * myHero.totalDamage)
end
local t = _Pewalk.GetSkillFarmTarget(0.625, d, 2200, 1300, false)
if t then
local CastPos = self:MinionPrediction(t, 0.625, 90, 2200, myHero)
if CastPos then
CastSpell(_Q, CastPos.x, CastPos.z)
end
end
end
end
end
end
if self.wReady and myHero.mana - 50 > 75 and self.PreventSpam < clock() then
for i, active in ipairs(self.W.Active) do
if active.endTime > clock() then
if GetDistanceSqr(active.pos) < 640000 then
local cast = true
for k, v in ipairs(self.W.Timers) do
if v.obj.valid and GetDistanceSqr(v.obj, active.pos) < 10000 then
cast = false
end
end
if cast then CastSpell(_W, active.pos.x, active.pos.z) end
end
else
table.remove(self.W.Active, i)
return
end
end
if self.Menu.W.Path and _Pewalk.CanMove() and not _Pewalk.CanAttack() then
local target = _Pewalk.GetTarget(700)
if target and target.hasMovePath then
if GetDistanceSqr(target, target.endPath) > 160000 then
local CastPos = NormalizeX(target.endPath, target, 200)
CastSpell(_W, CastPos.x, CastPos.z)
elseif GetDistanceSqr(myHero, target.endPath) > 10000 then
local CastPos = NormalizeX(target.endPath, target, 200)
CastSpell(_W, CastPos.x, CastPos.z)
end
end
end
end
if self.eReady then
if IsKeyDown(17) then
self.LastCtrl = clock() + 0.15
end
if self.Menu.E.Mouse and self.LastCtrl < clock() then
if self.Menu.E.Block then
local d = Normalize(mousePos.x - myHero.x, mousePos.z - myHero.z)
local bWall = false
for i=30, self.Menu.E.MinimumBlock, 20 do
if IsWall(D3DXVECTOR3(myHero.x + (d.x * i), myHero.y, myHero.z + (d.z * i))) then
bWall = true
break
end
end
if bWall and IsWall(D3DXVECTOR3(myHero.x + (d.x * 400), myHero.y, myHero.z + (d.z * 400))) then
return
end
end
local x, z = mousePos.x - myHero.x, mousePos.z - myHero.z
local nLength = sqrt(x * x + z * z)
local CastPos = {x=myHero.x + ((x / nLength) * (-400)), z=myHero.z + ((z / nLength) * (-400))}
self.AllowECast = {x=CastPos.x, z=CastPos.z}
CastSpell(_E, CastPos.x, CastPos.z)
end
if (OM.Farm or OM.Clear) and self.Menu.E.LastHit then
local d = function() return (50 * myHero:GetSpellData(_E).level) + 30 + (myHero.ap * 0.8) end
local t = _Pewalk.GetSkillFarmTarget(0.125, d, 2000, 1000, true)
if t and GetDistanceSqr(t, self.SpawnPos) > GetDistanceSqr(self.SpawnPos) then
local CastPos = self:MinionPrediction(t, 0.125, 80, 2000, myHero)
if CastPos and _Pewalk.GetCollision(t, CastPos, {length=1000, width=80, delay=0.125}, myHero) then
self.AllowECast = {x=CastPos.x, z=CastPos.z}
CastSpell(_E, CastPos.x, CastPos.z)
end
end
end
end
if self.rReady then
local range = self:GetUltRange()
for i, enemy in ipairs(self.Enemies) do
if _Pewalk.ValidTarget(enemy, range, true) and self:RDamage(enemy) > enemy.health + enemy.shield then
self.KillDraw = enemy
if self.Menu.R.Key or self.Menu.R.Auto then
CastSpell(_R, enemy)
return
end
end
end
end
end
class "ScriptUpdate"
function ScriptUpdate:__init(LocalVersion,UseHttps, Host, VersionPath, ScriptPath, SavePath, CallbackUpdate, CallbackNoUpdate, CallbackNewVersion,CallbackError)
self.LocalVersion = LocalVersion
self.Host = Host
self.VersionPath = '/BoL/TCPUpdater/GetScript'..(UseHttps and '5' or '6')..'.php?script='..self:Base64Encode(self.Host..VersionPath)..'&rand='..math.random(99999999)
self.ScriptPath = '/BoL/TCPUpdater/GetScript'..(UseHttps and '5' or '6')..'.php?script='..self:Base64Encode(self.Host..ScriptPath)..'&rand='..math.random(99999999)
self.SavePath = SavePath
self.CallbackUpdate = CallbackUpdate
self.CallbackNoUpdate = CallbackNoUpdate
self.CallbackNewVersion = CallbackNewVersion
self.CallbackError = CallbackError
AddDrawCallback(function() self:OnDraw() end)
self:CreateSocket(self.VersionPath)
self.DownloadStatus = 'Connect to Server for VersionInfo'
AddTickCallback(function() self:GetOnlineVersion() end)
end
function ScriptUpdate:print(str)
print(''..os.clock()..': '..str)
end
function ScriptUpdate:OnDraw()
if self.DownloadStatus ~= 'Downloading Script (100%)' and self.DownloadStatus ~= 'Downloading VersionInfo (100%)'then
DrawText('Download Status: '..(self.DownloadStatus or 'Unknown'),20,10,50,ARGB(0xFF,0xFF,0xFF,0xFF))
end
end
function ScriptUpdate:CreateSocket(url)
if not self.LuaSocket then
self.LuaSocket = require("socket")
else
self.Socket:close()
self.Socket = nil
self.Size = nil
self.RecvStarted = false
end
self.LuaSocket = require("socket")
self.Socket = self.LuaSocket.tcp()
self.Socket:settimeout(0, 'b')
self.Socket:settimeout(99999999, 't')
self.Socket:connect('sx-bol.eu', 80)
self.Url = url
self.Started = false
self.LastPrint = ""
self.File = ""
end
function ScriptUpdate:Base64Encode(data)
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
function ScriptUpdate:GetOnlineVersion()
if self.GotScriptVersion then return end
self.Receive, self.Status, self.Snipped = self.Socket:receive(1024)
if self.Status == 'timeout' and not self.Started then
self.Started = true
self.Socket:send("GET "..self.Url.." HTTP/1.1\r\nHost: sx-bol.eu\r\n\r\n")
end
if (self.Receive or (#self.Snipped > 0)) and not self.RecvStarted then
self.RecvStarted = true
self.DownloadStatus = 'Downloading VersionInfo (0%)'
end
self.File = self.File .. (self.Receive or self.Snipped)
if self.File:find('') then
if not self.Size then
self.Size = tonumber(self.File:sub(self.File:find('')+6,self.File:find('')-1))
end
if self.File:find('') then
local _,ScriptFind = self.File:find('')
local ScriptEnd = self.File:find('')
if ScriptEnd then ScriptEnd = ScriptEnd - 1 end
local DownloadedSize = self.File:sub(ScriptFind+1,ScriptEnd or -1):len()
self.DownloadStatus = 'Downloading VersionInfo ('..math.round(100/self.Size*DownloadedSize,2)..'%)'
end
end
if self.File:find('') then
self.DownloadStatus = 'Downloading VersionInfo (100%)'
local a,b = self.File:find('\r\n\r\n')
self.File = self.File:sub(a,-1)
self.NewFile = ''
for line,content in ipairs(self.File:split('\n')) do
if content:len() > 5 then
self.NewFile = self.NewFile .. content
end
end
local HeaderEnd, ContentStart = self.File:find('')
local ContentEnd, _ = self.File:find('')
if not ContentStart or not ContentEnd then
if self.CallbackError and type(self.CallbackError) == 'function' then
self.CallbackError()
end
else
self.OnlineVersion = (Base64Decode(self.File:sub(ContentStart + 1,ContentEnd-1)))
self.OnlineVersion = tonumber(self.OnlineVersion)
if self.OnlineVersion > self.LocalVersion then
if self.CallbackNewVersion and type(self.CallbackNewVersion) == 'function' then
self.CallbackNewVersion(self.OnlineVersion,self.LocalVersion)
end
self:CreateSocket(self.ScriptPath)
self.DownloadStatus = 'Connect to Server for ScriptDownload'
AddTickCallback(function() self:DownloadUpdate() end)
else
if self.CallbackNoUpdate and type(self.CallbackNoUpdate) == 'function' then
self.CallbackNoUpdate(self.LocalVersion)
end
end
end
self.GotScriptVersion = true
end
end
function ScriptUpdate:DownloadUpdate()
if self.GotScriptUpdate then return end
self.Receive, self.Status, self.Snipped = self.Socket:receive(1024)
if self.Status == 'timeout' and not self.Started then
self.Started = true
self.Socket:send("GET "..self.Url.." HTTP/1.1\r\nHost: sx-bol.eu\r\n\r\n")
end
if (self.Receive or (#self.Snipped > 0)) and not self.RecvStarted then
self.RecvStarted = true
self.DownloadStatus = 'Downloading Script (0%)'
end
self.File = self.File .. (self.Receive or self.Snipped)
if self.File:find('') then
if not self.Size then
self.Size = tonumber(self.File:sub(self.File:find('')+6,self.File:find('')-1))
end
if self.File:find('') then
local _,ScriptFind = self.File:find('')
local ScriptEnd = self.File:find('')
if ScriptEnd then ScriptEnd = ScriptEnd - 1 end
local DownloadedSize = self.File:sub(ScriptFind+1,ScriptEnd or -1):len()
self.DownloadStatus = 'Downloading Script ('..math.round(100/self.Size*DownloadedSize,2)..'%)'
end
end
if self.File:find('') then
self.DownloadStatus = 'Downloading Script (100%)'
local a,b = self.File:find('\r\n\r\n')
self.File = self.File:sub(a,-1)
self.NewFile = ''
for line,content in ipairs(self.File:split('\n')) do
if content:len() > 5 then
self.NewFile = self.NewFile .. content
end
end
local HeaderEnd, ContentStart = self.NewFile:find('')
local ContentEnd, _ = self.NewFile:find('')
if not ContentStart or not ContentEnd then
if self.CallbackError and type(self.CallbackError) == 'function' then
self.CallbackError()
end
else
local newf = self.NewFile:sub(ContentStart+1,ContentEnd-1)
local newf = newf:gsub('\r','')
if newf:len() ~= self.Size then
if self.CallbackError and type(self.CallbackError) == 'function' then
self.CallbackError()
end
return
end
local newf = Base64Decode(newf)
if type(load(newf)) ~= 'function' then
if self.CallbackError and type(self.CallbackError) == 'function' then
self.CallbackError()
end
else
local f = io.open(self.SavePath,"w+b")
f:write(newf)
f:close()
if self.CallbackUpdate and type(self.CallbackUpdate) == 'function' then
self.CallbackUpdate(self.OnlineVersion,self.LocalVersion)
end
end
end
self.GotScriptUpdate = true
end
end