360 lines
12 KiB
C#
360 lines
12 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.SetDieValue(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.SetDieLocked(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;
|
|
}
|
|
}
|
|
}
|