[Add] GameLoop base
This commit is contained in:
@@ -11,6 +11,7 @@ using YachtDice.Modifiers.Definition;
|
||||
using YachtDice.Modifiers.Pipeline;
|
||||
using YachtDice.Modifiers.Runtime;
|
||||
using YachtDice.Player;
|
||||
using YachtDice.Run;
|
||||
using YachtDice.Scoring;
|
||||
using YachtDice.Shop;
|
||||
using YachtDice.UI;
|
||||
@@ -25,6 +26,7 @@ namespace YachtDice.DI
|
||||
[SerializeField] private CategoryCatalog categoryCatalog;
|
||||
[SerializeField] private DiceCatalog diceCatalog;
|
||||
[SerializeField] private ShopCatalog shopCatalog;
|
||||
[SerializeField] private RunBalanceConfigSO runBalanceConfig;
|
||||
|
||||
[Header("Scene References")]
|
||||
[SerializeField] private ScoringSystem scoringSystem;
|
||||
@@ -45,6 +47,7 @@ namespace YachtDice.DI
|
||||
builder.RegisterInstance(categoryCatalog);
|
||||
builder.RegisterInstance(diceCatalog);
|
||||
builder.RegisterInstance(shopCatalog);
|
||||
builder.RegisterInstance(runBalanceConfig != null ? runBalanceConfig : RunBalanceConfigSO.CreateDefault());
|
||||
|
||||
// Core modifier services
|
||||
builder.Register<ModifierRegistry>(Lifetime.Singleton)
|
||||
@@ -62,6 +65,10 @@ namespace YachtDice.DI
|
||||
// Shop
|
||||
builder.Register<ShopModel>(Lifetime.Singleton);
|
||||
|
||||
// Run loop
|
||||
builder.Register<StoredRollBank>(Lifetime.Singleton);
|
||||
builder.Register<RunLoopService>(Lifetime.Singleton);
|
||||
|
||||
// Presentation services
|
||||
builder.Register<IGameSaveService, GameSaveService>(Lifetime.Singleton);
|
||||
builder.Register<IScoreSummaryService, ScoreSummaryService>(Lifetime.Singleton);
|
||||
|
||||
@@ -2,58 +2,105 @@ using System;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
using YachtDice.Categories;
|
||||
using YachtDice.Run;
|
||||
using YachtDice.Scoring;
|
||||
|
||||
namespace YachtDice.Game
|
||||
{
|
||||
public class GameLoopController : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
[SerializeField] private int maxRollsPerTurn = 3;
|
||||
|
||||
private DiceManager _diceManager;
|
||||
private RunLoopService _runLoopService;
|
||||
private ScoringSystem _scoringSystem;
|
||||
|
||||
public int CurrentRoll { get; private set; }
|
||||
public int CurrentTurn { get; private set; }
|
||||
public int MaxRollsPerTurn => maxRollsPerTurn;
|
||||
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 => CurrentRoll < maxRollsPerTurn && !_diceManager.IsAnyRolling;
|
||||
public bool CanScore => CurrentRoll > 0 && !_diceManager.IsAnyRolling;
|
||||
public bool IsGameOver => _scoringSystem.IsComplete;
|
||||
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<int> OnTurnStarted;
|
||||
public event Action<int> OnRollComplete;
|
||||
public event Action<CategoryDefinition, int> OnScored;
|
||||
public event Action<int> OnGameOver;
|
||||
|
||||
public event Action<int> OnBetStarted;
|
||||
public event Action OnShopOpened;
|
||||
public event Action OnShopClosed;
|
||||
public event Action<int> OnStoredRollsChanged;
|
||||
public event Action<int> OnCurrencyChanged;
|
||||
public event Action<int> OnQuotaChanged;
|
||||
public event Action<int, int> OnCycleCompleted;
|
||||
public event Action<RunPhase> OnPhaseChanged;
|
||||
|
||||
[Inject]
|
||||
public void Construct(DiceManager diceManager, ScoringSystem scoringSystem)
|
||||
public void Construct(DiceManager diceManager, RunLoopService runLoopService, ScoringSystem scoringSystem)
|
||||
{
|
||||
this._diceManager = diceManager;
|
||||
this._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()
|
||||
{
|
||||
_scoringSystem.ResetScorecard();
|
||||
CurrentTurn = 0;
|
||||
StartNewTurn();
|
||||
_diceManager.UnlockAll();
|
||||
_runLoopService.StartNewRun();
|
||||
}
|
||||
|
||||
private void StartNewTurn()
|
||||
public void CompleteShop()
|
||||
{
|
||||
CurrentTurn++;
|
||||
CurrentRoll = 0;
|
||||
_diceManager.UnlockAll();
|
||||
OnTurnStarted?.Invoke(CurrentTurn);
|
||||
if (!IsShopOpen)
|
||||
return;
|
||||
|
||||
_runLoopService.CompleteShop();
|
||||
OnShopClosed?.Invoke();
|
||||
}
|
||||
|
||||
public void Roll()
|
||||
{
|
||||
if (!CanRoll) return;
|
||||
if (!CanRoll)
|
||||
return;
|
||||
|
||||
if (!_runLoopService.TryBeginRoll())
|
||||
return;
|
||||
|
||||
CurrentRoll++;
|
||||
_diceManager.OnAllDiceSettled += HandleAllDiceSettled;
|
||||
_diceManager.RollUnlocked();
|
||||
}
|
||||
@@ -61,6 +108,7 @@ namespace YachtDice.Game
|
||||
private void HandleAllDiceSettled()
|
||||
{
|
||||
_diceManager.OnAllDiceSettled -= HandleAllDiceSettled;
|
||||
_runLoopService.NotifyRollResolved(_diceManager.GetDice());
|
||||
OnRollComplete?.Invoke(CurrentRoll);
|
||||
}
|
||||
|
||||
@@ -71,25 +119,79 @@ namespace YachtDice.Game
|
||||
_diceManager.ToggleLock(index);
|
||||
}
|
||||
|
||||
public void ScoreInCategory(CategoryDefinition category)
|
||||
public bool CanScoreCategory(CategoryDefinition category)
|
||||
{
|
||||
if (!CanScore) return;
|
||||
if (_scoringSystem.IsCategoryUsed(category)) return;
|
||||
return _runLoopService != null && _runLoopService.CanScoreCategory(_diceManager.GetDice(), category);
|
||||
}
|
||||
|
||||
var dice = _diceManager.GetDice();
|
||||
var result = _scoringSystem.ScoreCategory(dice, 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);
|
||||
}
|
||||
|
||||
if (_scoringSystem.IsComplete)
|
||||
{
|
||||
var total = _scoringSystem.TotalScore;
|
||||
OnGameOver?.Invoke(total);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartNewTurn();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4fce5c4a7443cb418371ed455b52146
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
[CreateAssetMenu(fileName = "RunBalanceConfig", menuName = "YachtDice/Run/Balance Config")]
|
||||
public class RunBalanceConfigSO : ScriptableObject
|
||||
{
|
||||
[Header("Quota")]
|
||||
[SerializeField] private int startingBaseQuota = 30;
|
||||
[SerializeField] private int quotaGrowthPerCycle = 30;
|
||||
|
||||
[Header("Stage Targets")]
|
||||
[SerializeField] private float[] stageTargetMultipliers = { 1f, 1.5f, 2.5f };
|
||||
|
||||
[Header("Rewards")]
|
||||
[SerializeField] private int stageClearReward = 25;
|
||||
[SerializeField] private int cycleStoredRollBonusMultiplier = 10;
|
||||
|
||||
[Header("Roll Economy")]
|
||||
[SerializeField] private int baseRollsPerStage = 3;
|
||||
|
||||
public int StartingBaseQuota => startingBaseQuota;
|
||||
public int QuotaGrowthPerCycle => quotaGrowthPerCycle;
|
||||
public int StageClearReward => stageClearReward;
|
||||
public int CycleStoredRollBonusMultiplier => cycleStoredRollBonusMultiplier;
|
||||
public int BaseRollsPerStage => baseRollsPerStage;
|
||||
public int StageCount => stageTargetMultipliers != null ? stageTargetMultipliers.Length : 0;
|
||||
|
||||
public int GetStageTarget(int baseQuota, int stageIndex)
|
||||
{
|
||||
if (stageTargetMultipliers == null || stageTargetMultipliers.Length == 0)
|
||||
return baseQuota;
|
||||
|
||||
var clampedIndex = Mathf.Clamp(stageIndex, 0, stageTargetMultipliers.Length - 1);
|
||||
return Mathf.CeilToInt(baseQuota * stageTargetMultipliers[clampedIndex]);
|
||||
}
|
||||
|
||||
public int GetNextQuota(int currentQuota)
|
||||
{
|
||||
return currentQuota + quotaGrowthPerCycle;
|
||||
}
|
||||
|
||||
public static RunBalanceConfigSO CreateDefault()
|
||||
{
|
||||
return CreateInstance<RunBalanceConfigSO>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5917f01e056f9c24988a1e0e726becc0
|
||||
@@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using YachtDice.Categories;
|
||||
using YachtDice.Dice;
|
||||
using YachtDice.Economy;
|
||||
using YachtDice.Scoring;
|
||||
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
public sealed class RunLoopService
|
||||
{
|
||||
private readonly RunBalanceConfigSO _config;
|
||||
private readonly ScoringSystem _scoringSystem;
|
||||
private readonly CurrencyBank _currencyBank;
|
||||
private readonly StoredRollBank _storedRollBank;
|
||||
private readonly RunState _state = new();
|
||||
|
||||
public RunLoopService(
|
||||
RunBalanceConfigSO config,
|
||||
ScoringSystem scoringSystem,
|
||||
CurrencyBank currencyBank,
|
||||
StoredRollBank storedRollBank)
|
||||
{
|
||||
_config = config != null ? config : RunBalanceConfigSO.CreateDefault();
|
||||
_scoringSystem = scoringSystem;
|
||||
_currencyBank = currencyBank;
|
||||
_storedRollBank = storedRollBank;
|
||||
|
||||
if (_storedRollBank != null)
|
||||
_storedRollBank.OnChanged += HandleStoredRollsChanged;
|
||||
|
||||
if (_currencyBank != null)
|
||||
_currencyBank.OnBalanceChanged += HandleCurrencyChanged;
|
||||
}
|
||||
|
||||
public RunState State => _state;
|
||||
public int CurrentCurrency => _currencyBank != null ? _currencyBank.Balance : 0;
|
||||
|
||||
public event Action<RunState> OnRunStarted;
|
||||
public event Action<RunState> OnBetStarted;
|
||||
public event Action<RunState> OnShopOpened;
|
||||
public event Action<RunStageState> OnStageStarted;
|
||||
public event Action<RunStageState, CategoryDefinition, ScoreResult> OnStageCleared;
|
||||
public event Action<RunStageState> OnStageFailed;
|
||||
public event Action<int> OnStoredRollsChanged;
|
||||
public event Action<int> OnCurrencyChanged;
|
||||
public event Action<int, int> OnCycleCompleted;
|
||||
public event Action<int> OnQuotaChanged;
|
||||
public event Action<RunState> OnRunFailed;
|
||||
public event Action<RunPhase> OnPhaseChanged;
|
||||
public event Action OnCategoriesRefreshed;
|
||||
|
||||
public void StartNewRun()
|
||||
{
|
||||
_scoringSystem.ResetScorecard();
|
||||
_storedRollBank.Reset();
|
||||
|
||||
_state.BaseQuota = _config.StartingBaseQuota;
|
||||
_state.BetIndex = 0;
|
||||
_state.StageIndex = 0;
|
||||
_state.CurrentRoll = 0;
|
||||
_state.CurrentStageRollBudget = _config.BaseRollsPerStage;
|
||||
_state.CurrentStageTarget = _config.GetStageTarget(_state.BaseQuota, 0);
|
||||
_state.StoredRolls = _storedRollBank.Value;
|
||||
_state.IsActive = true;
|
||||
_state.IsFailed = false;
|
||||
SetPhase(RunPhase.None);
|
||||
|
||||
OnRunStarted?.Invoke(_state);
|
||||
StartNextBet();
|
||||
}
|
||||
|
||||
public void CompleteShop()
|
||||
{
|
||||
if (_state.Phase != RunPhase.Shop || !_state.IsActive)
|
||||
return;
|
||||
|
||||
StartStage(0);
|
||||
}
|
||||
|
||||
public bool CanRoll()
|
||||
{
|
||||
if (!_state.IsActive || _state.IsFailed)
|
||||
return false;
|
||||
|
||||
return _state.Phase == RunPhase.StageStart
|
||||
|| _state.Phase == RunPhase.CategorySelection
|
||||
|| _state.Phase == RunPhase.Rolling;
|
||||
}
|
||||
|
||||
public bool TryBeginRoll()
|
||||
{
|
||||
if (!CanRoll())
|
||||
return false;
|
||||
|
||||
if (_state.CurrentRoll >= _state.CurrentStageRollBudget)
|
||||
{
|
||||
if (!_storedRollBank.TrySpend(1))
|
||||
return false;
|
||||
|
||||
_state.CurrentStageRollBudget += 1;
|
||||
_state.StoredRolls = _storedRollBank.Value;
|
||||
}
|
||||
|
||||
_state.CurrentRoll += 1;
|
||||
SetPhase(RunPhase.Rolling);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void NotifyRollResolved(IReadOnlyList<IDice> dice)
|
||||
{
|
||||
if (!_state.IsActive || _state.IsFailed || _state.Phase != RunPhase.Rolling)
|
||||
return;
|
||||
|
||||
SetPhase(RunPhase.CategorySelection);
|
||||
|
||||
if (!HasRemainingRollCapacity() && !HasAnyScorableCategory(dice))
|
||||
FailCurrentStage();
|
||||
}
|
||||
|
||||
public bool CanScoreCategory(IReadOnlyList<IDice> dice, CategoryDefinition category)
|
||||
{
|
||||
if (!_state.IsActive || _state.IsFailed || _state.Phase != RunPhase.CategorySelection)
|
||||
return false;
|
||||
|
||||
if (category == null || _scoringSystem.IsCategoryUsed(category))
|
||||
return false;
|
||||
|
||||
if (_state.CurrentRoll <= 0)
|
||||
return false;
|
||||
|
||||
var preview = PreviewScore(dice, category);
|
||||
return preview.FinalScore >= _state.CurrentStageTarget;
|
||||
}
|
||||
|
||||
public ScoreResult PreviewScore(IReadOnlyList<IDice> dice, CategoryDefinition category)
|
||||
{
|
||||
return _scoringSystem.PreviewScore(
|
||||
dice,
|
||||
category,
|
||||
_state.CurrentRoll,
|
||||
GetProgressOrdinal(),
|
||||
CurrentCurrency);
|
||||
}
|
||||
|
||||
public bool HasAnyScorableCategory(IReadOnlyList<IDice> dice)
|
||||
{
|
||||
var catalog = _scoringSystem.Catalog;
|
||||
if (catalog == null)
|
||||
return false;
|
||||
|
||||
var categories = catalog.All;
|
||||
for (var i = 0; i < categories.Count; i++)
|
||||
{
|
||||
if (CanScoreCategory(dice, categories[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasRemainingRollCapacity()
|
||||
{
|
||||
return _state.CurrentRoll < _state.CurrentStageRollBudget || _storedRollBank.Value > 0;
|
||||
}
|
||||
|
||||
public async UniTask<bool> TryScoreCategoryAsync(IReadOnlyList<IDice> dice, CategoryDefinition category)
|
||||
{
|
||||
if (!CanScoreCategory(dice, category))
|
||||
return false;
|
||||
|
||||
var clearedStage = GetCurrentStageState();
|
||||
var result = await _scoringSystem.ScoreCategoryAsync(
|
||||
dice,
|
||||
category,
|
||||
_state.CurrentRoll,
|
||||
GetProgressOrdinal(),
|
||||
CurrentCurrency);
|
||||
|
||||
var remainingRolls = Math.Max(0, _state.CurrentStageRollBudget - _state.CurrentRoll);
|
||||
if (remainingRolls > 0)
|
||||
_storedRollBank.Add(remainingRolls);
|
||||
|
||||
if (_config.StageClearReward > 0 && _currencyBank != null)
|
||||
_currencyBank.Add(_config.StageClearReward);
|
||||
|
||||
SetPhase(RunPhase.StageResolved);
|
||||
OnStageCleared?.Invoke(clearedStage, category, result);
|
||||
|
||||
if (_state.StageIndex >= _config.StageCount - 1)
|
||||
{
|
||||
ResolveBet();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartStage(_state.StageIndex + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void FailCurrentStage()
|
||||
{
|
||||
if (!_state.IsActive || _state.IsFailed)
|
||||
return;
|
||||
|
||||
var failedStage = GetCurrentStageState();
|
||||
_state.IsActive = false;
|
||||
_state.IsFailed = true;
|
||||
SetPhase(RunPhase.RunFailed);
|
||||
|
||||
OnStageFailed?.Invoke(failedStage);
|
||||
OnRunFailed?.Invoke(_state);
|
||||
}
|
||||
|
||||
private void StartNextBet()
|
||||
{
|
||||
_state.BetIndex += 1;
|
||||
_state.StageIndex = 0;
|
||||
_state.CurrentRoll = 0;
|
||||
_state.CurrentStageRollBudget = _config.BaseRollsPerStage;
|
||||
_state.CurrentStageTarget = _config.GetStageTarget(_state.BaseQuota, 0);
|
||||
|
||||
SetPhase(RunPhase.StartBet);
|
||||
OnCategoriesRefreshed?.Invoke();
|
||||
OnBetStarted?.Invoke(_state);
|
||||
|
||||
SetPhase(RunPhase.Shop);
|
||||
OnShopOpened?.Invoke(_state);
|
||||
}
|
||||
|
||||
private void StartStage(int stageIndex)
|
||||
{
|
||||
_state.StageIndex = stageIndex;
|
||||
_state.CurrentRoll = 0;
|
||||
_state.CurrentStageRollBudget = _config.BaseRollsPerStage;
|
||||
_state.CurrentStageTarget = _config.GetStageTarget(_state.BaseQuota, stageIndex);
|
||||
|
||||
SetPhase(RunPhase.StageStart);
|
||||
OnStageStarted?.Invoke(GetCurrentStageState());
|
||||
}
|
||||
|
||||
private void ResolveBet()
|
||||
{
|
||||
SetPhase(RunPhase.BetResolved);
|
||||
|
||||
if (_scoringSystem.IsComplete)
|
||||
{
|
||||
var bonus = _storedRollBank.Value * _config.CycleStoredRollBonusMultiplier;
|
||||
if (bonus > 0 && _currencyBank != null)
|
||||
_currencyBank.Add(bonus);
|
||||
|
||||
OnCycleCompleted?.Invoke(bonus, _storedRollBank.Value);
|
||||
|
||||
_scoringSystem.ResetScorecard();
|
||||
var nextQuota = _config.GetNextQuota(_state.BaseQuota);
|
||||
_state.BaseQuota = nextQuota;
|
||||
OnQuotaChanged?.Invoke(nextQuota);
|
||||
SetPhase(RunPhase.CycleResolved);
|
||||
}
|
||||
|
||||
StartNextBet();
|
||||
}
|
||||
|
||||
private RunStageState GetCurrentStageState()
|
||||
{
|
||||
return new RunStageState(_state.StageIndex, (RunStageType)Math.Min(_state.StageIndex, 2), _state.CurrentStageTarget);
|
||||
}
|
||||
|
||||
private int GetProgressOrdinal()
|
||||
{
|
||||
return ((_state.BetIndex - 1) * Math.Max(1, _config.StageCount)) + _state.StageIndex + 1;
|
||||
}
|
||||
|
||||
private void SetPhase(RunPhase phase)
|
||||
{
|
||||
_state.Phase = phase;
|
||||
OnPhaseChanged?.Invoke(phase);
|
||||
}
|
||||
|
||||
private void HandleStoredRollsChanged(int value)
|
||||
{
|
||||
_state.StoredRolls = value;
|
||||
OnStoredRollsChanged?.Invoke(value);
|
||||
}
|
||||
|
||||
private void HandleCurrencyChanged(int value)
|
||||
{
|
||||
OnCurrencyChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 303eb3c5c68f41b4183853b80f5bdf0d
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
public enum RunPhase
|
||||
{
|
||||
None,
|
||||
StartBet,
|
||||
Shop,
|
||||
StageStart,
|
||||
Rolling,
|
||||
CategorySelection,
|
||||
StageResolved,
|
||||
BetResolved,
|
||||
CycleResolved,
|
||||
RunFailed,
|
||||
RunCompleted,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3538676a7c72a1f4088981a1a33c6126
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
[Serializable]
|
||||
public readonly struct RunStageState
|
||||
{
|
||||
public RunStageState(int index, RunStageType stageType, int target)
|
||||
{
|
||||
Index = index;
|
||||
StageType = stageType;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public int Index { get; }
|
||||
public RunStageType StageType { get; }
|
||||
public int Target { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efe1d4387ae5ef94da49a7fcd867a3cb
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
public enum RunStageType
|
||||
{
|
||||
Base = 0,
|
||||
Mid = 1,
|
||||
Final = 2,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 279fbb0d4676dcf4eb0224a8535f8a86
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class RunState
|
||||
{
|
||||
public int BaseQuota;
|
||||
public int BetIndex;
|
||||
public int StageIndex;
|
||||
public int CurrentStageTarget;
|
||||
public int CurrentRoll;
|
||||
public int CurrentStageRollBudget;
|
||||
public int StoredRolls;
|
||||
public bool IsActive;
|
||||
public bool IsFailed;
|
||||
public RunPhase Phase;
|
||||
|
||||
public int StageNumber => StageIndex + 1;
|
||||
public bool IsInShop => Phase == RunPhase.Shop;
|
||||
public bool IsCategorySelection => Phase == RunPhase.CategorySelection;
|
||||
public bool IsRollingState => Phase == RunPhase.StageStart || Phase == RunPhase.Rolling || Phase == RunPhase.CategorySelection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 308eb21a80d1c2a4283e6de6aac0d026
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace YachtDice.Run
|
||||
{
|
||||
public sealed class StoredRollBank
|
||||
{
|
||||
public int Value { get; private set; }
|
||||
|
||||
public event Action<int> OnChanged;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
SetValue(0);
|
||||
}
|
||||
|
||||
public void Add(int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
SetValue(Value + amount);
|
||||
}
|
||||
|
||||
public bool TrySpend(int amount)
|
||||
{
|
||||
if (amount <= 0 || Value < amount)
|
||||
return false;
|
||||
|
||||
SetValue(Value - amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetValue(int value)
|
||||
{
|
||||
Value = Math.Max(0, value);
|
||||
OnChanged?.Invoke(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e46140b5dd26bfc469334aabd4ab51b8
|
||||
@@ -54,6 +54,20 @@ namespace YachtDice.Shop
|
||||
shopView.Show();
|
||||
}
|
||||
|
||||
public void Open()
|
||||
{
|
||||
if (shopView == null) return;
|
||||
shopView.Show();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (shopView == null) return;
|
||||
shopView.Hide();
|
||||
}
|
||||
|
||||
public bool IsOpen => shopView != null && shopView.IsVisible;
|
||||
|
||||
private void HandleBuyClicked(IShopItem item)
|
||||
{
|
||||
_model.TryPurchase(item);
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using YachtDice.Categories;
|
||||
using YachtDice.Dice;
|
||||
using YachtDice.Economy;
|
||||
using YachtDice.Run;
|
||||
using YachtDice.Scoring;
|
||||
|
||||
namespace YachtDice.Tests
|
||||
{
|
||||
public sealed class RunLoopServiceTests
|
||||
{
|
||||
private readonly List<Object> _createdAssets = new();
|
||||
private readonly IReadOnlyList<IDice> _emptyDice = new IDice[0];
|
||||
|
||||
private CurrencyBank _currencyBank;
|
||||
private ScoringSystem _scoringSystem;
|
||||
private StoredRollBank _storedRollBank;
|
||||
private RunBalanceConfigSO _config;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var bankGo = new GameObject("CurrencyBank");
|
||||
_currencyBank = bankGo.AddComponent<CurrencyBank>();
|
||||
_currencyBank.SetBalance(0);
|
||||
|
||||
var scoringGo = new GameObject("ScoringSystem");
|
||||
_scoringSystem = scoringGo.AddComponent<ScoringSystem>();
|
||||
|
||||
_storedRollBank = new StoredRollBank();
|
||||
_config = RunBalanceConfigSO.CreateDefault();
|
||||
_createdAssets.Add(_config);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
foreach (var scoring in Object.FindObjectsByType<ScoringSystem>(FindObjectsSortMode.None))
|
||||
Object.DestroyImmediate(scoring.gameObject);
|
||||
|
||||
foreach (var bank in Object.FindObjectsByType<CurrencyBank>(FindObjectsSortMode.None))
|
||||
Object.DestroyImmediate(bank.gameObject);
|
||||
|
||||
for (var i = 0; i < _createdAssets.Count; i++)
|
||||
{
|
||||
if (_createdAssets[i] != null)
|
||||
Object.DestroyImmediate(_createdAssets[i]);
|
||||
}
|
||||
|
||||
_createdAssets.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StartNewRun_EntersShopWithConfigQuota()
|
||||
{
|
||||
var categories = CreateFixedCatalog(100, 100, 100);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
|
||||
Assert.AreEqual(30, service.State.BaseQuota);
|
||||
Assert.AreEqual(1, service.State.BetIndex);
|
||||
Assert.AreEqual(RunPhase.Shop, service.State.Phase);
|
||||
Assert.AreEqual(0, service.State.StoredRolls);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearedStage_AwardsCurrencyAndBanksUnusedRolls()
|
||||
{
|
||||
var categories = CreateFixedCatalog(100, 100, 100);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
service.CompleteShop();
|
||||
service.TryBeginRoll();
|
||||
service.NotifyRollResolved(_emptyDice);
|
||||
|
||||
var cleared = service.TryScoreCategoryAsync(_emptyDice, categories.All[0]).GetAwaiter().GetResult();
|
||||
|
||||
Assert.IsTrue(cleared);
|
||||
Assert.AreEqual(25, _currencyBank.Balance);
|
||||
Assert.AreEqual(2, service.State.StoredRolls);
|
||||
Assert.AreEqual(2, service.State.StageNumber);
|
||||
Assert.AreEqual(RunPhase.StageStart, service.State.Phase);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoredRolls_CanBeConsumedOnLaterStage()
|
||||
{
|
||||
var categories = CreateFixedCatalog(100, 100, 100);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
service.CompleteShop();
|
||||
service.TryBeginRoll();
|
||||
service.NotifyRollResolved(_emptyDice);
|
||||
service.TryScoreCategoryAsync(_emptyDice, categories.All[0]).GetAwaiter().GetResult();
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
Assert.IsTrue(service.TryBeginRoll());
|
||||
service.NotifyRollResolved(_emptyDice);
|
||||
}
|
||||
|
||||
service.TryScoreCategoryAsync(_emptyDice, categories.All[1]).GetAwaiter().GetResult();
|
||||
|
||||
Assert.AreEqual(1, service.State.StoredRolls);
|
||||
Assert.AreEqual(50, _currencyBank.Balance);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CompletedCycle_GrantsBonusRaisesQuotaAndStartsNextBet()
|
||||
{
|
||||
var categories = CreateFixedCatalog(100, 100, 100);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
service.CompleteShop();
|
||||
|
||||
ClearStageInOneRoll(service, categories.All[0]);
|
||||
ClearStageInOneRoll(service, categories.All[1]);
|
||||
ClearStageInOneRoll(service, categories.All[2]);
|
||||
|
||||
Assert.AreEqual(135, _currencyBank.Balance);
|
||||
Assert.AreEqual(60, service.State.BaseQuota);
|
||||
Assert.AreEqual(2, service.State.BetIndex);
|
||||
Assert.AreEqual(RunPhase.Shop, service.State.Phase);
|
||||
Assert.AreEqual(6, service.State.StoredRolls);
|
||||
Assert.AreEqual(0, _scoringSystem.CategoriesFilledCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailedStage_EndsRunWhenNoTargetCanBeMet()
|
||||
{
|
||||
var categories = CreateFixedCatalog(10);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
service.CompleteShop();
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
Assert.IsTrue(service.TryBeginRoll());
|
||||
service.NotifyRollResolved(_emptyDice);
|
||||
}
|
||||
|
||||
Assert.IsTrue(service.State.IsFailed);
|
||||
Assert.AreEqual(RunPhase.RunFailed, service.State.Phase);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Shop_ReopensOnlyAtStartOfNextBet()
|
||||
{
|
||||
var categories = CreateFixedCatalog(100, 100, 100, 100);
|
||||
var service = CreateService(categories);
|
||||
|
||||
service.StartNewRun();
|
||||
Assert.AreEqual(RunPhase.Shop, service.State.Phase);
|
||||
|
||||
service.CompleteShop();
|
||||
ClearStageInOneRoll(service, categories.All[0]);
|
||||
Assert.AreEqual(RunPhase.StageStart, service.State.Phase);
|
||||
|
||||
ClearStageInOneRoll(service, categories.All[1]);
|
||||
Assert.AreEqual(RunPhase.StageStart, service.State.Phase);
|
||||
|
||||
ClearStageInOneRoll(service, categories.All[2]);
|
||||
Assert.AreEqual(RunPhase.Shop, service.State.Phase);
|
||||
Assert.AreEqual(2, service.State.BetIndex);
|
||||
}
|
||||
|
||||
private RunLoopService CreateService(CategoryCatalog catalog)
|
||||
{
|
||||
_scoringSystem.Construct(null, null, catalog, _currencyBank);
|
||||
return new RunLoopService(_config, _scoringSystem, _currencyBank, _storedRollBank);
|
||||
}
|
||||
|
||||
private CategoryCatalog CreateFixedCatalog(params int[] scores)
|
||||
{
|
||||
var categories = new List<CategoryDefinition>();
|
||||
for (var i = 0; i < scores.Length; i++)
|
||||
{
|
||||
var category = FixedScoreCategory.Create($"cat_{i}", scores[i]);
|
||||
_createdAssets.Add(category);
|
||||
categories.Add(category);
|
||||
}
|
||||
|
||||
var catalog = CategoryCatalog.CreateForTest(categories);
|
||||
_createdAssets.Add(catalog);
|
||||
return catalog;
|
||||
}
|
||||
|
||||
private void ClearStageInOneRoll(RunLoopService service, CategoryDefinition category)
|
||||
{
|
||||
Assert.IsTrue(service.TryBeginRoll());
|
||||
service.NotifyRollResolved(_emptyDice);
|
||||
Assert.IsTrue(service.TryScoreCategoryAsync(_emptyDice, category).GetAwaiter().GetResult());
|
||||
}
|
||||
|
||||
private sealed class FixedScoreCategory : CategoryDefinition
|
||||
{
|
||||
[SerializeField] private int fixedScore;
|
||||
|
||||
public override int Calculate(IReadOnlyList<IDice> dice)
|
||||
{
|
||||
return fixedScore;
|
||||
}
|
||||
|
||||
public static FixedScoreCategory Create(string id, int score)
|
||||
{
|
||||
var category = CreateInstance<FixedScoreCategory>();
|
||||
category.SetTestData(id, id);
|
||||
category.fixedScore = score;
|
||||
return category;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10f09d1ab020a9f498748f79ae8c5730
|
||||
@@ -82,6 +82,11 @@ namespace YachtDice.UI
|
||||
rollButtonText.text = $"Бросок {currentRoll + 1}/{maxRolls}";
|
||||
}
|
||||
|
||||
public void SetRollButtonInteractable(bool interactable)
|
||||
{
|
||||
rollButton.interactable = interactable;
|
||||
}
|
||||
|
||||
public void ResetForNewTurn()
|
||||
{
|
||||
for (int i = 0; i < diceValues.Length; i++)
|
||||
|
||||
@@ -42,12 +42,24 @@ namespace YachtDice.UI
|
||||
turnText.text = $"Ход {turn} / {maxTurns}";
|
||||
}
|
||||
|
||||
public void SetRunInfoText(string text)
|
||||
{
|
||||
if (turnText != null)
|
||||
turnText.text = text;
|
||||
}
|
||||
|
||||
public void SetCurrencyText(int amount)
|
||||
{
|
||||
if (currencyText != null)
|
||||
currencyText.text = amount.ToString();
|
||||
}
|
||||
|
||||
public void SetShopButtonInteractable(bool interactable)
|
||||
{
|
||||
if (shopButton != null)
|
||||
shopButton.interactable = interactable;
|
||||
}
|
||||
|
||||
public void ShowGameOver(int finalScore)
|
||||
{
|
||||
gameOverPanel.SetActive(true);
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace YachtDice.UI
|
||||
private void Start()
|
||||
{
|
||||
_dicePanelPresenter = new DicePanelPresenter(dicePanelView, _gameLoopController, _diceManager);
|
||||
_scoreCardPresenter = new ScoreCardPresenter(scoreCardView, _categoryCatalog, _scoringSystem, _diceManager);
|
||||
_scoreCardPresenter = new ScoreCardPresenter(scoreCardView, _gameLoopController, _categoryCatalog, _scoringSystem, _diceManager);
|
||||
_gameInfoPresenter = new GameInfoPresenter(gameInfoView);
|
||||
|
||||
_gameFlowPresenter = new GameFlowPresenter(
|
||||
|
||||
@@ -69,6 +69,12 @@ namespace YachtDice.UI.Presentation
|
||||
_view.SetDiceLocked(index, isLocked);
|
||||
}
|
||||
|
||||
public void SetRollingEnabled(bool enabled)
|
||||
{
|
||||
_view.SetRollButtonInteractable(enabled);
|
||||
_view.SetDiceInteractable(enabled && _gameLoopController.CurrentRoll > 0);
|
||||
}
|
||||
|
||||
private void HandleRollClicked()
|
||||
{
|
||||
RollClicked?.Invoke();
|
||||
|
||||
@@ -4,6 +4,7 @@ using YachtDice.Economy;
|
||||
using YachtDice.Game;
|
||||
using YachtDice.Inventory;
|
||||
using YachtDice.Player;
|
||||
using YachtDice.Run;
|
||||
using YachtDice.Shop;
|
||||
|
||||
namespace YachtDice.UI.Presentation
|
||||
@@ -57,6 +58,13 @@ namespace YachtDice.UI.Presentation
|
||||
_gameLoopController.OnRollComplete += HandleRollComplete;
|
||||
_gameLoopController.OnScored += HandleScored;
|
||||
_gameLoopController.OnGameOver += HandleGameOver;
|
||||
_gameLoopController.OnBetStarted += HandleBetStarted;
|
||||
_gameLoopController.OnShopOpened += HandleShopOpened;
|
||||
_gameLoopController.OnShopClosed += HandleShopClosed;
|
||||
_gameLoopController.OnStoredRollsChanged += HandleStoredRollsChanged;
|
||||
_gameLoopController.OnQuotaChanged += HandleQuotaChanged;
|
||||
_gameLoopController.OnCycleCompleted += HandleCycleCompleted;
|
||||
_gameLoopController.OnPhaseChanged += HandlePhaseChanged;
|
||||
|
||||
_dicePanelPresenter.RollClicked += HandleRollClicked;
|
||||
_dicePanelPresenter.DiceToggled += HandleDiceToggled;
|
||||
@@ -70,6 +78,7 @@ namespace YachtDice.UI.Presentation
|
||||
|
||||
_saveService.Load();
|
||||
_gameInfoPresenter.SetCurrencyText(_currencyBank.Balance);
|
||||
_gameInfoPresenter.SetShopButtonInteractable(false);
|
||||
_gameLoopController.StartNewGame();
|
||||
}
|
||||
|
||||
@@ -79,6 +88,13 @@ namespace YachtDice.UI.Presentation
|
||||
_gameLoopController.OnRollComplete -= HandleRollComplete;
|
||||
_gameLoopController.OnScored -= HandleScored;
|
||||
_gameLoopController.OnGameOver -= HandleGameOver;
|
||||
_gameLoopController.OnBetStarted -= HandleBetStarted;
|
||||
_gameLoopController.OnShopOpened -= HandleShopOpened;
|
||||
_gameLoopController.OnShopClosed -= HandleShopClosed;
|
||||
_gameLoopController.OnStoredRollsChanged -= HandleStoredRollsChanged;
|
||||
_gameLoopController.OnQuotaChanged -= HandleQuotaChanged;
|
||||
_gameLoopController.OnCycleCompleted -= HandleCycleCompleted;
|
||||
_gameLoopController.OnPhaseChanged -= HandlePhaseChanged;
|
||||
|
||||
_dicePanelPresenter.RollClicked -= HandleRollClicked;
|
||||
_dicePanelPresenter.DiceToggled -= HandleDiceToggled;
|
||||
@@ -95,8 +111,9 @@ namespace YachtDice.UI.Presentation
|
||||
|
||||
private void HandleTurnStarted(int turn)
|
||||
{
|
||||
_gameInfoPresenter.SetTurnText(turn, _categoryCatalog.Count);
|
||||
UpdateRunInfoText();
|
||||
_dicePanelPresenter.ResetForNewTurn();
|
||||
_dicePanelPresenter.SetRollingEnabled(true);
|
||||
_scoreCardPresenter.ClearAllPreviews();
|
||||
}
|
||||
|
||||
@@ -110,6 +127,7 @@ namespace YachtDice.UI.Presentation
|
||||
{
|
||||
_scoreCardPresenter.SetCategoryScored(category, finalScore);
|
||||
_scoreCardPresenter.UpdateTotalDisplay(_scoreSummaryService.Calculate());
|
||||
UpdateRunInfoText();
|
||||
_saveService.Save();
|
||||
}
|
||||
|
||||
@@ -118,6 +136,8 @@ namespace YachtDice.UI.Presentation
|
||||
_dicePanelPresenter.HandleGameOver();
|
||||
_scoreCardPresenter.SetAllInteractable(false);
|
||||
_gameInfoPresenter.ShowGameOver(_scoreSummaryService.Calculate().DisplayTotal);
|
||||
_shopController.Close();
|
||||
_gameInfoPresenter.SetShopButtonInteractable(false);
|
||||
_saveService.Save();
|
||||
}
|
||||
|
||||
@@ -142,6 +162,8 @@ namespace YachtDice.UI.Presentation
|
||||
private void HandleNewGameClicked()
|
||||
{
|
||||
_gameInfoPresenter.HideGameOver();
|
||||
_shopController.Close();
|
||||
_gameInfoPresenter.SetShopButtonInteractable(false);
|
||||
_scoreCardPresenter.ResetAll();
|
||||
_dicePanelPresenter.ResetForNewGame();
|
||||
_gameLoopController.StartNewGame();
|
||||
@@ -149,7 +171,18 @@ namespace YachtDice.UI.Presentation
|
||||
|
||||
private void HandleShopClicked()
|
||||
{
|
||||
_shopController.ToggleVisibility();
|
||||
if (!_gameLoopController.CanOpenShopManually())
|
||||
return;
|
||||
|
||||
if (_shopController.IsOpen)
|
||||
{
|
||||
_shopController.Close();
|
||||
_gameLoopController.CompleteShop();
|
||||
}
|
||||
else
|
||||
{
|
||||
_shopController.Open();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleInventoryClicked()
|
||||
@@ -160,11 +193,63 @@ namespace YachtDice.UI.Presentation
|
||||
private void HandleCurrencyChanged(int newBalance)
|
||||
{
|
||||
_gameInfoPresenter.SetCurrencyText(newBalance);
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandlePlayerChangedForSave()
|
||||
{
|
||||
_saveService.Save();
|
||||
}
|
||||
|
||||
private void HandleBetStarted(int betIndex)
|
||||
{
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandleShopOpened()
|
||||
{
|
||||
_shopController.Open();
|
||||
_gameInfoPresenter.SetShopButtonInteractable(true);
|
||||
_dicePanelPresenter.SetRollingEnabled(false);
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandleShopClosed()
|
||||
{
|
||||
_shopController.Close();
|
||||
_gameInfoPresenter.SetShopButtonInteractable(false);
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandleStoredRollsChanged(int value)
|
||||
{
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandleQuotaChanged(int value)
|
||||
{
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandleCycleCompleted(int bonus, int storedRolls)
|
||||
{
|
||||
_scoreCardPresenter.ResetAll();
|
||||
_scoreCardPresenter.UpdateTotalDisplay(_scoreSummaryService.Calculate());
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void HandlePhaseChanged(RunPhase phase)
|
||||
{
|
||||
if (phase != RunPhase.Shop)
|
||||
_gameInfoPresenter.SetShopButtonInteractable(false);
|
||||
|
||||
UpdateRunInfoText();
|
||||
}
|
||||
|
||||
private void UpdateRunInfoText()
|
||||
{
|
||||
var info = $"Bet {_gameLoopController.CurrentBet} | Stage {_gameLoopController.CurrentStage}/3 | Target {_gameLoopController.CurrentStageTarget} | Quota {_gameLoopController.CurrentBaseQuota} | Bank {_gameLoopController.StoredRolls}";
|
||||
_gameInfoPresenter.SetRunInfoText(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,21 @@ namespace YachtDice.UI.Presentation
|
||||
_view.SetTurnText(turn, maxTurns);
|
||||
}
|
||||
|
||||
public void SetRunInfoText(string text)
|
||||
{
|
||||
_view.SetRunInfoText(text);
|
||||
}
|
||||
|
||||
public void SetCurrencyText(int amount)
|
||||
{
|
||||
_view.SetCurrencyText(amount);
|
||||
}
|
||||
|
||||
public void SetShopButtonInteractable(bool interactable)
|
||||
{
|
||||
_view.SetShopButtonInteractable(interactable);
|
||||
}
|
||||
|
||||
public void ShowGameOver(int finalScore)
|
||||
{
|
||||
_view.ShowGameOver(finalScore);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace YachtDice.UI.Presentation
|
||||
public sealed class ScoreCardPresenter : IDisposable
|
||||
{
|
||||
private readonly ScoreCardView _view;
|
||||
private readonly GameLoopController _gameLoopController;
|
||||
private readonly CategoryCatalog _categoryCatalog;
|
||||
private readonly ScoringSystem _scoringSystem;
|
||||
private readonly DiceManager _diceManager;
|
||||
@@ -17,11 +18,13 @@ namespace YachtDice.UI.Presentation
|
||||
|
||||
public ScoreCardPresenter(
|
||||
ScoreCardView view,
|
||||
GameLoopController gameLoopController,
|
||||
CategoryCatalog categoryCatalog,
|
||||
ScoringSystem scoringSystem,
|
||||
DiceManager diceManager)
|
||||
{
|
||||
_view = view;
|
||||
_gameLoopController = gameLoopController;
|
||||
_categoryCatalog = categoryCatalog;
|
||||
_scoringSystem = scoringSystem;
|
||||
_diceManager = diceManager;
|
||||
@@ -55,11 +58,12 @@ namespace YachtDice.UI.Presentation
|
||||
if (_scoringSystem.IsCategoryUsed(category))
|
||||
continue;
|
||||
|
||||
var result = _scoringSystem.PreviewScore(dice, category);
|
||||
var result = _gameLoopController.PreviewCategory(category);
|
||||
previews[category] = result.FinalScore;
|
||||
}
|
||||
|
||||
_view.UpdatePreviews(previews);
|
||||
SetAvailableCategoriesInteractable();
|
||||
}
|
||||
|
||||
public void SetCategoryScored(CategoryDefinition category, int finalScore)
|
||||
@@ -72,6 +76,19 @@ namespace YachtDice.UI.Presentation
|
||||
_view.SetAllInteractable(interactable);
|
||||
}
|
||||
|
||||
public void SetAvailableCategoriesInteractable()
|
||||
{
|
||||
var allCategories = _categoryCatalog.All;
|
||||
for (var i = 0; i < allCategories.Count; i++)
|
||||
{
|
||||
var category = allCategories[i];
|
||||
if (_scoringSystem.IsCategoryUsed(category))
|
||||
continue;
|
||||
|
||||
_view.SetCategoryInteractable(category, _gameLoopController.CanScoreCategory(category));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTotalDisplay(ScoreSummary summary)
|
||||
{
|
||||
_view.UpdateTotalDisplay(summary.DisplayTotal);
|
||||
|
||||
@@ -74,6 +74,12 @@ namespace YachtDice.UI
|
||||
t.SetInteractable(interactable);
|
||||
}
|
||||
|
||||
public void SetCategoryInteractable(CategoryDefinition category, bool interactable)
|
||||
{
|
||||
if (_categoryToRowIndex != null && _categoryToRowIndex.TryGetValue(category, out int index))
|
||||
categoryRows[index].SetInteractable(interactable);
|
||||
}
|
||||
|
||||
public void UpdateTotalDisplay(int totalScore)
|
||||
{
|
||||
totalScoreText.text = totalScore.ToString();
|
||||
|
||||
Reference in New Issue
Block a user