Add actual carts and shit

Upgrade UI to Level 6

Balls
This commit is contained in:
2026-07-06 13:41:15 +02:00
parent f69e832503
commit 8b6c6235c2
17 changed files with 978 additions and 165 deletions
+21
View File
@@ -0,0 +1,21 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 85f230365a0e4f28a4bfbdb0a15115a8, type: 3}
m_Name: CardDatabase
m_EditorClassIdentifier:
allCards:
- {fileID: 11400000, guid: 0a4f1d1d84564f3cad58b8863e941201, type: 2}
- {fileID: 11400000, guid: 14c5d40f866a4cb6b0a6316e01f42891, type: 2}
- {fileID: 11400000, guid: 2a0f50d541f046fc99c8fb6deef4f1aa, type: 2}
- {fileID: 11400000, guid: 3d57857f3f30419c8be4c44914c5abbe, type: 2}
- {fileID: 11400000, guid: 4cae271a0f4146c59aab74e4c9d6d0f8, type: 2}
- {fileID: 11400000, guid: 5fef058a72b54b4aa2b2dd8f4d08bfe5, type: 2}
+26
View File
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: AskUbuntu
m_EditorClassIdentifier:
id: ubuntu_ask_ubuntu
displayName: ask ubuntu
description: "queue: draw 2 cards."
language: 3
rarity: 0
cycleCost: 0
resolutionTrack: 1
distroExclusive: 1
isToken: 0
designNotes: pure draw on resolve.
upgradeTarget: {fileID: 0}
effects: []
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: DoReleaseUpgrade
m_EditorClassIdentifier:
id: ubuntu_do_release_upgrade
displayName: do-release-upgrade
description: upgrade 1-3 random cards in your hand this combat.
language: 4
rarity: 1
cycleCost: 2
resolutionTrack: 0
distroExclusive: 1
isToken: 0
designNotes: count rolled on resolution (JS variance).
upgradeTarget: {fileID: 0}
effects: []
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: SnapInstall
m_EditorClassIdentifier:
id: ubuntu_snap_install
displayName: snap install
description: deal 6-14 damage. shuffle an ubuntu pro trial into your draw pile.
language: 4
rarity: 0
cycleCost: 0
resolutionTrack: 0
distroExclusive: 1
isToken: 0
designNotes: "JS variance roll at resolution; junk-token insertion; references token by id ubuntu_pro_trial."
upgradeTarget: {fileID: 0}
effects: []
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: SudoAptInstall
m_EditorClassIdentifier:
id: ubuntu_apt_install
displayName: sudo apt install
description: "queue: add a random common python card to your hand. it costs 0 this combat."
language: 3
rarity: 0
cycleCost: 1
resolutionTrack: 1
distroExclusive: 1
isToken: 0
designNotes: on-resolve card generation from the common Python pool.
upgradeTarget: {fileID: 0}
effects: []
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: UbuntuProTrial
m_EditorClassIdentifier:
id: ubuntu_pro_trial
displayName: ubuntu pro trial
description: unplayable. exhausts at end of combat.
language: 3
rarity: 0
cycleCost: 0
resolutionTrack: 0
distroExclusive: 0
isToken: 1
designNotes: "junk token; unplayable flag TBD in combat model."
upgradeTarget: {fileID: 0}
effects: []
@@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
m_Name: UnattendedUpgrades
m_EditorClassIdentifier:
id: ubuntu_unattended_upgrades
displayName: unattended-upgrades
description: gain 4 shield now and at the end of your next 2 turns.
language: 3
rarity: 0
cycleCost: 1
resolutionTrack: 1
distroExclusive: 1
isToken: 0
designNotes: immediate shield + 2-turn delayed shield ticks.
upgradeTarget: {fileID: 0}
effects: []
+13
View File
@@ -10,10 +10,12 @@ namespace KernelPanic.Meta
public sealed class PlayerCollection
{
private readonly List<DistroDefinition> ownedUnits = new();
private int featuredIndex;
// TODO: Populate owned units from SaveService during bootstrap.
// TODO: Add newly unlocked units from GachaService rewards when pulls exist.
public IReadOnlyList<DistroDefinition> OwnedUnits => ownedUnits;
public DistroDefinition FeaturedUnit => ownedUnits.Count == 0 ? null : ownedUnits[Math.Clamp(featuredIndex, 0, ownedUnits.Count - 1)];
public event Action Changed;
@@ -26,7 +28,18 @@ namespace KernelPanic.Meta
// Persistence is wired by the owner so this domain class stays IO-free.
ownedUnits.Add(unit);
featuredIndex = Math.Clamp(featuredIndex, 0, ownedUnits.Count - 1);
Changed?.Invoke();
}
public void SelectNextFeatured()
{
if (ownedUnits.Count < 2)
{
return;
}
featuredIndex = (featuredIndex + 1) % ownedUnits.Count;
}
}
}
+6 -10
View File
@@ -60,7 +60,7 @@ namespace KernelPanic.Meta
public bool starterChosen;
public List<string> ownedUnitIds = new();
public List<string> bannerPoolIds = new();
public List<CardLoadoutSaveEntry> cardLoadouts = new();
public LastRunLoadoutSaveEntry lastRunLoadout = new();
public static SaveData CreateDefault()
{
@@ -71,24 +71,20 @@ namespace KernelPanic.Meta
{
ownedUnitIds ??= new List<string>();
bannerPoolIds ??= new List<string>();
cardLoadouts ??= new List<CardLoadoutSaveEntry>();
for (int i = 0; i < cardLoadouts.Count; i++)
{
cardLoadouts[i] ??= new CardLoadoutSaveEntry();
cardLoadouts[i].EnsureLists();
}
lastRunLoadout ??= new LastRunLoadoutSaveEntry();
lastRunLoadout.EnsureLists();
}
}
[Serializable]
public sealed class CardLoadoutSaveEntry
public sealed class LastRunLoadoutSaveEntry
{
public string distroId;
public List<string> equippedCardIds = new();
public List<string> cardIds = new();
public void EnsureLists()
{
equippedCardIds ??= new List<string>();
cardIds ??= new List<string>();
}
}
}
+142 -7
View File
@@ -19,6 +19,7 @@ namespace KernelPanic.UI
private VisualElement detail;
private FontAsset monospaceFont;
private IReadOnlyList<DistroDefinition> units = Array.Empty<DistroDefinition>();
private IReadOnlyList<CardEntry> cards = Array.Empty<CardEntry>();
private int selectedIndex;
public void Bind(VisualElement root, FontAsset artFont)
@@ -28,7 +29,7 @@ namespace KernelPanic.UI
detail = root.Q<VisualElement>("CollectionDetail");
}
public void Refresh(IReadOnlyList<DistroDefinition> ownedUnits)
public void RefreshUnits(IReadOnlyList<DistroDefinition> ownedUnits)
{
units = ownedUnits ?? Array.Empty<DistroDefinition>();
if (list == null || detail == null)
@@ -73,6 +74,55 @@ namespace KernelPanic.UI
SelectUnit(selectedIndex);
}
public void RefreshCards(DistroDefinition featuredUnit)
{
cards = BuildCardEntries(featuredUnit);
if (list == null || detail == null)
{
return;
}
rows.Clear();
list.Clear();
if (cards.Count == 0)
{
detail.Clear();
detail.Add(new Label("no cards installed") { name = "CollectionEmptyTitle" });
detail.Add(new Label("featured distro cards appear here") { name = "CollectionEmptyHint" });
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, cards.Count - 1);
for (int i = 0; i < cards.Count; i++)
{
int index = i;
CardEntry entry = cards[i];
VisualElement row = new();
row.AddToClassList("collection-row");
row.RegisterCallback<PointerEnterEvent>(_ => SelectCard(index));
row.RegisterCallback<ClickEvent>(_ => SelectCard(index));
Label name = new(GetCardDisplayName(entry.Card));
name.AddToClassList("collection-row-name");
Label meta = new($"{DistroPresentation.DisplayName(entry.Owner)} / {FormatCardMeta(entry.Card)}");
meta.AddToClassList("collection-row-languages");
row.Add(name);
row.Add(meta);
list.Add(row);
rows.Add(row);
}
SelectCard(selectedIndex);
}
public void Refresh(IReadOnlyList<DistroDefinition> ownedUnits)
{
RefreshUnits(ownedUnits);
}
private void SelectUnit(int index)
{
if (units.Count == 0)
@@ -89,10 +139,35 @@ namespace KernelPanic.UI
RenderDetail(units[selectedIndex]);
}
private void SelectCard(int index)
{
if (cards.Count == 0)
{
return;
}
selectedIndex = Mathf.Clamp(index, 0, cards.Count - 1);
for (int i = 0; i < rows.Count; i++)
{
rows[i].EnableInClassList("selected", i == selectedIndex);
}
RenderCardDetail(cards[selectedIndex]);
}
private void RenderDetail(DistroDefinition unit)
{
detail.Clear();
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("collection-detail-name");
name.style.color = new StyleColor(unit.AccentColor);
detail.Add(name);
Label description = new(string.IsNullOrWhiteSpace(unit.Description) ? "--" : unit.Description);
description.AddToClassList("collection-detail-description");
detail.Add(description);
VisualElement readout = new();
readout.AddToClassList("collection-detail-readout");
@@ -107,11 +182,6 @@ namespace KernelPanic.UI
VisualElement details = new();
details.AddToClassList("collection-detail-values");
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("collection-detail-name");
name.style.color = new StyleColor(unit.AccentColor);
details.Add(name);
details.Add(BuildDetailLine("lang", DistroPresentation.FormatLanguages(unit)));
details.Add(BuildDetailLine("passive", string.IsNullOrWhiteSpace(unit.PassiveName) ? "--" : unit.PassiveName));
details.Add(BuildDetailLine("uptime", unit.BaseUptime.ToString()));
@@ -120,10 +190,26 @@ namespace KernelPanic.UI
readout.Add(details);
detail.Add(readout);
}
Label description = new(string.IsNullOrWhiteSpace(unit.Description) ? "--" : unit.Description);
private void RenderCardDetail(CardEntry entry)
{
detail.Clear();
CardDefinition card = entry.Card;
Label name = new(GetCardDisplayName(card));
name.AddToClassList("collection-detail-name");
detail.Add(name);
Label description = new(card == null || string.IsNullOrWhiteSpace(card.Description) ? "--" : card.Description);
description.AddToClassList("collection-detail-description");
detail.Add(description);
detail.Add(BuildDetailLine("owner", DistroPresentation.DisplayName(entry.Owner)));
detail.Add(BuildDetailLine("lang", card == null ? "--" : card.Language.ToString()));
detail.Add(BuildDetailLine("rarity", card == null ? "--" : card.Rarity.ToString()));
detail.Add(BuildDetailLine("cost", card == null ? "--" : card.CycleCost.ToString()));
detail.Add(BuildDetailLine("type", card != null && card.IsToken ? "token" : "loadout"));
}
private static VisualElement BuildDetailLine(string key, string value)
@@ -140,5 +226,54 @@ namespace KernelPanic.UI
row.Add(valueLabel);
return row;
}
private static IReadOnlyList<CardEntry> BuildCardEntries(DistroDefinition featuredUnit)
{
List<CardEntry> entries = new();
if (featuredUnit == null)
{
return entries;
}
for (int cardIndex = 0; cardIndex < featuredUnit.ExclusiveCards.Count; cardIndex++)
{
CardDefinition card = featuredUnit.ExclusiveCards[cardIndex];
if (card == null)
{
continue;
}
entries.Add(new CardEntry(featuredUnit, card));
}
return entries;
}
private static string GetCardDisplayName(CardDefinition card)
{
if (card == null)
{
return "--";
}
return string.IsNullOrWhiteSpace(card.DisplayName) ? card.Id : card.DisplayName;
}
private static string FormatCardMeta(CardDefinition card)
{
return card == null ? "--" : $"{card.Language} / {card.CycleCost}c";
}
private readonly struct CardEntry
{
public CardEntry(DistroDefinition owner, CardDefinition card)
{
Owner = owner;
Card = card;
}
public DistroDefinition Owner { get; }
public CardDefinition Card { get; }
}
}
}
+28 -2
View File
@@ -55,12 +55,22 @@ namespace KernelPanic.UI
}
public void Refresh(IReadOnlyList<DistroDefinition> ownedUnits)
{
Refresh(ownedUnits, null);
}
public void Refresh(IReadOnlyList<DistroDefinition> ownedUnits, DistroDefinition featuredUnit)
{
units = ownedUnits ?? Array.Empty<DistroDefinition>();
Refresh();
Refresh(featuredUnit);
}
public void Refresh()
{
Refresh((DistroDefinition)null);
}
private void Refresh(DistroDefinition featuredUnit)
{
if (units == null || units.Count == 0)
{
@@ -68,7 +78,7 @@ namespace KernelPanic.UI
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, units.Count - 1);
selectedIndex = ResolveSelectedIndex(featuredUnit);
ShowUnit(units[selectedIndex]);
}
@@ -84,6 +94,22 @@ namespace KernelPanic.UI
Refresh();
}
private int ResolveSelectedIndex(DistroDefinition featuredUnit)
{
if (featuredUnit != null)
{
for (int i = 0; i < units.Count; i++)
{
if (units[i] == featuredUnit)
{
return i;
}
}
}
return Mathf.Clamp(selectedIndex, 0, units.Count - 1);
}
private void ShowEmptyState()
{
populatedState.AddToClassList("hidden");
+393 -81
View File
@@ -43,6 +43,8 @@ namespace KernelPanic.UI
[SerializeField] private StarterSelectionController starterSelection = new();
private readonly List<CommandMenuEntry> commandEntries = new();
private readonly List<VisualElement> packageRows = new();
private readonly List<VisualElement> loadoutRows = new();
private UIDocument document;
private VisualElement root;
private VisualElement shellRoot;
@@ -54,6 +56,8 @@ namespace KernelPanic.UI
private VisualElement settingsPanel;
private VisualElement eventBanner;
private VisualElement backgroundLogLayer;
private ScrollView runSetupList;
private VisualElement runSetupDetail;
private Label appIdLabel;
private Label entropyLabel;
private Label pullTokensLabel;
@@ -62,12 +66,12 @@ namespace KernelPanic.UI
private Label bootIntroLogLabel;
private Label motdBodyLabel;
private VisualElement motdBlock;
private Button collectionBackButton;
private Button collectionUnitsButton;
private Button collectionCardsButton;
private Button runSetupBackButton;
private Button gachaBackButton;
private Button settingsBackButton;
private readonly ScreenFrameController runSetupFrame = new();
private readonly ScreenFrameController collectionFrame = new();
private readonly ScreenFrameController gachaFrame = new();
private readonly ScreenFrameController settingsFrame = new();
private SaveService saveService;
private SaveData saveData;
private EntropyWallet wallet;
@@ -77,12 +81,14 @@ namespace KernelPanic.UI
private BackgroundLogRingBuffer backgroundLog;
private IEventBannerSource eventBannerSource;
private int selectedCommandIndex;
private int selectedPackageIndex;
private string runSetupNotice;
private bool collectionShowingCards;
private float bootIntroElapsed;
private int bootIntroCharacterCount;
private bool cursorVisible;
private bool suppressNextClick;
private bool warnedUnresolvedSaveId;
private bool warnedInvalidLoadoutId;
private string bootIntroCopy;
private IVisualElementScheduledItem blinkSchedule;
private IVisualElementScheduledItem bootIntroSchedule;
@@ -106,6 +112,7 @@ namespace KernelPanic.UI
RegisterCommandEntryCallbacks();
featuredUnitPanel.Bind(root, monospaceFont);
collectionScreen.Bind(root, monospaceFont);
BindScreenFrames();
starterSelection.Bind(root, distroDatabase, HandleStarterConfirmed);
LoadMetaState();
playerCollection.Changed += HandleMetaStateChanged;
@@ -121,8 +128,8 @@ namespace KernelPanic.UI
RefreshStaticText();
RefreshCurrencyReadouts();
RefreshEventBanner();
featuredUnitPanel.Refresh(playerCollection.OwnedUnits);
collectionScreen.Refresh(playerCollection.OwnedUnits);
featuredUnitPanel.Refresh(playerCollection.OwnedUnits, playerCollection.FeaturedUnit);
collectionScreen.RefreshUnits(playerCollection.OwnedUnits);
SelectCommand(0);
ShowMainMenu();
StartAmbientSchedules();
@@ -151,6 +158,8 @@ namespace KernelPanic.UI
eventBanner = root.Q<VisualElement>("EventBanner");
motdBlock = root.Q<VisualElement>("MotdBlock");
backgroundLogLayer = root.Q<VisualElement>("BackgroundLogLayer");
runSetupList = root.Q<ScrollView>("RunSetupList");
runSetupDetail = root.Q<VisualElement>("RunSetupDetail");
backgroundLog = new BackgroundLogRingBuffer(backgroundLogLayer, BootLogCopy.Lines);
appIdLabel = root.Q<Label>("AppIdLabel");
@@ -161,12 +170,16 @@ namespace KernelPanic.UI
bootIntroLogLabel = root.Q<Label>("BootIntroLogLabel");
motdBodyLabel = root.Q<Label>("MotdBodyLabel");
collectionBackButton = root.Q<Button>("CollectionBackButton");
collectionUnitsButton = root.Q<Button>("CollectionUnitsButton");
collectionCardsButton = root.Q<Button>("CollectionCardsButton");
runSetupBackButton = root.Q<Button>("RunSetupBackButton");
gachaBackButton = root.Q<Button>("GachaBackButton");
settingsBackButton = root.Q<Button>("SettingsBackButton");
}
private void BindScreenFrames()
{
runSetupFrame.Bind(runSetupPanel, "$ ./start_run --configure", "[esc] back [arrows] navigate [enter] select [b] boot run", ShowMainMenu);
collectionFrame.Bind(collectionPanel, "$ ls ~/collection", "[esc] back [left/right] tabs [tab] tabs [arrows] navigate [enter] select", ShowMainMenu);
gachaFrame.Bind(gachaPanel, "$ curl gacha.sh | sh", "[esc] back", ShowMainMenu);
settingsFrame.Bind(settingsPanel, "$ dpkg-reconfigure kernel-panic", "[esc] back", ShowMainMenu);
}
private void BindCommandEntries()
@@ -193,24 +206,16 @@ namespace KernelPanic.UI
{
root.RegisterCallback<KeyDownEvent>(HandleKeyDown);
root.RegisterCallback<PointerDownEvent>(HandlePointerDown);
collectionBackButton.clicked += ShowMainMenu;
collectionUnitsButton.clicked += ShowCollectionUnits;
collectionCardsButton.clicked += ShowCollectionCards;
runSetupBackButton.clicked += ShowMainMenu;
gachaBackButton.clicked += ShowMainMenu;
settingsBackButton.clicked += ShowMainMenu;
}
private void UnregisterCallbacks()
{
root.UnregisterCallback<KeyDownEvent>(HandleKeyDown);
root.UnregisterCallback<PointerDownEvent>(HandlePointerDown);
collectionBackButton.clicked -= ShowMainMenu;
collectionUnitsButton.clicked -= ShowCollectionUnits;
collectionCardsButton.clicked -= ShowCollectionCards;
runSetupBackButton.clicked -= ShowMainMenu;
gachaBackButton.clicked -= ShowMainMenu;
settingsBackButton.clicked -= ShowMainMenu;
}
private void LoadMetaState()
@@ -236,27 +241,6 @@ namespace KernelPanic.UI
}
}
for (int i = 0; i < saveData.cardLoadouts.Count; i++)
{
CardLoadoutSaveEntry entry = saveData.cardLoadouts[i];
entry.EnsureLists();
List<string> resolvedIds = new();
for (int cardIndex = 0; cardIndex < entry.equippedCardIds.Count; cardIndex++)
{
string resolvedId = ResolveSavedCardId(entry.equippedCardIds[cardIndex]);
if (!string.IsNullOrWhiteSpace(resolvedId))
{
resolvedIds.Add(resolvedId);
}
}
if (!cardLoadout.TryLoad(entry.distroId, resolvedIds, out bool skippedInvalid) || skippedInvalid)
{
WarnInvalidLoadoutId();
}
}
EnsureLoadoutsForOwnedUnits();
SaveCurrentState();
}
@@ -272,40 +256,11 @@ namespace KernelPanic.UI
return unit;
}
private string ResolveSavedCardId(string id)
{
if (cardDatabase == null)
{
return id;
}
CardDefinition card = cardDatabase.FindById(id);
if (card == null)
{
WarnInvalidLoadoutId();
return null;
}
return card.Id;
}
private void WarnInvalidLoadoutId()
{
if (warnedInvalidLoadoutId)
{
return;
}
warnedInvalidLoadoutId = true;
Debug.LogWarning("Save references an invalid card loadout id; restoring a valid default loadout.");
}
private void HandleMetaStateChanged()
{
EnsureLoadoutsForOwnedUnits();
SaveCurrentState();
featuredUnitPanel.Refresh(playerCollection.OwnedUnits);
collectionScreen.Refresh(playerCollection.OwnedUnits);
featuredUnitPanel.Refresh(playerCollection.OwnedUnits, playerCollection.FeaturedUnit);
collectionScreen.RefreshUnits(playerCollection.OwnedUnits);
}
private void HandleStarterConfirmed(DistroDefinition picked, IReadOnlyList<DistroDefinition> remaining)
@@ -318,8 +273,8 @@ namespace KernelPanic.UI
saveData.starterChosen = true;
SaveCurrentState();
featuredUnitPanel.Refresh(playerCollection.OwnedUnits);
collectionScreen.Refresh(playerCollection.OwnedUnits);
featuredUnitPanel.Refresh(playerCollection.OwnedUnits, playerCollection.FeaturedUnit);
collectionScreen.RefreshUnits(playerCollection.OwnedUnits);
}
private void SaveCurrentState()
@@ -347,11 +302,24 @@ namespace KernelPanic.UI
}
}
cardLoadout.WriteTo(saveData.cardLoadouts);
saveService.Save(saveData);
}
private void SaveLastRunLoadout(DistroDefinition unit, IReadOnlyList<string> cardIds)
{
saveData ??= SaveData.CreateDefault();
saveData.EnsureLists();
saveData.lastRunLoadout.distroId = unit == null ? null : unit.Id;
saveData.lastRunLoadout.cardIds.Clear();
for (int i = 0; i < cardIds.Count; i++)
{
saveData.lastRunLoadout.cardIds.Add(cardIds[i]);
}
SaveCurrentState();
}
private void RefreshStaticText()
{
appIdLabel.text = $"kernel-panic v{Application.version} - tty1";
@@ -488,6 +456,13 @@ namespace KernelPanic.UI
return;
}
if (evt.keyCode == KeyCode.Escape && IsSubScreenVisible())
{
ShowMainMenu();
evt.StopPropagation();
return;
}
if (IsRunSetupVisible())
{
if (evt.keyCode == KeyCode.UpArrow)
@@ -504,9 +479,19 @@ namespace KernelPanic.UI
return;
}
if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter)
if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter || evt.keyCode == KeyCode.B)
{
ToggleSelectedPackage();
BootSelectedPackage();
evt.StopPropagation();
return;
}
}
if (IsCollectionVisible())
{
if (evt.keyCode == KeyCode.LeftArrow || evt.keyCode == KeyCode.RightArrow || evt.keyCode == KeyCode.Tab)
{
ToggleCollectionTab();
evt.StopPropagation();
return;
}
@@ -535,7 +520,8 @@ namespace KernelPanic.UI
if (evt.keyCode == KeyCode.Tab)
{
featuredUnitPanel.SelectNext();
playerCollection.SelectNextFeatured();
featuredUnitPanel.Refresh(playerCollection.OwnedUnits, playerCollection.FeaturedUnit);
evt.StopPropagation();
return;
}
@@ -554,6 +540,78 @@ namespace KernelPanic.UI
return runSetupPanel != null && !runSetupPanel.ClassListContains(HiddenClassName);
}
private bool IsCollectionVisible()
{
return collectionPanel != null && !collectionPanel.ClassListContains(HiddenClassName);
}
private bool IsSubScreenVisible()
{
return IsRunSetupVisible() || IsCollectionVisible() ||
(gachaPanel != null && !gachaPanel.ClassListContains(HiddenClassName)) ||
(settingsPanel != null && !settingsPanel.ClassListContains(HiddenClassName));
}
private void RefreshRunSetup()
{
packageRows.Clear();
loadoutRows.Clear();
cardLoadout.ClearAll();
runSetupList?.Clear();
runSetupDetail?.Clear();
runSetupNotice = null;
if (runSetupList == null || runSetupDetail == null)
{
return;
}
if (playerCollection.OwnedUnits.Count == 0)
{
runSetupDetail.Add(new Label("no units installed") { name = "RunSetupEmptyTitle" });
runSetupDetail.Add(new Label("install a starter or summon a unit before starting a run") { name = "RunSetupEmptyHint" });
return;
}
selectedPackageIndex = Mathf.Clamp(selectedPackageIndex, 0, playerCollection.OwnedUnits.Count - 1);
for (int i = 0; i < playerCollection.OwnedUnits.Count; i++)
{
int index = i;
DistroDefinition unit = playerCollection.OwnedUnits[i];
VisualElement row = new();
row.AddToClassList("package-row");
row.RegisterCallback<PointerEnterEvent>(_ => SelectPackage(index));
row.RegisterCallback<ClickEvent>(_ => SelectPackage(index));
VisualElement summary = new();
summary.AddToClassList("package-summary");
summary.Add(new Label(">") { name = $"RunSetupMarker{index}" });
summary.ElementAt(0).AddToClassList("package-marker");
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("package-name");
name.style.color = new StyleColor(unit.AccentColor);
summary.Add(name);
Label meta = new(DistroPresentation.FormatLanguages(unit));
meta.AddToClassList("package-meta");
summary.Add(meta);
row.Add(summary);
row.Add(new Label(string.IsNullOrWhiteSpace(unit.PassiveName) ? "passive: --" : $"passive: {unit.PassiveName}")
{
name = $"RunSetupDescription{index}"
});
row.ElementAt(1).AddToClassList("package-description");
runSetupList.Add(row);
packageRows.Add(row);
}
RefreshPackageSelection();
}
private void SelectPackage(int index)
{
if (packageRows.Count == 0)
@@ -562,9 +620,242 @@ namespace KernelPanic.UI
}
selectedPackageIndex = (index + packageRows.Count) % packageRows.Count;
cardLoadout.ClearLoadout(playerCollection.OwnedUnits[selectedPackageIndex]);
runSetupNotice = null;
RefreshPackageSelection();
}
private void RefreshPackageSelection()
{
for (int i = 0; i < packageRows.Count; i++)
{
packageRows[i].EnableInClassList(SelectedClassName, i == selectedPackageIndex);
}
RenderSelectedPackageDetail();
}
private void RenderSelectedPackageDetail()
{
runSetupDetail?.Clear();
loadoutRows.Clear();
if (runSetupDetail == null || selectedPackageIndex < 0 || selectedPackageIndex >= playerCollection.OwnedUnits.Count)
{
return;
}
DistroDefinition unit = playerCollection.OwnedUnits[selectedPackageIndex];
runSetupDetail.Add(BuildRunSetupReadout(unit));
ScrollView packageScroll = new(ScrollViewMode.Vertical);
packageScroll.AddToClassList("package-scroll");
VisualElement packageList = new();
packageList.AddToClassList("package-list");
packageList.Add(new Label("equipped cards") { name = "RunSetupCardsHeader" });
packageList.ElementAt(0).AddToClassList("package-header");
IReadOnlyList<string> equippedCardIds = cardLoadout.GetEquippedCardIds(unit.Id);
if (!string.IsNullOrWhiteSpace(runSetupNotice))
{
packageList.Add(new Label(runSetupNotice) { name = "RunSetupNotice" });
packageList.ElementAt(packageList.childCount - 1).AddToClassList("package-notice");
}
if (equippedCardIds.Count < CardLoadout.MaxEquippedCards)
{
packageList.Add(new Label($"select {CardLoadout.MaxEquippedCards - equippedCardIds.Count} more card(s) before booting") { name = "RunSetupIncompleteNotice" });
packageList.ElementAt(packageList.childCount - 1).AddToClassList("package-notice");
}
bool addedCards = false;
for (int i = 0; i < unit.ExclusiveCards.Count; i++)
{
CardDefinition card = unit.ExclusiveCards[i];
if (card == null || card.IsToken)
{
continue;
}
bool equipped = ContainsCardId(equippedCardIds, card.Id);
VisualElement row = BuildCardLoadoutRow(unit, card, equipped);
packageList.Add(row);
loadoutRows.Add(row);
addedCards = true;
}
if (!addedCards)
{
packageList.Add(new Label("no compatible cards available") { name = "RunSetupCardsEmpty" });
packageList.ElementAt(packageList.childCount - 1).AddToClassList("package-empty");
}
packageScroll.Add(packageList);
runSetupDetail.Add(packageScroll);
runSetupDetail.Add(BuildBootRow(unit, equippedCardIds.Count > 0));
}
private VisualElement BuildRunSetupReadout(DistroDefinition unit)
{
VisualElement readout = new();
readout.AddToClassList("run-readout");
Label artLabel = new();
DistroArtPresenter.ConfigureArtLabel(artLabel, monospaceFont);
AsciiArtFitter artFitter = new(artLabel, monospaceFont);
VisualElement artPlaceholder = DistroArtPresenter.CreatePlaceholder();
artFitter.SetArt(DistroArtPresenter.Render(artLabel, artPlaceholder, unit));
readout.Add(artPlaceholder);
readout.Add(artLabel);
VisualElement copy = new();
copy.AddToClassList("run-readout-copy");
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("collection-detail-name");
name.style.color = new StyleColor(unit.AccentColor);
copy.Add(name);
Label languages = new(DistroPresentation.FormatLanguages(unit));
languages.AddToClassList("collection-detail-description");
copy.Add(languages);
Label stats = new($"uptime {unit.BaseUptime} · ram {unit.BaseRam} · cycles {unit.BaseCyclesPerTurn}");
stats.AddToClassList("collection-detail-muted");
copy.Add(stats);
readout.Add(copy);
return readout;
}
private static VisualElement BuildDetailLine(string key, string value)
{
VisualElement row = new();
row.AddToClassList("kv-row");
row.Add(new Label(key) { name = $"RunSetup{key}Key" });
row.ElementAt(0).AddToClassList("kv-key");
row.Add(new Label(value) { name = $"RunSetup{key}Value" });
row.ElementAt(1).AddToClassList("kv-value");
return row;
}
private VisualElement BuildCardLoadoutRow(DistroDefinition unit, CardDefinition card, bool equipped)
{
VisualElement row = new();
row.AddToClassList("package-row");
row.AddToClassList("loadout-card-row");
row.EnableInClassList("equipped", equipped);
row.RegisterCallback<ClickEvent>(_ => ToggleCardInSelectedLoadout(unit, card));
VisualElement summary = new();
summary.AddToClassList("package-summary");
summary.Add(new Label(equipped ? "[x]" : "[ ]") { name = "RunSetupCardMarker" });
summary.ElementAt(0).AddToClassList("package-marker");
string displayName = string.IsNullOrWhiteSpace(card.DisplayName) ? card.Id : card.DisplayName;
summary.Add(new Label(displayName) { name = "RunSetupCardName" });
summary.ElementAt(1).AddToClassList("package-name");
string metaText = $"{card.Language} / {card.CycleCost}c";
summary.Add(new Label(metaText) { name = "RunSetupCardMeta" });
summary.ElementAt(2).AddToClassList("package-meta");
row.Add(summary);
if (!string.IsNullOrWhiteSpace(card.Description))
{
row.Add(new Label(card.Description) { name = "RunSetupCardDescription" });
row.ElementAt(1).AddToClassList("package-description");
}
return row;
}
private void ToggleCardInSelectedLoadout(DistroDefinition unit, CardDefinition card)
{
runSetupNotice = TryToggleLoadoutCard(unit, card);
RenderSelectedPackageDetail();
}
private string TryToggleLoadoutCard(DistroDefinition unit, CardDefinition card)
{
if (unit == null || card == null)
{
return "loadout change failed";
}
IReadOnlyList<string> equippedCardIds = cardLoadout.GetEquippedCardIds(unit.Id);
bool equipped = ContainsCardId(equippedCardIds, card.Id);
CardLoadoutFailureReason reason;
bool changed = equipped
? cardLoadout.TryUnequip(unit.Id, card.Id, out reason)
: cardLoadout.TryEquip(unit.Id, card.Id, out reason);
return changed ? null : FormatLoadoutFailure(reason);
}
private static bool ContainsCardId(IReadOnlyList<string> cardIds, string cardId)
{
for (int i = 0; i < cardIds.Count; i++)
{
if (string.Equals(cardIds[i], cardId, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
private static string FormatLoadoutFailure(CardLoadoutFailureReason reason)
{
return reason switch
{
CardLoadoutFailureReason.Full => $"loadout already has {CardLoadout.MaxEquippedCards} cards",
CardLoadoutFailureReason.Duplicate => "card is already equipped",
CardLoadoutFailureReason.Token => "token cards cannot be equipped",
CardLoadoutFailureReason.NotEquipped => "card is not equipped",
CardLoadoutFailureReason.NotOwned => "card is not owned by this distro",
_ => "loadout change failed"
};
}
private VisualElement BuildBootRow(DistroDefinition unit, bool enabled)
{
VisualElement row = new();
row.AddToClassList("command-row");
row.AddToClassList("boot-command-row");
row.EnableInClassList("disabled-row", !enabled);
row.RegisterCallback<ClickEvent>(_ => BootSelectedPackage());
row.Add(new Label(">") { name = "BootCommandCursor" });
row.ElementAt(0).AddToClassList("command-cursor");
row.Add(new Label($"./boot --distro={unit.Id}") { name = "BootCommandText" });
row.ElementAt(1).AddToClassList("command-text");
row.Add(new Label("start run") { name = "BootCommandDescription" });
row.ElementAt(2).AddToClassList("command-description");
return row;
}
private void BootSelectedPackage()
{
if (selectedPackageIndex < 0 || selectedPackageIndex >= playerCollection.OwnedUnits.Count)
{
return;
}
DistroDefinition unit = playerCollection.OwnedUnits[selectedPackageIndex];
IReadOnlyList<string> equippedCardIds = cardLoadout.GetEquippedCardIds(unit.Id);
if (equippedCardIds.Count < 1)
{
runSetupNotice = "boot: no packages staged";
RenderSelectedPackageDetail();
return;
}
SaveLastRunLoadout(unit, equippedCardIds);
SceneLoader.LoadGame();
}
private void HandlePointerDown(PointerDownEvent evt)
{
root.Focus();
@@ -613,26 +904,47 @@ namespace KernelPanic.UI
private void ShowMainMenu()
{
cardLoadout.ClearAll();
runSetupNotice = null;
ShowPanel(mainMenuPanel);
root.Focus();
}
private void ShowCollection()
{
collectionScreen.Refresh(playerCollection.OwnedUnits);
ShowCollectionUnits();
ShowPanel(collectionPanel);
}
private void ShowCollectionUnits()
{
collectionShowingCards = false;
RefreshCollection();
collectionUnitsButton.EnableInClassList(SelectedClassName, true);
collectionCardsButton.EnableInClassList(SelectedClassName, false);
collectionFrame.SetTitle("$ ls ~/collection");
collectionScreen.RefreshUnits(playerCollection.OwnedUnits);
}
private void ShowCollectionCards()
{
collectionShowingCards = true;
RefreshCollection();
collectionUnitsButton.EnableInClassList(SelectedClassName, false);
collectionCardsButton.EnableInClassList(SelectedClassName, true);
DistroDefinition featuredUnit = playerCollection.FeaturedUnit;
string distroId = featuredUnit == null ? "--" : featuredUnit.Id;
collectionFrame.SetTitle($"$ dpkg -l --distro={distroId}");
collectionScreen.RefreshCards(playerCollection.FeaturedUnit);
}
private void ToggleCollectionTab()
{
if (collectionShowingCards)
{
ShowCollectionUnits();
return;
}
ShowCollectionCards();
}
private void ShowGacha()
+18 -10
View File
@@ -1,14 +1,22 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:VisualElement name="CollectionPanel" class="sub-panel hidden">
<ui:Label text="COLLECTION" class="screen-title" />
<ui:VisualElement class="collection-actions">
<ui:Button name="CollectionUnitsButton" text="units" class="terminal-button collection-action-button" />
<ui:Button name="CollectionCardsButton" text="cards" class="terminal-button collection-action-button" />
<ui:VisualElement name="CollectionPanel" class="screen-panel hidden">
<ui:VisualElement class="screen-frame">
<ui:VisualElement class="screen-frame-header">
<ui:Label class="screen-frame-title" />
</ui:VisualElement>
<ui:VisualElement class="screen-frame-content">
<ui:VisualElement class="collection-actions">
<ui:Button name="CollectionUnitsButton" text="units" class="collection-tab" />
<ui:Button name="CollectionCardsButton" text="cards" class="collection-tab" />
</ui:VisualElement>
<ui:VisualElement name="CollectionContent" class="collection-shell">
<ui:ScrollView name="CollectionList" class="collection-list" />
<ui:VisualElement name="CollectionDetail" class="collection-detail" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement class="screen-frame-footer">
<ui:Label class="screen-frame-hint" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="CollectionContent" class="collection-shell">
<ui:ScrollView name="CollectionList" class="collection-list" />
<ui:VisualElement name="CollectionDetail" class="collection-detail" />
</ui:VisualElement>
<ui:Button name="CollectionBackButton" text="Back" class="terminal-button back-button" />
</ui:VisualElement>
</ui:UXML>
+13 -5
View File
@@ -1,9 +1,17 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:VisualElement name="GachaPanel" class="sub-panel hidden">
<ui:Label text="GACHA" class="screen-title" />
<ui:VisualElement name="GachaContent" class="stub-box">
<!-- TODO: Render summon options and results here when gacha logic exists. -->
<ui:VisualElement name="GachaPanel" class="screen-panel hidden">
<ui:VisualElement class="screen-frame">
<ui:VisualElement class="screen-frame-header">
<ui:Label class="screen-frame-title" />
</ui:VisualElement>
<ui:VisualElement class="screen-frame-content">
<ui:VisualElement name="GachaContent" class="stub-box">
<!-- TODO: Render summon options and results here when gacha logic exists. -->
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement class="screen-frame-footer">
<ui:Label class="screen-frame-hint" />
</ui:VisualElement>
</ui:VisualElement>
<ui:Button name="GachaBackButton" text="Back" class="terminal-button back-button" />
</ui:VisualElement>
</ui:UXML>
+160 -39
View File
@@ -239,13 +239,6 @@ Button {
font-size: 12px;
}
.screen-title {
color: var(--kp-primary);
font-size: 24px;
-unity-font-style: bold;
margin-bottom: 20px;
}
.featured-empty {
flex-grow: 1;
flex-direction: row;
@@ -449,17 +442,53 @@ Button {
color: var(--kp-amber);
}
.sub-panel {
.screen-panel {
flex-grow: 1;
align-items: center;
min-height: 0;
background-color: var(--kp-bg-solid);
}
.screen-frame {
flex-grow: 1;
min-height: 0;
background-color: var(--kp-bg-solid);
padding: 30px 0 18px 0;
}
.screen-frame-header {
min-height: 34px;
justify-content: center;
padding: 48px;
border-bottom-width: 1px;
border-bottom-color: var(--kp-border);
}
.screen-frame-title {
color: var(--kp-muted);
font-size: 17px;
}
.screen-frame-content {
flex-grow: 1;
min-height: 0;
padding-top: 18px;
padding-bottom: 14px;
}
.screen-frame-footer {
min-height: 32px;
justify-content: center;
border-top-width: 1px;
border-top-color: var(--kp-border);
}
.screen-frame-hint {
color: var(--kp-muted);
}
.stub-scroll,
.stub-box {
width: 560px;
height: 300px;
flex-grow: 1;
min-height: 0;
border-left-width: 1px;
border-right-width: 1px;
border-top-width: 1px;
@@ -476,38 +505,55 @@ Button {
}
.collection-shell {
width: 760px;
height: 330px;
flex-grow: 1;
min-height: 0;
flex-direction: row;
}
#RunSetupContent {
flex-grow: 1;
min-height: 0;
}
.run-setup-shell {
flex-grow: 1;
min-height: 0;
flex-direction: row;
}
.collection-actions {
width: 760px;
flex-direction: row;
justify-content: flex-end;
justify-content: flex-start;
margin-bottom: 10px;
}
.collection-action-button {
width: 110px;
height: 34px;
margin-top: 0;
margin-left: 8px;
.collection-tab {
width: 92px;
height: 30px;
margin-right: 10px;
border-bottom-width: 2px;
border-bottom-color: transparent;
background-color: transparent;
color: var(--kp-muted);
}
.collection-action-button.selected {
background-color: var(--kp-primary);
color: var(--kp-bg);
.collection-tab.selected {
color: var(--kp-primary);
border-bottom-color: var(--kp-primary);
}
.collection-tab:hover {
color: var(--kp-primary);
}
.run-setup-hint {
width: 760px;
margin-top: -12px;
margin-top: 0;
margin-bottom: 12px;
}
.collection-list {
width: 300px;
width: 38%;
min-width: 330px;
margin-right: 16px;
border-left-width: 1px;
border-right-width: 1px;
@@ -522,6 +568,8 @@ Button {
.collection-detail {
flex-grow: 1;
min-width: 0;
overflow: hidden;
padding: 16px;
border-left-width: 1px;
border-right-width: 1px;
@@ -536,6 +584,7 @@ Button {
.collection-detail-readout {
flex-direction: row;
margin-top: 12px;
}
.collection-detail-values {
@@ -543,6 +592,14 @@ Button {
min-width: 0;
}
.collection-detail .kv-value {
max-width: none;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.collection-row {
min-height: 44px;
padding: 8px 10px;
@@ -574,12 +631,19 @@ Button {
.collection-detail-description {
color: var(--kp-primary);
white-space: normal;
margin-top: 14px;
margin-top: 4px;
margin-bottom: 12px;
}
.package-list {
margin-top: 18px;
min-width: 0;
flex-grow: 1;
}
.package-scroll {
flex-grow: 1;
min-height: 0;
margin-top: 18px;
}
.package-header {
@@ -633,18 +697,25 @@ Button {
flex-grow: 1;
min-width: 0;
color: var(--kp-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
-unity-text-overflow-position: end;
white-space: normal;
}
.package-meta {
min-width: 96px;
width: 92px;
min-width: 92px;
color: var(--kp-muted);
-unity-text-align: upper-right;
}
.loadout-card-row .package-name {
flex-grow: 1;
}
.loadout-card-row .package-meta {
width: 104px;
min-width: 104px;
}
.package-description {
min-width: 0;
color: var(--kp-muted);
@@ -653,6 +724,60 @@ Button {
margin-top: 2px;
}
.run-readout {
min-height: 110px;
max-height: 128px;
flex-direction: row;
}
.run-readout .ascii-art,
.run-readout .ascii-placeholder {
width: 100px;
min-width: 100px;
height: 100px;
}
.run-readout-copy {
flex-grow: 1;
min-width: 0;
padding-left: 14px;
}
.boot-command-row {
min-height: 42px;
margin-top: 12px;
border-left-color: var(--kp-primary);
}
.boot-command-row.disabled-row {
opacity: 0.45;
}
.collection-equip-row {
margin-top: 18px;
}
ScrollView .unity-scroll-view__vertical-scroller,
ScrollView .unity-scroll-view__horizontal-scroller {
width: 6px;
background-color: var(--kp-panel);
}
ScrollView .unity-scroller__low-button,
ScrollView .unity-scroller__high-button {
display: none;
}
ScrollView .unity-base-slider__tracker {
background-color: var(--kp-panel);
border-radius: 0;
}
ScrollView .unity-base-slider__dragger {
background-color: var(--kp-muted);
border-radius: 0;
}
.modal-overlay {
position: absolute;
left: 0;
@@ -762,12 +887,8 @@ Button {
color: var(--kp-bg);
}
.back-button {
width: 220px;
}
.settings-row {
width: 420px;
width: 100%;
flex-direction: row;
align-items: center;
justify-content: space-between;
+14 -5
View File
@@ -1,5 +1,6 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<Style src="MainMenu.uss" />
<ui:Template name="ScreenFrame" src="ScreenFrame.uxml" />
<ui:Template name="CollectionScreen" src="CollectionScreen.uxml" />
<ui:Template name="GachaScreen" src="GachaScreen.uxml" />
<ui:Template name="SettingsScreen" src="SettingsScreen.uxml" />
@@ -124,14 +125,22 @@
</ui:VisualElement>
<ui:Instance template="CollectionScreen" />
<ui:VisualElement name="RunSetupPanel" class="sub-panel hidden">
<ui:Label text="NEW RUN" class="screen-title" />
<ui:Label text="choose 4 distro cards before booting a run" class="collection-detail-muted run-setup-hint" />
<ui:VisualElement name="RunSetupContent" class="collection-shell">
<ui:VisualElement name="RunSetupPanel" class="screen-panel hidden">
<ui:VisualElement class="screen-frame">
<ui:VisualElement class="screen-frame-header">
<ui:Label class="screen-frame-title" />
</ui:VisualElement>
<ui:VisualElement class="screen-frame-content">
<ui:Label text="choose distro packages before booting a run" class="collection-detail-muted run-setup-hint" />
<ui:VisualElement name="RunSetupContent" class="run-setup-shell">
<ui:ScrollView name="RunSetupList" class="collection-list" />
<ui:VisualElement name="RunSetupDetail" class="collection-detail" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement class="screen-frame-footer">
<ui:Label class="screen-frame-hint" />
</ui:VisualElement>
</ui:VisualElement>
<ui:Button name="RunSetupBackButton" text="Back" class="terminal-button back-button" />
</ui:VisualElement>
<ui:Instance template="GachaScreen" />
<ui:Instance template="SettingsScreen" />
+14 -6
View File
@@ -1,10 +1,18 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:VisualElement name="SettingsPanel" class="sub-panel hidden">
<ui:Label text="SETTINGS" class="screen-title" />
<ui:VisualElement class="settings-row disabled-row">
<ui:Label text="Audio" class="settings-label" />
<ui:Toggle name="AudioToggle" text="TODO" enabled="false" class="settings-toggle" />
<ui:VisualElement name="SettingsPanel" class="screen-panel hidden">
<ui:VisualElement class="screen-frame">
<ui:VisualElement class="screen-frame-header">
<ui:Label class="screen-frame-title" />
</ui:VisualElement>
<ui:VisualElement class="screen-frame-content">
<ui:VisualElement class="settings-row disabled-row">
<ui:Label text="Audio" class="settings-label" />
<ui:Toggle name="AudioToggle" text="TODO" enabled="false" class="settings-toggle" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement class="screen-frame-footer">
<ui:Label class="screen-frame-hint" />
</ui:VisualElement>
</ui:VisualElement>
<ui:Button name="SettingsBackButton" text="Back" class="terminal-button back-button" />
</ui:VisualElement>
</ui:UXML>