进一步拆分与注释补强
This commit is contained in:
Submodule
+1
Submodule .worktrees/ack-syc-swj added at 58ab400949
+208
-128
@@ -381,6 +381,129 @@ void DropDown()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 收集当前方块将要固定到棋盘上的格子,并标记是否越过顶部。
|
||||||
|
* @param overflowTop 返回是否有方块格位于可视区域顶部之外。
|
||||||
|
* @param fixedCells 返回普通落地格,用于后续特殊效果定位。
|
||||||
|
* @param fixedCellCount 返回普通落地格数量。
|
||||||
|
* @param explosiveCells 返回爆破方块落地格。
|
||||||
|
* @param explosiveCellCount 返回爆破方块落地格数量。
|
||||||
|
*/
|
||||||
|
static void CollectAndWriteFixedCells(
|
||||||
|
bool& overflowTop,
|
||||||
|
Point fixedCells[],
|
||||||
|
int& fixedCellCount,
|
||||||
|
Point explosiveCells[],
|
||||||
|
int& explosiveCellCount)
|
||||||
|
{
|
||||||
|
overflowTop = false;
|
||||||
|
fixedCellCount = 0;
|
||||||
|
explosiveCellCount = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if (bricks[type][state][i][j] == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fixY = point.y + i;
|
||||||
|
int fixX = point.x + j;
|
||||||
|
|
||||||
|
// 顶部溢出只记录状态,真正的复活或结束逻辑在后续统一处理。
|
||||||
|
if (fixY < 0)
|
||||||
|
{
|
||||||
|
overflowTop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixY >= 0 && fixY < GetRoguePlayableHeight() && fixX >= 0 && fixX < nGameWidth)
|
||||||
|
{
|
||||||
|
workRegion[fixY][fixX] = currentPieceIsRainbow ? 8 : bricks[type][state][i][j];
|
||||||
|
if (fixedCellCount < 4)
|
||||||
|
{
|
||||||
|
fixedCells[fixedCellCount].x = fixX;
|
||||||
|
fixedCells[fixedCellCount].y = fixY;
|
||||||
|
fixedCellCount++;
|
||||||
|
}
|
||||||
|
if (currentPieceIsExplosive && explosiveCellCount < 4)
|
||||||
|
{
|
||||||
|
explosiveCells[explosiveCellCount].x = fixX;
|
||||||
|
explosiveCells[explosiveCellCount].y = fixY;
|
||||||
|
explosiveCellCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理方块固定时的顶部溢出、终末清场和最后一搏。
|
||||||
|
* @param overflowTop 是否出现顶部溢出。
|
||||||
|
* @return 溢出已被处理且游戏可以继续时返回 true;需要结束游戏时返回 false。
|
||||||
|
*/
|
||||||
|
static bool ResolveFixingOverflow(bool overflowTop)
|
||||||
|
{
|
||||||
|
if (!overflowTop)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMode == MODE_ROGUE && rogueStats.terminalClearLevel > 0 && rogueStats.lastChanceCount > 0 && rogueStats.screenBombCount > 0)
|
||||||
|
{
|
||||||
|
rogueStats.lastChanceCount--;
|
||||||
|
rogueStats.screenBombCount--;
|
||||||
|
|
||||||
|
int clearedByTerminal = TriggerScreenBomb();
|
||||||
|
rogueStats.feverTicks = 10;
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
|
||||||
|
TCHAR terminalDetail[128];
|
||||||
|
_stprintf_s(
|
||||||
|
terminalDetail,
|
||||||
|
_T("终末清场启动,清除 %d 格,并进入 10 秒狂热。"),
|
||||||
|
clearedByTerminal);
|
||||||
|
SetFeedbackMessage(_T("终末清场"), terminalDetail, 14);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMode == MODE_ROGUE && rogueStats.lastChanceCount > 0)
|
||||||
|
{
|
||||||
|
rogueStats.lastChanceCount--;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
DeleteOneLine(GetRoguePlayableHeight() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFeedbackMessage(
|
||||||
|
_T("最后一搏"),
|
||||||
|
_T("底部 3 行被清除,战局得以延续。"),
|
||||||
|
14);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameOverFlag = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 生成下一枚活动方块,并刷新 Hold、特殊方块和预测落点状态。
|
||||||
|
*/
|
||||||
|
static void SpawnNextFallingPiece()
|
||||||
|
{
|
||||||
|
// 消耗预览队列后重置本回合状态,确保 Hold 和特殊标记只影响新方块。
|
||||||
|
type = ConsumeNextType();
|
||||||
|
nType = nextTypes[0];
|
||||||
|
state = 0;
|
||||||
|
holdUsedThisTurn = false;
|
||||||
|
RollCurrentPieceSpecialFlags(true);
|
||||||
|
point = GetSpawnPoint(type);
|
||||||
|
target = point;
|
||||||
|
ComputeTarget();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 将当前活动方块固定到工作区,并生成下一个活动方块。
|
* @brief 将当前活动方块固定到工作区,并生成下一个活动方块。
|
||||||
*
|
*
|
||||||
@@ -400,81 +523,13 @@ void Fixing()
|
|||||||
int explosiveCellCount = 0;
|
int explosiveCellCount = 0;
|
||||||
pendingChainBombFollowup = false;
|
pendingChainBombFollowup = false;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
CollectAndWriteFixedCells(overflowTop, fixedCells, fixedCellCount, explosiveCells, explosiveCellCount);
|
||||||
{
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
if (bricks[type][state][i][j] != 0)
|
|
||||||
{
|
|
||||||
int fixY = point.y + i;
|
|
||||||
int fixX = point.x + j;
|
|
||||||
|
|
||||||
// 只要当前方块任意非空单元仍超出顶部,就标记为结束
|
|
||||||
if (fixY < 0)
|
|
||||||
{
|
|
||||||
overflowTop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将当前方块在可视区域内的部分写入工作区
|
|
||||||
if (fixY >= 0 && fixY < GetRoguePlayableHeight() && fixX >= 0 && fixX < nGameWidth)
|
|
||||||
{
|
|
||||||
workRegion[fixY][fixX] = currentPieceIsRainbow ? 8 : bricks[type][state][i][j];
|
|
||||||
if (fixedCellCount < 4)
|
|
||||||
{
|
|
||||||
fixedCells[fixedCellCount].x = fixX;
|
|
||||||
fixedCells[fixedCellCount].y = fixY;
|
|
||||||
fixedCellCount++;
|
|
||||||
}
|
|
||||||
if (currentPieceIsExplosive && explosiveCellCount < 4)
|
|
||||||
{
|
|
||||||
explosiveCells[explosiveCellCount].x = fixX;
|
|
||||||
explosiveCells[explosiveCellCount].y = fixY;
|
|
||||||
explosiveCellCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplyRainbowLandingEffect(overflowTop, fixedCells, fixedCellCount);
|
ApplyRainbowLandingEffect(overflowTop, fixedCells, fixedCellCount);
|
||||||
|
|
||||||
if (overflowTop)
|
if (!ResolveFixingOverflow(overflowTop))
|
||||||
{
|
{
|
||||||
if (currentMode == MODE_ROGUE && rogueStats.terminalClearLevel > 0 && rogueStats.lastChanceCount > 0 && rogueStats.screenBombCount > 0)
|
return;
|
||||||
{
|
|
||||||
rogueStats.lastChanceCount--;
|
|
||||||
rogueStats.screenBombCount--;
|
|
||||||
|
|
||||||
int clearedByTerminal = TriggerScreenBomb();
|
|
||||||
rogueStats.feverTicks = 10;
|
|
||||||
currentFallInterval = GetRogueFallInterval();
|
|
||||||
|
|
||||||
TCHAR terminalDetail[128];
|
|
||||||
_stprintf_s(
|
|
||||||
terminalDetail,
|
|
||||||
_T("终末清场启动,清除 %d 格,并进入 10 秒狂热。"),
|
|
||||||
clearedByTerminal);
|
|
||||||
SetFeedbackMessage(_T("终末清场"), terminalDetail, 14);
|
|
||||||
}
|
|
||||||
else if (currentMode == MODE_ROGUE && rogueStats.lastChanceCount > 0)
|
|
||||||
{
|
|
||||||
rogueStats.lastChanceCount--;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
DeleteOneLine(GetRoguePlayableHeight() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetFeedbackMessage(
|
|
||||||
_T("最后一搏"),
|
|
||||||
_T("底部 3 行被清除,战局得以延续。"),
|
|
||||||
14);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gameOverFlag = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplySpecialLandingEffects(fixedCells, fixedCellCount, explosiveCells, explosiveCellCount);
|
ApplySpecialLandingEffects(fixedCells, fixedCellCount, explosiveCells, explosiveCellCount);
|
||||||
@@ -484,15 +539,7 @@ void Fixing()
|
|||||||
currentFallInterval = GetRogueFallInterval();
|
currentFallInterval = GetRogueFallInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成下一个活动方块
|
SpawnNextFallingPiece();
|
||||||
type = ConsumeNextType();
|
|
||||||
nType = nextTypes[0];
|
|
||||||
state = 0;
|
|
||||||
holdUsedThisTurn = false;
|
|
||||||
RollCurrentPieceSpecialFlags(true);
|
|
||||||
point = GetSpawnPoint(type);
|
|
||||||
target = point;
|
|
||||||
ComputeTarget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -521,20 +568,15 @@ void DeleteOneLine(int number)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 检查并删除所有已满的行,同时更新当前得分。
|
* @brief 从底向上扫描满行并删除,记录本次消除的原始行号。
|
||||||
*
|
* @param clearedRows 返回最多 8 个被消除行号,用于播放消行动画。
|
||||||
* 该函数会从底部向上遍历工作区,判断每一行是否被完全填满。
|
* @param clearedRowCount 返回记录的行号数量。
|
||||||
* 如果某一行全部非 0,则调用 DeleteOneLine 删除该行,
|
* @return 本次标准消行数量。
|
||||||
* 并将该行上方的内容整体下移。为了避免连续满行被漏检,
|
|
||||||
* 删除后会继续检查当前行号。每成功消除 1 行,当前得分增加 100 分。
|
|
||||||
*
|
|
||||||
* @return 本次实际消除的行数。
|
|
||||||
*/
|
*/
|
||||||
int DeleteLines()
|
static int ScanAndDeleteFullLines(int clearedRows[], int& clearedRowCount)
|
||||||
{
|
{
|
||||||
int clearedLines = 0;
|
int clearedLines = 0;
|
||||||
int clearedRows[8] = {};
|
clearedRowCount = 0;
|
||||||
int clearedRowCount = 0;
|
|
||||||
|
|
||||||
int playableHeight = GetRoguePlayableHeight();
|
int playableHeight = GetRoguePlayableHeight();
|
||||||
for (int i = playableHeight - 1; i >= 0; i--)
|
for (int i = playableHeight - 1; i >= 0; i--)
|
||||||
@@ -564,8 +606,17 @@ int DeleteLines()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 消行数量先进入玩法结算,再根据是否正在升级决定动画立即播放还是暂存。
|
return clearedLines;
|
||||||
ApplyLineClearResult(clearedLines);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 根据当前界面状态立即播放或暂存消行动画。
|
||||||
|
* @param clearedRows 已消除行号数组。
|
||||||
|
* @param clearedRowCount 行号数量。
|
||||||
|
* @param clearedLines 本次消行数量。
|
||||||
|
*/
|
||||||
|
static void DispatchLineClearEffect(const int clearedRows[], int clearedRowCount, int clearedLines)
|
||||||
|
{
|
||||||
if (currentScreen == SCREEN_UPGRADE)
|
if (currentScreen == SCREEN_UPGRADE)
|
||||||
{
|
{
|
||||||
QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||||
@@ -574,55 +625,84 @@ int DeleteLines()
|
|||||||
{
|
{
|
||||||
TriggerLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
TriggerLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 连环炸弹的追加爆破只在爆破方块导致后续消行时触发一次。
|
/**
|
||||||
if (pendingChainBombFollowup && clearedLines > 0)
|
* @brief 处理连环炸弹因消行触发的一次追加 3x3 爆破。
|
||||||
|
* @param clearedLines 本次标准消行数量。
|
||||||
|
*/
|
||||||
|
static void ResolveChainBombFollowup(int clearedLines)
|
||||||
|
{
|
||||||
|
if (!pendingChainBombFollowup || clearedLines <= 0)
|
||||||
{
|
{
|
||||||
pendingChainBombFollowup = false;
|
pendingChainBombFollowup = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int followupCleared = 0;
|
pendingChainBombFollowup = false;
|
||||||
int centerY = pendingChainBombCenter.y;
|
|
||||||
int centerX = pendingChainBombCenter.x;
|
|
||||||
Point followupCells[9] = {};
|
|
||||||
|
|
||||||
for (int y = centerY - 1; y <= centerY + 1; y++)
|
int followupCleared = 0;
|
||||||
|
int centerY = pendingChainBombCenter.y;
|
||||||
|
int centerX = pendingChainBombCenter.x;
|
||||||
|
Point followupCells[9] = {};
|
||||||
|
|
||||||
|
for (int y = centerY - 1; y <= centerY + 1; y++)
|
||||||
|
{
|
||||||
|
for (int x = centerX - 1; x <= centerX + 1; x++)
|
||||||
{
|
{
|
||||||
for (int x = centerX - 1; x <= centerX + 1; x++)
|
if (y >= 0 && y < GetRoguePlayableHeight() && x >= 0 && x < nGameWidth && workRegion[y][x] != 0)
|
||||||
{
|
{
|
||||||
if (y >= 0 && y < GetRoguePlayableHeight() && x >= 0 && x < nGameWidth && workRegion[y][x] != 0)
|
if (followupCleared < 9)
|
||||||
{
|
{
|
||||||
if (followupCleared < 9)
|
followupCells[followupCleared].x = x;
|
||||||
{
|
followupCells[followupCleared].y = y;
|
||||||
followupCells[followupCleared].x = x;
|
|
||||||
followupCells[followupCleared].y = y;
|
|
||||||
}
|
|
||||||
workRegion[y][x] = 0;
|
|
||||||
followupCleared++;
|
|
||||||
}
|
}
|
||||||
|
workRegion[y][x] = 0;
|
||||||
|
followupCleared++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMode == MODE_ROGUE && followupCleared > 0)
|
|
||||||
{
|
|
||||||
TriggerCellClearEffect(followupCells, followupCleared < 9 ? followupCleared : 9, true);
|
|
||||||
int followupScore = 0;
|
|
||||||
int followupExp = 0;
|
|
||||||
AwardRogueSkillClearRewards(followupCleared, followupScore, followupExp, false);
|
|
||||||
|
|
||||||
TCHAR followupDetail[128];
|
|
||||||
_stprintf_s(
|
|
||||||
followupDetail,
|
|
||||||
_T("追加爆炸清除 %d 格 +%d 分 +%d EXP"),
|
|
||||||
followupCleared,
|
|
||||||
followupScore,
|
|
||||||
followupExp);
|
|
||||||
SetFeedbackMessage(_T("连环炸弹"), followupDetail, 12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (currentMode == MODE_ROGUE && followupCleared > 0)
|
||||||
{
|
{
|
||||||
pendingChainBombFollowup = false;
|
TriggerCellClearEffect(followupCells, followupCleared < 9 ? followupCleared : 9, true);
|
||||||
|
int followupScore = 0;
|
||||||
|
int followupExp = 0;
|
||||||
|
AwardRogueSkillClearRewards(followupCleared, followupScore, followupExp, false);
|
||||||
|
|
||||||
|
TCHAR followupDetail[128];
|
||||||
|
_stprintf_s(
|
||||||
|
followupDetail,
|
||||||
|
_T("追加爆炸清除 %d 格 +%d 分 +%d EXP"),
|
||||||
|
followupCleared,
|
||||||
|
followupScore,
|
||||||
|
followupExp);
|
||||||
|
SetFeedbackMessage(_T("连环炸弹"), followupDetail, 12);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查并删除所有已满的行,同时更新当前得分。
|
||||||
|
*
|
||||||
|
* 该函数会从底部向上遍历工作区,判断每一行是否被完全填满。
|
||||||
|
* 如果某一行全部非 0,则调用 DeleteOneLine 删除该行,
|
||||||
|
* 并将该行上方的内容整体下移。为了避免连续满行被漏检,
|
||||||
|
* 删除后会继续检查当前行号。每成功消除 1 行,当前得分增加 100 分。
|
||||||
|
*
|
||||||
|
* @return 本次实际消除的行数。
|
||||||
|
*/
|
||||||
|
int DeleteLines()
|
||||||
|
{
|
||||||
|
int clearedRows[8] = {};
|
||||||
|
int clearedRowCount = 0;
|
||||||
|
int clearedLines = ScanAndDeleteFullLines(clearedRows, clearedRowCount);
|
||||||
|
|
||||||
|
// 消行数量先进入玩法结算,再根据是否正在升级决定动画立即播放还是暂存。
|
||||||
|
ApplyLineClearResult(clearedLines);
|
||||||
|
DispatchLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||||
|
|
||||||
|
// 连环炸弹的追加爆破只在爆破方块导致后续消行时触发一次。
|
||||||
|
ResolveChainBombFollowup(clearedLines);
|
||||||
|
|
||||||
return clearedLines;
|
return clearedLines;
|
||||||
}
|
}
|
||||||
|
|||||||
+305
-178
@@ -417,6 +417,88 @@ static bool HandleMenuKey(HWND hWnd, WPARAM key)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在帮助首页选项之间循环移动。
|
||||||
|
* @param direction 负数向前,正数向后。
|
||||||
|
*/
|
||||||
|
static void MoveHelpHomeSelection(int direction)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex += direction;
|
||||||
|
if (helpState.selectedIndex < 0)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex = helpState.optionCount - 1;
|
||||||
|
}
|
||||||
|
if (helpState.selectedIndex >= helpState.optionCount)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在技能演示列表中移动选中项,并同步滚动偏移。
|
||||||
|
* @param direction 负数向上,正数向下。
|
||||||
|
*/
|
||||||
|
static void MoveSkillDemoSelection(int direction)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex += direction;
|
||||||
|
if (helpState.selectedIndex < 0)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex = GetRogueSkillDemoCount() - 1;
|
||||||
|
}
|
||||||
|
if (helpState.selectedIndex >= GetRogueSkillDemoCount())
|
||||||
|
{
|
||||||
|
helpState.selectedIndex = 0;
|
||||||
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
|
else if (direction < 0 && helpState.selectedIndex * 68 < helpScrollOffset)
|
||||||
|
{
|
||||||
|
helpScrollOffset = helpState.selectedIndex * 68;
|
||||||
|
}
|
||||||
|
else if (direction > 0 && helpState.selectedIndex * 68 > helpScrollOffset + 360)
|
||||||
|
{
|
||||||
|
helpScrollOffset = helpState.selectedIndex * 68 - 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 打开帮助首页当前选中的子页面。
|
||||||
|
*/
|
||||||
|
static void ActivateHelpSelection()
|
||||||
|
{
|
||||||
|
if (helpState.selectedIndex == 3)
|
||||||
|
{
|
||||||
|
helpState.currentPage = 5;
|
||||||
|
helpState.selectedIndex = 0;
|
||||||
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
helpState.currentPage = helpState.selectedIndex + 1;
|
||||||
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从帮助子页返回帮助首页或主菜单。
|
||||||
|
*/
|
||||||
|
static void LeaveRulesPage()
|
||||||
|
{
|
||||||
|
int previousPage = helpState.currentPage;
|
||||||
|
if (helpState.currentPage == 0)
|
||||||
|
{
|
||||||
|
ReturnToMainMenu();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
helpState.currentPage = 0;
|
||||||
|
if (previousPage == 4 || previousPage == 5)
|
||||||
|
{
|
||||||
|
helpState.selectedIndex = 3;
|
||||||
|
}
|
||||||
|
helpScrollOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 处理帮助和致谢页键盘导航。
|
* @brief 处理帮助和致谢页键盘导航。
|
||||||
* @param hWnd 当前窗口句柄。
|
* @param hWnd 当前窗口句柄。
|
||||||
@@ -438,11 +520,7 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
case 'A':
|
case 'A':
|
||||||
if (helpState.currentPage == 0)
|
if (helpState.currentPage == 0)
|
||||||
{
|
{
|
||||||
helpState.selectedIndex--;
|
MoveHelpHomeSelection(-1);
|
||||||
if (helpState.selectedIndex < 0)
|
|
||||||
{
|
|
||||||
helpState.selectedIndex = helpState.optionCount - 1;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
else if (helpState.currentPage == 4)
|
else if (helpState.currentPage == 4)
|
||||||
@@ -452,15 +530,7 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
}
|
}
|
||||||
else if (helpState.currentPage == 5)
|
else if (helpState.currentPage == 5)
|
||||||
{
|
{
|
||||||
helpState.selectedIndex--;
|
MoveSkillDemoSelection(-1);
|
||||||
if (helpState.selectedIndex < 0)
|
|
||||||
{
|
|
||||||
helpState.selectedIndex = GetRogueSkillDemoCount() - 1;
|
|
||||||
}
|
|
||||||
if (helpState.selectedIndex * 68 < helpScrollOffset)
|
|
||||||
{
|
|
||||||
helpScrollOffset = helpState.selectedIndex * 68;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -470,11 +540,7 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
case 'D':
|
case 'D':
|
||||||
if (helpState.currentPage == 0)
|
if (helpState.currentPage == 0)
|
||||||
{
|
{
|
||||||
helpState.selectedIndex++;
|
MoveHelpHomeSelection(1);
|
||||||
if (helpState.selectedIndex >= helpState.optionCount)
|
|
||||||
{
|
|
||||||
helpState.selectedIndex = 0;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
else if (helpState.currentPage == 4)
|
else if (helpState.currentPage == 4)
|
||||||
@@ -484,16 +550,7 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
}
|
}
|
||||||
else if (helpState.currentPage == 5)
|
else if (helpState.currentPage == 5)
|
||||||
{
|
{
|
||||||
helpState.selectedIndex++;
|
MoveSkillDemoSelection(1);
|
||||||
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);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -501,17 +558,7 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
case VK_SPACE:
|
case VK_SPACE:
|
||||||
if (helpState.currentPage == 0)
|
if (helpState.currentPage == 0)
|
||||||
{
|
{
|
||||||
if (helpState.selectedIndex == 3)
|
ActivateHelpSelection();
|
||||||
{
|
|
||||||
helpState.currentPage = 5;
|
|
||||||
helpState.selectedIndex = 0;
|
|
||||||
helpScrollOffset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
helpState.currentPage = helpState.selectedIndex + 1;
|
|
||||||
helpScrollOffset = 0;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
else if (helpState.currentPage == 5)
|
else if (helpState.currentPage == 5)
|
||||||
@@ -524,24 +571,9 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
case VK_ESCAPE:
|
case VK_ESCAPE:
|
||||||
case VK_BACK:
|
case VK_BACK:
|
||||||
case 'M':
|
case 'M':
|
||||||
{
|
LeaveRulesPage();
|
||||||
int previousPage = helpState.currentPage;
|
|
||||||
if (helpState.currentPage == 0)
|
|
||||||
{
|
|
||||||
ReturnToMainMenu();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
helpState.currentPage = 0;
|
|
||||||
if (previousPage == 4 || previousPage == 5)
|
|
||||||
{
|
|
||||||
helpState.selectedIndex = 3;
|
|
||||||
}
|
|
||||||
helpScrollOffset = 0;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -549,6 +581,92 @@ static bool HandleRulesKey(HWND hWnd, WPARAM key)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算升级卡片网格列数。
|
||||||
|
* @return 当前升级界面使用的列数,至少为 1。
|
||||||
|
*/
|
||||||
|
static int GetUpgradeColumnCount()
|
||||||
|
{
|
||||||
|
int upgradeColumnCount = upgradeUiState.optionCount <= 3 ? upgradeUiState.optionCount : 3;
|
||||||
|
if (upgradeColumnCount < 1)
|
||||||
|
{
|
||||||
|
upgradeColumnCount = 1;
|
||||||
|
}
|
||||||
|
return upgradeColumnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在升级卡片网格中横向移动选中项。
|
||||||
|
* @param direction 负数向左,正数向右。
|
||||||
|
*/
|
||||||
|
static void MoveUpgradeSelectionHorizontal(int direction)
|
||||||
|
{
|
||||||
|
if (upgradeUiState.optionCount <= 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int upgradeColumnCount = GetUpgradeColumnCount();
|
||||||
|
int rowStart = upgradeUiState.selectedIndex - (upgradeUiState.selectedIndex % upgradeColumnCount);
|
||||||
|
int rowEnd = rowStart + upgradeColumnCount - 1;
|
||||||
|
if (rowEnd >= upgradeUiState.optionCount)
|
||||||
|
{
|
||||||
|
rowEnd = upgradeUiState.optionCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction < 0)
|
||||||
|
{
|
||||||
|
upgradeUiState.selectedIndex = (upgradeUiState.selectedIndex > rowStart) ? upgradeUiState.selectedIndex - 1 : rowEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
upgradeUiState.selectedIndex = (upgradeUiState.selectedIndex < rowEnd) ? upgradeUiState.selectedIndex + 1 : rowStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在升级卡片网格中纵向移动选中项。
|
||||||
|
* @param direction 负数向上,正数向下。
|
||||||
|
*/
|
||||||
|
static void MoveUpgradeSelectionVertical(int direction)
|
||||||
|
{
|
||||||
|
int upgradeColumnCount = GetUpgradeColumnCount();
|
||||||
|
if (direction < 0 && upgradeUiState.selectedIndex >= upgradeColumnCount)
|
||||||
|
{
|
||||||
|
upgradeUiState.selectedIndex -= upgradeColumnCount;
|
||||||
|
}
|
||||||
|
else if (direction > 0 && upgradeUiState.selectedIndex + upgradeColumnCount < upgradeUiState.optionCount)
|
||||||
|
{
|
||||||
|
upgradeUiState.selectedIndex += upgradeColumnCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 切换多选升级中的当前卡片标记状态。
|
||||||
|
*/
|
||||||
|
static void ToggleUpgradeMarkedSelection()
|
||||||
|
{
|
||||||
|
if (upgradeUiState.picksRemaining <= 1 || upgradeUiState.optionCount <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool currentlyMarked = upgradeUiState.marked[upgradeUiState.selectedIndex];
|
||||||
|
if (currentlyMarked)
|
||||||
|
{
|
||||||
|
upgradeUiState.marked[upgradeUiState.selectedIndex] = false;
|
||||||
|
if (upgradeUiState.markedCount > 0)
|
||||||
|
{
|
||||||
|
upgradeUiState.markedCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (upgradeUiState.markedCount < upgradeUiState.picksRemaining)
|
||||||
|
{
|
||||||
|
upgradeUiState.marked[upgradeUiState.selectedIndex] = true;
|
||||||
|
upgradeUiState.markedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 处理升级选择界面键盘导航。
|
* @brief 处理升级选择界面键盘导航。
|
||||||
* @param hWnd 当前窗口句柄。
|
* @param hWnd 当前窗口句柄。
|
||||||
@@ -562,64 +680,26 @@ static bool HandleUpgradeKey(HWND hWnd, WPARAM key)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int upgradeColumnCount = upgradeUiState.optionCount <= 3 ? upgradeUiState.optionCount : 3;
|
|
||||||
if (upgradeColumnCount < 1)
|
|
||||||
{
|
|
||||||
upgradeColumnCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case VK_LEFT:
|
case VK_LEFT:
|
||||||
case 'A':
|
case 'A':
|
||||||
if (upgradeUiState.optionCount > 1)
|
MoveUpgradeSelectionHorizontal(-1);
|
||||||
{
|
|
||||||
int rowStart = upgradeUiState.selectedIndex - (upgradeUiState.selectedIndex % upgradeColumnCount);
|
|
||||||
if (upgradeUiState.selectedIndex > rowStart)
|
|
||||||
{
|
|
||||||
upgradeUiState.selectedIndex--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int rowEnd = rowStart + upgradeColumnCount - 1;
|
|
||||||
if (rowEnd >= upgradeUiState.optionCount)
|
|
||||||
{
|
|
||||||
rowEnd = upgradeUiState.optionCount - 1;
|
|
||||||
}
|
|
||||||
upgradeUiState.selectedIndex = rowEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
case VK_RIGHT:
|
case VK_RIGHT:
|
||||||
case 'D':
|
case 'D':
|
||||||
if (upgradeUiState.optionCount > 1)
|
MoveUpgradeSelectionHorizontal(1);
|
||||||
{
|
|
||||||
int rowStart = upgradeUiState.selectedIndex - (upgradeUiState.selectedIndex % upgradeColumnCount);
|
|
||||||
int rowEnd = rowStart + upgradeColumnCount - 1;
|
|
||||||
if (rowEnd >= upgradeUiState.optionCount)
|
|
||||||
{
|
|
||||||
rowEnd = upgradeUiState.optionCount - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
upgradeUiState.selectedIndex = (upgradeUiState.selectedIndex < rowEnd) ? upgradeUiState.selectedIndex + 1 : rowStart;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
case VK_UP:
|
case VK_UP:
|
||||||
case 'W':
|
case 'W':
|
||||||
if (upgradeUiState.selectedIndex >= upgradeColumnCount)
|
MoveUpgradeSelectionVertical(-1);
|
||||||
{
|
|
||||||
upgradeUiState.selectedIndex -= upgradeColumnCount;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
case VK_DOWN:
|
case VK_DOWN:
|
||||||
case 'S':
|
case 'S':
|
||||||
if (upgradeUiState.selectedIndex + upgradeColumnCount < upgradeUiState.optionCount)
|
MoveUpgradeSelectionVertical(1);
|
||||||
{
|
|
||||||
upgradeUiState.selectedIndex += upgradeColumnCount;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
break;
|
break;
|
||||||
case VK_RETURN:
|
case VK_RETURN:
|
||||||
@@ -630,20 +710,7 @@ static bool HandleUpgradeKey(HWND hWnd, WPARAM key)
|
|||||||
case VK_SPACE:
|
case VK_SPACE:
|
||||||
if (upgradeUiState.picksRemaining > 1 && upgradeUiState.optionCount > 0)
|
if (upgradeUiState.picksRemaining > 1 && upgradeUiState.optionCount > 0)
|
||||||
{
|
{
|
||||||
bool currentlyMarked = upgradeUiState.marked[upgradeUiState.selectedIndex];
|
ToggleUpgradeMarkedSelection();
|
||||||
if (currentlyMarked)
|
|
||||||
{
|
|
||||||
upgradeUiState.marked[upgradeUiState.selectedIndex] = false;
|
|
||||||
if (upgradeUiState.markedCount > 0)
|
|
||||||
{
|
|
||||||
upgradeUiState.markedCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (upgradeUiState.markedCount < upgradeUiState.picksRemaining)
|
|
||||||
{
|
|
||||||
upgradeUiState.marked[upgradeUiState.selectedIndex] = true;
|
|
||||||
upgradeUiState.markedCount++;
|
|
||||||
}
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -665,40 +732,54 @@ static bool HandleUpgradeKey(HWND hWnd, WPARAM key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 处理游戏过程中的按键。
|
* @brief 处理 Rogue 技能演示模式的专用按键。
|
||||||
* @param hWnd 当前窗口句柄。
|
* @param hWnd 当前窗口句柄。
|
||||||
* @param key 按键虚拟键码。
|
* @param key 按键虚拟键码。
|
||||||
|
* @return 已处理返回 true。
|
||||||
*/
|
*/
|
||||||
static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
static bool HandleDemoPlayingKey(HWND hWnd, WPARAM key)
|
||||||
{
|
{
|
||||||
if (IsRogueSkillDemoMode())
|
if (!IsRogueSkillDemoMode())
|
||||||
{
|
{
|
||||||
if (key == 'N')
|
return false;
|
||||||
{
|
|
||||||
AdvanceRogueSkillDemo();
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (key == 'R')
|
|
||||||
{
|
|
||||||
RestartCurrentRogueSkillDemo();
|
|
||||||
ResetGameTimer(hWnd);
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (key == VK_ESCAPE || key == VK_BACK || key == 'M')
|
|
||||||
{
|
|
||||||
OpenSkillDemoScreen();
|
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == 'N')
|
||||||
|
{
|
||||||
|
AdvanceRogueSkillDemo();
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == 'R')
|
||||||
|
{
|
||||||
|
RestartCurrentRogueSkillDemo();
|
||||||
|
ResetGameTimer(hWnd);
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == VK_ESCAPE || key == VK_BACK || key == 'M')
|
||||||
|
{
|
||||||
|
OpenSkillDemoScreen();
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理正常战局控制键,如菜单、重开、暂停、目标提示和复活。
|
||||||
|
* @param hWnd 当前窗口句柄。
|
||||||
|
* @param key 按键虚拟键码。
|
||||||
|
* @return 已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool HandleBattleControlKey(HWND hWnd, WPARAM key)
|
||||||
|
{
|
||||||
if (!IsRogueSkillDemoMode() && key == 'M')
|
if (!IsRogueSkillDemoMode() && key == 'M')
|
||||||
{
|
{
|
||||||
ReturnToMainMenu();
|
ReturnToMainMenu();
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsRogueSkillDemoMode() && key == 'R')
|
if (!IsRogueSkillDemoMode() && key == 'R')
|
||||||
@@ -706,21 +787,21 @@ static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
|||||||
StartGameWithMode(currentMode);
|
StartGameWithMode(currentMode);
|
||||||
ResetGameTimer(hWnd);
|
ResetGameTimer(hWnd);
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsRogueSkillDemoMode() && key == 'P')
|
if (!IsRogueSkillDemoMode() && key == 'P')
|
||||||
{
|
{
|
||||||
suspendFlag = !suspendFlag;
|
suspendFlag = !suspendFlag;
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == 'G')
|
if (key == 'G')
|
||||||
{
|
{
|
||||||
targetFlag = !targetFlag;
|
targetFlag = !targetFlag;
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameOverFlag && reviveAvailable && key == 'V')
|
if (gameOverFlag && reviveAvailable && key == 'V')
|
||||||
@@ -735,23 +816,70 @@ static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
|||||||
SetFeedbackMessage(_T("视频播放失败"), _T("无法打开复活视频,复活机会未消耗。"), 14);
|
SetFeedbackMessage(_T("视频播放失败"), _T("无法打开复活视频,复活机会未消耗。"), 14);
|
||||||
}
|
}
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameOverFlag || suspendFlag)
|
return false;
|
||||||
{
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理 Rogue 侧栏滚动和主动技能按键。
|
||||||
|
* @param hWnd 当前窗口句柄。
|
||||||
|
* @param key 按键虚拟键码。
|
||||||
|
* @return 已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool HandleRogueSkillKey(HWND hWnd, WPARAM key)
|
||||||
|
{
|
||||||
if (currentMode == MODE_ROGUE && (key == 'J' || key == 'K'))
|
if (currentMode == MODE_ROGUE && (key == 'J' || key == 'K'))
|
||||||
{
|
{
|
||||||
int direction = (key == 'J') ? 1 : -1;
|
int direction = (key == 'J') ? 1 : -1;
|
||||||
AdjustScrollOffset(upgradeListScrollOffset, direction * GetScrollStep(hWnd, 52));
|
AdjustScrollOffset(upgradeListScrollOffset, direction * GetScrollStep(hWnd, 52));
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 正常游玩按键先改变方块或触发技能,再统一刷新预测落点和界面。
|
switch (key)
|
||||||
|
{
|
||||||
|
case 'C':
|
||||||
|
case VK_SHIFT:
|
||||||
|
case VK_LSHIFT:
|
||||||
|
case VK_RSHIFT:
|
||||||
|
HoldCurrentPiece();
|
||||||
|
return true;
|
||||||
|
case 'Z':
|
||||||
|
UseBlackHole();
|
||||||
|
return true;
|
||||||
|
case 'X':
|
||||||
|
UseScreenBomb();
|
||||||
|
return true;
|
||||||
|
case 'V':
|
||||||
|
UseAirReshape();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 固定当前方块后执行消行和 Rogue 升级检查。
|
||||||
|
*/
|
||||||
|
static void FixPieceAndResolveLines()
|
||||||
|
{
|
||||||
|
Fixing();
|
||||||
|
if (!gameOverFlag)
|
||||||
|
{
|
||||||
|
DeleteLines();
|
||||||
|
CheckRogueLevelProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理移动、旋转、软降和硬降等方块操作键。
|
||||||
|
* @param key 按键虚拟键码。
|
||||||
|
* @return 已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool HandlePieceMovementKey(WPARAM key)
|
||||||
|
{
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case VK_LEFT:
|
case VK_LEFT:
|
||||||
@@ -760,14 +888,14 @@ static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
|||||||
{
|
{
|
||||||
MoveLeft();
|
MoveLeft();
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
case VK_RIGHT:
|
case VK_RIGHT:
|
||||||
case 'D':
|
case 'D':
|
||||||
if (CanMoveRight())
|
if (CanMoveRight())
|
||||||
{
|
{
|
||||||
MoveRight();
|
MoveRight();
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
case VK_DOWN:
|
case VK_DOWN:
|
||||||
case 'S':
|
case 'S':
|
||||||
if (CanMoveDown())
|
if (CanMoveDown())
|
||||||
@@ -776,44 +904,43 @@ static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Fixing();
|
FixPieceAndResolveLines();
|
||||||
if (!gameOverFlag)
|
|
||||||
{
|
|
||||||
DeleteLines();
|
|
||||||
CheckRogueLevelProgress();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
case VK_UP:
|
case VK_UP:
|
||||||
case 'W':
|
case 'W':
|
||||||
Rotate();
|
Rotate();
|
||||||
break;
|
return true;
|
||||||
case VK_SPACE:
|
case VK_SPACE:
|
||||||
DropDown();
|
DropDown();
|
||||||
Fixing();
|
FixPieceAndResolveLines();
|
||||||
if (!gameOverFlag)
|
return true;
|
||||||
{
|
|
||||||
DeleteLines();
|
|
||||||
CheckRogueLevelProgress();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
case VK_SHIFT:
|
|
||||||
case VK_LSHIFT:
|
|
||||||
case VK_RSHIFT:
|
|
||||||
HoldCurrentPiece();
|
|
||||||
break;
|
|
||||||
case 'Z':
|
|
||||||
UseBlackHole();
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
UseScreenBomb();
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
UseAirReshape();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理游戏过程中的按键。
|
||||||
|
* @param hWnd 当前窗口句柄。
|
||||||
|
* @param key 按键虚拟键码。
|
||||||
|
*/
|
||||||
|
static void HandlePlayingKey(HWND hWnd, WPARAM key)
|
||||||
|
{
|
||||||
|
if (HandleDemoPlayingKey(hWnd, key) || HandleBattleControlKey(hWnd, key))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameOverFlag || suspendFlag)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正常游玩按键先改变方块或触发技能,再统一刷新预测落点和界面。
|
||||||
|
if (!HandlePieceMovementKey(key))
|
||||||
|
{
|
||||||
|
HandleRogueSkillKey(hWnd, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gameOverFlag)
|
if (!gameOverFlag)
|
||||||
|
|||||||
+459
-335
@@ -1555,18 +1555,15 @@ static int TriggerUpgradeShockwave(int rowsToClear)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 按权重和当前局势生成升级菜单中的候选强化。
|
* @brief 收集当前可进入升级池的强化下标和动态权重。
|
||||||
*
|
* @param selectableIndexes 返回候选在强化池中的下标。
|
||||||
* 该函数只负责生成 UI 选项,不应用强化效果。候选池会先过滤前置、
|
* @param selectableWeights 返回候选动态权重。
|
||||||
* 等级上限和互斥条件,再按动态权重不放回抽取,保证同一轮不会重复出现。
|
* @return 候选数量。
|
||||||
*/
|
*/
|
||||||
static void FillUpgradeOptions()
|
static int CollectSelectableUpgrades(int selectableIndexes[], int selectableWeights[])
|
||||||
{
|
{
|
||||||
int selectableIndexes[kUpgradePoolSize] = { 0 };
|
|
||||||
int selectableWeights[kUpgradePoolSize] = { 0 };
|
|
||||||
int selectableCount = 0;
|
int selectableCount = 0;
|
||||||
|
|
||||||
// 第一段:筛出当前真正可选的强化,并记录它们的动态权重。
|
|
||||||
for (int i = 0; i < kUpgradePoolSize; i++)
|
for (int i = 0; i < kUpgradePoolSize; i++)
|
||||||
{
|
{
|
||||||
if (IsUpgradeSelectable(kUpgradePool[i]))
|
if (IsUpgradeSelectable(kUpgradePool[i]))
|
||||||
@@ -1577,7 +1574,16 @@ static void FillUpgradeOptions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 命运轮盘把候选扩到 6 个;双重抉择和命运轮盘都会允许本轮选 2 个。
|
return selectableCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化本轮升级界面的数量、选中项和多选状态。
|
||||||
|
* @param selectableCount 当前可选候选数量。
|
||||||
|
* @return 本轮实际展示的选项数量。
|
||||||
|
*/
|
||||||
|
static int PrepareUpgradeOptionState(int selectableCount)
|
||||||
|
{
|
||||||
int optionLimit = (rogueStats.destinyWheelLevel > 0) ? 6 : 3;
|
int optionLimit = (rogueStats.destinyWheelLevel > 0) ? 6 : 3;
|
||||||
int optionCount = selectableCount < optionLimit ? selectableCount : optionLimit;
|
int optionCount = selectableCount < optionLimit ? selectableCount : optionLimit;
|
||||||
upgradeUiState.optionCount = optionCount;
|
upgradeUiState.optionCount = optionCount;
|
||||||
@@ -1589,71 +1595,114 @@ static void FillUpgradeOptions()
|
|||||||
upgradeUiState.marked[i] = false;
|
upgradeUiState.marked[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return optionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按权重从候选数组中抽取一个槽位。
|
||||||
|
* @param selectableWeights 候选权重数组。
|
||||||
|
* @param selectableCount 候选数量。
|
||||||
|
* @return 被抽中的候选槽位。
|
||||||
|
*/
|
||||||
|
static int PickUpgradeSlotByWeight(const int selectableWeights[], int selectableCount)
|
||||||
|
{
|
||||||
|
int totalWeight = 0;
|
||||||
|
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
|
||||||
|
{
|
||||||
|
totalWeight += selectableWeights[weightIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
int pickSlot = 0;
|
||||||
|
if (totalWeight > 0)
|
||||||
|
{
|
||||||
|
int roll = rand() % totalWeight;
|
||||||
|
int accumulatedWeight = 0;
|
||||||
|
|
||||||
|
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
|
||||||
|
{
|
||||||
|
accumulatedWeight += selectableWeights[weightIndex];
|
||||||
|
if (roll < accumulatedWeight)
|
||||||
|
{
|
||||||
|
pickSlot = weightIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pickSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将抽中的强化池条目写入升级 UI 选项。
|
||||||
|
* @param optionIndex UI 选项下标。
|
||||||
|
* @param pickedEntry 被抽中的强化池条目。
|
||||||
|
*/
|
||||||
|
static void FillUpgradeOptionFromEntry(int optionIndex, const UpgradeEntry& pickedEntry)
|
||||||
|
{
|
||||||
|
upgradeUiState.options[optionIndex].id = pickedEntry.id;
|
||||||
|
upgradeUiState.options[optionIndex].currentLevel = GetUpgradeCurrentLevel(pickedEntry.id);
|
||||||
|
upgradeUiState.options[optionIndex].targetPieceType = -1;
|
||||||
|
upgradeUiState.options[optionIndex].rarity = GetUpgradeBaseRarity(pickedEntry.id);
|
||||||
|
upgradeUiState.options[optionIndex].cursed = false;
|
||||||
|
upgradeUiState.options[optionIndex].name = pickedEntry.name;
|
||||||
|
upgradeUiState.options[optionIndex].category = pickedEntry.category;
|
||||||
|
upgradeUiState.options[optionIndex].description = pickedEntry.description;
|
||||||
|
|
||||||
|
if (pickedEntry.id == UPGRADE_PIECE_TUNING)
|
||||||
|
{
|
||||||
|
int targetPieceType = 0;
|
||||||
|
upgradeUiState.options[optionIndex].targetPieceType = targetPieceType;
|
||||||
|
upgradeUiState.options[optionIndex].currentLevel = rogueStats.pieceTuningLevels[0];
|
||||||
|
upgradeUiState.options[optionIndex].name = _T("方块改造");
|
||||||
|
|
||||||
|
static TCHAR tuningDescriptions[6][64];
|
||||||
|
_stprintf_s(
|
||||||
|
tuningDescriptions[optionIndex],
|
||||||
|
_T("%s 块的生成概率提高。"),
|
||||||
|
GetPieceShortName(0));
|
||||||
|
upgradeUiState.options[optionIndex].description = tuningDescriptions[optionIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命运轮盘生效时,为本轮候选随机附加一个诅咒标记。
|
||||||
|
* @param optionCount 本轮展示选项数量。
|
||||||
|
*/
|
||||||
|
static void MarkDestinyCursedOption(int optionCount)
|
||||||
|
{
|
||||||
|
if (rogueStats.destinyWheelLevel > 0 && optionCount > 0)
|
||||||
|
{
|
||||||
|
int cursedIndex = rand() % optionCount;
|
||||||
|
upgradeUiState.options[cursedIndex].cursed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按权重和当前局势生成升级菜单中的候选强化。
|
||||||
|
*
|
||||||
|
* 该函数只负责生成 UI 选项,不应用强化效果。候选池会先过滤前置、
|
||||||
|
* 等级上限和互斥条件,再按动态权重不放回抽取,保证同一轮不会重复出现。
|
||||||
|
*/
|
||||||
|
static void FillUpgradeOptions()
|
||||||
|
{
|
||||||
|
int selectableIndexes[kUpgradePoolSize] = { 0 };
|
||||||
|
int selectableWeights[kUpgradePoolSize] = { 0 };
|
||||||
|
int selectableCount = CollectSelectableUpgrades(selectableIndexes, selectableWeights);
|
||||||
|
int optionCount = PrepareUpgradeOptionState(selectableCount);
|
||||||
|
|
||||||
// 第二段:按权重不放回抽取候选,抽中后用末尾元素覆盖当前槽位。
|
// 第二段:按权重不放回抽取候选,抽中后用末尾元素覆盖当前槽位。
|
||||||
for (int i = 0; i < optionCount; i++)
|
for (int i = 0; i < optionCount; i++)
|
||||||
{
|
{
|
||||||
int totalWeight = 0;
|
int pickSlot = PickUpgradeSlotByWeight(selectableWeights, selectableCount);
|
||||||
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
|
|
||||||
{
|
|
||||||
totalWeight += selectableWeights[weightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
int pickSlot = 0;
|
|
||||||
if (totalWeight > 0)
|
|
||||||
{
|
|
||||||
int roll = rand() % totalWeight;
|
|
||||||
int accumulatedWeight = 0;
|
|
||||||
|
|
||||||
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
|
|
||||||
{
|
|
||||||
accumulatedWeight += selectableWeights[weightIndex];
|
|
||||||
if (roll < accumulatedWeight)
|
|
||||||
{
|
|
||||||
pickSlot = weightIndex;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int pickedIndex = selectableIndexes[pickSlot];
|
int pickedIndex = selectableIndexes[pickSlot];
|
||||||
const UpgradeEntry& pickedEntry = kUpgradePool[pickedIndex];
|
FillUpgradeOptionFromEntry(i, kUpgradePool[pickedIndex]);
|
||||||
|
|
||||||
upgradeUiState.options[i].id = pickedEntry.id;
|
|
||||||
upgradeUiState.options[i].currentLevel = GetUpgradeCurrentLevel(pickedEntry.id);
|
|
||||||
upgradeUiState.options[i].targetPieceType = -1;
|
|
||||||
upgradeUiState.options[i].rarity = GetUpgradeBaseRarity(pickedEntry.id);
|
|
||||||
upgradeUiState.options[i].cursed = false;
|
|
||||||
upgradeUiState.options[i].name = pickedEntry.name;
|
|
||||||
upgradeUiState.options[i].category = pickedEntry.category;
|
|
||||||
upgradeUiState.options[i].description = pickedEntry.description;
|
|
||||||
|
|
||||||
// 方块改造目前固定展示 I 块概率提升,说明文字需要运行时拼接。
|
|
||||||
if (pickedEntry.id == UPGRADE_PIECE_TUNING)
|
|
||||||
{
|
|
||||||
int targetPieceType = 0;
|
|
||||||
upgradeUiState.options[i].targetPieceType = targetPieceType;
|
|
||||||
upgradeUiState.options[i].currentLevel = rogueStats.pieceTuningLevels[0];
|
|
||||||
upgradeUiState.options[i].name = _T("方块改造");
|
|
||||||
|
|
||||||
static TCHAR tuningDescriptions[6][64];
|
|
||||||
_stprintf_s(
|
|
||||||
tuningDescriptions[i],
|
|
||||||
_T("%s 块的生成概率提高。"),
|
|
||||||
GetPieceShortName(0));
|
|
||||||
upgradeUiState.options[i].description = tuningDescriptions[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
selectableIndexes[pickSlot] = selectableIndexes[selectableCount - 1];
|
selectableIndexes[pickSlot] = selectableIndexes[selectableCount - 1];
|
||||||
selectableWeights[pickSlot] = selectableWeights[selectableCount - 1];
|
selectableWeights[pickSlot] = selectableWeights[selectableCount - 1];
|
||||||
selectableCount--;
|
selectableCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 命运轮盘在候选中随机附加一个诅咒,确认时才提高下一次升级需求。
|
MarkDestinyCursedOption(optionCount);
|
||||||
if (rogueStats.destinyWheelLevel > 0 && optionCount > 0)
|
|
||||||
{
|
|
||||||
int cursedIndex = rand() % optionCount;
|
|
||||||
upgradeUiState.options[cursedIndex].cursed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1708,6 +1757,241 @@ int GetRogueFallInterval()
|
|||||||
return baseInterval;
|
return baseInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 应用成长、保命和基础操作类强化。
|
||||||
|
* @param upgradeId 强化编号。
|
||||||
|
* @param applyCount 本次应用次数。
|
||||||
|
* @return 当前强化已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool ApplyGrowthOrOperationUpgrade(int upgradeId, int applyCount)
|
||||||
|
{
|
||||||
|
switch (upgradeId)
|
||||||
|
{
|
||||||
|
case UPGRADE_SCORE_MULTIPLIER:
|
||||||
|
rogueStats.scoreMultiplierPercent += 20 * applyCount;
|
||||||
|
rogueStats.scoreUpgradeLevel += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_COMBO_BONUS:
|
||||||
|
rogueStats.comboBonusStacks += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_EXP_MULTIPLIER:
|
||||||
|
rogueStats.expMultiplierPercent += 25 * applyCount;
|
||||||
|
rogueStats.expUpgradeLevel += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_SLOW_FALL:
|
||||||
|
rogueStats.slowFallStacks += applyCount;
|
||||||
|
if (rogueStats.slowFallStacks > 4)
|
||||||
|
{
|
||||||
|
rogueStats.slowFallStacks = 4;
|
||||||
|
}
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
return true;
|
||||||
|
case UPGRADE_PREVIEW_PLUS_ONE:
|
||||||
|
if (rogueStats.previewCount < 2)
|
||||||
|
{
|
||||||
|
rogueStats.previewCount = 2;
|
||||||
|
}
|
||||||
|
rogueStats.previewUpgradeLevel = rogueStats.previewCount - 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_LAST_CHANCE:
|
||||||
|
rogueStats.lastChanceCount += applyCount;
|
||||||
|
rogueStats.lastChanceUpgradeLevel += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_HOLD_UNLOCK:
|
||||||
|
rogueStats.holdUnlocked = 1;
|
||||||
|
holdUsedThisTurn = false;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_PERFECT_ROTATE:
|
||||||
|
rogueStats.perfectRotateLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_TIME_DILATION:
|
||||||
|
rogueStats.timeDilationLevel = 1;
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
return true;
|
||||||
|
case UPGRADE_CONTROL_MASTER:
|
||||||
|
rogueStats.controlMasterLevel = 1;
|
||||||
|
if (rogueStats.previewCount < 3)
|
||||||
|
{
|
||||||
|
rogueStats.previewCount++;
|
||||||
|
}
|
||||||
|
rogueStats.previewUpgradeLevel = rogueStats.previewCount - 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_DOUBLE_GROWTH:
|
||||||
|
rogueStats.doubleGrowthLevel = 1;
|
||||||
|
rogueStats.scoreMultiplierPercent += 15;
|
||||||
|
rogueStats.expMultiplierPercent += 15;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 应用特殊方块和落地派生类强化。
|
||||||
|
* @param upgradeId 强化编号。
|
||||||
|
* @param applyCount 本次应用次数。
|
||||||
|
* @return 当前强化已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool ApplySpecialPieceUpgrade(int upgradeId, int applyCount)
|
||||||
|
{
|
||||||
|
switch (upgradeId)
|
||||||
|
{
|
||||||
|
case UPGRADE_PRESSURE_RELIEF:
|
||||||
|
rogueStats.pressureReliefLevel += applyCount;
|
||||||
|
for (int i = 0; i < applyCount; i++)
|
||||||
|
{
|
||||||
|
int topOccupiedRow = GetTopOccupiedRow();
|
||||||
|
if (topOccupiedRow >= 0)
|
||||||
|
{
|
||||||
|
DeleteOneLine(topOccupiedRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case UPGRADE_SWEEPER:
|
||||||
|
rogueStats.sweeperLevel += applyCount;
|
||||||
|
if (rogueStats.sweeperLevel > 4)
|
||||||
|
{
|
||||||
|
rogueStats.sweeperLevel = 4;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case UPGRADE_EXPLOSIVE_PIECE:
|
||||||
|
rogueStats.explosiveLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_CHAIN_BLAST:
|
||||||
|
rogueStats.chainBlastLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_CHAIN_BOMB:
|
||||||
|
rogueStats.chainBombLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_LASER_PIECE:
|
||||||
|
rogueStats.laserLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_THUNDER_TETRIS:
|
||||||
|
rogueStats.thunderTetrisLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_THUNDER_LASER:
|
||||||
|
rogueStats.thunderLaserLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_CROSS_PIECE:
|
||||||
|
rogueStats.crossPieceLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_RAINBOW_PIECE:
|
||||||
|
rogueStats.rainbowPieceLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_STABLE_STRUCTURE:
|
||||||
|
rogueStats.stableStructureLevel += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_PIECE_TUNING:
|
||||||
|
rogueStats.pieceTuningLevels[0] += applyCount;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 应用主动技能、爆发和资源次数类强化。
|
||||||
|
* @param upgradeId 强化编号。
|
||||||
|
* @param applyCount 本次应用次数。
|
||||||
|
* @return 当前强化已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool ApplyActiveSkillUpgrade(int upgradeId, int applyCount)
|
||||||
|
{
|
||||||
|
switch (upgradeId)
|
||||||
|
{
|
||||||
|
case UPGRADE_FEVER_MODE:
|
||||||
|
rogueStats.feverLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_RAGE_STACK:
|
||||||
|
rogueStats.rageStackLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_INFINITE_FEVER:
|
||||||
|
rogueStats.infiniteFeverLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_SCREEN_BOMB:
|
||||||
|
rogueStats.screenBombLevel += applyCount;
|
||||||
|
rogueStats.screenBombCount += applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_TERMINAL_CLEAR:
|
||||||
|
rogueStats.terminalClearLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_BLOCK_STORM:
|
||||||
|
rogueStats.blockStormLevel = 1;
|
||||||
|
rogueStats.blockStormPiecesRemaining = 5;
|
||||||
|
nextTypes[0] = 0;
|
||||||
|
nextTypes[1] = 0;
|
||||||
|
nextTypes[2] = 0;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_BLACK_HOLE:
|
||||||
|
rogueStats.blackHoleLevel = 1;
|
||||||
|
rogueStats.blackHoleCharges += 2 * applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_AIR_RESHAPE:
|
||||||
|
rogueStats.reshapeLevel += applyCount;
|
||||||
|
rogueStats.reshapeCharges += 2 * applyCount;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_VOID_CORE:
|
||||||
|
rogueStats.voidCoreLevel = 1;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 应用风险、升级规则和进化类强化。
|
||||||
|
* @param upgradeId 强化编号。
|
||||||
|
* @param applyCount 本次应用次数。
|
||||||
|
* @return 当前强化已处理返回 true。
|
||||||
|
*/
|
||||||
|
static bool ApplyRiskOrEvolutionUpgrade(int upgradeId, int applyCount)
|
||||||
|
{
|
||||||
|
switch (upgradeId)
|
||||||
|
{
|
||||||
|
case UPGRADE_DUAL_CHOICE:
|
||||||
|
rogueStats.dualChoiceLevel = 1;
|
||||||
|
rogueStats.requiredExp = rogueStats.requiredExp * 130 / 100;
|
||||||
|
if (rogueStats.requiredExp < 10)
|
||||||
|
{
|
||||||
|
rogueStats.requiredExp = 10;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case UPGRADE_DESTINY_WHEEL:
|
||||||
|
rogueStats.destinyWheelLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_HIGH_PRESSURE:
|
||||||
|
rogueStats.highPressureLevel = 1;
|
||||||
|
rogueStats.scoreMultiplierPercent += 50;
|
||||||
|
rogueStats.expMultiplierPercent += 50;
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
return true;
|
||||||
|
case UPGRADE_TETRIS_GAMBLE:
|
||||||
|
rogueStats.tetrisGambleLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_EXTREME_PLAYER:
|
||||||
|
rogueStats.extremePlayerLevel = 1;
|
||||||
|
rogueStats.extremeDangerTicks = 30;
|
||||||
|
rogueStats.extremeDangerLevel = 0;
|
||||||
|
currentFallInterval = GetRogueFallInterval();
|
||||||
|
return true;
|
||||||
|
case UPGRADE_UPGRADE_SHOCKWAVE:
|
||||||
|
rogueStats.upgradeShockwaveLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_EVOLUTION_IMPACT:
|
||||||
|
rogueStats.evolutionImpactLevel = 1;
|
||||||
|
return true;
|
||||||
|
case UPGRADE_GAMBLER:
|
||||||
|
rogueStats.gamblerLevel += applyCount;
|
||||||
|
if (rogueStats.gamblerLevel > 4)
|
||||||
|
{
|
||||||
|
rogueStats.gamblerLevel = 4;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 根据强化编号把对应效果写入 Rogue 属性。
|
* @brief 根据强化编号把对应效果写入 Rogue 属性。
|
||||||
*
|
*
|
||||||
@@ -1727,191 +2011,10 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基础成长类强化直接叠加倍率或层数。
|
ApplyGrowthOrOperationUpgrade(upgradeId, applyCount) ||
|
||||||
switch (upgradeId)
|
ApplySpecialPieceUpgrade(upgradeId, applyCount) ||
|
||||||
{
|
ApplyActiveSkillUpgrade(upgradeId, applyCount) ||
|
||||||
case UPGRADE_SCORE_MULTIPLIER:
|
ApplyRiskOrEvolutionUpgrade(upgradeId, applyCount);
|
||||||
rogueStats.scoreMultiplierPercent += 20 * applyCount;
|
|
||||||
rogueStats.scoreUpgradeLevel += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_COMBO_BONUS:
|
|
||||||
rogueStats.comboBonusStacks += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_EXP_MULTIPLIER:
|
|
||||||
rogueStats.expMultiplierPercent += 25 * applyCount;
|
|
||||||
rogueStats.expUpgradeLevel += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_SLOW_FALL:
|
|
||||||
rogueStats.slowFallStacks += applyCount;
|
|
||||||
if (rogueStats.slowFallStacks > 4)
|
|
||||||
{
|
|
||||||
rogueStats.slowFallStacks = 4;
|
|
||||||
}
|
|
||||||
currentFallInterval = GetRogueFallInterval();
|
|
||||||
break;
|
|
||||||
case UPGRADE_PREVIEW_PLUS_ONE:
|
|
||||||
if (rogueStats.previewCount < 2)
|
|
||||||
{
|
|
||||||
rogueStats.previewCount = 2;
|
|
||||||
}
|
|
||||||
rogueStats.previewUpgradeLevel = rogueStats.previewCount - 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_LAST_CHANCE:
|
|
||||||
rogueStats.lastChanceCount += applyCount;
|
|
||||||
rogueStats.lastChanceUpgradeLevel += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_HOLD_UNLOCK:
|
|
||||||
rogueStats.holdUnlocked = 1;
|
|
||||||
holdUsedThisTurn = false;
|
|
||||||
break;
|
|
||||||
case UPGRADE_PRESSURE_RELIEF:
|
|
||||||
{
|
|
||||||
// 卸压清场立即从最高占用行开始删除,直接改善当前局面。
|
|
||||||
rogueStats.pressureReliefLevel += applyCount;
|
|
||||||
for (int i = 0; i < applyCount; i++)
|
|
||||||
{
|
|
||||||
int topOccupiedRow = GetTopOccupiedRow();
|
|
||||||
if (topOccupiedRow >= 0)
|
|
||||||
{
|
|
||||||
DeleteOneLine(topOccupiedRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case UPGRADE_SWEEPER:
|
|
||||||
rogueStats.sweeperLevel += applyCount;
|
|
||||||
if (rogueStats.sweeperLevel > 4)
|
|
||||||
{
|
|
||||||
rogueStats.sweeperLevel = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UPGRADE_EXPLOSIVE_PIECE:
|
|
||||||
rogueStats.explosiveLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_CHAIN_BLAST:
|
|
||||||
rogueStats.chainBlastLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_CHAIN_BOMB:
|
|
||||||
rogueStats.chainBombLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_LASER_PIECE:
|
|
||||||
rogueStats.laserLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_THUNDER_TETRIS:
|
|
||||||
rogueStats.thunderTetrisLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_THUNDER_LASER:
|
|
||||||
rogueStats.thunderLaserLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_FEVER_MODE:
|
|
||||||
rogueStats.feverLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_RAGE_STACK:
|
|
||||||
rogueStats.rageStackLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_INFINITE_FEVER:
|
|
||||||
rogueStats.infiniteFeverLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_SCREEN_BOMB:
|
|
||||||
rogueStats.screenBombLevel += applyCount;
|
|
||||||
rogueStats.screenBombCount += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_TERMINAL_CLEAR:
|
|
||||||
rogueStats.terminalClearLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_DUAL_CHOICE:
|
|
||||||
rogueStats.dualChoiceLevel = 1;
|
|
||||||
rogueStats.requiredExp = rogueStats.requiredExp * 130 / 100;
|
|
||||||
if (rogueStats.requiredExp < 10)
|
|
||||||
{
|
|
||||||
rogueStats.requiredExp = 10;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UPGRADE_DESTINY_WHEEL:
|
|
||||||
rogueStats.destinyWheelLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_PERFECT_ROTATE:
|
|
||||||
rogueStats.perfectRotateLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_TIME_DILATION:
|
|
||||||
rogueStats.timeDilationLevel = 1;
|
|
||||||
currentFallInterval = GetRogueFallInterval();
|
|
||||||
break;
|
|
||||||
case UPGRADE_HIGH_PRESSURE:
|
|
||||||
rogueStats.highPressureLevel = 1;
|
|
||||||
rogueStats.scoreMultiplierPercent += 50;
|
|
||||||
rogueStats.expMultiplierPercent += 50;
|
|
||||||
currentFallInterval = GetRogueFallInterval();
|
|
||||||
break;
|
|
||||||
case UPGRADE_TETRIS_GAMBLE:
|
|
||||||
rogueStats.tetrisGambleLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_EXTREME_PLAYER:
|
|
||||||
rogueStats.extremePlayerLevel = 1;
|
|
||||||
rogueStats.extremeDangerTicks = 30;
|
|
||||||
rogueStats.extremeDangerLevel = 0;
|
|
||||||
currentFallInterval = GetRogueFallInterval();
|
|
||||||
break;
|
|
||||||
case UPGRADE_UPGRADE_SHOCKWAVE:
|
|
||||||
rogueStats.upgradeShockwaveLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_EVOLUTION_IMPACT:
|
|
||||||
rogueStats.evolutionImpactLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_CONTROL_MASTER:
|
|
||||||
rogueStats.controlMasterLevel = 1;
|
|
||||||
if (rogueStats.previewCount < 3)
|
|
||||||
{
|
|
||||||
rogueStats.previewCount++;
|
|
||||||
}
|
|
||||||
rogueStats.previewUpgradeLevel = rogueStats.previewCount - 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_BLOCK_STORM:
|
|
||||||
// 方块风暴会同时改写预览队列,确保玩家马上看到连续 I 块。
|
|
||||||
rogueStats.blockStormLevel = 1;
|
|
||||||
rogueStats.blockStormPiecesRemaining = 5;
|
|
||||||
nextTypes[0] = 0;
|
|
||||||
nextTypes[1] = 0;
|
|
||||||
nextTypes[2] = 0;
|
|
||||||
break;
|
|
||||||
case UPGRADE_CROSS_PIECE:
|
|
||||||
rogueStats.crossPieceLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_BLACK_HOLE:
|
|
||||||
rogueStats.blackHoleLevel = 1;
|
|
||||||
rogueStats.blackHoleCharges += 2 * applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_AIR_RESHAPE:
|
|
||||||
rogueStats.reshapeLevel += applyCount;
|
|
||||||
rogueStats.reshapeCharges += 2 * applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_RAINBOW_PIECE:
|
|
||||||
rogueStats.rainbowPieceLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_VOID_CORE:
|
|
||||||
rogueStats.voidCoreLevel = 1;
|
|
||||||
break;
|
|
||||||
case UPGRADE_STABLE_STRUCTURE:
|
|
||||||
rogueStats.stableStructureLevel += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_DOUBLE_GROWTH:
|
|
||||||
rogueStats.doubleGrowthLevel = 1;
|
|
||||||
rogueStats.scoreMultiplierPercent += 15;
|
|
||||||
rogueStats.expMultiplierPercent += 15;
|
|
||||||
break;
|
|
||||||
case UPGRADE_PIECE_TUNING:
|
|
||||||
rogueStats.pieceTuningLevels[0] += applyCount;
|
|
||||||
break;
|
|
||||||
case UPGRADE_GAMBLER:
|
|
||||||
rogueStats.gamblerLevel += applyCount;
|
|
||||||
if (rogueStats.gamblerLevel > 4)
|
|
||||||
{
|
|
||||||
rogueStats.gamblerLevel = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2473,6 +2576,109 @@ void OpenUpgradeMenu()
|
|||||||
currentScreen = SCREEN_UPGRADE;
|
currentScreen = SCREEN_UPGRADE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结束一轮升级选择,如果还有待处理升级则刷新下一轮选项。
|
||||||
|
* @return 仍停留在升级界面返回 true;已回到游戏返回 false。
|
||||||
|
*/
|
||||||
|
static bool FinishUpgradeSelectionRound()
|
||||||
|
{
|
||||||
|
if (upgradeUiState.pendingCount > 0)
|
||||||
|
{
|
||||||
|
upgradeUiState.pendingCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upgradeUiState.pendingCount > 0)
|
||||||
|
{
|
||||||
|
FillUpgradeOptions();
|
||||||
|
currentScreen = SCREEN_UPGRADE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
upgradeUiState.optionCount = 0;
|
||||||
|
upgradeUiState.picksRemaining = 0;
|
||||||
|
upgradeUiState.markedCount = 0;
|
||||||
|
|
||||||
|
currentScreen = SCREEN_PLAYING;
|
||||||
|
ResolvePendingUpgradeShockwave();
|
||||||
|
PlayPendingLineClearEffect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 构造单选强化的反馈正文。
|
||||||
|
* @param selectedOption 被选择的强化选项。
|
||||||
|
* @param gamblerSuffix 赌徒契约附加说明。
|
||||||
|
* @param feedbackDetail 返回反馈正文。
|
||||||
|
* @param feedbackDetailCapacity 反馈正文缓冲区长度。
|
||||||
|
*/
|
||||||
|
static void BuildSingleUpgradeFeedback(const UpgradeOption& selectedOption, const TCHAR* gamblerSuffix, TCHAR feedbackDetail[], int feedbackDetailCapacity)
|
||||||
|
{
|
||||||
|
if (selectedOption.id == UPGRADE_PIECE_TUNING && selectedOption.targetPieceType >= 0)
|
||||||
|
{
|
||||||
|
_stprintf_s(
|
||||||
|
feedbackDetail,
|
||||||
|
feedbackDetailCapacity,
|
||||||
|
_T("%s 块的生成概率提高%s"),
|
||||||
|
GetPieceShortName(0),
|
||||||
|
gamblerSuffix);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stprintf_s(feedbackDetail, feedbackDetailCapacity, _T("%s%s"), selectedOption.description, gamblerSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedOption.cursed)
|
||||||
|
{
|
||||||
|
_stprintf_s(
|
||||||
|
feedbackDetail + lstrlen(feedbackDetail),
|
||||||
|
feedbackDetailCapacity - lstrlen(feedbackDetail),
|
||||||
|
_T(" 诅咒缠身:下一次升级所需 EXP 提高 25%。"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 应用多选升级中一个已标记的选项并拼接反馈。
|
||||||
|
* @param selectedOption 被应用的选项。
|
||||||
|
* @param appliedSelections 已应用选项数量。
|
||||||
|
* @param feedbackTitle 返回反馈标题。
|
||||||
|
* @param feedbackDetail 返回反馈正文。
|
||||||
|
*/
|
||||||
|
static void ApplyMarkedUpgradeOption(const UpgradeOption& selectedOption, int& appliedSelections, TCHAR feedbackTitle[], TCHAR feedbackDetail[])
|
||||||
|
{
|
||||||
|
TCHAR gamblerSuffix[64] = _T("");
|
||||||
|
int applyCount = RollGamblerApplyCount(gamblerSuffix, 64, true);
|
||||||
|
|
||||||
|
ApplyUpgradeById(selectedOption.id, selectedOption.targetPieceType, applyCount);
|
||||||
|
upgradeUiState.totalChosenCount++;
|
||||||
|
|
||||||
|
if (selectedOption.cursed)
|
||||||
|
{
|
||||||
|
ApplyDestinyCurse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appliedSelections == 0)
|
||||||
|
{
|
||||||
|
_stprintf_s(feedbackTitle, 64, _T("获得强化:%s"), selectedOption.name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stprintf_s(feedbackTitle, 64, _T("获得强化 x%d"), appliedSelections + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstrlen(feedbackDetail) > 0)
|
||||||
|
{
|
||||||
|
_stprintf_s(feedbackDetail + lstrlen(feedbackDetail), 128 - lstrlen(feedbackDetail), _T(";"));
|
||||||
|
}
|
||||||
|
_stprintf_s(
|
||||||
|
feedbackDetail + lstrlen(feedbackDetail),
|
||||||
|
128 - lstrlen(feedbackDetail),
|
||||||
|
_T("%s%s%s"),
|
||||||
|
selectedOption.name,
|
||||||
|
gamblerSuffix,
|
||||||
|
selectedOption.cursed ? _T(" [诅咒]") : _T(""));
|
||||||
|
appliedSelections++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 确认升级菜单中的选择并应用对应强化效果。
|
* @brief 确认升级菜单中的选择并应用对应强化效果。
|
||||||
*
|
*
|
||||||
@@ -2507,59 +2713,11 @@ void ConfirmUpgradeSelection()
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpgradeOption selectedOption = upgradeUiState.options[optionIndex];
|
UpgradeOption selectedOption = upgradeUiState.options[optionIndex];
|
||||||
TCHAR gamblerSuffix[64] = _T("");
|
ApplyMarkedUpgradeOption(selectedOption, appliedSelections, feedbackTitle, feedbackDetail);
|
||||||
int applyCount = RollGamblerApplyCount(gamblerSuffix, 64, true);
|
|
||||||
|
|
||||||
ApplyUpgradeById(selectedOption.id, selectedOption.targetPieceType, applyCount);
|
|
||||||
upgradeUiState.totalChosenCount++;
|
|
||||||
|
|
||||||
if (selectedOption.cursed)
|
|
||||||
{
|
|
||||||
ApplyDestinyCurse();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appliedSelections == 0)
|
|
||||||
{
|
|
||||||
_stprintf_s(feedbackTitle, _T("获得强化:%s"), selectedOption.name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_stprintf_s(feedbackTitle, _T("获得强化 x%d"), appliedSelections + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lstrlen(feedbackDetail) > 0)
|
|
||||||
{
|
|
||||||
_stprintf_s(feedbackDetail + lstrlen(feedbackDetail), 128 - lstrlen(feedbackDetail), _T(";"));
|
|
||||||
}
|
|
||||||
_stprintf_s(
|
|
||||||
feedbackDetail + lstrlen(feedbackDetail),
|
|
||||||
128 - lstrlen(feedbackDetail),
|
|
||||||
_T("%s%s%s"),
|
|
||||||
selectedOption.name,
|
|
||||||
gamblerSuffix,
|
|
||||||
selectedOption.cursed ? _T(" [诅咒]") : _T(""));
|
|
||||||
appliedSelections++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFeedbackMessage(feedbackTitle, feedbackDetail, 12);
|
SetFeedbackMessage(feedbackTitle, feedbackDetail, 12);
|
||||||
if (upgradeUiState.pendingCount > 0)
|
FinishUpgradeSelectionRound();
|
||||||
{
|
|
||||||
upgradeUiState.pendingCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upgradeUiState.pendingCount > 0)
|
|
||||||
{
|
|
||||||
FillUpgradeOptions();
|
|
||||||
currentScreen = SCREEN_UPGRADE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
upgradeUiState.optionCount = 0;
|
|
||||||
upgradeUiState.picksRemaining = 0;
|
|
||||||
upgradeUiState.markedCount = 0;
|
|
||||||
currentScreen = SCREEN_PLAYING;
|
|
||||||
ResolvePendingUpgradeShockwave();
|
|
||||||
PlayPendingLineClearEffect();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2573,26 +2731,11 @@ void ConfirmUpgradeSelection()
|
|||||||
TCHAR feedbackTitle[64];
|
TCHAR feedbackTitle[64];
|
||||||
TCHAR feedbackDetail[128];
|
TCHAR feedbackDetail[128];
|
||||||
_stprintf_s(feedbackTitle, _T("获得强化:%s"), selectedOption.name);
|
_stprintf_s(feedbackTitle, _T("获得强化:%s"), selectedOption.name);
|
||||||
if (selectedOption.id == UPGRADE_PIECE_TUNING && selectedOption.targetPieceType >= 0)
|
BuildSingleUpgradeFeedback(selectedOption, gamblerSuffix, feedbackDetail, 128);
|
||||||
{
|
|
||||||
_stprintf_s(
|
|
||||||
feedbackDetail,
|
|
||||||
_T("%s 块的生成概率提高%s"),
|
|
||||||
GetPieceShortName(0),
|
|
||||||
gamblerSuffix);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_stprintf_s(feedbackDetail, _T("%s%s"), selectedOption.description, gamblerSuffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedOption.cursed)
|
if (selectedOption.cursed)
|
||||||
{
|
{
|
||||||
ApplyDestinyCurse();
|
ApplyDestinyCurse();
|
||||||
_stprintf_s(
|
|
||||||
feedbackDetail + lstrlen(feedbackDetail),
|
|
||||||
128 - lstrlen(feedbackDetail),
|
|
||||||
_T(" 诅咒缠身:下一次升级所需 EXP 提高 25%。"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFeedbackMessage(feedbackTitle, feedbackDetail, 12);
|
SetFeedbackMessage(feedbackTitle, feedbackDetail, 12);
|
||||||
@@ -2622,26 +2765,7 @@ void ConfirmUpgradeSelection()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连续升级时重新生成下一轮强化;全部完成后回到游戏并播放延迟效果。
|
FinishUpgradeSelectionRound();
|
||||||
if (upgradeUiState.pendingCount > 0)
|
|
||||||
{
|
|
||||||
upgradeUiState.pendingCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upgradeUiState.pendingCount > 0)
|
|
||||||
{
|
|
||||||
FillUpgradeOptions();
|
|
||||||
currentScreen = SCREEN_UPGRADE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
upgradeUiState.optionCount = 0;
|
|
||||||
upgradeUiState.picksRemaining = 0;
|
|
||||||
upgradeUiState.markedCount = 0;
|
|
||||||
|
|
||||||
currentScreen = SCREEN_PLAYING;
|
|
||||||
ResolvePendingUpgradeShockwave();
|
|
||||||
PlayPendingLineClearEffect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user