initial commit
This commit is contained in:
444
aghanim_singleplayer/scripts/vscripts/ai/boss_aghanim.lua
Executable file
444
aghanim_singleplayer/scripts/vscripts/ai/boss_aghanim.lua
Executable file
@@ -0,0 +1,444 @@
|
||||
require( "ai/boss_base" )
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
if CBossAghanim == nil then
|
||||
CBossAghanim = class( {}, {}, CBossBase )
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function Precache( context )
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function Spawn( entityKeyValues )
|
||||
if IsServer() then
|
||||
if thisEntity == nil then
|
||||
return
|
||||
end
|
||||
|
||||
thisEntity.AI = CBossAghanim( thisEntity, 1.0 )
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:constructor( hUnit, flInterval )
|
||||
CBossBase.constructor( self, hUnit, flInterval )
|
||||
|
||||
self.bDefeated = false
|
||||
|
||||
self.ATTACKS_BETWEEN_TELEPORT = 3
|
||||
self.ENRAGE_LESS_ATTACKS_BETWEEN_TELEPORT = 1
|
||||
self.nCurrentAttacksBetweenTeleport = self.ATTACKS_BETWEEN_TELEPORT
|
||||
|
||||
self.PHASE_CRYSTAL_ATTACK = 1
|
||||
self.PHASE_STAFF_BEAMS = 2
|
||||
self.PHASE_SUMMON_PORTALS = 3
|
||||
self.PHASE_SPELL_SWAP = 4
|
||||
self.PHASE_SHARD_ATTACK = 5
|
||||
|
||||
self.nSpellSwapPct = 80
|
||||
self.bSpellSwapEnabled = false
|
||||
self.nShardAttackPct = 50
|
||||
self.bShardAttackEnabled = false
|
||||
self.nLevelUpPct = 66
|
||||
self.bHasLeveledUp = false
|
||||
|
||||
self.AllowedPhases =
|
||||
{
|
||||
self.PHASE_CRYSTAL_ATTACK,
|
||||
self.PHASE_SUMMON_PORTALS,
|
||||
self.PHASE_STAFF_BEAMS,
|
||||
}
|
||||
|
||||
self.flInitialAcquireRange = 5000
|
||||
self.flAggroAcquireRange = 5000
|
||||
self.nPhaseIndex = 1
|
||||
self.nNumAttacksBeforeTeleport = self.nCurrentAttacksBetweenTeleport
|
||||
self.bReturnHome = true
|
||||
self.vLastBlinkLocation = Vector( -3328, 3264, 0 )
|
||||
|
||||
self.me:SetThink( "OnBossAghanimThink", self, "OnBossAghanimThink", self.flDefaultInterval )
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:GetCurrentPhase()
|
||||
return self.AllowedPhases[ self.nPhaseIndex ]
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function CBossAghanim:SetEncounter( hEncounter )
|
||||
CBossBase.SetEncounter( self, hEncounter )
|
||||
|
||||
self.TeleportPositions = {}
|
||||
|
||||
local TeleportPositions = hEncounter:GetRoom():FindAllEntitiesInRoomByName( "teleport_position" )
|
||||
for _,hEnt in pairs ( TeleportPositions ) do
|
||||
table.insert( self.TeleportPositions, hEnt:GetAbsOrigin() )
|
||||
end
|
||||
|
||||
local TeleportPositionMain = hEncounter:GetRoom():FindAllEntitiesInRoomByName( "teleport_position_main" )
|
||||
if #TeleportPositionMain > 0 then
|
||||
self.TeleportPositionMain = TeleportPositionMain[1]
|
||||
self.me.vHomePosition = self.TeleportPositionMain:GetAbsOrigin()
|
||||
|
||||
table.insert( self.TeleportPositions, self.me.vHomePosition )
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:SetupAbilitiesAndItems()
|
||||
CBossBase.SetupAbilitiesAndItems( self )
|
||||
|
||||
self.hBlink = self.me:FindAbilityByName( "aghanim_blink" )
|
||||
if self.hBlink ~= nil then
|
||||
self.hBlink.Evaluate = self.EvaluateBlink
|
||||
self.AbilityPriority[ self.hBlink:GetAbilityName() ] = 5
|
||||
end
|
||||
|
||||
self.hCrystalAttack = self.me:FindAbilityByName( "aghanim_crystal_attack" )
|
||||
if self.hCrystalAttack ~= nil then
|
||||
self.hCrystalAttack.nCrystalAttackPhase = 1
|
||||
self.hCrystalAttack.hLastCrystalTarget = nil
|
||||
self.hCrystalAttack.Evaluate = self.EvaluateCrystalAttack
|
||||
self.AbilityPriority[ self.hCrystalAttack:GetAbilityName() ] = 4
|
||||
end
|
||||
|
||||
self.hStaffBeams = self.me:FindAbilityByName( "aghanim_staff_beams" )
|
||||
if self.hStaffBeams ~= nil then
|
||||
self.hStaffBeams.Evaluate = self.EvaluateStaffBeams
|
||||
self.AbilityPriority[ self.hStaffBeams:GetAbilityName() ] = 3
|
||||
end
|
||||
|
||||
self.hSummonPortals = self.me:FindAbilityByName( "aghanim_summon_portals" )
|
||||
if self.hSummonPortals ~= nil then
|
||||
self.hSummonPortals.Evaluate = self.EvaluateSummonPortals
|
||||
self.AbilityPriority[ self.hSummonPortals:GetAbilityName() ] = 2
|
||||
end
|
||||
|
||||
self.hSpellSwap = self.me:FindAbilityByName( "aghanim_spell_swap" )
|
||||
if self.hSpellSwap ~= nil then
|
||||
self.hSpellSwap.Evaluate = self.EvaluateSpellSwap
|
||||
self.AbilityPriority[ self.hSpellSwap:GetAbilityName() ] = 1
|
||||
end
|
||||
|
||||
self.hShardAttack = self.me:FindAbilityByName( "aghanim_shard_attack" )
|
||||
if self.hShardAttack ~= nil then
|
||||
self.hShardAttack.Evaluate = self.EvaluateShardAttack
|
||||
self.AbilityPriority[ self.hShardAttack:GetAbilityName() ] = 1
|
||||
end
|
||||
end
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:OnBossAghanimThink()
|
||||
if self.bDefeated then
|
||||
return -1
|
||||
end
|
||||
|
||||
return self:OnBaseThink()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:OnFirstSeen()
|
||||
CBossBase.OnFirstSeen( self )
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:ChangePhase()
|
||||
self.nNumAttacksBeforeTeleport = self.nNumAttacksBeforeTeleport - 1
|
||||
--print ( "Aghanim is changing phase! old:" .. self:GetCurrentPhase() )
|
||||
if self.nPhaseIndex == #self.AllowedPhases then
|
||||
self.nPhaseIndex = 1
|
||||
else
|
||||
self.nPhaseIndex = self.nPhaseIndex + 1
|
||||
end
|
||||
|
||||
self.nPhase = self.AllowedPhases[ self.nPhaseIndex ]
|
||||
if self.nPhase == self.PHASE_SHARD_ATTACK then
|
||||
self.nNumAttacksBeforeTeleport = 0
|
||||
self.bReturnHome = true
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:OnHealthPercentThreshold( nPct )
|
||||
CBossBase.OnHealthPercentThreshold( self, nPct )
|
||||
|
||||
if nPct < self.nSpellSwapPct and self.bSpellSwapEnabled == false then
|
||||
self.nCurrentAttacksBetweenTeleport = math.max( 1, self.nCurrentAttacksBetweenTeleport - self.ENRAGE_LESS_ATTACKS_BETWEEN_TELEPORT )
|
||||
self.bSpellSwapEnabled = true
|
||||
self.AllowedPhases =
|
||||
{
|
||||
self.PHASE_SPELL_SWAP,
|
||||
self.PHASE_SUMMON_PORTALS,
|
||||
self.PHASE_STAFF_BEAMS,
|
||||
self.PHASE_CRYSTAL_ATTACK,
|
||||
}
|
||||
|
||||
self.nPhaseIndex = #self.AllowedPhases
|
||||
self:ChangePhase()
|
||||
|
||||
self.nNumAttacksBeforeTeleport = 0
|
||||
self.bReturnHome = true
|
||||
end
|
||||
|
||||
if nPct < self.nLevelUpPct and self.bHasLeveledUp == false then
|
||||
self.bHasLeveledUp = true
|
||||
self.me:CreatureLevelUp( 1 )
|
||||
end
|
||||
|
||||
|
||||
if nPct < self.nShardAttackPct and self.bShardAttackEnabled == false then
|
||||
self.nCurrentAttacksBetweenTeleport = math.max( 1, self.nCurrentAttacksBetweenTeleport - self.ENRAGE_LESS_ATTACKS_BETWEEN_TELEPORT )
|
||||
self.bShardAttackEnabled = true
|
||||
self.AllowedPhases =
|
||||
{
|
||||
self.PHASE_SHARD_ATTACK,
|
||||
self.PHASE_STAFF_BEAMS,
|
||||
self.PHASE_CRYSTAL_ATTACK,
|
||||
self.PHASE_SPELL_SWAP,
|
||||
self.PHASE_SUMMON_PORTALS,
|
||||
}
|
||||
|
||||
self.nPhaseIndex = #self.AllowedPhases
|
||||
self:ChangePhase()
|
||||
|
||||
self.nNumAttacksBeforeTeleport = 0
|
||||
self.bReturnHome = true
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateCrystalAttack()
|
||||
if self:GetCurrentPhase() ~= self.PHASE_CRYSTAL_ATTACK then
|
||||
return nil
|
||||
end
|
||||
|
||||
local Enemies = shallowcopy( self.hPlayerHeroes )
|
||||
local Order = nil
|
||||
if Enemies == nil or #Enemies == 0 then
|
||||
return Order
|
||||
end
|
||||
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = Enemies[ #Enemies ]:GetAbsOrigin(),
|
||||
AbilityIndex = self.hCrystalAttack:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = GetSpellCastTime( self.hCrystalAttack )
|
||||
self.hCrystalAttack.hLastCrystalTarget = Enemies[#Enemies]
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateStaffBeams()
|
||||
if self:GetCurrentPhase() ~= self.PHASE_STAFF_BEAMS then
|
||||
return nil
|
||||
end
|
||||
|
||||
local vTargetPos = self.me.vHomePosition
|
||||
if vTargetPos == self.vLastBlinkLocation then
|
||||
local hEnemies = GetEnemyHeroesInRange( self.me, 5000 )
|
||||
if #hEnemies > 0 then
|
||||
vTargetPos = hEnemies[#hEnemies]:GetAbsOrigin()
|
||||
end
|
||||
end
|
||||
|
||||
local Order = nil
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = vTargetPos,
|
||||
AbilityIndex = self.hStaffBeams:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = GetSpellCastTime( self.hStaffBeams ) + self.hStaffBeams:GetChannelTime()
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateBlink()
|
||||
if self.nNumAttacksBeforeTeleport > 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if self.bReturnHome == true and self.vLastBlinkLocation == self.me.vHomePosition then
|
||||
self.nNumAttacksBeforeTeleport = self.nCurrentAttacksBetweenTeleport
|
||||
self.bReturnHome = false
|
||||
return nil
|
||||
end
|
||||
|
||||
local vTeleportLocations = shallowcopy( self.TeleportPositions )
|
||||
for k,v in pairs ( vTeleportLocations ) do
|
||||
if v == self.vLastBlinkLocation then
|
||||
table.remove( vTeleportLocations, k )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local vPos = nil
|
||||
if self.bReturnHome == true then
|
||||
vPos = self.me.vHomePosition
|
||||
else
|
||||
if self:GetCurrentPhase() == self.PHASE_SUMMON_PORTALS then
|
||||
local hEnemies = GetEnemyHeroesInRange( self.me, 5000 )
|
||||
if #hEnemies > 0 then
|
||||
local vFarthestEnemyPos = hEnemies[#hEnemies]:GetAbsOrigin()
|
||||
local vClosestPosToEnemy = nil
|
||||
local flShortestDist = 99999
|
||||
for _,vTeleportPos in pairs ( vTeleportLocations ) do
|
||||
local flDistToEnemy = ( vTeleportPos - vFarthestEnemyPos ):Length2D()
|
||||
if flDistToEnemy < flShortestDist then
|
||||
flShortestDist = flDistToEnemy
|
||||
vClosestPosToEnemy = vTeleportPos
|
||||
end
|
||||
end
|
||||
|
||||
if vTeleportPos ~= nil then
|
||||
vPos = vClosestPosToEnemy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vPos == nil then
|
||||
vPos = vTeleportLocations[ RandomInt( 1, #vTeleportLocations ) ]
|
||||
end
|
||||
end
|
||||
|
||||
if vPos == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
self.vLastBlinkLocation = vPos
|
||||
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = vPos,
|
||||
AbilityIndex = self.hBlink:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = 3.0
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateSummonPortals()
|
||||
if self:GetCurrentPhase() ~= self.PHASE_SUMMON_PORTALS then
|
||||
return nil
|
||||
end
|
||||
|
||||
local vTarget = self.me.vHomePosition
|
||||
local hEnemies = GetEnemyHeroesInRange( self.me, 5000 )
|
||||
if #hEnemies > 0 and self.vLastBlinkLocation == self.me.vHomePosition then
|
||||
vTarget = hEnemies[ 1 ]:GetAbsOrigin()
|
||||
end
|
||||
|
||||
local Order = nil
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = vTarget,
|
||||
AbilityIndex = self.hSummonPortals:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = GetSpellCastTime( self.hSummonPortals ) + self.hSummonPortals:GetChannelTime()
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateSpellSwap()
|
||||
if self:GetCurrentPhase() ~= self.PHASE_SPELL_SWAP then
|
||||
return nil
|
||||
end
|
||||
|
||||
local vTargetPos = self.me.vHomePosition
|
||||
if vTargetPos == self.vLastBlinkLocation then
|
||||
local hEnemies = GetEnemyHeroesInRange( self.me, 5000 )
|
||||
if #hEnemies > 0 then
|
||||
vTargetPos = hEnemies[#hEnemies]:GetAbsOrigin()
|
||||
end
|
||||
end
|
||||
|
||||
local Order = nil
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = vTargetPos,
|
||||
AbilityIndex = self.hSpellSwap:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = GetSpellCastTime( self.hSpellSwap ) + self.hSpellSwap:GetChannelTime()
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:EvaluateShardAttack()
|
||||
if self:GetCurrentPhase() ~= self.PHASE_SHARD_ATTACK then
|
||||
return nil
|
||||
end
|
||||
|
||||
local Order = nil
|
||||
Order =
|
||||
{
|
||||
UnitIndex = self.me:entindex(),
|
||||
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
|
||||
Position = self.me.vHomePosition + Vector( 0, -150, 0 ),
|
||||
AbilityIndex = self.hShardAttack:entindex(),
|
||||
Queue = false,
|
||||
}
|
||||
Order.flOrderInterval = GetSpellCastTime( self.hShardAttack ) + self.hShardAttack:GetChannelTime()
|
||||
|
||||
return Order
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function CBossAghanim:OnBossUsedAbility( szAbilityName )
|
||||
if szAbilityName == "aghanim_blink" then
|
||||
self.nNumAttacksBeforeTeleport = self.nCurrentAttacksBetweenTeleport
|
||||
self.bReturnHome = false
|
||||
return
|
||||
end
|
||||
|
||||
if szAbilityName == "aghanim_crystal_attack" then
|
||||
if self.hCrystalAttack.nPhase == 6 then
|
||||
self:ChangePhase()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:ChangePhase()
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user