补充十字方块、黑洞和空中换形强化
This commit is contained in:
+284
-11
@@ -24,6 +24,7 @@ int holdType = -1;
|
||||
bool holdUsedThisTurn = false;
|
||||
bool currentPieceIsExplosive = false;
|
||||
bool currentPieceIsLaser = false;
|
||||
bool currentPieceIsCross = false;
|
||||
Point pendingChainBombCenter = { 0, 0 };
|
||||
bool pendingChainBombFollowup = false;
|
||||
|
||||
@@ -63,7 +64,10 @@ enum UpgradeId
|
||||
UPGRADE_UPGRADE_SHOCKWAVE = 31,
|
||||
UPGRADE_EVOLUTION_IMPACT = 32,
|
||||
UPGRADE_CONTROL_MASTER = 33,
|
||||
UPGRADE_BLOCK_STORM = 34
|
||||
UPGRADE_BLOCK_STORM = 34,
|
||||
UPGRADE_CROSS_PIECE = 35,
|
||||
UPGRADE_BLACK_HOLE = 36,
|
||||
UPGRADE_AIR_RESHAPE = 37
|
||||
};
|
||||
|
||||
static const UpgradeEntry kUpgradePool[] =
|
||||
@@ -99,6 +103,9 @@ static const UpgradeEntry kUpgradePool[] =
|
||||
{ UPGRADE_EVOLUTION_IMPACT, 1, 118, false, _T("\u8fdb\u5316\u51b2\u51fb"), _T("\u8fdb\u5316"), _T("\u5347\u7ea7\u65f6\u6e05\u9664\u5e95\u90e8 3 \u884c\uff0c\u5e76\u83b7\u5f97 10 \u79d2\u53cc\u500d EXP\u3002") },
|
||||
{ UPGRADE_CONTROL_MASTER, 1, 112, false, _T("\u64cd\u63a7\u5927\u5e08"), _T("\u8fdb\u5316"), _T("Hold \u540e\u77ed\u6682\u964d\u4f4e\u4e0b\u843d\u901f\u5ea6\uff0c\u5e76\u989d\u5916\u589e\u52a0 1 \u4e2a\u9884\u89c8\u65b9\u5757\u3002") },
|
||||
{ UPGRADE_BLOCK_STORM, 1, 82, false, _T("\u65b9\u5757\u98ce\u66b4"), _T("\u723d\u611f"), _T("\u63a5\u4e0b\u6765 5 \u4e2a\u65b9\u5757\u5168\u90e8\u53d8\u6210 I \u5757\uff0c\u5feb\u901f\u5236\u9020\u56db\u6d88\u673a\u4f1a\u3002") },
|
||||
{ UPGRADE_CROSS_PIECE, -1, 76, true, _T("\u5341\u5b57\u65b9\u5757"), _T("\u723d\u611f"), _T("\u63d0\u9ad8\u5341\u5b57\u65b9\u5757\u51fa\u73b0\u6982\u7387\uff0c\u843d\u5730\u540e\u6e05\u9664\u6240\u5728\u884c\u4e0e\u6240\u5728\u5217\u3002") },
|
||||
{ UPGRADE_BLACK_HOLE, 1, 78, false, _T("\u9ed1\u6d1e"), _T("\u7279\u6b8a"), _T("\u83b7\u5f97 1 \u6b21\u4e3b\u52a8\u9ed1\u6d1e\uff0c\u91ca\u653e\u540e\u6e05\u9664\u68cb\u76d8\u4e0a\u6570\u91cf\u6700\u591a\u7684\u4e00\u79cd\u65b9\u5757\u3002") },
|
||||
{ UPGRADE_AIR_RESHAPE, 1, 74, false, _T("\u7a7a\u4e2d\u6362\u5f62"), _T("\u64cd\u4f5c"), _T("\u83b7\u5f97 1 \u6b21\u4e3b\u52a8\u6362\u5f62\uff0c\u53ef\u5c06\u5f53\u524d\u65b9\u5757\u53d8\u4e3a I \u5757\u3002") },
|
||||
{ UPGRADE_STABLE_STRUCTURE, -1, 72, true, _T("\u7a33\u5b9a\u7ed3\u6784"), _T("\u7279\u6b8a"), _T("\u843d\u5730\u540e\u5c0f\u6982\u7387\u81ea\u52a8\u586b\u8865\u90bb\u8fd1\u7a7a\u6d1e\uff0c\u63d0\u9ad8\u76d8\u9762\u7ed3\u6784\u7a33\u5b9a\u6027\u3002") },
|
||||
{ UPGRADE_DOUBLE_GROWTH, 1, 84, false, _T("\u6210\u957f\u6838\u5fc3"), _T("\u6210\u957f"), _T("\u6c38\u4e45\u83b7\u5f97 +15% \u5f97\u5206\u4e0e +15% EXP\uff0c\u53ea\u80fd\u9009\u62e9\u4e00\u6b21\u3002") },
|
||||
{ UPGRADE_PIECE_TUNING, -1, 64, true, _T("\u65b9\u5757\u6539\u9020"), _T("\u7279\u6b8a"), _T("\u9009\u62e9\u4e00\u79cd\u65b9\u5757\uff0c\u964d\u4f4e\u5176\u540e\u7eed\u51fa\u73b0\u6982\u7387\u3002") },
|
||||
@@ -287,6 +294,10 @@ static void ResetPlayerStats(PlayerStats& stats, bool useRogueRules)
|
||||
stats.holdSlowTicks = 0;
|
||||
stats.blockStormLevel = 0;
|
||||
stats.blockStormPiecesRemaining = 0;
|
||||
stats.blackHoleLevel = 0;
|
||||
stats.blackHoleCharges = 0;
|
||||
stats.reshapeLevel = 0;
|
||||
stats.reshapeCharges = 0;
|
||||
stats.stableStructureLevel = 0;
|
||||
stats.doubleGrowthLevel = 0;
|
||||
stats.gamblerLevel = 0;
|
||||
@@ -382,6 +393,12 @@ static int GetUpgradeCurrentLevel(int upgradeId)
|
||||
return rogueStats.controlMasterLevel;
|
||||
case UPGRADE_BLOCK_STORM:
|
||||
return rogueStats.blockStormLevel;
|
||||
case UPGRADE_CROSS_PIECE:
|
||||
return rogueStats.crossPieceLevel;
|
||||
case UPGRADE_BLACK_HOLE:
|
||||
return rogueStats.blackHoleLevel;
|
||||
case UPGRADE_AIR_RESHAPE:
|
||||
return rogueStats.reshapeLevel;
|
||||
case UPGRADE_STABLE_STRUCTURE:
|
||||
return rogueStats.stableStructureLevel;
|
||||
case UPGRADE_DOUBLE_GROWTH:
|
||||
@@ -568,6 +585,24 @@ static int GetUpgradeDynamicWeight(const UpgradeEntry& entry)
|
||||
weight += 20;
|
||||
}
|
||||
break;
|
||||
case UPGRADE_CROSS_PIECE:
|
||||
if (rogueStats.laserLevel > 0 || rogueStats.feverLevel > 0)
|
||||
{
|
||||
weight += 14;
|
||||
}
|
||||
break;
|
||||
case UPGRADE_BLACK_HOLE:
|
||||
if (boardIsDangerous)
|
||||
{
|
||||
weight += 18;
|
||||
}
|
||||
break;
|
||||
case UPGRADE_AIR_RESHAPE:
|
||||
if (boardIsDangerous || rogueStats.tetrisGambleLevel > 0)
|
||||
{
|
||||
weight += 18;
|
||||
}
|
||||
break;
|
||||
case UPGRADE_STABLE_STRUCTURE:
|
||||
if (boardIsDangerous)
|
||||
{
|
||||
@@ -813,6 +848,37 @@ static bool RollLaserPiece()
|
||||
return (rand() % 100) < chancePercent;
|
||||
}
|
||||
|
||||
static bool RollCrossPiece()
|
||||
{
|
||||
if (currentMode != MODE_ROGUE || rogueStats.crossPieceLevel <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int chancePercent = 8 + (rogueStats.crossPieceLevel - 1) * 6;
|
||||
if (chancePercent > 28)
|
||||
{
|
||||
chancePercent = 28;
|
||||
}
|
||||
|
||||
return (rand() % 100) < chancePercent;
|
||||
}
|
||||
|
||||
static void RollCurrentPieceSpecialFlags(bool allowRandomSpecials)
|
||||
{
|
||||
if (!allowRandomSpecials)
|
||||
{
|
||||
currentPieceIsExplosive = false;
|
||||
currentPieceIsLaser = false;
|
||||
currentPieceIsCross = false;
|
||||
return;
|
||||
}
|
||||
|
||||
currentPieceIsExplosive = RollExplosivePiece();
|
||||
currentPieceIsLaser = !currentPieceIsExplosive && RollLaserPiece();
|
||||
currentPieceIsCross = !currentPieceIsExplosive && !currentPieceIsLaser && RollCrossPiece();
|
||||
}
|
||||
|
||||
static int ClearExplosiveAreaAt(int centerY, int centerX)
|
||||
{
|
||||
int radius = (currentMode == MODE_ROGUE && rogueStats.chainBombLevel > 0) ? 2 : 1;
|
||||
@@ -857,6 +923,74 @@ static int ClearColumnAt(int column)
|
||||
return clearedCellCount;
|
||||
}
|
||||
|
||||
static int ClearRowAt(int row)
|
||||
{
|
||||
int clearedCellCount = 0;
|
||||
|
||||
if (row < 0 || row >= nGameHeight)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int x = 0; x < nGameWidth; x++)
|
||||
{
|
||||
if (workRegion[row][x] != 0)
|
||||
{
|
||||
workRegion[row][x] = 0;
|
||||
clearedCellCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return clearedCellCount;
|
||||
}
|
||||
|
||||
static int TriggerBlackHole()
|
||||
{
|
||||
int blockCounts[8] = { 0 };
|
||||
for (int y = 0; y < nGameHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < nGameWidth; x++)
|
||||
{
|
||||
int cell = workRegion[y][x];
|
||||
if (cell >= 1 && cell <= 7)
|
||||
{
|
||||
blockCounts[cell]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int targetBlock = 0;
|
||||
int maxCount = 0;
|
||||
for (int block = 1; block <= 7; block++)
|
||||
{
|
||||
if (blockCounts[block] > maxCount)
|
||||
{
|
||||
maxCount = blockCounts[block];
|
||||
targetBlock = block;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetBlock == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clearedCellCount = 0;
|
||||
for (int y = 0; y < nGameHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < nGameWidth; x++)
|
||||
{
|
||||
if (workRegion[y][x] == targetBlock)
|
||||
{
|
||||
workRegion[y][x] = 0;
|
||||
clearedCellCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clearedCellCount;
|
||||
}
|
||||
|
||||
static int TriggerScreenBomb()
|
||||
{
|
||||
int clearedCellCount = 0;
|
||||
@@ -1366,6 +1500,17 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
|
||||
nextTypes[1] = 0;
|
||||
nextTypes[2] = 0;
|
||||
break;
|
||||
case UPGRADE_CROSS_PIECE:
|
||||
rogueStats.crossPieceLevel += applyCount;
|
||||
break;
|
||||
case UPGRADE_BLACK_HOLE:
|
||||
rogueStats.blackHoleLevel = 1;
|
||||
rogueStats.blackHoleCharges++;
|
||||
break;
|
||||
case UPGRADE_AIR_RESHAPE:
|
||||
rogueStats.reshapeLevel = 1;
|
||||
rogueStats.reshapeCharges++;
|
||||
break;
|
||||
case UPGRADE_STABLE_STRUCTURE:
|
||||
rogueStats.stableStructureLevel += applyCount;
|
||||
break;
|
||||
@@ -2085,6 +2230,51 @@ void Fixing()
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPieceIsCross)
|
||||
{
|
||||
int crossRow = point.y + 1;
|
||||
int crossColumn = point.x + 1;
|
||||
if (crossRow < 0)
|
||||
{
|
||||
crossRow = 0;
|
||||
}
|
||||
if (crossRow >= nGameHeight)
|
||||
{
|
||||
crossRow = nGameHeight - 1;
|
||||
}
|
||||
if (crossColumn < 0)
|
||||
{
|
||||
crossColumn = 0;
|
||||
}
|
||||
if (crossColumn >= nGameWidth)
|
||||
{
|
||||
crossColumn = nGameWidth - 1;
|
||||
}
|
||||
|
||||
int crossCellsCleared = ClearRowAt(crossRow);
|
||||
int columnCellsCleared = ClearColumnAt(crossColumn);
|
||||
if (workRegion[crossRow][crossColumn] == 0 && columnCellsCleared > 0)
|
||||
{
|
||||
// center cell may already be counted by row clear
|
||||
}
|
||||
int totalCrossCleared = crossCellsCleared + columnCellsCleared;
|
||||
|
||||
if (currentMode == MODE_ROGUE && totalCrossCleared > 0)
|
||||
{
|
||||
int crossScore = totalCrossCleared * rogueStats.scoreMultiplierPercent / 100;
|
||||
if (crossScore < totalCrossCleared)
|
||||
{
|
||||
crossScore = totalCrossCleared;
|
||||
}
|
||||
rogueStats.score += crossScore;
|
||||
tScore = rogueStats.score;
|
||||
|
||||
TCHAR crossDetail[128];
|
||||
_stprintf_s(crossDetail, _T("\u6e05\u9664 %d \u683c +%d Score"), totalCrossCleared, crossScore);
|
||||
SetFeedbackMessage(_T("\u5341\u5b57\u65b9\u5757\u89e6\u53d1"), crossDetail, 12);
|
||||
}
|
||||
}
|
||||
|
||||
if (TryStabilizeBoard() > 0)
|
||||
{
|
||||
SetFeedbackMessage(_T("\u7a33\u5b9a\u7ed3\u6784\u751f\u6548"), _T("\u81ea\u52a8\u586b\u8865\u4e86\u4e00\u4e2a\u90bb\u8fd1\u7a7a\u6d1e\u3002"), 10);
|
||||
@@ -2100,8 +2290,7 @@ void Fixing()
|
||||
nType = nextTypes[0];
|
||||
state = 0;
|
||||
holdUsedThisTurn = false;
|
||||
currentPieceIsExplosive = RollExplosivePiece();
|
||||
currentPieceIsLaser = !currentPieceIsExplosive && RollLaserPiece();
|
||||
RollCurrentPieceSpecialFlags(true);
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
ComputeTarget();
|
||||
@@ -2274,8 +2463,7 @@ void Restart()
|
||||
feedbackState.detail[0] = _T('\0');
|
||||
holdType = -1;
|
||||
holdUsedThisTurn = false;
|
||||
currentPieceIsExplosive = false;
|
||||
currentPieceIsLaser = false;
|
||||
RollCurrentPieceSpecialFlags(false);
|
||||
tScore = 0;
|
||||
|
||||
ResetNextQueue();
|
||||
@@ -2283,8 +2471,7 @@ void Restart()
|
||||
nType = nextTypes[0];
|
||||
state = 0;
|
||||
holdUsedThisTurn = false;
|
||||
currentPieceIsExplosive = RollExplosivePiece();
|
||||
currentPieceIsLaser = !currentPieceIsExplosive && RollLaserPiece();
|
||||
RollCurrentPieceSpecialFlags(true);
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
|
||||
@@ -2452,14 +2639,12 @@ void HoldCurrentPiece()
|
||||
{
|
||||
type = ConsumeNextType();
|
||||
nType = nextTypes[0];
|
||||
currentPieceIsExplosive = RollExplosivePiece();
|
||||
currentPieceIsLaser = !currentPieceIsExplosive && RollLaserPiece();
|
||||
RollCurrentPieceSpecialFlags(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = previousHoldType;
|
||||
currentPieceIsExplosive = false;
|
||||
currentPieceIsLaser = false;
|
||||
RollCurrentPieceSpecialFlags(false);
|
||||
}
|
||||
|
||||
point = GetSpawnPoint(type);
|
||||
@@ -2518,3 +2703,91 @@ void UseScreenBomb()
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
ComputeTarget();
|
||||
}
|
||||
|
||||
void UseBlackHole()
|
||||
{
|
||||
if (currentMode != MODE_ROGUE || rogueStats.blackHoleCharges <= 0 || currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int clearedCells = TriggerBlackHole();
|
||||
if (clearedCells <= 0)
|
||||
{
|
||||
SetFeedbackMessage(_T("黑洞未触发"), _T("当前棋盘上没有可被黑洞吞噬的固定方块。"), 10);
|
||||
return;
|
||||
}
|
||||
|
||||
rogueStats.blackHoleCharges--;
|
||||
|
||||
int scoreGain = clearedCells * rogueStats.scoreMultiplierPercent / 100;
|
||||
if (scoreGain < clearedCells)
|
||||
{
|
||||
scoreGain = clearedCells;
|
||||
}
|
||||
|
||||
rogueStats.score += scoreGain;
|
||||
tScore = rogueStats.score;
|
||||
|
||||
TCHAR detail[128];
|
||||
_stprintf_s(
|
||||
detail,
|
||||
_T("吞噬数量最多的一种方块,清除 %d 格 +%d Score"),
|
||||
clearedCells,
|
||||
scoreGain);
|
||||
SetFeedbackMessage(_T("主动释放黑洞"), detail, 12);
|
||||
|
||||
currentFallInterval = GetRogueFallInterval();
|
||||
ComputeTarget();
|
||||
}
|
||||
|
||||
void UseAirReshape()
|
||||
{
|
||||
if (currentMode != MODE_ROGUE || rogueStats.reshapeCharges <= 0 || currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int targetType = 0;
|
||||
const int candidateStates[2] = { 0, 1 };
|
||||
const int candidateOffsets[5] = { 0, -1, 1, -2, 2 };
|
||||
Point originalPoint = point;
|
||||
int originalType = type;
|
||||
int originalState = state;
|
||||
bool transformed = false;
|
||||
|
||||
for (int stateIndex = 0; stateIndex < 2 && !transformed; stateIndex++)
|
||||
{
|
||||
int nextState = candidateStates[stateIndex];
|
||||
for (int offsetIndex = 0; offsetIndex < 5; offsetIndex++)
|
||||
{
|
||||
Point candidatePoint = originalPoint;
|
||||
candidatePoint.x += candidateOffsets[offsetIndex];
|
||||
|
||||
if (IsPiecePlacementValid(targetType, nextState, candidatePoint))
|
||||
{
|
||||
type = targetType;
|
||||
state = nextState;
|
||||
point = candidatePoint;
|
||||
transformed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!transformed)
|
||||
{
|
||||
type = originalType;
|
||||
state = originalState;
|
||||
point = originalPoint;
|
||||
SetFeedbackMessage(_T("空中换形失败"), _T("当前空间不足,无法将方块变为 I 方块。"), 10);
|
||||
return;
|
||||
}
|
||||
|
||||
rogueStats.reshapeCharges--;
|
||||
|
||||
TCHAR detail[128];
|
||||
_stprintf_s(detail, _T("当前方块已变为 I 方块,剩余 %d 次。"), rogueStats.reshapeCharges);
|
||||
SetFeedbackMessage(_T("空中换形"), detail, 12);
|
||||
ComputeTarget();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user