Merge remote-tracking branch 'origin/main'
This commit is contained in:
+82
-56
@@ -11,30 +11,40 @@
|
|||||||
</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/Scripts/Combat/EnemyArchetype.cs" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/AurHelper.asset" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/AurHelper.asset.meta" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/ConsultWiki.asset" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/ConsultWiki.asset.meta" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/Makepkg.asset" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/Makepkg.asset.meta" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/MinimalInstall.asset" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/MinimalInstall.asset.meta" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/PacmanSyu.asset" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Assets/Data/Cards/Arch/PacmanSyu.asset.meta" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/.idea.linuxdistrosbuttheyarebreedable/.idea/indexLayout.xml" beforeDir="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/Fedora/DnfUpdate.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Fedora/DnfUpdate.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/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/C/Pointer.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Pointer.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/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/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/Cards/Languages/Java/JavaNewObject.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaNewObject.asset" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaPublicStaticMain.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaPublicStaticMain.asset" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaSystemOutPrintln.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaSystemOutPrintln.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/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/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/Data/Cards/Shop/Sizeof.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Data/Cards/Shop/Sizeof.asset" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/Assets/Resources/CombatScene.uss" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Resources/CombatScene.uss" 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/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/Combat/EnemyArchetype.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyArchetype.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/Combat/EnemyInstance.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/EnemyInstance.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/Combat/StatusEffectController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Combat/StatusEffectController.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/Run/RepositoryOffer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Run/RepositoryOffer.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/CombatSceneController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/CombatSceneController.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/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" />
|
|
||||||
</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" />
|
||||||
@@ -66,15 +76,22 @@
|
|||||||
}
|
}
|
||||||
}</component>
|
}</component>
|
||||||
<component name="HighlightingSettingsPerFile">
|
<component name="HighlightingSettingsPerFile">
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Arch/AurHelper.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Arch/ConsultWiki.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Arch/PacmanSyu.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/BorrowChecker.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/BorrowChecker.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/CargoBuildRelease.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/CargoBuildRelease.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/DnfUpdate.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Fedora/DnfUpdate.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Malloc.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Malloc.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Pointer.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/C/Printf.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaPublicStaticMain.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaPublicStaticMain.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaSystemOutPrintln.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Java/JavaSystemOutPrintln.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Python/PyPrint.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Python/PyPrint.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Rust/RsBorrow.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Rust/RsBorrow.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Rust/RsUnwrap.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Languages/Rust/RsUnwrap.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Shop/Free.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Shop/KernelExploit.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Ubuntu/AskUbuntu.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Ubuntu/AskUbuntu.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Ubuntu/UbuntuProTrial.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Cards/Ubuntu/UbuntuProTrial.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
<setting file="file://$PROJECT_DIR$/Assets/Data/Distros/DistroDatabase.asset" root0="FORCE_HIGHLIGHTING" />
|
<setting file="file://$PROJECT_DIR$/Assets/Data/Distros/DistroDatabase.asset" root0="FORCE_HIGHLIGHTING" />
|
||||||
@@ -111,23 +128,23 @@
|
|||||||
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
|
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
|
||||||
<component name="NextEditCompletionFeaturesState">
|
<component name="NextEditCompletionFeaturesState">
|
||||||
<decayedCancelled>
|
<decayedCancelled>
|
||||||
<entry key="MS100" value="1.5438155496731856" />
|
<entry key="MS100" value="1.743262326028233" />
|
||||||
<entry key="MS500" value="5.416837026621939" />
|
<entry key="MS500" value="5.976929062573193" />
|
||||||
<entry key="S2" value="12.668957872278758" />
|
<entry key="S2" value="17.53689034207893" />
|
||||||
<entry key="S5" value="16.026673635995547" />
|
<entry key="S5" value="27.584806857875957" />
|
||||||
<entry key="S10" value="17.426595593285192" />
|
<entry key="S10" value="33.27162043754185" />
|
||||||
<entry key="S30" value="18.454820586422397" />
|
<entry key="S30" value="38.14780953249457" />
|
||||||
<entry key="S60" value="18.72472582023672" />
|
<entry key="S60" value="39.53571836868974" />
|
||||||
<entry key="M2" value="18.86168439667557" />
|
<entry key="M2" value="40.262726944904955" />
|
||||||
<entry key="M5" value="18.95087896044715" />
|
<entry key="M5" value="43.32220297215448" />
|
||||||
<entry key="M10" value="19.972234082604384" />
|
<entry key="M10" value="66.17309975101882" />
|
||||||
<entry key="M15" value="25.48708802307527" />
|
<entry key="M15" value="106.65472090214925" />
|
||||||
<entry key="M30" value="70.33485962789716" />
|
<entry key="M30" value="269.18080676227913" />
|
||||||
<entry key="H1" value="193.24800336339004" />
|
<entry key="H1" value="561.7788280748766" />
|
||||||
<entry key="H2" value="411.97552826367775" />
|
<entry key="H2" value="954.5740596560953" />
|
||||||
<entry key="H4" value="796.6715755808564" />
|
<entry key="H4" value="1474.025592246917" />
|
||||||
<entry key="D1" value="3240.2139167478695" />
|
<entry key="D1" value="4120.268616608263" />
|
||||||
<entry key="W1" value="5547.574956248048" />
|
<entry key="W1" value="6567.8208311010485" />
|
||||||
</decayedCancelled>
|
</decayedCancelled>
|
||||||
<decayedSelected>
|
<decayedSelected>
|
||||||
<entry key="MS100" value="0.0" />
|
<entry key="MS100" value="0.0" />
|
||||||
@@ -138,34 +155,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="6.004482652781533E-147" />
|
<entry key="M5" value="9.303102041982209E-153" />
|
||||||
<entry key="M10" value="7.748859692098003E-74" />
|
<entry key="M10" value="9.645258960745102E-77" />
|
||||||
<entry key="M15" value="1.817573009109616E-49" />
|
<entry key="M15" value="2.1031775057960495E-51" />
|
||||||
<entry key="M30" value="4.263301749081961E-25" />
|
<entry key="M30" value="4.586042805192191E-26" />
|
||||||
<entry key="H1" value="6.535814477556539E-13" />
|
<entry key="H1" value="2.1436097902215403E-13" />
|
||||||
<entry key="H2" value="8.519293271851925E-7" />
|
<entry key="H2" value="4.878952351612686E-7" />
|
||||||
<entry key="H4" value="0.0012617458857475668" />
|
<entry key="H4" value="9.54846149789426E-4" />
|
||||||
<entry key="D1" value="0.9778028711909533" />
|
<entry key="D1" value="0.9334224145260533" />
|
||||||
<entry key="W1" value="3.2663828053013284" />
|
<entry key="W1" value="3.244779666296953" />
|
||||||
</decayedSelected>
|
</decayedSelected>
|
||||||
<decayedShown>
|
<decayedShown>
|
||||||
<entry key="MS100" value="1.4317187710347317" />
|
<entry key="MS100" value="1.668533264021644" />
|
||||||
<entry key="MS500" value="5.34064632290837" />
|
<entry key="MS500" value="5.913573457970713" />
|
||||||
<entry key="S2" value="12.621006367063478" />
|
<entry key="S2" value="17.47919105497625" />
|
||||||
<entry key="S5" value="16.001716646214877" />
|
<entry key="S5" value="27.548161746345162" />
|
||||||
<entry key="S10" value="17.412885614576528" />
|
<entry key="S10" value="33.249516115897215" />
|
||||||
<entry key="S30" value="18.449946114998543" />
|
<entry key="S30" value="38.1393616328719" />
|
||||||
<entry key="S60" value="18.722248425273893" />
|
<entry key="S60" value="39.53134062098556" />
|
||||||
<entry key="M2" value="18.860435494937665" />
|
<entry key="M2" value="40.26049784489663" />
|
||||||
<entry key="M5" value="18.95037608361192" />
|
<entry key="M5" value="43.32125926171084" />
|
||||||
<entry key="M10" value="19.971930307306003" />
|
<entry key="M10" value="66.17242872752867" />
|
||||||
<entry key="M15" value="25.486739213245762" />
|
<entry key="M15" value="106.65399822613271" />
|
||||||
<entry key="M30" value="70.33427160959226" />
|
<entry key="M30" value="269.1797553890588" />
|
||||||
<entry key="H1" value="193.24731132495674" />
|
<entry key="H1" value="561.7775677248208" />
|
||||||
<entry key="H2" value="411.97491708219036" />
|
<entry key="H2" value="954.5729275577665" />
|
||||||
<entry key="H4" value="796.6723332411082" />
|
<entry key="H4" value="1474.025680151079" />
|
||||||
<entry key="D1" value="3241.1913812104362" />
|
<entry key="D1" value="4121.2016186941155" />
|
||||||
<entry key="W1" value="5550.841244628519" />
|
<entry key="W1" value="6571.065502619166" />
|
||||||
</decayedShown>
|
</decayedShown>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectColorInfo">{
|
<component name="ProjectColorInfo">{
|
||||||
@@ -258,7 +275,8 @@
|
|||||||
<workItem from="1783507489679" duration="5909000" />
|
<workItem from="1783507489679" duration="5909000" />
|
||||||
<workItem from="1783519887449" duration="6425000" />
|
<workItem from="1783519887449" duration="6425000" />
|
||||||
<workItem from="1783578446731" duration="20118000" />
|
<workItem from="1783578446731" duration="20118000" />
|
||||||
<workItem from="1783615847433" duration="3713000" />
|
<workItem from="1783615847433" duration="3791000" />
|
||||||
|
<workItem from="1783665689762" duration="4791000" />
|
||||||
</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" />
|
||||||
@@ -484,7 +502,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1783614775509</updated>
|
<updated>1783614775509</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="29" />
|
<task id="LOCAL-00029" summary="Fix C, more enemies and less scaling for enemies.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1783620160977</created>
|
||||||
|
<option name="number" value="00029" />
|
||||||
|
<option name="presentableId" value="LOCAL-00029" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1783620160977</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="30" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -500,7 +526,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="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 Upgrade UI to Level 6 Balls" />
|
<MESSAGE value="Add actual carts and shit Upgrade UI to Level 6 Balls" />
|
||||||
<MESSAGE value="Implement more UX and cards for other distros" />
|
<MESSAGE value="Implement more UX and cards for other distros" />
|
||||||
@@ -525,7 +550,8 @@
|
|||||||
<MESSAGE value="restructure packages (it looks shit)" />
|
<MESSAGE value="restructure packages (it looks shit)" />
|
||||||
<MESSAGE value="Make multiple UX improvements in distro -> packages" />
|
<MESSAGE value="Make multiple UX improvements in distro -> packages" />
|
||||||
<MESSAGE value="Implement Arch and some additional changes" />
|
<MESSAGE value="Implement Arch and some additional changes" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Implement Arch and some additional changes" />
|
<MESSAGE value="Fix C, more enemies and less scaling for enemies." />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Fix C, more enemies and less scaling for enemies." />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
|
||||||
|
m_Name: AurHelper
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
id: arch_aur_helper
|
||||||
|
displayName: AUR helper
|
||||||
|
description: add a random common C or Rust card to hand. it costs 0 this turn.
|
||||||
|
flavorText: definitely read the PKGBUILD. definitely.
|
||||||
|
language: 2
|
||||||
|
rarity: 1
|
||||||
|
cycleCost: 1
|
||||||
|
resolutionTrack: 0
|
||||||
|
distroExclusive: 1
|
||||||
|
isToken: 0
|
||||||
|
isRunOnly: 0
|
||||||
|
designNotes: Arch exclusive. Uses existing generated-card pool; reports TODO if C/Rust commons are unavailable.
|
||||||
|
requiresSystem: []
|
||||||
|
upgradeTarget: {fileID: 0}
|
||||||
|
effects: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa110000000000000000000000000004
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
|
||||||
|
m_Name: ConsultWiki
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
id: arch_consult_wiki
|
||||||
|
displayName: Consult the Wiki
|
||||||
|
description: fix a broken card and draw 1. if none are broken, deal 6.
|
||||||
|
flavorText: the answer was in a footnote from 2013.
|
||||||
|
language: 2
|
||||||
|
rarity: 0
|
||||||
|
cycleCost: 0
|
||||||
|
resolutionTrack: 0
|
||||||
|
distroExclusive: 1
|
||||||
|
isToken: 0
|
||||||
|
isRunOnly: 0
|
||||||
|
designNotes: Arch exclusive. Uses existing IsBroken flag if present; card-break creation is TODO, draw/damage fallback works now.
|
||||||
|
requiresSystem:
|
||||||
|
- card-break
|
||||||
|
upgradeTarget: {fileID: 0}
|
||||||
|
effects: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa110000000000000000000000000002
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
|
||||||
|
m_Name: Makepkg
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
id: arch_makepkg
|
||||||
|
displayName: makepkg
|
||||||
|
description: deal 7 + btw stacks x3; x4 at Arch v3+. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
|
flavorText: it built on my machine, which is the only machine.
|
||||||
|
language: 0
|
||||||
|
rarity: 1
|
||||||
|
cycleCost: 2
|
||||||
|
resolutionTrack: 0
|
||||||
|
distroExclusive: 1
|
||||||
|
isToken: 0
|
||||||
|
isRunOnly: 0
|
||||||
|
designNotes: Arch exclusive. Reads CombatantState.ArchBtwStacks, then damage still routes through DamagePipeline and receives normal btw flat bonus too.
|
||||||
|
requiresSystem: []
|
||||||
|
upgradeTarget: {fileID: 0}
|
||||||
|
effects: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa110000000000000000000000000003
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
|
||||||
|
m_Name: MinimalInstall
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
id: arch_minimal_install
|
||||||
|
displayName: minimal install
|
||||||
|
description: exhaust up to 2 cards from hand. per card exhausted, gain 3 Shield and 1 Cycle.
|
||||||
|
flavorText: no desktop, no browser, no regrets.
|
||||||
|
language: 2
|
||||||
|
rarity: 1
|
||||||
|
cycleCost: 1
|
||||||
|
resolutionTrack: 0
|
||||||
|
distroExclusive: 1
|
||||||
|
isToken: 0
|
||||||
|
isRunOnly: 0
|
||||||
|
designNotes: Arch exclusive. Exhausts first available hand cards using existing exhaust pile, shield, and cycle systems.
|
||||||
|
requiresSystem: []
|
||||||
|
upgradeTarget: {fileID: 0}
|
||||||
|
effects: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa110000000000000000000000000005
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5178747fac4dbfc448ff15d8a687e03c, type: 3}
|
||||||
|
m_Name: PacmanSyu
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
id: arch_pacman_syu
|
||||||
|
displayName: pacman -Syu
|
||||||
|
description: deal 14. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
|
flavorText: full system upgrade. what could possibly ABI wrong?
|
||||||
|
language: 0
|
||||||
|
rarity: 1
|
||||||
|
cycleCost: 1
|
||||||
|
resolutionTrack: 0
|
||||||
|
distroExclusive: 1
|
||||||
|
isToken: 0
|
||||||
|
isRunOnly: 0
|
||||||
|
designNotes: Arch exclusive. Damage and segfault card corruption are live through DamagePipeline and the broken-card hand state.
|
||||||
|
requiresSystem: []
|
||||||
|
upgradeTarget: {fileID: 0}
|
||||||
|
effects: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa110000000000000000000000000001
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: fedora_dnf_update
|
id: fedora_dnf_update
|
||||||
displayName: dnf update
|
displayName: dnf update
|
||||||
description: deal 9. costs 1 less per java card played this combat (min 0).
|
description: deal 9. overkill spills. costs 1 less per java card played this combat (min 0).
|
||||||
flavorText: today everything gets newer.
|
flavorText: today everything gets newer.
|
||||||
language: 8
|
language: 8
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -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: uptime -3.
|
description: deal 12. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
flavorText: memory acquired. ownership emotionally unresolved.
|
flavorText: memory acquired. ownership emotionally unresolved.
|
||||||
language: 0
|
language: 0
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -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. 20% segfault: uptime -3.
|
description: deal 9. if the previous card was C, deal 15 instead. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
flavorText: points at the bug with suspicious confidence.
|
flavorText: points at the bug with suspicious confidence.
|
||||||
language: 0
|
language: 0
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: lang_c_printf
|
id: lang_c_printf
|
||||||
displayName: printf()
|
displayName: printf()
|
||||||
description: deal 4. 20% segfault: uptime -3.
|
description: deal 7. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
flavorText: debugging by yelling into the void.
|
flavorText: debugging by yelling into the void.
|
||||||
language: 0
|
language: 0
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: lang_java_new_object
|
id: lang_java_new_object
|
||||||
displayName: new Object()
|
displayName: new Object()
|
||||||
description: uses 2 RAM. deal 3. JIT applies.
|
description: uses 2 RAM. deal 3. overkill spills. JIT applies.
|
||||||
flavorText: allocation as a love language.
|
flavorText: allocation as a love language.
|
||||||
language: 8
|
language: 8
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: lang_java_public_static_main
|
id: lang_java_public_static_main
|
||||||
displayName: public static void main
|
displayName: public static void main
|
||||||
description: uses 2 RAM. deal 7. JIT: Java cards cost 1 less this combat each time you play a Java card; the discount decays by 1 after each wave.
|
description: uses 2 RAM. deal 7. overkill spills. JIT: Java cards cost 1 less this combat each time you play a Java card; the discount decays by 1 after each wave.
|
||||||
flavorText: verbose, but warmed up.
|
flavorText: verbose, but warmed up.
|
||||||
language: 8
|
language: 8
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: lang_java_system_out_println
|
id: lang_java_system_out_println
|
||||||
displayName: System.out.println
|
displayName: System.out.println
|
||||||
description: uses 2 RAM. deal 5. JIT applies.
|
description: uses 2 RAM. deal 5. overkill spills. JIT applies.
|
||||||
flavorText: standard output, standard damage.
|
flavorText: standard output, standard damage.
|
||||||
language: 8
|
language: 8
|
||||||
rarity: 0
|
rarity: 0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
id: shop_c_free
|
id: shop_c_free
|
||||||
displayName: free()
|
displayName: free()
|
||||||
description: deal 12. 20% segfault: uptime -3 and draw 2.
|
description: deal 18. overkill spills. 20% segfault: uptime -3, corrupt a random card in hand, 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
|
||||||
|
|||||||
@@ -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: uptime -8.
|
description: deal 36 ignoring Shield. overkill spills. 50% segfault: uptime -8 and corrupt a random card in hand.
|
||||||
flavorText: privilege escalated. heartbeat also escalated.
|
flavorText: privilege escalated. heartbeat also escalated.
|
||||||
language: 0
|
language: 0
|
||||||
rarity: 1
|
rarity: 1
|
||||||
|
|||||||
@@ -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. 20% segfault: uptime -3.
|
description: deal 5 x C cards in hand. overkill spills. 20% segfault: uptime -3 and corrupt a random card in hand.
|
||||||
flavorText: compile-time confidence, runtime consequences.
|
flavorText: compile-time confidence, runtime consequences.
|
||||||
language: 0
|
language: 0
|
||||||
rarity: 1
|
rarity: 1
|
||||||
|
|||||||
@@ -400,10 +400,23 @@
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.enemy-scroll {
|
||||||
|
flex-grow: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-scroll .unity-scroll-view__content-container {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.enemy-row {
|
.enemy-row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
min-height: 0;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +435,64 @@
|
|||||||
color: var(--kp-text);
|
color: var(--kp-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.enemy-row-compact {
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact {
|
||||||
|
width: 98px;
|
||||||
|
min-height: 126px;
|
||||||
|
margin-right: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .enemy-name {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .meter-block {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .meter-head {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .metric-label,
|
||||||
|
.enemy-card-compact .status-label,
|
||||||
|
.enemy-card-compact .enemy-shield {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .metric-value,
|
||||||
|
.enemy-card-compact .metric-value-muted {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .meter-track {
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .status-pip,
|
||||||
|
.enemy-card-compact .tag {
|
||||||
|
font-size: 9px;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
margin-right: 3px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .intent-panel {
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-card-compact .intent-value {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.enemy-card:hover {
|
.enemy-card:hover {
|
||||||
border-color: var(--kp-border-strong);
|
border-color: var(--kp-border-strong);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace KernelPanic.Combat
|
|||||||
{
|
{
|
||||||
public sealed class DealDamageEffect : ICardEffect
|
public sealed class DealDamageEffect : ICardEffect
|
||||||
{
|
{
|
||||||
|
private const int RustOverflowRollMax = 1000000;
|
||||||
|
private const string RustUnsigned64LimitText = "18446744073709551615";
|
||||||
|
|
||||||
private readonly int _minAmount;
|
private readonly int _minAmount;
|
||||||
private readonly int _maxAmount;
|
private readonly int _maxAmount;
|
||||||
private readonly Language _language;
|
private readonly Language _language;
|
||||||
@@ -49,22 +52,80 @@ namespace KernelPanic.Combat
|
|||||||
int amount = minAmount == maxAmount
|
int amount = minAmount == maxAmount
|
||||||
? minAmount
|
? minAmount
|
||||||
: RandomRoll.RollRange(minAmount, maxAmount, new RollContext(context.Source));
|
: RandomRoll.RollRange(minAmount, maxAmount, new RollContext(context.Source));
|
||||||
|
bool rustUnsignedOverflow = IsRustDamage(context)
|
||||||
|
&& RandomRoll.RollRange(1, RustOverflowRollMax, new RollContext(context.Source)) == 1;
|
||||||
|
if (rustUnsignedOverflow)
|
||||||
|
{
|
||||||
|
amount = int.MaxValue;
|
||||||
|
context.CombatManager.ReportEffectResult($"rust unsigned overflow: {RustUnsigned64LimitText}");
|
||||||
|
}
|
||||||
|
|
||||||
bool rustOverkillToShield = _language == Language.Rust || context.Card?.Definition?.Language == Language.Rust;
|
bool rustOverkillToShield = IsRustDamage(context);
|
||||||
int survivable = rustOverkillToShield
|
bool overkillSpills = IsSpillDamage(context);
|
||||||
? _trueDamage ? target.CurrentUptime : target.CurrentUptime + target.Shield
|
int survivable = rustOverkillToShield || overkillSpills
|
||||||
|
? GetSurvivableDamage(target, _trueDamage)
|
||||||
: 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 && !rustUnsignedOverflow));
|
||||||
dealtDamage |= result.IncomingAmount > 0;
|
dealtDamage |= result.IncomingAmount > 0;
|
||||||
if (rustOverkillToShield)
|
if (rustOverkillToShield)
|
||||||
{
|
{
|
||||||
GrantRustOverkillShield(context, result, survivable);
|
GrantRustOverkillShield(context, result, survivable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (overkillSpills)
|
||||||
|
{
|
||||||
|
dealtDamage |= SpillOverkillDamage(context, target, result, survivable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SegfaultRecoil.TryApply(context, _language, dealtDamage);
|
SegfaultRecoil.TryApply(context, _language, dealtDamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsRustDamage(CombatContext context)
|
||||||
|
{
|
||||||
|
return _language == Language.Rust || context.Card?.Definition?.Language == Language.Rust;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSpillDamage(CombatContext context)
|
||||||
|
{
|
||||||
|
Language cardLanguage = context.Card?.Definition == null ? _language : context.Card.Definition.Language;
|
||||||
|
return _language == Language.C
|
||||||
|
|| _language == Language.Java
|
||||||
|
|| cardLanguage == Language.C
|
||||||
|
|| cardLanguage == Language.Java;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetSurvivableDamage(CombatantState target, bool trueDamage)
|
||||||
|
{
|
||||||
|
return target == null ? 0 : trueDamage ? target.CurrentUptime : target.CurrentUptime + target.Shield;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SpillOverkillDamage(CombatContext context, CombatantState firstTarget, DamageResult firstResult, int firstSurvivable)
|
||||||
|
{
|
||||||
|
int remaining = UnityEngine.Mathf.Max(0, firstResult.IncomingAmount - firstSurvivable);
|
||||||
|
if (remaining <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dealtDamage = false;
|
||||||
|
for (int i = 0; i < context.Enemies.Count && remaining > 0; i++)
|
||||||
|
{
|
||||||
|
CombatantState spillTarget = context.Enemies[i].State;
|
||||||
|
if (spillTarget == null || spillTarget == firstTarget || spillTarget.IsDefeated)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int survivable = GetSurvivableDamage(spillTarget, _trueDamage);
|
||||||
|
DamageResult spillResult = context.DamagePipeline.DealDamage(new DamageRequest(context.Source, spillTarget, remaining, _language, _trueDamage, false, applySourceModifiers: false));
|
||||||
|
dealtDamage |= spillResult.IncomingAmount > 0;
|
||||||
|
remaining = UnityEngine.Mathf.Max(0, spillResult.IncomingAmount - survivable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dealtDamage;
|
||||||
|
}
|
||||||
|
|
||||||
private static void GrantRustOverkillShield(CombatContext context, DamageResult result, int survivable)
|
private static void GrantRustOverkillShield(CombatContext context, DamageResult result, int survivable)
|
||||||
{
|
{
|
||||||
int overkill = UnityEngine.Mathf.Max(0, result.IncomingAmount - survivable);
|
int overkill = UnityEngine.Mathf.Max(0, result.IncomingAmount - survivable);
|
||||||
@@ -165,7 +226,9 @@ namespace KernelPanic.Combat
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int roll = RandomRoll.RollRange(1, 100, new RollContext(context.Source));
|
int roll = context.Source != null && context.Source.ForceMaxRolls
|
||||||
|
? 1
|
||||||
|
: RandomRoll.RollRange(1, 100, RollContext.None);
|
||||||
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;
|
||||||
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));
|
||||||
@@ -308,7 +371,7 @@ namespace KernelPanic.Combat
|
|||||||
public void Execute(CombatContext context)
|
public void Execute(CombatContext context)
|
||||||
{
|
{
|
||||||
int cCards = context.HandController.Cards.Count(card => card?.Definition != null && card.Definition.Language == Language.C);
|
int cCards = context.HandController.Cards.Count(card => card?.Definition != null && card.Definition.Language == Language.C);
|
||||||
int amount = 3 * cCards;
|
int amount = 5 * cCards;
|
||||||
new DealDamageEffect(amount, amount, Language.C).Execute(context);
|
new DealDamageEffect(amount, amount, Language.C).Execute(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -873,6 +936,7 @@ namespace KernelPanic.Combat
|
|||||||
|
|
||||||
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(null, context.Source, uptimeDamage, Language.C, true, false));
|
DamageResult result = context.DamagePipeline.DealDamage(new DamageRequest(null, context.Source, uptimeDamage, Language.C, true, false));
|
||||||
context.CombatManager.ReportEffectResult($"segfault: uptime -{result.FinalAmount}");
|
context.CombatManager.ReportEffectResult($"segfault: uptime -{result.FinalAmount}");
|
||||||
|
context.CombatManager.TryCorruptRandomHandCard("segfault");
|
||||||
if (drawOnSegfault)
|
if (drawOnSegfault)
|
||||||
{
|
{
|
||||||
context.CombatManager.DrawCards(2, "free() recoil");
|
context.CombatManager.DrawCards(2, "free() recoil");
|
||||||
@@ -922,9 +986,9 @@ 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 DealDamageEffect(8, 8, Language.C)),
|
"lang_c_malloc" => One(new DealDamageEffect(12, 12, Language.C)),
|
||||||
"lang_c_printf" => One(new DealDamageEffect(4, 4, Language.C)),
|
"lang_c_printf" => One(new DealDamageEffect(7, 7, Language.C)),
|
||||||
"lang_c_pointer" => One(new PreviousLanguageDamageEffect(6, 10, Language.C)),
|
"lang_c_pointer" => One(new PreviousLanguageDamageEffect(9, 15, 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)),
|
||||||
"lang_java_system_out_println" => One(new DealDamageEffect(5, 5, Language.Java)),
|
"lang_java_system_out_println" => One(new DealDamageEffect(5, 5, Language.Java)),
|
||||||
"lang_java_new_object" => One(new DealDamageEffect(3, 3, Language.Java)),
|
"lang_java_new_object" => One(new DealDamageEffect(3, 3, Language.Java)),
|
||||||
@@ -976,14 +1040,14 @@ namespace KernelPanic.Combat
|
|||||||
"fedora_dnf_update" => One(new DealDamageEffect(9, 9, Language.Java)),
|
"fedora_dnf_update" => One(new DealDamageEffect(9, 9, Language.Java)),
|
||||||
"fedora_rawhide" => One(new RawhideEffect()),
|
"fedora_rawhide" => One(new RawhideEffect()),
|
||||||
"fedora_selinux" => One(new IncomingAttackHalveEffect(2)),
|
"fedora_selinux" => One(new IncomingAttackHalveEffect(2)),
|
||||||
"arch_pacman_syu" => One(new DealDamageEffect(8, 8, Language.C)),
|
"arch_pacman_syu" => One(new DealDamageEffect(14, 14, Language.C)),
|
||||||
"arch_consult_wiki" => One(new ConsultWikiEffect()),
|
"arch_consult_wiki" => One(new ConsultWikiEffect()),
|
||||||
"arch_makepkg" => One(new BtwScaledDamageEffect(4, 2, Language.C)),
|
"arch_makepkg" => One(new BtwScaledDamageEffect(7, 3, 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 DealDamageEffect(12, 12, Language.C)),
|
"shop_c_free" => One(new DealDamageEffect(18, 18, Language.C)),
|
||||||
"shop_c_sizeof" => One(new SizeofDamageEffect()),
|
"shop_c_sizeof" => One(new SizeofDamageEffect()),
|
||||||
"shop_c_kernel_exploit" => One(new DealDamageEffect(25, 25, Language.C, true)),
|
"shop_c_kernel_exploit" => One(new DealDamageEffect(36, 36, Language.C, true)),
|
||||||
_ => Todo("card effect is not authored")
|
_ => Todo("card effect is not authored")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1053,12 +1117,12 @@ 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, uptime -3.{marker}",
|
"lang_c_malloc" => $"deal {UpgradeMath.ScaleAmount(12, card)}. overkill spills. 20%: segfault, uptime -3 and corrupt a hand card.{marker}",
|
||||||
"lang_c_printf" => $"deal {UpgradeMath.ScaleAmount(4, card)}. 20%: segfault, uptime -3.{marker}",
|
"lang_c_printf" => $"deal {UpgradeMath.ScaleAmount(7, card)}. overkill spills. 20%: segfault, uptime -3 and corrupt a hand card.{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_c_pointer" => $"deal {UpgradeMath.ScaleAmount(9, card)}; {UpgradeMath.ScaleAmount(15, card)} if the previous card was C. overkill spills. 20%: segfault, uptime -3 and corrupt a hand card.{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)}. overkill spills. 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)}. overkill spills. 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)}. overkill spills. JIT applies; discount decays by 1 after each wave.{marker}",
|
||||||
"shop_py_list_append" => $"queue: deal {UpgradeMath.ScaleAmount(4 + UnityEngine.Mathf.Max(0, card.QueuePlayCount - 1), card)}; +1 each time re-queued.{marker}",
|
"shop_py_list_append" => $"queue: deal {UpgradeMath.ScaleAmount(4 + UnityEngine.Mathf.Max(0, card.QueuePlayCount - 1), card)}; +1 each time re-queued.{marker}",
|
||||||
"shop_py_async_def" => $"queue: draw {UpgradeMath.ScaleAmount(2, card)}. gain {UpgradeMath.ScaleAmount(1, card)} cycle next turn.{marker}",
|
"shop_py_async_def" => $"queue: draw {UpgradeMath.ScaleAmount(2, card)}. gain {UpgradeMath.ScaleAmount(1, card)} cycle next turn.{marker}",
|
||||||
"shop_py_zip" => $"next {UpgradeMath.ScaleAmount(2, card)} queued cards resolve twice.{marker}",
|
"shop_py_zip" => $"next {UpgradeMath.ScaleAmount(2, card)} queued cards resolve twice.{marker}",
|
||||||
@@ -1077,17 +1141,17 @@ namespace KernelPanic.Combat
|
|||||||
"mint_timeshift" => $"queue: record uptime now. at end of your next turn, restore to it if lower.{marker}",
|
"mint_timeshift" => $"queue: record uptime now. at end of your next turn, restore to it if lower.{marker}",
|
||||||
"fedora_dnf_autoremove" => $"deal {UpgradeMath.ScaleAmount(7, card)}. exhaust a junk/NOP/broken card from hand; if you do, gain {UpgradeMath.ScaleAmount(1, card)} cycle. if not, do nothing.{marker}",
|
"fedora_dnf_autoremove" => $"deal {UpgradeMath.ScaleAmount(7, card)}. exhaust a junk/NOP/broken card from hand; if you do, gain {UpgradeMath.ScaleAmount(1, card)} cycle. if not, do nothing.{marker}",
|
||||||
"fedora_first_to_package" => $"deal {UpgradeMath.ScaleAmount(7, card)}. Java cards cost 1 less this turn.{marker}",
|
"fedora_first_to_package" => $"deal {UpgradeMath.ScaleAmount(7, card)}. Java cards cost 1 less this turn.{marker}",
|
||||||
"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)}. overkill spills. 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)}. 20%: segfault, uptime -3. TODO: 20% break a random hand card.{marker}",
|
"arch_pacman_syu" => $"deal {UpgradeMath.ScaleAmount(14, card)}. overkill spills. 20%: segfault, uptime -3 and corrupt a 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+. 20%: segfault, uptime -3.{marker}",
|
"arch_makepkg" => $"deal {UpgradeMath.ScaleAmount(7, card)} + btw x3; x4 at Arch v3+. overkill spills. 20%: segfault, uptime -3 and corrupt a hand card.{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)}. 20%: segfault, uptime -3 and draw 2.{marker}",
|
"shop_c_free" => $"deal {UpgradeMath.ScaleAmount(18, card)}. overkill spills. 20%: segfault, uptime -3, corrupt a hand card, and draw 2.{marker}",
|
||||||
"shop_c_sizeof" => $"deal 3 x C cards in hand. 20%: segfault, uptime -3.{marker}",
|
"shop_c_sizeof" => $"deal 5 x C cards in hand. overkill spills. 20%: segfault, uptime -3 and corrupt a hand card.{marker}",
|
||||||
"shop_c_kernel_exploit" => $"deal {UpgradeMath.ScaleAmount(25, card)} ignoring Shield. 50%: segfault, uptime -8.{marker}",
|
"shop_c_kernel_exploit" => $"deal {UpgradeMath.ScaleAmount(36, card)} ignoring Shield. overkill spills. 50%: segfault, uptime -8 and corrupt a hand card.{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}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ namespace KernelPanic.Combat
|
|||||||
private int _rawhideBonusCharges;
|
private int _rawhideBonusCharges;
|
||||||
private int _queuedRepeatCharges;
|
private int _queuedRepeatCharges;
|
||||||
private int _nextTurnCycleBonus;
|
private int _nextTurnCycleBonus;
|
||||||
|
private int _nextRacePairId = 1;
|
||||||
private Coroutine _phaseCoroutine;
|
private Coroutine _phaseCoroutine;
|
||||||
|
|
||||||
public TurnPhase CurrentPhase => currentPhase;
|
public TurnPhase CurrentPhase => currentPhase;
|
||||||
@@ -77,6 +78,7 @@ namespace KernelPanic.Combat
|
|||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
_runManager = GetComponent<RunManager>();
|
_runManager = GetComponent<RunManager>();
|
||||||
|
_damagePipeline.ResistanceResolver = ResolveDamageResistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
@@ -184,6 +186,18 @@ namespace KernelPanic.Combat
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (card.IsBroken)
|
||||||
|
{
|
||||||
|
Log($"{GetCardName(card)} is corrupted");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card.IsLocked)
|
||||||
|
{
|
||||||
|
Log($"{GetCardName(card)} is locked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool fedoraBonus = CanApplyFedoraBonus();
|
bool fedoraBonus = CanApplyFedoraBonus();
|
||||||
int cost = GetEffectiveCardCost(card);
|
int cost = GetEffectiveCardCost(card);
|
||||||
if (fedoraBonus)
|
if (fedoraBonus)
|
||||||
@@ -343,6 +357,21 @@ namespace KernelPanic.Combat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryCorruptRandomHandCard(string sourceLabel)
|
||||||
|
{
|
||||||
|
CardInstance card = RandomHandCard(cardInstance => cardInstance != null && !cardInstance.IsBroken);
|
||||||
|
if (card == null)
|
||||||
|
{
|
||||||
|
Log($"{sourceLabel}: no card available to corrupt");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
card.IsBroken = true;
|
||||||
|
Log($"{sourceLabel}: corrupted {GetCardName(card)}");
|
||||||
|
StateChanged?.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void ReportEffectResult(string message)
|
public void ReportEffectResult(string message)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(message))
|
if (!string.IsNullOrWhiteSpace(message))
|
||||||
@@ -651,6 +680,7 @@ namespace KernelPanic.Combat
|
|||||||
_pendingTargetCard = null;
|
_pendingTargetCard = null;
|
||||||
_cardsPlayedThisWave = 0;
|
_cardsPlayedThisWave = 0;
|
||||||
_turnNumberThisWave = 0;
|
_turnNumberThisWave = 0;
|
||||||
|
_nextRacePairId = 1;
|
||||||
_packageShieldBonusTriggeredThisTurn = false;
|
_packageShieldBonusTriggeredThisTurn = false;
|
||||||
_packageTimeshiftTriggeredThisWave = false;
|
_packageTimeshiftTriggeredThisWave = false;
|
||||||
ResetArchWaveState();
|
ResetArchWaveState();
|
||||||
@@ -753,10 +783,10 @@ namespace KernelPanic.Combat
|
|||||||
|
|
||||||
private IEnumerator ProcessEnemiesSequenced()
|
private IEnumerator ProcessEnemiesSequenced()
|
||||||
{
|
{
|
||||||
int enemyCountAtPhaseStart = _enemies.Count;
|
List<EnemyInstance> actors = BuildEnemyActionOrder();
|
||||||
for (int i = 0; i < enemyCountAtPhaseStart && i < _enemies.Count; i++)
|
for (int i = 0; i < actors.Count; i++)
|
||||||
{
|
{
|
||||||
EnemyInstance enemy = _enemies[i];
|
EnemyInstance enemy = actors[i];
|
||||||
if (enemy.State.IsDefeated)
|
if (enemy.State.IsDefeated)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -779,11 +809,17 @@ namespace KernelPanic.Combat
|
|||||||
StateChanged?.Invoke();
|
StateChanged?.Invoke();
|
||||||
yield return Wait(CombatTuning.EnemyTelegraphDelaySeconds);
|
yield return Wait(CombatTuning.EnemyTelegraphDelaySeconds);
|
||||||
|
|
||||||
ExecuteEnemyIntent(enemy, i);
|
ExecuteEnemyIntent(enemy, _enemies.IndexOf(enemy));
|
||||||
|
ResolvePassiveEnemyAfterAction(enemy);
|
||||||
|
if (!enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
enemy.MarkTurnSurvived();
|
enemy.MarkTurnSurvived();
|
||||||
|
}
|
||||||
|
|
||||||
GameEvents.RaiseEnemyActed(new EnemyActedEvent(enemy, enemy.CurrentIntent));
|
GameEvents.RaiseEnemyActed(new EnemyActedEvent(enemy, enemy.CurrentIntent));
|
||||||
|
RemoveDefeatedEnemies();
|
||||||
StateChanged?.Invoke();
|
StateChanged?.Invoke();
|
||||||
if (CheckLoss())
|
if (CheckWinOrLoss())
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
@@ -1519,7 +1555,7 @@ namespace KernelPanic.Combat
|
|||||||
state.DamageMultiplierPercent = 100;
|
state.DamageMultiplierPercent = 100;
|
||||||
state.CurrentCardDamageMultiplierPercent = 100;
|
state.CurrentCardDamageMultiplierPercent = 100;
|
||||||
state.ArchBtwDamagePerStack = IsDistro("arch") && _runConfig.DistroVersion >= 2 ? 2 : 1;
|
state.ArchBtwDamagePerStack = IsDistro("arch") && _runConfig.DistroVersion >= 2 ? 2 : 1;
|
||||||
state.ArchMakepkgBtwMultiplier = IsDistro("arch") && _runConfig.DistroVersion >= 3 ? 3 : 2;
|
state.ArchMakepkgBtwMultiplier = IsDistro("arch") && _runConfig.DistroVersion >= 3 ? 4 : 3;
|
||||||
state.ArchRollingReleaseShieldOnSave = IsDistro("arch") && _runConfig.DistroVersion >= 4 ? 15 : 0;
|
state.ArchRollingReleaseShieldOnSave = IsDistro("arch") && _runConfig.DistroVersion >= 4 ? 15 : 0;
|
||||||
state.ArchRollingReleaseCyclesOnSave = IsDistro("arch") && _runConfig.DistroVersion >= 4 ? 2 : 0;
|
state.ArchRollingReleaseCyclesOnSave = IsDistro("arch") && _runConfig.DistroVersion >= 4 ? 2 : 0;
|
||||||
}
|
}
|
||||||
@@ -1693,13 +1729,15 @@ namespace KernelPanic.Combat
|
|||||||
{
|
{
|
||||||
if (_enemies[i].State.IsDefeated)
|
if (_enemies[i].State.IsDefeated)
|
||||||
{
|
{
|
||||||
if (_enemies[i].PendingRevive)
|
EnemyInstance enemy = _enemies[i];
|
||||||
|
if (enemy.PendingRevive)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log($"{_enemies[i].Name} exited");
|
Log($"{enemy.Name} exited");
|
||||||
_runManager?.AddBits(CombatTuning.BitsPerKill);
|
_runManager?.AddBits(CombatTuning.BitsPerKill);
|
||||||
|
HandleEnemyDeath(enemy);
|
||||||
_enemies.RemoveAt(i);
|
_enemies.RemoveAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1710,23 +1748,135 @@ namespace KernelPanic.Combat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleEnemyDeath(EnemyInstance enemy)
|
||||||
|
{
|
||||||
|
if (enemy == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath))
|
||||||
|
{
|
||||||
|
ApplySegfaultDeathPayload(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasBehavior(EnemyBehaviorFlags.RacePair))
|
||||||
|
{
|
||||||
|
BreakRacePair(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasBehavior(EnemyBehaviorFlags.LeavesOrphan))
|
||||||
|
{
|
||||||
|
SpawnOrphanFromDeath(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySegfaultDeathPayload(EnemyInstance enemy)
|
||||||
|
{
|
||||||
|
_statusEffects.Apply(_playerState, StatusType.Segfault, 1, -1, enemy.State, skipNextTick: true);
|
||||||
|
TryCorruptRandomHandCard("segfault");
|
||||||
|
}
|
||||||
|
|
||||||
|
private CardInstance RandomHandCard(Predicate<CardInstance> predicate)
|
||||||
|
{
|
||||||
|
if (_handController == null || _handController.Cards.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CardInstance> candidates = new();
|
||||||
|
for (int i = 0; i < _handController.Cards.Count; i++)
|
||||||
|
{
|
||||||
|
CardInstance candidate = _handController.Cards[i];
|
||||||
|
if (predicate == null || predicate(candidate))
|
||||||
|
{
|
||||||
|
candidates.Add(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidates.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = RandomRoll.RollRange(0, candidates.Count - 1, new RollContext(_playerState));
|
||||||
|
return candidates[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BreakRacePair(EnemyInstance defeated)
|
||||||
|
{
|
||||||
|
EnemyInstance survivor = RacePartner(defeated);
|
||||||
|
if (survivor == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
survivor.EnrageRaceSurvivor();
|
||||||
|
Log($"{survivor.Name} race link broke; survivor enraged");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnOrphanFromDeath(EnemyInstance source)
|
||||||
|
{
|
||||||
|
EnemyInstance orphan = SpawnEnemy("orphan_process", 0);
|
||||||
|
orphan.MarkSpawnedFromDeath();
|
||||||
|
Log($"{source.Name} left an orphan process");
|
||||||
|
}
|
||||||
|
|
||||||
private void SpawnStructuralEnemies()
|
private void SpawnStructuralEnemies()
|
||||||
{
|
{
|
||||||
int wave = CurrentWaveNumber;
|
int wave = CurrentWaveNumber;
|
||||||
int countGrowth = ((wave - 1) / 2) * CombatTuning.AdditionalEnemiesPerWave;
|
int countGrowth = ((wave - 1) / 2) * CombatTuning.AdditionalEnemiesPerWave;
|
||||||
int count = Mathf.Clamp(CombatTuning.BaseEnemiesPerWave + countGrowth, CombatTuning.BaseEnemiesPerWave, CombatTuning.MaxEnemiesPerWave);
|
int count = Mathf.Clamp(CombatTuning.BaseEnemiesPerWave + countGrowth, CombatTuning.BaseEnemiesPerWave, CombatTuning.MaxEnemiesPerWave);
|
||||||
int waveUptimeBonus = Mathf.Max(0, wave - 1) * CombatTuning.EnemyUptimeGrowthPerWave;
|
int waveUptimeBonus = Mathf.Max(0, wave - 1) * CombatTuning.EnemyUptimeGrowthPerWave;
|
||||||
|
bool rootkitSpawned = false;
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
SpawnEnemy(CreatePlaceholderArchetypeId(wave, i), waveUptimeBonus);
|
string archetypeId = CreatePlaceholderArchetypeId(wave, i);
|
||||||
|
if (archetypeId == "rootkit")
|
||||||
|
{
|
||||||
|
if (rootkitSpawned)
|
||||||
|
{
|
||||||
|
archetypeId = CreateRootkitFallbackArchetypeId(wave, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rootkitSpawned = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SpawnEnemy(string archetypeId, int uptimeBonus)
|
if (archetypeId == "race_condition" && i + 1 < count)
|
||||||
|
{
|
||||||
|
SpawnRacePair(waveUptimeBonus);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (archetypeId == "race_condition")
|
||||||
|
{
|
||||||
|
archetypeId = "segfault";
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnEnemy(archetypeId, waveUptimeBonus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnRacePair(int uptimeBonus)
|
||||||
|
{
|
||||||
|
int pairId = _nextRacePairId++;
|
||||||
|
EnemyInstance first = SpawnEnemy("race_condition", uptimeBonus);
|
||||||
|
EnemyInstance second = SpawnEnemy("race_condition", uptimeBonus);
|
||||||
|
first.SetPairId(pairId);
|
||||||
|
second.SetPairId(pairId);
|
||||||
|
Log("race condition pair spawned");
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnemyInstance SpawnEnemy(string archetypeId, int uptimeBonus)
|
||||||
{
|
{
|
||||||
EnemyArchetypeDescriptor archetype = EnemyArchetypeCatalog.Get(archetypeId);
|
EnemyArchetypeDescriptor archetype = EnemyArchetypeCatalog.Get(archetypeId);
|
||||||
int baseUptime = RandomRoll.RollRange(archetype.BaseUptimeMin, archetype.BaseUptimeMax, RollContext.None);
|
int baseUptime = RandomRoll.RollRange(archetype.BaseUptimeMin, archetype.BaseUptimeMax, RollContext.None);
|
||||||
_enemies.Add(new EnemyInstance(archetype, baseUptime + Mathf.Max(0, uptimeBonus)));
|
EnemyInstance enemy = new(archetype, baseUptime + Mathf.Max(0, uptimeBonus));
|
||||||
|
_enemies.Add(enemy);
|
||||||
|
return enemy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CreatePlaceholderArchetypeId(int wave, int slotIndex)
|
private static string CreatePlaceholderArchetypeId(int wave, int slotIndex)
|
||||||
@@ -1736,17 +1886,28 @@ namespace KernelPanic.Combat
|
|||||||
{
|
{
|
||||||
<= 1 => new[] { "zombie_process", "memory_leak" },
|
<= 1 => new[] { "zombie_process", "memory_leak" },
|
||||||
2 => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld" },
|
2 => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld" },
|
||||||
3 => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld", "daemon" },
|
3 => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld", "segfault" },
|
||||||
_ => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld", "daemon", "cron_job" }
|
4 => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld", "cron_job", "segfault", "race_condition" },
|
||||||
|
_ => new[] { "zombie_process", "memory_leak", "fork_bomb", "firewalld", "daemon", "cron_job", "segfault", "race_condition", "rootkit" }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (slotIndex == 0)
|
if (slotIndex == 0)
|
||||||
{
|
{
|
||||||
|
if (wave >= 5 && wave % 2 == 1)
|
||||||
|
{
|
||||||
|
return "rootkit";
|
||||||
|
}
|
||||||
|
|
||||||
return wave % 2 == 0 ? "firewalld" : "zombie_process";
|
return wave % 2 == 0 ? "firewalld" : "zombie_process";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slotIndex == 1 && wave >= 2)
|
if (slotIndex == 1 && wave >= 2)
|
||||||
{
|
{
|
||||||
|
if (wave >= 4 && wave % 4 == 0)
|
||||||
|
{
|
||||||
|
return "race_condition";
|
||||||
|
}
|
||||||
|
|
||||||
return wave % 3 == 0 ? "fork_bomb" : "memory_leak";
|
return wave % 3 == 0 ? "fork_bomb" : "memory_leak";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1754,6 +1915,13 @@ namespace KernelPanic.Combat
|
|||||||
return pool[index];
|
return pool[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string CreateRootkitFallbackArchetypeId(int wave, int slotIndex)
|
||||||
|
{
|
||||||
|
return slotIndex % 2 == 0
|
||||||
|
? "firewalld"
|
||||||
|
: wave % 3 == 0 ? "fork_bomb" : "memory_leak";
|
||||||
|
}
|
||||||
|
|
||||||
private void PickEnemyIntents()
|
private void PickEnemyIntents()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _enemies.Count; i++)
|
for (int i = 0; i < _enemies.Count; i++)
|
||||||
@@ -1765,6 +1933,37 @@ namespace KernelPanic.Combat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<EnemyInstance> BuildEnemyActionOrder()
|
||||||
|
{
|
||||||
|
List<EnemyInstance> actors = _enemies
|
||||||
|
.Where(enemy => enemy.State != null && !enemy.State.IsDefeated)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
for (int i = 0; i < actors.Count - 1; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance enemy = actors[i];
|
||||||
|
if (!IsRacePairLinked(enemy))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnemyInstance partner = RacePartner(enemy);
|
||||||
|
int partnerIndex = partner == null ? -1 : actors.IndexOf(partner);
|
||||||
|
if (partnerIndex <= i)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RandomRoll.RollRange(0, 1, new RollContext(enemy.State)) == 1)
|
||||||
|
{
|
||||||
|
actors[i] = partner;
|
||||||
|
actors[partnerIndex] = enemy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actors;
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteEnemyIntent(EnemyInstance enemy, int enemyIndex)
|
private void ExecuteEnemyIntent(EnemyInstance enemy, int enemyIndex)
|
||||||
{
|
{
|
||||||
EnemyIntent intent = enemy.CurrentIntent;
|
EnemyIntent intent = enemy.CurrentIntent;
|
||||||
@@ -1775,6 +1974,7 @@ namespace KernelPanic.Combat
|
|||||||
switch (intent.Kind)
|
switch (intent.Kind)
|
||||||
{
|
{
|
||||||
case EnemyIntentKind.Attack:
|
case EnemyIntentKind.Attack:
|
||||||
|
value = ApplyEnemyAttackBonuses(enemy, value);
|
||||||
value = ApplyIncomingAttackMitigation(value);
|
value = ApplyIncomingAttackMitigation(value);
|
||||||
DamageResult attackResult = _damagePipeline.DealDamage(new DamageRequest(enemy.State, _playerState, value, intent.DamageType, intent.TrueDamage, false));
|
DamageResult attackResult = _damagePipeline.DealDamage(new DamageRequest(enemy.State, _playerState, value, intent.DamageType, intent.TrueDamage, false));
|
||||||
GameEvents.RaisePlayerDamaged(new PlayerDamagedEvent(enemy, attackResult.FinalAmount));
|
GameEvents.RaisePlayerDamaged(new PlayerDamagedEvent(enemy, attackResult.FinalAmount));
|
||||||
@@ -1790,6 +1990,7 @@ namespace KernelPanic.Combat
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EnemyIntentKind.StatusAttack:
|
case EnemyIntentKind.StatusAttack:
|
||||||
|
value = ApplyEnemyAttackBonuses(enemy, value);
|
||||||
DamageResult statusResult = _damagePipeline.DealDamage(new DamageRequest(enemy.State, _playerState, value, intent.DamageType, intent.TrueDamage, false));
|
DamageResult statusResult = _damagePipeline.DealDamage(new DamageRequest(enemy.State, _playerState, value, intent.DamageType, intent.TrueDamage, false));
|
||||||
GameEvents.RaisePlayerDamaged(new PlayerDamagedEvent(enemy, statusResult.FinalAmount));
|
GameEvents.RaisePlayerDamaged(new PlayerDamagedEvent(enemy, statusResult.FinalAmount));
|
||||||
if (intent.StatusStacks > 0)
|
if (intent.StatusStacks > 0)
|
||||||
@@ -1810,15 +2011,50 @@ namespace KernelPanic.Combat
|
|||||||
|
|
||||||
private void ExecuteSpecialEnemyIntent(EnemyInstance enemy)
|
private void ExecuteSpecialEnemyIntent(EnemyInstance enemy)
|
||||||
{
|
{
|
||||||
if (enemy.HasBehavior(EnemyBehaviorFlags.Split))
|
if (enemy.HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath))
|
||||||
{
|
{
|
||||||
TrySplitForkBomb(enemy);
|
enemy.AdvanceSegfaultCountdown();
|
||||||
|
if (enemy.CountdownRemaining <= 0)
|
||||||
|
{
|
||||||
|
_damagePipeline.DealDamage(new DamageRequest(enemy.State, enemy.State, enemy.CurrentUptime, Language.C, true, false));
|
||||||
|
Log($"{enemy.Name} dereferenced null");
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log("TODO: special intent needs enemy-specific behavior hooks.");
|
Log("TODO: special intent needs enemy-specific behavior hooks.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResolvePassiveEnemyAfterAction(EnemyInstance enemy)
|
||||||
|
{
|
||||||
|
if (enemy == null || enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasBehavior(EnemyBehaviorFlags.Split))
|
||||||
|
{
|
||||||
|
TrySplitForkBomb(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ApplyEnemyAttackBonuses(EnemyInstance enemy, int value)
|
||||||
|
{
|
||||||
|
int modified = value;
|
||||||
|
if (IsRacePairLinked(enemy))
|
||||||
|
{
|
||||||
|
modified += EnemyArchetypeCatalog.RacePairDamageBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy != null && enemy.RaceEnrageStacks > 0)
|
||||||
|
{
|
||||||
|
modified += enemy.RaceEnrageStacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
private void TrySplitForkBomb(EnemyInstance source)
|
private void TrySplitForkBomb(EnemyInstance source)
|
||||||
{
|
{
|
||||||
int totalForkBombs = _enemies.Count(enemy => enemy.ArchetypeId == source.ArchetypeId && !enemy.State.IsDefeated);
|
int totalForkBombs = _enemies.Count(enemy => enemy.ArchetypeId == source.ArchetypeId && !enemy.State.IsDefeated);
|
||||||
@@ -1836,6 +2072,34 @@ namespace KernelPanic.Combat
|
|||||||
Log("fork bomb split");
|
Log("fork bomb split");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsRacePairLinked(EnemyInstance enemy)
|
||||||
|
{
|
||||||
|
return enemy != null
|
||||||
|
&& enemy.HasBehavior(EnemyBehaviorFlags.RacePair)
|
||||||
|
&& RacePartner(enemy) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnemyInstance RacePartner(EnemyInstance enemy)
|
||||||
|
{
|
||||||
|
if (enemy == null || enemy.PairId < 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _enemies.Count; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance candidate = _enemies[i];
|
||||||
|
if (candidate != enemy
|
||||||
|
&& candidate.PairId == enemy.PairId
|
||||||
|
&& !candidate.State.IsDefeated)
|
||||||
|
{
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void DefendSelfAndAdjacent(int enemyIndex, int amount)
|
private void DefendSelfAndAdjacent(int enemyIndex, int amount)
|
||||||
{
|
{
|
||||||
int applied = 0;
|
int applied = 0;
|
||||||
@@ -1866,6 +2130,38 @@ namespace KernelPanic.Combat
|
|||||||
return mitigated;
|
return mitigated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int ResolveDamageResistance(DamageRequest request, int amount)
|
||||||
|
{
|
||||||
|
EnemyInstance target = FindEnemy(request.Target);
|
||||||
|
if (target == null
|
||||||
|
|| !target.HasBehavior(EnemyBehaviorFlags.RootkitMasked)
|
||||||
|
|| !HasOtherLivingEnemy(target))
|
||||||
|
{
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mathf.Max(1, Mathf.CeilToInt(amount * (EnemyArchetypeCatalog.RootkitMaskedDamagePercent / 100f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasOtherLivingEnemy(EnemyInstance target)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _enemies.Count; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance enemy = _enemies[i];
|
||||||
|
if (enemy != target && enemy.State != null && !enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void ResolveDelayedEndOfTurnEffects()
|
private void ResolveDelayedEndOfTurnEffects()
|
||||||
{
|
{
|
||||||
for (int i = _delayedEffects.Count - 1; i >= 0; i--)
|
for (int i = _delayedEffects.Count - 1; i >= 0; i--)
|
||||||
|
|||||||
@@ -37,11 +37,21 @@ namespace KernelPanic.Combat
|
|||||||
public const int EntropyStartWave = 5;
|
public const int EntropyStartWave = 5;
|
||||||
public const int EntropyPerWave = 3;
|
public const int EntropyPerWave = 3;
|
||||||
public const int StatUpgradeMaxCycles = 1;
|
public const int StatUpgradeMaxCycles = 1;
|
||||||
public const int StatUpgradeMaxUptime = 4;
|
public const int StatUpgradeMaxUptimePercent = 20;
|
||||||
public const int StatUpgradeHeal = 5;
|
public const int StatUpgradeHealPercent = 30;
|
||||||
public const int StatUpgradeRam = 1;
|
public const int StatUpgradeRam = 1;
|
||||||
public const int UpgradeMagnitudeBonus = 2;
|
public const int UpgradeMagnitudeBonus = 2;
|
||||||
|
|
||||||
|
public static int ScaleStatUpgradeMaxUptime(int maxUptime)
|
||||||
|
{
|
||||||
|
return System.Math.Max(1, ((System.Math.Max(1, maxUptime) * StatUpgradeMaxUptimePercent) + 99) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ScaleStatUpgradeHeal(int maxUptime)
|
||||||
|
{
|
||||||
|
return System.Math.Max(1, ((System.Math.Max(1, maxUptime) * StatUpgradeHealPercent) + 99) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
// Combat pacing: gaps between phase transitions and per-item resolution steps so
|
// Combat pacing: gaps between phase transitions and per-item resolution steps so
|
||||||
// players can follow drawing/queue/enemy resolution instead of seeing it all at once.
|
// players can follow drawing/queue/enemy resolution instead of seeing it all at once.
|
||||||
// Skipped entirely when UIPreferences.ReducedMotion is set.
|
// Skipped entirely when UIPreferences.ReducedMotion is set.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace KernelPanic.Combat
|
|||||||
public int IncomingAttackHalfCharges { get; set; }
|
public int IncomingAttackHalfCharges { get; set; }
|
||||||
public int ArchBtwStacks { get; set; }
|
public int ArchBtwStacks { get; set; }
|
||||||
public int ArchBtwDamagePerStack { get; set; } = 1;
|
public int ArchBtwDamagePerStack { get; set; } = 1;
|
||||||
public int ArchMakepkgBtwMultiplier { get; set; } = 2;
|
public int ArchMakepkgBtwMultiplier { get; set; } = 3;
|
||||||
public int ArchRollingReleaseSavesRemaining { get; set; }
|
public int ArchRollingReleaseSavesRemaining { get; set; }
|
||||||
public int ArchRollingReleaseShieldOnSave { get; set; }
|
public int ArchRollingReleaseShieldOnSave { get; set; }
|
||||||
public int ArchRollingReleaseCyclesOnSave { get; set; }
|
public int ArchRollingReleaseCyclesOnSave { get; set; }
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ namespace KernelPanic.Combat
|
|||||||
int amount,
|
int amount,
|
||||||
Language language,
|
Language language,
|
||||||
bool trueDamage,
|
bool trueDamage,
|
||||||
bool canCrit)
|
bool canCrit,
|
||||||
|
bool applySourceModifiers = true)
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
@@ -19,6 +20,7 @@ namespace KernelPanic.Combat
|
|||||||
Language = language;
|
Language = language;
|
||||||
TrueDamage = trueDamage;
|
TrueDamage = trueDamage;
|
||||||
CanCrit = canCrit;
|
CanCrit = canCrit;
|
||||||
|
ApplySourceModifiers = applySourceModifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CombatantState Source { get; }
|
public CombatantState Source { get; }
|
||||||
@@ -27,6 +29,7 @@ namespace KernelPanic.Combat
|
|||||||
public Language Language { get; }
|
public Language Language { get; }
|
||||||
public bool TrueDamage { get; }
|
public bool TrueDamage { get; }
|
||||||
public bool CanCrit { get; }
|
public bool CanCrit { get; }
|
||||||
|
public bool ApplySourceModifiers { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct DamageResult
|
public readonly struct DamageResult
|
||||||
@@ -56,6 +59,8 @@ namespace KernelPanic.Combat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DamagePipeline
|
public sealed class DamagePipeline
|
||||||
{
|
{
|
||||||
|
public System.Func<DamageRequest, int, int> ResistanceResolver { get; set; }
|
||||||
|
|
||||||
public DamageResult DealDamage(DamageRequest request)
|
public DamageResult DealDamage(DamageRequest request)
|
||||||
{
|
{
|
||||||
if (request.Target == null || request.Target.IsDefeated)
|
if (request.Target == null || request.Target.IsDefeated)
|
||||||
@@ -64,9 +69,14 @@ namespace KernelPanic.Combat
|
|||||||
}
|
}
|
||||||
|
|
||||||
int amount = Mathf.Max(0, request.Amount);
|
int amount = Mathf.Max(0, request.Amount);
|
||||||
|
bool wasCritical = false;
|
||||||
|
if (request.ApplySourceModifiers)
|
||||||
|
{
|
||||||
amount = ApplyFlatAdditions(amount, request);
|
amount = ApplyFlatAdditions(amount, request);
|
||||||
amount = ApplyMultipliers(amount, request);
|
amount = ApplyMultipliers(amount, request);
|
||||||
amount = ApplyCrit(amount, request, out bool wasCritical);
|
amount = ApplyCrit(amount, request, out wasCritical);
|
||||||
|
}
|
||||||
|
|
||||||
amount = ApplyResistancesAndWeaknesses(amount, request);
|
amount = ApplyResistancesAndWeaknesses(amount, request);
|
||||||
|
|
||||||
int finalAmount = ApplyShieldAndUptime(amount, request, out int absorbedAmount, out int shieldDamage, out int uptimeDamage);
|
int finalAmount = ApplyShieldAndUptime(amount, request, out int absorbedAmount, out int shieldDamage, out int uptimeDamage);
|
||||||
@@ -86,6 +96,11 @@ namespace KernelPanic.Combat
|
|||||||
|
|
||||||
private static int ApplyMultipliers(int amount, DamageRequest request)
|
private static int ApplyMultipliers(int amount, DamageRequest request)
|
||||||
{
|
{
|
||||||
|
if (amount == int.MaxValue)
|
||||||
|
{
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.Source != null && request.Source.IgnoreDamageMultipliers)
|
if (request.Source != null && request.Source.IgnoreDamageMultipliers)
|
||||||
{
|
{
|
||||||
// Mint V1+ ignores multiplicative damage modifiers. Mint V4 still allows flat
|
// Mint V1+ ignores multiplicative damage modifiers. Mint V4 still allows flat
|
||||||
@@ -100,6 +115,11 @@ namespace KernelPanic.Combat
|
|||||||
|
|
||||||
private static int ApplyFlatAdditions(int amount, DamageRequest request)
|
private static int ApplyFlatAdditions(int amount, DamageRequest request)
|
||||||
{
|
{
|
||||||
|
if (amount == int.MaxValue)
|
||||||
|
{
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.Source != null && request.Language == Language.JavaScript)
|
if (request.Source != null && request.Language == Language.JavaScript)
|
||||||
{
|
{
|
||||||
amount += Mathf.Max(0, request.Source.JavaScriptFlatDamageBonus);
|
amount += Mathf.Max(0, request.Source.JavaScriptFlatDamageBonus);
|
||||||
@@ -116,7 +136,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 || amount == int.MaxValue || request.Source != null && request.Source.ForceMaxRolls)
|
||||||
{
|
{
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
@@ -144,12 +164,12 @@ namespace KernelPanic.Combat
|
|||||||
target.ArchRollingReleaseRecoveredThisHit = true;
|
target.ArchRollingReleaseRecoveredThisHit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ApplyResistancesAndWeaknesses(int amount, DamageRequest request)
|
private int ApplyResistancesAndWeaknesses(int amount, DamageRequest request)
|
||||||
{
|
{
|
||||||
// TODO: Enemy resistances/reductions are not authored yet. Mint V5 should re-resolve
|
// TODO: Enemy resistances/reductions are not authored yet. Mint V5 should re-resolve
|
||||||
// a once-per-combat reduced effect here once those reduction sources exist.
|
// a once-per-combat reduced effect here once those reduction sources exist.
|
||||||
// TODO: Apply enemy language resistances and weaknesses here.
|
// TODO: Apply enemy language resistances and weaknesses here.
|
||||||
return amount;
|
return ResistanceResolver == null ? amount : ResistanceResolver(request, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ApplyShieldAndUptime(int amount, DamageRequest request, out int absorbedAmount, out int shieldDamage, out int uptimeDamage)
|
private static int ApplyShieldAndUptime(int amount, DamageRequest request, out int absorbedAmount, out int shieldDamage, out int uptimeDamage)
|
||||||
|
|||||||
@@ -14,7 +14,12 @@ namespace KernelPanic.Combat
|
|||||||
Grow = 1 << 2,
|
Grow = 1 << 2,
|
||||||
ObfuscateIntent = 1 << 3,
|
ObfuscateIntent = 1 << 3,
|
||||||
DefendAllies = 1 << 4,
|
DefendAllies = 1 << 4,
|
||||||
Countdown = 1 << 5
|
Countdown = 1 << 5,
|
||||||
|
LeavesOrphan = 1 << 6,
|
||||||
|
SegfaultOnDeath = 1 << 7,
|
||||||
|
RacePair = 1 << 8,
|
||||||
|
RootkitMasked = 1 << 9,
|
||||||
|
Elite = 1 << 10
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class EnemyArchetypeDescriptor
|
public sealed class EnemyArchetypeDescriptor
|
||||||
@@ -51,18 +56,23 @@ namespace KernelPanic.Combat
|
|||||||
{
|
{
|
||||||
public const int ZombieReapThresholdPercent = 30;
|
public const int ZombieReapThresholdPercent = 30;
|
||||||
public const int MemoryLeakAttackGrowthPerTurn = 1;
|
public const int MemoryLeakAttackGrowthPerTurn = 1;
|
||||||
|
public const int MemoryLeakAttackCapMin = 4;
|
||||||
|
public const int MemoryLeakAttackCapMax = 5;
|
||||||
public const int ForkBombTotalCap = 5;
|
public const int ForkBombTotalCap = 5;
|
||||||
|
public const int RootkitMaskedDamagePercent = 10;
|
||||||
|
public const int RacePairDamageBonus = 2;
|
||||||
public const int CronInitialCountdown = 2;
|
public const int CronInitialCountdown = 2;
|
||||||
|
public const int SegfaultInitialCountdown = 2;
|
||||||
|
|
||||||
private static readonly EnemyArchetypeDescriptor ZombieProcess = new(
|
private static readonly EnemyArchetypeDescriptor ZombieProcess = new(
|
||||||
"zombie_process",
|
"zombie_process",
|
||||||
"Zombie Process",
|
"Zombie Process",
|
||||||
6,
|
6,
|
||||||
10,
|
10,
|
||||||
EnemyBehaviorFlags.Revive,
|
EnemyBehaviorFlags.Revive | EnemyBehaviorFlags.LeavesOrphan,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new EnemyIntent(EnemyIntentKind.Attack, 3, 4, Language.C, "attack", "!")
|
new EnemyIntent(EnemyIntentKind.Attack, 2, 3, Language.C, "attack", "!")
|
||||||
});
|
});
|
||||||
|
|
||||||
private static readonly EnemyArchetypeDescriptor MemoryLeak = new(
|
private static readonly EnemyArchetypeDescriptor MemoryLeak = new(
|
||||||
@@ -73,7 +83,7 @@ namespace KernelPanic.Combat
|
|||||||
EnemyBehaviorFlags.Grow,
|
EnemyBehaviorFlags.Grow,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new EnemyIntent(EnemyIntentKind.StatusAttack, 1, 1, Language.C, "leak", "!", false, StatusType.MemoryLeak, 1, CombatTuning.EnemyStatusDuration)
|
new EnemyIntent(EnemyIntentKind.StatusAttack, 1, 2, Language.C, "leak", "!", false, StatusType.MemoryLeak, 1, CombatTuning.EnemyStatusDuration)
|
||||||
});
|
});
|
||||||
|
|
||||||
private static readonly EnemyArchetypeDescriptor ForkBomb = new(
|
private static readonly EnemyArchetypeDescriptor ForkBomb = new(
|
||||||
@@ -81,10 +91,10 @@ namespace KernelPanic.Combat
|
|||||||
"Fork Bomb",
|
"Fork Bomb",
|
||||||
3,
|
3,
|
||||||
5,
|
5,
|
||||||
EnemyBehaviorFlags.Split,
|
EnemyBehaviorFlags.Split | EnemyBehaviorFlags.LeavesOrphan,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new EnemyIntent(EnemyIntentKind.Special, 0, 0, Language.C, "fork", ":", false, StatusType.MemoryLeak, 0, -1, "split")
|
new EnemyIntent(EnemyIntentKind.Attack, 1, 2, Language.C, "fork hit", "!")
|
||||||
});
|
});
|
||||||
|
|
||||||
private static readonly EnemyArchetypeDescriptor Daemon = new(
|
private static readonly EnemyArchetypeDescriptor Daemon = new(
|
||||||
@@ -92,7 +102,7 @@ namespace KernelPanic.Combat
|
|||||||
"Daemon",
|
"Daemon",
|
||||||
10,
|
10,
|
||||||
14,
|
14,
|
||||||
EnemyBehaviorFlags.ObfuscateIntent,
|
EnemyBehaviorFlags.ObfuscateIntent | EnemyBehaviorFlags.Elite,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new EnemyIntent(EnemyIntentKind.Attack, 6, 8, Language.C, "daemon hit", "!")
|
new EnemyIntent(EnemyIntentKind.Attack, 6, 8, Language.C, "daemon hit", "!")
|
||||||
@@ -108,7 +118,7 @@ namespace KernelPanic.Combat
|
|||||||
{
|
{
|
||||||
new EnemyIntent(EnemyIntentKind.Defend, 3, 5, Language.C, "shield adjacent", "#"),
|
new EnemyIntent(EnemyIntentKind.Defend, 3, 5, Language.C, "shield adjacent", "#"),
|
||||||
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", "!")
|
new EnemyIntent(EnemyIntentKind.Attack, 0, 1, Language.C, "poke", "!")
|
||||||
});
|
});
|
||||||
|
|
||||||
private static readonly EnemyArchetypeDescriptor CronJob = new(
|
private static readonly EnemyArchetypeDescriptor CronJob = new(
|
||||||
@@ -122,6 +132,50 @@ namespace KernelPanic.Combat
|
|||||||
new EnemyIntent(EnemyIntentKind.Attack, 10, 12, Language.C, "cron fire", "@")
|
new EnemyIntent(EnemyIntentKind.Attack, 10, 12, Language.C, "cron fire", "@")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private static readonly EnemyArchetypeDescriptor OrphanProcess = new(
|
||||||
|
"orphan_process",
|
||||||
|
"Orphan Process",
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
EnemyBehaviorFlags.None,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new EnemyIntent(EnemyIntentKind.Attack, 1, 2, Language.C, "orphan chip", ".")
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly EnemyArchetypeDescriptor Segfault = new(
|
||||||
|
"segfault",
|
||||||
|
"Segfault",
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
EnemyBehaviorFlags.SegfaultOnDeath,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new EnemyIntent(EnemyIntentKind.Attack, 2, 3, Language.C, "unstable hit", "!")
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly EnemyArchetypeDescriptor RaceCondition = new(
|
||||||
|
"race_condition",
|
||||||
|
"Race Condition",
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
EnemyBehaviorFlags.RacePair,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new EnemyIntent(EnemyIntentKind.Attack, 2, 3, Language.C, "racy strike", "~")
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly EnemyArchetypeDescriptor Rootkit = new(
|
||||||
|
"rootkit",
|
||||||
|
"Rootkit",
|
||||||
|
14,
|
||||||
|
18,
|
||||||
|
EnemyBehaviorFlags.RootkitMasked,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new EnemyIntent(EnemyIntentKind.Attack, 1, 2, Language.C, "masked hit", "?")
|
||||||
|
});
|
||||||
|
|
||||||
public static EnemyArchetypeDescriptor Get(string id)
|
public static EnemyArchetypeDescriptor Get(string id)
|
||||||
{
|
{
|
||||||
return id switch
|
return id switch
|
||||||
@@ -131,6 +185,10 @@ namespace KernelPanic.Combat
|
|||||||
"daemon" => Daemon,
|
"daemon" => Daemon,
|
||||||
"firewalld" => Defender,
|
"firewalld" => Defender,
|
||||||
"cron_job" => CronJob,
|
"cron_job" => CronJob,
|
||||||
|
"orphan_process" => OrphanProcess,
|
||||||
|
"segfault" => Segfault,
|
||||||
|
"race_condition" => RaceCondition,
|
||||||
|
"rootkit" => Rootkit,
|
||||||
_ => ZombieProcess
|
_ => ZombieProcess
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace KernelPanic.Combat
|
|||||||
_intentPool.AddRange(Archetype.IntentPool);
|
_intentPool.AddRange(Archetype.IntentPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
CountdownRemaining = HasBehavior(EnemyBehaviorFlags.Countdown) ? EnemyArchetypeCatalog.CronInitialCountdown : 0;
|
CountdownRemaining = HasBehavior(EnemyBehaviorFlags.Countdown)
|
||||||
|
? EnemyArchetypeCatalog.CronInitialCountdown
|
||||||
|
: HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath) ? EnemyArchetypeCatalog.SegfaultInitialCountdown : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@@ -42,7 +44,16 @@ namespace KernelPanic.Combat
|
|||||||
public bool PendingRevive { get; private set; }
|
public bool PendingRevive { get; private set; }
|
||||||
public bool Reaped { get; private set; }
|
public bool Reaped { get; private set; }
|
||||||
public bool LethalHitThisTurn { get; private set; }
|
public bool LethalHitThisTurn { get; private set; }
|
||||||
|
public int PairId { get; private set; } = -1;
|
||||||
|
public int RaceEnrageStacks { get; private set; }
|
||||||
|
public bool SpawnedFromDeath { get; private set; }
|
||||||
public bool HasPendingMarker => PendingRevive || HasRevived;
|
public bool HasPendingMarker => PendingRevive || HasRevived;
|
||||||
|
public bool HasSpecialSignal => HasSplitSignal || HasSegfaultSignal || HasRaceSignal || HasRootkitSignal || HasEliteSignal || SpawnedFromDeath;
|
||||||
|
public bool HasSplitSignal => HasBehavior(EnemyBehaviorFlags.Split);
|
||||||
|
public bool HasSegfaultSignal => HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath);
|
||||||
|
public bool HasRaceSignal => HasBehavior(EnemyBehaviorFlags.RacePair);
|
||||||
|
public bool HasRootkitSignal => HasBehavior(EnemyBehaviorFlags.RootkitMasked);
|
||||||
|
public bool HasEliteSignal => HasBehavior(EnemyBehaviorFlags.Elite);
|
||||||
public EnemyIntent DisplayIntent => BuildDisplayIntent();
|
public EnemyIntent DisplayIntent => BuildDisplayIntent();
|
||||||
|
|
||||||
public void PickNextIntent()
|
public void PickNextIntent()
|
||||||
@@ -61,6 +72,12 @@ namespace KernelPanic.Combat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath) && CountdownRemaining > 0)
|
||||||
|
{
|
||||||
|
CurrentIntent = new EnemyIntent(EnemyIntentKind.Special, CountdownRemaining, CountdownRemaining, KernelPanic.Core.Language.C, "segfault in", "!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_intentPool.Count == 0)
|
if (_intentPool.Count == 0)
|
||||||
{
|
{
|
||||||
CurrentIntent = default;
|
CurrentIntent = default;
|
||||||
@@ -72,7 +89,9 @@ namespace KernelPanic.Combat
|
|||||||
if (HasBehavior(EnemyBehaviorFlags.Grow))
|
if (HasBehavior(EnemyBehaviorFlags.Grow))
|
||||||
{
|
{
|
||||||
int growth = TurnsAlive * EnemyArchetypeCatalog.MemoryLeakAttackGrowthPerTurn;
|
int growth = TurnsAlive * EnemyArchetypeCatalog.MemoryLeakAttackGrowthPerTurn;
|
||||||
CurrentIntent = CurrentIntent.WithValues(CurrentIntent.MinValue + growth, CurrentIntent.MaxValue + growth, "growing leak");
|
int minValue = UnityEngine.Mathf.Min(CurrentIntent.MinValue + growth, EnemyArchetypeCatalog.MemoryLeakAttackCapMin);
|
||||||
|
int maxValue = UnityEngine.Mathf.Min(CurrentIntent.MaxValue + growth, EnemyArchetypeCatalog.MemoryLeakAttackCapMax);
|
||||||
|
CurrentIntent = CurrentIntent.WithValues(minValue, maxValue, "growing leak");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +113,21 @@ namespace KernelPanic.Combat
|
|||||||
TurnsAlive++;
|
TurnsAlive++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPairId(int pairId)
|
||||||
|
{
|
||||||
|
PairId = pairId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkSpawnedFromDeath()
|
||||||
|
{
|
||||||
|
SpawnedFromDeath = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnrageRaceSurvivor()
|
||||||
|
{
|
||||||
|
RaceEnrageStacks++;
|
||||||
|
}
|
||||||
|
|
||||||
public void ResetTurnLethalMarker()
|
public void ResetTurnLethalMarker()
|
||||||
{
|
{
|
||||||
LethalHitThisTurn = false;
|
LethalHitThisTurn = false;
|
||||||
@@ -142,6 +176,14 @@ namespace KernelPanic.Combat
|
|||||||
: UnityEngine.Mathf.Max(0, CountdownRemaining - 1);
|
: UnityEngine.Mathf.Max(0, CountdownRemaining - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AdvanceSegfaultCountdown()
|
||||||
|
{
|
||||||
|
if (HasBehavior(EnemyBehaviorFlags.SegfaultOnDeath))
|
||||||
|
{
|
||||||
|
CountdownRemaining = UnityEngine.Mathf.Max(0, CountdownRemaining - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private EnemyIntent BuildDisplayIntent()
|
private EnemyIntent BuildDisplayIntent()
|
||||||
{
|
{
|
||||||
if (PendingRevive)
|
if (PendingRevive)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace KernelPanic.Combat
|
|||||||
private static readonly Dictionary<StatusType, StatusDescriptor> Descriptors = new()
|
private static readonly Dictionary<StatusType, StatusDescriptor> Descriptors = new()
|
||||||
{
|
{
|
||||||
[StatusType.MemoryLeak] = new(StatusType.MemoryLeak, "Memory Leak", "leak", false, StatusStackingRule.Intensity, StatusTickTiming.StartOfTurn, "Takes damage equal to stacks at start of turn."),
|
[StatusType.MemoryLeak] = new(StatusType.MemoryLeak, "Memory Leak", "leak", false, StatusStackingRule.Intensity, StatusTickTiming.StartOfTurn, "Takes damage equal to stacks at start of turn."),
|
||||||
[StatusType.Segfault] = new(StatusType.Segfault, "Segfault", "segv", false, StatusStackingRule.Unique, StatusTickTiming.StartOfTurn, "Loses one cycle this turn. TODO: lock a random card slot."),
|
[StatusType.Segfault] = new(StatusType.Segfault, "Segfault", "segv", false, StatusStackingRule.Unique, StatusTickTiming.StartOfTurn, "Loses one cycle this turn. Segfault events corrupt a random hand card until fixed."),
|
||||||
[StatusType.RaceCondition] = new(StatusType.RaceCondition, "Race Condition", "race", false, StatusStackingRule.Refresh, StatusTickTiming.None, "Randomizes multi-target resolution order where supported."),
|
[StatusType.RaceCondition] = new(StatusType.RaceCondition, "Race Condition", "race", false, StatusStackingRule.Refresh, StatusTickTiming.None, "Randomizes multi-target resolution order where supported."),
|
||||||
[StatusType.Deprecated] = new(StatusType.Deprecated, "Deprecated", "dep", false, StatusStackingRule.Duration, StatusTickTiming.StartOfTurn, "A temporary positive value decays. Currently reduces shield by 1."),
|
[StatusType.Deprecated] = new(StatusType.Deprecated, "Deprecated", "dep", false, StatusStackingRule.Duration, StatusTickTiming.StartOfTurn, "A temporary positive value decays. Currently reduces shield by 1."),
|
||||||
[StatusType.DependencyError] = new(StatusType.DependencyError, "Dependency Error", "deps", false, StatusStackingRule.Unique, StatusTickTiming.None, "Registered for off-support card cost rules. TODO: connect draw-time cost path."),
|
[StatusType.DependencyError] = new(StatusType.DependencyError, "Dependency Error", "deps", false, StatusStackingRule.Unique, StatusTickTiming.None, "Registered for off-support card cost rules. TODO: connect draw-time cost path."),
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ namespace KernelPanic.Run
|
|||||||
return upgradeKind switch
|
return upgradeKind switch
|
||||||
{
|
{
|
||||||
RunStatUpgradeKind.MaxCycles => $"+{CombatTuning.StatUpgradeMaxCycles} max cycles this run",
|
RunStatUpgradeKind.MaxCycles => $"+{CombatTuning.StatUpgradeMaxCycles} max cycles this run",
|
||||||
RunStatUpgradeKind.MaxUptime => $"+{CombatTuning.StatUpgradeMaxUptime} max uptime this run",
|
RunStatUpgradeKind.MaxUptime => $"+{CombatTuning.StatUpgradeMaxUptimePercent}% max uptime this run",
|
||||||
RunStatUpgradeKind.Heal => $"heal {CombatTuning.StatUpgradeHeal} uptime now",
|
RunStatUpgradeKind.Heal => $"heal {CombatTuning.StatUpgradeHealPercent}% max uptime now",
|
||||||
RunStatUpgradeKind.Ram => $"+{CombatTuning.StatUpgradeRam} RAM this run",
|
RunStatUpgradeKind.Ram => $"+{CombatTuning.StatUpgradeRam} RAM this run",
|
||||||
_ => "--"
|
_ => "--"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -496,10 +496,11 @@ namespace KernelPanic.Run
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case RunStatUpgradeKind.MaxUptime:
|
case RunStatUpgradeKind.MaxUptime:
|
||||||
_maxUptimeBonus += CombatTuning.StatUpgradeMaxUptime;
|
int uptimeBonus = CombatTuning.ScaleStatUpgradeMaxUptime(playerState == null ? EffectiveMaxUptime() : playerState.MaxUptime);
|
||||||
|
_maxUptimeBonus += uptimeBonus;
|
||||||
if (playerState != null)
|
if (playerState != null)
|
||||||
{
|
{
|
||||||
playerState.MaxUptime += CombatTuning.StatUpgradeMaxUptime;
|
playerState.MaxUptime += uptimeBonus;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case RunStatUpgradeKind.Heal:
|
case RunStatUpgradeKind.Heal:
|
||||||
@@ -508,7 +509,8 @@ namespace KernelPanic.Run
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerState.CurrentUptime = Mathf.Min(playerState.MaxUptime, playerState.CurrentUptime + CombatTuning.StatUpgradeHeal);
|
int healAmount = CombatTuning.ScaleStatUpgradeHeal(playerState.MaxUptime);
|
||||||
|
playerState.CurrentUptime = Mathf.Min(playerState.MaxUptime, playerState.CurrentUptime + healAmount);
|
||||||
return true;
|
return true;
|
||||||
case RunStatUpgradeKind.Ram:
|
case RunStatUpgradeKind.Ram:
|
||||||
_ramBonus += CombatTuning.StatUpgradeRam;
|
_ramBonus += CombatTuning.StatUpgradeRam;
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ namespace KernelPanic.UI
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runtime-built GameScene combat UI. Intent icons use a compact terminal vocabulary:
|
/// Runtime-built GameScene combat UI. Intent icons use a compact terminal vocabulary:
|
||||||
/// ! attack/status attack, # defend, + buff, * special, ? hidden, ~ reviving, : split, @ countdown.
|
/// ! attack/status attack/segfault, # defend, + buff, * special, ? hidden/rootkit,
|
||||||
|
/// ~ reviving/race link, : split, @ countdown, . orphan.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RequireComponent(typeof(UIDocument))]
|
[RequireComponent(typeof(UIDocument))]
|
||||||
[RequireComponent(typeof(RunManager))]
|
[RequireComponent(typeof(RunManager))]
|
||||||
@@ -276,9 +277,12 @@ namespace KernelPanic.UI
|
|||||||
|
|
||||||
VisualElement enemiesPanel = CreatePanel("enemy processes", "intent telemetry", 438);
|
VisualElement enemiesPanel = CreatePanel("enemy processes", "intent telemetry", 438);
|
||||||
main.Add(enemiesPanel);
|
main.Add(enemiesPanel);
|
||||||
|
ScrollView enemyScroll = new(ScrollViewMode.Vertical);
|
||||||
|
enemyScroll.AddToClassList("enemy-scroll");
|
||||||
|
enemiesPanel.Add(enemyScroll);
|
||||||
_enemyRow = new();
|
_enemyRow = new();
|
||||||
_enemyRow.AddToClassList("enemy-row");
|
_enemyRow.AddToClassList("enemy-row");
|
||||||
enemiesPanel.Add(_enemyRow);
|
enemyScroll.Add(_enemyRow);
|
||||||
|
|
||||||
VisualElement bottom = new();
|
VisualElement bottom = new();
|
||||||
bottom.AddToClassList("bottom-layout");
|
bottom.AddToClassList("bottom-layout");
|
||||||
@@ -445,6 +449,9 @@ namespace KernelPanic.UI
|
|||||||
{
|
{
|
||||||
_enemyRow.Clear();
|
_enemyRow.Clear();
|
||||||
_combatantElements.Clear();
|
_combatantElements.Clear();
|
||||||
|
int enemyCount = _combatManager.Enemies.Count;
|
||||||
|
bool compactEnemies = enemyCount >= 5;
|
||||||
|
_enemyRow.EnableInClassList("enemy-row-compact", compactEnemies);
|
||||||
if (_combatManager.PlayerState != null)
|
if (_combatManager.PlayerState != null)
|
||||||
{
|
{
|
||||||
_combatantElements[_combatManager.PlayerState] = _playerPanel;
|
_combatantElements[_combatManager.PlayerState] = _playerPanel;
|
||||||
@@ -457,6 +464,7 @@ namespace KernelPanic.UI
|
|||||||
Button card = new(() => _combatManager.SelectEnemy(index));
|
Button card = new(() => _combatManager.SelectEnemy(index));
|
||||||
card.text = string.Empty;
|
card.text = string.Empty;
|
||||||
card.AddToClassList("enemy-card");
|
card.AddToClassList("enemy-card");
|
||||||
|
card.EnableInClassList("enemy-card-compact", compactEnemies);
|
||||||
bool highlighted = _combatManager.PendingTargetCard != null || _combatManager.SelectedEnemyIndex == index;
|
bool highlighted = _combatManager.PendingTargetCard != null || _combatManager.SelectedEnemyIndex == index;
|
||||||
if (highlighted)
|
if (highlighted)
|
||||||
{
|
{
|
||||||
@@ -473,6 +481,11 @@ namespace KernelPanic.UI
|
|||||||
card.Add(marker);
|
card.Add(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enemy.HasSpecialSignal)
|
||||||
|
{
|
||||||
|
card.Add(EnemySignalPanel(enemy, _combatManager.Enemies));
|
||||||
|
}
|
||||||
|
|
||||||
_combatantElements[enemy.State] = card;
|
_combatantElements[enemy.State] = card;
|
||||||
DetectBeneficialResourceFeedback(enemy.State, card);
|
DetectBeneficialResourceFeedback(enemy.State, card);
|
||||||
ApplyStatusStateClasses(card, enemy.State);
|
ApplyStatusStateClasses(card, enemy.State);
|
||||||
@@ -823,6 +836,12 @@ namespace KernelPanic.UI
|
|||||||
button.AddToClassList("hand-card-unaffordable");
|
button.AddToClassList("hand-card-unaffordable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (card.IsBroken || card.IsLocked)
|
||||||
|
{
|
||||||
|
button.AddToClassList("hand-card-unaffordable");
|
||||||
|
button.SetEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
PopulateCardFace(button, card);
|
PopulateCardFace(button, card);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
@@ -853,6 +872,13 @@ namespace KernelPanic.UI
|
|||||||
top.Add(name);
|
top.Add(name);
|
||||||
target.Add(top);
|
target.Add(top);
|
||||||
|
|
||||||
|
if (card.IsBroken || card.IsLocked)
|
||||||
|
{
|
||||||
|
Label state = new(card.IsBroken ? "segv corrupt" : "locked");
|
||||||
|
state.AddToClassList("status-label");
|
||||||
|
target.Add(state);
|
||||||
|
}
|
||||||
|
|
||||||
VisualElement tags = new();
|
VisualElement tags = new();
|
||||||
tags.AddToClassList("tag-row");
|
tags.AddToClassList("tag-row");
|
||||||
tags.Add(Tag(card.Definition.Language.ToString(), LanguageClass(card.Definition.Language)));
|
tags.Add(Tag(card.Definition.Language.ToString(), LanguageClass(card.Definition.Language)));
|
||||||
@@ -885,6 +911,97 @@ namespace KernelPanic.UI
|
|||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static VisualElement EnemySignalPanel(EnemyInstance enemy, IReadOnlyList<EnemyInstance> enemies)
|
||||||
|
{
|
||||||
|
VisualElement row = new();
|
||||||
|
row.AddToClassList("status-row");
|
||||||
|
|
||||||
|
if (enemy.SpawnedFromDeath)
|
||||||
|
{
|
||||||
|
row.Add(Tag(". orphaned", "track-tag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasEliteSignal)
|
||||||
|
{
|
||||||
|
row.Add(Tag("! elite", "intent-attack"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasSplitSignal)
|
||||||
|
{
|
||||||
|
string text = CountLivingArchetype(enemies, enemy.ArchetypeId) >= EnemyArchetypeCatalog.ForkBombTotalCap
|
||||||
|
? ": split capped"
|
||||||
|
: ": split next";
|
||||||
|
row.Add(Tag(text, "track-tag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasSegfaultSignal)
|
||||||
|
{
|
||||||
|
row.Add(Tag($"! corrupt in {enemy.CountdownRemaining}", "track-tag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasRaceSignal)
|
||||||
|
{
|
||||||
|
string text = HasLivingPair(enemies, enemy) ? "~ linked random" : "~ unlinked";
|
||||||
|
row.Add(Tag(text, "track-tag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.HasRootkitSignal)
|
||||||
|
{
|
||||||
|
string text = HasOtherLivingEnemy(enemies, enemy) ? "? masked reduced" : "? exposed";
|
||||||
|
row.Add(Tag(text, "track-tag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CountLivingArchetype(IReadOnlyList<EnemyInstance> enemies, string archetypeId)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < enemies.Count; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance enemy = enemies[i];
|
||||||
|
if (enemy.ArchetypeId == archetypeId && !enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HasLivingPair(IReadOnlyList<EnemyInstance> enemies, EnemyInstance target)
|
||||||
|
{
|
||||||
|
if (target == null || target.PairId < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < enemies.Count; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance enemy = enemies[i];
|
||||||
|
if (enemy != target && enemy.PairId == target.PairId && !enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HasOtherLivingEnemy(IReadOnlyList<EnemyInstance> enemies, EnemyInstance target)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < enemies.Count; i++)
|
||||||
|
{
|
||||||
|
EnemyInstance enemy = enemies[i];
|
||||||
|
if (enemy != target && !enemy.State.IsDefeated)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static VisualElement MeterBlock(string name, int current, int max, MeterTone tone)
|
private static VisualElement MeterBlock(string name, int current, int max, MeterTone tone)
|
||||||
{
|
{
|
||||||
float ratio = max <= 0 ? 0f : Mathf.Clamp01((float)current / max);
|
float ratio = max <= 0 ? 0f : Mathf.Clamp01((float)current / max);
|
||||||
|
|||||||
Reference in New Issue
Block a user