using System.Collections.Generic; using EventSystem.Runtime; using Adventurer.Runtime; using Core.Runtime; using Quests.Runtime; using TMPro; using UnityEngine; namespace GameUI.Runtime { public class AdventurersPanel : BasePanel { #region Unity API void OnEnable() { AdventurerSignals.OnPortraitCaptured += OnPortraitCapturedHandler; AdventurerSignals.OnRefresh += DisplayAdventurers; } private void Start() { foreach (var txt in GetComponentsInChildren()) { txt.text = LocalizationSystem.Instance.GetLocalizedText(txt.text); } DisplayAdventurers(); } private void OnDisable() { AdventurerSignals.OnPortraitCaptured -= OnPortraitCapturedHandler; AdventurerSignals.OnRefresh -= DisplayAdventurers; } #endregion #region Utils void OnPortraitCapturedHandler(AdventurerClass adventurer, Sprite portrait) { foreach (Transform child in _heroesPanel.transform) { AdventurerCardUI card = child.GetComponent(); if (card != null && card.Adventurer == adventurer) { card.SetPortrait(portrait); break; } } } void DisplayAdventurers() { // Build a lookup of existing cards by their Adventurer instance Dictionary existing = new Dictionary(); List orphaned = new List(); foreach (Transform child in _heroesPanel.transform) { AdventurerCardUI card = child.GetComponent(); if (card != null && card.Adventurer != null) { if (!existing.ContainsKey(card.Adventurer)) existing.Add(card.Adventurer, card); else orphaned.Add(card); // duplicate safety } else if (card != null) { orphaned.Add(card); } } List filtered = FilterAdventurers(_sort); // Reuse or create cards to match the filtered list and order HashSet used = new HashSet(); for (int i = 0; i < filtered.Count; i++) { AdventurerClass adv = filtered[i]; AdventurerCardUI card; if (existing.TryGetValue(adv, out card)) { // Refresh textual data and availability indicators without touching portrait card.setup(adv); card.transform.SetSiblingIndex(i); } else { GameObject cardAdventurerGO = Instantiate(_adventurerPrefab, _heroesPanel.transform); cardAdventurerGO.transform.SetSiblingIndex(i); card = cardAdventurerGO.GetComponent(); if (card != null) { card.setup(adv); } } if (card != null) used.Add(card); } // Remove cards that are no longer needed (not part of filtered) or orphaned foreach (Transform child in _heroesPanel.transform) { AdventurerCardUI card = child.GetComponent(); if (card != null && !used.Contains(card)) { Destroy(child.gameObject); } } // Cleanup any explicit orphaned duplicates detected earlier foreach (var card in orphaned) { if (card != null && !used.Contains(card)) { Destroy(card.gameObject); } } } List FilterAdventurers(AdventurerSortEnum sortType) { List allAdventurers = GetFact>("my_adventurers"); switch (sortType) { case AdventurerSortEnum.Available: return allAdventurers.FindAll(a => a.IsAvailable); case AdventurerSortEnum.NotAvailable: return allAdventurers.FindAll(a => !a.IsAvailable); case AdventurerSortEnum.AssignedToQuest: return QuestClass.GetAdventurersFromId(QuestManager.Instance.AssignedAdventurers); case AdventurerSortEnum.None: return allAdventurers; default: return allAdventurers; } } #endregion #region Privates and Protected [SerializeField] GameObject _adventurerPrefab; [SerializeField] GameObject _heroesPanel; [SerializeField] AdventurerSortEnum _sort; #endregion } }