Implement many UX improvements, packages and their assets and a UI overhaul in collection
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -329,10 +329,10 @@ namespace KernelPanic.UI
|
||||
|
||||
waveLabel = AddStatusReadout(bar, "wave", "--", false);
|
||||
phaseLabel = AddStatusReadout(bar, "phase", "--", true);
|
||||
bitsLabel = AddStatusReadout(bar, "bits", "0", false);
|
||||
entropyLabel = AddStatusReadout(bar, "entropy", "0", false);
|
||||
bandwidthLabel = AddStatusReadout(bar, "bandwidth", "0", false);
|
||||
rootCreditsLabel = AddStatusReadout(bar, "root credits", "TODO", false);
|
||||
bitsLabel = AddStatusReadout(bar, "Bits", "0", false);
|
||||
entropyLabel = AddStatusReadout(bar, "Entropy", "0", false);
|
||||
bandwidthLabel = AddStatusReadout(bar, "Bandwidth", "0", false);
|
||||
rootCreditsLabel = AddStatusReadout(bar, "Root Credits", "0", false);
|
||||
|
||||
VisualElement spacer = new();
|
||||
spacer.AddToClassList("status-spacer");
|
||||
@@ -405,8 +405,8 @@ namespace KernelPanic.UI
|
||||
phaseLabel.text = PhaseText(combatManager.CurrentPhase);
|
||||
bitsLabel.text = runManager.Bits.ToString();
|
||||
entropyLabel.text = FormatWalletWithAccrual(data.entropyBalance, runManager.AccruedEntropy);
|
||||
bandwidthLabel.text = FormatWalletWithAccrual(data.standardPullCurrency, runManager.AccruedBandwidth);
|
||||
rootCreditsLabel.text = "TODO";
|
||||
bandwidthLabel.text = FormatWalletWithAccrual(data.bandwidthBalance, runManager.AccruedBandwidth);
|
||||
rootCreditsLabel.text = data.rootCredits.ToString();
|
||||
seedLabel.text = $"seed {config?.RunSeed ?? 0}";
|
||||
}
|
||||
|
||||
@@ -575,8 +575,9 @@ namespace KernelPanic.UI
|
||||
}
|
||||
|
||||
SaveData data = saveService.Load();
|
||||
data.standardPullCurrency = Math.Max(0, data.standardPullCurrency) + bandwidth;
|
||||
data.bandwidthBalance = Math.Max(0, data.bandwidthBalance) + bandwidth;
|
||||
data.entropyBalance = Math.Max(0, data.entropyBalance) + entropy;
|
||||
data.RecordRunStats(runManager.CurrentConfig?.Distro?.Id, runManager.CurrentWaveNumber);
|
||||
saveService.Save(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,16 @@ namespace KernelPanic.UI
|
||||
private FontAsset _monospaceFont;
|
||||
private AsciiArtFitter _asciiFitter;
|
||||
private IReadOnlyList<DistroDefinition> _units = Array.Empty<DistroDefinition>();
|
||||
private Func<DistroDefinition, int> _getBestWave;
|
||||
private Action<DistroDefinition> _activateUnit;
|
||||
private DistroDefinition _currentUnit;
|
||||
private int _selectedIndex;
|
||||
|
||||
public void Bind(VisualElement root, FontAsset artFont)
|
||||
public void Bind(VisualElement root, FontAsset artFont, Func<DistroDefinition, int> getBestWave = null, Action<DistroDefinition> activateUnit = null)
|
||||
{
|
||||
_monospaceFont = artFont;
|
||||
_getBestWave = getBestWave;
|
||||
_activateUnit = activateUnit;
|
||||
_panel = root.Q<VisualElement>("FeaturedUnitPanel");
|
||||
_titleLabel = root.Q<Label>("FeaturedUnitTitle");
|
||||
_asciiLabel = root.Q<Label>("FeaturedUnitAscii");
|
||||
@@ -52,6 +57,7 @@ namespace KernelPanic.UI
|
||||
_asciiPlaceholder = DistroArtPresenter.CreatePlaceholder();
|
||||
_asciiPlaceholder.AddToClassList("hidden");
|
||||
_populatedState.Insert(0, _asciiPlaceholder);
|
||||
_panel?.RegisterCallback<ClickEvent>(_ => ActivateCurrentUnit());
|
||||
}
|
||||
|
||||
public void Refresh(IReadOnlyList<DistroDefinition> ownedUnits)
|
||||
@@ -114,6 +120,7 @@ namespace KernelPanic.UI
|
||||
{
|
||||
_populatedState.AddToClassList("hidden");
|
||||
_emptyState.RemoveFromClassList("hidden");
|
||||
_currentUnit = null;
|
||||
|
||||
_titleLabel.text = "[ neofetch ]";
|
||||
_emptyTitleLabel.text = "no units installed";
|
||||
@@ -125,16 +132,26 @@ namespace KernelPanic.UI
|
||||
{
|
||||
_populatedState.RemoveFromClassList("hidden");
|
||||
_emptyState.AddToClassList("hidden");
|
||||
_currentUnit = unit;
|
||||
|
||||
_titleLabel.text = "[ neofetch ]";
|
||||
_asciiFitter.SetArt(DistroArtPresenter.Render(_asciiLabel, _asciiPlaceholder, unit));
|
||||
_unitNameLabel.text = DistroPresentation.DisplayName(unit);
|
||||
_languagesLabel.text = DistroPresentation.FormatLanguages(unit);
|
||||
_passiveLabel.text = unit.Passive == null || string.IsNullOrWhiteSpace(unit.Passive.Name) ? "--" : unit.Passive.Name;
|
||||
_bestWaveLabel.text = "--"; // TODO: Bind best-wave stats from SaveService when stats exist.
|
||||
int bestWave = Math.Max(0, _getBestWave?.Invoke(unit) ?? 0);
|
||||
_bestWaveLabel.text = bestWave > 0 ? bestWave.ToString() : "--";
|
||||
SetAccent(ColorUtility.ToHtmlStringRGB(unit.AccentColor));
|
||||
}
|
||||
|
||||
public void ActivateCurrentUnit()
|
||||
{
|
||||
if (_currentUnit != null)
|
||||
{
|
||||
_activateUnit?.Invoke(_currentUnit);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAccent(string htmlColor)
|
||||
{
|
||||
string color = $"#{htmlColor}";
|
||||
|
||||
@@ -161,13 +161,14 @@ namespace KernelPanic.UI
|
||||
title.AddToClassList("gacha-detail-title");
|
||||
_bannerDetail.Add(title);
|
||||
|
||||
_bannerDetail.Add(BuildInfoLine("entropy", _wallet == null ? "--" : _wallet.Balance.ToString()));
|
||||
_bannerDetail.Add(BuildInfoLine("Entropy", _wallet == null ? "--" : _wallet.Balance.ToString()));
|
||||
_bannerDetail.Add(BuildInfoLine("Commits", _gachaService.PullTokens.ToString()));
|
||||
_bannerDetail.Add(BuildInfoLine("pulls", $"{state.totalPulls}/{GachaService.BeginnerMaxPulls}"));
|
||||
_bannerDetail.Add(BuildInfoLine("4-star pity", $"{state.pityCounter}/{GachaService.FourStarHardPity}"));
|
||||
_bannerDetail.Add(BuildInfoLine("ten pull", $"{GachaService.BeginnerTenPullCost} Commits for 10 pulls"));
|
||||
_bannerDetail.Add(BuildInfoLine("cost", $"1 Commit / {GachaService.EntropyPerCommit} Entropy per pull"));
|
||||
_bannerDetail.Add(BuildInfoLine("guarantees", FormatBeginnerGuarantees()));
|
||||
|
||||
Label rules = new("Base result is a 3-star equipment cache. A 4-star equipment cache or starter distro can appear early, with one 4-star+ result guaranteed every 10 pulls.");
|
||||
Label rules = new("Base result is a 3-star package cache. A 4-star package cache or starter distro can appear early, with one 4-star+ result guaranteed every 10 pulls.");
|
||||
rules.AddToClassList("gacha-rules");
|
||||
_bannerDetail.Add(rules);
|
||||
|
||||
@@ -185,7 +186,7 @@ namespace KernelPanic.UI
|
||||
|
||||
Button tenButton = new(() => RequestPullSelectedBanner(10))
|
||||
{
|
||||
text = $"git pull --ten\n8x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||
text = $"git pull --ten\n10x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||
};
|
||||
tenButton.AddToClassList("terminal-button");
|
||||
tenButton.AddToClassList("gacha-action-button");
|
||||
@@ -214,10 +215,7 @@ namespace KernelPanic.UI
|
||||
title.AddToClassList("gacha-detail-title");
|
||||
_bannerDetail.Add(title);
|
||||
|
||||
string currency = bannerId == GachaService.StandardBannerId
|
||||
? GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)
|
||||
: GachaService.FormatCurrencyName(GachaCurrencyType.LimitedPull);
|
||||
_bannerDetail.Add(BuildInfoLine("pull currency", currency));
|
||||
_bannerDetail.Add(BuildInfoLine("pull currency", $"Commits or Entropy ({GachaService.EntropyPerCommit}:1)"));
|
||||
_bannerDetail.Add(BuildInfoLine("status", "not implemented yet"));
|
||||
_bannerDetail.Add(BuildInfoLine("pity", "own counter, 10-pull 4-star+ guarantee"));
|
||||
_bannerDetail.Add(new Label("Use the beginner implementation as the template: define the banner pool, persist a separate GachaBannerState, then route single/ten pulls through GachaService.") { name = "FutureBannerHint" });
|
||||
@@ -250,7 +248,8 @@ namespace KernelPanic.UI
|
||||
return;
|
||||
}
|
||||
|
||||
GachaPullResult result = _gachaService.PerformBeginnerPull(pullCount, _wallet, entropyTokenCount);
|
||||
PullPaymentSource source = entropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits;
|
||||
GachaPullResult result = _gachaService.PerformBeginnerPull(pullCount, _wallet, source);
|
||||
if (!result.Success)
|
||||
{
|
||||
_resultBannerId = bannerId;
|
||||
@@ -262,11 +261,9 @@ namespace KernelPanic.UI
|
||||
}
|
||||
|
||||
List<string> header = new();
|
||||
header.Add($"git pull complete: spent {result.CurrencySpent} {GachaService.FormatCurrencyName(result.CurrencyType)}");
|
||||
if (result.EntropySpent > 0)
|
||||
{
|
||||
header.Add($"entropy fallback: spent {result.EntropySpent} entropy");
|
||||
}
|
||||
header.Add(result.EntropySpent > 0
|
||||
? $"git pull complete: spent {result.EntropySpent} Entropy"
|
||||
: $"git pull complete: spent {result.CurrencySpent} {GachaService.FormatCurrencyName(result.CurrencyType)}");
|
||||
|
||||
List<DistroDefinition> distroRewards = new();
|
||||
for (int i = 0; i < result.Rewards.Count; i++)
|
||||
@@ -419,7 +416,7 @@ namespace KernelPanic.UI
|
||||
|
||||
private static string FormatRewardDisplayName(GachaReward reward)
|
||||
{
|
||||
if (reward.RewardType != GachaRewardType.Equipment || string.IsNullOrWhiteSpace(reward.DisplayName))
|
||||
if (reward.RewardType != GachaRewardType.Package || string.IsNullOrWhiteSpace(reward.DisplayName))
|
||||
{
|
||||
return reward.DisplayName;
|
||||
}
|
||||
@@ -450,7 +447,8 @@ namespace KernelPanic.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_gachaService.CanCoverMissingPullTokensWithEntropy(_wallet, missingTokens))
|
||||
int entropyCost = cost * GachaService.EntropyPerCommit;
|
||||
if (_wallet == null || _wallet.Balance < entropyCost)
|
||||
{
|
||||
if (_gachaService.RootCredits > 0)
|
||||
{
|
||||
@@ -459,13 +457,13 @@ namespace KernelPanic.UI
|
||||
}
|
||||
|
||||
_resultBannerId = bannerId;
|
||||
_resultText = $"git pull failed: need {missingTokens} {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)} or {missingTokens * GachaService.EntropyPerPullToken} entropy";
|
||||
_resultText = $"git pull failed: need {cost} {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)} or {entropyCost} Entropy";
|
||||
RenderSelectedBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
_pendingPullCount = pullCount;
|
||||
_pendingMissingTokens = missingTokens;
|
||||
_pendingMissingTokens = cost;
|
||||
_resultBannerId = bannerId;
|
||||
_resultText = null;
|
||||
RenderSelectedBanner();
|
||||
@@ -476,8 +474,8 @@ namespace KernelPanic.UI
|
||||
VisualElement prompt = new();
|
||||
prompt.AddToClassList("gacha-entropy-prompt");
|
||||
|
||||
int entropyCost = _pendingMissingTokens * GachaService.EntropyPerPullToken;
|
||||
Label copy = new($"missing {_pendingMissingTokens} Commits. spend {entropyCost} entropy to complete git pull?");
|
||||
int entropyCost = _pendingMissingTokens * GachaService.EntropyPerCommit;
|
||||
Label copy = new($"spend {entropyCost} Entropy instead of {_pendingMissingTokens} Commits?");
|
||||
copy.AddToClassList("gacha-result");
|
||||
prompt.Add(copy);
|
||||
|
||||
@@ -499,9 +497,9 @@ namespace KernelPanic.UI
|
||||
Button confirm = new(() =>
|
||||
{
|
||||
int pullCount = _pendingPullCount;
|
||||
int missingTokens = _pendingMissingTokens;
|
||||
int entropyPulls = _pendingMissingTokens;
|
||||
ClearEntropyPrompt();
|
||||
PullSelectedBanner(pullCount, missingTokens);
|
||||
PullSelectedBanner(pullCount, entropyPulls);
|
||||
})
|
||||
{
|
||||
text = $"git pull --use-entropy={entropyCost}"
|
||||
@@ -526,9 +524,10 @@ namespace KernelPanic.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
int missingTokens = _gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, _gachaService.GetBeginnerPullCost(pullCount));
|
||||
int cost = _gachaService.GetBeginnerPullCost(pullCount);
|
||||
int missingTokens = _gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, cost);
|
||||
return missingTokens > 0 &&
|
||||
(_gachaService.CanCoverMissingPullTokensWithEntropy(_wallet, missingTokens) ||
|
||||
((_wallet != null && _wallet.Balance >= cost * GachaService.EntropyPerCommit) ||
|
||||
_gachaService.RootCredits > 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,8 +173,8 @@ namespace KernelPanic.UI
|
||||
commandLabel.text = pending.PullCount == 10 ? "git pull --ten" : "git pull --single";
|
||||
int pullCost = pending.PullCount == 10 ? GachaService.BeginnerTenPullCost : GachaService.BeginnerSinglePullCost;
|
||||
costLabel.text = pending.EntropyTokenCount > 0
|
||||
? $"cost: {pullCost} Commits / entropy fallback: {pending.EntropyTokenCount * GachaService.EntropyPerPullToken}"
|
||||
: $"cost: {pullCost} Commits";
|
||||
? $"cost: {pending.EntropyTokenCount * GachaService.EntropyPerCommit} Entropy"
|
||||
: $"cost: {pullCost} Commits / {pullCost * GachaService.EntropyPerCommit} Entropy";
|
||||
flourishLabel.text = "$ fetch-pack | verify | unpack";
|
||||
|
||||
CompletedGachaPull completed = ResolvePull(pending);
|
||||
@@ -248,13 +248,13 @@ namespace KernelPanic.UI
|
||||
EntropyWallet wallet = new();
|
||||
wallet.SetBalance(saveData.entropyBalance);
|
||||
|
||||
PlayerCollection collection = BuildCollection(saveData, pending.DistroDatabase);
|
||||
PlayerCollection collection = BuildCollection(saveData, pending.DistroDatabase, pending.PackageDatabase);
|
||||
GachaService gacha = new();
|
||||
RestoreBannerPool(gacha, saveData, pending.DistroDatabase);
|
||||
gacha.LoadProgress(saveData);
|
||||
|
||||
GachaPullResult result = pending.BannerId == GachaService.BeginnerBannerId
|
||||
? gacha.PerformBeginnerPull(pending.PullCount, wallet, pending.EntropyTokenCount)
|
||||
? gacha.PerformBeginnerPull(pending.PullCount, wallet, pending.EntropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits)
|
||||
: GachaPullResult.Failed(pending.BannerId, "remote not implemented yet");
|
||||
|
||||
if (!result.Success)
|
||||
@@ -264,12 +264,10 @@ namespace KernelPanic.UI
|
||||
|
||||
List<string> header = new()
|
||||
{
|
||||
$"spent {result.CurrencySpent} {GachaService.FormatCurrencyName(result.CurrencyType)}"
|
||||
result.EntropySpent > 0
|
||||
? $"spent {result.EntropySpent} Entropy"
|
||||
: $"spent {result.CurrencySpent} {GachaService.FormatCurrencyName(result.CurrencyType)}"
|
||||
};
|
||||
if (result.EntropySpent > 0)
|
||||
{
|
||||
header.Add($"spent {result.EntropySpent} entropy");
|
||||
}
|
||||
|
||||
List<DistroDefinition> distroRewards = new();
|
||||
for (int i = 0; i < result.Rewards.Count; i++)
|
||||
@@ -296,7 +294,27 @@ namespace KernelPanic.UI
|
||||
PullOutcomeKind outcomeKind = outcome?.Kind ?? PullOutcomeKind.Invalid;
|
||||
int merges = outcome?.MergesAwarded ?? 0;
|
||||
IReadOnlyList<Language> languages = outcome?.LanguagesNewlyUnlocked ?? Array.Empty<Language>();
|
||||
completedRewards.Add(new CompletedGachaReward(i + 1, reward.StarRating, reward.DisplayName, reward.RewardType, outcomeKind, merges, languages, reward.Guaranteed, reward.PityTriggered));
|
||||
string displayName = reward.DisplayName;
|
||||
if (reward.RewardType == GachaRewardType.Package)
|
||||
{
|
||||
PackageDefinition package = GrantRandomPackageByRarity(pending.PackageDatabase, collection, saveData, reward.StarRating, out bool duplicatePackage);
|
||||
if (package != null)
|
||||
{
|
||||
displayName = string.IsNullOrWhiteSpace(package.DisplayName) ? package.Id : package.DisplayName;
|
||||
if (duplicatePackage)
|
||||
{
|
||||
outcomeKind = PullOutcomeKind.Dupe;
|
||||
merges = Mathf.Max(1, GachaTuning.MergesPerDupe);
|
||||
saveData.packageMerges += merges;
|
||||
}
|
||||
else
|
||||
{
|
||||
outcomeKind = PullOutcomeKind.Granted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
completedRewards.Add(new CompletedGachaReward(i + 1, reward.StarRating, displayName, reward.RewardType, outcomeKind, merges, languages, reward.Guaranteed, reward.PityTriggered));
|
||||
}
|
||||
|
||||
WriteState(saveService, saveData, wallet, collection, gacha);
|
||||
@@ -424,7 +442,7 @@ namespace KernelPanic.UI
|
||||
return string.Join(", ", names);
|
||||
}
|
||||
|
||||
private static PlayerCollection BuildCollection(SaveData saveData, DistroDatabase distroDatabase)
|
||||
private static PlayerCollection BuildCollection(SaveData saveData, DistroDatabase distroDatabase, PackageDatabase packageDatabase)
|
||||
{
|
||||
PlayerCollection collection = new();
|
||||
for (int i = 0; i < saveData.ownedUnits.Count; i++)
|
||||
@@ -437,9 +455,46 @@ namespace KernelPanic.UI
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < saveData.ownedPackages.Count; i++)
|
||||
{
|
||||
OwnedPackageSaveEntry entry = saveData.ownedPackages[i];
|
||||
PackageDefinition package = packageDatabase == null ? null : packageDatabase.FindById(entry?.id);
|
||||
if (package != null)
|
||||
{
|
||||
collection.AddPackageSilently(package, entry.upgradeLevel);
|
||||
}
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
private static PackageDefinition GrantRandomPackageByRarity(PackageDatabase packageDatabase, PlayerCollection collection, SaveData saveData, int rarity, out bool duplicate)
|
||||
{
|
||||
duplicate = false;
|
||||
int count = packageDatabase == null ? 0 : packageDatabase.CountByRarity(rarity);
|
||||
if (count <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = UnityEngine.Random.Range(0, count);
|
||||
PackageDefinition package = packageDatabase.FindByRarity(rarity, index);
|
||||
if (package == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
duplicate = collection.IsPackageOwned(package.Id) || saveData.ownedPackageIds.Exists(id => string.Equals(id, package.Id, StringComparison.OrdinalIgnoreCase));
|
||||
if (!duplicate)
|
||||
{
|
||||
collection.AddPackageSilently(package);
|
||||
saveData.ownedPackages.Add(new OwnedPackageSaveEntry { id = package.Id, upgradeLevel = 0 });
|
||||
saveData.ownedPackageIds.Add(package.Id);
|
||||
}
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
private static void RestoreBannerPool(GachaService gacha, SaveData saveData, DistroDatabase distroDatabase)
|
||||
{
|
||||
for (int i = 0; i < saveData.bannerPoolIds.Count; i++)
|
||||
@@ -475,6 +530,8 @@ namespace KernelPanic.UI
|
||||
|
||||
saveData.entropyBalance = wallet.Balance;
|
||||
saveData.ownedUnits.Clear();
|
||||
saveData.ownedPackages.Clear();
|
||||
saveData.ownedPackageIds.Clear();
|
||||
saveData.ownedUnitIds.Clear();
|
||||
saveData.bannerPoolIds.Clear();
|
||||
gacha.WriteProgress(saveData);
|
||||
@@ -493,6 +550,16 @@ namespace KernelPanic.UI
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < collection.OwnedPackageInstances.Count; i++)
|
||||
{
|
||||
OwnedPackageInstance package = collection.OwnedPackageInstances[i];
|
||||
if (package != null && !string.IsNullOrWhiteSpace(package.PackageId))
|
||||
{
|
||||
saveData.ownedPackages.Add(new OwnedPackageSaveEntry { id = package.PackageId, upgradeLevel = package.UpgradeLevel });
|
||||
saveData.ownedPackageIds.Add(package.PackageId);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < gacha.BannerPool.Count; i++)
|
||||
{
|
||||
DistroDefinition unit = gacha.BannerPool[i];
|
||||
|
||||
@@ -89,6 +89,7 @@ namespace KernelPanic.UI
|
||||
[SerializeField] private string motdBody = "unstable userspace detected; keep a rollback shell open.";
|
||||
[SerializeField] private DistroDatabase distroDatabase;
|
||||
[SerializeField] private CardDatabase cardDatabase;
|
||||
[SerializeField] private PackageDatabase packageDatabase;
|
||||
[SerializeField] private LanguageDeckDatabase languageDeckDatabase;
|
||||
[SerializeField] private FeaturedUnitPanel featuredUnitPanel = new();
|
||||
[SerializeField] private CollectionScreenController collectionScreen = new();
|
||||
@@ -149,6 +150,7 @@ namespace KernelPanic.UI
|
||||
private GachaService _gachaService;
|
||||
private PlayerCollection _playerCollection;
|
||||
private CardLoadout _cardLoadout;
|
||||
private PackageLoadout _packageLoadout;
|
||||
private BackgroundLogRingBuffer _backgroundLog;
|
||||
private IEventBannerSource _eventBannerSource;
|
||||
private int _selectedCommandIndex;
|
||||
@@ -189,8 +191,8 @@ namespace KernelPanic.UI
|
||||
BindScreenFrames();
|
||||
starterSelection.Bind(_root, distroDatabase, HandleStarterConfirmed);
|
||||
FontAsset resolvedFont = ResolveMonospaceFont();
|
||||
featuredUnitPanel.Bind(_root, resolvedFont);
|
||||
collectionScreen.Bind(_root, resolvedFont, languageDeckDatabase, cardDatabase, _playerCollection, GetMergesBalance, UpgradeCollectionUnit);
|
||||
featuredUnitPanel.Bind(_root, resolvedFont, GetBestWaveForUnit, OpenFeaturedUnitDetail);
|
||||
collectionScreen.Bind(_root, resolvedFont, languageDeckDatabase, cardDatabase, _playerCollection, GetMergesBalance, UpgradeCollectionUnit, packageDatabase, _packageLoadout, SaveCurrentState, () => _saveData, UpgradeCollectionPackage, ScrapCollectionPackage);
|
||||
gachaScreen.Bind(_root, distroDatabase, resolvedFont, _gachaService, _playerCollection, _wallet, ResolvePulledDistros, HandleMetaStateChanged, OpenRootCreditExchange, StartGachaPullCutscene);
|
||||
LoadMetaState();
|
||||
_playerCollection.Changed += HandleMetaStateChanged;
|
||||
@@ -205,6 +207,7 @@ namespace KernelPanic.UI
|
||||
_gachaService = new GachaService();
|
||||
_playerCollection = new PlayerCollection();
|
||||
_cardLoadout = new CardLoadout(_playerCollection.OwnedUnits);
|
||||
_packageLoadout = new PackageLoadout(_playerCollection, packageDatabase);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
@@ -216,7 +219,7 @@ namespace KernelPanic.UI
|
||||
RefreshStaticText();
|
||||
RefreshCurrencyReadouts();
|
||||
RefreshEventBanner();
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, _playerCollection.FeaturedUnit);
|
||||
RefreshFeaturedUnitPanel();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
gachaScreen.Refresh();
|
||||
SelectCommand(0);
|
||||
@@ -603,7 +606,7 @@ namespace KernelPanic.UI
|
||||
|
||||
if (_rootCreditExchangePreviewLabel != null)
|
||||
{
|
||||
_rootCreditExchangePreviewLabel.text = $"+{amount} entropy";
|
||||
_rootCreditExchangePreviewLabel.text = $"+{amount * GachaService.RootCreditsToEntropy} Entropy";
|
||||
}
|
||||
|
||||
int max = _gachaService.RootCredits;
|
||||
@@ -665,6 +668,18 @@ namespace KernelPanic.UI
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _saveData.ownedPackages.Count; i++)
|
||||
{
|
||||
OwnedPackageSaveEntry entry = _saveData.ownedPackages[i];
|
||||
PackageDefinition package = packageDatabase == null ? null : packageDatabase.FindById(entry?.id);
|
||||
if (package != null)
|
||||
{
|
||||
_playerCollection.AddPackageSilently(package, entry.upgradeLevel);
|
||||
}
|
||||
}
|
||||
|
||||
LoadPackageLoadoutsFromSave();
|
||||
|
||||
for (int i = 0; i < _saveData.bannerPoolIds.Count; i++)
|
||||
{
|
||||
DistroDefinition unit = ResolveSavedDistro(_saveData.bannerPoolIds[i]);
|
||||
@@ -718,12 +733,51 @@ namespace KernelPanic.UI
|
||||
private void HandleMetaStateChanged()
|
||||
{
|
||||
SaveCurrentState();
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, _playerCollection.FeaturedUnit);
|
||||
RefreshFeaturedUnitPanel();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
gachaScreen.Refresh();
|
||||
RefreshCurrencyReadouts();
|
||||
}
|
||||
|
||||
private void RefreshFeaturedUnitPanel()
|
||||
{
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, ResolveFeaturedUnitForNeofetch());
|
||||
}
|
||||
|
||||
private DistroDefinition ResolveFeaturedUnitForNeofetch()
|
||||
{
|
||||
DistroDefinition lastRun = string.IsNullOrWhiteSpace(_saveData?.lastRunDistroId) ? null : ResolveSavedDistro(_saveData.lastRunDistroId);
|
||||
if (lastRun != null && _playerCollection.IsOwned(lastRun.Id))
|
||||
{
|
||||
return lastRun;
|
||||
}
|
||||
|
||||
return _playerCollection.FeaturedUnit;
|
||||
}
|
||||
|
||||
private int GetBestWaveForUnit(DistroDefinition unit)
|
||||
{
|
||||
_saveData ??= SaveData.CreateDefault();
|
||||
_saveData.EnsureLists();
|
||||
return unit == null ? 0 : _saveData.GetBestWave(unit.Id);
|
||||
}
|
||||
|
||||
private void OpenFeaturedUnitDetail(DistroDefinition unit)
|
||||
{
|
||||
if (unit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_collectionShowingLanguages = false;
|
||||
_collectionUnitsButton.EnableInClassList(SelectedClassName, true);
|
||||
_collectionLanguagesButton.EnableInClassList(SelectedClassName, false);
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
collectionScreen.ShowUnitDetail(unit, false);
|
||||
SyncCollectionFrame();
|
||||
ShowScreen(MenuScreen.Collection);
|
||||
}
|
||||
|
||||
private void HandleStarterConfirmed(DistroDefinition picked, IReadOnlyList<DistroDefinition> remaining)
|
||||
{
|
||||
_playerCollection.Add(picked, 1);
|
||||
@@ -731,7 +785,7 @@ namespace KernelPanic.UI
|
||||
_gachaService.SetBeginnerGuaranteedDistros(remaining);
|
||||
_saveData.starterChosen = true;
|
||||
SaveCurrentState();
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, _playerCollection.FeaturedUnit);
|
||||
RefreshFeaturedUnitPanel();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
gachaScreen.Refresh();
|
||||
}
|
||||
@@ -752,6 +806,9 @@ namespace KernelPanic.UI
|
||||
|
||||
_saveData.entropyBalance = _wallet == null ? 0 : _wallet.Balance;
|
||||
_saveData.ownedUnits.Clear();
|
||||
_saveData.ownedPackages.Clear();
|
||||
_saveData.ownedPackageIds.Clear();
|
||||
_saveData.packageLoadouts.Clear();
|
||||
_saveData.ownedUnitIds.Clear();
|
||||
_saveData.bannerPoolIds.Clear();
|
||||
_gachaService.WriteProgress(_saveData);
|
||||
@@ -770,6 +827,22 @@ namespace KernelPanic.UI
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _playerCollection.OwnedPackageInstances.Count; i++)
|
||||
{
|
||||
OwnedPackageInstance package = _playerCollection.OwnedPackageInstances[i];
|
||||
if (package != null && !string.IsNullOrWhiteSpace(package.PackageId))
|
||||
{
|
||||
_saveData.ownedPackages.Add(new OwnedPackageSaveEntry
|
||||
{
|
||||
id = package.PackageId,
|
||||
upgradeLevel = package.UpgradeLevel
|
||||
});
|
||||
_saveData.ownedPackageIds.Add(package.PackageId);
|
||||
}
|
||||
}
|
||||
|
||||
SavePackageLoadouts();
|
||||
|
||||
for (int i = 0; i < _gachaService.BannerPool.Count; i++)
|
||||
{
|
||||
DistroDefinition unit = _gachaService.BannerPool[i];
|
||||
@@ -791,7 +864,7 @@ namespace KernelPanic.UI
|
||||
private void StartGachaPullCutscene(string bannerId, int pullCount, int entropyTokenCount)
|
||||
{
|
||||
SaveCurrentState();
|
||||
GachaPullContext.SetPending(bannerId, pullCount, entropyTokenCount, distroDatabase, _playerCollection.FeaturedUnit?.Id);
|
||||
GachaPullContext.SetPending(bannerId, pullCount, entropyTokenCount, distroDatabase, packageDatabase, _playerCollection.FeaturedUnit?.Id);
|
||||
SceneLoader.LoadGambling(_root);
|
||||
}
|
||||
|
||||
@@ -814,7 +887,33 @@ namespace KernelPanic.UI
|
||||
if (result.Success)
|
||||
{
|
||||
SaveCurrentState();
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, _playerCollection.FeaturedUnit);
|
||||
RefreshFeaturedUnitPanel();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
RefreshCurrencyReadouts();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private PackageUpgradeResult UpgradeCollectionPackage(OwnedPackageInstance package)
|
||||
{
|
||||
PackageUpgradeResult result = PackageUpgrader.TryUpgrade(package, _saveData);
|
||||
if (result.Success)
|
||||
{
|
||||
SaveCurrentState();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
RefreshCurrencyReadouts();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private PackageScrapResult ScrapCollectionPackage(OwnedPackageInstance package)
|
||||
{
|
||||
PackageScrapResult result = PackageScrapper.Scrap(_playerCollection, _packageLoadout, _saveData, package?.PackageId);
|
||||
if (result.Success)
|
||||
{
|
||||
SaveCurrentState();
|
||||
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||
RefreshCurrencyReadouts();
|
||||
}
|
||||
@@ -837,6 +936,77 @@ namespace KernelPanic.UI
|
||||
SaveCurrentState();
|
||||
}
|
||||
|
||||
private void LoadPackageLoadoutsFromSave()
|
||||
{
|
||||
_packageLoadout?.Clear();
|
||||
if (_saveData?.packageLoadouts == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _saveData.packageLoadouts.Count; i++)
|
||||
{
|
||||
PackageLoadoutSaveEntry entry = _saveData.packageLoadouts[i];
|
||||
if (entry == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entry.EnsureLists();
|
||||
_packageLoadout?.Load(entry.distroId, entry.slots);
|
||||
}
|
||||
}
|
||||
|
||||
private void SavePackageLoadouts()
|
||||
{
|
||||
if (_saveData == null || _packageLoadout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int unitIndex = 0; unitIndex < _playerCollection.OwnedUnits.Count; unitIndex++)
|
||||
{
|
||||
DistroDefinition unit = _playerCollection.OwnedUnits[unitIndex];
|
||||
if (unit == null || string.IsNullOrWhiteSpace(unit.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IReadOnlyDictionary<PackageSlot, string> equipped = _packageLoadout.GetEquippedPackageIds(unit.Id);
|
||||
if (equipped.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PackageLoadoutSaveEntry entry = new()
|
||||
{
|
||||
distroId = unit.Id
|
||||
};
|
||||
|
||||
AddPackageSlotSave(entry, equipped, PackageSlot.Kernel);
|
||||
AddPackageSlotSave(entry, equipped, PackageSlot.Runtime);
|
||||
AddPackageSlotSave(entry, equipped, PackageSlot.Daemon);
|
||||
if (entry.slots.Count > 0)
|
||||
{
|
||||
_saveData.packageLoadouts.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddPackageSlotSave(PackageLoadoutSaveEntry entry, IReadOnlyDictionary<PackageSlot, string> equipped, PackageSlot slot)
|
||||
{
|
||||
if (entry == null || equipped == null || !equipped.TryGetValue(slot, out string packageId) || string.IsNullOrWhiteSpace(packageId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entry.slots.Add(new PackageLoadoutSlotSaveEntry
|
||||
{
|
||||
slot = slot,
|
||||
packageId = packageId
|
||||
});
|
||||
}
|
||||
|
||||
private void RefreshStaticText()
|
||||
{
|
||||
_appIdLabel.text = $"kernel-panic v{Application.version} - tty1";
|
||||
@@ -862,11 +1032,11 @@ namespace KernelPanic.UI
|
||||
return;
|
||||
}
|
||||
|
||||
_entropyLabel.text = $"entropy={_wallet.Balance}";
|
||||
_entropyLabel.text = $"Entropy={_wallet.Balance}";
|
||||
_rootCreditsToEntropyButton?.SetEnabled(true);
|
||||
bool showPullTokens = IsGachaVisible();
|
||||
_pullTokensLabel.text = showPullTokens
|
||||
? $"commits={_gachaService.PullTokens} root-credits={_gachaService.LimitedPullTokens} distro-merges={GetTotalDistroMerges()}"
|
||||
? $"Commits={_gachaService.PullTokens} Root Credits={_gachaService.RootCredits} Bandwidth={_saveData.bandwidthBalance} Cache={_saveData.cacheBalance} Merges={GetTotalDistroMerges()}"
|
||||
: string.Empty;
|
||||
_pullTokensLabel.EnableInClassList(HiddenClassName, !showPullTokens);
|
||||
}
|
||||
@@ -1053,7 +1223,16 @@ namespace KernelPanic.UI
|
||||
|
||||
if (IsCollectionVisible())
|
||||
{
|
||||
if (!collectionScreen.IsCardSubview &&
|
||||
if (collectionScreen.IsUnitDetail &&
|
||||
(evt.keyCode == KeyCode.LeftArrow || evt.keyCode == KeyCode.RightArrow || evt.keyCode == KeyCode.Tab))
|
||||
{
|
||||
collectionScreen.SwitchUnitDetailTabRelative(evt.keyCode == KeyCode.LeftArrow ? -1 : 1);
|
||||
SyncCollectionFrame();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!collectionScreen.IsPushedSubview &&
|
||||
(evt.keyCode == KeyCode.LeftArrow || evt.keyCode == KeyCode.RightArrow || evt.keyCode == KeyCode.Tab))
|
||||
{
|
||||
ToggleCollectionTab();
|
||||
@@ -1113,8 +1292,7 @@ namespace KernelPanic.UI
|
||||
|
||||
if (evt.keyCode == KeyCode.Tab)
|
||||
{
|
||||
_playerCollection.SelectNextFeatured();
|
||||
featuredUnitPanel.Refresh(_playerCollection.OwnedUnits, _playerCollection.FeaturedUnit);
|
||||
featuredUnitPanel.SelectNext();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
@@ -1626,7 +1804,7 @@ namespace KernelPanic.UI
|
||||
}
|
||||
|
||||
SaveLastRunLoadout(unit, equippedCardIds);
|
||||
RunContext.Set(unit, BuildEquippedCardDefinitions(unit, equippedCardIds), _selectedRunLanguages[0], _selectedRunLanguages[1], _playerCollection.GetVersion(unit.Id));
|
||||
RunContext.Set(unit, BuildEquippedCardDefinitions(unit, equippedCardIds), _packageLoadout.GetEquippedPackageInstances(unit.Id), _selectedRunLanguages[0], _selectedRunLanguages[1], _playerCollection.GetVersion(unit.Id));
|
||||
SceneLoader.LoadGame(_root);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user