local version = "1.1301"
local AUTOUPDATE = true
local UPDATE_HOST = "raw.github.com"
local UPDATE_PATH = "/Hellsing/BoL/master/common/SOW.lua".."?rand="..math.random(1,10000)
local UPDATE_FILE_PATH = LIB_PATH.."SOW.lua"
local UPDATE_URL = "https://"..UPDATE_HOST..UPDATE_PATH
function _AutoupdaterMsg(msg) print("SOW: "..msg..".") end
if AUTOUPDATE then
local ServerData = GetWebResult(UPDATE_HOST, "/Hellsing/BoL/master/version/SOW.version")
if ServerData then
ServerVersion = type(tonumber(ServerData)) == "number" and tonumber(ServerData) or nil
if ServerVersion then
if tonumber(version) < ServerVersion then
_AutoupdaterMsg("New version available"..ServerVersion)
_AutoupdaterMsg("Updating, please don't press F9")
DelayAction(function() DownloadFile(UPDATE_URL, UPDATE_FILE_PATH, function () _AutoupdaterMsg("Successfully updated. ("..version.." => "..ServerVersion.."), press F9 twice to load the updated version.") end) end, 3)
else
_AutoupdaterMsg("You have got the latest version ("..ServerVersion..")")
end
end
else
_AutoupdaterMsg("Error downloading version info")
end
end
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
class "SOW"
function SOW:__init(VP)
_G.SOWLoaded = true
self.ProjectileSpeed = myHero.range > 300 and VP:GetProjectileSpeed(myHero) or math.huge
self.BaseWindupTime = 3
self.BaseAnimationTime = 0.65
self.DataUpdated = false
self.VP = VP
--Callbacks
self.AfterAttackCallbacks = {}
self.OnAttackCallbacks = {}
self.BeforeAttackCallbacks = {}
self.AttackTable =
{
["Ashes Q"] = "frostarrow",
}
self.NoAttackTable =
{
["Shyvana1"] = "shyvanadoubleattackdragon",
["Shyvana2"] = "ShyvanaDoubleAttack",
["Wukong"] = "MonkeyKingDoubleAttack",
}
self.AttackResetTable =
{
["vayne"] = _Q,
["darius"] = _W,
["fiora"] = _E,
["gangplank"] = _Q,
["jax"] = _W,
["leona"] = _Q,
["mordekaiser"] = _Q,
["nasus"] = _Q,
["nautilus"] = _W,
["nidalee"] = _Q,
["poppy"] = _Q,
["renekton"] = _W,
["rengar"] = _Q,
["shyvana"] = _Q,
["sivir"] = _W,
["talon"] = _Q,
["trundle"] = _Q,
["vi"] = _E,
["volibear"] = _Q,
["xinzhao"] = _Q,
["monkeyking"] = _Q,
["yorick"] = _Q,
["cassiopeia"] = _E,
["garen"] = _Q,
["khazix"] = _Q,
["gnar"] = _E
}
self.LastAttack = 0
self.EnemyMinions = minionManager(MINION_ENEMY, 2000, myHero, MINION_SORT_MAXHEALTH_ASC)
self.JungleMinions = minionManager(MINION_JUNGLE, 2000, myHero, MINION_SORT_MAXHEALTH_DEC)
self.OtherMinions = minionManager(MINION_OTHER, 2000, myHero, MINION_SORT_HEALTH_ASC)
GetSave("SOW").FarmDelay = GetSave("SOW").FarmDelay and GetSave("SOW").FarmDelay or 0
GetSave("SOW").ExtraWindUpTime = GetSave("SOW").ExtraWindUpTime and GetSave("SOW").ExtraWindUpTime or 50
GetSave("SOW").Mode3 = GetSave("SOW").Mode3 and GetSave("SOW").Mode3 or string.byte("X")
GetSave("SOW").Mode2 = GetSave("SOW").Mode2 and GetSave("SOW").Mode2 or string.byte("V")
GetSave("SOW").Mode1 = GetSave("SOW").Mode1 and GetSave("SOW").Mode1 or string.byte("C")
GetSave("SOW").Mode0 = GetSave("SOW").Mode0 and GetSave("SOW").Mode0 or 32
self.Attacks = true
self.Move = true
self.mode = -1
self.checkcancel = 0
AddProcessSpellCallback(function(unit, spell) self:OnProcessSpell(unit, spell) end)
end
function SOW:LoadToMenu(m, STS)
if not m then
self.Menu = scriptConfig("Simple OrbWalker", "SOW")
else
self.Menu = m
end
if STS then
self.STS = STS
self.STS.VP = self.VP
end
self.Menu:addParam("Enabled", "Enabled", SCRIPT_PARAM_ONOFF, true)
self.Menu:addParam("FarmDelay", "Farm Delay", SCRIPT_PARAM_SLICE, -150, 0, 150)
self.Menu:addParam("ExtraWindUpTime", "Extra WindUp Time", SCRIPT_PARAM_SLICE, -150, 0, 150)
self.Menu.FarmDelay = GetSave("SOW").FarmDelay
self.Menu.ExtraWindUpTime = GetSave("SOW").ExtraWindUpTime
self.Menu:addParam("Attack", "Attack", SCRIPT_PARAM_LIST, 2, { "Only Farming", "Farming + Carry mode"})
self.Menu:addParam("Mode", "Orbwalking mode", SCRIPT_PARAM_LIST, 1, { "To mouse", "To target"})
self.Menu:addParam("Hotkeys", "", SCRIPT_PARAM_INFO, "")
self.Menu:addParam("Mode3", "Last hit!", SCRIPT_PARAM_ONKEYDOWN, false, string.byte("X"))
self.Mode3ParamID = #self.Menu._param
self.Menu:addParam("Mode1", "Mixed Mode!", SCRIPT_PARAM_ONKEYDOWN, false, string.byte("C"))
self.Mode1ParamID = #self.Menu._param
self.Menu:addParam("Mode2", "Laneclear!", SCRIPT_PARAM_ONKEYDOWN, false, string.byte("V"))
self.Mode2ParamID = #self.Menu._param
self.Menu:addParam("Mode0", "Carry me!", SCRIPT_PARAM_ONKEYDOWN, false, 32)
self.Mode0ParamID = #self.Menu._param
self.Menu._param[self.Mode3ParamID].key = GetSave("SOW").Mode3
self.Menu._param[self.Mode2ParamID].key = GetSave("SOW").Mode2
self.Menu._param[self.Mode1ParamID].key = GetSave("SOW").Mode1
self.Menu._param[self.Mode0ParamID].key = GetSave("SOW").Mode0
AddTickCallback(function() self:OnTick() end)
AddTickCallback(function() self:CheckConfig() end)
end
function SOW:CheckConfig()
GetSave("SOW").FarmDelay = self.Menu.FarmDelay
GetSave("SOW").ExtraWindUpTime = self.Menu.ExtraWindUpTime
GetSave("SOW").Mode3 = self.Menu._param[self.Mode3ParamID].key
GetSave("SOW").Mode2 = self.Menu._param[self.Mode2ParamID].key
GetSave("SOW").Mode1 = self.Menu._param[self.Mode1ParamID].key
GetSave("SOW").Mode0 = self.Menu._param[self.Mode0ParamID].key
end
function SOW:DisableAttacks()
self.Attacks = false
end
function SOW:EnableAttacks()
self.Attacks = true
end
function SOW:ForceTarget(target)
self.forcetarget = target
end
function SOW:GetTime()
return os.clock()
end
function SOW:MyRange(target)
local myRange = myHero.range + self.VP:GetHitBox(myHero)
if target and ValidTarget(target) then
myRange = myRange + self.VP:GetHitBox(target)
end
return myRange - 20
end
function SOW:InRange(target)
local MyRange = self:MyRange(target)
if target and GetDistanceSqr(target.visionPos, myHero.visionPos) <= MyRange * MyRange then
return true
end
end
function SOW:ValidTarget(target)
if target and target.type and (target.type == "obj_BarracksDampener" or target.type == "obj_HQ") then
return false
end
return ValidTarget(target) and self:InRange(target)
end
function SOW:Attack(target)
self.LastAttack = self:GetTime() + self:Latency()
myHero:Attack(target)
end
function SOW:WindUpTime(exact)
return (1 / (myHero.attackSpeed * self.BaseWindupTime)) + (exact and 0 or GetSave("SOW").ExtraWindUpTime / 1000)
end
function SOW:AnimationTime()
return (1 / (myHero.attackSpeed * self.BaseAnimationTime))
end
function SOW:Latency()
return GetLatency() / 2000
end
function SOW:CanAttack()
if self.LastAttack <= self:GetTime() then
return (self:GetTime() + self:Latency() > self.LastAttack + self:AnimationTime())
end
return false
end
function SOW:CanMove()
if self.LastAttack <= self:GetTime() then
return ((self:GetTime() + self:Latency() > self.LastAttack + self:WindUpTime()) or self.ParticleCreated) and not _G.evade
end
end
function SOW:BeforeAttack(target)
local result = false
for i, cb in ipairs(self.BeforeAttackCallbacks) do
local ri = cb(target, self.mode)
if ri then
result = true
end
end
return result
end
function SOW:RegisterBeforeAttackCallback(f)
table.insert(self.BeforeAttackCallbacks, f)
end
function SOW:OnAttack(target)
for i, cb in ipairs(self.OnAttackCallbacks) do
cb(target, self.mode)
end
end
function SOW:RegisterOnAttackCallback(f)
table.insert(self.OnAttackCallbacks, f)
end
function SOW:AfterAttack(target)
for i, cb in ipairs(self.AfterAttackCallbacks) do
cb(target, self.mode)
end
end
function SOW:RegisterAfterAttackCallback(f)
table.insert(self.AfterAttackCallbacks, f)
end
function SOW:MoveTo(x, y)
myHero:MoveTo(x, y)
end
function SOW:OrbWalk(target, point)
point = point or self.forceorbwalkpos
if self.Attacks and self:CanAttack() and self:ValidTarget(target) and not self:BeforeAttack(target) then
self:Attack(target)
elseif self:CanMove() and self.Move then
if not point then
local OBTarget = GetTarget() or target
if self.Menu.Mode == 1 or not OBTarget then
local Mv = Vector(myHero) + 400 * (Vector(mousePos) - Vector(myHero)):normalized()
self:MoveTo(Mv.x, Mv.z)
elseif GetDistanceSqr(OBTarget) > 100*100 + math.pow(self.VP:GetHitBox(OBTarget), 2) then
local point = self.VP:GetPredictedPos(OBTarget, 0, 2*myHero.ms, myHero, false)
if GetDistanceSqr(point) < 100*100 + math.pow(self.VP:GetHitBox(OBTarget), 2) then
point = Vector(Vector(myHero) - point):normalized() * 50
end
self:MoveTo(point.x, point.z)
end
else
self:MoveTo(point.x, point.z)
end
end
end
function SOW:IsAttack(SpellName)
return (SpellName:lower():find("attack") or table.contains(self.AttackTable, SpellName:lower())) and not table.contains(self.NoAttackTable, SpellName:lower())
end
function SOW:IsAAReset(SpellName)
local SpellID
if SpellName:lower() == myHero:GetSpellData(_Q).name:lower() then
SpellID = _Q
elseif SpellName:lower() == myHero:GetSpellData(_W).name:lower() then
SpellID = _W
elseif SpellName:lower() == myHero:GetSpellData(_E).name:lower() then
SpellID = _E
elseif SpellName:lower() == myHero:GetSpellData(_R).name:lower() then
SpellID = _R
end
if SpellID then
return self.AttackResetTable[myHero.charName:lower()] == SpellID
end
return false
end
function SOW:OnProcessSpell(unit, spell)
if unit.isMe and self:IsAttack(spell.name) then
if self.debugdps then
DPS = DPS and DPS or 0
print("DPS: "..(1000/(self:GetTime()- DPS)).." "..(1000/(self:AnimationTime())))
DPS = self:GetTime()
end
if not self.DataUpdated and not spell.name:lower():find("card") then
self.BaseAnimationTime = 1 / (spell.animationTime * myHero.attackSpeed)
self.BaseWindupTime = 1 / (spell.windUpTime * myHero.attackSpeed)
if self.debug then
print("Basic Attacks data updated: ")
print("BaseWindupTime: "..self.BaseWindupTime.."")
print("BaseAnimationTime: "..self.BaseAnimationTime.."")
print("ProjectileSpeed: "..self.ProjectileSpeed.."")
end
self.DataUpdated = true
end
self.LastAttack = self:GetTime() - self:Latency()
self.checking = true
self.LastAttackCancelled = false
self:OnAttack(spell.target)
self.checkcancel = self:GetTime()
DelayAction(function(t) self:AfterAttack(t) end, self:WindUpTime() - self:Latency(), {spell.target})
elseif unit.isMe and self:IsAAReset(spell.name) then
DelayAction(function() self:resetAA() end, 0.25)
end
end
function SOW:resetAA()
self.LastAttack = 0
end
--TODO: Change this.
function SOW:BonusDamage(minion)
local AD = myHero:CalcDamage(minion, myHero.totalDamage)
local BONUS = 0
if myHero.charName == 'Vayne' then
if myHero:GetSpellData(_Q).level > 0 and myHero:CanUseSpell(_Q) == SUPRESSED then
BONUS = BONUS + myHero:CalcDamage(minion, ((0.05 * myHero:GetSpellData(_Q).level) + 0.25 ) * myHero.totalDamage)
end
if not VayneCBAdded then
VayneCBAdded = true
function VayneParticle(obj)
if GetDistance(obj) < 1000 and obj.name:lower():find("vayne_w_ring2.troy") then
VayneWParticle = obj
end
end
AddCreateObjCallback(VayneParticle)
end
if VayneWParticle and VayneWParticle.valid and GetDistance(VayneWParticle, minion) < 10 then
BONUS = BONUS + 10 + 10 * myHero:GetSpellData(_W).level + (0.03 + (0.01 * myHero:GetSpellData(_W).level)) * minion.maxHealth
end
elseif myHero.charName == 'Teemo' and myHero:GetSpellData(_E).level > 0 then
BONUS = BONUS + myHero:CalcMagicDamage(minion, (myHero:GetSpellData(_E).level * 10) + (myHero.ap * 0.3) )
elseif myHero.charName == 'Corki' then
BONUS = BONUS + myHero.totalDamage/10
elseif myHero.charName == 'MissFortune' and myHero:GetSpellData(_W).level > 0 then
BONUS = BONUS + myHero:CalcMagicDamage(minion, (4 + 2 * myHero:GetSpellData(_W).level) + (myHero.ap/20))
elseif myHero.charName == 'Varus' and myHero:GetSpellData(_W).level > 0 then
BONUS = BONUS + (6 + (myHero:GetSpellData(_W).level * 4) + (myHero.ap * 0.25))
elseif myHero.charName == 'Caitlyn' then
if not CallbackCaitlynAdded then
function CaitlynParticle(obj)
if GetDistance(obj) < 100 and obj.name:lower():find("caitlyn_headshot_rdy") then
HeadShotParticle = obj
end
end
AddCreateObjCallback(CaitlynParticle)
CallbackCaitlynAdded = true
end
if HeadShotParticle and HeadShotParticle.valid then
BONUS = BONUS + AD * 1.5
end
elseif myHero.charName == 'Orianna' then
BONUS = BONUS + myHero:CalcMagicDamage(minion, 10 + 8 * ((myHero.level - 1) % 3))
elseif myHero.charName == 'TwistedFate' then
if not TFCallbackAdded then
function TFParticle(obj)
if GetDistance(obj) < 100 and obj.name:lower():find("cardmaster_stackready.troy") then
TFEParticle = obj
elseif GetDistance(obj) < 100 and obj.name:lower():find("card_blue.troy") then
TFWParticle = obj
end
end
AddCreateObjCallback(TFParticle)
TFCallbackAdded = true
end
if TFEParticle and TFEParticle.valid then
BONUS = BONUS + myHero:CalcMagicDamage(minion, myHero:GetSpellData(_E).level * 15 + 40 + 0.5 * myHero.ap)
end
if TFWParticle and TFWParticle.valid then
BONUS = BONUS + math.max(myHero:CalcMagicDamage(minion, myHero:GetSpellData(_W).level * 20 + 20 + 0.5 * myHero.ap) - 40, 0)
end
elseif myHero.charName == 'Draven' then
if not CallbackDravenAdded then
function DravenParticle(obj)
if GetDistance(obj) < 100 and obj.name:lower():find("draven_q_buf") then
DravenParticleo = obj
end
end
AddCreateObjCallback(DravenParticle)
CallbackDravenAdded = true
end
if DravenParticleo and DravenParticleo.valid then
BONUS = BONUS + AD * (0.3 + (0.10 * myHero:GetSpellData(_Q).level))
end
elseif myHero.charName == 'Nasus' and VIP_USER then
if myHero:GetSpellData(_Q).level > 0 and myHero:CanUseSpell(_Q) == SUPRESSED then
local Qdamage = {30, 50, 70, 90, 110}
NasusQStacks = NasusQStacks or 0
BONUS = BONUS + myHero:CalcDamage(minion, 10 + 20 * (myHero:GetSpellData(_Q).level) + NasusQStacks)
if not RecvPacketNasusAdded then
function NasusOnRecvPacket(p)
if p.header == 0xFE and p.size == 0xC then
p.pos = 1
pNetworkID = p:DecodeF()
unk01 = p:Decode2()
unk02 = p:Decode1()
stack = p:Decode4()
if pNetworkID == myHero.networkID then
NasusQStacks = stack
end
end
end
RecvPacketNasusAdded = true
AddRecvPacketCallback(NasusOnRecvPacket)
end
end
elseif myHero.charName == "Ziggs" then
if not CallbackZiggsAdded then
function ZiggsParticle(obj)
if GetDistance(obj) < 100 and obj.name:lower():find("ziggspassive") then
ZiggsParticleObj = obj
end
end
AddCreateObjCallback(ZiggsParticle)
CallbackZiggsAdded = true
end
if ZiggsParticleObj and ZiggsParticleObj.valid then
local base = {20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 100, 112, 124, 136, 148, 160}
BONUS = BONUS + myHero:CalcMagicDamage(minion, base[myHero.level] + (0.25 + 0.05 * (myHero.level % 7)) * myHero.ap)
end
end
return BONUS
end
function SOW:KillableMinion()
local result
for i, minion in ipairs(self.EnemyMinions.objects) do
local time = self:WindUpTime(true) + GetDistance(minion.visionPos, myHero.visionPos) / self.ProjectileSpeed - 0.07
local PredictedHealth = self.VP:GetPredictedHealth(minion, time, GetSave("SOW").FarmDelay / 1000)
if self:ValidTarget(minion) and PredictedHealth < self.VP:CalcDamageOfAttack(myHero, minion, {name = "Basic"}, 0) + self:BonusDamage(minion) and PredictedHealth > -40 then
result = minion
break
end
end
return result
end
function SOW:ShouldWait()
for i, minion in ipairs(self.EnemyMinions.objects) do
local time = self:AnimationTime() + GetDistance(minion.visionPos, myHero.visionPos) / self.ProjectileSpeed - 0.07
if self:ValidTarget(minion) and self.VP:GetPredictedHealth2(minion, time * 2) < (self.VP:CalcDamageOfAttack(myHero, minion, {name = "Basic"}, 0) + self:BonusDamage(minion)) then
return true
end
end
end
function SOW:ValidStuff()
local result = self:GetTarget()
if result then
return result
end
for i, minion in ipairs(self.EnemyMinions.objects) do
local time = self:AnimationTime() + GetDistance(minion.visionPos, myHero.visionPos) / self.ProjectileSpeed - 0.07
local pdamage2 = minion.health - self.VP:GetPredictedHealth(minion, time, GetSave("SOW").FarmDelay / 1000)
local pdamage = self.VP:GetPredictedHealth2(minion, time * 2)
if self:ValidTarget(minion) and ((pdamage) > 2*self.VP:CalcDamageOfAttack(myHero, minion, {name = "Basic"}, 0) + self:BonusDamage(minion) or pdamage2 == 0) then
return minion
end
end
for i, minion in ipairs(self.JungleMinions.objects) do
if self:ValidTarget(minion) then
return minion
end
end
for i, minion in ipairs(self.OtherMinions.objects) do
if self:ValidTarget(minion) then
return minion
end
end
end
function SOW:GetTarget(OnlyChampions)
local result
local healthRatio
if self:ValidTarget(self.forcetarget) then
return self.forcetarget
elseif self.forcetarget ~= nil then
return nil
end
if (not self.STS or not OnlyChampions) and self:ValidTarget(GetTarget()) and (GetTarget().type == myHero.type or (not OnlyChampions)) then
return GetTarget()
end
if self.STS then
local oldhitboxmode = self.STS.hitboxmode
self.STS.hitboxmode = true
result = self.STS:GetTarget(myHero.range)
self.STS.hitboxmode = oldhitboxmode
return result
end
for i, champion in ipairs(GetEnemyHeroes()) do
local hr = champion.health / myHero:CalcDamage(champion, 200)
if self:ValidTarget(champion) and ((healthRatio == nil) or hr < healthRatio) then
result = champion
healthRatio = hr
end
end
return result
end
function SOW:Farm(mode, point)
if mode == 1 then
self.EnemyMinions:update()
local target = self:KillableMinion() or self:GetTarget()
self:OrbWalk(target, point)
self.mode = 1
elseif mode == 2 then
self.EnemyMinions:update()
self.OtherMinions:update()
self.JungleMinions:update()
local target = self:KillableMinion()
if target then
self:OrbWalk(target, point)
elseif not self:ShouldWait() then
if self:ValidTarget(self.lasttarget) then
target = self.lasttarget
else
target = self:ValidStuff()
end
self.lasttarget = target
self:OrbWalk(target, point)
else
self:OrbWalk(nil, point)
end
self.mode = 2
elseif mode == 3 then
self.EnemyMinions:update()
local target = self:KillableMinion()
self:OrbWalk(target, point)
self.mode = 3
end
end
function SOW:OnTick()
if not self.Menu.Enabled then return end
if self.Menu.Mode0 then
local target = self:GetTarget(true)
if self.Menu.Attack == 2 then
self:OrbWalk(target)
else
self:OrbWalk()
end
self.mode = 0
elseif self.Menu.Mode1 then
self:Farm(1)
elseif self.Menu.Mode2 then
self:Farm(2)
elseif self.Menu.Mode3 then
self:Farm(3)
else
self.mode = -1
end
end
function SOW:DrawAARange(width, color)
local p = WorldToScreen(D3DXVECTOR3(myHero.x, myHero.y, myHero.z))
if OnScreen(p.x, p.y) then
DrawCircle3D(myHero.x, myHero.y, myHero.z, self:MyRange() + 25, width or 1, color or ARGB(255, 255, 0, 0))
end
end