space-game001/src/MenuManager.cpp
2026-03-10 11:39:02 +03:00

329 lines
11 KiB
C++

#include "MenuManager.h"
#include <iostream>
#ifdef EMSCRIPTEN
#include <emscripten.h>
#include <cstdlib>
#endif
namespace ZL {
extern bool inverseVertical;
MenuManager::MenuManager(Renderer& iRenderer) :
renderer(iRenderer)
{
}
void MenuManager::setupMenu()
{
mainMenuRoot = loadUiFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
connectingRoot = loadUiFromFile("resources/config/connecting.json", renderer, CONST_ZIP_FILE);
connectionFailedRoot= loadUiFromFile("resources/config/connection_failed.json", renderer, CONST_ZIP_FILE);
gameplayRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
gameOverRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
connectionLostRoot = loadUiFromFile("resources/config/connection_lost.json", renderer, CONST_ZIP_FILE);
enterMainMenu();
}
bool MenuManager::shouldRenderSpace() const
{
return state == GameState::Gameplay
|| state == GameState::GameOver
|| state == GameState::ConnectionLost;
}
// ── State: MainMenu ──────────────────────────────────────────────────────
void MenuManager::enterMainMenu()
{
state = GameState::MainMenu;
uiManager.replaceRoot(mainMenuRoot);
if (onMainMenuEntered) onMainMenuEntered();
uiManager.setButtonCallback("singleButton", [this](const std::string&) {
enterShipSelectionSingle();
});
uiManager.setButtonCallback("multiplayerButton", [this](const std::string&) {
enterShipSelectionMulti();
});
}
// ── State: ShipSelectionSingle ───────────────────────────────────────────
void MenuManager::enterShipSelectionSingle()
{
state = GameState::ShipSelectionSingle;
uiManager.replaceRoot(shipSelectionRoot);
std::string initialNick;
#ifdef EMSCRIPTEN
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
if (savedNickC) {
initialNick = savedNickC;
free(savedNickC);
}
#endif
auto tf = uiManager.findTextField("nicknameInput");
if (tf) {
if (!initialNick.empty()) tf->text = initialNick;
#ifdef EMSCRIPTEN
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
EM_ASM_({
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
}, value.c_str());
});
#endif
}
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: ShipSelectionMulti ─────────────────────────────────────────────
void MenuManager::enterShipSelectionMulti()
{
state = GameState::ShipSelectionMulti;
uiManager.replaceRoot(shipSelectionRoot);
std::string initialNick;
#ifdef EMSCRIPTEN
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
if (savedNickC) {
initialNick = savedNickC;
free(savedNickC);
}
#endif
auto tf = uiManager.findTextField("nicknameInput");
if (tf) {
if (!initialNick.empty()) tf->text = initialNick;
#ifdef EMSCRIPTEN
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
EM_ASM_({
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
}, value.c_str());
});
#endif
}
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 0;
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 1;
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: Connecting ────────────────────────────────────────────────────
void MenuManager::enterConnecting()
{
state = GameState::Connecting;
uiManager.replaceRoot(connectingRoot);
// No interactive elements — just a static "Connecting..." image
}
// ── State: ConnectionFailed ───────────────────────────────────────────────
void MenuManager::enterConnectionFailed()
{
state = GameState::ConnectionFailed;
uiManager.replaceRoot(connectionFailedRoot);
uiManager.setButtonCallback("connectionFailedReconnectButton", [this](const std::string&) {
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(pendingMultiNick, pendingMultiShipType);
});
uiManager.setButtonCallback("connectionFailedGoBack", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: Gameplay ──────────────────────────────────────────────────────
void MenuManager::enterGameplay()
{
state = GameState::Gameplay;
uiManager.replaceRoot(gameplayRoot);
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
if (auto btn = uiManager.findButton("takeButton")) btn->state = ButtonState::Disabled;
/*
auto velocityTv = uiManager.findTextView("velocityText");
if (velocityTv) {
velocityTv->rect.x = 10.0f;
velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f;
}*/
uiManager.setButtonPressCallback("shootButton", [this](const std::string&) {
if (onFirePressed) onFirePressed();
});
uiManager.setButtonPressCallback("shootButton2", [this](const std::string&) {
if (onFirePressed) onFirePressed();
});
uiManager.setButtonPressCallback("plusButton", [this](const std::string&) {
int newVel = Environment::shipState.selectedVelocity + 1;
if (newVel > 4) newVel = 4;
uiManager.findButton("minusButton")->state = ButtonState::Normal;
if (newVel == 4)
{
uiManager.findButton("plusButton")->state = ButtonState::Disabled;
}
else
{
uiManager.findButton("plusButton")->state = ButtonState::Normal;
}
if (onVelocityChanged) onVelocityChanged(newVel);
});
uiManager.setButtonPressCallback("minusButton", [this](const std::string&) {
int newVel = Environment::shipState.selectedVelocity - 1;
if (newVel < 0) newVel = 0;
uiManager.findButton("plusButton")->state = ButtonState::Normal;
if (newVel == 0)
{
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
}
else
{
uiManager.findButton("minusButton")->state = ButtonState::Normal;
}
if (onVelocityChanged) onVelocityChanged(newVel);
});
uiManager.setButtonPressCallback("takeButton", [this](const std::string&) {
if (onTakeButtonPressed) onTakeButtonPressed();
});
uiManager.setButtonCallback("showPlayersButton", [this](const std::string&) {
if (onShowPlayersPressed) onShowPlayersPressed();
});
//inverseMouseButton
uiManager.setButtonPressCallback("inverseMouseButton", [this](const std::string&) {
inverseVertical = !inverseVertical;
std::cout << "Inverse mouse: " << (inverseVertical ? "ON" : "OFF") << std::endl;
});
/*
uiManager.setSliderCallback("velocitySlider", [this](const std::string&, float value) {
int newVel = static_cast<int>(roundf(value * 10));
if (newVel > 2) newVel = 2;
if (newVel != Environment::shipState.selectedVelocity) {
if (onVelocityChanged) onVelocityChanged(newVel);
}
});*/
}
// ── State: GameOver ──────────────────────────────────────────────────────
void MenuManager::enterGameOver(int score)
{
state = GameState::GameOver;
uiManager.replaceRoot(gameOverRoot);
uiManager.setText("scoreText", "Score: " + std::to_string(score));
uiManager.setButtonCallback("restartButton", [this](const std::string&) {
if (onRestartPressed) onRestartPressed();
enterGameplay();
});
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: ConnectionLost ─────────────────────────────────────────────────
void MenuManager::enterConnectionLost()
{
state = GameState::ConnectionLost;
uiManager.replaceRoot(connectionLostRoot);
uiManager.setButtonCallback("reconnectButton", [this](const std::string&) {
// TODO: reconnect logic
});
uiManager.setButtonCallback("exitServerButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── Public event API ──────────────────────────────────────────────────────
void MenuManager::notifyConnected()
{
if (state == GameState::Connecting) {
enterGameplay();
}
}
void MenuManager::notifyConnectionFailed()
{
if (state == GameState::Connecting) {
enterConnectionFailed();
}
}
void MenuManager::showGameOver(int score)
{
if (state == GameState::Gameplay) {
enterGameOver(score);
}
}
void MenuManager::showConnectionLost()
{
if (state == GameState::Gameplay) {
enterConnectionLost();
}
}
} // namespace ZL