diff --git a/src/include/Tetris.h b/src/include/Tetris.h index 28c97d3..2df1cf2 100644 --- a/src/include/Tetris.h +++ b/src/include/Tetris.h @@ -74,10 +74,13 @@ struct PlayerStats int destinyWheelLevel; int perfectRotateLevel; int timeDilationLevel; + int timeDilationTicks; int highPressureLevel; int tetrisGambleLevel; int extremePlayerLevel; int extremeSlowTicks; + int extremeDangerTicks; + int extremeDangerLevel; int upgradeShockwaveLevel; int evolutionImpactLevel; int controlMasterLevel; diff --git a/src/source/Tetris.cpp b/src/source/Tetris.cpp index 8bcd68d..aa602ab 100644 --- a/src/source/Tetris.cpp +++ b/src/source/Tetris.cpp @@ -158,11 +158,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (currentMode == MODE_ROGUE && rogueStats.feverTicks > 0) { rogueStats.feverTicks--; - currentFallInterval = 500 + rogueStats.slowFallStacks * 80; - if (rogueStats.feverTicks > 0) - { - currentFallInterval += 120; - } + currentFallInterval = GetRogueFallInterval(); + ResetGameTimer(hWnd); + shouldRefresh = true; + } + + if (currentMode == MODE_ROGUE && + rogueStats.timeDilationTicks > 0 && + currentScreen == SCREEN_PLAYING && + !suspendFlag && + !gameOverFlag) + { + rogueStats.timeDilationTicks--; + currentFallInterval = GetRogueFallInterval(); ResetGameTimer(hWnd); shouldRefresh = true; } @@ -175,6 +183,32 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) shouldRefresh = true; } + if (currentMode == MODE_ROGUE && + rogueStats.extremePlayerLevel > 0 && + currentScreen == SCREEN_PLAYING && + !suspendFlag && + !gameOverFlag) + { + if (rogueStats.extremeDangerTicks > 0) + { + rogueStats.extremeDangerTicks--; + } + else + { + rogueStats.extremeDangerTicks = 30; + if (rogueStats.extremeDangerLevel < 5) + { + rogueStats.extremeDangerLevel++; + } + currentFallInterval = GetRogueFallInterval(); + ResetGameTimer(hWnd); + feedbackState.visibleTicks = 10; + lstrcpyn(feedbackState.title, _T("\u6781\u9650\u5371\u9669\u5347\u7ea7"), sizeof(feedbackState.title) / sizeof(TCHAR)); + lstrcpyn(feedbackState.detail, _T("30 \u79d2\u5185\u672a\u5b8c\u6210\u56db\u6d88\uff0c\u5371\u9669\u7b49\u7ea7\u63d0\u5347\uff0c\u4e0b\u843d\u901f\u5ea6\u8fdb\u4e00\u6b65\u52a0\u5feb\u3002"), sizeof(feedbackState.detail) / sizeof(TCHAR)); + shouldRefresh = true; + } + } + if (currentMode == MODE_ROGUE && rogueStats.holdSlowTicks > 0) { rogueStats.holdSlowTicks--; @@ -187,6 +221,39 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) !suspendFlag && !gameOverFlag) { + if (currentMode == MODE_ROGUE && rogueStats.timeDilationLevel > 0 && rogueStats.timeDilationTicks <= 0) + { + int occupiedHeight = 0; + for (int y = 0; y < nGameHeight; y++) + { + bool hasCell = false; + for (int x = 0; x < nGameWidth; x++) + { + if (workRegion[y][x] != 0) + { + hasCell = true; + break; + } + } + if (hasCell) + { + occupiedHeight = nGameHeight - y; + break; + } + } + + if (occupiedHeight > 15) + { + rogueStats.timeDilationTicks = 8; + currentFallInterval = GetRogueFallInterval(); + ResetGameTimer(hWnd); + feedbackState.visibleTicks = 10; + lstrcpyn(feedbackState.title, _T("\u65f6\u95f4\u7f13\u6d41"), sizeof(feedbackState.title) / sizeof(TCHAR)); + lstrcpyn(feedbackState.detail, _T("\u68cb\u76d8\u9ad8\u5ea6\u8d85\u8fc7 15 \u884c\uff0c\u63a5\u4e0b\u6765 8 \u79d2\u4e0b\u843d\u51cf\u901f 30%\u3002"), sizeof(feedbackState.detail) / sizeof(TCHAR)); + shouldRefresh = true; + } + } + if (CanMoveDown()) { MoveDown(); diff --git a/src/source/TetrisLogic.cpp b/src/source/TetrisLogic.cpp index 8903a4c..1c340e9 100644 --- a/src/source/TetrisLogic.cpp +++ b/src/source/TetrisLogic.cpp @@ -290,10 +290,13 @@ static void ResetPlayerStats(PlayerStats& stats, bool useRogueRules) stats.destinyWheelLevel = 0; stats.perfectRotateLevel = 0; stats.timeDilationLevel = 0; + stats.timeDilationTicks = 0; stats.highPressureLevel = 0; stats.tetrisGambleLevel = 0; stats.extremePlayerLevel = 0; stats.extremeSlowTicks = 0; + stats.extremeDangerTicks = 30; + stats.extremeDangerLevel = 0; stats.upgradeShockwaveLevel = 0; stats.evolutionImpactLevel = 0; stats.controlMasterLevel = 0; @@ -879,6 +882,15 @@ static bool RollLaserPiece() chancePercent = 35; } + if (rogueStats.feverTicks > 0) + { + chancePercent += 10; + if (chancePercent > 50) + { + chancePercent = 50; + } + } + return (rand() % 100) < chancePercent; } @@ -895,6 +907,15 @@ static bool RollCrossPiece() chancePercent = 28; } + if (rogueStats.feverTicks > 0) + { + chancePercent += 10; + if (chancePercent > 40) + { + chancePercent = 40; + } + } + return (rand() % 100) < chancePercent; } @@ -906,6 +927,10 @@ static bool RollRainbowPiece() } int chancePercent = 12; + if (rogueStats.feverTicks > 0) + { + chancePercent += 10; + } return (rand() % 100) < chancePercent; } @@ -1478,13 +1503,9 @@ int GetRogueFallInterval() baseInterval = baseInterval * 90 / 100; } - if (rogueStats.timeDilationLevel > 0) + if (rogueStats.extremeDangerLevel > 0) { - int topOccupiedRow = GetTopOccupiedRow(); - if (topOccupiedRow >= 0 && topOccupiedRow <= 5) - { - baseInterval += 180; - } + baseInterval = baseInterval * (100 - rogueStats.extremeDangerLevel * 8) / 100; } if (currentMode == MODE_ROGUE && rogueStats.feverTicks > 0) @@ -1492,6 +1513,11 @@ int GetRogueFallInterval() baseInterval += 120; } + if (rogueStats.timeDilationTicks > 0) + { + baseInterval = baseInterval * 130 / 100; + } + if (rogueStats.extremeSlowTicks > 0) { baseInterval += 180; @@ -1629,6 +1655,8 @@ static void ApplyUpgradeById(int upgradeId, int targetPieceType, int applyCount) break; case UPGRADE_EXTREME_PLAYER: rogueStats.extremePlayerLevel = 1; + rogueStats.extremeDangerTicks = 30; + rogueStats.extremeDangerLevel = 0; currentFallInterval = GetRogueFallInterval(); break; case UPGRADE_UPGRADE_SHOCKWAVE: @@ -1721,12 +1749,10 @@ static void ApplyLineClearResult(int linesCleared) if (linesCleared == 4) { scoreGain *= 4; - expGain *= 3; } else { - scoreGain = scoreGain * 60 / 100; - expGain = expGain * 75 / 100; + scoreGain = scoreGain * 50 / 100; } } @@ -1785,7 +1811,7 @@ static void ApplyLineClearResult(int linesCleared) rogueStats.feverLineCharge -= 20; rogueStats.feverTicks = 10; currentFallInterval = GetRogueFallInterval(); - SetFeedbackMessage(_T("\u8fdb\u5165\u72c2\u70ed\u6a21\u5f0f"), _T("\u672a\u6765 10 \u79d2\u5f97\u5206 / EXP x2\uff0c\u4e0b\u843d\u66f4\u6162\u3002"), 12); + SetFeedbackMessage(_T("\u8fdb\u5165\u72c2\u70ed\u6a21\u5f0f"), _T("\u672a\u6765 10 \u79d2\u5f97\u5206 / EXP x2\uff0c\u4e0b\u843d\u66f4\u6162\uff0c\u7279\u6b8a\u65b9\u5757\u66f4\u6613\u51fa\u73b0\u3002"), 12); } } @@ -1806,6 +1832,7 @@ static void ApplyLineClearResult(int linesCleared) if (rogueStats.extremePlayerLevel > 0 && linesCleared == 4) { rogueStats.extremeSlowTicks = 5; + rogueStats.extremeDangerTicks = 30; currentFallInterval = GetRogueFallInterval(); SetFeedbackMessage(_T("\u6781\u9650\u73a9\u5bb6\u89e6\u53d1"), _T("\u56db\u6d88\u6210\u529f\uff0c\u63a5\u4e0b\u6765 5 \u79d2\u77ed\u6682\u7f13\u901f\u8865\u4f4d\u3002"), 12); } diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 0bb86bc..ab63031 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -767,8 +767,8 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (rogueStats.feverLevel > 0) { - TCHAR feverText[96]; - _stprintf_s(feverText, _T("\u72c2\u70ed\u5145\u80fd %d / 20 \u5269\u4f59 %d \u79d2"), rogueStats.feverLineCharge, rogueStats.feverTicks); + TCHAR feverText[128]; + _stprintf_s(feverText, _T("\u72c2\u70ed\u5145\u80fd %d / 20 \u5269\u4f59 %d \u79d2 \u7279\u5757\u51fa\u73b0\u7387\u63d0\u9ad8"), rogueStats.feverLineCharge, rogueStats.feverTicks); TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(434), feverText, lstrlen(feverText)); } @@ -824,7 +824,9 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (rogueStats.timeDilationLevel > 0) { - TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(626), _T("\u65f6\u95f4\u7f13\u6d41 \u76d8\u9762\u8fc7\u9ad8\u65f6\u81ea\u52a8\u51cf\u901f"), lstrlen(_T("\u65f6\u95f4\u7f13\u6d41 \u76d8\u9762\u8fc7\u9ad8\u65f6\u81ea\u52a8\u51cf\u901f"))); + TCHAR dilationText[128]; + _stprintf_s(dilationText, _T("\u65f6\u95f4\u7f13\u6d41 \u5269\u4f59 %d \u79d2 \u9ad8\u5ea6>15\u65f6\u89e6\u53d1 8 \u79d2 30%%\u51cf\u901f"), rogueStats.timeDilationTicks); + TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(626), dilationText, lstrlen(dilationText)); } if (rogueStats.highPressureLevel > 0) @@ -834,13 +836,13 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (rogueStats.tetrisGambleLevel > 0) { - TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(690), _T("\u8d4c\u547d\u56db\u6d88 \u975e\u56db\u6d88\u964d\u76ca\uff0c\u56db\u6d88\u66b4\u589e"), lstrlen(_T("\u8d4c\u547d\u56db\u6d88 \u975e\u56db\u6d88\u964d\u76ca\uff0c\u56db\u6d88\u66b4\u589e"))); + TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(690), _T("\u8d4c\u547d\u56db\u6d88 1~3\u6d88\u5f97\u5206 x0.5 4\u6d88\u5f97\u5206 x4"), lstrlen(_T("\u8d4c\u547d\u56db\u6d88 1~3\u6d88\u5f97\u5206 x0.5 4\u6d88\u5f97\u5206 x4"))); } if (rogueStats.extremePlayerLevel > 0) { - TCHAR extremeText[96]; - _stprintf_s(extremeText, _T("\u6781\u9650\u73a9\u5bb6 \u7f13\u901f\u5269\u4f59 %d"), rogueStats.extremeSlowTicks); + TCHAR extremeText[128]; + _stprintf_s(extremeText, _T("\u6781\u9650\u73a9\u5bb6 \u7f13\u901f %d \u5371\u9669 %d \u8ddd\u4e0b\u6b21\u589e\u538b %d \u79d2"), rogueStats.extremeSlowTicks, rogueStats.extremeDangerLevel, rogueStats.extremeDangerTicks); TextOut(hdc, combatRect.left + SS(18), combatRect.top + SS(722), extremeText, lstrlen(extremeText)); } diff --git a/强化TODO.md b/强化TODO.md index 0ba26d3..69d4249 100644 --- a/强化TODO.md +++ b/强化TODO.md @@ -11,8 +11,8 @@ | 状态 | 数量 | |---|---:| -| 已完成 | 31 | -| 部分完成 | 4 | +| 已完成 | 35 | +| 部分完成 | 0 | | 未完成 | 0 | ## 已完成 @@ -50,15 +50,15 @@ | 操控大师 | 进化 | Hold 后短时间减速、旋转失败自动修正、增加一个预览 | 完美旋转 + 暂存槽 | | 命运轮盘 | 进化 | 升级出现 5 个选项,可选 2 个,其中 1 个附带诅咒 | 赌徒 + 双重选择 | | 虚空核心 | 进化 | 黑洞后额外生成一个彩虹方块;彩虹方块参与消行时触发一次小型黑洞 | 黑洞 + 彩虹方块 | +| 狂热模式 | 爽感 | 每累计消除 20 行进入 10 秒狂热;期间得分/EXP x2、下落减慢,特殊方块出现率提高 | 基础出现 | +| 时间缓流 | 操作/生存 | 当棋盘高度超过 15 行时,自动触发 8 秒 30% 下落减速 | 基础出现 | +| 赌命四消 | 风险 | 普通 1~3 消得分降低,四消得分提高 300% | 基础出现 | +| 极限玩家 | 进化 | 进一步提速,四消得分更高、四消后缓速 5 秒,30 秒未四消会提高危险等级 | 高压奖励 + 赌命四消 | ## 部分完成 | 强化 | 分类 | 当前状态 | 升级路径 | |---|---|---|---| -| 狂热模式 | 爽感 | 已实现累计 20 行进入 10 秒狂热、得分/EXP x2、下落变慢;文档里的“特殊方块出现率提高”还没接入 | 基础出现 | -| 时间缓流 | 操作/生存 | 已实现盘面过高时自动减速;文档要求是“高度超过 15 行时减速 30%,持续 8 秒”,当前是危险高度下的持续性减速逻辑 | 基础出现 | -| 赌命四消 | 风险 | 已实现 1~3 消降益、4 消暴增;数值实现与文档“普通消行降低、四消奖励提高 300%”不完全一致 | 基础出现 | -| 极限玩家 | 进化 | 已实现“进一步提速”和“四消后缓速 5 秒”;文档里的“30 秒内没有四消则增加危险等级”还没做 | 高压奖励 + 赌命四消 | ## 未完成 @@ -75,7 +75,5 @@ ## 推荐下一批实现顺序 -1. `狂热模式` 补上“特殊方块出现率提高” -2. `极限玩家` 补上“30 秒未四消增加危险等级” -3. `时间缓流` 的触发条件、减速比例和持续时间继续向文档收敛 -4. `赌命四消` 的普通消行 / 四消收益数值继续向文档收敛 +1. 强化系统文档与 UI 文案细节继续统一 +2. 继续做更强的视觉反馈和特效表现