----------------------------------------------------------------------------------------------------
--- The Creation Come From: BOT EXPERIMENT Credit:FURIOUSPUPPY
--- BOT EXPERIMENT Author: Arizona Fauzie
--- 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 J = {}


local sDota2Version= '7.29'
local sDebugVersion= '20210424ver1.8c'
local bDebugMode = true
local bDebugTeam = ( GetTeam() == TEAM_RADIANT )
local sDebugHero = 'npc_dota_hero_abaddon'
local tAllyIDList = GetTeamPlayers( GetTeam() )
local tAllyHeroList = {}
local tAllyHumanList = {}
local nAllyTotalKill = 0
local nAllyAverageLevel = 1
local tEnemyIDList = GetTeamPlayers( GetOpposingTeam() )
local tEnemyHeroList = {}
local tEnemyHumanList = {}
local nEnemyTotalKill = 0
local nEnemyAverageLevel = 1


local RB = Vector( -7175, -6670, 385 )
local DB = Vector( 7025, 6450, 385 )
local fKeepManaPercent = 0.39


for i, id in pairs( tAllyIDList )
do

	local bHuman = not IsPlayerBot( id )
	local hHero = GetTeamMember( i )

	if hHero ~= nil
	then
		if bHuman then table.insert( tAllyHumanList, hHero ) end
		table.insert( tAllyHeroList, hHero )
	end

end


J.Site = require( GetScriptDirectory()..'/FunLib/aba_site' )
J.Item = require( GetScriptDirectory()..'/FunLib/aba_item' )
J.Buff = require( GetScriptDirectory()..'/FunLib/aba_buff' )
J.Role = require( GetScriptDirectory()..'/FunLib/aba_role' )
J.Skill = require( GetScriptDirectory()..'/FunLib/aba_skill' )
J.Chat = require( GetScriptDirectory()..'/FunLib/aba_chat' )


if bDebugTeam
then
	print( GetTeam()..': Function Init Successful!' )
end


function J.SetUserHeroInit( nAbilityBuildList, nTalentBuildList, sBuyList, sSellList )

	local bot = GetBot()

	if J.Role.IsUserHero() --已激活锦囊
	then

		local sBotDir = J.Chat.GetHeroDirName( bot )
		
		if J.Chat.GetNormName(bot) == '力丸'  --修复力丸的错误路径
			and xpcall( function( loadDir ) require( loadDir ) end, function( err ) print( err ) end, sBotDir ) == false
		then sBotDir = sBotDir..' '	end

		if xpcall( function( loadDir ) require( loadDir ) end, function( err ) print( err ) end, sBotDir )
		then
			local BotSet = require( sBotDir )
			if J.Chat.GetRawGameWord( BotSet['ShiFouShengXiao'] ) == true
			then
				nAbilityBuildList = BotSet['JiNeng']
				nTalentBuildList = J.Chat.GetTalentBuildList( BotSet['TianFu'] )
				sBuyList = J.Chat.GetItemBuildList( BotSet['ChuZhuang'] )
				sSellList = J.Chat.GetItemBuildList( BotSet['GuoDuZhuang'] )
				if J.Chat.GetRawGameWord( BotSet['ShiFouDaFuZhu'] ) == true
				then J.Role.SetUserSup( bot ) end
			end
		end

	end

	return nAbilityBuildList, nTalentBuildList, sBuyList, sSellList

end


local tInitList = {}
function J.PrintInitMessage( sFlag, sMessage )

	local bot = GetBot()

	if not J.IsDebugHero( bot ) or tInitList[sFlag] ~= nil then return end

	tInitList[sFlag] = true

	local botName = string.gsub( string.sub( bot:GetUnitName(), 15 ), '_', '' )

	print( 'A Beginner AI '..string.sub( botName, 1, 4 )..': '..string.sub( sFlag, 1, 5 )..' with '..sMessage..' init successful!' )

end


function J.IsDebugHero( bot )

	return bDebugMode
			and bDebugTeam
			and bot:GetUnitName() == sDebugHero

end

function J.CanNotUseAction( bot )

	return not bot:IsAlive()
			or (bot==GetBot() and bot:NumQueuedActions() > 0)
			or bot:IsInvulnerable()
			or bot:IsCastingAbility()
			or bot:IsUsingAbility()
			or bot:IsChanneling()
			or bot:IsStunned()
			or bot:IsNightmared()
			or bot:HasModifier( 'modifier_item_forcestaff_active' )
			or bot:HasModifier( 'modifier_phantom_lancer_phantom_edge_boost' )

end

function J.CanNotUseAbility( bot )

	return not bot:IsAlive()
			or (bot==GetBot() and bot:NumQueuedActions() > 0)
			or bot:IsInvulnerable()
			or bot:IsCastingAbility()
			or bot:IsUsingAbility()
			or bot:IsChanneling()
			or bot:IsSilenced()
			or bot:IsStunned()
			or bot:IsHexed()
			or bot:IsNightmared()
			or bot:HasModifier( "modifier_doom_bringer_doom" )
			or bot:HasModifier( 'modifier_item_forcestaff_active' )

end

function J.CanNotUseAbilityIgnoreStun( bot )

	return not bot:IsAlive()
			or (bot==GetBot() and bot:NumQueuedActions() > 0)
			or bot:IsInvulnerable()
			or bot:IsCastingAbility()
			or bot:IsUsingAbility()
			or bot:IsChanneling()
			or bot:IsSilenced()
			or bot:IsStunned()
			or bot:IsHexed()
			or bot:IsNightmared()
			or bot:HasModifier( "modifier_doom_bringer_doom" )
			or bot:HasModifier( 'modifier_item_forcestaff_active' )

end

--友军生物数量
function J.GetUnitAllyCountAroundEnemyTarget( target, nRadius )

	local targetLoc = target:GetLocation()
	local heroCount = J.GetNearbyAroundLocationUnitCount( false, true, nRadius, targetLoc )
	local creepCount = J.GetNearbyAroundLocationUnitCount( false, false, nRadius, targetLoc )

	return heroCount + creepCount

end


--敌军生物数量
function J.GetAroundTargetEnemyUnitCount( target, nRadius )

	local targetLoc = target:GetLocation()
	local heroCount = J.GetNearbyAroundLocationUnitCount( true, true, nRadius, targetLoc )
	local creepCount = J.GetNearbyAroundLocationUnitCount( true, false, nRadius, targetLoc )

	return heroCount + creepCount

end


--敌军英雄数量
function J.GetAroundTargetEnemyHeroCount( target, nRadius )

	return J.GetNearbyAroundLocationUnitCount( true, true, nRadius, target:GetLocation() )

end


--通用数量
function J.GetNearbyAroundLocationUnitCount( bEnemy, bHero, nRadius, vLoc )

	local bot = GetBot()
	local nCount = 0
	local unitList = {}

	if bHero
	then
		unitList = bot:GetNearbyHeroes( 1600, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyCreeps( 1600, bEnemy )
	end

	for _, u in pairs( unitList )
	do
		if u:IsAlive()
			and GetUnitToLocationDistance( u, vLoc ) <= nRadius
		then
			nCount = nCount + 1
		end
	end

	return nCount

end


function J.GetAttackEnemysAllyCreepCount( target, nRadius )

	local bot = GetBot()
	local nAllyCreeps = bot:GetNearbyCreeps( nRadius, false )
	local nAttackEnemyCount = 0
	for _, creep in pairs( nAllyCreeps )
	do
		if creep:IsAlive() and creep:CanBeSeen()
			and creep:GetAttackTarget() == target
		then
			nAttackEnemyCount = nAttackEnemyCount + 1
		end
	end

	return nAttackEnemyCount

end


function J.GetVulnerableWeakestUnit( bot, bHero, bEnemy, nRadius )

	local unitList = {}
	local weakest = nil
	local weakestHP = 10000
	if bHero
	then
		unitList = bot:GetNearbyHeroes( nRadius, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyLaneCreeps( nRadius, bEnemy )
	end

	for _, u in pairs( unitList )
	do
		if u:GetHealth() < weakestHP
			and J.CanCastOnNonMagicImmune( u )
		then
			weakest = u
			weakestHP = u:GetHealth()
		end
	end

	return weakest

end

function J.GetVulnerableWeakestUnitMagicImmune( bot, bHero, bEnemy, nRadius )
	local unitList = {}
	local weakest = nil
	local weakestHP = 10000
	if bHero
	then
		unitList = bot:GetNearbyHeroes( nRadius, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyLaneCreeps( nRadius, bEnemy )
	end
	for _, u in pairs( unitList )
	do
		if u:GetHealth() < weakestHP
			and J.CanCastOnMagicImmune( u )
		then
			weakest = u
			weakestHP = u:GetHealth()
		end
	end
	return weakest
end

function J.GetVulnerableWeakestUnitWithLotusCheck( bot, bHero, bEnemy, nRadius )
	local unitList = {}
	local weakest = nil
	local weakestHP = 10000
	if bHero
	then
		unitList = bot:GetNearbyHeroes( nRadius, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyLaneCreeps( nRadius, bEnemy )
	end
	for _, u in pairs( unitList )
	do
		if u:GetHealth() < weakestHP
			and J.CanCastOnNonMagicImmune( u )
			and J.CanCastOnTargetAdvanced( u )
			and J.CanCastOnTargetAdvanced( u )
		then
			weakest = u
			weakestHP = u:GetHealth()
		end
	end
	return weakest
end


function J.GetVulnerableUnitNearLoc( bot, bHero, bEnemy, nCastRange, nRadius, vLoc )

	local unitList = {}
	local weakest = nil
	local weakestHP = 10000

	if bHero
	then
		unitList = bot:GetNearbyHeroes( nCastRange, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyLaneCreeps( nCastRange, bEnemy )
	end

	for _, u in pairs( unitList )
	do
		if GetUnitToLocationDistance( u, vLoc ) < nRadius
			and u:GetHealth() < weakestHP
			and J.CanCastOnNonMagicImmune( u )
		then
			weakest = u
			weakestHP = u:GetHealth()
		end
	end

	return weakest

end


function J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, nCount )

	local nAoe = bot:FindAoELocation( true, true, bot:GetLocation(), nCastRange, nRadius, 0, 0 )

	if nAoe.count >= nCount
	then
		local nEnemyHeroList = J.GetEnemyList( bot, 1600 )
		local nTrueCount = 0
		for _, enemy in pairs( nEnemyHeroList )
		do
			if GetUnitToLocationDistance( enemy, nAoe.targetloc ) <= nRadius
				and not enemy:IsMagicImmune()
			then
				nTrueCount = nTrueCount + 1
			end
		end

		if nTrueCount >= nCount
		then
			return nAoe.targetloc
		end
	end

	return nil

end


function J.IsWithoutTarget( bot )

	return bot:GetTarget() == nil and bot:GetAttackTarget() == nil

end


function J.GetProperTarget( bot )

	local target = bot:GetTarget()

	if target == nil
	then
		target = bot:GetAttackTarget()
	end

	if target ~= nil
		and target:GetTeam() == bot:GetTeam()
		and ( target:IsHero() or target:IsBuilding() )
	then
		target = nil
	end

	return target

end


function J.IsAllyCanKill( target )

	if target:GetHealth() / target:GetMaxHealth() > 0.38
	then
		return false
	end

	local nTotalDamage = 0
	local nDamageType = DAMAGE_TYPE_PHYSICAL
	local nTeamMember = GetTeamPlayers( GetTeam() )
	for i = 1, #nTeamMember
	do
		local ally = GetTeamMember( i )
		if ally ~= nil and ally:IsAlive()
			and ( ally:GetAttackTarget() == target )
			and GetUnitToUnitDistance( ally, target ) <= ally:GetAttackRange() + 50
		then
			nTotalDamage = nTotalDamage + ally:GetAttackDamage()
		end
	end

	nTotalDamage = nTotalDamage * 2.44 + J.GetAttackProjectileDamageByRange( target, 1200 )

	if J.CanKillTarget( target, nTotalDamage, nDamageType )
	then
		return true
	end

	return false

end


function J.IsOtherAllyCanKillTarget( bot, target )

	if target:GetHealth() / target:GetMaxHealth() > 0.38
	then
		return false
	end

	local nTotalDamage = 0
	local nDamageType = DAMAGE_TYPE_PHYSICAL
	local nTeamMember = GetTeamPlayers( GetTeam() )

	for i = 1, #nTeamMember
	do
		local ally = GetTeamMember( i )
		if ally ~= nil
			and ally ~= bot
			and ally:IsAlive()
			and not J.IsDisabled( ally )
			and ally:GetHealth() / ally:GetMaxHealth() > 0.15
			and ally:IsFacingLocation( target:GetLocation(), 20 )
			and GetUnitToUnitDistance( ally, target ) <= ally:GetAttackRange() + 50
		then
			local allyTarget = J.GetProperTarget( ally )
			if allyTarget == nil or allyTarget == target or J.IsHumanPlayer( ally )
			then
				local allyDamageTime = J.IsHumanPlayer( ally ) and 6.0 or 2.0
				nTotalDamage = nTotalDamage + ally:GetEstimatedDamageToTarget( true, target, allyDamageTime, DAMAGE_TYPE_PHYSICAL )
			end
		end
	end

	if nTotalDamage > target:GetHealth()
	then
		return true
	end

	return false
end


function J.GetAlliesNearLoc( vLoc, nRadius )

	local allies = {}
	for i = 1, 5
	do
		local member = GetTeamMember( i )
		if member ~= nil
			and member:IsAlive()
			and GetUnitToLocationDistance( member, vLoc ) <= nRadius
		then
			table.insert( allies, member )
		end
	end

	return allies

end

function J.GetEnemiesNearLoc(vLoc, nRadius)

	local enemies = GetUnitList( UNIT_LIST_ENEMY_HEROES )
	return J.FilterGroup(enemies,function(u)
		return GetUnitToLocationDistance( u, vLoc ) <= nRadius
	end)
	
end

function J.IsAllyHeroBetweenAllyAndEnemy( hAlly, hEnemy, vLoc, nRadius )

	local vStart = hAlly:GetLocation()
	local vEnd = vLoc
	local heroList = hAlly:GetNearbyHeroes( 1600, false, BOT_MODE_NONE )
	for i, hero in pairs( heroList )
	do
		if hero ~= hAlly
		then
			local tResult = PointToLineDistance( vStart, vEnd, hero:GetLocation() )
			if tResult ~= nil
				and tResult.within
				and tResult.distance <= nRadius + 50
			then
				return true
			end
		end
	end

	heroList = hEnemy:GetNearbyHeroes( 1600, true, BOT_MODE_NONE )
	for i, hero in pairs( heroList )
	do
		if hero ~= hAlly
		then
			local tResult = PointToLineDistance( vStart, vEnd, hero:GetLocation() )
			if tResult ~= nil
				and tResult.within
				and tResult.distance <= nRadius + 50
			then
				return true
			end
		end
	end

	return false

end


function J.IsSandKingThere( bot, nCastRange, fTime )

	return false

end


function J.GetUltimateAbility( bot )

	return bot:GetAbilityInSlot( 5 )

end


function J.CanUseRefresherShard( bot )

	local ult = J.GetUltimateAbility( bot )

	if ult ~= nil
		and ult:IsPassive() == false
	then
		local ultCD = ult:GetCooldown()
		local manaCost = ult:GetManaCost()
		if bot:GetMana() >= manaCost
			and ult:GetCooldownTimeRemaining() >= ultCD / 2
		then
			return true
		end
	end

	return false

end


function J.GetMostUltimateCDUnit()

	local unit = nil
	local maxCD = 0
	for i, id in pairs( GetTeamPlayers( GetTeam() ) )
	do
		if IsHeroAlive( id )
		then
			local member = GetTeamMember( i )
			if member ~= nil and member:IsAlive()
				and member:GetUnitName() ~= "npc_dota_hero_nevermore"
				and member:GetUnitName() ~= "npc_dota_hero_arc_warden"
			then
				if member:GetUnitName() == "npc_dota_hero_silencer" or member:GetUnitName() == "npc_dota_hero_warlock"
				then
					return member
				end
				local ult = J.GetUltimateAbility( member )
				if ult ~= nil
					and ult:IsPassive() == false
					and ult:GetCooldown() >= maxCD
				then
					unit = member
					maxCD = ult:GetCooldown()
				end
			end
		end
	end

	return unit

end


function J.GetPickUltimateScepterUnit()

	local unit = nil
	local maxNetWorth = 0
	for i, id in pairs( GetTeamPlayers( GetTeam() ) )
	do
		if IsHeroAlive( id )
		then
			local member = GetTeamMember( i )
			if member ~= nil and member:IsAlive()
				and not member:HasScepter()
				and ( member:GetPrimaryAttribute() == ATTRIBUTE_INTELLECT
					 or not member:IsBot() )
			then
				if not member:IsBot()
				then
					return member
				end

				if member:GetUnitName() ~= "npc_dota_hero_warlock"
					and member:GetUnitName() ~= "npc_dota_hero_zuus"
					and ( member:GetItemInSlot( 8 ) == nil or member:GetItemInSlot( 7 ) == nil )
				then
					local mNetWorth = member:GetNetWorth()
					if mNetWorth >= maxNetWorth
					then
						unit = member
						maxNetWorth = mNetWorth
					end
				end
			end
		end
	end

	return unit

end


function J.CanUseRefresherOrb( bot )

	local ult = J.GetUltimateAbility( bot )

	if ult ~= nil
		and ult:IsPassive() == false
	then
		local ultCD = ult:GetCooldown()
		local manaCost = ult:GetManaCost()
		if bot:GetMana() >= manaCost + 375
			and ult:GetCooldownTimeRemaining() >= ultCD / 2
		then
			return true
		end
	end

	return false
end


function J.IsSuspiciousIllusion( npcTarget )

	if not npcTarget:IsHero()
		or npcTarget:IsCastingAbility()
		or npcTarget:IsUsingAbility()
		or npcTarget:IsChanneling()
		-- or npcTarget:HasModifier( "modifier_item_satanic_unholy" )
		-- or npcTarget:HasModifier( "modifier_item_mask_of_madness_berserk" )
		-- or npcTarget:HasModifier( "modifier_black_king_bar_immune" )
		-- or npcTarget:HasModifier( "modifier_rune_doubledamage" )
		-- or npcTarget:HasModifier( "modifier_rune_regen" )
		-- or npcTarget:HasModifier( "modifier_rune_haste" )
		-- or npcTarget:HasModifier( "modifier_rune_arcane" )
		-- or npcTarget:HasModifier( "modifier_item_phase_boots_active" )
	then
		return false
	end

	local bot = GetBot()

	if npcTarget:GetTeam() == bot:GetTeam()
	then
		return npcTarget:IsIllusion() or npcTarget:HasModifier( "modifier_arc_warden_tempest_double" )
	elseif npcTarget:GetTeam() == GetOpposingTeam()
	then

		if npcTarget:HasModifier( 'modifier_illusion' )
			or npcTarget:HasModifier( 'modifier_phantom_lancer_doppelwalk_illusion' )
			or npcTarget:HasModifier( 'modifier_phantom_lancer_juxtapose_illusion' )
			or npcTarget:HasModifier( 'modifier_darkseer_wallofreplica_illusion' )
			or npcTarget:HasModifier( 'modifier_terrorblade_conjureimage' )
		then
			return true
		end

		local tID = npcTarget:GetPlayerID()

		if not IsHeroAlive( tID )
		then
			return true
		end

		if GetHeroLevel( tID ) > npcTarget:GetLevel()
		then
			return true
		end
		--[[
		if GetSelectedHeroName( tID ) ~= "npc_dota_hero_morphling"
			and GetSelectedHeroName( tID ) ~= npcTarget:GetUnitName()
		then
			return true
		end
		--]]
	end

	return false

end


function J.CanCastAbilityOnTarget( npcTarget, bIgnoreMagicImmune )

	return npcTarget:CanBeSeen()
			and ( bIgnoreMagicImmune or not npcTarget:IsMagicImmune() )
			and not npcTarget:IsInvulnerable()
			and not J.IsSuspiciousIllusion( npcTarget )
			and not J.HasForbiddenModifier( npcTarget )
			-- and not J.IsAllyCanKill( npcTarget )

end


function J.CanCastOnMagicImmune( npcTarget )

	return npcTarget:CanBeSeen()
			and not npcTarget:IsInvulnerable()
			and not J.IsSuspiciousIllusion( npcTarget )
			and not J.HasForbiddenModifier( npcTarget )
			and not J.IsAllyCanKill( npcTarget )

end


function J.CanCastOnNonMagicImmune( npcTarget )

	return npcTarget:CanBeSeen()
			and not npcTarget:IsMagicImmune()
			and not npcTarget:IsInvulnerable()
			and not J.IsSuspiciousIllusion( npcTarget )
			and not J.HasForbiddenModifier( npcTarget )
			and not J.IsAllyCanKill( npcTarget )

end


function J.CanCastOnTargetAdvanced( npcTarget )

	if npcTarget:GetUnitName() == 'npc_dota_hero_antimage' --and npcTarget:IsBot()
	then

		if npcTarget:IsSilenced()
			or npcTarget:IsStunned()
			or npcTarget:IsHexed()
			or npcTarget:IsNightmared()
			or npcTarget:IsChanneling()
			or J.IsTaunted( npcTarget )
			or npcTarget:GetMana() < 45
		then
			return J.CanCastUnitSpellOnTarget( npcTarget, 0.27 )
		end

		return false
	end

	return J.CanCastUnitSpellOnTarget( npcTarget, 0.27 )

end


--加入时间后的进阶函数
function J.CanCastUnitSpellOnTarget( npcTarget, nDelay )

	for _, modifier in pairs( J.Buff["hero_has_spell_shield"] )
	do
		if npcTarget:HasModifier( modifier )
			and J.GetModifierTime( npcTarget, modifier ) >= nDelay
		then
			if modifier == "modifier_dazzle_shallow_grave" then
				if npcTarget:GetHealth() <= 300 then
					return false
				end
			else
				return false
			end
		end
	end
	return true
end


function J.CanKillTarget( npcTarget, dmg, dmgType )

	return npcTarget:GetActualIncomingDamage( dmg, dmgType ) >= npcTarget:GetHealth()

end


--未计算技能增强
function J.WillKillTarget( npcTarget, dmg, dmgType, nDelay )

	local targetHealth = npcTarget:GetHealth() + npcTarget:GetHealthRegen() * nDelay + 0.8

	local nRealBonus = J.GetTotalAttackWillRealDamage( npcTarget, nDelay )

	local nTotalDamage = npcTarget:GetActualIncomingDamage( dmg, dmgType ) + nRealBonus

	return nTotalDamage > targetHealth and nRealBonus < targetHealth - 1

end


--未计算技能增强
function J.WillMixedDamageKillTarget( npcTarget, nPhysicalDamge, nMagicalDamage, nPureDamage, nDelay )

	local targetHealth = npcTarget:GetHealth() + npcTarget:GetHealthRegen() * nDelay + 0.8

	local nRealBonus = J.GetTotalAttackWillRealDamage( npcTarget, nDelay )

	local nRealPhysicalDamge = npcTarget:GetActualIncomingDamage( nPhysicalDamge, DAMAGE_TYPE_PHYSICAL )

	local nRealMagicalDamge = npcTarget:GetActualIncomingDamage( nMagicalDamage, DAMAGE_TYPE_MAGICAL )

	local nRealPureDamge = npcTarget:GetActualIncomingDamage( nPureDamage, DAMAGE_TYPE_PURE )

	local nTotalDamage = nRealPhysicalDamge + nRealMagicalDamge + nRealPureDamge + nRealBonus

	return nTotalDamage > targetHealth and nRealBonus < targetHealth - 1

end

--计算了技能增强
function J.WillMagicKillTarget( bot, npcTarget, dmg, nDelay )

	local nDamageType = DAMAGE_TYPE_MAGICAL

	local MagicResistReduce = 1 - npcTarget:GetMagicResist()

	if MagicResistReduce < 0.05 then MagicResistReduce = 0.05 end

	local HealthBack = npcTarget:GetHealthRegen() * nDelay

	local EstDamage = dmg * ( 1 + bot:GetSpellAmp() ) - HealthBack / MagicResistReduce

	if npcTarget:HasModifier( "modifier_medusa_mana_shield" )
	then
		local EstDamageMaxReduce = EstDamage * 0.98
		if npcTarget:GetMana() * 3.2 >= EstDamageMaxReduce
		then
			EstDamage = EstDamage * 0.02
		else
			EstDamage = EstDamage - (npcTarget:GetMana() * 3.2) * 0.98
		end
	end

	if npcTarget:GetUnitName() == "npc_dota_hero_mars" then
		if not npcTarget:IsFacingLocation( bot:GetLocation(), 110 ) then
			EstDamage = EstDamage * 0.3
		elseif not npcTarget:IsFacingLocation( bot:GetLocation(), 60 ) then
			EstDamage = EstDamage * 0.65
		end
	end

	if npcTarget:GetUnitName() == "npc_dota_hero_spectre" then
		EstDamage = EstDamage * 0.8
	end

	if npcTarget:GetUnitName() == "npc_dota_hero_bristleback" then
		if not npcTarget:IsFacingLocation( bot:GetLocation(), 145 ) then
			EstDamage = EstDamage * 0.6
		elseif not npcTarget:IsFacingLocation( bot:GetLocation(), 125 ) then
			EstDamage = EstDamage * 0.8
		end
	end

	if npcTarget:HasModifier( "modifier_kunkka_ghost_ship_damage_delay" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_kunkka_ghost_ship_damage_delay" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.55 end
	end

	if npcTarget:HasModifier( "modifier_templar_assassin_refraction_absorb" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_templar_assassin_refraction_absorb" )
		if buffTime >= nDelay then EstDamage = 0 end
	end

	--7.32
	if npcTarget:HasModifier( "modifier_lich_frost_shield" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_lich_frost_shield" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.4 end
	end

	if npcTarget:HasModifier( "modifier_nyx_assassin_burrow" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_nyx_assassin_burrow" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.6 end
	end

	if npcTarget:HasModifier( "modifier_legion_commander_duel" ) and npcTarget:HasScepter()
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_legion_commander_duel" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.5 end
	end

	if npcTarget:HasModifier( "modifier_ogre_magi_smash_buff" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_ogre_magi_smash_buff" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.15 end
	end

	if npcTarget:HasModifier( "modifier_ursa_enrage" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_ursa_enrage" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.2 end
	end

	if npcTarget:HasModifier( "modifier_vengefulspirit_nether_swap_damage_reduction" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_vengefulspirit_nether_swap_damage_reduction" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.5 end
	end

	if npcTarget:HasModifier( "modifier_item_wraith_pact_death_aura" )
	then
		local buffTime = J.GetModifierTime( npcTarget, "modifier_item_wraith_pact_death_aura" )
		if buffTime >= nDelay then EstDamage = EstDamage * 0.7 end
	end

	local nRealDamage = npcTarget:GetActualIncomingDamage( EstDamage, nDamageType )

	return nRealDamage >= npcTarget:GetHealth() --, nRealDamage

end


function J.HasForbiddenModifier( npcTarget )

	for _, mod in pairs( J.Buff['enemy_is_immune'] )
	do
		if npcTarget:HasModifier( mod )
		then
			return true
		end
	end

	if npcTarget:IsHero()
	then
		local enemies = npcTarget:GetNearbyHeroes( 800, false, BOT_MODE_NONE )
		if enemies ~= nil and #enemies >= 2
		then
			for _, mod in pairs( J.Buff['enemy_is_undead'] )
			do
				if npcTarget:HasModifier( mod )
				then
					return true
				end
			end
		end
		
		if not npcTarget:IsBot()
		then
			
			local nID = npcTarget:GetPlayerID()
			local nKillCount = GetHeroKills( nID )
			local nDeathCount = GetHeroDeaths( nID )
			
			if nDeathCount >= 6 
				and nKillCount <= 6
				and nKillCount / nDeathCount <= 0.5
			then
				return true
			end
		
		end
		
	else
		if npcTarget:HasModifier( "modifier_crystal_maiden_frostbite" )
			or npcTarget:HasModifier( "modifier_fountain_glyph" )
		then
			return true
		end
	end
	
	return false
end

function J.GetBonusCastRange( bot )

	local bonusRange = 0

	local itemAether = J.IsItemAvailable( "item_aether_lens" )
	local itemOctarine = J.IsItemAvailable( "item_octarine_core" )
	if ( itemAether ~= nil or itemOctarine ~= nil ) then bonusRange = bonusRange + 225 end

	local itemOptic = J.IsItemAvailable( "item_keen_optic" )
	if itemOptic ~= nil then bonusRange = bonusRange + 75 end

	local itemVizier = J.IsItemAvailable( "item_eye_of_the_vizier" )
	if itemVizier ~= nil then bonusRange = bonusRange + 125 end

	local itemPsychic = J.IsItemAvailable( "item_psychic_headband" )
	if itemPsychic ~= nil then bonusRange = bonusRange + 100 end

	local itemSeerStone = J.IsItemAvailable( "item_seer_stone" )
	if itemSeerStone ~= nil then bonusRange = bonusRange + 350 end

	local itemTelescope = J.IsItemAvailable( "item_spy_gadget" )
	if ( itemTelescope ~= nil or bot:HasModifier( 'modifier_item_spy_gadget' ) ) then bonusRange = bonusRange + 100 end

	return bonusRange

end

function J.IsHealing( bot )
	for _, modifier in pairs( J.Buff["hero_is_healing"] )
	do
		if bot:HasModifier( modifier )
		then
			return true
		end
	end
	return false
end


function J.ShouldInterrupt( bot )

	if bot:IsChanneling()
		or bot:IsCastingAbility()
		or bot:HasModifier( 'modifier_crystal_maiden_freezing_field' )
	then
		return true
	end

	return false

end


function J.GetMeleeAlly( bot )

	local nMelee = nil
	local nMeleeAttackRange = 1000
	local nAlliedHeroesInRange = bot:GetNearbyHeroes( 1400, false, BOT_MODE_NONE )

	for _, npcAlly in pairs( nAlliedHeroesInRange )
	do
		npcAttackRange = npcAlly:GetAttackRange()
		if nMeleeAttackRange < npcAttackRange
		then
			nMeleeAttackRange = npcAttackRange
			nMelee = npcAlly
		end
	end

	return nMelee

end

function J.ShouldEscape( bot )

	local tableNearbyAttackAllies = bot:GetNearbyHeroes( 800, false, BOT_MODE_ATTACK )

	if #tableNearbyAttackAllies > 0 and J.GetHP( bot ) > 0.16 then return false end

	local tableNearbyEnemyHeroes = bot:GetNearbyHeroes( 1000, true, BOT_MODE_NONE )
	if bot:WasRecentlyDamagedByAnyHero( 2.0 )
		or bot:WasRecentlyDamagedByTower( 2.0 )
		or #tableNearbyEnemyHeroes >= 2
	then
		return true
	end
end


function J.IsDisabled( npcTarget )

	if npcTarget:GetTeam() ~= GetTeam()
	then
		return npcTarget:IsRooted()
				or npcTarget:IsStunned()
				or npcTarget:IsHexed()
				or npcTarget:IsNightmared()
				or J.IsTaunted( npcTarget )
	else

		if npcTarget:IsStunned() and J.GetRemainStunTime( npcTarget ) > 0.3
		then
			return true
		end

		if npcTarget:IsSilenced()
			and not npcTarget:HasModifier( "modifier_item_mask_of_madness_berserk" )
			and J.IsWithoutTarget( npcTarget )
		then
			return true
		end

		return npcTarget:IsRooted()
				or npcTarget:IsHexed()
				or npcTarget:IsNightmared()
				or J.IsTaunted( npcTarget )

	end

end


function J.IsTaunted( npcTarget )

	for _, modifier in pairs( J.Buff["hero_is_taunted"] )
	do
		if npcTarget:HasModifier( modifier )
		then
			return true
		end
	end

	return false

end


function J.IsInRange( bot, npcTarget, nRadius )

	return GetUnitToUnitDistance( bot, npcTarget ) <= nRadius

end


function J.IsInLocRange( npcTarget, nLoc, nRadius )

	return GetUnitToLocationDistance( npcTarget, nLoc ) <= nRadius

end


function J.IsInTeamFight( bot, nRadius )

	if nRadius == nil or nRadius > 1600 then nRadius = 1600 end

	local attackModeAllyList = bot:GetNearbyHeroes( nRadius, false, BOT_MODE_ATTACK )

	return #attackModeAllyList >= 2 and bot:GetActiveMode() ~= BOT_MODE_RETREAT

end


function J.IsRetreating( bot )

	local mode = bot:GetActiveMode()
	local modeDesire = bot:GetActiveModeDesire()
	local bDamagedByAnyHero = bot:WasRecentlyDamagedByAnyHero( 2.0 )

	return ( mode == BOT_MODE_RETREAT and modeDesire >= BOT_MODE_DESIRE_HIGH and bot:DistanceFromFountain() > 600 )
		 or ( mode == BOT_MODE_EVASIVE_MANEUVERS and bDamagedByAnyHero )
		 or ( bot:HasModifier( 'modifier_bloodseeker_rupture' ) and bDamagedByAnyHero )
		 or ( mode == BOT_MODE_FARM and modeDesire > BOT_MODE_DESIRE_ABSOLUTE )
		
end


function J.IsGoingOnSomeone( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_ROAM
		or mode == BOT_MODE_TEAM_ROAM
		or mode == BOT_MODE_ATTACK
		or mode == BOT_MODE_DEFEND_ALLY

end


function J.IsDefending( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_DEFEND_TOWER_TOP
		or mode == BOT_MODE_DEFEND_TOWER_MID
		or mode == BOT_MODE_DEFEND_TOWER_BOT

end


function J.IsPushing( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_PUSH_TOWER_TOP
		or mode == BOT_MODE_PUSH_TOWER_MID
		or mode == BOT_MODE_PUSH_TOWER_BOT

end


function J.IsLaning( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_LANING

end


function J.IsDoingRoshan( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_ROSHAN

end


function J.IsFarming( bot )

	local mode = bot:GetActiveMode()
	local nTarget = J.GetProperTarget( bot )

	return mode == BOT_MODE_FARM
			or ( nTarget ~= nil
					and nTarget:IsAlive()
					and nTarget:GetTeam() == TEAM_NEUTRAL
					and not J.IsRoshan( nTarget ) )
end


function J.IsShopping( bot )

	local mode = bot:GetActiveMode()

	return mode == BOT_MODE_RUNE
		or mode == BOT_MODE_SECRET_SHOP
		or mode == BOT_MODE_SIDE_SHOP

end


function J.GetTeamFountain()

	local Team = GetTeam()
	if Team == TEAM_DIRE
	then
		return DB
	else
		return RB
	end

end


function J.GetEnemyFountain()

	local Team = GetTeam()

	if Team == TEAM_DIRE
	then
		return RB
	else
		return DB
	end

end


function J.GetComboItem( bot, sItemName )

	local Slot = bot:FindItemSlot( sItemName )

	if Slot >= 0 and Slot <= 5
	then
		return bot:GetItemInSlot( Slot )
	end

end


function J.HasItem( bot, sItemName )

	local Slot = bot:FindItemSlot( sItemName )

	if Slot >= 0 and Slot <= 5 then	return true end

	return false

end


function J.IsItemAvailable( sItemName )

	local bot = GetBot()

	local slot = bot:FindItemSlot( sItemName )

	if slot >= 0 and slot <= 5
	then
		return bot:GetItemInSlot( slot )
	end

end


function J.GetMostHpUnit( unitList )

	local mostHpUnit = nil
	local maxHP = 0
	for _, unit in pairs( unitList )
	do
		local uHp = unit:GetHealth()
		if uHp > maxHP
		then
			mostHpUnit = unit
			maxHP = uHp
		end
	end

	return mostHpUnit

end


function J.GetLeastHpUnit( unitList )

	local leastHpUnit = nil
	local minHP = 999999

	for _, unit in pairs( unitList )
	do
		local uHp = unit:GetHealth()
		if uHp < minHP
		then
			leastHpUnit = unit
			minHP = uHp
		end
	end

	return leastHpUnit

end


function J.IsAllowedToSpam( bot, nManaCost )

	if bot:HasModifier( "modifier_silencer_curse_of_the_silent" ) then return false end

	if bot:HasModifier( "modifier_rune_regen" ) then return true end

	return ( bot:GetMana() - nManaCost ) / bot:GetMaxMana() >= fKeepManaPercent

end


function J.IsAllyUnitSpell( sAbilityName )

	return J.Skill['sAllyUnitAbilityIndex'][sAbilityName] == true

end


function J.IsProjectileUnitSpell( sAbilityName )

	return J.Skill['sProjectileAbilityIndex'][sAbilityName] == true


end


function J.IsOnlyProjectileSpell( sAbilityName )

	return J.Skill['sOnlyProjectileAbilityIndex'][sAbilityName] == true

end


function J.IsStunProjectileSpell( sAbilityName )

	return J.Skill['sStunProjectileAbilityIndex'][sAbilityName] == true

end


function J.IsWillBeCastUnitTargetSpell( bot, nRadius )

	if nRadius > 1600 then nRadius = 1600 end

	local enemyList = bot:GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )
	for _, npcEnemy in pairs( enemyList )
	do
		if npcEnemy ~= nil and npcEnemy:IsAlive()
			and ( npcEnemy:IsCastingAbility() or npcEnemy:IsUsingAbility() )
			and npcEnemy:IsFacingLocation( bot:GetLocation(), 20 )
		then
			local nAbility = npcEnemy:GetCurrentActiveAbility()
			if nAbility ~= nil
				and nAbility:GetBehavior() == ABILITY_BEHAVIOR_UNIT_TARGET
			then
				local sAbilityName = nAbility:GetName()
				if not J.IsAllyUnitSpell( sAbilityName )
				then
					if J.IsInRange( npcEnemy, bot, 330 )
						or not J.IsProjectileUnitSpell( sAbilityName )
					then
						if not J.IsHumanPlayer( npcEnemy )
						then
							return true
						else
							local nCycle = npcEnemy:GetAnimCycle()
							local nPoint = nAbility:GetCastPoint()
							if nCycle > 0.1 and nPoint * ( 1 - nCycle ) < 0.27 --极限时机0.26
							then
								return true
							end
						end
					end
				end
			end
		end
	end

	return false

end


function J.IsWillBeCastPointSpell( bot, nRadius )

	local enemyList = bot:GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )

	for _, npcEnemy in pairs( enemyList )
	do
		if npcEnemy ~= nil and npcEnemy:IsAlive()
			and ( npcEnemy:IsCastingAbility() or npcEnemy:IsUsingAbility() )
			and npcEnemy:IsFacingLocation( bot:GetLocation(), 50 )
		then
			local nAbility = npcEnemy:GetCurrentActiveAbility()
			if nAbility ~= nil
			then
				if nAbility:GetBehavior() == ABILITY_BEHAVIOR_POINT
					or nAbility:GetBehavior() == ABILITY_BEHAVIOR_NO_TARGET
					or nAbility:GetBehavior() == 48
				then
					return true
				end
			end
		end
	end

	return false

end


--可躲避敌方非攻击弹道
function J.IsProjectileIncoming( bot, range )

	local incProj = bot:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if p.is_dodgeable
			and not p.is_attack
			and GetUnitToLocationDistance( bot, p.location ) < range
			and ( p.caster == nil or p.caster:GetTeam() ~= GetTeam() )
			and ( p.ability ~= nil
					and not J.IsOnlyProjectileSpell( p.ability:GetName() )
					and ( p.ability:GetName() ~= "medusa_mystic_snake"
							or p.caster == nil
							or p.caster:GetUnitName() == "npc_dota_hero_medusa" ) )
		then
			return true
		end
	end

	return false

end


--可反弹敌方非攻击弹道
function J.IsUnitTargetProjectileIncoming( bot, range )

	local incProj = bot:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if not p.is_attack
			and GetUnitToLocationDistance( bot, p.location ) < range
			and ( p.caster == nil
				 or ( p.caster:GetTeam() ~= bot:GetTeam()
					 and p.caster:IsHero()
					 and p.caster:GetUnitName() ~= "npc_dota_hero_antimage"
					 and p.caster:GetUnitName() ~= "npc_dota_hero_templar_assassin" ) )
			and ( p.ability ~= nil
				 and ( p.ability:GetName() ~= "medusa_mystic_snake"
						or p.caster == nil
						or p.caster:GetUnitName() == "npc_dota_hero_medusa" ) )
			and ( p.ability:GetBehavior() == ABILITY_BEHAVIOR_UNIT_TARGET
				 or not J.IsOnlyProjectileSpell( p.ability:GetName() ) )
		then
			return true
		end
	end

	return false

end


--将被眩晕的弹道
function J.IsStunProjectileIncoming( bot, range )

	local incProj = bot:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if not p.is_attack
			and GetUnitToLocationDistance( bot, p.location ) < range
			and p.ability ~= nil
			and J.IsStunProjectileSpell( p.ability:GetName() )
		then
			return true
		end
	end

	return false

end


--攻击弹道
function J.IsAttackProjectileIncoming( bot, range )

	local incProj = bot:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if p.is_attack
			and GetUnitToLocationDistance( bot, p.location ) < range
		then
			return true
		end
	end

	return false

end


--非攻击敌方弹道
function J.IsNotAttackProjectileIncoming( bot, range )

	local incProj = bot:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if not p.is_attack
			and GetUnitToLocationDistance( bot, p.location ) < range
			and ( p.caster == nil or p.caster:GetTeam() ~= bot:GetTeam() )
			and ( p.ability ~= nil
					and ( p.ability:GetName() ~= "medusa_mystic_snake"
							or p.caster == nil
							or p.caster:GetUnitName() == "npc_dota_hero_medusa" ) )
		then
			return true
		end
	end

	return false

end


--以下可少算但不可多算
function J.GetAttackProDelayTime( bot, nCreep )

	local botName = bot:GetUnitName()
	local botAttackRange = bot:GetAttackRange()
	local botAttackPoint = bot:GetAttackPoint()
	local botAttackSpeed = bot:GetAttackSpeed()
	local botProSpeed = bot:GetAttackProjectileSpeed()
	local botMoveSpeed = bot:GetCurrentMovementSpeed()
	local botAttackPointTime = botAttackPoint / botAttackSpeed
	local botAttackIdleTime = bot:GetSecondsPerAttack() - botAttackPointTime
	local nLastAttackRemainIdleTime = 0

	if GameTime() - bot:GetLastAttackTime() < botAttackIdleTime
	then
		nLastAttackRemainIdleTime = botAttackIdleTime - ( GameTime() - bot:GetLastAttackTime() )
	end

	local nAttackDamageDelayTime = botAttackPointTime + nLastAttackRemainIdleTime * 0.98
	local nDist = GetUnitToUnitDistance( bot, nCreep )

	if bot:GetAttackTarget() == nCreep
		and bot:GetAnimActivity() == 1503
		and bot:GetAnimCycle() < botAttackPoint
	then
		nAttackDamageDelayTime = 0.9 * ( botAttackPoint - bot:GetAnimCycle() ) / botAttackSpeed
	end

	if botAttackRange > 320 or botName == "npc_dota_hero_templar_assassin"
	then

		local ignoreDist = 39
		if bot:GetPrimaryAttribute() == ATTRIBUTE_INTELLECT then ignoreDist = 59 end

		local projectMoveDist = nDist - ignoreDist

		if projectMoveDist < 0 then projectMoveDist = 0 end

		if projectMoveDist > botAttackRange then projectMoveDist = botAttackRange - 32 end

		nAttackDamageDelayTime = nAttackDamageDelayTime + projectMoveDist / botProSpeed

		if nDist > botAttackRange + ignoreDist / 1.2 and botName ~= "npc_dota_hero_sniper"
		then
			nAttackDamageDelayTime = nAttackDamageDelayTime + ( nDist - botAttackRange - ignoreDist / 1.2 ) / botMoveSpeed
		end

	end

	if botAttackRange < 326
		and nDist > botAttackRange + 50
		and botName ~= "npc_dota_hero_templar_assassin"
	then
		nAttackDamageDelayTime = nAttackDamageDelayTime + ( nDist - botAttackRange - 50 ) / botMoveSpeed
	end

	return nAttackDamageDelayTime

end


--当前点 * 攻击间隔 / 1.0 = 当前时
function J.GetCreepAttackActivityWillRealDamage( nUnit, nTime )

	local bot = GetBot()
	local botLV = bot:GetLevel()
	local gameTime = GameTime()
	local nDamage = 0
	local othersBeEnemy = true

	if nUnit:GetTeam() ~= bot:GetTeam() then othersBeEnemy = false end

	local nCreeps = bot:GetNearbyLaneCreeps( 1600, othersBeEnemy )
	for _, creep in pairs( nCreeps )
	do
		if creep:GetAttackTarget() == nUnit
			and creep:GetAnimActivity() == 1503
			and creep:GetLastAttackTime() < gameTime - 0.2
		then
			local attackPoint	= creep:GetAttackPoint()
			local animCycle	 = creep:GetAnimCycle()
			local attackPerTime = creep:GetSecondsPerAttack()

			if J.IsKeyWordUnit( 'melee', creep )
				and animCycle < attackPoint
				and ( attackPoint - animCycle ) * attackPerTime < nTime * ( 0.99 - botLV / 300 )
			then
				nDamage = nDamage + creep:GetAttackDamage() * creep:GetAttackCombatProficiency( nUnit )
			end

			if J.IsKeyWordUnit( 'ranged', creep )
				and animCycle < attackPoint
			then
				local nDist = GetUnitToUnitDistance( creep, nUnit ) - 22
				local nProjectSpeed = creep:GetAttackProjectileSpeed()
				local nProjectTime = nDist / ( nProjectSpeed + 1 )
				if ( attackPoint - animCycle ) * attackPerTime + nProjectTime < nTime * ( 0.98 - botLV / 200 )
				then
					nDamage = nDamage + creep:GetAttackDamage() * creep:GetAttackCombatProficiency( nUnit )
				end
			end

			if J.IsKeyWordUnit( 'siege', creep )
				and animCycle < 0.292 --0.285
			then
				local nDist = GetUnitToUnitDistance( creep, nUnit ) - 28
				local nProjectSpeed = creep:GetAttackProjectileSpeed()
				local nProjectTime = nDist / ( nProjectSpeed + 1 )
				if ( 0.292 - animCycle ) * 0.699 / 0.292 + nProjectTime < nTime * ( 0.9 - botLV / 150 )
				then
					nDamage = nDamage + creep:GetAttackDamage() * creep:GetAttackCombatProficiency( nUnit )
				end
			end

		end
	end

	return nUnit:GetActualIncomingDamage( nDamage, DAMAGE_TYPE_PHYSICAL )

end


function J.GetCreepAttackProjectileWillRealDamage( nUnit, nTime )

	local nDamage = 0
	local incProj = nUnit:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if p.is_attack
			and p.caster ~= nil
		then
			local nProjectSpeed = p.caster:GetAttackProjectileSpeed()
			if p.caster:IsTower() then nProjectSpeed = nProjectSpeed * 0.93 end
			local nProjectDist = nProjectSpeed * nTime * 0.95
			local nDistance	 = GetUnitToLocationDistance( nUnit, p.location )
			if nProjectDist > nDistance * 1.02
			then
				nDamage = nDamage + p.caster:GetAttackDamage() * p.caster:GetAttackCombatProficiency( nUnit )
			end
		end
	end

	return nUnit:GetActualIncomingDamage( nDamage, DAMAGE_TYPE_PHYSICAL )

end


function J.GetTotalAttackWillRealDamage( nUnit, nTime )

	 return J.GetCreepAttackProjectileWillRealDamage( nUnit, nTime ) + J.GetCreepAttackActivityWillRealDamage( nUnit, nTime )

end


function J.GetAttackProjectileDamageByRange( nUnit, nRadius )

	local nDamage = 0
	local incProj = nUnit:GetIncomingTrackingProjectiles()
	for _, p in pairs( incProj )
	do
		if p.is_attack and p.caster ~= nil
			and GetUnitToLocationDistance( nUnit, p.location ) < nRadius
		then
			nDamage = nDamage + p.caster:GetAttackDamage() * p.caster:GetAttackCombatProficiency( nUnit )
		end
	end

	return nDamage

end


function J.GetCorrectLoc( npcTarget, fDelay )

	local nStability = npcTarget:GetMovementDirectionStability()

	local vFirst = npcTarget:GetLocation()
	local vFuture = npcTarget:GetExtrapolatedLocation( fDelay )
	local vMidFutrue = ( vFirst + vFuture ) * 0.5
	local vLowFutrue = ( vFirst + vMidFutrue ) * 0.5
	local vHighFutrue = ( vFuture + vMidFutrue ) * 0.5


	if nStability < 0.5
	then
		return vLowFutrue
	elseif nStability < 0.7
	then
		return vMidFutrue
	elseif nStability < 0.9
	then
		return vHighFutrue
	end

	return vFuture
end


function J.GetEscapeLoc()

	local bot = GetBot()
	local team = GetTeam()

	if bot:DistanceFromFountain() > 2500
	then
		return GetAncient( team ):GetLocation()
	else
		if team == TEAM_DIRE
		then
			return DB
		else
			return RB
		end
	end

end


function J.IsStuck2( bot )

	if bot.stuckLoc ~= nil and bot.stuckTime ~= nil
	then
		local EAd = GetUnitToUnitDistance( bot, GetAncient( GetOpposingTeam() ) )
		if DotaTime() > bot.stuckTime + 5.0 and GetUnitToLocationDistance( bot, bot.stuckLoc ) < 25
			and bot:GetCurrentActionType() == BOT_ACTION_TYPE_MOVE_TO and EAd > 2200
		then
			print( bot:GetUnitName().." is stuck" )
			--DebugPause()
			return true
		end
	end

	return false

end


function J.IsStuck( bot )

	if bot.stuckLoc ~= nil and bot.stuckTime ~= nil
	then
		local attackTarget = bot:GetAttackTarget()
		local EAd = GetUnitToUnitDistance( bot, GetAncient( GetOpposingTeam() ) )
		local TAd = GetUnitToUnitDistance( bot, GetAncient( GetTeam() ) )
		local Et = bot:GetNearbyTowers( 450, true )
		local At = bot:GetNearbyTowers( 450, false )
		if bot:GetCurrentActionType() == BOT_ACTION_TYPE_MOVE_TO
			and attackTarget == nil and EAd > 2200 and TAd > 2200 and #Et == 0 and #At == 0
			and DotaTime() > bot.stuckTime + 5.0
			and GetUnitToLocationDistance( bot, bot.stuckLoc ) < 25
		then
			print( bot:GetUnitName().." is stuck" )
			return true
		end
	end

	return false

end


function J.IsExistInTable( u, tUnit )

	for _, t in pairs( tUnit )
	do
		if u == t
		then
			return true
		end
	end

	return false

end


function J.CombineTwoTable( tableA, tableB )

	local targetTable = tableA
	local Num = #tableA

	for i, u in pairs( tableB )
	do
		targetTable[Num + i] = u
	end

	return targetTable
end


function J.GetInvUnitInLocCount( bot, nRadius, nFindRadius, vLocation, pierceImmune )

	local nUnits = 0
	if nRadius > 1600 then nRadius = 1600 end
	local unitList = bot:GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )
	for _, u in pairs( unitList ) do
		if ( ( pierceImmune and J.CanCastOnMagicImmune( u ) )
			 or ( not pierceImmune and J.CanCastOnNonMagicImmune( u ) ) )
			and GetUnitToLocationDistance( u, vLocation ) <= nFindRadius
		then
			nUnits = nUnits + 1
		end
	end

	return nUnits

end


function J.GetInLocLaneCreepCount( bot, nRadius, nFindRadius, vLocation )

	local nUnits = 0
	if nRadius > 1600 then nRadius = 1600 end
	local unitList = bot:GetNearbyLaneCreeps( nRadius, true )
	for _, u in pairs( unitList ) do
		if GetUnitToLocationDistance( u, vLocation ) <= nFindRadius
		then
			nUnits = nUnits + 1
		end
	end

	return nUnits

end


function J.GetInvUnitCount( pierceImmune, unitList )

	local nUnits = 0
	if unitList ~= nil
	then
		for _, u in pairs( unitList )
		do
			if ( pierceImmune and J.CanCastOnMagicImmune( u ) )
				or ( not pierceImmune and J.CanCastOnNonMagicImmune( u ) )
			then
				nUnits = nUnits + 1
			end
		end
	end

	return nUnits

end


----------------------------------------------------new functions 2018.12.7

function J.GetDistanceFromEnemyFountain( bot )

	local EnemyFountain = J.GetEnemyFountain()
	local Distance = GetUnitToLocationDistance( bot, EnemyFountain )

	return Distance

end


function J.GetDistanceFromAllyFountain( bot )

	local OurFountain = J.GetTeamFountain()
	local Distance = GetUnitToLocationDistance( bot, OurFountain )

	return Distance

end


function J.GetDistanceFromAncient( bot, bEnemy )

	local targetAncient = GetAncient( GetTeam() )

	if bEnemy then targetAncient = GetAncient( GetOpposingTeam() ) end

	return GetUnitToUnitDistance( bot, targetAncient )

end


function J.GetAroundTargetAllyHeroCount( target, nRadius )

	local heroList = J.GetAlliesNearLoc( target:GetLocation(), nRadius )

	return #heroList

end


function J.GetAroundTargetOtherAllyHeroCount( bot, target, nRadius )

	local heroList = J.GetAlliesNearLoc( target:GetLocation(), nRadius )

	if GetUnitToUnitDistance( bot, target ) <= nRadius
	then
		return #heroList - 1
	end

	return #heroList

end


function J.GetAllyCreepNearLoc( bot, vLoc, nRadius )

	local AllyCreepsAll = bot:GetNearbyCreeps( 1600, false )
	local allyCreepList = { }

	for _, creep in pairs( AllyCreepsAll )
	do
		if creep ~= nil
			and creep:IsAlive()
			and GetUnitToLocationDistance( creep, vLoc ) <= nRadius
		then
			table.insert( allyCreepList, creep )
		end
	end

	return allyCreepList

end


function J.GetAllyUnitCountAroundEnemyTarget( bot, target, nRadius )

	local heroList = J.GetAlliesNearLoc( target:GetLocation(), nRadius )
	local creepList = J.GetAllyCreepNearLoc( bot, target:GetLocation(), nRadius )

	return #heroList + #creepList

end


function J.GetAroundBotUnitList( bot, nRadius, bEnemy )

	if nRadius > 1600 then nRadius = 1600 end

	local heroList = bot:GetNearbyHeroes( nRadius, bEnemy, BOT_MODE_NONE )
	local creepList = bot:GetNearbyCreeps( nRadius, bEnemy )
	local unitList = {}

	if #heroList > 0 and #creepList > 0
	then
		unitList = heroList
		for i = 1, #creepList
		do
			table.insert( unitList, creepList[1] )
		end
	elseif #heroList == 0
	then
		unitList = creepList
	elseif #creepList == 0
	then
		unitList = heroList
	end

	return unitList

end


function J.GetLocationToLocationDistance( fLoc, sLoc )

	local x1 = fLoc.x
	local x2 = sLoc.x
	local y1 = fLoc.y
	local y2 = sLoc.y

	return math.sqrt( math.pow( ( y2-y1 ), 2 ) + math.pow( ( x2-x1 ), 2 ) )

end


function J.GetUnitTowardDistanceLocation( bot, towardTarget, nDistance )

	local npcBotLocation = bot:GetLocation()
	local tempVector = ( towardTarget:GetLocation() - npcBotLocation ) / GetUnitToUnitDistance( bot, towardTarget )

	return npcBotLocation + nDistance * tempVector

end


function J.GetLocationTowardDistanceLocation( bot, towardLocation, nDistance )

	local npcBotLocation = bot:GetLocation()
	local tempVector = ( towardLocation - npcBotLocation ) / GetUnitToLocationDistance( bot, towardLocation )

	return npcBotLocation + nDistance * tempVector

end


function J.GetFaceTowardDistanceLocation( bot, nDistance )

	local npcBotLocation = bot:GetLocation()
	local tempRadians = bot:GetFacing() * math.pi / 180
	local tempVector = Vector( math.cos( tempRadians ), math.sin( tempRadians ) )

	return npcBotLocation + nDistance * tempVector

end


function J.SetBotPing( vLoc )

	GetBot():ActionImmediate_Ping( vLoc.x, vLoc.y, false )

end


function J.SetBotPrint( sMessage, vLoc, bReport, bPing )

	local bot = GetBot()

	local nTime = J.GetOne( DotaTime() / 10 )* 10
	local sTime = ( J.GetOne( nTime / 600 )* 10 )..":"..( nTime%60 )
	local sTeam = GetTeam() == TEAM_DIRE and "夜魇" or "天辉"

	if bDebugMode
	then

		print( sTeam..sTime.." "..J.Chat.GetNormName( bot ).." "..sMessage )

		if bReport then bot:ActionImmediate_Chat( sTime.."_"..sMessage, true ) end

		if bPing then bot:ActionImmediate_Ping( vLoc.x, vLoc.y, false ) end

	end

end


function J.SetReportMotive( bDebugFile, sMotive )

	if bDebugMode and bDebugFile and sMotive ~= nil
	then

		local nTime = J.GetOne( DotaTime() / 10 ) * 10
		local sTime = ( J.GetOne( nTime / 600 ) * 10 )..":"..( nTime%60 )
		local sTeam = GetTeam() == TEAM_DIRE and "夜魇 " or "天辉 "

		GetBot():ActionImmediate_Chat( sTime.."_"..sMotive, true )

		print( sTeam..sTime.." "..J.Chat.GetNormName( GetBot() ).." "..sMotive )

	end

end


function J.GetCastLocation( bot, npcTarget, nCastRange, nRadius )

	local nDistance = GetUnitToUnitDistance( bot, npcTarget )

	if nDistance <= nCastRange
	then
		return npcTarget:GetLocation()
	end

	if nDistance <= nCastRange + nRadius - 120
	then
		return J.GetUnitTowardDistanceLocation( bot, npcTarget, nCastRange )
	end

	if nDistance < nCastRange + nRadius - 18
		and ( ( J.IsDisabled( npcTarget ) or npcTarget:GetCurrentMovementSpeed() <= 160 )
				or npcTarget:IsFacingLocation( bot:GetLocation(), 45 )
				or ( bot:IsFacingLocation( npcTarget:GetLocation(), 45 ) and npcTarget:GetCurrentMovementSpeed() <= 220 ) )
	then
		return J.GetUnitTowardDistanceLocation( bot, npcTarget, nCastRange +18 )
	end

	if nDistance < nCastRange + nRadius + 28
		and npcTarget:IsFacingLocation( bot:GetLocation(), 30 )
		and bot:IsFacingLocation( npcTarget:GetLocation(), 30 )
		and npcTarget:GetMovementDirectionStability() > 0.95
		and npcTarget:GetCurrentMovementSpeed() >= 300
	then
		return J.GetUnitTowardDistanceLocation( bot, npcTarget, nCastRange + 18 )
	end

	return nil

end


function J.GetDelayCastLocation( bot, npcTarget, nCastRange, nRadius, nTime )

	local nFutureLoc = J.GetCorrectLoc( npcTarget, nTime )
	local nDistance = GetUnitToLocationDistance( bot, nFutureLoc )

	if nDistance > nCastRange + nRadius - 16
	then
		return nil
	end

	if nDistance > nCastRange - nRadius * 0.38
	then
		return J.GetLocationTowardDistanceLocation( bot, nFutureLoc, nCastRange +8 )
	end

	return nFutureLoc

end


function J.GetOne( number )

	return math.floor( number * 10 ) / 10

end


function J.GetTwo( number )

	return math.floor( number * 100 ) / 100

end


function J.SetQueueToInvisible( bot )

	if bot:IsAlive()
		and not bot:IsInvisible()
		and not bot:HasModifier( "modifier_item_dustofappearance" )
	then
		local enemyTowerList = bot:GetNearbyTowers( 888, true )

		if enemyTowerList[1] ~= nil then return end

		local itemAmulet = J.IsItemAvailable( 'item_shadow_amulet' )
		if itemAmulet ~= nil
			and itemAmulet:IsFullyCastable()
		then
			bot:ActionQueue_UseAbilityOnEntity( itemAmulet, bot )
			return
		end
	
		local itemGlimer = J.IsItemAvailable( 'item_glimmer_cape' )
		if itemGlimer ~= nil and itemGlimer:IsFullyCastable()
		then
			bot:ActionQueue_UseAbilityOnEntity( itemGlimer, bot )
			return
		end

		local itemInvisSword = J.IsItemAvailable( 'item_invis_sword' )
		if itemInvisSword ~= nil and itemInvisSword:IsFullyCastable()
		then
			bot:ActionQueue_UseAbility( itemInvisSword )
			return
		end

		local itemSilverEdge = J.IsItemAvailable( 'item_silver_edge' )
		if itemSilverEdge ~= nil and itemSilverEdge:IsFullyCastable()
		then
			bot:ActionQueue_UseAbility( itemSilverEdge )
			return
		end

	end


end


function J.SetQueueSwitchPtToINT( bot )

	local pt = J.IsItemAvailable( "item_power_treads" )
	if pt ~= nil and pt:IsFullyCastable()
	then
		if pt:GetPowerTreadsStat() == ATTRIBUTE_INTELLECT
		then
			bot:ActionQueue_UseAbility( pt )
			bot:ActionQueue_UseAbility( pt )
			return
		elseif pt:GetPowerTreadsStat() == ATTRIBUTE_STRENGTH
			then
				bot:ActionQueue_UseAbility( pt )
				return
		end
	end

end


function J.SetQueueUseSoulRing( bot )

	local sr = J.IsItemAvailable( "item_soul_ring" )

	if sr ~= nil and sr:IsFullyCastable()
	then
		local nEnemyCount = J.GetEnemyCount( bot, 1600 )
		local botHP = J.GetHP( bot )
		local botMP = J.GetMP( bot )
		if botHP > 0.35 + 0.1 * nEnemyCount
			and botMP < 0.99 - 0.1 * nEnemyCount
			and ( nEnemyCount <= 2 or botHP > botMP * 2.5 )
		then
			bot:ActionQueue_UseAbility( sr )
			return
		end
	end

end


function J.SetQueuePtToINT( bot, bSoulRingUsed )

	bot:Action_ClearActions( true )

	if bSoulRingUsed then J.SetQueueUseSoulRing( bot ) end

	if not J.IsPTReady( bot, ATTRIBUTE_INTELLECT )
	then
		J.SetQueueSwitchPtToINT( bot )
	end

end


function J.IsPTReady( bot, status )

	if not bot:IsAlive()
		or bot:IsMuted()
		or bot:IsChanneling()
		or bot:IsInvisible()
		or bot:GetHealth() / bot:GetMaxHealth() < 0.2
	then
		return true
	end

	if status == ATTRIBUTE_INTELLECT
	then
		status = ATTRIBUTE_AGILITY
	elseif status == ATTRIBUTE_AGILITY
		then
			status = ATTRIBUTE_INTELLECT
	end

	local pt = J.IsItemAvailable( "item_power_treads" )
	if pt ~= nil and pt:IsFullyCastable()
	then
		if pt:GetPowerTreadsStat() ~= status
		then
			return false
		end
	end

	return true

end


function J.ShouldSwitchPTStat( bot, pt )

	local ptStatus = pt:GetPowerTreadsStat()
	if ptStatus == ATTRIBUTE_INTELLECT
	then
		ptStatus = ATTRIBUTE_AGILITY
	elseif ptStatus == ATTRIBUTE_AGILITY
		then
			ptStatus = ATTRIBUTE_INTELLECT
	end

	return bot:GetPrimaryAttribute() ~= ptStatus

end


function J.IsOtherAllysTarget( unit )

	local bot = GetBot()
	local hAllyList = bot:GetNearbyHeroes( 800, false, BOT_MODE_NONE )

	if #hAllyList <= 1 then return false end

	for _, ally in pairs( hAllyList )
	do
		if J.IsValid( ally )
			and ally ~= bot
			and not ally:IsIllusion()
			and ( J.GetProperTarget( ally ) == unit
					or ( not ally:IsBot() and ally:IsFacingLocation( unit:GetLocation(), 20 ) ) )
		then
			return true
		end
	end

	return false

end


function J.IsAllysTarget( unit )

	local bot = GetBot()
	local hAllyList = bot:GetNearbyHeroes( 800, false, BOT_MODE_NONE )

	for _, ally in pairs( hAllyList )
	do
		if J.IsValid( ally )
			and not ally:IsIllusion()
			and ( J.GetProperTarget( ally ) == unit
					or ( not ally:IsBot() and ally:IsFacingLocation( unit:GetLocation(), 12 ) ) )
		then
			return true
		end
	end

	return false

end


function J.IsKeyWordUnit( keyWord, uUnit )

	if string.find( uUnit:GetUnitName(), keyWord ) ~= nil
	then
		return true
	end

	return false
end


function J.IsHumanPlayer( nUnit )

	return not nUnit:IsBot() --not IsPlayerBot( nUnit:GetPlayerID() )

end


function J.IsValid( nTarget )

	return nTarget ~= nil
			and not nTarget:IsNull()
			and nTarget:IsAlive()
			and not nTarget:IsBuilding()

end


function J.IsValidHero( nTarget )

	return nTarget ~= nil
			and not nTarget:IsNull()
			and nTarget:IsAlive()
			and nTarget:IsHero()
end


function J.IsValidBuilding( nTarget )

	return nTarget ~= nil
			and not nTarget:IsNull()
			and nTarget:IsAlive()
			and nTarget:IsBuilding()

end


function J.IsRoshan( nTarget )

	return nTarget ~= nil
			and not nTarget:IsNull()
			and nTarget:CanBeSeen()
			and nTarget:IsAlive()
			and string.find( nTarget:GetUnitName(), "roshan" ) ~= nil

end


function J.IsMoving( bot )

	if not bot:IsAlive() then return false end

	local vLocation = bot:GetExtrapolatedLocation( 0.6 )
	if GetUnitToLocationDistance( bot, vLocation ) > bot:GetCurrentMovementSpeed() * 0.45
	then
		return true
	end

	return false

end


function J.IsRunning( bot )

	if not bot:IsAlive() then return false end

	return bot:GetAnimActivity() == ACTIVITY_RUN

end


function J.IsAttacking( bot )

	local nAnimActivity = bot:GetAnimActivity()

	if nAnimActivity ~= ACTIVITY_ATTACK
		and nAnimActivity ~= ACTIVITY_ATTACK2
	then
		return false
	end

	if bot:GetAttackPoint() > bot:GetAnimCycle() * 0.99
	then
		return true
	end

	return false
end


function J.IsChasingTarget( bot, nTarget )

	if J.IsRunning( bot )
		and J.IsRunning( nTarget )
		and bot:IsFacingLocation( nTarget:GetLocation(), 20 )
		and not nTarget:IsFacingLocation( bot:GetLocation(), 150 )
	then
		return true
	end

	return false

end


function J.IsRealInvisible( bot )

	local enemyTowerList = bot:GetNearbyTowers( 880, true )

	if bot:IsInvisible()
		and not bot:HasModifier( 'modifier_item_dustofappearance' )
		and not bot:HasModifier( 'modifier_bloodseeker_thirst_vision' )
		and not bot:HasModifier( 'modifier_slardar_amplify_damage' )
		and not bot:HasModifier( 'modifier_sniper_assassinate' )
		and not bot:HasModifier( 'modifier_bounty_hunter_track' )
		and #enemyTowerList == 0
	then
		return true
	end


	return false

end

function J.ShouldDispelBuff( npcTarget )

	for _, modifier in pairs( J.Buff["dispellable_buffs"] )
	do
		if npcTarget:HasModifier( modifier )
		then
			return true
		end
	end

	return false

end


function J.ShouldDispelDebuff( npcTarget )

	if npcTarget:IsSilenced()
		or npcTarget:IsRooted()
		or npcTarget:IsNightmared()
	then
		return true
	end

	for _, modifier in pairs( J.Buff["dispellable_debuffs"] )
	do
		if npcTarget:HasModifier( modifier )
		then
			return true
		end
	end

	return false

end


function J.ShouldDispelStrongDebuff( npcTarget )

	if npcTarget:IsStunned()
		or npcTarget:IsHexed()
	then
		return true
	end

	return J.ShouldDispelDebuff( npcTarget )

end

function J.HasInvisibilityBuff( npcTarget )

	for _, modifier in pairs( J.Buff["invisible_buffs"] )
	do
		if npcTarget:HasModifier( modifier )
		then
			return true
		end
	end

	return false

end

function J.GetModifierTime( bot, sModifierName )

	if not bot:HasModifier( sModifierName ) then return 0 end

	local npcModifier = bot:NumModifiers()
	for i = 0, npcModifier
	do
		if bot:GetModifierName( i ) == sModifierName
		then
			return bot:GetModifierRemainingDuration( i )
		end
	end

	return 0

end


function J.GetModifierCount( bot, sModifierName )

	if not bot:HasModifier( sModifierName ) then return 0 end

	local npcModifier = bot:NumModifiers()
	for i = 0, npcModifier
	do
		if bot:GetModifierName( i ) == sModifierName
		then
			return bot:GetModifierStackCount( i )
		end
	end

	return 0

end




function J.GetRemainStunTime( bot )

	if not bot:HasModifier( "modifier_stunned" ) then return 0 end

	local npcModifier = bot:NumModifiers()
	for i = 0, npcModifier
	do
		if bot:GetModifierName( i ) == "modifier_stunned"
		then
			return bot:GetModifierRemainingDuration( i )
		end
	end

	return 0

end


function J.IsTeamActivityCount( bot, nCount )

	local numPlayer = GetTeamPlayers( GetTeam() )
	for i = 1, #numPlayer
	do
		local member = GetTeamMember( i )
		if member ~= nil and member:IsAlive()
		then
			if J.GetAllyCount( member, 1600 ) >= nCount
			then
				return true
			end
		end
	end

	return false

end


function J.GetSpecialModeAllies( bot, nDistance, nMode )

	local allyList = {}
	local numPlayer = GetTeamPlayers( GetTeam() )
	for i = 1, #numPlayer
	do
		local member = GetTeamMember( i )
		if member ~= nil and member:IsAlive()
		then
			if member:GetActiveMode() == nMode
				and GetUnitToUnitDistance( member, bot ) <= nDistance
			then
				table.insert( allyList, member )
			end
		end
	end

	return allyList

end


function J.GetSpecialModeAlliesCount( nMode )

	local allyList = J.GetSpecialModeAllies( GetBot(), 99999, nMode )

	return #allyList

end


function J.GetTeamFightLocation( bot )

	local targetLocation = nil
	local numPlayer = GetTeamPlayers( GetTeam() )

	for i = 1, #numPlayer
	do
		local member = GetTeamMember( i )
		if member ~= nil and member:IsAlive()
			and J.IsInTeamFight( member, 1500 )
			and J.GetEnemyCount( member, 1400 ) >= 2
		then
			local allyList = J.GetSpecialModeAllies( member, 1400, BOT_MODE_ATTACK )
			targetLocation = J.GetCenterOfUnits( allyList )
			break
		end
	end

	return targetLocation

end


function J.GetTeamFightAlliesCount( bot )

	local numPlayer = GetTeamPlayers( GetTeam() )
	local nCount = 0
	for i = 1, #numPlayer
	do
		local member = GetTeamMember( i )
		if member ~= nil and member:IsAlive()
			and J.IsInTeamFight( member, 1200 )
			and J.GetEnemyCount( member, 1400 ) >= 2
		then
			nCount = J.GetSpecialModeAlliesCount( BOT_MODE_ATTACK )
			break
		end
	end

	return nCount

end


function J.GetCenterOfUnits( nUnits )

	if #nUnits == 0
	then
		return Vector( 0.0, 0.0 )
	end

	local sum = Vector( 0.0, 0.0 )
	local num = 0

	for _, unit in pairs( nUnits )
	do
		if unit ~= nil
			and unit:IsAlive()
		then
			sum = sum + unit:GetLocation()
			num = num + 1
		end
	end

	if num == 0 then return Vector( 0.0, 0.0 ) end

	return sum / num

end


function J.GetMostFarmLaneDesire()

	local nTopDesire = GetFarmLaneDesire( LANE_TOP )
	local nMidDesire = GetFarmLaneDesire( LANE_MID )
	local nBotDesire = GetFarmLaneDesire( LANE_BOT )

	if nTopDesire > nMidDesire and nTopDesire > nBotDesire
	then
		return LANE_TOP, nTopDesire
	end

	if nBotDesire > nMidDesire and nBotDesire > nTopDesire
	then
		return LANE_BOT, nBotDesire
	end

	return LANE_MID, nMidDesire

end


function J.GetMostDefendLaneDesire()

	local nTopDesire = GetDefendLaneDesire( LANE_TOP )
	local nMidDesire = GetDefendLaneDesire( LANE_MID )
	local nBotDesire = GetDefendLaneDesire( LANE_BOT )

	if nTopDesire > nMidDesire and nTopDesire > nBotDesire
	then
		return LANE_TOP, nTopDesire
	end

	if nBotDesire > nMidDesire and nBotDesire > nTopDesire
	then
		return LANE_BOT, nBotDesire
	end

	return LANE_MID, nMidDesire

end


function J.GetMostPushLaneDesire()

	local nTopDesire = GetPushLaneDesire( LANE_TOP )
	local nMidDesire = GetPushLaneDesire( LANE_MID )
	local nBotDesire = GetPushLaneDesire( LANE_BOT )

	if nTopDesire > nMidDesire and nTopDesire > nBotDesire
	then
		return LANE_TOP, nTopDesire
	end

	if nBotDesire > nMidDesire and nBotDesire > nTopDesire
	then
		return LANE_BOT, nBotDesire
	end

	return LANE_MID, nMidDesire

end


function J.GetNearestLaneFrontLocation( nUnitLoc, bEnemy, fDeltaFromFront )

	local nTeam = GetTeam()
	if bEnemy then nTeam = GetOpposingTeam() end

	local nTopLoc = GetLaneFrontLocation( nTeam, LANE_TOP, fDeltaFromFront )
	local nMidLoc = GetLaneFrontLocation( nTeam, LANE_MID, fDeltaFromFront )
	local nBotLoc = GetLaneFrontLocation( nTeam, LANE_BOT, fDeltaFromFront )

	local nTopDist = J.GetLocationToLocationDistance( nUnitLoc, nTopLoc )
	local nMidDist = J.GetLocationToLocationDistance( nUnitLoc, nMidLoc )
	local nBotDist = J.GetLocationToLocationDistance( nUnitLoc, nBotLoc )

	if nTopDist < nMidDist and nTopDist < nBotDist
	then
		return nTopLoc
	end

	if nBotDist < nMidDist and nBotDist < nTopDist
	then
		return nBotLoc
	end

	return nMidLoc

end


function J.GetAttackableWeakestUnit( bot, nRadius, bHero, bEnemy )

	local unitList = {}
	local weakest = nil
	local weakestHP = 10000

	if bHero
	then
		unitList = bot:GetNearbyHeroes( nRadius, bEnemy, BOT_MODE_NONE )
	else
		unitList = bot:GetNearbyLaneCreeps( nRadius, bEnemy )
	end

	for _, unit in pairs( unitList )
	do
		if J.IsValid( unit )
			and unit:GetHealth() < weakestHP
			and not unit:IsAttackImmune()
			and not unit:IsInvulnerable()
			and not J.HasForbiddenModifier( unit )
			and not J.IsSuspiciousIllusion( unit )
			--and not J.IsAllyCanKill( unit )
		then
			weakest = unit
			weakestHP = unit:GetHealth()
		end
	end

	return weakest

end


function J.CanBeAttacked( npcTarget )

	return not npcTarget:IsAttackImmune()
			and not npcTarget:IsInvulnerable()
			and not J.HasForbiddenModifier( npcTarget )

end


function J.GetHP( bot )

	return bot:GetHealth() / bot:GetMaxHealth()

end


function J.GetMP( bot )

	return bot:GetMana() / bot:GetMaxMana()

end


function J.GetAllyList( bot, nRadius )

	if nRadius > 1600 then nRadius = 1600 end

	local nRealAllyList = {}
	local nCandidate = bot:GetNearbyHeroes( nRadius, false, BOT_MODE_NONE )
	if #nCandidate <= 1 then return nCandidate end

	for _, ally in pairs( nCandidate )
	do
		if ally ~= nil and ally:IsAlive()
			and not ally:IsIllusion()
		then
			table.insert( nRealAllyList, ally )
		end
	end

	return nRealAllyList

end


function J.GetAllyCount( bot, nRadius )

	local nRealAllyList = J.GetAllyList( bot, nRadius )

	return #nRealAllyList

end


function J.GetAroundEnemyHeroList( nRadius )

	if nRadius > 1600 then nRadius = 1600 end

	return GetBot():GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )

end


function J.GetAroundCreepList( nRadius, bEnemy, bNeutral, bLaneCreep )

	local bot = GetBot()
	if nRadius > 1600 then nRadius = 1600 end
	local creepList = {}

	if bNeutral
	then
		creepList = bot:GetNearbyNeutralCreeps( nRadius )
	elseif bLaneCreep
	then
		creepList = bot:GetNearbyLaneCreeps( nRadius, bEnemy )
	else
		creepList = bot:GetNearbyCreeps( nRadius, bEnemy )
	end

	return creepList

end


function J.GetAroundBuildingList( nRadius, bEnemy, bTower, bShrine, bFiller, bBarrack, bAcient )

	local bot = GetBot()
	if nRadius > 1600 then nRadius = 1600 end
	local buildingList = {}

	-- GetNearbyBarracks( nRadius, bEnemies )
	-- GetNearbyTowers( nRadius, bEnemies )
	-- GetNearbyShrines( nRadius, bEnemies )
	-- GetNearbyFillers( nRadius, bEnemies )
	-- GetAncient( nTeam )

	return buildingList

end


function J.GetEnemyList( bot, nRadius )

	if nRadius > 1600 then nRadius = 1600 end
	local nRealEnemyList = {}
	local nCandidate = bot:GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )
	if nCandidate[1] == nil then return nCandidate end

	for _, enemy in pairs( nCandidate )
	do
		if enemy ~= nil and enemy:IsAlive()
			and not J.IsSuspiciousIllusion( enemy )
		then
			table.insert( nRealEnemyList, enemy )
		end
	end

	return nRealEnemyList

end


function J.GetEnemyCount( bot, nRadius )

	local nRealEnemyList = J.GetEnemyList( bot, nRadius )

	return #nRealEnemyList

end


function J.ConsiderTarget()

	local bot = GetBot()

	if not J.IsRunning( bot )
		or bot:HasModifier( "modifier_item_hurricane_pike_range" )
	then return end

	local npcTarget = J.GetProperTarget( bot )
	if not J.IsValidHero( npcTarget ) then return end

	local nAttackRange = bot:GetAttackRange() + 69
	if nAttackRange > 1600 then nAttackRange = 1600 end
	if nAttackRange < 300 then nAttackRange = 350 end

	local nInAttackRangeWeakestEnemyHero = J.GetAttackableWeakestUnit( bot, nAttackRange, true, true )

	if J.IsValidHero( nInAttackRangeWeakestEnemyHero )
		and ( GetUnitToUnitDistance( npcTarget, bot ) > nAttackRange or J.HasForbiddenModifier( npcTarget ) )
	then
		bot:SetTarget( nInAttackRangeWeakestEnemyHero )
		return
	end

end


function J.IsHaveAegis( bot )

	return bot:FindItemSlot( "item_aegis" ) >= 0

end


function J.IsLocHaveTower( nRadius, bEnemy, nLoc )

	local nTeam = GetTeam()
	if bEnemy then nTeam = GetOpposingTeam() end

	if ( not bEnemy and J.GetLocationToLocationDistance( nLoc, J.GetTeamFountain() ) < 2500 )
		or ( bEnemy and J.GetLocationToLocationDistance( nLoc, J.GetEnemyFountain() ) < 2500 )
	then
		return true
	end

	for i = 0, 10
	do
		local tower = GetTower( nTeam, i )
		if tower ~= nil and GetUnitToLocationDistance( tower, nLoc ) <= nRadius
		then
			 return true
		end
	end

	return false

end


function J.GetNearbyLocationToTp( nLoc )

	local nTeam = GetTeam()
	local nFountain = J.GetTeamFountain()

	if J.GetLocationToLocationDistance( nLoc, nFountain ) <= 2500
	then
		return nLoc
	end

	local targetTower = nil
	local minDist = 99999
	for i=0, 10, 1 do
		local tower = GetTower( nTeam, i )
		if tower ~= nil
			and GetUnitToLocationDistance( tower, nLoc ) < minDist
		then
			 targetTower = tower
			 minDist = GetUnitToLocationDistance( tower, nLoc )
		end
	end

	local watchTowerList = J.Site.GetAllWatchTower()
	for _, watchTower in pairs( watchTowerList )
	do
		if watchTower ~= nil
			and watchTower:GetTeam() == nTeam
			and GetUnitToLocationDistance( watchTower, nLoc ) < minDist - 1300
			and ( not J.IsEnemyHeroAroundLocation( watchTower:GetLocation(), 600 )
					or J.IsAllyHeroAroundLocation( watchTower:GetLocation(), 600 ) )
		then
			 targetTower = watchTower
			 minDist = GetUnitToLocationDistance( watchTower, nLoc ) + 1300
		end
	end

	if targetTower ~= nil
	then
		return J.GetLocationTowardDistanceLocation( targetTower, nLoc, 575 )
	end

	return nFountain

end


function J.IsEnemyFacingUnit( bot, nRadius, nDegrees )

	local nLoc = bot:GetLocation()

	if nRadius > 1600 then nRadius = 1600 end
	local nEnemyHeroes = bot:GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )
	for _, enemy in pairs( nEnemyHeroes )
	do
		if J.IsValid( enemy )
			and enemy:IsFacingLocation( nLoc, nDegrees )
		then
			return true
		end
	end

	return false

end


function J.IsAllyFacingUnit( bot, nRadius, nDegrees )

	local nLoc = bot:GetLocation()
	local numPlayer = GetTeamPlayers( GetTeam() )
	for i = 1, #numPlayer
	do
		local member = GetTeamMember( i )
		if member ~= nil
			and member ~= bot
			and GetUnitToUnitDistance( member, bot ) <= nRadius
			and member:IsFacingLocation( nLoc, nDegrees )
		then
			return true
		end
	end

	return false

end


function J.IsEnemyTargetUnit( nUnit, nRadius )

	if nRadius > 1600 then nRadius = 1600 end
	local nEnemyHeroes = GetBot():GetNearbyHeroes( nRadius, true, BOT_MODE_NONE )
	for _, enemy in pairs( nEnemyHeroes )
	do
		if J.IsValid( enemy )
			and J.GetProperTarget( enemy ) == nUnit
		then
			return true
		end
	end

	return false

end


function J.IsCastingUltimateAbility( bot )

	if bot:IsCastingAbility() or bot:IsUsingAbility()
	then
		local nAbility = bot:GetCurrentActiveAbility()
		if nAbility ~= nil
			and nAbility:IsUltimate()
		then
			return true
		end
	end

	return false

end


function J.IsInAllyArea( bot )

	local hAllyAcient = GetAncient( GetTeam() )
	local hEnemyAcient = GetAncient( GetOpposingTeam() )
	
	if GetUnitToUnitDistance( bot, hAllyAcient ) + 768 < GetUnitToUnitDistance( bot, hEnemyAcient )
	then
		return true
	end
	
	return false

end


function J.IsInEnemyArea( bot )

	local hAllyAcient = GetAncient( GetTeam() )
	local hEnemyAcient = GetAncient( GetOpposingTeam() )
	
	if GetUnitToUnitDistance( bot, hEnemyAcient ) + 1280 < GetUnitToUnitDistance( bot, hAllyAcient )
	then
		return true
	end
	
	return false

end


function J.IsAllyHeroAroundLocation( vLoc, nRadius )

	for i = 1, 5
	do
		local npcAlly = GetTeamMember( i )
		if npcAlly ~= nil
			and npcAlly:IsAlive()
			and GetUnitToLocationDistance( npcAlly, vLoc ) <= nRadius
		then
			return true
		end
	end

	return false

end


function J.IsEnemyHeroAroundLocation( vLoc, nRadius )

	for i, id in pairs( GetTeamPlayers( GetOpposingTeam() ) )
	do
		if IsHeroAlive( id ) then
			local info = GetHeroLastSeenInfo( id )
			if info ~= nil then
				local dInfo = info[1]
				if dInfo ~= nil
					and J.GetLocationToLocationDistance( vLoc, dInfo.location ) <= nRadius
					and dInfo.time_since_seen < 2.0
				then
					return true
				end
			end
		end
	end

	return false

end


function J.GetNumOfAliveHeroes( bEnemy )

	local count = 0
	local nTeam = GetTeam()
	if bEnemy then nTeam = GetOpposingTeam() end

	for i, id in pairs( GetTeamPlayers( nTeam ) )
	do
		if IsHeroAlive( id )
		then
			count = count + 1
		end
	end

	return count

end


function J.GetAverageLevel( bEnemy )

	local count = 0
	local sum = 0
	local nTeam = GetTeam()
	if bEnemy then nTeam = GetOpposingTeam() end

	for i, id in pairs( GetTeamPlayers( nTeam ) )
	do
		sum = sum + GetHeroLevel( id )
		count = count + 1
	end

	return sum / count

end


function J.GetNumOfTeamTotalKills( bEnemy )

	local count = 0
	local nTeam = GetOpposingTeam()
	if bEnemy then nTeam = GetTeam() end

	for i, id in pairs( GetTeamPlayers( nTeam ) )
	do
		count = count + GetHeroDeaths( id )
	end

	return count

end


function J.ConsiderForMkbDisassembleMask( bot )

	if bot.maskDismantleDone == nil then bot.maskDismantleDone = false end
	if bot.staffUnlockDone == nil then bot.staffUnlockDone = false end
	if bot.lifestealUnlockDone == nil then bot.lifestealUnlockDone = false end
	if bot.dismantleCheckTime == nil then bot.dismantleCheckTime = 600 end

	if bot.staffUnlockDone then return end

	if bot.dismantleCheckTime < DotaTime() + 1.0
	then
		bot.dismantleCheckTime = DotaTime()

		local mask	 = bot:FindItemSlot( "item_mask_of_madness" )
		local claymore = bot:FindItemSlot( "item_claymore" )
		local reaver	= bot:FindItemSlot( "item_reaver" )

		if not bot.maskDismantleDone
			and ( bot:GetItemInSlot( 6 ) == nil or bot:GetItemInSlot( 7 ) == nil or bot:GetItemInSlot( 8 ) == nil )
		then

			if mask >= 0 and mask <= 8
				and ( ( reaver >= 0 and reaver <= 8 ) or ( claymore >= 0 and claymore <= 8 ) )
				and ( bot:GetGold() >= 1400 or bot:GetStashValue() >= 1400 or bot:GetCourierValue() >= 1400 )
			then
				if bDebugMode then print( bot:GetUnitName().." mask Dismantle1" ) end
				bot.maskDismantleDone = true
				bot:ActionImmediate_DisassembleItem( bot:GetItemInSlot( mask ) )
				return
			end

			if mask >= 0 and mask <= 8
				and claymore >= 0 and reaver >= 0
			then
				if bDebugMode then print( bot:GetUnitName().." mask Dismantle2" ) end
				bot.maskDismantleDone = true
				bot:ActionImmediate_DisassembleItem( bot:GetItemInSlot( mask ) )
				return
			end
		end

		if not bot.maskDismantleDone then return end

		local lifesteal = bot:FindItemSlot( "item_lifesteal" )
		local staff = bot:FindItemSlot( "item_quarterstaff" )

		if lifesteal >= 0
			and not bot.lifestealUnlockDone
		then
			if bDebugMode then print( bot:GetUnitName().." lifestealUnlockDone" ) end
			bot.lifestealUnlockDone = true
			bot:ActionImmediate_SetItemCombineLock( bot:GetItemInSlot( lifesteal ), false )
			return
		end

		local satanic = bot:FindItemSlot( "item_satanic" )

		if satanic >= 0 and staff >= 0 and not bot.staffUnlockDone
		then
			if bDebugMode then print( bot:GetUnitName().." staffUnlockDone" ) end
			bot.staffUnlockDone = true
			bot:ActionImmediate_SetItemCombineLock( bot:GetItemInSlot( staff ), false )
			return
		end

	end
end


local LastActionTime = {}
function J.HasNotActionLast( nCD, nNumber )

	if LastActionTime[nNumber] == nil then LastActionTime[nNumber] = -90 end

	if DotaTime() > LastActionTime[nNumber] + nCD
	then
		LastActionTime[nNumber] = DotaTime()
		return true
	end

	return false

end


function J.GetCastDelay( bot, unit, nPointTime, nProjectSpeed )

	local nDist = GetUnitToUnitDistance( bot, unit )

	local nDistTime = 0
	if nProjectSpeed ~= 0 then nDistTime = nDist / nProjectSpeed end

	return nPointTime + nDistTime

end


function J.CanBreakTeleport( bot, unit, nPointTime, nProjectSpeed )

	if unit:HasModifier( "modifier_teleporting" )
	then
		return J.GetCastPoint( bot, unit, nPointTime, nProjectSpeed ) < J.GetModifierTime( unit, "modifier_teleporting" )
	end

	return true

end


function J.GetMagicToPhysicalDamage( bot, nUnit, nMagicDamage )

	local realMagicDamage = nUnit:GetActualIncomingDamage( nMagicDamage, DAMAGE_TYPE_MAGICAL )

	local basePhysicalDamage = 100 * bot:GetAttackCombatProficiency( nUnit )
	local nTDamage = nUnit:GetActualIncomingDamage( basePhysicalDamage, DAMAGE_TYPE_PHYSICAL ) / 100

	return realMagicDamage / nTDamage

end

function J.FilterGroup(nList,func)
	local newGroup={}
	for _, npc in pairs( nList ) do
		if func(npc) then
			table.insert(newGroup,npc)
		end
	end
	return newGroup
end

function J.MergeGroup(nList,...)
	local args = {...}
	for a in arg do
		table.insert(nList,a)
	end
	return nList
end

function J.Not(f)
	return function(...)
		return not f(...)
	end
end

function J.And(...)
	local funcList={...}
	return function(...)
		for _,func in pairs(funcList) do
			if not func(...) then
				return false
			end
		end
		return true
	end
end

function J.Or(...)
	local funcList={...}
	return function(...)
		for _,func in pairs(funcList) do
			if func(...) then
				return true
			end
		end
		return false
	end
end

function J.GetAngle(x1,y1,x2,y2)
	if math.atan2 then
		return math.deg(math.atan2( y2 - y1, x2 - x1 ))
	else
		return math.deg(math.atan( y2 - y1, x2 - x1 ))
	end
end

function J.GetDistanceFromXYToXY(x1, y1, x2, y2)
	return math.sqrt(( x1 - x2 )*( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ))
end

function J.GetAngleFromVectorToXY(v, x, y)
    return J.GetAngle(v.x, v.y, x, y)
end

function J.GetAngleFromXYToVector(x, y, v)
    return J.GetAngle(x, y, v.x, v.y)
end

function J.GetAngleFromVectorToVector(v1, v2)
    return J.GetAngle(v1.x, v1.y, v2.x, v2.y)
end

function J.GetDistanceFromVectorToXY(v, x, y)
    return J.GetDistanceFromXYToXY(v.x, v.y, x, y)
end

function J.GetDistanceFromXYToVector(x, y, v)
    return J.GetDistanceFromXYToXY(x, y, v.x, v.y)
end

function J.GetDistanceFromVectorToVector(v1, v2)
    return J.GetDistanceFromXYToXY(v1.x, v1.y, v2.x, v2.y)
end

function J.GetAngleFromUnitToXY(unit, x, y)
	return J.GetAngleFromVectorToXY(unit:GetLocation(), x, y)
end

function J.GetAngleFromUnitToVector(unit, v)
	return J.GetAngleFromVectorToVector(unit:GetLocation(), v)
end

function J.GetAngleFromVectorToUnit(v, unit)
	return J.GetAngleFromVectorToVector(v, unit:GetLocation())
end

function J.GetAngleFromUnitToUnit(unit1, unit2)
	return J.GetAngleFromVectorToVector(unit1:GetLocation(), unit2:GetLocation())
end

function J.GetDistanceFromUnitToXY(unit, x, y)
    return J.GetDistanceFromVectorToXY(unit:GetLocation(), x, y)
end

function J.GetDistanceFromUnitToUnit(unit1, unit2)
    return J.GetDistanceFromVectorToVector(unit1:GetLocation(), unit2:GetLocation())
end

function J.GetDistanceFromUnitToVector(unit, vector)
    return J.GetDistanceFromVectorToVector(unit:GetLocation(), vector)
end

function J.GetUnitFacingAngle(unit)
    return J.GetAngleFromVectorToVector(RandomVector(0.0), unit:GetForwardVector())
end

function J.GetVectorFromVectorRotation(v, center, rotate)
    local angle = J.GetAngleFromVectorToVector(center, v)
    angle = angle + rotate
    local r = J.GetDistanceFromVectorToVector(center, v)
    return J.GetVectorFromVectorToAngleWithDistance(center, angle, r, nil)
end

function J.GetAngleBetweenTwoAngles(angleA, angleB)
    --返回角A与角B之间的夹角
    local a = math.rad(angleA)
    local b = math.rad(angleB)
    local r = math.abs( a - b )

    if r > math.pi then
        r = math.pi * 2 - r
    end

    return math.deg(r)
end

function J.GetDistanceFromPointToLine(x, y, x1, y1, x2, y2)
    --过(x1,y1) (x2,y2)两点作直线，返回(x,y)到这条直线的距离
    if x1 == x2 then
        return math.abs( y - y1 )
    elseif y1 == y2 then
        return math.abs( x - x1 )
    end
    return J.GetDistanceFromXYToXY( ( y + ( x2 - x1 ) / ( y2 - y1 ) * x + ( y2 - y1 ) / ( x2 - x1 ) * x2 - y2 ) / ( ( y2 - y1 ) / ( x2 - x1 ) + ( x2 - x1 ) / ( y2 - y1 ) ), ( y2 - y1 ) / ( x2 - x1 ) * ( ( y + ( x2 - x1 ) / ( y2 - y1 ) * x + ( y2 - y1 ) / ( x2 - x1 ) * x2 - y2 ) / ( ( y2 - y1 ) / ( x2 - x1 ) + ( x2 - x1 ) / ( y2 - y1 ) ) ) + y2 - ( y2 - y1 ) / ( x2 - x1 ) * x2, x, y )
end

function J.IsVectorInRectangle(p, p1, a, d, r)
    local x = p.x
    local y = p.y
    local x1 = p1.x
    local y1 = p1.y
    --从(x1,y1)起向a方向作一条直线。若(x,y)到这条直线的直线距离小于d，且到(x1,y1)的距离小于r，则返回真
    return J.GetDistanceFromPointToLine( x, y, x1, y1, x1 + math.cos( math.rad(a) ) * r, y1 + math.sin( math.rad(a) ) * r ) < d and J.GetDistance( x, y, x1, y1 ) < r and J.GetAngleBetweenTwoAngles( J.GetAngle( x1, y1, x, y ), a ) < 90
end

function J.IsXYInRectangle(x, y, x1, y1, a, d, r)
    --从(x1,y1)起向a方向作一条直线。若(x,y)到这条直线的直线距离小于d，且到(x1,y1)的距离小于r，则返回真
    return J.GetDistanceFromPointToLine( x, y, x1, y1, x1 + math.cos( math.rad(a) ) * r, y1 + math.sin( math.rad(a) ) * r ) < d and J.GetDistance( x, y, x1, y1 ) < r and J.GetAngleBetweenTwoAngles( J.GetAngle( x1, y1, x, y ), a ) < 90
end

function J.GetVectorFromVectorToAngleWithDistance(v, a, d)
    --从vector v开始，向a方向d距离的位置。
    a = math.rad(a)
    local newV = RandomVector(0.0)
    newV.x = v.x + math.cos(a) * d
    newV.y = v.y + math.sin(a) * d
    return newV
end

function J.VectorToAngle(v)
    return J.GetAngleFromVectorToVector(RandomVector(0.0), v)
end
function J.Cos(angle)
    return math.cos(math.rad(angle))
end
function J.Sin(angle)
    return math.sin(math.rad(angle))
end
function J.CosSin(angle)
    return J.Cos(angle),J.Sin(angle)
end
function J.AngleToVector(angle)
	local v=RandomVector(0.0)
	v.x, v.y=J.CosSin(angle)
    return v
end

function J.GetRandomPointInCircle(center, max, min)
    min = min or 0
    if max <= 1 then max = 1 end
    if max < min then min, max = max, min end
    local distribute = 1 / (max * max - min * min)
    local r = math.sqrt(RandomFloat(0,1.0) / distribute + min * min)
    local angle = RandomFloat(0,360)
    return J.GetVectorFromVectorToAngleWithDistance(center, angle, r)
end

function J.DebugMessage(str,b)
	if b then
		GetBot():ActionImmediate_Chat( str, true )
	end
end

function J.FindAoeLocationForLinearSkillFilter(u)
	return not u:IsMagicImmune() and not u:IsInvulnerable() and not u:IsHidden()
end

function J.FindAoeLocationForLinearSkill(data)
	local range = data.range or 600
	local radius = data.range or 200
	local castPoint = data.castPoint or 0.5
	local projSpeed = data.projSpeed or 1000
	local onlyHero = data.onlyHero==nil or data.onlyHero
	local bot = GetBot()
	local loc=data.loc or bot:GetLocation()
	local enemies = bot:GetNearbyHeroes( range, true, BOT_MODE_NONE )
	local creeps = bot:GetNearbyLaneCreeps( range + radius, true )
	local filter = data.filter or J.FindAoeLocationForLinearSkillFilter
	local least = data.least or 2

	enemies = J.FilterGroup(enemies, function(u)
		return J.IsValidHero(u)
	end)

	creeps = J.FilterGroup(creeps, function(u)
		return J.IsValid(u)
	end)
	if not onlyHero then
		enemies = J.MergeGroup(enemies, creeps)
	end

    local most=least
	local nAoeLoc
	local mostUnstablity = 99999999
	for i=1,36 do
        local angle = 10 * i
		local unstablity = 0
        local hitEnemy = J.FilterGroup(enemies,J.And(filter, function(u)
			local distance = J.GetDistanceFromUnitToUnit(bot, u)
			local uLoc = J.GetCorrectLoc(u,distance / projSpeed + castPoint)
			if J.IsVectorInRectangle(uLoc,loc,angle,radius,range) then
				unstablity = unstablity + J.GetDistanceFromPointToLine( uLoc.x, uLoc.y, loc.x, loc.y, loc.x + math.cos( math.rad(angle) ) * range, loc.y + math.sin( math.rad(angle) ) * range )
			end
		end))
        if #hitEnemy>=most and unstablity < mostUnstablity then
            most=#hitEnemy
            nAoeLoc=J.GetVectorFromVectorToAngleWithDistance(loc, angle, range / 2)
        end
    end

	return nAoeLoc
end

function J.GetVal(ability, name)
	local f=ability:GetSpecialValueFloat(name)
	if math.abs(f)<0.0001 then
		f=ability:GetSpecialValueInt(name)
	end
	return f
end

function J.WontDie(unit)
	if not unit:CanBeSeen() then return false end
	for _,buff in J.Buff['enemy_is_undead'] do
		if unit:HasModifier(buff) then
			return true
		end
	end
	return false
end

return J

--[[

[[
CanAbilityBeUpgraded(): bool
CanBeDisassembled(): bool
GetAOERadius(): int
GetAbilityDamage(): int
GetAutoCastState(): bool
GetBehavior(): int
GetCastPoint(): float
GetCastRange(): int
GetCaster(): handle
GetChannelTime(): float
GetChannelledManaCostPerSecond(): int
GetCooldown(): float
GetCooldownTimeRemaining(): float
GetCurrentCharges(): int
GetDamageType(): int
GetDuration(): float
GetEstimatedDamageToTarget( handlehTarget, floatfDuration, intnDamageTypes ): int
GetHeroLevelRequiredToUpgrade(): int
GetInitialCharges(): int
GetLevel(): int
GetManaCost(): int
GetMaxLevel(): int
GetName(): cstring
GetPowerTreadsStat(): int
GetSecondaryCharges(): int
GetSpecialValueFloat( cstringpszKey ): float
GetSpecialValueInt( cstringpszKey ): int
GetTargetFlags(): int
GetTargetTeam(): int
GetTargetType(): int
GetToggleState(): bool
IsActivated(): bool
IsChanneling(): bool
IsCombineLocked(): bool
IsCooldownReady(): bool
IsFullyCastable(): bool
IsHidden(): bool
IsInAbilityPhase(): bool
IsItem(): bool
IsOwnersManaEnough(): bool
IsPassive(): bool
IsStealable(): bool
IsStolen(): bool
IsTalent(): bool
IsToggle(): bool
IsTrained(): bool
IsUltimate(): bool
ProcsMagicStick(): bool
ToggleAutoCast(): void
ActionImmediate_Buyback(): void
ActionImmediate_Chat( cstringpszMessage, boolbAllChat ): void
ActionImmediate_Courier( handlehCourier, inteAction ): bool
ActionImmediate_DisassembleItem( handlehItem ): void
ActionImmediate_Glyph(): void
ActionImmediate_LevelAbility( cstringpszAbilityName ): void
ActionImmediate_Ping( floatx, floaty, boolbNormalPing ): void
ActionImmediate_PurchaseItem( cstringpszItemName ):
ActionImmediate_SellItem( handlehItem ): void
ActionImmediate_SetItemCombineLock( handlehItem, boolbLocked ): void
ActionImmediate_SwapItems( intnSlot1, intnSlot2 ): void
ActionPush_AttackMove( vectorlocation ): void
ActionPush_AttackUnit( handlehTarget, boolbOnce ): void
ActionPush_Delay( floatfDelay ): void
ActionPush_DropItem( handlehItem, vectorlocation ): void
ActionPush_MoveDirectly( vectorlocation ): void
ActionPush_MovePath( handlehPathTable ): void
ActionPush_MoveToLocation( vectorlocation ): void
ActionPush_MoveToUnit( handlehTarget ): void
ActionPush_PickUpItem( handlehItem ): void
ActionPush_PickUpRune( intnRune ): void
ActionPush_UseAbility( handlehAbility ): void
ActionPush_UseAbilityOnEntity( handlehAbility, handlehTarget ): void
ActionPush_UseAbilityOnLocation( handlehAbility, vectorlocation ): void
ActionPush_UseAbilityOnTree( handlehAbility, intiTree ): void
ActionPush_UseShrine( handlehShrine ): void
ActionQueue_AttackMove( vectorlocation ): void
ActionQueue_AttackUnit( handlehTarget, boolbOnce ): void
ActionQueue_Delay( floatfDelay ): void
ActionQueue_DropItem( handlehItem, vectorlocation ): void
ActionQueue_MoveDirectly( vectorlocation ): void
ActionQueue_MovePath( handlehPathTable ): void
ActionQueue_MoveToLocation( vectorlocation ): void
ActionQueue_MoveToUnit( handlehTarget ): void
ActionQueue_PickUpItem( handlehItem ): void
ActionQueue_PickUpRune( intnRune ): void
ActionQueue_UseAbility( handlehAbility ): void
ActionQueue_UseAbilityOnEntity( handlehAbility, handlehTarget ): void
ActionQueue_UseAbilityOnLocation( handlehAbility, vectorlocation ): void
ActionQueue_UseAbilityOnTree( handlehAbility, intiTree ): void
ActionQueue_UseShrine( handlehShrine ): void
Action_AttackMove( vectorlocation ): void
Action_AttackUnit( handlehTarget, boolbOnce ): void
Action_ClearActions( boolbStop ): void
Action_Delay( floatfDelay ): void
Action_DropItem( handlehItem, vectorlocation ): void
Action_MoveDirectly( vectorlocation ): void
Action_MovePath( handlehPathTable ): void
Action_MoveToLocation( vectorlocation ): void
Action_MoveToUnit( handlehTarget ): void
Action_PickUpItem( handlehItem ): void
Action_PickUpRune( intnRune ): void
Action_UseAbility( handlehAbility ): void
Action_UseAbilityOnEntity( handlehAbility, handlehTarget ): void
Action_UseAbilityOnLocation( handlehAbility, vectorlocation ): void
Action_UseAbilityOnTree( handlehAbility, intiTree ): void
Action_UseShrine( handlehShrine ): void
CanBeSeen(): bool
DistanceFromFountain(): int
DistanceFromSecretShop(): int
DistanceFromSideShop(): int
FindAoELocation( boolbEnemies, boolbHeroes, vectorvBaseLocation, intnMaxDistanceFromBase, intnRadius, floatfTimeInFuture, intnMaxHealth ): variant
FindItemSlot( cstringpszItemName ): int
GetAbilityByName( cstringpszAbilityName ): handle
GetAbilityInSlot( intiAbility ): handle
GetAbilityPoints(): int
GetAbilityTarget(): handle
GetAcquisitionRange(): int
GetActiveMode(): int
GetActiveModeDesire(): float
GetActualIncomingDamage( intnDamage, inteDamageType ): int
GetAnimActivity(): int
GetAnimCycle(): float
GetArmor(): float
GetAssignedLane(): int
GetAttackCombatProficiency( handlehTarget ): float
GetAttackDamage(): float
GetAttackPoint(): float
GetAttackProjectileSpeed(): int
GetAttackRange(): int
GetAttackSpeed(): float
GetAttackTarget(): handle
GetAttributeValue( intnAttribute ): int
GetBaseDamage(): float
GetBaseDamageVariance(): float
GetBaseHealthRegen(): float
GetBaseManaRegen(): float
GetBaseMovementSpeed(): int
GetBoundingRadius(): float
GetBountyGoldMax(): int
GetBountyGoldMin(): int
GetBountyXP(): int
GetBuybackCooldown(): float
GetBuybackCost(): int
GetCourierValue(): int
GetCurrentActionType(): int
GetCurrentActiveAbility(): handle
GetCurrentMovementSpeed(): int
GetCurrentVisionRange(): int
GetDayTimeVisionRange(): int
GetDefendCombatProficiency( handlehAttacker ): float
GetDenies(): int
GetDifficulty(): int
GetEstimatedDamageToTarget( boolbCurrentlyAvailable, handlehTarget, floatfDuration, intnDamageTypes ): int
GetEvasion(): float
GetExtrapolatedLocation( floatfDelay ): vector
GetFacing(): int
GetGold(): int
GetGroundHeight(): int
GetHealth(): int
GetHealthRegen(): float
GetHealthRegenPerStr(): float
GetIncomingTrackingProjectiles(): variant
GetItemInSlot( intnSlot ): handle
GetItemSlotType( intnSlot ): int
GetLastAttackTime(): float
GetLastHits(): int
GetLevel(): int
GetLocation(): vector
GetMagicResist(): float
GetMana(): int
GetManaRegen(): float
GetManaRegenPerInt(): float
GetMaxHealth(): int
GetMaxMana(): int
GetModifierAuxiliaryUnits( intnModifier ): variant
GetModifierByName( cstringpszModifierName ): int
GetModifierList(): variant
GetModifierName( intnModifier ): cstring
GetModifierRemainingDuration( intnModifier ): float
GetModifierStackCount( intnModifier ): int
GetMostRecentPing(): variant
GetMovementDirectionStability(): float
GetNearbyBarracks( intnRadius, boolbEnemies ): variant
GetNearbyCreeps( intnRadius, boolbEnemies ): variant
GetNearbyFillers( intnRadius, boolbEnemies ): variant
GetNearbyHeroes( intnRadius, boolbEnemies, inteBotMode ): variant
GetNearbyLaneCreeps( intnRadius, boolbEnemies ): variant
GetNearbyNeutralCreeps( intnRadius ): variant
GetNearbyShrines( intnRadius, boolbEnemies ): variant
GetNearbyTowers( intnRadius, boolbEnemies ): variant
GetNearbyTrees( intnRadius ): variant
GetNetWorth(): int
GetNextItemPurchaseValue(): int
GetNightTimeVisionRange(): int
GetOffensivePower(): float
GetPlayerID(): int
GetPrimaryAttribute(): int
GetQueuedActionType( intnQueuedAction ): int
GetRawOffensivePower(): float
GetRemainingLifespan(): float
GetRespawnTime(): float
GetSecondsPerAttack(): float
GetSlowDuration( boolbCurrentlyAvailable ): float
GetSpellAmp(): float
GetStashValue(): int
GetStunDuration( boolbCurrentlyAvailable ): float
GetTalent( intnLevel, intnSide ): handle
GetTarget(): handle
GetTeam(): int
GetUnitName(): cstring
GetVelocity(): vector
GetXPNeededToLevel(): int
HasBlink( boolbCurrentlyAvailable ): bool
HasBuyback(): bool
HasInvisibility( boolbCurrentlyAvailable ): bool
HasMinistunOnAttack(): bool
HasModifier( cstringpszModifierName ): bool
HasScepter(): bool
HasSilence( boolbCurrentlyAvailable ): bool
IsAlive(): bool
IsAncientCreep(): bool
IsAttackImmune(): bool
IsBlind(): bool
IsBlockDisabled(): bool
IsBot(): bool
IsBuilding(): bool
IsCastingAbility(): bool
IsChanneling(): bool
IsCourier(): bool
IsCreep(): bool
IsDisarmed(): bool
IsDominated(): bool
IsEvadeDisabled(): bool
IsFacingLocation( vectorvLocation, intnDegrees ): bool
IsFort(): bool
IsHero(): bool
IsHexed(): bool
IsIllusion(): bool
IsInvisible(): bool
IsInvulnerable(): bool
IsMagicImmune(): bool
IsMinion(): bool
IsMuted(): bool
IsNightmared(): bool
IsRooted(): bool
IsSilenced(): bool
IsSpeciallyDeniable(): bool
IsStunned(): bool
IsTower(): bool
IsUnableToMiss(): bool
IsUsingAbility(): bool
NumModifiers(): int
NumQueuedActions(): int
SetNextItemPurchaseValue( intnGold ): void
SetTarget( handle ): void
TimeSinceDamagedByAnyHero(): float
TimeSinceDamagedByCreep(): float
TimeSinceDamagedByHero( handlehHero ): float
TimeSinceDamagedByPlayer( intnPlayerID ): float
TimeSinceDamagedByTower(): float
UsingItemBreaksInvisibility(): bool
WasRecentlyDamagedByAnyHero( floatfTime ): bool
WasRecentlyDamagedByCreep( floatfTime ): bool
WasRecentlyDamagedByHero( handlehHero, floatfTime ): bool
WasRecentlyDamagedByPlayer( intnPlayerID, floatfTime ): bool
WasRecentlyDamagedByTower( floatfTime ): bool
CDOTA_TeamCommander
AddAvoidanceZone( vector, float ): int
AddConditionalAvoidanceZone( vector, handle ): int
CMBanHero( cstring ): void
CMPickHero( cstring ): void
Clamp( float, float, float ): float
CreateHTTPRequest( cstring ): handle
CreateRemoteHTTPRequest( cstring ): handle
DebugDrawCircle( vector, float, int, int, int ): void
DebugDrawLine( vector, vector, int, int, int ): void
DebugDrawText( float, float, cstring, int, int, int ): void
DebugPause(): void
DotaTime(): float
GameTime(): float
GeneratePath( vector, vector, handle, handle ): int
GetAllTrees(): variant
GetAmountAlongLane( int, vector ): variant
GetAncient( int ): handle
GetAvoidanceZones(): variant
GetBarracks( int, int ): handle
GetBot(): handle
GetBotAbilityByHandle( uint ): handle
GetBotByHandle( uint ): handle
GetCMCaptain(): int
GetCMPhaseTimeRemaining(): float
GetCourier( int ): handle
GetCourierState( handle ): int
GetDefendLaneDesire( int ): float
GetDroppedItemList(): variant
GetFarmLaneDesire( int ): float
GetGameMode(): int
GetGameState(): int
GetGameStateTimeRemaining(): float
GetGlyphCooldown(): float
GetHeightLevel( vector ): int
GetHeroAssists( int ): int
GetHeroDeaths( int ): int
GetHeroKills( int ): int
GetHeroLastSeenInfo( int ): variant
GetHeroLevel( int ): int
GetHeroPickState(): int
GetIncomingTeleports(): variant
GetItemComponents( cstring ): variant
GetItemCost( cstring ): int
GetItemStockCount( cstring ): int
GetLaneFrontAmount( int, int, bool ): float
GetLaneFrontLocation( int, int, float ): vector
GetLinearProjectileByHandle( int ): variant
GetLinearProjectiles(): variant
GetLocationAlongLane( int, float ): vector
GetNeutralSpawners(): variant
GetNumCouriers(): int
GetOpposingTeam(): int
GetPushLaneDesire( int ): float
GetRoamDesire(): float
GetRoamTarget(): handle
GetRoshanDesire(): float
GetRoshanKillTime(): float
GetRuneSpawnLocation( int ): vector
GetRuneStatus( int ):
GetRuneTimeSinceSeen( int ): float
GetRuneType( int ): int
GetScriptDirectory(): cstring
GetSelectedHeroName( int ): cstring
GetShopLocation( int, int ): vector
GetShrine( int, int ): handle
GetShrineCooldown( handle ): float
GetTeam(): int
GetTeamForPlayer( int ): int
GetTeamMember( int ): handle
GetTeamPlayers( int ): variant
GetTimeOfDay(): float
GetTower( int, int ): handle
GetTowerAttackTarget( int, int ): handle
GetTreeLocation( int ): vector
GetUnitList( int ): variant
GetUnitPotentialValue( handle, vector, float ): int
GetUnitToLocationDistance( handle, vector ): float
GetUnitToLocationDistanceSqr( handle, vector ): float
GetUnitToUnitDistance( handle, handle ): float
GetUnitToUnitDistanceSqr( handle, handle ): float
GetWorldBounds(): variant
InstallCastCallback( int, handle ): void
InstallChatCallback( handle ): void
InstallCourierDeathCallback( handle ): void
InstallDamageCallback( int, handle ): void
InstallRoshanDeathCallback( handle ): void
IsCMBannedHero( cstring ): bool
IsCMPickedHero( int, cstring ): bool
IsCourierAvailable(): bool
IsFlyingCourier( handle ): bool
IsHeroAlive( int ): bool
IsInCMBanPhase(): bool
IsInCMPickPhase(): bool
IsItemPurchasedFromSecretShop( cstring ): bool
IsItemPurchasedFromSideShop( cstring ): bool
IsLocationPassable( vector ): bool
IsLocationVisible( vector ): bool
IsPlayerBot( int ): bool
IsPlayerInHeroSelectionControl( int ): bool
IsRadiusVisible( vector, float ): bool
IsShrineHealing( handle ): bool
IsTeamPlayer( int ): bool
Max( float, float ): float
Min( float, float ): float
PointToLineDistance( vector, vector, vector ): variant
RandomFloat( float, float ): float
RandomInt( int, int ): int
RandomVector( float ): vector
RealTime(): float
RemapVal( float, float, float, float, float ): float
RemapValClamped( float, float, float, float, float ): float
RemoveAvoidanceZone( int ): void
RollPercentage( int ): bool
SelectHero( int, cstring ): void
SetCMCaptain( int ): void
]]


--[[
BOT_MODE_NONE
BOT_MODE_LANING
BOT_MODE_ATTACK
BOT_MODE_ROAM
BOT_MODE_RETREAT
BOT_MODE_RUNE
BOT_MODE_SECRET_SHOP
BOT_MODE_SIDE_SHOP
BOT_MODE_PUSH_TOWER_TOP
BOT_MODE_PUSH_TOWER_MID
BOT_MODE_PUSH_TOWER_BOT
BOT_MODE_DEFEND_TOWER_TOP
BOT_MODE_DEFEND_TOWER_MID
BOT_MODE_DEFEND_TOWER_BOT
BOT_MODE_ASSEMBLE
BOT_MODE_TEAM_ROAM
BOT_MODE_FARM
BOT_MODE_DEFEND_ALLY
BOT_MODE_EVASIVE_MANEUVERS
BOT_MODE_ROSHAN
BOT_MODE_ITEM
BOT_MODE_WARD
BOT_ACTION_DESIRE_NONE - 0.0
BOT_ACTION_DESIRE_VERYLOW - 0.1
BOT_ACTION_DESIRE_LOW - 0.25
BOT_ACTION_DESIRE_MODERATE - 0.5
BOT_ACTION_DESIRE_HIGH - 0.75
BOT_ACTION_DESIRE_VERYHIGH - 0.9
BOT_ACTION_DESIRE_ABSOLUTE - 1.0
BOT_MODE_DESIRE_NONE - 0
BOT_MODE_DESIRE_VERYLOW - 0.1
BOT_MODE_DESIRE_LOW - 0.25
BOT_MODE_DESIRE_MODERATE - 0.5
BOT_MODE_DESIRE_HIGH - 0.75
BOT_MODE_DESIRE_VERYHIGH - 0.9
BOT_MODE_DESIRE_ABSOLUTE - 1.0
DAMAGE_TYPE_PHYSICAL
DAMAGE_TYPE_MAGICAL
DAMAGE_TYPE_PURE
DAMAGE_TYPE_ALL
UNIT_LIST_ALL
UNIT_LIST_ALLIES
UNIT_LIST_ALLIED_HEROES
UNIT_LIST_ALLIED_CREEPS
UNIT_LIST_ALLIED_WARDS
UNIT_LIST_ALLIED_BUILDINGS
UNIT_LIST_ENEMIES
UNIT_LIST_ENEMY_HEROES
UNIT_LIST_ENEMY_CREEPS
UNIT_LIST_ENEMY_WARDS
UNIT_LIST_NEUTRAL_CREEPS
UNIT_LIST_ENEMY_BUILDINGS
DIFFICULTY_INVALID
DIFFICULTY_PASSIVE
DIFFICULTY_EASY
DIFFICULTY_MEDIUM
DIFFICULTY_HARD
DIFFICULTY_UNFAIR
ATTRIBUTE_INVALID
ATTRIBUTE_STRENGTH
ATTRIBUTE_AGILITY
ATTRIBUTE_INTELLECT
PURCHASE_ITEM_SUCCESS
PURCHASE_ITEM_OUT_OF_STOCK
PURCHASE_ITEM_DISALLOWED_ITEM
PURCHASE_ITEM_INSUFFICIENT_GOLD
PURCHASE_ITEM_NOT_AT_HOME_SHOP
PURCHASE_ITEM_NOT_AT_SIDE_SHOP
PURCHASE_ITEM_NOT_AT_SECRET_SHOP
PURCHASE_ITEM_INVALID_ITEM_NAME
GAMEMODE_NONE
GAMEMODE_AP
GAMEMODE_CM
GAMEMODE_RD
GAMEMODE_SD
GAMEMODE_AR
GAMEMODE_REVERSE_CM
GAMEMODE_MO
GAMEMODE_CD
GAMEMODE_ABILITY_DRAFT
GAMEMODE_ARDM
GAMEMODE_1V1MID
GAMEMODE_ALL_DRAFT
TEAM_RADIANT
TEAM_DIRE
TEAM_NEUTRAL
TEAM_NONE
LANE_NONE
LANE_TOP
LANE_MID
LANE_BOT
GAME_STATE_INIT
GAME_STATE_WAIT_FOR_PLAYERS_TO_LOAD
GAME_STATE_HERO_SELECTION
GAME_STATE_STRATEGY_TIME
GAME_STATE_PRE_GAME
GAME_STATE_GAME_IN_PROGRESS
GAME_STATE_POST_GAME
GAME_STATE_DISCONNECT
GAME_STATE_TEAM_SHOWCASE
GAME_STATE_CUSTOM_GAME_SETUP
GAME_STATE_WAIT_FOR_MAP_TO_LOAD
GAME_STATE_LAST
HEROPICK_STATE_NONE
HEROPICK_STATE_AP_SELECT
HEROPICK_STATE_SD_SELECT
HEROPICK_STATE_CM_INTRO
HEROPICK_STATE_CM_CAPTAINPICK
HEROPICK_STATE_CM_BAN1
HEROPICK_STATE_CM_BAN2
HEROPICK_STATE_CM_BAN3
HEROPICK_STATE_CM_BAN4
HEROPICK_STATE_CM_BAN5
HEROPICK_STATE_CM_BAN6
HEROPICK_STATE_CM_BAN7
HEROPICK_STATE_CM_BAN8
HEROPICK_STATE_CM_BAN9
HEROPICK_STATE_CM_BAN10
HEROPICK_STATE_CM_SELECT1
HEROPICK_STATE_CM_SELECT2
HEROPICK_STATE_CM_SELECT3
HEROPICK_STATE_CM_SELECT4
HEROPICK_STATE_CM_SELECT5
HEROPICK_STATE_CM_SELECT6
HEROPICK_STATE_CM_SELECT7
HEROPICK_STATE_CM_SELECT8
HEROPICK_STATE_CM_SELECT9
HEROPICK_STATE_CM_SELECT10
HEROPICK_STATE_CM_PICK
HEROPICK_STATE_AR_SELECT
HEROPICK_STATE_MO_SELECT
HEROPICK_STATE_FH_SELECT
HEROPICK_STATE_CD_INTRO
HEROPICK_STATE_CD_CAPTAINPICK
HEROPICK_STATE_CD_BAN1
HEROPICK_STATE_CD_BAN2
HEROPICK_STATE_CD_BAN3
HEROPICK_STATE_CD_BAN4
HEROPICK_STATE_CD_BAN5
HEROPICK_STATE_CD_BAN6
HEROPICK_STATE_CD_SELECT1
HEROPICK_STATE_CD_SELECT2
HEROPICK_STATE_CD_SELECT3
HEROPICK_STATE_CD_SELECT4
HEROPICK_STATE_CD_SELECT5
HEROPICK_STATE_CD_SELECT6
HEROPICK_STATE_CD_SELECT7
HEROPICK_STATE_CD_SELECT8
HEROPICK_STATE_CD_SELECT9
HEROPICK_STATE_CD_SELECT10
HEROPICK_STATE_CD_PICK
HEROPICK_STATE_BD_SELECT
HERO_PICK_STATE_ABILITY_DRAFT_SELECT
HERO_PICK_STATE_ARDM_SELECT
HEROPICK_STATE_ALL_DRAFT_SELECT
HERO_PICK_STATE_CUSTOMGAME_SELECT
HEROPICK_STATE_SELECT_PENALTY
RUNE_INVALID ( used as return value )
RUNE_DOUBLEDAMAGE
RUNE_HASTE
RUNE_ILLUSION
RUNE_INVISIBILITY
RUNE_REGENERATION
RUNE_BOUNTY
RUNE_ARCANE
RUNE_STATUS_UNKNOWN
RUNE_STATUS_AVAILABLE
RUNE_STATUS_MISSING
RUNE_POWERUP_1
RUNE_POWERUP_2
RUNE_BOUNTY_1
RUNE_BOUNTY_2
RUNE_BOUNTY_3
RUNE_BOUNTY_4
ITEM_SLOT_TYPE_INVALID
ITEM_SLOT_TYPE_MAIN
ITEM_SLOT_TYPE_BACKPACK
ITEM_SLOT_TYPE_STASH
BOT_ACTION_TYPE_NONE
BOT_ACTION_TYPE_IDLE
BOT_ACTION_TYPE_MOVE_TO
BOT_ACTION_TYPE_MOVE_TO_DIRECTLY
BOT_ACTION_TYPE_ATTACK
BOT_ACTION_TYPE_ATTACKMOVE
BOT_ACTION_TYPE_USE_ABILITY
BOT_ACTION_TYPE_PICK_UP_RUNE
BOT_ACTION_TYPE_PICK_UP_ITEM
BOT_ACTION_TYPE_DROP_ITEM
BOT_ACTION_TYPE_SHRINE
BOT_ACTION_TYPE_DELAY
COURIER_ACTION_BURST
COURIER_ACTION_ENEMY_SECRET_SHOP
COURIER_ACTION_RETURN
COURIER_ACTION_SECRET_SHOP
COURIER_ACTION_SIDE_SHOP
COURIER_ACTION_SIDE_SHOP2
COURIER_ACTION_TAKE_STASH_ITEMS
COURIER_ACTION_TAKE_AND_TRANSFER_ITEMS
COURIER_ACTION_TRANSFER_ITEMS
COURIER_STATE_IDLE - 0
COURIER_STATE_AT_BASE - 1
COURIER_STATE_MOVING - 2
COURIER_STATE_DELIVERING_ITEMS - 3
COURIER_STATE_RETURNING_TO_BASE - 4
COURIER_STATE_DEAD
TOWER_TOP_1
TOWER_TOP_2
TOWER_TOP_3
TOWER_MID_1
TOWER_MID_2
TOWER_MID_3
TOWER_BOT_1
TOWER_BOT_2
TOWER_BOT_3
TOWER_BASE_1
TOWER_BASE_2
BARRACKS_TOP_MELEE
BARRACKS_TOP_RANGED
BARRACKS_MID_MELEE
BARRACKS_MID_RANGED
BARRACKS_BOT_MELEE
BARRACKS_BOT_RANGED
SHRINE_JUNGLE_1
SHRINE_JUNGLE_2
SHOP_HOME
SHOP_SIDE
SHOP_SECRET
SHOP_SIDE2
SHOP_SECRET2
ABILITY_TARGET_TEAM_NONE
ABILITY_TARGET_TEAM_FRIENDLY
ABILITY_TARGET_TEAM_ENEMY
ABILITY_TARGET_TYPE_NONE
ABILITY_TARGET_TYPE_HERO
ABILITY_TARGET_TYPE_CREEP
ABILITY_TARGET_TYPE_BUILDING
ABILITY_TARGET_TYPE_COURIER
ABILITY_TARGET_TYPE_OTHER
ABILITY_TARGET_TYPE_TREE
ABILITY_TARGET_TYPE_BASIC
ABILITY_TARGET_TYPE_ALL
ABILITY_TARGET_FLAG_NONE
ABILITY_TARGET_FLAG_RANGED_ONLY
ABILITY_TARGET_FLAG_MELEE_ONLY
ABILITY_TARGET_FLAG_DEAD
ABILITY_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES
ABILITY_TARGET_FLAG_NOT_MAGIC_IMMUNE_ALLIES
ABILITY_TARGET_FLAG_INVULNERABLE
ABILITY_TARGET_FLAG_FOW_VISIBLE
ABILITY_TARGET_FLAG_NO_INVIS
ABILITY_TARGET_FLAG_NOT_ANCIENTS
ABILITY_TARGET_FLAG_PLAYER_CONTROLLED
ABILITY_TARGET_FLAG_NOT_DOMINATED
ABILITY_TARGET_FLAG_NOT_SUMMONED
ABILITY_TARGET_FLAG_NOT_ILLUSIONS
ABILITY_TARGET_FLAG_NOT_ATTACK_IMMUNE
ABILITY_TARGET_FLAG_MANA_ONLY
ABILITY_TARGET_FLAG_CHECK_DISABLE_HELP
ABILITY_TARGET_FLAG_NOT_CREEP_HERO
ABILITY_TARGET_FLAG_OUT_OF_WORLD
ABILITY_TARGET_FLAG_NOT_NIGHTMARED
ABILITY_TARGET_FLAG_PREFER_ENEMIES
ABILITY_BEHAVIOR_NONE
ABILITY_BEHAVIOR_HIDDEN
ABILITY_BEHAVIOR_PASSIVE
ABILITY_BEHAVIOR_NO_TARGET
ABILITY_BEHAVIOR_UNIT_TARGET
ABILITY_BEHAVIOR_POINT
ABILITY_BEHAVIOR_AOE
ABILITY_BEHAVIOR_NOT_LEARNABLE
ABILITY_BEHAVIOR_CHANNELLED
ABILITY_BEHAVIOR_ITEM
ABILITY_BEHAVIOR_TOGGLE
ABILITY_BEHAVIOR_DIRECTIONAL
ABILITY_BEHAVIOR_IMMEDIATE
ABILITY_BEHAVIOR_AUTOCAST
ABILITY_BEHAVIOR_OPTIONAL_UNIT_TARGET
ABILITY_BEHAVIOR_OPTIONAL_POINT
ABILITY_BEHAVIOR_OPTIONAL_NO_TARGET
ABILITY_BEHAVIOR_AURA
ABILITY_BEHAVIOR_ATTACK
ABILITY_BEHAVIOR_DONT_RESUME_MOVEMENT
ABILITY_BEHAVIOR_ROOT_DISABLES
ABILITY_BEHAVIOR_UNRESTRICTED
ABILITY_BEHAVIOR_IGNORE_PSEUDO_QUEUE
ABILITY_BEHAVIOR_IGNORE_CHANNEL
ABILITY_BEHAVIOR_DONT_CANCEL_MOVEMENT
ABILITY_BEHAVIOR_DONT_ALERT_TARGET
ABILITY_BEHAVIOR_DONT_RESUME_ATTACK
ABILITY_BEHAVIOR_NORMAL_WHEN_STOLEN
ABILITY_BEHAVIOR_IGNORE_BACKSWING
ABILITY_BEHAVIOR_RUNE_TARGET
ABILITY_BEHAVIOR_DONT_CANCEL_CHANNEL
ABILITY_BEHAVIOR_VECTOR_TARGETING
ABILITY_BEHAVIOR_LAST_RESORT_POINT
GLYPH_COOLDOWN
ACTIVITY_IDLE - 1500
ACTIVITY_IDLE_RARE - 1501
ACTIVITY_RUN - 1502
ACTIVITY_ATTACK - 1503
ACTIVITY_ATTACK2 - 1504
ACTIVITY_ATTACK_EVENT - 1505
ACTIVITY_DIE - 1506
ACTIVITY_FLINCH - 1507
ACTIVITY_FLAIL - 1508
ACTIVITY_DISABLED - 1509
ACTIVITY_CAST_ABILITY_1 - 1510
ACTIVITY_CAST_ABILITY_2 - 1511
ACTIVITY_CAST_ABILITY_3 - 1512
ACTIVITY_CAST_ABILITY_4 - 1513
ACTIVITY_CAST_ABILITY_5 - 1514
ACTIVITY_CAST_ABILITY_6 - 1515
ACTIVITY_OVERRIDE_ABILITY_1 - 1516
ACTIVITY_OVERRIDE_ABILITY_2 - 1517
ACTIVITY_OVERRIDE_ABILITY_3 - 1518
ACTIVITY_OVERRIDE_ABILITY_4 - 1519
ACTIVITY_CHANNEL_ABILITY_1 - 1520
ACTIVITY_CHANNEL_ABILITY_2 - 1521
ACTIVITY_CHANNEL_ABILITY_3 - 1522
ACTIVITY_CHANNEL_ABILITY_4 - 1523
ACTIVITY_CHANNEL_ABILITY_5 - 1524
ACTIVITY_CHANNEL_ABILITY_6 - 1525
ACTIVITY_CHANNEL_END_ABILITY_1 - 1526
ACTIVITY_CHANNEL_END_ABILITY_2 - 1527
ACTIVITY_CHANNEL_END_ABILITY_3 - 1528
ACTIVITY_CHANNEL_END_ABILITY_4 - 1529
ACTIVITY_CHANNEL_END_ABILITY_5 - 1530
ACTIVITY_CHANNEL_END_ABILITY_6 - 1531
ACTIVITY_CONSTANT_LAYER - 1532
ACTIVITY_CAPTURE - 1533
ACTIVITY_SPAWN - 1534
ACTIVITY_KILLTAUNT - 1535
ACTIVITY_TAUNT - 1536
--]]


--[[
J.SetUserHeroInit( nAbilityBuildList, nTalentBuildList, sBuyList, sSellList )
J.PrintInitMessage( sFlag, sMessage )
J.IsDebugHero( bot )
J.CanNotUseAbility( bot )
J.GetVulnerableWeakestUnit( bot, bHero, bEnemy, nRadius )
J.GetUnitAllyCountAroundEnemyTarget( target, nRadius )
J.GetAroundTargetEnemyUnitCount( target, nRadius )
J.GetAroundTargetEnemyHeroCount( target, nRadius )
J.GetNearbyAroundLocationUnitCount( bEnemy, bHero, nRadius, vLoc )
J.GetAttackEnemysAllyCreepCount( target, nRadius )
J.GetVulnerableUnitNearLoc( bot, bHero, bEnemy, nCastRange, nRadius, vLoc )
J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, nCount )
J.IsWithoutTarget( bot )
J.GetProperTarget( bot )
J.IsAllyCanKill( target )
J.IsOtherAllyCanKillTarget( bot, target )
J.GetAlliesNearLoc( vLoc, nRadius )
J.IsAllyHeroBetweenAllyAndEnemy( hAlly, hEnemy, vLoc, nRadius )
J.IsSandKingThere( bot, nCastRange, fTime )
J.GetUltimateAbility( bot )
J.CanUseRefresherShard( bot )
J.GetMostUltimateCDUnit()
J.GetPickUltimateScepterUnit()
J.CanUseRefresherOrb( bot )
J.IsSuspiciousIllusion( npcTarget )
J.CanCastAbilityOnTarget( npcTarget, bIgnoreMagicImmune )
J.CanCastOnMagicImmune( npcTarget )
J.CanCastOnNonMagicImmune( npcTarget )
J.CanCastOnTargetAdvanced( npcTarget )
J.CanCastUnitSpellOnTarget( npcTarget, nDelay )
J.CanKillTarget( npcTarget, dmg, dmgType )
J.WillKillTarget( npcTarget, dmg, dmgType, dTime )
J.WillMixedDamageKillTarget( npcTarget, nPhysicalDamge, nMagicalDamage, nPureDamage, nDelay )
J.WillMagicKillTarget( bot, npcTarget, dmg, nDelay )
J.HasForbiddenModifier( npcTarget )
J.ShouldEscape( bot )
J.IsDisabled( npcTarget )
J.IsTaunted( npcTarget )
J.IsInRange( bot, npcTarget, nCastRange )
J.IsInLocRange( npcTarget, nLoc, nCastRange )
J.IsInTeamFight( bot, range )
J.IsRetreating( bot )
J.IsGoingOnSomeone( bot )
J.IsDoingRoshan( bot )
J.IsDefending( bot )
J.IsPushing( bot )
J.IsLaning( bot )
J.IsFarming( bot )
J.IsShopping( bot )
J.GetTeamFountain()
J.GetEnemyFountain()
J.GetComboItem( bot, sItemName )
J.HasItem( bot, sItemName )
J.IsItemAvailable( sItemName )
J.GetMostHpUnit( unitList )
J.GetLeastHpUnit( unitList )
J.IsAllowedToSpam( bot, nManaCost )
J.IsAllyUnitSpell( sAbilityName )
J.IsProjectileUnitSpell( sAbilityName )
J.IsOnlyProjectileSpell( sAbilityName )
J.IsStunProjectileSpell( sAbilityName )
J.IsWillBeCastUnitTargetSpell( bot, nRadius )
J.IsWillBeCastPointSpell( bot, nRadius )
J.IsProjectileIncoming( bot, range )
J.IsUnitTargetProjectileIncoming( bot, range )
J.IsStunProjectileIncoming( bot, range )
J.IsAttackProjectileIncoming( bot, range )
J.IsNotAttackProjectileIncoming( bot, range )
J.GetAttackProDelayTime( bot, nCreep )
J.GetCreepAttackActivityWillRealDamage( nUnit, nTime )
J.GetCreepAttackProjectileWillRealDamage( nUnit, nTime )
J.GetTotalAttackWillRealDamage( nUnit, nTime )
J.GetAttackProjectileDamageByRange( nUnit, nRadius )
J.GetCorrectLoc( target, delay )
J.GetEscapeLoc()
J.IsStuck2( bot )
J.IsStuck( bot )
J.IsExistInTable( u, tUnit )
J.CombineTwoTable( tableA, tableB )
J.GetInvUnitInLocCount( bot, nRadius, nFindRadius, vLocation, pierceImmune )
J.GetInLocLaneCreepCount( bot, nRadius, nFindRadius, vLocation )
J.GetInvUnitCount( pierceImmune, unitList )
J.GetDistanceFromEnemyFountain( bot )
J.GetDistanceFromAllyFountain( bot )
J.GetDistanceFromAncient( bot, bEnemy )
J.GetAroundTargetAllyHeroCount( target, nRadius )
J.GetAroundTargetOtherAllyHeroCount( bot, target, nRadius )
J.GetAllyCreepNearLoc( bot, vLoc, nRadius )
J.GetAllyUnitCountAroundEnemyTarget( bot, target, nRadius )
J.GetAroundBotUnitList( bot, nRadius, bEnemy )
J.GetLocationToLocationDistance( fLoc, sLoc )
J.GetUnitTowardDistanceLocation( bot, towardTarget, nDistance )
J.GetLocationTowardDistanceLocation( bot, towardLocation, nDistance )
J.GetFaceTowardDistanceLocation( bot, nDistance )
J.SetBotPing( vLoc )
J.SetBotPrint( sMessage, vLoc, bReport, bPing )
J.SetReportMotive( bDebugFile, sMotive )
J.GetCastLocation( bot, npcTarget, nCastRange, nRadius )
J.GetDelayCastLocation( bot, npcTarget, nCastRange, nRadius, nTime )
J.GetOne( number )
J.GetTwo( number )
J.SetQueueToInvisible( bot )
J.SetQueueSwitchPtToINT( bot )
J.SetQueueUseSoulRing( bot )
J.SetQueuePtToINT( bot, bSoulRingUsed )
J.IsPTReady( bot, status )
J.ShouldSwitchPTStat( bot, pt )
J.IsOtherAllysTarget( unit )
J.IsAllysTarget( unit )
J.IsKeyWordUnit( keyWord, Unit )
J.IsHumanPlayer( nUnit )
J.IsValid( nTarget )
J.IsValidHero( nTarget )
J.IsValidBuilding( nTarget )
J.IsRoshan( nTarget )
J.IsMoving( bot )
J.IsRunning( bot )
J.IsAttacking( bot )
J.IsChasingTarget( bot, nTarget )
J.IsRealInvisible( bot )
J.GetModifierTime( bot, sModifierName )
J.GetModifierCount( bot, sModifierName )
J.GetRemainStunTime( bot )
J.IsTeamActivityCount( bot, nCount )
J.GetSpecialModeAllies( bot, nDistance, nMode )
J.GetSpecialModeAlliesCount( nMode )
J.GetTeamFightLocation( bot )
J.GetTeamFightAlliesCount( bot )
J.GetCenterOfUnits( nUnits )
J.GetMostFarmLaneDesire()
J.GetMostDefendLaneDesire()
J.GetMostPushLaneDesire()
J.GetNearestLaneFrontLocation( nUnitLoc, bEnemy, fDeltaFromFront )
J.GetAttackableWeakestUnit( bot, nRadius, bHero, bEnemy )
J.CanBeAttacked( npcTarget )
J.GetHP( bot )
J.GetMP( bot )
J.GetAllyList( bot, nRadius )
J.GetAllyCount( bot, nRadius )
J.GetEnemyList( bot, nRadius )
J.GetEnemyCount( bot, nRadius )
J.GetAroundEnemyHeroList( nRadius )
J.GetAroundCreepList( nRadius, bNeutral, bLaneCreep, bEnemy )
J.ConsiderTarget()
J.IsHaveAegis( bot )
J.IsLocHaveTower( nRadius, bEnemy, nLoc )
J.GetNearbyLocationToTp( nLoc )
J.IsEnemyFacingUnit( bot, nRadius, nDegrees )
J.IsAllyFacingUnit( bot, nRadius, nDegrees )
J.IsEnemyTargetUnit( nUnit, nRadius )
J.IsCastingUltimateAbility( bot )
J.IsInAllyArea( bot )
J.IsInEnemyArea( bot )
J.IsEnemyHeroAroundLocation( vLoc, nRadius )
J.GetNumOfAliveHeroes( bEnemy )
J.GetAverageLevel( bEnemy )
J.GetNumOfTeamTotalKills( bEnemy )
J.ConsiderForMkbDisassembleMask( bot )
J.HasNotActionLast( nCD, nNumber )
J.GetCastDelay( bot, unit, nPointTime, nProjectSpeed )
J.CanBreakTeleport( bot, unit, nPointTime, nProjectSpeed )
J.GetMagicToPhysicalDamage( bot, nUnit, nMagicDamage )
--]]


--]]
-- dota2jmz@163.com QQ:2462331592..