451 lines
16 KiB
Lua
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
|