---@diagnostic disable: lowercase-global
require("libs.enum")

local Enum = GetEnums()
local G_OBS_BYPASS = dota.ObsByPass()
local floor = math.floor
local screen = dota.GetScreenSize()
local screenx = screen.x/1920
local screeny= screen.y/1080

MAX_NUMBER = 0xFFFFFFFF
OBS_HERO = -1
MyVisible = false

--// Obs
function ObsByPass() return G_OBS_BYPASS end 
function IsVisibleByEnemyTeam(v,ret) return MyVisible end --dota.GetVisabilityStatus(v:GetIndex())
function IsVisibleByEnemyTeam2(v,ret) return ret end--dota.GetVisabilityStatus(v:GetIndex()) end


function SelectLanguages(set)
	if set and set["Languges"] == false then
		for i,v in ipairs(Enum.languages) do 
			if set["l"..v]==false then 
				return v
			end 
		end 
	end 
	return dota.GetLanguage()
end 

function GetLocalHero(handle)
	if not handle and OBS_HERO < 1 then 
		return 
	end
	local pl = dota.GetLocalPlayer()
	if not pl or (pl:GetPlayerId()~=-1 and pl:GetPlayerId()<10) then 
		OBS_HERO = -1
		return
	end 
	if handle then 
		if tonumber(handle) and tonumber(handle)>0 then 
			local heros = dota.GlobalInstanceManager:GetClientEntityList():GetClientEntityFromHandle(handle)
			if heros then 
				return dota.EntityToBaseNPCHero(heros)
			end 
		end 
	elseif OBS_HERO > 0 then
		local heros = dota.GlobalInstanceManager:GetClientEntityList():GetClientEntityFromHandle(OBS_HERO)
		if heros then 
			return dota.EntityToBaseNPCHero(heros)
		end 
	end
end 

function PrettyName(name)
	name = name:gsub("_30lvl","")
	name = name:gsub("_custom","")
	name = name:gsub("_lua","")
	return name
end 

--// Camera
function MoveCamera(pos)
	--dota.ExecuteCommand("dota_camera_set_lookatpos "..math.floor(pos.x).." "..math.floor(pos.y))
	camera.SetCameraEx(pos.x,pos.y)
	if newHum.IsNewHum() then
		newHum.ResetCamera()
	end
end

--// NPC Ability
function TalantNameToEnum(self,name,other_value)
	local num = 0
	for f = Enum.SLOT_SPELL_VISIBLE + 1, Enum.SLOT_SPELL_MAX do 
		local spell = self:GetAbility(f)
		if spell then 
			if spell:IsTalant() then					
				if spell:GetName()== name then 
					local data = {}
					data.enum = 2^num
					data.value = spell:GetLevelSpecialValue("value",1) 
					if data.value == 0 then 
						data.value = other_value
					end
					if data.value == nil then 
						return false 
					end
					return data
				end 
				num = num + 1 
			end 
		else 
			return false
		end 
	end 
	return false
end 


function FindSpellMax(self,spellName)
	for i = 1, Enum.SLOT_SPELL_MAX do
		local ability = self:GetAbility(i)
		if ability then
			if ability:GetName()==spellName then
				return ability
			end
		elseif i > 6 then
			break
		end
	end
	return false
end

function FindSpellOnMap(tab,team,name,ent)
	if not tab then 
		tab = dota.FindEntities(dota.kDotaBaseNPCHero)
	end
	for i,v in ipairs(tab) do 
		if not v:IsIllusion() and (not team or v:IsTeam(team)) then 
			local spell = FindSpellMax(v,name)
			if spell then 
				if ent then 
					return spell,v 
				else
					return spell
				end
			end 
		end
	end 
end 

function GetUlt(self)
	local ult = self:GetAbility(6)
	if ult and not ult:IsUlt() then
		return self:GetAbility(7)
	end 
	return ult
end


--// KeyCode
function KeyCode(code,needbyte)
	if needbyte then 
		if not code or code == "" then 
			return ""
		end 
		code = string.byte(code)
	end	

	if code >= 112 and code <=132 then  
		return "F"..tostring(code-111)
	elseif code >= 96 and code <= 105 then  
		return "N"..tostring(code-96)
	elseif code == 32 then 
		return "Sp"
	elseif code == 8 then 
		return "Bs"
	elseif code == 9 then 
		return "Tb"
	elseif code == 16 then 
		return "Sh"
	elseif code == 20 then 
		return "Cl"
	elseif code == 134 then 
		return "M4"
	elseif code == 135 then 
		return "M5"
	elseif code == 192 then 
		return "~"
	elseif code == 17 then 
		return "Cn"	
	elseif code == 13 then 
		return "En"
	elseif code == 27 then 
		return "♦"

	elseif code == 219 then 
		return "{"
	elseif code == 221 then 
		return "}"
	elseif code == 222 then 
		return "'"	
	elseif code == 226 or code == 220 then 
		return "|"

	elseif code == 37 then 
		return "←"
	elseif code == 38 then 
		return "↑"
	elseif code == 39 then 
		return "→"
	elseif code == 40 then 
		return "↓"

	elseif code == 106 then 
		return "*"
	elseif code == 107 then 
		return "+"
	elseif code == 111 then 
		return "/"
	elseif code == 109 then 
		return "-"

	else
		return string.char(code)
	end 
end 

--// Items
function FindItem(self,itemName)
	return FindItemInventory(self:GetInventory(),itemName)
end

function FindItemInventory(inventory,itemName)
	if not inventory then return false end
	for i = 0, Enum.SLOT_ITEM_NORMAL do
        local item = inventory:GetItemInSlot(i)
        if item and item:GetName() == itemName then
			return item
        end
	end
	local item = inventory:GetItemInSlot(Enum.SLOT_NEUTRAL)
	if item and item:GetName() == itemName then
		return item
	end
	return false
end

function FindItemFn(self,fn)
	local inventory = self:GetInventory()
	for i = 0, Enum.SLOT_ITEM_NORMAL do
        local item = inventory:GetItemInSlot(i)
        if item and fn(item:GetName()) then
			return item
        end
	end
	local item = inventory:GetItemInSlot(Enum.SLOT_NEUTRAL)
	if item and fn(item:GetName()) then
		return item
	end
	return false
end

function GetTp(self)
	return self:GetInventory():GetItemInSlot(Enum.SLOT_ITEM_TP)
end 

function FindDagon(self)
	local name_fn = function(x) return x:sub(1,10) == "item_dagon" end
	return FindItemFn(self,name_fn)
end

function FindNecro(self)
	local name_fn = function(x) return x:sub(1,8) == "item_nec" end
	return FindItemFn(self,name_fn)
end

function FindTravel(self)
	local name_fn = function(x) return x:sub(1,17) == "item_travel_boots" end
	return FindItemFn(self,name_fn)
end 

--// BLINK
function GetBlink(self,option)
	if option then return false end
	return FindItemFn(self,IsBlinkName)
end
function IsBlinkName(name)
	return name == "item_blink" or name == "item_overwhelming_blink" or name == "item_swift_blink" or name == "item_arcane_blink"
end 
function IsBlinkModifier(name)
	return name == "modifier_item_blink_dagger" or name == "modifier_item_overwhelming_blink" or name == "modifier_item_swift_blink" or name == "modifier_item_arcane_blink"
end 
function GetFullBlinkRange(blink)
	if not blink then 
		return 0 
	end 
	return blink:GetCastRange() - 6
end

--// EUL
function GetEul(self,option)
	if option then return false end
	return FindItemFn(self,IsEulName)
end
function IsEulName(name)
	return name == "item_cyclone" or name == "item_wind_waker"
end 

--// Atos
local function IsAtosName(name)
	return name == "item_rod_of_atos" or name == "item_gungir"
end 
function GetAtos(self,option)
	if option then return false end
	return FindItemFn(self,IsAtosName)
end

--// Hood
local function IsHoodName(name)
	return name == "item_pipe" 
end 
function GetHood(self,option)
	if option then return false end
	return FindItemFn(self,IsHoodName)
end

--// Orchid
local function IsOrchidName(name)
	return name == "item_orchid" or name == "item_bloodthorn" or name == "item_basher_bloodthorn_monkey_king_bar"
end 
function GetOrchid(self,option)
	if option then return false end
	return FindItemFn(self,IsOrchidName)
end

--// Diffuse
local function IsDiffusalName(name)
	return name == "item_diffusal_blade" or name == "item_disperser" or name == "item_disperser_desolator_lesser_crit"
end 
function GetDiffusal(self,option)
	if option then return false end
	return FindItemFn(self,IsDiffusalName)
end

local function IsUrnName(name)
	return name == "item_urn_of_shadows" or name == "item_spirit_vessel" or name == "item_essence_distiller"
end 
function GetUrn(self,option)
	if option then return false end
	return FindItemFn(self,IsUrnName)
end


--// Particles
function CreateColorCircle(attach,target,pos,color,range,alpha,dota_alpha)
	if not ObsByPass() then 
		local eff = dota.CreateParticle("materials/NtUI/particles/radius_main.vpcf",attach,target)
		if pos then 
			eff:SetControlPoint(0, pos)
		end
		if color then
			eff:SetControlPoint(1, color)
		end
		eff:SetControlPoint(2, dota.Vector(range,  alpha or 255, 255))
		if dota_alpha then 
			eff:SetControlPoint(3, dota.Vector(dota_alpha, 0, 0))
		end 
		return eff
	else 
		if not color then color = dota.Vector(255,255,255)	end 
		return DrawCircle(pos,range*1.1,24,3,rgbToHex(color),true,target,dota.Vector(0,0,0))
	end 
end 

function CreateCircleTimer(attach,target,pos,color,range,timer)
	if not ObsByPass() then 
		local eff = dota.CreateParticle("materials/NtUI/particles/generic_timer.vpcf",attach,target)
		if pos then 
			eff:SetControlPoint(0, pos)
		end
		eff:SetControlPoint(1, dota.Vector(range-50, 1.01/timer, 0)) -- скорость
		if color then
			eff:SetControlPoint(15, color) -- цвет таймера
		end
		
		eff:SetControlPoint(14, dota.Vector(0,0,0)) -- цвет обводки
		eff:SetControlPoint(16, dota.Vector(1, 0, 0)) -- фикс цвета
		return eff
	else 
		return CreateColorCircle(attach,target,pos,color,range,nil)
	end 
end 

function CreateTowerParticle(source,target)
	if not ObsByPass() then 
		-- if another_effect then
		-- 	local particles = dota.CreateParticle("particles/units/heroes/hero_void_spirit/planeshift/void_spirit_planeshift_untargetable_ground.vpcf",Enum.PATTACH_ROOTBONE_FOLLOW,target)
		-- 	particles:SetControlPoint(0,target:GetAbsOrigin())
		-- 	return particles
		-- else
		local particles = dota.CreateParticle("particles/ui_mouseactions/range_finder_tower_aoe.vpcf",Enum.PATTACH_CUSTOMORIGIN,target)
		particles:SetControlPoint(6, dota.Vector(1, 0, 0))

		particles:SetControlPoint(2, source:GetAbsOrigin())
		particles:SetControlPoint(7, target:GetAbsOrigin())

		-- particles:SetParticleControlEnt(2, source, Enum.PATTACH_ABSORIGIN_FOLLOW, "follow_origin",dota.Vector(0,0,0),false)
		-- particles:SetParticleControlEnt(7, target, Enum.PATTACH_ABSORIGIN_FOLLOW, "follow_origin",dota.Vector(0,0,0),false)
		return particles
	else 
		local rat = screen.y/1440
		return DrawRect(-24*rat,-115*rat,50*rat,50*rat,Enum.WHITE,GetTextureId("NtUI/other/arrow_green_down.png"),true,target,dota.Vector(0,0,target:GetHealthbarOffset()))
	end 
end 

function CreateRectParticle(from,to,size,color)
	local particle = dota.CreateParticle("materials/NtUI/particles/new_rect.vpcf", Enum.PATTACH_CUSTOMORIGIN, nil)
	particle:SetControlPoint(0,to) 
	particle:SetControlPoint(1,to)
	particle:SetControlPoint(2,from)
	particle:SetControlPoint(3,dota.Vector(size/2,size/2,0)) --size
	--particle:SetControlPoint(5,color) --color
	return particle
end 

function CreateArrowParticle(pos,rate,force)
	local eff
	if ObsByPass() or force then
		eff = DrawRect(-15*rate,-15*rate,30*rate,30*rate,force or Enum.WHITE,GetTextureId("NtUI/other/arrow_green_down.png"))
		eff.vector = pos
		eff.vectorPosition = dota.Vector( 0, 0, dota.GetGroundHeight(pos))
	else
		eff =  dota.CreateParticle("particles/newplayer_fx/npx_moveto_arrow.vpcf",Enum.PATTACH_CUSTOMORIGIN,nil)
		eff:SetControlPoint(0, dota.Vector( pos.x, pos.y, dota.GetGroundHeight(pos)+25))
	end
	return eff
end

function DestroyParticle(particle)
	if not particle or particle == true then 
		return 
	end
	if particle.color then 
		DestroyImg(particle)
		return
	end 
	particle:Destroy()
end 



--// Draw 
function IsMouseOnButton(obj)
	local m = dota.GetMousePosition()
    return m.x > obj.x and m.x <= obj.x + obj.w and m.y > obj.y and m.y <= obj.y + obj.h
end

function IsMouseOnButtonLeft(obj,left)
	local m = dota.GetMousePosition()
    return m.x > obj.x and m.x <= obj.x + obj.w + left and m.y > obj.y and m.y <= obj.y + obj.h
end

function IsMouseOnEntityButton(obj)	
	local ent = obj:GetEntity()
	if ent then 
		local m = dota.GetMousePosition()
		local toworld = dota.WorldToScreen(ent:GetAbsOrigin(),obj.entityPosition)	
		return m.x > toworld.x+obj.x and m.x <= toworld.x+obj.x + obj.w and m.y > toworld.y+obj.y and m.y <= toworld.y+obj.y + obj.h
	end 
end

function IsMouseOnGroundButton(obj)
	local m = dota.GetMousePosition()
	local toworld = dota.WorldToScreen(obj.vector,obj.vectorPosition)	
	return m.x > toworld.x+obj.x and m.x <= toworld.x+obj.x + obj.w and m.y > toworld.y+obj.y and m.y <= toworld.y+obj.y + obj.h
end

function DrawRect(x,y,w,h,color,texture,visible,hand,offset)
	local img =  nil
	if x and y and h and w and color then
		if texture == 0 then
			img = dota.CreateRect(x,y,w,h,color,true,0)
		elseif texture == -1 then
			img = dota.CreateRect(x,y,w,h,color,false,0)
		else
			img = dota.CreateRect(x,y,w,h,color,false,texture)
		end
		if visible == false then
			img.visible = false
		end	
		if hand then
			img.entityHandle = hand:GetHandle()
			img.entityPosition = offset
			img.textureName = hand:GetName()
		end
		return img
	end
end

function DrawRound(x,y,w,h,color,texture,visible,rounded,border,thick)
	local img =  nil
	if x and y and h and w and color then
		if texture == 0 then
			img = dota.CreateRect(x,y,w,h,color,true,0)
		elseif texture == -1 then
			img = dota.CreateRect(x,y,w,h,color,false,0)
		else
			img = dota.CreateRect(x,y,w,h,color,false,texture)
		end
		if visible == false then
			img.visible = false
		end	
		img.rounded = rounded or img.rounded 
		img.border = border or img.border 
		img.thick = thick or img.thick 
		return img
	end
end

function RoundedImage(img,rounded,border,thick)
	img.rounded = rounded or img.rounded 
	img.border = border or img.border 
	img.thick = thick or img.thick 
end 

function ProcentImage(img,timer_type,border,procent)
	img.timer_type = timer_type or img.timer_type 
	img.procent = procent or img.procent 
	img.border = border or img.border 
	return true
end 

function DrawFastGroundImage(size,ent,spellName) --for OBS
	local img = DrawRect(size/2*(-1),size/2*(-1),size,size,0xffffff99,spellName,true)
	RoundedImage(img,10)
	if ent.x then 
		img.vector = ent
		img.vectorPosition = dota.Vector( 0, 0, 0)
		return img
	else 
		img.entityHandle = ent:GetHandle()
		img.entityPosition = dota.Vector(0,0,ent:GetHealthbarOffset())
		return img
	end
end

function DrawText(x,y,color,text,font,visible,hand,offset)
	if x and y and color and text and font then
		local img =  dota.CreateText(x,y,color,text,font)
		if visible == false then
			img.visible = false
		end
		if hand then
			img.entityHandle = hand:GetHandle()
			img.entityPosition = offset
		end
		return img
	end
end	

function DrawLine(x,y,x1,y1,color,width,visible,hand,offset,hand2,offset2) --wtf broken
	if x and y and color then
		local img =  d3d.CreateLine(x,y,x1,y1,color)
		if visible == false then
			img.visible = false
		end
		if width then
			img.width = width
		end
		if hand then
			img.entityHandle = hand
			img.entityPosition = offset
			img.vector = hand2
			img.vectorPosition = offset2
		end
		return img
	end
end	

function DrawLineCommon(x,y,x1,y1,color,width,visible,hand,offset,hand2,offset2) --wtf broken
	if x and y and color then
		local img =  dota.CreateLine(x,y,x1,y1,color)
		if visible == false then
			img.visible = false
		end
		if width then
			img.width = width
		end
		if hand then
			img.entityHandle = hand
			img.entityPosition = offset
			img.vector = hand2
			img.vectorPosition = offset2
		end
		return img
	end
end	

function DrawLineGround(pos_1,pos_2,width,color)
	local pos1 = dota.Vector(pos_1.x,pos_1.y,0)
	local pos2 = dota.Vector(pos_2.x,pos_2.y,0)
	return DrawLine(0,0,0,0,color,width,true,pos1,dota.Vector(0,0,dota.GetGroundHeight(pos1)),
		pos2,dota.Vector(0,0,dota.GetGroundHeight(pos1)))
end 

function DrawCircle(pos,radius,sideCount,width,color,visible,hand,offset)
	local img =  d3d.CreateCircle(pos or dota.Vector(0,0,0),radius/1.1+10,sideCount,color)
	if visible ~= nil then
		img.visible = visible
	end
	img.width = width
	img.vectorPosition = offset or dota.Vector(0,0,0)
	if hand then
		img.entityHandle = hand:GetHandle()
	end 
	return img
end	

function GetTextureId(name)
	return dota.GetTextureId(name) 
end 

function GetTextureId2(name,minicon)
	if name:startWith("item_") then 
		return dota.GetTextureId("panorama/images/items/"..name:removeItem().."_png.vtex_c")
	elseif name:startWith("npc_dota_") then 
		if not minicon then 
			return dota.GetTextureId("panorama/images/heroes/"..name.."_png.vtex_c")
		else 
			return dota.GetTextureId("panorama/images/heroes/icons/"..name.."_png.vtex_c")
		end
	elseif name:startWith("panorama/") or name:startWith("NtUI/") then 
		return dota.GetTextureId(name)
	else 
		if name == "kez_switch_weapons" then
			return dota.GetTextureId("panorama/images/spellicons/"..name.."_sai_png.vtex_c")
		elseif name == "shredder_twisted_chakram" then
			return dota.GetTextureId("panorama/images/spellicons/shredder_chakram_2_png.vtex_c")
		else
			return dota.GetTextureId("panorama/images/spellicons/"..name.."_png.vtex_c")
		end
	end
end 


function DestroyImg(img)
	if not img or not img.visible then 
		return 
	end
	img.visible = false
end 


--//  UI positions
function LoadHudPosition(screen)
	--size from start = 86,50,33
	--104,64,42
	local size = math.floor(screen.x/screen.y*100)
	local tab = {}
	if size == 233 then
		tab.x = 1834 
		tab.y = 786
		tab.top_panel_size = 45
		tab.top_panel_down = 30
		tab.top_panel_center = 158
		tab.mana_x = 38
		tab.mana_y = 12
		tab.mana_size = 75
		return tab	
	elseif size > 233 then --2.38 (21:9)
		tab.x = 2560 
		tab.y = 1080
		tab.top_panel_size = 62.5
		tab.top_panel_down = 40
		tab.top_panel_center = 210
		tab.mana_x = 52
		tab.mana_y = 20
		tab.mana_size = 102
		return tab
	elseif size == 177 then --16x9
		tab.x = 1600 
		tab.y = 900
		tab.top_panel_size = 52
		tab.top_panel_down = 34
		tab.top_panel_center = 176
		tab.mana_x = 43
		tab.mana_y = 15
		tab.mana_size = 86
		return tab
	elseif size == 166 then
		tab.x = 1280 
		tab.y = 768
		tab.top_panel_size = 44
		tab.top_panel_down = 30
		tab.top_panel_center = 154
		tab.mana_x = 37
		tab.mana_y = 11
		tab.mana_size = 74
		return tab
	elseif size == 160 then
		tab.x = 1280 
		tab.y = 800
		tab.top_panel_size = 46
		tab.top_panel_down = 30
		tab.top_panel_center = 160
		tab.mana_x = 39
		tab.mana_y = 13
		tab.mana_size = 78
		return tab
	elseif size == 156 then
		tab.x = 1600 
		tab.y = 1024
		tab.top_panel_size = 60
		tab.top_panel_down = 40
		tab.top_panel_center = 200		
		tab.mana_x = 49
		tab.mana_y = 17
		tab.mana_size = 98
		return tab
	elseif size == 133 then
		tab.x = 1280 
		tab.y = 960
		tab.top_panel_size = 55
		tab.top_panel_down = 35
		tab.top_panel_center = 192
		tab.mana_x = 46
		tab.mana_y = 15
		tab.mana_size = 90
		return tab
	elseif size == 125 then
		tab.x = 1280 
		tab.y = 1024
		tab.top_panel_size = 55.5
		tab.top_panel_down = 38
		tab.top_panel_center = 192
		tab.mana_x = 49
		tab.mana_y = 17
		tab.mana_size = 98
		return tab
	else
		tab.x = 1600 
		tab.y = 900
		tab.top_panel_size = 52.5
		tab.top_panel_down = 33
		tab.top_panel_center = 174		
		tab.mana_x = 42
		tab.mana_y = 18
		tab.mana_size = 84
		return tab
	end
end

function OnScreen(vec,z)
	local toworld = dota.WorldToScreen(vec,dota.Vector(0,0,z or 0))
	return toworld.x > 70*screenx and toworld.y > 70*screeny and toworld.x < screen.x-55*screenx and toworld.y < screen.y-55*screeny
end

function OnScreenEnt(ent)
	local offset = ent:IsDotaNPC() and ent:GetHealthbarOffset()/3 or 35
	return OnScreen(ent:GetAbsOrigin(),offset)
end

--// Engine
function IsDay(only_cycle)
	if only_cycle then 
		local inst = dota.GameRules.GetInstance()
		local cycl = inst:GetPropertyInt("C_DOTAGamerules","m_iNetTimeOfDay") * 0.000015259022
		local day_start = inst:GetPropertyFloat("C_DOTAGamerules","m_flDaytimeStart") 		--0.25 0.775005
		local night_start = inst:GetPropertyFloat("C_DOTAGamerules","m_flNighttimeStart") 	--0.75 0.250000
		if day_start < night_start then --без баланара аспекта
			return (cycl > day_start and cycl < night_start)
		else 
			return (cycl < night_start or cycl > day_start)
		end
	end 
	return dota.IsDayTime()
end 

function IsBearName(name)
	return name == "C_DOTA_Unit_SpiritBear"
end 

function TimeToString(time)
	if tonumber(time)<=0 then 
		return "0:00"
	end
    local sec = time % 60
    local min = math.floor(time / 60) % 60 --SECOND_OF_MINUTE  
	if math.abs(min)< 10 then 
		return string.format("%2d:%02d", min, sec)
	else
		return string.format("%02d:%02d", min, sec)
	end
end


function HasFlag(x,p)
	if not x or not p then
		aaa("HasFlag missing arg")
		return false
	end
	return bit.band(x, p) == p
end

function Tern(fal,one,two)
	if fal then 
		return one 
	else 
		return two
	end 
end 

function round(num, idp)
  local mult = 10^(idp or 0)
  return floor(num * mult + 0.5) / mult
end

function rgbToHex(rgb)
	if not rgb then return 0xffffff99 end
	local hexadecimal = '0X'
	local arrray = {rgb.x,rgb.y,rgb.z}
	for key, value in pairs(arrray) do
		local hex = ''

		while(value > 0)do
			local index = math.fmod(value, 16) + 1
			value = math.floor(value / 16)
			hex = string.sub('0123456789ABCDEF', index, index) .. hex			
		end

		if(string.len(hex) == 0)then
			hex = '00'

		elseif(string.len(hex) == 1)then
			hex = '0' .. hex
		end

		hexadecimal = hexadecimal .. hex
	end

	return hexadecimal .. '60'
end

function GetAllEntities(name)
	local temp = {}
	local entity_system = dota.GlobalInstanceManager:GetClientEntityList() 
	for i = 0,30000 do 
		local ent = entity_system:GetClientEntity(i)
		-- Force Crash
		-- if ent and dota.EntityToBaseNPC(ent):GetHealthRegen() then 
		-- 	aaa(ent:GetBaseClassName())
		-- end 
		if ent and ent:GetBaseClassName()==name then 			
			temp[#temp+1] = ent			
		end 
	end 
	return temp
end 

local textColors = 0xFFCCCCFF
function aaa(val,write)	
	if val==nil then val = "No Value" end
	if type(val) == "userdata" and val.x then 
		val = val.x.." x "..val.y
	end
	local pint_value = ""
	if type(val) == "table" then 
		for i,v in pairs(val) do 
			if type(v) == "table" then 
				local str = "["
				for z,x in pairs(v) do 
					if type(x) ~= "table" then
						str = str..z.."="..tostring(x).." ,"
					else
						str = str..z.."= table,"
					end 
				end 
				v = str.."]"
			end
			pint_value = tostring(v).." , "..tostring(v)			
		end
		--val = print_table(val)
	end 
	local str = pint_value.."   "..tostring(val).."\n"
	if write then
		log.Write(str)
	end
	if textColors == 0xFFCCCCFF then 
		textColors = 0xCCFFCCFF
	else 
		textColors = 0xFFCCCCFF
	end 
	log.ColorMsg(textColors,str)
	return true
end

function print_address(me)
	if not me then return end
	aaa(string.format("%x", log.GetAddress(me)))
end
 
function print_table(node)
    local cache, stack, output = {},{},{}
    local depth = 1
    local output_str = "{\n"

    while true do
        local size = 0
        for k,v in pairs(node) do
            size = size + 1
        end

        local cur_index = 1
        for k,v in pairs(node) do
            if (cache[node] == nil) or (cur_index >= cache[node]) then

                if (string.find(output_str,"}",output_str:len())) then
                    output_str = output_str .. ",\n"
                elseif not (string.find(output_str,"\n",output_str:len())) then
                    output_str = output_str .. "\n"
                end

                -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
                table.insert(output,output_str)
                output_str = ""

                local key
                if (type(k) == "number" or type(k) == "boolean") then
                    key = "["..tostring(k).."]"
                else
                    key = "['"..tostring(k).."']"
                end

                if (type(v) == "number" or type(v) == "boolean") then
                    output_str = output_str .. string.rep('\t',depth) .. key .. " = "..tostring(v)
                elseif (type(v) == "table") then
                    output_str = output_str .. string.rep('\t',depth) .. key .. " = {\n"
                    table.insert(stack,node)
                    table.insert(stack,v)
                    cache[node] = cur_index+1
                    break
                else
                    output_str = output_str .. string.rep('\t',depth) .. key .. " = '"..tostring(v).."'"
                end

                if (cur_index == size) then
                    output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
                else
                    output_str = output_str .. ","
                end
            else
                -- close the table
                if (cur_index == size) then
                    output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
                end
            end

            cur_index = cur_index + 1
        end

        if (size == 0) then
            output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
        end

        if (#stack > 0) then
            node = stack[#stack]
            stack[#stack] = nil
            depth = cache[node] == nil and depth + 1 or depth - 1
        else
            break
        end
    end

    -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
    return output_str
end

function print_vertor(vec)
	return math.floor(vec.x).."x"..math.floor(vec.y).."x"..math.floor(vec.z)
end 

--// PLAYERs Heroes Talants
local all_heroes_names = nil
function GetAllHeoresName()
	if not all_heroes_names then
		all_heroes_names = ReadLines(dota.GetLuaPath().."scripts/libs/all_heroes.txt")
	end
	return all_heroes_names
end 

local nameCache = {}
function FindHero(id)
	if id == -1 or id == 0 then 
		return "npc_dota_hero_default"
	end
	if not nameCache[id] then 
		for i,v in ipairs(GetAllHeoresName()) do 
			local heroId = dota.FindKeyValues("npc_heroes.txt",v, "HeroID")
			if heroId and heroId~="null" and tonumber(heroId) == id then 
				nameCache[id] = v
				break
			end 
		end 
	end 
	if not nameCache[id] or #nameCache[id]>100 then 
		nameCache[id] = "npc_dota_hero_abaddon"
	end
	return nameCache[id]
end

function GetCurrentHeroesStrImage(team,ignore,add_empty)
	local temp = ""
	local count = 0
	local player_resource = dota.PlayerResource.GetInstance()
	for i,v in ipairs(dota.FindEntities(dota.kDotaPlayer)) do
		local i = v:GetPlayerId()
		if IsGoodPlayerId(i) and (not ignore or v:GetPlayerId()~=ignore) then
			local vteam = v:GetTeamIndex()
			if not team or vteam == team then				
				local resursID = player_resource:GetHeroId(i)
				if resursID>0 and resursID < 160 then 					
					local heroid = FindHero(resursID)
					temp = temp.." @"..heroid:lower()
					count = count + 1
				end 
			end
		end 
	end
	if add_empty and count > 0 and 9 - count > 0 then
		count = math.floor((9 - count) / 2)
		while count > 0 do
			temp = " @item_recipe " .. temp
			count = count - 1
		end
	end
	return temp
end 

function IsGoodPlayerId(i)
	return i >-1 and i<10
end

function IsTalant(self,const)
	return HasFlag(self:GetSpecialAbilityFlag(),const)
end

function IsBehaviour(self,flag)
	return HasFlag(self:GetBehavior(),flag)
end

function IsExistSpell(spell,check_item)
	local csl_name = (check_item and "C_DOTA_Item") or "C_DOTABaseAbility"
	return spell and spell:IsValid() and spell:GetNewClassName() == csl_name
end 

function num2hex(num)
    local hexstr = '0123456789abcdef'
    local s = ''
    while num > 0 do
        local mod = math.fmod(num, 16)
        s = hexstr:sub(mod+1, mod+1) .. s
        num = floor(num / 16)
    end
    if s == '' then s = '0' end
    return s
end


 --// Source

function ReadLines(sPath,add)
	local file = io.open(sPath, "r")
	if file then
		local tLines = {}
		for line in file:lines() do
			table.insert(tLines, line)
		end
		file:close()
		return tLines
	elseif add then
		WriteLines(sPath,add)
		return add
	else
		WriteLines(sPath,{})
		return {}
	end
end

function WriteLines(sPath, tLines)
	local file = io.open(sPath, "w")
	if file then
		local text = ""
		for _, sLine in ipairs(tLines) do
			text = text..sLine.."\n"
		end
		file:write(text)
		file:close()
		return tLines
	end
end

function ReWriteLines(sPath, var, val)
	local lines = ReadLines(sPath)
	local finded = false
	for i = 0, #lines do
		if lines[i] and lines[i]:split()[1] == var then
			lines[i] = var..":"..val
			finded = true
		end
	end
	if not finded then
		table.insert(lines, var..":"..val)
	end
	WriteLines(sPath, lines)
end


--// Override 

function string:removeNpc()
	return self:gsub("npc_dota_hero_","")
end

function string:removeItem()
	return self:gsub("item_","")
end  

function string:split(sep)
    local sep, fields = sep or ":", {}
    local pattern = string.format("([^%s]+)", sep)
    self:gsub(pattern, function(c) fields[#fields+1] = c end)
    return fields
end

function string:include(array)
  for i = 1,#array do 
		local v = array[i]
		if v and v ==  self then
			return true 
		end 
	end
	return false
end

function string:startWith(str)
	return self:sub(1,#str) == str
end

math.clamp = function(x, min, max)
    if x < min then return min end
    if x > max then return max end
    return x
end

table.filter = function(tab, filterIter)
	local out = {}
	for k, v in ipairs(tab) do
		if filterIter(v) then 
			out[#out+1] = v
		end
	end
	return out
end

table.find = function(tab, filterIter)
	for k, v in ipairs(tab) do
		if filterIter(v) then 
			return v
		end
	end
	return nil
end

table.find_value = function(tab,name)
	for i,v in ipairs(tab) do	
		if v == name then 				
			return i 
		end 
	end 
	return nil
end 

table.add_= function(tab,value)
	for k, v in ipairs(tab) do
		if v == value then 
			return tab
		end
	end
	tab[#tab+1] = value 
	return tab
end 

table.find_remove_if_value = function(tab,value)
	for k, v in ipairs(tab) do
		if v == value then 
			table.remove(tab,k)
			return tab
		end
	end
end 

table.clone = function(tab)
	return {table.unpack(tab)}
end

table.map = function(tab,filterIter)
	local t = {}
    for k,v in pairs(tab) do
        t[k] = filterIter(v)
    end
    return t
end 

table.shadow_copy = function(tab)
	function deepcopy(orig)
		local orig_type = type(orig)
		local copy
		if orig_type == 'table' then
			copy = {}
			for orig_key, orig_value in next, orig, nil do
				copy[deepcopy(orig_key)] = deepcopy(orig_value)
			end
			setmetatable(copy, deepcopy(getmetatable(orig)))
		else -- number, string, boolean, etc
			copy = orig
		end
		return copy
	end
	return deepcopy(tab)
end 

table.merge = function(...)
	local temp = {}	
	local arg = {...}
	for z = 1, #arg do
		local x = arg[z] 
		local count = #temp
		for i = 1, #x do
			local v = x[i] 
			temp[count+i] = v
		end 
	end 
	return temp 
end

table.merge_name = function(...)
	local temp = {}	
	local arg = {...}
	for z = 1, #arg do
		for i,v in pairs(arg[z]) do
			temp[i] = v
		end 
	end 
	return temp 
end