From 7db0bfadfc70e4a3f3819327ba986c69a654e2b8 Mon Sep 17 00:00:00 2001 From: Qi-huanye <2728290997@qq.com> Date: Sun, 26 Apr 2026 16:02:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=BC=A0=E6=A0=87=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- image.png | Bin 0 -> 8630 bytes src/source/Tetris.cpp | 417 ++++++++++++++++++++++++++++++++++-- src/source/TetrisRender.cpp | 127 +++++++++-- 3 files changed, 507 insertions(+), 37 deletions(-) create mode 100644 image.png diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..58b16c6085a259475f745f27ddf202e77d3be750 GIT binary patch literal 8630 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 1) + { + bool currentlyMarked = upgradeUiState.marked[i]; + if (currentlyMarked) + { + upgradeUiState.marked[i] = false; + if (upgradeUiState.markedCount > 0) + { + upgradeUiState.markedCount--; + } + } + else if (upgradeUiState.markedCount < upgradeUiState.picksRemaining) + { + upgradeUiState.marked[i] = true; + upgradeUiState.markedCount++; + } + + if (upgradeUiState.markedCount == upgradeUiState.picksRemaining) + { + ConfirmUpgradeSelection(); + ResetGameTimer(hWnd); + } + } + else + { + ConfirmUpgradeSelection(); + ResetGameTimer(hWnd); + } + + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + break; + } + + if (currentScreen == SCREEN_PLAYING && suspendFlag) + { + if (IsPointInRect(GetOverlayButtonRect(hWnd, 0, 2), mouseX, mouseY)) + { + suspendFlag = false; + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + if (IsPointInRect(GetOverlayButtonRect(hWnd, 1, 2), mouseX, mouseY)) + { + ReturnToMainMenu(); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + } + + if (currentScreen == SCREEN_PLAYING && gameOverFlag) + { + if (reviveAvailable) + { + if (IsPointInRect(GetOverlayButtonRect(hWnd, 0, 3), mouseX, mouseY)) + { + if (PlayReviveVideo(hWnd)) + { + ReviveAfterVideo(); + ResetGameTimer(hWnd); + } + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + if (IsPointInRect(GetOverlayButtonRect(hWnd, 1, 3), mouseX, mouseY)) + { + StartGameWithMode(currentMode); + ResetGameTimer(hWnd); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + if (IsPointInRect(GetOverlayButtonRect(hWnd, 2, 3), mouseX, mouseY)) + { + ReturnToMainMenu(); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + } + else + { + if (IsPointInRect(GetOverlayButtonRect(hWnd, 0, 2), mouseX, mouseY)) + { + StartGameWithMode(currentMode); + ResetGameTimer(hWnd); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + if (IsPointInRect(GetOverlayButtonRect(hWnd, 1, 2), mouseX, mouseY)) + { + ReturnToMainMenu(); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + } + } + return DefWindowProc(hWnd, message, wParam, lParam); } case WM_KEYDOWN: diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 631c1b4..835af4f 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -374,6 +374,33 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(musicPen); }; + auto DrawBackButton = [&]() + { + RECT backButtonRect = + { + SX(6), + SY(6), + SX(34), + SY(34) + }; + DrawPanelCardAlpha( + backButtonRect, + RGB(255, 242, 247), + RGB(222, 130, 166), + 12, + 214); + + HPEN backPen = CreatePen(PS_SOLID, SS(3), RGB(128, 70, 100)); + HPEN oldBackPen = (HPEN)SelectObject(hdc, backPen); + MoveToEx(hdc, backButtonRect.left + SS(20), backButtonRect.top + SS(8), nullptr); + LineTo(hdc, backButtonRect.left + SS(10), backButtonRect.top + SS(14)); + LineTo(hdc, backButtonRect.left + SS(20), backButtonRect.top + SS(20)); + MoveToEx(hdc, backButtonRect.left + SS(10), backButtonRect.top + SS(14), nullptr); + LineTo(hdc, backButtonRect.right - SS(8), backButtonRect.top + SS(14)); + SelectObject(hdc, oldBackPen); + DeleteObject(backPen); + }; + if (currentScreen == SCREEN_MENU) { RECT menuCard = @@ -746,6 +773,7 @@ void TDrawScreen(HDC hdc, HWND hWnd) : _T("Esc / Backspace / M \u8fd4\u56de\u5e2e\u52a9"); DrawText(hdc, helpHint, -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawBackButton(); DrawMusicButton(); SelectObject(hdc, oldFont); DeleteObject(titleFont); @@ -1767,10 +1795,10 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RECT overlayRect = { - gameRect.left + SS(48), - gameRect.top + grid * 7, - gameRect.right - SS(48), - gameRect.top + grid * 11 + SS(18) + gameRect.left + SS(28), + gameRect.top + grid * 6 + SS(10), + gameRect.right - SS(28), + gameRect.top + grid * 10 + SS(30) }; HBRUSH overlayBrush = CreateSolidBrush(RGB(255, 241, 246)); @@ -1805,21 +1833,88 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (suspendFlag) { DrawText(hdc, _T("时间静止"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + int buttonGap = SS(18); + int buttonWidth = (overlayRect.right - overlayRect.left - SS(68) - buttonGap) / 2; + RECT continueRect = + { + overlayRect.left + SS(34), + overlayRect.top + SS(94), + overlayRect.left + SS(34) + buttonWidth, + overlayRect.top + SS(138) + }; + RECT menuRect = + { + continueRect.right + buttonGap, + continueRect.top, + overlayRect.right - SS(34), + continueRect.bottom + }; + DrawPanelCardAlpha(continueRect, RGB(255, 232, 240), RGB(222, 130, 166), 18, 224); + DrawPanelCardAlpha(menuRect, RGB(255, 247, 250), RGB(210, 182, 194), 18, 210); SelectObject(hdc, bodyFont); - DrawText(hdc, _T("按 P 继续战斗"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK); + DrawText(hdc, _T("继续 (P)"), -1, &continueRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("主菜单 (M)"), -1, &menuRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else { DrawText(hdc, _T("战局崩塌"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - SelectObject(hdc, bodyFont); - DrawText( - hdc, - reviveAvailable - ? _T("按 V 看视频复活(仅一次)\r\n按 R 重新挑战 或按 M 返回菜单") - : _T("按 R 重新挑战\r\n或按 M 返回菜单"), - -1, - &tipRect, - DT_CENTER | DT_VCENTER | DT_WORDBREAK); + if (reviveAvailable) + { + int buttonGap = SS(8); + int buttonWidth = (overlayRect.right - overlayRect.left - SS(28) - buttonGap * 2) / 3; + RECT reviveRect = + { + overlayRect.left + SS(14), + overlayRect.top + SS(94), + overlayRect.left + SS(14) + buttonWidth, + overlayRect.top + SS(138) + }; + RECT restartRect = + { + reviveRect.right + buttonGap, + reviveRect.top, + reviveRect.right + buttonGap + buttonWidth, + reviveRect.bottom + }; + RECT menuRect = + { + restartRect.right + buttonGap, + reviveRect.top, + overlayRect.right - SS(14), + reviveRect.bottom + }; + DrawPanelCardAlpha(reviveRect, RGB(255, 232, 240), RGB(222, 130, 166), 18, 224); + DrawPanelCardAlpha(restartRect, RGB(255, 247, 250), RGB(210, 182, 194), 18, 210); + DrawPanelCardAlpha(menuRect, RGB(255, 247, 250), RGB(210, 182, 194), 18, 210); + SelectObject(hdc, bodyFont); + DrawText(hdc, _T("复活 (V)"), -1, &reviveRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("重开 (R)"), -1, &restartRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("主菜单 (M)"), -1, &menuRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + else + { + int buttonGap = SS(18); + int buttonWidth = (overlayRect.right - overlayRect.left - SS(68) - buttonGap) / 2; + RECT restartRect = + { + overlayRect.left + SS(34), + overlayRect.top + SS(94), + overlayRect.left + SS(34) + buttonWidth, + overlayRect.top + SS(138) + }; + RECT menuRect = + { + restartRect.right + buttonGap, + restartRect.top, + overlayRect.right - SS(34), + restartRect.bottom + }; + DrawPanelCardAlpha(restartRect, RGB(255, 232, 240), RGB(222, 130, 166), 18, 224); + DrawPanelCardAlpha(menuRect, RGB(255, 247, 250), RGB(210, 182, 194), 18, 210); + SelectObject(hdc, bodyFont); + DrawText(hdc, _T("重开 (R)"), -1, &restartRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("主菜单 (M)"), -1, &menuRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } } } @@ -2075,6 +2170,10 @@ void TDrawScreen(HDC hdc, HWND hWnd) DT_CENTER | DT_VCENTER | DT_SINGLELINE); } + if (currentScreen != SCREEN_MENU) + { + DrawBackButton(); + } DrawMusicButton(); SelectObject(hdc, oldFont);