完善帮助

This commit is contained in:
2026-04-26 14:28:22 +08:00
parent 96ab175877
commit 68967f66c6
4 changed files with 245 additions and 74 deletions
+8
View File
@@ -31,6 +31,13 @@ struct MenuState
int optionCount;
};
struct HelpState
{
int selectedIndex;
int optionCount;
int currentPage;
};
struct PlayerStats
{
int score;
@@ -207,6 +214,7 @@ extern int workRegion[20][10];
extern Point point;
extern Point target;
extern MenuState menuState;
extern HelpState helpState;
extern PlayerStats classicStats;
extern PlayerStats rogueStats;
extern UpgradeUiState upgradeUiState;
+44 -1
View File
@@ -698,10 +698,53 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case VK_UP:
case VK_LEFT:
case 'W':
case 'A':
if (helpState.currentPage == 0)
{
helpState.selectedIndex--;
if (helpState.selectedIndex < 0)
{
helpState.selectedIndex = helpState.optionCount - 1;
}
InvalidateRect(hWnd, nullptr, FALSE);
}
break;
case VK_DOWN:
case VK_RIGHT:
case 'S':
case 'D':
if (helpState.currentPage == 0)
{
helpState.selectedIndex++;
if (helpState.selectedIndex >= helpState.optionCount)
{
helpState.selectedIndex = 0;
}
InvalidateRect(hWnd, nullptr, FALSE);
}
break;
case VK_RETURN:
case VK_SPACE:
if (helpState.currentPage == 0)
{
helpState.currentPage = helpState.selectedIndex + 1;
InvalidateRect(hWnd, nullptr, FALSE);
}
break;
case VK_ESCAPE:
case VK_BACK:
case 'M':
ReturnToMainMenu();
if (helpState.currentPage == 0)
{
ReturnToMainMenu();
}
else
{
helpState.currentPage = 0;
}
InvalidateRect(hWnd, nullptr, FALSE);
break;
default:
+4
View File
@@ -14,6 +14,7 @@ int workRegion[20][10] = { 0 };
Point point = { 0, 0 };
Point target = { 0, 0 };
MenuState menuState = { 0, 2 };
HelpState helpState = { 0, 3, 0 };
PlayerStats classicStats = { 0, 1, 0, 0, 0 };
PlayerStats rogueStats = { 0, 1, 0, 30, 0, 100, 100, 0 };
UpgradeUiState upgradeUiState = { 0, 0, 0, 0, {} };
@@ -1268,4 +1269,7 @@ void OpenRulesScreen()
{
currentScreen = SCREEN_RULES;
suspendFlag = false;
helpState.selectedIndex = 0;
helpState.optionCount = 3;
helpState.currentPage = 0;
}
+189 -73
View File
@@ -387,14 +387,14 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{
_T("\u7ecf\u5178\u6a21\u5f0f"),
_T("Rogue \u6a21\u5f0f"),
_T("\u6e38\u620f\u89c4\u5219")
_T("\u5e2e\u52a9")
};
const TCHAR* modeDescriptions[3] =
{
_T("纯粹方块挑战,专注消行、堆叠与生存。"),
_T("在不断升级的棋盘中收集强化,构筑本局专属流派。"),
_T("查看操作、成长、主动技能与特殊方块规则")
_T("查看操作、模式规则与全部强化效果")
};
for (int i = 0; i < menuState.optionCount; i++)
@@ -502,7 +502,20 @@ void TDrawScreen(HDC hdc, HWND hWnd)
rulesCard.right - SS(36),
rulesCard.top + SS(78)
};
DrawText(hdc, _T("\u6e38\u620f\u89c4\u5219"), -1, &rulesTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
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);
@@ -511,87 +524,187 @@ void TDrawScreen(HDC hdc, HWND hWnd)
SelectObject(hdc, oldPen);
DeleteObject(rulesAccentPen);
RECT leftSection =
RECT contentRect =
{
rulesCard.left + SS(36),
rulesCard.top + SS(126),
rulesCard.left + SS(330),
rulesCard.bottom - SS(86)
};
RECT rightSection =
{
rulesCard.left + SS(360),
rulesCard.top + SS(126),
rulesCard.right - SS(36),
rulesCard.bottom - SS(86)
};
SetTextColor(hdc, textColor);
SelectObject(hdc, sectionFont);
RECT sectionTitle =
if (helpState.currentPage == 0)
{
leftSection.left,
leftSection.top,
leftSection.right,
leftSection.top + SS(34)
};
DrawText(hdc, _T("\u57fa\u672c\u64cd\u4f5c"), -1, &sectionTitle, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
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")
};
SelectObject(hdc, bodyFont);
RECT leftBody =
{
leftSection.left,
leftSection.top + SS(48),
leftSection.right,
leftSection.bottom
};
DrawText(
hdc,
_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"),
-1,
&leftBody,
DT_LEFT | DT_TOP | DT_WORDBREAK);
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);
SelectObject(hdc, sectionFont);
RECT rulesSectionTitle =
{
rightSection.left,
rightSection.top,
rightSection.right,
rightSection.top + SS(34)
};
DrawText(hdc, _T("\u6a21\u5f0f\u89c4\u5219"), -1, &rulesSectionTitle, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
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);
SelectObject(hdc, bodyFont);
RECT rulesBody =
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
{
rightSection.left,
rightSection.top + SS(48),
rightSection.right,
rightSection.bottom
};
DrawText(
hdc,
_T("经典模式:没有成长与主动技能,只考验基础堆叠、消行和生存。\r\n\r\n")
_T("Rogue \u6a21\u5f0f\uff1a消行得分数与 EXP。EXP 满后选择强化,逐步塑造本局能力\r\n\r\n")
_T("强化会带来爆破、雷霆、狂热、黑洞、备用仓等能力;部分进阶强化需要先掌握对应前置\r\n\r\n")
_T("战斗持续越久,危险等级越高,底部封锁区会逐步压缩可用空间"),
-1,
&rulesBody,
DT_LEFT | DT_TOP | DT_WORDBREAK);
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行\r\n黑洞奇点:Z 吞噬最多方块"),
_T("爆破核心:爆破块清 3x3\r\n棱镜激光:清整列\r\n十字方块:清行列\r\n彩虹方块:补齐缺口;方块改造:提高 I 块概率"),
_T("连锁火花:消行追加破坏\r\n连环炸弹:爆破扩大 5x5\r\n雷霆四消:四消额外轰击\r\n雷霆棱镜:四消额外激光"),
_T("狂热节拍:20行进狂热\r\n怒火连段:连击加倍率\r\n无尽狂热:延长狂热\r\n高压悬赏 / 豪赌四消 / 极限玩家:高风险高收益"),
_T("双重抉择:升级多选1个\r\n命运轮盘:6选2但带诅咒\r\n升级冲击波 / 进化冲击:升级清底\r\n成长核心:永久得分 / EXP +15%"),
_T("操控大师:Hold 后减速并预览+1\r\n方块风暴:接下来全 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));
@@ -602,7 +715,10 @@ void TDrawScreen(HDC hdc, HWND hWnd)
rulesCard.right - SS(36),
rulesCard.bottom - SS(24)
};
DrawText(hdc, _T("Esc / Backspace / M \u8fd4\u56de\u4e3b\u83dc\u5355"), -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
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);