11 Commits

Author SHA1 Message Date
Qi-huanye 2f435f5ca6 优化帮助页逻辑 2026-04-28 21:11:50 +08:00
Qi-huanye 45d9e988df 去除重力 2026-04-28 20:57:57 +08:00
Qi-huanye aa9e2f3ddc 补充调整演示模式 2026-04-28 20:41:15 +08:00
Qi-huanye 971d8be0dc 下落调整 2026-04-28 20:31:41 +08:00
Qi-huanye 9341ac9a05 演示调整 2026-04-28 20:18:04 +08:00
wyk c77b877b8b 增加技能演示选项 2026-04-28 18:28:46 +08:00
Qi-huanye da741d1e56 加入帮助页轮播框架未完善(实则一坨) 2026-04-28 15:03:51 +08:00
Qi-huanye 647038b27a 致谢页添加 2026-04-28 14:34:26 +08:00
Qi-huanye 00729fbe17 清屏炸弹可以重复选择 2026-04-28 14:22:36 +08:00
Qi-huanye 2c04796010 修复强化界面m不能返回 2026-04-27 23:16:54 +08:00
Qi-huanye f3065c5fe7 空中换形可重复选择 2026-04-27 23:14:50 +08:00
12 changed files with 1396 additions and 95 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 722 KiB

+24
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,
@@ -221,6 +231,7 @@ extern bool suspendFlag;
extern bool targetFlag; extern bool targetFlag;
extern bool bgmEnabled; extern bool bgmEnabled;
extern bool reviveAvailable; extern bool reviveAvailable;
extern bool rogueDemoMode;
extern int workRegion[20][10]; extern int workRegion[20][10];
extern Point point; extern Point point;
extern Point target; extern Point target;
@@ -239,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;
@@ -268,8 +280,19 @@ void Restart();
void StartGameWithMode(int mode); void StartGameWithMode(int mode);
void ReturnToMainMenu(); void ReturnToMainMenu();
void ReviveAfterVideo(); void ReviveAfterVideo();
void StartRogueSkillDemo();
void StartRogueSkillDemoAt(int demoIndex);
void RestartCurrentRogueSkillDemo();
bool IsRogueSkillDemoMode();
bool TickRogueSkillDemo();
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();
@@ -287,6 +310,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.
+169 -13
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;
@@ -789,7 +817,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
shouldRefresh = true; shouldRefresh = true;
} }
if (currentMode == MODE_ROGUE && rogueStats.feverTicks > 0) if (IsRogueSkillDemoMode())
{
if (TickRogueSkillDemo())
{
shouldRefresh = true;
}
}
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.feverTicks > 0)
{ {
rogueStats.feverTicks--; rogueStats.feverTicks--;
currentFallInterval = GetRogueFallInterval(); currentFallInterval = GetRogueFallInterval();
@@ -798,6 +834,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
if (currentMode == MODE_ROGUE && if (currentMode == MODE_ROGUE &&
!IsRogueSkillDemoMode() &&
rogueStats.timeDilationTicks > 0 && rogueStats.timeDilationTicks > 0 &&
currentScreen == SCREEN_PLAYING && currentScreen == SCREEN_PLAYING &&
!suspendFlag && !suspendFlag &&
@@ -809,7 +846,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
shouldRefresh = true; shouldRefresh = true;
} }
if (currentMode == MODE_ROGUE && rogueStats.extremeSlowTicks > 0) if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.extremeSlowTicks > 0)
{ {
rogueStats.extremeSlowTicks--; rogueStats.extremeSlowTicks--;
currentFallInterval = GetRogueFallInterval(); currentFallInterval = GetRogueFallInterval();
@@ -818,6 +855,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
if (currentMode == MODE_ROGUE && if (currentMode == MODE_ROGUE &&
!IsRogueSkillDemoMode() &&
rogueStats.extremePlayerLevel > 0 && rogueStats.extremePlayerLevel > 0 &&
currentScreen == SCREEN_PLAYING && currentScreen == SCREEN_PLAYING &&
!suspendFlag && !suspendFlag &&
@@ -843,7 +881,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
} }
if (currentMode == MODE_ROGUE && rogueStats.holdSlowTicks > 0) if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.holdSlowTicks > 0)
{ {
rogueStats.holdSlowTicks--; rogueStats.holdSlowTicks--;
currentFallInterval = GetRogueFallInterval(); currentFallInterval = GetRogueFallInterval();
@@ -855,7 +893,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
!suspendFlag && !suspendFlag &&
!gameOverFlag) !gameOverFlag)
{ {
if (currentMode == MODE_ROGUE) if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode())
{ {
int previousFallInterval = currentFallInterval; int previousFallInterval = currentFallInterval;
AdvanceRogueDifficulty(currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL); AdvanceRogueDifficulty(currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL);
@@ -865,7 +903,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
} }
if (currentMode == MODE_ROGUE && rogueStats.timeDilationLevel > 0 && rogueStats.timeDilationTicks <= 0) if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.timeDilationLevel > 0 && rogueStats.timeDilationTicks <= 0)
{ {
int occupiedHeight = 0; int occupiedHeight = 0;
int playableHeight = GetRoguePlayableHeight(); int playableHeight = GetRoguePlayableHeight();
@@ -942,8 +980,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
if (currentScreen != SCREEN_MENU && IsPointInRect(GetBackButtonRect(hWnd), mouseX, mouseY)) if (currentScreen != SCREEN_MENU && IsPointInRect(GetBackButtonRect(hWnd), mouseX, mouseY))
{
if (currentScreen == SCREEN_PLAYING && IsRogueSkillDemoMode())
{
OpenSkillDemoScreen();
}
else if (currentScreen == SCREEN_RULES && helpState.currentPage != 0)
{
helpState.selectedIndex = (helpState.currentPage == 5) ? 3 : helpState.currentPage - 1;
helpState.currentPage = 0;
helpScrollOffset = 0;
}
else
{ {
ReturnToMainMenu(); ReturnToMainMenu();
}
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
break; break;
} }
@@ -990,8 +1041,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
if (IsPointInRect(GetHelpOptionRect(hWnd, i), mouseX, mouseY)) if (IsPointInRect(GetHelpOptionRect(hWnd, i), mouseX, mouseY))
{ {
helpState.selectedIndex = i; helpState.selectedIndex = i;
if (i == 3)
{
helpState.currentPage = 5;
helpState.selectedIndex = 0;
helpScrollOffset = 0;
}
else
{
helpState.currentPage = i + 1; helpState.currentPage = i + 1;
helpScrollOffset = 0; helpScrollOffset = 0;
}
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
break; break;
} }
@@ -1002,17 +1062,36 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
} }
else if (IsPointInRect(GetHelpBackHintRect(hWnd), mouseX, mouseY)) else if (helpState.currentPage == 5)
{ {
if (helpState.currentPage == 4) if (IsPointInRect(GetHelpBackHintRect(hWnd), mouseX, mouseY))
{ {
ReturnToMainMenu(); helpState.currentPage = 0;
helpState.selectedIndex = 3;
helpScrollOffset = 0;
InvalidateRect(hWnd, nullptr, FALSE);
} }
else 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))
{
helpState.selectedIndex = (helpState.currentPage == 5) ? 3 : helpState.currentPage - 1;
helpState.currentPage = 0; helpState.currentPage = 0;
helpScrollOffset = 0; helpScrollOffset = 0;
}
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
else if (helpState.currentPage == 4 && IsPointInRect(GetCreditArrowRect(hWnd, -1), mouseX, mouseY)) else if (helpState.currentPage == 4 && IsPointInRect(GetCreditArrowRect(hWnd, -1), mouseX, mouseY))
@@ -1235,6 +1314,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:
@@ -1254,13 +1346,42 @@ 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:
if (helpState.currentPage == 0) if (helpState.currentPage == 0)
{
if (helpState.selectedIndex == 3)
{
helpState.currentPage = 5;
helpState.selectedIndex = 0;
helpScrollOffset = 0;
}
else
{ {
helpState.currentPage = helpState.selectedIndex + 1; helpState.currentPage = helpState.selectedIndex + 1;
helpScrollOffset = 0; helpScrollOffset = 0;
}
InvalidateRect(hWnd, nullptr, FALSE);
}
else if (helpState.currentPage == 5)
{
StartRogueSkillDemoAt(helpState.selectedIndex);
ResetGameTimer(hWnd);
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
break; break;
@@ -1273,7 +1394,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
else if (helpState.currentPage == 4) else if (helpState.currentPage == 4)
{ {
ReturnToMainMenu(); helpState.currentPage = 0;
helpState.selectedIndex = 3;
helpScrollOffset = 0;
}
else if (helpState.currentPage == 5)
{
helpState.currentPage = 0;
helpState.selectedIndex = 3;
helpScrollOffset = 0;
} }
else else
{ {
@@ -1388,20 +1517,47 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
} }
break; break;
case 'M':
ReturnToMainMenu();
InvalidateRect(hWnd, nullptr, FALSE);
break;
default: default:
break; break;
} }
break; break;
} }
if (wParam == 'M') if (IsRogueSkillDemoMode())
{
if (wParam == 'N')
{
AdvanceRogueSkillDemo();
InvalidateRect(hWnd, nullptr, FALSE);
break;
}
else if (wParam == 'R')
{
RestartCurrentRogueSkillDemo();
ResetGameTimer(hWnd);
InvalidateRect(hWnd, nullptr, FALSE);
break;
}
else if (wParam == VK_ESCAPE || wParam == VK_BACK || wParam == 'M')
{
OpenSkillDemoScreen();
InvalidateRect(hWnd, nullptr, FALSE);
break;
}
}
if (!IsRogueSkillDemoMode() && wParam == 'M')
{ {
ReturnToMainMenu(); ReturnToMainMenu();
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
break; break;
} }
if (wParam == 'R') if (!IsRogueSkillDemoMode() && wParam == 'R')
{ {
StartGameWithMode(currentMode); StartGameWithMode(currentMode);
ResetGameTimer(hWnd); ResetGameTimer(hWnd);
@@ -1409,7 +1565,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break; break;
} }
if (wParam == 'P') if (!IsRogueSkillDemoMode() && wParam == 'P')
{ {
suspendFlag = !suspendFlag; suspendFlag = !suspendFlag;
InvalidateRect(hWnd, nullptr, FALSE); InvalidateRect(hWnd, nullptr, FALSE);
+3 -11
View File
@@ -10,11 +10,12 @@ bool gameOverFlag = false;
bool suspendFlag = false; bool suspendFlag = false;
bool targetFlag = false; bool targetFlag = false;
bool reviveAvailable = false; bool reviveAvailable = false;
bool rogueDemoMode = false;
int workRegion[20][10] = { 0 }; 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;
@@ -28,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;
@@ -465,7 +467,6 @@ void Fixing()
voidClearedCount = TriggerMiniBlackHole(5); voidClearedCount = TriggerMiniBlackHole(5);
AwardRogueSkillClearRewards(voidClearedCount, voidScore, voidExp, false); AwardRogueSkillClearRewards(voidClearedCount, voidScore, voidExp, false);
} }
ApplyBoardGravity();
} }
TCHAR rainbowDetail[128]; TCHAR rainbowDetail[128];
@@ -544,7 +545,6 @@ void Fixing()
if (currentMode == MODE_ROGUE && explosiveCellsCleared > 0) if (currentMode == MODE_ROGUE && explosiveCellsCleared > 0)
{ {
AwardRogueSkillClearRewards(explosiveCellsCleared, explosiveScoreGain, explosiveExpGain, false); AwardRogueSkillClearRewards(explosiveCellsCleared, explosiveScoreGain, explosiveExpGain, false);
ApplyBoardGravity();
} }
TCHAR explosiveDetail[128]; TCHAR explosiveDetail[128];
@@ -590,7 +590,6 @@ void Fixing()
int laserScore = 0; int laserScore = 0;
int laserExp = 0; int laserExp = 0;
AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false); AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false);
ApplyBoardGravity();
TCHAR laserDetail[128]; TCHAR laserDetail[128];
_stprintf_s(laserDetail, _T("激光贯穿第 %d 列,清除 %d 格 +%d 分 +%d EXP"), laserColumn + 1, laserCellsCleared, laserScore, laserExp); _stprintf_s(laserDetail, _T("激光贯穿第 %d 列,清除 %d 格 +%d 分 +%d EXP"), laserColumn + 1, laserCellsCleared, laserScore, laserExp);
@@ -644,7 +643,6 @@ void Fixing()
int crossScore = 0; int crossScore = 0;
int crossExp = 0; int crossExp = 0;
AwardRogueSkillClearRewards(totalCrossCleared, crossScore, crossExp, false); AwardRogueSkillClearRewards(totalCrossCleared, crossScore, crossExp, false);
ApplyBoardGravity();
TCHAR crossDetail[128]; TCHAR crossDetail[128];
_stprintf_s(crossDetail, _T("十字冲击第 %d 行 / 第 %d 列,清除 %d 格 +%d 分 +%d EXP"), crossRow + 1, crossColumn + 1, totalCrossCleared, crossScore, crossExp); _stprintf_s(crossDetail, _T("十字冲击第 %d 行 / 第 %d 列,清除 %d 格 +%d 分 +%d EXP"), crossRow + 1, crossColumn + 1, totalCrossCleared, crossScore, crossExp);
@@ -741,11 +739,6 @@ int DeleteLines()
} }
ApplyLineClearResult(clearedLines); ApplyLineClearResult(clearedLines);
if (currentMode == MODE_CLASSIC && clearedLines > 0)
{
ApplyBoardGravity();
}
if (currentScreen == SCREEN_UPGRADE) if (currentScreen == SCREEN_UPGRADE)
{ {
QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines); QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines);
@@ -787,7 +780,6 @@ int DeleteLines()
int followupScore = 0; int followupScore = 0;
int followupExp = 0; int followupExp = 0;
AwardRogueSkillClearRewards(followupCleared, followupScore, followupExp, false); AwardRogueSkillClearRewards(followupCleared, followupScore, followupExp, false);
ApplyBoardGravity();
TCHAR followupDetail[128]; TCHAR followupDetail[128];
_stprintf_s( _stprintf_s(
+83 -5
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 判断指定方块、旋转状态和位置是否可以合法放置。
*/ */
@@ -518,6 +577,7 @@ void ReviveAfterVideo()
*/ */
void StartGameWithMode(int mode) void StartGameWithMode(int mode)
{ {
rogueDemoMode = false;
currentMode = mode; currentMode = mode;
currentScreen = SCREEN_PLAYING; currentScreen = SCREEN_PLAYING;
upgradeListScrollOffset = 0; upgradeListScrollOffset = 0;
@@ -531,6 +591,7 @@ void StartGameWithMode(int mode)
*/ */
void ReturnToMainMenu() void ReturnToMainMenu()
{ {
rogueDemoMode = false;
currentScreen = SCREEN_MENU; currentScreen = SCREEN_MENU;
suspendFlag = false; suspendFlag = false;
gameOverFlag = false; gameOverFlag = false;
@@ -558,10 +619,11 @@ void ReturnToMainMenu()
*/ */
void OpenRulesScreen() void OpenRulesScreen()
{ {
rogueDemoMode = false;
currentScreen = SCREEN_RULES; currentScreen = SCREEN_RULES;
suspendFlag = false; suspendFlag = false;
helpState.selectedIndex = 0; helpState.selectedIndex = 0;
helpState.optionCount = 3; helpState.optionCount = 4;
helpState.currentPage = 0; helpState.currentPage = 0;
helpScrollOffset = 0; helpScrollOffset = 0;
creditPageIndex = 0; creditPageIndex = 0;
@@ -572,12 +634,27 @@ void OpenRulesScreen()
/** /**
* @brief 打开致谢界面并重置致谢页切换状态。 * @brief 打开致谢界面并重置致谢页切换状态。
*/ */
void OpenCreditScreen() void OpenSkillDemoScreen()
{ {
rogueDemoMode = false;
currentScreen = SCREEN_RULES; currentScreen = SCREEN_RULES;
suspendFlag = false; suspendFlag = false;
helpState.selectedIndex = 0; helpState.selectedIndex = 0;
helpState.optionCount = 3; helpState.optionCount = 4;
helpState.currentPage = 5;
helpScrollOffset = 0;
creditPageIndex = 0;
creditAnimationTicks = 0;
creditAnimationDirection = 0;
}
void OpenCreditScreen()
{
rogueDemoMode = false;
currentScreen = SCREEN_RULES;
suspendFlag = false;
helpState.selectedIndex = 0;
helpState.optionCount = 4;
helpState.currentPage = 4; helpState.currentPage = 4;
helpScrollOffset = 0; helpScrollOffset = 0;
creditPageIndex = 0; creditPageIndex = 0;
@@ -590,6 +667,7 @@ void OpenCreditScreen()
*/ */
void ChangeCreditPage(int direction) void ChangeCreditPage(int direction)
{ {
constexpr int creditPageCount = 4;
if (direction == 0) if (direction == 0)
{ {
return; return;
@@ -609,9 +687,9 @@ void ChangeCreditPage(int direction)
if (creditPageIndex < 0) if (creditPageIndex < 0)
{ {
creditPageIndex = 1; creditPageIndex = creditPageCount - 1;
} }
if (creditPageIndex > 1) if (creditPageIndex >= creditPageCount)
{ {
creditPageIndex = 0; creditPageIndex = 0;
} }
+267 -32
View File
@@ -131,11 +131,12 @@ static Bitmap* LoadBackgroundImage()
*/ */
static Bitmap* LoadCreditImage(int index) static Bitmap* LoadCreditImage(int index)
{ {
constexpr int creditPageCount = 4;
static ULONG_PTR gdiplusToken = 0; static ULONG_PTR gdiplusToken = 0;
static Bitmap* creditImages[2] = {}; static Bitmap* creditImages[creditPageCount] = {};
static bool attempted[2] = {}; static bool attempted[creditPageCount] = {};
if (index < 0 || index >= 2) if (index < 0 || index >= creditPageCount)
{ {
return nullptr; return nullptr;
} }
@@ -147,19 +148,29 @@ static Bitmap* LoadCreditImage(int index)
GdiplusStartupInput startupInput; GdiplusStartupInput startupInput;
if (GdiplusStartup(&gdiplusToken, &startupInput, nullptr) == Ok) if (GdiplusStartup(&gdiplusToken, &startupInput, nullptr) == Ok)
{ {
const wchar_t* imageNames[2] = const wchar_t* imageNames[creditPageCount] =
{ {
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\\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;
@@ -637,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);
@@ -656,17 +671,19 @@ void TDrawScreen(HDC hdc, HWND hWnd)
if (helpState.currentPage == 0) if (helpState.currentPage == 0)
{ {
const TCHAR* optionTitles[3] = const TCHAR* optionTitles[4] =
{ {
_T("\u6e38\u620f\u4ecb\u7ecd"), _T("\u6e38\u620f\u4ecb\u7ecd"),
_T("\u64cd\u4f5c\u8bf4\u660e"), _T("\u64cd\u4f5c\u8bf4\u660e"),
_T("\u5f3a\u5316\u56fe\u9274") _T("\u5f3a\u5316\u56fe\u9274"),
_T("\u6280\u80fd\u6f14\u793a")
}; };
const TCHAR* optionDetails[3] = const TCHAR* optionDetails[4] =
{ {
_T("\u7ecf\u5178\u6a21\u5f0f\u3001Rogue \u6a21\u5f0f\u548c\u590d\u6d3b\u89c4\u5219\u6982\u89c8\u3002"), _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("\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") _T("\u67e5\u770b Rogue \u6a21\u5f0f\u5168\u90e8\u5f3a\u5316\u7684\u7b80\u8981\u6548\u679c\u3002"),
_T("\u9009\u62e9\u4e00\u4e2a\u9884\u8bbe\u573a\u666f\uff0c\u4eb2\u81ea\u64cd\u4f5c\u89e6\u53d1 Rogue \u6280\u80fd\u6548\u679c\u3002")
}; };
int optionHeight = SS(100); int optionHeight = SS(100);
@@ -765,8 +782,8 @@ void TDrawScreen(HDC hdc, HWND hWnd)
const TCHAR* categoryTexts[8] = const TCHAR* categoryTexts[8] =
{ {
_T("赏金纹章:所有得分收益提高 20%,可重复叠加,是最直接的分数成长。\r\n成长印记:所有 EXP 收益提高 25%,可重复叠加,用来更快进入后续构筑。\r\n缓坠羽翼:降低自然下落速度,最多叠加 4 次。\r\n连击律动:连续消行时追加得分和 EXP,断连后重新累计。\r\n先见之眼:额外显示 1 个后续方块;第三个预览由操控大师解锁。"), _T("赏金纹章:所有得分收益提高 20%,可重复叠加,是最直接的分数成长。\r\n成长印记:所有 EXP 收益提高 25%,可重复叠加,用来更快进入后续构筑。\r\n缓坠羽翼:降低自然下落速度,最多叠加 4 次。\r\n连击律动:连续消行时追加得分和 EXP,断连后重新累计。\r\n先见之眼:额外显示 1 个后续方块;第三个预览由操控大师解锁。"),
_T("最后一搏:首次濒死时自动清理底部 3 行,并保留本局继续机会。\r\n备用仓:解锁 C / Shift,将当前方块放入 Hold 仓或取出备用方块。\r\n完美旋转:旋转被阻挡时尝试左右修正,提高贴墙和缝隙旋转成功率。\r\n时间缓流:堆叠过高时自动减速,给危险局面留出处理时间。\r\n空中换形:按 V 将当前下落方块变成 I 块,次数有限"), _T("最后一搏:首次濒死时自动清理底部 3 行,并保留本局继续机会。\r\n备用仓:解锁 C / Shift,将当前方块放入 Hold 仓或取出备用方块。\r\n完美旋转:旋转被阻挡时尝试左右修正,提高贴墙和缝隙旋转成功率。\r\n时间缓流:堆叠过高时自动减速,给危险局面留出处理时间。\r\n空中换形:可重复补充次数,按 V 将当前下落方块变成 I 块。"),
_T("卸压清场:获得时立刻清除最高的一条占用行,直接降低顶部压力。\r\n底线清道夫:通过消行充能自动清底;每级降低需求,最多 4 级。\r\n清屏炸弹:按 X 主动清理底部 5 行,需要通过消行充能后使用\r\n黑洞奇点:可重复补充次数,按 Z 吞噬当前场上数量最多的一种颜色方块。"), _T("卸压清场:获得时立刻清除最高的一条占用行,直接降低顶部压力。\r\n底线清道夫:通过消行充能自动清底;每级降低需求,最多 4 级。\r\n清屏炸弹:可重复补充数量,按 X 主动清理底部 5 行,消行也会继续充能\r\n黑洞奇点:可重复补充次数,按 Z 吞噬当前场上数量最多的一种颜色方块。"),
_T("爆破核心:一次性解锁橙红边框方块,落地后以落点为中心清除 3x3 区域。\r\n棱镜激光:一次性解锁青色边框方块,按落地中心列清除整列固定方块。\r\n十字方块:一次性解锁绿色边框方块,按落地中心同时清除一行一列。\r\n彩虹方块:一次性解锁紫色边框方块,清中心行主色并把覆盖行染成场上主色。\r\n方块改造:提高指定方块出现概率,目前主要强化 I 块生成。"), _T("爆破核心:一次性解锁橙红边框方块,落地后以落点为中心清除 3x3 区域。\r\n棱镜激光:一次性解锁青色边框方块,按落地中心列清除整列固定方块。\r\n十字方块:一次性解锁绿色边框方块,按落地中心同时清除一行一列。\r\n彩虹方块:一次性解锁紫色边框方块,清中心行主色并把覆盖行染成场上主色。\r\n方块改造:提高指定方块出现概率,目前主要强化 I 块生成。"),
_T("连锁火花:完成消行后追加随机破坏,适合配合稳定堆叠扩大收益。\r\n连环炸弹:强化爆破核心,将爆破范围从 3x3 扩大为 5x5。\r\n雷霆四消:三消或四消后追加雷击,额外清除局部方块。\r\n雷霆棱镜:三消或四消后追加激光清列,强化四消后的清场能力。"), _T("连锁火花:完成消行后追加随机破坏,适合配合稳定堆叠扩大收益。\r\n连环炸弹:强化爆破核心,将爆破范围从 3x3 扩大为 5x5。\r\n雷霆四消:三消或四消后追加雷击,额外清除局部方块。\r\n雷霆棱镜:三消或四消后追加激光清列,强化四消后的清场能力。"),
_T("狂热节拍:累计清除 12 行进入狂热,狂热期间收益更高。\r\n怒火连段:连击越高倍率越高,适合连续小消和稳定节奏。\r\n无尽狂热:狂热期间继续消行会延长狂热时间。\r\n高压悬赏:游戏速度更快,但高压下收益也更高。\r\n豪赌四消:四消收益更高,但非四消表现更不稳定。\r\n极限玩家:危险高度下获得更高收益,同时承担更高操作压力。\r\n赌徒契约:后续强化有概率翻倍或落空,每级提高概率,最多 4 级。"), _T("狂热节拍:累计清除 12 行进入狂热,狂热期间收益更高。\r\n怒火连段:连击越高倍率越高,适合连续小消和稳定节奏。\r\n无尽狂热:狂热期间继续消行会延长狂热时间。\r\n高压悬赏:游戏速度更快,但高压下收益也更高。\r\n豪赌四消:四消收益更高,但非四消表现更不稳定。\r\n极限玩家:危险高度下获得更高收益,同时承担更高操作压力。\r\n赌徒契约:后续强化有概率翻倍或落空,每级提高概率,最多 4 级。"),
@@ -876,18 +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;
const TCHAR* creditNames[2] = constexpr int creditPageCount = 4;
const TCHAR* creditNames[creditPageCount] =
{ {
_T("qls"), _T("qls"),
_T("wyk") _T("wyk"),
_T("juju"),
_T("qhy")
}; };
const TCHAR* creditTexts[2] = 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\u8c22qhy\u7684\u5929\u624d\u6784\u60f3")
}; };
int currentCredit = creditPageIndex; int currentCredit = creditPageIndex;
@@ -895,17 +1002,17 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{ {
currentCredit = 0; currentCredit = 0;
} }
if (currentCredit > 1) if (currentCredit >= creditPageCount)
{ {
currentCredit = 1; currentCredit = creditPageCount - 1;
} }
int previousCredit = currentCredit - creditAnimationDirection; int previousCredit = currentCredit - creditAnimationDirection;
if (previousCredit < 0) if (previousCredit < 0)
{ {
previousCredit = 1; previousCredit = creditPageCount - 1;
} }
if (previousCredit > 1) if (previousCredit >= creditPageCount)
{ {
previousCredit = 0; previousCredit = 0;
} }
@@ -939,8 +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++)
{
preloadedCreditImages[i] = LoadCreditImage(i);
}
Graphics creditGraphics(hdc); Graphics creditGraphics(hdc);
creditGraphics.SetInterpolationMode(InterpolationModeHighQualityBilinear); creditGraphics.SetInterpolationMode(InterpolationModeHighQualityBilinear);
@@ -951,7 +1061,11 @@ void TDrawScreen(HDC hdc, HWND hWnd)
OffsetRect(&shiftedImageArea, offset, 0); OffsetRect(&shiftedImageArea, offset, 0);
OffsetRect(&shiftedTextArea, offset, 0); OffsetRect(&shiftedTextArea, offset, 0);
Bitmap* creditImage = (cardIndex == 0) ? preloadedCreditImageA : preloadedCreditImageB; Bitmap* creditImage = nullptr;
if (cardIndex >= 0 && cardIndex < creditPageCount)
{
creditImage = preloadedCreditImages[cardIndex];
}
if (creditImage != nullptr) if (creditImage != nullptr)
{ {
int imageWidth = static_cast<int>(creditImage->GetWidth()); int imageWidth = static_cast<int>(creditImage->GetWidth());
@@ -1067,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);
@@ -1117,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 \u8fdb\u5165\u64cd\u4f5c\u573a\u666f\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);
@@ -1357,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;
@@ -1545,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);
@@ -1654,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)
}; };
@@ -1758,7 +1978,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
} }
if (rogueStats.screenBombLevel > 0) if (rogueStats.screenBombLevel > 0)
{ {
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6e05\u5c4f\u70b8\u5f39 Lv.1\r\n")); _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u6e05\u5c4f\u70b8\u5f39 Lv.%d \u5269\u4f59 %d \u679a\r\n"), rogueStats.screenBombLevel, rogueStats.screenBombCount);
} }
if (rogueStats.terminalClearLevel > 0) if (rogueStats.terminalClearLevel > 0)
{ {
@@ -1810,7 +2030,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
} }
if (rogueStats.reshapeLevel > 0) if (rogueStats.reshapeLevel > 0)
{ {
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a7a\u4e2d\u6362\u5f62 Lv.1\r\n")); _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a7a\u4e2d\u6362\u5f62 Lv.%d \u5269\u4f59 %d \u6b21\r\n"), rogueStats.reshapeLevel, rogueStats.reshapeCharges);
} }
if (rogueStats.rainbowPieceLevel > 0) if (rogueStats.rainbowPieceLevel > 0)
{ {
@@ -2205,6 +2425,20 @@ void TDrawScreen(HDC hdc, HWND hWnd)
controlRect.bottom - SS(22) controlRect.bottom - SS(22)
}; };
if (currentMode == MODE_ROGUE) if (currentMode == MODE_ROGUE)
{
if (IsRogueSkillDemoMode())
{
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("演示:R 重置当前 N 下一个 M 菜单\r\n")
_T("技能:C 备用仓 Z 黑洞 X 炸弹 V 换形"),
-1,
&controlBodyRect,
DT_LEFT | DT_TOP | DT_WORDBREAK);
}
else
{ {
DrawText( DrawText(
hdc, hdc,
@@ -2216,6 +2450,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
&controlBodyRect, &controlBodyRect,
DT_LEFT | DT_TOP | DT_WORDBREAK); DT_LEFT | DT_TOP | DT_WORDBREAK);
} }
}
else else
{ {
DrawText( DrawText(
+822 -12
View File
@@ -73,7 +73,7 @@ static const UpgradeEntry kUpgradePool[] =
{ UPGRADE_FEVER_MODE, 1, 92, false, _T("狂热节拍"), _T("进阶"), _T("累计消行 12 行后进入 12 秒狂热:得分与 EXP 翻倍。") }, { UPGRADE_FEVER_MODE, 1, 92, false, _T("狂热节拍"), _T("进阶"), _T("累计消行 12 行后进入 12 秒狂热:得分与 EXP 翻倍。") },
{ UPGRADE_RAGE_STACK, 1, 84, false, _T("怒火连段"), _T("进阶"), _T("连续消行越多,得分倍率追加越高。") }, { UPGRADE_RAGE_STACK, 1, 84, false, _T("怒火连段"), _T("进阶"), _T("连续消行越多,得分倍率追加越高。") },
{ UPGRADE_INFINITE_FEVER, 1, 110, false, _T("无尽狂热"), _T("进化"), _T("狂热期间消行可延长狂热时间;连击越高,倍率越凶。") }, { UPGRADE_INFINITE_FEVER, 1, 110, false, _T("无尽狂热"), _T("进化"), _T("狂热期间消行可延长狂热时间;连击越高,倍率越凶。") },
{ UPGRADE_SCREEN_BOMB, 1, 90, false, _T("清屏炸弹"), _T("进阶"), _T("立刻获得 1 枚炸弹;之后累计消行 16 行再获得 1 枚。按 X 清底 5 行。") }, { UPGRADE_SCREEN_BOMB, -1, 90, true, _T("清屏炸弹"), _T("进阶"), _T("立刻获得 1 枚炸弹;可重复选择补充数量,之后累计消行 16 行再获得 1 枚。按 X 清底 5 行。") },
{ UPGRADE_TERMINAL_CLEAR, 1, 108, false, _T("终末清场"), _T("进化"), _T("最后一搏启动时,自动引爆 1 枚清屏炸弹,并进入 10 秒狂热。") }, { UPGRADE_TERMINAL_CLEAR, 1, 108, false, _T("终末清场"), _T("进化"), _T("最后一搏启动时,自动引爆 1 枚清屏炸弹,并进入 10 秒狂热。") },
{ UPGRADE_DUAL_CHOICE, 1, 68, false, _T("双重抉择"), _T("进阶"), _T("每次升级可额外选择 1 个强化,但下一次升级所需 EXP +30%。") }, { UPGRADE_DUAL_CHOICE, 1, 68, false, _T("双重抉择"), _T("进阶"), _T("每次升级可额外选择 1 个强化,但下一次升级所需 EXP +30%。") },
{ UPGRADE_DESTINY_WHEEL, 1, 104, false, _T("命运轮盘"), _T("进化"), _T("升级时出现 6 个选项,可选择 2 个;其中 1 个会携带诅咒。") }, { UPGRADE_DESTINY_WHEEL, 1, 104, false, _T("命运轮盘"), _T("进化"), _T("升级时出现 6 个选项,可选择 2 个;其中 1 个会携带诅咒。") },
@@ -88,7 +88,7 @@ static const UpgradeEntry kUpgradePool[] =
{ UPGRADE_BLOCK_STORM, 1, 82, false, _T("方块风暴"), _T("爆发"), _T("接下来 5 个方块全部变为 I 块,快速制造四消机会。") }, { UPGRADE_BLOCK_STORM, 1, 82, false, _T("方块风暴"), _T("爆发"), _T("接下来 5 个方块全部变为 I 块,快速制造四消机会。") },
{ UPGRADE_CROSS_PIECE, 1, 84, false, _T("十字方块"), _T("爆发"), _T("解锁十字方块生成。十字方块落地后清除所在行与所在列。") }, { UPGRADE_CROSS_PIECE, 1, 84, false, _T("十字方块"), _T("爆发"), _T("解锁十字方块生成。十字方块落地后清除所在行与所在列。") },
{ UPGRADE_BLACK_HOLE, -1, 88, true, _T("黑洞奇点"), _T("特殊"), _T("获得 2 次黑洞。可重复选择继续补充次数;按 Z 吞噬棋盘上数量最多的一种固定方块。") }, { UPGRADE_BLACK_HOLE, -1, 88, true, _T("黑洞奇点"), _T("特殊"), _T("获得 2 次黑洞。可重复选择继续补充次数;按 Z 吞噬棋盘上数量最多的一种固定方块。") },
{ UPGRADE_AIR_RESHAPE, 1, 82, false, _T("空中换形"), _T("操作"), _T("获得 2 次换形。按 V 将正在下落的方块重塑为 I 块。") }, { UPGRADE_AIR_RESHAPE, -1, 82, true, _T("空中换形"), _T("操作"), _T("获得 2 次换形。可重复选择继续补充次数;按 V 将正在下落的方块重塑为 I 块。") },
{ UPGRADE_RAINBOW_PIECE, 1, 84, false, _T("彩虹方块"), _T("爆发"), _T("解锁彩虹方块生成。落地后清中心行主色,并把覆盖行染成场上主色。") }, { UPGRADE_RAINBOW_PIECE, 1, 84, false, _T("彩虹方块"), _T("爆发"), _T("解锁彩虹方块生成。落地后清中心行主色,并把覆盖行染成场上主色。") },
{ UPGRADE_VOID_CORE, 1, 112, false, _T("虚空核心"), _T("进化"), _T("黑洞后额外生成 1 个彩虹方块;彩虹生效后追加一次小型黑洞。") }, { UPGRADE_VOID_CORE, 1, 112, false, _T("虚空核心"), _T("进化"), _T("黑洞后额外生成 1 个彩虹方块;彩虹生效后追加一次小型黑洞。") },
{ UPGRADE_STABLE_STRUCTURE, -1, 72, true, _T("稳定结构"), _T("特殊"), _T("落地后有小概率填补邻近空洞,让阵型更加稳固。") }, { UPGRADE_STABLE_STRUCTURE, -1, 72, true, _T("稳定结构"), _T("特殊"), _T("落地后有小概率填补邻近空洞,让阵型更加稳固。") },
@@ -109,6 +109,79 @@ static constexpr int kExplosiveBaseInterval = 6;
static constexpr int kExplosiveMinInterval = 3; static constexpr int kExplosiveMinInterval = 3;
static int pendingUpgradeShockwaveRows = 0; static int pendingUpgradeShockwaveRows = 0;
static bool pendingEvolutionImpactShockwave = false; static bool pendingEvolutionImpactShockwave = false;
static int rogueDemoStepIndex = 0;
static int rogueDemoTicks = 0;
static bool rogueDemoAutoAdvance = true;
enum RogueDemoKind
{
DEMO_SCORE_MULTIPLIER = 0,
DEMO_EXP_MULTIPLIER,
DEMO_SLOW_FALL,
DEMO_COMBO_BONUS,
DEMO_PREVIEW_PLUS_ONE,
DEMO_LAST_CHANCE,
DEMO_HOLD,
DEMO_PRESSURE_RELIEF,
DEMO_SWEEPER,
DEMO_EXPLOSIVE,
DEMO_STABLE_STRUCTURE,
DEMO_DOUBLE_GROWTH,
DEMO_PIECE_TUNING,
DEMO_GAMBLER,
DEMO_CHAIN_BLAST,
DEMO_CHAIN_BOMB,
DEMO_LASER,
DEMO_THUNDER_TETRIS,
DEMO_THUNDER_LASER,
DEMO_FEVER_MODE,
DEMO_RAGE_STACK,
DEMO_INFINITE_FEVER,
DEMO_SCREEN_BOMB,
DEMO_TERMINAL_CLEAR,
DEMO_DUAL_CHOICE,
DEMO_DESTINY_WHEEL,
DEMO_PERFECT_ROTATE,
DEMO_TIME_DILATION,
DEMO_HIGH_PRESSURE,
DEMO_TETRIS_GAMBLE,
DEMO_EXTREME_PLAYER,
DEMO_UPGRADE_SHOCKWAVE,
DEMO_EVOLUTION_IMPACT,
DEMO_CONTROL_MASTER,
DEMO_BLOCK_STORM,
DEMO_CROSS,
DEMO_BLACK_HOLE,
DEMO_AIR_RESHAPE,
DEMO_RAINBOW,
DEMO_VOID_CORE
};
struct RogueDemoStep
{
int kind;
const TCHAR* name;
const TCHAR* detail;
};
static const RogueDemoStep kRogueDemoSteps[] =
{
{ DEMO_HOLD, _T("备用仓"), _T("按 C / Shift 换出备用 I 块,再用 Space 填平底行缺口。") },
{ DEMO_BLACK_HOLE, _T("黑洞奇点"), _T("按 Z 吞噬场上最多的粉色方块,观察棋盘变化。") },
{ DEMO_SCREEN_BOMB, _T("清屏炸弹"), _T("按 X 主动引爆,清理底部 5 行高压区。") },
{ DEMO_AIR_RESHAPE, _T("空中换形"), _T("按 V 把当前方块变为 I 块,再用 Space 完成落位。") },
{ DEMO_EXPLOSIVE, _T("爆破核心"), _T("用方向键微调红框方块,Space 落地后清除 3x3 区域。") },
{ DEMO_CHAIN_BOMB, _T("连环炸弹"), _T("Space 落下红框方块,演示更大的连环爆破范围。") },
{ DEMO_LASER, _T("棱镜激光"), _T("把青色边框方块落到中列,落地后贯穿整列。") },
{ DEMO_CROSS, _T("十字方块"), _T("把绿色边框方块落到交叉点,清除一行一列。") },
{ DEMO_RAINBOW, _T("彩虹方块"), _T("把紫色边框方块落到彩色层,按中心行主色触发清除。") },
{ DEMO_VOID_CORE, _T("虚空核心"), _T("按 Z 释放黑洞后,下一枚方块会被召唤成彩虹方块。") },
{ DEMO_UPGRADE_SHOCKWAVE, _T("升级冲击波"), _T("Space 消一行立刻升级,不弹强化菜单并清除底部 2 行。") },
{ DEMO_STABLE_STRUCTURE, _T("稳定结构"), _T("Space 落地后只触发稳定结构,自动填补局部空洞。") }
};
static constexpr int kRogueDemoStepCount = sizeof(kRogueDemoSteps) / sizeof(kRogueDemoSteps[0]);
static constexpr int kRogueDemoStepTicks = 7;
static int GetUpgradeCurrentLevel(int upgradeId); static int GetUpgradeCurrentLevel(int upgradeId);
static bool IsUpgradePrerequisiteConsumed(int upgradeId); static bool IsUpgradePrerequisiteConsumed(int upgradeId);
@@ -136,6 +209,14 @@ static void FillUpgradeOptions();
static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount); static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount);
static void ApplyDestinyCurse(); static void ApplyDestinyCurse();
static void ClearLockedRows(); static void ClearLockedRows();
static void ApplyRogueSkillDemoStep();
static void ResetRogueDemoBoard();
static void ShowRogueDemoFloatingName(const TCHAR* name);
static void FillRogueDemoCell(int y, int x, int value);
static void FillRogueDemoRows(int firstRow, int lastRow, int baseValue);
static void FillRogueDemoRowExcept(int row, int gapStart, int gapWidth, int baseValue);
static void SetRogueDemoCurrentPiece(int pieceType, int pieceState, int x, int y);
static void StartRogueSkillDemoInternal(int demoIndex, bool autoAdvance);
/** /**
* @brief Rogue * @brief Rogue
@@ -211,7 +292,7 @@ static void ClearLockedRows()
*/ */
void AdvanceRogueDifficulty(int elapsedMs) void AdvanceRogueDifficulty(int elapsedMs)
{ {
if (currentMode != MODE_ROGUE || currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag || elapsedMs <= 0) if (currentMode != MODE_ROGUE || rogueDemoMode || currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag || elapsedMs <= 0)
{ {
return; return;
} }
@@ -891,6 +972,25 @@ void RollCurrentPieceSpecialFlags(bool allowRandomSpecials)
return; return;
} }
if (rogueDemoMode)
{
if (currentMode == MODE_ROGUE && rogueStats.pendingRainbowPieceCount > 0)
{
rogueStats.pendingRainbowPieceCount--;
currentPieceIsExplosive = false;
currentPieceIsLaser = false;
currentPieceIsCross = false;
currentPieceIsRainbow = true;
return;
}
currentPieceIsExplosive = false;
currentPieceIsLaser = false;
currentPieceIsCross = false;
currentPieceIsRainbow = false;
return;
}
if (currentMode == MODE_ROGUE && rogueStats.pendingRainbowPieceCount > 0) if (currentMode == MODE_ROGUE && rogueStats.pendingRainbowPieceCount > 0)
{ {
rogueStats.pendingRainbowPieceCount--; rogueStats.pendingRainbowPieceCount--;
@@ -1319,6 +1419,10 @@ int TryStabilizeBoard()
{ {
triggerChance = 70; triggerChance = 70;
} }
if (rogueDemoMode && kRogueDemoSteps[rogueDemoStepIndex].kind == DEMO_STABLE_STRUCTURE)
{
triggerChance = 100;
}
if ((rand() % 100) >= triggerChance) if ((rand() % 100) >= triggerChance)
{ {
@@ -1680,7 +1784,7 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
rogueStats.infiniteFeverLevel = 1; rogueStats.infiniteFeverLevel = 1;
break; break;
case UPGRADE_SCREEN_BOMB: case UPGRADE_SCREEN_BOMB:
rogueStats.screenBombLevel = 1; rogueStats.screenBombLevel += applyCount;
rogueStats.screenBombCount += applyCount; rogueStats.screenBombCount += applyCount;
break; break;
case UPGRADE_TERMINAL_CLEAR: case UPGRADE_TERMINAL_CLEAR:
@@ -1748,7 +1852,7 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
rogueStats.blackHoleCharges += 2 * applyCount; rogueStats.blackHoleCharges += 2 * applyCount;
break; break;
case UPGRADE_AIR_RESHAPE: case UPGRADE_AIR_RESHAPE:
rogueStats.reshapeLevel = 1; rogueStats.reshapeLevel += applyCount;
rogueStats.reshapeCharges += 2 * applyCount; rogueStats.reshapeCharges += 2 * applyCount;
break; break;
case UPGRADE_RAINBOW_PIECE: case UPGRADE_RAINBOW_PIECE:
@@ -1831,7 +1935,7 @@ void AwardRogueSkillClearRewards(int clearedCells, int& scoreGain, int& expGain,
} }
} }
if (allowLevelProgress) if (allowLevelProgress && !rogueDemoMode)
{ {
int levelUps = ApplyLevelProgress(rogueStats); int levelUps = ApplyLevelProgress(rogueStats);
if (levelUps > 0) if (levelUps > 0)
@@ -1851,6 +1955,10 @@ void CheckRogueLevelProgress()
{ {
return; return;
} }
if (rogueDemoMode)
{
return;
}
int levelUps = ApplyLevelProgress(rogueStats); int levelUps = ApplyLevelProgress(rogueStats);
if (levelUps <= 0) if (levelUps <= 0)
@@ -1908,6 +2016,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--;
} }
} }
@@ -2064,7 +2176,6 @@ void ApplyLineClearResult(int linesCleared)
int chainBlastScore = 0; int chainBlastScore = 0;
int chainBlastExp = 0; int chainBlastExp = 0;
AwardRogueSkillClearRewards(chainBlastCells, chainBlastScore, chainBlastExp, false); AwardRogueSkillClearRewards(chainBlastCells, chainBlastScore, chainBlastExp, false);
ApplyBoardGravity();
TCHAR blastDetail[128]; TCHAR blastDetail[128];
_stprintf_s( _stprintf_s(
@@ -2105,7 +2216,6 @@ void ApplyLineClearResult(int linesCleared)
int thunderScore = 0; int thunderScore = 0;
int thunderExp = 0; int thunderExp = 0;
AwardRogueSkillClearRewards(thunderRowsCleared, thunderScore, thunderExp, false); AwardRogueSkillClearRewards(thunderRowsCleared, thunderScore, thunderExp, false);
ApplyBoardGravity();
SetFeedbackMessage(_T("雷霆四消"), _T("雷击落下,额外清理了 2 行范围内的方块。"), 12); SetFeedbackMessage(_T("雷霆四消"), _T("雷击落下,额外清理了 2 行范围内的方块。"), 12);
} }
} }
@@ -2123,7 +2233,6 @@ void ApplyLineClearResult(int linesCleared)
int laserScore = 0; int laserScore = 0;
int laserExp = 0; int laserExp = 0;
AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false); AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false);
ApplyBoardGravity();
TCHAR thunderLaserDetail[128]; TCHAR thunderLaserDetail[128];
_stprintf_s( _stprintf_s(
@@ -2163,7 +2272,6 @@ void ApplyLineClearResult(int linesCleared)
} }
int levelUps = ApplyLevelProgress(rogueStats); int levelUps = ApplyLevelProgress(rogueStats);
upgradeUiState.pendingCount += levelUps;
tScore = rogueStats.score; tScore = rogueStats.score;
if (levelUps > 0) if (levelUps > 0)
@@ -2189,16 +2297,35 @@ void ApplyLineClearResult(int linesCleared)
TCHAR feedbackTitle[64]; TCHAR feedbackTitle[64];
TCHAR feedbackDetail[128]; TCHAR feedbackDetail[128];
_stprintf_s(feedbackTitle, _T("灵感涌现 x%d"), levelUps); _stprintf_s(feedbackTitle, _T("灵感涌现 x%d"), levelUps);
if (rogueDemoMode)
{
_stprintf_s(
feedbackDetail,
_T("演示升级 Lv.%d,普通强化菜单已关闭。"),
rogueStats.level);
}
else
{
_stprintf_s( _stprintf_s(
feedbackDetail, feedbackDetail,
_T("等级 Lv.%d EXP %d/%d 选择新的强化"), _T("等级 Lv.%d EXP %d/%d 选择新的强化"),
rogueStats.level, rogueStats.level,
rogueStats.exp, rogueStats.exp,
rogueStats.requiredExp); rogueStats.requiredExp);
}
SetFeedbackMessage(feedbackTitle, feedbackDetail, 10); SetFeedbackMessage(feedbackTitle, feedbackDetail, 10);
if (rogueDemoMode)
{
ResolvePendingUpgradeShockwave();
PlayPendingLineClearEffect();
}
else
{
upgradeUiState.pendingCount += levelUps;
OpenUpgradeMenu(); OpenUpgradeMenu();
} }
}
currentFallInterval = GetRogueFallInterval(); currentFallInterval = GetRogueFallInterval();
} }
@@ -2560,7 +2687,6 @@ void UseScreenBomb()
rogueStats.screenBombCount--; rogueStats.screenBombCount--;
int clearedCells = TriggerScreenBomb(); int clearedCells = TriggerScreenBomb();
ApplyBoardGravity();
int scoreGain = 0; int scoreGain = 0;
int expGain = 0; int expGain = 0;
AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true); AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true);
@@ -2607,7 +2733,6 @@ void UseBlackHole()
rogueStats.blackHoleCharges--; rogueStats.blackHoleCharges--;
ApplyBoardGravity();
int scoreGain = 0; int scoreGain = 0;
int expGain = 0; int expGain = 0;
AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true); AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true);
@@ -2705,3 +2830,688 @@ void UseAirReshape()
SetFeedbackMessage(_T("空中换形"), detail, 12); SetFeedbackMessage(_T("空中换形"), detail, 12);
ComputeTarget(); ComputeTarget();
} }
/**
* @brief Rogue
*/
bool IsRogueSkillDemoMode()
{
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
*/
void StartRogueSkillDemo()
{
StartRogueSkillDemoInternal(0, false);
}
/**
* @brief Rogue
*/
void StartRogueSkillDemoAt(int demoIndex)
{
StartRogueSkillDemoInternal(demoIndex, false);
}
/**
* @brief Rogue
*/
void RestartCurrentRogueSkillDemo()
{
if (!rogueDemoMode)
{
StartRogueSkillDemoAt(0);
return;
}
StartRogueSkillDemoInternal(rogueDemoStepIndex, false);
}
/**
* @brief Rogue
*/
static void StartRogueSkillDemoInternal(int demoIndex, bool autoAdvance)
{
if (demoIndex < 0)
{
demoIndex = 0;
}
if (demoIndex >= kRogueDemoStepCount)
{
demoIndex = kRogueDemoStepCount - 1;
}
currentMode = MODE_ROGUE;
currentScreen = SCREEN_PLAYING;
rogueDemoMode = true;
rogueDemoStepIndex = demoIndex;
rogueDemoTicks = 0;
rogueDemoAutoAdvance = autoAdvance;
Restart();
rogueDemoMode = true;
reviveAvailable = false;
suspendFlag = false;
gameOverFlag = false;
targetFlag = true;
upgradeListScrollOffset = 0;
currentFallInterval = 500;
ApplyRogueSkillDemoStep();
}
/**
* @brief Rogue
*/
bool TickRogueSkillDemo()
{
if (!rogueDemoMode)
{
return false;
}
if (rogueDemoAutoAdvance)
{
rogueDemoTicks++;
if (rogueDemoTicks >= kRogueDemoStepTicks)
{
AdvanceRogueSkillDemo();
}
}
return true;
}
/**
* @brief Rogue
*/
void AdvanceRogueSkillDemo()
{
if (!rogueDemoMode)
{
return;
}
rogueDemoStepIndex++;
if (rogueDemoStepIndex >= kRogueDemoStepCount)
{
rogueDemoStepIndex = 0;
}
rogueDemoTicks = 0;
ApplyRogueSkillDemoStep();
}
/**
* @brief
*/
static void ResetRogueDemoBoard()
{
for (int y = 0; y < nGameHeight; y++)
{
for (int x = 0; x < nGameWidth; x++)
{
workRegion[y][x] = 0;
}
}
ResetPlayerStats(rogueStats, true);
ResetUpgradeUiState();
ResetPendingRogueVisualEvents();
ResetVisualEffects();
pendingLineClearEffectTicks = 0;
pendingLineClearEffectRowCount = 0;
pendingLineClearEffectLineCount = 0;
clearEffectState.ticks = 0;
currentPieceIsExplosive = false;
currentPieceIsLaser = false;
currentPieceIsCross = false;
currentPieceIsRainbow = false;
holdType = -1;
holdUsedThisTurn = false;
tScore = 0;
currentScreen = SCREEN_PLAYING;
currentMode = MODE_ROGUE;
gameOverFlag = false;
suspendFlag = false;
reviveAvailable = false;
currentFallInterval = 500;
ResetNextQueue();
SetRogueDemoCurrentPiece(1, 0, 3, 0);
}
/**
* @brief
*/
static void ShowRogueDemoFloatingName(const TCHAR* name)
{
floatingTextEffects[0].ticks = 70;
floatingTextEffects[0].totalTicks = 70;
floatingTextEffects[0].boardX = 500;
floatingTextEffects[0].boardY = 1000;
floatingTextEffects[0].color = RGB(255, 248, 250);
lstrcpyn(floatingTextEffects[0].text, name, sizeof(floatingTextEffects[0].text) / sizeof(TCHAR));
}
/**
* @brief
*/
static void FillRogueDemoCell(int y, int x, int value)
{
if (y < 0 || y >= nGameHeight || x < 0 || x >= nGameWidth)
{
return;
}
workRegion[y][x] = value;
}
/**
* @brief
*/
static void FillRogueDemoRows(int firstRow, int lastRow, int baseValue)
{
if (firstRow < 0)
{
firstRow = 0;
}
if (lastRow >= nGameHeight)
{
lastRow = nGameHeight - 1;
}
for (int y = firstRow; y <= lastRow; y++)
{
int gapX = (baseValue + y) % nGameWidth;
for (int x = 0; x < nGameWidth; x++)
{
if (x == gapX)
{
workRegion[y][x] = 0;
}
else
{
workRegion[y][x] = 1 + ((baseValue + y + x) % 7);
}
}
}
}
/**
* @brief
*/
static void FillRogueDemoRowExcept(int row, int gapStart, int gapWidth, int baseValue)
{
if (row < 0 || row >= nGameHeight)
{
return;
}
for (int x = 0; x < nGameWidth; x++)
{
if (x >= gapStart && x < gapStart + gapWidth)
{
workRegion[row][x] = 0;
}
else
{
workRegion[row][x] = 1 + ((baseValue + row + x) % 7);
}
}
}
/**
* @brief
*/
static void SetRogueDemoCurrentPiece(int pieceType, int pieceState, int x, int y)
{
type = pieceType;
nType = 0;
state = pieceState;
point.x = x;
point.y = y;
target = point;
nextTypes[0] = 0;
nextTypes[1] = 0;
nextTypes[2] = 0;
ComputeTarget();
}
/**
* @brief Rogue
*/
static void ApplyRogueSkillDemoStep()
{
ResetRogueDemoBoard();
const RogueDemoStep& demoStep = kRogueDemoSteps[rogueDemoStepIndex];
ShowRogueDemoFloatingName(demoStep.name);
SetFeedbackMessage(demoStep.name, demoStep.detail, 12);
switch (demoStep.kind)
{
case DEMO_SCORE_MULTIPLIER:
rogueStats.scoreUpgradeLevel = 2;
rogueStats.scoreMultiplierPercent = 160;
FillRogueDemoRows(16, 18, 1);
FillRogueDemoRowExcept(19, 3, 4, 1);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_EXP_MULTIPLIER:
rogueStats.expUpgradeLevel = 2;
rogueStats.expMultiplierPercent = 150;
FillRogueDemoRows(16, 18, 2);
FillRogueDemoRowExcept(19, 3, 4, 2);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_SLOW_FALL:
rogueStats.slowFallStacks = 4;
currentFallInterval = GetRogueFallInterval();
FillRogueDemoRows(16, 19, 3);
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_COMBO_BONUS:
rogueStats.comboBonusStacks = 2;
rogueStats.comboChain = 1;
FillRogueDemoRows(16, 18, 4);
FillRogueDemoRowExcept(19, 3, 4, 4);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_PREVIEW_PLUS_ONE:
rogueStats.previewCount = 2;
rogueStats.previewUpgradeLevel = 1;
FillRogueDemoRows(16, 19, 5);
SetRogueDemoCurrentPiece(4, 0, 4, 0);
nextTypes[0] = 0;
nextTypes[1] = 1;
nextTypes[2] = 2;
break;
case DEMO_LAST_CHANCE:
rogueStats.lastChanceUpgradeLevel = 1;
rogueStats.lastChanceCount = 1;
FillRogueDemoRows(0, 5, 5);
FillRogueDemoRows(14, 19, 3);
SetRogueDemoCurrentPiece(4, 0, 3, -1);
break;
case DEMO_HOLD:
rogueStats.holdUnlocked = 1;
rogueStats.controlMasterLevel = 1;
holdType = 0;
FillRogueDemoRows(16, 18, 1);
FillRogueDemoRowExcept(19, 3, 4, 1);
SetRogueDemoCurrentPiece(2, 0, 3, 0);
break;
case DEMO_PRESSURE_RELIEF:
rogueStats.pressureReliefLevel = 1;
FillRogueDemoRows(5, 19, 6);
DeleteOneLine(5);
SetRogueDemoCurrentPiece(1, 0, 3, 0);
SetFeedbackMessage(_T("卸压清场"), _T("最高占用行已被清除,顶部压力立即下降。"), 12);
break;
case DEMO_SWEEPER:
rogueStats.sweeperLevel = 4;
FillRogueDemoRows(15, 18, 1);
FillRogueDemoRowExcept(19, 3, 4, 3);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_EXPLOSIVE:
FillRogueDemoRows(12, 19, 1);
FillRogueDemoCell(14, 4, 0);
FillRogueDemoCell(15, 5, 0);
FillRogueDemoCell(16, 4, 0);
currentPieceIsExplosive = true;
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_STABLE_STRUCTURE:
rogueStats.stableStructureLevel = 4;
FillRogueDemoRows(14, 19, 1);
workRegion[15][4] = 0;
workRegion[16][6] = 0;
workRegion[17][5] = 0;
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_DOUBLE_GROWTH:
rogueStats.doubleGrowthLevel = 1;
rogueStats.scoreMultiplierPercent = 115;
rogueStats.expMultiplierPercent = 115;
FillRogueDemoRows(16, 18, 2);
FillRogueDemoRowExcept(19, 3, 4, 2);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_PIECE_TUNING:
rogueStats.pieceTuningLevels[0] = 4;
FillRogueDemoRows(16, 19, 3);
SetRogueDemoCurrentPiece(0, 1, 3, 0);
nextTypes[0] = 0;
nextTypes[1] = 0;
nextTypes[2] = 0;
break;
case DEMO_GAMBLER:
rogueStats.gamblerLevel = 4;
FillRogueDemoRows(16, 18, 4);
FillRogueDemoRowExcept(19, 3, 4, 4);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_CHAIN_BLAST:
rogueStats.chainBlastLevel = 1;
FillRogueDemoRows(15, 18, 5);
FillRogueDemoRowExcept(19, 3, 4, 5);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_CHAIN_BOMB:
rogueStats.chainBombLevel = 1;
FillRogueDemoRows(10, 19, 4);
for (int y = 13; y <= 17; y++)
{
FillRogueDemoCell(y, 3, 0);
FillRogueDemoCell(y, 6, 0);
}
currentPieceIsExplosive = true;
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_LASER:
for (int y = 4; y < nGameHeight; y++)
{
FillRogueDemoCell(y, 5, 4);
if (y >= 12)
{
FillRogueDemoCell(y, 3, 2);
FillRogueDemoCell(y, 7, 6);
}
}
currentPieceIsLaser = true;
SetRogueDemoCurrentPiece(0, 1, 3, 0);
break;
case DEMO_THUNDER_TETRIS:
rogueStats.thunderTetrisLevel = 1;
FillRogueDemoRows(10, 15, 1);
FillRogueDemoRows(16, 18, 2);
FillRogueDemoRowExcept(19, 3, 4, 2);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_THUNDER_LASER:
rogueStats.thunderLaserLevel = 1;
FillRogueDemoRows(10, 15, 3);
FillRogueDemoRows(16, 18, 4);
FillRogueDemoRowExcept(19, 3, 4, 4);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_FEVER_MODE:
rogueStats.feverLevel = 1;
rogueStats.feverLineCharge = kFeverLineThreshold - 1;
FillRogueDemoRows(16, 18, 5);
FillRogueDemoRowExcept(19, 3, 4, 5);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_RAGE_STACK:
rogueStats.rageStackLevel = 1;
rogueStats.comboChain = 3;
FillRogueDemoRows(16, 18, 6);
FillRogueDemoRowExcept(19, 3, 4, 6);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_INFINITE_FEVER:
rogueStats.feverLevel = 1;
rogueStats.infiniteFeverLevel = 1;
rogueStats.feverTicks = 8;
currentFallInterval = GetRogueFallInterval();
FillRogueDemoRows(16, 18, 1);
FillRogueDemoRowExcept(19, 3, 4, 1);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_SCREEN_BOMB:
rogueStats.screenBombLevel = 1;
rogueStats.screenBombCount = 1;
FillRogueDemoRows(11, 19, 0);
SetRogueDemoCurrentPiece(4, 0, 4, 0);
break;
case DEMO_TERMINAL_CLEAR:
rogueStats.lastChanceUpgradeLevel = 1;
rogueStats.lastChanceCount = 1;
rogueStats.terminalClearLevel = 1;
rogueStats.screenBombLevel = 1;
rogueStats.screenBombCount = 1;
FillRogueDemoRows(0, 5, 2);
FillRogueDemoRows(12, 19, 3);
SetRogueDemoCurrentPiece(4, 0, 3, -1);
break;
case DEMO_DUAL_CHOICE:
rogueStats.dualChoiceLevel = 1;
FillRogueDemoRows(16, 18, 4);
FillRogueDemoRowExcept(19, 3, 4, 4);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_DESTINY_WHEEL:
rogueStats.destinyWheelLevel = 1;
FillRogueDemoRows(16, 18, 5);
FillRogueDemoRowExcept(19, 3, 4, 5);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_PERFECT_ROTATE:
rogueStats.perfectRotateLevel = 1;
FillRogueDemoRows(16, 19, 6);
for (int y = 10; y < nGameHeight; y++)
{
FillRogueDemoCell(y, 0, 0);
}
SetRogueDemoCurrentPiece(2, 1, 0, 0);
break;
case DEMO_TIME_DILATION:
rogueStats.timeDilationLevel = 1;
rogueStats.timeDilationTicks = 8;
FillRogueDemoRows(3, 19, 4);
currentFallInterval = GetRogueFallInterval();
SetRogueDemoCurrentPiece(0, 1, 3, 0);
SetFeedbackMessage(_T("时间缓流"), _T("堆叠高度危险,短时间内下落速度降低。"), 12);
break;
case DEMO_HIGH_PRESSURE:
rogueStats.highPressureLevel = 1;
rogueStats.scoreMultiplierPercent = 150;
rogueStats.expMultiplierPercent = 150;
currentFallInterval = GetRogueFallInterval();
FillRogueDemoRows(16, 18, 1);
FillRogueDemoRowExcept(19, 3, 4, 1);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_TETRIS_GAMBLE:
rogueStats.tetrisGambleLevel = 1;
FillRogueDemoRows(16, 18, 2);
FillRogueDemoRowExcept(19, 3, 4, 2);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_EXTREME_PLAYER:
rogueStats.extremePlayerLevel = 1;
rogueStats.highPressureLevel = 1;
rogueStats.tetrisGambleLevel = 1;
currentFallInterval = GetRogueFallInterval();
FillRogueDemoRows(16, 18, 3);
FillRogueDemoRowExcept(19, 3, 4, 3);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_UPGRADE_SHOCKWAVE:
rogueStats.upgradeShockwaveLevel = 1;
rogueStats.exp = 0;
rogueStats.requiredExp = 12;
FillRogueDemoRows(12, 18, 2);
FillRogueDemoRowExcept(19, 3, 4, 6);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_EVOLUTION_IMPACT:
rogueStats.evolutionImpactLevel = 1;
rogueStats.exp = 0;
rogueStats.requiredExp = 12;
FillRogueDemoRows(11, 18, 3);
FillRogueDemoRowExcept(19, 3, 4, 3);
SetRogueDemoCurrentPiece(0, 0, 3, 0);
break;
case DEMO_CONTROL_MASTER:
rogueStats.holdUnlocked = 1;
rogueStats.controlMasterLevel = 1;
rogueStats.previewCount = 3;
holdType = 0;
FillRogueDemoRows(16, 18, 4);
FillRogueDemoRowExcept(19, 3, 4, 4);
SetRogueDemoCurrentPiece(2, 0, 3, 0);
break;
case DEMO_BLOCK_STORM:
rogueStats.blockStormLevel = 1;
rogueStats.blockStormPiecesRemaining = 5;
FillRogueDemoRows(15, 19, 0);
for (int y = 8; y < nGameHeight; y++)
{
FillRogueDemoCell(y, 5, 0);
}
SetRogueDemoCurrentPiece(0, 1, 3, 0);
nextTypes[0] = 0;
nextTypes[1] = 0;
nextTypes[2] = 0;
SetFeedbackMessage(_T("方块风暴"), _T("当前和后续预览全部变为 I 块,方便制造四消。"), 12);
break;
case DEMO_BLACK_HOLE:
rogueStats.blackHoleLevel = 1;
rogueStats.blackHoleCharges = 1;
FillRogueDemoRows(9, 19, 2);
for (int y = 8; y < nGameHeight; y++)
{
for (int x = 1; x < nGameWidth; x += 3)
{
workRegion[y][x] = 2;
}
}
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_AIR_RESHAPE:
rogueStats.reshapeLevel = 1;
rogueStats.reshapeCharges = 1;
FillRogueDemoRows(16, 19, 3);
for (int y = 10; y < nGameHeight; y++)
{
FillRogueDemoCell(y, 9, 0);
}
SetRogueDemoCurrentPiece(1, 0, 6, 0);
break;
case DEMO_CROSS:
FillRogueDemoRows(13, 17, 5);
for (int y = 6; y < nGameHeight; y++)
{
FillRogueDemoCell(y, 4, 3);
}
currentPieceIsCross = true;
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_RAINBOW:
FillRogueDemoRows(10, 16, 2);
for (int x = 0; x < nGameWidth; x++)
{
workRegion[13][x] = (x < 6) ? 3 : 5;
}
currentPieceIsRainbow = true;
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
case DEMO_VOID_CORE:
rogueStats.blackHoleLevel = 1;
rogueStats.blackHoleCharges = 1;
rogueStats.voidCoreLevel = 1;
FillRogueDemoRows(8, 19, 6);
for (int y = 8; y < nGameHeight; y++)
{
for (int x = 1; x < nGameWidth; x += 3)
{
workRegion[y][x] = 6;
}
}
SetRogueDemoCurrentPiece(1, 0, 3, 0);
break;
default:
break;
}
ComputeTarget();
}