补充彩虹方块与虚空核心强化链

This commit is contained in:
2026-04-25 16:36:20 +08:00
parent 750a10b5c0
commit 71a3684ce1
4 changed files with 265 additions and 18 deletions
+4
View File
@@ -87,6 +87,9 @@ struct PlayerStats
int blackHoleCharges;
int reshapeLevel;
int reshapeCharges;
int rainbowPieceLevel;
int voidCoreLevel;
int pendingRainbowPieceCount;
int stableStructureLevel;
int doubleGrowthLevel;
int gamblerLevel;
@@ -170,6 +173,7 @@ extern bool holdUsedThisTurn;
extern bool currentPieceIsExplosive;
extern bool currentPieceIsLaser;
extern bool currentPieceIsCross;
extern bool currentPieceIsRainbow;
extern int bricks[7][4][4][4];
extern COLORREF BrickColor[7];
+215 -7
View File
@@ -25,6 +25,7 @@ bool holdUsedThisTurn = false;
bool currentPieceIsExplosive = false;
bool currentPieceIsLaser = false;
bool currentPieceIsCross = false;
bool currentPieceIsRainbow = false;
Point pendingChainBombCenter = { 0, 0 };
bool pendingChainBombFollowup = false;
@@ -67,7 +68,9 @@ enum UpgradeId
UPGRADE_BLOCK_STORM = 34,
UPGRADE_CROSS_PIECE = 35,
UPGRADE_BLACK_HOLE = 36,
UPGRADE_AIR_RESHAPE = 37
UPGRADE_AIR_RESHAPE = 37,
UPGRADE_RAINBOW_PIECE = 38,
UPGRADE_VOID_CORE = 39
};
static const UpgradeEntry kUpgradePool[] =
@@ -106,6 +109,8 @@ static const UpgradeEntry kUpgradePool[] =
{ 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_RAINBOW_PIECE, 1, 74, false, _T("\u5f69\u8679\u65b9\u5757"), _T("\u723d\u611f"), _T("\u6982\u7387\u751f\u6210\u5f69\u8679\u65b9\u5757\uff0c\u843d\u5730\u540e\u53ef\u81ea\u52a8\u8865\u5168\u884c\u5185\u7f3a\u53e3\uff0c\u66f4\u5bb9\u6613\u8865\u9f50\u6d88\u884c\u3002") },
{ UPGRADE_VOID_CORE, 1, 112, false, _T("\u865a\u7a7a\u6838\u5fc3"), _T("\u8fdb\u5316"), _T("\u9ed1\u6d1e\u540e\u989d\u5916\u751f\u6210 1 \u4e2a\u5f69\u8679\u65b9\u5757\uff0c\u5f69\u8679\u6d88\u884c\u65f6\u89e6\u53d1\u5c0f\u578b\u9ed1\u6d1e\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") },
@@ -298,6 +303,9 @@ static void ResetPlayerStats(PlayerStats& stats, bool useRogueRules)
stats.blackHoleCharges = 0;
stats.reshapeLevel = 0;
stats.reshapeCharges = 0;
stats.rainbowPieceLevel = 0;
stats.voidCoreLevel = 0;
stats.pendingRainbowPieceCount = 0;
stats.stableStructureLevel = 0;
stats.doubleGrowthLevel = 0;
stats.gamblerLevel = 0;
@@ -399,6 +407,10 @@ static int GetUpgradeCurrentLevel(int upgradeId)
return rogueStats.blackHoleLevel;
case UPGRADE_AIR_RESHAPE:
return rogueStats.reshapeLevel;
case UPGRADE_RAINBOW_PIECE:
return rogueStats.rainbowPieceLevel;
case UPGRADE_VOID_CORE:
return rogueStats.voidCoreLevel;
case UPGRADE_STABLE_STRUCTURE:
return rogueStats.stableStructureLevel;
case UPGRADE_DOUBLE_GROWTH:
@@ -603,6 +615,15 @@ static int GetUpgradeDynamicWeight(const UpgradeEntry& entry)
weight += 18;
}
break;
case UPGRADE_RAINBOW_PIECE:
if (boardIsDangerous || rogueStats.totalLinesCleared >= 8)
{
weight += 16;
}
break;
case UPGRADE_VOID_CORE:
weight += 30;
break;
case UPGRADE_STABLE_STRUCTURE:
if (boardIsDangerous)
{
@@ -744,6 +765,13 @@ static bool IsUpgradeSelectable(const UpgradeEntry& entry)
rogueStats.controlMasterLevel == 0;
}
if (entry.id == UPGRADE_VOID_CORE)
{
return rogueStats.blackHoleLevel > 0 &&
rogueStats.rainbowPieceLevel > 0 &&
rogueStats.voidCoreLevel == 0;
}
if (entry.repeatable)
{
return true;
@@ -864,6 +892,70 @@ static bool RollCrossPiece()
return (rand() % 100) < chancePercent;
}
static bool RollRainbowPiece()
{
if (currentMode != MODE_ROGUE || rogueStats.rainbowPieceLevel <= 0)
{
return false;
}
int chancePercent = 12;
return (rand() % 100) < chancePercent;
}
static bool IsRainbowBoardCell(int cellValue)
{
return cellValue == 8;
}
static int TriggerMiniBlackHole(int maxCellsToClear)
{
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 || maxCellsToClear <= 0)
{
return 0;
}
int clearedCellCount = 0;
for (int y = nGameHeight - 1; y >= 0 && clearedCellCount < maxCellsToClear; y--)
{
for (int x = 0; x < nGameWidth && clearedCellCount < maxCellsToClear; x++)
{
if (workRegion[y][x] == targetBlock)
{
workRegion[y][x] = 0;
clearedCellCount++;
}
}
}
return clearedCellCount;
}
static void RollCurrentPieceSpecialFlags(bool allowRandomSpecials)
{
if (!allowRandomSpecials)
@@ -871,12 +963,24 @@ static void RollCurrentPieceSpecialFlags(bool allowRandomSpecials)
currentPieceIsExplosive = false;
currentPieceIsLaser = false;
currentPieceIsCross = false;
currentPieceIsRainbow = false;
return;
}
if (currentMode == MODE_ROGUE && rogueStats.pendingRainbowPieceCount > 0)
{
rogueStats.pendingRainbowPieceCount--;
currentPieceIsExplosive = false;
currentPieceIsLaser = false;
currentPieceIsCross = false;
currentPieceIsRainbow = true;
return;
}
currentPieceIsExplosive = RollExplosivePiece();
currentPieceIsLaser = !currentPieceIsExplosive && RollLaserPiece();
currentPieceIsCross = !currentPieceIsExplosive && !currentPieceIsLaser && RollCrossPiece();
currentPieceIsRainbow = !currentPieceIsExplosive && !currentPieceIsLaser && !currentPieceIsCross && RollRainbowPiece();
}
static int ClearExplosiveAreaAt(int centerY, int centerX)
@@ -944,6 +1048,48 @@ static int ClearRowAt(int row)
return clearedCellCount;
}
static int TriggerRainbowRowCompletion(int minRow, int maxRow)
{
int filledCellCount = 0;
if (minRow < 0)
{
minRow = 0;
}
if (maxRow >= nGameHeight)
{
maxRow = nGameHeight - 1;
}
for (int row = minRow; row <= maxRow; row++)
{
int emptyCount = 0;
int emptyColumn = -1;
bool hasRainbowCell = false;
for (int x = 0; x < nGameWidth; x++)
{
if (workRegion[row][x] == 0)
{
emptyCount++;
emptyColumn = x;
}
else if (IsRainbowBoardCell(workRegion[row][x]))
{
hasRainbowCell = true;
}
}
if (hasRainbowCell && emptyCount == 1 && emptyColumn >= 0)
{
workRegion[row][emptyColumn] = 8;
filledCellCount++;
}
}
return filledCellCount;
}
static int TriggerBlackHole()
{
int blockCounts[8] = { 0 };
@@ -1511,6 +1657,12 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
rogueStats.reshapeLevel = 1;
rogueStats.reshapeCharges++;
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;
@@ -2099,6 +2251,7 @@ void Fixing()
bool overflowTop = false;
Point explosiveCells[4] = {};
int explosiveCellCount = 0;
int rainbowFilledCount = 0;
pendingChainBombFollowup = false;
for (int i = 0; i < 4; i++)
@@ -2119,7 +2272,7 @@ void Fixing()
// 将当前方块在可视区域内的部分写入工作区
if (fixY >= 0 && fixY < nGameHeight && fixX >= 0 && fixX < nGameWidth)
{
workRegion[fixY][fixX] = bricks[type][state][i][j];
workRegion[fixY][fixX] = currentPieceIsRainbow ? 8 : bricks[type][state][i][j];
if (currentPieceIsExplosive && explosiveCellCount < 4)
{
explosiveCells[explosiveCellCount].x = fixX;
@@ -2131,6 +2284,17 @@ void Fixing()
}
}
if (!overflowTop && currentPieceIsRainbow)
{
rainbowFilledCount = TriggerRainbowRowCompletion(point.y, point.y + 3);
if (rainbowFilledCount > 0)
{
TCHAR rainbowDetail[128];
_stprintf_s(rainbowDetail, _T("\u8865\u5168 %d \u4e2a\u884c\u5185\u7f3a\u53e3\uff0c\u66f4\u5bb9\u6613\u8fbe\u6210\u6d88\u884c\u3002"), rainbowFilledCount);
SetFeedbackMessage(_T("\u5f69\u8679\u65b9\u5757\u751f\u6548"), rainbowDetail, 10);
}
}
if (overflowTop)
{
if (currentMode == MODE_ROGUE && rogueStats.terminalClearLevel > 0 && rogueStats.lastChanceCount > 0 && rogueStats.screenBombCount > 0)
@@ -2332,6 +2496,7 @@ void DeleteOneLine(int number)
int DeleteLines()
{
int clearedLines = 0;
bool clearedWithRainbow = false;
for (int i = nGameHeight - 1; i >= 0; i--)
{
@@ -2348,6 +2513,14 @@ int DeleteLines()
if (fullLine)
{
for (int j = 0; j < nGameWidth; j++)
{
if (IsRainbowBoardCell(workRegion[i][j]))
{
clearedWithRainbow = true;
break;
}
}
DeleteOneLine(i);
clearedLines++;
i++;
@@ -2400,6 +2573,25 @@ int DeleteLines()
pendingChainBombFollowup = false;
}
if (currentMode == MODE_ROGUE && clearedWithRainbow && rogueStats.voidCoreLevel > 0)
{
int miniBlackHoleCleared = TriggerMiniBlackHole(5);
if (miniBlackHoleCleared > 0)
{
int miniScore = miniBlackHoleCleared * rogueStats.scoreMultiplierPercent / 100;
if (miniScore < miniBlackHoleCleared)
{
miniScore = miniBlackHoleCleared;
}
rogueStats.score += miniScore;
tScore = rogueStats.score;
TCHAR miniDetail[128];
_stprintf_s(miniDetail, _T("\u5f69\u8679\u6d88\u884c\u89e6\u53d1\u5c0f\u578b\u9ed1\u6d1e\uff0c\u6e05\u9664 %d \u683c +%d Score"), miniBlackHoleCleared, miniScore);
SetFeedbackMessage(_T("\u865a\u7a7a\u6838\u5fc3\u89e6\u53d1"), miniDetail, 12);
}
}
return clearedLines;
}
@@ -2729,12 +2921,28 @@ void UseBlackHole()
rogueStats.score += scoreGain;
tScore = rogueStats.score;
if (rogueStats.voidCoreLevel > 0)
{
rogueStats.pendingRainbowPieceCount++;
}
TCHAR detail[128];
_stprintf_s(
detail,
_T("吞噬数量最多的一种方块,清除 %d 格 +%d Score"),
clearedCells,
scoreGain);
if (rogueStats.voidCoreLevel > 0)
{
_stprintf_s(
detail,
_T("吞噬数量最多的一种方块,清除 %d 格 +%d Score 并生成 1 个彩虹方块"),
clearedCells,
scoreGain);
}
else
{
_stprintf_s(
detail,
_T("吞噬数量最多的一种方块,清除 %d 格 +%d Score"),
clearedCells,
scoreGain);
}
SetFeedbackMessage(_T("主动释放黑洞"), detail, 12);
currentFallInterval = GetRogueFallInterval();
+38 -3
View File
@@ -454,7 +454,9 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{
if (workRegion[i][j] != 0)
{
int colorIndex = workRegion[i][j] - 1;
int cellValue = workRegion[i][j];
bool isRainbowCell = (cellValue == 8);
int colorIndex = isRainbowCell ? 0 : (cellValue - 1);
RECT brickRect =
{
gameRect.left + j * grid + SS(2),
@@ -463,8 +465,10 @@ void TDrawScreen(HDC hdc, HWND hWnd)
gameRect.top + (i + 1) * grid - SS(2)
};
HBRUSH brickBrush = CreateSolidBrush(BrickColor[colorIndex]);
HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 248, 250));
COLORREF fillColor = isRainbowCell ? RGB(255, 214, 120) : BrickColor[colorIndex];
COLORREF borderColor = isRainbowCell ? RGB(255, 248, 191) : RGB(255, 248, 250);
HBRUSH brickBrush = CreateSolidBrush(fillColor);
HPEN brickPen = CreatePen(PS_SOLID, isRainbowCell ? SS(2) : 1, borderColor);
oldPen = (HPEN)SelectObject(hdc, brickPen);
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(10), SS(10));
@@ -549,6 +553,11 @@ void TDrawScreen(HDC hdc, HWND hWnd)
activeOutlineColor = RGB(196, 255, 132);
activeOutlineWidth = SS(3);
}
else if (currentPieceIsRainbow)
{
activeOutlineColor = RGB(255, 226, 126);
activeOutlineWidth = SS(3);
}
HPEN brickPen = CreatePen(PS_SOLID, activeOutlineWidth, activeOutlineColor);
oldPen = (HPEN)SelectObject(hdc, brickPen);
oldBrush = (HBRUSH)SelectObject(hdc, brickBrush);
@@ -724,6 +733,17 @@ void TDrawScreen(HDC hdc, HWND hWnd)
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(178), crossText, lstrlen(crossText));
}
if (rogueStats.rainbowPieceLevel > 0)
{
TCHAR rainbowText[128];
_stprintf_s(
rainbowText,
_T("\u5f69\u8679\u6982\u7387 12%% %s"),
currentPieceIsRainbow ? _T("\u672c\u5757\u5df2\u5f69\u8679") :
(rogueStats.pendingRainbowPieceCount > 0 ? _T("\u4e0b\u4e00\u5757\u5f69\u8679") : _T("\u672c\u5757\u666e\u901a")));
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(210), rainbowText, lstrlen(rainbowText));
}
if (rogueStats.laserLevel > 0)
{
TCHAR laserText[96];
@@ -786,6 +806,13 @@ void TDrawScreen(HDC hdc, HWND hWnd)
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(850), reshapeText, lstrlen(reshapeText));
}
if (rogueStats.voidCoreLevel > 0)
{
TCHAR voidText[128];
_stprintf_s(voidText, _T("\u865a\u7a7a\u6838\u5fc3 \u9ed1\u6d1e\u540e\u989d\u5916\u751f\u6210\u5f69\u8679\uff0c\u5f69\u8679\u6d88\u884c\u89e6\u53d1\u5c0f\u578b\u9ed1\u6d1e"));
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(882), voidText, lstrlen(voidText));
}
if (rogueStats.terminalClearLevel > 0)
{
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(562), _T("\u7ec8\u672b\u6e05\u573a \u6fc0\u6d3b\u6700\u540e\u4e00\u640f\u65f6\u81ea\u52a8\u89e6\u53d1"), lstrlen(_T("\u7ec8\u672b\u6e05\u573a \u6fc0\u6d3b\u6700\u540e\u4e00\u640f\u65f6\u81ea\u52a8\u89e6\u53d1")));
@@ -1026,6 +1053,14 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a7a\u4e2d\u6362\u5f62 Lv.1\r\n"));
}
if (rogueStats.rainbowPieceLevel > 0)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u5f69\u8679\u65b9\u5757 Lv.1\r\n"));
}
if (rogueStats.voidCoreLevel > 0)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u865a\u7a7a\u6838\u5fc3 Lv.1\r\n"));
}
if (rogueStats.stableStructureLevel > 0)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u7a33\u5b9a\u7ed3\u6784 Lv.%d\r\n"), rogueStats.stableStructureLevel);