2025 lines
77 KiB
C++
2025 lines
77 KiB
C++
#include "stdafx.h"
|
|
#include "Tetris.h"
|
|
#include <objidl.h>
|
|
#include <gdiplus.h>
|
|
#include <string>
|
|
|
|
#pragma comment(lib, "gdiplus.lib")
|
|
|
|
using namespace Gdiplus;
|
|
|
|
static std::wstring BuildAssetPath(const wchar_t* relativePath)
|
|
{
|
|
wchar_t modulePath[MAX_PATH] = {};
|
|
GetModuleFileNameW(nullptr, modulePath, MAX_PATH);
|
|
|
|
std::wstring basePath(modulePath);
|
|
size_t lastSlash = basePath.find_last_of(L"\\/");
|
|
if (lastSlash != std::wstring::npos)
|
|
{
|
|
basePath.resize(lastSlash);
|
|
}
|
|
|
|
std::wstring projectRelative = basePath + L"\\..\\..\\" + relativePath;
|
|
wchar_t fullPath[MAX_PATH] = {};
|
|
DWORD result = GetFullPathNameW(projectRelative.c_str(), MAX_PATH, fullPath, nullptr);
|
|
if (result > 0 && result < MAX_PATH)
|
|
{
|
|
return fullPath;
|
|
}
|
|
|
|
return projectRelative;
|
|
}
|
|
|
|
static std::wstring BuildWorkingDirAssetPath(const wchar_t* relativePath)
|
|
{
|
|
wchar_t currentDirectory[MAX_PATH] = {};
|
|
DWORD length = GetCurrentDirectoryW(MAX_PATH, currentDirectory);
|
|
if (length == 0 || length >= MAX_PATH)
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
std::wstring candidate = std::wstring(currentDirectory) + L"\\" + relativePath;
|
|
wchar_t fullPath[MAX_PATH] = {};
|
|
DWORD result = GetFullPathNameW(candidate.c_str(), MAX_PATH, fullPath, nullptr);
|
|
if (result > 0 && result < MAX_PATH)
|
|
{
|
|
return fullPath;
|
|
}
|
|
|
|
return candidate;
|
|
}
|
|
|
|
static Bitmap* LoadBackgroundImage()
|
|
{
|
|
static ULONG_PTR gdiplusToken = 0;
|
|
static Bitmap* backgroundImage = nullptr;
|
|
static bool attempted = false;
|
|
|
|
if (!attempted)
|
|
{
|
|
attempted = true;
|
|
|
|
GdiplusStartupInput startupInput;
|
|
if (GdiplusStartup(&gdiplusToken, &startupInput, nullptr) == Ok)
|
|
{
|
|
const std::wstring candidates[] =
|
|
{
|
|
BuildAssetPath(L"assets\\images\\background.png"),
|
|
BuildWorkingDirAssetPath(L"assets\\images\\background.png"),
|
|
BuildAssetPath(L"assets\\images\\background.bmp"),
|
|
BuildWorkingDirAssetPath(L"assets\\images\\background.bmp")
|
|
};
|
|
|
|
for (const std::wstring& candidate : candidates)
|
|
{
|
|
if (candidate.empty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
DWORD attributes = GetFileAttributesW(candidate.c_str());
|
|
if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Bitmap* loadedImage = Bitmap::FromFile(candidate.c_str(), FALSE);
|
|
if (loadedImage != nullptr && loadedImage->GetLastStatus() == Ok)
|
|
{
|
|
backgroundImage = loadedImage;
|
|
break;
|
|
}
|
|
|
|
delete loadedImage;
|
|
}
|
|
}
|
|
}
|
|
|
|
return backgroundImage;
|
|
}
|
|
|
|
void TDrawScreen(HDC hdc, HWND hWnd)
|
|
{
|
|
RECT clientRect;
|
|
GetClientRect(hWnd, &clientRect);
|
|
|
|
int clientWidth = clientRect.right - clientRect.left;
|
|
int clientHeight = clientRect.bottom - clientRect.top;
|
|
int scaleX = MulDiv(clientWidth, 1000, WINDOW_CLIENT_WIDTH);
|
|
int scaleY = MulDiv(clientHeight, 1000, WINDOW_CLIENT_HEIGHT);
|
|
int scale = (scaleX < scaleY) ? scaleX : scaleY;
|
|
|
|
if (scale < 500)
|
|
{
|
|
scale = 500;
|
|
}
|
|
|
|
int layoutWidth = MulDiv(WINDOW_CLIENT_WIDTH, scale, 1000);
|
|
int layoutHeight = MulDiv(WINDOW_CLIENT_HEIGHT, scale, 1000);
|
|
int offsetX = (clientWidth - layoutWidth) / 2;
|
|
int offsetY = 0;
|
|
|
|
auto SX = [offsetX, scale](int value) -> int
|
|
{
|
|
return offsetX + MulDiv(value, scale, 1000);
|
|
};
|
|
|
|
auto SY = [offsetY, scale](int value) -> int
|
|
{
|
|
return offsetY + MulDiv(value, scale, 1000);
|
|
};
|
|
|
|
auto SS = [scale](int value) -> int
|
|
{
|
|
int result = MulDiv(value, scale, 1000);
|
|
return result < 1 ? 1 : result;
|
|
};
|
|
|
|
int grid = SS(GRID);
|
|
int previewMiniCell = SS(16);
|
|
int panelGap = SS(SIDE_PANEL_GAP);
|
|
int panelWidth = SS(SIDE_PANEL_WIDTH);
|
|
int panelHeight = SS(SIDE_PANEL_HEIGHT - WINDOW_PADDING * 2);
|
|
int boardWidth = grid * nGameWidth;
|
|
int boardHeight = grid * nGameHeight;
|
|
|
|
const RECT leftPanelRect =
|
|
{
|
|
SX(WINDOW_PADDING),
|
|
SY(WINDOW_PADDING),
|
|
SX(WINDOW_PADDING) + panelWidth,
|
|
SY(WINDOW_PADDING) + panelHeight
|
|
};
|
|
|
|
const RECT gameRect =
|
|
{
|
|
leftPanelRect.right + panelGap,
|
|
SY(WINDOW_PADDING),
|
|
leftPanelRect.right + panelGap + boardWidth,
|
|
SY(WINDOW_PADDING) + boardHeight
|
|
};
|
|
|
|
const RECT rightPanelRect =
|
|
{
|
|
gameRect.right + panelGap,
|
|
SY(WINDOW_PADDING),
|
|
gameRect.right + panelGap + panelWidth,
|
|
SY(WINDOW_PADDING) + panelHeight
|
|
};
|
|
|
|
const COLORREF pageColor = RGB(255, 244, 248);
|
|
const COLORREF blobColorA = RGB(255, 230, 238);
|
|
const COLORREF blobColorB = RGB(250, 221, 233);
|
|
const COLORREF cardColor = RGB(255, 252, 253);
|
|
const COLORREF boardColor = RGB(70, 57, 78);
|
|
const COLORREF boardInnerColor = RGB(54, 44, 62);
|
|
const COLORREF lineColor = RGB(104, 90, 116);
|
|
const COLORREF frameColor = RGB(212, 168, 188);
|
|
const COLORREF titleColor = RGB(104, 62, 84);
|
|
const COLORREF textColor = RGB(92, 73, 88);
|
|
const COLORREF accentColor = RGB(228, 145, 182);
|
|
const BYTE shellAlpha = 142;
|
|
const BYTE panelAlpha = 150;
|
|
const BYTE panelNestedAlpha = 128;
|
|
const BYTE panelStrongAlpha = 168;
|
|
|
|
Bitmap* backgroundImage = LoadBackgroundImage();
|
|
if (backgroundImage != nullptr)
|
|
{
|
|
Graphics graphics(hdc);
|
|
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
|
|
graphics.DrawImage(
|
|
backgroundImage,
|
|
Rect(0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top));
|
|
SolidBrush washBrush(Color(76, 255, 250, 252));
|
|
graphics.FillRectangle(&washBrush, 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
|
}
|
|
else
|
|
{
|
|
HBRUSH pageBrush = CreateSolidBrush(pageColor);
|
|
FillRect(hdc, &clientRect, pageBrush);
|
|
DeleteObject(pageBrush);
|
|
}
|
|
|
|
HBRUSH oldBrush = nullptr;
|
|
HPEN oldPen = nullptr;
|
|
if (backgroundImage == nullptr)
|
|
{
|
|
HBRUSH blobBrushA = CreateSolidBrush(blobColorA);
|
|
HBRUSH blobBrushB = CreateSolidBrush(blobColorB);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, blobBrushA);
|
|
oldPen = (HPEN)SelectObject(hdc, GetStockObject(NULL_PEN));
|
|
Ellipse(hdc, clientRect.right - 260, -20, clientRect.right + 80, 260);
|
|
Ellipse(hdc, -80, clientRect.bottom - 200, 220, clientRect.bottom + 70);
|
|
SelectObject(hdc, blobBrushB);
|
|
Ellipse(hdc, clientRect.right - 180, clientRect.bottom - 220, clientRect.right + 120, clientRect.bottom + 40);
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(blobBrushA);
|
|
DeleteObject(blobBrushB);
|
|
}
|
|
|
|
HFONT titleFont = CreateFont(
|
|
-SS(36), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
|
|
DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
|
|
VARIABLE_PITCH, _T("Microsoft YaHei UI"));
|
|
|
|
HFONT sectionFont = CreateFont(
|
|
-SS(22), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
|
|
DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
|
|
VARIABLE_PITCH, _T("Microsoft YaHei UI"));
|
|
|
|
HFONT bodyFont = CreateFont(
|
|
-SS(18), 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,
|
|
DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
|
|
VARIABLE_PITCH, _T("Microsoft YaHei UI"));
|
|
|
|
HFONT smallFont = CreateFont(
|
|
-SS(15), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
|
DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
|
|
VARIABLE_PITCH, _T("Microsoft YaHei UI"));
|
|
|
|
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);
|
|
};
|
|
|
|
auto DrawPanelCardAlpha = [&](const RECT& rect, COLORREF fillColor, COLORREF borderColor, int radius, BYTE alpha)
|
|
{
|
|
Graphics graphics(hdc);
|
|
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
|
|
|
|
GraphicsPath path;
|
|
INT left = static_cast<INT>(rect.left);
|
|
INT top = static_cast<INT>(rect.top);
|
|
INT width = static_cast<INT>(rect.right - rect.left);
|
|
INT height = static_cast<INT>(rect.bottom - rect.top);
|
|
INT corner = static_cast<INT>(SS(radius));
|
|
|
|
path.AddArc(left, top, corner, corner, 180.0f, 90.0f);
|
|
path.AddArc(left + width - corner, top, corner, corner, 270.0f, 90.0f);
|
|
path.AddArc(left + width - corner, top + height - corner, corner, corner, 0.0f, 90.0f);
|
|
path.AddArc(left, top + height - corner, corner, corner, 90.0f, 90.0f);
|
|
path.CloseFigure();
|
|
|
|
SolidBrush brush(Color(alpha, GetRValue(fillColor), GetGValue(fillColor), GetBValue(fillColor)));
|
|
Pen pen(Color(232, GetRValue(borderColor), GetGValue(borderColor), GetBValue(borderColor)), 1.0f);
|
|
graphics.FillPath(&brush, &path);
|
|
graphics.DrawPath(&pen, &path);
|
|
};
|
|
|
|
auto DrawPanelHeader = [&](const RECT& panelRect, const TCHAR* title, int lineWidth)
|
|
{
|
|
SelectObject(hdc, titleFont);
|
|
SetTextColor(hdc, titleColor);
|
|
RECT titleRect =
|
|
{
|
|
panelRect.left + SS(24),
|
|
panelRect.top + SS(20),
|
|
panelRect.right - SS(24),
|
|
panelRect.top + SS(62)
|
|
};
|
|
DrawText(hdc, title, -1, &titleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
HPEN localAccentPen = CreatePen(PS_SOLID, SS(3), accentColor);
|
|
HPEN savedPen = (HPEN)SelectObject(hdc, localAccentPen);
|
|
MoveToEx(hdc, panelRect.left + SS(24), panelRect.top + SS(78), nullptr);
|
|
LineTo(hdc, panelRect.left + SS(24) + SS(lineWidth), panelRect.top + SS(78));
|
|
SelectObject(hdc, savedPen);
|
|
DeleteObject(localAccentPen);
|
|
};
|
|
|
|
auto DrawMusicButton = [&]()
|
|
{
|
|
RECT musicButtonRect =
|
|
{
|
|
SX(WINDOW_CLIENT_WIDTH - 40),
|
|
SY(WINDOW_CLIENT_HEIGHT - 40),
|
|
SX(WINDOW_CLIENT_WIDTH - 12),
|
|
SY(WINDOW_CLIENT_HEIGHT - 12)
|
|
};
|
|
DrawPanelCardAlpha(
|
|
musicButtonRect,
|
|
bgmEnabled ? RGB(255, 238, 246) : RGB(244, 236, 240),
|
|
bgmEnabled ? RGB(222, 130, 166) : RGB(170, 148, 158),
|
|
12,
|
|
bgmEnabled ? 218 : 190);
|
|
|
|
HPEN musicPen = CreatePen(PS_SOLID, SS(3), bgmEnabled ? RGB(128, 70, 100) : RGB(128, 112, 120));
|
|
HPEN oldMusicPen = (HPEN)SelectObject(hdc, musicPen);
|
|
HBRUSH oldMusicBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
|
|
int noteStemX = musicButtonRect.left + SS(17);
|
|
int noteTop = musicButtonRect.top + SS(7);
|
|
int noteBottom = musicButtonRect.bottom - SS(9);
|
|
MoveToEx(hdc, noteStemX, noteTop, nullptr);
|
|
LineTo(hdc, noteStemX, noteBottom);
|
|
MoveToEx(hdc, noteStemX, noteTop, nullptr);
|
|
LineTo(hdc, musicButtonRect.right - SS(7), noteTop + SS(4));
|
|
LineTo(hdc, musicButtonRect.right - SS(7), noteTop + SS(10));
|
|
Ellipse(
|
|
hdc,
|
|
musicButtonRect.left + SS(7),
|
|
musicButtonRect.bottom - SS(13),
|
|
musicButtonRect.left + SS(19),
|
|
musicButtonRect.bottom - SS(4));
|
|
|
|
if (!bgmEnabled)
|
|
{
|
|
MoveToEx(hdc, musicButtonRect.left + SS(7), musicButtonRect.bottom - SS(7), nullptr);
|
|
LineTo(hdc, musicButtonRect.right - SS(6), musicButtonRect.top + SS(6));
|
|
}
|
|
|
|
SelectObject(hdc, oldMusicBrush);
|
|
SelectObject(hdc, oldMusicPen);
|
|
DeleteObject(musicPen);
|
|
};
|
|
|
|
if (currentScreen == SCREEN_MENU)
|
|
{
|
|
RECT menuCard =
|
|
{
|
|
SX(110),
|
|
SY(70),
|
|
SX(WINDOW_CLIENT_WIDTH - 110),
|
|
SY(WINDOW_CLIENT_HEIGHT - 70)
|
|
};
|
|
|
|
DrawPanelCardAlpha(menuCard, cardColor, frameColor, 34, 214);
|
|
|
|
HFONT oldFont = (HFONT)SelectObject(hdc, titleFont);
|
|
SetTextColor(hdc, titleColor);
|
|
|
|
RECT titleRect =
|
|
{
|
|
menuCard.left,
|
|
menuCard.top + SS(24),
|
|
menuCard.right,
|
|
menuCard.top + SS(70)
|
|
};
|
|
DrawText(hdc, _T("Rogue Tetris"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
RECT subtitleRect =
|
|
{
|
|
menuCard.left,
|
|
menuCard.top + SS(72),
|
|
menuCard.right,
|
|
menuCard.top + SS(110)
|
|
};
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, textColor);
|
|
DrawText(hdc, _T("选择你的战局"), -1, &subtitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
const TCHAR* modeNames[3] =
|
|
{
|
|
_T("\u7ecf\u5178\u6a21\u5f0f"),
|
|
_T("Rogue \u6a21\u5f0f"),
|
|
_T("\u5e2e\u52a9")
|
|
};
|
|
|
|
const TCHAR* modeDescriptions[3] =
|
|
{
|
|
_T("纯粹方块挑战,专注消行、堆叠与生存。"),
|
|
_T("在不断升级的棋盘中收集强化,构筑本局专属流派。"),
|
|
_T("查看操作、模式规则与全部强化效果。")
|
|
};
|
|
|
|
for (int i = 0; i < menuState.optionCount; i++)
|
|
{
|
|
bool isSelected = (i == menuState.selectedIndex);
|
|
int top = menuCard.top + SS(140) + i * SS(130);
|
|
|
|
RECT optionRect =
|
|
{
|
|
menuCard.left + SS(36),
|
|
top,
|
|
menuCard.right - SS(36),
|
|
top + SS(104)
|
|
};
|
|
|
|
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 =
|
|
{
|
|
optionRect.left + SS(24),
|
|
optionRect.top + SS(14),
|
|
optionRect.right - SS(24),
|
|
optionRect.top + SS(44)
|
|
};
|
|
|
|
RECT modeDescriptionRect =
|
|
{
|
|
optionRect.left + SS(24),
|
|
optionRect.top + SS(46),
|
|
optionRect.right - SS(24),
|
|
optionRect.bottom - SS(14)
|
|
};
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, isSelected ? titleColor : textColor);
|
|
DrawText(hdc, modeNames[i], -1, &modeNameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(118, 96, 110));
|
|
DrawText(hdc, modeDescriptions[i], -1, &modeDescriptionRect, DT_LEFT | DT_WORDBREAK);
|
|
}
|
|
|
|
RECT hintRect =
|
|
{
|
|
menuCard.left + SS(36),
|
|
menuCard.bottom - SS(92),
|
|
menuCard.right - SS(36),
|
|
menuCard.bottom - SS(36)
|
|
};
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
DrawText(hdc, _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter \u6216 Space \u786e\u8ba4\uff0cEsc \u9000\u51fa"), -1, &hintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
DrawMusicButton();
|
|
SelectObject(hdc, oldFont);
|
|
DeleteObject(titleFont);
|
|
DeleteObject(sectionFont);
|
|
DeleteObject(bodyFont);
|
|
DeleteObject(smallFont);
|
|
return;
|
|
}
|
|
|
|
if (currentScreen == SCREEN_RULES)
|
|
{
|
|
RECT rulesCard =
|
|
{
|
|
SX(76),
|
|
SY(54),
|
|
SX(WINDOW_CLIENT_WIDTH - 76),
|
|
SY(WINDOW_CLIENT_HEIGHT - 54)
|
|
};
|
|
|
|
HPEN rulesPen = CreatePen(PS_SOLID, 1, frameColor);
|
|
HBRUSH rulesBrush = CreateSolidBrush(cardColor);
|
|
HFONT oldFont = (HFONT)SelectObject(hdc, titleFont);
|
|
oldPen = (HPEN)SelectObject(hdc, rulesPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, rulesBrush);
|
|
RoundRect(hdc, rulesCard.left, rulesCard.top, rulesCard.right, rulesCard.bottom, SS(34), SS(34));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(rulesBrush);
|
|
DeleteObject(rulesPen);
|
|
|
|
SetTextColor(hdc, titleColor);
|
|
RECT rulesTitleRect =
|
|
{
|
|
rulesCard.left + SS(36),
|
|
rulesCard.top + SS(26),
|
|
rulesCard.right - SS(36),
|
|
rulesCard.top + SS(78)
|
|
};
|
|
const TCHAR* helpTitle = _T("\u5e2e\u52a9");
|
|
if (helpState.currentPage == 1)
|
|
{
|
|
helpTitle = _T("\u6e38\u620f\u4ecb\u7ecd");
|
|
}
|
|
else if (helpState.currentPage == 2)
|
|
{
|
|
helpTitle = _T("\u64cd\u4f5c\u8bf4\u660e");
|
|
}
|
|
else if (helpState.currentPage == 3)
|
|
{
|
|
helpTitle = _T("\u5f3a\u5316\u56fe\u9274");
|
|
}
|
|
DrawText(hdc, helpTitle, -1, &rulesTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
HPEN rulesAccentPen = CreatePen(PS_SOLID, SS(3), accentColor);
|
|
oldPen = (HPEN)SelectObject(hdc, rulesAccentPen);
|
|
MoveToEx(hdc, rulesCard.left + SS(38), rulesCard.top + SS(92), nullptr);
|
|
LineTo(hdc, rulesCard.left + SS(186), rulesCard.top + SS(92));
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(rulesAccentPen);
|
|
|
|
RECT contentRect =
|
|
{
|
|
rulesCard.left + SS(36),
|
|
rulesCard.top + SS(126),
|
|
rulesCard.right - SS(36),
|
|
rulesCard.bottom - SS(86)
|
|
};
|
|
|
|
if (helpState.currentPage == 0)
|
|
{
|
|
const TCHAR* optionTitles[3] =
|
|
{
|
|
_T("\u6e38\u620f\u4ecb\u7ecd"),
|
|
_T("\u64cd\u4f5c\u8bf4\u660e"),
|
|
_T("\u5f3a\u5316\u56fe\u9274")
|
|
};
|
|
const TCHAR* optionDetails[3] =
|
|
{
|
|
_T("\u7ecf\u5178\u6a21\u5f0f\u3001Rogue \u6a21\u5f0f\u548c\u590d\u6d3b\u89c4\u5219\u6982\u89c8\u3002"),
|
|
_T("\u79fb\u52a8\u3001\u65cb\u8f6c\u3001\u786c\u964d\u3001Hold \u4e0e\u6280\u80fd\u5feb\u6377\u952e\u3002"),
|
|
_T("\u67e5\u770b Rogue \u6a21\u5f0f\u5168\u90e8\u5f3a\u5316\u7684\u7b80\u8981\u6548\u679c\u3002")
|
|
};
|
|
|
|
int optionHeight = SS(100);
|
|
int optionGap = SS(22);
|
|
int optionTop = contentRect.top + SS(18);
|
|
for (int i = 0; i < helpState.optionCount; ++i)
|
|
{
|
|
RECT optionRect =
|
|
{
|
|
contentRect.left,
|
|
optionTop + i * (optionHeight + optionGap),
|
|
contentRect.right,
|
|
optionTop + i * (optionHeight + optionGap) + optionHeight
|
|
};
|
|
bool selected = (i == helpState.selectedIndex);
|
|
COLORREF optionFill = selected ? RGB(255, 245, 249) : RGB(255, 252, 250);
|
|
COLORREF optionFrame = selected ? accentColor : frameColor;
|
|
HPEN optionPen = CreatePen(PS_SOLID, selected ? SS(2) : SS(1), optionFrame);
|
|
HBRUSH optionBrush = CreateSolidBrush(optionFill);
|
|
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);
|
|
|
|
SetTextColor(hdc, selected ? titleColor : textColor);
|
|
SelectObject(hdc, sectionFont);
|
|
RECT optionTitleRect =
|
|
{
|
|
optionRect.left + SS(28),
|
|
optionRect.top + SS(16),
|
|
optionRect.right - SS(28),
|
|
optionRect.top + SS(48)
|
|
};
|
|
DrawText(hdc, optionTitles[i], -1, &optionTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SetTextColor(hdc, RGB(112, 91, 104));
|
|
SelectObject(hdc, bodyFont);
|
|
RECT optionDetailRect =
|
|
{
|
|
optionRect.left + SS(28),
|
|
optionRect.top + SS(52),
|
|
optionRect.right - SS(28),
|
|
optionRect.bottom - SS(14)
|
|
};
|
|
DrawText(hdc, optionDetails[i], -1, &optionDetailRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetTextColor(hdc, textColor);
|
|
SelectObject(hdc, bodyFont);
|
|
const TCHAR* pageText = _T("");
|
|
UINT pageFlags = DT_LEFT | DT_TOP | DT_WORDBREAK;
|
|
if (helpState.currentPage == 1)
|
|
{
|
|
pageText =
|
|
_T("经典模式:只考验堆叠、消行和生存。\r\n\r\n")
|
|
_T("Rogue:消行得分和 EXP,升级后选择强化。\r\n\r\n")
|
|
_T("战斗越久危险越高,底部封锁区会压缩空间。\r\n\r\n")
|
|
_T("死亡后可以按 V 看视频复活一次,经典模式和 Rogue 模式都支持。");
|
|
}
|
|
else if (helpState.currentPage == 2)
|
|
{
|
|
pageText =
|
|
_T("\u2190 / A\uff1a\u5411\u5de6\u79fb\u52a8\r\n")
|
|
_T("\u2192 / D\uff1a\u5411\u53f3\u79fb\u52a8\r\n")
|
|
_T("\u2191 / W\uff1a\u65cb\u8f6c\u65b9\u5757\r\n")
|
|
_T("\u2193 / S\uff1a\u8f6f\u964d\r\n")
|
|
_T("Space\uff1a\u786c\u964d\r\n")
|
|
_T("C / Shift\uff1a备用仓\uff08获得后\uff09\r\n")
|
|
_T("Z\uff1a黑洞奇点\uff08获得后\uff09\r\n")
|
|
_T("X\uff1a清屏炸弹\uff08获得后\uff09\r\n")
|
|
_T("V\uff1a空中换形\uff08获得后\uff09\r\n")
|
|
_T("P\uff1a\u6682\u505c / \u7ee7\u7eed\r\n")
|
|
_T("R\uff1a\u91cd\u5f00\u5f53\u524d\u5bf9\u5c40\r\n")
|
|
_T("M\uff1a\u8fd4\u56de\u4e3b\u83dc\u5355\r\n")
|
|
_T("死亡后 V:看视频复活一次");
|
|
}
|
|
else if (helpState.currentPage == 3)
|
|
{
|
|
const TCHAR* categoryNames[8] =
|
|
{
|
|
_T("基础"),
|
|
_T("保命 / 操作"),
|
|
_T("清场"),
|
|
_T("特殊方块"),
|
|
_T("进阶"),
|
|
_T("狂热 / 风险"),
|
|
_T("升级系"),
|
|
_T("构筑")
|
|
};
|
|
const TCHAR* categoryTexts[8] =
|
|
{
|
|
_T("赏金纹章:得分+20%\r\n成长印记:EXP+25%\r\n缓坠羽翼:下落变慢\r\n连击律动:连续消行加分;先见之眼:预览+1"),
|
|
_T("最后一搏:濒死清底3行\r\n备用仓:解锁 Hold\r\n完美旋转:卡墙修正\r\n时间缓流:高堆叠减速;空中换形:V 变 I 块"),
|
|
_T("卸压清场:清最高行\r\n底线清道夫:更快充能清底\r\n清屏炸弹:X 清底5行,16行充能\r\n黑洞奇点:Z 吞噬最多方块,获得2次"),
|
|
_T("爆破核心:更频繁爆破块清 3x3\r\n棱镜激光:更高概率清整列\r\n十字方块:更高概率清行列\r\n彩虹方块:更高概率补齐缺口;方块改造:提高 I 块概率"),
|
|
_T("连锁火花:消行追加破坏\r\n连环炸弹:爆破扩大 5x5\r\n雷霆四消:三消/四消额外轰击\r\n雷霆棱镜:三消/四消额外激光"),
|
|
_T("狂热节拍:12行进狂热\r\n怒火连段:连击加倍率\r\n无尽狂热:延长狂热\r\n高压悬赏 / 豪赌四消 / 极限玩家:高风险高收益"),
|
|
_T("双重抉择:升级多选1个\r\n命运轮盘:6选2但带诅咒\r\n升级冲击波 / 进化冲击:升级清底\r\n成长核心:永久得分 / EXP +15%"),
|
|
_T("操控大师:Hold 后减速并预览+1\r\n方块风暴:接下来5个全 I 块\r\n稳定结构:更高概率落地补洞\r\n虚空核心:黑洞和彩虹联动;赌徒契约:强化可能翻倍或落空")
|
|
};
|
|
|
|
int columnGap = SS(18);
|
|
int rowGap = SS(14);
|
|
int columnWidth = (contentRect.right - contentRect.left - columnGap) / 2;
|
|
int rowHeight = (contentRect.bottom - contentRect.top - rowGap * 3) / 4;
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
int column = i % 2;
|
|
int row = i / 2;
|
|
RECT categoryRect =
|
|
{
|
|
contentRect.left + column * (columnWidth + columnGap),
|
|
contentRect.top + row * (rowHeight + rowGap),
|
|
contentRect.left + column * (columnWidth + columnGap) + columnWidth,
|
|
contentRect.top + row * (rowHeight + rowGap) + rowHeight
|
|
};
|
|
|
|
HPEN categoryPen = CreatePen(PS_SOLID, 1, RGB(232, 202, 215));
|
|
HBRUSH categoryBrush = CreateSolidBrush(RGB(255, 252, 250));
|
|
oldPen = (HPEN)SelectObject(hdc, categoryPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, categoryBrush);
|
|
RoundRect(hdc, categoryRect.left, categoryRect.top, categoryRect.right, categoryRect.bottom, SS(16), SS(16));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(categoryBrush);
|
|
DeleteObject(categoryPen);
|
|
|
|
SetTextColor(hdc, titleColor);
|
|
SelectObject(hdc, bodyFont);
|
|
RECT categoryTitleRect =
|
|
{
|
|
categoryRect.left + SS(16),
|
|
categoryRect.top + SS(10),
|
|
categoryRect.right - SS(16),
|
|
categoryRect.top + SS(34)
|
|
};
|
|
DrawText(hdc, categoryNames[i], -1, &categoryTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SetTextColor(hdc, RGB(86, 66, 80));
|
|
SelectObject(hdc, smallFont);
|
|
RECT categoryBodyRect =
|
|
{
|
|
categoryRect.left + SS(16),
|
|
categoryRect.top + SS(40),
|
|
categoryRect.right - SS(16),
|
|
categoryRect.bottom - SS(10)
|
|
};
|
|
DrawText(hdc, categoryTexts[i], -1, &categoryBodyRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
}
|
|
}
|
|
if (helpState.currentPage != 3)
|
|
{
|
|
DrawText(hdc, pageText, -1, &contentRect, pageFlags);
|
|
}
|
|
}
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT backHintRect =
|
|
{
|
|
rulesCard.left + SS(36),
|
|
rulesCard.bottom - SS(58),
|
|
rulesCard.right - SS(36),
|
|
rulesCard.bottom - SS(24)
|
|
};
|
|
const TCHAR* helpHint = helpState.currentPage == 0
|
|
? _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter / Space \u786e\u8ba4\uff0cEsc / M \u8fd4\u56de\u4e3b\u83dc\u5355")
|
|
: _T("Esc / Backspace / M \u8fd4\u56de\u5e2e\u52a9");
|
|
DrawText(hdc, helpHint, -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
DrawMusicButton();
|
|
SelectObject(hdc, oldFont);
|
|
DeleteObject(titleFont);
|
|
DeleteObject(sectionFont);
|
|
DeleteObject(bodyFont);
|
|
DeleteObject(smallFont);
|
|
return;
|
|
}
|
|
|
|
DrawPanelCardAlpha(
|
|
{ gameRect.left - SS(10), gameRect.top - SS(10), gameRect.right + SS(10), gameRect.bottom + SS(10) },
|
|
cardColor,
|
|
frameColor,
|
|
28,
|
|
shellAlpha);
|
|
DrawPanelCardAlpha(leftPanelRect, cardColor, frameColor, 30, shellAlpha);
|
|
DrawPanelCardAlpha(rightPanelRect, cardColor, frameColor, 30, shellAlpha);
|
|
|
|
RECT innerRect =
|
|
{
|
|
gameRect.left + SS(6),
|
|
gameRect.top + SS(6),
|
|
gameRect.right - SS(6),
|
|
gameRect.bottom - SS(6)
|
|
};
|
|
|
|
{
|
|
Graphics boardGraphics(hdc);
|
|
SolidBrush boardBrush(Color(164, GetRValue(boardColor), GetGValue(boardColor), GetBValue(boardColor)));
|
|
SolidBrush innerBrush(Color(176, GetRValue(boardInnerColor), GetGValue(boardInnerColor), GetBValue(boardInnerColor)));
|
|
boardGraphics.FillRectangle(
|
|
&boardBrush,
|
|
static_cast<INT>(gameRect.left),
|
|
static_cast<INT>(gameRect.top),
|
|
static_cast<INT>(gameRect.right - gameRect.left),
|
|
static_cast<INT>(gameRect.bottom - gameRect.top));
|
|
boardGraphics.FillRectangle(
|
|
&innerBrush,
|
|
static_cast<INT>(innerRect.left),
|
|
static_cast<INT>(innerRect.top),
|
|
static_cast<INT>(innerRect.right - innerRect.left),
|
|
static_cast<INT>(innerRect.bottom - innerRect.top));
|
|
}
|
|
|
|
HPEN borderPen = CreatePen(PS_SOLID, SS(2), RGB(132, 108, 146));
|
|
oldPen = (HPEN)SelectObject(hdc, borderPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
RoundRect(hdc, gameRect.left, gameRect.top, gameRect.right, gameRect.bottom, SS(18), SS(18));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(borderPen);
|
|
|
|
HPEN gridPen = CreatePen(PS_SOLID, 1, lineColor);
|
|
oldPen = (HPEN)SelectObject(hdc, gridPen);
|
|
|
|
for (int i = 1; i < nGameWidth; i++)
|
|
{
|
|
int x = gameRect.left + i * grid;
|
|
MoveToEx(hdc, x, gameRect.top, nullptr);
|
|
LineTo(hdc, x, gameRect.bottom);
|
|
}
|
|
|
|
for (int i = 1; i < nGameHeight; i++)
|
|
{
|
|
int y = gameRect.top + i * grid;
|
|
MoveToEx(hdc, gameRect.left, y, nullptr);
|
|
LineTo(hdc, gameRect.right, y);
|
|
}
|
|
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(gridPen);
|
|
|
|
int lockedRows = GetRogueLockedRows();
|
|
if (lockedRows > 0)
|
|
{
|
|
RECT lockedRect =
|
|
{
|
|
gameRect.left,
|
|
gameRect.top + (nGameHeight - lockedRows) * grid,
|
|
gameRect.right,
|
|
gameRect.bottom
|
|
};
|
|
|
|
Graphics lockedGraphics(hdc);
|
|
SolidBrush lockedBrush(Color(150, 58, 48, 68));
|
|
Pen lockedPen(Color(210, 232, 170, 194), 1.0f);
|
|
lockedGraphics.FillRectangle(
|
|
&lockedBrush,
|
|
static_cast<INT>(lockedRect.left),
|
|
static_cast<INT>(lockedRect.top),
|
|
static_cast<INT>(lockedRect.right - lockedRect.left),
|
|
static_cast<INT>(lockedRect.bottom - lockedRect.top));
|
|
lockedGraphics.DrawRectangle(
|
|
&lockedPen,
|
|
static_cast<INT>(lockedRect.left),
|
|
static_cast<INT>(lockedRect.top),
|
|
static_cast<INT>(lockedRect.right - lockedRect.left),
|
|
static_cast<INT>(lockedRect.bottom - lockedRect.top));
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(238, 204, 216));
|
|
RECT lockedTextRect =
|
|
{
|
|
lockedRect.left + SS(12),
|
|
lockedRect.top + SS(8),
|
|
lockedRect.right - SS(12),
|
|
lockedRect.bottom - SS(8)
|
|
};
|
|
DrawText(hdc, _T("封锁区"), -1, &lockedTextRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
for (int i = 0; i < nGameHeight; i++)
|
|
{
|
|
for (int j = 0; j < nGameWidth; j++)
|
|
{
|
|
if (workRegion[i][j] != 0)
|
|
{
|
|
int cellValue = workRegion[i][j];
|
|
bool isRainbowCell = (cellValue == 8);
|
|
int colorIndex = isRainbowCell ? 0 : (cellValue - 1);
|
|
RECT brickRect =
|
|
{
|
|
gameRect.left + j * grid + SS(2),
|
|
gameRect.top + i * grid + SS(2),
|
|
gameRect.left + (j + 1) * grid - SS(2),
|
|
gameRect.top + (i + 1) * grid - SS(2)
|
|
};
|
|
|
|
COLORREF fillColor = isRainbowCell ? RGB(255, 214, 120) : BrickColor[colorIndex];
|
|
COLORREF borderColor = isRainbowCell ? RGB(255, 248, 191) : RGB(255, 248, 250);
|
|
HBRUSH brickBrush = CreateSolidBrush(fillColor);
|
|
HPEN brickPen = CreatePen(PS_SOLID, isRainbowCell ? SS(2) : 1, borderColor);
|
|
oldPen = (HPEN)SelectObject(hdc, brickPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
|
|
RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(10), SS(10));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(brickBrush);
|
|
DeleteObject(brickPen);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (targetFlag && !gameOverFlag)
|
|
{
|
|
HPEN targetPen = CreatePen(PS_DOT, SS(2), RGB(255, 240, 245));
|
|
oldPen = (HPEN)SelectObject(hdc, targetPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (bricks[type][state][i][j] != 0)
|
|
{
|
|
int drawY = target.y + i;
|
|
int drawX = target.x + j;
|
|
|
|
if (drawY >= 0 && drawY < nGameHeight && drawX >= 0 && drawX < nGameWidth)
|
|
{
|
|
RoundRect(
|
|
hdc,
|
|
gameRect.left + drawX * grid + SS(5),
|
|
gameRect.top + drawY * grid + SS(5),
|
|
gameRect.left + (drawX + 1) * grid - SS(5),
|
|
gameRect.top + (drawY + 1) * grid - SS(5),
|
|
SS(8), SS(8));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(targetPen);
|
|
}
|
|
|
|
if (!gameOverFlag)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (bricks[type][state][i][j] != 0)
|
|
{
|
|
int drawY = point.y + i;
|
|
int drawX = point.x + j;
|
|
|
|
if (drawY >= 0 && drawY < nGameHeight && drawX >= 0 && drawX < nGameWidth)
|
|
{
|
|
RECT brickRect =
|
|
{
|
|
gameRect.left + drawX * grid + SS(2),
|
|
gameRect.top + drawY * grid + SS(2),
|
|
gameRect.left + (drawX + 1) * grid - SS(2),
|
|
gameRect.top + (drawY + 1) * grid - SS(2)
|
|
};
|
|
|
|
HBRUSH brickBrush = CreateSolidBrush(BrickColor[type]);
|
|
COLORREF activeOutlineColor = RGB(255, 250, 252);
|
|
int activeOutlineWidth = 1;
|
|
if (currentPieceIsExplosive)
|
|
{
|
|
activeOutlineColor = RGB(255, 214, 82);
|
|
activeOutlineWidth = SS(3);
|
|
}
|
|
else if (currentPieceIsLaser)
|
|
{
|
|
activeOutlineColor = RGB(120, 232, 255);
|
|
activeOutlineWidth = SS(3);
|
|
}
|
|
else if (currentPieceIsCross)
|
|
{
|
|
activeOutlineColor = RGB(196, 255, 132);
|
|
activeOutlineWidth = SS(3);
|
|
}
|
|
else if (currentPieceIsRainbow)
|
|
{
|
|
activeOutlineColor = RGB(255, 226, 126);
|
|
activeOutlineWidth = SS(3);
|
|
}
|
|
HPEN brickPen = CreatePen(PS_SOLID, activeOutlineWidth, activeOutlineColor);
|
|
oldPen = (HPEN)SelectObject(hdc, brickPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
|
|
RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(12), SS(12));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(brickBrush);
|
|
DeleteObject(brickPen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clearEffectState.ticks > 0 && clearEffectState.totalTicks > 0)
|
|
{
|
|
int elapsed = clearEffectState.totalTicks - clearEffectState.ticks;
|
|
int alpha = 42 + clearEffectState.ticks * 150 / clearEffectState.totalTicks;
|
|
int inset = SS(elapsed * 2);
|
|
Graphics flashGraphics(hdc);
|
|
|
|
for (int i = 0; i < clearEffectState.rowCount; i++)
|
|
{
|
|
int row = clearEffectState.rows[i];
|
|
if (row < 0 || row >= nGameHeight)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int top = gameRect.top + row * grid + inset;
|
|
int height = grid - inset * 2;
|
|
if (height < SS(4))
|
|
{
|
|
height = SS(4);
|
|
}
|
|
|
|
SolidBrush flashBrush(Color(alpha, 255, 248, 174));
|
|
flashGraphics.FillRectangle(
|
|
&flashBrush,
|
|
static_cast<INT>(gameRect.left + SS(2)),
|
|
static_cast<INT>(top),
|
|
static_cast<INT>(gameRect.right - gameRect.left - SS(4)),
|
|
static_cast<INT>(height));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 96; i++)
|
|
{
|
|
if (particleEffects[i].ticks <= 0 || particleEffects[i].totalTicks <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int elapsed = particleEffects[i].totalTicks - particleEffects[i].ticks;
|
|
int particleX = gameRect.left + particleEffects[i].boardX * grid / 100 + SS(particleEffects[i].velocityX * elapsed);
|
|
int particleY = gameRect.top + particleEffects[i].boardY * grid / 100 + SS(particleEffects[i].velocityY * elapsed + elapsed * elapsed / 4);
|
|
int particleSize = SS(particleEffects[i].size * particleEffects[i].ticks / particleEffects[i].totalTicks);
|
|
if (particleSize < SS(2))
|
|
{
|
|
particleSize = SS(2);
|
|
}
|
|
|
|
RECT particleRect =
|
|
{
|
|
particleX - particleSize,
|
|
particleY - particleSize,
|
|
particleX + particleSize,
|
|
particleY + particleSize
|
|
};
|
|
|
|
HBRUSH particleBrush = CreateSolidBrush(particleEffects[i].color);
|
|
FillRect(hdc, &particleRect, particleBrush);
|
|
DeleteObject(particleBrush);
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (floatingTextEffects[i].ticks <= 0 || floatingTextEffects[i].totalTicks <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int elapsed = floatingTextEffects[i].totalTicks - floatingTextEffects[i].ticks;
|
|
int textX = gameRect.left + floatingTextEffects[i].boardX * grid / 100;
|
|
int textY = gameRect.top + floatingTextEffects[i].boardY * grid / 100 - SS(elapsed * 4);
|
|
|
|
HFONT oldFloatFont = (HFONT)SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, floatingTextEffects[i].color);
|
|
RECT floatRect =
|
|
{
|
|
textX - SS(160),
|
|
textY - SS(24),
|
|
textX + SS(160),
|
|
textY + SS(28)
|
|
};
|
|
DrawText(hdc, floatingTextEffects[i].text, -1, &floatRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
SelectObject(hdc, oldFloatFont);
|
|
}
|
|
|
|
HFONT oldFont = (HFONT)SelectObject(hdc, titleFont);
|
|
DrawPanelHeader(leftPanelRect, _T("战局信息"), 120);
|
|
DrawPanelHeader(rightPanelRect, _T("预览与战术"), 148);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
|
|
RECT overviewRect =
|
|
{
|
|
leftPanelRect.left + SS(20),
|
|
leftPanelRect.top + SS(98),
|
|
leftPanelRect.right - SS(20),
|
|
leftPanelRect.top + SS(252)
|
|
};
|
|
DrawPanelCardAlpha(overviewRect, RGB(255, 247, 250), RGB(233, 191, 208), 24, panelAlpha);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
RECT overviewTitleRect =
|
|
{
|
|
overviewRect.left + SS(18),
|
|
overviewRect.top + SS(12),
|
|
overviewRect.right - SS(18),
|
|
overviewRect.top + SS(42)
|
|
};
|
|
DrawText(hdc, _T("战场状态"), -1, &overviewTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
TCHAR overviewText[160];
|
|
int totalLines = (currentMode == MODE_CLASSIC) ? classicStats.totalLinesCleared : rogueStats.totalLinesCleared;
|
|
if (currentMode == MODE_ROGUE)
|
|
{
|
|
_stprintf_s(
|
|
overviewText,
|
|
_T("得分 %d\r\n模式 Rogue\r\n消行 %d\r\n危险 Lv.%d 封锁 %d"),
|
|
tScore,
|
|
totalLines,
|
|
rogueStats.difficultyLevel,
|
|
GetRogueLockedRows());
|
|
}
|
|
else
|
|
{
|
|
_stprintf_s(
|
|
overviewText,
|
|
_T("得分 %d\r\n模式 经典\r\n消行 %d"),
|
|
tScore,
|
|
totalLines);
|
|
}
|
|
RECT overviewBodyRect =
|
|
{
|
|
overviewRect.left + SS(22),
|
|
overviewRect.top + SS(62),
|
|
overviewRect.right - SS(22),
|
|
overviewRect.bottom - SS(22)
|
|
};
|
|
DrawText(hdc, overviewText, -1, &overviewBodyRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
|
|
if (currentMode == MODE_ROGUE)
|
|
{
|
|
RECT progressRect =
|
|
{
|
|
leftPanelRect.left + SS(20),
|
|
leftPanelRect.top + SS(270),
|
|
leftPanelRect.right - SS(20),
|
|
leftPanelRect.top + SS(488)
|
|
};
|
|
DrawPanelCardAlpha(progressRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
RECT progressTitleRect =
|
|
{
|
|
progressRect.left + SS(18),
|
|
progressRect.top + SS(12),
|
|
progressRect.right - SS(18),
|
|
progressRect.top + SS(42)
|
|
};
|
|
DrawText(hdc, _T("成长进度"), -1, &progressTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
TCHAR progressText[96];
|
|
_stprintf_s(progressText, _T("等级 %d\r\nEXP %d / %d"), rogueStats.level, rogueStats.exp, rogueStats.requiredExp);
|
|
RECT progressTextRect =
|
|
{
|
|
progressRect.left + SS(22),
|
|
progressRect.top + SS(56),
|
|
progressRect.right - SS(22),
|
|
progressRect.top + SS(120)
|
|
};
|
|
DrawText(hdc, progressText, -1, &progressTextRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
|
|
RECT expBarRect =
|
|
{
|
|
progressRect.left + SS(22),
|
|
progressRect.top + SS(122),
|
|
progressRect.right - SS(22),
|
|
progressRect.top + SS(148)
|
|
};
|
|
HBRUSH expTrackBrush = CreateSolidBrush(RGB(240, 220, 229));
|
|
FillRect(hdc, &expBarRect, expTrackBrush);
|
|
DeleteObject(expTrackBrush);
|
|
|
|
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;
|
|
}
|
|
if (expFillRect.right > expBarRect.right)
|
|
{
|
|
expFillRect.right = expBarRect.right;
|
|
}
|
|
HBRUSH expFillBrush = CreateSolidBrush(accentColor);
|
|
FillRect(hdc, &expFillRect, expFillBrush);
|
|
DeleteObject(expFillBrush);
|
|
|
|
const TCHAR* statLabels[2] =
|
|
{
|
|
_T("\u5f97\u5206\u500d\u7387"),
|
|
_T("EXP \u500d\u7387")
|
|
};
|
|
TCHAR statValues[2][32];
|
|
_stprintf_s(statValues[0], _T("%d%%"), rogueStats.scoreMultiplierPercent);
|
|
_stprintf_s(statValues[1], _T("%d%%"), rogueStats.expMultiplierPercent);
|
|
|
|
int statGap = SS(8);
|
|
int statWidth = (progressRect.right - progressRect.left - SS(44) - statGap) / 2;
|
|
for (int statIndex = 0; statIndex < 2; statIndex++)
|
|
{
|
|
RECT statRect =
|
|
{
|
|
progressRect.left + SS(22) + statIndex * (statWidth + statGap),
|
|
progressRect.top + SS(154),
|
|
progressRect.left + SS(22) + statIndex * (statWidth + statGap) + statWidth,
|
|
progressRect.top + SS(204)
|
|
};
|
|
DrawPanelCardAlpha(statRect, RGB(255, 239, 245), RGB(232, 184, 202), 16, panelNestedAlpha);
|
|
|
|
RECT statLabelRect =
|
|
{
|
|
statRect.left + SS(8),
|
|
statRect.top + SS(4),
|
|
statRect.right - SS(8),
|
|
statRect.top + SS(22)
|
|
};
|
|
RECT statValueRect =
|
|
{
|
|
statRect.left + SS(8),
|
|
statRect.top + SS(21),
|
|
statRect.right - SS(8),
|
|
statRect.bottom - SS(2)
|
|
};
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(132, 102, 118));
|
|
DrawText(hdc, statLabels[statIndex], -1, &statLabelRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, titleColor);
|
|
DrawText(hdc, statValues[statIndex], -1, &statValueRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
RECT upgradeListRect =
|
|
{
|
|
leftPanelRect.left + SS(20),
|
|
leftPanelRect.top + SS(510),
|
|
leftPanelRect.right - SS(20),
|
|
leftPanelRect.bottom - SS(20)
|
|
};
|
|
DrawPanelCardAlpha(upgradeListRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
TextOut(hdc, upgradeListRect.left + SS(18), upgradeListRect.top + SS(16), _T("已掌握强化"), lstrlen(_T("已掌握强化")));
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT upgradeBodyRect =
|
|
{
|
|
upgradeListRect.left + SS(22),
|
|
upgradeListRect.top + SS(56),
|
|
upgradeListRect.right - SS(22),
|
|
upgradeListRect.bottom - SS(20)
|
|
};
|
|
|
|
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 (rogueStats.pressureReliefLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u51cf\u538b Lv.%d\r\n"), rogueStats.pressureReliefLevel);
|
|
}
|
|
if (rogueStats.sweeperLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6e05\u626b\u8005 Lv.%d\r\n"), rogueStats.sweeperLevel);
|
|
}
|
|
if (rogueStats.explosiveLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7206\u7834\u65b9\u5757 Lv.%d\r\n"), rogueStats.explosiveLevel);
|
|
}
|
|
if (rogueStats.chainBlastLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8fde\u9501\u7206\u7834 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.chainBombLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8fde\u73af\u70b8\u5f39 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.laserLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6fc0\u5149\u65b9\u5757 Lv.%d\r\n"), rogueStats.laserLevel);
|
|
}
|
|
if (rogueStats.thunderTetrisLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u96f7\u9706\u56db\u6d88 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.thunderLaserLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u96f7\u9706\u6fc0\u5149 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.feverLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u72c2\u70ed\u6a21\u5f0f Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.rageStackLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u66b4\u8d70\u5806\u53e0 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.infiniteFeverLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u65e0\u9650\u72c2\u70ed Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.screenBombLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6e05\u5c4f\u70b8\u5f39 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.terminalClearLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7ec8\u672b\u6e05\u573a Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.perfectRotateLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5b8c\u7f8e\u65cb\u8f6c Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.timeDilationLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u65f6\u95f4\u7f13\u6d41 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.highPressureLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u9ad8\u538b\u5956\u52b1 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.tetrisGambleLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8d4c\u547d\u56db\u6d88 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.extremePlayerLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6781\u9650\u73a9\u5bb6 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.upgradeShockwaveLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5347\u7ea7\u51b2\u51fb\u6ce2 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.evolutionImpactLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8fdb\u5316\u51b2\u51fb Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.controlMasterLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u64cd\u63a7\u5927\u5e08 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.blockStormLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u65b9\u5757\u98ce\u66b4 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.crossPieceLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5341\u5b57\u65b9\u5757 Lv.%d\r\n"), rogueStats.crossPieceLevel);
|
|
}
|
|
if (rogueStats.blackHoleLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u9ed1\u6d1e Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.reshapeLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a7a\u4e2d\u6362\u5f62 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.rainbowPieceLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5f69\u8679\u65b9\u5757 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.voidCoreLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u865a\u7a7a\u6838\u5fc3 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.stableStructureLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a33\u5b9a\u7ed3\u6784 Lv.%d\r\n"), rogueStats.stableStructureLevel);
|
|
}
|
|
if (rogueStats.doubleGrowthLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6210\u957f\u6838\u5fc3 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.pieceTuningLevels[0] > 0)
|
|
{
|
|
_stprintf_s(
|
|
upgradeSummary + lstrlen(upgradeSummary),
|
|
512 - lstrlen(upgradeSummary),
|
|
_T("I \u65b9\u5757\u6539\u9020 Lv.%d\r\n"),
|
|
rogueStats.pieceTuningLevels[0]);
|
|
}
|
|
if (rogueStats.gamblerLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8d4c\u5f92 Lv.%d\r\n"), rogueStats.gamblerLevel);
|
|
}
|
|
if (rogueStats.dualChoiceLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u53cc\u91cd\u9009\u62e9 Lv.1\r\n"));
|
|
}
|
|
if (rogueStats.destinyWheelLevel > 0)
|
|
{
|
|
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u547d\u8fd0\u8f6e\u76d8 Lv.1\r\n"));
|
|
}
|
|
if (lstrlen(upgradeSummary) == 0)
|
|
{
|
|
_stprintf_s(upgradeSummary, _T("尚未掌握强化。\r\n下一次升级将开启构筑。"));
|
|
}
|
|
|
|
DrawText(hdc, upgradeSummary, -1, &upgradeBodyRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
}
|
|
else
|
|
{
|
|
RECT classicInfoRect =
|
|
{
|
|
leftPanelRect.left + SS(20),
|
|
leftPanelRect.top + SS(270),
|
|
leftPanelRect.right - SS(20),
|
|
leftPanelRect.top + SS(458)
|
|
};
|
|
DrawPanelCardAlpha(classicInfoRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT classicBodyRect =
|
|
{
|
|
classicInfoRect.left + SS(22),
|
|
classicInfoRect.top + SS(24),
|
|
classicInfoRect.right - SS(22),
|
|
classicInfoRect.bottom - SS(24)
|
|
};
|
|
DrawText(hdc, _T("经典模式:没有成长、EXP 和强化,只保留纯粹的消行挑战。\r\n\r\n在有限空间中保持阵型,尽可能活得更久。"), -1, &classicBodyRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
}
|
|
RECT holdNextRect =
|
|
{
|
|
rightPanelRect.left + SS(20),
|
|
rightPanelRect.top + SS(98),
|
|
rightPanelRect.right - SS(20),
|
|
rightPanelRect.top + SS(326)
|
|
};
|
|
DrawPanelCardAlpha(holdNextRect, RGB(255, 247, 250), RGB(233, 191, 208), 24, panelAlpha);
|
|
|
|
RECT holdCard =
|
|
{
|
|
holdNextRect.left + SS(88),
|
|
holdNextRect.top + SS(24),
|
|
holdNextRect.left + SS(150),
|
|
holdNextRect.top + SS(86)
|
|
};
|
|
|
|
RECT nextSectionRect =
|
|
{
|
|
holdNextRect.left + SS(18),
|
|
holdNextRect.top + SS(146),
|
|
holdNextRect.right - SS(18),
|
|
holdNextRect.bottom - SS(22)
|
|
};
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
RECT holdTitleRect =
|
|
{
|
|
holdNextRect.left + SS(18),
|
|
holdNextRect.top + SS(34),
|
|
holdNextRect.left + SS(80),
|
|
holdNextRect.top + SS(70)
|
|
};
|
|
DrawText(hdc, _T("Hold"), -1, &holdTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
RECT nextTitleRect =
|
|
{
|
|
nextSectionRect.left,
|
|
holdNextRect.top + SS(102),
|
|
holdNextRect.right - SS(18),
|
|
holdNextRect.top + SS(136)
|
|
};
|
|
DrawText(hdc, _T("\u4e0b\u4e00\u4e2a"), -1, &nextTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
DrawPanelCardAlpha(holdCard, RGB(255, 238, 244), RGB(233, 191, 208), 22, panelNestedAlpha);
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT holdHintRect =
|
|
{
|
|
holdCard.right + SS(14),
|
|
holdCard.top + SS(2),
|
|
holdNextRect.right - SS(18),
|
|
holdCard.bottom - SS(2)
|
|
};
|
|
DrawText(
|
|
hdc,
|
|
currentMode == MODE_ROGUE && rogueStats.holdUnlocked > 0
|
|
? (holdUsedThisTurn ? _T("已使用\r\n落地后恢复") : _T("C / Shift\r\n暂存一次"))
|
|
: _T("未开启\r\n需备用仓"),
|
|
-1,
|
|
&holdHintRect,
|
|
DT_LEFT | DT_VCENTER | DT_WORDBREAK);
|
|
|
|
if (currentMode == MODE_ROGUE)
|
|
{
|
|
if (rogueStats.holdUnlocked == 0)
|
|
{
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT holdLockedRect =
|
|
{
|
|
holdCard.left + SS(10),
|
|
holdCard.top + SS(10),
|
|
holdCard.right - SS(10),
|
|
holdCard.bottom - SS(10)
|
|
};
|
|
DrawText(hdc, _T("封存"), -1, &holdLockedRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
|
}
|
|
else if (holdType >= 0)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (bricks[holdType][0][i][j] != 0)
|
|
{
|
|
int holdAvailableWidth = holdCard.right - holdCard.left - SS(16);
|
|
int holdAvailableHeight = holdCard.bottom - holdCard.top - SS(16);
|
|
int holdMiniCell = holdAvailableWidth < holdAvailableHeight ? holdAvailableWidth / 4 : holdAvailableHeight / 4;
|
|
if (holdMiniCell < SS(7))
|
|
{
|
|
holdMiniCell = SS(7);
|
|
}
|
|
int holdOffsetX = holdCard.left + (holdCard.right - holdCard.left - holdMiniCell * 4) / 2;
|
|
int holdOffsetY = holdCard.top + (holdCard.bottom - holdCard.top - holdMiniCell * 4) / 2;
|
|
RECT brickRect =
|
|
{
|
|
holdOffsetX + j * holdMiniCell,
|
|
holdOffsetY + i * holdMiniCell,
|
|
holdOffsetX + (j + 1) * holdMiniCell - SS(1),
|
|
holdOffsetY + (i + 1) * holdMiniCell - SS(1)
|
|
};
|
|
|
|
HBRUSH brickBrush = CreateSolidBrush(BrickColor[holdType]);
|
|
HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 248, 250));
|
|
oldPen = (HPEN)SelectObject(hdc, brickPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
|
|
RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(8), SS(8));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(brickBrush);
|
|
DeleteObject(brickPen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT emptyHoldRect =
|
|
{
|
|
holdCard.left + SS(10),
|
|
holdCard.top + SS(10),
|
|
holdCard.right - SS(10),
|
|
holdCard.bottom - SS(10)
|
|
};
|
|
DrawText(hdc, _T("\u7a7a"), -1, &emptyHoldRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT classicHoldRect =
|
|
{
|
|
holdCard.left + SS(10),
|
|
holdCard.top + SS(10),
|
|
holdCard.right - SS(10),
|
|
holdCard.bottom - SS(10)
|
|
};
|
|
DrawText(hdc, _T("\u5173"), -1, &classicHoldRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
|
}
|
|
|
|
int previewCount = 1;
|
|
if (currentMode == MODE_ROGUE)
|
|
{
|
|
previewCount = rogueStats.previewCount;
|
|
if (previewCount < 1)
|
|
{
|
|
previewCount = 1;
|
|
}
|
|
if (previewCount > 3)
|
|
{
|
|
previewCount = 3;
|
|
}
|
|
}
|
|
|
|
for (int previewIndex = 0; previewIndex < previewCount; previewIndex++)
|
|
{
|
|
int nextCardGap = SS(8);
|
|
int nextCardWidth = (nextSectionRect.right - nextSectionRect.left - nextCardGap * 2) / 3;
|
|
RECT nextCard =
|
|
{
|
|
nextSectionRect.left + previewIndex * (nextCardWidth + nextCardGap),
|
|
nextSectionRect.top,
|
|
nextSectionRect.left + previewIndex * (nextCardWidth + nextCardGap) + nextCardWidth,
|
|
nextSectionRect.bottom
|
|
};
|
|
|
|
DrawPanelCardAlpha(nextCard, RGB(255, 247, 250), RGB(233, 191, 208), 18, panelStrongAlpha);
|
|
|
|
int previewType = nextTypes[previewIndex];
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (bricks[previewType][0][i][j] != 0)
|
|
{
|
|
int nextAvailableWidth = nextCard.right - nextCard.left - SS(14);
|
|
int nextAvailableHeight = nextCard.bottom - nextCard.top - SS(14);
|
|
int nextMiniCell = nextAvailableWidth < nextAvailableHeight ? nextAvailableWidth / 4 : nextAvailableHeight / 4;
|
|
if (nextMiniCell < SS(7))
|
|
{
|
|
nextMiniCell = SS(7);
|
|
}
|
|
int previewOffsetX = nextCard.left + (nextCard.right - nextCard.left - nextMiniCell * 4) / 2;
|
|
int previewOffsetY = nextCard.top + (nextCard.bottom - nextCard.top - nextMiniCell * 4) / 2;
|
|
RECT brickRect =
|
|
{
|
|
previewOffsetX + j * nextMiniCell,
|
|
previewOffsetY + i * nextMiniCell,
|
|
previewOffsetX + (j + 1) * nextMiniCell - SS(1),
|
|
previewOffsetY + (i + 1) * nextMiniCell - SS(1)
|
|
};
|
|
|
|
HBRUSH brickBrush = CreateSolidBrush(BrickColor[previewType]);
|
|
HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 248, 250));
|
|
oldPen = (HPEN)SelectObject(hdc, brickPen);
|
|
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
|
|
RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(8), SS(8));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(brickBrush);
|
|
DeleteObject(brickPen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RECT controlRect =
|
|
{
|
|
rightPanelRect.left + SS(20),
|
|
rightPanelRect.top + SS(346),
|
|
rightPanelRect.right - SS(20),
|
|
rightPanelRect.bottom - SS(20)
|
|
};
|
|
DrawPanelCardAlpha(controlRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
TextOut(hdc, controlRect.left + SS(18), controlRect.top + SS(16), _T("战斗日志"), lstrlen(_T("战斗日志")));
|
|
|
|
RECT feedbackPanelRect =
|
|
{
|
|
controlRect.left + SS(18),
|
|
controlRect.top + SS(56),
|
|
controlRect.right - SS(18),
|
|
controlRect.top + SS(172)
|
|
};
|
|
DrawPanelCardAlpha(feedbackPanelRect, RGB(255, 244, 248), RGB(232, 184, 202), 20, panelNestedAlpha);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, titleColor);
|
|
RECT feedbackTitleRect =
|
|
{
|
|
feedbackPanelRect.left + SS(16),
|
|
feedbackPanelRect.top + SS(14),
|
|
feedbackPanelRect.right - SS(16),
|
|
feedbackPanelRect.top + SS(42)
|
|
};
|
|
DrawText(
|
|
hdc,
|
|
feedbackState.visibleTicks > 0 ? feedbackState.title : _T("局势平稳"),
|
|
-1,
|
|
&feedbackTitleRect,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(116, 90, 104));
|
|
RECT feedbackBodyRect =
|
|
{
|
|
feedbackPanelRect.left + SS(16),
|
|
feedbackPanelRect.top + SS(46),
|
|
feedbackPanelRect.right - SS(16),
|
|
feedbackPanelRect.bottom - SS(14)
|
|
};
|
|
DrawText(
|
|
hdc,
|
|
feedbackState.visibleTicks > 0
|
|
? feedbackState.detail
|
|
: _T("连消、主动技能和特殊方块的战斗记录会出现在这里。"),
|
|
-1,
|
|
&feedbackBodyRect,
|
|
DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, textColor);
|
|
RECT tipsTitleRect =
|
|
{
|
|
controlRect.left + SS(22),
|
|
controlRect.top + SS(192),
|
|
controlRect.right - SS(22),
|
|
controlRect.top + SS(224)
|
|
};
|
|
DrawText(hdc, _T("操作指令"), -1, &tipsTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT controlBodyRect =
|
|
{
|
|
controlRect.left + SS(22),
|
|
controlRect.top + SS(232),
|
|
controlRect.right - SS(22),
|
|
controlRect.bottom - SS(22)
|
|
};
|
|
if (currentMode == MODE_ROGUE)
|
|
{
|
|
DrawText(
|
|
hdc,
|
|
_T("\u79fb\u52a8\uff1a\u2190/\u2192 \u6216 A/D\r\n")
|
|
_T("\u65cb\u8f6c/\u4e0b\u843d\uff1a\u2191/W\u3001\u2193/S\u3001Space\r\n")
|
|
_T("战局:P 暂停 R 重开 M 菜单\r\n")
|
|
_T("技能:C 备用仓 Z 黑洞 X 炸弹 V 换形"),
|
|
-1,
|
|
&controlBodyRect,
|
|
DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
}
|
|
else
|
|
{
|
|
DrawText(
|
|
hdc,
|
|
_T("\u79fb\u52a8\uff1a\u2190/\u2192 \u6216 A/D\r\n")
|
|
_T("\u65cb\u8f6c/\u4e0b\u843d\uff1a\u2191/W\u3001\u2193/S\u3001Space\r\n")
|
|
_T("战局:P 暂停 R 重开 M 菜单"),
|
|
-1,
|
|
&controlBodyRect,
|
|
DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
}
|
|
|
|
if (suspendFlag || gameOverFlag)
|
|
{
|
|
RECT overlayRect =
|
|
{
|
|
gameRect.left + SS(48),
|
|
gameRect.top + grid * 7,
|
|
gameRect.right - SS(48),
|
|
gameRect.top + grid * 11 + SS(18)
|
|
};
|
|
|
|
HBRUSH overlayBrush = CreateSolidBrush(RGB(255, 241, 246));
|
|
HPEN overlayPen = CreatePen(PS_SOLID, 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(26), SS(26));
|
|
SelectObject(hdc, oldBrush);
|
|
SelectObject(hdc, oldPen);
|
|
DeleteObject(overlayBrush);
|
|
DeleteObject(overlayPen);
|
|
|
|
RECT titleRect =
|
|
{
|
|
overlayRect.left + SS(24),
|
|
overlayRect.top + SS(18),
|
|
overlayRect.right - SS(24),
|
|
overlayRect.top + SS(78)
|
|
};
|
|
|
|
RECT tipRect =
|
|
{
|
|
overlayRect.left + SS(28),
|
|
overlayRect.top + SS(86),
|
|
overlayRect.right - SS(28),
|
|
overlayRect.bottom - SS(20)
|
|
};
|
|
|
|
SetTextColor(hdc, RGB(121, 76, 99));
|
|
SelectObject(hdc, titleFont);
|
|
|
|
if (suspendFlag)
|
|
{
|
|
DrawText(hdc, _T("时间静止"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
SelectObject(hdc, bodyFont);
|
|
DrawText(hdc, _T("按 P 继续战斗"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
|
}
|
|
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 (currentScreen == SCREEN_UPGRADE)
|
|
{
|
|
RECT dimRect =
|
|
{
|
|
SX(20),
|
|
SY(20),
|
|
SX(WINDOW_CLIENT_WIDTH - 20),
|
|
SY(WINDOW_CLIENT_HEIGHT - 20)
|
|
};
|
|
Graphics dimGraphics(hdc);
|
|
SolidBrush dimBrush(Color(214, 246, 232, 238));
|
|
dimGraphics.FillRectangle(
|
|
&dimBrush,
|
|
static_cast<INT>(dimRect.left),
|
|
static_cast<INT>(dimRect.top),
|
|
static_cast<INT>(dimRect.right - dimRect.left),
|
|
static_cast<INT>(dimRect.bottom - dimRect.top));
|
|
|
|
RECT overlayRect =
|
|
{
|
|
SX(60),
|
|
SY(80),
|
|
SX(WINDOW_CLIENT_WIDTH - 60),
|
|
SY(WINDOW_CLIENT_HEIGHT - 80)
|
|
};
|
|
|
|
DrawPanelCardAlpha(overlayRect, RGB(255, 250, 252), RGB(232, 170, 194), 30, 238);
|
|
|
|
SetTextColor(hdc, titleColor);
|
|
SelectObject(hdc, titleFont);
|
|
|
|
RECT overlayTitleRect =
|
|
{
|
|
overlayRect.left,
|
|
overlayRect.top + SS(24),
|
|
overlayRect.right,
|
|
overlayRect.top + SS(68)
|
|
};
|
|
DrawText(hdc, _T("选择强化"), -1, &overlayTitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, textColor);
|
|
RECT overlaySubtitleRect =
|
|
{
|
|
overlayRect.left,
|
|
overlayRect.top + SS(70),
|
|
overlayRect.right,
|
|
overlayRect.top + SS(106)
|
|
};
|
|
TCHAR overlaySubtitle[128];
|
|
_stprintf_s(
|
|
overlaySubtitle,
|
|
_T("出现 %d 个强化,还可选择 %d 个"),
|
|
upgradeUiState.optionCount,
|
|
upgradeUiState.picksRemaining);
|
|
DrawText(hdc, overlaySubtitle, -1, &overlaySubtitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
int gap = SS(18);
|
|
int horizontalPadding = SS(36);
|
|
int verticalTop = overlayRect.top + SS(138);
|
|
int columnCount = upgradeUiState.optionCount <= 3 ? upgradeUiState.optionCount : 3;
|
|
if (columnCount < 1)
|
|
{
|
|
columnCount = 1;
|
|
}
|
|
int rowCount = (upgradeUiState.optionCount + columnCount - 1) / columnCount;
|
|
if (rowCount < 1)
|
|
{
|
|
rowCount = 1;
|
|
}
|
|
int cardWidth = (overlayRect.right - overlayRect.left - horizontalPadding * 2 - gap * (columnCount - 1)) / columnCount;
|
|
int availableHeight = overlayRect.bottom - verticalTop - SS(72) - (rowCount - 1) * gap;
|
|
int cardHeight = availableHeight / rowCount;
|
|
|
|
for (int i = 0; i < upgradeUiState.optionCount; i++)
|
|
{
|
|
bool isSelected = (i == upgradeUiState.selectedIndex);
|
|
int column = i % columnCount;
|
|
int row = i / columnCount;
|
|
int left = overlayRect.left + horizontalPadding + column * (cardWidth + gap);
|
|
int top = verticalTop + row * (cardHeight + gap);
|
|
int right = left + cardWidth;
|
|
|
|
RECT cardRect =
|
|
{
|
|
left,
|
|
top,
|
|
right,
|
|
top + cardHeight
|
|
};
|
|
|
|
COLORREF cardFill = RGB(255, 247, 250);
|
|
COLORREF cardBorder = RGB(221, 197, 208);
|
|
COLORREF descColor = RGB(108, 86, 99);
|
|
COLORREF footerColor = RGB(128, 104, 118);
|
|
const TCHAR* synthesisPath = GetUpgradeSynthesisPath(upgradeUiState.options[i].id);
|
|
bool hasSynthesisPath = synthesisPath != nullptr && lstrlen(synthesisPath) > 0;
|
|
const TCHAR* rarityText = _T("\u7a00\u6709\u5ea6\uff1a\u666e\u901a");
|
|
|
|
if (upgradeUiState.options[i].cursed)
|
|
{
|
|
cardFill = isSelected ? RGB(238, 232, 238) : RGB(250, 245, 248);
|
|
cardBorder = RGB(38, 34, 42);
|
|
descColor = RGB(72, 62, 72);
|
|
footerColor = RGB(48, 42, 50);
|
|
rarityText = _T("\u7a00\u6709\u5ea6\uff1a\u8bc5\u5492");
|
|
}
|
|
else if (hasSynthesisPath)
|
|
{
|
|
cardBorder = RGB(208, 74, 78);
|
|
footerColor = RGB(164, 58, 64);
|
|
rarityText = _T("\u7a00\u6709\u5ea6\uff1a\u8fdb\u9636");
|
|
}
|
|
else if (upgradeUiState.options[i].rarity == UPGRADE_RARITY_RARE)
|
|
{
|
|
cardBorder = RGB(218, 172, 72);
|
|
footerColor = RGB(150, 111, 40);
|
|
rarityText = _T("\u7a00\u6709\u5ea6\uff1a\u73cd\u7a00");
|
|
}
|
|
else if (upgradeUiState.options[i].rarity == UPGRADE_RARITY_UNCOMMON)
|
|
{
|
|
cardBorder = RGB(92, 152, 218);
|
|
footerColor = RGB(68, 112, 166);
|
|
rarityText = _T("\u7a00\u6709\u5ea6\uff1a\u7f55\u89c1");
|
|
}
|
|
|
|
if (isSelected && !upgradeUiState.options[i].cursed)
|
|
{
|
|
cardFill = RGB(255, 235, 242);
|
|
}
|
|
|
|
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);
|
|
RECT levelRect =
|
|
{
|
|
cardRect.right - SS(88),
|
|
cardRect.top + SS(20),
|
|
cardRect.right - SS(20),
|
|
cardRect.top + SS(48)
|
|
};
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, footerColor);
|
|
DrawText(hdc, levelText, -1, &levelRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
SelectObject(hdc, sectionFont);
|
|
SetTextColor(hdc, upgradeUiState.options[i].cursed ? RGB(130, 54, 54) : (isSelected ? titleColor : textColor));
|
|
RECT nameRect =
|
|
{
|
|
cardRect.left + SS(20),
|
|
cardRect.top + SS(44),
|
|
cardRect.right - SS(96),
|
|
cardRect.top + SS(98)
|
|
};
|
|
DrawText(hdc, upgradeUiState.options[i].name, -1, &nameRect, DT_LEFT | DT_TOP | DT_WORDBREAK);
|
|
|
|
SelectObject(hdc, bodyFont);
|
|
SetTextColor(hdc, descColor);
|
|
RECT descRect =
|
|
{
|
|
cardRect.left + SS(20),
|
|
cardRect.top + SS(116),
|
|
cardRect.right - SS(20),
|
|
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(42),
|
|
cardRect.right - SS(20),
|
|
cardRect.bottom - SS(14)
|
|
};
|
|
SetTextColor(hdc, footerColor);
|
|
DrawText(
|
|
hdc,
|
|
rarityText,
|
|
-1,
|
|
&footerRect,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
SelectObject(hdc, smallFont);
|
|
SetTextColor(hdc, RGB(128, 104, 118));
|
|
RECT hintRect =
|
|
{
|
|
overlayRect.left + SS(30),
|
|
overlayRect.bottom - SS(52),
|
|
overlayRect.right - SS(30),
|
|
overlayRect.bottom - SS(18)
|
|
};
|
|
DrawText(hdc, _T("W/A/S/D \u6216\u65b9\u5411\u952e\u5207\u6362\uff0cEnter \u6216 Space \u786e\u8ba4"), -1, &hintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
DrawMusicButton();
|
|
|
|
SelectObject(hdc, oldFont);
|
|
DeleteObject(titleFont);
|
|
DeleteObject(sectionFont);
|
|
DeleteObject(bodyFont);
|
|
DeleteObject(smallFont);
|
|
}
|