修改抽取机制

This commit is contained in:
2026-04-25 13:33:34 +08:00
parent 1c12d42c69
commit 51650e223d
4 changed files with 413 additions and 40 deletions
+7 -1
View File
@@ -68,6 +68,8 @@ struct PlayerStats
int screenBombCharge; int screenBombCharge;
int screenBombCount; int screenBombCount;
int terminalClearLevel; int terminalClearLevel;
int dualChoiceLevel;
int destinyWheelLevel;
int stableStructureLevel; int stableStructureLevel;
int doubleGrowthLevel; int doubleGrowthLevel;
int gamblerLevel; int gamblerLevel;
@@ -79,6 +81,7 @@ struct UpgradeOption
int id; int id;
int currentLevel; int currentLevel;
int targetPieceType; int targetPieceType;
bool cursed;
const TCHAR* name; const TCHAR* name;
const TCHAR* category; const TCHAR* category;
const TCHAR* description; const TCHAR* description;
@@ -88,6 +91,7 @@ struct UpgradeEntry
{ {
int id; int id;
int maxLevel; int maxLevel;
int baseWeight;
bool repeatable; bool repeatable;
const TCHAR* name; const TCHAR* name;
const TCHAR* category; const TCHAR* category;
@@ -100,7 +104,8 @@ struct UpgradeUiState
int optionCount; int optionCount;
int pendingCount; int pendingCount;
int totalChosenCount; int totalChosenCount;
UpgradeOption options[4]; int picksRemaining;
UpgradeOption options[5];
}; };
struct FeedbackState struct FeedbackState
@@ -169,5 +174,6 @@ void OpenRulesScreen();
void OpenUpgradeMenu(); void OpenUpgradeMenu();
void ConfirmUpgradeSelection(); void ConfirmUpgradeSelection();
void HoldCurrentPiece(); void HoldCurrentPiece();
void UseScreenBomb();
void TDrawScreen(HDC hdc, HWND hWnd); void TDrawScreen(HDC hdc, HWND hWnd);
+3
View File
@@ -419,6 +419,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case VK_SHIFT: case VK_SHIFT:
HoldCurrentPiece(); HoldCurrentPiece();
break; break;
case 'X':
UseScreenBomb();
break;
default: default:
break; break;
} }
+344 -28
View File
@@ -52,38 +52,43 @@ enum UpgradeId
UPGRADE_RAGE_STACK = 20, UPGRADE_RAGE_STACK = 20,
UPGRADE_INFINITE_FEVER = 21, UPGRADE_INFINITE_FEVER = 21,
UPGRADE_SCREEN_BOMB = 22, UPGRADE_SCREEN_BOMB = 22,
UPGRADE_TERMINAL_CLEAR = 23 UPGRADE_TERMINAL_CLEAR = 23,
UPGRADE_DUAL_CHOICE = 24,
UPGRADE_DESTINY_WHEEL = 25
}; };
static const UpgradeEntry kUpgradePool[] = static const UpgradeEntry kUpgradePool[] =
{ {
{ UPGRADE_SCORE_MULTIPLIER, -1, true, _T("\u5206\u6570\u500d\u7387"), _T("\u5f97\u5206"), _T("\u6240\u6709\u5f97\u5206\u63d0\u9ad8 20%\u3002") }, { UPGRADE_SCORE_MULTIPLIER, -1, 100, true, _T("\u5206\u6570\u500d\u7387"), _T("\u5f97\u5206"), _T("\u6240\u6709\u5f97\u5206\u63d0\u9ad8 20%\u3002") },
{ UPGRADE_COMBO_BONUS, -1, true, _T("\u8fde\u51fb\u52a0\u6210"), _T("\u8282\u594f"), _T("\u8fde\u7eed\u6d88\u884c\u65f6\u8ffd\u52a0\u8fde\u51fb\u5956\u52b1\u3002") }, { UPGRADE_COMBO_BONUS, -1, 95, true, _T("\u8fde\u51fb\u52a0\u6210"), _T("\u8282\u594f"), _T("\u8fde\u7eed\u6d88\u884c\u65f6\u8ffd\u52a0\u8fde\u51fb\u5956\u52b1\u3002") },
{ UPGRADE_SLOW_FALL, -1, true, _T("\u6162\u901f\u4e0b\u843d"), _T("\u64cd\u4f5c"), _T("\u81ea\u7136\u4e0b\u843d\u53d8\u6162\uff0c\u6bcf\u6b21\u63d0\u9ad8 80ms\u3002") }, { UPGRADE_SLOW_FALL, -1, 90, true, _T("\u6162\u901f\u4e0b\u843d"), _T("\u64cd\u4f5c"), _T("\u81ea\u7136\u4e0b\u843d\u53d8\u6162\uff0c\u6bcf\u6b21\u63d0\u9ad8 80ms\u3002") },
{ UPGRADE_PREVIEW_PLUS_ONE, 3, false, _T("\u989d\u5916\u9884\u89c8"), _T("\u89c6\u91ce"), _T("\u4e0b\u4e00\u4e2a\u65b9\u5757\u9884\u89c8 +1\uff0c\u6700\u591a 3 \u4e2a\u3002") }, { UPGRADE_PREVIEW_PLUS_ONE, 3, 85, false, _T("\u989d\u5916\u9884\u89c8"), _T("\u89c6\u91ce"), _T("\u4e0b\u4e00\u4e2a\u65b9\u5757\u9884\u89c8 +1\uff0c\u6700\u591a 3 \u4e2a\u3002") },
{ UPGRADE_EXP_MULTIPLIER, -1, true, _T("\u7ecf\u9a8c\u5f3a\u5316"), _T("\u6210\u957f"), _T("\u540e\u7eed\u6d88\u884c\u83b7\u5f97 EXP \u63d0\u9ad8 25%\u3002") }, { UPGRADE_EXP_MULTIPLIER, -1, 100, true, _T("\u7ecf\u9a8c\u5f3a\u5316"), _T("\u6210\u957f"), _T("\u540e\u7eed\u6d88\u884c\u83b7\u5f97 EXP \u63d0\u9ad8 25%\u3002") },
{ UPGRADE_LAST_CHANCE, 1, false, _T("\u6700\u540e\u4e00\u640f"), _T("\u4fdd\u547d"), _T("\u9996\u6b21\u9876\u6b7b\u65f6\u81ea\u52a8\u6e05\u9664\u5e95\u90e8 3 \u884c\u5e76\u7ee7\u7eed\u6e38\u620f\u3002") }, { UPGRADE_LAST_CHANCE, 1, 72, false, _T("\u6700\u540e\u4e00\u640f"), _T("\u4fdd\u547d"), _T("\u9996\u6b21\u9876\u6b7b\u65f6\u81ea\u52a8\u6e05\u9664\u5e95\u90e8 3 \u884c\u5e76\u7ee7\u7eed\u6e38\u620f\u3002") },
{ UPGRADE_HOLD_UNLOCK, 1, false, _T("Hold \u89e3\u9501"), _T("\u7279\u6b8a"), _T("\u89e3\u9501 Hold \u69fd\uff0c\u5bf9\u5c40\u4e2d\u53ef\u7528 C \u6216 Shift \u6682\u5b58\u65b9\u5757\u3002") }, { UPGRADE_HOLD_UNLOCK, 1, 78, false, _T("Hold \u89e3\u9501"), _T("\u7279\u6b8a"), _T("\u89e3\u9501 Hold \u69fd\uff0c\u5bf9\u5c40\u4e2d\u53ef\u7528 C \u6216 Shift \u6682\u5b58\u65b9\u5757\u3002") },
{ UPGRADE_PRESSURE_RELIEF, -1, true, _T("\u51cf\u538b"), _T("\u7279\u6b8a"), _T("\u7acb\u5373\u6e05\u9664\u5f53\u524d\u6700\u9ad8\u5360\u7528\u884c\uff0c\u4e3a\u76d8\u9762\u817e\u51fa\u547c\u5438\u7a7a\u95f4\u3002") }, { UPGRADE_PRESSURE_RELIEF, -1, 82, true, _T("\u51cf\u538b"), _T("\u7279\u6b8a"), _T("\u7acb\u5373\u6e05\u9664\u5f53\u524d\u6700\u9ad8\u5360\u7528\u884c\uff0c\u4e3a\u76d8\u9762\u817e\u51fa\u547c\u5438\u7a7a\u95f4\u3002") },
{ UPGRADE_SWEEPER, -1, true, _T("\u6e05\u626b\u8005"), _T("\u7279\u6b8a"), _T("\u7d2f\u8ba1\u6d88\u884c\u5145\u80fd\uff0c\u6536\u6ee1\u540e\u81ea\u52a8\u6e05\u9664\u5e95\u90e8 1 \u884c\u3002") }, { UPGRADE_SWEEPER, -1, 74, true, _T("\u6e05\u626b\u8005"), _T("\u7279\u6b8a"), _T("\u7d2f\u8ba1\u6d88\u884c\u5145\u80fd\uff0c\u6536\u6ee1\u540e\u81ea\u52a8\u6e05\u9664\u5e95\u90e8 1 \u884c\u3002") },
{ UPGRADE_EXPLOSIVE_PIECE, -1, true, _T("\u7206\u7834\u65b9\u5757"), _T("\u7279\u6b8a"), _T("\u63d0\u9ad8\u7206\u7834\u65b9\u5757\u51fa\u73b0\u6982\u7387\uff0c\u843d\u5730\u65f6\u89e6\u53d1 3x3 \u6e05\u9664\u3002") }, { UPGRADE_EXPLOSIVE_PIECE, -1, 76, true, _T("\u7206\u7834\u65b9\u5757"), _T("\u7279\u6b8a"), _T("\u63d0\u9ad8\u7206\u7834\u65b9\u5757\u51fa\u73b0\u6982\u7387\uff0c\u843d\u5730\u65f6\u89e6\u53d1 3x3 \u6e05\u9664\u3002") },
{ UPGRADE_CHAIN_BLAST, 1, false, _T("\u8fde\u9501\u7206\u7834"), _T("\u8fdb\u9636"), _T("\u6d88\u884c\u540e\u5bf9\u88ab\u6e05\u9664\u884c\u9644\u8fd1\u968f\u673a\u6e05\u6389\u51e0\u683c\u3002") }, { UPGRADE_CHAIN_BLAST, 1, 92, false, _T("\u8fde\u9501\u7206\u7834"), _T("\u8fdb\u9636"), _T("\u6d88\u884c\u540e\u5bf9\u88ab\u6e05\u9664\u884c\u9644\u8fd1\u968f\u673a\u6e05\u6389\u51e0\u683c\u3002") },
{ UPGRADE_CHAIN_BOMB, 1, false, _T("\u8fde\u73af\u70b8\u5f39"), _T("\u8fdb\u5316"), _T("\u7206\u7834\u8303\u56f4\u63d0\u5347\u4e3a 5x5\uff0c\u82e5\u5f15\u53d1\u6d88\u884c\u5219\u8ffd\u52a0\u4e00\u6b21\u5c0f\u7206\u70b8\u3002") }, { UPGRADE_CHAIN_BOMB, 1, 110, false, _T("\u8fde\u73af\u70b8\u5f39"), _T("\u8fdb\u5316"), _T("\u7206\u7834\u8303\u56f4\u63d0\u5347\u4e3a 5x5\uff0c\u82e5\u5f15\u53d1\u6d88\u884c\u5219\u8ffd\u52a0\u4e00\u6b21\u5c0f\u7206\u70b8\u3002") },
{ UPGRADE_LASER_PIECE, -1, true, _T("\u6fc0\u5149\u65b9\u5757"), _T("\u7279\u6b8a"), _T("\u63d0\u9ad8\u6fc0\u5149\u65b9\u5757\u51fa\u73b0\u6982\u7387\uff0c\u843d\u5730\u540e\u6e05\u9664\u6240\u5728\u6574\u5217\u3002") }, { UPGRADE_LASER_PIECE, -1, 72, true, _T("\u6fc0\u5149\u65b9\u5757"), _T("\u7279\u6b8a"), _T("\u63d0\u9ad8\u6fc0\u5149\u65b9\u5757\u51fa\u73b0\u6982\u7387\uff0c\u843d\u5730\u540e\u6e05\u9664\u6240\u5728\u6574\u5217\u3002") },
{ UPGRADE_THUNDER_TETRIS, 1, false, _T("\u96f7\u9706\u56db\u6d88"), _T("\u8fdb\u9636"), _T("\u6bcf\u6b21\u5b8c\u6210\u56db\u6d88\u65f6\uff0c\u989d\u5916\u6e05\u9664\u968f\u673a 2 \u884c\u3002") }, { UPGRADE_THUNDER_TETRIS, 1, 94, false, _T("\u96f7\u9706\u56db\u6d88"), _T("\u8fdb\u9636"), _T("\u6bcf\u6b21\u5b8c\u6210\u56db\u6d88\u65f6\uff0c\u989d\u5916\u6e05\u9664\u968f\u673a 2 \u884c\u3002") },
{ UPGRADE_THUNDER_LASER, 1, false, _T("\u96f7\u9706\u6fc0\u5149"), _T("\u8fdb\u5316"), _T("\u56db\u6d88\u65f6\u989d\u5916\u53d1\u5c04 2 \u9053\u6fc0\u5149\uff0c\u968f\u673a\u6e05\u9664 2 \u5217\u5e76\u83b7\u5f97 EXP\u3002") }, { UPGRADE_THUNDER_LASER, 1, 112, false, _T("\u96f7\u9706\u6fc0\u5149"), _T("\u8fdb\u5316"), _T("\u56db\u6d88\u65f6\u989d\u5916\u53d1\u5c04 2 \u9053\u6fc0\u5149\uff0c\u968f\u673a\u6e05\u9664 2 \u5217\u5e76\u83b7\u5f97 EXP\u3002") },
{ UPGRADE_FEVER_MODE, 1, false, _T("\u72c2\u70ed\u6a21\u5f0f"), _T("\u8fdb\u9636"), _T("\u7d2f\u8ba1\u6d88\u884c 20 \u884c\u540e\u8fdb\u5165 10 \u79d2\u72c2\u70ed\u72b6\u6001\u3002") }, { UPGRADE_FEVER_MODE, 1, 84, false, _T("\u72c2\u70ed\u6a21\u5f0f"), _T("\u8fdb\u9636"), _T("\u7d2f\u8ba1\u6d88\u884c 20 \u884c\u540e\u8fdb\u5165 10 \u79d2\u72c2\u70ed\u72b6\u6001\u3002") },
{ UPGRADE_RAGE_STACK, 1, false, _T("\u66b4\u8d70\u5806\u53e0"), _T("\u8fdb\u9636"), _T("\u8fde\u7eed\u6d88\u884c\u8d8a\u591a\uff0c\u5f97\u5206\u500d\u7387\u8ffd\u52a0\u8d8a\u9ad8\u3002") }, { UPGRADE_RAGE_STACK, 1, 84, false, _T("\u66b4\u8d70\u5806\u53e0"), _T("\u8fdb\u9636"), _T("\u8fde\u7eed\u6d88\u884c\u8d8a\u591a\uff0c\u5f97\u5206\u500d\u7387\u8ffd\u52a0\u8d8a\u9ad8\u3002") },
{ UPGRADE_INFINITE_FEVER, 1, false, _T("\u65e0\u9650\u72c2\u70ed"), _T("\u8fdb\u5316"), _T("\u72c2\u70ed\u671f\u95f4\u6d88\u884c\u53ef\u5ef6\u957f\u65f6\u95f4\uff0c\u8fde\u51fb\u8d8a\u9ad8\u500d\u7387\u8d8a\u5f3a\u3002") }, { UPGRADE_INFINITE_FEVER, 1, 110, false, _T("\u65e0\u9650\u72c2\u70ed"), _T("\u8fdb\u5316"), _T("\u72c2\u70ed\u671f\u95f4\u6d88\u884c\u53ef\u5ef6\u957f\u65f6\u95f4\uff0c\u8fde\u51fb\u8d8a\u9ad8\u500d\u7387\u8d8a\u5f3a\u3002") },
{ UPGRADE_SCREEN_BOMB, 1, false, _T("\u6e05\u5c4f\u70b8\u5f39"), _T("\u8fdb\u9636"), _T("\u7d2f\u8ba1\u6d88\u884c 30 \u884c\u540e\u83b7\u5f97 1 \u6b21\u6e05\u5c4f\u70b8\u5f39\uff0c\u53ef\u81ea\u52a8\u6216\u4e3b\u52a8\u6e05\u9664\u5e95\u90e8 5 \u884c\u3002") }, { UPGRADE_SCREEN_BOMB, 1, 78, false, _T("\u6e05\u5c4f\u70b8\u5f39"), _T("\u8fdb\u9636"), _T("\u7d2f\u8ba1\u6d88\u884c 30 \u884c\u540e\u83b7\u5f97 1 \u6b21\u6e05\u5c4f\u70b8\u5f39\uff0c\u53ef\u81ea\u52a8\u6216\u4e3b\u52a8\u6e05\u9664\u5e95\u90e8 5 \u884c\u3002") },
{ UPGRADE_TERMINAL_CLEAR, 1, false, _T("\u7ec8\u672b\u6e05\u573a"), _T("\u8fdb\u5316"), _T("\u6fc0\u6d3b\u6700\u540e\u4e00\u640f\u65f6\u81ea\u52a8\u91ca\u653e\u4e00\u6b21\u6e05\u5c4f\u70b8\u5f39\uff0c\u5e76\u8fdb\u5165 10 \u79d2\u72c2\u70ed\u3002") }, { UPGRADE_TERMINAL_CLEAR, 1, 108, false, _T("\u7ec8\u672b\u6e05\u573a"), _T("\u8fdb\u5316"), _T("\u6fc0\u6d3b\u6700\u540e\u4e00\u640f\u65f6\u81ea\u52a8\u91ca\u653e\u4e00\u6b21\u6e05\u5c4f\u70b8\u5f39\uff0c\u5e76\u8fdb\u5165 10 \u79d2\u72c2\u70ed\u3002") },
{ UPGRADE_STABLE_STRUCTURE, -1, 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_DUAL_CHOICE, 1, 68, false, _T("\u53cc\u91cd\u9009\u62e9"), _T("\u8fdb\u9636"), _T("\u6bcf\u6b21\u5347\u7ea7\u53ef\u989d\u5916\u518d\u9009 1 \u4e2a\u5f3a\u5316\uff0c\u4f46\u4e0b\u4e00\u6b21\u5347\u7ea7\u9700\u6c42 +30%\u3002") },
{ UPGRADE_DOUBLE_GROWTH, -1, true, _T("\u53cc\u500d\u6210\u957f"), _T("\u7279\u6b8a"), _T("\u989d\u5916\u63d0\u9ad8\u6d88\u884c\u5f97\u5206\u4e0e EXP \u6536\u76ca\uff0c\u6bcf\u5c42\u518d\u8ffd\u52a0 15%\u3002") }, { UPGRADE_DESTINY_WHEEL, 1, 104, false, _T("\u547d\u8fd0\u8f6e\u76d8"), _T("\u8fdb\u5316"), _T("\u6bcf\u6b21\u5347\u7ea7\u51fa\u73b0 5 \u4e2a\u9009\u9879\uff0c\u53ef\u9009 2 \u4e2a\uff0c\u4f46\u5176\u4e2d 1 \u4e2a\u9644\u5e26\u8d1f\u9762\u6548\u679c\u3002") },
{ UPGRADE_PIECE_TUNING, -1, 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") }, { 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_GAMBLER, -1, true, _T("\u8d4c\u5f92"), _T("\u7279\u6b8a"), _T("\u9009\u62e9\u5f3a\u5316\u65f6\uff0c\u6709\u6982\u7387\u53cc\u500d\u751f\u6548\uff0c\u4e5f\u6709\u6982\u7387\u5b8c\u5168\u843d\u7a7a\u3002") } { UPGRADE_DOUBLE_GROWTH, -1, 86, true, _T("\u53cc\u500d\u6210\u957f"), _T("\u7279\u6b8a"), _T("\u989d\u5916\u63d0\u9ad8\u6d88\u884c\u5f97\u5206\u4e0e EXP \u6536\u76ca\uff0c\u6bcf\u5c42\u518d\u8ffd\u52a0 15%\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") },
{ UPGRADE_GAMBLER, -1, 64, true, _T("\u8d4c\u5f92"), _T("\u7279\u6b8a"), _T("\u9009\u62e9\u5f3a\u5316\u65f6\uff0c\u6709\u6982\u7387\u53cc\u500d\u751f\u6548\uff0c\u4e5f\u6709\u6982\u7387\u5b8c\u5168\u843d\u7a7a\u3002") }
}; };
static constexpr int kUpgradePoolSize = sizeof(kUpgradePool) / sizeof(kUpgradePool[0]); static constexpr int kUpgradePoolSize = sizeof(kUpgradePool) / sizeof(kUpgradePool[0]);
static int GetTopOccupiedRow();
int bricks[7][4][4][4] = int bricks[7][4][4][4] =
{ {
@@ -250,6 +255,8 @@ static void ResetPlayerStats(PlayerStats& stats, bool useRogueRules)
stats.screenBombCharge = 0; stats.screenBombCharge = 0;
stats.screenBombCount = 0; stats.screenBombCount = 0;
stats.terminalClearLevel = 0; stats.terminalClearLevel = 0;
stats.dualChoiceLevel = 0;
stats.destinyWheelLevel = 0;
stats.stableStructureLevel = 0; stats.stableStructureLevel = 0;
stats.doubleGrowthLevel = 0; stats.doubleGrowthLevel = 0;
stats.gamblerLevel = 0; stats.gamblerLevel = 0;
@@ -323,6 +330,10 @@ static int GetUpgradeCurrentLevel(int upgradeId)
return rogueStats.screenBombLevel; return rogueStats.screenBombLevel;
case UPGRADE_TERMINAL_CLEAR: case UPGRADE_TERMINAL_CLEAR:
return rogueStats.terminalClearLevel; return rogueStats.terminalClearLevel;
case UPGRADE_DUAL_CHOICE:
return rogueStats.dualChoiceLevel;
case UPGRADE_DESTINY_WHEEL:
return rogueStats.destinyWheelLevel;
case UPGRADE_STABLE_STRUCTURE: case UPGRADE_STABLE_STRUCTURE:
return rogueStats.stableStructureLevel; return rogueStats.stableStructureLevel;
case UPGRADE_DOUBLE_GROWTH: case UPGRADE_DOUBLE_GROWTH:
@@ -334,6 +345,175 @@ static int GetUpgradeCurrentLevel(int upgradeId)
} }
} }
static int GetUpgradeDynamicWeight(const UpgradeEntry& entry)
{
int weight = entry.baseWeight;
int currentLevel = GetUpgradeCurrentLevel(entry.id);
int topOccupiedRow = GetTopOccupiedRow();
bool boardIsDangerous = (topOccupiedRow >= 0 && topOccupiedRow <= 6);
bool boardIsStable = (topOccupiedRow < 0 || topOccupiedRow >= 12);
if (entry.repeatable)
{
weight -= currentLevel * 8;
}
else if (currentLevel > 0)
{
weight = 0;
}
switch (entry.id)
{
case UPGRADE_SCORE_MULTIPLIER:
if (rogueStats.level >= 4)
{
weight += 8;
}
break;
case UPGRADE_EXP_MULTIPLIER:
if (rogueStats.level <= 5)
{
weight += 16;
}
break;
case UPGRADE_SLOW_FALL:
if (boardIsDangerous)
{
weight += 22;
}
break;
case UPGRADE_COMBO_BONUS:
if (rogueStats.comboChain >= 2)
{
weight += 18;
}
break;
case UPGRADE_PREVIEW_PLUS_ONE:
if (boardIsStable)
{
weight += 10;
}
break;
case UPGRADE_LAST_CHANCE:
if (boardIsDangerous)
{
weight += 30;
}
break;
case UPGRADE_HOLD_UNLOCK:
if (rogueStats.holdUnlocked == 0 && rogueStats.level <= 6)
{
weight += 14;
}
break;
case UPGRADE_PRESSURE_RELIEF:
if (boardIsDangerous)
{
weight += 26;
}
break;
case UPGRADE_SWEEPER:
if (rogueStats.totalLinesCleared >= 8)
{
weight += 12;
}
break;
case UPGRADE_EXPLOSIVE_PIECE:
if (rogueStats.explosiveLevel == 0)
{
weight += 12;
}
break;
case UPGRADE_CHAIN_BLAST:
weight += rogueStats.explosiveLevel * 20;
break;
case UPGRADE_CHAIN_BOMB:
weight += 28;
break;
case UPGRADE_LASER_PIECE:
if (rogueStats.laserLevel == 0)
{
weight += 10;
}
break;
case UPGRADE_THUNDER_TETRIS:
weight += rogueStats.laserLevel * 18;
break;
case UPGRADE_THUNDER_LASER:
weight += 28;
break;
case UPGRADE_FEVER_MODE:
if (rogueStats.totalLinesCleared >= 10)
{
weight += 14;
}
break;
case UPGRADE_RAGE_STACK:
if (rogueStats.comboBonusStacks > 0 || rogueStats.comboChain >= 2)
{
weight += 18;
}
break;
case UPGRADE_INFINITE_FEVER:
if (rogueStats.feverLevel > 0 && rogueStats.rageStackLevel > 0)
{
weight += 34;
}
break;
case UPGRADE_SCREEN_BOMB:
if (boardIsDangerous)
{
weight += 18;
}
break;
case UPGRADE_TERMINAL_CLEAR:
weight += 34;
break;
case UPGRADE_DUAL_CHOICE:
if (rogueStats.level <= 6)
{
weight += 10;
}
break;
case UPGRADE_DESTINY_WHEEL:
weight += 30;
break;
case UPGRADE_STABLE_STRUCTURE:
if (boardIsDangerous)
{
weight += 14;
}
break;
case UPGRADE_DOUBLE_GROWTH:
if (rogueStats.level >= 3)
{
weight += 12;
}
break;
case UPGRADE_PIECE_TUNING:
if (rogueStats.level >= 4)
{
weight += 8;
}
break;
case UPGRADE_GAMBLER:
if (rogueStats.level >= 5)
{
weight += 10;
}
break;
default:
break;
}
if (weight < 1)
{
weight = 1;
}
return weight;
}
static const TCHAR* GetPieceShortName(int pieceType) static const TCHAR* GetPieceShortName(int pieceType)
{ {
static const TCHAR* kPieceNames[7] = static const TCHAR* kPieceNames[7] =
@@ -402,6 +582,16 @@ static bool IsUpgradeSelectable(const UpgradeEntry& entry)
return rogueStats.screenBombLevel > 0 && rogueStats.lastChanceUpgradeLevel > 0 && rogueStats.terminalClearLevel == 0; return rogueStats.screenBombLevel > 0 && rogueStats.lastChanceUpgradeLevel > 0 && rogueStats.terminalClearLevel == 0;
} }
if (entry.id == UPGRADE_DUAL_CHOICE)
{
return rogueStats.dualChoiceLevel == 0;
}
if (entry.id == UPGRADE_DESTINY_WHEEL)
{
return rogueStats.gamblerLevel > 0 && rogueStats.dualChoiceLevel > 0 && rogueStats.destinyWheelLevel == 0;
}
if (entry.repeatable) if (entry.repeatable)
{ {
return true; return true;
@@ -751,29 +941,57 @@ static int ApplyLevelProgress(PlayerStats& stats)
static void FillUpgradeOptions() static void FillUpgradeOptions()
{ {
int selectableIndexes[kUpgradePoolSize] = { 0 }; int selectableIndexes[kUpgradePoolSize] = { 0 };
int selectableWeights[kUpgradePoolSize] = { 0 };
int selectableCount = 0; int selectableCount = 0;
for (int i = 0; i < kUpgradePoolSize; i++) for (int i = 0; i < kUpgradePoolSize; i++)
{ {
if (IsUpgradeSelectable(kUpgradePool[i])) if (IsUpgradeSelectable(kUpgradePool[i]))
{ {
selectableIndexes[selectableCount++] = i; selectableIndexes[selectableCount] = i;
selectableWeights[selectableCount] = GetUpgradeDynamicWeight(kUpgradePool[i]);
selectableCount++;
} }
} }
int optionCount = selectableCount < 4 ? selectableCount : 4; int optionLimit = (rogueStats.destinyWheelLevel > 0) ? 5 : 4;
int optionCount = selectableCount < optionLimit ? selectableCount : optionLimit;
upgradeUiState.optionCount = optionCount; upgradeUiState.optionCount = optionCount;
upgradeUiState.selectedIndex = 0; upgradeUiState.selectedIndex = 0;
upgradeUiState.picksRemaining = (rogueStats.dualChoiceLevel > 0 || rogueStats.destinyWheelLevel > 0) ? 2 : 1;
for (int i = 0; i < optionCount; i++) for (int i = 0; i < optionCount; i++)
{ {
int pickSlot = rand() % selectableCount; int totalWeight = 0;
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
{
totalWeight += selectableWeights[weightIndex];
}
int pickSlot = 0;
if (totalWeight > 0)
{
int roll = rand() % totalWeight;
int accumulatedWeight = 0;
for (int weightIndex = 0; weightIndex < selectableCount; weightIndex++)
{
accumulatedWeight += selectableWeights[weightIndex];
if (roll < accumulatedWeight)
{
pickSlot = weightIndex;
break;
}
}
}
int pickedIndex = selectableIndexes[pickSlot]; int pickedIndex = selectableIndexes[pickSlot];
const UpgradeEntry& pickedEntry = kUpgradePool[pickedIndex]; const UpgradeEntry& pickedEntry = kUpgradePool[pickedIndex];
upgradeUiState.options[i].id = pickedEntry.id; upgradeUiState.options[i].id = pickedEntry.id;
upgradeUiState.options[i].currentLevel = GetUpgradeCurrentLevel(pickedEntry.id); upgradeUiState.options[i].currentLevel = GetUpgradeCurrentLevel(pickedEntry.id);
upgradeUiState.options[i].targetPieceType = -1; upgradeUiState.options[i].targetPieceType = -1;
upgradeUiState.options[i].cursed = false;
upgradeUiState.options[i].name = pickedEntry.name; upgradeUiState.options[i].name = pickedEntry.name;
upgradeUiState.options[i].category = pickedEntry.category; upgradeUiState.options[i].category = pickedEntry.category;
upgradeUiState.options[i].description = pickedEntry.description; upgradeUiState.options[i].description = pickedEntry.description;
@@ -813,8 +1031,15 @@ static void FillUpgradeOptions()
} }
selectableIndexes[pickSlot] = selectableIndexes[selectableCount - 1]; selectableIndexes[pickSlot] = selectableIndexes[selectableCount - 1];
selectableWeights[pickSlot] = selectableWeights[selectableCount - 1];
selectableCount--; selectableCount--;
} }
if (rogueStats.destinyWheelLevel > 0 && optionCount > 0)
{
int cursedIndex = rand() % optionCount;
upgradeUiState.options[cursedIndex].cursed = true;
}
} }
static int GetRogueFallInterval() static int GetRogueFallInterval()
@@ -917,6 +1142,17 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount)
case UPGRADE_TERMINAL_CLEAR: case UPGRADE_TERMINAL_CLEAR:
rogueStats.terminalClearLevel = 1; rogueStats.terminalClearLevel = 1;
break; break;
case UPGRADE_DUAL_CHOICE:
rogueStats.dualChoiceLevel = 1;
rogueStats.requiredExp = rogueStats.requiredExp * 130 / 100;
if (rogueStats.requiredExp < 10)
{
rogueStats.requiredExp = 10;
}
break;
case UPGRADE_DESTINY_WHEEL:
rogueStats.destinyWheelLevel = 1;
break;
case UPGRADE_STABLE_STRUCTURE: case UPGRADE_STABLE_STRUCTURE:
rogueStats.stableStructureLevel += applyCount; rogueStats.stableStructureLevel += applyCount;
break; break;
@@ -1204,6 +1440,17 @@ static void ApplyLineClearResult(int linesCleared)
} }
} }
static void ApplyDestinyCurse()
{
int expPenalty = rogueStats.requiredExp * 25 / 100;
if (expPenalty < 10)
{
expPenalty = 10;
}
rogueStats.requiredExp += expPenalty;
}
/** /**
* @brief 判断当前方块是否可以继续向下移动。 * @brief 判断当前方块是否可以继续向下移动。
* *
@@ -1738,6 +1985,7 @@ void Restart()
upgradeUiState.optionCount = 0; upgradeUiState.optionCount = 0;
upgradeUiState.pendingCount = 0; upgradeUiState.pendingCount = 0;
upgradeUiState.totalChosenCount = 0; upgradeUiState.totalChosenCount = 0;
upgradeUiState.picksRemaining = 0;
feedbackState.visibleTicks = 0; feedbackState.visibleTicks = 0;
feedbackState.title[0] = _T('\0'); feedbackState.title[0] = _T('\0');
feedbackState.detail[0] = _T('\0'); feedbackState.detail[0] = _T('\0');
@@ -1776,6 +2024,7 @@ void ReturnToMainMenu()
gameOverFlag = false; gameOverFlag = false;
menuState.optionCount = 3; menuState.optionCount = 3;
upgradeUiState.pendingCount = 0; upgradeUiState.pendingCount = 0;
upgradeUiState.picksRemaining = 0;
if (menuState.selectedIndex < 0 || menuState.selectedIndex >= menuState.optionCount) if (menuState.selectedIndex < 0 || menuState.selectedIndex >= menuState.optionCount)
{ {
@@ -1849,8 +2098,43 @@ void ConfirmUpgradeSelection()
{ {
_stprintf_s(feedbackDetail, _T("%s%s"), selectedOption.description, gamblerSuffix); _stprintf_s(feedbackDetail, _T("%s%s"), selectedOption.description, gamblerSuffix);
} }
if (selectedOption.cursed)
{
ApplyDestinyCurse();
_stprintf_s(
feedbackDetail + lstrlen(feedbackDetail),
128 - lstrlen(feedbackDetail),
_T(" \u8be5\u9009\u9879\u9644\u5e26\u8bc5\u5492\uff1a\u4e0b\u6b21\u5347\u7ea7\u6240\u9700 EXP \u63d0\u9ad8 25%\u3002"));
}
SetFeedbackMessage(feedbackTitle, feedbackDetail, 12); SetFeedbackMessage(feedbackTitle, feedbackDetail, 12);
if (upgradeUiState.picksRemaining > 0)
{
upgradeUiState.picksRemaining--;
}
for (int i = upgradeUiState.selectedIndex; i + 1 < upgradeUiState.optionCount; i++)
{
upgradeUiState.options[i] = upgradeUiState.options[i + 1];
}
if (upgradeUiState.optionCount > 0)
{
upgradeUiState.optionCount--;
}
if (upgradeUiState.optionCount > 0 && upgradeUiState.selectedIndex >= upgradeUiState.optionCount)
{
upgradeUiState.selectedIndex = upgradeUiState.optionCount - 1;
}
if (upgradeUiState.picksRemaining > 0 && upgradeUiState.optionCount > 0)
{
currentScreen = SCREEN_UPGRADE;
return;
}
if (upgradeUiState.pendingCount > 0) if (upgradeUiState.pendingCount > 0)
{ {
upgradeUiState.pendingCount--; upgradeUiState.pendingCount--;
@@ -1863,6 +2147,9 @@ void ConfirmUpgradeSelection()
return; return;
} }
upgradeUiState.optionCount = 0;
upgradeUiState.picksRemaining = 0;
currentScreen = SCREEN_PLAYING; currentScreen = SCREEN_PLAYING;
} }
@@ -1913,3 +2200,32 @@ void HoldCurrentPiece()
SetFeedbackMessage(_T("Hold \u5df2\u4ea4\u6362"), _T("\u5df2\u4e0e Hold \u69fd\u4e2d\u7684\u65b9\u5757\u4ea4\u6362\u3002"), 10); SetFeedbackMessage(_T("Hold \u5df2\u4ea4\u6362"), _T("\u5df2\u4e0e Hold \u69fd\u4e2d\u7684\u65b9\u5757\u4ea4\u6362\u3002"), 10);
} }
} }
void UseScreenBomb()
{
if (currentMode != MODE_ROGUE || rogueStats.screenBombCount <= 0 || currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag)
{
return;
}
rogueStats.screenBombCount--;
int clearedCells = TriggerScreenBomb();
int scoreGain = clearedCells * rogueStats.scoreMultiplierPercent / 100;
if (scoreGain < clearedCells)
{
scoreGain = clearedCells;
}
rogueStats.score += scoreGain;
tScore = rogueStats.score;
TCHAR detail[128];
_stprintf_s(
detail,
_T("\u6e05\u9664\u5e95\u90e8 5 \u884c\uff0c\u6e05\u6389 %d \u683c +%d Score"),
clearedCells,
scoreGain);
SetFeedbackMessage(_T("\u4e3b\u52a8\u91ca\u653e\u6e05\u5c4f\u70b8\u5f39"), detail, 12);
ComputeTarget();
}
+59 -11
View File
@@ -748,7 +748,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
if (rogueStats.screenBombLevel > 0) if (rogueStats.screenBombLevel > 0)
{ {
TCHAR bombText[96]; TCHAR bombText[96];
_stprintf_s(bombText, _T("\u6e05\u5c4f\u70b8\u5f39 %d / 30 \u5e93\u5b58 %d"), rogueStats.screenBombCharge, rogueStats.screenBombCount); _stprintf_s(bombText, _T("\u6e05\u5c4f\u70b8\u5f39 %d / 30 \u5e93\u5b58 %d X \u4e3b\u52a8\u91ca\u653e"), rogueStats.screenBombCharge, rogueStats.screenBombCount);
TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(530), bombText, lstrlen(bombText)); TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(530), bombText, lstrlen(bombText));
} }
@@ -934,6 +934,14 @@ void TDrawScreen(HDC hdc, HWND hWnd)
{ {
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8d4c\u5f92 Lv.%d\r\n"), rogueStats.gamblerLevel); _stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u8d4c\u5f92 Lv.%d\r\n"), rogueStats.gamblerLevel);
} }
if (rogueStats.dualChoiceLevel > 0)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u53cc\u91cd\u9009\u62e9 Lv.1\r\n"));
}
if (rogueStats.destinyWheelLevel > 0)
{
_stprintf_s(upgradeSummary + lstrlen(upgradeSummary), 512 - lstrlen(upgradeSummary), _T("\u547d\u8fd0\u8f6e\u76d8 Lv.1\r\n"));
}
if (lstrlen(upgradeSummary) == 0) if (lstrlen(upgradeSummary) == 0)
{ {
_stprintf_s(upgradeSummary, _T("\u6682\u672a\u9009\u62e9\u4efb\u4f55\u5f3a\u5316\u3002\r\n\u5347\u7ea7\u540e\u4f1a\u5728\u8fd9\u91cc\u7d2f\u79ef\u663e\u793a\u3002")); _stprintf_s(upgradeSummary, _T("\u6682\u672a\u9009\u62e9\u4efb\u4f55\u5f3a\u5316\u3002\r\n\u5347\u7ea7\u540e\u4f1a\u5728\u8fd9\u91cc\u7d2f\u79ef\u663e\u793a\u3002"));
@@ -1243,13 +1251,25 @@ void TDrawScreen(HDC hdc, HWND hWnd)
overlayRect.right, overlayRect.right,
overlayRect.top + SS(106) overlayRect.top + SS(106)
}; };
DrawText(hdc, _T("\u8bf7\u4ece\u4e09\u4e2a\u9009\u9879\u4e2d\u9009\u62e9\u4e00\u4e2a\u5f3a\u5316"), -1, &overlaySubtitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); TCHAR overlaySubtitle[128];
_stprintf_s(
overlaySubtitle,
_T("\u672c\u6b21\u51fa\u73b0 %d \u4e2a\u9009\u9879\uff0c\u8fd8\u53ef\u9009 %d \u4e2a"),
upgradeUiState.optionCount,
upgradeUiState.picksRemaining);
DrawText(hdc, overlaySubtitle, -1, &overlaySubtitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
int gap = SS(18); int gap = SS(18);
int horizontalPadding = SS(36); int horizontalPadding = SS(36);
int verticalTop = overlayRect.top + SS(138); int verticalTop = overlayRect.top + SS(138);
int rowCount = (upgradeUiState.optionCount + 1) / 2;
if (rowCount < 1)
{
rowCount = 1;
}
int cardWidth = (overlayRect.right - overlayRect.left - horizontalPadding * 2 - gap) / 2; int cardWidth = (overlayRect.right - overlayRect.left - horizontalPadding * 2 - gap) / 2;
int cardHeight = (overlayRect.bottom - verticalTop - SS(72) - gap) / 2; int availableHeight = overlayRect.bottom - verticalTop - SS(72) - (rowCount - 1) * gap;
int cardHeight = availableHeight / rowCount;
for (int i = 0; i < upgradeUiState.optionCount; i++) for (int i = 0; i < upgradeUiState.optionCount; i++)
{ {
@@ -1268,8 +1288,31 @@ void TDrawScreen(HDC hdc, HWND hWnd)
top + cardHeight top + cardHeight
}; };
HBRUSH cardBrush = CreateSolidBrush(isSelected ? RGB(255, 235, 242) : RGB(255, 247, 250)); COLORREF cardFill = RGB(255, 247, 250);
HPEN cardPen = CreatePen(PS_SOLID, isSelected ? SS(3) : 1, isSelected ? accentColor : RGB(221, 197, 208)); COLORREF cardBorder = RGB(221, 197, 208);
COLORREF iconFill = RGB(233, 206, 217);
COLORREF categoryColor = RGB(122, 95, 110);
COLORREF descColor = RGB(108, 86, 99);
COLORREF footerColor = RGB(128, 104, 118);
if (upgradeUiState.options[i].cursed)
{
cardFill = isSelected ? RGB(255, 233, 233) : RGB(255, 243, 243);
cardBorder = isSelected ? RGB(210, 92, 92) : RGB(224, 156, 156);
iconFill = isSelected ? RGB(235, 128, 128) : RGB(232, 182, 182);
categoryColor = RGB(146, 73, 73);
descColor = RGB(120, 74, 74);
footerColor = RGB(150, 70, 70);
}
else if (isSelected)
{
cardFill = RGB(255, 235, 242);
cardBorder = accentColor;
iconFill = RGB(242, 176, 202);
}
HBRUSH cardBrush = CreateSolidBrush(cardFill);
HPEN cardPen = CreatePen(PS_SOLID, isSelected ? SS(3) : 1, cardBorder);
oldPen = (HPEN)SelectObject(hdc, cardPen); oldPen = (HPEN)SelectObject(hdc, cardPen);
oldBrush = (HBRUSH)SelectObject(hdc, cardBrush); oldBrush = (HBRUSH)SelectObject(hdc, cardBrush);
RoundRect(hdc, cardRect.left, cardRect.top, cardRect.right, cardRect.bottom, SS(24), SS(24)); RoundRect(hdc, cardRect.left, cardRect.top, cardRect.right, cardRect.bottom, SS(24), SS(24));
@@ -1286,7 +1329,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
cardRect.top + SS(84) cardRect.top + SS(84)
}; };
HBRUSH iconBrush = CreateSolidBrush(isSelected ? RGB(242, 176, 202) : RGB(233, 206, 217)); HBRUSH iconBrush = CreateSolidBrush(iconFill);
HPEN iconPen = CreatePen(PS_SOLID, 1, RGB(255, 250, 252)); HPEN iconPen = CreatePen(PS_SOLID, 1, RGB(255, 250, 252));
oldPen = (HPEN)SelectObject(hdc, iconPen); oldPen = (HPEN)SelectObject(hdc, iconPen);
oldBrush = (HBRUSH)SelectObject(hdc, iconBrush); oldBrush = (HBRUSH)SelectObject(hdc, iconBrush);
@@ -1297,7 +1340,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DeleteObject(iconPen); DeleteObject(iconPen);
SelectObject(hdc, smallFont); SelectObject(hdc, smallFont);
SetTextColor(hdc, RGB(122, 95, 110)); SetTextColor(hdc, categoryColor);
RECT categoryRect = RECT categoryRect =
{ {
cardRect.left + SS(20), cardRect.left + SS(20),
@@ -1319,7 +1362,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DrawText(hdc, levelText, -1, &levelRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); DrawText(hdc, levelText, -1, &levelRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
SelectObject(hdc, sectionFont); SelectObject(hdc, sectionFont);
SetTextColor(hdc, isSelected ? titleColor : textColor); SetTextColor(hdc, upgradeUiState.options[i].cursed ? RGB(130, 54, 54) : (isSelected ? titleColor : textColor));
RECT nameRect = RECT nameRect =
{ {
cardRect.left + SS(20), cardRect.left + SS(20),
@@ -1330,7 +1373,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DrawText(hdc, upgradeUiState.options[i].name, -1, &nameRect, DT_LEFT | DT_VCENTER | DT_WORDBREAK); DrawText(hdc, upgradeUiState.options[i].name, -1, &nameRect, DT_LEFT | DT_VCENTER | DT_WORDBREAK);
SelectObject(hdc, bodyFont); SelectObject(hdc, bodyFont);
SetTextColor(hdc, RGB(108, 86, 99)); SetTextColor(hdc, descColor);
RECT descRect = RECT descRect =
{ {
cardRect.left + SS(20), cardRect.left + SS(20),
@@ -1348,8 +1391,13 @@ void TDrawScreen(HDC hdc, HWND hWnd)
cardRect.right - SS(20), cardRect.right - SS(20),
cardRect.bottom - SS(22) cardRect.bottom - SS(22)
}; };
SetTextColor(hdc, RGB(128, 104, 118)); SetTextColor(hdc, footerColor);
DrawText(hdc, _T("\u5360\u4f4d\u56fe\u6807 / \u5360\u4f4d\u7a00\u6709\u5ea6"), -1, &footerRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); DrawText(
hdc,
upgradeUiState.options[i].cursed ? _T("\u547d\u8fd0\u8f6e\u76d8\uff1a\u9644\u5e26\u8bc5\u5492") : _T("\u5360\u4f4d\u56fe\u6807 / \u5360\u4f4d\u7a00\u6709\u5ea6"),
-1,
&footerRect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
} }
SelectObject(hdc, smallFont); SelectObject(hdc, smallFont);