From 164f58aa1ef52b72a56dc561534241f6d5b9d1ee Mon Sep 17 00:00:00 2001 From: cellos51 Date: Sat, 9 Aug 2025 21:49:37 -0400 Subject: [PATCH] Main menu prototype --- graphics/affine_main_menu_background_gfx.grit | 1 + graphics/affine_main_menu_background_gfx.png | Bin 0 -> 5222 bytes graphics/background_main_menu_gfx.grit | 1 + graphics/background_main_menu_gfx.png | Bin 0 -> 8404 bytes include/affine_background.h | 11 +- include/game.h | 2 + include/graphic_utils.h | 6 + source/affine_background.c | 69 ++++++++--- source/game.c | 108 +++++++++++++++--- source/graphic_utils.c | 30 +++++ source/main.c | 2 +- 11 files changed, 200 insertions(+), 30 deletions(-) create mode 100644 graphics/affine_main_menu_background_gfx.grit create mode 100644 graphics/affine_main_menu_background_gfx.png create mode 100644 graphics/background_main_menu_gfx.grit create mode 100644 graphics/background_main_menu_gfx.png diff --git a/graphics/affine_main_menu_background_gfx.grit b/graphics/affine_main_menu_background_gfx.grit new file mode 100644 index 0000000..3205289 --- /dev/null +++ b/graphics/affine_main_menu_background_gfx.grit @@ -0,0 +1 @@ +-gt -gB8 -mLa -mRa \ No newline at end of file diff --git a/graphics/affine_main_menu_background_gfx.png b/graphics/affine_main_menu_background_gfx.png new file mode 100644 index 0000000000000000000000000000000000000000..74b938aa355d628b5e2e33f682ebf1c7545076fc GIT binary patch literal 5222 zcmV-s6q)OZP)C00001b5ch_0olnc ze*gdg1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUyFi=cXMI9w64>d_YDk@noEd@z&cQi4VIyC}rxw=3()I>byP)G4_ zX*Hwr`L;#2d9Y_EG010qNS#tmY4s-wj4s-!)B(v54 z000McNliru=?Dq{Bq@*^-9K1>K= zG1f zm=WYkC6cd1=0>+7xGH&Y9@kYW-v9v7fq>|Ouv=i@;j*t(AkgC?64l5At%%eKH=gSU z6H>{Q3VbD%ZltiFvu_c?7PIg`o-P6s08tUhj+{^`@>HlVR!P7h>LOcF)u^Tssj1{J zhi#wa0Ns;yn&l7x5xn2~8=4r(0ZoJqN{Su8u`Ce-5o8$U*({@EJbkf<6gKQ@-#Zf$ zb+%mDKnhF+u)nB?TNWmP1ptu00T2Y#vWTaV2Yf$PGWzz-!IGilzA*vDW;kO5;J~Z5 zBJi=`*&Lh_CLpg_4UxW0 znVw*h@(Z|ETB`bZA7Qk*dHam02dt&3xElaAvH-B5O=7R*!2$T=^Cb7jii!T6&KdqN zPV{AE1|@s1DX4^_bT$cuCIYUPu;6g?u`__eD5d}sn6FO^2_6$sP1Ubi%?!YAEm(B~ z5-d^^0(7GR(3s$TI-&*($|w+k1|4|4%aNxpWVJkOTjgu6_)gz%*O{{$Hlccu^GOL9 z08apji{3jit4aVZ#5s$57h__{RJoJBFAmvSBv{FF1-x|$&FT(v@?i!bUoT;S%STcU zB-Jo+#X?p-aFPY^w}W;Q>?iU)%4`_{a{^Fki?tAd_yNfZ6aZu(K2`&*0zhPeb%EE| zyI7eR>R1zbP5o&lT}v@J9BS&b^#=EvT*J8fI#L=JF*^+=5n z#51jod705S0GXK=0f?qT2eQ#$otsfl>d!vxds)zX`N)NUej$yy_=J@K3gAqVX`Kc@ zlrS>~)ud;kPQ}yw>ksl!F(QZxp%zi>&VX$&fB+(c+yKC&kK$j~LVo+Xu*JQFfOOJ< zsRk&3Z2{(bkIzH=)BWTk}%)Btsb^g?O`sPV*Te*i#5^W=U9;5Eum2qp|P zrlv^B01Jo<0EyTDkkk{LSGNOIeE(zrMBo~NZs9`_Q)DWW+eQ`uCIKpG1^^^)s0-Tu zr#SFS{TfDRWG4jMMSsL>%6Z@E&j48A0R-*MNk*g$$Ta(~AaI}6Ujn@*yq)*kZvRfb zEOLzj+ji%GH^*Jf~Vt%S6`-hcS7@7ih1~dS!1Bh0hdL$&^m|KbtH>tu; z5BOMHSHQM~=B;l4lmP;OCeW*?Zb6*^&)u6=eOUpvs4|*4Fsr}=K(ZgFWdrXiosb=D2+ez0DJ-GB(1#BjEZ;T@mC5{ksl=UeK+o+9qoOl=MLn zXQKpy{VxQ)UT6}00tiXtg|@%4B-dBY)`gk*=ej-)-{AJY5ja@5^Fv*q98dsK7f5hC zS@!f4Aar_N3}JSVzgWO3a930GlfB$^FqtC=;)*pBPp!Tg+Z{6Civ)ZtxPQ@C1RI0l zlrwz-pcQ26zi6f69{g`ud_3wQ-$MMwf!F(O5O%kQkgpubGyQO*KZGDv-El_mL;8b0 z5WHU_NZbH4704+VfS!jv$ottLi>Sh%HXxgS|NBQK7>3<{29UC~F$}TU1Wn70K3_a-o6 zFnIta4}rrsoNnQRJj}=R!4LZ2CoNC_c!kH%Ht7U_3YU^K=>Q;2(bq(eEP>r}cb9~G zQY-ydR>)(;dxmYM|7!d|cj~RY@FOKZleQa_3ogf-`@t&g981~W)W4a44KYxUY9xFSmC9A)f{GOKc2?3xGNCVJiy==KheHf@8DEdp9Ldn|cA= zKE5|8{CmTLbR)<-hskNAz;0&1#DY-BE!JxD{+VrvOr!Hwrt$ah*A#$uYm1_C5GdPA zmB6u$1P$m7eK?{IMxY9dcAw?fgFH#No$YdS*o;*BN}m<6DlNhh?EtN3N&d9;+qE}p z{uLSrT1ke)!|HU)#iz|VZIz60>)#7~QV%#uFgTEb9>cKx5rTE3v^Z23iCEyLRLqB7 z-`vQ{cEaw5>*JYB4?%B4z>Oykp?%DY7UG$#SwVQB4;rCmf~_yWe}<7AKH`rP9?vNl z6;J@S455}S?U z|K>q&B~C@OM$U?R*uBw*CHSc=Z4&5J`D6RHBHSYWs05S&&;&KjHB%jhK->R~zHc?C zWd!~w`Q5h%@00U=86;LAYpRMYxTL8lXC}gxv@yQWw+6`1?N7VA0nnD@3}BPpm#e0U zd_NFLsWU+N@144^UkUiOH4!Y~haxZrjJBB+X`o+lUOoEJ$%HJ9soA^j-<+#8pw0C@ zS>Q+Xf4?6b=n`P}R*dgN9>x}EY|h8}HQF2UBNkb2-8S0nYTdpe=!De|zjitUtpa+- z3W4&Kw zdZ+*TL|@y4g5X62PXM2+#!Dnl+gc}g01pOi4+d;YuYnm*(02>~-{>PQC6)cyzMqZ; zn*xmXqoq636YbQcH3}dA7xXO(VE;^>X#p)@C2tm}&Ecsdo6fBCRU8ZbsY3IL077`Z zmV)?Evs&lX?<@IakP@pw3n5Z;$iUQru|SIOc+)i2LhjzF_VB;ARhm^k@L!Q$yt(U9uCg zS8qEqzj2}J5o@0k+~Bt)`utM=mK-Q6wn_hZGRU;B=i?|uPWcM6OMZ6%q9B4l2zz5pShA^j}8-43b#R&kKWyc9%LTLba z-2uc17SL4$RAl=dz}#b=o3&&AAV26g02%c-Ja$N>;=z7zuAl?ZoJwS5r*}b9uLZ!@ zW9CMmV(epq1VFXNcoRpZGDc{0@aMIUEFX-qRcafc@tQMC0KOA%+mEpwiYWbdxPlYy zio^}mbEOr5%{8;Tm5Po!j z8I@GCJvvNj(>DN1^udvFj?0XO0l?l406^|4-?rui8i0_`R5@lVKu$kWgGp1`kG5On z8T3=zey0xrL3I$V1D#vMq|d{tLvUvmST)W8t05x!c{wy(vs2Ui{0po-EcNhGaX83LcgFg40vmO((U#d3k z^yg~h7_^k%Ts0NRm-P%7qtXH@qjkUTaWR66*oih)0nS= zgK3)E%P%D*PMngvw$C#7$ovTa`_5;!X_0IK!0}P7BI8sV0IFK7n64FPNfp4Du2hwb z5ViR4A{dIlt`M(cGmG*kI5*M9iGT|Lz)9FFoEQ29*I*E}R0nx+Ah{Iq?))3T_N0D7 z*c^_>goK_NHT`22Yydb1TchlpCn}g|=HZmnlV-q=xW5s%ZTm6UvofDSB`7i6yl}St zK^*|x0wC1uJT6S}Qwv!pX&No8Im=Za>CRj;uba=8&Sit!C$2iVq{H>be4XB&0q~yG zaR>mRC?Qj;Vo#67PvI_){{X-*`6xDTEiuhC3MGnk*KTxSz`q)l1wanGsl#!MD2O_UaK?zFiS6SM$p`GMOP#&q@&H7#MNpthK09LPR z_moPzK$e^LB>>MmJh=lX2XAcUcC6CrgFLSu$@i9QZ)*~+?-DHQ85Ot8xsa|mWes$Hp&(hR^U0Ja~p<9Ik~ zkd$rG$wq9DkyYM;A-?K+G~Rn!z*^WYDC*h3G@r&ZIQFEhB3S`&;vE-!PKXUtHYNjO zS5^SHsipvG3j|C3sauR`>P;ryJVwMqr#}M-%`+h{W`>%NOhG9(RRgqSlI`Ql4}?*h z2k`rvjFCzlHw9ulsIrz^w7j4LNCNCApO*;B&~;EXkolnCycZIlvi zz%6wz!ooovQS>bXSXvW}{H-Fh786b=48YR4f{b9q3gscW1*yeVT^UgQ0~y?>cLYcbF?_(IA05E6||V_7anG zN#Krn4zr*P*%V7;1Xw*r~m={;-gQH9IN8oSiWjED(KJ(;aXOU^gd!ldCH zYH%8Yl6Cql+%b${&~Z1r5IXW6dPr`I_iK*@Ku_EB=Au=oS$ij{1_hZTuUUg7u{TAZ z!#GB};9~cIj4rp^gq-Ns7AcA^0N`!+N)}X|_2u=^eu;(-iTJ9-gwxVGI@IXmG;c%2 zi&_F%?pr!NrJj0=R7$f`SpXHtIOVhfqI95c9Rq|(U83HWJ1r{q3=96A{iCxdy#|n8 g-Oa?cLu?HD4;3oE_tw2Lv(BEG6MLVt&)&b^#A<6Qlwi9(H}V7kT#|nW3XqdW2?{a2R5TPZcd@W3 zgoyk|BXqz<02Kwt9Q|}e{S@&jJ6m6ok&|_jy#_loUG$SIB^jL+ zpsa(ixM&XjW0c!=Iot_>LItmb^VzKO-nZE!+h%-&L-!kI%xNBDMf~@FH(uH6a=$n8 zoSFtqe*EJsSeoyu%zMn*Sf6()0OOWbJ>kwK8MElv*;s_zWLBrHapB+kOfuZ&r+s5O zSu=QL-C`TM%-?QoH>}98xV2y50GTl;aGz}!Ksvi7b0YHz3P}hPBG}bg=_j0Pr?l-; z(2P#tBYFEp0zlR9gNdruQ|#;`uH$z+2-KF5gd}65yex}0hRVeA=c;_NyXye`vRrqu z6m+#}biv&7k$yZ?Equ#zW}5c)3uSh&5C&LLa+wL-a&n(7^FUy7_Jv10Z8oKoLV@pv z&c~v9^xQZt&O5|u-@JCfPQp!U>V50C4@-7MxX7k6Q2nsl0U*Us&Se+sPX9PkoucFqKKrJIGx_|x4mkpthd9# zMTx9{OrVCr%=^dSSd~Cc!t-CVuuGa@0XZR6i1*mU&{fRQ+>15VjdwGJXYTBWCNI3= z6lpZFy`N$pJT+tDHEDfh8{go7c=Ein_i=h^J2^Ofc9T{`Dq>DavlxdWY{9r?8AlsQ zJBCErz!9?Vv!-1MYa)csLL8bJDPgfFN?1Zqf_Z?I#gc1kUtW%9eN(7BMlX}8`dl4) z)vzm8!f^zE_mY=VE(!7Sw;9YaRE7YQM~i+vQ8*_LL9yP>Z0=!cox<_&#dK)SSi#hp z_q1SzD)}@T5SvAteWc8$nJ>bCckwKU--<)dh7A?yR??aZ(h?P1@>c+LVA}fzl)mYe z;6eHm^Mm%ZCqmPPaevX7cb+|pd{C7g{1hN@9-pPsJB7)5Td8Fl&`b!{7URBRWZ((C zDV4~ae8bOmw*k%)jLLplutx1(pIkh-A93OgiCtf4javUQvNgY9w(K5Ls2J6bhX{Ra zE3{fR$=x-#B!*6y^nUVa$FViTqX3mUm*M$hy&FM`l(C@s%91ZDaz+s0m#Mg!A51@F zP__EI<3UyuT`UxBSWP{3dy=1I2?~&TXydm;fsyC4YTns_&K>lA=JPY2&ZMf`- zo>)rQonZokv^C&57X`bFV$id&1cg#M7z6lNSA(#j&}VQ}cnNt2NX$Fz&BpP<3;!N| zU5lVC$VlH2Zrqpp{H1d5^7IKx;9La$h9U)-$xC!C9CNi zXC)B&F<=>Pr9$AW-~z}_b(I!E6rU*9S4WELGKH$=CK>akN3DT&AIQ0 z$gz*>pDv-;BrQR=j@=s?gu?jIzH-~OwqM#nXvpG!;%*1~M51idMyC)0ofIYbHu4wP zfQ-6R-arGXhl-rSOZ5Wug>=6spR8#oWZPLecMrUY*6zCEO^!zOw#V$L!z+_MmXs<< z<)0nfQLZ0O1ZjCu{0I+DCvV#)5U$y^jqmFHK4FkJ}OVnv#IZTIX}G`;23ny zBR_pW2b8BK)xnpgmbPWs#9X-PB3WUZA1^Oj?SR!Ct>7r->e#%#F$M2-B;pnH3Px@Z zLiFA_Qm@8gvrQbB`%+U)F0w7kf&-b1*> zE-of{#}Lcle)W_~t(E!|G%N9Qb4>!B2vtH<W68xYWA2SVZ{v@y%bR^9)=O#Du6o2t7=zo*(l@3=FW*K+4qj~@cxacx#|`GNNMq;na@GSp}nIM@Ms)bjFuX3ua_duwFvC8 zjk)=*+A4Q7xxGN-EL7Nh`)LUM_tmbTw#D(I{QTUCsj4iI_Qa8@HW}1It?VwKpHg3a zAKeCn)+@%~m0qH|dyH_7WnDIZz^#y;-f5D!_fygDcXSPmH{gshY_JZ;-CkGK(t;Hj zTdANiTdJHki`*Sd{)&1I`unQG9|NVZKp}baW8E~%4tI^$i=ATkF3yj(iRY=!-WGt; zYN>rnrQT#cYOzR0(xj4nCLyND!2=Rv-8>H(q?rKV&{ZYU8Wn1B8BaeZ|EgY*&fS|Q zZF^)JukU@Q>hJR`4HtQZDQ%CH`;F865%#JB9HUT)CvxkQVL`4=;6~;2Q!KVbNwPFZ z>U`_1c@y%3ajwZReA%1!$y&c<@C-lg4ECAZjE_X?iA87E609DLOzu?b;mdlChmC38 zuWDVe3b)wxrH*BNM6RR@d*cS;;6RvWBiO7vdr+4SPayr5NnQ(NTCro{4SytC@u${$ zvci=8u;MR9yWh?-9B^j(Zc$Y`F-D0#dA#e$&Nb6-KK^BYWH4J?^hqDTm~{XjrDNCs z%Gg3Taq+`~5HeQ%vbn;>!MQPV@n_q3x3WIe@Zuk-+d_I7@ zLz#tX$LAf=TyRr{SKSVtZh4N1jZYMEFpT;)$PwMdY2^*0bP^J8?NkjFRE<5`BJ~mM zuXgD}eHC$slp*^@!o9xh`|H9VwCYlqHQQRno*y( zzXokmK6Set`zz;~)`W%O76y9w*ZH*(#cu_Eb!rkHC;%-d#Tp>mU5w9tU9ZwU2d6e2 z-Bijyt%{<-L?|S=^m0XqOfB+CZyN`>)OYCF_F*y@gn5eLJr#5(y?0K`i<)NhcoptJ zIln+g0WIak-=^gtQF?6Kjb)oFNfk~Z7s%Y*jx`r~WB_ptzTUK=gs640VBm`#7yFw0 zo@ObD4oCm9z1U_HA4z5Mv=A9;#@%@|Cu+*qvg6+OcjA(Dy=s6DpiTPx-qC(#<$1m+ z@gRwEb46Zo*$T>PXRw&`^d(|UoWRaf(#5gEo$lfCTzchbVAC>TH5IAl$rvOylggIm zMj<=;yq-dB|0t#Y+Oghw#x}r4^G~tQbv|RB!4tr;6u`#zsH)|-KnZgr&0C3$kC%=v4N%BI$&G0 zG}n*czUzghZ@58i%A%fXFq*dKxj@pvkWX!Th+8S(X4yDbwaq95eacU+OJcJsK(jge zovNn?cXL|tep$)CRO?rxM^bl3rg(q}WSuQLzFO7M@qfauRR*HU99wbn&}69BtdB8aE-h-W3YLEr#G7FER_?^r>|GEn8)7! zQP;TKG5pPuK%4&YwW(NG$|(M(bY#|riN{P_TCM)@dr6FRwt-Z%8*1-@S-Q7^f=5`} zw?E)?!)SL*-)r&M?mckwJk@ib8Wr{A_m-3MGE5N~dtA>`B=(YUbe5q(k`1pNleo^yNHOX52wXO?(I;c#v^01`JeXlzttyl2i+ZH^wj6zm84$z z_$Yo8r#m)=9XLfxAQ@ zLly2bM0gX;<#gyr9}C|>m65gu^E|EJ_M7ZC6|}!PKE$}|f@&l9?zd?&Ejm+aSgH;) zXgN+b6R*zp%rE#b*j#RKc{di7(@-mXPo5>sBP&WlmQ_^SMxwhtCVS0hpNXS=H?7z4 zBLH8Wc&I^~^!p5(=+G!641f}@B~sB5$mEOT0{aHtD!u+K zzSjJrV`HNy4h|}3{_Dtt9B(f>HT*X`w$PxKt{IhGG=?nV0g)G(Mi_I4>8M(%(q@z(`h35xY;WGy=<`pu>CgK=f;h5GD9j+H# z@v{+!X;IgK-;P$kWiHXnTz8Q)`qy+1SrAm@zKh_DEpDH%yjZ+xT(XltX}vbg@`ljl z`)E3C+S{)&hJ`k=#rr=oFYil`erb*hB&g;j=%}Ql0NeMCBQp$CH-z0*eM}>*l6@URYEk5#( zF}o(2xw}!Xat(^M{*T6-HVZ2AW3NqFMubI&C!u>fYmZNp>FM=w!2{`ev29KOT{jCP zb$&DBU2hjgX?T`v1~OQ#q~Y(u&^2ACYn8z=XoGI~q0lw2=T|JLH-ck}&;moUH3(^1A=jXcPm)Fb}EUqYC6E5zO7 zvCuLSs}u}w1>F{S746*l3&o1dJzviyvqbh%8pvIdkDNanF}+1XO|oQ+CEIg3hnWLY zdv~^Yw^eLYxj#Q`=?%CQTajDVXT1t6FD;JNi(6ZQp%{?dRG5`uTC)`A-vvOdy31B{ zX&JBNe0dq2GUe!}+8x~D{6+m=qNtqVB}>b>ho3`!Yl+LR>*F6LiadP#Qnk;%-&rT5 zhTS!Va?e;z#v3ffwQ$OT270=HZ*vAyX|Bu6HZgF!6r+J)3PTI-l(L_^HmJS6q`Ww? zP9Cc&L1G`nM?^oFPHBw&;Cpg^K>&*gr=m0-yGPS*f!f6RwGjJrJM4RF!^ZPTwNxfJ zgatylXKd*_->23uH?qE+nI6nOKDD3oz@SM)T<@%U<7|H{)R8oNt!UH> zmPb?)B4;hVKdiV}5^!mNGe6;jfS%FS(jZB8F2C;9p}%BBps&?k-sY}1@sKY*1nAES z-8{c;^0aL8Q*@C}U~jD#WN7KoiB09Zqj^=SY8g%F@65B>ndZXFWy5S4TEr+q0T2qi zrwuH`v>*L78~E@pl5C&7$%7DM>*Sq+uS*Xprd{MtCt6DH-q1CF^o*yS5Cz%b!DAcB zztZh!W9bxQJf2;O&iIq408>H^7^#E5%KK4>LCs@-}ulSVSS|)y4J{}+pUJjLz(GD(40%f zCjFGZU+4aVnHcWObUA)9Ej-vThhohAu*#k>J!}bj))kfVYyrg%Kuaf~G=KcJi>6j< zB}G@7a^=X>Yj`3V4FGKg2FZm*bw;~<@na@ZH{!r!Rvx?r{waO)E;KEkEF|-c5ao&V z8@Qp{ZLq)oWH%dL>&ji*aG*1uDX|(ul;26<+B|G58*c3Oar*$o>xiS1wTTU>v%K9U zKsZG*`rMkwz0Ge)GBXu@Q4Q4M$D-+DQL-6q{LV0F)uktx-M{r|-Jg8ZhFgdill>m` z1{v~pww=4L6n30*qy>v*8m<}}?hTA5xBQVOM*sGHV0j@DGvE65DljnHckQGNZ9nQO zQqGU*zC{c<*lm;VYyd)hEb1)==B~2SfBE|tpH=z^e-G)`k8IPtE)U7z5UVCg{fy5t zb)eDrvWjk`SW}2z3f1i~H~&N#>eAhi1)-F;aq{o2H)>HQ#^Rb4lI__AULy-_wT={` znAZ8`yLH+UsxGDV{8!`QO#%xlQnUY2VDayDDYu0vTr?Czz)UqYeltQC z7A&iOx6B^{P4rlZ_0M-rU92d1N>pg%7>HF zlCNB9$6(%@$=<7rndJ8}ziKfjbaDMv?%zPLKOS?Vd5V?fc8)e}=|j!?$hhD%w3`<{ zl8#hJBM3{y@tqbTl4e+o3;M*xGi@VLI_<7iRbWE&gFWMK8D6qtHUZrlbM_mR4YK6+DZD1xE@oc#W{y0oC{PaN6zJn>_(q1B+ z06K~97EO?w1eF{mV+rGnu~-gh|I)e{1rKLGf9mIb(V&_=Ol-rq&9-_3Xt3ai7F9(@ z$L69k(Y*xExfBNtMTV13RK*nx*g2(KBo)-!i#F+%vpp{tM-~n0`9_eh!r=p@hE@=P zCpq_{tY^o`$%xBmuy+))9SAZ6b>c2hv$pG_X*GtW<ct>Fr!{6n z9=m@DFGk>p$*?%gRx~paX|L^iAP>fMv5QP*!TXv^1@nt?J9nw{k%zx=M_CEIyGYIn z5e8rcbXx)vBtp~6-Tjgbg-!S570t>G+!k%ov$ON#6Eg|pM}_85uTpQMqwkzptj%w2 ztK?Qp^z=6l5V4~d1&}W^4x5O8yihb?%`@#G%{7}t9X41>pP8@E?6on zmxVw1#dA^1f1@z#8uQSy+vHmRvXhcJ>AWS$=GCoX@`ua%0}w|os#DqQY*)8-R~G4B z(QDlOI=1KhMBBLx=oC7gq6_s0108&#-7L-fb)^FPI*SNu<`NAB> zz1A|9bOx0bj~V&O$5RxRTiLaH6jYWKZA7dv)+`@+_ac{cv@tBLXZ^c->n2|V-0FO*8-280xu zec0Yniy5B8i487m^L;Op$0XmtbW|Yc%zytiE?y`6=iwKFP@+;+SnzhIe!P)Oo_bMW z8-w?Cz+XZiZ^<3Ic@~lWK90msY81Y=<{z;|KFT?i_f>ePX^`y&>?*32^GbMkv5e)8 zoijEJ7)`rS<4zQucuCi8BL?~|G#U;hFZvD<6@7(t$WL`O=Id9;Anl!6W_@tyQTPvL zPTZr^ck#@GhKLNUoMoAVXj+#l&T-+xiX!au;i2CGVS3n2SsGTupMwx|mu{Y{wRqv2 z0KIAu#J9acoRyrBRh2kL_2l0OS(MGKwGp|tqg=#i-LyHu9YUd%Q}WjxEiv z=Ku+f4gb?jN1B9g2o6d)SL{5`O$6H`&hBMIbDZd5JIwa*@9d$2b48XtgIFH-yhC@4 z$nufV@0j&{$8X9C5QIdJ5p2K$GaTc4*mUNr$GGKuhYK{v=Whe^z}DYOm1_1ch3t|Q zywkF%pKU?P+zVs-0g4jZ9V~LS?TtuFgX(_(v~E($@2s_hsznU!Z?2R(#14vV^drR2 z$y7J6M}u>!VhqnhgQ=7*2l)3rNnyU);N~jEBw8kk=>4eEc`Wr<{ z6&KI8e1Oi+KiB~oKhsvF;rqwd5$NiTg#3ULUV8jx`H-3546C9Nha4*rrc_2R4iiW~ z@wbe8!7^m7nH*qY3N~c|Ry=fzl*T1_U^4$WAZ8G5%(CeOL1v{NVR@A<)w8KFV0+S! zUGC?o`>UTOh~Y6}Ta_fMO*Ohjw&8RHCqf{sXGlRBl3COz36MPYwu zek|~{MW8LzKR)QwAk|C{i|z8U035_TF|u;0Q>A!yJPk6jsuUTFV3V`-p$WY7Amzh0 zb!Q4V)ar5Z23?%7#p$AXyx{srO63qKf_zTeYMENbELR9ieBI_SRgiZR>h3x*2xvYU zrq)IWRri*#yt$y_%b6FWhCM`EZkHIH&7_BNPf&2eV+%6xG@UaREm4DR@n=MTF$)IL zZWvUlW=S`v1@3@{$Jc`u6jPTsQ)lrF(flK8VfXEBVzTIx|JaI^@oQuAyW7)Nw+T7K zq+4!-(Bc*-|HpRzD;h}E!$L!X__RPr_Ii%}2)j^?@M=x6+8NhFZC_h|0UdaL^~WY# ziQ4_Oq4?V2`#5D9nq%!uGGCvA{>?8+PVfrl?-MW(E-h`>ZwiMqMUD49PBWQ*D)s~% zxi#Db${~Pr8KfPvz(D$GM86WdILfaK`HwV2=YPl5xHyGXYG;$`7fHg|3n(xC;Com7 zs97K3cij9al~1zB-wEqKE?5&6Cq)()!vtjTh|_Ev8sCgSeZ{1Y1l1z&GicF@4xnM{XYOun#OEj!4=OYI{5AzfVlLqFZSS z|0c*eM9_*p{@d|JWai-j-l0yo(HXMRo)g-F^PVFJ)ChJ2$i4oj2YYBYj9(b#CywM! zKi*vk4Wj_G&%CgtZ&wL0H%0O3p21!(e_nUv_!w*dd1 cIl{b`CZ057SV&yz2jzf@qNV~|&NAYE0M&96MF0Q* literal 0 HcmV?d00001 diff --git a/include/affine_background.h b/include/affine_background.h index 8e5f78f..31a5b65 100644 --- a/include/affine_background.h +++ b/include/affine_background.h @@ -5,13 +5,20 @@ #include "graphic_utils.h" -#define AFFINE_BG_PAL_LEN 5 -#define AFFINE_BG_PB (PAL_ROW_LEN * 15) // This isn't really a palette bank, just the starting index of the palette +#define AFFINE_BG_PAL_LEN 16 +#define AFFINE_BG_PB (PAL_ROW_LEN * 10) // This isn't really a palette bank, just the starting index of the palette + +enum AffineBackgroundID +{ + AFFINE_BG_MAIN_MENU, + AFFINE_BG_GAME, +}; void affine_background_init(); void affine_background_update(); void affine_background_set_color(COLOR color); // Must be called with an array of size at least AFFINE_BG_PAL_LEN void affine_background_load_palette(const u16 *src); +void affine_background_change_background(enum AffineBackgroundID new_bg); #endif // AFFINE_BACKGROUND_H diff --git a/include/game.h b/include/game.h index 55e8730..b6063ff 100644 --- a/include/game.h +++ b/include/game.h @@ -16,6 +16,7 @@ #define BG_ID_ROUND_END 3 #define BG_ID_SHOP 4 #define BG_ID_BLIND_SELECT 5 +#define BG_ID_MAIN_MENU 6 // Input bindings #define SELECT_CARD KEY_A @@ -26,6 +27,7 @@ enum GameState { + GAME_MAIN_MENU, GAME_PLAYING, GAME_ROUND_END, GAME_SHOP, diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 2e80828..dd90ace 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -138,4 +138,10 @@ void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, */ void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint wcount, u8 palette_offset); +/* Toggles the visibility of the window layers. + * win0 and win1 are the visibility states for the two windows. + * These windows are primarily used for the shadows on held jokers, consumables and cards. + */ +void toggle_windows(bool win0, bool win1); + #endif //GRAPHIC_UTILS_H diff --git a/source/affine_background.c b/source/affine_background.c index f9e15e7..b61be78 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -1,16 +1,17 @@ #include "affine_background.h" #include "affine_background_gfx.h" +#include "affine_main_menu_background_gfx.h" #include "graphic_utils.h" BG_AFFINE bgaff; -AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; +AFF_SRC_EX asx = {0}; + +enum AffineBackgroundID background = AFFINE_BG_MAIN_MENU; void affine_background_init() -{ - memcpy32_tile8_with_palette_offset((u32*)&tile8_mem[AFFINE_BG_CBB], (const u32*)affine_background_gfxTiles, affine_background_gfxTilesLen/4, AFFINE_BG_PB); - GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); - affine_background_load_palette(affine_background_gfxPal); +{ + affine_background_change_background(background); bgaff = bg_aff_default; } @@ -20,20 +21,37 @@ void affine_background_update() static uint timer = 0; timer++; - // These values are not permament, just the current configuration for the affine background - asx.tex_x += 5; - asx.tex_y += 12; - asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16 - asx.sx += 256; // Add 256 to the sine value to make it positive - asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16 - asx.sy += 256; // Add 256 to the sine value to make it positive + switch (background) + { + case AFFINE_BG_MAIN_MENU: + asx.scr_x = SCREEN_WIDTH / 2; + asx.scr_y = SCREEN_HEIGHT / 2; + asx.tex_x = 16560; + asx.tex_y = 14400; + asx.sx = 128; + asx.sy = 128; + asx.alpha = 1000; // This slightly rotates it which increases the percieved resolution of the background + break; + case AFFINE_BG_GAME: + asx.scr_x = 0; + asx.scr_y = 0; + asx.tex_x += 5; + asx.tex_y += 12; + asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16 + asx.sx += 256; // Add 256 to the sine value to make it positive + asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16 + asx.sy += 256; // Add 256 to the sine value to make it positive + asx.alpha = 0; + break; + } + bg_rotscale_ex(&bgaff, &asx); REG_BG_AFFINE[2] = bgaff; } void affine_background_set_color(COLOR color) { - memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); + memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_main_menu_background_gfxPal, AFFINE_BG_PAL_LEN); for (int i = 0; i < AFFINE_BG_PAL_LEN; i++) { clr_rgbscale(&pal_bg_mem[AFFINE_BG_PB] + i, &pal_bg_mem[AFFINE_BG_PB] + i, 1, color); @@ -43,4 +61,29 @@ void affine_background_set_color(COLOR color) void affine_background_load_palette(const u16 *src) { memcpy16(&pal_bg_mem[AFFINE_BG_PB], src, AFFINE_BG_PAL_LEN); +} + +void affine_background_change_background(enum AffineBackgroundID new_bg) +{ + background = new_bg; + + switch (background) + { + case AFFINE_BG_MAIN_MENU: + REG_BG2CNT &= ~BG_AFF_32x32; + REG_BG2CNT |= BG_AFF_16x16; + + memcpy32_tile8_with_palette_offset((u32*)&tile8_mem[AFFINE_BG_CBB], (const u32*)affine_main_menu_background_gfxTiles, affine_main_menu_background_gfxTilesLen/4, AFFINE_BG_PB); + GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_main_menu_background_gfxMap); + affine_background_load_palette(affine_main_menu_background_gfxPal); + break; + case AFFINE_BG_GAME: + REG_BG2CNT &= ~BG_AFF_16x16; + REG_BG2CNT |= BG_AFF_32x32; + + memcpy32_tile8_with_palette_offset((u32*)&tile8_mem[AFFINE_BG_CBB], (const u32*)affine_background_gfxTiles, affine_background_gfxTilesLen/4, AFFINE_BG_PB); + GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); + affine_background_load_palette(affine_background_gfxPal); + break; + } } \ No newline at end of file diff --git a/source/game.c b/source/game.c index f58d644..9d3d73a 100644 --- a/source/game.c +++ b/source/game.c @@ -20,6 +20,8 @@ #include "background_shop_gfx.h" #include "background_blind_select_gfx.h" #include "affine_background_gfx.h" +#include "background_main_menu_gfx.h" +#include "affine_main_menu_background_gfx.h" #include "soundbank.h" @@ -33,7 +35,7 @@ static uint timer = 0; // This might already exist in libtonc but idk so i'm jus static int game_speed = 1; static int background = 0; -static enum GameState game_state = GAME_BLIND_SELECT; // The current game state, this is used to determine what the game is doing at any given time +static enum GameState game_state = GAME_MAIN_MENU; // The current game state, this is used to determine what the game is doing at any given time static enum HandState hand_state = HAND_DRAW; static enum PlayState play_state = PLAY_PLAYING; static int state = 0; // General state variable, used for switch statements in each game state related function @@ -241,6 +243,8 @@ static const Rect CASHOUT_RECT = {88, 72, UNDEFINED, UNDEF static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFINED }; //TODO: Properly define and use +#define MAIN_MENU_BUTTONS 4 + #define MENU_POP_OUT_ANIM_FRAMES 20 #define SCORED_CARD_TEXT_Y 48 @@ -429,7 +433,8 @@ void change_background(int id) } else { - REG_DISPCNT |= DCNT_WIN0; // Enable window 0 to make hand background transparent + toggle_windows(true, true); // Enable window 0 for the hand shadow + // Load the tiles and palette // Background memcpy(pal_bg_mem, background_gfxPal, 64); // This '64" isn't a specific number, I'm just using it to prevent the text colors from being overridden @@ -484,16 +489,16 @@ void change_background(int id) background = BG_ID_ROUND_END; } - REG_DISPCNT &= ~DCNT_WIN0; // Disable window 0 so it doesn't make the cashout menu transparent + toggle_windows(false, true); // Disable window 0 so it doesn't make the cashout menu transparent main_bg_se_clear_rect(ROUND_END_MENU_RECT); tte_erase_rect_wrapper(HAND_SIZE_RECT); } else if (id == BG_ID_SHOP) { - REG_DISPCNT &= ~DCNT_WIN0; + toggle_windows(false, true); - memcpy(pal_bg_mem, background_shop_gfxPal, 64); + memcpy16(pal_bg_mem, background_shop_gfxPal, 64); GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_shop_gfxTiles); GRIT_CPY(&se_mem[MAIN_BG_SBB], background_shop_gfxMap); @@ -520,7 +525,7 @@ void change_background(int id) sprite_position(blind_select_tokens[BIG_BLIND], 120, default_y); sprite_position(blind_select_tokens[BOSS_BLIND], 160, default_y); - REG_DISPCNT &= ~DCNT_WIN0; + toggle_windows(false, true); memcpy16(pal_bg_mem, background_blind_select_gfxPal, 64); GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_blind_select_gfxTiles); @@ -619,6 +624,21 @@ void change_background(int id) } } } + else if (id == BG_ID_MAIN_MENU) + { + toggle_windows(false, false); + + tte_erase_screen(); + memcpy16(pal_bg_mem, background_main_menu_gfxPal, PAL_ROW_LEN * 9); + GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_main_menu_gfxTiles); + GRIT_CPY(&se_mem[MAIN_BG_SBB], background_main_menu_gfxMap); + + // Disable the button highlight colors + // Select button PID is 5 and the outline is 3 + memcpy16(&pal_bg_mem[3], &pal_bg_mem[5], 1); + + affine_background_change_background(AFFINE_BG_MAIN_MENU); + } else { return; // Invalid background ID @@ -1015,10 +1035,7 @@ void jokers_avialable_to_shop_init() void game_init() { - jokers_avialable_to_shop_init(); - - hands = max_hands; - discards = max_discards; + change_background(BG_ID_MAIN_MENU); blind_select_tokens[SMALL_BLIND] = blind_token_new(SMALL_BLIND, 8, 18, MAX_SELECTION_SIZE + MAX_HAND_SIZE + 3); blind_select_tokens[BIG_BLIND] = blind_token_new(BIG_BLIND, 8, 18, MAX_SELECTION_SIZE + MAX_HAND_SIZE + 4); @@ -1037,8 +1054,26 @@ void game_init() deck_push(card); } } +} - change_background(BG_ID_BLIND_SELECT); +void game_start() +{ + affine_background_change_background(AFFINE_BG_GAME); + + jokers_avialable_to_shop_init(); + + hands = max_hands; + discards = max_discards; + + // Fill the deck with all the cards. Later on this can be replaced with a more dynamic system that allows for different decks and card types. + for (int suit = 0; suit < NUM_SUITS; suit++) + { + for (int rank = 0; rank < NUM_RANKS; rank++) + { + Card *card = card_new(suit, rank); + deck_push(card); + } + } tte_printf("#{P:%d,%d; cx:0xF000}%d/%d", DECK_SIZE_RECT.left, DECK_SIZE_RECT.top, deck_get_size(), deck_get_max_size()); // Deck size/max size @@ -1055,6 +1090,9 @@ void game_init() display_money(money); // Set the money display tte_printf("#{P:%d,%d; cx:0xC000}%d#{cx:0xF000}/%d", ANTE_TEXT_RECT.left, ANTE_TEXT_RECT.top, ante, MAX_ANTE); // Ante + + change_background(BG_ID_BLIND_SELECT); + game_set_state(GAME_BLIND_SELECT); } static void game_playing_process_hand_select_input() @@ -2375,7 +2413,6 @@ static void game_shop_lights_anim_frame() memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1); } - void game_shop() { change_background(BG_ID_SHOP); @@ -2473,8 +2510,6 @@ void game_shop() } } - - void game_blind_select() { switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer @@ -2639,6 +2674,48 @@ void game_blind_select() } } +void game_main_menu() +{ + change_background(BG_ID_MAIN_MENU); + + if (key_hit(KEY_LEFT)) + { + if (selection_x > 0) + { + selection_x--; + } + } + else if (key_hit(KEY_RIGHT)) + { + // TODO: Don't allow cursor on sold items + if (selection_x < MAIN_MENU_BUTTONS) + { + selection_x++; + } + else if (selection_x < MAIN_MENU_BUTTONS) + { + selection_x++; + } + } + + if (selection_x == 0) // Play button + { + // Select button PID is 5 and the outline is 3 + memset16(&pal_bg_mem[3], CLR_WHITE, 1); + + if (key_hit(KEY_A)) + { + // Start the game + game_start(); + } + } + else + { + // Select button PID is 5 and the outline is 3 + memcpy16(&pal_bg_mem[3], &pal_bg_mem[5], 1); + } +} + void game_update() { timer++; @@ -2656,6 +2733,9 @@ void game_update() switch (game_state) { + case GAME_MAIN_MENU: + game_main_menu(); + break; case GAME_PLAYING: game_playing(); break; diff --git a/source/graphic_utils.c b/source/graphic_utils.c index b568442..2c64e88 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -186,4 +186,34 @@ void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint wcount, u // Copying u8 data 4 times across u32 data dst[i] = src[i] + offset; } +} + +void toggle_windows(bool win0, bool win1) +{ + if (win0) + { + REG_DISPCNT |= DCNT_WIN0; + } + else + { + REG_DISPCNT &= ~DCNT_WIN0; + } + + if (win1) + { + REG_DISPCNT |= DCNT_WIN1; + } + else + { + REG_DISPCNT &= ~DCNT_WIN1; + } + + if (win0 || win1) + { + REG_BLDCNT = BLD_BUILD(BLD_BG1, BLD_BG2, 1); + } + else + { + REG_BLDCNT = 0; + } } \ No newline at end of file diff --git a/source/main.c b/source/main.c index 76abc07..bbee8aa 100644 --- a/source/main.c +++ b/source/main.c @@ -44,7 +44,7 @@ void init() // BG1 is the main background layer REG_BG1CNT = BG_PRIO(1) | BG_CBB(MAIN_BG_CBB) | BG_SBB(MAIN_BG_SBB) | BG_8BPP; // BG2 is the affine background layer - REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_CBB) | BG_8BPP | BG_WRAP | BG_AFF_32x32; + REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_CBB) | BG_8BPP | BG_WRAP | BG_AFF_16x16; int win1_left = 72; int win1_top = 44;