space-game001/src/MenuManager.h
2026-05-31 21:57:18 +03:00

137 lines
3.9 KiB
C++

#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 <vector>
#include <string>
#include <memory>
#include <unordered_set>
namespace ZL {
extern const char* CONST_ZIP_FILE;
enum class GameState {
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;
ZL::Quest::QuestJournal questJournal;
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 openPhoneScreen();
void closePhoneScreen();
void revealPhoneChatBubble(const std::string& slotName);
bool isPhoneScreenOpen() const { return state == GameState::PhoneScreen; }
std::function<void(const std::string&)> startDialogueFunc;
std::function<void()> startDarklandsTransitionFunc;
void setDarklandsMode(bool enabled);
void advanceTutorialStep();
void onItemPickedUp(const std::string& itemId);
void onLocationChanged(const std::string& locationName);
TutorialStep tutorialStep = TutorialStep::Step0;
protected:
Renderer& renderer;
private:
void enterGameplay();
void refreshQuestJournalUi();
void selectQuestByIndex(int index);
void refreshItemPickupHud();
void setupStep5Callbacks();
void setupGameplayHudCallbacks();
void resetPhoneChatNodes();
void recomputePhoneChatPositions();
void openPhoneChatFromList(std::shared_ptr<UiNode> chatRoot, const std::string& dialogueId);
void returnToPhoneChatList();
void closePhoneScreenFromChat();
GameState state = GameState::Gameplay;
Inventory* inventory = nullptr;
std::string zipFile_;
int inventorySelectedIndex_ = -1;
bool tutorialPhonePickedUp = false;
bool tutorialJournalPickedUp = false;
bool tutorialPhoneScreenOpened = false;
bool tutorialJournalScreenOpened = false;
std::shared_ptr<UiNode> hudRoot;
std::shared_ptr<UiNode> hudStep1Root;
std::shared_ptr<UiNode> hudStep2Root;
std::shared_ptr<UiNode> hudStep3Root;
std::shared_ptr<UiNode> hudStep4Root;
std::shared_ptr<UiNode> hudStep5aRoot;
std::shared_ptr<UiNode> hudStep5bRoot;
std::shared_ptr<UiNode> hudStep5abRoot;
std::shared_ptr<UiNode> hudUniExtRoot;
std::shared_ptr<UiNode> hudUniIntRoot;
std::shared_ptr<UiNode> phoneChatListRoot;
std::shared_ptr<UiNode> phoneChat1Root;
std::shared_ptr<UiNode> phoneChat2Root;
std::shared_ptr<UiNode> phoneChat3Root;
std::shared_ptr<UiNode> newInventoryRoot;
std::shared_ptr<UiNode> questJournalRoot;
std::shared_ptr<Texture> texObjectiveCompleted_;
std::shared_ptr<Texture> texObjectiveBlank_;
std::shared_ptr<Texture> texItemSelected_;
std::shared_ptr<Texture> texItemTransparent_;
int selectedQuestIndex = -1;
std::vector<std::string> visibleQuestIds;
// Dialogues that have been started at least once; re-opening a chat won't restart them
std::unordered_set<std::string> startedDialogues_;
// Phone chat state
struct PhoneChatBubbleInfo {
std::string nodeName;
float height;
};
std::vector<PhoneChatBubbleInfo> phoneChatVisibleBubbles_;
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