增加技能演示选项

This commit is contained in:
wyk
2026-04-28 18:28:46 +08:00
parent da741d1e56
commit c77b877b8b
12 changed files with 512 additions and 39 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 722 KiB

+18
View File
@@ -191,6 +191,16 @@ struct CellFlashEffect
COLORREF color; COLORREF color;
}; };
struct GravityFallEffect
{
int ticks;
int totalTicks;
int x;
int fromY;
int toY;
int cellValue;
};
enum ScreenState enum ScreenState
{ {
SCREEN_MENU = 0, SCREEN_MENU = 0,
@@ -240,6 +250,7 @@ extern ClearEffectState clearEffectState;
extern FloatingTextEffect floatingTextEffects[8]; extern FloatingTextEffect floatingTextEffects[8];
extern ParticleEffect particleEffects[96]; extern ParticleEffect particleEffects[96];
extern CellFlashEffect cellFlashEffects[64]; extern CellFlashEffect cellFlashEffects[64];
extern GravityFallEffect gravityFallEffects[80];
extern int currentScreen; extern int currentScreen;
extern int currentMode; extern int currentMode;
extern int currentFallInterval; extern int currentFallInterval;
@@ -270,11 +281,17 @@ void StartGameWithMode(int mode);
void ReturnToMainMenu(); void ReturnToMainMenu();
void ReviveAfterVideo(); void ReviveAfterVideo();
void StartRogueSkillDemo(); void StartRogueSkillDemo();
void StartRogueSkillDemoAt(int demoIndex);
bool IsRogueSkillDemoMode(); bool IsRogueSkillDemoMode();
bool TickRogueSkillDemo(); bool TickRogueSkillDemo();
void AdvanceRogueSkillDemo(); void AdvanceRogueSkillDemo();
int GetRogueSkillDemoCount();
const TCHAR* GetRogueSkillDemoName(int demoIndex);
const TCHAR* GetRogueSkillDemoDetail(int demoIndex);
const TCHAR* GetCurrentRogueSkillDemoName();
void SetFeedbackMessage(const TCHAR* title, const TCHAR* detail, int ticks); void SetFeedbackMessage(const TCHAR* title, const TCHAR* detail, int ticks);
void OpenRulesScreen(); void OpenRulesScreen();
void OpenSkillDemoScreen();
void OpenCreditScreen(); void OpenCreditScreen();
void ChangeCreditPage(int direction); void ChangeCreditPage(int direction);
void OpenUpgradeMenu(); void OpenUpgradeMenu();
@@ -292,6 +309,7 @@ void TriggerLineClearEffect(const int* rows, int rowCount, int linesCleared);
void PlayPendingLineClearEffect(); void PlayPendingLineClearEffect();
void TriggerCellClearEffect(const Point* cells, int cellCount, bool strongBurst); void TriggerCellClearEffect(const Point* cells, int cellCount, bool strongBurst);
void TriggerColoredCellClearEffect(const Point* cells, int cellCount, COLORREF flashColor, bool strongBurst); void TriggerColoredCellClearEffect(const Point* cells, int cellCount, COLORREF flashColor, bool strongBurst);
void TriggerGravityFallEffect(int x, int fromY, int toY, int cellValue);
void AwardRogueSkillClearRewards(int clearedCells, int& scoreGain, int& expGain, bool allowLevelProgress); void AwardRogueSkillClearRewards(int clearedCells, int& scoreGain, int& expGain, bool allowLevelProgress);
void CheckRogueLevelProgress(); void CheckRogueLevelProgress();
void ApplyBoardGravity(); void ApplyBoardGravity();
+5
View File
@@ -84,6 +84,11 @@ void RollCurrentPieceSpecialFlags(bool allowRandomSpecials);
*/ */
void QueueLineClearEffect(const int* rows, int rowCount, int linesCleared); void QueueLineClearEffect(const int* rows, int rowCount, int linesCleared);
/**
* @brief 记录固定方块受重力下落的轨迹,用于播放纵向残影特效。
*/
void TriggerGravityFallEffect(int x, int fromY, int toY, int cellValue);
/** /**
* @brief 尝试把旋转后的方块横向偏移指定格数后放置。 * @brief 尝试把旋转后的方块横向偏移指定格数后放置。
*/ */
+1
View File
@@ -12,6 +12,7 @@
#define IDD_ABOUTBOX 103 #define IDD_ABOUTBOX 103
#define IDM_ABOUT 104 #define IDM_ABOUT 104
#define IDM_EXIT 105 #define IDM_EXIT 105
#define IDM_SKILL_DEMO 106
#define IDI_TETRIS 107 #define IDI_TETRIS 107
#define IDI_SMALL 108 #define IDI_SMALL 108
#define IDC_TETRIS 109 #define IDC_TETRIS 109
Binary file not shown.
+98 -4
View File
@@ -197,6 +197,30 @@ static RECT GetHelpOptionRect(HWND hWnd, int index)
return rect; return rect;
} }
static RECT GetHelpSkillDemoItemRect(HWND hWnd, int index)
{
LayoutMetrics metrics = GetLayoutMetrics(hWnd);
RECT rulesCard = GetRulesCardRect(hWnd);
RECT contentRect =
{
rulesCard.left + ScaleValue(metrics, 36),
rulesCard.top + ScaleValue(metrics, 126),
rulesCard.right - ScaleValue(metrics, 36),
rulesCard.bottom - ScaleValue(metrics, 86)
};
int itemHeight = ScaleValue(metrics, 58);
int itemGap = ScaleValue(metrics, 10);
int itemTop = contentRect.top + ScaleValue(metrics, 8) - helpScrollOffset;
RECT rect =
{
contentRect.left,
itemTop + index * (itemHeight + itemGap),
contentRect.right,
itemTop + index * (itemHeight + itemGap) + itemHeight
};
return rect;
}
static RECT GetHelpBackHintRect(HWND hWnd) static RECT GetHelpBackHintRect(HWND hWnd)
{ {
LayoutMetrics metrics = GetLayoutMetrics(hWnd); LayoutMetrics metrics = GetLayoutMetrics(hWnd);
@@ -744,6 +768,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (wmId) switch (wmId)
{ {
case IDM_SKILL_DEMO:
OpenSkillDemoScreen();
InvalidateRect(hWnd, nullptr, FALSE);
break;
case IDM_ABOUT: case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break; break;
@@ -1005,8 +1033,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
helpState.selectedIndex = i; helpState.selectedIndex = i;
if (i == 3) if (i == 3)
{ {
StartRogueSkillDemo(); helpState.currentPage = 5;
ResetGameTimer(hWnd); helpState.selectedIndex = 0;
helpScrollOffset = 0;
} }
else else
{ {
@@ -1023,6 +1052,31 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
} }
else if (helpState.currentPage == 5)
{
if (IsPointInRect(GetHelpBackHintRect(hWnd), mouseX, mouseY))
{
helpState.currentPage = 0;
helpState.selectedIndex = 3;
helpScrollOffset = 0;
InvalidateRect(hWnd, nullptr, FALSE);
}
else
{
int demoCount = GetRogueSkillDemoCount();
for (int i = 0; i < demoCount; i++)
{
if (IsPointInRect(GetHelpSkillDemoItemRect(hWnd, i), mouseX, mouseY))
{
helpState.selectedIndex = i;
StartRogueSkillDemoAt(i);
ResetGameTimer(hWnd);
InvalidateRect(hWnd, nullptr, FALSE);
break;
}
}
}
}
else if (IsPointInRect(GetHelpBackHintRect(hWnd), mouseX, mouseY)) else if (IsPointInRect(GetHelpBackHintRect(hWnd), mouseX, mouseY))
{ {
if (helpState.currentPage == 4) if (helpState.currentPage == 4)
@@ -1256,6 +1310,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
ChangeCreditPage(-1); ChangeCreditPage(-1);
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
else if (helpState.currentPage == 5)
{
helpState.selectedIndex--;
if (helpState.selectedIndex < 0)
{
helpState.selectedIndex = GetRogueSkillDemoCount() - 1;
}
if (helpState.selectedIndex * 68 < helpScrollOffset)
{
helpScrollOffset = helpState.selectedIndex * 68;
}
InvalidateRect(hWnd, nullptr, FALSE);
}
break; break;
case VK_DOWN: case VK_DOWN:
case VK_RIGHT: case VK_RIGHT:
@@ -1275,6 +1342,20 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
ChangeCreditPage(1); ChangeCreditPage(1);
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
else if (helpState.currentPage == 5)
{
helpState.selectedIndex++;
if (helpState.selectedIndex >= GetRogueSkillDemoCount())
{
helpState.selectedIndex = 0;
helpScrollOffset = 0;
}
else if (helpState.selectedIndex * 68 > helpScrollOffset + 360)
{
helpScrollOffset = helpState.selectedIndex * 68 - 360;
}
InvalidateRect(hWnd, nullptr, FALSE);
}
break; break;
case VK_RETURN: case VK_RETURN:
case VK_SPACE: case VK_SPACE:
@@ -1282,8 +1363,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
if (helpState.selectedIndex == 3) if (helpState.selectedIndex == 3)
{ {
StartRogueSkillDemo(); helpState.currentPage = 5;
ResetGameTimer(hWnd); helpState.selectedIndex = 0;
helpScrollOffset = 0;
} }
else else
{ {
@@ -1292,6 +1374,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
else if (helpState.currentPage == 5)
{
StartRogueSkillDemoAt(helpState.selectedIndex);
ResetGameTimer(hWnd);
InvalidateRect(hWnd, nullptr, FALSE);
}
break; break;
case VK_ESCAPE: case VK_ESCAPE:
case VK_BACK: case VK_BACK:
@@ -1304,6 +1392,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
ReturnToMainMenu(); ReturnToMainMenu();
} }
else if (helpState.currentPage == 5)
{
helpState.currentPage = 0;
helpState.selectedIndex = 3;
helpScrollOffset = 0;
}
else else
{ {
helpState.currentPage = 0; helpState.currentPage = 0;
+2 -1
View File
@@ -15,7 +15,7 @@ int workRegion[20][10] = { 0 };
Point point = { 0, 0 }; Point point = { 0, 0 };
Point target = { 0, 0 }; Point target = { 0, 0 };
MenuState menuState = { 0, 4 }; MenuState menuState = { 0, 4 };
HelpState helpState = { 0, 3, 0 }; HelpState helpState = { 0, 4, 0 };
int helpScrollOffset = 0; int helpScrollOffset = 0;
int creditPageIndex = 0; int creditPageIndex = 0;
int creditAnimationTicks = 0; int creditAnimationTicks = 0;
@@ -29,6 +29,7 @@ ClearEffectState clearEffectState = { 0, 0, 0, {} };
FloatingTextEffect floatingTextEffects[8] = {}; FloatingTextEffect floatingTextEffects[8] = {};
ParticleEffect particleEffects[96] = {}; ParticleEffect particleEffects[96] = {};
CellFlashEffect cellFlashEffects[64] = {}; CellFlashEffect cellFlashEffects[64] = {};
GravityFallEffect gravityFallEffects[80] = {};
int currentScreen = SCREEN_MENU; int currentScreen = SCREEN_MENU;
int currentMode = MODE_CLASSIC; int currentMode = MODE_CLASSIC;
int currentFallInterval = 500; int currentFallInterval = 500;
+74 -1
View File
@@ -116,6 +116,11 @@ void ResetVisualEffects()
{ {
cellFlashEffects[i].ticks = 0; cellFlashEffects[i].ticks = 0;
} }
for (int i = 0; i < 80; i++)
{
gravityFallEffects[i].ticks = 0;
}
} }
/** /**
@@ -158,6 +163,15 @@ bool TickVisualEffects()
} }
} }
for (int i = 0; i < 80; i++)
{
if (gravityFallEffects[i].ticks > 0)
{
gravityFallEffects[i].ticks--;
active = true;
}
}
return active; return active;
} }
@@ -429,6 +443,51 @@ void TriggerColoredCellClearEffect(const Point* cells, int cellCount, COLORREF f
} }
} }
/**
* @brief 为一个受重力下落的固定方块记录纵向残影和落点粒子。
*/
void TriggerGravityFallEffect(int x, int fromY, int toY, int cellValue)
{
if (x < 0 || x >= nGameWidth || fromY < 0 || fromY >= nGameHeight ||
toY < 0 || toY >= nGameHeight || toY <= fromY || cellValue == 0)
{
return;
}
int effectIndex = -1;
for (int i = 0; i < 80; i++)
{
if (gravityFallEffects[i].ticks <= 0)
{
effectIndex = i;
break;
}
}
if (effectIndex < 0)
{
return;
}
int totalTicks = 12 + (toY - fromY) * 2;
if (totalTicks > 26)
{
totalTicks = 26;
}
gravityFallEffects[effectIndex].ticks = totalTicks;
gravityFallEffects[effectIndex].totalTicks = totalTicks;
gravityFallEffects[effectIndex].x = x;
gravityFallEffects[effectIndex].fromY = fromY;
gravityFallEffects[effectIndex].toY = toY;
gravityFallEffects[effectIndex].cellValue = cellValue;
COLORREF particleColor = BrickColor[(cellValue - 1) % 7];
AddParticle(x * 100 + 50, toY * 100 + 18, -2 - rand() % 5, -12 - rand() % 7, 4, particleColor);
AddParticle(x * 100 + 50, toY * 100 + 18, 2 + rand() % 5, -12 - rand() % 7, 4, particleColor);
AddCellFlash(x, toY, RGB(210, 245, 255), true);
}
/** /**
* @brief 判断指定方块、旋转状态和位置是否可以合法放置。 * @brief 判断指定方块、旋转状态和位置是否可以合法放置。
*/ */
@@ -575,6 +634,20 @@ void OpenRulesScreen()
/** /**
* @brief 打开致谢界面并重置致谢页切换状态。 * @brief 打开致谢界面并重置致谢页切换状态。
*/ */
void OpenSkillDemoScreen()
{
rogueDemoMode = false;
currentScreen = SCREEN_RULES;
suspendFlag = false;
helpState.selectedIndex = 0;
helpState.optionCount = 4;
helpState.currentPage = 5;
helpScrollOffset = 0;
creditPageIndex = 0;
creditAnimationTicks = 0;
creditAnimationDirection = 0;
}
void OpenCreditScreen() void OpenCreditScreen()
{ {
rogueDemoMode = false; rogueDemoMode = false;
@@ -594,7 +667,7 @@ void OpenCreditScreen()
*/ */
void ChangeCreditPage(int direction) void ChangeCreditPage(int direction)
{ {
constexpr int creditPageCount = 3; constexpr int creditPageCount = 4;
if (direction == 0) if (direction == 0)
{ {
return; return;
+227 -23
View File
@@ -131,7 +131,7 @@ static Bitmap* LoadBackgroundImage()
*/ */
static Bitmap* LoadCreditImage(int index) static Bitmap* LoadCreditImage(int index)
{ {
constexpr int creditPageCount = 3; constexpr int creditPageCount = 4;
static ULONG_PTR gdiplusToken = 0; static ULONG_PTR gdiplusToken = 0;
static Bitmap* creditImages[creditPageCount] = {}; static Bitmap* creditImages[creditPageCount] = {};
static bool attempted[creditPageCount] = {}; static bool attempted[creditPageCount] = {};
@@ -152,16 +152,25 @@ static Bitmap* LoadCreditImage(int index)
{ {
L"assets\\images\\qls.jpg", L"assets\\images\\qls.jpg",
L"assets\\images\\wyk.jpg", L"assets\\images\\wyk.jpg",
L"assets\\images\\swj.jpg" L"assets\\images\\swj.jpg",
L"assets\\images\\qhy.jpg"
}; };
const std::wstring candidates[] = const std::wstring creditExtraCandidates[] =
{ {
BuildAssetPath(imageNames[index]), BuildAssetPath(imageNames[index]),
BuildWorkingDirAssetPath(imageNames[index]) BuildWorkingDirAssetPath(imageNames[index]),
BuildAssetPath(L"assets\\images\\qhy.png"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.png"),
BuildAssetPath(L"assets\\images\\qhy.jpeg"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.jpeg"),
BuildAssetPath(L"assets\\images\\qhy.bmp"),
BuildWorkingDirAssetPath(L"assets\\images\\qhy.bmp")
}; };
int candidateCount = (index == 3) ? 8 : 2;
for (const std::wstring& candidate : candidates) for (int i = 0; i < candidateCount; i++)
{ {
const std::wstring& candidate = creditExtraCandidates[i];
if (candidate.empty()) if (candidate.empty())
{ {
continue; continue;
@@ -639,6 +648,10 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{ {
helpTitle = _T("\u81f4\u8c22"); helpTitle = _T("\u81f4\u8c22");
} }
else if (helpState.currentPage == 5)
{
helpTitle = _T("\u6280\u80fd\u6f14\u793a");
}
DrawText(hdc, helpTitle, -1, &rulesTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); DrawText(hdc, helpTitle, -1, &rulesTitleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
HPEN rulesAccentPen = CreatePen(PS_SOLID, SS(3), accentColor); HPEN rulesAccentPen = CreatePen(PS_SOLID, SS(3), accentColor);
@@ -880,21 +893,108 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DeleteObject(contentClipRegion); DeleteObject(contentClipRegion);
DeleteObject(oldClipRegion); DeleteObject(oldClipRegion);
} }
else if (helpState.currentPage == 5)
{
int demoCount = GetRogueSkillDemoCount();
int itemHeight = SS(58);
int itemGap = SS(10);
int contentHeight = contentRect.bottom - contentRect.top;
int virtualHeight = SS(8) + demoCount * (itemHeight + itemGap);
int maxHelpScroll = virtualHeight - contentHeight;
if (maxHelpScroll < 0)
{
maxHelpScroll = 0;
}
if (helpScrollOffset > maxHelpScroll)
{
helpScrollOffset = maxHelpScroll;
}
HRGN oldClipRegion = CreateRectRgn(0, 0, 0, 0);
int hasOldClipRegion = GetClipRgn(hdc, oldClipRegion);
HRGN contentClipRegion = CreateRectRgn(contentRect.left, contentRect.top, contentRect.right, contentRect.bottom);
SelectClipRgn(hdc, contentClipRegion);
int itemTop = contentRect.top + SS(8) - helpScrollOffset;
for (int i = 0; i < demoCount; i++)
{
RECT itemRect =
{
contentRect.left,
itemTop + i * (itemHeight + itemGap),
contentRect.right,
itemTop + i * (itemHeight + itemGap) + itemHeight
};
if (itemRect.bottom < contentRect.top || itemRect.top > contentRect.bottom)
{
continue;
}
bool selected = (i == helpState.selectedIndex);
COLORREF itemFill = selected ? RGB(255, 245, 249) : RGB(255, 252, 250);
COLORREF itemFrame = selected ? accentColor : frameColor;
HPEN itemPen = CreatePen(PS_SOLID, selected ? SS(2) : SS(1), itemFrame);
HBRUSH itemBrush = CreateSolidBrush(itemFill);
oldPen = (HPEN)SelectObject(hdc, itemPen);
oldBrush = (HBRUSH)SelectObject(hdc, itemBrush);
RoundRect(hdc, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom, SS(18), SS(18));
SelectObject(hdc, oldBrush);
SelectObject(hdc, oldPen);
DeleteObject(itemBrush);
DeleteObject(itemPen);
SetTextColor(hdc, selected ? titleColor : textColor);
SelectObject(hdc, sectionFont);
RECT nameRect =
{
itemRect.left + SS(22),
itemRect.top + SS(8),
itemRect.left + SS(210),
itemRect.bottom - SS(8)
};
DrawText(hdc, GetRogueSkillDemoName(i), -1, &nameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
SetTextColor(hdc, RGB(112, 91, 104));
SelectObject(hdc, bodyFont);
RECT detailRect =
{
itemRect.left + SS(220),
itemRect.top + SS(8),
itemRect.right - SS(22),
itemRect.bottom - SS(8)
};
DrawText(hdc, GetRogueSkillDemoDetail(i), -1, &detailRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
if (hasOldClipRegion == 1)
{
SelectClipRgn(hdc, oldClipRegion);
}
else
{
SelectClipRgn(hdc, nullptr);
}
DeleteObject(contentClipRegion);
DeleteObject(oldClipRegion);
}
else if (helpState.currentPage == 4) else if (helpState.currentPage == 4)
{ {
const int creditAnimationTotalTicks = 60; const int creditAnimationTotalTicks = 60;
constexpr int creditPageCount = 3; constexpr int creditPageCount = 4;
const TCHAR* creditNames[creditPageCount] = const TCHAR* creditNames[creditPageCount] =
{ {
_T("qls"), _T("qls"),
_T("wyk"), _T("wyk"),
_T("juju") _T("juju"),
_T("qhy")
}; };
const TCHAR* creditTexts[creditPageCount] = const TCHAR* creditTexts[creditPageCount] =
{ {
_T("\u611f\u8c22\u6fc0\u60c5\u6295\u8eab\u4e8e\u6d4b\u8bd5\u4e4b\u4e2d\u7684Lisa"), _T("\u611f\u8c22\u6fc0\u60c5\u6295\u8eab\u4e8e\u6d4b\u8bd5\u4e4b\u4e2d\u7684Lisa"),
_T("\u611f\u8c22\u70ed\u5ff1coding\u7684\u5c0f\u86cb\u7cd5"), _T("\u611f\u8c22\u70ed\u5ff1coding\u7684\u5c0f\u86cb\u7cd5"),
_T("\u611f\u8c22\u8bfe\u524d\u95f2\u91cc\u5077\u5fd9\u7684juju") _T("\u611f\u8c22\u8bfe\u524d\u95f2\u91cc\u5077\u5fd9\u7684juju"),
_T("\u611f\u8c22qhy\u7684\u5929\u624d\u6784\u60f3")
}; };
int currentCredit = creditPageIndex; int currentCredit = creditPageIndex;
@@ -946,9 +1046,11 @@ void TDrawScreen(HDC hdc, HWND hWnd)
previousOffset = currentOffset - creditAnimationDirection * slideDistance; previousOffset = currentOffset - creditAnimationDirection * slideDistance;
} }
Bitmap* preloadedCreditImageA = LoadCreditImage(0); Bitmap* preloadedCreditImages[creditPageCount] = {};
Bitmap* preloadedCreditImageB = LoadCreditImage(1); for (int i = 0; i < creditPageCount; i++)
Bitmap* preloadedCreditImageC = LoadCreditImage(2); {
preloadedCreditImages[i] = LoadCreditImage(i);
}
Graphics creditGraphics(hdc); Graphics creditGraphics(hdc);
creditGraphics.SetInterpolationMode(InterpolationModeHighQualityBilinear); creditGraphics.SetInterpolationMode(InterpolationModeHighQualityBilinear);
@@ -959,14 +1061,10 @@ void TDrawScreen(HDC hdc, HWND hWnd)
OffsetRect(&shiftedImageArea, offset, 0); OffsetRect(&shiftedImageArea, offset, 0);
OffsetRect(&shiftedTextArea, offset, 0); OffsetRect(&shiftedTextArea, offset, 0);
Bitmap* creditImage = preloadedCreditImageA; Bitmap* creditImage = nullptr;
if (cardIndex == 1) if (cardIndex >= 0 && cardIndex < creditPageCount)
{ {
creditImage = preloadedCreditImageB; creditImage = preloadedCreditImages[cardIndex];
}
else if (cardIndex == 2)
{
creditImage = preloadedCreditImageC;
} }
if (creditImage != nullptr) if (creditImage != nullptr)
{ {
@@ -1083,7 +1181,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
SelectObject(hdc, oldPen); SelectObject(hdc, oldPen);
DeleteObject(chevronPen); DeleteObject(chevronPen);
} }
if (helpState.currentPage != 3 && helpState.currentPage != 4) if (helpState.currentPage != 3 && helpState.currentPage != 4 && helpState.currentPage != 5)
{ {
RECT calculateRect = { contentRect.left, contentRect.top, contentRect.right, contentRect.top }; RECT calculateRect = { contentRect.left, contentRect.top, contentRect.right, contentRect.top };
DrawText(hdc, pageText, -1, &calculateRect, pageFlags | DT_CALCRECT); DrawText(hdc, pageText, -1, &calculateRect, pageFlags | DT_CALCRECT);
@@ -1133,7 +1231,9 @@ void TDrawScreen(HDC hdc, HWND hWnd)
? _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter / Space \u786e\u8ba4\uff0cEsc / M \u8fd4\u56de\u4e3b\u83dc\u5355") ? _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter / Space \u786e\u8ba4\uff0cEsc / M \u8fd4\u56de\u4e3b\u83dc\u5355")
: (helpState.currentPage == 4 : (helpState.currentPage == 4
? _T("\u5de6\u53f3\u65b9\u5411\u952e / A D \u5207\u6362\uff0cEsc / Backspace / M \u8fd4\u56de\u4e3b\u83dc\u5355") ? _T("\u5de6\u53f3\u65b9\u5411\u952e / A D \u5207\u6362\uff0cEsc / Backspace / M \u8fd4\u56de\u4e3b\u83dc\u5355")
: _T("\u9f20\u6807\u6eda\u8f6e\u4e0a\u4e0b\u7ffb\u52a8\uff0cEsc / Backspace / M \u8fd4\u56de\u5e2e\u52a9")); : (helpState.currentPage == 5
? _T("\u70b9\u51fb\u6280\u80fd\u540d\u79f0\u6216 Enter \u6f14\u793a\uff0c\u6eda\u8f6e\u7ffb\u52a8\uff0cEsc / Backspace / M \u8fd4\u56de\u5e2e\u52a9")
: _T("\u9f20\u6807\u6eda\u8f6e\u4e0a\u4e0b\u7ffb\u52a8\uff0cEsc / Backspace / M \u8fd4\u56de\u5e2e\u52a9")));
DrawText(hdc, helpHint, -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); DrawText(hdc, helpHint, -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
SelectClipRgn(hdc, nullptr); SelectClipRgn(hdc, nullptr);
@@ -1373,6 +1473,72 @@ void TDrawScreen(HDC hdc, HWND hWnd)
} }
} }
for (int i = 0; i < 80; i++)
{
if (gravityFallEffects[i].ticks <= 0 || gravityFallEffects[i].totalTicks <= 0)
{
continue;
}
if (gravityFallEffects[i].x < 0 || gravityFallEffects[i].x >= nGameWidth ||
gravityFallEffects[i].fromY < 0 || gravityFallEffects[i].fromY >= nGameHeight ||
gravityFallEffects[i].toY < 0 || gravityFallEffects[i].toY >= nGameHeight)
{
continue;
}
int elapsed = gravityFallEffects[i].totalTicks - gravityFallEffects[i].ticks;
int travel = gravityFallEffects[i].toY - gravityFallEffects[i].fromY;
int offsetY = travel * grid * elapsed / gravityFallEffects[i].totalTicks;
int drawX = gameRect.left + gravityFallEffects[i].x * grid;
int fromPixelY = gameRect.top + gravityFallEffects[i].fromY * grid;
int toPixelY = gameRect.top + gravityFallEffects[i].toY * grid;
int currentPixelY = fromPixelY + offsetY;
int colorIndex = gravityFallEffects[i].cellValue - 1;
if (colorIndex < 0 || colorIndex >= 7)
{
colorIndex = (gravityFallEffects[i].x + gravityFallEffects[i].toY) % 7;
}
COLORREF fallColor = BrickColor[colorIndex];
int alpha = 56 + gravityFallEffects[i].ticks * 150 / gravityFallEffects[i].totalTicks;
int trailTop = fromPixelY + grid / 2;
int trailBottom = currentPixelY + grid / 2;
if (trailBottom < trailTop + SS(8))
{
trailBottom = trailTop + SS(8);
}
if (trailBottom > toPixelY + grid / 2)
{
trailBottom = toPixelY + grid / 2;
}
Graphics fallGraphics(hdc);
fallGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
SolidBrush trailBrush(Color(alpha / 2, GetRValue(fallColor), GetGValue(fallColor), GetBValue(fallColor)));
fallGraphics.FillRectangle(
&trailBrush,
static_cast<INT>(drawX + SS(12)),
static_cast<INT>(trailTop),
static_cast<INT>(grid - SS(24)),
static_cast<INT>(trailBottom - trailTop));
SolidBrush ghostBrush(Color(alpha, GetRValue(fallColor), GetGValue(fallColor), GetBValue(fallColor)));
Pen ghostPen(Color(230, 255, 255, 255), static_cast<REAL>(SS(2)));
fallGraphics.FillRectangle(
&ghostBrush,
static_cast<INT>(drawX + SS(3)),
static_cast<INT>(currentPixelY + SS(3)),
static_cast<INT>(grid - SS(6)),
static_cast<INT>(grid - SS(6)));
fallGraphics.DrawRectangle(
&ghostPen,
static_cast<INT>(drawX + SS(3)),
static_cast<INT>(currentPixelY + SS(3)),
static_cast<INT>(grid - SS(6)),
static_cast<INT>(grid - SS(6)));
}
if (clearEffectState.ticks > 0 && clearEffectState.totalTicks > 0) if (clearEffectState.ticks > 0 && clearEffectState.totalTicks > 0)
{ {
int elapsed = clearEffectState.totalTicks - clearEffectState.ticks; int elapsed = clearEffectState.totalTicks - clearEffectState.ticks;
@@ -1561,12 +1727,50 @@ void TDrawScreen(HDC hdc, HWND hWnd)
if (currentMode == MODE_ROGUE) if (currentMode == MODE_ROGUE)
{ {
RECT progressRect = int progressTop = IsRogueSkillDemoMode() ? 350 : 270;
int progressBottom = IsRogueSkillDemoMode() ? 568 : 488;
int upgradeTop = IsRogueSkillDemoMode() ? 590 : 510;
if (IsRogueSkillDemoMode())
{
RECT demoSkillRect =
{ {
leftPanelRect.left + SS(20), leftPanelRect.left + SS(20),
leftPanelRect.top + SS(270), leftPanelRect.top + SS(270),
leftPanelRect.right - SS(20), leftPanelRect.right - SS(20),
leftPanelRect.top + SS(488) leftPanelRect.top + SS(332)
};
DrawPanelCardAlpha(demoSkillRect, RGB(255, 244, 248), RGB(232, 184, 202), 20, panelNestedAlpha);
SelectObject(hdc, smallFont);
SetTextColor(hdc, RGB(132, 102, 118));
RECT demoSkillLabelRect =
{
demoSkillRect.left + SS(18),
demoSkillRect.top + SS(8),
demoSkillRect.right - SS(18),
demoSkillRect.top + SS(26)
};
DrawText(hdc, _T("\u5f53\u524d\u6280\u80fd"), -1, &demoSkillLabelRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
SelectObject(hdc, sectionFont);
SetTextColor(hdc, titleColor);
RECT demoSkillNameRect =
{
demoSkillRect.left + SS(18),
demoSkillRect.top + SS(26),
demoSkillRect.right - SS(18),
demoSkillRect.bottom - SS(8)
};
DrawText(hdc, GetCurrentRogueSkillDemoName(), -1, &demoSkillNameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
RECT progressRect =
{
leftPanelRect.left + SS(20),
leftPanelRect.top + SS(progressTop),
leftPanelRect.right - SS(20),
leftPanelRect.top + SS(progressBottom)
}; };
DrawPanelCardAlpha(progressRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha); DrawPanelCardAlpha(progressRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
@@ -1670,7 +1874,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
RECT upgradeListRect = RECT upgradeListRect =
{ {
leftPanelRect.left + SS(20), leftPanelRect.left + SS(20),
leftPanelRect.top + SS(510), leftPanelRect.top + SS(upgradeTop),
leftPanelRect.right - SS(20), leftPanelRect.right - SS(20),
leftPanelRect.bottom - SS(20) leftPanelRect.bottom - SS(20)
}; };
+84 -7
View File
@@ -111,6 +111,7 @@ static int pendingUpgradeShockwaveRows = 0;
static bool pendingEvolutionImpactShockwave = false; static bool pendingEvolutionImpactShockwave = false;
static int rogueDemoStepIndex = 0; static int rogueDemoStepIndex = 0;
static int rogueDemoTicks = 0; static int rogueDemoTicks = 0;
static bool rogueDemoAutoAdvance = true;
enum RogueDemoKind enum RogueDemoKind
{ {
@@ -194,6 +195,7 @@ static void ShowRogueDemoFloatingName(const TCHAR* name);
static void FillRogueDemoCell(int y, int x, int value); static void FillRogueDemoCell(int y, int x, int value);
static void FillRogueDemoRows(int firstRow, int lastRow, int baseValue); static void FillRogueDemoRows(int firstRow, int lastRow, int baseValue);
static void SetRogueDemoCurrentPiece(int pieceType, int pieceState, int x, int y); static void SetRogueDemoCurrentPiece(int pieceType, int pieceState, int x, int y);
static void StartRogueSkillDemoInternal(int demoIndex, bool autoAdvance);
/** /**
* @brief 限制 Rogue 模式的下一方块预览数量。 * @brief 限制 Rogue 模式的下一方块预览数量。
@@ -1966,6 +1968,10 @@ void ApplyBoardGravity()
int cell = workRegion[y][x]; int cell = workRegion[y][x];
workRegion[y][x] = 0; workRegion[y][x] = 0;
workRegion[writeY][x] = cell; workRegion[writeY][x] = cell;
if (writeY != y)
{
TriggerGravityFallEffect(x, y, writeY, cell);
}
writeY--; writeY--;
} }
} }
@@ -2772,16 +2778,89 @@ bool IsRogueSkillDemoMode()
return rogueDemoMode; return rogueDemoMode;
} }
/**
* @brief 返回 Rogue 技能演示条目数量,供帮助页逐行绘制可点击名单。
*/
int GetRogueSkillDemoCount()
{
return kRogueDemoStepCount;
}
/**
* @brief 按序号返回 Rogue 技能演示名称。
*/
const TCHAR* GetRogueSkillDemoName(int demoIndex)
{
if (demoIndex < 0 || demoIndex >= kRogueDemoStepCount)
{
return _T("");
}
return kRogueDemoSteps[demoIndex].name;
}
/**
* @brief 按序号返回 Rogue 技能演示说明。
*/
const TCHAR* GetRogueSkillDemoDetail(int demoIndex)
{
if (demoIndex < 0 || demoIndex >= kRogueDemoStepCount)
{
return _T("");
}
return kRogueDemoSteps[demoIndex].detail;
}
/**
* @brief 返回当前正在演示的 Rogue 技能名称。
*/
const TCHAR* GetCurrentRogueSkillDemoName()
{
if (!rogueDemoMode)
{
return _T("");
}
return GetRogueSkillDemoName(rogueDemoStepIndex);
}
/** /**
* @brief 从帮助页进入 Rogue 技能演示,并播放第一段技能展示。 * @brief 从帮助页进入 Rogue 技能演示,并播放第一段技能展示。
*/ */
void StartRogueSkillDemo() void StartRogueSkillDemo()
{ {
StartRogueSkillDemoInternal(0, true);
}
/**
* @brief 从帮助页的技能名单进入指定 Rogue 技能演示。
*/
void StartRogueSkillDemoAt(int demoIndex)
{
StartRogueSkillDemoInternal(demoIndex, false);
}
/**
* @brief 进入 Rogue 技能演示并配置起始条目和是否自动轮播。
*/
static void StartRogueSkillDemoInternal(int demoIndex, bool autoAdvance)
{
if (demoIndex < 0)
{
demoIndex = 0;
}
if (demoIndex >= kRogueDemoStepCount)
{
demoIndex = kRogueDemoStepCount - 1;
}
currentMode = MODE_ROGUE; currentMode = MODE_ROGUE;
currentScreen = SCREEN_PLAYING; currentScreen = SCREEN_PLAYING;
rogueDemoMode = true; rogueDemoMode = true;
rogueDemoStepIndex = 0; rogueDemoStepIndex = demoIndex;
rogueDemoTicks = 0; rogueDemoTicks = 0;
rogueDemoAutoAdvance = autoAdvance;
Restart(); Restart();
rogueDemoMode = true; rogueDemoMode = true;
@@ -2805,11 +2884,14 @@ bool TickRogueSkillDemo()
return false; return false;
} }
if (rogueDemoAutoAdvance)
{
rogueDemoTicks++; rogueDemoTicks++;
if (rogueDemoTicks >= kRogueDemoStepTicks) if (rogueDemoTicks >= kRogueDemoStepTicks)
{ {
AdvanceRogueSkillDemo(); AdvanceRogueSkillDemo();
} }
}
return true; return true;
} }
@@ -2876,12 +2958,7 @@ static void ResetRogueDemoBoard()
*/ */
static void ShowRogueDemoFloatingName(const TCHAR* name) static void ShowRogueDemoFloatingName(const TCHAR* name)
{ {
floatingTextEffects[0].ticks = 56; (void)name;
floatingTextEffects[0].totalTicks = 56;
floatingTextEffects[0].boardX = 500;
floatingTextEffects[0].boardY = 980;
floatingTextEffects[0].color = RGB(255, 248, 250);
lstrcpyn(floatingTextEffects[0].text, name, sizeof(floatingTextEffects[0].text) / sizeof(TCHAR));
} }
/** /**
Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB