Files
YachtDice/Assets/Scripts/UI/GameController.cs
T

360 lines
13 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using VContainer;
using YachtDice.Categories;
using YachtDice.Dice;
using YachtDice.Game;
using YachtDice.Scoring;
using YachtDice.Economy;
using YachtDice.Shop;
using YachtDice.Inventory;
using YachtDice.Persistence;
using YachtDice.Player;
using YachtDice.Modifiers.Definition;
using YachtDice.Modifiers.Runtime;
namespace YachtDice.UI
{
public class GameController : MonoBehaviour
{
[Header("Views")]
[SerializeField] private ScoreCardView scoreCardView;
[SerializeField] private DicePanelView dicePanelView;
[SerializeField] private GameInfoView gameInfoView;
[Header("Settings")]
[SerializeField] private int maxRollsPerTurn = 3;
private const int UpperBonusThreshold = 63;
private const int UpperBonusValue = 35;
private GameManager _gameManager;
private ScoringSystem _scoringSystem;
private DiceManager _diceManager;
private CurrencyBank _currencyBank;
private ShopController _shopController;
private InventoryController _inventoryController;
private ModifierRegistry _modifierRegistry;
private CategoryCatalog _categoryCatalog;
private ModifierCatalog _modifierCatalog;
private DiceCatalog _diceCatalog;
private ShopModel _shopModel;
private PlayerModel _playerModel;
[Inject]
public void Construct(
GameManager gameManager,
ScoringSystem scoringSystem,
DiceManager diceManager,
CurrencyBank currencyBank,
ShopController shopController,
InventoryController inventoryController,
ModifierRegistry modifierRegistry,
CategoryCatalog categoryCatalog,
ModifierCatalog modifierCatalog,
DiceCatalog diceCatalog,
ShopModel shopModel,
PlayerModel playerModel)
{
this._gameManager = gameManager;
this._scoringSystem = scoringSystem;
this._diceManager = diceManager;
this._currencyBank = currencyBank;
this._shopController = shopController;
this._inventoryController = inventoryController;
this._modifierRegistry = modifierRegistry;
this._categoryCatalog = categoryCatalog;
this._modifierCatalog = modifierCatalog;
this._diceCatalog = diceCatalog;
this._shopModel = shopModel;
this._playerModel = playerModel;
}
// ── Lifecycle ──────────────────────────────────────────────
private void Start()
{
// Model → Controller
_gameManager.OnTurnStarted += HandleTurnStarted;
_gameManager.OnRollComplete += HandleRollComplete;
_gameManager.OnScored += HandleScored;
_gameManager.OnGameOver += HandleGameOver;
_diceManager.OnDiceSettled += HandleDiceSettled;
// View → Controller
scoreCardView.OnCategorySelected += HandleCategorySelected;
dicePanelView.OnRollClicked += HandleRollClicked;
dicePanelView.OnDiceToggled += HandleDiceToggled;
gameInfoView.OnNewGameClicked += HandleNewGameClicked;
gameInfoView.OnShopClicked += HandleShopClicked;
gameInfoView.OnInventoryClicked += HandleInventoryClicked;
// Currency & Player state
_currencyBank.OnBalanceChanged += HandleCurrencyChanged;
_playerModel.OnChanged += HandlePlayerChangedForSave;
// Initialize
scoreCardView.Initialize(_categoryCatalog);
LoadSaveData();
gameInfoView.SetCurrencyText(_currencyBank.Balance);
// Start the game after all subscriptions are in place
_gameManager.StartNewGame();
}
private void OnDestroy()
{
_gameManager.OnTurnStarted -= HandleTurnStarted;
_gameManager.OnRollComplete -= HandleRollComplete;
_gameManager.OnScored -= HandleScored;
_gameManager.OnGameOver -= HandleGameOver;
_diceManager.OnDiceSettled -= HandleDiceSettled;
scoreCardView.OnCategorySelected -= HandleCategorySelected;
dicePanelView.OnRollClicked -= HandleRollClicked;
dicePanelView.OnDiceToggled -= HandleDiceToggled;
gameInfoView.OnNewGameClicked -= HandleNewGameClicked;
gameInfoView.OnShopClicked -= HandleShopClicked;
gameInfoView.OnInventoryClicked -= HandleInventoryClicked;
_currencyBank.OnBalanceChanged -= HandleCurrencyChanged;
if (_playerModel != null)
_playerModel.OnChanged -= HandlePlayerChangedForSave;
}
// ── Save / Load ─────────────────────────────────────────
private void LoadSaveData()
{
SaveData save = SaveSystem.Load();
if (save.currency > 0)
_currencyBank.SetBalance(save.currency);
if (_modifierCatalog != null && save.ownedModifiers.Count > 0)
{
var entries = new List<ModifierSaveEntry>();
var permanentIds = new HashSet<string>();
for (int i = 0; i < save.ownedModifiers.Count; i++)
{
var oldEntry = save.ownedModifiers[i];
var def = _modifierCatalog.FindById(oldEntry.modifierId);
if (def == null)
{
Debug.LogWarning($"Modifier '{oldEntry.modifierId}' not found in catalog, skipping.");
continue;
}
entries.Add(new ModifierSaveEntry
{
modifierId = oldEntry.modifierId,
isActive = oldEntry.isActive,
remainingUses = oldEntry.remainingUses,
stacks = oldEntry.stacks,
customState = oldEntry.customState,
});
if (!def.HasLimitedUses)
permanentIds.Add(def.Id);
}
_modifierRegistry.LoadSaveData(entries, _modifierCatalog);
_shopModel.LoadPurchasedPermanentIds(permanentIds);
}
if (_diceCatalog != null && save.ownedDiceIds != null && save.ownedDiceIds.Count > 0)
{
_playerModel.Dice.LoadSaveData(save.ownedDiceIds, _diceCatalog);
var dicePermIds = new HashSet<string>(save.ownedDiceIds);
var existingIds = _shopModel.GetPurchasedPermanentIds();
foreach (var id in dicePermIds)
existingIds.Add(id);
_shopModel.LoadPurchasedPermanentIds(existingIds);
}
}
private void PerformSave()
{
var save = new SaveData
{
currency = _currencyBank.Balance,
ownedDiceIds = _playerModel.Dice.GetSaveData(),
};
var entries = _modifierRegistry.GetSaveData();
for (int i = 0; i < entries.Count; i++)
{
save.ownedModifiers.Add(entries[i]);
}
SaveSystem.Save(save);
}
// ── Model Event Handlers ──────────────────────────────────
private void HandleTurnStarted(int turn)
{
int totalCategoryCount = _categoryCatalog.Count;
gameInfoView.SetTurnText(turn, totalCategoryCount);
dicePanelView.ResetForNewTurn();
dicePanelView.SetRollButtonState(true, 0, maxRollsPerTurn);
scoreCardView.ClearAllPreviews();
}
private void HandleRollComplete(int rollNumber)
{
bool canRollAgain = _gameManager.CanRoll;
dicePanelView.SetRollButtonState(canRollAgain, rollNumber, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(true);
int[] values = _diceManager.GetCurrentValues();
dicePanelView.SetAllDiceValues(values);
UpdatePreviewScores();
}
private void HandleDiceSettled(int index, int value)
{
dicePanelView.SetDiceValue(index, value);
}
private void HandleScored(CategoryDefinition category, int finalScore)
{
scoreCardView.SetCategoryScored(category, finalScore);
UpdateTotalDisplay();
PerformSave();
}
private void HandleGameOver(int totalScore)
{
dicePanelView.SetRollButtonState(false, maxRollsPerTurn, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
int displayTotal = CalculateDisplayTotal();
gameInfoView.ShowGameOver(displayTotal);
PerformSave();
}
// ── View Event Handlers ───────────────────────────────────
private void HandleRollClicked()
{
if (!_gameManager.CanRoll) return;
dicePanelView.SetRollButtonState(false, _gameManager.CurrentRoll, maxRollsPerTurn);
dicePanelView.SetDiceInteractable(false);
scoreCardView.SetAllInteractable(false);
_gameManager.Roll();
}
private void HandleDiceToggled(int index)
{
if (_gameManager.CurrentRoll == 0) return;
if (_diceManager.IsAnyRolling) return;
_gameManager.ToggleDiceLock(index);
bool isLocked = _diceManager.IsLocked(index);
dicePanelView.SetDiceLocked(index, isLocked);
}
private void HandleCategorySelected(CategoryDefinition category)
{
if (!_gameManager.CanScore) return;
if (_scoringSystem.IsCategoryUsed(category)) return;
_gameManager.ScoreInCategory(category);
}
private void HandleNewGameClicked()
{
gameInfoView.HideGameOver();
scoreCardView.ResetAll();
dicePanelView.ResetForNewGame();
_gameManager.StartNewGame();
}
private void HandleShopClicked()
{
_shopController.ToggleVisibility();
}
private void HandleInventoryClicked()
{
_inventoryController.ToggleVisibility();
}
private void HandleCurrencyChanged(int newBalance)
{
gameInfoView.SetCurrencyText(newBalance);
}
private void HandlePlayerChangedForSave()
{
PerformSave();
}
// ── Helpers ────────────────────────────────────────────────
private void UpdatePreviewScores()
{
var dice = _diceManager.GetDice();
var previews = new Dictionary<CategoryDefinition, int>();
var allCategories = _categoryCatalog.All;
for (int i = 0; i < allCategories.Count; i++)
{
var cat = allCategories[i];
if (_scoringSystem.IsCategoryUsed(cat)) continue;
ScoreResult result = _scoringSystem.PreviewScore(dice, cat);
previews[cat] = result.FinalScore;
}
scoreCardView.UpdatePreviews(previews);
}
private void UpdateTotalDisplay()
{
int upperSum = CalculateUpperSum();
bool hasBonus = upperSum >= UpperBonusThreshold;
int displayTotal = CalculateDisplayTotal();
scoreCardView.UpdateTotalDisplay(displayTotal, upperSum, hasBonus);
}
private int CalculateUpperSum()
{
int upperSum = 0;
var allCategories = _categoryCatalog.All;
for (int i = 0; i < allCategories.Count; i++)
{
if (!allCategories[i].IsUpperSection) continue;
int catScore = _scoringSystem.GetCategoryScore(allCategories[i]);
if (catScore >= 0) upperSum += catScore;
}
return upperSum;
}
private int CalculateDisplayTotal()
{
int total = _scoringSystem.TotalScore;
int upperSum = CalculateUpperSum();
if (upperSum >= UpperBonusThreshold)
total += UpperBonusValue;
return total;
}
}
}