#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) { 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(); }