diff --git a/TODO.md b/TODO.md index 9c7ceca..dc9171e 100644 --- a/TODO.md +++ b/TODO.md @@ -178,8 +178,8 @@ 目标:让系统信息足够清楚,不靠猜测理解机制。 -- [ ] 右侧面板补充等级、EXP 条、强化列表、当前倍率 -- [ ] 增加本次结算浮动提示:`+Score`、`+EXP`、`Level Up` +- [x] 右侧面板补充等级、EXP 条、强化列表、当前倍率 +- [x] 增加本次结算浮动提示:`+Score`、`+EXP`、`Level Up` - [ ] 为特殊强化增加简短提示文案 - [x] 增加暂停、升级、失败三种不同遮罩样式 - [ ] 增加占位图标、占位按钮、占位边框资源 @@ -187,7 +187,7 @@ 完成标准: -- [ ] 玩家能看懂自己为什么升级、为什么得分变化 +- [x] 玩家能看懂自己为什么升级、为什么得分变化 ## 阶段 10:平衡与稳定性 diff --git a/src/include/Tetris.h b/src/include/Tetris.h index 4b586b7..d272850 100644 --- a/src/include/Tetris.h +++ b/src/include/Tetris.h @@ -79,6 +79,13 @@ struct UpgradeUiState UpgradeOption options[3]; }; +struct FeedbackState +{ + int visibleTicks; + TCHAR title[64]; + TCHAR detail[128]; +}; + enum ScreenState { SCREEN_MENU = 0, @@ -107,6 +114,7 @@ extern MenuState menuState; extern PlayerStats classicStats; extern PlayerStats rogueStats; extern UpgradeUiState upgradeUiState; +extern FeedbackState feedbackState; extern int currentScreen; extern int currentMode; extern int currentFallInterval; diff --git a/src/source/Tetris.cpp b/src/source/Tetris.cpp index 70a1136..0bd05e1 100644 --- a/src/source/Tetris.cpp +++ b/src/source/Tetris.cpp @@ -145,30 +145,45 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_TIMER: - if (wParam == GAME_TIMER_ID && - currentScreen == SCREEN_PLAYING && - !suspendFlag && - !gameOverFlag) + if (wParam == GAME_TIMER_ID) { - if (CanMoveDown()) + bool shouldRefresh = false; + + if (feedbackState.visibleTicks > 0) { - MoveDown(); + feedbackState.visibleTicks--; + shouldRefresh = true; } - else + + if (currentScreen == SCREEN_PLAYING && + !suspendFlag && + !gameOverFlag) { - Fixing(); + if (CanMoveDown()) + { + MoveDown(); + } + else + { + Fixing(); + if (!gameOverFlag) + { + DeleteLines(); + } + } + if (!gameOverFlag) { - DeleteLines(); + ComputeTarget(); } + + shouldRefresh = true; } - if (!gameOverFlag) + if (shouldRefresh) { - ComputeTarget(); + InvalidateRect(hWnd, nullptr, FALSE); } - - InvalidateRect(hWnd, nullptr, FALSE); } break; case WM_SIZE: diff --git a/src/source/TetrisLogic.cpp b/src/source/TetrisLogic.cpp index b2bc2ca..f865606 100644 --- a/src/source/TetrisLogic.cpp +++ b/src/source/TetrisLogic.cpp @@ -15,6 +15,7 @@ MenuState menuState = { 0, 2 }; PlayerStats classicStats = { 0, 1, 0, 0, 0 }; PlayerStats rogueStats = { 0, 1, 0, 30, 0, 100, 100, 0 }; UpgradeUiState upgradeUiState = { 0, 0, 0, 0, {} }; +FeedbackState feedbackState = { 0, _T(""), _T("") }; int currentScreen = SCREEN_MENU; int currentMode = MODE_CLASSIC; int currentFallInterval = 500; @@ -246,6 +247,13 @@ static bool IsUpgradeSelectable(const UpgradeEntry& entry) return GetUpgradeCurrentLevel(entry.id) < entry.maxLevel; } +static void SetFeedbackMessage(const TCHAR* title, const TCHAR* detail, int ticks) +{ + feedbackState.visibleTicks = ticks; + lstrcpyn(feedbackState.title, title, sizeof(feedbackState.title) / sizeof(TCHAR)); + lstrcpyn(feedbackState.detail, detail, sizeof(feedbackState.detail) / sizeof(TCHAR)); +} + static void ResetNextQueue() { for (int i = 0; i < 3; i++) @@ -410,9 +418,23 @@ static void ApplyLineClearResult(int linesCleared) rogueStats.totalLinesCleared += linesCleared; rogueStats.score += scoreGain; rogueStats.exp += expGain; - upgradeUiState.pendingCount += ApplyLevelProgress(rogueStats); + int levelUps = ApplyLevelProgress(rogueStats); + upgradeUiState.pendingCount += levelUps; tScore = rogueStats.score; + TCHAR feedbackTitle[64]; + TCHAR feedbackDetail[128]; + _stprintf_s(feedbackTitle, _T("+%d Score +%d EXP"), scoreGain, expGain); + if (levelUps > 0) + { + _stprintf_s(feedbackDetail, _T("Level Up x%d \u5f53\u524d Lv.%d"), levelUps, rogueStats.level); + } + else + { + _stprintf_s(feedbackDetail, _T("\u6d88\u884c %d \u8fde\u51fb %d"), linesCleared, rogueStats.comboChain); + } + SetFeedbackMessage(feedbackTitle, feedbackDetail, 10); + if (upgradeUiState.pendingCount > 0) { OpenUpgradeMenu(); @@ -677,6 +699,11 @@ void Fixing() { DeleteOneLine(nGameHeight - 1); } + + SetFeedbackMessage( + _T("\u6700\u540e\u4e00\u640f\u89e6\u53d1"), + _T("\u81ea\u52a8\u6e05\u9664\u5e95\u90e8 3 \u884c\uff0c\u672c\u5c40\u7ee7\u7eed\u3002"), + 14); } else { @@ -810,6 +837,9 @@ void Restart() upgradeUiState.optionCount = 0; upgradeUiState.pendingCount = 0; upgradeUiState.totalChosenCount = 0; + feedbackState.visibleTicks = 0; + feedbackState.title[0] = _T('\0'); + feedbackState.detail[0] = _T('\0'); tScore = 0; ResetNextQueue(); @@ -869,8 +899,14 @@ void ConfirmUpgradeSelection() return; } - ApplyUpgradeById(upgradeUiState.options[upgradeUiState.selectedIndex].id); + UpgradeOption selectedOption = upgradeUiState.options[upgradeUiState.selectedIndex]; + ApplyUpgradeById(selectedOption.id); upgradeUiState.totalChosenCount++; + TCHAR feedbackTitle[64]; + TCHAR feedbackDetail[128]; + _stprintf_s(feedbackTitle, _T("\u5df2\u83b7\u5f97\uff1a%s"), selectedOption.name); + _stprintf_s(feedbackDetail, _T("%s"), selectedOption.description); + SetFeedbackMessage(feedbackTitle, feedbackDetail, 12); if (upgradeUiState.pendingCount > 0) { diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 67e795f..650b278 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -113,6 +113,19 @@ void TDrawScreen(HDC hdc, HWND hWnd) SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, textColor); + auto DrawPanelCard = [&](const RECT& rect, COLORREF fillColor, COLORREF borderColor, int radius) + { + HBRUSH cardBrush = CreateSolidBrush(fillColor); + HPEN cardPen = CreatePen(PS_SOLID, 1, borderColor); + HGDIOBJ savedPen = SelectObject(hdc, cardPen); + HGDIOBJ savedBrush = SelectObject(hdc, cardBrush); + RoundRect(hdc, rect.left, rect.top, rect.right, rect.bottom, SS(radius), SS(radius)); + SelectObject(hdc, savedBrush); + SelectObject(hdc, savedPen); + DeleteObject(cardBrush); + DeleteObject(cardPen); + }; + if (currentScreen == SCREEN_MENU) { RECT menuCard = @@ -543,56 +556,173 @@ void TDrawScreen(HDC hdc, HWND hWnd) SelectObject(hdc, sectionFont); SetTextColor(hdc, textColor); + RECT overviewRect = + { + panelRect.left + SS(20), + panelRect.top + SS(92), + panelRect.right - SS(20), + panelRect.top + SS(208) + }; + DrawPanelCard(overviewRect, RGB(255, 247, 250), RGB(233, 191, 208), 24); + TCHAR scoreText[64]; _stprintf_s(scoreText, _T("\u5f53\u524d\u5f97\u5206 %d"), tScore); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(104), scoreText, lstrlen(scoreText)); + TextOut(hdc, overviewRect.left + SS(18), overviewRect.top + SS(16), scoreText, lstrlen(scoreText)); TCHAR modeText[64]; _stprintf_s(modeText, _T("\u5f53\u524d\u6a21\u5f0f %s"), currentMode == MODE_CLASSIC ? _T("\u7ecf\u5178") : _T("Rogue")); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(140), modeText, lstrlen(modeText)); + TextOut(hdc, overviewRect.left + SS(18), overviewRect.top + SS(48), modeText, lstrlen(modeText)); TCHAR linesText[64]; int totalLines = (currentMode == MODE_CLASSIC) ? classicStats.totalLinesCleared : rogueStats.totalLinesCleared; _stprintf_s(linesText, _T("\u7d2f\u8ba1\u6d88\u884c %d"), totalLines); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(176), linesText, lstrlen(linesText)); + TextOut(hdc, overviewRect.left + SS(18), overviewRect.top + SS(80), linesText, lstrlen(linesText)); if (currentMode == MODE_ROGUE) { + RECT progressRect = + { + panelRect.left + SS(20), + panelRect.top + SS(224), + panelRect.right - SS(20), + panelRect.top + SS(364) + }; + DrawPanelCard(progressRect, RGB(255, 248, 251), RGB(233, 191, 208), 24); + TCHAR levelText[64]; _stprintf_s(levelText, _T("\u5f53\u524d\u7b49\u7ea7 %d"), rogueStats.level); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(212), levelText, lstrlen(levelText)); + TextOut(hdc, progressRect.left + SS(18), progressRect.top + SS(16), levelText, lstrlen(levelText)); TCHAR expText[64]; _stprintf_s(expText, _T("EXP %d / %d"), rogueStats.exp, rogueStats.requiredExp); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(248), expText, lstrlen(expText)); + TextOut(hdc, progressRect.left + SS(18), progressRect.top + SS(46), expText, lstrlen(expText)); - TCHAR scoreMultiplierText[64]; - _stprintf_s(scoreMultiplierText, _T("\u5206\u6570\u500d\u7387 %d%%"), rogueStats.scoreMultiplierPercent); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(284), scoreMultiplierText, lstrlen(scoreMultiplierText)); + RECT expBarRect = + { + progressRect.left + SS(18), + progressRect.top + SS(82), + progressRect.right - SS(18), + progressRect.top + SS(106) + }; + HBRUSH expTrackBrush = CreateSolidBrush(RGB(240, 220, 229)); + FillRect(hdc, &expBarRect, expTrackBrush); + DeleteObject(expTrackBrush); - TCHAR expMultiplierText[64]; - _stprintf_s(expMultiplierText, _T("EXP \u500d\u7387 %d%%"), rogueStats.expMultiplierPercent); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(320), expMultiplierText, lstrlen(expMultiplierText)); + RECT expFillRect = expBarRect; + int expWidth = expBarRect.right - expBarRect.left; + if (rogueStats.requiredExp > 0) + { + expFillRect.right = expBarRect.left + expWidth * rogueStats.exp / rogueStats.requiredExp; + } + if (expFillRect.right < expFillRect.left) + { + expFillRect.right = expFillRect.left; + } + HBRUSH expFillBrush = CreateSolidBrush(accentColor); + FillRect(hdc, &expFillRect, expFillBrush); + DeleteObject(expFillBrush); - TCHAR fallText[64]; - _stprintf_s(fallText, _T("\u4e0b\u843d\u95f4\u9694 %dms"), currentFallInterval); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(356), fallText, lstrlen(fallText)); + RECT growthRect = + { + progressRect.left + SS(18), + progressRect.top + SS(118), + progressRect.right - SS(18), + progressRect.bottom - SS(16) + }; + SelectObject(hdc, smallFont); + SetTextColor(hdc, RGB(122, 95, 110)); + TCHAR growthText[128]; + _stprintf_s( + growthText, + _T("\u5206\u6570 %d%% EXP %d%% \u901f\u5ea6 %dms"), + rogueStats.scoreMultiplierPercent, + rogueStats.expMultiplierPercent, + currentFallInterval); + DrawText(hdc, growthText, -1, &growthRect, DT_LEFT | DT_TOP | DT_WORDBREAK); + RECT combatRect = + { + panelRect.left + SS(20), + panelRect.top + SS(382), + panelRect.right - SS(20), + panelRect.top + SS(492) + }; + DrawPanelCard(combatRect, RGB(255, 247, 250), RGB(233, 191, 208), 24); + + SelectObject(hdc, sectionFont); + SetTextColor(hdc, textColor); + TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(16), _T("\u5f53\u524d\u6218\u6597\u72b6\u6001"), lstrlen(_T("\u5f53\u524d\u6218\u6597\u72b6\u6001"))); + + SelectObject(hdc, bodyFont); TCHAR comboText[64]; _stprintf_s(comboText, _T("\u8fde\u51fb\u94fe %d \u5956\u52b1\u5c42\u6570 %d"), rogueStats.comboChain, rogueStats.comboBonusStacks); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(392), comboText, lstrlen(comboText)); + TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(50), comboText, lstrlen(comboText)); - TCHAR summaryText[64]; + TCHAR summaryText[96]; _stprintf_s( summaryText, - _T("\u9884\u89c8 %d \u4fdd\u547d %d"), + _T("\u9884\u89c8 %d \u4fdd\u547d %d \u5df2\u9009 %d"), rogueStats.previewCount, - rogueStats.lastChanceCount); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(428), summaryText, lstrlen(summaryText)); + rogueStats.lastChanceCount, + upgradeUiState.totalChosenCount); + TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(82), summaryText, lstrlen(summaryText)); + + RECT upgradeListRect = + { + panelRect.left + SS(20), + panelRect.top + SS(510), + panelRect.right - SS(20), + panelRect.top + SS(676) + }; + DrawPanelCard(upgradeListRect, RGB(255, 248, 251), RGB(233, 191, 208), 24); + + SelectObject(hdc, sectionFont); + SetTextColor(hdc, textColor); + TextOut(hdc, upgradeListRect.left + SS(18), upgradeListRect.top + SS(16), _T("\u5df2\u83b7\u5f97\u5f3a\u5316"), lstrlen(_T("\u5df2\u83b7\u5f97\u5f3a\u5316"))); SelectObject(hdc, smallFont); SetTextColor(hdc, RGB(128, 104, 118)); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(464), _T("\u53f3\u4fa7 HUD \u5df2\u5f00\u59cb\u663e\u793a Rogue \u5f53\u524d\u6210\u957f\u72b6\u6001"), lstrlen(_T("\u53f3\u4fa7 HUD \u5df2\u5f00\u59cb\u663e\u793a Rogue \u5f53\u524d\u6210\u957f\u72b6\u6001"))); + RECT upgradeBodyRect = + { + upgradeListRect.left + SS(18), + upgradeListRect.top + SS(48), + upgradeListRect.right - SS(18), + upgradeListRect.bottom - SS(14) + }; + + TCHAR upgradeSummary[512]; + upgradeSummary[0] = _T('\0'); + + if (rogueStats.scoreUpgradeLevel > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5206\u6570\u500d\u7387 Lv.%d\r\n"), rogueStats.scoreUpgradeLevel); + } + if (rogueStats.expUpgradeLevel > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("EXP \u5f3a\u5316 Lv.%d\r\n"), rogueStats.expUpgradeLevel); + } + if (rogueStats.slowFallStacks > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6162\u901f\u4e0b\u843d Lv.%d\r\n"), rogueStats.slowFallStacks); + } + if (rogueStats.comboBonusStacks > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8fde\u51fb\u52a0\u6210 Lv.%d\r\n"), rogueStats.comboBonusStacks); + } + if (rogueStats.previewUpgradeLevel > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u989d\u5916\u9884\u89c8 Lv.%d\r\n"), rogueStats.previewUpgradeLevel); + } + if (rogueStats.lastChanceUpgradeLevel > 0) + { + _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6700\u540e\u4e00\u640f Lv.1 \u5269\u4f59 %d \u6b21\r\n"), rogueStats.lastChanceCount); + } + if (lstrlen(upgradeSummary) == 0) + { + _stprintf_s(upgradeSummary, _T("\u6682\u672a\u9009\u62e9\u4efb\u4f55\u5f3a\u5316\u3002\r\n\u5347\u7ea7\u540e\u4f1a\u5728\u8fd9\u91cc\u7d2f\u79ef\u663e\u793a\u3002")); + } + + DrawText(hdc, upgradeSummary, -1, &upgradeBodyRect, DT_LEFT | DT_TOP | DT_WORDBREAK); SelectObject(hdc, sectionFont); SetTextColor(hdc, textColor); } @@ -600,13 +730,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) { SelectObject(hdc, smallFont); SetTextColor(hdc, RGB(128, 104, 118)); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(212), _T("\u7ecf\u5178\u6a21\u5f0f\u4fdd\u6301\u539f\u7248\u7b80\u5355\u8ba1\u5206"), lstrlen(_T("\u7ecf\u5178\u6a21\u5f0f\u4fdd\u6301\u539f\u7248\u7b80\u5355\u8ba1\u5206"))); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(240), _T("\u6682\u4e0d\u63a5\u5165\u7b49\u7ea7\u548c\u5f3a\u5316\u7cfb\u7edf"), lstrlen(_T("\u6682\u4e0d\u63a5\u5165\u7b49\u7ea7\u548c\u5f3a\u5316\u7cfb\u7edf"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(232), _T("\u7ecf\u5178\u6a21\u5f0f\u4fdd\u6301\u539f\u7248\u7b80\u5355\u8ba1\u5206"), lstrlen(_T("\u7ecf\u5178\u6a21\u5f0f\u4fdd\u6301\u539f\u7248\u7b80\u5355\u8ba1\u5206"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(260), _T("\u6682\u4e0d\u63a5\u5165\u7b49\u7ea7\u548c\u5f3a\u5316\u7cfb\u7edf"), lstrlen(_T("\u6682\u4e0d\u63a5\u5165\u7b49\u7ea7\u548c\u5f3a\u5316\u7cfb\u7edf"))); SelectObject(hdc, sectionFont); SetTextColor(hdc, textColor); } - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(430), _T("\u4e0b\u4e00\u4e2a\u65b9\u5757"), lstrlen(_T("\u4e0b\u4e00\u4e2a\u65b9\u5757"))); + int previewTitleTop = (currentMode == MODE_ROGUE) ? panelRect.top + SS(690) : panelRect.top + SS(430); + int nextCardTop = (currentMode == MODE_ROGUE) ? panelRect.top + SS(724) : panelRect.top + SS(472); + int hintTop = (currentMode == MODE_ROGUE) ? panelRect.top + SS(818) : panelRect.top + SS(656); + + TextOut(hdc, panelRect.left + SS(24), previewTitleTop, _T("\u4e0b\u4e00\u4e2a\u65b9\u5757"), lstrlen(_T("\u4e0b\u4e00\u4e2a\u65b9\u5757"))); int previewCount = 1; if (currentMode == MODE_ROGUE) @@ -627,9 +761,9 @@ void TDrawScreen(HDC hdc, HWND hWnd) RECT nextCard = { panelRect.left + SS(24) + previewIndex * SS(94), - panelRect.top + SS(472), + nextCardTop, panelRect.left + SS(24) + previewIndex * SS(94) + grid * 2 + SS(40), - panelRect.top + SS(472) + grid * 2 + SS(40) + nextCardTop + grid * 2 + SS(40) }; HBRUSH nextCardBrush = CreateSolidBrush(RGB(255, 238, 244)); @@ -674,8 +808,42 @@ void TDrawScreen(HDC hdc, HWND hWnd) SelectObject(hdc, smallFont); SetTextColor(hdc, RGB(128, 104, 118)); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(656), _T("M \uff1a\u8fd4\u56de\u83dc\u5355"), lstrlen(_T("M \uff1a\u8fd4\u56de\u83dc\u5355"))); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(688), _T("\u89c4\u5219\u8bf4\u660e\u8bf7\u5728\u4e3b\u83dc\u5355\u8fdb\u5165"), lstrlen(_T("\u89c4\u5219\u8bf4\u660e\u8bf7\u5728\u4e3b\u83dc\u5355\u8fdb\u5165"))); + TextOut(hdc, panelRect.left + SS(24), hintTop, _T("M \uff1a\u8fd4\u56de\u83dc\u5355"), lstrlen(_T("M \uff1a\u8fd4\u56de\u83dc\u5355"))); + TextOut(hdc, panelRect.left + SS(24), hintTop + SS(32), _T("\u89c4\u5219\u8bf4\u660e\u8bf7\u5728\u4e3b\u83dc\u5355\u8fdb\u5165"), lstrlen(_T("\u89c4\u5219\u8bf4\u660e\u8bf7\u5728\u4e3b\u83dc\u5355\u8fdb\u5165"))); + + if (feedbackState.visibleTicks > 0) + { + RECT feedbackRect = + { + gameRect.left + SS(16), + gameRect.top + SS(16), + gameRect.right - SS(16), + gameRect.top + SS(98) + }; + DrawPanelCard(feedbackRect, RGB(255, 245, 249), RGB(232, 170, 194), 22); + + SelectObject(hdc, bodyFont); + SetTextColor(hdc, titleColor); + RECT titleRect = + { + feedbackRect.left + SS(16), + feedbackRect.top + SS(12), + feedbackRect.right - SS(16), + feedbackRect.top + SS(40) + }; + DrawText(hdc, feedbackState.title, -1, &titleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + + SelectObject(hdc, smallFont); + SetTextColor(hdc, RGB(116, 90, 104)); + RECT detailRect = + { + feedbackRect.left + SS(16), + feedbackRect.top + SS(42), + feedbackRect.right - SS(16), + feedbackRect.bottom - SS(12) + }; + DrawText(hdc, feedbackState.detail, -1, &detailRect, DT_LEFT | DT_WORDBREAK); + } if (suspendFlag || gameOverFlag) {