From 39c31f004222fae5033b4affce4d4daedf584c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Ryb=C3=A1rsky?= Date: Tue, 10 Jun 2025 21:59:51 +0200 Subject: [PATCH] Most texure work --- CMakeLists.txt | 2 + assets/items/08-iron_bullet-00.png | Bin 0 -> 614 bytes assets/items/10-gold_bullet-00.png | Bin 0 -> 464 bytes assets/items/11-platinum_bullet-00.png | Bin 0 -> 662 bytes assets/items/{08-log-00.png => 12-log-00.png} | Bin assets/tiles/04_miner_00.png | Bin 489 -> 528 bytes assets/tiles/04_miner_01.png | Bin 492 -> 541 bytes assets/tiles/04_miner_02.png | Bin 486 -> 530 bytes assets/tiles/04_miner_03.png | Bin 487 -> 539 bytes assets/tiles/04_miner_04.png | Bin 485 -> 574 bytes assets/tiles/04_miner_05.png | Bin 487 -> 565 bytes assets/tiles/04_miner_06.png | Bin 483 -> 586 bytes assets/tiles/04_miner_07.png | Bin 481 -> 583 bytes assets/tiles/04_miner_08.png | Bin 0 -> 592 bytes assets/tiles/04_miner_09.png | Bin 0 -> 592 bytes assets/tiles/04_miner_10.png | Bin 0 -> 572 bytes assets/tiles/05_turret_00.png | Bin 239 -> 393 bytes assets/tiles/05_turret_01.png | Bin 261 -> 415 bytes assets/tiles/05_turret_02.png | Bin 256 -> 417 bytes assets/tiles/05_turret_03.png | Bin 265 -> 415 bytes assets/tiles/05_turret_04.png | Bin 252 -> 415 bytes assets/tiles/05_turret_05.png | Bin 0 -> 393 bytes assets/tiles/05_turret_06.png | Bin 0 -> 414 bytes assets/tiles/05_turret_07.png | Bin 0 -> 415 bytes assets/tiles/05_turret_08.png | Bin 0 -> 415 bytes assets/tiles/05_turret_09.png | Bin 0 -> 419 bytes assets/tiles/05_turret_10.png | Bin 0 -> 390 bytes assets/tiles/05_turret_11.png | Bin 0 -> 411 bytes assets/tiles/05_turret_12.png | Bin 0 -> 412 bytes assets/tiles/05_turret_13.png | Bin 0 -> 410 bytes assets/tiles/05_turret_14.png | Bin 0 -> 411 bytes assets/tiles/05_turret_15.png | Bin 0 -> 391 bytes assets/tiles/05_turret_16.png | Bin 0 -> 391 bytes assets/tiles/05_turret_17.png | Bin 0 -> 417 bytes assets/tiles/05_turret_18.png | Bin 0 -> 418 bytes assets/tiles/05_turret_19.png | Bin 0 -> 413 bytes assets/tiles/05_turret_20.png | Bin 0 -> 414 bytes assets/tiles/05_turret_21.png | Bin 0 -> 423 bytes assets/tiles/05_turret_22.png | Bin 0 -> 420 bytes assets/tiles/05_turret_23.png | Bin 0 -> 419 bytes assets/tiles/05_turret_24.png | Bin 0 -> 421 bytes assets/tiles/05_turret_25.png | Bin 0 -> 432 bytes assets/tiles/05_turret_26.png | Bin 0 -> 428 bytes assets/tiles/05_turret_27.png | Bin 0 -> 420 bytes assets/tiles/05_turret_28.png | Bin 0 -> 410 bytes assets/tiles/05_turret_29.png | Bin 0 -> 419 bytes assets/tiles/05_turret_30.png | Bin 0 -> 413 bytes assets/tiles/05_turret_31.png | Bin 0 -> 417 bytes assets/tiles/05_turret_32.png | Bin 0 -> 416 bytes assets/tiles/05_turret_33.png | Bin 0 -> 417 bytes assets/tiles/05_turret_34.png | Bin 0 -> 426 bytes assets/tiles/05_turret_35.png | Bin 0 -> 427 bytes assets/tiles/05_turret_36.png | Bin 0 -> 408 bytes assets/tiles/05_turret_37.png | Bin 0 -> 392 bytes assets/tiles/05_turret_38.png | Bin 0 -> 391 bytes assets/tiles/05_turret_39.png | Bin 0 -> 389 bytes assets/tiles/05_turret_40.png | Bin 0 -> 391 bytes assets/tiles/05_turret_41.png | Bin 0 -> 389 bytes assets/tiles/06_splitter_00.png | Bin 0 -> 408 bytes assets/tiles/06_splitter_01.png | Bin 0 -> 422 bytes assets/tiles/06_splitter_02.png | Bin 0 -> 426 bytes assets/tiles/06_splitter_03.png | Bin 0 -> 418 bytes assets/tiles/06_splitter_04.png | Bin 0 -> 425 bytes assets/tiles/12_core_00.png | Bin 0 -> 763 bytes assets/tiles/12_core_01.png | Bin 0 -> 777 bytes assets/tiles/12_core_02.png | Bin 0 -> 785 bytes assets/tiles/12_core_03.png | Bin 0 -> 780 bytes assets/tiles/12_core_04.png | Bin 0 -> 780 bytes assets/tiles/12_core_05.png | Bin 0 -> 839 bytes assets/tiles/12_core_06.png | Bin 0 -> 846 bytes assets/tiles/12_core_07.png | Bin 0 -> 853 bytes assets/tiles/12_core_08.png | Bin 0 -> 841 bytes assets/tiles/12_core_09.png | Bin 0 -> 799 bytes assets/tiles/12_core_10.png | Bin 0 -> 801 bytes assets/tiles/12_core_11.png | Bin 0 -> 772 bytes assets/tiles/12_core_12.png | Bin 0 -> 777 bytes assets/tiles/12_core_13.png | Bin 0 -> 785 bytes assets/tiles/12_core_14.png | Bin 0 -> 780 bytes assets/tiles/12_core_15.png | Bin 0 -> 839 bytes assets/tiles/12_core_16.png | Bin 0 -> 846 bytes assets/tiles/12_core_17.png | Bin 0 -> 853 bytes assets/tiles/12_core_18.png | Bin 0 -> 799 bytes assets/tiles/12_core_19.png | Bin 0 -> 801 bytes assets/tiles/12_core_20.png | Bin 0 -> 772 bytes entity/entity.c | 45 +++- entity/entity.h | 6 +- items/item.c | 216 +++++++++++++----- items/item.h | 8 +- main.c | 51 ++++- player/player.c | 91 ++++++-- tiles/belt.c | 14 +- tiles/furnace.c | 62 +---- tiles/furnace.h | 9 +- tiles/miner.h | 2 - tiles/tile.c | 61 +++-- tiles/tile.h | 10 +- tiles/turret.c | 111 ++++++--- util/crafter.c | 97 ++++++++ util/crafter.h | 37 +++ util/font.c | 72 +++--- util/font.h | 13 +- util/util.c | 2 +- util/util.h | 3 +- 103 files changed, 666 insertions(+), 246 deletions(-) create mode 100644 assets/items/08-iron_bullet-00.png create mode 100644 assets/items/10-gold_bullet-00.png create mode 100644 assets/items/11-platinum_bullet-00.png rename assets/items/{08-log-00.png => 12-log-00.png} (100%) create mode 100644 assets/tiles/04_miner_08.png create mode 100644 assets/tiles/04_miner_09.png create mode 100644 assets/tiles/04_miner_10.png create mode 100644 assets/tiles/05_turret_05.png create mode 100644 assets/tiles/05_turret_06.png create mode 100644 assets/tiles/05_turret_07.png create mode 100644 assets/tiles/05_turret_08.png create mode 100644 assets/tiles/05_turret_09.png create mode 100644 assets/tiles/05_turret_10.png create mode 100644 assets/tiles/05_turret_11.png create mode 100644 assets/tiles/05_turret_12.png create mode 100644 assets/tiles/05_turret_13.png create mode 100644 assets/tiles/05_turret_14.png create mode 100644 assets/tiles/05_turret_15.png create mode 100644 assets/tiles/05_turret_16.png create mode 100644 assets/tiles/05_turret_17.png create mode 100644 assets/tiles/05_turret_18.png create mode 100644 assets/tiles/05_turret_19.png create mode 100644 assets/tiles/05_turret_20.png create mode 100644 assets/tiles/05_turret_21.png create mode 100644 assets/tiles/05_turret_22.png create mode 100644 assets/tiles/05_turret_23.png create mode 100644 assets/tiles/05_turret_24.png create mode 100644 assets/tiles/05_turret_25.png create mode 100644 assets/tiles/05_turret_26.png create mode 100644 assets/tiles/05_turret_27.png create mode 100644 assets/tiles/05_turret_28.png create mode 100644 assets/tiles/05_turret_29.png create mode 100644 assets/tiles/05_turret_30.png create mode 100644 assets/tiles/05_turret_31.png create mode 100644 assets/tiles/05_turret_32.png create mode 100644 assets/tiles/05_turret_33.png create mode 100644 assets/tiles/05_turret_34.png create mode 100644 assets/tiles/05_turret_35.png create mode 100644 assets/tiles/05_turret_36.png create mode 100644 assets/tiles/05_turret_37.png create mode 100644 assets/tiles/05_turret_38.png create mode 100644 assets/tiles/05_turret_39.png create mode 100644 assets/tiles/05_turret_40.png create mode 100644 assets/tiles/05_turret_41.png create mode 100644 assets/tiles/06_splitter_00.png create mode 100644 assets/tiles/06_splitter_01.png create mode 100644 assets/tiles/06_splitter_02.png create mode 100644 assets/tiles/06_splitter_03.png create mode 100644 assets/tiles/06_splitter_04.png create mode 100644 assets/tiles/12_core_00.png create mode 100644 assets/tiles/12_core_01.png create mode 100644 assets/tiles/12_core_02.png create mode 100644 assets/tiles/12_core_03.png create mode 100644 assets/tiles/12_core_04.png create mode 100644 assets/tiles/12_core_05.png create mode 100644 assets/tiles/12_core_06.png create mode 100644 assets/tiles/12_core_07.png create mode 100644 assets/tiles/12_core_08.png create mode 100644 assets/tiles/12_core_09.png create mode 100644 assets/tiles/12_core_10.png create mode 100644 assets/tiles/12_core_11.png create mode 100644 assets/tiles/12_core_12.png create mode 100644 assets/tiles/12_core_13.png create mode 100644 assets/tiles/12_core_14.png create mode 100644 assets/tiles/12_core_15.png create mode 100644 assets/tiles/12_core_16.png create mode 100644 assets/tiles/12_core_17.png create mode 100644 assets/tiles/12_core_18.png create mode 100644 assets/tiles/12_core_19.png create mode 100644 assets/tiles/12_core_20.png create mode 100644 util/crafter.c create mode 100644 util/crafter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a5d8ee8..1026f98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ set(SOURCE_FILES entity/entity.h tiles/turret.c tiles/turret.h + util/crafter.c + util/crafter.h ) add_executable(factorygame ${SOURCE_FILES}) diff --git a/assets/items/08-iron_bullet-00.png b/assets/items/08-iron_bullet-00.png new file mode 100644 index 0000000000000000000000000000000000000000..361f32fd0717c1667e9f941075093d6bc00b321b GIT binary patch literal 614 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!x}GkMArY->r^n~rau7IH z&-X*j)#7!SrJHv1pG(PGl%}n^*Q^|IXR$ut#H!w98+U8&ZRNe)p76+i!#vh~>RaBN zsrh{N%)48UYi1~C&s!~=&g}hRbIm;G0}Ov6{=fPAvGU)^oA1vqJ=kqy|0i$FZIP_R zHy#UGLuWB<;BaQhJ9F)3dpFbCH?JR@e!6Mv$xznmat2#J`~G8b5OK}fYuI}2z-%V# z{E+X57u08RM%{D?WVyh__aP?Z-s%O}>8gr~1tDH*O_yFb3r{@J7pEWL>EV?yD|Y|M z`5lWo?(6?&S;jLhX$5EW&ELzEP8+RuEY|V=S*Unn*3XjrKX3PaIlCase$w$b=anw- zUXtCN>=>({R;H90t#h-j zi+b&7Ey#F3W_SNAe$Ni8qy1t?8zsmkk^(^2%agO<;$dsPA z{9U%YF8x||$Xs;tgKwd~ru%09*R-(r$_=>88I?VcyEfu?-T$Lf?!OY1{#`5X{V4Ac X{zyGW`gs-u0|SGntDnm{r-UW|wKW@< literal 0 HcmV?d00001 diff --git a/assets/items/10-gold_bullet-00.png b/assets/items/10-gold_bullet-00.png new file mode 100644 index 0000000000000000000000000000000000000000..80db29bb8f8ccf8d12c9d2695d8dba8dd20eddee GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf(>+}rLn2zYh8yM`HsIMK z^0&jnY`(^WgWj$G7S5jjOMdRFlkYWbQaLWzi@fx(Jt`R_x=F`-$=f?qP6)j(QQ~~r z@Kr)MnLStFYZK4URWq_#dKfGEn zM^p-LF7+@K;O6iQ;;aZ~JkzsIKH>G^jCIE^O>7kiWfVMkZPLtNj|Hq5?nqsj_pO_? zV$S*JH*YxI?0gf>Dd9KWll$9=$a`jG_Kd1W{I>Lp?%XiDVe8(6$qh?C@1NbUgK1ld z!&Zi9`B3X=W_mAMU3#}|G&m;myX^#{5|iLcy#fUM(byR^5veV)d?KUZ!1J1wlb;cjlUae2b4BNfivKm6><6*sUp zthcYrtgos0eCo#g#kB`JHU7uW$Ul7{j>StYwL@dqjpMC?jX__6+87!>f7V~>x-8P* z;(;(rbtRR(jK>}u&dZ7D@vU=>dgK#LqNk- ze`(9+eVHt=k!7LGTX|P!#0WNZJXn*zWfSv+=CE_~Qs3AG^yu^@tL$yumX>;x-?^bf zA+_V=6BY)kgTEuAE;VF@RSOF^J$Z1d?~-rknoIFl9j0$IS+M9+t^EG=LKfC@N+(Ok zx^2GcBP=C&b)K#IUpJOTFPQed&;IPx;r5mN;Fo_K8momB7ML$km~n4DNB6Te`Pt8X zk8U?^Tx7cCZo6{8-tX=AUi=rF;p4ZZW9pAts~-F~9JxIHTkHjvD=Cf!t)+j2ZYJH^ z)io^Gj literal 0 HcmV?d00001 diff --git a/assets/items/08-log-00.png b/assets/items/12-log-00.png similarity index 100% rename from assets/items/08-log-00.png rename to assets/items/12-log-00.png diff --git a/assets/tiles/04_miner_00.png b/assets/tiles/04_miner_00.png index 7d28435cf2ccf2ff245c59fec7b38284ad21b401..59775b996739b059913dc6f2937330d356881877 100644 GIT binary patch delta 503 zcmaFKJb`6`ay{d9PZ!6Kh}NUi_45xoNVM0x8`Lx`n&I%kvm83eV;e3^2^@m5BJ`y4sQy+^7<=>c#i@H z2ZI3H|6A|%PagMO*`mO~@$lj5qkoh>9D5wBGcmnc>qkeBdcgVm@2!tlAGMiwf_uI| z!|}_K8ym}SukCnx+GPn-RHBK z;fl*=zxW(sG5dnZxuVd8q8j3TH*(643B8$lwyeGAVTSsF>GD5xtJg*uPI~ZgYnG}Z z`-jhVOSW&>#v`J82*A-y&1iB4krz`9|V!a^v&%YW2=V&s|;5 z7q>AxtSgK*tPRtc$jX-ywb7^PZ?@g6W=_7ujJtb!?lu1B$!;`#>%QhrjZVAl>NHXA zHFjlT1qwT#@vOVG$cvGoqPDucN&e7;4W;E%4WgLt+Fk$J>BCf09hz$zcj(!h0uPQa zHTH#hud8koYEJ0 zAl&e#-1%l~faU=o_bFE09}-??@ANvN7Lp(q{@-NxzvG(HJFY$dY5q{n;acw*<4Ft* O3=E#GelF{r5}E)gLhx$< delta 464 zcmbQh@{)OiayRWzsO7djDm@LPM+;v z>eCz6E?By`d3Ja3N{e6eF?U$HCwsF87Vw7!w)NSE;1$my{NpbrI>^|lltuWGV9enQ$MMMoSnFdanZI= zg{dc<_ZKWZSN*qVdRFG5*e5OyXT>(2;d=GP>HSXq{~X6pE)-evwKAh;UgXK6is1}W z3yyleK7Hdm+q9dLZkL~E5U7Sl_<4@{%iVF4{aVUeNEz(OBVz<5k8V<}8$ANY3HX+1#2MHpfn4@0FR=Yx3r? z8|@0y-6<=fv!ZuS%)XxwUOtqntSR?jU$OTNE056fs0GP2d5bP0l+XkK_buBR diff --git a/assets/tiles/04_miner_01.png b/assets/tiles/04_miner_01.png index 6e68be03ea5063e537c41012bfb7f95f415909c7..8577b7463362eb3cb3720c54bd50af83b02bc3fe 100644 GIT binary patch delta 516 zcmaFEJeOsHay{b{PZ!6Kh}NUi74r`{h#dd#Zt$1E)v)ov#50N~&U_J3nav_3B3hi$ zG;g*=i13OQmMdR)Rvyqjs3_pv%O7yFv+(TJJF)NAaobex+&&aj1k&|Df;zhL2W&g0ilyD9~W zofByITj}8QpgGPw?RBbBP@~d=H@j>EGud(uGHh75_=$^cMSf>T#=F)7Q-XecZs;&G zY?N1GH&ypKcAj4(eRDuiZdu2iE6a9$c$+uBX|2oK=G=9B)kArWCz0EYi=uRPqJ@qwWO{@D>O>5w_`F-`X(5|P^wcZWu zKUO}!yQGGjwQb(?SGUc0+omVnopN-+b<^zQ2jacWUgrI=nLBMxbjJ;~WmEmi|Fs^l zblqsr-;rA>+N$x_iLs6`;LZIB_ua*u7}KnlUWsa9m;OI(wTq7vYg*yw)i>YjFVA@p ccKvg_!Zueg-_#l{1_lNOPgg&ebxsLQ07bp==Kufz delta 467 zcmbQs@`ibWayRWf5#7QshA@R11>qf zd?Iv#D{7AHofxaBUhe;!yJsg97QIy9dbd#P)dbJ>poN;Zd_<$PO2XQUGxW_&Goub3 zQee-s8K=r#E+W)VI7i9Wry`xv#xUhM|)ieRy51-fyX2%}{b%_nuX$<@e`j zSXTS6FU%Kl@wvJzj(uTz!nO1}+T5oO?0B?T`T4P9Cl6G9o4k3htB`kQ(yC`$f*1<7 zPFLJGrLFFv*WB-~RL=&z3txWXWW%gmhm5*cd_KMRecf+%9<~)bwkfPUzR<3!v@nD13 z<-x0mPun>Z1)K^>vKB1c7W3^-*N5;Jd$Sdx(!y&CuQEt9MkmZPn-*E}E8)wwb2cf) z(R?L4Voz1Ff5;7x&Qz%XfAI5V*-yXT#ohT-Rm>o9L~qN1?3%>yM?&TO80L0e%=Wn* zy6df2!)2!0!`;fw(!%E-w5?ClKe+t;QggF9*B8^BQhDZfa{P@K*vqc6a4&m|W6Mh$ eB_)%63@J@}K0hoM=V4%AVDNPHb6Mw<&;$SxZsKMD diff --git a/assets/tiles/04_miner_02.png b/assets/tiles/04_miner_02.png index 98c4e9a776d253896592dacfe637ecf4d1c90805..22dab23626cfbe021cf35371892217937ef03da4 100644 GIT binary patch delta 505 zcmaFHJc(t3ay{csPZ!6Kh}NUi_45xoNVM0h&ZuJu@KGpGDdsRTwq-r3*2v;|RA$zK z=W2YeOdcK%zUL=!-4T*uGQ9GGVd~tQw`Je{Z9kyB{(AMi>i56m&L57y^7^Ypc#i>( zEyD+nf3+4dllylEaVAPs$??bQJ_~O&pBFFGX=A$Tf%36A4twhr1h%ag`|P5m|3;Ca zf4T8_wtKnTld9s?lteAq=hXSDE1hl7mSDKHW`0c||G{V_rB}1P&3hzvbJWQHRDb*U z^s@(DIK_3F zO_)s_))%ywSqtQ}}uH&A0l?uN16){Zs$;7u%4du8jW} Q7#J8lUHx3vIVCg!0GJHp#sB~S delta 461 zcmbQl@{DwNB!j z>ZivT?RfO&!LvtKhFJZw-?4*JOno|E(m`8|MSL@3RGfmZ_=!qsm4vkyXT0BHe<|$Z zF-3WscSV(z??1k~d)m?Eh`m!u>Z&74inEt?BLwvMuu(XEuCIjJ&XKO*W&|r@Kd1@XX2EU%biE-)OG0xsRzAw6w9Dm~l?y{>ayvttI#BsUO#U-PLLFDxI WBkv+~#26SD7(8A5T-G@yGywqaM9*UY diff --git a/assets/tiles/04_miner_03.png b/assets/tiles/04_miner_03.png index 5d7d1a8dc949abb12d8fe35a9bee78ef5825017f..31dc758eb88bacc41be205108018662ce0d0663d 100644 GIT binary patch delta 514 zcmaFPJey^Lay{cCPZ!6Kh}NUi75fhvh&04=rr9TG_$d^qJQv`8_C?duWKs?s#FU+ zxS4b^=fPe->qFlsy9lvM#__hXLc1UAjUwM61{Ys%_AC`E`VTxR2I%l#_Mx4bT>S1<_NbxRLUKu&A?#r^UtOx=9u~>iA^rI{uQbgaPQDc+|*ee$$2AZ z_a>HWBFc^X-cK%#URSovTK=Ej^k;F)WmmQfy`AXOdOOT|a-Can0oPogrPoxFn68*4 zNPRxA@(XjuG6vO8{~j;dydaFhcln%d#!WJ(uYT-dEm1OC$ee8RC+pjf)0$>Bud4pB ZU)t+3r`tAa83O|YgQu&X%Q~loCII$v>%IU0 delta 462 zcmbQu@|<~sayR%nPn(e!i7^qP*U( zX3MD(0k?G;LbL3?T5;Gi8QZ;%3+&)sbG)YH$?lDTf)@AxKFG25tV*2PvP@f(U18lf zGY|bWO~E^Yp06!)Ts>$03z3x^88>}%R=1dKzfoWIMBnJejIK%Atdh#Cy$RY&r$$EH zWRO~Lev;v}7h%3Rt2O)I*MCT3*m9~eXZ6WnAD3pwE_INSbUo&=F-BuWrG1g_EAQVi zckOq!2{0+LxGz_WD!Y7nUc8{6%ieE)9_PoHGCVsWawAOmw$@6^8Go-tw%_2ujqSKplW>y2CP&bvV6 zfrKBMm3h;Fe+GBD_OjU(>+jw8QQOHrKRNlupNgTe~DWM4f47t?` diff --git a/assets/tiles/04_miner_04.png b/assets/tiles/04_miner_04.png index 779ed201ed0af1d0c64b3ab35cab2a3a8b7484a7..3d3ae07c207ad0257e6160804164511d07abd22f 100644 GIT binary patch delta 550 zcmaFLypLsqay=8Pr;B4qMC;M%y7`A3BpU83&-mA{XokZBk7oib#1`;H@*Ja_Wa#yd0UoxLkS+E z9SKJYdl(o58tdozO@DIOcQZ3b_jH-Ue0R|uqAeTd_HBK@uv0Lh z{lyF^R>{B>hbl8QmNY!spIpCWgS|>nC&%x|tMj;7Z?yf|o43+M)~5soLO zZfFu%qp*gDogt$qZ}*|;OCG*0iJ6cwQ*CPE{H?5~v_7a*9GI4wCiu;Gs^{spFFGf@ zSFGa*@>eyDlD>Fh_QHkc&i9`eFH8(N<~=y|+Sfn%FD7`IJ@$LCkb!}L N!PC{xWt~$(695q{155w_ delta 460 zcmdnT@|1akayozhwL3}5ExozL^$_q*6_ zQfOPV!L(IM>t8yrZ@yw|Ahl6$TI-$VUt?POYOb4WF(03uFSFJ^NJDqR^%7Gr#v?zk zakXAz`q8Rg8aHcs$*ZUGbCsqt=BA0>UbV2-zxw>YAKo>5S`!u?5EJRu%s3jo>TLhP zKU^1>YI_!K?6_^PaqTvneew0OmsU>SxYq3S@AUg`R_ac0o1`HXd?r*Y>s{))vv=Q^ zJvZm~Y7yX2ykTu}F)d8_t*hw6{vFwNe1CiwupRKZ!*n|Z~EP!vh}xvLWjxR^pqvXtaF?; W{jnGIEMj0_VDNPHb6Mw<&;$VgG1i9w diff --git a/assets/tiles/04_miner_05.png b/assets/tiles/04_miner_05.png index c80d002629fa3553eab5dff73c9e5136a01ac027..5eb6328429208c12bc870461bd9d86c175501610 100644 GIT binary patch delta 541 zcmaFPyp?5way{c8PZ!6Kh}NUi74r`{h&0?6^r?3U^ie2KDduRJId9QPwMLe$U6v)y z$9zRx!zN5)$CXucJO=cF_#}zJ9lvH`TRx3Ys$tz*7-Z?^Ym_X=N`Xx?X;^# zVBc4*2bXWoS$fdyoxvUV-0Gh5#a>L!A{SV@KR72ioaK1(QKsRXTW6DhdU2b*?2oeT z{Rf_U2Aq}@bf^&1V9hss#US8W@1qpxU@nkn8K-2UnN;ntapIIjOSv^}f4d(rbn(bA zDXRsu)L6|nu9Tm^WUAay|2A*F#>T>SoAYO;GX2<;ws@XaqGg<3g~o?pKNd{cAk#nP zz_+f1&(+R-zKkuE=R`5TYsge#t&E7Ekny*{yI9&>K>nOomx z{GIE!kViCWf7VSsA&*HDA9|i%CK6HqzEmbDz*2dU%dPz!59Ty(@AuDT{3tV_-ue0Z znm}EF?1on|0;(TUbX^=;RvRgJCv?hv*|kx}rR(C)LkB{a2D9sVFKDRIJUNGP<2&&{ z<}ECn;;guY7hHQKAhGko6>Cq%80AWaJeAlV3$8!?q4z4t>t0tYyCuVc-`CfFiw&I9 z@NH|1oJC=5D%a*7|E}5fv+n+TEFzuvwNmUKzv={!4L_o{oMd2NVDNPHb6Mw<&;$U> Cb^U$- delta 462 zcmdnW@|<~sayTlFV^5IK3vl{=3ad$GpjpnvWcj# z%%_7N^~&Ghv%ObcZh7Lw4|k6Bs;6e$xucQ0Fl$$dilNBPowsxAnJ>Jy`}n5p$({Me zW-+RgErGX$RxMMHV_)f>V3T5_!F6hRp{k4fxueJW4}3f(?VcU{q`P~?tasiw87|(? znXIqZ6uu+q`O?}`&U-&C4u0b9Fgy0(wyX?c{t}zpC?e96`NAc7weFLI zg*+t==K~F<6-29TdwSxr^@jSF&U>43Ep^_{XT9|~SfQ6^ae|L={MuiC>z>HuJ=>OP z@;<}ly?~QKOTzmLF0*4hw}^+e*gslUYyW9hqZC7N23OAMgWIy|T-T66b+!TM|3 zA7y?RtZ>&`5x2Lfy0&xAzG`)Gn|bdU)LwP|dn+|R#=gTwbRTox={KkIX2*T!bU!e? zA-zKD(oTV-yWH{XA1!e6u=mh6OLUcZwpGYET_xzhc*=W5&#d>2jOv%}*eENT-ecrk YyJ1G=ia&E17#J8lUHx3vIVCg!0G`U&bpQYW diff --git a/assets/tiles/04_miner_06.png b/assets/tiles/04_miner_06.png index c7b966f67cc01c56f0afb1cba6a74a8db23ec4af..8d85ee838775a5a712d10487283cfbcc6e82f6cf 100644 GIT binary patch delta 562 zcmaFNe2Qg)ay^rvr;B4qMC;M%>+=seh#bE!=<~n9&#>{p#50Nqb!N7_6Ys028Sms7FI-#^@a*%^Ne`DN z?YsS(^YaFK_7VPZNOud(7#-JehkHEPM;6H7=}AiRjz1(?i7}mOF9#_hQAEYMETM=AdVW2VP%Jj%i@t zHmlc(<8aXfzw6$Ak7(U(cUv~0{eZ!8#SJnH5B#nxUzc-t^>$8mP}Dt5t%F< zI^#|~qtks;{jb>FohIKt>5AnA!{uv|{cdVf4we zDRv3%WMcU6?c++8Mk`jv#fuI)i@aUdEpv2{=`+O-1-m5}&bf&+nz+PrKm7aJTs|RX zmcg6vT-*8Qzcf0u$B|#Lp{L?=x9rhX&vx&Pm-rRLaK-4vy&4xG-CQm9EOI80MN zC+-)27;$Ck6q~M{ZJZo?3Qo=VEF7?J+Hz~{b2-)F ZOW1n7HGAr@hJk^B!PC{xWt~$(696%L1w#M; delta 458 zcmX@b@|byoayRWzt~4{l^q`J3zsxs zI;olU5o!8JnFl_VrPi}>-Pm6Rw+fAg0mKtt-27jaI@7M=c?svdpkvi z+iME;oPK(D_w?`gV)=xG{s}I+ucWFgZr*)6W0#_AXU~+FJ+}+%8D5m$vMHDTba(z_ zzOYWVM6vCy%cLh>cYGr_WThQf_o zoyy7tf3<3t#?3K~x_T*Mw}-34`Sp)(iGEpW`F^K<{mJxnH@7qeR?A{Gsr%7uMAQ~; zU@|!{LnU4B;@Zd^Wx;vzTk8u}M;+QaTStD*?_0r|6Wp3k%rw@Sa(dN!*L9w?b?x1^ z*;@oS6mQsXy6|~*K%*ZCmbo0mncv=cT`v?>9OqG%5^5K U$M>``FfcH9y85}Sb4q9e05~$(SpWb4 diff --git a/assets/tiles/04_miner_07.png b/assets/tiles/04_miner_07.png index 100482d0073d3150a392c64a92ff52d633854132..5f7063f2097812abd58a925f901bf0e0d784957b 100644 GIT binary patch delta 559 zcmaFJe4J&1ay=8Dr;B4qMC;M%Yx55|NF1B5Z2XtmA(yF9d8V_#nJ-sn#o24nkP^p#Pa>4-TvQis(GqSXZ!XE zYjr8HG4!0NH=7;&>+!2kLV+TNYO~JYyYH7&SN?y3Lrg&8yr16n0x~JzUR2K9bn|yK zQ{lvwXAR|h)pge2wRus@5OJJum0!;^bCKIcqAZ@A30XR`^rvZ?yxQvXcb`4`mCb=c zGy9JTyV*w66$5GIXm=byl!XjwGm(N>PUo6cvMH_h3A(Y#ithieDL0# zlVM(7eo$*~)mni=U!55omc~5Wc6u7qj@^Foawcngt8@(~HV6MSOqg>%C>udYti(1XM5pO+nT4mGi9cn+pCkcym>p*g@Y#qKGh2@%Fv&hc3)e#o-J8I za#4o!bcP2%A7AEb+H&{pjCXbdiZAK{nf`>A$iHwA2vrZeCjT@#K&9zL>8+V|nhmvw z4)}g%`1xX{ho9G)=?*6Pv+9H+89O8|7@jF+49QNNRrl0WG?>#Nd&#Q}eX`k~@0SU_MR-!_m^Kc*YVPoM*^I0-G#0e1b0hR1X)UIh+BjoHm!KS^x@0QC#HA! z<=)?|zW@8)@$a?oce67x{^z)z>8+~6cfBZeQI{4^q?BUej;r^2b8TRtsUVc6J>q!9))y*DRg=XHWmU30=oURYiE zUu~Yhv?Azms*UG4<2=t7X|*Ss&&2%rr_XVZnd$yL=47`Yl@$&R`8AB@eyhztyKK^D QU|?YIboFyt=akR{0DK0~`2YX_ diff --git a/assets/tiles/04_miner_08.png b/assets/tiles/04_miner_08.png new file mode 100644 index 0000000000000000000000000000000000000000..f4e90ec143499acc870d43210172ed621919f060 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!;+`&!ArY-dr?1Uda+EkW zU(xh8d%#sLmcAv+7V;jPvo2}!Y8Ii8@Hx);7j_6&cim}P!nxv=amwUtrYoHlqAq`8 zUo*#e&+MBwZ~oL^na6UlX3zP2yYI4XbEDRZ9T%Lc!pY3w_Uyg9{P8cxpB`nMq>|`k z5^r~|Kk44j%K46S0uyKcoUd`~^czJEuGG`VE7=OeR_Gee_eo!~=B}1h5yOooa#?X* zWd>rmi$qyGITNyVX6@gz_F~Qz?ytN5$poBtb4|6Ic~0VQ%-N+EpR+BDIw!+0^R-Xv z&%`yR(-pTctow9WqC4<@#=6O6!mnH|@9(!a8LelAdKVMJ{`vnb9VhJD7QJjYzYE8% z_$dtcMenj(3A&v1p8A#jr`QY^f#$gF7u4A|cuVZal~a(nl|Jd&`B|vr*|L}0Cki*r zV3a+yN5o-k*tVD9GeZogGHh{M#W(v(v6=jrU2~FFP6~ReDIoPs;f2P{8QshUey5N2 zT{qvJbK&);{paVOda&%D+T1^xWxtMViq3ge`A=T+m;07|?|;@ZFfcH9y85}Sb4q9e E0M_~rr2qf` literal 0 HcmV?d00001 diff --git a/assets/tiles/04_miner_09.png b/assets/tiles/04_miner_09.png new file mode 100644 index 0000000000000000000000000000000000000000..5360907bb41ddd2fa1d0d3e489ab13c2d9d4ac82 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!;+`&!ArY-d!)^VU90h8< zGk!1zWF{8McFM9Y+_>$NknYqYUD|Kf?F+aZxkmKkf+H+i*|Sfp-kNzMFv4T;ABIy~ z3-wOldsEwRz}sWT&bgKO;1Dy zvz3fkr!-2pw4U5NA+p6R;A5^gpMkc+!Scq389HaI5`rhFAL2b!KhswG!Q13{no5)Q z&HA=Gz z>_j7P|D#P8!ry*-R;9};&As6DjctEqe2NZe9GdrhW3xrkfw+c9gV~cVUEjFx_+!pF>+`A+|Y_C(tBH_(=QX&I`AvC&n`!$lB|;IF6a2qHe+W z$ucaG+z*7p&MNvnRz2Xp_&_KBabd@P-#xYxkw?GwKe$vW!YH)8b5h`s*hgANK3`tE z@oF!}lC8lyVp(~PBw;3heV>vw<^0Yjw^PWu;SM` zy%Qz|Ib2d-qjVPeFX~>sXr4UBd43lu3FZT)o|mr8-v70y@oY^8gyZXfXSO!z z`1(Fr^-%D@LwViH)1H`^I@(W3@jJLQ>saK~4??Oldl{x{$JT7Ur}FNzopr09^_Ls{jB1 literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_00.png b/assets/tiles/05_turret_00.png index af1f0047b86debdae8703dbb6d5132fada687830..21a4b1260b7b888d8e95b81c9597f4a778856485 100644 GIT binary patch delta 367 zcmaFQ*vULWxt=k=)5S3)qV?@`!@gz%0ayFgG6&cf-c{>znW}b**FxUBjBOHn-VVgB2X1`PjW&oauHJ^dbf^9Iv_*FQVTtU`_4j@-EWc%}yD zf}UPO1_q^1>*DjvUn_iLh^TawYCp4d8-vU8h(3!YmUpBYmT1-sek@#D#IVO>nsUJ@ z)9HVwF--Y6EpXYCQ_S-!t@)0gO=i$)-14|#2pJdwjVR)>MXYKs46}& zOW|M-l2!^8Onus<+r^g1k&$O7Y}!<^QsuM4opAqcwx@Kxx@-G-4fD2}W;1L`Ywi*RDjK82Sa5`2@Ve-?uQdg|ieI1aPm|xv Z7_4y0%wv150|NsCgQu&X%Q~loCIA$hpojnf delta 212 zcmeBVe$O~Txt@WsILO_JVcj{ImkbOHD?MEtLn2y}ORjGCdETI*AyYwDzVyHfW{olj ztLx@%CF}A4J}t3md7+_@V!1P`vxq^HZPKdt z1PY&kW#^;0HFziuu@bkUswMvp%j+I5$!BazE z@$?k}3daSHyi&B{@+f4{%#u8rIqk95-4mRen`9h(4Sp0KT*2%nYw$*vfgxF1FH<&> SU4(&wfx*+&&t;ucLK6T8lTXF~ diff --git a/assets/tiles/05_turret_01.png b/assets/tiles/05_turret_01.png index d19106855783f834ce1e2398ff6c8b3291cd46d7..181115065e5fcb186f959754804eaf8d870c5ed0 100644 GIT binary patch delta 389 zcmZo=n$J8zxt=l2)5S3)qV?_cy}5@C1X|}a9X4eT6g}XZaA2zRVd)(oWh4(2FS*Fp zCLJDiU}|tWYo3GoL)SgZnqEpz4^=WK1}Oco`zPyvVD;)*2M-_lbB{|}nqf!Wxr1)q zPRBSTZs(f_TQat64B}!~u(j-7etC7W;xYz_e@)WA&+I(Lz_Pr4M*ofFdUpgGR;;`> zYo7B|rU!3Q?3h-E6yICN?=YiZGSz3J#e*5wb0^=mVNqc6xNEi}pKnp(U9;v_@8jn$ z;@`)jR5aCu{f^{}yD~qxJMYanYb~|->G|!!`(^!ay!-a#?VH96g4&wg0gMM;CF@Gv zF=r3_@jc>inT;x=z>)V~0@CaDrJmqC*stgqG2xQH#vTn#v7W#J;a?AS83!g!{FVdQ&MBb@06z}1 Ap8x;= delta 234 zcmbQw+{!dTxt@WsILO_JVcj{ImkbOH`#oJ8Ln2y}ORjGCdETI*AyYwD{ukek(!U=L zSTdwpF6~pe&6qc9n}*3<*#id-9N2K}#tg-|uccl25)|Dh#~7O2ST4QzgZ$S?a#AXm z40(o(l|eF2B_aZw=EQ7uv1|}w_PpwRf$>R%U)Q~Zu|h$Qs*{q>O59O2P?B*7^Wxt=k@)5S3)qV?_cy}5@C1X|}aDVwqfiXQM4I51WEu=I|PGLi?1mt16P zlMatMFf}-xHP6BPVXMs~buXo}9}5Ffs|p?%_?d0Nua3_Ie^o%CDn zb<9KJwpmo?B!4i~Uz7ClGdq_ts7$Y)ao$2rJddX#W7XDW z&m*2PRH)B9e?aT{obS?19A}oF37RCrZu5ED`>xr`8JZX_eUp7R+xf!Ax7Hi~efp?( zt+9Z+=|t#dnGfL!g~bolRos%z?5(_dHA1MfgTGurXX)pYPcI z`@ybVya8z#)Pg(?FMYm*SYjMTTPi% zDe!Ie@zXL-)s`N$JMN`feS4N6!%c$&1x`ld3Jeb&HcmMc`c6?M=rC7o{904VXbJOu z9~`~3ce(N;bjmB8(mwOGXqim&>+AJr|9xdxQ*g#iCZ9clfq{X+)78&qol^p16996K Bt-$~Q delta 229 zcmZ3;+`u$Jxt@WsILO_JVcj{ImkbOHyF6VSLn2y}ORjGCdETI*AyYwjc^7k8ti4SE zUqhr{r?N&-!|Y|cT)un>GM73H=DwD8wz_WKC3C>3Pi<#X#vFfhw}VCYfP$NTprS*ca>rHY5|IgyID)QBx~g<2bk{`TAm`nl kX0I9o*?X)Sq!<|9iCCm4GCZ8ez`(%Z>FVdQ&MBb@0BQkQYybcN diff --git a/assets/tiles/05_turret_03.png b/assets/tiles/05_turret_03.png index 42db6b6c8aa629cc15c64466b2126c642f635ae2..eab1bc6c21e2ec6dd70afbf61547542c8cff97e7 100644 GIT binary patch delta 389 zcmeBVn$J8zxt=l2)5S3)qV?_cy}5@C1X|}aDVwqfiXQM4I51WEu=I|PGLi?1mt16P zlMatMFf}-xHP6BPVXMtQ?LPBxcAL1+EXo?4@aUJQ$t1$ph7 zrp11sE5(j^ZA`J99_xb{{xeg3Hrgc2{QfxLt_{lrl?in+1@~pC30s%SCiw5X5;Wht`nAd8F4$+ zf329k_|Bp&x1L9EEcA~KXPUsvyo7twP6j>>_D@q&mK8M{EbTM3+85+ybj={G?xFrl x-S=XK4XSk=E7k>EKRq*xXI=b%)8E&bcPX4P+o~5diGhKE!PC{xWt~$(69D3LtAPLj delta 238 zcmbQw+{rXSxt@WsILO_JVcj{ImkbOHhdo^!Ln2y}ORjGCdEPmdKI;Vst04R!8O#lD@ diff --git a/assets/tiles/05_turret_04.png b/assets/tiles/05_turret_04.png index 565bc3758ecd7bc79370fd95189d6ac6df53c926..0c27dfd87e75fcca98699a75267684a07380bd84 100644 GIT binary patch delta 389 zcmeyvIG=ffay?_3r;B4qMC;q>dvgyP2(->;I&8`wD0;v*;lNbs!_qrG%19n4UUHGG zO*%a4z|`P$);tIEhpjgMycfk-@GG!*PPunnxzdVp{kk+Ze$mg>t8>;cJgBl{x7O8? zR8Cm)K2T*DOF>Vo00V>O($d=9x3zf<*&IG{-?@=~&Xh$#BB|akX}-@6p@tPJr%dWw zdWvyFn2~&A*gDJi)0qm+wD%Y-i;&xJ=JvkXcWhW5s7%=QzTm#hoWA$*^B13EEa#eY zCiJq*24#cYmLH}I?X}$f*808k>G|&;a0l;_^}q4%+mqb2jTgjLYw})TIPfa@ZOM*& zK0o79>v>)0oEca?O3N92_pNhYnaR_X@7#1jVXI=2XkeJ0#G(gEUk=WkxMHJ6u*?_c(}_3V3lPk-1|Rd30_z`)??>gTe~DWM4fug|R( delta 225 zcmbQw{D*OZayGv^2h*nXXyJ za8E#Cd4}rM9>#vACcXtKA{`gKLpUZp=1BS~Aj`VMqDf?H%GR#Jsd-OYu4HVkxx%=Z dPok88;i{Ukzy&Wedj diff --git a/assets/tiles/05_turret_05.png b/assets/tiles/05_turret_05.png new file mode 100644 index 0000000000000000000000000000000000000000..16ad8a53af395edd746fcad4ef0cf83b935a04cc GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf0iG_7ArY-_r=QJjF%W2# z59BJ)_1L+l=syNzMW&v}8%rkrA)S83mW^=vYOR^yk? z9jP-yj@QZY&tzBAx9W34hPEH`AQpxj#Xhhd)AR7BkuD=6g0 z?^r)C$9+oll(642(#bJfQgs~-c{apOkYNo_5Yh;lv^I1Td(bPF#~)Oc%*qU2|51t$ xiaw|+#E||+pfENu{yh72iJ<-evcIj@cMUz?%W+pZn}LCW!PC{xWt~$(698HKqm}>w literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_06.png b/assets/tiles/05_turret_06.png new file mode 100644 index 0000000000000000000000000000000000000000..fe142a8d89f3ec7a7373bb7220e2fc399d96c2c1 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfsh%#5ArY-_r|-=@Y#`7& zpNaoKB+ClUJG%^f&O9(O&R{tIpk&rTgF6+C42&_U6K*$T9_p_6Bd9siYobkqfQDd= z{Qo}n2kTcy9&|qbXP%aHHp7nl>khij_BzHPF+1NzSd~#Gd8r6PL&uu$yZ<^$cc?N% z?VE7Su6U&-!$Hky%HJ}1rZWqesw&kz(_%ev>tqp&+sbE~?us-d+oex2Jo>01^&Ves z;b(ycVTW4_k3X&`lG^4xKlFb^ZQ-v8-Va>X&3e{g%e;Cvv%TU)>CLI`#b3Vt%e=b# zGwbfZjeFPH3RoqXrZPw|yqLG$ule}LCn7&>!``2puENmvW1if*GuwGo6`vTUa4-i+ zD@_wrJ=$a`m49gElr>%&eDj$4*VHEF*+x#&FxAv8lhs~&Ceu5rDMuo~N->h_L4$`v zyq8(nIk}FNg021ff*UtBN*))#>6uwM-GgDxN9QAzt^4k;o0IJE_t*NH`}Z-JT)No% UN^<^D1_lNOPgg&ebxsLQ0O$g*hyVZp literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_07.png b/assets/tiles/05_turret_07.png new file mode 100644 index 0000000000000000000000000000000000000000..3783cd844bb07eb77d2a3caf8a69801efc819b96 GIT binary patch literal 415 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfX`U{QArY-_r|-=@Y#`7& zpNaoKB+ClUJG%^f&O9(O&R{tIpk&rTgF6+C42&_U0(l2a9=6&{Quk7ts#M9K7@+dQ z?%!O$1M%UTo7yM-nWrT!&9LMCx|4phy^eWE+%}8qoW#($F^G#{!Pam0-hX3HR-DEl z@vlkx_?ey07*wXuIB%gQp2yXYv1;qG=OIrSD%5A5KcIDe&Ua~Mjx*2C1WgiQxA|Q5 zqI>poh9-tfe717OgD-59t=jnS<1eLajRo9ICqggFdjaP~F#x$VGRSY`O6~LNhf#`kI(e8{;wINlO_R zIoP|FrmR~whtZQ)yQFsOwUnI1J3kJwYp#7EX4qg_*P*fA;QQ^VMLg@`|C|24F8(aw WV(*%>!Nm*=3=E#GelF{r5}E)_cC_mN literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_08.png b/assets/tiles/05_turret_08.png new file mode 100644 index 0000000000000000000000000000000000000000..a1c19613828d51080056cbf6d6d2093bdeac38cb GIT binary patch literal 415 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfX`U{QArY-_r|-=@Y#`7& zpNaoKB+ClUJG%^d&Ob0R&R{tIpk&rTgF6+C42&_A0(lPR4_j^ibxiSCS|I1ZF@E}#Y6?Pn{Ic7Jrz>*;_SW`8&cq&uE+!Q*@*zt`A3$ZMRuGiw&}H!ht#zCX)c^3OeUv#YJMbvr)e zm0x+jZG;wLFtT$NZ;?#rMsov^+@k5Rh78 z=CVe~>lABnirk@%lh$}?@wqj+U)y;h-uB)zjjbBG-z>$PUSxRRYRZvF*rPC$`$0p2 zLcC|1)^naCS2nmk)LyER%$xj7{NJQYpYjBmBObMPyy7a|9k=4xgI}NHH`m)TPQQDx Vm#e&BF#`hwgQu&X%Q~loCIB_*uFwDg literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_09.png b/assets/tiles/05_turret_09.png new file mode 100644 index 0000000000000000000000000000000000000000..e82443c60b054f532001624e4040b2b8a4f52b02 GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfS)MMAArY-_r=RUTWFXKQ zA13l3O6h0Qjv~hnsc$<>moQ{;Y`-F)sAtl!MQFM15!niVxi=sE>txywzniS|WWtkb zxqfxw2kTcyH7*R^(|;&|m*M+u)2fTh1SAAE{OniSxP*~kr-gw*W9gjFzYhmW3tO_8 z*dIKoXmMSJ`J%vQ$@Y}lvy&7!L%lA(59u|0kYY5y@nVF<{=5?n?DLIJPYEhL(0Dy| zvxQCC0d0lS>kocbe$)H&&nmT-v7U3!sZb%l9fA?Ee0#i-Hl$sT72fmm(~nNO0*_5^ zH`>c|zJ215(>-;{$wsb*X}9N!w_Xr>@R4g}PPO_G=VU!=CQ$}qxu*7Mj@xRlS)?5> zOzfFrHt|)5+tnt^O_K{&sA>mwE#9r5pss%=x?kQ>>h=`9Z&qSX4teEA=3N#|H&@xo zW}|#3V1?>tQ&sk$RW}@OhikefBp+L+|3}eVdxy)J15)xXSHfTXe(Pn+cKx>f*?(WT Z7tFf6QFmYZaRvqk22WQ%mvv4FO#piuvl9RS literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_10.png b/assets/tiles/05_turret_10.png new file mode 100644 index 0000000000000000000000000000000000000000..03b59ea8544f84579105d33180db7aad588d6543 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfzMd|QArY-_ryuNXHV|;N z59BH^j#(5_+^O_xfyyg~Kt0XIv}MfiQ*FD`bCM6JwZECJ!y@r-v#lK4gWFeS9wY|W zEkAWkjN#t;^evZnPBK(F_D=4+izh>BP7fo4z{K*uW%Uv48`%$>;=W{&qPLY*!Rlzy z5yi6)uQ90jc6RhNVI8$C(Z#lfe z%CC0&Yncn)3yi{jix13iJbbos{}hQcH&?Q6UnT2y=NB*Hn>*B|dxMm6yL&n;HdMZi`wwVcowHqYcZSW)}tZ^1qlMu8*ezXYW3OFhAPuwT(JV!|bXjXfHg zVm^Td!oME;G7e0d%(pa!uVwGoikXYAEHSxVx@O9z3uSQMY*!uFg_&v|O%IO`9Iv<@~DqAb>{0C> z-sA`CS4SQ^>`|vbwU?K{ChvO6Vqeu{m7cfevpOd+G;R#yVpy>C+r9kq>SV=f3=;pE zq>rE3`HVqj`HX%GHSs*IhKyBPmpu=8%1~iFv;TnB^*P(6nK{lp?+KbD!fx|<;rp)H z%Nd#&jK0X;daRmZ@nvqr|34MtuN`)*xy$Y~z{^?cZ%R=UkF4tAl|3W#_rar!7=ri8pB4ps-bO zNsorM*qOj0;bRZ(%v`b2^LUUE|Dk(TdvpTxf}-A7g?Zh)e9edPL>uEV;Ymvw7&+Lx zmZq#LGJiNjD(uCNthFa^9NO`*wLB>5qG}RD_8)=3xJ0?_+D|27_W#TNwm!cp^-R@2 TE!n#a3=9mOu6{1-oD!ME1Sz;do4EOh+I>yB??|XE?g;kRbnU4Lk?sD;DI3B^l$S@%&>b&{wxt9cr8AR$2 z^wvI$31(p1IlC##LTF`LO0- z+HU3i*Vh*+hXqS5U~KqS{FW!fKYaO2t2z3Se+3vE|FpE9sXZMa)TFQAm@(m&z{V~O zO>v*V0^wf|&Ujq8u_QVDMAL=sa{0wmqNa%L?rRnJwZ+tu;iSQV3P&UH1B?$H_Dwny z@=8r6_^_00yr!yTwuJHi5B8e6?}ZE-RO32UtP42*yEltxU3|Ui@9XBe^UhQmUeBp! QU|?YIboFyt=akR{0EzjruK)l5 literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_14.png b/assets/tiles/05_turret_14.png new file mode 100644 index 0000000000000000000000000000000000000000..1077580a3981b657b46e28fbe2e22f122e376147 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfNuDl_ArY-_r|-=@Y#`7& zpNaoK>J^sEyAo{^?6@;H!y^xI?=a^%Z16yE%Na(=hRj38m45^^JG~~_G#ID^SIPH3 z`N;C8)Kt6T#gzNrsmZ(y{kKhTWd@&=5KR6o@1Eqza6Uqll|e!2`Mq>h&tRoT_k*4?SZGJ~9niQQ^G%xh!C^y7}7@Bbcoy}_O}?%AqLz8!)QcV#M;9Z5JR_e<}`g}>Rq1dA-@ZoK>U z=IzShobIbr7&90a)Yg8s+H$=6dXB8$^F^;E7@YsKw4Zgp9FR4uX~N`_0&GjnTvjQa zI>j0+65FC^VJ&1T_VPwuk;0jk>bGT{iY@JyJ?^Es`SvWKh8&56Jqk0qA2fO_2=GkP zE*I=uDcHMRUvT5b#*Lr5YffI`@|(yI@wmC;HP_!Au{)1V`1RF)bA2syUh5fkW2RL; Q3=9kmp00i_>zopr0E-{5qyPW_ literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_15.png b/assets/tiles/05_turret_15.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce0dcdf9f4d2350b457809d4f1c9e3eabf2bc6c GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfex5FlArY-_r`zVW7znh= z2l72Qy`*#7-L$Q&w&@EW>3k7co%=1Qn0a}pdc`p_vl~l1=A|ee_+a<{i~&P^>|IVd zv!~y$-MGPY;Puarva0-)o{o*Xj~fRHJ4i|=GcdS3iQRwi-8DxU#tomEO!#Jczh&(3 z+bC1$k-bBxVTq>T$BiMD4EOw|DHohFo&I+l!<3)%0+&rW#XRq)$(O5VlNq!ceVqFX z<3f&SzTltBT*VpkEGv`mhjGC!%MX)M$PF&Tospz2GTJwitp4U`F-4`n;Z54Nwr$2${4tbQ62fE0@O~RF%xi3|{|HiVuoD ws4B#e{zsrNHZlG@`*n$+{r|GRt=In?a{l@E!bkrZ7#J8lUHx3vIVCg!0Hau@wg3PC literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_16.png b/assets/tiles/05_turret_16.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce0dcdf9f4d2350b457809d4f1c9e3eabf2bc6c GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfex5FlArY-_r`zVW7znh= z2l72Qy`*#7-L$Q&w&@EW>3k7co%=1Qn0a}pdc`p_vl~l1=A|ee_+a<{i~&P^>|IVd zv!~y$-MGPY;Puarva0-)o{o*Xj~fRHJ4i|=GcdS3iQRwi-8DxU#tomEO!#Jczh&(3 z+bC1$k-bBxVTq>T$BiMD4EOw|DHohFo&I+l!<3)%0+&rW#XRq)$(O5VlNq!ceVqFX z<3f&SzTltBT*VpkEGv`mhjGC!%MX)M$PF&Tospz2GTJwitp4U`F-4`n;Z54Nwr$2${4tbQ62fE0@O~RF%xi3|{|HiVuoD ws4B#e{zsrNHZlG@`*n$+{r|GRt=In?a{l@E!bkrZ7#J8lUHx3vIVCg!0Hau@wg3PC literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_17.png b/assets/tiles/05_turret_17.png new file mode 100644 index 0000000000000000000000000000000000000000..308730cf0f6fcc4f5297bb59ad4d7627c68884dd GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf8J;eVArY-_r|-=@Y#`7& zpNao~B2!A!5`#;-3}aSY*I8%MUCnHEr=t15(%B4>P0|Lw6$%FmC#kyHNU?c2s1g4vqf7Z?w`{uLW?L%wg(hwrN24H=q#%#_QLiE5iA@JB+Z zg*B6R;;D{JNe5+i&MweW%@*ofyj(#cKmNvgIeqUbv!{gpmeF4NCi8SuQ<6l2m0~29 zf`dhXhH7!>Cib9L5epx$-l~?&{rH&pJvvaTV{Kqj~(nudnf&>uZ_C Y+pqM#R$J7-z`(%Z>FVdQ&MBb@0IKSrXo|Aid@g*k zdiHS!7Y508x!r#qO=Q~lt@!utlg_<^(;ZyaO?%d0&wTbw<=v^god;*keHF3l@pEy8 z2UWY1_uibeeLH)S`?;X{K#5+^2VVZA6xe?+1BKJghB43vrA>`&N=>5k_-O+T7Pr@ bKE})Sm#l1ml(jN2Ffe$!`njxgN@xNAO$xRJ literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_19.png b/assets/tiles/05_turret_19.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7ec35c6d18111aef4d4edf495af2163ba127d5 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfDV{ElArY-_!>#)c83@!m zRx`*aEwyD7>6peAxa54~iXyS9C9WoS7;<;=3boIWo^k4!T>axCHWC1-y6MFQ7u;2oSURrSzwOjywK(F$!N4FGd4K!vy&+1+I41mI zR{u7!cnSx{t{LZVum|4}Uf(P*(I{s?c7`+0t4^zn@=UxBssE zjd$N>-R^3+A+Wkg)QJ-x$ZqfqiQ@w}9*is>DkGafrFdCgV1cTQ>V!H>_wH=ECsO1rqI Uw>Iq<0|Nttr>mdKI;Vst0EP##H2?qr literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_20.png b/assets/tiles/05_turret_20.png new file mode 100644 index 0000000000000000000000000000000000000000..34204c6f877033190df302530f8f413713e6df8f GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfsh%#5ArY-_r|-=@Y#`7& zpNao~B2!A!5{^r|3}aSY*I8%MUCnHEr-E5IRf<`zN&13sh2VRSt|=Z%J>(oXrf}@* zuRkvQ;rdmb2Z>2_{!@E-8Dh>YPgoqPn#|Jk)_hjyB!)u~nyd^LqO9LvpS^aYKrsVP z{lVVaXEDJHO~Gf}-&_{ZV^_#pwRKtgx*&!*bI-UZOwBrXyO)vUv*zL+O)++v&-=2w zXSXxBFudF?w)?N6$(!9~tN(rbr1R^6w}Mi*Z}EY-jYrQm&Y$q2_vW6(npSmnmS11L z?faVMeeawchwR2#n;3W*_Ux3nJ?+(^dZ?pKx~Pb zi;l8a7i+M|ot9+H$f*G`Hmq`%zYpE3+H)o_D=6xXRhZY!%hR^7+%z~);bbK4&`_Wd z?`0NpPOf8RVr$>}YqNTE&lv3c;OBLEw+l}~r@YcB?K4kn7RfZfzFvR!-&clY%}dY2 UCFETg7#J8lUHx3vIVCg!05)&0dH?_b literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_21.png b/assets/tiles/05_turret_21.png new file mode 100644 index 0000000000000000000000000000000000000000..65e4d8afb70eb4c66006bc2e0fde1a505790faf7 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfd7dtgArY-_r`zWpRuDO6 zA8yOgzT%4T7U!#`-ct_lK0oPX`boK!fz$3Nyt<(p#CMSQL{QvA#`6izR$Jz`=;R#v z{`mf5$sey@y?cMN^zk!0pE0N`pV4ojCcciv!Q^Vx<;@|M4EOw=DQ`Gs`uy!O2By!Ji>Ig@WjtRa z^Xt_!%?5>r9_RkIdGaPQ?Qv`N+u3)PD#SD?6rDAdZ%68}7bsKD6Ka>*uGlSRDlJUv{2* zblO5S7W+1qM8_y+56QqVof*pI!hTCre4PqEiMTv@%U%8Y<0hA#o|#);M`)({M_&^X zIm~dG^JGv1LksiKAfs^AYKNfXT(a?NO(mlx%=dlp%hKNE!t+4R-epSojLRP#EZMHF f|3B;RYc^-sE4^uZe`PQ*Ffe$!`njxgN@xNAS0uU0 literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_22.png b/assets/tiles/05_turret_22.png new file mode 100644 index 0000000000000000000000000000000000000000..c822b4fa4f8185005ff6666e16a9291e2aa78f3a GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf*`6+rArY-_r`zWpRuDO6 zA8yIezT%4T7U!#`-ct_lK0oPX`bjy>z-f0BUfoa);ycLuB52+N+XD&CR$Jz`=omcu z{qg-z$sey@$vsF6s`Kyd)EcsB*GP&s*!L&RGnHA~abUE<{zoeSP*?M29Lv zn|Z@78NybVB(W$|wEgSyObja=#`+qFwql&83eT((U+a zOFv6Aa40;!ki6Z#qwnzr_1F3O=TBNGY8huEy;j%uO%3|CEj8ECkjG%| z1RYiZ1sRPglXhxZGHaHux$yOB)Z~q=g^#)Amuzc_KEfdP(b=W4b>|%aDai$Yf33f{ ce;?y5-b+?H&*gP7FfcH9y85}Sb4q9e0K%5L&j0`b literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_23.png b/assets/tiles/05_turret_23.png new file mode 100644 index 0000000000000000000000000000000000000000..d90603de0b5c4ce6f5100f281bb000ac8a4513db GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfS)MMAArY-_r`z@&G7xBu zzaV#@JtEVefpyVRN0FDsVyot~%4G`jnma`2H6KxY#ErIpmN~Z+}09y4Rj2_03>$^*^YeQhmm zQWZQDa)Tci*s#jpUM6;X^?Lt}ye-}WDeEQ`9Oysrrr^O;p~aT7`RA;DKmY!d-M9ZX zzRkIF;-roZ+TXkDjjA>;3O`|8_&0@DxlI#)cD+tu~ z6*2G$YO0?Q3%q3#$o1XMTWh{*?Gl&FBIfMVxjH`u?lgpKFgPGl|3PfFx?;A$Bipt_ ziH84uNsN3)Kdv_L9x^qobMnAfq3sk7GwCmEz)?hG#Y|1a^sd2ajT zmpMD;N_5C>oO8i2fFWS_--Dl>?u*5&Ge4ep>s+DbR?QrK5r!?*O_Pti1n$nXzShTC z;F6)Z)3rb}Fi1~=*_z|G*Cw5n7FAqK1&^HWS8efi%nG!+U8>V^Ag|uwPV%ZpCs|L1 zFwPUu(g>M!Q$mPYhU?Oqk5hxBl5~%q(=VB{Q}B+GQbH&D#Fg4tUjH;OWji|G{;XXE a^NBl`l+~7Q{Kmk*z~JfX=d#Wzp$PyfLaaOh literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_25.png b/assets/tiles/05_turret_25.png new file mode 100644 index 0000000000000000000000000000000000000000..8c5d9d95484d3c5af9c388f6b11f1018d50093a3 GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf<(@8%ArY-_ryJ%SRuE~c z54UA#UvWiviSraw?eZ<{rfgQXqeroRKauXVB`Er z5^HXjJg~ee`M{({_*?tpMCm<{q-yN78a<^IQa~FFTSjEq&kWg2DYO-vT@dbtp zFFEi*W&u5P|c%nG&xS(6#uo>eZA09v!$!| z_O%M!$SH5zyF^| p)wb@szi!#_1;4)fZ?3mxI2>{LWJaPh69WSSgQu&X%Q~loCIEC6z>WX_ literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_26.png b/assets/tiles/05_turret_26.png new file mode 100644 index 0000000000000000000000000000000000000000..fb02a830995d2b7e617afbadaff665233336d7c8 GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf#hxyXArY-_r|-=@Y#`7& zzlrC7B2x;}a)Ud&3}aSY*I8%MUCnHGr-E5ARf zVu_#ngR56<4mcnEb5BcJn_@v)b$H z^5mEbxIFG}wV11a?!dlm&p%&(P84N+CuT8q^)gEb%_$hWQ24a^GOb?bEmN8{PD z^gZ6Y9v$U98N|Te!u&JJDB3bzVOd-3vyW4Qq>_1)uZ!EAy!9zhkh$Ur`^1;pSN@in j+Ol20Y=8FOS9X*C7t8cmb5$4^7#KWV{an^LB{Ts5+?ul0 literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_27.png b/assets/tiles/05_turret_27.png new file mode 100644 index 0000000000000000000000000000000000000000..ce8ce945bd08fb13b107fbc0ca93ef53fc2c111f GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf*`6+rArY-_r|-=@Y#`7& zzlZ05B2NX=a)Ud&3}aSY*I8-e{foiyP6e}asuZ)_BeMi8qdkxNJv>9YelRvUbYA#g zVKdk7Kz;aT2Iu7!t4}5HGF(4xY4vickc8ldo$1Pk%NhCCOkrXW5Zqm7F>i~Z;n9X^ z;wly_)1{IXq>^?%nh;a0$~GxLY18wdrxFP>b;1*-a8Li-##8aZaJ7$SD7(a-_qT37 zG-Qrre7RdJ|GoUZBm1&%{wUq7C&m0vtYYeFHJJy35i)##rX5K*J8i)XyZ!q%KVv-b z_TPbr6`OLVF>efCv&@IjgyBos_V0@fwy=Ks_x4|c;`C%qb0%H}VY%NQE||3}P<=du zG3}7V%3P(Zf~i-V42vcgtWaGY)U`O@(LqQ5Ot`;X@RZwA&V92C^Ge)(JNny7ktu~~xxt-XhA}Iy>#Q{Kt`cvP&VRtmQ_*p|A=9bN=3l4MN|BSyER8}7zu%o` zHMe2E-o~bOub+EM%)%H7cE>H6Y&N$?(D2%KAGIi^ieo`u3=D#n*ZGf6z9eAE&=vpS zm}2odRfdZqpF5m4J@jIjw9F;t+|pUh58kB6HC~G;w$o>SFjK$NXlaOS!I|ZS8F_Nd zAGl7K@csB4Le%D+lHt9U2fjJH5q+&W zmyyvSx4c@Pd#CCS`+0s-b{bBf%gD&k{`jOJzb<3@F8g_|k0lzI7dlosFR@w_xiz74 zU$d|!1OK8>&25ZDx-&QHe+loGH=T8RirH@&Z_SN&-}Zi=v~I^P#g(id94rD>sBRA3 z#2zH{#$dg^pky*{@^$fl6RvUT2{K1KZa?uw^i|p38FJ09uh*ab_m%ba_p^T6-(A;X QU|?YIboFyt=akR{0P=sTGynhq literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_29.png b/assets/tiles/05_turret_29.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac498734ce8590be62280bf1bfabc37901a8b1a GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfS)MMAArY-_r|-=@Y#`7o z-^_DBktc;|xxt-XhA}Iy>#Q{K{>5N;r-E5|sWh|PBeMmwCn)yUFY>tA`kBFTfy;~P z@+E%i4{oZyI}o6G@AR1jR)*t;?W|swsu?IH)SgdSw3LxwXDJJVz{KL(&383(7aePO zByM5B@_bg3!mK2@LXT}bg_u1x1ZNhnJSI_4X4LPHtuyERX~_={f*1K{hO*22xKMuf zp&@e|qvS6>`T6npj(p$ldR5}X^aHD741ZiG|MAZ<{2-$_v+D<;2p+yasR~h>Eqhk8 z@olgbs6P5^%DD!H1=ChRFXgFK;{D8Cf0pGcL*B2F@X-IaG zo_X74m9kVQ_p%q}788vh%*+Vw%4Oa;?aWQ_U#pMzOZDb@&93cRIwfM=wKm(O+UxQ> zvUn@pb}S6=PFtPAzeMFmVqCnEQ9|yqb^3o4*NVm{r9F_dcUiVR;P~NtUnFAq|C|24 b&ilRn+?RVLOT!o#7#KWV{an^LB{Ts5yOy-E literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_30.png b/assets/tiles/05_turret_30.png new file mode 100644 index 0000000000000000000000000000000000000000..e50fca1786e661907492321cbcc3a158b1073c9c GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfDV{ElArY-_r|-=@Y#`7o z-^_DBktu~~xxt-XhA}Iy>#Q{K{w2~To&SKBr=sI_L!M8Y&A;v`u@?LSEM6`5%H3a; zFvZ0_VwBT*`hDAmjZ6)fKMKtKvTuT+(y?FjPP+IroR9G0WKd9g{;OrF%1*=Sa~T;KZr{CU$gj)TZWX^S^sz((^FqfYfvw97J3`z; zLb#v3kehRYu|i<4*GAq6*(c}JF5F-BCnGR3_}1HEoux;z_8Q(R-u38N+Y-?O%nuzF zPCFBJR?fq7!{I&qTvB>Wdt&2%I9F-!aN&6%Xz#LYeZca^2fs+f`2RQkeVx~8)0u^? UzcmaQ7#J8lUHx3vIVCg!0ERWN+yDRo literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_31.png b/assets/tiles/05_turret_31.png new file mode 100644 index 0000000000000000000000000000000000000000..bb696cf9c960ac23918fd01089b4a845e697aba2 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf8J;eVArY-_r|-=@Y#`7& zpNao~B2x;}Zi73!3}aSY*I8-e{foiyP6e}KsuZJCleB@T{*#X$e*;3go-j5!Mqc_} zVKdL~Kz#UC#=}c0{96yQG01(7{<0`m(LgETx4dhTFEe9=CM&~*sOsnEr?1|qR>UJw z*VL?Pab1Y{qQGZK@1nD34JWi@t$kU(ZkfafqnYOqWNFQbH&0V&(4U#=wbJUr!Q0E? zWaW$nL?&!o`SI5`xtNNI%5zf84~1B!u2zxxpuE9S=7(ly(%HP(QF~rK{;d7$fMMz1 zhR;vEa`f4gqSq|R;R|6n^RI$yk%DgH>UHva1p0e--r)#g$f@Aa({;YiANhC&lEcZfuvcFEZJx8T+<$&6Gp`DwMuWT4%9a@uaDM z#KX2F)6QI-Bjd3$i9I)dt!d+0$?f|-w6D=E?3~f4YuB-2y+Qx)-YTAT@&8SJUpM!k Xdw#ZLd1fjD0|SGntDnm{r-UW|Zildb literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_32.png b/assets/tiles/05_turret_32.png new file mode 100644 index 0000000000000000000000000000000000000000..9d0584488b86b051f35c26fba0414588a9d788e6 GIT binary patch literal 416 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf>7Fi*ArY-_r*F(XY#`ve zzlrC7B2x;}a)Ud&3}aSY*I8-e{foiyP6e}KsuZKtBeMi8qbIVS!HZUioMdNd-n8U< zrOiCQ1M%UT8J(9`@J~G`#gKR1`^%!^UI{J-p4m%xn(}gN2;yRJaJl#M@yj*6okGmB z=0A8KFekgSF{9&Wk8{!4vxXB|geLx-yIO`hPVKX##M47ROTY7Q{FoHEY|1KTxjpZ1 zU43ZCyr|(zZ1?r;<%JJVe-6GVF~M6wE8N%OfqO!+#fM;_X4Bp8qY4ine;)oN(NgLd z=kd!oH|>?_$lW;0$npZih24K0T^jWd8u-O|Jn!3ihr@)yr$WbO3(sK-(cWY>8{uOf zxxy>^G**l0Oq|{FJ!+HIQj1;OOrJg-+Vk~C;G#RrO156#7{s;v@4-#eOO77p^<2rA z*doofHD%qiCk|e`)^EP4Dsh{o-T8G$e$%!l?;|`pA01PEbJgyS%jrM(_4WL;|G(Js Y^)JnKX>^>!z`(%Z>FVdQ&MBb@0MY2UJ^%m! literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_33.png b/assets/tiles/05_turret_33.png new file mode 100644 index 0000000000000000000000000000000000000000..c72472a201cb271800baa8b321f033b39023a10f GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf8J;eVArY-_r`zVW7znh= z2l72|b~(j4Ny%&X*(~m=bDKodZ`Lhcv+btzf+?93ERNhcaQld`&A)?eK3z{d#f&2M zoc~rK(XfAA7Bj!>=W30dHH;6+_Oh_siW#{bxMA~nYJ~6s!!R#KhK>`v_TQG@(ip+C z;3;qB8{_G-m<3{zER*LSE3jk;3|4xSy)KAhjmI=&125C*kC!pXe74-&qdART=kvCe z;pY5|7Mx3Rvt<0!(;vM4e0h=GgS^JcJH2Kxf8)x@|3wuYwB3zr>t5h zzu~t0joV#~7X-C6nFAOPoW8x=_(6qL@#|lVvGx(?i+?LJwEc*aGn;s(vF^h5*R9z+E93v0{=P0d Yx8w2@)1|&v3=9kmp00i_>zopr07AC2rT_o{ literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_34.png b/assets/tiles/05_turret_34.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6e4c30be2e66be3166f4ed2b3d5528339470d0 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfg`O^sArY-_r`zVW7znh= z2l72|Ub990gjnFM+_2~i#bR3LocgC+HLGTxV#F)d{(*On+PnuJ`OOl7RQxyn*jzFH z_%{QF`q-m)a;Z5ISHa=ET6TWXiF>pP#NWIU>by zG`}Euy5)5thWw779kH_xEoETwT{@-2CzPjQRz;Xfrd zIeG7xHwbwIPkqsT@l}PDTv#mgH<5^$t5w#z1+)Zp#moh2~oBUg>33|NqCA zeJZYh4Ib6(oV0x-TTQgiauWwe2L1KY|+m$4>3$h%K-Z`fHFDxujTiCgZ~WReRP3<^=A#`8xykD){0pCR(q*RGOzJj{XeSFr!8H168hzpR%u^(T(?-N h`Stbsv;V%bvOK(Sw!YA;j)8%J!PC{xWt~$(69D(}w?O~^ literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_35.png b/assets/tiles/05_turret_35.png new file mode 100644 index 0000000000000000000000000000000000000000..6b60c29b1ae08e960acc6204ed88010a5cb827f0 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfMV>B>ArY-_r`zW>8;BgU zUnO^--Qf{S>WW=yokl6=BWDzel`V0LEMmU0kz1(!1Mi)sWgkDw=j2>o_*X@{DWb;S z-ripBKz#Vt=JpRiZAHz*7(VQ{KWFkhZpp)mI{$+wp5RQ7Fh0h>FsJzKzlRkJ8;+n0B&+HE7|pl6z7OiThHg+Wmahkao|k zw5(XXA<*I0vSSu!j~&^za`HOHV(y+(rF-XG{OT-N?9hMU-LnJ!o?EWHdHs}!q2m9K z5<7*k$0m;pY&7$A*<;+-EKzY_Wzb)rf2?Jlyn)|lvuRy>%NR8}-ha?2-pQ-E%#Ndq zN3@0I<*$RYTy`qd$OZ=J-cU*xy7eGMqe#_X=Hsid-64g6m4NF!Uw$*LdVn1;EWDT3&&Sy1uq#6wF8=syMRC&Ny{@1!) zl{^kA6BfQV@Y^h5@g?@6sls%Jly%ddHOMn2{`>gt))ko@t_rg@2lG###hk-`q%XqT zl7W@M|Ga+E0gJPXKK_ngm(0LYXfbca4s)rBkO^tG^gq zvMw=RxLxJ3iTTYX*{U-8>rkA2`YOX6b$>6viNAmJ)0w5xJ)yf9 Q7#J8lUHx3vIVCg!0Kb{9MF0Q* literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_37.png b/assets/tiles/05_turret_37.png new file mode 100644 index 0000000000000000000000000000000000000000..1e3c996e541454319567da662ab41fa3009f512e GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf{+=$5ArY-_ryuNXHV|;N zU#)wn5t+?#f!L?GyIH$kv-Md$!BX{GhA_iWDId$h& z9X9Y=b@F%ixnu^OkMrc}EVl5dDn2nw;b0GvRtgnNecGhk#g@pCXD4jhRI*a#v%;Nl z|82IXbiKN3`+5!Ywwq=%Y)Wi++LWT-z%|D67I#viY<_&#jV z+`sL_~~VeXPOJ* zZEt?l*sh`b&C=}Hj=R^^FrH{*oW?zAF9VkgQ>)jeokh(Bp1m1+YCAi6WzX2`KQVnu xSV1St0YQ70nD86dKOZ!0yK=n#?7y$fcNQI&Dw)6k6$1kUgQu&X%Q~loCIFTOt@;1} literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_39.png b/assets/tiles/05_turret_39.png new file mode 100644 index 0000000000000000000000000000000000000000..a0256e0412a0e9098dad650de118528f3cfe599a GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfKAtX)ArY-_r#tpFD~Pn! zs}(c&*tCehNV}A4?%RL6{Go;Aof9zNT6pTniN?A61d;)b=2H^j0vxfd`z_);t;yDL+q_x}AN zIpzX^>95aLTZkN*B~T-6#ld|^N-0z@^=XrB6~7|D67I#viY<_&#jV z+`sL_~~VeXPOJ* zZEt?l*sh`b&C=}Hj=R^^FrH{*oW?zAF9VkgQ>)jeokh(Bp1m1+YCAi6WzX2`KQVnu xSV1St0YQ70nD86dKOZ!0yK=n#?7y$fcNQI&Dw)6k6$1kUgQu&X%Q~loCIFTOt@;1} literal 0 HcmV?d00001 diff --git a/assets/tiles/05_turret_41.png b/assets/tiles/05_turret_41.png new file mode 100644 index 0000000000000000000000000000000000000000..a0256e0412a0e9098dad650de118528f3cfe599a GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfKAtX)ArY-_r#tpFD~Pn! zs}(c&*tCehNV}A4?%RL6{Go;Aof9zNT6pTniN?A61d;)b=2H^j0vxfd`z_);t;yDL+q_x}AN zIpzX^>95aLTZkN*B~T-6#ld|^N-0z@^=XrB6~7>WQ`)E<>+&SW`ogxd2s%&J|JpO)r zYu!5K1zp~TJuS?__y3lyRa($)ug|sVLx~wXL&NpYjpruUSbbNKYkr}<&VF~#3vW%G z;**bJgsm3+&5LGwz5JU1__gPOOK&M(K*vt+YpXbaa|9gOd!S_cJgs OFnGH9xvXpeKM>UJ)L=A?*1spDt9Yz7G9HY1#oDS&8GT62_KY3vBtwL?%QR~(td)}wM z`JwK$Y_g2V*Ilv)w*0qUa6Ub=$!@>>ys7sCjpjbl(-8IJUD(!nRl51%iCY!ZQ&oZ+ zlwMSA-DI~v?%dPTNJde;#2K9KYWrV5jR|qk|F3uY#DmM{*%%m(9oN0(_v_`oy?N{| z(L3tiaxE%fx?zjz;hl;luBVUMupeMoV1M$8Pt#H$Qgp!{)$KwXcb|;DvinziI%_NMy?tbrY)rczZ!z~^f1;Oik-KWLGi(i^2IYREYD)h`(J-B zK`lR-)v0AeWz_Bi=^SUg6K<=^D;o4i&Jq#j5Iw}op0PpZ_oSG<$kmFaeGfu%Vty_o4(= zR;|UezuvlCXC?RQxfQco%;6OZLOUPL?Q7R!F8fvPdXVk@U3&(Gy83-5>#XLdNBPdK-{nGAB`2); zyw50-YeD&rb(6Un_RZUV&+Kf-$_FvR_dF$-&lx^65fGL$x@a_k$#3S1EyBk_PCImM zUHA3NPcgFzr&_q*nF`!);pb!M(wd(%W5I*du5qafQ#%D@UKGe2pJdnPx?Hime?p4y z7XAVz@AfsJ!rvGR9t37NiLZE_k}FXVx>iOwX2QfS^&YPvab+ZUl6Ne<1U hPfd1z{rX2f=heQx|Hbal85kHCJYD@<);T3K0RZ)?w;TWf literal 0 HcmV?d00001 diff --git a/assets/tiles/06_splitter_03.png b/assets/tiles/06_splitter_03.png new file mode 100644 index 0000000000000000000000000000000000000000..d7760fac24772fd020a802c9e0cdfa95e09c713a GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfnVv3=ArY-d!@ao<83@c} z>tAs1fPT|yE>W9?9UlZ986HXY@K=7p$nvq8`72*(U{LZbpR}x|{Htb{zsITF@0=7k zr?Dw*F`vY?-L|*vB-Jy1KmPfvs((`8oSiN!AB707nmOy&!rQN-o6R%5lvq#n>WOn_ z|9)DdHLsgz#iJk|<%b83lv~dK#Pj0i{Uw@_JFdQCU^wu%%=NL#{Bw76t~mbDT4%qz z=Y_MT&c>9&b)2#nYs}6veBeAGSj5}jGN)q=Pe9elvo2?4KQV4Cml2VCu;z38!YodP zn)cOJJ7fNP`3ic?$vR}kS=$l3qlc}gYqy0rn^Q;fovCF`^ED(nHeNH#OJ;MLv7s=k z{lIe09`A(f>hfv^eJ3qW8Vj6i@s?R|sPGNvL3yu9XR=qPG_ch~>888uhi_IVk{`n1P1sWR)eX!tFzpZ+}m Yw9Ga>o|!@!3=9kmp00i_>zopr0R2O?p#T5? literal 0 HcmV?d00001 diff --git a/assets/tiles/06_splitter_04.png b/assets/tiles/06_splitter_04.png new file mode 100644 index 0000000000000000000000000000000000000000..7e9c47ca72bd63ce4efc8c83e9ecb41910cb42e3 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf1)eUBArY-dr^k04G7vbn ze4%?l{)X4`Ewv#T2bnwg<(zEVDtKOIwtQu1TCw|{!(QiFjg^_Re9~^Q>|dUB=+8dC zOD9#lmQ9us`MOK?z?T2E3m$JaaXkLMKmBR>6d(1S++MB0zAMs_zV;t1NSV9mv{6t% z!=V>dTQ~K^>p%ar^GpNRbORj@_hl8=Pwza@Fz;XNw224f@7FRg?D+eC;pY?^+p_hy z883>hv)|qG!dp|P_+-I4&e)4ZhUXbS@Sb4YInCKC&n1jaBmd-CmpAi1iG6)*p=EsF z=egTnshkXZ4$ZAI>vge^*Nb3N=EslC zB+i7m_egRi9tu0M#{0o#mM}-wYj!^k8V{yt2Bj!W;S`ryaIo-=_a}?AxouY#Pb<#a z^ol{%;QNVnUt4k+M0QM{cY!7A)|wEW8N0%|IJNFvDXssL6tq+N*REMF4PrkDuaPX! iJo41!*O#wzg(!FOGqMfx*+&&t;ucLK6VIj>BmH literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_00.png b/assets/tiles/12_core_00.png new file mode 100644 index 0000000000000000000000000000000000000000..eba6f1922a7a17e4234ed57ce09b6f1fb0dad188 GIT binary patch literal 763 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!hdf;zLn2zwhVRY0Z6NSZ zr`q!(PZQ(Pd;yay${d>%`8hYSy@*cPc%4NcVg0v9?S^kIUbwM9*5$DN!;BoWQUgER zxgK7b?O$fId^+;}U&Zm)swbDQFswD55)`rS+JqUt@(Z`JF}MWw=-gKBdNhk?ZR$-q zhN$yFUW^Pj`&Mo}mh;w{G7Q7l+w;Z#@Iov8c0Oc;$NT zs`n(%%v&!OwS2iyeR68hhiR)zzZ&=V^12*&8uKK`Gc)1+@$=4^moGhIo%H>$BEtd= zKR-*W(@*Ydah?>Ob7$%lmlzTC*ZWkKf8M!?`5$xciPeWT&R9NGM{|43+SOl|Ki{Hu z|JhkB7PYrale#OrY|b+>Bua!``~7djHb1W!=Q1=Vs7&6ZTWL`#(dOoTl37LhyYCEN z`SYa*rshoA^Y+2IO(M_!-Mw4;>)SW(-EY~pZ~y+^g^%H5M$hAq4L0WsZR7;{kGT~w z?AZ6OY9H&S6(y?iXD*-mD&v1%^N@kdyywSi&sjbwos(WFUE!qnEc5vcVavjAa&r5o zZkj3ZqH3m4-w94N{fqnmm=%1|=sNGIu{&Di=vJn~wn<9cH4k>y*57z=VpHv2*?Jb6 zp9ccGLa*tEzg~4uSmU6IkK%{FiBI<~vIu>+wauZ-^t$eZ(2LvhSM}KNv(4G#{jJ#l z#;g6jd#+Dl|7C8jwRg`S9)@10D`6pzF5Za9xb^CI-fl+$mK{5OwETPhT9dcwKvwPa zQ{Uu@j7qlOeem?@@A?ZpcDrPyUpKt`$@6Dt(>D)O*5mU*3#sYKYf9!=>gnetaeMg3Ql5J6`QRdo+l1ft=8JGm{$$Qa&$ke{E8; zT-ow{d$6Fq-(rn2twia%E!Un~9aw8HarZCF3o?F|8*SP@Gdz;o^~jGiMe6)dsgpAg d*gF2;y*6?4?|`OPVGIlm44$rjF6*2UngDuEb1eV> literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_01.png b/assets/tiles/12_core_01.png new file mode 100644 index 0000000000000000000000000000000000000000..1a9c453dc5346fb4e48227bc0dd0724be55bbe89 GIT binary patch literal 777 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!7d%}YLn2zwhHuQfZ6HuP zZSRr{wu6nA>^Y=fv2$^3Qsn2{#P%Y-V&iodfrRzn9`zf(xhQa9siSpAo4r!s@w8y} zhgU9lPMK2XabIPE`o7(dKTf>fxhRm0Au3yA>4u1P3Wjrg7H(x@U~%kFxv9u;XcBL) z>PbEZsp~;rj0`e%E4LmiFgmdm6$Z+sp!3Rq2_KHo@b!AYz4Cj;NHsIy;~ z;d<_B=c2&0Ss9O8&RmE-IW?$2>~!cy|9$3J?`W|T_ey^= zG+cfek?o#6b5pd4VrtXm>!PZH^Zndk?@?L)b?0W=f6Tro79TR4f3#KCa(l$Ou8-}< zcck2(ayE(E=brcRXPYH5XE8C<+}B@Jezz`j&K!fafrScPZjr$s3ySW4@0}RLcEau4 zY=gNy#j-23%{=dIDTt1~_3Yi-x3PbI{o=lTR?6JG{J#qy!^4D*!-@SSzJ(TV1o_(B ziWqk6`ZZ@hlcrYg$>*DQc-S64oXm6o`^04{3+EMo+tK%VRUVW6iJv-od!M`b&6)fA z_xhQ8d^k$>_^`S^VF{l0BEC+_qEeuxQt;GmU5-PO4t(e-_|)B<&(QGvxxSma#m3j) zv}HUuX~!Rb&**MvFeS+KOZU@N7pj>=B__D%b<3StyzI?fzvD^OYoitNx9$p72)$^Q zALJItZtHh%*{@2qoL~9O`?EEe@4n6!oj<>xrJ+l}wA0H%LaKF{r~S6srZ(pf-@M6Q z5+B#M@pNTN1xEV@HVY?`SSPw52k*(cYR|ZyU+Rb2j>N+2;MrzS*pJ}i0y}A zX4T0Ptg~kc{5$k$Tc1guvtPm8I@c9TfI#0hJqOXbmBONAXOy=9^= zCp51#T=;&MxXDdV^*Q_Bc2yKhu_Ue)-uBErd+uw7{zEQt<@1@ZKAR$Zy3~SSp)c|7 ozF@|gw~FoD%G5si2-GqEP}?oLGH8hy0|Nttr>mdKI;Vst0LMFOTL1t6 literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_02.png b/assets/tiles/12_core_02.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7177ab6879f993da9294ab710d34be641c09a9 GIT binary patch literal 785 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!H#}V&Ln2zwhVRXLtYwmum`@G%Qn)kl^5(a_ehEswfbiyY{^tW|9mSA|WOYTqs`}MCy zMq9+%tQl6=cx$pUZ1|BTb6ldot#$qjhovEn9+M`|;kzT?^!U@J*+PuD(=z?Lic~Eu z8@%+3*0sIo54!6ntGcB9p4Yl5Ox|Nq1E9KBYTtbxy4j zZ_%gFduN;$T#nN+o6p*@h=bvQgk2>Gx_|rf zWv76aU(W5fOzslzKE3^6n{bl7El6u~-Nu;Iuk#!@)fRe(+|EnC=RGM|EH0TNC0u(q z>n5#P-%6)WeD2si`TEJacbvh0%^SZ)#E}K7TfRQDWux`gO>*?Gq+1ynR-RpWpspbJ~}CZzH1FOU|c1I4?RyY}Pf- zRQ=U+*ngO=tU7sud3Bq>zeA5UO%qw??6=`<*}?$NrB9@Ts}4VU;_z48uwYilihZ+V zbfz+VQrzg{+|0S_V9UPKaTiq7r*8OHruFFX%GXs(y=Jt{x9IaPZHQi|tpEDCL!rgf xBcEi>F?VD~h?RRO+^slw-NTRl9p|C^T`#u%=COX5!@$76;OXk;vd$@?2>@AkbP)gm literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_03.png b/assets/tiles/12_core_03.png new file mode 100644 index 0000000000000000000000000000000000000000..7baa29be03b9e3b21ca56f84f920fd6ce27d5bd4 GIT binary patch literal 780 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!mpxq^Ln2zwhVRXL3FhY!w3sWe z=JCgMZ|{iiT)%10=FeyEpL@5ZDPabq!z7geuf&~E&Phgcik?CY4bOjeEV8vZuYcmg zevMnq4r}$6iZC2_)a^Mb!ANeZ*+i$MA)OwRCePu!Bk1({)vD=&jJjcw{%u9d7M2aS zG>X=R3Gf)-brM!iX}RaUZc5YEn6;nJ+L)^eFiu~sG~LaMJ=(rb&S>(~Wf~Lq=D<*1a~6 z>_1n#VATzk%DIo0ZJP4z+ugghKYsn<-u;$s`}XhuUHBO4>Kh(^Y_RAnw2^!8ojt0E zVaL9IMRu&4R+^~BpE+#vMdorO$MsUd;~UH77ME4XKM##`#m{w zv#R39tdpl(9FBX37r6Mn_t9*bt2tqN)K$#~D-E8; zzq=}$*gn~OWu08-(LaX&^O)+c2e8~SH`m&;=MN9VQn!%nA%Ffk+|GFQ>v-Po#>W;r zcKm4hcKWntiOlgAwUf_%lPfAJ*?#xI%a_0F3nXj5l&*Qpyz9B~hvmn;`F;O$hU%|& zV)S92{rK?8=RaP`K8O7$sXVtku=m2m@Vn0)DlMKK3F3dw sc*JncDQnRQc{b1gd-$=-aUPOxU$FUFlG3!33=9kmp00i_>zopr08u@6JOBUy literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_04.png b/assets/tiles/12_core_04.png new file mode 100644 index 0000000000000000000000000000000000000000..7baa29be03b9e3b21ca56f84f920fd6ce27d5bd4 GIT binary patch literal 780 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!mpxq^Ln2zwhVRXL3FhY!w3sWe z=JCgMZ|{iiT)%10=FeyEpL@5ZDPabq!z7geuf&~E&Phgcik?CY4bOjeEV8vZuYcmg zevMnq4r}$6iZC2_)a^Mb!ANeZ*+i$MA)OwRCePu!Bk1({)vD=&jJjcw{%u9d7M2aS zG>X=R3Gf)-brM!iX}RaUZc5YEn6;nJ+L)^eFiu~sG~LaMJ=(rb&S>(~Wf~Lq=D<*1a~6 z>_1n#VATzk%DIo0ZJP4z+ugghKYsn<-u;$s`}XhuUHBO4>Kh(^Y_RAnw2^!8ojt0E zVaL9IMRu&4R+^~BpE+#vMdorO$MsUd;~UH77ME4XKM##`#m{w zv#R39tdpl(9FBX37r6Mn_t9*bt2tqN)K$#~D-E8; zzq=}$*gn~OWu08-(LaX&^O)+c2e8~SH`m&;=MN9VQn!%nA%Ffk+|GFQ>v-Po#>W;r zcKm4hcKWntiOlgAwUf_%lPfAJ*?#xI%a_0F3nXj5l&*Qpyz9B~hvmn;`F;O$hU%|& zV)S92{rK?8=RaP`K8O7$sXVtku=m2m@Vn0)DlMKK3F3dw sc*JncDQnRQc{b1gd-$=-aUPOxU$FUFlG3!33=9kmp00i_>zopr08u@6JOBUy literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_05.png b/assets/tiles/12_core_05.png new file mode 100644 index 0000000000000000000000000000000000000000..30f98ad5ca7465c9b8c7d6701aa3a376c5048aaa GIT binary patch literal 839 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANOKe4Z|jArY--!}sPrauE1u zFmcTsz1CKjKMWo(Hr275?(~?bp*ry$uSVtq)k&%u3m2ZTUeY_sXwjY*>pr--JYvk? zNOd|Yn)2<~>)6{nC%?t_p|5EoePUvds&ykLsPNkK!s7O-rqR!ATI_73AY(% z$nfT1WGMKtXo}F^IP=Y&JY0%K4ptT~XSP^71zFmB+0Nq7UHPU{ zL;c`EMiIA($)QneFR#s9$ir#tB+n}DbU@O7S(fqnUSAFejz+h~lD)@@^>+9Lm2dd; z_xR;&$1aJnUi!XAiXmZd+|ySRb%RSn1%p&9exwyA>v}Q8tq;HUwQha)*=K60!R1-~ z`3qQYz1a1(=i)_!uw5>BHZxbfZ(eP&^!={4E+6dXnSOQYqc!v9#~;bh zU%zAj?xQzv9+huob||T7`uT^`b5ep`y;Dg|5(|4n+UL{nL|*tV)%lSjvHC)>WXw^H zCI-(*64x!C$-RHPXH|EKNzcZZxc&d%O*v=TD4h26)2G*A`+YoKRLtb+JK$Mk@7?t6 z)8zvP4;$PPRoovT)tmmKPW@^^g^SMvGa;E9pR*$L)^Ch3Vf?e}fXv+!_r=`h4Pv&h z-6QY6Y}NhAJnNEv)Tt+*n8I{^^~x7(uWMh8T&sB@f9sy$1Hp->_wTzN(o!w6$LH&3 zkDfN!ue*Cb>~2#Eu(cBUc<^94!wHi`i_qY@%H}@jDB6ezHuY}1&2l4Un}l9-!7lD=cJY>W1UZiN^$IG zmBrFqUQXb(`%o0yuI;TE%)Eqm&XLbqGu@U>e)J$^{^W8Ci-0;MwuYylqD+;eJ2G!P z6?~u~b9?bYH5=bKNE&m%QzAl=D;m!Bmi_4yz7Kz=;sVOwarYr55uji59f6v`Ie{ylgvOmQe z(`y(?zf|X%1{}|j(1;c?pXU?$`+=Ru4dI=-v$8mSUX>;;PHZsXVPx3%e)Y}Wd4?DL zlzi-hm}Z>~o3pjjV(0tc$7TkxoN#+@zVQBQxlavmPs}{AS!RBg_iVfR;$rDN`~DqB z`q%OL^=*44_J*jvjbE!;4R|)jtq)jj-t&YZU}cTf941@ad0uu>Y+7GrntwCwd#}vn zoNWKx=5ghm_pfw%+8DRpZjZk|ck=Z)CpwMG%fDNy3EqC|{OHBSk4Cu`O6nDHQ7pYr zmn(Lqec02t>p;=dP2!Vhoj(2kl%&6bjgnf?Y!1ISyIf84Hm_X4VX zv;I~Xh5nppu!H|W<=iRCmxXrZ1-j<%zrXV7(>a~07v6tPUf!VJn)~g+ z{A(k$IMKa!e$)2d%T_B**uP8Y;L)S*3?8bB)+`BHZQj$Vrd_Y|tY2fQmxcZRhCioI z>uF5&x^{E^q?`Ag{e)xB$bbCv=c)aUo_}9UbIve_oP4oBX8rjK*ZeHPB2|?RXy04o zkO9< zlje69s}w4b5=a_#EZPBwa@1WF$oGJ zN?IQNfPZ)UO2=ce4JoD;3RQ=o1#1#Lxb>$Ip*%!~6+73I~mp84~v2 zPuzb$^LuL1=~qwJZCmy!$D+bsA=!#EIMOK3EPly-_s0gx=TC+P8rA))@+!G@y3JQz z@sR}^L&d!5Rr$BSo+&qSTB@Axu)TVs$X^>4rSCTWFEw2oQl8X`wl)8Ymc6iaPS+lv z!q7;svx`@+e*NL=S97^{?+Yp`|N1{+xL|30yy|a@Mc>9a`-R12>r~hq%6{LD7CZ5D zqt?$7p=Ar7OY}Nd%xkykoBDgsX1CIs-LXj)8u}V@=6HQ95enH?{9x_1A9W2HQ3rSI z{5h{cx#Cq|)yg^xC3OqGdmL7$H#goBd}K1qS6#7aU5~hgoS^8=a~ys-x4+7`i>%#r z{$u)qCFOIncBOs|dY}H8HD~ucO9QF)l{)ROxN>&SbIad)ccVE6ducGLaC__=}iZv@r&Yhdu zx@=9I&7J!TFJ?UW@q@cBF0L$b@x=>O@k=-T<+Zf@RZ!o4{J8x8gUMfRp5M5MFF;+n zIcv|Gh3~8vuGoCarD3^eq`I>9m6IoSr9@8V=2q02D4erK;+OJ-wGcN2}(R?rG*36j`dJOEXL_dB%P}t<89CDa{ zEw7#I>k~VJ6kYP1rnLwA>AZeu(=esY_3TOkCr`c<_p(XBjqXh!*qw~FN`<6N&u3s@ OVDNPHb6Mw<&;$SjKZ`8@ literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_08.png b/assets/tiles/12_core_08.png new file mode 100644 index 0000000000000000000000000000000000000000..f0379edbb704c0499a233e5ca8bb7237e4eb1254 GIT binary patch literal 841 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANOK0-i38ArY--!}sPrauE1e zptN(_gcJK5OE$?LR1(ze(C945e=vzHYJ!dcZGQ(GW>3olcuXlM&a{o~$@A+xPw;xg`XCB~pdJz-bX)Jgl zZSGfw38~f`f*Q&%Zf`rzaN&jPxzveU@90KuGp=e9x&3X&lSZ{qI=82uh`rvr^-`SWF`51+I>Z#-{`jf2szeVm(Ls;p-Y zt;|=-54saJ?bV^9fB$Oy`SYiD`g3)j_Qmx|><$0U>h>LHeq?d%V}-;2XV*OV7_MKp z|D?0v%MY!eS&~}Ui_eHF+MIWmIex76T;)vji42~b4(Hrjw?M!$^zc=q4B28OaU}L{4ZcafFE}riloqJAk z_`R{XE95Tnw)^c5>x7FhTR9k>OzrmDe=jF=ulgDBg_E8dv>qtjb*ehED(K--fgg4I zC7AZEzM9I&?;85&YrXIE50fTu-}(2B@aohB`))UUpQUp1;P>V~d^2Y8X|6l{{O6)M ziVnLUxy})nmtVf&`s>hn`+QS>YyB*+ICT26a9n)-U-q*vcHiE(k?+IDp5}Kgb%$1! zI^9hP{lMTqd6}nMc!W7`aqO-&OS!izs$2MN4_Q&N_={xlcem$n{}x=6=gn11VrbRe zeu{gS`j?G&R#j~baa4bPzf{;Hpr-tS@dcxa=11pxX*zZ+xW>WNda{GBUUssgRb{L_ zd&90ur|X9+8FYDHw*_meE}62b^M%|3(@DmS_RO6142KLiNz9%Zxr%{-fx*+&&t;uc GLK6TZN|b*9 literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_09.png b/assets/tiles/12_core_09.png new file mode 100644 index 0000000000000000000000000000000000000000..c33b0ba7a21d2991b3c49eb4256e4c7962d98149 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!&pcfmLn2zwhA+%}>>yBE zrYyNTF!XHv%stPCmi4OX{bC z$?cC7*UL&5e4p@i?p$+gV{7AVUbgS53`;V(?tkAHvsTe?Zcm^{G(*Gl))Sj}ZS>ci zxUgU6HUoo9ddd~o7>0z;M@@VU=k{dJ_E`A1C(C8hoF^p;MSQP6UD9Se@V$2HjVGK8 z8eO?ZIsEt*e0(zLv|4z|dfY4h&CpY zm)++qtK~~;x?e7dc2q1{)z)2k!}6Jn-_zSwHGjfRr8zBlz0}(xuB$QF{=&(#i*^)A zTkL$^x?E+--Lsz$c{M(iyEt)n&x0fDZm%y)xw-6C-+rcTG6pi~OZ@i7tPS0(erC}Q zvmSPX*b8q6_eQ&*f zX1p*GWM1L3Q%&E)|HQ^SW_u%iCOrAGJF|&x)qB1wwp&)8w(SVkRIP}+k-^gHl-_bQ z{&-4X>yBE zrYyNT@akW7>FFU^t3_P2e3t%ZK0KjCZPL<~TSp9j9GG}v)zycK%MbK5@y&J#yKwac z`=XnD*LQDQ%)GaK&E1cCZqB?pGcwzxY7K+JX`_mH?HYaylI&(L(%H_ypvd&(Cz}(C zsbtjY&%6u=3f0_VkFYYB-9NL5=kv`iAB8nb=6E)HsH$7acFZ}vYoC}XL&ZFG|C?#H z3{#$NOJh-Izwpxa_)HJyoFdoAyroT>?qu0IcAXTy!~A^0yG;%x;U1uhOox*!lkVt;v(vJ>2eIPqdqTXxCobu-uc&CY5Wx)As&ZSXlhox~Ber z^Y-iFJ;(k3yYMlTf9JpPzTD%o$nU>=<=^?EiWqk6`c=1!wZ!(EYW#YqmsNd7jauIS z_P89f`@AK)d}&Sh&o%Lmibbp1UWZ<=e&*u$^mbL0|osrPWZYNBwd#^v-ngKoPT^iW3;S+OuCZ4{L#)e-&>9v z^9;K0e>DfZuwREeH=Z}(uY+IfGs z8w@?h4%chrbY`2gya?aZ@%hoGPwo~HHOBMy`KMY>ud%5+bo(`T-|_YT9gTmzDOH8Byw6e8WunKV)ArJ-LGG_Oirv-cz@RKD2wna$VMpYiiaMtK?PpHdtC- zs8?e1d(WulrY64Hjp6Hr8-I2laZeYnn8ESou9@Rx8A-?U4$QwsQRDd@g%R@rwtyh>q`C~Fi=_8nR0R=Cnt|xfy$Pw(jPBmH!NCkSZ$(ciRmZC z>}`)fuG{;z@t#6<`JVT0&%CMOIaCnC=n(nt;V!{zvvrr8Ne`a#RF2`nZ^KVD?DzYn zt+q^iZq4w*_H?N-L&IV7(?$J1b8h|Wq_9r@#6iC6(scvx{9Bw%j~AucJsv zM#f>isO2>Up5s&V4!5;zxlnyD*1T!+y_~D(@0hD8GOWAKs^@u%o3HMlRfyU&HSG!e zp7$~^xE8*;vUqdJwNOWoX%8O6I(i;(Ei`)PU0^kTvg{}MjAXm+o_7&TJ1?mgy*?YZ zR)3nO^ZxU*PO(~jn{-3VcS5Qpg8~OrY4v$&(`%hA?|Q@<4P?S=4<0_)tZ?Dp6debv zqImVsH@BQ)jy+4F@h zmcBpu`0;cvF=3&qxLpm8k8-Sd-RPIU(MM{1WApF281{v0^7hG_3-N64;Jf3}#9V!E zMeD@pyVETH@f4;sKioBO*Waqmp+D!PZ1jmb%dw!m@pv6Qp+)?|rQ#CAe&A!~0>$7auds;B`*gD*=j?=lV&$7WguBEcD@~5&S-+syb z{K+@(aof$bdGPcn=kw3k|1XfJEwjA#j4}2%&z_?#dlqKSU9x&}Rz!pS z?prmf<@3dr9oL!f_gj0;Xq&(3&h^TM`%dilLeDpTD>&8o)KZ3B;QWTu??oJTeVns? h;yk|{sviHCe$3vqF|&^Q2?GNIgQu&X%Q~loCIBH$aDD&) literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_12.png b/assets/tiles/12_core_12.png new file mode 100644 index 0000000000000000000000000000000000000000..1a9c453dc5346fb4e48227bc0dd0724be55bbe89 GIT binary patch literal 777 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!7d%}YLn2zwhHuQfZ6HuP zZSRr{wu6nA>^Y=fv2$^3Qsn2{#P%Y-V&iodfrRzn9`zf(xhQa9siSpAo4r!s@w8y} zhgU9lPMK2XabIPE`o7(dKTf>fxhRm0Au3yA>4u1P3Wjrg7H(x@U~%kFxv9u;XcBL) z>PbEZsp~;rj0`e%E4LmiFgmdm6$Z+sp!3Rq2_KHo@b!AYz4Cj;NHsIy;~ z;d<_B=c2&0Ss9O8&RmE-IW?$2>~!cy|9$3J?`W|T_ey^= zG+cfek?o#6b5pd4VrtXm>!PZH^Zndk?@?L)b?0W=f6Tro79TR4f3#KCa(l$Ou8-}< zcck2(ayE(E=brcRXPYH5XE8C<+}B@Jezz`j&K!fafrScPZjr$s3ySW4@0}RLcEau4 zY=gNy#j-23%{=dIDTt1~_3Yi-x3PbI{o=lTR?6JG{J#qy!^4D*!-@SSzJ(TV1o_(B ziWqk6`ZZ@hlcrYg$>*DQc-S64oXm6o`^04{3+EMo+tK%VRUVW6iJv-od!M`b&6)fA z_xhQ8d^k$>_^`S^VF{l0BEC+_qEeuxQt;GmU5-PO4t(e-_|)B<&(QGvxxSma#m3j) zv}HUuX~!Rb&**MvFeS+KOZU@N7pj>=B__D%b<3StyzI?fzvD^OYoitNx9$p72)$^Q zALJItZtHh%*{@2qoL~9O`?EEe@4n6!oj<>xrJ+l}wA0H%LaKF{r~S6srZ(pf-@M6Q z5+B#M@pNTN1xEV@HVY?`SSPw52k*(cYR|ZyU+Rb2j>N+2;MrzS*pJ}i0y}A zX4T0Ptg~kc{5$k$Tc1guvtPm8I@c9TfI#0hJqOXbmBONAXOy=9^= zCp51#T=;&MxXDdV^*Q_Bc2yKhu_Ue)-uBErd+uw7{zEQt<@1@ZKAR$Zy3~SSp)c|7 ozF@|gw~FoD%G5si2-GqEP}?oLGH8hy0|Nttr>mdKI;Vst0LMFOTL1t6 literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_13.png b/assets/tiles/12_core_13.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7177ab6879f993da9294ab710d34be641c09a9 GIT binary patch literal 785 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!H#}V&Ln2zwhVRXLtYwmum`@G%Qn)kl^5(a_ehEswfbiyY{^tW|9mSA|WOYTqs`}MCy zMq9+%tQl6=cx$pUZ1|BTb6ldot#$qjhovEn9+M`|;kzT?^!U@J*+PuD(=z?Lic~Eu z8@%+3*0sIo54!6ntGcB9p4Yl5Ox|Nq1E9KBYTtbxy4j zZ_%gFduN;$T#nN+o6p*@h=bvQgk2>Gx_|rf zWv76aU(W5fOzslzKE3^6n{bl7El6u~-Nu;Iuk#!@)fRe(+|EnC=RGM|EH0TNC0u(q z>n5#P-%6)WeD2si`TEJacbvh0%^SZ)#E}K7TfRQDWux`gO>*?Gq+1ynR-RpWpspbJ~}CZzH1FOU|c1I4?RyY}Pf- zRQ=U+*ngO=tU7sud3Bq>zeA5UO%qw??6=`<*}?$NrB9@Ts}4VU;_z48uwYilihZ+V zbfz+VQrzg{+|0S_V9UPKaTiq7r*8OHruFFX%GXs(y=Jt{x9IaPZHQi|tpEDCL!rgf xBcEi>F?VD~h?RRO+^slw-NTRl9p|C^T`#u%=COX5!@$76;OXk;vd$@?2>@AkbP)gm literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_14.png b/assets/tiles/12_core_14.png new file mode 100644 index 0000000000000000000000000000000000000000..7baa29be03b9e3b21ca56f84f920fd6ce27d5bd4 GIT binary patch literal 780 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!mpxq^Ln2zwhVRXL3FhY!w3sWe z=JCgMZ|{iiT)%10=FeyEpL@5ZDPabq!z7geuf&~E&Phgcik?CY4bOjeEV8vZuYcmg zevMnq4r}$6iZC2_)a^Mb!ANeZ*+i$MA)OwRCePu!Bk1({)vD=&jJjcw{%u9d7M2aS zG>X=R3Gf)-brM!iX}RaUZc5YEn6;nJ+L)^eFiu~sG~LaMJ=(rb&S>(~Wf~Lq=D<*1a~6 z>_1n#VATzk%DIo0ZJP4z+ugghKYsn<-u;$s`}XhuUHBO4>Kh(^Y_RAnw2^!8ojt0E zVaL9IMRu&4R+^~BpE+#vMdorO$MsUd;~UH77ME4XKM##`#m{w zv#R39tdpl(9FBX37r6Mn_t9*bt2tqN)K$#~D-E8; zzq=}$*gn~OWu08-(LaX&^O)+c2e8~SH`m&;=MN9VQn!%nA%Ffk+|GFQ>v-Po#>W;r zcKm4hcKWntiOlgAwUf_%lPfAJ*?#xI%a_0F3nXj5l&*Qpyz9B~hvmn;`F;O$hU%|& zV)S92{rK?8=RaP`K8O7$sXVtku=m2m@Vn0)DlMKK3F3dw sc*JncDQnRQc{b1gd-$=-aUPOxU$FUFlG3!33=9kmp00i_>zopr08u@6JOBUy literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_15.png b/assets/tiles/12_core_15.png new file mode 100644 index 0000000000000000000000000000000000000000..30f98ad5ca7465c9b8c7d6701aa3a376c5048aaa GIT binary patch literal 839 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANOKe4Z|jArY--!}sPrauE1u zFmcTsz1CKjKMWo(Hr275?(~?bp*ry$uSVtq)k&%u3m2ZTUeY_sXwjY*>pr--JYvk? zNOd|Yn)2<~>)6{nC%?t_p|5EoePUvds&ykLsPNkK!s7O-rqR!ATI_73AY(% z$nfT1WGMKtXo}F^IP=Y&JY0%K4ptT~XSP^71zFmB+0Nq7UHPU{ zL;c`EMiIA($)QneFR#s9$ir#tB+n}DbU@O7S(fqnUSAFejz+h~lD)@@^>+9Lm2dd; z_xR;&$1aJnUi!XAiXmZd+|ySRb%RSn1%p&9exwyA>v}Q8tq;HUwQha)*=K60!R1-~ z`3qQYz1a1(=i)_!uw5>BHZxbfZ(eP&^!={4E+6dXnSOQYqc!v9#~;bh zU%zAj?xQzv9+huob||T7`uT^`b5ep`y;Dg|5(|4n+UL{nL|*tV)%lSjvHC)>WXw^H zCI-(*64x!C$-RHPXH|EKNzcZZxc&d%O*v=TD4h26)2G*A`+YoKRLtb+JK$Mk@7?t6 z)8zvP4;$PPRoovT)tmmKPW@^^g^SMvGa;E9pR*$L)^Ch3Vf?e}fXv+!_r=`h4Pv&h z-6QY6Y}NhAJnNEv)Tt+*n8I{^^~x7(uWMh8T&sB@f9sy$1Hp->_wTzN(o!w6$LH&3 zkDfN!ue*Cb>~2#Eu(cBUc<^94!wHi`i_qY@%H}@jDB6ezHuY}1&2l4Un}l9-!7lD=cJY>W1UZiN^$IG zmBrFqUQXb(`%o0yuI;TE%)Eqm&XLbqGu@U>e)J$^{^W8Ci-0;MwuYylqD+;eJ2G!P z6?~u~b9?bYH5=bKNE&m%QzAl=D;m!Bmi_4yz7Kz=;sVOwarYr55uji59f6v`Ie{ylgvOmQe z(`y(?zf|X%1{}|j(1;c?pXU?$`+=Ru4dI=-v$8mSUX>;;PHZsXVPx3%e)Y}Wd4?DL zlzi-hm}Z>~o3pjjV(0tc$7TkxoN#+@zVQBQxlavmPs}{AS!RBg_iVfR;$rDN`~DqB z`q%OL^=*44_J*jvjbE!;4R|)jtq)jj-t&YZU}cTf941@ad0uu>Y+7GrntwCwd#}vn zoNWKx=5ghm_pfw%+8DRpZjZk|ck=Z)CpwMG%fDNy3EqC|{OHBSk4Cu`O6nDHQ7pYr zmn(Lqec02t>p;=dP2!Vhoj(2kl%&6bjgnf?Y!1ISyIf84Hm_X4VX zv;I~Xh5nppu!H|W<=iRCmxXrZ1-j<%zrXV7(>a~07v6tPUf!VJn)~g+ z{A(k$IMKa!e$)2d%T_B**uP8Y;L)S*3?8bB)+`BHZQj$Vrd_Y|tY2fQmxcZRhCioI z>uF5&x^{E^q?`Ag{e)xB$bbCv=c)aUo_}9UbIve_oP4oBX8rjK*ZeHPB2|?RXy04o zkO9< zlje69s}w4b5=a_#EZPBwa@1WF$oGJ zN?IQNfPZ)UO2=ce4JoD;3RQ=o1#1#Lxb>$Ip*%!~6+73I~mp84~v2 zPuzb$^LuL1=~qwJZCmy!$D+bsA=!#EIMOK3EPly-_s0gx=TC+P8rA))@+!G@y3JQz z@sR}^L&d!5Rr$BSo+&qSTB@Axu)TVs$X^>4rSCTWFEw2oQl8X`wl)8Ymc6iaPS+lv z!q7;svx`@+e*NL=S97^{?+Yp`|N1{+xL|30yy|a@Mc>9a`-R12>r~hq%6{LD7CZ5D zqt?$7p=Ar7OY}Nd%xkykoBDgsX1CIs-LXj)8u}V@=6HQ95enH?{9x_1A9W2HQ3rSI z{5h{cx#Cq|)yg^xC3OqGdmL7$H#goBd}K1qS6#7aU5~hgoS^8=a~ys-x4+7`i>%#r z{$u)qCFOIncBOs|dY}H8HD~ucO9QF)l{)ROxN>&SbIad)ccVE6ducGLaC__=}iZv@r&Yhdu zx@=9I&7J!TFJ?UW@q@cBF0L$b@x=>O@k=-T<+Zf@RZ!o4{J8x8gUMfRp5M5MFF;+n zIcv|Gh3~8vuGoCarD3^eq`I>9m6IoSr9@8V=2q02D4erK;+OJ-wGcN2}(R?rG*36j`dJOEXL_dB%P}t<89CDa{ zEw7#I>k~VJ6kYP1rnLwA>AZeu(=esY_3TOkCr`c<_p(XBjqXh!*qw~FN`<6N&u3s@ OVDNPHb6Mw<&;$SjKZ`8@ literal 0 HcmV?d00001 diff --git a/assets/tiles/12_core_18.png b/assets/tiles/12_core_18.png new file mode 100644 index 0000000000000000000000000000000000000000..c33b0ba7a21d2991b3c49eb4256e4c7962d98149 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANM!&pcfmLn2zwhA+%}>>yBE zrYyNTF!XHv%stPCmi4OX{bC z$?cC7*UL&5e4p@i?p$+gV{7AVUbgS53`;V(?tkAHvsTe?Zcm^{G(*Gl))Sj}ZS>ci zxUgU6HUoo9ddd~o7>0z;M@@VU=k{dJ_E`A1C(C8hoF^p;MSQP6UD9Se@V$2HjVGK8 z8eO?ZIsEt*e0(zLv|4z|dfY4h&CpY zm)++qtK~~;x?e7dc2q1{)z)2k!}6Jn-_zSwHGjfRr8zBlz0}(xuB$QF{=&(#i*^)A zTkL$^x?E+--Lsz$c{M(iyEt)n&x0fDZm%y)xw-6C-+rcTG6pi~OZ@i7tPS0(erC}Q zvmSPX*b8q6_eQ&*f zX1p*GWM1L3Q%&E)|HQ^SW_u%iCOrAGJF|&x)qB1wwp&)8w(SVkRIP}+k-^gHl-_bQ z{&-4X>yBE zrYyNT@akW7>FFU^t3_P2e3t%ZK0KjCZPL<~TSp9j9GG}v)zycK%MbK5@y&J#yKwac z`=XnD*LQDQ%)GaK&E1cCZqB?pGcwzxY7K+JX`_mH?HYaylI&(L(%H_ypvd&(Cz}(C zsbtjY&%6u=3f0_VkFYYB-9NL5=kv`iAB8nb=6E)HsH$7acFZ}vYoC}XL&ZFG|C?#H z3{#$NOJh-Izwpxa_)HJyoFdoAyroT>?qu0IcAXTy!~A^0yG;%x;U1uhOox*!lkVt;v(vJ>2eIPqdqTXxCobu-uc&CY5Wx)As&ZSXlhox~Ber z^Y-iFJ;(k3yYMlTf9JpPzTD%o$nU>=<=^?EiWqk6`c=1!wZ!(EYW#YqmsNd7jauIS z_P89f`@AK)d}&Sh&o%Lmibbp1UWZ<=e&*u$^mbL0|osrPWZYNBwd#^v-ngKoPT^iW3;S+OuCZ4{L#)e-&>9v z^9;K0e>DfZuwREeH=Z}(uY+IfGs z8w@?h4%chrbY`2gya?aZ@%hoGPwo~HHOBMy`KMY>ud%5+bo(`T-|_YT9gTmzDOH8Byw6e8WunKV)ArJ-LGG_Oirv-cz@RKD2wna$VMpYiiaMtK?PpHdtC- zs8?e1d(WulrY64Hjp6Hr8-I2laZeYnn8ESou9@Rx8A-?U4$QwsQRDd@g%R@rwtyh>q`C~Fi=_8nR0R=Cnt|xfy$Pw(jPBmH!NCkSZ$(ciRmZC z>}`)fuG{;z@t#6<`JVT0&%CMOIaCnC=n(nt;V!{zvvrr8Ne`a#RF2`nZ^KVD?DzYn zt+q^iZq4w*_H?N-L&IV7(?$J1b8h|Wq_9r@#6iC6(scvx{9Bw%j~AucJsv zM#f>isO2>Up5s&V4!5;zxlnyD*1T!+y_~D(@0hD8GOWAKs^@u%o3HMlRfyU&HSG!e zp7$~^xE8*;vUqdJwNOWoX%8O6I(i;(Ei`)PU0^kTvg{}MjAXm+o_7&TJ1?mgy*?YZ zR)3nO^ZxU*PO(~jn{-3VcS5Qpg8~OrY4v$&(`%hA?|Q@<4P?S=4<0_)tZ?Dp6debv zqImVsH@BQ)jy+4F@h zmcBpu`0;cvF=3&qxLpm8k8-Sd-RPIU(MM{1WApF281{v0^7hG_3-N64;Jf3}#9V!E zMeD@pyVETH@f4;sKioBO*Waqmp+D!PZ1jmb%dw!m@pv6Qp+)?|rQ#CAe&A!~0>$7auds;B`*gD*=j?=lV&$7WguBEcD@~5&S-+syb z{K+@(aof$bdGPcn=kw3k|1XfJEwjA#j4}2%&z_?#dlqKSU9x&}Rz!pS z?prmf<@3dr9oL!f_gj0;Xq&(3&h^TM`%dilLeDpTD>&8o)KZ3B;QWTu??oJTeVns? h;yk|{sviHCe$3vqF|&^Q2?GNIgQu&X%Q~loCIBH$aDD&) literal 0 HcmV?d00001 diff --git a/entity/entity.c b/entity/entity.c index ba5d3e1..10bc0b4 100644 --- a/entity/entity.c +++ b/entity/entity.c @@ -8,6 +8,7 @@ #include "../player/player.h" #include "../util/pathfinding.h" #include "../util/font.h" +#include "../util/audio.h" EntityArray entities; @@ -29,11 +30,12 @@ void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect) { SDL_RenderCopy(renderer, atlasTexture, &entType.animation.atlasRects[animationFrame], &renderRect); char healthStr[12]; snprintf(healthStr, 12, "%d/%d", ent->health, entType.maxHealth); - renderText(renderer, fonts[2], healthStr, renderRect.x, renderRect.y); + renderText(renderer, fonts[3], healthStr, renderRect.x, renderRect.y); } SDL_SetRenderTarget(renderer, oldTarget); } -void updateEntities() { + +void updateEntities(Player *plr) { for (int i = 0; i < entities.activeCount; i++) { Entity *ent = &entities.entities[i]; EntityTypeReg entT = EntityRegistry[ent->type]; @@ -48,6 +50,35 @@ void updateEntities() { bool atTarget = ent->tileRect.x == ent->target.x && ent->tileRect.y == ent->target.y; + if (animationStep >= ent->entityNextTick) { + if (sqrt(pow(abs(plr->tileRect.x - ent->tileRect.x), 2) + pow(abs(plr->tileRect.y - ent->tileRect.y), 2)) < ENEMY_RANGE) { + plr->health -= ENEMY_DAMAGE; + } + if (plr->tileRect.x) + for (int y = ent->tileRect.y - ENEMY_RANGE; y < ent->tileRect.y + ENEMY_RANGE; y++) { + if (y < 0 || y >= MAP_HEIGHT) { + continue; + } + for (int x = ent->tileRect.x - ENEMY_RANGE; x < ent->tileRect.x + ENEMY_RANGE; x++) { + if (x < 0 || x >= MAP_WIDTH) { + continue; + } + Tile *targTile = &tileMap[y][x]; + if (targTile->type == TYPE_AIR) { + continue; + } + targTile->health -= ENEMY_DAMAGE; + if (targTile->health <= 0) { + if (targTile->audioCh < NUM_SYNTH_VOICES) { + audioData.synthVoices[targTile->audioCh].volume = 0; + } + memset(targTile->items, 0, sizeof(targTile->items)); + targTile->type = TYPE_AIR; + } + } + } + } + // Retry pathfinding every 10 ticks if we don't have a path and aren't at the target bool shouldRetryPathfinding = ( ent->path.length == 0 && @@ -93,9 +124,9 @@ void updateEntities() { .y = ent->toTile.y * TILE_SIZE }; - float t = (float)ent->interpolateTick / entT.entityTickRate; - ent->renderRect.x = (int)(from.x + (to.x - from.x) * t); - ent->renderRect.y = (int)(from.y + (to.y - from.y) * t); + float t = (float) ent->interpolateTick / entT.entityTickRate; + ent->renderRect.x = (int) (from.x + (to.x - from.x) * t); + ent->renderRect.y = (int) (from.y + (to.y - from.y) * t); if (ent->interpolateTick < entT.entityTickRate) { ent->interpolateTick++; @@ -104,9 +135,6 @@ void updateEntities() { } - - - void registerEntity(char fname[20], SDL_Renderer *renderer) { char name[21]; @@ -133,7 +161,6 @@ void registerEntity(char fname[20], SDL_Renderer *renderer) { //printf("Ent %s to %d\n", fname, indexEntity); - EntityRegistry[indexEntity].animation.textures[frame] = texture; EntityRegistry[indexEntity].animation.atlasRects[frame] = allocate_32x32(texture, renderer); EntityRegistry[indexEntity].type = indexEntity; diff --git a/entity/entity.h b/entity/entity.h index b99a4af..6fd28e1 100644 --- a/entity/entity.h +++ b/entity/entity.h @@ -7,9 +7,13 @@ #include "../tiles/tile.h" #include "../util/pathfinding.h" +#include "../player/player.h" #define ENTITY_MAX_COUNT 1024 +#define ENEMY_DAMAGE 2 +#define ENEMY_RANGE 3 + typedef enum EntityType { GHOST, } EntityType; @@ -49,7 +53,7 @@ void remove_entity(EntityArray *arr, int index); int add_entity(EntityArray *arr, Entity t); void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect); -void updateEntities(); +void updateEntities(Player * plr); void registerEntity(char fname[20], SDL_Renderer *renderer); void loadEntities(SDL_Renderer *renderer); diff --git a/items/item.c b/items/item.c index 868cf9a..931a82b 100644 --- a/items/item.c +++ b/items/item.c @@ -42,6 +42,72 @@ bool putOntoNext(ItemOnBelt *itm, int nx, int ny, Tile *next, TileTypeReg *ntt, } } + +OrientDirection rotateMainDirection(OrientDirection dir, int steps) { + + // The main directions indices array + int mainDirs[] = {1, 3, 5, 7}; + int count = 4; + + // Find index of dir in mainDirs + int index = 0; + for (; index < count; index++) { + if (mainDirs[index] == dir) break; + } + if (index == count) index = 0; // fallback + + // Rotate steps (positive = clockwise, negative = counterclockwise) + int newIndex = (index + steps) % count; + if (newIndex < 0) newIndex += count; + + return (OrientDirection)mainDirs[newIndex]; +} + +// Map 8 directions to main 4 for code output +int map8To4DirectionCode(OrientDirection dir) { + switch (dir) { + case ORIENT_LEFT: + return 4; // left + + case ORIENT_UP: + return 5; // up + + case ORIENT_RIGHT: + return 2; // right + + case ORIENT_DOWN: + return 3; // down + + default: + return 1; // undefined/error + } +} + +int getDirectionCode(OrientDirection dir, OrientDirection dir2) { + // Apply dir2 rotation: + switch (dir2) { + case ORIENT_UP: + // no change + break; + case ORIENT_LEFT: + // move dir one step to the right (clockwise) + dir = rotateMainDirection(dir, +1); + break; + case ORIENT_RIGHT: + // move dir one step to the left (counterclockwise) + dir = rotateMainDirection(dir, -1); + break; + case ORIENT_DOWN: + // move dir two steps to the left (counterclockwise) + dir = rotateMainDirection(dir, -2); + break; + default: + break; + } + return map8To4DirectionCode(dir); +} + + void updateItems() { for (int i = 0; i < neededUpdates.activeCount; i++) { @@ -70,52 +136,87 @@ void updateItems() { itm->offset -= 1.0f; } - // target coords - int nx = x + dirDx[dir]; - int ny = y + dirDy[dir]; - - // bounds & belt? - if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) { - if (tt.itemMoves) { - itm->offset += 1.0f - speed; - } - continue; + int inputDir = -1; // invalid by default + // Only valid if this tile is a belt and we can infer the input direction + if (tt.itemMoves) { + inputDir = (t->direction + 2) % 4; // Assume item entered from opposite of its direction } - Tile *next = &tileMap[ny][nx]; - TileTypeReg ntt = TileRegistry[next->type]; - int newLane = lane; - switch (next->type) { - case TYPE_BELT: - int newDir = next->direction; - bool nH = (newDir == ORIENT_LEFT || newDir == ORIENT_RIGHT); - bool nV = (newDir == ORIENT_UP || newDir == ORIENT_DOWN); - if ((horz && nH) || (vert && nV)) { - // same axis → keep lane - } else if (horz && nV) { - // came off a horizontal: lane0=top→vertical.left, lane1=bottom→vertical.right - newLane = (dir == ORIENT_RIGHT ^ newDir == ORIENT_UP ? 0 : 1); - itm->offset = 0.0f; - } else if (vert && nH) { - // came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom - newLane = (dir == ORIENT_UP ^ newDir == ORIENT_RIGHT ? 1 : 0); - itm->offset = 0.0f; + bool handled = false; + if (tt.allDir) { + for (OrientDirection outDir = 0; outDir < ORIENT_DIRECTION_COUNT; outDir++) { + if (outDir == inputDir) continue; // skip input dir + + int nx = x + dirDx[outDir]; + int ny = y + dirDy[outDir]; + + if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) + continue; + + Tile *next = &tileMap[ny][nx]; + TileTypeReg ntt = TileRegistry[next->type]; + + // Try to put item into any slot + for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { + if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + handled = true; + break; + } } - // (diagonals fall back to same-lane) - - // Find a free slot in - break; - - default: - itm->offset += 1.0f - speed; - } - - - if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && next->type != TYPE_BELT) { - for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { - if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + if (handled) { + t->fixedFrame = getDirectionCode(outDir, t->direction); break; + }; + } + } else { + // target coords + int nx = x + dirDx[dir]; + int ny = y + dirDy[dir]; + + // bounds & belt? + if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) { + if (tt.itemMoves) { + itm->offset += 1.0f - speed; } + continue; + } + Tile *next = &tileMap[ny][nx]; + TileTypeReg ntt = TileRegistry[next->type]; + int newLane = lane; + switch (next->type) { + case TYPE_BELT: + int newDir = next->direction; + bool nH = (newDir == ORIENT_LEFT || newDir == ORIENT_RIGHT); + bool nV = (newDir == ORIENT_UP || newDir == ORIENT_DOWN); + + if ((horz && nH) || (vert && nV)) { + // same axis → keep lane + } else if (horz && nV) { + // came off a horizontal: lane0=top→vertical.left, lane1=bottom→vertical.right + newLane = (dir == ORIENT_RIGHT ^ newDir == ORIENT_UP ? 0 : 1); + itm->offset = 0.0f; + } else if (vert && nH) { + // came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom + newLane = (dir == ORIENT_UP ^ newDir == ORIENT_RIGHT ? 1 : 0); + itm->offset = 0.0f; + } + // (diagonals fall back to same-lane) + + // Find a free slot in + break; + + default: + itm->offset += 1.0f - speed; + } + + + if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && (next->type != TYPE_BELT || newLane >= 2)) { + for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { + if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + break; + } + } + } } } @@ -284,10 +385,15 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play SDL_RenderFillRect(renderer, &rectA); } //SDL_RenderCopyx(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &tileRect); + SDL_RenderCopy(renderer, atlasTexture, - &ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][ - (animationStep / ItemRegistry[item.type].beltAnimation.divisor) % - ItemRegistry[item.type].beltAnimation.frameCount], + &ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][( + (animationStep / + ItemRegistry[item.type].beltAnimation.divisor) % + ( + ItemRegistry[item.type].beltAnimation.frameCount - + ItemRegistry[item.type].beltAnimation.startFrame)) + + ItemRegistry[item.type].beltAnimation.startFrame], &rect); if (debugMode) { @@ -311,24 +417,30 @@ void loadItems(SDL_Renderer *renderer) { strcpy(item->name, tile.name); memcpy(&item->animation, &tile.animation, sizeof(tile.animation)); + SDL_Texture *texTmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, TILE_SIZE, + TILE_SIZE); for (int frame = 0; frame < item->animation.frameCount; frame++) { for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) { - SDL_SetTextureBlendMode(item->animation.textures[a][frame], SDL_BLENDMODE_BLEND); - item->beltAnimation.textures[a][frame] = ScaleTexture(renderer, tile.animation.textures[a][frame], - TILE_SIZE / 2, TILE_SIZE / 2); - item->beltAnimation.atlasRects[a][frame] = allocate_16x16(item->beltAnimation.textures[a][frame], + SDL_SetRenderTarget(renderer, texTmp); + SDL_RenderCopy(renderer, atlasTexture, &tile.animation.atlasRects[a][frame], NULL); + SDL_Texture *tex = ScaleTexture(renderer, texTmp, + TILE_SIZE / 2, TILE_SIZE / 2); + item->beltAnimation.atlasRects[a][frame] = allocate_16x16(tex, renderer); + SDL_DestroyTexture(tex); if (frame + 1 > item->beltAnimation.frameCount) { item->beltAnimation.frameCount = frame + 1; } - SDL_SetTextureBlendMode(item->beltAnimation.textures[a][frame], SDL_BLENDMODE_BLEND); } } + SDL_DestroyTexture(texTmp); item->type = itemRegistryIndex; item->isTile = true; - item->animation.divisor = 1; - item->beltAnimation.divisor = 1; + item->animation.divisor = tile.animation.divisor; + item->beltAnimation.divisor = tile.animation.divisor; + item->animation.startFrame = tile.animation.startFrame; + item->beltAnimation.startFrame = tile.animation.startFrame; itemRegistryIndex++; } @@ -384,8 +496,6 @@ void loadItems(SDL_Renderer *renderer) { SDL_Rect beltRect = allocate_16x16(beltTex, renderer); // Assign to all orientations for (int o = 0; o < ORIENT_DIRECTION_COUNT; o++) { - item->animation.textures[o][frame] = tex; - item->beltAnimation.textures[o][frame] = beltTex; item->animation.atlasRects[o][frame] = mainRect; item->beltAnimation.atlasRects[o][frame] = beltRect; if (frame + 1 > item->animation.frameCount) { diff --git a/items/item.h b/items/item.h index 39340aa..fbe3d09 100644 --- a/items/item.h +++ b/items/item.h @@ -20,6 +20,8 @@ typedef enum ItemType { TYPE_FURNACE, TYPE_MINER, TYPE_TURRET, + TYPE_SPLITTER, + TYPE_CORE, IRON_ORE = ITEMREGISTRY_SIZE / 2, SILVER_ORE, GOLD_ORE, @@ -28,7 +30,11 @@ typedef enum ItemType { SILVER_INGOT, GOLD_INGOT, PLATINUM_INGOT, - LOG + LOG, + IRON_BULLET, + SILVER_BULLET, + GOLD_BULLET, + PLATINUM_BULLET, } ItemType; diff --git a/main.c b/main.c index d353747..94f1a99 100644 --- a/main.c +++ b/main.c @@ -83,6 +83,7 @@ const int delayNeeded = 1000 / targetFPS; #define smallFont fonts[1] #define smallerFont fonts[2] #define smallestFont fonts[3] +#define reallySmallestFont fonts[4] char *autosaveName = "autosave.dat"; @@ -150,11 +151,12 @@ int init() { loadBackgroundTiles(mainRenderer); loadTiles(mainRenderer); + preSetupTiles(); loadItems(mainRenderer); loadEntities(mainRenderer); - setupTiles(); + // for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) { // if (strlen(ItemRegistry[i].name)) { // printf("%d -> %s\n", i, ItemRegistry[i].name); @@ -206,10 +208,11 @@ int init() { SDL_RenderSetViewport(mainRenderer, &viewport); SDL_SetRenderDrawBlendMode(mainRenderer, SDL_BLENDMODE_BLEND); - biggerFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallerFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf", 255, 255, 255, 255); + biggerFont = prepText(mainRenderer, 32, "assets/PublicPixel.ttf"); + smallFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf"); + smallerFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf"); + smallestFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf"); + reallySmallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf"); SDL_RenderSetLogicalSize(mainRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); initPlayer(&player); @@ -250,6 +253,17 @@ int render() { } else { SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2); + unsigned int ix = ATLAS_SIZE; + for (unsigned char i = 1; i < fontCount; i++) { + SDL_Rect tmpRectFont = fonts[i].atlasRect; + tmpRectFont.x += ix; + SDL_RenderCopy(mainRenderer, fonts[i].atlas, &fonts[i].atlasRect, &tmpRectFont); + ix += fonts[i].atlasRect.w; + } + SDL_Rect tmpRectFont = fonts[0].atlasRect; + tmpRectFont.x += ATLAS_SIZE; + tmpRectFont.y = fonts[1].atlasRect.h; + SDL_RenderCopy(mainRenderer, fonts[0].atlas, &fonts[0].atlasRect, &tmpRectFont); } @@ -546,6 +560,31 @@ void processKeyboardHeld() { setActivePlayerSlot(&player, 0); } } + if (keyboardState[SDL_SCANCODE_E]) { + if (player.cursor.targetTile->health < TileRegistry[player.cursor.targetTile->type].maxHealth) { + player.cursor.targetTile->health++; + } + for (int x = playerTileX - 2; x < playerTileX + 2; x++) { + if (x < 0) { + continue; + } + if (x >= MAP_WIDTH) { + continue; + } + for (int y = playerTileY - 2; y < playerTileY + 2; y++) { + if (y < 0) { + continue; + } + if (y >= MAP_HEIGHT) { + continue; + } + Tile *t = &tileMap[y][x]; + if (t->health < TileRegistry[t->type].maxHealth) { + t->health++; + } + } + } + } if (keyboardState[SDL_SCANCODE_F9]) { player.inventory.slotCounts[player.inventory.activeSlotIndex]++; } @@ -649,7 +688,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[]) } } updateItems(); - updateEntities(); + updateEntities(&player); updatePlayer(&player); updateTiles(); animationStep++; diff --git a/player/player.c b/player/player.c index a5c2ee5..8c8612b 100644 --- a/player/player.c +++ b/player/player.c @@ -30,8 +30,9 @@ SDL_Color breakingBarColor = {128, 128, 0, 255}; void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) { activeSlotIndex = activeSlotIndex % itemRegistryIndex; - if((activeSlotIndex < tileTypeIndex || (activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) { - plr->inventory.activeSlotIndex = activeSlotIndex; + if ((activeSlotIndex < tileTypeIndex || + (activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) { + plr->inventory.activeSlotIndex = activeSlotIndex; } } @@ -149,15 +150,27 @@ void initPlayer(Player *plr) { } void updatePlayer(Player *plr) { - if (plr->health == plr->prevHealth && plr->healthIdle < neededHealthIdle) { - plr->healthIdle++; + if (plr->health == plr->prevHealth) { + if (plr->healthIdle < neededHealthIdle) + plr->healthIdle++; + } else { + plr->healthIdle = 0; // Reset if health changed (e.g., took damage or regen happened) } + if (plr->health < playerMaxHealth && plr->healthIdle >= neededHealthIdle) { plr->health++; + // Don’t reset healthIdle here — only reset if something changes externally } + plr->prevHealth = plr->health; + + if (plr->health <= 0) { + plr->rect.x = DISPLAY_WIDTH / 2; + plr->rect.y = DISPLAY_HEIGHT / 2; + } } + void renderPlayer(Player *plr) { SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer); @@ -176,26 +189,39 @@ void renderPlayer(Player *plr) { ItemType itemIndex = plr->inventory.activeSlotIndex; //SDL_Texture *itemTex; char itemStringCount[6]; - if ((itemIndex < tileTypeIndex || (itemIndex < itemRegistryIndex && itemIndex >= ITEMREGISTRY_SIZE / 2)) && itemIndex > 0) { + if ((itemIndex < tileTypeIndex || (itemIndex < itemRegistryIndex && itemIndex >= ITEMREGISTRY_SIZE / 2)) && + itemIndex > 0) { plr->cursor.heldItemRect.x = plr->cursor.windowX; plr->cursor.heldItemRect.y = plr->cursor.windowY; //itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction]; - SDL_Rect itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[plr->cursor.direction][(animationStep / ItemRegistry[itemIndex].animation.divisor) % ItemRegistry[itemIndex].animation.frameCount]; + SDL_Rect itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[plr->cursor.direction][( + (animationStep / + ItemRegistry[itemIndex].beltAnimation.divisor) % + ( + ItemRegistry[itemIndex].beltAnimation.frameCount - + ItemRegistry[itemIndex].beltAnimation.startFrame)) + + ItemRegistry[itemIndex].beltAnimation.startFrame]; if (itemAtlasRect.w == 0 || itemAtlasRect.h == 0) { - itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[ORIENT_LEFT][(animationStep / ItemRegistry[itemIndex].animation.divisor) % ItemRegistry[itemIndex].animation.frameCount]; + itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[ORIENT_LEFT][( + (animationStep / + ItemRegistry[itemIndex].beltAnimation.divisor) % + ( + ItemRegistry[itemIndex].beltAnimation.frameCount - + ItemRegistry[itemIndex].beltAnimation.startFrame)) + + ItemRegistry[itemIndex].beltAnimation.startFrame]; } if (itemAtlasRect.w != 0 && itemAtlasRect.h != 0) { -// if (plr->inventory.slotCounts[itemIndex] <= 0) { -// // Set a red tint (255, 0, 0) -// SDL_SetTextureColorMod(itemTex, 128, 128, 255); -// -// SDL_SetTextureAlphaMod(itemTex, 192); -// } else { -// SDL_SetTextureColorMod(itemTex, 255, 255, 255); -// -// SDL_SetTextureAlphaMod(itemTex, 255); -// } + if (plr->inventory.slotCounts[itemIndex] <= 0) { + // Set a red tint (255, 0, 0) + SDL_SetTextureColorMod(atlasTexture, 128, 128, 255); + + SDL_SetTextureAlphaMod(atlasTexture, 230); + } else { + SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); + + SDL_SetTextureAlphaMod(atlasTexture, 255); + } // SDL_RenderCopy(mainRenderer, itemTex, NULL, // &plr->cursor.heldItemRect); char nameItem[80]; @@ -204,6 +230,9 @@ void renderPlayer(Player *plr) { renderText(mainRenderer, fonts[2], nameItem, plr->cursor.heldItemRect.x, plr->cursor.heldItemRect.y - (fonts[2].size * 3 / 2)); } + SDL_SetTextureAlphaMod(atlasTexture, 255); + SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); + } @@ -213,7 +242,7 @@ void renderPlayer(Player *plr) { if (plr->cursor.targetTile) { uint16_t tempko = getBreakTime(plr->cursor.targetTile->type); uint16_t tempko2 = plr->cursor.breakingProgress; - renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 90, 200, 8, + renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 110, 200, 8, tempko, tempko2, breakingBarColor, 4); } @@ -229,17 +258,29 @@ void renderPlayer(Player *plr) { if (ItemRegistry[i].name[0] == 0x00) { continue; } - SDL_Rect itemAtlasRectd = ItemRegistry[i].animation.atlasRects[plr->cursor.direction][(animationStep / ItemRegistry[i].animation.divisor) % ItemRegistry[i].animation.frameCount]; + SDL_Rect itemAtlasRectd = ItemRegistry[i].animation.atlasRects[plr->cursor.direction][( + (animationStep / + ItemRegistry[i].beltAnimation.divisor) % + ( + ItemRegistry[i].beltAnimation.frameCount - + ItemRegistry[i].beltAnimation.startFrame)) + + ItemRegistry[i].beltAnimation.startFrame]; if (itemAtlasRectd.w == 0 || itemAtlasRectd.h == 0) { - itemAtlasRectd = ItemRegistry[i].animation.atlasRects[ORIENT_LEFT][(animationStep / ItemRegistry[i].animation.divisor) % ItemRegistry[i].animation.frameCount]; + itemAtlasRectd = ItemRegistry[i].animation.atlasRects[ORIENT_LEFT][( + (animationStep / + ItemRegistry[i].beltAnimation.divisor) % + ( + ItemRegistry[i].beltAnimation.frameCount - + ItemRegistry[i].beltAnimation.startFrame)) + + ItemRegistry[i].beltAnimation.startFrame]; } if (itemAtlasRectd.w != 0 && itemAtlasRectd.h != 0) { -// if (plr->inventory.slotCounts[i] <= 0) { -// // Set a red tint (255, 0, 0) -// SDL_SetTextureColorMod(itemTex, 128, 128, 255); -// } + if (plr->inventory.slotCounts[i] <= 0) { + // Set a red tint (255, 0, 0) + SDL_SetTextureColorMod(atlasTexture, 128, 128, 255); + } SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRectd, &targetItemRect); - //SDL_SetTextureColorMod(itemTex, 255, 255, 255); + SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); if (plr->inventory.activeSlotIndex == i) { SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16, diff --git a/tiles/belt.c b/tiles/belt.c index 1b09468..2fdb647 100644 --- a/tiles/belt.c +++ b/tiles/belt.c @@ -9,10 +9,15 @@ #include "../player/player.h" #include "../items/item.h" #include "../util/atlas.h" +#include "../util/font.h" void generateBeltFrames(SDL_Renderer *renderer) { - SDL_Texture *baseTexture = TileRegistry[TYPE_BELT].animation.textures[ORIENT_LEFT][0]; // Base belt tile + SDL_Texture *baseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, + TILE_SIZE, + TILE_SIZE); SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer); + SDL_SetRenderTarget(renderer, baseTexture); + SDL_RenderCopy(renderer, atlasTexture, &TileRegistry[TYPE_BELT].animation.atlasRects[ORIENT_LEFT][0], NULL); const int frameCount = TILE_SIZE; // 32 frames, 1px per frame = full seamless loop for (OrientDirection dir = ORIENT_LEFT_DOWN; dir < ORIENT_DIRECTION_COUNT; dir++) { @@ -79,7 +84,6 @@ void generateBeltFrames(SDL_Renderer *renderer) { SDL_RenderCopy(renderer, rotated, NULL, &dst1); SDL_RenderCopy(renderer, rotated, NULL, &dst2); - TileRegistry[TYPE_BELT].animation.textures[dir][f] = frame; TileRegistry[TYPE_BELT].animation.atlasRects[dir][f] = allocate_32x32(frame, renderer); } @@ -88,6 +92,7 @@ void generateBeltFrames(SDL_Renderer *renderer) { TileRegistry[TYPE_BELT].animation.divisor = 1; } + SDL_DestroyTexture(baseTexture); SDL_SetRenderTarget(renderer, oldTarget); } @@ -103,4 +108,9 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player (animationStep / TileRegistry[TYPE_BELT].animation.divisor) % TileRegistry[TYPE_BELT].animation.frameCount], &dst); + if (tileMap[y][x].health < TileRegistry[TYPE_BELT].maxHealth) { + char healthStr[12]; + snprintf(healthStr, 12, "%d/%d", tileMap[y][x].health, TileRegistry[tileMap[y][x].type].maxHealth); + renderText(renderer, fonts[3], healthStr, dst.x, dst.y); + } } \ No newline at end of file diff --git a/tiles/furnace.c b/tiles/furnace.c index 8cf38ac..f92b443 100644 --- a/tiles/furnace.c +++ b/tiles/furnace.c @@ -6,58 +6,20 @@ #include "tile.h" #include "../util/audio.h" -const ItemType FurnaceRecipes[ITEMREGISTRY_SIZE] = { - [IRON_ORE] = IRON_INGOT, - [SILVER_ORE] = SILVER_INGOT, - [GOLD_ORE] = GOLD_INGOT, - [PLATINUM_ORE] = PLATINUM_INGOT + +const MachineRecipe FurnaceRecipes[] = { + {IRON_ORE, TYPE_AIR, IRON_INGOT, 60}, + {SILVER_ORE, TYPE_AIR, SILVER_INGOT, 70}, + {GOLD_ORE, TYPE_AIR, GOLD_INGOT, 80}, + {PLATINUM_ORE, TYPE_AIR, PLATINUM_INGOT, 90} }; +void initFurnaceTile() { + initMachineTile(TYPE_FURNACE, FurnaceRecipes, sizeof(FurnaceRecipes) / sizeof(FurnaceRecipes[0]), + 1, /* start frame */ + 8 /* frame divisor */); +} void updateFurnace(Tile *tile) { - ItemOnBelt *inItem = &tile->items[FURNACE_INPUT_SLOT]; - ItemOnBelt *outItem = &tile->items[FURNACE_OUTPUT_SLOT]; - Item inItemType = ItemRegistry[inItem->type]; - - ItemType targetOutItemType = FurnaceRecipes[inItem->type]; - - Item targetOutItem = ItemRegistry[targetOutItemType]; - - if (targetOutItemType != TYPE_AIR) { - if (tile->miscVal == 0) { - if (outItem->type != TYPE_AIR) { - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 0; - } - tile->fixedFrame = 1; - return; - } - tile->audioCh = getAvailableChannel(); - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 255; - audioData.synthVoices[tile->audioCh].phase = 0; - audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->rect.x; - audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->rect.y; - audioData.synthVoices[tile->audioCh].waveform = WAVE_SINE; - audioData.synthVoices[tile->audioCh].frequency = 200; - } - tile->fixedFrame = 0; - } - ++audioData.synthVoices[tile->audioCh].frequency; - if (audioData.synthVoices[tile->audioCh].volume < 255) { - audioData.synthVoices[tile->audioCh].volume++; - } - if (outItem->type == 0 && ++tile->miscVal >= targetOutItem.miscVal) { - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 0; - } - tile->fixedFrame = 1; - tile->miscVal = 0; - inItem->type = 0; - outItem->type = targetOutItemType; - outItem->offset = -0.5f; - } - } else { - tile->fixedFrame = 1; - } + updateMachine(tile, FurnaceRecipes, sizeof(FurnaceRecipes) / sizeof(FurnaceRecipes[0]), WAVE_SINE, 200, 1); } \ No newline at end of file diff --git a/tiles/furnace.h b/tiles/furnace.h index 7f9f046..af975d6 100644 --- a/tiles/furnace.h +++ b/tiles/furnace.h @@ -7,8 +7,15 @@ #include "../items/item.h" #include "stdint.h" +#include "../util/crafter.h" -extern const ItemType FurnaceRecipes[]; +// Suppose this is defined somewhere +extern const MachineRecipe FurnaceRecipes[]; +extern const size_t FurnaceRecipeCount; + +void updateFurnace(Tile *tile); + +void initFurnaceTile(); #define FURNACE_INPUT_SLOT 0 #define FURNACE_OUTPUT_SLOT 1 diff --git a/tiles/miner.h b/tiles/miner.h index 7d01d44..9b446c1 100644 --- a/tiles/miner.h +++ b/tiles/miner.h @@ -8,8 +8,6 @@ #include "../items/item.h" #include "stdint.h" -extern const ItemType FurnaceRecipes[]; - #define MINER_OUTPUT_SLOT 0 void updateMiner(Tile * tile); diff --git a/tiles/tile.c b/tiles/tile.c index bd04607..11cb38a 100644 --- a/tiles/tile.c +++ b/tiles/tile.c @@ -113,7 +113,6 @@ void registerTile(char fname[20], SDL_Renderer *renderer) { }; // printf("Bound %s to %d orient %s\n", fname, indexTile, OrientStrings[o]); - TileRegistry[indexTile].animation.textures[o][frame] = textures[o]; SDL_SetTextureBlendMode(textures[o], SDL_BLENDMODE_BLEND); TileRegistry[indexTile].animation.atlasRects[o][frame] = allocate_32x32(textures[o], renderer); } @@ -126,6 +125,10 @@ void registerTile(char fname[20], SDL_Renderer *renderer) { TileRegistry[indexTile].type = tileTypeIndex; TileRegistry[indexTile].breakTime = 15; + TileRegistry[indexTile].itemMoves = false; + TileRegistry[indexTile].walkable = false; + TileRegistry[indexTile].needsTicks = false; + TileRegistry[indexTile].updateTileCallback = NULL; if (indexTile + 1 > tileTypeIndex) { tileTypeIndex = indexTile + 1; @@ -159,7 +162,6 @@ void registerBackgroundTile(char fname[20], SDL_Renderer *renderer) { //printf("Bound %s to %d\n", fname, indexBgTile); - BackgroundTileRegistry[indexBgTile].animation.textures[frame] = texture; BackgroundTileRegistry[indexBgTile].animation.atlasRects[frame] = allocate_32x32(texture, renderer); BackgroundTileRegistry[indexBgTile].type = indexBgTile; @@ -257,6 +259,17 @@ void loadBackgroundTiles(SDL_Renderer *renderer) { } } +void preSetupTiles() { + TileRegistry[TYPE_MINER].animation.startFrame = 1; + TileRegistry[TYPE_FURNACE].animation.divisor = 8; + TileRegistry[TYPE_CORE].animation.divisor = 8; + BackgroundTileRegistry[BGType_WATER_DEEP].animation.divisor = 16; + BackgroundTileRegistry[BGType_WATER_SHALLOW].animation.divisor = 12; + BackgroundTileRegistry[BGType_GRASS_FLOWER0].animation.divisor = 16; + BackgroundTileRegistry[BGType_GRASS_FLOWER1].animation.divisor = 16; + BackgroundTileRegistry[BGType_GRASS_FLOWER2].animation.divisor = 16; +} + void setupTiles() { TileRegistry[TYPE_AIR].breakTime = 0; TileRegistry[TYPE_BELT].itemMoves = true; @@ -268,33 +281,34 @@ void setupTiles() { TileRegistry[TYPE_BELT].allowedInItems[l][i] = true; } } - for (ItemType i = 0; i < itemRegistryIndex; i++) { - if (FurnaceRecipes[i] != 0) { - TileRegistry[TYPE_FURNACE].allowedInItems[FURNACE_INPUT_SLOT][i] = true; - } + TileRegistry[TYPE_SPLITTER].allowedInItems[0][i] = true; } -; TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1; - TileRegistry[TYPE_FURNACE].startFrame = 1; + TileRegistry[TYPE_SPLITTER].outputLane[0] = true; + TileRegistry[TYPE_SPLITTER].needsTicks = true; + TileRegistry[TYPE_SPLITTER].walkable = true; + TileRegistry[TYPE_SPLITTER].allDir = true; + + TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1; + TileRegistry[TYPE_FURNACE].animation.startFrame = 1; TileRegistry[TYPE_FURNACE].needsTicks = true; - TileRegistry[TYPE_FURNACE].animation.divisor = 8; TileRegistry[TYPE_BELT].needsTicks = true; TileRegistry[TYPE_BELT].walkable = true; TileRegistry[TYPE_MINER].needsTicks = true; TileRegistry[TYPE_MINER].outputLane[MINER_OUTPUT_SLOT] = 1; - TileRegistry[TYPE_MINER].startFrame = 1; TileRegistry[TYPE_AIR].walkable = true; TileRegistry[TYPE_TURRET].needsTicks = true; - TileRegistry[TYPE_TURRET].allowedInItems[TURRET_AMMO_INPUT_SLOT][IRON_INGOT] = true; + for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) { + if (AmmoDamages[i] > 0) + TileRegistry[TYPE_TURRET].allowedInItems[TURRET_AMMO_INPUT_SLOT][i] = true; + } + - BackgroundTileRegistry[BGType_WATER_DEEP].animation.divisor = 16; - BackgroundTileRegistry[BGType_WATER_SHALLOW].animation.divisor = 12; - BackgroundTileRegistry[BGType_GRASS_FLOWER0].animation.divisor = 16; - BackgroundTileRegistry[BGType_GRASS_FLOWER1].animation.divisor = 16; - BackgroundTileRegistry[BGType_GRASS_FLOWER2].animation.divisor = 16; BackgroundTileRegistry[BGType_WATER_SHALLOW].walkable = false; BackgroundTileRegistry[BGType_WATER_DEEP].walkable = false; + + initFurnaceTile(); } uint16_t getBreakTime(int type) { @@ -358,8 +372,6 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { printf("Error on tile %d, %d\n", x, y); backgroundMap[y][x].type = BGType_PLATINUM_ORE; } else { - SDL_Texture *tex = BackgroundTileRegistry[bt.type].animation.textures[animationStep % - BackgroundTileRegistry[bt.type].animation.frameCount]; SDL_Rect atlRect = BackgroundTileRegistry[bt.type].animation.atlasRects[ (animationStep / BackgroundTileRegistry[bt.type].animation.divisor) % BackgroundTileRegistry[bt.type].animation.frameCount]; @@ -396,20 +408,23 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { default: { char animationFrame = ((animationStep / TileRegistry[t.type].animation.divisor) % (TileRegistry[t.type].animation.frameCount - - TileRegistry[t.type].startFrame)) + TileRegistry[t.type].startFrame; + TileRegistry[t.type].animation.startFrame)) + + TileRegistry[t.type].animation.startFrame; if (t.fixedFrame > 0) { animationFrame = t.fixedFrame - 1; } SDL_Rect atlRect = TileRegistry[t.type].animation.atlasRects[t.direction][animationFrame]; - SDL_Texture *tex = TileRegistry[t.type].animation.textures[t.direction][animationFrame]; if (atlRect.w == 0 || atlRect.h == 0) { - tex = TileRegistry[t.type].animation.textures[ORIENT_LEFT][animationFrame]; atlRect = TileRegistry[t.type].animation.atlasRects[ORIENT_LEFT][ animationFrame]; } if (atlRect.w != 0 && atlRect.h != 0) { - //SDL_RenderCopy(renderer, tex, NULL, &dstRect); SDL_RenderCopy(renderer, atlasTexture, &atlRect, &dstRect); + if (t.health < TileRegistry[t.type].maxHealth) { + char healthStr[12]; + snprintf(healthStr, 12, "%d/%d", t.health, TileRegistry[t.type].maxHealth); + renderText(renderer, fonts[3], healthStr, dstRect.x, dstRect.y); + } // if (t.health < TileRegistry[t.type].maxHealth) { // SDL_Color tileHealthColor = {(t.health / TileRegistry[t.type].maxHealth ) * 255, (TileRegistry[t.type].maxHealth / t.health) * 255, 0, 255}; // renderBar(mainRenderer, x * TILE_SIZE, (y * TILE_SIZE) + (TILE_SIZE / 2), TILE_SIZE, 8, @@ -439,7 +454,7 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { .h = TILE_SIZE }; adjustRect(&dstRect, playerRect); - renderText(renderer, fonts[3], locChar, dstRect.x, dstRect.y); + renderText(renderer, fonts[4], locChar, dstRect.x, dstRect.y); } if (t.type == TYPE_BELT || itemViewing) { for (uint8_t lane = 0; lane < ItemSlotCount; lane++) { diff --git a/tiles/tile.h b/tiles/tile.h index 7d3335a..216db0f 100644 --- a/tiles/tile.h +++ b/tiles/tile.h @@ -7,6 +7,7 @@ #include "../util/util.h" #include "../items/item.h" +#include "tilecallbacks.h" #define MAP_WIDTH 500 #define MAP_HEIGHT 500 @@ -83,6 +84,8 @@ typedef enum BackgroundType { #define MAX_BASE_NAMES 512 #define MAX_ANIMATION_FRAMES 32 +typedef void (*UpdateTileCallback)(struct Tile *tile); + typedef struct TileTypeReg { ItemType type; char name[20]; @@ -92,9 +95,10 @@ typedef struct TileTypeReg { bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE]; bool outputLane[ItemSlotCount]; bool needsTicks; - char startFrame; bool walkable; + bool allDir; uint16_t maxHealth; + UpdateTileCallback updateTileCallback; } TileTypeReg; bool isWalkable(MiniRect tileCoords); @@ -141,7 +145,7 @@ typedef struct Tile { int neededUpdateIndex; char fixedFrame; PathFindDat pathFind; - uint16_t health; + int16_t health; } Tile; @@ -151,6 +155,8 @@ extern BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH]; void setupTiles(); +void preSetupTiles(); + void generateTestMap(); void loadBackgroundTiles(SDL_Renderer *renderer); diff --git a/tiles/turret.c b/tiles/turret.c index efdc35e..7c84602 100644 --- a/tiles/turret.c +++ b/tiles/turret.c @@ -8,7 +8,14 @@ #include "../entity/entity.h" const uint16_t AmmoDamages[ITEMREGISTRY_SIZE] = { - [IRON_INGOT] = 1 + [IRON_INGOT] = 2, + [GOLD_INGOT] = 1, + [SILVER_INGOT] = 3, + [PLATINUM_INGOT] = 5, + [IRON_BULLET] = 20, + [GOLD_BULLET] = 10, + [SILVER_BULLET] = 30, + [PLATINUM_BULLET] = 50, }; void updateTurret(Tile *tile) { @@ -17,45 +24,77 @@ void updateTurret(Tile *tile) { uint16_t damage = AmmoDamages[inItem->type]; - if (damage > 0) { - bool foundEnt = false; + // Reduce cooldown (miscVal) if above 0 + if (tile->miscVal > 0) { + tile->miscVal--; + } - for (int i = 0; i < entities.activeCount; i++) { - Entity *ent = &entities.entities[i]; - int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE)); - int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE)); - int d = sqrt(pow(dx, 2) + pow(dy, 2)); - if (d <= (TILE_SIZE * 8)) { - ent->health -= damage; - inItem->type = 0; - tile->audioCh = getAvailableChannel(); - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 255; - audioData.synthVoices[tile->audioCh].phase = 0; - audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->rect.x; - audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->rect.y; - audioData.synthVoices[tile->audioCh].waveform = WAVE_TRIANGLE; - audioData.synthVoices[tile->audioCh].frequency = 400; - } - tile->fixedFrame = 0; - foundEnt = true; - break; - } - } - if (!foundEnt) { - audioData.synthVoices[tile->audioCh].volume = 0; - tile->fixedFrame = 1; - } - - - } else { + // If there's no ammo or it's invalid, stop the sound and return + if (damage == 0) { if (tile->audioCh < NUM_SYNTH_VOICES) { audioData.synthVoices[tile->audioCh].volume = 0; } - tile->fixedFrame = 1; + if (animationStep % (TileRegistry[tile->type].animation.frameCount - 1) == 0) { + tile->fixedFrame = 1; + } return; } - if (audioData.synthVoices[tile->audioCh].frequency > 80) { - audioData.synthVoices[tile->audioCh].frequency--; + + // Search for a target entity + bool foundEnt = false; + for (int i = 0; i < entities.activeCount; i++) { + Entity *ent = &entities.entities[i]; + int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE)); + int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE)); + int d = sqrt(dx * dx + dy * dy); + + if (d <= (TILE_SIZE * 8)) { + foundEnt = true; + + if (tile->miscVal == 0) { + // Do damage and consume ammo + ent->health -= damage; + inItem->type = 0; + + // Get or reuse audio channel + if (tile->audioCh >= NUM_SYNTH_VOICES) { + tile->audioCh = getAvailableChannel(); + } + + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + voice->volume = 255; + voice->phase = 0; + voice->sourceRect.x = tile->rect.x * TILE_SIZE; + voice->sourceRect.y = tile->rect.y * TILE_SIZE; + voice->waveform = WAVE_TRIANGLE; + voice->frequency = 400; + } + + tile->fixedFrame = 0; + tile->miscVal = 20; // Cooldown (ticks) until next fire + } + + break; // Only shoot one entity + } } -} \ No newline at end of file + + // No entity found? Fade sound out + if (!foundEnt && tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + if (voice->volume > 0) { + voice->volume--; + } + if (animationStep % (TileRegistry[tile->type].animation.frameCount - 1) == 0) { + tile->fixedFrame = 1; + } + } + + // Lower frequency for pitch effect if it's still playing + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + if (voice->frequency > 80) { + voice->frequency--; + } + } +} diff --git a/util/crafter.c b/util/crafter.c new file mode 100644 index 0000000..5608e8b --- /dev/null +++ b/util/crafter.c @@ -0,0 +1,97 @@ +// +// Created by bruno on 10.6.2025. +// + +#include "crafter.h" +#include "audio.h" + + +void initMachineTile(ItemType type, const MachineRecipe *recipes, size_t count, uint8_t startFrame, uint8_t divisor) { + // Force slot assignments for allowed items based on recipes + for (size_t i = 0; i < count; i++) { + const MachineRecipe *r = &recipes[i]; + if (r->input1 != TYPE_AIR) + TileRegistry[type].allowedInItems[SLOT_INPUT1][r->input1] = true; + if (r->input2 != TYPE_AIR) + TileRegistry[type].allowedInItems[SLOT_INPUT2][r->input2] = true; + } + + // Output slot is fixed to SLOT_OUTPUT + TileRegistry[type].outputLane[SLOT_OUTPUT] = 1; + + // Animation and behavior settings + TileRegistry[type].animation.startFrame = startFrame; + TileRegistry[type].animation.divisor = divisor; + TileRegistry[type].needsTicks = true; +} + + +bool findMachineRecipe(const MachineRecipe *recipes, size_t count, ItemType in1, ItemType in2, + ItemType *out, uint16_t *ticks) { + for (size_t i = 0; i < count; i++) { + const MachineRecipe *r = &recipes[i]; + if (r->input1 == in1 && r->input2 == in2) { + *out = r->output; + *ticks = r->ticksRequired; + return true; + } + } + return false; +} + +void updateMachine(Tile *tile, + const MachineRecipe *recipes, size_t recipeCount, + uint8_t waveform, uint16_t freqStart, uint16_t freqStep) { + ItemOnBelt *in1 = &tile->items[SLOT_INPUT1]; + ItemOnBelt *in2 = &tile->items[SLOT_INPUT2]; + ItemOnBelt *out = &tile->items[SLOT_OUTPUT]; + + ItemType result; + uint16_t ticksNeeded; + + if (!findMachineRecipe(recipes, recipeCount, in1->type, in2->type, &result, &ticksNeeded)) { + tile->fixedFrame = 1; + return; + } + + if (tile->miscVal == 0) { + if (out->type != TYPE_AIR) { + if (tile->audioCh < NUM_SYNTH_VOICES) + audioData.synthVoices[tile->audioCh].volume = 0; + tile->fixedFrame = 1; + return; + } + + tile->audioCh = getAvailableChannel(); + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *v = &audioData.synthVoices[tile->audioCh]; + v->volume = 255; + v->phase = 0; + v->waveform = waveform; + v->frequency = freqStart; + v->sourceRect.x = TILE_SIZE * tile->rect.x; + v->sourceRect.y = TILE_SIZE * tile->rect.y; + } + + tile->fixedFrame = 0; + } + + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *v = &audioData.synthVoices[tile->audioCh]; + v->frequency += freqStep; + } + + if (++tile->miscVal >= ticksNeeded) { + if (tile->audioCh < NUM_SYNTH_VOICES) + audioData.synthVoices[tile->audioCh].volume = 0; + + tile->miscVal = 0; + tile->fixedFrame = 1; + in1->type = TYPE_AIR; + if (in2->type != TYPE_AIR) in2->type = TYPE_AIR; + out->type = result; + out->tileX = tile->rect.x; + out->tileY = tile->rect.y; + out->offset = -0.5f; + } +} diff --git a/util/crafter.h b/util/crafter.h new file mode 100644 index 0000000..b0fe001 --- /dev/null +++ b/util/crafter.h @@ -0,0 +1,37 @@ +// +// Created by bruno on 10.6.2025. +// + +#ifndef FACTORYGAME_CRAFTER_H +#define FACTORYGAME_CRAFTER_H + +#include "../items/item.h" + +#define MATCHES(a, b, x, y) ((a == x && b == y) || (a == y && b == x)) + + +enum { + SLOT_INPUT1 = 0, + SLOT_INPUT2 = 1, + SLOT_OUTPUT = 2, + MACHINE_SLOTS = 3 +}; + +typedef struct { + ItemType input1; + ItemType input2; // use TYPE_AIR if single-input + ItemType output; + uint16_t ticksRequired; // used for output delay +} MachineRecipe; + +void updateMachine(Tile *tile, + const MachineRecipe *recipes, size_t recipeCount, + uint8_t waveform, uint16_t freqStart, uint16_t freqStep); + +bool findMachineRecipe(const MachineRecipe *recipes, size_t count, ItemType in1, ItemType in2, + ItemType *out, uint16_t *ticks); + +void initMachineTile(ItemType type, const MachineRecipe *recipes, size_t count, + uint8_t startFrame, uint8_t divisor); + +#endif //FACTORYGAME_CRAFTER_H diff --git a/util/font.c b/util/font.c index 6bd844c..ab554ac 100644 --- a/util/font.c +++ b/util/font.c @@ -7,58 +7,78 @@ BitmapFont fonts[fontCount]; -BitmapFont -prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { +BitmapFont prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file) { TTF_Font *gFont = TTF_OpenFont(file, pxSize); BitmapFont out; out.size = pxSize; - out.color = (SDL_Color) {r, g, b, a}; - unsigned int i = 1; - do { - if (i == 173) { //specifically this char is 0 width (IDK why) - out.surface[i] = SDL_CreateRGBSurface(0, pxSize, pxSize, 32, 0, 0, 0, 0); + out.color = (SDL_Color) {255, 255, 255, 255}; + + const int glyphsPerRow = 16; + const int glyphsPerCol = 16; + const int atlasWidth = glyphsPerRow * (pxSize + 1); + const int atlasHeight = glyphsPerCol * (pxSize + 1); + + SDL_Surface *atlasSurface = SDL_CreateRGBSurface(0, atlasWidth, atlasHeight, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + out.atlasRect.x = 0; + out.atlasRect.y = 0; + out.atlasRect.w = atlasWidth; + out.atlasRect.h = atlasHeight; + SDL_FillRect(atlasSurface, NULL, SDL_MapRGBA(atlasSurface->format, 0, 0, 0, 0)); // transparent + + for (uint16_t i = 1; i < 256; i++) { + SDL_Surface *surf; + + if (i == 173) { + surf = SDL_CreateRGBSurface(0, pxSize, pxSize, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + SDL_FillRect(surf, NULL, SDL_MapRGBA(surf->format, 0, 0, 0, 0)); // transparent } else { char tmpOut[2] = {i, 0}; - out.surface[i] = TTF_RenderText_Solid(gFont, tmpOut, out.color); + surf = TTF_RenderText_Solid(gFont, tmpOut, out.color); } - out.texture[i] = SDL_CreateTextureFromSurface(renderer, out.surface[i]); - i++; - } while (i < 256); + int x = (i % glyphsPerRow) * (pxSize + 1); + int y = (i / glyphsPerRow) * (pxSize + 1); + + SDL_Rect dest = {x, y, pxSize, pxSize}; + SDL_BlitSurface(surf, NULL, atlasSurface, &dest); + + out.glyphs[i] = dest; + + SDL_FreeSurface(surf); + } + + out.atlas = SDL_CreateTextureFromSurface(renderer, atlasSurface); + SDL_SetTextureBlendMode(out.atlas, SDL_BLENDMODE_BLEND); + SDL_FreeSurface(atlasSurface); TTF_CloseFont(gFont); + return out; } void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y) { - SDL_Rect charRect; - charRect.x = 0; - charRect.y = 0; - charRect.w = font.size; - charRect.h = font.size; - SDL_Rect outRect = charRect; + SDL_Rect outRect; outRect.x = x; outRect.y = y; + outRect.w = font.size; + outRect.h = font.size; while (*string) { if (*string == '\n') { outRect.x = x; - outRect.y += charRect.h + 4; + outRect.y += outRect.h + 4; string++; continue; } - SDL_RenderCopy(renderer, font.texture[*string], &charRect, &outRect); //TODO CONSIDER FONTS IN ONE ATLAS - outRect.x += charRect.w + 1; + SDL_RenderCopy(renderer, font.atlas, &font.glyphs[*string], &outRect); //TODO CONSIDER FONTS IN ONE ATLAS + outRect.x += outRect.w + 1; string++; } } void destroyFont(BitmapFont *font) { for (uint16_t i = 1; i < 256; i++) { - if (font->texture[i]) { - SDL_DestroyTexture(font->texture[i]); - } - if (font->surface[i]) { - SDL_FreeSurface(font->surface[i]); - } + SDL_DestroyTexture(font->atlas); } } \ No newline at end of file diff --git a/util/font.h b/util/font.h index 3430e9b..6302ae6 100644 --- a/util/font.h +++ b/util/font.h @@ -9,19 +9,20 @@ #include #include -#define fontCount 4 +#define fontCount 5 -typedef struct BitmapFont { - SDL_Texture *texture[256]; - SDL_Surface *surface[256]; +typedef struct { + SDL_Texture *atlas; + SDL_Rect glyphs[256]; uint8_t size; + SDL_Rect atlasRect; SDL_Color color; } BitmapFont; + extern BitmapFont fonts[fontCount]; -BitmapFont -prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +BitmapFont prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file); void destroyFont(BitmapFont *font); diff --git a/util/util.c b/util/util.c index 2d48927..cfd1b71 100644 --- a/util/util.c +++ b/util/util.c @@ -134,7 +134,7 @@ void renderBar(SDL_Renderer *renderer, char barString[20]; sprintf(barString, "%d/%d", currentValue, maxValue); - renderText(mainRenderer, fonts[3], barString, width / 2, margin); + renderText(mainRenderer, fonts[1], barString, x + (width / 2 - (fonts[2].size * strlen(barString))), y - fonts[2].size - barRect.h); } int cmpstringp(const void *p1, const void *p2) { diff --git a/util/util.h b/util/util.h index 2b7543e..483b566 100644 --- a/util/util.h +++ b/util/util.h @@ -38,7 +38,6 @@ extern bool itemViewing; extern bool renderAtlas; typedef struct Animation { - SDL_Texture *textures[TILE_SIZE]; SDL_Rect atlasRects[TILE_SIZE]; unsigned char frameCount; unsigned char divisor; @@ -46,10 +45,10 @@ typedef struct Animation { typedef struct OrientedAnimation { - SDL_Texture *textures[ORIENT_DIRECTION_COUNT][TILE_SIZE * 2]; SDL_Rect atlasRects[ORIENT_DIRECTION_COUNT][TILE_SIZE * 2]; unsigned char frameCount; unsigned char divisor; + char startFrame; } OrientedAnimation;