using System; using UnityEngine; using VContainer; using YachtDice.Categories; using YachtDice.Run; using YachtDice.Scoring; namespace YachtDice.Game { public class GameLoopController : MonoBehaviour { private DiceManager _diceManager; private RunLoopService _runLoopService; private ScoringSystem _scoringSystem; public int CurrentRoll => _runLoopService != null ? _runLoopService.State.CurrentRoll : 0; public int CurrentTurn => _runLoopService != null ? _runLoopService.State.StageNumber : 0; public int CurrentBet => _runLoopService != null ? _runLoopService.State.BetIndex : 0; public int CurrentStage => _runLoopService != null ? _runLoopService.State.StageNumber : 0; public int CurrentStageTarget => _runLoopService != null ? _runLoopService.State.CurrentStageTarget : 0; public int CurrentBaseQuota => _runLoopService != null ? _runLoopService.State.BaseQuota : 0; public int StoredRolls => _runLoopService != null ? _runLoopService.State.StoredRolls : 0; public int MaxRollsPerTurn => _runLoopService != null ? _runLoopService.State.CurrentStageRollBudget : 0; public RunPhase CurrentPhase => _runLoopService != null ? _runLoopService.State.Phase : RunPhase.None; public bool CanRoll => _runLoopService != null && _runLoopService.CanRoll() && !_diceManager.IsAnyRolling; public bool CanScore => _runLoopService != null && CurrentPhase == RunPhase.CategorySelection && !_diceManager.IsAnyRolling; public bool IsGameOver => _runLoopService != null && _runLoopService.State.IsFailed; public bool IsShopOpen => CurrentPhase == RunPhase.Shop; public event Action OnTurnStarted; public event Action OnRollComplete; public event Action OnScored; public event Action OnGameOver; public event Action OnBetStarted; public event Action OnShopOpened; public event Action OnShopClosed; public event Action OnStoredRollsChanged; public event Action OnCurrencyChanged; public event Action OnQuotaChanged; public event Action OnCycleCompleted; public event Action OnPhaseChanged; [Inject] public void Construct(DiceManager diceManager, RunLoopService runLoopService, ScoringSystem scoringSystem) { _diceManager = diceManager; _runLoopService = runLoopService; _scoringSystem = scoringSystem; _runLoopService.OnStageStarted += HandleStageStarted; _runLoopService.OnStageCleared += HandleStageCleared; _runLoopService.OnRunFailed += HandleRunFailed; _runLoopService.OnBetStarted += HandleBetStarted; _runLoopService.OnShopOpened += HandleShopOpened; _runLoopService.OnStoredRollsChanged += HandleStoredRollsChanged; _runLoopService.OnCurrencyChanged += HandleCurrencyChanged; _runLoopService.OnQuotaChanged += HandleQuotaChanged; _runLoopService.OnCycleCompleted += HandleCycleCompleted; _runLoopService.OnPhaseChanged += HandlePhaseChanged; } private void OnDestroy() { if (_runLoopService == null) return; _runLoopService.OnStageStarted -= HandleStageStarted; _runLoopService.OnStageCleared -= HandleStageCleared; _runLoopService.OnRunFailed -= HandleRunFailed; _runLoopService.OnBetStarted -= HandleBetStarted; _runLoopService.OnShopOpened -= HandleShopOpened; _runLoopService.OnStoredRollsChanged -= HandleStoredRollsChanged; _runLoopService.OnCurrencyChanged -= HandleCurrencyChanged; _runLoopService.OnQuotaChanged -= HandleQuotaChanged; _runLoopService.OnCycleCompleted -= HandleCycleCompleted; _runLoopService.OnPhaseChanged -= HandlePhaseChanged; } public void StartNewGame() { _diceManager.UnlockAll(); _runLoopService.StartNewRun(); } public void CompleteShop() { if (!IsShopOpen) return; _runLoopService.CompleteShop(); OnShopClosed?.Invoke(); } public void Roll() { if (!CanRoll) return; if (!_runLoopService.TryBeginRoll()) return; _diceManager.OnAllDiceSettled += HandleAllDiceSettled; _diceManager.RollUnlocked(); } private void HandleAllDiceSettled() { _diceManager.OnAllDiceSettled -= HandleAllDiceSettled; _runLoopService.NotifyRollResolved(_diceManager.GetDice()); OnRollComplete?.Invoke(CurrentRoll); } public void ToggleDiceLock(int index) { if (_diceManager.IsAnyRolling) return; if (CurrentRoll == 0) return; _diceManager.ToggleLock(index); } public bool CanScoreCategory(CategoryDefinition category) { return _runLoopService != null && _runLoopService.CanScoreCategory(_diceManager.GetDice(), category); } public ScoreResult PreviewCategory(CategoryDefinition category) { return _runLoopService.PreviewScore(_diceManager.GetDice(), category); } public async void ScoreInCategory(CategoryDefinition category) { if (!CanScore) return; await _runLoopService.TryScoreCategoryAsync(_diceManager.GetDice(), category); } public bool CanOpenShopManually() { return IsShopOpen; } private void HandleStageStarted(RunStageState stage) { _diceManager.UnlockAll(); OnTurnStarted?.Invoke(stage.Index + 1); } private void HandleStageCleared(RunStageState stage, CategoryDefinition category, ScoreResult result) { _diceManager.UnlockAll(); OnScored?.Invoke(category, result.FinalScore); } private void HandleRunFailed(RunState state) { OnGameOver?.Invoke(_scoringSystem != null ? _scoringSystem.TotalScore : 0); } private void HandleBetStarted(RunState state) { OnBetStarted?.Invoke(state.BetIndex); } private void HandleShopOpened(RunState state) { OnShopOpened?.Invoke(); } private void HandleStoredRollsChanged(int value) { OnStoredRollsChanged?.Invoke(value); } private void HandleCurrencyChanged(int value) { OnCurrencyChanged?.Invoke(value); } private void HandleQuotaChanged(int value) { OnQuotaChanged?.Invoke(value); } private void HandleCycleCompleted(int bonus, int storedRolls) { OnCycleCompleted?.Invoke(bonus, storedRolls); } private void HandlePhaseChanged(RunPhase phase) { OnPhaseChanged?.Invoke(phase); } } }