From 43843a398fccd983e179aa600e6f0f152ab417fa Mon Sep 17 00:00:00 2001 From: c0ffee Date: Thu, 18 Apr 2024 15:32:31 -0700 Subject: [PATCH] added extended animator, animationstages, animator selects animations to play iteratively and queues them to be played; saving and loading as well --- 1.5/Assemblies/0MultiplayerAPI.dll | Bin 24064 -> 0 bytes 1.5/Assemblies/Rimworld-Animations.dll | Bin 23552 -> 25600 bytes 1.5/Defs/AnimationDefs/TestAnimation2.xml | 32 ++--- .../TestGroupAnimation1.xml | 15 ++- .../OffsetDef_GroinToAppropriateHeight.xml | 37 ++++++ .../AnimationWorker_KeyframesExtended.cs | 6 + 1.5/Source/Comps/CompExtendedAnimator.cs | 116 +++++++++++++++++- .../Comps/CompProperties_ExtendedAnimator.cs | 1 + .../BaseExtendedAnimatorAnchor.cs | 23 ++++ .../ExtendedAnimatorAnchor_Thing.cs | 34 +++++ .../ExtendedAnimatorAnchor_Vector3.cs | 33 +++++ .../BaseGroupAnimationContext.cs | 1 + .../GroupAnimationContext_RJWSex.cs | 7 +- .../GroupAnimations/GroupAnimationDef.cs | 20 +++ .../GroupAnimationStages/AnimationStage.cs | 2 +- .../AnimationStage_Branch.cs | 4 +- .../AnimationStage_LoopRandomSelectChance.cs | 42 ++++--- .../AnimationStage_TicksDuration.cs | 7 +- ...HarmonyPatch_JobDriver_SexBaseInitiator.cs | 3 +- .../HarmonyPatch_PawnRenderNode.cs | 24 ++-- .../HarmonyPatch_PawnRenderTree.cs | 1 + .../HarmonyPatch_Pawn_DrawTracker.cs | 17 +-- 1.5/Source/Settings/AnimationSettings.cs | 2 +- 1.5/Source/Utilities/AnimationUtility.cs | 43 +++++-- .../Assemblies/Patch_SexToysMasturbation.dll | Bin 5120 -> 5120 bytes Rimworld-Animations.csproj | 4 + 26 files changed, 389 insertions(+), 85 deletions(-) delete mode 100644 1.5/Assemblies/0MultiplayerAPI.dll create mode 100644 1.5/Defs/OffsetDefs/OffsetDef_GroinToAppropriateHeight.xml create mode 100644 1.5/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs create mode 100644 1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs create mode 100644 1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Vector3.cs diff --git a/1.5/Assemblies/0MultiplayerAPI.dll b/1.5/Assemblies/0MultiplayerAPI.dll deleted file mode 100644 index 9648606231a54f626544853a52d3f06a798c39db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24064 zcmeHv3w&HvwfEZRoH;X@B$LS`Z7EI5^hrqDke2eal&0w`&_~*)Ed@$DO-_=blbJ9x zp@e5DMM1<1%0ny&$U^}|@PXo!3N4~ML_`EpTJV9N7ZK$Os2A>kt-a^WN!!ck{l4G# zyT9-An|9V&|F!mW?X}n5`&>V7lU=E7Hdjn;@sjz$Y%-lqE?l`L*`Mq7nyag$Q%unvi-?vf zn~DwB-Cn9~FHK5TsurSkkhog?e24KRiVJV)cC)}FBYFq`a{kz~`BF~G|I1ec zS%lAxD0d|@!$eoHA@={=LR1CWFw!;buX{h7B#H#|5#Xf(++6g|hjJ5P$sk0(B(zD%yz8JNFQ!Rw3e|iOSC*TJ z%9;${9N>=(@R~%}rx+IFm+@#z&8YbF5BjJJr(zhKTSvWGwB8GmyL%GF_eZz!uHXMY?333PtFhr?mhzS97 zvY=9Da;FH?7PoTCfJ*u7+;T={xK}V=N`|oOD>{M-xSyXt$F50DO_tsGY38VD9a$Gt z!;kV$!2w5)Zp1u5v;DXeNIAhepA$l7Unop;Ow%+onWzad3jga`EW)61xU40s{#_My zXVg<8yf=D2LSb~wg_tE#nm(QyXM(}RaU0>Z(P@ov*Qk|)qr%;rPD2&&)2QWK2p5f( zW^D71;PK-c;i=Ikw1!hiYlMM-(~3YCZVN`8*W=m(JUSY6^RMt!ghNNCx%qc|-g0yB z>*$OM_pl^8G_;3ZXc(D`O}}Y`Uq|h{Qlbm1~BqK$Ce=!}*?@wQl! z9XLAUkj8TPwytFftL&vIu^|OD=rF zE?^2oqtoG=knvbe#TEUiEu72>*SZkXAWH7LE+#;oyR6Lmc6*PfTp zYs`g*YJ|AYLhM`6D@5QZ{M^0}i;2_pCCCxsS)J4ugm6Za_)<=c^}uO5le10HdUTqT zO=G#(LBTjgVX;weJ-6^T=wjJUO7G_Y149Y*)9G~e=#r@`Z1s3o3 znd4j*JViccy07tzvaMVQ*-O*CH>hv}iYtPOu&>Z@pb~h$I1q!#Os>Ty4mg}^K1N<< zHupHkshTdrWFBkJsIzjM!WJr%+2n@_0sSbPWb#EsZ{zy;dhlzC`E<6oz$tD=*nC_;wss8- zAVkI?o4jOgJE9&91HXy+H+eyZE0d3fJ<=OQoHxO8>})2qXm z)zpxMX1etI@Mo)Bx<116T%o5{F#neDap4aa{&b-WB8XlzF3jazTJct;OQ$864u#*U zjM5+6*`PlT&xYhikv~@TR%MKCu3BNcw9@62v3f55l`5vMfyOY~x4AAoL0?fZI=Py8 zE5f2bXFU%ik3Fv(?wtxpax}-$xrI`j+#FYL})-?Ss;fD?>~@mwWoQ^z`F#F5y!)({B6iM2w0trcDmh>*|^I zN-gKrahlN~uIpuo+i*oK+x#11jZUO->8IdbIy3ZHc3SZm_63YMHsBTEr{gF3=njk* zBlf&FO@|kp2;QM#pr*Q)YgWNuLeR(Q1T|Hy6~unLseYnpZq2rVr2s;mYH8fRSj$GUEFHZBTrm7CCsM{sq-z8r)tjuLDtmRUw=_*0X;u>8o zs0;a6_X%lPePpUS5$GDJ;TCtQx)$hKsi9zMxIxf%pjFWAlu|k?xs({)A?QNnV|1sW z$1RN>5cFe5qg{e-wl(^mAQwI2d_R)5IMQ22+hM_zYPh~Q?Uj~&rjGj_r&lE9#xS>f zj6ug3^efS|3z|T`rV5nuWz_I2O`+dNAKGJF=Hc`^N%ZZ_dR=|OcHPbDddTZ5KLt9zhUpZcLqZEePX~2qnRUHAk(7P3nn=I1+Egj; zy`fJdSH6CAejZ9>OZT@PNT{Gp^g zF~M3TRHyt@?Pt)JPWMj82VBXE(x%bIDD#KaG2M;y$Iv0_ZlU*Cqp=#@X1R2KY(40c z)gQMyk}wZ_=#U=FIYk?M^hH}y-bY^n`k;?k_i-O_zMX=8Q_&m!26Ue`XnGB!TMb$g zdK@WlH>hB$Op^u({J)ZH=3w8zl+@Q0dsiId5T3Wf!uA<)?^qlouyPE#&qu1>k`kO)b*nhF( z1V_NH;x*dqZd2JQl4n2biP5~uHEUJM3)%UW8DsPg+W!ZyPf&;34^A@z6i9llrsK+(@M7q z(w?<|O@z;$YW9#aVh<@J_K-4S4=E$|kTPNqDI@lfGGY($QHVXHjMzi?gu>*hnv4`Y+#2#`^01Y`qK4K3! z&qwSb=lh5~CN9YiP&a%%|SJG62mR2%a;-kMiSJGO8p0ljb$EeFk(a=>i zV9-5wZRl#c*hk|-*U*&)^{K|tb#${qdt=9hcGA5DUE!V-`ZRspM@vJu(o+U)SL;G| z(msP!O?T)X`lCTlss7Ntgaw{0Ppz?`(3hyzpk>bGp$BN9kFE(lNJkp<=jf+G-=Gr> zddt2g^i5i3&<5*sp>NX$gVtI1hQ33+27SBsfzU(5cQCoW9_zb6!v0Tz9eXmx)J-$N4P+I_Ee9peJ)f+ugCWW&=Ix23!qT# zp91I$h*^HV(9uv6rC;mf-TVT$EH2%bIxS< zM?SjNIo5sJM;AG5?oa4xDMj1!SZFO)M^mDY(`!Durt$%| zj8<0%(c1cN26W4S{@~}UjX&VN?xSRV5FI-L#i||+q#TMq;r`Lj_nLaf{gaQlW&h?Q z_K-6AdgTl5UwmCM5kxQ72GJFz~(?$_?yK1$ZV;J)LdV@IINoPQ1I zZUy?QpE6eUlKVFw_0_%O{@q9W5*6Y1e8fFcYROa<@H|RdN}Va_k%|u|UL{+drFD^= zu|b?o@&?@*J0xtY^9{PE`U>T!OALCTx+(0aj|$pDTti6xOwc3hqS`JMQi*9?-*u78 z>aSO>nqbfcKoK=Z&>pIDzU4$!(V$o3$A_b8heqnv_&uspy=0K0dEqMcTR}XF$*NY7 z!=*>`Y@$6JQw@Tyqvz_n!*O+-k1h=-RK}oP)whM~)i-rMIa`cUkND`T;Zch3FKH`% zH9T5P<=dHJvu}pSsQH4fi`3Qa3Lm02`{)PZvFcnw+_E2s4^D%FZsi@H%E>LpgEDI06HNuJ%Hv%W(3gU2=1x+r7Vjy2T*6^ zNc92J+iUI9BD2&Ijbt2VOUhDYFCmWXsmL6o+oP^^wnmQe(M8VrkrULJQi}HExuyE5 zzaG0ZQbtb+I!jXSsko>13g`wj65pMxzNJeM-<_)tZQ@R_?_L)q&|L+RDM%Un>8cKn&Dz=A)ALgF=5OH9jO%N6}kkE^Er3W6{ZoQ8w+BsK~r!c#e=GwZXh& ztKxBvy_`Pifj3ofX!n9*fBjK(M5P7$-yP#9r%StEN`6wx3Gz=?bMKx)EG@-7_G)=s0>q<~+clbBRCfdIq6_N340??FO?r?T?OpU3T~qNW-70&yeQG%I zBl?|MTk}(TL&|?ceKPcOdPjZ7ewiw)Z-rh(u4w&hRBP2#zJ-`@tX-uhS|5xh)DhNU z&KPyP_4B$0)oQik4qCgF2qo1jYfkkvHA9}L%#bH457L{?3U#%Vf3^CUeFn6A-eLYM zm9ln4&xVB0Q7qX3p3hA)(DLg+`Ajp1j<5SJcs_Z}!3pRwHCH5agRBQaN*4b7|{5@+ItqVo$?bbNl_uQv0sE^s#NXgeoX*Wu}x6|jG z7W?y3*H^$Vv13$4YwZNQ=?u_Opb?BG(7nLz{KXA0j!gU~J% zeyQYY7askFyaOpC==XV`r_#m9l@hH7nxIRC-YSwigx@9fF;EN7xOad)4Vu8yI8OhX z&{2x{u|lT`ohfvd(B(os&F@V%7XC486R3zUyuB9co)atRgahUjf{K0Op|Q&%AUF2#9w zshyOL?h}5W@RO|qJr=#qz75)kZRTGA{c+TGnC}w$FrGN1>{o>T&Pm{jcYyzG^cK4%Lr%7C6cO%>IBnqo_s>(Xv8nS+E{oZ=r3S;ewU^S`0?2qD^do>+K^@!l(@Emv>8#=q9b8ni(0T=TUe*ZfzGD!phv;x7S@%C zpldLDu{VP4En15)uxK5ktwrlGpDo1BnV_ekB#TZ*85VxFa1`i9IvVs$tSA<3qT@j~ z<4s))QI_9Xxr9yv-9fFOm*SbFg?m?vKtD`NKzC9*eBee+J z*7vNRSii8|vg+*ydzyW$eUj}A^BxnMG5>Q4c0!Ji@Gh7ASxEMmy@lNr@0c8VH+lFn z=85{S8{I$M2JAkGreS0b$7JEgLfJHu)z-- zyc?L?{j90~Idgs9Tz_t^zcAOA%=H~ykEYAuH}}%V=ua45TfM0ML~r9;2`g0LTaB-L z=C);WS#RDHnmh0KO`B$KYN5Gn()|M&Z?%`|_VV+#7-4f)S1~8>C{DA&+r}zzLB*^C zGeb15YtyEM>B2xJHPn_#6$+?ivk}h*vv@Gug-iRQ>|no_Pi@I~g3caH6%AN3lQEZK8>QzLm5Unhpj<#m*=_%Gu}K}KA0({x%pncxwWI6+L^4)rnBjy&e+X@mOwJb z%R4ad&q-wly-k~FwbzR_d3o;2at2@X-_o5Lp(ypvs1}_&kSll#VFv0ibmj7y z^cL3pHMK3(jCn6s_%3I$jWsIVU@$vg8yTrd~0U`W@}A?6dr zqeLrm#dOcmrncN*w%FE}%JzDYdBtr!%-!T=dFZ zFyP^`APusZiF8T(%ZNT15n5$9o&wnt=obgmL!52TqI*55E|1m}(Q)((Y{?xLdOayP z_cE`DL~VV!G;}C*X{ylIhF>evwiI%AV;*>VC|09+US2Sppe>bM3lH_q5lN{~?$JU_ zj9l*uWbDj)f%-;@VUG6fIk~N9n^)|}dj>4PWI?-qMXpdZDCnzH4j2d?JXhFfw8{GN zxorA8!K>k5>3*+sXuw+v8zTie$Y^ms*KZ_ZW*zp#YD-f6o-iwz!H)~|1QH|;Ae=U{ zuxt$N;Q~>ETw4nTuYXHsD3E+*z9XL-@bX11JvN2QILS)R^zqWQ#q zz@*6{70k=+mj6XIyS?t#B3^3WGKj>yu%t6yUScb92UOfdi3{b_EYkfPDH}Nv$~vE0TS)bKJ|f+6 z_S~{;#b72gQgT55%8B>uV_8vh#?EvxSoq2V;mRE1w=1sbo`Y4=86?oJsW-%21D; z6uR2Wq|OyCpf9xzbFq7{t60uhQncj;hVtp&zJRJU3TQI_fVrGUrb%l)pBgI5%H?2p zk_{+KIFemUF})?tTbOdT1w(K=%r2RodhPL9=@*SySA7L$7bT0NtywRZCma_Q@)$iKq<(eWx1`0vibg0hBC52Tbb`pXMu9?24Vcb)<1w~j5QZ)T*fc7HIva{ zja$0^maw@SGHeN!=MdD|JOFgM%geO)z^)Qc*vEXKIDts;=L95KSrW+Dn(rNv2xXN- zrBqUOK~f=3r~1uc%L=MTLY7=!h0VCrIeNyjGp@|Hc4HGJn>*^j7zUuf?gsU%z5d)e zUP;o!cH@EWf_-NB_}t;!Zl(t;_UJq25}j9yI_r(}ccJEval5GvrgxfJ$0*};_( z9ca}dEfn(zK)L)%cG!Gz5GuXB zUzX0EjWr0TGZ< zj}r7{P~u>v0;&K3JmNNF~egECLtQg`+KDi4?Dqut4a{n+^gcalJe zB4{NTecbU!L;9;X=h9!pZjE&4;t}sfnof*;o()MA$ zB$yS5s#0Zpp*x%z(Z4*EKhgkbA?<_5$EG>uN9$t2$4qLEzri(XSTpG6hD2GAh;ge^4vBZvkKIKd5R#$ zp{PJ+gqC_4Op=1xDf`nww*W`YZZE5STguhZs^G5~D{>{5S-IsboSF}&k@ILtU0Pbo z8Aqr~D@a+5IQO6D4JiFhjou)lf3hm@fEM`Z#rJ5?x?Hv^Rg{4(-_XexaY!wau7>vl z=*a#H5mq_m?a9E#ROrhMW_YupgDG6P%jdNtVnx@@AOu+i2`Zh`n_<8#aK`H?l5F@W zH?XN4H^8u+C{nuMv%H%^7=S~yrV35}rzZvk< z!G3rwnF&GL`f&e&r!j5GU}qzoSpquw@8ob`Mc3qS=3sIL_IUwmiABF9A#Tq}3uP=< z>j>MuBBzDrwW}SW_gpMfOgVIx!ggs^4{xEgt&@(;5q8YzZ_+O4xXx&I&e>X0n(=lH(`*IYTJ>%fbvqfcClpZ!Sg1i>~2aT zCywIyb_r$47PP5|Yg%X@$|?Y5(Uv4y(t*3tTyJtj%~9ONraH`Vq%9yPx4Ru>)2KC& zaSK!EUz*MnMByZ!&Lxp!z3909Jn)Gu8#4oRH6$r%n=hZ*Nqs0Gi=HmVm956P*iu>H z&jqErpw5&ynM>?Id3ogEvxc|Cs2e&5Qcm7E7%1?cF^Yld@ zy*0WtaarO%a*|3#>?A2X@>jLB3}eE!3T>|*l^Fi28kNXcbyTNZPBi>rM1+aqYrf_4SmeN{yVLFk*!y+U|pkS5Q$Zbt{F*LiO0lkRfc~UGEa|pdaTNA_o9tkBWv0XW! z8=0g~#ssR2<9+V<1d2_-pP7iNh!eK(a~(p;TE|UnALY2U+sE=tNFqCeO_3Nx+q4y` zU9@r+ep%QszM&3(y+ztwr|R$=3r(usJ~I?X)sIO79^-bPZwA>YRK=3qBfkKhuAx$- zyDcsV54&J4U0dl|iE>JOcvNEh(Wnd0DTJ#dG!btg)d~t09xF+7!D76PiH+f;#REzx z)F0evSl9`KSF^byW)8vV1&i~$S{LT=yhRd~5?A<=l1<<;6-k?W1XEQ>K@*srpyHDM zc5wu*ssUXZW*A{}KEcMs^+pJ)0@iL2?Tyezl6HfXT3If&0Y-pK`%uFKErC`Wc*~FzXzCKIUNP$>9fc4!nvSJT)Z;FVW%|ob8SeSuXy^EZ4H# zMAC92wp%*`-y(G2;k<5Q_>(+6L+p*?L-2MB)h0H;ec)}^M3N5AhlU0>X{&~qT!6%N zQyA{V8PKw;ossY=lXjvTa6HTsg{nJ|X0|#R5^-caym$sItPzV(Me5l27!)iPR1%j{ zvp7Y?YY8 z;wcgC>l|+XoW!7Hn+pqwbP#cxQ$|WT`eA9r0JaT@ZNhjGhk6_E)LBe}3!8?O98R=p zNSlTNrh%$t8X935lPD4aqm2Q5*+$g{8Pk|VkxB}fh9gkWG`fjA4AQQ&(4}adHVs+_ z)4)H)G(7FaG!Vly=;|E)B|4jiJ2kgtiH;J}Qeu{snE5cGmFQrLb|gB&Eec~afkG_` z)D?u#2^~`_G05qLua4ltS9YM`8xn(w;hW%S9N%ux8oU*V1cMPyeQWLTT`mR_^PO{_ zIv!z~5~m7ZTdZOc3~)c|Yg#NA(vLb;tOYS1S{;Netwty_n9Df>p(}BQE`Yr}aRyq7 zrG_2fYG`QSG~F!k=0+#Fb&cI4YV6*xMrch9wMlhY{fNjHD@k-9bB^GH0}xw3+3Tg@d}|) zp_M|bgjNfc4MW`0<#F>c3><1u_~r_L#PDVDI;ufnfX@iee#07wA>-gX{0lLr>>>75 zz|RrV@E@fxCn>Ih%fJHLF=??^K+V_&*o|1g8!_7(G26jJm>CQ=nt-6MiGIB0W#Jn` z&`oTJ7->g|X(=(wO3ZvNW@C&KmPfQwpdQl@^k}k3(4gUc5q|%NKNIkZDs@_;*XL6M zcy8q1AM3=kv26wX01R(#_D~gc`1OOj@5Inq_0Uz z>amLI@o+3@4&nGas<>sC>TbqMK#Ce!^M1$EQgZ1H`hz}U`9o9nXPTlNTlpp3POBOR z{oFRwQxAfQ_AKsg;at{DNVZJg5r6+=C{`B?X1-Lw6^RIce~4FH)J$VJ-;xMS)NK~^(zCOC-Pvo$!~t)vye?VyXzU;O*F z^ZL8&BO#NobUn#nET`IQ4Cc#1d=*ON)0sYV;V~*sX+1dC@n;Hgu1;wAOk0psGM|_E z)Tcl9IoH4y721TG6VQ}Th{2KuBuxw6Zqxtf;G7E^(4okw{PVUx9~Ml>lLEQ{secH) z#mg%=N0vTIVP)mFd?7RioTa%P187gVod-WTCe3M@@cx$*C}*9VZA&L7R4{4qU50@TwhCGa_V0QVob<-Is*^AtT$mZZBd z>5_OaumxWPO1y!|_A8g8M~d$%^rPH7-pegnliye4wy!jG@JMmnOQX(6TlOFA!*O`? zOQF;}+TM-37JLsQI6eorInfNU^~iktTfAiNDvfTMM$h$*h(oF9I*JB)pIqQIejl!lioht14_E zY$Rw1NgC3Ggus`O2}>3dIvuklEa?Q2w23DP!81JxbkpvTkW52QI-w_YLU+eK|2g;7 zCL6+ZGV^`&O_yEw-E+^m=bn4cx#!$>-z#ms@=wShA`{<#`!}K|aOKZBDc`x60=jDc zQ&sd>@O$Szp>6rzx&5QbOl;hB_PL3%*ia&!cCxWSJLcxnv1B^dwY@Jk<_y~{m6f4I z9_yYBL|Zh2-uRQ@SMsC%h!(^uv{s_`qQz3JKe!Ip7`{{Z5>-oGS8{WMM@IAv0JQVR zpsR0YQvP4OdLTF9^GD#johwsB-)2S3{CtWijJ8qGojnuxPH>DUP=XHt-dqB=WbH#) zz%O5k0yvqgCpRGZ#E7nLaWn1^Adzhf6*kmW_?CRu!CWn_opM0PveKvUWnP2$mVDL` ztuFzk`ULA0AC^rgAN_GVWa=Q&r1gKlsA)B5!0V>hANE0DT>R<+g)kK4OQx16bT}kc z=-oP8!PN!aRfO z&q8~sk*sAzHLWH&KoZuRo<#2AdYrY4{wZ(w+2CSagM z9-d>36|tIDmoirr6@mIwdW}EgZ)zw*dJ_sYE@+HVpkX%*6qq^qDYGUJ2{gaYDxE_k zMa*Rd-NWqve%-@{|2K5+4fFrB?$sRfy4NH|AdFy5OkyROvLb3)b(#eS^V+f4%-U0i zS}ZlK8i@1jXp(UbmXhTyCD_xT5#X`d3p}l+KGO9`tVFY6_hG&$K%c~tHtU@jFS2ua zk@144@be;z!;dUL;XqRbph}7AjX_kgiY377al{5JeO|vhwP8#&^O($(mtiBihpeVq zUQ@lZi0MlSDjLZz{SDfP{@#3N^lu}*;V|n4(Mn{GM=_MMn1x<~qI4F{c{0SZrwGK- zr}i+j(`yg2rt}$IYZd*n^@vD{PEB;#RivA$M|r!7Ro#$PK6)HcCq(-7Jd}$mkJs17 z5ycwO#KXGhb5k5^t1*traWjkI?m)9@g_#;@S(`rD3`RMy(Ux737d_s>%$JSmaj;>< zy#NL4apdCA;pHewF$m+Om?(2aOjaD0c)^*Lf!#dHz*eE_R3kVpTQ6wlZ5)OxnTXY8 zKE`d%3iJ^lOJg9I!NOb^;pSwD=#3H2%oE{U@#K66C9#iio3OjF$d23GPqS)PVX*o* z5*2t}MlbZEn@l^t8VC{%Atw})5BvNc@J0v3up<`&wYa%q$&m|CIb|gvY-SBQE}mkH z(~j!oS}uSO<=~WB2n&K4_Un_#5vDZ>!qDVJD4dH?cy20di}N8;XN26phNOyqakIIk zw$bNY0^0bcC}d_(KfKYx0+|c>4x%576rm%SgNbEv4!PYLb6AHCZU)tO2lro(0<`)h zMlzjFKoyN=N40ntYGDc(CVRexOlVO~0;*NpWltEZXgzoGc z3o)`e|H3O(&Djd_z0Nk2m^+W1*Dh8CYghH>?J4|=`$InnYTMCa5(Y4x9@IiIMb5s6 zZDwG19R6%o`h!AYIGA$5DfF<9D#o* zXM?xE*@nS3(+ft6rx+85t2BlTOvc*Vup7hIS2nhDer6eiO2#Fq?hg9{vcus4oAS&R z0S1p#uwi#)P<3;#91y8_pV0i6YKp_?jh>KDuu=>vh$qnWm56>zF$lsaw1ri(Q<~Q= zps9cDgqMA-Q}%bf7x2+;%&&^)7o}NRd>1HjK_g$V#`tn2F7fxE$Uy0#3cuy-#g+W- z$Kk}_H}&;e=PI-;@dH@b;b032taCMAphKOoBH0-*%{ZzdI)WvM49CeLrq%~?P=)(- zUK8t?ATx+^imB)bRxZ;bFL|_B3Ki}Ti?l;b%T%>V7&2rbpI7+Tei}%!^qxtF`;Bv9p&?w>gbf}ymbFPs`~W&& z_RPECunWKl9M0fU&Jz9or}gKSQyOnK+2Q6FIFygVRB$VfG-?H?Iei&YBL^eaI=F2L zO(F$^j$DhPWwf*fAurUj(`Yto8|N95hXAQS8HsZ*FKCu@ZhTjy%yq@thNx_E0>BKl zHfr_oo;ir(il(SmrJIt#!**=NTxyhk;)p+u@WFuPU_Dui5hiIl@CR!eR2t%k*${4| zfaFN1N9|ea^C4+AMz9E^$HGU%sXfMTg zXwFTH;mRLL#kpB7DmUJOy4oEsA)`M2K1M0o;MwrWSsvt}IG^3Bx`@MJ#QOOAxf4-6 ze9M=2utLyc+bjVVt`Glinx#7*0Qr#*qBy0=Bm%-+7$t;|@iAP*fhqvp4Iu32^%V7=*@G&B7>YB)T428>`%lOG4qDlAlgc1d1GaikvE1myP+i0F|F zLb%u-doi&+mTn`Ah;Xiq=zNmpDv1Otu3_UrSizCZHD3R9sz18!f4i=HcJXWUlaC(% zPt5p+)#>L)`rBzzv)}+?z^UmUGM3OIw<`C1{lNVmrB)mbSET%XDcA0+{JOTH3;{ z<-S(h(#9>#W(nu>xy3;XmVplK&<$(2<#Dtuz*N@N#}T~H+Rm+SsGe9>Xj#iG=lg^g zoL${#+$Z|v`-bhFDjKGEh=wT^uYQUrTR+8O)KBrG8m3st`YBdR{S>Q9MxA0IGJ{|y z$v#s^<;ylAG2hRFAS=VfjZ2hIS@a>SxjDS%WHS=747C}t-2D*o29}|gS@Sv8)TPdY z%))X%#yFPg47lTrV;RqY3tGVOEKb86;Z{V>T5#_M6%Uu+2BGOBcVzpX*3ohUe&E=y zXTY^Ej#YRD+z8`Xjc35U$T(K+8F0}6aIEM!wjb(#rBqt$2;=fP!}jenYz}U-+^e`N zTkCYT&eg11Sn0ETmE9Af>gl^D_K^zMBfvIuvtTH>^L5;?O9Ct2*B?0>1F0Kyy@=4^xP7xb=zi^P$f%LSH48LVMh$XmB@o5)z*;g8{7?tBlkau^a?T5R)I9d%x~HgrTuB$01$wjhDWv!pP^%!nh`zYlSkh>D$1}h^44m8)(y97r z@x}~tse7^@Ep1cxWV}s=O&Uu%fK2wUn{mb5BbgLt%K5Ydn#ak|VF+Z#{}f{&I*tLC z`6BAL7exSVTw++0jPLg&X+Zy`zp~M+t!$*=vX;!%AfCdW$1KL*v~hYmTcq+PIv@&I zQ_y2c2ka-8lr>0xxg4_cN0%(`dq;EUiW{tq{kb3$&10tC-F z8@A#8@JscDD1zga$zQl6K0gR?KW^FSe{hyX-<0wL*2Y=0=m)asAHhDyqP2c5&yw=< zQeG?Nhon3%G@rC?28ZjV{H?USY7HVg{3J>h7X1Ugu7&8;z$I1{ZP&i*tD;tv7Cnt4 zju5S@zQhXAQ^1BO7v}O`Yq;EGa(Qlq%Uv3mPy3`4nkwn_&qA{$$nDnz93w=}p^Va4 z)#2JG{jBzItwjloXZK?n>+dkiCfv01tW5-7#A6wEy4EqO=w$S}z7T!KU~WGUZr`pk zYeM82T>c2-*3-PYuWA|PV%WzCI z@Jwg|^gq_P{AGa4I-R9`v63l22FfTk7>8>^bU$WiQH92OdrstO2(eTj#wa0LEE@QR z)DH;dFKc-&H;Jy6i#&fOG~Y!FEC^{W+8bt?Z_Q#3OJ#Onu4Ii}UCEOC7G;$FKEl!- z2{PqZpjFt;q>8iXC+5F|L-c2&=UZ!;Lpw&dsJgBO?QaUt_lYJ~3g_$Un5LzI%XA&j z@ng_Nhz<(PGqpV8gJCY`niJ3`LI6g*E5h|KHuZ|D~R3yl9=-c z!5O8@beCx36+iP_0nY5%S4+vOR>OL0nU#oiNS&eD8isHdFStbl;ocU#s%e*=i0r|F zGX?j}szhW0P(Yvu03AkVtrh4+52_RBO`$vswA0|S6i^2!XA7<|n25vyoh?wi#?V}f z(KKYdJiwG^(<13NRLjsj+#Rr-9|hD-^Kl-?&;y{n54{?N^5Z5`E<`+F+|wAL3s9>- zFB=Rk!gC15b%&X939S<7QC}jG14ry!fcqyvN5OH8$a1B~(nuEx!4=ZDqOxSl+CnFpw%9(N1(4(Cn6E8nR*54jU*y-vI!s zoU4v-d13Tsl-XHazo+VX-J+$HN8#_ggIqtNbGg^Y<#6?FpjlD#QIzXz?m>B0CHJ~l zxP8ILz1G*RU0B-r(bC zSr@*?S5I%!Qz&O^PoY6h{w z(!N02AJMq|JZZVV?hSC*6#W&-UsRm(t)};Ce#F{(3R_&SL;V6e3(-h77fHEP$`+K{ zqiZ46dD^Yi6N6dkmf3a41sXkF27Rjx`d$Ir1j?5MIz~=tH?sV16pjW%D=a@{7Z5(T zP=9Ex6`)^o>ZMx(cLq;tK?-2M#?X&-h88J^x~did>JsP}T^_RV4CDz9_doqi`5O=V zb42VQUB*WQ7~y8*(jZNE&<%*ILHa-e+KgEEpg_my7LK6wmO#^i8^bleFj?3ef{V;O zO!Z|@YZ-KzKuWSOZ7;*^E`tUYrS<_CkNFcF^F13`q=m^=l$6x&1~gXI?_dGyx59L* z;zHc7l0NN0%(If7El@J_odWb8tCC(W=~qR+D(P26b?31xcg((ERs#DC^*QEyL$^zy z+s(VNrulgk-m($BR8zY^$A~Gb=~EuWlu>$KAf-X%YXy;M*jAKMaprOh&7F0?s-;&I zBs?1!fzL5tE^^pvpq~p)jW>sWBhWEo+#G6J%9Lt^xzsL@!p)^m2{cUuHMd&l&<5U) zdX)2MTN$*g3`z@hEKnP`-I_;J3ZnN$Z`bG1s~*$_KbucGusemEREsq;pGE{yvdkym z0_XKPpKdJRp3~>kZC<~R)>z0&pDUq^(F+3IML(>)(~8l9P0WR%d#wdD(#((=VKI#h z#JGp7#q@9idel0PzFtBZr*9W){Fc))ftbrlYdKxyK__c}Zne?4KuYSBbbSH$TWckKp#-;@ z9uw#ou_v#lue9+9s^4mQMj+*%t7$HdRunF6uBKLjj?oxww1&Qe`vSJg7prj)O0Rm* zlDfOKcKR2A?xHVN1pMvPzKSXDqWu+7|5|#X04?xeOtU%71GgKL>*!DcI^W+xf8s$K zDpvW|)2jk0$-3y50x7Ax=q-V6f_JRK?&wR}f3U~>E2A#OiElCP^4jXqq#EnMozom}q?a=8v1@E$-^M|*4KJJnat z;=U7lb+zG9`a#bv-0SV?3j1=DX%1l{sv(~hB~*2m-0)<+4)W-9e@&h;Pp@YBTjBFX z8MjDNPJgS+jydQ1o=*9?@K;i87oJ?|^f}7*gH;dn~;OsmHCGJpAR?~7R*GkzTWw(?&q}(HA0%aW~rG7xl2`M8Qb6YOu9a27o z@+{(V0dgc`??br~<@;+cz>c0f{NQwe=77*{WbktzE7h340d>L=$yy0!smJ^-_SXiy`_K4 zcv@esa|BHYhiR10>C+l#tO?DBo$5Vk!T#Pb>wbv(_dR2UeQ-Y7MZVUzp1#$JXh!J#@@RXb@t5VDAVS0{rT#gc|d!geye$h!Jc+N ztEv1j+BvJ;W8CZelDSf>zfyeZBjQUR5ij}#oeKPS^FfikTmMSUZ!r4(l{LPHj1Bs1 z-%@SR7&cC5m+SL>^%u2$z5wp%CVVY8Ss(Pb z;Cc3blym6=C>PS5C>!Zvlq;mXP|8keznmUHd!MwtN6I1k&uH0Cze1TIE%1OgiTm}R z=v*!|K8Ui@xRZJULnxmM++=*5E($(?`Xj+_qMRN23CcrwQ|C_luc3t~TPr$I-c>P# z@?R@%LV0!g0hA}g3w<{+Hz|jtyh+Ljr2M9oeRMT_i0(zi`XXJXeMGxo`>|H1&(kl} zC-evO6Z)&VWz02Njim7-W3}07PMi0bkD1Sye`zkkeVHa_8blup_WOx`rgM2qcsI(~ zfxUhmCmaSMdl2_II^JjSqg(^18TY-D^jX@W4QRJ$&uAyKf6;WkO}|Y4y#A>EY2zv5 zyXN1TzchFF%qfoRrJqZXU6Ec2pK;%FLV$Zy`uu`6?bBm8#e2@t5SbE4C zr7!2-d<)Lv`EYZ_7_Up;r8wQec{OZ(F3u1ZVIGTdQWB?4^fg%cM>qlad)kHi9tvwo zTA}sPCE90cpZ*1WzXN}NlNyb;sKc0}-DaGNZzH~|G=@8j3$-@$3v`>&N8M(JHiU1| z+@wvK16mc2ebFUD0|Q;j%y=p>(V0qQGOYuxXk0rmu$(KMiF8LgIhM#Ko%DM9ii|yc z$)JZ~niWj5&(0QTwm8oC_Hm(}*kvd8jb@o%$Yu_-iu-O%riVAVPHw!wf$4$haWdJF z@OEQzi zrQgmJCHDBWQCD(^)^WKP}WWl+rvt1$L&ZDjXLgt zLa(4+C%clhNEdB&hI1+V653>EuSh2kFmH2|((5&V|L&gAt*8JoLgHs*%*qtZEQ5A7dx4sA&c+9|+A{(bhL^)O_wJ(RRDUT`jh|ap@qN z_;<{sJDtoX6L7ZySd)zekE0%}Q_Qo^$pOen3D<&`iF32j`m%}iaKbGy0$TRj1H3eQ zfpW(BpyQ!z=V&55WYfSvGMzyeRE6DkXwFRz+XPFGVqmbgY1kgj?UNd~?3YTJ4SEs> z)4dSScDFIP>o{4dq#5dR69>2DPiF-9l7Mt{-ljXkg{o`J;s-gOffc4HwQW=!*K#JgBP4s2Xoo1lir!k zBpGq7cin^qhebHzxY>=aGuCORQr#n1sfwyMm(C`~?EZ;ydoz@ZelP<=OzX7_Iq9tH zq_E7A*+i-%y$@77)>hAmljOcXALb!ES{ua_%4qJnPxSVGL7rCDs5j+>ynT zMra%g%Oy)7vHd=_N09=ZJ*yPkIx-o1Y%n#^pUjq$7Mk6}Ff8xxFZSq9xLAZ6IsRbT zl_2tcHbOw23W8#>S00(yi=@EQ(Oq_C$W2PdDp2%ZjoWW!YzEs2_lJ3aaIh(G@S9+XcvQ?-=KEo>z${OfZ zi_9KIqUlRs2lwGngUq^p1c9M+vG*tTspdiqRiN@J_O$h~yi_amMq=XlZjTh0o{=RX zYB5py_JCXVm2DWfr8}KP`j@oEVA-g&-Wi_Y)?s`xFa$=>7{WS~1=f*D0h!^g0YXSG zav)>MLKS|FiKhIzQ}ZmOe1+WPWF1w@3bD#;+|A3oo|RfWKVwY4qaM0bAL4+gJv6h5 zIAO`I3vjZe&QfyMEzZ6f@o`|iix@syE;y@MrRnZ;AKV{lTJm=pl?-?=Ih-9O7g47t zF|?l$fZ+Go;$#Kv&TLL(Mn%cjCQ=-dlZ1gt7CS0dvPzYT|}Y2+!$?4Bvaed2=Qs&Pi{vhru8<$HL=a<^i8ao zwA^vglyI{%+BlofXexJZ>MPk?D;9-0$zEWaeW zNB!=^COa$Dd}M9z>>EwEP-JTXZ;N4zto=BYs2%*Dqx8=qLZI}8| z*!{S&%}CY}4h6fVF*Ovz;3EMo?QX0Io=hO4-sW-9VFzeL>$S z?~jW_G?a5ypdhvWu-KS@~OIlWt(4YV26~=uk0X@C^6S;(#{Ob6hiQ4Y%J*{p;>7ba!91&FkNVY`*_<# zma~Puf%kKWB?WV2kR7l>fDmT^kpR~?gPFW5btMz~(%3vDhcYt^U9xG<&|nI_kU}K4 zv7;Tb3*GZ6LgK75-e3K(0#H&ToYmeBlKlf03DNK-e>KT~DyMvdVbY@1j zEvjjTs*WRb9dAK1`MqeSn1qzK7H{-ufBu$_237v$T`1KOUIJKxV;Nq6C^IaZs^GgS>Seq`3DFPqn8XGZ1YM50!C-YE18_s$ zIx`TXHY9<)*#tO0$R4!q^gwph&1KL!#N7{}!Z)n@?4HcTh%=OfX6-TDQ+H&MoU?2a zobh-bt0aUw;T|zd+Xt`V3lue=vI`}>D-tqV*^2Pq)Nl*3aT;((Dru*AWvbc9{*j&6 z1KFKRKu7MLJlRwBNLHy3Ar@7zFIc*m7}tA8V*43j)usS zuARxHvJ(6~-Ezjm%`k4|H>m77g5w9Rn#f=G(BD$2{{s*aPhg`|_xDS`H~h zXFg*<7vA@5No2C{SKgQ+?&HopXKzfp0Jg$7yg8A~QNG6!hXBUC=3x1)s0e&$#*W{k z9>Bta3zsJmQkLvSiavyMoD3{K02k#=8V(QTPL{8S4jmHK6V&0li3!4ipm)@Vn`jR7 z8xGk+IgT;;{R5OUL9Jf4=1rIcpibPt?sMD;u~r(P0%poi5LVM*Lfv>_TR1#$MOJRY ziVDs*aKg{mWwr83%{TPoP$OT*MDx{*7G7Xv5ezN@`9}8c!0(@QchWt`49K z-Udse>?p%vhedSmnW+y@4sVI^mlmFxf?J31?wCU^(fPldW&qNRLJApm)w`h|2XBP_ z!YpX46C7-ey5HjyqY)WDhWFww!#Q{#u!rytM@QK_Sp%J-hpgbUc+0vQZ44o2gI``x zU1%A>m=}NtEqxDgN|PDdir1zLEzTrs@+$CL@! zf~BE`ZMYspe+Rr-794<~q&fL^7Z^m6g3L6_#XEZk3**swTVb~>zAVdTX&)9lr68Bm ze=qeA%`c^6DfVM5NBRnWtYX^T*X~2V4A#jGNS}o5SpQnb zJM|io9*B=JE^huXrt9@rUWwT+entCKtQw>Nyou)Le|xoXq#o&4tesr(>9b# zQS?ieM|oymnm)*pL;qoLP&0RBt^6*J$&~0SzixRx92q7^yZD_XNMOA3SXkddt^qir8^B?sd&n_=J&N^JoG zWDb=10q{Ty*a^Vw@Gdy<@LBw5kHaPRRfda+Yi5B_!6^ew7JWH{G7k=BF+Ap8!7r09 zEmwJ|z_GH0OpD7Yd%cCns^B!F9FW$OQ*nC9FE^eW&r(Sh!$Qa}z4J&rP&CfzE><*2 z8hy%_9?yys4$m?UNx1jS@Z1C(r|)7w#=Dbi%OyRN`N~sCj8sUa%S&f`ewmhHg+y3f zP%IZ)nuA>qvu5qL;Z-I{igm?slVd}_{H@=Q{(>y=s;kCrb!dF15{J)hZjR2%LifjXEjo3gDiky18ku^Ul*OaSBoZCNoUViawjTyj)JHm9$*g_ zd$~yP2)CgV6gzbrWzH`p3})F9B_8ow1#wLr8- zbRPA(^{}dI@asB%03RJ#5KcXWN}#4%6W|RPNZRI6fK}TQhT)`%F#*3GnR+}r^(15r z`{6!ed@L|UYanKztO|=GhAqE|X*0{|I=w2g1Ipq`*ax%DBeBLOxMOtcFLVq3g39;s z7DaS=T3V;4Lw+k-s~nJhW%^v!`Ac{|1#OW7h7~#BgY9Z{LEg+(c|ZI#Y59%lY>X>X zv&Auo*#W=B!sxo^#R+arFfUL90=#AtsNu&1s3?y2F~|F&elt4tu(I=;(JB644bI$9 z(230DP1A}@e>zMCC{T$^|0#R_^ifT(gktAm$_ny)=1mJ@29#Sp3HMeuEU=vKuZBR0 z=(HA{_Cah26;LKkMArpmLBdtBfNqxAYiv9i&9fa}<`IvZZU~kFH~1IiX>u_$wCBG%pWXp6lwc zobz*%rg?-Qz{XsMm4oF=8gwOg1?Nfxq3G0Gb&)IJp1(zOh)ll(l~u8k-hy!f;y>H@ z6$l|jmFx<|E(oHL>7T-zzH;4rcg|V)qxYK##$?GFtnz#*>|MLzebsQwt@!Rh8#Cmq zEJ@%vMory}%HDu#L;z8hF7MjzU3-}FPr3MWZh={=bSoT0RV^j%FKdZO9%M*j7ek+8 zDz%^){5gv0AQzQb`H=$wEsXI~Ao(K8P1&hh$M5mb;pcEc zOcm?LPnuSZsEiN|+B*b29W0>nV_+IER1f|H8z@J+2YH%Cq87r{}!!59`!vxn- z)YU9GJOw2}q}10LalCpRhZCWQ>4q zrkkx%%^4n+;cYfSH)s?sJc^EeC*Q&0t&e%GTv8 zo7>xlhMSkS54E)>hFaU(+eYwry)e>p{QMaIi10_#&T84Vp}+7bzR7zUdNF>Y+zx@O zY6~dul{7wXj&h$^0TTnQ$>LqB(I7LhTlic>Jp%_Slo>W|%wsToGk!p(d`&-UD&mqi4@B zEWg6?haEPo9%^k(;BARRL^+Lyi*qe~X!M62*5Acv-A+c#Pqs#T)TnY=^@knG;-PSS zO9L8h#Zh2O*?D7A4Cj4C!>wvr(XzIs?cJFyT=tR_UHOOR@5k|6KR=+xPx|O`7QN)u z@AnbBqVyd))_z~PUJ5VU{XT<)`N`xq`yf9$hdX1GE6Yd0?D%P4;k5Vn8O*0nifQQo z=qLtWrox|e)aa@+&ZO++!QW>#GgRmNt^wr@z~5)U3bqw{8^7i-^HV*e;o<9w4ac}1 zE5fC<{NJipZ3B3ht1Fe_S7y{}q_!>ZN-*}{7K6vkVM#S{M{`yt zLMA+|o#{5?yBnAk_A&WS%HSW*?Zk1$0Ll$GOu>8HICt6xxEtk0)cN!0<}XgEH`-O? z&cEG`KP)02-U8}gJ%8y!MFUqp3fYJQ5I(ErlQ%wX=g%T}SG^xtKEA*MMO^b|=t4kW zGQSI^2vca!AEBJi>2pHUig~MlD{$S*7S&$EV__)c%ffLVGeRj(n_<)Va;6pGTIj>WO_&kx| zckf1rrE_81^nfoP9_8dPtkiz*jvwJyNNkgGJ~J&d(=PZct?1K%S@LQ47`%;7w`1`1 ea*NLFm)FU^>pG6TE;_!5zmD`Dpa1_f@V@}7S^N9| literal 23552 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 diff --git a/1.5/Defs/AnimationDefs/TestAnimation2.xml b/1.5/Defs/AnimationDefs/TestAnimation2.xml index 81923af..06bdbd0 100644 --- a/1.5/Defs/AnimationDefs/TestAnimation2.xml +++ b/1.5/Defs/AnimationDefs/TestAnimation2.xml @@ -2,7 +2,7 @@ TestAnimation2 - 200 + 50 False False @@ -13,27 +13,27 @@ Rimworld_Animations.AnimationWorker_KeyframesExtended
  • - (0, -1, 0) + (1, -1, 0) 0 - 23 + 0 North
  • (0, -1, 0) - 6 - -5 + 20 + 0 + North +
  • +
  • + (-1, -1, 0) + 30 + 0 North
  • (0, -1, 0) - 12 - 4 - North -
  • -
  • - (0, -1, 0) - 188 - -1 + 40 + 0 North
  • @@ -51,16 +51,16 @@
  • 6 - -5 + 0 North
  • 12 - 4 + 0 North
  • - 128 + 18 0 North
  • diff --git a/1.5/Defs/GroupAnimationDefs/TestGroupAnimation1.xml b/1.5/Defs/GroupAnimationDefs/TestGroupAnimation1.xml index 701c56d..58c6dd2 100644 --- a/1.5/Defs/GroupAnimationDefs/TestGroupAnimation1.xml +++ b/1.5/Defs/GroupAnimationDefs/TestGroupAnimation1.xml @@ -4,13 +4,6 @@ TestGroupAnimation1 2 -
  • - 200 - -
  • TestAnimation1
  • -
  • TestAnimation2
  • - -
  • 10 @@ -72,7 +65,7 @@
  • -->
    - +
  • @@ -89,6 +82,12 @@
  • +
    diff --git a/1.5/Defs/OffsetDefs/OffsetDef_GroinToAppropriateHeight.xml b/1.5/Defs/OffsetDefs/OffsetDef_GroinToAppropriateHeight.xml new file mode 100644 index 0000000..3fe9c46 --- /dev/null +++ b/1.5/Defs/OffsetDefs/OffsetDef_GroinToAppropriateHeight.xml @@ -0,0 +1,37 @@ + + + + GroinToAppropriateHeight + +
  • + Male + (0, 0, 0.5) +
  • +
    + +
  • + MinecraftCreeper + + + (0, 0, 0.5) + (0, 0, 0.3) + + + (0, 0, 0.5) + (0, 0, 0.3) + + +
  • +
  • + MinecraftPig + Male + (0, 0, -0.5) +
  • +
  • + MinecraftPig + Female + (0, 0, -0.5) +
  • +
    +
    +
    diff --git a/1.5/Source/AnimationWorkers/AnimationWorker_KeyframesExtended.cs b/1.5/Source/AnimationWorkers/AnimationWorker_KeyframesExtended.cs index 50af003..7546b67 100644 --- a/1.5/Source/AnimationWorkers/AnimationWorker_KeyframesExtended.cs +++ b/1.5/Source/AnimationWorkers/AnimationWorker_KeyframesExtended.cs @@ -15,6 +15,12 @@ namespace Rimworld_Animations { } + public override Vector3 OffsetAtTick(int tick, PawnDrawParms parms) + { + //Todo: Use this for bodyoffsets + return base.OffsetAtTick(tick, parms); + } + //use extendedkeyframes to determine addon facing diff --git a/1.5/Source/Comps/CompExtendedAnimator.cs b/1.5/Source/Comps/CompExtendedAnimator.cs index 17231e2..e1cb8cf 100644 --- a/1.5/Source/Comps/CompExtendedAnimator.cs +++ b/1.5/Source/Comps/CompExtendedAnimator.cs @@ -11,7 +11,121 @@ using Verse.Sound; namespace Rimworld_Animations { public class CompExtendedAnimator : ThingComp { - List> animationQueue; + + // CompExtendedAnimator + // Helps manage AnimationQueue, AbsolutePosition + + private List animationQueue; + private BaseExtendedAnimatorAnchor anchor; + private bool isAnimating = false; + + + public bool IsAnimating + { + get + { + return isAnimating; + } + } + + public bool IsAnchored + { + get + { + return anchor != null; + } + } + + public Vector3 getAnchor() + { + return anchor.getDrawPos(); + } + + //ticks of current animation + private int animationTicks; + + public override void CompTick() + { + if (isAnimating) + { + animationTicks++; + + //if animationticks is equal to cur. anim duration, + if (animationTicks >= animationQueue[0].durationTicks) + { + //dequeue; returns false if more animations + if (!PopAnimationQueue()) + { + //play next if more anims still + PlayNextAnimation(); + } + else + { + StopAnimating(); + } + } + } + + + + base.CompTick(); + } + + //returns false if still more animations + public bool PopAnimationQueue() + { + + if (!animationQueue.Empty()) + { + //pop queue + animationQueue.RemoveAt(0); + } + + return animationQueue.Empty(); + } + + public void PlayNextAnimation() + { + if (!animationQueue.Empty()) + { + isAnimating = true; + animationTicks = 0; + pawn.Drawer.renderer.SetAnimation(animationQueue[0]); + } + } + + public void StopAnimating() + { + isAnimating = false; + animationQueue = null; + anchor = null; + pawn.Drawer.renderer.SetAnimation(null); + } + + public void PlayGroupAnimation(List groupAnimation) + { + animationQueue = groupAnimation; + PlayNextAnimation(); + } + + public void PlayGroupAnimation(List groupAnimation, BaseExtendedAnimatorAnchor anchor) + { + this.anchor = anchor; + animationQueue = groupAnimation; + PlayNextAnimation(); + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref this.isAnimating, "animations_isAnimating", false); + + Scribe_Collections.Look(ref animationQueue, "animations_queue"); + Scribe_Deep.Look(ref this.anchor, "animations_anchor"); + + } + + private Pawn pawn => base.parent as Pawn; } diff --git a/1.5/Source/Comps/CompProperties_ExtendedAnimator.cs b/1.5/Source/Comps/CompProperties_ExtendedAnimator.cs index c74848a..47fc1a5 100644 --- a/1.5/Source/Comps/CompProperties_ExtendedAnimator.cs +++ b/1.5/Source/Comps/CompProperties_ExtendedAnimator.cs @@ -12,6 +12,7 @@ namespace Rimworld_Animations { public CompProperties_ExtendedAnimator() { base.compClass = typeof(CompExtendedAnimator); + } } } diff --git a/1.5/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs b/1.5/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs new file mode 100644 index 0000000..6116a8c --- /dev/null +++ b/1.5/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace Rimworld_Animations +{ + public abstract class BaseExtendedAnimatorAnchor : IExposable + { + public BaseExtendedAnimatorAnchor() { } + + public virtual void ExposeData() { } + public abstract Vector3 getDrawPos(); + + public string GetUniqueLoadID() + { + throw new NotImplementedException(); + } + } +} diff --git a/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs b/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs new file mode 100644 index 0000000..8b61405 --- /dev/null +++ b/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace Rimworld_Animations +{ + public class ExtendedAnimatorAnchor_Thing : BaseExtendedAnimatorAnchor + { + + private Thing thing; + + public ExtendedAnimatorAnchor_Thing() : base() { } + + public ExtendedAnimatorAnchor_Thing(Thing thing) : base() + { + this.thing = thing; + } + + public override Vector3 getDrawPos() + { + return thing.DrawPos; + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_References.Look(ref this.thing, "animations_anchor_thing", false); + } + } +} diff --git a/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Vector3.cs b/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Vector3.cs new file mode 100644 index 0000000..ffb84ab --- /dev/null +++ b/1.5/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Vector3.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace Rimworld_Animations +{ + public class ExtendedAnimatorAnchor_Vector3 : BaseExtendedAnimatorAnchor + { + + public ExtendedAnimatorAnchor_Vector3() : base() { } + + private Vector3 position; + public ExtendedAnimatorAnchor_Vector3(Vector3 position) : base() + { + this.position = position; + } + + public override Vector3 getDrawPos() + { + return position; + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref position, "animations_anchor_position", Vector3.zero); + } + } +} diff --git a/1.5/Source/GroupAnimations/GroupAnimationContexts/BaseGroupAnimationContext.cs b/1.5/Source/GroupAnimations/GroupAnimationContexts/BaseGroupAnimationContext.cs index f5ee3dc..d62b348 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationContexts/BaseGroupAnimationContext.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationContexts/BaseGroupAnimationContext.cs @@ -11,6 +11,7 @@ namespace Rimworld_Animations { public int actorShift = 0; public abstract bool CanAnimationBeUsed(List actors, out int reorder); + public abstract string DebugMessage(); //cool class for designating contexts for animations // configure CanAnimationBeUsed to test whether it can be used diff --git a/1.5/Source/GroupAnimations/GroupAnimationContexts/GroupAnimationContext_RJWSex.cs b/1.5/Source/GroupAnimations/GroupAnimationContexts/GroupAnimationContext_RJWSex.cs index 7c2033e..a0bb3be 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationContexts/GroupAnimationContext_RJWSex.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationContexts/GroupAnimationContext_RJWSex.cs @@ -17,7 +17,6 @@ namespace Rimworld_Animations public override bool CanAnimationBeUsed(List actors, out int reorder) { - Log.Message("Testing this animation"); JobDriver_SexBaseInitiator latestSexBaseInitiator = (actors.FindLast(x => x.jobs?.curDriver is JobDriver_SexBaseInitiator).jobs.curDriver as JobDriver_SexBaseInitiator); reorder = base.actorShift; @@ -25,5 +24,11 @@ namespace Rimworld_Animations return interactionDefs.Contains(latestSexBaseInitiator.Sexprops.dictionaryKey); } + + public override string DebugMessage() + { + return "Checking for RJWSex AnimationContext\n" + + "InteractionDefs: " + interactionDefs; + } } } diff --git a/1.5/Source/GroupAnimations/GroupAnimationDef.cs b/1.5/Source/GroupAnimations/GroupAnimationDef.cs index 36eb64a..c54984f 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationDef.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationDef.cs @@ -16,6 +16,11 @@ namespace Rimworld_Animations public bool canAnimationBeUsed(List actors, out int reorder) { + if (AnimationSettings.debugMode) + { + Log.Message("[anims] Checking if " + defName + " is valid animation"); + } + foreach (BaseGroupAnimationContext context in contexts) { @@ -28,5 +33,20 @@ namespace Rimworld_Animations reorder = 0; return false; } + + public List GetAllAnimationsForActor(int actor, int seed, int reorder = 0) + { + List animations = new List(); + int actorNumber = (actor + reorder) % numActors; + + + foreach (AnimationStage stage in animationStages) + { + //add all new animations to list of animations + animations.AddRange(stage.GetAnimations(actorNumber, seed)); + } + + return animations; + } } } diff --git a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage.cs b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage.cs index 58e86ab..b212183 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage.cs @@ -11,7 +11,7 @@ namespace Rimworld_Animations { //Return a list containing a tuple; int for how long the animation should play for - public abstract List> GetAnimations(int actor, int seed); + public abstract List GetAnimations(int actorNumber, int seed); } } diff --git a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_Branch.cs b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_Branch.cs index 889b06e..a187270 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_Branch.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_Branch.cs @@ -10,9 +10,9 @@ namespace Rimworld_Animations public class AnimationStage_Branch : AnimationStage { public List paths; - public override List> GetAnimations(int actor, int seed) + public override List GetAnimations(int actorNumber, int seed) { - return paths[(seed * 59) % paths.Count].GetAnimations(actor, seed); + return paths[(seed * 59) % paths.Count].GetAnimations(actorNumber, seed); } } } diff --git a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_LoopRandomSelectChance.cs b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_LoopRandomSelectChance.cs index a6fa374..09cbc9c 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_LoopRandomSelectChance.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_LoopRandomSelectChance.cs @@ -12,48 +12,50 @@ namespace Rimworld_Animations public int loops; public List loopOptions; - public override List> GetAnimations(int actor, int seed) + public override List GetAnimations(int actorNumber, int seed) { int numberOfActors = loopOptions[0].animationDefs.Count; - List> animations = new List>(); + List animations = new List(); for (int i = 0; i < loops; i++) { - - AnimationLoopOption option = getAnimationLoopOptionByWeight(seed + i, out int longestAnimLength); - Tuple animation = Tuple.Create(longestAnimLength, option.animationDefs[actor]); - animations.Append(animation); + AnimationLoopOption option = getAnimationLoopOptionByWeight(seed + i); + animations.Add(option.animationDefs[actorNumber]); } return animations; } - public class AnimationLoopOption - { - public int probability; - public List animationDefs; - } + //select random element from loop options by weight; also calculate the longest anim length - public AnimationLoopOption getAnimationLoopOptionByWeight(int seed, out int longestAnimLength) + private AnimationLoopOption getAnimationLoopOptionByWeight(int seed) { int totalWeight = loopOptions.Sum(x => x.probability); - int randomNumber = (seed * 56) % totalWeight; + int randomNumber = ((seed * 59) % totalWeight) + 1; int cumulativeWeight = 0; - foreach(AnimationLoopOption option in loopOptions) { - cumulativeWeight += option.probability; + for (int i = 0; i < loopOptions.Count; i++) { + + + cumulativeWeight += loopOptions[i].probability; + + //random number is same for all pawns because they all have the same seed + if (randomNumber <= cumulativeWeight) { - longestAnimLength = option.animationDefs.Max(x => x.durationTicks); - return option; + return loopOptions[i]; } } - longestAnimLength = loopOptions[0].animationDefs.Max(x => x.durationTicks); - return loopOptions[0]; + //default + return loopOptions.Last(); } + } - + public class AnimationLoopOption + { + public int probability; + public List animationDefs; } } diff --git a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_TicksDuration.cs b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_TicksDuration.cs index e502596..cd63ecf 100644 --- a/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_TicksDuration.cs +++ b/1.5/Source/GroupAnimations/GroupAnimationStages/AnimationStage_TicksDuration.cs @@ -7,14 +7,17 @@ using Verse; namespace Rimworld_Animations { + /* don't use? just use looprandomselect once public class AnimationStage_TicksDuration : AnimationStage { - int ticks; - List animationDefs; + public int ticks; + public List animationDefs; public override List> GetAnimations(int actor, int seed) { return new List>() { Tuple.Create(ticks, animationDefs[actor]) }; } } + + */ } diff --git a/1.5/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs b/1.5/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs index 830ac41..8980cec 100644 --- a/1.5/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs +++ b/1.5/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs @@ -42,10 +42,9 @@ namespace Rimworld_Animations { List participants = partnerSexBaseReceiver.parteners.Append(partner).ToList(); GroupAnimationDef groupAnimation = AnimationUtility.FindGroupAnimation(participants, out int reorder); - if (groupAnimation != null) { - AnimationUtility.StartGroupAnimation(participants, groupAnimation, reorder); + AnimationUtility.StartGroupAnimation(participants, groupAnimation, reorder, partner); } diff --git a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderNode.cs b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderNode.cs index c7cff4f..d482853 100644 --- a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderNode.cs +++ b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderNode.cs @@ -18,26 +18,28 @@ namespace Rimworld_Animations { if (__instance.AnimationWorker is AnimationWorker_KeyframesExtended extendedAnimWorker) { - //INVIS IF ANIM CALLS FOR IT - //replace maybe? - if (!extendedAnimWorker.visibleAtTick(__instance.tree.AnimationTick)) - { - __instance.requestRecache = true; - return false; - } - - // HEAD ROTATION ADJUST FACING get rotated textures + // ADJUST FACING get rotated textures + // compare the previous tick to the current tick; if the current tick rotation is different, recache Rot4 animFacing = extendedAnimWorker.facingAtTick(__instance.tree.AnimationTick); - if (parms.facing != animFacing) + if (extendedAnimWorker.facingAtTick(__instance.tree.AnimationTick - 1) != extendedAnimWorker.facingAtTick(__instance.tree.AnimationTick)) { - //requestRecache or else it won't update properly __instance.requestRecache = true; parms.facing = animFacing; } + //INVIS IF ANIM CALLS FOR IT + //replace maybe? + + //cheaper call now comparing prev tick to cur tick + if (extendedAnimWorker.visibleAtTick(__instance.tree.AnimationTick - 1) != extendedAnimWorker.visibleAtTick(__instance.tree.AnimationTick)) + { + __instance.requestRecache = true; + return extendedAnimWorker.visibleAtTick(__instance.tree.AnimationTick); + } + } return true; diff --git a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs index edc16af..6acbe35 100644 --- a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs +++ b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs @@ -28,6 +28,7 @@ namespace Rimworld_Animations && node.tree.rootNode.AnimationWorker is AnimationWorker_KeyframesExtended rootNodeAnimationWorker) { + // this is only for the Vector3 position to work right parms.facing = rootNodeAnimationWorker.facingAtTick(node.tree.AnimationTick); } } diff --git a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_Pawn_DrawTracker.cs b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_Pawn_DrawTracker.cs index 65b34e9..8b467e1 100644 --- a/1.5/Source/Patches/RimworldPatches/HarmonyPatch_Pawn_DrawTracker.cs +++ b/1.5/Source/Patches/RimworldPatches/HarmonyPatch_Pawn_DrawTracker.cs @@ -9,23 +9,18 @@ namespace Rimworld_Animations { public static class HarmonyPatch_Pawn_DrawTracker { public static bool Prefix(ref Pawn ___pawn, ref Vector3 __result) { - // If animating and is sexbaseinitiator jobdriver, - if (___pawn?.Drawer?.renderer?.renderTree?.rootNode?.AnimationWorker is AnimationWorker_KeyframesExtended - && ___pawn.jobs?.curDriver is JobDriver_SexBaseInitiator sexdriver) + + CompExtendedAnimator animator = ___pawn.TryGetComp(); + + //align pos on top of partner, position, etc., based on animatoranchor + if (animator != null && animator.IsAnchored) { - - //align pos on top of partner - if (sexdriver?.Partner?.Drawer?.DrawPos != null) - __result = sexdriver.Partner.Drawer.DrawPos; - - + __result = animator.getAnchor(); return false; - } return true; - } } } diff --git a/1.5/Source/Settings/AnimationSettings.cs b/1.5/Source/Settings/AnimationSettings.cs index 0a96621..f320fa2 100644 --- a/1.5/Source/Settings/AnimationSettings.cs +++ b/1.5/Source/Settings/AnimationSettings.cs @@ -29,7 +29,7 @@ namespace Rimworld_Animations { Scribe_Values.Look(ref orgasmQuiver, "RJWAnimations-orgasmQuiver"); Scribe_Values.Look(ref fastAnimForQuickie, "RJWAnimations-fastAnimForQuickie"); Scribe_Values.Look(ref rapeShiver, "RJWAnimations-rapeShiver"); - Scribe_Values.Look(ref hearts, "RJWAnimation-sheartsOnLovin"); + Scribe_Values.Look(ref hearts, "RJWAnimation-heartsOnLovin"); Scribe_Values.Look(ref PlayAnimForNonsexualActs, "RJWAnims-PlayAnimForNonsexualActs"); Scribe_Values.Look(ref applySemenOnAnimationOrgasm, "RJWAnimations-applySemenOnOrgasm", false); Scribe_Values.Look(ref soundOverride, "RJWAnimations-rjwAnimSoundOverride", true); diff --git a/1.5/Source/Utilities/AnimationUtility.cs b/1.5/Source/Utilities/AnimationUtility.cs index d06d203..71c785a 100644 --- a/1.5/Source/Utilities/AnimationUtility.cs +++ b/1.5/Source/Utilities/AnimationUtility.cs @@ -21,15 +21,42 @@ namespace Rimworld_Animations { participants[1].Drawer.renderer.SetAnimation(AnimationDefOf.TestAnimation2); } + //startgroupanimator with anchor + //don't anchor to self if anchor is self + public static void StartGroupAnimation(List participants, GroupAnimationDef groupAnimationDef, int reorder, Thing anchor) + { + int seed = GenTicks.TicksGame; + + for (int i = 0; i < participants.Count; i++) + { + if (anchor is Pawn pawn && pawn == participants[i]) + { + + List allAnimationsForPawn = groupAnimationDef.GetAllAnimationsForActor(i, seed, reorder); + participants[i].TryGetComp().PlayGroupAnimation(allAnimationsForPawn); + } + else + { + //each participant gets their own unique extendedanimatoranchor, important for scribe_deep saving + + List allAnimationsForPawn = groupAnimationDef.GetAllAnimationsForActor(i, seed, reorder); + BaseExtendedAnimatorAnchor animatorAnchor = new ExtendedAnimatorAnchor_Thing(anchor); + + participants[i].TryGetComp().PlayGroupAnimation(allAnimationsForPawn, animatorAnchor); + } + } + } + + //startgroupanimation without anchor; just play where standing public static void StartGroupAnimation(List participants, GroupAnimationDef groupAnimationDef, int reorder) { - for(int i = 0; i < participants.Count; i++) + int seed = GenTicks.TicksGame; + + for (int i = 0; i < participants.Count; i++) { - //todo: pass all animationstages to ExtendedAnimator, and queue animations - participants[i].Drawer.renderer.SetAnimation( - groupAnimationDef.animationStages[0] - .GetAnimations((i + reorder) % participants.Count, GenTicks.TicksGame)[0].Item2); + List allAnimationsForPawn = groupAnimationDef.GetAllAnimationsForActor(i, seed, reorder); + participants[i].TryGetComp().PlayGroupAnimation(allAnimationsForPawn); } } @@ -38,13 +65,13 @@ namespace Rimworld_Animations { { foreach(Pawn pawn in participants) { - pawn.Drawer.renderer.SetAnimation(null); + pawn.TryGetComp()?.StopAnimating(); } } public static void StopGroupAnimation(Pawn participant) { - participant?.Drawer?.renderer?.SetAnimation(null); + participant.TryGetComp()?.StopAnimating(); } public static GroupAnimationDef FindGroupAnimation(List participants, out int reorder) @@ -55,8 +82,6 @@ namespace Rimworld_Animations { int reorder2 = 0; - Log.Message(DefDatabase.AllDefsListForReading[0].defName); - DefDatabase.AllDefsListForReading.TryRandomElement((GroupAnimationDef x) => x.canAnimationBeUsed(participants, out reorder2), out GroupAnimationDef result); diff --git a/Patch_SexToysMasturbation/1.5/Assemblies/Patch_SexToysMasturbation.dll b/Patch_SexToysMasturbation/1.5/Assemblies/Patch_SexToysMasturbation.dll index e21340145df82a2c120b0fcd500136f6b5ff17d2..abfae70b07947ce717fcd7fc9bf700d598c2f32c 100644 GIT binary patch delta 47 zcmV+~0MP${D1a!Chy;V`zP_=H@C5{_A~FlJfCdZ&5Medt;MWnWK!gVRs}8@^U$dMG FWC-G!6cPXc delta 47 zcmV+~0MP${D1a!Chy)RN_mi=V@C5{?B93CSfCdZ&5E1Sy1n{?=MTj|Uh@6uaBeR?f FWC+8y5@i4Y diff --git a/Rimworld-Animations.csproj b/Rimworld-Animations.csproj index cd6b26a..2317000 100644 --- a/Rimworld-Animations.csproj +++ b/Rimworld-Animations.csproj @@ -77,6 +77,9 @@ + + + @@ -114,6 +117,7 @@ +