---------------------------------------------------------------------------
--- The Creation Come From: A Beginner AI
--- Author: 决明子 Email: dota2jmz@163.com 微博@Dota2_决明子
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1573671599
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1627071163
---------------------------------------------------------------------------
-- 有多少人工, 才有多么智能
-- How much artificial, how many intelligence.
------------------------------------------------------2017.08.20
--if _G.Rewrite then return end
--_G.Rewrite = true

--------------------------------
--new functions
--------------------------------
function print_r(t,page)
    local print_r_cache={}
    local function sub_print_r(t,indent)
        if (print_r_cache[tostring(t)]) then
            print(indent.."*"..tostring(t))
        else
            print_r_cache[tostring(t)]=true
            if (type(t)=="table") then
                for pos,val in pairs(t) do
                    if (type(val)=="table") then
                        print(indent.."["..pos.."] => "..tostring(t).." {")
                        sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
                        print(indent..string.rep(" ",string.len(pos)+6).."}")
                    elseif (type(val)=="string") then
                        print(indent.."["..pos..'] => "'..val..'"')
                    else
                        print(indent.."["..pos.."] => "..tostring(val))
                    end
                end
            else
                print(indent..tostring(t))
            end
        end
    end
    if (type(t)=="table") then
        print(tostring(t).." {")
        sub_print_r(t,"  ")
        print("}")
    else
        sub_print_r(t,"  ")
    end
end

_G.FilterTable = function(t,filter)
	local newGroup={}
	for _, obj in pairs( t ) do
		if filter(obj) then
			table.insert(newGroup,obj)
		end
	end
	return newGroup
end

function CDOTA_Bot_Script.IsAlly(unit)
	return GetBot():GetTeam() == unit:GetTeam()
end
function CDOTA_Bot_Script.GetHealthPercent(unit)
	return unit:GetHealth() / unit:GetMaxHealth() * 100.0
end
function CDOTA_Bot_Script.GetManaPercent(unit)
	return unit:GetMana() / unit:GetMaxMana() * 100.0
end
function CDOTA_Bot_Script.IsEnemy(unit)
	return GetBot():GetTeam() ~= unit:GetTeam()
end
function CDOTA_Bot_Script.GetDistanceToUnit(unit, unit2)
	if not unit2 then return 99999 end
	local loc1=unit:GetLocation()
	local loc2=unit2:GetLocation()
	return math.sqrt(( loc1.x - loc2.x )*( loc1.x - loc2.x ) + ( loc1.y - loc2.y ) * ( loc1.y - loc2.y ))
end
function CDOTA_Bot_Script.GetDistanceToLocation(unit, loc)
	if not loc then return 99999 end
	local loc1=unit:GetLocation()
	return math.sqrt(( loc1.x - loc.x )*( loc1.x - loc.x ) + ( loc1.y - loc.y ) * ( loc1.y - loc.y ))
end
function CDOTA_Bot_Script.WasRecentlyDamagedByAnyUnit(unit,time)
	return unit:WasRecentlyDamagedByAnyHero(time)
		or unit:WasRecentlyDamagedByCreep(time)
end
function CDOTA_Bot_Script.IsCanInvisible(unit)
	if not unit:CanBeSeen() then return false end
	local buffs = require( GetScriptDirectory()..'/FunLib/aba_buff' )
	for _,buff in buffs['truesight_buffs'] do
		if unit:HasModifier(buff) then
			return false
		end
	end
	return true
end
function CDOTA_Bot_Script.GetStrength(unit)
	if not unit:CanBeSeen() or not unit:IsHero() then return 0 end
	return unit:GetAttributeValue(ATTRIBUTE_STRENGTH)
end
function CDOTA_Bot_Script.GetAgility(unit)
	if not unit:CanBeSeen() or not unit:IsHero() then return 0 end
	return unit:GetAttributeValue(ATTRIBUTE_AGILITY)
end
function CDOTA_Bot_Script.GetIntellect(unit)
	if not unit:CanBeSeen() or not unit:IsHero() then return 0 end
	return unit:GetAttributeValue(ATTRIBUTE_INTELLECT)
end
function CDOTA_Bot_Script.GetAllAttributes(unit)
	return unit:GetStrength() + unit:GetAgility() + unit:GetIntellect()
end
function CDOTABaseAbility_BotScript.GetVal(ability, name)
	local f=ability:GetSpecialValueFloat(name)
	if math.abs(f)<0.0001 then
		f=ability:GetSpecialValueInt(name)
	end
	return f
end
--------------------------------
--rewrite functions CDOTA_Bot_Script
--------------------------------
CDOTA_Bot_Script.GetAttackCombatProficiency=CDOTA_Bot_Script.GetAttackCombatProficiency or function(u)
	return 1.0
end
local gl=CDOTA_Bot_Script.GetLocation
function CDOTA_Bot_Script.GetLocation(unit)
	if not unit:CanBeSeen() then
		local id=unit:GetPlayerID()
		local info=GetHeroLastSeenInfo(id)
		if info and info.time_since_seen < 2.0 then
			return info.location
		end
	end
	return gl(unit)
end
local gar=CDOTA_Bot_Script.GetAttackRange
local gar_data={}
CDOTA_Bot_Script.GetAttackRange=function(u)
	if u:CanBeSeen() then
		gar_data[u]=gar(u)
		return gar(u)
	end
	return gar_data[u] or 0
end

local ic=CDOTA_Bot_Script.IsChanneling
CDOTA_Bot_Script.IsChanneling=function(u)
	if u:CanBeSeen() then
		return ic(u)
	end
	return false
end

local hm=CDOTA_Bot_Script.HasModifier
CDOTA_Bot_Script.HasModifier=function(u,pszModifierName)
	if u:CanBeSeen() then
		return hm(u,pszModifierName)
	end
	return false
end

local gedtt=CDOTA_Bot_Script.GetEstimatedDamageToTarget
CDOTA_Bot_Script.GetEstimatedDamageToTarget=function(u,bCurrentlyAvailable,hTarget,fDuration,nDamageTypes)
	if u:CanBeSeen() then
		return gedtt(u,bCurrentlyAvailable,hTarget,fDuration,nDamageTypes)
	end
	local result = DotaTime() * 0.5 + 50
	if DotaTime() > 5 * 60 then
		result = 200 + (DotaTime()-300) * 0.4
	end
	if DotaTime() > 10 * 60 then
		result = 320 + (DotaTime()-600) * 0.2
	end
	if DotaTime() > 20 * 60 then
		result = 440 + (DotaTime()-600) * 0.1
	end
	if DotaTime() > 30 * 60 then
		result = 500
	end
	return math.floor(result * fDuration)
end

local iua=CDOTA_Bot_Script.IsUsingAbility
CDOTA_Bot_Script.IsUsingAbility=function(u)
	if u:CanBeSeen() then
		return iua(u)
	end
	return false
end

local gat=CDOTA_Bot_Script.GetAttackTarget
CDOTA_Bot_Script.GetAttackTarget=function(u)
	if u:CanBeSeen() then
		return gat(u)
	end
	return nil
end

local gt=CDOTA_Bot_Script.GetTarget
CDOTA_Bot_Script.GetTarget=function(u)
	if u:IsAlly() then
		return gt(u)
	end
	return nil
end

local ii=CDOTA_Bot_Script.IsInvulnerable
CDOTA_Bot_Script.IsInvulnerable=function(u)
	if u:CanBeSeen() then
		return ii(u)
	end
	return false
end

local iai=CDOTA_Bot_Script.IsAttackImmune
CDOTA_Bot_Script.IsAttackImmune=function(u)
	if u:CanBeSeen() then
		return iai(u)
	end
	return false
end

local gaid=CDOTA_Bot_Script.GetActualIncomingDamage
CDOTA_Bot_Script.GetActualIncomingDamage=function(u, nDamage, nType)
	if u:CanBeSeen() then
		return gaid(u, nDamage, nType)
	end
	return 0
end

local gh=CDOTA_Bot_Script.GetHealth
CDOTA_Bot_Script.GetHealth=function(u)
	if u:CanBeSeen() then
		return gh(u)
	end
	return GetBot():GetMaxHealth() - gh(GetBot())
	--自己血越少，认为看不见的敌人血越多
end

local gmh=CDOTA_Bot_Script.GetMaxHealth
CDOTA_Bot_Script.GetMaxHealth=function(u)
	if u:CanBeSeen() then
		return gmh(u)
	end
	return gmh(GetBot())
end

local ghr=CDOTA_Bot_Script.GetHealthRegen
CDOTA_Bot_Script.GetHealthRegen=function(u)
	if u:CanBeSeen() then
		return ghr(u)
	end
	return ghr(GetBot())
end

local gm=CDOTA_Bot_Script.GetMana
CDOTA_Bot_Script.GetMana=function(u)
	if u:CanBeSeen() then
		return gm(u)
	end
	return gm(GetBot())
end

local gmm=CDOTA_Bot_Script.GetMaxMana
CDOTA_Bot_Script.GetMaxMana=function(u)
	if u:CanBeSeen() then
		return gmm(u)
	end
	return gmm(GetBot())
end

local gnh=CDOTA_Bot_Script.GetNearbyHeroes
CDOTA_Bot_Script.GetNearbyHeroes = function(u,nRadius,bEnemies,eBotMode)
	if not u:CanBeSeen() then return {} end
	if nRadius <= 1600 and u:IsBot() then return gnh(u,nRadius,bEnemies,eBotMode) end
	local list
	if bEnemies then
		list=GetUnitList(UNIT_LIST_ENEMY_HEROES)
	else
		list=GetUnitList(UNIT_LIST_ALLIED_HEROES)
	end
	list=FilterTable(list,function(unit)
		return u:GetDistanceToUnit(unit) <= nRadius
			and (bEnemies or eBotMode == BOT_MODE_NONE or not unit:IsBot() or eBotMode == unit:GetActiveMode())
	end)
	return list
end

local gnc=CDOTA_Bot_Script.GetNearbyCreeps
CDOTA_Bot_Script.GetNearbyCreeps = function(u,nRadius,bEnemies)
	if not u:CanBeSeen() then return {} end
	if nRadius <= 1600 and u:IsBot() then return gnc(u,nRadius,bEnemies) end
	local list
	if bEnemies then
		list=GetUnitList(UNIT_LIST_ENEMY_CREEPS) or {}
	else
		list=GetUnitList(UNIT_LIST_ALLIED_CREEPS) or {}
	end
	list=FilterTable(list,function(unit)
		return u:GetDistanceToUnit(unit) <= nRadius
	end)
	return list
end

--------------------------------
--rewrite functions CDOTABaseAbility_BotScript
--------------------------------