diff --git a/assets/images/cooperate_info.png b/assets/images/cooperate_info.png new file mode 100644 index 0000000..4b586aa Binary files /dev/null and b/assets/images/cooperate_info.png differ diff --git a/settings.ini b/settings.ini index 99029f7..7e2630a 100644 --- a/settings.ini +++ b/settings.ini @@ -14,7 +14,7 @@ SmoothScroll=1 UpRotateClockwise=0 [Player] -Name=GREGOR +Name=P2 [Debug] Enabled=1 diff --git a/src/gameplay/coop/CoopGame.cpp b/src/gameplay/coop/CoopGame.cpp index aad5d23..e6676bc 100644 --- a/src/gameplay/coop/CoopGame.cpp +++ b/src/gameplay/coop/CoopGame.cpp @@ -307,9 +307,8 @@ void CoopGame::spawn(PlayerState& ps) { pieceSequence++; if (collides(ps, ps.cur)) { ps.toppedOut = true; - if (left.toppedOut && right.toppedOut) { - gameOver = true; - } + // Cooperative mode: game ends when any player tops out. + gameOver = true; } } diff --git a/src/states/MenuState.cpp b/src/states/MenuState.cpp index 82cbea5..c2cb59b 100644 --- a/src/states/MenuState.cpp +++ b/src/states/MenuState.cpp @@ -9,6 +9,8 @@ #include "../audio/Audio.h" #include "../audio/SoundEffect.h" #include +#include +#include #include #include #include @@ -256,7 +258,7 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale, ui::BottomMenu menu = ui::buildBottomMenu(params, startLevel, coopVsAI); const int hovered = (ctx.hoveredButton ? *ctx.hoveredButton : -1); - const double baseAlpha = 1.0; + const double baseAlpha = 1.0; // Base alpha for button rendering // Pulse is encoded as a signed delta so PLAY can dim/brighten while focused. const double pulseDelta = (buttonPulseAlpha - 1.0); const double flashDelta = buttonFlash * buttonFlashAmount; @@ -274,6 +276,7 @@ void MenuState::onExit() { if (optionsIcon) { SDL_DestroyTexture(optionsIcon); optionsIcon = nullptr; } if (exitIcon) { SDL_DestroyTexture(exitIcon); exitIcon = nullptr; } if (helpIcon) { SDL_DestroyTexture(helpIcon); helpIcon = nullptr; } + if (coopInfoTexture) { SDL_DestroyTexture(coopInfoTexture); coopInfoTexture = nullptr; } } void MenuState::handleEvent(const SDL_Event& e) { @@ -969,8 +972,8 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi } } - // Small TOP PLAYER label under the logo - const std::string smallTitle = "TOP PLAYER"; + // Small label under the logo — show "COOPERATE" when coop setup is active + const std::string smallTitle = (coopSetupAnimating || coopSetupVisible) ? "COOPERATE" : "TOP PLAYER"; float titleScale = 0.9f; int tW = 0, tH = 0; useFont->measure(smallTitle, titleScale, tW, tH); @@ -1279,12 +1282,15 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi // highscores area (not sliding offscreen with the scores). const float panelBaseY = scoresStartY - 20.0f; - // Make the choice buttons larger and center them vertically in the highscores area - const float btnW2 = std::min(420.0f, panelW * 0.44f); - const float btnH2 = 84.0f; - const float gap = 28.0f; - const float bx = panelBaseX + (panelW - (btnW2 * 2.0f + gap)) * 0.5f; - const float by = panelBaseY + (panelH - btnH2) * 0.5f; + // Make the choice buttons smaller, add more spacing, and raise them higher + const float btnW2 = std::min(300.0f, panelW * 0.30f); + const float btnH2 = 60.0f; + const float gap = 96.0f; + // Shift the image and buttons to the right for layout balance (reduced) + const float shiftX = 20.0f; // move right by 30px (moved 20px left from previous) + const float bx = panelBaseX + (panelW - (btnW2 * 2.0f + gap)) * 0.5f + shiftX; + // Move the buttons up by ~80px to sit closer under the logo + const float by = panelBaseY + (panelH - btnH2) * 0.5f - 80.0f; coopSetupBtnRects[0] = SDL_FRect{ bx, by, btnW2, btnH2 }; coopSetupBtnRects[1] = SDL_FRect{ bx + btnW2 + gap, by, btnW2, btnH2 }; @@ -1292,6 +1298,42 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi SDL_Color bg{ 24, 36, 52, 220 }; SDL_Color border{ 110, 200, 255, 220 }; + + // Load coop info image once when the coop setup is first shown + if (!coopInfoTexture) { + const std::string resolved = AssetPath::resolveImagePath("assets/images/cooperate_info.png"); + if (!resolved.empty()) { + SDL_Surface* surf = IMG_Load(resolved.c_str()); + if (surf) { + // Save dimensions from surface then create texture + coopInfoTexW = surf->w; + coopInfoTexH = surf->h; + coopInfoTexture = SDL_CreateTextureFromSurface(renderer, surf); + SDL_DestroySurface(surf); + } else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "MenuState: failed to load %s: %s", resolved.c_str(), SDL_GetError()); + } + } + } + + // If the image loaded, render it centered above the two choice buttons + if (coopInfoTexture && coopInfoTexW > 0 && coopInfoTexH > 0) { + float totalW = btnW2 * 2.0f + gap; + // 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)); + 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 + float minY = panelBaseY + 6.0f; + if (imgY < minY) imgY = minY; + SDL_FRect dst{ imgX, imgY, targetW, targetH }; + SDL_SetTextureBlendMode(coopInfoTexture, SDL_BLENDMODE_BLEND); + SDL_RenderTexture(renderer, coopInfoTexture, nullptr, &dst); + } + UIRenderer::drawButton(renderer, ctx.pixelFont, coopSetupBtnRects[0].x + btnW2 * 0.5f, coopSetupBtnRects[0].y + btnH2 * 0.5f, btnW2, btnH2, "2 PLAYERS", false, coopSetupSelected == 0, bg, border, false, nullptr); UIRenderer::drawButton(renderer, ctx.pixelFont, coopSetupBtnRects[1].x + btnW2 * 0.5f, coopSetupBtnRects[1].y + btnH2 * 0.5f, diff --git a/src/states/MenuState.h b/src/states/MenuState.h index e148bee..425fcac 100644 --- a/src/states/MenuState.h +++ b/src/states/MenuState.h @@ -107,4 +107,8 @@ private: int coopSetupSelected = 0; // 0 = 2 players, 1 = AI SDL_FRect coopSetupBtnRects[2]{}; bool coopSetupRectsValid = false; + // Optional cooperative info image shown when coop setup panel is active + SDL_Texture* coopInfoTexture = nullptr; + int coopInfoTexW = 0; + int coopInfoTexH = 0; }; diff --git a/src/ui/BottomMenu.cpp b/src/ui/BottomMenu.cpp index 1151f1c..fa7b3cb 100644 --- a/src/ui/BottomMenu.cpp +++ b/src/ui/BottomMenu.cpp @@ -22,7 +22,8 @@ BottomMenu buildBottomMenu(const MenuLayoutParams& params, int startLevel, bool std::snprintf(levelBtnText, sizeof(levelBtnText), "LEVEL %d", startLevel); menu.buttons[0] = Button{ BottomMenuItem::Play, rects[0], "PLAY", false }; - menu.buttons[1] = Button{ BottomMenuItem::Cooperate, rects[1], coopVsAI ? "COOPERATE (AI)" : "COOPERATE (2P)", false }; + // Always show a neutral "COOPERATE" label (remove per-mode suffixes) + menu.buttons[1] = Button{ BottomMenuItem::Cooperate, rects[1], "COOPERATE", false }; menu.buttons[2] = Button{ BottomMenuItem::Challenge, rects[2], "CHALLENGE", false }; menu.buttons[3] = Button{ BottomMenuItem::Level, rects[3], levelBtnText, true }; menu.buttons[4] = Button{ BottomMenuItem::Options, rects[4], "OPTIONS", true };