From 56e900d93a9e29ba0f046ea3854e037086822657 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Sun, 9 Nov 2025 11:28:31 -0600 Subject: [PATCH] Add physics-based collision damage, spatial audio, and synchronized audio loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audio Loading Improvements: - Ensure all sounds load before gameplay starts - Wrap RockFactory explosion sound in Promise for async/await support - Move background music loading from play() to initialize() in Level1 - Update loading messages to reflect audio loading progress Collision and Audio Features: - Implement energy-based collision damage using reduced mass and kinetic energy - Add ship velocity property and display on scoreboard HUD - Add collision sound effect with volume-adjusted playback (0.35) on ship impacts - Move explosion sound to RockFactory with spatial audio positioning - Configure explosion sound with exponential rolloff for better audibility Technical Changes: - Reorder audio engine initialization to load before RockFactory - Background music now preloaded and ready when play() is called - All audio assets guaranteed loaded before ready observable fires 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../assets/themes/default/audio/collision.mp3 | Bin 0 -> 21146 bytes .../assets/themes/default/audio/explosion.mp3 | Bin 0 -> 43104 bytes src/level1.ts | 24 +++++--- src/main.ts | 12 ++-- src/rockFactory.ts | 56 ++++++++++++++++-- src/scoreboard.ts | 34 ++++++++++- src/ship.ts | 54 +++++++++++++++-- src/shipAudio.ts | 18 ++++++ 8 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 public/assets/themes/default/audio/collision.mp3 create mode 100644 public/assets/themes/default/audio/explosion.mp3 diff --git a/public/assets/themes/default/audio/collision.mp3 b/public/assets/themes/default/audio/collision.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..5b55eab58e694f2b0137e68c9bc96683efa97874 GIT binary patch literal 21146 zcmdRVWl&sAu=eg^iv|`aKyY^!4YI)E?(QzZf&_vr?(QzZ-8BR!xN8UrPLKcz79e3i z-XFK>`*r`{sp>j2HK)#*nSQFfXZjgMI6n&DzXH=Sl+}8EqCE>A53hg@TubKvZ)(W$ zJ~zppMcUKR(v`;2)rLmf`|Wd0+s)I`!O|7^m~Qjj`@a?gM_2pj7hXIII{=`i0l>y4 zBBG$6rKM$I;pP?;6ciVS!`0N(baaf3EiEk_9X&n${QN>fqN9_Nk}@-kimIxr8XLR1 zK7IN$GBPzaJ3G6$xVpNrvGMim_V(W1-r?cN$@St}8&-esr7|?PO0Ko14#__PDoc=!@|5u;L$NlH^2Vr0u>5>7!{4lJUVgQhu z*89!0n<*Hd7I6O&eB>VRDoZjwnEOwG#WwBl zZRFtP-!5S=2$=NrA__?z%<^1~z6_9n!9W%rbhq2ZG+}tCG7CvgKz(y9!7sY#D6kIa)TW6T{xJboX(;;eBBsl$sg!`Xluu%P% zU|ZdT1xly>y6@RX|D#<`5^-I}qKud)uZ4gBsjk@tGR z$QPkq>_9R|*m!KDv?fBy!=O8hWw~-V)bLPie#tB02Xt?y|H{4n_hB4<{e&ew)qwEs zHh%hcDB~|9!~tM#G#{>fa8M0`ih2;J5+reFRx0j=t306T%;9^}1cL5ULOd1)6-N1) z6%u%OmtrSO{1vGu7qsKCZ*Z6zS*BE?HsBZTdF7fv;6cx z8FNbQ=(4{H<}#g;&!q}MjwcL@9Kc6|Y5`g{Q=H}w#Y(PMRo3tl*}mh)USdLB)-u>I z6n_Wobm@hk(N^cNY@zee&APW8GUR@9lW>iOVKtJEPtFr5s|Pqj*KN)pD)XddupBxUt>rr0t@K91Nd z12FW=z6Lqd0Ny&}nNN=cNOml3x1tc35Zs?ag%+rJBs8^@^q)5qKTK}O-%UXqRL!&}JQ+9X@2nDcW*l`{=Ndp;oObQ9_Q~1 zN|**4&)*P+9F;^-=@49_YVuX~nsMU`W8TI)t7+3mRJRWo=QvC8c{(svX`x}W#_%Sg z#FmxQ1Q0PciI(8?cx%VDB_DemwKv>~J^gmtz!h0Z!=*HJ_@#}gwM2#GqGjVo71X8t zCaDV{v_^^iIl}ARw91%JTt4CgsR% zo-Y)_%eHYIFCUk0?izc)UoSu&X8rq}P+INA0X8g|9(9F7~ixseiY&Qm-HjfXXGdwplSdB0N_WIM8nX7X!dUAlBsUsGCv)ct%KhiBG`cw3`ncJO;N zr3V7KD}5W0i-Xnr8Y)ZBHWCRaMPTIAa;u6q)5r68P1Tq39oF-H3}WPH@Zj(gXwbP|DjBwC9psM0D~A(q77FGgwWK) zNEspkQ8WynE|Qa&&v;Ho(5JvS{a4Osx|qpo5&AR{eG9Y~(LKK~tQ^m+aVi3f$MmnK zfhbxdbo2A!@NgQnKmzaa_!x4Q)%X~uRDz1M5Q_apLtt2mmh~H8lkM;hzV!8v1|S13 z|MUXN`*=6sO^NP)Pdi-t-ojd~%hsfy6fOsp9go`78bJnDaVnYOQ_j{){JMdqCw`hq z_H53`$2Oat}?R zQ5!huiz|jrJr|2)!spUwQS+2b^n)RMB1#Kcy@82cKdcO!U08h@$uKa`%0GYTZaQR6 z875Me4Qs*|;evT+t`deWc$R8bZ;ld{N?TWa23iU%RfWf9sS}cGB}w3hhM~{Dp0L$z ztm1W9b5Pyv`BQlC+wg4;`bF9gvAl=h)}`(UTWj&LadV=bgU( z%^d!>hLX-kp7htcH?Ay&s$39Hz6YI1pR*r?FgEdB^EZ)?!FC@P>yxeF9qatq!=s$C zOvSXPQP|?TiXg(J1lwOFOFw6MXf_2_18KAcbCKT#moMnQFXGDMRZdevU`bVV7j zUHpR|kjTcbgo)Y)dUb>H0<%QCwCZIFp3XWj)DShB3oyaRV5n*cCU&^W6%GCmW4pUdOiYO8OM}+*CQ+7!l&Cd&cuOKrDx0CAtRd4k<$v9LH49z2 ztgU6q4Nbq%9F6T6F<5UxkL?HNkIO4Fr``qrc~o!Hc^7@tovcltyU{7q4sVHdec_quvOg$<90IF2}?@8X{c*Q{moF8QQ(HhZ8Iw46dUeX4F2BXD3 zyKR-)-3MxN1q7sJ<*34VgulSyf+IPiUtU<@c`#!0^a_#8T)|Ix$#FU>Vk2Nt{0%mu z+K{vZkgP?{`8%7ExcqUc!myL_by0G|%Yl2e;HMN!;513A^jFlTQEWT_tstApI2HdZ5O4-P1#(~Y(N%RDEDRVe~pn@k>{=#Z0C%Toiq>-drdlchTRLZ13 z35O(R)E4a~W*Vy!UP9)nmYr>g&kwY|i@?ldjzKH4U&tcxXZi4MhrUt93PSGw&nrNf zMCH351s0YVOyI|xPxHY(%f~#e%i|`=lPU$xNp@Ki=N+FeCZ(lSROtq?qXBem0b0XP za)sNnG95;6M+RxnZ;Aim=O_{#U2m0NUFEmh=e&L~=1h_hU1Lt34WJ9TYrqv2)Y4=m zcxYwN6Sr;1tlf(Hq{GTL%V+gVhg!3~-@gqnarAEHey**Z1~8sNbytq`*D~%$#{6Dm zx)y!}C4`7Y(H|!=gmg8oo=vS;Qi;jnfhg0?4hkaxkj8*mSb?&H0T^uy_;nD_MQlhD zGaZ5!Wx97iSw|9`Fa;0%2Ad<5N{75udcF%gpVBy65hYEoxp{$Oy0-1p@{w`?JoL?U zb>vGkSC{nRMR+=RA!lOQIs}Mm&qSpbuSGLS zJGlZZ$%aVLvT_tkF%MoPO9ATDUpq+9QZ}tNk!lidkEf$JM@NS^E1~i{2Xl7rEMYl$ zP}?|CVOV^zVH`f0F2Ul49Sn?V6Gz@*r)#uF8(|!jciCr3i{XwGqmNm?XQFRrMGb(< zg}5{ee~2GEHlaF@;-pja1`+x&VUTQolFb@|oS)ETh{nENVs&?E>8fLl*%^T;@=n4G ziO(jkZeG}`%hmXKnyQn@wyS<91*xuD&Jibc%e0^s#vB>nFU|&q9g1fik~-{-wwj6T z4xxD*$oyZs`>Sya>IYw#4gafu* zf=C$*3?}P<(P-jAqZm15FchQMZav4@nhnB!p|!%-N8Fo38<^QXgpioU5%iSusqtsm zJHKLG;w;N7jNDO4ktB*VQBWsj?GR?g$gJ;Sy| zrHEuzD50(v}vVXKXinso6q0#L?RnBKAcYtlW+iO0Jb zrNaGQg239OHfrna?4BF& z0u8pFg!7DD67VhMC=9_`KD-AE&IRyR;nJKXnLQFla|MnJDa_%!$|0W zCRMt;IU%XJ!M6s;NuU8>{D+@Ep-iIYtF7wL-;PnvxR%kuq^g>RxIEvaYV$d~BU>m} z3a6M9SxFdNQ-{Z3#0v8U)=lf%EE$0mz20QJEfr2aE$cQ>T4H^A=?!KZcKXWc-5XC5 z3y$MzVIMHeKFCiMn16P@pbl~qbGW8*)4tPw4UIK8I+m{?A&BtMKCFDWrJM+41Ka!P zGB8M?G9TkCNV1?DeWixuFo{Uz`e8x}Fvv}&QyTk2h*8S06Hs)96=Y+K9Nnt|A+!}K zDFmL;QzLIRmhw7ucJ{AUz1!&sBb*?tY-KODF5l+qri;wIHX_S|+x_&b9G`CdU1aXF z{x!>0&SZJ*Q^A_Y`;~4v_?OHg>3;Qf6Xj_95C9C_x0f+AkwJ1cr&GyaSmfGe`G;gv z+eNM0Ev;wpPw4b*b!TZa@MT=FB2eXF)ybkH;5U(W^aarW?<{xDTI-cr&gRyH?Uyfk z8S1FUVpC#ge;0b+Vx{?vU3y~u1f3sz4)G(QSD0atd<6|FOJM^A9E@%&nbm)iNKZF@KRNmT&E9R{v~Ms|e9+|hL= zBPGve)~}k-Ew+c>c*kYY6;j0^AD3-55vauS#*di%ld)LFlGYrww44PhvzBR-46LW^ zQKjONTzj*hUNL=R30GyxeH>|79I5aya1`Qw6}7;LDSU3C5nR@_BO_(7a9H<-7N|(m zxhQ-pe9&2o-rXth|XMQqg9KQi-w z^-eafCr*Jof4lWqSFGs?)>diyEm!wrzvHR$k4D#(=~(|^#R?4zH`F*THVH5;FydWE zQH!8i^3mL=^}b$S{q5AY7SJ6KXb>j8g&Ri7Mf1ENoJ5~hf#a0oyLQLhxO7C~1B^55 zxv*B==+k7e!j^@23TS+?!(9c$;yesiq)eE*C=1If>r;C3AbK?9A9p~vzB7mztzo1 zO3eNm;_Rn8|6Qio3*1;3C}Ap}8}#)|d&Res;VjY0ST`}Nrj(mi@goBhD3cM7k?N{$ zQPp)0n+d_7?0foF2=5oMA+dFl9*(n%^9Z#!G3t+Mi?s(X_qVQ@|?)l^Xd z5*5s6?@UN9VX*nu*g&5*0;|T)&OpA+WccGRo5GBb3S+%-1au?4ybuM*!A#q}29TNk z=tDR4Yg8MR7us@@Vfo@I8NJ-sPT<5%qQ}aY(6AFQcNAsZ0Spci_XRDqxWT=9jn01q74Fo zilpPQ!&}dmq0|gfjC~7t5Cjm`jMBKRm9aq=cW0q3I>(01ocDF5gEOXfcFY8rsA&<5+4429E}FZt0o! zD7tMwi#aa`8zAil*IF7hm?!)K6-hJ=YlaGas*ggU$`$Z}Bbej=$+9tPu5{Ki5CyKP| z^wmXJ#V+#SkygCQo(^EtkV6E{%i^sxS-1*x{uf>&vQAfzY<^w?fL}>QrpE(DqzzF> zi3Y?&*kaQONzS_)UdJ~7{}=%Eq(hItB&#m<_=owS`OV$MZI_w*EH(TYu|L1nu-= z<=z?^`k1!UNa5IgKJ!(1>^;xny~Mfc0bKD!Gr{lygjZ>IxPyVHKo#4bZml}>mFuL_ zArwa??5fBf2AH-oy?7q!fBx|+08Q1*@RT*sU!8F?7z5=s#MadLtZd=9Dwm@#yyT!$ z7xgt}*D*nYL;1LIahGJy#B>rI!KmOxeH@e?30Lz2O zwA5(zDF`i-PKh2d5kw%ip7hmoz&N|sZrTlbi+(!HGV}o@T8GaxTxKcG@ieBB^v1?n z{9otAZ9}kMcqF}(h>g-W9i&;VQR2pw+iXA*)1D1K-%p0U(@9|u`u74@Q}sb9$1CaK z1J4=Nr~Xk4BDy8DBjU2DU)PSel+Ek;Q`csGdts>(eW%m>M}e;&-yeNTZIY!!2{p_h z*-Z3RuFs|GQyx#mr@VP8`j@2qo-o$h;huPcY@|egys9{$w4!0D&-bM++l_dPg>p=F zZPn` zvlw^qtA}4jV485TzE+wW=)><-iEi>HwjP8I z01CP`a1a52{U7(zEN!l+`?za@B?}i{F1k*X=5lyn;=gmh&+JU{6-v`OoD3wCqh1rP z0CY0(Y~6oK({AdVx)0NibM$Qg*@p`Ns=vO`BPP_}WBioc(jic5P}jch89xCmoMOK+ zZPwbC!%1zLbx-bkOTJ#QYCL3mKgJv~9P9l{b9q)oKwVU8gSWSz_(&`O(j-!EcDS`)h#lCWRc+jl;XW#nRbz2bPUuHFEow`S+Y0;EaC^;paovS zfrZ~Y7HLd|)&pvT3sVy9EC#$7JToV@kIi?iRD#o>b!ZfFTSiMNU+@x*p@?XOSB?jO zv^*(i<=;?$!;GR7RG@e28DH`m(8@bXyO!#bctN`=v#wA3PCd)+;iu*cJo!iR^*~05 zkRIeS>Q<7x>Voz7#~lczvR-!5-|qJu&ieYFzP0|B|5^kwl;~`naw~PYfKMecz%Ps$ z-)o#(?hO`E)Col5{#~f9*Xy#$WbhSEovm{>mt$UE&*t_zllwYbz;>>Lg$}0`A$aV1 zEL(i%@wfF)q?A+bBE-hsCpxPVK_5qtoM(DGt=gg}5*=|e-KKu}o7GwruU%A!1MK)wup8P~ z6P!RVX^x_c+^X0pwvgEX6)#hMj_XkbsSZqrhXx=FLd79NpwGt3GA6GMR4R2inJjTo zUU%_u5+kO##)qxX1TenKy*nL78AFZl6^7Q1|KZI6jUuRNgB^Zs}j;L<>jd|z0elujAdE;VbDyBgqsQG+y2Dq6?s~8uH zKoDZu>@q+Hs7qC?xOKJ2Yh8vYV%V@z{JQc#&0kKWn0QHnN8(QkRQxzTVnHE#P|YrG@JqIcoFxS*eYR^&<}8RWJpV*S zr6ZA`?saY|*rDv8YsgAdtxm5Rrb-fd%^Ffd;~GERQMwHQ25QF_%QGgop53}D$WoT= z#IIYZw@${W(QJ2j$~kLwIblDzav-G8l0v;{i?qt#lzRXC96F#K35(VQ0XnPE1XZms7PrAT>Z z()6Q^E^tC+ZXs$aCpOV6=x(W>7~D+*prnKjvD7Oy#}%f_uAvgD`|oGod{$Su*09ucOgs5DTp|4;r~(09XpK<3>-2njDWM z$m0O$rNbAMLxeB^0WGu^b)rdZfH3e2?nece(`^XAHSYewfB8V(t4?XGSZ#__m2tkU z*^AuYECIN!qZ+j=pj2V*djM2sJ)uyH;1~>0TdD!NND_mcS+;QYIXP6OHXTZYG7br} z8d%UUCFFq>I)&lKf37Q+Ib}7H0PtAxI8O@tu?K-1l}ZDq@vC2?1~{BkHE@St1XOa^ zYME{G2^?}*V1+Mq(tD`0S_G=^GX&@;=p3_8_eC)|Xou*sWot_`As*{%S4I-1W?hE{ z!l@&L;9OsOM?D|8XDFKOgUA5y^jix%Hfq>NR9j7g(hu}Hb)ys=JSC=hp6L$q>7Gfk z6hH4yZr<#b&CMqE)#A(MOaa2W%8Me9r`ZtPsE+NbuC7FRYLic_K?T8U|MpU$9qsru z06^a(FE`4Dtg;{_jg~fL%%pyf)Z#b7jIpMF)4EQes3wC*t8gZ?lp>aB2U}h0HgJxS zlVV_53X2Je&t? zb~Afo$kEYeKtd>1T6h1){=fL@0f50_u~eI+)?sRwr*6p-MhNt?uiK$L{>SR_cbX9w z6(IqYQccYi)Dk2S+Q6d@ZHgMT{p|t&xX=GxJHto?nHo>5;_b;qi%PCIS)!STDUJx=^~cMD=%Dg#%!{6?33zHtvFY{z@bYx z!3j?W0A_EJHB9-Wrbh=$BVaa4H)@vcW_3x4m^z7SxtX7>4_7lM3?AkkSVg&O#oVif zv)`QzH>zu5R|j15jubF>nipa?(ls_!Vhtp2KFsj@<%xIkEDZPJH$KhyS%6|{5H zcV$s5KQdcn;u!D;&}IDMVaCL0UeNtj%eqLrX<`X|=vT|MuAXDkPV8EXy@Ilp{+OeO zDP<3$2!LNMq#OgRbgSbvSr?nms90Bd@M9vShT2Lqt6tgNv2;gF^T6Hckv zhIz!Gu2UZ_=6m^&NZ{L^Bb(=_UOQN z^0Y=5OP%Mb%-cytR-{)Rmz}$_WuUEt9EB7bK;}PJ23qNm$-L7Sla!P+h{7s*Mm%~o zt`K+zMa$s0MIfY|`2CIYDm9V!MKhYohO6Sxtj7vb%u?fr-fR&ygYIb27nPCsdEb7x zM_YgyE`^J4UXqXvh-5JK|6?OPwN^+60%i?|2ZzB-V7z>;cPt?QhT)!(p`M?9irPF! zjL4{++DV(TgbYOSTN6!_n~(+_Ia2knXplFN^mhqbuILTxmv<4-GhaMk%Pga8lsqi% zWMX&gwp2SRD3RC+uGqZ%;=sB7?XwbNN*ys|k_Fq^_&wdon$~90uls*48i!_Y^kxvv z#Zvb~KeGiCnxb=!*;Yy%yfQbAn>hsZQlKl0wo)*jidZ-Z3_yJ%WrPlCf~~otihP^5 z1M~E@n=V&9rNTl9=c%PFOKr;|Jj!jI?(ck8w1`b#VBb-4uy&Pr)X*_Sq`iV0M=Y_wX<^qWLl|G z006nSgm78j%vp-)iju2?C4Go>SRs6lc?5`}Df{8@*?a!K)j(Zt6ysqfHtj~UE zq4sF^J$TkU2?ti)qDiSQjqR+El)3VK7O^`5S)|KX4dzv-< zvbI7;km99KRHf}VuV|SCkF_r6?7Wv17ceY=dcrfqN0puVeS_cEU+rlJeeZR>@B_@~ zT}l+grlOj&0&M=QbrV$Y;ZTh)4CisLtQ<~ ztK&S}iL4aeOz(H5-r1cgvF)XXr{gy=jk%{>p^$JxX%=F|8sFrG7^Q*S85vv_U$s=hDj0UG*L)Sp>%?FAS^V*vufMAt8|RqL$!Da^y_>Jcn7X_d z9b_5ud_={aA%c*!&`9B?O z?R260%{5j7c2+Mvx^#DyUv#KgWpKeMrU`f5$d{JXG4J9>CA#AEl?9+88Mk?%-knd# zPsXR`=W^AuZ=mlzyOdb*xNFeaKngkk8Te^S`N-Fk)>5|pBytoeMA#NPfIXPgYSd&x zG}qc<&kvikt%}hdzD%778?|ZCsg*s;)b=BfAhrJU4zAps0X(HOL)XRST~RrzoM~2; z&5U;iM4IDd5l#IkV;l@3oYm}E_BfJwXPo&GHj1b(6z$w7i?Uw85&3_j8Iw`Q)(xoQ z21_Okyci2;su)ud`0^nx_Q$jdQv*NuLNfEsGlGt(2o_0aQXo@DqhW%{^E%{7Ry_FB z6H+^3DoWH~I~jnhFd9gjejbAn4L6@tvYa+JYmi{`+N1m%b&v_Bqh|c`98r?SP!%FY zkx^tyEP4toA5MOhjElgF-)u7ldg?M0cio2MT2@FXEy@M9Gd`_kt?3S@H}e&aKoCy* z0|}hgtETTRbL>C1Mfl5WeUoT^`c%tU{WD=Vxzj{nPfI;(vSYQrZ^dlX(#j|f^J+aS zvt{bb>&&XV-_mu9XR(oBK$a*qda+AWIb!e&mMgnuGJkO%=H+qw;R~EWzN{yfKZE{_ zLA$?};Mp_I_L-qSuj8Ex+V9$j3;OHWKX&}O4I1<5X7%mS*4&+flEk+QNxluAU~b&u|3o;i!T7|4OI{aGKuF?~wi-^<+e zs5EoJ(XT=_9k)H@lgo8*8Ed>RKMXwPdDJMA73-j>uOpp;_+nix7`rm{yl6mZd({z@ zYU2*q*bcN4QW8v2WRlp!fP_!Fu!z@0Z|3k6e)l4k?*ohe283wAFl|f9tp~I6Q(yHy z-K5d_To}Eq_69`hOVK{-fPIiTk#fk9Maq$+U_V#yI6mQ#(w=n0i!3^A@o^1YB1v;T z?S7?|-g~E|fRU!Udav4e^-82WK!=%iOD7#2_#(l_c#^<-bUhhHLjq;R6xvtJ%zpQ7 z^~tEpXw}?$KEENzdEJub*Y_2#KT;Stq!!i5@6bu=pg3WOsaeX`>A_8u$P<9Vb8u-6 zio~fU=LK+*jlwusPziWw2m*LAKxtEYkT+9FQ?`Wjoa`G|UfYvoTYq|2k*cHCiD61w zSyGd(^ZSt$?T)VU#iXHPYx}%Cm~;yjS#$8Mo3Celpa;3)2{Bjfl}ERa?U|uiIg_eB zV-!}$$s+TcH@vKQh@#KG5U*2WRD3!P@SmXFBfr-EeQCe*^ep`OPy48G&io#E`r_iq z^^?)+{U@Z*pSJ-A7rp)G&4)tI{JIgFl~6Qk)73|H=!41#JGbSYG8xcRvwa#syHa@i z>6rw!nPFQf2xE*8aKVV~u#s^G0KQ2au;1o7uq=GhkP8*!?s$;o*KkIUnmw@n)n`ln zqCBYR!soMH0`f_9Z8I=ekh}lpPT*`1Z^mzmsn|sgCu0MhUlDmZvGD_L0tJWzKRnsqVx$N0kQ5xm21}g}78@RJPqI+g3&pMbs zR~L5Ll{NgWCMY3bURYMF_;DncQ|5^VOLx^YnsJQsKh@6HTZiP_Doqh{tDC!1De&=o zdOr?AHw~32cC14E*&5j8M_YRIf*4_YbyaLp$#OUIa>{ zSG%(IG)V0WkE1ze033o0FJ zuEpxMq9${yE-~~75o$l@AK^~`Fs{jJ&|B2d-`Kg|XSS0y3v_M&MIhLy*<6B~lF=l1 zh|^U%py*`K5KkJKu7fVb6hE5C+;xz|9ZIq)V`^0Mdh>pwxYW*Dc@d_WG6#?FTCoV8 z(-ond;L7Dvo2zJhTs>ae?69h}4g3#l!KO2tU}?cX6q)2>#(r)|hU5`^h?pPP<4!Mz z(GMA(kmsNYk|=e0C9nCz8+mo}%lqocmH=iLot32(kzSauQNsbh5mmZW0aYjrco#-L z7>Hivu?2p!{c6!?|7?rfB_A&qauJzEueWOmc%_T@m=Mb2?ScU1L_(q0`S z&O}F1U3W!3KJVL5kgB5Gj3VWO4J`&+Em^K@Zf?yiaw}DrL7FklD7;EXfGzW)@#62z zzxVk+BPh_{_4wJ!EpW{o04AvcOQF-UfY9c7{ncU+{*_mgpZ z-XDrI-ksr**Ftlclj1j644!zh*>On}zK2QxqW3iTSAKR*Axl3-&F(%{EqhT`h|8oF zez7?!hi+e~;Vo5D&ht<=k`QDB6AC-T9b@w0IeiW;{La9SH5UD?V-gkrk(C~<{ zW)sx`=w$aPVCK^II6&7)2$U+8E_;&PaxzeueYVWSPX8j~@_lS);G-9l!3)YXTbgXkm6TCoXW?5_M=k{G-Y*N*&s_ zEp5#qS*?ZyBL|__%&!OpFEV26M*Y+0lIFs}crmIuwS9A<4WF)GSrA8MUPHx&Lj1&U zPYQ|RUvg1X5`>oBNP9bO%3&Lt4M({p;+ft85XYyG#B1{ufBTp6>TL(2cJC#dE9=vc zsHEkut6P=CDZkm-*`+@f84?CBdsM!XNY!D^l98P*M%&vX>)?zMw#o6v4JC1l;*)S{ zEv%^KLl|6(Hq7uX2b@xza8vhCv#GZKIdyXG&9$6E{*(ONB>XjVRdNn|=VW zQNa*`Kt%v8Xuxc0S-h?aycYUmHLdFWDoT5(FnSu;6==j7BDVxaz*uZ}D9O>y$eQ?3 z$p&Fng9Ok4DIRH{hG3ZiJ~jdHWb6)?^5eo+e8RsAse__q!Xcim$_$h^h8SrUIOJaX z46@mkd>O2s^2Iwm)}!>>WMFWN9OUCfRH2K*6^U`(H@(KRSY_1i8kXtQh!@|N=M3bw z8arbBvIfriE<<#1wInl_aidr`bQ{(AvQ~N*7X+Yj?i7Sa&@;)HWjZXqL_Bu9V9RU@ zaq95@{QC|7^;&P`jUxiA@|g`;nGd9|ey@K2H5Fv|fkP5{jp)*Uw?D#M)FbL=BlRNS0~B3EZEut;tm0~*`Nw`CKk_NE z?-jCU9td!VleR{~hp|xd2xI}64*rG(yA1=Actzf@ro8i#%lD$;X2m&4y~Iye$}~#l zheycT=sI6;b&69WTRNa(Ng2wS)E#gQ;oE(y?ft3TGYv8&+`(uos#vzEuRnDUb zR@h5HF#)6l?P^+tBt*j~#7xm2N@9W8#bB->!shNi&WRtD1LV|@)seq8!@N|M$(h&A zN_F?MxlIAO24WSjc8wZIx%A&xaY~%a7~GeCPHJhH7Mr1qBn(Z*Nz-gBb8x8r+RZ(9 z?zlj{lx1^VYxG9MuK#ptrJ%m@lfSchp>cexvYLS7l*(GKZ$;C_nM|}CU;8J+{PrG+<44l`{bNyA5V5_1t~55ID~{{m9|{1) zc+{bA?dhQbIAEJjuRt!eULaiBQ2Aw0Y8M#NwUi@DtwtJA>z*o{SSjngwh2?DxVqzL zNoIHDp8dF~EL&OO8+=l^BPn6&J)L~=>*?-j#_>j*NJDQTrBlfM*y))*ySv$nE%0b& zf1ExkK%_}mE|9n6d-QT{I<)99_(T6+?W%GcL=wnILSIVTeh0)+@1Gv`UK5#h->-G= z{=IkkROkCa>Jb(ITt?poislJvE{Uaw@Swl35JAU+`8(YzGm)26S%^UfVZ3N)?^pmh zKp=wyp$c}$j{#u<8N`nP6BNXth6Ndr77(9XRo1I4+BYKY9m`SZ{KrD2Kovh*B{~~X zjcT+%s@UwdT6Wp4*Uuhw z6>K8#k%d^^Tf+KmQEq;oGlVb`)vH8XZ}ns8^93mQ(SeH66Y)J(u{)JhYlbUy>^F4k zrIN5G>YVY)q)F4T>GwNiz|qt(?L_wTm<7&eS_THb+H#h^KZ5}50E}19?ga-G1O($hGgEt7x~ckX zyRQ0UL+kFH0L)Xy^$=r{u~4-^d|MxzM3U4j@5lPeZDUAHH2h{zESkX(MjGYHy6jgCfi z5@^i+zO+NPQK%9SGCu&tUxHua5&QBFQWXd{P8NnA|t=rDR|B zs#v*B0;XxKt^_ioII0~hwlUfJ7$!qeJYH4EZbbhvAdi){kt2Z*5#vx698)}w7QYJ{ zby}ONUJCj?Vv^hP3rG)9)zJpvgU9H|nTp1>puH3n+%aZ-8;pL{OvDzs&S}uLon#zD zlM@WEB+RKvrcvc*HY zHhL>QjOmssGoKLE@EKsN@+0V*L>so?``}(Hy@*Oq%yDn4~e!m z{Rua#Kxl(yM|G$5fAPs80&~>rIX;I!>+;3r002NpU~c*^62JlgNDe=fqI@fBp&O@1 zUzP%jaz6Ikc_#eqj{TBwz?kK9#kc3TxT(%{QO-o7h>>>_SfUFO>hyuqXaT0CEAYm# zpk%aIG2syH2A(VR)V-><^d7!F0fVoatHdk{*jA)0?~;`9Yj$|xUqGmek?r285}1L}J)ZA7TJCo-%bB&jQJ8D(??n;kC|g77E`lOU=^!E6_cM#cmu02kWykqY?1hs zsa~L{P32uzou^%P{(LK|T3hMc2J&3X=BBS3g=|xs1&KcGZbc{UoKGfSuQD$ZsHn!@ z48;MU#ITefz7uQ!Mf&F@2Dy{ugf&FI1V>28F{8b}hYi8-@vA$3zY5h z=+3Pr$@@F~zjm%Os;Q-GpOAn75=`hNXc9UEX#r`{OX#76Q1ns~s;DR^MKJUtBE4TJ zLZl-Ih@E~>ihv-BsGtZ4Qk0??l{efacYS}}weI`>JO5^#nOW<3=GilQ_St8Pp#kEP zI6c0Z(ZZnyqZBKMiKJyprH5Hzq9Fh=3=%ZRR!iaVm4<)CW6Xan*r~KM-}CUdQLAPD zvdajje5GxkbbKBmgD3ClhnZuEY&ErA5g(ml>W8T&<`3YIh-)0TZq7!CveexleMi_h zdn6&H+Ct6Z*kjonU#y0+1x8^};Gqi+R4WtV`7hLK@hoa~pFdx5`{6;L*JV6i_~g{* zI$c5fr20n}NcS8XU{_fONT<_T){qjcSbl8}NE2vmB~Xs@u4El%BrS?y*`i$grRgm+ z57!rWv)#nmkxg!+EZ%aJ-KcMBLxc9d59~E_#J@Q6j1G3BSw(}+3DbXPgj+(SHv2Zb z3pBR6jO!2eT+$$4D+rOC^{SMrh1~QD_BKBxFk{2KV}gV_%klyHl68+NlUQjl_SYOPGx@LLOc^Ejr@M?e%0kTMGrQ4%WVNc_{2=Pqj8`7WGn;?& zgE`Ibr)HP6s5{b>A`UMowyWtv3DG!*=v=LkMS zdPvIg<>BV%dOR*OMtE6S)7JJCGuzb)h6E>gV(o9Q!zgGFBaN!tU+wUno4XPy>u#Xs zihq&KTqXL1(pmIP$r7S3K6~Q_lr)FS%Qog+=;e85kG-u-AFfZIc=&Dn=Cq~flELdz z3#yM|bF;tb2p?@k_497{}KxaEy@ncNZh3-s@d{I3`Z_4v>uEjoD(O{Y`r=U)u6hLTPSu7nCUz4jtuXF z*MF-P_cFu!y^?sPi(@F0hUN~`#rD7T9D zoTzg}FV8wXjIwPJjTrmW^!)d!t>w3zHxC~=xbjsQ4by$tl>X@v%_F}0Rr&!cZR9eW z6mdi*X^)@P=#4BjA|v13|2IGI!Aax#Sxo6~y>US(+&`~^{9ppJqlyA{nw*>&2c$#p zC3Eqg#*{Qp9%Ehj1qL_QTnhoTVl?Nb*7p5#SwV0n7Io_k>F6LLVh7p)|4_h{~CJh~7w;^6=%MRL?jrbFb^Qqxr# zf{ed_>OxRM`zWK94SUoll}A=idY3_=`~Wsm)ohkS3H$tT5uX{ae28}c&5wrzGo9A= zy0oMvOF1t-{@VCo&nELEPI?~52 z1oiFwu0kZ@oE#kHOV$C9Jyq}WxB~>p<>n#twwtjlk3HkF5*`S0KHYPTBN~gh!91XdnUN6aQ(twkMcWjX-@@9AM3*f^(Z8&KfB zzdv(n4;eOii0#`8`@QPdDhE%$-Z6@7;7QtyM11dsW#S7aM9_lD=A&)I7=tb`U$UqA zsA6RfQUDbjFc4IDsvx^H80Vcs{xpg+TROa(c8)_;(OAOv!#7Zb`54G%9T3z}r*B62 z+qsK?gf)d(dJ=<$^voA2O1INIF}R>VK0`UAjHZG(WrcWiBnI3_d@W%cJcuodY5D3lQ%3UUY_(T>YC2)yd{O6!XO!lA}~bKP4iH94D_1| zvpxoe@{_iabdk9&-~!LNy?vC1{AW^KGY9M(dflu{W%LYlS-h0*eS8&&vl>fxn$9KG`A&r|2P zsN2EXmhiUK+Tp{YH30jcl@6Bik<(y7aV|+`F70wfA4h^L*V|;WR?PWxfBsc5n6Bm5Ro);EZ}`~i#nXCYAw0QC zl`5M4cdl}^3&yfGnak5=tI)Q7<1HGTL+sA|H@Q%0z2s<4@%~YvCpC(odQHv; z52A#%RT4YY1i;zY!>|@gj)N@z7Q5FZ#V~0YGQCqPDt@v6c}#f>DkEdUmsNRanEyGx zc00Fz&_#FG*Yowqq4{k{25f1`_rV1KoJ4QRI9wZ(j7jf>_JOpb$69Vw;u7K$_>sSS zY_}Z|kwg3j;`pSZO;q@EL#Zm&Du*%m{%XlWV=}FCgAf6yV%uHMSnZv^tF$c^{UJtO zPv~#Fh;M6#%>2)Nd*{e3g3&Y8Z(9~CUd%U|}i-utKP5bQ-bk1y{<?G8UMbT@y1?1tp-)(QS2T z*LZS|&Mlfb%N@AOeKd!!G9X)%SUA-eq;P`Mi>t*2&uYbC(bi_LwFzJg3$28G`)y4U zLGHwHCG=ExFcjcQqUQ*DClA?U`<}bE!BV!9IXf9-3GV#6%xd58H zXD{ot4JpM@2HDK~H=nT0PTf`NKlhlA|}Y#nTZNBD^5F&&c(2>ptNwQb7m zi;MDy+Pz1uK&qeYRCV}E4mZ$C==JXoPd`HFj}JAj6*|Xh$-5vPx&b$ln}m;x20Qu)#D$3gR;288`=qhi#DaW z4QXmEY?Hr#4@?-TFAi7dwp|NrJi!c%z0!_cCmPne^IRWSsp&qs4k+Ro2UQnf2xVk( zhp4zBR;2GX=g7E2Z&~XNew-W-O&v@X!eUc^EK+e2#MnVn=L$&#&JI^Yb3%J?XiO2& z*|#^;ba;iKif~GOkEA)|ThYletdRF_;|o&cW!cZ?S10%{yzO99;xKyF)d)+?jP6!! zPO`U-2AWi#Tovy`*+ct_UE?a8)3h}4T!c~3dzBB!={>w_z=nx}6>~q_$IGSOtF`J8 zyYH{sIZa`#oZ4*t1fv3F8jjo@wX};d`>Mcn#t7sq14br73(jK&K8KRy-jdkEeVe> zSQ&Lv+g*Y<<)5cIP&0d2`ihORvlV4Z$0GOyAiVzRd_XDQ#3X(&Ho*2#v|%2|z*BJ# z?*eUuPu?aX)ZKS~eZRFHUGWgx-ycqi^A5S#ZNz7k*7k0yR6aezXn(191wKIh6NPG- zNH6yKn4Q1uN}UdG?AvI>53C-dJIl=!y;TTV>p8E<6_DBXKy#tqNi*{u=@^(b_5Ney zSC78b5k($I<}PFJnmk4W0D#KUk4`OQpFzNSI4l7ul;*iM?}?zk>xuKwL!x7-Dzaec zi9f*6;s6jG-N*~JGCHdds4rqU;3Hrb95fmVL(bt_1WWl(fzVwO(SXOQ2x1J&rhyhr z$D9T|M@I)6bQ{dayrb>;1B<|h=h3GTIE#Jzg_9?BnfJAQyd&JGjNlL+LuD=2Lgn6f zET}V)th}zh{W`fpQg&BT-dFUr&$&4fKzKvT-a);{urHzgpKH7qH7Lb$1$pp6r}{|C z2~~??qq`@4LwAC}mq_(fg@F;vdi_h8MmtUKFW^;vhX1q)?Ry`tFv@f;Qw)0xOv~b{t3nPs}%q$F#wc| zijIi|!O1IdTSP)i4yCN7rE6ehVs2%Nad39^@b>i!41W0NNqAIjd{T01dR9(;LD7q{ z%BtFzjm@p?op0Xt^!5)9kA9e#nw^{fvatALd39}L>-Wy?{^8Nd-_x^;%d6{qiRvop zsfh`R2n$21|F4A-2u=ud5&-J?*N)^fBJ}^A`2Y3&>TJdd06;QC#@nO-lo8KFR)hl? z0UdgOUsD0=Y3o6vM%P^f@!hru0HRZNb^sKXK-|3(3Wt!hH-sws^==3~2`4{{_>&Hy zl%wT*g}eTraIC?>AxlfwAIaNP2Cwkf7a#~g5P+~!)$j2|*WZ#z889wHMEVZSz_x2& z#0@zIl_iw&35+VIk}ZmkLD)^0#?nNma8(CHh*nF>Ng8)!o3R{MIpC>C_`3HETbn6| zYt63D={yNw8vat`IW4Guk7r)_tT(y#u2jUj{?G5YMK^*&?$~!C9da+_kKbG@e2|l< z?KoH*y1kF`Q<^) z63I~McqcyTgsZaTn|p1^mLS4XRF7Yr2@^5~-tH;rwJGzlJ|B znsB1R!)ZlgSsd{d)?a%TBnZTS=49p4Cf!oX$_N*eF|xwjoq2MU zbdqbm2rcGL`#h4_&8OAbgLSH^s%pkR7GaKmq}wFxe}ChjRc)Yo{J=U1;y@WSid=cP zy7}%Z$ol2W!PTEM>FIlCz6R6XKqw2TJPrrK^*!cy2q3!d9u*l9`D}5`Vgjb|wF`YN zQ{!cst_@-AP ztEl4YXV&r6ZoiRa;x|L-Cs+R+7gteTlyQTCwrN&RZ&*%KM*cxhQ`TP!^6V=#BExF}l&|Hf%J(cUp<;Qk_68d`aFeOZaf*JVDhmVnkdY~UWAwO*aQH0B!GdmihmXc05JR&6hy$7 zP06-&b=K^(1`u+~8UOYGaN*G;WTT4!6+?${$5%j^oZjvD4i0LVBgKd#C{Mv+P)o^- z48kZVLz7yKPnZTCBI(d&^2~K|OID(6{6a`GQQ&X(N9oHz_IhV|`)|_T{5&!IauYMs zydN#^u>?{U#%wR~mf4qWj`gn#9h_#B>FuwieG0Kj-G6K4!l7^P=@LdxQTU-@_no$Cf4InG~Cj zkuD1LuUT$KRtIAPEF~Dyg>U1x@3uU#SkgP-RbUK=A5SNHxhcb`(G$ttd%JKp89=_KKihJW_>L_C{FFgfDN7DANyquvssW zlrXLr3KKCLcsu>QHH|`u$B|f0(?l0Cj{R!Jt$G0Yp_RsQOxtM?Ue0M|Y8*%sm7MY5A zM%s3nLg2>@^V3lT(h0StSqMlgmv0nGO<0XI^sZyfj~;}ZS}8tS$hIF`@yBvYe zivWHK$G80B=MzAPku~!6M*um|O!8xkzzy_M$2ZRaHp=*|pax+`R)+TDX}svCx|4$< zyHfpwy4wXAcN10mi0?G+#u>%bSxx*DB_yYy*P&JDx>Nkl1b8wdwhJWRc0{5Q}iyJ#vhMcl*INvoIjq6Od`0U|iNa2)Wv#WXHHDSOOr{P`BfDdmX_p7{hZs^!G0V!voV7SK8J zHZwb3SY$d2>-x^?=FO9x{`JU^?i+rUcJ4W3A+xJ8NLWr~0T*$o839;}n!y5;aShs-|<%?&Uvt`ICz$DEQ<86%0X-JC6Tgfoj(-l*Hp+6m?f7L-%nYyBc z0m|&cH3C@fk$U7S#iY%9e{PjFw~4Zl$Vf{+)Zq;|szQhGg7vrYX5pkaw5Bj-Kz^NU zQukDrSXgQRKc!l$dnHzSI_ZmE`qCYzcXH*Hi($DhA8ZwxeYoA6zCWneq$mA6w2=0z z?90_(0PnTel(pgbXja9PCnTH+HJm@S#9D4V#S(V=-Tq^|5&3Gilq6dyd)@R|pScR= z)m!-wcE%q(GCyYIej!bk`*nUsQQbS~To_Uus#rk|);%BnBBi8$-D@H? zj-AY=qFLW@>Oi>Tlu$6egIFxr!vae?X!^T#nUu9gEJNcCi58P%Yi;*5F*8}&uh^=3 zS*k{O#uqc9A%IV>9V}9AzQ}hP!T*srer3?3TJY*D(&-!k7mHYUXfX{Lvu$i+*Xgx+ z`|b6FJ&;`49+gLAdV*#HlWU=@0IrIcgz^ZuV{+5Alr^8PHY!7TtXH{CzaoyZ@!`Ur zLI3u>pY3vm8N!$DeK+4-brq5R0N`b zeVd%$-@4!9d7*oMDTwlJ+vTM8AB*X9HJD#~t^c_pM=ur_E-ZGZ>Yl16<3e%++}n%L zmozE+jIW=dPh7L&h;w={Be^P`3)sImXemWi?|*B88&wc3HgP%qO7t8ru{m5|jr?xw zB(Pxj~z1|q{MFPKi{IgDXD5w?1qo>j^zn*rwx`Np{LS9C9l??X|PjFN@X zUV%Zj_hQ|{V?&PcNKX$5JQ2Pt^hgxvORrXt+ZZMsV>%Lk!E8FMONXal(x?QbdY@+dsA6>w%uWG_KjLi0;@9eUZ%)^p_MGuxY}=} zEa0fsWskyo^{v5`OVU}Wf>rYI4i6S0O6~WXP&l4bAG3j{B?;-$nM|h#>oQB-&YS2U z0bW5%Ub@XDYL1#a%YRxmD>q_n`w_qP@l59PfsEp}Kqa%od1>4DS&p->?SPWmHeO$h zT~plO2MZgw>%Xl_toBgIuqc3?s^K5cS7G2n`Hx*l=5{^D_zi5dDak~X*><>sAjZmwyVaohAleau*ryUnDA`&ajm_QW^884%-u12XvowS1-_t*W%-^GJb7p24MtJ#98eb&eXci_`UfZc(1# zsNzDMZ#g4c%zM99``lJem$B%nobo4cX*Up)5!@O_q# z)4EK0eSau!l^dzfo;o)_5hML2yM2U1+NrIx3Md^m>%H;U|z{gg;WSzadO*4C( zbTs4IS_EV?dB#uip$cuH8hh_nSoW+Y`vb*}=e9KV@46M0Ls0tGcrleV(m%?P@(z4; zlxE-`I?)8GDkVN_l(=>y;@~%`)UmZv)8a(;;oSB+pPGlf-V7Iyt1Yib+x+gbXWQzF zdGx4&u%mK?Ru}|;SH9qiSJ}l?d1u0k;#h`ng!asLaXl^;aeW|xyq}kEdx3!Hl8SLX zB%r=M6=*nde%Dy#%TJ%A;Z-}tZ?$9M0!>ZUw}H(}By?{*T)wY{y!-a&68D7?xM8%7 zH;NN(;hiPLvN#iAzKhwJ2iVBe@bMCZq!O(%9c;+@Yld0jeJ1bS;KGuI^)png?|(mw zD>^HzFNFk$<-}F!{W)Cy7tbvK>`L=-nnIgTeVJ)P{yM)*Pq5S#_HYx9uW>y{vVA;& z0bs*YY2(~7RpFW(qWTgzzlGun2)RnTK1G^AsT5T*L0==8ETId})VpU*dp2MF_BLKS ze~;d=SWV7jm!5gEc(Gm^6uNrn+Y@GWWk7%A2>^#XQ8b?1#TzCa3J|KkbN3@j6L7hs z@SEF|%A`PeIlQIzF5<7QXQ`{)3JLnl?(_;>aoa$un@H|N6sZM-Q0N>=I?;%gCbxQ^ zW%&Xf!`#JnOrjmB|3VvfZl*5YH&<|E{1{x=5MSKb{~2lbU7A=Sr`K=d^lnqIKJ!NG zYfe67co`4zJ&Fh|T>xzM2Y_5FW(yBY@W<~G}OVbRv* za9@y*P}9Oh+3N}qRl!I-ul06xhe>)h%!?WwOgHc~_aTqzpDF(aca2a`UudKc7As4X z6Z;}TPr8L&C0zW}3RP;Csg{ReMc92GRQ%3V`(*oI-DXpL`@09_)w`>Am^2)C>kBSn z)$Khz3Fa_6|G=hsh5J*M^&ySBgYeKUvudz{Gm8(I;p`Ftp{QfDASG2HBW8f}K{%&; z5{Jhh2x3%y{`Y;V0;S~M@n^8Y{rix%dmy9dgAjXS`H_xo!vlVo>hdDW*#ufQv}4X4 znyeP6i#eq+%=o5NGMi7ik}IQS(et7fydgKs>JDYaGoLOJ;cYVcT^yjLMjNUvKCNak zxDMh#LFu-?;L?ate!S$Amr{Lt%8oIJcD5bwk2UF$g>)gDMi1{Nh>>8@YWR_{jz*bz z1ki=6JB6{&p&vMhoVInZ+_u~91^-l7b*L1NM0DI=)CjL2g0P%RLOP=KId z%9Lf-Jgc7Lz;5Dm#xQ10?UK%I>@OZ|aYt+2QZJ-B4ZmA@Qihsp!-4+|gUCCsJx!ZvL107uHu7m$*?N7LZ(7G!tyV>Y|ndp<{49?)pL( zwL1lF{T#6O@JBWtG5HR*NVoAr&#jEYqD5|yk7oBGSm_kZLD+uG}Lx-YT7 zJ=`LbSbs05`zCwBAd+^BlAWvROYH}m3=Q2`euPs@w@joWt@_zC?LoBrduX5ai$-&Fy9+;59?sMboa(vli-xy zDa-C2?v87wemzy==a;>D_g7IS^LLm6XynQ7GD9h;@iW$2Xl<6k^?Bf+^W zW}5;`^SX{qW6r;ju)Yy1&j!yW^7zf>BhnS=M~(?^PFTFY`KibpA|r-AX*S1L1$1BC zMt{C_frzp)dZ0B*k@>y-xQ+M+3ijziGJHY+B}Vc?Gcqk`!#MVJ1=~U{0z}>oji9bt zUY?8IZZ*9*aLN@X*gYfr^2(Y}CfkEjZt#1J3&X`7;H4%|A#@IySTaO~4_TTH5YnhF zf^|fLlY$>tFy1r^lhLu7t}L7Kf0-82i^H+=k+TR*4zObQM5E~+Xvi}gyT3t+KO}hBPfMJ z8yNe3kfq-EkU0hXtBk#W0swJa@nepowqj}B_D!X_8b`rfg65hxDk&y_zjB%?QmX5{ zrUHaFSd1bW(KACLz5V~<`8$frMsRMEh}lB@=k<8!Fo&@`yw+PUBvE?J+HTxoHC`lc zHp9aOk?7>~^u=%4tKn0&yWYo($0RLpz3mH#vT@fg{k}Skf2Mdy=_l|V2I%6OenhL1 z>J7pQ`eG}_Qr>6I-yM--Ogx{GVs4F&ZkRZMa0au<^J zD^JiiqU_EB0wB$|hQ7QMR8RovS{0#WW%sNI!>g>TsVb3D-`=^dpDAYbVv>qcm{B>3 zOnAA49jnhB?i^wZ?-moeDbvhjRIL^rLnumH=#?^PdhK74PDcP0GxeuU3Q=B_h};Wo zgy{`Pf^}_!=QAhYdPx*gUS+gkd4u+Z1dhAOy@`rX zc~L%W$?iP*yLn_u$+?=8)G=570!u?KZzD5;b2gbugxn9t8xsQ;BQp(0TW79qg;aoH1!2VRPEDn?B& zeWqPpj~IHlwm3#dp)uXg zcvGpuIUC7*!yKm&>5V=bR>kjTC=2VwXbw|#zMM`zL47XamLc3lwY{mFFYh@#LtQ2S zU{Kr6)mebkS(uR_(p=VnVM99Hed9VGfaOtnu_?`!fk4}S;f_%SKUKN4%theZ%Ne^`3i z5WmDAX71K_dMh=ctIm@;;D!BY=dWa$?+qw|r#^(3wK(LS``SJMN+2^3Tl|-$dqQ-{ zzgExIdpt!PF)3+iYt-%V>t@3Yd57Y~)$*2neQ4}w<^IB76cz+w2Jr0Ms7wbex^3vb zK0Q3ZA#p*lzvc(}ar(xr0Cyl$nl^)>)zYH>opL9||JB1t?Mur@f?#d~JUse=W_LpBYuokE zAA~9MJTl6WoU4TC(~*h7of~q(#WX~?9rQ@jDm9-qfN6sod_VQvrSoWJia zGyDTtSEY-JY-d{d8~9{(2O5UJf!c7OJrZH@FSrcq)E$oZ><^u>wJvhjJ$Ur1Aq2!+ zeILsjE+`{?Q1=$PY|Q@N`DKvVycBH(s(JRues%nh zxBVz(C;pGjS}aT`Wtoa=J=7e{FxQoHLu?cCRi1NlM$_z{l>FUJSwjJtmw;A0P8l9n zLK~6zO-gAdQzn(i+MlgGg<%At=;xvsk6e424Z;wS6+__6fa ze$?YxI3A!`T?ALY$Ty{1a0FVny}tK|c7qHN08JN;!ca#ou~#a9Nqxtk zxaX!KQ5e*w`>lt^UvlDtkgU)WW`5I6;cZ!Mf|zYoKqYFWPX*=vePTc6sUHd%MaOa$ z5j8K`Bj7hv(;xN7C7sreQyg+SLO=PBw+#U7!fx6HWA0SsJgt-K2_gyTH`(U&MN*Ku zuN}l?a2X;5Z$`y&q0--r=;`=6Iz;(tZwV%jjqb;9r}d!RWn_7`yieo}F5)wCP=nJy zliM~?6$*eQ0_t6Kuon{hqZItg`7fK(hR+?P_E7#q)luZFPaA47-!h*^>>hm1O_WR~1#H!GhWsz|ZD ztN(FeFoHxPRh8y~&bscwt5>mGw9j{nzg^%KRpDuQK0qjrtaq)3V)1aw10}2+s_UEg za#e@@OD$)-;Y`>Ms?n$9D(v4ltq1WNb&chIS(zRupdcS0Q4`NL=1I#LkH`0n zAa61v+3FQ)$HIjAACJ6Wtm(f2e_u43O{P=wLBXA+x)kgRLUh6UXWZoA1a;+UJA0nY zOBOk8vmmV#unCV(2p+B;W7a%s+y4>mzGYd*>!=%M)tb)|*}MC7f$Ge*zD!qYds$q} zOKa9~Zicb%)oA4FTcz45uOy|^-^)+lST@=%xXB*?(EM41*i+(k1cXJwM1nE(7TGdX z8eKUEu^Xk7L?X~JWTF>%Q_WRjGTvnTtYwVv@amkxVB7Y|Tjc3fE)+~#|9O!LL#R3h zRfS5C;CRjzBDL5To*#q!ThzTN8orQzUCXsnFkEbby9%e@z1NW{(>wY}sEM1QC@nf5 zaf7=`M{Jz=ar;E`zwvvR2u9MH=H1qum+qM#laJun&QCD%YVcmWh^;=1W~ABI!I`j- zT+;Ga+nN*zQgdkCjnl}el6Ua=8ZsEh&DJi%GLSX|EE>O`lnxMb;Cm?&yQi3Xxu89L zh3F}C+BFC@C9`b@)TLaPQMEFDF%WHPjHX#|`moJ;eU7sGU|u#Am1=QtT4Q63O{#D% z+?O_&vD)X?==Mt)M;fat(Y*WidVQe5WJwmoRVo)=O-yF`CeVfl>G!7GuYh6JDa}wm zDJ&_|gs2%ZMzpWOUd$`juX9$dLiMj%slM%MXHt?DlpKaA?W&1`nj7OX;@Lo{M0DMs zEI0!OAH_r)c_DjUQZ```-#>OFU^2dDrdB@^g~PEEnEnj1$bY=8M;UpDndS*FcPf-T zsK7?BYL)hz>j`@oU8K8>MUa>#!nRbMO4d4p`?|vmjZ!ZdCf&0}Ho4DIX4gJB5&l^+ z*{nl_m4eXqH+n2mZ$cz=uNR{{ceAuxDeoU3TBKvekNrPPV=~~pC7TJxThD}d5ic?T z1VA9P2w9Pp<6bbTLx)>EaA$|Pd{*A}*dC|J^4U^$(29a(i7r6=LLZonad9*+C>M&$ zr40V=N~P|UGJ4^u6i!nH^P!U|3%}paq|OBzJzT)6*i-rvnMoVxrH~= z^(-63Fj)dwt(UA<5*No;Z$B@9bant(?9uYa+l!7-01J2qCAik=DuaQ9R>RSI-W@LCH``JI@g}%8N36kK>u<7( z5%kIxFPayT79GJl2P70KkU3Tmi10;}3{U0oN7Y|+O_;2{NMeLs52Z*60gNNf!yNJp zmrk`uPdcj8F?|tkczd4V{;Z-Uc@|`NOKTwi8oY^zzP?jH)Wja}8I)CnPN540t<6Z*y z^!4!)^Z=)XIa)WWvJcBQKR|n(neDb`4L2zY=SEAJ@d7MIibdD^59}6!TWs~VYV8jo z>7{y+;*ay4ij^DUnVeK<$+gOM_L^3+4e7)>0=Grp7AO+ZQw2S_dNwQ+3$k7V9AHZV z4!V`E#0A0c^=E1=`oAcNoDW-|RhMJ2XxJ;hziFQcNDo?hX_3<4<0s!4&s2UDaHk&z zTb3`Fkbg@~qJMgI@dAJX;LM83Veq2uzxW)HQN?o3E;t6Q4QlH8n ziF~XviH|s9sc7W7i(6lBbJwF)hzP0^ca{ul4jXHnI5Tw;Oj*M9$g-5wxc)F|Jjl`e z7chooe}?FO97jqNv8K6N6E?ATgja_BVNphYLu>3X&AGxZfHOgdDZz{Smqc7|DQD1} zNz??{T1JwW73a#Usg5of5A$_$P*`Uvt;K>29s`tsFNt}W&1kYpH-X3&B{!YYD~Lgu zGsgJ7mb!4$nW2DioH zUh^p)%$eo41l;~KVFn@CszmBFNerRF+$g`9%gY!!Ra`}L@;-U|kl3Z2^MRwvfB6Q4 zDgiN_XQ6p2z04FZ&wf{n<&nv@-0<2D628D_vUJqFzzK?8se9@7plsv$v^3$pdpr3m zRx!NQRrjY{HmNHbeu(-sD?TdtS-5oFsJw?KKn@;Ijr`F_n5c%3di2Sy5sm$B%H`4XsoozecPSp$ZnfOqZ(FIc(R*ZKV7lO)ThVjC@GTC9BD~8> zrn*}AWNLAVos0}1xrEcpm&EtZ#P&r(0ka9nl%5$QHV zb8^;>vRbX?w4MSq$W5{$dnLZO?$&(JQ*e=M@Wx!CmT4!b0}m)OIhhr0FaTBLLrWZclhLDIT<*g-J$F+Y}DMQY9yN-Q}-o|!oWCSiR(o($p zdv3fovslv(+(D7D>wb>Bmyp9wX59^SL1~uSsnDTYXC1J~!KyV%Vhyb?I3+6v#M&aY zX&hIqEvVkjk0_=KHZWJ_KA*cvz8bzMo0GnNhWrKQ_d?}yaPoigIU_SF7no+& zWvP}^CGnT%a3gW5(e+w#T>BMQwH{Mi8oY!R1dA_;q66xkpg91q87u`KB5=?e#rn+T zJ}>i9#V@55!3`9m&}7pLwcr`})EN#S+W}fbCa(cDxG;%kPS2KUDGA7Z7`@b-5vEho zQc@TAm&1peD$bhph4T(qPiyzAM}|Tp<}U^cR+)cdc7|$m_(?l~fu1>a{m-)H7jDV_$H9HZfhs2sdcw=FKRg0TW(d%{sWd%}*7tO^sY+V#I`g@qJa- zlvw(83vzUcCPC?k?kNUR^7o`Psey?L>&%w^W1yq)Us1Pt3t8S3X(| zmR_cR?T>3yaT~~JMwTxvKo=eetNIa(9cn;y^wL#Y^3I@9YL#<0k}V^-N-U&|+8Pdj z$JH!|&iG|~B#rCYDCd$ZnpaCzU@9H{Hh{HHH2u@ZIY_8SCiNzzg5#^)N;3ulQ0)K= zSrhW{8Gm(V&-a^ofCF&2CvkL%A!exH#>ZpQpCUxiir0V6e~C=TN*G*myI`mZf#k+5 z=@}MHGD6`LV3~t}h~;n6&=kOd^kVW2O}{dk%o1VD!1{iVEs&dmt{L_=&)m`m$ABC< z#;WQ%7A_AgY3AOvadcJ3S}3A{FaVIhDo*^Z5}8&?qw(0>Rm)qN(<4M)PTy%k&&0U6 zU!eVZ{vP0TN=9{?&V<=Q_*AgxbWns_0=5{V@3lC%_=U{5BA)nHJQswPKms~830D?|GOAJdnP6*7c^7Bs{c41=1TRRl ziIj{M9bG6O7nN?UWfmiM;(kb0kXg!o+_9|Lzcp7K^?frIu-U?}u$3THG4tTvdlG|8 z8EB+HoJ*iiBT4EzlcDFzVT~9keb3%!{Ette|LOS|8P!v^>FfGWwRi+yE;d3-Yv`q} z*P_N^S>k5EPBIHWz4Ena01ibfi6YY|uvB+%44>Hr4KUL{7yVI3&b|erR7%(k?L1t* z#XznaObTVd@miWjleGG)3T%7{Fo?wje!M2J`EeT<>=}_>gecJWola@-5Fv)k7cdnBx4qzDA_;uygCI?a4ut+ov2{ zLA+Jmz*+n!zQaYor_Revu-L~)NZbTCky+-21r5Kp7E8>FXMAtWUMF2$%wK%z${Fh* z{9k_jXs4NjvF@Tu)z|e3X&8<5wVrcS4iLMuUe_y#yaAwrMjnto+2LBl0IxFElJ%V1 z>-styx^)N^Z&40KM-DPeBNe_|wZ?O}l8DTL(dMHOZ$#_JQf9(4%b-9N9*|OU5KVd< z&!OpBEEKJww9as;7e+YY@8MgQP9gP<~m06{T*KpXY+D7Y|&4QatW;c&3E=D5roq}ahkBB1u z&L=Dj-paQd4&$a9@|`xkH@uX$Ht1 z4`APa_+$Ys@xw)r~G{}-PmBTbI!JZ_e3apm|rY%~{aD?!_9g=4LOc!Tta zVGIwa(&j0CBn(DL+!4BYT%tuRZB|0NhU+0D4T02HOi&}bOUn6X?$0xaMKFKj6A&l6 z#q$W@A^@Vj7Xdf}{G9gZ8coC^xMyuNoKb1&9-ZJ;G|S`Cx5?N@?n&2SBeiiidlZQ= z;H1{fwP&AcA=Q|sZ>=qWq|+>7KyX^>tl6wdNAWCc^+g)kyh=RpWaNgl_G(MI9!h*W zew}zcnwe*;N0dOx7977KfB@dO#?uhob>MFi+^){gxbeAj7NgVNZW3UIME7XpGZVQ! zu`h@!76w)1-%_CYNInJnjt5QOu>^W_Frt8p?hnE3{+k34!#;vC>!~Bu)tQsiIVt4{ z`z*6Av&`+{jUcTpVwk3_t`{~2Q5WTY7?Yj8(L(E4_H0NbEPTB`;^S@3QpvRVy78T} zS7^`M&8I45C}oE^#at-BhzC?uv=mwtOzQLvmxFabYwOI|%*8`>O@$wQfyDOyM*es z-YhAv10wd-Be=IAhsqLMlSS)OQlkGq9{wazIdU53Suh6QR+f3g_Ui_8`H{XCrhjoT zscIoIDMLKiQJW9+1`ni%;fwC-afNe2sFyW-^7*DfXEu)|XKsd)|L(BfYh^R}@io^?vZlCEf!E#F3YV=6>ill0jA98e=2m z;30Vgt_anN5n-evo`>>uFI4K3b$y|A#$OY$;km zsyk9kg2Ik>IbNS#`t6_4zWvJ?1wVEWlj;-I@gc_#HBTDEQDh!`D}DYM#mc(3^8_UMqJ3T_=lBBqxbN z{(AKd={sDp5~A}3CdzNP=-+{FV|l!Sbi6L|!Z z7EHf_Z7Udpea}a!ux{+Y z!f5Q{*SNEtfi851+N6 zAw_pMX#_9cM*T0l2DFwQqx=#{yMDc&-^uB3l93VPH9sN`Zij6+V%N!Ft`WM|{H#?F zZB!n?SiOy($CfqwO`9?owDyI`)u_Zd-9~VTSc({jF1w=Xm238UrL+K`1`kMzC?WkN zwOjKWztBHu%^5<3#eX76<<3cbH{f_BPogCa?e$96E<^6k$9L3RK@BRnN00-ycI z!x|ZtFk*(;0^=$K=Ig|+F+%_GfazUpByuM`;#?_80jLUvY{Wo>cD-ge1_6mcx($Kn zB<4UfJa~~A4QI>|bLwG-DcRFI-8Gj_k}*Bf^0GV8-gT)A6+EB~1_*a(k!55HUIVFB z^GS_rJt-;a_S#O~KuRqp&?qf!%UGadwcuolgwa{#aVc{tZefUvq#_J&XcBHrZL6<9?8lH-WFN=JghSMiyv9gp%hI3Rk3|`T!YX^N6DwB z3XFX|uU}|6H}OMV2jDY4yJ*@-(`nLQF5Vi|>ju_mv!L;76ns|9L`ofjKdB4?#pOKN z(h(`1e_rLLM9muqPeY=gAI+}4{Kvy#5|sq^46^~#C%&-UYAm-gG(8UOg~hJ5CAcG_ zVJw8X0zwQbtxS=uLTgnfp0>9A78@NCBs!oZHh>i1xXw0&!PQCXEM!Gz-i?NyH=gH+ ztB~u{?USX=MPI}<771kByLepGO3HZGAM>V9JBfNi`u>GAh>beqIaj<{b@e0e@LeMh zrB6??Ycizl8Ck2SZ&FBdhqxOfk!+%{rJ4{6$71Uy?Pm&)!i~>MzznLqK#sfxnlzG9 zSi^IT;Z{KgN~0uAVMQR*Y#2d8>5=yC{!pL&o-gb=ZwQL`N)yjcsXyB&L#Nz&o9iDB z>v2;GZ2#&N8=~L`{@6G*VsU$utp?Av+PG@cBbe!UA1(h$8CQq(&HGlclto?Z@^ z7O#xR+tub-63S_GJ*KQ&M{@PsoFFi;5&rHcr67fV@)s(UcK zAPJnT>o~zT-THkMrsv(ZMI6k@7HJ}BgA$hNzZ5Q(o0Xv+v?8{!h~w;@XL%%N9$<#P zQZ)L6vk8vk-RSA1gyoE`PYj9j1YrwyZ)G}+$IO9vpJ5n-BSVOUZbDb~RFkMdXkq@% zX1>gEqg!u^x)Od7zsYz$@lOYsN+*nrd2o@7^{l#jMqkUIOq?o=)S(}5jntgpjA6+v zU7nCpdY>he$E~w<199j|)#-sqdwA;~4<}?s%q-XXfI1Ndlf+}A)igc@qP;}mysfd- zEJqApKawj7e;=DXG@na;5I+Gs0iZ=?;JI6>(oC#Q3z`;bvD&_(wOA+hfl_4*CZ|-c zC%Ln=Gk1t>0}4|8F{$JN^d$r&uRjLkd^mzg$Qmix7&X&NQ<)fRmqvJsv>fFLnQrbN zB5w3b9$SkU8hPIL(7lYHqd4g&>2_#rKmfqgV3AW@Hl^G>$L2GCTQ5&nCUQ*`Tw3$w zlPMy6w2NuzSTG6->N^>G6A1bZfC$MRzG`-2krA-!SFUv|Q|6>FFneqV=iMSDvbe4% zJ30L(qx?cW!z>_{D}v2Ul3#~uYF^J@umo#aQ62$<4JM6Q-?&E>zUs{n7*jQe8`{Pv z2mdm8FkB|VMs9u*hLT?GeAn1MBM0hMQoP9aP65|m*fi;mAOIn(ftpZwOxdR-as0=B43#Xq@%3WBsX%dcjQmduDB53- z3^VB36}KUAJ>G|JayRAl*6WN;nHFDqK!H|A^*_eiGX@r+`60vViOKbZ$ZDeln(;zI z2m%4Uu4fW_{_B_=1XmtN6xR~U+ImmAVUph6-FM)nPo2A*m5((0<{4yf+J56J&Tv3M z@+$<;Uk4L1Jk!%-WWZAkFwx#|7g!RqU2e~8N8oiQK|@AypW^0Ur|R23*00+9eZH&F zSabMrozK(c&Uu~mK>PS8x(nWep&fUdPMr_2ixdAstt!Y5=0gv-4St!y8+X0=^-huR zY%`bSF#xove2ScbkV1^au0!xFxQ(wtmOx5uu&|p`qhA&_`9v*1d+Mdn0SzG|sp%er z&OaUwl8oqC{^`SsU~y*wc3q4Z?P%ordXTq)n2+~}i*#sG#*`?GPxds7wspG^AUy$q zinvN3Or0RM0S1rAG76Q>&({6bvsY}Vx?py3Sk9=0NNbSbN0SbT@j>6t2rvfI@07+& zsOr+ys#fBdI0?C@L6os&>vrR|bg4`g7JF>?W^L*Z{aP9ANQgm>V$M-Olg?4y-`LmH zJE>E5B54-K5a7oJMskAjzHjg2)$^-n+DX<(d8V_ad@OQCo>TKbK6~<2=to@$iR?@`BCedVb0)r2OD|{XI}q?jQdg zMQ>nkNio@8n$o+`F6SoED?Xd6dI$paj2+3``k#Je(pV`gIPOE?Ra3&^51EeujxZR2 zXi^}66n058%gR<~^gerjbXMi)NAXCEK|E331Fq3n*5<3nm*GV^Jz2Vlu-XCLkh`Yo zJuyHE)lET(w}K{b0G00E@aty)qY({;2uZRZCVFzAf8A0y$c2J#GP1b2+ZGJSY8=+F zHmM z^D(6UOATC*zo9}f(Fs=pL@&OZ^Z_XYF;uMxXPmB?c2s(LZa_=xfl1M(;gE*tGyLP> zBFPAHUEjXVWF@9_YA*lt7V(ysu4lsprX;57>pm}ZFS0Ei2nNN_4nxRT_y@#_UDU1@JU8Bbw`TR2aFZpmk9lx%5*ma<(* z(mF$16|4KUh_?|_K43jU0Fcy()ry?)Enakn!4Jyfnu4u@(8B?-ec)#_14z~6HI-bvTzGb)m%(mzSx8P3+*u$~! zS574d4glE>0K(rYx)j$9RAGpz(s#IdQ^QI3$14VEwOKL+^T|Yul)UWHVd5H)H^kNJ zED6L$lJJ8b5O!rdfHst-cOk9%P2ept`}r4-9*rHTzmlVCCKf z_c&+pHJgmJZ{Ne+Q6>()8J0q>No`{=WJzjil;%2;D#gdc+`DPtv_I(Cb@?@_=~Sa|6XL2e3JQzhd!3pNk?=zt5!q|G!F0~A_QP&VG}tGmFMUIOz! z9?r=`W$2BVEioIyCAoL6{ZZ33Q2TnkR5r)07aft==D6P>shdfgDW{io{@&&Z27{kp z--v#ty_4l7d^d;yBSmvNE<)P^DIB74gCW9-c~tHsaBZQ<1jpZ9G^lVuo+>hhpo})e ztZ2M(xa*+IIiy7r{eo023)=0?SCENnWyyBWh7jy{Lx&V71w`Tqes*SPTooF$RxQvY zf6Pv2fQ;B=dtH}_WT)(GVs`CfVmqW1X`g;LFbX?(eWTb-UI^tW&Fs{dp_BDbAsc9@ zfS;Ufa5?N!w3IXslgQbnUE4s)#<@Jw^56R4b`ljUn^B&n@F|}|{9XBQS!m)l57+)! z9L>i&*ic}RlI<%+nCDAXcIDF^_>7nsh=CywEeEXKO8?UV2|c4=6wC>-Wr3Q=xSrAd3B41(z3+@||8t_8$Sd~lafB2A+#~lPSVjNi z;Sxqg$1-*87Z3PArw`<#C1B7f&FvL}wMu9;?>=nwrfK+NShx!uZjk_8GtZ5L8+n!l z2gEbbAvt$j%Il^l(OHBUtG3&2&NHauD;Dgw0}3|* z2qNc@p_kP|liH1B%QqpkGq;>LZD+1?w=X=oOis963WYsqz0~+HzUEKe_vz3FQn1Cf zqyNRnE4UvbAU_24p*^V1tLum<5M_?>i=DrZSOEKr>h6B0#{htT<&VpFm~=OGMvgvn zq)i4wH4uf_0Tx`_7mnn+J`0U4a9dRwvo7a;KSCl5l&p`l$B+=dXiX@_I$#=9PN_V`f5b>|*_g;h66ZNvc#1T@rinP5rnwJHv zQy>Yi#NAtJbj-vVeitdezJlN0Zoq$qR--_93tJyP^+b4}IFa!5MKsjF`AEjiwQCFe zG1?8s;b!6xJH8u|seQHW3dhw=iyG&&7*nBPyLi863@#8rzT|aIH4de!yP#zv5en9q zNTm-`C}4c7bsW;T@aE*-M8J&+;NP_KS)@KNVCq;CVD|xY@6_M664FAe%5!_LWnBr8of2Fc#7swPQy);Ld~e?Oilx6?m5_}S zm&H8jtsY)#VW{?08yTFA@P}KE!Fa+}>PaVg*W~S2b`*Ut*qdMtOQv#-lt)hW*0$SS z*w57(H_8oKx1!g#y_Cf3UdPkYQPLXr;pT-tVQt}&2XBi*g2K2|0~_Xte^b>M6WF#& zi}Dh1-qY820iHE2>@W=K^Zse7s`nBvPxQ%MyzD|m)q8OMsBBp_b@|zw+So?V`v|Tu z0CG>h%1wOC{)u0WbIPIK-ilL1Tt_=K!IOOw4;3nYgcUWtdNTZ!h$!@;)6sf4fWVu~ zGZij=(X_&VN3lXVY(c>%jno>GpG2>b$jT9n&NOVlhI(d^7jZpwqL@X zPlc08{reQ-8~4ZB3PO)dn~3mdiQWx$Te$*TyT|meuRrOhszzHF1@BEDAy;YJCJQRu zm(@zkj;@RGt~^o4MCrfQYH#(6buab7L6R)dGQkPuZM*UAO9pODbe9jGQ-yA6c*pyh zC`Orwfc;%L+<_(Qg_hHMQjWm=V+5%I0MLFH0QNw92bS**q%iu`%L8nRu2%*w>X>K2 zMC~0f6kfT8{;8{n|@If#q_*O2FdoxP&%N67YjAD2dCsvM`< zmR~tH%(dVn(foJ(!=v0^S05^8vsqwKe)R9f;Jh|~r%jT^hbQ=J|&0bzdeS_~2w$zP`OmS*~^{5;rPQ@n*pufb2D`zv1ST<_k0pICBO8e z=+$4eQLRFUX)yIWF8O}THl+6|czf~cpaIn?ECnw^o8`0e@A~6@pEh&2ZM%5(Xzpkm zF(mkg*3ZRjd7)c=*89T!Zb5;&Jn^&-PW&=RMZE}x&U;zxWMoVJQZe76lYA!nZ%3zXID5I(%!X(uAYxO7 zhmGhWuc63Vu31z)n{`RfRAR=?%5c!lLf;qJD9g#rKXLALSKUF6b8weC(S(OW>aJ!Y z0N^++TTh&Z&G$Q9ow=jww;;2hW*Nh~*ky0=z*P96bBekQa z>Quhp7Z!}|5mK4DVsX<5_9MnZ;Zw^#Bed^VJEJz36X6p#4scs#v2Pc`8U=YaA2Bm2 zjvNA(-z?QZ+~}&0tINj(IZqb%UdiAdCnx~--~jLtbvW1H^1N+hjDFh&hUP2U!w@MB z7>stLe$c-ljhl+kepl<%CF?$^{o&VgDQL7L%(|DBXv!|$4GeBsXt3DXD`@|;w#IIK zW5miZ)H@-dK5;=lslpE`;hv*Vs;DAV>i*D&8PCh-G-lFl`Lyo-r+*%Q-}9|#_Vitm zmLRE+42pti1?_m-p_geaF|}1UcEDAIdtZW9Gc_ahH8tEn4xXMRgcl#QJo|3n(Q^im zKY1V8!xEaJvq!!vo#xHSeZr^e-c*)fXscatuc}!P*&7N)5B2D2EBJ7S0f5hHO>>|T zlo@XheIN<@htmAZ)bwt^vkyYuRGNM+9q2DFJmlhvz@SSx(X&FiV);LtWF`)p{{GQN zh_q(eX@HA{60^2;@qUZNje~p@tbZz(PY8ImCz#m!nJ-mD1l&%mVy~w!1r|@u7E5-% ztk1kP;EH&Ts+Eq3_v>wY@492he|jJ8(>7L|bA+LuG5C^Z_gIQUZbN2Y_KM$clz7W? zIdD4AdhKcRr#_F~dX%A1*UiBFnbhDzKT}3+zW#jmn!-e_JeKvA+Vh-6yIDWtCDb^KmpUPP?JHgrE2GyC~Gg+jvl4N~Xs3*=#)Fs+5qn8(*8=%vX zsjc?)*@?Pn{Dt9ij7X@j(7v4{cH{SFjqd~H?M$7cLgPR>!&N>B&M)}-F2>qb2#z@L zEB8@is||FSW+t71p#8?P^Lgam{R`Bp*{(2$3qxZ?R|XBe-G?3bmcPFlqW9VxzAU-E zH8OWOl@}lS{`x;H9a0$$h(|@vHtaPwgKov%f;NA3&%eEl2{A6dlwDI-Wqu@Lg$j2~Q ztD+!Y(=Fv`Z7%Q6S|&XnjL^CGfV$*>YpjgizQaw!KNO=eOw+FynE)L%2|#mk-a^*! zu_N)eO3dqHT#yECg2IDRsmuoNZ-lWwgdjOgVky7)MbDZthbU(!jiFo(c9+Wij z%qzaX3c|x=5F`x*>yOD)?=PRDu}$mWorgTGo~ku_UuYrDblqP6_7hVRFl$$EdOcX+ z(16F`XmAb_%qn;%rzssONYH=o;{BC@s}&j&R}^O}aiKJHrTlo*cH>ukz;hmUo zn}Y}`u{Gju&t4ZACXY;>uOMKgz;UjnJTM|d_Po|tEl6;SC3RgbVEGId5*@$(#G$O? z5rRBdU7uJV(XPJ2;wsZ8dF-|8fRESNd2~p&s^9UOo*!CfVZjZJ6o&%WS1;M;0%i1@ zPm0`J9(=8A!ez>B#*4(N*Rp9TGUOW{cJZ!d;Jygk7HcY>qmV$nvUc3-M;N>JmDiIg zVE&bdYWkTFEwU%fK^zM$*XQS|Fh|bX4io%sQygC~)eg%1Ic97A-M9Lth3D8AZXrlY z1(w`}RQ5$YM@Ss^L{20BmI1>1A!{*>5ywK)4Qy?$Bw}t+iQ(UkIK3T`55F;-UgNGL zE=Yp*3c)=T=dT>bvad{brrJ-v>l4{y~?#8iq5w26fpr0 znb3;R5A85mw(qwZIdPF=!G4#0i3?Dvwg1?({a{`R6F5)T_ggrQ6ixQZp~wsL+A6{{ zOc4+D>fS7U&46SZ9woF}q`W5xCa5lHsu5)tPm@9sUy={FQfw(Ry=jSH6D} zaHB#4#m*vIV0|o9H&K*_aEQJP>T`W6d;X<}l3Z2R>lXLOdA{&Jr0}axBnH*-BGU%X z@EdjT5fXG5rFALX^3^4Cnc8TBC$fc*S6tQ;fWf2+6|w3AOnJ@iO~^2H!|@5~3!Bs- zVOXz2#|tTbamgVAj(vi=F^8UYwy04J*Y%h+uaZFFL8+C`Dj#S}O=8CxBgh1nUD|MFw{30}4Jt+B#ARCXwFsU3)A} z1v_FhGJt)rD+CJ53&rPIR$@xo!rab_3hs5`3||R`6}65%QhFQSqpU^~=hl>ouHlxy zQ{a+0ng!Pvl0RRnLd2kf<5y{m{r3uE>WO5YB1*c$gpgM4OL<`6WV#J2ZC_vFQ=Sy5 zwSw%DRQVhqSqM>r8!c$a<5G{Wxx z@z#pii6h0$72>E?y0Qi)65foEDH*S8Nfh_z1!}GXIf7I9-2z6RHKK&<#O3rAPd1#D zz=?TA^`KUe=>QCaev;X1VI@T`g_$?=7af+Z*ME`PCzAR%<|bbaWb?^$rS*G_8Ir~Y zw|3sR!k=6VR)~|4&f$hU!l%LVTD(3wcVDg-#(DtS|I@Y znE;gAu6|ke{zz5M!i4!~-;$Qs%LszNF5ab#tRbNRaembzIsLD?y74AFwN82=Q%K5X zL||lR@=_Wt$5SRntWF{@$!)&MQ?f^j^8owE}+E0G=V0|#b7Yc}4bNv`NiN6mBPjeD(*fzw4 zwM!XcrH;!(?{OJ*gr3vFX>eBkOsKn%?PxyTjbA6I3KQHF-5%q6WG3ihsoF14ePhxU z!l|%hLv~sX+;7|ONcVmF`PbPz&pb1Qu9l{DNL3MWV zu3~V%_t=2_KNB+3=gfEUYW`23;}RFxS1Vx6cG;f5w+o{a34bBn+R@QogTl_$T`H#B zUNk~*UbQ3p`r)nvC-q6R9yVQCtw?CO?8xErxDpeqcx=NYGw>aeFHB$%9UmoSX#tE& znGoOG?^Bm6sFh10*p0mQ&y8}tYJT9_RmZu#Lj0h4HgzYLy`<~Fk*ThNqTc<1u0=yv zA9t-fJDvX4onP!9|EbWZFLMkv%qMfE%617h!hp|dVB!HH{_Z4Lgm*`r-CqA9yYJx) zWe`=P0k4+$_yetFy2n5@+H;cC1MZ^$`4R>P%C}e(%=d31x4``gJigxakjXA~MH(B- zf9Lc&KV!p_Cx;(Py+)OmF33WaPaXEDQm8ashe7}sgr#0wLec5_k-32vYTw_#k-M# z>lU#E=Ld_V%d|t4XJm{=K>G#v8{9?)xc`(9ye~k+#@@o{3+1f^lBF`QrVB$2es8!` z%N?9JdUWx{K(zDc(urmBxF)y|R6MNGCX>zIJLv76qXP#4TTQ0k&?WTRW` z??*q4eU>05-W(8j+m6s#0i`69>u|{3_yY3(UJx%BU!>c`LUpC(OngrqJ_6&}F; zNzRSeV0?>XeXl!?xVQO_gJcc(B-xCBC<*q_p^0I_s4H=q#N^zAJpBl= zp$sCim;jHibx4il2lR(_RMur0M*00} z*J=`&V!a!7%eOvcW_v`3`kntiyur+@YyxjvxXv>H2p=Awr)}LI)>MLlws_>FKf(1f z{_{UbT(5xbBTdtDl&MrJZ&?lQc{_T@R4ltZmBRjkDY2Us9L}OZzf64Wy^*jaiYTCH zFk(4_#rFr8qd%L^*r%jFc!`ApXbTWty-f-eWAc0Cqoi?A zX5n?BqX=)2RV|S=WG<`y_?{B+$A>Ud=70VNp4E=EJqX(4zGGT5Ivw%GB@VlMkDbFq zS??CPhB?$x%G)+&X6pX=5MOGU26m)&uR+R^7hR9Xgz$!f=NA-URmgpEXR)Z4-+GFy z#%vn^kW-VbnwDjK=K6^1cw4JF{$q~=(J&T|gHL3Q$7!GCfuRDITE5ahXYN>l#AlwX zO|}@D|9V3(VfatdPTu+iKpGU``Js{C4S)U9l%uJ zJpf?Ry0gRF?C#|xbm2%iN<$n`_K4bEffv{tz3H(f$v$Pkfel^0S8bP=l>oCit3u&F zew%@NE@HdOA7tCWc)9>Lc06hb?iZRbWK~7}s=(0fvFOe6pwHg;doSS(wXB|+VZ5`L zHKtizbXzN$skM|C>ECp$^<38(J*W{+Roy%c^gUljBateNF>#b!0e_>;@6jiO$q&Qh zW{zj3yeixNs8_1w<}-FUwse^CkT$ijaDAM54`VDNbmT|bk*uS zg)C9g;_4o;uO)rdw0c*W`xR^BMQ>Fg4n36=~9 z3tT+w70+v4V8|65K*1_;9OFu;*tR=y{OPu{%RvIAqqH-out8-nx{ zsS8$!S=b(0X?tQED>GK*>Q{W`Ae7SA>7LRV6FA7(9ua?9arkkx=J-9=RmsD($=@3K zTu#mgZS&+CKxPuLT@^J-xJ#W=zQfK5TU_Up2N zkttDF$eKq&YhH?27S_YU?9mSy$L#Mb=V(6ypaA4(8!1r@#i8D5ICOQ7ZLDPq5Ioyr zvKJkn`BK*rlPB=ju=-+-n>K-JzNG*-87AN}uj}(Z983QuElcarFwKR> zV`P{5H{u56#BsRaYUH%L4!^6OKld~Y5-!_4>Kov$t~poRp;hE~L8ZujQJ0YNFQ zb9A&gY_fO^D|y_}uaKrjzI^-3&SCQ5R8^1{R3jJ_FC5`Y@LVi2*vL@KeyVI#sz)EE zzg`#NYVfl`IefzH2_7O5|Lyi(a^!Y{+vGpN+Ll~EPBa+~3J5YpRwq5Zc$Gw?vz#-$ zPQN(GIRbEj`y70IzsBMwgl!!xRSV?XzKSV-<~45gGq9uu&EE#kzg{RvLjBb0Ixth$ z_GIzJDnLhmZv&o_{SwFU2UQvcZmt;|R0vGI>&X)rRuU;gb@v(6;%K4%+NeslFNtiu z(;TF_$q5564s`!!#9p~IwU{al)b+E1H9IvS7{yQnLN_Q?*ny2#CHRVIrw{*nJ^BuT zXj{A7nHN2{V6X7?)mkS6Rm^ixlQqq+;e4>^Xx2Grzq1<&@^cZ(55qm#@3vZQAD-G7 zqXT^4hlK3S7FqpHeGl0&0Yt=EeGVC#b)jQbIQfkgRwMq=F5YiQ+--q@Vty5Esd6zn z-FO-90t*J1f3a_&Z!fS?Jl>1terj(nnJZx>Rmr|}`HCVF=Pjy}QcryFt-&qX{VJSI zNwn)sS+xAD&{UgUflJXZlj^?H*ERq-5?i)@hMn$&kiSgxfxt+&AS~CuFU?mJQ=F*> za6WQJn~4A%9BhI6sb}1j*3?Q~DM_|4VlGG*yW^5*1(ti-22-vmUZs}^KD!ZpT@Z^( zxSSBh56P8>AKV0hp7aZ4ZTt?`Dpqo^Z;`fKVVZQW8|SM0UgsGyzla@AP~Ov7ym@$F z49*i`z9Mu?8w!^4|(M7gG2+t ziuGc(S|wdTNL0Y$vwDcQ0L22~JUu>hkbPzW%He83Pm5`!O%P%<z z&0XsN^sSdwZ}D9yf~spL0(8tL4uB*z5l=IO<`V7lrBXkikGU>yhgy%d1y>i|nn#iibeHJ{oMn+*_w|8=sL$z*JzEzQh* zI$7zhESW6`{D%4yF9xsDW};=VrT<>n1*O5D6vKyOJ{@gVZ_!B<*V2w%4&;<+8E7BA`bFM9t{XUKx z(SKjzV7`Q5tO=#=ugndMjEvQ;yp|xiQUN;$v`T>jsZUAfGcR|f6+J|!XTAdYWq#$d zVBnoG&yooK-wifb84j!bOe}Oj#G%KH_4?Ax2?K>|?$u=^NZDp~0JHUt@+a5E#SW3A z@s39!rDKce8>FLeh_I7kT!|7KeS5fx-L;U%yiQH#EqZtx3|=R><3(%in-Di6-8qJ; z(KdDKD;EH<1{0?>RQcJbP!~(#a@`s){cqWSLMNURk&J(lNexp9(MO>de6-VyM)A_) zs$1xldVnYhI@N&OigX8ug0pu;EA0j3i%Ps5vLm4}6MVL7H}sC4Jy~>mu@`2!i+3G@ zYZR~r4h)4(&0R04}Hri()<MEyi2JMVMwfhL<&2-E2sm$7A5$n+84qMQ0Fp`Ch;6oi+4 zT<3&y^+sBNe2Blk%KqZPZ(RQoJs_x~Fo_u7Qy!bL^+%)HE4c=tR^)2+9DY{Bn>XJ- zqyF(mfkDs^N9!v=QEKvF$02tJ0Cu^8DB)$(!D6%PT(O)(uXQmH$~d*WbCFnfgY$jq zS7^3kP%D2G*&zl8s@ z?D9z6i|Xp2Xm#B5$+!*0Og#^Kjdp}_YQ?eKwDBF|Ux6zX0;KeF0Pb%Ao>mOjRa!3j zv+dzKODfSffBre~>2ePcv20!ta>A zC`IWz=Zcj{pNh*&Qi3iRU&Hoacs7?kdB+J0QC+!t+@Skf&^}gfDw)_Agqp98+qK7S z2(Ch;e;BN1D*3p4_5LhwY-na+3HA@)%5l1Y1_az@$}zwK9CG+U>}n!R3})iXRJYG|$f_`+<-S{@iB zA>x>*Qy*k%Td}!CKIK;q%*8q$DMCU@XG<8UPc4QWKjBD-m zmc1eDnq*28E5k7$N$SEDL2U1XfVeG05MO7v=+Uw_*Qmx=Q~QalhOPYZ@=`F&<&Ju~ zjDYEKr7xWCe&?YY+nom~PWFF)wLr2ECAN(V9*fHJ(=-U2>uS(FFAvu%%gYRJp+d8 z4?o#?*2xv}#ikw)shs2^NyKXp2??I0n;YF#j%tHi?wH4aMP&yq> z#<_kvAYOKDx<8n2W(ecbT;lc3?X(mVhI?7Z&QYJPe_`@~Y=b|R%@d-B<0oVcs2TOF zda(1P&=pIy>L)^^lb_%IcjkxK`AGnBvhcj0gPkGix+|}3a`7n(U*_Iu7%ww5IbPqN zuCAxHW`17l6};#4Sd+4c(stt{*5U&g?46Yd2YXXCWe+GRNg0Ze4t91isRuHreBqU2 zC+buQ37!zgQ$2X$h0(Eas%FB=-Co) zvny;&0)U7-qxKUVABkSdn>ch2q%6o4{Mh&;|R`{_EeU6t;Q95AvC|AdK#U zoDs{y$dc9-Mr}c`yJ8R;3_DD)CV{Z84;m%H|wvcs)nSY}K_g>{e{d?~o%#(^plz~txj9q5t50$#e z)Nw*+#DJQc3AF$GX9})ZxWCv;rCO%VoGO~g1E06iS$f<9#>arj_4?e_^s=81DvjD6 z^2HlW7=3K+|59&0_GmjBPyjtQaY!zaX?xNx@Qsgxxy76IHxcZvTV=}`qWfi3b>1Z$ zIQHt}0QoMmDXwjEMT$r!gGoI+Me(&>Y$Ap$S4hsl0;n5LVOc{3u3iJzLV8Vv$K36H z@yJWyX@c;<+>_|4Hx_X}ovsYm*&eF{+^}}+*vGA9H3R#DR z9sXo8w_sx@zKY*3NHeE(_NOsZ{5rpY(VBwd2~;9+kLRwuiSdp@8KN5_2W;Ezto94W z36&d!n515!V}%|}DWR(iMM^PyoWzEXb(JI)E!ueD&dADB zE?(;?Fi^9UYBR{dj&~=eD7YHm60sprCW0eS!Cn zNE}PJ{~%hNLY?Z}(UsLORuDTA(Kxb629>LIsYeeipwHer);OKYJEH1l!c0fkL=u?~+S3ZUVRJn{rh=$F(1} zA^4>=w>EGDgfO52plmpzb`sg{$i5F5qjz?kXbZ@?#ka>5l~>+6Ux zJzn$pg3fH+ck3Uk&w0gOud3Oy0@PVk{@59H_%{6P@99-c`%>2&FqWn{^ z**MmuRmP;`{WQ!yDsO|iT`T(6R^LNY_(MH31S+#@WZVDtRy&~}n>07(2q6huKNa0s z_B69ckkwZ5QhM&ryS~@39(}!aF>kVMQ>F?l%NKbOVnHuN$B>efsL-6emz>Rj{)hj` z3xdlRuyN3&pQDtW-O^1oF{(E?WT{N0G^KrM{6Uf_xD@K`EHLi{HsC(W?5UVs^rdX;tpI~c5!M%3pA)wHg$yV*Xh8}%y zIy0H2jia*KPD` zbvnG*DgNs}k%GFnW(#Mwjab1p;@gA>BEH&TA4ij;4M`J`ZfZ)$inUs}O3wng zhIJBGZ$S$J@lgwBRuq@uMi0#a{Lig4#pMoeR2-0k00eU|{RUbA4Z9LZw*yZKWT`At zF>umWMfN5?YlDk|Oxym&kZx^!d%m%FB5r{?syf+X3pu}nAL|>7bC&zj6otsg&7Gb=$a--L5$-6o z9LU(kyAhA80OiH6Y)TxogD z?adDrpIBnPCcEqmVqZqN_D=)ZFPe)gmKmn3?we|*9f@H-4voZ$BDv@mG#MdA)K-jHN~uy z8gHU5mz#N3`Z(sQamf=U-Z2NV5%xqkhM3l_e(uELF5&x!_bWe?Y17)#{VZeDX$AU| z9`?-yfA+5mB{m{cJo(h#0H4GBvBMCpEZgZ^)%MenqNyMNoJ8NnR5mlp_1<}iRpA&c zDJ7JhY+~(`H7N$0IM36qCSj&7EOm~YJlMs=1w0gb+X2A`$?gjI)7 z--~8^Zj#(7d%6V6o~IH^DE<*NR3@?}98ShQ!8d5)78zAX}pofxn`cu<{ z9xgulPhJq^GD80%TBUkl+}UO2nY~7Ak3-=50`sM*{#kK_dC^*%*B@>w^4XFPinkmp zb*DSkv+#$fOI3TqLvSY}?@92GD+T#CxZlf! zWR&V(wg|Z6p=gr`{clEo)eDHi zwWU{aO@k`T`VdxwV0g? zO7$p1q!Vj8do?hwp`lfMPEkY#gUf21vckP%@R4fp)~$-F0vOw7db`Dz~ zT9o-0UC)xitWKYT5VIZpwRD>|JH0A3*8{$CsHOJzS9s7as>=HR`9laU2iL!-X=*M9 zSpf4dX``Ma;Q#NQEKa?>4&Kkko1C7#-phDm$grRLDJ+muNYWG0b8Zr)%POyWe0+T0 z?A&%yXaX_gmYfC$U!FW03|x4)7WcDMblhz7Q(_dE7Q5cmlv`gX9-> z8Xn?(>+{9Jhs~)!HfrS7wrCO+@lPi=f1fqgUaL>;7 zb#lMMCvZfyF^>II%oyvzw^N3&mzS2blbI(oc~7l~m}+rm4;sxff_R&IXK%QpQI)eD z8u>+a8a9v;*~iMi!2BBI8?m@_f&N8NQ*%n rM*Rc?yDeyy%7yFS@}{iVpQD80{Z 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 if (!this._started) { diff --git a/src/rockFactory.ts b/src/rockFactory.ts index 5b9671f..9dab2da 100644 --- a/src/rockFactory.ts +++ b/src/rockFactory.ts @@ -1,5 +1,6 @@ import { AbstractMesh, + AudioEngineV2, DistanceConstraint, InstancedMesh, Mesh, @@ -7,7 +8,9 @@ import { PhysicsAggregate, PhysicsBody, PhysicsMotionType, - PhysicsShapeType, TransformNode, + PhysicsShapeType, + Sound, + TransformNode, Vector3 } from "@babylonjs/core"; import {DefaultScene} from "./defaultScene"; @@ -34,13 +37,18 @@ export class RockFactory { private static _asteroidMesh: AbstractMesh; private static _explosionManager: ExplosionManager; private static _orbitCenter: PhysicsAggregate; + private static _explosionSound: Sound; + private static _audioEngine: AudioEngineV2 | null = null; - public static async init() { + public static async init(audioEngine?: AudioEngineV2) { + if (audioEngine) { + this._audioEngine = audioEngine; + } // Initialize explosion manager const node = new TransformNode('orbitCenter', DefaultScene.MainScene); node.position = Vector3.Zero(); this._orbitCenter = new PhysicsAggregate(node, PhysicsShapeType.SPHERE, {radius: .1, mass: 1000}, DefaultScene.MainScene ); - + this._orbitCenter.body.setMotionType(PhysicsMotionType.ANIMATED); this._explosionManager = new ExplosionManager(DefaultScene.MainScene, { duration: 800, explosionForce: 20.0, @@ -48,6 +56,35 @@ export class RockFactory { }); await this._explosionManager.initialize(); + // Load explosion sound with spatial audio (only if audio engine available) + if (this._audioEngine) { + debugLog('[RockFactory] Loading explosion sound with AudioEngineV2...'); + + // Wrap Sound loading in a Promise to ensure it's loaded before continuing + await new Promise((resolve) => { + this._explosionSound = new Sound( + "explosionSound", + "/assets/themes/default/audio/explosion.mp3", + DefaultScene.MainScene, + () => { + debugLog('[RockFactory] Explosion sound loaded successfully'); + resolve(); + }, + { + loop: false, + autoplay: false, + spatialSound: true, + maxDistance: 500, + distanceModel: "exponential", + rolloffFactor: 1, + volume: 5.0 + } + ); + }); + } else { + debugLog('[RockFactory] WARNING: No audio engine provided, explosion sounds will be disabled'); + } + if (!this._asteroidMesh) { await this.loadMesh(); } @@ -100,12 +137,23 @@ export class RockFactory { // Get the asteroid mesh before disposing const asteroidMesh = eventData.collider.transformNode as AbstractMesh; + const asteroidPosition = asteroidMesh.getAbsolutePosition(); debugLog('[RockFactory] Asteroid mesh to explode:', { name: asteroidMesh.name, id: asteroidMesh.id, - position: asteroidMesh.position.toString() + position: asteroidPosition.toString() }); + // Play spatial explosion sound at asteroid position + if (RockFactory._explosionSound) { + debugLog('[RockFactory] Explosion sound exists, isReady:', RockFactory._explosionSound.isReady()); + RockFactory._explosionSound.setPosition(asteroidPosition); + const playResult = RockFactory._explosionSound.play(); + debugLog('[RockFactory] Playing explosion sound at position:', asteroidPosition.toString(), 'play() returned:', playResult); + } else { + debugLog('[RockFactory] WARNING: Explosion sound not loaded!'); + } + // Play explosion using ExplosionManager (clones mesh internally) debugLog('[RockFactory] Calling ExplosionManager.playExplosion()...'); RockFactory._explosionManager.playExplosion(asteroidMesh); diff --git a/src/scoreboard.ts b/src/scoreboard.ts index 5108e7f..dcac546 100644 --- a/src/scoreboard.ts +++ b/src/scoreboard.ts @@ -32,6 +32,9 @@ export class Scoreboard { // Ship status manager private _shipStatus: ShipStatus; + // Reference to ship for velocity reading + private _ship: any = null; + constructor() { this._shipStatus = new ShipStatus(); @@ -64,9 +67,24 @@ export class Scoreboard { return this._shipStatus; } + /** + * Get the number of asteroids remaining + */ + public get remaining(): number { + return this._remaining; + } + public setRemainingCount(count: number) { this._remaining = count; } + + /** + * Set the ship reference for velocity reading + */ + public setShip(ship: any): void { + this._ship = ship; + } + public initialize(): void { const scene = DefaultScene.MainScene; @@ -140,7 +158,11 @@ export class Scoreboard { remainingText.text = 'Remaining: 0'; const timeRemainingText = this.createText(); - timeRemainingText.text = 'Time: 2:00'; + timeRemainingText.text = 'Time: 00:00'; + + const velocityText = this.createText(); + velocityText.text = 'Velocity: 0 m/s'; + const panel = new StackPanel(); panel.isVertical = true; @@ -151,11 +173,21 @@ export class Scoreboard { panel.addControl(fpsText); panel.addControl(hullText); panel.addControl(timeRemainingText); + panel.addControl(velocityText); advancedTexture.addControl(panel); let i = 0; const afterRender = scene.onAfterRenderObservable.add(() => { scoreText.text = `Score: ${this.calculateScore()}`; remainingText.text = `Remaining: ${this._remaining}`; + + // Update velocity from ship if available + if (this._ship && this._ship.velocity) { + const velocityMagnitude = this._ship.velocity.length(); + velocityText.text = `Velocity: ${velocityMagnitude.toFixed(1)} m/s`; + } else { + velocityText.text = `Velocity: 0.0 m/s`; + } + const elapsed = Date.now() - this._startTime; if (this._active && i++%30 == 0) { timeRemainingText.text = `Time: ${Math.floor(elapsed/60000).toString().padStart(2,"0")}:${(Math.floor(elapsed/1000)%60).toString().padStart(2,"0")}`; diff --git a/src/ship.ts b/src/ship.ts index 4d08877..db5f1fa 100644 --- a/src/ship.ts +++ b/src/ship.ts @@ -80,6 +80,13 @@ export class Ship { return this._isInLandingZone; } + public get velocity(): Vector3 { + if (this._ship?.physicsBody) { + return this._ship.physicsBody.getLinearVelocity(); + } + return Vector3.Zero(); + } + public set position(newPosition: Vector3) { const body = this._ship.physicsBody; @@ -99,6 +106,7 @@ export class Ship { public async initialize() { this._scoreboard = new Scoreboard(); + this._scoreboard.setShip(this); // Pass ship reference for velocity reading this._gameStats = new GameStats(); this._ship = new TransformNode("shipBase", DefaultScene.MainScene); const data = await loadAsset("ship.glb"); @@ -126,12 +134,48 @@ export class Ship { agg.body.setAngularVelocity(new Vector3(0, 0, 0)); agg.body.setCollisionCallbackEnabled(true); - // Register collision handler for hull damage + // Register collision handler for energy-based hull damage const observable = agg.body.getCollisionObservable(); - observable.add(() => { - // Damage hull on any collision - if (this._scoreboard?.shipStatus) { - this._scoreboard.shipStatus.damageHull(0.01); + observable.add((collisionEvent) => { + // Only calculate damage on collision start to avoid double-counting + if (collisionEvent.type === 'COLLISION_STARTED') { + // Get collision bodies + const shipBody = collisionEvent.collider; + const otherBody = collisionEvent.collidedAgainst; + + // Get velocities + const shipVelocity = shipBody.getLinearVelocity(); + const otherVelocity = otherBody.getLinearVelocity(); + + // Calculate relative velocity + const relativeVelocity = shipVelocity.subtract(otherVelocity); + const relativeSpeed = relativeVelocity.length(); + + // Get masses + const shipMass = 10; // Known ship mass from aggregate creation + const otherMass = otherBody.getMassProperties().mass; + + // Calculate reduced mass for collision + const reducedMass = (shipMass * otherMass) / (shipMass + otherMass); + + // Calculate kinetic energy of collision + const kineticEnergy = 0.5 * reducedMass * relativeSpeed * relativeSpeed; + + // Convert energy to damage (tuning factor) + // 1000 units of energy = 0.01 (1%) damage + const ENERGY_TO_DAMAGE_FACTOR = 0.01 / 1000; + const damage = Math.min(kineticEnergy * ENERGY_TO_DAMAGE_FACTOR, 0.5); // Cap at 50% per hit + + // Apply damage if above minimum threshold + if (this._scoreboard?.shipStatus && damage > 0.001) { + this._scoreboard.shipStatus.damageHull(damage); + debugLog(`Collision damage: ${damage.toFixed(4)} (energy: ${kineticEnergy.toFixed(1)}, speed: ${relativeSpeed.toFixed(1)} m/s)`); + + // Play collision sound + if (this._audio) { + this._audio.playCollisionSound(); + } + } } }); } else { diff --git a/src/shipAudio.ts b/src/shipAudio.ts index c1ac127..4b43f16 100644 --- a/src/shipAudio.ts +++ b/src/shipAudio.ts @@ -8,6 +8,7 @@ export class ShipAudio { private _primaryThrustSound: StaticSound; private _secondaryThrustSound: StaticSound; private _weaponSound: StaticSound; + private _collisionSound: StaticSound; private _primaryThrustPlaying: boolean = false; private _secondaryThrustPlaying: boolean = false; @@ -47,6 +48,15 @@ export class ShipAudio { volume: 0.5, } ); + + this._collisionSound = await this._audioEngine.createSoundAsync( + "collision", + "/assets/themes/default/audio/collision.mp3", + { + loop: false, + volume: 0.35, + } + ); } /** @@ -98,6 +108,13 @@ export class ShipAudio { this._weaponSound?.play(); } + /** + * Play collision sound + */ + public playCollisionSound(): void { + this._collisionSound?.play(); + } + /** * Cleanup audio resources */ @@ -105,5 +122,6 @@ export class ShipAudio { this._primaryThrustSound?.dispose(); this._secondaryThrustSound?.dispose(); this._weaponSound?.dispose(); + this._collisionSound?.dispose(); } }