384 lines
13 KiB
Lua
Executable File
384 lines
13 KiB
Lua
Executable File
if CPortalSpawner == nil then
|
|
CPortalSpawner = class({})
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:constructor( szSpawnerNameInput, szLocatorNameInput, nPortalHealthInput, flInitialPortalSpawnDelayInput, flInitialSummonTimeInput, flPortalIntervalInput, flScaleInput, rgUnitsInfoInput )
|
|
self.szSpawnerName = szSpawnerNameInput
|
|
self.szLocatorName = szLocatorNameInput
|
|
self.rgUnitsInfo = rgUnitsInfoInput
|
|
self.nPortalHealth = nPortalHealthInput
|
|
self.flInitialPortalSpawnDelay = flInitialPortalSpawnDelayInput
|
|
self.flInitialSummonTime = flInitialSummonTimeInput
|
|
self.flPortalInterval = flPortalIntervalInput
|
|
self.flScale = flScaleInput
|
|
|
|
self.nNumSpawnsRemaining = 3
|
|
|
|
self.Encounter = nil
|
|
|
|
self.vLocation = nil
|
|
self.bHasCreatedPortal = false
|
|
self.hPortalEnt = nil
|
|
self.flNextSpawnTime = -1.0
|
|
self.nWarningFX = nil
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:GetSpawnerType()
|
|
return "CPortalSpawner"
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:Precache( context )
|
|
--print( "CPortalSpawner:Precache called for " .. self.szSpawnerName )
|
|
|
|
PrecacheUnitByNameSync( "npc_aghsfort_dark_portal", context, -1 )
|
|
PrecacheResource( "particle", "particles/units/heroes/heroes_underlord/abyssal_underlord_darkrift_target.vpcf", context )
|
|
PrecacheResource( "particle", "particles/units/heroes/hero_visage/visage_summon_familiars.vpcf", context )
|
|
|
|
for _,rgUnitInfo in pairs ( self.rgUnitsInfo ) do
|
|
PrecacheUnitByNameSync( rgUnitInfo.EntityName, context, -1 )
|
|
end
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:SetLocation( vLocationInput )
|
|
self.vLocation = vLocationInput
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:OnEncounterLoaded( EncounterInput )
|
|
--print( "CPortalSpawner:OnEncounterLoaded called for " .. self.szSpawnerName )
|
|
self.Encounter = EncounterInput
|
|
|
|
ListenToGameEvent( "entity_killed", Dynamic_Wrap( CPortalSpawner, 'OnEntityKilled' ), self )
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:Start( flStartTime )
|
|
self.flNextSpawnTime = GameRules:GetGameTime() + self.flInitialPortalSpawnDelay
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:IsDestroyed()
|
|
if self.bHasCreatedPortal == false then
|
|
return false
|
|
end
|
|
|
|
if not self.hPortalEnt or self.hPortalEnt:IsNull() or self.hPortalEnt:IsAlive() == false then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
--[[
|
|
function CPortalSpawner:GetSpawnCountPerSpawnPosition()
|
|
|
|
local nCount = 0
|
|
for _,rgUnitInfo in pairs ( self.rgUnitsInfo ) do
|
|
nCount = nCount + rgUnitInfo.Count
|
|
end
|
|
return nCount
|
|
|
|
end
|
|
--]]
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:SpawnSingleUnitType( rgUnitInfo )
|
|
|
|
local hSpawnedUnits = {}
|
|
for i=1,rgUnitInfo.Count do
|
|
|
|
local vSpawnPos = self.vLocation
|
|
if rgUnitInfo.PositionNoise ~= nil then
|
|
local nAttempts = 0
|
|
while nAttempts < 16 do
|
|
local vTestPos = vSpawnPos + RandomVector( RandomFloat( 0.0, rgUnitInfo.PositionNoise ) )
|
|
vTestPos.z = GetGroundHeight( vTestPos, nil )
|
|
if GridNav:CanFindPath( vTestPos, self.vLocation ) then
|
|
vSpawnPos = vTestPos
|
|
break
|
|
end
|
|
nAttempts = nAttempts + 1
|
|
end
|
|
end
|
|
|
|
local hUnit = CreateUnitByName( rgUnitInfo.EntityName, vSpawnPos, true, nil, nil, rgUnitInfo.Team )
|
|
|
|
if hUnit == nil then
|
|
print( "ERROR! Failed to spawn unit named " .. rgUnitInfo.EntityName )
|
|
return nil
|
|
else
|
|
hUnit.bPortalUnit = true
|
|
hUnit:FaceTowards( self.vLocation )
|
|
if rgUnitInfo.PostSpawn ~= nil then
|
|
rgUnitInfo.PostSpawn( hUnit )
|
|
end
|
|
|
|
local nFXIndex = ParticleManager:CreateParticle( "particles/units/heroes/hero_visage/visage_summon_familiars.vpcf", PATTACH_CUSTOMORIGIN, hUnit );
|
|
ParticleManager:SetParticleControl( nFXIndex, 0, hUnit:GetAbsOrigin() );
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 1, hUnit, PATTACH_POINT_FOLLOW, "attach_hitloc", hUnit:GetAbsOrigin(), true )
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 2, hUnit, PATTACH_POINT_FOLLOW, "attach_hitloc", hUnit:GetAbsOrigin(), true )
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 3, hUnit, PATTACH_POINT_FOLLOW, "attach_hitloc", hUnit:GetAbsOrigin(), true )
|
|
ParticleManager:SetParticleControlEnt( nFXIndex, 4, hUnit, PATTACH_POINT_FOLLOW, "attach_hitloc", hUnit:GetAbsOrigin(), true )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex )
|
|
|
|
table.insert( hSpawnedUnits, hUnit )
|
|
end
|
|
end
|
|
|
|
return hSpawnedUnits
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:TrySpawningUnits()
|
|
--print( "CPortalSpawner:TrySpawningUnits" )
|
|
|
|
-- Don't spawn if Start() hasn't been called
|
|
if self.flNextSpawnTime < 0 then
|
|
return
|
|
end
|
|
|
|
if self.bHasCreatedPortal == false then
|
|
local flTimeReaminingToPortalSpawn = self.flNextSpawnTime - GameRules:GetGameTime()
|
|
|
|
if flTimeReaminingToPortalSpawn <= 0 then
|
|
--print( "Portal named " .. self:GetSpawnerName() .. " spawning portal!" )
|
|
self:SpawnPortal()
|
|
end
|
|
end
|
|
|
|
if self.bHasCreatedPortal == false then
|
|
return
|
|
end
|
|
|
|
if self.hPortalEnt ~= nil and self.hPortalEnt:IsNull() == false and self.hPortalEnt:IsAlive() then
|
|
local flTimeRemaining = self.flNextSpawnTime - GameRules:GetGameTime()
|
|
--print( "Portal named " .. self:GetSpawnerName() .. " has " .. flTimeRemaining .. " time remaining till spawn." )
|
|
|
|
if flTimeRemaining <= 0 then
|
|
--print( "Portal named " .. self:GetSpawnerName() .. " is spawning units!" )
|
|
self:SpawnUnits()
|
|
if self.nNumSpawnsRemaining > 0 then
|
|
self.flNextSpawnTime = self.flNextSpawnTime + self.flPortalInterval
|
|
else
|
|
self.flNextSpawnTime = -1 -- disabled from here on out
|
|
end
|
|
end
|
|
|
|
if flTimeRemaining <= 5 and flTimeRemaining > 0 and self.nWarningFX == nil then
|
|
--print( "Portal named " .. self:GetSpawnerName() .. " creating warning fx and sounds" )
|
|
|
|
self.nWarningFX = ParticleManager:CreateParticle( "particles/units/heroes/heroes_underlord/abyssal_underlord_darkrift_target.vpcf", PATTACH_OVERHEAD_FOLLOW, self.hPortalEnt )
|
|
ParticleManager:SetParticleControlEnt( self.nWarningFX, 1, self.hPortalEnt, PATTACH_POINT_FOLLOW, "attach_hitloc", self.hPortalEnt:GetAbsOrigin(), true )
|
|
ParticleManager:SetParticleControlEnt( self.nWarningFX, 6, self.hPortalEnt, PATTACH_ABSORIGIN_FOLLOW, nil, self.hPortalEnt:GetAbsOrigin(), true )
|
|
ParticleManager:SetParticleControl( self.nWarningFX, 10, Vector( flTimeRemaining*0.9, flTimeRemaining*0.9, flTimeRemaining*0.9 ) );
|
|
|
|
EmitSoundOn( "Aghsfort_DarkPortal.StartSummon", self.hPortalEnt )
|
|
end
|
|
end
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:SpawnUnits()
|
|
if self.vLocation == nil then
|
|
print( "ERROR - Spawner " .. self.szSpawnerName .. " does not have a valid location!" )
|
|
return
|
|
end
|
|
|
|
local nSpawned = 0
|
|
|
|
local hSpawnedUnits = {}
|
|
|
|
for _,rgUnitInfo in pairs ( self.rgUnitsInfo ) do
|
|
local hSingleSpawnedUnits = self:SpawnSingleUnitType( rgUnitInfo )
|
|
nSpawned = nSpawned + rgUnitInfo.Count
|
|
|
|
for _,hUnit in pairs ( hSingleSpawnedUnits ) do
|
|
table.insert( hSpawnedUnits, hUnit )
|
|
end
|
|
end
|
|
|
|
--printf( "%s spawning %d units", self.szSpawnerName, nSpawned )
|
|
|
|
if self.nWarningFX ~= nil then
|
|
ParticleManager:DestroyParticle( self.nWarningFX, false )
|
|
self.nWarningFX = nil
|
|
end
|
|
|
|
EmitSoundOn( "Aghsfort_DarkPortal.Complete", self.hPortalEnt )
|
|
StopSoundOn( "Aghsfort_DarkPortal.StartSummon", self.hPortalEnt )
|
|
|
|
if #hSpawnedUnits > 0 then
|
|
self.Encounter:OnSpawnerFinished( self, hSpawnedUnits )
|
|
end
|
|
|
|
self.nNumSpawnsRemaining = self.nNumSpawnsRemaining - 1
|
|
|
|
if self.nNumSpawnsRemaining <= 0 then
|
|
self.hPortalEnt:SetSkin( 1 )
|
|
end
|
|
|
|
--[[
|
|
if self.nNumSpawnsRemaining <= 0 then
|
|
if self.Encounter ~= nil then
|
|
local hAttacker = nil
|
|
self.Encounter:OnPortalKilled( self.hPortalEnt, hAttacker, 0 )
|
|
end
|
|
|
|
self:DestroyPortal( true )
|
|
end
|
|
--]]
|
|
return hSpawnedUnits
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:SpawnPortal()
|
|
--print( "CPortalSpawner:SpawnPortal" )
|
|
|
|
if self.bHasCreatedPortal == true then
|
|
print( 'ERROR: Trying to spawn a portal named ' .. self.szSpawnerName .. ' but it has already spawned a portal!')
|
|
return
|
|
end
|
|
|
|
if self.hPortalEnt ~= nil then
|
|
print( 'ERROR: Trying to spawn a portal named ' .. self.szSpawnerName .. ' but it already has a portal!')
|
|
return
|
|
end
|
|
|
|
if self.vLocation == nil then
|
|
print( 'ERROR: Trying to spawn a portal named ' .. self.szSpawnerName .. ' with a nil location!' )
|
|
return
|
|
end
|
|
|
|
local portalTable =
|
|
{
|
|
MapUnitName = "npc_aghsfort_dark_portal",
|
|
origin = tostring( self.vLocation.x ) .. " " .. tostring( self.vLocation.y ) .. " " .. tostring( self.vLocation.z ),
|
|
StatusHealth = self.nPortalHealth,
|
|
teamnumber = DOTA_TEAM_BADGUYS,
|
|
modelscale = self.flScale,
|
|
}
|
|
|
|
self.hPortalEnt = CreateUnitFromTable( portalTable, self.vLocation )
|
|
|
|
self.hPortalEnt:SetTeam( DOTA_TEAM_BADGUYS )
|
|
self.hPortalEnt:RemoveModifierByName( "modifier_invulnerable" )
|
|
|
|
self.hPortalEnt:SetMaxHealth( self.nPortalHealth )
|
|
self.hPortalEnt:SetBaseMaxHealth( self.nPortalHealth )
|
|
self.hPortalEnt:Heal( self.nPortalHealth, nil )
|
|
self.hPortalEnt:AddNewModifier( self.hPortalEnt, nil, "modifier_provide_vision", { duration = -1 } )
|
|
self.hPortalEnt:AddNewModifier( self.hPortalEnt, nil, "modifier_magic_immune", { duration = -1 } )
|
|
self.hPortalEnt:AddNewModifier( self.hPortalEnt, nil, "modifier_phased", { duration = -1 } )
|
|
|
|
self.hPortalEnt:SetAbsScale( self.flScale )
|
|
|
|
self.flNextSpawnTime = GameRules:GetGameTime() + self.flInitialSummonTime
|
|
|
|
-- hPortalEnt.nAmbientFX = ParticleManager:CreateParticle( "particles/units/heroes/heroes_underlord/abyssal_underlord_darkrift_target.vpcf", PATTACH_OVERHEAD_FOLLOW, hPortalEnt )
|
|
-- ParticleManager:SetParticleControlEnt( hPortalEnt.nAmbientFX , 1, hPortalEnt, PATTACH_POINT_FOLLOW, "attach_hitloc", hPortalEnt:GetAbsOrigin(), true )
|
|
-- ParticleManager:SetParticleControlEnt( hPortalEnt.nAmbientFX , 6, hPortalEnt, PATTACH_ABSORIGIN_FOLLOW, nil, hPortalEnt:GetAbsOrigin(), true )
|
|
-- ParticleManager:SetParticleControl( hPortalEnt.nAmbientFX , 10, Vector( 30, 30, 30 ) );
|
|
|
|
-- self.nWarningFX = ParticleManager:CreateParticle( "particles/units/heroes/heroes_underlord/abyssal_underlord_darkrift_target.vpcf", PATTACH_OVERHEAD_FOLLOW, self.hPortalEnt )
|
|
-- ParticleManager:SetParticleControlEnt( self.nWarningFX, 1, self.hPortalEnt, PATTACH_POINT_FOLLOW, "attach_hitloc", self.hPortalEnt:GetAbsOrigin(), true )
|
|
-- ParticleManager:SetParticleControlEnt( self.nWarningFX, 6, self.hPortalEnt, PATTACH_ABSORIGIN_FOLLOW, nil, self.hPortalEnt:GetAbsOrigin(), true )
|
|
-- ParticleManager:SetParticleControl( self.nWarningFX, 10, Vector( self.flNextSpawnTime*0.9, self.flNextSpawnTime*0.9, self.flNextSpawnTime*0.9 ) );
|
|
|
|
EmitSoundOn( "Aghsfort_DarkPortal.Created", self.hPortalEnt )
|
|
|
|
self.bHasCreatedPortal = true
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:OnEntityKilled( event )
|
|
local hVictim = nil
|
|
if event.entindex_killed ~= nil then
|
|
hVictim = EntIndexToHScript( event.entindex_killed )
|
|
end
|
|
|
|
if hVictim == nil or hVictim:IsRealHero() then
|
|
return
|
|
end
|
|
|
|
if hVictim ~= self.hPortalEnt then
|
|
return
|
|
end
|
|
|
|
if self.Encounter ~= nil then
|
|
local hAttacker = nil
|
|
if event.entindex_attacker ~= nil then
|
|
hAttacker = EntIndexToHScript( event.entindex_attacker )
|
|
end
|
|
|
|
local nSupressedUnits = 0
|
|
for _,rgUnitInfo in pairs ( self.rgUnitsInfo ) do
|
|
nSupressedUnits = nSupressedUnits + ( rgUnitInfo.Count * self.nNumSpawnsRemaining )
|
|
end
|
|
|
|
self.Encounter:OnPortalKilled( hVictim, hAttacker, nSupressedUnits )
|
|
end
|
|
|
|
self:DestroyPortal( false )
|
|
end
|
|
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:DestroyPortal( bRemove )
|
|
StopSoundOn( "Aghsfort_DarkPortal.StartSummon", self.hPortalEnt )
|
|
StopSoundOn( "Aghsfort_DarkPortal.Created", self.hPortal )
|
|
if self.hPortal and not self.hPortal:IsNull() then
|
|
EmitSoundOnLocationWithCaster( self.hPortal:GetAbsOrigin(), "Aghsfort_DarkPortal.Cancel", self.hPortal )
|
|
end
|
|
|
|
if self.nWarningFX ~= nil then
|
|
ParticleManager:DestroyParticle( self.nWarningFX, false )
|
|
self.nWarningFX = nil
|
|
end
|
|
|
|
if bRemove and self.hPortalEnt and not self.hPortalEnt:IsNull() then
|
|
UTIL_Remove( self.hPortalEnt )
|
|
self.hPortalEnt = nil
|
|
end
|
|
|
|
-- if hVictim.nAmbientFX ~= nil then
|
|
-- ParticleManager:DestroyParticle( hPortal.nAmbientFX, false )
|
|
-- hPortal.nAmbientFX = nil
|
|
-- end
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:GetSpawnerName()
|
|
return self.szSpawnerName
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:GetLocatorName()
|
|
return self.szLocatorName
|
|
end
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
function CPortalSpawner:GetNumSpawnsRemaining()
|
|
return self.nNumSpawnsRemaining
|
|
end
|