Compare commits
9 Commits
2c04796010
...
qhy_dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f435f5ca6 | |||
| 45d9e988df | |||
| aa9e2f3ddc | |||
| 971d8be0dc | |||
| 9341ac9a05 | |||
| c77b877b8b | |||
| da741d1e56 | |||
| 647038b27a | |||
| 00729fbe17 |
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 |
@@ -191,6 +191,16 @@ struct CellFlashEffect
|
||||
COLORREF color;
|
||||
};
|
||||
|
||||
struct GravityFallEffect
|
||||
{
|
||||
int ticks;
|
||||
int totalTicks;
|
||||
int x;
|
||||
int fromY;
|
||||
int toY;
|
||||
int cellValue;
|
||||
};
|
||||
|
||||
enum ScreenState
|
||||
{
|
||||
SCREEN_MENU = 0,
|
||||
@@ -221,6 +231,7 @@ extern bool suspendFlag;
|
||||
extern bool targetFlag;
|
||||
extern bool bgmEnabled;
|
||||
extern bool reviveAvailable;
|
||||
extern bool rogueDemoMode;
|
||||
extern int workRegion[20][10];
|
||||
extern Point point;
|
||||
extern Point target;
|
||||
@@ -239,6 +250,7 @@ extern ClearEffectState clearEffectState;
|
||||
extern FloatingTextEffect floatingTextEffects[8];
|
||||
extern ParticleEffect particleEffects[96];
|
||||
extern CellFlashEffect cellFlashEffects[64];
|
||||
extern GravityFallEffect gravityFallEffects[80];
|
||||
extern int currentScreen;
|
||||
extern int currentMode;
|
||||
extern int currentFallInterval;
|
||||
@@ -268,8 +280,19 @@ void Restart();
|
||||
void StartGameWithMode(int mode);
|
||||
void ReturnToMainMenu();
|
||||
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 OpenRulesScreen();
|
||||
void OpenSkillDemoScreen();
|
||||
void OpenCreditScreen();
|
||||
void ChangeCreditPage(int direction);
|
||||
void OpenUpgradeMenu();
|
||||
@@ -287,6 +310,7 @@ void TriggerLineClearEffect(const int* rows, int rowCount, int linesCleared);
|
||||
void PlayPendingLineClearEffect();
|
||||
void TriggerCellClearEffect(const Point* cells, int cellCount, 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 CheckRogueLevelProgress();
|
||||
void ApplyBoardGravity();
|
||||
|
||||
@@ -84,6 +84,11 @@ void RollCurrentPieceSpecialFlags(bool allowRandomSpecials);
|
||||
*/
|
||||
void QueueLineClearEffect(const int* rows, int rowCount, int linesCleared);
|
||||
|
||||
/**
|
||||
* @brief 记录固定方块受重力下落的轨迹,用于播放纵向残影特效。
|
||||
*/
|
||||
void TriggerGravityFallEffect(int x, int fromY, int toY, int cellValue);
|
||||
|
||||
/**
|
||||
* @brief 尝试把旋转后的方块横向偏移指定格数后放置。
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define IDD_ABOUTBOX 103
|
||||
#define IDM_ABOUT 104
|
||||
#define IDM_EXIT 105
|
||||
#define IDM_SKILL_DEMO 106
|
||||
#define IDI_TETRIS 107
|
||||
#define IDI_SMALL 108
|
||||
#define IDC_TETRIS 109
|
||||
|
||||
Binary file not shown.
+171
-19
@@ -197,6 +197,30 @@ static RECT GetHelpOptionRect(HWND hWnd, int index)
|
||||
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)
|
||||
{
|
||||
LayoutMetrics metrics = GetLayoutMetrics(hWnd);
|
||||
@@ -744,6 +768,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
switch (wmId)
|
||||
{
|
||||
case IDM_SKILL_DEMO:
|
||||
OpenSkillDemoScreen();
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
break;
|
||||
case IDM_ABOUT:
|
||||
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
|
||||
break;
|
||||
@@ -789,7 +817,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
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--;
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
@@ -798,6 +834,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
|
||||
if (currentMode == MODE_ROGUE &&
|
||||
!IsRogueSkillDemoMode() &&
|
||||
rogueStats.timeDilationTicks > 0 &&
|
||||
currentScreen == SCREEN_PLAYING &&
|
||||
!suspendFlag &&
|
||||
@@ -809,7 +846,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
shouldRefresh = true;
|
||||
}
|
||||
|
||||
if (currentMode == MODE_ROGUE && rogueStats.extremeSlowTicks > 0)
|
||||
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.extremeSlowTicks > 0)
|
||||
{
|
||||
rogueStats.extremeSlowTicks--;
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
@@ -818,6 +855,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
|
||||
if (currentMode == MODE_ROGUE &&
|
||||
!IsRogueSkillDemoMode() &&
|
||||
rogueStats.extremePlayerLevel > 0 &&
|
||||
currentScreen == SCREEN_PLAYING &&
|
||||
!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--;
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
@@ -855,7 +893,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
!suspendFlag &&
|
||||
!gameOverFlag)
|
||||
{
|
||||
if (currentMode == MODE_ROGUE)
|
||||
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode())
|
||||
{
|
||||
int previousFallInterval = currentFallInterval;
|
||||
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 playableHeight = GetRoguePlayableHeight();
|
||||
@@ -943,7 +981,20 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
if (currentScreen != SCREEN_MENU && IsPointInRect(GetBackButtonRect(hWnd), mouseX, mouseY))
|
||||
{
|
||||
ReturnToMainMenu();
|
||||
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();
|
||||
}
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
break;
|
||||
}
|
||||
@@ -990,8 +1041,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
if (IsPointInRect(GetHelpOptionRect(hWnd, i), mouseX, mouseY))
|
||||
{
|
||||
helpState.selectedIndex = i;
|
||||
helpState.currentPage = i + 1;
|
||||
helpScrollOffset = 0;
|
||||
if (i == 3)
|
||||
{
|
||||
helpState.currentPage = 5;
|
||||
helpState.selectedIndex = 0;
|
||||
helpScrollOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
helpState.currentPage = i + 1;
|
||||
helpScrollOffset = 0;
|
||||
}
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
break;
|
||||
}
|
||||
@@ -1002,17 +1062,36 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
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
|
||||
{
|
||||
helpState.currentPage = 0;
|
||||
helpScrollOffset = 0;
|
||||
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;
|
||||
helpScrollOffset = 0;
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
case VK_DOWN:
|
||||
case VK_RIGHT:
|
||||
@@ -1254,13 +1346,42 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
ChangeCreditPage(1);
|
||||
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;
|
||||
case VK_RETURN:
|
||||
case VK_SPACE:
|
||||
if (helpState.currentPage == 0)
|
||||
{
|
||||
helpState.currentPage = helpState.selectedIndex + 1;
|
||||
helpScrollOffset = 0;
|
||||
if (helpState.selectedIndex == 3)
|
||||
{
|
||||
helpState.currentPage = 5;
|
||||
helpState.selectedIndex = 0;
|
||||
helpScrollOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
helpState.currentPage = helpState.selectedIndex + 1;
|
||||
helpScrollOffset = 0;
|
||||
}
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
}
|
||||
else if (helpState.currentPage == 5)
|
||||
{
|
||||
StartRogueSkillDemoAt(helpState.selectedIndex);
|
||||
ResetGameTimer(hWnd);
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
}
|
||||
break;
|
||||
@@ -1273,7 +1394,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -1398,14 +1527,37 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
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();
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wParam == 'R')
|
||||
if (!IsRogueSkillDemoMode() && wParam == 'R')
|
||||
{
|
||||
StartGameWithMode(currentMode);
|
||||
ResetGameTimer(hWnd);
|
||||
@@ -1413,7 +1565,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
break;
|
||||
}
|
||||
|
||||
if (wParam == 'P')
|
||||
if (!IsRogueSkillDemoMode() && wParam == 'P')
|
||||
{
|
||||
suspendFlag = !suspendFlag;
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
|
||||
@@ -10,11 +10,12 @@ bool gameOverFlag = false;
|
||||
bool suspendFlag = false;
|
||||
bool targetFlag = false;
|
||||
bool reviveAvailable = false;
|
||||
bool rogueDemoMode = false;
|
||||
int workRegion[20][10] = { 0 };
|
||||
Point point = { 0, 0 };
|
||||
Point target = { 0, 0 };
|
||||
MenuState menuState = { 0, 4 };
|
||||
HelpState helpState = { 0, 3, 0 };
|
||||
HelpState helpState = { 0, 4, 0 };
|
||||
int helpScrollOffset = 0;
|
||||
int creditPageIndex = 0;
|
||||
int creditAnimationTicks = 0;
|
||||
@@ -28,6 +29,7 @@ ClearEffectState clearEffectState = { 0, 0, 0, {} };
|
||||
FloatingTextEffect floatingTextEffects[8] = {};
|
||||
ParticleEffect particleEffects[96] = {};
|
||||
CellFlashEffect cellFlashEffects[64] = {};
|
||||
GravityFallEffect gravityFallEffects[80] = {};
|
||||
int currentScreen = SCREEN_MENU;
|
||||
int currentMode = MODE_CLASSIC;
|
||||
int currentFallInterval = 500;
|
||||
@@ -465,7 +467,6 @@ void Fixing()
|
||||
voidClearedCount = TriggerMiniBlackHole(5);
|
||||
AwardRogueSkillClearRewards(voidClearedCount, voidScore, voidExp, false);
|
||||
}
|
||||
ApplyBoardGravity();
|
||||
}
|
||||
|
||||
TCHAR rainbowDetail[128];
|
||||
@@ -544,7 +545,6 @@ void Fixing()
|
||||
if (currentMode == MODE_ROGUE && explosiveCellsCleared > 0)
|
||||
{
|
||||
AwardRogueSkillClearRewards(explosiveCellsCleared, explosiveScoreGain, explosiveExpGain, false);
|
||||
ApplyBoardGravity();
|
||||
}
|
||||
|
||||
TCHAR explosiveDetail[128];
|
||||
@@ -590,7 +590,6 @@ void Fixing()
|
||||
int laserScore = 0;
|
||||
int laserExp = 0;
|
||||
AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false);
|
||||
ApplyBoardGravity();
|
||||
|
||||
TCHAR laserDetail[128];
|
||||
_stprintf_s(laserDetail, _T("激光贯穿第 %d 列,清除 %d 格 +%d 分 +%d EXP"), laserColumn + 1, laserCellsCleared, laserScore, laserExp);
|
||||
@@ -644,7 +643,6 @@ void Fixing()
|
||||
int crossScore = 0;
|
||||
int crossExp = 0;
|
||||
AwardRogueSkillClearRewards(totalCrossCleared, crossScore, crossExp, false);
|
||||
ApplyBoardGravity();
|
||||
|
||||
TCHAR crossDetail[128];
|
||||
_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);
|
||||
if (currentMode == MODE_CLASSIC && clearedLines > 0)
|
||||
{
|
||||
ApplyBoardGravity();
|
||||
}
|
||||
|
||||
if (currentScreen == SCREEN_UPGRADE)
|
||||
{
|
||||
QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||
@@ -787,7 +780,6 @@ int DeleteLines()
|
||||
int followupScore = 0;
|
||||
int followupExp = 0;
|
||||
AwardRogueSkillClearRewards(followupCleared, followupScore, followupExp, false);
|
||||
ApplyBoardGravity();
|
||||
|
||||
TCHAR followupDetail[128];
|
||||
_stprintf_s(
|
||||
|
||||
@@ -116,6 +116,11 @@ void ResetVisualEffects()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 判断指定方块、旋转状态和位置是否可以合法放置。
|
||||
*/
|
||||
@@ -518,6 +577,7 @@ void ReviveAfterVideo()
|
||||
*/
|
||||
void StartGameWithMode(int mode)
|
||||
{
|
||||
rogueDemoMode = false;
|
||||
currentMode = mode;
|
||||
currentScreen = SCREEN_PLAYING;
|
||||
upgradeListScrollOffset = 0;
|
||||
@@ -531,6 +591,7 @@ void StartGameWithMode(int mode)
|
||||
*/
|
||||
void ReturnToMainMenu()
|
||||
{
|
||||
rogueDemoMode = false;
|
||||
currentScreen = SCREEN_MENU;
|
||||
suspendFlag = false;
|
||||
gameOverFlag = false;
|
||||
@@ -558,10 +619,11 @@ void ReturnToMainMenu()
|
||||
*/
|
||||
void OpenRulesScreen()
|
||||
{
|
||||
rogueDemoMode = false;
|
||||
currentScreen = SCREEN_RULES;
|
||||
suspendFlag = false;
|
||||
helpState.selectedIndex = 0;
|
||||
helpState.optionCount = 3;
|
||||
helpState.optionCount = 4;
|
||||
helpState.currentPage = 0;
|
||||
helpScrollOffset = 0;
|
||||
creditPageIndex = 0;
|
||||
@@ -572,12 +634,27 @@ void OpenRulesScreen()
|
||||
/**
|
||||
* @brief 打开致谢界面并重置致谢页切换状态。
|
||||
*/
|
||||
void OpenCreditScreen()
|
||||
void OpenSkillDemoScreen()
|
||||
{
|
||||
rogueDemoMode = false;
|
||||
currentScreen = SCREEN_RULES;
|
||||
suspendFlag = false;
|
||||
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;
|
||||
helpScrollOffset = 0;
|
||||
creditPageIndex = 0;
|
||||
@@ -590,6 +667,7 @@ void OpenCreditScreen()
|
||||
*/
|
||||
void ChangeCreditPage(int direction)
|
||||
{
|
||||
constexpr int creditPageCount = 4;
|
||||
if (direction == 0)
|
||||
{
|
||||
return;
|
||||
@@ -609,9 +687,9 @@ void ChangeCreditPage(int direction)
|
||||
|
||||
if (creditPageIndex < 0)
|
||||
{
|
||||
creditPageIndex = 1;
|
||||
creditPageIndex = creditPageCount - 1;
|
||||
}
|
||||
if (creditPageIndex > 1)
|
||||
if (creditPageIndex >= creditPageCount)
|
||||
{
|
||||
creditPageIndex = 0;
|
||||
}
|
||||
|
||||
+274
-39
@@ -131,11 +131,12 @@ static Bitmap* LoadBackgroundImage()
|
||||
*/
|
||||
static Bitmap* LoadCreditImage(int index)
|
||||
{
|
||||
constexpr int creditPageCount = 4;
|
||||
static ULONG_PTR gdiplusToken = 0;
|
||||
static Bitmap* creditImages[2] = {};
|
||||
static bool attempted[2] = {};
|
||||
static Bitmap* creditImages[creditPageCount] = {};
|
||||
static bool attempted[creditPageCount] = {};
|
||||
|
||||
if (index < 0 || index >= 2)
|
||||
if (index < 0 || index >= creditPageCount)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -147,19 +148,29 @@ static Bitmap* LoadCreditImage(int index)
|
||||
GdiplusStartupInput startupInput;
|
||||
if (GdiplusStartup(&gdiplusToken, &startupInput, nullptr) == Ok)
|
||||
{
|
||||
const wchar_t* imageNames[2] =
|
||||
const wchar_t* imageNames[creditPageCount] =
|
||||
{
|
||||
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]),
|
||||
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())
|
||||
{
|
||||
continue;
|
||||
@@ -637,6 +648,10 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
{
|
||||
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);
|
||||
|
||||
HPEN rulesAccentPen = CreatePen(PS_SOLID, SS(3), accentColor);
|
||||
@@ -656,17 +671,19 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
|
||||
if (helpState.currentPage == 0)
|
||||
{
|
||||
const TCHAR* optionTitles[3] =
|
||||
const TCHAR* optionTitles[4] =
|
||||
{
|
||||
_T("\u6e38\u620f\u4ecb\u7ecd"),
|
||||
_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("\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);
|
||||
@@ -766,7 +783,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
{
|
||||
_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("卸压清场:获得时立刻清除最高的一条占用行,直接降低顶部压力。\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("连锁火花:完成消行后追加随机破坏,适合配合稳定堆叠扩大收益。\r\n连环炸弹:强化爆破核心,将爆破范围从 3x3 扩大为 5x5。\r\n雷霆四消:三消或四消后追加雷击,额外清除局部方块。\r\n雷霆棱镜:三消或四消后追加激光清列,强化四消后的清场能力。"),
|
||||
_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(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)
|
||||
{
|
||||
const int creditAnimationTotalTicks = 60;
|
||||
const TCHAR* creditNames[2] =
|
||||
constexpr int creditPageCount = 4;
|
||||
const TCHAR* creditNames[creditPageCount] =
|
||||
{
|
||||
_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\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;
|
||||
@@ -895,17 +1002,17 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
{
|
||||
currentCredit = 0;
|
||||
}
|
||||
if (currentCredit > 1)
|
||||
if (currentCredit >= creditPageCount)
|
||||
{
|
||||
currentCredit = 1;
|
||||
currentCredit = creditPageCount - 1;
|
||||
}
|
||||
|
||||
int previousCredit = currentCredit - creditAnimationDirection;
|
||||
if (previousCredit < 0)
|
||||
{
|
||||
previousCredit = 1;
|
||||
previousCredit = creditPageCount - 1;
|
||||
}
|
||||
if (previousCredit > 1)
|
||||
if (previousCredit >= creditPageCount)
|
||||
{
|
||||
previousCredit = 0;
|
||||
}
|
||||
@@ -939,8 +1046,11 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
previousOffset = currentOffset - creditAnimationDirection * slideDistance;
|
||||
}
|
||||
|
||||
Bitmap* preloadedCreditImageA = LoadCreditImage(0);
|
||||
Bitmap* preloadedCreditImageB = LoadCreditImage(1);
|
||||
Bitmap* preloadedCreditImages[creditPageCount] = {};
|
||||
for (int i = 0; i < creditPageCount; i++)
|
||||
{
|
||||
preloadedCreditImages[i] = LoadCreditImage(i);
|
||||
}
|
||||
Graphics creditGraphics(hdc);
|
||||
creditGraphics.SetInterpolationMode(InterpolationModeHighQualityBilinear);
|
||||
|
||||
@@ -951,7 +1061,11 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
OffsetRect(&shiftedImageArea, 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)
|
||||
{
|
||||
int imageWidth = static_cast<int>(creditImage->GetWidth());
|
||||
@@ -1067,7 +1181,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
SelectObject(hdc, oldPen);
|
||||
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 };
|
||||
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")
|
||||
: (helpState.currentPage == 4
|
||||
? _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);
|
||||
|
||||
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)
|
||||
{
|
||||
int elapsed = clearEffectState.totalTicks - clearEffectState.ticks;
|
||||
@@ -1545,12 +1727,50 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
|
||||
if (currentMode == MODE_ROGUE)
|
||||
{
|
||||
int progressTop = IsRogueSkillDemoMode() ? 350 : 270;
|
||||
int progressBottom = IsRogueSkillDemoMode() ? 568 : 488;
|
||||
int upgradeTop = IsRogueSkillDemoMode() ? 590 : 510;
|
||||
|
||||
if (IsRogueSkillDemoMode())
|
||||
{
|
||||
RECT demoSkillRect =
|
||||
{
|
||||
leftPanelRect.left + SS(20),
|
||||
leftPanelRect.top + SS(270),
|
||||
leftPanelRect.right - SS(20),
|
||||
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(270),
|
||||
leftPanelRect.top + SS(progressTop),
|
||||
leftPanelRect.right - SS(20),
|
||||
leftPanelRect.top + SS(488)
|
||||
leftPanelRect.top + SS(progressBottom)
|
||||
};
|
||||
DrawPanelCardAlpha(progressRect, RGB(255, 248, 251), RGB(233, 191, 208), 24, panelAlpha);
|
||||
|
||||
@@ -1654,7 +1874,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
RECT upgradeListRect =
|
||||
{
|
||||
leftPanelRect.left + SS(20),
|
||||
leftPanelRect.top + SS(510),
|
||||
leftPanelRect.top + SS(upgradeTop),
|
||||
leftPanelRect.right - SS(20),
|
||||
leftPanelRect.bottom - SS(20)
|
||||
};
|
||||
@@ -1758,7 +1978,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -2206,15 +2426,30 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
};
|
||||
if (currentMode == MODE_ROGUE)
|
||||
{
|
||||
DrawText(
|
||||
hdc,
|
||||
_T("\u79fb\u52a8\uff1a\u2190/\u2192 \u6216 A/D\r\n")
|
||||
_T("\u65cb\u8f6c/\u4e0b\u843d\uff1a\u2191/W\u3001\u2193/S\u3001Space\r\n")
|
||||
_T("战局:P 暂停 R 重开 M 菜单\r\n")
|
||||
_T("技能:C 备用仓 Z 黑洞 X 炸弹 V 换形"),
|
||||
-1,
|
||||
&controlBodyRect,
|
||||
DT_LEFT | DT_TOP | DT_WORDBREAK);
|
||||
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(
|
||||
hdc,
|
||||
_T("\u79fb\u52a8\uff1a\u2190/\u2192 \u6216 A/D\r\n")
|
||||
_T("\u65cb\u8f6c/\u4e0b\u843d\uff1a\u2191/W\u3001\u2193/S\u3001Space\r\n")
|
||||
_T("战局:P 暂停 R 重开 M 菜单\r\n")
|
||||
_T("技能:C 备用仓 Z 黑洞 X 炸弹 V 换形"),
|
||||
-1,
|
||||
&controlBodyRect,
|
||||
DT_LEFT | DT_TOP | DT_WORDBREAK);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+827
-17
@@ -73,7 +73,7 @@ static const UpgradeEntry kUpgradePool[] =
|
||||
{ UPGRADE_FEVER_MODE, 1, 92, false, _T("狂热节拍"), _T("进阶"), _T("累计消行 12 行后进入 12 秒狂热:得分与 EXP 翻倍。") },
|
||||
{ UPGRADE_RAGE_STACK, 1, 84, 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_DUAL_CHOICE, 1, 68, false, _T("双重抉择"), _T("进阶"), _T("每次升级可额外选择 1 个强化,但下一次升级所需 EXP +30%。") },
|
||||
{ UPGRADE_DESTINY_WHEEL, 1, 104, false, _T("命运轮盘"), _T("进化"), _T("升级时出现 6 个选项,可选择 2 个;其中 1 个会携带诅咒。") },
|
||||
@@ -109,6 +109,79 @@ static constexpr int kExplosiveBaseInterval = 6;
|
||||
static constexpr int kExplosiveMinInterval = 3;
|
||||
static int pendingUpgradeShockwaveRows = 0;
|
||||
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 bool IsUpgradePrerequisiteConsumed(int upgradeId);
|
||||
@@ -136,6 +209,14 @@ static void FillUpgradeOptions();
|
||||
static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount);
|
||||
static void ApplyDestinyCurse();
|
||||
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 模式的下一方块预览数量。
|
||||
@@ -211,7 +292,7 @@ static void ClearLockedRows()
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -891,6 +972,25 @@ void RollCurrentPieceSpecialFlags(bool allowRandomSpecials)
|
||||
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)
|
||||
{
|
||||
rogueStats.pendingRainbowPieceCount--;
|
||||
@@ -1319,6 +1419,10 @@ int TryStabilizeBoard()
|
||||
{
|
||||
triggerChance = 70;
|
||||
}
|
||||
if (rogueDemoMode && kRogueDemoSteps[rogueDemoStepIndex].kind == DEMO_STABLE_STRUCTURE)
|
||||
{
|
||||
triggerChance = 100;
|
||||
}
|
||||
|
||||
if ((rand() % 100) >= triggerChance)
|
||||
{
|
||||
@@ -1680,7 +1784,7 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
|
||||
rogueStats.infiniteFeverLevel = 1;
|
||||
break;
|
||||
case UPGRADE_SCREEN_BOMB:
|
||||
rogueStats.screenBombLevel = 1;
|
||||
rogueStats.screenBombLevel += applyCount;
|
||||
rogueStats.screenBombCount += applyCount;
|
||||
break;
|
||||
case UPGRADE_TERMINAL_CLEAR:
|
||||
@@ -1831,7 +1935,7 @@ void AwardRogueSkillClearRewards(int clearedCells, int& scoreGain, int& expGain,
|
||||
}
|
||||
}
|
||||
|
||||
if (allowLevelProgress)
|
||||
if (allowLevelProgress && !rogueDemoMode)
|
||||
{
|
||||
int levelUps = ApplyLevelProgress(rogueStats);
|
||||
if (levelUps > 0)
|
||||
@@ -1851,6 +1955,10 @@ void CheckRogueLevelProgress()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (rogueDemoMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int levelUps = ApplyLevelProgress(rogueStats);
|
||||
if (levelUps <= 0)
|
||||
@@ -1908,6 +2016,10 @@ void ApplyBoardGravity()
|
||||
int cell = workRegion[y][x];
|
||||
workRegion[y][x] = 0;
|
||||
workRegion[writeY][x] = cell;
|
||||
if (writeY != y)
|
||||
{
|
||||
TriggerGravityFallEffect(x, y, writeY, cell);
|
||||
}
|
||||
writeY--;
|
||||
}
|
||||
}
|
||||
@@ -2064,7 +2176,6 @@ void ApplyLineClearResult(int linesCleared)
|
||||
int chainBlastScore = 0;
|
||||
int chainBlastExp = 0;
|
||||
AwardRogueSkillClearRewards(chainBlastCells, chainBlastScore, chainBlastExp, false);
|
||||
ApplyBoardGravity();
|
||||
|
||||
TCHAR blastDetail[128];
|
||||
_stprintf_s(
|
||||
@@ -2105,7 +2216,6 @@ void ApplyLineClearResult(int linesCleared)
|
||||
int thunderScore = 0;
|
||||
int thunderExp = 0;
|
||||
AwardRogueSkillClearRewards(thunderRowsCleared, thunderScore, thunderExp, false);
|
||||
ApplyBoardGravity();
|
||||
SetFeedbackMessage(_T("雷霆四消"), _T("雷击落下,额外清理了 2 行范围内的方块。"), 12);
|
||||
}
|
||||
}
|
||||
@@ -2123,7 +2233,6 @@ void ApplyLineClearResult(int linesCleared)
|
||||
int laserScore = 0;
|
||||
int laserExp = 0;
|
||||
AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false);
|
||||
ApplyBoardGravity();
|
||||
|
||||
TCHAR thunderLaserDetail[128];
|
||||
_stprintf_s(
|
||||
@@ -2163,7 +2272,6 @@ void ApplyLineClearResult(int linesCleared)
|
||||
}
|
||||
|
||||
int levelUps = ApplyLevelProgress(rogueStats);
|
||||
upgradeUiState.pendingCount += levelUps;
|
||||
tScore = rogueStats.score;
|
||||
|
||||
if (levelUps > 0)
|
||||
@@ -2189,15 +2297,34 @@ void ApplyLineClearResult(int linesCleared)
|
||||
TCHAR feedbackTitle[64];
|
||||
TCHAR feedbackDetail[128];
|
||||
_stprintf_s(feedbackTitle, _T("灵感涌现 x%d"), levelUps);
|
||||
_stprintf_s(
|
||||
feedbackDetail,
|
||||
_T("等级 Lv.%d EXP %d/%d 选择新的强化"),
|
||||
rogueStats.level,
|
||||
rogueStats.exp,
|
||||
rogueStats.requiredExp);
|
||||
if (rogueDemoMode)
|
||||
{
|
||||
_stprintf_s(
|
||||
feedbackDetail,
|
||||
_T("演示升级 Lv.%d,普通强化菜单已关闭。"),
|
||||
rogueStats.level);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stprintf_s(
|
||||
feedbackDetail,
|
||||
_T("等级 Lv.%d EXP %d/%d 选择新的强化"),
|
||||
rogueStats.level,
|
||||
rogueStats.exp,
|
||||
rogueStats.requiredExp);
|
||||
}
|
||||
SetFeedbackMessage(feedbackTitle, feedbackDetail, 10);
|
||||
|
||||
OpenUpgradeMenu();
|
||||
if (rogueDemoMode)
|
||||
{
|
||||
ResolvePendingUpgradeShockwave();
|
||||
PlayPendingLineClearEffect();
|
||||
}
|
||||
else
|
||||
{
|
||||
upgradeUiState.pendingCount += levelUps;
|
||||
OpenUpgradeMenu();
|
||||
}
|
||||
}
|
||||
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
@@ -2560,7 +2687,6 @@ void UseScreenBomb()
|
||||
|
||||
rogueStats.screenBombCount--;
|
||||
int clearedCells = TriggerScreenBomb();
|
||||
ApplyBoardGravity();
|
||||
int scoreGain = 0;
|
||||
int expGain = 0;
|
||||
AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true);
|
||||
@@ -2607,7 +2733,6 @@ void UseBlackHole()
|
||||
|
||||
rogueStats.blackHoleCharges--;
|
||||
|
||||
ApplyBoardGravity();
|
||||
int scoreGain = 0;
|
||||
int expGain = 0;
|
||||
AwardRogueSkillClearRewards(clearedCells, scoreGain, expGain, true);
|
||||
@@ -2705,3 +2830,688 @@ void UseAirReshape()
|
||||
SetFeedbackMessage(_T("空中换形"), detail, 12);
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user