Fix C, more enemies and less scaling for enemies.
This commit is contained in:
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: lang_c_malloc
|
||||
displayName: malloc()
|
||||
description: deal 8. 20% segfault: take 3.
|
||||
description: deal 8. 20% segfault: uptime -3.
|
||||
flavorText: memory acquired. ownership emotionally unresolved.
|
||||
language: 0
|
||||
rarity: 0
|
||||
|
||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: lang_c_pointer
|
||||
displayName: pointer
|
||||
description: deal 6. if the previous card was C, deal 10 instead.
|
||||
description: deal 6. if the previous card was C, deal 10 instead. 20% segfault: uptime -3.
|
||||
flavorText: points at the bug with suspicious confidence.
|
||||
language: 0
|
||||
rarity: 0
|
||||
|
||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: lang_c_printf
|
||||
displayName: printf()
|
||||
description: deal 4.
|
||||
description: deal 4. 20% segfault: uptime -3.
|
||||
flavorText: debugging by yelling into the void.
|
||||
language: 0
|
||||
rarity: 0
|
||||
|
||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: shop_c_free
|
||||
displayName: free()
|
||||
description: deal 12. if segfault recoil happens, draw 2.
|
||||
description: deal 12. 20% segfault: uptime -3 and draw 2.
|
||||
flavorText: double-free your schedule, not your heap.
|
||||
language: 0
|
||||
rarity: 0
|
||||
|
||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: shop_c_kernel_exploit
|
||||
displayName: kernel_exploit
|
||||
description: deal 25 ignoring Shield. 50% segfault: take 8.
|
||||
description: deal 25 ignoring Shield. 50% segfault: uptime -8.
|
||||
flavorText: privilege escalated. heartbeat also escalated.
|
||||
language: 0
|
||||
rarity: 1
|
||||
|
||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
id: shop_c_sizeof
|
||||
displayName: sizeof()
|
||||
description: deal 3 x C cards in hand.
|
||||
description: deal 3 x C cards in hand. 20% segfault: uptime -3.
|
||||
flavorText: compile-time confidence, runtime consequences.
|
||||
language: 0
|
||||
rarity: 1
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace KernelPanic.Combat
|
||||
targets = ShuffleTargets(targets, context.Source);
|
||||
}
|
||||
|
||||
bool dealtDamage = false;
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
CombatantState target = targets[i];
|
||||
@@ -54,11 +55,14 @@ namespace KernelPanic.Combat
|
||||
? _trueDamage ? target.CurrentUptime : target.CurrentUptime + target.Shield
|
||||
: 0;
|
||||
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, _trueDamage, _canCrit));
|
||||
dealtDamage |= result.IncomingAmount > 0;
|
||||
if (rustOverkillToShield)
|
||||
{
|
||||
GrantRustOverkillShield(context, result, survivable);
|
||||
}
|
||||
}
|
||||
|
||||
SegfaultRecoil.TryApply(context, _language, dealtDamage);
|
||||
}
|
||||
|
||||
private static void GrantRustOverkillShield(CombatContext context, DamageResult result, int survivable)
|
||||
@@ -164,7 +168,8 @@ namespace KernelPanic.Combat
|
||||
int roll = RandomRoll.RollRange(1, 100, new RollContext(context.Source));
|
||||
int damageAmount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_damageAmount, context), context.Card);
|
||||
int amount = roll <= _successPercent ? damageAmount : 0;
|
||||
context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, false, true));
|
||||
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, false, true));
|
||||
SegfaultRecoil.TryApply(context, _language, result.IncomingAmount > 0);
|
||||
context.CombatManager.ReportEffectResult(amount == 0 ? "typeof -> NaN (0)" : $"typeof -> {amount}");
|
||||
}
|
||||
}
|
||||
@@ -189,41 +194,6 @@ namespace KernelPanic.Combat
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SegfaultDamageEffect : ICardEffect
|
||||
{
|
||||
private readonly int _amount;
|
||||
private readonly int _selfDamage;
|
||||
private readonly int _segfaultPercent;
|
||||
private readonly bool _trueDamage;
|
||||
private readonly bool _drawOnSegfault;
|
||||
|
||||
public SegfaultDamageEffect(int amount, int selfDamage, int segfaultPercent, bool trueDamage = false, bool drawOnSegfault = false)
|
||||
{
|
||||
_amount = amount;
|
||||
_selfDamage = selfDamage;
|
||||
_segfaultPercent = segfaultPercent;
|
||||
_trueDamage = trueDamage;
|
||||
_drawOnSegfault = drawOnSegfault;
|
||||
}
|
||||
|
||||
public void Execute(CombatContext context)
|
||||
{
|
||||
new DealDamageEffect(_amount, _amount, Language.C, _trueDamage).Execute(context);
|
||||
bool segfault = RandomRoll.RollRange(1, 100, new RollContext(context.Source)) <= _segfaultPercent;
|
||||
if (!segfault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.DamagePipeline.DealDamage(new DamageRequest(context.Source, context.Source, _selfDamage, Language.C, false, false));
|
||||
context.CombatManager.ReportEffectResult($"segfault: took {_selfDamage}");
|
||||
if (_drawOnSegfault)
|
||||
{
|
||||
context.CombatManager.DrawCards(2, "free() recoil");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PreviousLanguageDamageEffect : ICardEffect
|
||||
{
|
||||
private readonly int _baseAmount;
|
||||
@@ -687,6 +657,7 @@ namespace KernelPanic.Combat
|
||||
int amount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_amount, context), context.Card);
|
||||
int survivable = target.CurrentUptime + target.Shield;
|
||||
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, false, true));
|
||||
SegfaultRecoil.TryApply(context, _language, result.IncomingAmount > 0);
|
||||
int overkill = UnityEngine.Mathf.Max(0, result.IncomingAmount - survivable);
|
||||
if (overkill > 0)
|
||||
{
|
||||
@@ -875,6 +846,58 @@ namespace KernelPanic.Combat
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SegfaultRecoil
|
||||
{
|
||||
private const int DefaultPercent = 20;
|
||||
private const int DefaultUptimeDamage = 3;
|
||||
|
||||
public static void TryApply(CombatContext context, Language damageLanguage, bool dealtDamage)
|
||||
{
|
||||
if (!dealtDamage
|
||||
|| context == null
|
||||
|| context.SegfaultRecoilRolled
|
||||
|| context.Source == null
|
||||
|| context.Source.IsDefeated
|
||||
|| context.Card?.Definition?.Language != Language.C
|
||||
|| damageLanguage != Language.C)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.SegfaultRecoilRolled = true;
|
||||
GetProfile(context.Card, out int percent, out int uptimeDamage, out bool drawOnSegfault);
|
||||
if (RandomRoll.RollRange(1, 100, new RollContext(context.Source)) > percent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(null, context.Source, uptimeDamage, Language.C, true, false));
|
||||
context.CombatManager.ReportEffectResult($"segfault: uptime -{result.FinalAmount}");
|
||||
if (drawOnSegfault)
|
||||
{
|
||||
context.CombatManager.DrawCards(2, "free() recoil");
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetProfile(CardInstance card, out int percent, out int uptimeDamage, out bool drawOnSegfault)
|
||||
{
|
||||
percent = DefaultPercent;
|
||||
uptimeDamage = DefaultUptimeDamage;
|
||||
drawOnSegfault = false;
|
||||
|
||||
switch (card?.Definition?.Id)
|
||||
{
|
||||
case "shop_c_free":
|
||||
drawOnSegfault = true;
|
||||
break;
|
||||
case "shop_c_kernel_exploit":
|
||||
percent = 50;
|
||||
uptimeDamage = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CardEffectFactory
|
||||
{
|
||||
public static IReadOnlyList<ICardEffect> CreateEffects(CardDefinition definition)
|
||||
@@ -899,7 +922,7 @@ namespace KernelPanic.Combat
|
||||
new DrawEffect(1)
|
||||
},
|
||||
"lang_rs_borrow" => One(new ShieldEffect(5)),
|
||||
"lang_c_malloc" => One(new SegfaultDamageEffect(8, 3, 20)),
|
||||
"lang_c_malloc" => One(new DealDamageEffect(8, 8, Language.C)),
|
||||
"lang_c_printf" => One(new DealDamageEffect(4, 4, Language.C)),
|
||||
"lang_c_pointer" => One(new PreviousLanguageDamageEffect(6, 10, Language.C)),
|
||||
"lang_java_public_static_main" => One(new DealDamageEffect(7, 7, Language.Java)),
|
||||
@@ -958,9 +981,9 @@ namespace KernelPanic.Combat
|
||||
"arch_makepkg" => One(new BtwScaledDamageEffect(4, 2, Language.C)),
|
||||
"arch_aur_helper" => One(new RandomCommonLanguageCardEffect()),
|
||||
"arch_minimal_install" => One(new MinimalInstallEffect()),
|
||||
"shop_c_free" => One(new SegfaultDamageEffect(12, 3, 20, drawOnSegfault: true)),
|
||||
"shop_c_free" => One(new DealDamageEffect(12, 12, Language.C)),
|
||||
"shop_c_sizeof" => One(new SizeofDamageEffect()),
|
||||
"shop_c_kernel_exploit" => One(new SegfaultDamageEffect(25, 8, 50, true)),
|
||||
"shop_c_kernel_exploit" => One(new DealDamageEffect(25, 25, Language.C, true)),
|
||||
_ => Todo("card effect is not authored")
|
||||
};
|
||||
}
|
||||
@@ -1030,9 +1053,9 @@ namespace KernelPanic.Combat
|
||||
"lang_rs_fn_main" => $"deal {UpgradeMath.ScaleAmount(6, card)}. overkill becomes shield.{marker}",
|
||||
"lang_rs_unwrap" => $"deal {UpgradeMath.ScaleAmount(9, card)}. overkill becomes shield. draw {UpgradeMath.ScaleAmount(1, card)}.{marker}",
|
||||
"lang_rs_borrow" => $"gain {UpgradeMath.ScaleShield(5, card)} shield.{marker}",
|
||||
"lang_c_malloc" => $"deal {UpgradeMath.ScaleAmount(8, card)}. 20%: segfault, take 3.{marker}",
|
||||
"lang_c_printf" => $"deal {UpgradeMath.ScaleAmount(4, card)}.{marker}",
|
||||
"lang_c_pointer" => $"deal {UpgradeMath.ScaleAmount(6, card)}; {UpgradeMath.ScaleAmount(10, card)} if the previous card was C.{marker}",
|
||||
"lang_c_malloc" => $"deal {UpgradeMath.ScaleAmount(8, card)}. 20%: segfault, uptime -3.{marker}",
|
||||
"lang_c_printf" => $"deal {UpgradeMath.ScaleAmount(4, card)}. 20%: segfault, uptime -3.{marker}",
|
||||
"lang_c_pointer" => $"deal {UpgradeMath.ScaleAmount(6, card)}; {UpgradeMath.ScaleAmount(10, card)} if the previous card was C. 20%: segfault, uptime -3.{marker}",
|
||||
"lang_java_public_static_main" => $"uses 2 RAM. deal {UpgradeMath.ScaleAmount(7, card)}. JIT: Java cards cost 1 less this combat each time you play a Java card; discount decays by 1 after each wave.{marker}",
|
||||
"lang_java_system_out_println" => $"uses 2 RAM. deal {UpgradeMath.ScaleAmount(5, card)}. JIT applies; discount decays by 1 after each wave.{marker}",
|
||||
"lang_java_new_object" => $"uses 2 RAM. deal {UpgradeMath.ScaleAmount(3, card)}. JIT applies; discount decays by 1 after each wave.{marker}",
|
||||
@@ -1057,14 +1080,14 @@ namespace KernelPanic.Combat
|
||||
"fedora_dnf_update" => $"deal {UpgradeMath.ScaleAmount(9, card)}. costs 1 less per Java card played this combat.{marker}",
|
||||
"fedora_rawhide" => $"draw {UpgradeMath.ScaleAmount(2, card)}. next card this turn gains bleeding edge.{marker}",
|
||||
"fedora_selinux" => $"next {UpgradeMath.ScaleAmount(2, card)} enemy attacks deal half damage.{marker}",
|
||||
"arch_pacman_syu" => $"deal {UpgradeMath.ScaleAmount(8, card)}. TODO: 20% break a random hand card.{marker}",
|
||||
"arch_pacman_syu" => $"deal {UpgradeMath.ScaleAmount(8, card)}. 20%: segfault, uptime -3. TODO: 20% break a random hand card.{marker}",
|
||||
"arch_consult_wiki" => $"fix a broken card and draw {UpgradeMath.ScaleAmount(1, card)}; if none, deal {UpgradeMath.ScaleAmount(6, card)}.{marker}",
|
||||
"arch_makepkg" => $"deal {UpgradeMath.ScaleAmount(4, card)} + btw x2; x3 at Arch v3+.{marker}",
|
||||
"arch_makepkg" => $"deal {UpgradeMath.ScaleAmount(4, card)} + btw x2; x3 at Arch v3+. 20%: segfault, uptime -3.{marker}",
|
||||
"arch_aur_helper" => $"add a random C/Rust common card to hand; it costs 0 this turn.{marker}",
|
||||
"arch_minimal_install" => $"exhaust up to 2 hand cards. per card: gain 3 Shield and 1 Cycle.{marker}",
|
||||
"shop_c_free" => $"deal {UpgradeMath.ScaleAmount(12, card)}. segfault recoil draws 2.{marker}",
|
||||
"shop_c_sizeof" => $"deal 3 x C cards in hand.{marker}",
|
||||
"shop_c_kernel_exploit" => $"deal {UpgradeMath.ScaleAmount(25, card)} ignoring Shield. 50%: take 8.{marker}",
|
||||
"shop_c_free" => $"deal {UpgradeMath.ScaleAmount(12, card)}. 20%: segfault, uptime -3 and draw 2.{marker}",
|
||||
"shop_c_sizeof" => $"deal 3 x C cards in hand. 20%: segfault, uptime -3.{marker}",
|
||||
"shop_c_kernel_exploit" => $"deal {UpgradeMath.ScaleAmount(25, card)} ignoring Shield. 50%: segfault, uptime -8.{marker}",
|
||||
_ => string.IsNullOrWhiteSpace(card.Definition.Description) ? "effect not authored." : $"{card.Definition.Description}{marker}"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,5 +38,7 @@ namespace KernelPanic.Combat
|
||||
public DeckController DeckController { get; }
|
||||
public HandController HandController { get; }
|
||||
public IReadOnlyList<EnemyInstance> Enemies { get; }
|
||||
|
||||
internal bool SegfaultRecoilRolled { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ namespace KernelPanic.Combat
|
||||
|
||||
public const int BaseEnemyUptimeMin = 5;
|
||||
public const int BaseEnemyUptimeMax = 10;
|
||||
public const int EnemyUptimeGrowthPerWave = 2;
|
||||
public const int EnemyUptimeGrowthPerWave = 1;
|
||||
|
||||
public const int BaseEnemyAttack = 3;
|
||||
public const int EnemyAttackGrowthEveryWaves = 2;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace KernelPanic.Combat
|
||||
public int Cycles { get; set; }
|
||||
public int MaxCycles { get; set; }
|
||||
public bool IsDefeated { get; set; }
|
||||
public bool forceMaxRolls { get; set; }
|
||||
public bool ForceMaxRolls { get; set; }
|
||||
public bool IgnoreDamageMultipliers { get; set; }
|
||||
public bool AllowFlatDamageBuffs { get; set; }
|
||||
public int FlatEffectBonus { get; set; }
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace KernelPanic.Combat
|
||||
private static int ApplyCrit(int amount, DamageRequest request, out bool wasCritical)
|
||||
{
|
||||
wasCritical = false;
|
||||
if (!request.CanCrit || amount <= 0 || request.Source != null && request.Source.forceMaxRolls)
|
||||
if (!request.CanCrit || amount <= 0 || request.Source != null && request.Source.ForceMaxRolls)
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KernelPanic.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace KernelPanic.Combat
|
||||
{
|
||||
[Flags]
|
||||
public enum EnemyBehaviorFlags
|
||||
{
|
||||
None = 0,
|
||||
Revive = 1 << 0,
|
||||
Split = 1 << 1,
|
||||
Grow = 1 << 2,
|
||||
ObfuscateIntent = 1 << 3,
|
||||
DefendAllies = 1 << 4,
|
||||
Countdown = 1 << 5
|
||||
}
|
||||
|
||||
public sealed class EnemyArchetypeDescriptor
|
||||
{
|
||||
public EnemyArchetypeDescriptor(
|
||||
string id,
|
||||
string displayName,
|
||||
int baseUptimeMin,
|
||||
int baseUptimeMax,
|
||||
EnemyBehaviorFlags behaviorFlags,
|
||||
IReadOnlyList<EnemyIntent> intentPool)
|
||||
{
|
||||
Id = string.IsNullOrWhiteSpace(id) ? "unknown_process" : id;
|
||||
DisplayName = string.IsNullOrWhiteSpace(displayName) ? Id : displayName;
|
||||
BaseUptimeMin = Mathf.Max(1, baseUptimeMin);
|
||||
BaseUptimeMax = Mathf.Max(BaseUptimeMin, baseUptimeMax);
|
||||
BehaviorFlags = behaviorFlags;
|
||||
IntentPool = intentPool ?? Array.Empty<EnemyIntent>();
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string DisplayName { get; }
|
||||
public int BaseUptimeMin { get; }
|
||||
public int BaseUptimeMax { get; }
|
||||
public EnemyBehaviorFlags BehaviorFlags { get; }
|
||||
public IReadOnlyList<EnemyIntent> IntentPool { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runtime archetype construction site. Future EnemyDefinition assets should replace this table
|
||||
/// by providing the same descriptor data: id, display name, base Uptime range, intents, and flags.
|
||||
/// </summary>
|
||||
public static class EnemyArchetypeCatalog
|
||||
{
|
||||
public const int ZombieReapThresholdPercent = 30;
|
||||
public const int MemoryLeakAttackGrowthPerTurn = 1;
|
||||
public const int ForkBombTotalCap = 5;
|
||||
public const int CronInitialCountdown = 2;
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor ZombieProcess = new(
|
||||
"zombie_process",
|
||||
"Zombie Process",
|
||||
6,
|
||||
10,
|
||||
EnemyBehaviorFlags.Revive,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.Attack, 3, 4, Language.C, "attack", "!")
|
||||
});
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor MemoryLeak = new(
|
||||
"memory_leak",
|
||||
"Memory Leak",
|
||||
4,
|
||||
7,
|
||||
EnemyBehaviorFlags.Grow,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.StatusAttack, 1, 1, Language.C, "leak", "!", false, StatusType.MemoryLeak, 1, CombatTuning.EnemyStatusDuration)
|
||||
});
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor ForkBomb = new(
|
||||
"fork_bomb",
|
||||
"Fork Bomb",
|
||||
3,
|
||||
5,
|
||||
EnemyBehaviorFlags.Split,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.Special, 0, 0, Language.C, "fork", ":", false, StatusType.MemoryLeak, 0, -1, "split")
|
||||
});
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor Daemon = new(
|
||||
"daemon",
|
||||
"Daemon",
|
||||
10,
|
||||
14,
|
||||
EnemyBehaviorFlags.ObfuscateIntent,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.Attack, 6, 8, Language.C, "daemon hit", "!")
|
||||
});
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor Defender = new(
|
||||
"firewalld",
|
||||
"firewalld",
|
||||
5,
|
||||
8,
|
||||
EnemyBehaviorFlags.DefendAllies,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.Defend, 3, 5, Language.C, "shield adjacent", "#"),
|
||||
new EnemyIntent(EnemyIntentKind.Defend, 3, 5, Language.C, "shield adjacent", "#"),
|
||||
new EnemyIntent(EnemyIntentKind.Attack, 1, 2, Language.C, "poke", "!")
|
||||
});
|
||||
|
||||
private static readonly EnemyArchetypeDescriptor CronJob = new(
|
||||
"cron_job",
|
||||
"Cron Job",
|
||||
6,
|
||||
9,
|
||||
EnemyBehaviorFlags.Countdown,
|
||||
new[]
|
||||
{
|
||||
new EnemyIntent(EnemyIntentKind.Attack, 10, 12, Language.C, "cron fire", "@")
|
||||
});
|
||||
|
||||
public static EnemyArchetypeDescriptor Get(string id)
|
||||
{
|
||||
return id switch
|
||||
{
|
||||
"memory_leak" => MemoryLeak,
|
||||
"fork_bomb" => ForkBomb,
|
||||
"daemon" => Daemon,
|
||||
"firewalld" => Defender,
|
||||
"cron_job" => CronJob,
|
||||
_ => ZombieProcess
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,24 +10,57 @@ namespace KernelPanic.Combat
|
||||
private readonly List<EnemyIntent> _intentPool = new();
|
||||
|
||||
public EnemyInstance(string name, int maxUptime, IEnumerable<EnemyIntent> intentPool)
|
||||
: this(new EnemyArchetypeDescriptor(name, name, maxUptime, maxUptime, EnemyBehaviorFlags.None, new List<EnemyIntent>(intentPool ?? System.Array.Empty<EnemyIntent>())), maxUptime)
|
||||
{
|
||||
Name = string.IsNullOrWhiteSpace(name) ? "unknown_process" : name;
|
||||
}
|
||||
|
||||
public EnemyInstance(EnemyArchetypeDescriptor archetype, int maxUptime)
|
||||
{
|
||||
Archetype = archetype ?? EnemyArchetypeCatalog.Get("zombie_process");
|
||||
Name = Archetype.DisplayName;
|
||||
State = new CombatantState(maxUptime, 0, 0);
|
||||
if (intentPool != null)
|
||||
if (Archetype.IntentPool != null)
|
||||
{
|
||||
_intentPool.AddRange(intentPool);
|
||||
_intentPool.AddRange(Archetype.IntentPool);
|
||||
}
|
||||
|
||||
CountdownRemaining = HasBehavior(EnemyBehaviorFlags.Countdown) ? EnemyArchetypeCatalog.CronInitialCountdown : 0;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public EnemyArchetypeDescriptor Archetype { get; }
|
||||
public string ArchetypeId => Archetype.Id;
|
||||
public int CurrentUptime => State.CurrentUptime;
|
||||
public int MaxUptime => State.MaxUptime;
|
||||
public CombatantState State { get; }
|
||||
public IReadOnlyList<EnemyIntent> IntentPool => _intentPool;
|
||||
public EnemyIntent CurrentIntent { get; private set; }
|
||||
public int TurnsAlive { get; private set; }
|
||||
public int CountdownRemaining { get; private set; }
|
||||
public bool IntentRevealed { get; private set; }
|
||||
public bool HasRevived { get; private set; }
|
||||
public bool PendingRevive { get; private set; }
|
||||
public bool Reaped { get; private set; }
|
||||
public bool LethalHitThisTurn { get; private set; }
|
||||
public bool HasPendingMarker => PendingRevive || HasRevived;
|
||||
public EnemyIntent DisplayIntent => BuildDisplayIntent();
|
||||
|
||||
public void PickNextIntent()
|
||||
{
|
||||
if (PendingRevive)
|
||||
{
|
||||
CurrentIntent = new EnemyIntent(EnemyIntentKind.Special, 0, 0, KernelPanic.Core.Language.C, "reviving", "~", false, KernelPanic.Core.StatusType.MemoryLeak, 0, -1, "next");
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasBehavior(EnemyBehaviorFlags.Countdown))
|
||||
{
|
||||
CurrentIntent = CountdownRemaining > 0
|
||||
? new EnemyIntent(EnemyIntentKind.Special, CountdownRemaining, CountdownRemaining, KernelPanic.Core.Language.C, "countdown", "@")
|
||||
: _intentPool.Count > 0 ? _intentPool[0] : default;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_intentPool.Count == 0)
|
||||
{
|
||||
CurrentIntent = default;
|
||||
@@ -36,6 +69,92 @@ namespace KernelPanic.Combat
|
||||
|
||||
int index = RandomRoll.RollRange(0, _intentPool.Count - 1, new RollContext(State));
|
||||
CurrentIntent = _intentPool[index];
|
||||
if (HasBehavior(EnemyBehaviorFlags.Grow))
|
||||
{
|
||||
int growth = TurnsAlive * EnemyArchetypeCatalog.MemoryLeakAttackGrowthPerTurn;
|
||||
CurrentIntent = CurrentIntent.WithValues(CurrentIntent.MinValue + growth, CurrentIntent.MaxValue + growth, "growing leak");
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasBehavior(EnemyBehaviorFlags behavior)
|
||||
{
|
||||
return (Archetype.BehaviorFlags & behavior) != 0;
|
||||
}
|
||||
|
||||
public void MarkDamaged()
|
||||
{
|
||||
if (HasBehavior(EnemyBehaviorFlags.ObfuscateIntent))
|
||||
{
|
||||
IntentRevealed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkTurnSurvived()
|
||||
{
|
||||
TurnsAlive++;
|
||||
}
|
||||
|
||||
public void ResetTurnLethalMarker()
|
||||
{
|
||||
LethalHitThisTurn = false;
|
||||
}
|
||||
|
||||
public void MarkLethalHit()
|
||||
{
|
||||
LethalHitThisTurn = true;
|
||||
}
|
||||
|
||||
public void MarkPendingRevive()
|
||||
{
|
||||
PendingRevive = true;
|
||||
State.IsDefeated = false;
|
||||
State.CurrentUptime = 0;
|
||||
State.Shield = 0;
|
||||
CurrentIntent = new EnemyIntent(EnemyIntentKind.Special, 0, 0, KernelPanic.Core.Language.C, "reviving", "~", false, KernelPanic.Core.StatusType.MemoryLeak, 0, -1, "next");
|
||||
}
|
||||
|
||||
public void ReviveAtHalfUptime()
|
||||
{
|
||||
PendingRevive = false;
|
||||
HasRevived = true;
|
||||
State.IsDefeated = false;
|
||||
State.CurrentUptime = UnityEngine.Mathf.Max(1, UnityEngine.Mathf.CeilToInt(State.MaxUptime * 0.5f));
|
||||
PickNextIntent();
|
||||
}
|
||||
|
||||
public void MarkReaped()
|
||||
{
|
||||
PendingRevive = false;
|
||||
Reaped = true;
|
||||
State.IsDefeated = true;
|
||||
State.CurrentUptime = 0;
|
||||
}
|
||||
|
||||
public void AdvanceCountdownAfterAction()
|
||||
{
|
||||
if (!HasBehavior(EnemyBehaviorFlags.Countdown))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CountdownRemaining = CurrentIntent.Kind == EnemyIntentKind.Attack
|
||||
? EnemyArchetypeCatalog.CronInitialCountdown
|
||||
: UnityEngine.Mathf.Max(0, CountdownRemaining - 1);
|
||||
}
|
||||
|
||||
private EnemyIntent BuildDisplayIntent()
|
||||
{
|
||||
if (PendingRevive)
|
||||
{
|
||||
return new EnemyIntent(EnemyIntentKind.Special, 0, 0, KernelPanic.Core.Language.C, "reviving", "~", false, KernelPanic.Core.StatusType.MemoryLeak, 0, -1, "next");
|
||||
}
|
||||
|
||||
if (HasBehavior(EnemyBehaviorFlags.ObfuscateIntent) && !IntentRevealed)
|
||||
{
|
||||
return new EnemyIntent(EnemyIntentKind.Special, 0, 0, KernelPanic.Core.Language.C, "unknown", "?", false, KernelPanic.Core.StatusType.MemoryLeak, 0, -1, "?");
|
||||
}
|
||||
|
||||
return CurrentIntent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace KernelPanic.Combat
|
||||
bool trueDamage = false,
|
||||
StatusType statusType = StatusType.MemoryLeak,
|
||||
int statusStacks = 0,
|
||||
int statusDuration = -1)
|
||||
int statusDuration = -1,
|
||||
string valueTextOverride = null)
|
||||
{
|
||||
Kind = kind;
|
||||
MinValue = minValue;
|
||||
@@ -38,6 +39,7 @@ namespace KernelPanic.Combat
|
||||
StatusType = statusType;
|
||||
StatusStacks = statusStacks;
|
||||
StatusDuration = statusDuration;
|
||||
ValueTextOverride = valueTextOverride;
|
||||
}
|
||||
|
||||
public EnemyIntentKind Kind { get; }
|
||||
@@ -50,8 +52,27 @@ namespace KernelPanic.Combat
|
||||
public StatusType StatusType { get; }
|
||||
public int StatusStacks { get; }
|
||||
public int StatusDuration { get; }
|
||||
public string ValueTextOverride { get; }
|
||||
|
||||
public string ValueText => MinValue == MaxValue ? MinValue.ToString() : $"{MinValue}-{MaxValue}";
|
||||
public string ValueText => string.IsNullOrWhiteSpace(ValueTextOverride)
|
||||
? MinValue == MaxValue ? MinValue.ToString() : $"{MinValue}-{MaxValue}"
|
||||
: ValueTextOverride;
|
||||
public string DisplayText => $"{IconKey} {DisplayLabel} {ValueText}";
|
||||
|
||||
public EnemyIntent WithValues(int minValue, int maxValue, string displayLabel = null, string iconKey = null, string valueTextOverride = null)
|
||||
{
|
||||
return new EnemyIntent(
|
||||
Kind,
|
||||
minValue,
|
||||
maxValue,
|
||||
DamageType,
|
||||
displayLabel ?? DisplayLabel,
|
||||
iconKey ?? IconKey,
|
||||
TrueDamage,
|
||||
StatusType,
|
||||
StatusStacks,
|
||||
StatusDuration,
|
||||
valueTextOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace KernelPanic.Combat
|
||||
}
|
||||
|
||||
// Mint's passive will flip this bool; no passive sets it in this scaffold.
|
||||
if (context.Source != null && context.Source.forceMaxRolls)
|
||||
if (context.Source != null && context.Source.ForceMaxRolls)
|
||||
{
|
||||
return max;
|
||||
}
|
||||
|
||||
@@ -10,34 +10,34 @@ namespace KernelPanic.Meta
|
||||
/// </summary>
|
||||
public static class GachaPullContext
|
||||
{
|
||||
private static PendingGachaPull pendingPull;
|
||||
private static CompletedGachaPull completedPull;
|
||||
private static PendingGachaPull _pendingPull;
|
||||
private static CompletedGachaPull _completedPull;
|
||||
|
||||
public static bool HasPendingPull => pendingPull != null;
|
||||
public static bool HasCompletedPull => completedPull != null;
|
||||
public static bool HasPendingPull => _pendingPull != null;
|
||||
public static bool HasCompletedPull => _completedPull != null;
|
||||
|
||||
public static void SetPending(string bannerId, int pullCount, int entropyTokenCount, DistroDatabase distroDatabase, PackageDatabase packageDatabase, string focusUnitId)
|
||||
{
|
||||
pendingPull = new PendingGachaPull(bannerId, pullCount, entropyTokenCount, distroDatabase, packageDatabase, focusUnitId);
|
||||
completedPull = null;
|
||||
_pendingPull = new PendingGachaPull(bannerId, pullCount, entropyTokenCount, distroDatabase, packageDatabase, focusUnitId);
|
||||
_completedPull = null;
|
||||
}
|
||||
|
||||
public static bool TryConsumePending(out PendingGachaPull pull)
|
||||
{
|
||||
pull = pendingPull;
|
||||
pendingPull = null;
|
||||
pull = _pendingPull;
|
||||
_pendingPull = null;
|
||||
return pull != null;
|
||||
}
|
||||
|
||||
public static void SetCompleted(CompletedGachaPull pull)
|
||||
{
|
||||
completedPull = pull;
|
||||
_completedPull = pull;
|
||||
}
|
||||
|
||||
public static bool TryConsumeCompleted(out CompletedGachaPull pull)
|
||||
{
|
||||
pull = completedPull;
|
||||
completedPull = null;
|
||||
pull = _completedPull;
|
||||
_completedPull = null;
|
||||
return pull != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace KernelPanic.Meta
|
||||
// with access to PackageDatabase) consumes this once per load to grant Cache for the extras,
|
||||
// then clears it. See MainMenuController.LoadMetaState.
|
||||
[NonSerialized]
|
||||
public List<CollapsedPackageDuplicate> collapsedPackageDuplicates = new();
|
||||
public List<CollapsedPackageDuplicate> CollapsedPackageDuplicates = new();
|
||||
|
||||
public static SaveData CreateDefault()
|
||||
{
|
||||
@@ -236,7 +236,7 @@ namespace KernelPanic.Meta
|
||||
|
||||
private void NormalizeOwnedPackages()
|
||||
{
|
||||
collapsedPackageDuplicates.Clear();
|
||||
CollapsedPackageDuplicates.Clear();
|
||||
Dictionary<string, OwnedPackageSaveEntry> highestById = new(StringComparer.OrdinalIgnoreCase);
|
||||
Dictionary<string, int> extraCountById = new(StringComparer.OrdinalIgnoreCase);
|
||||
for (int i = 0; i < ownedPackages.Count; i++)
|
||||
@@ -265,7 +265,7 @@ namespace KernelPanic.Meta
|
||||
ownedPackages = new List<OwnedPackageSaveEntry>(highestById.Values);
|
||||
foreach (KeyValuePair<string, int> extra in extraCountById)
|
||||
{
|
||||
collapsedPackageDuplicates.Add(new CollapsedPackageDuplicate(extra.Key, extra.Value));
|
||||
CollapsedPackageDuplicates.Add(new CollapsedPackageDuplicate(extra.Key, extra.Value));
|
||||
}
|
||||
|
||||
ownedPackageIds.Clear();
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace KernelPanic.Run
|
||||
/// </summary>
|
||||
public static class RunContext
|
||||
{
|
||||
private static PendingRun pendingRun;
|
||||
private static PendingRun _pendingRun;
|
||||
|
||||
public static bool HasPendingRun => pendingRun != null;
|
||||
public static bool HasPendingRun => _pendingRun != null;
|
||||
|
||||
public static void Set(DistroDefinition distro, IReadOnlyList<CardDefinition> equippedCards, Language primaryLanguage, Language secondaryLanguage)
|
||||
{
|
||||
@@ -28,44 +28,44 @@ namespace KernelPanic.Run
|
||||
|
||||
public static void Set(DistroDefinition distro, IReadOnlyList<CardDefinition> equippedCards, IReadOnlyList<PackageDefinition> equippedPackages, Language primaryLanguage, Language secondaryLanguage, int distroVersion)
|
||||
{
|
||||
pendingRun = new PendingRun(distro, equippedCards, ToInstances(equippedPackages), primaryLanguage, secondaryLanguage, Environment.TickCount, distroVersion);
|
||||
_pendingRun = new PendingRun(distro, equippedCards, ToInstances(equippedPackages), primaryLanguage, secondaryLanguage, Environment.TickCount, distroVersion);
|
||||
}
|
||||
|
||||
public static void Set(DistroDefinition distro, IReadOnlyList<CardDefinition> equippedCards, IReadOnlyList<PackageInstance> equippedPackages, Language primaryLanguage, Language secondaryLanguage, int distroVersion)
|
||||
{
|
||||
pendingRun = new PendingRun(distro, equippedCards, equippedPackages, primaryLanguage, secondaryLanguage, Environment.TickCount, distroVersion);
|
||||
_pendingRun = new PendingRun(distro, equippedCards, equippedPackages, primaryLanguage, secondaryLanguage, Environment.TickCount, distroVersion);
|
||||
}
|
||||
|
||||
public static bool TryCreateRunConfig(LanguageDeckDatabase languageDeckDatabase, out RunConfig config)
|
||||
{
|
||||
if (pendingRun == null || pendingRun.Distro == null)
|
||||
if (_pendingRun == null || _pendingRun.Distro == null)
|
||||
{
|
||||
config = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
config = pendingRun.CreateRunConfig(languageDeckDatabase);
|
||||
pendingRun = null;
|
||||
config = _pendingRun.CreateRunConfig(languageDeckDatabase);
|
||||
_pendingRun = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private sealed class PendingRun
|
||||
{
|
||||
private readonly DistroDefinition distro;
|
||||
private readonly List<CardDefinition> equippedCards = new();
|
||||
private readonly List<PackageInstance> equippedPackages = new();
|
||||
private readonly Language primaryLanguage;
|
||||
private readonly Language secondaryLanguage;
|
||||
private readonly int runSeed;
|
||||
private readonly int distroVersion;
|
||||
private readonly DistroDefinition _distro;
|
||||
private readonly List<CardDefinition> _equippedCards = new();
|
||||
private readonly List<PackageInstance> _equippedPackages = new();
|
||||
private readonly Language _primaryLanguage;
|
||||
private readonly Language _secondaryLanguage;
|
||||
private readonly int _runSeed;
|
||||
private readonly int _distroVersion;
|
||||
|
||||
public PendingRun(DistroDefinition distro, IReadOnlyList<CardDefinition> cards, IReadOnlyList<PackageInstance> packages, Language primaryLanguage, Language secondaryLanguage, int runSeed, int distroVersion)
|
||||
{
|
||||
this.distro = distro;
|
||||
this.primaryLanguage = primaryLanguage;
|
||||
this.secondaryLanguage = secondaryLanguage;
|
||||
this.runSeed = runSeed;
|
||||
this.distroVersion = distroVersion;
|
||||
this._distro = distro;
|
||||
this._primaryLanguage = primaryLanguage;
|
||||
this._secondaryLanguage = secondaryLanguage;
|
||||
this._runSeed = runSeed;
|
||||
this._distroVersion = distroVersion;
|
||||
|
||||
if (cards == null)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ namespace KernelPanic.Run
|
||||
{
|
||||
if (cards[i] != null && !cards[i].IsRunOnly)
|
||||
{
|
||||
equippedCards.Add(cards[i]);
|
||||
_equippedCards.Add(cards[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,19 +89,19 @@ namespace KernelPanic.Run
|
||||
{
|
||||
if (packages[i]?.Definition != null)
|
||||
{
|
||||
equippedPackages.Add(packages[i]);
|
||||
_equippedPackages.Add(packages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DistroDefinition Distro => distro;
|
||||
public DistroDefinition Distro => _distro;
|
||||
|
||||
public RunConfig CreateRunConfig(LanguageDeckDatabase languageDeckDatabase)
|
||||
{
|
||||
List<CardDefinition> startingDeck = new(equippedCards);
|
||||
AddLanguageDeck(languageDeckDatabase, primaryLanguage, startingDeck);
|
||||
AddLanguageDeck(languageDeckDatabase, secondaryLanguage, startingDeck);
|
||||
return new RunConfig(distro, primaryLanguage, secondaryLanguage, startingDeck, equippedPackages, runSeed, distroVersion);
|
||||
List<CardDefinition> startingDeck = new(_equippedCards);
|
||||
AddLanguageDeck(languageDeckDatabase, _primaryLanguage, startingDeck);
|
||||
AddLanguageDeck(languageDeckDatabase, _secondaryLanguage, startingDeck);
|
||||
return new RunConfig(_distro, _primaryLanguage, _secondaryLanguage, startingDeck, _equippedPackages, _runSeed, _distroVersion);
|
||||
}
|
||||
|
||||
private static void AddLanguageDeck(LanguageDeckDatabase languageDeckDatabase, Language language, List<CardDefinition> target)
|
||||
|
||||
+102
-102
@@ -18,39 +18,39 @@ namespace KernelPanic.Run
|
||||
[SerializeField] private bool isRunActive;
|
||||
[SerializeField] private bool isPlayerDead;
|
||||
|
||||
private readonly List<CardInstance> runDeck = new();
|
||||
private readonly List<RepositoryOffer> repositoryOffers = new();
|
||||
private readonly HashSet<string> soldOfferKeys = new(StringComparer.OrdinalIgnoreCase);
|
||||
private int bits;
|
||||
private int rerollsThisVisit;
|
||||
private int maxUptimeBonus;
|
||||
private int maxCyclesBonus;
|
||||
private int ramBonus;
|
||||
private int packageMaxUptimeBonus;
|
||||
private int packageMaxCyclesBonus;
|
||||
private int packageRamBonus;
|
||||
private int wavesCleared;
|
||||
private int accruedBandwidth;
|
||||
private int accruedEntropy;
|
||||
private bool repositoryVisitActive;
|
||||
private bool rewardsSettled;
|
||||
private readonly List<CardInstance> _runDeck = new();
|
||||
private readonly List<RepositoryOffer> _repositoryOffers = new();
|
||||
private readonly HashSet<string> _soldOfferKeys = new(StringComparer.OrdinalIgnoreCase);
|
||||
private int _bits;
|
||||
private int _rerollsThisVisit;
|
||||
private int _maxUptimeBonus;
|
||||
private int _maxCyclesBonus;
|
||||
private int _ramBonus;
|
||||
private int _packageMaxUptimeBonus;
|
||||
private int _packageMaxCyclesBonus;
|
||||
private int _packageRamBonus;
|
||||
private int _wavesCleared;
|
||||
private int _accruedBandwidth;
|
||||
private int _accruedEntropy;
|
||||
private bool _repositoryVisitActive;
|
||||
private bool _rewardsSettled;
|
||||
|
||||
public int CurrentWaveNumber => currentWaveNumber;
|
||||
public bool IsRunActive => isRunActive;
|
||||
public bool IsPlayerDead => isPlayerDead;
|
||||
public RunConfig CurrentConfig { get; private set; }
|
||||
public IReadOnlyList<CardInstance> RunDeck => runDeck;
|
||||
public IReadOnlyList<RepositoryOffer> RepositoryOffers => repositoryOffers;
|
||||
public bool RepositoryVisitActive => repositoryVisitActive;
|
||||
public int Bits => bits;
|
||||
public int RerollCost => CombatTuning.RerollBaseCost + (rerollsThisVisit * CombatTuning.RerollCostStep);
|
||||
public int MaxUptimeBonus => maxUptimeBonus;
|
||||
public int MaxCyclesBonus => maxCyclesBonus;
|
||||
public int RamBonus => ramBonus;
|
||||
public int WavesCleared => wavesCleared;
|
||||
public int AccruedBandwidth => accruedBandwidth;
|
||||
public int AccruedEntropy => accruedEntropy;
|
||||
public bool RewardsSettled => rewardsSettled;
|
||||
public IReadOnlyList<CardInstance> RunDeck => _runDeck;
|
||||
public IReadOnlyList<RepositoryOffer> RepositoryOffers => _repositoryOffers;
|
||||
public bool RepositoryVisitActive => _repositoryVisitActive;
|
||||
public int Bits => _bits;
|
||||
public int RerollCost => CombatTuning.RerollBaseCost + (_rerollsThisVisit * CombatTuning.RerollCostStep);
|
||||
public int MaxUptimeBonus => _maxUptimeBonus;
|
||||
public int MaxCyclesBonus => _maxCyclesBonus;
|
||||
public int RamBonus => _ramBonus;
|
||||
public int WavesCleared => _wavesCleared;
|
||||
public int AccruedBandwidth => _accruedBandwidth;
|
||||
public int AccruedEntropy => _accruedEntropy;
|
||||
public bool RewardsSettled => _rewardsSettled;
|
||||
|
||||
public event Action RepositoryChanged;
|
||||
|
||||
@@ -72,18 +72,18 @@ namespace KernelPanic.Run
|
||||
isRunActive = true;
|
||||
isPlayerDead = false;
|
||||
currentWaveNumber = 1;
|
||||
bits = 0;
|
||||
rerollsThisVisit = 0;
|
||||
maxUptimeBonus = 0;
|
||||
maxCyclesBonus = 0;
|
||||
ramBonus = 0;
|
||||
packageMaxUptimeBonus = 0;
|
||||
packageMaxCyclesBonus = 0;
|
||||
packageRamBonus = 0;
|
||||
wavesCleared = 0;
|
||||
accruedBandwidth = 0;
|
||||
accruedEntropy = 0;
|
||||
rewardsSettled = false;
|
||||
_bits = 0;
|
||||
_rerollsThisVisit = 0;
|
||||
_maxUptimeBonus = 0;
|
||||
_maxCyclesBonus = 0;
|
||||
_ramBonus = 0;
|
||||
_packageMaxUptimeBonus = 0;
|
||||
_packageMaxCyclesBonus = 0;
|
||||
_packageRamBonus = 0;
|
||||
_wavesCleared = 0;
|
||||
_accruedBandwidth = 0;
|
||||
_accruedEntropy = 0;
|
||||
_rewardsSettled = false;
|
||||
ApplyKernelPackageBonuses(config);
|
||||
InitializeRunDeck(config);
|
||||
StartCombat();
|
||||
@@ -101,40 +101,40 @@ namespace KernelPanic.Run
|
||||
return;
|
||||
}
|
||||
|
||||
bits += amount;
|
||||
_bits += amount;
|
||||
RepositoryChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void GenerateRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
|
||||
{
|
||||
repositoryOffers.Clear();
|
||||
rerollsThisVisit = 0;
|
||||
soldOfferKeys.Clear();
|
||||
_repositoryOffers.Clear();
|
||||
_rerollsThisVisit = 0;
|
||||
_soldOfferKeys.Clear();
|
||||
FillRepositoryOffers(cardDatabase, languageDeckDatabase);
|
||||
repositoryVisitActive = true;
|
||||
_repositoryVisitActive = true;
|
||||
RepositoryChanged?.Invoke();
|
||||
}
|
||||
|
||||
public bool RerollRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
|
||||
{
|
||||
int cost = RerollCost;
|
||||
if (bits < cost)
|
||||
if (_bits < cost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bits -= cost;
|
||||
rerollsThisVisit++;
|
||||
repositoryOffers.Clear();
|
||||
_bits -= cost;
|
||||
_rerollsThisVisit++;
|
||||
_repositoryOffers.Clear();
|
||||
FillRepositoryOffers(cardDatabase, languageDeckDatabase);
|
||||
repositoryVisitActive = true;
|
||||
_repositoryVisitActive = true;
|
||||
RepositoryChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BuyOffer(RepositoryOffer offer, CombatantState playerState)
|
||||
{
|
||||
if (offer == null || offer.Sold || bits < offer.Price)
|
||||
if (offer == null || offer.Sold || _bits < offer.Price)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -152,43 +152,43 @@ namespace KernelPanic.Run
|
||||
return false;
|
||||
}
|
||||
|
||||
bits -= offer.Price;
|
||||
_bits -= offer.Price;
|
||||
offer.MarkSold();
|
||||
soldOfferKeys.Add(OfferKey(offer));
|
||||
_soldOfferKeys.Add(OfferKey(offer));
|
||||
RepositoryChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveCard(CardInstance card)
|
||||
{
|
||||
if (card == null || bits < CombatTuning.RemoveCardCost || runDeck.Count <= 1)
|
||||
if (card == null || _bits < CombatTuning.RemoveCardCost || _runDeck.Count <= 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!runDeck.Remove(card))
|
||||
if (!_runDeck.Remove(card))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bits -= CombatTuning.RemoveCardCost;
|
||||
_bits -= CombatTuning.RemoveCardCost;
|
||||
RepositoryChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public int EffectiveMaxUptime()
|
||||
{
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseUptime ?? 1) + maxUptimeBonus + packageMaxUptimeBonus);
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseUptime ?? 1) + _maxUptimeBonus + _packageMaxUptimeBonus);
|
||||
}
|
||||
|
||||
public int EffectiveRam()
|
||||
{
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseRam ?? 1) + ramBonus + packageRamBonus);
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseRam ?? 1) + _ramBonus + _packageRamBonus);
|
||||
}
|
||||
|
||||
public int EffectiveMaxCycles()
|
||||
{
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseCyclesPerTurn ?? 1) + maxCyclesBonus + packageMaxCyclesBonus);
|
||||
return Mathf.Max(1, (CurrentConfig?.Distro?.BaseCyclesPerTurn ?? 1) + _maxCyclesBonus + _packageMaxCyclesBonus);
|
||||
}
|
||||
|
||||
public static PackageStatImpact CalculatePackageStatImpact(DistroDefinition distro, IReadOnlyList<PackageInstance> packages)
|
||||
@@ -232,35 +232,35 @@ namespace KernelPanic.Run
|
||||
private void ApplyKernelPackageBonuses(RunConfig config)
|
||||
{
|
||||
PackageStatImpact impact = CalculatePackageStatImpact(config?.Distro, config?.EquippedPackages);
|
||||
packageMaxUptimeBonus = impact.UptimeBonus;
|
||||
packageMaxCyclesBonus = impact.CyclesBonus;
|
||||
packageRamBonus = impact.RamBonus;
|
||||
_packageMaxUptimeBonus = impact.UptimeBonus;
|
||||
_packageMaxCyclesBonus = impact.CyclesBonus;
|
||||
_packageRamBonus = impact.RamBonus;
|
||||
}
|
||||
|
||||
public bool TrySettleRunRewards(out int bandwidth, out int entropy)
|
||||
{
|
||||
bandwidth = accruedBandwidth;
|
||||
entropy = accruedEntropy;
|
||||
if (rewardsSettled)
|
||||
bandwidth = _accruedBandwidth;
|
||||
entropy = _accruedEntropy;
|
||||
if (_rewardsSettled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rewardsSettled = true;
|
||||
_rewardsSettled = true;
|
||||
return bandwidth > 0 || entropy > 0;
|
||||
}
|
||||
|
||||
private void HandleWaveCleared(WaveClearedEvent payload)
|
||||
{
|
||||
int clearedWave = Mathf.Max(1, payload.WaveNumber);
|
||||
wavesCleared = Mathf.Max(wavesCleared, clearedWave);
|
||||
accruedBandwidth += CalculateBandwidthReward(clearedWave);
|
||||
accruedEntropy += CalculateEntropyReward(clearedWave);
|
||||
_wavesCleared = Mathf.Max(_wavesCleared, clearedWave);
|
||||
_accruedBandwidth += CalculateBandwidthReward(clearedWave);
|
||||
_accruedEntropy += CalculateEntropyReward(clearedWave);
|
||||
currentWaveNumber = Mathf.Max(currentWaveNumber + 1, payload.WaveNumber + 1);
|
||||
repositoryOffers.Clear();
|
||||
rerollsThisVisit = 0;
|
||||
soldOfferKeys.Clear();
|
||||
repositoryVisitActive = false;
|
||||
_repositoryOffers.Clear();
|
||||
_rerollsThisVisit = 0;
|
||||
_soldOfferKeys.Clear();
|
||||
_repositoryVisitActive = false;
|
||||
GameEvents.RaiseWaveAdvanced(new WaveAdvancedEvent(currentWaveNumber));
|
||||
}
|
||||
|
||||
@@ -268,13 +268,13 @@ namespace KernelPanic.Run
|
||||
{
|
||||
isRunActive = false;
|
||||
isPlayerDead = payload.PlayerDied;
|
||||
bits = 0;
|
||||
repositoryOffers.Clear();
|
||||
repositoryVisitActive = false;
|
||||
runDeck.Clear();
|
||||
maxUptimeBonus = 0;
|
||||
maxCyclesBonus = 0;
|
||||
ramBonus = 0;
|
||||
_bits = 0;
|
||||
_repositoryOffers.Clear();
|
||||
_repositoryVisitActive = false;
|
||||
_runDeck.Clear();
|
||||
_maxUptimeBonus = 0;
|
||||
_maxCyclesBonus = 0;
|
||||
_ramBonus = 0;
|
||||
RepositoryChanged?.Invoke();
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace KernelPanic.Run
|
||||
|
||||
private void InitializeRunDeck(RunConfig config)
|
||||
{
|
||||
runDeck.Clear();
|
||||
_runDeck.Clear();
|
||||
if (config?.StartingDeck == null)
|
||||
{
|
||||
return;
|
||||
@@ -302,7 +302,7 @@ namespace KernelPanic.Run
|
||||
CardDefinition definition = config.StartingDeck[i];
|
||||
if (definition != null && !definition.IsRunOnly)
|
||||
{
|
||||
runDeck.Add(new CardInstance(definition));
|
||||
_runDeck.Add(new CardInstance(definition));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,16 +310,16 @@ namespace KernelPanic.Run
|
||||
private void FillRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
|
||||
{
|
||||
int guard = 0;
|
||||
while (repositoryOffers.Count < CombatTuning.ShopSize && guard < 80)
|
||||
while (_repositoryOffers.Count < CombatTuning.ShopSize && guard < 80)
|
||||
{
|
||||
guard++;
|
||||
RepositoryOffer offer = CreateRandomOffer(cardDatabase, languageDeckDatabase);
|
||||
if (offer == null || soldOfferKeys.Contains(OfferKey(offer)) || repositoryOffers.Any(existing => IsDuplicateOffer(existing, offer)))
|
||||
if (offer == null || _soldOfferKeys.Contains(OfferKey(offer)) || _repositoryOffers.Any(existing => IsDuplicateOffer(existing, offer)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
repositoryOffers.Add(offer);
|
||||
_repositoryOffers.Add(offer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace KernelPanic.Run
|
||||
|
||||
private RepositoryOffer CreateUpgradeOffer()
|
||||
{
|
||||
List<CardInstance> candidates = runDeck.Where(card => card != null && card.CanReceiveRepositoryUpgrade).ToList();
|
||||
List<CardInstance> candidates = _runDeck.Where(card => card != null && card.CanReceiveRepositoryUpgrade).ToList();
|
||||
if (candidates.Count == 0)
|
||||
{
|
||||
return CreateStatOffer();
|
||||
@@ -463,7 +463,7 @@ namespace KernelPanic.Run
|
||||
return false;
|
||||
}
|
||||
|
||||
runDeck.Add(new CardInstance(card));
|
||||
_runDeck.Add(new CardInstance(card));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ namespace KernelPanic.Run
|
||||
switch (kind)
|
||||
{
|
||||
case RunStatUpgradeKind.MaxCycles:
|
||||
maxCyclesBonus += CombatTuning.StatUpgradeMaxCycles;
|
||||
_maxCyclesBonus += CombatTuning.StatUpgradeMaxCycles;
|
||||
if (playerState != null)
|
||||
{
|
||||
playerState.MaxCycles += CombatTuning.StatUpgradeMaxCycles;
|
||||
@@ -496,7 +496,7 @@ namespace KernelPanic.Run
|
||||
}
|
||||
return true;
|
||||
case RunStatUpgradeKind.MaxUptime:
|
||||
maxUptimeBonus += CombatTuning.StatUpgradeMaxUptime;
|
||||
_maxUptimeBonus += CombatTuning.StatUpgradeMaxUptime;
|
||||
if (playerState != null)
|
||||
{
|
||||
playerState.MaxUptime += CombatTuning.StatUpgradeMaxUptime;
|
||||
@@ -511,7 +511,7 @@ namespace KernelPanic.Run
|
||||
playerState.CurrentUptime = Mathf.Min(playerState.MaxUptime, playerState.CurrentUptime + CombatTuning.StatUpgradeHeal);
|
||||
return true;
|
||||
case RunStatUpgradeKind.Ram:
|
||||
ramBonus += CombatTuning.StatUpgradeRam;
|
||||
_ramBonus += CombatTuning.StatUpgradeRam;
|
||||
if (playerState != null)
|
||||
{
|
||||
playerState.Ram += CombatTuning.StatUpgradeRam;
|
||||
@@ -525,9 +525,9 @@ namespace KernelPanic.Run
|
||||
|
||||
public struct PackageStatImpact
|
||||
{
|
||||
private readonly List<string> uptimeSources;
|
||||
private readonly List<string> ramSources;
|
||||
private readonly List<string> cyclesSources;
|
||||
private readonly List<string> _uptimeSources;
|
||||
private readonly List<string> _ramSources;
|
||||
private readonly List<string> _cyclesSources;
|
||||
|
||||
public PackageStatImpact(int baseUptime, int baseRam, int baseCycles)
|
||||
{
|
||||
@@ -537,9 +537,9 @@ namespace KernelPanic.Run
|
||||
UptimeBonus = 0;
|
||||
RamBonus = 0;
|
||||
CyclesBonus = 0;
|
||||
uptimeSources = new List<string>();
|
||||
ramSources = new List<string>();
|
||||
cyclesSources = new List<string>();
|
||||
_uptimeSources = new List<string>();
|
||||
_ramSources = new List<string>();
|
||||
_cyclesSources = new List<string>();
|
||||
}
|
||||
|
||||
public int BaseUptime { get; }
|
||||
@@ -551,9 +551,9 @@ namespace KernelPanic.Run
|
||||
public int FinalUptime => Mathf.Max(1, BaseUptime + UptimeBonus);
|
||||
public int FinalRam => Mathf.Max(1, BaseRam + RamBonus);
|
||||
public int FinalCycles => Mathf.Max(1, BaseCycles + CyclesBonus);
|
||||
public IReadOnlyList<string> UptimeSources => uptimeSources;
|
||||
public IReadOnlyList<string> RamSources => ramSources;
|
||||
public IReadOnlyList<string> CyclesSources => cyclesSources;
|
||||
public IReadOnlyList<string> UptimeSources => _uptimeSources;
|
||||
public IReadOnlyList<string> RamSources => _ramSources;
|
||||
public IReadOnlyList<string> CyclesSources => _cyclesSources;
|
||||
|
||||
public void AddUptime(int amount, PackageDefinition source)
|
||||
{
|
||||
@@ -563,7 +563,7 @@ namespace KernelPanic.Run
|
||||
}
|
||||
|
||||
UptimeBonus += amount;
|
||||
AddSource(source, uptimeSources);
|
||||
AddSource(source, _uptimeSources);
|
||||
}
|
||||
|
||||
public void AddRam(int amount, PackageDefinition source)
|
||||
@@ -574,7 +574,7 @@ namespace KernelPanic.Run
|
||||
}
|
||||
|
||||
RamBonus += amount;
|
||||
AddSource(source, ramSources);
|
||||
AddSource(source, _ramSources);
|
||||
}
|
||||
|
||||
public void AddCycles(int amount, PackageDefinition source)
|
||||
@@ -585,7 +585,7 @@ namespace KernelPanic.Run
|
||||
}
|
||||
|
||||
CyclesBonus += amount;
|
||||
AddSource(source, cyclesSources);
|
||||
AddSource(source, _cyclesSources);
|
||||
}
|
||||
|
||||
private static void AddSource(PackageDefinition source, List<string> sources)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,53 +33,53 @@ namespace KernelPanic.UI
|
||||
private const int SummaryTickSteps = 8;
|
||||
private const int SummaryTickMs = 220;
|
||||
|
||||
private readonly List<CompletedGachaReward> rewards = new();
|
||||
private readonly List<PullCardView> cardViews = new();
|
||||
private UIDocument document;
|
||||
private VisualElement root;
|
||||
private Label commandLabel;
|
||||
private Label costLabel;
|
||||
private Label flourishLabel;
|
||||
private Label skipHint;
|
||||
private VisualElement resultGrid;
|
||||
private VisualElement effectLayer;
|
||||
private VisualElement goldShimmer;
|
||||
private VisualElement summaryPanel;
|
||||
private Label summaryTotalsLabel;
|
||||
private Button continueButton;
|
||||
private string completedHeader;
|
||||
private bool skipRequested;
|
||||
private bool revealComplete;
|
||||
private bool failed;
|
||||
private readonly List<CompletedGachaReward> _rewards = new();
|
||||
private readonly List<PullCardView> _cardViews = new();
|
||||
private UIDocument _document;
|
||||
private VisualElement _root;
|
||||
private Label _commandLabel;
|
||||
private Label _costLabel;
|
||||
private Label _flourishLabel;
|
||||
private Label _skipHint;
|
||||
private VisualElement _resultGrid;
|
||||
private VisualElement _effectLayer;
|
||||
private VisualElement _goldShimmer;
|
||||
private VisualElement _summaryPanel;
|
||||
private Label _summaryTotalsLabel;
|
||||
private Button _continueButton;
|
||||
private string _completedHeader;
|
||||
private bool _skipRequested;
|
||||
private bool _revealComplete;
|
||||
private bool _failed;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
document = GetComponent<UIDocument>();
|
||||
root = document.rootVisualElement;
|
||||
root.Clear();
|
||||
root.focusable = true;
|
||||
root.AddToClassList("gambling-root");
|
||||
root.EnableInClassList("reduced-motion", UIPreferences.ReducedMotion);
|
||||
_document = GetComponent<UIDocument>();
|
||||
_root = _document.rootVisualElement;
|
||||
_root.Clear();
|
||||
_root.focusable = true;
|
||||
_root.AddToClassList("gambling-root");
|
||||
_root.EnableInClassList("reduced-motion", UIPreferences.ReducedMotion);
|
||||
LoadStyles();
|
||||
BuildLayout();
|
||||
root.RegisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
root.RegisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
_root.RegisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
_root.RegisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (root == null)
|
||||
if (_root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
root.UnregisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
root.UnregisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
_root.UnregisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
_root.UnregisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
root.Focus();
|
||||
_root.Focus();
|
||||
StartCoroutine(RunCutscene());
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace KernelPanic.UI
|
||||
StyleSheet styleSheet = Resources.Load<StyleSheet>(resourcePath);
|
||||
if (styleSheet != null)
|
||||
{
|
||||
root.styleSheets.Add(styleSheet);
|
||||
_root.styleSheets.Add(styleSheet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace KernelPanic.UI
|
||||
{
|
||||
VisualElement shell = new();
|
||||
shell.AddToClassList("gambling-shell");
|
||||
root.Add(shell);
|
||||
_root.Add(shell);
|
||||
|
||||
VisualElement frame = new();
|
||||
frame.AddToClassList("gambling-frame");
|
||||
@@ -117,76 +117,76 @@ namespace KernelPanic.UI
|
||||
titleBlock.AddToClassList("gambling-title-block");
|
||||
header.Add(titleBlock);
|
||||
|
||||
commandLabel = new("git pull");
|
||||
commandLabel.AddToClassList("gambling-command");
|
||||
titleBlock.Add(commandLabel);
|
||||
_commandLabel = new("git pull");
|
||||
_commandLabel.AddToClassList("gambling-command");
|
||||
titleBlock.Add(_commandLabel);
|
||||
|
||||
costLabel = new();
|
||||
costLabel.AddToClassList("gambling-cost");
|
||||
titleBlock.Add(costLabel);
|
||||
_costLabel = new();
|
||||
_costLabel.AddToClassList("gambling-cost");
|
||||
titleBlock.Add(_costLabel);
|
||||
|
||||
skipHint = new("[tap/key] reveal all");
|
||||
skipHint.AddToClassList("gambling-skip");
|
||||
header.Add(skipHint);
|
||||
_skipHint = new("[tap/key] reveal all");
|
||||
_skipHint.AddToClassList("gambling-skip");
|
||||
header.Add(_skipHint);
|
||||
|
||||
flourishLabel = new();
|
||||
flourishLabel.AddToClassList("gambling-flourish");
|
||||
frame.Add(flourishLabel);
|
||||
_flourishLabel = new();
|
||||
_flourishLabel.AddToClassList("gambling-flourish");
|
||||
frame.Add(_flourishLabel);
|
||||
|
||||
resultGrid = new VisualElement();
|
||||
resultGrid.AddToClassList("gambling-results");
|
||||
frame.Add(resultGrid);
|
||||
_resultGrid = new VisualElement();
|
||||
_resultGrid.AddToClassList("gambling-results");
|
||||
frame.Add(_resultGrid);
|
||||
|
||||
goldShimmer = new VisualElement();
|
||||
goldShimmer.AddToClassList("gold-shimmer");
|
||||
goldShimmer.pickingMode = PickingMode.Ignore;
|
||||
frame.Add(goldShimmer);
|
||||
_goldShimmer = new VisualElement();
|
||||
_goldShimmer.AddToClassList("gold-shimmer");
|
||||
_goldShimmer.pickingMode = PickingMode.Ignore;
|
||||
frame.Add(_goldShimmer);
|
||||
|
||||
effectLayer = new VisualElement();
|
||||
effectLayer.AddToClassList("effect-layer");
|
||||
effectLayer.pickingMode = PickingMode.Ignore;
|
||||
frame.Add(effectLayer);
|
||||
_effectLayer = new VisualElement();
|
||||
_effectLayer.AddToClassList("effect-layer");
|
||||
_effectLayer.pickingMode = PickingMode.Ignore;
|
||||
frame.Add(_effectLayer);
|
||||
|
||||
summaryPanel = new VisualElement();
|
||||
summaryPanel.AddToClassList("summary-panel");
|
||||
summaryPanel.AddToClassList("hidden");
|
||||
frame.Add(summaryPanel);
|
||||
_summaryPanel = new VisualElement();
|
||||
_summaryPanel.AddToClassList("summary-panel");
|
||||
_summaryPanel.AddToClassList("hidden");
|
||||
frame.Add(_summaryPanel);
|
||||
|
||||
continueButton = new Button(ContinueToMenu) { text = "> continue" };
|
||||
continueButton.AddToClassList("continue-button");
|
||||
continueButton.AddToClassList("continue-button-pending");
|
||||
continueButton.SetEnabled(false);
|
||||
frame.Add(continueButton);
|
||||
_continueButton = new Button(ContinueToMenu) { text = "> continue" };
|
||||
_continueButton.AddToClassList("continue-button");
|
||||
_continueButton.AddToClassList("continue-button-pending");
|
||||
_continueButton.SetEnabled(false);
|
||||
frame.Add(_continueButton);
|
||||
}
|
||||
|
||||
private IEnumerator RunCutscene()
|
||||
{
|
||||
if (!GachaPullContext.TryConsumePending(out PendingGachaPull pending))
|
||||
{
|
||||
failed = true;
|
||||
commandLabel.text = "git pull failed";
|
||||
costLabel.text = "no pending pull";
|
||||
_failed = true;
|
||||
_commandLabel.text = "git pull failed";
|
||||
_costLabel.text = "no pending pull";
|
||||
ShowContinue();
|
||||
yield break;
|
||||
}
|
||||
|
||||
commandLabel.text = pending.PullCount == 10 ? "git pull --ten" : "git pull --single";
|
||||
_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
|
||||
_costLabel.text = pending.EntropyTokenCount > 0
|
||||
? $"cost: {pending.EntropyTokenCount * GachaService.EntropyPerCommit} Entropy"
|
||||
: $"cost: {pullCost} Commits / {pullCost * GachaService.EntropyPerCommit} Entropy";
|
||||
flourishLabel.text = "$ fetch-pack | verify | unpack";
|
||||
_flourishLabel.text = "$ fetch-pack | verify | unpack";
|
||||
|
||||
CompletedGachaPull completed = ResolvePull(pending);
|
||||
GachaPullContext.SetCompleted(completed);
|
||||
completedHeader = completed.HeaderText;
|
||||
rewards.Clear();
|
||||
rewards.AddRange(completed.Rewards);
|
||||
_completedHeader = completed.HeaderText;
|
||||
_rewards.Clear();
|
||||
_rewards.AddRange(completed.Rewards);
|
||||
|
||||
if (rewards.Count == 0)
|
||||
if (_rewards.Count == 0)
|
||||
{
|
||||
failed = true;
|
||||
costLabel.text = completed.HeaderText;
|
||||
_failed = true;
|
||||
_costLabel.text = completed.HeaderText;
|
||||
ShowContinue();
|
||||
yield break;
|
||||
}
|
||||
@@ -199,24 +199,24 @@ namespace KernelPanic.UI
|
||||
}
|
||||
|
||||
yield return WaitOrSkip(FlourishMs);
|
||||
flourishLabel.text = "$ unpacking sealed objects";
|
||||
for (int i = 0; i < rewards.Count; i++)
|
||||
_flourishLabel.text = "$ unpacking sealed objects";
|
||||
for (int i = 0; i < _rewards.Count; i++)
|
||||
{
|
||||
if (skipRequested)
|
||||
if (_skipRequested)
|
||||
{
|
||||
RevealAll();
|
||||
yield break;
|
||||
}
|
||||
|
||||
CompletedGachaReward reward = rewards[i];
|
||||
PullCardView card = cardViews[i];
|
||||
CompletedGachaReward reward = _rewards[i];
|
||||
PullCardView card = _cardViews[i];
|
||||
int holdMs = GetAnticipationMs(reward.Stars);
|
||||
if (holdMs > 0)
|
||||
{
|
||||
ApplyGridFocus(i, reward.Stars);
|
||||
card.ShowHold(reward.Stars >= 5 ? "........ signed tag" : "... promoted object", reward.Stars);
|
||||
yield return WaitOrSkip(holdMs);
|
||||
if (skipRequested)
|
||||
if (_skipRequested)
|
||||
{
|
||||
RevealAll();
|
||||
yield break;
|
||||
@@ -315,25 +315,25 @@ namespace KernelPanic.UI
|
||||
|
||||
private void BuildRows()
|
||||
{
|
||||
resultGrid.Clear();
|
||||
cardViews.Clear();
|
||||
for (int i = 0; i < rewards.Count; i++)
|
||||
_resultGrid.Clear();
|
||||
_cardViews.Clear();
|
||||
for (int i = 0; i < _rewards.Count; i++)
|
||||
{
|
||||
PullCardView card = new(rewards[i]);
|
||||
cardViews.Add(card);
|
||||
resultGrid.Add(card.Root);
|
||||
PullCardView card = new(_rewards[i]);
|
||||
_cardViews.Add(card);
|
||||
_resultGrid.Add(card.Root);
|
||||
}
|
||||
}
|
||||
|
||||
private void RevealAll()
|
||||
{
|
||||
skipRequested = true;
|
||||
_skipRequested = true;
|
||||
ClearGridFocus();
|
||||
goldShimmer.RemoveFromClassList("gold-shimmer-on");
|
||||
for (int i = 0; i < cardViews.Count; i++)
|
||||
_goldShimmer.RemoveFromClassList("gold-shimmer-on");
|
||||
for (int i = 0; i < _cardViews.Count; i++)
|
||||
{
|
||||
cardViews[i].HideHold();
|
||||
cardViews[i].Reveal(allowFlash: false, persistentMotion: !UIPreferences.ReducedMotion);
|
||||
_cardViews[i].HideHold();
|
||||
_cardViews[i].Reveal(allowFlash: false, persistentMotion: !UIPreferences.ReducedMotion);
|
||||
}
|
||||
|
||||
CompleteReveal();
|
||||
@@ -341,49 +341,49 @@ namespace KernelPanic.UI
|
||||
|
||||
private void CompleteReveal()
|
||||
{
|
||||
if (revealComplete)
|
||||
if (_revealComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
revealComplete = true;
|
||||
skipHint.text = "complete";
|
||||
flourishLabel.text = completedHeader;
|
||||
flourishLabel.AddToClassList("gambling-flourish-complete");
|
||||
BuildSummary(animate: !skipRequested && !UIPreferences.ReducedMotion);
|
||||
_revealComplete = true;
|
||||
_skipHint.text = "complete";
|
||||
_flourishLabel.text = _completedHeader;
|
||||
_flourishLabel.AddToClassList("gambling-flourish-complete");
|
||||
BuildSummary(animate: !_skipRequested && !UIPreferences.ReducedMotion);
|
||||
ShowContinue();
|
||||
}
|
||||
|
||||
private void BuildSummary(bool animate)
|
||||
{
|
||||
summaryPanel.Clear();
|
||||
summaryPanel.RemoveFromClassList("hidden");
|
||||
summaryTotalsLabel = new Label { name = "PullSummaryTotals" };
|
||||
summaryTotalsLabel.AddToClassList("summary-totals");
|
||||
summaryPanel.Add(summaryTotalsLabel);
|
||||
_summaryPanel.Clear();
|
||||
_summaryPanel.RemoveFromClassList("hidden");
|
||||
_summaryTotalsLabel = new Label { name = "PullSummaryTotals" };
|
||||
_summaryTotalsLabel.AddToClassList("summary-totals");
|
||||
_summaryPanel.Add(_summaryTotalsLabel);
|
||||
|
||||
SummaryTotals totals = CalculateTotals();
|
||||
if (!animate)
|
||||
{
|
||||
summaryTotalsLabel.text = FormatTotals(totals.Units, totals.Merges, totals.Cache, totals.LanguagesText);
|
||||
_summaryTotalsLabel.text = FormatTotals(totals.Units, totals.Merges, totals.Cache, totals.LanguagesText);
|
||||
return;
|
||||
}
|
||||
|
||||
summaryTotalsLabel.AddToClassList("summary-tick");
|
||||
_summaryTotalsLabel.AddToClassList("summary-tick");
|
||||
for (int step = 0; step <= SummaryTickSteps; step++)
|
||||
{
|
||||
int capturedStep = step;
|
||||
int delay = Mathf.RoundToInt((SummaryTickMs / (float)SummaryTickSteps) * capturedStep);
|
||||
summaryTotalsLabel.schedule.Execute(() =>
|
||||
_summaryTotalsLabel.schedule.Execute(() =>
|
||||
{
|
||||
float t = capturedStep / (float)SummaryTickSteps;
|
||||
int units = Mathf.RoundToInt(Mathf.Lerp(0, totals.Units, t));
|
||||
int merges = Mathf.RoundToInt(Mathf.Lerp(0, totals.Merges, t));
|
||||
int cache = Mathf.RoundToInt(Mathf.Lerp(0, totals.Cache, t));
|
||||
summaryTotalsLabel.text = FormatTotals(units, merges, cache, capturedStep == SummaryTickSteps ? totals.LanguagesText : "...");
|
||||
_summaryTotalsLabel.text = FormatTotals(units, merges, cache, capturedStep == SummaryTickSteps ? totals.LanguagesText : "...");
|
||||
if (capturedStep == SummaryTickSteps)
|
||||
{
|
||||
summaryTotalsLabel.RemoveFromClassList("summary-tick");
|
||||
_summaryTotalsLabel.RemoveFromClassList("summary-tick");
|
||||
}
|
||||
}).StartingIn(delay);
|
||||
}
|
||||
@@ -395,25 +395,25 @@ namespace KernelPanic.UI
|
||||
int merges = 0;
|
||||
int cache = 0;
|
||||
HashSet<Language> languages = new();
|
||||
for (int i = 0; i < rewards.Count; i++)
|
||||
for (int i = 0; i < _rewards.Count; i++)
|
||||
{
|
||||
if (rewards[i].OutcomeKind == PullOutcomeKind.Granted && rewards[i].IsCharacter)
|
||||
if (_rewards[i].OutcomeKind == PullOutcomeKind.Granted && _rewards[i].IsCharacter)
|
||||
{
|
||||
units++;
|
||||
}
|
||||
|
||||
if (rewards[i].RewardType == GachaRewardType.Package)
|
||||
if (_rewards[i].RewardType == GachaRewardType.Package)
|
||||
{
|
||||
cache += rewards[i].MergesAwarded;
|
||||
cache += _rewards[i].MergesAwarded;
|
||||
}
|
||||
else
|
||||
{
|
||||
merges += rewards[i].MergesAwarded;
|
||||
merges += _rewards[i].MergesAwarded;
|
||||
}
|
||||
|
||||
for (int languageIndex = 0; languageIndex < rewards[i].LanguagesUnlocked.Count; languageIndex++)
|
||||
for (int languageIndex = 0; languageIndex < _rewards[i].LanguagesUnlocked.Count; languageIndex++)
|
||||
{
|
||||
languages.Add(rewards[i].LanguagesUnlocked[languageIndex]);
|
||||
languages.Add(_rewards[i].LanguagesUnlocked[languageIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ namespace KernelPanic.UI
|
||||
{
|
||||
float elapsed = 0f;
|
||||
float duration = Mathf.Max(0f, milliseconds / 1000f);
|
||||
while (!skipRequested && elapsed < duration)
|
||||
while (!_skipRequested && elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
@@ -615,17 +615,17 @@ namespace KernelPanic.UI
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cardViews.Count; i++)
|
||||
for (int i = 0; i < _cardViews.Count; i++)
|
||||
{
|
||||
cardViews[i].SetDimmed(i != focusedIndex);
|
||||
_cardViews[i].SetDimmed(i != focusedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearGridFocus()
|
||||
{
|
||||
for (int i = 0; i < cardViews.Count; i++)
|
||||
for (int i = 0; i < _cardViews.Count; i++)
|
||||
{
|
||||
cardViews[i].SetDimmed(false);
|
||||
_cardViews[i].SetDimmed(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,32 +656,32 @@ namespace KernelPanic.UI
|
||||
|
||||
private void PlayGoldShimmer(VisualElement source)
|
||||
{
|
||||
if (source == null || goldShimmer?.parent == null)
|
||||
if (source == null || _goldShimmer?.parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rect sourceBounds = source.worldBound;
|
||||
Rect parentBounds = goldShimmer.parent.worldBound;
|
||||
Rect parentBounds = _goldShimmer.parent.worldBound;
|
||||
float left = Mathf.Max(0f, sourceBounds.x - parentBounds.x);
|
||||
float top = Mathf.Max(0f, sourceBounds.y - parentBounds.y);
|
||||
goldShimmer.style.left = left;
|
||||
goldShimmer.style.top = top;
|
||||
goldShimmer.style.width = sourceBounds.width;
|
||||
goldShimmer.style.height = sourceBounds.height;
|
||||
goldShimmer.AddToClassList("gold-shimmer-on");
|
||||
goldShimmer.schedule.Execute(() => goldShimmer.RemoveFromClassList("gold-shimmer-on")).StartingIn(LegendaryShimmerMs);
|
||||
_goldShimmer.style.left = left;
|
||||
_goldShimmer.style.top = top;
|
||||
_goldShimmer.style.width = sourceBounds.width;
|
||||
_goldShimmer.style.height = sourceBounds.height;
|
||||
_goldShimmer.AddToClassList("gold-shimmer-on");
|
||||
_goldShimmer.schedule.Execute(() => _goldShimmer.RemoveFromClassList("gold-shimmer-on")).StartingIn(LegendaryShimmerMs);
|
||||
}
|
||||
|
||||
private void EmitSparks(VisualElement source, Color color, int count, float radius)
|
||||
{
|
||||
if (effectLayer == null || source == null)
|
||||
if (_effectLayer == null || source == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rect sourceBounds = source.worldBound;
|
||||
Rect layerBounds = effectLayer.worldBound;
|
||||
Rect layerBounds = _effectLayer.worldBound;
|
||||
float centerX = sourceBounds.center.x - layerBounds.x;
|
||||
float centerY = sourceBounds.center.y - layerBounds.y;
|
||||
float halfWidth = sourceBounds.width * 0.5f;
|
||||
@@ -728,41 +728,41 @@ namespace KernelPanic.UI
|
||||
VisualElement spark = new();
|
||||
spark.pickingMode = PickingMode.Ignore;
|
||||
spark.AddToClassList("spark");
|
||||
effectLayer.Add(spark);
|
||||
_effectLayer.Add(spark);
|
||||
return spark;
|
||||
}
|
||||
|
||||
private void HandleKeyDown(KeyDownEvent evt)
|
||||
{
|
||||
if (revealComplete)
|
||||
if (_revealComplete)
|
||||
{
|
||||
ContinueToMenu();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
skipRequested = true;
|
||||
_skipRequested = true;
|
||||
evt.StopPropagation();
|
||||
}
|
||||
|
||||
private void HandlePointerDown(PointerDownEvent evt)
|
||||
{
|
||||
if (revealComplete)
|
||||
if (_revealComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
skipRequested = true;
|
||||
_skipRequested = true;
|
||||
evt.StopPropagation();
|
||||
}
|
||||
|
||||
private void ShowContinue()
|
||||
{
|
||||
continueButton.SetEnabled(true);
|
||||
continueButton.RemoveFromClassList("continue-button-pending");
|
||||
if (failed)
|
||||
_continueButton.SetEnabled(true);
|
||||
_continueButton.RemoveFromClassList("continue-button-pending");
|
||||
if (_failed)
|
||||
{
|
||||
skipHint.text = "failed";
|
||||
_skipHint.text = "failed";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,17 +789,17 @@ namespace KernelPanic.UI
|
||||
|
||||
private sealed class PullCardView
|
||||
{
|
||||
private readonly CompletedGachaReward reward;
|
||||
private readonly Label rarityLabel;
|
||||
private readonly Label nameLabel;
|
||||
private readonly Label statusLabel;
|
||||
private readonly Label typeIconLabel;
|
||||
private IVisualElementScheduledItem glowPulse;
|
||||
private bool glowOn;
|
||||
private readonly CompletedGachaReward _reward;
|
||||
private readonly Label _rarityLabel;
|
||||
private readonly Label _nameLabel;
|
||||
private readonly Label _statusLabel;
|
||||
private readonly Label _typeIconLabel;
|
||||
private IVisualElementScheduledItem _glowPulse;
|
||||
private bool _glowOn;
|
||||
|
||||
public PullCardView(CompletedGachaReward reward)
|
||||
{
|
||||
this.reward = reward;
|
||||
this._reward = reward;
|
||||
RarityStyle rarity = RarityPresentation.ForStars(reward.Stars);
|
||||
Root = new VisualElement();
|
||||
Root.AddToClassList("pull-card");
|
||||
@@ -814,27 +814,27 @@ namespace KernelPanic.UI
|
||||
indexLabel.AddToClassList("pull-index");
|
||||
top.Add(indexLabel);
|
||||
|
||||
rarityLabel = new(rarity.Stars);
|
||||
rarityLabel.AddToClassList("pull-rarity");
|
||||
rarityLabel.AddToClassList(rarity.ClassName);
|
||||
top.Add(rarityLabel);
|
||||
_rarityLabel = new(rarity.Stars);
|
||||
_rarityLabel.AddToClassList("pull-rarity");
|
||||
_rarityLabel.AddToClassList(rarity.ClassName);
|
||||
top.Add(_rarityLabel);
|
||||
|
||||
typeIconLabel = new(reward.IsCharacter ? "@" : "#");
|
||||
typeIconLabel.tooltip = reward.TypeText;
|
||||
typeIconLabel.AddToClassList("pull-type-icon");
|
||||
top.Add(typeIconLabel);
|
||||
_typeIconLabel = new(reward.IsCharacter ? "@" : "#");
|
||||
_typeIconLabel.tooltip = reward.TypeText;
|
||||
_typeIconLabel.AddToClassList("pull-type-icon");
|
||||
top.Add(_typeIconLabel);
|
||||
|
||||
nameLabel = new(reward.DisplayName);
|
||||
nameLabel.AddToClassList("pull-name");
|
||||
Root.Add(nameLabel);
|
||||
_nameLabel = new(reward.DisplayName);
|
||||
_nameLabel.AddToClassList("pull-name");
|
||||
Root.Add(_nameLabel);
|
||||
|
||||
statusLabel = new(reward.StatusText);
|
||||
statusLabel.AddToClassList("pull-status");
|
||||
statusLabel.EnableInClassList("pull-status-new", reward.OutcomeKind == PullOutcomeKind.Granted);
|
||||
statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText);
|
||||
if (statusLabel.visible)
|
||||
_statusLabel = new(reward.StatusText);
|
||||
_statusLabel.AddToClassList("pull-status");
|
||||
_statusLabel.EnableInClassList("pull-status-new", reward.OutcomeKind == PullOutcomeKind.Granted);
|
||||
_statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText);
|
||||
if (_statusLabel.visible)
|
||||
{
|
||||
Root.Add(statusLabel);
|
||||
Root.Add(_statusLabel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,11 +846,11 @@ namespace KernelPanic.UI
|
||||
Root.AddToClassList("pull-card-held");
|
||||
Root.EnableInClassList("pull-card-held-rare", stars == 4);
|
||||
Root.EnableInClassList("pull-card-held-legendary", stars >= 5);
|
||||
rarityLabel.text = "...";
|
||||
nameLabel.text = holdText;
|
||||
statusLabel.text = "";
|
||||
statusLabel.visible = false;
|
||||
typeIconLabel.visible = false;
|
||||
_rarityLabel.text = "...";
|
||||
_nameLabel.text = holdText;
|
||||
_statusLabel.text = "";
|
||||
_statusLabel.visible = false;
|
||||
_typeIconLabel.visible = false;
|
||||
}
|
||||
|
||||
public void HideHold()
|
||||
@@ -862,21 +862,21 @@ namespace KernelPanic.UI
|
||||
|
||||
public void Reveal(bool allowFlash, bool persistentMotion)
|
||||
{
|
||||
RarityStyle rarity = RarityPresentation.ForStars(reward.Stars);
|
||||
RarityStyle rarity = RarityPresentation.ForStars(_reward.Stars);
|
||||
Root.RemoveFromClassList("pull-card-hidden");
|
||||
Root.RemoveFromClassList("pull-card-held");
|
||||
Root.RemoveFromClassList("pull-card-held-rare");
|
||||
Root.RemoveFromClassList("pull-card-held-legendary");
|
||||
Root.AddToClassList("pull-card-revealed");
|
||||
Root.EnableInClassList("pull-card-glow-4", persistentMotion && reward.Stars == 4);
|
||||
Root.EnableInClassList("pull-card-glow-5", persistentMotion && reward.Stars >= 5);
|
||||
SetPersistentGlow(persistentMotion && reward.Stars >= 5);
|
||||
rarityLabel.text = reward.Stars >= 5 ? $"{rarity.Badge} {rarity.Stars}" : rarity.Stars;
|
||||
nameLabel.text = reward.DisplayName;
|
||||
typeIconLabel.text = reward.IsCharacter ? "@" : "#";
|
||||
typeIconLabel.visible = true;
|
||||
statusLabel.text = reward.StatusText;
|
||||
statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText);
|
||||
Root.EnableInClassList("pull-card-glow-4", persistentMotion && _reward.Stars == 4);
|
||||
Root.EnableInClassList("pull-card-glow-5", persistentMotion && _reward.Stars >= 5);
|
||||
SetPersistentGlow(persistentMotion && _reward.Stars >= 5);
|
||||
_rarityLabel.text = _reward.Stars >= 5 ? $"{rarity.Badge} {rarity.Stars}" : rarity.Stars;
|
||||
_nameLabel.text = _reward.DisplayName;
|
||||
_typeIconLabel.text = _reward.IsCharacter ? "@" : "#";
|
||||
_typeIconLabel.visible = true;
|
||||
_statusLabel.text = _reward.StatusText;
|
||||
_statusLabel.visible = !string.IsNullOrWhiteSpace(_reward.StatusText);
|
||||
if (allowFlash)
|
||||
{
|
||||
Root.AddToClassList("pull-card-flash");
|
||||
@@ -897,34 +897,34 @@ namespace KernelPanic.UI
|
||||
|
||||
public void PulseStatus(int durationMs)
|
||||
{
|
||||
if (!statusLabel.visible)
|
||||
if (!_statusLabel.visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
statusLabel.AddToClassList("pull-status-pop");
|
||||
statusLabel.schedule.Execute(() => statusLabel.RemoveFromClassList("pull-status-pop")).StartingIn(durationMs);
|
||||
_statusLabel.AddToClassList("pull-status-pop");
|
||||
_statusLabel.schedule.Execute(() => _statusLabel.RemoveFromClassList("pull-status-pop")).StartingIn(durationMs);
|
||||
}
|
||||
|
||||
private void SetPersistentGlow(bool enabled)
|
||||
{
|
||||
if (!enabled)
|
||||
{
|
||||
glowPulse?.Pause();
|
||||
_glowPulse?.Pause();
|
||||
Root.RemoveFromClassList("pull-card-glow-on");
|
||||
return;
|
||||
}
|
||||
|
||||
if (glowPulse != null)
|
||||
if (_glowPulse != null)
|
||||
{
|
||||
glowPulse.Resume();
|
||||
_glowPulse.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
glowPulse = Root.schedule.Execute(() =>
|
||||
_glowPulse = Root.schedule.Execute(() =>
|
||||
{
|
||||
glowOn = !glowOn;
|
||||
Root.EnableInClassList("pull-card-glow-on", glowOn);
|
||||
_glowOn = !_glowOn;
|
||||
Root.EnableInClassList("pull-card-glow-on", _glowOn);
|
||||
}).Every(900);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace KernelPanic.UI
|
||||
"Courier New"
|
||||
};
|
||||
|
||||
private static FontAsset runtimeMonospaceFont;
|
||||
private static bool warnedMissingFont;
|
||||
private static FontAsset _runtimeMonospaceFont;
|
||||
private static bool _warnedMissingFont;
|
||||
|
||||
public static FontAsset Resolve(FontAsset configuredFont)
|
||||
{
|
||||
@@ -38,25 +38,25 @@ namespace KernelPanic.UI
|
||||
return configuredFont;
|
||||
}
|
||||
|
||||
if (runtimeMonospaceFont != null)
|
||||
if (_runtimeMonospaceFont != null)
|
||||
{
|
||||
return runtimeMonospaceFont;
|
||||
return _runtimeMonospaceFont;
|
||||
}
|
||||
|
||||
Font dynamicFont = Font.CreateDynamicFontFromOSFont(PreferredMonospaceFontFamilies, 16);
|
||||
if (dynamicFont == null)
|
||||
{
|
||||
if (!warnedMissingFont)
|
||||
if (!_warnedMissingFont)
|
||||
{
|
||||
Debug.LogWarning("No monospace OS font found; terminal UI will use Unity's default font.");
|
||||
warnedMissingFont = true;
|
||||
_warnedMissingFont = true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
runtimeMonospaceFont = FontAsset.CreateFontAsset(dynamicFont);
|
||||
return runtimeMonospaceFont;
|
||||
_runtimeMonospaceFont = FontAsset.CreateFontAsset(dynamicFont);
|
||||
return _runtimeMonospaceFont;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,7 +667,7 @@ namespace KernelPanic.UI
|
||||
_saveData = _saveService.Load();
|
||||
// Snapshot before the next EnsureLists() call below, which re-runs NormalizeOwnedPackages
|
||||
// and would otherwise clear this (no new duplicates survive a second normalization pass).
|
||||
List<CollapsedPackageDuplicate> collapsedPackageDuplicates = new(_saveData.collapsedPackageDuplicates);
|
||||
List<CollapsedPackageDuplicate> collapsedPackageDuplicates = new(_saveData.CollapsedPackageDuplicates);
|
||||
_saveData.EnsureLists();
|
||||
_wallet.SetBalance(_saveData.entropyBalance);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user