diff --git a/src/core/application/ApplicationManager.cpp b/src/core/application/ApplicationManager.cpp index d013923..4d000cb 100644 --- a/src/core/application/ApplicationManager.cpp +++ b/src/core/application/ApplicationManager.cpp @@ -586,6 +586,7 @@ bool ApplicationManager::initializeGame() { m_stateContext.hoveredButton = &m_hoveredButton; m_stateContext.showSettingsPopup = &m_showSettingsPopup; m_stateContext.showExitConfirmPopup = &m_showExitConfirmPopup; + m_stateContext.exitPopupSelectedButton = &m_exitPopupSelectedButton; // Create state instances m_loadingState = std::make_unique(m_stateContext); @@ -1048,7 +1049,8 @@ void ApplicationManager::setupStateHandlers() { logicalScale, static_cast(winW), static_cast(winH), - m_showExitConfirmPopup + m_showExitConfirmPopup, + m_exitPopupSelectedButton ); // Reset viewport diff --git a/src/core/application/ApplicationManager.h b/src/core/application/ApplicationManager.h index f73a2ee..0ed7992 100644 --- a/src/core/application/ApplicationManager.h +++ b/src/core/application/ApplicationManager.h @@ -94,6 +94,7 @@ private: int m_hoveredButton = -1; bool m_showSettingsPopup = false; bool m_showExitConfirmPopup = false; + int m_exitPopupSelectedButton = 1; // 0 = YES, 1 = NO uint64_t m_loadStartTicks = 0; bool m_musicStarted = false; bool m_musicLoaded = false; diff --git a/src/main.cpp b/src/main.cpp index 8378d82..1c02302 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -277,6 +277,7 @@ static void drawSettingsPopup(SDL_Renderer* renderer, FontAtlas& font, bool musi static double logoAnimCounter = 0.0; static bool showSettingsPopup = false; static bool showExitConfirmPopup = false; +static int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO static bool musicEnabled = true; static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings static bool isNewHighScore = false; @@ -650,6 +651,7 @@ int main(int, char **) ctx.hoveredButton = &hoveredButton; ctx.showSettingsPopup = &showSettingsPopup; ctx.showExitConfirmPopup = &showExitConfirmPopup; + ctx.exitPopupSelectedButton = &exitPopupSelectedButton; // Instantiate state objects auto loadingState = std::make_unique(ctx); @@ -1324,7 +1326,8 @@ int main(int, char **) logicalScale, (float)winW, (float)winH, - showExitConfirmPopup + showExitConfirmPopup, + exitPopupSelectedButton ); break; case AppState::GameOver: diff --git a/src/main_dist.cpp b/src/main_dist.cpp index 66099ec..c109dda 100644 --- a/src/main_dist.cpp +++ b/src/main_dist.cpp @@ -276,6 +276,7 @@ static void drawSettingsPopup(SDL_Renderer* renderer, FontAtlas& font, bool musi static double logoAnimCounter = 0.0; static bool showSettingsPopup = false; static bool showExitConfirmPopup = false; +static int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO static bool musicEnabled = true; static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings @@ -644,6 +645,7 @@ int main(int, char **) ctx.hoveredButton = &hoveredButton; ctx.showSettingsPopup = &showSettingsPopup; ctx.showExitConfirmPopup = &showExitConfirmPopup; + ctx.exitPopupSelectedButton = &exitPopupSelectedButton; // Instantiate state objects auto loadingState = std::make_unique(ctx); diff --git a/src/states/PlayingState.cpp b/src/states/PlayingState.cpp index c7c6680..0f5398f 100644 --- a/src/states/PlayingState.cpp +++ b/src/states/PlayingState.cpp @@ -24,6 +24,17 @@ void PlayingState::handleEvent(const SDL_Event& e) { // We keep short-circuited input here; main still owns mouse UI if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) { if (!ctx.game) return; + + auto setExitSelection = [&](int value) { + if (ctx.exitPopupSelectedButton) { + *ctx.exitPopupSelectedButton = value; + } + }; + + auto getExitSelection = [&]() -> int { + return ctx.exitPopupSelectedButton ? *ctx.exitPopupSelectedButton : 1; + }; + // Pause toggle (P) if (e.key.scancode == SDL_SCANCODE_P) { bool paused = ctx.game->isPaused(); @@ -35,20 +46,26 @@ void PlayingState::handleEvent(const SDL_Event& e) { if (ctx.showExitConfirmPopup && *ctx.showExitConfirmPopup) { // Navigate between YES (0) and NO (1) buttons if (e.key.scancode == SDL_SCANCODE_LEFT || e.key.scancode == SDL_SCANCODE_UP) { - exitPopupSelectedButton = 0; // YES + setExitSelection(0); return; } if (e.key.scancode == SDL_SCANCODE_RIGHT || e.key.scancode == SDL_SCANCODE_DOWN) { - exitPopupSelectedButton = 1; // NO + setExitSelection(1); return; } - + // Activate selected button with Enter or Space if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER || e.key.scancode == SDL_SCANCODE_SPACE) { + const bool confirmExit = (getExitSelection() == 0); *ctx.showExitConfirmPopup = false; - if (exitPopupSelectedButton == 0) { + if (confirmExit) { // YES - Reset game and return to menu - ctx.game->reset(false); + if (ctx.startLevelSelection) { + ctx.game->reset(*ctx.startLevelSelection); + } else { + ctx.game->reset(0); + } + ctx.game->setPaused(false); if (ctx.stateManager) ctx.stateManager->setState(AppState::Menu); } else { // NO - Just close popup and resume @@ -60,6 +77,7 @@ void PlayingState::handleEvent(const SDL_Event& e) { if (e.key.scancode == SDL_SCANCODE_ESCAPE) { *ctx.showExitConfirmPopup = false; ctx.game->setPaused(false); + setExitSelection(1); return; } // While modal is open, suppress other gameplay keys @@ -71,6 +89,7 @@ void PlayingState::handleEvent(const SDL_Event& e) { if (ctx.showExitConfirmPopup) { if (ctx.game) ctx.game->setPaused(true); *ctx.showExitConfirmPopup = true; + setExitSelection(1); // Default to NO for safety } return; } @@ -78,7 +97,7 @@ void PlayingState::handleEvent(const SDL_Event& e) { // Tetris controls (only when not paused) if (!ctx.game->isPaused()) { // Rotation (still event-based for precise timing) - if (e.key.scancode == SDL_SCANCODE_UP || e.key.scancode == SDL_SCANCODE_W || + if (e.key.scancode == SDL_SCANCODE_UP || e.key.scancode == SDL_SCANCODE_W || e.key.scancode == SDL_SCANCODE_Z) { ctx.game->rotate(1); // Clockwise rotation return; @@ -87,7 +106,7 @@ void PlayingState::handleEvent(const SDL_Event& e) { ctx.game->rotate(-1); // Counter-clockwise rotation return; } - + // Hard drop (space) if (e.key.scancode == SDL_SCANCODE_SPACE) { ctx.game->hardDrop(); @@ -95,8 +114,8 @@ void PlayingState::handleEvent(const SDL_Event& e) { } } } - - // Note: Left/Right movement and soft drop are now handled by + + // Note: Left/Right movement and soft drop are now handled by // ApplicationManager's update handler for proper DAS/ARR timing } diff --git a/src/states/PlayingState.h b/src/states/PlayingState.h index 341611f..f8b177e 100644 --- a/src/states/PlayingState.h +++ b/src/states/PlayingState.h @@ -14,5 +14,4 @@ public: private: // Local per-state variables if needed bool localPaused = false; - int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO (default to NO for safety) }; diff --git a/src/states/State.h b/src/states/State.h index 610579a..cc8d7cc 100644 --- a/src/states/State.h +++ b/src/states/State.h @@ -47,6 +47,7 @@ struct StateContext { // Menu popups (exposed from main) bool* showSettingsPopup = nullptr; bool* showExitConfirmPopup = nullptr; // If true, show "Exit game?" confirmation while playing + int* exitPopupSelectedButton = nullptr; // 0 = YES, 1 = NO (default) // Pointer to the application's StateManager so states can request transitions StateManager* stateManager = nullptr; };