Fix C, more enemies and less scaling for enemies.

This commit is contained in:
2026-07-09 20:02:37 +02:00
parent 1e53968c36
commit e3ea42c93e
24 changed files with 1582 additions and 1113 deletions
@@ -11,37 +11,30 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="4222a6b8-add3-4f43-9c42-fd6bb5a76169" name="Changes" comment=""> <list default="true" id="4222a6b8-add3-4f43-9c42-fd6bb5a76169" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Malloc.asset" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyArchetype.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Pointer.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Printf.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/CDeck.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Free.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/KernelExploit.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Sizeof.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Distros/Arch.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Distros/Art/arch.txt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Distros/Art/arch.txt.meta" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Packages/Aur.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Packages/Systemd.asset" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Assets/Data/Passives/IUseArchBtw.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.linuxdistrosbuttheyarebreedable/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.linuxdistrosbuttheyarebreedable/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.linuxdistrosbuttheyarebreedable/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.linuxdistrosbuttheyarebreedable/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/CardDatabase.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/CardDatabase.asset" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Malloc.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Malloc.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/LanguageDeckDatabase.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/LanguageDeckDatabase.asset" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Pointer.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Pointer.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Distros/DistroDatabase.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Distros/DistroDatabase.asset" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Printf.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Printf.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Packages/PackageDatabase.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Packages/PackageDatabase.asset" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Free.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Free.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Shop/KernelExploit.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/KernelExploit.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Sizeof.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Sizeof.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CardEffects.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CardEffects.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CardEffects.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CardEffects.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatContext.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatContext.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatManager.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatTuning.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatTuning.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatantState.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatantState.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatantState.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/CombatantState.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/DamagePipeline.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/DamagePipeline.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/DamagePipeline.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/DamagePipeline.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Data/PackageDefinition.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Data/PackageDefinition.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyInstance.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyInstance.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Meta/DistroVersionCatalog.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Meta/DistroVersionCatalog.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyIntent.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyIntent.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Meta/GachaService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Meta/GachaService.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Combat/RandomRoll.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/RandomRoll.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Meta/GachaPullContext.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Meta/GachaPullContext.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Meta/SaveService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Meta/SaveService.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Run/RunContext.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Run/RunContext.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Run/RunManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Run/RunManager.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Run/RunManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Run/RunManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/CollectionScreenController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/CollectionScreenController.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/CombatSceneController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/CombatSceneController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/GachaScreenController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/GachaScreenController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/GamblingSceneController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/GamblingSceneController.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/GamblingSceneController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/GamblingSceneController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/StarterSelectionController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/StarterSelectionController.cs" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -49,7 +42,7 @@
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </component>
<component name="EmbeddingIndexingInfo"> <component name="EmbeddingIndexingInfo">
<option name="cachedIndexableFilesCount" value="46" /> <option name="cachedIndexableFilesCount" value="48" />
<option name="fileBasedEmbeddingIndicesEnabled" value="true" /> <option name="fileBasedEmbeddingIndicesEnabled" value="true" />
</component> </component>
<component name="Git.Settings"> <component name="Git.Settings">
@@ -118,23 +111,23 @@
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" /> <component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="NextEditCompletionFeaturesState"> <component name="NextEditCompletionFeaturesState">
<decayedCancelled> <decayedCancelled>
<entry key="MS100" value="1.1040497809107481" /> <entry key="MS100" value="1.5438155496731856" />
<entry key="MS500" value="3.714798159570809" /> <entry key="MS500" value="5.416837026621939" />
<entry key="S2" value="11.68860568898124" /> <entry key="S2" value="12.668957872278758" />
<entry key="S5" value="20.10530350052927" /> <entry key="S5" value="16.026673635995547" />
<entry key="S10" value="26.13933097157673" /> <entry key="S10" value="17.426595593285192" />
<entry key="S30" value="32.13507287696936" /> <entry key="S30" value="18.454820586422397" />
<entry key="S60" value="34.35034847825896" /> <entry key="S60" value="18.72472582023672" />
<entry key="M2" value="41.829650528743535" /> <entry key="M2" value="18.86168439667557" />
<entry key="M5" value="82.9519319589652" /> <entry key="M5" value="18.95087896044715" />
<entry key="M10" value="147.82939685711494" /> <entry key="M10" value="19.972234082604384" />
<entry key="M15" value="193.49123741346352" /> <entry key="M15" value="25.48708802307527" />
<entry key="M30" value="274.2846911461227" /> <entry key="M30" value="70.33485962789716" />
<entry key="H1" value="385.98935725422314" /> <entry key="H1" value="193.24800336339004" />
<entry key="H2" value="566.2873520605849" /> <entry key="H2" value="411.97552826367775" />
<entry key="H4" value="919.4750522788173" /> <entry key="H4" value="796.6715755808564" />
<entry key="D1" value="3279.123798476327" /> <entry key="D1" value="3240.2139167478695" />
<entry key="W1" value="5478.811080497626" /> <entry key="W1" value="5547.574956248048" />
</decayedCancelled> </decayedCancelled>
<decayedSelected> <decayedSelected>
<entry key="MS100" value="0.0" /> <entry key="MS100" value="0.0" />
@@ -145,34 +138,34 @@
<entry key="S30" value="0.0" /> <entry key="S30" value="0.0" />
<entry key="S60" value="0.0" /> <entry key="S60" value="0.0" />
<entry key="M2" value="0.0" /> <entry key="M2" value="0.0" />
<entry key="M5" value="1.5957500715172193E-141" /> <entry key="M5" value="6.004482652781533E-147" />
<entry key="M10" value="3.994684056990454E-71" /> <entry key="M10" value="7.748859692098003E-74" />
<entry key="M15" value="1.1685706048432312E-47" /> <entry key="M15" value="1.817573009109616E-49" />
<entry key="M30" value="3.418437300700796E-24" /> <entry key="M30" value="4.263301749081961E-25" />
<entry key="H1" value="1.850719023980869E-12" /> <entry key="H1" value="6.535814477556539E-13" />
<entry key="H2" value="1.4335866743543608E-6" /> <entry key="H2" value="8.519293271851925E-7" />
<entry key="H4" value="0.0016367490238057612" /> <entry key="H4" value="0.0012617458857475668" />
<entry key="D1" value="1.0211424728874252" /> <entry key="D1" value="0.9778028711909533" />
<entry key="W1" value="3.2866828573220803" /> <entry key="W1" value="3.2663828053013284" />
</decayedSelected> </decayedSelected>
<decayedShown> <decayedShown>
<entry key="MS100" value="1.050513762775976" /> <entry key="MS100" value="1.4317187710347317" />
<entry key="MS500" value="3.6754429047622104" /> <entry key="MS500" value="5.34064632290837" />
<entry key="S2" value="11.65796718737336" /> <entry key="S2" value="12.621006367063478" />
<entry key="S5" value="20.084311060325582" /> <entry key="S5" value="16.001716646214877" />
<entry key="S10" value="26.125711482692548" /> <entry key="S10" value="17.412885614576528" />
<entry key="S30" value="32.12949996608303" /> <entry key="S30" value="18.449946114998543" />
<entry key="S60" value="34.34737056791278" /> <entry key="S60" value="18.722248425273893" />
<entry key="M2" value="41.827834097645756" /> <entry key="M2" value="18.860435494937665" />
<entry key="M5" value="82.95047510295649" /> <entry key="M5" value="18.95037608361192" />
<entry key="M10" value="147.82807658405247" /> <entry key="M10" value="19.971930307306003" />
<entry key="M15" value="193.49007535362955" /> <entry key="M15" value="25.486739213245762" />
<entry key="M30" value="274.283859325205" /> <entry key="M30" value="70.33427160959226" />
<entry key="H1" value="385.98877279131835" /> <entry key="H1" value="193.24731132495674" />
<entry key="H2" value="566.2869146370476" /> <entry key="H2" value="411.97491708219036" />
<entry key="H4" value="919.4763100903577" /> <entry key="H4" value="796.6723332411082" />
<entry key="D1" value="3280.1446307590936" /> <entry key="D1" value="3241.1913812104362" />
<entry key="W1" value="5482.097674456233" /> <entry key="W1" value="5550.841244628519" />
</decayedShown> </decayedShown>
</component> </component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
@@ -264,7 +257,8 @@
<workItem from="1783410502976" duration="23430000" /> <workItem from="1783410502976" duration="23430000" />
<workItem from="1783507489679" duration="5909000" /> <workItem from="1783507489679" duration="5909000" />
<workItem from="1783519887449" duration="6425000" /> <workItem from="1783519887449" duration="6425000" />
<workItem from="1783578446731" duration="20078000" /> <workItem from="1783578446731" duration="20118000" />
<workItem from="1783615847433" duration="3713000" />
</task> </task>
<task id="LOCAL-00001" summary="implement main screen"> <task id="LOCAL-00001" summary="implement main screen">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -482,7 +476,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1783603850701</updated> <updated>1783603850701</updated>
</task> </task>
<option name="localTasksCounter" value="28" /> <task id="LOCAL-00028" summary="Implement Arch and some additional changes">
<option name="closed" value="true" />
<created>1783614775509</created>
<option name="number" value="00028" />
<option name="presentableId" value="LOCAL-00028" />
<option name="project" value="LOCAL" />
<updated>1783614775509</updated>
</task>
<option name="localTasksCounter" value="29" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -498,7 +500,6 @@
<component name="UnityUnitTestConfiguration" currentTestLauncher="Both" /> <component name="UnityUnitTestConfiguration" currentTestLauncher="Both" />
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" /> <option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
<MESSAGE value="fix shit and stuff" />
<MESSAGE value="Add actual ASCII-Art for distros, add first three distros and being able to choose a starting-distro. Update UI to fix multiple small bugs." /> <MESSAGE value="Add actual ASCII-Art for distros, add first three distros and being able to choose a starting-distro. Update UI to fix multiple small bugs." />
<MESSAGE value="refactor card systems" /> <MESSAGE value="refactor card systems" />
<MESSAGE value="Add actual carts and shit&#10;&#10;Upgrade UI to Level 6&#10;&#10;Balls" /> <MESSAGE value="Add actual carts and shit&#10;&#10;Upgrade UI to Level 6&#10;&#10;Balls" />
@@ -523,7 +524,8 @@
<MESSAGE value="Implement many UX improvements, packages and their assets and a UI overhaul in collection" /> <MESSAGE value="Implement many UX improvements, packages and their assets and a UI overhaul in collection" />
<MESSAGE value="restructure packages (it looks shit)" /> <MESSAGE value="restructure packages (it looks shit)" />
<MESSAGE value="Make multiple UX improvements in distro -&gt; packages" /> <MESSAGE value="Make multiple UX improvements in distro -&gt; packages" />
<option name="LAST_COMMIT_MESSAGE" value="Make multiple UX improvements in distro -&gt; packages" /> <MESSAGE value="Implement Arch and some additional changes" />
<option name="LAST_COMMIT_MESSAGE" value="Implement Arch and some additional changes" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: lang_c_malloc id: lang_c_malloc
displayName: malloc() displayName: malloc()
description: deal 8. 20% segfault: take 3. description: deal 8. 20% segfault: uptime -3.
flavorText: memory acquired. ownership emotionally unresolved. flavorText: memory acquired. ownership emotionally unresolved.
language: 0 language: 0
rarity: 0 rarity: 0
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: lang_c_pointer id: lang_c_pointer
displayName: 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. flavorText: points at the bug with suspicious confidence.
language: 0 language: 0
rarity: 0 rarity: 0
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: lang_c_printf id: lang_c_printf
displayName: printf() displayName: printf()
description: deal 4. description: deal 4. 20% segfault: uptime -3.
flavorText: debugging by yelling into the void. flavorText: debugging by yelling into the void.
language: 0 language: 0
rarity: 0 rarity: 0
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: shop_c_free id: shop_c_free
displayName: 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. flavorText: double-free your schedule, not your heap.
language: 0 language: 0
rarity: 0 rarity: 0
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: shop_c_kernel_exploit id: shop_c_kernel_exploit
displayName: 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. flavorText: privilege escalated. heartbeat also escalated.
language: 0 language: 0
rarity: 1 rarity: 1
+1 -1
View File
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
id: shop_c_sizeof id: shop_c_sizeof
displayName: 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. flavorText: compile-time confidence, runtime consequences.
language: 0 language: 0
rarity: 1 rarity: 1
+70 -47
View File
@@ -35,6 +35,7 @@ namespace KernelPanic.Combat
targets = ShuffleTargets(targets, context.Source); targets = ShuffleTargets(targets, context.Source);
} }
bool dealtDamage = false;
for (int i = 0; i < targets.Count; i++) for (int i = 0; i < targets.Count; i++)
{ {
CombatantState target = targets[i]; CombatantState target = targets[i];
@@ -54,11 +55,14 @@ namespace KernelPanic.Combat
? _trueDamage ? target.CurrentUptime : target.CurrentUptime + target.Shield ? _trueDamage ? target.CurrentUptime : target.CurrentUptime + target.Shield
: 0; : 0;
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, _trueDamage, _canCrit)); DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, target, amount, _language, _trueDamage, _canCrit));
dealtDamage |= result.IncomingAmount > 0;
if (rustOverkillToShield) if (rustOverkillToShield)
{ {
GrantRustOverkillShield(context, result, survivable); GrantRustOverkillShield(context, result, survivable);
} }
} }
SegfaultRecoil.TryApply(context, _language, dealtDamage);
} }
private static void GrantRustOverkillShield(CombatContext context, DamageResult result, int survivable) 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 roll = RandomRoll.RollRange(1, 100, new RollContext(context.Source));
int damageAmount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_damageAmount, context), context.Card); int damageAmount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_damageAmount, context), context.Card);
int amount = roll <= _successPercent ? damageAmount : 0; 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}"); 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 public sealed class PreviousLanguageDamageEffect : ICardEffect
{ {
private readonly int _baseAmount; private readonly int _baseAmount;
@@ -687,6 +657,7 @@ namespace KernelPanic.Combat
int amount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_amount, context), context.Card); int amount = UpgradeMath.ScaleAmount(UpgradeMath.ApplySourceFlatBonus(_amount, context), context.Card);
int survivable = target.CurrentUptime + target.Shield; int survivable = target.CurrentUptime + target.Shield;
DamageResult result = 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);
int overkill = UnityEngine.Mathf.Max(0, result.IncomingAmount - survivable); int overkill = UnityEngine.Mathf.Max(0, result.IncomingAmount - survivable);
if (overkill > 0) 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 class CardEffectFactory
{ {
public static IReadOnlyList<ICardEffect> CreateEffects(CardDefinition definition) public static IReadOnlyList<ICardEffect> CreateEffects(CardDefinition definition)
@@ -899,7 +922,7 @@ namespace KernelPanic.Combat
new DrawEffect(1) new DrawEffect(1)
}, },
"lang_rs_borrow" => One(new ShieldEffect(5)), "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_printf" => One(new DealDamageEffect(4, 4, Language.C)),
"lang_c_pointer" => One(new PreviousLanguageDamageEffect(6, 10, Language.C)), "lang_c_pointer" => One(new PreviousLanguageDamageEffect(6, 10, Language.C)),
"lang_java_public_static_main" => One(new DealDamageEffect(7, 7, Language.Java)), "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_makepkg" => One(new BtwScaledDamageEffect(4, 2, Language.C)),
"arch_aur_helper" => One(new RandomCommonLanguageCardEffect()), "arch_aur_helper" => One(new RandomCommonLanguageCardEffect()),
"arch_minimal_install" => One(new MinimalInstallEffect()), "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_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") _ => 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_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_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_rs_borrow" => $"gain {UpgradeMath.ScaleShield(5, card)} shield.{marker}",
"lang_c_malloc" => $"deal {UpgradeMath.ScaleAmount(8, card)}. 20%: segfault, take 3.{marker}", "lang_c_malloc" => $"deal {UpgradeMath.ScaleAmount(8, card)}. 20%: segfault, uptime -3.{marker}",
"lang_c_printf" => $"deal {UpgradeMath.ScaleAmount(4, card)}.{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.{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_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_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}", "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_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_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}", "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_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_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}", "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_free" => $"deal {UpgradeMath.ScaleAmount(12, card)}. 20%: segfault, uptime -3 and draw 2.{marker}",
"shop_c_sizeof" => $"deal 3 x C cards in hand.{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%: take 8.{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}" _ => string.IsNullOrWhiteSpace(card.Definition.Description) ? "effect not authored." : $"{card.Definition.Description}{marker}"
}; };
} }
+2
View File
@@ -38,5 +38,7 @@ namespace KernelPanic.Combat
public DeckController DeckController { get; } public DeckController DeckController { get; }
public HandController HandController { get; } public HandController HandController { get; }
public IReadOnlyList<EnemyInstance> Enemies { get; } public IReadOnlyList<EnemyInstance> Enemies { get; }
internal bool SegfaultRecoilRolled { get; set; }
} }
} }
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -12,7 +12,7 @@ namespace KernelPanic.Combat
public const int BaseEnemyUptimeMin = 5; public const int BaseEnemyUptimeMin = 5;
public const int BaseEnemyUptimeMax = 10; public const int BaseEnemyUptimeMax = 10;
public const int EnemyUptimeGrowthPerWave = 2; public const int EnemyUptimeGrowthPerWave = 1;
public const int BaseEnemyAttack = 3; public const int BaseEnemyAttack = 3;
public const int EnemyAttackGrowthEveryWaves = 2; public const int EnemyAttackGrowthEveryWaves = 2;
+1 -1
View File
@@ -26,7 +26,7 @@ namespace KernelPanic.Combat
public int Cycles { get; set; } public int Cycles { get; set; }
public int MaxCycles { get; set; } public int MaxCycles { get; set; }
public bool IsDefeated { get; set; } public bool IsDefeated { get; set; }
public bool forceMaxRolls { get; set; } public bool ForceMaxRolls { get; set; }
public bool IgnoreDamageMultipliers { get; set; } public bool IgnoreDamageMultipliers { get; set; }
public bool AllowFlatDamageBuffs { get; set; } public bool AllowFlatDamageBuffs { get; set; }
public int FlatEffectBonus { get; set; } public int FlatEffectBonus { get; set; }
+1 -1
View File
@@ -116,7 +116,7 @@ namespace KernelPanic.Combat
private static int ApplyCrit(int amount, DamageRequest request, out bool wasCritical) private static int ApplyCrit(int amount, DamageRequest request, out bool wasCritical)
{ {
wasCritical = false; 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; return amount;
} }
+138
View File
@@ -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
};
}
}
}
+122 -3
View File
@@ -10,24 +10,57 @@ namespace KernelPanic.Combat
private readonly List<EnemyIntent> _intentPool = new(); private readonly List<EnemyIntent> _intentPool = new();
public EnemyInstance(string name, int maxUptime, IEnumerable<EnemyIntent> intentPool) 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); 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 string Name { get; }
public EnemyArchetypeDescriptor Archetype { get; }
public string ArchetypeId => Archetype.Id;
public int CurrentUptime => State.CurrentUptime; public int CurrentUptime => State.CurrentUptime;
public int MaxUptime => State.MaxUptime; public int MaxUptime => State.MaxUptime;
public CombatantState State { get; } public CombatantState State { get; }
public IReadOnlyList<EnemyIntent> IntentPool => _intentPool; public IReadOnlyList<EnemyIntent> IntentPool => _intentPool;
public EnemyIntent CurrentIntent { get; private set; } 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() 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) if (_intentPool.Count == 0)
{ {
CurrentIntent = default; CurrentIntent = default;
@@ -36,6 +69,92 @@ namespace KernelPanic.Combat
int index = RandomRoll.RollRange(0, _intentPool.Count - 1, new RollContext(State)); int index = RandomRoll.RollRange(0, _intentPool.Count - 1, new RollContext(State));
CurrentIntent = _intentPool[index]; 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;
} }
} }
} }
+23 -2
View File
@@ -26,7 +26,8 @@ namespace KernelPanic.Combat
bool trueDamage = false, bool trueDamage = false,
StatusType statusType = StatusType.MemoryLeak, StatusType statusType = StatusType.MemoryLeak,
int statusStacks = 0, int statusStacks = 0,
int statusDuration = -1) int statusDuration = -1,
string valueTextOverride = null)
{ {
Kind = kind; Kind = kind;
MinValue = minValue; MinValue = minValue;
@@ -38,6 +39,7 @@ namespace KernelPanic.Combat
StatusType = statusType; StatusType = statusType;
StatusStacks = statusStacks; StatusStacks = statusStacks;
StatusDuration = statusDuration; StatusDuration = statusDuration;
ValueTextOverride = valueTextOverride;
} }
public EnemyIntentKind Kind { get; } public EnemyIntentKind Kind { get; }
@@ -50,8 +52,27 @@ namespace KernelPanic.Combat
public StatusType StatusType { get; } public StatusType StatusType { get; }
public int StatusStacks { get; } public int StatusStacks { get; }
public int StatusDuration { 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 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);
}
} }
} }
+1 -1
View File
@@ -36,7 +36,7 @@ namespace KernelPanic.Combat
} }
// Mint's passive will flip this bool; no passive sets it in this scaffold. // 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; return max;
} }
+11 -11
View File
@@ -10,34 +10,34 @@ namespace KernelPanic.Meta
/// </summary> /// </summary>
public static class GachaPullContext public static class GachaPullContext
{ {
private static PendingGachaPull pendingPull; private static PendingGachaPull _pendingPull;
private static CompletedGachaPull completedPull; private static CompletedGachaPull _completedPull;
public static bool HasPendingPull => pendingPull != null; public static bool HasPendingPull => _pendingPull != null;
public static bool HasCompletedPull => completedPull != null; public static bool HasCompletedPull => _completedPull != null;
public static void SetPending(string bannerId, int pullCount, int entropyTokenCount, DistroDatabase distroDatabase, PackageDatabase packageDatabase, string focusUnitId) 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); _pendingPull = new PendingGachaPull(bannerId, pullCount, entropyTokenCount, distroDatabase, packageDatabase, focusUnitId);
completedPull = null; _completedPull = null;
} }
public static bool TryConsumePending(out PendingGachaPull pull) public static bool TryConsumePending(out PendingGachaPull pull)
{ {
pull = pendingPull; pull = _pendingPull;
pendingPull = null; _pendingPull = null;
return pull != null; return pull != null;
} }
public static void SetCompleted(CompletedGachaPull pull) public static void SetCompleted(CompletedGachaPull pull)
{ {
completedPull = pull; _completedPull = pull;
} }
public static bool TryConsumeCompleted(out CompletedGachaPull pull) public static bool TryConsumeCompleted(out CompletedGachaPull pull)
{ {
pull = completedPull; pull = _completedPull;
completedPull = null; _completedPull = null;
return pull != null; return pull != null;
} }
} }
+3 -3
View File
@@ -90,7 +90,7 @@ namespace KernelPanic.Meta
// with access to PackageDatabase) consumes this once per load to grant Cache for the extras, // with access to PackageDatabase) consumes this once per load to grant Cache for the extras,
// then clears it. See MainMenuController.LoadMetaState. // then clears it. See MainMenuController.LoadMetaState.
[NonSerialized] [NonSerialized]
public List<CollapsedPackageDuplicate> collapsedPackageDuplicates = new(); public List<CollapsedPackageDuplicate> CollapsedPackageDuplicates = new();
public static SaveData CreateDefault() public static SaveData CreateDefault()
{ {
@@ -236,7 +236,7 @@ namespace KernelPanic.Meta
private void NormalizeOwnedPackages() private void NormalizeOwnedPackages()
{ {
collapsedPackageDuplicates.Clear(); CollapsedPackageDuplicates.Clear();
Dictionary<string, OwnedPackageSaveEntry> highestById = new(StringComparer.OrdinalIgnoreCase); Dictionary<string, OwnedPackageSaveEntry> highestById = new(StringComparer.OrdinalIgnoreCase);
Dictionary<string, int> extraCountById = new(StringComparer.OrdinalIgnoreCase); Dictionary<string, int> extraCountById = new(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < ownedPackages.Count; i++) for (int i = 0; i < ownedPackages.Count; i++)
@@ -265,7 +265,7 @@ namespace KernelPanic.Meta
ownedPackages = new List<OwnedPackageSaveEntry>(highestById.Values); ownedPackages = new List<OwnedPackageSaveEntry>(highestById.Values);
foreach (KeyValuePair<string, int> extra in extraCountById) 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(); ownedPackageIds.Clear();
+26 -26
View File
@@ -12,9 +12,9 @@ namespace KernelPanic.Run
/// </summary> /// </summary>
public static class RunContext 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) 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) 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) 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) public static bool TryCreateRunConfig(LanguageDeckDatabase languageDeckDatabase, out RunConfig config)
{ {
if (pendingRun == null || pendingRun.Distro == null) if (_pendingRun == null || _pendingRun.Distro == null)
{ {
config = null; config = null;
return false; return false;
} }
config = pendingRun.CreateRunConfig(languageDeckDatabase); config = _pendingRun.CreateRunConfig(languageDeckDatabase);
pendingRun = null; _pendingRun = null;
return true; return true;
} }
private sealed class PendingRun private sealed class PendingRun
{ {
private readonly DistroDefinition distro; private readonly DistroDefinition _distro;
private readonly List<CardDefinition> equippedCards = new(); private readonly List<CardDefinition> _equippedCards = new();
private readonly List<PackageInstance> equippedPackages = new(); private readonly List<PackageInstance> _equippedPackages = new();
private readonly Language primaryLanguage; private readonly Language _primaryLanguage;
private readonly Language secondaryLanguage; private readonly Language _secondaryLanguage;
private readonly int runSeed; private readonly int _runSeed;
private readonly int distroVersion; private readonly int _distroVersion;
public PendingRun(DistroDefinition distro, IReadOnlyList<CardDefinition> cards, IReadOnlyList<PackageInstance> packages, Language primaryLanguage, Language secondaryLanguage, int runSeed, int distroVersion) public PendingRun(DistroDefinition distro, IReadOnlyList<CardDefinition> cards, IReadOnlyList<PackageInstance> packages, Language primaryLanguage, Language secondaryLanguage, int runSeed, int distroVersion)
{ {
this.distro = distro; this._distro = distro;
this.primaryLanguage = primaryLanguage; this._primaryLanguage = primaryLanguage;
this.secondaryLanguage = secondaryLanguage; this._secondaryLanguage = secondaryLanguage;
this.runSeed = runSeed; this._runSeed = runSeed;
this.distroVersion = distroVersion; this._distroVersion = distroVersion;
if (cards == null) if (cards == null)
{ {
@@ -76,7 +76,7 @@ namespace KernelPanic.Run
{ {
if (cards[i] != null && !cards[i].IsRunOnly) 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) 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) public RunConfig CreateRunConfig(LanguageDeckDatabase languageDeckDatabase)
{ {
List<CardDefinition> startingDeck = new(equippedCards); List<CardDefinition> startingDeck = new(_equippedCards);
AddLanguageDeck(languageDeckDatabase, primaryLanguage, startingDeck); AddLanguageDeck(languageDeckDatabase, _primaryLanguage, startingDeck);
AddLanguageDeck(languageDeckDatabase, secondaryLanguage, startingDeck); AddLanguageDeck(languageDeckDatabase, _secondaryLanguage, startingDeck);
return new RunConfig(distro, primaryLanguage, secondaryLanguage, startingDeck, equippedPackages, runSeed, distroVersion); return new RunConfig(_distro, _primaryLanguage, _secondaryLanguage, startingDeck, _equippedPackages, _runSeed, _distroVersion);
} }
private static void AddLanguageDeck(LanguageDeckDatabase languageDeckDatabase, Language language, List<CardDefinition> target) private static void AddLanguageDeck(LanguageDeckDatabase languageDeckDatabase, Language language, List<CardDefinition> target)
+102 -102
View File
@@ -18,39 +18,39 @@ namespace KernelPanic.Run
[SerializeField] private bool isRunActive; [SerializeField] private bool isRunActive;
[SerializeField] private bool isPlayerDead; [SerializeField] private bool isPlayerDead;
private readonly List<CardInstance> runDeck = new(); private readonly List<CardInstance> _runDeck = new();
private readonly List<RepositoryOffer> repositoryOffers = new(); private readonly List<RepositoryOffer> _repositoryOffers = new();
private readonly HashSet<string> soldOfferKeys = new(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _soldOfferKeys = new(StringComparer.OrdinalIgnoreCase);
private int bits; private int _bits;
private int rerollsThisVisit; private int _rerollsThisVisit;
private int maxUptimeBonus; private int _maxUptimeBonus;
private int maxCyclesBonus; private int _maxCyclesBonus;
private int ramBonus; private int _ramBonus;
private int packageMaxUptimeBonus; private int _packageMaxUptimeBonus;
private int packageMaxCyclesBonus; private int _packageMaxCyclesBonus;
private int packageRamBonus; private int _packageRamBonus;
private int wavesCleared; private int _wavesCleared;
private int accruedBandwidth; private int _accruedBandwidth;
private int accruedEntropy; private int _accruedEntropy;
private bool repositoryVisitActive; private bool _repositoryVisitActive;
private bool rewardsSettled; private bool _rewardsSettled;
public int CurrentWaveNumber => currentWaveNumber; public int CurrentWaveNumber => currentWaveNumber;
public bool IsRunActive => isRunActive; public bool IsRunActive => isRunActive;
public bool IsPlayerDead => isPlayerDead; public bool IsPlayerDead => isPlayerDead;
public RunConfig CurrentConfig { get; private set; } public RunConfig CurrentConfig { get; private set; }
public IReadOnlyList<CardInstance> RunDeck => runDeck; public IReadOnlyList<CardInstance> RunDeck => _runDeck;
public IReadOnlyList<RepositoryOffer> RepositoryOffers => repositoryOffers; public IReadOnlyList<RepositoryOffer> RepositoryOffers => _repositoryOffers;
public bool RepositoryVisitActive => repositoryVisitActive; public bool RepositoryVisitActive => _repositoryVisitActive;
public int Bits => bits; public int Bits => _bits;
public int RerollCost => CombatTuning.RerollBaseCost + (rerollsThisVisit * CombatTuning.RerollCostStep); public int RerollCost => CombatTuning.RerollBaseCost + (_rerollsThisVisit * CombatTuning.RerollCostStep);
public int MaxUptimeBonus => maxUptimeBonus; public int MaxUptimeBonus => _maxUptimeBonus;
public int MaxCyclesBonus => maxCyclesBonus; public int MaxCyclesBonus => _maxCyclesBonus;
public int RamBonus => ramBonus; public int RamBonus => _ramBonus;
public int WavesCleared => wavesCleared; public int WavesCleared => _wavesCleared;
public int AccruedBandwidth => accruedBandwidth; public int AccruedBandwidth => _accruedBandwidth;
public int AccruedEntropy => accruedEntropy; public int AccruedEntropy => _accruedEntropy;
public bool RewardsSettled => rewardsSettled; public bool RewardsSettled => _rewardsSettled;
public event Action RepositoryChanged; public event Action RepositoryChanged;
@@ -72,18 +72,18 @@ namespace KernelPanic.Run
isRunActive = true; isRunActive = true;
isPlayerDead = false; isPlayerDead = false;
currentWaveNumber = 1; currentWaveNumber = 1;
bits = 0; _bits = 0;
rerollsThisVisit = 0; _rerollsThisVisit = 0;
maxUptimeBonus = 0; _maxUptimeBonus = 0;
maxCyclesBonus = 0; _maxCyclesBonus = 0;
ramBonus = 0; _ramBonus = 0;
packageMaxUptimeBonus = 0; _packageMaxUptimeBonus = 0;
packageMaxCyclesBonus = 0; _packageMaxCyclesBonus = 0;
packageRamBonus = 0; _packageRamBonus = 0;
wavesCleared = 0; _wavesCleared = 0;
accruedBandwidth = 0; _accruedBandwidth = 0;
accruedEntropy = 0; _accruedEntropy = 0;
rewardsSettled = false; _rewardsSettled = false;
ApplyKernelPackageBonuses(config); ApplyKernelPackageBonuses(config);
InitializeRunDeck(config); InitializeRunDeck(config);
StartCombat(); StartCombat();
@@ -101,40 +101,40 @@ namespace KernelPanic.Run
return; return;
} }
bits += amount; _bits += amount;
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
} }
public void GenerateRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase) public void GenerateRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
{ {
repositoryOffers.Clear(); _repositoryOffers.Clear();
rerollsThisVisit = 0; _rerollsThisVisit = 0;
soldOfferKeys.Clear(); _soldOfferKeys.Clear();
FillRepositoryOffers(cardDatabase, languageDeckDatabase); FillRepositoryOffers(cardDatabase, languageDeckDatabase);
repositoryVisitActive = true; _repositoryVisitActive = true;
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
} }
public bool RerollRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase) public bool RerollRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
{ {
int cost = RerollCost; int cost = RerollCost;
if (bits < cost) if (_bits < cost)
{ {
return false; return false;
} }
bits -= cost; _bits -= cost;
rerollsThisVisit++; _rerollsThisVisit++;
repositoryOffers.Clear(); _repositoryOffers.Clear();
FillRepositoryOffers(cardDatabase, languageDeckDatabase); FillRepositoryOffers(cardDatabase, languageDeckDatabase);
repositoryVisitActive = true; _repositoryVisitActive = true;
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
return true; return true;
} }
public bool BuyOffer(RepositoryOffer offer, CombatantState playerState) 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; return false;
} }
@@ -152,43 +152,43 @@ namespace KernelPanic.Run
return false; return false;
} }
bits -= offer.Price; _bits -= offer.Price;
offer.MarkSold(); offer.MarkSold();
soldOfferKeys.Add(OfferKey(offer)); _soldOfferKeys.Add(OfferKey(offer));
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
return true; return true;
} }
public bool RemoveCard(CardInstance card) 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; return false;
} }
if (!runDeck.Remove(card)) if (!_runDeck.Remove(card))
{ {
return false; return false;
} }
bits -= CombatTuning.RemoveCardCost; _bits -= CombatTuning.RemoveCardCost;
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
return true; return true;
} }
public int EffectiveMaxUptime() 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() 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() 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) public static PackageStatImpact CalculatePackageStatImpact(DistroDefinition distro, IReadOnlyList<PackageInstance> packages)
@@ -232,35 +232,35 @@ namespace KernelPanic.Run
private void ApplyKernelPackageBonuses(RunConfig config) private void ApplyKernelPackageBonuses(RunConfig config)
{ {
PackageStatImpact impact = CalculatePackageStatImpact(config?.Distro, config?.EquippedPackages); PackageStatImpact impact = CalculatePackageStatImpact(config?.Distro, config?.EquippedPackages);
packageMaxUptimeBonus = impact.UptimeBonus; _packageMaxUptimeBonus = impact.UptimeBonus;
packageMaxCyclesBonus = impact.CyclesBonus; _packageMaxCyclesBonus = impact.CyclesBonus;
packageRamBonus = impact.RamBonus; _packageRamBonus = impact.RamBonus;
} }
public bool TrySettleRunRewards(out int bandwidth, out int entropy) public bool TrySettleRunRewards(out int bandwidth, out int entropy)
{ {
bandwidth = accruedBandwidth; bandwidth = _accruedBandwidth;
entropy = accruedEntropy; entropy = _accruedEntropy;
if (rewardsSettled) if (_rewardsSettled)
{ {
return false; return false;
} }
rewardsSettled = true; _rewardsSettled = true;
return bandwidth > 0 || entropy > 0; return bandwidth > 0 || entropy > 0;
} }
private void HandleWaveCleared(WaveClearedEvent payload) private void HandleWaveCleared(WaveClearedEvent payload)
{ {
int clearedWave = Mathf.Max(1, payload.WaveNumber); int clearedWave = Mathf.Max(1, payload.WaveNumber);
wavesCleared = Mathf.Max(wavesCleared, clearedWave); _wavesCleared = Mathf.Max(_wavesCleared, clearedWave);
accruedBandwidth += CalculateBandwidthReward(clearedWave); _accruedBandwidth += CalculateBandwidthReward(clearedWave);
accruedEntropy += CalculateEntropyReward(clearedWave); _accruedEntropy += CalculateEntropyReward(clearedWave);
currentWaveNumber = Mathf.Max(currentWaveNumber + 1, payload.WaveNumber + 1); currentWaveNumber = Mathf.Max(currentWaveNumber + 1, payload.WaveNumber + 1);
repositoryOffers.Clear(); _repositoryOffers.Clear();
rerollsThisVisit = 0; _rerollsThisVisit = 0;
soldOfferKeys.Clear(); _soldOfferKeys.Clear();
repositoryVisitActive = false; _repositoryVisitActive = false;
GameEvents.RaiseWaveAdvanced(new WaveAdvancedEvent(currentWaveNumber)); GameEvents.RaiseWaveAdvanced(new WaveAdvancedEvent(currentWaveNumber));
} }
@@ -268,13 +268,13 @@ namespace KernelPanic.Run
{ {
isRunActive = false; isRunActive = false;
isPlayerDead = payload.PlayerDied; isPlayerDead = payload.PlayerDied;
bits = 0; _bits = 0;
repositoryOffers.Clear(); _repositoryOffers.Clear();
repositoryVisitActive = false; _repositoryVisitActive = false;
runDeck.Clear(); _runDeck.Clear();
maxUptimeBonus = 0; _maxUptimeBonus = 0;
maxCyclesBonus = 0; _maxCyclesBonus = 0;
ramBonus = 0; _ramBonus = 0;
RepositoryChanged?.Invoke(); RepositoryChanged?.Invoke();
} }
@@ -291,7 +291,7 @@ namespace KernelPanic.Run
private void InitializeRunDeck(RunConfig config) private void InitializeRunDeck(RunConfig config)
{ {
runDeck.Clear(); _runDeck.Clear();
if (config?.StartingDeck == null) if (config?.StartingDeck == null)
{ {
return; return;
@@ -302,7 +302,7 @@ namespace KernelPanic.Run
CardDefinition definition = config.StartingDeck[i]; CardDefinition definition = config.StartingDeck[i];
if (definition != null && !definition.IsRunOnly) 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) private void FillRepositoryOffers(CardDatabase cardDatabase, LanguageDeckDatabase languageDeckDatabase)
{ {
int guard = 0; int guard = 0;
while (repositoryOffers.Count < CombatTuning.ShopSize && guard < 80) while (_repositoryOffers.Count < CombatTuning.ShopSize && guard < 80)
{ {
guard++; guard++;
RepositoryOffer offer = CreateRandomOffer(cardDatabase, languageDeckDatabase); 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; continue;
} }
repositoryOffers.Add(offer); _repositoryOffers.Add(offer);
} }
} }
@@ -353,7 +353,7 @@ namespace KernelPanic.Run
private RepositoryOffer CreateUpgradeOffer() 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) if (candidates.Count == 0)
{ {
return CreateStatOffer(); return CreateStatOffer();
@@ -463,7 +463,7 @@ namespace KernelPanic.Run
return false; return false;
} }
runDeck.Add(new CardInstance(card)); _runDeck.Add(new CardInstance(card));
return true; return true;
} }
@@ -488,7 +488,7 @@ namespace KernelPanic.Run
switch (kind) switch (kind)
{ {
case RunStatUpgradeKind.MaxCycles: case RunStatUpgradeKind.MaxCycles:
maxCyclesBonus += CombatTuning.StatUpgradeMaxCycles; _maxCyclesBonus += CombatTuning.StatUpgradeMaxCycles;
if (playerState != null) if (playerState != null)
{ {
playerState.MaxCycles += CombatTuning.StatUpgradeMaxCycles; playerState.MaxCycles += CombatTuning.StatUpgradeMaxCycles;
@@ -496,7 +496,7 @@ namespace KernelPanic.Run
} }
return true; return true;
case RunStatUpgradeKind.MaxUptime: case RunStatUpgradeKind.MaxUptime:
maxUptimeBonus += CombatTuning.StatUpgradeMaxUptime; _maxUptimeBonus += CombatTuning.StatUpgradeMaxUptime;
if (playerState != null) if (playerState != null)
{ {
playerState.MaxUptime += CombatTuning.StatUpgradeMaxUptime; playerState.MaxUptime += CombatTuning.StatUpgradeMaxUptime;
@@ -511,7 +511,7 @@ namespace KernelPanic.Run
playerState.CurrentUptime = Mathf.Min(playerState.MaxUptime, playerState.CurrentUptime + CombatTuning.StatUpgradeHeal); playerState.CurrentUptime = Mathf.Min(playerState.MaxUptime, playerState.CurrentUptime + CombatTuning.StatUpgradeHeal);
return true; return true;
case RunStatUpgradeKind.Ram: case RunStatUpgradeKind.Ram:
ramBonus += CombatTuning.StatUpgradeRam; _ramBonus += CombatTuning.StatUpgradeRam;
if (playerState != null) if (playerState != null)
{ {
playerState.Ram += CombatTuning.StatUpgradeRam; playerState.Ram += CombatTuning.StatUpgradeRam;
@@ -525,9 +525,9 @@ namespace KernelPanic.Run
public struct PackageStatImpact public struct PackageStatImpact
{ {
private readonly List<string> uptimeSources; private readonly List<string> _uptimeSources;
private readonly List<string> ramSources; private readonly List<string> _ramSources;
private readonly List<string> cyclesSources; private readonly List<string> _cyclesSources;
public PackageStatImpact(int baseUptime, int baseRam, int baseCycles) public PackageStatImpact(int baseUptime, int baseRam, int baseCycles)
{ {
@@ -537,9 +537,9 @@ namespace KernelPanic.Run
UptimeBonus = 0; UptimeBonus = 0;
RamBonus = 0; RamBonus = 0;
CyclesBonus = 0; CyclesBonus = 0;
uptimeSources = new List<string>(); _uptimeSources = new List<string>();
ramSources = new List<string>(); _ramSources = new List<string>();
cyclesSources = new List<string>(); _cyclesSources = new List<string>();
} }
public int BaseUptime { get; } public int BaseUptime { get; }
@@ -551,9 +551,9 @@ namespace KernelPanic.Run
public int FinalUptime => Mathf.Max(1, BaseUptime + UptimeBonus); public int FinalUptime => Mathf.Max(1, BaseUptime + UptimeBonus);
public int FinalRam => Mathf.Max(1, BaseRam + RamBonus); public int FinalRam => Mathf.Max(1, BaseRam + RamBonus);
public int FinalCycles => Mathf.Max(1, BaseCycles + CyclesBonus); public int FinalCycles => Mathf.Max(1, BaseCycles + CyclesBonus);
public IReadOnlyList<string> UptimeSources => uptimeSources; public IReadOnlyList<string> UptimeSources => _uptimeSources;
public IReadOnlyList<string> RamSources => ramSources; public IReadOnlyList<string> RamSources => _ramSources;
public IReadOnlyList<string> CyclesSources => cyclesSources; public IReadOnlyList<string> CyclesSources => _cyclesSources;
public void AddUptime(int amount, PackageDefinition source) public void AddUptime(int amount, PackageDefinition source)
{ {
@@ -563,7 +563,7 @@ namespace KernelPanic.Run
} }
UptimeBonus += amount; UptimeBonus += amount;
AddSource(source, uptimeSources); AddSource(source, _uptimeSources);
} }
public void AddRam(int amount, PackageDefinition source) public void AddRam(int amount, PackageDefinition source)
@@ -574,7 +574,7 @@ namespace KernelPanic.Run
} }
RamBonus += amount; RamBonus += amount;
AddSource(source, ramSources); AddSource(source, _ramSources);
} }
public void AddCycles(int amount, PackageDefinition source) public void AddCycles(int amount, PackageDefinition source)
@@ -585,7 +585,7 @@ namespace KernelPanic.Run
} }
CyclesBonus += amount; CyclesBonus += amount;
AddSource(source, cyclesSources); AddSource(source, _cyclesSources);
} }
private static void AddSource(PackageDefinition source, List<string> sources) private static void AddSource(PackageDefinition source, List<string> sources)
File diff suppressed because it is too large Load Diff
+189 -189
View File
@@ -33,53 +33,53 @@ namespace KernelPanic.UI
private const int SummaryTickSteps = 8; private const int SummaryTickSteps = 8;
private const int SummaryTickMs = 220; private const int SummaryTickMs = 220;
private readonly List<CompletedGachaReward> rewards = new(); private readonly List<CompletedGachaReward> _rewards = new();
private readonly List<PullCardView> cardViews = new(); private readonly List<PullCardView> _cardViews = new();
private UIDocument document; private UIDocument _document;
private VisualElement root; private VisualElement _root;
private Label commandLabel; private Label _commandLabel;
private Label costLabel; private Label _costLabel;
private Label flourishLabel; private Label _flourishLabel;
private Label skipHint; private Label _skipHint;
private VisualElement resultGrid; private VisualElement _resultGrid;
private VisualElement effectLayer; private VisualElement _effectLayer;
private VisualElement goldShimmer; private VisualElement _goldShimmer;
private VisualElement summaryPanel; private VisualElement _summaryPanel;
private Label summaryTotalsLabel; private Label _summaryTotalsLabel;
private Button continueButton; private Button _continueButton;
private string completedHeader; private string _completedHeader;
private bool skipRequested; private bool _skipRequested;
private bool revealComplete; private bool _revealComplete;
private bool failed; private bool _failed;
private void Awake() private void Awake()
{ {
document = GetComponent<UIDocument>(); _document = GetComponent<UIDocument>();
root = document.rootVisualElement; _root = _document.rootVisualElement;
root.Clear(); _root.Clear();
root.focusable = true; _root.focusable = true;
root.AddToClassList("gambling-root"); _root.AddToClassList("gambling-root");
root.EnableInClassList("reduced-motion", UIPreferences.ReducedMotion); _root.EnableInClassList("reduced-motion", UIPreferences.ReducedMotion);
LoadStyles(); LoadStyles();
BuildLayout(); BuildLayout();
root.RegisterCallback<KeyDownEvent>(HandleKeyDown); _root.RegisterCallback<KeyDownEvent>(HandleKeyDown);
root.RegisterCallback<PointerDownEvent>(HandlePointerDown); _root.RegisterCallback<PointerDownEvent>(HandlePointerDown);
} }
private void OnDestroy() private void OnDestroy()
{ {
if (root == null) if (_root == null)
{ {
return; return;
} }
root.UnregisterCallback<KeyDownEvent>(HandleKeyDown); _root.UnregisterCallback<KeyDownEvent>(HandleKeyDown);
root.UnregisterCallback<PointerDownEvent>(HandlePointerDown); _root.UnregisterCallback<PointerDownEvent>(HandlePointerDown);
} }
private void Start() private void Start()
{ {
root.Focus(); _root.Focus();
StartCoroutine(RunCutscene()); StartCoroutine(RunCutscene());
} }
@@ -95,7 +95,7 @@ namespace KernelPanic.UI
StyleSheet styleSheet = Resources.Load<StyleSheet>(resourcePath); StyleSheet styleSheet = Resources.Load<StyleSheet>(resourcePath);
if (styleSheet != null) if (styleSheet != null)
{ {
root.styleSheets.Add(styleSheet); _root.styleSheets.Add(styleSheet);
} }
} }
@@ -103,7 +103,7 @@ namespace KernelPanic.UI
{ {
VisualElement shell = new(); VisualElement shell = new();
shell.AddToClassList("gambling-shell"); shell.AddToClassList("gambling-shell");
root.Add(shell); _root.Add(shell);
VisualElement frame = new(); VisualElement frame = new();
frame.AddToClassList("gambling-frame"); frame.AddToClassList("gambling-frame");
@@ -117,76 +117,76 @@ namespace KernelPanic.UI
titleBlock.AddToClassList("gambling-title-block"); titleBlock.AddToClassList("gambling-title-block");
header.Add(titleBlock); header.Add(titleBlock);
commandLabel = new("git pull"); _commandLabel = new("git pull");
commandLabel.AddToClassList("gambling-command"); _commandLabel.AddToClassList("gambling-command");
titleBlock.Add(commandLabel); titleBlock.Add(_commandLabel);
costLabel = new(); _costLabel = new();
costLabel.AddToClassList("gambling-cost"); _costLabel.AddToClassList("gambling-cost");
titleBlock.Add(costLabel); titleBlock.Add(_costLabel);
skipHint = new("[tap/key] reveal all"); _skipHint = new("[tap/key] reveal all");
skipHint.AddToClassList("gambling-skip"); _skipHint.AddToClassList("gambling-skip");
header.Add(skipHint); header.Add(_skipHint);
flourishLabel = new(); _flourishLabel = new();
flourishLabel.AddToClassList("gambling-flourish"); _flourishLabel.AddToClassList("gambling-flourish");
frame.Add(flourishLabel); frame.Add(_flourishLabel);
resultGrid = new VisualElement(); _resultGrid = new VisualElement();
resultGrid.AddToClassList("gambling-results"); _resultGrid.AddToClassList("gambling-results");
frame.Add(resultGrid); frame.Add(_resultGrid);
goldShimmer = new VisualElement(); _goldShimmer = new VisualElement();
goldShimmer.AddToClassList("gold-shimmer"); _goldShimmer.AddToClassList("gold-shimmer");
goldShimmer.pickingMode = PickingMode.Ignore; _goldShimmer.pickingMode = PickingMode.Ignore;
frame.Add(goldShimmer); frame.Add(_goldShimmer);
effectLayer = new VisualElement(); _effectLayer = new VisualElement();
effectLayer.AddToClassList("effect-layer"); _effectLayer.AddToClassList("effect-layer");
effectLayer.pickingMode = PickingMode.Ignore; _effectLayer.pickingMode = PickingMode.Ignore;
frame.Add(effectLayer); frame.Add(_effectLayer);
summaryPanel = new VisualElement(); _summaryPanel = new VisualElement();
summaryPanel.AddToClassList("summary-panel"); _summaryPanel.AddToClassList("summary-panel");
summaryPanel.AddToClassList("hidden"); _summaryPanel.AddToClassList("hidden");
frame.Add(summaryPanel); frame.Add(_summaryPanel);
continueButton = new Button(ContinueToMenu) { text = "> continue" }; _continueButton = new Button(ContinueToMenu) { text = "> continue" };
continueButton.AddToClassList("continue-button"); _continueButton.AddToClassList("continue-button");
continueButton.AddToClassList("continue-button-pending"); _continueButton.AddToClassList("continue-button-pending");
continueButton.SetEnabled(false); _continueButton.SetEnabled(false);
frame.Add(continueButton); frame.Add(_continueButton);
} }
private IEnumerator RunCutscene() private IEnumerator RunCutscene()
{ {
if (!GachaPullContext.TryConsumePending(out PendingGachaPull pending)) if (!GachaPullContext.TryConsumePending(out PendingGachaPull pending))
{ {
failed = true; _failed = true;
commandLabel.text = "git pull failed"; _commandLabel.text = "git pull failed";
costLabel.text = "no pending pull"; _costLabel.text = "no pending pull";
ShowContinue(); ShowContinue();
yield break; 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; 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: {pending.EntropyTokenCount * GachaService.EntropyPerCommit} Entropy"
: $"cost: {pullCost} Commits / {pullCost * 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); CompletedGachaPull completed = ResolvePull(pending);
GachaPullContext.SetCompleted(completed); GachaPullContext.SetCompleted(completed);
completedHeader = completed.HeaderText; _completedHeader = completed.HeaderText;
rewards.Clear(); _rewards.Clear();
rewards.AddRange(completed.Rewards); _rewards.AddRange(completed.Rewards);
if (rewards.Count == 0) if (_rewards.Count == 0)
{ {
failed = true; _failed = true;
costLabel.text = completed.HeaderText; _costLabel.text = completed.HeaderText;
ShowContinue(); ShowContinue();
yield break; yield break;
} }
@@ -199,24 +199,24 @@ namespace KernelPanic.UI
} }
yield return WaitOrSkip(FlourishMs); yield return WaitOrSkip(FlourishMs);
flourishLabel.text = "$ unpacking sealed objects"; _flourishLabel.text = "$ unpacking sealed objects";
for (int i = 0; i < rewards.Count; i++) for (int i = 0; i < _rewards.Count; i++)
{ {
if (skipRequested) if (_skipRequested)
{ {
RevealAll(); RevealAll();
yield break; yield break;
} }
CompletedGachaReward reward = rewards[i]; CompletedGachaReward reward = _rewards[i];
PullCardView card = cardViews[i]; PullCardView card = _cardViews[i];
int holdMs = GetAnticipationMs(reward.Stars); int holdMs = GetAnticipationMs(reward.Stars);
if (holdMs > 0) if (holdMs > 0)
{ {
ApplyGridFocus(i, reward.Stars); ApplyGridFocus(i, reward.Stars);
card.ShowHold(reward.Stars >= 5 ? "........ signed tag" : "... promoted object", reward.Stars); card.ShowHold(reward.Stars >= 5 ? "........ signed tag" : "... promoted object", reward.Stars);
yield return WaitOrSkip(holdMs); yield return WaitOrSkip(holdMs);
if (skipRequested) if (_skipRequested)
{ {
RevealAll(); RevealAll();
yield break; yield break;
@@ -315,25 +315,25 @@ namespace KernelPanic.UI
private void BuildRows() private void BuildRows()
{ {
resultGrid.Clear(); _resultGrid.Clear();
cardViews.Clear(); _cardViews.Clear();
for (int i = 0; i < rewards.Count; i++) for (int i = 0; i < _rewards.Count; i++)
{ {
PullCardView card = new(rewards[i]); PullCardView card = new(_rewards[i]);
cardViews.Add(card); _cardViews.Add(card);
resultGrid.Add(card.Root); _resultGrid.Add(card.Root);
} }
} }
private void RevealAll() private void RevealAll()
{ {
skipRequested = true; _skipRequested = true;
ClearGridFocus(); ClearGridFocus();
goldShimmer.RemoveFromClassList("gold-shimmer-on"); _goldShimmer.RemoveFromClassList("gold-shimmer-on");
for (int i = 0; i < cardViews.Count; i++) for (int i = 0; i < _cardViews.Count; i++)
{ {
cardViews[i].HideHold(); _cardViews[i].HideHold();
cardViews[i].Reveal(allowFlash: false, persistentMotion: !UIPreferences.ReducedMotion); _cardViews[i].Reveal(allowFlash: false, persistentMotion: !UIPreferences.ReducedMotion);
} }
CompleteReveal(); CompleteReveal();
@@ -341,49 +341,49 @@ namespace KernelPanic.UI
private void CompleteReveal() private void CompleteReveal()
{ {
if (revealComplete) if (_revealComplete)
{ {
return; return;
} }
revealComplete = true; _revealComplete = true;
skipHint.text = "complete"; _skipHint.text = "complete";
flourishLabel.text = completedHeader; _flourishLabel.text = _completedHeader;
flourishLabel.AddToClassList("gambling-flourish-complete"); _flourishLabel.AddToClassList("gambling-flourish-complete");
BuildSummary(animate: !skipRequested && !UIPreferences.ReducedMotion); BuildSummary(animate: !_skipRequested && !UIPreferences.ReducedMotion);
ShowContinue(); ShowContinue();
} }
private void BuildSummary(bool animate) private void BuildSummary(bool animate)
{ {
summaryPanel.Clear(); _summaryPanel.Clear();
summaryPanel.RemoveFromClassList("hidden"); _summaryPanel.RemoveFromClassList("hidden");
summaryTotalsLabel = new Label { name = "PullSummaryTotals" }; _summaryTotalsLabel = new Label { name = "PullSummaryTotals" };
summaryTotalsLabel.AddToClassList("summary-totals"); _summaryTotalsLabel.AddToClassList("summary-totals");
summaryPanel.Add(summaryTotalsLabel); _summaryPanel.Add(_summaryTotalsLabel);
SummaryTotals totals = CalculateTotals(); SummaryTotals totals = CalculateTotals();
if (!animate) 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; return;
} }
summaryTotalsLabel.AddToClassList("summary-tick"); _summaryTotalsLabel.AddToClassList("summary-tick");
for (int step = 0; step <= SummaryTickSteps; step++) for (int step = 0; step <= SummaryTickSteps; step++)
{ {
int capturedStep = step; int capturedStep = step;
int delay = Mathf.RoundToInt((SummaryTickMs / (float)SummaryTickSteps) * capturedStep); int delay = Mathf.RoundToInt((SummaryTickMs / (float)SummaryTickSteps) * capturedStep);
summaryTotalsLabel.schedule.Execute(() => _summaryTotalsLabel.schedule.Execute(() =>
{ {
float t = capturedStep / (float)SummaryTickSteps; float t = capturedStep / (float)SummaryTickSteps;
int units = Mathf.RoundToInt(Mathf.Lerp(0, totals.Units, t)); int units = Mathf.RoundToInt(Mathf.Lerp(0, totals.Units, t));
int merges = Mathf.RoundToInt(Mathf.Lerp(0, totals.Merges, t)); int merges = Mathf.RoundToInt(Mathf.Lerp(0, totals.Merges, t));
int cache = Mathf.RoundToInt(Mathf.Lerp(0, totals.Cache, 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) if (capturedStep == SummaryTickSteps)
{ {
summaryTotalsLabel.RemoveFromClassList("summary-tick"); _summaryTotalsLabel.RemoveFromClassList("summary-tick");
} }
}).StartingIn(delay); }).StartingIn(delay);
} }
@@ -395,25 +395,25 @@ namespace KernelPanic.UI
int merges = 0; int merges = 0;
int cache = 0; int cache = 0;
HashSet<Language> languages = new(); 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++; units++;
} }
if (rewards[i].RewardType == GachaRewardType.Package) if (_rewards[i].RewardType == GachaRewardType.Package)
{ {
cache += rewards[i].MergesAwarded; cache += _rewards[i].MergesAwarded;
} }
else 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 elapsed = 0f;
float duration = Mathf.Max(0f, milliseconds / 1000f); float duration = Mathf.Max(0f, milliseconds / 1000f);
while (!skipRequested && elapsed < duration) while (!_skipRequested && elapsed < duration)
{ {
elapsed += Time.deltaTime; elapsed += Time.deltaTime;
yield return null; yield return null;
@@ -615,17 +615,17 @@ namespace KernelPanic.UI
return; 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() 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) private void PlayGoldShimmer(VisualElement source)
{ {
if (source == null || goldShimmer?.parent == null) if (source == null || _goldShimmer?.parent == null)
{ {
return; return;
} }
Rect sourceBounds = source.worldBound; Rect sourceBounds = source.worldBound;
Rect parentBounds = goldShimmer.parent.worldBound; Rect parentBounds = _goldShimmer.parent.worldBound;
float left = Mathf.Max(0f, sourceBounds.x - parentBounds.x); float left = Mathf.Max(0f, sourceBounds.x - parentBounds.x);
float top = Mathf.Max(0f, sourceBounds.y - parentBounds.y); float top = Mathf.Max(0f, sourceBounds.y - parentBounds.y);
goldShimmer.style.left = left; _goldShimmer.style.left = left;
goldShimmer.style.top = top; _goldShimmer.style.top = top;
goldShimmer.style.width = sourceBounds.width; _goldShimmer.style.width = sourceBounds.width;
goldShimmer.style.height = sourceBounds.height; _goldShimmer.style.height = sourceBounds.height;
goldShimmer.AddToClassList("gold-shimmer-on"); _goldShimmer.AddToClassList("gold-shimmer-on");
goldShimmer.schedule.Execute(() => goldShimmer.RemoveFromClassList("gold-shimmer-on")).StartingIn(LegendaryShimmerMs); _goldShimmer.schedule.Execute(() => _goldShimmer.RemoveFromClassList("gold-shimmer-on")).StartingIn(LegendaryShimmerMs);
} }
private void EmitSparks(VisualElement source, Color color, int count, float radius) private void EmitSparks(VisualElement source, Color color, int count, float radius)
{ {
if (effectLayer == null || source == null) if (_effectLayer == null || source == null)
{ {
return; return;
} }
Rect sourceBounds = source.worldBound; Rect sourceBounds = source.worldBound;
Rect layerBounds = effectLayer.worldBound; Rect layerBounds = _effectLayer.worldBound;
float centerX = sourceBounds.center.x - layerBounds.x; float centerX = sourceBounds.center.x - layerBounds.x;
float centerY = sourceBounds.center.y - layerBounds.y; float centerY = sourceBounds.center.y - layerBounds.y;
float halfWidth = sourceBounds.width * 0.5f; float halfWidth = sourceBounds.width * 0.5f;
@@ -728,41 +728,41 @@ namespace KernelPanic.UI
VisualElement spark = new(); VisualElement spark = new();
spark.pickingMode = PickingMode.Ignore; spark.pickingMode = PickingMode.Ignore;
spark.AddToClassList("spark"); spark.AddToClassList("spark");
effectLayer.Add(spark); _effectLayer.Add(spark);
return spark; return spark;
} }
private void HandleKeyDown(KeyDownEvent evt) private void HandleKeyDown(KeyDownEvent evt)
{ {
if (revealComplete) if (_revealComplete)
{ {
ContinueToMenu(); ContinueToMenu();
evt.StopPropagation(); evt.StopPropagation();
return; return;
} }
skipRequested = true; _skipRequested = true;
evt.StopPropagation(); evt.StopPropagation();
} }
private void HandlePointerDown(PointerDownEvent evt) private void HandlePointerDown(PointerDownEvent evt)
{ {
if (revealComplete) if (_revealComplete)
{ {
return; return;
} }
skipRequested = true; _skipRequested = true;
evt.StopPropagation(); evt.StopPropagation();
} }
private void ShowContinue() private void ShowContinue()
{ {
continueButton.SetEnabled(true); _continueButton.SetEnabled(true);
continueButton.RemoveFromClassList("continue-button-pending"); _continueButton.RemoveFromClassList("continue-button-pending");
if (failed) if (_failed)
{ {
skipHint.text = "failed"; _skipHint.text = "failed";
} }
} }
@@ -789,17 +789,17 @@ namespace KernelPanic.UI
private sealed class PullCardView private sealed class PullCardView
{ {
private readonly CompletedGachaReward reward; private readonly CompletedGachaReward _reward;
private readonly Label rarityLabel; private readonly Label _rarityLabel;
private readonly Label nameLabel; private readonly Label _nameLabel;
private readonly Label statusLabel; private readonly Label _statusLabel;
private readonly Label typeIconLabel; private readonly Label _typeIconLabel;
private IVisualElementScheduledItem glowPulse; private IVisualElementScheduledItem _glowPulse;
private bool glowOn; private bool _glowOn;
public PullCardView(CompletedGachaReward reward) public PullCardView(CompletedGachaReward reward)
{ {
this.reward = reward; this._reward = reward;
RarityStyle rarity = RarityPresentation.ForStars(reward.Stars); RarityStyle rarity = RarityPresentation.ForStars(reward.Stars);
Root = new VisualElement(); Root = new VisualElement();
Root.AddToClassList("pull-card"); Root.AddToClassList("pull-card");
@@ -814,27 +814,27 @@ namespace KernelPanic.UI
indexLabel.AddToClassList("pull-index"); indexLabel.AddToClassList("pull-index");
top.Add(indexLabel); top.Add(indexLabel);
rarityLabel = new(rarity.Stars); _rarityLabel = new(rarity.Stars);
rarityLabel.AddToClassList("pull-rarity"); _rarityLabel.AddToClassList("pull-rarity");
rarityLabel.AddToClassList(rarity.ClassName); _rarityLabel.AddToClassList(rarity.ClassName);
top.Add(rarityLabel); top.Add(_rarityLabel);
typeIconLabel = new(reward.IsCharacter ? "@" : "#"); _typeIconLabel = new(reward.IsCharacter ? "@" : "#");
typeIconLabel.tooltip = reward.TypeText; _typeIconLabel.tooltip = reward.TypeText;
typeIconLabel.AddToClassList("pull-type-icon"); _typeIconLabel.AddToClassList("pull-type-icon");
top.Add(typeIconLabel); top.Add(_typeIconLabel);
nameLabel = new(reward.DisplayName); _nameLabel = new(reward.DisplayName);
nameLabel.AddToClassList("pull-name"); _nameLabel.AddToClassList("pull-name");
Root.Add(nameLabel); Root.Add(_nameLabel);
statusLabel = new(reward.StatusText); _statusLabel = new(reward.StatusText);
statusLabel.AddToClassList("pull-status"); _statusLabel.AddToClassList("pull-status");
statusLabel.EnableInClassList("pull-status-new", reward.OutcomeKind == PullOutcomeKind.Granted); _statusLabel.EnableInClassList("pull-status-new", reward.OutcomeKind == PullOutcomeKind.Granted);
statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText); _statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText);
if (statusLabel.visible) if (_statusLabel.visible)
{ {
Root.Add(statusLabel); Root.Add(_statusLabel);
} }
} }
@@ -846,11 +846,11 @@ namespace KernelPanic.UI
Root.AddToClassList("pull-card-held"); Root.AddToClassList("pull-card-held");
Root.EnableInClassList("pull-card-held-rare", stars == 4); Root.EnableInClassList("pull-card-held-rare", stars == 4);
Root.EnableInClassList("pull-card-held-legendary", stars >= 5); Root.EnableInClassList("pull-card-held-legendary", stars >= 5);
rarityLabel.text = "..."; _rarityLabel.text = "...";
nameLabel.text = holdText; _nameLabel.text = holdText;
statusLabel.text = ""; _statusLabel.text = "";
statusLabel.visible = false; _statusLabel.visible = false;
typeIconLabel.visible = false; _typeIconLabel.visible = false;
} }
public void HideHold() public void HideHold()
@@ -862,21 +862,21 @@ namespace KernelPanic.UI
public void Reveal(bool allowFlash, bool persistentMotion) 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-hidden");
Root.RemoveFromClassList("pull-card-held"); Root.RemoveFromClassList("pull-card-held");
Root.RemoveFromClassList("pull-card-held-rare"); Root.RemoveFromClassList("pull-card-held-rare");
Root.RemoveFromClassList("pull-card-held-legendary"); Root.RemoveFromClassList("pull-card-held-legendary");
Root.AddToClassList("pull-card-revealed"); Root.AddToClassList("pull-card-revealed");
Root.EnableInClassList("pull-card-glow-4", persistentMotion && reward.Stars == 4); Root.EnableInClassList("pull-card-glow-4", persistentMotion && _reward.Stars == 4);
Root.EnableInClassList("pull-card-glow-5", persistentMotion && reward.Stars >= 5); Root.EnableInClassList("pull-card-glow-5", persistentMotion && _reward.Stars >= 5);
SetPersistentGlow(persistentMotion && reward.Stars >= 5); SetPersistentGlow(persistentMotion && _reward.Stars >= 5);
rarityLabel.text = reward.Stars >= 5 ? $"{rarity.Badge} {rarity.Stars}" : rarity.Stars; _rarityLabel.text = _reward.Stars >= 5 ? $"{rarity.Badge} {rarity.Stars}" : rarity.Stars;
nameLabel.text = reward.DisplayName; _nameLabel.text = _reward.DisplayName;
typeIconLabel.text = reward.IsCharacter ? "@" : "#"; _typeIconLabel.text = _reward.IsCharacter ? "@" : "#";
typeIconLabel.visible = true; _typeIconLabel.visible = true;
statusLabel.text = reward.StatusText; _statusLabel.text = _reward.StatusText;
statusLabel.visible = !string.IsNullOrWhiteSpace(reward.StatusText); _statusLabel.visible = !string.IsNullOrWhiteSpace(_reward.StatusText);
if (allowFlash) if (allowFlash)
{ {
Root.AddToClassList("pull-card-flash"); Root.AddToClassList("pull-card-flash");
@@ -897,34 +897,34 @@ namespace KernelPanic.UI
public void PulseStatus(int durationMs) public void PulseStatus(int durationMs)
{ {
if (!statusLabel.visible) if (!_statusLabel.visible)
{ {
return; return;
} }
statusLabel.AddToClassList("pull-status-pop"); _statusLabel.AddToClassList("pull-status-pop");
statusLabel.schedule.Execute(() => statusLabel.RemoveFromClassList("pull-status-pop")).StartingIn(durationMs); _statusLabel.schedule.Execute(() => _statusLabel.RemoveFromClassList("pull-status-pop")).StartingIn(durationMs);
} }
private void SetPersistentGlow(bool enabled) private void SetPersistentGlow(bool enabled)
{ {
if (!enabled) if (!enabled)
{ {
glowPulse?.Pause(); _glowPulse?.Pause();
Root.RemoveFromClassList("pull-card-glow-on"); Root.RemoveFromClassList("pull-card-glow-on");
return; return;
} }
if (glowPulse != null) if (_glowPulse != null)
{ {
glowPulse.Resume(); _glowPulse.Resume();
return; return;
} }
glowPulse = Root.schedule.Execute(() => _glowPulse = Root.schedule.Execute(() =>
{ {
glowOn = !glowOn; _glowOn = !_glowOn;
Root.EnableInClassList("pull-card-glow-on", glowOn); Root.EnableInClassList("pull-card-glow-on", _glowOn);
}).Every(900); }).Every(900);
} }
} }
+9 -9
View File
@@ -28,8 +28,8 @@ namespace KernelPanic.UI
"Courier New" "Courier New"
}; };
private static FontAsset runtimeMonospaceFont; private static FontAsset _runtimeMonospaceFont;
private static bool warnedMissingFont; private static bool _warnedMissingFont;
public static FontAsset Resolve(FontAsset configuredFont) public static FontAsset Resolve(FontAsset configuredFont)
{ {
@@ -38,25 +38,25 @@ namespace KernelPanic.UI
return configuredFont; return configuredFont;
} }
if (runtimeMonospaceFont != null) if (_runtimeMonospaceFont != null)
{ {
return runtimeMonospaceFont; return _runtimeMonospaceFont;
} }
Font dynamicFont = Font.CreateDynamicFontFromOSFont(PreferredMonospaceFontFamilies, 16); Font dynamicFont = Font.CreateDynamicFontFromOSFont(PreferredMonospaceFontFamilies, 16);
if (dynamicFont == null) if (dynamicFont == null)
{ {
if (!warnedMissingFont) if (!_warnedMissingFont)
{ {
Debug.LogWarning("No monospace OS font found; terminal UI will use Unity's default font."); Debug.LogWarning("No monospace OS font found; terminal UI will use Unity's default font.");
warnedMissingFont = true; _warnedMissingFont = true;
} }
return null; return null;
} }
runtimeMonospaceFont = FontAsset.CreateFontAsset(dynamicFont); _runtimeMonospaceFont = FontAsset.CreateFontAsset(dynamicFont);
return runtimeMonospaceFont; return _runtimeMonospaceFont;
} }
} }
@@ -667,7 +667,7 @@ namespace KernelPanic.UI
_saveData = _saveService.Load(); _saveData = _saveService.Load();
// Snapshot before the next EnsureLists() call below, which re-runs NormalizeOwnedPackages // Snapshot before the next EnsureLists() call below, which re-runs NormalizeOwnedPackages
// and would otherwise clear this (no new duplicates survive a second normalization pass). // 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(); _saveData.EnsureLists();
_wallet.SetBalance(_saveData.entropyBalance); _wallet.SetBalance(_saveData.entropyBalance);