using UnityEngine; using UnityEngine.Events; using TMPro; using ColliderEventSystem; /// /// A resource that accumulates (coins, ammo, fragments): the amount, its rules, its display and its events. /// The CES calls Add(int), Remove(int) or Spend(int) with an Invoke Events action. /// public class Resource : MonoBehaviour { [Header("Value")] [Tooltip("Amount at start")] public int startValue = 0; [Tooltip("Maximum amount. 0 = no limit.")] public int maximum = 0; [Tooltip("Amount to reach to trigger On Goal Reached. 0 = no goal.")] public int goal = 0; [Header("CES link (optional)")] [Tooltip("CES variable kept up to date by this script. Lets the amount be used in a CES condition.")] public IntVariable variable; [Tooltip("Checked: back to the start value each time the scene loads. Unchecked: takes the variable's value (the resource follows the player from one level to the next).")] public bool resetOnStart = true; [Header("Display")] [Tooltip("Canvas text")] public TMP_Text text; [Tooltip("{0} = amount, {1} = goal")] public string format = "× {0}"; [Header("Events")] public UnityEvent onAdded; public UnityEvent onRemoved; public UnityEvent onGoalReached; public UnityEvent onInsufficientFunds; int amount; bool goalAlreadyReached; public int Amount => amount; void Start() { if (variable != null && !resetOnStart) amount = Clamp(variable.RuntimeValue); else amount = Clamp(startValue); if (variable != null) variable.RuntimeValue = amount; goalAlreadyReached = goal > 0 && amount >= goal; Display(); } void Update() { // A CES Variable action changed the amount directly: apply the rules anyway if (variable != null && variable.RuntimeValue != amount) Set(variable.RuntimeValue); } // --- Public methods: visible in Invoke Events and On Click --- public void Add(int count) => Set(amount + count); /// Removes what it can, without going below 0. public void Remove(int count) => Set(amount - count); /// All or nothing: removes the price only if there is enough. Otherwise, On Insufficient Funds. public void Spend(int price) { if (amount >= price) Set(amount - price); else onInsufficientFunds.Invoke(); } public void ResetValue() { goalAlreadyReached = false; Set(startValue); } // --- Rules --- int Clamp(int n) { n = Mathf.Max(0, n); if (maximum > 0) n = Mathf.Min(n, maximum); return n; } void Set(int newAmount) { newAmount = Clamp(newAmount); int oldAmount = amount; amount = newAmount; if (variable != null) variable.RuntimeValue = amount; Display(); if (amount > oldAmount) onAdded.Invoke(); if (amount < oldAmount) onRemoved.Invoke(); if (goal > 0 && !goalAlreadyReached && amount >= goal) { goalAlreadyReached = true; onGoalReached.Invoke(); } } // --- Display --- void Display() { if (text != null) text.text = string.Format(format, amount, goal); } }