From d28feb3276abcddeec64b35813d0fbd66d9d9dde Mon Sep 17 00:00:00 2001 From: Gregor Klevze Date: Tue, 23 Dec 2025 20:24:50 +0100 Subject: [PATCH] minor fixes --- src/core/Settings.cpp | 6 +- src/core/Settings.h | 3 +- src/states/MenuState.cpp | 123 +++++++++++++++++++++++++-------------- 3 files changed, 87 insertions(+), 45 deletions(-) diff --git a/src/core/Settings.cpp b/src/core/Settings.cpp index 2f5e200..3982a4f 100644 --- a/src/core/Settings.cpp +++ b/src/core/Settings.cpp @@ -21,7 +21,11 @@ std::string Settings::getSettingsPath() { bool Settings::load() { std::ifstream file(getSettingsPath()); if (!file.is_open()) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Settings file not found, using defaults"); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Settings file not found, using defaults. Creating settings file with defaults."); + // Persist defaults so next run has an explicit settings.ini + try { + save(); + } catch (...) {} return false; } diff --git a/src/core/Settings.h b/src/core/Settings.h index f29d75b..6e158a4 100644 --- a/src/core/Settings.h +++ b/src/core/Settings.h @@ -48,7 +48,8 @@ private: Settings& operator=(const Settings&) = delete; // Settings values - bool m_fullscreen = false; + // Default to fullscreen on first run when no settings.ini exists + bool m_fullscreen = true; bool m_musicEnabled = true; bool m_soundEnabled = true; bool m_debugEnabled = false; diff --git a/src/states/MenuState.cpp b/src/states/MenuState.cpp index e69cc26..3b9bcb1 100644 --- a/src/states/MenuState.cpp +++ b/src/states/MenuState.cpp @@ -1241,11 +1241,15 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi } static const std::vector EMPTY_SCORES; const auto& hs = ctx.scores ? ctx.scores->all() : EMPTY_SCORES; - // Choose which game_type to show based on current menu selection + // Choose which game_type to show based on current menu selection or mouse hover. + // Prefer `hoveredButton` (mouse-over) when available so the TOP PLAYER panel + // updates responsively while the user moves the pointer over the bottom menu. + int activeBtn = (ctx.hoveredButton ? *ctx.hoveredButton : -1); + if (activeBtn < 0) activeBtn = selectedButton; std::string wantedType = "classic"; - if (selectedButton == 0) wantedType = "classic"; // Play / Endless - else if (selectedButton == 1) wantedType = "cooperate"; // Coop - else if (selectedButton == 2) wantedType = "challenge"; // Challenge + if (activeBtn == 0) wantedType = "classic"; // Play / Endless + else if (activeBtn == 1) wantedType = "cooperate"; // Coop + else if (activeBtn == 2) wantedType = "challenge"; // Challenge // Filter highscores to the desired game type std::vector filtered; filtered.reserve(hs.size()); @@ -1581,16 +1585,19 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi float alphaFactor = static_cast(coopSetupTransition); if (alphaFactor < 0.0f) alphaFactor = 0.0f; if (alphaFactor > 1.0f) alphaFactor = 1.0f; + // Compute coop info image placement (draw as background for both ChoosePartner and Network steps) + float imgX = 0.0f, imgY = 0.0f, targetW = 0.0f, targetH = 0.0f; + bool hasCoopImg = false; if (coopInfoTexture && coopInfoTexW > 0 && coopInfoTexH > 0) { float totalW = totalChoiceW; - // Increase allowed image width by ~15% (was 0.75 of totalW) - const float scaleFactor = 0.75f * 1.25f; // ~0.8625 - float maxImgW = totalW * scaleFactor; - float targetW = std::min(maxImgW, static_cast(coopInfoTexW)); + // Keep coop info image slightly smaller than the button row. + // Use a modest scale so it doesn't dominate the UI. + float maxImgW = totalW * 0.65f; + targetW = std::min(maxImgW, static_cast(coopInfoTexW)); float scale = targetW / static_cast(coopInfoTexW); - float targetH = static_cast(coopInfoTexH) * scale; - float imgX = bx + (totalW - targetW) * 0.5f; - float imgY = by - targetH - 8.0f; // keep the small gap above buttons + targetH = static_cast(coopInfoTexH) * scale; + imgX = bx + (totalW - targetW) * 0.5f; + imgY = by - targetH - 8.0f; // keep the small gap above buttons float minY = panelBaseY + 6.0f; if (imgY < minY) imgY = minY; SDL_FRect dst{ imgX, imgY, targetW, targetH }; @@ -1598,28 +1605,30 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi // Make the coop info image slightly transparent scaled by transition SDL_SetTextureAlphaMod(coopInfoTexture, static_cast(std::round(200.0f * alphaFactor))); SDL_RenderTexture(renderer, coopInfoTexture, nullptr, &dst); - - // Draw cooperative instructions inside the panel area (overlayed on the panel background) - FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont; - if (f) { - const float pad = 38.0f; - float textX = panelBaseX + pad; - // Position the text over the lower portion of the image (overlay) - // Move the block upward by ~150px to match UI request - float textY = imgY + targetH - std::min(80.0f, targetH * 0.35f) - 150.0f; + hasCoopImg = true; - // Bulleted list (measure sample line height first) - const std::vector bullets = { - "The playfield is shared between two players", - "Each player controls one half of the grid", - "A line clears only when both halves are filled", - "Timing and coordination are essential" - }; - float bulletScale = 0.78f; - SDL_Color bulletCol{200,220,230,220}; - bulletCol.a = static_cast(std::round(bulletCol.a * alphaFactor)); - int sampleLW = 0, sampleLH = 0; - f->measure(bullets[0], bulletScale, sampleLW, sampleLH); + // Only draw the instructional overlay text when choosing partner. + if (coopSetupStep == CoopSetupStep::ChoosePartner) { + FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont; + if (f) { + const float pad = 38.0f; + float textX = panelBaseX + pad; + // Position the text over the lower portion of the image (overlay) + // Move the block upward by ~150px to match UI request + float textY = imgY + targetH - std::min(80.0f, targetH * 0.35f) - 150.0f; + + // Bulleted list (measure sample line height first) + const std::vector bullets = { + "The playfield is shared between two players", + "Each player controls one half of the grid", + "A line clears only when both halves are filled", + "Timing and coordination are essential" + }; + float bulletScale = 0.78f; + SDL_Color bulletCol{200,220,230,220}; + bulletCol.a = static_cast(std::round(bulletCol.a * alphaFactor)); + int sampleLW = 0, sampleLH = 0; + f->measure(bullets[0], bulletScale, sampleLW, sampleLH); // Header: move it up by one sample row so it sits higher const std::string header = "* HOW TO PLAY – COOPERATE MODE *"; @@ -1654,6 +1663,7 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi f->draw(renderer, goalX, textY, goalText, 0.86f, goalTextCol); } } + } // Delay + eased fade specifically for the two coop buttons so they appear after the image/text. const float btnDelay = 0.25f; // fraction of transition to wait before buttons start fading @@ -1694,7 +1704,7 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi coopSetupBtnRects[2].x + btnW2 * 0.5f, coopSetupBtnRects[2].y + btnH2 * 0.5f, btnW2, btnH2, - "2 PLAYER (NETWORK)", + "2 PLAYER (NET)", false, coopSetupSelected == 2, bgA, @@ -1710,7 +1720,9 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi const float roleGap = 48.0f; const float roleTotalW = roleBtnW * 2.0f + roleGap; const float roleX = panelBaseX + (panelW - roleTotalW) * 0.5f + shiftX; - const float roleY = by + btnH2 + 18.0f; + // Move the host/join buttons down from the previous higher position. + // Shift down by one button height plus half a button (effectively lower them): + const float roleY = by + (btnH2 * 0.5f) - 18.0f; SDL_FRect hostRect{ roleX, roleY, roleBtnW, btnH2 }; SDL_FRect joinRect{ roleX + roleBtnW + roleGap, roleY, roleBtnW, btnH2 }; @@ -1744,23 +1756,48 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont; if (f) { SDL_Color infoCol{200, 220, 230, static_cast(std::round(220.0f * buttonFade))}; - char endpoint[256]; - std::snprintf(endpoint, sizeof(endpoint), "PORT %u HOST IP %s JOIN IP %s", - (unsigned)coopNetworkPort, - coopNetworkBindAddress.c_str(), - coopNetworkJoinAddress.c_str()); - f->draw(renderer, panelBaseX + 60.0f, roleY + btnH2 + 12.0f, endpoint, 0.90f, infoCol); + // Draw connection info on separate lines and shift right by ~200px + char portLine[64]; + std::snprintf(portLine, sizeof(portLine), "PORT %u", (unsigned)coopNetworkPort); + char hostLine[128]; + std::snprintf(hostLine, sizeof(hostLine), "HOST IP %s", coopNetworkBindAddress.c_str()); + char joinLine[128]; + std::snprintf(joinLine, sizeof(joinLine), "JOIN IP %s", coopNetworkJoinAddress.c_str()); + const float textShiftX = 200.0f; + const float textX = panelBaseX + 60.0f + textShiftX; + const float endpointY = (hasCoopImg ? (imgY + targetH * 0.62f) : (roleY + btnH2 + 12.0f)); + const float lineSpacing = 28.0f; + // Show only the minimal info needed for the selected role. + f->draw(renderer, textX, endpointY, portLine, 0.90f, infoCol); + if (coopNetworkRoleSelected == 0) { + // Host: show bind address only + f->draw(renderer, textX, endpointY + lineSpacing, hostLine, 0.90f, infoCol); + } else { + // Client: show join target only + f->draw(renderer, textX, endpointY + lineSpacing, joinLine, 0.90f, infoCol); + } + + float hintY = endpointY + lineSpacing * 2.0f + 6.0f; + + // Bottom helper prompt: show a compact instruction under the image window + float bottomY = hasCoopImg ? (imgY + targetH + 18.0f) : (hintY + 36.0f); + SDL_Color bottomCol{180,200,210,200}; + if (coopNetworkRoleSelected == 0) { + f->draw(renderer, textX, bottomY, "HOST: press ENTER to edit bind IP, then press ENTER to confirm", 0.82f, bottomCol); + } else { + f->draw(renderer, textX, bottomY, "JOIN: press ENTER to type server IP, then press ENTER to connect", 0.82f, bottomCol); + } if (coopSetupStep == CoopSetupStep::NetworkWaiting && !coopNetworkStatusText.empty()) { SDL_Color statusCol{255, 215, 80, static_cast(std::round(240.0f * buttonFade))}; - f->draw(renderer, panelBaseX + 60.0f, roleY + btnH2 + 44.0f, coopNetworkStatusText, 1.00f, statusCol); + f->draw(renderer, textX, hintY, coopNetworkStatusText, 1.00f, statusCol); } else if (coopSetupStep == CoopSetupStep::NetworkEnterAddress) { SDL_Color hintCol{160, 190, 210, static_cast(std::round(200.0f * buttonFade))}; const char* label = (coopNetworkRoleSelected == 0) ? "TYPE HOST IP (BIND) THEN ENTER" : "TYPE JOIN IP THEN ENTER"; - f->draw(renderer, panelBaseX + 60.0f, roleY + btnH2 + 44.0f, label, 0.82f, hintCol); + f->draw(renderer, textX, hintY, label, 0.82f, hintCol); } else { SDL_Color hintCol{160, 190, 210, static_cast(std::round(200.0f * buttonFade))}; - f->draw(renderer, panelBaseX + 60.0f, roleY + btnH2 + 44.0f, "PRESS ENTER TO EDIT/CONFIRM ESC TO GO BACK", 0.82f, hintCol); + f->draw(renderer, textX, hintY, "PRESS ENTER TO EDIT/CONFIRM ESC TO GO BACK", 0.82f, hintCol); } } }