minor fixes

This commit is contained in:
2025-12-23 20:24:50 +01:00
parent a7a3ae9055
commit d28feb3276
3 changed files with 87 additions and 45 deletions

View File

@ -21,7 +21,11 @@ std::string Settings::getSettingsPath() {
bool Settings::load() { bool Settings::load() {
std::ifstream file(getSettingsPath()); std::ifstream file(getSettingsPath());
if (!file.is_open()) { 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; return false;
} }

View File

@ -48,7 +48,8 @@ private:
Settings& operator=(const Settings&) = delete; Settings& operator=(const Settings&) = delete;
// Settings values // 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_musicEnabled = true;
bool m_soundEnabled = true; bool m_soundEnabled = true;
bool m_debugEnabled = false; bool m_debugEnabled = false;

View File

@ -1241,11 +1241,15 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
} }
static const std::vector<ScoreEntry> EMPTY_SCORES; static const std::vector<ScoreEntry> EMPTY_SCORES;
const auto& hs = ctx.scores ? ctx.scores->all() : 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"; std::string wantedType = "classic";
if (selectedButton == 0) wantedType = "classic"; // Play / Endless if (activeBtn == 0) wantedType = "classic"; // Play / Endless
else if (selectedButton == 1) wantedType = "cooperate"; // Coop else if (activeBtn == 1) wantedType = "cooperate"; // Coop
else if (selectedButton == 2) wantedType = "challenge"; // Challenge else if (activeBtn == 2) wantedType = "challenge"; // Challenge
// Filter highscores to the desired game type // Filter highscores to the desired game type
std::vector<ScoreEntry> filtered; std::vector<ScoreEntry> filtered;
filtered.reserve(hs.size()); filtered.reserve(hs.size());
@ -1581,16 +1585,19 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
float alphaFactor = static_cast<float>(coopSetupTransition); float alphaFactor = static_cast<float>(coopSetupTransition);
if (alphaFactor < 0.0f) alphaFactor = 0.0f; if (alphaFactor < 0.0f) alphaFactor = 0.0f;
if (alphaFactor > 1.0f) alphaFactor = 1.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) { if (coopInfoTexture && coopInfoTexW > 0 && coopInfoTexH > 0) {
float totalW = totalChoiceW; float totalW = totalChoiceW;
// Increase allowed image width by ~15% (was 0.75 of totalW) // Keep coop info image slightly smaller than the button row.
const float scaleFactor = 0.75f * 1.25f; // ~0.8625 // Use a modest scale so it doesn't dominate the UI.
float maxImgW = totalW * scaleFactor; float maxImgW = totalW * 0.65f;
float targetW = std::min(maxImgW, static_cast<float>(coopInfoTexW)); targetW = std::min(maxImgW, static_cast<float>(coopInfoTexW));
float scale = targetW / static_cast<float>(coopInfoTexW); float scale = targetW / static_cast<float>(coopInfoTexW);
float targetH = static_cast<float>(coopInfoTexH) * scale; targetH = static_cast<float>(coopInfoTexH) * scale;
float imgX = bx + (totalW - targetW) * 0.5f; imgX = bx + (totalW - targetW) * 0.5f;
float imgY = by - targetH - 8.0f; // keep the small gap above buttons imgY = by - targetH - 8.0f; // keep the small gap above buttons
float minY = panelBaseY + 6.0f; float minY = panelBaseY + 6.0f;
if (imgY < minY) imgY = minY; if (imgY < minY) imgY = minY;
SDL_FRect dst{ imgX, imgY, targetW, targetH }; 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 // Make the coop info image slightly transparent scaled by transition
SDL_SetTextureAlphaMod(coopInfoTexture, static_cast<Uint8>(std::round(200.0f * alphaFactor))); SDL_SetTextureAlphaMod(coopInfoTexture, static_cast<Uint8>(std::round(200.0f * alphaFactor)));
SDL_RenderTexture(renderer, coopInfoTexture, nullptr, &dst); SDL_RenderTexture(renderer, coopInfoTexture, nullptr, &dst);
hasCoopImg = true;
// Draw cooperative instructions inside the panel area (overlayed on the panel background) // Only draw the instructional overlay text when choosing partner.
FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont; if (coopSetupStep == CoopSetupStep::ChoosePartner) {
if (f) { FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont;
const float pad = 38.0f; if (f) {
float textX = panelBaseX + pad; const float pad = 38.0f;
// Position the text over the lower portion of the image (overlay) float textX = panelBaseX + pad;
// Move the block upward by ~150px to match UI request // Position the text over the lower portion of the image (overlay)
float textY = imgY + targetH - std::min(80.0f, targetH * 0.35f) - 150.0f; // 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) // Bulleted list (measure sample line height first)
const std::vector<std::string> bullets = { const std::vector<std::string> bullets = {
"The playfield is shared between two players", "The playfield is shared between two players",
"Each player controls one half of the grid", "Each player controls one half of the grid",
"A line clears only when both halves are filled", "A line clears only when both halves are filled",
"Timing and coordination are essential" "Timing and coordination are essential"
}; };
float bulletScale = 0.78f; float bulletScale = 0.78f;
SDL_Color bulletCol{200,220,230,220}; SDL_Color bulletCol{200,220,230,220};
bulletCol.a = static_cast<Uint8>(std::round(bulletCol.a * alphaFactor)); bulletCol.a = static_cast<Uint8>(std::round(bulletCol.a * alphaFactor));
int sampleLW = 0, sampleLH = 0; int sampleLW = 0, sampleLH = 0;
f->measure(bullets[0], bulletScale, sampleLW, sampleLH); f->measure(bullets[0], bulletScale, sampleLW, sampleLH);
// Header: move it up by one sample row so it sits higher // Header: move it up by one sample row so it sits higher
const std::string header = "* HOW TO PLAY COOPERATE MODE *"; 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); 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. // 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 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].x + btnW2 * 0.5f,
coopSetupBtnRects[2].y + btnH2 * 0.5f, coopSetupBtnRects[2].y + btnH2 * 0.5f,
btnW2, btnH2, btnW2, btnH2,
"2 PLAYER (NETWORK)", "2 PLAYER (NET)",
false, false,
coopSetupSelected == 2, coopSetupSelected == 2,
bgA, bgA,
@ -1710,7 +1720,9 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
const float roleGap = 48.0f; const float roleGap = 48.0f;
const float roleTotalW = roleBtnW * 2.0f + roleGap; const float roleTotalW = roleBtnW * 2.0f + roleGap;
const float roleX = panelBaseX + (panelW - roleTotalW) * 0.5f + shiftX; 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 hostRect{ roleX, roleY, roleBtnW, btnH2 };
SDL_FRect joinRect{ roleX + roleBtnW + roleGap, 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; FontAtlas* f = ctx.font ? ctx.font : ctx.pixelFont;
if (f) { if (f) {
SDL_Color infoCol{200, 220, 230, static_cast<Uint8>(std::round(220.0f * buttonFade))}; SDL_Color infoCol{200, 220, 230, static_cast<Uint8>(std::round(220.0f * buttonFade))};
char endpoint[256]; // Draw connection info on separate lines and shift right by ~200px
std::snprintf(endpoint, sizeof(endpoint), "PORT %u HOST IP %s JOIN IP %s", char portLine[64];
(unsigned)coopNetworkPort, std::snprintf(portLine, sizeof(portLine), "PORT %u", (unsigned)coopNetworkPort);
coopNetworkBindAddress.c_str(), char hostLine[128];
coopNetworkJoinAddress.c_str()); std::snprintf(hostLine, sizeof(hostLine), "HOST IP %s", coopNetworkBindAddress.c_str());
f->draw(renderer, panelBaseX + 60.0f, roleY + btnH2 + 12.0f, endpoint, 0.90f, infoCol); 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()) { if (coopSetupStep == CoopSetupStep::NetworkWaiting && !coopNetworkStatusText.empty()) {
SDL_Color statusCol{255, 215, 80, static_cast<Uint8>(std::round(240.0f * buttonFade))}; SDL_Color statusCol{255, 215, 80, static_cast<Uint8>(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) { } else if (coopSetupStep == CoopSetupStep::NetworkEnterAddress) {
SDL_Color hintCol{160, 190, 210, static_cast<Uint8>(std::round(200.0f * buttonFade))}; SDL_Color hintCol{160, 190, 210, static_cast<Uint8>(std::round(200.0f * buttonFade))};
const char* label = (coopNetworkRoleSelected == 0) ? "TYPE HOST IP (BIND) THEN ENTER" : "TYPE JOIN IP THEN ENTER"; 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 { } else {
SDL_Color hintCol{160, 190, 210, static_cast<Uint8>(std::round(200.0f * buttonFade))}; SDL_Color hintCol{160, 190, 210, static_cast<Uint8>(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);
} }
} }
} }