#nullable enable using System.Collections; using TMPro; using UnityEngine; using UnityEngine.UI; namespace ReplacedPerson.Runtime { [DisallowMultipleComponent] public sealed class ReplacedBattlePhaseMotion : MonoBehaviour { private RectTransform? _panel; private CanvasGroup? _group; private Image? _background; private Image? _accent; private TMP_Text? _title; private TMP_Text? _detail; public bool IsVisible => _panel != null && _panel.gameObject.activeSelf; public string CurrentTitle => _title?.text ?? string.Empty; private void Awake() { CreateOverlay(); SetVisible(false); } public IEnumerator PlayStage(string title, string detail, Color accent, float holdSeconds = .68f) { if (!Prepare(title, detail, accent)) yield break; yield return FadeIn(); yield return new WaitForSecondsRealtime(holdSeconds); yield return FadeOut(); } public IEnumerator PlayDie(string title, int finalFace, string result, Color accent) { if (!Prepare(title, "D6 ยท", accent)) yield break; yield return FadeIn(); for (var frame = 0; frame < 8; frame++) { if (_detail != null) _detail.text = "D6 " + ((frame * 5 + 2) % 6 + 1); if (_panel != null) _panel.localRotation = Quaternion.Euler(0, 0, frame % 2 == 0 ? -1.2f : 1.2f); yield return new WaitForSecondsRealtime(.065f); } if (_panel != null) _panel.localRotation = Quaternion.identity; if (_detail != null) _detail.text = $"D6 {finalFace}\n{result}"; yield return new WaitForSecondsRealtime(.75f); yield return FadeOut(); } private bool Prepare(string title, string detail, Color accent) { if (_panel == null || _group == null || _background == null || _accent == null || _title == null || _detail == null) return false; _title.text = title; _detail.text = detail; _accent.color = accent; _background.color = new Color(.035f, .041f, .043f, .96f); _panel.localScale = Vector3.one * .92f; _panel.localRotation = Quaternion.identity; _group.alpha = 0f; SetVisible(true); _panel.SetAsLastSibling(); return true; } private IEnumerator FadeIn() { if (_panel == null || _group == null) yield break; var elapsed = 0f; const float duration = .16f; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; var t = 1f - Mathf.Pow(1f - Mathf.Clamp01(elapsed / duration), 3f); _group.alpha = t; _panel.localScale = Vector3.one * Mathf.Lerp(.92f, 1f, t); yield return null; } _group.alpha = 1f; _panel.localScale = Vector3.one; } private IEnumerator FadeOut() { if (_panel == null || _group == null) yield break; var elapsed = 0f; const float duration = .16f; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; var t = Mathf.Clamp01(elapsed / duration); _group.alpha = 1f - t; _panel.localScale = Vector3.one * Mathf.Lerp(1f, .97f, t); yield return null; } SetVisible(false); } private void CreateOverlay() { var panelObject = new GameObject("ResolutionPhaseOverlay", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(CanvasGroup)); _panel = panelObject.GetComponent(); _panel.SetParent(transform, false); _panel.anchorMin = new Vector2(.25f, .37f); _panel.anchorMax = new Vector2(.75f, .64f); _panel.offsetMin = Vector2.zero; _panel.offsetMax = Vector2.zero; _background = panelObject.GetComponent(); _background.raycastTarget = false; _group = panelObject.GetComponent(); _group.blocksRaycasts = false; _group.interactable = false; var accentObject = new GameObject("Accent", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image)); var accentRect = accentObject.GetComponent(); accentRect.SetParent(_panel, false); accentRect.anchorMin = new Vector2(0, 0); accentRect.anchorMax = new Vector2(0, 1); accentRect.pivot = new Vector2(0, .5f); accentRect.sizeDelta = new Vector2(9, 0); _accent = accentObject.GetComponent(); _accent.raycastTarget = false; var font = GetComponentInChildren(true)?.font; _title = CreateText("Title", _panel, font, new Vector2(.08f, .55f), new Vector2(.92f, .92f), 31, FontStyles.Bold); _detail = CreateText("Detail", _panel, font, new Vector2(.08f, .10f), new Vector2(.92f, .58f), 22, FontStyles.Normal); _detail.enableAutoSizing = true; _detail.fontSizeMin = 14; _detail.fontSizeMax = 22; } private static TMP_Text CreateText(string name, Transform parent, TMP_FontAsset? font, Vector2 anchorMin, Vector2 anchorMax, float fontSize, FontStyles style) { var textObject = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI)); var rect = textObject.GetComponent(); rect.SetParent(parent, false); rect.anchorMin = anchorMin; rect.anchorMax = anchorMax; rect.offsetMin = Vector2.zero; rect.offsetMax = Vector2.zero; var text = textObject.GetComponent(); text.font = font; text.fontSize = fontSize; text.fontStyle = style; text.alignment = TextAlignmentOptions.Center; text.color = new Color(.95f, .93f, .87f, 1f); text.raycastTarget = false; return text; } private void SetVisible(bool visible) { if (_panel != null) _panel.gameObject.SetActive(visible); } private void OnDisable() { if (_panel != null) { _panel.localScale = Vector3.one; _panel.localRotation = Quaternion.identity; } if (_group != null) _group.alpha = 0f; SetVisible(false); } } }