Files
Tereis/src/source/app/TetrisTimers.cpp
T
2026-04-28 23:18:51 +08:00

325 lines
7.7 KiB
C++

#include "stdafx.h"
/**
* @file TetrisTimers.cpp
* @brief 实现游戏下落、视觉特效、致谢动画和 Rogue 限时状态的定时推进。
*/
#include "TetrisAppInternal.h"
static MMRESULT creditTimerHandle = 0;
/**
* @brief 多媒体定时器回调,用于高频率请求致谢页动画刷新。
* @param userData 创建定时器时传入的窗口句柄。
*/
static void CALLBACK CreditTimerCallback(UINT, UINT, DWORD_PTR userData, DWORD_PTR, DWORD_PTR)
{
HWND hWnd = reinterpret_cast<HWND>(userData);
if (hWnd != nullptr)
{
PostMessage(hWnd, WM_CREDIT_TICK, 0, 0);
}
}
/**
* @brief 重置主下落定时器。
* @param hWnd 当前窗口句柄。
*/
void ResetGameTimer(HWND hWnd)
{
KillTimer(hWnd, GAME_TIMER_ID);
SetTimer(hWnd, GAME_TIMER_ID, currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL, nullptr);
}
/**
* @brief 启动游戏、特效和致谢页动画定时器。
* @param hWnd 当前窗口句柄。
*/
void StartAppTimers(HWND hWnd)
{
ResetGameTimer(hWnd);
SetTimer(hWnd, EFFECT_TIMER_ID, EFFECT_TIMER_INTERVAL, nullptr);
creditTimerHandle = timeSetEvent(
CREDIT_TIMER_INTERVAL,
1,
CreditTimerCallback,
reinterpret_cast<DWORD_PTR>(hWnd),
TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
if (creditTimerHandle == 0)
{
// 多媒体定时器不可用时退回普通窗口定时器,保证致谢页仍可动画。
SetTimer(hWnd, CREDIT_TIMER_ID, CREDIT_TIMER_INTERVAL, nullptr);
}
}
/**
* @brief 停止游戏、特效和致谢页动画定时器。
* @param hWnd 当前窗口句柄。
*/
void StopAppTimers(HWND hWnd)
{
KillTimer(hWnd, GAME_TIMER_ID);
KillTimer(hWnd, EFFECT_TIMER_ID);
if (creditTimerHandle != 0)
{
timeKillEvent(creditTimerHandle);
creditTimerHandle = 0;
}
else
{
KillTimer(hWnd, CREDIT_TIMER_ID);
}
}
/**
* @brief 处理致谢页高频动画刷新消息。
* @param hWnd 当前窗口句柄。
*/
void HandleCreditTick(HWND hWnd)
{
if (currentScreen == SCREEN_RULES && helpState.currentPage == 4 && TickCreditAnimation())
{
InvalidateRect(hWnd, nullptr, FALSE);
}
}
/**
* @brief 推进 Rogue 限时状态并按需要重置下落定时器。
* @param hWnd 当前窗口句柄。
* @return 任意状态变化需要刷新界面时返回 true。
*/
static bool TickRogueTimedStates(HWND hWnd)
{
bool shouldRefresh = false;
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.feverTicks > 0)
{
rogueStats.feverTicks--;
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
shouldRefresh = true;
}
if (currentMode == MODE_ROGUE &&
!IsRogueSkillDemoMode() &&
rogueStats.timeDilationTicks > 0 &&
currentScreen == SCREEN_PLAYING &&
!suspendFlag &&
!gameOverFlag)
{
rogueStats.timeDilationTicks--;
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
shouldRefresh = true;
}
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.extremeSlowTicks > 0)
{
rogueStats.extremeSlowTicks--;
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
shouldRefresh = true;
}
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode() && rogueStats.holdSlowTicks > 0)
{
rogueStats.holdSlowTicks--;
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
shouldRefresh = true;
}
return shouldRefresh;
}
/**
* @brief 检查极限玩家的危险等级计时。
* @param hWnd 当前窗口句柄。
* @return 危险等级变化时返回 true。
*/
static bool TickExtremeDanger(HWND hWnd)
{
if (currentMode != MODE_ROGUE ||
IsRogueSkillDemoMode() ||
rogueStats.extremePlayerLevel <= 0 ||
currentScreen != SCREEN_PLAYING ||
suspendFlag ||
gameOverFlag)
{
return false;
}
if (rogueStats.extremeDangerTicks > 0)
{
rogueStats.extremeDangerTicks--;
return false;
}
rogueStats.extremeDangerTicks = 30;
if (rogueStats.extremeDangerLevel < 5)
{
rogueStats.extremeDangerLevel++;
}
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
SetFeedbackMessage(
_T("极限压力升高"),
_T("30 秒内没有完成四消,危险等级提升,下落速度进一步加快。"),
10);
return true;
}
/**
* @brief 检查高堆叠触发的时间缓流。
* @param hWnd 当前窗口句柄。
* @return 成功触发时间缓流时返回 true。
*/
static bool TryStartTimeDilation(HWND hWnd)
{
if (currentMode != MODE_ROGUE ||
IsRogueSkillDemoMode() ||
rogueStats.timeDilationLevel <= 0 ||
rogueStats.timeDilationTicks > 0)
{
return false;
}
int occupiedHeight = 0;
int playableHeight = GetRoguePlayableHeight();
for (int y = 0; y < playableHeight; y++)
{
bool hasCell = false;
for (int x = 0; x < nGameWidth; x++)
{
if (workRegion[y][x] != 0)
{
hasCell = true;
break;
}
}
if (hasCell)
{
occupiedHeight = playableHeight - y;
break;
}
}
if (occupiedHeight <= 15)
{
return false;
}
rogueStats.timeDilationTicks = 8;
currentFallInterval = GetRogueFallInterval();
ResetGameTimer(hWnd);
SetFeedbackMessage(
_T("时间缓流"),
_T("堆叠高度超过 15 行,接下来 8 秒下落速度降低 30%。"),
10);
return true;
}
/**
* @brief 推进一次自动下落逻辑。
* @param hWnd 当前窗口句柄。
* @return 游戏状态推进后需要刷新界面返回 true。
*/
static bool TickGameFall(HWND hWnd)
{
if (currentScreen != SCREEN_PLAYING || suspendFlag || gameOverFlag)
{
return false;
}
if (currentMode == MODE_ROGUE && !IsRogueSkillDemoMode())
{
int previousFallInterval = currentFallInterval;
AdvanceRogueDifficulty(currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL);
if (currentFallInterval != previousFallInterval)
{
ResetGameTimer(hWnd);
}
}
TryStartTimeDilation(hWnd);
if (CanMoveDown())
{
MoveDown();
}
else
{
Fixing();
if (!gameOverFlag)
{
DeleteLines();
CheckRogueLevelProgress();
}
}
if (!gameOverFlag)
{
ComputeTarget();
}
return true;
}
/**
* @brief 处理窗口定时器消息。
* @param hWnd 当前窗口句柄。
* @param timerId 触发的定时器编号。
*/
void HandleTimerMessage(HWND hWnd, WPARAM timerId)
{
if (timerId == EFFECT_TIMER_ID)
{
if (TickVisualEffects())
{
InvalidateRect(hWnd, nullptr, FALSE);
}
return;
}
if (timerId == CREDIT_TIMER_ID && creditTimerHandle == 0)
{
HandleCreditTick(hWnd);
return;
}
if (timerId != GAME_TIMER_ID)
{
return;
}
bool shouldRefresh = false;
if (feedbackState.visibleTicks > 0)
{
feedbackState.visibleTicks--;
shouldRefresh = true;
}
if (IsRogueSkillDemoMode() && TickRogueSkillDemo())
{
shouldRefresh = true;
}
if (TickRogueTimedStates(hWnd))
{
shouldRefresh = true;
}
if (TickExtremeDanger(hWnd))
{
shouldRefresh = true;
}
if (TickGameFall(hWnd))
{
shouldRefresh = true;
}
if (shouldRefresh)
{
InvalidateRect(hWnd, nullptr, FALSE);
}
}