UJL9bgn^Sxy6<0`Ank@qM4$R`0J|?SQduqz<|-o_Q;NOC zEs={W{R>x%-ni2)iw7hhdANLamJPIIS~&o@6}`ChvS~@Y3H3m#ACXpO_{}D!rl*aR zm4KLZG=##?Z5<@_YwZD)o8pV`x{P{kA(7s+SmH{vMWDBH0u81O`Y*)riS2A8U#GZ4 zM=HNMp-BNj$Kpb4$|pFe|Ktbje~w;HxTd}~>UJxJLwMM)n4j9#nMQ9CeotAp_JE;| z*WkGpT7wPqj}CwKpaLX3dosd#E6ABI3LtjCk&y&4mKT?Z{{5dwOaC~+m97#EHFa1c zi%c8^56OcW?;jbVWMX0x;&_t>(}sVlWzIp-zLK)Q84`kQpRK}J{ z4eNxEL?)X3G2ZR-kTXeXcj3SQ$q@*EIcEo5_)g9a1gde|gQkehet(vHId~8se260& zW$V%%rlJbFf*=E=)sC9ZHJxY6AjQSS!I@l4ObVA$wAk@uuqjY<%IuxuO`1kr-RMN< z@0)v;4UewQJ~rhP|DhOyH3JNZ)sA8{s8k#c840&)AO?K?TssdMR0i>N5ri8$8qi7i zubvx~ec>|vW(USOlNq8YmF7X}M#4b_BTSq7JCm!Q#zRTyBZI^_i&dOve)uf!o%v7C z1%wv1pvlzZ6?PcDp4P_=T^nmdvK8Ihl>ZZd=*ak`p85^Qi|VWiUy{*!FmhvCIfmy; zgvz|;AG)m}vK|&1B2KcJgT31EmkM^MvRa3v_g-_eTp0V@yZNO`MqXjOwqp%=W{=|g zn^>xmGC#7np!&=aDpnS?cHXw?<`g2p_uMPM#-*;;kGsn4QgFV7q`arH5sOo$7c~b9 zaiUo5-tN~jH+!zMDVCyCn~6q|3&aU_bLvrkF6z=^H%xe490vQ;c7kX_c2`0GpVoSk z?^mTXJ?y*2$ij-hUrE(ppfwGJivQyxmUQQy|K_+A!K;o{nU1@9fYqBI*z=32|LIE# z?Bda%c)=gu=ZziTX6s{-6~LynV@LgVq$6){Z3}uTkcv>MU_Vq+?6$8$_GP@7Mf!Zg zIvO3vJ2E3arj|RExzTWMb%*fXGSNoDhPIJ dUbHB+#WHP&A{8n>&9dF>Jr&`NAx ziiDU?+dmN|mf6TJji|3BKc&=C1}{c)`K1D@%$=QE0s_uN*4OG2%vC9sJ_QrmO8M0U zpga7|&(v>NF^T|N@jc$D5%!0gQubw`*2=P2>GL%sL!JHjJ+8q*fPoOXDS4yJM)>85 zD{%&=xnB -MsN5VGoVg5cI{ z)dj_nvN=dCfKIG|HtWPgS`Shwu(i2~MT ICOn@xm$p^0BEDwMZ0@&3o*r;i z53F8_0C!u}0@1Ot9ZvV2;= )VJrCj z-iQOd9gUPt`b0U G qI4<>+5zb7fvoCCd0OidffaKGI{qT z%v@%Tz}Qxj@45t=%TEUDJy@`b jhnT(>pXHq8xnjtDkZZg;*XCL9ewJ1x3YZ=@Q z!30Hkq r9L*;!%fH*X21)4zBl2%~ B?YmaXq>uZ88A;k)V1f z@H#2|im@C!czxR*Coni{l)m&9(ubS;Hty4(_GvVftQ&_{KL^?(96-)7AJOK2i0-Br z#OTYWSiSHDiQaM{$s7%3wF)S}qE3#0H88I~n19fM4tNIk4pgamwpCPzn`j d6Z60ectr^GV6W`TAn?iXmijuW#0g67JKN0>>LL`% zNffkbbFA;EHDHY4cmF5o@n*f% 8UMLc znSh`(hf2Iq(E4^0vHFTs^;KF6c)HSsq*m|+buu%b24Qpt4(`_~wj|pJS&5DA$}P|1 zvrXTb8 =D%lKbeYyb@3jy`gT^t`iLC*>P$ z!~>z{LrlLFfH(d9Yt*I3cH&phEma#c2^w%^9@toojA8JXp!JsngFT^zs}3CtPQo7h z0k?eVN~>#N)OlrJ#Ae0ff*18XI4!Evr~&yx{HAF;pH`61t0bcT%6VJ12PQc7k3c%h zSg@M?IHFmF4r7f6d<1U&dy6gM&szPAu;iilBMP(>OmFZdLl_3K9vY*fVv=75PLhmr zf2A!bw$|{HAfa+gV8qHGK<5B8m$QrGc2HSNl<%yPQV}76>1U1o>X?R?7&TSJq9=?L zS-cd1Y296_djjMk)%3>b>S*Q>4Z28n?P6AGd}fpE_}_| ziTHJ?hu({Y;IaP|dWxXd|QVr%`mHssZbo>}Wr^?mV5>=JDXoHbZ zU4q`htCvtq`p3Da8~NF^D}Q-crR ?Rdtv<2w ze|OKiV~cFvb{|~*tD2mx&ETPdEHZjIyzK2);^QtYbj#oU6xWtcV*Vw--jQ1@c{a>V z3ETz<%m rf1rhbe&QGJ6sX4&5gW9iPb5u*;G^M8gAp2+;1T zo$4rZiuBJo@~>e} #jUU_vHhW%mLR-5h1)bCojt1$S= zht`Mp0=&@2d1>5EVjMX6aol9>1)-HR7x+{_%u&<~-DuU_5DEjEH}j_`ChyhD2SHn7 zn)4lRBu?O{1hM9DGlRbD)Gs`4 ^@syZy=OG=vM}d_ET_xHGSiK{`kx* zm64|$rbSZNi5{}82LxHASBgYS_@#~m4{E6+hm?ro2Nd)u<{n$~Cx%DLJ>*D6D_ET$ z@+F}h;iWtVTrx}hI_|2`Sj8tj8 i!Nq*R^zuZs8(+XYZR}8UakK^<$n~!~@b42s9DTY{@^)s!B@c8KQKVWE+(z&-Hix r?y*EwyiAJ~exU84O#0}a@D+>QSY6wvb?_w~z<-;ktDnm{r-UW|^0Orf literal 17246 zcmbunbyQSu^geoqF6op;N@ 5wj^ySt {^s3^Rvw=Ingl=iPhHM5w)$e}eTC3jly8iV89s005zTd|;pf06-j60R`VQ zdA-wdm9cO!bN=Y)`qAMN0C;59Cy&`2aN~!}!ZgF(Z8@tGNRN9ml$D0^d{KF- D-$S?Rw&QZxL8zFB77e>_pd&YZtNr&n!1 zY$`d8cLpP1kRdMj5bQZy2zYo (^F3gfjRap!pYQ3SHoT%G5?rOlnA3&bi=P- zcM%PuZXUACVMm|4e(5@1*gB*X9c*w}ln`Er @B96=2)J(%kQcbWWg5y_^6Fdef&ZO}=2FT!Sc%_AD0|8=z_`h|yFK}a z@hVNhJ=oYqcKF5vVLu5JxEz|S`s49ma4l*riX^$eRrF;x{W8Fgc^sTZcyNOxO}@<> zWH68JU-k`OZk{p3?avbS7t;)0o3TZ)r`<90uZ5ys{$&fKuHCUEwJ=YIo|7%G50544 zPqS}WU`ev1#Q64lWayK3#fnB!{>mV_KqKgm+1raY9!#>RDZn@LipqkLe@=$xoSJIk zZY?|8&%AFJ4g5*{TBb93UA?XCz(CYrUjlu09RQ#M6lJ8|d1M}a^YkHd`!^^N zaLI}4#qwT_7+ 22$DX1N!V#X`pv;yCiN^Qe573K>cmb4R=i3=Yt zO(!QFj6k~RoRmpaI*hy>X(So^V3Rn20L6ryQ4&RpJam2+2_J>Pi SW$^c( zi#T-RJjSATn1?2=y5U)}Qc?kN2?;?XT%A-xLPDITTWpMy^x+z=3c=x$E;pwpI212Y z!tiKe2cqC{1viVY-}7ftas^a;LUAZIW<3?4()j04jC^{$5_Gd*^vj-FJgf|UQKnIU zW380F;}9!a#`r@y>ut#G5*DerMP{5J57k*G8cbgq#|dH2uP+V|lah{aHX>X28!d(W zNcy<7mk+rW|1C-
P0XJBZtjT0!=ztNKt$z347G!!xBql#F-mJY(qN2$wH8gj zzkmJ_I Kz4Bs@h1ddsbWWN%|R9(HW{qWM8@5Vkf z%hb4b{(QPcYvD+xZlTe>TKeRIbOqc(Vu+hpmB0!I^Z1W|81 zXd=MTqd^DKTO3VfiXQU09>*Y%EOUx)!$m!v8ph;)ORJ>paRz~=7ilrdG#m1IPb7p9 zAGTGQmVX2#4n91z)Acd*L>S;uIOqC|R&PFOvKd7^=e>wNgke1@@`3L!lHI~-;wk7Y z8%}Z2wzWGG!~+Ci{_?hGw$$q29L}bjxZU fILkm1@OTc@-)vT^oVQk#U6sURrrGe5sjd=XZv8Tm`Rp*g&a_m=Vf%%!7& zWiLPTOc64(3gGUtc?&^XF^+!N^n5}7*W$zc&iM9Qs~<0cJWLb^sM!I-P95|)`O7Wo zN0XoP(s_xJD!%|D;Zbl HW_$_??Os#G{u~I;uFZ-9CLFOkZ@?5aCem7ZI)41( zmYiA6tLreuzW%4FW^z4=g|7a#nUd9kB@N*CDqp}|wS$;~f&vM^utx%4zw?uD@hR$B z!A2D($@%(~aQZZM`C5P$vL9QYcdt_l&k*jC=7JNpwyEyjvi2(|4=~E+7JVl%` Kf++kKXX4 I}K4$wL)XI^U?GG wUPMcFvG9)WjII-rG0lNKy@wh|YuFb79sxV?}BHR>sLDi5c^A#T6rPmc|sQ1Q@f z^tJgRF%x;-iS%svs?(ZTI7^gPte1NrwSe^x`s*}GEL5G;K9taiG0>7#i)^RE2PZwI zib=gM-4EA$ SW4^y%J*@A%QCYeRiHKpDkiX_uX_-vCUVZBR@V=m1obQb$ zd{XuTRny^&t$ib{9RO AlM-&cML^FcW0C G9O%j~a>nkqkw<#O(e3b=(Fnopy^S z;jmD*{@mm@39m|iMe6!}$5uaR@E~>VQSNrfew?bR@`9~r=H?%sw6^zbHY1)>u5R?H zDN7>%3pNP}3AwP-t$; S3)Vvm)>YslBz_zC_S1?ZH->1c8 MyFJ>h?qjcJ59s9 _h#4Ih9kxo*Ahpm%FlB F2-R%UzG~5(uhwWMg~3ZlNHMlMIufyl?r)?)OaQEm8l@zlhn9 zh+P-7%%J52uKr(m0S_Elyb#H=7}M#=e0dR(^3^K%$!4qs?BM?52dx@+ck6n M@*>&KO9Lh gvBO@cZ0dXF>hM{3hW#|3E2|V^M zGL||h!GJ^^l2+-T-8_6T{L(*>-!+T>`98#h3?U9(h8)vVQY;e;m~_tOEkY$pqR^Z_ z2>EhjkXN92KC%lmOnfQ)P^ten>G)qhOfNt^I34?j49F?_(Z9*VRpu?
Tl!(O)@Ai3_6(hd8S z0@NX--20w5S9e++D~R3?&Ax?)$-q0Qg$eV~ dymbTuyRNAk-s2_|0_;vn$8 zra=e(aG?NGUl~rrSXQUD2f2I1iI6QH&RO^&K;&^7E^lKbQa4KceC$I@-r@&|c|2dZ z0cp<5k30=^3{Lh1HSF3vSeF`1ha+p97;-kI(IaHJVNpu3FZC0Bsbr?}em>FceFrrI z`+f-OdGxv~j6a8AQzs`0z*(vE4^Qzna*Ap#qP1fNq`ZtK(G$}-ntz1vzaZj?4T|+M z?dp8RWz1J5ql`|v-kiOD)XKy8j#0E>liJ_~q;?|A8tQ=<6>s%xKcqw;5`0$=y*VUp za>>??Z@F7uNM2aIb#4ayJ4!M$sZ4%%$yH}+OqJErLJt#sYiI@G;@J3r(4DC@N$44w z(Vsb5Adc7oz3YPP?9yyHWZRQ$GmTH8rO7kPc!z_P)ltMqwei8t#((}kVUq;{&@7(e z0uv^^k1lWU*9cQ}>R}oMGHJ+9o`?zg5n7V^hMpD2dRnZe9CRM0HCnW`y`gbOtjuNW zUZ&ZtPG8L$etoe-EJ2*Tf$|rJX2ZQ*sjdC~$H2W#3SYzYN%nlF)xOaA$!a_zreZZ5 zUO7Tfo?}lwz u+tVDEZWN-WFADJTJgn zY9saD>;aceVx9$VF5w9CC8cxdS!f^L1lOJ?W^l|a05cRoK5bs(%bCltzuL_0shA@5%HOr^lx@oss0bA*DZ=y zQO0E7l8Nb0GzZcTdmtWn=R@N2=unUmKmbzTTcTu{l^xTEOs4FOzC0&q36`$;*{FHY za1@}3Rh+i$MfSp5b+lXy*NlEyhyD_FyoQLHrve`=d;B|y9YOgLX@0m78CX8%N8 zW6MdairG~Xc*?h^kZU8Xi!z2K$23gdsR3h`dCnB>jK+x`d!wVz-zl=}4<^yWmxH13 zFR8=^VW2n2`Kr{l-b=Raw(D2A3E|>9^oSHQxqEHK`_`z!zErPnyLBh7#2Jnq-*qz3 zwS<9Q2^^ZmOODkQKA}p?ybJP)AN}?&$_-TSdZ=TIq@b`60*Jp5i98C6F+NwDyl;UI zn(iqZ {(Do_&a3?d!>d z)2ECU8KBTz+L3(z$XxFfRaMDKG+2Kj}S0yd*ySs>1iXpDDR+>+AmO#*y zUq7M9ar>;jeFJoUr_npo_g>&(dl`GfA PyU{L_QROJ=XKzXpE7O5leLp< ziI1*?GY+>{T2UmjBp+`=PKC-y*&J4FdCu9;->In?o5pH4zB4 +PR z2yQcU)qNk;hE`8X{xQ3A-KzKm0(|h_LFm-mXWZcxva})iY>i7058fBwXsogydOck( z9>Cq&k^5ZK6q0E+S!OnwI3*rHqI{TY(}> jMmhos6FCvuyAn2v?Ed3?-pUBMR6(l=bkwKNYzQG zh-Gforur0SK>CL4A)5V1_Uy3VKEniTwhW@-R(*`qzA|qR0zYoW^Vhp%A)`lvdKVe& zPYW%hDD2VS=&9fS!FO?X4pv8|gh;xrd+|j#oM09n;5C7?=RFz+CK`O$F=77mvA?4B zf3LK$Utd+N?p-_7A)dD^Of)VQOLvXb?B00}WkY~rM8_I~q|bJx&EZMSL;}7jV$RjX zbEV(Iax9kfmK0EkL>vCGB+)xw-e(P8>GHe0Hu6<;>#Tjb@Z&1HU!->8MgExSWWP8( zOnbo!u4_^CCM_?@7lv0^Hvv1a@2ow^-VU}CSefHE%5bCw*0xiOw3a74@@_V*K8a^!<&-QQk0_F`jW6WNnSMIj_Zb2qNMt7xIz?~dTwAl)9%R1>I`m@su3 zJE}6TlU={%p7==#-rlgA_j}hjfZ0fb9K^@dYz@d>?}oZp)eKWa##XvzybHS$7bC}W zq=v8#84zM0&m;PzpR0HKrQw7_NkHdz0#x6SgFp#B?C+;Vfo!p=Nj_(A#MY~(HJ>Cz z(SFGG;EH5#G{4{PEIy1_X$T%ddJNZL1wTCiT4!`5JMS-VVj>RJP k1fui&h;bG+T_h$Hm#uRW<{PklsWcIEG~23*R-4fBQwN^a13mtfjo9 5*i%$fBk_8fZxGD2}%{x#7*GiDG %fCuC%O$2+8XJjRk>!aDks4RH5IQ zvVD)@=03{Htgu1)aQz?GGH()~%5_DERp=HyWriikwmI3j_5^e01tk2TFW@lZDLbrq z;Ruj{aQA@eKMBUV+2e{&X(zGzDH{u@(rMUVB@%vi`w`OH(0au6{5j^&Cbkt`=jsVe z)f}EYN>LC(rOa0=O~|3yuOF*ScL7D4bQnF{3Q&wdZX80oKsuZtlyEwXUOEWF|I*>t zwTgQYS>35TW-7pMGyuER{b L4?={DK86eji24v25W2 APd>Dqe72>wjw>+adcwEmg# z_Qx=t+eL^VaV4sMumWM0A- zN_P(Hg7=1xU zM5VR2xb^}NkBT$Tm^V(6_;5DbbL|e4 6^tR!xAg_r*B#CLY=5_lWLNtRHd lp4$m5r_ZM)?O*Z zdVR;?&=67x4or=+4dvqGBz?)tYf`Ug(zpmd$ET%zf1yN=!zF1MP7?FJ#}D|29Ih?; zPw7Nn39t6jGeKa;mSj=IC$GSTMf$_xAr*iO$wXiC*}MG!XzitT;D<0!eQ5e?Pa!zL zqS6wh11RE?1(E~C_)vO)bAu+R;F^7^x>}>T7r4}5tc;*zDA4Opy#XXYetbSPJ*}>% z7fJs*^d|%HepXx$+=O0%5lX(-EeatG<;E+3 D89`dwZEg6F 2p2$H `3B- zZP01;kcN|pY5Wsa?r2cJ`^%J@z%4`ZFXVOEE`r{Rnl!vQi#VJ{C)m{|$~BWBFKiM+ z9Um07i&-#X?;9rF2}D-0L6go){G$d%>UICQFs|T**wNQ^&8f}kcQhS~P-YWyF2PmW z7Thi^-DtZY`&+LlfJ>0|4Z7MuMEpGry?lZg=%PJ?v=QgPVD9S+zpa*G{%U7cfM7^C z^|e%gZ%g>EUuCpvS`A3mDdp;(*M>M_>5+j*<>f73CGLzk1y0+L8`Ba`F5rokV!77t zRt#N))jV;*YeLfv==ol<&qj#@40l6XskD#7SOI3>P3$*=`i-F~q0YdYN?LdA-u$G> zKGFUjCWqJDGf4ey1VVd=i7K(z-Wff=Mi>pJ>^Yug(67kj0$2Vd{M(|YEmw{By}3Wr zzQk%*MET`8Sk2 H{0>rATUG(tc?mySe1_Os6<~v=Nrw>O!Ea52%ojz!2HxbI+Bho zu*llCIHkWcO^1Y+nx5u+z7AXUEJo^+DSSxE&N)tCGgvXp>kC$RQ&3m1R70YiOl&fl z=e@k5UsHgwom`H8@XdV-?;%A^`=9<{lZoJuQj{gw${%uxTmkpCS!VH+ddy9haQ}f? zCyB(3T0}STXvTJ}ZZoEz;YET`=Di;?Kf)A9e~P+f$cOx#lt?c Q{H(pa7YKeBs{S;#mu^=k&P9M523<-nC7?hR z97p=gy;g=9|Cd_^3yJW2vC-&KVX@pljP=91OGb*{m49rJ$ud@>%V(6;JKBr7(}9zN z{o>8rEy22a%%4IcXeR4#;W380_PDPdq$Ib}VR&Eviqza=e _4o9I2! z; <{QeH3?;fu0^^sE3{&xby+g@Aijde1T&g*;dktILEm-rIa;MLQI@`Ws zdUlTBXL)ynhQ%IlvNYqK{R_e~wLcVPuQ92LQQAT$Cf$`>i?DjH*Z2;l&BVCL64YUu zearUt@e`s;|9bQ(X;ohzMGEaG?HrboMANQJVoN&EFSSjX?|<1z*o@O&jrKPtTX>7< zLG5i0r|gBT@%hBekQyiN>HYpAbB86pbvH T zT`mjIDBr_qeGskkRZqE0U?<0ec0h*zKP6F*Ij(?gsD3Df*YSCSL~7vBgf HZ1rqM@#M-7C6_I|1QPIbynu)wfgdTu -Lhp1X0h zH*J`#`nen4r$Lgp@FU8;gwzMjx~veU22|y^fRt<@yiVP^*v<;~oA`(4?ChCVBhKZ& z18{n=u(5Y^iDAeDp$Jp`7^pd0-cEF%koHM`MC_-odA!(7+6liP5zx%tBHKUH%w^|3 zBY?Sh_!?cJ?}w-W?QN`;@HlOx-w(s8fCns4yu^bXdQYGFN1SAPiY%i;n7Xi5*@E8m z1bKlu0Oog@h6%_Sw7>RnWOP)eKHXRyH@@I7TL1l%TJX;*V$KsC5asfc^jK-7!tWdI z#;deOU*m3UC`7K}*Trr$NVb$#v}KF&Ukq*K@}Ra?XPYDye=3~{g|X(e7hYik671+P z0*Gy{6Owy+l9*zeQeUROL)ISJw+qc-$dXat|L`aSoWhii?o!g3nD$4wzqPTN#P+iB zM<-r$8{tBbg1Oh&^;YBrW7r|M-*lVq3bko#bG9QwEDrKhV0%AzD-2o}2BRsa(XO2g z%B4r<$*8& Ws|50$U!)1 zer@mV&1vdIGT6rd##30e^dL=!yzSl#r<@_hUI{jd#0|G>f;}jP&SAM$JZG@e bL zZOrPFFI``mv;avhPtwRTSpX^ |GU+E)%q2h-bexPfA8#g@Ic3q2~0k;J*p>ycF+%oia%B%ep zdrh@^m&m4z0msM%bq?mVISwb<4v2G-N*Bo$tjH{1D0viV5;DGi&s03BWVx<*-CVtG z3SC4Tm7i4Et2d6+zT?6)HHL#_EUwgj_mXaoSa=5!hewxGWsQ!d<|jCr`IGeRvw)SV zomN&hz1Ii#aOrowN!{z)+P`qsf8BH!y5XbpJstNGAH(k#`0&DkEfeVjv)Efu<%B1{ zuXcTJkxJK8Fmy0TOCrItgmjhUb?}U|4-}s=Qr*id?Kwhu5?dqkEvvW03vPNr?CPE~ zP1RRYWvB6uF{rkII`iWSvCIl${_FbZN!z(|;a>cGL2e9op{&kj&lu<;WyNHwOX6up z;WlRtI9~zYGy9~9uq*kO%Gp-ZBY6GBG;@mK8=s|L^giFa(c-FHX1OV-Bj}~ODR3>p z?FFRmSkZ!>46W^PZse!lCtgKF1iL6jV+ii_n-B%^R0g~Wn?%~75@T;Z_~TmsAu4f+ z3_Wj<0K0mlHXvtIoM^}^T-p(9{5el5`qrN<;}7IBl;iQIzVxuZw}~`}!k5oct4Q-O z-ggUe#$2Ny(y6}u3X3DoIgUXmzzTACS-~yX&ak3yvz>K|IqZ|pmYxw3KX2x8UWJ|! z8|JCZ{?7b0mj~qXqos5|d$_tImN9MkMsE?-`fKjw;CqU36FQaXc^{cqENb|K8uU7N zfg#c=A9SpHf I#c!&M4&IwHv=__3CEKB|8{ zTKL2K=F=+Lq&FnfPz$-haK_PH&s>O&*>Cj1Cd5TcfiRmcL^Ov^w)*aibEu3(rD4Yd zu7p6HQK@-}hv_J#=D6~h%ukEA))Mv?E)robc*$`)M;9x!BO*e89@DcqdI*+jQ;}yO z`Pl??xWGv7O-JEwHcAsr$MSTeShpf1V@OSizQfs$OyWBBkY@_Tyc-WwEiV6M(nt9r z_c#6Wh3qQ9H#Cc!u=<9v?fg`O`}!%;kPq}|m}(f4lWoId>#K&cfalLmOsW4W5z%q_ zBtdlH$H@OvGirTWr)o5C^etSMc*mMo6+;StnYL0aXEabHSFm_4*j3S7RMh*K28t9u zG?rfHZ>~zNhjsP$e5-aWC48CdUKYr{ice&i#*Hj~@HN;OdmOU)e>~s3dYYBKjv4ri zu(N10F5@p|AYF^3!W*TBlh5v)9UrIoq8WztOn+7^86ff4vClrzlOWoMj3!&Zamdb7D_IEk&*S2 I`;r z(8k`+ju|0Vqh7=Ir%2()vMH!PZR$6=-lIDXU8h* `OVL3hW{M?yiWRt+?Uj6Fk8gbD+Vi6m-9dt8$*FeKzEVl?&wpdzN3`ps~u4CkP zk}AD&z2xH8ZOzqJZMU>d7XNbgTfUKt3StMLTQ!H60CCxkZyW!9&OZW6SVYUQac59+ z>gBb7rdv 5M(-?4-da<2-~ZS_jhA6^|(H zf>IUueTzH~?(zaVn69+aFF-%aTr+GrOUg_z2?%I=@E~Z?U6cYQSCv0~s)(aWnPqzH z-Tj|k(97Vr;WCcg$BPR2QTU1Eh<2Y=d*c*|gIQ~jKspTnoa+C&qyJMV{(rYifoR?1 z$j540nq-uk0;h@sesG61hs@pA{kze$Ey({h(DgsJ8xUY=4p>`|U{Nbw`ueDtq#6;Q z9+)0rkq+;Fu~hd4g%vbI_}B+JYbQ?sp|LR%LzT|Ks+z68f3Z+0D5TB|$fZEbRORHr zjr_TntoDdlLhr82A^`j6%6~Rqr9ax{^^vN$Q;!;4E O<$`^?c)>KcNe=So@f7 zz}!*8{U2n>p&$qfm*j{#_}I`&;?U-H_%ogX=vwR6 3W_N-c 2d}zfWhmQkJsl~c(U7f;{ zXz*3tmfr%7XTi|DmgEc!Y7j`sZsL^2Y}JXLiEn9KeElu1j1Of%(LWo|AB=v1K_FTZ z^6ncodbr_u{4?1a>$Al}KB?2DZKy&p291%-Yl<44*zn-6)8Ik;Q6qW{W|qeYrgML5 zgNjKl>M2RR?VHG9JiLh+xV`~#yHqWN(YRD6ed0d}Bw8j~sWtJWgY9O|kwGsEPZ{3@ z^P49oW06gy5q;HkaZL|~@zc*wisyN+DXJvql3n-^!V`9P73DsDKXo_3{IMUqb}`o- zju~f=F_w%6JPx?r993kNYC<&JUzuI19v;l}=@~Rm_aDJXW(ZD-6ld9IS~O|=$H#>? zws*=Y`@(Xvgm=zZJF%H^NdsT_yYQW Lr=>}oE-2i(xy_3os!~Sm z*ZAI0bs>784#Gn618KZHi~fdDsaAeg`!+&${Q7?CvQMY9PXhWao#rhEZy4k_k$z7; znVNhuWEge$?g+8(^ ( z@n63;=>;-nr$*CC^cr!)iHx3oBIo~x+pCOzO`ib&(0lU048-;S-4JpKPAcx@Htmh% zjKYhxh?iaA{N^hZhjnVYRgU5L2haL+js4y1k?VKpFy-*os#CF#3hSy*+2LV}?!-!q z&9%R;oauwDnzjLP&BMQ};bnCz84J#me3!6=YXSwohku`)X?7YCD*-@p=y^%HCnbNo z3x4CkxBlTy1ajj5q*Ybc#C4S!=vrD`4oLEcqr-N@>43b?eLwq79M3X^dYGT|g@x$r zez$mAy&jC=7#ZK_`a<$s2&s~AYj+?5?Hw#&9kr-pq1~Ao);Yj*sV1Vznmc-RM)U0@ zZ3zrLpP0KoYdTn@(;p$SzKAD)1mqE-ZLD7%IQ5GiSkP;jP497MvZV5OEekI_-C4@M zY~9XFL0KytRmokC{NA-kd-oz+d6y|7CSxZb|Cz(?JLuie9+2xleKxzQzB@Sy7wx7A ze1RH*$C9*BmTY`HicF~9d2dV+y{P^pV33kao8xnGcH=k)`p-VA#f8B)nwDbpjIr(L z5;Qj`3K3Eo&RBlwD0d$XcxuW%&iM}4FC2@LgwU$sE k_Mnf>9hn%-1w>|)?Ks%QAhgErZlRG53w1GzVzMKC>7)pDo{pTl c zB_1 Qbrd&yj#>9jGTpOZ`EFxm(H-~WYN5#+ zwFf-IjI9Fn$&If?q6c;lvR@uxcKh9cGa(i~uYL?NDsdR;&KTvCP(c$ NI_32JF2IM$z^Eu81KPL6*o?!H+K>nWE4W57hMDp|B7RtvEH-~I> zU@38XOG2w>JME7)i^Q0i9v{r`^=qfYX}6o+8}fJG%KF&gW@kGtm2pI)-ou?;;dR77 zg`$;uu!dS@+TIk;S;qTPmDMsm3saMHiNx^^DkypASuXkF>b9jvpfRgHpnJ1c2}P+z z?=!o+I(hz_2hz1o FQsEEWvTkd}?jpr+^a< O*x~QRa)YH&OBXW%}-zSOi^_EAu_W5ePO5TPdj)YX2goBsGQnW#q3EMxHm(T zzN^dXEre`Z`FVRy pfgK)nxakM_xm%5wUSmI5gOjOG?-~iat+?;JA<0x zgon+vs+X4sC*hBSe)r*cl1MVFyVj9UB<)Z&+~u}bPm~^VjPr_({B!6b3`?iK%gSc3 z`eF`BY7I*e@axM1JjO(1EXduS@S1WbOYQeY5+H{50lzm?1sS;W`G>u=+|H`eeqB>c zv%GPi!tY>fxpNkl<%d|NAf)RF*&LMUgF-qJjk52XS1K X(DD{;UqQk(*qI4L=AVh^Y1W)ZvUyDTes>1&R_Lx6X!MDu~z+rCt_l6Cjx7(h|3- z0 FMBX>->>D+B0y%fWCSo==18u&c!5OInh(19gs`D+Bzp+SVf bX77&EIKj!!3d^BWSXZBCFi2 zz yZ+8UW@&t(QgBY&pKPo`nK*Ve`!g<~>)^Au*3{`OiZhi>!n?9a2?+HZ}e ze@!1E=iQ77-k%ffqGZzO9%M5&MHr=|yoIoW=F#Oq8!u%`{I>b}T(d9hNVD>2<4f zaSrw--%et+4}%@V;LE+~!4pynCcF x{10g&@L0HfjM z4U?qji63X{!0OR*kiXc=V)^TR92ALsYDCjd-CN _}m2DQ9jD zRoXmSd;{6_co`+#UqV2+V(k$>FR9ZwItO6_RPgM-S+Oe?yXW5$u8()5UmHAuRz%=& z8FrY01LN~$cX#eNRr7XmJN`xS?S{^~Xc#B;HSa?Ey&d;rWu?(4n@=9Y2WA3zt*F51 zGTt}^I#cdc0U=t{4fkmEbH~i*@~iRl7$^Q&ce^4lDPwrIxd)4OO+OEpu>@z(=&^+v z>m_$vL0XO~OHus$SWcEFLfSq{kaaA!4r)&WGTmwX_D{je-f{yny&QjreYS5zdx3H7 zvi+hF&-p-t@n99!Dqi~%EaZo;Byq9>p2ueq3sSPuNVU(~s}o}{>-qj50WsyR 2)AvXuOL38BKGxr4z*VaKfw=PtT%L45Ne=j;W3Mkjg5&L;1F?g z^zdbjF*`UcH4y+^QSlNxu+U73@vEvzF(@Ih)~}$tXd_MVlUv0B9uW~ybhOy`X!CD0 zrNp@x iayEjDPL*DXCAv3cl%O>N%3B8BVd*e;gOorBC xPq%{0@zjm#GkA zzjc3e$Q~_i?67}lpc2sgsRbJpFiA#%_*vI;HN@s-ylFK A}XYl3f(!8GT(chtZ6AY%fZwz_D%KwYvO1PHcLd2L|N(Zl<}>b$bFJgG75=H0@` z l!TNt zrf!a%vzfZQw<=ppR%Nc87I=B~cPSh*Umi%}>nbtnN~Z3T#E$z49IoK0P~y$0MlK?A z><{A90TK)SX1tuZe( rWGu8ZEyKi5U6rbe%cA{s}6(JJ>c&g@nuY8 zSaU21Ptd^TBkt%i6$o&(>VEQyrFdm{@v;f!NF^MYWYgn5X?#?LJ@s0D$>m_o`qQW6 zc6x8m=8PNm3IEBX?iiB@TYr-X%g~pQc8d{GFeLjcuYQOGGNn@tqtsc%GxgT|{5nZ; zvXk~EEtTJJiH76v?P HDfMYjp?wXTF0 zm;gD-6d%6+a``(-aIDucunk4M@B=5tK;d;d_uiz$*?Hbaoi})$-^xOOe}y_*!SyR9 zsfHW9yX-gzHoJco79v;MQ!%^tq;Tq*yof-X4!2pLn^%{V5nStjH3-S68SuP2Mr_n> zj)h}NTB GIFs-+&1W9`IeL1ySX04RB_X zs)te3cys#ZaJZn(yi<9j*5l07 p zq(*bjK)|MX>c7CD?W%Q_G$^#Mns-|5lpd1Bj$U9vu@q{0YLfc&(Y_0VDl%W%M~j2c zJ89C)oEu^c){h34jFEbSS=9{jto#ei{b|=aXY;pWM2@=#zEDmsEbL!5_w@F@pO}vC zBDXhs0-DbCWoGX|aJ|L{K;3xG`_OmWkBe)FZ6V!e(ry(SIM*o+H4}kK __p?ZR~;>TFtA*&e)tubg1NA^`2S#iU!)k$F5Thx_KEm&YSuIL zxs-${uR8Z-r$K7YN~`R4vZiz8wSVY?@mM$H)H1gM7&J^QN3C0S;h17CC+?9wnD zy#(z<=8i6Y&vFTn7;t*=ts>O6HvZ_alb$}i?l-T6ZT3au^y_e$^PgV)7C%!>`O ka7x62vB-wg{O9X-GwD|^_Uwgh6;x4_k4YSv$ypF zv+VsZKSJ_q+PO}1Twv{3Kx=&rQObOZ>6QHOqs-}Vp9Ue|;9?94(}(jkwxLK*D0hUg zhkXZ0Pz0%F6I`0Z>!QEPO0!+E1{vkAf4pq D(>*&_>7dRKTH_gVXQqL@~OK!ieq$U5%#l z@1)?3L9F>_`4by-Bp(;@7&>uZa1GSj OiFm8X2 zk89aCzgqC)?&=Hp;$k*r3CtnXBYZNs77s6y&8-}qjON=8EvG@OL=_(z2@? Mt<&6RWtb_9qq|z1Pi?&KPoZ zkNnu2o8Z?E%*ENa{&I_W%&FXa0bCosdObQ7vO*^>GiZY9#XpKYPs_4!q{No9R@S}O zXhtd;)8B;!nOj<-)rq1IsKlWcJOj(%orD>hxLZpMqtpUQ@53?jSfr5(cx!H633Gp5 zVm-SWwOg0WM;^gip`&N;di5KRRT3wbKmVo_A^2-I&S+ stKw(UE3~T%bPjm2 z{H@^=EZgsiLkYx4vATWMwzZA;j$CDodsVK-T`g{vLpl>_x{Z`#jf mpIiRkqYUmVp2er p5q2brH4xM7TvGO9(>jF*YJsu<&Z0evBR@R(6K zkB5t`$L+y+&n0yCdsUpGEs}0%Tc&<6@)z8#ibZQv4x>jSCS@PHeVqUCBv#7DHfU+y z(W5TSON1zx%#~GgbkSHS3Eb0+^jV6FG#m@3>^vgfApy&D2d-Cm+=>P3h|!D0Z7!0V zEf>Ra4(Z3o-@<2VcYpkv-?MepOZfq&e%9N?-cC7_^#06TJESJPqjpl|+tGAh!r#0k z!4-VIG!?AC&@cC*pV@dpCPr6Jbt8*e?E-H%%g6; z(32WJWA4_sH-9V@wBJiE>U9Psak5Cdmgm%1aYFp4W3YC|-`c~yXVg~12BalBMztn4 zAY#5+yl#0ie@)gt(v|)@si%kK>nu%uYug|;!Rk=l5!<~@=ON$o31xgS>Pj1w)k_X< za^JFZ;%Ga5pX56Wp=aeLJ9y?4iRC)AoUWX`ZLkvRTF$zkS*r4w)}(>z{&azkQ@H@h zUD5S3(miSIHt1>i2?)TBFe%ftmwjGEVgQHz!4scw)RHJvT1y@t4ctoBdmD+D7b#e6 z7@oYLpiQ1qWBmd#V#L>WPWpoVa2>UaDuaPbXCOwT-XXteZ2b{V9^<0%<*8V@SnlW< zs~D{u7!yTLcxzEdM@bbtFnV~uG3U-7!eag uk(t+p>fos}v*Efn2Hx zjOa;_Ug;h9IT8RcW0KDLWArMs`pmR!Phqb_spsNQa_KQ@f#Elz&a?KfIM_UT>&n)i zOrKiU-aS>rn`K>njZeM#$NJ_moVGx!(OXT;iS%pc-GRm#Wy}#2+zL(Sk~gqOko*Hf zcVr0hD<4PcOx-MqAyK14D=3020$<8w;9yU%q1<;#HW=8MqVnmV^ bg(f-0B}#Ja5M`ZG{15qm)WOM~g&!8_Z^V`QYu5nHLPH3QL#e%fR@Cq8{@-(E z$inHuW6l z%>ZcASPWuK6E)pc`t?3*;%1N!m=# ziKX2Vd(VpYvgj}-ZZ5UQ^zwCNcTB|M>v4N;JpC`(k%{Q<>x(zR=2?vh;3 -hc*<27*mf=9rAxal_;Vh85pWEp=W6ni7CiXSX&h>5?NKesd(2`c=UEwSL=^BlG9 zGd%(v3$+^1c?r%QXh3>!7F}CkX>dOnm>HH^?axmY4Ld5w-r$v!Jo50nj{;Oy!+b}m z)G8LIXoR$Zr! Date: Sat, 21 May 2022 14:03:07 -0400 Subject: [PATCH 03/10] fish feature --- code/modules/fish/fish_eggs.dm | 20 ++--------- code/modules/fish/fish_tank.dm | 65 ++++++++++++++-------------------- 2 files changed, 29 insertions(+), 56 deletions(-) diff --git a/code/modules/fish/fish_eggs.dm b/code/modules/fish/fish_eggs.dm index 81be965533d..15184517c67 100644 --- a/code/modules/fish/fish_eggs.dm +++ b/code/modules/fish/fish_eggs.dm @@ -5,27 +5,12 @@ icon_state = "eggs" w_class = W_CLASS_SMALL var/fish_type = "dud" //Holds the name of the fish that the egg is for + var/acidic = FALSE + var/hatching = TRUE /obj/item/fish_eggs/New() ..() -var/list/fish_eggs_list = list("dud" = /obj/item/fish_eggs, - "goldfish" = /obj/item/fish_eggs/goldfish, - "clownfish" = /obj/item/fish_eggs/clownfish, - "shark" = /obj/item/fish_eggs/shark, - //"baby space carp" = /obj/item/fish_eggs/babycarp, - "catfish" = /obj/item/fish_eggs/catfish, - "feederfish" = /obj/item/fish_eggs/feederfish, - "salmon" = /obj/item/fish_eggs/salmon, - "shrimp" = /obj/item/fish_eggs/shrimp, - "electric eel" = /obj/item/fish_eggs/electric_eel, - "glofish" = /obj/item/fish_eggs/glofish, - "sea devil" = /obj/item/fish_eggs/seadevil, - "lobster" = /obj/item/fish_eggs/lobster - ) - -var/list/nonhatching_types = list("sea devil") //If you ever want to create another no-egg fish, add it here. - /obj/item/fish_eggs/goldfish name = "goldfish eggs" desc = "Goldfish eggs, surprisingly, don't contain actual gold." @@ -91,6 +76,7 @@ var/list/nonhatching_types = list("sea devil") //If you ever want to create anot desc = "An aquatic offshoot of gremlins that engage in the peculiar behavior of hatching fish eggs to eat mature adults." icon_state = "seadevil" fish_type = "sea devil" + hatching = FALSE /obj/item/fish_eggs/lobster name = "lobster eggs" diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index 0821551d6ec..7b8ae815333 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -43,8 +43,10 @@ var/lid_switch = FALSE // FALSE = open, TRUE = closed (open by default) var/max_fish = 0 // How many fish the tank can support (varies with tank type, 1 fish per 50 units sounds reasonable) var/food_level = 0 // Amount of fishfood floating in the tank (max 10) - var/list/fish_list = list() // Tracks the current types of fish in the tank - var/list/egg_list = list() // Tracks the current types of harvestable eggs in the tank + var/list/fish_list_water = list() // Tracks the current types of fish in the tank + var/list/fish_list_acidic = list() + var/list/fish_list = list() + var/list/egg_list = list() // Strings containing egg.fish_type var/has_lid = FALSE // FALSE if the tank doesn't have a lid/light, TRUE if it does var/max_health = 0 // Can handle a couple hits @@ -251,7 +253,6 @@ /obj/machinery/fishtank/process() - //Check if the water level can support the current number of fish if((fish_list.len * 50) > water_level) if(prob(50)) //Not enough water for all the fish, chance to kill one @@ -259,15 +260,15 @@ add_filth(2) //Dead fish raise the filth level quite a bit, reflect this //Check filth_level - if(filth_level == MAX_FILTH && fish_list.len > 0) //This tank is nasty and possibly unsuitable for fish if any are in it + if(filth_level == MAX_FILTH && fish_list.len > 0)//This tank is nasty and possibly unsuitable for fish if any are in it if(prob(30)) //Chance for a fish to die each cycle while the tank is this nasty kill_fish() //Kill a random fish, don't raise filth level since we're at cap already //Check breeding conditions - if(fish_list.len >=2 && egg_list.len < max_fish) //Need at least 2 fish to breed, but won't breed if there are as many eggs as max_fish + if(fish_list.len >=2 && egg_list.len < max_fish)//Need at least 2 fish to breed, but won't breed if there are as many eggs as max_fish if(food_level > 2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high - if(prob(((fish_list.len - 2) * 5)+10)) //Chances increase with each additional fish, 10% base + 5% per additional fish - egg_list.Add(select_egg_type()) //Add the new egg to the egg_list for storage + if(prob(((fish_list.len - 2) * 5)+8)) //Chances increase with each additional fish, 8% base + 4% per additional fish + egg_list.Add(pick(fish_list)) //Add string in fish_list from egg.fish_type remove_food(2) //Remove extra food for the breeding process //Handle standard food and filth adjustments @@ -331,9 +332,8 @@ if(fish_list.len > 1 && prob(5)) //Small chance to eat a random fish that isn't itself. seadevil_eat() - if(fish_list.len < max_fish && egg_list.len) - add_fish(get_key_by_element(fish_eggs_list,egg_list[1])) //add_fish takes a string. egg_list gives a path. fish_eggs_list is an associative list keyed with strings. get_key_by_index returns that string key by matching the path + add_fish(egg_list[1]) egg_list -= egg_list[1] if(!light_switch && (glo_light > 0)) @@ -394,36 +394,24 @@ visible_message("The sea devil devours \an [eat_target].") kill_fish(eat_target) -/obj/machinery/fishtank/proc/add_fish(var/type) - if(!type || type == "dud") +/obj/machinery/fishtank/proc/add_fish(var/fish_type) + if(!fish_type || fish_type == "dud") return - //Check if we were passed a fish type - fish_list.Add("[type]") //Add a fish of the specified type - //Announce the new fish - update_icon() - if(nonhatching_types.Find(type)) - visible_message("The [type] has been placed in \the [src]!") - else - visible_message("A new [type] has hatched in \the [src]!") - -/obj/machinery/fishtank/proc/select_egg_type() - var/fish = null - if(prob(10)) //Small chance for infertility - fish = "dud" - else - fish = recursive_valid_egg(fish_list) - var/obj/item/fish_eggs/egg_path = fish_eggs_list[fish] //Locate the corresponding path from fish_eggs_list that matches the fish - return egg_path - -/obj/machinery/fishtank/proc/recursive_valid_egg(var/list/pick_egg_from) - var/fish = pick(pick_egg_from) - if(!fish || nonhatching_types.Find(fish)) - var/list/new_list = pick_egg_from.Copy() - return recursive_valid_egg(new_list.Remove(fish)) - //If it's a nonvalid type, let's try again without it. - else - return fish - //If it's valid, return this. + for (var/egg_path in subtypesof(/obj/item/fish_eggs/)) + var/obj/item/fish_eggs/egg = new egg_path + if(egg.fish_type != fish_type) + continue + if(egg.acidic) + fish_list_acidic.Add(egg.fish_type) + else + fish_list_water.Add(egg.fish_type) + fish_list.Add(egg.fish_type) + //Announce the new fish + update_icon() + if(egg.hatching) + visible_message("A new [egg.fish_type] has hatched in \the [src]!") + else + visible_message("The [egg.fish_type] has been placed in \the [src]!") /obj/machinery/fishtank/proc/harvest_eggs(var/mob/user) if(!egg_list.len) //Can't harvest non-existant eggs @@ -612,7 +600,6 @@ return attack_generic(user, 15) - /obj/machinery/fishtank/attack_hand(var/mob/user) if (!Adjacent(user) || user.incapacitated()) From 3945f9db34f5914db4d1fa08ba8fc5040b6966c8 Mon Sep 17 00:00:00 2001 From: adacovsk <94659603+adacovsk@users.noreply.github.com> Date: Sat, 21 May 2022 14:37:33 -0400 Subject: [PATCH 04/10] Update fish_tank.dm --- code/modules/fish/fish_tank.dm | 64 +++++++++++++--------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index 7b8ae815333..91d1bf3ddf0 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -49,8 +49,8 @@ var/list/egg_list = list() // Strings containing egg.fish_type var/has_lid = FALSE // FALSE if the tank doesn't have a lid/light, TRUE if it does - var/max_health = 0 // Can handle a couple hits - var/cur_health = 0 // Current health, starts at max_health + var/maxHealth = 0 // Can handle a couple hits + var/health = 0 // Current health, starts at maxHealth var/leaking = NO_LEAK var/shard_count = 0 // Number of glass shards to salvage when broken (1 less than the number of sheets to build the tank) var/automated = 0 // Cleans the aquarium on its own @@ -70,8 +70,8 @@ max_fish = 1 // What a lonely fish has_lid = FALSE - max_health = 15 // Not very sturdy - cur_health = 15 + maxHealth = 15 // Not very sturdy + health = 15 shard_count = 0 // No salvageable shards /obj/machinery/fishtank/bowl/full @@ -97,8 +97,8 @@ max_fish = 4 // Room for a few fish has_lid = TRUE - max_health = 50 // Average strength, will take a couple hits from a toolbox. - cur_health = 50 + maxHealth = 50 // Average strength, will take a couple hits from a toolbox. + health = 50 shard_count = 4 /obj/machinery/fishtank/tank/full @@ -119,8 +119,8 @@ max_fish = 10 // Plenty of room for a lot of fish has_lid = TRUE - max_health = 100 // This thing is a freaking wall, it can handle abuse. - cur_health = 100 + maxHealth = 100 // This thing is a freaking wall, it can handle abuse. + health = 100 shard_count = 9 /obj/machinery/fishtank/wall/full @@ -364,20 +364,25 @@ food_level = min(MAX_FOOD, food_level + amount) update_icon() -/obj/machinery/fishtank/proc/check_health() - //Max value check - if(cur_health > max_health) //Cur_health cannot exceed max_health, set it to max_health if it does - cur_health = max_health +/obj/machinery/fishtank/proc/add_health(var/amount) + if(amount > 0) + health = min(health + amount, maxHealth) + else + health = max(0, health + amount) //Leaking status check - if(cur_health <= (max_health * 0.25)) //Major leak at or below 25% health (-10 water/cycle) + if(health <= (maxHealth * 0.25)) //Major leak at or below 25% health (-10 water/cycle) leaking = MAJOR_LEAK - else if(cur_health <= (max_health * 0.5)) //Minor leak at or below 50% health (-1 water/cycle) + else if(health <= (maxHealth * 0.5)) //Minor leak at or below 50% health (-1 water/cycle) leaking = MINOR_LEAK else //Not leaking above 50% health leaking = NO_LEAK - //Destruction check - if(cur_health <= 0) //The tank is broken, destroy it + + if(health < 1) + user.visible_message("\The [src] was destroyed!") destroy() + else + user.visible_message("\The [src] was smashed!") + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) /obj/machinery/fishtank/proc/kill_fish(var/type = null) //Check if we were passed a fish to kill, otherwise kill a random one @@ -416,11 +421,9 @@ /obj/machinery/fishtank/proc/harvest_eggs(var/mob/user) if(!egg_list.len) //Can't harvest non-existant eggs return - for(var/i = 1 to egg_list.len) //Loop until you've harvested all the eggs var/obj/item/fish_eggs/egg = egg_list[i] //Go through the eggs new egg(get_turf(user)) //Spawn the egg at the user's feet - egg_list = list() //Destroy any excess eggs, clearing the egg_list /obj/machinery/fishtank/proc/harvest_fish(var/mob/user) @@ -614,26 +617,16 @@ user.visible_message("\The [user] taps on \the [src].", \ "You tap on \the [src].", \ "You hear a knocking sound.") - user.delayNextAttack(0.8 SECONDS) - /obj/machinery/fishtank/proc/hit(var/obj/O, var/mob/user) user.delayNextAttack(0.8 SECONDS) user.do_attack_animation(src, O) playsound(src, 'sound/effects/glassknock.ogg', 80, 1) - cur_health = max(0, cur_health - O.force) - check_health() + add_health(-O.force) /obj/machinery/fishtank/proc/attack_generic(var/mob/living/user, var/damage = 0) //used by attack_alien, attack_animal, and attack_slime - cur_health = max(0, cur_health - damage) - if(cur_health <= 0) - user.visible_message("\The [user] smashes through \the [src]!") - destroy() - else //for nicer text - user.visible_message("\The [user] smashes into \the [src]!") - playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) - check_health() + add_health(-damage) /obj/machinery/fishtank/attackby(var/obj/item/O, var/mob/user as mob) //Silicate sprayers repair damaged tanks on help intent @@ -641,15 +634,8 @@ var/obj/item/device/silicate_sprayer/S = O if(user.a_intent == I_HELP) if (S.get_amount() >= 2) - if(cur_health < max_health) - to_chat(user, "You repair some of the cracks on \the [src].") - cur_health += 20 - S.remove_silicate(2) - check_health() - else - to_chat(user, "There is no damage to fix!") - else if (cur_health < max_health) - to_chat(user, "You require more silicate to fix the damage on \the [src].") + add_health(20) + S.remove_silicate(2) return TRUE //Open reagent containers add and remove water if(O.is_open_container()) From 23eb3e4d12eb2f130dd86e7d8ae6422184e25b64 Mon Sep 17 00:00:00 2001 From: adacovsk <94659603+adacovsk@users.noreply.github.com> Date: Sat, 21 May 2022 15:29:02 -0400 Subject: [PATCH 05/10] compiled --- code/modules/fish/fish_tank.dm | 130 +++++++++++++++------------------ 1 file changed, 57 insertions(+), 73 deletions(-) diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index 91d1bf3ddf0..a52ddbe0436 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -49,8 +49,6 @@ var/list/egg_list = list() // Strings containing egg.fish_type var/has_lid = FALSE // FALSE if the tank doesn't have a lid/light, TRUE if it does - var/maxHealth = 0 // Can handle a couple hits - var/health = 0 // Current health, starts at maxHealth var/leaking = NO_LEAK var/shard_count = 0 // Number of glass shards to salvage when broken (1 less than the number of sheets to build the tank) var/automated = 0 // Cleans the aquarium on its own @@ -185,8 +183,8 @@ /obj/machinery/fishtank/update_icon() overlays.Cut() //Update Alert Lights - if(has_lid) //Skip the alert lights for aquariums that don't have lids (fishbowls) - if(egg_list.len) //There is at least 1 egg to harvest + if(has_lid) + if(egg_list.len) overlays += "over_egg" if(lid_switch == TRUE) //Lid is closed, lid status light is red overlays += "over_lid_1" @@ -238,7 +236,7 @@ if (FILTH_THRESHOLD to MAX_FILTH) water_type = "dirty" // Lest there can be fish in waterless environments - if(!acidic && water_level/water_capacity < 0.85)) + if(!acidic && water_level/water_capacity < 0.85) overlays += icon('icons/obj/fish_items.dmi', "over_[tank_type]_half_[water_type]", WATER_LAYER) else if (!acidic) overlays += icon('icons/obj/fish_items.dmi', "over_[tank_type]_full_[water_type]", WATER_LAYER) @@ -247,50 +245,46 @@ else overlays += icon('icons/obj/fish_items.dmi', "over_[tank_type]_full_[water_type]_acidic", WATER_LAYER) -////////////////////////////// -// PROCESS PROC // -////////////////////////////// - - /obj/machinery/fishtank/process() //Check if the water level can support the current number of fish if((fish_list.len * 50) > water_level) - if(prob(50)) //Not enough water for all the fish, chance to kill one - kill_fish() //Chance passed, kill a random fish - add_filth(2) //Dead fish raise the filth level quite a bit, reflect this + if(prob(50)) + kill_fish() + add_filth(2) //Check filth_level - if(filth_level == MAX_FILTH && fish_list.len > 0)//This tank is nasty and possibly unsuitable for fish if any are in it - if(prob(30)) //Chance for a fish to die each cycle while the tank is this nasty - kill_fish() //Kill a random fish, don't raise filth level since we're at cap already + if(filth_level == MAX_FILTH && fish_list.len > 0) + if(prob(30)) + kill_fish() //Check breeding conditions - if(fish_list.len >=2 && egg_list.len < max_fish)//Need at least 2 fish to breed, but won't breed if there are as many eggs as max_fish - if(food_level > 2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high - if(prob(((fish_list.len - 2) * 5)+8)) //Chances increase with each additional fish, 8% base + 4% per additional fish - egg_list.Add(pick(fish_list)) //Add string in fish_list from egg.fish_type - remove_food(2) //Remove extra food for the breeding process + if(fish_list.len >=2 && egg_list.len < max_fish) + if(food_level > 2 && filth_level <=5) + if(prob(((fish_list.len - 2) * 5)+8)) + egg_list.Add(pick(fish_list)) + remove_food(2) //Handle standard food and filth adjustments var/ate_food = FALSE - if(food_level > 0 && prob(50)) //Chance for the fish to eat some food - if(food_level >= (fish_list.len * 0.01)) //If there is at least enough food to go around, feed all the fish + if(food_level > 0 && prob(50)) + if(food_level >= (fish_list.len * 0.01)) remove_food(fish_list.len * 0.01) - else //Use up the last of the food + else food_level = 0 ate_food = TRUE - if(water_level > 0) //Don't dirty the tank if it has no water - if(fish_list.len == 0) //If the tank has no fish, algae growth can occur - if(filth_level < ALGAE_THRESHOLD && prob(15)) //Algae growth is a low chance and cannot exceed filth_level of 7.5 - add_filth(0.05) //Algae growth is slower than fish filth build-up - else if(filth_level < MAX_FILTH && prob(10)) //Chance for the tank to get dirtier if the filth_level isn't 10 - if(ate_food && prob(25)) //If they ate this cycle, there is an additional chance they make a bigger mess + if(water_level > 0) + if(fish_list.len == 0) + //If the tank has no fish, algae growth can occur + if(filth_level < ALGAE_THRESHOLD && prob(15)) + add_filth(0.05) + //Chance for the tank to get dirtier if the filth_level isn't max + else if(filth_level < MAX_FILTH && prob(10)) + if(ate_food && prob(25)) add_filth(fish_list.len * 0.1) - else //If they didn't make the big mess, make a little one + else add_filth(0.1) - //Handle special interactions handle_special_interactions() //Handle water leakage from damage @@ -314,15 +308,17 @@ var/glo_light = 0 for(var/fish in fish_list) switch(fish) - if("catfish") //Catfish have a small chance of cleaning some filth since they are a bottom-feeder + //Catfish have a small chance of cleaning some filth since they are a bottom-feeder + if("catfish") if(filth_level > 0 && prob(30)) remove_filth(0.1) - if("feederfish") //Feeder fish have a small chance of sacrificing themselves to produce some food - if(fish_list.len < 2) //Don't sacrifice the last fish, there's nothing to eat it + if("feederfish") + //only feederfish left + if(fish_list.len < 2) continue if(food_level <= FOOD_OK && prob(25)) - kill_fish("feederfish") //Kill the fish to reflect it's sacrifice, but don't increase the filth_level - add_food(1) //The corpse became food for the other fish, ecology at it's finest + kill_fish("feederfish") + add_food(1) if("glofish") glo_light++ if("clownfish") @@ -339,7 +335,6 @@ if(!light_switch && (glo_light > 0)) set_light(2,glo_light,"#99FF66") - /obj/machinery/fishtank/proc/remove_water(var/amount) water_level = max(0, water_level - amount) update_icon() @@ -369,27 +364,23 @@ health = min(health + amount, maxHealth) else health = max(0, health + amount) - //Leaking status check - if(health <= (maxHealth * 0.25)) //Major leak at or below 25% health (-10 water/cycle) + if(health <= (maxHealth * 0.25)) leaking = MAJOR_LEAK - else if(health <= (maxHealth * 0.5)) //Minor leak at or below 50% health (-1 water/cycle) + else if(health <= (maxHealth * 0.5)) leaking = MINOR_LEAK - else //Not leaking above 50% health + else leaking = NO_LEAK if(health < 1) - user.visible_message("\The [src] was destroyed!") destroy() else - user.visible_message("\The [src] was smashed!") playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) /obj/machinery/fishtank/proc/kill_fish(var/type = null) - //Check if we were passed a fish to kill, otherwise kill a random one if(type) - fish_list.Remove(type) //Kill a fish of the specified type + fish_list.Remove(type) else - fish_list.Remove(pick(fish_list)) //Kill a random fish + fish_list.Remove(pick(fish_list)) update_icon() /obj/machinery/fishtank/proc/seadevil_eat() @@ -419,45 +410,43 @@ visible_message("The [egg.fish_type] has been placed in \the [src]!") /obj/machinery/fishtank/proc/harvest_eggs(var/mob/user) - if(!egg_list.len) //Can't harvest non-existant eggs + if(!egg_list.len) return - for(var/i = 1 to egg_list.len) //Loop until you've harvested all the eggs - var/obj/item/fish_eggs/egg = egg_list[i] //Go through the eggs - new egg(get_turf(user)) //Spawn the egg at the user's feet - egg_list = list() //Destroy any excess eggs, clearing the egg_list + for(var/egg in egg_list) + new egg(get_turf(user)) + egg_list = list() /obj/machinery/fishtank/proc/harvest_fish(var/mob/user) - if(!fish_list.len) //Can't catch non-existant fish! + if(!fish_list.len) to_chat(user, "There are no fish in \the [src] to catch!") return - var/caught_fish = input("Select a fish to catch.", "Fishing") as null|anything in fish_list //Select a fish from the tank + var/caught_fish = pick(fish_list) if(caught_fish) - var/dead_fish = fish_items_list[caught_fish] //Locate the appropriate fish_item for the caught fish - if(!dead_fish) //No fish_item found, possibly due to typo or not being listed. Do nothing. + var/dead_fish = fish_items_list[caught_fish] + if(!dead_fish) return - kill_fish(caught_fish) //Kill the caught fish from the tank + kill_fish(caught_fish) user.visible_message("[user.name] harvests \a [caught_fish] from \the [src].", "You scoop \a [caught_fish] out of \the [src].") - new dead_fish(get_turf(user)) //Spawn the appropriate fish_item at the user's feet. + new dead_fish(get_turf(user)) /obj/machinery/fishtank/proc/destroy(var/deconstruct = FALSE) - if(!deconstruct) //Check if we are deconstructing or breaking the tank - for(var/i = 0 to shard_count) //Produce the appropriate number of glass shards + if(!deconstruct) + for(var/i = 0 to shard_count) new /obj/item/weapon/shard(get_turf(src)) - if(water_level) //Spill any water that was left in the tank when it broke + if(water_level) spill_water() - else //We are deconstructing, make glass sheets instead of shards - var/sheets = shard_count + 1 //Deconstructing it salvages all the glass used to build the tank + else + var/sheets = shard_count + 1 var/cur_turf = get_turf(src) - new /obj/item/stack/sheet/glass/glass(cur_turf, sheets) //Produce the appropriate number of glass sheets, in a single stack (/glass/glass) + new /obj/item/stack/sheet/glass/glass(cur_turf, sheets) if(circuitboard) - new circuitboard(cur_turf) //Eject the circuitboard - qdel(src) //qdel the tank and it's contents - + new circuitboard(cur_turf) + qdel(src) /obj/machinery/fishtank/proc/spill_water() switch(tank_type) - if(FISH_BOWL) //Fishbowl: Wets it's own tile + if(FISH_BOWL) var/turf/T = get_turf(src) if(!istype(T, /turf/simulated)) return @@ -474,11 +463,6 @@ for(var/turf/simulated/S in view(src, 1)) S.wet(10 SECONDS, TURF_WET_WATER) - -////////////////////////////// Note from FalseIncarnate: -// EXAMINE PROC // This proc is massive, messy, and probably could be handled better. -////////////////////////////// Feel free to try cleaning it up if you think of a better way to do it. - /obj/machinery/fishtank/examine(var/mob/user) ..() var/examine_message = list() From 5f8b6df49fbd77f1638905490e5a2618fbe38671 Mon Sep 17 00:00:00 2001 From: adacovsk <94659603+adacovsk@users.noreply.github.com> Date: Sat, 21 May 2022 16:52:42 -0400 Subject: [PATCH 06/10] great --- code/modules/fish/fish_eggs.dm | 2 +- code/modules/fish/fish_items.dm | 25 ----------------- code/modules/fish/fish_tank.dm | 50 ++++++++++++++++----------------- 3 files changed, 26 insertions(+), 51 deletions(-) diff --git a/code/modules/fish/fish_eggs.dm b/code/modules/fish/fish_eggs.dm index 15184517c67..e75cbf5ac4d 100644 --- a/code/modules/fish/fish_eggs.dm +++ b/code/modules/fish/fish_eggs.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/fish_items.dmi' icon_state = "eggs" w_class = W_CLASS_SMALL - var/fish_type = "dud" //Holds the name of the fish that the egg is for + var/fish_type = "dud" var/acidic = FALSE var/hatching = TRUE diff --git a/code/modules/fish/fish_items.dm b/code/modules/fish/fish_items.dm index 2b5298e13c7..400d96802c5 100644 --- a/code/modules/fish/fish_items.dm +++ b/code/modules/fish/fish_items.dm @@ -1,23 +1,3 @@ - - -var/list/fish_items_list = list("goldfish" = /obj/item/weapon/fish/goldfish, - "clownfish" = /obj/item/weapon/bananapeel/clownfish, - "shark" = /obj/item/weapon/fish/shark, - //"baby space carp" = /obj/item/weapon/fish/babycarp, - "catfish" = /obj/item/weapon/fish/catfish, - "feederfish" = /obj/item/weapon/reagent_containers/food/snacks/feederfish, - "salmon" = /obj/item/weapon/fish/salmon, - "shrimp" = /obj/item/weapon/reagent_containers/food/snacks/shrimp, - "electric eel" = /obj/item/weapon/fish/electric_eel, - "glofish" = /obj/item/weapon/fish/glofish, -, "sea devil" = /obj/item/fish_eggs/seadevil, //You can fish a sea devil straight back out and stick it in another tank. - "lobster" = /obj/item/weapon/lobster - ) - -////////////////////////////////////////////// -// Aquarium Supplies // -////////////////////////////////////////////// - /obj/item/weapon/fishtools/fish_egg_scoop name = "fish egg scoop" desc = "A small scoop to collect fish eggs with." @@ -77,11 +57,6 @@ var/list/fish_items_list = list("goldfish" = /obj/item/weapon/fish/goldfish, icon_state = "cyborg_upgrade" w_class = W_CLASS_SMALL - -////////////////////////////////////////////// -// Fish Items // -////////////////////////////////////////////// - /obj/item/weapon/reagent_containers/food/snacks/shrimp name = "shrimp" desc = "A single raw shrimp." diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index a52ddbe0436..cebc4ea1ab5 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -249,13 +249,13 @@ //Check if the water level can support the current number of fish if((fish_list.len * 50) > water_level) if(prob(50)) - kill_fish() + remove_fish() add_filth(2) //Check filth_level if(filth_level == MAX_FILTH && fish_list.len > 0) if(prob(30)) - kill_fish() + remove_fish() //Check breeding conditions if(fish_list.len >=2 && egg_list.len < max_fish) @@ -299,11 +299,6 @@ if(filth_level > 0) remove_filth(0.05) - -////////////////////////////// -// SUPPORT PROCS // -////////////////////////////// - /obj/machinery/fishtank/proc/handle_special_interactions() var/glo_light = 0 for(var/fish in fish_list) @@ -317,7 +312,7 @@ if(fish_list.len < 2) continue if(food_level <= FOOD_OK && prob(25)) - kill_fish("feederfish") + remove_fish("feederfish") add_food(1) if("glofish") glo_light++ @@ -376,7 +371,7 @@ else playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) -/obj/machinery/fishtank/proc/kill_fish(var/type = null) +/obj/machinery/fishtank/proc/remove_fish(var/type = null) if(type) fish_list.Remove(type) else @@ -388,7 +383,7 @@ fish_to_eat.Remove("sea devil") var/eat_target = pick(fish_to_eat) visible_message("The sea devil devours \an [eat_target].") - kill_fish(eat_target) + remove_fish(eat_target) /obj/machinery/fishtank/proc/add_fish(var/fish_type) if(!fish_type || fish_type == "dud") @@ -423,12 +418,12 @@ var/caught_fish = pick(fish_list) if(caught_fish) - var/dead_fish = fish_items_list[caught_fish] - if(!dead_fish) - return - kill_fish(caught_fish) + remove_fish(caught_fish) user.visible_message("[user.name] harvests \a [caught_fish] from \the [src].", "You scoop \a [caught_fish] out of \the [src].") - new dead_fish(get_turf(user)) + for(var/fish_path in subtypesof(/obj/item/weapon/fish/)) + var/obj/item/weapon/fish = new fish_path + if(fish.name == caught_fish) + new fish(get_turf(user)) /obj/machinery/fishtank/proc/destroy(var/deconstruct = FALSE) if(!deconstruct) @@ -631,30 +626,35 @@ //Containers with any reagents will get dumped in if(C.reagents.total_volume) var/water_value = 0 - if(C.reagents.get_reagent_amount(WATERS) > 0 && acidic) + if( C.reagents.get_reagent_amount(WATERS) > 0 || \ + C.reagents.get_reagent_amount(HOLYWATER) > 0 || \ + C.reagents.get_reagent_amount(ICE) > 0 && \ + acidic) acidic = FALSE - water_value += C.reagents.get_reagent_amount(WATER) //Water is full value - water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 //Holywater is (somehow) better. Who said religion had to make sense? - water_value += C.reagents.get_reagent_amount(ICE) * 0.80 //Ice is 80% value - else if(C.reagents.get_reagent_amount(PACIDS) > 0 || C.reagents.get_reagent_amount(SACIDS) > 0 && !acidic) + water_value += C.reagents.get_reagent_amount(WATER) + water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 + water_value += C.reagents.get_reagent_amount(ICE) * 0.80 + else if( C.reagents.get_reagent_amount(PACID) > 0 || \ + C.reagents.get_reagent_amount(SACID) > 0 && \ + !acidic) acidic = TRUE - water_value += C.reagents.get_reagent_amount(PACIDS) * 2 - water_value += C.reagents.get_reagent_amount(SACIDS) + water_value += C.reagents.get_reagent_amount(PACID) * 2 + water_value += C.reagents.get_reagent_amount(SACID) else water_value += C.reagents.get_reagent_amount(WATER) water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 water_value += C.reagents.get_reagent_amount(ICE) * 0.80 var/message = "" - if(!water_value) //The container has no water value, clear everything in it - message = "The filtration process removes everything, leaving the water level unchanged." + if(!water_value) + message = "The filtration process removes everything, leaving the fluid level unchanged." C.reagents.clear_reagents() else if(water_level == water_capacity) to_chat(user, "\The [src] is already full!") return TRUE else - message = "The filtration process purifies the water, raising the water level." + message = "The filtration process purifies the fluid, raising the fluid level." add_water(water_value) if(water_level == water_capacity) message += "You filled \the [src] to the brim!" From d23bdca1c647e2b324baf3bd891992b1064699fd Mon Sep 17 00:00:00 2001 From: adacovsk <94659603+adacovsk@users.noreply.github.com> Date: Sat, 21 May 2022 17:44:06 -0400 Subject: [PATCH 07/10] Update fish_tank.dm --- code/modules/fish/fish_tank.dm | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index cebc4ea1ab5..36ddbe14f6d 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -626,25 +626,20 @@ //Containers with any reagents will get dumped in if(C.reagents.total_volume) var/water_value = 0 - if( C.reagents.get_reagent_amount(WATERS) > 0 || \ - C.reagents.get_reagent_amount(HOLYWATER) > 0 || \ - C.reagents.get_reagent_amount(ICE) > 0 && \ - acidic) + if(!C.has_any_reagents(PETRITRICINCURES) && C.has_any_reagents(WATERS)) acidic = FALSE water_value += C.reagents.get_reagent_amount(WATER) water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 water_value += C.reagents.get_reagent_amount(ICE) * 0.80 - else if( C.reagents.get_reagent_amount(PACID) > 0 || \ - C.reagents.get_reagent_amount(SACID) > 0 && \ - !acidic) + if(C.has_any_reagents(PETRITRICINCURES) && !C.has_any_reagents(WATERS)) acidic = TRUE water_value += C.reagents.get_reagent_amount(PACID) * 2 water_value += C.reagents.get_reagent_amount(SACID) + water_value += C.reagents.get_reagent_amount(FORMIC_ACID) else water_value += C.reagents.get_reagent_amount(WATER) water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 water_value += C.reagents.get_reagent_amount(ICE) * 0.80 - var/message = "" if(!water_value) message = "The filtration process removes everything, leaving the fluid level unchanged." @@ -654,12 +649,9 @@ to_chat(user, "\The [src] is already full!") return TRUE else - message = "The filtration process purifies the fluid, raising the fluid level." add_water(water_value) if(water_level == water_capacity) message += "You filled \the [src] to the brim!" - if(water_level > water_capacity) - message += "You overfilled \the [src] and some water runs down the side, wasted." C.reagents.clear_reagents() user.visible_message("\The [user] pours the contents of \the [C] into \the [src].", "[message]") return TRUE From ddf08e372245a4fbf69d755e7dd8cb46bc7cb0d1 Mon Sep 17 00:00:00 2001 From: adacovsk <94659603+adacovsk@users.noreply.github.com> Date: Sat, 21 May 2022 23:57:12 -0400 Subject: [PATCH 08/10] done, time for some testing removing fish when wrong environment code --- code/modules/fish/fish_tank.dm | 256 +++++++++++++++++---------------- icons/obj/fish_items.dmi | Bin 17387 -> 17417 bytes 2 files changed, 133 insertions(+), 123 deletions(-) diff --git a/code/modules/fish/fish_tank.dm b/code/modules/fish/fish_tank.dm index 36ddbe14f6d..ee7255784bb 100644 --- a/code/modules/fish/fish_tank.dm +++ b/code/modules/fish/fish_tank.dm @@ -274,12 +274,17 @@ ate_food = TRUE if(water_level > 0) - if(fish_list.len == 0) + if(!fish_list.len) //If the tank has no fish, algae growth can occur if(filth_level < ALGAE_THRESHOLD && prob(15)) add_filth(0.05) //Chance for the tank to get dirtier if the filth_level isn't max - else if(filth_level < MAX_FILTH && prob(10)) + else + if(acidic && fish_list_water.len) + remove_fish(pick(fish_list_water)) + else if(!acidic && fish_list_acidic.len) + remove_fish(pick(fish_list_acidic)) + if(filth_level < MAX_FILTH && prob(10)) if(ate_food && prob(25)) add_filth(fish_list.len * 0.1) else @@ -374,8 +379,13 @@ /obj/machinery/fishtank/proc/remove_fish(var/type = null) if(type) fish_list.Remove(type) + fish_list_water.Remove(type) + fish_list_acidic.Remove(type) else - fish_list.Remove(pick(fish_list)) + var/fish = pick(fish_list) + fish_list.Remove(fish) + fish_list_water.Remove(fish) + fish_list_acidic.Remove(fish) update_icon() /obj/machinery/fishtank/proc/seadevil_eat() @@ -570,7 +580,6 @@ if(MAJOR_LEAK) examine_message += "\The [src] is nearly shattered!" - //Finally, report the full examine_message constructed from the above reports to_chat(user, jointext(examine_message, "")) ////////////////////////////// @@ -604,135 +613,35 @@ playsound(src, 'sound/effects/glassknock.ogg', 80, 1) add_health(-O.force) -/obj/machinery/fishtank/proc/attack_generic(var/mob/living/user, var/damage = 0) //used by attack_alien, attack_animal, and attack_slime +//used by attack_alien, attack_animal, and attack_slime +/obj/machinery/fishtank/proc/attack_generic(var/mob/living/user, var/damage = 0) add_health(-damage) /obj/machinery/fishtank/attackby(var/obj/item/O, var/mob/user as mob) //Silicate sprayers repair damaged tanks on help intent if(issilicatesprayer(O)) - var/obj/item/device/silicate_sprayer/S = O - if(user.a_intent == I_HELP) - if (S.get_amount() >= 2) - add_health(20) - S.remove_silicate(2) - return TRUE + return handle_silicate_sprayer(O, user) //Open reagent containers add and remove water if(O.is_open_container()) - if(istype(O, /obj/item/weapon/reagent_containers/glass)) - if(lid_switch) - to_chat(user, "Open the lid on \the [src] first!") - return TRUE - var/obj/item/weapon/reagent_containers/glass/C = O - //Containers with any reagents will get dumped in - if(C.reagents.total_volume) - var/water_value = 0 - if(!C.has_any_reagents(PETRITRICINCURES) && C.has_any_reagents(WATERS)) - acidic = FALSE - water_value += C.reagents.get_reagent_amount(WATER) - water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 - water_value += C.reagents.get_reagent_amount(ICE) * 0.80 - if(C.has_any_reagents(PETRITRICINCURES) && !C.has_any_reagents(WATERS)) - acidic = TRUE - water_value += C.reagents.get_reagent_amount(PACID) * 2 - water_value += C.reagents.get_reagent_amount(SACID) - water_value += C.reagents.get_reagent_amount(FORMIC_ACID) - else - water_value += C.reagents.get_reagent_amount(WATER) - water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 - water_value += C.reagents.get_reagent_amount(ICE) * 0.80 - var/message = "" - if(!water_value) - message = "The filtration process removes everything, leaving the fluid level unchanged." - C.reagents.clear_reagents() - else - if(water_level == water_capacity) - to_chat(user, "\The [src] is already full!") - return TRUE - else - add_water(water_value) - if(water_level == water_capacity) - message += "You filled \the [src] to the brim!" - C.reagents.clear_reagents() - user.visible_message("\The [user] pours the contents of \the [C] into \the [src].", "[message]") - return TRUE - //Empty containers will scoop out water, filling the container as much as possible from the water_level - else - if(water_level == 0) - to_chat(user, "\The [src] is empty!") - else - C.reagents.add_reagent(WATER, water_level) - remove_water(C.volume) - if(water_level >= C.volume) //Enough to fill the container completely - user.visible_message("\The [user] scoops out some water from \the [src].", "You completely fill [C.name] from \the [src].") - else //Fill the container as much as possible with the water_level - user.visible_message("\The [user] scoops out some water from \the [src].", "You fill [C.name] with the last of the water in \the [src].") - - return TRUE - //Wrenches can deconstruct empty tanks, but not tanks with any water. Kills any fish left inside and destroys any unharvested eggs in the process + return handle_containers(O, user) + //Wrenches can deconstruct empty tanks, but not tanks with any water if(O.is_wrench(user)) - if (water_level == 0) - to_chat(user, "Now disassembling \the [src].") - O.playtoolsound(loc, 50) - if(do_after(user,50, target = src)) - destroy(1) - else - to_chat(user, "\The [src] must be empty before you disassemble it!") - return TRUE + return handle_wrench(O, user) //Fish eggs - else if(istype(O, /obj/item/fish_eggs)) - var/obj/item/fish_eggs/egg = O - //Don't add eggs if there is no water (they kinda need that to live) - if(water_level == 0) - to_chat(user, "\The [src] has no water; [egg.name] won't hatch without water!") - return FALSE - //Don't add eggs if the tank already has the max number of fish - if(fish_list.len >= max_fish) - to_chat(user, "\The [src] can't hold any more fish.") - return FALSE - if (egg.fish_type == "dud") // Fugging duds - to_chat(user, "The eggs didn't hatch. They were duds!") - qdel(egg) - return FALSE - add_fish(egg.fish_type) - qdel(egg) - return TRUE + if(istype(O, /obj/item/fish_eggs)) + return handle_eggs(O, user) //Fish food - else if(istype(O, /obj/item/weapon/fishtools/fish_food)) - //Only add food if there is water and it isn't already full of food - if(!water_level) - to_chat(user, "\The [src] doesn't have any water in it. You should fill it with water first.") - return FALSE - if(food_level >= MAX_FOOD) - to_chat(user, "\The [src] already has plenty of food in it. You decide to not add more.") - return FALSE - - if(fish_list.len == 0) - user.visible_message("\The [user] shakes some fish food into the empty [src]... How sad.", "You shake some fish food into the empty [src]... If only it had fish.") - else - user.visible_message("\The [user] feeds the fish in \the [src]. The fish look excited!", "You feed the fish in \the [src]. They look excited!") - add_food(MAX_FOOD) - - return TRUE + if(istype(O, /obj/item/weapon/fishtools/fish_food)) + return handle_food(O, user) //Fish egg scoop - else if(istype(O, /obj/item/weapon/fishtools/fish_egg_scoop)) - if(egg_list.len) - user.visible_message("\The [user] harvests some fish eggs from \the [src].", "You scoop the fish eggs out of \the [src].") - harvest_eggs(user) - else - user.visible_message("\The [user] fails to harvest any fish eggs from \the [src].", "There are no fish eggs in \the [src] to scoop out.") - return TRUE + if(istype(O, /obj/item/weapon/fishtools/fish_egg_scoop)) + return handle_fish_scoop(O, user) //Fish net if(istype(O, /obj/item/weapon/fishtools/fish_net)) - harvest_fish(user) - return TRUE + return harvest_fish(user) //Tank brush if(istype(O, /obj/item/weapon/fishtools/fish_tank_brush)) - if(filth_level == 0) - to_chat(user, "\The [src] is already spotless!") - return TRUE - filth_level = 0 - user.visible_message("\The [user] scrubs the inside of \the [src], cleaning the filth.", "You scrub the inside of \the [src], cleaning the filth.") - return TRUE + return handle_brush(O, user) //Installing the automation module if(istype(O, /obj/item/weapon/fishtools/fishtank_helper)) if(automated) @@ -748,6 +657,112 @@ hit(O, user) return TRUE +/obj/machinery/fishtank/proc/handle_silicate_sprayer(var/obj/item/O, var/mob/user as mob) + var/obj/item/device/silicate_sprayer/S = O + if(user.a_intent == I_HELP) + if (S.get_amount() >= 2) + add_health(20) + S.remove_silicate(2) + return TRUE + +/obj/machinery/fishtank/proc/handle_containers(var/obj/item/O, var/mob/user as mob) + if(!istype(O, /obj/item/weapon/reagent_containers/glass)) + return FALSE + if(lid_switch) + to_chat(user, "Open the lid on \the [src] first!") + return FALSE + var/obj/item/weapon/reagent_containers/glass/C = O + if(water_level && !C.reagents.total_volume) + //Empty containers will scoop out water, filling the container as much as possible from the water_level + if(acidic) + C.reagents.add_reagent(SACID, water_level) + remove_water(C.volume) + else + C.reagents.add_reagent(WATER, water_level) + remove_water(C.volume) + return FALSE + else if(water_level == water_capacity) + to_chat(user, "\The [src] is already full!") + return FALSE + + var/water_value = 0 + if(!C.reagents.has_any_reagents(PETRITRICINCURES) && C.reagents.has_any_reagents(WATERS)) + acidic = FALSE + water_value += C.reagents.get_reagent_amount(WATER) + water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 + water_value += C.reagents.get_reagent_amount(ICE) * 0.80 + else if(C.reagents.has_any_reagents(PETRITRICINCURES) && !C.reagents.has_any_reagents(WATERS)) + acidic = TRUE + water_value += C.reagents.get_reagent_amount(PACID) * 2 + water_value += C.reagents.get_reagent_amount(SACID) + water_value += C.reagents.get_reagent_amount(PHENOL) + water_value += C.reagents.get_reagent_amount(FORMIC_ACID) + else + water_value += C.reagents.get_reagent_amount(WATER) + water_value += C.reagents.get_reagent_amount(HOLYWATER) *1.1 + water_value += C.reagents.get_reagent_amount(ICE) * 0.80 + var/message = "" + if(water_value) + add_water(water_value) + C.reagents.clear_reagents() + if(water_level == water_capacity) + message += "You filled \the [src] to the brim!" + return TRUE + +/obj/machinery/fishtank/proc/handle_wrench(var/obj/item/O, var/mob/user as mob) + if (water_level == 0) + O.playtoolsound(loc, 50) + if(do_after(user,50, target = src)) + destroy(1) + else + to_chat(user, "\The [src] must be empty before you disassemble it!") + return TRUE + +/obj/machinery/fishtank/proc/handle_eggs(var/obj/item/O, var/mob/user as mob) + var/obj/item/fish_eggs/egg = O + if(water_level == 0) + to_chat(user, "\The [src] has no water; [egg.name] won't hatch without water!") + return FALSE + //Don't add eggs if the tank already has the max number of fish + if(fish_list.len >= max_fish) + to_chat(user, "\The [src] can't hold any more fish.") + return FALSE + if (egg.fish_type == "dud") + to_chat(user, "The eggs didn't hatch.") + qdel(egg) + return FALSE + add_fish(egg.fish_type) + qdel(egg) + return TRUE + +/obj/machinery/fishtank/proc/handle_food(var/obj/item/O, var/mob/user as mob) + //Only add food if there is water and it isn't already full of food + if(!water_level) + to_chat(user, "\The [src] doesn't have any water in it. You should fill it with water first.") + return FALSE + if(food_level >= MAX_FOOD) + to_chat(user, "\The [src] already has plenty of food in it. You decide to not add more.") + return FALSE + add_food(MAX_FOOD) + + return TRUE + +/obj/machinery/fishtank/proc/handle_fish_scoop(var/obj/item/O, var/mob/user as mob) + if(egg_list.len) + user.visible_message("\The [user] harvests some fish eggs from \the [src].", "You scoop the fish eggs out of \the [src].") + harvest_eggs(user) + else + user.visible_message("\The [user] fails to harvest any fish eggs from \the [src].", "There are no fish eggs in \the [src] to scoop out.") + return TRUE + +/obj/machinery/fishtank/proc/handle_brush(var/obj/item/O, var/mob/user as mob) + if(filth_level == 0) + to_chat(user, "\The [src] is already spotless!") + return TRUE + filth_level = 0 + user.visible_message("\The [user] scrubs the inside of \the [src], cleaning the filth.", "You scrub the inside of \the [src], cleaning the filth.") + return TRUE + //Conduction plate for electric eels /obj/machinery/power/conduction_plate @@ -788,15 +803,10 @@ add_avail(power) /obj/machinery/power/conduction_plate/proc/check_tank() - //Are we anchored? if(!anchored) return 0 - - //Is our old tank is still valid? if(attached_tank && attached_tank.loc == loc) return 1 - - //No? Let's look for a new one. attached_tank = locate(/obj/machinery/fishtank/) in loc if(attached_tank) return 1 diff --git a/icons/obj/fish_items.dmi b/icons/obj/fish_items.dmi index 645ee303cb59c4330971272bd23b0a7f13ce622d..a1b115976a299e104fa39311a9e72f863186f28b 100644 GIT binary patch literal 17417 zcmbWfbyQU0_b+^gZiWVFl#&h!NeKyQrMp8?x`$5bl1@?SMmh!QP*PgDYXFD1hwr`j zx9(c+TEF+b?;i|v&Ybg{y`R1JXXi|mnu;7Q))OoM0B{xLWi$W)LihNGfd&8oaY!W$ zJQ(+Rr{gAL>1zJL*4fS0$q@j&vK!Jy9gDc31LG&eTE4Pnl2eMltF?-nn-d+uFS?O+ zlnzo4Q8o{KBi}(eE`>DuQHxgsJ2EH`>bJh$Vr?;Zi}aoO=L=8NW0vxib3f{Z8T~TT z-_(t7+3!8 bUHScj56HbsHgrK`}XJn!SY+u z=0)BH>RbY~GSW~q(5mw9$AZ@j-MGYROcg=GM6FfjT-ImJ(R%M>HQ&h!`!)u4HeE_D zj3>93uAhGzsgJ~>?i?wvZCJRfZP1ea8F$dqzr+q7tspl}Y5OAbCR(-j13!6TY i-NIDfBf(rSJe$dRPr(eBLS;OPiug$Joaa{6wWD$7!uDBJI$*# z*($2R)*JgYSz(FbK^lKa&)MA637e9v*0_Xchi3Ov4W9oDN90@54zJYP+K&704-*1` zz!?4IwDOnf06+&Q$h>;zm3^4w>qle>e~>8HZ71Fl`x;yb!(ebsjY)UtCy^QIuli!^ zT~Qc}!JZ$}YUh$(i@o!$ToLteV@r!9*;*4)|2}79;fKWM43P#hvJ3SWOcNru+gAf4 zeBQhY3&o#)K0Ea8H1f9O{WRju^l3ZUb iJ&25@L72pb0-tDQmzg!&`0-K7!$Y95 z^WMk8+FB$su_*ySrB|G!Ct$c8J>3|X> Lnk5U^(K5HRix4)IAH&r5E zzsDD{=bY-lY|>%(1`_h}BqCPe>37mK+AZZu(qnlS!&hrV$Wt1jM&749-4=>LzxBek z)2iHSd;2zj?Y=C%5_IxXsn#2I-gC>b+nhvP%`OJe<)@)roLI2Wr8muB0^H*JD(?<# z(yp$IshMKb=B^Ww9`xAQN#86V5p=E&)!=e-@CU6}*|_s@uTkWZM_mtczk9(i($-m3 z2!TC>+KhJ8^*rrOepmOx>Bubzb8riH95e3_L4$wqffGk7!AjfPSL}3bb2D$Dn7Hy_ zzjC!Y-W})3Xh7X B$yt_VKsgtz65UT@p?>9F#0c3nTCz QXk+0M4&9>JhXME?e n1b4I-O-{BY62cLkO`TGtSyyoF)%H7*GajYbde}VIykk=T=Vz`W zio8w31K9@U_jd!XykaPb0mGP!3pWT5N(uqrvvub2JeM{(MnyivQd3t?G@Y;>Lr|&$ z4W*gtzTf6=lyOZ8(%lm^mrF1FQa~ k?S2NG+^5%~xBYD{?-xcX_KSa3 zmpI;eQ|Ic@iJ3a=X>GrPG36Ub2N4-_#VXZi>OqZH#y&nR3AwqP?@DoB8yuQ?uUr+y zb^(LI^$%CGJy0{r>PWR#q!jRigD8jBG7|YF`>i&j^x}MLw#zjGYQEnnN&=D5((M8# zmE8V#i|d7(J`&GKi(~1?LT+M8NJP#g;O{HfYsb;M@8l08v&!NP&(#dX=ec>E2-5-0 zo t`gLueUTky-@VbbA zk&&_4EFIUSKf;v%iR@%eqx nk3dc)4s$NtcY?K0FaJ^SgYhg04l@_=ZhWno932HtCW-!V7q@7 z z7OwA-PbZ6HjQ|*V(B?OWya;4%u z^dE9TVSjLR^!$y&b!Z;Eso4BWhV^CJcJJ}*H^yiu2=akhuU;>2$qe_4!+}(qANS?& zP45>~sKk7T(~+BNzo1$#KVj)yUV5O#5c8f&s5yVXHnPhn 9KV%{U zE4FU@!|;0z4rf~^vcvR0v0`yaV~zi+@ARC|4=1>;fbysl=PeHW;bbo4+V#hT$G4Iq zi$m_4xPJjaSSuDTvudvWalLr&QRlcgVx$x?UKAi1gmN5?D8rv9m}5f~A3z3rIit|4 zpTIJRmjXX425^b<;vDCSm)ZvAGrmc~i0b?l7yVG#AB>8Pq)1mE`fzu*gf4Fzcok{v zyvc{lZE3fH{xK0W&^d`CJ)G}FPY7HCUawV3Auo ZFpmJqc00GM>PM zhBQP&%%s$YY46nzQhOxy-_|^QJ9e=-wr=*g#t;>? umlkQZDeQ-R>JVScue zJf-(=4Z1CUQ7E?QoTqmFmt)<72MaD>wIFI1@FD@!G|l@rT@(iGZ$55;h;3CzF}vIe zC3!F`EBOSIJvN2jw>_lnu!`c;&BtarwqX8;gKbPbe0lr~=6b Q+B<( zQ&^!CS*JFCo(2%m!bIt$j9c2!|2pZ6Z=tuOn#la5140g*n4(ni-PjW28Sx``M!sx9 z5&>@vE|%eZe>Q2~l(e+ d$pDql1n(83(-g>!CO^@^Fi&-_K%n8(nBMCdyrx;R#U=RSl z%EK^%CvXYrg6Z5sP$KCtmgpe=H>WXLc7<{SeUboxkwn=s-rI7?H}fNu8S!tSs)MP& z 5TbfadE4@8w* zqP5VrH%3RGTj6)} y1 Vw-o5H3@hXGE{_uWep@ zCOPOoM#JeY8^D7Am8@mE{Ija?-wnqNfbJtEBe6|Q!48>-K;KSd#_w*1ghwNa3vhNq z0eNMd0opu&xnx>te1sBC#@#-d6B
{^rF&|AEXe78o6X!U>rsW7XVecMil<^hZ3vOR%Zvq(3)yvbi$tK0 zY~`TG&;|KquSVL- <|;q9b!z=!L8H8z|Lu8zVEGJuZf z8yXD3wSH5|j5++F@(1?&fDg{+f4aw7T{d2qp1ZpvR*El@4kbkF*n!nu!()gut$^sm z#WU0G?H6+)e0Zj4CRbfvPCN7J<~$W9T(5H^HWU4wDj! 0efGW-i?sQ=FsLOV2^a5h)1R7 P#L9b&Y0?s{m$sT&`){CUr^Yg zot2t*knCT3EP*h>PAE0aXj+cvEy4pVt-qZF)WAfha1Ot*tsD#_XOhPyMKcvMg`4k8 zER*}Md`MSRfnPR^Z&!XcN{6}Ez0N;SBH`4nNB1 Mh4;1 z?$TltC}|X^-LOIrL0Z7;eVO^7pz31;z<#Yz$@~nAFnhI3(N mU6IqC!BS{wW^b}H5@SEK{~_KZ7QR9|(C$xzUY zxLwY9TJMA=J48-htsf$S^iO_hr#5fAL|%SS?4q8fQ1dHaP;mS7XmM)b9pH`BRh>`a zRjtI>R)*Lc7f63xav;fXBh26Y6p!G}Y8vlxa60t-LXqq6eiA)$DHL}8F@sz)1QZ7O zLaC9Krexbr$fA?G5FXU2=PMD>Li_39Bf iA1i{P{ByAkHBil{27X@&}l_Z_#~PZLvAa^89&{ zLyhy4X5s96gpYCO54gWx#zbB(x0mJC8dvr~@}0_i2{FU2NtgAQAdy43@Y?hr@r@m! z?>HR`rK#$eAZ%sEh5TP5*8d&8{m-jomjhNG%>(9tL!@ofaO6fe$BZE*)|N}8_x<`7 zv@v;w$TZ_R_pIx%p FS$W*{Q0~?KZ zpRI#H=lph4YqbBp;KQZ#`NmPMALZ7Pcd1{ItwY|!XyDz%ZFBCM+%NEr<2*qR9flbv z#1pGz3RKIl*QqC{BTRfwE9N|BtmyTiZ6o_WswR41bk9UVySkPxvxEkyo|lDho@f4j z@#VLqD&iJb;^`p(tir$6Roe~V-Owt&@j|?xk<>;!IPLoyj)^}+)VU8o002?BmJYVY zomn1PwlQfNIXYk&Q=Vbc@ULH-OUU>MSUGu2QZ(Lw?OiW9Tyw`8q_!vEon(vp;N`@! z_c!4S2ty!hv3;Q?z3CN4m`eDVm)zye{%w|dQHG Mi4-sXkLAAYWE@Wl1;AHrn<;aBiJ34ZebQKX zRz`1SZH+CB_=OA`4%;^@X!7@DF%0ZF&70M 3{<9>&Y zI1G63S){G{dM8@uj)c<26f Z?%_#)z7S7q?Sc23Sz2P7T|F!DWok&X}^XBkg6NMM&NFH{x#9U4s$ zQgdEJ1oRDMf_CdY{R7L7P*6lf-y~+@d>M7PiF@ezel_S@MvVVe{Bb+78?|XaY(igI z?{dBxuL`3)8tP~b4B+^4@~EUSKmVGn -f~N+)ylr&oj|HrrE^s8;$qHDMnO=r2G$Cv5{Z4`ol}l ze@dhY-!9$^izB8dhwszFDPhDs6o+=5f} 1E>zO&jIGu{cYR)yj&0ehM56h81m%kB^O+5g*96p5Gie zMD%%xFq|1-(s^7j-b`Z7mjN(FSI$?H^Aa!X#Ua$g4JeuZp4D2IlDEuoYt>(pH4@!+ zsB~B`8u&126#Omep84Z))(CH{eG~xpv)&MqJF%-Uj!oV?Z5s%tzs5fdPjeGP{8hYe zKhi9%f)I>PhY-i@1^lR@UqMmUu=%Oc|Et!N01%)QQ2swkQ2*`eZ_0|QZn)w2w2r{4 z9Z+5Ev?BgnOO(C^?V04O(04bBGS~#<;(kKsDc P76v`aRCXI2h zB8z>+4%pBWVA06Kkf;=Z6q39v8I+^Rp-#AL|*erB0dlTF(&og00~9B~z@ai~0D zt|L^;{V7aM2#dgktb-IF`))ld$|EHPu0R|%+xwjQVdOa-5tY`i{wfP#6q8_)HE)tC zp>#UZbEO50LfP7teXJHacJeV?j8vN~_>>m#QX4;E%s)en0-4Vi4?eXO0L(0?U#hDo zzG_%nSnLS!6)rfh_qO3LBd>}!VN?9+6m~#&M|`woqOmx1u0p@B6>L` zIiPHQVlcGbNensqGsVznr `OdKKX7;NYM$tKushF3H!CBypNOxquHO@~x bwLPnc@+n!;&R$b{?JPb t@9zB?ZmR ~W?AN|kkpv`)4JQbVtOO+1=R$Dx}JVPvAGY$ zudx>~5y(nRO$}4d5};>e!ybsIm9w>F-BP`V_HXlDaDJ{j@uuxy;2kfGxQI-Mt9eD7 zYg~+8cFWGXge3`TXESpFdEIbZrA_2|G7_Dpk4n-I0X_8!#wryIE3#(}7aq$02CI&@ z{!{XLTORjOCXwk?%gEHe&R0Jq8OYzmh%U|+f!*%ypMK$av4$U`=0iq1GEp?~SU3da z0GQ>XoJhN1U{3@9TR(pjGJ~w)MW^J~B3&Md31tf;lu?fi+9}~j7Q&xI7Q)V_l4R^t z)J69d|6Ecbij$5o%~i#bae9hsw%JKl2rZT*rdvjSi9U(Ars#?X0+7^@CfQo(QVS>! z>y;Fc`s@c@UHJGQHxqV|KxMguT0P{q+W~c00NM#MELnqMh%Wj=g e@uUk5EPYek`Q2qLIchj_W006_fN@C_*|9@ezvuD#xKJVg_?-FSl#Ze=RKRUG%!| z&y4 BuECgkW~f|ZO`6*%G=upAW}h<)sTrevu+HSu;_ 4evjSBbcihby6@^Qupd?x?|SGt;}{+uScCy|Ov}w>Ec1 z`rJP^42C)7I(}PSwSg1v$SvOvJ#u(rA1ZcW=hd&~ye~@ciYYT0=T{uCw);XoW_@+e z^NVz~b17IU-M+E+6bg?@B;`hYRx+|DMprN^CRrIJ4BHl&Hwt(Dt!Pc4$eQ^qbcOh1 zUM%Ip?bsp-9n nYG$v zx)%O89^ic+VLNwQwrul-%sH^%;#n4sjU5U@5$s fqj zX!!i$VhepAc{KEuWMAe?Jkj<%?*sN%l7pJhWa3Ln$ Eq73be8m-cG>E`= zU18frpS&-OcvZMR|0?jb<0lNiklZYAJ*#u^4>w_p`LT;Cg6ltPjd7_B4`p6Q_L{`0 zBBssNe{1y1z>oa<=P;f6FF*__Nxm1_-$R3GsoxH`?cSjP(0W83s(wt{jWg2I6tTZ) z4P0OC2xkQ8&Rv>fYnd~SrTt;Yp-JK7KJ^Z4nXULx%k0KezsTAJ8|~cth#seRT4?(8 z$v3^~Wi^zwU?2oCN7au0z6P7b8dWq5-TAND+|brmWKJDrx?jU3E1#X#Sd4adD@QBd zB8MqGDjIq9zgiSgBNxcN8p@(D#AzM7KAR}#>uoi%7ZF0u7<=T0P|7XUz1o{Meb}n} zoo8d8tu@r!{kBS`gcskVZbW#xAwwBLDYVIP=)HtlNrf9eUNgfBHnU+(&XSFttQWv? zADN9K(q~FXS!K;@CpwuC-ye-uqxvzNvX{g02K_nH)>Q_?)RWlHfBreDmuN6Saug>x ztPXGaMqCPkw$p)0&~(82SI@ydi00vyVIDpC+dUH_FLZJCugU$)ZfdH}aCRa3y8JB? zL@~!!mKevRz2>KoHhWapP1N02mA3SF#AG7&+jjZ)=n_lsbpp@d^!O~k*>SNUCcV4! z_d7>0*F0h4*|@6XM(#?>>m TE&Is=wuUkHE{1(imlLUvN9Xz){Y@wCN`V^*-AGmWDO3#l1 zj)+%vb{7eOj` =$83JYWn3>Vz~Qj`~B$qnZfu0N}{!hKvqF z@;XaWny7MTK9bqxsgbcCCVNaglEYtr@;_dD;y5qJGaXzX$OBf+O7%Io1xCBW&a`WU zH-V!8Tn|JAWnVJ+11i69DC=j;n1r}lqh_2=L$AorO0DaJho9r)dFDUe%75MC^q!rc zZ)Xt0?+C*0?Bp6@&-e z)9qxs9StD&Ip ;T>*sa{*1>N1=$AyzJMz@S?%yD(3r}^`?w7 z9b ?gz~mVIs`L3#D%b#=$rGIVgMN%)1ftXEUmt?*=CAhz z)cT?>1G-D(sYZ(2FiV)B^TK*uLs&4gX+|M(Awk?-U=m#;lA#?2zTtxM)Yr7nTdMSp zUYd| YE7oIqh16dnlN9cc*`Py2q{<9U4-yOM0 zIe3u)-Zy;eCY%7kZlDvrP=$x?AVKH&1&K&Fp^@l+&jQfRpwMF1kUYmMq I_tTravXRf;sns7K_vtiO6T{{R)54X2%FNA>7=HvDGYRA88d;y> zG%zr^UA{rT?>^!qH7j|5{|>qJq&jynS7p502V3wBoU=>(3H6k(d-YYH)#eRq;ecfr zi;SiLg*{CGY6TSaBdviRvbtK4$?^6yhPq#G@tHs`XBXomuhcyAl7>yo>4Mc*W1+Ax zllyPiiU@X;b5B*97k%g$wFTt;+v!iHItbh8N_J4{t~QXEP{`=DgaY=W&>~61k>E8Z zxKOr5)ZIzo>o!;0n~qvhVoLS#aIb2W(2r2rICmKonVK(QETo!XwqUHBoA!#(gsEe6 z>azM?{`Ky;lFdy4`3SNIw)*XuyrmE`^~%9ogD+}c%8WTVN?r=yj48Qf0&c%aH9duB zj;tT?bY87E4?(qR6agNhO~_t~d+SB@E_bF$UQq<2r&wlX>ifhb#Jc2#kQtqpp8zyv z-kL!dTODJpTbvQ?944Ac6^q>~WkQR&f^4RGfU-OJ=6SLPP(~lEhI+8E?xi|W`g0P) z0Yee8chF2wpf<<6ffcsIw%%T1b@VAOf28bt;dfo~PhtYh_`cOQUKve&QnCUU!DNzE zR$#q4m>jbe@Q7d$w;v)9M=@8}F*cz^>*>oFm6LHrLZy2}66{W|!_wCm7RIDxqcd(K zZr!(REsQUGa4K*`|01UDmXOOCw|YEsP$qh_%+7Z1RQO1A9WL+wfQe2%)OZ@CCe;OUOtnA;LP$@5kI}BaOT-f*GqO{{l^T6 z6HB9LyZ)N?e$9&aol0aC)nfnn-BaIKeu(a>G!pS@bH-48g+=SP^^HPyrO<1dMLhWL z#?j5948!||Dbg^5S7?}O(8-y$A;Yzm