Commit 7b32f085 authored by JoyJ's avatar JoyJ

more updates from jodyjmaulana/aba-update

parent ddbb5b8a
----------------------------------------------------------------------------------------------------
--- The Creation Come From: BOT EXPERIMENT Credit:FURIOUSPUPPY
--- BOT EXPERIMENT Author: Arizona Fauzie 2018.11.21
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=837040016
--- Refactor: 决明子 Email: dota2jmz@163.com 微博@Dota2_决明子
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1573671599
--- Link:http://steamcommunity.com/sharedfiles/filedetails/?id=1627071163
--- Updated: Nikel
--- mid, mage, priest
----------------------------------------------------------------------------------------------------
local X = {}
local bDebugMode = ( 10 == 10 )
local bot = GetBot()
local J = require( GetScriptDirectory()..'/FunLib/jmz_func' )
local A = dofile( GetScriptDirectory()..'/FunLib/aba_ability' )
local Minion = dofile( GetScriptDirectory()..'/FunLib/aba_minion' )
local sTalentList = J.Skill.GetTalentList( bot )
local sAbilityList = J.Skill.GetAbilityList( bot )
local sOutfitType = J.Item.GetOutfitType( bot )
local tTalentTreeList = {
['outfit_carry'] = {
['t25'] = {10, 0},
['t20'] = {0, 10},
['t15'] = {0, 10},
['t10'] = {0, 10},
},
['outfit_mid'] = {
['t25'] = {10, 0},
['t20'] = {0, 10},
['t15'] = {0, 10},
['t10'] = {0, 10},
},
['outfit_priest'] = {
['t25'] = {0, 10},
['t20'] = {10, 0},
['t15'] = {10, 0},
['t10'] = {10, 0},
},
['outfit_mage'] = {
['t25'] = {0, 10},
['t20'] = {10, 0},
['t15'] = {10, 0},
['t10'] = {10, 0},
},
['outfit_tank'] = {
['t25'] = {0, 10},
['t20'] = {10, 0},
['t15'] = {10, 0},
['t10'] = {10, 0},
},
}
local tAllAbilityBuildList = {
['outfit_carry'] = {
{1,2,1,2,1,6,2,3,1,2,6,3,3,3,6}
},
['outfit_mid'] = {
{1,2,1,2,1,6,2,3,1,2,6,3,3,3,6}
},
['outfit_priest'] = {
{1,3,1,3,2,6,3,3,1,1,6,2,2,2,6}
},
['outfit_mage'] = {
{1,3,1,3,2,6,3,1,3,1,6,2,2,2,6}
},
['outfit_tank'] = {
{1,3,1,3,2,6,3,1,3,1,6,2,2,2,6}
},
}
local nAbilityBuildList = J.Skill.GetRandomBuild( tAllAbilityBuildList[sOutfitType] )
local nTalentBuildList = J.Skill.GetTalentBuild( tTalentTreeList[sOutfitType] )
local sRandomItem = RandomInt( 1, 9 ) > 6 and 0 or 10
local sRandomItem_1 = sRandomItem == 0 and "item_aether_lens" or "item_orchid"
local sRandomItem_2 = sRandomItem == 0 and "item_octarine_core" or "item_bloodthorn"
local tOutFitList = {}
tOutFitList['outfit_carry'] = {
"item_mid_skywrath_mage_outfit",
"item_dagon",
sRandomItem_1,
"item_dagon_2",
"item_aghanims_shard",
"item_ultimate_scepter",
"item_dagon_3",
"item_sheepstick",
"item_dagon_4",
"item_blink",
"item_dagon_5",
"item_travel_boots",
sRandomItem_2,
"item_ultimate_scepter_2",
"item_kaya",
"item_ethereal_blade",
"item_travel_boots_2",
"item_moon_shard",
}
tOutFitList['outfit_mid'] = tOutFitList['outfit_carry']
tOutFitList['outfit_priest'] = {
"item_priest_2_outfit",
"item_aether_lens",
"item_glimmer_cape",
"item_force_staff",
"item_ultimate_scepter",
"item_aghanims_shard",
"item_aeon_disk",
"item_guardian_greaves",
"item_octarine_core",
"item_hurricane_pike",
"item_ultimate_scepter_2",
"item_sheepstick",
"item_moon_shard",
}
tOutFitList['outfit_mage'] = {
"item_mage_grimstroke_outfit",
"item_aether_lens",
"item_ancient_janggo",
"item_force_staff",
"item_ultimate_scepter",
"item_aghanims_shard",
"item_boots_of_bearing",
"item_aeon_disk",
"item_sheepstick",
"item_octarine_core",
"item_hurricane_pike",
"item_ultimate_scepter_2",
"item_cyclone",
"item_wind_waker",
"item_moon_shard",
}
tOutFitList['outfit_tank'] = tOutFitList['outfit_carry']
X['sBuyList'] = tOutFitList[sOutfitType]
X['sSellList'] = {
"item_sheepstick",
"item_bottle",
"item_blink",
"item_null_talisman",
"item_travel_boots",
"item_arcane_boots",
"item_aeon_disk",
"item_magic_wand",
"item_sheepstick",
"item_ring_of_basilius",
}
if J.Role.IsPvNMode() or J.Role.IsAllShadow() then X['sBuyList'], X['sSellList'] = { 'PvN_mage' }, {} end
nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] = J.SetUserHeroInit( nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] )
X['sSkillList'] = J.Skill.GetSkillList( sAbilityList, nAbilityBuildList, sTalentList, nTalentBuildList )
X['bDeafaultAbility'] = false
X['bDeafaultItem'] = false
function X.MinionThink( hMinionUnit )
if Minion.IsValidUnit( hMinionUnit )
then
Minion.IllusionThink( hMinionUnit )
end
end
--[[
npc_dota_hero_grimstroke
"Ability1" "grimstroke_dark_artistry"
"Ability2" "grimstroke_ink_creature"
"Ability3" "grimstroke_spirit_walk"
"Ability4" "grimstroke_dark_portrait"
"Ability5" "generic_hidden"
"Ability6" "grimstroke_soul_chain"
"Ability10" "special_bonus_unique_grimstroke_8"
"Ability11" "special_bonus_unique_grimstroke_7"
"Ability12" "special_bonus_unique_grimstroke_soul_chain_reflect_damage"
"Ability13" "special_bonus_unique_grimstroke_6"
"Ability14" "special_bonus_unique_grimstroke_3"
"Ability15" "special_bonus_unique_grimstroke_4"
"Ability16" "special_bonus_unique_grimstroke_1"
"Ability17" "special_bonus_unique_grimstroke_2"
modifier_grimstroke_dark_artistry_slow
modifier_grimstroke_ink_creature_spawning
modifier_grimstroke_ink_creature
modifier_grimstroke_ink_creature_latched
modifier_grimstroke_ink_creature_debuff
modifier_grimstroke_spirit_walk_buff
modifier_grimstroke_scepter_buff
modifier_grimstroke_soul_chain_channel_check
modifier_grimstroke_soul_chain
--]]
local abilityQ = bot:GetAbilityByName( sAbilityList[1] )
local abilityW = bot:GetAbilityByName( sAbilityList[2] )
local abilityE = bot:GetAbilityByName( sAbilityList[3] )
local abilityD = bot:GetAbilityByName( sAbilityList[4] )
local abilityR = bot:GetAbilityByName( sAbilityList[6] )
local castQDesire, castQLocation
local castWDesire, castWTarget
local castEDesire, castETarget
local castDDesire, castDTarget
local castRDesire, castRTarget
local nKeepMana, nMP, nHP, nLV, botTarget, hEnemyList, hAllyList, sMotive
local bonusRange = 0
function X.SkillsComplement()
if J.CanNotUseAbility( bot ) or bot:IsInvisible() then return end
nKeepMana = 400
bonusRange = 0
nLV = bot:GetLevel()
nMP = bot:GetMana()/bot:GetMaxMana()
nHP = bot:GetHealth()/bot:GetMaxHealth()
botTarget = J.GetProperTarget( bot )
hEnemyList = bot:GetNearbyHeroes( 1600, true, BOT_MODE_NONE )
hAllyList = J.GetAlliesNearLoc( bot:GetLocation(), 1600 )
bonusRange = J.GetBonusCastRange( bot )
castRDesire, castRTarget, sMotive = A.ConsiderGrimstrokeSoulbind( bot )
if castRDesire > 0
then
J.SetReportMotive( bDebugMode, sMotive )
J.SetQueuePtToINT( bot, true )
bot:ActionQueue_UseAbilityOnEntity( abilityR, castRTarget )
return
end
castWDesire, castWTarget, sMotive = A.ConsiderGrimstrokePhantomsEmbrace( bot )
if castWDesire > 0
then
J.SetReportMotive( bDebugMode, sMotive )
J.SetQueuePtToINT( bot, true )
bot:ActionQueue_UseAbilityOnEntity( abilityW, castWTarget )
return
end
castDDesire, castDTarget, sMotive = A.ConsiderGrimstrokeDarkPortrait( bot )
if castDDesire > 0
then
J.SetReportMotive( bDebugMode, sMotive )
J.SetQueuePtToINT( bot, true )
bot:ActionQueue_UseAbilityOnEntity( abilityD, castDTarget )
return
end
castEDesire, castETarget, sMotive = A.ConsiderGrimstrokeInkSwell( bot )
if castEDesire > 0
then
J.SetReportMotive( bDebugMode, sMotive )
J.SetQueuePtToINT( bot, true )
bot:ActionQueue_UseAbilityOnEntity( abilityE, castETarget )
return
end
castQDesire, castQLocation, sMotive = A.ConsiderGrimstrokeStrokeOfFate( bot )
if castQDesire > 0
then
J.SetReportMotive( bDebugMode, sMotive )
J.SetQueuePtToINT( bot, true )
bot:ActionQueue_UseAbilityOnLocation( abilityQ, castQLocation )
return
end
end
return X
\ No newline at end of file
----------------------------------------------------------------------------------------------------
--- The Creation Come From: Nikel
----------------------------------------------------------------------------------------------------
local X = {}
local ability = nil
local bonusRange, nMP, nHP, nLV, botTarget, nEnemyHeroesInRange, nAlliedHeroesInRange
-- local BOT_ACTION_DESIRE_NONE, BOT_ACTION_DESIRE_HIGH, BOT_MODE_ROSHAN, DAMAGE_TYPE_MAGICAL, DAMAGE_TYPE_PHYSICAL, DAMAGE_TYPE_PURE, BOT_MODE_NONE, ATTRIBUTE_INTELLECT
local J = require( GetScriptDirectory()..'/FunLib/jmz_func')
function X.Init( bot )
nLV = bot:GetLevel()
nMP = bot:GetMana() / bot:GetMaxMana()
nHP = bot:GetHealth() / bot:GetMaxHealth()
botTarget = J.GetProperTarget( bot )
nEnemyHeroesInRange = bot:GetNearbyHeroes( 1400, true, BOT_MODE_NONE )
nAlliedHeroesInRange = J.GetAlliesNearLoc( bot:GetLocation(), 1400 )
bonusRange = J.GetBonusCastRange( bot )
end
-- npc_dota_hero_abaddon
function X.ConsiderAbaddonMistCoil( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'abaddon_death_coil' )
local talent = bot:GetAbilityByName( 'special_bonus_unique_abaddon_4' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nSkillLV = ability:GetLevel()
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = talent:IsTrained() and 250 or 0
local nCastPoint = ability:GetCastPoint()
local nManaCost = ability:GetManaCost()
local nDamage = ability:GetSpecialValueInt( 'target_damage' )
local nLowestHealthAlly = nil
local nLowestHealth = 100000
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and J.GetHP( npcAlly ) < 0.76
and npcAlly:GetHealth() < nLowestHealth
and npcAlly ~= bot
then
nLowestHealth = npcAlly:GetHealth()
nLowestHealthAlly = npcAlly
end
end
if nLowestHealthAlly ~= nil
and J.IsInRange( nLowestHealthAlly, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nLowestHealthAlly, "MistCoil-Heal:"..J.Chat.GetNormName( nLowestHealthAlly )
end
local nLowestHealthEnemy = nil
nLowestHealth = 100000
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint )
and not npcEnemy:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "MistCoil-Kill:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.GetHP( npcEnemy ) < 0.55
and not npcEnemy:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "MistCoil-Attack:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and J.IsHealing( npcEnemy )
and not npcEnemy:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "MistCoil-DispelHeal:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and npcEnemy:GetHealth() < nLowestHealth
and DotaTime() > 8 * 60
then
nLowestHealth = npcEnemy:GetHealth()
nLowestHealthEnemy = npcEnemy
end
end
if nLowestHealthEnemy ~= nil
and J.IsInRange( nLowestHealthEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nLowestHealthEnemy, "MistCoil-Battle:"..J.Chat.GetNormName( nLowestHealthEnemy )
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "MistCoil-Attack:"..J.Chat.GetNormName( botTarget )
end
end
if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nSkillLV >= 2 and DotaTime() > 8 * 60
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and talent:IsTrained()
then
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
and J.GetAroundTargetEnemyUnitCount( nEnemyCreeps[1], 300 ) >= 1
then
return BOT_ACTION_DESIRE_HIGH, nEnemyCreeps[1], "MistCoil-Push:"..( J.GetAroundTargetEnemyUnitCount( nEnemyCreeps[1], 300 ) + 1 )
end
end
if J.IsFarming( bot )
and not ( J.IsPushing( bot ) or J.IsDefending( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.25 )
and nSkillLV >= 3
and #nEnemyHeroesInRange == 0
and #nAlliedHeroesInRange <= 2
and nMP >= 0.55
and X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
and talent:IsTrained()
then
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 2
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 200
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
return BOT_ACTION_DESIRE_HIGH, targetCreep, "MistCoil-Farm:"..( #nNeutralCreeps )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "MistCoil-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAbaddonAphoticShield( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'abaddon_aphotic_shield' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnNonMagicImmune( npcAlly )
and ( J.IsDisabled( npcAlly ) or J.ShouldDispelStrongDebuff( npcAlly ) )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "AphoticShield-Protect:"..J.Chat.GetNormName( npcAlly )
end
if J.IsValidHero( npcAlly )
and J.CanCastOnNonMagicImmune( npcAlly )
and not npcAlly:HasModifier( 'modifier_fountain_aura' )
and not npcAlly:HasModifier( 'modifier_abaddon_aphotic_shield' )
and J.GetHP( npcAlly ) < 0.85
and npcAlly:WasRecentlyDamagedByAnyHero( 1.0 )
and #nEnemyHeroesInRange >= 1
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "AphoticShield-Protect:"..J.Chat.GetNormName( npcAlly )
end
-- if J.IsValidHero( npcAlly )
-- and J.CanCastOnNonMagicImmune( npcAlly )
-- and J.GetAroundTargetEnemyHeroCount( npcAlly, nRadius ) >= 1
-- and not npcAlly:HasModifier( 'modifier_abaddon_aphotic_shield' )
-- then
-- return BOT_ACTION_DESIRE_HIGH, npcAlly, "AphoticShield-Buff:"..J.Chat.GetNormName( npcAlly )
-- end
end
if J.IsGoingOnSomeone( bot )
then
local npcAlly = J.GetNearestUnitToTarget( nAlliedHeroesInRange, botTarget, nRadius )
if J.IsValidHero( npcAlly )
and J.CanCastOnNonMagicImmune( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "AphoticShield-Chase:"..J.Chat.GetNormName( npcAlly )
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
local npcAlly = J.GetNearestUnitToTarget( nAlliedHeroesInRange, botTarget, nRadius )
if J.IsValidHero( npcAlly )
and J.CanCastOnNonMagicImmune( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "AphoticShield-Roshan:"..J.Chat.GetNormName( npcAlly )
end
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAbaddonBorrowedTime( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'abaddon_borrowed_time' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = bot:HasScepter() and ability:GetSpecialValueInt( 'redirect_range_scepter' ) or 0
if ( bot:GetHealth() < 500 or nHP < 0.23 )
and bot:WasRecentlyDamagedByAnyHero( 2.0 )
then
return BOT_ACTION_DESIRE_HIGH, "BorrowedTime-Defend"
end
if bot:HasScepter()
then
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if npcAlly:WasRecentlyDamagedByAnyHero( 2.0 )
and J.GetHP( npcAlly ) < 0.65
and J.IsInRange( npcAlly, bot, nRadius )
then
return BOT_ACTION_DESIRE_HIGH, "BorrowedTime-Protect"
end
if J.IsRetreating( npcAlly )
and npcAlly:WasRecentlyDamagedByAnyHero( 2.0 )
and J.GetHP( npcAlly ) < 0.55
and J.IsInRange( npcAlly, bot, nRadius )
then
return BOT_ACTION_DESIRE_HIGH, "BorrowedTime-Retreat"
end
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.CanCastAbilityAbaddonMistCoil( bot, nDamage )
return bot:GetHealth() - ( nDamage * 0.5 ) > 500
or bot:HasModifier( 'modifier_abaddon_borrowed_time' )
end
-- npc_dota_hero_abyssal_underlord
-- npc_dota_hero_alchemist
function X.ConsiderAlchemistAcidSpray( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'alchemist_acid_spray' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nSkillLV = ability:GetLevel()
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'radius' )
local nCastPoint = ability:GetCastPoint()
local nManaCost = ability:GetManaCost()
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.GetHP( npcEnemy ) < 0.55
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'AcidSpray-Attack:'..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.IsHealing( npcEnemy )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'AcidSpray-DispelHeal:'..J.Chat.GetNormName( npcEnemy )
end
end
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.38
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'AcidSpray-Harass'
end
if #nAlliedHeroesInRange >= #nEnemyHeroesInRange
then
nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.58
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "AcidSpray-Harass"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = J.GetCastLocation( bot, botTarget, nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "AcidSpray-Attack:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and J.CanCastOnNonMagicImmune( npcEnemy )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
then
nTargetLocation = J.GetCastLocation( bot, npcEnemy, nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'AcidSpray-Retreat:'..J.Chat.GetNormName( npcEnemy )
end
end
end
if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nSkillLV >= 2 and DotaTime() > 8 * 60
then
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
then
local nAoeLoc = bot:FindAoELocation( true, false, bot:GetLocation(), nCastRange, nRadius, 0, 0 )
if nAoeLoc.count >= 3
then
nTargetLocation = nAoeLoc.targetloc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "AcidSpray-Push:"..nAoeLoc.count
end
end
end
if J.IsFarming( bot )
and not ( J.IsPushing( bot ) or J.IsDefending( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.25 )
and nSkillLV >= 3
and #nEnemyHeroesInRange == 0
and #nAlliedHeroesInRange <= 2
and nMP >= 0.55
then
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 3 or nMP >= 0.7
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 300
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
nTargetLocation = targetCreep:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "AcidSpray-Farm:"..( #nNeutralCreeps )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
nTargetLocation = botTarget:GetLocation()
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "AcidSpray-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAlchemistUnstableConcoction( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'alchemist_unstable_concoction' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.GetHP( npcEnemy ) < 0.55
then
return BOT_ACTION_DESIRE_HIGH, "UnstableConcoction-Attack"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, "UnstableConcoction-Attack"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAlchemistUnstableConcoctionThrow( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'alchemist_unstable_concoction_throw' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if ( not ability:IsFullyCastable() or ability:IsHidden() ) then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and ( bot:IsChanneling() or bot:HasModifier( 'modifier_crystal_maiden_freezing_field' ) )
and ( nLV >= 6 or nMP > 0.55 )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, true, "UnstableConcoctionThrow-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.GetHP( npcEnemy ) < 0.55
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, false, "UnstableConcoctionThrow-Attack:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, false, "UnstableConcoctionThrow-Attack:"..J.Chat.GetNormName( botTarget )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAlchemistBerserkPotion( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'alchemist_berserk_potion' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and J.ShouldDispelDebuff( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "BerserkPotion-Protect:"..J.Chat.GetNormName( npcAlly )
end
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and not npcAlly:HasModifier( 'modifier_fountain_aura' )
and J.GetHP( npcAlly ) < 0.65
and npcAlly:WasRecentlyDamagedByAnyHero( 1.0 )
and #nEnemyHeroesInRange >= 1
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "BerserkPotion-Protect:"..J.Chat.GetNormName( npcAlly )
end
end
if J.IsGoingOnSomeone( bot )
then
return BOT_ACTION_DESIRE_HIGH, bot, "BerserkPotion-Chase:"..J.Chat.GetNormName( bot )
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
return BOT_ACTION_DESIRE_HIGH, bot, "BerserkPotion-Roshan:"..J.Chat.GetNormName( bot )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderAlchemistChemicalRage( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'alchemist_chemical_rage' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
if #nAlliedHeroesInRange + 1 >= #nEnemyHeroesInRange
and J.IsGoingOnSomeone( bot )
and J.IsValidHero( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, "ChemicalRage-Attack"
end
return BOT_ACTION_DESIRE_NONE, nil
end
-- npc_dota_hero_ancient_apparition
-- npc_dota_hero_antimage
-- npc_dota_hero_arc_warden
-- npc_dota_hero_axe
-- npc_dota_hero_bane
-- npc_dota_hero_batrider
-- npc_dota_hero_beastmaster
-- npc_dota_hero_bloodseeker
-- npc_dota_hero_bounty_hunter
-- npc_dota_hero_brewmaster
-- npc_dota_hero_bristleback
-- npc_dota_hero_broodmother
-- npc_dota_hero_centaur
-- npc_dota_hero_chaos_knight
-- npc_dota_hero_chen
-- npc_dota_hero_clinkz
-- npc_dota_hero_crystal_maiden
-- npc_dota_hero_dark_seer
-- npc_dota_hero_dark_willow
-- npc_dota_hero_dawnbreaker
-- npc_dota_hero_dazzle
-- npc_dota_hero_disruptor
-- npc_dota_hero_death_prophet
-- npc_dota_hero_doom_bringer
-- npc_dota_hero_dragon_knight
-- npc_dota_hero_drow_ranger
-- npc_dota_hero_earth_spirit
-- npc_dota_hero_earthshaker
-- npc_dota_hero_elder_titan
-- npc_dota_hero_ember_spirit
-- npc_dota_hero_enchantress
-- npc_dota_hero_enigma
-- npc_dota_hero_faceless_void
-- npc_dota_hero_furion
-- npc_dota_hero_grimstroke
function X.ConsiderGrimstrokeStrokeOfFate( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'grimstroke_dark_artistry' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nSkillLV = ability:GetLevel()
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'end_radius' )
local nCastPoint = ability:GetCastPoint()
local nManaCost = ability:GetManaCost()
local nDamage = ability:GetSpecialValueInt( 'damage' )
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.GetHP( npcEnemy ) < 0.55
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Attack:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint )
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Kill:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.IsHealing( npcEnemy )
and not npcEnemy:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-DispelHeal:"..J.Chat.GetNormName( npcEnemy )
end
end
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.38
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Harass"
end
if #nAlliedHeroesInRange >= #nEnemyHeroesInRange
then
nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.58
and not nEnemyHeroesInRange[1]:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Harass"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Attack:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Retreat:"..J.Chat.GetNormName( npcEnemy )
end
end
end
if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nSkillLV >= 2 and DotaTime() > 8 * 60
then
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
then
nAoeLoc = bot:FindAoELocation( true, false, bot:GetLocation(), nCastRange, nRadius, 0, 0 )
if nAoeLoc.count >= 3
then
nTargetLocation = nAoeLoc.targetloc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Push:"..nAoeLoc.count
end
end
end
if J.IsFarming( bot )
and not ( J.IsPushing( bot ) or J.IsDefending( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.25 )
and nSkillLV >= 3
and #nEnemyHeroesInRange == 0
and #nAlliedHeroesInRange <= 2
and nMP >= 0.55
then
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 2
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 200
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
nTargetLocation = targetCreep:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Farm:"..( #nNeutralCreeps )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
nTargetLocation = botTarget:GetLocation()
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "StrokeOfFate-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderGrimstrokePhantomsEmbrace( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'grimstroke_ink_creature' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nCastPoint = ability:GetCastPoint()
local nMostDangerousEnemy = nil
local nMostDangerousDamage = 0
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.ShouldInterrupt( npcEnemy )
and ( nLV >= 6 or nMP > 0.55 )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "PhantomsEmbrace-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and npcEnemy:HasModifier( 'modifier_grimstroke_soul_chain' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "PhantomsEmbrace-Ult:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.GetHP( npcEnemy ) < 0.55
and ( not J.IsDisabled( npcEnemy ) or not npcEnemy:IsSilenced() )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "PhantomsEmbrace-Attack:"..J.Chat.GetNormName( npcEnemy )
end
local nEnemyDamage = npcEnemy:GetEstimatedDamageToTarget( false, bot, 3.0, DAMAGE_TYPE_MAGICAL )
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and ( not J.IsDisabled( npcEnemy ) or not npcEnemy:IsSilenced() )
and nEnemyDamage > nMostDangerousDamage
and ( nLV >= 6 or J.GetHP( npcEnemy ) < 0.65 )
then
nMostDangerousDamage = nEnemyDamage
nMostDangerousEnemy = npcEnemy
end
end
if nMostDangerousEnemy ~= nil
and J.IsInRange( nMostDangerousEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nMostDangerousEnemy, "PhantomsEmbrace-Battle:"..J.Chat.GetNormName( nMostDangerousEnemy )
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
and ( not J.IsDisabled( botTarget ) or not botTarget:IsSilenced() )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "PhantomsEmbrace-Chase:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
and ( not J.IsDisabled( npcEnemy ) or not npcEnemy:IsSilenced() )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "PhantomsEmbrace-Retreat:"..J.Chat.GetNormName( npcEnemy )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "PhantomsEmbrace-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderGrimstrokeInkSwell( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'grimstroke_spirit_walk' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and ( J.IsDisabled( npcAlly ) or J.ShouldDispelStrongDebuff( npcAlly ) )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "InkSwell-Protect:"..J.Chat.GetNormName( npcAlly )
end
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and not npcAlly:HasModifier( 'modifier_fountain_aura' )
and J.GetHP( npcAlly ) < 0.85
and npcAlly:WasRecentlyDamagedByAnyHero( 1.0 )
and #nEnemyHeroesInRange >= 1
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "InkSwell-Protect:"..J.Chat.GetNormName( npcAlly )
end
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and J.GetAroundTargetEnemyHeroCount( npcAlly, nRadius ) >= 1
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "InkSwell-Buff:"..J.Chat.GetNormName( npcAlly )
end
end
if J.IsGoingOnSomeone( bot )
then
local npcAlly = J.GetNearestUnitToTarget( nAlliedHeroesInRange, botTarget, nRadius )
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "InkSwell-Chase:"..J.Chat.GetNormName( botTarget )
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
local npcAlly = J.GetNearestUnitToTarget( nAlliedHeroesInRange, botTarget, nRadius )
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "InkSwell-Roshan:"..J.Chat.GetNormName( npcAlly )
end
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderGrimstrokeDarkPortrait( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'grimstroke_dark_portrait' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nMostDangerousEnemy = nil
local nMostDangerousDamage = 0
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and npcEnemy:HasModifier( 'modifier_grimstroke_soul_chain' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "DarkPortrait-Ult:"..J.Chat.GetNormName( npcEnemy )
end
local nEnemyDamage = npcEnemy:GetEstimatedDamageToTarget( false, bot, 3.0, DAMAGE_TYPE_PHYSICAL )
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and nEnemyDamage > nMostDangerousDamage
then
nMostDangerousDamage = nEnemyDamage
nMostDangerousEnemy = npcEnemy
end
end
if nMostDangerousEnemy ~= nil
and J.IsInRange( nMostDangerousEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nMostDangerousEnemy, "DarkPortrait-Battle:"..J.Chat.GetNormName( nMostDangerousEnemy )
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "DarkPortrait-Chase:"..J.Chat.GetNormName( botTarget )
end
end
end
function X.ConsiderGrimstrokeSoulbind( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'grimstroke_soul_chain' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'chain_latch_radius' )
if #nEnemyHeroesInRange < 2 then return BOT_ACTION_DESIRE_NONE, nil end
local nMostDangerousEnemy = nil
local nMostDangerousDamage = 0
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
local nEnemyDamage = npcEnemy:GetEstimatedDamageToTarget( false, bot, 3.0, DAMAGE_TYPE_PHYSICAL )
if J.IsValidHero( npcEnemy )
and J.CanCastOnMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and nEnemyDamage > nMostDangerousDamage
and J.GetAroundTargetEnemyHeroCount( npcEnemy, nRadius + 250 ) >= 1
then
nMostDangerousDamage = nEnemyDamage
nMostDangerousEnemy = npcEnemy
end
end
if nMostDangerousEnemy ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nMostDangerousEnemy, "SoulBind-Battle:"..J.Chat.GetNormName( nMostDangerousEnemy )
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
and J.GetAroundTargetEnemyHeroCount( botTarget, nRadius + 250 ) >= 1
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "SoulBind-Chase:"..J.Chat.GetNormName( botTarget )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
-- npc_dota_hero_gyrocopter
-- npc_dota_hero_hoodwink
-- npc_dota_hero_huskar
-- npc_dota_hero_invoker
-- npc_dota_hero_jakiro
-- npc_dota_hero_juggernaut
-- npc_dota_hero_keeper_of_the_light
-- npc_dota_hero_kunkka
-- npc_dota_hero_legion_commander
-- npc_dota_hero_leshrac
-- npc_dota_hero_lich
-- npc_dota_hero_life_stealer
-- npc_dota_hero_lina
function X.ConsiderLinaDragonSlave( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'lina_dragon_slave' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nSkillLV = ability:GetLevel()
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( "dragon_slave_width_end" )
local nCastPoint = ability:GetCastPoint()
local nManaCost = ability:GetManaCost()
local nDamage = ability:GetSpecialValueInt( "AbilityDamage" )
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Kill:'..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.GetHP( npcEnemy ) < 0.55
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Attack:'..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.IsHealing( npcEnemy )
and not npcEnemy:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-DispelHeal:'..J.Chat.GetNormName( npcEnemy )
end
end
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.38
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Harass'
end
if #nAlliedHeroesInRange >= #nEnemyHeroesInRange
then
nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nMP > 0.58
and not nEnemyHeroesInRange[1]:HasModifier( 'modifier_templar_assassin_refraction_absorb' )
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "DragonSlave-Harass"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Attack:'..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and J.CanCastOnNonMagicImmune( npcEnemy )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Retreat:'..J.Chat.GetNormName( npcEnemy )
end
end
end
if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nSkillLV >= 2 and DotaTime() > 8 * 60
then
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
then
nAoeLoc = bot:FindAoELocation( true, false, bot:GetLocation(), nCastRange, nRadius, 0, 0 )
if nAoeLoc.count >= 3
then
nTargetLocation = nAoeLoc.targetloc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "DragonSlave-Push:"..nAoeLoc.count
end
end
end
if J.IsFarming( bot )
and not ( J.IsPushing( bot ) or J.IsDefending( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.25 )
and nSkillLV >= 3
and #nEnemyHeroesInRange == 0
and #nAlliedHeroesInRange <= 2
and nMP >= 0.55
then
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 3 or nMP >= 0.7
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 300
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
nTargetLocation = targetCreep:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "DragonSlave-Farm:"..( #nNeutralCreeps )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and bot:GetMana() >= 400
then
if J.IsRoshan( botTarget ) and J.GetHP( botTarget ) > 0.15
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = botTarget:GetLocation()
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'DragonSlave-Roshan'
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderLinaLightStrikeArray( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'lina_light_strike_array' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nSkillLV = ability:GetLevel()
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( "light_strike_array_aoe" )
local nCastPoint = ability:GetCastPoint()
local nCastDelay = 0.5
local nManaCost = ability:GetManaCost()
local nDamage = ability:GetSpecialValueInt( 'light_strike_array_damage' )
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.ShouldInterrupt( npcEnemy )
and ( nLV >= 6 or nMP > 0.55 )
then
nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius, nCastPoint + nCastDelay )
if nTargetLocation ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint + nCastDelay )
then
nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius, nCastPoint + nCastDelay )
if nTargetLocation ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-Kill:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsValidHero( npcEnemy )
and J.IsInRange( botTarget, bot, nCastRange + nRadius )
and ( ( botTarget:HasModifier( 'modifier_obsidian_destroyer_astral_imprisonment_prison' )
and J.GetModifierTime( botTarget, 'modifier_obsidian_destroyer_astral_imprisonment_prison' ) < nCastPoint + nCastDelay
and J.GetModifierTime( botTarget, 'modifier_obsidian_destroyer_astral_imprisonment_prison' ) >= ( nCastPoint + nCastDelay - 0.5 )
)
or (
botTarget:HasModifier( 'modifier_shadow_demon_disruption' )
and J.GetModifierTime( botTarget, 'modifier_shadow_demon_disruption' ) < nCastPoint + nCastDelay
and J.GetModifierTime( botTarget, 'modifier_shadow_demon_disruption' ) >= ( nCastPoint + nCastDelay - 0.5 )
)
or (
botTarget:HasModifier( 'modifier_wind_waker' )
and J.GetModifierTime( botTarget, 'modifier_wind_waker' ) < nCastPoint + nCastDelay
and J.GetModifierTime( botTarget, 'modifier_wind_waker' ) >= ( nCastPoint + nCastDelay - 0.5 )
)
or (
botTarget:HasModifier( 'modifier_eul_cyclone' )
and J.GetModifierTime( botTarget, 'modifier_eul_cyclone' ) < nCastPoint + nCastDelay
and J.GetModifierTime( botTarget, 'modifier_eul_cyclone' ) >= ( nCastPoint + nCastDelay - 0.5 )
)
or (
botTarget:HasModifier( 'modifier_invoker_tornado' )
and J.GetModifierTime( botTarget, 'modifier_invoker_tornado' ) < nCastPoint + nCastDelay
and J.GetModifierTime( botTarget, 'modifier_invoker_tornado' ) >= ( nCastPoint + nCastDelay - 0.5 )
)
)
then
nTargetLocation = J.GetCastLocation( bot, botTarget, nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-ChainStun:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange + nRadius )
and J.GetHP( npcEnemy ) < 0.55
and not J.IsDisabled( npcEnemy )
then
nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius, nCastPoint + nCastDelay )
if nTargetLocation ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-Attack:"..J.Chat.GetNormName( npcEnemy )
end
end
end
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'LightStrikeArray-Harass'
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
and not J.IsDisabled( botTarget )
then
nTargetLocation = J.GetDelayCastLocation( bot, botTarget, nCastRange, nRadius, nCastPoint + nCastDelay )
if nTargetLocation ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'LightStrikeArray-Attack:'..J.Chat.GetNormName( botTarget )
end
end
end
if J.IsRetreating( bot )
then
nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 2 )
if nAoeLoc ~= nil
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'LightStrikeArray-Retreat'
end
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and J.CanCastOnNonMagicImmune( npcEnemy )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
and not J.IsDisabled( npcEnemy )
then
nTargetLocation = J.GetDelayCastLocation( bot, npcEnemy, nCastRange, nRadius, nCastPoint + nCastDelay )
if nTargetLocation ~= nil
then
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'LightStrikeArray-Retreat:'..J.Chat.GetNormName( npcEnemy )
end
end
end
end
if ( J.IsPushing( bot ) or J.IsDefending( bot ) or J.IsFarming( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.72 )
and nSkillLV >= 2 and DotaTime() > 8 * 60
then
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
then
nAoeLoc = bot:FindAoELocation( true, false, bot:GetLocation(), nCastRange, nRadius, 0, 0 )
if nAoeLoc.count >= 3
then
nTargetLocation = nAoeLoc.targetloc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-ClearWave:"..nAoeLoc.count
end
end
end
if J.IsFarming( bot )
and not ( J.IsPushing( bot ) or J.IsDefending( bot ) )
and J.IsAllowedToSpam( bot, nManaCost * 0.25 )
and nSkillLV >= 3
and #nEnemyHeroesInRange == 0
and #nAlliedHeroesInRange <= 2
and nMP >= 0.55
then
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 2
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 200
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
nTargetLocation = targetCreep:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "LightStrikeArray-Farm:"..( #nNeutralCreeps )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
nTargetLocation = botTarget:GetLocation()
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'LightStrikeArray-Roshan'
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderLinaFlameCloak( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'lina_flame_cloak' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable()
or not bot:HasScepter()
then
return BOT_ACTION_DESIRE_NONE, nil
end
if J.IsInTeamFight( bot, 1400 )
then
if #nEnemyHeroesInRange >= #nAlliedHeroesInRange
then
return BOT_ACTION_DESIRE_HIGH, "FlameCloak-Battle"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.IsInRange( botTarget, bot, 700 )
and J.CanCastOnNonMagicImmune( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, "FlameCloak-Chase:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
if #nEnemyHeroesInRange >= 1
and J.IsValidHero( nEnemyHeroesInRange[1] )
and J.WasRecentlyDamagedByAnyHero( bot, 5.0 )
then
return BOT_ACTION_DESIRE_HIGH, "FlameCloak-Retreat"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderLinaLagunaBlade( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'lina_laguna_blade' )
local talent = bot:GetAbilityByName( 'special_bonus_unique_lina_7' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nCastPoint = ability:GetCastPoint()
local nDamage = ability:GetSpecialValueInt( "damage" )
local nDamageType = talent:IsTrained() and DAMAGE_TYPE_PURE or DAMAGE_TYPE_MAGICAL
local nWeakestEnemy = nil
local nWeakestEnemyHealth = 100000
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and X.CanCastAbilityLinaLagunaBlade( npcEnemy, talent )
then
if ( nDamageType == DAMAGE_TYPE_MAGICAL
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint ) )
or J.WillKillTarget( npcEnemy, nDamage, nDamageType, nCastPoint )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "LagunaBlade-Kill:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsValidHero( npcEnemy )
and X.CanCastAbilityLinaLagunaBlade( botTarget, talent )
and J.GetHP( npcEnemy ) < 0.45
and npcEnemy:GetHealth() < nWeakestEnemyHealth
then
nWeakestEnemyHealth = npcEnemy:GetHealth()
nWeakestEnemy = npcEnemy
end
end
if nWeakestEnemy ~= nil
and J.IsInRange( nWeakestEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nWeakestEnemy, "LagunaBlade-Battle:"..J.Chat.GetNormName( nWeakestEnemy )
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and X.CanCastAbilityLinaLagunaBlade( botTarget, talent )
and J.IsInRange( botTarget, bot, nCastRange )
and J.WillMagicKillTarget( bot, botTarget, nDamage * 1.88, nCastPoint )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "LagunaBlade-Attack:"..J.Chat.GetNormName( botTarget )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.CanCastAbilityLinaLagunaBlade( nTarget, talent )
if J.CanCastOnTargetAdvanced( nTarget )
and not nTarget:HasModifier( "modifier_arc_warden_tempest_double" )
then
if talent:IsTrained()
then
return J.CanCastOnMagicImmune( nTarget )
else
return J.CanCastOnNonMagicImmune( nTarget )
end
end
return false
end
-- npc_dota_hero_lion
-- npc_dota_hero_lone_druid
-- npc_dota_hero_luna
-- npc_dota_hero_lycan
-- npc_dota_hero_magnataur
-- npc_dota_hero_marci
-- npc_dota_hero_mars
-- npc_dota_hero_medusa
-- npc_dota_hero_meepo
-- npc_dota_hero_mirana
-- npc_dota_hero_morphling
-- npc_dota_hero_monkey_king
-- npc_dota_hero_naga_siren
-- npc_dota_hero_necrolyte
-- npc_dota_hero_nevermore
-- npc_dota_hero_night_stalker
-- npc_dota_hero_nyx_assassin
-- npc_dota_hero_obsidian_destroyer
-- npc_dota_hero_ogre_magi
-- npc_dota_hero_omniknight
-- npc_dota_hero_oracle
-- npc_dota_hero_pangolier
-- npc_dota_hero_phantom_lancer
-- npc_dota_hero_phantom_assassin
-- npc_dota_hero_phoenix
-- npc_dota_hero_primal_beast
-- npc_dota_hero_puck
-- npc_dota_hero_pudge
-- npc_dota_hero_pugna
-- npc_dota_hero_queenofpain
-- npc_dota_hero_rattletrap
-- npc_dota_hero_razor
-- npc_dota_hero_riki
-- npc_dota_hero_rubick
-- npc_dota_hero_sand_king
-- npc_dota_hero_shadow_demon
-- npc_dota_hero_shadow_shaman
-- npc_dota_hero_shredder
-- npc_dota_hero_silencer
-- npc_dota_hero_skeleton_king
-- npc_dota_hero_skywrath_mage
-- npc_dota_hero_slardar
-- npc_dota_hero_slark
-- npc_dota_hero_snapfire
-- npc_dota_hero_sniper
-- npc_dota_hero_spectre
-- npc_dota_hero_spirit_breaker
-- npc_dota_hero_storm_spirit
-- npc_dota_hero_sven
-- npc_dota_hero_techies
-- npc_dota_hero_terrorblade
-- npc_dota_hero_templar_assassin
-- npc_dota_hero_tidehunter
-- npc_dota_hero_tinker
-- npc_dota_hero_tiny
-- npc_dota_hero_treant
-- npc_dota_hero_troll_warlord
-- npc_dota_hero_tusk
-- npc_dota_hero_undying
-- npc_dota_hero_ursa
-- npc_dota_hero_vengefulspirit
-- npc_dota_hero_venomancer
-- npc_dota_hero_viper
-- npc_dota_hero_visage
-- npc_dota_hero_void_spirit
-- npc_dota_hero_warlock
-- npc_dota_hero_weaver
-- npc_dota_hero_windrunner
-- npc_dota_hero_winter_wyvern
-- npc_dota_hero_wisp
-- npc_dota_hero_witch_doctor
-- npc_dota_hero_zuus
-- neutral
function X.ConsiderNecronomiconPurge( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'necronomicon_archer_purge' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.ShouldDispelBuff( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "Purge-Dispel:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "Purge-Chase:"..J.Chat.GetNormName( botTarget )
end
end
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.IsRetreating( npcAlly )
and bot:WasRecentlyDamagedByAnyHero( 5.0 )
and not J.IsDisabled( nEnemyHeroesInRange[1] )
then
return BOT_ACTION_DESIRE_HIGH, nEnemyHeroesInRange[1], "Purge-Retreat:"..J.Chat.GetNormName( nEnemyHeroesInRange[1] )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralFrenzy( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'big_thunder_lizard_frenzy' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nStrongestAlly = nil
local nStrongestDamage = 0
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
local npcAllyDamage = npcAlly:GetEstimatedDamageToTarget( false, bot, 3.0, DAMAGE_TYPE_PHYSICAL )
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and ( not J.IsDisabled( npcAlly ) or not npcAlly:IsDisarmed() )
and npcAllyDamage > nStrongestDamage
and #nEnemyHeroesInRange >= 1
then
nStrongestDamage = npcAllyDamage
nStrongestAlly = npcAlly
end
end
if nStrongestAlly ~= nil
and J.IsInRange( nStrongestAlly, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nStrongestAlly, "Frenzy-Buff:"..J.Chat.GetNormName( nStrongestAlly )
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralSlam( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'big_thunder_lizard_slam' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nRadius )
and not J.IsDisabled( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, "Slam-Slow:"..J.Chat.GetNormName( npcEnemy )
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
and J.IsInRange( botTarget, bot, nRadius )
and not J.IsDisabled( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, "Slam-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralFireball( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'black_dragon_fireball' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'radius' )
local nTargetLocation
if #nEnemyHeroesInRange >= 1
then
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Fireball-Battle"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = J.GetCastLocation( bot, botTarget, nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Fireball-Attack:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and J.CanCastOnNonMagicImmune( npcEnemy )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( 0.3 ), 20 )
then
nTargetLocation = J.GetCastLocation( bot, npcEnemy, nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, 'Fireball-Retreat:'..J.Chat.GetNormName( npcEnemy )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
nTargetLocation = botTarget:GetLocation()
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Fireball-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralWarStomp( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'centaur_khan_war_stomp' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nRadius )
and J.ShouldInterrupt( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, "WarStomp-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nRadius )
and not J.IsDisabled( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, "WarStomp-Stun:"..J.Chat.GetNormName( npcEnemy )
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
and J.IsInRange( botTarget, bot, nRadius )
and not J.IsDisabled( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, "WarStomp-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralEnsnare( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'dark_troll_warlord_ensnare' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and npcEnemy:IsChanneling()
and npcEnemy:HasModifier( 'modifier_teleporting' )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "Ensnare-Root"
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and not J.IsDisabled( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "Ensnare-Chase:"..J.Chat.GetNormName( botTarget )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralRaiseDead( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'dark_troll_warlord_raise_dead' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
return BOT_ACTION_DESIRE_HIGH, "RaiseDead"
end
function X.ConsiderNeutralHurricane( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'enraged_wildkin_hurricane' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
then
nTargetLocation = J.GetFaceTowardDistanceLocation( botTarget, nCastRange )
return BOT_ACTION_DESIRE_HIGH, botTarget, nTargetLocation, "Hurricane-Battle:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = J.GetFaceTowardDistanceLocation( botTarget, nCastRange * -1 )
return BOT_ACTION_DESIRE_HIGH, botTarget, nTargetLocation, "Hurricane-Chase:"..J.Chat.GetNormName( botTarget )
end
end
if J.IsRetreating( bot )
then
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if #nEnemyHeroesInRange >= 1
and J.IsValidHero( npcAlly )
and npcAlly:WasRecentlyDamagedByAnyHero( 5.0 )
and J.CanCastOnNonMagicImmune( nEnemyHeroesInRange[1] )
and J.CanCastOnTargetAdvanced( nEnemyHeroesInRange[1] )
then
nTargetLocation = J.GetFaceTowardDistanceLocation( botTarget, nCastRange * -1 )
return BOT_ACTION_DESIRE_HIGH, botTarget, nTargetLocation, "Hurricane-Retreat:"..J.Chat.GetNormName( botTarget )
end
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralTornado( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'enraged_wildkin_tornado' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = 150
local nTargetLocation
if #nEnemyHeroesInRange >= 1
and J.IsValidHero( nEnemyHeroesInRange[1] )
and J.CanCastOnNonMagicImmune( nEnemyHeroesInRange[1] )
and J.IsInRange( nEnemyHeroesInRange[1], bot, nCastRange + 200 )
then
nTargetLocation = J.GetCastLocation( bot, nEnemyHeroesInRange[1], nCastRange, nRadius )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Tornado-Battle:"..J.Chat.GetNormName( nEnemyHeroesInRange[1] )
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralVex( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'fel_beast_haunt' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.ShouldInterrupt( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "Vex-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and ( not J.IsDisabled( npcEnemy ) or not npcEnemy:IsSilenced() )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "Vex-Silence:"..J.Chat.GetNormName( npcEnemy )
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
and ( not J.IsDisabled( botTarget ) or not botTarget:IsSilenced() )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "Vex-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralHeal( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'forest_troll_high_priest_heal' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nHealAmount = ability:GetSpecialValueInt( 'health' )
local nLowestHealthAlly = nil
local nLowestHealth = 100000
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and npcAlly:GetHealth() < nHealAmount * 1.12
and npcAlly:GetHealth() < nLowestHealth
then
nLowestHealth = npcAlly:GetHealth()
nLowestHealthAlly = npcAlly
end
end
if nLowestHealthAlly ~= nil
and J.IsInRange( nLowestHealthAlly, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nLowestHealthAlly, "Heal-Heal:"..J.Chat.GetNormName( nLowestHealthAlly )
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralTakeOff( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'harpy_scout_take_off' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
--------
--TODO--
--------
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralChainLightning( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'harpy_storm_chain_lightning' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nil, "ChainLightning-Battle:"..J.Chat.GetNormName( npcEnemy )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralIcefireBomb( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'ice_shaman_incendiary_bomb' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nil, "IcefireBomb-Battle:"..J.Chat.GetNormName( npcEnemy )
end
end
local nTowerList = bot:GetNearbyTowers( 1000, true )
local nBarrackList = bot:GetNearbyBarracks( 1000, true )
local nEnemyAncient = GetAncient( GetOpposingTeam() )
local nBuildingList = {
botTarget,
nTowerList[1],
nBarrackList[1],
nEnemyAncient,
}
for _, building in pairs( nBuildingList )
do
if J.IsValidBuilding( building )
and J.IsInRange( bot, building, nCastRange )
and not building:HasModifier( 'modifier_fountain_glyph' )
and not building:HasModifier( 'modifier_invulnerable' )
and not building:HasModifier( 'modifier_backdoor_protection' )
and not J.IsKeyWordUnit( "DOTA_Outpost", building )
then
return BOT_ACTION_DESIRE_HIGH, building, "IcefireBomb-Tower"
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "IcefireBomb-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralHurlBoulder( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'mud_golem_hurl_boulder' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.ShouldInterrupt( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "HurlBoulder-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
and not J.IsDisabled( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "HurlBoulder-Chase:"..J.Chat.GetNormName( botTarget )
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( 0.3 ), 20 )
and not J.IsDisabled( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "HurlBoulder-Retreat:"..J.Chat.GetNormName( npcEnemy )
end
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
and not J.IsDisabled( botTarget )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "HurlBoulder-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralIceArmor( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'ogre_magi_frost_armor' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and not npcAlly:HasModifier( 'modifier_ogre_magi_frost_armor' )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "IceArmor-Protect:"..J.Chat.GetNormName( npcAlly )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralOgreSmash( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'ogre_bruiser_ogre_smash' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
local nCastPoint = ability:GetCastPoint()
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.ShouldInterrupt( npcEnemy )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( nCastPoint ), 20 )
and J.IsInRange( npcEnemy, bot, nRadius * 2 )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "OgreSmash-Interrupt:"..J.Chat.GetNormName( npcEnemy )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralThunderClap( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'polar_furbolg_ursa_warrior_thunder_clap' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nRadius = ability:GetSpecialValueInt( 'radius' )
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.IsInRange( npcEnemy, bot, nRadius )
and not J.IsDisabled( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, "ThunderClap-Slow"
end
end
if bot:GetActiveMode() == BOT_MODE_ROSHAN
and nMP >= 0.78
then
if J.IsRoshan( botTarget )
and J.GetHP( botTarget ) > 0.15
and J.IsInRange( botTarget, bot, nRadius )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "ThunderClap-Roshan"
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralShockwave( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'satyr_hellcaller_shockwave' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'radius_end' )
local nCastPoint = ability:GetCastPoint()
local nDamage = ability:GetAbilityDamage()
local nTargetLocation
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.GetHP( npcEnemy ) < 0.55
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Attack:"..J.Chat.GetNormName( npcEnemy )
end
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.WillMagicKillTarget( bot, npcEnemy, nDamage, nCastPoint )
then
nTargetLocation = npcEnemy:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Kill:"..J.Chat.GetNormName( npcEnemy )
end
end
local nAoeLoc = J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, 1 )
if nAoeLoc ~= nil
then
nTargetLocation = nAoeLoc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Harass"
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
nTargetLocation = botTarget:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Attack:"..J.Chat.GetNormName( botTarget )
end
end
local nEnemyCreeps = bot:GetNearbyLaneCreeps( nCastRange + nRadius, true )
if #nEnemyCreeps >= 3
and J.IsValid( nEnemyCreeps[1] )
and not nEnemyCreeps[1]:HasModifier( "modifier_fountain_glyph" )
then
nAoeLoc = bot:FindAoELocation( true, false, bot:GetLocation(), nCastRange, nRadius, 0, 0 )
if ( nAoeLoc.count >= 3 )
then
nTargetLocation = nAoeLoc.targetloc
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Push:"..nAoeLoc.count
end
end
local nNeutralCreeps = bot:GetNearbyNeutralCreeps( nCastRange + nRadius )
if #nNeutralCreeps >= 2
then
local targetCreep = nNeutralCreeps[1]
if J.IsValid( targetCreep )
and targetCreep:GetHealth() >= 200
and J.GetAroundTargetEnemyUnitCount( targetCreep, 300 ) >= 1
then
nTargetLocation = targetCreep:GetExtrapolatedLocation( nCastPoint )
return BOT_ACTION_DESIRE_HIGH, nTargetLocation, "Shockwave-Farm:"..( #nNeutralCreeps )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralManaBurn( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'satyr_soulstealer_mana_burn' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nHighestIntEnemy = nil
local nHighestInt = 0
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
local npcEnemyInt = npcEnemy:GetAttributeValue( ATTRIBUTE_INTELLECT )
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and npcEnemyInt > nHighestInt
then
nHighestInt = npcEnemyInt
nHighestIntEnemy = npcEnemy
end
end
if nHighestIntEnemy ~= nil
and J.IsInRange( nHighestIntEnemy, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, nHighestIntEnemy, "ManaBurn-Attack:"..J.Chat.GetNormName( nHighestIntEnemy )
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralPurge( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'satyr_trickster_purge' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and J.IsInRange( npcEnemy, bot, nCastRange )
and J.ShouldDispelBuff( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "Purge-Dispel:"..J.Chat.GetNormName( npcEnemy )
end
end
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.CanCastOnMagicImmune( npcAlly )
and J.IsInRange( npcAlly, bot, nCastRange )
and J.ShouldDispelDebuff( npcAlly )
then
return BOT_ACTION_DESIRE_HIGH, npcAlly, "Purge-Dispel:"..J.Chat.GetNormName( npcAlly )
end
end
if J.IsGoingOnSomeone( bot )
then
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "Purge-Chase:"..J.Chat.GetNormName( botTarget )
end
end
for _, npcAlly in pairs( nAlliedHeroesInRange )
do
if J.IsValidHero( npcAlly )
and J.IsRetreating( npcAlly )
and bot:WasRecentlyDamagedByAnyHero( 5.0 )
and not J.IsDisabled( nEnemyHeroesInRange[1] )
then
return BOT_ACTION_DESIRE_HIGH, nEnemyHeroesInRange[1], "Purge-Retreat:"..J.Chat.GetNormName( nEnemyHeroesInRange[1] )
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
function X.ConsiderNeutralSeedShot( bot )
X.Init( bot )
ability = bot:GetAbilityByName( 'warpine_raider_seed_shot' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
local nRadius = ability:GetSpecialValueInt( 'bounce_range' )
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and not J.IsDisabled( npcEnemy )
and J.GetAroundTargetEnemyUnitCount( npcEnemy, nRadius ) >= 2
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "SeedShot-Battle:"..J.Chat.GetNormName( npcEnemy )
end
end
if J.IsValidHero( botTarget )
and J.CanCastOnNonMagicImmune( botTarget )
and J.CanCastOnTargetAdvanced( botTarget )
and J.IsInRange( botTarget, bot, nCastRange )
and not J.IsDisabled( botTarget )
and J.GetAroundTargetEnemyUnitCount( botTarget, nRadius ) >= 2
then
return BOT_ACTION_DESIRE_HIGH, botTarget, "SeedShot-Chase:"..J.Chat.GetNormName( botTarget )
end
if J.IsRetreating( bot )
then
for _, npcEnemy in pairs( nEnemyHeroesInRange )
do
if J.IsValidHero( npcEnemy )
and J.CanCastOnNonMagicImmune( npcEnemy )
and J.CanCastOnTargetAdvanced( npcEnemy )
and bot:WasRecentlyDamagedByHero( npcEnemy, 5.0 )
and bot:IsFacingLocation( npcEnemy:GetExtrapolatedLocation( 0.3 ), 20 )
and not J.IsDisabled( npcEnemy )
then
return BOT_ACTION_DESIRE_HIGH, npcEnemy, "HurlBoulder-Retreat:"..J.Chat.GetNormName( npcEnemy )
end
end
end
return BOT_ACTION_DESIRE_NONE, nil
end
--[[
function X.ConsiderNeutral( bot )
X.Init( bot )
ability = bot:GetAbilityByName( '' )
if ability == nil then return BOT_ACTION_DESIRE_NONE, nil end
if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, nil end
local nCastRange = ability:GetCastRange() + bonusRange
return BOT_ACTION_DESIRE_NONE, nil
end
]]
return X
\ No newline at end of file
......@@ -1521,6 +1521,7 @@ X["hero_roles"] = {
}
X["bottle"] = {
["npc_dota_hero_grimstroke"] = 1,
["npc_dota_hero_tinker"] = 1,
["npc_dota_hero_storm_spirit"] = 1,
["npc_dota_hero_pudge"] = 1,
......@@ -1678,6 +1679,7 @@ X['off'] = {
}
X['mid'] = {
'npc_dota_hero_grimstroke',
'npc_dota_hero_alchemist',
'npc_dota_hero_arc_warden',
'npc_dota_hero_bloodseeker',
......@@ -2157,6 +2159,7 @@ function X.IsABAHero()
["npc_dota_hero_antimage"] = true,
["npc_dota_hero_night_stalker"] = true,
["npc_dota_hero_obsidian_destroyer"] = true,
["npc_dota_hero_grimstroke"] = true,
["npc_dota_hero_arc_warden"] = true,
["npc_dota_hero_bane"] = true,
["npc_dota_hero_bloodseeker"] = true,
......
......@@ -274,6 +274,52 @@ function J.GetVulnerableWeakestUnit( bot, bHero, bEnemy, nRadius )
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 )
......@@ -323,7 +369,7 @@ function J.GetAoeEnemyHeroLocation( bot, nCastRange, nRadius, nCount )
if nTrueCount >= nCount
then
return nAoe.targetLoc
return nAoe.targetloc
end
end
......@@ -992,6 +1038,52 @@ function J.GetBonusCastRange( bot )
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 )
......@@ -1019,7 +1111,7 @@ function J.IsDisabled( npcTarget )
or J.IsTaunted( npcTarget )
else
if npcTarget:IsStunned() and J.GetRemainStunTime( npcTarget ) > 0.8
if npcTarget:IsStunned() and J.GetRemainStunTime( npcTarget ) > 0.3
then
return true
end
......@@ -1043,10 +1135,15 @@ end
function J.IsTaunted( npcTarget )
return npcTarget:HasModifier( "modifier_axe_berserkers_call" )
or npcTarget:HasModifier( "modifier_legion_commander_duel" )
or npcTarget:HasModifier( "modifier_winter_wyvern_winters_curse" )
or npcTarget:HasModifier( "modifier_winter_wyvern_winters_curse_aura" )
for _, modifier in pairs( J.Buff["hero_is_taunted"] )
do
if npcTarget:HasModifier( modifier )
then
return true
end
end
return false
end
......@@ -2494,6 +2591,19 @@ function J.ShouldDispelStrongDebuff( 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 )
......
......@@ -1021,10 +1021,11 @@ X.ConsiderItemDesire["item_black_king_bar"] = function( hItem )
local sCastType = 'none'
local hEffectTarget = nil
local sCastMotive = nil
local nInRangeEnmyList = bot:GetNearbyHeroes( nCastRange, true, BOT_MODE_NONE )
local nAlliedHeroesInRange = bot:GetNearbyHeroes( nCastRange, false, BOT_MODE_NONE )
local nEnemyHeroesInRange = bot:GetNearbyHeroes( nCastRange, true, BOT_MODE_NONE )
if #nInRangeEnmyList > 0
if #nEnemyHeroesInRange >= #nAlliedHeroesInRange
and not bot:IsMagicImmune()
and not bot:IsInvulnerable()
and not bot:HasModifier( 'modifier_item_lotus_orb_active' )
......@@ -2041,10 +2042,10 @@ X.ConsiderItemDesire["item_glimmer_cape"] = function( hItem )
and not bot:IsMagicImmune()
then
if bot:IsSilenced() or bot:IsRooted() or J.IsStunProjectileIncoming( bot, 1000 )
if bot:IsSilenced() or J.IsStunProjectileIncoming( bot, 1000 )
then
hEffectTarget = bot
sCastMotive = '自己被缠绕或沉默了'
sCastMotive = '自己被沉默了'
return BOT_ACTION_DESIRE_HIGH, hEffectTarget, sCastType, sCastMotive
end
......@@ -2108,6 +2109,62 @@ X.ConsiderItemDesire["item_glimmer_cape"] = function( hItem )
end
X.ConsiderItemDesire["item_mekansm"] = function( hItem )
local nCastRange = 1200
local sCastType = 'none'
local hEffectTarget = nil
local sCastMotive = nil
local hAllyList = J.GetAllyList( bot, nCastRange )
for _, npcAlly in pairs( hAllyList )
do
if npcAlly ~= nil and npcAlly:IsAlive()
and J.GetHP( npcAlly ) < 0.45
and #hNearbyEnemyHeroList > 0
then
hEffectTarget = npcAlly
sCastMotive = '治疗队友'..J.Chat.GetNormName( hEffectTarget )
return BOT_ACTION_DESIRE_HIGH, hEffectTarget, sCastType, sCastMotive
end
end
local needHPCount = 0
for _, npcAlly in pairs( hAllyList )
do
if npcAlly ~= nil
and npcAlly:GetMaxHealth()- npcAlly:GetHealth() > 325
then
needHPCount = needHPCount + 1
if needHPCount >= 2 and npcAlly:GetHealth() / npcAlly:GetMaxHealth() < 0.55
then
hEffectTarget = npcAlly
sCastMotive = '治疗二队友:'..J.Chat.GetNormName( hEffectTarget )
return BOT_ACTION_DESIRE_HIGH, hEffectTarget, sCastType, sCastMotive
end
if needHPCount >= 3
then
hEffectTarget = npcAlly
sCastMotive = '治疗多个队友:'..J.Chat.GetNormName( hEffectTarget )
return BOT_ACTION_DESIRE_HIGH, hEffectTarget, sCastType, sCastMotive
end
end
end
if bot:GetHealth() / bot:GetMaxHealth() < 0.5
then
hEffectTarget = bot
sCastMotive = '治疗自己:'..J.Chat.GetNormName( hEffectTarget )
return BOT_ACTION_DESIRE_HIGH, hEffectTarget, sCastType, sCastMotive
end
return BOT_ACTION_DESIRE_NONE
end
--大鞋
X.ConsiderItemDesire["item_guardian_greaves"] = function( hItem )
......@@ -4937,10 +4994,12 @@ end
function X.HasInvisibilityOrItem( npcEnemy )
if npcEnemy:HasInvisibility( false )
or J.HasInvisibilityBuff( npcEnemy )
or J.HasItem( npcEnemy, "item_shadow_amulet" )
or J.HasItem( npcEnemy, "item_glimmer_cape" )
or J.HasItem( npcEnemy, "item_invis_sword" )
or J.HasItem( npcEnemy, "item_silver_edge" )
or J.HasItem( npcEnemy, "item_trickster_cloak" )
then
return true
end
......
......@@ -174,6 +174,7 @@ local sUserKeyDir = Chat.GetUserKeyDir()
local sHasDevelopmentHeroList = {
"npc_dota_hero_abaddon",
"npc_dota_hero_grimstroke",
"npc_dota_hero_night_stalker",
"npc_dota_hero_obsidian_destroyer",
"npc_dota_hero_abyssal_underlord",
......@@ -243,6 +244,7 @@ local sHasDevelopmentHeroList = {
local sFirstList = {
"npc_dota_hero_grimstroke",
"npc_dota_hero_silencer",
"npc_dota_hero_warlock",
"npc_dota_hero_necrolyte",
......@@ -357,6 +359,7 @@ local sPriestList = {
"npc_dota_hero_queenofpain",
"npc_dota_hero_disruptor",
"npc_dota_hero_muerta",
"npc_dota_hero_grimstroke",
}
local sMageList = {
......@@ -385,6 +388,7 @@ local sMageList = {
"npc_dota_hero_disruptor",
'npc_dota_hero_venomancer',
"npc_dota_hero_obsidian_destroyer",
"npc_dota_hero_grimstroke",
}
local sCarryList = {
......
......@@ -873,8 +873,9 @@ function X.ShouldRun(bot)
end
--防止美杜莎石化
--美杜莎石化/电棍吸
if bot:HasModifier('modifier_medusa_stone_gaze_facing')
or bot:HasModifier( 'modifier_razor_link_vision' )
then
return 3.33
end
......
......@@ -1628,7 +1628,8 @@ function X.IsSpecialSupport(bot)
["npc_dota_hero_bane"] = true,
["npc_dota_hero_crystal_maiden"] = true,
["npc_dota_hero_dazzle"] = true,
["npc_dota_hero_death_prophet"] = true,
["npc_dota_hero_death_prophet"] = true,
["npc_dota_hero_grimstroke"] = true,
["npc_dota_hero_jakiro"] = true,
["npc_dota_hero_lich"] = true,
["npc_dota_hero_lina"] = true,
......@@ -1640,9 +1641,9 @@ function X.IsSpecialSupport(bot)
["npc_dota_hero_shadow_shaman"] = true,
["npc_dota_hero_silencer"] = true,
["npc_dota_hero_skywrath_mage"] = true,
["npc_dota_hero_warlock"] = true,
["npc_dota_hero_windrunner"] = true,
["npc_dota_hero_witch_doctor"] = true,
["npc_dota_hero_warlock"] = true,
["npc_dota_hero_windrunner"] = true,
["npc_dota_hero_witch_doctor"] = true,
["npc_dota_hero_zuus"] = true,
["npc_dota_hero_abaddon"] = true,
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment