From 93389f6b30d630780c57d093e4082025fac07805 Mon Sep 17 00:00:00 2001 From: "ProjectKoi-Kalo\\Kalo" Date: Sun, 27 Jul 2025 16:20:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9A=82=E5=AD=982?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.6/Assemblies/WulaFallenEmpire.dll | Bin 68096 -> 72704 bytes 1.6/Defs/CustomUIDefs/CustomUI_Example.xml | 30 ++- Documentation/EventSystem_Documentation.md | 255 ++++++++++++++++++ .../.vs/WulaFallenEmpire/v17/.suo | Bin 118784 -> 120320 bytes .../WulaFallenEmpire/v17/DocumentLayout.json | 5 +- Source/WulaFallenEmpire/Condition.cs | 64 +++++ Source/WulaFallenEmpire/CustomUIDef.cs | 2 + .../WulaFallenEmpire/Dialog_CustomDisplay.cs | 90 +++++-- Source/WulaFallenEmpire/Effect.cs | 101 ++++++- Source/WulaFallenEmpire/EventContext.cs | 52 ++++ .../WulaFallenEmpire/WulaFallenEmpire.csproj | 2 + 11 files changed, 577 insertions(+), 24 deletions(-) create mode 100644 Documentation/EventSystem_Documentation.md create mode 100644 Source/WulaFallenEmpire/Condition.cs create mode 100644 Source/WulaFallenEmpire/EventContext.cs diff --git a/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/Assemblies/WulaFallenEmpire.dll index d62c5b8ba9a8c0b4e9263fedc1056a8363021b7d..74c54aec4a296cfed55bec1f5b7b6167c7c6031f 100644 GIT binary patch delta 25680 zcmb8Y31Cy@(mp=tBsp1{ra5VowsbEP(uLB6rDc=KS{9*#NL7RiRf|BOEo!YbO#u}J z72}2=vZ;U~a*GOA@QMOg-0O0ciz0}kATGG$)%t&CPD+c{@BjP0*i7b`nRjO1d6#qY zCc&nA%uPGYcio!awBYxrDf~D>>8TM)9#M=!q#44W3YTx5?AlPM(0CRMQD}#0d0Mn{ zxg*Ya3o06^gLeD5YlrEveN_zYUFyzN5JXNyL2aQBe zA+mCRP*wW1Oi))U3G0Z=89igW-?SD?oAw5hsD-^FqiJ1>W*(s^ceISNToqw^6N(JA z@zIuD?p0Rh{Fd^#iDu>P(3Zs6%D+QhlBOsvq1vQ=ppPdN_WE19({1APAUpj{oU+D` zZf5(fOl%;HEuqNdbmdSeFS$YasO5>|E6fScwmW!692{i_xe90XY)fX>CzNT&AaQ7> z#+}fUC8o?}jw#a`7*$_`Kn+7-9A7;Q^rju>`uc=@4HsXm@#{z-!d!g?T3OSZ#=kUD zYtudreb{3_OLc}zo%TgI(5`a=G5W7S&$S2oJD4`@^Nv8Q`O82jT0ZQNp}J2>5Od>h z*r8L;hxDuhCj&`KYuFtcpOp~Df_NVuvHnTOKb;09jzF?shMKed&gVOOSgS=O_gYHKruZ?){~^+Hs@t{5eM7dE6d z@Jquq1B%XmZC-iOFeU3MrT%aB!WS2&~h(GVHEAKEq~QF%Y~#*lpF{ku!@11$INM!RUc zZqKn(OteIC;FwAM=_ZFc{69Hy|a z_Pk4?%`p6RsBXR_+9FMu)4(;0%$kn)s<5_nYDyo*YCF_7hzwDh;zSmqTXg%BXs514 zM}~vyPVNK^xis1p4z5SGOQJk(-K9sNk>)o#u^63*@qdrRqJ6qAMQ>z*zB<|Hdg%L+>53lmjYBUDI9MJ7pu(_9jnI{x1z=vBV!h@qWVAV zA+G2_h&^%s-x$S{8qnh#mO}06;(rX&IXXd4h)&cKb8-o>;u~&bmx$POUiI(XB1uom zagz$o?a*+h8vJFCf;FtZEip{n*fd#B4m1Y_|UufH=fUH z2p1cNUjZ?4Q^EDW<*{Y%}l&=jgIP0zGI z8j%zX+$kHYM7kTd+Zxb#s|7;&2MV#=%kEK@_#k zm)Vgre33N^v5bsUD1QP4qJSwHNp!{QAWp*6u#5}(6^aA*$ifj8MP!@J;v!x3<2r$^ zgNZ<_P7M1pQ7L>4W?yQ<9q<+Fcf!h{VMat)bG+n_1k`wQ&;r#ic0k!lR5LS*<{1rY z&Vcnlg&6*oNP{H66I{fsEHcGbN3{nvWJb_l2x>Nh-UTj3a*rhSrW@g+kwr-7PQ0iM z3}XFmcuDBwnlqmTC+8VXmWN bcrwD8ugoZH#6%wlM}T*wmK8N3|EcR_y~tsc?Bf zFB;w4i{&AGOk5zGUUZ(7u7l$thU2@@64{{?E~-vr5fbvDME5|VEqw{o#E%Ox=56)>wL#2Oe>}`0?PtwwOZzAtW-;N$ zhBX=oxOGQl1m#LJ;T3C*CkHNDTnTg$mH3&vB*UFOBU}mAcT@s_&sKspe_e?lYQz0d z`uxd=pB-V;#mXfyqa>(^ZvJygBr!96gV&)(Vh<#=P!{W2IX?j1tv-l44vNnU;b_XG{R>wfn^ZCOluGJdeO^qEPrnU#$xk683 z?U;Bhj0JtuN=~lY4<)uEoeXTM&J>5)QD+5NBBOsrd9WZxRaHGgZ~11GQlpP<{7rCISJZn*+P{~x;YDp@t#bSPhG~4A6IK7aD|a( zbuRa*rmq(bjlSg8_JXL1Ytpd+^U|`=4RA5Sn8B-{j`63;b;MX=iDas2h8wkkbu|yL z$ET2B8K&w8t@yD{>D+Soz|D%L+C%Q_YiS8yYs6pF3Da*>))9qD9uoY_fAk z*gCLLOG1l~&`2Yp)$pAD#~*<|{ArSu@Ur$h5@VZiV%WPRvr*X79)`G0?MSExVtywH zaRWmyJCSDWNB_^%jA~UY^8Qk<^J*op(n>CpwTO1hbV=ih;iL*tj3LA?@;l$kxFSOIIic|J`h#+1#uQ(114K_Kk!&@ z4Mlk6`zs!vM(hM4s4iyn{vgqo?6Dq;e*m)@>6*vtPY?Y%E-?>@nANyt@t9y4v9U|v z#_PK3K``r%dx!o+Xfzn8=i|6}u(bL5g+^R(VW1(F=EcPL&x4|g9c1O!zK$VoTFd;| zTYxOn0yBDvtg>c>ZwpjY<9ZJ0AA+WhkFdFhxgL$RcrCg!8WTfpU<<5jTQ+I2x#n#C zZ?Z2-^-5Dz?a^2m_#+T7C*EI<;i)cxH^@V|;}ZgpLfMF2-Q2hV1p64fi#^-imzAtG zuqLZZ?fGbSLpwxxz7Y1q>zK1?q_h>rsSTW`WLy}b`iu@ZvZH;q*!%Im9f6^5WTIsy z2UP!i5Thd4`Lw2O9O-ODl1&Xm5wk-eLCw?`uVWF^)G!R{o;ik@+OQq1GkW^Et7@C} zA>7pthdRU2$a2l!6{`kkBw2mch874+)gz$2B8!X3z36ZlTX@#v)15pX?&Oi>|AR+# z8JI}sp-mI=Mi_T_&zq_%vFdX&Osbq$_(yX7u?8^ti=d13#`yfBAm&taYmc+5 zzn^uLQWn?$zg_Ku{;Vqof8mOY8k%3`3+z5?oToN0_>*x?yeTEhUy2M2br`hq`BK(u zB>wza2S}X3pB%7VrwRNIScE6=9&X8(5|yxp(KwkmtaoTBzvmhgSj~3QVXNx@Hk5mz zU-?Jq;tTr)*aQ<9_v_fJn6_!Nc`!yJNq;vCD@I)84VR*V2J5ecMXb+1Rytxdn!}C8 zaia@BV&nW7XxsRbcyD*l$Uh5))hSpijr#xtYRd18oJ00N#9>KwGVAt(BS`qQ@dXg9 z9yW`0e1zFe?X9q+#WdVhF5b_ggNVT@_6H{%*KiUSc5-+o)-d~;-|jIw?9t~qY*YPThd!O?m*N_!)04sZj|V!aEUl-BNLSCRpwt|p3C){QLZfG-6G0`>qmRJu&o;9vd}w9d%0c@StpMR zuocSn7GC1~J!GK>Fhp%y9o!nL$lsxqMI@(tIq8OBhs41CYP74yi8OCg?L)vp#4tPr zIL8U_7;p|U29nIVW01*X07G0-&$Z(*IP1_D12Ky~*NoJ-IAc5wFI~=62QV|(i+>*S zO(%Ncyzqt)7hd|}GvVAu;lrxi5>2w{xVBAP^VcU zu;T(cLFNh9$CxKPq8;;u<;FZ|Lk7H*IG;u)GB?b)`NEaLikBwbk94|zh9*o&P$ELJ zrz8)17mBl&2nK(#Y3J7BhF@#K^|+IdE~uOF9yB8K#uT4%t}2(U3{{R&|Kupgg-gWy z9Bm3#4(5jg_az-y@GFe73sv6e$N`3Ne$io3V`|93jwWw{RJmVl;AJQG)L9goQJxVv zGJvS-O}Jza#3vu;fuC4cQ#JRhTF!KO1JP34@pQdtBAvRM$PHQ7kr$N?!|QLr+tHt{ z=g;Q%iSkf!2X}GGx(K@q@K>dfd=P*g4{{-1aX(7@Da(_1jlq+9MG0VVCq)xN`X$i; z-1bQmD_*g63XhqM$Btxng;AsFF%7tneO+j2bpM&i zULTR-prM0tgGyBi`!tQNDP+m_>8$mcG;1}fxC?a9^KmRmjplUsscbU?9vsx*WBOJs zM~TSdC_Tl0PLBYGkN4l{aM7+Lo9?10PzRaa+~746(+j$CvnaDo*XUMpy-C%q4tf}J zjizMWUyLN8Mx`@c)uTN5~~=_%a% zbm?VvT&Y8&1`|sTIk;6$;%bkF1`XV&1swE_mDQ`ITxF@O?&;^M^ebk5i_>gz(1r}= zRY~+mjU|T%l{!4s(0?D^J59)BNkxCAvn09A$;|iku^$)0<4t%W(??>N4i*0K2=D>g zUc|0)=qxFeB>G2k;P*XDAC0K% z=Aety*uyJD%%@5!`y`2o9&8i%PI`GWLi*^nOfK?nahfTnkN4un)Le&FNg~i@JYa=%FQ2p<_kt=K`6qL%S|abI>5^*lhtB zk87p859jivcqfjNSfX*CeoJP_wgjG-BT|{>=diZY!(&{BN#~$rGH+rBbAZI|+-fD} z1nMEP;a-_Bf8?nFzt^Bup%;&>GDBL3qu3gP7GQCdSM~*;t(#&Bo%|0LDgD(S8l`k*Yr?b3D@+B#@NCe!1bR)7{tsYfD=gVMy& zjWVL@@L2SrJ+8zsQ=Sey=eT6%wF2J=g$ z?I9;y&N9|ZPnHK_CFC|4p??Zhd0mo4_|u^OF}eHj=;|VQT^8p~IMS$Dh9FmFPf+%Z zp%VUYGGwnv`28~K!;qXt7Fiws0bJL)G6dZN()%`XT_B?0HO_I3QAXM0?vzcb(aZ9c z;_jr3?ljp6t`H9=q#mcFm*cU!Imjv<`%voFrI@?4Rkod*r5>jwxs!teye;Go;FA6) zgZaZ6)BB{^2fevjjqG~=M#yAJw(ugnrqHG*)5}htXfs6nMiPfCl0lp%;a`+sNj=!Z z5bPxy?U3afna!40$-w=RzB&N#wv0-bNZv+%^z%0IP!X5t?iAi??i~DiAtoA1=b&CF zuSS=67N&VW#8Cd(%CmW+MnKn^nj>qw*fW%35|xRa_>;tSc-GqLew z{%`KeiskvGSVu$^W~MmTryy=WhIkI?C4v;7cio3{8;}`KH?7J(q+diTSt*F)%aI9( z^hzMsyJ-(}K_I)JV?fI(33G^b^9l~>yD1wVIRORe$=E~sY09M@qCB2_NdKLRC{xfU z13AP9>LchSpiE^HPEgp*tByl@AE5q%W)482Km!Dg1u9ia(UL81=yOOPr;Ni&D^z4WmE;;5cPGO%V7h8Zw$9Xugw8C(v~1;aDVENo705wq5#&iZr0-Ow)9r%#BJGQ)mX-=ijt_82 z7tk_+Cz1C)Y}&=srPr0+lK^(u0B~#POirL@NbF3_7I0t^{e7piH1rpoaxb z1o})_L~8`K^*^Ma09q%g(03>RH#gHJfxXhXG`G=anR+t|8QnpTi!R-ANZ$ptMbP3d zjP9hZf|f-ZXq%uilzSIW`&$GZNM&?4JuT>G7o&UVSwVY%0=v+^odSQ+S@{4xCnMSu z1+GN@b_;s3*g(%qYDdx-t)dsDT~4n<`WHZZ1=XS4U(jmWFYV$I-pr{)-(MDVq>F(L z2>KhN0FQ@T@fPFb z{%b&6g~k;ye`8OF345B*XM|Q2eGPkWBGagxXmZBOU3Jh3;^Ys6+v)Ozr}bcZRQ4it>F+!+Y-IkNl zI{nSe^k2gNWDYQxC*UqoY#07r@cC34$<3~@bG~JHJ~+A}HxWs+<@_C&m6;LT<5!DQ zA=%%btMWiH(*g%mhtMzW%rEuvLVdNk8!YpSxCW05bePJTW;*qh1tK`H9C^)j=;F0fkx>LVV570~bi;A!|!wzFg+e zX5UiGiN;8l98YBrkICR}_1CEZyfKR9^2R$^@k~E9st}1Hk_Scds9u2F%ktUv0i7-P z#W9~IseGEql3g+QFEiWv3qvXLQQCX!m;l`#EUvi>#Oqv2EUp4ULq z*}k1$k54f_cGSi6rP1bk4Cny52}wspb5#cSyBYj=E619ctHx;BR{_f!n%q>P-ySo$ z={^h7XUt6hE&Q*-*9m`*@H>S606Yh{3juDRdy$H(Cr`%3Vwr& z38{kUk%Bu>;C^Y07R4oGYh1kL-Xva-Xnx1Q*csrw~1ns99t-IGrFND#h+Ir}Q^Wb`g7(u(2`|I+-7t!@5jaAScdId6<44$mrKWo!gmlR%m#M zvG$;Wf`Yc2i`RJlbZZ#Bk$BwXr@*_0sVyG!(obIq+HX@a+5F@@kKOFI-JZ;*7YgE0 zn_%_RbVElUBx!iF@<$j|Br|dkk#;nq%X(8LT^2@hmX+2_S{Fv!F-i02iGV<3aplob zLuux_59K0$r4hcAD#D1vm(olFN%&H_ zI*d5{Xj(dwo$e>@?>PEFP>>!%zzLL6+7WOP`OiTEfe`;bYVLo=JBe-;B_p%%V*2nb zI^(^B{G-`T&^F4Mtxlz}VYDOTxM?aqAZS1Fh)$)a!)Rg`MyJBalNaTiO0&kWm%VgJ zuNdFubOWOR3N^e}3gB{48Y44}9uyR$IZ6+jMt={Z2(_ng8vPPR#kc{PPCtxgr;BXP zh-`H_#f>x2+&;^d=`=*pe&X=cX^S8udX`LEG`c4_AFn|LGA|(6lnKl&i}Oy80Y+pMl_|*f)bV2r|6Ppy?CC zUIK74lOp(SK{$LR#Rv*g6%F=P(hxyLz$Ophp0YO39m>L-Fn?t|y=OXA659M5ny`-bzT=JiTzBvb_Tq>66;aJ~X z$}te_h<{O;OGSeAlbTc;SxsFoGa{@-gn3jdNU9wGyezDIYw(4>dGwl~z4Wy<#W$a3 zPvwTZjHml*sN3ZdP|96L7YJHzJI^=ES4Wo#+E3#KeiT_p_Xsk)ETGuw9qq2Af=(!K zEnUzFUQ06t?Wfy{+&HXAoxu(FQ+=X>vx>2Tj9GF$U33nb9k#ruC@$)H`nr>@fqpi0 zwk6&uwSjCi*(ZCM=flTjc>?#-7dX(mk**J;Bl%mSZlt`c*)&LbY1jE0>7FpUt+3g5 z6U9{-y7lRI`kH8@AS1PAns5$cJ9NVGbF!RtTWD1$-7S<7xTd4wt>hPEG`y7_=%iah z8#?KhP~Pm0cDK<$K}NgVsNb9p-R(3=&~nPODBj!YLqYdZn`^c2cFLJ67lQlfOVoMl8%Q>e=cOx zufn?Me#Jn)gmtU44#RRl9jA6wIg&L2x}k!ML|4*yK}KpTX^NnQw2)4q-E>BQa4}ZV z?69)J^rLSTJsC!uOuzXaqFrIssQ&0%O@D;Zx6nOIkqbDy5pWH~3o-((p>#nDahj#X zuA%;6)JL&8*3xJ}0mF11O$;k9Q>~75v`~=YbUocE$go^b4}>k*&3f9{Nw~#@ z10C(8dxTDfb&sOmBUE%Pr@b&hgJJq8O&7=^6nczq6l9FkM%oodJWLzu#_PFZkdkm2 z+(;_~9knm-YmMDVYYn9Eplzg$VI2?JMtUl&yCf?Tmfwd_fJbd3{YRh?ek1wnIfM~@ z6UBuQhu=g;4I}|K(TT8*18$;k!#WPQiGB&|IN&B4d4u7T<87kxf)Fo&{%)dKVI|MY z%``iVIN)X)bE7nrfSYNefux6<>5{OH18%07VI2qDOpk>T2i#0s1sMannVu8G-NhTB z&9qnGLYy929h>RHvq}x8u%Cr>Jfe?NdLt)exOswd1+g2Ao}hk$7Sb^#F7^o;+)1~E zMum0vV(hoj9UVG+5J2~bmCcF<^i+ouXlGcr7Y(08Xob?OZnsL`bY=cGyhl|jvk&u8 z_|}9<`|}8If!_gD=mxPdXuo{cvJDQ55}1zd&5{5E6YcE9qV;$Ktk9QetkTD5Y@#>q zDn9mDsq?Q7d~i8B!w;UwTC2p@14egDl|3af3OUQ zQ+A<>Qd3u+NuYGb_rH+)>!%{=yPR(PVq%t;Z4B+(GC=>(API!$ zFpEso7yaV{Kc)$VOxH<(d+_Bvm5gSqWX>D>0}}ZEN?*Y$P^pI`6nMqWldB7U)1)9k zXUgFVoNQ`j&1F|X`R&286;BtQfqftc@I`75 zo~?Mg@Z5*z0epzb7b6`M$Hbrxyv0w*cH^LvX|d1}p`}90gq91f0QKSx3|r0@S}$}h zs78B0yU=Oo15~9XWT(**Wf}JV<#H?Hq=J6E!FTP=k^=1QG4w~)2wJQB!50tMYow?N z*^|Z5RD4T;C5h6in^>L^NxV5ByPnEGakwl;g*(-iwjNY(uF1HMg64pG6$OH{BykN6 zY24?nrzH?QO3Te!>Sjn>knB{K;!}td%DvilT47${-AQ|t)j0Iuqp)^4dhk50HK!)- zgJsvWS7-&93g4s(WwPZxT0*xZeL_3UTN1uNcur!EIZ*r)0rS*px8ug2MBrV_Xl1!<+3 zI4^3Y=Y)^6Gyj?gS9{a4%!iPQzw3IWG7{fLtvBD9y+yHGRC|lE+}ywa4!Gk}$V`NJ z5j>wk>XyDqZz}Pi$CNb7u*e_KrJvL6YMJtYDN4<^JYe#w#g-U7Ni9_#4`gJkB^H0z ze1N3%0cxpb557fNX8E>Yl)6)WvFil2+=7u-D=eS)u28EigNtUV^DVDL)v3DjpY(dP zTIIW0t+$M~ECv5Vzg1L@RF5^2|tZ3UANrM})2l(9T$ zIptVtI%+vla33TK9ji>4$}AiiAD}@vcSAxl(avC^ov>V#@|dYaB=rg(thR!G-E`X0 z(*Hfv8Ot+{k4=GAL=!e>4Rr*2Bqp7kV|xm7pwPDpai^%8iGIeNfPl&`H%>SHcex_L^>!{~b3 zc=J)wo(?F3GbWq&nCJBWiOxWDnYmQ!o;$-_rhVS~YVeNK8K6TUDb;+S<=PuPt3kiX zc>t8>N4)xy{bBPNWqsNPv#z=dH<>flKeD!(^VNcWJn0@!dm22ih;nUB!UN`b#TWg7 zxk@_~aoC)u1|BFlX)acE%=UWi=ZNp2sE9ml-l>|h&X|K5c0EfO(ncL^`N`o6>`VXf*+no03nOPMaHSms^i& zdj?lpPndu4RYU%d$dj<-i5yfnMjkhv&`SE;Xg#gHj}MzqYwNr>!#{t37znES^6#)N zl7cM4JAYg%R6eo}s(c!@Tryp&F7LM08n5ood&#O;AIp2$x>V|MkIdu~=I7$ttgSRI zN3+?juUmWL_isz%+_p69!`3dgqvrUYskVIUHC-}nnbya>S+*1E=e_f7CDw<#^tb5& z?UADOrZVg2y~o>_PPUa>pY=?$9mE8gZL6@xW&e>Jl_o%bX*V{K)cW2&a4_Y60t+F4rTsP=n_Jisf?GtEs z6n+lNS@GG}4XdJlft-iwfc10h@8G#|2UR`_Zl#?ARY$A!AHA%O1M0=y;v6N`1>SVW zK}m6^IwpXN%}(`Atj<`d~>GR$fMC9AvPrev7lX1;7eaVVmDwJMS`|@YbDZ~V z#8K_pw7n5kwg%gK5eJnkyz2v|(^_KgN8^eZKYDqb z^)^1){ZRVxsr2JhNh@gU*X=@Qy_S*X)k-Caauc8PF0m!&&vKTV%($*Dx4mLo<6L6< z+P~4c!ZtByho#%A8eN_*S+gGhc5 z$r9V!h1c8H+E%50<}A0Yw~vdgGToaoF|ypmqh2oI=Z9${ZaT_TJ^?OM`Q&$-t#49& zBv0g3k*)Z>SWD!YfO$aT?#Lz5V2O#(Zui)dV}FZ0VB2r&Vsm1@yG99GueC?IcB=1S z<}Wv^sXLSt%J;q3VA|e4aEg6}iH~Ymn0NxNz_`wFwc27Zphqq0c{Q$swh}w9risPh zYpu4_OpkUDSA^?a_2w~&LDvae;9%S>uA??j=2F*A?fLw_xfJ_*y`OcZnZ_lrqBPUR z_%T4exjEx`m)-7+-RsirUEHrDl}TxDyW;KlM;vl(L+Zy|%PlQYr(Bu#ha=9o)|#5S zazY>EB1IFQ9Ir5$UCe)jTig}W)dMCzCq7_W8i-4cDz+c<%yE_26S6a+6#J{abD`il z+zQ$^s@1f?<1n?Fjutch6kqFUHSt;T3C)cD#VAdM<8e((8SsI*+@6qib5yJHUczzQ zH>j!Cn=0%J2Q7;#xA*qkA9cp^K>rQU=Ew!zE3{Alz;V+-2{zxJkh(Q05x3YQm2SA{ z?o9_x&lc~Gnr}}pd>xISEj}DoZ~wga>8PN6VCpYX-Q-q%zMb!v%53KI-0t4ecA&H! zDB58n87q>pA~}GWq|qdW?*Qt}mnO~)xR=;hTI<}craF(8c;Pj;&qzY`=C`^o1%IUQ zZqRMG**a}H-u-^}3j3Ea54ks)K2F%}j@Rz>9CUB8-|IQzo{71FDQ5pTy{oQRM;5$n z-J?w{enZ=7kILw)@3H?UeW*TD;Y)CxSWZ&-vKP1!IgX%3l4CyJD%_&iiP1p}$KCo; zWyk=JbEz^YSaP6>7@NAHXPe{bp01Z!`5??s2)w-%Bc2XBHjs?3ML0Q+A7d$9pO7dP=M{-j6)Rj&Uic zJgE+ z+T!QI=9!d6G%k(075t;%>mAGd@8VwyvD4vb8{X9%iFV@Kil0TRw2iiaJ`L)@ck#A? z-z}0>SgQ1q(BJVzAOO3NDUss?UKw zp}qk6l)4XeyZQ>~4)smYUFy4_FQ^Bjb18!Ej?KldeO7`d(BDD3Qs5=LWYa;=LZJhM z4keb4p^rf)isVwEGw5eXuA#KJT%5?~#?7DxdM0{3PPD)1a!h!WA`*kD$EYIVCD64= z$3PFK3^kdQXQGdoLUdzXn)ML98tAg#x{#vNUIJa4b__H>-DJBRPP+=7A#|b8^+I0~ zdQ7OvE|x-v3Y{Tzq0se0UlMvusL3JrLWc?sq&mMuupvUH3r&p-(LdvcfJVeOMRJ2R zLSGO%#1*0`@l7s~3r%$k9~+^pjHmc$^eLZ=ID61pbU%!<(8me%E{ z?gDqY`*Qap_XhXd?$6!7xG&PT>aF@m`U$ZRv&Zv`XIgY9dUbSY$g*L966%fv z6+dQ47VhnF_NfcY==a+!qRy+dq?Zh#lNda-BNwYhXS(H^g9(0TIqCfGs6<_)%$yn!f zNOom#tNaM&AML}5=I382^ctb_K!^IS1zqO75j3}NGw7_ow}O7#CzXG(*AD)Q53Rf7 zNZ@V!VqC?I(0I_(_!hZJ-(x|kbOzrASLr`=F{q-HgPN2}ab~p!AN-flIwccygOUyU zsL~U3qtXj>vyu<`1b*>1nm&Z(XgUnb(e#Nj2=r4}j;7rE z*NBUriF!Wjy{L3|mb=tl=B{*acSq}8^f~$h{U-fk{YBmCxx{mYr`{9vyy5xHlM!uh z;*-A4k3%{ir*=FxM86d}dRKJdd>jz|`7sJ-mVEqZ!hh|LfdkvQj@M~ocdpk{i1X)1 zp4bh+L2e0I>3p0W4#iiphT%ETCDq#V?5Qa;n`&G&dhl&#%w z)}tRbkB@#_o-3m7H?N4^3cjWP-OEglVO2Bgs;cK!)YP}^y?39YOlrCH{_Cu!i>v0f zoLPO1;<&21dggUivu6*zIy7y~b;E{Vd1d8{x@kkNu9$mO<%kMtdtv453idH=L{0Ua z$rUwK6<5rzq>+_%XZdieiH0cDy5{e;39~EaR@P0b3f;PPzuq3Cy}<>c(d%-QxuKeM z_n0|U=#O<%OmG;waD9JoyR&%}*Ug=PXUW`|6YD~^uD?~AR8v2pqNXKsL#^5cykszY zK_$(sys~1!Y^1~B+Lne#&r_nf<(R6uGlx}PN!L`(ZF%~!R}}lGs@l5hn)>0_wp_pI zK2tP<_O^hKq162G0*4oOtX{B|Qq0vv}cd4E`vr0Nyj+!b2-(&mK`-!;M>Rcsg3OPO7e+U5DAR z_}Mp1Ru;3HvCkd1a_K5dYFqMm%~!0~8q=WV;oU8Ycj$kWW%&FBEf@S_qN2=bx&MW~ zDN%@w*;83Lw0d^++^X8ph!(KvouJ{Jm2>7nX7mg+)Y7Kf+L06zR zmE4Q?KWB2b7ok0e`=m|87lSJBotwGXV~p1l@H27osFRGvNAxxD$N6&D$MTQEf6r)fis( zUXNn(;2Zu^F$fDn&X3}!T_MsLk~Vju2DV&|_KX^+0Qn%B!vA|R%9tLZ+#~S;p1^gq z0KVtSU|j|8Ga=*QUx3NbUY*%MQqnR1|FKHYW;T5Md02P|XYk~b;o@FkL3k$z{%iCw zr}3>?9{XwuUMmTrlS4Vx`ADM*$yUmoFoq}ZzUL7_DPzuIJEVX;mWuA@GodImphPrIL8>Wa&|}>soFfvpV>T3Yi;O7b9rd`r*{PwTC7MzZ#v;} zlLasMb9$N%;!lNZMGv0F*Z*C30O?I%xj1Pt`$|iNdZAYmdkCRDK?@gTVUpF0AC)Q| zeA=T%lS^e`(8AW9pdFQ2mPHqUS#5m%xs!fFDG4!Yxk>X>adJ~buFunyv{2sXr(!B4>4lY=)dc&2tgZ^> zebFnX9%V2oo+?jsz0;PedKQ2Q)qXKVZ**7{ucv7zx;mB3gQ2}&c5r-->_%nh^PqgNyRy)1kPagpCcp`IraQy$@Q&=+oUNl!PyvCP4*T#(@}boGg@ z#R#zQX&0G1!3r>XZ~^{2R*NSX*PaZTsSu()0E#scYT>& zvdHfBEQ(a2w{ZkS_3FXliayRJlVp*Ox+$LW7^}?_T%vmQ`AA|p{#2(#Sri}o{>!YG zB(&!&evH6Eb$J#6{}{?Y6{l#N7Gh@bgtaq2}f&Cvg*AMq#4ZHqG%m48~+>6Xx?Uk~^45IC%6Pp}BFRn?9u zxoB$W>96yYA)(`6_fy^rC4V!1VikV-tnz}wy5gk;XP!m8cPy$;NpE5G3FtDW=>xGyR5-hPY^Cvgp_Yn z`aERAQt|{pvZ=gncowadMdw-c2+F)@6FeV0&zg$O@0>^If^U<1x-bQ>`i)`WtpQs= z(=v2H^(@+kKMW!SCp-(2^hHmHZvQrOEF$oh;4Zd$?HQO))vHPhmx6OEQx_LFSVY^iqD<(IVVU?=du)x}zE}}8D%@Ob%ng3! zxzSwg80J=ZGY-0w@lWn4ozUWcW+c& zxIOO}nXHNpmWwkKH4-6Y@d1S%{BE?9Zz~q(i#vbl+wTgU zIUIVX2=YR`zTY0;rpUMH3#1=B1JZ0^k(8eiK6~~A$qEs6+lv62cEe}T#$sm_#KC;b z#-36O7iTP)dV(>$|FEt~b+lVe<%>Zukx4x+ebZqQ8uLSx)|({*L(_kljmxf^FRP^B z!W^{m)u(9_Uv`iE&_l(G^T(6tW2RtqBxkn^GsNX-+ToJr)%27FgXl`MNf}(pWWgoP zjcXW2wmHL7g?~LlaeJEcTU;uHpr##P3(t6A1g?@Be)vQ~iEb^{VRCtM|I+ z&4kA7*2X2)hwjZt9I<^ng?|oHMp}eYM5HQ2n#r7+w)mNm?xZw@hBKp|Lfb8i)1zJE z6ml^Gf}~KonjadaWIJaOI;MfEhVEDL6l-X!lC9{WLrO;c2q^N;V3v}NCfrH1dIOQN zd~>`~);dC6r6fK~WX&q@cb~r)jSlT)1Tho(&aB3VTQ%!IMY*?inC+Gb{m&3&sSV3o zU-7KAD}7o=#a(4p-VSX_nyl;#B_v;`tP9OdE(3iwxwOX(lLpi>#Kj?f6*c_p0>#uBUfY@S5z(5EQ*1DU}%bw9Ve9s`Q zLwh&$Np|1Xx-7SP`6*RWv%ZAE6x1GE01ccuuq3*I{w#`8rwcHU7xFkyg`8c$92W zk{Tb#gUNVP*g1yCE<^sALbiUZJ->t_+K-NiXn$yPza-SrU;7m+`yZ|<4l+Nm1O1{M zh9loWzG$udO{@i|vMZkQaFc5$undyGFw-+Dbb1!Yw5AHV{*{L{5RCczpdjN#abvt^ zSg;dPhSjRk=W1yFz$7nG1~0}aC2-QT_+98v19O8n-`xEY%q1=B zuU#LJL5=s}>hfB`YW7jwsoxENC|{=@hIT!$4$y1$S_0pj)&^H=*Ix&ST4QssGt8iV zEiec82VBf9Hm|j_ODuG*8U-Bg!zS3lFSz0|xU-L1e;3B&3;Y02(Gf;OzCnh~WX1)4 z1d}L$W#tTf$8EzF`fiY~O!L|TKLejP|6P@7zS%Ud;vyk+?W=`y24^T*Xz1XypxvuU zq_~`dA&%%$8B}9Ncu@b%g5B>6{KRo|HET!bG`J5ui7=yeLs#n;U`X}%f&{Q!o#b_N zdb5YU1smf`H_JNR%sdUd(N4o@IJ(-aJHzh67VqOsby%WZhAaPOY`dl(=GOhfy(9B_ zc_RbAa??$)Nl@=su<#n$fOt^OYM(gSKJ@3M>>0B1y=*Q*2+v|OaCb=V|f4;&Sog0Ems z>4@zfy5q8xV1^pN4FHDFut3_SLD5AP8iF_~i3|*DAwu&9tWa`l7;l6)XsJLM(Qj0sUR&D5W92F<{W@DNzV@rwCpIGo&EviR$q_D-MAgxW8U9q>oaOo!ss z@*_!|KM!3Rm<8_-;-c0w@CWpBox~Eyc^l%q$c%GQD1T^txdS>`0Vilf1ULN+E?k^y z{UVsCi$q(ibA!fqDA=D6bc2V3UKDB=8aKv_kP?e*gc~Sb%!X%1aeoSUaH%suBJ%p! z>%3^V_)e!ql0$EJ9mX|BJzwfiVbrmX4(%+2GrtFz8O>dNp~r?NmPp=wGh>(|iOUU7 zWHb#NMG?9>qn1390+!_-#H$>9hzITOXuRn0?D6)ZSp|q;;Z^8@uA>V z-F5C{I0FfxO;-(4`h|YFs$gg$SanGtuJWY_QLjrz8zZkz!IkY;4QqY_g&B3JteyrE zZOa>q-65Tu8X20`9!L&Ny*jDrA;ho7J&1dSlI8a=d>hv%>N26$JvQP{9~7-E&<&{I zSro0UBeqBA<*Tm@CU|L@&lkvoppgya7S3$Lpc?ss=6oUNT4r0ZG!RwpZQrArwW-?>sbQ@sOOR9FSO?Izmc)IYK(M6B`ym>A%H2;^5X-e zFt2slum*l7y8{npu~;5hiZipImSxHs@}SVL1Vr_VE&n;AvAHQ~Jxg*EW(HvF51mlT zK&3KVFFhArFtwvJPOazgWgw*yYOFafXI^ydOnz>2YGI!olm_d8-QXfmdvR&xXSDNq zO0m@Ez~^~}IJHu5T&v;KQlATPLB6S`)<4PP&nk%RuBsgxDqWkI2YHsW;Ys!tNWmU} z@#pqd>#;3ZEp_>9oKwuBIB(Ejdd}kdE(YJ|Vvza&#bAtBES&ikj|F?BIhIiJwM9X5 z3)^X_n~3_(&$6iUfEXy?0r*W|36w+TkMYF@3c==33upd~O<~n{Nz28S`h1>T+{N>_ zhR$t}U9Iy|;W_KiQ4r((pXSf?bQC@s`x6Ko5jzio-w( zEcY=Oc>bILjP7~5_P_e?QvEMLKV1Er(agmbr&2nC=`YpAVyBjRw$LnoHP1zd>}ueX z&=c1Mlovv8URM@m6)b{3u_2)y+GL(G*l`9@kt>vi@au0tn$2clA~gK5ff5-AckR%o zaHmr4)Dy%X7f3_jhE}oOX`WHwHYnD?u(RPMz@VCXwt-{FtAros)S=*<4O`J7aQNDQ z`wg!#R`WYQMTJmjFKh>*8t&>t*Me;rAbhZh?ZF89HI2lDjU1YQ_0RUMQ)l)@ybW7e zv)-iUfTr?*zUNrVWSA`THtHVQ^)O~ z221<(9 zx0xay*!dJO-%Qcx;S{mg1|~=sc2sKv9+S+S^r)GxT=RJe=|W;U)AbiLC0#apPw7n8 zj!^yRVOO&j(zOehxBwphuuue;v_qQ(v*s$wJTH_*B=5QMGfc(v9N9Vj`c5Y$q<~`ROO45b)q$1c+mx>U` zyRf-z21!kDe$1NS**jko%r|S|I3nO>!|^mQk!AB8xVUw=f55fzRdD4N5&Fy6G{q7+ zJT@hWd+qs~1B3tA-OXFiY3}}7XLnwKxe3Ub`KWB(&*Zj&hanUY9z?P2%iCPJso~jz z!GBoJcSGrN(YhEG;mC=nne(@>o6HAyRUTBkJiVXSm|@=i%9v8Y*=sQ9`5uISj zI|7}j3k`_ilvjy&(v6-zcw;a<>3zdZ2P`u^PC9FO-*D2I45l@C?;9G$8lDsd2MDd;MlVb4GeO(AQMfxfT|jG(Q-_m-k}XO-z8@)QW=v zS?oTud!y4$E0Sh<+;k$5rT0a#{$C`N5Zt&)wa)Ztv{OuPR8MKJChn(ab}Q59DYqv@ zqw4}ug&LiLRHKz{ZhN8&bKNx28f2q?Dq%wp$|!Fy;C6cv^E2bwSv_KR(nAQ*Nrxod zhHP%<`+C^ibXz8CewoUgC<%RogWLOx-Z%V;Ir<&aw?2V$kekAzA1RtQ`TGQ&8r55v z^_G*nITGJDytKJuE5@!U+vD)IGNY2lBZ~cITuL~8IkNb(#v#t#D)yK;b+T1y0$li zOvK`(*CmKU$-rc;`eJQ8%hWO|WgE_h!)&-Xq*&*C36cKJ>+bDm7#qC1+xG%J^-PhvD0 zS)+KeK9rhx0I7CTuWsC{sF-PQnQ1RvI_b4Sri*e|=a6K@FSEW)hV+w*rM6&SzT7Eu zlUT{BN8^}g3V)sO=chM<^DnFgj6i1Y179EK3v{A_m)5T`9aqRiZ1%8Dr8s+9!g?{6 z?bk`c{+z=D8=&!!`gnLqUl~Czu}k84Odn(1PRg+{oz{ctWikaxy|{f-<@-h~eVEOQ ztyBtjSb+Jxy-ZbEHFp|pbeqbY?-8Pt`pJaeFYeEZ%>y#9UnPID;@=MCAaaQo6lcA7=usa{DqhYO3IQy+g7REv0&!IH;7+ zi-i7F(*6hO+k(DM8j;QP7=lCnpORUufiowSi=jG+Zcbk=!=GhFrf2XBeVX7hxN1bzztuAym=64t+E75JpRM)tB|+1-}-*v%p_cUs8v41fS>~YD5MWkbceR=giU(PA@b>sFs8q*chZAuAum?+!u-{CR^r?OnV z{^FUQ6l!yExs4QQrMSFS9Q2lZhZ@QI!SCIfUYs(o*h!YkdBqwutWx7Hv}@7nPJ6>w)eP)ZbTXYy!GR&{s%ln=+0b5R`+kuc4W=P>=zXqs*oU1&zh% zUsLX+hXrK|`U5Q!WC0qY%%hczf>iD2S({I*L>R=(ysb3RYC(?z4FP&w(0-t=lm)a# z(0pX(7|;`fE<-L((%tm5py$#!GxyU5DLqdyqlL6lWHGi<;}xK11qJ8CGklOX37j2i zq89{xja?wLvWY?kdM2zU2F0yB+y^HKQ zdS6hMSlL7$3aS$KFVI0jn1432jXoEcE5aRgyo=FS>3flJv=eDB{nSPF8lCDQ+fTm; zx>_8*PQP_Q2dIOJ>GqcQaVJf{VBG@)yRcJyjMhwl@Z zo-LZCYLpXbvTJlAl{L$4Ot<87--m^c6#9A(<_FwNZxhZjo!cu?S#zP2t?f!@&JVUA z$8x~V^lKZ_gXo~pw?gX^xjhi73JvMr>{Y0s`#tEq4dE)ZxtQr-(J6{rhxSU3(^5k4yx4?8R;DjW`y*)& zlXji77fZVp?P7|^ecWr%RQEc(du*}IMSH!K>3(S+lXk7NTco{S+WXNirs7EMHQM2{ z1dA!7a6P&W&3_g_e4jf6yZki~JmSmCUI1rcIcMeeWTu%;roTFvej;>H46l^S%UYqi zuNUVazK_#V(|C<@o42NMkkCn>v9z=JtRt3s~`{ANvA0P8ahp z@5MS3g!6p_b9x9Ts2RHvyI)Es-C)6XKbJ6em!VqV{Mp78dji>xP+@V@jjY*u+W z==XYdpxw{TIk+f)F}fYHt)Y>P&v}BD=#h>0*qCm#GJR9p-$;9+wC|DjMrpr^HapOx zW9bhRiI08MJg%6fmSnU)0cB}7NViZ9XueVke(!9D#{7#f;Ghn=JAxPii_b?|9eqC1 z!DyGN%(=qCbgN}3XuGsKN7kvY(A?x|IGZK(qI~ZApE^AHk>IDnCI@tVbdV$E7^~9F z7;i+3e^(}iIoM<{H5&EI=MQQ5XK&=VqFFF8B25sDDq4gDm!&gW5a-XqqdN5yv{z?M z3k?!wCVf`- z#fpu_g=M3C+4z2t-i84G(m)a6AJK zv>gwkI(?GM_aEG&kM`(Lb!xsgdb1q!;mI(LJ)`Zug z`hFOZZDVvKMHQd#=%F}4W2JHU@rc&O zC@9g4wtDEasY;hQ=0+Rz79V|Kyr;0Z40^JZ(K6Z}u^X~?dofx}%aT4svEIrb=>dII zd??yap9pHA+wA|0j-w4_rtCKR>F88?5=VTjS)yycZnO~Zp5fmdMK*2aqsVY-vgsp1 zO(?c#l+>4k_R%oRb~d?i-o?qky$_>bF6!FPdT}T6*|VuqP?H{A7Uv7lyDs;^|7eS038*$Pj5!C1;}*?o7tz2O=i_A1@Wwnum@mWLFj|iyEu!ZH-5nR?6J`r2lz`{iu8Zqb6##Pw-XKv@l}#1IUe! zN;=&Sp*TT2F~P~cAv8ju>3#^+h7r3TLK93R?uXE=VZ`n)qlJ8Ci_!CVhtZFMn&@db z96_l=&O5xC0vDi4LCZ)jpC0sGP4}LI^L*FRC+E;~-}Mx@jLkIZ6|OvW3=IvV_ROy> zW9Sh<`-o?B480Ua1LGN;2%|3w?(vPG+b(A-dnvDAp>HhxK~NLL7A*I<#?oSeJTsx+ z?o7IRz3)ak9oDG8gTOfYaVYm*pr3W-spBYan29W~r}O8o`xqn_ynu3IVY+Viq0)J@P{`m9$rO`%5wHPL0M!5zLS^b4Q#V@y0{ zQ^|k*`HoX5Z~^-E0+f1#XkvtWeN!plMD%RjtIAX=7qpK)OPm>5M+u`%4-dn`G#VmE zvK<5*9TxVle8V@5-V%gJwRe5fY4RBE$jkL(-wf(DRvb#YXVDdc7V9HpKKIR{(Sr8T z?ut(%XVDTtrj^;`A9udr9aPc<1@E9My1+YVf}nkr+S`M-@M+_@<31XhsNgO9P(fyu z%%N*8K$F9oIlbee=Fq>p$m;2oDbv^ZqSSiQC$LSna@1EJq#}X)XbFya=FyxmdaB3D zD4<(dwTWIz{npn&p9nJD&!?|0K&*#AZQXpo_~z5UMP@$u1nIP(eZ;aL4ZD>!O)HHQ z94XKgHd1XDVG~X6BEt^SMb=C&c9Atx_etlCwos9v#gt^58{I;C1@YsP64OHcZf8wK z&X~JsPB0AB@|c)=Xd%Ae(0S{>pEh2AUJ_)+eLw9K)PgTlq{ZA%2hPb99D{r*=!nvW zyYxaj8b*m_*+92VVGll+r%?%4T^sE3{U?OEhARnsx!{~Tm z1Z3|BGVjt0=^uj3&=%5{f?BAB%Fypb7ukb!IxMTTRL49>eWuEjRtv4RTo&_38a$PQ zX`u$SI%W|)5Jq1>_7JTQWI9|->jjw(7t`}$%^fs6W-;vxqh5;L`7nLhMKeU7g=M2v zyE8;lbzPpcmf#zY?A|oGgt`f8AvUvwdUla5rHjHcHnWtbbdfEiIbqpT=(mjahS9~) zTuvv>X)5#x>C@mYNaj4Ppur4*c%D{}K7&ycC1bB&L0N*1IJ)<|CT0Z{m`EmV1@#Qe zc+yr-Wmq;La04`hVZ@WRg69nw!>hpVWsAhSwV(I7$Qgs!3yf?DV^vO8DNtznrwX|1N|VIj}x zYIkr+&Ju1fiQ@LcLVTx-R)8w>JfxlU zEI6v@DD;;E<{v3$4!13Ie*tsS(wJ@*&FBoQe+%uxH(0IoD;(Nzl*QuR9;UwvZ7pIG znReEk@8)j?^oyjhrbcl|{6TmCRH5vY|GTCl7F4lmp=cS{;hv~}b9@S=6!VBJJv<%@ zy`AFmSgESWRRrf{nvr{+t`T1*$838uQU9Gu8&>w;+h$5lb6u&a|37;TE33c< zK@~XmuE4=o1-*vX0eq*{i&r~dZoFQ@>j1ti=EWxsU{-@!4Q4f%{h`<&y#C zl3v|J^NeuLSo}G2Dc#D_COMsIQy1#lG$d$!AafbjSgoGb5Zs)&1}6avaCA8eoTsSP z`lpm}T+?|Nn{)ESR;KVxug|MjF;5LRo9Q#h0wK zsc)yID;urXMP@7Q^tXgUWwW(UajDW~J)KvsJdOXFrNirlhY!C^g-YI_m>Do0NmrAM{qG*7|bUc9`RXuN=5}6>UEDI%17ZdPg}1 z`h{}RnjiTihBPb9q1Gr5SfW(L_JAcAqdIIsPqI2h*_)ZC8n!9v#b~cg>#N4w-t68_ zO}9N+G+1p@e@-8v=GZXPYO!rzNv&F8d#~4RYL#tx)GXCd`lZiBug7EVR)^RwwJk*Z zzFwzG{>0FWEVkcx8)*`mn_W)=-sV4HQ|LtdlCsEw#!(+r^gPbZase8JETo z2RBleI2B~CH)M3zjBstOgRotT4o1y-pr1&p0u$u4kFfi z5Jo+8#`cYoY~^0vtZm>FTIY)6#nw>y&*ab=lX_Vzl<`KDwLb+X>BFr@M0`@YHglwP zvGp6odj_1*)^yF2Ki-<7%`3ST?X4-}K?}f1$0q^ft;O2*ygJY?avuTZ`iNJzI3Bm2 zQPR?$v>NKGMH{U-sw3wGYq7e&Cl_5H?IpB%MHFkHgh#CL%Fv+qV{4W6X~ZFGx;nJz zxV1tZVPsQ{b~NG#@P|YmvbL#_fiu=o8g@Nf4Z=zWJ(%9jR;=BdP>uF}OJB80eIjY7 ztwKqJ=3=W`HxpiCTWn27yGpee-E135St!ZHxI?a^p|sFG+g7DsR200~wp*E3QV&qs zqs3N>u`aY-9TpGDf7CYGY-?ZIx5L?$y}Ne<5ALHRs#I>NnO znX6fQy#>zvQmb|hw=Rd)PILQ2YDX0QsH8?qjE@Ow6J+z@?II0dZ$FV&j<4r(=e61& zD{8d0T4wPa(1X42hxCYll{POdO*Ed@4p^&8|Eg`aeUb7HZG~15@ipk6h!dcbK-=kc z{ReH7`a+Z!IxiNTfy>6o7-=i^&DOPk-5#uw{dp3o&psE_LmRc(6^Up!C#Tz+u<7=& zA5ko+J<;Y7v}t9&OVI9*L(nF5bxJlhq1Om-YLbszc3UUwW9_@OUX>H=ZPs67>cD?G z@;EfPkek$pBEPmA&^|1gXK&Yz;Pc1!pw{NQ8xHt0r6%=(9)GkikbEql>P*}!R6Zqb zQu$zJu>`tSeJ$e!d%W6GxW|4(n^O3?eWB!I32`B}S)ccJ*xRWpSJRJaJMBH~C$*s8 zqbv4@>Qf{Qmm)jACB*%AF-A6US}z`&np?OGaac{ z*uODu)DNOQChJvpJ$I(QTHMswKhl=yyVaInYbajL&flt!vTw`yv;L%n@|@6Gd+(&f z`U(lUomN!vroO3njAN4B8KN-B$9?ww+4nnY?F-zi9h+_c>hq!Fpn6>U9MWOM|Agk4xIFBJXWXa3 z=V{t#|JZ&OZO+_5l}{hrsi2SQ+-!fS!0tStK9CXTOt&xe1v8unCB`8(CwDAvCaebW&Yco$0$&F+_Kra(BJ4hV&50H#CgpA zXxs*8o7z_KuG69S3Vh^r;I5Ac77HKNwNrV)_fA7EFF57gD|gPf_|6%mbPHxEBHdD$ z9usjy;m;G}^?4;p5m>oBvm$cz#>iYq$EWrN=O{RD$t{(qrhi0^WnRe@5r+Ou^0m+z zgu7+Dg%2j<#c>7btq~QL?;=;@TL-+RiuFL$>WC_Re&x1^-CEDIy%E77`eglsh=a;p z-#SaXrsaPsMn4yNETTsLu6Kf-FI&fMZFrjI%BP14ysl9?A2NO-jZ0KSy4YW3SQ zu5{ICJpwV>5D8+Gg^wI3>0cJ!<{D*b!hLnRzQeM{HAz3+eS>RmP#=`L-8RJbhPF_h zZfTBs0jgKHwz#I-R`zwc<886`7p9ZvMZqrK~yqXU8{z2QU=Vp7ggGwNncBgxY zHIUfkKA^wlzsJ2>Ps(2CUZE}M@hA5Y{kD>A?sQ99@@iB`F1}wq#JVbTr~8;56}#7c zQhz+^ZG>_#^>6Mo`n?hVaBoKFU$|>+)lnzh4#z_gXWVNoThck8SM%3^@*(C5%ZW&C zXW`@170?gjdlnWxvpj%!)1u-X@!l!!bca7DE9!_ouA~rruHkmj-cjwAzZ*_VyQQ{_ z=?D0tN4tfOEe~jOFg~A>UpyT5w8zUowpKW@0@I_~mDdyamc6v>YfF{mRG&Ff6^@xk zbJPJ_T=^nMpDX)12=Pl09~3t=j{PYsqmuA&JxJ+>$L*eU(9*wbb5u8Z7_V{g6H&1~ zr*dCZzUcH6ot`2+fXcw9HVW^9L#*YAr=vzW7TP-ybgL0VypC+1lj3EF)tV8D_Uz&$ zPw=GW2|PR99N=kIG1-HkH5%u&=jwZ_YHMk7rvu43xArs znJPhF0`*cG^+S7yaN41%(x*bt3Uw&VDHeKB5EmN_Rw_Y<3LT+b3~@W!I*n8Nflg2d zfZnQJ20B?C4mwS}8g!OA3UrP-7IdCE9<))t)mw-^={+1%h`&rY2AW8EY$3jhXn^KX zHfX8PzCx?<1xT0yLOru|EK7>Gpq6d@w#!z<8l8 zLe~l1BlHWQ7M(j}3au78UTBNZbwc+D{X(e4A^JkAg{Haw1q=OzjuV;|8KM|}upcg? z{Ed;^VU5sTLi@Qx^pwBREqtMA9&V3|jZlvH8)Ks}zBNL}`QHP-QRptAhlNrc^V5X( zGuw&G=_hoJ&|N{f92QDR(m`lHq2q+E5xPt0VWE^PnnL>t9Vc{+&|N|g3#Am%6nZ!Q zdx&MqPUV1dM%k>MP$Mn3SVGg5jZ4@bbu`NDDfG#Mjw=EcM)Kwn5)0eVwV4Bai=Zc1j>w%(6|KIU5Y zA8mix#{b}4Q4>Gw|Mg+I}mU5t{3bzPt6S@=h`k1|-Px{^f-BbE5=Xzn4|%8~jO;O5f5AII@|e zWP|=e$pM|GllX(u!PeU3yV;@nt0rgvZuwi(0BfcZqC9Q9b&YYm^^kF=yaL|w)_}Jj zZG^Tw%B3W=R;`|DX?^AKSC!VrwRhNCf8Q`s3C(KR5LX^?H6m>#NUCQ(J2`_fc9O|I=$q>#Qw{EUod|4=Sy{wW0TIf9?_5_UDbE z+g@o2Id{x$ePBl~CHu0vn+DcSntbKN+L?7zX@+?jI&MuTpYC(|$<0s+UzW8jomc7RBXqSv7C-MbT*zBt6?UrhHd7C1=O@`4FZ#2aijT?=|qv)%82cWI0TAHF5EyjD@Fj|VyA12^2HU$&G>eEB3e<=<|BAK;F zwu+0&?AcbQ;w|S^1GoCyaN2CTzl)gW2tKWMy@&^DT`F`7o{y0>Mi zio_Z%E8LQR6;P7e`^F6(ej#)ljo;W%E$-0JU;Pz`p=G_BEZ(MCG{n?wuifTtJlz>D zOsEpwCRZ8;F@?uqv`h)D{mWUsDqg@?hv6zvbymO_!gB+-Eamjzo~fg{(G> z@izX1;h1?Hcs5=6CUooB46Wr1rtfU%p|c5!5_OIvIhb=JqZC zK8b-CO)GS}RW+L61FHtv;M{~VIz}qVp}8F?akU=&d9rts$2;5OZCabma|AW0ywK4b zYw+uir?CeA`1@UH1EjPXHzF$h%4%8aN<%7Nl4Z7ZX{jwTOPfq|`L0VsZgw6d!mOOp%Fb{K>7W zHdIRE23DOe_0jaHbe_HZ5k<*TnwIZWlmz9zgR2?!@o`4%mv=;fO%eEja#@Oa^AVz#)4oQ*0c-b z6$PW&;ZEkgCg3fX8By_rib7c$O#?8lO`UPB;TU$isI%w+5DFA^qyov?jb@S^{|SZZ zZ<2SCnS$nYFMg9yU1@|Q90+1ZK#&}qToD^@DGS~f`4nsd=`senat@o*ogRgEg-Q4W zGu{Z2v@|s-DLKhaR&R5%ca$41{95fQrXO2!uvmz z7Y55Fsm@NVF}&?G{9;K{LAh7i=8jc +
  • + wula_event_progress + 1 +
  • - 你选择继续... + 你选择继续... (事件进度变量 'wula_event_progress' 已设为 1) PositiveEvent
  • @@ -40,17 +44,37 @@ 这是事件链的第二部分。你已经从第一个窗口来到了这里。
  • - +
  • - 事件链已完成!一位流浪者加入了你的殖民地。 + 事件链已完成!一位流浪者加入了你的殖民地,帝国对你的行为表示赞赏。
  • WandererJoin
  • +
  • + Empire + 15 +
  • +
  • + + 需要事件进度=1 + +
  • + wula_event_progress + 1 +
  • + + +
  • + 你触发了特殊选项! +
  • +
  • + +
  • diff --git a/Documentation/EventSystem_Documentation.md b/Documentation/EventSystem_Documentation.md new file mode 100644 index 00000000..cbf1a381 --- /dev/null +++ b/Documentation/EventSystem_Documentation.md @@ -0,0 +1,255 @@ +# 自定义UI事件系统文档 + +## 1. 简介 + +本事件系统旨在为RimWorld提供一个强大的、数据驱动的、类似视觉小说的事件和事件链创建框架。它的设计灵感来源于Stellaris等策略游戏,允许开发者在XML中定义复杂的UI窗口、交互选项、事件效果和触发条件。 + +系统的核心由四个部分组成: +- **`CustomUIDef`**: 定义一个独立事件(UI窗口)的所有内容。 +- **`Effect`**: 定义一个选项被点击后执行的具体动作(例如,给予物品、改变关系、打开新窗口等)。 +- **`Condition`**: 定义一个选项是否可选的前提条件(例如,需要某个变量达到特定值)。 +- **`EventContext`**: 一个全局的静态变量存储系统,允许在不同事件和效果之间传递数据。 + +--- + +## 2. 如何创建事件 (`CustomUIDef`) + +每个事件都是一个 `CustomUIDef`。你需要在一个 `Defs` XML文件中定义它。 + +**基本结构:** +```xml + + + MyEvent_UniqueName + + Textures/UI/MyCharacter + 角色名称 + 这里是事件的描述文本。 + + + + + +``` + +**字段说明:** +- `defName`: 事件的唯一ID,用于在代码或其他事件中引用它。 +- `label`: 显示在窗口顶部的标题(当前版本未在UI中显示,但建议填写)。 +- `portraitPath`: 立绘的纹理路径(相对于`Resources`或`Textures`目录)。 +- `characterName`: 显示在名称框中的文本。 +- `description`: 显示在描述框中的主要文本。 +- `options`: 一个 `
  • ` 列表,定义了所有的交互选项。 + +--- + +## 3. 核心概念:选项 (`CustomUIOption`) + +每个选项都在 `` 列表中的一个 `
  • ` 标签内定义。 + +**字段说明:** +- `label`: (必须) 按钮上显示的文本。 +- `effects`: (可选) 一个 `
  • ` 列表,定义了点击此按钮后按顺序执行的所有 `Effect`。 +- `conditions`: (可选) 一个 `
  • ` 列表,定义了此按钮可选所必须满足的所有 `Condition`。只有所有条件都满足,按钮才能被点击。 +- `disabledReason`: (可选) 一个字符串。当按钮因不满足`conditions`而禁用时,鼠标悬停在按钮上会显示此文本。如果未提供,则会自动显示第一个未满足的条件的原因。 + +--- + +## 4. 核心概念:效果 (`Effect`) + +效果定义了“做什么”。每个效果都在 `effects` 列表中的一个 `
  • ` 标签内定义,并且必须有一个 `Class` 属性。 + +### 已实现的 `Effect` 列表 + +#### 4.1 `Effect_OpenCustomUI` +- **功能**: 打开另一个自定义UI事件窗口。 +- **Class**: `WulaFallenEmpire.Effect_OpenCustomUI` +- **字段**: + - `defName`: (必须) 要打开的 `CustomUIDef` 的 `defName`。 +- **示例**: + ```xml +
  • + MyEvent_Step2 +
  • + ``` + +#### 4.2 `Effect_CloseDialog` +- **功能**: 关闭当前的事件窗口。 +- **Class**: `WulaFallenEmpire.Effect_CloseDialog` +- **字段**: 无 +- **示例**: + ```xml +
  • + ``` + +#### 4.3 `Effect_ShowMessage` +- **功能**: 在屏幕左上角显示一条游戏消息。 +- **Class**: `WulaFallenEmpire.Effect_ShowMessage` +- **字段**: + - `message`: (必须) 要显示的文本。 + - `messageTypeDef`: (可选) 消息类型 (例如 `PositiveEvent`, `NegativeEvent`, `NeutralEvent`)。默认为 `PositiveEvent`。 +- **示例**: + ```xml +
  • + 你获得了一个物品! + PositiveEvent +
  • + ``` + +#### 4.4 `Effect_FireIncident` +- **功能**: 触发一个原版或Mod添加的游戏内事件。 +- **Class**: `WulaFallenEmpire.Effect_FireIncident` +- **字段**: + - `incident`: (必须) 要触发的 `IncidentDef` 的 `defName`。 +- **示例**: + ```xml +
  • + RaidEnemy +
  • + ``` + +#### 4.5 `Effect_ChangeFactionRelation` +- **功能**: 改变与指定派系的好感度。 +- **Class**: `WulaFallenEmpire.Effect_ChangeFactionRelation` +- **字段**: + - `faction`: (必须) 目标 `FactionDef` 的 `defName`。 + - `goodwillChange`: (必须) 好感度的改变量,可以是正数或负数。 +- **示例**: + ```xml +
  • + Empire + 15 +
  • + ``` + +#### 4.6 `Effect_SetVariable` +- **功能**: 在 `EventContext` 中设置或修改一个变量的值。 +- **Class**: `WulaFallenEmpire.Effect_SetVariable` +- **字段**: + - `name`: (必须) 变量的名称。 + - `value`: (必须) 变量的值。系统会尝试将其解析为整数或浮点数,如果失败则存为字符串。 +- **示例**: + ```xml +
  • + my_quest_progress + 1 +
  • + ``` + +--- + +## 5. 核心概念:条件 (`Condition`) + +条件定义了选项是否可选的“前提”。每个条件都在 `conditions` 列表中的一个 `
  • ` 标签内定义,并且必须有一个 `Class` 属性。 + +### 已实现的 `Condition` 列表 + +#### 5.1 `Condition_VariableEquals` +- **功能**: 检查一个变量是否等于指定的值。 +- **Class**: `WulaFallenEmpire.Condition_VariableEquals` +- **字段**: + - `name`: (必须) 要检查的变量的名称。 + - `value`: (必须) 要比较的值(作为字符串)。 +- **示例**: + ```xml +
  • + my_quest_progress + 1 +
  • + ``` + +#### 5.2 `Condition_VariableGreaterThan` +- **功能**: 检查一个变量是否大于指定的值。 +- **Class**: `WulaFallenEmpire.Condition_VariableGreaterThan` +- **字段**: + - `name`: (必须) 要检查的变量的名称。 + - `value`: (必须) 要比较的数值。 +- **示例**: + ```xml +
  • + player_reputation + 50 +
  • + ``` + +--- + +## 6. 核心概念:变量系统 (`EventContext`) + +`EventContext` 是一个全局的静态字典,用于在事件链的不同部分之间传递信息。 + +- **设置变量**: 使用 `Effect_SetVariable` 在XML中设置变量。 +- **检查变量**: 使用 `Condition_VariableEquals` 或其他条件类来检查变量的值,从而控制事件流程。 +- **使用变量**: 一些特殊的 `Effect` (例如 `Effect_ChangeFactionRelation_FromVariable`) 可以被设计为从 `EventContext` 中读取值来执行操作。 + +**注意**: 当前 `EventContext` 是全局共享的。在一个事件链结束后,最好能有一个 `Effect` 来清理掉设置的变量,以避免对其他不相关的事件产生影响(此功能待实现)。 + +--- + +## 7. 完整示例 + +以下是一个演示了事件链、变量和条件的完整示例。 + +```xml + + + + + Wula_ExampleUI + + 这是一个事件链的开端。 + +
  • + + + +
  • + wula_event_progress + 1 +
  • + +
  • + Wula_ExampleUI_Next +
  • + +
  • + +
  • +
    +
    + + + + Wula_ExampleUI_Next + + 这是事件链的第二部分。 + +
  • + + +
  • + 事件链已完成! +
  • +
  • + +
  • +
  • + + 需要事件进度=1 + + +
  • + wula_event_progress + 1 +
  • + + +
  • + 你触发了特殊选项! +
  • +
  • + +
  • +
    +
    + +
    diff --git a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo index a8a344fa282cd9c4eb41b49a2b13f737da10f6ee..653b39b7387008c5de978785048b2e89e3c24f09 100644 GIT binary patch delta 2203 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 diff --git a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json index 9877f5de..01d50c37 100644 --- a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json +++ b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json @@ -7,7 +7,7 @@ "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:debugactions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\mentalstate_brokenpersonality.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\mentalstate_brokenpersonality.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:mentalstate_brokenpersonality.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { @@ -91,8 +91,7 @@ "RelativeToolTip": "MentalState_BrokenPersonality.cs", "ViewState": "AQIAABMAAAAAAAAAAAAAwEsAAAAjAAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-07-25T13:51:03.13Z", - "EditorCaption": "" + "WhenOpened": "2025-07-25T13:51:03.13Z" }, { "$type": "Document", diff --git a/Source/WulaFallenEmpire/Condition.cs b/Source/WulaFallenEmpire/Condition.cs new file mode 100644 index 00000000..d898b4cc --- /dev/null +++ b/Source/WulaFallenEmpire/Condition.cs @@ -0,0 +1,64 @@ +using Verse; + +namespace WulaFallenEmpire +{ + public abstract class Condition + { + public abstract bool IsMet(out string reason); + } + + public class Condition_VariableEquals : Condition + { + public string name; + public string value; + + public override bool IsMet(out string reason) + { + object variable = EventContext.GetVariable(name); + if (variable == null) + { + reason = $"Variable '{name}' not set."; + return false; + } + + // Simple string comparison for now. Can be expanded. + bool met = variable.ToString() == value; + if (!met) + { + reason = $"Requires {name} = {value} (Current: {variable})"; + } + else + { + reason = ""; + } + return met; + } + } + + public class Condition_VariableGreaterThan : Condition + { + public string name; + public float value; + + public override bool IsMet(out string reason) + { + float variable = EventContext.GetVariable(name, float.MinValue); + if (variable == float.MinValue) + { + reason = $"Variable '{name}' not set."; + return false; + } + + bool met = variable > value; + if (!met) + { + reason = $"Requires {name} > {value} (Current: {variable})"; + } + else + { + reason = ""; + } + return met; + } + } +} diff --git a/Source/WulaFallenEmpire/CustomUIDef.cs b/Source/WulaFallenEmpire/CustomUIDef.cs index cfe71551..438c69d4 100644 --- a/Source/WulaFallenEmpire/CustomUIDef.cs +++ b/Source/WulaFallenEmpire/CustomUIDef.cs @@ -15,5 +15,7 @@ namespace WulaFallenEmpire { public string label; public List effects; + public List conditions; + public string disabledReason; // Custom text to show if conditions aren't met } } diff --git a/Source/WulaFallenEmpire/Dialog_CustomDisplay.cs b/Source/WulaFallenEmpire/Dialog_CustomDisplay.cs index d1487557..21207fdc 100644 --- a/Source/WulaFallenEmpire/Dialog_CustomDisplay.cs +++ b/Source/WulaFallenEmpire/Dialog_CustomDisplay.cs @@ -31,27 +31,42 @@ namespace WulaFallenEmpire public override void DoWindowContents(Rect inRect) { - // Top-left defName + // Top-left defName and Label Text.Font = GameFont.Tiny; GUI.color = Color.gray; - Widgets.Label(new Rect(0, 0, inRect.width, 30f), def.defName); + Widgets.Label(new Rect(5, 5, inRect.width - 10, 20f), def.defName); GUI.color = Color.white; + Text.Font = GameFont.Small; + Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label); - // Scaling factor to fit the new window size while maintaining layout proportions. - float scale = 0.65f; - // The original CSS was based on a large canvas. We create a virtual canvas inside our window. - // Center the main content block. - float contentWidth = 1200f * scale; - float contentHeight = 1100f * scale; - Rect contentRect = new Rect((inRect.width - contentWidth) / 2, (inRect.height - contentHeight) / 2, contentWidth, contentHeight); + // Define virtual total size from the CSS layout + float virtualWidth = 500f + 650f; // lihui + text + float virtualHeight = 800f; // lihui height - // All original positions are now relative to this contentRect and scaled. - Rect mainBodySRect = new Rect(contentRect.x + 200f * scale, contentRect.y + 400f * scale, 1050f * scale, 1000f * scale); + // Calculate scale to fit the window, maintaining aspect ratio + float scaleX = inRect.width / virtualWidth; + float scaleY = inRect.height / virtualHeight; + float scale = Mathf.Min(scaleX, scaleY) * 0.95f; // Use 95% of space to leave some margin + + // Calculate scaled dimensions + float scaledLihuiWidth = 500f * scale; + float scaledLihuiHeight = 800f * scale; + float scaledNameWidth = 260f * scale; + float scaledNameHeight = 130f * scale; + float scaledTextWidth = 650f * scale; + float scaledTextHeight = 250f * scale; + float scaledOptionsWidth = 610f * scale; + + // Center the whole content block + float totalContentWidth = scaledLihuiWidth + scaledTextWidth; + float totalContentHeight = scaledLihuiHeight; + float startX = (inRect.width - totalContentWidth) / 2; + float startY = (inRect.height - totalContentHeight) / 2; // lihui (Portrait) - Rect lihuiRect = new Rect(mainBodySRect.x - 150f * scale, mainBodySRect.y - 200f * scale, 500f * scale, 800f * scale); + Rect lihuiRect = new Rect(startX, startY, scaledLihuiWidth, scaledLihuiHeight); if (portrait != null) { GUI.DrawTexture(lihuiRect, portrait, ScaleMode.ScaleToFit); @@ -62,7 +77,7 @@ namespace WulaFallenEmpire // name - Rect nameRect = new Rect(lihuiRect.xMax, mainBodySRect.y - 30f * scale, 260f * scale, 130f * scale); + Rect nameRect = new Rect(lihuiRect.xMax, lihuiRect.y, scaledNameWidth, scaledNameHeight); GUI.color = Color.white; Widgets.DrawBox(nameRect); GUI.color = Color.white; // Reset color @@ -73,7 +88,7 @@ namespace WulaFallenEmpire Text.Anchor = TextAnchor.UpperLeft; // text (Description) - Rect textRect = new Rect(nameRect.x, nameRect.yMax + 50f * scale, 650f * scale, 250f * scale); + Rect textRect = new Rect(nameRect.x, nameRect.yMax + 20f * scale, scaledTextWidth, scaledTextHeight); GUI.color = Color.white; Widgets.DrawBox(textRect); GUI.color = Color.white; // Reset color @@ -81,7 +96,7 @@ namespace WulaFallenEmpire Widgets.Label(textInnerRect, def.description); // option (Buttons) - Rect optionRect = new Rect(nameRect.x, textRect.yMax, 610f * scale, 300f * scale); + Rect optionRect = new Rect(nameRect.x, textRect.yMax + 20f * scale, scaledOptionsWidth, lihuiRect.height - nameRect.height - textRect.height - 40f * scale); // No need to draw a box for the options area, the buttons will be listed inside. Listing_Standard listing = new Listing_Standard(); @@ -90,9 +105,22 @@ namespace WulaFallenEmpire { foreach (var option in def.options) { - if (listing.ButtonText(option.label)) + string reason; + bool conditionsMet = AreConditionsMet(option.conditions, out reason); + + if (conditionsMet) { - HandleAction(option.effects); + if (listing.ButtonText(option.label)) + { + HandleAction(option.effects); + } + } + else + { + // Draw a disabled button and add a tooltip + Rect rect = listing.GetRect(30f); + Widgets.ButtonText(rect, option.label, false, true, false); + TooltipHandler.TipRegion(rect, GetDisabledReason(option, reason)); } } } @@ -111,5 +139,33 @@ namespace WulaFallenEmpire effect.Execute(this); } } + + private bool AreConditionsMet(List conditions, out string reason) + { + reason = ""; + if (conditions.NullOrEmpty()) + { + return true; + } + + foreach (var condition in conditions) + { + if (!condition.IsMet(out string singleReason)) + { + reason = singleReason; + return false; + } + } + return true; + } + + private string GetDisabledReason(CustomUIOption option, string reason) + { + if (!option.disabledReason.NullOrEmpty()) + { + return option.disabledReason; + } + return reason; + } } } diff --git a/Source/WulaFallenEmpire/Effect.cs b/Source/WulaFallenEmpire/Effect.cs index a1fe47e3..a078daee 100644 --- a/Source/WulaFallenEmpire/Effect.cs +++ b/Source/WulaFallenEmpire/Effect.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using Verse; using RimWorld; @@ -87,4 +89,101 @@ namespace WulaFallenEmpire return; } - Faction.OfPlayer.TryAffectGoodwillWith(faction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: HistoryEventDefOf.QuestGoodwill, lookTarget: null); + Faction targetFaction = Find.FactionManager.FirstFactionOfDef(faction); + if (targetFaction == null) + { + Log.Warning($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{faction.defName}'."); + return; + } + + Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null); + } + } + + public class Effect_SetVariable : Effect + { + public string name; + public string value; + + public override void Execute(Dialog_CustomDisplay dialog) + { + // Try to parse as int, then float, otherwise keep as string + if (int.TryParse(value, out int intValue)) + { + EventContext.SetVariable(name, intValue); + } + else if (float.TryParse(value, out float floatValue)) + { + EventContext.SetVariable(name, floatValue); + } + else + { + EventContext.SetVariable(name, value); + } + } + } + + public class Effect_ChangeFactionRelation_FromVariable : Effect + { + public FactionDef faction; + public string goodwillVariableName; + + public override void Execute(Dialog_CustomDisplay dialog) + { + if (faction == null) + { + Log.Error("[WulaFallenEmpire] Effect_ChangeFactionRelation_FromVariable has a null faction Def."); + return; + } + + Faction targetFaction = Find.FactionManager.FirstFactionOfDef(faction); + if (targetFaction == null) + { + Log.Warning($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{faction.defName}'."); + return; + } + + int goodwillChange = EventContext.GetVariable(goodwillVariableName); + Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null); + } + } + + public class Effect_SpawnPawnAndStore : Effect + { + public PawnKindDef kindDef; + public int count = 1; + public string storeAs; + + public override void Execute(Dialog_CustomDisplay dialog) + { + if (kindDef == null) + { + Log.Error("[WulaFallenEmpire] Effect_SpawnPawnAndStore has a null kindDef."); + return; + } + if (storeAs.NullOrEmpty()) + { + Log.Error("[WulaFallenEmpire] Effect_SpawnPawnAndStore needs a 'storeAs' variable name."); + return; + } + + List spawnedPawns = new List(); + for (int i = 0; i < count; i++) + { + Pawn newPawn = PawnGenerator.GeneratePawn(kindDef, Faction.OfPlayer); + IntVec3 loc = CellFinder.RandomSpawnCellForPawnNear(Find.CurrentMap.mapPawns.FreeColonists.First().Position, Find.CurrentMap, 10); + GenSpawn.Spawn(newPawn, loc, Find.CurrentMap); + spawnedPawns.Add(newPawn); + } + + if (count == 1) + { + EventContext.SetVariable(storeAs, spawnedPawns.First()); + } + else + { + EventContext.SetVariable(storeAs, spawnedPawns); + } + } + } +} diff --git a/Source/WulaFallenEmpire/EventContext.cs b/Source/WulaFallenEmpire/EventContext.cs new file mode 100644 index 00000000..ec1c72bf --- /dev/null +++ b/Source/WulaFallenEmpire/EventContext.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Verse; + +namespace WulaFallenEmpire +{ + public static class EventContext + { + private static Dictionary variables = new Dictionary(); + + public static void SetVariable(string name, object value) + { + if (variables.ContainsKey(name)) + { + variables[name] = value; + } + else + { + variables.Add(name, value); + } + Log.Message($"[EventContext] Set variable '{name}' to '{value}'."); + } + + public static T GetVariable(string name, T defaultValue = default) + { + if (variables.TryGetValue(name, out object value)) + { + if (value is T typedValue) + { + return typedValue; + } + // Try to convert, e.g., from int to float + try + { + return (T)System.Convert.ChangeType(value, typeof(T)); + } + catch (System.Exception) + { + Log.Warning($"[EventContext] Variable '{name}' is of type {value.GetType()} but could not be converted to {typeof(T)}."); + return defaultValue; + } + } + Log.Warning($"[EventContext] Variable '{name}' not found. Returning default value."); + return defaultValue; + } + + public static void Clear() + { + variables.Clear(); + Log.Message("[EventContext] All variables cleared."); + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index b0cbd491..9bb016c8 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -106,6 +106,8 @@ + +