-------------------------------------------------------------------------------- function GetEnemyHeroesInRange( hUnit , flRange ) if flRange == nil then flRange = 1250 end local enemies = FindUnitsInRadius( hUnit:GetTeamNumber(), hUnit:GetAbsOrigin(), nil, flRange, DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, FIND_CLOSEST, false ) return enemies end -------------------------------------------------------------------------------- function GetVisibleEnemyHeroesInRange( hUnit , flRange ) if flRange == nil then flRange = 1250 end local enemies = FindUnitsInRadius( hUnit:GetTeamNumber(), hUnit:GetAbsOrigin(), nil, flRange, DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_FLAG_NO_INVIS + DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, FIND_CLOSEST, false ) return enemies end -------------------------------------------------------------------------------- function GetNoteworthyVisibleEnemiesNearby( hUnit, flRange ) if flRange == nil then flRange = 1250 end local eTARGETED_UNITS = DOTA_UNIT_TARGET_CREEP + DOTA_UNIT_TARGET_BASIC + DOTA_UNIT_TARGET_HERO local enemies = FindUnitsInRadius( hUnit:GetTeamNumber(), hUnit:GetAbsOrigin(), nil, flRange, DOTA_UNIT_TARGET_TEAM_ENEMY, eTARGETED_UNITS, DOTA_UNIT_TARGET_FLAG_NO_INVIS + DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, FIND_CLOSEST, false ) for index, hEnemy in pairs( enemies ) do if hEnemy:IsRealHero() == false and hEnemy:IsConsideredHero() == false and hEnemy:IsIllusion() == false then -- Remove the most unimportant units table.remove( enemies, index ) end end return enemies end -------------------------------------------------------------------------------- function FilterEntitiesOutsideOfRange( vPosition, hEntitiesTable, flRange ) if hEntitiesTable == nil or #hEntitiesTable == 0 then return {} end for n=#hEntitiesTable,1,-1 do local hEntity = hEntitiesTable[ n ] if hEntity ~= nil then local fDist = ( hEntity:GetOrigin() - vPosition ):Length2D() if fDist > flRange then table.remove( hEntitiesTable, n ) end end end return hEntitiesTable end -------------------------------------------------------------------------------- -- General Utility Fucntions -- -------------------------------------------------------------------------------- function AdvancedRandomVector( MaxLength, MinLength, vAwayFromVec, vAwayFromDist ) local vCandidate = nil repeat vCandidate = RandomVector(1):Normalized()*RandomFloat(MinLength,MaxLength) until (vAwayFromVec == nil or vAwayFromDist == nil) or ( (vAwayFromVec - vCandidate):Length2D() > vAwayFromDist ) return vCandidate end function MoveOrder( hUnit, vPos ) ExecuteOrderFromTable({ UnitIndex = hUnit:entindex(), OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION, Position = vPos, }) return 1.0 end function StopOrder( hUnit ) ExecuteOrderFromTable({ UnitIndex = hUnit:entindex(), OrderType = DOTA_UNIT_ORDER_STOP, }) end -------------------------------------------------------------------------------- function AttackMoveOrder( hAttacker, hEnemy ) if (not hAttacker or not hEnemy or not hAttacker:HasAttackCapability() ) then return 0.25 end ExecuteOrderFromTable({ UnitIndex = hAttacker:entindex(), OrderType = DOTA_UNIT_ORDER_ATTACK_MOVE, Position = hEnemy:GetOrigin(), }) return 1.0 end -------------------------------------------------------------------------------- function AttackTargetOrder( hAttacker, hEnemy ) if ( not hAttacker or not hEnemy or not hAttacker:HasAttackCapability() ) then return 0.25 end --printf( "AttackTargetOrder -- attacker: %s, target: %s", hAttacker:GetUnitName(), hEnemy:GetUnitName() ) ExecuteOrderFromTable({ UnitIndex = hAttacker:entindex(), OrderType = DOTA_UNIT_ORDER_ATTACK_TARGET, TargetIndex = hEnemy:entindex(), }) return 1.0 end -------------------------------------------------------------------------------- function SprintIsReady( hCaster ) local hAbility = hCaster.abilities.hSprint if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastSprint( hCaster ) local hAbility = hCaster.abilities.hSprint ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 5.0 end -------------------------------------------------------------------------------- function TailIsReady( hCaster ) local hAbility = hCaster.abilities.hTailSpinCCW if hCaster.bEnemiesInFront and hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastTailSpinCCW( hCaster ) local hAbility = hCaster.abilities.hTailSpinCCW ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex() }) return 5.0 end -------------------------------------------------------------------------------- function MindControlIsReady( hCaster, hEnemies ) local nEnemiesAlive = 0 for _, hEnemy in pairs( hEnemies ) do if hEnemy:IsAlive() then nEnemiesAlive = nEnemiesAlive + 1 end end if nEnemiesAlive <= 1 then return false end local hAbility = hCaster.abilities.hMindControl if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastMindControl( hCaster, hEnemies ) local hAbility = hCaster.abilities.hMindControl local hTarget = hEnemies[ RandomInt( 1, #hEnemies ) ] ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_TARGET, TargetIndex = hTarget:entindex(), AbilityIndex = hAbility:entindex(), Queue = false, }) return 4.0 end -------------------------------------------------------------------------------- function TorrentsIsReady( hCaster ) local hAbility = hCaster.abilities.hTorrents if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastTorrents( hCaster ) local hAbility = hCaster.abilities.hTorrents ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 10 end -------------------------------------------------------------------------------- function LineWaveIsReady( hCaster ) local hAbility = hCaster.abilities.hLineWave if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastLineWave( hCaster, hEnemies ) local hAbility = hCaster.abilities.hLineWave local hTarget = hEnemies[ RandomInt( 1, #hEnemies ) ] local fDist = -1 local fHighestDist = 0 local hFarthestEnemy = nil for _, hEnemy in pairs( hEnemies ) do fDist = ( hEnemy:GetOrigin() - hCaster:GetOrigin() ):Length2D() if fDist > fHighestDist then fHighestDist = fDist hFarthestEnemy = hEnemy end end if hFarthestEnemy == nil then return 0.5 end ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_TARGET, TargetIndex = hFarthestEnemy:entindex(), AbilityIndex = hAbility:entindex(), Queue = false, }) return 4 end -------------------------------------------------------------------------------- function WavesIsReady( hCaster ) local hAbility = hCaster.abilities.hWaves if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastWaves( hCaster ) local hAbility = hCaster.abilities.hWaves ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 14 end -------------------------------------------------------------------------------- function SummonMinionsIsReady( hCaster ) local hAbility = hCaster.abilities.hSummonMinions if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastSummonMinions( hCaster ) local hAbility = hCaster.abilities.hSummonMinions ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 7 end -------------------------------------------------------------------------------- function SummonMinionsMediumIsReady( hCaster ) local hAbility = hCaster.abilities.hSummonMinionsMedium if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastSummonMinionsMedium( hCaster ) local hAbility = hCaster.abilities.hSummonMinionsMedium ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 7 end -------------------------------------------------------------------------------- function SummonCloneIsReady( hCaster ) local hAbility = hCaster.abilities.hSummonClone if hAbility ~= nil and hAbility:IsFullyCastable() and hCaster.nSummonCloneCasts < ( hCaster.Phase - 1 ) then return true end return false end -------------------------------------------------------------------------------- function CastSummonClone( hCaster ) local hAbility = hCaster.abilities.hSummonClone ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex(), Queue = false, }) return 2 end -------------------------------------------------------------------------------- function MouthBeamIsReady( hCaster ) local hAbility = hCaster.abilities.hMouthBeam if hAbility ~= nil and hAbility:IsFullyCastable() then return true end return false end -------------------------------------------------------------------------------- function CastMouthBeam( hCaster, hEnemies ) local hAbility = hCaster.abilities.hMouthBeam local hTarget = hEnemies[ RandomInt( 1, #hEnemies ) ] if hTarget == nil then return 1 end ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_POSITION, Position = hTarget:GetOrigin(), AbilityIndex = hAbility:entindex(), Queue = false, }) return 10.0 end -------------------------------------------------------------------------------- function FindItemAbility( hCaster, szItemName ) for i = 0, 5 do local item = hCaster:GetItemInSlot( i ) if item then if item:GetAbilityName() == szItemName then return item end end end end -------------------------------------------------------------------------------- function CastTargetedItem( hUnit, hTarget, szItemName ) local hItem = hUnit:FindItemInInventory( szItemName ) return CastTargetedAbility( hUnit, hTarget, hItem ) end -------------------------------------------------------------------------------- function CastUntargetedItem( hUnit, szItemName ) local hItem = hUnit:FindItemInInventory( szItemName ) return CastUntargetedAbility( hUnit, hItem ) end -------------------------------------------------------------------------------- function CastPositionalItem( hUnit, vPosition, szItemName ) local hItem = hUnit:FindItemInInventory( szItemName ) return CastPositionalAbility( hUnit, vPosition, hItem ) end -------------------------------------------------------------------------------- function CastTargetedAbility( hUnit, hTarget, hAbility ) if type(hAbility) == "string" then hAbility = hUnit:FindAbilityByName(hAbility) printf("result of string ability is %s", hAbility:GetName()) end if hAbility and hAbility:IsFullyCastable() then --printf( "%s casting %s on %s", hUnit:GetName(), hAbility:GetName(), hTarget:GetName() ) ExecuteOrderFromTable({ UnitIndex = hUnit:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_TARGET, TargetIndex = hTarget:entindex(), AbilityIndex = hAbility:entindex() }) return true end return false end -------------------------------------------------------------------------------- function CastPositionalAbility( hUnit, vPosition, hAbility ) if type(hAbility) == "string" then hAbility = hUnit:FindAbilityByName(hAbility) end if hAbility and hAbility:IsFullyCastable() then ExecuteOrderFromTable({ UnitIndex = hUnit:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_POSITION, Position = vPosition, AbilityIndex = hAbility:entindex() }) return true end return false end -------------------------------------------------------------------------------- function CastUntargetedAbility( hUnit, hAbility ) if type(hAbility) == "string" then hAbility = hUnit:FindAbilityByName(hAbility) end if hAbility and hAbility:IsFullyCastable() then ExecuteOrderFromTable({ UnitIndex = hUnit:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET, AbilityIndex = hAbility:entindex() }) return true end return false end -------------------------------------------------------------------------------- function GetAlliesInRange( hCaster, flRange ) return FindUnitsInRadius( hCaster:GetTeamNumber(), hCaster:GetOrigin(), nil, flRange, DOTA_UNIT_TARGET_TEAM_FRIENDLY, DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_BASIC + DOTA_UNIT_TARGET_OTHER, DOTA_UNIT_TARGET_FLAG_NO_INVIS + DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, FIND_CLOSEST, false ) end function LastAllyCastTime( hCaster, hAbility, flRange, hTarget ) if flRange == nil then flRange = 1000 end local flLastCastTime = -999999 local hAllies = GetAlliesInRange( hCaster, flRange ) for index,hAlly in pairs(hAllies) do local flAllyTime = hAlly["last_cast_time_"..hAbility:GetName()] local hAllyTarget = hAlly["last_cast_target_"..hAbility:GetName()] if flAllyTime ~= nil and (hTarget == nil or hTarget == hAllyTarget) then flLastCastTime = math.max(flAllyTime,flLastCastTime) end end return flLastCastTime end -------------------------------------------------------------------------------- function UpdateLastCastTime( hCaster, hAbility, hTarget ) hCaster["last_cast_time_"..hAbility:GetName()] = GameRules:GetGameTime() hCaster["last_cast_target_"..hAbility:GetName()] = hTarget end -------------------------------------------------------------------------------- function TeleportIsReady( hCaster ) if ( GameRules:GetGameTime() > ( hCaster.fLastTeleportChain + hCaster.nTeleportChainCD ) ) then hCaster.nRecentTeleportsCast = 0 hCaster.fLastTeleportChain = GameRules:GetGameTime() end local hAbility = hCaster.abilities.hTeleport if hAbility ~= nil and hAbility:IsFullyCastable() and ( hCaster.nRecentTeleportsCast < hCaster.nTeleportsToChain ) then return true end return false end -------------------------------------------------------------------------------- function CastTeleport( hCaster, hEnemies ) local hAbility = hCaster.abilities.hTeleport local hFilteredEnemies = {} for _, hEnemy in pairs( hEnemies ) do local fDist = ( hEnemy:GetOrigin() - hCaster:GetOrigin() ):Length2D() if fDist > 500 then table.insert( hFilteredEnemies, hEnemy ) end end local hTarget = nil if #hFilteredEnemies > 0 then hTarget = hFilteredEnemies[ RandomInt( 1, #hFilteredEnemies ) ] else hTarget = hEnemies[ RandomInt( 1, #hEnemies ) ] end local vTargetPos = hTarget:GetOrigin() ExecuteOrderFromTable({ UnitIndex = hCaster:entindex(), OrderType = DOTA_UNIT_ORDER_CAST_POSITION, Position = vTargetPos, AbilityIndex = hAbility:entindex(), Queue = false, }) hCaster.nRecentTeleportsCast = hCaster.nRecentTeleportsCast + 1 if ( hCaster.nRecentTeleportsCast >= hCaster.nTeleportsToChain ) then return 4.0 end return 1.8 end -------------------------------------------------------------------------------- --------------------------------------------------------------------------------