264 lines
8.6 KiB
C++
264 lines
8.6 KiB
C++
#include "stdafx.h"
|
|
/**
|
|
* @file TetrisPieceEffects.cpp
|
|
* @brief 实现彩虹、爆破、激光、十字和稳定结构等特殊方块落地效果。
|
|
*/
|
|
|
|
#include "TetrisLogicInternal.h"
|
|
|
|
/**
|
|
* @brief 结算彩虹方块固定后的染色和清除效果。
|
|
* @param overflowTop 固定时是否已经越过棋盘顶部。
|
|
* @param fixedCells 当前方块写入棋盘的格子数组。
|
|
* @param fixedCellCount 写入棋盘的格子数量。
|
|
*/
|
|
void ApplyRainbowLandingEffect(bool overflowTop, const Point* fixedCells, int fixedCellCount)
|
|
{
|
|
// 顶部溢出时优先交给失败/复活逻辑处理,避免在不可见区域触发奖励。
|
|
if (overflowTop || !currentPieceIsRainbow)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 优先使用实际固定格子的平均行作为主色行,避免旋转形状偏移导致判定不自然。
|
|
int rainbowAnchorRow = point.y + 1;
|
|
if (fixedCellCount > 0)
|
|
{
|
|
int ySum = 0;
|
|
for (int i = 0; i < fixedCellCount; i++)
|
|
{
|
|
ySum += fixedCells[i].y;
|
|
}
|
|
rainbowAnchorRow = (ySum + fixedCellCount / 2) / fixedCellCount;
|
|
}
|
|
if (rainbowAnchorRow < 0)
|
|
{
|
|
rainbowAnchorRow = 0;
|
|
}
|
|
if (rainbowAnchorRow >= GetRoguePlayableHeight())
|
|
{
|
|
rainbowAnchorRow = GetRoguePlayableHeight() - 1;
|
|
}
|
|
|
|
// 第二阶段:按锚点行执行彩虹清除和覆盖行染色。
|
|
int rainbowRecoloredCount = 0;
|
|
int rainbowClearedCount = TriggerRainbowColorShift(rainbowAnchorRow, point.y, point.y + 3, rainbowRecoloredCount);
|
|
int rainbowScore = 0;
|
|
int rainbowExp = 0;
|
|
int voidClearedCount = 0;
|
|
int voidScore = 0;
|
|
int voidExp = 0;
|
|
if (currentMode == MODE_ROGUE && rainbowClearedCount > 0)
|
|
{
|
|
// Rogue 模式下特殊清除也能获得得分和经验,但不直接触发升级菜单。
|
|
AwardRogueSkillClearRewards(rainbowClearedCount, rainbowScore, rainbowExp, false);
|
|
if (rogueStats.voidCoreLevel > 0)
|
|
{
|
|
voidClearedCount = TriggerMiniBlackHole(5);
|
|
AwardRogueSkillClearRewards(voidClearedCount, voidScore, voidExp, false);
|
|
}
|
|
}
|
|
|
|
TCHAR rainbowDetail[128];
|
|
if (voidClearedCount > 0)
|
|
{
|
|
_stprintf_s(
|
|
rainbowDetail,
|
|
_T("第 %d 行清 %d 格,染色 %d 格,虚空追加 %d 格"),
|
|
rainbowAnchorRow + 1,
|
|
rainbowClearedCount,
|
|
rainbowRecoloredCount,
|
|
voidClearedCount);
|
|
}
|
|
else
|
|
{
|
|
_stprintf_s(
|
|
rainbowDetail,
|
|
_T("第 %d 行清除主色 %d 格,覆盖行染色 %d 格。"),
|
|
rainbowAnchorRow + 1,
|
|
rainbowClearedCount,
|
|
rainbowRecoloredCount);
|
|
}
|
|
SetFeedbackMessage(_T("彩虹方块"), rainbowDetail, 10);
|
|
}
|
|
|
|
/**
|
|
* @brief 结算爆破方块的范围清除效果。
|
|
* @param explosiveCells 爆破方块写入棋盘的格子数组。
|
|
* @param explosiveCellCount 爆破格子数量。
|
|
*/
|
|
static void ApplyExplosiveLandingEffect(const Point* explosiveCells, int explosiveCellCount)
|
|
{
|
|
// 非爆破方块直接跳过,保持普通方块落地流程轻量。
|
|
if (!currentPieceIsExplosive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 每个落地格都作为爆心清除范围,连环炸弹会扩大底层清除函数的范围。
|
|
int explosiveCellsCleared = 0;
|
|
for (int i = 0; i < explosiveCellCount; i++)
|
|
{
|
|
explosiveCellsCleared += ClearExplosiveAreaAt(explosiveCells[i].y, explosiveCells[i].x);
|
|
}
|
|
|
|
int explosiveScoreGain = 0;
|
|
int explosiveExpGain = 0;
|
|
if (currentMode == MODE_ROGUE && explosiveCellsCleared > 0)
|
|
{
|
|
AwardRogueSkillClearRewards(explosiveCellsCleared, explosiveScoreGain, explosiveExpGain, false);
|
|
}
|
|
|
|
TCHAR explosiveDetail[128];
|
|
_stprintf_s(
|
|
explosiveDetail,
|
|
_T("爆破清除 %d 格 +%d 分 +%d EXP"),
|
|
explosiveCellsCleared,
|
|
explosiveScoreGain,
|
|
explosiveExpGain);
|
|
SetFeedbackMessage(_T("爆破核心"), explosiveDetail, 12);
|
|
|
|
// 连环炸弹需要等标准消行判断完成后,再决定是否追加一次小爆炸。
|
|
if (rogueStats.chainBombLevel > 0 && explosiveCellCount > 0)
|
|
{
|
|
pendingChainBombCenter = explosiveCells[0];
|
|
pendingChainBombFollowup = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 结算激光方块的整列清除效果。
|
|
* @param fixedCells 当前方块写入棋盘的格子数组。
|
|
* @param fixedCellCount 写入棋盘的格子数量。
|
|
*/
|
|
static void ApplyLaserLandingEffect(const Point* fixedCells, int fixedCellCount)
|
|
{
|
|
// 激光方块以落地格平均列作为贯穿列,减少不同形状造成的位置偏差。
|
|
if (!currentPieceIsLaser)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int laserColumn = point.x + 1;
|
|
if (fixedCellCount > 0)
|
|
{
|
|
int xSum = 0;
|
|
for (int i = 0; i < fixedCellCount; i++)
|
|
{
|
|
xSum += fixedCells[i].x;
|
|
}
|
|
laserColumn = (xSum + fixedCellCount / 2) / fixedCellCount;
|
|
}
|
|
if (laserColumn < 0)
|
|
{
|
|
laserColumn = 0;
|
|
}
|
|
if (laserColumn >= nGameWidth)
|
|
{
|
|
laserColumn = nGameWidth - 1;
|
|
}
|
|
|
|
int laserCellsCleared = ClearColumnAt(laserColumn);
|
|
if (currentMode == MODE_ROGUE && laserCellsCleared > 0)
|
|
{
|
|
int laserScore = 0;
|
|
int laserExp = 0;
|
|
AwardRogueSkillClearRewards(laserCellsCleared, laserScore, laserExp, false);
|
|
|
|
TCHAR laserDetail[128];
|
|
_stprintf_s(laserDetail, _T("激光贯穿第 %d 列,清除 %d 格 +%d 分 +%d EXP"), laserColumn + 1, laserCellsCleared, laserScore, laserExp);
|
|
SetFeedbackMessage(_T("棱镜激光"), laserDetail, 12);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 结算十字方块的整行整列清除效果。
|
|
* @param fixedCells 当前方块写入棋盘的格子数组。
|
|
* @param fixedCellCount 写入棋盘的格子数量。
|
|
*/
|
|
static void ApplyCrossLandingEffect(const Point* fixedCells, int fixedCellCount)
|
|
{
|
|
// 十字方块同时计算中心行和中心列,后续分别触发行清除与列清除。
|
|
if (!currentPieceIsCross)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int crossRow = point.y + 1;
|
|
int crossColumn = point.x + 1;
|
|
if (fixedCellCount > 0)
|
|
{
|
|
int xSum = 0;
|
|
int ySum = 0;
|
|
for (int i = 0; i < fixedCellCount; i++)
|
|
{
|
|
xSum += fixedCells[i].x;
|
|
ySum += fixedCells[i].y;
|
|
}
|
|
crossColumn = (xSum + fixedCellCount / 2) / fixedCellCount;
|
|
crossRow = (ySum + fixedCellCount / 2) / fixedCellCount;
|
|
}
|
|
if (crossRow < 0)
|
|
{
|
|
crossRow = 0;
|
|
}
|
|
if (crossRow >= GetRoguePlayableHeight())
|
|
{
|
|
crossRow = GetRoguePlayableHeight() - 1;
|
|
}
|
|
if (crossColumn < 0)
|
|
{
|
|
crossColumn = 0;
|
|
}
|
|
if (crossColumn >= nGameWidth)
|
|
{
|
|
crossColumn = nGameWidth - 1;
|
|
}
|
|
|
|
int crossCellsCleared = ClearRowAt(crossRow);
|
|
int columnCellsCleared = ClearColumnAtWithColor(crossColumn, RGB(196, 255, 132));
|
|
if (workRegion[crossRow][crossColumn] == 0 && columnCellsCleared > 0)
|
|
{
|
|
// 中心格可能已经在行清除时被计数,这里保持原有结算方式。
|
|
}
|
|
int totalCrossCleared = crossCellsCleared + columnCellsCleared;
|
|
|
|
if (currentMode == MODE_ROGUE && totalCrossCleared > 0)
|
|
{
|
|
int crossScore = 0;
|
|
int crossExp = 0;
|
|
AwardRogueSkillClearRewards(totalCrossCleared, crossScore, crossExp, false);
|
|
|
|
TCHAR crossDetail[128];
|
|
_stprintf_s(crossDetail, _T("十字冲击第 %d 行 / 第 %d 列,清除 %d 格 +%d 分 +%d EXP"), crossRow + 1, crossColumn + 1, totalCrossCleared, crossScore, crossExp);
|
|
SetFeedbackMessage(_T("十字方块"), crossDetail, 12);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 结算非彩虹方块触发的稳定结构效果。
|
|
*/
|
|
static void ApplyStableStructureEffect()
|
|
{
|
|
if (!currentPieceIsRainbow && TryStabilizeBoard() > 0)
|
|
{
|
|
SetFeedbackMessage(_T("稳定结构"), _T("附近空洞被自动填补,阵型更加稳固。"), 10);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 结算爆破、激光、十字和稳定结构等特殊落地效果。
|
|
* @param fixedCells 当前方块写入棋盘的格子数组。
|
|
* @param fixedCellCount 写入棋盘的格子数量。
|
|
* @param explosiveCells 爆破方块写入棋盘的格子数组。
|
|
* @param explosiveCellCount 爆破格子数量。
|
|
*/
|
|
void ApplySpecialLandingEffects(const Point* fixedCells, int fixedCellCount, const Point* explosiveCells, int explosiveCellCount)
|
|
{
|
|
// 多种特殊标记按固定顺序结算,保证同一落地事件的反馈和奖励稳定。
|
|
ApplyExplosiveLandingEffect(explosiveCells, explosiveCellCount);
|
|
ApplyLaserLandingEffect(fixedCells, fixedCellCount);
|
|
ApplyCrossLandingEffect(fixedCells, fixedCellCount);
|
|
ApplyStableStructureEffect();
|
|
}
|