加入帮助页轮播框架未完善(实则一坨)
This commit is contained in:
@@ -221,6 +221,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;
|
||||||
@@ -268,6 +269,10 @@ void Restart();
|
|||||||
void StartGameWithMode(int mode);
|
void StartGameWithMode(int mode);
|
||||||
void ReturnToMainMenu();
|
void ReturnToMainMenu();
|
||||||
void ReviveAfterVideo();
|
void ReviveAfterVideo();
|
||||||
|
void StartRogueSkillDemo();
|
||||||
|
bool IsRogueSkillDemoMode();
|
||||||
|
bool TickRogueSkillDemo();
|
||||||
|
void AdvanceRogueSkillDemo();
|
||||||
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 OpenCreditScreen();
|
void OpenCreditScreen();
|
||||||
|
|||||||
@@ -789,6 +789,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
shouldRefresh = true;
|
shouldRefresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsRogueSkillDemoMode())
|
||||||
|
{
|
||||||
|
if (TickRogueSkillDemo())
|
||||||
|
{
|
||||||
|
shouldRefresh = true;
|
||||||
|
}
|
||||||
|
if (shouldRefresh)
|
||||||
|
{
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentMode == MODE_ROGUE && rogueStats.feverTicks > 0)
|
if (currentMode == MODE_ROGUE && rogueStats.feverTicks > 0)
|
||||||
{
|
{
|
||||||
rogueStats.feverTicks--;
|
rogueStats.feverTicks--;
|
||||||
@@ -990,8 +1003,16 @@ 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)
|
||||||
|
{
|
||||||
|
StartRogueSkillDemo();
|
||||||
|
ResetGameTimer(hWnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
helpState.currentPage = i + 1;
|
helpState.currentPage = i + 1;
|
||||||
helpScrollOffset = 0;
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1258,9 +1279,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
case VK_RETURN:
|
case VK_RETURN:
|
||||||
case VK_SPACE:
|
case VK_SPACE:
|
||||||
if (helpState.currentPage == 0)
|
if (helpState.currentPage == 0)
|
||||||
|
{
|
||||||
|
if (helpState.selectedIndex == 3)
|
||||||
|
{
|
||||||
|
StartRogueSkillDemo();
|
||||||
|
ResetGameTimer(hWnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
helpState.currentPage = helpState.selectedIndex + 1;
|
helpState.currentPage = helpState.selectedIndex + 1;
|
||||||
helpScrollOffset = 0;
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1398,6 +1427,27 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsRogueSkillDemoMode())
|
||||||
|
{
|
||||||
|
if (wParam == VK_RETURN || wParam == VK_SPACE)
|
||||||
|
{
|
||||||
|
AdvanceRogueSkillDemo();
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
}
|
||||||
|
else if (wParam == 'R')
|
||||||
|
{
|
||||||
|
StartRogueSkillDemo();
|
||||||
|
ResetGameTimer(hWnd);
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
}
|
||||||
|
else if (wParam == VK_ESCAPE || wParam == VK_BACK || wParam == 'M')
|
||||||
|
{
|
||||||
|
ReturnToMainMenu();
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (wParam == 'M')
|
if (wParam == 'M')
|
||||||
{
|
{
|
||||||
ReturnToMainMenu();
|
ReturnToMainMenu();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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 };
|
||||||
|
|||||||
@@ -518,6 +518,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 +532,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 +560,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;
|
||||||
@@ -574,10 +577,11 @@ void OpenRulesScreen()
|
|||||||
*/
|
*/
|
||||||
void OpenCreditScreen()
|
void OpenCreditScreen()
|
||||||
{
|
{
|
||||||
|
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 = 4;
|
helpState.currentPage = 4;
|
||||||
helpScrollOffset = 0;
|
helpScrollOffset = 0;
|
||||||
creditPageIndex = 0;
|
creditPageIndex = 0;
|
||||||
|
|||||||
@@ -658,17 +658,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("\u8fdb\u5165\u81ea\u52a8\u8f6e\u64ad\u6f14\u793a\uff0c\u4f9d\u6b21\u5c55\u793a Rogue \u4e3b\u8981\u6280\u80fd\u548c\u68cb\u76d8\u6548\u679c\u3002")
|
||||||
};
|
};
|
||||||
|
|
||||||
int optionHeight = SS(100);
|
int optionHeight = SS(100);
|
||||||
|
|||||||
@@ -109,6 +109,58 @@ 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;
|
||||||
|
|
||||||
|
enum RogueDemoKind
|
||||||
|
{
|
||||||
|
DEMO_HOLD = 0,
|
||||||
|
DEMO_BLACK_HOLE,
|
||||||
|
DEMO_SCREEN_BOMB,
|
||||||
|
DEMO_AIR_RESHAPE,
|
||||||
|
DEMO_EXPLOSIVE,
|
||||||
|
DEMO_CHAIN_BOMB,
|
||||||
|
DEMO_LASER,
|
||||||
|
DEMO_CROSS,
|
||||||
|
DEMO_RAINBOW,
|
||||||
|
DEMO_VOID_CORE,
|
||||||
|
DEMO_SWEEPER,
|
||||||
|
DEMO_LAST_CHANCE,
|
||||||
|
DEMO_TIME_DILATION,
|
||||||
|
DEMO_UPGRADE_SHOCKWAVE,
|
||||||
|
DEMO_BLOCK_STORM,
|
||||||
|
DEMO_STABLE_STRUCTURE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RogueDemoStep
|
||||||
|
{
|
||||||
|
int kind;
|
||||||
|
const TCHAR* name;
|
||||||
|
const TCHAR* detail;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const RogueDemoStep kRogueDemoSteps[] =
|
||||||
|
{
|
||||||
|
{ DEMO_HOLD, _T("备用仓"), _T("演示 C / Shift 暂存当前方块,并换出备用方块。") },
|
||||||
|
{ DEMO_BLACK_HOLE, _T("黑洞奇点"), _T("吞噬棋盘中数量最多的一种固定方块。") },
|
||||||
|
{ DEMO_SCREEN_BOMB, _T("清屏炸弹"), _T("主动引爆后清理可玩区域底部 5 行。") },
|
||||||
|
{ DEMO_AIR_RESHAPE, _T("空中换形"), _T("把正在下落的方块重塑为 I 块。") },
|
||||||
|
{ DEMO_EXPLOSIVE, _T("爆破核心"), _T("爆破方块落地后清除 3x3 区域。") },
|
||||||
|
{ DEMO_CHAIN_BOMB, _T("连环炸弹"), _T("爆破范围进化为 5x5。") },
|
||||||
|
{ DEMO_LASER, _T("棱镜激光"), _T("激光方块落地后清除整列。") },
|
||||||
|
{ DEMO_CROSS, _T("十字方块"), _T("十字方块同时清除所在行与所在列。") },
|
||||||
|
{ DEMO_RAINBOW, _T("彩虹方块"), _T("按中心行主色清除,并把覆盖行染成主色。") },
|
||||||
|
{ DEMO_VOID_CORE, _T("虚空核心"), _T("黑洞生效后追加召来彩虹方块。") },
|
||||||
|
{ DEMO_SWEEPER, _T("底线清道夫"), _T("消行充能后自动清扫底部。") },
|
||||||
|
{ DEMO_LAST_CHANCE, _T("最后一搏"), _T("濒死时自动清理底部 3 行。") },
|
||||||
|
{ DEMO_TIME_DILATION, _T("时间缓流"), _T("堆叠过高时临时降低下落速度。") },
|
||||||
|
{ DEMO_UPGRADE_SHOCKWAVE, _T("升级冲击波"), _T("升级后清除底部多行。") },
|
||||||
|
{ DEMO_BLOCK_STORM, _T("方块风暴"), _T("接下来多个方块固定变为 I 块。") },
|
||||||
|
{ DEMO_STABLE_STRUCTURE, _T("稳定结构"), _T("落地后填补局部空洞,让结构更平整。") }
|
||||||
|
};
|
||||||
|
|
||||||
|
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 +188,12 @@ 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 SetRogueDemoCurrentPiece(int pieceType, int pieceState, int x, int y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 限制 Rogue 模式的下一方块预览数量。
|
* @brief 限制 Rogue 模式的下一方块预览数量。
|
||||||
@@ -2705,3 +2763,367 @@ void UseAirReshape()
|
|||||||
SetFeedbackMessage(_T("空中换形"), detail, 12);
|
SetFeedbackMessage(_T("空中换形"), detail, 12);
|
||||||
ComputeTarget();
|
ComputeTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 判断当前是否处于 Rogue 技能自动演示模式。
|
||||||
|
*/
|
||||||
|
bool IsRogueSkillDemoMode()
|
||||||
|
{
|
||||||
|
return rogueDemoMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从帮助页进入 Rogue 技能演示,并播放第一段技能展示。
|
||||||
|
*/
|
||||||
|
void StartRogueSkillDemo()
|
||||||
|
{
|
||||||
|
currentMode = MODE_ROGUE;
|
||||||
|
currentScreen = SCREEN_PLAYING;
|
||||||
|
rogueDemoMode = true;
|
||||||
|
rogueDemoStepIndex = 0;
|
||||||
|
rogueDemoTicks = 0;
|
||||||
|
|
||||||
|
Restart();
|
||||||
|
rogueDemoMode = true;
|
||||||
|
reviveAvailable = false;
|
||||||
|
suspendFlag = false;
|
||||||
|
gameOverFlag = false;
|
||||||
|
targetFlag = true;
|
||||||
|
upgradeListScrollOffset = 0;
|
||||||
|
currentFallInterval = 500;
|
||||||
|
|
||||||
|
ApplyRogueSkillDemoStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 推进 Rogue 技能演示计时,到点后切换到下一项技能。
|
||||||
|
*/
|
||||||
|
bool TickRogueSkillDemo()
|
||||||
|
{
|
||||||
|
if (!rogueDemoMode)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 56;
|
||||||
|
floatingTextEffects[0].totalTicks = 56;
|
||||||
|
floatingTextEffects[0].boardX = 500;
|
||||||
|
floatingTextEffects[0].boardY = 980;
|
||||||
|
floatingTextEffects[0].color = RGB(255, 248, 250);
|
||||||
|
lstrcpyn(floatingTextEffects[0].text, name, sizeof(floatingTextEffects[0].text) / sizeof(TCHAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < nGameWidth; x++)
|
||||||
|
{
|
||||||
|
workRegion[y][x] = 1 + ((baseValue + y + 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_HOLD:
|
||||||
|
rogueStats.holdUnlocked = 1;
|
||||||
|
rogueStats.controlMasterLevel = 1;
|
||||||
|
holdType = 0;
|
||||||
|
SetRogueDemoCurrentPiece(2, 0, 3, 1);
|
||||||
|
HoldCurrentPiece();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_BLACK_HOLE:
|
||||||
|
rogueStats.blackHoleLevel = 1;
|
||||||
|
rogueStats.blackHoleCharges = 1;
|
||||||
|
FillRogueDemoRows(8, 19, 2);
|
||||||
|
for (int y = 8; y < nGameHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < nGameWidth; x += 3)
|
||||||
|
{
|
||||||
|
workRegion[y][x] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UseBlackHole();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_SCREEN_BOMB:
|
||||||
|
rogueStats.screenBombLevel = 1;
|
||||||
|
rogueStats.screenBombCount = 1;
|
||||||
|
FillRogueDemoRows(12, 19, 0);
|
||||||
|
UseScreenBomb();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_AIR_RESHAPE:
|
||||||
|
rogueStats.reshapeLevel = 1;
|
||||||
|
rogueStats.reshapeCharges = 1;
|
||||||
|
FillRogueDemoRows(15, 19, 3);
|
||||||
|
SetRogueDemoCurrentPiece(1, 0, 3, 4);
|
||||||
|
UseAirReshape();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_EXPLOSIVE:
|
||||||
|
FillRogueDemoRows(11, 17, 1);
|
||||||
|
currentPieceIsExplosive = true;
|
||||||
|
SetRogueDemoCurrentPiece(5, 0, 3, 8);
|
||||||
|
ClearExplosiveAreaAt(14, 5);
|
||||||
|
ApplyBoardGravity();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_CHAIN_BOMB:
|
||||||
|
rogueStats.chainBombLevel = 1;
|
||||||
|
FillRogueDemoRows(10, 18, 4);
|
||||||
|
currentPieceIsExplosive = true;
|
||||||
|
SetRogueDemoCurrentPiece(5, 0, 3, 8);
|
||||||
|
ClearExplosiveAreaAt(14, 5);
|
||||||
|
ApplyBoardGravity();
|
||||||
|
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, 4);
|
||||||
|
ClearColumnAt(5);
|
||||||
|
ApplyBoardGravity();
|
||||||
|
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, 8);
|
||||||
|
ClearRowAt(14);
|
||||||
|
ClearColumnAtWithColor(4, RGB(196, 255, 132));
|
||||||
|
ApplyBoardGravity();
|
||||||
|
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, 8);
|
||||||
|
{
|
||||||
|
int recoloredCount = 0;
|
||||||
|
TriggerRainbowColorShift(13, 11, 15, recoloredCount);
|
||||||
|
}
|
||||||
|
ApplyBoardGravity();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UseBlackHole();
|
||||||
|
SetFeedbackMessage(_T("虚空核心"), _T("黑洞吞噬后,下一枚特殊方块将变为彩虹方块。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_SWEEPER:
|
||||||
|
rogueStats.sweeperLevel = 4;
|
||||||
|
FillRogueDemoRows(13, 19, 1);
|
||||||
|
ClearRowAt(GetRoguePlayableHeight() - 1);
|
||||||
|
ApplyBoardGravity();
|
||||||
|
SetFeedbackMessage(_T("底线清道夫"), _T("清道夫完成充能,自动扫掉底部压力行。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_LAST_CHANCE:
|
||||||
|
rogueStats.lastChanceUpgradeLevel = 1;
|
||||||
|
rogueStats.lastChanceCount = 1;
|
||||||
|
FillRogueDemoRows(2, 7, 5);
|
||||||
|
FillRogueDemoRows(14, 19, 3);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
DeleteOneLine(GetRoguePlayableHeight() - 1);
|
||||||
|
}
|
||||||
|
TriggerLineClearEffect(nullptr, 0, 3);
|
||||||
|
SetFeedbackMessage(_T("最后一搏"), _T("触顶前自动清除底部 3 行,保留继续操作空间。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_TIME_DILATION:
|
||||||
|
rogueStats.timeDilationLevel = 1;
|
||||||
|
rogueStats.timeDilationTicks = 8;
|
||||||
|
FillRogueDemoRows(3, 19, 4);
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
SetFeedbackMessage(_T("时间缓流"), _T("堆叠高度危险,短时间内下落速度降低。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_UPGRADE_SHOCKWAVE:
|
||||||
|
rogueStats.upgradeShockwaveLevel = 1;
|
||||||
|
FillRogueDemoRows(12, 19, 2);
|
||||||
|
TriggerUpgradeShockwave(2);
|
||||||
|
ApplyBoardGravity();
|
||||||
|
SetFeedbackMessage(_T("升级冲击波"), _T("升级完成后,冲击波清除底部 2 行。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_BLOCK_STORM:
|
||||||
|
rogueStats.blockStormLevel = 1;
|
||||||
|
rogueStats.blockStormPiecesRemaining = 5;
|
||||||
|
FillRogueDemoRows(15, 19, 0);
|
||||||
|
SetRogueDemoCurrentPiece(0, 0, 3, 2);
|
||||||
|
nextTypes[0] = 0;
|
||||||
|
nextTypes[1] = 0;
|
||||||
|
nextTypes[2] = 0;
|
||||||
|
SetFeedbackMessage(_T("方块风暴"), _T("当前和后续预览全部变为 I 块,方便制造四消。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMO_STABLE_STRUCTURE:
|
||||||
|
rogueStats.stableStructureLevel = 4;
|
||||||
|
FillRogueDemoRows(14, 19, 1);
|
||||||
|
workRegion[13][3] = 2;
|
||||||
|
workRegion[15][4] = 0;
|
||||||
|
workRegion[16][6] = 0;
|
||||||
|
TryStabilizeBoard();
|
||||||
|
SetFeedbackMessage(_T("稳定结构"), _T("自动填补局部空洞,让堆叠更稳。"), 12);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputeTarget();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user