再次整理文件结构
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
#include "stdafx.h"
|
||||
/**
|
||||
* @file TetrisCoreHelpers.cpp
|
||||
* @brief 存放基础逻辑框架函数之外的内部辅助流程。
|
||||
*/
|
||||
|
||||
#include "Tetris.h"
|
||||
#include "TetrisLogicInternal.h"
|
||||
|
||||
/**
|
||||
* @brief 计算指定方块在指定旋转状态下的最小包围盒边界。
|
||||
*
|
||||
* 该函数会遍历 4x4 形状矩阵,找出所有非空单元的上下左右边界,
|
||||
* 供后续统一计算生成位置和对齐方式时使用。
|
||||
*
|
||||
* @param brickType 方块类型编号。
|
||||
* @param brickState 方块旋转状态编号。
|
||||
* @param minRow 返回最上方非空行号。
|
||||
* @param maxRow 返回最下方非空行号。
|
||||
* @param minCol 返回最左侧非空列号。
|
||||
* @param maxCol 返回最右侧非空列号。
|
||||
*/
|
||||
static void GetBrickBounds(int brickType, int brickState, int& minRow, int& maxRow, int& minCol, int& maxCol)
|
||||
{
|
||||
minRow = 4;
|
||||
maxRow = -1;
|
||||
minCol = 4;
|
||||
maxCol = -1;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (bricks[brickType][brickState][i][j] != 0)
|
||||
{
|
||||
if (i < minRow)
|
||||
{
|
||||
minRow = i;
|
||||
}
|
||||
if (i > maxRow)
|
||||
{
|
||||
maxRow = i;
|
||||
}
|
||||
if (j < minCol)
|
||||
{
|
||||
minCol = j;
|
||||
}
|
||||
if (j > maxCol)
|
||||
{
|
||||
maxCol = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算指定方块的统一生成位置。
|
||||
*
|
||||
* 该函数会根据方块在初始旋转状态下的最小包围盒,
|
||||
* 自动把方块水平居中到游戏区附近,并将顶部非空行对齐到可视区域顶部。
|
||||
* 这样不同形状的方块在生成时看起来会更加统一。
|
||||
*
|
||||
* @param brickType 方块类型编号。
|
||||
* @return Point 计算得到的生成坐标。
|
||||
*/
|
||||
Point GetSpawnPoint(int brickType)
|
||||
{
|
||||
int minRow, maxRow, minCol, maxCol;
|
||||
GetBrickBounds(brickType, 0, minRow, maxRow, minCol, maxCol);
|
||||
|
||||
int brickWidth = maxCol - minCol + 1;
|
||||
int brickHeight = maxRow - minRow + 1;
|
||||
Point spawnPoint;
|
||||
spawnPoint.x = (nGameWidth - brickWidth) / 2 - minCol;
|
||||
spawnPoint.y = -brickHeight;
|
||||
|
||||
return spawnPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 收集当前方块将要固定到棋盘上的格子,并标记是否越过顶部。
|
||||
* @param overflowTop 返回是否有方块格位于可视区域顶部之外。
|
||||
* @param fixedCells 返回普通落地格,用于后续特殊效果定位。
|
||||
* @param fixedCellCount 返回普通落地格数量。
|
||||
* @param explosiveCells 返回爆破方块落地格。
|
||||
* @param explosiveCellCount 返回爆破方块落地格数量。
|
||||
*/
|
||||
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。
|
||||
*/
|
||||
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、特殊方块和预测落点状态。
|
||||
*/
|
||||
void SpawnNextFallingPiece()
|
||||
{
|
||||
// 消耗预览队列后重置本回合状态,确保 Hold 和特殊标记只影响新方块。
|
||||
type = ConsumeNextType();
|
||||
nType = nextTypes[0];
|
||||
state = 0;
|
||||
holdUsedThisTurn = false;
|
||||
RollCurrentPieceSpecialFlags(true);
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
ComputeTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从底向上扫描满行并删除,记录本次消除的原始行号。
|
||||
* @param clearedRows 返回最多 8 个被消除行号,用于播放消行动画。
|
||||
* @param clearedRowCount 返回记录的行号数量。
|
||||
* @return 本次标准消行数量。
|
||||
*/
|
||||
int ScanAndDeleteFullLines(int clearedRows[], int& clearedRowCount)
|
||||
{
|
||||
int clearedLines = 0;
|
||||
clearedRowCount = 0;
|
||||
|
||||
int playableHeight = GetRoguePlayableHeight();
|
||||
for (int i = playableHeight - 1; i >= 0; i--)
|
||||
{
|
||||
bool fullLine = true;
|
||||
|
||||
for (int j = 0; j < nGameWidth; j++)
|
||||
{
|
||||
if (workRegion[i][j] == 0)
|
||||
{
|
||||
fullLine = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullLine)
|
||||
{
|
||||
if (clearedRowCount < 8)
|
||||
{
|
||||
clearedRows[clearedRowCount] = i;
|
||||
clearedRowCount++;
|
||||
}
|
||||
|
||||
DeleteOneLine(i);
|
||||
clearedLines++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return clearedLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据当前界面状态立即播放或暂存消行动画。
|
||||
* @param clearedRows 已消除行号数组。
|
||||
* @param clearedRowCount 行号数量。
|
||||
* @param clearedLines 本次消行数量。
|
||||
*/
|
||||
void DispatchLineClearEffect(const int clearedRows[], int clearedRowCount, int clearedLines)
|
||||
{
|
||||
if (currentScreen == SCREEN_UPGRADE)
|
||||
{
|
||||
QueueLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerLineClearEffect(clearedRows, clearedRowCount, clearedLines);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理连环炸弹因消行触发的一次追加 3x3 爆破。
|
||||
* @param clearedLines 本次标准消行数量。
|
||||
*/
|
||||
void ResolveChainBombFollowup(int clearedLines)
|
||||
{
|
||||
if (!pendingChainBombFollowup || clearedLines <= 0)
|
||||
{
|
||||
pendingChainBombFollowup = false;
|
||||
return;
|
||||
}
|
||||
|
||||
pendingChainBombFollowup = false;
|
||||
|
||||
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++)
|
||||
{
|
||||
if (y >= 0 && y < GetRoguePlayableHeight() && x >= 0 && x < nGameWidth && workRegion[y][x] != 0)
|
||||
{
|
||||
if (followupCleared < 9)
|
||||
{
|
||||
followupCells[followupCleared].x = x;
|
||||
followupCells[followupCleared].y = y;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user