using System; using System.Collections.Generic; using KernelPanic.Data; using KernelPanic.Meta; using UnityEngine; using UnityEngine.TextCore.Text; using UnityEngine.UIElements; namespace KernelPanic.UI { /// /// Renders banner selection and pull controls for the gacha screen. /// [Serializable] public sealed class GachaScreenController { private const string SelectedClassName = "selected"; private readonly List bannerRows = new(); private readonly string[] bannerIds = { GachaService.BeginnerBannerId, GachaService.StandardBannerId, GachaService.LimitedBannerId }; private VisualElement bannerList; private VisualElement bannerDetail; private DistroDatabase distroDatabase; private FontAsset monospaceFont; private GachaService gachaService; private PlayerCollection playerCollection; private EntropyWallet wallet; private Action onChanged; private Action requestRootCreditExchange; private int selectedBannerIndex; private int pendingPullCount; private int pendingMissingTokens; private bool hasOpened; private string resultBannerId; private string resultText; public void Bind(VisualElement root, DistroDatabase database, FontAsset artFont, GachaService service, PlayerCollection collection, EntropyWallet entropyWallet, Action changedCallback, Action rootCreditExchangeCallback) { distroDatabase = database; monospaceFont = artFont; gachaService = service; playerCollection = collection; wallet = entropyWallet; onChanged = changedCallback; requestRootCreditExchange = rootCreditExchangeCallback; bannerList = root.Q("GachaBannerList"); bannerDetail = root.Q("GachaBannerDetail"); } public void Open() { if (!hasOpened) { selectedBannerIndex = 0; hasOpened = true; } Refresh(); } public void Refresh() { if (bannerList == null || bannerDetail == null || gachaService == null) { return; } bannerRows.Clear(); bannerList.Clear(); for (int i = 0; i < bannerIds.Length; i++) { int index = i; VisualElement row = BuildBannerRow(bannerIds[i]); row.RegisterCallback(_ => SelectBanner(index)); bannerList.Add(row); bannerRows.Add(row); } selectedBannerIndex = Mathf.Clamp(selectedBannerIndex, 0, bannerRows.Count - 1); ApplySelectedBanner(); } public void HandleKeyDown(KeyDownEvent evt) { // Pulls are deliberately click-only to avoid accidental currency spend. } private VisualElement BuildBannerRow(string bannerId) { VisualElement row = new(); row.AddToClassList("gacha-banner-row"); row.Add(new Label(">") { name = $"GachaBannerCursor_{bannerId}" }); row.ElementAt(0).AddToClassList("command-cursor"); row.Add(new Label(GetBannerTitle(bannerId)) { name = $"GachaBannerName_{bannerId}" }); row.ElementAt(1).AddToClassList("command-text"); row.Add(new Label(GetBannerStatus(bannerId)) { name = $"GachaBannerStatus_{bannerId}" }); row.ElementAt(2).AddToClassList("command-description"); return row; } private void SelectBanner(int index) { if (bannerRows.Count == 0) { return; } selectedBannerIndex = (index + bannerRows.Count) % bannerRows.Count; ApplySelectedBanner(); } private void ApplySelectedBanner() { for (int i = 0; i < bannerRows.Count; i++) { bool selected = i == selectedBannerIndex; bannerRows[i].EnableInClassList(SelectedClassName, selected); bannerRows[i].Q