276 lines
7.4 KiB
Lua
Executable File
276 lines
7.4 KiB
Lua
Executable File
require( "ai/ai_core" )
|
|
|
|
|
|
function Precache( context )
|
|
|
|
PrecacheResource( "particle", "particles/neutral_fx/harpy_chain_lightning_head.vpcf", context )
|
|
PrecacheResource( "particle", "particles/units/heroes/hero_dark_seer/dark_seer_surge.vpcf", context )
|
|
PrecacheResource( "particle", "particles/neutral_fx/harpy_chain_lightning.vpcf", context )
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Spawn( entityKeyValues )
|
|
|
|
thisEntity.hSurgeAbility = thisEntity:FindAbilityByName( "tornado_harpy_intrinsic" )
|
|
thisEntity.PreviousHealthPct = thisEntity:GetHealthPercent()
|
|
thisEntity.PreviousHealthPctGameTime = GameRules:GetGameTime()
|
|
|
|
thisEntity:SetContextThink( "TornadoHarpyThink", TornadoHarpyThink, 0.5 )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function TornadoHarpyThink()
|
|
|
|
if not IsServer() then
|
|
return
|
|
end
|
|
|
|
if ( not thisEntity:IsAlive() ) then
|
|
return -1
|
|
end
|
|
|
|
if GameRules:IsGamePaused() == true then
|
|
return 0.5
|
|
end
|
|
|
|
--check our health pct every 4 seconds
|
|
if GameRules:GetGameTime() > thisEntity.PreviousHealthPctGameTime + 4 then
|
|
thisEntity.PreviousHealthPctGameTime = GameRules:GetGameTime()
|
|
thisEntity.PreviousHealthPct = thisEntity:GetHealthPercent()
|
|
end
|
|
local hEnemies = FindUnitsInRadius( thisEntity:GetTeamNumber(), thisEntity:GetOrigin(), nil, 5000, DOTA_UNIT_TARGET_TEAM_ENEMY, DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES, FIND_CLOSEST, false )
|
|
|
|
if #hEnemies > 0 then
|
|
for i = 1, #hEnemies do
|
|
thisEntity.avoidTarget = hEnemies[i]
|
|
if thisEntity.avoidTarget ~= nil then
|
|
if thisEntity:GetHealthPercent() < thisEntity.PreviousHealthPct then
|
|
return Retreat(thisEntity.avoidTarget )
|
|
else
|
|
ExecuteOrderFromTable({
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_ATTACK_TARGET,
|
|
TargetIndex = thisEntity.avoidTarget:entindex(),
|
|
Queue = false
|
|
})
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
return 0.5
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function Retreat(unit)
|
|
|
|
local vAwayFromEnemy = thisEntity:GetOrigin() - unit:GetOrigin()
|
|
vAwayFromEnemy = vAwayFromEnemy:Normalized()
|
|
local vMoveToPos = thisEntity:GetOrigin() + vAwayFromEnemy * thisEntity:GetIdealSpeed()*4
|
|
|
|
-- if away from enemy is an unpathable area, find a new direction to run to
|
|
local nAttempts = 0
|
|
while ( ( not GridNav:CanFindPath( thisEntity:GetOrigin(), vMoveToPos ) ) and ( nAttempts < 5 ) ) do
|
|
vMoveToPos = thisEntity:GetOrigin() + RandomVector( thisEntity:GetIdealSpeed() * 4 )
|
|
nAttempts = nAttempts + 1
|
|
end
|
|
|
|
thisEntity.fTimeOfLastRetreat = GameRules:GetGameTime()
|
|
|
|
thisEntity:AddNewModifier(thisEntity, thisEntity.hSurgeAbility, "modifier_tornado_harpy_surge", {duration = 2.0})
|
|
|
|
ExecuteOrderFromTable({
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
|
|
Position = vMoveToPos,
|
|
})
|
|
|
|
return 2.5
|
|
end
|
|
|
|
--[[
|
|
|
|
--------------------------------------------------------------------------------------------------------
|
|
|
|
BehaviorNone = {}
|
|
|
|
function BehaviorNone:Evaluate()
|
|
return 1 -- must return a value > 0, so we have a default
|
|
end
|
|
|
|
function BehaviorNone:Begin()
|
|
-- print( "BehaviorNone:Begin()" )
|
|
local orders = nil
|
|
local hTarget = AICore:ClosestEnemyHeroInRange( thisEntity, thisEntity:GetDayTimeVisionRange() )
|
|
|
|
if hTarget ~= nil then
|
|
thisEntity.lastTargetPosition = hTarget:GetAbsOrigin()
|
|
for i=1,6 do
|
|
local vLoc = FindPathablePositionNearby(hTarget:GetAbsOrigin(), 650, 650 )
|
|
--and thisEntity:IsMoving() == false
|
|
if GameRules.Aghanim:GetCurrentRoom():IsInRoomBounds( vLoc ) then
|
|
--orders =
|
|
--{
|
|
-- UnitIndex = thisEntity:entindex(),
|
|
-- OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
|
|
-- Position = vLoc,
|
|
-- Queue = true,
|
|
--}
|
|
break
|
|
end
|
|
end
|
|
elseif thisEntity.lastTargetPosition ~= nil then
|
|
for i=1,6 do
|
|
local vLoc = FindPathablePositionNearby(thisEntity.lastTargetPosition, 650, 650 )
|
|
|
|
if GameRules.Aghanim:GetCurrentRoom():IsInRoomBounds( vLoc ) then
|
|
--orders =
|
|
--{
|
|
-- UnitIndex = thisEntity:entindex(),
|
|
-- OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
|
|
-- Position = vLoc
|
|
--}
|
|
break
|
|
end
|
|
end
|
|
else
|
|
orders =
|
|
{
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_STOP
|
|
}
|
|
end
|
|
|
|
return orders
|
|
end
|
|
|
|
BehaviorNone.Continue = BehaviorNone.Begin
|
|
|
|
--------------------------------------------------------------------------------------------------------
|
|
|
|
BehaviorAttack = {}
|
|
|
|
function BehaviorAttack:Evaluate()
|
|
|
|
local desire = 6
|
|
|
|
-- let's not choose this twice in a row
|
|
if behaviorSystem.currentBehavior == self then
|
|
return desire
|
|
end
|
|
|
|
self.chainLightningAbility = thisEntity:FindAbilityByName( "harpy_storm_chain_lightning" )
|
|
|
|
if self.chainLightningAbility and self.chainLightningAbility:IsFullyCastable() then
|
|
|
|
self.target = AICore:ClosestEnemyHeroInRange( thisEntity, thisEntity:GetDayTimeVisionRange() )
|
|
if self.target ~= nil and self.target:IsAlive() then
|
|
desire = 6
|
|
end
|
|
end
|
|
|
|
return desire
|
|
end
|
|
|
|
function BehaviorAttack:Begin()
|
|
-- print( "BehaviorAttack:Begin()" )
|
|
|
|
--if self.chainLightningAbility and self.chainLightningAbility:IsFullyCastable() then
|
|
if self.target and self.target:IsAlive() then
|
|
--print( "Casting Chain Lightning" )
|
|
local targetPoint = self.target:GetAbsOrigin() + RandomVector( 100 )
|
|
thisEntity.lastTargetPosition = self.target:GetAbsOrigin()
|
|
ExecuteOrderFromTable({
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_ATTACK_TARGET,
|
|
--AbilityIndex = self.chainLightningAbility:entindex(),
|
|
TargetIndex = self.target:entindex(),
|
|
Queue = false
|
|
})
|
|
end
|
|
--end
|
|
|
|
return nil
|
|
end
|
|
|
|
BehaviorAttack.Continue = BehaviorAttack.Begin
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------
|
|
|
|
BehaviorAvoid = {}
|
|
|
|
function BehaviorAvoid:Evaluate()
|
|
|
|
local desire = 0
|
|
|
|
-- let's not choose this twice in a row
|
|
if behaviorSystem.currentBehavior == self then
|
|
return desire
|
|
end
|
|
--don't even think about running if you can damage!
|
|
if self.chainLightningAbility and self.chainLightningAbility:IsFullyCastable() then
|
|
return desire
|
|
end
|
|
|
|
--check our health pct every 5 seconds
|
|
if GameRules:GetGameTime() > thisEntity.PreviousHealthPctGameTime + 5 then
|
|
printf("reseting healthpct")
|
|
thisEntity.PreviousHealthPctGameTime = GameRules:GetGameTime()
|
|
thisEntity.PreviousHealthPct = thisEntity:GetHealthPercent()
|
|
end
|
|
|
|
self.avoidTarget = AICore:ClosestEnemyHeroInRange( thisEntity, 650 )
|
|
if self.avoidTarget ~= nil then
|
|
desire = 4
|
|
end
|
|
|
|
if thisEntity:GetHealthPercent() < thisEntity.PreviousHealthPct then
|
|
printf("I'm hurt")
|
|
desire = 8
|
|
end
|
|
|
|
return desire
|
|
end
|
|
|
|
function BehaviorAvoid:Begin()
|
|
print( "BehaviorAvoid:Begin()" )
|
|
|
|
for i=1,6 do
|
|
self.vEscapeLoc = FindPathablePositionNearby(thisEntity:GetAbsOrigin(), 350, 350 )
|
|
|
|
if GameRules.Aghanim:GetCurrentRoom():IsInRoomBounds( self.vEscapeLoc ) and ( self.vEscapeLoc - self.avoidTarget:GetAbsOrigin() ):Length2D() > 650 then
|
|
ExecuteOrderFromTable({
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
|
|
Position = self.vEscapeLoc
|
|
})
|
|
printf("function BehaviorAvoid: Executing order()")
|
|
break
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
|
|
function BehaviorAvoid:Think(dt)
|
|
|
|
-- keep moving towards our escape point
|
|
ExecuteOrderFromTable({
|
|
UnitIndex = thisEntity:entindex(),
|
|
OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
|
|
Position = self.vEscapeLoc
|
|
})
|
|
return nil
|
|
end
|
|
|
|
|
|
BehaviorAvoid.Continue = BehaviorAvoid.Begin ]]-- |