From 7e5c35207f2923e61ecc09f4449ebbe44750b76f Mon Sep 17 00:00:00 2001 From: Aaron Song <31906374+AaronSong321@users.noreply.github.com> Date: Fri, 23 Apr 2021 10:32:35 +0100 Subject: [PATCH] Fix many bugs in 7.29 (#44) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix rune mode; Add battle power evaluation of illusion; Change ability building tree of Chen, Dazzle, Kotl, Dazzle; Implement Life_stealer, Dragon_knight, Leshrac, Magnataur, Phantom_assassin; Try to improve Kunkka’s x-mark combo; Fix bugs in Alchemist, Bane, Kunkka; Co-authored-by: adamqqq --- ability_item_usage_abaddon.lua | 23 +- ability_item_usage_alchemist.lua | 8 +- ability_item_usage_ancient_apparition.lua | 2 +- ability_item_usage_antimage.lua | 11 +- ability_item_usage_arc_warden.lua | 34 +- ability_item_usage_axe.lua | 1 - ability_item_usage_bane.lua | 46 +- ability_item_usage_bristleback.lua | 21 +- ability_item_usage_broodmother.lua | 88 ++- ability_item_usage_centaur.lua | 3 + ability_item_usage_chen.lua | 243 +++--- ability_item_usage_crystal_maiden.lua | 26 +- ability_item_usage_dazzle.lua | 14 +- ability_item_usage_death_prophet.lua | 10 +- ability_item_usage_doom_bringer.lua | 23 +- ability_item_usage_dragon_knight.lua | 131 +++- ability_item_usage_drow_ranger.lua | 57 ++ ability_item_usage_earth_spirit.lua | 4 +- ability_item_usage_earthshaker.lua | 11 +- ability_item_usage_ember_spirit.lua | 4 +- ability_item_usage_enchantress.lua | 112 ++- ability_item_usage_faceless_void.lua | 25 +- ability_item_usage_furion.lua | 25 +- ability_item_usage_hoodwink.lua | 24 +- ability_item_usage_jakiro.lua | 130 ++++ ability_item_usage_keeper_of_the_light.lua | 4 +- ability_item_usage_kunkka.lua | 65 +- ability_item_usage_leshrac.lua | 37 +- ability_item_usage_life_stealer.lua | 40 +- ability_item_usage_lina.lua | 10 + ability_item_usage_luna.lua | 2 +- ability_item_usage_magnataur.lua | 40 +- ability_item_usage_mirana.lua | 2 +- ability_item_usage_naga_siren.lua | 2 +- ability_item_usage_obsidian_destroyer.lua | 4 +- ability_item_usage_omniknight.lua | 47 ++ ability_item_usage_phantom_assassin.lua | 34 +- ability_item_usage_phantom_lancer.lua | 24 +- ability_item_usage_puck.lua | 125 +++ ability_item_usage_pudge.lua | 140 +++- ability_item_usage_pugna.lua | 23 +- ability_item_usage_queenofpain.lua | 2 +- ability_item_usage_shredder.lua | 2 +- ability_item_usage_slardar.lua | 2 +- ability_item_usage_slark.lua | 2 +- ability_item_usage_sniper.lua | 7 +- ability_item_usage_tidehunter.lua | 2 +- ability_item_usage_tinker.lua | 122 +++ ability_item_usage_troll_warlord.lua | 6 +- ability_item_usage_tusk.lua | 2 +- ability_item_usage_ursa.lua | 2 +- ability_item_usage_warlock.lua | 75 +- ability_item_usage_winter_wyvern.lua | 4 +- ability_item_usage_witch_doctor.lua | 2 +- bot_beastmaster.lua | 2 +- dev/DEV_item_purchase_normal.lua | 3 +- item_purchase_abaddon.lua | 9 +- item_purchase_abyssal_underlord.lua | 7 +- item_purchase_alchemist.lua | 7 +- item_purchase_ancient_apparition.lua | 8 +- item_purchase_antimage.lua | 3 +- item_purchase_arc_warden.lua | 7 +- item_purchase_bane.lua | 8 +- item_purchase_batrider.lua | 7 +- item_purchase_beastmaster.lua | 7 +- item_purchase_bloodseeker.lua | 7 +- item_purchase_bounty_hunter.lua | 9 +- item_purchase_brewmaster.lua | 7 +- item_purchase_bristleback.lua | 6 +- item_purchase_broodmother.lua | 9 +- item_purchase_centaur.lua | 7 +- item_purchase_chen.lua | 38 +- item_purchase_clinkz.lua | 11 +- item_purchase_crystal_maiden.lua | 18 +- item_purchase_dark_seer.lua | 7 +- item_purchase_dazzle.lua | 10 +- item_purchase_death_prophet.lua | 7 +- item_purchase_disruptor.lua | 10 +- item_purchase_doom_bringer.lua | 7 +- item_purchase_dragon_knight.lua | 7 +- item_purchase_drow_ranger.lua | 2 +- item_purchase_earth_spirit.lua | 10 +- item_purchase_earthshaker.lua | 10 +- item_purchase_elder_titan.lua | 10 +- item_purchase_ember_spirit.lua | 7 +- item_purchase_enchantress.lua | 7 +- item_purchase_enigma.lua | 7 +- item_purchase_faceless_void.lua | 7 +- item_purchase_gyrocopter.lua | 7 +- item_purchase_hoodwink.lua | 7 +- item_purchase_huskar.lua | 7 +- item_purchase_invoker.lua | 7 +- item_purchase_jakiro.lua | 10 +- item_purchase_juggernaut.lua | 10 +- item_purchase_keeper_of_the_light.lua | 10 +- item_purchase_legion_commander.lua | 7 +- item_purchase_leshrac.lua | 7 +- item_purchase_lich.lua | 8 +- item_purchase_life_stealer.lua | 7 +- item_purchase_lina.lua | 7 +- item_purchase_lion.lua | 8 +- item_purchase_luna.lua | 7 +- item_purchase_lycan.lua | 7 +- item_purchase_magnataur.lua | 7 +- item_purchase_medusa.lua | 15 +- item_purchase_mirana.lua | 7 +- item_purchase_monkey_king.lua | 7 +- item_purchase_naga_siren.lua | 8 +- item_purchase_necrolyte.lua | 7 +- item_purchase_nevermore.lua | 7 +- item_purchase_night_stalker.lua | 8 +- item_purchase_nyx_assassin.lua | 8 +- item_purchase_obsidian_destroyer.lua | 7 +- item_purchase_ogre_magi.lua | 8 +- item_purchase_omniknight.lua | 8 +- item_purchase_oracle.lua | 8 +- item_purchase_phantom_assassin.lua | 7 +- item_purchase_phantom_lancer.lua | 7 +- item_purchase_pudge.lua | 8 +- item_purchase_pugna.lua | 7 +- item_purchase_queenofpain.lua | 7 +- item_purchase_razor.lua | 7 +- item_purchase_riki.lua | 8 +- item_purchase_sand_king.lua | 8 +- item_purchase_shadow_demon.lua | 8 +- item_purchase_shadow_shaman.lua | 8 +- item_purchase_shredder.lua | 7 +- item_purchase_silencer.lua | 10 +- item_purchase_skeleton_king.lua | 7 +- item_purchase_skywrath_mage.lua | 8 +- item_purchase_slardar.lua | 8 +- item_purchase_slark.lua | 14 +- item_purchase_sniper.lua | 7 +- item_purchase_spectre.lua | 12 +- item_purchase_spirit_breaker.lua | 8 +- item_purchase_sven.lua | 7 +- item_purchase_templar_assassin.lua | 7 +- item_purchase_terrorblade.lua | 7 +- item_purchase_tidehunter.lua | 7 +- item_purchase_tiny.lua | 7 +- item_purchase_treant.lua | 8 +- item_purchase_troll_warlord.lua | 7 +- item_purchase_tusk.lua | 8 +- item_purchase_undying.lua | 8 +- item_purchase_ursa.lua | 7 +- item_purchase_vengefulspirit.lua | 8 +- item_purchase_venomancer.lua | 8 +- item_purchase_viper.lua | 7 +- item_purchase_warlock.lua | 1 - item_purchase_weaver.lua | 7 +- item_purchase_windrunner.lua | 7 +- item_purchase_winter_wyvern.lua | 8 +- item_purchase_witch_doctor.lua | 8 +- item_purchase_zuus.lua | 7 +- mode_rune_generic.lua | 96 +-- util/AbilityAbstraction.lua | 839 +++++++++++++++++---- util/ItemPurchaseSystem.lua | 18 +- util/ItemUsageSystem.lua | 120 +-- util/PushUtility.lua | 33 +- 159 files changed, 2884 insertions(+), 926 deletions(-) create mode 100644 ability_item_usage_puck.lua create mode 100644 ability_item_usage_tinker.lua diff --git a/ability_item_usage_abaddon.lua b/ability_item_usage_abaddon.lua index af264ff6..0b1fc350 100644 --- a/ability_item_usage_abaddon.lua +++ b/ability_item_usage_abaddon.lua @@ -119,7 +119,7 @@ Consider[1]=function() -- TODO: lv 25 AOE mist coil local HeroHealth=10000 local CreepHealth=10000 - local allys = npcBot:GetNearbyHeroes( CastRange+300, false, BOT_MODE_NONE ); + local allys = npcBot:GetNearbyHeroes( CastRange+150, false, BOT_MODE_NONE ); for _,hero in pairs (allys) do if (hero==npcBot) @@ -128,7 +128,7 @@ Consider[1]=function() -- TODO: lv 25 AOE mist coil end end local WeakestAlly,AllyHealth=utility.GetWeakestUnit(allys) - local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + local enemys = npcBot:GetNearbyHeroes(CastRange+150,true,BOT_MODE_NONE) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) @@ -149,18 +149,7 @@ Consider[1]=function() -- TODO: lv 25 AOE mist coil end end end - - -- If we're seriously retreating, try to suicide - if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) - then - if ( #enemys>=1 and npcBot:WasRecentlyDamagedByAnyHero(2.0) and npcBot:GetHealth() <= SelfDamage) - then - if ( CanCast[abilityNumber]( enemys[1] )) - then - return BOT_ACTION_DESIRE_HIGH, enemys[1]; - end - end - end + -------------------------------------- -- Mode based usage -------------------------------------- @@ -186,6 +175,12 @@ Consider[1]=function() -- TODO: lv 25 AOE mist coil end end end + + if npcBot:HasModifier("modifier_abaddon_borrowed_time") then + if WeakestEnemy ~= nil then + return BOT_ACTION_DESIRE_MODERATE, WeakestEnemy + end + end -- If we're going after someone if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or diff --git a/ability_item_usage_alchemist.lua b/ability_item_usage_alchemist.lua index b1d86922..76cd2392 100644 --- a/ability_item_usage_alchemist.lua +++ b/ability_item_usage_alchemist.lua @@ -73,7 +73,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.CanCastNoTarget} +local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.CanCastNoTarget,utility.NCanCast} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -109,7 +109,9 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - + if not ability:IsFullyCastable() then + return 0 + end local CastRange = ability:GetCastRange(); local Damage = ability:GetAbilityDamage(); local Radius = ability:GetAOERadius() @@ -518,7 +520,7 @@ Consider[6]=function() for _,npcEnemy in pairs( enemys )do if ( npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) ) then if ( CanCast[abilityNumber]( npcEnemy ) and not enemyDisabled(npcEnemy)) then - if (GetUnitToUnitDistance(npcBot,npcEnemy)>CastRange-100 and GetUnitToUnitDistance(npcBot,npcEnemy)3 and TimeSinceCast<5) + if (GetUnitToUnitDistance(npcBot,npcEnemy)>CastRange-100 and GetUnitToUnitDistance(npcBot,npcEnemy)2 and TimeSinceCast<5) or npcEnemy:GetHealth()/npcEnemy:GetMaxHealth() <= 0.2 then return BOT_ACTION_DESIRE_HIGH,npcEnemy end diff --git a/ability_item_usage_ancient_apparition.lua b/ability_item_usage_ancient_apparition.lua index a32cc6bc..84ffe08e 100644 --- a/ability_item_usage_ancient_apparition.lua +++ b/ability_item_usage_ancient_apparition.lua @@ -327,7 +327,7 @@ Consider[3]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_antimage.lua b/ability_item_usage_antimage.lua index 21b2cf17..be9c2af7 100644 --- a/ability_item_usage_antimage.lua +++ b/ability_item_usage_antimage.lua @@ -9,6 +9,15 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +-- for k,v in pairs(GetUnitList(UNIT_LIST_ALLIED_WARDS)) do +-- print("unit: "..v:GetUnitName()..", "..AbilityExtensions:ToStringVector(v:GetLocation())) +-- end +-- for k,v in pairs(GetUnitList(UNIT_LIST_ENEMY_WARDS)) do +-- print("unit: "..v:GetUnitName()..", "..AbilityExtensions:ToStringVector(v:GetLocation())) +-- end +-- for k,v in pairs(GetUnitList(UNIT_LIST_ENEMY_HEROES)) do +-- print("unit: "..v:GetUnitName()..", "..AbilityExtensions:ToStringVector(v:GetLocation())) +-- end local debugmode=false local npcBot = GetBot() @@ -95,7 +104,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_arc_warden.lua b/ability_item_usage_arc_warden.lua index 2de99752..0ae9baa4 100644 --- a/ability_item_usage_arc_warden.lua +++ b/ability_item_usage_arc_warden.lua @@ -149,17 +149,17 @@ Consider[1]=function() -------------------------------------- --protect myself local enemys2 = npcBot:GetNearbyHeroes( 400, true, BOT_MODE_NONE ); - --[[ If we're seriously retreating, see if we can land a stun on someone who's damaged us recently - if ( (npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) or #enemys2>0) - then - for _,npcEnemy in pairs( enemys ) - do - if ( (npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) and CanCast[abilityNumber]( npcEnemy )) or GetUnitToUnitDistance(npcBot,npcEnemy)<400) - then - return BOT_ACTION_DESIRE_HIGH, npcEnemy; - end - end - end]] + -- --[[ If we're seriously retreating, see if we can land a stun on someone who's damaged us recently + -- if ( (npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) or #enemys2>0) + -- then + -- for _,npcEnemy in pairs( enemys ) + -- do + -- if ( (npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) and CanCast[abilityNumber]( npcEnemy )) or GetUnitToUnitDistance(npcBot,npcEnemy)<400) + -- then + -- return BOT_ACTION_DESIRE_HIGH, npcEnemy; + -- end + -- end + -- end]] -- If my mana is enough,use it at enemy if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) @@ -475,18 +475,24 @@ Consider[4]=function() local CastPoint = ability:GetCastPoint(); local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); - local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + local enemys = npcBot:GetNearbyHeroes(800,true,BOT_MODE_NONE) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) - local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) + local creeps = npcBot:GetNearbyCreeps(800,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) -------------------------------------- -- Global high-priorty usage -------------------------------------- + + -- Stop making a huge bounty for the enemy + if (npcBot:GetHealth() <= 450 or HealthPercentage <= 0.3) and (npcBot:WasRecentlyDamagedByAnyHero(1.5) or AbilityExtensions:CanHardlyMove(npcBot) or not AbilityExtensions:CanMove(npcBot)) and not AbilityExtensions:Outnumber(allys, enemys) then + return 0 + end + -- If we're in a teamfight, use it on the scariest enemy local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes( 1000, false, BOT_MODE_ATTACK ); if ( #tableNearbyAttackingAlliedHeroes >= 2 ) then - return BOT_ACTION_DESIRE_HIGH, npcMostDangerousEnemy; + return BOT_ACTION_DESIRE_HIGH end -------------------------------------- -- Mode based usage diff --git a/ability_item_usage_axe.lua b/ability_item_usage_axe.lua index 6eec2c34..a070df2b 100644 --- a/ability_item_usage_axe.lua +++ b/ability_item_usage_axe.lua @@ -63,7 +63,6 @@ local TalentTree={ -- check skill build vs current level utility.CheckAbilityBuild(AbilityToLevelUp) -AbilityExtensions:DebugArray(AbilityToLevelUp) function AbilityLevelUpThink() ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp,TalentTree) diff --git a/ability_item_usage_bane.lua b/ability_item_usage_bane.lua index 1ddee3a0..950121be 100644 --- a/ability_item_usage_bane.lua +++ b/ability_item_usage_bane.lua @@ -16,7 +16,7 @@ local Talents ={} local Abilities ={} local AbilitiesReal ={} -ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) +ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) local AbilityToLevelUp= { @@ -233,7 +233,7 @@ Consider[2]=function() local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) - local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(AbilityExtensions:Filter(enemys, function(t) return not AbilityExtensions:HasAbilityRetargetModifier(t) end)) local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) -------------------------------------- @@ -454,7 +454,7 @@ Consider[4]=function() -- Check for a channeling enemy for _,npcEnemy in pairs( enemys ) do - if ( npcEnemy:IsChanneling() and CanCast[abilityNumber]( npcEnemy )) + if ( npcEnemy:IsChanneling() and CanCast[abilityNumber]( npcEnemy ) and not AbilityExtensions:HasAbilityRetargetModifier(npcEnemy)) then return BOT_ACTION_DESIRE_HIGH, npcEnemy end @@ -523,6 +523,10 @@ Consider[4]=function() end end end]] + + if AbilityExtensions:IsRetreating(npcBot) and #enemys == 0 and not AbilityExtensions:HasAbilityRetargetModifier(enemys[1]) then + return BOT_ACTION_DESIRE_HIGH, enemys[0] + end -- If we're going after someone if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or @@ -541,12 +545,46 @@ Consider[4]=function() end end + local disabledAllies = AbilityExtensions:Filter(allys, function(t) return AbilityExtensions:IsSeverlyDisabled(t) and not t:IsChanneling() end) + disabledAllies = AbilityExtensions:SortByMinFirst(disabledAllies, function(t) return t:GetHealth() end) + if #disabledAllies ~= 0 then + return BOT_ACTION_DESIRE_MODERATE, disabledAllies[1] + end + + disabledAllies = AbilityExtensions:Filter(allys, function(t) + local b = t:GetIncomingTrackingProjectiles() + return AbilityExtensions:Any(b, function(s) + return GetUnitToLocationDistance(t, s.location) <= 400 and not s.is_attack + end) + end) + if disabledAllies ~= 0 then + disabledAllies = AbilityExtensions:SortByMinFirst(disabledAllies, function(t) return t:GetHealth() end) + return BOT_ACTION_DESIRE_MODERATE, disabledAllies[1] + end + return BOT_ACTION_DESIRE_NONE, 0; end Consider[5]=function() - return BOT_ACTION_DESIRE_NONE, 0; + local enemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1200, true, BOT_MODE_NONE) + local nightmaredEnemies = AbilityExtensions:Filter(enemies, function(t) return t:HasModifier("modifier_bane_nightmare") end) + local friends = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1200, false, BOT_MODE_NONE) + local nightmaredFriends = AbilityExtensions:Filter(friends, function(t) return t:HasModifier("modifier_bane_nightmare") end) + if #nightmaredEnemies ~= 0 then + if #enemies == 1 and #friends >= 2 and AbilityExtensions:GetModifierRemainingDuration(nightmaredFriends[1], "modifier_bane_nightmare") <= 4 + or AbilityExtensions:All(nightmaredEnemies, function(t) return AbilityExtensions:GetHealthPercent(t) <= 0.3 and AbilityExtensions:GetModifierRemainingDuration(nightmaredFriends[1], "modifier_bane_nightmare") <= 4 end) and AbilityExtensions:All(friends, function(t) return AbilityExtensions:GetHealthPercent(t) >= 0.5 end) then + return BOT_ACTION_DESIRE_HIGH + end + end + if #nightmaredFriends ~= 0 then + if AbilityExtensions:All(nightmaredFriends, function(t) + return AbilityExtensions:GetHealthPercent(t) >= 0.3 + end) or AbilityExtensions:All(nightmaredFriends, function(t) return #t:GetIncomingTrackingProjectiles() == 0 end) and #enemies == 0 then + return BOT_ACTION_DESIRE_HIGH + end + end + return BOT_ACTION_DESIRE_NONE end AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) diff --git a/ability_item_usage_bristleback.lua b/ability_item_usage_bristleback.lua index ffbc4d5b..d6b16d47 100644 --- a/ability_item_usage_bristleback.lua +++ b/ability_item_usage_bristleback.lua @@ -118,7 +118,26 @@ Consider[1]=function() local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) - + if npcBot:HasScepter() then + local enemies = npcBot:GetNearbyHeroes(CastRange, true, BOT_MODE_NONE) + enemies = AbilityExtensions:Filter(enemies, function(t) + local m = t:GetModifierByName("modifier_bristleback_viscous_nasal_goo") + if m ~= -1 and t:GetModifierStackCount(m) >= 6 and t:GetModifierRemainingDuration(m) >= 2.5 then + return false + end + return true + end) + if AbilityExtensions:IsAttackingEnemies(npcBot) or AbilityExtensions:IsRetreating(npcBot) then + if #enemies == 0 then + return 0 + end + return #enemies >= 2 and AbilityExtensions:GetManaPercent(npcBot) >= 0.3 + or #enemies == 1 and AbilityExtensions:GetManaPercent(npcBot) >= 0.6 + or npcBot:WasRecentlyDamagedByAnyHero(1.5) + end + return 0 + end + -- If we're in a teamfight, use it on the scariest enemy local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes( 1000, false, BOT_MODE_ATTACK ); if ( #tableNearbyAttackingAlliedHeroes >= 2 ) diff --git a/ability_item_usage_broodmother.lua b/ability_item_usage_broodmother.lua index d17db0b2..801e8284 100644 --- a/ability_item_usage_broodmother.lua +++ b/ability_item_usage_broodmother.lua @@ -19,24 +19,24 @@ ability_item_usage_generic.InitAbility(Abilities, AbilitiesReal, Talents) local AbilityToLevelUp = { - Abilities[2], - Abilities[1], Abilities[1], Abilities[2], - Abilities[1], - Abilities[5], - Abilities[1], + Abilities[3], Abilities[2], Abilities[2], - "talent", - Abilities[3], - Abilities[5], + Abilities[4], + Abilities[2], Abilities[3], Abilities[3], "talent", Abilities[3], + Abilities[4], + Abilities[1], + Abilities[1], + "talent", + Abilities[1], "nil", - Abilities[5], + Abilities[4], "nil", "talent", "nil", @@ -338,6 +338,71 @@ Consider[2] = function() return BOT_ACTION_DESIRE_NONE, 0; +end +local ability2InfoTable = {} +Consider[2] = AbilityExtensions:AddCooldownToChargeAbility(Consider[2], AbilitiesReal[2], ability2InfoTable, 0.8) + +-- copied from chen_penance +Consider[3]=function() + local abilityNumber=3 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = ability:GetCastRange(); + local Damage = 0; + local CastPoint = ability:GetCastPoint(); + + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + -------------------------------------- + -- Global high-priorty usage + -------------------------------------- + + -------------------------------------- + -- Mode based usage + -------------------------------------- + --protect myself + local enemys2 = npcBot:GetNearbyHeroes( 400, true, BOT_MODE_NONE ); + -- If we're seriously retreating, see if we can land a stun on someone who's damaged us recently + if ( (npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) or #enemys2>0) + then + for _,npcEnemy in pairs( enemys ) + do + if ( (npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) and CanCast[abilityNumber]( npcEnemy )) or GetUnitToUnitDistance(npcBot,npcEnemy)<400) + then + return BOT_ACTION_DESIRE_HIGH, npcEnemy; + end + end + end + + -- If we're going after someone + if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or + npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or + npcBot:GetActiveMode() == BOT_MODE_ATTACK ) + then + local npcEnemy = npcBot:GetTarget(); + + if ( npcEnemy ~= nil ) + then + if ( CanCast[abilityNumber]( npcEnemy ) and GetUnitToUnitDistance(npcBot,npcEnemy)< CastRange + 75*#allys) + then + return BOT_ACTION_DESIRE_MODERATE, npcEnemy + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + end Consider[1] = function() @@ -418,7 +483,10 @@ function AbilityUsageThink() then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal, cast) end - ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + if index == 2 then + AbilityExtensions:GetUsedAbilityInfo(AbilitiesReal[2], ability2InfoTable, target) + end end function CourierUsageThink() diff --git a/ability_item_usage_centaur.lua b/ability_item_usage_centaur.lua index 67205460..f24be452 100644 --- a/ability_item_usage_centaur.lua +++ b/ability_item_usage_centaur.lua @@ -236,6 +236,9 @@ Consider[2]=function() local CastRange = ability:GetCastRange(); local Damage = ability:GetAbilityDamage(); + if HealthPercentage <= 0.2 + npcBot:GetActualIncomingDamage(Damage, DAMAGE_TYPE_MAGICAL) then + return 0 + end local HeroHealth=10000 local CreepHealth=10000 diff --git a/ability_item_usage_chen.lua b/ability_item_usage_chen.lua index 9b4b17d4..1812c1ac 100644 --- a/ability_item_usage_chen.lua +++ b/ability_item_usage_chen.lua @@ -147,105 +147,105 @@ Consider[1]=function() end -Consider[2]=function() - local abilityNumber=2 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; - - if not ability:IsFullyCastable() then - return BOT_ACTION_DESIRE_NONE, 0; - end - - local CastRange = ability:GetCastRange(); - --local Damage = (ability:GetSpecialValueInt("damage_max")+ability:GetSpecialValueInt("damage_min"))*0.5 - local Heal = (ability:GetSpecialValueInt("heal_max")+ability:GetSpecialValueInt("heal_min"))*0.5 - - local HeroHealth=10000 - local CreepHealth=10000 - local allys = npcBot:GetNearbyHeroes( CastRange+300, false, BOT_MODE_NONE ); - local WeakestAlly,AllyHealth=utility.GetWeakestUnit(allys) - local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) - local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) - local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) - local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) - -------------------------------------- - -- Global high-priorty usage - -------------------------------------- - - -------------------------------------- - -- Mode based usage - -------------------------------------- - -- If we're seriously retreating - if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) - then - if ( HealthPercentage<=0.5 and npcBot:WasRecentlyDamagedByAnyHero(2.0)) - then - if ( CanCast[abilityNumber]( npcBot )) - then - return BOT_ACTION_DESIRE_HIGH, npcBot - end - end - end - - --teamfightUsing - if( npcBot:GetActiveMode() == BOT_MODE_ROAM or - npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or - npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or - npcBot:GetActiveMode() == BOT_MODE_ATTACK ) - then - if (WeakestAlly~=nil) - then - if(AllyHealth/WeakestAlly:GetMaxHealth()<0.3+0.2*ManaPercentage) - then - return BOT_ACTION_DESIRE_MODERATE,WeakestAlly - end - end +-- Consider[2]=function() +-- local abilityNumber=2 +-- -------------------------------------- +-- -- Generic Variable Setting +-- -------------------------------------- +-- local ability=AbilitiesReal[abilityNumber]; + +-- if not ability:IsFullyCastable() then +-- return BOT_ACTION_DESIRE_NONE, 0; +-- end + +-- local CastRange = ability:GetCastRange(); +-- --local Damage = (ability:GetSpecialValueInt("damage_max")+ability:GetSpecialValueInt("damage_min"))*0.5 +-- local Heal = (ability:GetSpecialValueInt("heal_max")+ability:GetSpecialValueInt("heal_min"))*0.5 + +-- local HeroHealth=10000 +-- local CreepHealth=10000 +-- local allys = npcBot:GetNearbyHeroes( CastRange+300, false, BOT_MODE_NONE ); +-- local WeakestAlly,AllyHealth=utility.GetWeakestUnit(allys) +-- local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) +-- local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) +-- local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) +-- local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) +-- -------------------------------------- +-- -- Global high-priorty usage +-- -------------------------------------- + +-- -------------------------------------- +-- -- Mode based usage +-- -------------------------------------- +-- -- If we're seriously retreating +-- if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) +-- then +-- if ( HealthPercentage<=0.5 and npcBot:WasRecentlyDamagedByAnyHero(2.0)) +-- then +-- if ( CanCast[abilityNumber]( npcBot )) +-- then +-- return BOT_ACTION_DESIRE_HIGH, npcBot +-- end +-- end +-- end + +-- --teamfightUsing +-- if( npcBot:GetActiveMode() == BOT_MODE_ROAM or +-- npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or +-- npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or +-- npcBot:GetActiveMode() == BOT_MODE_ATTACK ) +-- then +-- if (WeakestAlly~=nil) +-- then +-- if(AllyHealth/WeakestAlly:GetMaxHealth()<0.3+0.2*ManaPercentage) +-- then +-- return BOT_ACTION_DESIRE_MODERATE,WeakestAlly +-- end +-- end - for _,npcTarget in pairs( allys ) - do - local enemys2 = npcTarget:GetNearbyHeroes(600,true,BOT_MODE_NONE) - local healingFactor=0.2+#enemys2*0.05+0.2*ManaPercentage - if(enemyDisabled(npcTarget)) - then - healingFactor=healingFactor+0.1 - end +-- for _,npcTarget in pairs( allys ) +-- do +-- local enemys2 = npcTarget:GetNearbyHeroes(600,true,BOT_MODE_NONE) +-- local healingFactor=0.2+#enemys2*0.05+0.2*ManaPercentage +-- if(enemyDisabled(npcTarget)) +-- then +-- healingFactor=healingFactor+0.1 +-- end - if(npcTarget:GetHealth()/npcTarget:GetMaxHealth()0) then - local nAllyHP = npcAlly:GetHealth(); - if nAllyHP < nLowestHealth and npcAlly:GetHealth() / npcAlly:GetMaxHealth() < 0.25 and npcAlly:WasRecentlyDamagedByAnyHero(3.0) - then - nLowestHealth = nAllyHP; - lowHpAlly = npcAlly; - end + return desire,targetloc end end - if ( lowHpAlly ~= nil ) - then - return BOT_ACTION_DESIRE_MODERATE, lowHpAlly; - end - - local desire,targetloc=ConsiderRecall() - if(desire>0) - then - return desire,targetloc - end - return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_crystal_maiden.lua b/ability_item_usage_crystal_maiden.lua index 53499cfa..e721ea3e 100644 --- a/ability_item_usage_crystal_maiden.lua +++ b/ability_item_usage_crystal_maiden.lua @@ -368,6 +368,7 @@ Consider[2]=function() end + Consider[4]=function() local abilityNumber=4 -------------------------------------- @@ -388,6 +389,7 @@ Consider[4]=function() local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); local enemys = npcBot:GetNearbyHeroes(Radius,true,BOT_MODE_NONE) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + -------------------------------------- -- Global high-priorty usage -------------------------------------- @@ -432,11 +434,30 @@ end AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) +local freezingFieldHitSomeoneTimer function AbilityUsageThink() - -- Check if we're already using an ability if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) - then + then + if npcBot:IsChanneling() and npcBot:GetCurrentActiveAbility() == AbilitiesReal[4] then + --if npcBot:HasModifier("modifier_crystal_maiden_freezing_field") then + local glimmer = AbilityExtensions:GetAvailableItem(npcBot, "item_glimmer_cape") + if glimmer and glimmer:IsFullyCastable() then + npcBot:ActionImmediate_UseAbilityOnEntity(glimmer, npcBot) + end + local enemies = npcBot:GetNearbyHeroes(AbilitiesReal[4]:GetAOERadius(), true, BOT_MODE_NONE) + if #enemies > 0 or freezingFieldHitSomeoneTimer == nil then + freezingFieldHitSomeoneTimer = DotaTime() + else + if DotaTime() - freezingFieldHitSomeoneTimer >= 1.5 and #npcBot:GetNearbyHeroes(AbilitiesReal[4]:GetAOERadius() + 200, false, BOT_MODE_NONE) > 0 then + local location = npcBot:GetLocation() + RandomVector(50) + npcBot:Action_ClearActions(true) + else + end + end + else + freezingFieldHitSomeoneTimer = nil + end return end @@ -452,6 +473,7 @@ function AbilityUsageThink() ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + end function CourierUsageThink() diff --git a/ability_item_usage_dazzle.lua b/ability_item_usage_dazzle.lua index e60a601d..f6a536de 100644 --- a/ability_item_usage_dazzle.lua +++ b/ability_item_usage_dazzle.lua @@ -21,20 +21,20 @@ local AbilityToLevelUp= { Abilities[1], Abilities[3], - Abilities[2], - Abilities[1], Abilities[1], Abilities[3], - Abilities[3], - Abilities[3], - Abilities[4], - "talent", + Abilities[1], Abilities[2], + Abilities[4], + Abilities[3], Abilities[2], + "talent", + Abilities[3], + Abilities[1], Abilities[2], Abilities[4], "talent", - Abilities[1], + Abilities[2], "nil", Abilities[4], "nil", diff --git a/ability_item_usage_death_prophet.lua b/ability_item_usage_death_prophet.lua index aad6d1d4..fe090600 100644 --- a/ability_item_usage_death_prophet.lua +++ b/ability_item_usage_death_prophet.lua @@ -217,6 +217,7 @@ local abilityNumber=2 local CreepHealth=10000 local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + enemys = AbilityExtensions:Filter(enemys, function(t) return not t:IsStunned() and not t:IsSilenced() and not t:IsInvulnerable() and not t:IsMagicImmune() end) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) @@ -239,8 +240,7 @@ local abilityNumber=2 -- Check for a channeling enemy for _,npcEnemy in pairs( enemys ) do - if ( npcEnemy:IsChanneling() and CanCast[abilityNumber]( npcEnemy ) and not npcEnemy:HasModifier("modifier_teleporting") and not npcEnemy:HasModifier("modifier_boots_of_travel_incoming")) - then + if AbilityExtensions:IsChannelingAbility(npcEnemy) and CanCast[abilityNumber](npcEnemy) then return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetExtrapolatedLocation( CastPoint ) end end @@ -472,6 +472,8 @@ Consider[4]=function() end AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) +local lastAbilityIndex +local lastAbilityTarget function AbilityUsageThink() @@ -480,6 +482,8 @@ function AbilityUsageThink() then return end + lastAbilityIndex = nil + lastAbilityTarget = nil ComboMana=GetComboMana() AttackRange=npcBot:GetAttackRange() @@ -492,7 +496,7 @@ function AbilityUsageThink() then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end - ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + lastAbilityIndex, lastAbilityTarget = ability_item_usage_generic.UseAbility(AbilitiesReal,cast) end function CourierUsageThink() diff --git a/ability_item_usage_doom_bringer.lua b/ability_item_usage_doom_bringer.lua index 1c8f5c42..94d23824 100644 --- a/ability_item_usage_doom_bringer.lua +++ b/ability_item_usage_doom_bringer.lua @@ -117,21 +117,18 @@ Consider[1]=function() local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) local StrongstCreep,CreepHealth=utility.GetStrongestUnit(creeps) - if ( not npcBot:HasModifier("modifier_doom_bringer_devour") ) + if(CanCast[abilityNumber]( StrongstCreep )) then - if(CanCast[abilityNumber]( StrongstCreep )) + return BOT_ACTION_DESIRE_HIGH, StrongstCreep + end + + for _,npcEnemy in pairs( creeps ) + do + if ( CanCast[abilityNumber]( npcEnemy ) ) then - return BOT_ACTION_DESIRE_HIGH, StrongstCreep; - end - - for _,npcEnemy in pairs( creeps ) - do - if ( CanCast[abilityNumber]( npcEnemy ) ) - then - return BOT_ACTION_DESIRE_HIGH, npcEnemy; - end + return BOT_ACTION_DESIRE_HIGH, npcEnemy end - end + end return BOT_ACTION_DESIRE_NONE, 0; @@ -211,7 +208,7 @@ Consider[3]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_dragon_knight.lua b/ability_item_usage_dragon_knight.lua index 824ab679..396dbf17 100644 --- a/ability_item_usage_dragon_knight.lua +++ b/ability_item_usage_dragon_knight.lua @@ -115,7 +115,9 @@ Consider[1]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if + -- HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or + (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana) then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy:GetLocation(); end @@ -311,6 +313,133 @@ Consider[2]=function() return BOT_ACTION_DESIRE_NONE, 0 end +-- copied from abyssal_underlord_firestorm +Consider[4]=function() --Location AOE Example + + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = ability:GetCastRange(); + local Damage = ability:GetAbilityDamage(); + local Radius = ability:GetAOERadius() + local CastPoint = ability:GetCastPoint(); + + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + + -------------------------------------- + -- Global high-priorty usage + -------------------------------------- + --try to kill enemy hero + if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + then + return BOT_ACTION_DESIRE_HIGH,WeakestEnemy:GetExtrapolatedLocation(CastPoint); + end + end + end + end + -------------------------------------- + -- Mode based usage + -------------------------------------- + -- If we're farming and can kill 3+ creeps with LSA + if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) then + local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), CastRange, Radius, 0, Damage ); + + if ( locationAoE.count >= 3 ) then + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + end + end + + -- If my mana is enough,use it at enemy + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if(ManaPercentage>0.6) + then + local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), CastRange, Radius, 0, Damage ); + if ( locationAoE.count >= 4 ) then + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + end + end + end + + -- If my mana is enough,use it at enemy + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if(ManaPercentage>0.6 and ability:GetLevel()>=2 ) + then + local locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, 0, Damage ); + if ( locationAoE.count >= 2 ) then + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + end + + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + return BOT_ACTION_DESIRE_LOW,WeakestEnemy:GetExtrapolatedLocation(CastPoint); + end + end + end + end + + -- If we're pushing or defending a lane and can hit 4+ creeps, go for it + if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or + npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or + npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) + then + local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); + + if ( locationAoE.count >= 4 ) + then + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + end + end + + -- If we're going after someone + if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or + npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or + npcBot:GetActiveMode() == BOT_MODE_ATTACK) + then + local locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); + if ( locationAoE.count >= 2 ) then + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + end + + local npcEnemy = npcBot:GetTarget(); + + if ( npcEnemy ~= nil ) + then + if ( CanCast[abilityNumber]( npcEnemy ) ) + then + return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetExtrapolatedLocation(CastPoint); + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + +end + Consider[5]=function() local abilityNumber=5 diff --git a/ability_item_usage_drow_ranger.lua b/ability_item_usage_drow_ranger.lua index 7ac5b6e0..1c971930 100644 --- a/ability_item_usage_drow_ranger.lua +++ b/ability_item_usage_drow_ranger.lua @@ -196,6 +196,63 @@ Consider[1]=function() end +-- copied and modified from enchantress_impetus +Consider[1] = function() + local abilityNumber=1 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then + return 0 + end + + local CastRange = ability:GetCastRange() + local enemys = npcBot:GetNearbyHeroes(CastRange+100,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + + local function UseAt(target) + if not CanCast[abilityNumber](target) then + return false + end + if target:IsHero() then + local modifier = target:GetModifierByName("modifier_drow_ranger_frost_arrows_slow") + if modifier ~= nil and target:GetModifierRemainingDuration(modifier) > npcBot:GetAttackSpeed()/100*0.7/1.7 + 0.2 then + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 + end + if AbilityExtensions:MustBeIllusion(npcBot, target) then + return (AbilityExtensions:GetManaPercent(npcBot) >= 0.8 or AbilityExtensions:GetHealthPercent(target) <= 0.4) and (GetUnitToUnitDistance(npcBot, target) >= 300 or npcBot:GetLevel() < 6) + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.4 or AbilityExtensions:GetManaPercent(npcBot) >= 0.2 and (GetUnitToUnitDistance(npcBot, target) >= 300 or npcBot:GetLevel() < 6) + end + elseif target:IsBuilding() then + return false + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 + end + + end + + if AbilityExtensions:NotRetreating(npcBot) then + local target = npcBot:GetAttackTarget() + if target == nil then + if WeakestEnemy ~= nil then + local b = UseAt(WeakestEnemy) + if b then + return BOT_ACTION_DESIRE_HIGH, WeakestEnemy + else + return false + end + end + else + return UseAt(target) + end + end + return false +end +Consider[1] = AbilityExtensions:ToggleFunctionToAutoCast(npcBot, Consider[1], AbilitiesReal[1]) + Consider[2]=function() local abilityNumber=2 -------------------------------------- diff --git a/ability_item_usage_earth_spirit.lua b/ability_item_usage_earth_spirit.lua index e12b5894..1821e1fc 100644 --- a/ability_item_usage_earth_spirit.lua +++ b/ability_item_usage_earth_spirit.lua @@ -146,7 +146,7 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end @@ -345,7 +345,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_earthshaker.lua b/ability_item_usage_earthshaker.lua index 74024674..6f14c3a7 100644 --- a/ability_item_usage_earthshaker.lua +++ b/ability_item_usage_earthshaker.lua @@ -250,7 +250,7 @@ Consider[2]=function() -------------------------------------- -- Mode based usage -------------------------------------- - if(npcBot:HasScepter() or npcBot:HasModifier("modifier_-- item_ultimate_scepter")) + if(npcBot:HasScepter() or npcBot:HasModifier("modifier_item_ultimate_scepter")) then -- If we're seriously retreating, see if we can land a stun on someone who's damaged us recently if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) @@ -399,7 +399,10 @@ Consider[4]=function() local count=#enemys+#creeps local Damage = ability:GetSpecialValueInt("AbilityDamage")+count*ability:GetSpecialValueInt("echo_slam_echo_damage") - + local checkIfThereAreManyEnemies = AbilityExtensions:Filter(enemys, function(t) return AbilityExtensions:MayNotBeIllusion(npcBot, t) end) + if #checkIfThereAreManyEnemies >= 3 then + return #checkIfThereAreManyEnemies*0.2 + end -- If we're going after someone if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or @@ -428,7 +431,7 @@ Consider[4]=function() then if ( CanCast[abilityNumber]( WeakestEnemy )) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetUltDamage(WeakestEnemy),DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if (#enemys > 1 or not WeakestEnemy:WasRecentlyDamagedByAnyHero(1.5)) and (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetUltDamage(WeakestEnemy),DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) then npcBot:Action_UseAbilityOnLocation( blink,WeakestEnemy:GetLocation() ); return 0 @@ -447,7 +450,7 @@ Consider[4]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)) + if (#enemys > 1 or not WeakestEnemy:WasRecentlyDamagedByAnyHero(1.5)) and (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)) then return BOT_ACTION_DESIRE_MODERATE end diff --git a/ability_item_usage_ember_spirit.lua b/ability_item_usage_ember_spirit.lua index dbd01fa7..a5e8144d 100644 --- a/ability_item_usage_ember_spirit.lua +++ b/ability_item_usage_ember_spirit.lua @@ -311,7 +311,7 @@ Consider[2]=function() --Target AOE Ability Example -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end @@ -515,7 +515,7 @@ Consider[4]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_enchantress.lua b/ability_item_usage_enchantress.lua index 80528167..b9d44511 100644 --- a/ability_item_usage_enchantress.lua +++ b/ability_item_usage_enchantress.lua @@ -74,7 +74,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast} +local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.UCanCast} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -134,11 +134,21 @@ Consider[2]=function() -------------------------------------- -- Mode based usage -------------------------------------- + + -- dispell + local buffedEnemies = AbilityExtensions:Filter(enemys, function(t) return CanCast[2](t) end) + buffedEnemies = AbilityExtensions:Map(enemys, function(t) return {t, AbilityExtensions:IndexOfBasicDispellablePositiveModifier(t)} end) + buffedEnemies = AbilityExtensions:Filter(buffedEnemies, function(t) return t[2] ~= -1 end) + buffedEnemies = AbilityExtensions:SortByMinFirst(buffedEnemies, function(t) return t[2] end) + if AbilityExtensions:Any(buffedEnemies) then + return BOT_ACTION_DESIRE_MODERATE, buffedEnemies[1][1] + end + -- Find neural creeps if(ManaPercentage>=0.4) then for k,creep in pairs(creepsNeutral) do - if(IsGoodNeutralCreeps(creep) or (creep:IsAncientCreep() and npcBot:HasScepter())) + if(IsGoodNeutralCreeps(creep) and not creep:WasRecentlyDamagedByAnyHero(1.5) or (creep:IsAncientCreep() and npcBot:HasScepter())) then return BOT_ACTION_DESIRE_MODERATE, creep; end @@ -261,7 +271,7 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end @@ -282,7 +292,7 @@ Consider[1]=function() local t=npcBot:GetAttackTarget() if(t~=nil) then - if (t:IsHero() or t:IsTower()) or AbilityExtensions:MustBeIllusions(npcBot, t) and (AbilityExtensions:GetManaPercent(npcBot) >= 0.8) + if (t:IsHero() or t:IsTower()) or AbilityExtensions:MustBeIllusion(npcBot, t) and (AbilityExtensions:GetManaPercent(npcBot) >= 0.8) then ability:ToggleAutoCast() return BOT_ACTION_DESIRE_NONE, 0; @@ -352,7 +362,101 @@ Consider[1]=function() end +Consider[1] = function() + local abilityNumber=1 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() then + return 0 + end + + local CastRange = ability:GetCastRange() + local enemys = npcBot:GetNearbyHeroes(CastRange+100,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + + local function UseAt(target) + if not CanCast[abilityNumber](target) then + return false + end + if npcBot:HasModifier("modifier_enchantress_bunny_hop") and target:IsHero() then + return true + end + if target:IsHero() then + if AbilityExtensions:MustBeIllusion(npcBot, target) then + return (AbilityExtensions:GetManaPercent(npcBot) >= 0.6 or AbilityExtensions:GetHealthPercent(target) <= 0.4) and GetUnitToUnitDistance(npcBot, target) >= 400 + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.4 or GetUnitToUnitDistance(npcBot, target) >= 250 + end + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 + end + end + + if AbilityExtensions:NotRetreating(npcBot) then + local target = npcBot:GetAttackTarget() + if target == nil then + if WeakestEnemy ~= nil then + local b = UseAt(WeakestEnemy) + if b then + return BOT_ACTION_DESIRE_HIGH, WeakestEnemy + else + return false + end + end + else + return UseAt(target) + end + end + return false +end +Consider[1] = AbilityExtensions:ToggleFunctionToAutoCast(npcBot, Consider[1], AbilitiesReal[1]) + +Consider[4] = function() + local abilityNumber = 4 + local ability = AbilitiesReal[abilityNumber] + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE + end + + local function TrySproink(t) + if t == nil or t:IsBuilding() then + return false + end + if not t:IsHero() then + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 + end + local dis = GetUnitToUnitDistance(npcBot, t) + if dis <= npcBot:GetAttackRange() + ability:GetSpecialValueInt("impetus_attacks_range_buffer") - ability:GetSpecialValueInt("leap_distance") + 100 and npcBot:IsFacingLocation(t:GetLocation(), 40) then + return true + else + return false + end + end + + if TrySproink(npcBot:GetAttackTarget()) then + if npcBot:WasRecentlyDamagedByHero(npcBot:GetAttackTarget(), 2) then + return BOT_ACTION_DESIRE_HIGH + else + return BOT_ACTION_DESIRE_LOW + end + end + local enemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, npcBot:GetAttackRange()+150, true, BOT_MODE_NONE) + if AbilityExtensions:Contains(enemies, npcBot:GetAttackTarget()) then + + end + enemies = AbilityExtensions:SortByMinFirst(enemies, function(t) return GetUnitToUnitDistance(npcBot, t) end) + enemies = AbilityExtensions:Filter(enemies, function(t) return TrySproink(t) end) + if AbilityExtensions:Any(enemies, function(t) return npcBot:WasRecentlyDamagedByHero(t, 2) end) then + return BOT_ACTION_DESIRE_HIGH + end + return 0 +end + AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) + function AbilityUsageThink() -- Check if we're already using an ability if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) diff --git a/ability_item_usage_faceless_void.lua b/ability_item_usage_faceless_void.lua index 07e7ce46..c0b4798d 100644 --- a/ability_item_usage_faceless_void.lua +++ b/ability_item_usage_faceless_void.lua @@ -91,7 +91,7 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end @@ -132,6 +132,15 @@ Consider[1]=function() then return BOT_ACTION_DESIRE_HIGH, utility.GetUnitsTowardsLocation(npcBot,GetAncient(GetTeam()),CastRange-200) + RandomVector(200); end + + -- try to dodge a projectile + local projectiles = npcBot:GetIncomingTrackingProjectiles() + for _,p in pairs(projectiles) + do + if GetUnitToLocationDistance(npcBot, p.location) <= 400 and p.is_attack == false and not AbilityExtensions:IgnoreAbilityBlock(p.ability) then + return BOT_ACTION_DESIRE_HIGH, AbilityExtensions:GetPointFromLineByDistance(npcBot:GetLocation(), p.location, 450) + end + end -- If we're seriously retreating if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT or npcBot.FacelessVoidSkill1.Hp-HealthPercentage>=0.25+0.05*#enemys) @@ -255,6 +264,20 @@ Consider[2]=function() end +-- Consider[4] = function() +-- local abilityNumber=4 +-- -------------------------------------- +-- -- Generic Variable Setting +-- -------------------------------------- +-- local ability=AbilitiesReal[abilityNumber]; + +-- if not ability:IsFullyCastable() then +-- return BOT_ACTION_DESIRE_NONE, 0; +-- end + +-- return 0 +-- end + Consider[5]=function() local abilityNumber=5 -------------------------------------- diff --git a/ability_item_usage_furion.lua b/ability_item_usage_furion.lua index 69a86b71..2045944f 100644 --- a/ability_item_usage_furion.lua +++ b/ability_item_usage_furion.lua @@ -43,7 +43,6 @@ local AbilityToLevelUp = { "nil", "nil", "nil", - "nil", "talent", } @@ -91,14 +90,14 @@ Consider[1]=function() end local function BlockFriendMeleeHeroes(enemy) - local friends = enemy:GetNearbyHeroes(260, true, BOT_MODE_NONE) + local friends = enemy:GetNearbyHeroes(330, true, BOT_MODE_NONE) return AbilityExtensions:Any(friends, function(p) return AbilityExtensions:MayNotBeIllusion(npcBot, p) - --and enemy:WasRecentlyDamagedByHero(p, 2) - and (print("furion: might block "..p:GetUnitName()) or true) + -- and enemy:WasRecentlyDamagedByHero(p, 1.5) end) or AbilityExtensions:Any(npcBot:GetNearbyHeroes(350, false, BOT_MODE_NONE), function(p) - return AbilityExtensions:MayNotBeIllusion(npcBot, p) and AbilityExtensions:IsMeleeHero(p) - and (print("furion: might block"..p:GetUnitName()) or true) + return AbilityExtensions:MayNotBeIllusion(npcBot, p) + and AbilityExtensions:IsMeleeHero(p) + -- and enemy:WasRecentlyDamagedByHero(p, 2) end) end @@ -133,7 +132,7 @@ Consider[1]=function() local tableNearbyEnemyHeroes = npcBot:GetNearbyHeroes( CastRange, true, BOT_MODE_NONE ); for _,npcEnemy in pairs( tableNearbyEnemyHeroes ) do - if ( CanCast[abilityNumber]( npcEnemy ) and not enemyDisabled(npcEnemy)) + if ( CanCast[abilityNumber]( npcEnemy ) and not enemyDisabled(npcEnemy) and not AbilityExtensions:GetAvailableItem("item_quelling_blade") and not AbilityExtensions:GetAvailableItem("bfury")) then local Damage2 = npcEnemy:GetEstimatedDamageToTarget( false, npcBot, 3.0, DAMAGE_TYPE_ALL ); if ( Damage2 > nMostDangerousDamage ) @@ -155,12 +154,9 @@ Consider[1]=function() then if (WeakestEnemy~=nil) then - if ( CanCast[abilityNumber]( WeakestEnemy ) ) + if ( CanCast[abilityNumber]( WeakestEnemy ) and not AbilityExtensions:GetAvailableItem(WeakestEnemy, "item_quelling_blade") and not AbilityExtensions:GetAvailableItem(WeakestEnemy, "bfury") ) then local tt = WeakestEnemy:GetNearbyHeroes(150, true, BOT_MODE_NONE) - if #tt > 0 then - print("furion: dont block 1") - end if BlockFriendMeleeHeroes(WeakestEnemy) then return 0 end @@ -177,7 +173,7 @@ Consider[1]=function() then local tableNearbyEnemyHeroes = npcBot:GetNearbyHeroes( 150, true, BOT_MODE_NONE ); - if ( npcBot:WasRecentlyDamagedByAnyHero( 5.0 ) and #tableNearbyEnemyHeroes==0) + if ( npcBot:WasRecentlyDamagedByAnyHero(3) and #tableNearbyEnemyHeroes==0) then return UseAtTarget(BOT_ACTION_DESIRE_VERYHIGH, npcBot) end @@ -205,9 +201,6 @@ Consider[1]=function() if ( CanCast[abilityNumber]( npcTarget ) and not enemyDisabled(npcTarget) and GetUnitToUnitDistance(npcBot,npcTarget)< CastRange + 75*#allys) then local tt = npcTarget:GetNearbyHeroes(150, true, BOT_MODE_NONE) - if #tt > 0 then - print("furion: dont block 2") - end if BlockFriendMeleeHeroes(npcTarget) then return 0 end @@ -227,7 +220,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_hoodwink.lua b/ability_item_usage_hoodwink.lua index 3a2f9f77..43f8cde6 100644 --- a/ability_item_usage_hoodwink.lua +++ b/ability_item_usage_hoodwink.lua @@ -73,7 +73,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast} +local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.UCanCast,utility.UCanCast} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -232,11 +232,11 @@ Consider[2]=function() for _,myFriend in pairs(allys) do if ( GetUnitToUnitDistance( myFriend, npcBot ) < CastRange and not myFriend:HasModifier(modifierName) ) then - return BOT_ACTION_DESIRE_MODERATE, myFriend; + return BOT_ACTION_DESIRE_MODERATE, myFriend, "Target" end end if not npcBot:HasModifier(modifierName) then - return BOT_ACTION_DESIRE_MODERATE, npcBot; + return BOT_ACTION_DESIRE_MODERATE, npcBot, "Target" end end end @@ -248,12 +248,12 @@ Consider[2]=function() do if ( not ally:HasModifier(modifierName) ) then - return BOT_ACTION_DESIRE_MODERATE,ally; + return BOT_ACTION_DESIRE_MODERATE,ally, "Target" end end if not npcBot:HasModifier(modifierName) then - return BOT_ACTION_DESIRE_MODERATE, npcBot; + return BOT_ACTION_DESIRE_MODERATE, npcBot, "Target" end end @@ -292,7 +292,7 @@ Consider[3]=function() do if ( npcEnemy:IsChanneling() ) then - return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation(); + return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation(), "Location" end end @@ -304,7 +304,7 @@ Consider[3]=function() local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), CastRange, Radius, 0, Damage ); if ( locationAoE.count >= 3 ) then - return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc, "Location" end end @@ -313,7 +313,7 @@ Consider[3]=function() then if ( npcBot:WasRecentlyDamagedByAnyHero( 2.0 ) ) then - return BOT_ACTION_DESIRE_HIGH, utility.Fountain(GetTeam()); + return BOT_ACTION_DESIRE_HIGH, utility.Fountain(GetTeam()), "Location" end end @@ -325,7 +325,7 @@ Consider[3]=function() then local locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); if ( locationAoE.count >= 2 ) then - return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; + return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc, "Location" end local npcEnemy = npcBot:GetTarget(); @@ -334,7 +334,7 @@ Consider[3]=function() then if ( CanCast[abilityNumber]( npcEnemy ) ) then - return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetExtrapolatedLocation(CastPoint); + return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetExtrapolatedLocation(CastPoint), "Location" end end end @@ -343,8 +343,8 @@ Consider[3]=function() end -Consider[4]=function() - local abilityNumber=4 +Consider[6]=function() + local abilityNumber=6 -------------------------------------- -- Generic Variable Setting -------------------------------------- diff --git a/ability_item_usage_jakiro.lua b/ability_item_usage_jakiro.lua index bfccf7a5..2fc7129f 100644 --- a/ability_item_usage_jakiro.lua +++ b/ability_item_usage_jakiro.lua @@ -463,6 +463,136 @@ Consider[3]=function() return BOT_ACTION_DESIRE_NONE, 0; +end + +Consider[4] = function() + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = ability:GetCastRange(); + local Damage = ability:GetAbilityDamage(); + local Radius = ability:GetAOERadius() + + local HeroHealth=10000 + local CreepHealth=10000 + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + local towers = npcBot:GetNearbyTowers(CastRange+300,true) + -------------------------------------- + -- Global high-priorty usage + -------------------------------------- + --Try to kill enemy hero + if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + then + return BOT_ACTION_DESIRE_HIGH,WeakestEnemy; + end + end + end + end + + -------------------------------------- + -- Mode based usage + -------------------------------------- + -- If we're seriously retreating, see if we can land a stun on someone who's damaged us recently + if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) + then + for _,npcEnemy in pairs( enemys ) + do + if ( npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) ) + then + if ( CanCast[abilityNumber]( npcEnemy )) + then + return BOT_ACTION_DESIRE_MODERATE, npcEnemy; + end + end + end + end + + -- If we're farming and can hit 2+ creeps and kill 1+ + if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) + then + if ( #creeps >= 2 ) + then + return BOT_ACTION_DESIRE_LOW, WeakestCreep; + end + end + + -- If we're pushing or defending a lane and can hit 3+ creeps, go for it + if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or + npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or + npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) + then + if(#towers>=1) + then + return BOT_ACTION_DESIRE_LOW, towers[1]; + end + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) + then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy; + end + end + if (WeakestCreep~=nil) + then + if ( CanCast[abilityNumber]( WeakestCreep )and GetUnitToUnitDistance(npcBot,WeakestCreep)< CastRange + 75*#allys ) + then + return BOT_ACTION_DESIRE_LOW, WeakestCreep; + end + end + end + + -- If my mana is enough,use it at enemy + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if (#enemys>=1) + then + if ( CanCast[abilityNumber]( enemys[1] ) ) + then + return BOT_ACTION_DESIRE_LOW,enemys[1]; + end + end + end + + -- If we're going after someone + if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or + npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or + npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or + npcBot:GetActiveMode() == BOT_MODE_ATTACK ) + then + local npcEnemy = npcBot:GetTarget(); + + if ( npcEnemy ~= nil ) + then + if ( CanCast[abilityNumber]( npcEnemy ) and GetUnitToUnitDistance(npcBot,npcEnemy)< CastRange + 75*#allys) + then + return BOT_ACTION_DESIRE_MODERATE, npcEnemy + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + + end Consider[5]=function() diff --git a/ability_item_usage_keeper_of_the_light.lua b/ability_item_usage_keeper_of_the_light.lua index c70c1fed..ed2a2e1e 100644 --- a/ability_item_usage_keeper_of_the_light.lua +++ b/ability_item_usage_keeper_of_the_light.lua @@ -38,12 +38,12 @@ local AbilityToLevelUp = Abilities[1], Abilities[3], Abilities[2], - Abilities[3], Abilities[1], + Abilities[3], Abilities[5], Abilities[3], Abilities[1], - Abilities[3], + Abilities[1], "talent", Abilities[3], Abilities[5], diff --git a/ability_item_usage_kunkka.lua b/ability_item_usage_kunkka.lua index 4f9899c9..db716a3f 100644 --- a/ability_item_usage_kunkka.lua +++ b/ability_item_usage_kunkka.lua @@ -94,9 +94,15 @@ end local xMarkTarget local xMarkTime local xMarkLocation +local xMarkDuration local useTorrentAtXMark local useTorrentAtXMarkTime local function XMarksEnemy() + if xMarkTarget ~= nil then + print(xMarkTarget:GetUnitName()) + print(AbilityExtensions:ToStringVector(xMarkLocation)) + AbilityExtensions:DebugTable(xMarkTarget) + end return xMarkTarget ~= nil and xMarkTarget:GetTeam() ~= npcBot:GetTeam() end @@ -111,7 +117,7 @@ Consider[1]=function() return BOT_ACTION_DESIRE_NONE, 0; end - local CastRange = 1600; + local CastRange = ability:GetCastRange(); local Damage = ability:GetAbilityDamage(); local Radius = ability:GetAOERadius() local CastPoint = 2; @@ -138,8 +144,9 @@ Consider[1]=function() end end - if XMarksEnemy() and CanCast[1](xMarkTarget) and DotaTime()-xMarkTime <= 0.2 then - return BOT_ACTION_DESIRE_VERYHIGH, npcEnemy:GetLocation() + if XMarksEnemy() and CanCast[1](xMarkTarget) and DotaTime()-xMarkTime <= 0.8 then + print("Torrent on x marked target: "..xMarkTarget:GetUnitName().." at location "..AbilityExtensions:ToStringVector(xMarkLocation).." at "..DotaTime()) + return BOT_ACTION_DESIRE_VERYHIGH, xMarkLocation end --try to kill enemy hero @@ -232,6 +239,36 @@ Consider[1]=function() return BOT_ACTION_DESIRE_NONE, 0; end +-- Consider[2] = function() +-- local ability=AbilitiesReal[3]; + +-- if not ability:IsFullyCastable() then +-- return 0 +-- end + +-- local CastRange = ability:GetCastRange(); +-- local Damage = ability:GetAbilityDamage(); + +-- local HeroHealth=10000 +-- local CreepHealth=10000 +-- local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); +-- local enemys = npcBot:GetNearbyHeroes(CastRange,true,BOT_MODE_NONE) +-- local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + +-- if npcBot:GetActiveMode() == BOT_MODE_LANING then +-- if ability:GetAutoCastState() then +-- ability:ToggleAutoCast() +-- end + +-- end +-- Consider[2] = AbilityExtensions:ToggleFunctionToAutoCast(npcBot, Consider[2], AbilitiesReal[2]) + +-- Consider[4] = function() +-- return 0 +-- end +-- Consider[5] = function() +-- return 0 +-- end Consider[3]=function() @@ -280,7 +317,7 @@ Consider[3]=function() then if(CanCast[3]( npcTarget )) then - if (GetComboDamage() > npcTarget:GetHealth() and GetUnitToUnitDistance( npcTarget, npcBot ) < ( CastRange + 200 ) ) + if (GetComboDamage()*(0.85+0.15*#allys) > npcTarget:GetHealth() and GetUnitToUnitDistance( npcTarget, npcBot ) < ( CastRange + 200 ) ) then return BOT_ACTION_DESIRE_HIGH, npcTarget; end @@ -370,7 +407,7 @@ Consider[6]=function() then if (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana) then - if not AbilitiesReal[1]:IsCooldownReady() or WeakestEnemy:GetModifierRemainingDuration( WeakestEnemy:GetModifierByName('modifier_kunkka_x_marks_the_spot') )< 1.2 + if not AbilitiesReal[1]:IsFullyCastable() or WeakestEnemy:GetModifierRemainingDuration( WeakestEnemy:GetModifierByName('modifier_kunkka_x_marks_the_spot') )< 1.2 then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy:GetExtrapolatedLocation(-2.9); end @@ -422,7 +459,7 @@ Consider[6]=function() then if ( CanCast[abilityNumber]( npcEnemy )) then - if not AbilitiesReal[1]:IsCooldownReady() or npcEnemy:GetModifierRemainingDuration( npcEnemy:GetModifierByName('modifier_kunkka_x_marks_the_spot') )< 1.2 + if not AbilitiesReal[1]:IsFullyCastable() or npcEnemy:GetModifierRemainingDuration( npcEnemy:GetModifierByName('modifier_kunkka_x_marks_the_spot') )< 1.2 then return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetExtrapolatedLocation(-2.9); end @@ -440,7 +477,7 @@ end Consider[7] = function() local abilityNumber=7 local ability=AbilitiesReal[abilityNumber] - if not ability:IsFullyCastable() or xMarkTarget == nil or not xMarkTarget:HasModifier("modifier_kunkka_x_marks_the_spot") then + if not ability:IsFullyCastable() or ability:IsHidden() or xMarkTarget == nil or not xMarkTarget:HasModifier("modifier_kunkka_x_marks_the_spot") then return 0 end if xMarkTarget:IsChanneling() then @@ -478,7 +515,7 @@ function AbilityUsageThink() ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end - if xMarkTime and (DotaTime() > xMarkTime + 8 or not npcBot:IsAlive() or not xMarkTarget:IsAlive()) then + if xMarkTarget ~= nil and (DotaTime() > xMarkTime + xMarkDuration or not npcBot:IsAlive() or not xMarkTarget:IsAlive() or not xMarkTarget:HasModifier("modifier_kunkka_x_marks_the_target")) then xMarkTarget = nil xMarkTime = nil xMarkLocation = nil @@ -487,13 +524,19 @@ function AbilityUsageThink() end local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal,cast) - if index == 3 then + if index == 3 and target ~= nil then xMarkTarget = target - xMarkTime = DotaTime() + xMarkTime = DotaTime()+AbilitiesReal[3]:GetCastPoint() xMarkLocation = target:GetLocation() + if target:GetTeam() == npcBot:GetTeam() then + xMarkDuration = AbilitiesReal[3]:GetSpecialValueFloat("allied_duration") + else + xMarkDuration = AbilitiesReal[3]:GetSpecialValueFloat("duration") + end + elseif index == 1 and xMarkTarget then useTorrentAtXMark = true - useTorrentAtXMarkTime = DotaTime() + useTorrentAtXMarkTime = DotaTime()+AbilitiesReal[1]:GetCastPoint() end end diff --git a/ability_item_usage_leshrac.lua b/ability_item_usage_leshrac.lua index 1f3ba5b0..e7e4dc11 100644 --- a/ability_item_usage_leshrac.lua +++ b/ability_item_usage_leshrac.lua @@ -116,7 +116,7 @@ Consider[1]=function() -- Check for a channeling enemy for _,npcEnemy in pairs( enemys ) do - if ( npcEnemy:IsChanneling() ) + if ( npcEnemy:IsChanneling() and CanCast[1](npcEnemy)) then return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation(); end @@ -129,7 +129,7 @@ Consider[1]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)*1.8 or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy:GetExtrapolatedLocation(CastPoint); end @@ -254,7 +254,7 @@ Consider[2]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)*1.8 or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) then return BOT_ACTION_DESIRE_HIGH end @@ -361,7 +361,7 @@ Consider[3]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)*1.8 or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy; end @@ -436,6 +436,33 @@ Consider[3]=function() end +Consider[4] = function() + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber] + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE + end + + local Damage = ability:GetAbilityDamage() + local Radius = ability:GetAOERadius() + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ) + local enemys = npcBot:GetNearbyHeroes(Radius,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(Radius,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + if #enemys >= 2 and (AbilitiesReal[1]:IsFullyCastable() or AbilitiesReal[3]:IsFullyCastable() or AbilitiesReal[5]:GetToggleState()) then + return BOT_MODE_DESIRE_MODERATE + end + if HealthPercentage <= 0.3 and #enemys >= 1 then + return BOT_MODE_DESIRE_HIGH + end + return 0 +end + Consider[5]=function() local abilityNumber=5 -------------------------------------- @@ -476,7 +503,7 @@ Consider[5]=function() then if ( CanCast[abilityNumber]( WeakestEnemy )) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)*1.8 or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) then return BOT_ACTION_DESIRE_HIGH end diff --git a/ability_item_usage_life_stealer.lua b/ability_item_usage_life_stealer.lua index 9d886fad..a3d1ba5f 100644 --- a/ability_item_usage_life_stealer.lua +++ b/ability_item_usage_life_stealer.lua @@ -431,6 +431,40 @@ Consider[7]=function() end +local lastInfestTime +local lastInfestTarget +local lastInfestTable = {} +Consider[6] = function() + local ability = AbilitiesReal[6] + if not ability:IsFullyCastable() or ability:IsHidden() or lastInfestTarget == nil then + return 0 + end + if lastInfestTarget ~= nil and not lastInfestTarget:IsAlive() then + lastInfestTarget = nil + lastInfestTime = nil + end + local infest3 = AbilityExtensions:LastForAtLeastSeconds(function() return lastInfestTarget ~= nil end, 3, lastInfestTable) + local infest10 = AbilityExtensions:LastForAtLeastSeconds(function() return lastInfestTarget ~= nil end, 10, lastInfestTable) + + local enemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1000, true) + local friends = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1200, false) + + if AbilityExtensions:IsAttackingEnemies(npcBot) then + local nearbyEnemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, ability:GetAOERadius(), true) + if #nearbyEnemies >= 3 or AbilityExtensions:IsSeverlyDisabled(lastInfestTarget) and #nearbyEnemies <= 2 then + return BOT_ACTION_DESIRE_MODERATE + end + end + if infest3 and (#enemies == 0 or AbilityExtensions:Outnumber(friends, enemies)) then + return BOT_ACTION_DESIRE_HIGH + end + if infest10 then + return BOT_ACTION_DESIRE_VERYHIGH + end + return 0 +end + + AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) @@ -453,7 +487,11 @@ function AbilityUsageThink() then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end - ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + if index == 5 then + lastInfestTime = DotaTime() + lastInfestTarget = target + end end function CourierUsageThink() diff --git a/ability_item_usage_lina.lua b/ability_item_usage_lina.lua index c73402f8..5a059151 100644 --- a/ability_item_usage_lina.lua +++ b/ability_item_usage_lina.lua @@ -249,6 +249,16 @@ Consider[2]=function() end end end + + local imprisonedEnemy = AbilityExtensions:Map(npcBot:GetNearbyHeroes(CastRange+100,true,BOT_MODE_NONE), function(t) return { t, AbilityExtensions:GetImprisonmentRemainingDuration(t) } end) + imprisonedEnemy = AbilityExtensions:First(imprisonedEnemy, function(t) return t[2] ~= nil end) + if imprisonedEnemy ~= nil then + local timer = imprisonedEnemy[2] - ability:GetSpecialValueFloat("effect_delay") - ability:GetCastPoint() - 0.1 + if timer >= 0 then + return BOT_ACTION_DESIRE_VERYHIGH, imprisonedEnemy[1]:GetLocation() + end + end + -------------------------------------- -- Mode based usage -------------------------------------- diff --git a/ability_item_usage_luna.lua b/ability_item_usage_luna.lua index a671f400..80aa5a83 100644 --- a/ability_item_usage_luna.lua +++ b/ability_item_usage_luna.lua @@ -233,7 +233,7 @@ Consider[4]=function() end end - if(npcBot:HasScepter() or npcBot:HasModifier("modifier_-- item_ultimate_scepter")) + if(npcBot:HasScepter() or npcBot:HasModifier("modifier_item_ultimate_scepter")) then local locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); if(locationAoE.count-#creeps>=2) diff --git a/ability_item_usage_magnataur.lua b/ability_item_usage_magnataur.lua index 3a3196f0..da8ddebc 100644 --- a/ability_item_usage_magnataur.lua +++ b/ability_item_usage_magnataur.lua @@ -269,7 +269,7 @@ Consider[3]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end @@ -343,6 +343,44 @@ Consider[3]=function() end +Consider[4] = function() + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber] + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE, 0; + end + local radius = ability:GetSpecialValueInt("radius") + local pullAngle = ability:GetSpecialValueInt("pull_angle") / 2 + local CastPoint = ability:GetCastPoint() + local function CanToss(target) + local loc = target:GetExtrapolatedLocation(CastPoint) + return GetUnitToLocationDistance(npcBot, loc) <= radius and npcBot:IsFacingLocation(loc, pullAngle) + end + local f = AbilityExtensions:Filter(AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 500, true), CanToss) + f = AbilityExtensions:GetEnemyHeroNumber(f) + if AbilityExtensions:NotRetreating(npcBot) and f >= 2 or f == 1 and #AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1200, true) == 1 then + return BOT_MODE_DESIRE_HIGH + end + + local function CanTossAfterTurnBack(target) + local loc = target:GetExtrapolatedLocation(CastPoint) + return GetUnitToLocationDistance(npcBot, loc) <= radius and not npcBot:IsFacingLocation(loc, 180-pullAngle) + end + f = AbilityExtensions:Filter(AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 500, true), CanTossAfterTurnBack) + f = AbilityExtensions:GetEnemyHeroNumber(f) + if AbilityExtensions:NotRetreating(npcBot) and f >= 1 then + npcBot:Action_MoveDirectly(utility.GetUnitsTowardsLocation(npcBot, f[1]:GetLocation(), 10)) + npcBot:ActionQueue_UseAbility(ability) + return 0 + end + + return 0 +end + Consider[5]=function() local abilityNumber=5 -------------------------------------- diff --git a/ability_item_usage_mirana.lua b/ability_item_usage_mirana.lua index f03614b7..3f8e82ae 100644 --- a/ability_item_usage_mirana.lua +++ b/ability_item_usage_mirana.lua @@ -276,7 +276,7 @@ Consider[3]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_naga_siren.lua b/ability_item_usage_naga_siren.lua index 285737e5..12a41e01 100644 --- a/ability_item_usage_naga_siren.lua +++ b/ability_item_usage_naga_siren.lua @@ -148,7 +148,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_obsidian_destroyer.lua b/ability_item_usage_obsidian_destroyer.lua index 494bd681..115f6c4b 100644 --- a/ability_item_usage_obsidian_destroyer.lua +++ b/ability_item_usage_obsidian_destroyer.lua @@ -91,7 +91,7 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if npcBot:IsIllusion() or not ability:IsFullyCastable() then -- destroyer's illusions (from illusion rune or from shadow_demon_disruption) can use the first ability + if npcBot:IsIllusion() or not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then -- destroyer's illusions (from illusion rune or from shadow_demon_disruption) can use the first ability return BOT_ACTION_DESIRE_NONE, 0; end @@ -112,7 +112,7 @@ Consider[1]=function() local t=npcBot:GetAttackTarget() if(t~=nil) then - if (ManaPercentage > 0.35 and npcBot:GetLevel()>=7) + if npcBot:GetLevel()>=7 then ability:ToggleAutoCast() return BOT_ACTION_DESIRE_NONE, 0; diff --git a/ability_item_usage_omniknight.lua b/ability_item_usage_omniknight.lua index 5e2feab6..0de6408c 100644 --- a/ability_item_usage_omniknight.lua +++ b/ability_item_usage_omniknight.lua @@ -378,6 +378,53 @@ Consider[2]=function() end +Consider[4] = function() + local ability = AbilitiesReal[4] + if not ability:IsFullyCastable() or AbilityExtensions:IsPhysicalOutputDisabled(npcBot) then + return 0 + end + + local CastRange = ability:GetCastRange() + local enemys = npcBot:GetNearbyHeroes(CastRange+100,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + + local function UseAt(target) + if not CanCast[abilityNumber](target) then + return false + end + if target:IsHero() then + if AbilityExtensions:MustBeIllusion(npcBot, target) then + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 or AbilityExtensions:GetHealthPercent(target) <= 0.4 + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.4 or AbilityExtensions:GetManaPercent(npcBot) >= 0.2 + end + elseif target:IsBuilding() then + return false + else + return AbilityExtensions:GetManaPercent(npcBot) >= 0.8 + end + + end + + if AbilityExtensions:NotRetreating(npcBot) then + local target = npcBot:GetAttackTarget() + if target == nil then + if WeakestEnemy ~= nil then + local b = UseAt(WeakestEnemy) + if b then + return BOT_ACTION_DESIRE_HIGH, WeakestEnemy + else + return false + end + end + else + return UseAt(target) + end + end + return false +end +Consider[4] = AbilityExtensions:ToggleFunctionToAutoCast(npcBot, Consider[4], AbilitiesReal[4]) + Consider[5]=function() local abilityNumber=5 diff --git a/ability_item_usage_phantom_assassin.lua b/ability_item_usage_phantom_assassin.lua index 0a88a14d..cdaba6d6 100644 --- a/ability_item_usage_phantom_assassin.lua +++ b/ability_item_usage_phantom_assassin.lua @@ -331,7 +331,12 @@ Consider[3]=function() -- Mode based usage -------------------------------------- --protect myself - if(npcBot:WasRecentlyDamagedByAnyHero(5) or + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if HealthPercentage >= 0.6 or HealthPercentage >= 0.3 and ManaPercentage <= 0.3 then + return 0 + end + end + if(npcBot:WasRecentlyDamagedByAnyHero(2.5) or (npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_MODERATE)) then if (#enemys==0) @@ -361,6 +366,33 @@ Consider[3]=function() end +Consider[4] = function() + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE + end + + local CastRange = ability:GetAOERadius(); + + local allys = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1200, true) + local enemys = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, CastRange-100, false) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(CastRange,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + + if AbilityExtensions:IsAttackingEnemies(npcBot) then + if #enemys >= 2 or #enemys == 1 and #allys == 0 then + return BOT_ACTION_DESIRE_HIGH + end + end + return 0 +end + AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) function AbilityUsageThink() diff --git a/ability_item_usage_phantom_lancer.lua b/ability_item_usage_phantom_lancer.lua index 9b2bf12c..1af877a8 100644 --- a/ability_item_usage_phantom_lancer.lua +++ b/ability_item_usage_phantom_lancer.lua @@ -202,9 +202,11 @@ Consider[2]=function() if (WeakestEnemy~=nil) then local enemys2= WeakestEnemy:GetNearbyHeroes(900,true,BOT_MODE_NONE) - if ( CanCast[abilityNumber]( WeakestEnemy ) and #enemys2<=2) + -- TODO: don't know why, but enemys2 can be null + + if CanCast[abilityNumber]( WeakestEnemy ) and (enemys ~= nil or #enemys2<=2) then - if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) or npcBot:GetMana()>ComboMana) + if npcBot:GetMana()>ComboMana*1.5 then return BOT_ACTION_DESIRE_MODERATE,utility.GetUnitsTowardsLocation(npcBot,WeakestEnemy,CastRange); end @@ -250,6 +252,24 @@ Consider[2]=function() end +Consider[3] = function() + if not AbilitiesReal[3]:IsFullyCastable() then + return 0 + end + if npcBot:GetActiveMode() == BOT_MODE_LANING then + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(1200,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(1200, true) + local weakestCreep, creepHealth = utility.GetWeakestUnit(creeps) + if weakestCreep ~= nil and creepHealth <= weakestCreep:GetActualIncomingDamage(npcBot:GetAttackDamage()*1.05, DAMAGE_TYPE_PHYSICAL) and GetUnitToUnitDistance(npcBot, weakestCreep) <= 250 then + return true + end + end + return false +end +Consider[3] = AbilityExtensions:ToggleFunctionToAction(npcBot, Consider[3], AbilitiesReal[3]) + AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) function AbilityUsageThink() diff --git a/ability_item_usage_puck.lua b/ability_item_usage_puck.lua new file mode 100644 index 00000000..0910bcb4 --- /dev/null +++ b/ability_item_usage_puck.lua @@ -0,0 +1,125 @@ +local utility = require( GetScriptDirectory().."/utility" ) +require(GetScriptDirectory() .. "/ability_item_usage_generic") +local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") + +local debugmode=false +local npcBot = GetBot() +local Talents ={} +local Abilities ={} +local AbilitiesReal ={} + +ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) + +local AbilityToLevelUp = { + Abilities[1], + Abilities[3], + Abilities[3], + Abilities[2], + Abilities[3], + Abilities[4], + Abilities[3], + Abilities[2], + Abilities[2], + "talent", + Abilities[2], + Abilities[4], + Abilities[1], + Abilities[1], + "talent", + Abilities[1], + "nil", + Abilities[4], + "nil", + "talent", + "nil", + "nil", + "nil", + "nil", + "talent", +} + +local TalentTree = { + function() return Talents[1] end, + function() return Talents[3] end, + function() return Talents[6] end, + function() return Talents[7] end, + function() return Talents[2] end, + function() return Talents[4] end, + function() return Talents[5] end, + function() return Talents[8] end, +} + +utility.CheckAbilityBuild(AbilityToLevelUp) + +function AbilityLevelUpThink() + ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp,TalentTree) +end + + +-------------------------------------- +-- Ability Usage Thinking +-------------------------------------- +local cast={} cast.Desire={} cast.Target={} cast.Type={} +local Consider ={} +local CanCast={utility.UCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast} +local enemyDisabled=utility.enemyDisabled + +Consider[1] = function() + local ability = AbilitiesReal[1] + local enemies = npcBot:GetNearbyHeroes(1599, true, BOT_MODE_NONE) + local realEnemies = AbilityExtensions:Filter(enemies, function(t) return AbilityExtensions:MayNotBeIllusion(t) end) + local friends = npcBot:GetNearbyHeroes(1599, true, BOT_MODE_NONE) + local enemyCreeps = AbilityExtensions:GetNearbyAttackableCreeps(npcBot, 900, true) + local damage = ability:GetAbilityDamage() + local weakCreeps = AbilityExtensions:Filter(enemyCreeps, function(t) return t:GetHealth() < t:GetActualIncomingDamage(damage, DAMAGE_TYPE_MAGICAL) end) + if not ability:IsFullyCastable() then + return 0 + end + + local distance = 1500 + local orbSpeed = 1500 + local radius = 150 + + local function TryUseAt(location) + local botLocation = npcBot:GetLocation() + -- local + end + + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if #realEnemies ~= 0 then + if #weakCreeps > 1 and ManaPercentage >= 0.4+ability:GetManaCost() and (HealthPercentage>=0.7 or HealthPercentage<=0.3) then + local rates = AbilityExtensions:Map(AbilityExtensions:Concat(weakCreeps, realEnemies), function(t) + -- local + end) + end + end + end + return 0 +end + +AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) +function AbilityUsageThink() + + -- Check if we're already using an ability + if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) + then + return + end + + ComboMana=GetComboMana() + AttackRange=npcBot:GetAttackRange() + ManaPercentage=npcBot:GetMana()/npcBot:GetMaxMana() + HealthPercentage=npcBot:GetHealth()/npcBot:GetMaxHealth() + + cast=ability_item_usage_generic.ConsiderAbility(AbilitiesReal,Consider) + ---------------------------------debug-------------------------------------------- + if(debugmode==true) + then + ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) + end + ability_item_usage_generic.UseAbility(AbilitiesReal,cast) +end + +function CourierUsageThink() + ability_item_usage_generic.CourierUsageThink() +end \ No newline at end of file diff --git a/ability_item_usage_pudge.lua b/ability_item_usage_pudge.lua index 83813047..e22c6b6d 100644 --- a/ability_item_usage_pudge.lua +++ b/ability_item_usage_pudge.lua @@ -76,6 +76,129 @@ local Consider ={} local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast} local enemyDisabled=utility.enemyDisabled +Consider[1] = function() + local ability = AbilitiesReal[1] + if not ability:IsFullyCastable() then + return 0 + end + local castPoint = 0.3 + local range = ability:GetSpecialValueInt("hook_distance") + local searchRadius = ability:GetSpecialValueInt("hook_width") + local hookSpeed = ability:GetSpecialValueFloat("hook_speed") + local allNearbyUnits = AbilityExtensions:GetNearbyAllUnits(npcBot, range) + + local function NotBlockedByAnyUnit(line, target, distance) + return AbilityExtensions:All(AbilityExtensions:Remove(allNearbyUnits, target), function(t) + local f = AbilityExtensions:GetPointToLineDistance(t:GetLocation(), line) <= searchRadius + target:GetBoundingRadius() and distance <= GetUnitToUnitDistance(npcBot, t) + return f + end) + end + + local function T(target) + local point = target:GetExtrapolatedLocation(GetUnitToUnitDistance(npcBot, target) / hookSpeed + castPoint) + local distance = GetUnitToLocationDistance(npcBot, point) + local line = AbilityExtensions:GetLine(npcBot:GetLocation(), point) + if line == nil then + print("pudge: line == nil") + end + print("pudge: if I hook "..target:GetUnitName()) + local result = GetUnitToLocationDistance(npcBot, point) <= range and NotBlockedByAnyUnit(line, target, distance) + if result then + print("pudge: I can hook "..target:GetUnitName()) + end + return result + end + + local enemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range, true, BOT_MODE_NONE) + enemies = AbilityExtensions:SortByMaxFirst(enemies, function(t) return GetUnitToUnitDistance(npcBot, t) end) + enemies = AbilityExtensions:Filter(enemies, T) + if #enemies ~= 0 then + return BOT_MODE_DESIRE_HIGH, enemies[1]:GetExtrapolatedLocation(GetUnitToUnitDistance(npcBot, enemies[1]) / 1450) + end + + local allies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range, false, BOT_MODE_NONE) + allies = AbilityExtensions:Filter(allies, function(t) return t:IsStunned() or t:IsRooted() end) + allies = AbilityExtensions:Filter(allies, T) + if #allies ~= 0 then + return BOT_MODE_DESIRE_HIGH, allies[1]:GetExtrapolatedLocation(GetUnitToUnitDistance(npcBot, enemies[1]) / 1450) + end + + return 0 +end + +Consider[2] = function() + local ability = AbilitiesReal[2] + local radius = 250 + if npcBot:HasScepter() then + radius = 475 + end + if not ability:IsFullyCastable() then + return false + end + if AbilityExtensions:IsAttackingEnemies(npcBot) or AbilityExtensions:IsRetreating(npcBot) then + local nearbyEnemies = npcBot:GetNearbyHeroes(radius, true, BOT_MODE_NONE) + if #nearbyEnemies ~= 0 then + return AbilityExtensions:Any(nearbyEnemies, function(t) npcBot:WasRecentlyDamagedByHero(t, 1.5) end) or AbilityExtensions:GetHealthPercent(npcBot) >= 0.3 + end + return false + end + return false +end +Consider[2] = AbilityExtensions:ToggleFunctionToAction(npcBot, Consider[2], AbilitiesReal[2]) + +local swallowingSomething +local swallowTimer +Consider[4] = function() + local ability = AbilitiesReal[4] + if not ability:IsFullyCastable() then + return 0 + end + swallowingSomething = npcBot:HasModifier("modifier_pudge_swallow") or npcBot:HasModifier("modifier_pudge_swallow_effect") or npcBot:HasModifier("modifier_pudge_swallow_hide") + if swallowingSomething then + if swallowTimer ~= nil then + if DotaTime() >= swallowTimer + 3 then + return BOT_MODE_DESIRE_VERYHIGH + end + else + swallowTimer = DotaTime() + end + end + return 0 +end + +Consider[5] = function() + local ability = AbilitiesReal[5] + if not ability:IsFullyCastable() then + return nil + end + local range = ability:GetCastRange() + 100 + local hookedEnemy = AbilityExtensions:First(AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range, true, BOT_MODE_NONE), function(t) + return t:IsHero() and AbilityExtensions:MayNotBeIllusion(npcBot, t) and t:HasModifier("modifier_pudge_meat_hook") + end) + if hookedEnemy ~= nil then + return BOT_MODE_DESIRE_VERYHIGH, hookedEnemy + end + local nearbyEnemies = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 900, true, BOT_MODE_NONE) + if AbilityExtensions:IsAttackingEnemies(npcBot) then + local u = utility.GetWeakestUnit(nearbyEnemies) + if u ~= nil then + return BOT_MODE_DESIRE_HIGH, u + end + end + if AbilityExtensions:IsRetreating(npcBot) and #nearbyEnemies == 1 then + local loneEnemy = nearbyEnemies[1] + if not AbilityExtensions:HasAbilityRetargetModifier(loneEnemy) then + return BOT_MODE_DESIRE_MODERATE, loneEnemy + end + end + + local nearbyAllies = AbilityExtensions:Filter(AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range+200, false, BOT_MODE_NONE), function(t) return AbilityExtensions:CanHardlyMove(t) end) + nearbyAllies = AbilityExtensions:SortByMinFirst(nearbyAllies, function(t) return t:GetHealth() end) + if #nearbyAllies ~= 0 then + return BOT_MODE_DESIRE_MODERATE, nearbyAllies[1] + end +end + function GetComboDamage() return ability_item_usage_generic.GetComboDamage(AbilitiesReal) end @@ -86,4 +209,19 @@ end function CourierUsageThink() ability_item_usage_generic.CourierUsageThink() -end \ No newline at end of file +end + +function AbilityUsageThink() + if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) + then + return + end + + + cast=ability_item_usage_generic.ConsiderAbility(AbilitiesReal,Consider) + ---------------------------------debug-------------------------------------------- + if true then + --ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) + end + ability_item_usage_generic.UseAbility(AbilitiesReal,cast) +end diff --git a/ability_item_usage_pugna.lua b/ability_item_usage_pugna.lua index 27299b7f..42724395 100644 --- a/ability_item_usage_pugna.lua +++ b/ability_item_usage_pugna.lua @@ -19,22 +19,22 @@ ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) local AbilityToLevelUp= { - Abilities[1], - Abilities[2], Abilities[1], Abilities[3], Abilities[1], - Abilities[4], - Abilities[1], - Abilities[2], - Abilities[2], - "talent", Abilities[2], + Abilities[1], Abilities[4], + Abilities[1], Abilities[3], Abilities[3], "talent", Abilities[3], + Abilities[4], + Abilities[2], + Abilities[2], + "talent", + Abilities[2], "nil", Abilities[4], "nil", @@ -442,8 +442,8 @@ Consider[4]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() or ability:GetCurrentCharges()==0 then - return BOT_ACTION_DESIRE_NONE, 0; + if not ability:IsFullyCastable() then + return BOT_ACTION_DESIRE_NONE end local CastRange = ability:GetCastRange(); @@ -452,6 +452,9 @@ Consider[4]=function() local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) + enemys = AbilityExtensions:Filter(enemys, function(t) + return not t:HasModifier("modifier_pudge_life_drain") + end) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) @@ -465,7 +468,7 @@ Consider[4]=function() then if ( CanCast[abilityNumber]( WeakestEnemy ) ) then - if(WeakestEnemy:GetHealth()/WeakestEnemy:GetMaxHealth() < 0.5 or WeakestEnemy:HasModifier("modifier_pugna_decrepify")) + if(WeakestEnemy:GetHealth()/WeakestEnemy:GetMaxHealth() < 0.8 or WeakestEnemy:HasModifier("modifier_pugna_decrepify")) and GetUnitToUnitDistance(npcBot,WeakestEnemy) < CastRange - 200 then return BOT_ACTION_DESIRE_LOW,WeakestEnemy; diff --git a/ability_item_usage_queenofpain.lua b/ability_item_usage_queenofpain.lua index 70e7edef..476cad3b 100644 --- a/ability_item_usage_queenofpain.lua +++ b/ability_item_usage_queenofpain.lua @@ -208,7 +208,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_shredder.lua b/ability_item_usage_shredder.lua index 6d02330b..3d56c3b3 100644 --- a/ability_item_usage_shredder.lua +++ b/ability_item_usage_shredder.lua @@ -283,7 +283,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_slardar.lua b/ability_item_usage_slardar.lua index 17462001..79928ed2 100644 --- a/ability_item_usage_slardar.lua +++ b/ability_item_usage_slardar.lua @@ -161,7 +161,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_slark.lua b/ability_item_usage_slark.lua index a098cc2c..a4d8421a 100644 --- a/ability_item_usage_slark.lua +++ b/ability_item_usage_slark.lua @@ -226,7 +226,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_sniper.lua b/ability_item_usage_sniper.lua index a7042a1d..6825d4b2 100644 --- a/ability_item_usage_sniper.lua +++ b/ability_item_usage_sniper.lua @@ -117,6 +117,8 @@ Consider[1]=function() return desire,templocation end end +local ability1InfoTable = {} +Consider[1] = AbilityExtensions:AddCooldownToChargeAbility(Consider[1], AbilitiesReal[1], ability1InfoTable, 0.8) function Consider1() @@ -350,7 +352,10 @@ function AbilityUsageThink() then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end - ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + if index == 1 then + AbilityExtensions:GetUsedAbilityInfo(AbilitiesReal[1], ability1InfoTable, target) + end end function CourierUsageThink() diff --git a/ability_item_usage_tidehunter.lua b/ability_item_usage_tidehunter.lua index e733aad7..f8e5373a 100644 --- a/ability_item_usage_tidehunter.lua +++ b/ability_item_usage_tidehunter.lua @@ -541,7 +541,7 @@ function AbilityUsageThink() return end - if(npcBot:HasScepter() or npcBot:HasModifier("modifier_-- item_ultimate_scepter")) + if(npcBot:HasScepter() or npcBot:HasModifier("modifier_item_ultimate_scepter")) then Consider[1]=Consider1New; end diff --git a/ability_item_usage_tinker.lua b/ability_item_usage_tinker.lua new file mode 100644 index 00000000..5f020874 --- /dev/null +++ b/ability_item_usage_tinker.lua @@ -0,0 +1,122 @@ +local utility = require( GetScriptDirectory().."/utility" ) +require(GetScriptDirectory() .. "/ability_item_usage_generic") +local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") + + +local debugmode=false +local npcBot = GetBot() +local Talents ={} +local Abilities ={} +local AbilitiesReal ={} + +ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) + + +local AbilityToLevelUp = { + Abilities[1], + Abilities[2], + Abilities[1], + Abilities[2], + Abilities[1], + Abilities[2], + Abilities[1], + Abilities[2], + Abilities[5], + "talent", + Abilities[3], + Abilities[5], + Abilities[3], + Abilities[3], + "talent", + Abilities[3], + "nil", + Abilities[5], + "nil", + "talent", + "nil", + "nil", + "nil", + "nil", + "talent", +} + +local TalentTree = { + function() return Talents[2] end, + function() return Talents[3] end, + function() return Talents[5] end, + function() return Talents[7] end, +} + +utility.CheckAbilityBuild(AbilityToLevelUp) + +local function TryLastHitWithAttack(npc, target) + local time = npc:GetAttackPoint() + GetUnitToUnitDistance(npc, target) / npc:GetAttackProjectileSpeed() + return time +end +local function ReadyForLastHit(npc, target) + local damage = npc:GetAttackDamage() + if target:WasRecentlyDamagedByAnyHero(1.5) or target:WasRecentlyDamagedByCreep(1.7) then + damage = damage * 1.05 + end + return target:GetActualIncomingDamage(damage, DAMAGE_TYPE_PHYSICAL) >= target:GetHealth() +end + +Consider[1] = function() + local manaPercentage = AbilityExtensions:GetManaPercent(npcBot) + local ability = AbilitiesReal[1] + if not ability:IsFullyCastable() + return 0 + end + if npcBot:GetActiveMode() == BOT_MODE_LANING then + local enemyCreeps = npcBot:GetNearbyCreeps(1200, true) + local rangedCreep = AbilityExtensions:First(enemyCreeps, function(t) + return t:GetAttackRange() >= 500 + end) + local enemy = AbilityExtensions:First(npcBot:GetNearbyHeroes(1200, true, BOT_MODE_NONE)) + if rangedCreep ~= nil and enemy ~= nil then + if ReadyForLastHit(npcBot, rangedCreep) and manaPercentage >= 0.6 then + if enemy:GetAttackTarget() == rangedCreep then + return BOT_MODE_DESIRE_MODERATE, rangedCreep + end + if TryLastHitWithAttack(enemy, rangedCreep) < TryLastHitWithAttack(npcBot, rangedCreep) then + return BOT_MODE_DESIRE_MODERATE, rangedCreep + end + end + end + + if enemy ~= nil then + local allCreeps = AbilityExtensions:Concat(npcBot:GetNearbyCreeps(900, true), npcBot:GetNearbyCreeps(900, false)) + allCreeps = AbilityExtensions:Filter(allCreeps, function(t) return t:GetHealth() <= enemy:GetAttackDamage() * 1.2 end) + if #allCreeps >= 2 and manaPercentage >= 0.4 then + return BOT_MODE_DESIRE_MODERATE, enemy + end + + if manaPercentage >= 0.6 then + return BOT_MODE_DESIRE_MODERATE, enemy + end + end + end + if AbilityExtensions:IsAttackingEnemy(npcBot) then + local enemies = npcBot:GetNearbyHeroes(900, true, BOT_MODE_NONE) + end +end + +function AbilityLevelUpThink() + ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp,TalentTree) +end + +AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) + +function AbilityUsageThink() + if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) + then + return + end + + cast=ability_item_usage_generic.ConsiderAbility(AbilitiesReal,Consider) + ability_item_usage_generic.UseAbility(AbilitiesReal,cast) +end + +function CourierUsageThink() + ability_item_usage_generic.CourierUsageThink() +end \ No newline at end of file diff --git a/ability_item_usage_troll_warlord.lua b/ability_item_usage_troll_warlord.lua index b0f32e59..114c100e 100644 --- a/ability_item_usage_troll_warlord.lua +++ b/ability_item_usage_troll_warlord.lua @@ -74,7 +74,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.NCanCast} +local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.UCanCast,utility.UCanCast} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -400,8 +400,8 @@ Consider[3]=function() end -Consider[5]=function() - local abilityNumber=5 +Consider[6]=function() + local abilityNumber=6 -------------------------------------- -- Generic Variable Setting -------------------------------------- diff --git a/ability_item_usage_tusk.lua b/ability_item_usage_tusk.lua index d6bc3289..ea67d9a4 100644 --- a/ability_item_usage_tusk.lua +++ b/ability_item_usage_tusk.lua @@ -215,7 +215,7 @@ Consider[2]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_ursa.lua b/ability_item_usage_ursa.lua index a0a93e92..03adc7e4 100644 --- a/ability_item_usage_ursa.lua +++ b/ability_item_usage_ursa.lua @@ -90,7 +90,7 @@ Consider[1]=function() -------------------------------------- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then + if not ability:IsFullyCastable() or not AbilityExtensions:CanMove(npcBot) then return BOT_ACTION_DESIRE_NONE, 0; end diff --git a/ability_item_usage_warlock.lua b/ability_item_usage_warlock.lua index 5fd6820d..7285ea5c 100644 --- a/ability_item_usage_warlock.lua +++ b/ability_item_usage_warlock.lua @@ -122,6 +122,11 @@ Consider[1]=function() -- Global high-priorty usage -------------------------------------- --Try to kill enemy hero + + if #enemys + #creeps <= 1 then + return 0 + end + if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) then if (WeakestEnemy~=nil) @@ -481,9 +486,9 @@ Consider[4]=function() -- Check for a channeling enemy for _,npcEnemy in pairs( enemys ) do - if ( npcEnemy:IsChanneling() ) + if npcEnemy:IsChanneling() and not npcEnemy:IsInvulnerable() then - return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation(); + return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation() end end @@ -501,24 +506,6 @@ Consider[4]=function() end end end - -------------------------------------- - -- Mode based usage - -------------------------------------- - -- If we're pushing or defending a lane and can hit 4+ creeps, go for it - if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or - npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or - npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT or - npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or - npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or - npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) - then - local locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); - - if ( locationAoE.count >= 3 ) - then - return BOT_ACTION_DESIRE_HIGH, locationAoE.targetloc; - end - end local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes( 1000, false, BOT_MODE_ATTACK ); -- If we're going after someone @@ -538,6 +525,24 @@ Consider[4]=function() end AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) + +local upheavelTimer +local upheavelLocation +local upheavelRadius + +local function GetSpellImmuneRemainingTime(target) + local spellImmuneModifiers = { + "modifier_black_king_bar_immune", + "modifier_minotaur_horn_immune", + "modifier_life_stealer_rage", + } + local c = AbilityExtensions:Map(spellImmuneModifiers, function(t) return AbilityExtensions:GetModifierRemainingDuration(t) end) + c = AbilityExtensions:Filter(c, function(t) return t ~= nil end) + c = AbilityExtensions:SortByMaxFirst(c, function(t) return t end) + c = c[1] or 0 + return c +end + function AbilityUsageThink() local enemys = npcBot:GetNearbyHeroes(500,true,BOT_MODE_NONE) @@ -550,8 +555,28 @@ function AbilityUsageThink() end -- Check if we're already using an ability - if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) - then + if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) then + if npcBot:IsChanneling() and npcBot:GetCurrentActiveAbility() == AbilitiesReal[3] then + if upheavelTimer == nil then + upheavelTimer = DotaTime() + else + local enemies = npcBot:GetNearbyHeroes(1500, true, BOT_MODE_NONE) + enemies = AbilityExtensions:Count(enemies, function(t) + return t:HasModifier("modifier_warlock_upheavel") + or GetUnitToLocationDistance(t, upheavelLocation) <= upheavelRadius and GetSpellImmuneRemainingTime(t) <= 1 + end) + if enemies == 0 then + if DotaTime() > upheavelTimer + 1.5 then + npcBot:Action_ClearActions() + upheavelTimer = nil + end + else + upheavelTimer = DotaTime() + end + end + else + upheavelTimer = nil + end return end @@ -566,7 +591,11 @@ function AbilityUsageThink() then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal,cast) end - ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal,cast) + if index == 3 then + upheavelLocation = target + upheavelRadius = AbilitiesReal[3]:GetAOERadius() + end end function CourierUsageThink() diff --git a/ability_item_usage_winter_wyvern.lua b/ability_item_usage_winter_wyvern.lua index 31c93c63..53fc04a0 100644 --- a/ability_item_usage_winter_wyvern.lua +++ b/ability_item_usage_winter_wyvern.lua @@ -408,7 +408,7 @@ Consider[3]=function() if(npcTarget:GetHealth()/npcTarget:GetMaxHealth() 60 and ( minute % 4 == 0 and sec > 52 ) and closestDist <= ProxDist then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); - elseif IsTeamMustSaveRune(closestRune) and runeStatus == RUNE_STATUS_UNKNOWN then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); - end - else - runeStatus = GetRuneStatus( closestRune ); - if runeStatus == RUNE_STATUS_AVAILABLE then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); - elseif runeStatus == RUNE_STATUS_UNKNOWN and closestDist <= ProxDist then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); - elseif runeStatus == RUNE_STATUS_MISSING and DotaTime() > 60 and ( minute % 2 == 1 and sec > 52 ) and closestDist <= ProxDist then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); - elseif IsTeamMustSaveRune(closestRune) and runeStatus == RUNE_STATUS_UNKNOWN then - return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); - end - end - end + -- closestRune, closestDist = GetBotClosestRune(); + -- if closestRune ~= -1 then + -- if closestRune == RUNE_BOUNTY_1 or closestRune == RUNE_BOUNTY_2 or closestRune == RUNE_BOUNTY_3 or closestRune == RUNE_BOUNTY_4 then + -- runeStatus = GetRuneStatus( closestRune ); + -- if runeStatus == RUNE_STATUS_AVAILABLE then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 3000); + -- elseif runeStatus == RUNE_STATUS_UNKNOWN and closestDist <= ProxDist then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); + -- elseif runeStatus == RUNE_STATUS_MISSING and DotaTime() > 60 and ( minute % 4 == 0 and sec > 52 ) and closestDist <= ProxDist then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); + -- elseif IsTeamMustSaveRune(closestRune) and runeStatus == RUNE_STATUS_UNKNOWN then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); + -- end + -- else + -- runeStatus = GetRuneStatus( closestRune ); + -- if runeStatus == RUNE_STATUS_AVAILABLE then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); + -- elseif runeStatus == RUNE_STATUS_UNKNOWN and closestDist <= ProxDist then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); + -- elseif runeStatus == RUNE_STATUS_MISSING and DotaTime() > 60 and ( minute % 2 == 1 and sec > 52 ) and closestDist <= ProxDist then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, ProxDist); + -- elseif IsTeamMustSaveRune(closestRune) and runeStatus == RUNE_STATUS_UNKNOWN then + -- return CountDesire(BOT_MODE_DESIRE_MODERATE, closestDist, 5000); + -- end + -- end + -- end - return BOT_MODE_DESIRE_NONE; + -- return BOT_MODE_DESIRE_NONE; end function OnStart() diff --git a/util/AbilityAbstraction.lua b/util/AbilityAbstraction.lua index e4ace901..8b9a38e6 100644 --- a/util/AbilityAbstraction.lua +++ b/util/AbilityAbstraction.lua @@ -2,6 +2,8 @@ local M = {} local binlib = require(GetScriptDirectory().."/util/BinDecHex") +-- LINQ functions + M.Range = function(self, min, max, step) if step == nil then step = 1 end local g = {} @@ -11,9 +13,10 @@ M.Range = function(self, min, max, step) return g end -M.Contains = function(self, tb, value) +M.Contains = function(self, tb, value, compare) + compare = compare or function(a, b) return a == b end for _, v in ipairs(tb) do - if v == value then + if compare(v, value) then return true end end @@ -51,20 +54,20 @@ end M.Map = function(self, tb, transform) local g = {} - for k, v in pairs(tb) do + for k, v in ipairs(tb) do g[k] = transform(v) end return g end M.ForEach = function(self, tb, action) - for k, v in pairs(tb) do + for k, v in ipairs(tb) do action(v, k) end end M.Any = function(self, tb, filter) - for k, v in pairs(tb) do + for k, v in ipairs(tb) do if filter == nil or filter(v, k) then return true end @@ -73,7 +76,7 @@ M.Any = function(self, tb, filter) end M.All = function(self, tb, filter) - for k, v in pairs(tb) do + for k, v in ipairs(tb) do if not filter(v, k) then return false end @@ -81,6 +84,13 @@ M.All = function(self, tb, filter) return true end +M.Aggregate = function(self, seed, tb, aggregate) + for k, v in ipairs(tb) do + seed = aggregate(seed, v, k) + end + return seed +end + M.ShallowCopy = function(self, tb) local g = {} for k, v in pairs(tb) do @@ -176,6 +186,123 @@ M.Prepend = function(self, a, b) return self:Concat(b, a) end +M.Distinct = function(self, tb, compare) + compare = compare or function(a, b) return a == b end + local g = {} + for _, v in pairs(tb) do + if not self:Contains(tb, v, compare) then + table.insert(g, v) + end + end + return g +end + +M.Reverse = function(self, tb) + local g = {} + for i = #tb, 1, -1 do + table.insert(g, tb[i]) + end + return g +end + +M.Last = function(self, tb, filter) + return self:First(self:Reverse(tb), filter) +end + +M.Repeat = function(self, element, count) + local g = {} + for i = 1, count do + table.insert(g, element) + end + return g +end + +M.Select = M.Map +M.SelectMany = function(self, tb, map, filter) + local g = {} + for _, source in ipairs(tb) do + local collection = map(source) + for index, value in ipairs(collection) do + if filter == nil or filter(value, index) then + table.insert(g, value) + end + end + end + return g +end + +M.SkipLast = function(self, tb, number) + return self:Skip(self:Reverse(tb), number) +end + +M.Replace = function(self, tb, filter, map) + local g = {} + for k, v in ipairs(tb) do + if filter(v, k) then + table.insert(g, map(v, k)) + else + table.insert(g, v) + end + end + return g +end + +M.IndexOf = function(self, tb, filter) + local g = {} + for k, v in ipairs(tb) do + if type(filter) == "function" then + if filter(v, k) then + return k + end + elseif filter ~= nil then + if v == filter then + return k + end + end + end + return -1 +end + +M.Zip2 = function(self, tb1, tb2, map) + if map == nil then + map = function(a, b) + return {a, b} + end + end + local g = {} + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i])) + end + return g +end + +M.ForEach2 = function(self, tb1, tb2, func) + for i = 1, #tb1 do + func(tb1[i], tb2[i]) + end +end + +M.Map2 = function(self, tb1, tb2, map) + local g = {} + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i], i)) + end + return g +end + +M.Filter2 = function(self, tb1, tb2, filter, map) + if map == nil then + map = function(a,b,c) return {a,b,c} end + end + local g = {} + for i = 1, #tb1 do + if filter(tb1[i], tb2[i], i) then + table.insert(map(tb1[i], tb2[i], i)) + end + end + return g +end + M.SlowSort = function(self, tb, sort) local g = self:ShallowCopy(tb) local len = #g @@ -244,6 +371,18 @@ M.MergeSort = function(self, tb, sort) end M.Sort = M.SlowSort +M.SortByMaxFirst = function(self, tb, map) + return self:Sort(tb, function(a, b) + return map(b) - map(a) + end) +end +M.SortByMinFirst = function(self, tb, map) + return self:Sort(tb, function(a, b) + return map(a) - map(b) + end) +end + +-- bot mode behaviour M.SeriouslyRetreatingStunSomeone = function(self, npcBot, abilityIndex, ability, targetType) if not ability:IsFullyCastable() then @@ -313,6 +452,9 @@ M.IsAttackingEnemies = function(self, npcBot) return mode == BOT_MODE_ROAM or mode == BOT_MODE_TEAM_ROAM or mode == BOT_MODE_ATTACK or mode == BOT_MODE_DEFEND_ALLY end +M.IsRetreating = function(self, npcBot) + return npcBot:GetActiveMode() == BOT_MODE_RETREAT +end M.NotRetreating = function(self, npcBot) return npcBot:GetActiveMode() ~= BOT_MODE_RETREAT end @@ -325,18 +467,185 @@ M.HasEnoughManaToUseAttackAttachedAbility = function(self, npcBot, ability) return percent >= 0.4 and npcBot:GetMana() >= 300 and npcBot:GetManaRegen() >= npcBot:GetAttackSpeed() / 100 * ability:GetManaCost() * 0.75 end +-- function generator + -- turn a function that returns true, false, nil to a function that decides whether to toggle the ability or not M.ToggleFunctionToAction = function(self, npcBot, oldConsider, ability) return function() - local value = oldConsider() - if value == nil or value == ability:GetToggleState() then - return 0 - else + local value, target, castType = oldConsider() + if type(value) == "number" then + return value, target, castType + end + if value ~= ability:GetToggleState() and ability:IsFullyCastable() then return BOT_ACTION_DESIRE_HIGH + else + return 0 + end + end +end + +M.ToggleFunctionToAutoCast = function(self, npcBot, oldConsider, ability) + return function() + local value, target, castType = oldConsider() + if type(value) == "number" then + return value, target, castType + end + if ability:IsFullyCastable() and value ~= ability:GetAutoCastState() then + ability:ToggleAutoCast() + end + return 0 + end +end + +M.PreventAbilityAtIllusion = function(self, npcBot, oldConsiderFunction, ability) + return function() + local desire, target, targetTypeString = oldConsiderFunction() + if desire == 0 or target == nil or target == 0 or self:IsVector(target) or targetTypeString == "Location" then + return desire, target, targetTypeString + end + if self:MustBeIllusion(npcBot, target) then + return 0 + end + return desire, target, targetTypeString + end +end + +M.PreventEnemyTargetAbilityUsageAtAbilityBlock = function(self, npcBot, oldConsiderFunction, ability) + local newConsider = function() + -- TODO: do we consider the base cooldown or the modified cooldown (arcane rune, octarine orb)? Will you crack a sphere's spell block with an ultimate ability when you're on arcane rune? + local desire, target, targetTypeString = oldConsiderFunction() + if desire == 0 or target == nil or target == 0 or self:IsVector(target) or targetTypeString == "Location" then + --if self:IsVector(target) then + -- print("npcBot "..npcBot:GetUnitName().." lands target ability "..ability:GetName().." at location "..self:ToStringVector(target)) + --end + return desire, target, targetTypeString end + local oldDesire = desire + if npcBot:GetTeam() ~= target:GetTeam() then -- some ability can cast to both allies and enemies (abbadon_mist_coil, etc) + local cooldown = ability:GetCooldown() + local abilityImportance = self:GetAbilityImportance(cooldown) + + if target:HasModifier("modifier_antimage_counterspell") then + return 0 + end + if target:HasModifier "modifier_item_sphere" or target:HasModifier("modifier_roshan_spell_block") or target:HasModifier("modifier_special_bonus_spell_block") then -- qop lv 25 + if cooldown >= 30 then + desire = desire - abilityImportance + elseif cooldown <= 20 then + desire = desire + abilityImportance + end + end + if target:HasModifier("modifier_item_sphere_target") then + if cooldown >= 60 then + desire = 0 + elseif cooldown >= 30 then + desire = desire - abilityImportance + 0.1 + elseif cooldown <= 20 then + desire = desire + abilityImportance + if abilityImportance > 0.1 then + desire = desire - 0.1 + end + end + end + if target:HasModifier("modifier_item_lotus_orb_active") then + if npcBot:GetActiveMode() == BOT_MODE_RETREAT then + desire = 0 + else + desire = desire - abilityImportance/2 + end + end + if target:HasModifier("modifier_mirror_shield_delay") then + desire = desire - abilityImportance*1.5 + end + + desire = self:TrimDesire(desire) + end + if desire ~= oldDesire then + print("desire modified from "..oldDesire.." to "..desire) + end + return desire, target, targetTypeString + end + return newConsider +end + +M.GetUsedAbilityInfo = function(self, ability, abilityInfoTable, considerTarget) + abilityInfoTable.lastUsedTime = DotaTime() + abilityInfoTable.lastUsedCharge = ability:GetCurrentCharges() + abilityInfoTable.lastUsedTarget = considerTarget + abilityInfoTable.lastUsedRemainingCooldown = ability:GetCooldownTimeRemaining() +end + +M.AddCooldownToChargeAbility = function(self, oldConsider, ability, abilityInfoTable, additionalCooldown) + return function() + if abilityInfoTable.lastUsedTime == nil then + abilityInfoTable.lastUsedTime = DotaTime() + end + if not (ability:GetCurrentCharges() > 0 and ability:IsFullyCastable()) then + return 0 + end + if DotaTime() <= abilityInfoTable.lastUsedTime + additionalCooldown and abilityInfoTable.lastUsedCharge >= ability:GetCurrentCharges() and abilityInfoTable.lastUsedRemainingCooldown <= ability:GetCooldownTimeRemaining() then + return 0 + end + return oldConsider() end end + + +M.AutoModifyConsiderFunction = function(self, npcBot, considers, abilitiesReal) + for index, ability in pairs(abilitiesReal) do + if not binlib.Test(ability:GetBehavior(), ABILITY_BEHAVIOR_PASSIVE) and considers[index] == nil then + print("Missing consider function "..ability:GetName()) + elseif binlib.Test(ability:GetTargetTeam(), ABILITY_TARGET_TEAM_ENEMY) and binlib.Test(ability:GetTargetType(), binlib.Or(ABILITY_TARGET_TYPE_HERO, ABILITY_TARGET_TYPE_CREEP, ABILITY_TARGET_TYPE_BUILDING)) and binlib.Test(ability:GetBehavior(), ABILITY_BEHAVIOR_UNIT_TARGET) then + considers[index] = self.PreventAbilityAtIllusion(self, npcBot, considers[index], ability) + if not self:IgnoreAbilityBlock(ability) then + considers[index] = self.PreventEnemyTargetAbilityUsageAtAbilityBlock(self, npcBot, considers[index], ability) + end + end + end +end + +-- unit function + +M.GetTargetHealAmplifyPercent = function(self, npc) + local modifiers = npc:FindAllModifiers() + local amplify = 1 + for i, modifier in pairs(modifiers) do + local a = (modifier:GetModifierHealAmplify_PercentageSource()) + if a ~= 0 then + print("modifier: "..modifier:GetName()..", heal amplify source:"..a..", target:"..modifier:GetModifierHealAmplify_PercentageTarget()) + end + local modifierName = modifier:GetName() + if modifierName == "modifier_ice_blast" then + return 0 + end + if modifierName == "modifier_item_spirit_vessel_damage" then + amplify = amplify - 0.45 + end + if modifierName == "modifier_holy_blessing" then + amplify = amplify + 0.3 + end + if modifierName == "modifier_necrolyte_sadist_active" then -- ghost shroud + amplify = amplify + 0.75 + end + if modifierName == "modifier_wisp_tether_haste" then + amplify = amplify + 0.6 -- 0.8/1/1.2 + end + if modifierName == "modifier_oracle_false_promise" then + amplify = amplify + 1 + end + end + return amplify +end + +M.IsChannelingItem = function(self, npc) + return npc:HasModifier("modifier_item_meteor_hammer") or npc:HasModifier("modifier_teleporting") or npc:HasModifier("modifier_boots_of_travel_incoming") +end + +M.IsChannelingAbility = function(self, npc) + return npc:IsChanneling() and not self:IsChannelingItem(npc) +end + local GetOtherTeam = function(team) if team == TEAM_RADIANT then return TEAM_DIRE @@ -359,7 +668,7 @@ end M.MustBeIllusion = function(self, npcBot, target) if npcBot:GetTeam() == target:GetTeam() then - return target:IsIllusion() + return target:IsIllusion() and not target:HasModifier("modifier_skeleton_king_reincarnation_active") end if self:Contains(self:GetTeamPlayers(npcBot:GetTeam()), target:GetPlayerID()) then return true @@ -368,21 +677,92 @@ M.MustBeIllusion = function(self, npcBot, target) end M.MayNotBeIllusion = function(self, npcBot, target) return not self:MustBeIllusion(npcBot, target) end -M.GetNearbyNonIllusionHeroes = function(self, npcBot, range, getEnemy, additionalParameter) - local heroes = npcBot:GetNearbyHeroes(range, getEnemy, additionalParameter) +M.GetNearbyNonIllusionHeroes = function(self, npcBot, range, getEnemy, botModeMask) + botModeMask = botModeMask or BOT_MODE_NONE + local heroes = npcBot:GetNearbyHeroes(range, getEnemy, botModeMask) return self:Filter(heroes, function(t) return self:MayNotBeIllusion(npcBot, t) end) end -M.GetEnemyHeroNumber = function(self, npcBot, enemies) +function M:GetNearbyAttackableCreeps(npcBot, range, getEnemy) + local creeps = npcBot:GetNearbyCreeps(range, getEnemy) + if getEnemy then + creeps = self:Filter(creeps, function(t) return t:HasModifier("modifier_fountain_glyph") end) + end + return creeps +end + +M.GetNearbyAllUnits = function(self, npcBot, range) + local h1 = npcBot:GetNearbyHeroes(range, true, BOT_MODE_NONE) + local h2 = self:Remove(npcBot:GetNearbyHeroes(range, false, BOT_MODE_NONE), npcBot) + local h3 = npcBot:GetNearbyCreeps(range, true) + local h4 = npcBot:GetNearbyCreeps(range, false) + return self:Concat(h1, h2, h3, h4) +end + +M.GetEnemyHeroUnique = function(self, npcBot, enemies) local p = self:Filter(enemies, function(t) self:MayNotBeIllusion(npcBot, t) end) + local g = {} local readNames = {} for _, enemy in pairs(p) do local name = enemy:GetUnitName() if not self:Contains(readNames, name) then table.insert(readNames, name) + table.insert(g, enemy) + end + end + return g +end + +M.GetMovementSpeedPercent = function(self, npc) + return npc:GetCurrentMovementSpeed() / npc:GetBaseMovementSpeed() +end +M.CanHardlyMove = function(self, npc) + return npc:IsStunned() or npc:IsRooted() or npc:GetCurrentMovementSpeed() <= 150 +end + +M.GetModifierRemainingDuration = function(self, npc, modifierName) + local mod = npc:GetModifierByName(modifierName) + if mod ~= -1 then + return npc:GetModifierRemainingDuration(mod) + end + return nil +end +M.ImprisonmentModifier = { + "modifier_item_cyclone", + "modifier_item_wind_waker", + "modifier_shadow_demon_disruption", + "modifier_obsidian_destroyer_astral_imprisonment_prison", + "modifier_brewmaster_storm_cyclone", + "modifier_invoker_tornado", + --"modifier_x_marks_the_target", +} +M.GetImprisonmentRemainingDuration = function(self, npc) + return self:First(self:Map(self.ImprisonmentModifier, function(t) return self:GetModifierRemainingDuration(npc, t) end), function(t) return t ~= nil end) +end + +M.GetEnemyHeroNumber = function(self, npcBot, enemies) + return #self:GetEnemyHeroUnique(npcBot, enemies) +end + +M.GetAvailableItem = function(self, npc, itemName) + for i = 0,6 do + local item = npc:GetItemInSlot(i) + if item ~= nil and item:GetName() == itemName then + return item end end - return #readNames +end + +M.GetAvailableBlink = function(self, npc) + local blinks = { + "item_blink", + "item_overwhelming_blink", + "item_swift_blink", + "item_arcane_blink", + } + return self:Aggregate(nil, blinks, function(a, blinkName) + return a or self:GetAvailableItem(blinkName) + end) end M.GetEmptyItemSlots = function(self, npc) @@ -439,6 +819,31 @@ M.GetInventoryItems = function(self, npc) return g end +function M:GetCourierItems(courier) + if courier ~= nil then + for i = 0, 8 do + local item = courier:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + end + return g +end + +M.GetAllBoughtItems = function(self) + local g = {} + local npcBot = GetBot() + for i = 0, 15 do + local item = npcBot:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + g = self:Concat(g, self:GetCourierItems(GetCourier(0))) + return g +end + M.IsBoots = function(self, item) if type(item) ~= "string" then item = item:GetName() @@ -452,7 +857,11 @@ M.SwapCheapestItemToBackpack = function(self, npc) print(npc:GetUnitName()..": only have shoes in inventory") return false end - return self:SwapItemToBackpack(npc, cheapestItem.itemIndex) + return self:SwapItemToBackpack(npc, cheapestItem.slotIndex) +end + +M.SuitableForSilence = function(self, npc, target) + return self:MayNotBeIllusion(npc, target) and not target:IsMagicImmune() and not target:IsInvulnerable() end local heroNameTable = {} @@ -462,11 +871,14 @@ setmetatable(heroNameTable, { M.GetHeroFullName = function(self, s) return "npc_dota_hero_"..s end +M.GetHeroShortName = function(self, s) + return string.sub(s, 12) +end M.IsMeleeHero = function(self, npc) local range = npc:GetAttackRange() local name = npc:GetUnitName() - return range <= 210 or name == self:GetHeroFullName("tiny") or name == self:GetHeroFullName("doom_bringer") + return range <= 210 or name == self:GetHeroFullName("tiny") or name == self:GetHeroFullName("doom_bringer") or name == self:GetHeroFullName("pudge") end M.AttackPassiveAbilities = { @@ -497,6 +909,90 @@ M.IgnoreAbilityBlock = function(self, ability) return self:Contains(self.AttackPassiveAbilities, abilityName) or self:Contains(self.IgnoreAbilityBlockAbilities, abilityName) or self:Contains(self.OtherIgnoreAbilityBlockAbilities, abilityName) end +M.AbilityRetargetModifiers = { + "modifier_antimage_counterspell", + "modifier_item_lotus_orb_active", + "modifier_nyx_assassin_spiked_carapace", + "modifier_item_blade_mail", +} +M.HasAbilityRetargetModifier = function(self, npc) + return self:Any(self.AbilityRetargetModifiers, function(t) return npc:HasModifier(t) end) +end + +M.CanMove = function(self, npc) + return not npc:IsStunned() and not npc:IsRooted() +end + +M.IsSeverlyDisabled = function(self, npc) + return npc:IsStunned() or npc:IsHexed() or npc:IsRooted() or self:GetMovementSpeedPercent(npc) <= 0.4 or npc:IsNightmared() +end + +M.EtherealModifiers = { + "modifier_ghost_state", + "modifier_item_ethereal_blade_slow", + "modifier_necrolyte_death_seeker", + "modifier_necrylte_sadist_active", + "modifier_pugna_decrepify", +} +M.IsEthereal = function(self, npc) + return self:Any(self.EtherealModifiers, function(t) return npc:HasModifier(t) end) +end + +M.CannotBeAttacked = function(self, npc) + return self:IsEthereal() or self:IsInvulnerable() +end + +M.ShouldNotBeAttacked = function(self, npc) + return self:CannotBeAttacked(npc) or self:Any(self.IgnoreDamageModifiers, function(t) return npc:HasModifier(t) end) or self:Any(self.IgnorePhysicalDamageModifiers, function(t) return npc:HasModifier(t) end) +end + +M.IsPhysicalOutputDisabled = function(self, npc) + return npc:IsDisarmed() or npc:IsBlind() or self:IsEthereal(npc) +end + +M.GetHealthPercent = function(self, npc) + return npc:GetHealth() / npc:GetMaxHealth() +end + +M.GetManaPercent = function(self, npc) + return npc:GetMana() / npc:GetMaxMana() +end + +M.BasicDispellablePositiveModifiers = { + "modifier_ember_spirit_flame_guard", + "modifier_legion_commander_press_the_attack", + "modifier_windrunner_windrun", + "modifier_lich_frost_shield", + "modifier_oracle_purifying_flames", + "modifier_treant_living_armor", + "modifier_mirana_leap_buff", + "modifier_necrolyte_death_seeker", + "modifier_necrylte_sadist_active", + "modifier_pugna_decrepify", + "modifier_ghost_state", + "modifier_spirit_breaker_bulldoze", +} + +function M:IndexOfBasicDispellablePositiveModifier(npc) + return self:Aggregate(nil, self.BasicDispellablePositiveModifiers, function(seed, modifier, index) + if seed then + return seed + end + local b = npc:HasModifier(modifier) + if b then + return index + else + return nil + end + end) or -1 +end + +function M:HasBasicDispellablePositiveModifier(npc) + return self:Any(self.BasicDispellablePositiveModifiers, function(t) return t:HasModifier(t) end) +end + +-- debug functions + M.DebugTable = function(self, tb) local msg = "{ " local DebugRec @@ -552,6 +1048,8 @@ M.PrintAbilities = function(self, npcBot) print(abilityNames) end +-- ability function + M.SpecialBonusAttributes = "special_bonus_attributes" M.TalentNamePrefix = "special_bonus_" M.IncorrectAbilityName = "incorrect_name" @@ -642,6 +1140,8 @@ M.ExecuteAbilityLevelUp = function(self, npcBot) abilityTable.justLevelUpAbility = true end +-- geometry + M.IsVector = function(self, object) return type(object)=="userdata" and type(object.x)=="number" and type(object.y)=="number" and type(object.z)=="number" and type(object.Length) == "function" end @@ -649,127 +1149,92 @@ M.ToStringVector = function(self, object) return string.format("(%d,%d,%d)",object.x,object.y,object.z) end -M.PreventAbilityAtIllusion = function(self, npcBot, oldConsiderFunction, ability) - return function() - local desire, target, targetTypeString = oldConsiderFunction() - if desire == 0 or target == nil or target == 0 or self:IsVector(target) or targetTypeString == "Location" then - return desire, target, targetTypeString - end - if self:MustBeIllusion(npcBot, target) then - return 0 - end - return desire, target, targetTypeString +M.GetLine = function(self, a, b) + if a.x == b.x then + return { a = 1, b = 0, c = -a.x } end + local k = (a.y-b.y)/(a.x-b.x) + local bb = a.y-k*a.x + return { a = k, b = -1, c = bb } end -M.PreventEnemyTargetAbilityUsageAtAbilityBlock = function(self, npcBot, oldConsiderFunction, ability) - local newConsider = function() - -- TODO: do we consider the base cooldown or the modified cooldown (arcane rune, octarine orb)? Will you crack a sphere's spell block with an ultimate ability when you're on arcane rune? - local desire, target, targetTypeString = oldConsiderFunction() - if desire == 0 or target == nil or target == 0 or self:IsVector(target) or targetTypeString == "Location" then - if self:IsVector(target) then - print("npcBot "..npcBot:GetUnitName().." lands target ability "..ability:GetName().." at location "..self:ToStringVector(target)) - end - return desire, target, targetTypeString - end - local oldDesire = desire - if npcBot:GetTeam() ~= target:GetTeam() then -- some ability can cast to both allies and enemies (abbadon_mist_coil, etc) - local cooldown = ability:GetCooldown() - local abilityImportance = self:GetAbilityImportance(cooldown) +M.GetPointToLineDistance = function(self, point, line) + local up = math.abs(line.a*point.x+line.b*point.y+line.c) + local down = math.sqrt(line.a*line.a+line.b*line.b) + return up/down +end - if target:HasModifier("modifier_antimage_counterspell") then - return 0 - end - if target:HasModifier "modifier_item_sphere" or target:HasModifier("modifier_roshan_spell_block") or target:HasModifier("modifier_special_bonus_spell_block") then -- qop lv 25 - if cooldown >= 30 then - desire = desire - abilityImportance - elseif cooldown <= 20 then - desire = desire + abilityImportance - end - end - if target:HasModifier("modifier_item_sphere_target") then - if cooldown >= 60 then - desire = 0 - elseif cooldown >= 30 then - desire = desire - abilityImportance + 0.1 - elseif cooldown <= 20 then - desire = desire + abilityImportance - if abilityImportance > 0.1 then - desire = desire - 0.1 - end - end - end - if target:HasModifier("modifier_item_lotus_orb_active") then - if npcBot:GetActiveMode() == BOT_MODE_RETREAT then - desire = 0 - else - desire = desire - abilityImportance/2 - end - end - if target:HasModifier("modifier_mirror_shield_delay") then - desire = desire - abilityImportance*1.5 - end +-- Get the location on the line determined by startPoint and endPoint, with distance from startPoint to the target location +M.GetPointFromLineByDistance = function(self, startPoint, endPoint, distance) + local line = self:GetLine(startPoint, endPoint) + local distanceTo = math.sqrt(math.pow(startPoint.x-endPoint.x, 2)+math.pow(startPoint.y-endPoint.y, 2)) + local divide = distanceTo / distance + local point = { x = startPoint.x + divide*(endPoint.x-startPoint.x), y = startPoint.y + divide*(endPoint.y-endPoint.x), z = 0 } + return point +end - desire = self:TrimDesire(desire) +M.MinValue = function(self, coefficients, min, max) + max = max or 10000 + min = min or -10000 + local function Differential(coefficients) + local g = {} + for index, coefficient in pairs(coefficients) do + g[index-1] = coefficient*index end - if desire ~= oldDesire then - print("desire modified from "..oldDesire.." to "..desire) + return g + end + local function Y(coefficients, x) + local g = 0 + for index, coefficient in pairs(coefficients) do + g = g + coefficient * x ^ index end - return desire, target, targetTypeString + return g end - return newConsider -end -M.AutoModifyConsiderFunction = function(self, npcBot, considers, abilitiesReal) - for index, ability in pairs(abilitiesReal) do - if not binlib.Test(ability:GetBehavior(), ABILITY_BEHAVIOR_PASSIVE) and considers[index] == nil then - print("Missing consider function "..ability:GetName()) - elseif binlib.Test(ability:GetTargetTeam(), ABILITY_TARGET_TEAM_ENEMY) and binlib.Test(ability:GetTargetType(), binlib.Or(ABILITY_TARGET_TYPE_HERO, ABILITY_TARGET_TYPE_CREEP, ABILITY_TARGET_TYPE_BUILDING)) and binlib.Test(ability:GetBehavior(), ABILITY_BEHAVIOR_UNIT_TARGET) then - considers[index] = self.PreventAbilityAtIllusion(self, npcBot, considers[index], ability) - if not self:IgnoreAbilityBlock(ability) then - considers[index] = self.PreventEnemyTargetAbilityUsageAtAbilityBlock(self, npcBot, considers[index], ability) + local differential = Differential(coefficients) + if differential[1] ~= nil and differential[1] ~= 0 then + local zeroPoint = -differential[0]/differential[1] + if Y(coefficients, zeroPoint+0.1)>0 then + if zeroPoint > max then + return Y(coefficients, max) + elseif zeroPoint < min then + return Y(coefficients, min) + else + return Y(coefficients, zeroPoint) + end + else + if zeroPoint > max then + return Y(coefficients, min) + elseif zeroPoint < min then + return Y(coefficients, max) + else + local val1 = Y(coefficients, min) + local val2 = Y(coefficients, min) + return math.min(val1, val2) end end + else + return Y(coefficients, min) end end -M.GetHealthPercent = function(self, npc) - return npc:GetHealth() / npc:GetMaxHealth() +M.MaxValue = function(self, coefficients, min, max) + local g = {} + for index, coefficient in coefficients do + g[index] = -coefficient + end + return self:MinValue(g, -max, -min) end -M.GetManaPercent = function(self, npc) - return npc:GetMana() / npc:GetMaxMana() -end - -M.GetTargetHealAmplifyPercent = function(self, npc) - local modifiers = npc:FindAllModifiers() - local amplify = 1 - for i, modifier in pairs(modifiers) do - local a = (modifier:GetModifierHealAmplify_PercentageSource()) - if a ~= 0 then - print("modifier: "..modifier:GetName()..", heal amplify source:"..a..", target:"..modifier:GetModifierHealAmplify_PercentageTarget()) - end - local modifierName = modifier:GetName() - if modifierName == "modifier_ice_blast" then - return 0 - end - if modifierName == "modifier_item_spirit_vessel_damage" then - amplify = amplify - 0.45 - end - if modifierName == "modifier_holy_blessing" then - amplify = amplify + 0.3 - end - if modifierName == "modifier_necrolyte_sadist_active" then -- ghost shroud - amplify = amplify + 0.75 - end - if modifierName == "modifier_wisp_tether_haste" then - amplify = amplify + 0.6 -- 0.8/1/1.2 - end - if modifierName == "modifier_oracle_false_promise" then - amplify = amplify + 1 - end - end - return amplify +M.GetCollapseInfo = function(self, obj1, obj2, timeLimit) + local x1 = obj1.location.x-obj2.location.x + local x2 = obj1.velocity.x-obj2.velocity.x + local coefficient0 = x1^2 + local coefficient1 = 2*x1*x2 + local coefficient3 = x2^2 + x1 = obj1.location.y-obj2.location.y + x2 = obj2.velocity.y-obj2.velocity.y + coefficient0 = coefficient0 end M.PreventHealAtHealSuppressTarget = function(self, npcBot, oldConsiderFunction, ability) @@ -797,26 +1262,130 @@ M.PURCHASE_ITEM_SUCCESS=-1 -- invalid order(40) order not allowed for illusions -- attempt to purchase "item_energy_booster" failed code 68 -M.CannotBeKilledNormally = function(self, target) - return target:IsInvulnerable() or target:HasModifier("modifier_abaddon_borrowed_time") or target:HasModifier("modifier_dazzle_shallow_grave") or target:HasModifier("modifier_aeon_disk") +M.IgnoreDamageModifiers = { + "modifier_abaddon_borrowed_time", + "modifier_aeon_disk", + "modifier_winter_wyvern_winters_curse", + "modifier_winter_wyvern_winters_curse_aura", + "modifier_skeleton_king_reincarnation_scepter_active", +} + +M.IgnorePhysicalDamageModifiers = { + "modifier_winter_wyvern_cold_embrace", +} +M.IgnoreMagicalDamageModifiers = { + "modifier_oracle_fates_edict", +} + +M.LastForAtLeastSeconds = function(self, predicate, time, infoTable) + if infoTable.lastTrueTime == nil then + infoTable.lastTrueTime = DotaTime() + end + if predicate() then + if DotaTime() - infoTable.lastTrueTime >= time then + return true + else + return false + end + else + infoTable.lastTrueTime = nil + return false + end end -M.HasScepter = function(self, npc) - return npc:HasScepter() or npc:HasModifier("modifier_wisp_tether_scepter") +M.GoodIllusionHero = { + "antimage","spectre","terrorblade","naga_siren", +} +M.ModerateIllusionHero = { + "abaddon","axe","chaos_knight","arc_warden","juggernaut","luna","medusa","morphling","phantom_lancer","sniper","wraith_king","phantom_assassin", +} +M.GetIllusionBattlePower = function(self, npc) + local name = self:GetHeroShortName(npc:GetUnitName()) + if npc:HasModifier("modifier_arc_warden_tempest_double") or npc:HasModifier("modifier_skeleton_king_reincarnation_active") then + return 0.8 + end + local t = 0.1 + if self:Contains(self.GoodIllusionHero, name) then + t = 0.25 + elseif self:Contains(self.ModerateIllusionHero, name) then + t = 0.4 + elseif t:IsRanged() then + t = t + t:GetAttackRange() / 600 + end + local inventory = self:Map(self:GetInventoryItems(npc), function(t) return t:GetName() end) + if self:Contains(inventory, "item_radiance") then + t = t+0.07 + end + if self:Contains(inventory, "item_diffusal_blade") then + t = t+0.05 + end + if self:Contains(inventory, "item_lesser_crit") then + t = t+0.04 + end + if self:Contains(inventory, "item_greater_crit") then + t = t+0.08 + end + if npc:HasModifier("modifier_special_bonus_mana_break") then-- mirana talent[5] + t = t+0.04 + end + return t end -M.CheckForBestTarget = function(self, npc, ability, targets, filter, map, sort, select) - local g = {} - for _, target in ipairs(targets) do - if filter(npc, ability, target) then - table.insert(g, map) +M.GetNetWorth = function(self, npc, isEnemy) + if isEnemy then + local itemCost = self:Map(self:GetInventoryItems(npc), function(t) return GetItemCost(t:GetName()) end) + return self:Aggregate(0, itemCost, function(a, b) return a+b end) + else + return npc:GetNetWorth() + end +end + +M.GetHeroGroupNetWorth = function(self, heroes, isEnemy) + local function A(tb) + tb = self:SortByMaxFirst(tb, function(t) return t:GetNetWorth() end) + local f = self:Map(tb, function(t, index) return t:GetNetWorth() * 1.15-0.15*index end) + local g = {} + for _,v in ipairs(f) do + g[v:GetUnitName()] = v end + return g end - self:Sort(g, sort) - if g[1] == nil then - return nil + local enemyNetWorthMap = A(self:GetEnemyHeroUnique(heroes)) + local netWorth = 0 + local readNames = {} + for _, enemy in pairs(heroes) do + local name = enemy:GetUnitName() + if not self:Contains(readNames, name) then + table.insert(readNames, name) + netWorth = netWorth + enemyNetWorthMap[name] + else + netWorth = netWorth + enemyNetWorthMap[name] * self:GetIllusionBattlePower(enemy) + end end - return select(g[1]) + return netWorth +end + +M.Outnumber = function(self, friends, enemies) + return self:GetHeroGroupNetWorth(friends, false) >= self:GetHeroGroupNetWorth(enemies, true) * 1.8 +end + + +M.CannotBeKilledNormally = function(self, target) + return target:IsInvulnerable() or self:Any(self.IgnoreDamageModifiers, function(t) target:HasModifier(t) end) or target:HasModifier("modifier_dazzle_shallow_grave") +end + +M.HasScepter = function(self, npc) + return npc:HasScepter() or npc:HasModifier("modifier_wisp_tether_scepter") +end + + +-- Courier system + +M.CourierUsageThink = function(self) + local npcBot = GetBot() + local courier = GetCourier(0) + local items = self:GetCourierItems() + end return M diff --git a/util/ItemPurchaseSystem.lua b/util/ItemPurchaseSystem.lua index 15d09b68..728a9623 100644 --- a/util/ItemPurchaseSystem.lua +++ b/util/ItemPurchaseSystem.lua @@ -595,7 +595,7 @@ function M.BuySupportItem() npcBot:ActionImmediate_PurchaseItem( "item_dust" ); end - if (DotaTime()>=30*60 and npcBot:GetGold() >= GetItemCost("item_gem") and GetItemStockCount("item_gem") >= 1) and AbilityExtensions:GetEmptyItemSlots(npcBot) >= 1 + if (DotaTime()>=25*60 and npcBot:GetGold() >= GetItemCost("item_gem") and GetItemStockCount("item_gem") >= 1) and AbilityExtensions:GetEmptyItemSlots(npcBot) >= 1 then if AbilityExtensions:GetEmptyItemSlots(npcBot) >= 1 and AbilityExtensions:GetEmptyBackpackSlots(npcBot) == 0 then npcBot:ActionImmediate_PurchaseItem( "item_gem" ) @@ -701,7 +701,7 @@ M.GetAllBoughtItems = function(self) end local courier = GetCourier(0) if courier ~= nil then - for i = 0, 5 do + for i = 0, 8 do local item = courier:GetItemInSlot(i) if item then table.insert(g, item) @@ -711,6 +711,8 @@ M.GetAllBoughtItems = function(self) return g end + + M.CreateItemInformationTable = function(self, npcBot, itemTable) local function ExpandFirstLevel(item) if isLeaf(item) then @@ -735,8 +737,18 @@ M.CreateItemInformationTable = function(self, npcBot, itemTable) item.recipe = g return expandSomething end + local function TranslateToEquivalentItem(tb) + local k = "item_power_treads" + tb = AbilityExtensions:Replace(tb, function(t) + return #t > #k and string.sub(t, 1, #k) == k + end, function(t) + return k + end) + return tb + end local function RemoveBoughtItems() -- used only when reloading scripts in game - local boughtItems = AbilityExtensions:Map(self:GetAllBoughtItems(), function(t) return t:GetName() end) + local boughtItems = AbilityExtensions:Map(self:GetAllBoughtItems(), function(t) return t:GetName() end) + boughtItems = TranslateToEquivalentItem(boughtItems) local function TryRemoveItem(itemName, tbToRemoveFirst) if DotaTime() > -60 and self:IsConsumableItem(itemName) then table.remove(tbToRemoveFirst, 1) diff --git a/util/ItemUsageSystem.lua b/util/ItemUsageSystem.lua index 2dce1afd..933755d9 100644 --- a/util/ItemUsageSystem.lua +++ b/util/ItemUsageSystem.lua @@ -49,9 +49,10 @@ end local function GiveToMidLaner() local teamPlayers = GetTeamPlayers(GetTeam()) --local target = nil + if DotaTime() <= 0 then return nil end for k, _ in pairs(teamPlayers) do local member = GetTeamMember(k) - if member ~= nil and not member:IsIllusion() and member:IsAlive() then + if member ~= nil and not member:IsIllusion() and member:IsAlive() and member:GetMaxHealth()-member:GetHealth() >= 150 then local num_sts = GetItemCount(member, "item_tango_single") local num_ff = GetItemCount(member, "item_faerie_fire") local num_stg = GetItemCharges(member, "item_tango") @@ -80,7 +81,7 @@ local function IsItemAvailable(item_name) for i = 0, 5 do local item = npcBot:GetItemInSlot(i) if (item ~= nil) then - if (item:GetName() == item_name) then + if (item:GetName() == item_name) and item:IsFullyCastable() then return item end end @@ -296,26 +297,62 @@ function M.UnImplementedItemUsage() end end - local pt = IsItemAvailable("item_power_treads") - if pt ~= nil and pt:IsFullyCastable() then - if - mode == BOT_MODE_RETREAT and pt:GetPowerTreadsStat() ~= ATTRIBUTE_STRENGTH and - npcBot:WasRecentlyDamagedByAnyHero(5.0) - then - npcBot:Action_UseAbility(pt) - return - elseif mode == BOT_MODE_ATTACK and CanSwitchPTStat(pt) then - npcBot:Action_UseAbility(pt) - return + local function GetWantedPowerTreadsAttribute() + if mode == BOT_MODE_RETREAT and npcBot:WasRecentlyDamagedByAnyHero(3) then + return ATTRIBUTE_STRENGTH + elseif AbilityExtensions:IsAttackingEnemies(npcBot) then + local name = npcBot:GetUnitName() + name = AbilityExtensions:GetHeroShortName(name) + if AbilityExtensions:Contains({"obsidian_destroyer","enchantress","silencer"}, name) then + return npcBot:GetPrimaryAttribute() + else + return ATTRIBUTE_AGILITY + end + elseif mode == BOT_MODE_LANING then + return npcBot:GetPrimaryAttribute() else - local enemies = npcBot:GetNearbyHeroes(1300, true, BOT_MODE_NONE) - if #enemies == 0 and mode ~= BOT_MODE_RETREAT and CanSwitchPTStat(pt) then - npcBot:Action_UseAbility(pt) - return + return npcBot:GetPrimaryAttribute() + end + end + local function UsePowerTreads(treads) + if math.floor(DotaTime()) / 4 ~= 0 then + return + end + if npcBot:IsInvisible() and npcBot:UsingItemBreakInvisibility() then + if npcBot:HasModifier("modifier_item_dust") then + npcBot:Action_UseAbility(treads) + return true end + return + end + if GetWantedPowerTreadsAttribute() ~= treads:GetPowerTreadsStat() then + print(npcBot:GetUnitName()..": power treads attribute "..treads:GetPowerTreadsStat()..", but I want "..GetWantedPowerTreadsAttribute()) + npcBot:Action_UseAbility(treads) + return true end end + local pt = IsItemAvailable("item_power_treads") + if pt ~= nil and pt:IsFullyCastable() then + UsePowerTreads(pt) + -- if + -- mode == BOT_MODE_RETREAT and pt:GetPowerTreadsStat() ~= ATTRIBUTE_STRENGTH and + -- npcBot:WasRecentlyDamagedByAnyHero(5.0) + -- then + -- npcBot:Action_UseAbility(pt) + -- return + -- elseif mode == BOT_MODE_ATTACK and CanSwitchPTStat(pt) then + -- npcBot:Action_UseAbility(pt) + -- return + -- else + -- local enemies = npcBot:GetNearbyHeroes(1300, true, BOT_MODE_NONE) + -- if #enemies == 0 and mode ~= BOT_MODE_RETREAT and CanSwitchPTStat(pt) then + -- npcBot:Action_UseAbility(pt) + -- return + -- end + -- end + end + local bas = IsItemAvailable("item_ring_of_basilius") if bas ~= nil and bas:IsFullyCastable() then if mode == BOT_MODE_LANING and not bas:GetToggleState() then @@ -362,11 +399,6 @@ function M.UnImplementedItemUsage() then local target = GiveToMidLaner() if target ~= nil then - --[[npcBot:ActionImmediate_Chat(string.gsub(npcBot:GetUnitName(),"npc_dota_hero_","").. - " giving tango to ".. - string.gsub(target:GetUnitName(),"npc_dota_hero_","").. - "Don't ask why we only give you one tango. We are poor. 别问我们为什么只给一颗吃树了,我们穷。" - , false);]] npcBot:Action_UseAbilityOnEntity(itg, target) giveTime = DotaTime() return @@ -461,25 +493,25 @@ function M.UnImplementedItemUsage() end end - local irt = IsItemAvailable("item_iron_talon") - if irt ~= nil and irt:IsFullyCastable() then - if npcBot:GetActiveMode() == BOT_MODE_FARM then - local neutrals = npcBot:GetNearbyNeutralCreeps(500) - local maxHP = 0 - local target = nil - for _, c in pairs(neutrals) do - local cHP = c:GetHealth() - if cHP > maxHP and not c:IsAncientCreep() then - maxHP = cHP - target = c - end - end - if target ~= nil then - npcBot:Action_UseAbilityOnEntity(irt, target) - return - end - end - end + -- local irt = IsItemAvailable("item_iron_talon") + -- if irt ~= nil and irt:IsFullyCastable() then + -- if npcBot:GetActiveMode() == BOT_MODE_FARM then + -- local neutrals = npcBot:GetNearbyNeutralCreeps(500) + -- local maxHP = 0 + -- local target = nil + -- for _, c in pairs(neutrals) do + -- local cHP = c:GetHealth() + -- if cHP > maxHP and not c:IsAncientCreep() then + -- maxHP = cHP + -- target = c + -- end + -- end + -- if target ~= nil then + -- npcBot:Action_UseAbilityOnEntity(irt, target) + -- return + -- end + -- end + -- end local msh = IsItemAvailable("item_moon_shard") if msh ~= nil and msh:IsFullyCastable() then @@ -508,7 +540,7 @@ function M.UnImplementedItemUsage() if ff ~= nil and ff:IsFullyCastable() then if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH and - (npcBot:GetHealth() / npcBot:GetMaxHealth()) < 0.15 + (npcBot:GetHealth() / npcBot:GetMaxHealth()) < 0.15 and npcBot:WasRecentlyDamagedByAnyHero(3) then npcBot:Action_UseAbility(ff) return @@ -534,7 +566,7 @@ function M.UnImplementedItemUsage() if bst ~= nil and bst:IsFullyCastable() then if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH and - (npcBot:GetHealth() / npcBot:GetMaxHealth()) < 0.10 + (npcBot:GetHealth() / npcBot:GetMaxHealth()) < 0.2 then npcBot:Action_UseAbilityOnLocation(bst, npcBot:GetLocation()) return @@ -1007,7 +1039,7 @@ function M.UnImplementedItemUsage() end local sentry = IsItemAvailable("item_ward_sentry") - if sentry ~= nil and sentry:IsFullyCastable() then + if sentry ~= nil and sentry:IsFullyCastable() and sentry:IsCooldownReady() then local NearbyTowers = npcBot:GetNearbyTowers(1600, true) local NearbyTowers2 = npcBot:GetNearbyTowers(800, true) local NearbyTowers3 = npcBot:GetNearbyTowers(800, false) diff --git a/util/PushUtility.lua b/util/PushUtility.lua index 4af2e78f..5191680a 100644 --- a/util/PushUtility.lua +++ b/util/PushUtility.lua @@ -2,6 +2,7 @@ _G._savedEnv = getfenv() module("PushUtility", package.seeall) local role = require(GetScriptDirectory() .. "/util/RoleUtility") +local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") function GetLane( nTeam ,hHero ) local vBot = GetLaneFrontLocation(nTeam, LANE_BOT, 0) @@ -333,7 +334,9 @@ function UnitPushLaneThink(npcBot,lane) StepBack( npcBot ) --print(getCurrentFileName().." "..getShortName(npcBot).." situation is not good"); elseif npcBot:WasRecentlyDamagedByTower(1) then --if I'm under attck of tower, then try to avoid attack - if(not TransferHatred( npcBot ) or (enemys~=nil and #enemys>=1)) + if not TransferHatred( npcBot ) or (enemys~=nil and #enemys>=1) or AbilityExtensions:Any(npcBot:GetNearbyTowers(700, true), function(t) + return t:GetAttackTarget() == npcBot and t:HasModifier("modifier_fountain_glyph") + end) then StepBack( npcBot ) --print(getCurrentFileName().." "..getShortName(npcBot).." attacked"); @@ -656,6 +659,34 @@ function StepBack( unit ) local targetloc = Normalized(spawnloc - unit:GetLocation()) * 500 + unit:GetLocation() unit:Action_MoveToLocation(targetloc+RandomVector( 100 ) ) end + +function StepBackCreeps(unit) + if not NotNilOrDead(unit) then + return + end + local tower = unit:GetNearbyTowers(700, true) + tower = AbilityExtensions:First(tower, function(t) return t:GetAttackTarget() == unit end) + if tower == nil then + return + end + + local friends = unit:GetNearbyHeroes(1200, false, BOT_MODE_NONE) + local enemies = unit:GetNearbyHeroes(1200, true, BOT_MODE_NONE) + local friendCreeps = tower:GetNearbyCreeps(tower:GetAttackRange(), true) + friendCreeps = AbilityExtensions:SortByMinFirst(friendCreeps, function(t) return GetUnitToUnitDistance(t, tower) end) + if #friendCreeps == 0 then + if AbilityExtensions:GetHealthPercent(unit) >= 0.75 or #friends >= #enemies + 1 and AbilityExtensions:GetHealthPercent(unit) >= 0.6 then + if tower:HasModifier("modifier_fountain_glyph") then + unit:Action_MoveDirectly(AbilityExtensions:GetPointFromLineByDistance(tower:GetLocation(), unit:GetLocation(), tower:GetAttackRange() + 10)) + end + end + else + local g = GetUnitToUnitDistance(tower, friendCreeps[1]) + 10 + unit:Action_MoveDirectly(AbilityExtensions:GetPointFromLineByDistance(tower:GetLocation(), unit:GetLocation(), g)) + coroutine.yield(g) + TransferHatred(unit) + end +end function Normalized(vector) local mod = ( vector.x ^ 2 + vector.y ^ 2 ) ^ 0.5