From 7011bbb7548399c4f8949cea6274ab32a6f92caf Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sat, 6 Jun 2026 21:21:56 +0300 Subject: [PATCH] Working on cutscene skip --- .../cutscenes/cutscene1/cutscene1_aida1_x.png | 3 ++ .../cutscenes/cutscene1/cutscene1_aida2_x.png | 3 ++ .../cutscenes/cutscene1/cutscene1_aida3_x.png | 3 ++ .../cutscenes/cutscene1/cutscene1_heads_x.png | 3 ++ .../cutscenes/cutscene1/cutscene1_wall_x.png | 3 ++ resources/w/cutscenes/cutscene2/scr1.png | 3 ++ resources/w/cutscenes/cutscene2/scr2.png | 3 ++ resources/w/cutscenes/cutscene2/scr3.png | 3 ++ resources/w/cutscenes/cutscene2/scr4.png | 3 ++ .../w/ui/{hud_skip.json => hud_cutscene.json} | 0 src/Game.cpp | 28 ++++++++++++++++--- src/MenuManager.cpp | 17 ++++++++++- src/MenuManager.h | 7 +++++ src/UiManager.cpp | 22 ++++++++------- src/dialogue/DialogueSystem.cpp | 22 +++++++++++++-- src/dialogue/DialogueSystem.h | 6 ++++ 16 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png create mode 100644 resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png create mode 100644 resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png create mode 100644 resources/w/cutscenes/cutscene1/cutscene1_heads_x.png create mode 100644 resources/w/cutscenes/cutscene1/cutscene1_wall_x.png create mode 100644 resources/w/cutscenes/cutscene2/scr1.png create mode 100644 resources/w/cutscenes/cutscene2/scr2.png create mode 100644 resources/w/cutscenes/cutscene2/scr3.png create mode 100644 resources/w/cutscenes/cutscene2/scr4.png rename resources/w/ui/{hud_skip.json => hud_cutscene.json} (100%) diff --git a/resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png b/resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png new file mode 100644 index 0000000..c196475 --- /dev/null +++ b/resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:973534a19e25c881a88c44361304e9286728250b1f7a2f93d6ef1d0762af98bc +size 301489 diff --git a/resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png b/resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png new file mode 100644 index 0000000..2fce25d --- /dev/null +++ b/resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9de6dd9c32e2de7031cd7ee377b54e863138e4a4c873b2651245273df99c2ee2 +size 308616 diff --git a/resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png b/resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png new file mode 100644 index 0000000..80e4894 --- /dev/null +++ b/resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0506915c45b0c14c80da4fc7f07e21fb01659cf89c0636859204c9eb1deba9a +size 309033 diff --git a/resources/w/cutscenes/cutscene1/cutscene1_heads_x.png b/resources/w/cutscenes/cutscene1/cutscene1_heads_x.png new file mode 100644 index 0000000..4e3dc38 --- /dev/null +++ b/resources/w/cutscenes/cutscene1/cutscene1_heads_x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b133568b28ec2c5afb66081ecf76e88a0a0baf1764458e03f3a66b5b10b43f9c +size 134230 diff --git a/resources/w/cutscenes/cutscene1/cutscene1_wall_x.png b/resources/w/cutscenes/cutscene1/cutscene1_wall_x.png new file mode 100644 index 0000000..f75e028 --- /dev/null +++ b/resources/w/cutscenes/cutscene1/cutscene1_wall_x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c1408923a467f85c5f9857173c4808a784177a37cacae70a170a6091127ab4c +size 1828601 diff --git a/resources/w/cutscenes/cutscene2/scr1.png b/resources/w/cutscenes/cutscene2/scr1.png new file mode 100644 index 0000000..00cb709 --- /dev/null +++ b/resources/w/cutscenes/cutscene2/scr1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6516e33b563f3ea0149a46fd76c9cef35031cb1efad738579bfb810bf8fb45bb +size 856497 diff --git a/resources/w/cutscenes/cutscene2/scr2.png b/resources/w/cutscenes/cutscene2/scr2.png new file mode 100644 index 0000000..0f7a798 --- /dev/null +++ b/resources/w/cutscenes/cutscene2/scr2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6593670001b5eef629acebd90dbf08b9b3e1b4c5bcd03df893bfd9529dad5efb +size 856703 diff --git a/resources/w/cutscenes/cutscene2/scr3.png b/resources/w/cutscenes/cutscene2/scr3.png new file mode 100644 index 0000000..5062dd8 --- /dev/null +++ b/resources/w/cutscenes/cutscene2/scr3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27883838ec5d9a7adc40a484cc80f6aa4bb81de1631a3f1e9dd7986e74d49166 +size 842904 diff --git a/resources/w/cutscenes/cutscene2/scr4.png b/resources/w/cutscenes/cutscene2/scr4.png new file mode 100644 index 0000000..3524be7 --- /dev/null +++ b/resources/w/cutscenes/cutscene2/scr4.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24f6d785879f93ed2e9ddef21dfbe27a0dcef564e9d7aadb7e4d31ec81226431 +size 824230 diff --git a/resources/w/ui/hud_skip.json b/resources/w/ui/hud_cutscene.json similarity index 100% rename from resources/w/ui/hud_skip.json rename to resources/w/ui/hud_cutscene.json diff --git a/src/Game.cpp b/src/Game.cpp index ebbd7fd..116c79c 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -418,6 +418,19 @@ namespace ZL }); } + // Wire cutscene HUD: show skip button when cutscene starts, restore HUD when it ends. + for (auto& [name, loc] : locations) { + loc->dialogueSystem.setOnCutsceneStarted([this]() { + menuManager.onCutsceneStarted(); + }); + loc->dialogueSystem.setOnCutsceneFinishedExtra([this](const std::string&) { + menuManager.onCutsceneFinished(); + }); + } + menuManager.skipCutsceneFunc = [this]() { + if (currentLocation) currentLocation->dialogueSystem.skipCutscene(); + }; + currentLocation = locations["location_dorm"]; currentLocation->scriptEngine.callLocationEnterCallback(); @@ -498,12 +511,14 @@ namespace ZL renderer.RenderUniform1i(textureUniformName, 0); glEnable(GL_BLEND); - menuManager.uiManager.draw(renderer); + if (!menuManager.cutsceneHudActive_) + menuManager.uiManager.draw(renderer); if (currentLocation) { currentLocation->dialogueSystem.draw(renderer); } - + glEnable(GL_BLEND); + menuManager.topUiManager.draw(renderer); glDisable(GL_BLEND); renderer.shaderManager.PopShader(); @@ -619,6 +634,7 @@ namespace ZL updateDarklandsFlash(delta); menuManager.uiManager.update(static_cast(delta)); + menuManager.topUiManager.update(static_cast(delta)); if (currentLocation) { @@ -1029,11 +1045,13 @@ namespace ZL const int uiX = mx; const int uiY = Environment::projectionHeight - my; + menuManager.topUiManager.onTouchDown(fingerId, uiX, uiY); + const bool capturedByTopUi = menuManager.topUiManager.isUiInteractionForFinger(fingerId); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive(); - if (!dialogueActive) { + if (!dialogueActive && !capturedByTopUi) { menuManager.uiManager.onTouchDown(fingerId, uiX, uiY); } - st.capturedByUi = !dialogueActive && menuManager.uiManager.isUiInteractionForFinger(fingerId); + st.capturedByUi = capturedByTopUi || (!dialogueActive && menuManager.uiManager.isUiInteractionForFinger(fingerId)); activePointers[fingerId] = st; @@ -1064,6 +1082,7 @@ namespace ZL { const int uiX = mx; const int uiY = Environment::projectionHeight - my; + menuManager.topUiManager.onTouchUp(fingerId, uiX, uiY); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive(); if (!dialogueActive) { menuManager.uiManager.onTouchUp(fingerId, uiX, uiY); @@ -1108,6 +1127,7 @@ namespace ZL { const int uiX = mx; const int uiY = Environment::projectionHeight - my; + menuManager.topUiManager.onTouchMove(fingerId, uiX, uiY); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive(); if (!dialogueActive) { menuManager.uiManager.onTouchMove(fingerId, uiX, uiY); diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 301b3ed..15dbb7d 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -100,7 +100,7 @@ namespace ZL { hudUniIntFullRoot = loadUiFromFile("resources/w/ui/hud_uni_int_full.json", renderer, zipFile); hudUniIntDarkFullRoot = loadUiFromFile("resources/w/ui/hud_uni_int_dark_full.json", renderer, zipFile); hudUniExtDarkRoot = loadUiFromFile("resources/w/ui/hud_uni_ext_dark.json", renderer, zipFile); - + hudCutsceneRoot_ = loadUiFromFile("resources/w/ui/hud_cutscene.json", renderer, zipFile); phoneMainRoot = loadUiFromFile("resources/w/ui/screen_phone.json", renderer, zipFile); phoneBankRoot = loadUiFromFile("resources/w/ui/screen_phone_bank.json", renderer, zipFile); @@ -896,6 +896,21 @@ namespace ZL { applyCurrentHealthBar(); } + void MenuManager::onCutsceneStarted() { + cutsceneHudActive_ = true; + topUiManager.replaceRoot(hudCutsceneRoot_); + topUiManager.setButtonCallback("skipButton", [this](const std::string&) { + if (skipCutsceneFunc) skipCutsceneFunc(); + }); + } + + void MenuManager::onCutsceneFinished() { + cutsceneHudActive_ = false; + topUiManager.replaceRoot(nullptr); + if (state == GameState::Gameplay) + onLocationChanged(currentLocationName_); + } + void MenuManager::applyCurrentHealthBar() { if (currentPlayerMaxHp_ <= 0.f) return; const float fraction = std::clamp(currentPlayerHp_ / currentPlayerMaxHp_, 0.f, 1.f); diff --git a/src/MenuManager.h b/src/MenuManager.h index 22f564f..4b5387c 100644 --- a/src/MenuManager.h +++ b/src/MenuManager.h @@ -33,6 +33,7 @@ namespace ZL { class MenuManager { public: UiManager uiManager; + UiManager topUiManager; ZL::Quest::QuestJournal questJournal; // Global night mode state — persists across location transitions. @@ -69,6 +70,7 @@ namespace ZL { std::function startDarklandsTransitionFunc; std::function startNightTransitionFunc; std::function chatOpenCallback; + std::function skipCutsceneFunc; // Called when a chat message bubble should be shown (text + direction) void onChatBubbleReady(const std::string& text, bool incoming); @@ -84,6 +86,10 @@ namespace ZL { // Called by Game when the player's HP changes. Stores values and updates HUD. void updateHealthBar(float hp, float maxHp); + void onCutsceneStarted(); + void onCutsceneFinished(); + bool cutsceneHudActive_ = false; + TutorialStep tutorialStep = TutorialStep::Step0; protected: @@ -141,6 +147,7 @@ namespace ZL { std::shared_ptr hudUniIntStep13Root; std::shared_ptr hudUniIntDarkFullRoot; std::shared_ptr hudUniExtDarkRoot; + std::shared_ptr hudCutsceneRoot_; std::shared_ptr phoneMainRoot; std::shared_ptr phoneBankRoot; std::shared_ptr phoneVideoRoot; diff --git a/src/UiManager.cpp b/src/UiManager.cpp index 4b7b2de..16a2d50 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -934,14 +934,6 @@ namespace ZL { void UiManager::replaceRoot(std::shared_ptr newRoot) { root = newRoot; - layoutNode( - root, - 0.0f, 0.0f, // parentX, parentY (экран начинается с 0,0) - Environment::projectionWidth, // parentW - Environment::projectionHeight, // parentH - root->localX, // finalLocalX - root->localY // finalLocalY - ); buttons.clear(); textButtons.clear(); allInteractives.clear(); @@ -952,10 +944,20 @@ namespace ZL { chatBubbles.clear(); pulsingNodes.clear(); popInNodes.clear(); - collectButtonsAndSliders(root); - nodeActiveAnims.clear(); + if (!root) return; + + layoutNode( + root, + 0.0f, 0.0f, + Environment::projectionWidth, + Environment::projectionHeight, + root->localX, + root->localY + ); + collectButtonsAndSliders(root); + for (auto& b : buttons) { b->buildMesh(); } diff --git a/src/dialogue/DialogueSystem.cpp b/src/dialogue/DialogueSystem.cpp index 9604d53..e9988d6 100644 --- a/src/dialogue/DialogueSystem.cpp +++ b/src/dialogue/DialogueSystem.cpp @@ -4,6 +4,10 @@ namespace ZL::Dialogue { bool DialogueSystem::init(Renderer& renderer, const std::string& zipFile) { runtime.setDatabase(&database); + runtime.setOnCutsceneFinished([this](const std::string& id) { + if (onCutsceneFinishedCallback) onCutsceneFinishedCallback(id); + if (onCutsceneFinishedExtraCallback) onCutsceneFinishedExtraCallback(id); + }); return overlay.init(renderer, zipFile); } @@ -121,11 +125,25 @@ bool DialogueSystem::startDialogue(const std::string& dialogueId) { } bool DialogueSystem::startCutscene(const std::string& cutsceneId) { - return runtime.startStandaloneCutscene(cutsceneId); + bool result = runtime.startStandaloneCutscene(cutsceneId); + if (result && onCutsceneStartedCallback) onCutsceneStartedCallback(); + return result; +} + +void DialogueSystem::skipCutscene() { + runtime.skipCurrentCutscene(); +} + +void DialogueSystem::setOnCutsceneStarted(std::function cb) { + onCutsceneStartedCallback = std::move(cb); } void DialogueSystem::setOnCutsceneFinished(std::function cb) { - runtime.setOnCutsceneFinished(std::move(cb)); + onCutsceneFinishedCallback = std::move(cb); +} + +void DialogueSystem::setOnCutsceneFinishedExtra(std::function cb) { + onCutsceneFinishedExtraCallback = std::move(cb); } void DialogueSystem::setOnDialogueLineStarted(std::function cb) { diff --git a/src/dialogue/DialogueSystem.h b/src/dialogue/DialogueSystem.h index 28e5f15..0147d4d 100644 --- a/src/dialogue/DialogueSystem.h +++ b/src/dialogue/DialogueSystem.h @@ -24,7 +24,10 @@ public: bool startDialogue(const std::string& dialogueId); bool startCutscene(const std::string& cutsceneId); + void skipCutscene(); + void setOnCutsceneStarted(std::function cb); void setOnCutsceneFinished(std::function cb); + void setOnCutsceneFinishedExtra(std::function cb); void setOnDialogueLineStarted(std::function cb); void setOnCutsceneLineStarted(std::function cb); void setOnCutsceneFadeInComplete(std::function cb); @@ -47,6 +50,9 @@ private: DialogueRuntime runtime; DialogueOverlay overlay; std::function onDialogueAdvancedCallback; + std::function onCutsceneStartedCallback; + std::function onCutsceneFinishedCallback; + std::function onCutsceneFinishedExtraCallback; }; } // namespace ZL::Dialogue