From 7f3ba0567fb0d17a50c7426d09ab400fb1468647 Mon Sep 17 00:00:00 2001 From: Aaron Song <31906374+AaronSong321@users.noreply.github.com> Date: Sat, 30 Apr 2022 11:43:23 +0800 Subject: [PATCH] Next version update (#64) Ogre_magi prefers to use bloodbust on allies with higher battle power; Decreate desire of zeus using thundergods_wrath at far enemies; Decrease necrolyte and zeus (again) use ultimate to steal kills; Fix omniknight never use purification on damaged allies when mana is enough; Fix faceless_void item purchase; Fix tusk, ember_spirit abilities; Add guardian_greaves to team item purchase; Disable brewmaster drunken_brawler for now; Add team arcane_boots purchase; Remove battle_fury and radiance from item build lists of some heroes; Fix shadow_demon, nyx_assasin cast certain abilities on creep heroes (i.e. lone_druid_bear, visage_familiar); --- ability_item_usage_abaddon.lua | 14 +- ability_item_usage_abyssal_underlord.lua | 8 +- ability_item_usage_alchemist.lua | 1 + ability_item_usage_ancient_apparition.lua | 19 - ability_item_usage_antimage.lua | 13 +- ability_item_usage_arc_warden.lua | 845 +++----- ability_item_usage_arc_warden.mira | 554 ++++++ ability_item_usage_axe.lua | 39 +- ability_item_usage_axe.mira | 28 +- ability_item_usage_bane.lua | 14 +- ability_item_usage_batrider.lua | 4 +- ability_item_usage_beastmaster.lua | 10 +- ability_item_usage_bloodseeker.lua | 6 +- ability_item_usage_bounty_hunter.lua | 10 +- ability_item_usage_brewmaster.lua | 5 +- ability_item_usage_bristleback.lua | 6 +- ability_item_usage_centaur.lua | 113 +- ability_item_usage_chen.lua | 18 +- ability_item_usage_clinkz.lua | 24 +- ability_item_usage_clinkz.mira | 6 +- ability_item_usage_doom_bringer.lua | 55 +- ability_item_usage_doom_bringer.mira | 47 +- ability_item_usage_ember_spirit.lua | 24 +- ability_item_usage_ember_spirit.mira | 2 +- ability_item_usage_faceless_void.lua | 14 +- ability_item_usage_faceless_void.mira | 2 +- ability_item_usage_furion.lua | 3 +- ability_item_usage_generic.lua | 56 +- ability_item_usage_jakiro.lua | 16 +- ability_item_usage_kunkka.lua | 17 +- ability_item_usage_kunkka.mira | 3 +- ability_item_usage_lion.lua | 2 + ability_item_usage_lycan.lua | 10 +- ability_item_usage_mirana.lua | 2 +- ability_item_usage_necrolyte.lua | 12 +- ability_item_usage_nyx_assassin.lua | 5 +- ability_item_usage_omniknight.lua | 20 +- ability_item_usage_oracle.lua | 6 +- ability_item_usage_puck.lua | 6 +- ability_item_usage_pudge.lua | 4 +- ability_item_usage_pudge.mira | 2 +- ability_item_usage_queenofpain.lua | 2 +- ability_item_usage_shadow_demon.lua | 23 +- ability_item_usage_shredder.lua | 23 +- ability_item_usage_skywrath_mage.lua | 74 +- ability_item_usage_sniper.lua | 1 - ability_item_usage_terrorblade.lua | 2 + ability_item_usage_tusk.lua | 28 +- ability_item_usage_undying.lua | 4 +- ability_item_usage_ursa.lua | 2 +- ability_item_usage_venomancer.lua | 4 +- ability_item_usage_warlock.lua | 2 +- ability_item_usage_zuus.lua | 87 +- bot_undying.lua | 13 +- item_purchase_abaddon.lua | 1 - item_purchase_antimage.lua | 3 +- item_purchase_axe.lua | 1 - item_purchase_bane.lua | 2 - item_purchase_batrider.lua | 2 +- item_purchase_clinkz.lua | 2 +- item_purchase_dragon_knight.lua | 5 +- item_purchase_life_stealer.lua | 3 +- item_purchase_lina.lua | 2 - item_purchase_ogre_magi.lua | 7 +- item_purchase_phantom_assassin.lua | 2 +- item_purchase_sand_king.lua | 2 +- item_purchase_shredder.lua | 5 +- item_purchase_skeleton_king.lua | 5 +- item_purchase_slark.lua | 2 +- item_purchase_spectre.lua | 8 +- item_purchase_troll_warlord.lua | 3 +- item_purchase_zuus.lua | 5 +- mode_laning_generic.lua | 8 +- util/AbilityAbstraction.lua | 71 +- util/AbilityAbstraction.mira | 41 +- util/CommonBehaviours.lua | 32 +- util/CommonBehaviours.mira | 48 +- util/ItemPurchaseSystem.lua | 257 ++- util/ItemPurchaseSystem.mira | 273 ++- util/ItemUsage-New.lua | 11 +- util/ItemUsage-New.mira | 14 + util/ItemUsageSystem.lua | 4 + util/MiraDota.lua | 2029 +++++++++++++++++++ util/MiraDota.mira | 2176 +++++++++++++++++++++ util/PushUtility.lua | 302 ++- util/TeamItemThink.lua | 631 +++++- util/TeamItemThink.mira | 317 ++- 87 files changed, 7089 insertions(+), 1495 deletions(-) create mode 100644 ability_item_usage_arc_warden.mira create mode 100644 util/MiraDota.lua create mode 100644 util/MiraDota.mira diff --git a/ability_item_usage_abaddon.lua b/ability_item_usage_abaddon.lua index d792d140..a168866f 100644 --- a/ability_item_usage_abaddon.lua +++ b/ability_item_usage_abaddon.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -106,11 +106,11 @@ Consider[1] = function() table.remove(allys, _) end end - local WeakestAlly,AllyHealth = utility.GetWeakestUnit(allys) + local WeakestAlly, AllyHealth = utility.GetWeakestUnit(allys) local enemys = npcBot:GetNearbyHeroes(CastRange + 150, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -178,11 +178,11 @@ Consider[2] = function() local allys = fun1:GetNearbyNonIllusionHeroes(npcBot, CastRange + 200, false):Filter(CanCast[2]):Filter(function(it) return it:WasRecentlyDamagedByAnyHero(4) or it:WasRecentlyDamagedByTower(2) end) - local WeakestAlly,AllyHealth = utility.GetWeakestUnit(allys) + local WeakestAlly, AllyHealth = utility.GetWeakestUnit(allys) local enemys = npcBot:GetNearbyHeroes(CastRange + 300, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local function Rate(it) local rate = 0 if it == npcBot then diff --git a/ability_item_usage_abyssal_underlord.lua b/ability_item_usage_abyssal_underlord.lua index 64464251..d1c3a64e 100644 --- a/ability_item_usage_abyssal_underlord.lua +++ b/ability_item_usage_abyssal_underlord.lua @@ -139,7 +139,7 @@ Consider[1]=function() --Location AOE Example -- Mode based usage -------------------------------------- -- If we're farming and can kill 3+ creeps with LSA - if npcBot:GetActiveMode() == BOT_MODE_FARM and mana > maxMana * 0.3 + manaCost then + if npcBot:GetActiveMode() == BOT_MODE_FARM and mana > maxMana * 0.55 + manaCost then local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), CastRange, Radius, 0, Damage ); if ( locationAoE.count >= 3 ) then @@ -314,9 +314,9 @@ end local function FindNearbyTeleportTarget(target) local isEnemy = not AbilityExtensions:IsOnSameTeam(npcBot, target) local castDelay = AbilitiesReal[4]:GetSpecialValueInt("cast_delay") - local creeps = target:GetNearbyCreeps(600, isEnemy) - creeps = AbilityExtensions:Filter(creeps, function(t) return not t:WasRecentlyDamagedByAnyHero(3) and #AbilityExtensions:GetNearbyHeroes(t, 500, true, BOT_MODE_NONE) == 0 end) - creeps = AbilityExtensions:Max(creeps, function(t) return t:GetHealth() end) + local creeps = AbilityExtensions:GetNearbyCreeps(target, 600, isEnemy) + :Filter(function(t) return not t:WasRecentlyDamagedByAnyHero(3) and #AbilityExtensions:GetNearbyHeroes(t, 500, true, BOT_MODE_NONE) == 0 end) + :Max(function(t) return t:GetHealth() end) local buildings = AbilityExtensions:Concat(target:GetNearbyTowers(700, isEnemy), target:GetNearbyBarracks(700, isEnemy)) buildings = AbilityExtensions:Filter(buildings, function(t) return t:HasModifier("modifier_backdoor_protection_active") and t:GetHealth() >= 100 or t:GetHealth() >= 300 and not t:WasRecentlyDamagedByAnyHero(castDelay-2) or t:GetHealth() >= 800 or t:HasModifier("modifier_fountain_glyph") end) buildings = AbilityExtensions:Max(buildings, function(t) return AbilityExtensions:GetBuildingPhysicalHealth(t) end) diff --git a/ability_item_usage_alchemist.lua b/ability_item_usage_alchemist.lua index 3db22c77..b60cbd02 100644 --- a/ability_item_usage_alchemist.lua +++ b/ability_item_usage_alchemist.lua @@ -8,6 +8,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local ItemUsage = require(GetScriptDirectory().."/util/ItemUsage-New") local debugmode=false diff --git a/ability_item_usage_ancient_apparition.lua b/ability_item_usage_ancient_apparition.lua index a458c6f2..b2bc6c00 100644 --- a/ability_item_usage_ancient_apparition.lua +++ b/ability_item_usage_ancient_apparition.lua @@ -234,7 +234,6 @@ Consider[1]=function() end Consider[2]=function() - local abilityNumber=2 -------------------------------------- -- Generic Variable Setting @@ -256,24 +255,6 @@ Consider[2]=function() local creeps = npcBot:GetNearbyCreeps(1600,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) - -------------------------------------- - -- 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, false, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); - - if ( locationAoE.count >= 4 ) - then - return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; - 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 ) diff --git a/ability_item_usage_antimage.lua b/ability_item_usage_antimage.lua index 18650367..bb3a4912 100644 --- a/ability_item_usage_antimage.lua +++ b/ability_item_usage_antimage.lua @@ -9,15 +9,6 @@ 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() @@ -168,7 +159,7 @@ Consider[2]=function() 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:DistanceFromFountain()>=2000 and (ManaPercentage>=0.6 or npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH or HealthPercentage<=0.6)) + if ( AbilityExtensions:IsRetreating(npcBot) and npcBot:DistanceFromFountain()>=2000 and (ManaPercentage>=0.6 or npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH or HealthPercentage<=0.6)) then return BOT_ACTION_DESIRE_HIGH, utility.GetUnitsTowardsLocation(npcBot,GetAncient(GetTeam()),CastRange) end @@ -207,7 +198,7 @@ Consider[2]=function() if #projectiles ~= 0 and not AbilitiesReal[3]:IsFullyCastable() and not npcBot:HasModifier("modifier_antimage_counterspell") then for _, projectile in pairs(projectiles) do if GetUnitToLocationDistance(npcBot, projectile.location) > castPoint * defaultProjectileVelocity then - local escapeLocation = utility.GetUnitsTowardsLocation(npcBot, projectile.location, 400) + local escapeLocation = AbilityExtensions:GetPointFromLineByDistance(npcBot:GetLocation(), projectile.location, 400) return BOT_ACTION_DESIRE_MODERATE, escapeLocation end end diff --git a/ability_item_usage_arc_warden.lua b/ability_item_usage_arc_warden.lua index 83912276..66659c99 100644 --- a/ability_item_usage_arc_warden.lua +++ b/ability_item_usage_arc_warden.lua @@ -1,540 +1,347 @@ ----------------------------------------------------------------------------- --- Ranked Matchmaking AI v1.1 NewStructure --- Author: adamqqq Email:adamqqq@163.com ----------------------------------------------------------------------------- --------------------------------------- --- General Initialization --------------------------------------- -if GetBot():IsInvulnerable() or not GetBot():IsHero() or not string.find(GetBot():GetUnitName(), "hero") or GetBot():IsIllusion() then - return; +--------------------------------------------- +-- Generated from Mirana Compiler version 1.6.2 +-- Do not modify +-- https://github.com/AaronSong321/Mirana +--------------------------------------------- +if GetBot():IsInvulnerable() or not GetBot():IsHero() or not string.find(GetBot():GetUnitName(), "hero") or GetBot():IsIllusion() then + return end - -local utility = require( GetScriptDirectory().."/utility" ) -require(GetScriptDirectory() .. "/ability_item_usage_generic") +local utility = require(GetScriptDirectory().."/utility") +require(GetScriptDirectory().."/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") - -local debugmode=false +local A = require(GetScriptDirectory().."/util/MiraDota") +local debugmode = false local npcBot = GetBot() -local Talents ={} -local Abilities ={} -local AbilitiesReal ={} - -ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) - - - -local AbilityToLevelUp= -{ - Abilities[3], - Abilities[1], - Abilities[1], - 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", - "talent", - "nil", - "nil", - "nil", - "nil", - "talent", +local Talents = {} +local Abilities = {} +local AbilitiesReal = {} +ability_item_usage_generic.InitAbility(Abilities, AbilitiesReal, Talents) +local AbilityToLevelUp = { + Abilities[3], + Abilities[1], + Abilities[1], + 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", + "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 +local TalentTree = { + function() + return Talents[1] + end, + function() + return Talents[3] + end, + function() + return Talents[6] + end, + function() + return Talents[7] + end, } - --- check skill build vs current level utility.CheckAbilityBuild(AbilityToLevelUp) - function AbilityLevelUpThink() - ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp,TalentTree) + ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp, TalentTree) end - --------------------------------------- --- Ability Usage Thinking --------------------------------------- function CanCast1(npcTarget) - if(npcTarget==nil or npcTarget:CanBeSeen()==false) - then - return utility.NCanCast(npcTarget) - end - - local enemys = npcTarget:GetNearbyCreeps(150,false) - local enemys2 = npcTarget:GetNearbyHeroes(150,false, BOT_MODE_NONE) - - if(enemys~=nil and enemys2~=nil and #enemys==0 and #enemys2==0) - then - return utility.NCanCast(npcTarget) - end - - return utility.NCanCast(npcTarget) + if npcTarget == nil or npcTarget:CanBeSeen() == false then + return utility.NCanCast(npcTarget) + end + local enemys = npcTarget:GetNearbyCreeps(150, false) + local enemys2 = npcTarget:GetNearbyHeroes(150, false, BOT_MODE_NONE) + if enemys ~= nil and enemys2 ~= nil and #enemys == 0 and #enemys2 == 0 then + return utility.NCanCast(npcTarget) + end + return utility.NCanCast(npcTarget) end - -local cast={} cast.Desire={} cast.Target={} cast.Type={} -local Consider ={} -local CanCast={CanCast1,utility.NCanCast,utility.NCanCast,utility.UCanCast} -local enemyDisabled=utility.enemyDisabled - +local cast = {} +cast.Desire = {} +cast.Target = {} +cast.Type = {} +local Consider = {} +local CanCast = { + CanCast1, + utility.NCanCast, + utility.NCanCast, + utility.UCanCast, +} +local enemyDisabled = utility.enemyDisabled function GetComboDamage() - return ability_item_usage_generic.GetComboDamage(AbilitiesReal) + return ability_item_usage_generic.GetComboDamage(AbilitiesReal) end - function GetComboMana() - return ability_item_usage_generic.GetComboMana(AbilitiesReal) + return ability_item_usage_generic.GetComboMana(AbilitiesReal) end - -Consider[1]=function() - local abilityNumber=1 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; - - if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() then - -- tempest double doesn't check ability:IsFullyCastable(), so manual check is required here - return BOT_ACTION_DESIRE_NONE, 0; - end - - local CastRange = ability:GetCastRange(); - local Damage = ability:GetAbilityDamage(); - 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(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) - then - if ( CanCast[abilityNumber]( WeakestEnemy ) ) - then - return BOT_ACTION_DESIRE_HIGH,WeakestEnemy; - end - end - end - end - -------------------------------------- - -- 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 my mana is enough,use it at enemy - if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) - then - if(HealthPercentage>0.6 and (ManaPercentage>0.6 or npcBot:GetMana()>ComboMana)) - then - if (WeakestEnemy~=nil) - then - if ( CanCast[abilityNumber]( WeakestEnemy ) ) - then - return BOT_ACTION_DESIRE_LOW,WeakestEnemy; - 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 >=1 ) - then - if(npcBot:GetMana()>ComboMana*2 and CanCast[abilityNumber](WeakestCreep)) - then - return BOT_ACTION_DESIRE_LOW, WeakestCreep; - end - end - end - - -- If we're pushing or defending a lane - 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 ( #enemys>=1) - then - if (ManaPercentage>0.5 or npcBot:GetMana()>ComboMana) - then - if (WeakestEnemy~=nil) - then - if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) - then - return BOT_ACTION_DESIRE_LOW, WeakestEnemy; - end - end - 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; - +local health +local maxHealth +local healthPercent +local mana +local maxMana +local manaPercent +Consider[1] = function() + local abilityNumber = 1 + local ability = AbilitiesReal[abilityNumber] + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() then + return BOT_ACTION_DESIRE_NONE, 0 + end + local CastRange = ability:GetCastRange() + local Damage = ability:GetAbilityDamage() + local CastPoint = ability:GetCastPoint() + local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) + local enemys = A.Dota.GetNearbyHeroes(npcBot, CastRange + 300, true) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) + if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then + if WeakestEnemy ~= nil then + if HeroHealth <= WeakestEnemy:GetActualIncomingDamage(Damage, DAMAGE_TYPE_MAGICAL) or (HeroHealth <= WeakestEnemy:GetActualIncomingDamage(GetComboDamage(), DAMAGE_TYPE_MAGICAL) and npcBot:GetMana() > ComboMana) then + if CanCast[abilityNumber](WeakestEnemy) then + return BOT_ACTION_DESIRE_HIGH, WeakestEnemy + end + end + end + end + local enemys2 = npcBot:GetNearbyHeroes(400, true, BOT_MODE_NONE) + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if HealthPercentage > 0.6 and (ManaPercentage > 0.6 or npcBot:GetMana() > ComboMana) then + if WeakestEnemy ~= nil then + if CanCast[abilityNumber](WeakestEnemy) then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy + end + end + end + end + if npcBot:GetActiveMode() == BOT_MODE_FARM then + if #creeps >= 1 then + if npcBot:GetMana() > ComboMana * 2 and CanCast[abilityNumber](WeakestCreep) then + return BOT_ACTION_DESIRE_LOW, WeakestCreep + end + end + end + 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 #enemys >= 1 then + if ManaPercentage > 0.5 or npcBot:GetMana() > ComboMana then + if WeakestEnemy ~= nil then + if CanCast[abilityNumber](WeakestEnemy) and GetUnitToUnitDistance(npcBot, WeakestEnemy) < CastRange + 75 * #allys then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy + end + end + end + end + end + 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[2]=function() - - local abilityNumber=2 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; - - if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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) - local towers = npcBot:GetNearbyTowers(CastRange+300,false) - - -------------------------------------- - -- 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 - if ( #towers >= 1 ) - then - return BOT_ACTION_DESIRE_LOW, towers[1]:GetLocation() - end - - local locationAoE = npcBot:FindAoELocation( false, true, npcBot:GetLocation(), CastRange, Radius, 0, 0 ); - - if ( locationAoE.count >= 2 ) then - return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; - end - end - - --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, utility.GetUnitsTowardsLocation(npcEnemy,npcBot,Radius); - 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 locationAoE = npcBot:FindAoELocation( false, 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, utility.GetUnitsTowardsLocation(npcBot,npcEnemy,Radius); - end - end - end - - return BOT_ACTION_DESIRE_NONE, 0; - +Consider[2] = function() + local abilityNumber = 2 + local ability = AbilitiesReal[abilityNumber] + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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) + local towers = npcBot:GetNearbyTowers(CastRange + 300, false) + local enemys2 = npcBot:GetNearbyHeroes(400, true, BOT_MODE_NONE) + 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, utility.GetUnitsTowardsLocation(npcEnemy, npcBot, Radius) + end + end + end + 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(false, 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, utility.GetUnitsTowardsLocation(npcBot, npcEnemy, Radius) + end + end + end + return BOT_ACTION_DESIRE_NONE, 0 end - -Consider[3]=function() - local abilityNumber=3 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; - - if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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 Delay = ability:GetSpecialValueFloat("activation_delay"); - - local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); - local enemys = npcBot:GetNearbyHeroes(1600,true,BOT_MODE_NONE) - local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) - local creeps = npcBot:GetNearbyCreeps(1600,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+Delay); - end - end - end - end - - -------------------------------------- - -- Mode based usage - -------------------------------------- - local enemys2 = npcBot:GetNearbyHeroes( 400, true, BOT_MODE_NONE ); - - if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) - then - if ManaPercentage>0.7 or ManaPercentage >= 0.4 and ability:GetLevel() >= 2 - then - if (WeakestEnemy~=nil) - then - if ( CanCast[abilityNumber]( WeakestEnemy ) ) - then - return BOT_ACTION_DESIRE_LOW,utility.GetUnitsTowardsLocation(npcBot,WeakestEnemy,GetUnitToUnitDistance(npcBot,WeakestEnemy)+300) - 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 - if(CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana) - then - return BOT_ACTION_DESIRE_LOW, WeakestCreep:GetExtrapolatedLocation(CastPoint+Delay); - end - end - end - - -- If we're pushing or defending a lane - 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 ( #enemys>=1) - then - if (ManaPercentage>0.5 or npcBot:GetMana()>ComboMana and AbilitiesReal[abilityNumber]:GetLevel()>=1) - then - if (WeakestEnemy~=nil) - then - if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) - then - return BOT_ACTION_DESIRE_LOW, WeakestEnemy:GetExtrapolatedLocation(CastPoint+Delay); - end - end - 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 locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, CastPoint+Delay, 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 ) and not enemyDisabled(npcEnemy) and GetUnitToUnitDistance(npcBot,npcEnemy)< CastRange + 75*#allys) - then - return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetExtrapolatedLocation(CastPoint+Delay); - end - end - end - - return BOT_ACTION_DESIRE_NONE, 0; - +Consider[3] = function() + local abilityNumber = 3 + local ability = AbilitiesReal[abilityNumber] + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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 Delay = ability:GetSpecialValueFloat("activation_delay") + local searchRadius = ability:GetSpecialValueInt "search_radius" or 375 + local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) + local enemys = npcBot:GetNearbyHeroes(1600, true, BOT_MODE_NONE) + local vulnerableEnemy = A.Linq.Filter(enemys, A.Hero.MayNotBeIllusion):First(CanCast[abilityNumber]) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(1600, true) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) + 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 + Delay) + end + end + end + end + local enemys2 = npcBot:GetNearbyHeroes(400, true, BOT_MODE_NONE) + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if ManaPercentage > 0.7 or ManaPercentage >= 0.55 and ability:GetLevel() >= 3 then + if WeakestEnemy ~= nil then + if CanCast[abilityNumber](WeakestEnemy) then + return BOT_ACTION_DESIRE_LOW, utility.GetUnitsTowardsLocation(npcBot, WeakestEnemy, GetUnitToUnitDistance(npcBot, WeakestEnemy) + 300) + end + end + end + end + local manaLeft = mana - ability:GetManaCost() + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if manaLeft >= 0.7 * maxMana or manaLeft >= 0.55 * maxMana then + if vulnerableEnemy then + local enemyFriends = vulnerableEnemy:GetNearbyCreeps(searchRadius + vulnerableEnemy + GetBoundingRadius() + 128):Count(function(t) + return A.Unit.GetHealthPercent(t) >= 0.3 + end) + if enemyFriends == 1 then + return BOT_ACTION_DESIRE_LOW, vulnerableEnemy:GetExtrapolatedLocation(CastPoint + Delay) + elseif enemyFriends == 0 then + return BOT_ACTION_DESIRE_MODERATE + 0.15, vulnerableEnemy:GetExtrapolatedLocation(CastPoint + Delay) + end + end + end + end + if npcBot:GetActiveMode() == BOT_MODE_FARM then + if #creeps >= 2 and ability:GetLevel() >= 3 then + if CreepHealth <= WeakestCreep:GetActualIncomingDamage(Damage, DAMAGE_TYPE_MAGICAL) and manaLeft >= 0.75 * maxMana then + return BOT_ACTION_DESIRE_LOW, WeakestCreep:GetExtrapolatedLocation(CastPoint + Delay) + end + end + end + 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 #enemys >= 1 then + if manaLeft >= 0.65 * maxMana and npcBot:GetMana() > ComboMana and ability:GetLevel() >= 4 then + if WeakestEnemy ~= nil then + if CanCast[abilityNumber](WeakestEnemy) and GetUnitToUnitDistance(npcBot, WeakestEnemy) < CastRange + 75 * #allys then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy:GetExtrapolatedLocation(CastPoint + Delay) + end + end + end + end + end + 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, CastPoint + Delay, 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) and not enemyDisabled(npcEnemy) and GetUnitToUnitDistance(npcBot, npcEnemy) < CastRange + 75 * #allys then + return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetExtrapolatedLocation(CastPoint + Delay) + end + end + end + return BOT_ACTION_DESIRE_NONE, 0 end - -Consider[4]=function() - local abilityNumber=4 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; - - if not ability:IsFullyCastable() or AbilityExtensions:CannotTeleport(npcBot) or AbilityExtensions:IsTempestDouble(npcBot) then - return BOT_ACTION_DESIRE_NONE, 0; - end - - local CastRange = 0 - local Damage = 0 - local CastPoint = ability:GetCastPoint(); - - local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); - local enemys = npcBot:GetNearbyHeroes(800,true,BOT_MODE_NONE) - local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) - 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 AbilityExtensions:CannotTeleport(npcBot)) and not AbilityExtensions:Outnumber(npcBot, 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 - end - -------------------------------------- - -- Mode based usage - -------------------------------------- - 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 - 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 - end - end - end - - return BOT_ACTION_DESIRE_NONE, 0; - +Consider[4] = function() + local abilityNumber = 4 + local ability = AbilitiesReal[abilityNumber] + if not ability:IsFullyCastable() or AbilityExtensions:CannotTeleport(npcBot) or AbilityExtensions:IsTempestDouble(npcBot) then + return BOT_ACTION_DESIRE_NONE, 0 + end + local CastRange = 0 + local Damage = 0 + local CastPoint = ability:GetCastPoint() + local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) + local enemys = npcBot:GetNearbyHeroes(800, true, BOT_MODE_NONE) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(800, true) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) + if (npcBot:GetHealth() <= 450 or HealthPercentage <= 0.3) and (npcBot:WasRecentlyDamagedByAnyHero(1.5) or AbilityExtensions:CanHardlyMove(npcBot) or AbilityExtensions:CannotTeleport(npcBot)) and not AbilityExtensions:Outnumber(npcBot, allys, enemys) then + return 0 + end + local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes(1000, false, BOT_MODE_ATTACK) + if #tableNearbyAttackingAlliedHeroes >= 2 then + return BOT_ACTION_DESIRE_HIGH + end + local enemys2 = npcBot:GetNearbyHeroes(400, true, BOT_MODE_NONE) + 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 + end + end + end + 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 + end + end + end + return BOT_ACTION_DESIRE_NONE, 0 end AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) - function AbilityUsageThink() - if npcBot == nil then npcBot = GetBot(); end - - -- 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) + if npcBot == nil then + npcBot = GetBot() + end + health = npcBot:GetHealth() + maxHealth = npcBot:GetMaxHealth() + healthPercent = AbilityExtensions:GetHealthPercent(npcBot) + mana = npcBot:GetMana() + maxMana = npcBot:GetMaxMana() + manaPercent = AbilityExtensions:GetManaPercent(npcBot) + 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) + 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 - -function CourierUsageThink() - ability_item_usage_generic.CourierUsageThink() -end \ No newline at end of file diff --git a/ability_item_usage_arc_warden.mira b/ability_item_usage_arc_warden.mira new file mode 100644 index 00000000..a2019ab3 --- /dev/null +++ b/ability_item_usage_arc_warden.mira @@ -0,0 +1,554 @@ +---------------------------------------------------------------------------- +-- Ranked Matchmaking AI v1.1 NewStructure +-- Author: adamqqq Email:adamqqq@163.com +---------------------------------------------------------------------------- +-------------------------------------- +-- General Initialization +-------------------------------------- +if GetBot():IsInvulnerable() or not GetBot():IsHero() or not string.find(GetBot():GetUnitName(), "hero") or GetBot():IsIllusion() then + return; +end + +local utility = require( GetScriptDirectory().."/utility" ) +require(GetScriptDirectory() .. "/ability_item_usage_generic") +local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") + +local debugmode=false +local npcBot = GetBot() +local Talents ={} +local Abilities ={} +local AbilitiesReal ={} + +ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) + + + +local AbilityToLevelUp= +{ + Abilities[3], + Abilities[1], + Abilities[1], + 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", + "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 +} + +-- check skill build vs current level +utility.CheckAbilityBuild(AbilityToLevelUp) + +function AbilityLevelUpThink() + ability_item_usage_generic.AbilityLevelUpThink2(AbilityToLevelUp,TalentTree) +end + +-------------------------------------- +-- Ability Usage Thinking +-------------------------------------- +function CanCast1(npcTarget) + if(npcTarget==nil or npcTarget:CanBeSeen()==false) + then + return utility.NCanCast(npcTarget) + end + + local enemys = npcTarget:GetNearbyCreeps(150,false) + local enemys2 = npcTarget:GetNearbyHeroes(150,false, BOT_MODE_NONE) + + if(enemys~=nil and enemys2~=nil and #enemys==0 and #enemys2==0) + then + return utility.NCanCast(npcTarget) + end + + return utility.NCanCast(npcTarget) +end + +local cast={} cast.Desire={} cast.Target={} cast.Type={} +local Consider ={} +local CanCast={CanCast1,utility.NCanCast,utility.NCanCast,utility.UCanCast} +local enemyDisabled=utility.enemyDisabled + +function GetComboDamage() + return ability_item_usage_generic.GetComboDamage(AbilitiesReal) +end + +function GetComboMana() + return ability_item_usage_generic.GetComboMana(AbilitiesReal) +end + +local health +local maxHealth +local healthPercent +local mana +local maxMana +local manaPercent + +Consider[1]=function() + local abilityNumber=1 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() then + -- tempest double doesn't check ability:IsFullyCastable(), so manual check is required here + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = ability:GetCastRange(); + local Damage = ability:GetAbilityDamage(); + local CastPoint = ability:GetCastPoint(); + + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = A.Dota.GetNearbyHeroes(npcBot, CastRange+300, true) + 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(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) or (HeroHealth<=WeakestEnemy:GetActualIncomingDamage(GetComboDamage(),DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana)) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + return BOT_ACTION_DESIRE_HIGH,WeakestEnemy; + end + end + end + end + -------------------------------------- + -- 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 my mana is enough,use it at enemy + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if(HealthPercentage>0.6 and (ManaPercentage>0.6 or npcBot:GetMana()>ComboMana)) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + return BOT_ACTION_DESIRE_LOW,WeakestEnemy; + 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 >=1 ) + then + if(npcBot:GetMana()>ComboMana*2 and CanCast[abilityNumber](WeakestCreep)) + then + return BOT_ACTION_DESIRE_LOW, WeakestCreep; + end + end + end + + -- If we're pushing or defending a lane + 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 ( #enemys>=1) + then + if (ManaPercentage>0.5 or npcBot:GetMana()>ComboMana) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) + then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy; + end + end + 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[2]=function() + + local abilityNumber=2 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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) + local towers = npcBot:GetNearbyTowers(CastRange+300,false) + + -------------------------------------- + -- 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, utility.GetUnitsTowardsLocation(npcEnemy,npcBot,Radius); + 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 locationAoE = npcBot:FindAoELocation( false, 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, utility.GetUnitsTowardsLocation(npcBot,npcEnemy,Radius); + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + +end + +Consider[3]=function() + local abilityNumber=3 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or npcBot:GetMana() < ability:GetManaCost() or not ability:IsCooldownReady() 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 Delay = ability:GetSpecialValueFloat("activation_delay"); + local searchRadius = ability:GetSpecialValueInt "search_radius" or 375 + + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(1600,true,BOT_MODE_NONE) + local vulnerableEnemy = A.Linq.Filter(enemys, A.Hero.MayNotBeIllusion):First(CanCast[abilityNumber]) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + local creeps = npcBot:GetNearbyCreeps(1600,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+Delay); + end + end + end + end + + -------------------------------------- + -- Mode based usage + -------------------------------------- + local enemys2 = npcBot:GetNearbyHeroes( 400, true, BOT_MODE_NONE ); + + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if ManaPercentage>0.7 or ManaPercentage >= 0.55 and ability:GetLevel() >= 3 + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + return BOT_ACTION_DESIRE_LOW,utility.GetUnitsTowardsLocation(npcBot,WeakestEnemy,GetUnitToUnitDistance(npcBot,WeakestEnemy)+300) + end + end + end + end + local manaLeft = mana-ability:GetManaCost() + if npcBot:GetActiveMode() == BOT_MODE_LANING then + if manaLeft >= 0.7 * maxMana or manaLeft >= 0.55 * maxMana then + if vulnerableEnemy then + local enemyFriends = vulnerableEnemy:GetNearbyCreeps(searchRadius + vulnerableEnemy+GetBoundingRadius() + 128):Count { t -> + A.Unit.GetHealthPercent(t) >= 0.3 + } + if enemyFriends == 1 then + return BOT_ACTION_DESIRE_LOW, vulnerableEnemy:GetExtrapolatedLocation(CastPoint+Delay) + elif enemyFriends == 0 then + return BOT_ACTION_DESIRE_MODERATE+0.15, vulnerableEnemy:GetExtrapolatedLocation(CastPoint+Delay) + 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 and ability:GetLevel() >= 3 + then + if CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) and manaLeft >= 0.75 * maxMana + then + return BOT_ACTION_DESIRE_LOW, WeakestCreep:GetExtrapolatedLocation(CastPoint+Delay); + end + end + end + + -- If we're pushing or defending a lane + 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 ( #enemys>=1) + then + if (manaLeft >= 0.65 * maxMana and npcBot:GetMana()>ComboMana and ability:GetLevel()>=4) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) + then + return BOT_ACTION_DESIRE_LOW, WeakestEnemy:GetExtrapolatedLocation(CastPoint+Delay); + end + end + 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 locationAoE = npcBot:FindAoELocation( true, true, npcBot:GetLocation(), CastRange, Radius, CastPoint+Delay, 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 ) and not enemyDisabled(npcEnemy) and GetUnitToUnitDistance(npcBot,npcEnemy)< CastRange + 75*#allys) + then + return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetExtrapolatedLocation(CastPoint+Delay); + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + +end + +Consider[4]=function() + local abilityNumber=4 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or AbilityExtensions:CannotTeleport(npcBot) or AbilityExtensions:IsTempestDouble(npcBot) then + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = 0 + local Damage = 0 + local CastPoint = ability:GetCastPoint(); + + local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); + local enemys = npcBot:GetNearbyHeroes(800,true,BOT_MODE_NONE) + local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) + 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 AbilityExtensions:CannotTeleport(npcBot)) and not AbilityExtensions:Outnumber(npcBot, 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 + end + -------------------------------------- + -- Mode based usage + -------------------------------------- + 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 + 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 + end + end + end + + return BOT_ACTION_DESIRE_NONE, 0; + +end +AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) + +function AbilityUsageThink() + if npcBot == nil then npcBot = GetBot(); end + + health = npcBot:GetHealth() + maxHealth = npcBot:GetMaxHealth() + healthPercent = AbilityExtensions:GetHealthPercent(npcBot) + mana = npcBot:GetMana() + maxMana = npcBot:GetMaxMana() + manaPercent = AbilityExtensions:GetManaPercent(npcBot) + + -- 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_axe.lua b/ability_item_usage_axe.lua index 7994c467..88e87188 100644 --- a/ability_item_usage_axe.lua +++ b/ability_item_usage_axe.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -106,9 +106,9 @@ Consider[1] = function() end 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 WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(Radius, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) for _, npcEnemy in pairs(enemys) do if npcEnemy:IsChanneling() then return BOT_ACTION_DESIRE_HIGH @@ -127,7 +127,7 @@ Consider[1] = function() end end if npcBot:GetActiveMode() == BOT_MODE_LANING then - if (ManaPercentage > 0.4 or npcBot:GetMana() > ComboMana) then + if npcBot:GetMana() >= npcBot:GetMaxMana() * 0.4 + ability:GetManaCost() then if WeakestEnemy ~= nil then if GetUnitToUnitDistance(npcBot, WeakestEnemy) < Radius - CastPoint * WeakestEnemy:GetCurrentMovementSpeed() then return BOT_ACTION_DESIRE_LOW @@ -161,9 +161,9 @@ Consider[2] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -227,13 +227,12 @@ Consider[4] = function() return BOT_ACTION_DESIRE_NONE end local CastRange = ability:GetCastRange() - local Damage = ability:GetSpecialValueInt "kill_threshold" + local Damage = ability:GetAbilityDamage() local function IsWeak(t) - local c = CanCast[4](t) and t:GetHealth() <= Damage - return c + return CanCast[4](t) and t:GetHealth() <= Damage end local CastPoint = ability:GetCastPoint() - local enemies,enemyIllusions = fun1:GetNearbyHeroes(npcBot, CastRange + 300):Filter(IsWeak):Partition(function(it) + local enemies, enemyIllusions = fun1:GetNearbyHeroes(npcBot, CastRange + 300):Filter(IsWeak):Partition(function(it) return fun1:MayNotBeIllusion(npcBot, it) end) if fun1:NotRetreating(npcBot) and #enemies == 0 then @@ -259,11 +258,9 @@ Consider[4] = function() if fun1:NotRetreating(npcBot) then do local blink = fun1:GetAvailableBlink(npcBot) - if blink then - if dis > CastRange + 150 then - ItemUsage.UseItemOnLocation(npcBot, blink, target:GetLocation()) - return 0 - end + if blink and dis > CastRange + 150 then + ItemUsage.UseItemOnLocation(npcBot, blink, target:GetLocation()) + return 0 end end return BOT_ACTION_DESIRE_HIGH, target @@ -287,7 +284,7 @@ Consider[4] = function() return BOT_ACTION_DESIRE_NONE end fun1:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) -local roarLosingTarget +local callLosingTarget local cullingBladeTarget function AbilityUsageThink() if npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() then @@ -296,9 +293,9 @@ function AbilityUsageThink() if not fun1:IsFarmingOrPushing(npcBot) then local nearbyEnemies = fun1:GetNearbyHeroes(npcBot, AbilitiesReal[1]:GetAOERadius() + 90):Filter(CanCast[1]) if #nearbyEnemies == 0 then - if roarLosingTarget == nil then - roarLosingTarget = DotaTime() - elseif DotaTime() - roarLosingTarget > 0.15 then + if callLosingTarget == nil then + callLosingTarget = DotaTime() + elseif DotaTime() - callLosingTarget > 0.15 then npcBot:Action_ClearActions(true) end return @@ -307,7 +304,7 @@ function AbilityUsageThink() else end end - roarLosingTarget = nil + callLosingTarget = nil return end ComboMana = GetComboMana() @@ -318,7 +315,7 @@ function AbilityUsageThink() if debugmode == true then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal, cast) end - local index,target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) if index == 4 then cullingBladeTarget = target end diff --git a/ability_item_usage_axe.mira b/ability_item_usage_axe.mira index 9aa4aee1..56d84746 100644 --- a/ability_item_usage_axe.mira +++ b/ability_item_usage_axe.mira @@ -166,8 +166,7 @@ Consider[1]=function() -- If my mana is enough,use it at enemy if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) then - if((ManaPercentage>0.4 or npcBot:GetMana()>ComboMana)) - then + if npcBot:GetMana() >= npcBot:GetMaxMana() * 0.4 + ability:GetManaCost() then if (WeakestEnemy~=nil) then if(GetUnitToUnitDistance(npcBot,WeakestEnemy) CanCast[4](t) and t:GetHealth() <= Damage local CastPoint = ability:GetCastPoint() local enemies, enemyIllusions = fun1:GetNearbyHeroes(npcBot, CastRange + 300):Filter(IsWeak):Partition { it -> fun1:MayNotBeIllusion(npcBot, it) @@ -364,11 +360,9 @@ Consider[4]=function() } then local dis = GetUnitToUnitDistance(npcBot, target) if fun1:NotRetreating(npcBot) then - if local blink = fun1:GetAvailableBlink(npcBot) then - if dis > CastRange + 150 then - ItemUsage.UseItemOnLocation(npcBot, blink, target:GetLocation()) - return 0 - end + if local blink = fun1:GetAvailableBlink(npcBot); blink and dis > CastRange + 150 then + ItemUsage.UseItemOnLocation(npcBot, blink, target:GetLocation()) + return 0 end return BOT_ACTION_DESIRE_HIGH, target else @@ -393,7 +387,7 @@ end fun1:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) -local roarLosingTarget +local callLosingTarget local cullingBladeTarget function AbilityUsageThink() @@ -404,9 +398,9 @@ function AbilityUsageThink() if not fun1:IsFarmingOrPushing(npcBot) then local nearbyEnemies = fun1:GetNearbyHeroes(npcBot, AbilitiesReal[1]:GetAOERadius() + 90):Filter(CanCast[1]) if #nearbyEnemies == 0 then - if roarLosingTarget == nil then - roarLosingTarget = DotaTime() - elseif DotaTime() - roarLosingTarget > 0.15 then + if callLosingTarget == nil then + callLosingTarget = DotaTime() + elseif DotaTime() - callLosingTarget > 0.15 then npcBot:Action_ClearActions(true) end return @@ -421,7 +415,7 @@ function AbilityUsageThink() -- end end end - roarLosingTarget = nil + callLosingTarget = nil return end diff --git a/ability_item_usage_bane.lua b/ability_item_usage_bane.lua index f522b705..a27f141c 100644 --- a/ability_item_usage_bane.lua +++ b/ability_item_usage_bane.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -104,9 +104,9 @@ Consider[1] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes(1000, false, BOT_MODE_ATTACK) if #tableNearbyAttackingAlliedHeroes >= 2 then local npcMostDangerousEnemy = nil @@ -167,7 +167,7 @@ Consider[2] = function() local damage = ability:GetAbilityDamage() local castRange = ability:GetCastRange() local enemyHeroes = fun1:GetNearbyHeroes(npcBot, castRange + 200, true) - local enemies,enemyIllusions = enemyHeroes:Partition(function(it) + local enemies, enemyIllusions = enemyHeroes:Partition(function(it) return fun1:MayNotBeIllusion(npcBot, it) end) local allies = fun1:GetNearbyNonIllusionHeroes(npcBot, 900, false) @@ -339,9 +339,9 @@ Consider[4] = function() local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = npcBot:GetNearbyHeroes(CastRange + 300, true, BOT_MODE_NONE) local enemys2 = npcBot:GetNearbyHeroes(CastRange - 300, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local abilityLevel = ability:GetLevel() local radius = ability:GetAOERadius() - 100 local castPoint = ability:GetCastPoint() @@ -464,7 +464,7 @@ function AbilityUsageThink() if debugmode == true then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal, cast) end - local index,target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) if index == 2 then drainSnapTarget = target elseif index == 4 then diff --git a/ability_item_usage_batrider.lua b/ability_item_usage_batrider.lua index 6d55aee7..6df50f43 100644 --- a/ability_item_usage_batrider.lua +++ b/ability_item_usage_batrider.lua @@ -514,7 +514,7 @@ Consider[4]=function() end --Try to kill enemy hero - if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) + if AbilityExtensions:IsAttackingEnemies(npcBot) then if (WeakestEnemy~=nil) then @@ -534,7 +534,7 @@ Consider[4]=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) + if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH then for _,npcEnemy in pairs( enemys ) do diff --git a/ability_item_usage_beastmaster.lua b/ability_item_usage_beastmaster.lua index 3ede0388..8aff65d4 100644 --- a/ability_item_usage_beastmaster.lua +++ b/ability_item_usage_beastmaster.lua @@ -25,19 +25,19 @@ local AbilityToLevelUp= Abilities[1], Abilities[2], Abilities[1], - Abilities[6], + Abilities[5], Abilities[1], Abilities[2], Abilities[2], "talent", Abilities[4], - Abilities[6], + Abilities[5], Abilities[4], Abilities[4], "talent", Abilities[4], "nil", - Abilities[6], + Abilities[5], "nil", "talent", "nil", @@ -390,8 +390,8 @@ Consider[3]=function() end -Consider[6]=function() --Target Ability Example - local abilityNumber=6 +Consider[5]=function() --Target Ability Example + local abilityNumber=5 -------------------------------------- -- Generic Variable Setting -------------------------------------- diff --git a/ability_item_usage_bloodseeker.lua b/ability_item_usage_bloodseeker.lua index 0e58c75e..c90b8e10 100644 --- a/ability_item_usage_bloodseeker.lua +++ b/ability_item_usage_bloodseeker.lua @@ -25,19 +25,19 @@ local AbilityToLevelUp= Abilities[3], Abilities[2], Abilities[3], - Abilities[4], + Abilities[5], Abilities[3], Abilities[2], Abilities[2], "talent", Abilities[2], - Abilities[4], + Abilities[5], Abilities[1], Abilities[1], "talent", Abilities[1], "nil", - Abilities[4], + Abilities[5], "nil", "talent", "nil", diff --git a/ability_item_usage_bounty_hunter.lua b/ability_item_usage_bounty_hunter.lua index a16c2e51..9cefcd79 100644 --- a/ability_item_usage_bounty_hunter.lua +++ b/ability_item_usage_bounty_hunter.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -90,9 +90,9 @@ Consider[1] = function() local CastPoint = ability:GetCastPoint() 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 WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) for _, npcEnemy in pairs(enemys) do if npcEnemy:IsChanneling() and CanCast[abilityNumber](npcEnemy) then if GetUnitToUnitDistance(npcBot, npcEnemy) < CastRange then @@ -186,9 +186,9 @@ Consider[3] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_MODERATE then if npcBot:WasRecentlyDamagedByAnyHero(2.0) then return BOT_ACTION_DESIRE_HIGH diff --git a/ability_item_usage_brewmaster.lua b/ability_item_usage_brewmaster.lua index 7f9074db..e9dbd877 100644 --- a/ability_item_usage_brewmaster.lua +++ b/ability_item_usage_brewmaster.lua @@ -407,6 +407,9 @@ Consider[3]=function() return BOT_ACTION_DESIRE_NONE, 0; end +-- TODO: 7.31 ability rework +Consider[3] = function() return 0 end + local function EnemyCloseEnoughToUsePrimalSplit(t) return GetUnitToUnitDistance(npcBot, t) <= 600 or GetUnitToUnitDistance(npcBot, t) <= 1000 and npcBot:WasRecentlyDamagedByHero(t, 1.5) end @@ -423,7 +426,7 @@ Consider[4]=function() end local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); - local enemys = AbilityExtensions:GetPureHeroes(npcBot, 700) + local enemys = AbilityExtensions:GetPureHeroes(npcBot, 850) local enemyCount = AbilityExtensions:GetEnemyHeroNumber(npcBot, enemys) local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) -------------------------------------- diff --git a/ability_item_usage_bristleback.lua b/ability_item_usage_bristleback.lua index 1b1af729..c2099296 100644 --- a/ability_item_usage_bristleback.lua +++ b/ability_item_usage_bristleback.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -174,9 +174,9 @@ Consider[2] = function() local CastPoint = ability:GetCastPoint() 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 WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(Radius, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then diff --git a/ability_item_usage_centaur.lua b/ability_item_usage_centaur.lua index 19d82f11..a1eabea4 100644 --- a/ability_item_usage_centaur.lua +++ b/ability_item_usage_centaur.lua @@ -226,8 +226,12 @@ Consider[2]=function() return BOT_ACTION_DESIRE_NONE, 0; end - if npcBot:HasModifier("modifier_centaur_stampede") and AbilitiesReal[1]:IsFullyCastable() then - return BOT_ACTION_DESIRE_NONE, 0; + local function PrioritiseStompFactor(enemy) + if npcBot:HasModifier("modifier_centaur_stampede") and AbilitiesReal[1]:IsFullyCastable() and CanCast[1](enemy) then + return 0.25 + else + return 1 + end end local CastRange = ability:GetCastRange(); @@ -253,7 +257,7 @@ Consider[2]=function() 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; + return BOT_ACTION_DESIRE_HIGH * PrioritiseStompFactor(WeakestEnemy), WeakestEnemy end end end @@ -268,7 +272,7 @@ Consider[2]=function() then if(CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) and HealthPercentage>=0.4+selfDamage) then - return BOT_ACTION_DESIRE_LOW, WeakestCreep; + return BOT_ACTION_DESIRE_LOW, WeakestCreep end end end @@ -282,7 +286,7 @@ Consider[2]=function() then if ( CanCast[abilityNumber]( creeps[1] )and GetUnitToUnitDistance(npcBot,creeps[1])< CastRange + 75*#allys and HealthPercentage>=0.6-0.05*#allys) then - return BOT_ACTION_DESIRE_LOW, creeps[1]; + return BOT_ACTION_DESIRE_LOW, creeps[1] end end end @@ -298,64 +302,65 @@ Consider[2]=function() then if ( CanCast[abilityNumber]( npcEnemy ) and GetUnitToUnitDistance(npcBot,npcEnemy)< CastRange + 75*#allys and HealthPercentage>=0.6-0.05*#allys) then - return BOT_ACTION_DESIRE_MODERATE, npcEnemy; + return BOT_ACTION_DESIRE_MODERATE * PrioritiseStompFactor(npcEnemy), npcEnemy end end end - return BOT_ACTION_DESIRE_NONE, 0; + return BOT_ACTION_DESIRE_NONE, 0 end -Consider[3]=function() +-- retaliate is no longer an active ability +-- Consider[3]=function() - local abilityNumber=3 - -------------------------------------- - -- Generic Variable Setting - -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; +-- local abilityNumber=3 +-- -------------------------------------- +-- -- Generic Variable Setting +-- -------------------------------------- +-- local ability=AbilitiesReal[abilityNumber]; - if not ability:IsFullyCastable() then - return BOT_ACTION_DESIRE_NONE, 0; - end - - -- Get some of its values - local nRadius = 300; - local maxStacks = ability:GetSpecialValueInt('max_stacks'); - local stack = 0; - local modIdx = npcBot:GetModifierByName("modifier_centaur_return_counter"); - if modIdx > -1 then - stack = npcBot:GetModifierStackCount(modIdx); - end - if stack <= maxStacks / 2 then - return BOT_ACTION_DESIRE_NONE; - end - -------------------------------------- - -- Mode based usage - -------------------------------------- - if ( npcBot:GetActiveMode() == BOT_MODE_ROSHAN ) - then - local npcTarget = npcBot:GetAttackTarget(); - if ( utility.IsRoshan(npcTarget) and GetUnitToUnitDistance(npcBot,npcTarget) < nRadius ) - then - return BOT_ACTION_DESIRE_LOW; - 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 npcTarget = npcBot:GetTarget(); - if ( CanCast[abilityNumber]( npcTarget ) and GetUnitToUnitDistance(npcBot,npcTarget) < nRadius ) - then - return BOT_ACTION_DESIRE_HIGH; - end - end - return BOT_ACTION_DESIRE_NONE; -end +-- if not ability:IsFullyCastable() then +-- return BOT_ACTION_DESIRE_NONE, 0; +-- end + +-- -- Get some of its values +-- local nRadius = 300; +-- local maxStacks = ability:GetSpecialValueInt('max_stacks'); +-- local stack = 0; +-- local modIdx = npcBot:GetModifierByName("modifier_centaur_return_counter"); +-- if modIdx > -1 then +-- stack = npcBot:GetModifierStackCount(modIdx); +-- end +-- if stack <= maxStacks / 2 then +-- return BOT_ACTION_DESIRE_NONE; +-- end +-- -------------------------------------- +-- -- Mode based usage +-- -------------------------------------- +-- if ( npcBot:GetActiveMode() == BOT_MODE_ROSHAN ) +-- then +-- local npcTarget = npcBot:GetAttackTarget(); +-- if ( utility.IsRoshan(npcTarget) and GetUnitToUnitDistance(npcBot,npcTarget) < nRadius ) +-- then +-- return BOT_ACTION_DESIRE_LOW; +-- 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 npcTarget = npcBot:GetTarget(); +-- if ( CanCast[abilityNumber]( npcTarget ) and GetUnitToUnitDistance(npcBot,npcTarget) < nRadius ) +-- then +-- return BOT_ACTION_DESIRE_HIGH; +-- end +-- end +-- return BOT_ACTION_DESIRE_NONE; +-- end Consider[4]=function() diff --git a/ability_item_usage_chen.lua b/ability_item_usage_chen.lua index 139e29e7..8c2c12e5 100644 --- a/ability_item_usage_chen.lua +++ b/ability_item_usage_chen.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -102,9 +102,9 @@ Consider[1] = function() local CastPoint = ability:GetCastPoint() local allys = fun1:GetNearbyHeroes(npcBot, 1200, false) local enemys = fun1:GetNearbyHeroes(npcBot, CastRange + 300, true) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = fun1:GetNearbyCreeps(npcBot, CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local enemys2 = fun1:GetNearbyCreeps(npcBot, 400, true) if (npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) or #enemys2 > 0 then for _, npcEnemy in pairs(enemys) do @@ -151,11 +151,11 @@ Consider[2] = function() local CastPoint = ability:GetCastPoint() local allys = fun1:GetNearbyHeroes(npcBot, 1200, false) local enemys = fun1:GetNearbyHeroes(npcBot, CastRange + 300, true) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = fun1:GetNearbyCreeps(npcBot, CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local creepsNeutral = npcBot:GetNearbyNeutralCreeps(1600) - local StrongestCreep,CreepHealth2 = utility.GetStrongestUnit(creepsNeutral) + local StrongestCreep, CreepHealth2 = utility.GetStrongestUnit(creepsNeutral) if ManaPercentage >= 0.3 then for k, creep in pairs(creepsNeutral) do if IsGoodNeutralCreeps(creep) or (creep:IsAncientCreep() and fun1:HasScepter(npcBot)) and CanCast[1](creep) then @@ -163,7 +163,7 @@ Consider[2] = function() end end end - local recallDesire,target = ConsiderRecall() + local recallDesire, target = ConsiderRecall() if recallDesire > 0 then return recallDesire, target end @@ -177,9 +177,9 @@ function ConsiderRecall() end local allys = fun1:GetNearbyHeroes(npcBot, 1200, false) local enemys = fun1:GetNearbyHeroes(npcBot, 1600, true) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = fun1:GetNearbyCreeps(npcBot, 1600, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local numPlayer = GetTeamPlayers(GetTeam()) return BOT_ACTION_DESIRE_NONE, 0 end diff --git a/ability_item_usage_clinkz.lua b/ability_item_usage_clinkz.lua index 4361e54b..697cac12 100644 --- a/ability_item_usage_clinkz.lua +++ b/ability_item_usage_clinkz.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -72,7 +72,11 @@ local Consider = {} local CanCast = { utility.NCanCast, function(t) +<<<<<<< HEAD return AbilityExtensions:PhysicalCanCast(t) or t:IsTower() and not t:HasModifier "modifier_fountain_glyph" +======= + return AbilityExtensions.PhysicalCanCastFunction(t) or t:IsTower() and not t:HasModifier "modifier_fountain_glyph" +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end, utility.NCanCast, utility.UCanCast, @@ -98,9 +102,9 @@ Consider[1] = function() local Radius = ability:GetAOERadius() 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(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -157,7 +161,11 @@ Consider[2] = AbilityExtensions:ToggleFunctionToAutoCast(npcBot, AbilitiesReal[2 end local CastRange = ability:GetCastRange() local enemys = npcBot:GetNearbyHeroes(CastRange + 100, true, BOT_MODE_NONE) +<<<<<<< HEAD local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) +======= + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local function UseAt(target) if not CanCast[abilityNumber](target) then return false @@ -202,9 +210,9 @@ Consider[3] = function() local Radius = ability:GetAOERadius() 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(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH then return BOT_ACTION_DESIRE_MODERATE end @@ -246,9 +254,9 @@ Consider[4] = function() local Radius = ability:GetAOERadius() 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(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_ATTACK) if #tableNearbyAttackingAlliedHeroes >= 2 then local locationAoE = npcBot:FindAoELocation(true, true, npcBot:GetLocation(), AttackRange, 400, 0, 0) @@ -287,7 +295,7 @@ local function RateCreep(creep) end local standardCreepRate = 0 local GetStandardCreepRate = AbilityExtensions:EveryManySeconds(2, function() - standardCreepRate = RateCreep(AbilityExtensions:Max(GetUnitList(UNIT_LIST_ENEMY_CREEPS), RateCreep)) + standardCreepRate = AbilityExtensions:MaxV(GetUnitList(UNIT_LIST_ENEMY_CREEPS) or {}, RateCreep) or 0 end) Consider[5] = function() local abilityNumber = 5 diff --git a/ability_item_usage_clinkz.mira b/ability_item_usage_clinkz.mira index 498c1cde..bd763d8c 100644 --- a/ability_item_usage_clinkz.mira +++ b/ability_item_usage_clinkz.mira @@ -77,7 +77,11 @@ local HealthPercentage; local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} local CanCast={utility.NCanCast,{ t -> +<<<<<<< HEAD AbilityExtensions:PhysicalCanCast(t) or t:IsTower() and not t:HasModifier "modifier_fountain_glyph" +======= + AbilityExtensions.PhysicalCanCastFunction(t) or t:IsTower() and not t:HasModifier "modifier_fountain_glyph" +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a },utility.NCanCast,utility.UCanCast,{ t -> not t:IsAncientCreep() and not t:IsRoshan() }} @@ -411,7 +415,7 @@ local function RateCreep(creep) end local standardCreepRate = 0 local GetStandardCreepRate = AbilityExtensions:EveryManySeconds(2) { -> - standardCreepRate = RateCreep(AbilityExtensions:Max(GetUnitList(UNIT_LIST_ENEMY_CREEPS), RateCreep)) + standardCreepRate = AbilityExtensions:MaxV(GetUnitList(UNIT_LIST_ENEMY_CREEPS) or {}, RateCreep) or 0 } Consider[5]=function() diff --git a/ability_item_usage_doom_bringer.lua b/ability_item_usage_doom_bringer.lua index 70496dc7..05012093 100644 --- a/ability_item_usage_doom_bringer.lua +++ b/ability_item_usage_doom_bringer.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -94,12 +94,12 @@ local neutralCreeps local tower local CanCast = { function(t) - return not t:IsHero() and not fun1:IsRoshan(t) and t:GetLevel() <= AbilitiesReal[1]:GetLevel() + 3 + return not t:IsHero() and not fun1:IsRoshan(t) and t:GetLevel() <= AbilitiesReal[1]:GetLevel() + 3 and (not t:IsAncient() or level >= 28) end, - utility.NCanCast, - utility.NCanCast, - utility.UCanCast, - utility.UCanCast, + AbilityExtensions.NormalCanCastFunction, + AbilityExtensions.PhysicalCanCastFunction, + AbilityExtensions.NormalCanCastFunction, + AbilityExtensions.NormalCanCastFunction, utility.UCanCast, } local enemyDisabled = utility.enemyDisabled @@ -143,26 +143,12 @@ Consider[1] = function() local abilityNumber = 1 local ability = AbilitiesReal[abilityNumber] if not ability:IsFullyCastable() then - return BOT_ACTION_DESIRE_NONE, 0 + return BOT_ACTION_DESIRE_NONE end - local CastRange = ability:GetCastRange() - local Damage = ability:GetAbilityDamage() - local CreepHealth = 10000 - local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) - local creeps = npcBot:GetNearbyCreeps(CastRange + 200, true) - if npcBot:GetAbilityByName "special_bonus_unique_doom_bringer_3":GetLevel() < 1 then - creeps = fun1:Filter(creeps, function(t) - return not t:IsAncientCreep() - end) - end - local StrongstCreep,CreepHealth = utility.GetStrongestUnit(creeps) - if StrongstCreep and CanCast[abilityNumber](StrongstCreep) 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 + local creeps = A.Dota.GetNearbyCreeps(npcBot, 800, true):Concat(A.Dota.GetNearbyNeutralCreeps(npcBot, 800)) + local strongstCreep = A.Linq.Filter(utility.GetStrongestUnit(creeps), CanCast[1]) + if strongstCreep then + return BOT_ACTION_DESIRE_MODERATE, strongstCreep end return BOT_ACTION_DESIRE_NONE end @@ -177,9 +163,10 @@ Consider[2] = function() local allys = fun1:GetNearbyNonIllusionHeroes(npcBot, 1200, false) local allyCount = fun1:GetEnemyHeroNumber(npcBot, allys) local enemys = npcBot:GetNearbyHeroes(Radius + 300, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(Radius + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) + local abilityLevel = ability:GetLevel() if npcBot:WasRecentlyDamagedByAnyHero(2) or (npcBot:GetActiveMode() == BOT_MODE_RETREAT and HealthPercentage <= 0.4 + #enemys * 0.05) then return BOT_ACTION_DESIRE_HIGH end @@ -187,14 +174,14 @@ Consider[2] = function() local npcEnemy = npcBot:GetTarget() if ManaPercentage > 0.4 or npcBot:GetMana() > ComboMana then if npcEnemy ~= nil then - if (GetUnitToUnitDistance(npcBot, npcEnemy) > 450 or npcEnemy:GetHealth() / npcEnemy:GetMaxHealth() < 0.4) and GetUnitToLocationDistance(npcBot, npcEnemy) < 1100 then + if (GetUnitToUnitDistance(npcBot, npcEnemy) > 350 or npcEnemy:GetHealth() / npcEnemy:GetMaxHealth() < 0.4) and GetUnitToUnitDistance(npcBot, npcEnemy) < 900 then return BOT_ACTION_DESIRE_HIGH end end end end if npcBot:GetActiveMode() == BOT_MODE_FARM then - if (#creeps >= 3 and (ManaPercentage > 0.4 or npcBot:GetMana() > ComboMana)) and allyCount < 3 then + if (#creeps >= 3 and (ManaPercentage > 0.4 or npcBot:GetMana() > ComboMana)) and allyCount < 3 and abilityLevel >= 3 then return BOT_ACTION_DESIRE_LOW end end @@ -210,9 +197,9 @@ Consider[3] = function() local Damage = ability:GetAbilityDamage() local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = npcBot:GetNearbyHeroes(CastRange + 150, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 150, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) for _, npcEnemy in pairs(enemys) do if npcEnemy:IsChanneling() and CanCast[abilityNumber](npcEnemy) then return BOT_ACTION_DESIRE_HIGH, npcEnemy @@ -265,7 +252,7 @@ local function centaur_khan_war_stomp(ability) end end else - if enemies:Count(fun1.NormalCanCastFunction) then + if enemies:Any(fun1.NormalCanCastFunction) then return RemapValClamped(mana, 100, ComboMana, BOT_ACTION_DESIRE_MODERATE, BOT_ACTION_DESIRE_HIGH) end end @@ -419,9 +406,9 @@ Consider[6] = function() local CastRange = ability:GetCastRange() local allys = fun1:GetNearbyNonIllusionHeroes(npcBot, 1200, false) local enemys = fun1:GetNearbyNonIllusionHeroes(npcBot, CastRange + 300, true) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local tableNearbyAttackingAlliedHeroes = npcBot:GetNearbyHeroes(1000, false, BOT_MODE_ATTACK) if #tableNearbyAttackingAlliedHeroes >= 2 or #allys >= 3 then local npcMostDangerousEnemy = nil diff --git a/ability_item_usage_doom_bringer.mira b/ability_item_usage_doom_bringer.mira index d3034a20..6868c5ff 100644 --- a/ability_item_usage_doom_bringer.mira +++ b/ability_item_usage_doom_bringer.mira @@ -17,6 +17,7 @@ local Abilities ={} local AbilitiesReal ={} ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) +-- utility.PrintAbilityName(Abilities) local AbilityToLevelUp= { @@ -106,10 +107,12 @@ local friendCreeps local neutralCreeps local tower -local CanCast={function(t) - return not t:IsHero() and not fun1:IsRoshan(t) and t:GetLevel() <= AbilitiesReal[1]:GetLevel()+3 -end - ,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.UCanCast,utility.UCanCast} +local CanCast = {function(t) -> not t:IsHero() and not fun1:IsRoshan(t) and t:GetLevel() <= AbilitiesReal[1]:GetLevel()+3 and (not t:IsAncient() or level >= 28), + AbilityExtensions.NormalCanCastFunction, + AbilityExtensions.PhysicalCanCastFunction, + AbilityExtensions.NormalCanCastFunction, + AbilityExtensions.NormalCanCastFunction, + utility.UCanCast} local enemyDisabled=utility.enemyDisabled local function GetComboMana() @@ -147,34 +150,17 @@ Consider[1]=function() -------------------------------------- -- Generic Variable Setting -------------------------------------- - local ability=AbilitiesReal[abilityNumber]; + local ability=AbilitiesReal[abilityNumber] if not ability:IsFullyCastable() then - return BOT_ACTION_DESIRE_NONE, 0; + return BOT_ACTION_DESIRE_NONE end - local CastRange = ability:GetCastRange(); - local Damage = ability:GetAbilityDamage(); + local creeps = A.Dota.GetNearbyCreeps(npcBot, 800, true):Concat(A.Dota.GetNearbyNeutralCreeps(npcBot, 800)) + local strongstCreep = A.Linq.Filter(utility.GetStrongestUnit(creeps), CanCast[1]) - local CreepHealth=10000 - local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ) - - local creeps = npcBot:GetNearbyCreeps(CastRange + 200, true) - if npcBot:GetAbilityByName "special_bonus_unique_doom_bringer_3":GetLevel() < 1 then - creeps = fun1:Filter(creeps, function(t) return not t:IsAncientCreep() end) - end - local StrongstCreep,CreepHealth=utility.GetStrongestUnit(creeps) - - if StrongstCreep and CanCast[abilityNumber](StrongstCreep) 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 + if strongstCreep then + return BOT_ACTION_DESIRE_MODERATE, strongstCreep end return BOT_ACTION_DESIRE_NONE @@ -202,6 +188,7 @@ Consider[2]=function() local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(Radius+300,true) local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + local abilityLevel = ability:GetLevel() --try to kill enemy hero @@ -226,7 +213,7 @@ Consider[2]=function() then if ( npcEnemy ~= nil ) then - if ( GetUnitToUnitDistance(npcBot,npcEnemy) > 450 or npcEnemy:GetHealth()/npcEnemy:GetMaxHealth() < 0.4) and GetUnitToLocationDistance(npcBot, npcEnemy) < 1100 + if ( GetUnitToUnitDistance(npcBot,npcEnemy) > 350 or npcEnemy:GetHealth()/npcEnemy:GetMaxHealth() < 0.4) and GetUnitToUnitDistance(npcBot, npcEnemy) < 900 then return BOT_ACTION_DESIRE_HIGH end @@ -237,7 +224,7 @@ Consider[2]=function() -- If we're farming if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) then - if ( #creeps >= 3 and (ManaPercentage>0.4 or npcBot:GetMana()>ComboMana)) and allyCount < 3 + if ( #creeps >= 3 and (ManaPercentage>0.4 or npcBot:GetMana()>ComboMana)) and allyCount < 3 and abilityLevel >= 3 then return BOT_ACTION_DESIRE_LOW; end @@ -351,7 +338,7 @@ local function centaur_khan_war_stomp(ability) end end else - if enemies:Count(fun1.NormalCanCastFunction) then + if enemies:Any(fun1.NormalCanCastFunction) then return RemapValClamped(mana, 100, ComboMana, BOT_ACTION_DESIRE_MODERATE, BOT_ACTION_DESIRE_HIGH) end end diff --git a/ability_item_usage_ember_spirit.lua b/ability_item_usage_ember_spirit.lua index 5843e293..14f5d0d9 100644 --- a/ability_item_usage_ember_spirit.lua +++ b/ability_item_usage_ember_spirit.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -13,7 +13,7 @@ end if npcBot:IsIllusion() then return end -local AbilityNames,Abilities,Talents = fun1:InitAbility(npcBot) +local AbilityNames, Abilities, Talents = fun1:InitAbility(npcBot) local AbilityToLevelUp = { AbilityNames[2], AbilityNames[3], @@ -169,16 +169,18 @@ Consider[1] = function() else do local target = fun1:GetTargetIfGood(npcBot) - local target = fun1:GetTargetIfBad(npcBot) if target then local p = ChainExpectancy(#enemies, unitCount, targetNumber) if p >= 0.5 then return RemapValClamped(p, 0.5, 1, BOT_ACTION_DESIRE_MODERATE, BOT_ACTION_DESIRE_VERYHIGH) end - elseif target then - local p = ChainExpectancy(#enemies, unitCount, targetNumber) - if p >= 1 then - return RemapValClamped(p, 0.5, 1, BOT_ACTION_DESIRE_MODERATE, BOT_ACTION_DESIRE_VERYHIGH) + else + local target = fun1:GetTargetIfBad(npcBot) + if target then + local p = ChainExpectancy(#enemies, unitCount, targetNumber) + if p >= 1 then + return RemapValClamped(p, 0.5, 1, BOT_ACTION_DESIRE_MODERATE, BOT_ACTION_DESIRE_VERYHIGH) + end end end end @@ -208,7 +210,7 @@ Consider[2] = function() local enemyCreeps = fun1:GetNearbyAttackableCreeps(npcBot, castRange + radius) local friendCreeps = fun1:GetNearbyAttackableCreeps(npcBot, npcBot:GetAttackRange() + 150, false) local neutralCreeps = npcBot:GetNearbyNeutralCreeps(castRange) - local weakestEnemy,enemyHealth = utility.GetWeakestUnit(targettableEnemies) + local weakestEnemy, enemyHealth = utility.GetWeakestUnit(targettableEnemies) local creepDamage = npcBot:GetAttackDamage() * (1 + ability:GetSpecialValueInt "creep_damage_penalty" / 100) local weakCreeps = fun1:Filter(enemyCreeps, function(t) return t:GetHealth() < t:GetActualIncomingDamage(creepDamage, DAMAGE_TYPE_MAGICAL) @@ -296,7 +298,7 @@ Consider[3] = function() local enemyCreeps = fun1:GetNearbyAttackableCreeps(npcBot, 900) local friendCreeps = fun1:GetNearbyAttackableCreeps(npcBot, npcBot:GetAttackRange() + 150, false) local neutralCreeps = npcBot:GetNearbyNeutralCreeps(castRange) - local weakestEnemy,enemyHealth = utility.GetWeakestUnit(targettableEnemies) + local weakestEnemy, enemyHealth = utility.GetWeakestUnit(targettableEnemies) local weakCreeps = enemyCreeps local weakestCreep = utility.GetWeakestUnit(weakCreeps) local forbiddenCreeps = {} @@ -364,7 +366,7 @@ end local activeRemnants local refreshRemnantToken local function RefreshActiveRemnants() - activeRemnants = fun1:Filter(GetUnitList(UNIT_LIST_ALL), function(t) + activeRemnants = fun1:Filter(GetUnitList(UNIT_LIST_ALLIES), function(t) return t:GetUnitName() == "npc_dota_ember_spirit_remnant" end) end @@ -593,7 +595,7 @@ function AbilityUsageThink() neutralCreeps = npcBot:GetNearbyNeutralCreeps(1599) tower = fun1:GetLaningTower(npcBot) cast = ability_item_usage_generic.ConsiderAbility(Abilities, Consider) - local abilityIndex,target,castType = ability_item_usage_generic.UseAbility(Abilities, cast) + local abilityIndex, target, castType = ability_item_usage_generic.UseAbility(Abilities, cast) fun1:RecordAbility(npcBot, abilityIndex, target, castType, Abilities) if abilityIndex == 5 then refreshRemnantToken = true diff --git a/ability_item_usage_ember_spirit.mira b/ability_item_usage_ember_spirit.mira index 2055cc4c..f3889572 100644 --- a/ability_item_usage_ember_spirit.mira +++ b/ability_item_usage_ember_spirit.mira @@ -347,7 +347,7 @@ end local activeRemnants local refreshRemnantToken local function RefreshActiveRemnants() - activeRemnants = fun1:Filter(GetUnitList(UNIT_LIST_ALL), function(t) return t:GetUnitName() == "npc_dota_ember_spirit_remnant" end) + activeRemnants = fun1:Filter(GetUnitList(UNIT_LIST_ALLIES), function(t) return t:GetUnitName() == "npc_dota_ember_spirit_remnant" end) end local DetectRemnant = fun1:EveryManySeconds(2, RefreshActiveRemnants) RefreshActiveRemnants() diff --git a/ability_item_usage_faceless_void.lua b/ability_item_usage_faceless_void.lua index 4be062f3..ea4baec7 100644 --- a/ability_item_usage_faceless_void.lua +++ b/ability_item_usage_faceless_void.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -91,7 +91,7 @@ Consider[1] = function() local CastRange = ability:GetSpecialValueInt("range") 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(enemys) local trees = npcBot:GetNearbyTrees(300) if npcBot.FacelessVoidSkill1 == nil or DotaTime() - npcBot.FacelessVoidSkill1.Timer >= 2 then npcBot.FacelessVoidSkill1 = { @@ -118,7 +118,7 @@ Consider[1] = function() return BOT_ACTION_DESIRE_HIGH, fun1:GetPointFromLineByDistance(npcBot:GetLocation(), p.location, 450) end end - if npcBot:GetActiveMode() == BOT_MODE_RETREAT or npcBot.FacelessVoidSkill1.Hp - HealthPercentage >= 0.25 + 0.05 * #enemys then + if AbilityExtensions:IsRetreating(npcBot) or npcBot.FacelessVoidSkill1.Hp - HealthPercentage >= 0.25 + 0.05 * #enemys then return BOT_ACTION_DESIRE_HIGH, utility.GetUnitsTowardsLocation(npcBot, GetAncient(GetTeam()), CastRange) end if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT and ManaPercentage > ComboMana and AbilitiesReal[4]:IsFullyCastable() then @@ -153,9 +153,9 @@ Consider[2] = function() local Radius = ability:GetAOERadius() local CastPoint = ability:GetCastPoint() local allys = npcBot:GetNearbyHeroes(Radius, false, BOT_MODE_NONE) - local WeakestAlly,AllyHealth = utility.GetWeakestUnit(allys) + local WeakestAlly, AllyHealth = utility.GetWeakestUnit(allys) local enemys = npcBot:GetNearbyHeroes(Radius, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -236,7 +236,7 @@ Consider[5] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) for _, npcEnemy in pairs(enemys) do if npcEnemy:IsChanneling() then local TargetLocation = npcEnemy:GetLocation() @@ -294,7 +294,7 @@ function AbilityUsageThink() if debugmode == true then ability_item_usage_generic.PrintDebugInfo(AbilitiesReal, cast) end - local index,target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) if index == 1 then timeWalkLocation = npcBot:GetLocation() timeWalkTime = DotaTime() diff --git a/ability_item_usage_faceless_void.mira b/ability_item_usage_faceless_void.mira index 5237248b..fff7a54e 100644 --- a/ability_item_usage_faceless_void.mira +++ b/ability_item_usage_faceless_void.mira @@ -146,7 +146,7 @@ Consider[1]=function() end -- If we're seriously retreating - if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT or npcBot.FacelessVoidSkill1.Hp-HealthPercentage>=0.25+0.05*#enemys) + if ( AbilityExtensions:IsRetreating(npcBot) or npcBot.FacelessVoidSkill1.Hp-HealthPercentage>=0.25+0.05*#enemys) then return BOT_ACTION_DESIRE_HIGH, utility.GetUnitsTowardsLocation(npcBot,GetAncient(GetTeam()),CastRange) end diff --git a/ability_item_usage_furion.lua b/ability_item_usage_furion.lua index 14c020c3..37d39207 100644 --- a/ability_item_usage_furion.lua +++ b/ability_item_usage_furion.lua @@ -99,7 +99,8 @@ Consider[1]=function() end local function HasDagger(t) - return t:GetUnitName() == "npc_dota_hero_spectre" and t:GetAbilityByName("spectre_spectres_dagger"):IsFullyCastable() + local dagger = t:GetAbilityByName "spectre_spectres_dagger" + return dagger and dagger:IsFullyCastable() and not t:IsSilenced() end local blockNearbyMeleeHeroes = AbilityExtensions:Any(npcBot:GetNearbyHeroes(350, false, BOT_MODE_NONE), function(p) diff --git a/ability_item_usage_generic.lua b/ability_item_usage_generic.lua index 3d64f056..cc625b10 100644 --- a/ability_item_usage_generic.lua +++ b/ability_item_usage_generic.lua @@ -100,12 +100,16 @@ local function SecondaryOperation() end end +local fun2 = require(GetScriptDirectory().."/util/CommonBehaviours") +local A = require(GetScriptDirectory().."/util/MiraDota") + function CourierUsageThink() if not GetBot():IsAlive() then return end AbilityExtensions:TickFromDota() - local fun2 = require(GetScriptDirectory().."/util/CommonBehaviours") + A.Game.TickFromDota() + A.ItemUse.ItemUsageThink() fun2.Think() SecondaryOperation() end @@ -154,49 +158,6 @@ end function AbilityLevelUpThink2(AbilityToLevelUp, TalentTree) ExecuteAbilityLevelUp(AbilityToLevelUp, TalentTree) return - -- - --local npcBot = GetBot() - --if (npcBot:GetAbilityPoints() < 1 or #AbilityToLevelUp == 0 or - -- (GetGameState() ~= GAME_STATE_PRE_GAME and GetGameState() ~= GAME_STATE_GAME_IN_PROGRESS)) - --then - -- return - --end - -- - --local abilityname = AbilityToLevelUp[1] - --print(npcBot:GetUnitName()..": ability to learn "..tostring(abilityname)) - --if abilityname == "nil" then - -- table.remove(AbilityToLevelUp, 1) - -- return - --end - --if abilityname == "talent" then - -- for i, temp in pairs(AbilityToLevelUp) do - -- if temp == "talent" then - -- table.remove(AbilityToLevelUp, i) - -- if #TalentTree >= 1 then - -- table.insert(AbilityToLevelUp, i, TalentTree[1]()) - -- else - -- - -- end - -- table.remove(TalentTree, 1) - -- break - -- end - -- end - --end - -- - --local ability = npcBot:GetAbilityByName(abilityname) - --if ability == nil then - -- print(npcBot:GetUnitName()..": learn ability nil") - --elseif not ability:CanAbilityBeUpgraded() then - -- print(npcBot:GetUnitName()..": cannot learn ability "..abilityname) - --else - -- npcBot:ActionImmediate_Chat("learn ability "..abilityname, true) - -- print(npcBot:GetUnitName()..": learn ability "..abilityname) - --end - --if ability ~= nil and ability:CanAbilityBeUpgraded() then - -- npcBot:ActionImmediate_LevelAbility(abilityname) - -- IncrementIncorrectAbility(AbilityToLevelUp) - --end - --table.remove(AbilityToLevelUp, 1) end local function CanBuybackUpperRespawnTime(respawnTime) @@ -407,13 +368,16 @@ function UseAbility(AbilitiesReal, cast) if (HighestDesire > 0) then local j = HighestDesireAbilityNumber local ability = AbilitiesReal[j] - -- print(npcBot:GetUnitName()..": use "..ability:GetName()) + local sToPrint = npcBot:GetUnitName()..": use "..ability:GetName() + -- if ability:GetName() ~= "doom_bringer_infernal_blade" then + -- print(sToPrint) + -- end if not ability:IsCooldownReady() then print("Ability still in cooldown: "..ability:GetName()) AbilityExtensions:DebugPause() return end - if npcBot:GetMana() < ability:GetManaCost() * 0.65 then --GetManaCost() doesn't count mana cost reduction + if npcBot:GetMana() < ability:GetManaCost() * 0.7 then --GetManaCost() doesn't count mana cost reduction print("Ability mana not enough: "..ability:GetName()) AbilityExtensions:DebugPause() return diff --git a/ability_item_usage_jakiro.lua b/ability_item_usage_jakiro.lua index 6ffa48f4..2eb9e4c5 100644 --- a/ability_item_usage_jakiro.lua +++ b/ability_item_usage_jakiro.lua @@ -8,6 +8,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -403,6 +404,17 @@ Consider[3]=function() end end + if 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 tower = towers[1] + if tower then + if A.Building.CanBeAttacked(tower) then + return BOT_ACTION_DESIRE_VERYHIGH, tower + end + 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 @@ -411,10 +423,6 @@ Consider[3]=function() npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) then - if(#towers>=1) - then - return BOT_ACTION_DESIRE_VERYHIGH, towers[1]; - end if (WeakestEnemy~=nil) then if ( CanCast[abilityNumber]( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) diff --git a/ability_item_usage_kunkka.lua b/ability_item_usage_kunkka.lua index a2bae112..e4a296d5 100644 --- a/ability_item_usage_kunkka.lua +++ b/ability_item_usage_kunkka.lua @@ -1,11 +1,12 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- local utility = require(GetScriptDirectory().."/utility") require(GetScriptDirectory().."/ability_item_usage_generic") local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode = false local npcBot = GetBot() if npcBot:IsIllusion() then @@ -92,7 +93,7 @@ local useTorrentAtXMark local useTorrentAtXMarkTime local xMarkTargetWasTeleporting local function XMarksEnemy() - return xMarkTarget ~= nil and xMarkTarget:IsAlive() and xMarkTarget:GetTeam() ~= npcBot:GetTeam() + return A.Dota.IsValidUnit(xMarkTarget) and xMarkTarget:GetTeam() ~= npcBot:GetTeam() end Consider[1] = function() local abilityNumber = 1 @@ -106,9 +107,9 @@ Consider[1] = function() local CastPoint = 2 local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = npcBot:GetNearbyHeroes(CastRange, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) for _, npcEnemy in pairs(enemys) do if npcEnemy:IsChanneling() then return BOT_ACTION_DESIRE_HIGH - 0.1, npcEnemy:GetLocation() @@ -176,7 +177,7 @@ Consider[3] = function() local Damage = ability:GetAbilityDamage() local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = npcBot:GetNearbyHeroes(CastRange, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) for _, enemy in pairs(enemys) do if enemy:IsChanneling() and CanCast[3](enemy) and not enemy:IsSilenced() then return BOT_ACTION_DESIRE_HIGH, enemy @@ -239,9 +240,9 @@ Consider[6] = function() local CastPoint = ability:GetCastPoint() local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = npcBot:GetNearbyHeroes(CastRange, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -377,7 +378,7 @@ function AbilityUsageThink() useTorrentAtXMarkTime = nil end end) - local index,target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) + local index, target = ability_item_usage_generic.UseAbility(AbilitiesReal, cast) if index == 3 and target ~= nil then xMarkTarget = target xMarkTime = DotaTime() + AbilitiesReal[3]:GetCastPoint() diff --git a/ability_item_usage_kunkka.mira b/ability_item_usage_kunkka.mira index 1ff95198..cdf4b51b 100644 --- a/ability_item_usage_kunkka.mira +++ b/ability_item_usage_kunkka.mira @@ -9,6 +9,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -105,7 +106,7 @@ local useTorrentAtXMarkTime local xMarkTargetWasTeleporting local function XMarksEnemy() - return xMarkTarget ~= nil and xMarkTarget:IsAlive() and xMarkTarget:GetTeam() ~= npcBot:GetTeam() + return A.Dota.IsValidUnit(xMarkTarget) and xMarkTarget:GetTeam() ~= npcBot:GetTeam() end Consider[1]=function() diff --git a/ability_item_usage_lion.lua b/ability_item_usage_lion.lua index d3494fa4..b66be750 100644 --- a/ability_item_usage_lion.lua +++ b/ability_item_usage_lion.lua @@ -8,6 +8,8 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") +-- ItemUsageThink = A.Dota.EmptyDesireFun local debugmode=false local npcBot = GetBot() diff --git a/ability_item_usage_lycan.lua b/ability_item_usage_lycan.lua index 8bca604f..24814a09 100644 --- a/ability_item_usage_lycan.lua +++ b/ability_item_usage_lycan.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -91,9 +91,9 @@ Consider[1] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) local wolves = 0 local units = GetUnitList(UNIT_LIST_ALLIES) for _, unit in pairs(units) do @@ -241,9 +241,9 @@ Consider[5] = 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 WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH then if npcBot:WasRecentlyDamagedByAnyHero(2.0) then return BOT_ACTION_DESIRE_HIGH diff --git a/ability_item_usage_mirana.lua b/ability_item_usage_mirana.lua index 65569e1b..d29e75c1 100644 --- a/ability_item_usage_mirana.lua +++ b/ability_item_usage_mirana.lua @@ -365,7 +365,7 @@ Consider[4]=function() then if npcBot:HasModifier "modifier_bounty_hunter_track" or npcBot:HasModifier "modifier_slardar_amplify_damage" then else - local hasDust = enemys:Any(function(t) + local hasDust = AbilityExtensions:Any(enemys, function(t) return AbilityExtensions:GetCarriedItems(t):Map(function(t) return t:GetName() end):Any(function(t) return t == "item_gem" or t == "item_dust" end) end) if not hasDust then diff --git a/ability_item_usage_necrolyte.lua b/ability_item_usage_necrolyte.lua index 39671e30..ab812533 100644 --- a/ability_item_usage_necrolyte.lua +++ b/ability_item_usage_necrolyte.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -106,11 +106,11 @@ Consider[1] = function() local Radius = ability:GetAOERadius() local CastPoint = ability:GetCastPoint() local allys = npcBot:GetNearbyHeroes(Radius, false, BOT_MODE_NONE) - local WeakestAlly,AllyHealth = utility.GetWeakestUnit(allys) + local WeakestAlly, AllyHealth = utility.GetWeakestUnit(allys) local enemys = npcBot:GetNearbyHeroes(Radius, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(Radius, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) if npcBot:GetActiveMode() ~= BOT_MODE_RETREAT then if WeakestEnemy ~= nil then if CanCast[abilityNumber](WeakestEnemy) then @@ -182,7 +182,7 @@ Consider[2] = function() local Radius = 750 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 WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) if npcBot:WasRecentlyDamagedByAnyHero(2.0) and #enemys >= 2 and HealthPercentage <= 0.35 + 0.05 * #enemys then return BOT_ACTION_DESIRE_HIGH end @@ -258,7 +258,7 @@ Consider[5] = function() local DamagePercent = ability:GetSpecialValueFloat("damage_per_health") local allys = npcBot:GetNearbyHeroes(1200, false, BOT_MODE_NONE) local enemys = AbilityExtensions:GetPureHeroes(npcBot, CastRange + 300) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local maxHealth = (AbilityExtensions:GetNearbyHeroes(npcBot):MaxV(function(t) return t:GetHealth() end) or npcBot:GetHealth()) / 4 diff --git a/ability_item_usage_nyx_assassin.lua b/ability_item_usage_nyx_assassin.lua index 9df147a5..f59afebe 100644 --- a/ability_item_usage_nyx_assassin.lua +++ b/ability_item_usage_nyx_assassin.lua @@ -9,6 +9,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -74,7 +75,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={utility.NCanCast,utility.NCanCast,utility.NCanCast,utility.UCanCast,utility.CanCastNoTarget,utility.CanCastNoTarget} +local CanCast={utility.NCanCast, function(t) return AbilityExtensions:NormalCanCast(t) and A.Unit.IsHero(t) end,utility.NCanCast,utility.UCanCast,utility.CanCastNoTarget,utility.CanCastNoTarget} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -174,7 +175,7 @@ Consider[1]=function() then for _,npcEnemy in pairs( enemys ) do - if ( npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) ) + if CanCast[abilityNumber](npcEnemy) and npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) then return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetExtrapolatedLocation(CastPoint); end diff --git a/ability_item_usage_omniknight.lua b/ability_item_usage_omniknight.lua index 722fc3e9..fc41c353 100644 --- a/ability_item_usage_omniknight.lua +++ b/ability_item_usage_omniknight.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -135,8 +135,8 @@ function GetTargetFactor2() table.remove(allycreeps, i) end end - local HighestFactor,TempTarget = GetTargetFactor() - local HighestFactor2,TempTarget2 = ComputeFactor(allycreeps) + local HighestFactor, TempTarget = GetTargetFactor() + local HighestFactor2, TempTarget2 = ComputeFactor(allycreeps) if HighestFactor2 > HighestFactor then return HighestFactor2, TempTarget2 else @@ -171,14 +171,14 @@ Consider[1] = function() return not t:HasModifier("modifier_ice_blast") end) local enemys = npcBot:GetNearbyHeroes(CastRange + 300, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local creeps = npcBot:GetNearbyCreeps(CastRange + 300, true) - local WeakestCreep,CreepHealth = utility.GetWeakestUnit(creeps) + local WeakestCreep, CreepHealth = utility.GetWeakestUnit(creeps) 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 - local desire,target = GetAbilityTarget(WeakestEnemy) + local desire, target = GetAbilityTarget(WeakestEnemy) if desire > 0 then return desire, target end @@ -209,7 +209,7 @@ Consider[1] = function() local npcEnemy = npcBot:GetTarget() if npcEnemy ~= nil then if CanCast[abilityNumber](npcEnemy) and GetUnitToUnitDistance(npcBot, npcEnemy) < CastRange + 75 * #allys then - local desire,target = GetAbilityTarget(npcEnemy) + local desire, target = GetAbilityTarget(npcEnemy) if desire > 0 then return desire - 0.02, target end @@ -230,7 +230,7 @@ Consider[2] = function() local enemys = npcBot:GetNearbyHeroes(CastRange + 300, true, BOT_MODE_NONE) local allys = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, CastRange + 300, false, BOT_MODE_ATTACK) if npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or npcBot:GetActiveMode() == BOT_MODE_ATTACK then - local weakestAlly,allyHealth = utility.GetWeakestUnit(allys) + local weakestAlly, allyHealth = utility.GetWeakestUnit(allys) if weakestAlly ~= nil then local allyNeaybyEnemys = weakestAlly:GetNearbyHeroes(CastRange, true, BOT_MODE_NONE) if allyHealth / weakestAlly:GetMaxHealth() < 0.4 + 0.4 * ManaPercentage + #allyNeaybyEnemys * 0.05 or #allyNeaybyEnemys >= 2 then @@ -275,7 +275,7 @@ Consider[4] = function() end local CastRange = ability:GetCastRange() local enemys = npcBot:GetNearbyHeroes(CastRange + 100, true, BOT_MODE_NONE) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) local function UseAt(target) if not CanCast[abilityNumber](target) then return false @@ -320,7 +320,7 @@ Consider[5] = function() local Damage = 0 local allys = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1600, false, BOT_MODE_NONE) local enemys = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, 1600) - local WeakestEnemy,HeroHealth = utility.GetWeakestUnit(enemys) + local WeakestEnemy, HeroHealth = utility.GetWeakestUnit(enemys) 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 #allys + #enemys >= 5 then for i, npcTarget in pairs(allys) do diff --git a/ability_item_usage_oracle.lua b/ability_item_usage_oracle.lua index 1a6eb374..5b4af20c 100644 --- a/ability_item_usage_oracle.lua +++ b/ability_item_usage_oracle.lua @@ -25,19 +25,19 @@ local AbilityToLevelUp= Abilities[2], Abilities[3], Abilities[3], - Abilities[4], + Abilities[5], Abilities[3], Abilities[1], Abilities[1], "talent", Abilities[1], - Abilities[4], + Abilities[5], Abilities[2], Abilities[2], "talent", Abilities[2], "nil", - Abilities[4], + Abilities[5], "nil", "talent", "nil", diff --git a/ability_item_usage_puck.lua b/ability_item_usage_puck.lua index 2b9c0695..b2bd23ab 100644 --- a/ability_item_usage_puck.lua +++ b/ability_item_usage_puck.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -13,7 +13,7 @@ end if npcBot:IsIllusion() then return end -local AbilityNames,Abilities,Talents = fun1:InitAbility() +local AbilityNames, Abilities, Talents = fun1:InitAbility() local AbilityToLevelUp = { AbilityNames[1], AbilityNames[3], @@ -201,7 +201,7 @@ function AbilityUsageThink() neutralCreeps = npcBot:GetNearbyNeutralCreeps(900) tower = fun1:GetLaningTower(npcBot) cast = ability_item_usage_generic.ConsiderAbility(Abilities, Consider) - local abilityIndex,target,castType = ability_item_usage_generic.UseAbility(Abilities, cast) + local abilityIndex, target, castType = ability_item_usage_generic.UseAbility(Abilities, cast) if abilityIndex == 1 then illusoryOrbCastLocation = npcBot:GetLocation() illusoryOrbMaxTravelDistance = Abilities[1]:GetSpecialValueInt("max_distance") - 50 diff --git a/ability_item_usage_pudge.lua b/ability_item_usage_pudge.lua index 1dd18cb6..120843de 100644 --- a/ability_item_usage_pudge.lua +++ b/ability_item_usage_pudge.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -126,7 +126,7 @@ Consider[1] = function() end if AbilityExtensions:IsAttackingEnemies(npcBot) then do - local atos = AbilityExtensions:GetAvailableItem(npcBot, "item_rod_of_atos") or AbilityExtensions:GetAvailableItem(npcBot, "item_gleipnir") + local atos = AbilityExtensions:GetAvailableItem(npcBot, "item_rod_of_atos") or AbilityExtensions:GetAvailableItem(npcBot, "item_gungir") if atos then do local t = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range):First(function(t) diff --git a/ability_item_usage_pudge.mira b/ability_item_usage_pudge.mira index 1dca38c4..ba9fb555 100644 --- a/ability_item_usage_pudge.mira +++ b/ability_item_usage_pudge.mira @@ -123,7 +123,7 @@ Consider[1] = function() end if AbilityExtensions:IsAttackingEnemies(npcBot) then - if local atos = AbilityExtensions:GetAvailableItem(npcBot, "item_rod_of_atos") or AbilityExtensions:GetAvailableItem(npcBot, "item_gleipnir") then + if local atos = AbilityExtensions:GetAvailableItem(npcBot, "item_rod_of_atos") or AbilityExtensions:GetAvailableItem(npcBot, "item_gungir") then if local t = AbilityExtensions:GetNearbyNonIllusionHeroes(npcBot, range):First { t -> not AbilityExtensions:CannotMove(t) and T(t) and AbilityExtensions:NormalCanCast(t) } then diff --git a/ability_item_usage_queenofpain.lua b/ability_item_usage_queenofpain.lua index 9f66b4dc..9c3c1c21 100644 --- a/ability_item_usage_queenofpain.lua +++ b/ability_item_usage_queenofpain.lua @@ -247,7 +247,7 @@ Consider[2]=function() 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:DistanceFromFountain()>=2000 and (ManaPercentage>=0.6 or HealthPercentage<=0.5 or npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) ) + if ( AbilityExtensions:IsRetreating(npcBot) and npcBot:DistanceFromFountain()>=2000 and (ManaPercentage>=0.6 or HealthPercentage<=0.5 or npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH) ) then return BOT_ACTION_DESIRE_HIGH, utility.GetUnitsTowardsLocation(npcBot,GetAncient(GetTeam()),CastRange) end diff --git a/ability_item_usage_shadow_demon.lua b/ability_item_usage_shadow_demon.lua index c8185ffd..b4a8202f 100644 --- a/ability_item_usage_shadow_demon.lua +++ b/ability_item_usage_shadow_demon.lua @@ -10,6 +10,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") local AbilityHelper = dofile(GetScriptDirectory() .. "/util/AbilityHelper") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -18,7 +19,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= { @@ -27,19 +28,19 @@ local AbilityToLevelUp= Abilities[3], Abilities[2], Abilities[3], - Abilities[5], + Abilities[6], Abilities[3], Abilities[1], Abilities[1], "talent", Abilities[1], - Abilities[5], + Abilities[6], Abilities[2], Abilities[2], "talent", Abilities[2], "nil", - Abilities[5], + Abilities[6], "nil", "talent", "nil", @@ -89,7 +90,7 @@ end local CanCast = {} CanCast[1] = function(target) - if target:HasModifier("modifier_shadow_demon_disruption") then + if target:HasModifier("modifier_shadow_demon_disruption") or A.Unit.IsCreepHero(target) then return false end if npcBot:GetTeam() == target:GetTeam() then @@ -107,7 +108,8 @@ end CanCast[4] = function(target) return target:HasModifier("modifier_shadow_demon_disruption") or AbilityExtensions:NormalCanCast(target, false, DAMAGE_TYPE_MAGICAL, false, true) end -CanCast[5] = function(target) +CanCast[5] = CanCast[4] +CanCast[6] = function(target) return not target:HasModifier("modifier_antimage_counterspell") and not target:HasModifier("modifier_shadow_demon_purge_slow") and (target:HasModifier("modifier_shadow_demon_disruption") or AbilityExtensions:NormalCanCast(target, false, DAMAGE_TYPE_MAGICAL, false, true)) end @@ -395,6 +397,7 @@ Consider[3]=function() end +-- shadow poison release --[[Consider[4]=function() local abilityNumber=4 -------------------------------------- @@ -431,10 +434,12 @@ end end]] +-- 7.31 upgrade demonic cleanse +Consider[5] = A.Dota.EmptyDesireFun -Consider[5]=function() - - local abilityNumber=5 +-- demonic purge +Consider[6]=function() + local abilityNumber=6 -------------------------------------- -- Generic Variable Setting -------------------------------------- diff --git a/ability_item_usage_shredder.lua b/ability_item_usage_shredder.lua index 3f5f9650..ac573cc9 100644 --- a/ability_item_usage_shredder.lua +++ b/ability_item_usage_shredder.lua @@ -18,7 +18,18 @@ local Abilities ={} local AbilitiesReal ={} local ultTime = nil; -ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) +ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) + +-- 1 = shredder_whirling_death +-- [VScript] 2 = shredder_timber_chain +-- [VScript] 3 = shredder_reactive_armor +-- [VScript] 4 = shredder_chakram_2 +-- [VScript] 5 = shredder_flamethrower +-- [VScript] 6 = shredder_chakram +-- [VScript] 7 = shredder_return_chakram +-- [VScript] 8 = shredder_return_chakram_2 +-- [VScript] 9 = ability_capture +-- [VScript] 10 = abyssal_underlord_portal_warp local AbilityToLevelUp= { @@ -27,19 +38,19 @@ local AbilityToLevelUp= Abilities[3], Abilities[2], Abilities[3], - Abilities[5], + Abilities[6], Abilities[3], Abilities[2], Abilities[2], "talent", Abilities[2], - Abilities[5], + Abilities[6], Abilities[1], Abilities[1], "talent", Abilities[1], "nil", - Abilities[5], + Abilities[6], "nil", "talent", "nil", @@ -360,7 +371,7 @@ Consider[2]=function() end - +-- flamethrower Consider[5]=function() local abilityNumber=5 -------------------------------------- @@ -461,6 +472,7 @@ Consider[5]=function() return BOT_ACTION_DESIRE_NONE, 0; end +-- scepter: chakram Consider[6]=function() local abilityNumber=6 -------------------------------------- @@ -490,6 +502,7 @@ Consider[6]=function() return BOT_ACTION_DESIRE_NONE, 0; end +-- scepter: chakram Consider[4]=function() --A杖大 local abilityNumber=4 -------------------------------------- diff --git a/ability_item_usage_skywrath_mage.lua b/ability_item_usage_skywrath_mage.lua index c3adc300..bcb14d68 100644 --- a/ability_item_usage_skywrath_mage.lua +++ b/ability_item_usage_skywrath_mage.lua @@ -8,6 +8,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -25,19 +26,19 @@ local AbilityToLevelUp= Abilities[1], Abilities[3], Abilities[1], - Abilities[4], + Abilities[5], Abilities[1], Abilities[2], Abilities[3], "talent", Abilities[3], - Abilities[4], + Abilities[5], Abilities[3], Abilities[2], "talent", Abilities[2], "nil", - Abilities[4], + Abilities[5], "nil", "talent", "nil", @@ -96,7 +97,7 @@ Consider[1]=function() local CastRange = ability:GetCastRange(); local Damage = ability:GetAbilityDamage(); - + local castPoint = ability:GetCastPoint() local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) @@ -121,20 +122,14 @@ Consider[1]=function() end --protect myself - local enemys2 = npcBot:GetNearbyHeroes( 500, true, BOT_MODE_NONE ); - if(npcBot:WasRecentlyDamagedByAnyHero(5)) - then - for _,enemy in pairs( enemys2 ) - do - if ( CanCast[1]( enemy ) ) - then - return BOT_ACTION_DESIRE_HIGH, enemy - end + if A.Unit.IsAttackingEnemies(npcBot) or A.Unit.IsRetreating(npcBot) then + local enemyAttackingMe = A.Dota.GetNearbyHeroes(npcBot, CastRange-castPoint*300) + :First(function(t) return t:GetActualIncomingDamage(Damage, DAMAGE_TYPE_MAGICAL) * 6 <= t:GetHealth() and CanCast[1](t) end) + if enemyAttackingMe then + return BOT_ACTION_DESIRE_MODERATE + 0.15, enemyAttackingMe end end - -------------------------------------- - -- Mode based usage - -------------------------------------- + --消耗 --if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) --then @@ -212,7 +207,7 @@ Consider[2]=function() 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; + return BOT_ACTION_DESIRE_HIGH end end end @@ -301,22 +296,26 @@ Consider[3]=function() end end - -- If a mode has set a target, and we can kill them, do it - local npcTarget = npcBot:GetTarget(); - if ( npcTarget ~= nil ) + if(npcBot:WasRecentlyDamagedByAnyHero(2.5) and A.Unit.IsRetreating(npcBot)) then - if(CanCast[3]( npcTarget )) + local enemy = A.Dota.GetNearbyHeroes(npcBot, CastRange-CastRange*npcBot:GetCurrentMovementSpeed()):Filter(CanCast[3]) + if enemy then + return BOT_ACTION_DESIRE_HIGH, enemy + end + end + + -- If a mode has set a target, and we can kill them, do it + local npcTarget = A.Unit.GetHeroTarget(npcBot) + if npcTarget and (CanCast[3]( npcTarget )) then + if GetUnitToUnitDistance( npcTarget, npcBot ) < ( CastRange + 200 ) then - if (GetComboDamage() > npcTarget:GetHealth() and GetUnitToUnitDistance( npcTarget, npcBot ) < ( CastRange + 200 ) ) - then - return BOT_ACTION_DESIRE_HIGH, npcTarget; - end + return BOT_ACTION_DESIRE_MODERATE-0.05, npcTarget end 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 ) + if ( #tableNearbyAttackingAlliedHeroes >= 1 ) then local npcMostDangerousEnemy = nil; @@ -342,29 +341,16 @@ Consider[3]=function() 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 npcTarget = AbilityExtensions:GetTargetIfGood(npcBot) - - if ( npcTarget ~= nil ) - then - if ( CanCast[3]( npcTarget ) and not npcTarget:IsSilenced() and GetUnitToUnitDistance(npcBot,npcTarget)< CastRange) - then - return BOT_ACTION_DESIRE_MODERATE, npcTarget; - end - end - end return BOT_ACTION_DESIRE_NONE, 0 end -Consider[4]=function() +-- 7.30 new ability shield of the scion (passive) + +-- mystic flare +Consider[5]=function() - local ability=AbilitiesReal[4]; + local ability=AbilitiesReal[5] if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, 0; diff --git a/ability_item_usage_sniper.lua b/ability_item_usage_sniper.lua index 8ca4344e..09f1881a 100644 --- a/ability_item_usage_sniper.lua +++ b/ability_item_usage_sniper.lua @@ -226,7 +226,6 @@ function Consider1() end return BOT_ACTION_DESIRE_NONE, 0; - end Consider[5]=function() diff --git a/ability_item_usage_terrorblade.lua b/ability_item_usage_terrorblade.lua index 9eb655d4..e3aaba94 100644 --- a/ability_item_usage_terrorblade.lua +++ b/ability_item_usage_terrorblade.lua @@ -9,6 +9,8 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") +-- ItemUsageThink = A.Dota.EmptyDesireFun local debugmode=false local npcBot = GetBot() diff --git a/ability_item_usage_tusk.lua b/ability_item_usage_tusk.lua index 57961e5c..8eee9d31 100644 --- a/ability_item_usage_tusk.lua +++ b/ability_item_usage_tusk.lua @@ -19,10 +19,7 @@ local AbilitiesReal ={} ability_item_usage_generic.InitAbility(Abilities,AbilitiesReal,Talents) --- utility.PrintAbilityName(Abilities) -local abilityName = { "tusk_ice_shards", "tusk_snowball", "tusk_tag_team", "tusk_walrus_kick", "tusk_frozen_sigil", "tusk_walrus_punch", "tusk_launch_snowball" } -local abilityIndex = utility.ReverseTable(abilityName) - +local abilityName = { "tusk_ice_shards", "tusk_snowball", "tusk_tag_team", "tusk_walrus_kick", "tusk_frozen_sigil", "tusk_walrus_punch", "tusk_launch_snowball", "ability_capture", "abyssal_underlord_portal_warp" } local AbilityToLevelUp= { @@ -79,7 +76,9 @@ 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,function()return true end,AbilityExtensions.PhysicalCanCastFunction,function(t) + return AbilityExtensions:AllyCanCast(t) and not AbilityExtensions:DontInterruptAlly(t) +end} local enemyDisabled=utility.enemyDisabled function GetComboDamage() @@ -541,6 +540,7 @@ Consider[6]=function() return BOT_ACTION_DESIRE_NONE, 0 end +-- launch snowball local function IsSnowballTarget(t) return t:HasModifier("modifier_tusk_snowball_target") end local snowballTarget local function RefreshSnowballTarget() @@ -553,6 +553,7 @@ Consider[7] = function() if not ability:IsFullyCastable() or ability:IsHidden() then return 0 end + local range = ability:GetSpecialValueInt "snowball_windup_radius" if snowballTarget == nil then RefreshSnowballTarget() end @@ -563,9 +564,19 @@ Consider[7] = function() if AbilityExtensions:HasAbilityRetargetModifier(snowballTarget) and not snowballTarget:IsChanneling() then return 0 end - if snowballTarget:IsChanneling() or GetUnitToUnitDistance(snowballTarget, npcBot) >= 600 then + if snowballTarget:IsChanneling() or GetUnitToUnitDistanceSqr(snowballTarget, npcBot) >= 360000 then return BOT_ACTION_DESIRE_VERYHIGH end + local availableFriends = AbilityExtensions:GetNearbyHeroes(npcBot, 600, false):Filter(function(t) + return GetUnitToUnitDistance(npcBot, t) <= range + t:GetBoundingRadius() and CanCast[7](t) + end) + availableFriends:ForEach(function(t) + print("nearby friend "..t:GetUnitName()) + end) + if availableFriends[1] then + return BOT_ACTION_DESIRE_HIGH, availableFriends[1] + end + local snowballFriends = npcBot:GetNearbyHeroes(100, false, BOT_MODE_NONE) snowballFriends = AbilityExtensions:Filter(snowballFriends, function (t) return t:HasModifier("modifier_tusk_snowball_movement_friendly") @@ -579,7 +590,8 @@ Consider[7] = function() end -Consider[4]=function() --A杖大 +-- walrus kick +Consider[4]=function() local abilityNumber=4 -------------------------------------- @@ -668,7 +680,7 @@ local clearSnowballTarget AbilityExtensions:AutoModifyConsiderFunction(npcBot, Consider, AbilitiesReal) function AbilityUsageThink() - if snowballTarget and not AbilitiesReal[2]:IsCooldownReady() and not AbilitiesReal[7]:IsHidden() and not clearSnowballTarget then + if snowballTarget and not snowballTarget:IsNull() and not AbilitiesReal[2]:IsCooldownReady() and not AbilitiesReal[7]:IsHidden() and not clearSnowballTarget then clearSnowballTarget = 1 AbilityExtensions:StartCoroutine(function() AbilityExtensions:WaitForSeconds(AbilitiesReal[2]:GetSpecialValueFloat "snowball_duration") diff --git a/ability_item_usage_undying.lua b/ability_item_usage_undying.lua index ca443df8..aafae756 100644 --- a/ability_item_usage_undying.lua +++ b/ability_item_usage_undying.lua @@ -11,7 +11,7 @@ local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstractio local debugmode=false local npcBot = GetBot() -if npcBot:IsIllusion() then return end +if npcBot:IsIllusion() or npcBot:GetUnitName() ~= "npc_dota_hero_undying" then return end local Talents ={} local Abilities ={} local AbilitiesReal ={} @@ -388,7 +388,7 @@ Consider[3]=function() -- don't give the bounty of the tombstome to enemies if there's no chance if HealthPercentage <= 0.3 and AbilityExtensions:All(enemys, function(t) return AbilityExtensions:GetHealthPercent(t) >= 0.7 - end) and npcBot:GetHeroLevel() <= 15 then + end) and npcBot:GetLevel() <= 15 then return 0 end if(trees~=nil and #trees>=1 and #enemys>=1) diff --git a/ability_item_usage_ursa.lua b/ability_item_usage_ursa.lua index 963fd46f..2e1fc912 100644 --- a/ability_item_usage_ursa.lua +++ b/ability_item_usage_ursa.lua @@ -184,7 +184,7 @@ Consider[1]=function() -- If we're farming and can hit 2+ creeps if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) then - if ( #creeps >= 2 ) + if ( #creeps >= 3 ) then if(CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL) and npcBot:GetMana()>ComboMana) then diff --git a/ability_item_usage_venomancer.lua b/ability_item_usage_venomancer.lua index 0d241a37..02c91468 100644 --- a/ability_item_usage_venomancer.lua +++ b/ability_item_usage_venomancer.lua @@ -73,9 +73,7 @@ end -------------------------------------- local cast={} cast.Desire={} cast.Target={} cast.Type={} local Consider ={} -local CanCast={function(t) - return AbilityExtensions:StunCanCast(t, AbilitiesReal[1], false, false, true, false) -end,utility.NCanCast,utility.NCanCast,utility.UCanCast} +local CanCast={AbilityExtensions.NormalCanCastFunction,utility.NCanCast,utility.NCanCast,utility.UCanCast} local enemyDisabled=utility.enemyDisabled function GetComboDamage() diff --git a/ability_item_usage_warlock.lua b/ability_item_usage_warlock.lua index 142dcc7c..0cbe5730 100644 --- a/ability_item_usage_warlock.lua +++ b/ability_item_usage_warlock.lua @@ -487,7 +487,7 @@ Consider[4]=function() -------------------------------------- -- Global high-priorty usage -------------------------------------- - local channelling = enemys:First(function(t) return AbilityExtensions:IsChannelingBreakWorthAbility(t, "moderate") and CanCast[4](t) end) + local channelling = AbilityExtensions:First(enemys, function(t) return AbilityExtensions:IsChannelingBreakWorthAbility(t, "moderate") and CanCast[4](t) end) if channelling then return BOT_ACTION_DESIRE_MODERATE-0.1, channelling:GetLocation() end diff --git a/ability_item_usage_zuus.lua b/ability_item_usage_zuus.lua index 67169c40..5dafa77d 100644 --- a/ability_item_usage_zuus.lua +++ b/ability_item_usage_zuus.lua @@ -8,6 +8,7 @@ local utility = require( GetScriptDirectory().."/utility" ) require(GetScriptDirectory() .. "/ability_item_usage_generic") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local debugmode=false local npcBot = GetBot() @@ -339,8 +340,92 @@ Consider[2]=function() return BOT_ACTION_DESIRE_NONE, 0 ,"nil"; end +-- 7.31 upgrade +Consider[3] = function() + local abilityNumber=3 + -------------------------------------- + -- Generic Variable Setting + -------------------------------------- + local ability=AbilitiesReal[abilityNumber]; + + if not ability:IsFullyCastable() or AbilityExtensions:CannotMove(npcBot) then + return BOT_ACTION_DESIRE_NONE, 0; + end + + local CastRange = 0 + local Damage = ability:GetAbilityDamage() + local Radius = ability:GetAOERadius() - 50 + local CastPoint = ability:GetCastPoint() + + 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+300,true) + local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) + --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) and GetUnitToUnitDistance(npcBot,WeakestEnemy) <= Radius-CastPoint* WeakestEnemy:GetCurrentMovementSpeed()) + then + return BOT_ACTION_DESIRE_HIGH,WeakestEnemy + end + end + end + end + + -- protect myself + if(npcBot:WasRecentlyDamagedByAnyHero(2) or #enemys >=2) + then + for _,npcEnemy in pairs( enemys ) + do + if ( CanCast[abilityNumber]( npcEnemy ) ) + then + return BOT_ACTION_DESIRE_HIGH + end + end + end + + -- If my mana is enough,use it at enemy + if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) + then + if((ManaPercentage>0.75 or npcBot:GetMana()>ComboMana) and ability:GetLevel()>=2 ) + then + if (WeakestEnemy~=nil) + then + if ( CanCast[abilityNumber]( WeakestEnemy ) ) + then + if(GetUnitToUnitDistance(npcBot,WeakestEnemy) maxm then @@ -313,7 +311,11 @@ function M:MaxV(tb, map) return nil end map = map or self.IdentityFunction +<<<<<<< HEAD local maxv,maxm = tb[1], map(tb[1]) +======= + local maxv, maxm = tb[1], map(tb[1]) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a for i = 2, #tb do local m = map(tb[i]) if m > maxm then @@ -328,7 +330,7 @@ function M:Min(tb, map) return nil end map = map or self.IdentityFunction - local maxv,maxm = tb[1], map(tb[1]) + local maxv, maxm = tb[1], map(tb[1]) for i = 2, #tb do local m = map(tb[i]) if m < maxm then @@ -343,7 +345,11 @@ function M:MinV(tb, map) return nil end map = map or self.IdentityFunction +<<<<<<< HEAD local maxv,maxm = tb[1], map(tb[1]) +======= + local maxv, maxm = tb[1], map(tb[1]) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a for i = 2, #tb do local m = map(tb[i]) if m < maxm then @@ -517,17 +523,13 @@ M.MergeSort = function(self, tb, sort) end M.Sort = M.SlowSort M.SortByMaxFirst = function(self, tb, map) - map = map or function(a, b) - return b - a - end + map = map or M.IdentityFunction return self:Sort(tb, function(a, b) return map(b) - map(a) end) end M.SortByMinFirst = function(self, tb, map) - map = map or function(a, b) - return a - b - end + map = map or M.IdentityFunction return self:Sort(tb, function(a, b) return map(a) - map(b) end) @@ -641,10 +643,10 @@ function M:CanBeEngaged(npcBot) return self:IsAttackingEnemies(npcBot) or self:IsFarmingOrPushing(npcBot) or self:IsLaning(npcBot) or not npcBot:IsBot() end M.IsRetreating = function(self, npcBot) - return npcBot:GetActiveMode() == BOT_MODE_RETREAT + return npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_ACTION_DESIRE_MODERATE end M.NotRetreating = function(self, npcBot) - return npcBot:GetActiveMode() ~= BOT_MODE_RETREAT + return not self:IsRetreating(npcBot) end M.HasEnoughManaToUseAttackAttachedAbility = function(self, npcBot, ability) local percent = self:GetManaPercent(npcBot) @@ -656,7 +658,7 @@ end M.ToggleFunctionToAction = function(self, npcBot, oldConsider, ability) local name = ability:GetName() return function() - local value,target,castType = oldConsider() + local value, target, castType = oldConsider() if type(value) == "number" then return value, target, castType end @@ -667,7 +669,7 @@ M.ToggleFunctionToAction = function(self, npcBot, oldConsider, ability) end M.ToggleFunctionToAutoCast = function(self, npcBot, ability, oldToggle) return function() - local value,target,castType = oldToggle() + local value, target, castType = oldToggle() if type(value) == "number" then return value, target, castType end @@ -679,7 +681,7 @@ M.ToggleFunctionToAutoCast = function(self, npcBot, ability, oldToggle) end M.PreventAbilityAtIllusion = function(self, npcBot, oldConsiderFunction, ability) return function() - local desire,target,targetTypeString = oldConsiderFunction() + 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 @@ -691,7 +693,7 @@ M.PreventAbilityAtIllusion = function(self, npcBot, oldConsiderFunction, ability end M.PreventEnemyTargetAbilityUsageAtAbilityBlock = function(self, npcBot, oldConsiderFunction, ability) local newConsider = function() - local desire,target,targetTypeString = oldConsiderFunction() + 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 @@ -1105,6 +1107,7 @@ M.unbreakableChannelAbilities = { "lycan_shapeshift", "item_trusty_shovel", "item_fallen_sky", + "pangolier_rollup", } M.lowPriorityChannelAbilities = { "windrunner_powershot", @@ -1240,7 +1243,7 @@ M.conditionalTrueSightRootAbilityAssociation = { ember_spirit_searing_chains = "modifier_ember_spirit_searing_chains", oracle_fortunes_end = "modifier_oracle_fortunes_end_purge", item_rod_of_atos = "modifier_rod_of_atos_debuff", - item_gleipnir = "modifier_gungir_debuff", + item_gungir = "modifier_gungir_debuff", } M.permanentTrueSightRootAbilityAssociation = { broodmother_silken_bola = "modifier_broodmother_silken_bola", @@ -1270,7 +1273,7 @@ local function ExtendAssociation(association) end):Distinct() end abilityInformationKeys:ForEach(function(t) - local a,b = ExtendAssociation(M[t]) + local a, b = ExtendAssociation(M[t]) local k = t:sub(1, #t - #"AbilityAssociation") M[k.."Abilities"] = a M[k.."Modifiers"] = b @@ -2029,7 +2032,7 @@ function M:GetMyCourier(npcBot) if npcBot.courierIDNew == nil then self:FindCourier(npcBot) end - return GetCourier(npcBot.courierIDNew) + return GetCourier(npcBot.courierIDNew or 0) end function M:FindCourier(npcBot) for i = 0, 4 do @@ -2156,6 +2159,9 @@ function M:IsDuelCaster(npc) local ability = _npc:GetAbilityByName "modifier_legion_commander_duel" return ability and ability:GetCooldownTimeRemaining() + self:GetModifierRemainingDuration(_npc, "modifier_legion_commander_duel") + 1 >= ability:GetCooldown() end + if not npc then + return false + end local npcBot = GetBot() if npcBot:GetTeam() == npc:GetTeam() then return IsTaunting(npc) @@ -2164,11 +2170,11 @@ function M:IsDuelCaster(npc) local tauntingPlayer = self:First(players, function(t) return IsTaunting(t) and t:GetAttackTarget() == npc end) - return IsTaunting and not IsTaunting(tauntingPlayer) + return tauntingPlayer and not IsTaunting(tauntingPlayer) end end function M:IsMuted(npc) - return npc:IsHexed() or self:HasAnyModifier(npc, self.muteModifiers) + return self:HasAnyModifier(npc, self.muteModifiers) end function M:IsHypnosed(npc) return self:HasAnyModifier(npc, self.hypnosisModifiers) @@ -2235,7 +2241,7 @@ M.invisibilityItems = { } M.invisibilityHeroes = { riki = 6, - clinkz = 1, + clinkz = 4, bounty_hunter = 1, phantom_assassin = 2, weaver = 1, @@ -2359,7 +2365,7 @@ function M:HasBasicDispellablePositiveModifier(npc) end) end function M:DontInterruptAlly(npc) - return self:HasAnyModifier(npc, self.positiveForceMovementModifiers) or self:HasAnyModifier(npc, self.timeSensitivePositiveModifiers) or self:IsDuelCaster(npc) + return self:HasAnyModifier(npc, self.positiveForceMovementModifiers) or self:HasAnyModifier(npc, self.timeSensitivePositiveModifiers) or self:IsDuelCaster(npc) or npc:IsChanneling() end M.MidLaneTowers = { TOWER_MID_1, @@ -2793,7 +2799,7 @@ M.GetCollapseInfo = function(self, obj1, obj2, timeLimit) end M.PreventHealAtHealSuppressTarget = function(self, npcBot, oldConsiderFunction, ability) return function() - local desire,target,targetTypeString = oldConsiderFunction() + local desire, target, targetTypeString = oldConsiderFunction() if desire == 0 or target == nil or target == 0 or targetTypeString == "Location" then return desire, target, targetTypeString end @@ -2817,6 +2823,7 @@ M.IgnoreDamageModifiers = { "modifier_winter_wyvern_winters_curse", "modifier_winter_wyvern_winters_curse_aura", "modifier_skeleton_king_reincarnation_scepter_active", + "modifier_fountain_glyph", } M.CannotKillModifiers = { "modifier_dazzle_shadow_grave", @@ -2877,11 +2884,16 @@ M.GetIllusionBattlePower = function(self, npc) 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 +<<<<<<< HEAD elseif not self:IsMeleeHero(npc) then t = t + t:GetAttackRange() / 2000 +======= + elseif self:Contains(self.ModerateIllusionHero, name) then + t = 0.25 + elseif not self:IsMeleeHero(npc) then + t = t + npc:GetAttackRange() / 2000 +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end local inventory = self:Map(self:GetInventoryItems(npc), function(t) return t:GetName() @@ -3110,7 +3122,7 @@ function M:TickFromDota() if not coroutineResult[1] then table.remove(coroutineResult, 1) print("error in coroutine:") - self:DebugTable(coroutineResult) + self:DebugLongTable(coroutineResult) end end if dotaTimer == nil then @@ -3184,9 +3196,8 @@ function M:ResumeUntilReturn(func) else table.remove(values, 1) print("error in coroutine:") - self:DebugTable(values) + self:DebugLongTable(values) break - end end return g diff --git a/util/AbilityAbstraction.mira b/util/AbilityAbstraction.mira index 66a77a76..35b78d77 100644 --- a/util/AbilityAbstraction.mira +++ b/util/AbilityAbstraction.mira @@ -539,13 +539,13 @@ end M.Sort = M.SlowSort M.SortByMaxFirst = function(self, tb, map) - map = map or function(a, b) return b-a end + map = map or M.IdentityFunction return self:Sort(tb, function(a, b) return map(b) - map(a) end) end M.SortByMinFirst = function(self, tb, map) - map = map or function(a, b) return a-b end + map = map or M.IdentityFunction return self:Sort(tb, function(a, b) return map(a) - map(b) end) @@ -682,10 +682,10 @@ function M:CanBeEngaged(npcBot) end M.IsRetreating = function(self, npcBot) - return npcBot:GetActiveMode() == BOT_MODE_RETREAT + return npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_ACTION_DESIRE_MODERATE end M.NotRetreating = function(self, npcBot) - return npcBot:GetActiveMode() ~= BOT_MODE_RETREAT + return not self:IsRetreating(npcBot) end M.HasEnoughManaToUseAttackAttachedAbility = function(self, npcBot, ability) @@ -1189,7 +1189,6 @@ M.basicDispellWorthNegativeModifiers = { M.basicDispellableNegativeModifiers = { "modifier_abaddon_frostmourne_debuff", "modifier_abaddon_frostmourne_debuff_bonus", - } M.unbreakableChannelAbilities = { @@ -1199,6 +1198,7 @@ M.unbreakableChannelAbilities = { "lycan_shapeshift", "item_trusty_shovel", "item_fallen_sky", + "pangolier_rollup", } -- items cannot be break by silence @@ -1362,7 +1362,7 @@ M.conditionalTrueSightRootAbilityAssociation = { ember_spirit_searing_chains = "modifier_ember_spirit_searing_chains", oracle_fortunes_end = "modifier_oracle_fortunes_end_purge", item_rod_of_atos = "modifier_rod_of_atos_debuff", - item_gleipnir = "modifier_gungir_debuff", + item_gungir = "modifier_gungir_debuff", } M.permanentTrueSightRootAbilityAssociation = { @@ -2167,7 +2167,7 @@ function M:GetMyCourier(npcBot) if npcBot.courierIDNew == nil then self:FindCourier(npcBot) end - return GetCourier(npcBot.courierIDNew) + return GetCourier(npcBot.courierIDNew or 0) end function M:FindCourier(npcBot) @@ -2311,6 +2311,9 @@ function M:IsDuelCaster(npc) local ability = _npc:GetAbilityByName "modifier_legion_commander_duel" return ability and ability:GetCooldownTimeRemaining() + self:GetModifierRemainingDuration(_npc, "modifier_legion_commander_duel") + 1 >= ability:GetCooldown() end + if not npc then --dont know why _npc can be null + return false + end local npcBot = GetBot() if npcBot:GetTeam() == npc:GetTeam() then return IsTaunting(npc) @@ -2319,12 +2322,12 @@ function M:IsDuelCaster(npc) local tauntingPlayer = self:First(players, function(t) return IsTaunting(t) and t:GetAttackTarget() == npc end) - return IsTaunting and not IsTaunting(tauntingPlayer) + return tauntingPlayer and not IsTaunting(tauntingPlayer) end end function M:IsMuted(npc) - return npc:IsHexed() or self:HasAnyModifier(npc, self.muteModifiers) + return self:HasAnyModifier(npc, self.muteModifiers) end function M:IsHypnosed(npc) @@ -2404,7 +2407,7 @@ M.invisibilityItems = { } M.invisibilityHeroes = { riki = 6, - clinkz = 1, + clinkz = 4, bounty_hunter = 1, phantom_assassin = 2, weaver = 1, @@ -2533,7 +2536,7 @@ function M:HasBasicDispellablePositiveModifier(npc) end function M:DontInterruptAlly(npc) - return self:HasAnyModifier(npc, self.positiveForceMovementModifiers) or self:HasAnyModifier(npc, self.timeSensitivePositiveModifiers) or self:IsDuelCaster(npc) + return self:HasAnyModifier(npc, self.positiveForceMovementModifiers) or self:HasAnyModifier(npc, self.timeSensitivePositiveModifiers) or self:IsDuelCaster(npc) or npc:IsChanneling() end M.MidLaneTowers = { TOWER_MID_1, TOWER_MID_2, TOWER_MID_3 } @@ -3080,6 +3083,7 @@ M.IgnoreDamageModifiers = { "modifier_winter_wyvern_winters_curse", "modifier_winter_wyvern_winters_curse_aura", "modifier_skeleton_king_reincarnation_scepter_active", + "modifier_fountain_glyph", } M.CannotKillModifiers = { @@ -3135,13 +3139,18 @@ M.GetIllusionBattlePower = function(self, npc) 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 +<<<<<<< HEAD elseif not self:IsMeleeHero(npc) then t = t + t:GetAttackRange() / 2000 +======= + elseif self:Contains(self.ModerateIllusionHero, name) then + t = 0.25 + elseif not self:IsMeleeHero(npc) then + t = t + npc:GetAttackRange() / 2000 +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end - local inventory = self:Map(self:GetInventoryItems(npc), function(t) return t:GetName() end) + local inventory = self:Map(self:GetInventoryItems(npc)) { t -> t:GetName() } if self:Contains(inventory, "item_radiance") then t = t+0.07 end @@ -3383,7 +3392,7 @@ function M:TickFromDota() if not coroutineResult[1] then table.remove(coroutineResult, 1) print("error in coroutine:") - self:DebugTable(coroutineResult) + self:DebugLongTable(coroutineResult) end end if dotaTimer == nil then @@ -3460,7 +3469,7 @@ function M:ResumeUntilReturn(func) else table.remove(values, 1) print("error in coroutine:") - self:DebugTable(values) + self:DebugLongTable(values) break end end diff --git a/util/CommonBehaviours.lua b/util/CommonBehaviours.lua index 5a8f31d1..e20a4ec4 100644 --- a/util/CommonBehaviours.lua +++ b/util/CommonBehaviours.lua @@ -1,9 +1,10 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local M = {} local avoidCurseList = fun1:NewTable() local bot @@ -14,19 +15,9 @@ local AvoidWintersCurse = fun1:EveryManySeconds(0.3, function() return t:HasModifier "modifier_winter_wyvern_winters_curse_aura" end) if cursedOne then - if not l.avoidCurseList:Contains(cursedOne) then + if not bot:IsMagicImmune() and not l.avoidCurseList:Contains(cursedOne) then table.insert(l.avoidCurseList, cursedOne) local location = cursedOne:GetLocation() - location.z = 525 + bot:GetBoundingRadius() - local zone = AddAvoidanceZone(location) - print("add zone "..tostring(zone)) - fun1:StartCoroutine(function(deltaTime) - while cursedOne:HasModifier "modifier_winter_wyvern_winters_curse_aura" do - coroutine.yield() - end - RemoveAvoidanceZone(zone) - return l.avoidCurseList:Remove_Modify(cursedOne) - end) end end end @@ -59,8 +50,25 @@ local Init = function() } end end +local pushModes = A.Linq.NewTable(BOT_MODE_PUSH_TOWER_BOT, BOT_MODE_PUSH_TOWER_MID, BOT_MODE_PUSH_TOWER_TOP) +local function IsPushingMode(mode) + return pushModes:Contains(mode) +end +local NoNearbyEnemiesWhenLaning = function() + if bot:GetActiveMode() == BOT_MODE_LANING or IsPushingMode(bot:GetActiveMode()) and A.Dota.GetNearbyHeroes(bot, 1600):Count() == 0 then + if bot.noNearbyEnemiesWhenLaningTime == nil then + bot.noNearbyEnemiesWhenLaningTime = DotaTime() + end + if bot.noNearbyEnemiesWhenLaningTime - DotaTime() > 3 then + bot.pushWhenNoEnemies = true + end + else + bot.pushWhenNoEnemies = nil + end +end local Think = function() AvoidWintersCurse() + NoNearbyEnemiesWhenLaning() end function M.Think() bot = GetBot() diff --git a/util/CommonBehaviours.mira b/util/CommonBehaviours.mira index ec31ee38..64f716c4 100644 --- a/util/CommonBehaviours.mira +++ b/util/CommonBehaviours.mira @@ -1,27 +1,29 @@ local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") local M = {} local avoidCurseList = fun1:NewTable() + local bot local AvoidWintersCurse = fun1:EveryManySeconds(0.3) { -> local l = bot._commonBehaviours_alt if local cursedOne = fun1:GetNearbyHeroes(bot, 800, false):First { t -> t:HasModifier "modifier_winter_wyvern_winters_curse_aura" } then - if not l.avoidCurseList:Contains(cursedOne) then + if not bot:IsMagicImmune() and not l.avoidCurseList:Contains(cursedOne) then table.insert(l.avoidCurseList, cursedOne) local location = cursedOne:GetLocation() - location.z = 525 + bot:GetBoundingRadius() - local zone = AddAvoidanceZone(location) - print("add zone "..tostring(zone)) - fun1:StartCoroutine { deltaTime -> - -- fun1:WaitForSeconds(cursedOne:GetModifierRemainingDuration "modifier_winter_wyvern_winters_curse_aura") - while cursedOne:HasModifier "modifier_winter_wyvern_winters_curse_aura" do - -- DebugDrawCircle(cursedOne:GetLocation(), 525+fun1.commonBoudingRadius, 255, 0, 0) - coroutine.yield() - end - RemoveAvoidanceZone(zone) - l.avoidCurseList:Remove_Modify(cursedOne) - } + -- location.z = 525 + bot:GetBoundingRadius() + -- local zone = AddAvoidanceZone(location) + -- print("add zone "..tostring(zone)) + -- fun1:StartCoroutine { deltaTime -> + -- -- fun1:WaitForSeconds(cursedOne:GetModifierRemainingDuration "modifier_winter_wyvern_winters_curse_aura") + -- while cursedOne:HasModifier "modifier_winter_wyvern_winters_curse_aura" do + -- -- DebugDrawCircle(cursedOne:GetLocation(), 525+fun1.commonBoudingRadius, 255, 0, 0) + -- coroutine.yield() + -- end + -- RemoveAvoidanceZone(zone) + -- l.avoidCurseList:Remove_Modify(cursedOne) + -- } end end } @@ -52,13 +54,31 @@ local Init = function() bot._commonBehaviours_alt = { avoidCurseList = fun1:NewTable(), avoidFirestorm = fun1:NewTable(), - } end end +local pushModes = A.Linq.NewTable(BOT_MODE_PUSH_TOWER_BOT, BOT_MODE_PUSH_TOWER_MID, BOT_MODE_PUSH_TOWER_TOP) +local function IsPushingMode(mode) + return pushModes:Contains(mode) +end + +local NoNearbyEnemiesWhenLaning = function() + if bot:GetActiveMode() == BOT_MODE_LANING or IsPushingMode(bot:GetActiveMode()) and A.Dota.GetNearbyHeroes(bot, 1600):Count() == 0 then + if bot.noNearbyEnemiesWhenLaningTime == nil then + bot.noNearbyEnemiesWhenLaningTime = DotaTime() + end + if bot.noNearbyEnemiesWhenLaningTime - DotaTime() > 3 then + bot.pushWhenNoEnemies = true + end + else + bot.pushWhenNoEnemies = nil + end +end + local Think = function() AvoidWintersCurse() + NoNearbyEnemiesWhenLaning() end function M.Think() diff --git a/util/ItemPurchaseSystem.lua b/util/ItemPurchaseSystem.lua index 835b912d..f1d29564 100644 --- a/util/ItemPurchaseSystem.lua +++ b/util/ItemPurchaseSystem.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -8,23 +8,14 @@ local M = BotsInit.CreateGeneric() local utility = require(GetScriptDirectory().."/utility") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") local TeamItemThink = require(GetScriptDirectory().."/util/TeamItemThink") +local A = require(GetScriptDirectory().."/util/MiraDota") function M.SellExtraItem(ItemsToBuy) local npcBot = GetBot() local level = npcBot:GetLevel() - local item_travel_boots = M.NoNeedTpscrollForTravelBoots() if M.IsItemSlotsFull() then - if GameTime() > 6 * 60 or level >= 6 then - M.SellSpecifiedItem("item_faerie_fire") - M.SellSpecifiedItem("item_tango") - M.SellSpecifiedItem("item_clarity") - M.SellSpecifiedItem("item_flask") - end if GameTime() > 25 * 60 or level >= 10 then M.SellSpecifiedItem("item_orb_of_venom") M.SellSpecifiedItem("item_enchanted_mango") - M.SellSpecifiedItem("item_bracer") - M.SellSpecifiedItem("item_null_talisman") - M.SellSpecifiedItem("item_wraith_band") end if GameTime() > 35 * 60 or level >= 15 then M.SellSpecifiedItem("item_branches") @@ -37,6 +28,9 @@ function M.SellExtraItem(ItemsToBuy) M.SellSpecifiedItem("item_soul_ring") M.SellSpecifiedItem("item_buckler") M.SellSpecifiedItem("item_headdress") + M.SellSpecifiedItem("item_bracer") + M.SellSpecifiedItem("item_null_talisman") + M.SellSpecifiedItem("item_wraith_band") end if GameTime() > 40 * 60 or level >= 20 then M.SellSpecifiedItem("item_urn_of_shadows") @@ -44,23 +38,12 @@ function M.SellExtraItem(ItemsToBuy) M.SellSpecifiedItem("item_witch_blade") end end - if item_travel_boots[1] ~= nil or item_travel_boots[2] ~= nil then - M.SellSpecifiedItem("item_boots") - M.SellSpecifiedItem("item_arcane_boots") - M.SellSpecifiedItem("item_phase_boots") - M.SellSpecifiedItem("item_power_treads_agi") - M.SellSpecifiedItem("item_power_treads_int") - M.SellSpecifiedItem("item_power_treads_str") - M.SellSpecifiedItem("item_tranquil_boots") - end end -function isLeaf(Node) - local recipe = GetItemComponents(Node) - return next(recipe) == nil +local function isLeaf(Node) + return next(GetItemComponents(Node)) == nil end -function nextNodes(Node) - local recipe = GetItemComponents(Node) - return recipe[1] +local function nextNodes(Node) + return GetItemComponents(Node)[1] end M.ExpandItemRecipe = function(self, itemTable) local output = {} @@ -275,7 +258,6 @@ function M.BuySupportItem() npcBot:ActionImmediate_PurchaseItem("item_ward_observer") end if item_smoke == nil and GetItemStockCount("item_smoke_of_deceit") >= 1 and npcBot:GetGold() >= GetItemCost("item_smoke_of_deceit") then - npcBot:ActionImmediate_PurchaseItem("item_smoke_of_deceit") end end end @@ -329,142 +311,141 @@ M.Consumables = { M.IsConsumableItem = function(self, item) return AbilityExtensions:Contains(self.Consumables, string.sub(item, 6)) end -M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) - local function ExpandFirstLevel(item) - if isLeaf(item) then - return { - name = item, - isSingleItem = true, - } +local function ExpandFirstLevel(item) + if isLeaf(item) then + return { + name = item, + isSingleItem = true, + } + else + return { + name = item, + recipe = nextNodes(item), + } + end +end +local function ExpandOnce(item) + local g = {} + local expandSomething = false + for _, v in ipairs(item.recipe) do + if isLeaf(v) then + table.insert(g, v) else - return { - name = item, - recipe = nextNodes(item), - } - end - end - local function ExpandOnce(item) - local g = {} - local expandSomething = false - for _, v in ipairs(item.recipe) do - if isLeaf(v) then - table.insert(g, v) - else - expandSomething = true - for _, i in ipairs(nextNodes(v)) do - table.insert(g, i) - end + expandSomething = true + for _, i in ipairs(nextNodes(v)) do + table.insert(g, i) end end - item.recipe = g - return expandSomething end - local function RemoveBoughtItems() - local boughtItems = AbilityExtensions:Map(AbilityExtensions:GetAllBoughtItems(npcBot), function(t) - return t:GetName() - end) - local function TryRemoveItemWithName(itemName, tbToRemoveFirst) - if self:IsConsumableItem(itemName) then - table.remove(tbToRemoveFirst, 1) - return true - end - for i, boughtItem in ipairs(boughtItems) do - if boughtItem and boughtItem == itemName then - table.remove(boughtItems, i) - table.remove(tbToRemoveFirst, 1) - return true + item.recipe = g + return expandSomething +end +local function PrintItemInfoTableOf(npcBot) + local tb = npcBot.itemInformationTable + print(npcBot:GetUnitName().." items to buy: ") + A.Linq.ForEach(tb, function(t, index) + if t.isSingleItem then + print(index..": "..t.name) + else + local s = "" + A.Linq.ForEach(t.recipe, function(t1, t1Index) + s = s..t1 + if t1Index ~= #t.recipe then + s = s..", " end - end + end) + print(index..": "..t.name.." { "..s.." }") end - local function TryRemoveItem(item, tbToRemoveFirst) - if self:IsConsumableItem(item.name) then - table.remove(tbToRemoveFirst, 1) - return true - end - local i = 1 - local boughtItem - while i <= #boughtItems do - boughtItem = boughtItems[i] - if boughtItem and boughtItem == item.name then - table.remove(boughtItems, i) - table.remove(tbToRemoveFirst, 1) - return true - elseif item.usedAsRecipeOf and AbilityExtensions:Contains(boughtItems, item.usedAsRecipeOf) then - table.remove(tbToRemoveFirst, 1) - return true - end - i = i + 1 + end) +end +M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) + local g = A.Linq.NewTable() + g.hero = npcBot + if not A.Unit.CanBuyItem(npcBot) then + npcBot.itemInformationTable = g + return + end + local boughtItems = AbilityExtensions:GetAllBoughtItems(npcBot):Map(function(t) + return { + name = t:GetName(), + charge = t:GetCurrentCharges(), + } + end) + for _, item in pairs(itemTable) do + local dontExpand + if DotaTime() > 0 and M:IsConsumableItem(item) then + dontExpand = true + end + for i, b in ipairs(boughtItems) do + if item == b.name then + dontExpand = true + table.remove(boughtItems, i) + break end end - local infoTable = npcBot.itemInformationTable - while TryRemoveItem(infoTable[1], infoTable) do + if item == "item_ultimate_scepter" and A.Hero.HasBoughtScepter(npcBot) then + dontExpand = true end - while infoTable[1] and infoTable[1].recipe do - while #infoTable[1].recipe > 0 and TryRemoveItemWithName(infoTable[1].recipe[1], infoTable[1].recipe) do - end - if #infoTable[1].recipe == 0 then - table.remove(infoTable, 1) - else - break - - end + if item == "item_ultimate_scepter_2" and (npcBot:HasModifier "modifier_item_ultimate_scepter" or npcBot:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist") then + dontExpand = true end - if npcBot:HasModifier "modifier_item_ultimate_scepter" then - AbilityExtensions:Remove_Modify(infoTable, function(t) - return t.name == "item_ultimate_scepter" or t.name == "item_ultimate_scepter_2" - end) + if item == "item_moon_shard" and npcBot:HasModifier "modifier_item_moon_shard_consumed" then + dontExpand = true end - if npcBot:HasModifier "modifier_item_moon_shard_consumed" then - AbilityExtensions:Remove_Modify(infoTable, function(t) - return t.name == "item_moon_shard" - end) + if item == "item_aghanims_shard" and npcBot:HasModifier "modifier_item_agahanims_shard" then + dontExpand = true end - end - local g = {} - g.hero = npcBot - for _, item in pairs(itemTable) do - local itemInformation = ExpandFirstLevel(item) - if itemInformation.isSingleItem then - else - ::h:: - local recipe = itemInformation.recipe - local deletedKeys = {} - for _, boughtItem in pairs(g) do - if not boughtItem.usedAsRecipeOf then + if not dontExpand then + local itemInformation = ExpandFirstLevel(item) + if itemInformation.isSingleItem then + else + ::expandSuccess:: + local recipe = itemInformation.recipe + for _, builtItem in ipairs(g) do + if not builtItem.usedAsRecipeOf then + for componentIndex, componentName in ipairs(recipe) do + if componentName == builtItem.name then + builtItem.usedAsRecipeOf = itemInformation.name + table.remove(recipe, componentIndex) + break + end + end + end + end + ::removeBoughtItems:: + local boughtItemIndex = 1 + while boughtItemIndex <= #boughtItems do + local boughtItem = boughtItems[boughtItemIndex] for componentIndex, componentName in ipairs(recipe) do if componentName == boughtItem.name then - table.insert(deletedKeys, componentName) - boughtItem.usedAsRecipeOf = itemInformation.name - break - + table.remove(boughtItems, boughtItemIndex) + table.remove(recipe, componentIndex) + goto removeBoughtItems end end + boughtItemIndex = boughtItemIndex + 1 end - end - for _, v in pairs(deletedKeys) do - for t1, t2 in ipairs(recipe) do - if t2 == v then - table.remove(recipe, t1) - break - - end + if ExpandOnce(itemInformation) then + goto expandSuccess end end - if ExpandOnce(itemInformation) then - goto h + if itemInformation.recipe and #itemInformation.recipe > 0 or itemInformation.isSingleItem then + table.insert(g, itemInformation) end end - table.insert(g, itemInformation) end npcBot.itemInformationTable = g +<<<<<<< HEAD if not AbilityExtensions:GameNotReallyStarting() then RemoveBoughtItems() end +======= +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local function RemoveTeamItems(t) local implmentedItems = TeamItemThink.ImplmentedTeamItems or {} AbilityExtensions:ForEach(implmentedItems, function(itemName) AbilityExtensions:Remove_Modify(t, function(itemInfo) - return itemInfo.name == itemName or itemInfo.usedAsRecipeOf == itemName or itemInfo.recipe and AbilityExtensions:Contains(itemInfo.recipe, itemName) + return itemInfo.name == itemName end) end) return t @@ -473,10 +454,14 @@ M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) RemoveTeamItems(g) TeamItemThink.TeamItemThink(npcBot) end + PrintItemInfoTableOf(npcBot) end local sNextItem local UseCourier = function() local npcBot = GetBot() + if not A.Unit.CanBuyItem(npcBot) then + return + end local courier = AbilityExtensions:GetMyCourier(npcBot) if courier == nil then return @@ -570,7 +555,7 @@ M.ItemPurchaseExtend = function(self, ItemsToBuy) return AbilityExtensions:MayNotBeIllusion(GetBot(), t) end) if AbilityExtensions:Any(enemies, function(t) - return t:GetUnitName() == AbilityExtensions:GetHeroFullName("bounty_hunter") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("slardar") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("rattletrap") and t:GetLevel() >= 18 + return t:GetUnitName() == AbilityExtensions:GetHeroFullName("bounty_hunter") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("slardar") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("rattletrap") and t:GetLevel() >= 12 end) then M:RemoveInvisibleItemPurchase(GetBot()) end @@ -620,7 +605,11 @@ M.ItemPurchaseExtend = function(self, ItemsToBuy) npcBot.secretShopMode = false RemoveTopItemToBuy() elseif PurchaseResult ~= -2 then +<<<<<<< HEAD print("purchase item failed: "..sNextItem..", fail code: "..AbilityExtensions:ToIntItemPurchaseResult(PurchaseResult)) +======= + print(npcBot:GetUnitName().."purchase item failed: "..sNextItem..", fail code: "..AbilityExtensions:ToIntItemPurchaseResult(PurchaseResult)) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end if PurchaseResult == PURCHASE_ITEM_OUT_OF_STOCK then M.SellSpecifiedItem("item_faerie_fire") diff --git a/util/ItemPurchaseSystem.mira b/util/ItemPurchaseSystem.mira index 033d1c37..1211ce1e 100644 --- a/util/ItemPurchaseSystem.mira +++ b/util/ItemPurchaseSystem.mira @@ -3,30 +3,18 @@ local M = BotsInit.CreateGeneric() local utility = require(GetScriptDirectory().."/utility") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") local TeamItemThink = require(GetScriptDirectory().."/util/TeamItemThink") +local A = require(GetScriptDirectory().."/util/MiraDota") function M.SellExtraItem(ItemsToBuy) local npcBot = GetBot() local level = npcBot:GetLevel() - local item_travel_boots = M.NoNeedTpscrollForTravelBoots() - -- local item_travel_boots_1 = item_travel_boots[1] - -- local item_travel_boots_2 = item_travel_boots[2] if(M.IsItemSlotsFull()) then - if(GameTime()>6*60 or level>=6) - then - M.SellSpecifiedItem("item_faerie_fire") - M.SellSpecifiedItem("item_tango") - M.SellSpecifiedItem("item_clarity") - M.SellSpecifiedItem("item_flask") - end if(GameTime()>25*60 or level>=10) then M.SellSpecifiedItem("item_orb_of_venom") M.SellSpecifiedItem("item_enchanted_mango") - M.SellSpecifiedItem("item_bracer") - M.SellSpecifiedItem("item_null_talisman") - M.SellSpecifiedItem("item_wraith_band") end if(GameTime()>35*60 or level>=15) then @@ -40,6 +28,9 @@ function M.SellExtraItem(ItemsToBuy) M.SellSpecifiedItem("item_soul_ring") M.SellSpecifiedItem("item_buckler") M.SellSpecifiedItem("item_headdress") + M.SellSpecifiedItem("item_bracer") + M.SellSpecifiedItem("item_null_talisman") + M.SellSpecifiedItem("item_wraith_band") end if(GameTime()>40*60 or level>=20) then @@ -49,39 +40,23 @@ function M.SellExtraItem(ItemsToBuy) -- M.SellSpecifiedItem("item_mask_of_madness") -- M.SellSpecifiedItem("item_hand_of_midas") end - --if(GameTime()>40*60 and npcBot:GetGold()>2500 and (item_travel_boots[1]==nil and item_travel_boots[2]==nil) and npcBot.HaveTravelBoots~=true ) - --then - -- table.insert(ItemsToBuy,"item_boots") - -- table.insert(ItemsToBuy,"item_recipe_travel_boots") - -- npcBot.HaveTravelBoots = true - -- if npcBot:GetGold() >= 4500 then - -- table.insert(ItemsToBuy, "item_recipe_travel_boots") - -- end - --end - end - - if(item_travel_boots[1]~=nil or item_travel_boots[2]~=nil) - then - M.SellSpecifiedItem("item_boots") - M.SellSpecifiedItem("item_arcane_boots") - M.SellSpecifiedItem("item_phase_boots") - M.SellSpecifiedItem("item_power_treads_agi") - M.SellSpecifiedItem("item_power_treads_int") - M.SellSpecifiedItem("item_power_treads_str") - M.SellSpecifiedItem("item_tranquil_boots") end -end + -- if(item_travel_boots[1]~=nil or item_travel_boots[2]~=nil) + -- then + -- M.SellSpecifiedItem("item_boots") + -- M.SellSpecifiedItem("item_arcane_boots") + -- M.SellSpecifiedItem("item_phase_boots") + -- M.SellSpecifiedItem("item_power_treads_agi") + -- M.SellSpecifiedItem("item_power_treads_int") + -- M.SellSpecifiedItem("item_power_treads_str") + -- M.SellSpecifiedItem("item_tranquil_boots") + -- end -function isLeaf (Node) - local recipe = GetItemComponents(Node) - return next(recipe) == nil end -function nextNodes (Node) - local recipe = GetItemComponents(Node) - return recipe[1] -end +local function isLeaf(Node) -> next(GetItemComponents(Node)) == nil +local function nextNodes(Node) -> GetItemComponents(Node)[1] M.ExpandItemRecipe = function(self, itemTable) local output = {} @@ -158,7 +133,6 @@ function M.WeNeedTpscroll() -- If we are at the sideshop or fountain with no TPs, then buy one or two if ((iScrollCount <= 2 and DotaTime() >= 5*60) or iScrollCount == 0) and item_travel_boots_1 == nil and item_travel_boots_2 == nil then if npcBot:DistanceFromFountain() <= 200 then - if (DotaTime() > 2*60 and DotaTime() < 20 * 60) then npcBot:ActionImmediate_PurchaseItem("item_tpscroll") elseif (DotaTime() >= 20 * 60) then @@ -385,7 +359,7 @@ function M.BuySupportItem() if(item_smoke==nil and GetItemStockCount("item_smoke_of_deceit")>=1 and npcBot:GetGold() >= GetItemCost("item_smoke_of_deceit")) then - npcBot:ActionImmediate_PurchaseItem("item_smoke_of_deceit") + -- npcBot:ActionImmediate_PurchaseItem("item_smoke_of_deceit") end end @@ -449,134 +423,141 @@ M.IsConsumableItem = function(self, item) return AbilityExtensions:Contains(self.Consumables, string.sub(item, 6)) end -M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) - local function ExpandFirstLevel(item) - if isLeaf(item) then - return { name = item, isSingleItem = true } - else - return { name = item, recipe = nextNodes(item) } - end +-- create item info table functions +local function ExpandFirstLevel(item) + if isLeaf(item) then + return { name = item, isSingleItem = true } + else + return { name = item, recipe = nextNodes(item) } end - local function ExpandOnce(item) - local g = {} - local expandSomething = false - for _,v in ipairs(item.recipe) do - if isLeaf(v) then - table.insert(g, v) - else - expandSomething = true - for _, i in ipairs(nextNodes(v)) do - table.insert(g, i) - end - end - end - item.recipe = g - return expandSomething - end - - local function RemoveBoughtItems() -- used only when reloading scripts in game - local boughtItems = AbilityExtensions:Map(AbilityExtensions:GetAllBoughtItems(npcBot)) { - t -> t:GetName() - } - local function TryRemoveItemWithName(itemName, tbToRemoveFirst) - -- print("try remove item with name "..itemName) - if self:IsConsumableItem(itemName) then - table.remove(tbToRemoveFirst, 1) - return true - end - for i, boughtItem in ipairs(boughtItems) do - if boughtItem and boughtItem == itemName then - table.remove(boughtItems, i) - table.remove(tbToRemoveFirst, 1) - return true - end +end + +local function ExpandOnce(item) + local g = {} + local expandSomething = false + for _,v in ipairs(item.recipe) do + if isLeaf(v) then + table.insert(g, v) + else + expandSomething = true + for _, i in ipairs(nextNodes(v)) do + table.insert(g, i) end end + end + item.recipe = g + return expandSomething +end - local function TryRemoveItem(item, tbToRemoveFirst) - -- print("try remove item "..item.name) - if self:IsConsumableItem(item.name) then - table.remove(tbToRemoveFirst, 1) - return true - end - local i = 1 - local boughtItem - while i <= #boughtItems do - boughtItem = boughtItems[i] - if boughtItem and boughtItem == item.name then - table.remove(boughtItems, i) - table.remove(tbToRemoveFirst, 1) - return true - elseif item.usedAsRecipeOf and AbilityExtensions:Contains(boughtItems, item.usedAsRecipeOf) then - table.remove(tbToRemoveFirst, 1) - return true +local function PrintItemInfoTableOf(npcBot) + local tb = npcBot.itemInformationTable + print(npcBot:GetUnitName().." items to buy: ") + A.Linq.ForEach(tb) { t, index -> + if t.isSingleItem then print(index..": "..t.name) + else + local s = "" + A.Linq.ForEach(t.recipe) { t1, t1Index -> + s = s..t1 + if t1Index ~= #t.recipe then + s = s..", " end - i = i + 1 - end + } + print(index..": "..t.name.." { "..s.." }") end + } +end - local infoTable = npcBot.itemInformationTable - while TryRemoveItem(infoTable[1], infoTable) do end - while infoTable[1] and infoTable[1].recipe do - while #infoTable[1].recipe > 0 and TryRemoveItemWithName(infoTable[1].recipe[1], infoTable[1].recipe) do end - if #infoTable[1].recipe == 0 then - table.remove(infoTable, 1) - else +M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) + local g = A.Linq.NewTable() + g.hero = npcBot + if not A.Unit.CanBuyItem(npcBot) then + npcBot.itemInformationTable = g + return + end + local boughtItems = AbilityExtensions:GetAllBoughtItems(npcBot):Map { t -> { name = t:GetName(), charge = t:GetCurrentCharges() } } + for _, item in pairs(itemTable) do + local dontExpand + if DotaTime() > 0 and M:IsConsumableItem(item) then + dontExpand = true + end + for i, b in ipairs(boughtItems) do + if item == b.name then + dontExpand = true + table.remove(boughtItems, i) break end end - if npcBot:HasModifier "modifier_item_ultimate_scepter" then - AbilityExtensions:Remove_Modify(infoTable, function(t) return t.name == "item_ultimate_scepter" or t.name == "item_ultimate_scepter_2" end) + if item == "item_ultimate_scepter" and A.Hero.HasBoughtScepter(npcBot) then + dontExpand = true end - if npcBot:HasModifier "modifier_item_moon_shard_consumed" then - AbilityExtensions:Remove_Modify(infoTable, function(t) return t.name == "item_moon_shard" end) + if item == "item_ultimate_scepter_2" and (npcBot:HasModifier "modifier_item_ultimate_scepter" or npcBot:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist") then + dontExpand = true + end + if item == "item_moon_shard" and npcBot:HasModifier "modifier_item_moon_shard_consumed" then + dontExpand = true + end + if item == "item_aghanims_shard" and npcBot:HasModifier "modifier_item_agahanims_shard" then + dontExpand = true end - end - local g = {} - g.hero = npcBot - for _, item in pairs(itemTable) do - local itemInformation = ExpandFirstLevel(item) - if itemInformation.isSingleItem then - else - ::h:: local recipe = itemInformation.recipe - local deletedKeys = {} - for _, boughtItem in pairs(g) do - if not boughtItem.usedAsRecipeOf then + if not dontExpand then + local itemInformation = ExpandFirstLevel(item) + if itemInformation.isSingleItem then + -- intentionally do nothing + else + ::expandSuccess:: + local recipe = itemInformation.recipe + -- remove components from built items + for _, builtItem in ipairs(g) do + if not builtItem.usedAsRecipeOf then + for componentIndex, componentName in ipairs(recipe) do + if componentName == builtItem.name then + builtItem.usedAsRecipeOf = itemInformation.name + table.remove(recipe, componentIndex) + break + end + end + end + end + + -- remove already bought items (used when reloading) + ::removeBoughtItems:: + local boughtItemIndex = 1 + while boughtItemIndex <= #boughtItems do + local boughtItem = boughtItems[boughtItemIndex] for componentIndex, componentName in ipairs(recipe) do if componentName == boughtItem.name then - table.insert(deletedKeys, componentName) - boughtItem.usedAsRecipeOf = itemInformation.name - break + table.remove(boughtItems, boughtItemIndex) + table.remove(recipe, componentIndex) + goto removeBoughtItems end end + boughtItemIndex += 1 end - end - for _, v in pairs(deletedKeys) do - for t1,t2 in ipairs(recipe) do - if t2 == v then - table.remove(recipe, t1) - break - end + + if ExpandOnce(itemInformation) then + goto expandSuccess end end - if ExpandOnce(itemInformation) then - goto h - end + if itemInformation.recipe and #itemInformation.recipe > 0 or itemInformation.isSingleItem then + table.insert(g, itemInformation) + end end - table.insert(g, itemInformation) end npcBot.itemInformationTable = g +<<<<<<< HEAD if not AbilityExtensions:GameNotReallyStarting() then RemoveBoughtItems() end -- AbilityExtensions:ForEach(g) {item -> AbilityExtensions:DebugTable(item)} +======= +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local function RemoveTeamItems(t) local implmentedItems = TeamItemThink.ImplmentedTeamItems or {} AbilityExtensions:ForEach(implmentedItems, function(itemName) AbilityExtensions:Remove_Modify(t, function(itemInfo) - return itemInfo.name == itemName or itemInfo.usedAsRecipeOf == itemName or itemInfo.recipe and AbilityExtensions:Contains(itemInfo.recipe, itemName) + return itemInfo.name == itemName end) end) return t @@ -586,11 +567,15 @@ M.CreateItemInformationTable = function(self, npcBot, itemTable, noRemove) RemoveTeamItems(g) TeamItemThink.TeamItemThink(npcBot) end + PrintItemInfoTableOf(npcBot) end local sNextItem local UseCourier = function() local npcBot = GetBot() + if not A.Unit.CanBuyItem(npcBot) then + return + end local courier = AbilityExtensions:GetMyCourier(npcBot) if courier == nil then return @@ -691,7 +676,7 @@ M.ItemPurchaseExtend = function(self, ItemsToBuy) return AbilityExtensions:MayNotBeIllusion(GetBot(), t) end) if AbilityExtensions:Any(enemies, function(t) - return t:GetUnitName() == AbilityExtensions:GetHeroFullName("bounty_hunter") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("slardar") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("rattletrap") and t:GetLevel() >= 18 + return t:GetUnitName() == AbilityExtensions:GetHeroFullName("bounty_hunter") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("slardar") or t:GetUnitName() == AbilityExtensions:GetHeroFullName("rattletrap") and t:GetLevel() >= 12 end) then M:RemoveInvisibleItemPurchase(GetBot()) end @@ -716,11 +701,11 @@ M.ItemPurchaseExtend = function(self, ItemsToBuy) M.SellExtraItem(ItemsToBuy) if npcBot:DistanceFromFountain()<=2500 or npcBot:GetHealth()/npcBot:GetMaxHealth()<=0.35 then - npcBot.secretShopMode = false + npcBot.secretShopMode = false end if IsItemPurchasedFromSecretShop(sNextItem)==false then - npcBot.secretShopMode = false + npcBot.secretShopMode = false end if npcBot:GetGold() >= GetItemCost(sNextItem) then @@ -752,7 +737,11 @@ M.ItemPurchaseExtend = function(self, ItemsToBuy) npcBot.secretShopMode = false RemoveTopItemToBuy() elseif PurchaseResult ~= -2 then +<<<<<<< HEAD print("purchase item failed: "..sNextItem..", fail code: "..AbilityExtensions:ToIntItemPurchaseResult(PurchaseResult)) +======= + print(npcBot:GetUnitName().."purchase item failed: "..sNextItem..", fail code: "..AbilityExtensions:ToIntItemPurchaseResult(PurchaseResult)) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end if(PurchaseResult==PURCHASE_ITEM_OUT_OF_STOCK) then diff --git a/util/ItemUsage-New.lua b/util/ItemUsage-New.lua index aa2bf6f6..225a85ad 100644 --- a/util/ItemUsage-New.lua +++ b/util/ItemUsage-New.lua @@ -1,5 +1,5 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- @@ -7,6 +7,7 @@ local M = {} local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") local BotsInit = require("game/botsinit") local role = require(GetScriptDirectory().."/util/RoleUtility") +local A = require(GetScriptDirectory().."/util/MiraDota") local function IsItemAvailable(item_name) return fun1:GetAvailableItem(GetBot(), item_name) end @@ -228,7 +229,11 @@ local CannotFade = function(t) return false end local DontUseItemIfBreakInvisibility = function(t) +<<<<<<< HEAD return t:IsInvisible() and (not CannotFade(t) or not t:UsingItemBreakInvisibility()) +======= + return t:IsInvisible() and (not CannotFade(t) or not t:UsingItemBreaksInvisibility()) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end local giveTime = -90 function M.ItemUsageThink() @@ -280,7 +285,11 @@ function M.ItemUsageThink() if math.floor(DotaTime()) / 4 ~= 0 then return end +<<<<<<< HEAD if npcBot:IsInvisible() and npcBot:UsingItemBreakInvisibility() then +======= + if npcBot:IsInvisible() and npcBot:UsingItemBreaksInvisibility() then +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a if npcBot:HasModifier("modifier_item_dustofappearance") then M.UseItemNoTarget(npcBot, treads) return true diff --git a/util/ItemUsage-New.mira b/util/ItemUsage-New.mira index 499f1722..0ad40740 100644 --- a/util/ItemUsage-New.mira +++ b/util/ItemUsage-New.mira @@ -3,6 +3,10 @@ local M = {} local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") local BotsInit = require("game/botsinit") local role = require(GetScriptDirectory() .. "/util/RoleUtility") +<<<<<<< HEAD +======= +local A = require(GetScriptDirectory().."/util/MiraDota") +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local function IsItemAvailable(item_name) return fun1:GetAvailableItem(GetBot(), item_name) @@ -222,6 +226,7 @@ local function ShouldTP() end -- old functions end + -- use functions to use items for debugging issues function M.UseItemNoTarget(npc, item) @@ -249,7 +254,11 @@ local CannotFade = function(t) end local DontUseItemIfBreakInvisibility = function(t) +<<<<<<< HEAD return t:IsInvisible() and (not CannotFade(t) or not t:UsingItemBreakInvisibility()) +======= + return t:IsInvisible() and (not CannotFade(t) or not t:UsingItemBreaksInvisibility()) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end local giveTime = -90 @@ -293,6 +302,7 @@ function M.ItemUsageThink() elseif mode == BOT_MODE_LANING then return npcBot:GetPrimaryAttribute() else + -- return npcBot:GetPrimaryAttribute() return npcBot:GetPrimaryAttribute() end end @@ -300,7 +310,11 @@ function M.ItemUsageThink() if math.floor(DotaTime()) / 4 ~= 0 then return end +<<<<<<< HEAD if npcBot:IsInvisible() and npcBot:UsingItemBreakInvisibility() then +======= + if npcBot:IsInvisible() and npcBot:UsingItemBreaksInvisibility() then +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a if npcBot:HasModifier("modifier_item_dustofappearance") then M.UseItemNoTarget(npcBot, treads) return true diff --git a/util/ItemUsageSystem.lua b/util/ItemUsageSystem.lua index 84681989..e8ac46c9 100644 --- a/util/ItemUsageSystem.lua +++ b/util/ItemUsageSystem.lua @@ -319,7 +319,11 @@ function M.UnImplementedItemUsage() if math.floor(DotaTime()) / 4 ~= 0 then return end +<<<<<<< HEAD if npcBot:IsInvisible() and npcBot:UsingItemBreakInvisibility() then +======= + if npcBot:IsInvisible() and npcBot:UsingItemBreaksInvisibility() then +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a if npcBot:HasModifier("modifier_item_dustofappearance") then npcBot:Action_UseAbility(treads) return true diff --git a/util/MiraDota.lua b/util/MiraDota.lua new file mode 100644 index 00000000..07f5ba3e --- /dev/null +++ b/util/MiraDota.lua @@ -0,0 +1,2029 @@ +--------------------------------------------- +-- Generated from Mirana Compiler version 1.6.2 +-- Do not modify +-- https://github.com/AaronSong321/Mirana +--------------------------------------------- +local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local M = {} +local Linq = {} +local Debug = {} +local DotaExt = {} +local AbilInfo = {} +local ItemUseDefaultImpl = {} +local Push = {} +local Abil = {} +local Math = {} +local Hero = {} +local UnitFun = {} +local Building = {} +local magicTable = {} +function Linq.Give(t) + setmetatable(t, magicTable) +end +magicTable.__index = magicTable +function Linq.NewTable(...) + local a = { ... } + Linq.Give(a, magicTable) + return a +end +function Linq.Aggregate(tb, seed, aggregate) + for k, v in ipairs(tb) do + seed = aggregate(seed, v, k) + end + return seed +end +function Linq.All(tb, filter) + for k, v in ipairs(tb) do + if not filter(v, k) then + return false + end + end + return true +end +function Linq.Any(tb, filter) + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + return true + end + end + return false +end +function Linq.Append(tb, item) + local g = Linq.ShallowCopy(tb) + table.insert(g, item) + return g +end +function Linq.Average(tb) + local i = 0 + local sum = 0 + for _, v in ipairs(tb) do + i = i + 1 + sum = sum + v + end + return sum / i +end +function Linq.Concat(a, b) + local g = Linq.NewTable() + for _, v in ipairs(a) do + table.insert(g, v) + end + for _, v in ipairs(b) do + table.insert(g, v) + end + return g +end +function Linq.Contains(tb, value, equals) + equals = equals or function(opv_1, opv_2) return opv_1 == opv_2 end + for _, v in ipairs(tb) do + if equals(v, value) then + return true + end + end + return false +end +function Linq.ContainsKey(tb, key, equals) + equals = equals or function(opv_1, opv_2) return opv_1 == opv_2 end + for k, _ in pairs(tb) do + if equals(key, k) then + return true + end + end + return false +end +function Linq.Count(tb, filter) + local g = 0 + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + g = g + 1 + end + end + return g +end +function Linq.DeepCopy(tb) + local copiedTables = Linq.NewTable() + local g = Linq.NewTable() + table.insert(copiedTables, tb) + for k, v in pairs(tb) do + if type(v) ~= "table" then + g[k] = v + else + if Linq.Contains(copiedTables, v) then + return {} + end + g[k] = Linq.DeepCopy(v) + end + end + return g +end +function Linq.Distinct(tb, equals) + equals = equals or function(opv_1, opv_2) return opv_1 == opv_2 end + local g = Linq.NewTable() + for _, v in pairs(tb) do + if not Linq.Contains(g, v, equals) then + table.insert(g, v) + end + end + return g +end +function Linq.Except(tb, tb2, equals) + local g = Linq.NewTable() + for _, v in ipairs(tb) do + if not Linq.Contains(tb2, v, equals) then + table.insert(g, v) + end + end + return g +end +function Linq.Filter(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if filter(v, k) then + table.insert(g, v) + end + end + return g +end +function Linq.Filter2(tb1, tb2, filter, map) + map = map or function(a, b, c) + return { + a, + b, + } + end + local g = Linq.NewTable() + 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 +function Linq.FilterNot(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if not filter(v, k) then + table.insert(g, v) + end + end + return g +end +function Linq.First(tb, filter) + filter = filter or function() + return true + end + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + return v + end + end +end +function Linq.ForEach2(tb1, tb2, func) + for i = 1, #tb1 do + func(tb1[i], tb2[i]) + end +end +function Linq.ForEach(tb, action) + for k, v in ipairs(tb) do + action(v, k) + end +end +function Linq.ForEachDic(tb, action) + for k, v in pairs(tb) do + action(v, k) + end +end +function Linq.GroupBy(collection, keySelector, elementSelector, resultSelector, comparer) + comparer = comparer or function(opv_1, opv_2) return opv_1 == opv_2 end + resultSelector = resultSelector or function(key, value) + return value + end + elementSelector = elementSelector or Linq.Identity + local keys = Linq.NewTable() + local values = Linq.NewTable() + for _, k in ipairs(collection) do + local keyFound = false + for readKeyIndex, readKey in ipairs(keys) do + if comparer(readKey, keySelector(k)) then + keyFound = true + table.insert(values[readKeyIndex], elementSelector(k)) + break + end + end + if not keyFound then + table.insert(keys, keySelector(k)) + local v = Linq.NewTable() + table.insert(v, elementSelector(k)) + table.insert(values, v) + end + end + return Linq.Map2(keys, values, resultSelector) +end +function Linq.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer) + comparer = comparer or function(opv_1, opv_2) return opv_1 == opv_2 end + resultSelector = resultSelector or function(key, values) + return { + key, + values, + } + end + innerKeySelector = innerKeySelector or Linq.Identity + outerKeySelector = outerKeySelector or Linq.Identity + local t = NewTable() + for k, v in ipairs(outer) do + local key = outerKeySelector(v, k) + local m = Linq.Filter(inner, function(v, k) + return comparer(innerKeySelector(v, k), key) + end) + table.insert(t, resultSelector { + key, + m, + }) + end + return t +end +Linq.Identity = function(t) + return t +end +function Linq.InsertAfter_Modify(tb, item, after) + if after == nil then + table.insert(tb, item) + else + for index, value in ipairs(tb) do + if after == value then + table.insert(tb, index, item) + return + end + end + table.insert(tb, item) + end +end +function Linq.Intersect(tb, tb2, equals) + local g = Linq.NewTable() + for _, v in tb do + if Linq.Contains(tb2, v, equals) then + table.insert(g, v) + end + end + return g +end +function Linq.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer) + comparer = comparer or function(opv_1, opv_2) return opv_1 == opv_2 end + resultSelector = resultSelector or function(o, i) + return { + o, + i, + } + end + innerKeySelector = innerKeySelector or Linq.Identity + outerKeySelector = outerKeySelector or Linq.Identity + local g = NewTable() + for k, v in ipairs(outer) do + local key = outerKeySelector(v, k) + Linq.Filter(inner, function(v, k) + return comparer(innerKeySelector(v, k), key) + end):Map(function(v2) + return resultSelector(v, v2) + end):ForEach(function(t) + return table.insert(g, t) + end) + end + return g +end +function Linq.Keys(tb) + local g = Linq.NewTable() + for k, _ in pairs(tb) do + table.insert(g, k) + end + return g +end +function Linq.Last(tb, filter) + return Linq.First(Linq.Reverse(tb), filter) +end +function Linq.Map(tb, transform) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + g[k] = transform(v) + end + return g +end +function Linq.MapDic(tb, transform) + local g = Linq.NewTable() + for k, v in pairs(tb) do + g[k] = transform(k, v) + end + return g +end +function Linq.Max(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m > maxm then + maxm = m + maxv = tb[i] + end + end + return maxm +end +function Linq.MaxKey(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m > maxm then + maxm = m + maxv = tb[i] + end + end + return maxv +end +function Linq.Min(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m < maxm then + maxm = m + maxv = tb[i] + end + end + return maxm +end +function Linq.MinKey(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m < maxm then + maxm = m + maxv = tb[i] + end + end + return maxv +end +function Linq.NonEmpty(tb) + return Linq.Filter(tb, function(t) + return t ~= nil and #t ~= 0 + end) +end +function Linq.IndexOf(tb, filter) + local g = Linq.NewTable() + 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 +function Linq.Map2(tb1, tb2, map) + local g = Linq.NewTable() + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i], i)) + end + return g +end +function Linq.MergeSort(tb, sort) + sort = sort or function(opv_1, opv_2) return opv_1 - opv_2 end + local function Merge(a, b) + local g = Linq.NewTable() + local aLen = #a + local bLen = #b + local i = 1 + local j = 1 + while i <= aLen and j <= bLen do + if sort(a[i], b[j]) > 0 then + table.insert(g, b[j]) + j = j + 1 + else + table.insert(g, a[i]) + i = i + 1 + end + end + if i <= aLen then + for _ = i, aLen do + table.insert(g, a[i]) + end + end + if j <= bLen then + for _ = j, bLen do + table.insert(g, b[j]) + end + end + return g + end + local function SortRec(tab) + local tableLength = #tab + if tableLength == 1 then + return tab + end + local left = SortRec(Linq.Take(tab, tableLength / 2)) + local right = SortRec(Linq.Skip(tab, tableLength / 2)) + local merge = Merge(left, right) + return merge + end + return SortRec(tb) +end +function Linq.OrderBy(tb, map) + map = map or Linq.Identity + return Linq.Sort(tb, function(a, b) + return map(a) - map(b) + end) +end +function Linq.OrderByDescending(tb, map) + map = map or Linq.Identity + return Linq.Sort(tb, function(a, b) + return map(b) - map(a) + end) +end +function Linq.Partition(tb, filter) + local a = Linq.NewTable() + local b = Linq.NewTable() + for k, v in pairs(tb) do + if filter(v, k) then + table.insert(a, v) + else + table.insert(b, v) + end + end + return a, b +end +function Linq.Prepend(a, b) + return Linq.Concat(b, a) +end +function Linq.Range(min, max, step) + step = step or 1 + local g = Linq.NewTable() + for i = min, max, step do + table.insert(g, i) + end + return g +end +function Linq.Remove(a, b) + local g = Linq.ShallowCopy(a) + for k, v in pairs(a) do + if v == b then + g[k] = nil + end + end + return g +end +function Linq.RemoveAll(a, b) + local g = Linq.NewTable() + for _, v in pairs(a) do + if not Linq.Contains(b, v) then + table.insert(g, v) + end + end + return g +end +function Linq.Remove_Modify(tb, item) + local filter = item + if type(item) ~= "function" then + filter = function(t) + return t == item + end + end + local i = 1 + local d = #tb + while i <= d do + if filter(tb[i]) then + table.remove(tb, i) + d = d - 1 + else + i = i + 1 + end + end +end +function Linq.Repeat(element, count) + local g = Linq.NewTable() + for i = 1, count do + table.insert(g, element) + end + return g +end +function Linq.Replace(tb, filter, map) + local g = Linq.NewTable() + 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 +function Linq.Reverse(tb) + local g = Linq.NewTable() + for i = #tb, 1, -1 do + table.insert(g, tb[i]) + end + return g +end +function Linq.ShallowCopy(tb) + local g = Linq.NewTable() + for k, v in pairs(tb) do + g[k] = v + end + return g +end +function Linq.SlowSort(tb, sort) + local g = Linq.ShallowCopy(tb) + local len = #g + if sort ~= nil then + for i = 1, len - 1 do + for j = i + 1, len do + if sort(g[i], g[j]) > 0 then + g[i], g[j] = g[j], g[i] + end + end + end + else + for i = 1, len - 1 do + for j = i + 1, len do + if g[i] > g[j] then + g[i], g[j] = g[j], g[i] + end + end + end + end + return g +end +Linq.Sort = Linq.SlowSort +function Linq.SelectMany(tb, map, filter) + local g = Linq.NewTable() + 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 +function Linq.Skip(tb, number) + local g = Linq.NewTable() + local i = 0 + for _, v in ipairs(tb) do + i = i + 1 + if i > number then + table.insert(g, v) + end + end + return g +end +function Linq.SkipLast(tb, number) + return Linq.Skip(Linq.Reverse(tb), number) +end +function Linq.SkipWhile(tb, filter) + local g = Linq.NewTable() + local failure + for k, v in ipairs(tb) do + if failure then + table.insert(tb, v) + else + if not filter(v, k) then + table.insert(tb, v) + failure = true + end + end + end + return g +end +function Linq.Take(tb, number) + local g = Linq.NewTable() + local i = 0 + for _, v in ipairs(tb) do + i = i + 1 + if i <= number then + table.insert(g, v) + else + break + end + end + return g +end +function Linq.TakeWhile(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if filter(v, k) then + table.insert(g, v) + else + break + end + end + return g +end +function Linq.Zip2(tb1, tb2, map) + map = map or function(a, b) + return { + a, + b, + } + end + local g = Linq.NewTable() + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i])) + end + return g +end +local function AddLinqfunctionsToMetatable(mt) + for functionName, func in pairs(table) do + mt[functionName] = func + end + for k, v in pairs(Linq) do + mt[k] = v + end +end +AddLinqfunctionsToMetatable(magicTable) +function Debug.DebugTable(tb) + local msg = "{ " + local DebugRec + DebugRec = function(tc) + for k, v in pairs(tc) do + if type(v) == "number" or type(v) == "string" then + msg = msg..k.." = "..v..", " + elseif type(v) == "boolean" then + msg = msg..k.." = "..tostring(v)..", " + elseif type(v) == "table" then + msg = msg..k.." = ".."{ " + DebugRec(v) + msg = msg.."}, " + end + end + end + DebugRec(tb) + msg = msg.." }" + print(msg) +end +function Debug.DebugLongTable(tb) + if type(tb) ~= "table" then + print(tostring(tb)) + return + end + for k, v in pairs(tb) do + if type(v) == "table" then + print(tostring(k).." = ") + Debug.DebugTable(v) + else + print(tostring(k).." = "..tostring(v)) + end + end +end +local AttributeTypeEnum = { + ATTRIBUTE_INVALID = ATTRIBUTE_INVALID, + ATTRIBUTE_STRENGTH = ATTRIBUTE_STRENGTH, + ATTRIBUTE_AGILITY = ATTRIBUTE_AGILITY, + ATTRIBUTE_INTELLECT = ATTRIBUTE_INTELLECT, +} +function DotaExt.AttributeTypeToString(i) + for k, v in pairs(AttributeTypeEnum) do + if v == i then + return k + end + end + return "unknown attribute type" +end +function DotaExt.GetNearbyHeroes(bot, range, getEnemy, botMode) + botMode = botMode or BOT_MODE_NONE + getEnemy = getEnemy or true + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyHeroes(range1, getEnemy, botMode) + Linq.Give(units) + return units +end +function DotaExt.GetNearbyLaneCreeps(bot, range, getEnemy) + getEnemy = getEnemy or true + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyLaneCreeps(range1, getEnemy) + Linq.Give(units) + return units +end +function DotaExt.GetNearbyNeutralCreeps(bot, range) + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyNeutralCreeps(range1) + Linq.Give(units) + return units +end +local botModeEnum = { + BOT_MODE_NONE = BOT_MODE_NONE, + BOT_MODE_LANING = BOT_MODE_LANING, + BOT_MODE_ATTACK = BOT_MODE_ATTACK, + BOT_MODE_ROAM = BOT_MODE_ROAM, + BOT_MODE_RETREAT = BOT_MODE_RETREAT, + BOT_MODE_SECRET_SHOP = BOT_MODE_SECRET_SHOP, + BOT_MODE_SIDE_SHOP = BOT_MODE_SIDE_SHOP, + BOT_MODE_PUSH_TOWER_TOP = BOT_MODE_PUSH_TOWER_TOP, + BOT_MODE_PUSH_TOWER_MID = BOT_MODE_PUSH_TOWER_MID, + BOT_MODE_PUSH_TOWER_BOT = BOT_MODE_PUSH_TOWER_BOT, + BOT_MODE_DEFEND_TOWER_TOP = BOT_MODE_DEFEND_TOWER_TOP, + BOT_MODE_DEFEND_TOWER_MID = BOT_MODE_DEFEND_TOWER_MID, + BOT_MODE_DEFEND_TOWER_BOT = BOT_MODE_DEFEND_TOWER_BOT, + BOT_MODE_ASSEMBLE = BOT_MODE_ASSEMBLE, + BOT_MODE_TEAM_ROAM = BOT_MODE_TEAM_ROAM, + BOT_MODE_FARM = BOT_MODE_FARM, + BOT_MODE_DEFEND_ALLY = BOT_MODE_DEFEND_ALLY, + BOT_MODE_EVASIVE_MANEUVERS = BOT_MODE_EVASIVE_MANEUVERS, + BOT_MODE_ROSHAN = BOT_MODE_ROSHAN, + BOT_MODE_ITEM = BOT_MODE_ITEM, + BOT_MODE_WARD = BOT_MODE_WARD, +} +function DotaExt.BotModeToString(mode) + for k, v in pairs(botModeEnum) do + if mode == v then + return k + end + end + return "unknown bot mode "..mode +end +DotaExt.towerNames = Linq.NewTable(TOWER_TOP_1, TOWER_TOP_2, TOWER_TOP_3, TOWER_MID_1, TOWER_MID_2, TOWER_MID_3, TOWER_BOT_1, TOWER_BOT_2, TOWER_BOT_3, TOWER_BASE_1, TOWER_BASE_2) +DotaExt.barracksNames = Linq.NewTable(BARRACKS_TOP_MELEE, BARRACKS_TOP_RANGED, BARRACKS_MID_MELEE, BARRACKS_MID_RANGED, BARRACKS_BOT_MELEE, BARRACKS_BOT_RANGED) +DotaExt.shrineNames = Linq.NewTable(SHRINE_BASE_1, SHRINE_BASE_2, SHRINE_BASE_3, SHRINE_BASE_4, SHRINE_BASE_5) +function DotaExt.IsValidUnit(v) + return v and not v:IsNull() and v:IsAlive() +end +function DotaExt.GetAllBuildings(team) + return DotaExt.towerNames:Map(function(t) + return GetTower(team, t) + end):Concat(DotaExt.barracksNames:Map(function(t) + return GetBarracks(team, t) + end)):Concat(DotaExt.shrineNames:Map(function(t) + return GetShrine(team, t) + end)):Concat { GetAncient(team) }:Filter(function(t) + return DotaExt.IsValidUnit(t) and not t:IsInvulnerable() + end) +end +function DotaExt.GetPureHeroes(npcBot, range, getEnemy) + range = range or 1600 + if getEnemy == nil then + getEnemy = true + end + return Linq.Filter(DotaExt.GetNearbyHeroes(npcBot, range, getEnemy), function(t) + return Hero.MayNotBeIllusion(npcBot, t) and not UnitFun.IsHeroLevelUnit(t) + end) +end +function DotaExt.EmptyFun() end +function DotaExt.EmptyDesireFun() + return BOT_ACTION_DESIRE_NONE +end +AbilInfo.invisibleModifiers = Linq.NewTable("modifier_bounty_hunter_wind_walk", "modifier_clinkz_wind_walk", "modifier_dark_willow_shadow_realm_buff", "modifier_item_glimmer_cape_glimmer", "modifier_invoker_ghost_walk_self", "modifier_nyx_assassin_vendetta", "modifier_item_phase_boots_active", "modifier_item_shadow_amulet_fade", "modifier_item_invisibility_edge_windwalk", "modifier_shadow_fiend_requiem_thinker", "modifier_item_silver_edge_windwalk", "modifier_windrunner_wind_walk", "modifier_storm_wind_walk", "modifier_templar_assassin_meld", "modifier_visage_silent_as_the_grave", "modifier_weaver_shukuchi", "modified_invisible", "modifier_rune_invis", "modifier_nyx_assassin_burrow", "modifier_oracle_false_promise_invis") +AbilInfo.truesightModifiers = Linq.NewTable("modifier_item_dustofappearance", "modifier_bounty_hunter_track", "modifier_slardar_amplify_damage", "modifier_truesight") +function AbilInfo.HasAnyModifier(bot, modifiers) + return modifiers:Any(function(t) + return bot:HasModifier(t) + end) +end +local frameNumber = 0 +local dotaTimer +local deltaTime = 0 +local function FloatEqual(a, b) + return math.abs(a - b) < 0.000001 +end +local GameLoop = {} +function GameLoop.GetFrameNumber() + return frameNumber +end +function GameLoop.GetDeltaTime() + return deltaTime +end +function GameLoop.EveryManyFrames(count, times) + times = times or 1 + return frameNumber % count < times +end +local defaultReturn = Linq.NewTable() +local everySecondsCallRegistry = Linq.NewTable() +function GameLoop.EveryManySeconds(second, registerName, oldFunction, ...) + if everySecondsCallRegistry[registerName] == nil then + local callTable = {} + callTable.lastCallTime = DotaTime() + RandomFloat(0, second) - second + callTable.interval = second + everySecondsCallRegistry[registerName] = callTable + end + local callTable = everySecondsCallRegistry[registerName] + if callTable.lastCallTime <= DotaTime() - callTable.interval then + callTable.lastCallTime = DotaTime() + return oldFunction(...) + else + return defaultReturn + end +end +local singleForTeamRegistry = Linq.NewTable() +function GameLoop.SingleForTeam(oldFunction) + local functionName = tostring(oldFunction) + return function(...) + if singleForTeamRegistry[functionName] ~= frameNumber then + singleForTeamRegistry[functionName] = frameNumber + return oldFunction(...) + else + return defaultReturn + end + end +end +function GameLoop.CalledOnThisFrame(functionInvocationResult) + return functionInvocationResult ~= defaultReturn +end +function GameLoop.AiTicking() + return DotaTime() >= -75 +end +local coroutineRegistry = Linq.NewTable() +local coroutineExempt = Linq.NewTable() +function GameLoop.TickFromDota() + if not GameLoop.AiTicking() then + return + end + local time = DotaTime() + local function ResumeCoroutine(thread) + local coroutineResult = { coroutine.resume(thread, deltaTime) } + if not coroutineResult[1] then + print("error in coroutine:") + table.remove(coroutineResult, 1) + Debug.DebugLongTable(coroutineResult) + end + end + if dotaTimer == nil then + dotaTimer = time + return + end + deltaTime = time - dotaTimer + if not FloatEqual(time, dotaTimer) then + frameNumber = frameNumber + 1 + local threadIndex = 1 + while threadIndex <= #coroutineRegistry do + local t = coroutineRegistry[threadIndex] + local exemptIndex + local exempt + coroutineExempt:ForEach(function(exemptPair, index) + if exemptPair[1] == t then + if exemptPair[2] == frameNumber then + exempt = true + end + exemptIndex = index + end + end) + if exemptIndex then + table.remove(coroutineExempt, exemptIndex) + end + if not exempt then + if coroutine.status(t) == "suspended" then + ResumeCoroutine(t) + threadIndex = threadIndex + 1 + elseif coroutine.status(t) == "dead" then + table.remove(coroutineRegistry, threadIndex) + else + threadIndex = threadIndex + 1 + end + end + end + dotaTimer = time + end +end +function GameLoop.ResumeUntilReturn(func) + local g = NewTable() + local thread = coroutine.create(func) + while true do + local values = { coroutine.resume(thread) } + if values[1] then + table.remove(values, 1) + table.insert(g, values) + else + print("error in coroutine:") + table.remove(values, 1) + Debug.DebugLongTable(values) + break + end + end + return g +end +function GameLoop.StartCoroutine(func) + local newCoroutine = coroutine.create(func) + table.insert(coroutineRegistry, newCoroutine) + table.insert(coroutineExempt, { + newCoroutine, + frameNumber, + }) + return newCoroutine +end +function GameLoop.WaitForSeconds(seconds) + local t = seconds + while t > 0 do + t = t - coroutine.yield() + end +end +function GameLoop.StopCoroutine(thread) + GameLoop.Remove_Modify(coroutineExempt, function(t) + return t[1] == thread + end) + GameLoop.Remove_Modify(coroutineRegistry, thread) +end +function Abil.UseAbilityOnEntity(bot, abil, entity, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on entity "..entity:GetUnitName() + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnEntity(abil, entity) + elseif queueType == "push" then + bot:ActionPush_UseAbilityOnEntity(abil, entity) + else + bot:Action_UseAbilityOnEntity(abil, entity) + end +end +function Abil.UseAbility(bot, abil, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName() + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbility(abil) + elseif queueType == "push" then + bot:ActionPush_UseAbility(abil) + else + bot:Action_UseAbility(abil) + end +end +function Abil.UseAbilityOnLocation(bot, abil, location, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on location "..fun1:ToStringVector(location) + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnLocation(abil, location) + elseif queueType == "push" then + bot:ActionPush_UseAbilityOnLocation(abil, location) + else + bot:Action_UseAbilityOnLocation(abil, location) + end +end +function Abil.UseAbilityOnTree(bot, abil, tree, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on tree "..tree + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnTree(abil, tree) + elseif queueType == "push" then + bot:ActionPush_UseAbilityOnTree(abil, tree) + else + bot:Action_UseAbilityOnTree(abil, tree) + end +end +function UnitFun.IsFarmingOrPushing(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_FARM or mode == BOT_MODE_PUSH_TOWER_BOT or mode == BOT_MODE_PUSH_TOWER_MID or mode == BOT_MODE_PUSH_TOWER_TOP or mode == BOT_MODE_DEFEND_TOWER_BOT or mode == BOT_MODE_DEFEND_TOWER_MID or mode == BOT_MODE_DEFEND_TOWER_TOP +end +function UnitFun.IsLaning(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_LANING +end +function UnitFun.IsAttackingEnemies(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_ROAM or mode == BOT_MODE_TEAM_ROAM or mode == BOT_MODE_ATTACK or mode == BOT_MODE_DEFEND_ALLY +end +function UnitFun.IsRetreating(npcBot) + return npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_MODERATE +end +function UnitFun.NotRetreating(npcBot) + return not UnitFun.IsRetreating(npcBot) +end +local heroNamePrefixLen = #"npc_dota_hero_" +function UnitFun.GetHeroShortName(name) + return string.sub(name, heroNamePrefixLen + 1) +end +function UnitFun.IsTempestDouble(npc) + return npc:HasModifier "modifier_arc_warden_tempest_double" +end +function UnitFun.IsLoneDruidBear(npc) + return string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") +end +function UnitFun.IsVisageFamiliar(npc) + return string.match(npc:GetUnitName(), "npc_dota_visage_familiar") +end +function UnitFun.IsBrewmasterPrimalSplit(npc) + local unitName = npc:GetUnitName() + return string.match(unitName, "npc_dota_brewmaster_") +end +function UnitFun.IsHeroLevelUnit(npc) + if UnitFun.IsBrewmasterPrimalSplit(npc) then + return true + end + local name = npc:GetUnitName() + if name == "npc_dota_phoenix_sun" then + return true + end + if string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") then + return true + end + return false +end +local canUseItemIllusionModifiers = Linq.NewTable("modifier_arc_warden_tempest_double", "modifier_skeleton_king_reincarnation_active", "modifier_vengefulspirit_hybrid_special") +function UnitFun.CanBuyItem(npc) + if UnitFun.IsHeroLevelUnit(npc) or UnitFun.IsTempestDouble(npc) then + return false + end + if npc:IsIllusion() then + return false + end + return true +end +function UnitFun.CanUseItem(npc) + if UnitFun.IsBrewmasterPrimalSplit(npc) then + return false + end + if string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") then + return true + end + if name == "npc_dota_phoenix_sun" then + return false + end + if npc:IsIllusion() and not AbilInfo.HasAnyModifier(npc, canUseItemIllusionModifiers) then + return false + end + return true +end +function UnitFun.IsGoodTarget(npc, target) + return target:IsHero() and Hero.MayNotBeIllusion(npc, target) and not UnitFun.IsHeroLevelUnit(target) +end +function UnitFun.GetHeroTarget(npc) + do + local t = npc:GetTarget() + if t and UnitFun.IsGoodTarget(npc, t) then + return t + end + end +end +function UnitFun.IsHero(npc) + return npc:IsHero() and not UnitFun.IsCreepHero(npc) +end +function UnitFun.IsCreepHero(npc) + return UnitFun.IsLoneDruidBear(npc) or UnitFun.IsVisageFamiliar(npc) +end +function Building.CanBeAttacked(buillding, npc) + if not building:IsAlive() or building:HasModifier "modifier_foutain_glyph" then + return false + end + npc = npc or GetBot() + if buidling:HasModifier "modifier_backdoor_protection_active" then + do + local target = building:GetAttackTarget() + if target then + if not target:IsHero() or target:IsIllusion() then + return true + end + end + end + return DotaExt.GetNearbyHeroes(npc, 1500, false):Filter(Hero.MayNotBeIllusion):Count(function(it) + return it:GetAttackTarget() == building + end) * 80 >= building:GetHealth() + end + return true +end +local ItemFun = {} +function ItemFun.GetAvailableItem(npc, itemName, isNeutral) + if npc:IsMuted() then + return nil + end + if (itemName) == "item_tpscroll" then + local item = npc:GetItemInSlot(15) + if item and item:IsFullyCastable() then + return item + end + end + if isNeutral then + local item = npc:GetItemInSlot(16) + if item and item:IsFullyCastable() then + return item + end + end + for _, i in ipairs(Linq.Range(0, 5):Concat { 16 }) do + local item = npc:GetItemInSlot(i) + if item and item:GetName() == itemName and item:IsFullyCastable() then + return item + end + end +end +function ItemFun.GetAvailableTp(npc) + do + local teleportation = npc:GetAbilityByName("furion_teleportation") + if teleportation then + if not npc:IsSilenced() and teleportation:IsFullyCastable() and teleportation:GetLevel() >= 2 then + return teleportation + end + end + end + do + local keenConveyance = npc:GetAbilityByName("tinker_keen_conveyance") + if keenConveyance then + if keenConveyance:IsTrained() then + return keenConveyance + end + end + end + return ItemFun.GetAvailableItem(npc, "item_tpscroll") +end +function ItemFun.CanUseAvailableTp(npc, tp) + local rearm = npc:GetAbilityByName "tinker_rearm" + if tp:GetName() == "tinker_keen_conveyance" then + if tp:IsFullyCastable() then + return true + end + if not tp:IsCooldownReady() and not npc:HasModifier "modifier_rejuvenation_aura_buff" and rearm and rearm:IsTrained() then + return true + end + end + if tp:GetName() == "furion_teleportation" then + return not npc:IsSilenced() and tp:IsFullyCastable() + end + return not npc:IsMuted() and tp:IsFullyCastable() +end +function ItemFun.UseAvailableTp(npc, tp, location) + if tp:GetName() == "tinker_keen_conveyance" then + if tp:IsFullyCastable() then + ItemFun.UseAbilityOnLocation(npc, tp, location) + end + local rearm = npc:GetAbilityByName "tinker_rearm" + if not tp:IsCooldownReady() and not npc:HasModifier "modifier_rejuvenation_aura_buff" and rearm and rearm:IsTrained() then + while npc:IsSilenced() or not rearm:IsFullyCastable() do + coroutine.yield() + end + Abil.UseAbility(npc, rearm) + coroutine.yield() + while npc:IsChanneling() do + coroutine.yield() + end + Abil.UseAbilityOnLocation(npc, tp, location) + return true + end + return false + end + if tp:GetName() == "furion_teleportation" then + Abil.UseAbilityOnLocation(npc, tp, location) + return true + end + ItemFun.UseItemOnLocation(npc, tp, location) +end +function ItemFun.GetAvailableBlink(npc) + local blinks = { + "item_blink", + "item_overwhelming_blink", + "item_swift_blink", + "item_arcane_blink", + } + return Linq.Aggregate(blinks, nil, function(a, blinkName) + return a or ItemFun.GetAvailableItem(npc, blinkName) + end) +end +function ItemFun.GetAvailableTravelBoots(npc) + local travelBoots = { + "item_travel_boots", + "item_travel_boots_2", + } + return Linq.Aggregate(travelBoots, nil, function(seed, t) + return seed or ItemFun.GetAvailableItem(npc, t) + end) +end +function ItemFun.GetEmptyInventorySlots(npc) + local g = 0 + for i = 0, 5 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end +function ItemFun.GetEmptyItemSlots(npc) + local g = 0 + for i = 0, 8 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end +function ItemFun.GetEmptyBackpackSlots(npc) + local g = 0 + for i = 6, 8 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end +function ItemFun.SwapItemToBackpack(npc, itemIndex) + for i = 6, 8 do + if npc:GetItemInSlot(i) == nil then + npc:ActionImmediate_SwapItems(itemIndex, i) + return true + end + end + return false +end +function ItemFun.GetCarriedItems(npc) + local g = Linq.NewTable() + for i = 0, 8 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end +function ItemFun.GetCarriedItemsWithIndex(npc) + local g = Linq.NewTable() + for i = 0, 8 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, { + i, + item, + }) + end + end + return g +end +function ItemFun.GetInventoryItems(npc) + local g = Linq.NewTable() + for i = 0, 5 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end +function ItemFun.GetInventoryItemNames(npc) + local g = Linq.NewTable() + for i = 0, 5 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item:GetName()) + end + end + return g +end +function ItemFun.GetStashItems(npc) + local g = Linq.NewTable() + for i = 9, 14 do + local item = npc:GetItemInSlot(i) + if item then + item.slotIndex = i + table.insert(g, item) + end + end + return g +end +function ItemFun.GetAllBoughtItems(npcBot) + local g = Linq.NewTable() + for i = 0, 16 do + local item = npcBot:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end +function ItemFun.IsBoots(item) + if type(item) ~= "string" then + item = item:GetName() + end + return string.match(item, "boots") or item == "item_guardian_greaves" or item == "item_power_treads" +end +ItemFun.InventoryOnlyItems = Linq.NewTable("item_gem", "item_rapier", "item_bloodstone", "item_aegis") +ItemFun.PurchasedConsumables = Linq.NewTable('item_clarity', 'item_tango', 'item_flask', 'item_faerie_fire', 'item_enchanted_mango', 'item_infused_raindrop') +ItemFun.NeutralItems = Linq.NewTable() +ItemFun.NeutralItems.T1 = Linq.NewTable("item_arcane_ring", "item_broom_handle", "item_chipped_vest", "item_fairys_trinket", "item_keen_optic", "item_ocean_heart", "item_pig_hole", "item_possessed_mask", "item_trusty_shovel", "item_tumblers_toy") +ItemFun.NeutralItems.T2 = Linq.NewTable("item_brigands_blade", "item_bullwhip", "item_dragon_scale", "item_essence_ring", "item_fae_grenade", "item_grove_bow", "item_nether_shawl", "item_philosophers_stome", "item_pupils_gift", "item_quicksilver_amulet", "item_ring_of_aquila", "item_vambrace") +ItemFun.NeutralItems.T3 = Linq.NewTable("item_blast_rig", "item_ceremonial_robe", "item_cloak_of_flames", "item_elven_tunic", "item_enchanted_quiver", "item_mind_breaker", "item_paladin_sword", "item_psychic_headband", "item_quickening_charm", "item_spider_legs", "item_titan_silver") +ItemFun.NeutralItems.T4 = Linq.NewTable("item_ascetics_cap", "item_flicker", "item_ninja_gear", "item_penta_edged_sword", "item_spell_prism", "item_stormcrafter", "item_telescope", "item_the_leveller", "item_timeless_relic", "item_trickster_cloak", "item_witchblade") +ItemFun.NeutralItems.T5 = Linq.NewTable("item_apex", "item_arcanists_armor", "item_book_of_shadows", "item_book_of_the_dead", "item_ex_machina", "item_fallen_sky", "item_force_boots", "item_giants_ring", "item_mirror_shield", "item_pirate_hat", "item_seer_stone", "item_stygian_desolator") +function ItemFun.IsNeutralItem(name) + return Linq.Range(1, 5):Map(function(t) + return ItemFun.NeutralItems["T"..t] + end):Any(function(t) + return t:Contains(name) + end) +end +function ItemFun.CannotBePutIntoBackpack(item) + if type(item) ~= "string" then + item = item:GetName() + end + return ItemFun.InventoryOnlyItems:Contains(item) +end +local function RateItem(item) + local name = item:GetName() + local rate = (function() + if name == "item_gem" then + return 4000 + elseif name == "item_dust" then + return 1800 + 200 * item:GetCurrentCharges() + elseif ItemFun.PurchasedConsumables:Contains(name) then + local rate1 = GetItemCost(name) * item:GetCurrentCharges() + if name == "item_tango" then + rate1 = rate1 / 3 + elseif name == "item_infused_raindrop" then + rate1 = rate1 / 6 + end + return rate1 + elseif name == "item_rapier" then + return 14000 + elseif string.match(name, "recipe_") then + return 0 + else + return GetItemCost(name) + end + end)() + return rate +end +function ItemFun.SwapUsefulOnes(bot) + local items = ItemFun.GetCarriedItemsWithIndex(bot):Map(function(t) + return { + inventIndex = t[1], + item = t[2], + rate = RateItem(t[2]), + } + end):OrderByDescending(function(t) + if bot:GetActiveMode() == BOT_MODE_WARD and (t.item:GetName() == "item_ward_observer" or t.item:GetName() == "item_ward_dispenser") then + return 10000 + end + return (function() + if ItemFun.InventoryOnlyItems:Contains(t.item:GetName()) then + return 20000 + elseif ItemFun.IsNeutralItem(t) then + return 0 + else + return t.rate + end + end)() + end) + items:ForEach(function(t, index) + t.correctIndex = index - 1 + end) + local backpackItemsInInventory = items:Filter(function(t) + return bot:GetItemSlotType(t.inventIndex) == ITEM_SLOT_TYPE_MAIN and bot:GetItemSlotType(t.correctIndex) == ITEM_SLOT_TYPE_BACKPACK + end) + local inventoryItemsInBackpack = items:Filter(function(t) + return bot:GetItemSlotType(t.inventIndex) == ITEM_SLOT_TYPE_BACKPACK and bot:GetItemSlotType(t.correctIndex) == ITEM_SLOT_TYPE_MAIN + end) + Linq.ForEach2(backpackItemsInInventory, inventoryItemsInBackpack, function(a, b) + end) +end +ItemFun.defaultAbilityFunctions = Linq.NewTable("CanAbilityBeUpgraded", "GetAbilityDamage", "GetAOERadius", "GetAutoCastState", "GetBehavior", "GetCaster", "GetCastPoint", "GetCastRange", "GetChannelledManaCostPerSecond", "GetChannelTime", "GetDuration", "GetCooldown", "GetCooldownTimeRemaining", "GetCurrentCharges", "GetDamageType", "GetEstimatedDamageToTarget", "GetHeroLevelRequiredToUpgrade", "GetInitialCharges", "GetLevel", "GetManaCost", "GetMaxLevel", "GetName", "GetSecondaryCharges", "GetSpecialValueFloat", "GetSpecialValueInt", "GetTargetFlags", "GetTargetTeam", "GetTargetType", "GetToggleState", "IsActivated", "IsAttributeBonus", "IsChanneling", "IsCooldownReady", "IsFullyCastable", "IsHidden", "IsInAbilityPhase", "IsItem", "IsNull", "IsOwnersManaEnough", "IsPassive", "IsStealable", "IsStolen", "IsTalent", "IsToggle", "IsTrained", "IsUltimate", "ProcsMagicStick", "ToggleAutoCast") +ItemFun.defaultItemExtraFunctions = Linq.NewTable("CanBeDisassembled", "IsCombineLocked", "GetPowerTreadsStat") +ItemFun.defaultItemFunctions = ItemFun.defaultAbilityFunctions:Concat(ItemFun.defaultItemExtraFunctions) +function ItemFun.UseItemNoTarget(npc, item, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName() + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbility(item) +end +function ItemFun.UseItemOnEntity(npc, item, entity, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on entity "..entity:GetUnitName() + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnEntity(item, entity) +end +function ItemFun.UseItemOnLocation(npc, item, loc, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on location "..fun1:ToStringVector(loc) + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnLocation(item, loc) +end +function ItemFun.UseItemOnTree(npc, item, tree, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on tree "..tostring(tree) + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnTree(item, tree) +end +function ItemFun.FadeWouldMakeNoSense(t) + if t:HasModifier "modifier_item_dustofappearance" or t:HasModifier "modifier_truesight" or t:HasModifier "modifier_bounty_hunter_track" or t:HasModifier "modifier_slardar_amplify_damage" then + return true + end + return false +end +local itemNamePrefix = "item_" +function ItemFun.GetItemShortName(t) + return string.sub(t, #itemNamePrefix + 1) +end +function Hero.MustBeIllusion(target) + if target:IsIllusion() then + return true + end + if GetTeam() == target:GetTeam() then + return target:IsIllusion() + end + if target.markedAsIllusion then + return true + end + if target.markedAsRealHero then + return false + end + if not IsHeroAlive(target:GetPlayerID()) then + return true + end + return false +end +function Hero.MayNotBeIllusion(t) + return not Hero.MustBeIllusion(t) +end +function Hero.GetUniqueHeroNumber(heroes) + if #heroes == 0 then + return 0 + end + return Linq.Filter(heroes, Hero.MayNotBeIllusion):GroupBy(function(t) + return t:GetPlayerID() + end):Count() +end +function Hero.HasScepter(npc) + return npc:HasScepter() or npc:HasModifier "modifier_wisp_tether_scepter" or npc:HasModifier "modifier_item_ultimate_scepter" or npc:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist" +end +function Hero.HasBoughtScepter(npc) + return npc:HasScepter() or npc:HasModifier "modifier_item_ultimate_scepter" or npc:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist" +end +function Hero.PrintMode(npc) + print("bot "..npc:GetUnitName().." in mode "..DotaExt.BotModeToString(npc:GetActiveMode())..", desire = "..npc:GetActiveModeDesire()) +end +local oldRoleUtils = require(GetScriptDirectory().."/util/RoleUtility") +local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local ItemUse = {} +function ItemUse.GetItemInfo(bot, item) + local itemAuxTable + if bot.itemAuxTable then + itemAuxTable = bot.itemAuxTable + else + itemAuxTable = {} + bot.itemAuxTable = itemAuxTable + end + local thisItemTable + local itemKey = tostring(item) + if itemAuxTable[itemKey] then + thisItemTable = itemAuxTable[itemKey] + else + itemAuxTable[itemKey] = {} + thisItemTable = itemAuxTable[itemKey] + end + return thisItemTable +end +local primaryAbilityHasBonus = Linq.NewTable("obsidian_destroyer", "enchantress", "silencer", "drow_ranger") +local function GetWantedPowerTreadsAttribute(npcBot, info) + local mode = npcBot:GetActiveMode() + if mode == BOT_MODE_RETREAT and npcBot:WasRecentlyDamagedByAnyHero(3) then + return ATTRIBUTE_STRENGTH, "MoreHealthWhenRetreat" + elseif UnitFun.IsAttackingEnemies(npcBot) then + local name = UnitFun.GetHeroShortName(npcBot:GetUnitName()) + if primaryAbilityHasBonus:Contains(name) then + return npcBot:GetPrimaryAttribute(), "PrimaryWithAbilityBonus" + else + return ATTRIBUTE_AGILITY, "AgilityWhenAttacking" + end + elseif mode == BOT_MODE_LANING then + return info.primAttr, "PrimaryForLH" + elseif npcBot:WasRecentlyDamagedByAnyHero(2) then + return ATTRIBUTE_STRENGTH, "StrengthWhenAttacked" + else + return info.primAttr, "PrimaryWhenIdle" + end +end +local function UsePowerTreads(pt, bot, info) + if bot:HasModifier "modifier_ice_blast" then + return + end + if AbilInfo.HasAnyModifier(bot, AbilInfo.invisibleModifiers) and bot:UsingItemBreaksInvisibility() then + if bot:HasModifier("modifier_item_dustofappearance") then + bot:Action_UseAbility(pt) + return "BreakInvisibility" + end + if not AbilInfo.HasAnyModifier(bot, AbilInfo.truesightModifiers) then + return + end + end + local wantedAttribute, reason = GetWantedPowerTreadsAttribute(bot, info) + print(bot:GetUnitName().." want "..DotaExt.AttributeTypeToString(wantedAttribute)..", currently "..DotaExt.AttributeTypeToString(pt:GetPowerTreadsStat())..", reason = "..reason..", mode = "..DotaExt.BotModeToString(bot:GetActiveMode())) + if wantedAttribute ~= pt:GetPowerTreadsStat() then + return reason + end +end +function ItemUseDefaultImpl.branch(item, bot, info) +end +local function CountInventoryItemCooldown(bot, inventoryItems) + inventoryItems:ForEach(function(t) + local r = ItemUse.GetItemInfo(bot, t) + if r.cooldownFromBackpack then + local __mira_locvar_1 = r + __mira_locvar_1.cooldownFromBackpack = __mira_locvar_1.cooldownFromBackpack - deltaTime + if r.cooldownFromBackpack <= 0 then + r.cooldownFromBackpack = 0 + end + end + end) +end +local entityOnlyItems = Linq.NewTable() +local noTargetOnlyItems = Linq.NewTable("arcane_boots", "phase_boots", "power_treads") +local treeOnlyItems = Linq.NewTable() +local locationOnlyItems = Linq.NewTable("travel_boots", "travel_boots_2") +local function ConsiderAvailableItem(item, bot, itemUsageAuxiliaryInfo) + local name = ItemFun.GetItemShortName(item:GetName()) + local itemFunc = bot.ItemUsage and bot.ItemUsage[name] or ItemUseDefaultImpl[name] + if itemFunc == nil then + GameLoop.EveryManySeconds(5, "NotifyUnimplementedItem "..name, function() + end) + return 0 + else + local castTarget, targetType, cause + local desire, b, c, d = itemFunc(item, bot, itemUsageAuxiliaryInfo) + if noTargetOnlyItems:Contains(name) then + castTarget, targetType, cause = nil, "none", b + elseif treeOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "tree", c + elseif locationOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "location", c + elseif entityOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "entity", c + else + castTarget, targetType, cause = b, c, d + end + return desire, castTarget, targetType, cause + end +end +local function UseAvailableItems(bot, inventoryItems) + local itemUsageAuxiliaryInfo = Linq.NewTable() + local info = itemUsageAuxiliaryInfo + info.hp = bot:GetHealth() + info.hpm = bot:GetMaxHealth() + info.hpp = bot:GetHealth() / bot:GetMaxHealth() + info.mn = bot:GetMana() + info.mnm = bot:GetMaxMana() + info.mnp = info.mn / info.mnm + info.lev = bot:GetLevel() + info.allEnemies1400 = DotaExt.GetNearbyHeroes(bot, 1400) + info.e1400 = info.allEnemies1400:Filter(Hero.MayNotBeIllusion) + info.ec1400 = Hero.GetUniqueHeroNumber(info.e1400) + info.allEnemies1600 = DotaExt.GetNearbyHeroes(bot, 1600) + info.e1600 = info.allEnemies1600:Filter(Hero.MayNotBeIllusion) + info.ec1600 = Hero.GetUniqueHeroNumber(info.e1600) + info.allEnemies1200 = DotaExt.GetNearbyHeroes(bot, 1200) + info.e1200 = info.allEnemies1200:Filter(Hero.MayNotBeIllusion) + info.ec1200 = Hero.GetUniqueHeroNumber(info.e1200) + info.allEnemies900 = DotaExt.GetNearbyHeroes(bot, 900) + info.e900 = info.allEnemies900:Filter(Hero.MayNotBeIllusion) + info.ec900 = Hero.GetUniqueHeroNumber(info.e900) + info.allEnemies650 = DotaExt.GetNearbyHeroes(bot, 650) + info.e650 = info.allEnemies650:Filter(Hero.MayNotBeIllusion) + info.ec650 = Hero.GetUniqueHeroNumber(info.e650) + info.allAllies = DotaExt.GetNearbyHeroes(bot, 1500) + info.allies = info.allAllies:Filter(Hero.MayNotBeIllusion) + info.allyCount = Hero.GetUniqueHeroNumber(info.allies) + info.nw = bot:GetNetWorth() + info.bp = fun1:GetBattlePower(bot) + info.primAttr = bot:GetPrimaryAttribute() + info.blasted = bot:HasModifier "modifier_ice_blast" + info.target = bot:GetTarget() + local highDesireItem = inventoryItems:Map(function(t) + local pack = { ConsiderAvailableItem(t, bot, itemUsageAuxiliaryInfo) } + pack[5] = t + return pack + end):Filter(function(t) + return t[1] > 0 + end):MaxKey(function(t) + return t[1] + end) + do + local t = highDesireItem + if t then + if t[3] == "none" then + if t[5]:GetName() == "item_power_treads" then + print(bot:GetUnitName().." use power treads") + end + ItemFun.UseItemNoTarget(bot, t[5], t[4]) + elseif t[3] == "location" then + ItemFun.UseItemOnLocation(bot, t[5], t[2], t[4]) + elseif t[3] == "tree" then + ItemFun.UseItemOnTree(bot, t[5], t[2], t[4]) + else + ItemFun.UseItemOnEntity(bot, t[5], t[2], t[4]) + end + end + end +end +function ItemUse.CanUseAnyItem(t) + return not (fun1:IsMuted(t) or fun1:IsHypnosed(t) or fun1:IsFeared(t) or t:IsHexed() or t:IsChanneling()) +end +function ItemUse.ItemUsageThink() + local bot = GetBot() + if not UnitFun.CanUseItem(bot) then + return + end + GameLoop.EveryManySeconds(3, "SwapUsefulItems "..bot:GetUnitName(), function() + return ItemFun.SwapUsefulOnes(bot) + end) + local inventoryItems = ItemFun.GetInventoryItems(bot) + CountInventoryItemCooldown(bot, inventoryItems) + if ItemUse.CanUseAnyItem(bot) then + UseAvailableItems(bot, inventoryItems:Filter(function(t) + return t:IsFullyCastable() and (not bot:IsIllusion() or bot:HasModifier "modifier_skeleton_king_reincarnation_active" or bot:HasModifier "modifier_vengefulspirit_hybrid_special" or bot:HasModifier "modifier_arc_warden_tempest_double") and ItemUse.GetItemInfo(bot, t).cooldownFromBackpack == nil + end)) + end +end +local Role = {} +function Role.GetRoleValue(npc, role) + return oldRoleUtils.hero_roles[npc:GetUnitName()][role] +end +function Role.Push(npc) + return Role.GetRoleValue(npc, "pusher") +end +function Math.PointToPointDistance(a, b) + local x = a.x - b.x + local y = a.y - b.y + return (x * x + y * y) ^ 0.5 +end +local Push_impl = {} +function Push_impl.GetCarryRate(hero) + return oldRoleUtils.hero_roles[hero:GetUnitName()].carry +end +function Push_impl.GetLane(nTeam, hHero) + local vBot = GetLaneFrontLocation(nTeam, LANE_BOT, 0) + local vTop = GetLaneFrontLocation(nTeam, LANE_TOP, 0) + local vMid = GetLaneFrontLocation(nTeam, LANE_MID, 0) + return (function() + if GetUnitToLocationDistance(hHero, vBot) < 2500 then + return LANE_BOT + elseif GetUnitToLocationDistance(hHero, vTop) < 2500 then + return LANE_TOP + elseif GetUnitToLocationDistance(hHero, vMid) < 2500 then + return LANE_MID + else + return LANE_NONE + end + end)() +end +function Push_impl.CreepRate(creep) + local rate = 1 + rate = rate * (function() + if string.match(t, "upgraded_mega") then + return 3.5 + elseif string.match(t, "upgraded") then + return 2 + else + return 1 + end + end)() + rate = rate * (function() + if string.match(t, "melee") then + return 1 + elseif string.match(t, "ranged") then + return 1.2 + else + return 1.8 + end + end)() + return rate +end +function Push_impl.CreepReward(creep) + local rate = 1 + rate = rate * (function() + if string.match(t, "upgraded_mega") then + return 0.25 + elseif string.match(t, "upgraded") then + return 0.5 + else + return 1 + end + end)() + rate = rate * (function() + if string.match(t, "melee") then + return 1 + elseif string.match(t, "ranged") then + return 1.7 + else + return 2 + end + end)() + return rate +end +function Push_impl.GetAllyTower(towerIndex) + return GetTower(GetTeam(), towerIndex) +end +local allyTower1 = fun1:Map({ + TOWER_TOP_1, + TOWER_MID_1, + TOWER_BOT_1, +}, Push_impl.GetAllyTower) +local allyTower2 = fun1:Map({ + TOWER_TOP_2, + TOWER_MID_2, + TOWER_BOT_2, +}, Push_impl.GetAllyTower) +local allyTower3 = fun1:Map({ + TOWER_TOP_3, + TOWER_MID_3, + TOWER_BOT_3, +}, Push_impl.GetAllyTower) +local allyTower4 = fun1:Map({ + TOWER_BASE_1, + TOWER_BASE_2, +}, Push_impl.GetAllyTower) +function Push_impl.TowerRate(tower) + return (function() + if allyTower1:Contains(tower) then + return 1 + elseif allyTower2:Contains(tower) then + return 1.5 + elseif allyTower3:Contains(tower) then + return (function() + if allyTower3:All(function(t) + return t:IsAlive() + end) then + return 2 + else + return 1.5 + end + end)() + else + return 1.7 + end + end)() +end +function Push_impl.CleanLaneDesire(npc, lane) + local front = GetLaneFrontLocation(GetTeam(), lane, 0) + local allyTower = GetNearestBuilding(GetTeam(), front) + local distanceToFront = GetUnitToUnitDistance(npc, allyTower:GetLocation()) + local creeps = fun1:Filter(GetUnitList(UNIT_LIST_ENEMY_CREEPS), function(t) + return GetUnitToLocationDistance(t, front) <= 1500 + end) + local allyCreeps = fun1:Filter(GetUnitList(UNIT_LIST_FRIEND_CREEPS), function(t) + return GetUnitToLocationDistance(t, front) <= 1500 + end) + local creepRateDiff = fun1:Aggregate(0, creeps:Map(Push_impl.CreepRate), function(opv_1, opv_2) return opv_1 + opv_2 end) - fun1:Aggregate(0, allyCreeps:Map(Push_impl.CreepRate), function(opv_1, opv_2) return opv_1 + opv_2 end) + local desire = 0 + local necessity = 0 + if distanceToFront <= 3000 then + if creepRateDiff >= DotaTime() / 300 and creepRateDiff >= 3 then + necessity = necessity + creepRateDiff + end + if creepRateDiff >= 2 and creepRateDiff then + desire = desire + fun1:Aggregate(0, creeps:Map(Push_impl.CreepReward), function(opv_1, opv_2) return opv_1 + opv_2 end) + end + end + necessity = necessity * TowerRate(allyTower) + desire = desire * TowerRate(allyTower) + return desire, necessity +end +function Push_impl.DefendLaneDesire() + return 0 +end +function Push_impl.PushLaneDesire(npc, lane) + local team = GetTeam() + local teamPush = TeamPushLaneDesire(lane) + local levelFactor = (function() + if npc:GetLevel() < 6 then + return 0 + else + return 0.2 + end + end)() + local myLane = GetLane(team, npc) + if myLane ~= LANE_NONE then + if Push_impl.CleanLaneDesire(myLane) > Push_impl.CleanLaneDesire(lane) then + return 0 + end + end + local healthRate = npcBot:GetHealth() / npcBot:GetMaxHealth() + fun1:GetLifeSteal(npc) * 2 + if healthRate > 1 then + healthRate = 0 + end + local manaRate = npcBot:GetMana() / npcBot:GetMaxMana() + local stateFactor = healthRate * 0.7 + manaRate * 0.3 + if stateFactor < 0.6 then + return 0 + end + local roleFactor = (function() + if Role.Push(npc) then + return Role.Push(npc) * 0.2 + elseif Role.Support(npc) then + return Role.Support(npc) * 0.1 + else + return 0 + end + end)() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local distanceToFront = GetUnitToUnitDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local ddis = GetUnitToUnitDistance(nearestBuilding, laneFront) + local tp = ItemFun.GetAvailableTp(npc) + local canCastTp = ItemFun.CanUseAvailableTp(npc, tp) + local distanceFactor = (function() + if distanceToFront <= 1000 or canCastTp then + return 1 + elseif distanceToFront - ddis >= 3000 and canCastTp then + return (function() + if ddis <= 1000 then + return 0.7 + elseif ddis >= 6000 then + return 0 + else + return -(ddis - 6000) * 0.7 / 5000 + end + end)() + elseif distanceToFront >= 10000 then + return 0 + else + return -(distanceToFront - 10000) / 9000 + end + end)() + local factor = 0.2 + levelFactor + roleFactor + 0.4 * distanceFactor + 0.2 * stateFactor + if stateFactor < 1.2 then + factor = factor * RemapVal(stateFactor, 0.6, 1.2, 0, 0.7) + end + return Clamp(factor, 0, 0.8) +end +function Push_impl.NoCreepsOnLane(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + return towerToEnemyHomeDistance < GetUnitToUnitDistance(enemyTower, allyTower) and Math.PointToPointDistance(laneFront, enemySpawnLocation) < towerToEnemyHomeDistance - maxDiveDistance +end +function Push_impl.GetAttackBuildingLocation(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + local distanceToTower = GetUnitToUnitDistance(npc, enemyTower) + if distanceToTower < 1000 then + return Push_impl.GetSafeLocation(npc, enemyTower) + else + if Math.PointToPointDistance(laneFront, enemySpawnLocation) < towerToEnemyHomeDistance - maxDiveDistance and npc:GetLevel() <= 11 then + return Push_impl.GetSafeLocation(npc, allyTower) + else + return Push_impl.GetSafeLocation(npc, enemyTower) + end + end +end +function Push_impl.CreepAttackingTower(creeps, tower) + return Linq.Any(creeps, function(t) + return t:GetAttackTarget() == tower + end) +end +function Push_impl.IsSafeToAttack(npc, lane, creeps) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local distanceToEnemyHome = GetUnitToLocationDistance(npc, enemySpawnLocation) + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + local distanceToTower = GetUnitToUnitDistance(npc, enemyTower) + local safe = distanceToTower > 1500 or GetUnitToUnitDistanceSqr(npc, allyTower) <= 490000 + local creepMinDistance = creeps:Min(function(t) + return GetUnitToUnitDistanceSqr(t, enemyTower) + end) + if creepMinDistance and (distanceToTower < creepMinDistance or distanceToEnemyHome < towerToEnemyHomeDistance - maxDiveDistance) then + safe = true + end + if enemyTower:GetAttackDamage() < 20 then + safe = true + end + return safe +end +function Push_impl.TryTp(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local distanceToFront = GetUnitToLocationDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local distanceToNearestBuilding = GetUnitToLocationDistance(nearestBuilding, laneFront) + local amount = Push_impl.GetAmountAlongLane(lane, npc:GetLocation()) + local tp = Push_impl.GetAvailableTp(npc) + if distanceToFront > 3000 and distanceToFront - distanceToNearestBuilding > 3000 then + npc.Push_impl_TryTp = GameLoop.StartCoroutine(function() + return Push_impl.UseAvailableTp(npc, tp) + end) + end +end +function Push_impl.GetCreepsNearTower(npc, tower) + return DotaExt.GetNearbyCreeps(npc, 1400, false):Filter(function(t) + return GetUnitToLocationDistanceSqr(t, tower) < 640000 + end) +end +function Push.UnitPushLaneThink(npc, lane) + if npc:IsChanneling() or npc:IsUsingAbility() or npc:GetQueuedActionType(0) == BOT_ACTION_TYPE_USE_ABILITY then + return + end + if npc.Push_impl_TryTp then + if coroutine.status(npc.Push_impl_TryTp) == "dead" then + npc.Push_impl_TryTp = nil + else + return + end + else + Push_impl.TryTp(npc, lane) + end + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local distanceToFront = GetUnitToLocationDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local distanceToNearestBuilding = GetUnitToLocationDistance(nearestBuilding, laneFront) + local creeps = Push_impl.GetCreepsNearTower(npc, enemyTower) + local targetLocation = Push_impl.GetTargetLocation(npc, lane) + local buildingAttackedByTower = Push_impl.CreepAttackingTower(creeps, enemyTower) + local isSafeToAttack = Push_impl.IsSafeToAttack(npc, lane, creeps) + local noCreeps = Push_impl.NoCreepsOnLane(npc, lane) + local enemies = DotaExt.GetNearbyHeroes(npc, 1200) + local target = Push_impl.GetMyTarget(npc, lane, targetLocation) + if target then + targetLocation = Push_impl.GetSafeLocation(npc, target) + end + local goodSituation = true + if (npc:GetLevel() >= 12 or npc:GetLevel() >= DotaTime() / 120) and npc:GetHealth() >= 700 and #enemeis == 0 then + goodSituation = true + end + if (not isSafeToAttack or noCreeps) and (fun1:GetHealthPercent(enemyTower) >= 0.2 and enemyTower:GetAttackDamage() > 20) then + goodSituation = false + end + if Push_impl.TooManyEnemies() then + Push_impl.AssembleWithAlly(npc) + elseif not goodSituation then + Push_impl.StepBack(npc) + end +end +M.Linq = Linq +M.Debug = Debug +M.Dota = DotaExt +M.Unit = UnitFun +M.Game = GameLoop +M.Item = ItemFun +M.ItemUse = ItemUse +M.Hero = Hero +M.Building = Building +return M diff --git a/util/MiraDota.mira b/util/MiraDota.mira new file mode 100644 index 00000000..ece7f346 --- /dev/null +++ b/util/MiraDota.mira @@ -0,0 +1,2176 @@ +local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") + +local M = {} + +local Linq = {} +local Debug = {} +local DotaExt = {} +local AbilInfo = {} +local ItemUseDefaultImpl = {} +local Push = {} +local Abil = {} +local Math = {} +local Hero = {} +local UnitFun = {} +local Building = {} + + + + +local magicTable = {} + +function Linq.Give(t) + setmetatable(t, magicTable) +end +magicTable.__index = magicTable + +function Linq.NewTable(...) + local a = { ... } + Linq.Give(a, magicTable) + return a +end + +function Linq.Aggregate(tb, seed, aggregate) + for k, v in ipairs(tb) do + seed = aggregate(seed, v, k) + end + return seed +end + +function Linq.All(tb, filter) + for k, v in ipairs(tb) do + if not filter(v, k) then + return false + end + end + return true +end + +function Linq.Any(tb, filter) + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + return true + end + end + return false +end + +function Linq.Append(tb, item) + local g = Linq.ShallowCopy(tb) + table.insert(g, item) + return g +end + +function Linq.Average(tb) + local i = 0 + local sum = 0 + for _, v in ipairs(tb) do + i = i + 1 + sum = sum + v + end + return sum / i +end + +function Linq.Concat(a, b) + local g = Linq.NewTable() + for _, v in ipairs(a) do + table.insert(g, v) + end + for _, v in ipairs(b) do + table.insert(g, v) + end + return g +end + +function Linq.Contains(tb, value, equals) + equals = equals or { == } + for _, v in ipairs(tb) do + if equals(v, value) then + return true + end + end + return false +end + +function Linq.ContainsKey(tb, key, equals) + equals = equals or { == } + for k, _ in pairs(tb) do + if equals(key, k) then + return true + end + end + return false +end + +function Linq.Count(tb, filter) + local g = 0 + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + g = g + 1 + end + end + return g +end + +function Linq.DeepCopy(tb) + local copiedTables = Linq.NewTable() + local g = Linq.NewTable() + table.insert(copiedTables, tb) + for k, v in pairs(tb) do + if type(v) ~= "table" then + g[k] = v + else + if Linq.Contains(copiedTables, v) then + return {} + end + g[k] = Linq.DeepCopy(v) + end + end + return g +end + +function Linq.Distinct(tb, equals) + equals = equals or { == } + local g = Linq.NewTable() + for _, v in pairs(tb) do + if not Linq.Contains(g, v, equals) then + table.insert(g, v) + end + end + return g +end + +function Linq.Except(tb, tb2, equals) + local g = Linq.NewTable() + for _, v in ipairs(tb) do + if not Linq.Contains(tb2, v, equals) then + table.insert(g, v) + end + end + return g +end + +function Linq.Filter(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if filter(v, k) then + table.insert(g, v) + end + end + return g +end + +function Linq.Filter2(tb1, tb2, filter, map) + map = map or { a, b, c -> { a, b } } + local g = Linq.NewTable() + 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 + +function Linq.FilterNot(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if not filter(v, k) then + table.insert(g, v) + end + end + return g +end + +function Linq.First(tb, filter) + filter = filter or { -> true } + for k, v in ipairs(tb) do + if filter == nil or filter(v, k) then + return v + end + end +end + +function Linq.ForEach2(tb1, tb2, func) + for i = 1, #tb1 do + func(tb1[i], tb2[i]) + end +end + +function Linq.ForEach(tb, action) + for k, v in ipairs(tb) do + action(v, k) + end +end + +function Linq.ForEachDic(tb, action) + for k, v in pairs(tb) do + action(v, k) + end +end + +function Linq.GroupBy(collection, keySelector, elementSelector, resultSelector, comparer) + comparer = comparer or { == } + resultSelector = resultSelector or { key, value -> value } + elementSelector = elementSelector or Linq.Identity + local keys = Linq.NewTable() + local values = Linq.NewTable() + for _, k in ipairs(collection) do + local keyFound = false + for readKeyIndex, readKey in ipairs(keys) do + if comparer(readKey, keySelector(k)) then + keyFound = true + table.insert(values[readKeyIndex], elementSelector(k)) + break + + end + end + if not keyFound then + table.insert(keys, keySelector(k)) + local v = Linq.NewTable() + table.insert(v, elementSelector(k)) + table.insert(values, v) + end + end + return Linq.Map2(keys, values, resultSelector) +end + +function Linq.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer) + comparer = comparer or { == } + resultSelector = resultSelector or { key, values -> { key, values } } + innerKeySelector = innerKeySelector or Linq.Identity + outerKeySelector = outerKeySelector or Linq.Identity + local t = NewTable() + for k, v in ipairs(outer) do + local key = outerKeySelector(v, k) + local m = Linq.Filter(inner, function(v, k) + return comparer(innerKeySelector(v, k), key) + end) + table.insert(t, resultSelector { key, m }) + end + return t +end + +Linq.Identity = { t -> t } + +function Linq.InsertAfter_Modify(tb, item, after) + if after == nil then + table.insert(tb, item) + else + for index, value in ipairs(tb) do + if after == value then + table.insert(tb, index, item) + return + end + end + table.insert(tb, item) + end +end + +function Linq.Intersect(tb, tb2, equals) + local g = Linq.NewTable() + for _, v in tb do + if Linq.Contains(tb2, v, equals) then + table.insert(g, v) + end + end + return g +end + +function Linq.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer) + comparer = comparer or { == } + resultSelector = resultSelector or { o, i -> { o, i } } + innerKeySelector = innerKeySelector or Linq.Identity + outerKeySelector = outerKeySelector or Linq.Identity + local g = NewTable() + for k, v in ipairs(outer) do + local key = outerKeySelector(v, k) + Linq.Filter(inner, function(v, k) + return comparer(innerKeySelector(v, k), key) + end):Map(function(v2) + return resultSelector(v, v2) + end):ForEach(function(t) + return table.insert(g, t) + end) + end + return g +end + +function Linq.Keys(tb) + local g = Linq.NewTable() + for k, _ in pairs(tb) do + table.insert(g, k) + end + return g +end + +function Linq.Last(tb, filter) + return Linq.First(Linq.Reverse(tb), filter) +end + +function Linq.Map(tb, transform) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + g[k] = transform(v) + end + return g +end + +function Linq.MapDic(tb, transform) + local g = Linq.NewTable() + for k, v in pairs(tb) do + g[k] = transform(k, v) + end + return g +end + +function Linq.Max(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m > maxm then + maxm = m + maxv = tb[i] + end + end + return maxm +end + +function Linq.MaxKey(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m > maxm then + maxm = m + maxv = tb[i] + end + end + return maxv +end + +function Linq.Min(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m < maxm then + maxm = m + maxv = tb[i] + end + end + return maxm +end + +function Linq.MinKey(tb, map) + if #tb == 0 then + return nil + end + map = map or Linq.Identity + local maxv, maxm = tb[1], map(tb[1]) + for i = 2, #tb do + local m = map(tb[i]) + if m < maxm then + maxm = m + maxv = tb[i] + end + end + return maxv +end + +function Linq.NonEmpty(tb) + return Linq.Filter(tb, function(t) + return t ~= nil and #t ~= 0 + end) +end + +function Linq.IndexOf(tb, filter) + local g = Linq.NewTable() + 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 + +function Linq.Map2(tb1, tb2, map) + local g = Linq.NewTable() + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i], i)) + end + return g +end + +function Linq.MergeSort(tb, sort) + sort = sort or { - } + local function Merge(a, b) + local g = Linq.NewTable() + local aLen = #a + local bLen = #b + local i = 1 + local j = 1 + while i <= aLen and j <= bLen do + if sort(a[i], b[j]) > 0 then + table.insert(g, b[j]) + j = j + 1 + else + table.insert(g, a[i]) + i = i + 1 + end + end + if i <= aLen then + for _ = i, aLen do + table.insert(g, a[i]) + end + end + if j <= bLen then + for _ = j, bLen do + table.insert(g, b[j]) + end + end + return g + end + local function SortRec(tab) + local tableLength = #tab + if tableLength == 1 then + return tab + end + local left = SortRec(Linq.Take(tab, tableLength / 2)) + local right = SortRec(Linq.Skip(tab, tableLength / 2)) + local merge = Merge(left, right) + return merge + end + return SortRec(tb) +end + +function Linq.OrderBy(tb, map) + map = map or Linq.Identity + return Linq.Sort(tb) { a, b -> return map(a) - map(b) } +end + +function Linq.OrderByDescending(tb, map) + map = map or Linq.Identity + return Linq.Sort(tb) { a, b -> return map(b) - map(a) } +end + +function Linq.Partition(tb, filter) + local a = Linq.NewTable() + local b = Linq.NewTable() + for k, v in pairs(tb) do + if filter(v, k) then + table.insert(a, v) + else + table.insert(b, v) + end + end + return a, b +end + +function Linq.Prepend(a, b) + return Linq.Concat(b, a) +end + +function Linq.Range(min, max, step) + step = step or 1 + local g = Linq.NewTable() + for i = min, max, step do + table.insert(g, i) + end + return g +end + +function Linq.Remove(a, b) + local g = Linq.ShallowCopy(a) + for k, v in pairs(a) do + if v == b then + g[k] = nil + end + end + return g +end + +function Linq.RemoveAll(a, b) + local g = Linq.NewTable() + for _, v in pairs(a) do + if not Linq.Contains(b, v) then + table.insert(g, v) + end + end + return g +end + +function Linq.Remove_Modify(tb, item) + local filter = item + if type(item) ~= "function" then + filter = { t -> t == item } + end + local i = 1 + local d = #tb + while i <= d do + if filter(tb[i]) then + table.remove(tb, i) + d = d - 1 + else + i = i + 1 + end + end +end + +function Linq.Repeat(element, count) + local g = Linq.NewTable() + for i = 1, count do + table.insert(g, element) + end + return g +end + +function Linq.Replace(tb, filter, map) + local g = Linq.NewTable() + 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 + +function Linq.Reverse(tb) + local g = Linq.NewTable() + for i = #tb, 1, -1 do + table.insert(g, tb[i]) + end + return g +end + +function Linq.ShallowCopy(tb) + local g = Linq.NewTable() + for k, v in pairs(tb) do + g[k] = v + end + return g +end + +function Linq.SlowSort(tb, sort) + local g = Linq.ShallowCopy(tb) + local len = #g + if sort ~= nil then + for i = 1, len - 1 do + for j = i + 1, len do + if sort(g[i], g[j]) > 0 then + g[i], g[j] = g[j], g[i] + end + end + end + else + for i = 1, len - 1 do + for j = i + 1, len do + if g[i] > g[j] then + g[i], g[j] = g[j], g[i] + end + end + end + end + return g +end +Linq.Sort = Linq.SlowSort + +function Linq.SelectMany(tb, map, filter) + local g = Linq.NewTable() + 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 + +function Linq.Skip(tb, number) + local g = Linq.NewTable() + local i = 0 + for _, v in ipairs(tb) do + i = i + 1 + if i > number then + table.insert(g, v) + end + end + return g +end + +function Linq.SkipLast(tb, number) + return Linq.Skip(Linq.Reverse(tb), number) +end + +function Linq.SkipWhile(tb, filter) + local g = Linq.NewTable() + local failure + for k, v in ipairs(tb) do + if failure then + table.insert(tb, v) + else + if not filter(v, k) then + table.insert(tb, v) + failure = true + end + end + end + return g +end + +function Linq.Take(tb, number) + local g = Linq.NewTable() + local i = 0 + for _, v in ipairs(tb) do + i = i + 1 + if i <= number then + table.insert(g, v) + else + break + end + end + return g +end + +function Linq.TakeWhile(tb, filter) + local g = Linq.NewTable() + for k, v in ipairs(tb) do + if filter(v, k) then + table.insert(g, v) + else + break + + end + end + return g +end + +function Linq.Zip2(tb1, tb2, map) + map = map or { a, b -> { a, b } } + local g = Linq.NewTable() + for i = 1, #tb1 do + table.insert(g, map(tb1[i], tb2[i])) + end + return g +end + +local function AddLinqfunctionsToMetatable(mt) + for functionName, func in pairs(table) do + mt[functionName] = func + end + for k, v in pairs(Linq) do + mt[k] = v + end +end + +AddLinqfunctionsToMetatable(magicTable) + + + + + + + +function Debug.DebugTable(tb) + local msg = "{ " + local DebugRec + DebugRec = function(tc) + for k,v in pairs(tc) do + if type(v) == "number" or type(v) == "string" then + msg = msg..k.." = "..v..", " + elseif type(v) == "boolean" then + msg = msg..k.." = "..tostring(v)..", " + elseif type(v) == "table" then + msg = msg..k.." = ".."{ " + DebugRec(v) + msg = msg.."}, " + end + end + end + DebugRec(tb) + msg = msg.." }" + print(msg) +end + +function Debug.DebugLongTable(tb) + if type(tb) ~= "table" then + print(tostring(tb)) + return + end + for k,v in pairs(tb) do + if type(v) == "table" then + print(tostring(k).." = ") + Debug.DebugTable(v) + else + print(tostring(k).." = "..tostring(v)) + end + end +end + + + + + +local AttributeTypeEnum = { + ATTRIBUTE_INVALID = ATTRIBUTE_INVALID, + ATTRIBUTE_STRENGTH = ATTRIBUTE_STRENGTH, + ATTRIBUTE_AGILITY = ATTRIBUTE_AGILITY, + ATTRIBUTE_INTELLECT = ATTRIBUTE_INTELLECT, +} +function DotaExt.AttributeTypeToString(i) + for k, v in pairs(AttributeTypeEnum) do + if v == i then + return k + end + end + return "unknown attribute type" +end + +function DotaExt.GetNearbyHeroes(bot, range, getEnemy, botMode) + botMode = botMode or BOT_MODE_NONE + getEnemy = getEnemy or true + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyHeroes(range1, getEnemy, botMode) + Linq.Give(units) + return units +end + +function DotaExt.GetNearbyLaneCreeps(bot, range, getEnemy) + getEnemy = getEnemy or true + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyLaneCreeps(range1, getEnemy) + Linq.Give(units) + return units +end + +function DotaExt.GetNearbyNeutralCreeps(bot, range) + local range1 = (function() + if range > 1600 then + return 1600 + else + return range + end + end)() + local units = bot:GetNearbyNeutralCreeps(range1) + Linq.Give(units) + return units +end + +local botModeEnum = { + BOT_MODE_NONE = BOT_MODE_NONE, + BOT_MODE_LANING = BOT_MODE_LANING, + BOT_MODE_ATTACK = BOT_MODE_ATTACK, + BOT_MODE_ROAM = BOT_MODE_ROAM, + BOT_MODE_RETREAT = BOT_MODE_RETREAT, + BOT_MODE_SECRET_SHOP = BOT_MODE_SECRET_SHOP, + BOT_MODE_SIDE_SHOP = BOT_MODE_SIDE_SHOP, + BOT_MODE_PUSH_TOWER_TOP = BOT_MODE_PUSH_TOWER_TOP, + BOT_MODE_PUSH_TOWER_MID = BOT_MODE_PUSH_TOWER_MID, + BOT_MODE_PUSH_TOWER_BOT = BOT_MODE_PUSH_TOWER_BOT, + BOT_MODE_DEFEND_TOWER_TOP = BOT_MODE_DEFEND_TOWER_TOP, + BOT_MODE_DEFEND_TOWER_MID = BOT_MODE_DEFEND_TOWER_MID, + BOT_MODE_DEFEND_TOWER_BOT = BOT_MODE_DEFEND_TOWER_BOT, + BOT_MODE_ASSEMBLE = BOT_MODE_ASSEMBLE, + BOT_MODE_TEAM_ROAM = BOT_MODE_TEAM_ROAM, + BOT_MODE_FARM = BOT_MODE_FARM, + BOT_MODE_DEFEND_ALLY = BOT_MODE_DEFEND_ALLY, + BOT_MODE_EVASIVE_MANEUVERS = BOT_MODE_EVASIVE_MANEUVERS, + BOT_MODE_ROSHAN = BOT_MODE_ROSHAN, + BOT_MODE_ITEM = BOT_MODE_ITEM, + BOT_MODE_WARD = BOT_MODE_WARD, +} +function DotaExt.BotModeToString(mode) + for k, v in pairs(botModeEnum) do + if mode == v then + return k + end + end + return "unknown bot mode "..mode +end + +DotaExt.towerNames = Linq.NewTable(TOWER_TOP_1, TOWER_TOP_2, TOWER_TOP_3, TOWER_MID_1, TOWER_MID_2, TOWER_MID_3, TOWER_BOT_1, TOWER_BOT_2, TOWER_BOT_3, TOWER_BASE_1, TOWER_BASE_2) +DotaExt.barracksNames = Linq.NewTable(BARRACKS_TOP_MELEE, BARRACKS_TOP_RANGED, BARRACKS_MID_MELEE, BARRACKS_MID_RANGED, BARRACKS_BOT_MELEE, BARRACKS_BOT_RANGED) +DotaExt.shrineNames = Linq.NewTable(SHRINE_BASE_1, SHRINE_BASE_2, SHRINE_BASE_3, SHRINE_BASE_4, SHRINE_BASE_5) + +function DotaExt.IsValidUnit(v) + return v and not v:IsNull() and v:IsAlive() +end + +function DotaExt.GetAllBuildings(team) + return DotaExt.towerNames:Map { t -> GetTower(team, t) } + :Concat( + DotaExt.barracksNames:Map { t -> GetBarracks(team, t) } + ) + :Concat( + DotaExt.shrineNames:Map { t -> GetShrine(team, t) } + ) + :Concat { GetAncient(team) } + :Filter { t -> DotaExt.IsValidUnit(t) and not t:IsInvulnerable() } +end + +function DotaExt.GetPureHeroes(npcBot, range, getEnemy) + range = range or 1600 + if getEnemy == nil then + getEnemy = true + end + return Linq.Filter(DotaExt.GetNearbyHeroes(npcBot, range, getEnemy)) { t -> + Hero.MayNotBeIllusion(npcBot, t) and not UnitFun.IsHeroLevelUnit(t) + } +end + +function DotaExt.EmptyFun() -> nil +function DotaExt.EmptyDesireFun() -> BOT_ACTION_DESIRE_NONE + + + + + + + + +AbilInfo.invisibleModifiers = Linq.NewTable( + "modifier_bounty_hunter_wind_walk", + "modifier_clinkz_wind_walk", + "modifier_dark_willow_shadow_realm_buff", + "modifier_item_glimmer_cape_glimmer", + "modifier_invoker_ghost_walk_self", + "modifier_nyx_assassin_vendetta", + "modifier_item_phase_boots_active", + "modifier_item_shadow_amulet_fade", + "modifier_item_invisibility_edge_windwalk", + "modifier_shadow_fiend_requiem_thinker", + "modifier_item_silver_edge_windwalk", + "modifier_windrunner_wind_walk", + "modifier_storm_wind_walk", + "modifier_templar_assassin_meld", + "modifier_visage_silent_as_the_grave", + "modifier_weaver_shukuchi", + "modified_invisible", + "modifier_rune_invis", + "modifier_nyx_assassin_burrow", + "modifier_oracle_false_promise_invis" +) + +AbilInfo.truesightModifiers = Linq.NewTable( + "modifier_item_dustofappearance", + "modifier_bounty_hunter_track", + "modifier_slardar_amplify_damage", + "modifier_truesight" +) + +function AbilInfo.HasAnyModifier(bot, modifiers) + return modifiers:Any { t -> + bot:HasModifier(t) + } +end + + + + + +local frameNumber = 0 +local dotaTimer +local deltaTime = 0 + +local function FloatEqual(a, b) + return math.abs(a - b) < 0.000001 +end + +local GameLoop = {} + +function GameLoop.GetFrameNumber() + return frameNumber +end + +function GameLoop.GetDeltaTime() + return deltaTime +end + +function GameLoop.EveryManyFrames(count, times) + times = times or 1 + return frameNumber % count < times +end + +local defaultReturn = Linq.NewTable() +local everySecondsCallRegistry = Linq.NewTable() + +function GameLoop.EveryManySeconds(second, registerName, oldFunction, ...) + if everySecondsCallRegistry[registerName] == nil then + local callTable = {} + callTable.lastCallTime = DotaTime() + RandomFloat(0, second) - second + callTable.interval = second + everySecondsCallRegistry[registerName] = callTable + end + local callTable = everySecondsCallRegistry[registerName] + if callTable.lastCallTime <= DotaTime() - callTable.interval then + callTable.lastCallTime = DotaTime() + return oldFunction(...) + else + return defaultReturn + end +end + +local singleForTeamRegistry = Linq.NewTable() +function GameLoop.SingleForTeam(oldFunction) + local functionName = tostring(oldFunction) + return function(...) + if singleForTeamRegistry[functionName] ~= frameNumber then + singleForTeamRegistry[functionName] = frameNumber + return oldFunction(...) + else + return defaultReturn + end + end +end + +function GameLoop.CalledOnThisFrame(functionInvocationResult) + return functionInvocationResult ~= defaultReturn +end + +function GameLoop.AiTicking() + return DotaTime() >= -75 +end + +local coroutineRegistry = Linq.NewTable() +local coroutineExempt = Linq.NewTable() + +function GameLoop.TickFromDota() + if not GameLoop.AiTicking() then + return + end + local time = DotaTime() + local function ResumeCoroutine(thread) + local coroutineResult = { coroutine.resume(thread, deltaTime) } + if not coroutineResult[1] then + print("error in coroutine:") + table.remove(coroutineResult, 1) + Debug.DebugLongTable(coroutineResult) + end + end + if dotaTimer == nil then + dotaTimer = time + return + end + deltaTime = time - dotaTimer + if not FloatEqual(time, dotaTimer) then + frameNumber = frameNumber + 1 + local threadIndex = 1 + while threadIndex <= #coroutineRegistry do + local t = coroutineRegistry[threadIndex] + local exemptIndex + local exempt + coroutineExempt:ForEach(function(exemptPair, index) + if exemptPair[1] == t then + if exemptPair[2] == frameNumber then + exempt = true + end + exemptIndex = index + end + end) + if exemptIndex then + table.remove(coroutineExempt, exemptIndex) + end + if not exempt then + if coroutine.status(t) == "suspended" then + ResumeCoroutine(t) + threadIndex = threadIndex + 1 + elseif coroutine.status(t) == "dead" then + table.remove(coroutineRegistry, threadIndex) + else + threadIndex = threadIndex + 1 + end + end + end + dotaTimer = time + end +end + +function GameLoop.ResumeUntilReturn(func) + local g = NewTable() + local thread = coroutine.create(func) + while true do + local values = { coroutine.resume(thread) } + if values[1] then + table.remove(values, 1) + table.insert(g, values) + else + print("error in coroutine:") + table.remove(values, 1) + Debug.DebugLongTable(values) + break + end + end + return g +end + +function GameLoop.StartCoroutine(func) + local newCoroutine = coroutine.create(func) + table.insert(coroutineRegistry, newCoroutine) + table.insert(coroutineExempt, { + newCoroutine, + frameNumber, + }) + return newCoroutine +end + +function GameLoop.WaitForSeconds(seconds) + local t = seconds + while t > 0 do + t = t - coroutine.yield() + end +end + +function GameLoop.StopCoroutine(thread) + GameLoop.Remove_Modify(coroutineExempt, function(t) + return t[1] == thread + end) + GameLoop.Remove_Modify(coroutineRegistry, thread) +end + + + + + +function Abil.UseAbilityOnEntity(bot, abil, entity, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on entity "..entity:GetUnitName() + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnEntity(abil, entity) + elif queueType == "push" then + bot:ActionPush_UseAbilityOnEntity(abil, entity) + else + bot:Action_UseAbilityOnEntity(abil, entity) + end +end +function Abil.UseAbility(bot, abil, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName() + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbility(abil) + elif queueType == "push" then + bot:ActionPush_UseAbility(abil) + else + bot:Action_UseAbility(abil) + end +end +function Abil.UseAbilityOnLocation(bot, abil, location, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on location "..fun1:ToStringVector(location) + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnLocation(abil, location) + elif queueType == "push" then + bot:ActionPush_UseAbilityOnLocation(abil, location) + else + bot:Action_UseAbilityOnLocation(abil, location) + end +end +function Abil.UseAbilityOnTree(bot, abil, tree, motive, queueType) + if Abil.print then + local printContent = bot:GetUnitName().." use "..abil:GetName().." on tree "..tree + if motive then + printContent = printContent..", motive = "..tostring(motive) + end + print(motive) + end + if queueType == "queue" then + bot:ActionQueue_UseAbilityOnTree(abil, tree) + elif queueType == "push" then + bot:ActionPush_UseAbilityOnTree(abil, tree) + else + bot:Action_UseAbilityOnTree(abil, tree) + end +end + + + + + + +function UnitFun.IsFarmingOrPushing(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_FARM or mode == BOT_MODE_PUSH_TOWER_BOT or mode == BOT_MODE_PUSH_TOWER_MID or mode == BOT_MODE_PUSH_TOWER_TOP or mode == BOT_MODE_DEFEND_TOWER_BOT or mode == BOT_MODE_DEFEND_TOWER_MID or mode == BOT_MODE_DEFEND_TOWER_TOP +end + +function UnitFun.IsLaning(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_LANING +end + +function UnitFun.IsAttackingEnemies(npcBot) + local mode = npcBot:GetActiveMode() + return mode == BOT_MODE_ROAM or mode == BOT_MODE_TEAM_ROAM or mode == BOT_MODE_ATTACK or mode == BOT_MODE_DEFEND_ALLY +end + +function UnitFun.IsRetreating(npcBot) + return npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_MODERATE +end + +function UnitFun.NotRetreating(npcBot) + return not UnitFun.IsRetreating(npcBot) +end + +local heroNamePrefixLen = #"npc_dota_hero_" +function UnitFun.GetHeroShortName(name) + return string.sub(name, heroNamePrefixLen + 1) +end + +function UnitFun.IsTempestDouble(npc) + return npc:HasModifier "modifier_arc_warden_tempest_double" +end + +function UnitFun.IsLoneDruidBear(npc) + return string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") +end + +function UnitFun.IsVisageFamiliar(npc) + return string.match(npc:GetUnitName(), "npc_dota_visage_familiar") +end + +function UnitFun.IsBrewmasterPrimalSplit(npc) + local unitName = npc:GetUnitName() + return string.match(unitName, "npc_dota_brewmaster_") +end + +function UnitFun.IsHeroLevelUnit(npc) + if UnitFun.IsBrewmasterPrimalSplit(npc) then return true end + local name = npc:GetUnitName() + if name == "npc_dota_phoenix_sun" then return true end + if string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") then + return true + end + return false +end + +local canUseItemIllusionModifiers = Linq.NewTable( + "modifier_arc_warden_tempest_double", + "modifier_skeleton_king_reincarnation_active", + "modifier_vengefulspirit_hybrid_special" +) + +function UnitFun.CanBuyItem(npc) + if UnitFun.IsHeroLevelUnit(npc) or UnitFun.IsTempestDouble(npc) then + return false + end + if npc:IsIllusion() then + return false + end + return true +end + +function UnitFun.CanUseItem(npc) + if UnitFun.IsBrewmasterPrimalSplit(npc) then return false end + if string.match(npc:GetUnitName(), "npc_dota_lone_druid_bear") then + return true + end + if name == "npc_dota_phoenix_sun" then + return false + end + if npc:IsIllusion() and not AbilInfo.HasAnyModifier(npc, canUseItemIllusionModifiers) then + return false + end + return true +end + +function UnitFun.IsGoodTarget(npc, target) + return target:IsHero() and Hero.MayNotBeIllusion(npc, target) and not UnitFun.IsHeroLevelUnit(target) +end + +function UnitFun.GetHeroTarget(npc) + if local t = npc:GetTarget(); t and UnitFun.IsGoodTarget(npc, t) then + return t + end +end + +function UnitFun.IsHero(npc) -> npc:IsHero() and not UnitFun.IsCreepHero(npc) +function UnitFun.IsCreepHero(npc) -> UnitFun.IsLoneDruidBear(npc) or UnitFun.IsVisageFamiliar(npc) + + + + + + + + +function Building.CanBeAttacked(buillding, npc) + if not building:IsAlive() or building:HasModifier "modifier_foutain_glyph" then + return false + end + npc = npc or GetBot() + if buidling:HasModifier "modifier_backdoor_protection_active" then + if local target = building:GetAttackTarget() then + if not target:IsHero() or target:IsIllusion() then + return true + end + end + return DotaExt.GetNearbyHeroes(npc, 1500, false):Filter(Hero.MayNotBeIllusion) + :Count { it -> + it:GetAttackTarget() == building + } * 80 >= building:GetHealth() + end + return true +end + + + + + + + + + +local ItemFun = {} + +function ItemFun.GetAvailableItem(npc, itemName, isNeutral) + if npc:IsMuted() then + return nil + end + if (itemName) == "item_tpscroll" then + local item = npc:GetItemInSlot(15) + if item and item:IsFullyCastable() then + return item + end + end + if isNeutral then -- although we can test if the item is neutral through ItemFun.IsNeutralItem, the parameter is passed explicitly for performance issue + local item = npc:GetItemInSlot(16) + if item and item:IsFullyCastable() then + return item + end + end + for _, i in ipairs(Linq.Range(0, 5):Concat { 16 }) do + local item = npc:GetItemInSlot(i) + if item and item:GetName() == itemName and item:IsFullyCastable() then + return item + end + end +end + +function ItemFun.GetAvailableTp(npc) + if local teleportation = npc:GetAbilityByName("furion_teleportation") then + if not npc:IsSilenced() and teleportation:IsFullyCastable() and teleportation:GetLevel() >= 2 then + return teleportation + end + end + if local keenConveyance = npc:GetAbilityByName("tinker_keen_conveyance") then + if keenConveyance:IsTrained() then + return keenConveyance + end + end + return ItemFun.GetAvailableItem(npc, "item_tpscroll") +end + +function ItemFun.CanUseAvailableTp(npc, tp) + local rearm = npc:GetAbilityByName "tinker_rearm" + if tp:GetName() == "tinker_keen_conveyance" then + if tp:IsFullyCastable() then + return true + end + if not tp:IsCooldownReady() and not npc:HasModifier "modifier_rejuvenation_aura_buff" and rearm and rearm:IsTrained() then + return true + end + end + if tp:GetName() == "furion_teleportation" then + return not npc:IsSilenced() and tp:IsFullyCastable() + end + return not npc:IsMuted() and tp:IsFullyCastable() +end + +function ItemFun.UseAvailableTp(npc, tp, location) + if tp:GetName() == "tinker_keen_conveyance" then + if tp:IsFullyCastable() then + ItemFun.UseAbilityOnLocation(npc, tp, location) + end + local rearm = npc:GetAbilityByName "tinker_rearm" + if not tp:IsCooldownReady() and not npc:HasModifier "modifier_rejuvenation_aura_buff" and rearm and rearm:IsTrained() then + while npc:IsSilenced() or not rearm:IsFullyCastable() do + coroutine.yield() + end + Abil.UseAbility(npc, rearm) + coroutine.yield() + while npc:IsChanneling() do + coroutine.yield() + end + Abil.UseAbilityOnLocation(npc, tp, location) + return true + end + return false + end + if tp:GetName() == "furion_teleportation" then + Abil.UseAbilityOnLocation(npc, tp, location) + return true + end + ItemFun.UseItemOnLocation(npc, tp, location) +end + + +function ItemFun.GetAvailableBlink(npc) + local blinks = { + "item_blink", + "item_overwhelming_blink", + "item_swift_blink", + "item_arcane_blink", + } + return Linq.Aggregate(blinks, nil, function(a, blinkName) + return a or ItemFun.GetAvailableItem(npc, blinkName) + end) +end + +function ItemFun.GetAvailableTravelBoots(npc) + local travelBoots = { + "item_travel_boots", + "item_travel_boots_2", + } + return Linq.Aggregate(travelBoots, nil, function(seed, t) + return seed or ItemFun.GetAvailableItem(npc, t) + end) +end + +function ItemFun.GetEmptyInventorySlots(npc) + local g = 0 + for i = 0, 5 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end + +function ItemFun.GetEmptyItemSlots(npc) + local g = 0 + for i = 0, 8 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end + +function ItemFun.GetEmptyBackpackSlots(npc) + local g = 0 + for i = 6, 8 do + if npc:GetItemInSlot(i) == nil then + g = g + 1 + end + end + return g +end + +function ItemFun.SwapItemToBackpack(npc, itemIndex) + for i = 6, 8 do + if npc:GetItemInSlot(i) == nil then + npc:ActionImmediate_SwapItems(itemIndex, i) + return true + end + end + return false +end + +function ItemFun.GetCarriedItems(npc) + local g = Linq.NewTable() + for i = 0, 8 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end + +function ItemFun.GetCarriedItemsWithIndex(npc) + local g = Linq.NewTable() + for i = 0, 8 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, { + i, + item, + }) + end + end + return g +end + +function ItemFun.GetInventoryItems(npc) + local g = Linq.NewTable() + for i = 0, 5 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end + +function ItemFun.GetInventoryItemNames(npc) + local g = Linq.NewTable() + for i = 0, 5 do + local item = npc:GetItemInSlot(i) + if item then + table.insert(g, item:GetName()) + end + end + return g +end + +function ItemFun.GetStashItems(npc) + local g = Linq.NewTable() + for i = 9, 14 do + local item = npc:GetItemInSlot(i) + if item then + item.slotIndex = i + table.insert(g, item) + end + end + return g +end + +function ItemFun.GetAllBoughtItems(npcBot) + local g = Linq.NewTable() + for i = 0, 16 do + local item = npcBot:GetItemInSlot(i) + if item then + table.insert(g, item) + end + end + return g +end + +function ItemFun.IsBoots(item) + if type(item) ~= "string" then + item = item:GetName() + end + return string.match(item, "boots") or item == "item_guardian_greaves" or item == "item_power_treads" +end + +ItemFun.InventoryOnlyItems = Linq.NewTable("item_gem", "item_rapier", "item_bloodstone", "item_aegis") +ItemFun.PurchasedConsumables = Linq.NewTable('item_clarity', 'item_tango', 'item_flask', 'item_faerie_fire', 'item_enchanted_mango', 'item_infused_raindrop') +ItemFun.NeutralItems = Linq.NewTable() +ItemFun.NeutralItems.T1 = Linq.NewTable("item_arcane_ring", "item_broom_handle", "item_chipped_vest", "item_fairys_trinket", "item_keen_optic", "item_ocean_heart", "item_pig_hole", "item_possessed_mask", "item_trusty_shovel", "item_tumblers_toy") +ItemFun.NeutralItems.T2 = Linq.NewTable("item_brigands_blade", "item_bullwhip", "item_dragon_scale", "item_essence_ring", "item_fae_grenade", "item_grove_bow", "item_nether_shawl", "item_philosophers_stome", "item_pupils_gift", "item_quicksilver_amulet", "item_ring_of_aquila", "item_vambrace") +ItemFun.NeutralItems.T3 = Linq.NewTable("item_blast_rig", "item_ceremonial_robe", "item_cloak_of_flames", "item_elven_tunic", "item_enchanted_quiver", "item_mind_breaker", "item_paladin_sword", "item_psychic_headband", "item_quickening_charm", "item_spider_legs", "item_titan_silver") +ItemFun.NeutralItems.T4 = Linq.NewTable("item_ascetics_cap", "item_flicker", "item_ninja_gear", "item_penta_edged_sword", "item_spell_prism", "item_stormcrafter", "item_telescope", "item_the_leveller", "item_timeless_relic", "item_trickster_cloak", "item_witchblade") +ItemFun.NeutralItems.T5 = Linq.NewTable("item_apex", "item_arcanists_armor", "item_book_of_shadows", "item_book_of_the_dead", "item_ex_machina", "item_fallen_sky", "item_force_boots", "item_giants_ring", "item_mirror_shield", "item_pirate_hat", "item_seer_stone", "item_stygian_desolator") + +function ItemFun.IsNeutralItem(name) + return Linq.Range(1, 5):Map { t -> + ItemFun.NeutralItems["T"..t] + }:Any { t -> + t:Contains(name) + } +end + +function ItemFun.CannotBePutIntoBackpack(item) + if type(item) ~= "string" then + item = item:GetName() + end + return ItemFun.InventoryOnlyItems:Contains(item) +end + +local function RateItem(item) + local name = item:GetName() + local rate = if name == "item_gem" { 4000 } + elif name == "item_dust" { 1800+200*item:GetCurrentCharges() } + elif ItemFun.PurchasedConsumables:Contains(name) { + local rate1 = GetItemCost(name) * item:GetCurrentCharges() + if name == "item_tango" then rate1 = rate1 / 3 + elseif name == "item_infused_raindrop" then rate1 = rate1 / 6 + end + rate1 + } + elif name == "item_rapier" { 14000 } + elif string.match(name, "recipe_") { 0 } + else { GetItemCost(name) } + return rate +end + +function ItemFun.SwapUsefulOnes(bot) + local items = ItemFun.GetCarriedItemsWithIndex(bot):Map { t -> + { + inventIndex = t[1], + item = t[2], + rate = RateItem(t[2]) + } + }:OrderByDescending { t -> + if bot:GetActiveMode() == BOT_MODE_WARD and (t.item:GetName() == "item_ward_observer" or t.item:GetName() == "item_ward_dispenser") then return 10000 end + if ItemFun.InventoryOnlyItems:Contains(t.item:GetName()) { 20000 } elif ItemFun.IsNeutralItem(t) { 0 } else { t.rate } + } + items:ForEach { t, index -> + t.correctIndex = index - 1 + } + local backpackItemsInInventory = items:Filter { t -> + bot:GetItemSlotType(t.inventIndex) == ITEM_SLOT_TYPE_MAIN and bot:GetItemSlotType(t.correctIndex) == ITEM_SLOT_TYPE_BACKPACK + } + local inventoryItemsInBackpack = items:Filter { t -> + bot:GetItemSlotType(t.inventIndex) == ITEM_SLOT_TYPE_BACKPACK and bot:GetItemSlotType(t.correctIndex) == ITEM_SLOT_TYPE_MAIN + } + Linq.ForEach2(backpackItemsInInventory, inventoryItemsInBackpack) { a, b -> + -- print(bot:GetUnitName().." swap "..a.item:GetName().." at index "..a.inventIndex.." with "..b.item:GetName().." index "..b.inventIndex) + -- bot:ActionImmediate_SwapItems(a.inventIndex, b.inventIndex) + -- b.item.cooldownFromBackpack = 6 + } +end + +ItemFun.defaultAbilityFunctions = Linq.NewTable("CanAbilityBeUpgraded", "GetAbilityDamage", "GetAOERadius", "GetAutoCastState", "GetBehavior", "GetCaster", "GetCastPoint", "GetCastRange", "GetChannelledManaCostPerSecond", "GetChannelTime", "GetDuration", "GetCooldown", "GetCooldownTimeRemaining", "GetCurrentCharges", "GetDamageType", "GetEstimatedDamageToTarget", "GetHeroLevelRequiredToUpgrade", "GetInitialCharges", "GetLevel", "GetManaCost", "GetMaxLevel", "GetName", "GetSecondaryCharges", "GetSpecialValueFloat", "GetSpecialValueInt", "GetTargetFlags", "GetTargetTeam", "GetTargetType", "GetToggleState", "IsActivated", "IsAttributeBonus", "IsChanneling", "IsCooldownReady", "IsFullyCastable", "IsHidden", "IsInAbilityPhase", "IsItem", "IsNull", "IsOwnersManaEnough", "IsPassive", "IsStealable", "IsStolen", "IsTalent", "IsToggle", "IsTrained", "IsUltimate", "ProcsMagicStick", "ToggleAutoCast") +ItemFun.defaultItemExtraFunctions = Linq.NewTable("CanBeDisassembled", "IsCombineLocked", "GetPowerTreadsStat") +ItemFun.defaultItemFunctions = ItemFun.defaultAbilityFunctions:Concat(ItemFun.defaultItemExtraFunctions) + +function ItemFun.UseItemNoTarget(npc, item, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName() + if cause then s = s.." because of "..cause end + print(s) + end + npc:Action_UseAbility(item) +end +function ItemFun.UseItemOnEntity(npc, item, entity, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on entity "..entity:GetUnitName() + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnEntity(item, entity) +end +function ItemFun.UseItemOnLocation(npc, item, loc, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on location "..fun1:ToStringVector(loc) + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnLocation(item, loc) +end +function ItemFun.UseItemOnTree(npc, item, tree, cause) + if ItemFun.print then + local s = npc:GetUnitName()..": use "..item:GetName().." on tree "..tostring(tree) + if cause then + s = s.." because of "..cause + end + print(s) + end + npc:Action_UseAbilityOnTree(item, tree) +end + +function ItemFun.FadeWouldMakeNoSense(t) + if t:HasModifier"modifier_item_dustofappearance" or t:HasModifier "modifier_truesight" or t:HasModifier"modifier_bounty_hunter_track" or t:HasModifier"modifier_slardar_amplify_damage" then + return true + end + return false +end + +local itemNamePrefix = "item_" +function ItemFun.GetItemShortName(t) + return string.sub(t, #itemNamePrefix+1) +end + + + + + + + +function Hero.MustBeIllusion(target) + if target:IsIllusion() then + return true + end + if GetTeam() == target:GetTeam() then + return target:IsIllusion() + end + if target.markedAsIllusion then + return true + end + if target.markedAsRealHero then + return false + end + if not IsHeroAlive(target:GetPlayerID()) then + return true + end + return false +end +function Hero.MayNotBeIllusion(t) + return not Hero.MustBeIllusion(t) +end + +function Hero.GetUniqueHeroNumber(heroes) + if #heroes == 0 then return 0 end + return Linq.Filter(heroes, Hero.MayNotBeIllusion):GroupBy { t -> t:GetPlayerID() }:Count() +end + +function Hero.HasScepter(npc) + return npc:HasScepter() or npc:HasModifier "modifier_wisp_tether_scepter" or npc:HasModifier "modifier_item_ultimate_scepter" or npc:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist" +end +function Hero.HasBoughtScepter(npc) + return npc:HasScepter() or npc:HasModifier "modifier_item_ultimate_scepter" or npc:HasModifier "modifier_item_ultimate_scepter_consumed_alchemist" +end + +function Hero.PrintMode(npc) + print("bot "..npc:GetUnitName().." in mode "..DotaExt.BotModeToString(npc:GetActiveMode())..", desire = "..npc:GetActiveModeDesire()) +end + + + + +local oldRoleUtils = require(GetScriptDirectory().."/util/RoleUtility") +local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") + + + + + +local ItemUse = {} + +function ItemUse.GetItemInfo(bot, item) + local itemAuxTable + if bot.itemAuxTable then + itemAuxTable = bot.itemAuxTable + else + itemAuxTable = {} + bot.itemAuxTable = itemAuxTable + end + local thisItemTable + local itemKey = tostring(item) + if itemAuxTable[itemKey] then + thisItemTable = itemAuxTable[itemKey] + else + itemAuxTable[itemKey] = {} + thisItemTable = itemAuxTable[itemKey] + end + return thisItemTable +end + +local primaryAbilityHasBonus = Linq.NewTable("obsidian_destroyer", "enchantress", "silencer", "drow_ranger") + +local function GetWantedPowerTreadsAttribute(npcBot, info) + local mode = npcBot:GetActiveMode() + if mode == BOT_MODE_RETREAT and npcBot:WasRecentlyDamagedByAnyHero(3) then + return ATTRIBUTE_STRENGTH, "MoreHealthWhenRetreat" + elseif UnitFun.IsAttackingEnemies(npcBot) then + local name = UnitFun.GetHeroShortName(npcBot:GetUnitName()) + if primaryAbilityHasBonus:Contains(name) then + return npcBot:GetPrimaryAttribute(), "PrimaryWithAbilityBonus" + else + return ATTRIBUTE_AGILITY, "AgilityWhenAttacking" + end + elseif mode == BOT_MODE_LANING then + return info.primAttr, "PrimaryForLH" + elseif npcBot:WasRecentlyDamagedByAnyHero(2) then + return ATTRIBUTE_STRENGTH, "StrengthWhenAttacked" + else + return info.primAttr, "PrimaryWhenIdle" + end +end + +local function UsePowerTreads(pt, bot, info) + if bot:HasModifier "modifier_ice_blast" then + return + end + if AbilInfo.HasAnyModifier(bot, AbilInfo.invisibleModifiers) and bot:UsingItemBreaksInvisibility() then + if bot:HasModifier("modifier_item_dustofappearance") then + bot:Action_UseAbility(pt) + return "BreakInvisibility" + end + if not AbilInfo.HasAnyModifier(bot, AbilInfo.truesightModifiers) then + return + end + end + local wantedAttribute, reason = GetWantedPowerTreadsAttribute(bot, info) + print(bot:GetUnitName().." want "..DotaExt.AttributeTypeToString(wantedAttribute)..", currently "..DotaExt.AttributeTypeToString(pt:GetPowerTreadsStat())..", reason = "..reason..", mode = "..DotaExt.BotModeToString(bot:GetActiveMode())) + if wantedAttribute ~= pt:GetPowerTreadsStat() then + return reason + end +end + +-- function ItemUseDefaultImpl.power_treads(item, bot, info) +-- print(bot:GetUnitName().." pt attribute: "..DotaExt.AttributeTypeToString(item:GetPowerTreadsStat())) +-- if bot:HasModifier "modifier_ice_blast" or math.floor(GameLoop.GetFrameNumber() % 4) ~= 0 then +-- return 0 +-- end +-- if local reason = UsePowerTreads(item, bot, info) then +-- return BOT_ACTION_DESIRE_HIGH, reason +-- end +-- return 0 +-- end + +function ItemUseDefaultImpl.branch(item, bot, info) + +end + +local function CountInventoryItemCooldown(bot, inventoryItems) + inventoryItems:ForEach { t -> + local r = ItemUse.GetItemInfo(bot, t) + if r.cooldownFromBackpack then + r.cooldownFromBackpack -= deltaTime + if r.cooldownFromBackpack <= 0 then + r.cooldownFromBackpack = 0 + end + end + } +end + +local entityOnlyItems = Linq.NewTable( +) +local noTargetOnlyItems = Linq.NewTable( + "arcane_boots", + "phase_boots", + "power_treads" +) +local treeOnlyItems = Linq.NewTable( +) +local locationOnlyItems = Linq.NewTable( + "travel_boots", + "travel_boots_2" +) + +local function ConsiderAvailableItem(item, bot, itemUsageAuxiliaryInfo) + local name = ItemFun.GetItemShortName(item:GetName()) + local itemFunc = bot.ItemUsage and bot.ItemUsage[name] or ItemUseDefaultImpl[name] + if itemFunc == nil then + GameLoop.EveryManySeconds(5, "NotifyUnimplementedItem "..name) { -> + -- print("Item not implemented: "..name) + } + return 0 + else + local castTarget, targetType, cause + local desire, b, c, d = itemFunc(item, bot, itemUsageAuxiliaryInfo) + if noTargetOnlyItems:Contains(name) then + castTarget, targetType, cause = nil, "none", b + elif treeOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "tree", c + elif locationOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "location", c + elif entityOnlyItems:Contains(name) then + castTarget, targetType, cause = b, "entity", c + else + castTarget, targetType, cause = b, c, d + end + return desire, castTarget, targetType, cause + end +end + +local function UseAvailableItems(bot, inventoryItems) + local itemUsageAuxiliaryInfo = Linq.NewTable() + local info = itemUsageAuxiliaryInfo + info.hp = bot:GetHealth() + info.hpm = bot:GetMaxHealth() + info.hpp = bot:GetHealth() / bot:GetMaxHealth() + info.mn = bot:GetMana() + info.mnm = bot:GetMaxMana() + info.mnp = info.mn / info.mnm + info.lev = bot:GetLevel() + info.allEnemies1400 = DotaExt.GetNearbyHeroes(bot, 1400) + info.e1400 = info.allEnemies1400:Filter(Hero.MayNotBeIllusion) + info.ec1400 = Hero.GetUniqueHeroNumber(info.e1400) + info.allEnemies1600 = DotaExt.GetNearbyHeroes(bot, 1600) + info.e1600 = info.allEnemies1600:Filter(Hero.MayNotBeIllusion) + info.ec1600 = Hero.GetUniqueHeroNumber(info.e1600) + info.allEnemies1200 = DotaExt.GetNearbyHeroes(bot, 1200) + info.e1200 = info.allEnemies1200:Filter(Hero.MayNotBeIllusion) + info.ec1200 = Hero.GetUniqueHeroNumber(info.e1200) + info.allEnemies900 = DotaExt.GetNearbyHeroes(bot, 900) + info.e900 = info.allEnemies900:Filter(Hero.MayNotBeIllusion) + info.ec900 = Hero.GetUniqueHeroNumber(info.e900) + info.allEnemies650 = DotaExt.GetNearbyHeroes(bot, 650) + info.e650 = info.allEnemies650:Filter(Hero.MayNotBeIllusion) + info.ec650 = Hero.GetUniqueHeroNumber(info.e650) + info.allAllies = DotaExt.GetNearbyHeroes(bot, 1500) + info.allies = info.allAllies:Filter(Hero.MayNotBeIllusion) + info.allyCount = Hero.GetUniqueHeroNumber(info.allies) + info.nw = bot:GetNetWorth() + info.bp = fun1:GetBattlePower(bot) + info.primAttr = bot:GetPrimaryAttribute() + info.blasted = bot:HasModifier "modifier_ice_blast" + info.target = bot:GetTarget() + + + local highDesireItem = inventoryItems:Map { t -> + local pack = { ConsiderAvailableItem(t, bot, itemUsageAuxiliaryInfo) } + pack[5] = t + return pack + }:Filter { t -> t[1] > 0 } + :MaxKey { t -> t[1] } + if local t = highDesireItem then + if t[3] == "none" then + if t[5]:GetName() == "item_power_treads" then + print(bot:GetUnitName().." use power treads") + end + ItemFun.UseItemNoTarget(bot, t[5], t[4]) + elseif t[3] == "location" then + ItemFun.UseItemOnLocation(bot, t[5], t[2], t[4]) + elseif t[3] == "tree" then + ItemFun.UseItemOnTree(bot, t[5], t[2], t[4]) + else + ItemFun.UseItemOnEntity(bot, t[5], t[2], t[4]) + end + end +end + +function ItemUse.CanUseAnyItem(t) + return not (fun1:IsMuted(t) or fun1:IsHypnosed(t) or fun1:IsFeared(t) or t:IsHexed() or t:IsChanneling()) +end + +function ItemUse.ItemUsageThink() + local bot = GetBot() + if not UnitFun.CanUseItem(bot) then + return + end + GameLoop.EveryManySeconds(3, "SwapUsefulItems "..bot:GetUnitName()) { -> + ItemFun.SwapUsefulOnes(bot) + } + local inventoryItems = ItemFun.GetInventoryItems(bot) + CountInventoryItemCooldown(bot, inventoryItems) + if ItemUse.CanUseAnyItem(bot) then + UseAvailableItems(bot, inventoryItems:Filter { t -> + t:IsFullyCastable() and (not bot:IsIllusion() or bot:HasModifier "modifier_skeleton_king_reincarnation_active" or bot:HasModifier "modifier_vengefulspirit_hybrid_special" or bot:HasModifier "modifier_arc_warden_tempest_double") + and ItemUse.GetItemInfo(bot, t).cooldownFromBackpack == nil + }) + end +end + + + + +local Role = {} +function Role.GetRoleValue(npc, role) + return oldRoleUtils.hero_roles[npc:GetUnitName()][role] +end +function Role.Push(npc) + return Role.GetRoleValue(npc, "pusher") +end + + + + +function Math.PointToPointDistance(a, b) + local x = a.x-b.x + local y = a.y-b.y + return (x*x+y*y)^0.5 +end + + + + + + +local Push_impl = {} +function Push_impl.GetCarryRate(hero) + return oldRoleUtils.hero_roles[hero:GetUnitName()].carry +end + +function Push_impl.GetLane( nTeam ,hHero ) + local vBot = GetLaneFrontLocation(nTeam, LANE_BOT, 0) + local vTop = GetLaneFrontLocation(nTeam, LANE_TOP, 0) + local vMid = GetLaneFrontLocation(nTeam, LANE_MID, 0) + return if GetUnitToLocationDistance(hHero, vBot) < 2500 { LANE_BOT } + elif GetUnitToLocationDistance(hHero, vTop) < 2500 { LANE_TOP } + elif GetUnitToLocationDistance(hHero, vMid) < 2500 { LANE_MID } + else { LANE_NONE } +end + +function Push_impl.CreepRate(creep) + local rate = 1 + rate *= if string.match(t, "upgraded_mega") {3.5} + elif string.match(t, "upgraded") {2} + else {1} + rate *= if string.match(t, "melee") {1} + elif string.match(t, "ranged") {1.2} + else {1.8} + return rate +end + +function Push_impl.CreepReward(creep) + local rate = 1 + rate *= if string.match(t, "upgraded_mega") {0.25} + elif string.match(t, "upgraded") {0.5} + else {1} + rate *= if string.match(t, "melee") {1} + elif string.match(t, "ranged") {1.7} + else {2} + return rate +end + +function Push_impl.GetAllyTower(towerIndex) + return GetTower(GetTeam(), towerIndex) +end +local allyTower1 = fun1:Map({TOWER_TOP_1, TOWER_MID_1, TOWER_BOT_1}, Push_impl.GetAllyTower) +local allyTower2 = fun1:Map({TOWER_TOP_2, TOWER_MID_2, TOWER_BOT_2}, Push_impl.GetAllyTower) +local allyTower3 = fun1:Map({TOWER_TOP_3, TOWER_MID_3, TOWER_BOT_3}, Push_impl.GetAllyTower) +local allyTower4 = fun1:Map({TOWER_BASE_1, TOWER_BASE_2}, Push_impl.GetAllyTower) + +function Push_impl.TowerRate(tower) + return if allyTower1:Contains(tower) { 1 } + elif allyTower2:Contains(tower) { 1.5 } + elif allyTower3:Contains(tower) { + if allyTower3:All { t -> t:IsAlive() } { 2 } else { 1.5 } + } + else { 1.7 } +end + +function Push_impl.CleanLaneDesire(npc, lane) + local front = GetLaneFrontLocation(GetTeam(), lane, 0) + local allyTower = GetNearestBuilding(GetTeam(), front) + local distanceToFront = GetUnitToUnitDistance(npc, allyTower:GetLocation()) + local creeps = fun1:Filter(GetUnitList(UNIT_LIST_ENEMY_CREEPS)) { t -> + GetUnitToLocationDistance(t, front) <= 1500 + } + local allyCreeps = fun1:Filter(GetUnitList(UNIT_LIST_FRIEND_CREEPS)) { t -> + GetUnitToLocationDistance(t, front) <= 1500 + } + local creepRateDiff = fun1:Aggregate(0, creeps:Map(Push_impl.CreepRate), { + }) - fun1:Aggregate(0, allyCreeps:Map(Push_impl.CreepRate), { + }) + local desire = 0 + local necessity = 0 + if distanceToFront <= 3000 then + if creepRateDiff >= DotaTime()/300 and creepRateDiff >= 3 then + necessity += creepRateDiff + end + if creepRateDiff >= 2 and creepRateDiff then + desire += fun1:Aggregate(0, creeps:Map(Push_impl.CreepReward), { + }) + end + end + necessity *= TowerRate(allyTower) + desire *= TowerRate(allyTower) + return desire, necessity +end + +function Push_impl.DefendLaneDesire() + return 0 +end + +function Push_impl.PushLaneDesire(npc, lane) + local team = GetTeam() + local teamPush = TeamPushLaneDesire(lane) + + local levelFactor = if npc:GetLevel() < 6 { 0 } else { 0.2 } + local myLane = GetLane(team, npc) + if myLane ~= LANE_NONE then + if Push_impl.CleanLaneDesire(myLane) > Push_impl.CleanLaneDesire(lane) then + return 0 + end + end + local healthRate = npcBot:GetHealth() / npcBot:GetMaxHealth() + fun1:GetLifeSteal(npc) * 2 + if healthRate > 1 then healthRate = 0 end + local manaRate = npcBot:GetMana() / npcBot:GetMaxMana() + local stateFactor = healthRate * 0.7 + manaRate * 0.3 + if stateFactor < 0.6 then + return 0 + end + + local roleFactor = if Role.Push(npc) { Role.Push(npc) * 0.2 } + elif Role.Support(npc) { Role.Support(npc) * 0.1 } + else { 0 } + local laneFront = GetLaneFrontLocation(team, lane, 0) + local distanceToFront = GetUnitToUnitDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local ddis = GetUnitToUnitDistance(nearestBuilding, laneFront) + + local tp = ItemFun.GetAvailableTp(npc) + local canCastTp = ItemFun.CanUseAvailableTp(npc, tp) + local distanceFactor = if distanceToFront <= 1000 or canCastTp { 1 } + elif distanceToFront - ddis >= 3000 and canCastTp { + if ddis <= 1000 { 0.7 } + elif ddis >= 6000 { 0 } + else { -(ddis-6000)*0.7/5000 } + } + elif distanceToFront >= 10000 { 0 } + else { -(distanceToFront-10000) / 9000 } + local factor = 0.2 + levelFactor + roleFactor + 0.4 * distanceFactor + 0.2 * stateFactor + if stateFactor < 1.2 then + factor *= RemapVal(stateFactor, 0.6, 1.2, 0, 0.7) + end + return Clamp(factor, 0, 0.8) +end + +function Push_impl.NoCreepsOnLane(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + return towerToEnemyHomeDistance < GetUnitToUnitDistance(enemyTower, allyTower) and Math.PointToPointDistance(laneFront, enemySpawnLocation) < towerToEnemyHomeDistance - maxDiveDistance +end + +function Push_impl.GetAttackBuildingLocation(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + local distanceToTower = GetUnitToUnitDistance(npc, enemyTower) + + if distanceToTower < 1000 then + return Push_impl.GetSafeLocation(npc, enemyTower) + else + if Math.PointToPointDistance(laneFront, enemySpawnLocation) < towerToEnemyHomeDistance - maxDiveDistance and npc:GetLevel() <= 11 then + return Push_impl.GetSafeLocation(npc, allyTower) + else + return Push_impl.GetSafeLocation(npc, enemyTower) + end + end +end + +function Push_impl.CreepAttackingTower(creeps, tower) + return Linq.Any(creeps) { t -> + t:GetAttackTarget() == tower + } +end + +function Push_impl.IsSafeToAttack(npc, lane, creeps) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local maxDiveDistance = 400 + local distanceToEnemyHome = GetUnitToLocationDistance(npc, enemySpawnLocation) + local towerToEnemyHomeDistance = GetUnitToLocationDistance(enemyTower, enemySpawnLocation) + local distanceToTower = GetUnitToUnitDistance(npc, enemyTower) + + local safe = distanceToTower > 1500 or GetUnitToUnitDistanceSqr(npc, allyTower) <= 490000 + local creepMinDistance = creeps:Min { t -> + GetUnitToUnitDistanceSqr(t, enemyTower) + } + if creepMinDistance and (distanceToTower < creepMinDistance or distanceToEnemyHome < towerToEnemyHomeDistance - maxDiveDistance) then + safe = true + end + if enemyTower:GetAttackDamage() < 20 then + safe = true + end + return safe +end + +function Push_impl.TryTp(npc, lane) + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local distanceToFront = GetUnitToLocationDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local distanceToNearestBuilding = GetUnitToLocationDistance(nearestBuilding, laneFront) + local amount = Push_impl.GetAmountAlongLane(lane, npc:GetLocation()) + + local tp = Push_impl.GetAvailableTp(npc) + if distanceToFront > 3000 and distanceToFront - distanceToNearestBuilding > 3000 then + npc.Push_impl_TryTp = GameLoop.StartCoroutine { -> Push_impl.UseAvailableTp(npc, tp) } + end +end + +function Push_impl.GetCreepsNearTower(npc, tower) + return DotaExt.GetNearbyCreeps(npc, 1400, false):Filter { t -> + GetUnitToLocationDistanceSqr(t, tower) < 640000 + } +end + +function Push.UnitPushLaneThink(npc, lane) + if (npc:IsChanneling() or npc:IsUsingAbility() or npc:GetQueuedActionType(0) == BOT_ACTION_TYPE_USE_ABILITY) then + return + end + + if npc.Push_impl_TryTp then + if coroutine.status(npc.Push_impl_TryTp) == "dead" then + npc.Push_impl_TryTp = nil + else + return + end + else + Push_impl.TryTp(npc, lane) + end + local team = GetTeam() + local laneFront = GetLaneFrontLocation(team, lane, 0) + local allyTower = Push_impl.GetNearestBuilding(team, laneFront) + local enemyTower = Push_impl.GetNearestBuilding(GetOpposingTeam(), laneFront) + local enemySpawnLocation = Push_impl.GetEnemySpawnLocation() + local distanceToFront = GetUnitToLocationDistance(npc, laneFront) + local nearestBuilding = Push_impl.GetNearestBuilding(team, laneFront) + local distanceToNearestBuilding = GetUnitToLocationDistance(nearestBuilding, laneFront) + local creeps = Push_impl.GetCreepsNearTower(npc, enemyTower) + local targetLocation = Push_impl.GetTargetLocation(npc, lane) + local buildingAttackedByTower = Push_impl.CreepAttackingTower(creeps, enemyTower) + local isSafeToAttack = Push_impl.IsSafeToAttack(npc, lane, creeps) + local noCreeps = Push_impl.NoCreepsOnLane(npc, lane) + + local enemies = DotaExt.GetNearbyHeroes(npc, 1200) + local target = Push_impl.GetMyTarget(npc, lane, targetLocation) + if target then + targetLocation = Push_impl.GetSafeLocation(npc, target) + end + + local goodSituation = true + if (npc:GetLevel() >= 12 or npc:GetLevel() >= DotaTime() / 120) and npc:GetHealth() >= 700 and #enemeis == 0 then + goodSituation = true + end + if (not isSafeToAttack or noCreeps) and (fun1:GetHealthPercent(enemyTower) >= 0.2 and enemyTower:GetAttackDamage() > 20) then + goodSituation = false + end + + if Push_impl.TooManyEnemies() then + Push_impl.AssembleWithAlly(npc) + elseif not goodSituation then + Push_impl.StepBack(npc) + end +end + + + + + + + +M.Linq = Linq +M.Debug = Debug +M.Dota = DotaExt +M.Unit = UnitFun +M.Game = GameLoop +M.Item = ItemFun +M.ItemUse = ItemUse +M.Hero = Hero +M.Building = Building + +return M \ No newline at end of file diff --git a/util/PushUtility.lua b/util/PushUtility.lua index 04b8c883..008168e8 100644 --- a/util/PushUtility.lua +++ b/util/PushUtility.lua @@ -3,22 +3,22 @@ module("PushUtility", package.seeall) local role = require(GetScriptDirectory() .. "/util/RoleUtility") local AbilityExtensions = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") function GetLane( nTeam ,hHero ) - local vBot = GetLaneFrontLocation(nTeam, LANE_BOT, 0) - local vTop = GetLaneFrontLocation(nTeam, LANE_TOP, 0) - local vMid = GetLaneFrontLocation(nTeam, LANE_MID, 0) - --print(GetUnitToLocationDistance(hHero, vMid)) - if GetUnitToLocationDistance(hHero, vBot) < 2500 then - return LANE_BOT - end - if GetUnitToLocationDistance(hHero, vTop) < 2500 then - return LANE_TOP - end - if GetUnitToLocationDistance(hHero, vMid) < 2500 then - return LANE_MID - end - return LANE_NONE + local vBot = GetLaneFrontLocation(nTeam, LANE_BOT, 0) + local vTop = GetLaneFrontLocation(nTeam, LANE_TOP, 0) + local vMid = GetLaneFrontLocation(nTeam, LANE_MID, 0) + if GetUnitToLocationDistance(hHero, vBot) < 2500 then + return LANE_BOT + end + if GetUnitToLocationDistance(hHero, vTop) < 2500 then + return LANE_TOP + end + if GetUnitToLocationDistance(hHero, vMid) < 2500 then + return LANE_MID + end + return LANE_NONE end function IsThisLaneNeedToClean(npcBot,lane) @@ -57,7 +57,7 @@ function IsThisLaneNeedToClean(npcBot,lane) return false end -function GetUnitPushLaneDesire(npcBot,lane) +function GetUnitPushLaneDesire(npcBot, lane) local team = GetTeam() local teamPush = GetPushLaneDesire( lane ); @@ -79,7 +79,7 @@ function GetUnitPushLaneDesire(npcBot,lane) local healthRate = npcBot:GetHealth() / npcBot:GetMaxHealth() local manaRate = npcBot:GetMana() / npcBot:GetMaxMana() local stateFactor = healthRate * 0.7 + manaRate * 0.3 - local roleFactor =0 + local roleFactor = 0 if role.IsPusher(npcBot:GetUnitName())==true then roleFactor=roleFactor+0.2; @@ -119,6 +119,9 @@ function GetUnitPushLaneDesire(npcBot,lane) end local sumFactor=0.2 + 0.2 * levelFactor + 0.2 * stateFactor + 0.2 * distFactor + roleFactor; + if npcBot.pushWhenNoEnemies then + sumFactor = sumFactor + 1 + end local desire = math.min(sumFactor * teamPush , 0.8) return desire @@ -140,7 +143,89 @@ function isNoCreeps(npcBot,lane) --判断兵线位置在不在塔前,不要 return false; end -function getTargetLocation(npcBot,lane) +local function IsRanged(npc) + return npc:GetAttackRange() >= 260 or npc:GetUnitName() == "npc_dota_hero_templar_assassin" +end + +local function GetSafeLocationToEnemyBuilding(npc, building) + local EnemyTeam = GetOpposingTeam() + local Allys = npc:GetNearbyHeroes(1600,false,BOT_MODE_NONE) + local enemys = npc:GetNearbyHeroes(1600,true,BOT_MODE_NONE) + local allyCount = AbilityExtensions:GetEnemyHeroNumber(npc, Allys) + local enemyCount = AbilityExtensions:GetEnemyHeroNumber(npc, enemys) + local attackRange = npc:GetAttackRange() + building:GetBoundingRadius() + local buildingLocation = building:GetLocation() + + local RandomInt = 240 + local isRanged = IsRanged(npc) + + local ids = {} + local MinDamageHeroID + local MinDamage=1000 + for k,v in pairs(Allys) + do + local damage=v:GetAttackDamage() + if damage=3 and enemyCount~=0) + then + attackRange = 800 + end + + local alpha + if isRanged then + alpha=210 + else + alpha=300 + end + local spawnloc=GetEnemySpawnLocation() + local DistanceToEnemyHome=GetUnitToLocationDistance(npc, spawnloc) + local DistanceToHome=npc:DistanceFromFountain() + local UnitVector + if(DistanceToEnemyHome-DistanceToHome<0) + then + UnitVector=GetUnitVector(spawnloc, buildingLocation) + else + UnitVector=GetUnitVector(buildingLocation, GetAllySpawnLocation()) + end + + local theta=math.deg(math.atan2(UnitVector.y,UnitVector.x)) + if(theta<0) + then + theta=theta+360 + end + local myid=npc:GetPlayerID() + local myNumber=1 + for k,v in pairs(ids) + do + if(myid==v) + then + myNumber=k + end + end + + local delta=math.rad(theta-alpha/2+alpha/(#ids+1)*myNumber) + local FinalVector=Vector(math.cos(delta),math.sin(delta)) + local TargetLocation=buildingLocation+attackRange*FinalVector + + return TargetLocation --+ RandomVector( RandomInt ) +end + +local function GetTargetLocation(npcBot,lane) local front = GetLaneFrontLocation( GetTeam(), lane, 0 ) local EnemyTower = GetNearestBuilding(GetOpposingTeam(), front) or GetAncient(GetOpposingTeam()) local AllyTower = GetNearestBuilding(GetTeam(), front) @@ -152,14 +237,8 @@ function getTargetLocation(npcBot,lane) if(TowerDistance<1000) then - -- if(lane==LANE_MID) then - -- gamma=-15 - -- end - return GetSafeLocation(npcBot,EnemyTower:GetLocation(),gamma); + return GetSafeLocationToEnemyBuilding(npcBot,EnemyTower) else - -- if(lane==LANE_MID) then - -- gamma=-5 - -- end if(PointToPointDistance(front,EnemySpawnLocation)=2) + if(creepsNearTower~=nil and #creepsNearTower>=1) then for k,v in pairs(creepsNearTower) do @@ -283,12 +360,71 @@ local function getMyTarget(npcBot,lane,TargetLocation) return nil; end +local function GetPhysicalDps(npc) + return npc:GetAttackDamage() * npc:GetAttackSpeed() / 170 +end + +local function AttackedByTowerRate(npc, targetBuilding) + if not targetBuilding then + return 0, "no tower provided" + end + local hpPercent = AbilityExtensions:GetHealthPercent(npc) + local targetHpPercent = AbilityExtensions:GetHealthPercent(targetBuilding) + if targetBuilding:HasModifier "modifier_fountain_glyph" then + return 0, "fountain glyph" + end + if targetBuilding:GetAttackDamage() < 20 then + return 1, "barracks" + end + if hpPercent < 0.7 and targetHpPercent > 0.15 or hpPercent < 0.5 then + return 0, "bad hp percent" + end + + local rate = 0 + local health = npc:GetHealth() + local enemyCount = AbilityExtensions:GetEnemyHeroNumber(npc, AbilityExtensions:GetNearbyHeroes(npc, 1400)) + local allyCount = AbilityExtensions:GetEnemyHeroNumber(npc, AbilityExtensions:GetNearbyHeroes(npc, 1400, false)) + if enemyCount ~= 0 and enemyCount >= allyCount - 1 then + return 0, "many enemies" + end + + if health >= 1000 and hpPercent >= 0.7 + enemyCount * 0.1 then + rate = rate + RemapValClamped(health-targetBuilding:GetHealth(), 500, 2000, -0.1, 0.3) + end + local armour = npc:GetArmor() + if armour > 12 then + rate = rate + RemapValClamped(armour, 12, 30, 0.04, 0.35) + end + rate = rate / (1 - npc:GetEvasion()) + + local allyCreepCount = AbilityExtensions:GetNearbyLaneCreeps(npc, 1400, false):Count(function(t) return GetUnitToUnitDistanceSqr(t, targetBuilding) <= 720*720 end) + if allyCreepCount == 0 and targetHpPercent > 0.25 and rate < 0.3 then + rate = rate - 0.1 + end + local allAlliesCount = AbilityExtensions:GetNearbyHeroes(npc, 1400, false):Concat(AbilityExtensions:GetNearbyLaneCreeps(npc, 1400, false)):Count(function(t) return GetUnitToUnitDistanceSqr(t, targetBuilding) <= 720*720 end) + + local dps = GetPhysicalDps(npc) + if targetBuilding:HasModifier "modifier_backdoor_protection_active" then + if dps < 360 / allyCount then + rate = rate - 0.15 + end + end + + if targetBuilding:HasModifier "modifier_fountain_glyph" then + if allAlliesCount <= 6 and rate < 0.32 or allAlliesCount <= 8 and rate <= 0.24 then + rate = 0 + end + end + return rate, "normal rating" +end + function UnitPushLaneThink(npcBot,lane) + -- print(npcBot:GetUnitName().." push lane think") if (npcBot:IsChanneling() or npcBot:IsUsingAbility() or npcBot:GetQueuedActionType(0) == BOT_ACTION_TYPE_USE_ABILITY) then return; end - tryTP(npcBot,lane); --use tp to push quickly + tryTP(npcBot,lane) local team = GetTeam() local front = GetLaneFrontLocation( team, lane, 0 ) @@ -296,61 +432,82 @@ function UnitPushLaneThink(npcBot,lane) local TowerDistance = GetUnitToUnitDistance(npcBot,EnemyTower) local creepsNearTower = getCreepsNearTower(npcBot,EnemyTower); - local TargetLocation = getTargetLocation(npcBot,lane) --Scatter positions to avoid AOE + local TargetLocation = GetTargetLocation(npcBot,lane) --Scatter positions to avoid AOE local CreepAttackTower = IsCreepAttackTower(creepsNearTower,EnemyTower) local Safe = IsSafe(npcBot,lane,creepsNearTower); local noCreeps=isNoCreeps(npcBot,lane) - - --print(getShortName(npcBot).."\tCreepAttackTower: "..tostring(CreepAttackTower).." Safe:"..tostring(Safe).." noCreeps:"..tostring(noCreeps)) - - local enemys = npcBot:GetNearbyHeroes(1200,true,BOT_MODE_NONE) - - local target=getMyTarget(npcBot,lane,TargetLocation) - - if target~=nil then + local enemys = npcBot:GetNearbyHeroes(1200,true,BOT_MODE_NONE) or {} + local enemyCount = A.Hero.GetUniqueHeroNumber(enemys) + local target = getMyTarget(npcBot,lane,TargetLocation) + if target then TargetLocation=GetSafeLocation(npcBot,target:GetLocation(),0) end - + local attackedByTowerRate, attackedByTowerRateReason = AttackedByTowerRate(npcBot, EnemyTower) + -- print(npcBot:GetUnitName().." rate = "..attackedByTowerRate.." reason = "..attackedByTowerRateReason) + local okToBeAttackedByTower = attackedByTowerRate > 0.3 - local goodSituation=true; + local goodSituation=true if (npcBot:GetLevel()>=12 and npcBot:GetHealth()>=1500 or npcBot:GetHealth() >= 700 and #enemys == 0) then - goodSituation=true; - elseif ((Safe==false or noCreeps==true) and EnemyTower:GetHealth()/EnemyTower:GetMaxHealth()>=0.2) + goodSituation=true + elseif ((Safe==false or noCreeps and not okToBeAttackedByTower) and EnemyTower:GetHealth()/EnemyTower:GetMaxHealth()>=0.2) then - goodSituation=false; + goodSituation=false end local MinDelta=200 - if(IsEnemyTooMany()) then + if IsEnemyTooMany() then AssembleWithAlly(npcBot) + -- print(npcBot:GetUnitName().." assemble with ally") elseif goodSituation==false then 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) or AbilityExtensions:Any(npcBot:GetNearbyTowers(700, true), function(t) + -- print(npcBot:GetUnitName().." situation is not good") + elseif npcBot:WasRecentlyDamagedByTower(1) then + local needToStepBack = AbilityExtensions:Any(npcBot:GetNearbyTowers(700 + npcBot:GetBoundingRadius(), true), function(t) t:HasModifier("modifier_fountain_glyph") end) - then - StepBack( npcBot ) - --print(getCurrentFileName().." "..getShortName(npcBot).." attacked"); + if not needToStepBack then + needToStepBack = not TransferHatred(npcBot) end - elseif GetUnitToLocationDistance(npcBot,TargetLocation)>=MinDelta then - npcBot:Action_MoveToLocation(TargetLocation); + if enemyCount >= 1 and needToStepBack or not okToBeAttackedByTower then + StepBack(npcBot) + else + npcBot:Action_AttackUnit(EnemyTower, false) + end + -- print(npcBot:GetUnitName().." damaged by tower") + elseif GetUnitToLocationDistance(npcBot, TargetLocation) >= MinDelta then + -- print(npcBot:GetUnitName().." way from target location, moving") + npcBot:Action_MoveToLocation(TargetLocation) + -- if GetUnitToLocationDistanceSqr(npcBot, TargetLocation) <= 90000 then + -- if not npcBot:GetAttackTarget() then + -- npcBot:Action_AttackMove(TargetLocation) + -- end + -- else + -- npcBot:Action_MoveToLocation(TargetLocation) + -- end elseif target then + -- print(npcBot:GetUnitName().." has target "..target:GetUnitName()) npcBot:Action_AttackUnit( target, true ) - elseif TowerDistance <= 1200 then - if (CreepAttackTower) then + elseif TowerDistance <= 1600 then + -- print(npcBot:GetUnitName().." push tower: "..EnemyTower:GetUnitName()) + if CreepAttackTower or EnemyTower:GetAttackDamage() < 20 then npcBot:Action_AttackUnit( EnemyTower, false ) else - --print(getCurrentFileName().." "..getShortName(npcBot).." tower distance too high"); StepBack( npcBot ) end else - npcBot:Action_MoveToLocation(TargetLocation); + -- print(npcBot:GetUnitName().." idle move: "..AbilityExtensions:ToStringVector(TargetLocation)) + npcBot:Action_MoveToLocation(TargetLocation) + -- if GetUnitToLocationDistanceSqr(npcBot, TargetLocation) <= 90000 then + -- if not npcBot:GetAttackTarget() then + -- npcBot:Action_AttackMove(TargetLocation) + -- end + -- else + -- npcBot:Action_MoveToLocation(TargetLocation) + -- end end return true end @@ -517,7 +674,9 @@ function GetNearestBuilding(team, location) return nearestBuilding end -function GetAllBuilding( team,location ) + + +function GetAllBuilding(team, location) local buildings = {} for i=0,10 do local tower = GetTower(team,i) @@ -582,7 +741,7 @@ end Locations = { ["RadiantSpawn"]= Vector(-6950,-6275), ["DireSpawn"]= Vector(7150, 6300), - } +} function TransferHatred( unit ) @@ -596,7 +755,6 @@ function TransferHatred( unit ) tower = towers[1] end local creeps = unit:GetNearbyCreeps( 1500, false ) - -- print("hurt",#creeps) for k,creep in pairs(creeps) do if NotNilOrDead(creep) and NotNilOrDead(tower) and GetUnitToUnitDistance(tower, creep)<=tower:GetAttackRange() then unit:Action_AttackUnit( creep, true ) @@ -656,34 +814,6 @@ 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]) + unit:GetBoundingRadius() - 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 diff --git a/util/TeamItemThink.lua b/util/TeamItemThink.lua index 0e03c3a6..74c87e02 100644 --- a/util/TeamItemThink.lua +++ b/util/TeamItemThink.lua @@ -1,16 +1,21 @@ --------------------------------------------- --- Generated from Mirana Compiler version 1.6.1 +-- Generated from Mirana Compiler version 1.6.2 -- Do not modify -- https://github.com/AaronSong321/Mirana --------------------------------------------- local M = {} local ItemUsage = require(GetScriptDirectory().."/util/ItemUsage-New") local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +<<<<<<< HEAD +======= +local A = require(GetScriptDirectory().."/util/MiraDota") +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a M.ImplmentedTeamItems = { "item_mekansm", "item_guardian_greaves", } local roles = { +<<<<<<< HEAD abaddon = { 9 }, abyssal_underlord = { 4 }, alchemist = { 0 }, @@ -114,12 +119,431 @@ local roles = { winter_wyvern = { 7 }, witch_doctor = { 6 }, zuus = { 3 }, +======= + abaddon = { + 9, + 6, + }, + abyssal_underlord = { + 4, + 7, + }, + alchemist = { + 0, + 1, + }, + ancient_apparition = { + 2, + 9, + }, + antimage = { + 1, + 0, + }, + arc_warden = { + 0, + 2, + }, + axe = { + 2, + 2, + }, + bane = { + 3, + 7, + }, + batrider = { + 4, + 6, + }, + beastmaster = { + 0, + 2, + }, + bloodseeker = { + 1, + 1, + }, + bounty_hunter = { + 3, + 5, + }, + brewmaster = { + 0, + 1, + }, + bristleback = { + 4, + 7, + }, + broodmother = { + 5, + 1, + }, + centaur = { + 3, + 3, + }, + chaos_knight = { + 2, + 2, + }, + chen = { + 9, + 8, + }, + clinkz = { + 1, + 1, + }, + crystal_maiden = { + 8, + 3, + }, + dark_seer = { + 7, + 7, + }, + dazzle = { + 9, + 5, + }, + death_prophet = { + 5, + 6, + }, + disruptor = { + 6, + 3, + }, + doom_bringer = { + 1, + 2, + }, + dragon_knight = { + 0, + 1, + }, + drow_ranger = { + 0, + 0, + }, + earth_spirit = { + 6, + 5, + }, + earthshaker = { + 5, + 6, + }, + ember_spirit = { + 2, + 2, + }, + enchantress = { + 3, + 4, + }, + enigma = { + 8, + 6, + }, + faceless_void = { + 1, + 0, + }, + furion = { + 5, + 0, + }, + gyrocopter = { + 4, + 2, + }, + hoodwink = { + 5, + 4, + }, + huskar = { + 1, + 0, + }, + jakiro = { + 7, + 5, + }, + juggernaut = { + 0, + 0, + }, + keeper_of_the_light = { + 4, + 0, + }, + kunkka = { + 1, + 2, + }, + legion_commander = { + 1, + 0, + }, + leshrac = { + 4, + 6, + }, + lich = { + 5, + 8, + }, + life_stealer = { + 2, + 0, + }, + lina = { + 5, + 6, + }, + lion = { + 5, + 3, + }, + luna = { + 1, + 1, + }, + lycan = { + 4, + 0, + }, + magnataur = { + 0, + 5, + }, + medusa = { + 0, + 3, + }, + mirana = { + 1, + 5, + }, + monkey_king = { + 0, + 0, + }, + naga_siren = { + 3, + 2, + }, + necrolyte = { + 7, + 8, + }, + nevermore = { + 3, + 2, + }, + night_stalker = { + 2, + 0, + }, + nyx_assassin = { + 5, + 7, + }, + obsidian_destroyer = { + 4, + 0, + }, + ogre_magi = { + 4, + 7, + }, + omniknight = { + 8, + 7, + }, + oracle = { + 8, + 8, + }, + phantom_assassin = { + 1, + 0, + }, + phantom_lancer = { + 1, + 1, + }, + pugna = { + 5, + 8, + }, + puck = { + 4, + 5, + }, + pudge = { + 1, + 4, + }, + queenofpain = { + 3, + 3, + }, + rattletrap = { + 4, + 2, + }, + razor = { + 6, + 0, + }, + riki = { + 3, + 0, + }, + sand_king = { + 5, + 7, + }, + shadow_demon = { + 6, + 6, + }, + shadow_shaman = { + 8, + 8, + }, + shredder = { + 3, + 9, + }, + silencer = { + 6, + 3, + }, + skeleton_king = { + 1, + 0, + }, + skywrath_mage = { + 4, + 9, + }, + slardar = { + 2, + 1, + }, + slark = { + 1, + 0, + }, + sniper = { + 0, + 0, + }, + spectre = { + 4, + 0, + }, + spirit_breaker = { + 3, + 1, + }, + sven = { + 1, + 2, + }, + templar_assassin = { + 1, + 0, + }, + terrorblade = { + 1, + 0, + }, + tidehunter = { + 7, + 7, + }, + tinker = { + 0, + 5, + }, + tiny = { + 2, + 4, + }, + treant = { + 7, + 7, + }, + troll_warlord = { + 0, + 0, + }, + tusk = { + 4, + 2, + }, + undying = { + 6, + 8, + }, + ursa = { + 0, + 0, + }, + vengefulspirit = { + 5, + 6, + }, + venomancer = { + 7, + 5, + }, + viper = { + 6, + 1, + }, + warlock = { + 7, + 8, + }, + weaver = { + 2, + 1, + }, + windrunner = { + 4, + 6, + }, + winter_wyvern = { + 7, + 5, + }, + witch_doctor = { + 6, + 5, + }, + zuus = { + 3, + 9, + }, +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a } local function heroItemMetaFunc(tb, key) - if key == "mekansm" then - return tb[1] - end - return 0 + return (function() + if key == "mekansm" then + return tb[1] + elseif key == "arcaneBoots" then + return tb[2] + else + return 0 + end + end)() end local heroItemMetatable = { __index = heroItemMetaFunc } fun1:ForEachDic(roles, function(it) @@ -171,17 +595,19 @@ local function NextNodes(item) return GetItemComponents(item)[1] end function M.ExpandFirstLevel(item) - if IsLeaf(item) then - return { - name = item, - isSingleItem = true, - } - else - return { - name = item, - recipe = NextNodes(item), - } - end + return (function() + if IsLeaf(item) then + return { + name = item, + isSingleItem = true, + } + else + return { + name = item, + recipe = NextNodes(item), + } + end + end)() end function M.ExpandOnce(item) local g = {} @@ -205,16 +631,21 @@ function M.FullyExpandItem(itemName) end return p end +function M.ExpandTeamThinkItem(itemName) + local p = M.FullyExpandItem(itemName) + p.origin = "TeamItemThink" + return p +end local function AddBefore(tb, item, before) for index, v in ipairs(tb) do - if not before(v) then + if before(v) then table.insert(tb, index, item) return end end - table.insert(tb, 1, item) + table.insert(tb, #tb + 1, item) end -local function GenerateFilter(maxCost, putBefore, putAfter) +local function GeneratePutBeforeFilter(maxCost, putBefore, putAfter) return function(itemInfo) local itemName = itemInfo.name local shortName = string.sub(itemName, 6) @@ -222,7 +653,7 @@ local function GenerateFilter(maxCost, putBefore, putAfter) if fun1:Contains(putAfter, shortName) then return false else - return fun1:Contains(putBefore, shortName) or GetItemCost(itemName) < maxCost + return fun1:Contains(putBefore, shortName) or GetItemCost(itemName) > maxCost end end)() end @@ -230,7 +661,7 @@ end local teamItemEvents = fun1:NewTable() local function NotifyTeam(npcBot, itemName) fun1:StartCoroutine(function() - fun1:WaitForSeconds(math.random(0, 4)) + fun1:WaitForSeconds(math.random(20, 28)) return table.insert(teamItemEvents, { npcBot, "I'll buy "..itemName, @@ -250,8 +681,26 @@ local function TeamItemEventThink() end end end +local function PrintItemInfoTableOf(npcBot) + local tb = npcBot.itemInformationTable + print(npcBot:GetUnitName().." items to buy: ") + A.Linq.ForEach(tb, function(t, index) + if t.isSingleItem then + print(index..": "..t.name) + else + local s = "" + A.Linq.ForEach(t.recipe, function(t1, t1Index) + s = s..t1 + if t1Index ~= #t.recipe then + s = s..", " + end + end) + print(index..": "..t.name.." { "..s.." }") + end + end) +end local function AddMekansm() - local AddMekansmBefore = GenerateFilter(2000, { + local AddMekansmBefore = GeneratePutBeforeFilter(2000, { "glimmer_cape", "ghost", }, { @@ -261,7 +710,11 @@ local function AddMekansm() }) local function Rate(hero) local heroName = fun1:GetHeroShortName(hero:GetUnitName()) +<<<<<<< HEAD local rate = roles[heroName].mekansm + math.random(0, 1.5) +======= + local rate = roles[heroName].mekansm + math.random() * 1.5 +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a if hero:GetPrimaryAttribute() == ATTRIBUTE_INTELLECT and rate <= 7 then rate = rate + 1 end @@ -277,7 +730,11 @@ local function AddMekansm() end) local function BuyMekansm(hero) NotifyTeam(hero, "mekansm") +<<<<<<< HEAD AddBefore(hero.itemInformationTable, M.FullyExpandItem "item_mekansm", AddMekansmBefore) +======= + AddBefore(hero.itemInformationTable, M.ExpandTeamThinkItem "item_mekansm", AddMekansmBefore) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local guardianGreavesTable = M.ExpandFirstLevel "item_guardian_greaves" fun1:Remove_Modify(guardianGreavesTable.recipe, "item_mekansm") do @@ -286,18 +743,37 @@ local function AddMekansm() end) if arcaneBoots then arcaneBoots.usedAsRecipeOf = guardianGreavesTable +<<<<<<< HEAD fun1:Remove_Modify(guardianGreavesTable, "item_arcane_boots") +======= + fun1:Remove_Modify(guardianGreavesTable, function(t) + return t.name == "item_boots" or t.name == "item_energy_booster" + end) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end end while M.ExpandOnce(guardianGreavesTable) do end +<<<<<<< HEAD AddBefore(hero.itemInformationTable, guardianGreavesTable, GenerateFilter(4800, {}, {})) fun1:Remove_Modify(hero.itemInformationTable, "item_urn_of_shadows") fun1:Remove_Modify(hero.itemInformationTable, "item_spirit_vessel") +======= + AddBefore(hero.itemInformationTable, guardianGreavesTable, GeneratePutBeforeFilter(4800, {}, {})) + hero.itemInformationTable:Remove_Modify(function(t) + return t.name == "item_urn_of_shadows" + end) + hero.itemInformationTable:Remove_Modify(function(t) + return t.name == "item_spirit_vessel" + end) + PrintItemInfoTableOf(hero) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end if #heroRates >= 3 then - local hero = heroRates[1][1] - BuyMekansm(hero) + if heroRates[1][2] > 2.85 then + local hero = heroRates[1][1] + BuyMekansm(hero) + end elseif #heroRates == 2 then hero = heroRates[1] if hero[2] >= 5 then @@ -309,6 +785,104 @@ local function AddMekansm() end end end +<<<<<<< HEAD +======= +local function AddArcaneBoots() + local AddArcaneBootsBefore = GeneratePutBeforeFilter(1200, {}, {}) + local function Rate(hero) + local heroName = fun1:GetHeroShortName(hero:GetUnitName()) + local rate = roles[heroName].arcaneBoots + math.random() * 1.5 + return rate + end + local heroRates = fun1:Map(teamMembers, function(it) + return { + it, + Rate(it), + } + end):SortByMaxFirst(function(it) + return it[2] + end) + local function IsUpgradedBoots(itemTable) + return A.Item.IsBoots(itemTable.name) and itemTable.name ~= "item_boots" and not string.match(itemTable.name, "item_travel_boots") + end + local function RemoveItemsInNewItemTable(informationTable, newItemTable, newItemIndex) + informationTable[newItemIndex] = newItemTable + local function ShouldRemove(itemTable) + return A.Linq.Contains(newItemTable.recipe, itemTable.name) + end + informationTable:Take(newItemIndex - 1):Filter(ShouldRemove):ForEach(function(t) + t.usedAsRecipeOf = newItemTable + return A.Linq.Remove_Modify(newItemTable.recipe, t.name) + end) + end + local function BuyArcaneBoots(hero) + NotifyTeam(hero, "arcane boots") + local bootsToReplaceIndex = A.Linq.IndexOf(hero.itemInformationTable, IsUpgradedBoots) + if bootsToReplaceIndex ~= -1 then + local bootsToReplaceName = hero.itemInformationTable[bootsToReplaceIndex].name + if bootsToReplaceName == "item_arcane_boots" then + else + local arcaneBoots = M.ExpandTeamThinkItem "item_arcane_boots" + RemoveItemsInNewItemTable(hero.itemInformationTable, arcaneBoots, bootsToReplaceIndex) + end + else + AddBefore(hero.itemInformationTable, M.ExpandTeamThinkItem "item_arcane_boots", AddArcaneBootsBefore) + end + PrintItemInfoTableOf(hero) + end + local function DontBuyArcaneBoots(heroRateTable) + local hero = heroRateTable[1] + local arcaneBootsIndex = A.Linq.IndexOf(hero.itemInformationTable, function(t) + return t.name == "item_arcane_boots" + end) + if arcaneBootsIndex ~= -1 and not hero.itemInformationTable[arcaneBootsIndex].usedAsRecipeOf then + local rd = math.random() + local replaceBoots = (function() + if rd <= 0.666667 then + return "item_power_treads" + else + return "item_phase_boots" + end + end)() + if heroRateTable[2] >= 6.65 and rd <= 0.22 then + replaceBoots = "item_tranquil_boots" + end + NotifyTeam(hero, replaceBoots) + local newBoots = M.ExpandTeamThinkItem(replaceBoots) + RemoveItemsInNewItemTable(hero.itemInformationTable, newBoots, arcaneBootsIndex) + end + PrintItemInfoTableOf(hero) + end + local teamArcaneBootsNumber = (function() + if #heroRates >= 4 then + return 2 + elseif #heroRates >= 2 then + return 1 + else + return 0 + end + end)() + local buyArcaneBootsHeroIndex = 0 + if teamArcaneBootsNumber >= 1 then + local hero = heroRates[1][1] + BuyArcaneBoots(hero) + buyArcaneBootsHeroIndex = buyArcaneBootsHeroIndex + 1 + end + teamArcaneBootsNumber = teamArcaneBootsNumber - 1 + local function HighDesireOfBuyingArcaneBoots(heroRateTable) + return heroRateTable[2] >= 7.55 + end + if teamArcaneBootsNumber >= 1 then + heroRates:Skip(buyArcaneBootsHeroIndex):Take(teamArcaneBootsNumber):Filter(HighDesireOfBuyingArcaneBoots):Map(function(t) + return t[1] + end):ForEach(function(t) + BuyArcaneBoots(t) + buyArcaneBootsHeroIndex = buyArcaneBootsHeroIndex + 1 + end) + end + heroRates:Skip(buyArcaneBootsHeroIndex):FilterNot(HighDesireOfBuyingArcaneBoots):ForEach(DontBuyArcaneBoots) +end +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local function IdToEnemyStateTableIndex(id) return (function() if id <= 4 then @@ -377,7 +951,7 @@ local function GetOtherTeam() end local npcBot local hasInvisibleEnemy -local CheckInvisibleEnemy = function() +local function CheckInvisibleEnemy() return fun1:Any(GetTeamPlayers(GetOtherTeam()) or {}, function(t) local heroName = fun1:GetHeroShortName(GetSelectedHeroName(t)) return fun1.invisibilityHeroes[heroName] and fun1.invisibilityHeroes[heroName] == 1 @@ -408,9 +982,11 @@ local BuyDustIfInvisibleEnemies = fun1:EveryManySeconds(2, function() return t:GetName() end) if not items:Contains("item_gem") and not items:Contains("item_dust") then - if npcBot:GetGold() >= 2 * GetItemCost("item_dust") then - npcBot:ActionImmediate_PurchaseItem("item_dust") + if npcBot:GetGold() >= GetItemCost("item_dust") then npcBot:ActionImmediate_PurchaseItem("item_dust") + if DotaTime() >= 8 * 60 and npcBot:GetGold() >= GetItemCost("item_dust") * 2 then + npcBot:ActionImmediate_PurchaseItem("item_dust") + end npcBot:ActionImmediate_Chat("Buying dusts", false) end end @@ -483,6 +1059,7 @@ function M.TeamItemThink(npcBot) else runned = true end + AddArcaneBoots() AddMekansm() end end) diff --git a/util/TeamItemThink.mira b/util/TeamItemThink.mira index eacfe93f..6fdef009 100644 --- a/util/TeamItemThink.mira +++ b/util/TeamItemThink.mira @@ -1,8 +1,12 @@ local M = {} local ItemUsage = require(GetScriptDirectory().."/util/ItemUsage-New") +<<<<<<< HEAD +======= +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local fun1 = require(GetScriptDirectory().."/util/AbilityAbstraction") +local A = require(GetScriptDirectory().."/util/MiraDota") M.ImplmentedTeamItems = { "item_mekansm", @@ -10,6 +14,7 @@ M.ImplmentedTeamItems = { } local roles = { +<<<<<<< HEAD abaddon = {9,}, abyssal_underlord = {4,}, alchemist={0,}, @@ -113,14 +118,118 @@ local roles = { winter_wyvern={7,}, witch_doctor={6,}, zuus={3,}, +======= + abaddon = {9,6,}, + abyssal_underlord = {4,7,}, + alchemist={0,1,}, + ancient_apparition={2,9,}, + antimage={1,0,}, + arc_warden={0,2,}, + axe={2,2,}, + bane={3,7,}, + batrider={4,6,}, + beastmaster={0,2,}, + bloodseeker={1,1,}, + bounty_hunter={3,5,}, + brewmaster={0,1,}, + bristleback={4,7,}, + broodmother={5,1,}, + centaur={3,3,}, + chaos_knight={2,2,}, + chen={9,8,}, + clinkz={1,1,}, + crystal_maiden={8,3,}, + dark_seer={7,7,}, + dazzle={9,5,}, + death_prophet={5,6,}, + disruptor={6,3,}, + doom_bringer={1,2,}, + dragon_knight={0,1,}, + drow_ranger={0,0,}, + earth_spirit={6,5,}, + earthshaker={5,6,}, + ember_spirit={2,2,}, + enchantress={3,4,}, + enigma={8,6,}, + faceless_void={1,0,}, + furion={5,0,}, + gyrocopter={4,2,}, + hoodwink={5,4,}, + huskar={1,0,}, + jakiro={7,5,}, + juggernaut={0,0,}, + keeper_of_the_light={4,0,}, + kunkka={1,2,}, + legion_commander={1,0,}, + leshrac={4,6,}, + lich={5,8,}, + life_stealer={2,0,}, + lina={5,6,}, + lion={5,3,}, + luna={1,1,}, + lycan={4,0,}, + magnataur={0,5,}, + medusa={0,3,}, + mirana={1,5,}, + monkey_king={0,0,}, + naga_siren={3,2,}, + necrolyte={7,8,}, + nevermore={3,2,}, + night_stalker={2,0,}, + nyx_assassin={5,7,}, + obsidian_destroyer={4,0,}, + ogre_magi={4,7,}, + omniknight={8,7,}, + oracle={8,8,}, + phantom_assassin={1,0,}, + phantom_lancer={1,1,}, + pugna={5,8,}, + puck={4,5,}, + pudge={1,4,}, + queenofpain={3,3,}, + rattletrap={4,2,}, + razor={6,0,}, + riki={3,0,}, + sand_king={5,7,}, + shadow_demon={6,6,}, + shadow_shaman={8,8,}, + shredder={3,9,}, + silencer={6,3,}, + skeleton_king={1,0,}, + skywrath_mage={4,9,}, + slardar={2,1,}, + slark={1,0,}, + sniper={0,0,}, + spectre={4,0,}, + spirit_breaker={3,1,}, + sven={1,2,}, + templar_assassin={1,0,}, + terrorblade={1,0,}, + tidehunter={7,7,}, + tinker={0,5,}, + tiny={2,4,}, + treant={7,7,}, + troll_warlord={0,0,}, + tusk={4,2,}, + undying={6,8,}, + ursa={0,0,}, + vengefulspirit={5,6,}, + venomancer={7,5,}, + viper={6,1,}, + warlock={7,8,}, + weaver={2,1,}, + windrunner={4,6,}, + winter_wyvern={7,5,}, + witch_doctor={6,5,}, + zuus={3,9,}, +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a } -local function heroItemMetaFunc(tb, key) - if key == "mekansm" then - return tb[1] - end - return 0 -end +local function heroItemMetaFunc(tb, key) -> + if key == "mekansm" { tb[1] } + elif key == "arcaneBoots" { tb[2] } + else { 0 } + local heroItemMetatable = { __index = heroItemMetaFunc } @@ -164,19 +273,14 @@ local function TeamItemInit() dustBuyers = if #dustBuyers >= defaultDustBuyerNumber { dustBuyers:Take(defaultDustBuyerNumber) } else { dustBuyers } end -local function IsLeaf(item) - return next(GetItemComponents(item)) == nil -end -local function NextNodes(item) - return GetItemComponents(item)[1] -end -function M.ExpandFirstLevel(item) - if IsLeaf(item) then - return { name = item, isSingleItem = true } - else - return { name = item, recipe = NextNodes(item) } - end -end + +local function IsLeaf(item) -> next(GetItemComponents(item)) == nil +local function NextNodes(item) -> GetItemComponents(item)[1] + +function M.ExpandFirstLevel(item) -> + if IsLeaf(item) { { name = item, isSingleItem = true } } + else { { name = item, recipe = NextNodes(item) } } + function M.ExpandOnce(item) local g = {} local expandSomething = false @@ -198,31 +302,33 @@ function M.FullyExpandItem(itemName) while M.ExpandOnce(p) do end return p end - +function M.ExpandTeamThinkItem(itemName) + local p = M.FullyExpandItem(itemName) + p.origin = "TeamItemThink" + return p +end local function AddBefore(tb, item, before) for index, v in ipairs(tb) do - if not before(v) then + if before(v) then table.insert(tb, index, item) return end end - table.insert(tb, 1, item) + table.insert(tb, #tb + 1, item) end -local function GenerateFilter(maxCost, putBefore, putAfter) - return { itemInfo -> +local function GeneratePutBeforeFilter(maxCost, putBefore, putAfter) -> { itemInfo -> local itemName = itemInfo.name local shortName = string.sub(itemName, 6) if fun1:Contains(putAfter, shortName) { false } - else { fun1:Contains(putBefore, shortName) or GetItemCost(itemName) < maxCost } + else { fun1:Contains(putBefore, shortName) or GetItemCost(itemName) > maxCost } } -end local teamItemEvents = fun1:NewTable() local function NotifyTeam(npcBot, itemName) fun1:StartCoroutine { -> - fun1:WaitForSeconds(math.random(0, 4)) + fun1:WaitForSeconds(math.random(20, 28)) table.insert(teamItemEvents, { npcBot, "I'll buy "..itemName, false }) } end @@ -240,11 +346,33 @@ local function TeamItemEventThink() end end +local function PrintItemInfoTableOf(npcBot) + local tb = npcBot.itemInformationTable + print(npcBot:GetUnitName().." items to buy: ") + A.Linq.ForEach(tb) { t, index -> + if t.isSingleItem then print(index..": "..t.name) + else + local s = "" + A.Linq.ForEach(t.recipe) { t1, t1Index -> + s = s..t1 + if t1Index ~= #t.recipe then + s = s..", " + end + } + print(index..": "..t.name.." { "..s.." }") + end + } +end + local function AddMekansm() - local AddMekansmBefore = GenerateFilter(2000, { "glimmer_cape", "ghost" }, { "travel_boots", "hand_of_midas", "bfury" }) + local AddMekansmBefore = GeneratePutBeforeFilter(2000, { "glimmer_cape", "ghost" }, { "travel_boots", "hand_of_midas", "bfury" }) local function Rate(hero) local heroName = fun1:GetHeroShortName(hero:GetUnitName()) +<<<<<<< HEAD local rate = roles[heroName].mekansm + math.random(0, 1.5) +======= + local rate = roles[heroName].mekansm + math.random() * 1.5 +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a if hero:GetPrimaryAttribute() == ATTRIBUTE_INTELLECT and rate <= 7 then rate += 1 end @@ -253,26 +381,45 @@ local function AddMekansm() local heroRates = fun1:Map(teamMembers) { it -> { it, Rate(it) } }:SortByMaxFirst { it -> it[2] } + local function BuyMekansm(hero) NotifyTeam(hero, "mekansm") +<<<<<<< HEAD AddBefore(hero.itemInformationTable, M.FullyExpandItem "item_mekansm", AddMekansmBefore) +======= + AddBefore(hero.itemInformationTable, M.ExpandTeamThinkItem "item_mekansm", AddMekansmBefore) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local guardianGreavesTable = M.ExpandFirstLevel "item_guardian_greaves" fun1:Remove_Modify(guardianGreavesTable.recipe, "item_mekansm") if local arcaneBoots = fun1:First(hero.itemInformationTable) { t -> t.name == "item_arcane_boots" } then arcaneBoots.usedAsRecipeOf = guardianGreavesTable +<<<<<<< HEAD fun1:Remove_Modify(guardianGreavesTable, "item_arcane_boots") end while M.ExpandOnce(guardianGreavesTable) do end AddBefore(hero.itemInformationTable, guardianGreavesTable, GenerateFilter(4800, {}, {})) fun1:Remove_Modify(hero.itemInformationTable, "item_urn_of_shadows") fun1:Remove_Modify(hero.itemInformationTable, "item_spirit_vessel") +======= + fun1:Remove_Modify(guardianGreavesTable) { t -> + t.name == "item_boots" or t.name == "item_energy_booster" + } + end + while M.ExpandOnce(guardianGreavesTable) do end + AddBefore(hero.itemInformationTable, guardianGreavesTable, GeneratePutBeforeFilter(4800, {}, {})) + hero.itemInformationTable:Remove_Modify { t -> t.name == "item_urn_of_shadows" } + hero.itemInformationTable:Remove_Modify { t -> t.name == "item_spirit_vessel" } + PrintItemInfoTableOf(hero) +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a end if #heroRates >= 3 then - local hero = heroRates[1][1] - BuyMekansm(hero) + if heroRates[1][2] > 2.85 then + local hero = heroRates[1][1] + BuyMekansm(hero) + end elseif #heroRates == 2 then hero = heroRates[1] if hero[2] >= 5 then @@ -285,9 +432,102 @@ local function AddMekansm() end end +<<<<<<< HEAD local function IdToEnemyStateTableIndex(id) return if id <= 4 { id + 1 } else { id - 4 } end +======= +local function AddArcaneBoots() + local AddArcaneBootsBefore = GeneratePutBeforeFilter(1200, { }, { }) + local function Rate(hero) + local heroName = fun1:GetHeroShortName(hero:GetUnitName()) + local rate = roles[heroName].arcaneBoots + math.random() * 1.5 + return rate + end + local heroRates = fun1:Map(teamMembers) { it -> + { it, Rate(it) } + }:SortByMaxFirst { it -> it[2] } + + local function IsUpgradedBoots(itemTable) + return A.Item.IsBoots(itemTable.name) and itemTable.name ~= "item_boots" and not string.match(itemTable.name, "item_travel_boots") + end + + local function RemoveItemsInNewItemTable(informationTable, newItemTable, newItemIndex) + informationTable[newItemIndex] = newItemTable + local function ShouldRemove(itemTable) + return A.Linq.Contains(newItemTable.recipe, itemTable.name) + end + informationTable:Take(newItemIndex-1) + :Filter(ShouldRemove) + :ForEach { t -> + t.usedAsRecipeOf = newItemTable + A.Linq.Remove_Modify(newItemTable.recipe, t.name) + } + end + + local function BuyArcaneBoots(hero) + NotifyTeam(hero, "arcane boots") + local bootsToReplaceIndex = A.Linq.IndexOf(hero.itemInformationTable, IsUpgradedBoots) + if bootsToReplaceIndex ~= -1 then + local bootsToReplaceName = hero.itemInformationTable[bootsToReplaceIndex].name + if bootsToReplaceName == "item_arcane_boots" then + -- do nothing + else + local arcaneBoots = M.ExpandTeamThinkItem "item_arcane_boots" + RemoveItemsInNewItemTable(hero.itemInformationTable, arcaneBoots, bootsToReplaceIndex) + end + else + AddBefore(hero.itemInformationTable, M.ExpandTeamThinkItem "item_arcane_boots", AddArcaneBootsBefore) + end + PrintItemInfoTableOf(hero) + end + + local function DontBuyArcaneBoots(heroRateTable) + local hero = heroRateTable[1] + local arcaneBootsIndex = A.Linq.IndexOf(hero.itemInformationTable) { t -> t.name == "item_arcane_boots" } + if arcaneBootsIndex ~= -1 and not hero.itemInformationTable[arcaneBootsIndex].usedAsRecipeOf then + local rd = math.random() + local replaceBoots = if rd <= 0.666667 { "item_power_treads" } + else { "item_phase_boots" } + if heroRateTable[2] >= 6.65 and rd <= 0.22 then + replaceBoots = "item_tranquil_boots" + end + NotifyTeam(hero, replaceBoots) + local newBoots = M.ExpandTeamThinkItem(replaceBoots) + RemoveItemsInNewItemTable(hero.itemInformationTable, newBoots, arcaneBootsIndex) + end + PrintItemInfoTableOf(hero) + end + + local teamArcaneBootsNumber = + if #heroRates >= 4 { 2 } + elif #heroRates >= 2 { 1 } + else { 0 } + local buyArcaneBootsHeroIndex = 0 + if teamArcaneBootsNumber >= 1 then + local hero = heroRates[1][1] + BuyArcaneBoots(hero) + ++buyArcaneBootsHeroIndex + end + teamArcaneBootsNumber -= 1 + local function HighDesireOfBuyingArcaneBoots(heroRateTable) -> heroRateTable[2] >= 7.55 + if teamArcaneBootsNumber >= 1 then + heroRates:Skip(buyArcaneBootsHeroIndex) + :Take(teamArcaneBootsNumber) + :Filter(HighDesireOfBuyingArcaneBoots) + :Map { t -> t[1] } + :ForEach { t -> + BuyArcaneBoots(t) + ++buyArcaneBootsHeroIndex + } + end + heroRates:Skip(buyArcaneBootsHeroIndex) + :FilterNot(HighDesireOfBuyingArcaneBoots) + :ForEach(DontBuyArcaneBoots) +end + +local function IdToEnemyStateTableIndex(id) -> if id <= 4 { id + 1 } else { id - 4 } +>>>>>>> fb1118d0d0092b991ad855021d58837357d90b5a local RefreshEnemyRespawnTime = fun1:EveryManySeconds(1) { -> fun1:GroupBy(GetUnitList(UNIT_LIST_ENEMY_HEROES), { t -> t:GetPlayerID() }, { t -> t }, { k, v -> { k, v } }) @@ -306,20 +546,18 @@ local RefreshEnemyRespawnTime = fun1:EveryManySeconds(1) { -> } function M.GetEnemyRespawnTime(id) - return if id { + -> if id { enemyStates[IdToEnemyStateTableIndex(id)].respawnTime or 0 } else { enemyStates:Map { t -> t.respawnTime } } -end - + function M.EnemyReadyToFight(id) - return if id { + -> if id { (enemyStates[IdToEnemyStateTableIndex(id)].respawnTime or 0) <= 8 } else { enemyStates:Count { _, id -> M.EnemyReadyToFight(id) } } -end local function TeamStateThink() if not finishInit then @@ -338,7 +576,7 @@ end local npcBot local hasInvisibleEnemy -local CheckInvisibleEnemy = function() +local function CheckInvisibleEnemy() return fun1:Any(GetTeamPlayers(GetOtherTeam()) or {}) { t -> local heroName = fun1:GetHeroShortName(GetSelectedHeroName(t)) return fun1.invisibilityHeroes[heroName] and fun1.invisibilityHeroes[heroName] == 1 @@ -365,9 +603,11 @@ local BuyDustIfInvisibleEnemies = fun1:EveryManySeconds(2) { -> if dustBuyers:Take(defaultDustBuyerNumber - #nonDefaultGemPlayers):Contains(npcBot) and hasInvisibleEnemy then local items = fun1:GetAllBoughtItems(npcBot):Map { t -> t:GetName() } if not items:Contains("item_gem") and not items:Contains("item_dust") then - if npcBot:GetGold() >= 2*GetItemCost("item_dust") then - npcBot:ActionImmediate_PurchaseItem("item_dust") + if npcBot:GetGold() >= GetItemCost("item_dust") then npcBot:ActionImmediate_PurchaseItem("item_dust") + if DotaTime() >= 8 * 60 and npcBot:GetGold() >= GetItemCost("item_dust") * 2 then + npcBot:ActionImmediate_PurchaseItem("item_dust") + end npcBot:ActionImmediate_Chat("Buying dusts", false) end end @@ -440,6 +680,7 @@ function M.TeamItemThink(npcBot) else runned = true end + AddArcaneBoots() AddMekansm() end }