----------------------------------------------------------------------------------------------------
--- The Creation Come From: BOT EXPERIMENT Credit:FURIOUSPUPPY
--- BOT EXPERIMENT Author: Arizona Fauzie 2018.11.21
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=837040016
--- Refactor: 决明子 Email: dota2jmz@163.com 微博@Dota2_决明子
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1573671599
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1627071163
----------------------------------------------------------------------------------------------------
local X = {}
local bDebugMode = ( 1 == 10 )
local bot = GetBot()

local J = require( GetScriptDirectory()..'/FunLib/jmz_func' )
local Minion = dofile( GetScriptDirectory()..'/FunLib/aba_minion' )
local sTalentList = J.Skill.GetTalentList( bot )
local sAbilityList = J.Skill.GetAbilityList( bot )
local sOutfitType = J.Item.GetOutfitType( bot )

local tTalentTreeList = {
						['t25'] = {0, 10},
						['t20'] = {10, 0},
						['t15'] = {0, 10},
						['t10'] = {10, 0},
}

local tAllAbilityBuildList = {
						{1,2,3,1,1,6,1,3,2,2,6,2,3,3,6},
}

local nAbilityBuildList = J.Skill.GetRandomBuild( tAllAbilityBuildList )

local nTalentBuildList = J.Skill.GetTalentBuild( tTalentTreeList )

local tOutFitList = {}

tOutFitList['outfit_carry'] = {

	"item_crystal_maiden_outfit",
	"item_force_staff",
	"item_glimmer_cape",
	"item_aghanims_shard",
	"item_rod_of_atos",
	"item_ultimate_scepter",
	"item_sheepstick",
	"item_moon_shard",
	"item_octarine_core",
	"item_ultimate_scepter_2",
}

tOutFitList['outfit_mid'] = tOutFitList['outfit_carry']

tOutFitList['outfit_priest'] = tOutFitList['outfit_carry']

tOutFitList['outfit_mage'] = tOutFitList['outfit_carry']

tOutFitList['outfit_tank'] = tOutFitList['outfit_carry']

X['sBuyList'] = tOutFitList[sOutfitType]

X['sSellList'] = {

	"item_vladmir",
	"item_magic_wand",
	
	"item_cyclone",
	"item_magic_wand",

}

if J.Role.IsPvNMode() or J.Role.IsAllShadow() then X['sBuyList'], X['sSellList'] = { 'PvN_mage' }, {} end

nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] = J.SetUserHeroInit( nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] )

X['sSkillList'] = J.Skill.GetSkillList( sAbilityList, nAbilityBuildList, sTalentList, nTalentBuildList )

X['bDeafaultAbility'] = false
X['bDeafaultItem'] = true

function X.MinionThink( hMinionUnit )

	if Minion.IsValidUnit( hMinionUnit )
	then
		Minion.IllusionThink( hMinionUnit )
	end

end

--[[

npc_dota_hero_lion

"Ability1"		"lion_impale"
"Ability2"		"lion_voodoo"
"Ability3"		"lion_mana_drain"
"Ability4"		"generic_hidden"
"Ability5"		"generic_hidden"
"Ability6"		"lion_finger_of_death"
"Ability10"		"special_bonus_cast_range_100"
"Ability11"		"special_bonus_attack_damage_90"
"Ability12"		"special_bonus_unique_lion_3"
"Ability13"		"special_bonus_gold_income_25"
"Ability14"		"special_bonus_hp_500"
"Ability15"		"special_bonus_unique_lion"
"Ability16"		"special_bonus_unique_lion_2"
"Ability17"		"special_bonus_unique_lion_4"

modifier_lion_impale
modifier_lion_voodoo
modifier_lion_mana_drain
modifier_lion_finger_of_death_kill_counter
modifier_lion_finger_of_death
modifier_lion_finger_of_death_delay
modifier_lion_arcana_kill_effect

--]]

local abilityQ = bot:GetAbilityByName( sAbilityList[1] )
local abilityW = bot:GetAbilityByName( sAbilityList[2] )
local abilityE = bot:GetAbilityByName( sAbilityList[3] )
local abilityR = bot:GetAbilityByName( sAbilityList[6] )

local castQDesire, castQTarget
local castWDesire, castWTarget
local castEDesire, castELocation
local castRDesire, castRLocation

local nKeepMana, nMP, nHP, nLV, hEnemyList, hAllyList, botTarget, sMotive
local aetherRange = 0
local lastCastQTime = -99

local lastWLocation=nil
local lastWTarget=nil
local lastWTime=0
local WECasted=false


local lastELocation=nil
local lastETime=0

function X.SkillsComplement()

	X.UpdateEnemyLocations()

	if lastWLocation and lastWTime+2.0<DotaTime() then
		lastWLocation=nil
		lastWTarget=nil
		lastWTime=0
		WECasted=false
	end

	if lastELocation and lastETime+2.0<DotaTime() then
		lastELocation=nil
		lastETime=0
	end

	if J.CanNotUseAbility( bot ) or bot:IsInvisible() then return end

	nKeepMana = 400
	aetherRange = 0
	nLV = bot:GetLevel()
	nMP = bot:GetMana()/bot:GetMaxMana()
	nHP = bot:GetHealth()/bot:GetMaxHealth()
	botTarget = J.GetProperTarget( bot )
	hEnemyList = bot:GetNearbyHeroes( 1600, true, BOT_MODE_NONE )
	hAllyList = J.GetAlliesNearLoc( bot:GetLocation(), 1600 )

	
	aetherRange = J.GetBonusCastRange( bot )


	castWDesire, castWTarget, sMotive = X.ConsiderW()
	if ( castWDesire > 0 )
	then
		J.SetReportMotive( bDebugMode, sMotive )

		J.SetQueuePtToINT( bot, true )

		lastWLocation=X.GetWLocation(castWTarget)
		if lastWLocation then
			local time=GetUnitToLocationDistance(castWTarget,lastWLocation)/600.0
			if time>1.8 then time = 1.8 end
			lastWTime=DotaTime()+time
		end
		lastWTarget=castWTarget
		bot:ActionQueue_UseAbilityOnEntity( abilityW, castWTarget )
		return
	end

	castEDesire, castELocation, sMotive = X.ConsiderE()
	if ( castEDesire > 0 )
	then
		J.SetReportMotive( bDebugMode, sMotive )

		J.SetQueuePtToINT( bot, true )

		lastELocation=castELocation
		lastETime=DotaTime()+1.0
		bot:ActionQueue_UseAbilityOnLocation( abilityE, castELocation )
		return
	end

	castRDesire, castRLocation, sMotive = X.ConsiderR()
	if ( castRDesire > 0 )
	then
		J.SetReportMotive( bDebugMode, sMotive )

		J.SetQueuePtToINT( bot, true )

		bot:ActionQueue_UseAbilityOnLocation( abilityR, castRLocation )
		return

	end

	castQDesire, castQTarget, sMotive = X.ConsiderQ()
	if ( castQDesire > 0 )
	then
		J.SetReportMotive( bDebugMode, sMotive )

		J.SetQueuePtToINT( bot, true )

		bot:ActionQueue_UseAbilityOnEntity( abilityQ, castQTarget )
		return
	end

end

function X.ConsiderQ()

	if not abilityQ:IsFullyCastable() then return 0 end

	local nSkillLV = abilityQ:GetLevel()
	local nCastRange = abilityQ:GetCastRange() + aetherRange + 20
	local nRadius	 = abilityQ:GetSpecialValueInt( "width" )
	local nCastPoint = abilityQ:GetCastPoint()
	local nManaCost = abilityQ:GetManaCost()
	local nDamage = abilityQ:GetAbilityDamage()
	local nDamageType = DAMAGE_TYPE_MAGICAL
	local nInRangeEnemyList = bot:GetNearbyHeroes( nCastRange, true, BOT_MODE_NONE )
	local nInBonusEnemyList = bot:GetNearbyHeroes( nCastRange + 200, true, BOT_MODE_NONE )

	nInRangeEnemyList = J.FilterGroup(nInRangeEnemyList,J.CanCastOnNonMagicImmune)

	--击杀
	for _, npcEnemy in pairs( nInRangeEnemyList )
	do
		if J.IsValidHero( npcEnemy )
			and J.WillMagicKillTarget( bot, npcEnemy, nDamage, 5.0 )
		then
			return BOT_ACTION_DESIRE_HIGH, npcEnemy, 'Q-击杀'..J.Chat.GetNormName( npcEnemy )
		end
	end

	--团战
	if J.IsInTeamFight( bot, 1200 )
	then
		local valid = J.FilterGroup(nInRangeEnemyList,J.IsValidHero)
		local enemy = J.GetLeastHpUnit( valid )
		if enemy ~= nil then
			return BOT_ACTION_DESIRE_HIGH, enemy, 'Q-团战攻击血量最少单位'
		end
	end

	--攻击
	if J.IsGoingOnSomeone( bot )
	then
		if J.IsValidHero( botTarget )
			and J.IsInRange( botTarget, bot, nCastRange + 300 )
		then
			if nSkillLV >= 2 or nMP > 0.68 or J.GetHP( botTarget ) < 0.5 then
				return BOT_ACTION_DESIRE_HIGH, botTarget, 'Q-攻击:'..J.Chat.GetNormName( botTarget )
			end
		end
	end

	--Farm
	if J.IsFarming( bot ) and nSkillLV >= 3
		and J.IsAllowedToSpam( bot, nManaCost )
		and J.IsValid( botTarget )
		and botTarget:GetTeam() == TEAM_NEUTRAL
		and J.IsInRange( bot, botTarget, 1000 )
		and bot:IsFacingLocation( botTarget:GetLocation(), 45 )
		and ( botTarget:GetMagicResist() < 0.4 or nMP > 0.9 ) then
				return BOT_ACTION_DESIRE_HIGH, botTarget, "Q-打钱"
	end

	--Push
	if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) or (J.IsLaning(bot) and bot:GetAssignedLane()==LANE_MID))
		and J.IsAllowedToSpam( bot, nManaCost )
		and nSkillLV >= 2 or DotaTime() > 9 * 60
		and #hAllyList <= 2 and #hEnemyList == 0
	then
		local laneCreepList = bot:GetNearbyLaneCreeps( nCastRange, true )
		laneCreepList = J.FilterGroup(laneCreepList, function(u)
			return J.IsValid(u) and not u:HasModifier( "modifier_fountain_glyph" )
		end)
		if #laneCreepList >= 3 then
			return BOT_ACTION_DESIRE_HIGH, laneCreepList[1], "Q-推线"
		end
	end

	--Roshan
	if bot:GetActiveMode() == BOT_MODE_ROSHAN
		and bot:GetMana() >= 900
	then
		if J.IsRoshan( botTarget ) and J.IsInRange( botTarget, bot, nCastRange )
		then
			return BOT_ACTION_DESIRE_HIGH, botTarget, "Q-Roshan"
		end
	end

	--常规
	if ( #hEnemyList > 0 or bot:WasRecentlyDamagedByAnyHero( 3.0 ) )
		and ( bot:GetActiveMode() ~= BOT_MODE_RETREAT or #hAllyList >= 2 )
		and #nInRangeEnemyList >= 1
		and nLV >= 15
	then
		for _, npcEnemy in pairs( nInRangeEnemyList )
		do
			if J.IsValid( npcEnemy )
				and J.CanCastOnNonMagicImmune( npcEnemy ) 
				and J.IsInRange( bot, npcEnemy, nCastRange ) then
				return BOT_ACTION_DESIRE_HIGH, npcEnemy, 'Q-常规'
			end
		end
	end

	return BOT_ACTION_DESIRE_NONE

end

local hEnemyLocations = {}
local nEnemyLocationsIndex = 1

function X.UpdateEnemyLocations()
	local enemies = GetUnitList( UNIT_LIST_ENEMY_HEROES )

	for id,_ in pairs(hEnemyLocations) do
		hEnemyLocations[id][nEnemyLocationsIndex]=nil
	end

	for _,u in pairs(enemies) do
		local pid="p"..tostring(u:GetPlayerID())
		if pid then
			if not hEnemyLocations[pid] then
				hEnemyLocations[pid] = {}
			end
			pcall(function()
				if not u:IsAlive() then
					hEnemyLocations[pid][nEnemyLocationsIndex]=J.GetEnemyFountain()
				end
				hEnemyLocations[pid][nEnemyLocationsIndex]=u:GetLocation()
			end)
		end
	end

	nEnemyLocationsIndex = nEnemyLocationsIndex + 1
	if nEnemyLocationsIndex > 121 then nEnemyLocationsIndex = 1 end
end

function X.GetWLocation(u)
	if u==nil then return nil end
	local index = nEnemyLocationsIndex + 1
	if index > 121 then index = 1 end
	local pid="p"..tostring(u:GetPlayerID())
	if hEnemyLocations[pid] and hEnemyLocations[pid][index] then return hEnemyLocations[pid][index] end
	return nil
end

function X.ConsiderW()

	if not abilityW:IsFullyCastable() then return 0 end

	local nSkillLV = abilityW:GetLevel()
	local nCastRange = abilityW:GetCastRange() + aetherRange
	local nCastPoint = abilityW:GetCastPoint()
	local nManaCost = abilityW:GetManaCost()
	local nDamage = abilityW:GetAbilityDamage()
	local nDamageType = DAMAGE_TYPE_MAGICAL
	local nInRangeEnemyList = GetUnitList( UNIT_LIST_ENEMY_HEROES )

	nInRangeEnemyList = J.FilterGroup(nInRangeEnemyList,function(u)
		return J.IsValidHero(u) and J.CanCastOnNonMagicImmune(u)
			and J.IsInRange(bot,u,nCastRange)
	end)

	--打断
	for _, npcEnemy in pairs( nInRangeEnemyList ) do
		if npcEnemy:IsChanneling() then
			return BOT_ACTION_DESIRE_HIGH, npcEnemy, 'W-打断吟唱:'..J.Chat.GetNormName( npcEnemy )
		end
	end

	--打回泉水或TP点
	for _, npcEnemy in pairs( nInRangeEnemyList ) do
		local newLocation = X.GetWLocation(npcEnemy)
		if npcEnemy:HasModifier( "modifier_fountain_glyph" ) or 
		(newLocation and GetUnitToLocationDistance(npcEnemy,newLocation)>2000) then
			return BOT_ACTION_DESIRE_HIGH, npcEnemy, 'W-打回泉水:'..J.Chat.GetNormName( npcEnemy )
		end
	end

	--撤退
	if J.IsRetreating( bot )
	then
		for _, npcEnemy in pairs( nInRangeEnemyList ) do
			local newLocation = X.GetWLocation(npcEnemy)
			if (newLocation and GetUnitToLocationDistance(bot,newLocation)>GetUnitToUnitDistance(bot,npcEnemy)+400
			or nHP<0.2)
				and not J.IsDisabled( npcEnemy )
				and not J.IsTaunted( npcEnemy )
			then
				return BOT_ACTION_DESIRE_HIGH, npcEnemy, "W-撤退:"..J.Chat.GetNormName( npcEnemy )
			end
		end
	end

	--团战
	if (J.IsInTeamFight(bot, 1200) or J.IsGoingOnSomeone(bot)) and abilityE:IsFullyCastable() and abilityR:IsFullyCastable()
		and bot:GetMana()>abilityE:GetManaCost()+abilityR:GetManaCost()+abilityW:GetManaCost() then
		for _, npcEnemy in pairs( nInRangeEnemyList ) do
			local newLocation = X.GetWLocation(npcEnemy)
			if newLocation and GetUnitToUnitDistance(bot,npcEnemy) > abilityE:GetCastRange() + aetherRange + 200
				and GetUnitToLocationDistance(bot,newLocation) < abilityE:GetCastRange() + aetherRange - 200 then
				return BOT_ACTION_DESIRE_HIGH, npcEnemy, 'W-准备连招:'..J.Chat.GetNormName( npcEnemy )
			end
		end
	end

	return BOT_ACTION_DESIRE_NONE

end

function X.ConsiderE()

	if not abilityE:IsFullyCastable() then return 0 end

	local nSkillLV = abilityE:GetLevel()
	local nCastRange = abilityE:GetCastRange() + aetherRange
	local nCastPoint = abilityE:GetCastPoint() + 1.0
	local nManaCost = abilityE:GetManaCost()
	local nDamageType = DAMAGE_TYPE_MAGICAL
	local nRadius 	 = 350

	local nInRangeEnemyList = bot:GetNearbyHeroes( nCastRange + nRadius * 0.5, true, BOT_MODE_NONE )

	local nTargetLocation = nil

	--连招
	local WTime = 0
	if lastWTime then WTime = lastWTime - DotaTime() end
	if lastWLocation and WTime<1.5 and WTime>0.5 and GetUnitToLocationDistance(bot, lastWLocation)<nCastRange
		and nLV>=6 and abilityR:IsFullyCastable()
		and bot:GetMana()>abilityE:GetManaCost()+abilityR:GetManaCost()
		and not lastWTarget:IsMagicImmune() then
		WECasted=true
		return BOT_ACTION_DESIRE_HIGH, lastWLocation, 'E连招'
	end

	--团战
	if J.IsInTeamFight( bot, 1200 )
	then
		local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
		if nAoeLoc ~= nil
		then
			return BOT_ACTION_DESIRE_HIGH, nAoeLoc, 'E团战'
		end
	end

	--团战2
	if J.IsInTeamFight( bot, 1200 ) then
		local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
		if nAoeLoc ~= nil
		then
			return BOT_ACTION_DESIRE_HIGH, nAoeLoc, 'E团战'
		end
	end

	--追杀
	if J.IsGoingOnSomeone( bot )
	then
		if J.IsValidHero( botTarget )
			and J.CanCastOnNonMagicImmune( botTarget )
			and J.IsInRange( botTarget, bot, nCastRange - 30 )
		then
			nTargetLocation = J.GetDelayCastLocation( bot, botTarget, nCastRange, nRadius, nCastPoint )
			if nTargetLocation ~= nil
			then
				return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "E追杀"..J.Chat.GetNormName( botTarget )
			end
		end
	end

	--撤退
	if J.IsRetreating( bot ) then
		local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange -100, nRadius -20, 2 )
		if nAoeLoc ~= nil
		then
			nTargetLocation = nAoeLoc
			return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'E撤退-阻止多人'
		end

		for _, npcEnemy in pairs( nInRangeEnemyList )
		do
			if J.IsValid( npcEnemy )
				and J.CanCastOnNonMagicImmune( npcEnemy )
				and ( bot:WasRecentlyDamagedByHero( npcEnemy, 4.0 ) or bot:GetActiveModeDesire() > BOT_ACTION_DESIRE_VERYHIGH )
			then
				nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius, nCastPoint )
				if nTargetLocation ~= nil
				then
					return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "E撤退-阻止单个敌人"..J.Chat.GetNormName( npcEnemy )
				end
			end
		end
	end

	--自保
	if bot:WasRecentlyDamagedByAnyHero( 3.0 ) and nLV >= 10
		and bot:GetActiveMode() ~= BOT_MODE_RETREAT
		and #nInRangeEnemyList >= 1
	then
		for _, npcEnemy in pairs( nInRangeEnemyList )
		do
			if J.IsValid( npcEnemy )
				and J.CanCastOnNonMagicImmune( npcEnemy ) 
				and bot:IsFacingLocation( npcEnemy:GetLocation(), 45 )
			then
				nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius -30, nCastPoint )
				if nTargetLocation ~= nil
				then
					return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "W自保"..J.Chat.GetNormName( npcEnemy )
				end
			end
		end
	end

	return BOT_ACTION_DESIRE_NONE

end

function X.ConsiderR()

	if not abilityR:IsFullyCastable() then return 0 end

	local nSkillLV = abilityR:GetLevel()
	local nCastRange = abilityR:GetCastRange() + aetherRange
	local nCastPoint = abilityR:GetCastPoint() + 0.5
	local nManaCost = abilityR:GetManaCost()
	local nDamageType = DAMAGE_TYPE_MAGICAL
	local nRadius = abilityR:GetAOERadius()

	local nInRangeEnemyList = bot:GetNearbyHeroes( nCastRange + nRadius * 0.5, true, BOT_MODE_NONE )

	local nTargetLocation = nil

	local WTime = 0
	if lastWTime then WTime = lastWTime - DotaTime() end
	if WECasted and WTime<0.5 and WTime>-0.5 and GetUnitToLocationDistance(bot, lastWLocation)<nCastRange
		and #J.GetEnemiesNearLoc(lastWLocation, nRadius)>0 then
		return BOT_ACTION_DESIRE_HIGH, lastWLocation, "R连招:WER"
	end

	local ETime = 0
	if lastETime then ETime = lastETime - DotaTime() end
	if lastELocation and ETime>-0.3 and ETime<0.3 and #J.GetEnemiesNearLoc(lastELocation, nRadius)>0 then
		return BOT_ACTION_DESIRE_HIGH, lastELocation, "R连招:ER"
	end

	if abilityE:IsFullyCastable() or lastWLocation or lastELocation then return BOT_ACTION_DESIRE_NONE end --有E等E，有连招等连招，没E再说

	--团战
	if J.IsInTeamFight( bot, 1200 ) then
		local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 3 )
		if nAoeLoc ~= nil
		then
			nTargetLocation = nAoeLoc
			return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'R团战'
		end
	end

	return BOT_ACTION_DESIRE_NONE

end

return X
-- dota2jmz@163.com QQ:2462331592..
