Created
July 3, 2012 14:50
-
-
Save DelusionalLogic/3040200 to your computer and use it in GitHub Desktop.
Veigarsuperfunhouse
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Circle = { | |
-- =========================== | |
-- Creates a new circle of the specified center and radius. | |
-- =========================== | |
New = function(self) | |
local c = {} | |
setmetatable(c, {__index = self}) | |
return c | |
end, | |
-- =========================== | |
-- Determines if the point is contained within the circle. | |
-- =========================== | |
Contains = function(self, point) | |
return point:Distance(self.center) < self.radius | |
or math.abs(point:Distance(self.center) - self.radius) < 1e-9 | |
end, | |
-- =========================== | |
-- Get the string representation of the circle. | |
-- =========================== | |
ToString = function(self) | |
return "{center: " .. self.center:ToString() .. ", radius: " .. tostring(self.radius) .. "}" | |
end, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Prediction calculation example v0.1 | |
Written by h0nda | |
]] | |
-- linear prediction with constant time | |
LinearPredictionConstT = {} | |
player = GetMyHero() | |
function LinearPredictionConstT:new(range, time) | |
local object = { range = range, time = time, memory={}, prediction={}} | |
setmetatable(object, { __index = LinearPredictionConstT }) | |
return object | |
end | |
function LinearPredictionConstT:check_if_target(obj) | |
return obj ~= nil and obj.team ~= player.team and obj.dead == false and obj.visible == true | |
end | |
function LinearPredictionConstT:tick() | |
local count = heroManager.iCount | |
local position, v,ft,dt | |
for i = 1, count, 1 do | |
local object = heroManager:GetHero(i) | |
if self:check_if_target(object) and (player:GetDistance(object)<=self.range or self.range ==0 )then | |
if self.memory[object.charName] then | |
ft = self.time | |
dt = GetTickCount()-self.memory[object.charName].t | |
position = Vector:New({x=object.x,z=object.z}) | |
old_position = self.memory[object.charName].p | |
dp = position-old_position | |
self.prediction[object.charName]=position+((dp)/dt)*ft | |
end | |
self.memory[object.charName]={p=Vector:New(object.x,object.z),t=GetTickCount()} | |
else | |
self.prediction[object.charName]=nil | |
end | |
end | |
end | |
function LinearPredictionConstT:getPredictionFor(champ_charName) | |
return self.prediction[champ_charName] | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- =========================== | |
-- Minimum enclosing circle algorithm | |
-- --------------------------- | |
-- Much of this code was inspired from the ruby implementation at: | |
-- [http://www.dseifert.net/code/mec/source.html] | |
-- =========================== | |
-- =========================== | |
-- Copy the array portion of the table. | |
-- =========================== | |
function CopyArray(t) | |
local ret = {} | |
for i,v in ipairs(t) do | |
ret[i] = v | |
end | |
return ret | |
end | |
-- =========================== | |
-- Create a new array, minus the element at the specified index | |
-- =========================== | |
function DeleteAt(t, index) | |
local ret = {} | |
for i,v in ipairs(t) do | |
if i ~= index then | |
table.insert(ret, v) | |
end | |
end | |
return ret | |
end | |
-- =========================== | |
-- Joins arrays t1 and t2 and outputs only the unique elements. | |
-- =========================== | |
function JoinUniqueArrayElements(t1, t2) | |
local ret = {} | |
local unique = {} | |
-- Place the elements of t1 and t2 into the unique dictionary | |
for i,p in ipairs(t1) do | |
unique["x" .. p.x .. "z" .. p.z] = p | |
end | |
for i,p in ipairs(t2) do | |
unique["x" .. p.x .. "z" .. p.z] = p | |
end | |
-- Insert each element of unique into the return array. | |
for k,p in pairs(unique) do | |
table.insert(ret, p) | |
end | |
return ret | |
end | |
-- =========================== | |
-- Minimum Enclosing Circle object and algorithm | |
-- =========================== | |
MEC = { | |
-- =========================== | |
-- Create a new MEC table | |
-- =========================== | |
New = function(self, points) | |
local mec = {} | |
mec = setmetatable({}, {__index = self}) | |
mec.circle = nil | |
mec.points = {} -- a table of x,z coordinates | |
if points then | |
mec:SetPoints(points) | |
end | |
return mec | |
end, | |
-- =========================== | |
-- Set the points used to compute the MEC. | |
-- points is an array, starting at 1. | |
-- =========================== | |
SetPoints = function(self, points) | |
-- Set the points | |
self.points = points | |
for i, p in ipairs(self.points) do | |
p = Vector:New(p) | |
end | |
end, | |
-- =========================== | |
-- Computes the half hull of a set of points | |
-- =========================== | |
HalfHull = function(left, right, pointTable, factor) | |
local input = CopyArray(pointTable) | |
table.insert(input, right) | |
local half = {} | |
table.insert(half, left) | |
for i,p in ipairs(input) do | |
table.insert(half, p) | |
while #half >= 3 do | |
local dir = factor * Vector.Direction(half[(#half+1)-3], half[(#half+1)-1], half[(#half+1)-2]) | |
if dir <= 0 then | |
half = DeleteAt(half, #half-1) | |
else | |
break | |
end | |
end | |
end | |
return half | |
end, | |
-- =========================== | |
-- Computes the set of points that represent the | |
-- convex hull of the set of points | |
-- =========================== | |
ConvexHull = function(self) | |
local a = self.points | |
local left = a[1] | |
local right = a[#a] | |
local upper = {} | |
local lower = {} | |
-- Partition remaining points into upper and lower buckets. | |
for i = 2, #a-1 do | |
local dir = Vector.Direction(left, right, a[i]) | |
if dir < 0 then | |
table.insert(upper, a[i]) | |
else | |
table.insert(lower, a[i]) | |
end | |
end | |
local upperHull = self.HalfHull(left, right, upper, -1) | |
local lowerHull = self.HalfHull(left, right, lower, 1) | |
return JoinUniqueArrayElements(upperHull, lowerHull) | |
end, | |
-- =========================== | |
-- Compute the MEC. | |
-- =========================== | |
Compute = function(self) | |
self.circle = self.circle or Circle:New() | |
-- Make sure there are some points. | |
if #self.points == 0 then return self.circle end | |
-- Handle degenerate cases first | |
if #self.points == 1 then | |
self.circle.center = self.points[1] | |
self.circle.radius = 0 | |
self.circle.radiusPoint = self.points[1] | |
elseif #self.points == 2 then | |
local a = self.points | |
self.circle.center = a[1]:Center(a[2]) | |
self.circle.radius = a[1]:Distance(self.circle.center) | |
self.circle.radiusPoint = a[1] | |
else | |
local a = self:ConvexHull() | |
local point_a = a[1] | |
local point_b = nil | |
local point_c = a[2] | |
if not point_c then | |
self.circle.center = point_a | |
self.circle.radius = 0 | |
self.circle.radiusPoint = point_a | |
return self.circle | |
end | |
-- Loop until we get appropriate values for point_a and point_c | |
while true do | |
point_b = nil | |
local best_theta = 180.0 | |
-- Search for the point "b" which subtends the smallest angle a-b-c. | |
for i,point in ipairs(self.points) do | |
if (not point:Equals(point_a)) and (not point:Equals(point_c)) then | |
local theta_abc = point:AngleBetween(point_a, point_c) | |
if theta_abc < best_theta then | |
point_b = point | |
best_theta = theta_abc | |
end | |
end | |
end | |
-- If the angle is obtuse, then line a-c is the diameter of the circle, | |
-- so we can return. | |
if best_theta >= 90.0 or (not point_b) then | |
self.circle.center = point_a:Center(point_c) | |
self.circle.radius = point_a:Distance(self.circle.center) | |
self.circle.radiusPoint = point_a | |
return self.circle | |
end | |
local ang_bca = point_c:AngleBetween(point_b, point_a) | |
local ang_cab = point_a:AngleBetween(point_c, point_b) | |
if ang_bca > 90.0 then | |
point_c = point_b | |
elseif ang_cab <= 90.0 then | |
break | |
else | |
point_a = point_b | |
end | |
end | |
local ch1 = (point_b - point_a):Scale(0.5) | |
local ch2 = (point_c - point_a):Scale(0.5) | |
local n1 = ch1:NormalLeft() | |
local n2 = ch2:NormalLeft() | |
ch1 = point_a + ch1 | |
ch2 = point_a + ch2 | |
self.circle.center = Vector.InfLineIntersection (ch1, n1, ch2, n2) | |
self.circle.radius = self.circle.center:Distance(point_a) | |
self.circle.radiusPoint = point_a | |
end | |
return self.circle | |
end, | |
} | |
function __check_if_target(obj,range,R) | |
return obj ~= nil and obj.team == TEAM_ENEMY and not obj.dead and obj.visible and player:GetDistance(obj) <= (range + R) | |
--return obj ~= nil | |
end | |
function __check_if_near_target(obj,target,range,R) | |
return obj ~= nil and obj.team == target.team and not obj.dead and obj.visible and obj:GetDistance(target) <= R*2 | |
end | |
function FindGroupCenterNearTarget(target,R,range) | |
local playerCount = heroManager.iCount | |
local points = {} | |
for i = 1, playerCount, 1 do | |
local object = heroManager:GetHero(i) | |
if __check_if_near_target(object,target,range,R) or object == target then -- finding enemies near our target. grouping them in points table. | |
table.insert(points, Vector:New(object.x,object.z)) | |
end | |
end | |
return CalcSpellPosForGroup(R,range,points) | |
end | |
function FindGroupCenterFromNearestEnemies(R,range) | |
local playerCount = heroManager.iCount | |
local points = {} | |
for i = 1, playerCount, 1 do | |
local object = heroManager:GetHero(i) | |
if __check_if_target(object,range,R) then -- finding enemies in our range (spell range + AoE radius) and grouping them in points table. | |
table.insert(points, Vector:New(object.x,object.z)) | |
end | |
end | |
return CalcSpellPosForGroup(R,range,points) | |
end | |
-- ============================================================ | |
-- Weee's additional stuff: | |
-- ============================================================ | |
-- ======================= | |
-- CalcCombosFromString is used to fill table "comboTableToFill[]" with unique | |
-- combinations (with size of comboSize) generated from table "targetsTable[]". | |
-- ======================= | |
function CalcCombosFromString(comboString,index_number,comboSize,targetsTable,comboTableToFill) | |
if string.len(comboString) == comboSize then | |
local b = {} | |
for i=1,string.len(comboString),1 do | |
local ai = tonumber(string.sub(comboString,i,i)) | |
table.insert(b,targetsTable[ai]) | |
end | |
return table.insert(comboTableToFill,b) | |
end | |
for i = index_number, #targetsTable, 1 do | |
CalcCombosFromString(comboString..i,i+1,comboSize,targetsTable,comboTableToFill) | |
end | |
end | |
-- ======================= | |
-- CalcSpellPosForGroup is used to get optimal position for your AoE circle spell (annie ult, brand W, etc). | |
-- It will always return MEC with position, where spell will hit most players and where players will be staying closer to each other. | |
-- ======================= | |
function CalcSpellPosForGroup(spellRadius,spellRange,enemyTable) | |
if #enemyTable == 1 then | |
--PrintChat("Casting shit on player (inside MEC lib)") | |
return { center = { x = enemyTable[1].x, z = enemyTable[1].z } } | |
end | |
local combos = { | |
[5] = {}, -- 5-player combos | |
[4] = {}, -- 4-player combos | |
[3] = {}, -- 3-player combos | |
[2] = {}, -- 2-player combos | |
} | |
mec = MEC:New() | |
for j = #enemyTable,2,-1 do | |
CalcCombosFromString("",1,j,enemyTable,combos[j]) | |
--for i,v in ipairs(combos[j]) do | |
--printTable(v) | |
--end | |
--print(j.."-player combinations: "..#combos[j].."\n") | |
--PrintChat(j.."-player combinations: "..#combos[j]) | |
local spellPos = nil | |
for i,v in ipairs(combos[j]) do | |
mec:SetPoints(v) | |
local c = mec:Compute() | |
if c.radius <= spellRadius and (spellPos == nil or c.radius < spellPos.radius) then | |
spellPos = Circle:New() | |
spellPos.center = c.center | |
spellPos.radius = c.radius | |
--print("MEC for combo #"..i.." of "..#combos[j]..": "..spellPos:ToString()) | |
--PrintChat("MEC for combo #"..i.." of "..#combos[j]..": "..spellPos:ToString()) | |
--PrintChat("true") | |
--print() | |
end | |
end | |
if spellPos ~= nil then return spellPos end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TARGET_LOW_HP = 1 | |
TARGET_NEAR = 2 | |
TARGET_FAR = 3 | |
DAMAGE_MAGIC = 1 | |
DAMAGE_PHYSICAL = 2 | |
targetMode=" " | |
mouseRange = 400 -- distance from mouse the target must be to attack if targetMouse is true. | |
targetMouse = false --default | |
TargetSelector = {} | |
player = GetMyHero() | |
mouseArray = {} | |
Array = { --A blank array for enemies and mode flags. | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0} | |
} | |
CommandArray = { -- a Table of commands. Easier to add new word commands later. | |
{command=".ignore", targetflag=true, --targetflag true means it requires ".ignore TargetName" to work | |
method= function(i) | |
Array[i].mode = "ignore" | |
PrintChat(" >> Ignoring "..Array[i].enemy.charName) | |
end | |
}, | |
{command=".target", targetflag=true, | |
method= function(i) | |
Array[i].mode="target" | |
PrintChat(" >> Targeting "..Array[i].enemy.charName) | |
end | |
}, | |
{command=".focus", targetflag=true, | |
method= function(i) | |
local j | |
targetMode = "Priority" | |
PrintChat(" >> Priority mode activated") | |
Array[i].mode= "target" | |
PrintChat(" >> Focusing "..Array[i].enemy.charName) | |
for j=1, #Array, 1 do | |
Array[j].priorityNum = 0 | |
end | |
Array[i].priorityNum = math.huge | |
end | |
}, | |
{command=".mostap", targetflag = false, | |
method = function(i) | |
targetMode = "MostAP" | |
PrintChat(" >> Focusing non-ignored enemy with most AP!") | |
end | |
}, | |
{command=".lowhp", targetflag = false, | |
method = function(i) | |
targetMode = "LowHP" | |
PrintChat(" >> Focusing non-ignored enemy with lowest effective HP") | |
end | |
}, | |
{command=".near", targetflag = false, | |
method = function(i) | |
targetMode = "Near" | |
PrintChat(" >> Focusing the nearest non-ignored enemy") | |
end | |
}, | |
{command=".far", targetflag = false, | |
method = function(i) | |
targetMode = "Far" | |
PrintChat(" >> Focusing the furthest non-ignored enemy") | |
end | |
}, | |
{command=".printarray", targetflag = false, | |
method = function(i) | |
local i | |
for i=1,#Array, 1 do | |
if Array[i].enemy.charName ~= "###" then | |
PrintChat(" >> Enemy "..i.." : "..Array[i].enemy.charName.." Mode= "..Array[i].mode.." Priority = "..Array[i].priorityNum) | |
end | |
end | |
PrintChat(" >> Target Mode: "..targetMode) | |
if targetMouse == true then | |
PrintChat(" >> Closest to mouse") | |
end | |
end | |
}, | |
{command=".primode", targetflag = false, | |
method = function(i) | |
targetMode = "Priority" | |
PrintChat(" >> Priority mode activated.") | |
end | |
}, | |
{command=".setpriority", targetflag = true, | |
method = function(i) | |
end | |
}, | |
{command=".mouse",targetflag = false, | |
method = function(i) | |
if targetMouse == false then | |
targetMouse = true | |
PrintChat(" >> Targeting Enemies "..mouseRange.." away from mouse.") | |
else | |
targetMouse = false | |
PrintChat(" >> Mouse targeting deactivated.") | |
end | |
end | |
} | |
} | |
function TargetSelector:new(mode, range, damageType) | |
local object = { mode = mode, range = range, damageType = damageType or DAMAGE_MAGIC, target = nil, paused=false } | |
setmetatable(object, { __index = TargetSelector }) | |
if mode == TARGET_LOW_HP then --just a conversion for consistency | |
targetMode= "LowHP" | |
elseif mode == TARGET_NEAR then | |
targetMode= "Near" | |
elseif mode == TARGET_FAR then | |
targetMode= "Far" | |
end | |
return object | |
end | |
function TargetSelector:getChatCommand(text,playername) | |
local i,j,n | |
for j=1,#CommandArray,1 do | |
for i=1, #Array, 1 do | |
if string.find(text,Array[i].enemy.charName)~=nil or CommandArray[j].targetflag == false then --true if found a character name that matches an enemy OR it doesn't need a target name | |
if string.find(text,CommandArray[j].command)~=nil then --if found a given command | |
if string.find(text,"%d")~=nil then --found a number after command set priority | |
n = tonumber(string.sub(text,string.find(text,"%d"))) | |
Array[i].priorityNum = n | |
targetMode = "Priority" | |
PrintChat(""..Array[i].enemy.charName.."'s priority set to "..n) | |
PrintChat(" >> Priority mode activated.") | |
else | |
CommandArray[j].method(i) --proceed with commands actions | |
if CommandArray[j].targetflag == false then --if command was a mode change not requiring a target, then for loop breaks | |
break | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
function TargetSelector:buildarray() --populates Array with enemy champion objects | |
local count = heroManager.iCount | |
local i | |
local n=1 | |
for i = 1, count, 1 do | |
local object = heroManager:GetHero(i) | |
if object ~= nil and object.team ~= player.team then | |
Array[n].enemy = object | |
n=n+1 | |
end | |
end | |
end | |
function TargetSelector:printarray() -- will print all enemies, their mode, and the targeting mode. | |
for i=1,#Array, 1 do | |
if Array[i].enemy.charName ~= "###" then | |
PrintChat(" >> Enemy "..i.." : "..Array[i].enemy.charName.." Mode= "..Array[i].mode.." Priority = "..Array[i].priorityNum) | |
end | |
end | |
PrintChat(" >> Target Mode: "..targetMode) | |
end | |
function CalculateMagicDmg(target, spellDamage) --TODO replace this with working target:CalculateMagicDamage() in next update | |
local magicArmor = target.magicArmor - player.magicPen | |
if magicArmor > 0 then | |
magicArmor = magicArmor * (1-(player.magicPenPercent/100)) | |
else | |
magicArmor = 0 | |
end | |
return spellDamage * (100/(100+magicArmor)) | |
end | |
function TargetSelector:tick(time) | |
if targetMouse == true then | |
self:findHeroNearestMouse() | |
end | |
if self.paused then return end | |
if targetMode==" " then | |
targetMode = self.mode | |
end | |
if targetMode == "LowHP" then | |
self:low_hp() | |
elseif targetMode == "Far" then | |
self:far() | |
elseif targetMode == "Near" then | |
self:near() | |
elseif targetMode == "MostAP" then | |
self:mostAP() | |
elseif targetMode == "Priority" then | |
self:highestPriority() | |
end | |
end | |
function TargetSelector:pause() | |
self.paused = true | |
end | |
function TargetSelector:resume() | |
self.paused = false | |
end | |
function TargetSelector:highestPriority() | |
local highestP = 0 | |
local highest = nil | |
if targetMouse == true then | |
for i=1, #mouseArray, 1 do | |
if mouseArray[i].mode ~= "ignore" then | |
if self:check_if_target(mouseArray[i].enemy) then | |
if player:GetDistance(object)<=self.range then | |
if mouseArray[i].priorityNum >= highestP then | |
highest = mouseArray[i].enemy | |
highestP=mouseArray[i].priorityNum | |
end | |
end | |
end | |
end | |
end | |
else | |
for i=1, #Array, 1 do | |
if Array[i].mode ~= "ignore" then | |
if self:check_if_target(Array[i].enemy) then | |
if player:GetDistanceTo(Array[i].enemy)<=self.range then | |
if Array[i].priorityNum >= highestP then | |
highest = Array[i].enemy | |
highestP=Array[i].priorityNum | |
end | |
end | |
end | |
end | |
end | |
end | |
self.target = highest | |
end | |
function TargetSelector:low_hp() | |
local tmp | |
local count,object | |
local ignoreflag=false | |
if targetMouse == true then | |
for i = 1, #mouseArray, 1 do | |
if mouseArray[i].mode ~= "ignore" then | |
if self:check_if_target(mouseArray[i].enemy) and player:GetDistance(object) <= self.range | |
and | |
(tmp == nil or | |
((self.damageType == DAMAGE_MAGIC and tmp.health * (100/CalculateMagicDmg(tmp,100)) > mouseArray[i].enemy.health * (100/CalculateMagicDmg(mouseArray[i].enemy,100))) | |
or | |
(self.damageType == DAMAGE_PHYSICAL and tmp.health * (player.totalDamage/player:CalculateDamage(tmp)) > mouseArray[i].enemy.health * (player.totalDamage/player:CalculateDamage(mouseArray[i].enemy)))) | |
) then | |
tmp = mouseArray[i].enemy | |
end | |
end | |
end | |
else | |
if Array[1].enemy.charName == "###" then --backwards compatibility. If true, then not using updated script for text input. | |
count = heroManager.iCount | |
else | |
count = #Array | |
end | |
for i = 1, count, 1 do | |
if Array[1].enemy.charName == "###" then --backwards compatibility | |
object = heroManager:GetHero(i) | |
elseif Array[i].mode == "ignore" then | |
ignoreflag = true | |
elseif Array[i].mode ~= "ignore" then | |
ignoreflag = false | |
object = Array[i].enemy | |
end | |
if ignoreflag == false then | |
if self:check_if_target(object) and player:GetDistance(object) <= self.range | |
and | |
(tmp == nil or | |
((self.damageType == DAMAGE_MAGIC and tmp.health * (100/CalculateMagicDmg(tmp,100)) > object.health * (100/CalculateMagicDmg(object,100))) | |
or | |
(self.damageType == DAMAGE_PHYSICAL and tmp.health * (player.totalDamage/player:CalculateDamage(tmp)) > object.health * (player.totalDamage/player:CalculateDamage(object)))) | |
) then | |
tmp = object | |
end | |
end | |
end | |
end | |
self.target = tmp | |
end | |
function TargetSelector:near() | |
local nc = nil | |
local count,object | |
local smallest_dist = self.range+1 | |
local ignoreflag = false | |
if targetMouse == true then | |
for i = 1, #mouseArray, 1 do | |
if mouseArray[i].mode ~= "ignore" then | |
if self:check_if_target(mouseArray[i].enemy) then | |
local d = player:GetDistance(mouseArray[i].enemy) | |
if d<=self.range and d<smallest_dist then | |
nc = mouseArray[i].enemy | |
smallest_dist = d | |
end | |
end | |
end | |
end | |
else | |
if Array[1].enemy.charName == "###" then --backwards compatibility. If true, then not using updated script for text input. | |
count = heroManager.iCount | |
else | |
count = #Array | |
end | |
for i = 1, count, 1 do | |
if Array[1].enemy.charName == "###" then --backwards compatibility | |
object = heroManager:GetHero(i) | |
elseif Array[i].mode == "ignore" then | |
ignoreflag = true | |
elseif Array[i].mode ~= "ignore" then | |
ignoreflag = false | |
object = Array[i].enemy | |
end | |
if ignoreflag==false then | |
if self:check_if_target(object) then | |
local d = player:GetDistance(object) | |
if d<=self.range and d<smallest_dist then | |
nc = object | |
smallest_dist = d | |
end | |
end | |
end | |
end | |
end | |
self.target = nc | |
end | |
function TargetSelector:far() | |
local fc = nil | |
local biggest_dist = -1 | |
local count,object | |
local ignoreflag = false | |
if targetMouse == true then | |
for i = 1, #mouseArray, 1 do | |
if mouseArray[i].mode ~= "ignore" then | |
if self:check_if_target(mouseArray[i].enemy) then | |
local d = player:GetDistance(mouseArray[i].enemy) | |
if d<=self.range and d>biggest_dist then | |
fc = mouseArray[i].enemy | |
biggest_dist = d | |
end | |
end | |
end | |
end | |
else | |
if Array[1].enemy.charName == "###" then --backwards compatibility. If true, then not using updated script for text input. | |
count = heroManager.iCount | |
else | |
count = #Array | |
end | |
for i = 1, count, 1 do | |
if Array[1].enemy.charName == "###" then --backwards compatibility | |
object = heroManager:GetHero(i) | |
elseif Array[i].mode == "ignore" then | |
ignoreflag = true | |
elseif Array[i].mode ~= "ignore" then | |
ignoreflag = false | |
object = Array[i].enemy | |
end | |
if ignoreflag == false then | |
if self:check_if_target(object) then | |
local d = player:GetDistance(object) | |
if d<=self.range and d>biggest_dist then | |
fc = object | |
biggest_dist = d | |
end | |
end | |
end | |
end | |
end | |
self.target = fc | |
end | |
function TargetSelector:mostAP() | |
local highestAP = 0 | |
local highest = nil | |
local ignoreflag = false | |
if targetMouse == true then | |
for i=1, #mouseArray, 1 do | |
if mouseArray[i].mode ~= "ignore" then | |
if self:check_if_target(mouseArray[i].enemy) then | |
if player:GetDistance(object)<=self.range then | |
if mouseArray[i].enemy.ap >= highestAP then | |
highest = mouseArray[i].enemy | |
highestAP=mouseArray[i].enemy.ap | |
end | |
end | |
end | |
end | |
end | |
else | |
for i=1, #Array, 1 do | |
if Array[i].mode ~= "ignore" then | |
if self:check_if_target(Array[i].enemy) then | |
if player:GetDistanceTo(Array[i].enemy)<=self.range then | |
if Array[i].enemy.ap >= highestAP then | |
highest = Array[i].enemy | |
highestAP=Array[i].enemy.ap | |
end | |
end | |
end | |
end | |
end | |
end | |
self.target = highest | |
end | |
function TargetSelector:findHeroNearestMouse() | |
local i | |
local j=1 | |
mouseArray = { --A blank array for enemies near the Mouse | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0}, | |
{enemy = {charName="###"}, mode = "target", priorityNum = 0} | |
} | |
for i=1, #Array, 1 do | |
if self:check_if_target(Array[i].enemy) then | |
if (self:distanceFromMouse(Array[i].enemy) <= mouseRange) then | |
mouseArray[j].enemy = Array[i].enemy | |
mouseArray[j].mode = Array[i].mode | |
mouseArray[j].priorityNum = Array[i].priorityNum | |
j = j+1 | |
end | |
end | |
end | |
end | |
function TargetSelector:distanceFromMouse(target) | |
if target ~= nil then | |
return math.floor(math.sqrt((target.x-MousePos.x)*(target.x-MousePos.x) + (target.z-MousePos.z)*(target.z-MousePos.z))) | |
else return math.huge | |
end | |
end | |
function TargetSelector:check_if_target(obj) | |
return obj ~= nil and obj.team ~= player.team and obj.visible and not obj.dead | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Vector = { | |
-- =========================== | |
-- Sets the metatable of the "point" table to | |
-- the Vector table. Kind of like dynamic inheritance. | |
-- =========================== | |
New = function(self,...) | |
local n = table.getn(arg) | |
local point | |
if(n==1) then | |
point = arg[1] | |
if not point or type(point) ~= "table" or point.x == nil or point.z == nil then | |
return | |
end | |
end | |
if(n==2) then | |
point = {x=arg[1], z=arg[2]} | |
end | |
setmetatable(point, {__index = self, | |
__add = self.Add, | |
__sub = self.Sub, | |
__eq = self.Equals, | |
__unm = self.Negative, | |
__mul = self.Mult, | |
__div = self.Div, | |
__lt = self.Lt, | |
__le = self.Le, | |
__tostring = self.ToString}) | |
return point | |
end, | |
-- =========================== | |
-- Overload the "+" operator | |
-- =========================== | |
Add = function(self, other) | |
return Vector:New(self.x + other.x, self.z + other.z) | |
end, | |
-- =========================== | |
-- Overload the "-" operator | |
-- =========================== | |
Sub = function(self, other) | |
return Vector:New(self.x - other.x, self.z - other.z) | |
end, | |
-- =========================== | |
-- Check if the other point is the same as self. | |
-- =========================== | |
Equals = function(self, other) | |
return self.x == other.x and self.z == other.z | |
end, | |
-- =========================== | |
-- [Static] Check to see if x and y are close, as defined by eps (if it is passed) | |
-- =========================== | |
CloseTo = function(x, y, eps) | |
if not eps then | |
eps = 1e-9 | |
end | |
return math.abs(x - y) <= eps | |
end, | |
-- =========================== | |
-- [Static] Get the intersection point of lines L1=(base1,v1) L2=(base2,v2) | |
-- =========================== | |
InfLineIntersection = function(base1, v1, base2, v2) | |
if Vector.CloseTo(v1.x, 0.0) and Vector.CloseTo(v2.z, 0.0) then | |
return Vector:New({x = base1.x, z = base2.z}) | |
end | |
if Vector.CloseTo(v1.z, 0.0) and Vector.CloseTo(v2.x, 0.0) then | |
return Vector:New({x = base2.x, z = base1.z}) | |
end | |
local m1 = (not Vector.CloseTo(v1.x, 0.0)) and v1.z / v1.x or 0.0 | |
local m2 = (not Vector.CloseTo(v2.x, 0.0)) and v2.z / v2.x or 0.0 | |
if Vector.CloseTo(m1, m2) then | |
return nil | |
end | |
local c1 = base1.z - m1 * base1.x | |
local c2 = base2.z - m2 * base2.x | |
local ix = (c2 - c1) / (m1 - m2) | |
local iy = m1 * ix + c1 | |
if Vector.CloseTo(v1.x, 0.0) then | |
return Vector:New({x = base1.x, z = base1.x * m2 + c2}) | |
end | |
if Vector.CloseTo(v2.x, 0.0) then | |
return Vector:New({x = base2.x, z = base2.x * m1 + c1}) | |
end | |
return Vector:New({x = ix, z = iy}) | |
end, | |
-- =========================== | |
-- Returns a positive number if self > other, 0 if self == other, and | |
-- a negative number if self < other. | |
-- =========================== | |
CompareTo = function(self, other) | |
local ret = self.x - other.x | |
if ret == 0 then | |
ret = self.z - other.z | |
end | |
return ret | |
end, | |
-- =========================== | |
-- Scale the current point to get a new point. | |
-- =========================== | |
Scale = function(self, factor) | |
return Vector:New({x = self.x * factor, z = self.z * factor}) | |
end, | |
-- =========================== | |
-- Get the string representation of the point. | |
-- =========================== | |
ToString = function(self) | |
return "(" .. tostring(self.x) .. ", " .. tostring(self.z) .. ")" | |
end, | |
-- =========================== | |
-- Computes the angle formed by p1 - self - p2 | |
-- =========================== | |
AngleBetween = function(self, p1, p2) | |
local vect_p1 = p1 - self | |
local vect_p2 = p2 - self | |
local theta = vect_p1:Polar() - vect_p2:Polar() | |
if theta < 0.0 then | |
theta = theta + 360.0 | |
end | |
if theta > 180.0 then | |
theta = 360.0 - theta | |
end | |
return theta | |
end, | |
-- =========================== | |
-- Compute the polar angle to this point | |
-- =========================== | |
Polar = function(self) | |
theta = 0.0 | |
if Vector.CloseTo(self.x, 0) then | |
if self.z > 0 then | |
theta = 90.0 | |
elseif self.z < 0 then | |
theta = 270.0 | |
end | |
else | |
theta = math.deg(math.atan(self.z/self.x)) | |
if self.x < 0.0 then | |
theta = theta + 180.0 | |
end | |
if theta < 0.0 then | |
theta = theta + 360.0 | |
end | |
end | |
return theta | |
end, | |
-- =========================== | |
-- Gets the left normal according to self's position. | |
-- =========================== | |
NormalLeft = function(self) | |
return Vector:New({x = self.z, z = -self.x}) | |
end, | |
-- =========================== | |
-- Get the center between self and the other point. | |
-- =========================== | |
Center = function(self, otherVector) | |
return Vector:New({x = (self.x + otherVector.x) / 2, z = (self.z + otherVector.z) / 2}) | |
end, | |
-- =========================== | |
-- Get the distance between myself and the other point. | |
-- =========================== | |
Distance = function(self, otherVector) | |
local dx = self.x - otherVector.x | |
local dy = self.z - otherVector.z | |
return math.sqrt(dx * dx + dy * dy) | |
end, | |
-- =========================== | |
-- Tests if a point is left|on|right of an infinite line | |
-- return >0 for p2 left of line through p0 and p1. | |
-- return =0 for p2 on the line. | |
-- return <0 for p2 right of the line. | |
-- =========================== | |
Direction = function(p0, p1, p2) | |
return (p0.x-p1.x)*(p2.z-p1.z) - (p2.x-p1.x)*(p0.z-p1.z) | |
end, | |
-- =========================== | |
-- h0nda added staff | |
-- =========================== | |
Cross = function(self,other) | |
return self.x * other.z - self.z * other.x | |
end, | |
Negative = function(self) | |
return Vector:New({x=-1*self.x,z=-1*self.z}) | |
end, | |
Mult = function (a, b) | |
if type(a) == "number" then | |
return Vector.new({x=b.x * a, y=b.z * a}) | |
elseif type(b) == "number" then | |
return Vector:New({x=a.x * b, z=a.z * b}) | |
else | |
return Vector:New({x=a.x * b.x, z=a.z * b.z}) | |
end | |
end, | |
Div = function(a,b) | |
if type(a) == "number" then | |
return Vector.new({x=b.x / a, y=b.z / a}) | |
elseif type(b) == "number" then | |
return Vector:New({x=a.x / b, z=a.z / b}) | |
else | |
return Vector:New({x= a.x / b.x, z=a.z / b.z}) | |
end | |
end, | |
Lt = function(a,b) | |
return a.x < b.x or (a.x == b.x and a.z < b.z) | |
end, | |
Le = function(a,b) | |
return a.x <= b.x and a.z <= b.z | |
end, | |
Clone = function(self) | |
return Vector:New({x=self.x, z=self.z}) | |
end, | |
Unpack = function(self) | |
return self.x, self.z | |
end, | |
Length = function ( self ) | |
return math.sqrt(self.x * self.x + self.z * self.z) | |
end, | |
LengthSQ = function ( self) | |
return self.x * self.x + self.z * self.z | |
end, | |
Normalize = function (self ) | |
local len = self:Length() | |
self.x = self.x / len | |
self.z = self.z / len | |
return self | |
end, | |
Normalized = function (self ) | |
return self / self:Length() | |
end, | |
Rotate = function(phi) | |
local c = math.cos(phi) | |
local s = math.sin(phi) | |
self.x = c * self.x - s * self.z | |
self.z = s * self.x + c * self.z | |
return self | |
end, | |
Rotated = function(phi) | |
return self:clone():rotate(phi) | |
end, | |
Perpendicular = function() | |
return Vector:New({x=-self.z, z=self.x}) | |
end, | |
ProjectOn = function(other) | |
return (self * other) * other / other:lenSq() | |
end, | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Veigar 2.0~ by llama | |
]]-- | |
--HotKeys | |
EHK=69 --HK for "E" by default | |
cageTeamHK= 71 -- hk for "G" by default | |
spaceHK = 90 --hk for "X" by default | |
--Skill attributes | |
qrange=650 | |
eradius=350 -- event horizon's radius has bounds from 300 to 400 | |
erange=600 | |
ecastspeed=350 --calculated from tick values before and after cast of even horizon | |
wrange = 900 | |
wradius = 245 --maximum radius of W | |
wLandParticle = "dark_matter_tar" | |
DFGID = 3128 | |
--Options | |
WAfterStun = true --if true, will attempt to cast W on a stunned target | |
spacebarToWin = true --true will use full combo on ts.target | |
comboDelay = 500 --time (in ms) to delay the combo. Prevents spam of combos before the first combo is complete. | |
assumeWHits = true --assume W will hit the target it was cast towards. This will premeptively subtract wDmg from target.health, if: it is the combo's focus target and W is still in the air. | |
stealOption = true --will attempt to auto-steal with up to 3 different spells, if the target is killable. | |
drawERange=true --draws E's range+radius | |
eCircleColor = 0xB820C3 -- purple by default | |
drawWRange=true --draws W's range | |
wCircleColor = 0xEA3737 -- orange by default | |
drawQRange=true --draws Q's (or R's) range | |
qCircleColor = 0x19A712 --green by default | |
drawKillable = true --draws a few circles around a killable target with full combo | |
circleRadius = 200 --radius of circle drawn | |
circleThickness = 75 --Higher means more vibrant circle. | |
--code | |
player = GetMyHero() | |
ECastActive = false | |
cageTeamActive = false | |
spacebarActive = false | |
ticknow=0 | |
wInAir = false | |
wTarget = nil | |
comboflag = false | |
function altDoFile(name) | |
dofile(debug.getinfo(1).source:sub(debug.getinfo(1).source:find(".*\\")):sub(2)..name)end | |
altDoFile("libs/target_selector.lua") | |
altDoFile("libs/vector.lua") | |
altDoFile("libs/linear_prediction_const_t.lua") | |
altDoFile("libs/mec.lua") | |
altDoFile("libs/circle.lua") | |
lp = LinearPredictionConstT:new(erange+eradius,ecastspeed) | |
ts = TargetSelector:new( TARGET_LOW_HP,erange+eradius,DAMAGE_MAGIC ) | |
ts:buildarray() | |
playername=player.charName | |
function Timer() | |
local dis = 0 | |
local players = heroManager.iCount | |
local CircX = nil | |
local CircZ = nil | |
local i,j,stealtarget | |
ts:tick() | |
lp:tick() | |
if CanUseSpell(Slots._W) == SpellState.READY and WAfterStun then | |
castWspell() | |
end | |
if spacebarActive == true and targetvalid(ts.target) then | |
performcombo(ts.target,false) | |
end | |
if stealOption == true then | |
for i=1, players, 1 do | |
stealtarget = heroManager:GetHero(i) | |
if targetvalid(stealtarget) then | |
performcombo(stealtarget,true) | |
end | |
end | |
end | |
if ECastActive == true and CanUseSpell(Slots._E) == SpellState.READY and targetvalid(ts.target) then | |
--Begin comparing all targets to each other | |
for i=1, players, 1 do | |
for j=1, players, 1 do | |
local target1 = heroManager:GetHero(i) | |
local target2 = heroManager:GetHero(j) | |
if targetvalid(target1) and targetvalid(target2) and target1.charName ~= target2.charName then --make sure both targets are valid enemies and in spell range | |
if targetsinradius(target1,target2) and CircX == nil and CircY == nil then --true if a double stun is possible | |
CircX,CircZ = calcdoublestun(target1,target2) --calculates coords for stun | |
end | |
end | |
end | |
end | |
if CircX == nil or CircZ == nil then --true if double stun coords were not found | |
if player:GetDistance(ts.target) <= (eradius+erange) then | |
CircX,CircZ = calcsinglestun() --calculate stun coords for a single target | |
end | |
end | |
if CircX ~= nil and CircZ ~= nil then --true if any coords were found | |
player:Attack(ts.target) | |
CastSpell(Slots._E,CircX,CircZ) | |
end | |
end | |
if cageTeamActive == true and ts.target~=nil then | |
local spellPos = FindGroupCenterFromNearestEnemies(eradius,erange) | |
if spellPos ~=nil then | |
CastSpell(Slots._E,spellPos.center.x,spellPos.center.z) | |
end | |
end | |
end | |
function targetvalid(target) | |
return target ~= nil and target.team ~= player.team and target.visible and not target.dead and player:GetDistance(target) <= (eradius + erange) | |
end | |
function targetsinradius(target1,target2) | |
local dis,dis1,dis2 | |
local predicted1 = lp:getPredictionFor(target1.charName) | |
local predicted2 = lp:getPredictionFor(target2.charName) | |
if predicted1 and predicted2 then | |
dis = math.sqrt((predicted2.x-predicted1.x)^2+(predicted2.z-predicted1.z)^2) --find the distance between the two targets | |
dis1 = math.sqrt((predicted1.x-player.x)^2+(predicted1.z-player.z)^2) --distance from player to predicted target 1 | |
dis2 = math.sqrt((predicted2.x-player.x)^2+(predicted2.z-player.z)^2) --distance from player to predicted target 2 | |
end | |
return dis ~=nil and dis <= (eradius*2) and dis1 <=(eradius + erange) and dis2 <=(eradius + erange) | |
end | |
function calcdoublestun(target1,target2) | |
local CircX = nil | |
local CircZ = nil | |
local predicted1 = lp:getPredictionFor(target1.charName) | |
local predicted2 = lp:getPredictionFor(target2.charName) | |
if predicted1 and predicted2 then | |
local h1=predicted1.x | |
local k1=predicted1.z | |
local h2=predicted2.x | |
local k2=predicted2.z | |
local u = (h1)^2 + (h2)^2 - 2*(h1)*(h2) - (k1)^2 + (k2)^2 | |
local w = k1 - k2 | |
local v = h2 - h1 | |
local a = 4*(w^2 + v^2) | |
local b = 4*(u*w - 2*((v)^2)*(k1)) | |
local c = (u)^2 - 4*((v^2))*(eradius^2-k1^2) | |
local Z1 = ((-b) + math.sqrt((b)^2 - 4*a*c))/(2*a) --Z coord for first solution | |
local Z2 = ((-b) - math.sqrt((b)^2 - 4*a*c))/(2*a) --Z coord for second solution | |
local d = (Z1 - k1)^2 - (eradius)^2 | |
local e = (Z1 - k2)^2 - (eradius)^2 | |
local X1 = ((h2)^2 - (h1)^2 - d + e)/(2*v) -- X Coord for first solution | |
local p = (Z2 - k1)^2 - (eradius)^2 | |
local q = (Z2 - k2)^2 - (eradius)^2 | |
local X2 = ((h2)^2 - (h1)^2 - p + q)/(2*v) --X Coord for second solution | |
--determine if these 2 points are within range, and which is closest | |
local dis1 = math.sqrt((X1 - player.x)^2+(Z1 - player.z)^2) | |
local dis2 = math.sqrt((X2 - player.x)^2+(Z2 - player.z)^2) | |
if dis1 <= (eradius + erange) and dis1 <=dis2 then | |
CircX = X1 | |
CircZ = Z1 | |
end | |
if dis2 <= (eradius + erange) and dis2 <dis1 then | |
CircX = X2 | |
CircZ = Z2 | |
end | |
end | |
return CircX,CircZ | |
end | |
function calcsinglestun() | |
if(ts.target ~= nil ) and CanUseSpell(Slots._E) == SpellState.READY then | |
local predicted = lp:getPredictionFor(ts.target.charName) | |
if predicted then | |
local CircX=nil | |
local CircZ=nil | |
local dis=math.sqrt((player.x-predicted.x)^2+(player.z-predicted.z)^2) | |
CircX=predicted.x+eradius*((player.x-predicted.x)/dis) | |
CircZ=predicted.z+eradius*((player.z-predicted.z)/dis) | |
return CircX,CircZ | |
end | |
end | |
end | |
function Hotkey(msg,key) | |
if msg == KEY_DOWN then | |
if key == EHK then | |
ECastActive = true | |
elseif key == cageTeamHK then | |
cageTeamActive = true | |
elseif key == spaceHK then | |
spacebarActive = true | |
end | |
else | |
if key == EHK then | |
ECastActive = false | |
elseif key == cageTeamHK then | |
cageTeamActive = false | |
elseif key == spaceHK then | |
spacebarActive = false | |
end | |
end | |
end | |
function castWspell() | |
local spellPos | |
local playercount = heroManager.iCount | |
for i=1, playercount, 1 do | |
local target = heroManager:GetHero(i) | |
if targetvalid(target) then | |
local count = target.buffCount | |
for j =0, count-1, 1 do | |
if target:getBuff(j) ~= nil then | |
if string.find(target:getBuff(j), "Stun") ~= nil then | |
if player:GetDistance(target) <= wrange then | |
--spellPos = FindGroupCenterNearTarget(target,wradius,wrange) | |
if spellPos ~= nil then | |
CastSpell(Slots._W,spellPos.center.x,spellPos.center.z) | |
else | |
CastSpell(Slots._W, target) | |
end | |
--wInAir = true | |
--wTarget = target | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
function performcombo(target,stealflag) | |
local wDmg,targetHealth | |
local skillArray = {} | |
skillArray,wDmg =findSkillDamage(target) | |
targetHealth = target.health | |
if wInAir == true and assumeWHits == true and wTarget == target then --will assume W will hit the current target. | |
targetHealth = targetHealth - wDmg | |
end | |
if targetvalid(target) then --check if target is alive, etc.. | |
comboflag = false -- allows the use of a combo if set to false | |
end | |
if GetTickCount() > ticknow+comboDelay and targetHealth >= 0 then --prevents from combo spam. Delay between combos | |
--1 spell to kill | |
if comboflag == false then | |
for i=1,#skillArray, 1 do | |
if (skillArray[i].damage > targetHealth) and skillArray[i].state and targetvalid(target) then | |
CastSpell(skillArray[i].combo,target) | |
comboflag = true | |
ticknow = GetTickCount() | |
end | |
end | |
end | |
--2 spells to kill | |
if comboflag == false then | |
for j=1, #skillArray, 1 do | |
for i=1, #skillArray, 1 do | |
if i ~= j then | |
if ((skillArray[i].damage + skillArray[j].damage) > targetHealth) and skillArray[i].state and skillArray[j].state and targetvalid(target) then | |
if skillArray[i].dfgFlag == true then --want to use dfg first in the combo, if possible | |
CastSpell(skillArray[i].combo,target) | |
elseif skillArray[j].dfgFlag == true then | |
CastSpell(skillArray[j].combo,target) | |
end | |
CastSpell(skillArray[i].combo,target) --use combo, dfg will already be on CD if ready | |
CastSpell(skillArray[j].combo,target) | |
comboflag = true | |
ticknow = GetTickCount() | |
end | |
end | |
end | |
end | |
end | |
-- 3 spells to kill | |
if comboflag == false then | |
for k=1, #skillArray, 1 do | |
for j=1, #skillArray, 1 do | |
for i=1, #skillArray, 1 do | |
if i~=j and i~=k and j~=k then | |
if ((skillArray[i].damage + skillArray[j].damage + skillArray[k].damage) > targetHealth) and skillArray[i].state and skillArray[j].state and skillArray[k].state and targetvalid(target) then | |
if skillArray[i].dfgFlag == true then --want to use dfg first in the combo, if possible | |
CastSpell(skillArray[i].combo,target) | |
elseif skillArray[j].dfgFlag == true then | |
CastSpell(skillArray[j].combo,target) | |
elseif skillArray[k].dfgFlag == true then | |
CastSpell(skillArray[k].combo,target) | |
end | |
CastSpell(skillArray[i].combo,target) --use combo, dfg will already be on cd, if ready. | |
CastSpell(skillArray[j].combo,target) | |
CastSpell(skillArray[k].combo,target) | |
comboflag = true | |
ticknow = GetTickCount() | |
end | |
end | |
end | |
end | |
end | |
end | |
---- Usese 4 spells, even if the kill is not possible | |
if comboflag == false and targetvalid(target) and stealflag == false then --will only use all four spells if spacebar is active | |
for i=1, #skillArray, 1 do | |
if skillArray[i].dfgFlag == true and skillArray[i].state then --use dfg first in combo | |
CastSpell(skillArray[i].combo,target) | |
end | |
end | |
for i=1, #skillArray, 1 do | |
CastSpell(skillArray[1].combo,target) --use combo, dfg will already be on cd, if ready. | |
CastSpell(skillArray[2].combo,target) | |
CastSpell(skillArray[3].combo,target) | |
CastSpell(skillArray[4].combo,target) | |
comboflag = true | |
ticknow = GetTickCount() | |
end | |
end | |
end | |
end | |
function findSkillDamage(target) | |
local i, invSlot, igniteSlot, igniteDmg, qDmg, wDmg, rDmg, dfgDmg | |
local ItemSlot = {Slots.ITEM_1,Slots.ITEM_2,Slots.ITEM_3,Slots.ITEM_4,Slots.ITEM_5,Slots.ITEM_6,} | |
local skillArray = {} | |
local totalDmg = 0 | |
for i=1, #ItemSlot, 1 do | |
if player:getInventorySlot(ItemSlot[i]) == (DFGID) then | |
invSlot = ItemSlot[i] | |
end | |
end | |
if invSlot ~= nil then | |
dfgDmg = (.25+(.04*(math.floor(player.ap/100))))*target.health | |
if dfgDmg < 200 then | |
dfgDmg = 200 | |
end | |
elseif invSlot == nil then | |
dfgDmg = 0 | |
end | |
if GetSpellData(Slots.SUMMONER_1).name == "SummonerDot" then | |
igniteSlot = Slots.SUMMONER_1 | |
elseif GetSpellData(Slots.SUMMONER_2).name == "SummonerDot" then | |
igniteSlot = Slots.SUMMONER_2 | |
end | |
if igniteSlot ~=nil then | |
igniteDmg = 50 + 20 * player.level | |
else | |
igniteDmg = 0 | |
end | |
qDmg = player:CalcMagicDamage(target, 45*(GetSpellData(Slots._Q).level-1)+80+ (.6*player.ap)) | |
wDmg = player:CalcMagicDamage(target, 50*(GetSpellData(Slots._W).level-1)+120+ (1*player.ap)) | |
rDmg = player:CalcMagicDamage(target, 125*(GetSpellData(Slots._R).level-1)+250+ (1.2*player.ap) + (.8 * target.ap)) | |
skillArray = { | |
{damage = qDmg, state = CanUseSpell(Slots._Q) == SpellState.READY, combo = Slots._Q, dfgFlag = false}, | |
{damage = dfgDmg, state = false, combo = invSlot, dfgFlag = true}, | |
{damage = igniteDmg, state = false, combo = igniteSlot, dfgFlag = false}, | |
{damage = rDmg, state = CanUseSpell(Slots._R) == SpellState.READY, combo = Slots._R, dfgFlag = false} | |
} | |
if invSlot ~= nil then | |
skillArray[2].state = CanUseSpell(invSlot) == SpellState.READY | |
end | |
if igniteSlot ~=nil then | |
skillArray[3].state = CanUseSpell(igniteSlot) == SpellState.READY | |
end | |
--calculate total damage possible | |
for i=1, #skillArray, 1 do | |
if skillArray[i].state then | |
totalDmg = totalDmg + skillArray[i].damage | |
end | |
end | |
if CanUseSpell(Slots._W) == SpellState.READY and CanUseSpell(Slots._E) then | |
totalDmg = totalDmg + wDmg | |
end | |
skillArray.total = totalDmg | |
return skillArray,wDmg | |
end | |
function Drawer() | |
local i,j,players,qDmg | |
if drawQRange==true then | |
DrawCircle(player.x, player.y, player.z, qrange, qCircleColor) | |
end | |
if drawWRange==true then | |
DrawCircle(player.x,player.y,player.z, wrange, wCircleColor) | |
end | |
if drawERange==true then | |
DrawCircle(player.x,player.y,player.z, erange+eradius, eCircleColor) | |
end | |
if drawKillable == true then | |
players = heroManager.iCount | |
for i=1, players, 1 do | |
target = heroManager:GetHero(i) | |
if target~= nil then | |
if target.team ~= player.team and target.visible and not target.dead then | |
skillArray,wDmg = findSkillDamage(target) | |
if skillArray ~= nil then | |
if skillArray.total > target.health then | |
for j = 0, circleThickness do | |
DrawCircle(target.x, target.y, target.z, circleRadius + j*2, 0xFFFF0000) | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
function test(text) | |
ts:getChatCommand(text,playername) | |
end | |
function DetectWLand(object) | |
if string.find(object.charName,wLandParticle)~=nil then | |
wInAir = false | |
end | |
end | |
if player.charName == "Veigar" then | |
BoL:addMsgHandler(Hotkey) | |
BoL:addTickHandler(Timer,100) | |
BoL:addDrawHandler(Drawer) | |
BoL:addChatHandler(test) | |
BoL:addCreateObjHandler(DetectWLand) | |
PrintChat(" >> Veigar's Super Fun House 2.0 loaded!") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment