diff --git a/Assets/Scenes/MainMenuScene.unity b/Assets/Scenes/MainMenuScene.unity index 39bacd8..c8a1d4a 100644 --- a/Assets/Scenes/MainMenuScene.unity +++ b/Assets/Scenes/MainMenuScene.unity @@ -304,5 +304,5 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: monospaceFont: {fileID: 0} - featuredUnitPanel: - featuredUnits: [] + motdBody: unstable userspace detected; keep a rollback shell open. + featuredUnitPanel: {} diff --git a/Assets/Scripts/UI/FeaturedUnitPanel.cs b/Assets/Scripts/UI/FeaturedUnitPanel.cs index 3b3a0ed..0847619 100644 --- a/Assets/Scripts/UI/FeaturedUnitPanel.cs +++ b/Assets/Scripts/UI/FeaturedUnitPanel.cs @@ -15,8 +15,6 @@ namespace KernelPanic.UI private const string EmptyAccent = "5cff91"; private const string EmptyAscii = " _\n | |\n ___| |__\n / __| '_ \\\n \\__ \\ | | |\n |___/_| |_|"; - [SerializeField] private List featuredUnits = new(); - private VisualElement panel; private Label titleLabel; private Label asciiLabel; @@ -28,6 +26,7 @@ namespace KernelPanic.UI private Label emptyHintLabel; private VisualElement populatedState; private VisualElement emptyState; + private IReadOnlyList units = Array.Empty(); private int selectedIndex; public void Bind(VisualElement root) @@ -45,26 +44,33 @@ namespace KernelPanic.UI emptyState = root.Q("FeaturedUnitEmptyState"); } + public void Refresh(IReadOnlyList ownedUnits) + { + units = ownedUnits ?? Array.Empty(); + Refresh(); + } + public void Refresh() { - if (featuredUnits == null || featuredUnits.Count == 0) + if (units == null || units.Count == 0) { ShowEmptyState(); return; } - selectedIndex = Mathf.Clamp(selectedIndex, 0, featuredUnits.Count - 1); - ShowUnit(featuredUnits[selectedIndex]); + selectedIndex = Mathf.Clamp(selectedIndex, 0, units.Count - 1); + ShowUnit(units[selectedIndex]); } public void SelectNext() { - if (featuredUnits == null || featuredUnits.Count < 2) + int unitCount = units?.Count ?? 0; + if (unitCount < 2) { return; } - selectedIndex = (selectedIndex + 1) % featuredUnits.Count; + selectedIndex = (selectedIndex + 1) % unitCount; Refresh(); } @@ -73,7 +79,7 @@ namespace KernelPanic.UI populatedState.AddToClassList("hidden"); emptyState.RemoveFromClassList("hidden"); - titleLabel.text = "neofetch"; + titleLabel.text = "[ neofetch ]"; emptyTitleLabel.text = "no units installed"; emptyHintLabel.text = "run: curl gacha.sh | sh"; SetAccent(EmptyAccent); @@ -85,7 +91,7 @@ namespace KernelPanic.UI emptyState.AddToClassList("hidden"); string displayName = string.IsNullOrWhiteSpace(unit.DisplayName) ? unit.name : unit.DisplayName; - titleLabel.text = displayName; + titleLabel.text = "[ neofetch ]"; asciiLabel.text = EmptyAscii; // TODO: Replace with unit-specific ASCII copy when unit presentation data exists. unitNameLabel.text = displayName; languagesLabel.text = $"{unit.PrimaryLanguage} / {unit.SecondaryLanguage}"; @@ -103,6 +109,7 @@ namespace KernelPanic.UI panel.style.borderBottomColor = new StyleColor(parsedColor); panel.style.borderLeftColor = new StyleColor(parsedColor); titleLabel.style.color = new StyleColor(parsedColor); + unitNameLabel.style.color = new StyleColor(parsedColor); } } } diff --git a/Assets/Scripts/UI/MainMenuController.cs b/Assets/Scripts/UI/MainMenuController.cs index 84d6540..6e37168 100644 --- a/Assets/Scripts/UI/MainMenuController.cs +++ b/Assets/Scripts/UI/MainMenuController.cs @@ -25,6 +25,7 @@ namespace KernelPanic.UI private static bool bootIntroPlayed; [SerializeField] private FontAsset monospaceFont; // TODO: Assign a real monospace FontAsset when typography assets exist. + [SerializeField] private string motdBody = "unstable userspace detected; keep a rollback shell open."; [SerializeField] private FeaturedUnitPanel featuredUnitPanel = new(); private readonly List commandEntries = new(); @@ -44,21 +45,23 @@ namespace KernelPanic.UI private Label titleCursorLabel; private Label promptCursorLabel; private Label bootIntroLogLabel; - private Label backgroundLogLabel; + private Label motdBodyLabel; + private VisualElement motdBlock; private Button collectionBackButton; private Button gachaBackButton; private Button settingsBackButton; private EntropyWallet wallet; private GachaService gachaService; + private PlayerCollection playerCollection; + private BackgroundLogRingBuffer backgroundLog; private IEventBannerSource eventBannerSource; private int selectedCommandIndex; - private float backgroundScrollOffset; private float bootIntroElapsed; private int bootIntroCharacterCount; + private bool cursorVisible; private bool suppressNextClick; private string bootIntroCopy; private IVisualElementScheduledItem blinkSchedule; - private IVisualElementScheduledItem backgroundSchedule; private IVisualElementScheduledItem bootIntroSchedule; public void Initialize(EntropyWallet initializedWallet) @@ -71,6 +74,7 @@ namespace KernelPanic.UI { document = GetComponent(); gachaService = new GachaService(); + playerCollection = new PlayerCollection(); // TODO: Replace with persistent player-collection service composition. Initialize(new EntropyWallet()); // TODO: Replace with persistent wallet service composition. BindElements(); BindCommandEntries(); @@ -87,7 +91,7 @@ namespace KernelPanic.UI RefreshStaticText(); RefreshCurrencyReadouts(); RefreshEventBanner(); - featuredUnitPanel.Refresh(); + featuredUnitPanel.Refresh(playerCollection.OwnedUnits); SelectCommand(0); ShowMainMenu(); StartAmbientSchedules(); @@ -98,7 +102,7 @@ namespace KernelPanic.UI { UnregisterCallbacks(); blinkSchedule?.Pause(); - backgroundSchedule?.Pause(); + backgroundLog?.Stop(); bootIntroSchedule?.Pause(); } @@ -112,7 +116,9 @@ namespace KernelPanic.UI gachaPanel = root.Q("GachaPanel"); settingsPanel = root.Q("SettingsPanel"); eventBanner = root.Q("EventBanner"); + motdBlock = root.Q("MotdBlock"); backgroundLogLayer = root.Q("BackgroundLogLayer"); + backgroundLog = new BackgroundLogRingBuffer(backgroundLogLayer, BootLogCopy.Lines); appIdLabel = root.Q