using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; namespace DuloGames.UI { [AddComponentMenu("UI/Icon Slots/Slot Cooldown", 28)] public class UISlotCooldown : MonoBehaviour { public class CooldownInfo { public float duration; public float startTime; public float endTime; public CooldownInfo(float duration, float startTime, float endTime) { this.duration = duration; this.startTime = startTime; this.endTime = endTime; } } private static Dictionary spellCooldowns = new Dictionary(); [SerializeField] private UISlotBase m_TargetSlot; [SerializeField] private Image m_TargetGraphic; [SerializeField] private Text m_TargetText; [SerializeField] private Image m_FinishGraphic; [SerializeField] private float m_FinishOffsetY = 0f; [SerializeField] private float m_FinishFadingPct = 25f; private IUISlotHasCooldown m_CooldownSlot; private bool m_IsOnCooldown = false; private int m_CurrentSpellId = 0; protected void Awake() { // Set the cooldown component variable on the target slot if (this.m_TargetSlot != null && this.m_TargetSlot is IUISlotHasCooldown) { this.m_CooldownSlot = this.m_TargetSlot as IUISlotHasCooldown; this.m_CooldownSlot.SetCooldownComponent(this); } else { Debug.LogWarning("The slot cooldown script cannot operate without a target slot with a IUISlotHasCooldown interface, disabling script."); this.enabled = false; return; } } protected void Start() { // Disable the image and text if they are shown by any chance if (this.m_TargetGraphic != null) this.m_TargetGraphic.enabled = false; if (this.m_TargetText != null) this.m_TargetText.enabled = false; // Prepare the finish if (this.m_FinishGraphic != null) { this.m_FinishGraphic.enabled = false; this.m_FinishGraphic.rectTransform.anchorMin = new Vector2(this.m_FinishGraphic.rectTransform.anchorMin.x, 1f); this.m_FinishGraphic.rectTransform.anchorMax = new Vector2(this.m_FinishGraphic.rectTransform.anchorMax.x, 1f); } } protected void OnEnable() { // Check for active cooldown this.CheckForActiveCooldown(); } protected void OnDisable() { // Disable any current cooldown display this.InterruptCooldown(); } /// /// Gets a value indicating whether the cooldown is active. /// /// true if this instance is on cooldown; otherwise, false. public bool IsOnCooldown { get { return this.m_IsOnCooldown; } } /// /// Raises the assign spell event. /// public void OnAssignSpell() { this.CheckForActiveCooldown(); } /// /// Raises the unassign event. /// public void OnUnassignSpell() { this.InterruptCooldown(); } /// /// Checks if the target slot has an active cooldown and resumes it. /// public void CheckForActiveCooldown() { // Return if the slot is not valid if (this.m_CooldownSlot == null) return; // Get the spell info UISpellInfo spellInfo = this.m_CooldownSlot.GetSpellInfo(); if (spellInfo == null) return; // Check if this spell still has cooldown if (spellCooldowns.ContainsKey(spellInfo.ID)) { float cooldownTill = spellCooldowns[spellInfo.ID].endTime; // Check if the cooldown isnt expired if (cooldownTill > Time.time) { this.m_IsOnCooldown = true; // Resume the cooldown this.ResumeCooldown(spellInfo.ID); } else { // Cooldown already expired, remove the record spellCooldowns.Remove(spellInfo.ID); } } } /// /// Starts a cooldown. /// /// Spell identifier. /// Duration. public void StartCooldown(int spellId, float duration) { if (!this.enabled || !this.gameObject.activeInHierarchy || this.m_TargetGraphic == null) return; // Save the spell id this.m_CurrentSpellId = spellId; // Enable the image if it's disabled if (!this.m_TargetGraphic.enabled) this.m_TargetGraphic.enabled = true; // Reset the fill amount this.m_TargetGraphic.fillAmount = 1f; // Enable the text if it's disabled if (this.m_TargetText != null) { if (!this.m_TargetText.enabled) this.m_TargetText.enabled = true; this.m_TargetText.text = duration.ToString("0"); } // Prepare the finish graphic if (this.m_FinishGraphic != null) { this.m_FinishGraphic.canvasRenderer.SetAlpha(0f); this.m_FinishGraphic.enabled = true; this.m_FinishGraphic.rectTransform.anchoredPosition = new Vector2( this.m_FinishGraphic.rectTransform.anchoredPosition.x, this.m_FinishOffsetY ); } // Set the slot on cooldown this.m_IsOnCooldown = true; // Create new cooldown info CooldownInfo cooldownInfo = new CooldownInfo(duration, Time.time, (Time.time + duration)); // Save that this spell is on cooldown if (!spellCooldowns.ContainsKey(spellId)) spellCooldowns.Add(spellId, cooldownInfo); // Start the coroutine this.StartCoroutine("_StartCooldown", cooldownInfo); } /// /// Resumes a cooldown. /// /// Spell identifier. public void ResumeCooldown(int spellId) { if (!this.enabled || !this.gameObject.activeInHierarchy || this.m_TargetGraphic == null) return; // Check if we have the cooldown info for that spell if (!spellCooldowns.ContainsKey(spellId)) return; // Get the cooldown info CooldownInfo cooldownInfo = spellCooldowns[spellId]; // Get the remaining time float remainingTime = (cooldownInfo.endTime - Time.time); float remainingTimePct = remainingTime / cooldownInfo.duration; // Save the spell id this.m_CurrentSpellId = spellId; // Enable the image if it's disabled if (!this.m_TargetGraphic.enabled) this.m_TargetGraphic.enabled = true; // Set the fill amount to the remaing percents this.m_TargetGraphic.fillAmount = (remainingTime / cooldownInfo.duration); // Enable the text if it's disabled if (this.m_TargetText != null) { if (!this.m_TargetText.enabled) this.m_TargetText.enabled = true; this.m_TargetText.text = remainingTime.ToString("0"); } // Update the finish if (this.m_FinishGraphic != null) { this.m_FinishGraphic.enabled = true; this.UpdateFinishPosition(remainingTimePct); } // Start the coroutine this.StartCoroutine("_StartCooldown", cooldownInfo); } /// /// Interrupts the current cooldown. /// public void InterruptCooldown() { // Cancel the coroutine this.StopCoroutine("_StartCooldown"); // Call the finish this.OnCooldownFinished(); } IEnumerator _StartCooldown(CooldownInfo cooldownInfo) { while (Time.time < (cooldownInfo.startTime + cooldownInfo.duration)) { float RemainingTime = (cooldownInfo.startTime + cooldownInfo.duration) - Time.time; float RemainingTimePct = RemainingTime / cooldownInfo.duration; // Update the cooldown image if (this.m_TargetGraphic != null) this.m_TargetGraphic.fillAmount = RemainingTimePct; // Update the text if (this.m_TargetText != null) this.m_TargetText.text = RemainingTime.ToString("0"); // Update the finish position this.UpdateFinishPosition(RemainingTimePct); yield return 0; } // Call the on finish this.OnCooldownCompleted(); } /// /// Raised when the cooldown completes it's full duration. /// private void OnCooldownCompleted() { // Remove from the cooldowns list if (spellCooldowns.ContainsKey(this.m_CurrentSpellId)) spellCooldowns.Remove(this.m_CurrentSpellId); // Fire up the cooldown finished this.OnCooldownFinished(); } /// /// Raised when the cooldown finishes or has been interrupted. /// private void OnCooldownFinished() { // No longer on cooldown this.m_IsOnCooldown = false; this.m_CurrentSpellId = 0; // Disable the image if (this.m_TargetGraphic != null) this.m_TargetGraphic.enabled = false; // Disable the text if (this.m_TargetText != null) this.m_TargetText.enabled = false; // Disable the finish sprite if (this.m_FinishGraphic != null) this.m_FinishGraphic.enabled = false; } /// /// Updates the finish position based on the remaining time percentage of the cooldown. /// /// Remaining time pct. protected void UpdateFinishPosition(float RemainingTimePct) { // Update the finish position if (this.m_FinishGraphic != null && this.m_TargetGraphic != null) { // Calculate the fill position float newY = (0f - this.m_TargetGraphic.rectTransform.rect.height + (this.m_TargetGraphic.rectTransform.rect.height * RemainingTimePct)); // Add the offset newY += this.m_FinishOffsetY; // Update the finish position this.m_FinishGraphic.rectTransform.anchoredPosition = new Vector2( this.m_FinishGraphic.rectTransform.anchoredPosition.x, newY ); float fadingPct = this.m_FinishFadingPct / 100; // Manage finish fading if (RemainingTimePct <= fadingPct) { this.m_FinishGraphic.canvasRenderer.SetAlpha(RemainingTimePct / fadingPct); } else if (RemainingTimePct >= (1f - fadingPct)) { this.m_FinishGraphic.canvasRenderer.SetAlpha(1f - (RemainingTimePct - (1f - fadingPct)) / fadingPct); } else if (RemainingTimePct > fadingPct && RemainingTimePct < (1f - fadingPct)) { this.m_FinishGraphic.canvasRenderer.SetAlpha(1f); } } } } }