Working on cutscene skip

This commit is contained in:
Vladislav Khorev 2026-06-06 21:21:56 +03:00
parent c991b5dbc1
commit 7011bbb754
16 changed files with 112 additions and 17 deletions

BIN
resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene1/cutscene1_heads_x.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene1/cutscene1_wall_x.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr1.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr2.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr3.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr4.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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 = locations["location_dorm"];
currentLocation->scriptEngine.callLocationEnterCallback(); currentLocation->scriptEngine.callLocationEnterCallback();
@ -498,12 +511,14 @@ namespace ZL
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
glEnable(GL_BLEND); glEnable(GL_BLEND);
if (!menuManager.cutsceneHudActive_)
menuManager.uiManager.draw(renderer); menuManager.uiManager.draw(renderer);
if (currentLocation) if (currentLocation)
{ {
currentLocation->dialogueSystem.draw(renderer); currentLocation->dialogueSystem.draw(renderer);
} }
glEnable(GL_BLEND);
menuManager.topUiManager.draw(renderer);
glDisable(GL_BLEND); glDisable(GL_BLEND);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
@ -619,6 +634,7 @@ namespace ZL
updateDarklandsFlash(delta); updateDarklandsFlash(delta);
menuManager.uiManager.update(static_cast<float>(delta)); menuManager.uiManager.update(static_cast<float>(delta));
menuManager.topUiManager.update(static_cast<float>(delta));
if (currentLocation) if (currentLocation)
{ {
@ -1029,11 +1045,13 @@ namespace ZL
const int uiX = mx; const int uiX = mx;
const int uiY = Environment::projectionHeight - my; 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(); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive();
if (!dialogueActive) { if (!dialogueActive && !capturedByTopUi) {
menuManager.uiManager.onTouchDown(fingerId, uiX, uiY); menuManager.uiManager.onTouchDown(fingerId, uiX, uiY);
} }
st.capturedByUi = !dialogueActive && menuManager.uiManager.isUiInteractionForFinger(fingerId); st.capturedByUi = capturedByTopUi || (!dialogueActive && menuManager.uiManager.isUiInteractionForFinger(fingerId));
activePointers[fingerId] = st; activePointers[fingerId] = st;
@ -1064,6 +1082,7 @@ namespace ZL
{ {
const int uiX = mx; const int uiX = mx;
const int uiY = Environment::projectionHeight - my; const int uiY = Environment::projectionHeight - my;
menuManager.topUiManager.onTouchUp(fingerId, uiX, uiY);
const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive(); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive();
if (!dialogueActive) { if (!dialogueActive) {
menuManager.uiManager.onTouchUp(fingerId, uiX, uiY); menuManager.uiManager.onTouchUp(fingerId, uiX, uiY);
@ -1108,6 +1127,7 @@ namespace ZL
{ {
const int uiX = mx; const int uiX = mx;
const int uiY = Environment::projectionHeight - my; const int uiY = Environment::projectionHeight - my;
menuManager.topUiManager.onTouchMove(fingerId, uiX, uiY);
const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive(); const bool dialogueActive = currentLocation && currentLocation->dialogueSystem.isActive();
if (!dialogueActive) { if (!dialogueActive) {
menuManager.uiManager.onTouchMove(fingerId, uiX, uiY); menuManager.uiManager.onTouchMove(fingerId, uiX, uiY);

View File

@ -100,7 +100,7 @@ namespace ZL {
hudUniIntFullRoot = loadUiFromFile("resources/w/ui/hud_uni_int_full.json", renderer, zipFile); 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); 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); 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); phoneMainRoot = loadUiFromFile("resources/w/ui/screen_phone.json", renderer, zipFile);
phoneBankRoot = loadUiFromFile("resources/w/ui/screen_phone_bank.json", renderer, zipFile); phoneBankRoot = loadUiFromFile("resources/w/ui/screen_phone_bank.json", renderer, zipFile);
@ -896,6 +896,21 @@ namespace ZL {
applyCurrentHealthBar(); 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() { void MenuManager::applyCurrentHealthBar() {
if (currentPlayerMaxHp_ <= 0.f) return; if (currentPlayerMaxHp_ <= 0.f) return;
const float fraction = std::clamp(currentPlayerHp_ / currentPlayerMaxHp_, 0.f, 1.f); const float fraction = std::clamp(currentPlayerHp_ / currentPlayerMaxHp_, 0.f, 1.f);

View File

@ -33,6 +33,7 @@ namespace ZL {
class MenuManager { class MenuManager {
public: public:
UiManager uiManager; UiManager uiManager;
UiManager topUiManager;
ZL::Quest::QuestJournal questJournal; ZL::Quest::QuestJournal questJournal;
// Global night mode state — persists across location transitions. // Global night mode state — persists across location transitions.
@ -69,6 +70,7 @@ namespace ZL {
std::function<void()> startDarklandsTransitionFunc; std::function<void()> startDarklandsTransitionFunc;
std::function<void()> startNightTransitionFunc; std::function<void()> startNightTransitionFunc;
std::function<void(int)> chatOpenCallback; std::function<void(int)> chatOpenCallback;
std::function<void()> skipCutsceneFunc;
// Called when a chat message bubble should be shown (text + direction) // Called when a chat message bubble should be shown (text + direction)
void onChatBubbleReady(const std::string& text, bool incoming); 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. // Called by Game when the player's HP changes. Stores values and updates HUD.
void updateHealthBar(float hp, float maxHp); void updateHealthBar(float hp, float maxHp);
void onCutsceneStarted();
void onCutsceneFinished();
bool cutsceneHudActive_ = false;
TutorialStep tutorialStep = TutorialStep::Step0; TutorialStep tutorialStep = TutorialStep::Step0;
protected: protected:
@ -141,6 +147,7 @@ namespace ZL {
std::shared_ptr<UiNode> hudUniIntStep13Root; std::shared_ptr<UiNode> hudUniIntStep13Root;
std::shared_ptr<UiNode> hudUniIntDarkFullRoot; std::shared_ptr<UiNode> hudUniIntDarkFullRoot;
std::shared_ptr<UiNode> hudUniExtDarkRoot; std::shared_ptr<UiNode> hudUniExtDarkRoot;
std::shared_ptr<UiNode> hudCutsceneRoot_;
std::shared_ptr<UiNode> phoneMainRoot; std::shared_ptr<UiNode> phoneMainRoot;
std::shared_ptr<UiNode> phoneBankRoot; std::shared_ptr<UiNode> phoneBankRoot;
std::shared_ptr<UiNode> phoneVideoRoot; std::shared_ptr<UiNode> phoneVideoRoot;

View File

@ -934,14 +934,6 @@ namespace ZL {
void UiManager::replaceRoot(std::shared_ptr<UiNode> newRoot) { void UiManager::replaceRoot(std::shared_ptr<UiNode> newRoot) {
root = 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(); buttons.clear();
textButtons.clear(); textButtons.clear();
allInteractives.clear(); allInteractives.clear();
@ -952,10 +944,20 @@ namespace ZL {
chatBubbles.clear(); chatBubbles.clear();
pulsingNodes.clear(); pulsingNodes.clear();
popInNodes.clear(); popInNodes.clear();
collectButtonsAndSliders(root);
nodeActiveAnims.clear(); 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) { for (auto& b : buttons) {
b->buildMesh(); b->buildMesh();
} }

View File

@ -4,6 +4,10 @@ namespace ZL::Dialogue {
bool DialogueSystem::init(Renderer& renderer, const std::string& zipFile) { bool DialogueSystem::init(Renderer& renderer, const std::string& zipFile) {
runtime.setDatabase(&database); runtime.setDatabase(&database);
runtime.setOnCutsceneFinished([this](const std::string& id) {
if (onCutsceneFinishedCallback) onCutsceneFinishedCallback(id);
if (onCutsceneFinishedExtraCallback) onCutsceneFinishedExtraCallback(id);
});
return overlay.init(renderer, zipFile); return overlay.init(renderer, zipFile);
} }
@ -121,11 +125,25 @@ bool DialogueSystem::startDialogue(const std::string& dialogueId) {
} }
bool DialogueSystem::startCutscene(const std::string& cutsceneId) { 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<void()> cb) {
onCutsceneStartedCallback = std::move(cb);
} }
void DialogueSystem::setOnCutsceneFinished(std::function<void(const std::string&)> cb) { void DialogueSystem::setOnCutsceneFinished(std::function<void(const std::string&)> cb) {
runtime.setOnCutsceneFinished(std::move(cb)); onCutsceneFinishedCallback = std::move(cb);
}
void DialogueSystem::setOnCutsceneFinishedExtra(std::function<void(const std::string&)> cb) {
onCutsceneFinishedExtraCallback = std::move(cb);
} }
void DialogueSystem::setOnDialogueLineStarted(std::function<void(const std::string&)> cb) { void DialogueSystem::setOnDialogueLineStarted(std::function<void(const std::string&)> cb) {

View File

@ -24,7 +24,10 @@ public:
bool startDialogue(const std::string& dialogueId); bool startDialogue(const std::string& dialogueId);
bool startCutscene(const std::string& cutsceneId); bool startCutscene(const std::string& cutsceneId);
void skipCutscene();
void setOnCutsceneStarted(std::function<void()> cb);
void setOnCutsceneFinished(std::function<void(const std::string&)> cb); void setOnCutsceneFinished(std::function<void(const std::string&)> cb);
void setOnCutsceneFinishedExtra(std::function<void(const std::string&)> cb);
void setOnDialogueLineStarted(std::function<void(const std::string&)> cb); void setOnDialogueLineStarted(std::function<void(const std::string&)> cb);
void setOnCutsceneLineStarted(std::function<void(const std::string&)> cb); void setOnCutsceneLineStarted(std::function<void(const std::string&)> cb);
void setOnCutsceneFadeInComplete(std::function<void(const std::string&)> cb); void setOnCutsceneFadeInComplete(std::function<void(const std::string&)> cb);
@ -47,6 +50,9 @@ private:
DialogueRuntime runtime; DialogueRuntime runtime;
DialogueOverlay overlay; DialogueOverlay overlay;
std::function<void()> onDialogueAdvancedCallback; std::function<void()> onDialogueAdvancedCallback;
std::function<void()> onCutsceneStartedCallback;
std::function<void(const std::string&)> onCutsceneFinishedCallback;
std::function<void(const std::string&)> onCutsceneFinishedExtraCallback;
}; };
} // namespace ZL::Dialogue } // namespace ZL::Dialogue