#pragma once #include "render/Renderer.h" #include "Environment.h" #include "render/TextureManager.h" #include "UiManager.h" #include "items/Item.h" #include "quest/QuestJournal.h" #include #include #include #include namespace ZL { extern const char* CONST_ZIP_FILE; enum class GameState { MainMenu, About, Gameplay, Inventory, QuestJournal, PhoneScreen }; enum class TutorialStep { Step0, // Dialogue hint: "click to advance" Step1, // Camera rotation hint Step2, // Floor tap / walk hint Step3, // Pinch-zoom hint Step4, // Pick-up item hint Step5, // Post-pickup reaction (sub-state: which items were collected) Step6, // Tutorial complete — both phone and journal opened }; class MenuManager { public: UiManager uiManager; UiManager topUiManager; ZL::Quest::QuestJournal questJournal; // Global night mode state — persists across location transitions. bool isNight = false; bool isDawn = false; // sub-variant of night: brighter pink ambient, same lighting MenuManager(Renderer& iRenderer); void setup(Inventory& inv, const std::string& zipFile); void openInventory(); void selectInventoryItem(int index); void closeInventory(); void openQuestJournal(); void closeQuestJournal(); void toggleQuestJournal(); bool isInventoryOpen() const { return state == GameState::Inventory; } bool isQuestJournalOpen() const { return state == GameState::QuestJournal; } void showMainMenu(); bool isMainMenuOpen() const { return state == GameState::MainMenu; } void openPhoneScreen(); void closePhoneScreen(); bool isPhoneScreenOpen() const { return state == GameState::PhoneScreen; } void closePhoneEntirely(); void tutorialShowTaxiHint(); void setChatUnread(int chatIndex, bool unread); void spendMoney(int amount); int getMoney() const { return money_; } std::function startGameFunc; std::function startDialogueFunc; std::function startDarklandsTransitionFunc; std::function startNightTransitionFunc; std::function chatOpenCallback; std::function skipCutsceneFunc; std::function callTaxiFunc; // Called when a chat message bubble should be shown (text + direction) void onChatBubbleReady(const std::string& text, bool incoming); void setDarklandsMode(bool enabled); void advanceTutorialStep(); void onItemPickedUp(const std::string& itemId); void onLocationChanged(const std::string& locationName); void onEnemyKilledInUniInterior(); void advanceUniIntDarklandsHud(); void onPlayerStartedWalking(); // 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; // Toast notification system void showToast(const std::string& iconPath, const std::string& text); void update(float deltaMs); TutorialStep tutorialStep = TutorialStep::Step0; protected: Renderer& renderer; private: void enterGameplay(); void refreshQuestJournalUi(); void selectQuestByIndex(int index); void refreshItemPickupHud(); void setupStep5Callbacks(); void setupGameplayHudCallbacks(); void openPhoneMessenger(); void openPhoneBank(); void openPhoneVideo(); void openPhoneTaxi(); void openPhoneMapScreen(std::shared_ptr mapRoot); void refreshChatUnreadIndicators(); void resetPhoneChatNodes(); void recomputePhoneChatPositions(); void openPhoneChatFromList(int chatIndex, std::shared_ptr chatRoot); void returnToPhoneChatList(); void closePhoneScreenFromChat(); void applyUniIntHud(); void rebuildChatBubblesFromHistory(int chatIndex); void showAboutScreen(); // Toast internals struct ToastEntry { std::string iconPath; std::string text; float timer = 0.0f; enum class State { FadeIn, Visible, FadeOut } state = State::FadeIn; float currentAlpha() const; }; struct ToastMessage { std::string iconPath; std::string text; }; void updateToasts(float deltaMs); void applyToastsToUi(); void hideAllToastWidgets(); std::vector activeToasts_; std::deque toastQueue_; static constexpr float TOAST_FADE_MS = 1000.0f; static constexpr float TOAST_VISIBLE_MS = 2000.0f; GameState state = GameState::Gameplay; Inventory* inventory = nullptr; //std::string zipFile_; int inventorySelectedIndex_ = -1; enum class UniIntTutorialState { Step10, Step11, DarklandsActive, DarklandsStep13, DarklandsFull }; UniIntTutorialState uniIntTutorialState_ = UniIntTutorialState::Step10; std::string currentLocationName_; bool currentIsDarklands_ = false; bool tutorialPhonePickedUp = false; bool tutorialJournalPickedUp = false; //bool tutorialPhoneScreenOpened = false; bool tutorialPhoneChatScreenOpened = false; bool tutorialJournalScreenOpened = false; bool tutorialMessengerScreenOpened = false; //bool tutorialTaxiScreenOpened = false; bool tutorialNeedOpenTaxiScreen = false; std::shared_ptr hudRoot; std::shared_ptr hudStep1Root; std::shared_ptr hudStep2Root; std::shared_ptr hudStep3Root; std::shared_ptr hudStep4Root; std::shared_ptr hudStep5aRoot; std::shared_ptr hudStep5bRoot; std::shared_ptr hudStep5abRoot; std::shared_ptr hudUniExtRoot; std::shared_ptr hudUniIntStep10Root; std::shared_ptr hudUniIntStep11Root; std::shared_ptr hudUniIntStep12Root; std::shared_ptr hudUniIntFullRoot; std::shared_ptr hudUniIntStep13Root; std::shared_ptr hudUniIntDarkFullRoot; std::shared_ptr hudUniExtDarkRoot; std::shared_ptr hudCutsceneRoot_; std::shared_ptr hudTopHintRoot_; std::shared_ptr phoneMainRoot; std::shared_ptr phoneMainHintARoot; std::shared_ptr phoneMainHintBRoot; std::shared_ptr phoneMainHintABRoot; std::shared_ptr phoneBankRoot; std::shared_ptr phoneVideoRoot; std::shared_ptr phoneMapDormRoot; std::shared_ptr phoneMapUniRoot; std::shared_ptr phoneChatListRoot; std::shared_ptr phoneChatListHintRoot; std::shared_ptr phoneChat1Root; std::shared_ptr phoneChat2Root; std::shared_ptr phoneChat3Root; std::shared_ptr mainMenuRoot; std::shared_ptr aboutScreenRoot; std::shared_ptr newInventoryRoot; std::shared_ptr questJournalRoot; std::shared_ptr texObjectiveCompleted_; std::shared_ptr texObjectiveBlank_; std::shared_ptr texItemSelected_; std::shared_ptr texItemTransparent_; float currentPlayerHp_ = 200.f; float currentPlayerMaxHp_ = 200.f; void applyCurrentHealthBar(); int selectedQuestIndex = -1; std::vector visibleQuestIds; bool chatUnread_[3] = { true, true, true }; int money_ = 5500; // Phone chat state struct PhoneChatBubbleInfo { std::string nodeName; float height; }; std::vector phoneChatVisibleBubbles_; // Per-chat message history (max 5 messages each) struct StoredChatMessage { std::string text; bool incoming; }; std::vector chatHistory_[3]; int activeChatIndex_ = -1; // Preloaded bubble textures std::shared_ptr texBubbleInCenter_, texBubbleInLT_, texBubbleInLB_, texBubbleInRT_, texBubbleInRB_; std::shared_ptr texBubbleOutCenter_, texBubbleOutLT_, texBubbleOutLB_, texBubbleOutRT_, texBubbleOutRB_; static constexpr float CHAT_TOP_Y = 610.0f; static constexpr float CHAT_BOTTOM_Y = 290.0f; static constexpr float CHAT_SPACING = 10.0f; }; } // namespace ZL