Files
Dota-Zombie-Invasion/scripts/vscripts/cutscenes/cutscenemanager.lua
T
2026-05-29 15:11:31 +07:00

451 lines
16 KiB
Lua

local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Set = ____lualib.Set
local __TS__New = ____lualib.__TS__New
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local __TS__StringTrim = ____lualib.__TS__StringTrim
local __TS__Decorate = ____lualib.__TS__Decorate
local ____exports = {}
local ____DayNightCycleManager = require("DayNightCycleManager")
local DayNightCycleManager = ____DayNightCycleManager.DayNightCycleManager
local ____modifier_cutscene_lock = require("modifiers.modifier_cutscene_lock")
local modifier_cutscene_lock = ____modifier_cutscene_lock.modifier_cutscene_lock
local ____modifier_cutscene_npc_lock = require("modifiers.modifier_cutscene_npc_lock")
local modifier_cutscene_npc_lock = ____modifier_cutscene_npc_lock.modifier_cutscene_npc_lock
local ____tstl_2Dutils = require("lib.tstl-utils")
local reloadable = ____tstl_2Dutils.reloadable
local ____player_connection_state = require("utils.player_connection_state")
local DOTA_CONNECTION_STATE = ____player_connection_state.DOTA_CONNECTION_STATE
local ____CutsceneFunctions = require("cutscenes.CutsceneFunctions")
local finishCameraStartEndingTeleportNow = ____CutsceneFunctions.finishCameraStartEndingTeleportNow
local ____CutsceneTable = require("cutscenes.CutsceneTable")
local CutsceneTable = ____CutsceneTable.CutsceneTable
local CUTSCENE_AUTO_SKIP_POLL_TIMER = "CutsceneDisconnectAutoSkip"
____exports.CutsceneManager = __TS__Class()
local CutsceneManager = ____exports.CutsceneManager
CutsceneManager.name = "CutsceneManager"
CutsceneManager.____file_path = "scripts/vscripts/cutscenes/CutsceneManager.lua"
function CutsceneManager.prototype.____constructor(self)
self.playedSceneIds = __TS__New(Set)
self.isGameEnding = false
self:registerEvents()
end
function CutsceneManager.prototype.isPlayerOfflineForCutsceneSkip(self, playerId)
if not PlayerResource:IsValidPlayerID(playerId) then
return true
end
return PlayerResource:GetConnectionState(playerId) ~= DOTA_CONNECTION_STATE.CONNECTED
end
function CutsceneManager.prototype.startAutoSkipDisconnectPoll(self)
Timers:RemoveTimer(CUTSCENE_AUTO_SKIP_POLL_TIMER)
Timers:CreateTimer(
CUTSCENE_AUTO_SKIP_POLL_TIMER,
{
callback = function()
if not self.active then
return nil
end
self:applyAutoSkipVotesForDisconnectedParticipants()
return 0.25
end,
endTime = 0
}
)
end
function CutsceneManager.prototype.applyAutoSkipVotesForDisconnectedParticipants(self)
if not self.active then
return
end
for ____, playerId in ipairs(self.active.participantPlayerIds) do
do
if self.active.votedPlayers:has(playerId) then
goto __continue10
end
if not self:isPlayerOfflineForCutsceneSkip(playerId) then
goto __continue10
end
self.active.votedPlayers:add(playerId)
CustomGameEventManager:Send_ServerToAllClients("cutscene_vote_to_skip_success", {playerId = playerId})
end
::__continue10::
end
self:tryFinishCutsceneIfAllParticipantsVoted()
end
function CutsceneManager.prototype.tryFinishCutsceneIfAllParticipantsVoted(self)
if not self.active then
return
end
if #self.active.participantPlayerIds == 0 then
return
end
for ____, playerId in ipairs(self.active.participantPlayerIds) do
if not self.active.votedPlayers:has(playerId) then
return
end
end
self:finishCutscene()
end
function CutsceneManager.prototype.registerEvents(self)
CustomGameEventManager:RegisterListener(
"end_cutscene",
function() return self:finishCutscene() end
)
CustomGameEventManager:RegisterListener(
"cutscene_camera_change",
function(_, data) return self:onCameraChange(data) end
)
CustomGameEventManager:RegisterListener(
"cutscene_dialog_action",
function(_, data) return self:onDialogAction(data) end
)
CustomGameEventManager:RegisterListener(
"cutscene_dialog_function",
function(_, data) return self:onDialogFunction(data) end
)
CustomGameEventManager:RegisterListener(
"cutscene_vote_to_skip",
function(_, data) return self:onVoteToSkip(data) end
)
end
function CutsceneManager.prototype.notifyPlayerConnected(self, playerId)
if not self.active then
return
end
local player = PlayerResource:GetPlayer(playerId)
if not player then
return
end
local ____CustomGameEventManager_Send_ServerToPlayer_2 = CustomGameEventManager.Send_ServerToPlayer
local ____opt_0 = self.active.npc
____CustomGameEventManager_Send_ServerToPlayer_2(
CustomGameEventManager,
player,
"start_cutscene",
{
npc = ____opt_0 and ____opt_0:entindex(),
scene = self.active.scene
}
)
end
function CutsceneManager.prototype.startScene(self, sceneId, options)
if self.active then
print(((("[CutsceneManager] startScene(\"" .. sceneId) .. "\") отклонено: уже идёт \"") .. self.active.sceneId) .. "\"")
return false
end
local scene = self:getSceneConfig(sceneId)
if not scene then
print(("[CutsceneManager] startScene(\"" .. sceneId) .. "\") отклонено: нет сцены в CutsceneTable")
return false
end
if not (options and options.force) and self.playedSceneIds:has(sceneId) then
print(("[CutsceneManager] startScene(\"" .. sceneId) .. "\") отклонено: уже в playedSceneIds (без force)")
return false
end
local ____scene_npc_5
if scene.npc then
____scene_npc_5 = Entities:FindByName(nil, scene.npc) or nil
else
____scene_npc_5 = nil
end
local npc = ____scene_npc_5
local participantPlayerIds = __TS__ArrayMap(
self:getPlayers(),
function(____, p) return p.playerId end
)
self.active = {
sceneId = sceneId,
scene = scene,
npc = npc,
votedPlayers = __TS__New(Set),
participantPlayerIds = participantPlayerIds,
onEnd = options and options.onEnd
}
self.playedSceneIds:add(sceneId)
DayNightCycleManager:getInstance():onCutsceneStarted()
self:applyAutoSkipVotesForDisconnectedParticipants()
self:startAutoSkipDisconnectPoll()
self:applySceneState()
CustomGameEventManager:Send_ServerToAllClients(
"start_cutscene",
{
npc = npc and npc:entindex(),
scene = scene
}
)
local ____print_14 = print
local ____sceneId_13 = sceneId
local ____temp_12 = options and options.force
if ____temp_12 == nil then
____temp_12 = false
end
____print_14((((("[CutsceneManager] startScene(\"" .. ____sceneId_13) .. "\") OK, force=") .. tostring(____temp_12)) .. ", npc=") .. (scene.npc or "none"))
return true
end
function CutsceneManager.prototype.getSceneConfig(self, sceneId)
local loaded = require("cutscenes.CutsceneTable")
local ____opt_15 = loaded.CutsceneTable
return ____opt_15 and ____opt_15[sceneId] or CutsceneTable[sceneId]
end
function CutsceneManager.prototype.startEndingCutscene(self, victory)
if self.isGameEnding then
return
end
self.isGameEnding = true
self:startScene(
victory and "ending_victory" or "ending_defeat",
{
force = true,
onEnd = function()
local ____GameRules_SetGameWinner_18 = GameRules.SetGameWinner
local ____victory_17
if victory then
____victory_17 = DOTA_TEAM_GOODGUYS
else
____victory_17 = DOTA_TEAM_BADGUYS
end
____GameRules_SetGameWinner_18(GameRules, ____victory_17)
end
}
)
end
function CutsceneManager.prototype.triggerMidWaveWarning(self, night, waveIndex)
if night == 1 and waveIndex == 2 then
self:startScene("mid_wave_warning")
end
end
function CutsceneManager.prototype.isCutsceneActive(self)
return self.active ~= nil
end
function CutsceneManager.prototype.resolveInitialCameraTarget(self, scene, hero, npc)
local d1 = scene.dialogs[1]
local cam = d1 and d1.camera
if cam and cam ~= "default" and type(cam) == "table" and cam.name ~= nil and string.lower(__TS__StringTrim(cam.name)) == "hero" then
return hero
end
return npc
end
function CutsceneManager.prototype.applySceneState(self)
if not self.active then
return
end
local ____self_active_21 = self.active
local scene = ____self_active_21.scene
local npc = ____self_active_21.npc
local players = self:getPlayers()
local npcPos = npc and npc:GetAbsOrigin()
local forward = npc and npc:GetForwardVector()
local npcAngles = npc and npc:GetAngles()
for ____, ____value in ipairs(players) do
local playerId = ____value.playerId
local hero = ____value.hero
do
if not hero then
goto __continue45
end
local camTarget = self:resolveInitialCameraTarget(scene, hero, npc)
if camTarget ~= nil then
PlayerResource:SetCameraTarget(playerId, camTarget)
end
hero:AddNewModifier(
hero,
getModifierSourceAbility(nil, hero),
modifier_cutscene_lock.name,
{}
)
hero:SetControllableByPlayer(playerId, false)
hero:Stop()
if not scene.disableTeleport and npcPos and forward and npcAngles then
local distance = 260 + playerId * 15
hero:SetAngles(0, npcAngles.y + 180, 0)
FindClearSpaceForUnit(hero, npcPos + forward * distance, true)
end
end
::__continue45::
end
if scene.lockNpc and npc then
npc:AddNewModifier(
npc,
getModifierSourceAbility(nil, npc),
modifier_cutscene_npc_lock.name,
{}
)
end
end
function CutsceneManager.prototype.clearSceneState(self)
if not self.active then
return
end
local players = self:getPlayers()
for ____, ____value in ipairs(players) do
local playerId = ____value.playerId
local hero = ____value.hero
do
if not hero then
goto __continue53
end
PlayerResource:SetCameraTarget(playerId, nil)
CenterCameraOnUnit(playerId, hero)
hero:SetControllableByPlayer(playerId, true)
hero:RemoveModifierByName(modifier_cutscene_lock.name)
end
::__continue53::
end
if self.active.scene.lockNpc and self.active.npc then
self.active.npc:RemoveModifierByName(modifier_cutscene_npc_lock.name)
end
end
function CutsceneManager.prototype.finishCutscene(self)
if not self.active then
return
end
local finished = self.active
Timers:RemoveTimer(CUTSCENE_AUTO_SKIP_POLL_TIMER)
self:clearSceneState()
self.active = nil
DayNightCycleManager:getInstance():onCutsceneEnded()
do
pcall(function()
CustomGameEventManager:Send_ServerToAllClients("cutscene_closed", {})
end)
end
if finished.sceneId == "camera_start_ending" then
finishCameraStartEndingTeleportNow(nil)
end
local ____this_29
____this_29 = finished.scene
local ____opt_28 = ____this_29.onSuccess
if ____opt_28 ~= nil then
____opt_28(____this_29)
end
local ____opt_30 = finished.onEnd
if ____opt_30 ~= nil then
____opt_30(finished)
end
end
function CutsceneManager.prototype.onDialogAction(self, data)
local action = data.dialog.action
if not action then
return
end
local unit = self:resolveDialogNpc(data.dialog.npc)
if not unit then
return
end
unit:StartGestureWithPlaybackRate(action.name, action.rate)
end
function CutsceneManager.prototype.onDialogFunction(self, data)
if not self.active then
return
end
local ____opt_34 = self.active.scene.dialogs[data.dialogId]
local ____opt_32 = ____opt_34 and ____opt_34.onStart
if ____opt_32 ~= nil then
____opt_32(____opt_34)
end
end
function CutsceneManager.prototype.onCameraChange(self, data)
if not self.active then
return
end
local camera = data.dialog.camera
if not camera then
return
end
local players = self:getPlayers()
if camera == "default" then
for ____, ____value in ipairs(players) do
local playerId = ____value.playerId
PlayerResource:SetCameraTarget(playerId, self.active.npc)
end
return
end
if string.lower(__TS__StringTrim(camera.name)) == "hero" then
for ____, ____value in ipairs(players) do
local playerId = ____value.playerId
local hero = ____value.hero
do
if not hero then
goto __continue73
end
PlayerResource:SetCameraTarget(playerId, hero)
end
::__continue73::
end
return
end
local target = Entities:FindByName(nil, camera.name)
if not target and self.active.npc ~= nil and IsValidEntity(self.active.npc) then
target = self.active.npc
end
if not target then
return
end
for ____, ____value in ipairs(players) do
local playerId = ____value.playerId
PlayerResource:SetCameraTarget(playerId, target)
end
if camera.vision and data.visionDuration and data.visionDuration > 0 then
local team = DOTA_TEAM_GOODGUYS
local ____opt_36 = players[1]
local hero = ____opt_36 and ____opt_36.hero
if hero then
team = hero:GetTeamNumber()
end
local ____opt_38 = Entities:FindByName(nil, camera.vision.name)
local visionPoint = ____opt_38 and ____opt_38:GetAbsOrigin() or target:GetAbsOrigin()
AddFOWViewer(
team,
visionPoint,
camera.vision.radius,
data.visionDuration,
false
)
end
end
function CutsceneManager.prototype.onVoteToSkip(self, data)
if not self.active then
return
end
if self.active.votedPlayers:has(data.playerId) then
return
end
self.active.votedPlayers:add(data.playerId)
CustomGameEventManager:Send_ServerToAllClients("cutscene_vote_to_skip_success", {playerId = data.playerId})
self:applyAutoSkipVotesForDisconnectedParticipants()
self:tryFinishCutsceneIfAllParticipantsVoted()
end
function CutsceneManager.prototype.resolveDialogNpc(self, name)
if name then
return Entities:FindByName(nil, name) or nil
end
local ____opt_40 = self.active
return ____opt_40 and ____opt_40.npc
end
function CutsceneManager.prototype.getPlayers(self)
local players = {}
do
local playerId = 0
while playerId < DOTA_MAX_PLAYERS do
do
if not PlayerResource:IsValidPlayerID(playerId) then
goto __continue88
end
local player = PlayerResource:GetPlayer(playerId)
if not player then
goto __continue88
end
players[#players + 1] = {
playerId = playerId,
hero = PlayerResource:GetSelectedHeroEntity(playerId)
}
end
::__continue88::
playerId = playerId + 1
end
end
return players
end
CutsceneManager = __TS__Decorate(CutsceneManager, CutsceneManager, {reloadable}, {kind = "class", name = "CutsceneManager"})
____exports.CutsceneManager = CutsceneManager
return ____exports