From 3a3f4e31a12694569872add09ba6e8df54a4578f Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sun, 19 May 2024 17:30:36 -0400 Subject: [PATCH] Add start of tiled map compilation for levels. --- .gitignore | 1 + Makefile | 9 +- assets/sounds/brick.wav | Bin 8672 -> 0 bytes assets/sounds/no.wav | Bin 0 -> 27292 bytes assets/sounds/paddle.wav | Bin 8660 -> 0 bytes assets/sounds/push.wav | Bin 0 -> 25340 bytes assets/sounds/undo.wav | Bin 0 -> 34076 bytes game.scm | 40 ++- modules/game/actors.scm | 14 +- modules/game/levels/level-1.tmx | 23 ++ modules/game/levels/tiles.tsx | 4 + scripts/compile-map.scm | 588 ++++++++++++++++++++++++++++++++ 12 files changed, 664 insertions(+), 15 deletions(-) delete mode 100644 assets/sounds/brick.wav create mode 100644 assets/sounds/no.wav delete mode 100644 assets/sounds/paddle.wav create mode 100644 assets/sounds/push.wav create mode 100644 assets/sounds/undo.wav create mode 100644 modules/game/levels/level-1.tmx create mode 100644 modules/game/levels/tiles.tsx create mode 100644 scripts/compile-map.scm diff --git a/.gitignore b/.gitignore index 907c4d7..74967b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /game.wasm +/modules/game/levels/*.scm diff --git a/Makefile b/Makefile index 31f1b94..d604e0d 100644 --- a/Makefile +++ b/Makefile @@ -22,9 +22,16 @@ modules = \ modules/srfi/srfi-9.scm \ modules/srfi/srfi-11.scm -game.wasm: game.scm $(modules) +levels = \ + modules/game/levels/level-1.scm + +game.wasm: game.scm $(modules) $(levels) guild compile-wasm -L modules -o $@ $< +$(levels): %.scm: %.tmx scripts/compile-map.scm + mkdir -p modules/game/levels + guile scripts/compile-map.scm $< > $@ + serve: game.wasm guile -c '((@ (hoot web-server) serve))' diff --git a/assets/sounds/brick.wav b/assets/sounds/brick.wav deleted file mode 100644 index 9212400305007f94fb9f91168927d351ac59c740..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8672 zcmdtoXK)nfz9#UIQO>!$C+Cp?lXFfYn1)%+r?*dcq{pV?X?N2OrL9OCmDV=Ro)(uz zq&`SJk-8yuYHC4hz0?tbL2nPeW#86)H~-!3ck#ttiZ>U(DptQA{C@BIlK0jRqdpw^ zfPb)k9Qkqo#}6O%B?C&fl{_y=EA3diqVz_ox3pH-__70KZ^|<94)`Mc0#4yZXD{a( z=QXF`w7UAZR=a+3F)qEkt9z0Al>5Cqm1s&#Aig7hA!Nctb|L4HhskGTh|HsUQ1hw7 z)KkhwndwgSbb2R!izexGram)>S;qXpJYi%8W1F(W*cI##>?4+EGr784A8szUlPlzk zxd>b6qrcI)TXO4h5Esg^v;NAq{)0&|M_7t>NxGn3zV$vDGU%g7r}873R5 z8Cd-({ZxHzJa$A$#mbi!r00fWxQcnXlP~#>u=~6>s#rg^}p!W=(^}Kb+5F$w8OP| zT2^yGvp|!tNzuGi?@^Ca*H(wH``8w22v!yIqIc2F=rFW88bTf+yO4=U6C@dVmwPI= zpQorS8gGnG!;j*{c$TxhbAj`Wv&@OQI=U9PPPsm~GTp7+)7=N$&)uI8HHo3b2BMH4 zh+MKYIfdLw{z8hRj%rU$qjpjED2_tu7W6oJ6MdQfK*urFn4Zi$W-oJ>p_p{G4%?TV z&+cXKur4-{tIBodrgEFP^W5*8!XbPEzArzA-^O3!U-E#@7HSFIgvr7>;h6A?P$oo) zI6hD6~(q8|=T? zmfPyvDC=HpFKd$ZXUiN*4U5~n&)nafZGK`}W6C#0nXVhZG&VGP3>OVE4RsAbe^EbM z-%uaWUDqwq(HQ*%-?L(@bPqj{{}rXHrQq6XMaY#r7Yvtj~z9bJp| zL-SAtxr=N?Mj>^PSY$wAu&g#d9^Z?<#FLyYoHLz2INv$bU9DX+T}NE6U5W0-?uqVQ z?nmx`yE4&__=>ndln`lT6LK86mApyPBto^MCQ{#0HzfUGO{}8jsAZ@Hu{<@eHn%bdO_xm5Ow~-J@rZGx z(QN!^*lQSKFc?1Q_vwf0t$LU4m~N7;rVePYY8PwswaMCNnjM;9nol*N`X}{rbr&_J zF2zn^^RTv97WN)JiOxgYqX_CmE+EU1o`?-ma_dl4@!|M)_!B(Z+0Z%Jx!?KHnc!;T zn&R5$dgh9D*L9C_Z*|{w1GkmvK`bFo5pRhEvK~2t+(=#}on!{pgc?nKO9M)+l8IRe#>5E-?1vr!sT;gxYgWo?h(guseCoQ zD?f$b$p6R}@id<#R2JF`qlM+dKH-M&R`3ZqVlAKMNlKQja#OjNJW*aQ@08EU59E)sM@|J+&fp^~;ORJMS3b$a37a&#>F=f7sUAn%P9_5$ix}ruDvMk)^(cGaoSz zGpo(No4z)6GR2wh7?&8E8$*Ud!AG?cf!UkcVVgS8`evJ-BtD*tq0rDL(4rz!aB6LWNcf-HJ zui+A&=N#zV*{6yO(>V`=T3nXA`Z7X~bTlhzJl4vM0HiJVE|J zR-&p=eW|6?3F;*kq4MZ%^c;FGeV^v&T&5{Af?3V{$h=^DjGk@9j%L@eKeE5EGK+AH zxPjb4ZZG#USHe}|t$Z7PB)^u>%3CUufm@f_!=Zo9L zbK(<`5Thl7)KDsrCP`mOd!;MVGl`O-WvyIS{#+g<&zHBz$K_k{YnhkhfDY6K9l#JU z6RZJy!3FRDyay79SF}nErH#^8nW!vQHY*Lx_PiI4WsX{o68mO*8@pmVY8z-vv)!@I zwN|s1S$0}_SQ0I_&GXH5&AjQDX|%~~DmLyk_BG}je>ZF~6d1A$FZ5gWee{_APu=&r z;X1pH)SlAL)Hc>eY42+`YWipl8n^n4`b%{ib(;DOb_kn_HN_IJm*@d>D%u=PMc*MO zkoibwM2nnCkHMSZ)A1kh_jtCmgL9$ttP^))uFkH7uG6j(SC+etdxra<`-Qs_QHvNx zY$UD`B!Q4^$S=rUA{StuvQdMpv50q!XemNjtm4B1nuwQa2`ehRAm+ck( zLc@N^spywcuwT|G8`ARgB*#8SH;2k`#y;GhWxr>eW2S?mh79P5VZFao`ZE=PNyMwCOYBO8#xNHrvqJ59*Lhu~ZB zhq%gF&pF=tz4Mtf*45B8!L{4<#HDiAbPsob7j9eJ57 zB~z(})Cg)lb&2{wCDOI%0rWEZIQ@+F(MF~nGl|*ETxN=yO00wJ%znXcVK1?NvSHT9 zwdO`~UvWpd2OPyE^HurJ`APgb{sjM!C;0>+PiQNQ6qX8mglobZ!6RgeHN?*1SaG?y zNBl{ADe_{HWS3e<{iPYwdg+LCQ+h3lQle~;8_Naq1bL~vLp~$lm*2~ZoD3|WA?ON5 zfqCF-a0pxlPe2*)ffU80)KfYtgOsVt3gu;RWL{?8O~(|6-tpMJ$X?T4YTIh-U<+E$ zSVvp6)@PR0mKGMD`HXqI*=jB}eP`-r$}klf*BILyV~uwW%MGm!(S|$vmHKx21pOo3 zMqPmp(Y@8~(~j1Drj;~THA^%dG?|(=>I3RY>iX(W)J52KY$R3#3!=ZG+t5*HZS)iL zH)JpJ1=0dZN2)~sV;wKSFTr(ecJ^_ub>4vM*bdk6TDXo`xQ@G(uj3EyG@=>tk9B;% zd>wZ!U&qhMF!?D}KrMvp__y+P+?k$1@1k$h)L+)|QwA_<_CK%VdgbeQ*I(B0Fn$TY zm%qus=fk{KXe{&-Wf?J<>l-6Y56) zwXL)X+9#TAn!y^ohErcwFHv_==c+$oC$QOAYb+gmhaN*`qixY_v=ljuEJb=CW<<)3 zl-0v0;s@|Q@Kk4O=WOS3=X+{LZu1X9bRuh+qG9r^~ zMou8Nk+(>e#HiNPWNJJ0GeuF^bQ5|My`DZ#zojcNm6>kLEM^yTi*Yf@Yz?*-JD1(f z-egPJSngA<6E}(5$erPyaT1r!*Wr8dGx;t2dHy*s@)<&P;d5bvuv$1G+z~zsVL>g{ z7YoEG;#%>r__O#{^oW^KRjI8sRGKGkkxokYr1z3nN|!&CTgv_9sq!j$uY5^ z-$3uzUDGYrwb8}vinQNo`)c)CTysJ*UDH?-ttnD}s~)PZtd_AG*jlU)X2E#$8oCDU zi#kw%+(EV=Bau2t406h2!u#SI@H@C4ukIY_-0pnjj5uq#M!B}Res%d>RonyJ>)eHI z+N~iv5Oavb#B(BwtVZ@HSCVJRVlsiMLk*@@QD>(UGOb}+F=Lqx z%z5TD6J{)IJ9YxQkv+%0WPPlbYsL-ZmT?EUdz_1l=kxdu{5XCUf0X})ck(fURcIv) z6&4D+ge$^JK@!r%s$zR_q_|kzC0-JriHsO8nWd&uAL$EejdW1DCcTt6DNZ)Z4dia} zSb4F$P5x27E5DT`IT08^J9*sq(EdIZvDS zz%kd6=lH|E+TO@c+xFOc*kWy0ty8Qv>z|fyEFCSMSgx9(E95XT3u%kwA`=sn@z(e}{50;wHO_9%<<84a+G%k0 za4mOTbh%xayQ6!a`PC2kT=iuc7*F)X4|ZRvAqjI>1B zA)S*RNw^f25V^YCP97r9mN&?Ub?30W7GbAWBuG zh0;?QqkO4sP=3v6oJTmeIodiD`w@Fzd!oJ2HpOPPy|S*gwzPUIKUzjvw3gq^8_ey@ zQRYI^Y*TF$XFOpXXLJ~G!$HGHgVj)`KcpY6&(l-7A9Yi8b#*@Nb?tI(2W`6crRICh zD9vXYMSVlPO5H=PRlBgW*g~u$mW%!S3ta=MIzAfTg+IgNoK2ilorj#Soyo4|uBonr zuHRj8?gs9$?(OdTZjake^dgoKXNdPiGTD$EMQ$Rmk!~`JYDSHtHdBR^lS-rO(?jW1 z^lADP9j0weCuSP6jk(5@FmY^Ewi`Qx-Od)W@7Yf{8`q8-$F1c~a*sKVOXq9w-TA5f z*ZgVz3D5E=LKUH-FjiP091v~_?*zYqh_%J8;so(4@ql<;d@agis`RPUS{fwHmcEvb zNw=l95|C14yWC9fEl-wL$h+n9@l1{axKEU1wc7RLl5i|$ua_%kP`P4!&Z@21uXg( z#guZ|3Wcq|EUT=KoE_wEVxK80KFTbM5~~F`4Bz{uS`X|F4Qcx#rwxZasI7d(DM83*R2vaua`n z|APjm)HJ2fT-cjHitwjEM1}VTqx>fr0%#NS~vB3|pkN zE(~v!v$VCfyylc<66|(HeNsIc-oZrd0yYP0f<I33>_ zZr%<2Ihb&eHwtZpF~S<*1QenmWQujfUT{@?D_(?dSKwcwI`Gal72Y3DN)Mq8V`Q`3 z9Ny|@%bVfOeE|Itk=39M=mN%qC2&ifhZ`4%_Q-`MYzwVE1Kv>fD_4{!ic<+HnI4Cy zsi%i$jAy>*YtJFi6;F}pqX&56y;^T|Z!2#v?-=hq?>g`I-qYS&-WOin>+#0>FyE)X zM!rtI0lo>oxv`?=N6iFHo(6|9AFej5OR)XW<#x=C9!Dobm3xpvXul3f8uBW4Pwtr9 z8oB^|AHY$@wj)~2jsSv9jh$$Fl7D05b3hfHlImvJj&TgHTp z7Vs@5mHu=3w)DyA`RTfJkXDp-IBii{zqHzEDQT|MTdCit&Q0x=S~K;de*t%dd%}4+ zBi{~QcfW;uwSutUV&kONrAb66@g8GNM=#yuFMIUjWQE6-((!mn4i%l!1|SB(ypWhNrRJ`Cz+ByNx~C-DsV1Sh=aZQ6weVWAilg^!7~ltn_^E zxd5NTGLPSr0ds5WE%1)>F7$5p9`#=HKJz+ZYNKhi(LzudpYf6#xb&^FLBFg!3NupqD| zuq|*fa3*j)@F4IiP#WL@!9ZLvD`*H-3Dyg?41ON$8ypdw9Gnwe7Tgfr9^4;18N3wy zIruR6B3K-B2ZdlD7#&Ip<%SHQyim&yOD(pC4a2K0RKEdmDEv?r7Y`xLI+7 z6wo|uxD$1zu9j>K$^SsXJdrhiQP zn7T2Rn2eZ6G#mXk`eF3d=pUlLi(VByCwgpj-{|(y4WlbZtD}>mLzUP{A1bW~t`6)7 z91Hvuco=vSAOrqDLJ$o);3sbrEC>z@P6;juu7RKWQ1D#vX0RyuCg==G!ALMEgoG@i z>Y>J=wxRB!L7}ms>7fOoRq%7}4jl=d2^EI!hMt68he|?p2!z6+_;5xT3!B4L!nMOq z!fnEx!@a_T!Xv{I!!yG3!^^^J!{3Cz3-1jd3I79~fw2HKgbdGe7^p5n842g`0jEzi;OpVNp%#AFJ zERC#;tch%hd=vRL@?B(iWMAZ9T4mj*EGc$80nJ_amGcz+!m~q0)oH$@RExzw=Sy4Na zGyl2w`_@0tT2ecn*iu#X+f}toJGCpNq|EM2Q4LDhFWcS45YrE2B%%Rnk?_RRvXam30+$<#nZXCGfrcx*WP#UAWF)=dLsAMCLp5 zj(N=7WX|Dd?O@h0^O;G^P^K5thN;I?V3L>wCWLWiBs!ITLSLi*qIb|M=o$0~x)M*s5T0~8x22h=-hExTrFcnMrQU)qrekI?OPszLFRq`x( zq}*F>E!URI$ob?b*-K{RZ_;z=Z|S78OIj_>mc~ebO6{cvQbj3AN|1sj7fBRT#i!zR z@uaw0Tr18OCy0Z@Zek0umRMFSBxV7eQ$qbe`SAee`3d9}?#5xMZRs>=f@kiL1$u7IXZp5a-9>ghO zZzlT?xrF_h96&4+4rX%5u5cJ}PB@auQA9rBSSEkj6^`Rwp>V>ka1!qn!l_J7Bvh!Cvb~&t*>R=ilEaeCB^DIRTl9L7{)OWTJuI*wf75)i zd4J@-l511WX*v2Qc1UO%-ynN~xMr~(v-OXe61^_!Oys)=uZZOEo?&Z3pM->lv*hI~6>e}HGAf5ROI^TfF#(bww(zEDxbP?J{Kc)6ilc?5IG0L0zET5NG%fsbnaxpnj zwo7-V{n7$ykkni%EyYL{>67@kctBhxjuX3!^~I9VU@uV+UJKWSBfQ-n7z;5h8kaCFR*9W6YMee5WAn<&F)~gvYXg->}qx;yNq4TE@0=fv)LK!G&Qz+H%c&H9A&XQ{_XYq7`SQq?K!4_FC!6r7kBoEb*b(n4)n>*9(s*lvMCX{=@mk z=WU!Pe{Qc_KXN=vypeD|{#5oeahGH7WqTh(#RNwei)tA;A!1+nyRh)E#-R&B9tKAT zcMm!o=pNWE;HZDF|6sqTz7>3T_=NjR^VWF}@cQoA!}GI8PmeVBLGA|k8E)Zj+g;1L z-gD{YVslw%D{p&c9cRs9yiLqQY4>9L3KQc`>l{0b19mdYa7~@mJQbSWih~cq* zxxSq~LH|X!UpE4|xS#F?vz-~nRA<7OFVNn(bQfgNe)K2mG_{oKPt~S!QC8}Wd>WbZ zNMy-np~H6m1OJ%6&Yy-7Z{b(+bNNZo;y?K=d@H^Ivfpxi zF+MM!9r>?6?+!(lxF1|9_lA4Q-Q#X>7r9f&gZFVexJ}#|ZW*@#+3-~4!=t%j+(77a zPp%6Tx;58~YlPgm7FU(4$d%(tL#dOHCFkREbBSDbE*rAtFfJIH?FZHN;9NNyXXcEY zj-#R80`%Js1^>=|WmDNt(DC=|TjbO)q2|xnC+s6+*Z0|b>>cR(E%t9{`*rpz^!+k> ziM`04N8WuFN`IO?#h!%TA7}pp$JnFn5%w^&{}6kSJplHz``Eo;57^D_0z1JDupMjz zTODj+x3HTXY{KWoCU#>c8(6~npRB`Y31Mv(*05PwjnA8ZV-@?~@NYjM>-Vz$cIU5@ z>r}2^xtD)Cs(1bCS+U8lN5x)QkHn5yQS9q{Bv#J~@r5(QKh6-JIYa#D%x?HrgZSDR z;(urMAtp5TBSxGdQKNAXail@w%9+E6HH{;PJ!g(08a0j~I{!kXp8O4`5XHaaG~)YL z&LHZ4yJA%j-e|Dp#)2p+@%Vld9gU9A9Zzg-7MfmD^P&vGk^r z`IAo-Z&Hj;T3MuKVMC$g1xDwumM=7KTJGz)cIRA@V^ZSqgn{t`vJZ`$5IaBHmY6fq zucFLRxg(oKOb$OD#)lRO9T;*f*b-bnXkDNXP%mJIzlZ-He)oLK_-^wF^O@mo^d9EL zdG_~YJ%)JbJSMyQyRUI8=yuk%sq1%_$u4m&r)}+QM%zYf4eJlfa!VD9-Mr4+z-%!e zG4(dZo1PmN85=xDtbJ2wu02OX7)Dp@Gg@r^R z96D?g1pW*EihsagpviUUSd5huj?~^JR1>PI1S$Lr~{k+*WQQGUruL=tbOoZZ~rcmt$(Cs=E z-!X9i#=rmFtl$0hcRPQrUZHZf;4aiV`t_{b@9&SQO|qVewSGmhqw|qiH!F(OwIlIF zR)~L`AwF})7k+excvge>+L-|O-x(4S8bOE=XGqi#LL6}vj(GZ&2t?UGiA41MN)%%9 zSE3QA&XCy6N;X8aGqH$qXW|g`&Sb~?z?pcwGn`34)#^+l-a86Qxr8A965}c!ubijy z&5GqKY$+dDZgLq@>4_zMlGhb4UF=2Dlp-Yxrx)B+pnv{y`TX*xqSLS|=h7Tg6UQWs zh##4KLfo9#wb_ou+>N$Jg+!%9_K8><{xHlxtUhwyr@@KA1A;CEMg2Tj{ZM3p$DRrc-%Hn}1JVjTP`H%bysPPT{0=mKn`Ca@bel_|O zbNFfeczy)B!+rSfd`G@D-xOJLE$DIuzBFGPo#K3aE_5$qkS~WIWA;YQY(v(p<0)vg zolA#Gf95`*r|}X>{g``zEc!OO$=A3m$feJ7XQ0`~q1s2F+XtZBySbgnt+#PokY8`$ z)j(Y>eL)}a2k7mf7uO59JfVk!?i`_8CS5s|F39&4 zI^&Z>r4xGNS?S3A|AF)G?ELe}l9hxFU()pHf$2HYOQqLNZy&s= zY+%uVq@#tq6pASLApeql?eiAQW6S*}=lL8v5|<^+il3Z)Qrz^|1=-fe9FD#f^*z!z zvP4A3@cChvLye(jLq-Rm5Aq6X5x70T5YWtjzn{O~K;I`m6@7Ml$9T{6vU!d6lsyJ} zi0;GPjqcOjg51`*7KTbRcS*NRwZ+@cSle4o)=ie0mLKL7<|<~pX`QKo$znQU>}`xU zJ~J#b)HiseCpleTOYZ}HSgdP}m8);eA!aO78+Gv~`Y=6(ZjN;?J$;wjLXDytQ~6L8 zzmkv13+2AZ%5uxD@<-_+a@*ul1+t5$icE917n1*{4>)Y>Wz4B%{As~J9?4DkrCy>XFw!AxqR>$Y~mPBU^7s|en9Q| zjD3K5^#*FxbI9jO4{{&smaV8I*P`NE#x7##JGzfk(0d%mjz;HkDEf~59bLzsY&W(G zIwhpv*b04^X6WNIL{F$LdP=0fNcvQyw^-59Q!MM~Ba-f6adZol&=V}g7Gw*s`PjT{ z9yT|di_OXAU=!H{HlEGS#<8(%HW0%`vr%j$h+xA(7#j*g*kBL@0zm-q2Y$fUfe-7$ zdOPr96+Bsj$4}f@6*pGHmHizq?Ei${{Y3I-ZnzfZs(yb|ul%29<<7Dm$sK1!v4nOc z*3lsL(jXSpAU4$?R#qWa*9d_hRESqp!r&zp;xm;9_)vv-R3!=?Cd9z!aUj^{o2P2> z%+lRU*DUopc~}Xr;v0)rPWoDSS)sZGJqrAtZ%N*6dCKOF$fe8qG4Vmd)%f$-&&ORs zKkaRd80{BbFsfnX@QBUfkHWmds)SAmxftvj+&E}G!lZh@T7SmBwclyqMBmvyv`;VZ z7ha9LZg^Jnyy#KYhze zrY)uxCU4Vu<8WgU<2S=rLl;B5;hlb?zN$oMmF=>zm6 zs78L;Oh3j-#uTa@RgwzC+Vgc(bCcvwaz#12Y?j|aH?~OAr9ZI3TtbSH%+hD^mUviP zElz=Qv=A$a1;jAXDy9q1g)71#tY*v=Mhkyn9l4fJTF8q&nwOvx(y*R!7umuQew(9< zHh~|)_ri)s6DUY|z9^rE&xU%<3)Py;WpJOMA`kGne~~+hPx@WlW_+$M;pXD=djdYG z2jla%2R<>|pl{X?dQy$6z?DJItO%DM)l~vA&q!2H0nil>)IVlaDKsadOO}BiSt|RH zeFuek!9GQ2>^@ZH7Ifw+l;#4o<_vlY$Dubzpg0GhIeX9@*?}I*7Dp#*y`x{X#<2#n z0xGnWT>>Rqh_#S;SPhv2MVf^bk?B|ynaWPVy2vD`(?oUxR!7FMW3fUq21+%G9SKIT z!@)49)=;dN3}FX@L0}*l0Q!S|4*p~beI4{+34dhLn^ozBl@^trY*u<;4d#D?p7;&w z@B7_Zy{g}zl`H@CsN9wFQMp^~sMtU|61!*+OKA|>X%K6w5bJ6Xd#e!ps|DXSa>um4O9*(vU!d1elpiIwuv#TqW_9|9%+dz7|||#LD=>)$6QhInUD`6+Ny%F`l_~cavPFyJmAe z>{8F=i*1T6hwX~Bm(|aD#L~gyX*p`{W)3x9HH|bCHhng(HMT@0a?daid4|8E3)EVl zU7xDkhYoyIU4ZTtvx^ytOe2~}r_a+%=-zZiI*iVsuA&MVNj0OAFtd^--;lS<)6oN} zg((#u`G<60Ix4M_#v|XTD;0xoSW$mGK*q6ETp*4Tdx(vZbL1BzFp0to?}WR;8DTH_ zKXZgJ!kv35u%l?2GrL$>Jq;JT1zCf2gqj&$&(Y=3%{{365 z#=d4>ftS##7mi;3GicURbo3vCM~=S!L*z+>`;HF(J#_i+IlaEi67FPj8~uO6t)JXv zHU7rRfHOCsivQa<|9t1y+Er+;w5wEK-Nt>~b=;wLpX9!?qSzzr@gY_~oFTSzhS*c% z2`sEZEUxhknW@HectwTyNaZDbrb0ZZ@fto=c>@nCyo1+2!1o%y^5ck31uiCaD7qx6 zXOYChuL`az&>?@me7d~%p%{yDj>*wCv2#MZ_;%U5#QhmNHrwKuy{Jmq$jHd*5yQjx zgr$b&3hf!PH<${p9<)3#BcMjWCV!iMcfVV{C4D#hgka5%bdGt?0iL|aFb{*rH1{C) z4Q@$pmt0%9vM#e+a=Bcxb+x(Kc3K-+DeFc{eT&Yr)7-}FYd&upW-4S#HEuArGe)5{ zSz&06?!`O(R()T6alJu*Rku*rL03Sh)BVk?V)|kxE|^KBPtl8@8kOm2TA=PwJE^Hu z7pfu^M;WQt@>zMkJVEX%*MM&L$-MLwz2hyIY8xcAk*Z1srEpA7d>0>!=fyqZ3UMkX z**b|0#PZOND9lhW;y2_Se+#FCJ;FL+fiOuJimpXlp#f$oN(%WgO%dYgSqPY7dxMp{ zo6wNs{C;F1YoQ{fgFJ>GiuJr6dEpW#k8y2<;|lh}cN@+NLQR{U0?6S0_Eh#tgj^dF|7_b>@v zhq355j6|nlsH3~kA0350sE$bQpc|_2&d?vyV{VITsgruID z=OeL&Gs#eU4PrYDVoeQVUkze$m9kg~P$B-%ARbDAw<=|!GQ5}-;#p^^!rRVNga0*T zfepHo`(43{g<=Z17krw3YrbK5>tmJQFPEI-bK;AHNAZucKacwqD`xY|mKakxx?9wo z$P*FY!?TCC4qF!bEF>E#RZ}-)1g`pX3Tm_f;E`?lf+xpvrZO5&htlrk6mM)ec%SEj8=QY1EEj86Q zd73U6Cm1Ul&BpVFNroB*AHxIvN_`i7K|Q6v1l8z>X&#kt}bv9H)xtOxZdgtezY(I$#QD)i%~a1NErHer=84+=6|=qq#< zT3`;g3M!bw$Uvx4D4s=vha9^dyw%FKE$G zbV(1R3v&Q-Vf&Ev?13`va`a2Lqhq=a8np#^&?c}Ez0(cQt96bJ>Kf?QYOo5dbaYc! zaLd6m2TRe>S>j+Zl#TRQ6&6C}2n&8PAK8`4JSgD&pWjjbAN6~`p2`3F-}CF={`G6^ zdYoUWSF4@X`_RtH{Vl=$DtE3Ni6wqz1#-!(5W6`;Y^g!4t3m9ou@*gS4dM}%_3)4e z@tDd+cu-|Cyt>r^@o`qRb6MGePb!sy@|lpQIp^dH%ik?uyS$b1BSgVj4#ei&`IfJHirCDtu7b!B8=ze8}|RCqemw#s@wRC>gNa-{9ZX z?~ZSI-@QHwJ}bO~z2|xPdoAz`^IYSR+vAXXW%q|zCo#A!K?n4vOK%r%m%X+oHX3Wx zb&+XowKTK1TTYn&#C*_8(-KodlaJ|!afY#$(c5_2u+Y%b5NAl$@7IsiSJwyY-=abp zr)#K7&^f_7}??{s3Bwwsre-odH*TlatIkZBYiIwZVVh2nQ zRTY!Pyka&nKy*RRG!6C3W8@&`Fw40M{f}knfJ_!f2?LRdbQD^mmZ^z}`cgs>bVCv_ zRUabw3T}cKYQkeBB^7$|5}C<8{%_3KpXX2U$FQQZhu^_(hOVsUmqS_Rq2oH8pNzGY zF<4z0$`3^MwGa9y-LdlBk#C0@s0H5)O4ATpQwM5O9ePuRuY{_o9Qw1R_++e#V+aA- zQ;;u!%q9;MC@1op1axlWkmY3KqxmT0IuWRzLa{Ov%m+c20i@yakw{TPEHJ3_uTbfN?-W&nO2nN01zdoPyvuqZR!V0otd)bIx%8@jsMP z|0VzNNBsPT^KaB%lj~8gn;ez<_~%i%%dAIo_s%Fb(T>DU&Jf#a5Nm1>`>GIoYnb5y zGyGt6_{0X^WQF+488`UQ8FzS9!vkK{AYRw-LL8`gBPtYZ=95vToNaSg&OIpCpq#yO zbV_WO&_2Fv_Wp6>W0z(-5OXhDjEaq_6FDa0P z>t^${9kX_^23pTq23T@fo|@;P4{9`2hg+kDj973EBC4>rrf{)-K*swyY6J(y}fAHU- zE+6=}(3fZYBRs=%2ldZ&sLVx7mY>GT?O*7}9zr#=7hRPd$YVBR+I&4Kqt(b~mZLse z%rE2@Kz-&we`Z2~rlDS%%unPeK#9gei$?RKphv^ei5Uh}8iHAzLC~fF$bb5wrs@lg z>Vr(EH(vr~9K?^7yq4`gm zLHRVAVofS5+V_5amG%Gox37NvoB#Y;yB_CP>eXszbv@(K$;HiOkFB}QY};dPWA(D0vh;&)JU1^i*EPGFFPbKpDq_|3qH(IRjxhkw zf~+_6G88wM3^!4y^ulb0m;NO(j!C+fP!1Q}OFRKMm+8q=Vd5Aa^OQb{&gfvw$CW^D zl%iiiJ2q0&s6JF9tg6IPZd8W+1ig+O@*;T*x};6y6!bg7WfwFB-$=KhA3LR$(hO;Y z)JtkD)sf0cg)p}qglG9=@tgQcyeD49^xPhCqqqzzGC>@MOr(q03OZ69)l6}8LlV#r z2@<_g)9BDqO%p!h>5?btt6qnmoEDA>`=KaX&?8wPEJl?x6RI)}Im%E>+w~QCV&bl& z&<5Jl1f7$*$XBXj<+r?029wamkhc^R@?riXhY&Bsq85r2!jQuR;yD#xR7D=hWn2Uc zRL20_VFXH$cmW@tEc7P>`OSB9UcNwwK4E6$19F|W=)=5%BE8_BLzSNLPmudO;vZs~ z{8xCAbO3*bCB2hM^s4o*YWPB}QqE1ZDJoj}J& zLHSDi`ZyF&;}|lpe{vK(=l^&9`Sa92`O9%l>J|O-tlmM^vvPONM{>{3D3;KU#5x+p zUK+%L3Kw8gVp|nrYiF*&{>~7OXk3GjG>FeMZorEgf5WRP#K$VP;B%GRh=RL_g{<61 zd^qy}5rYXNW2aF6SpV!)_F8fMW9Mbt7xN%mADt(vRph*g>*4Or87|Yr18FrG>>G&oN9ir(mM%1lCc?nvA9k#%ad-#xUa> z!w$n>LnVWs;gx>3evH1pK3*^CuItw6hG42Tht8mT!W?Ag;Hly2Ob*7%yu+%>26`gh zm99bOqkUM&({4^ISdNA@uuGaaqbFD)VGkb`6k6y%+B zPdYChlr|v;nF%1CT7p7LyM|lHK-yoo)lZ$OCethm%Xl337l$kO1NxWJixU&Ot2HEf&)* z3NcVRLUblk$gxx+p@ESNRIQEBBN2sNAXZk=(yC zidD2Dv6Kd}od&UH4p@~~H}@|PyE{XC;Y>dGM}zoFqX0apQV{;sApTV;41X&Wf%l7M zQVh}HOmW1AGbIo)8Wu_Ld>Z~fdU%XSOoQktQO6^HMC6U=5xzYvBeYcL)R3pa1%sys zy$`G$xFx_RV2J;Fzs7!-eareD_9^1C&%22CVXv}YmpmJKzV_(nVf9$%UfBJbTUR%$ z+eRqISC@G%CGp(pY+GsDSL+INILzpa_O;})yfd#hw>C$bpP5#g+F=s^vvH4ch%v?J zVSIqBqpzVH=Dl9(_v**%n__yysDG&2t(%M|QImCnx-{lGvlUOHc4jJ}OKM@>)0faE zok{;mH>OLXZn4r|sk@lZUl08lh#Ar9R1qo~Q~HAZR=y>lfPyT=tmq)Qv)o9oBqyPU z2}TwoN~xIIzlpV%1DFz9j`f%E(qQBw?W87{7b}ky+`LedFw`_QiIG_Gi})5h4BUm9 zoI`iyfVflKgozMjbK(qfBKjml#r|S%u`5)imDm(nN^P;4SP{ySEEa{fn_#nJR7V|=QhW^S!D9#<>7WypLFlTZ}xPX4k z8La!95ROBCj$#*sL&5=MIeW1Zvwwk_gdME;1;;g`aE!&-)J3t>VU1@FRIO0U3M0VM*~ z`}_HiL(b9L_oGiIpSRwfy;HsVdC}-`gnDlEDC2S0y{Eg)eVtp1+Z)%3uDM)qxeRs5 z?sC&M%9hXe(mKyt)yh~8TKZUWV~%`-xuZGW{K2#pPw^Bn$;NZ&kTx~O8Pg0W3^OoI zp3k5++|h5+4@c&aQ?J)Q((OgRql>PBE?P(F9;0qqjQvoWq303F=$SY4MLgLvhaQNP zmI`!k+MkxGx7bJJ5VeMyP7S6yP<5$NR8I6i%+wG0H8kWDdLXOi*{EawlsiC0DkBrg zjh#t+k&6h@7wILkk;~EvX&=^cS7JS8sx%s_xxJ-Mcp9jIR2}o^$*68}NwHYl^+#@E zfuaavI`WgZ;&bt#cpE#HTtt>~Ts$Q16?cf6#dYE;Xv;!z4%B6eI3D^kTpS_}Kn>Ij zPjhyL%Cv>fG{a0u1FTHNRuU`VDbLcFa4!MPDS{QB{Lr1;P@Y6F9;-jupg&Pi zpfE913`XS?fK10%^g#vXg^b4?isXV?3Y!Ip7_JkIcuoo1zhF+D0=P{<6a)c7>wp#P zP^=$92J)kHC|8>BUHAsRf-fKyd^ zr8U08_A0~^Y4Avf6U0v%c6d$$!#Pf5wxJy!=HO`!INs?$5s{!GAuc3A7D$W`=qxaZ z9}OMiNkcEzGtKw=5gZ(v7ScWBDxN%C1fXV)XUr)c+zAf?WNfVz(-mSdf zdiC~_Jf~n)Wrs%vkH_u<+@BQlVIbZfc_o(~MeMCo_xF?E63 zORYo?WC+#SvAaBJid+;*5`!Hy++;l# z3%*FNrAOH5=z??{dC7KZJu;K|m_;3r8fO3$rHj-SJ8U$NYDtyRF-ew+px()eJS9pB z#oDizMGe99OX}d`>(qo)C|rKYIXLvkU7yTad}D z$1^gkP#-N57ejUCW94`jlxG^WXA*iZVtZqu2=`u2DLy< z2Q{E+)g4qrCRH_)D(E6tLB*y}37V%+5xJI11?ZqNDVV!+{yOVx^4)(Y>;M1zuhieI zp2=0ISDE#!+(Fi(dUxuX+_5u?9ke5{jY>_2&4}GUvp3oq^ zQ6aw4Xyou<6L?aiDLkt|Jgw0jzSn4hSWsz+$k1qoNKt8xxFNJb3@NljJZZE?d}(wL zI~osqcMj+jm=btBASGa*f4u)vKVQG;zOKGgeB6EJc!zke^D5wV5?#`FnEeXy*yUc+ zJ=JZxTYk5@uEVfb&fhM>F#q+~Hr-a%X18v$cCbc5Jr-CRSo|z^uxCy)bCmh5X`89P zskF((bl14X*vD8F>$5Kn`wSBe%??Z8xJ@?qVDLJo43-jAKqCenTIj9X>8ARS4&q7U+hx<#F&c2LWqB15U} zRC81_CD9Lw!j3xzij_aek1=<8T0S6ekyl_EWTHF_y^+pxORUaR#a<9eavnJjPsI7+ z`40~fzD|{E5n^D^_yaKwTP3 z^`I}+q)MoQN@D^(3Asx?DYuk}{%kfW5;ajUw8mHRMkeEmDOWRkEjo#Y>IhiYv_pBm zi(ir3d=fuEf8IiYUP6PO;pv;l$aU_cvwH_>bPIZP19{I?@d`Sp$aW%kB5ViS9BjoZ z)K(}QVRI&%pm&6gKiPn%f;84c4cGtUYvoV>_m1lC)2>2$rCy=)S-pDavvObBQMp^~ zsMvrUiA5CKs7GQgXNUzgh)p$!l{NOl?i$1oD*GM2A^uT3r5+E#cN&M`OAX>%jid0k z$}#v}eh+%HIRq|QxyUw?o?_G3C zUwL=)wtJ27^6^^hS=95oM<)-x#|rn-?$6!ExFxtBL*8eI@ChNoXaLk`eu z=;>I6=}6b3%V4j?Fzi*pQ}3z!$VCpKqq>Ni3?1o-J-h0nuUZsUO(ZfB3nj_l(H(gN zEjcG2!LExN<>m4`c?vRG{ZqpHdYWlE6Zp-yqAu(DwtIvPYlsUlEsg@I5h1ez6$)uliX0Q~VhpdU2M z7yTU{D492MCnT7ectF`au!j!8EfZI09l<3N8~Q>DR%oCz7UW>R!wjV){O)`I&7V2{ zj$dD^*P@=)t5mPr`K;cNc2@3GJ1Y0D9#yL-XJRJ;u^EBbPlH(08DeD>e^_0EctL~s zMI{J+A`p*-WFZuu)F7VK2#2p#BH($INW_6g6yic98j+%s4RNCqizw2FLsV&GN0h0= zBj!{R5P>R*h{r^!f@CwUcI)FQd*1gPo6i@|ciJj2`&UDFSyy;yOnX$nK%^r&&Vv9+;~ z(TW|U_8O)b+8L4!0fuk-D|qs49Cnf_tB=w%`WL!Wy0zHTq>HWwa*zO>#JprKGCP@t z$U?ec+B6w+V_u9zzoT!_C(sR9j7+3I-5x4Z4)sh7?L!;zyvrNv9-h2ELTy7;Gl!ah z-bhcXE!KCdVX~|+v?PiOz&fu1o!0O2d-)k^oNHL|Jtpsyw_(P8xx7H0iRbD@%R^A_ z^hB1@7Bx>pR6W(?3dmJT;Mx8B(3W^P8`LF4_J_W>%Qh&CPL?HJ`XQyE9{L2Gc`d!b zl>8%T%^h@XuS-{@OUP!5>!SZGBidb zQdGtuZdAr1iZsR{suac}!X`K|5mBcy2{EWK88N9c1re$;Ra&U?vh8#&?Un=c9gAG6 zU?g#~OAE}Cp2t3)MQ!QU9o8P!T-H>}4s=b6SS0gl^AzlT6lwlsI%pb?=j-E4cH>3k zQaoc{!5E6(=|#h8!%#y*)GzLa5Bl@^b^5XT_WBfkoZh1Upu3{mp_{84h}n-6tl)ZM zyzvEdiP?iXW&-mE(;U5!LQE9n&It5-`YwHj-b1gZXVarl&$NY#q+q|$1UiIv!#rvl zx~mT`&3=;FkBRmb)Li5wBe0iJH)u&?Oqx|hg;NM>l8p*QZsH0(k!8F56^imgekk9@ z-1~X?B(ju!m?haPuSMOn7?sZqWGmz4QK)|gqAS}A^J$&rc5*B1N7@**P#vrmSH)^i zdFV_@6|=EMR8Bf%Ig~7+ zxy4JYWQP`|Lyf*mU!h2;(r2jBM@+%J$2#;|OtZX3jr9^5^&BfoPr(yZT#uxO-~lx2 zKDxvAq`T0rJJM}%3)}>MgBuR6L({G!iy~Zga79wMjJ`7A(oZfT*HXEFKGCn7hcf=Z z^XpIh^=tJvD`)Mhv{&jCYiIRd)U$Gj+EKZ0^{Ck5dZuL*``mEYir7nmSWko4Q-#=9 zgIHYUE<8XWzEB~)QF#DgX%OG3Jc2J(9>cRLPvB<-;&Z|?C!Ql3G+rP&R9+%hR9+!+ zR9+*FRNf$}2yZiahe*?SkH}N`fH+k7h^SQggc#NMjF?qPMFf9wkSMp)zcE*`j=>Ww z1+1*)h-D=933f-d2djWdlMjU|o###F<3!z#ltLlZ+` z?4tHve?z}hKTF>St1m?`r7r7U=+5c3q60Dr`*u{;<&-2;8qdU)ox7*=PZu|DGh70IAJP|v8_)FtT1 z0ctz7mRf?GWHL3H8btj;b%mBRrRt$uQUPl>NmPC+2WHSBu!iG<48?+J5*Y)`X>uw$ zD6f&JJVdT?6UuTC`N~OTEQjR%SmW7&uF6Iz%qrwAOR$s3JgoW5kf&nxc!E3@dCUl? z%@F8Ke<)5L>`~uS?vCg9I%BTBJ#w2iP@fjaaGGM)tr7B^`f@$FF0!3kn7XfloTn=4 zsmjo#ipYLapiJdZU6qkbW2&|!NJc(X927%GxG40h2q+BIDunv0pj-gtcaRTLba_D@ z2f5Kb&J9%~2Lyy7)igcRy48oxh&7E7M-7SFN7ayHU={ z9V$oVp0%T53H3;9qd}~tp;%Bk5{nXubv1~+RSLuY8pIzeN$`&f@s>(4c#lB*s8Rxc z)kub)RfyMBN+AkVN+Tvz${<1rWt}L8$WbYeI8sSLRH;-zjHy&a#Hmz5{1Gbuqza-^ zqbj0Qr5a*ZrMj$91JSHf6S1vO3vo`U4HD=KeP`n_Or$R|_BB?=N-d3jzxEksW4^Sy zA*aE`@KJwRzYQJJKKcgwV(6I~ka1kc4!Fxvv-H$8)|J)eMAf3hevA*8v&?R01$Jc| zg36^a@{T0vMi8dRc={9l7!&L#k$bGC7tzy@ee}a_xh-ys(>GT! zMSl@l%vp49Ps+#TzvQFxVQ9_)sLoz_5Be`VF{QE%yO3;=H$j0mpn6&d9a@7`=T-7b zWIW5|Wmq{{g3M{bKnaV;u)2B@RSPio5}+CQDGr` zszN-hvKSs$Spxs7EJZY^EJJK4EJvKEtU%PLtV9f{tU^R7tVVRHtU;`)tVQIhtV0|s ztVc|$Y(RvnY(%`OY(n&^Y(}oGumw@AvK29|unqC9vK`T{vIC#ODm(GMP}zld$u4;` zm5;fN$BFFtS847rr?F4RN@fN#oaup#q9#*{$%{QZd>IqN(jW2f(cC~*aS*d&E9rUk zWc-^n{V;Lbnr?)t(-cgt7oZc7T?Elym>|v0-S(H)?6QCl%r zwhB9MFQ8^)O=co?Asm4|NPo<^_e9pw5qi-QJAyQ#>SJf_8dOz0t(!uXg>IBUx3vhK zqREHVo19c4^dpvvLB}M53Zp`hmjqCLP!ey-6O(FglnZ4;mSV>K00v5rf8~dUvQWrb zFn9rd;bayX^Fz*n&ZHxY`3|-DDt`f~@@Mb~%JUJK%?H#>@4#E|2E2Cg3jemwO9wAd zQN56#XYvd>MR@v?C(td8$5?CnPdq~J_&@QV{*LpXYrn<$m3AfSEA<-HvwH37S-B(i zsNAJ`B=@bM*g`oH+h`DLsSxX_yoWVah;3DftyMn3_A0~^Dyi^{3h|T5SNKik8@#CS z9UfIlgMU?sw^cIWeU%@G1r<9YLxDwG)}fM*WA3PIxpLjaL0M+@sOV z>7>=@G#*XgUZZ>MP`~p!d?5TyxOq4lE(jeD%?Wi1l?-KqH-c+}6+E+Z&*n0@<=*st zv-Zv1H>S5W-wu1b_3fj#_PjcI!}B)hJ;*cWSIr-gzcT-7K9dhe4@W0QKa2XJ&mub_ zqat-9j>zM1PIz>!`D5~P@_)@Y6jUzgUGQDO znF6>VoNSaFk*pZ38W&?1WAkEdV$s;^=$`1ud!(g|0Gd&3Liqww#r6{&=DL3Y|J zf+^q#FdnD{Xo1V|`SDiqQ2cppYwYWoQyf>Yt>BjeO|opVb8=?#VDeeg0#|~&!L#9m z@Do^%lttPjlaX!6EhLRtP4~g&U zl8=)HxB}b-o&oQJAHf==6w(Hnh-^l#BLosc>!5wndYUgFH*^FupgT|$ z$cyiZkBCpRc2CYr9xd#pn%c_(wU?K$1^Ec+j7&pzBKHsufzU?iU~~z34DH14g@!=o zAQapO4g)^|Dc~qD5vT*`fU9w@CntF?DJDz6ZQx084ty8Rz(tX!$Vg-jaseqoJZLqv z8~QD}6TOY5(T)@Y9fn3jRUisH0*(c%gFJ8=mkcTpORVs)`TSR@)sJcL$2?VtekEBHOw35*OpajsF zYzPm9SHTxx7!Dw{k$%WRCnjbT+yN{RL&wI93nq zi_O9AJKHDxiC>^4P%Fp_-2<0`?Z6=T7+44N07U73PweZ$i9JKLSaGZwHVj*aZ8LwJ zD4ocMwnGD;;!qyA1N;gs17g4dU^LLgFbG}_pN8{b4^kcJh0H|`Aip6BQXFlLjzm|X zXVBNE1uKWO#>QZ)v60#-iP{MPItfjHK7lgeNiZ9%4JyC|U?#B4_70`>L3G<#mG_Q1!6?Y zpl#6c=mzv6T7WvSN>~Rh8{2?s=naW46OqJk&`PKS6oejutH91+4157>0*Z(J|CwBB zrjCV~E?~P80~5s)xzHAVdfhE8suooB({5K95R1UO8$D!;0!GZPId2DQS zRN|uq4()@6LggV0+z$>1E2(>P49Eudkl(}S-~!l()I|Cq^N}BsCx{j;iGG2OLD!<^ z&^M?JtAMq|#$ju*vsm50H;Gya9y$SyhpIyycmkXV)&gbVJTL=**=6eN-okEmc0G|f z>g*n=vn%#~cBczxSN8qve!@(yIf=#zL*gPd9jXuMpbOv(un}khZvcyc((+>X1pFFy zAXSiV$V_A}@&FN#qG%Iz7`g&IiM~V)SShR}HWK?DJAvIaFHN*cxDvOZ`A{>+4&4G5 zf-ONWcpvy47-X0aA1Tz5itn}LF2W+{?tqH`jY_!U}SxP1@Q z?du3e3b${M?Z4?`6#Wz(fG$LTM1Mmiv?$gX8;mW&4q>f@t%=@=MB)Xs9_j`G&~tDD z*b^)Y<^tOR+%p~C13!cnxFpgF8ISycTtjdqh}K5?pmWjv=mRu^f>?cQ05%WXhk59| ziNT4Ii99F=>IW5r-hw&cK(I830Q-R|p?8{c59Z+y-fPOmLQSb&s42VNYf2rgH#Q5~ zh5d{jP5jM+a{tDI3Gf#97R5=~xbS z9h(xJl=xrTa+urzUxi6HiquC2BTJE!$RCIWt$=nwC!w3st0;ncv8q@X>>F$|b{T6N zn3<@b&?L@6-#~RB89WP41?z(b@G3A5AlTKa(jjn`s&xI4MXJ(0M-1xb{mJr+Xui66 zAE}!+5qrmSyK7;hS;CsQ3eAEVLni1dI0tMBI>0-?QlPy2PhC0qm#&QZ4_!Hp-7$Zk zXq)gR?m~;9mXHg&1AYg#0R!Me)wPBg7Q@HkSFjzajC4h2AbXJe2#*v|xj7VFj-Dvw zW=X6CHUe9L9mkev|5FdTfbl{-*k_vy{|G;aO-Om9BQgcqj@(8VB#t&fzd{$IN6;sz zf_{iK!G>VpVTZ9cLQbM@qG;lGXd~1e0-=}S4`46w1Mn@d6Cgc*`tJYosE6-8Y9O`% zJAirV{fYms!3Tk=p(*fA)ulw$rCK0kkoBr3Ac$Xesh;R8)uryC3>s5i>YXR-#_nLp z5~CB95(Km#8m1}>4juqUfR#ZSIIb$oM0hLwv&tw4X@U$#Rw3t*Jj8{5jDCquL${;1 zR7M4{nph9)TWmXa1DhJ1tTHO2y45(#w?-_LsMNyy1s4uZ8DxYtef$Bnv%BX27ql_w}<^!b4sEdV+s)Gzv zxp@l7MI35P-Ow4TLv9B=vLXi7-$XnfCurF@s_qm>h7*qFCAF*@mlKDwLn#-C#w6FP#HN2 zTZNs*USTG@G~N;)iO&*hstSG-90OKSz2Gn~2B->f@ssh%@p|#1o@vN#Rdpp*zgwtI zupYgH!s^~u!@8;S+M#Mm3Jc;j@b36Dd>g)(ehRKp@0755*R29N15w~vd}F+KyjZ*- zb~o#^sw8gp?&_gl75mhCNkl)uK35fYxvJeSFdbe3Z-x)Wm*7Y6M>vmXt2YV{oK*Q! z3y|aI;?v`ebz7ff zTD&;k6d$5ia~OY!XYd$No9IFG^-Th5tJR#3f2&qwQ>$4P>l6cGxzSzGQ`~=6L%gqM zD!v83qE=%k$`M}>!-*xt5=R_(5&t3HCtf0+jO~w&j(rkSqL-r!qHUwS<%jRF8Kz=$ z5_^g13$Yo7FT;=Gzu^K75Os-O#B^c{af!$^{S==PuOBzXZ^RbG+QuTWm(iT)kZ6^t z75iHS7+clnuzmDyQ z4T)8XanUo;nbGFafcj>%EmFtY5*w}FT4%9b%z~H2Tj8VeRro3VIj$j!5)Fy|#B5>* zah*sKHnKD+31aM=`qt7k=8ip#u8a1GmWie#ry?^VEh3{_^HlBm72`1wuaEb~=iz(t zyLbxEBB~LciHXEo;wR!cArl~3hwMgPWY)!c#)`*~=%MHY^?k|`y&G8_=^ZH>VZzh= zS1|^%#OOT(D{mEJ6 zHu4hriaeRMDLNopA<9P1M&?9XM`DpT;r-!>;l^QKxHHukpM&qlZ{sBHC#n*ihzZ0R z;uP_WkO+XRt@bpDTuYuLACoMZmFnsFyQeY{I(#lXFWezqG>nB#hUR28;g|3{+^TZ8 zB{588%^~7GktPCU6|yZkid;$_B=3?K=}eVLHA$7R|E|8lj)>HV7$UdBtHXW66~kia zT4+V6Pv|@O?>WsOb`m!Tn6Q&&$Y$hVavr&pyhgqyjj0b(pQgH}vQvO*N~B4|7kL)m z9v&I49kzyl4Q&n$3)K$ULnHN3q88Dem`ZFSE)cH?J^3Nofb2tlOKv95lP^h`jHha( zI;O^?mZtWnKGuSf{P2(A$>Gn#S>ZoIdqWdLO+vv?Zt%xoc}quP{Ci}?e?x{NgQ+U1 z)~R8s1*x5>E2&qhG2-d)oN(JP6ox~`LNh{bLQn_`{uG=a{4#jav79(UJR}$*L{=j^ zl4Hs5$s^da9OZ- zuu@PLtmM5%kncG&l3YR_An&O7I#Q)oeEX%oP5qEMoqC*NQoeNg^yle*X+Cr{v@Fys zR6ZmIZw6NfzY10lT7r+Wc4cK}xybTlOL8c=klaJwB$K2iRU*|e)jKsMwLWz+^)QuA zxzlCRjnlo;lhdoxVSoQn<&ZXXH@G13_j1=mo+7;b=C)2m+5y?+C^R`^GH+b z!&LoL&(!49n$)q>gA|c+rc0$8rhBHd)8D5Lrf;RYx{RUw!Og)D!FoYY@b|2PS<|!H zWfjlj0yhKg`5oj{b=HPd(NsNk){|1JQ%6(xQ+UdrE|G4K?vb9DUXebKzL|cLR?=6j zTY@8l^@G0PtE?ZhW@NR`Dv^~5+zMM{To;WwC)9f%Spm zfrf!_0P&yqgXSK8;X)ST(kR_4Jt@61eJK5NIxnrI;?&2~7t}y%8nuQ(#BZ`%WfjSy z0#^d7178Q~1pJ*o>eidsNzqs~x|D4a6W5M7OKNsslE2`K&t z{vG~r{B8ZE{EF|PZ?A8LudA<$uOd4#y)eBaeKGwa&82-*S*kJBlbS#+rFK)7sAm*S zIq47ST68;lFg=~_zUr%3kpT}3= zz2IHz9qn!DE$RJESDI=_b*IKrOQ>Dc1?nl4rW|TNHR-nWAbJ|Tir!COp`Xzy+QNX$ z8_j0l1Yc`kDWBH&#CyoQz}wGT*BkLto;x0wX&^P7T1y?KZc%S2i3-x?=tgumdNe(s z-b|mM@6c~)k@hhqnc7TSrjJzD7xEF_Yu-)XY;QYnd9T&`+H=OU+B3$}&zeJ>rGBFb z%1RfZtJAIMf%FvmdwMT@k$yrGw26r`m6*?%Zp=t#He=$Sd5?G(c?Wvyd*fclbI-HK zGuzY0Q`ZyotZ?M2m1GrG()E8-GLV_fEM>McrB;d-^K|ok z;>q%)+_&9(+;iOn+>PApxbgI2I_Ld#v`mO8$JA#!F+-T?%t~etbB_6yDPSbV%NAp+ zv+Zn)JYRVld5U->_Y?Oq_j310cPn>!x5Ev)aN#KZGyR(8X%ADJsl~Kr1~8MDB}|Um z%^l`7!!mXjVk@(a*)Hr5RxrKm=C%8rd%Zi`-Pv8uo#m!nzqk&$mbhXHMcbJoOjV{i z)0-K`EMPVM+|9clyNi)bxq4h&Snrxtm?N&{cei!?t1jvE$kK>;|=$ zi)t_VEYCVPkgLdj%C+J8aAUZc+$XMxE8~3PJmp;H{KnbSS>O4g)9g$-es&yilw<3$ z?bv~AHoHj0^e}sceaynF#Jag6TqUj{*PiRojpOEUtGQj=N$w;2QRhnMcxM-9EhpsE zI&&RY9lIQh93vea92R~GyOiC=9%pZ`&sm(+a(=EDSCwnRb>;?hleh)kdTt+ghP%VP zL91aI*e`r5t-(+v9h^&iC zsGT(UM<=Jao7__l<^;~3iDk-UYGgjobk6AX^BhARZ5&k{QHNsBwO_aIvoE(#wD+_( zw(r;0WT8s;Hc4kZF_Yl^LFyl3A2lp(*aLIdJ;}`w9C-`waUa zdn8O$j#^0aeKJa+->d!hjB9J%7B^jncA5anXZ|^nTeUXnU$HG%#qB+ zOl$dqeY<^ueWbmUy^g(@-EL3W9^1~@cGwo%%%&6Eb?yn5e-s=1k`2%+pLkhRqmxAD`gM^EK7Sy|i7i?X|72O}6#3 zwXl6`18pW7ZvD-A!TM*0e*co;?7w92^F`DQwfN8Z4tyVeIKSBPu7+l|%C@-8U_-4B zt>>&et;?*Ftplv1g;|AN9Lk)}+{rx8z!^Sc=Ck+@_=%!6TYJ1kaewfrgfOLv$cV>yftjqTQSRH%Vo;}%Xr10q5$#b zR1})L?_n}OkN=+E!XMy&;;-?)@_+Cs&+!JqBh=KjuvW7cRV!dEuPi@XPFS{DzOziS z479Yj)X_HJTk+lb!TflBCcl*5$nWNl^OyL${Byp5r+Ka55W>O-LIt6Q&`21f$+z6M zoU!b(tguY846$^!G`3W-Ko*B3V}7Zd&M)TI@jLk=g&jQQ^Y}Ec@OB|66cx$|p9l?w zFN7{aKVi6#EnJhowG6X-Y5B}j*^;n0Exb9;{J?zPyx+Xu+{y3`fxqKJYJ7P$zLC&M z_)_REj1VRXvxOzXIw40mC^V4(i_OBCbIte6XUu!dYs|CFW6XWcZOosVcN%qqQ-}z~ zgpY(;LKC5_&|UaS7%fZ@<_Rl=jlwSBuy97WF5DNM3wZ(|95-(>FEdXw4>NZ&H#2`? zE@=*#O=jAZYkFY%RA?b|68Z>3g$cq8VX?4A*e2{3P6(HT+rn?cD*+K0K_gm4zX*uM zMZ{RoT)_;O9cIClG(9$5HytY{rk$qMrn#mGrmsw$O-)TTOl3@QQwRB<(LOOQ z785Io)x}T6W@0(r8cP}DMz>LCqz(Cor-nO*3x=bHU4|XHo8o=(nV2gg zA|;BVL9$DJDJB(_N=Y9{)up=9XHrY4z0_6eBYh?HkY5))8}=AB8kQMm8?p_< z4Sfxr3@r>_>i;jYv>N$|R8NikLh2xOlln@7rIFHjX^J#US|BZxR!cufInp@8U_(zs zJ3|vgZ9^qPaYM}DF&GVkp3uM1H<#Ku8_J){E# zd5645J}4iN0nOLCzPfI@_PUn3#=5$?>bi=$Qo5qLm@Z3qR}X zrLEFI>8x~Bs%bycmerQf7S#gUu-312X>D4g`j-b$!)pHgMh~U8(oY$v3|59JBa~6f zSY?8et$d?QQ@&MZDRY$h%0lHkWvQ}5b5nCgb3t=Pb5e6eb5OHavs1H8vq`f-vqp1F zS*@&7HY%HxElQ5EL)oqDRrV`~l*7tV<+yTE`AIpWoKr3;mz68ZHKm@WucoJ_o2Ij- zgQkt<3r%y)=bFZv`kK0$S{hP$qC8VxD8DPOlw9SllCLBcSV0wBA(fOuDU8A@8HHCw NMOG9={riUI{{jD`&l3Ou diff --git a/assets/sounds/push.wav b/assets/sounds/push.wav new file mode 100644 index 0000000000000000000000000000000000000000..09b370de2ba4ea683e04766549d460b8257b50b3 GIT binary patch literal 25340 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 tile-width) (inexact->exact tile-height))) -(define audio:bump (make-audio "assets/sounds/bump.wav")) +(define* (load-sound-effect name #:key (volume 0.5)) + (let ((audio (make-audio (string-append "assets/sounds/" name ".wav")))) + (set-media-volume! audio volume) + audio)) +(define audio:bump (load-sound-effect "bump")) +(define audio:push (load-sound-effect "push")) +(define audio:undo (load-sound-effect "undo")) +(define audio:no (load-sound-effect "no")) ;; Game state (define *actormap* (make-whactormap)) @@ -64,6 +73,8 @@ (define *level* #f) ;; Latest representation of all actors in level (define *grid* #f) +;; Background tile layer. +(define *background* #f) (define *snapshots* '()) (define (clear-snapshots!) @@ -72,10 +83,11 @@ (set! *snapshots* (cons (copy-whactormap *actormap*) *snapshots*))) (define (rollback-snapshot!) (match *snapshots* - (() #f) + (() (media-play audio:no)) ((snapshot . older-snapshots) (set! *actormap* snapshot) - (set! *snapshots* older-snapshots)))) + (set! *snapshots* older-snapshots) + (media-play audio:undo)))) (define (update-grid!) (set! *grid* ($ *level* 'describe))) @@ -84,7 +96,10 @@ (set! *actormap* (make-whactormap)) (clear-snapshots!) (with-goblins - (set! *level* (spawn ^level level-width level-height)) + (call-with-values load-level-1 + (lambda (background level) + (set! *background* background) + (set! *level* level))) (update-grid!))) ;; Update loop @@ -92,7 +107,8 @@ (save-snapshot!) (with-goblins (match ($ *level* 'move-player dir) - (#f (media-play audio:bump)) + ('bump (media-play audio:bump)) + ('push (media-play audio:push)) (_ #f)) (update-grid!))) @@ -154,7 +170,19 @@ (('block type) (draw-block type x y)) (('clock-emitter) (draw-clock-emitter x y)))))) +(define (draw-background) + (let* ((bv *background*) + (len (bytevector-length bv))) + (let lp ((i 0)) + (when (< i len) + (let ((x (bytevector-ieee-single-native-ref bv i)) + (y (bytevector-ieee-single-native-ref bv (+ i 4))) + (idx (bytevector-s16-native-ref bv (+ i 8)))) + (draw-tile context tileset idx x y) + (lp (+ i 10))))))) + (define (draw-level) + (draw-background) (let ((grid *grid*)) (let y-loop ((y 0)) (when (< y level-height) @@ -166,8 +194,6 @@ (define (draw prev-time) (clear-rect context 0.0 0.0 *canvas-width* *canvas-height*) - (set-fill-color! context "#cbdbfc") - (fill-rect context 0.0 0.0 *canvas-width* *canvas-height*) (set-transform! context 1.0 0.0 0.0 1.0 0.0 0.0) (set-scale! context *canvas-scale* *canvas-scale*) (draw-level) diff --git a/modules/game/actors.scm b/modules/game/actors.scm index 490dd05..4a7b3d9 100644 --- a/modules/game/actors.scm +++ b/modules/game/actors.scm @@ -29,7 +29,7 @@ (('set-wire-state type) (bcom (^wall bcom type))) (('describe) `(wall ,type)) - (('collide) 'stop))) + (('collide) 'bump))) (define (^block bcom type) (match-lambda* @@ -42,7 +42,7 @@ (('set-wire-state type) (bcom (^block bcom type))) (('describe) `(block ,type)) - (('collide) 'displace))) + (('collide) 'push))) (define (^clock-emitter bcom interval) (define timer (spawn ^cell 0)) @@ -59,7 +59,7 @@ 'copper)))) (('set-wire-state type) #f) (('describe) '(clock-emitter)) - (('collide) 'stop))) + (('collide) 'bump))) (define (^player bcom) (match-lambda* @@ -106,9 +106,9 @@ ($ player-coords (vector x y))) (occupant (match ($ occupant 'collide) - ('stop #f) + ('bump 'bump) ('goal (pk 'GOAL)) - ('displace + ('push (let ((next-cell (grid-ref grid (wrap-x (+ x dx)) (wrap-y (+ y dy))))) (match ($ next-cell) (#f @@ -116,7 +116,7 @@ ($ cell player) ($ old-cell #f) ($ player-coords (vector x y)) - 'displace) + 'push) (_ #f))))))))))) (define (warp-player x y) ($ (grid-ref grid x y) player) @@ -182,7 +182,7 @@ ($ (grid-ref grid 4 3) (spawn ^clock-emitter 3)) ($ (grid-ref grid 5 3) (spawn ^wall 'copper)) - ($ (grid-ref grid 6 4) (spawn ^block 'copper)) + ($ (grid-ref grid 6 5) (spawn ^block 'copper)) ($ (grid-ref grid 7 3) (spawn ^wall 'copper)) ($ (grid-ref grid 8 3) (spawn ^wall 'copper)) ($ (grid-ref grid 9 3) (spawn ^wall 'copper)) diff --git a/modules/game/levels/level-1.tmx b/modules/game/levels/level-1.tmx new file mode 100644 index 0000000..3564841 --- /dev/null +++ b/modules/game/levels/level-1.tmx @@ -0,0 +1,23 @@ + + + + + +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24 + + + diff --git a/modules/game/levels/tiles.tsx b/modules/game/levels/tiles.tsx new file mode 100644 index 0000000..c0e26a3 --- /dev/null +++ b/modules/game/levels/tiles.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/scripts/compile-map.scm b/scripts/compile-map.scm new file mode 100644 index 0000000..2aee8be --- /dev/null +++ b/scripts/compile-map.scm @@ -0,0 +1,588 @@ +;;; Adapted from the Chickadee Game Toolkit +;;; Copyright © 2018, 2020, 2021, 2023 David Thompson +;;; +;;; Licensed under the Apache License, Version 2.0 (the "License"); +;;; you may not use this file except in compliance with the License. +;;; You may obtain a copy of the License at +;;; +;;; http://www.apache.org/licenses/LICENSE-2.0 +;;; +;;; Unless required by applicable law or agreed to in writing, software +;;; distributed under the License is distributed on an "AS IS" BASIS, +;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;;; See the License for the specific language governing permissions and +;;; limitations under the License. + +(use-modules (ice-9 match) + (ice-9 pretty-print) + ((rnrs base) #:select (mod)) + (rnrs bytevectors) + (srfi srfi-1) + (srfi srfi-11) + (srfi srfi-9) + (srfi srfi-43) + (sxml simple) + (sxml xpath)) + +(define-record-type + (make-vec2 x y) + vec2? + (x vec2-x) + (y vec2-y)) + +(define-record-type + (make-rect x y width height) + rect? + (x rect-x) + (y rect-y) + (width rect-width) + (height rect-height)) + +(define-record-type + (make-color r g b a) + color? + (r color-r) + (g color-g) + (b color-b) + (a color-a)) + +(define-record-type + (make-image src width height trans) + image? + (src image-src) + (width image-width) + (height image-height) + (trans image-trans)) + + +;;; +;;; Tileset +;;; + +(define-record-type + (make-animation-frame id duration) + animation-frame? + (id animation-frame-id) + (duration animation-frame-duration)) + +(define-record-type + (%make-animation frames duration) + animation? + (frames animation-frames) + (duration animation-duration)) + +(define (make-animation atlas first-gid frame-spec) + (let ((frames (map (match-lambda + ((id duration) + (make-animation-frame (- id first-gid) duration))) + frame-spec))) + (%make-animation (list->vector frames) + (fold (lambda (frame memo) + (+ (animation-frame-duration frame) memo)) + 0 frames)))) + +(define (animation-frame-for-time animation time) + (let* ((time (mod time (animation-duration animation))) + (frames (animation-frames animation))) + (let loop ((i 0) + (t 0)) + (let* ((frame (vector-ref frames i)) + (d (animation-frame-duration frame))) + (if (< time (+ t d)) + frame + (loop (+ i 1) (+ t d))))))) + +(define-record-type + (make-tile id image animation properties) + tile? + (id tile-id) + (image tile-image) + (animation tile-animation) + (properties tile-properties)) + +(define (animated-tile? tile) + (animation? (tile-animation tile))) + +(define (tile-frame-for-time tile time) + (let ((animation (tile-animation tile))) + (and animation (animation-frame-for-time animation time)))) + +(define-record-type + (%make-tileset name first-gid tile-width tile-height + margin spacing rows columns tiles properties) + tileset? + (name tileset-name) + (first-gid tileset-first-gid) + (tile-width tileset-tile-width) + (tile-height tileset-tile-height) + (margin tileset-margin) + (spacing tileset-spacing) + (rows tileset-rows) + (columns tileset-columns) + (tiles tileset-tiles) + (properties tileset-properties)) + +(define (tileset-dimensions image tile-width tile-height margin spacing) + (values (inexact->exact + (ceiling (/ (- (image-width image) margin) + (+ tile-width spacing)))) + (inexact->exact + (ceiling (/ (- (image-height image) margin) + (+ tile-height spacing)))))) + +(define* (make-tileset image tile-width tile-height #:key + (first-gid 1) (margin 0) (spacing 0) + (name "anonymous") (properties '()) + (custom-tiles '())) + (let-values (((columns rows) + (tileset-dimensions image tile-width tile-height margin spacing))) + (let* ((tiles (make-vector (* columns rows)))) + (do ((i 0 (+ i 1))) + ((= i (vector-length tiles))) + (let* ((id (+ first-gid i)) + (custom (or (assv-ref custom-tiles id) '())) + (animation (assq-ref custom 'animation)) + (properties (assq-ref custom 'properties)) + (tile (make-tile id i + (and animation + (make-animation image first-gid animation)) + (or properties '())))) + (vector-set! tiles i tile))) + (%make-tileset name first-gid tile-width tile-height margin spacing + rows columns tiles properties)))) + +(define (tileset-size tileset) + (vector-length (tileset-tiles tileset))) + +(define (tileset-ref tileset i) + (vector-ref (tileset-tiles tileset) (- i (tileset-first-gid tileset)))) + + +;;; +;;; Object Layer +;;; + +(define-record-type + (%make-object-layer name objects properties) + object-layer? + (name object-layer-name) + (objects object-layer-objects) + (properties object-layer-properties)) + +(define-record-type + (make-polygon points) + polygon? + (points polygon-points)) + +(define-record-type + (%make-map-object id name type shape properties) + map-object? + (id map-object-id) + (name map-object-name) + (type map-object-type) + (shape map-object-shape) + (properties map-object-properties)) + + +;;; +;;; Tile Layer +;;; + +(define-record-type + (%make-map-tile tile flipped-horizontally? flipped-vertically? + flipped-diagonally?) + map-tile? + (tile map-tile-ref) + (flipped-horizontally? map-tile-flipped-horizontally?) + (flipped-vertically? map-tile-flipped-vertically?) + (flipped-diagonally? map-tile-flipped-diagonally?)) + +(define* (make-map-tile tile #:key flipped-horizontally? + flipped-vertically? flipped-diagonally?) + (%make-map-tile tile flipped-horizontally? flipped-vertically? + flipped-diagonally?)) + +(define-record-type + (%make-tile-layer name width height properties tiles) + tile-layer? + (name tile-layer-name) + (width tile-layer-width) + (height tile-layer-height) + (properties tile-layer-properties) + (tiles tile-layer-tiles)) + +(define* (make-tile-layer width height tile-width tile-height #:key + (name "anonymous") + (properties '())) + (%make-tile-layer name width height properties (make-vector (* width height)))) + +(define (tile-layer-bounds-check layer x y) + (unless (and (>= x 0) (>= y 0) + (< x (tile-layer-width layer)) + (< y (tile-layer-height layer))) + (error "tile layer coordinates out of bounds" layer x y))) + +(define (tile-layer-ref layer x y) + (vector-ref (tile-layer-tiles layer) (+ (* y (tile-layer-width layer)) x))) + +(define (tile-layer-set! layer x y tile) + (vector-set! (tile-layer-tiles layer) (+ (* y (tile-layer-width layer)) x) tile)) + + +;;; +;;; Tile Map +;;; + +(define-record-type + (%make-tile-map orientation width height tile-width tile-height + tilesets layers properties) + tile-map? + (orientation tile-map-orientation) + (width tile-map-width) + (height tile-map-height) + (tile-width tile-map-tile-width) + (tile-height tile-map-tile-height) + (tilesets tile-map-tilesets) + (layers tile-map-layers) + (properties tile-map-properties)) + +(define* (make-tile-map width height tile-width tile-height #:key + (orientation 'orthogonal) (tilesets '()) + (layers '()) (properties '())) + "Make a tile map that is WIDTH x HEIGHT tiles in size and each tile +is TILE-WIDTH x TILE-HEIGHT pixels in size. TILESETS is a list of +tilesets to be associated with the map. LAYERS is a list of object +and/or tile layers, sorted from bottom to top. PROPERTIES is an alist +of arbitrary custom data to associate with the map. Currently, only +the default ORIENTATION value of 'orthogonal' is supported." + (unless (eq? orientation 'orthogonal) + (error "unsupport tile map orientation" orientation)) + (%make-tile-map orientation width height tile-width tile-height + tilesets (list->vector layers) properties)) + +(define (tile-map-layer-ref tile-map name) + "Return the map layer named NAME." + (define (layer-name layer) + (if (tile-layer? layer) + (tile-layer-name layer) + (object-layer-name layer))) + (let ((layers (tile-map-layers tile-map))) + (let loop ((i 0)) + (cond + ((= i (vector-length layers)) + #f) + ((string=? name (layer-name (vector-ref layers i))) + (vector-ref layers i)) + (else + (loop (+ i 1))))))) + +(define (point->tile tile-map x y) + "Translate the pixel coordinates (X, Y) into tile coordinates." + (values (inexact->exact (floor (/ x (tile-map-tile-width tile-map)))) + (inexact->exact (floor (/ y (tile-map-tile-height tile-map)))))) + +(define* (load-tile-map file-name) + "Load the Tiled TMX formatted map in FILE-NAME." + (define map-directory + (if (absolute-file-name? file-name) + (dirname file-name) + (string-append (getcwd) "/" (dirname file-name)))) + (define (scope file-name) + (string-append map-directory "/" file-name)) + (define* (attr node name #:optional (parse identity)) + (let ((result ((sxpath `(@ ,name *text*)) node))) + (if (null? result) + #f + (parse (car result))))) + (define (parse-color-channel s start) + (/ (string->number (substring s start (+ start 2)) 16) 255.0)) + (define (parse-property node) + (let ((name (attr node 'name string->symbol)) + (type (or (attr node 'type string->symbol) 'string)) + (value (attr node 'value))) + (cons name + (match type + ((or 'string 'file) value) + ('bool (not (string=? value "false"))) + ((or 'int 'float) (string->number value)) + ('color + (make-color (parse-color-channel value 3) + (parse-color-channel value 5) + (parse-color-channel value 7) + (parse-color-channel value 1))) + (_ (error "unsupported property type" type)))))) + (define (parse-image node) + (let ((source (attr node 'source)) + (width (string->number (attr node 'width))) + (height (string->number (attr node 'height))) + (trans (attr node 'trans))) + (make-image (scope source) width height trans))) + (define (invert-tile-id id first-gid rows columns) + (let ((id* (- id first-gid))) + (+ (* (- rows (floor (/ id* columns)) 1) + columns) + (modulo id* columns) + first-gid))) + (define (parse-frame node first-gid rows columns) + (let ((tile-id (attr node 'tileid string->number)) + (duration (attr node 'duration string->number))) + (list (+ first-gid tile-id ;; (invert-tile-id tile-id 0 rows columns) + ) + (/ duration 1000.0)))) + (define (parse-tiles nodes first-gid rows columns) + (let ((frames (sxpath '(animation frame))) + (properties (sxpath '(properties property)))) + (fold (lambda (node memo) + (let ((id (+ first-gid (attr node 'id string->number) + ;; (invert-tile-id (attr node 'id string->number) + ;; 0 rows columns) + ))) + (cons `(,id . ((animation . ,(map (lambda (f) + (parse-frame f first-gid + rows columns)) + (frames node))) + (properties . ,(map parse-property + (properties node))))) + memo))) + '() + nodes))) + (define (first-gid node) + (attr node 'firstgid string->number)) + (define (parse-tileset node first-gid) + (let* ((name (attr node 'name)) + (tile-width (attr node 'tilewidth string->number)) + (tile-height (attr node 'tileheight string->number)) + (margin (or (attr node 'margin string->number) 0)) + (spacing (or (attr node 'spacing string->number) 0)) + (image (parse-image ((sxpath '(image)) node))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (make-tileset image tile-width tile-height + #:margin margin + #:spacing spacing + #:name name + #:first-gid first-gid + #:properties properties + #:custom-tiles '()))) + (define (parse-external-tileset node) + (let* ((first-gid (attr node 'firstgid string->number)) + (source (scope (attr node 'source))) + (tree (call-with-input-file source xml->sxml))) + (parse-tileset (car ((sxpath '(tileset)) tree)) first-gid))) + (define (parse-tileset* node) + (if (attr node 'source) + (parse-external-tileset node) + (parse-tileset node (first-gid node)))) + (define (tile-gid->map-tile raw-gid tilesets x y tile-width tile-height) + ;; The top 3 bits of the tile gid are flags for various types of + ;; flipping. + (let* ((flipped-horizontally? (> (logand raw-gid #x80000000) 0)) + (flipped-vertically? (> (logand raw-gid #x40000000) 0)) + (flipped-diagonally? (> (logand raw-gid #x20000000) 0)) + ;; Remove the upper 3 bits to get the true tile id. + (gid (logand raw-gid #x1FFFFFFF)) + (tileset (find (lambda (t) + (and (>= gid (tileset-first-gid t)) + (< gid (+ (tileset-first-gid t) + (tileset-size t))))) + tilesets)) + (tw (tileset-tile-width tileset)) + (th (tileset-tile-height tileset)) + (first-gid (tileset-first-gid tileset)) + (rows (tileset-rows tileset)) + (columns (tileset-columns tileset)) + (id (- gid first-gid) ;; (invert-tile-id gid first-gid rows columns) + )) + (make-map-tile (tileset-ref tileset id) + #:flipped-horizontally? flipped-horizontally? + #:flipped-vertically? flipped-vertically? + #:flipped-diagonally? flipped-diagonally?))) + (define (tile-gids->map-tiles gids width height tilesets) + (let ((tiles (make-vector (* width height)))) + (let y-loop ((y 0) + (rows gids)) + (when (< y height) + (match rows + ((row . rest) + (let x-loop ((x 0) + (columns row)) + (when (< x width) + (match columns + ((gid . rest) + (vector-set! tiles + (+ (* width y) x) + (if (zero? gid) + #f + (tile-gid->map-tile gid tilesets + x y width height))) + (x-loop (+ x 1) rest))))) + (y-loop (+ y 1) rest))))) + tiles)) + (define (parse-csv lines width height tilesets) + (let ((gids (map (lambda (line) + (filter-map (lambda (s) + (and (not (string-null? s)) + (string->number s))) + (string-split line #\,))) + (take (drop (string-split lines #\newline) 1) height)))) + (tile-gids->map-tiles gids width height tilesets))) + (define (parse-layer-data node width height tilesets) + (let ((encoding (attr node 'encoding string->symbol)) + (data (car ((sxpath '(*text*)) node)))) + (match encoding + ('csv (parse-csv data width height tilesets)) + (_ (error "unsupported tile layer encoding" encoding))))) + (define (parse-tile-layer node tile-width tile-height tilesets) + (let* ((name (attr node 'name)) + (width (attr node 'width string->number)) + (height (attr node 'height string->number)) + (tiles (parse-layer-data ((sxpath '(data)) node) + width height tilesets)) + (properties (map parse-property + ((sxpath '(properties property)) node))) + (layer (make-tile-layer width height tile-width tile-height + #:name name + #:properties properties))) + (do ((y 0 (+ y 1))) + ((= y height)) + (do ((x 0 (+ x 1))) + ((= x width)) + (tile-layer-set! layer x y (vector-ref tiles (+ (* y width) x))))) + layer)) + (define (parse-polygon node pixel-height) + (make-polygon + (list->vector + (map (lambda (s) + (match (string-split s #\,) + ((x y) + (make-vec2 (string->number x) (string->number y))))) + (string-split (attr node 'points) #\space))))) + (define (parse-object node pixel-height) + (let* ((id (attr node 'id string->number)) + (name (attr node 'name)) + (type (attr node 'type string->symbol)) + (x (attr node 'x string->number)) + (y (attr node 'y string->number)) + (width (attr node 'width string->number)) + (height (attr node 'height string->number)) + (shape (if (and width height) + (make-rect x y width height) + (parse-polygon (car ((sxpath '(polygon)) node)) + pixel-height))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (%make-map-object id name type shape properties))) + (define (parse-object-layer node pixel-height) + (let ((name (attr node 'name)) + (objects (map (lambda (node) + (parse-object node pixel-height)) + ((sxpath '(object)) node))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (%make-object-layer name objects properties))) + (let* ((tree (call-with-input-file file-name xml->sxml)) + (m ((sxpath '(map)) tree)) + (version (attr m 'version)) + (orientation (attr m 'orientation string->symbol)) + (width (attr m 'width string->number)) + (height (attr m 'height string->number)) + (tile-width (attr m 'tilewidth string->number)) + (tile-height (attr m 'tileheight string->number)) + (properties ((sxpath '(map properties property)) tree)) + (tilesets (map parse-tileset* ((sxpath '(map tileset)) tree))) + (layers ((node-or (sxpath '(map layer)) + (sxpath '(map objectgroup))) + tree))) + (make-tile-map width height tile-width tile-height + #:orientation orientation + #:tilesets tilesets + #:layers (map (lambda (node) + (match node + (('layer . _) + (parse-tile-layer node tile-width tile-height tilesets)) + (('objectgroup . _) + (parse-object-layer node (* height tile-height))))) + layers) + #:properties (map parse-property properties)))) + +(define (bytevector-concat bvs) + (let* ((size (fold (lambda (bv sum) + (+ sum (bytevector-length bv))) + 0 bvs)) + (new-bv (make-bytevector size))) + (let loop ((bvs bvs) (offset 0)) + (match bvs + (() new-bv) + ((bv . rest) + (let ((len (bytevector-length bv))) + (bytevector-copy! bv 0 new-bv offset len) + (loop rest (+ offset len)))))))) + +(define (compile-tile-layer tile-map layer-name) + (let ((tw (tile-map-tile-width tile-map)) + (th (tile-map-tile-height tile-map)) + (layer (tile-map-layer-ref tile-map layer-name))) + (bytevector-concat + (append-map (lambda (y) + (filter-map (lambda (x) + (let ((tile (tile-layer-ref layer x y))) + (and tile + (let ((bv (make-bytevector 10))) + (bytevector-ieee-single-native-set! bv 0 (* x tw)) + (bytevector-ieee-single-native-set! bv 4 (* y th)) + (bytevector-s16-native-set! bv 8 (tile-id (map-tile-ref tile))) + bv)))) + (iota (tile-layer-width layer)))) + (iota (tile-layer-height layer)))))) + +(define (compile-collision-layer layer) + (u8-list->bytevector + (append-map (lambda (y) + (map (lambda (x) + (if (tile-layer-ref layer x y) 1 0)) + (iota (tile-layer-width layer)))) + (iota (tile-layer-height layer))))) + +(define (compile-object-layer tile-map layer) + (let ((table (make-hash-table)) + (tw (tile-map-tile-width tile-map)) + (th (tile-map-tile-height tile-map))) + (for-each (lambda (obj) + (let* ((type (map-object-type obj)) + (properties (map-object-properties obj)) + (r (map-object-shape obj)) + (x (/ (rect-x r) tw)) + (y (/ (rect-y r) th))) + ;; (format (current-error-port) "obj: ~a ~a ~a ~a\n" (rect-x r) (rect-y r) x y) + (hashv-set! table y + (cons `(make-level-object ,x (quote ,type) + (quote ,properties)) + (hashv-ref table y '()))))) + (object-layer-objects layer)) + `(vector + ,@(map (lambda (y) + `(list ,@(hashv-ref table y '()))) + (iota (tile-map-height tile-map)))))) + +(define (basename-strip-extension file-name) + (match (string-split (basename file-name) #\.) + ((base . _) base))) + +(match (command-line) + ((_ file-name) + (let* ((name (basename-strip-extension file-name)) + (module-name `(game levels ,(string->symbol name))) + (proc-name (string->symbol (string-append "load-" name))) + (tile-map (load-tile-map file-name))) + (for-each pretty-print + `((define-module ,module-name + #:use-module (game actors) + #:use-module (goblins core) + #:use-module (math vector) + #:export (,proc-name)) + (define (,proc-name) + (values ,(compile-tile-layer tile-map "background") + (spawn ^level + ,(tile-map-width tile-map) + ,(tile-map-height tile-map)))))))) + (_ (error "file name expected")))