595 lines
22 KiB
Lua
595 lines
22 KiB
Lua
local ____lualib = require("lualib_bundle")
|
||
local __TS__Class = ____lualib.__TS__Class
|
||
local Map = ____lualib.Map
|
||
local __TS__New = ____lualib.__TS__New
|
||
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
|
||
local __TS__Decorate = ____lualib.__TS__Decorate
|
||
local ____exports = {}
|
||
local modifier_hero_gravestone_charger
|
||
local ____dota_ts_adapter = require("lib.dota_ts_adapter")
|
||
local BaseModifier = ____dota_ts_adapter.BaseModifier
|
||
local registerModifier = ____dota_ts_adapter.registerModifier
|
||
local ____invul_box = require("abilities.invul_box")
|
||
local invul_box = ____invul_box.invul_box
|
||
local ____game_stats_tracker = require("game_stats_tracker")
|
||
local GameStatsTracker = ____game_stats_tracker.GameStatsTracker
|
||
local ____player_connection_state = require("utils.player_connection_state")
|
||
local DOTA_CONNECTION_STATE = ____player_connection_state.DOTA_CONNECTION_STATE
|
||
--- Базовый юнит из npc_units_custom (хитбокс/инвул); визуал задаём моделью надгробия.
|
||
local GRAVESTONE_UNIT_NAME = "npc_grave"
|
||
local GRAVESTONE_MODEL = "models/items/wraith_king/arcana/wk_arcana_tombstone.vmdl"
|
||
--- Как в CutsceneFunctions — targetname живого босса на арене.
|
||
local NEVERMORE_BOSS_TARGETNAME = "npc_boss_nevermore"
|
||
--- infinity_levels: дроп item_tombstone_respawn + PICKUP_ITEM → BeginChannel(5).
|
||
-- Здесь то же время ожидания, но без предмета и без поднятия — только стояние в радиусе (как шрайн/defension).
|
||
local GRAVESTONE_RADIUS = 300
|
||
local GRAVESTONE_CAPTURE_TIME = 5
|
||
local INTERVAL = 0.03
|
||
--- Маркер на земле как в infinity_levels (GameMode precache Muerta).
|
||
local MUERTA_GRAVE_MARKER_PARTICLE = "particles/econ/items/muerta/muerta_gravemarker_lvl1.vpcf"
|
||
--- Последовательность модели надгробия при захвате (тряска). Должна быть в .vmdl (часто у tombstone/Muerta).
|
||
local GRAVESTONE_CAPTURE_SEQUENCE = "sk_tombstone_reincarnation_no_reform"
|
||
--- FindByName — только targetname в карте / SetEntityName; босс из KV — npc_dota_creature,
|
||
-- поэтому дублируем поиск по GetUnitName у живых юнитов в большом радиусе от точки арены.
|
||
local function findLiveNevermoreBoss(self)
|
||
local byTargetName = Entities:FindByName(nil, NEVERMORE_BOSS_TARGETNAME)
|
||
if byTargetName ~= nil and IsValidEntity(byTargetName) and byTargetName:IsAlive() then
|
||
return byTargetName
|
||
end
|
||
local searchOrigin = Vector(0, 0, 0)
|
||
local spawnPt = Entities:FindByName(nil, "point_boss_spawn_point")
|
||
if spawnPt ~= nil then
|
||
searchOrigin = spawnPt:GetAbsOrigin()
|
||
end
|
||
local units = FindUnitsInRadius(
|
||
DOTA_TEAM_NEUTRALS,
|
||
searchOrigin,
|
||
nil,
|
||
25000,
|
||
DOTA_UNIT_TARGET_TEAM_BOTH,
|
||
DOTA_UNIT_TARGET_ALL,
|
||
DOTA_UNIT_TARGET_FLAG_NONE,
|
||
FIND_ANY_ORDER,
|
||
false
|
||
)
|
||
do
|
||
local i = 0
|
||
while i < #units do
|
||
local u = units[i + 1]
|
||
if u ~= nil and IsValidEntity(u) and u:IsAlive() and u:GetUnitName() == NEVERMORE_BOSS_TARGETNAME then
|
||
return u
|
||
end
|
||
i = i + 1
|
||
end
|
||
end
|
||
return nil
|
||
end
|
||
local function isNevermoreBossFightActive(self)
|
||
return findLiveNevermoreBoss(nil) ~= nil
|
||
end
|
||
--- Radiant, сейчас реально в матче (CONNECTED). Ливнувших/дропнутых не считаем.
|
||
local function isGoodGuysPlayerCountedForGravestoneRules(self, playerId)
|
||
if not PlayerResource:IsValidPlayerID(playerId) or not PlayerResource:IsValidPlayer(playerId) then
|
||
return false
|
||
end
|
||
if PlayerResource:GetTeam(playerId) ~= DOTA_TEAM_GOODGUYS then
|
||
return false
|
||
end
|
||
return PlayerResource:GetConnectionState(playerId) == DOTA_CONNECTION_STATE.CONNECTED
|
||
end
|
||
local function countGoodGuysPlayersInMatch(self)
|
||
local n = 0
|
||
do
|
||
local i = 0
|
||
while i < DOTA_MAX_PLAYERS do
|
||
local pid = i
|
||
if isGoodGuysPlayerCountedForGravestoneRules(nil, pid) then
|
||
n = n + 1
|
||
end
|
||
i = i + 1
|
||
end
|
||
end
|
||
return n
|
||
end
|
||
--- Сколько героев Radiant из учитываемых слотов реально живы (истина для проверки вайпа).
|
||
local function countAliveGoodGuysHeroesInMatch(self)
|
||
local n = 0
|
||
do
|
||
local i = 0
|
||
while i < DOTA_MAX_PLAYERS do
|
||
do
|
||
local pid = i
|
||
if not isGoodGuysPlayerCountedForGravestoneRules(nil, pid) then
|
||
goto __continue15
|
||
end
|
||
local hero = PlayerResource:GetSelectedHeroEntity(pid)
|
||
if not hero or not IsValidEntity(hero) then
|
||
goto __continue15
|
||
end
|
||
if not hero:IsHero() or not hero:IsRealHero() or hero:IsIllusion() then
|
||
goto __continue15
|
||
end
|
||
if hero:GetTeamNumber() ~= DOTA_TEAM_GOODGUYS then
|
||
goto __continue15
|
||
end
|
||
if hero:IsAlive() then
|
||
n = n + 1
|
||
end
|
||
end
|
||
::__continue15::
|
||
i = i + 1
|
||
end
|
||
end
|
||
return n
|
||
end
|
||
--- Можно ли вообще поднимать героя респавном (надгробие не ставим и не завершаем заряд, если нет).
|
||
local function isHeroEligibleForGravestoneRespawn(self, hero)
|
||
if hero:WillReincarnate() then
|
||
return false
|
||
end
|
||
if hero:IsReincarnating() then
|
||
return false
|
||
end
|
||
return true
|
||
end
|
||
function ____exports.precacheHeroGravestoneParticles(self, context)
|
||
PrecacheResource("model", GRAVESTONE_MODEL, context)
|
||
PrecacheResource("particle", MUERTA_GRAVE_MARKER_PARTICLE, context)
|
||
PrecacheResource("particle", "particles/shrine/capture_point_ring_overthrow.vpcf", context)
|
||
PrecacheResource("particle", "particles/shrine/capture_point_ring_clock_overthrow.vpcf", context)
|
||
PrecacheResource("particle", "particles/units/heroes/hero_skeletonking/wraith_king_reincarnate.vpcf", context)
|
||
end
|
||
--- Надгробие: живой союзник стоит в зоне — копится прогресс (не клик по предмету, как в infinity_levels).
|
||
____exports.HeroGravestoneRespawn = __TS__Class()
|
||
local HeroGravestoneRespawn = ____exports.HeroGravestoneRespawn
|
||
HeroGravestoneRespawn.name = "HeroGravestoneRespawn"
|
||
HeroGravestoneRespawn.____file_path = "scripts/vscripts/gameplay/hero_gravestone_respawn.lua"
|
||
function HeroGravestoneRespawn.prototype.____constructor(self)
|
||
end
|
||
function HeroGravestoneRespawn.initialize(self)
|
||
ListenToGameEvent(
|
||
"entity_killed",
|
||
function(event) return self:onEntityKilled(event) end,
|
||
nil
|
||
)
|
||
ListenToGameEvent(
|
||
"dota_player_spawned",
|
||
function(event) return self:onPlayerSpawned(event) end,
|
||
nil
|
||
)
|
||
end
|
||
function HeroGravestoneRespawn.registerGravestone(self, playerId, entIndex)
|
||
local prev = self.graveEntIndexByPlayer:get(playerId)
|
||
if prev ~= nil and prev ~= entIndex then
|
||
local old = EntIndexToHScript(prev)
|
||
if old and IsValidEntity(old) then
|
||
UTIL_Remove(old)
|
||
end
|
||
end
|
||
self.graveEntIndexByPlayer:set(playerId, entIndex)
|
||
end
|
||
function HeroGravestoneRespawn.unregisterGravestone(self, playerId)
|
||
self.graveEntIndexByPlayer:delete(playerId)
|
||
end
|
||
function HeroGravestoneRespawn.hasGravestoneForPlayer(self, playerId)
|
||
return self.graveEntIndexByPlayer:has(playerId)
|
||
end
|
||
function HeroGravestoneRespawn.removeAllGravestones(self)
|
||
self.graveEntIndexByPlayer:forEach(function(____, entIndex)
|
||
local u = EntIndexToHScript(entIndex)
|
||
if u and IsValidEntity(u) then
|
||
UTIL_Remove(u)
|
||
end
|
||
end)
|
||
self.graveEntIndexByPlayer:clear()
|
||
end
|
||
function HeroGravestoneRespawn.pruneGravestonesForPlayersOutOfMatch(self)
|
||
local toRemove = {}
|
||
self.graveEntIndexByPlayer:forEach(function(____, _entIndex, playerId)
|
||
if not isGoodGuysPlayerCountedForGravestoneRules(nil, playerId) then
|
||
toRemove[#toRemove + 1] = playerId
|
||
end
|
||
end)
|
||
for ____, pid in ipairs(toRemove) do
|
||
local entIndex = self.graveEntIndexByPlayer:get(pid)
|
||
self:unregisterGravestone(pid)
|
||
if entIndex ~= nil then
|
||
local u = EntIndexToHScript(entIndex)
|
||
if u and IsValidEntity(u) then
|
||
UTIL_Remove(u)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
function HeroGravestoneRespawn.maybePruneGravestonesForPlayersOutOfMatch(self)
|
||
local t = GameRules:GetGameTime()
|
||
if t - self.lastOutOfMatchPruneGameTime < 1 then
|
||
return
|
||
end
|
||
self.lastOutOfMatchPruneGameTime = t
|
||
self:pruneGravestonesForPlayersOutOfMatch()
|
||
end
|
||
function HeroGravestoneRespawn.onPlayerSpawned(self, event)
|
||
local entIndex = self.graveEntIndexByPlayer:get(event.PlayerID)
|
||
if entIndex == nil then
|
||
return
|
||
end
|
||
self.graveEntIndexByPlayer:delete(event.PlayerID)
|
||
local unit = EntIndexToHScript(entIndex)
|
||
if unit and IsValidEntity(unit) then
|
||
UTIL_Remove(unit)
|
||
end
|
||
end
|
||
function HeroGravestoneRespawn.onEntityKilled(self, event)
|
||
if not IsServer() then
|
||
return
|
||
end
|
||
if GameRules:State_Get() ~= DOTA_GAMERULES_STATE_GAME_IN_PROGRESS then
|
||
return
|
||
end
|
||
local killed = EntIndexToHScript(event.entindex_killed)
|
||
if not killed or not IsValidEntity(killed) then
|
||
return
|
||
end
|
||
if killed:GetUnitName() == NEVERMORE_BOSS_TARGETNAME then
|
||
self:removeAllGravestones()
|
||
return
|
||
end
|
||
if not killed:IsHero() then
|
||
return
|
||
end
|
||
if not killed:IsRealHero() then
|
||
return
|
||
end
|
||
if killed:IsIllusion() then
|
||
return
|
||
end
|
||
local playerId = killed:GetPlayerOwnerID()
|
||
if playerId < 0 or not PlayerResource:IsValidPlayerID(playerId) then
|
||
return
|
||
end
|
||
if killed:GetTeamNumber() ~= DOTA_TEAM_GOODGUYS then
|
||
return
|
||
end
|
||
local heroDead = killed
|
||
local cutscene = GameRules.CutsceneManager
|
||
if cutscene ~= nil and cutscene:isCutsceneActive() then
|
||
return
|
||
end
|
||
if not isNevermoreBossFightActive(nil) then
|
||
return
|
||
end
|
||
local origin = killed:GetAbsOrigin()
|
||
local ground = GetGroundPosition(origin, killed)
|
||
local grave = CreateUnitByName(
|
||
GRAVESTONE_UNIT_NAME,
|
||
ground,
|
||
true,
|
||
nil,
|
||
nil,
|
||
DOTA_TEAM_NEUTRALS
|
||
)
|
||
if not grave or not IsValidEntity(grave) then
|
||
return
|
||
end
|
||
FindClearSpaceForUnit(grave, ground, true)
|
||
grave:AddAbility(invul_box.name)
|
||
grave:SetModel(GRAVESTONE_MODEL)
|
||
grave:SetUnitName(GRAVESTONE_UNIT_NAME)
|
||
grave:SetEntityName(GRAVESTONE_UNIT_NAME)
|
||
grave:AddNewModifier(
|
||
grave,
|
||
getModifierSourceAbility(nil, grave),
|
||
modifier_hero_gravestone_charger.name,
|
||
{ownerPlayerId = playerId}
|
||
)
|
||
self:registerGravestone(
|
||
playerId,
|
||
grave:entindex()
|
||
)
|
||
self:pruneGravestonesForPlayersOutOfMatch()
|
||
self:pruneGravestonesForAliveHeroes()
|
||
local players = countGoodGuysPlayersInMatch(nil)
|
||
if players > 0 and self.graveEntIndexByPlayer.size == players and countAliveGoodGuysHeroesInMatch(nil) == 0 then
|
||
GameStatsTracker:getInstance():onDefeat(function()
|
||
GameRules:SetGameWinner(DOTA_TEAM_BADGUYS)
|
||
end)
|
||
end
|
||
end
|
||
function HeroGravestoneRespawn.pruneGravestonesForAliveHeroes(self)
|
||
local toRemove = {}
|
||
self.graveEntIndexByPlayer:forEach(function(____, _entIndex, playerId)
|
||
local hero = PlayerResource:GetSelectedHeroEntity(playerId)
|
||
if hero and IsValidEntity(hero) and hero:IsHero() and hero:IsRealHero() and not hero:IsIllusion() and hero:IsAlive() then
|
||
toRemove[#toRemove + 1] = playerId
|
||
end
|
||
end)
|
||
for ____, pid in ipairs(toRemove) do
|
||
local entIndex = self.graveEntIndexByPlayer:get(pid)
|
||
self:unregisterGravestone(pid)
|
||
if entIndex ~= nil then
|
||
local u = EntIndexToHScript(entIndex)
|
||
if u and IsValidEntity(u) then
|
||
UTIL_Remove(u)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
HeroGravestoneRespawn.graveEntIndexByPlayer = __TS__New(Map)
|
||
HeroGravestoneRespawn.lastOutOfMatchPruneGameTime = -1000000000
|
||
modifier_hero_gravestone_charger = __TS__Class()
|
||
modifier_hero_gravestone_charger.name = "modifier_hero_gravestone_charger"
|
||
modifier_hero_gravestone_charger.____file_path = "scripts/vscripts/gameplay/hero_gravestone_respawn.lua"
|
||
__TS__ClassExtends(modifier_hero_gravestone_charger, BaseModifier)
|
||
function modifier_hero_gravestone_charger.prototype.____constructor(self, ...)
|
||
BaseModifier.prototype.____constructor(self, ...)
|
||
self.vPosition = Vector(0, 0, 0)
|
||
self.progress = 0
|
||
self.timer = 0
|
||
self.captureSequenceActive = false
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.IsHidden(self)
|
||
return true
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.IsPurgable(self)
|
||
return false
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.OnCreated(self, params)
|
||
if not IsServer() then
|
||
return
|
||
end
|
||
self.ownerPlayerId = params and params.ownerPlayerId or -1
|
||
self.vPosition = self:GetParent():GetAbsOrigin()
|
||
self:StartIntervalThink(INTERVAL)
|
||
self.vision = AddFOWViewer(
|
||
DOTA_TEAM_GOODGUYS,
|
||
self.vPosition,
|
||
GRAVESTONE_RADIUS,
|
||
99999,
|
||
true
|
||
)
|
||
local parent = self:GetParent()
|
||
self.muertaAmbient = ParticleManager:CreateParticle(MUERTA_GRAVE_MARKER_PARTICLE, PATTACH_ABSORIGIN_FOLLOW, parent)
|
||
ParticleManager:SetParticleControl(
|
||
self.muertaAmbient,
|
||
0,
|
||
parent:GetAbsOrigin()
|
||
)
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.OnDestroy(self)
|
||
if not IsServer() then
|
||
return
|
||
end
|
||
if self.vision ~= nil then
|
||
RemoveFOWViewer(DOTA_TEAM_GOODGUYS, self.vision)
|
||
end
|
||
if self.muertaAmbient ~= nil then
|
||
ParticleManager:DestroyParticle(self.muertaAmbient, false)
|
||
ParticleManager:ReleaseParticleIndex(self.muertaAmbient)
|
||
end
|
||
if self.baseParticle ~= nil then
|
||
ParticleManager:DestroyParticle(self.baseParticle, false)
|
||
ParticleManager:ReleaseParticleIndex(self.baseParticle)
|
||
end
|
||
if self.clockParticle ~= nil then
|
||
ParticleManager:DestroyParticle(self.clockParticle, true)
|
||
ParticleManager:ReleaseParticleIndex(self.clockParticle)
|
||
end
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.checkCapturePointParticles(self)
|
||
local parent = self:GetParent()
|
||
if not self.baseParticle then
|
||
self.baseParticle = ParticleManager:CreateParticle("particles/shrine/capture_point_ring_overthrow.vpcf", PATTACH_WORLDORIGIN, parent)
|
||
ParticleManager:SetParticleControl(
|
||
self.baseParticle,
|
||
0,
|
||
parent:GetAbsOrigin()
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.baseParticle,
|
||
3,
|
||
Vector(150, 150, 150)
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.baseParticle,
|
||
9,
|
||
Vector(GRAVESTONE_RADIUS, 0, 0)
|
||
)
|
||
else
|
||
ParticleManager:SetParticleControl(
|
||
self.baseParticle,
|
||
0,
|
||
parent:GetAbsOrigin()
|
||
)
|
||
end
|
||
if self.progress <= 0 or self.progress >= 1 then
|
||
if self.clockParticle ~= nil then
|
||
ParticleManager:DestroyParticle(self.clockParticle, true)
|
||
ParticleManager:ReleaseParticleIndex(self.clockParticle)
|
||
self.clockParticle = nil
|
||
end
|
||
return
|
||
end
|
||
local team = DOTA_TEAM_GOODGUYS
|
||
local origin = parent:GetAbsOrigin()
|
||
local z = origin.z + 75
|
||
if not self.clockParticle then
|
||
self.clockParticle = ParticleManager:CreateParticleForTeam("particles/shrine/capture_point_ring_clock_overthrow.vpcf", PATTACH_WORLDORIGIN, parent, team)
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
0,
|
||
Vector(origin.x, origin.y, z)
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
11,
|
||
Vector(0, 0, 1)
|
||
)
|
||
end
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
3,
|
||
Vector(220, 220, 220)
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
9,
|
||
Vector(GRAVESTONE_RADIUS, 0, 0)
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
17,
|
||
Vector(self.progress, 0, 0)
|
||
)
|
||
ParticleManager:SetParticleControl(
|
||
self.clockParticle,
|
||
0,
|
||
Vector(origin.x, origin.y, z)
|
||
)
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.updateCaptureModelAnimation(self, parent, isCapturing)
|
||
if isCapturing then
|
||
if not self.captureSequenceActive then
|
||
parent:SetSequence(GRAVESTONE_CAPTURE_SEQUENCE)
|
||
self.captureSequenceActive = true
|
||
elseif parent:IsSequenceFinished() then
|
||
parent:ResetSequence(GRAVESTONE_CAPTURE_SEQUENCE)
|
||
end
|
||
else
|
||
if self.captureSequenceActive then
|
||
parent:StopAnimation()
|
||
self.captureSequenceActive = false
|
||
end
|
||
end
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.OnIntervalThink(self)
|
||
if not IsServer() then
|
||
return
|
||
end
|
||
____exports.HeroGravestoneRespawn:maybePruneGravestonesForPlayersOutOfMatch()
|
||
local parent = self:GetParent()
|
||
if not parent or not IsValidEntity(parent) then
|
||
return
|
||
end
|
||
if not isNevermoreBossFightActive(nil) then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
local boundHero = PlayerResource:GetSelectedHeroEntity(self.ownerPlayerId)
|
||
if boundHero and IsValidEntity(boundHero) and not boundHero:IsAlive() and not isHeroEligibleForGravestoneRespawn(nil, boundHero) then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
self.vPosition = parent:GetAbsOrigin()
|
||
local heroesInRadius = FindUnitsInRadius(
|
||
DOTA_TEAM_NEUTRALS,
|
||
self.vPosition,
|
||
nil,
|
||
GRAVESTONE_RADIUS,
|
||
DOTA_UNIT_TARGET_TEAM_ENEMY,
|
||
DOTA_UNIT_TARGET_HERO,
|
||
bit.bor(
|
||
bit.bor(
|
||
bit.bor(
|
||
bit.bor(DOTA_UNIT_TARGET_FLAG_NOT_CREEP_HERO, DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES),
|
||
DOTA_UNIT_TARGET_FLAG_INVULNERABLE
|
||
),
|
||
DOTA_UNIT_TARGET_FLAG_NOT_ILLUSIONS
|
||
),
|
||
DOTA_UNIT_TARGET_FLAG_OUT_OF_WORLD
|
||
),
|
||
FIND_ANY_ORDER,
|
||
false
|
||
)
|
||
local heroes = {}
|
||
local teamRegister = {}
|
||
for ____, unit in ipairs(heroesInRadius) do
|
||
if unit:IsHero() and unit:IsAlive() and unit:IsRealHero() then
|
||
local team = unit:GetTeamNumber()
|
||
if not teamRegister[team] then
|
||
teamRegister[team] = true
|
||
heroes[#heroes + 1] = unit
|
||
end
|
||
end
|
||
end
|
||
if #heroes == 1 then
|
||
self.timer = self.timer + INTERVAL
|
||
self.progress = self.timer / GRAVESTONE_CAPTURE_TIME
|
||
if self.progress >= 1 then
|
||
self:completeResurrection()
|
||
return
|
||
end
|
||
else
|
||
self.timer = math.max(0, self.timer - INTERVAL)
|
||
self.progress = self.timer / GRAVESTONE_CAPTURE_TIME
|
||
end
|
||
local isCapturing = #heroes == 1 and self.progress > 0 and self.progress < 1
|
||
self:updateCaptureModelAnimation(parent, isCapturing)
|
||
self:checkCapturePointParticles()
|
||
end
|
||
function modifier_hero_gravestone_charger.prototype.completeResurrection(self)
|
||
local parent = self:GetParent()
|
||
if not parent or not IsValidEntity(parent) then
|
||
return
|
||
end
|
||
if not isNevermoreBossFightActive(nil) then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
local hero = PlayerResource:GetSelectedHeroEntity(self.ownerPlayerId)
|
||
if not hero or not IsValidEntity(hero) then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
if hero:IsAlive() then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
if not isHeroEligibleForGravestoneRespawn(nil, hero) then
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return
|
||
end
|
||
local pos = parent:GetAbsOrigin()
|
||
hero:SetRespawnPosition(pos)
|
||
do
|
||
local function ____catch()
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
return true
|
||
end
|
||
local ____try, ____hasReturned, ____returnValue = pcall(function()
|
||
hero:RespawnHero(false, false)
|
||
end)
|
||
if not ____try then
|
||
____hasReturned, ____returnValue = ____catch()
|
||
end
|
||
if ____hasReturned then
|
||
return ____returnValue
|
||
end
|
||
end
|
||
FindClearSpaceForUnit(hero, pos, true)
|
||
local pfx = ParticleManager:CreateParticle("particles/units/heroes/hero_skeletonking/wraith_king_reincarnate.vpcf", PATTACH_ABSORIGIN_FOLLOW, hero)
|
||
ParticleManager:SetParticleControl(
|
||
pfx,
|
||
0,
|
||
hero:GetAbsOrigin()
|
||
)
|
||
ParticleManager:ReleaseParticleIndex(pfx)
|
||
parent:EmitSound("Outpost.Captured")
|
||
____exports.HeroGravestoneRespawn:unregisterGravestone(self.ownerPlayerId)
|
||
UTIL_Remove(parent)
|
||
end
|
||
modifier_hero_gravestone_charger = __TS__Decorate(
|
||
modifier_hero_gravestone_charger,
|
||
modifier_hero_gravestone_charger,
|
||
{registerModifier(nil)},
|
||
{kind = "class", name = "modifier_hero_gravestone_charger"}
|
||
)
|
||
return ____exports
|