From 1b9a9ca31cff85f355ab202512ff7b63ef343cf2 Mon Sep 17 00:00:00 2001 From: Matthew Walls Date: Thu, 27 Oct 2022 22:14:53 -0700 Subject: [PATCH] Reorganizing code/Added ability to add chance of genes to PawnKindDefs --- 1.4/Assemblies/0JecsTools.dll | Bin 111104 -> 113664 bytes 1.4/Assemblies/AbilityUser.dll | Bin 76288 -> 76288 bytes 1.4/Assemblies/AbilityUserAI.dll | Bin 22528 -> 22528 bytes 1.4/Assemblies/CompActivatableEffect.dll | Bin 16896 -> 16896 bytes 1.4/Assemblies/CompAnimated.dll | Bin 12288 -> 12288 bytes 1.4/Assemblies/CompBalloon.dll | Bin 6144 -> 6144 bytes 1.4/Assemblies/CompBigBox.dll | Bin 6656 -> 6656 bytes 1.4/Assemblies/CompDeflector.dll | Bin 27648 -> 27648 bytes 1.4/Assemblies/CompDelayedSpawner.dll | Bin 8192 -> 8192 bytes 1.4/Assemblies/CompExtraSounds.dll | Bin 6144 -> 6144 bytes 1.4/Assemblies/CompInstalledPart.dll | Bin 20480 -> 20480 bytes 1.4/Assemblies/CompLumbering.dll | Bin 7168 -> 7168 bytes 1.4/Assemblies/CompOverlays.dll | Bin 5120 -> 5120 bytes 1.4/Assemblies/CompOversizedWeapon.dll | Bin 8704 -> 8704 bytes 1.4/Assemblies/CompSlotLoadable.dll | Bin 38912 -> 38400 bytes 1.4/Assemblies/CompToggleDef.dll | Bin 13312 -> 13312 bytes 1.4/Assemblies/PawnShields.dll | Bin 35840 -> 35840 bytes 1.4/Assemblies/ThinkNodes.dll | Bin 8192 -> 8192 bytes .../ApparelExtension.cs | 0 .../HarmonyPatches_ApparelExtension.cs | 90 +++ .../JecsTools/Backstories/BackstoryDef.cs | 27 +- .../BuildingExtension.cs | 0 .../HarmonyPatches_BuildingExtension.cs | 142 ++++ .../PlaceWorker_OnTopOfWalls.cs | 0 .../PlaceWorker_Outline.cs | 0 .../PlaceWorker_UnderCeiling.cs | 0 .../DamageSoak/HarmonyPatches_DamageSoak.cs | 268 +++++++ .../HediffCompProperties_DamageSoak.cs | 0 .../{ => DamageSoak}/HediffComp_DamageSoak.cs | 0 .../DamageDefCleave.cs | 0 .../DamageWorker_Cleave.cs | 0 .../HarmonyPatches_ExtraMeleeDamages.cs | 125 +++ .../HediffCompDamageOverTime.cs | 0 .../HediffCompProperties_DamageOverTime.cs | 0 .../HediffCompProperties_ExtraMeleeDamages.cs | 0 .../HediffComp_ExtraMeleeDamages.cs | 0 .../Hediff_InjuryCustomLabel.cs | 0 .../JecsTools/HarmonyPatches.cs | 744 ------------------ .../Knockback/HarmonyPatches_Knockback.cs | 65 ++ .../HediffCompProperties_Knockback.cs | 0 .../{ => Knockback}/HediffComp_Knockback.cs | 0 .../OtherHarmonyPatches/HarmonyPatches.cs | 52 ++ .../HarmonyPatches_Debug.cs | 26 + .../HarmonyPatches_GUI.cs | 0 .../HarmonyPatches_Obsolete.cs | 33 + .../ProjectileExtension.cs | 0 .../Projectile_Laser.cs | 0 .../ThingDef_LaserProjectile.cs | 0 .../HarmonyPatches_StartWithGenes.cs | 58 ++ .../StartWithGenes/PawnKindGeneExtension.cs | 41 + .../HarmonyPatches_StartWithHediff.cs | 40 + .../HediffExpandedDef.cs | 0 .../HediffGiver_StartWithHediff.cs | 0 .../HediffWithComps_Expanded.cs | 0 .../JecsTools/_HumanlikeOrdersUtility.cs | 1 - 55 files changed, 959 insertions(+), 753 deletions(-) rename Source/AllModdingComponents/JecsTools/{ => ApparelExtension}/ApparelExtension.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/ApparelExtension/HarmonyPatches_ApparelExtension.cs rename Source/AllModdingComponents/JecsTools/{ => BuildingExtension}/BuildingExtension.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/BuildingExtension/HarmonyPatches_BuildingExtension.cs rename Source/AllModdingComponents/JecsTools/{ => BuildingExtension}/PlaceWorker_OnTopOfWalls.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => BuildingExtension}/PlaceWorker_Outline.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => BuildingExtension}/PlaceWorker_UnderCeiling.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/DamageSoak/HarmonyPatches_DamageSoak.cs rename Source/AllModdingComponents/JecsTools/{ => DamageSoak}/HediffCompProperties_DamageSoak.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => DamageSoak}/HediffComp_DamageSoak.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/DamageDefCleave.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/DamageWorker_Cleave.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HarmonyPatches_ExtraMeleeDamages.cs rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/HediffCompDamageOverTime.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/HediffCompProperties_DamageOverTime.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/HediffCompProperties_ExtraMeleeDamages.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/HediffComp_ExtraMeleeDamages.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ExtraMeleeDamages}/Hediff_InjuryCustomLabel.cs (100%) delete mode 100644 Source/AllModdingComponents/JecsTools/HarmonyPatches.cs create mode 100644 Source/AllModdingComponents/JecsTools/Knockback/HarmonyPatches_Knockback.cs rename Source/AllModdingComponents/JecsTools/{ => Knockback}/HediffCompProperties_Knockback.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => Knockback}/HediffComp_Knockback.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches.cs create mode 100644 Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Debug.cs rename Source/AllModdingComponents/JecsTools/{ => OtherHarmonyPatches}/HarmonyPatches_GUI.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Obsolete.cs rename Source/AllModdingComponents/JecsTools/{ => ProjectileExtension}/ProjectileExtension.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ProjectileExtension}/Projectile_Laser.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => ProjectileExtension}/ThingDef_LaserProjectile.cs (100%) create mode 100644 Source/AllModdingComponents/JecsTools/StartWithGenes/HarmonyPatches_StartWithGenes.cs create mode 100644 Source/AllModdingComponents/JecsTools/StartWithGenes/PawnKindGeneExtension.cs create mode 100644 Source/AllModdingComponents/JecsTools/StartWithHediff/HarmonyPatches_StartWithHediff.cs rename Source/AllModdingComponents/JecsTools/{ => StartWithHediff}/HediffExpandedDef.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => StartWithHediff}/HediffGiver_StartWithHediff.cs (100%) rename Source/AllModdingComponents/JecsTools/{ => StartWithHediff}/HediffWithComps_Expanded.cs (100%) diff --git a/1.4/Assemblies/0JecsTools.dll b/1.4/Assemblies/0JecsTools.dll index 3f0619d0bf89cb225fef87920c2da6b6c48534c1..7d2e445fac66f36351adb785a0a94210058c6963 100644 GIT binary patch literal 113664 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

-%VrqI@JDQjiJ577E>Q~`8mwA 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≧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 literal 111104 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 delta 259 zcmZqJz}T>XaY6^nv8@w+Oze?i+%<7!IAg|SMn-j3pF9QznaPSwI+G(A)fo>=Ze*-y zoHLn`Ntkto2?GP;;|j}%*hPpn}5n) zWn^Vx0D{Sv<(0+z6<*hZI1CK@Tp*H>0W7zfSAknp!19DwshQ+bw^eyz5mvQ|ew#H+ zIa!st7#UcD!VUFI7#MgM8Q6ggJp(-h1_nMx22Lnva*Wj$UV})Gfe_#|S=L$_=vGVX zs}l`4CiB@;@v;Ez0s%0+d8$n^Bc}<29)kf0Z)UXfN8(P7v^Pdb0==2T8342#s5!=R Mv!KI!#)$^(0H63ljsO4v delta 337 zcmZo@VQgq&oY2AIU-4kW#2y*Oq=_rT83iUYGODwFiC|!mnXJg9GdYq`oiSr_BV#?I z%Vb6-Vb%kh3=E8u6RpiR2QaztGoINzRZy3QU4~VU!J9#I@<~}ub_>=7=46KY%|B(Y zGO{u=Ffg!AzAUdS-k}g*2IK$%KNpB(WB|);=2hSp6_~QN=kb)|HJ;NrW%AN4d|I+u z!<3WNScs8-Hpz^f#teE4 o20(1OnbFQ4i90#c-WVYX^nVU#0MIo+%_)|f1s&cqPBdT#04#7yRsaA1 diff --git a/1.4/Assemblies/CompAnimated.dll b/1.4/Assemblies/CompAnimated.dll index 9a4d5991ebe183bb78e7c5198e8ff1b51a47ab19..ac3e9e84b4c1718ee979cf14a174eb45e0023346 100644 GIT binary patch delta 439 zcmYk&F-rq66ae7&E;-t(wpfL>L%}O89<3TqEOb#gsi2^P=uk_SgSt7o38g1EbP(Dj zii<;07ZDshhYk)ENAW*Y6ch?Ni8yI4C>qF@_wrssh+{i;t3fZy&rNqPiI?tK32lyO zsPhW|NuE+Bco_}s@ExqC4pln-3&>G5Y*Mu z6w3n)A_PRhOlAT^5VW7f>l-y3Ziuh?9mjsGyQ!G?EH_(o%^;8Dw!;)qcF5H`$Q4n` k0|V2a-oyClzm#i}(|<)CW!IV|ULcNN6}%{WL)Q#^13p_}tpET3 delta 456 zcmYk&!7D^T90&04@6CJdzRlY##le=hQT8pyYH3euvr4iDk)%C%EVaeDkb{!vM(ts@ zNgVdDMZ)zRNDeE1hav|zPA*PnCt_+oGr!+&W}1GU>$#Ofz3XP^rdp2DUG-{#ih`)m z$V~!K5z_|5BK1*29MC@11ZnNYc@!Y=;H3Q-?KVVZ-?UDG`|XS)3tKvkca39C`iON* z=+DSwh`p+PhVnRN&sqTi9jsXe+mdEj0aLoGGOo&a%DNJI^Ng*`C|#wetT*k|8!E63 z^_27@TBKY-GyL=0tHF{a9jbP0# z4D*rs&8_X_m5nu^g%B9#DW2q`K$u|u1Xc(r5(**~?+~SU+;`$>vMRELzvEhzoG#hG zBWF*96T21z!H`9@`p1bZnJI82Nf6-9*Kn;H2PdHFu=NB9R-lYwvc C#bqP_ diff --git a/1.4/Assemblies/CompBalloon.dll b/1.4/Assemblies/CompBalloon.dll index b2879f70b927c8e052f17233656c62a4a003ae74..1f1c3ba052d340240f933efeb41ed17f153a4e9d 100644 GIT binary patch delta 290 zcmZoLXfT-2!SXM7=l6*{GK^jmSBCTb&|_fmX8-~R1_le}iHgEJ2@DK8K>i(|gv?|` zCY{NVjOvU5lN%Z98FeNzG6}O<0HqlxCkmQx4q)2C#JFZND{C|}dq1NdgEPaN$>|)n ztSmtN43k%KD6{k{ysq7Rfg^xT;NZRQ?7?;W9JX%0{AtO8us@p(_*)p2xfmH(gTf8< zOn{a$GOz;~dIow13=DjX44hETlA x1j~Wx%~OS}897ZD^cW04c=JtRVI=P4uOh|>$;pPI*O`3mHw%irXPjuj4gdvdLazV- delta 299 zcmZoLXfT-2!NRVxec{9&8OETAE5rF1^cfiZ8Gyinfx&`#qM|TQ0s{jNkpD!Ffk9@n zB9qSKNJe$Wh{=tN^^7Ky8JUDx9e~n|lLH0KHwQ3nVPf2}nUyt~nSDB=9)mN(lF8{D zwyexR{j8H$awxNOD8!d-zQ7T{CXiFSw)T69jORw1q%S9X9cOMf;BR5n7Gh-J4GK5Z zGYQQrE=f$vNd;QY$iQx>XRK$SXUf39$H>45PW%EOp)y(WS81)#u8J+Y?P`9ERv9{#h8s$7f=tU=+1dL|4EJd6zNK!%=yo&f^`A0q=Nl*7w4 zd7Gdd?-!seV1RG(LqTaqhRuHk1(_xqaBSui*~Y|d!N4{7xR^dOF9X-+pJM!sObP~@ M1ts1yPBdT#04el3MF0Q* delta 229 zcmZoLX)u}4!J?6EykcUH45Qk_mEnw6CNnasv+mGmV33)t$fPqll2M&eXL2KBJtN0t zMkZla3tk2W#>s|4=9>eUCNMGn+5C`YH8cAIMm+{^hPRU^bNI7#DI{iZe#UW(P2jR& zUAS1YjNg&wzn} zmyv-3%Hd*|yiQO~=nv2}Fdzn0!JsfvQH+se^H)JZrp%7t?3vVqn<( TQ;eUHNyA{Xpu~H|i3aQdq=Y)^ diff --git a/1.4/Assemblies/CompDeflector.dll b/1.4/Assemblies/CompDeflector.dll index 498b0e4a4517c43190f19971a9fa9c82f7e3c9d6..20653718d1f92fa848a54be7e0eaec32e490d275 100644 GIT binary patch delta 322 zcmZp;!PszvaY6^nOO~@oC-%rNHcea^&S)^1kx`vhq?v(1X0jra&g4i&b;gd#jg0k- zDU%tQgjpk87#J8QPfRu69Kdu&j`7ZBS;eWs?1>zD4BiZRlXsf<3fFQZvLrKnVQpY3 zX4uQI07!C7mNb=R_vdV2D`x25Y-<|G%*w(51d}IQD6{k{ysq86%OX!np!wQ6^J2N% zPAdva4R<6SDcNih9mb)|#mK-K6mF<`CG-1$VFaY7r57Xt5xRW_E cjS-TQ1+(^WHUM1!)ZSveSupE8<3s~?0Ldy(@&Et; delta 323 zcmZp;!PszvaY6@+PN(9Di9IrmT@zP^Gg?e$WK?IBX=Y%MnXJg9GdYq`opHkCM#g%^ zoXLz#!mJ4{3=E8uC#ITj4q!SX$M|Hktm0H*_Dl{v25*M4$vaJag!FWMBnKg6Yju)0`POjT!V941m~l l^TTv`B<^I+Ok;%PWWlUGoDD#$ftq`aHw$LHXPjuj4gfy{QEvbM diff --git a/1.4/Assemblies/CompDelayedSpawner.dll b/1.4/Assemblies/CompDelayedSpawner.dll index 09a326c80edcbe3a36fec1f894d5eb0975c64560..1c1eac8647910988ee54edb6d48d5d6b46e61a30 100644 GIT binary patch delta 272 zcmZp0XmFU&!IJB>=flJv8OE-OE5jKrCNnasv&xt;Fvv_+WYU=&$*9gaVR9p5J!8&f zMkZm_ErJXTjFT5im~ReXs$gL}v-u?3PZsvIOnMB?47(;1KXnKH`1lc$Hh%-+Hd4S&P{=2Z%0WQs!c0U=0d4)H7jV;9+E72Qu^w^b8mn z_!t>Dp`6LG63V;@K-a)P)ns1@X~vw*nG#DGCmL`}=98-8Wno|hOM~gnQ>CIAIZYV! j7z{vo^G|7KB<^HaS!0Cc;}T delta 281 zcmZp0XmFU&!Ln2~_tC^28OBKySB5h>OlD+MXH_v{V33)t$fPqll2M&;#^grEdd8B; zj7-9;djuI67$;AZFy9=&RKdb{W%Eh4pDgTKne-T(84gW8$sNqf%)r3FI$4oNnWaM^ zzHGAx&kqiP<0X$=g=7|bt>tbO-DkK(l(7fW3#H5^51_mBR z26jU|V?6^sQw9b;Mg~qOXR@e-vQP%lRWQ&5Vk=Bk6k{yeoG7uBaWbD&6)!UbBLgc? w987PXDizJhY0RLBXK9Y${HgiCpXHrGfgquEGYM$aiRe`08n*7(f|Me diff --git a/1.4/Assemblies/CompExtraSounds.dll b/1.4/Assemblies/CompExtraSounds.dll index bbef52296325fb477acf80df363e79d6deeb9461..d4c352c967933a1a9a79c79aa71194a07b212d8a 100644 GIT binary patch delta 282 zcmZoLXfT-2!D9V5eDcH|8AhXtE5jKdOlD+MXFa0Fz#ubOkx6HAB%?Z`#pFiDdPb4S zj7-9;Ke!nf7$-Xlnr{wZy2He{X0tA9J~MkSqaK4d!>q}RIXqce7=U2%M-F9{eudYy zn? zK1K#kC};9f0c9Z$eUOn5pafzoOjHyDx<^p(??eNR$$UapyetfiV0kdTd8&{%Bc}<2 p9)kf0Z+n+3(*Gfp&M2LRosJ#GL1 delta 283 zcmZoLXfT-2!D9LP5E)w%p(nO8s`XfzaPO@1pN4RjNy;NQu7LRGxX42%q{KshkI yd8&{%Bd0Ng9)kf8n{Iw7tc}E-EGue^kOcZ=1*ZbgW}s#p`^|!4?-?f=umb>!Rza@- diff --git a/1.4/Assemblies/CompInstalledPart.dll b/1.4/Assemblies/CompInstalledPart.dll index 5b6d60f47003de9c6b5ce0ed5ee9120316b54c7a..0823cc028e598556e8c2f97b536be4189b1a478c 100644 GIT binary patch delta 260 zcmZozz}T>WaY6^n-`kFJCiciM?whzWoH1uIBcnQNKsp11%w$C-oyn1m>WoJwH!{{U zE||>7B+P1I%D})l`J$)!<^U!QA;veGD@8W*v9ogMF?cfwO*U3`lvLzMV5(+_XK!HQ z29gWFWCL?CL&oG@Wm(3Rn^!A$GO_e4ysq7Bp(Z0G(C7ENv~EkF)7&MmS2En<5!{^O z@QYoAi;;mfDBMubgn@yFk%1k^&@<38U|`^5WZ;Bycqeyy+?t%?DZo1g=vo+9H@VSM t8tB%!o`n+)I5zWnePUv^VBng}?5oer3#3hbFEbr5-z@0&o^hf9I{@FDN1Olv delta 268 zcmZozz}T>WaY6@6j+5}Di9Irm$0n`}XDpe_$f(X5k?LeDBMubBs8zMBrz!`m4ShWk%1j3pl6_Gz`(%E$iM;ROm6bHH96W-P-qU& z(J-(L#8#N7Cj!Ls7e*}oHeWEg`ct_){nn9Rti&icfVfk9@nB9qSKNJe$Wh{=tN^^7Ky z8JUDxbNCn-7$+x+m~ReX>R@KPv-u|LR%Z5njCu^t45uegj!Sb&0^y!H`GK^6ZSB5ikOlD+MXMJPHz#ubOkx6HAB%?ZG!sJHAdPbYc zj7-9;C43AFjFS^Z%r^%xbucqN*?g0AD>M5sMm+{+hRc(uavHNTGcYi)PCm=2%+jF{ zU$*%RCkuzb#P-V$O`5#teE420(1O`JuQx5_dAEq%lGg=$Sp720*KUnq!PM3rf9boM^xf0PNyJ AUH||9 diff --git a/1.4/Assemblies/CompOverlays.dll b/1.4/Assemblies/CompOverlays.dll index 8c3208a1f461aec3441fab2288a9077f0ef0aa17..e0a3d2dd90765c4f5fa292045d7a0a9d8645bf5e 100644 GIT binary patch delta 282 zcmZqBXwaC@!4f;`=k$p^GK`NVt_)|KFqx52owY=pfk9@nB9qSKNJe$W7n2(q>lu$s zW@Hj(E#PEeV4NH%XudgsNrZ{9V{? zK1K#kC}(m7uY%AHple{@5{RuZQBe%&o`bx;6Ad^f^YK;jvM?}$Re@loC-h(0JT4{-Yh8eo^hf9I{->QKuiDt delta 283 zcmZqBXwaC@!Sd6%?#{#>8OB!=SB5jrn9Rti&RV0*z#ubOkx6HAB%?axhslkM^^9jG zGcpOYR&X*fFis8>G~XP+B*MfvVRI_WZ6@{-Mm+{+hQ`V6?B=Y@3=9mclbhL?I%|Oj>tTzh^y=Rgg)!SeC%|5+1zWEhW4Tp7+-GMSN4oi)OOfk9@nB9qSKNJe$WGm{$`>ls%} zW@Hj(RS{xfV4VC=%6xMGlM5T;n$1%=R9V^kne-UE8Rkqr$eYZ{!Tkz`4v2O^BVCMCS@*02G*c(Lp>7)1|CKRb|6E~K+k}I zfsc`a6Uvz!Eu|gg)!E*O>*0zZ~GK}XYt_)|anas$j&YEDsz#ubOkx6HAB%?axmC22a^^6-P zGcpOY>Ig9~FiyTGWxhFp$%Tz^%jT&Zs;unOne-UE8J0{w$eYZ{%)r3FI$4uXnWaM^ zzHD;xj0~Jm&g5VzMcySqSHZx($&FIdj2kx3mC9tC%qLUD%gn&YzzUQF v)0?NtL^E<4Gw3lG0I})jpR&$K+{v!;#t6yDjq>eG7c4dlD!gZ$Xuu8tSnovM diff --git a/1.4/Assemblies/CompSlotLoadable.dll b/1.4/Assemblies/CompSlotLoadable.dll index 9b3fae54969ca0e0853948f2cec39f5079aae987..9df18404301f62b85cf3130e25b8f4f0592cfa01 100644 GIT binary patch delta 330 zcmZqJz|^pYX+npRf#a*W3{dcZK}ms|(SU)W4=BI}5&X4w;;Jyl6_Xhm)meMiGBC(Y zR%Ftd9LcE81y-d1RMj`Ri&2|#!sKm?>Wot+-(yr_yfc}RNto3nk%576vfu>s%>hgq zI*bOJcj_&bmTcqGWAJ8}3?zdYQh{VNkZfQ`W>_@2+$)&(1s^kWHp4?+1?FT1)ydbr z^x4z+6IhZNmQUvOmSudoS=+mxg{5ENb?xST{(brao9`)E9N|m#S=c^R@oQi{_vV=T zYCdf)Mh4cPa6>&41_mBR26iAr&p;38Ej~sDPAG?$i-EzFk-=fIf1l`PxxPlm$qV`g ycrO4w2m`Ms@9mcc`s8N6?Pk77pO}~}7`P@gPt|AU1=6NdFEjnI-7Gla8zTT>l~`c_ delta 342 zcmZoz!_=^WX+npRfYzF=3{dcZK}ms|(SU(r0#JYrBFMCE;;Jyl4U-ue)mf*kWnhq* ztjMG@Ig(MGi=z*yLIH>;OzvXTW}Gy68>2eow8{4vl^CB)W@Hj(wMk@PV4Pey*?e;V zQ-%(s#pa!QOQj|I`1BaO8D;~?V1`s684V;G7?K%QPA>Nf=6%n{%$&{ekXL~@nL%gr zbuWGPT>b=>WQKK59mE!Mg|TjXY=pgxr~#i_X`T$ z0D2AvK7rT@6BWgPKDpR$yIFq9L&nJtjN+U5CVXOIHe=wN%sg42nTvs8vgzc@Oe}Vr M1*g1coM^xf0GiNTYybcN diff --git a/1.4/Assemblies/CompToggleDef.dll b/1.4/Assemblies/CompToggleDef.dll index a91468611f0407efde7991c495e190c8f5985643..25956f3390d789c5e9c07ace564de4f69317b75a 100644 GIT binary patch delta 307 zcmZq3Xvmn*!BRTy&8CSxGK@kKSB5hln9Rti&bq{tfk9@nB9qSKNJe!=iOG$O^^9L8 zGcpOY#>g`;Fiuv~G2a}(6v4%4vUw$sIH&wY7Ci=UhI>FVm|-)Jj0Tbk4A~5CSsEFV z8FVJ!7yZx5!T-UGrS0|N3^O>8n}j<^r{2EXrJr z46H%nhI%Fp3_Oes>_CQ|ft~>a10N#;CzLZeQ9E7e1<;i+z~lvFDNIxpWBjuDqqZ#5 zL<5e=e0o*9EDVfbC185co@IHF`cg)Hg>jqPV;%(@`B;e>dgge$5^z5 z7#Vnj!VUFILi37C5|eUL85npN8Q2Z=jP(rkOc@yX7#TRBoXL^e>AW9+u7v@v$!E2t z8UJj4sV&PinNP2ZmzjZ)ffXnVrZ-R3b7tf;X3%3W0Akb45B24dxRW^zjS-SSPwwG# T09p;yEMv7<(C9tmL<4pJ=-Erf diff --git a/1.4/Assemblies/PawnShields.dll b/1.4/Assemblies/PawnShields.dll index 680c59b6b330b79a1d1aa238cb75c2b35298a4f4..f27bd20bffff1935cf14909bffc1074ee72ad64a 100644 GIT binary patch delta 299 zcmZpe!PGE=X+j6f{-T*HC-%rNc1>Iv&S){2kx`vhW)TB}%w$C-oyn1m>WmX6H!{{U z=1gW}5@uzHW?*2Pys*W5a{!Z$I^&zowVLeG>{UE^4Biawle=A%ZKv@xGVW$bET2b(i;;mfDBMubgn@yFk%1k^ z&@<38U|`^5WZ;BycsHMFN@bjE&?3N_0Q3?JR8976k!H-pf5bI{WnicH!{{U zmP}@35@zLyW?*2PJh8=ma{!Z$I^&nkwVLeG>`gp+4Bia=le=A%ZRhedGVW%`;B98) zX1K+DnDH@?dzkCrHq^T l+O{zltTE zW@Hj(?Ga*NV4QqW(tL9O(-{^CIE6tQk3t8T1$ofY@~NO=)2y?&PmB#t6yDhO*b04w!EilzY!O H(SRKQ)9y#^ diff --git a/Source/AllModdingComponents/JecsTools/ApparelExtension.cs b/Source/AllModdingComponents/JecsTools/ApparelExtension/ApparelExtension.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/ApparelExtension.cs rename to Source/AllModdingComponents/JecsTools/ApparelExtension/ApparelExtension.cs diff --git a/Source/AllModdingComponents/JecsTools/ApparelExtension/HarmonyPatches_ApparelExtension.cs b/Source/AllModdingComponents/JecsTools/ApparelExtension/HarmonyPatches_ApparelExtension.cs new file mode 100644 index 00000000..f600b781 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/ApparelExtension/HarmonyPatches_ApparelExtension.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_ApparelExtension(Harmony harmony, Type type) + { + //Checks apparel that uses the ApparelExtension + harmony.Patch(AccessTools.Method(typeof(ApparelUtility), nameof(ApparelUtility.CanWearTogether)), + postfix: new HarmonyMethod(type, nameof(Post_CanWearTogether))); + + //Handles cases where gendered apparel swaps out for individual genders. + harmony.Patch(AccessTools.Method(typeof(PawnApparelGenerator), nameof(PawnApparelGenerator.GenerateStartingApparelFor)), + postfix: new HarmonyMethod(type, nameof(GenerateStartingApparelFor_PostFix))); + } + + + //PawnApparelGenerator + public static void GenerateStartingApparelFor_PostFix(Pawn pawn) + { + var allWornApparel = pawn.apparel?.WornApparel; + if (allWornApparel.NullOrEmpty()) + return; + List<(Apparel, Apparel)> swapEntries = null; + foreach (var wornApparel in allWornApparel) + { + if (wornApparel.def?.GetApparelExtension()?.swapCondition is SwapCondition sc && + sc.swapWhenGender is Gender gen && + gen != Gender.None && gen == pawn.gender) + { + var swapApparel = (Apparel)ThingMaker.MakeThing(sc.swapTo, wornApparel.Stuff); + // Avoid modifying WornApparel during its enumeration by doing the swaps afterwards. + swapEntries ??= new List<(Apparel worn, Apparel swap)>(); + swapEntries.Add((wornApparel, swapApparel)); + } + } + if (swapEntries != null) + { + foreach (var (wornApparel, swapApparel) in swapEntries) + { + PawnGenerator.PostProcessGeneratedGear(swapApparel, pawn); + if (ApparelUtility.HasPartsToWear(pawn, swapApparel.def)) + { + pawn.apparel.Wear(swapApparel, false); + DebugMessage($"apparel generation for {pawn}: swapped from {wornApparel} to {swapApparel}"); + } + wornApparel.Destroy(); + DebugMessage($"apparel generation for {pawn}: destroyed old {wornApparel}"); + } + } + } + + ///

+ /// Using the new ApparelExtension, we can have a string based apparel check. + /// + public static void Post_CanWearTogether(ThingDef A, ThingDef B, BodyDef body, ref bool __result) + { + static HashSet GetCoverage(ThingDef thingDef) + { + var coverage = thingDef.GetApparelExtension()?.Coverage; + return coverage == null || coverage.Count == 0 ? null : coverage; + } + + if (A == null || B == null || body == null || __result == true) + return; + var coverageA = GetCoverage(A); + var coverageB = GetCoverage(B); + if (coverageA != null && coverageB != null) + { + foreach (var coverageItem in coverageB) + { + if (coverageA.Contains(coverageItem)) + { + __result = false; + break; + } + } + } + else if ((coverageA != null && coverageB == null) || (coverageA == null && coverageB != null)) + { + __result = true; + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs b/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs index af749a1d..45e911bb 100644 --- a/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs +++ b/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs @@ -12,7 +12,6 @@ namespace JecsTools //Link -> https://github.com/RimWorld-CCL-Reborn/AlienRaces/blob/94bf6b6d7a91e9587bdc40e8a231b18515cb6bb7/Source/AlienRace/AlienRace/BackstoryDef.cs public class BackstoryDef : RimWorld.BackstoryDef { - public static HashSet checkBodyType = new HashSet(); public List forcedTraitsChance = new List(); @@ -27,21 +26,33 @@ public class BackstoryDef : RimWorld.BackstoryDef public IntRange chronoAgeRange; public List forcedItems = new List(); - public bool CommonalityApproved(Gender g) => Rand.Range(min: 0, max: 100) < (g == Gender.Female ? this.femaleCommonality : this.maleCommonality); + public bool CommonalityApproved(Gender g) => Rand.Range(min: 0, max: 100) < + (g == Gender.Female + ? this.femaleCommonality + : this.maleCommonality); public bool Approved(Pawn p) => this.CommonalityApproved(p.gender) && - (this.bioAgeRange == default || (this.bioAgeRange.min < p.ageTracker.AgeBiologicalYears && p.ageTracker.AgeBiologicalYears < this.bioAgeRange.max)) && - (this.chronoAgeRange == default || (this.chronoAgeRange.min < p.ageTracker.AgeChronologicalYears && p.ageTracker.AgeChronologicalYears < this.chronoAgeRange.max)); + (this.bioAgeRange == default || + (this.bioAgeRange.min < p.ageTracker.AgeBiologicalYears && + p.ageTracker.AgeBiologicalYears < this.bioAgeRange.max)) && + (this.chronoAgeRange == default || + (this.chronoAgeRange.min < p.ageTracker.AgeChronologicalYears && + p.ageTracker.AgeChronologicalYears < this.chronoAgeRange.max)); public override void ResolveReferences() { this.identifier = this.defName; base.ResolveReferences(); - this.forcedTraits = (this.forcedTraits ??= new List()). - Concat(this.forcedTraitsChance.Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance).ToList().ConvertAll(converter: trait => new BackstoryTrait { def = trait.defName, degree = trait.degree })).ToList(); - this.disallowedTraits = (this.disallowedTraits ??= new List()). - Concat(this.disallowedTraitsChance.Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance).ToList().ConvertAll(converter: trait => new BackstoryTrait { def = trait.defName, degree = trait.degree })).ToList(); + this.forcedTraits = (this.forcedTraits ??= new List()).Concat(this.forcedTraitsChance + .Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance).ToList() + .ConvertAll(converter: trait => new BackstoryTrait { def = trait.defName, degree = trait.degree })) + .ToList(); + this.disallowedTraits = (this.disallowedTraits ??= new List()).Concat(this + .disallowedTraitsChance.Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance) + .ToList() + .ConvertAll(converter: trait => new BackstoryTrait { def = trait.defName, degree = trait.degree })) + .ToList(); this.workDisables = (this.workAllows & WorkTags.AllWork) != 0 ? this.workDisables : ~this.workAllows; if (this.bodyTypeGlobal == null && this.bodyTypeFemale == null && this.bodyTypeMale == null) diff --git a/Source/AllModdingComponents/JecsTools/BuildingExtension.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension/BuildingExtension.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/BuildingExtension.cs rename to Source/AllModdingComponents/JecsTools/BuildingExtension/BuildingExtension.cs diff --git a/Source/AllModdingComponents/JecsTools/BuildingExtension/HarmonyPatches_BuildingExtension.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension/HarmonyPatches_BuildingExtension.cs new file mode 100644 index 00000000..f4a293d6 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/BuildingExtension/HarmonyPatches_BuildingExtension.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_BuildingExtension(Harmony harmony, Type type) + { + //BuildingExtension prevents some things from wiping other things when spawned/constructing/blueprinted. + harmony.Patch(AccessTools.Method(typeof(GenSpawn), nameof(GenSpawn.SpawningWipes)), + postfix: new HarmonyMethod(type, nameof(SpawningWipes_PostFix))); + harmony.Patch(AccessTools.Method(typeof(GenConstruct), nameof(GenConstruct.CanPlaceBlueprintOver)), + postfix: new HarmonyMethod(type, nameof(CanPlaceBlueprintOver_PostFix))); + + //Ignores all structures as part of objects that disallow being fired through. + harmony.Patch(AccessTools.Method(typeof(Projectile), "CanHit"), + postfix: new HarmonyMethod(type, nameof(CanHit_PostFix))); + + //Allows a bullet to pass through walls when fired. + harmony.Patch(AccessTools.Method(typeof(Verb), "CanHitCellFromCellIgnoringRange"), + prefix: new HarmonyMethod(type, nameof(CanHitCellFromCellIgnoringRange_Prefix))); + } + + + public static void SpawningWipes_PostFix(BuildableDef newEntDef, BuildableDef oldEntDef, ref bool __result) + { + // If SpawningWipes is already returning true, don't need to do anything. + if (__result == false && newEntDef is ThingDef newDef && oldEntDef is ThingDef oldDef) + { + if (HasSharedWipeCategory(newDef, oldDef)) + __result = true; + } + } + + + public static void CanPlaceBlueprintOver_PostFix(BuildableDef newDef, ThingDef oldDef, ref bool __result) + { + // If CanPlaceBlueprintOver is already returning false, don't need to do anything. + if (__result == true && newDef is ThingDef thingDef) + { + if (HasSharedWipeCategory(thingDef, oldDef)) + __result = false; + } + } + + //Check wipe categories on BuildingExtension between two defs + private static bool HasSharedWipeCategory(ThingDef newDef, ThingDef oldDef) + { + static HashSet GetWipeCategories(ThingDef thingDef) + { + var buildingExtension = GenConstruct.BuiltDefOf(thingDef)?.GetBuildingExtension(); + if (buildingExtension == null) + return null; + var wipeCategorySet = buildingExtension.WipeCategories; + return wipeCategorySet == null || wipeCategorySet.Count == 0 ? null : wipeCategorySet; + } + + var wipeCategoriesA = GetWipeCategories(newDef); + DebugMessage($"{newDef} wipeCategoriesA: {wipeCategoriesA.ToStringSafeEnumerable()}"); + var wipeCategoriesB = GetWipeCategories(oldDef); + DebugMessage($"{oldDef} wipeCategoriesB: {wipeCategoriesB.ToStringSafeEnumerable()}"); + if (wipeCategoriesB == null && wipeCategoriesA == null) + { + DebugMessage("both wipeCategories null => false"); + return false; + } + else if (wipeCategoriesA != null && wipeCategoriesB == null) + { + DebugMessage("wipeCategoriesB null => false"); + return false; + } + else if (wipeCategoriesB != null && wipeCategoriesA == null) + { + DebugMessage("wipeCategoriesA null => false"); + return false; + } + else + { + foreach (var strB in wipeCategoriesB) + { + if (wipeCategoriesA.Contains(strB)) + { + DebugMessage($"found shared wipeCategories ({strB}) => true"); + return true; + } + } + DebugMessage("no shared wipeCategories => false"); + return false; + } + } + + + + //Added B19, Oct 2019 + //ProjectileExtension check + //Ignores all structures as part of objects that disallow being fired through. + public static void CanHit_PostFix(Projectile __instance, Thing thing, ref bool __result) + { + // TODO: This patch looks pointless since it can only change __result from false to ... false. + if (__result == false && __instance.def?.GetProjectileExtension() is ProjectileExtension ext) + { + if (ext.passesWalls) + { + //Mods will often have their own walls, so we cannot do a def check for ThingDefOf.Wall + //Most "walls" should either be in the structure category or be able to hold walls. + // TODO: In RW 1.3+, it seems like BuildingProperties.isPlaceOverableWall indicates whether something is a "wall", + // but it may be better to just look at ThingDef.Fillage/fillPercent instead, + // or maybe use PlaceWorker_OnTopOfWalls's heuristic of checking whether the defName contains "Wall"? + if (thing?.def is ThingDef def && (def.designationCategory == DesignationCategoryDefOf.Structure || def.holdsRoof)) + { + __result = false; + return; + } + } + } + } + + + //Added B19, Oct 2019 + //ProjectileExtension check + //Allows a bullet to pass through walls when fired. + public static bool CanHitCellFromCellIgnoringRange_Prefix(Verb __instance, ref bool __result) + { + if (__instance.EquipmentCompSource?.PrimaryVerb?.verbProps?.defaultProjectile?.GetProjectileExtension() is ProjectileExtension ext) + { + if (ext.passesWalls) + { + // TODO: While this does bypass the line-of-sight checks (and should it really bypass all LOS checks?), + // this also bypasses non-LOS checks, which doesn't look right. + __result = true; + } + return false; + } + return true; + } + +} diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_OnTopOfWalls.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs rename to Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_OnTopOfWalls.cs diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_Outline.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs rename to Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_Outline.cs diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_UnderCeiling.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs rename to Source/AllModdingComponents/JecsTools/BuildingExtension/PlaceWorker_UnderCeiling.cs diff --git a/Source/AllModdingComponents/JecsTools/DamageSoak/HarmonyPatches_DamageSoak.cs b/Source/AllModdingComponents/JecsTools/DamageSoak/HarmonyPatches_DamageSoak.cs new file mode 100644 index 00000000..3620bfb1 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/DamageSoak/HarmonyPatches_DamageSoak.cs @@ -0,0 +1,268 @@ +using System; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + + public static float? tempDamageAmount = null; + public static float? tempDamageAbsorbed = null; + + public static void HarmonyPatches_DamageSoak(Harmony harmony, Type type) + { + //Allow fortitude (HediffComp_DamageSoak) to soak damage + //Adds HediffCompProperties_DamageSoak checks to damage + harmony.Patch(AccessTools.Method(typeof(Pawn_HealthTracker), nameof(Pawn_HealthTracker.PreApplyDamage)), + prefix: new HarmonyMethod(type, nameof(HarmonyPatches.PreApplyDamage_PrePatch))); + //Applies cached armor damage and absorption + harmony.Patch(AccessTools.Method(typeof(ArmorUtility), "ApplyArmor"), + prefix: new HarmonyMethod(type, nameof(HarmonyPatches.Pre_ApplyArmor))); + //Applies damage soak motes + harmony.Patch(AccessTools.Method(typeof(ArmorUtility), nameof(ArmorUtility.GetPostArmorDamage)), + postfix: new HarmonyMethod(type, nameof(HarmonyPatches.Post_GetPostArmorDamage))); + } + + public static bool PreApplyDamage_PrePatch(Pawn ___pawn, ref DamageInfo dinfo, out bool absorbed) + { + DebugMessage($"c6c:: === Enter Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); + if (___pawn != null) + { + DebugMessage("c6c:: Pawn exists."); + var hediffSet = ___pawn.health.hediffSet; + if (hediffSet.hediffs.Count > 0) + { + DebugMessage("c6c:: Pawn has hediffs."); + // See above ArmorUtility comments. + if (PreApplyDamage_ApplyDamageSoakers(ref dinfo, hediffSet, ___pawn)) + { + DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); + absorbed = true; + return false; + } + } + } + + // TODO: tempDamageAmount shouldn't be set if there are no damage soaks. + tempDamageAmount = dinfo.Amount; + DebugMessage($"c6c:: tempDamageAmount <= {tempDamageAmount}"); + absorbed = false; + DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); + return true; + } + + + + private static void DamageSoakedMote(Pawn pawn, float soakedDamage) + { + if (soakedDamage > 0f && pawn != null && pawn.Spawned && pawn.MapHeld != null && + pawn.DrawPos is Vector3 drawVecDos && drawVecDos.InBounds(pawn.MapHeld)) + { + // To avoid any rounding bias, use RoundRandom for converting int to float. + var roundedSoakedDamage = GenMath.RoundRandom(soakedDamage); + DebugMessage($"c6c:: DamageSoakedMote for {pawn}: {soakedDamage} rounded to {roundedSoakedDamage}"); + MoteMaker.ThrowText(drawVecDos, pawn.MapHeld, "JT_DamageSoaked".Translate(roundedSoakedDamage)); + } + } + + private static bool PreApplyDamage_ApplyDamageSoakers(ref DamageInfo dinfo, HediffSet hediffSet, Pawn pawn) + { + // Multiple damage soak hediff comps stack. + DebugMessage($"c6c:: --- Enter PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); + var damageDef = dinfo.Def; + var totalSoakedDamage = 0f; + foreach (var hediffComp in hediffSet.GetAllComps()) + { + if (!(hediffComp is HediffComp_DamageSoak damageSoakComp)) + continue; + DebugMessage("c6c:: Soak Damage Hediff checked."); + + var soakProps = damageSoakComp.Props; + if (soakProps == null) + { + DebugMessage("c6c:: Soak Damage Hediff has no damage soak XML properties."); + continue; + } + if (soakProps.settings.NullOrEmpty()) + { + DebugMessage("c6c:: Soak Damage Hediff has no damage soak settings."); + + // Null, here, means "all damage types", so null should pass this check. + if (soakProps.damageType != null && soakProps.damageType != damageDef) + { + DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is not in soak settings."); + continue; + } + + if (soakProps.damageTypesToExclude != null && + soakProps.damageTypesToExclude.Contains(damageDef)) + { + DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is to be excluded from damage soak."); + continue; + } + + var dmgAmount = dinfo.Amount; + var soakedDamage = Mathf.Min(soakProps.damageToSoak, dmgAmount); + DebugMessage($"c6c:: Soaked: Min({soakProps.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); + dmgAmount -= soakedDamage; + DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); + totalSoakedDamage += soakedDamage; + DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); + dinfo.SetAmount(dmgAmount); + + if (dinfo.Amount > 0) + { + DebugMessage($"c6c:: More damage exists. Continuing check for soakers."); + continue; + } + + DamageSoakedMote(pawn, totalSoakedDamage); + DebugMessage($"c6c:: Damage absorbed."); + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); + return true; + } + else + { + DebugMessage("c6c:: Soak Damage Hediff has damage soak settings."); + foreach (var soakSettings in soakProps.settings) + { + DebugMessage($"c6c:: Hediff Damage: {damageDef}"); + if (soakSettings.damageType != null) + DebugMessage($"c6c:: Soak Type: {soakSettings.damageType}"); + else + DebugMessage($"c6c:: Soak Type: All"); + + //Null, here, means "all damage types" + //So Null should pass this check. + if (soakSettings.damageType != null && soakSettings.damageType != damageDef) + { + DebugMessage($"c6c:: No match. No soak."); + continue; + } + + // This variable tracks whether the damage should be excluded by a damageTypesToExclude + // rule for breaking out of a nested for loop without using goto + bool damageExcluded = false; + if (!soakSettings.damageTypesToExclude.NullOrEmpty()) + { + DebugMessage($"c6c:: Damage Soak Exlusions: "); + foreach (var exclusion in soakSettings.damageTypesToExclude) + { + DebugMessage($"c6c:: {exclusion}"); + if (exclusion == damageDef) + { + DebugMessage($"c6c:: Exclusion match. Damage soak aborted."); + damageExcluded = true; + break; + } + } + if (damageExcluded) + continue; + } + + var dmgAmount = dinfo.Amount; + var soakedDamage = Mathf.Min(soakSettings.damageToSoak, dmgAmount); + DebugMessage($"c6c:: Soaked: Min({soakSettings.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); + dmgAmount -= soakedDamage; + DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); + totalSoakedDamage += soakedDamage; + DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); + dinfo.SetAmount(dmgAmount); + + if (dinfo.Amount > 0) + { + DebugMessage($"c6c:: Unsoaked damage remains. Checking for more soakers."); + continue; + } + + DamageSoakedMote(pawn, totalSoakedDamage); + DebugMessage($"c6c:: Damage absorbed."); + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); + return true; + } + } + } + if (totalSoakedDamage > 0) + { + DamageSoakedMote(pawn, totalSoakedDamage); + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); + } + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); + return false; + } + + // ArmorUtility patches: + // These are a workaround for PreApplyDamage_PrePatch changes to the dinfo struct not being saved, due to + // Pawn_HealthTracker.PreApplyDamage dinfo parameter being passed by value (PreApplyDamage_PrePatch has it passed + // by reference, but this only affects the patch; Pawn_HealthTracker.PreApplyDamage still has it passed by value). + // Incidentally, these patches have another purpose: it allows other Pawn_HealthTracker.PreApplyDamage code like + // Apparel.CheckPreAbsorbDamage (like shield belts), various pawn-specific notifications affecting pawn behavior, + // and other mod's patches on the method to run, some of which could affect dinfo.Amount and absorbed flag. + // Indeed, the choice of prefix patching Pawn_HealthTracker.PreApplyDamage rather than a Pawn.PreApplyDamage prefix + // or a Pawn_HealthTracker.PreApplyDamage postfix is likely a compromise to allow as much change to dinfo as + // possible yet still apply damage soaks before shield belt absorption. + // Pawn_HealthTracker.PreApplyDamage notification specifics: if it runs (no ThingComp.PostPreApplyDamage sets + // absorbed flag), prisoner guilt, AI updates, and current danger are triggered. If no Apparel.CheckPreAbsorbDamage + // sets the absorbed flag, stun effects, pawn thought/memory, and tale recording are triggered. + // XXX: I do not think this patch is reliable because: + // 1) It's not guaranteed to run under certain conditions (e.g. if dinfo.IgnoreArmor) when it should. + // 2) dinfo.Amount can be divided into multiple DamageInfos under certain conditions (bomb/flame damage), + // which this doesn't take into account. + // 3) It assumes that all new damage amount since our PreApplyDamage_PrePatch ran should be damage soaked + // (as long as this patch runs, e.g. not absorbed, etc.), by setting the damage amount back to tempDamageAmount, + // the final damage amount recorded in PreApplyDamage_PrePatch, even if no damage soaks exist + // (see TODO in PreApplyDamage_PrePatch). + // 4) If damage amount decreased yet still non-zero since our PreApplyDamage_PrePatch ran, this patch will + // increase the damage amount back to tempDamageAmount, which is the total opposite of damage soaking. + // 5) The relationship of PreApplyDamage_PrePatch and this patch with respect to tempDamageAmount is fragile, + // especially since (1) and tempDamageAmount not always being set in PreApplyDamage_PrePatch. + // If another mod happens to use ArmorUtility without going through PreApplyDamage, this scheme will break. + // TODO: + // If we want to retain damage soaking before shield belt absorption: + // Instead of this patch, postfix patch (highest patch priority) Pawn.PreApplyDamage to update the original + // dinfo struct with any changes from PreApplyDamage_PrePatch. Make PreApplyDamage_PrePatch patch with lowest + // patch priority so that it runs right before Pawn_HealthTracker.PreApplyDamage. This should ensure that there + // no other changes to dinfo in between PreApplyDamage_PrePatch and the new Pawn.PreApplyDamage postfix patch + // that should've been tracked. tempDamageAmount is still needed to to transfer the damage amount info between + // these patches. + // If we're fine with damage soaks applying after shield belt absorption: + // Simplify into a single Pawn.PreApplyDamage postfix patch. + public static void Pre_ApplyArmor(ref float damAmount, Pawn pawn) + { + if (tempDamageAmount != null && damAmount > 0f) + { + var damageDiff = Mathf.Max(damAmount - tempDamageAmount.Value, 0f); + var newDamAmount = GenMath.RoundRandom(tempDamageAmount.Value); + DebugMessage($"c6c:: ApplyArmor prefix on {pawn}: tempDamageAmount {tempDamageAmount} => null, damAmount {damAmount} => {newDamAmount}"); + damAmount = newDamAmount; + tempDamageAmount = null; + if (damageDiff > 0f) + tempDamageAbsorbed = damageDiff; + } + } + + + + // XXX: Damage soak mote is already emitted in PreApplyDamage_ApplyDamageSoakers, so this leads to a misleading + // redundant soak mote. Worse, if the damage amount actually changes between PreApplyDamage_ApplyDamageSoakers + // and Pre_ApplyArmor, leading to a tempDamageAbsorbed that's different from PreApplyDamage_ApplyDamageSoakers's + // totalSoakedDamage, this is even more misleading. + public static void Post_GetPostArmorDamage(Pawn pawn) + { + if (tempDamageAbsorbed != null) + { + DebugMessage($"c6c:: GetPostArmorDamage postfix on {pawn}: tempDamageAbsorbed {tempDamageAbsorbed}"); + if (pawn.GetHediffComp() != null) + { + DamageSoakedMote(pawn, tempDamageAbsorbed.Value); + } + + tempDamageAbsorbed = null; + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs b/Source/AllModdingComponents/JecsTools/DamageSoak/HediffCompProperties_DamageSoak.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs rename to Source/AllModdingComponents/JecsTools/DamageSoak/HediffCompProperties_DamageSoak.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs b/Source/AllModdingComponents/JecsTools/DamageSoak/HediffComp_DamageSoak.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs rename to Source/AllModdingComponents/JecsTools/DamageSoak/HediffComp_DamageSoak.cs diff --git a/Source/AllModdingComponents/JecsTools/DamageDefCleave.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/DamageDefCleave.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/DamageDefCleave.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/DamageDefCleave.cs diff --git a/Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/DamageWorker_Cleave.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/DamageWorker_Cleave.cs diff --git a/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HarmonyPatches_ExtraMeleeDamages.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HarmonyPatches_ExtraMeleeDamages.cs new file mode 100644 index 00000000..42f4373b --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HarmonyPatches_ExtraMeleeDamages.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_ExtraMeleeDamages(Harmony harmony, Type type) + { + //Applies hediff-based extra damage to melee attacks. + harmony.Patch(typeof(Verb_MeleeAttackDamage).FindIteratorMethod("DamageInfosToApply"), + transpiler: new HarmonyMethod(type, nameof(Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler))); + } + + public static IEnumerable Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler( + IEnumerable instructions, MethodBase method, ILGenerator ilGen) + { + // Transforms following: + // if (tool != null && tool.extraMeleeDamages != null) + // { + // foreach (ExtraDamage extraMeleeDamage in tool.extraMeleeDamages) + // ... + // } + // into: + // var extraDamages = DamageInfosToApply_ExtraDamages(this); + // if (extraDamages != null) + // { + // foreach (ExtraDamage extraMeleeDamage in extraDamages) + // ... + // } + // Note: We're actually modifying an iterator method, which delegates all of its logic to a compiler-generated + // IEnumerator class with a convoluted FSM with the primary logic in the MoveNext method. + // The logic surrounding yields within loops is especially complex, so it's best to just modify what's being + // looped over; in this case, that's replacing the tool.extraMeleeDamages with our own enumerable + // (along with adjusting the null check conditionals). + + var fieldof_Verb_tool = AccessTools.Field(typeof(Verb), nameof(Verb.tool)); + var fieldof_Tool_extraMeleeDamages = AccessTools.Field(typeof(Tool), nameof(Tool.extraMeleeDamages)); + var methodof_List_GetEnumerator = + AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator)); + var instructionList = instructions.AsList(); + var locals = new Locals(method, ilGen); + + var extraDamagesVar = locals.DeclareLocal>(); + + var verbToolFieldNullCheckIndex = instructionList.FindSequenceIndex( + locals.IsLdloc, + instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), + instr => instr.IsBrfalse()); + var toolExtraDamagesIndex = instructionList.FindIndex(verbToolFieldNullCheckIndex + 3, // after above 3 predicates + instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages)); + var verbToolFieldIndex = verbToolFieldNullCheckIndex + 1; + instructionList.SafeReplaceRange(verbToolFieldIndex, toolExtraDamagesIndex + 1 - verbToolFieldIndex, new[] + { + new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(HarmonyPatches), nameof(DamageInfosToApply_ExtraDamages))), + extraDamagesVar.ToStloc(), + extraDamagesVar.ToLdloc(), + }); + + var verbToolExtraDamagesEnumeratorIndex = instructionList.FindSequenceIndex(verbToolFieldIndex, + locals.IsLdloc, + instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), + instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages), + instr => instr.Calls(methodof_List_GetEnumerator)); + instructionList.SafeReplaceRange(verbToolExtraDamagesEnumeratorIndex, 4, new[] // after above 4 predicates + { + extraDamagesVar.ToLdloc(), + new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator))), + }); + + return instructionList; + } + + [ThreadStatic] + private static Dictionary<(Tool, Pawn), List> extraDamageCache; + + // In the above transpiler, this replaces tool.extraMeleeDamages as the foreach loop enumeration target in + // Verb_MeleeAttackDamage.DamageInfosToApply. + // This must return a List rather than IEnumerator since Tool.extraMeleeDamages is a list. + // Specifically, the compiler-generated code calls List.GetEnumerator(), stores it in a + // List.Enumerator field in the internal iterator class (necessary for the FSM to work), then explicitly + // calls List.Enumerator methods/properties in multiple iterator class methods along with an initobj + // rather than ldnull for clearing it (since List.Enumerator is a struct). Essentially, it would be + // difficult to replace all this with IEnumerator versions in the above transpiler, we just have this + // method return the same type as Tool.extraMeleeDamages: List. + // If either tool.extraMeleeDamages and CasterPawn.GetHediffComp().Props.ExtraDamages + // are null, we can simply return the other, since both are lists. However, if both are non-null, we cannot simply + // return Enumerable.Concat of them both; we need to create a new list that contains both. Since list creation and + // getting the hediff extra damages are both relatively expensive operations, we utilize a cache. + // This cache is ThreadStatic to be optimized for single-threaded usage yet safe for multithreaded usage. + private static List DamageInfosToApply_ExtraDamages(Verb_MeleeAttackDamage verb) + { + extraDamageCache ??= new Dictionary<(Tool, Pawn), List>(); + var key = (verb.tool, verb.CasterPawn); + if (!extraDamageCache.TryGetValue(key, out var extraDamages)) + { + var toolExtraDamages = key.tool?.extraMeleeDamages; + var hediffExtraDamages = key.CasterPawn.GetHediffComp()?.Props?.ExtraDamages; + if (toolExtraDamages == null) + extraDamages = hediffExtraDamages; + else if (hediffExtraDamages == null) + extraDamages = toolExtraDamages; + else + { + extraDamages = new List(toolExtraDamages.Count + hediffExtraDamages.Count); + extraDamages.AddRange(toolExtraDamages); + extraDamages.AddRange(hediffExtraDamages); + } + DebugMessage($"DamageInfosToApply_ExtraDamages({verb}) => caching for {key}: {extraDamages.Join(ToString)}"); + extraDamageCache[key] = extraDamages; + } + return extraDamages; + } + + +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompDamageOverTime.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompDamageOverTime.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompProperties_DamageOverTime.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompProperties_DamageOverTime.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompProperties_ExtraMeleeDamages.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffCompProperties_ExtraMeleeDamages.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffComp_ExtraMeleeDamages.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/HediffComp_ExtraMeleeDamages.cs diff --git a/Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs b/Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/Hediff_InjuryCustomLabel.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs rename to Source/AllModdingComponents/JecsTools/ExtraMeleeDamages/Hediff_InjuryCustomLabel.cs diff --git a/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs b/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs deleted file mode 100644 index 08fa21cc..00000000 --- a/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs +++ /dev/null @@ -1,744 +0,0 @@ -//#define DEBUGLOG - -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Reflection.Emit; -using HarmonyLib; -using RimWorld; -using UnityEngine; -using Verse; - -namespace JecsTools -{ - [StaticConstructorOnStartup] - public static partial class HarmonyPatches - { - //For alternating fire on some weapons - public static Dictionary AlternatingFireTracker = new Dictionary(); - - public static float? tempDamageAmount = null; - public static float? tempDamageAbsorbed = null; - - static HarmonyPatches() - { - var harmony = new Harmony("jecstools.jecrell.main"); - var type = typeof(HarmonyPatches); - - //Debug Line - //------------ - //harmony.Patch(AccessTools.Method(typeof(PawnGroupKindWorker_Normal), nameof(PawnGroupKindWorker_Normal.MinPointsToGenerateAnything)), - // prefix: new HarmonyMethod(type, nameof(MinPointsTest))); - //------------ - - //Applies hediff-based extra damage to melee attacks. - harmony.Patch(typeof(Verb_MeleeAttackDamage).FindIteratorMethod("DamageInfosToApply"), - transpiler: new HarmonyMethod(type, nameof(Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler))); - - //Allow fortitude (HediffComp_DamageSoak) to soak damage - //Adds HediffCompProperties_DamageSoak checks to damage - harmony.Patch(AccessTools.Method(typeof(Pawn_HealthTracker), nameof(Pawn_HealthTracker.PreApplyDamage)), - prefix: new HarmonyMethod(type, nameof(PreApplyDamage_PrePatch))); - //Applies cached armor damage and absorption - harmony.Patch(AccessTools.Method(typeof(ArmorUtility), "ApplyArmor"), - prefix: new HarmonyMethod(type, nameof(Pre_ApplyArmor))); - //Applies damage soak motes - harmony.Patch(AccessTools.Method(typeof(ArmorUtility), nameof(ArmorUtility.GetPostArmorDamage)), - postfix: new HarmonyMethod(type, nameof(Post_GetPostArmorDamage))); - - //Applies knockback - harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.PreApplyDamage)), - prefix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Prefix)) { priority = Priority.High }, - postfix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Postfix)) { priority = Priority.Low }); - harmony.Patch(AccessTools.Method(typeof(Scenario), nameof(Scenario.TickScenario)), - postfix: new HarmonyMethod(type, nameof(Scenario_TickScenario_Postfix))); - - //Allows for adding additional HediffSets when characters spawn using the StartWithHediff class. - harmony.Patch(AccessTools.Method(typeof(PawnGenerator), nameof(PawnGenerator.GeneratePawn), - new[] { typeof(PawnGenerationRequest) }), - postfix: new HarmonyMethod(type, nameof(Post_GeneratePawn))); - - //Checks apparel that uses the ApparelExtension - harmony.Patch(AccessTools.Method(typeof(ApparelUtility), nameof(ApparelUtility.CanWearTogether)), - postfix: new HarmonyMethod(type, nameof(Post_CanWearTogether))); - - //Handles cases where gendered apparel swaps out for individual genders. - harmony.Patch(AccessTools.Method(typeof(PawnApparelGenerator), nameof(PawnApparelGenerator.GenerateStartingApparelFor)), - postfix: new HarmonyMethod(type, nameof(GenerateStartingApparelFor_PostFix))); - - //BuildingExtension prevents some things from wiping other things when spawned/constructing/blueprinted. - harmony.Patch(AccessTools.Method(typeof(GenSpawn), nameof(GenSpawn.SpawningWipes)), - postfix: new HarmonyMethod(type, nameof(SpawningWipes_PostFix))); - harmony.Patch(AccessTools.Method(typeof(GenConstruct), nameof(GenConstruct.CanPlaceBlueprintOver)), - postfix: new HarmonyMethod(type, nameof(CanPlaceBlueprintOver_PostFix))); - - harmony.Patch(AccessTools.Method(typeof(Projectile), "CanHit"), - postfix: new HarmonyMethod(type, nameof(CanHit_PostFix))); - harmony.Patch(AccessTools.Method(typeof(Verb), "CanHitCellFromCellIgnoringRange"), - prefix: new HarmonyMethod(type, nameof(CanHitCellFromCellIgnoringRange_Prefix))); - - //Improve DamageInfo.ToString for debugging purposes. - harmony.Patch(AccessTools.Method(typeof(DamageInfo), nameof(DamageInfo.ToString)), - postfix: new HarmonyMethod(type, nameof(DamageInfo_ToString_Postfix))); - - //optionally use "CutoutComplex" shader for apparel that wants it - //harmony.Patch(AccessTools.Method(typeof(ApparelGraphicRecordGetter), nameof(ApparelGraphicRecordGetter.TryGetGraphicApparel)), - // transpiler: new HarmonyMethod(type, nameof(CutOutComplexApparel_Transpiler))); - } - - [Conditional("DEBUGLOG")] - private static void DebugMessage(string s) - { - Log.Message(s); - } - - //Added B19, Oct 2019 - //ProjectileExtension check - //Allows a bullet to pass through walls when fired. - public static bool CanHitCellFromCellIgnoringRange_Prefix(Verb __instance, ref bool __result) - { - if (__instance.EquipmentCompSource?.PrimaryVerb?.verbProps?.defaultProjectile?.GetProjectileExtension() is ProjectileExtension ext) - { - if (ext.passesWalls) - { - // TODO: While this does bypass the line-of-sight checks (and should it really bypass all LOS checks?), - // this also bypasses non-LOS checks, which doesn't look right. - __result = true; - } - return false; - } - return true; - } - - //Added B19, Oct 2019 - //ProjectileExtension check - //Ignores all structures as part of objects that disallow being fired through. - public static void CanHit_PostFix(Projectile __instance, Thing thing, ref bool __result) - { - // TODO: This patch looks pointless since it can only change __result from false to ... false. - if (__result == false && __instance.def?.GetProjectileExtension() is ProjectileExtension ext) - { - if (ext.passesWalls) - { - //Mods will often have their own walls, so we cannot do a def check for ThingDefOf.Wall - //Most "walls" should either be in the structure category or be able to hold walls. - // TODO: In RW 1.3+, it seems like BuildingProperties.isPlaceOverableWall indicates whether something is a "wall", - // but it may be better to just look at ThingDef.Fillage/fillPercent instead, - // or maybe use PlaceWorker_OnTopOfWalls's heuristic of checking whether the defName contains "Wall"? - if (thing?.def is ThingDef def && (def.designationCategory == DesignationCategoryDefOf.Structure || def.holdsRoof)) - { - __result = false; - return; - } - } - } - } - - public static void SpawningWipes_PostFix(BuildableDef newEntDef, BuildableDef oldEntDef, ref bool __result) - { - // If SpawningWipes is already returning true, don't need to do anything. - if (__result == false && newEntDef is ThingDef newDef && oldEntDef is ThingDef oldDef) - { - if (HasSharedWipeCategory(newDef, oldDef)) - __result = true; - } - } - - public static void CanPlaceBlueprintOver_PostFix(BuildableDef newDef, ThingDef oldDef, ref bool __result) - { - // If CanPlaceBlueprintOver is already returning false, don't need to do anything. - if (__result == true && newDef is ThingDef thingDef) - { - if (HasSharedWipeCategory(thingDef, oldDef)) - __result = false; - } - } - - private static bool HasSharedWipeCategory(ThingDef newDef, ThingDef oldDef) - { - static HashSet GetWipeCategories(ThingDef thingDef) - { - var buildingExtension = GenConstruct.BuiltDefOf(thingDef)?.GetBuildingExtension(); - if (buildingExtension == null) - return null; - var wipeCategorySet = buildingExtension.WipeCategories; - return wipeCategorySet == null || wipeCategorySet.Count == 0 ? null : wipeCategorySet; - } - - var wipeCategoriesA = GetWipeCategories(newDef); - DebugMessage($"{newDef} wipeCategoriesA: {wipeCategoriesA.ToStringSafeEnumerable()}"); - var wipeCategoriesB = GetWipeCategories(oldDef); - DebugMessage($"{oldDef} wipeCategoriesB: {wipeCategoriesB.ToStringSafeEnumerable()}"); - if (wipeCategoriesB == null && wipeCategoriesA == null) - { - DebugMessage("both wipeCategories null => false"); - return false; - } - else if (wipeCategoriesA != null && wipeCategoriesB == null) - { - DebugMessage("wipeCategoriesB null => false"); - return false; - } - else if (wipeCategoriesB != null && wipeCategoriesA == null) - { - DebugMessage("wipeCategoriesA null => false"); - return false; - } - else - { - foreach (var strB in wipeCategoriesB) - { - if (wipeCategoriesA.Contains(strB)) - { - DebugMessage($"found shared wipeCategories ({strB}) => true"); - return true; - } - } - DebugMessage("no shared wipeCategories => false"); - return false; - } - } - - //public static void MinPointsTest(PawnGroupMaker groupMaker) - //{ - // if (!(groupMaker?.options?.Count > 0)) - // { - // Log.Message("No options available."); - // return; - // } - // foreach (var x in groupMaker.options) - // { - // Log.Message(x.kind.defName + " " + x.kind.isFighter.ToString() + " " + x.Cost); - // } - //} - - //PawnApparelGenerator - public static void GenerateStartingApparelFor_PostFix(Pawn pawn) - { - var allWornApparel = pawn.apparel?.WornApparel; - if (allWornApparel.NullOrEmpty()) - return; - List<(Apparel, Apparel)> swapEntries = null; - foreach (var wornApparel in allWornApparel) - { - if (wornApparel.def?.GetApparelExtension()?.swapCondition is SwapCondition sc && - sc.swapWhenGender is Gender gen && - gen != Gender.None && gen == pawn.gender) - { - var swapApparel = (Apparel)ThingMaker.MakeThing(sc.swapTo, wornApparel.Stuff); - // Avoid modifying WornApparel during its enumeration by doing the swaps afterwards. - swapEntries ??= new List<(Apparel worn, Apparel swap)>(); - swapEntries.Add((wornApparel, swapApparel)); - } - } - if (swapEntries != null) - { - foreach (var (wornApparel, swapApparel) in swapEntries) - { - PawnGenerator.PostProcessGeneratedGear(swapApparel, pawn); - if (ApparelUtility.HasPartsToWear(pawn, swapApparel.def)) - { - pawn.apparel.Wear(swapApparel, false); - DebugMessage($"apparel generation for {pawn}: swapped from {wornApparel} to {swapApparel}"); - } - wornApparel.Destroy(); - DebugMessage($"apparel generation for {pawn}: destroyed old {wornApparel}"); - } - } - } - - /// - /// Using the new ApparelExtension, we can have a string based apparel check. - /// - public static void Post_CanWearTogether(ThingDef A, ThingDef B, BodyDef body, ref bool __result) - { - static HashSet GetCoverage(ThingDef thingDef) - { - var coverage = thingDef.GetApparelExtension()?.Coverage; - return coverage == null || coverage.Count == 0 ? null : coverage; - } - - if (A == null || B == null || body == null || __result == true) - return; - var coverageA = GetCoverage(A); - var coverageB = GetCoverage(B); - if (coverageA != null && coverageB != null) - { - foreach (var coverageItem in coverageB) - { - if (coverageA.Contains(coverageItem)) - { - __result = false; - break; - } - } - } - else if ((coverageA != null && coverageB == null) || (coverageA == null && coverageB != null)) - { - __result = true; - } - } - - public static void Post_GeneratePawn(Pawn __result) - { - var hediffGiverSets = __result?.def?.race?.hediffGiverSets; - if (hediffGiverSets != null) - { - foreach (var hediffGiverSet in hediffGiverSets) - { - foreach (var hediffGiver in hediffGiverSet.hediffGivers) - { - if (hediffGiver is HediffGiver_StartWithHediff hediffGiverStartWithHediff) - { - hediffGiverStartWithHediff.GiveHediff(__result); - // TODO: Should this really only use the first found HediffGiver_StartWithHediff? - return; - } - } - } - } - } - - public static IEnumerable Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler( - IEnumerable instructions, MethodBase method, ILGenerator ilGen) - { - // Transforms following: - // if (tool != null && tool.extraMeleeDamages != null) - // { - // foreach (ExtraDamage extraMeleeDamage in tool.extraMeleeDamages) - // ... - // } - // into: - // var extraDamages = DamageInfosToApply_ExtraDamages(this); - // if (extraDamages != null) - // { - // foreach (ExtraDamage extraMeleeDamage in extraDamages) - // ... - // } - // Note: We're actually modifying an iterator method, which delegates all of its logic to a compiler-generated - // IEnumerator class with a convoluted FSM with the primary logic in the MoveNext method. - // The logic surrounding yields within loops is especially complex, so it's best to just modify what's being - // looped over; in this case, that's replacing the tool.extraMeleeDamages with our own enumerable - // (along with adjusting the null check conditionals). - - var fieldof_Verb_tool = AccessTools.Field(typeof(Verb), nameof(Verb.tool)); - var fieldof_Tool_extraMeleeDamages = AccessTools.Field(typeof(Tool), nameof(Tool.extraMeleeDamages)); - var methodof_List_GetEnumerator = - AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator)); - var instructionList = instructions.AsList(); - var locals = new Locals(method, ilGen); - - var extraDamagesVar = locals.DeclareLocal>(); - - var verbToolFieldNullCheckIndex = instructionList.FindSequenceIndex( - locals.IsLdloc, - instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), - instr => instr.IsBrfalse()); - var toolExtraDamagesIndex = instructionList.FindIndex(verbToolFieldNullCheckIndex + 3, // after above 3 predicates - instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages)); - var verbToolFieldIndex = verbToolFieldNullCheckIndex + 1; - instructionList.SafeReplaceRange(verbToolFieldIndex, toolExtraDamagesIndex + 1 - verbToolFieldIndex, new[] - { - new CodeInstruction(OpCodes.Call, - AccessTools.Method(typeof(HarmonyPatches), nameof(DamageInfosToApply_ExtraDamages))), - extraDamagesVar.ToStloc(), - extraDamagesVar.ToLdloc(), - }); - - var verbToolExtraDamagesEnumeratorIndex = instructionList.FindSequenceIndex(verbToolFieldIndex, - locals.IsLdloc, - instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), - instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages), - instr => instr.Calls(methodof_List_GetEnumerator)); - instructionList.SafeReplaceRange(verbToolExtraDamagesEnumeratorIndex, 4, new[] // after above 4 predicates - { - extraDamagesVar.ToLdloc(), - new CodeInstruction(OpCodes.Call, - AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator))), - }); - - return instructionList; - } - - [ThreadStatic] - private static Dictionary<(Tool, Pawn), List> extraDamageCache; - - // In the above transpiler, this replaces tool.extraMeleeDamages as the foreach loop enumeration target in - // Verb_MeleeAttackDamage.DamageInfosToApply. - // This must return a List rather than IEnumerator since Tool.extraMeleeDamages is a list. - // Specifically, the compiler-generated code calls List.GetEnumerator(), stores it in a - // List.Enumerator field in the internal iterator class (necessary for the FSM to work), then explicitly - // calls List.Enumerator methods/properties in multiple iterator class methods along with an initobj - // rather than ldnull for clearing it (since List.Enumerator is a struct). Essentially, it would be - // difficult to replace all this with IEnumerator versions in the above transpiler, we just have this - // method return the same type as Tool.extraMeleeDamages: List. - // If either tool.extraMeleeDamages and CasterPawn.GetHediffComp().Props.ExtraDamages - // are null, we can simply return the other, since both are lists. However, if both are non-null, we cannot simply - // return Enumerable.Concat of them both; we need to create a new list that contains both. Since list creation and - // getting the hediff extra damages are both relatively expensive operations, we utilize a cache. - // This cache is ThreadStatic to be optimized for single-threaded usage yet safe for multithreaded usage. - private static List DamageInfosToApply_ExtraDamages(Verb_MeleeAttackDamage verb) - { - extraDamageCache ??= new Dictionary<(Tool, Pawn), List>(); - var key = (verb.tool, verb.CasterPawn); - if (!extraDamageCache.TryGetValue(key, out var extraDamages)) - { - var toolExtraDamages = key.tool?.extraMeleeDamages; - var hediffExtraDamages = key.CasterPawn.GetHediffComp()?.Props?.ExtraDamages; - if (toolExtraDamages == null) - extraDamages = hediffExtraDamages; - else if (hediffExtraDamages == null) - extraDamages = toolExtraDamages; - else - { - extraDamages = new List(toolExtraDamages.Count + hediffExtraDamages.Count); - extraDamages.AddRange(toolExtraDamages); - extraDamages.AddRange(hediffExtraDamages); - } - DebugMessage($"DamageInfosToApply_ExtraDamages({verb}) => caching for {key}: {extraDamages.Join(ToString)}"); - extraDamageCache[key] = extraDamages; - } - return extraDamages; - } - - private static string ToString(ExtraDamage ed) - { - return $"(def={ed.def}, amount={ed.amount}, armorPenetration={ed.armorPenetration}, chance={ed.chance})"; - } - - // ArmorUtility patches: - // These are a workaround for PreApplyDamage_PrePatch changes to the dinfo struct not being saved, due to - // Pawn_HealthTracker.PreApplyDamage dinfo parameter being passed by value (PreApplyDamage_PrePatch has it passed - // by reference, but this only affects the patch; Pawn_HealthTracker.PreApplyDamage still has it passed by value). - // Incidentally, these patches have another purpose: it allows other Pawn_HealthTracker.PreApplyDamage code like - // Apparel.CheckPreAbsorbDamage (like shield belts), various pawn-specific notifications affecting pawn behavior, - // and other mod's patches on the method to run, some of which could affect dinfo.Amount and absorbed flag. - // Indeed, the choice of prefix patching Pawn_HealthTracker.PreApplyDamage rather than a Pawn.PreApplyDamage prefix - // or a Pawn_HealthTracker.PreApplyDamage postfix is likely a compromise to allow as much change to dinfo as - // possible yet still apply damage soaks before shield belt absorption. - // Pawn_HealthTracker.PreApplyDamage notification specifics: if it runs (no ThingComp.PostPreApplyDamage sets - // absorbed flag), prisoner guilt, AI updates, and current danger are triggered. If no Apparel.CheckPreAbsorbDamage - // sets the absorbed flag, stun effects, pawn thought/memory, and tale recording are triggered. - // XXX: I do not think this patch is reliable because: - // 1) It's not guaranteed to run under certain conditions (e.g. if dinfo.IgnoreArmor) when it should. - // 2) dinfo.Amount can be divided into multiple DamageInfos under certain conditions (bomb/flame damage), - // which this doesn't take into account. - // 3) It assumes that all new damage amount since our PreApplyDamage_PrePatch ran should be damage soaked - // (as long as this patch runs, e.g. not absorbed, etc.), by setting the damage amount back to tempDamageAmount, - // the final damage amount recorded in PreApplyDamage_PrePatch, even if no damage soaks exist - // (see TODO in PreApplyDamage_PrePatch). - // 4) If damage amount decreased yet still non-zero since our PreApplyDamage_PrePatch ran, this patch will - // increase the damage amount back to tempDamageAmount, which is the total opposite of damage soaking. - // 5) The relationship of PreApplyDamage_PrePatch and this patch with respect to tempDamageAmount is fragile, - // especially since (1) and tempDamageAmount not always being set in PreApplyDamage_PrePatch. - // If another mod happens to use ArmorUtility without going through PreApplyDamage, this scheme will break. - // TODO: - // If we want to retain damage soaking before shield belt absorption: - // Instead of this patch, postfix patch (highest patch priority) Pawn.PreApplyDamage to update the original - // dinfo struct with any changes from PreApplyDamage_PrePatch. Make PreApplyDamage_PrePatch patch with lowest - // patch priority so that it runs right before Pawn_HealthTracker.PreApplyDamage. This should ensure that there - // no other changes to dinfo in between PreApplyDamage_PrePatch and the new Pawn.PreApplyDamage postfix patch - // that should've been tracked. tempDamageAmount is still needed to to transfer the damage amount info between - // these patches. - // If we're fine with damage soaks applying after shield belt absorption: - // Simplify into a single Pawn.PreApplyDamage postfix patch. - public static void Pre_ApplyArmor(ref float damAmount, Pawn pawn) - { - if (tempDamageAmount != null && damAmount > 0f) - { - var damageDiff = Mathf.Max(damAmount - tempDamageAmount.Value, 0f); - var newDamAmount = GenMath.RoundRandom(tempDamageAmount.Value); - DebugMessage($"c6c:: ApplyArmor prefix on {pawn}: tempDamageAmount {tempDamageAmount} => null, damAmount {damAmount} => {newDamAmount}"); - damAmount = newDamAmount; - tempDamageAmount = null; - if (damageDiff > 0f) - tempDamageAbsorbed = damageDiff; - } - } - - // XXX: Damage soak mote is already emitted in PreApplyDamage_ApplyDamageSoakers, so this leads to a misleading - // redundant soak mote. Worse, if the damage amount actually changes between PreApplyDamage_ApplyDamageSoakers - // and Pre_ApplyArmor, leading to a tempDamageAbsorbed that's different from PreApplyDamage_ApplyDamageSoakers's - // totalSoakedDamage, this is even more misleading. - public static void Post_GetPostArmorDamage(Pawn pawn) - { - if (tempDamageAbsorbed != null) - { - DebugMessage($"c6c:: GetPostArmorDamage postfix on {pawn}: tempDamageAbsorbed {tempDamageAbsorbed}"); - if (pawn.GetHediffComp() != null) - { - DamageSoakedMote(pawn, tempDamageAbsorbed.Value); - } - - tempDamageAbsorbed = null; - } - } - - public static bool PreApplyDamage_PrePatch(Pawn ___pawn, ref DamageInfo dinfo, out bool absorbed) - { - DebugMessage($"c6c:: === Enter Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); - if (___pawn != null) - { - DebugMessage("c6c:: Pawn exists."); - var hediffSet = ___pawn.health.hediffSet; - if (hediffSet.hediffs.Count > 0) - { - DebugMessage("c6c:: Pawn has hediffs."); - // See above ArmorUtility comments. - if (PreApplyDamage_ApplyDamageSoakers(ref dinfo, hediffSet, ___pawn)) - { - DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); - absorbed = true; - return false; - } - } - } - - // TODO: tempDamageAmount shouldn't be set if there are no damage soaks. - tempDamageAmount = dinfo.Amount; - DebugMessage($"c6c:: tempDamageAmount <= {tempDamageAmount}"); - absorbed = false; - DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); - return true; - } - - // Stores original dinfo.Amount in __state, that below Pawn_PreApplyDamage_Postfix can access. - public static void Pawn_PreApplyDamage_Prefix(ref DamageInfo dinfo, ref float __state) - { - __state = dinfo.Amount; - } - - // This should happen after all modifications to dinfo and any possible setting of absorbed flag, - // i.e. after all ThingComp.PostPreApplyDamage and Apparel.CheckPreAbsorbDamage (shield belts). - public static void Pawn_PreApplyDamage_Postfix(Pawn __instance, ref DamageInfo dinfo, ref bool absorbed, - float __state) - { - if (dinfo.Weapon is ThingDef weaponDef && !weaponDef.IsRangedWeapon && - dinfo.Instigator is Pawn instigator) - { - DebugMessage($"c6c:: Instigator using non-ranged weapon: {dinfo}"); - var hediffCompKnockback = instigator.GetHediffComp(); - if (hediffCompKnockback != null) - { - // Hack to prevent multiple knockbacks occurring due to multiple damage infos (e.g. extra damage) for same instigator+target: - // prevent knockback if tick hasn't passed since last knockback for instigator+target pair. - // This requires a (instigator+target)=>tick cache, which is cleared after every tick via Scenario_TickScenario_Postfix. - var pair = new Pair(instigator, __instance); - var ticks = Find.TickManager.TicksGame; - if (knockbackLastTicks.TryGetValue(pair, out var lastTicks) && lastTicks == ticks) - return; - knockbackLastTicks[pair] = ticks; - hediffCompKnockback.ApplyKnockback(__instance, - damageAbsorbedPercent: absorbed ? 1f : 1f - Mathf.Clamp01(dinfo.Amount / __state)); - } - } - } - - public static void Scenario_TickScenario_Postfix() - { - knockbackLastTicks.Clear(); - } - - private static readonly ConcurrentDictionary, int> knockbackLastTicks = - new ConcurrentDictionary, int>(); - - private static bool PreApplyDamage_ApplyDamageSoakers(ref DamageInfo dinfo, HediffSet hediffSet, Pawn pawn) - { - // Multiple damage soak hediff comps stack. - DebugMessage($"c6c:: --- Enter PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); - var damageDef = dinfo.Def; - var totalSoakedDamage = 0f; - foreach (var hediffComp in hediffSet.GetAllComps()) - { - if (!(hediffComp is HediffComp_DamageSoak damageSoakComp)) - continue; - DebugMessage("c6c:: Soak Damage Hediff checked."); - - var soakProps = damageSoakComp.Props; - if (soakProps == null) - { - DebugMessage("c6c:: Soak Damage Hediff has no damage soak XML properties."); - continue; - } - if (soakProps.settings.NullOrEmpty()) - { - DebugMessage("c6c:: Soak Damage Hediff has no damage soak settings."); - - // Null, here, means "all damage types", so null should pass this check. - if (soakProps.damageType != null && soakProps.damageType != damageDef) - { - DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is not in soak settings."); - continue; - } - - if (soakProps.damageTypesToExclude != null && - soakProps.damageTypesToExclude.Contains(damageDef)) - { - DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is to be excluded from damage soak."); - continue; - } - - var dmgAmount = dinfo.Amount; - var soakedDamage = Mathf.Min(soakProps.damageToSoak, dmgAmount); - DebugMessage($"c6c:: Soaked: Min({soakProps.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); - dmgAmount -= soakedDamage; - DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); - totalSoakedDamage += soakedDamage; - DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); - dinfo.SetAmount(dmgAmount); - - if (dinfo.Amount > 0) - { - DebugMessage($"c6c:: More damage exists. Continuing check for soakers."); - continue; - } - - DamageSoakedMote(pawn, totalSoakedDamage); - DebugMessage($"c6c:: Damage absorbed."); - DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); - return true; - } - else - { - DebugMessage("c6c:: Soak Damage Hediff has damage soak settings."); - foreach (var soakSettings in soakProps.settings) - { - DebugMessage($"c6c:: Hediff Damage: {damageDef}"); - if (soakSettings.damageType != null) - DebugMessage($"c6c:: Soak Type: {soakSettings.damageType}"); - else - DebugMessage($"c6c:: Soak Type: All"); - - //Null, here, means "all damage types" - //So Null should pass this check. - if (soakSettings.damageType != null && soakSettings.damageType != damageDef) - { - DebugMessage($"c6c:: No match. No soak."); - continue; - } - - // This variable tracks whether the damage should be excluded by a damageTypesToExclude - // rule for breaking out of a nested for loop without using goto - bool damageExcluded = false; - if (!soakSettings.damageTypesToExclude.NullOrEmpty()) - { - DebugMessage($"c6c:: Damage Soak Exlusions: "); - foreach (var exclusion in soakSettings.damageTypesToExclude) - { - DebugMessage($"c6c:: {exclusion}"); - if (exclusion == damageDef) - { - DebugMessage($"c6c:: Exclusion match. Damage soak aborted."); - damageExcluded = true; - break; - } - } - if (damageExcluded) - continue; - } - - var dmgAmount = dinfo.Amount; - var soakedDamage = Mathf.Min(soakSettings.damageToSoak, dmgAmount); - DebugMessage($"c6c:: Soaked: Min({soakSettings.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); - dmgAmount -= soakedDamage; - DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); - totalSoakedDamage += soakedDamage; - DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); - dinfo.SetAmount(dmgAmount); - - if (dinfo.Amount > 0) - { - DebugMessage($"c6c:: Unsoaked damage remains. Checking for more soakers."); - continue; - } - - DamageSoakedMote(pawn, totalSoakedDamage); - DebugMessage($"c6c:: Damage absorbed."); - DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); - return true; - } - } - } - if (totalSoakedDamage > 0) - { - DamageSoakedMote(pawn, totalSoakedDamage); - DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); - } - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); - return false; - } - - private static void DamageSoakedMote(Pawn pawn, float soakedDamage) - { - if (soakedDamage > 0f && pawn != null && pawn.Spawned && pawn.MapHeld != null && - pawn.DrawPos is Vector3 drawVecDos && drawVecDos.InBounds(pawn.MapHeld)) - { - // To avoid any rounding bias, use RoundRandom for converting int to float. - var roundedSoakedDamage = GenMath.RoundRandom(soakedDamage); - DebugMessage($"c6c:: DamageSoakedMote for {pawn}: {soakedDamage} rounded to {roundedSoakedDamage}"); - MoteMaker.ThrowText(drawVecDos, pawn.MapHeld, "JT_DamageSoaked".Translate(roundedSoakedDamage)); - } - } - - // Not sure if another mod is using this, so obsoleting it rather than deleting it. - [Obsolete] - public static Vector3 PushResult(Thing Caster, Thing thingToPush, int pushDist, out bool collision) - { - return HediffComp_Knockback.PushResult(Caster, thingToPush, pushDist, out var _, out collision); - } - - // Not sure if another mod is using this, so obsoleting it rather than deleting it. - [Obsolete] - public static void PushEffect(Thing Caster, Thing target, int distance, bool damageOnCollision = false) - { - HediffComp_Knockback.PushEffect(Caster, target, damageAbsorbedPercent: 0f, new HediffCompProperties_Knockback - { - knockDistance = new FloatRange(distance, distance), - knockDistanceAbsorbedPercentCurve = HediffComp_Knockback.AlwaysOneCurve, - knockDistanceMassCurve = HediffComp_Knockback.AlwaysOneCurve, - knockImpactDamage = damageOnCollision ? new FloatRange(8f, 10f) : default, - knockImpactDamageDistancePercentCurve = HediffComp_Knockback.AlwaysOneCurve, - knockImpactDamageType = DamageDefOf.Blunt, - }); - } - - public static string DamageInfo_ToString_Postfix(string result, ref DamageInfo __instance) - { - var insertIndex = result.IndexOf(", angle="); - return result.Insert(insertIndex, $", hitPart={__instance.HitPart.ToStringSafe()}, " + - $"weapon={__instance.Weapon.ToStringSafe()}, armorPenetration={__instance.ArmorPenetrationInt}"); - } - - //added 2018/12/13 - Mehni. - //Uses CutoutComplex shader for apparel that wants it. - //private static IEnumerable CutOutComplexApparel_Transpiler(IEnumerable instructions) - //{ - // MethodInfo shader = AccessTools.Method(typeof(HarmonyPatches), nameof(HarmonyPatches.Shader)); - // FieldInfo cutOut = AccessTools.Field(typeof(ShaderDatabase), nameof(ShaderDatabase.Cutout)); - - // foreach (CodeInstruction codeInstruction in instructions) - // { - // if (codeInstruction.opcode == OpCodes.Ldsfld && codeInstruction.operand == cutOut) - // { - // yield return new CodeInstruction(OpCodes.Ldarg_0); //apparel - // yield return new CodeInstruction(OpCodes.Call, shader); //return shader type - // continue; //skip instruction. - // } - // yield return codeInstruction; - // } - //} - - //private static Shader Shader(Apparel apparel) - //{ - // if (apparel.def.graphicData.shaderType.Shader == ShaderDatabase.CutoutComplex) - // return ShaderDatabase.CutoutComplex; - - // return ShaderDatabase.Cutout; - //} - } -} diff --git a/Source/AllModdingComponents/JecsTools/Knockback/HarmonyPatches_Knockback.cs b/Source/AllModdingComponents/JecsTools/Knockback/HarmonyPatches_Knockback.cs new file mode 100644 index 00000000..5a62996e --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/Knockback/HarmonyPatches_Knockback.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Concurrent; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_Knockback(Harmony harmony, Type type) + { + //Applies knockback + harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.PreApplyDamage)), + prefix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Prefix)) { priority = Priority.High }, + postfix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Postfix)) { priority = Priority.Low }); + harmony.Patch(AccessTools.Method(typeof(Scenario), nameof(Scenario.TickScenario)), + postfix: new HarmonyMethod(type, nameof(Scenario_TickScenario_Postfix))); + } + + + private static readonly ConcurrentDictionary, int> knockbackLastTicks = + new ConcurrentDictionary, int>(); + + + // Stores original dinfo.Amount in __state, that below Pawn_PreApplyDamage_Postfix can access. + public static void Pawn_PreApplyDamage_Prefix(ref DamageInfo dinfo, ref float __state) + { + __state = dinfo.Amount; + } + + + // This should happen after all modifications to dinfo and any possible setting of absorbed flag, + // i.e. after all ThingComp.PostPreApplyDamage and Apparel.CheckPreAbsorbDamage (shield belts). + public static void Pawn_PreApplyDamage_Postfix(Pawn __instance, ref DamageInfo dinfo, ref bool absorbed, + float __state) + { + if (dinfo.Weapon is ThingDef weaponDef && !weaponDef.IsRangedWeapon && + dinfo.Instigator is Pawn instigator) + { + DebugMessage($"c6c:: Instigator using non-ranged weapon: {dinfo}"); + var hediffCompKnockback = instigator.GetHediffComp(); + if (hediffCompKnockback != null) + { + // Hack to prevent multiple knockbacks occurring due to multiple damage infos (e.g. extra damage) for same instigator+target: + // prevent knockback if tick hasn't passed since last knockback for instigator+target pair. + // This requires a (instigator+target)=>tick cache, which is cleared after every tick via Scenario_TickScenario_Postfix. + var pair = new Pair(instigator, __instance); + var ticks = Find.TickManager.TicksGame; + if (knockbackLastTicks.TryGetValue(pair, out var lastTicks) && lastTicks == ticks) + return; + knockbackLastTicks[pair] = ticks; + hediffCompKnockback.ApplyKnockback(__instance, + damageAbsorbedPercent: absorbed ? 1f : 1f - Mathf.Clamp01(dinfo.Amount / __state)); + } + } + } + + public static void Scenario_TickScenario_Postfix() + { + knockbackLastTicks.Clear(); + } + +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs b/Source/AllModdingComponents/JecsTools/Knockback/HediffCompProperties_Knockback.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs rename to Source/AllModdingComponents/JecsTools/Knockback/HediffCompProperties_Knockback.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs b/Source/AllModdingComponents/JecsTools/Knockback/HediffComp_Knockback.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs rename to Source/AllModdingComponents/JecsTools/Knockback/HediffComp_Knockback.cs diff --git a/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches.cs b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches.cs new file mode 100644 index 00000000..e865d33a --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches.cs @@ -0,0 +1,52 @@ +//#define DEBUGLOG + +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools +{ + [StaticConstructorOnStartup] + public static partial class HarmonyPatches + { + //For alternating fire on some weapons + public static Dictionary AlternatingFireTracker = new Dictionary(); + + static HarmonyPatches() + { + var harmony = new Harmony("jecstools.jecrell.main"); + var type = typeof(HarmonyPatches); + + HarmonyPatches_ApparelExtension(harmony, type); + HarmonyPatches_BuildingExtension(harmony, type); + HarmonyPatches_DamageSoak(harmony, type); + HarmonyPatches_Debug(harmony, type); + HarmonyPatches_ExtraMeleeDamages(harmony, type); + HarmonyPatches_Knockback(harmony, type); + HarmonyPatches_StartWithHediff(harmony, type); + HarmonyPatches_StartWithGenes(harmony, type); + } + + [Conditional("DEBUGLOG")] + private static void DebugMessage(string s) + { + Log.Message(s); + } + + private static string ToString(ExtraDamage ed) + { + return $"(def={ed.def}, amount={ed.amount}, armorPenetration={ed.armorPenetration}, chance={ed.chance})"; + } + + + + } +} diff --git a/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Debug.cs b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Debug.cs new file mode 100644 index 00000000..5301a3bc --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Debug.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_Debug(Harmony harmony, Type type) + { + //Improve DamageInfo.ToString for debugging purposes. + harmony.Patch(AccessTools.Method(typeof(DamageInfo), nameof(DamageInfo.ToString)), + postfix: new HarmonyMethod(type, nameof(DamageInfo_ToString_Postfix))); + } + + public static string DamageInfo_ToString_Postfix(string result, ref DamageInfo __instance) + { + var insertIndex = result.IndexOf(", angle="); + return result.Insert(insertIndex, $", hitPart={__instance.HitPart.ToStringSafe()}, " + + $"weapon={__instance.Weapon.ToStringSafe()}, armorPenetration={__instance.ArmorPenetrationInt}"); + } + +} diff --git a/Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_GUI.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs rename to Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_GUI.cs diff --git a/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Obsolete.cs b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Obsolete.cs new file mode 100644 index 00000000..d1a25db5 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/OtherHarmonyPatches/HarmonyPatches_Obsolete.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + // Not sure if another mod is using this, so obsoleting it rather than deleting it. + [Obsolete] + public static Vector3 PushResult(Thing Caster, Thing thingToPush, int pushDist, out bool collision) + { + return HediffComp_Knockback.PushResult(Caster, thingToPush, pushDist, out var _, out collision); + } + + // Not sure if another mod is using this, so obsoleting it rather than deleting it. + [Obsolete] + public static void PushEffect(Thing Caster, Thing target, int distance, bool damageOnCollision = false) + { + HediffComp_Knockback.PushEffect(Caster, target, damageAbsorbedPercent: 0f, new HediffCompProperties_Knockback + { + knockDistance = new FloatRange(distance, distance), + knockDistanceAbsorbedPercentCurve = HediffComp_Knockback.AlwaysOneCurve, + knockDistanceMassCurve = HediffComp_Knockback.AlwaysOneCurve, + knockImpactDamage = damageOnCollision ? new FloatRange(8f, 10f) : default, + knockImpactDamageDistancePercentCurve = HediffComp_Knockback.AlwaysOneCurve, + knockImpactDamageType = DamageDefOf.Blunt, + }); + } +} diff --git a/Source/AllModdingComponents/JecsTools/ProjectileExtension.cs b/Source/AllModdingComponents/JecsTools/ProjectileExtension/ProjectileExtension.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/ProjectileExtension.cs rename to Source/AllModdingComponents/JecsTools/ProjectileExtension/ProjectileExtension.cs diff --git a/Source/AllModdingComponents/JecsTools/Projectile_Laser.cs b/Source/AllModdingComponents/JecsTools/ProjectileExtension/Projectile_Laser.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/Projectile_Laser.cs rename to Source/AllModdingComponents/JecsTools/ProjectileExtension/Projectile_Laser.cs diff --git a/Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs b/Source/AllModdingComponents/JecsTools/ProjectileExtension/ThingDef_LaserProjectile.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs rename to Source/AllModdingComponents/JecsTools/ProjectileExtension/ThingDef_LaserProjectile.cs diff --git a/Source/AllModdingComponents/JecsTools/StartWithGenes/HarmonyPatches_StartWithGenes.cs b/Source/AllModdingComponents/JecsTools/StartWithGenes/HarmonyPatches_StartWithGenes.cs new file mode 100644 index 00000000..00d9d696 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/StartWithGenes/HarmonyPatches_StartWithGenes.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_StartWithGenes(Harmony harmony, Type type) + { + //Allows for adding additional genes when characters spawn using the StartWithHediff class. + harmony.Patch(AccessTools.Method(typeof(PawnGenerator), nameof(PawnGenerator.GeneratePawn), + new[] { typeof(PawnGenerationRequest) }), + postfix: new HarmonyMethod(type, nameof(Post_GeneratePawn_Genes))); + } + + public static void Post_GeneratePawn_Genes(Pawn __result) + { + if (!ModsConfig.BiotechActive) + return; + + if (__result?.kindDef?.modExtensions is { } extensions) + { + foreach (var extension in extensions) + { + if (extension is PawnKindGeneExtension newGenes) + { + foreach (var gene in newGenes.Genes.Where(gene => Rand.Range(min: 0, max: 100) < gene.chance)) + { + __result.genes.AddGene(DefDatabase.GetNamed(gene.defName), false); + } + } + } + } + + var hediffGiverSets = __result?.def?.race?.hediffGiverSets; + if (hediffGiverSets != null) + { + foreach (var hediffGiverSet in hediffGiverSets) + { + foreach (var hediffGiver in hediffGiverSet.hediffGivers) + { + if (hediffGiver is HediffGiver_StartWithHediff hediffGiverStartWithHediff) + { + hediffGiverStartWithHediff.GiveHediff(__result); + // TODO: Should this really only use the first found HediffGiver_StartWithHediff? + return; + } + } + } + } + } + +} diff --git a/Source/AllModdingComponents/JecsTools/StartWithGenes/PawnKindGeneExtension.cs b/Source/AllModdingComponents/JecsTools/StartWithGenes/PawnKindGeneExtension.cs new file mode 100644 index 00000000..fdce6f81 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/StartWithGenes/PawnKindGeneExtension.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Verse; + +namespace JecsTools +{ + public class ChancedGeneEntry + { + public string defName; + public float chance = 100; + } + + public class PawnKindGeneExtension : DefModExtension + { + private List genes; // set via reflection + + [Unsaved] + private HashSet geneSet; + + public HashSet Genes + { + get + { + // DefModExtension lacks a ResolveReferences hook, so must use lazy initialization in property instead. + if (geneSet == null && genes != null) + { + geneSet = new HashSet(genes.Count); + foreach (var gene in genes) + geneSet.Add(gene); + } + return geneSet; + } + } + + public override IEnumerable ConfigErrors() + { + if (genes != null && Genes.Count != genes.Count) + yield return nameof(genes) + " has duplicate genes: " + genes.ToStringSafeEnumerable(); + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/StartWithHediff/HarmonyPatches_StartWithHediff.cs b/Source/AllModdingComponents/JecsTools/StartWithHediff/HarmonyPatches_StartWithHediff.cs new file mode 100644 index 00000000..20280574 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/StartWithHediff/HarmonyPatches_StartWithHediff.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace JecsTools; + +public static partial class HarmonyPatches +{ + public static void HarmonyPatches_StartWithHediff(Harmony harmony, Type type) + { + //Allows for adding additional HediffSets when characters spawn using the StartWithHediff class. + harmony.Patch(AccessTools.Method(typeof(PawnGenerator), nameof(PawnGenerator.GeneratePawn), + new[] { typeof(PawnGenerationRequest) }), + postfix: new HarmonyMethod(type, nameof(Post_GeneratePawn))); + } + + public static void Post_GeneratePawn(Pawn __result) + { + var hediffGiverSets = __result?.def?.race?.hediffGiverSets; + if (hediffGiverSets != null) + { + foreach (var hediffGiverSet in hediffGiverSets) + { + foreach (var hediffGiver in hediffGiverSet.hediffGivers) + { + if (hediffGiver is HediffGiver_StartWithHediff hediffGiverStartWithHediff) + { + hediffGiverStartWithHediff.GiveHediff(__result); + // TODO: Should this really only use the first found HediffGiver_StartWithHediff? + return; + } + } + } + } + } + +} diff --git a/Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs b/Source/AllModdingComponents/JecsTools/StartWithHediff/HediffExpandedDef.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs rename to Source/AllModdingComponents/JecsTools/StartWithHediff/HediffExpandedDef.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs b/Source/AllModdingComponents/JecsTools/StartWithHediff/HediffGiver_StartWithHediff.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs rename to Source/AllModdingComponents/JecsTools/StartWithHediff/HediffGiver_StartWithHediff.cs diff --git a/Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs b/Source/AllModdingComponents/JecsTools/StartWithHediff/HediffWithComps_Expanded.cs similarity index 100% rename from Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs rename to Source/AllModdingComponents/JecsTools/StartWithHediff/HediffWithComps_Expanded.cs diff --git a/Source/AllModdingComponents/JecsTools/_HumanlikeOrdersUtility.cs b/Source/AllModdingComponents/JecsTools/_HumanlikeOrdersUtility.cs index ecb7e18e..0c189e6a 100644 --- a/Source/AllModdingComponents/JecsTools/_HumanlikeOrdersUtility.cs +++ b/Source/AllModdingComponents/JecsTools/_HumanlikeOrdersUtility.cs @@ -23,7 +23,6 @@ namespace JecsTools /// are loaded into FloatMenuOptionList; /// Next, I've created two harmony patches to make a saved list /// of float menu options with a unique ID tag. - /// Using this system should lower /// [StaticConstructorOnStartup] public static class _HumanlikeOrdersUtility