Archived on 2026-10-24. This is a historical implementation note, not current setup instructions or an active task list. Original claims, code examples, file paths, and completion statements have not all been revalidated. Use the current documentation and issue register for maintenance decisions.
Audit correction (2026-10-24): current source still has separate reward/pause gates and SetRewarding does not update time scale. The completion claims below do not establish resolved reward behavior; see GAME-02.
GameState Refactoring Summary¶
Overview¶
This document summarizes the complete refactoring of the GameState system to fix logic issues, remove unused states, and create a unified state management system with proper time-scale control.
Problems Identified¶
1. Redundant/Conflicting Reward States (4 flags)¶
The reward system had 4 separate states managing overlapping logic:
- isDisplayingReward - During reward animation
- isRewardEvent - Reward event is active
- isRerollReward - During reroll operation
- isSelectingReward - Player can select rewards
Issue: These states were not properly coordinated, causing potential conflicts and confusion.
2. Multiple Pause Tracking Systems¶
The game had THREE separate pause tracking mechanisms:
1. GameStateService.isPaused - Used everywhere
2. GameMenuManager.isGamePaused - Private bool for settings
3. GameStateService.isSettings - Never used anywhere
Issue: When rewards were displayed, PauseGame() was called (Time.timeScale = 0), but if player opened settings and closed them, ResumeGame() would be called, resuming time even though we were still in reward display. This caused the game to continue during reward selection.
3. Unused States (6 flags)¶
The following states were defined but never used:
- isGameRunning - Never referenced in codebase
- isBossFight - Never referenced in codebase
- isLevelUp - Never referenced in codebase
- isBonusTime - Never referenced in codebase
- isSettings - Never referenced in codebase
- isRewarding - Defined but never used
4. Missing State Blocking Logic¶
Nothing prevented: - Settings opening during rewards - Pausing during GameOver sequence - GameOver triggering during reward animation - Multiple reward queues processing simultaneously
Solution Implemented¶
Unified State System¶
States Kept (3 active + 1 achievement):¶
ACTIVE STATES:
1. isPaused - Manual pause (settings open)
2. isRewarding - In reward event
3. isGameOver - Game over sequence active
ACHIEVEMENT FLAG:
4. isBossDefeated - Achievement flag (not a state)
States Removed (10 total):¶
❌ isGameRunning - Never used
❌ isBossFight - Never used
❌ isLevelUp - Never used
❌ isBonusTime - Never used
❌ isSettings - Never used in GameState
❌ isRewarding - Was unused, now actively used
❌ isDisplayingReward - Merged into isRewarding
❌ isRewardEvent - Merged into isRewarding
❌ isRerollReward - Merged into isRewarding
❌ isSelectingReward - Merged into isRewarding
Reward Phase System¶
Instead of 4 separate flags, we now use a single isRewarding state with internal phases:
public enum RewardPhase
{
None, // No reward active
Rolling, // During roll/reroll animation
Displaying, // Cards showing but not yet selectable
Selecting // Player can select cards
}
This is tracked internally in RewardRoller.CurrentPhase.
Time Scale Management¶
Centralized Time Control¶
public bool ShouldTimeBePaused => isPaused || isRewarding || isGameOver;
public void UpdateTimeScale()
{
Time.timeScale = ShouldTimeBePaused ? 0f : 1f;
}
Fixed Pause/Resume Logic¶
- When
isPausedis set,UpdateTimeScale()is automatically called - When settings close, we set
isPaused = false(NOT call ResumeGame) UpdateTimeScale()checks ALL states to determine if time should stay paused
This fixes the bug where closing settings during rewards would resume time incorrectly.
Blocking Logic Properties¶
public bool CanPause => !isRewarding && !isGameOver;
public bool CanOpenSettings => !isRewarding && !isGameOver;
These properties prevent invalid state transitions.
Files Modified¶
1. GameStateService.cs¶
Changes:
- Removed 10 unused state properties and methods
- Added RewardPhase enum for internal tracking
- Added ShouldTimeBePaused property
- Added CanPause and CanOpenSettings blocking properties
- Added UpdateTimeScale() method
- Reduced from 13 states to 3 active states
2. GameManager.cs¶
Changes:
- Removed direct Time.timeScale manipulation (now handled by GameStateService)
- Modified isPaused setter to call UpdateTimeScale()
- Made reward properties Obsolete and mapped to RewardRoller.CurrentPhase
- Simplified PauseGame() and ResumeGame() methods
3. RewardRoller.cs¶
Changes:
- Added CurrentPhase property for phase tracking
- Set isRewarding = true when reward starts
- Set CurrentPhase through reward lifecycle
- Added CompleteReward() method to reset reward state
- Updated checks to use CurrentPhase instead of separate flags
- Integrated with GameStateService for state management
4. GameMenuManager.cs¶
Changes:
- Added check for CanPause before opening settings
- Modified settings close to set isPaused = false instead of calling ResumeGame
- This allows UpdateTimeScale() to check if rewards are still active
5. UpgradeSelection.cs¶
Changes:
- Replaced checks for isSelectingReward with RewardPhase.Selecting
- Removed check for menuManager.isSetting (now handled by GameState)
- Updated to call RewardRoller.CompleteReward() instead of setting individual flags
6. StatusPanel.cs¶
Changes:
- Replaced check for menuManager.isSetting with GameManager.isPaused
- Simplified pause detection logic
How It Works¶
Reward Flow¶
- Reward Enqueued →
ProcessRewardQueue()checks if we can start - Roll Starts →
isRewarding = true,CurrentPhase = Rolling - Animation Plays → Time is paused automatically
- Cards Display →
CurrentPhase = Displaying - Selection Ready →
CurrentPhase = Selecting, player can navigate/select - Reward Complete →
CompleteReward()called,isRewarding = false, time resumes
Settings During Rewards¶
- Player tries to open settings
CanPausereturnsfalse(becauseisRewarding = true)- Settings cannot open, warning logged
- Time remains paused (correct behavior)
Settings After Rewards Complete¶
- Player opens settings →
isPaused = true,UpdateTimeScale()sets Time.timeScale = 0 - Player closes settings →
isPaused = false UpdateTimeScale()checks:isRewarding = false,isGameOver = false→ Time.timeScale = 1- Game resumes (correct behavior)
Benefits¶
1. Fixed Bugs¶
- ✅ Settings no longer resume time during rewards
- ✅ Impossible to open settings during rewards
- ✅ Time scale automatically managed
- ✅ No more conflicting state flags
2. Cleaner Code¶
- ✅ Removed 10 unused states
- ✅ 4 reward flags → 1 state + phases
- ✅ Centralized time management
- ✅ Clear blocking logic
3. Better Maintainability¶
- ✅ Single source of truth for game states
- ✅ Easier to add new blocking logic
- ✅ Clear state transitions
- ✅ Reduced complexity from 13 to 3 active states
4. Backward Compatibility¶
- ✅ Legacy properties still work (marked Obsolete)
- ✅ Existing code using old properties will still compile
- ✅ Gradual migration possible
Migration Guide¶
For New Code¶
// OLD (deprecated):
if (GameManager.instance.isSelectingReward)
if (GameManager.instance.isRewardEvent)
if (GameManager.instance.isDisplayingReward)
// NEW (use phases):
if (GameManager.instance.RewardRoller.CurrentPhase == RewardPhase.Selecting)
if (GameManager.instance.RewardRoller.CurrentPhase != RewardPhase.None)
if (GameManager.instance.RewardRoller.CurrentPhase == RewardPhase.Rolling ||
GameManager.instance.RewardRoller.CurrentPhase == RewardPhase.Displaying)
For Checking Pause State¶
// Check if paused:
if (GameManager.instance.isPaused)
// Check if can pause:
if (GameManager.instance.GameState.CanPause)
// Manual pause:
GameManager.instance.isPaused = true; // Automatically calls UpdateTimeScale()
// Manual resume:
GameManager.instance.isPaused = false; // Automatically calls UpdateTimeScale()
For Time Scale¶
// Don't manipulate Time.timeScale directly!
// Instead, change state:
// To pause:
GameManager.instance.isPaused = true;
// To resume:
GameManager.instance.isPaused = false;
// The system will automatically manage Time.timeScale based on:
// - isPaused (manual pause)
// - isRewarding (reward display)
// - isGameOver (game over)
Testing Checklist¶
- [ ] Can pause during normal gameplay
- [ ] Cannot pause during rewards
- [ ] Cannot pause during game over
- [ ] Settings cannot open during rewards
- [ ] Settings cannot open during game over
- [ ] Settings close correctly (time resumes if appropriate)
- [ ] Rewards work end-to-end (roll → display → select → complete)
- [ ] Reroll works during selection phase
- [ ] Reroll cannot happen during animation
- [ ] Time pauses correctly during rewards
- [ ] Time resumes correctly after rewards complete
- [ ] Time stays paused if settings closed during rewards
- [ ] GameOver blocks all actions correctly
- [ ] Legacy properties still work (backward compatibility)
Future Improvements¶
- Add More Blocking Logic
- Can the player dash during rewards?
- Can the player attack during rewards?
-
Add
IsPlayerInputEnabledproperty -
Add State Transition Events
OnRewardStartedOnRewardCompleted-
OnStateChanged -
Separate Achievement System
- Move
isBossDefeatedto AchievementManager -
Create dedicated achievement tracking system
-
Add State Validation
- Validate state transitions
- Log warnings for invalid transitions
- Add debug mode for state visualization