using System.Collections.Generic; using UnityEngine; using System.Runtime.ExceptionServices; #if UNITY_EDITOR using UnityEditor; #endif public class UI_Idols : MonoBehaviour { [Header("prefabs")] public GameObject idolCardPrefab; public Transform idolCardParent; [Header("sprites")] public Sprite[] idolLevelIcons; public Sprite[] idolBtm; [Header("colors")] public Color[] idolSliderColors; [Header("paths")] public string idolSOpath_runtime; public string idolSOpath_editor; [Header("scan")] public bool includeLockedHeroes = false; [Header("rightPanel")] public GameObject righePanel; private readonly List spawnedCards = new List(); private void Start() { RebuildCards(); } private void OnEnable() { RebuildCards(); } [ContextMenu("Rebuild Idols")] public void RebuildCards() { if (idolCardPrefab == null || idolCardParent == null) { return; } ClearCards(); List heroes = LoadHeroAssets(); if (heroes.Count == 0) { return; } heroes.Sort((left, right) => left.ally_heroID.CompareTo(right.ally_heroID)); for (int i = 0; i < heroes.Count; i++) { AllyHero_SO hero = heroes[i]; if (hero == null) { continue; } if (!includeLockedHeroes && !hero.isUnlocked) { continue; } IdolLevelSnapshot snapshot = BuildLevelSnapshot(hero); GameObject instance = Instantiate(idolCardPrefab, idolCardParent); spawnedCards.Add(instance); idolCardPrefab card = instance.GetComponent(); if (card == null) { continue; } card.Setup( hero.ally_hero_squareProfile, hero.ally_heroDesignation, hero.ally_heroName, snapshot.sliderValue, snapshot.xpText, snapshot.levelIcon, snapshot.bottomSprite, snapshot.sliderColor); } } private List LoadHeroAssets() { List heroes = new List(); #if UNITY_EDITOR if (!Application.isPlaying && !string.IsNullOrWhiteSpace(idolSOpath_editor)) { string[] searchFolders = { idolSOpath_editor }; string[] guids = AssetDatabase.FindAssets("t:AllyHero_SO", searchFolders); for (int i = 0; i < guids.Length; i++) { string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]); AllyHero_SO hero = AssetDatabase.LoadAssetAtPath(assetPath); if (hero != null) { heroes.Add(hero); } } return heroes; } #endif AllyHero_SO[] loadedHeroes = Resources.LoadAll(string.IsNullOrWhiteSpace(idolSOpath_runtime) ? string.Empty : idolSOpath_runtime); for (int i = 0; i < loadedHeroes.Length; i++) { if (loadedHeroes[i] != null) { heroes.Add(loadedHeroes[i]); } } return heroes; } private IdolLevelSnapshot BuildLevelSnapshot(AllyHero_SO hero) { IdolLevelSnapshot snapshot = new IdolLevelSnapshot { sliderValue = 0f, xpText = "UNKNOWN", levelIcon = GetLevelIconByIndex(4), bottomSprite = GetBottomSpriteByIndex(4), sliderColor = GetSliderColorByIndex(4) }; if (hero == null) { return snapshot; } List levels = new List(); if (hero.levelStats != null) { for (int i = 0; i < hero.levelStats.Count; i++) { if (hero.levelStats[i] != null) { levels.Add(hero.levelStats[i]); } } } if (levels.Count == 0) { return snapshot; } levels.Sort((left, right) => left.requiredEXP.CompareTo(right.requiredEXP)); int currentExp = Mathf.Max(0, hero.ally_currentEXP); int currentLevelIndex = -1; for (int i = 0; i < levels.Count; i++) { if (currentExp >= levels[i].requiredEXP) { currentLevelIndex = i; } } int displayIndex = Mathf.Clamp(currentLevelIndex >= 0 ? currentLevelIndex : 0, 0, levels.Count - 1); AllyHero_SO.AllyLevelInfo currentLevel = levels[displayIndex]; int tierIndex = ResolveTierIndex(currentLevel, displayIndex, levels.Count); snapshot.levelIcon = GetLevelIconByIndex(tierIndex); snapshot.bottomSprite = GetBottomSpriteByIndex(tierIndex); snapshot.sliderColor = GetSliderColorByIndex(tierIndex); if (displayIndex >= levels.Count - 1 && currentExp >= currentLevel.requiredEXP) { snapshot.sliderValue = 1f; snapshot.xpText = "MAX"; return snapshot; } int floorExp = currentLevelIndex >= 0 ? currentLevel.requiredEXP : 0; int nextLevelIndex = Mathf.Clamp(displayIndex + 1, 0, levels.Count - 1); int nextExp = levels[nextLevelIndex].requiredEXP; int range = Mathf.Max(1, nextExp - floorExp); int gained = Mathf.Clamp(currentExp - floorExp, 0, range); snapshot.sliderValue = Mathf.Clamp01(gained / (float)range); int neededExp = nextExp - currentExp; if (neededExp > 0) { snapshot.xpText = "NEED " + neededExp + " EXP"; } else if (displayIndex >= levels.Count - 1) { snapshot.xpText = "MAX"; } return snapshot; } private int ResolveTierIndex(AllyHero_SO.AllyLevelInfo levelInfo, int levelIndex, int levelCount) { if (levelInfo != null && !string.IsNullOrWhiteSpace(levelInfo.levelName)) { string normalized = levelInfo.levelName.Trim().ToUpperInvariant(); if (normalized.Contains("S")) return 3; if (normalized.Contains("A")) return 2; if (normalized.Contains("B")) return 1; if (normalized.Contains("C")) return 0; } if (levelCount <= 1) { return 0; } float normalizedIndex = levelIndex / (float)Mathf.Max(1, levelCount - 1); if (normalizedIndex >= 0.99f) return 3; if (normalizedIndex >= 0.66f) return 2; if (normalizedIndex >= 0.33f) return 1; return 0; } private Sprite GetLevelIconByIndex(int index) { if (idolLevelIcons == null || idolLevelIcons.Length == 0) { return null; } return idolLevelIcons[Mathf.Clamp(index, 0, idolLevelIcons.Length - 1)]; } private Sprite GetBottomSpriteByIndex(int index) { if (idolBtm == null || idolBtm.Length == 0) { return null; } return idolBtm[Mathf.Clamp(index, 0, idolBtm.Length - 1)]; } private Color GetSliderColorByIndex(int index) { if (idolSliderColors == null || idolSliderColors.Length == 0) { return Color.white; } return idolSliderColors[Mathf.Clamp(index, 0, idolSliderColors.Length - 1)]; } private void ClearCards() { for (int i = spawnedCards.Count - 1; i >= 0; i--) { if (spawnedCards[i] == null) { continue; } #if UNITY_EDITOR if (!Application.isPlaying) { DestroyImmediate(spawnedCards[i]); } else #endif { Destroy(spawnedCards[i]); } } spawnedCards.Clear(); if (idolCardParent == null) { return; } for (int i = idolCardParent.childCount - 1; i >= 0; i--) { Transform child = idolCardParent.GetChild(i); if (child == null || child.GetComponent() == null) { continue; } #if UNITY_EDITOR if (!Application.isPlaying) { DestroyImmediate(child.gameObject); } else #endif { Destroy(child.gameObject); } } } private struct IdolLevelSnapshot { public float sliderValue; public string xpText; public Sprite levelIcon; public Sprite bottomSprite; public Color sliderColor; } }