Working on tutorial refactoring
This commit is contained in:
1 parent
ea8f64c940
commit
9fa120d4ad
82 files changed
+1877
-7563
No files matched your search
+133
-398
@@ -247,49 +247,17 @@ namespace FRG {
|
||||
}
|
||||
|
||||
void MenuManager::loadUiRoots(const std::string& zipFile) {
|
||||
hudRoot = loadLocalizedUi("resources/w/ui/hud_step0.json", zipFile);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
hudStep1Root = loadLocalizedUi("resources/w/ui/hud_step1android.json", zipFile);
|
||||
hudStep2Root = loadLocalizedUi("resources/w/ui/hud_step2android.json", zipFile);
|
||||
#else
|
||||
hudStep1Root = loadLocalizedUi("resources/w/ui/hud_step1.json", zipFile);
|
||||
hudStep2Root = loadLocalizedUi("resources/w/ui/hud_step2.json", zipFile);
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
hudStep3Root = loadLocalizedUi("resources/w/ui/hud_step3android.json", zipFile);
|
||||
hudDormRoot = loadLocalizedUi("resources/w/ui/hud_dorm_android.json", zipFile);
|
||||
hudUniIntRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_android.json", zipFile);
|
||||
hudUniIntDarkRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_dark_android.json", zipFile);
|
||||
#else
|
||||
hudStep3Root = loadLocalizedUi("resources/w/ui/hud_step3.json", zipFile);
|
||||
hudDormRoot = loadLocalizedUi("resources/w/ui/hud_dorm.json", zipFile);
|
||||
hudUniIntRoot = loadLocalizedUi("resources/w/ui/hud_uni_int.json", zipFile);
|
||||
hudUniIntDarkRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_dark.json", zipFile);
|
||||
#endif
|
||||
|
||||
hudStep4Root = loadLocalizedUi("resources/w/ui/hud_step4.json", zipFile);
|
||||
hudStep5aRoot = loadLocalizedUi("resources/w/ui/hud_step5a.json", zipFile);
|
||||
hudStep5bRoot = loadLocalizedUi("resources/w/ui/hud_step5b.json", zipFile);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
hudStep5abRoot = loadLocalizedUi("resources/w/ui/hud_step5abandroid.json", zipFile);
|
||||
#else
|
||||
hudStep5abRoot = loadLocalizedUi("resources/w/ui/hud_step5ab.json", zipFile);
|
||||
#endif
|
||||
|
||||
hudUniExtRoot = loadLocalizedUi("resources/w/ui/hud_uni_ext.json", zipFile);
|
||||
hudUniIntStep10Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step10.json", zipFile);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
hudUniIntStep11Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step11android.json", zipFile);
|
||||
#else
|
||||
hudUniIntStep11Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step11.json", zipFile);
|
||||
#endif
|
||||
hudUniIntStep12Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step12.json", zipFile);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
hudUniIntStep13Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step13android.json", zipFile);
|
||||
#else
|
||||
hudUniIntStep13Root = loadLocalizedUi("resources/w/ui/hud_uni_int_step13.json", zipFile);
|
||||
#endif
|
||||
hudUniIntFullRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_full.json", zipFile);
|
||||
hudUniIntDarkFullRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_dark_full.json", zipFile);
|
||||
hudUniExtDarkRoot = loadLocalizedUi("resources/w/ui/hud_uni_ext_dark.json", zipFile);
|
||||
hudUniExtRoot = loadLocalizedUi("resources/w/ui/hud_uni_ext.json", zipFile);
|
||||
hudUniExtDarkRoot = loadLocalizedUi("resources/w/ui/hud_uni_ext_dark.json", zipFile);
|
||||
|
||||
//hudCutsceneRoot_ = loadLocalizedUi("resources/w/ui/hud_cutscene.json", zipFile);
|
||||
hudCutsceneRoot_ = loadUiFromFile("resources/w/ui/hud_cutscene.json", renderer, zipFile);
|
||||
@@ -298,9 +266,6 @@ namespace FRG {
|
||||
hudTopHintRoot_ = loadLocalizedUi("resources/w/ui/hud_top_hint01.json", zipFile);
|
||||
|
||||
phoneMainRoot = loadLocalizedUi("resources/w/ui/screen_phone.json", zipFile);
|
||||
phoneMainHintARoot = loadLocalizedUi("resources/w/ui/screen_phone_hint001.json", zipFile);
|
||||
phoneMainHintBRoot = loadLocalizedUi("resources/w/ui/screen_phone_hint002.json", zipFile);
|
||||
phoneMainHintABRoot = loadLocalizedUi("resources/w/ui/screen_phone_hint001_002.json", zipFile);
|
||||
|
||||
phoneBankRoot = loadLocalizedUi("resources/w/ui/screen_phone_bank.json", zipFile);
|
||||
phoneVideoRoot = loadLocalizedUi("resources/w/ui/screen_phone_video.json", zipFile);
|
||||
@@ -308,18 +273,13 @@ namespace FRG {
|
||||
phoneMapUniRoot = loadLocalizedUi("resources/w/ui/screen_phone_map_uni.json", zipFile);
|
||||
|
||||
verticalPhoneMainRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone.json", zipFile);
|
||||
verticalPhoneMainHintARoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_hint001.json", zipFile);
|
||||
verticalPhoneMainHintBRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_hint002.json", zipFile);
|
||||
verticalPhoneMainHintABRoot= loadLocalizedUi("resources/w/ui/portrait_screen_phone_hint001_002.json", zipFile);
|
||||
verticalPhoneBankRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_bank.json", zipFile);
|
||||
verticalPhoneVideoRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_video.json", zipFile);
|
||||
verticalPhoneMapDormRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_map_dorm.json", zipFile);
|
||||
verticalPhoneMapUniRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_map_uni.json", zipFile);
|
||||
|
||||
phoneChatListRoot = loadLocalizedUi("resources/w/ui/screen_phone_chat_list.json", zipFile);
|
||||
phoneChatListHintRoot = loadLocalizedUi("resources/w/ui/screen_phone_chat_list_hint001.json", zipFile);
|
||||
verticalPhoneChatListRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_chat_list.json", zipFile);
|
||||
verticalPhoneChatListHintRoot = loadLocalizedUi("resources/w/ui/portrait_screen_phone_chat_list_hint001.json", zipFile);
|
||||
phoneChat1Root = loadLocalizedUi("resources/w/ui/screen_phone_chat1.json", zipFile);
|
||||
phoneChat2Root = loadLocalizedUi("resources/w/ui/screen_phone_chat2.json", zipFile);
|
||||
phoneChat3Root = loadLocalizedUi("resources/w/ui/screen_phone_chat3.json", zipFile);
|
||||
@@ -417,64 +377,83 @@ namespace FRG {
|
||||
}
|
||||
|
||||
void MenuManager::enterGameplay(bool isFromLoad) {
|
||||
if (!isFromLoad && uiState_ == GameUiState::MainMenu && startGameFunc) startGameFunc();
|
||||
uiState_ = GameUiState::Gameplay;
|
||||
uiManager.replaceRoot(hudRoot);
|
||||
topUiManager.replaceRoot(hudTopHintRoot_);
|
||||
if (isFromLoad) {
|
||||
uiManager.clearMenuStack();
|
||||
topUiManager.clearMenuStack();
|
||||
}
|
||||
|
||||
applyCurrentHealthBar();
|
||||
|
||||
uiManager.setButtonCallback("inventoryButton", [this](const std::string&) {
|
||||
openInventory();
|
||||
});
|
||||
if (uiManager.findButton("settingsButton")) {
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string&) {
|
||||
showModalMenuScreen();
|
||||
});
|
||||
}
|
||||
|
||||
if (isFromLoad)
|
||||
applyHudForCurrentState();
|
||||
// A new game resets the state on a later main-thread task, which then shows the
|
||||
// HUD itself; the main menu stays up until then. Showing the HUD now would draw
|
||||
// one frame from the previous game's state (e.g. its phone/journal buttons).
|
||||
if (!isFromLoad && uiState_ == GameUiState::MainMenu && startGameFunc)
|
||||
startGameFunc();
|
||||
else
|
||||
showGameplayHud();
|
||||
}
|
||||
|
||||
void MenuManager::applyHudForCurrentState() {
|
||||
// Clear the step-0 dialogue hint unless we're actually at step 0.
|
||||
if (gameState_.tutorialStep != TutorialStep::Step0)
|
||||
topUiManager.replaceRoot(nullptr);
|
||||
|
||||
std::shared_ptr<UiNode> MenuManager::gameplayHudRoot() const {
|
||||
const std::string& loc = gameState_.currentLocationName;
|
||||
if (loc == "uni_exterior") return gameState_.isDarklands ? hudUniExtDarkRoot : hudUniExtRoot;
|
||||
if (loc == "uni_interior") return gameState_.isDarklands ? hudUniIntDarkRoot : hudUniIntRoot;
|
||||
return hudDormRoot; // dorm, or a new game before the location is set
|
||||
}
|
||||
|
||||
// Non-dorm locations: reuse the existing location-change logic.
|
||||
if (loc == "uni_exterior" || loc == "uni_interior") {
|
||||
onLocationChanged(loc);
|
||||
return;
|
||||
void MenuManager::showGameplayHud() {
|
||||
uiState_ = GameUiState::Gameplay;
|
||||
uiManager.replaceRoot(gameplayHudRoot());
|
||||
applyCurrentHealthBar();
|
||||
setupGameplayHudCallbacks();
|
||||
refreshHudVisibility();
|
||||
}
|
||||
|
||||
void MenuManager::refreshHudVisibility() {
|
||||
if (!inventory) return; // update() already ticks during loading, before setup()
|
||||
|
||||
const TutorialStep step = gameState_.tutorialStep;
|
||||
const bool tutorial = gameState_.isTutorialActive();
|
||||
const bool hasPhone = inventory->hasItem("phone");
|
||||
const bool hasJournal = inventory->hasItem("journal");
|
||||
const bool hasNote = inventory->hasItem("note_spell");
|
||||
const bool dark = gameState_.isDarklands;
|
||||
|
||||
auto show = [this](std::initializer_list<const char*> names, bool visible) {
|
||||
for (const char* name : names) uiManager.setNodeVisible(name, visible);
|
||||
};
|
||||
|
||||
// --- HUD buttons: present while the matching item is in the inventory ---
|
||||
show({ "inventoryButton" }, inventory->getCount() > 0);
|
||||
show({ "phoneButton" }, hasPhone && !dark);
|
||||
show({ "journalButton" }, hasJournal);
|
||||
show({ "darklandsButton" }, hasNote && !dark);
|
||||
|
||||
// --- Tutorial hints ---
|
||||
// The dialogue hint lives in topUiManager so it is drawn above the dialogue.
|
||||
if (!cutsceneHudActive_) {
|
||||
auto topRoot = (step == TutorialStep::AdvanceDialogue) ? hudTopHintRoot_ : nullptr;
|
||||
if (topUiManager.getRoot() != topRoot) topUiManager.replaceRoot(topRoot);
|
||||
}
|
||||
|
||||
// Dorm (or pre-first-teleport): select HUD root by tutorial step.
|
||||
std::shared_ptr<UiNode> nextRoot;
|
||||
switch (gameState_.tutorialStep) {
|
||||
case TutorialStep::Step0: nextRoot = hudRoot; break;
|
||||
case TutorialStep::Step1: nextRoot = hudStep1Root; break;
|
||||
case TutorialStep::Step2: nextRoot = hudStep2Root; break;
|
||||
case TutorialStep::Step3: nextRoot = hudStep3Root; break;
|
||||
case TutorialStep::Step4: nextRoot = hudStep4Root; break;
|
||||
default: break; // Step5/6 handled below
|
||||
}
|
||||
// Dorm HUD: one hint per linear step...
|
||||
show({ "hint2" }, step == TutorialStep::RotateCamera);
|
||||
show({ "hint3" }, step == TutorialStep::Walk);
|
||||
show({ "hint4" }, step == TutorialStep::Zoom);
|
||||
show({ "hint5" }, step == TutorialStep::PickUpItem);
|
||||
// ...then the hints for the picked-up items, which can be done in any order.
|
||||
const bool chatHint = tutorial && !gameState_.tutorialPhoneChatScreenOpened;
|
||||
const bool journalHint = tutorial && !gameState_.tutorialJournalScreenOpened;
|
||||
const bool taxiHint = tutorial && gameState_.tutorialNeedOpenTaxiScreen;
|
||||
show({ "hint6a", "hint6aarrow" }, hasPhone && chatHint && !taxiHint);
|
||||
show({ "hint6b", "hint6barrow" }, hasJournal && journalHint);
|
||||
show({ "hint7", "hint7arrow" }, taxiHint);
|
||||
|
||||
if (nextRoot) {
|
||||
uiManager.replaceRoot(nextRoot);
|
||||
applyCurrentHealthBar();
|
||||
uiManager.setButtonCallback("inventoryButton", [this](const std::string&) { openInventory(); });
|
||||
if (uiManager.findButton("settingsButton"))
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string&) { showModalMenuScreen(); });
|
||||
} else {
|
||||
// Step5 or Step6: pick the right variant and apply hint visibility.
|
||||
refreshItemPickupHud();
|
||||
}
|
||||
// Phone screens.
|
||||
show({ "hint_m001", "hint_m001arrow" }, chatHint); // main screen: open the messenger
|
||||
show({ "hint_m003", "hint_m003arrow" }, taxiHint); // main screen: open the taxi app
|
||||
show({ "hint_m002" }, chatHint); // chat list: open a chat
|
||||
|
||||
// University interior HUDs.
|
||||
show({ "hint_darklands001", "hint_darklands001_arrow" }, step == TutorialStep::EnterDarklands && hasNote);
|
||||
show({ "hint_darklands003", "hint_darklands003_arrow" }, step == TutorialStep::DarklandsHealth);
|
||||
show({ "hint_darklands002" }, step == TutorialStep::DarklandsAttack);
|
||||
}
|
||||
|
||||
void MenuManager::showMainMenu() {
|
||||
@@ -762,12 +741,35 @@ namespace FRG {
|
||||
uiManager.setTextButtonCallback("soundToggleButton", [this](const std::string&) {
|
||||
audioPlayer_.setSoundEnabled(!audioPlayer_.isSoundEnabled());
|
||||
const bool on = audioPlayer_.isSoundEnabled();
|
||||
uiManager.setTextButtonText("soundToggleButton", on ? soundToggleOn : soundToggleOff);
|
||||
uiManager.setTextButtonText("soundToggleButton", on ? soundToggleOn : soundToggleOff);
|
||||
/*uiManager.setTextButtonColor("soundToggleButton", on
|
||||
? std::array<float, 4>{ 0.2f, 0.9f, 0.2f, 1.0f }
|
||||
: std::array<float, 4>{ 0.9f, 0.2f, 0.2f, 1.0f });*/
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
});
|
||||
|
||||
setupTutorialToggle();
|
||||
}
|
||||
|
||||
// Tutorial on/off button shared by the settings screens — takes effect on the next new game only.
|
||||
void MenuManager::setupTutorialToggle() {
|
||||
if (g_currentLanguage == Language::English)
|
||||
{
|
||||
tutorialToggleOn = "Tutorial: ON";
|
||||
tutorialToggleOff = "Tutorial: OFF";
|
||||
}
|
||||
else if (g_currentLanguage == Language::Russian)
|
||||
{
|
||||
tutorialToggleOn = u8"Обучение: ВКЛ";
|
||||
tutorialToggleOff = u8"Обучение: ВЫКЛ";
|
||||
}
|
||||
|
||||
uiManager.setTextButtonText("tutorialToggleButton", tutorialEnabledSetting ? tutorialToggleOn : tutorialToggleOff);
|
||||
uiManager.setTextButtonCallback("tutorialToggleButton", [this](const std::string&) {
|
||||
tutorialEnabledSetting = !tutorialEnabledSetting;
|
||||
uiManager.setTextButtonText("tutorialToggleButton", tutorialEnabledSetting ? tutorialToggleOn : tutorialToggleOff);
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
});
|
||||
}
|
||||
|
||||
void MenuManager::showSettingsGraphicsScreen() {
|
||||
@@ -956,6 +958,8 @@ namespace FRG {
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
});
|
||||
|
||||
setupTutorialToggle();
|
||||
|
||||
uiManager.setTextButtonCallback("musicDownloadButton", [this](const std::string&) {
|
||||
if (musicDownloadStarted) return; // Already downloading, ignore further clicks
|
||||
|
||||
@@ -1264,9 +1268,6 @@ namespace FRG {
|
||||
gameState_.tutorialJournalScreenOpened = true;
|
||||
journalMenuStackDepth_ = 1;
|
||||
|
||||
uiManager.setNodeVisible("hint6b", false);
|
||||
uiManager.setNodeVisible("hint6barrow", false);
|
||||
|
||||
const bool portrait = isPortraitMode();
|
||||
uiManager.pushMenuFromSavedRoot(portrait ? portraitQuestJournalListRoot : questJournalRoot);
|
||||
|
||||
@@ -1330,24 +1331,8 @@ namespace FRG {
|
||||
uiState_ = GameUiState::PhoneScreen;
|
||||
currentPhoneSubScreen_ = PhoneSubScreen::Main;
|
||||
|
||||
if (isPortraitMode()) {
|
||||
if (gameState_.tutorialNeedOpenTaxiScreen && (gameState_.tutorialPhoneChatScreenOpened == false))
|
||||
uiManager.pushMenuFromSavedRoot(verticalPhoneMainHintABRoot);
|
||||
else if (gameState_.tutorialNeedOpenTaxiScreen)
|
||||
uiManager.pushMenuFromSavedRoot(verticalPhoneMainHintBRoot);
|
||||
else if (gameState_.tutorialPhoneChatScreenOpened == false)
|
||||
uiManager.pushMenuFromSavedRoot(verticalPhoneMainHintARoot);
|
||||
else
|
||||
uiManager.pushMenuFromSavedRoot(verticalPhoneMainRoot);
|
||||
} else if (gameState_.tutorialNeedOpenTaxiScreen && (gameState_.tutorialPhoneChatScreenOpened == false)) {
|
||||
uiManager.pushMenuFromSavedRoot(phoneMainHintABRoot);
|
||||
} else if (gameState_.tutorialNeedOpenTaxiScreen) {
|
||||
uiManager.pushMenuFromSavedRoot(phoneMainHintBRoot);
|
||||
} else if (gameState_.tutorialPhoneChatScreenOpened == false) {
|
||||
uiManager.pushMenuFromSavedRoot(phoneMainHintARoot);
|
||||
} else {
|
||||
uiManager.pushMenuFromSavedRoot(phoneMainRoot);
|
||||
}
|
||||
uiManager.pushMenuFromSavedRoot(isPortraitMode() ? verticalPhoneMainRoot : phoneMainRoot);
|
||||
refreshHudVisibility();
|
||||
|
||||
|
||||
uiManager.setButtonCallback("phoneExitButton", [this](const std::string&) {
|
||||
@@ -1400,14 +1385,8 @@ namespace FRG {
|
||||
void MenuManager::openPhoneMessenger() {
|
||||
currentPhoneSubScreen_ = PhoneSubScreen::ChatList;
|
||||
|
||||
if (gameState_.tutorialPhoneChatScreenOpened)
|
||||
{
|
||||
uiManager.pushMenuFromSavedRoot(isPortraitMode() ? verticalPhoneChatListRoot : phoneChatListRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.pushMenuFromSavedRoot(isPortraitMode() ? verticalPhoneChatListHintRoot : phoneChatListHintRoot);
|
||||
}
|
||||
uiManager.pushMenuFromSavedRoot(isPortraitMode() ? verticalPhoneChatListRoot : phoneChatListRoot);
|
||||
refreshHudVisibility();
|
||||
refreshChatUnreadIndicators();
|
||||
|
||||
uiManager.setButtonCallback("phoneExitButton", [this](const std::string&) {
|
||||
@@ -1625,14 +1604,7 @@ namespace FRG {
|
||||
chatFrameBuffer_.reset();
|
||||
uiManager.popMenu();
|
||||
uiManager.updateAllLayouts();
|
||||
if (gameState_.tutorialPhoneChatScreenOpened)
|
||||
{
|
||||
uiManager.setNodeVisible("hint_m002", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.setNodeVisible("hint_m002", true);
|
||||
}
|
||||
refreshHudVisibility();
|
||||
refreshChatUnreadIndicators();
|
||||
}
|
||||
|
||||
@@ -1652,31 +1624,7 @@ namespace FRG {
|
||||
const int depth = uiManager.menuStackSize();
|
||||
for (int i = 0; i < depth; ++i) uiManager.popMenu();
|
||||
uiManager.updateAllLayouts();
|
||||
|
||||
if (gameState_.tutorialNeedOpenTaxiScreen)
|
||||
{
|
||||
uiManager.setNodeVisible("hint7", true);
|
||||
uiManager.setNodeVisible("hint7arrow", true);
|
||||
|
||||
uiManager.setNodeVisible("hint6a", false);
|
||||
uiManager.setNodeVisible("hint6aarrow", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.setNodeVisible("hint7", false);
|
||||
uiManager.setNodeVisible("hint7arrow", false);
|
||||
|
||||
if (gameState_.tutorialPhoneChatScreenOpened)
|
||||
{
|
||||
uiManager.setNodeVisible("hint6a", false);
|
||||
uiManager.setNodeVisible("hint6aarrow", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.setNodeVisible("hint6a", true);
|
||||
uiManager.setNodeVisible("hint6aarrow", true);
|
||||
}
|
||||
}
|
||||
refreshHudVisibility();
|
||||
}
|
||||
|
||||
void MenuManager::closePhoneScreenFromChat() {
|
||||
@@ -1727,80 +1675,9 @@ namespace FRG {
|
||||
void MenuManager::tutorialShowTaxiHint()
|
||||
{
|
||||
logger() << "tutorialShowTaxiHint" << std::endl;
|
||||
gameState_.tutorialNeedOpenTaxiScreen = true;
|
||||
if (uiState_ == GameUiState::Gameplay)
|
||||
{
|
||||
uiManager.setNodeVisible("hint6a", false);
|
||||
uiManager.setNodeVisible("hint6aarrow", false);
|
||||
|
||||
uiManager.setNodeVisible("hint7", true);
|
||||
uiManager.setNodeVisible("hint7arrow", true);
|
||||
}
|
||||
}
|
||||
|
||||
// Registers phoneButton / journalButton callbacks on the current HUD root
|
||||
// and hides any hints that have already been completed.
|
||||
// Called after every replaceRoot during step 5.
|
||||
void MenuManager::setupStep5Callbacks() {
|
||||
if (uiManager.findButton("phoneButton")) {
|
||||
uiManager.setButtonCallback("phoneButton", [this](const std::string&) {
|
||||
openPhoneScreen();
|
||||
});
|
||||
}
|
||||
if (uiManager.findButton("inventoryButton")) {
|
||||
uiManager.setButtonCallback("inventoryButton", [this](const std::string&) {
|
||||
openInventory();
|
||||
});
|
||||
}
|
||||
if (uiManager.findButton("journalButton")) {
|
||||
uiManager.setButtonCallback("journalButton", [this](const std::string&) {
|
||||
openQuestJournal();
|
||||
});
|
||||
}
|
||||
if (uiManager.findButton("settingsButton")) {
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string&) {
|
||||
showModalMenuScreen();
|
||||
});
|
||||
}
|
||||
if (gameState_.tutorialNeedOpenTaxiScreen)
|
||||
{
|
||||
uiManager.setNodeVisible("hint6a", false);
|
||||
uiManager.setNodeVisible("hint6aarrow", false);
|
||||
|
||||
uiManager.setNodeVisible("hint7", true);
|
||||
uiManager.setNodeVisible("hint7arrow", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.setNodeVisible("hint7", false);
|
||||
uiManager.setNodeVisible("hint7arrow", false);
|
||||
}
|
||||
|
||||
if (gameState_.tutorialPhoneChatScreenOpened) {
|
||||
uiManager.setNodeVisible("hint6a", false);
|
||||
uiManager.setNodeVisible("hint6aarrow", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gameState_.tutorialNeedOpenTaxiScreen)
|
||||
{
|
||||
uiManager.setNodeVisible("hint6a", true);
|
||||
uiManager.setNodeVisible("hint6aarrow", true);
|
||||
}
|
||||
}
|
||||
if (gameState_.tutorialJournalScreenOpened)
|
||||
{
|
||||
uiManager.setNodeVisible("hint6b", false);
|
||||
uiManager.setNodeVisible("hint6barrow", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiManager.setNodeVisible("hint6b", true);
|
||||
uiManager.setNodeVisible("hint6barrow", true);
|
||||
}
|
||||
if (gameState_.tutorialPhoneChatScreenOpened && gameState_.tutorialJournalScreenOpened) {
|
||||
gameState_.tutorialStep = TutorialStep::Step6;
|
||||
}
|
||||
if (!gameState_.isTutorialActive()) return;
|
||||
gameState_.tutorialNeedOpenTaxiScreen = true; // cleared when the taxi is ordered
|
||||
refreshHudVisibility();
|
||||
}
|
||||
|
||||
void MenuManager::setupGameplayHudCallbacks() {
|
||||
@@ -1823,28 +1700,9 @@ namespace FRG {
|
||||
void MenuManager::onLocationChanged(const std::string& locationName) {
|
||||
if (uiState_ != GameUiState::Gameplay) return;
|
||||
gameState_.currentLocationName = locationName;
|
||||
showGameplayHud();
|
||||
|
||||
if (locationName == "uni_exterior") {
|
||||
uiManager.replaceRoot(gameState_.isDarklands ? hudUniExtDarkRoot : hudUniExtRoot);
|
||||
applyCurrentHealthBar();
|
||||
setupGameplayHudCallbacks();
|
||||
if (gameState_.isDarklands)
|
||||
{
|
||||
audioPlayer_.crossFadeMusicAsync("music/bishkek fight calm.ogg");
|
||||
lastMusicTrack = "music/bishkek fight calm.ogg";
|
||||
}
|
||||
else if (gameState_.isNight)
|
||||
{
|
||||
audioPlayer_.crossFadeMusicAsync("music/bishkek night.ogg");
|
||||
lastMusicTrack = "music/bishkek night.ogg";
|
||||
}
|
||||
else
|
||||
{
|
||||
audioPlayer_.crossFadeMusicAsync("music/bishkek univer day.ogg");
|
||||
lastMusicTrack = "music/bishkek univer day.ogg";
|
||||
}
|
||||
} else if (locationName == "uni_interior") {
|
||||
applyUniIntHud();
|
||||
if (locationName == "uni_exterior" || locationName == "uni_interior") {
|
||||
if (gameState_.isDarklands)
|
||||
{
|
||||
audioPlayer_.crossFadeMusicAsync("music/bishkek fight calm.ogg");
|
||||
@@ -1861,11 +1719,6 @@ namespace FRG {
|
||||
lastMusicTrack = "music/bishkek univer day.ogg";
|
||||
}
|
||||
} else {
|
||||
// Returning to dorm: reuse step5ab, suppress already-completed hints
|
||||
uiManager.replaceRoot(hudStep5abRoot);
|
||||
applyCurrentHealthBar();
|
||||
setupStep5Callbacks();
|
||||
|
||||
if (gameState_.isNight)
|
||||
{
|
||||
audioPlayer_.crossFadeMusicAsync("music/bishkek night.ogg");
|
||||
@@ -1879,96 +1732,11 @@ namespace FRG {
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::advanceTutorialStep() {
|
||||
std::shared_ptr<UiNode> nextRoot;
|
||||
|
||||
switch (gameState_.tutorialStep) {
|
||||
case TutorialStep::Step0:
|
||||
gameState_.tutorialStep = TutorialStep::Step1;
|
||||
nextRoot = hudStep1Root;
|
||||
topUiManager.replaceRoot(nullptr);
|
||||
break;
|
||||
case TutorialStep::Step1:
|
||||
gameState_.tutorialStep = TutorialStep::Step2;
|
||||
nextRoot = hudStep2Root;
|
||||
break;
|
||||
case TutorialStep::Step2:
|
||||
gameState_.tutorialStep = TutorialStep::Step3;
|
||||
nextRoot = hudStep3Root;
|
||||
break;
|
||||
case TutorialStep::Step3:
|
||||
gameState_.tutorialStep = TutorialStep::Step4;
|
||||
nextRoot = hudStep4Root;
|
||||
if (tutorialUnlockInteractiveObjectsFunc)
|
||||
{
|
||||
tutorialUnlockInteractiveObjectsFunc();
|
||||
tutorialUnlockInteractiveObjectsFunc = nullptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return; // Step4/Step5 transitions are driven by onItemPickedUp
|
||||
}
|
||||
|
||||
if (uiState_ == GameUiState::Gameplay && nextRoot) {
|
||||
uiManager.replaceRoot(nextRoot);
|
||||
applyCurrentHealthBar();
|
||||
|
||||
uiManager.setButtonCallback("inventoryButton", [this](const std::string&) {
|
||||
openInventory();
|
||||
});
|
||||
if (uiManager.findButton("settingsButton")) {
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string&) {
|
||||
showModalMenuScreen();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::onItemPickedUp(const std::string& itemId) {
|
||||
if (itemId == "note_spell" && gameState_.uniIntTutorialState == UniIntTutorialState::Step10) {
|
||||
gameState_.uniIntTutorialState = UniIntTutorialState::Step11;
|
||||
if (gameState_.currentLocationName == "uni_interior" && uiState_ == GameUiState::Gameplay)
|
||||
applyUniIntHud();
|
||||
}
|
||||
|
||||
if (gameState_.tutorialStep != TutorialStep::Step4 && gameState_.tutorialStep != TutorialStep::Step5) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dorm tutorial HUD logic must not run in other locations.
|
||||
// currentLocationName is empty only before the first teleport (still in dorm).
|
||||
if (!gameState_.currentLocationName.empty() && gameState_.currentLocationName != "location_dorm") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemId == "phone") gameState_.tutorialPhonePickedUp = true;
|
||||
if (itemId == "journal") gameState_.tutorialJournalPickedUp = true;
|
||||
|
||||
if (gameState_.tutorialStep == TutorialStep::Step4) {
|
||||
gameState_.tutorialStep = TutorialStep::Step5;
|
||||
}
|
||||
|
||||
refreshItemPickupHud();
|
||||
}
|
||||
|
||||
void MenuManager::refreshItemPickupHud() {
|
||||
if (uiState_ != GameUiState::Gameplay) return;
|
||||
|
||||
std::shared_ptr<UiNode> nextRoot;
|
||||
if (gameState_.tutorialPhonePickedUp && gameState_.tutorialJournalPickedUp) {
|
||||
nextRoot = hudStep5abRoot;
|
||||
} else if (gameState_.tutorialPhonePickedUp) {
|
||||
nextRoot = hudStep5aRoot;
|
||||
} else if (gameState_.tutorialJournalPickedUp) {
|
||||
nextRoot = hudStep5bRoot;
|
||||
}
|
||||
|
||||
if (nextRoot) {
|
||||
uiManager.replaceRoot(nextRoot);
|
||||
applyCurrentHealthBar();
|
||||
// Register item-screen buttons and re-apply any already-completed hint visibility.
|
||||
setupStep5Callbacks();
|
||||
}
|
||||
// The new item's HUD button appears through refreshHudVisibility().
|
||||
if (itemId == "phone" || itemId == "journal")
|
||||
gameState_.completeTutorialStep(TutorialStep::PickUpItem);
|
||||
refreshHudVisibility();
|
||||
}
|
||||
|
||||
void MenuManager::refreshQuestJournalUi() {
|
||||
@@ -2351,70 +2119,32 @@ namespace FRG {
|
||||
{
|
||||
logger() << "MenuManager::setDarklandsMode called" << std::endl;
|
||||
|
||||
if (gameState_.currentLocationName == "uni_interior") {
|
||||
if (enabled && gameState_.uniIntTutorialState == UniIntTutorialState::Step11) {
|
||||
gameState_.uniIntTutorialState = UniIntTutorialState::DarklandsActive;
|
||||
}
|
||||
applyUniIntHud();
|
||||
} else if (gameState_.currentLocationName == "uni_exterior") {
|
||||
if (uiState_ == GameUiState::Gameplay) {
|
||||
uiManager.replaceRoot(enabled ? hudUniExtDarkRoot : hudUniExtRoot);
|
||||
applyCurrentHealthBar();
|
||||
setupGameplayHudCallbacks();
|
||||
}
|
||||
} else {
|
||||
uiManager.setNodeVisible("darklandsButton", !enabled);
|
||||
uiManager.setNodeVisible("phoneButton", !enabled);
|
||||
}
|
||||
}
|
||||
if (enabled && gameState_.currentLocationName == "uni_interior" && inventory->hasItem("note_spell"))
|
||||
gameState_.completeTutorialStep(TutorialStep::EnterDarklands);
|
||||
|
||||
void MenuManager::applyUniIntHud()
|
||||
{
|
||||
if (uiState_ != GameUiState::Gameplay) return;
|
||||
std::shared_ptr<UiNode> root;
|
||||
if (gameState_.isDarklands) {
|
||||
switch (gameState_.uniIntTutorialState) {
|
||||
case UniIntTutorialState::DarklandsStep13: root = hudUniIntStep13Root; break;
|
||||
case UniIntTutorialState::DarklandsFull: root = hudUniIntDarkFullRoot; break;
|
||||
default: root = hudUniIntStep12Root; break;
|
||||
}
|
||||
} else {
|
||||
switch (gameState_.uniIntTutorialState) {
|
||||
case UniIntTutorialState::Step10: root = hudUniIntStep10Root; break;
|
||||
case UniIntTutorialState::Step11: root = hudUniIntStep11Root; break;
|
||||
default: root = hudUniIntFullRoot; break;
|
||||
}
|
||||
}
|
||||
uiManager.replaceRoot(root);
|
||||
applyCurrentHealthBar();
|
||||
setupGameplayHudCallbacks();
|
||||
if (uiState_ == GameUiState::Gameplay)
|
||||
showGameplayHud(); // darklands has its own HUD layouts
|
||||
}
|
||||
|
||||
void MenuManager::onPlayerStartedWalking()
|
||||
{
|
||||
if (gameState_.currentLocationName == "uni_interior"
|
||||
&& gameState_.isDarklands
|
||||
&& gameState_.uniIntTutorialState == UniIntTutorialState::DarklandsActive) {
|
||||
uiManager.setNodeVisible("hint_darklands003", false);
|
||||
uiManager.setNodeVisible("hint_darklands003_arrow", false);
|
||||
}
|
||||
if (gameState_.currentLocationName == "uni_interior" && gameState_.isDarklands)
|
||||
gameState_.completeTutorialStep(TutorialStep::DarklandsHealth);
|
||||
}
|
||||
|
||||
void MenuManager::advanceUniIntDarklandsHud()
|
||||
{
|
||||
if (gameState_.uniIntTutorialState != UniIntTutorialState::DarklandsActive) return;
|
||||
gameState_.uniIntTutorialState = UniIntTutorialState::DarklandsStep13;
|
||||
if (gameState_.currentLocationName == "uni_interior" && gameState_.isDarklands && uiState_ == GameUiState::Gameplay)
|
||||
applyUniIntHud();
|
||||
// The ghost zone can be reached without a floor tap (DarklandsHealth never completed).
|
||||
if (gameState_.tutorialStep == TutorialStep::DarklandsHealth
|
||||
|| gameState_.tutorialStep == TutorialStep::DarklandsExplore)
|
||||
gameState_.tutorialStep = TutorialStep::DarklandsAttack;
|
||||
}
|
||||
|
||||
void MenuManager::onEnemyKilledInUniInterior()
|
||||
{
|
||||
if (gameState_.uniIntTutorialState != UniIntTutorialState::DarklandsActive
|
||||
&& gameState_.uniIntTutorialState != UniIntTutorialState::DarklandsStep13) return;
|
||||
gameState_.uniIntTutorialState = UniIntTutorialState::DarklandsFull;
|
||||
if (gameState_.currentLocationName == "uni_interior" && gameState_.isDarklands && uiState_ == GameUiState::Gameplay)
|
||||
applyUniIntHud();
|
||||
// The last tutorial step; like the attack hint, also ends the earlier darklands hints.
|
||||
if (gameState_.tutorialStep >= TutorialStep::DarklandsHealth)
|
||||
gameState_.tutorialStep = TutorialStep::Completed;
|
||||
}
|
||||
|
||||
void MenuManager::updateHealthBar(float hp, float maxHp) {
|
||||
@@ -2554,6 +2284,8 @@ namespace FRG {
|
||||
void MenuManager::update(float deltaMs) {
|
||||
updateToasts(deltaMs);
|
||||
chatUiManager.update(deltaMs);
|
||||
if (uiState_ != GameUiState::MainMenu && uiState_ != GameUiState::About)
|
||||
refreshHudVisibility();
|
||||
}
|
||||
|
||||
void MenuManager::drawChatFbo(Renderer& renderer) {
|
||||
@@ -2615,6 +2347,7 @@ namespace FRG {
|
||||
root["fullscreen"] = Environment::isFullscreen;
|
||||
root["language"] = FRG::languageToCode(FRG::g_currentLanguage);
|
||||
root["shadow"] = shadowsEnabled;
|
||||
root["tutorial"] = tutorialEnabledSetting;
|
||||
|
||||
saveJsonToFile(root, "settings.json");
|
||||
}
|
||||
@@ -2646,6 +2379,8 @@ namespace FRG {
|
||||
Environment::setFullscreen(root["fullscreen"].get<bool>());
|
||||
#endif
|
||||
}
|
||||
if (root.contains("tutorial"))
|
||||
tutorialEnabledSetting = root["tutorial"].get<bool>();
|
||||
if (root.contains("shadow")) {
|
||||
if (shadowMapSettingsChangedFunc)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user