diff --git a/image.png b/image.png deleted file mode 100644 index 161c336..0000000 Binary files a/image.png and /dev/null differ diff --git a/src/include/Tetris.h b/src/include/Tetris.h index 1557a5d..0709d56 100644 --- a/src/include/Tetris.h +++ b/src/include/Tetris.h @@ -210,5 +210,6 @@ int GetRogueFallInterval(); int GetRoguePlayableHeight(); int GetRogueLockedRows(); void AdvanceRogueDifficulty(int elapsedMs); +const TCHAR* GetUpgradeSynthesisPath(int upgradeId); void TDrawScreen(HDC hdc, HWND hWnd); diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 99c3617..ab25daa 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -312,15 +312,7 @@ void TDrawScreen(HDC hdc, HWND hWnd) SY(WINDOW_CLIENT_HEIGHT - 70) }; - HPEN menuFramePen = CreatePen(PS_SOLID, 1, frameColor); - HBRUSH menuCardBrush = CreateSolidBrush(cardColor); - oldPen = (HPEN)SelectObject(hdc, menuFramePen); - oldBrush = (HBRUSH)SelectObject(hdc, menuCardBrush); - RoundRect(hdc, menuCard.left, menuCard.top, menuCard.right, menuCard.bottom, SS(34), SS(34)); - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - DeleteObject(menuCardBrush); - DeleteObject(menuFramePen); + DrawPanelCardAlpha(menuCard, cardColor, frameColor, 34, 214); HFONT oldFont = (HFONT)SelectObject(hdc, titleFont); SetTextColor(hdc, titleColor); @@ -372,15 +364,22 @@ void TDrawScreen(HDC hdc, HWND hWnd) top + SS(104) }; - HBRUSH optionBrush = CreateSolidBrush(isSelected ? RGB(255, 232, 240) : RGB(255, 247, 250)); - HPEN optionPen = CreatePen(PS_SOLID, isSelected ? SS(3) : 1, isSelected ? accentColor : RGB(226, 198, 210)); - oldPen = (HPEN)SelectObject(hdc, optionPen); - oldBrush = (HBRUSH)SelectObject(hdc, optionBrush); - RoundRect(hdc, optionRect.left, optionRect.top, optionRect.right, optionRect.bottom, SS(24), SS(24)); - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - DeleteObject(optionBrush); - DeleteObject(optionPen); + DrawPanelCardAlpha( + optionRect, + isSelected ? RGB(255, 232, 240) : RGB(255, 247, 250), + isSelected ? accentColor : RGB(226, 198, 210), + 24, + isSelected ? 208 : 172); + if (isSelected) + { + HPEN optionPen = CreatePen(PS_SOLID, SS(3), accentColor); + oldPen = (HPEN)SelectObject(hdc, optionPen); + oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); + RoundRect(hdc, optionRect.left, optionRect.top, optionRect.right, optionRect.bottom, SS(24), SS(24)); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(optionPen); + } RECT modeNameRect = { @@ -1548,7 +1547,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (currentScreen == SCREEN_UPGRADE) { - HBRUSH dimBrush = CreateSolidBrush(RGB(246, 232, 238)); RECT dimRect = { SX(20), @@ -1556,8 +1554,14 @@ void TDrawScreen(HDC hdc, HWND hWnd) SX(WINDOW_CLIENT_WIDTH - 20), SY(WINDOW_CLIENT_HEIGHT - 20) }; - FillRect(hdc, &dimRect, dimBrush); - DeleteObject(dimBrush); + Graphics dimGraphics(hdc); + SolidBrush dimBrush(Color(214, 246, 232, 238)); + dimGraphics.FillRectangle( + &dimBrush, + static_cast(dimRect.left), + static_cast(dimRect.top), + static_cast(dimRect.right - dimRect.left), + static_cast(dimRect.bottom - dimRect.top)); RECT overlayRect = { @@ -1567,15 +1571,7 @@ void TDrawScreen(HDC hdc, HWND hWnd) SY(WINDOW_CLIENT_HEIGHT - 80) }; - HBRUSH overlayBrush = CreateSolidBrush(RGB(255, 250, 252)); - HPEN overlayPen = CreatePen(PS_SOLID, SS(2), RGB(232, 170, 194)); - oldPen = (HPEN)SelectObject(hdc, overlayPen); - oldBrush = (HBRUSH)SelectObject(hdc, overlayBrush); - RoundRect(hdc, overlayRect.left, overlayRect.top, overlayRect.right, overlayRect.bottom, SS(30), SS(30)); - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - DeleteObject(overlayBrush); - DeleteObject(overlayPen); + DrawPanelCardAlpha(overlayRect, RGB(255, 250, 252), RGB(232, 170, 194), 30, 238); SetTextColor(hdc, titleColor); SelectObject(hdc, titleFont); @@ -1658,15 +1654,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) cardBorder = accentColor; } - HBRUSH cardBrush = CreateSolidBrush(cardFill); - HPEN cardPen = CreatePen(PS_SOLID, isSelected ? SS(3) : 1, cardBorder); - oldPen = (HPEN)SelectObject(hdc, cardPen); - oldBrush = (HBRUSH)SelectObject(hdc, cardBrush); - RoundRect(hdc, cardRect.left, cardRect.top, cardRect.right, cardRect.bottom, SS(24), SS(24)); - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - DeleteObject(cardBrush); - DeleteObject(cardPen); + DrawPanelCardAlpha(cardRect, cardFill, cardBorder, 24, isSelected ? 238 : 226); + if (isSelected) + { + HPEN selectedPen = CreatePen(PS_SOLID, SS(3), cardBorder); + oldPen = (HPEN)SelectObject(hdc, selectedPen); + oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); + RoundRect(hdc, cardRect.left, cardRect.top, cardRect.right, cardRect.bottom, SS(24), SS(24)); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(selectedPen); + } TCHAR levelText[32]; _stprintf_s(levelText, _T("Lv.%d"), upgradeUiState.options[i].currentLevel + 1); @@ -1694,22 +1692,37 @@ void TDrawScreen(HDC hdc, HWND hWnd) SelectObject(hdc, bodyFont); SetTextColor(hdc, descColor); + const TCHAR* synthesisPath = GetUpgradeSynthesisPath(upgradeUiState.options[i].id); + bool hasSynthesisPath = synthesisPath != nullptr && lstrlen(synthesisPath) > 0; RECT descRect = { cardRect.left + SS(20), cardRect.top + SS(116), cardRect.right - SS(20), - cardRect.bottom - SS(64) + cardRect.bottom - (hasSynthesisPath ? SS(98) : SS(64)) }; DrawText(hdc, upgradeUiState.options[i].description, -1, &descRect, DT_LEFT | DT_WORDBREAK); SelectObject(hdc, smallFont); + if (hasSynthesisPath) + { + RECT synthesisRect = + { + cardRect.left + SS(20), + cardRect.bottom - SS(88), + cardRect.right - SS(20), + cardRect.bottom - SS(58) + }; + SetTextColor(hdc, upgradeUiState.options[i].cursed ? RGB(142, 78, 78) : RGB(116, 82, 104)); + DrawText(hdc, synthesisPath, -1, &synthesisRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + RECT footerRect = { cardRect.left + SS(20), - cardRect.bottom - SS(52), + cardRect.bottom - SS(42), cardRect.right - SS(20), - cardRect.bottom - SS(22) + cardRect.bottom - SS(14) }; SetTextColor(hdc, footerColor); DrawText( diff --git a/src/source/TetrisRogue.cpp b/src/source/TetrisRogue.cpp index 440efb2..594f006 100644 --- a/src/source/TetrisRogue.cpp +++ b/src/source/TetrisRogue.cpp @@ -96,6 +96,7 @@ static constexpr int kMaxRogueLockedRows = 4; static constexpr int kDifficultyLevelsPerLockedRow = 3; static int GetUpgradeCurrentLevel(int upgradeId); +static bool IsUpgradePrerequisiteConsumed(int upgradeId); static int GetUpgradeDynamicWeight(const UpgradeEntry& entry); static const TCHAR* GetPieceShortName(int pieceType); static bool IsUpgradeSelectable(const UpgradeEntry& entry); @@ -309,6 +310,68 @@ static int GetUpgradeCurrentLevel(int upgradeId) } } +const TCHAR* GetUpgradeSynthesisPath(int upgradeId) +{ + switch (upgradeId) + { + case UPGRADE_CHAIN_BOMB: + return _T("\u5408\u6210\uff1a\u7206\u7834\u65b9\u5757 -> \u8fde\u73af\u70b8\u5f39"); + case UPGRADE_THUNDER_LASER: + return _T("\u5408\u6210\uff1a\u96f7\u9706\u56db\u6d88 + \u6fc0\u5149\u65b9\u5757"); + case UPGRADE_INFINITE_FEVER: + return _T("\u5408\u6210\uff1a\u72c2\u70ed\u6a21\u5f0f + \u66b4\u8d70\u5806\u53e0"); + case UPGRADE_TERMINAL_CLEAR: + return _T("\u5408\u6210\uff1a\u6700\u540e\u4e00\u640f + \u6e05\u5c4f\u70b8\u5f39 + \u72c2\u70ed"); + case UPGRADE_DESTINY_WHEEL: + return _T("\u5408\u6210\uff1a\u53cc\u91cd\u9009\u62e9 -> \u547d\u8fd0\u8f6e\u76d8"); + case UPGRADE_CONTROL_MASTER: + return _T("\u5408\u6210\uff1aHold \u89e3\u9501 + \u989d\u5916\u9884\u89c8"); + case UPGRADE_EXTREME_PLAYER: + return _T("\u5408\u6210\uff1a\u9ad8\u538b\u5956\u52b1 + \u8d4c\u547d\u56db\u6d88"); + case UPGRADE_EVOLUTION_IMPACT: + return _T("\u5408\u6210\uff1a\u5347\u7ea7\u51b2\u51fb\u6ce2 + \u6210\u957f\u6838\u5fc3"); + case UPGRADE_VOID_CORE: + return _T("\u5408\u6210\uff1a\u9ed1\u6d1e + \u5f69\u8679\u65b9\u5757"); + default: + return _T(""); + } +} + +static bool IsUpgradePrerequisiteConsumed(int upgradeId) +{ + switch (upgradeId) + { + case UPGRADE_EXPLOSIVE_PIECE: + return rogueStats.chainBombLevel > 0; + case UPGRADE_LASER_PIECE: + case UPGRADE_THUNDER_TETRIS: + return rogueStats.thunderLaserLevel > 0; + case UPGRADE_FEVER_MODE: + return rogueStats.infiniteFeverLevel > 0 || rogueStats.terminalClearLevel > 0; + case UPGRADE_RAGE_STACK: + return rogueStats.infiniteFeverLevel > 0; + case UPGRADE_LAST_CHANCE: + case UPGRADE_SCREEN_BOMB: + return rogueStats.terminalClearLevel > 0; + case UPGRADE_DUAL_CHOICE: + return rogueStats.destinyWheelLevel > 0; + case UPGRADE_HOLD_UNLOCK: + case UPGRADE_PREVIEW_PLUS_ONE: + return rogueStats.controlMasterLevel > 0; + case UPGRADE_HIGH_PRESSURE: + case UPGRADE_TETRIS_GAMBLE: + return rogueStats.extremePlayerLevel > 0; + case UPGRADE_UPGRADE_SHOCKWAVE: + case UPGRADE_DOUBLE_GROWTH: + return rogueStats.evolutionImpactLevel > 0; + case UPGRADE_BLACK_HOLE: + case UPGRADE_RAINBOW_PIECE: + return rogueStats.voidCoreLevel > 0; + default: + return false; + } +} + static int GetUpgradeDynamicWeight(const UpgradeEntry& entry) { int weight = entry.baseWeight; @@ -375,6 +438,11 @@ static const TCHAR* GetPieceShortName(int pieceType) static bool IsUpgradeSelectable(const UpgradeEntry& entry) { + if (IsUpgradePrerequisiteConsumed(entry.id)) + { + return false; + } + if (entry.id == UPGRADE_CHAIN_BOMB) { return rogueStats.explosiveLevel > 0 &&