local version = 2.979 local TESTVERSION = false local AUTO_UPDATE = true local function AutoupdaterMsg(msg) print("VPrediction: "..msg..".") end class "VPredLibUpdate" function VPredLibUpdate:__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 VPredLibUpdate:print(str) print(''..clock()..': '..str) end function VPredLibUpdate:OnDraw() if self.DownloadStatus ~= 'Downloading Script (100%)' and self.DownloadStatus ~= 'Downloading VersionInfo (100%)'then DrawText('Download Status: '..(self.DownloadStatus or 'Unknown'),50,10,50,ARGB(0xFF,0xFF,0xFF,0xFF)) end end function VPredLibUpdate: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 VPredLibUpdate: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 VPredLibUpdate: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 or 0) > 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 VPredLibUpdate:DownloadUpdate() if self.GotVPredLibUpdate 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.GotVPredLibUpdate = true end end function VPredUpdate() local ToUpdate = {} ToUpdate.Version = version ToUpdate.UseHttps = true ToUpdate.Host = "raw.githubusercontent.com" ToUpdate.VersionPath = "/SidaBoL/Scripts/master/Common/VPrediction.version" ToUpdate.ScriptPath = "/SidaBoL/Scripts/master/Common/VPrediction.lua" ToUpdate.SavePath = LIB_PATH.."VPrediction.lua" ToUpdate.CallbackUpdate = function(NewVersion,OldVersion) AutoupdaterMsg("VPrediction succesfully updated! Restart to use new version.") end ToUpdate.CallbackNoUpdate = function(OldVersion) AutoupdaterMsg(" v"..version.." loaded") end ToUpdate.CallbackNewVersion = function(NewVersion) AutoupdaterMsg("New version found. Downloading now.") end ToUpdate.CallbackError = function(NewVersion) AutoupdaterMsg("Error updating your VPrediction download it manually.") end VPredLibUpdate(ToUpdate.Version,ToUpdate.UseHttps, ToUpdate.Host, ToUpdate.VersionPath, ToUpdate.ScriptPath, ToUpdate.SavePath, ToUpdate.CallbackUpdate,ToUpdate.CallbackNoUpdate, ToUpdate.CallbackNewVersion,ToUpdate.CallbackError) end if AUTO_UPDATE then VPredUpdate() end --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- local minionTar = {} --[[ local canPackets = VIP_USER and GetGameVersion and GetGameVersion():sub(1,4) == "5.22" local lshift, rshift, band, bxor, DwordToFloat, missileTarget = bit32.lshift, bit32.rshift, bit32.band, bit32.bxor, DwordToFloat, {} if canPackets then AddLoadCallback(function() L5_122() end) --Credits to PewPewPew and Redprince class 'L5_122' function L5_122:__init() self.Bytes = {[0x01] = 0x39,[0x02] = 0x38,[0x03] = 0x36,[0x04] = 0xB7,[0x05] = 0xB9,[0x06] = 0xB8,[0x07] = 0xB6,[0x08] = 0xF7,[0x09] = 0xF9,[0x0A] = 0xF8,[0x0B] = 0xF6,[0x0C] = 0x77,[0x0D] = 0x79,[0x0E] = 0x78,[0x0F] = 0x76,[0x10] = 0x57,[0x11] = 0x59,[0x12] = 0x58,[0x13] = 0x56,[0x14] = 0xD7,[0x15] = 0xD9,[0x16] = 0xD8,[0x17] = 0xD6,[0x18] = 0x17,[0x19] = 0x19,[0x1A] = 0x18,[0x1B] = 0x16,[0x1C] = 0x97,[0x1D] = 0x99,[0x1E] = 0x98,[0x1F] = 0x96,[0x20] = 0x67,[0x21] = 0x69,[0x22] = 0x68,[0x23] = 0x66,[0x24] = 0xE7,[0x25] = 0xE9,[0x26] = 0xE8,[0x27] = 0xE6,[0x28] = 0x27,[0x29] = 0x29,[0x2A] = 0x28,[0x2B] = 0x26,[0x2C] = 0xA7,[0x2D] = 0xA9,[0x2E] = 0xA8,[0x2F] = 0xA6,[0x30] = 0x4B,[0x31] = 0x4D,[0x32] = 0x4C,[0x33] = 0x4A,[0x34] = 0xCB,[0x35] = 0xCD,[0x36] = 0xCC,[0x37] = 0xCA,[0x38] = 0x0B,[0x39] = 0x0D,[0x3A] = 0x0C,[0x3B] = 0x0A,[0x3C] = 0x8B,[0x3D] = 0x8D,[0x3E] = 0x8C,[0x3F] = 0x8A,[0x40] = 0x30,[0x41] = 0x2E,[0x42] = 0x31,[0x43] = 0x2F,[0x44] = 0xB0,[0x45] = 0xAE,[0x46] = 0xB1,[0x47] = 0xAF,[0x48] = 0xF0,[0x49] = 0xEE,[0x4A] = 0xF1,[0x4B] = 0xEF,[0x4C] = 0x70,[0x4D] = 0x6E,[0x4E] = 0x71,[0x4F] = 0x6F,[0x50] = 0x50,[0x51] = 0x4E,[0x52] = 0x51,[0x53] = 0x4F,[0x54] = 0xD0,[0x55] = 0xCE,[0x56] = 0xD1,[0x57] = 0xCF,[0x58] = 0x10,[0x59] = 0x0E,[0x5A] = 0x11,[0x5B] = 0x0F,[0x5C] = 0x90,[0x5D] = 0x8E,[0x5E] = 0x91,[0x5F] = 0x8F,[0x60] = 0x60,[0x61] = 0x5E,[0x62] = 0x61,[0x63] = 0x5F,[0x64] = 0xE0,[0x65] = 0xDE,[0x66] = 0xE1,[0x67] = 0xDF,[0x68] = 0x20,[0x69] = 0x1E,[0x6A] = 0x21,[0x6B] = 0x1F,[0x6C] = 0xA0,[0x6D] = 0x9E,[0x6E] = 0xA1,[0x6F] = 0x9F,[0x70] = 0x44,[0x71] = 0x42,[0x72] = 0x45,[0x73] = 0x43,[0x74] = 0xC4,[0x75] = 0xC2,[0x76] = 0xC5,[0x77] = 0xC3,[0x78] = 0x04,[0x79] = 0x02,[0x7A] = 0x05,[0x7B] = 0x03,[0x7C] = 0x84,[0x7D] = 0x82,[0x7E] = 0x85,[0x7F] = 0x83,[0x80] = 0x3B,[0x81] = 0x3D,[0x82] = 0x3C,[0x83] = 0x3A,[0x84] = 0xBB,[0x85] = 0xBD,[0x86] = 0xBC,[0x87] = 0xBA,[0x88] = 0xFB,[0x89] = 0xFD,[0x8A] = 0xFC,[0x8B] = 0xFA,[0x8C] = 0x7B,[0x8D] = 0x7D,[0x8E] = 0x7C,[0x8F] = 0x7A,[0x90] = 0x5B,[0x91] = 0x5D,[0x92] = 0x5C,[0x93] = 0x5A,[0x94] = 0xDB,[0x95] = 0xDD,[0x96] = 0xDC,[0x97] = 0xDA,[0x98] = 0x1B,[0x99] = 0x1D,[0x9A] = 0x1C,[0x9B] = 0x1A,[0x9C] = 0x9B,[0x9D] = 0x9D,[0x9E] = 0x9C,[0x9F] = 0x9A,[0xA0] = 0x6B,[0xA1] = 0x6D,[0xA2] = 0x6C,[0xA3] = 0x6A,[0xA4] = 0xEB,[0xA5] = 0xED,[0xA6] = 0xEC,[0xA7] = 0xEA,[0xA8] = 0x2B,[0xA9] = 0x2D,[0xAA] = 0x2C,[0xAB] = 0x2A,[0xAC] = 0xAB,[0xAD] = 0xAD,[0xAE] = 0xAC,[0xAF] = 0xAA,[0xB0] = 0x40,[0xB1] = 0x3E,[0xB2] = 0x41,[0xB3] = 0x3F,[0xB4] = 0xC0,[0xB5] = 0xBE,[0xB6] = 0xC1,[0xB7] = 0xBF,[0xB8] = 0x00,[0xB9] = 0xFE,[0xBA] = 0x01,[0xBB] = 0xFF,[0xBC] = 0x80,[0xBD] = 0x7E,[0xBE] = 0x81,[0xBF] = 0x7F,[0xC0] = 0x34,[0xC1] = 0x32,[0xC2] = 0x35,[0xC3] = 0x33,[0xC4] = 0xB4,[0xC5] = 0xB2,[0xC6] = 0xB5,[0xC7] = 0xB3,[0xC8] = 0xF4,[0xC9] = 0xF2,[0xCA] = 0xF5,[0xCB] = 0xF3,[0xCC] = 0x74,[0xCD] = 0x72,[0xCE] = 0x75,[0xCF] = 0x73,[0xD0] = 0x54,[0xD1] = 0x52,[0xD2] = 0x55,[0xD3] = 0x53,[0xD4] = 0xD4,[0xD5] = 0xD2,[0xD6] = 0xD5,[0xD7] = 0xD3,[0xD8] = 0x14,[0xD9] = 0x12,[0xDA] = 0x15,[0xDB] = 0x13,[0xDC] = 0x94,[0xDD] = 0x92,[0xDE] = 0x95,[0xDF] = 0x93,[0xE0] = 0x64,[0xE1] = 0x62,[0xE2] = 0x65,[0xE3] = 0x63,[0xE4] = 0xE4,[0xE5] = 0xE2,[0xE6] = 0xE5,[0xE7] = 0xE3,[0xE8] = 0x24,[0xE9] = 0x22,[0xEA] = 0x25,[0xEB] = 0x23,[0xEC] = 0xA4,[0xED] = 0xA2,[0xEE] = 0xA5,[0xEF] = 0xA3,[0xF0] = 0x48,[0xF1] = 0x46,[0xF2] = 0x49,[0xF3] = 0x47,[0xF4] = 0xC8,[0xF5] = 0xC6,[0xF6] = 0xC9,[0xF7] = 0xC7,[0xF8] = 0x08,[0xF9] = 0x06,[0xFA] = 0x09,[0xFB] = 0x07,[0xFC] = 0x88,[0xFD] = 0x86,[0xFE] = 0x89,[0xFF] = 0x87,[0x00] = 0x37,} AddRecvPacketCallback2(function(p) if p.header == 0x0013 then p.pos = 23 local target = objManager:GetObjectByNetworkId(self:Float(p, self.Bytes)) p.pos = 2 local source = objManager:GetObjectByNetworkId(p:DecodeF()) if target ~= nil and source ~= nil and target.valid and source.valid and source.type ~= myHero.type and target.type == 'AIMinion' and source.team == myHero.team then missileTarget[source.networkID] = target end end end) end function L5_122:Float(p, tbl) local b = {} for i=4, 1, -1 do b[i] = tbl[p:Decode1()] end return DwordToFloat(bxor(lshift(band(b[1],0xFF),24),lshift(band(b[2],0xFF),16),lshift(band(b[3],0xFF),8),band(b[4],0xFF))) end end]] function GetAggro(unit) if unit.spell and unit.spell.target then return unit.spell.target else return minionTar[unit.networkID] and minionTar[unit.networkID] or nil end --[[ if canPackets then return type(unit) == "number" and missileTarget[unit] or missileTarget[unit.networkID] else return minionTar[unit.networkID] and minionTar[unit.networkID] or nil end]] end local _FAST, _MEDIUM, _SLOW = 1, 2, 3 local PA = {} for i, champ in pairs(GetEnemyHeroes()) do PA[champ.networkID] = {} end PA[myHero.networkID] = {} class 'VPrediction' --{ function VPrediction:__init() self.version = tonumber(version) self.showdevmode = false self.hitboxes = {['Braum'] = 80, ['RecItemsCLASSIC'] = 65, ['TeemoMushroom'] = 50.0, ['TestCubeRender'] = 65, ['Xerath'] = 65, ['Kassadin'] = 65, ['Rengar'] = 65, ['Thresh'] = 55.0, ['RecItemsTUTORIAL'] = 65, ['Ziggs'] = 55.0, ['ZyraPassive'] = 20.0, ['ZyraThornPlant'] = 20.0, ['KogMaw'] = 65, ['HeimerTBlue'] = 35.0, ['EliseSpider'] = 65, ['Skarner'] = 80.0, ['ChaosNexus'] = 65, ['Katarina'] = 65, ['Riven'] = 65, ['SightWard'] = 1, ['HeimerTYellow'] = 35.0, ['Ashe'] = 65, ['VisionWard'] = 1, ['TT_NGolem2'] = 80.0, ['ThreshLantern'] = 65, ['RecItemsCLASSICMap10'] = 65, ['RecItemsODIN'] = 65, ['TT_Spiderboss'] = 200.0, ['RecItemsARAM'] = 65, ['OrderNexus'] = 65, ['Soraka'] = 65, ['Jinx'] = 65, ['TestCubeRenderwCollision'] = 65, ['Red_Minion_Wizard'] = 48.0, ['JarvanIV'] = 65, ['Blue_Minion_Wizard'] = 48.0, ['TT_ChaosTurret2'] = 88.4, ['TT_ChaosTurret3'] = 88.4, ['TT_ChaosTurret1'] = 88.4, ['ChaosTurretGiant'] = 88.4, ['Dragon'] = 100.0, ['LuluSnowman'] = 50.0, ['Worm'] = 100.0, ['ChaosTurretWorm'] = 88.4, ['TT_ChaosInhibitor'] = 65, ['ChaosTurretNormal'] = 88.4, ['AncientGolem'] = 100.0, ['ZyraGraspingPlant'] = 20.0, ['HA_AP_OrderTurret3'] = 88.4, ['HA_AP_OrderTurret2'] = 88.4, ['Tryndamere'] = 65, ['OrderTurretNormal2'] = 88.4, ['Singed'] = 65, ['OrderInhibitor'] = 65, ['Diana'] = 65, ['HA_FB_HealthRelic'] = 65, ['TT_OrderInhibitor'] = 65, ['GreatWraith'] = 80.0, ['Yasuo'] = 65, ['OrderTurretDragon'] = 88.4, ['OrderTurretNormal'] = 88.4, ['LizardElder'] = 65.0, ['HA_AP_ChaosTurret'] = 88.4, ['Ahri'] = 65, ['Lulu'] = 65, ['ChaosInhibitor'] = 65, ['HA_AP_ChaosTurret3'] = 88.4, ['HA_AP_ChaosTurret2'] = 88.4, ['ChaosTurretWorm2'] = 88.4, ['TT_OrderTurret1'] = 88.4, ['TT_OrderTurret2'] = 88.4, ['TT_OrderTurret3'] = 88.4, ['LuluFaerie'] = 65, ['HA_AP_OrderTurret'] = 88.4, ['OrderTurretAngel'] = 88.4, ['YellowTrinketUpgrade'] = 1, ['MasterYi'] = 65, ['Lissandra'] = 65, ['ARAMOrderTurretNexus'] = 88.4, ['Draven'] = 65, ['FiddleSticks'] = 65, ['SmallGolem'] = 80.0, ['ARAMOrderTurretFront'] = 88.4, ['ChaosTurretTutorial'] = 88.4, ['NasusUlt'] = 80.0, ['Maokai'] = 80.0, ['Wraith'] = 50.0, ['Wolf'] = 50.0, ['Sivir'] = 65, ['Corki'] = 65, ['Janna'] = 65, ['Nasus'] = 80.0, ['Golem'] = 80.0, ['ARAMChaosTurretFront'] = 88.4, ['ARAMOrderTurretInhib'] = 88.4, ['LeeSin'] = 65, ['HA_AP_ChaosTurretTutorial'] = 88.4, ['GiantWolf'] = 65.0, ['HA_AP_OrderTurretTutorial'] = 88.4, ['YoungLizard'] = 50.0, ['Jax'] = 65, ['LesserWraith'] = 50.0, ['Blitzcrank'] = 80.0, ['brush_D_SR'] = 65, ['brush_E_SR'] = 65, ['brush_F_SR'] = 65, ['brush_C_SR'] = 65, ['brush_A_SR'] = 65, ['brush_B_SR'] = 65, ['ARAMChaosTurretInhib'] = 88.4, ['Shen'] = 65, ['Nocturne'] = 65, ['Sona'] = 65, ['ARAMChaosTurretNexus'] = 88.4, ['YellowTrinket'] = 1, ['OrderTurretTutorial'] = 88.4, ['Caitlyn'] = 65, ['Trundle'] = 65, ['Malphite'] = 80.0, ['Mordekaiser'] = 80.0, ['ZyraSeed'] = 65, ['Vi'] = 50, ['Tutorial_Red_Minion_Wizard'] = 48.0, ['Renekton'] = 80.0, ['Anivia'] = 65, ['Fizz'] = 65, ['Heimerdinger'] = 55.0, ['Evelynn'] = 65, ['Rumble'] = 80.0, ['Leblanc'] = 65, ['Darius'] = 80.0, ['OlafAxe'] = 50.0, ['Viktor'] = 65, ['XinZhao'] = 65, ['Orianna'] = 65, ['Vladimir'] = 65, ['Nidalee'] = 65, ['Tutorial_Red_Minion_Basic'] = 48.0, ['ZedShadow'] = 65, ['Syndra'] = 65, ['Zac'] = 80.0, ['Olaf'] = 65, ['Veigar'] = 55.0, ['Twitch'] = 65, ['Alistar'] = 80.0, ['Akali'] = 65, ['Urgot'] = 80.0, ['Leona'] = 65, ['Talon'] = 65, ['Karma'] = 65, ['Jayce'] = 65, ['Galio'] = 80.0, ['Shaco'] = 65, ['Taric'] = 65, ['TwistedFate'] = 65, ['Varus'] = 65, ['Garen'] = 65, ['Swain'] = 65, ['Vayne'] = 65, ['Fiora'] = 65, ['Quinn'] = 65, ['Kayle'] = 65, ['Blue_Minion_Basic'] = 48.0, ['Brand'] = 65, ['Teemo'] = 55.0, ['Amumu'] = 55.0, ['Annie'] = 55.0, ['Odin_Blue_Minion_caster'] = 48.0, ['Elise'] = 65, ['Nami'] = 65, ['Poppy'] = 55.0, ['AniviaEgg'] = 65, ['Tristana'] = 55.0, ['Graves'] = 65, ['Morgana'] = 65, ['Gragas'] = 80.0, ['MissFortune'] = 65, ['Warwick'] = 65, ['Cassiopeia'] = 65, ['Tutorial_Blue_Minion_Wizard'] = 48.0, ['DrMundo'] = 80.0, ['Volibear'] = 80.0, ['Irelia'] = 65, ['Odin_Red_Minion_Caster'] = 48.0, ['Lucian'] = 65, ['Yorick'] = 80.0, ['RammusPB'] = 65, ['Red_Minion_Basic'] = 48.0, ['Udyr'] = 65, ['MonkeyKing'] = 65, ['Tutorial_Blue_Minion_Basic'] = 48.0, ['Kennen'] = 55.0, ['Nunu'] = 65, ['Ryze'] = 65, ['Zed'] = 65, ['Nautilus'] = 80.0, ['Gangplank'] = 65, ['shopevo'] = 65, ['Lux'] = 65, ['Sejuani'] = 80.0, ['Ezreal'] = 65, ['OdinNeutralGuardian'] = 65, ['Khazix'] = 65, ['Sion'] = 80.0, ['Aatrox'] = 65, ['Hecarim'] = 80.0, ['Pantheon'] = 65, ['Shyvana'] = 50.0, ['Zyra'] = 65, ['Karthus'] = 65, ['Rammus'] = 65, ['Zilean'] = 65, ['Chogath'] = 80.0, ['Malzahar'] = 65, ['YorickRavenousGhoul'] = 1.0, ['YorickSpectralGhoul'] = 1.0, ['JinxMine'] = 65, ['YorickDecayedGhoul'] = 1.0, ['XerathArcaneBarrageLauncher'] = 65, ['Odin_SOG_Order_Crystal'] = 65, ['TestCube'] = 65, ['ShyvanaDragon'] = 80.0, ['FizzBait'] = 65, ['ShopKeeper'] = 65, ['Blue_Minion_MechMelee'] = 65.0, ['OdinQuestBuff'] = 65, ['TT_Buffplat_L'] = 65, ['TT_Buffplat_R'] = 65, ['KogMawDead'] = 65, ['TempMovableChar'] = 48.0, ['Lizard'] = 50.0, ['GolemOdin'] = 80.0, ['OdinOpeningBarrier'] = 65, ['TT_ChaosTurret4'] = 88.4, ['TT_Flytrap_A'] = 65, ['TT_Chains_Order_Periph'] = 65, ['TT_NWolf'] = 65.0, ['ShopMale'] = 65, ['OdinShieldRelic'] = 65, ['TT_Chains_Xaos_Base'] = 65, ['LuluSquill'] = 50.0, ['TT_Shopkeeper'] = 65, ['redDragon'] = 100.0, ['MonkeyKingClone'] = 65, ['Odin_skeleton'] = 65, ['OdinChaosTurretShrine'] = 88.4, ['Cassiopeia_Death'] = 65, ['OdinCenterRelic'] = 48.0, ['Ezreal_cyber_1'] = 65, ['Ezreal_cyber_3'] = 65, ['Ezreal_cyber_2'] = 65, ['OdinRedSuperminion'] = 55.0, ['TT_Speedshrine_Gears'] = 65, ['JarvanIVWall'] = 65, ['DestroyedNexus'] = 65, ['ARAMOrderNexus'] = 65, ['Red_Minion_MechCannon'] = 65.0, ['OdinBlueSuperminion'] = 55.0, ['SyndraOrbs'] = 65, ['LuluKitty'] = 50.0, ['SwainNoBird'] = 65, ['LuluLadybug'] = 50.0, ['CaitlynTrap'] = 65, ['TT_Shroom_A'] = 65, ['ARAMChaosTurretShrine'] = 88.4, ['Odin_Windmill_Propellers'] = 65, ['DestroyedInhibitor'] = 65, ['TT_NWolf2'] = 50.0, ['OdinMinionGraveyardPortal'] = 1.0, ['SwainBeam'] = 65, ['Summoner_Rider_Order'] = 65.0, ['TT_Relic'] = 65, ['odin_lifts_crystal'] = 65, ['OdinOrderTurretShrine'] = 88.4, ['SpellBook1'] = 65, ['Blue_Minion_MechCannon'] = 65.0, ['TT_ChaosInhibitor_D'] = 65, ['Odin_SoG_Chaos'] = 65, ['TrundleWall'] = 65, ['HA_AP_HealthRelic'] = 65, ['OrderTurretShrine'] = 88.4, ['OriannaBall'] = 48.0, ['ChaosTurretShrine'] = 88.4, ['LuluCupcake'] = 50.0, ['HA_AP_ChaosTurretShrine'] = 88.4, ['TT_Chains_Bot_Lane'] = 65, ['TT_NWraith2'] = 50.0, ['TT_Tree_A'] = 65, ['SummonerBeacon'] = 65, ['Odin_Drill'] = 65, ['TT_NGolem'] = 80.0, ['Shop'] = 65, ['AramSpeedShrine'] = 65, ['DestroyedTower'] = 65, ['OriannaNoBall'] = 65, ['Odin_Minecart'] = 65, ['Summoner_Rider_Chaos'] = 65.0, ['OdinSpeedShrine'] = 65, ['TT_Brazier'] = 65, ['TT_SpeedShrine'] = 65, ['odin_lifts_buckets'] = 65, ['OdinRockSaw'] = 65, ['OdinMinionSpawnPortal'] = 1.0, ['SyndraSphere'] = 48.0, ['TT_Nexus_Gears'] = 65, ['Red_Minion_MechMelee'] = 65.0, ['SwainRaven'] = 65, ['crystal_platform'] = 65, ['MaokaiSproutling'] = 48.0, ['Urf'] = 65, ['TestCubeRender10Vision'] = 65, ['MalzaharVoidling'] = 10.0, ['GhostWard'] = 1, ['MonkeyKingFlying'] = 65, ['LuluPig'] = 50.0, ['AniviaIceBlock'] = 65, ['TT_OrderInhibitor_D'] = 65, ['yonkey'] = 65, ['Odin_SoG_Order'] = 65, ['RammusDBC'] = 65, ['FizzShark'] = 65, ['LuluDragon'] = 50.0, ['OdinTestCubeRender'] = 65, ['OdinCrane'] = 65, ['TT_Tree1'] = 65, ['ARAMOrderTurretShrine'] = 88.4, ['TT_Chains_Order_Base'] = 65, ['Odin_Windmill_Gears'] = 65, ['ARAMChaosNexus'] = 65, ['TT_NWraith'] = 50.0, ['TT_OrderTurret4'] = 88.4, ['Odin_SOG_Chaos_Crystal'] = 65, ['TT_SpiderLayer_Web'] = 65, ['OdinQuestIndicator'] = 1.0, ['JarvanIVStandard'] = 65, ['TT_DummyPusher'] = 65, ['OdinClaw'] = 65, ['EliseSpiderling'] = 1.0, ['QuinnValor'] = 65, ['UdyrTigerUlt'] = 65, ['UdyrTurtleUlt'] = 65, ['UdyrUlt'] = 65, ['UdyrPhoenixUlt'] = 65, ['ShacoBox'] = 10, ['HA_AP_Poro'] = 65, ['AnnieTibbers'] = 80.0, ['UdyrPhoenix'] = 65, ['UdyrTurtle'] = 65, ['UdyrTiger'] = 65, ['HA_AP_OrderShrineTurret'] = 88.4, ['HA_AP_OrderTurretRubble'] = 65, ['HA_AP_Chains_Long'] = 65, ['HA_AP_OrderCloth'] = 65, ['HA_AP_PeriphBridge'] = 65, ['HA_AP_BridgeLaneStatue'] = 65, ['HA_AP_ChaosTurretRubble'] = 88.4, ['HA_AP_BannerMidBridge'] = 65, ['HA_AP_PoroSpawner'] = 50.0, ['HA_AP_Cutaway'] = 65, ['HA_AP_Chains'] = 65, ['HA_AP_ShpSouth'] = 65, ['HA_AP_HeroTower'] = 65, ['HA_AP_ShpNorth'] = 65, ['ChaosInhibitor_D'] = 65, ['ZacRebirthBloblet'] = 65, ['OrderInhibitor_D'] = 65, ['Nidalee_Spear'] = 65, ['Nidalee_Cougar'] = 65, ['TT_Buffplat_Chain'] = 65, ['WriggleLantern'] = 1, ['TwistedLizardElder'] = 65.0, ['RabidWolf'] = 65.0, ['HeimerTGreen'] = 50.0, ['HeimerTRed'] = 50.0, ['ViktorFF'] = 65, ['TwistedGolem'] = 80.0, ['TwistedSmallWolf'] = 50.0, ['TwistedGiantWolf'] = 65.0, ['TwistedTinyWraith'] = 50.0, ['TwistedBlueWraith'] = 50.0, ['TwistedYoungLizard'] = 50.0, ['Red_Minion_Melee'] = 48.0, ['Blue_Minion_Melee'] = 48.0, ['Blue_Minion_Healer'] = 48.0, ['Ghast'] = 60.0, ['blueDragon'] = 100.0, ['Red_Minion_MechRange'] = 65.0, ['Test_CubeSphere'] = 65,} self.projectilespeeds = {["Velkoz"]= 2000,["TeemoMushroom"] = math.huge,["TestCubeRender"] = math.huge ,["Xerath"] = 2000.0000 ,["Kassadin"] = math.huge ,["Rengar"] = math.huge ,["Thresh"] = 1000.0000 ,["Ziggs"] = 1500.0000 ,["ZyraPassive"] = 1500.0000 ,["ZyraThornPlant"] = 1500.0000 ,["KogMaw"] = 1800.0000 ,["HeimerTBlue"] = 1599.3999 ,["EliseSpider"] = 500.0000 ,["Skarner"] = 500.0000 ,["ChaosNexus"] = 500.0000 ,["Katarina"] = 467.0000 ,["Riven"] = 347.79999 ,["SightWard"] = 347.79999 ,["HeimerTYellow"] = 1599.3999 ,["Ashe"] = 2000.0000 ,["VisionWard"] = 2000.0000 ,["TT_NGolem2"] = math.huge ,["ThreshLantern"] = math.huge ,["TT_Spiderboss"] = math.huge ,["OrderNexus"] = math.huge ,["Soraka"] = 1000.0000 ,["Jinx"] = 2750.0000 ,["TestCubeRenderwCollision"] = 2750.0000 ,["Red_Minion_Wizard"] = 650.0000 ,["JarvanIV"] = 20.0000 ,["Blue_Minion_Wizard"] = 650.0000 ,["TT_ChaosTurret2"] = 1200.0000 ,["TT_ChaosTurret3"] = 1200.0000 ,["TT_ChaosTurret1"] = 1200.0000 ,["ChaosTurretGiant"] = 1200.0000 ,["Dragon"] = 1200.0000 ,["LuluSnowman"] = 1200.0000 ,["Worm"] = 1200.0000 ,["ChaosTurretWorm"] = 1200.0000 ,["TT_ChaosInhibitor"] = 1200.0000 ,["ChaosTurretNormal"] = 1200.0000 ,["AncientGolem"] = 500.0000 ,["ZyraGraspingPlant"] = 500.0000 ,["HA_AP_OrderTurret3"] = 1200.0000 ,["HA_AP_OrderTurret2"] = 1200.0000 ,["Tryndamere"] = 347.79999 ,["OrderTurretNormal2"] = 1200.0000 ,["Singed"] = 700.0000 ,["OrderInhibitor"] = 700.0000 ,["Diana"] = 347.79999 ,["HA_FB_HealthRelic"] = 347.79999 ,["TT_OrderInhibitor"] = 347.79999 ,["GreatWraith"] = 750.0000 ,["Yasuo"] = 347.79999 ,["OrderTurretDragon"] = 1200.0000 ,["OrderTurretNormal"] = 1200.0000 ,["LizardElder"] = 500.0000 ,["HA_AP_ChaosTurret"] = 1200.0000 ,["Ahri"] = 1750.0000 ,["Lulu"] = 1450.0000 ,["ChaosInhibitor"] = 1450.0000 ,["HA_AP_ChaosTurret3"] = 1200.0000 ,["HA_AP_ChaosTurret2"] = 1200.0000 ,["ChaosTurretWorm2"] = 1200.0000 ,["TT_OrderTurret1"] = 1200.0000 ,["TT_OrderTurret2"] = 1200.0000 ,["TT_OrderTurret3"] = 1200.0000 ,["LuluFaerie"] = 1200.0000 ,["HA_AP_OrderTurret"] = 1200.0000 ,["OrderTurretAngel"] = 1200.0000 ,["YellowTrinketUpgrade"] = 1200.0000 ,["MasterYi"] = math.huge ,["Lissandra"] = 2000.0000 ,["ARAMOrderTurretNexus"] = 1200.0000 ,["Draven"] = 1700.0000 ,["FiddleSticks"] = 1750.0000 ,["SmallGolem"] = math.huge ,["ARAMOrderTurretFront"] = 1200.0000 ,["ChaosTurretTutorial"] = 1200.0000 ,["NasusUlt"] = 1200.0000 ,["Maokai"] = math.huge ,["Wraith"] = 750.0000 ,["Wolf"] = math.huge ,["Sivir"] = 1750.0000 ,["Corki"] = 2000.0000 ,["Janna"] = 1200.0000 ,["Nasus"] = math.huge ,["Golem"] = math.huge ,["ARAMChaosTurretFront"] = 1200.0000 ,["ARAMOrderTurretInhib"] = 1200.0000 ,["LeeSin"] = math.huge ,["HA_AP_ChaosTurretTutorial"] = 1200.0000 ,["GiantWolf"] = math.huge ,["HA_AP_OrderTurretTutorial"] = 1200.0000 ,["YoungLizard"] = 750.0000 ,["Jax"] = 400.0000 ,["LesserWraith"] = math.huge ,["Blitzcrank"] = math.huge ,["ARAMChaosTurretInhib"] = 1200.0000 ,["Shen"] = 400.0000 ,["Nocturne"] = math.huge ,["Sona"] = 1500.0000 ,["ARAMChaosTurretNexus"] = 1200.0000 ,["YellowTrinket"] = 1200.0000 ,["OrderTurretTutorial"] = 1200.0000 ,["Caitlyn"] = 2500.0000 ,["Trundle"] = 347.79999 ,["Malphite"] = 1000.0000 ,["Mordekaiser"] = math.huge ,["ZyraSeed"] = math.huge ,["Vi"] = 1000.0000 ,["Tutorial_Red_Minion_Wizard"] = 650.0000 ,["Renekton"] = math.huge ,["Anivia"] = 1400.0000 ,["Fizz"] = math.huge ,["Heimerdinger"] = 1500.0000 ,["Evelynn"] = 467.0000 ,["Rumble"] = 347.79999 ,["Leblanc"] = 1700.0000 ,["Darius"] = math.huge ,["OlafAxe"] = math.huge ,["Viktor"] = 2300.0000 ,["XinZhao"] = 20.0000 ,["Orianna"] = 1450.0000 ,["Vladimir"] = 1400.0000 ,["Nidalee"] = 1750.0000 ,["Tutorial_Red_Minion_Basic"] = math.huge ,["ZedShadow"] = 467.0000 ,["Syndra"] = 1800.0000 ,["Zac"] = 1000.0000 ,["Olaf"] = 347.79999 ,["Veigar"] = 1100.0000 ,["Twitch"] = 2500.0000 ,["Alistar"] = math.huge ,["Akali"] = 467.0000 ,["Urgot"] = 1300.0000 ,["Leona"] = 347.79999 ,["Talon"] = math.huge ,["Karma"] = 1500.0000 ,["Jayce"] = 347.79999 ,["Galio"] = 1000.0000 ,["Shaco"] = math.huge ,["Taric"] = math.huge ,["TwistedFate"] = 1500.0000 ,["Varus"] = 2000.0000 ,["Garen"] = 347.79999 ,["Swain"] = 1600.0000 ,["Vayne"] = 2000.0000 ,["Fiora"] = 467.0000 ,["Quinn"] = 2000.0000 ,["Kayle"] = math.huge ,["Blue_Minion_Basic"] = math.huge ,["Brand"] = 2000.0000 ,["Teemo"] = 1300.0000 ,["Amumu"] = 500.0000 ,["Annie"] = 1200.0000 ,["Odin_Blue_Minion_caster"] = 1200.0000 ,["Elise"] = 1600.0000 ,["Nami"] = 1500.0000 ,["Poppy"] = 500.0000 ,["AniviaEgg"] = 500.0000 ,["Tristana"] = 2250.0000 ,["Graves"] = 3000.0000 ,["Morgana"] = 1600.0000 ,["Gragas"] = math.huge ,["MissFortune"] = 2000.0000 ,["Warwick"] = math.huge ,["Cassiopeia"] = 1200.0000 ,["Tutorial_Blue_Minion_Wizard"] = 650.0000 ,["DrMundo"] = math.huge ,["Volibear"] = 467.0000 ,["Irelia"] = 467.0000 ,["Odin_Red_Minion_Caster"] = 650.0000 ,["Lucian"] = 2800.0000 ,["Yorick"] = math.huge ,["RammusPB"] = math.huge ,["Red_Minion_Basic"] = math.huge ,["Udyr"] = 467.0000 ,["MonkeyKing"] = 20.0000 ,["Tutorial_Blue_Minion_Basic"] = math.huge ,["Kennen"] = 1600.0000 ,["Nunu"] = 500.0000 ,["Ryze"] = 2400.0000 ,["Zed"] = 467.0000 ,["Nautilus"] = 1000.0000 ,["Gangplank"] = 1000.0000 ,["Lux"] = 1600.0000 ,["Sejuani"] = 500.0000 ,["Ezreal"] = 2000.0000 ,["OdinNeutralGuardian"] = 1800.0000 ,["Khazix"] = 500.0000 ,["Sion"] = math.huge ,["Aatrox"] = 347.79999 ,["Hecarim"] = 500.0000 ,["Pantheon"] = 20.0000 ,["Shyvana"] = 467.0000 ,["Zyra"] = 1700.0000 ,["Karthus"] = 1200.0000 ,["Rammus"] = math.huge ,["Zilean"] = 1200.0000 ,["Chogath"] = 500.0000 ,["Malzahar"] = 2000.0000 ,["YorickRavenousGhoul"] = 347.79999 ,["YorickSpectralGhoul"] = 347.79999 ,["JinxMine"] = 347.79999 ,["YorickDecayedGhoul"] = 347.79999 ,["XerathArcaneBarrageLauncher"] = 347.79999 ,["Odin_SOG_Order_Crystal"] = 347.79999 ,["TestCube"] = 347.79999 ,["ShyvanaDragon"] = math.huge ,["FizzBait"] = math.huge ,["Blue_Minion_MechMelee"] = math.huge ,["OdinQuestBuff"] = math.huge ,["TT_Buffplat_L"] = math.huge ,["TT_Buffplat_R"] = math.huge ,["KogMawDead"] = math.huge ,["TempMovableChar"] = math.huge ,["Lizard"] = 500.0000 ,["GolemOdin"] = math.huge ,["OdinOpeningBarrier"] = math.huge ,["TT_ChaosTurret4"] = 500.0000 ,["TT_Flytrap_A"] = 500.0000 ,["TT_NWolf"] = math.huge ,["OdinShieldRelic"] = math.huge ,["LuluSquill"] = math.huge ,["redDragon"] = math.huge ,["MonkeyKingClone"] = math.huge ,["Odin_skeleton"] = math.huge ,["OdinChaosTurretShrine"] = 500.0000 ,["Cassiopeia_Death"] = 500.0000 ,["OdinCenterRelic"] = 500.0000 ,["OdinRedSuperminion"] = math.huge ,["JarvanIVWall"] = math.huge ,["ARAMOrderNexus"] = math.huge ,["Red_Minion_MechCannon"] = 1200.0000 ,["OdinBlueSuperminion"] = math.huge ,["SyndraOrbs"] = math.huge ,["LuluKitty"] = math.huge ,["SwainNoBird"] = math.huge ,["LuluLadybug"] = math.huge ,["CaitlynTrap"] = math.huge ,["TT_Shroom_A"] = math.huge ,["ARAMChaosTurretShrine"] = 500.0000 ,["Odin_Windmill_Propellers"] = 500.0000 ,["TT_NWolf2"] = math.huge ,["OdinMinionGraveyardPortal"] = math.huge ,["SwainBeam"] = math.huge ,["Summoner_Rider_Order"] = math.huge ,["TT_Relic"] = math.huge ,["odin_lifts_crystal"] = math.huge ,["OdinOrderTurretShrine"] = 500.0000 ,["SpellBook1"] = 500.0000 ,["Blue_Minion_MechCannon"] = 1200.0000 ,["TT_ChaosInhibitor_D"] = 1200.0000 ,["Odin_SoG_Chaos"] = 1200.0000 ,["TrundleWall"] = 1200.0000 ,["HA_AP_HealthRelic"] = 1200.0000 ,["OrderTurretShrine"] = 500.0000 ,["OriannaBall"] = 500.0000 ,["ChaosTurretShrine"] = 500.0000 ,["LuluCupcake"] = 500.0000 ,["HA_AP_ChaosTurretShrine"] = 500.0000 ,["TT_NWraith2"] = 750.0000 ,["TT_Tree_A"] = 750.0000 ,["SummonerBeacon"] = 750.0000 ,["Odin_Drill"] = 750.0000 ,["TT_NGolem"] = math.huge ,["AramSpeedShrine"] = math.huge ,["OriannaNoBall"] = math.huge ,["Odin_Minecart"] = math.huge ,["Summoner_Rider_Chaos"] = math.huge ,["OdinSpeedShrine"] = math.huge ,["TT_SpeedShrine"] = math.huge ,["odin_lifts_buckets"] = math.huge ,["OdinRockSaw"] = math.huge ,["OdinMinionSpawnPortal"] = math.huge ,["SyndraSphere"] = math.huge ,["Red_Minion_MechMelee"] = math.huge ,["SwainRaven"] = math.huge ,["crystal_platform"] = math.huge ,["MaokaiSproutling"] = math.huge ,["Urf"] = math.huge ,["TestCubeRender10Vision"] = math.huge ,["MalzaharVoidling"] = 500.0000 ,["GhostWard"] = 500.0000 ,["MonkeyKingFlying"] = 500.0000 ,["LuluPig"] = 500.0000 ,["AniviaIceBlock"] = 500.0000 ,["TT_OrderInhibitor_D"] = 500.0000 ,["Odin_SoG_Order"] = 500.0000 ,["RammusDBC"] = 500.0000 ,["FizzShark"] = 500.0000 ,["LuluDragon"] = 500.0000 ,["OdinTestCubeRender"] = 500.0000 ,["TT_Tree1"] = 500.0000 ,["ARAMOrderTurretShrine"] = 500.0000 ,["Odin_Windmill_Gears"] = 500.0000 ,["ARAMChaosNexus"] = 500.0000 ,["TT_NWraith"] = 750.0000 ,["TT_OrderTurret4"] = 500.0000 ,["Odin_SOG_Chaos_Crystal"] = 500.0000 ,["OdinQuestIndicator"] = 500.0000 ,["JarvanIVStandard"] = 500.0000 ,["TT_DummyPusher"] = 500.0000 ,["OdinClaw"] = 500.0000 ,["EliseSpiderling"] = 2000.0000 ,["QuinnValor"] = math.huge ,["UdyrTigerUlt"] = math.huge ,["UdyrTurtleUlt"] = math.huge ,["UdyrUlt"] = math.huge ,["UdyrPhoenixUlt"] = math.huge ,["ShacoBox"] = 1500.0000 ,["HA_AP_Poro"] = 1500.0000 ,["AnnieTibbers"] = math.huge ,["UdyrPhoenix"] = math.huge ,["UdyrTurtle"] = math.huge ,["UdyrTiger"] = math.huge ,["HA_AP_OrderShrineTurret"] = 500.0000 ,["HA_AP_Chains_Long"] = 500.0000 ,["HA_AP_BridgeLaneStatue"] = 500.0000 ,["HA_AP_ChaosTurretRubble"] = 500.0000 ,["HA_AP_PoroSpawner"] = 500.0000 ,["HA_AP_Cutaway"] = 500.0000 ,["HA_AP_Chains"] = 500.0000 ,["ChaosInhibitor_D"] = 500.0000 ,["ZacRebirthBloblet"] = 500.0000 ,["OrderInhibitor_D"] = 500.0000 ,["Nidalee_Spear"] = 500.0000 ,["Nidalee_Cougar"] = 500.0000 ,["TT_Buffplat_Chain"] = 500.0000 ,["WriggleLantern"] = 500.0000 ,["TwistedLizardElder"] = 500.0000 ,["RabidWolf"] = math.huge ,["HeimerTGreen"] = 1599.3999 ,["HeimerTRed"] = 1599.3999 ,["ViktorFF"] = 1599.3999 ,["TwistedGolem"] = math.huge ,["TwistedSmallWolf"] = math.huge ,["TwistedGiantWolf"] = math.huge ,["TwistedTinyWraith"] = 750.0000 ,["TwistedBlueWraith"] = 750.0000 ,["TwistedYoungLizard"] = 750.0000 ,["Red_Minion_Melee"] = math.huge ,["Blue_Minion_Melee"] = math.huge ,["Blue_Minion_Healer"] = 1000.0000 ,["Ghast"] = 750.0000 ,["blueDragon"] = 800.0000 ,["Red_Minion_MechRange"] = 3000, ["SRU_OrderMinionRanged"] = 650, ["SRU_ChaosMinionRanged"] = 650, ["SRU_OrderMinionSiege"] = 1200, ["SRU_ChaosMinionSiege"] = 1200, ["SRUAP_Turret_Chaos1"] = 1200, ["SRUAP_Turret_Chaos2"] = 1200, ["SRUAP_Turret_Chaos3"] = 1200, ["SRUAP_Turret_Order1"] = 1200, ["SRUAP_Turret_Order2"] = 1200, ["SRUAP_Turret_Order3"] = 1200, ["SRUAP_Turret_Chaos4"] = 1200, ["SRUAP_Turret_Chaos5"] = 500, ["SRUAP_Turret_Order4"] = 1200, ["SRUAP_Turret_Order5"] = 500 } self.ActiveAttacks = {} self.MinionsAttacks = {} if not _G.VPredictionMenu then _G.VPredictionMenu = scriptConfig("VPrediction", "VPrediction") _G.VPredictionMenu:addParam("Mode", "Cast Mode", SCRIPT_PARAM_LIST, 1, {"Fast", "Medium", "Slow" }) --[[Collision]] _G.VPredictionMenu:addSubMenu("Collision", "Collision") _G.VPredictionMenu.Collision:addParam("Buffer", "Collision buffer", SCRIPT_PARAM_SLICE, 20, 0, 100) _G.VPredictionMenu.Collision:addParam("Minions", "Normal minions", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("Mobs", "Jungle minions", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("Others", "Others", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("CHealth", "Check if minions are about to die", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("info", "-", SCRIPT_PARAM_INFO, "^ Can cause fps drops") _G.VPredictionMenu.Collision:addParam("UnitPos", "Check collision at the unit pos", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("CastPos", "Check collision at the cast pos", SCRIPT_PARAM_ONOFF, true) _G.VPredictionMenu.Collision:addParam("PredictPos", "Check collision at the predicted pos", SCRIPT_PARAM_ONOFF, false) _G.VPredictionMenu:addSubMenu("Developers", "Developers") _G.VPredictionMenu.Developers:addParam("Debug", "Enable debug", SCRIPT_PARAM_ONOFF, false) _G.VPredictionMenu.Developers:addParam("SC", "Show collision", SCRIPT_PARAM_ONOFF, false) _G.VPredictionMenu:addParam("Version", "Version", SCRIPT_PARAM_INFO, tostring(self.version)) end --[[Use waypoints from the last 10 seconds]] self.WaypointsTime = 10 self.EnemyMinions = minionManager(MINION_ENEMY, 2000, myHero, MINION_SORT_HEALTH_ASC) self.JungleMinions = minionManager(MINION_JUNGLE, 2000, myHero, MINION_SORT_HEALTH_ASC) self.OtherMinions = minionManager(MINION_OTHER, 2000, myHero, MINION_SORT_HEALTH_ASC) self.TargetsVisible = {} self.TargetsWaypoints = {} self.TargetsImmobile = {} self.TargetsDashing = {} self.TargetsSlowed = {} self.DontShoot = {} self.DontShoot2 = {} self.DontShootUntilNewWaypoints = {} AddNewPathCallback(function(unit, startPos, endPos, isDash ,dashSpeed,dashGravity, dashDistance) self:OnNewPath(unit, startPos, endPos, isDash, dashSpeed, dashGravity, dashDistance) end) AddTickCallback(function() self:OnTick() end) AddDrawCallback(function() self:OnDraw() end) AddAnimationCallback(function(unit, action) self:Animation(unit, action) end) AddProcessSpellCallback(function(unit, spell) self:OnProcessSpell(unit, spell) end) --AddProcessSpellCallback(function(unit, spell) self:CollisionProcessSpell(unit, spell) end) if AddProcessAttackCallback then --AddProcessAttackCallback(function(unit, spell) self:OnProcessSpell(unit, spell) end) AddProcessAttackCallback(function(unit, spell) self:CollisionProcessSpell(unit, spell) end) end self.BlackList = { {name = "aatroxq", duration = 0.75}, --[[4 Dashes, OnDash fails]] } --[[Spells that will cause OnDash to fire, dont shoot and wait to OnDash]] self.dashAboutToHappend = { {name = "ahritumble", duration = 0.25},--ahri's r {name = "akalishadowdance", duration = 0.25},--akali r {name = "headbutt", duration = 0.25},--alistar w {name = "caitlynentrapment", duration = 0.25},--caitlyn e {name = "carpetbomb", duration = 0.25},--corki w {name = "dianateleport", duration = 0.25},--diana r {name = "fizzpiercingstrike", duration = 0.25},--fizz q {name = "fizzjump", duration = 0.25},--fizz e {name = "gragasbodyslam", duration = 0.25},--gragas e {name = "gravesmove", duration = 0.25},--graves e {name = "ireliagatotsu", duration = 0.25},--irelia q {name = "jarvanivdragonstrike", duration = 0.25},--jarvan q {name = "jaxleapstrike", duration = 0.25},--jax q {name = "khazixe", duration = 0.25},--khazix e and e evolved {name = "leblancslide", duration = 0.25},--leblanc w {name = "leblancslidem", duration = 0.25},--leblanc w (r) {name = "blindmonkqtwo", duration = 0.25},--lee sin q {name = "blindmonkwone", duration = 0.25},--lee sin w {name = "luciane", duration = 0.25},--lucian e {name = "maokaiunstablegrowth", duration = 0.25},--maokai w {name = "nocturneparanoia2", duration = 0.25},--nocturne r {name = "pantheon_leapbash", duration = 0.25},--pantheon e? {name = "renektonsliceanddice", duration = 0.25},--renekton e {name = "riventricleave", duration = 0.25},--riven q {name = "rivenfeint", duration = 0.25},--riven e {name = "sejuaniarcticassault", duration = 0.25},--sejuani q {name = "shenshadowdash", duration = 0.25},--shen e {name = "shyvanatransformcast", duration = 0.25},--shyvana r {name = "rocketjump", duration = 0.25},--tristana w {name = "slashcast", duration = 0.25},--tryndamere e {name = "vaynetumble", duration = 0.25},--vayne q {name = "viq", duration = 0.25},--vi q {name = "monkeykingnimbus", duration = 0.25},--wukong q {name = "xenzhaosweep", duration = 0.25},--xin xhao q {name = "yasuodashwrapper", duration = 0.25},--yasuo e } --[[Spells that don't allow movement (durations approx)]] self.spells = { {name = "katarinar", duration = 1}, --Katarinas R {name = "drain", duration = 1}, --Fiddle W {name = "crowstorm", duration = 1}, --Fiddle R {name = "consume", duration = 0.5}, --Nunu Q {name = "absolutezero", duration = 1}, --Nunu R {name = "rocketgrab", duration = 0.5}, --Blitzcrank Q {name = "staticfield", duration = 0.5}, --Blitzcrank R {name = "cassiopeiapetrifyinggaze", duration = 0.5}, --Cassio's R {name = "ezrealtrueshotbarrage", duration = 1}, --Ezreal's R {name = "galioidolofdurand", duration = 1}, --Ezreal's R --{name = "gragasdrunkenrage", duration = 1}, --Gragas W, Rito changed it so that it allows full movement while casting {name = "luxmalicecannon", duration = 1}, --Lux R {name = "reapthewhirlwind", duration = 1}, --Jannas R {name = "jinxw", duration = 0.6}, --jinxW {name = "jinxr", duration = 0.6}, --jinxR {name = "missfortunebullettime", duration = 1}, --MissFortuneR {name = "shenstandunited", duration = 1}, --ShenR {name = "threshe", duration = 0.4}, --ThreshE {name = "threshrpenta", duration = 0.75}, --ThreshR {name = "infiniteduress", duration = 1}, --Warwick R {name = "meditate", duration = 1} --yi W } self.blinks = { {name = "ezrealarcaneshift", range = 475, delay = 0.25, delay2=0.8},--Ezreals E {name = "deceive", range = 400, delay = 0.25, delay2=0.8}, --Shacos Q {name = "riftwalk", range = 700, delay = 0.25, delay2=0.8},--KassadinR {name = "gate", range = 5500, delay = 1.5, delay2=1.5},--Twisted fate R {name = "katarinae", range = math.huge, delay = 0.25, delay2=0.8},--Katarinas E {name = "elisespideredescent", range = math.huge, delay = 0.25, delay2=0.8},--Elise E {name = "elisespidere", range = math.huge, delay = 0.25, delay2=0.8},--Elise insta E } return self end function VPrediction:GetTime() return os.clock() end function VPrediction:GetVersion() return self.version end function VPrediction:OnProcessSpell(unit, spell) if unit and unit.type == myHero.type then for i, s in ipairs(self.spells) do if spell.name:lower() == s.name then self.TargetsImmobile[unit.networkID] = self:GetTime() + s.duration return end end for i, s in ipairs(self.blinks) do local LandingPos = GetDistance(unit, Vector(spell.endPos)) < s.range and Vector(spell.endPos) or Vector(unit) + s.range * (Vector(spell.endPos) - Vector(unit)):normalized() if spell.name:lower() == s.name and not IsWall(D3DXVECTOR3(spell.endPos.x, spell.endPos.y, spell.endPos.z)) then self.TargetsDashing[unit.networkID] = {isblink = true, duration = s.delay, endT = self:GetTime() + s.delay, endT2 = self:GetTime() + s.delay2, startPos = Vector(unit), endPos = LandingPos} return end end for i, s in ipairs(self.BlackList) do if spell.name:lower() == s.name then self.DontShoot[unit.networkID] = self:GetTime() + s.duration return end end for i, s in ipairs(self.dashAboutToHappend) do if spell.name:lower() == s.name then self.DontShoot2[unit.networkID] = self:GetTime() + s.duration return end end end end --[[function OnNewWP(unit) if not lWP then lWP = Vector(unit.endPath) lastWP = os.clock() end if Vector(unit.endPath) ~= lWP then lWP = Vector(unit.endPath) lastWP = os.clock() end if lastWP < os.clock() - 1 then return false else return true end end]] function VPrediction:OnNewPath(unit, startPos, endPos, isDash, dashSpeed ,dashGravity, dashDistance) if unit.type == myHero.type and unit.team ~= myHero.team or unit == myHero then if PA[unit.networkID][#PA[unit.networkID] -1] then local p1 = PA[unit.networkID][#PA[unit.networkID] -1].p local p2 = PA[unit.networkID][#PA[unit.networkID]].p local angle = Vector(unit.x, unit.y, unit.z):angleBetween(Vector(p2.x, p2.y, p2.z), Vector(p1.x, p1.y, p1.z)) if angle > 20 then local submit = {t = os.clock(), p = endPos} table.insert(PA[unit.networkID], submit) end else local submit = {t = os.clock(), p = endPos} table.insert(PA[unit.networkID], submit) end end local object = unit local NetworkID = unit.networkID if object and object.valid and object.networkID and object.type == myHero.type then self.DontShootUntilNewWaypoints[NetworkID] = false if self.TargetsWaypoints[NetworkID] == nil then self.TargetsWaypoints[NetworkID] = {} end local WaypointsToAdd = self:GetCurrentWayPoints(unit) if WaypointsToAdd and #WaypointsToAdd >= 1 then --[[Save only the last waypoint (where the player clicked)]] table.insert(self.TargetsWaypoints[NetworkID], {unitpos = Vector(object) , waypoint = WaypointsToAdd[#WaypointsToAdd], time = self:GetTime(), n = #WaypointsToAdd}) end elseif object and object.valid and object.type ~= myHero.type then local i = 1 while i <= #self.ActiveAttacks do if (self.ActiveAttacks[i].Attacker and self.ActiveAttacks[i].Attacker.valid and self.ActiveAttacks[i].Attacker.networkID == NetworkID and (self.ActiveAttacks[i].starttime + self.ActiveAttacks[i].windUpTime - GetLatency()/2000) > self:GetTime()) then local wpts = self:GetWaypoints(unit.networkID) if #wpts > 1 then table.remove(self.ActiveAttacks, i) else i = i + 1 end else i = i + 1 end end end --[[OnDash Alternative]] if isDash then local dash = {} if unit.type == myHero.type then dash.startPos = startPos dash.endPos = endPos dash.speed = dashSpeed dash.startT = self:GetTime() - GetLatency()/2000 local dis = GetDistance(startPos, endPos) dash.endT = dash.startT + (dis/dashSpeed) self.TargetsDashing[unit.networkID] = dash self.DontShootUntilNewWaypoints[unit.networkID] = true end end end function VPrediction:IsImmobile(unit, delay, radius, speed, from, spelltype) if self.TargetsImmobile[unit.networkID] then local ExtraDelay = speed == math.huge and 0 or (GetDistance(from, unit) / speed) if (self.TargetsImmobile[unit.networkID] > (self:GetTime() + delay + ExtraDelay) and spelltype == "circular") then return true, Vector(unit), Vector(unit) + (radius/3) * (Vector(from) - Vector(unit)):normalized() elseif (self.TargetsImmobile[unit.networkID] + (radius / unit.ms)) > (self:GetTime() + delay + ExtraDelay) then return true, Vector(unit), Vector(unit) end end return false, Vector(unit), Vector(unit) end function VPrediction:isSlowed(unit, delay, speed, from) if self.TargetsSlowed[unit.networkID] then if self.TargetsSlowed[unit.networkID] > (self:GetTime() + delay + GetDistance(unit, from) / speed) then return true end end return false end function VPrediction:IsDashing(unit, delay, radius, speed, from) local TargetDashing = false local CanHit = false local Position if self.TargetsDashing[unit.networkID] then local dash = self.TargetsDashing[unit.networkID] if dash.endT >= self:GetTime() then TargetDashing = true if dash.isblink then if (dash.endT - self:GetTime()) <= (delay + GetDistance(from, dash.endPos)/speed) then Position = Vector(dash.endPos.x, 0, dash.endPos.z) CanHit = (unit.ms * (delay + GetDistance(from, dash.endPos)/speed - (dash.endT2 - self:GetTime()))) < radius end if ((dash.endT - self:GetTime()) >= (delay + GetDistance(from, dash.startPos)/speed)) and not CanHit then Position = Vector(dash.startPos.x, 0, dash.startPos.z) CanHit = true end else local t1, p1, t2, p2, dist = VectorMovementCollision(dash.startPos, dash.endPos, dash.speed, from, speed, (self:GetTime() - dash.startT) + delay) t1, t2 = (t1 and 0 <= t1 and t1 <= (dash.endT - self:GetTime() - delay)) and t1 or nil, (t2 and 0 <= t2 and t2 <= (dash.endT - self:GetTime() - delay)) and t2 or nil local t = t1 and t2 and math.min(t1,t2) or t1 or t2 if t then Position = t==t1 and Vector(p1.x, 0, p1.y) or Vector(p2.x, 0, p2.y) CanHit = true else Position = Vector(dash.endPos.x, 0, dash.endPos.z) CanHit = (unit.ms * (delay + GetDistance(from, Position)/speed - (dash.endT - self:GetTime()))) < radius end end end end return TargetDashing, CanHit, Position end function VPrediction:GetWaypoints(NetworkID, from, to) local Result = {} to = to and to or self:GetTime() if self.TargetsWaypoints[NetworkID] then for i, waypoint in ipairs(self.TargetsWaypoints[NetworkID]) do if from <= waypoint.time and to >= waypoint.time then table.insert(Result, waypoint) end end end return Result, #Result end function VPrediction:CountWaypoints(NetworkID, from, to) local R, N = self:GetWaypoints(NetworkID, from, to) return N end function VPrediction:GetWaypointsLength(Waypoints) local result = 0 for i = 1, #Waypoints -1 do result = result + GetDistance(Waypoints[i], Waypoints[i + 1]) end return result end function VPrediction:CutWaypoints(Waypoints, distance) local result = {} local remaining = distance if distance > 0 then for i = 1, #Waypoints -1 do local A, B = Waypoints[i], Waypoints[i + 1] local dist = GetDistance(A, B) if dist >= remaining then result[1] = Vector(A) + remaining * (Vector(B) - Vector(A)):normalized() for j = i + 1, #Waypoints do result[j - i + 1] = Waypoints[j] end remaining = 0 break else remaining = remaining - dist end end else local A, B = Waypoints[1], Waypoints[2] result = Waypoints result[1] = Vector(A) - distance * (Vector(B) - Vector(A)):normalized() end return result end function VPrediction:GetCurrentWayPoints(object) local result = {} if object.hasMovePath then table.insert(result, Vector(object)) for i = object.pathIndex, object.pathCount do path = object:GetPath(i) table.insert(result, Vector(path)) end else table.insert(result, Vector(object)) end return result end --[[Calculate the hero position based on the last waypoints]] function VPrediction:CalculateTargetPosition(unit, delay, radius, speed, from, spelltype, second) if unit.type == myHero.type and unit.team ~= myHero.team or unit == myHero then --print(unit.charName.." "..#PA[unit.networkID]) if #PA[unit.networkID] > 4 then return Vector(unit), Vector(unit) elseif #PA[unit.networkID] > 3 then delay = delay*.8 speed = speed*1.20 end end local spot if ValidTarget(unit) and unit.endPath or unit == myHero then ---- FIX local p90x = second and second or unit.pos local pathPot = (unit.ms*((GetDistance(myHero.pos, p90x)/speed)+delay)) if unit.pathCount < 3 then local v = Vector(unit) + (Vector(unit.endPath)-Vector(unit)):normalized()*(pathPot - unit.boundingRadius+10) if GetDistance(unit, v) > 1 then if GetDistance(unit.endPath, unit) >= GetDistance(unit, v) then spot = v else spot = Vector(unit.endPath) end else spot = Vector(unit.endPath) end else for i = unit.pathIndex, unit.pathCount do if unit:GetPath(i) and unit:GetPath(i-1) then local pStart = i == unit.pathIndex and unit.pos or unit:GetPath(i-1) local pEnd = unit:GetPath(i) local iPathDist = GetDistance(pStart, pEnd) if unit:GetPath(unit.pathIndex - 1) then if pathPot > iPathDist then pathPot = pathPot-iPathDist else local v = Vector(pStart) + (Vector(pEnd)-Vector(pStart)):normalized()*(pathPot- unit.boundingRadius+10) spot = v if second then return spot, spot else return self:CalculateTargetPosition(unit, delay, radius, speed, from, spelltype, spot) end end end end end if GetDistance(unit, unit.endPath) > unit.boundingRadius then spot = Vector(unit.endPath) else spot = Vector(unit) end end end spot = spot and spot or Vector(unit) if second then return spot, spot else return self:CalculateTargetPosition(unit, delay, radius, speed, from, spelltype, spot) end end function VPrediction:MaxAngle(unit, currentwaypoint, from) local WPtable, n = self:GetWaypoints(unit.networkID, from) local Max = 0 local CV = (Vector(currentwaypoint.x, 0, currentwaypoint.y) - Vector(unit)) for i, waypoint in ipairs(WPtable) do local angle = Vector(0, 0, 0):angleBetween(CV, Vector(waypoint.waypoint.x, 0, waypoint.waypoint.y) - Vector(waypoint.unitpos.x, 0, waypoint.unitpos.y)) if angle > Max then Max = angle end end return Max end function VPrediction:WayPointAnalysis(unit, delay, radius, range, speed, from, spelltype) local Position, CastPosition, HitChance local SavedWayPoints = self.TargetsWaypoints[unit.networkID] and self.TargetsWaypoints[unit.networkID] or {} local CurrentWayPoints = self:GetCurrentWayPoints(unit) local VisibleSince = self.TargetsVisible[unit.networkID] and self.TargetsVisible[unit.networkID] or self:GetTime() if delay < 0.25 then HitChance = 2 else HitChance = 1 end Position, CastPosition = self:CalculateTargetPosition(unit, delay, radius, speed, from, spelltype) if self:CountWaypoints(unit.networkID, self:GetTime() - 0.1) >= 1 or self:CountWaypoints(unit.networkID, self:GetTime() - 1) == 1 then HitChance = 2 end local N = (_G.VPredictionMenu.Mode == _SLOW) and 3 or 2 local t1 = (_G.VPredictionMenu.Mode == _SLOW) and 1 or 0.5 if self:CountWaypoints(unit.networkID, self:GetTime() - 0.75) >= N then local angle = self:MaxAngle(unit, CurrentWayPoints[#CurrentWayPoints], self:GetTime() - t1) if angle > 90 then HitChance = 1 elseif angle < 30 and self:CountWaypoints(unit.networkID, self:GetTime() - 0.1) >= 1 then HitChance = 2 end end N = (_G.VPredictionMenu.Mode == _SLOW) and 2 or 1 if self:CountWaypoints(unit.networkID, self:GetTime() - N) == 0 then HitChance = 2 end if _G.VPredictionMenu.Mode == _FAST then HitChance = 2 end if #CurrentWayPoints <= 1 and self:GetTime() - VisibleSince > 1 then HitChance = 2 end if self:isSlowed(unit, delay, speed, from) then HitChance = 2 end if Position and CastPosition and ((radius / unit.ms >= delay + GetDistance(from, CastPosition)/speed) or (radius / unit.ms >= delay + GetDistance(from, Position)/speed)) then HitChance = 3 end --[[Angle too wide]] if Vector(from):angleBetween(Vector(unit), Vector(CastPosition)) > 60 then HitChance = 1 end if not Position or not CastPosition then HitChance = 0 CastPosition = Vector(unit) Position = CastPosition end if GetDistance(myHero, unit) < 250 and unit ~= myHero then HitChance = 2 Position, CastPosition = self:CalculateTargetPosition(unit, delay*0.5, radius, speed*2, from, spelltype) Position = CastPosition end if #SavedWayPoints == 0 and (self:GetTime() - VisibleSince) > 3 then HitChance = 2 end if self.DontShootUntilNewWaypoints[unit.networkID] then HitChance = 0 CastPosition = Vector(unit) Position = CastPosition end return CastPosition, HitChance, Position end function VPrediction:GetBestCastPosition(unit, delay, radius, range, speed, from, collision, spelltype) assert(unit, "VPrediction: Target can't be nil") range = range and range - 15 or math.huge radius = radius == 0 and 1 or (radius + self:GetHitBox(unit)) - 4 speed = speed and speed or math.huge from = from and from or Vector(myHero) if from.networkID and from.networkID == myHero.networkID then from = Vector(myHero) end local IsFromMyHero = GetDistanceSqr(from, myHero) < 50*50 and true or false delay = delay + (0.07 + GetLatency() / 2000) local Position, CastPosition, HitChance = Vector(unit), Vector(unit), 0 local TargetDashing, CanHitDashing, DashPosition = self:IsDashing(unit, delay, radius, speed, from) local TargetImmobile, ImmobilePos, ImmobileCastPosition = self:IsImmobile(unit, delay, radius, speed, from, spelltype) local VisibleSince = self.TargetsVisible[unit.networkID] and self.TargetsVisible[unit.networkID] or self:GetTime() if unit.type ~= myHero.type then Position, CastPosition = self:CalculateTargetPosition(unit, delay, radius, speed, from, spelltype) HitChance = 2 else if self.DontShoot[unit.networkID] and self.DontShoot[unit.networkID] > self:GetTime() then Position, CastPosition = Vector(unit), Vector(unit) HitChance = 0 elseif TargetDashing then if CanHitDashing then HitChance = 5 else HitChance = 0 end Position, CastPosition = DashPosition, DashPosition elseif self.DontShoot2[unit.networkID] and self.DontShoot2[unit.networkID] > self:GetTime() then Position, CastPosition = Vector(unit.x, unit.y, unit.z), Vector(unit.x, unit.y, unit.z) HitChance = 7 elseif TargetImmobile then Position, CastPosition = ImmobilePos, ImmobileCastPosition HitChance = 4 elseif not self.DontUseWayPoints then CastPosition, HitChance, Position = self:WayPointAnalysis(unit, delay, radius, range, speed, from, spelltype) end end --[[Out of range]] if IsFromMyHero then if (spelltype == "line" and GetDistanceSqr(from, Position) >= range * range) then HitChance = 0 end if (spelltype == "circular" and (GetDistanceSqr(from, Position) >= (range + radius)^2)) then HitChance = 0 end if self.ShotAtMaxRange and HitChance ~= 0 and spelltype == "circular" and (GetDistanceSqr(from, CastPosition) > range ^ 2) then if GetDistanceSqr(from, Position) <= (range + radius / 1.4) ^ 2 then if GetDistanceSqr(from, Position) <= range * range then CastPosition = Position else CastPosition = Vector(from) + range * (Vector(Position) - Vector(from)):normalized() end end elseif (GetDistanceSqr(from, CastPosition) > range ^ 2) then HitChance = 0 end end radius = radius - self:GetHitBox(unit) + 4 if collision and HitChance > 0 then self.EnemyMinions.range = range + 500 * (delay + range/speed) self.JungleMinions.range = self.EnemyMinions.range self.OtherMinions.range = self.EnemyMinions.range self.EnemyMinions:update() self.JungleMinions:update() self.OtherMinions:update() if _G.VPredictionMenu.Collision.CastPos and self:CheckMinionCollision(unit, CastPosition, delay, radius, range, speed, from, false, false) then HitChance = -1 elseif _G.VPredictionMenu.Collision.PredictPos and self:CheckMinionCollision(unit, Position, delay, radius, range, speed, from, false, false) then HitChance = -1 end if _G.VPredictionMenu.Collision.UnitPos and self:CheckMinionCollision(unit, unit, delay, radius, range, speed, from, false, false) then HitChance = -1 end end return CastPosition, HitChance, Position end -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --Collision -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- function VPrediction:GetPredictedHealth(unit, time, delay) local IncDamage = 0 local i = 1 local MaxDamage = 0 local count = 0 delay = delay and delay or 0.07 while i <= #self.ActiveAttacks do if self.ActiveAttacks[i].Attacker and not self.ActiveAttacks[i].Attacker.dead and self.ActiveAttacks[i].Target and self.ActiveAttacks[i].Target.networkID == unit.networkID then local hittime = self.ActiveAttacks[i].starttime + self.ActiveAttacks[i].windUpTime + (GetDistance(self.ActiveAttacks[i].pos, unit)) / self.ActiveAttacks[i].projectilespeed + delay if self:GetTime() < hittime - delay and hittime < self:GetTime() + time then IncDamage = IncDamage + self.ActiveAttacks[i].damage count = count + 1 if self.ActiveAttacks[i].damage > MaxDamage then MaxDamage = self.ActiveAttacks[i].damage end end end i = i + 1 end return unit.health - IncDamage, MaxDamage, count end function VPrediction:GetClosestUnit(obj) local closest = nil for i = 1, objManager.maxObjects do local object = objManager:GetObject(i) if object and object.valid and obj ~= object and (object.type == myHero.type or object.type == "AIMinion") and object.team ~= myHero.team and GetDistanceSqr(object.pos, myHero.pos) < 2000*2000 then if GetDistanceSqr(obj.pos, object.pos) < 250*250 then if object.charName and object.charName ~= "SRU_BaronSpawn" then if closest == nil then closest = object elseif GetDistanceSqr(object.pos, obj) < GetDistanceSqr(closest.pos, obj) then closest = object end end end end end return closest end function VPrediction:GetPredictedHealth2(unit, t) local damage = 0 local i = 1 while i <= #self.ActiveAttacks do local n = 0 if (self:GetTime() - 0.1) <= self.ActiveAttacks[i].starttime + self.ActiveAttacks[i].animationTime and self.ActiveAttacks[i].Target and self.ActiveAttacks[i].Target.valid and self.ActiveAttacks[i].Target.networkID == unit.networkID and self.ActiveAttacks[i].Attacker and self.ActiveAttacks[i].Attacker.valid and not self.ActiveAttacks[i].Attacker.dead then local FromT = self.ActiveAttacks[i].starttime local ToT = t + self:GetTime() while FromT < ToT do if FromT >= self:GetTime() and (FromT + (self.ActiveAttacks[i].windUpTime + GetDistance(unit, self.ActiveAttacks[i].pos) / self.ActiveAttacks[i].projectilespeed)) < ToT then n = n + 1 end FromT = FromT + self.ActiveAttacks[i].animationTime end end damage = damage + n * self.ActiveAttacks[i].damage i = i + 1 end return unit.health - damage end function VPrediction:Animation(unit, action) if unit and unit.valid and unit.type ~= myHero.type and unit.team == myHero.team and action:lower():find("atta") and not self.projectilespeeds[unit.charName] then local time = self:GetTime() + 0.393 - GetLatency()/2000 local tar = GetAggro(unit) if tar then table.insert(self.ActiveAttacks, {Attacker = unit, pos = Vector(unit), Target = tar, animationTime = math.huge, damage = unit.totalDamage, hittime=time, starttime = self:GetTime() - GetLatency()/2000, windUpTime = 0.393, projectilespeed = math.huge}) end end end function VPrediction:CollisionProcessSpell(unit, spell) if unit and unit.valid and spell.target and unit.type ~= myHero.type and spell.target.type == 'AIMinion' and unit.team == myHero.team and spell and spell.name and (spell.name:lower():find("attack") or (spell.name == "frostarrow")) and spell.windUpTime and spell.target then if GetDistanceSqr(unit) < 4000000 then if self.projectilespeeds[unit.charName] then local time = self:GetTime() + GetDistance(spell.target, unit) / self:GetProjectileSpeed(unit) - GetLatency()/2000 local i = 1 while i <= #self.ActiveAttacks do if (self.ActiveAttacks[i].Attacker and self.ActiveAttacks[i].Attacker.valid and self.ActiveAttacks[i].Attacker.networkID == unit.networkID) or ((self.ActiveAttacks[i].hittime + 3) < self:GetTime()) then table.remove(self.ActiveAttacks, i) else i = i + 1 end end table.insert(self.ActiveAttacks, {Attacker = unit, pos = Vector(unit), Target = spell.target, animationTime = spell.animationTime, damage = self:CalcDamageOfAttack(unit, spell.target, spell, 0), hittime=time, starttime = self:GetTime() - GetLatency()/2000, windUpTime = 0, projectilespeed = self:GetProjectileSpeed(unit)}) else minionTar[unit.networkID] = spell.target end end end end function VPrediction:CheckCol(unit, minion, Position, delay, radius, range, speed, from, draw) if unit.networkID == minion.networkID then return false end --[[Check first if the minion is going to be dead when skillshots reaches his position]] if minion.type ~= myHero.type and self:GetPredictedHealth(minion, delay + GetDistance(from, minion) / speed) < 0 then return false end local waypoints = self:GetCurrentWayPoints(minion) local MPos, CastPosition = minion.pathCount == 1 and Vector(minion) or self:CalculateTargetPosition(minion, delay, radius, speed, from, "line") if GetDistanceSqr(from, MPos) <= (range)^2 and GetDistanceSqr(from, minion) <= (range + 100)^2 then local buffer = (minion.pathCount > 1) and _G.VPredictionMenu.Collision.Buffer or 8 if minion.type == myHero.type then buffer = buffer + self:GetHitBox(minion) end if draw then DrawCircle3D(minion.x, myHero.y, minion.z, self:GetHitBox(minion) + buffer, 1, ARGB(255, 255, 255, 255)) DrawCircle3D(MPos.x, myHero.y, MPos.z, self:GetHitBox(minion) + buffer, 1, ARGB(255, 255, 255, 255)) self:DLine(MPos, minion, Color) end if minion.pathCount > 1 then local proj1, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(from, Position, Vector(MPos)) if isOnSegment and (GetDistanceSqr(MPos, proj1) <= (self:GetHitBox(minion) + radius + buffer) ^ 2) then return true end end local proj2, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(from, Position, Vector(minion)) if isOnSegment and (GetDistanceSqr(minion, proj2) <= (self:GetHitBox(minion) + radius + buffer) ^ 2) then return true end end return false end function VPrediction:CheckMinionCollision(unit, Position, delay, radius, range, speed, from, draw, updatemanagers) Position = Vector(Position) from = from and Vector(from) or myHero --local draw = true if updatemanagers then self.EnemyMinions.range = range + 500 * (delay + range / speed) self.JungleMinions.range = self.EnemyMinions.range self.OtherMinions.range = self.EnemyMinions.range self.EnemyMinions:update() self.JungleMinions:update() self.OtherMinions:update() end local result = false if _G.VPredictionMenu.Collision.Minions then for i, minion in ipairs(self.EnemyMinions.objects) do if self:CheckCol(unit, minion, Position, delay, radius, range, speed, from, draw) then if not draw then return true else result = true end end end end if _G.VPredictionMenu.Collision.Mobs then for i, minion in ipairs(self.JungleMinions.objects) do if self:CheckCol(unit, minion, Position, delay, radius, range, speed, from, draw) then if not draw then return true else result = true end end end end if _G.VPredictionMenu.Collision.Others then for i, minion in ipairs(self.OtherMinions.objects) do if minion.team ~= myHero.team and self:CheckCol(unit, minion, Position, delay, radius, range, speed, from, draw) then if not draw then return true else result = true end end end end if self.ChampionCollision then for i, enemy in ipairs(GetEnemyHeroes()) do if self:CheckCol(unit, enemy, Position, delay, radius, range, speed, from, draw) then if not draw then return true else result = true end end end end if draw then local Direction = Vector(Position - from):perpendicular():normalized() local Color = result and ARGB(255, 255, 0, 0) or ARGB(255, 0, 255, 0) local P1r = Vector(from) + radius * Vector(Direction) local P1l = Vector(from) - radius * Vector(Direction) local P2r = Vector(from) + radius * Direction - Vector(Direction):perpendicular() * GetDistance(from, Position) local P2l = Vector(from) - radius * Direction - Vector(Direction):perpendicular() * GetDistance(from, Position) self:DLine(P1r, P1l, Color) self:DLine(P1r, P2r, Color) self:DLine(P1l, P2l, Color) self:DLine(P2r, P2l, Color) if not result and IsKeyDown(string.byte("T")) then CastSpell(_Q, Position.x, Position.z) end end return result end function VPrediction:GetCircularCastPosition(unit, delay, radius, range, speed, from, collision) return self:GetBestCastPosition(unit, delay, radius, range, speed, from, collision, "circular") end --Added dmg param to increase minimum health predicted on collision if desired for champs such as Kalista Q; Or to increase buffer on predicted health by doing negative function VPrediction:GetLineCastPosition(unit, delay, radius, range, speed, from, collision) return self:GetBestCastPosition(unit, delay, radius, range, speed, from, collision, "line") end function VPrediction:GetPredictedPos(unit, delay, speed, from, collision) return self:GetBestCastPosition(unit, delay, 1, math.huge, speed, from, collision, "circular") end --TODO: Recode this stuff and make it more readable :D function VPrediction:GetCircularAOECastPosition(unit, delay, radius, range, speed, from, collision) local CastPosition, HitChance, Position = self:GetBestCastPosition(unit, delay, radius, range, speed, from, collision, "circular") local points = {} local mainCastPosition, mainHitChance, mainPosition = CastPosition, HitChance, Position table.insert(points, Position) for i, target in ipairs(GetEnemyHeroes()) do if target.networkID ~= unit.networkID and ValidTarget(target, range * 1.5) then CastPosition, HitChance, Position = self:GetBestCastPosition(target, delay, radius, range, speed, from, collision, "circular") if GetDistance(from, Position) < (range + radius) and (Hitchance ~= -1 or not collision) then table.insert(points, Position) end end end while #points > 1 do local Mec = MEC(points) local Circle = Mec:Compute() if Circle.radius <= radius + self:GetHitBox(unit) - 8 then return Circle.center, mainHitChance, #points end local maxdist = -1 local maxdistindex = 0 for i=2, #points do local d = GetDistanceSqr(points[i], points[1]) if d > maxdist or maxdist == -1 then maxdistindex = i maxdist = d end end table.remove(points, maxdistindex) end return mainCastPosition, mainHitChance, #points, mainPosition end function VPrediction:GetLineAOECastPosition(unit, delay, radius, range, speed, from) local CastPosition, HitChance, Position = self:GetBestCastPosition(unit, delay, radius, range, speed, from, false, "line") local points = {} local Positions = {} local mainCastPosition, mainHitChance = CastPosition, HitChance table.insert(Positions, {unit = unit, HitChance = HitChance, Position = Position, CastPosition = CastPosition}) table.insert(points, Position) range = range and range - 4 or 20000 radius = radius == 0 and 1 or (radius + self:GetHitBox(unit)) - 4 from = from and Vector(from) or Vector(myHero) local function CircleCircleIntersection(C1, C2, R1, R2) local D = GetDistance(C1, C2) local A = (R1 * R1 - R2 * R2 + D * D ) / (2 * D) local H = math.sqrt(R1 * R1 - A * A); local Direction = (Vector(C2) - Vector(C1)):normalized() local PA = Vector(C1) + A * Direction local S1 = PA + H * Direction:perpendicular() local S2 = PA - H * Direction:perpendicular() return S1, S2 end local function GetPosiblePoints(from, pos, width, range) local middlepoint = (from + pos)/2 local P1, P2 = CircleCircleIntersection(from, middlepoint, width, GetDistance(middlepoint, from)) local V1 = (P1 - from) local V2 = (P2 - from) return from + range * (pos - V1 - from):normalized(), from + range * (pos - V2 - from):normalized() end local function CountHits(P1, P2, width, points) local hits = 0 local hitt = {} width = width + 2 for i, point in ipairs(points) do local pointSegment, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(P1, P2, point) if isOnSegment and GetDistanceSqr(pointSegment, point) <= width * width then hits = hits + 1 table.insert(hitt, point) elseif i == 1 then return -1 end end return hits, hitt end for i, target in ipairs(GetEnemyHeroes()) do if target.networkID ~= unit.networkID and ValidTarget(target, range * 1.5) then CastPosition, HitChance, Position = self:GetBestCastPosition(target, delay, radius, range, speed, from, false, "line") if GetDistance(from, Position) < (range + radius) then table.insert(points, Position) table.insert(Positions, {unit = target, HitChance = HitChance, Position = Position, CastPosition = CastPosition}) end end end local MaxHit = 1 local MaxHitPos if #points > 1 then for i, candidate in ipairs(points) do local C1, C2 = GetPosiblePoints(from, points[i], radius - 20, range) local hits, MPoints1 = CountHits(from, C1, radius, points) local hits2, MPoints2 = CountHits(from, C2, radius, points) if hits >= MaxHit then MaxHitPos = C1 MaxHit = hits MaxHitPoints = MPoints1 end if hits2 >= MaxHit then MaxHitPos = C2 MaxHit = hits2 MaxHitPoints = MPoints2 end end end if MaxHit > 1 then --center the line local maxdist = -1 local p1 local p2 for i, hitp in ipairs(MaxHitPoints) do for o, hitp2 in ipairs(MaxHitPoints) do local StartP, EndP = Vector(from), (Vector(hitp) + Vector(hitp2)) / 2 local pointSegment, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(StartP, EndP, hitp) local pointSegment2, pointLine2, isOnSegment2 = VectorPointProjectionOnLineSegment(StartP, EndP, hitp2) local dist = GetDistanceSqr(hitp, pointLine) + GetDistanceSqr(hitp2, pointLine2) if dist >= maxdist then maxdist = dist p1 = hitp p2 = hitp2 end end end if self.ReturnHitTable then for i = #Positions, 1, -1 do local pointSegment, pointLine, isOnSegment = VectorPointProjectionOnLineSegment(Vector(from), (p1 + p2) / 2, Positions[i].Position) if (not isOnSegment) or (GetDistanceSqr(pointLine, Positions[i].Position) > (radius + 5)^2) then table.remove(Positions, i) end end end return (p1 + p2) / 2, mainHitChance, MaxHit, Positions else return mainCastPosition, mainHitChance, 1, Positions end end function VPrediction:GetConeAOECastPosition(unit, delay, angle, range, speed, from) range = range and range - 4 or 20000 radius = 1 from = from and Vector(from) or Vector(myHero) angle = (angle < math.pi * 2) and angle or (angle * math.pi / 180) local CastPosition, HitChance, Position = self:GetBestCastPosition(unit, delay, radius, range, speed, from, false, "line") local points = {} local mainCastPosition, mainHitChance = CastPosition, HitChance table.insert(points, Vector(Position) - Vector(from)) local function CountVectorsBetween(V1, V2, points) local result = 0 local hitpoints = {} for i, test in ipairs(points) do local NVector = Vector(V1):crossP(test) local NVector2 = Vector(test):crossP(V2) if NVector.y >= 0 and NVector2.y >= 0 then result = result + 1 table.insert(hitpoints, test) elseif i == 1 then return -1 --doesnt hit the main target end end return result, hitpoints end local function CheckHit(position, angle, points) local direction = Vector(position):normalized() local v1 = Vector(position):rotated(0, -angle / 2, 0) local v2 = Vector(position):rotated(0, angle / 2, 0) return CountVectorsBetween(v1, v2, points) end for i, target in ipairs(GetEnemyHeroes()) do if target.networkID ~= unit.networkID and ValidTarget(target, range * 1.5) then CastPosition, HitChance, Position = self:GetBestCastPosition(target, delay, radius, range, speed, from, false, "line") if GetDistanceSqr(from, Position) < range * range then table.insert(points, Vector(Position) - Vector(from)) end end end local MaxHitPos local MaxHit = 1 local MaxHitPoints = {} if #points > 1 then for i, point in ipairs(points) do local pos1 = Vector(point):rotated(0, angle / 2, 0) local pos2 = Vector(point):rotated(0, - angle / 2, 0) local hits, points1 = CheckHit(pos1, angle, points) local hits2, points2 = CheckHit(pos2, angle, points) if hits >= MaxHit then MaxHitPos = C1 MaxHit = hits MaxHitPoints = points1 end if hits2 >= MaxHit then MaxHitPos = C2 MaxHit = hits2 MaxHitPoints = points2 end end end if MaxHit > 1 then --Center the cone local maxangle = -1 local p1 local p2 for i, hitp in ipairs(MaxHitPoints) do for o, hitp2 in ipairs(MaxHitPoints) do local cangle = Vector():angleBetween(hitp2, hitp) if cangle > maxangle then maxangle = cangle p1 = hitp p2 = hitp2 end end end return Vector(from) + range * (((p1 + p2) / 2)):normalized(), mainHitChance, MaxHit else return mainCastPosition, mainHitChance, 1 end end function VPrediction:OnTick() --[[Delete the old saved Waypoints]] if self.lastick == nil or self:GetTime() - self.lastick > 0.2 then self.lastick = self:GetTime() for i, enemy in pairs(GetEnemyHeroes()) do for i, tbl in pairs(PA[enemy.networkID]) do if os.clock() - 1.5 > tbl.t then table.remove(PA[enemy.networkID], i) end end end for i, tbl in pairs(PA[myHero.networkID]) do if os.clock() - 1.5 > tbl.t then table.remove(PA[myHero.networkID], i) end end for NID, TargetWaypoints in pairs(self.TargetsWaypoints) do local i = 1 while i <= #self.TargetsWaypoints[NID] do if self.TargetsWaypoints[NID][i]["time"] + self.WaypointsTime < self:GetTime() then table.remove(self.TargetsWaypoints[NID], i) else i = i + 1 end end end end end --[[Drawing functions for debug: ]] function VPrediction:DrawSavedWaypoints(object, time, color, drawPoints) colour = color and color or ARGB(255, 0, 255, 0) for i = object.pathIndex, object.pathCount do if object:GetPath(i) and object:GetPath(i-1) then local pStart = i == object.pathIndex and object.pos or object:GetPath(i-1) self:DLine(pStart, object:GetPath(i), colour) end end if drawPoints then local Waypoints = self:GetCurrentWayPoints(object) for i, waypoint in ipairs(Waypoints) do DrawCircle3D(waypoint.x, myHero.y, waypoint.z, 10, 2, ARGB(255, 0,0, 255), 200) end end end function VPrediction:DrawHitBox(object) DrawCircle3D(object.x, object.y, object.z, self:GetHitBox(object), 1, ARGB(255, 255, 255, 255)) if object then DrawCircle3D(object.x, object.y, object.z, self:GetHitBox(object), 1, ARGB(255, 0, 255, 0)) end end function VPrediction:DLine(From, To, Color) DrawLine3D(From.x, From.y, From.z, To.x, To.y, To.z, 2, Color) end function VPrediction:OnDraw() if self.showdevmode and _G.VPredictionMenu.Developers.Debug then LastGetTarget = LastGetTarget or myHero local target = GetTarget() or LastGetTarget LastGetTarget = target for i, enemy in ipairs(GetEnemyHeroes()) do self:DrawHitBox(enemy) end if _G.VPredictionMenu.Developers.SC then self.EnemyMinions:update() self.JungleMinions:update() self.OtherMinions:update() self:CheckMinionCollision(Vector(myHero) + 1050 * (Vector(mousePos) - Vector(myHero)):normalized(), 0.25, 70, 1050, 1800, myHero, true) end if target then self:DrawHitBox(target) local CastPosition, HitChance, Position = self:GetCircularCastPosition(target, 0.6, 70, 900, math.huge) if HitChance >= -1 then DrawText3D(tostring(HitChance), CastPosition.x, myHero.y, CastPosition.z, 40, ARGB(255, 255, 255, 255), true) DrawCircle3D(Position.x, myHero.y, Position.z, 70 + self:GetHitBox(target), 1, ARGB(255, 0, 255, 0)) DrawCircle3D(CastPosition.x, myHero.y, CastPosition.z, 70 + self:GetHitBox(target), 1, ARGB(255, 255, 0, 0)) end local waypoint = self:GetCurrentWayPoints(target) for i = 1, #waypoint-1 do self:DLine(Vector(waypoint[i].x, myHero.y, waypoint[i].y), Vector(waypoint[i+1].x, myHero.y, waypoint[i+1].y), ARGB(255,255,255,255)) end end end end function VPrediction:GetHitBox(object) if self.nohitboxmode and object.type and object.type == myHero.type then return 0 end return (self.hitboxes[object.charName] ~= nil and self.hitboxes[object.charName] ~= 0) and self.hitboxes[object.charName] or 65 end function VPrediction:GetProjectileSpeed(unit) return self.projectilespeeds[unit.charName] and self.projectilespeeds[unit.charName] or math.huge end function VPrediction:CalcDamageOfAttack(source, target, spell, additionalDamage) -- read initial armor and damage values local armorPenPercent = source.armorPenPercent local armorPen = source.armorPen local totalDamage = source.totalDamage + (additionalDamage or 0) local damageMultiplier = spell.name:find("CritAttack") and 2 or 1 -- minions give wrong values for armorPen and armorPenPercent if source.type == "AIMinion" then armorPenPercent = 1 elseif source.type == "AITurret" then armorPenPercent = 0.7 end -- turrets ignore armor penetration and critical attacks if target.type == "AITurret" then armorPenPercent = 1 armorPen = 0 damageMultiplier = 1 end -- calculate initial damage multiplier for negative and positive armor local targetArmor = (target.armor * armorPenPercent) - armorPen if targetArmor < 0 then -- minions can't go below 0 armor. --damageMultiplier = (2 - 100 / (100 - targetArmor)) * damageMultiplier damageMultiplier = 1 * damageMultiplier else damageMultiplier = 100 / (100 + targetArmor) * damageMultiplier end -- use ability power or ad based damage on turrets if source.type == myHero.type and target.type == "AITurret" then totalDamage = math.max(source.totalDamage, source.damage + 0.4 * source.ap) end -- minions deal less damage to enemy heros if source.type == "AIMinion" and target.type == myHero.type and source.team ~= TEAM_NEUTRAL then damageMultiplier = 0.60 * damageMultiplier end -- heros deal less damage to turrets if source.type == myHero.type and target.type == "AITurret" then damageMultiplier = 0.95 * damageMultiplier end -- minions deal less damage to turrets if source.type == "AIMinion" and target.type == "AITurret" then damageMultiplier = 0.475 * damageMultiplier end -- siege minions and superminions take less damage from turrets if source.type == "AITurret" and (target.charName == "Red_Minion_MechCannon" or target.charName == "Blue_Minion_MechCannon") then damageMultiplier = 0.8 * damageMultiplier end -- caster minions and basic minions take more damage from turrets if source.type == "AITurret" and (target.charName == "Red_Minion_Wizard" or target.charName == "Blue_Minion_Wizard" or target.charName == "Red_Minion_Basic" or target.charName == "Blue_Minion_Basic") then damageMultiplier = (1 / 0.875) * damageMultiplier end -- turrets deal more damage to all units by default if source.type == "AITurret" then damageMultiplier = 1.05 * damageMultiplier end -- calculate damage dealt return damageMultiplier * totalDamage end