From d33483fcfecdf0790976f4bf990d14acb2ce08d9 Mon Sep 17 00:00:00 2001 From: Metehan Gezer Date: Sun, 8 Oct 2023 21:33:53 +0300 Subject: [PATCH] winning, refactor and loading screen --- CMakeLists.txt | 20 +- assets/images/glistengine_logo.png | Bin 0 -> 36282 bytes assets/images/outliner.png | Bin 121 -> 1391 bytes assets/images/teoncreative_logo.png | Bin 0 -> 36270 bytes assets/images/teoncreative_logo_white.png | Bin 0 -> 80645 bytes src/GameCanvas.cpp | 304 ------------- src/GameCanvas.h | 80 ---- src/app/Button.cpp | 1 - src/app/app.cpp | 38 ++ src/app/{gApp.h => app.h} | 4 + src/app/button.cpp | 1 + src/app/{Button.h => button.h} | 2 +- src/app/gApp.cpp | 28 -- src/app/main.cpp | 4 +- src/chess/ChessBoard.h | 27 -- src/chess/{ChessBoard.cpp => chess_board.cpp} | 105 ++++- src/chess/chess_board.h | 58 +++ src/chess/{Piece.cpp => piece.cpp} | 0 src/chess/{Piece.h => piece.h} | 3 +- src/color.cpp | 85 ++++ src/color.h | 38 ++ src/game_canvas.cpp | 427 ++++++++++++++++++ src/game_canvas.h | 91 ++++ src/loading_canvas.cpp | 103 +++++ src/loading_canvas.h | 42 ++ src/{MenuCanvas.cpp => menu_canvas.cpp} | 74 ++- src/{MenuCanvas.h => menu_canvas.h} | 16 +- src/{MessageCanvas.cpp => message_canvas.cpp} | 4 +- src/{MessageCanvas.h => message_canvas.h} | 8 +- src/net/Packets.cpp | 1 - ...essConnection.cpp => chess_connection.cpp} | 129 +++++- .../{ChessConnection.h => chess_connection.h} | 85 +++- src/net/packets.cpp | 1 + src/net/{Packets.h => packets.h} | 31 +- src/{Util.cpp => util.cpp} | 6 +- src/{Util.h => util.h} | 0 znet | 2 +- 37 files changed, 1282 insertions(+), 536 deletions(-) create mode 100644 assets/images/glistengine_logo.png create mode 100644 assets/images/teoncreative_logo.png create mode 100644 assets/images/teoncreative_logo_white.png delete mode 100644 src/GameCanvas.cpp delete mode 100644 src/GameCanvas.h delete mode 100644 src/app/Button.cpp create mode 100644 src/app/app.cpp rename src/app/{gApp.h => app.h} (85%) create mode 100644 src/app/button.cpp rename src/app/{Button.h => button.h} (98%) delete mode 100644 src/app/gApp.cpp delete mode 100644 src/chess/ChessBoard.h rename src/chess/{ChessBoard.cpp => chess_board.cpp} (56%) create mode 100644 src/chess/chess_board.h rename src/chess/{Piece.cpp => piece.cpp} (100%) rename src/chess/{Piece.h => piece.h} (98%) create mode 100644 src/color.cpp create mode 100644 src/color.h create mode 100644 src/game_canvas.cpp create mode 100644 src/game_canvas.h create mode 100644 src/loading_canvas.cpp create mode 100644 src/loading_canvas.h rename src/{MenuCanvas.cpp => menu_canvas.cpp} (73%) rename src/{MenuCanvas.h => menu_canvas.h} (88%) rename src/{MessageCanvas.cpp => message_canvas.cpp} (97%) rename src/{MessageCanvas.h => message_canvas.h} (92%) delete mode 100644 src/net/Packets.cpp rename src/net/{ChessConnection.cpp => chess_connection.cpp} (66%) rename src/net/{ChessConnection.h => chess_connection.h} (57%) create mode 100644 src/net/packets.cpp rename src/net/{Packets.h => packets.h} (86%) rename src/{Util.cpp => util.cpp} (94%) rename src/{Util.h => util.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f1e773..5cd7f1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,16 +82,18 @@ add_subdirectory(znet/znet) ########## SOURCE FILES AND INCLUDE DIRECTORIES ########## set(GlistApp_SOURCES - ${APP_DIR}/src/Util.cpp + ${APP_DIR}/src/util.cpp + ${APP_DIR}/src/color.cpp ${APP_DIR}/src/app/main.cpp - ${APP_DIR}/src/app/gApp.cpp - ${APP_DIR}/src/MenuCanvas.cpp - ${APP_DIR}/src/MessageCanvas.cpp - ${APP_DIR}/src/GameCanvas.cpp - ${APP_DIR}/src/chess/ChessBoard.cpp - ${APP_DIR}/src/chess/Piece.cpp - ${APP_DIR}/src/net/Packets.cpp - ${APP_DIR}/src/net/ChessConnection.cpp + ${APP_DIR}/src/app/app.cpp + ${APP_DIR}/src/loading_canvas.cpp + ${APP_DIR}/src/menu_canvas.cpp + ${APP_DIR}/src/message_canvas.cpp + ${APP_DIR}/src/game_canvas.cpp + ${APP_DIR}/src/chess/chess_board.cpp + ${APP_DIR}/src/chess/piece.cpp + ${APP_DIR}/src/net/packets.cpp + ${APP_DIR}/src/net/chess_connection.cpp ) add_executable(${APP_NAME} diff --git a/assets/images/glistengine_logo.png b/assets/images/glistengine_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..76c5d20acbdaccf98033d3e7f02c9da3b6d50ef7 GIT binary patch literal 36282 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�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 literal 0 HcmV?d00001 diff --git a/assets/images/outliner.png b/assets/images/outliner.png index 93eacb23031c6a2cc2e155309b35bcd661efc0b4..f85dcf47ec33aa7bc0393ada0bfda2142dcb6297 100644 GIT binary patch literal 1391 zcmbVMJ#W)M7|;4bcoDSO4bHv?_Tm-M3aYz_xV5`hXS-Xh%=M*9Xt7IxAQXzC zZrF}e(slJ7FM)OT+tN`FqPARpIWvehy>+xA6M@PmHW^PQf zTaIJc1yaNWm(bwS!C=CDvQfD@Fb7|*-cl+imeuKW%ud0SNz<~+<+6pHi~|rxx)Ukd zHKKHS$WRd}OM+MhGC~<6ZOCoq>fmf&MHuI_Q96he#LVi_*s@KWsp=50XYzz)^}oIZHQEE zCrqr~2RElPH8EL91XVJrOW7XgYJKQ3a^_4M&3cptQ6}R2FGoa$D&gvow}N3~0~hMp zCfFg4eE}B;#(k(KdEoEtgU;0f;mi}q*#m{T;Z)JTf;l6;OhO8hgOE0b6-P}S<$)wC zvMm!Z4Bi!bUU(j9V3A)gXm*?F@S2mbf=qwFA_v143C=->%NG z#0stteg}t+K%chL5eaIkV=&~-)+)>O*^})1j~`2;GgI%-=_gZ{pMQEfe*EU>?DZ;V Y+UNJd%aO;gk7OgUwz^h%apmsApI+y%6#xJL delta 71 zcmaFQRXM@JkwM$j#W6%AClM$)0XyOr)zkZz>A8&p6VL^_lfVUX@ry1PTVOBkB-;oiS} z|L5Lw&OPg_duQnaW}bQ8r{AZ(a8+d)Y|N*aAP@*!PF7MK1VY*ZfxxopsK7fNl;c#u z4-7}y*DfFs7T&{uFeo+sFAxYd-bz#3Ra;3>(A2?>)!59z#GKXB&JlnHfrQ089gR(G z%v~u>%q^|#MPP>wEig(eGZB~;j}p6*;|udQR(y^Ely2<#7DLE!g?x7lEne?VMqL|_sR2U2P)sZzdha5kqDU}a}9WoKun z*XG=B?0RaIvcFqSJ00fJRm%Xd8CyTuc)qgNZn!A`fTRFN~ zIoMM^U^F&yaB~%b0mS~zg`MNSXzgA8krW^^Hcw+mHV#(y2d@4AnwkC!=ji5a`{!^o zQ#Ny3b31c;R~G=5<6l_EHx8~2E^i$EC#e7Z_`f>)U@P)Ivv8#i#rh|j+e{`k#ACf6Kxmh_V z>6MI4t?VC|VE8XzF_$!UH5Y*adgEeY=Vf8%*W~0BWakI;#>CDg$j<&ZsFH)3m4(-T z1?6Mm06;kefqxwTJt$x|X2!0@|F6Jirh*m@&UVHC%T{*Amga1Z_LeZpe+4P{!ok+T z88{fAj_VHypK63#xPLBV4U(&(U?LoKy`Mw$OeG^^*egSSXQx*#WGcy)$PCjE60X}nM z7Jg$6Gc$H`E-qeE^Z$Hb#n}pQFJs&PV>}N|_h1x)vQ{pDy1f4J2@P|ne}1#IqWohA zg2tu~_ALT4eNe2q8SJ08t^NlR_}}B;Z?qn7%mJkT3w8eu=Hg)C>S63`E@25s>wm+b z*#2kayBNFwuZib1F*C6+;Q-`q3OGDB2agGhfSH9ki?NBhDL3^92uf+dr zfDbX|KeqaRM*KgbHGN}jZ)pz1Og7m6IXnM**7*O_#lP(QSAY8dk{z~(Ncp#&vHjmo z@Xu%eC8`3-{PPwNsvmy+_nH9y`1hhQw+AHU3|u3ZV57eKL7*N&7Fl6YXFicEz#*2%;hP6;!d?nR_Xy~A^%<|C?Tzq7(92PE3 zg}`CCm7r!*K)UGflrNSZ&$Zm#5Qi@Mer`j1wpn8n6BC=FE20KZki-6d$-3mF>Vu(w zztjR*VSirn=$OM&l7C*f;^6v!Kq2(vM1KRyfl#*ohJ;~cgY^G~qz2<>NBj*+9SCv# z8!`@A^X9D$*jclO-cZB6$b8a_!Q@Q-aID+9=;p2~i}< znzfmEYhL{!TL~Xoq9cnd9wZ_mtmp_9XH0};D97}yJHvZ6Pj%5G%9L1>eDrA(QXcoW zB5&1MynIEy0#OWXo<`hW-rnB2giv}8BW@d}O7*Xi*<18j`RYFW!CTT70ozd-MfU~} zCiU5U8rl>~AKF~X>M>hHX&js!LEOrEi%QPw3+ktt{kp!BUyjBm;hooIOe{5M@xK*G zl>g~*=PPcR@*qXo;t1+b_BkLwagZuKe&^=tr3lu$_Ad3J@zAktSC2e(HFj3qXC#$c zjEQLSd7}g*ytcKT9q+O4i!>R}RqzWRR3WRY8Yn93#E*Sn=5V-gsrRt30zk zk)@$^=cUKN*>i~7s2eS)6`{~qgCfnlX8VQud)+4Qv!#8pmxly@Q{AT;c)-0jw#~iT z88uf>T)eB*T1=1}QHctWTQK$;fw;f>No064^B$Xoa4z7v#2*8#3{%D#HneVx**@@} zn08vVu;fe;sVYg3wfRc>(Z_$G-fc;z%6h_lLb)1$!kp=kzT_r*z*h=U=ikY*Qp+xj z2Mh5PR&Sj#a4YlD!XCwJdYN$&^V&{3{`x?`)cle)iRn#m!-Hxn1L;k+H9NAte;5AR z=5-J?H*y`4b#JnF5l(~zRV=A-5*Wzh`Xc{ikRHr1!B+h6s>nOyEi2?7Nm4^ z+;ppnUX|!nEv53<*cadFTCr%V=9aeas?L_Rs|8abbF$O>!*J(u6Gv+&y z8uqmeJnw5h5#b+?l50XJBM_K44#FSry;;`r{H4|x1HiGVf+)^jh5HrEFqR*s3Wk7q ziC)1C{M^r`7e68f}(a_fn&eh>JbrSAL*Oc-MaU~fB}Yn#PIk<-1j`%H47 z6|%&Ls8Oqyj+Ry0?!2RXMRx8?iovU{s_mi#ccvk@vJJ%tT-EMnyN#7g)#g24 zdAfVd`|YlyPW&TUMTnScHtXo~uQsDoaJ{+{5u3?xUZAMlKR)-o(j_nx60C`s&PK4^ zi-;nwwwLI|41<5OXVHLq!T8R(21sq?{=G!xDwpXA$D5)G*0w~EX~@lh)8$HOhWz&G z`^4gNeRZ~*q}pVVP5H;4QVaDF5&>3{w!iqI@Ad9j##+=eb;0?R2gwl@h>SkO_uPGM zALQG-qJ2}byF@LeEWh5IJd{M?b<9ZjVqTntGh2!hd5{F^VIo7L@JEN*4<}x9zwTF2L5)@#&(exf zcTz=|;<+<7SG*Pj2w8M~pUdZ|OJC>wQBFdoM&N<*)5%1R2GXM)V!F&*NpmLwvX7=u z(V5U<`&ODD-Qw$|0qO#me46&nlbZIE%v>J~N62?zatX=>GiAmdL!Vf5-T$K1eHSA= z@<1cC#XfHKoZDuQ))ppj!`@{Cm!F2{%h!5uHT!cW*Fh%}BI6C&z8!`P6t@AI z?+lR-UoL{(;eofw+^GUaGS(go5j$+y9B;BwYS)pDZg;{Xh~l89eqwWDV=mffU7!-V zKT(EvI1>6Bf4QJDvH+o?GM}8nV@DU@#y~ui7Z1yyj>sT06CS0#Cbh3P{XqTqadK6-8O2)YkdY z0uSSBj+s}Z)2Ll`9~JWZxct+f>&s#bm~+NrN;_A>yfc#6CHvF`!bblPykIZJA{h>T z?_FK8#lq~~7vV93M#(1K%21r#a%)z_D}d?VJKxdaQ{6&)O1y%-xT1#Jd&NIg_`#kZR<=EBD;BH z5yVHxc;6UxQWUDud?|Pe^RWbzf9&f?C!-v-7~SSB)`H*tj$mu{#7N!vgOI~2l;L2l zX2vOW{Kq&`$Q|LM!M4ak4VY(h*!^F*)&63aSa3W*7`03$I@BW~N6)J@m3+s`V)Zu>9R z0^DGWl>NW zmQ+J%eHgdSXVvMV8Mh}7#!no@FEiZJKkYl09ck&zU-b;98?`L|?Y%1T$yoR86(2rp zOWJRla~kcMMcaXD|A&6-4g`6{j|<*E)_h}cY53XMzcoOM?*C0Fwf2h z^e3V%{NxEfKueUL?Q?6Y%i$H1H-(%52G!-)xX2fOyTE|Y+LZ8{?)<0W_gO_hoZi^c zagVr>BVh-~k@Pjy&L!@Hwg~aG0+lT$i)jI$_VF8j-#5g^n4Nmu^qd_od*n!b$fFx4 zbl{6gber*8nWD|G@~zQ`u&mc?s*>5;U`on_p2q5{9HRO^xx8FsZGP?8?VX4>m!D}q zDv6-yxz%ilq7me*0HQu;t8%wj+>_-9E~>G8!5#o^i$}5WtB1J78Dj(oKL1=+cl$lX z4H~CLV!b&lX(Y)0vrY+q=TC25h^HbciAxjR)FK@Cdpg{&h}3{)YZXWaw3FI<4hQE5e&ct ztm>yBzd;VP8$sHyaeAe0LW7(HI1Po9f0Jhw_}(3VR2D!DIM8eSzTmk^n@TA%+=e&v zmN+>@0(@*oMT|D*H~_gek;YI^DpBKH4-5d;Xa%^-$RK5-O{4u4fw3(38nu?(GkF75 z`mEO<>nLbv-)$mGX4K$2nfu|R+vc}k3o2kfaLua#<=LcfBD~--p(BgzmNs*_S!Gg)u|gz)nq2r5@bkMui8qf33!>{NWJ11vnmT{o2?zL3WM zsh=-E(L07sUG&!DRv%5$MXwj&& zJPj}mcibwFh%L-fC(=z$kfiYWsVGx*|9)UoAma2SuzsYx_0_~&!Pk}sJiJ1~SAOZ- zOQ`PATXikqMgr{@CHsV%b<6I#O=$d#?d1nQkhiMm-LL$g#PLGs&=WTEI<51jq&>;a zM1qMFkZ}@^>n-B0e>&lp-r~%_@18WWR`BRLiI{yn);D{C$1cHKIW((YQ!$2QU~8hU z6GUe0x)gx8D2c8S47ad^{y2M$k;Fy7|5q&%9zWUh-))yhizvQ0Tu7^i$=Pn!TMoY( z^WXOA5E;KtL$Z8Hf#%j59by+FEmHBbl-M@u5DjYeLJei>?5XsncL4n}@>neNPoIvm zj*jzN-p?C{YSiw4Ij{YrmVdfkxNJ%kEm0@nLAAgYTLe?5TKbfdntT6FpewX_Tar&w?}y$j+!?c|4cy z$=n4BT5Bt;qB{)_{$5+ePF3gP#ASQtRYtc={5QW(J=+%O4A0*n#v{KJFNSl znuW&}IA=dk2c{wc_jM=GTCE}*w+Y<6nAjZTwQ_C!Maz$L!Ffb^8;^;Z_{yS!o zhrP;5qi#2aA9#_Zrp>S{*67kiwxCsmL{m^l$k2s*hs*VB5J{hO*JjNLgO1n-?FeTX zF<$<)=Bt)b{G-JWa@J@gDn2njlU*bn;e?+BDq?>R5>z>GkRur zz8G5Ca+7ugS83n%VYzF(L}vPwe75~mEopEvI>=V2IbV8=<7vG#Mez}@ekjNTJjYj? zZs8+VmFxcGwmRC$qu&q8AE>kWLQeqm*LbAu8F1NuK`(u2E<&GpM8Saj?WFr=XsX-L zpKa#w_NhZVH;~Bmhk4WH0ClloM)0{3$v%g3$SK58)S}^=yXd(Ln8+x8`HI`WvLU7G z04I6PbN|y>qrO3CSS5#)eMx@@aJ!U-1q48OT@!9MV!938C;-G1Yh5ct846|IC}vz1 zOngu)x2MO%0{X}~E2Vq^JQm}=OZk)ZqSqh<1pX7bVqiA^+lX^(R&mU#UJNU2^cX+8 z25BfH9j!P5Ip*V$`dGLBuBGeknS}Gb551=P1zZ2SJM7sPzzz1aCxiCJzTf+lB~2?M z-;>Ki|EhZMaQ0d90%5`onKc>C{!u*;ua&^wLdU`h$9^v{?!^eUc4)5qsCo>~Kr?=K zp+;wd!F8vt@MNByr=fVzxHy-&Ck@~lke||5g^Gb6$lDDZj!f0B5K2Zk<0em_;Zcy^ z?rY%JSw>zM_Yzs-kyG(Pcifm-OE0ddvYu%-{@DAR*^aye_7OerS2{_LK@`MG|w6kInB;5B{|*X!LZSYr)TFd2^!6 z$*zeOHX7#|w2u$Au;Cq|yKo3Mf|`j|u)R|_pg{z*bos0kUSJVHnf2e~H~9$iNJ_4m ztB*^o-9v0Af7DaIrf}rg@T^j>Kp27=Mn$=h0Fle7Y18$p&%N-YF}vUF!)L8enjf)T zu{-w$(lzu~tUz`SlXBEnZMI63E zzVnS~<-P#@r|^uQn954;b`(kP45SQn&7Y|vfX0oG$UCmv7oZ;LDxPo=*AtKD*P|s@YZaqa z%YbxqiVk2f>;jNJ>WOf-L|J3ly)24DC*fMONJjg*NBm_g>qP`1v_H+}jy0o{XGW5m z)f!zPXDz*pq#<=q((({=$2a=43J!x}l@s zSlGZEm->QlBrU`T@&TK2M6Gb=P*geJ-{UU3v|37EriU;fEg@};PE$_87kgVZ#DjEH zi3s@li z+(6qI=bukv`slMl`=7d(1L)A235gS8Ut>9bUF(Xd55uBO<50Wg6O@) z7~Ze6dgI&C9NHE#NFUXvc$*RFr6h-?4MBCcm`=N`@jj~}I;D^?XlT17sRh-d;(a9I z$oXZ;p0mbYc5t4~3dVtWfQd|`C&WH%zxB3Ut13P8Nd`6POOJq+k?m13v;7Pb!eqzj z#gkTgyj2;Y!l=K^dVEbBI2#U?wudZLMO}FB5@LQuF)S-3+e(ii`N>3Z%jS8D5xVSG z=WON-(ELK(It_Bl@oiR0)|Cgl@tFHlhdT4?ET-VZvV&`a^KnJAzpU4|rg(zzW-%I$gI$RF+>oVGX zT?Pt8yPR4RlSh^osC>!Je6jJe>GtRUimE~CGL2se5?D-?r-N}qdVjG}Z5m6DN6_4$ zMW`~y3jIcN)xQMIz{%v7eJ)Nn+TWkW_GBZ&VN@n!{Ja;HIX~QUtG9&7dj{_A%Qcig z+Ab_i4HsS|6_Mpox<-Vsbos^fV${!EX{M)bBv!lH!@`b}Go-GlXlrh*6P_=b|0%~CcQEc1-&da^i= z?|od99$&!zZMVD~{jF2vrwD2Gln*@B%SFhuo$4mU&BQl8XzshzK3_6)gSG$4nMBiJ zuaRu8>hUD8S;(2ygmZJS+yPM%$M}hGrGle<238|(RAxk2WHQ9nD*dA+=Kdp) zoCeK911Rqc(&P?nh3+E4TS0irdAU1RoiJlMsjcxq;OkePUI19gvgn$5&rsv8L} zkOKEmwqB&v9p~761S#Fn&$h0K%*HL zkiU+3)P_}lbDOyKx87~k4Q~R?ZSNm`D4Jh_xCAncN9%k3XjIcZnMkWrEBz#d;)&01 z@^SsqgikSIzidKBWYgpm)AVb|RWK2h7{Y@5=|U5sipWBzOroh8lj(LqJnJROR9uf- zE$a749ZzQcOKilpFTZ3)GPkPn=`?NvazELb9j|UE_Yreha*{)lg;#RmSCR_2+c+Vp zK#ipBF`Of`lcK}BPhgMmJxagMZ#HlmPwjk}$IHGsak~4FF3d&Hdy!)xtL0`bC->cZ$5OpS>5ALI2^bqKfqczqa7&2hFL`Db7^k%%aH~Pu;um*eTG=c~7N{Pn9M-~He^rtd7EnYWUYI|%pG&{sy^q|v z0M}EBHbswn?2Tlb06@7)!}uOnnWSaSZ|}1>kypF#meKG_lV6-Oi3Q8gQpYn9CCVyG z>d1{Eu{4?SmhG5q9pqb?swN^1V0{$sjjEmwr_7Eb%d5N{yG_Jo%DaM%RJBGy!od zQ3KQwbrj}w@x^)$1s?I4l@Dpi6t{!NCQX^sPzrgH%iBQeb_>p$UctV$@vZ7KGd$(+Vp^%god6)+?tK@tkY4+CE2!Ana7FEgp z_Z0!h`1;9ClaTkqx7*zX$_4U}mQK~`eRPJg#h_h_R*J7Ni8K0=W>omu3eL#MB{Q7l zZNad+1OoNBeepZQlsZ4cdz4}>!f2cGrp{%6qTpdr_9#K0i(A{#4C&`<=#(k8qv6?i z5_~?U@0l!9C4ETaoToD8T>ba~2%Z|7(y$yWD$$&Qo*-yKg4<|8Nb&F^iD&ciAhfQI!CJ$%yd8;x&g{VV>6?1`6nCz3q!JgRy@A#bZ)WBUO8KP9oY9t+-!_B7|lN*`cusZ_IjHvAwuBz6qn9SY` zdJ!bRkywLLb+$z?PDlVH7AKOjVsV$e9l>pj0GdVuZ*SaUVz1BHjxh0n9%u;m?nl5_ z&9>SlR``v4f0(ltE;fwKr7bi(Jvtc-zJw;FpybQwb>>H+T?Mh>-KP5NiZ548bjf)h zN=f3r0M}RMla`fA9%bPgn8Ri$ZqjdFA`)&#Jbo^hCxahG4?S zW4v*OYKv7UxS9KxGiUPSIE#~@p4Np{6%%FzPOD82?!$=e1Q!V8^}>``Z9BMk>70wx zuh;yA(%K2`X)AUMlsXYWGd>_nj<%ra5GZ${GTEf|0n{}74xO4l9u8L)Wg1s>pe{(# zPfdFqNB^_q_sPBZP&r`$<(0ZPFQvA6dq8$DB9$-UepPCX?TRmDh+MYJTjZ{>PIW#z z5pT)XrP zDj=E^Tob;+WqT52^Y23i)&sk6GV{v)Km64GOifJ0qk?s}nBL zNVRLqm(q(?@l6@y>jZN0WFtT3Bc|oq6CTyQ=HArjWg&!EG zBgKHZ36;n6v1fwM@#bL3!RJh{3Izsq+w)eEg1fog+c2^=J+9nlZRv@V0MlQdk5UQJ zXVqLuayQvC@C{K2J2gX*0x1&aU7kx)6Mm4+bukm6|8zvbh|7H1P5K)fQ)}oMq9p5i zejm__xC46Bnd1^<(75-fh2|%y+RDE*qH0>run}?_^xjaeuh*SneXpN$N)PW}8x}2o zXr*5ETDIYsTxAg#?K}YrR~c}IZ2Bp-WVQ4zp30#D3BYYda?pXwiR@o@?Hjmr+L*q?P$`kEFd z+XalGGkTDmpELp$f9)d?IHkw<_8Po4X>YUT@%qP^7fsVR#K3%bl*88j?2_YSmByLq z;Qqq9|2}OBRsVCxw$s%-cfwV z&4J2eJp2K1zv#Wf(J!5wy3=gE@v!=^$`Fo0Q<5iBBz1nA@9TZPcpHA^9cWJ3+p1f* z_J#k|>s#%emCN>*2X)gUeD<8}Yoy{-Z8l(*Kg@U?`$3XvA8Z~>1PQKVXnYN)4VW*| zJimULr-9Seay9f&Po|a3_y(*F(ZMpdtd^Y=gG+MDB;YYKW7o#k8K)8%Eft6uNkg7$ z@FK>1lvNBhjVw+e0<7Dmy0{9&fK;#fb~2s=BE7n+Lk;!}3^b(8&R1N}xW~C5{U3?P ztyt(A1Q;7$xdt^f?=)C*Z;o#nGOn0zt`C0nd3$Q)19uZpG30K*meE?xHa!L&^M9^( z`_yDa@U;cY1?fi@hfPkGv|fz^(zU7r;ncTP0&yna!LHV^2Z&8xPMM7p?+_s3O=!-sIX%C1Ky0TT*wT)^qde&C{)8gKB z|1&F0`svtlM#&=QpkIakwl$gaM3%;*{%Hdh)C%6K#SzlTXIIQ+1XV_5DZ9gV**AoW z1rpJ#vi(9is1TgRUmc4A!o+@ zCLecu(uQB!7&DLX4^Qe{edyyk6Pq~$N%FQHZ!CjxFtN{4ziv<6yMp>DtU)Ae@X11s z81;*CDo0gC^NH2co_pLf8^!g-*G)^><;@mFHD@}+F62rm2T08m-+IHtD!HU^VK2-P zs)o8h0?N?Wznit3YMdl3$Q&$Fh}%E9n%p6YVD0^Ihub+_7=b-*6prRHY+Tn9aZaK{KPrI zfnakHdwAjM{Vs*k0&P9VLl2Ps9YI6xeQbeevI`P`qOQb zi3YbALE9R=#Iw(~VfzCMnZ5cgB-C5HAE%6V=id=;`#Dd`n5->6nn&3aFByz#bo74I zZ+7qBuX)PHR~D({1-THisPs3@pppBPNyID521y8<3(VsFBVnnLVA-5p_Modq*jLmsWF7EAytN9aK)j#7a#EztUvcHErT5$9-oXDA25 zWa0i=pr8Cu1}{M94Kb~_%JInzfgGQ<1;X~sozggq2NqARqb-Rk>|^%=AcPJ7F-xe8o7r4o$IhjrjumXmvwVNiz2g*!l_&K{I=% ztqb#{Y)un>zsJ|2urX$s?|b+Cqq5jTH}=o8k?uv_BMGLeDM@60^y#G8J#Ib{@AzrZ ztxfC9BfTtawxw%t<|BN^M@JR4OeCX7jXB;GlP1zmW69Yys!cQla>>X}tLzeXOwrj5 zdtN3&B%{fLaal(3hjvSiUxC=c3hZY($%7dxLcPoI8yQx6{I552#k?rjE22O9o-dKiP_C$|vE=pCR}w*sJyX zIBrK>S2Y2Ws|P+=|E2m5vpYky8@3}hqvv}(KtOiVxnLZ9#DL>W-u4w}vePsk40PZA zdh^g|afc(Je=2Fs5+XvU%<<=jhD#QCJIGuvh>t8FW|c_{AKkE5&sHTJ8buotRTb@* zJWbbKdF$l9Th-HQnw$=X!8jFx0Fl~r+CPpkr@0CBYi#CA5ZbnVm~i)ByL0PS3}o2E zcjt`_l$L~55|JbqOna8|lLST~4I;5d6RC3nllyp<4dmpFl4ar)M465bS}dZKn9&Kuc8uYm6lR;$X3d^I|kIA-QCzcvNbk^ zU62-(yC;4VI-^#}x2;_o3e}qjK8vO8a;v?`rjAb?mHz}HPC&ku!OTF_FIFI1hFOkA zp}6wly2l@pG%OMgr1{zvy=J}-K`%gMhZ9!hH6VffQi(Wm4%}`&Xu#1mS zRHkl729s6)xigySc@PmaE(%yJ9%U4!+-wuXEA&YOE=Yt1U~V!SeM_|TCe;>9rCOaH zP%CPW*>dd0y{D_pj-Vri#YxsLX+`Te@lkk_I9s;6H8tv!7p zHx)nj4E+@$#sS+ew*hKIMNW^Q3tx%|f=au3G_vrT;2{O2KdT9TE_#PKDq%@ug5 z5E&7uVpKYc$G$tbP_(~Kp00a#F2e@a2n_i0FsUKQ1L^0!%oD~dWCLnd9omU&ixawZ znTMgn{?W7Gp9+fE2VSv*+zr*R(W`ceBr>v$FpN<|=Qo}M$pYi@M1<+29)io!+NS|7 z0;g-_^Trta%tcaL`EZ5GaRVM-!n!U&OPLJh3lR0gnRhp@rxJwDVCuRKp)E$>w#K?A z7eICrH-et-L*kkkgq@sS3Gzj`kkhc9A_X6b^rxOOS1mV6vV6|;nHPL_ow`6N67o9X z&TV=7A+}M^Jjf*?63rldxkV~?^Vw;fibn00@<~^gigg2Gl}$&n%qVjvRSDP(>h6B@ z3H=*I0=^yTkgbokk? zfYb0%BTg;qsrOj&)M0dbL->l|OMc^Y5fxeppGox>V81C8xT4$>&$6{)o|TeEk8%;y zN$oFj;;*;AdukX4i3J4xL-i5%C-i;`maHIR<3%E18m{N^b;fZBf@Z>5HH4P0;j_QO zvza02Ol}bqG?#)0G7ZW?s^Km&0M=ZA1Uz?P9n>Oun z*wWB$ncM?XU`|*2So;tSq388ryuc{%9cT}k6y=+}ypoIq&ykQ3+Hy>?U572IkH=c$ z7-u!kOV8qF+>N;+h%Z!o@gc5LM*y5C$K}6`cG__d`VG_gmL`e|+#|~ToX?@Ng?0O3=ni?4 zA2wf;x;>8hGPf3t7t|M&V_FyzCi}}uxmdOUgMB-a^9eHpF7wHe!7=Jdfq~@4ClZE? zJE5C^Mf5;EH_Ww$Y&~o1M4DHZ=vhLc+q56jutn9At$Iw>o?hr3pj&xrE-Z2;+iqGJ zJ$A&gxIe-{qG(s7IJ7d#c)u&P%)9KZcv54@-t`8x%58(Utdb1s^opulkNb4#1LVszDKV!z3JW0Id`$}7 z49=H7{KU8(=^^IA5FMyqyr7B}EV_>hrh@XL$qcJ>AWI~8N2GQORsz_+0(IOsFM8&RGKwgY0F0+<4wZjBP_Cv(tlmGc!`kqWyMOq?Ow&yvzs};IbzTH z$=bhr&3Q!EZ~G2=a49mM`I?l$x(iNVDG(+b`tVGK1&$lzg-YVHEUKz&x}L*hIj%4M z{X<3bE@+uR`F@{IV8}xxvx4 zY(H_*)+ib?D3I0>v@YN8v)G-rr&;b51A53U>QoH=BI4t|>TPm_9Lm+_R* z45KxcU)4|%U$Q|WID!r;k{Nb!AonGAdhOIzeWuajL#?gzWE?m{xM3&4%BIm>I2^k1 zm)sjJRzpZQW6#vGtD{9rw-4+WAvhJ}w;V=VifG}tw{PHL2g*oH?C^=^nDZN;cLfyv zF!cn06__WCvU@|eWh$~zi&Y?G)G2gT48d(M*^wrSbp!GZ7#m_JY2`H&F(ROJSQ(7rZ=2%u9bOWNF>Gt}2I;r*3MvzCg!_j#!HOQe4cO)Lr~Q*uQu}`NM&-@d z$yM7!#`$Szt)7apqD5Dpw6tMqVZ>22TwJYMG&L_eP~iv1ADnd>uICj3r5@erMZfnUpEjk?a&B;J=P#s*+U?W}AT(X<8u1rh z$aQtkHIS$aqfP~;CB)qw$U71k_s5{lweCH?C)@gnoST9K`dfeAyLm59(|TZ4om0X) zyIL8`MJA3h`S6|Z*&^y@jumyNOxYgGpiyfxFAg4Pc4ThEU9>XQTdsaDbNq>ZtUZO# zqesIU6KQ@9qk}-xAh<}gDsu=J=p?1LxD2WIP-MQMFdE!s-k8snyER>jj$gfbgd{WA z0cVjvpJ!3s?JtA-aks-4GRU52fp(QWJm44t))~Axei>)+MD>T?n;Rvmoq+44d)b-% zqx=O9(khl&i#Pgqj9*Z%SC_gd0s*w><5Gp8^_}8%jXebkk}fh8^VG^wZzw}UKGz1H zI+D#B^`XAYAk1#4sjWuALfc_?+-VRQ+6${E@ob1WO%~@Nja|JFp5ApdEEs?<-wlfJ z@$p7ArEHey!-m67d2i}>2Ofv%c#3#?%6n58T2{a%fSzbRNMDkdB@}377~?pMnw5(Q zME3g|7P$7p8M0g$k(rM2mEPGZhp*|V@E3l^K9fd+IF-(keS3U>{(0YXD;Gqz6T{k7 z^@`>ubB>ak)Du|EI*J-@65>2u3=P?78|-L18RGV`y3X2xSwfZ-8Xi?2Rxb$&+u4P-euD#ULf$HS%cIh44Dw;~eMHL}YR6cK*M( zUTG}p$~5uykTqGarAi9hSLxu}#cgzJ=%O zU+@ZV&KQFei{+G3%+6J(!n}(MiTb(goFI z>WWpgugCFnM}XLFp6*vq*uNObq|T+ z9r8H*$l{AJ+J4?WEv|283MEc#!_8m-0eR>rAg_~r%Crim3GRxxz@n@eB4W^Ur>M&! z3+FQy1RN2WDJdoL(14B&iSW--GW{gTuk2Rcbxf&-w{cy#5nC!a^g|h~%t2qM`o(U@ zTFaTKFq_O#JC^EvU{cSk`_PAnj$|z(Smg8s0?$N03b~n*#6_>A6!-6ZnMt)9#a9=* zAZU|m5x@MArO|u?Vf>bDGm2ckAab$pT*1Wru*yEleT=dt`WsDE9cCH#cunG|wi>l| zd}rFFP9xBbthx8tYTCDcrROASlf(ua6Or~Q__I>q^?^nFewInY*W6{A{e@6Nxa+qa z#dE!<`R)={6?PXLk-}XDE*Ob-*k%n~^u-Aebh>_<{<1z5b?j+J*lk@>6xOOgrQZW> z5stLEcf)z-WV)TnsiZOgXBRr>Ct-F=p?ggj2(c6(7E0mIPh{xJ0phY4gk_u*()0g$ zrsQ$K;ngmYd0c##J1sNTmubH-k!XAca10d(-C%5mj+wBQcC zvdEd{WT}4N^mkKYF@NDi`FG{g0}n?^8a%+k)QU9uPr9iD4r*7mYaO5I>+AnMJ6pMK zhPXWFCr%LX1=$w_5mJL<_rA*fE64{e_x{dx>HmEE?BV*vh9ZLlE;=aq0UVxdaWbG} z0TRPy_X0=cheN=%E^F;F1eC9m zrA(XfS-pt7*sjTfhs z%I82{VL7z%drV~$c$UuW=Hgf}jW^12pGY=g-bJ`lWc(EzOxHyPZI>}v#zg^MbKciF+- z#K}0!;7p`UP$n8Vm{8_IP}-zyiggrSuqBc{IwX33i+lIt=WF};p}5+eSMYRdiX@Bh z_2dUKlU~=@lXa1KkkV!Oa=HKy9whXd8YZ z+sV6ciLMZ!>BrM4omp56*%TK@Rfxq;#2|_;-=*JtwR(kqccsYWUngngAs+mwY*Jw*LL4P}9Mt1)7kUF1HIdaN=I z4r~%n=-CgM&w@`7U>_66sfUc-UH{JhZEF%cb`438E_+mwWf)&!r6@Wnxkg=-dZ(+s zaEySx3djRkO(1wA9IeL7KflV4#V`29Sw{^MFZ+c{i0cr;{Xi>)DQf`75nTamj>zMK z-5I=#LHaECg8tw#nO6gnSVY-g3wxPM=VHrKe&%-Pw)EZW_q}$!2=CXe$nRER%!f;@ zPM^#7oi0%GT@?DW+b+{?icudN1ElA<@~%HqB+cibE>w}WB^k8wDexZmtQ=Bs5 zGQK0?WwL><_!hTUng-#jK6X^MjCB;GACOP0_gOyfeM}Aq9vh5xpe^AcTdy!bw&jkeLys>vA|I`ub zuJJB?QEhwr_x?(9&P1vJC5h990iX|MDl5!Nj(<0@@ynmV}D~-g@AiUZ9dNbJv zdkb=I^PEid?Q2$~4N~HP??-PAj%|6sv_W*qrk_lHAGWE^%u`p}`t%tI;=(`F-h?Mp z{?*SR+b*!Gh6NELbb75&L}q%O+0Z3Ewez$Fk81Q(5~$lky?>9$%y=yM&G=vM*PYMW zr1083ZE9-r%q(c?7Yeltn^7Bh-D=f(+o~1bJmp`xh)No>Eqft<<`MOnb)i!p_o=BRY8^z+L$7O{`Zuq@6MxqLglglAW?UF|ZtU;Z_eILj!1C+iAKJDl7J@i>JEiS44^#f0ZI&ENdZcc$UNyBK-YkqrA2nk^_>8|qT)w`!=Ldy=V zha6*s`~88^D4#OMRcBDS%AGlB<>DGP>}%V*;0e*Is&5Mrydh1rjgSP6`qzudzS&o` zab3?h=kq5>h$Dr>adz9OOB=X$F)f>fR>F?a{-Ln_k4JwIH`PX)dhS<{l{5;! zFGqa%9I51lw-$xw9#z};-)Q>ks3^bhYZ^sDN~9GK1&JY~!z83c5b0)+8oC>mP(nat zXr+;M=p0&L0O>9fhMJ)nn)mYg{$BopHES{JKF_`P#6J7%V+UcqGdr3w%T*5Z&*uK7 z{t);B2V2nZ%@T05XkWYh?drn2)T)}8uv>IR=K!aKZ-_28;g*BmK%_v1r=~}lg9Gv8 z3oc}aY^H2ekz;VZThg(SkCKNZs_V6k~i?N8T|)4{0wl#q6y2Rw^dJ@4*w`JS%?0Yse)PS519lzdY(H(k%~ZYLeqt zOMYIU{n~UcY38}pR;Q?&T-o5|pd2M(e~}!_qpdK(D#%U<9mSlzp<5+4eQSmcp_)C} zN$tO4J6Qn@ta1oSCmf?af8ayahxtHmq9IT3?2R*%l5>Igmu;`sipByEM$F}SIdL!A zv*CSd;Q5Bk=_X?T@K6{y_?~6qrmZFKzKf;=Zl`#84E{_IW7;~G2~kO#Dr3cyI&u?A zg!M^P{@w9t%6A^bEGGGL;vAD%6>OeFv)sas$@;s<{E6rv3io(e1f)}}SO~}46&J}& z30LaaKEQ@7fs>d*7FW;pu=#Gbr2AsKWpOiYs3egjIe)2ymoE%*-NkTBfp}1&%sk0A zHg!fq!zXzVr+FjBbT(97hm9!Ap;=UejP~X}UIxs?$Z)GIa<%YTvFoI1d59jTKRa~t z^;ZvKs5ZN}og#6*T6N4zYTEC4nx^SWw%@}m$|PM^wrdCcqp1S6-y3=_C#a^&B+bnk zhui^T0f6+*`c4-1c-t0r z&1cA7!GX1;zqtQj$uoAshM?{&nj9mD%8$RPwTl6y7y{MkvZ6QeBuhO}m-MS7PaoO( z@y785u6ba3{=%bQW>3|}#|KzKD->MlYwxm}e6SnM^eVR1{>M<`j{KJHDSns^d!e(i zuq-mBFs3p$*L}hinU3={W7<&OpImR08j=c=6(>zu572C1*5H`40aWR#VRp}$nufw) zw2;FGGQ#(6{tVn7zyT%#q6?3jPex0Eic2@j@L6y-XO*jQS z8B95HweCbmE1sT7;|+82p?Maz;Kif%L6l6A8Z7=vpSVzu#tqwa3>-RINZC<)1M(Um zq8iRs%hKlMfh4N!2pP1e4sCv_`0|zjk(P1LDB*YdLp@sOFL#*A(3tJ}W7Pw>5>w^4 z`wcoLyWzblzmaF8n(3}s^bRNWH$v#-w5_UQ*stpQa3&6p>&_rh-7b&ukBkY}&jMF6 zOb-Da1a>*+H3-rdylvx^jM!H6Va*FMiW~i58!7PE=V}McN!6ymmh95Df46%#%y7lg z25WTa9x635dogo|zpAg?tJ%nU2w2$lkm(OE*5ZF;WF4i}WptH~ND*hccpo%{jHSgq zw;#7PT790p87+-9y*$UEK{_G-*2MqO)q|FnQqAKkt&+(TQqJ8=p*q!OK@kj6VSDnj|pdx=X489a`Vy=m0;q*@z7wGQlnkAJ50w{J7a(Xi*a7G)C z`pW!?fh9`hLk>Q)z=8>R>Ric!pBJ}e45zF|(t`}c=Oj2JA=Ne_<2-Vsq(1s}LHp6p z5~H*SAFxeHlUDhg?{YBR#}2d`G*$SBIfuJtM2N~8@M0Hkv$(~5YKQlh`B>uU7M5Po zKAVaoc;_&gs$y`8m2duKpiJ(Q3Lyi4b1~Hg>@A!3nKr!PK+yH^-K~hi*^S~BU9J0^P;KX!od5|q!Z`QR>V_1 zrffjs*%`yGp`k(5wDk~@7+Yqt?Q5FLC_YSpVymnsh%rAbGWuXcUSsl(-js#=6!%a_ zD_j0U5_FEX44FCSyK!H~Vi44`k+w=?aBMRD~dmZeiOvb}PdZpE^_L>JJoo}48 z=02>s>3u8+6k+xcBv5a!aE_z1)Lle%^Ps#Pnfo-IrT4||pR83xi4tnft1zA%TQQFj zqe^axo0UAXVM5TgU0ibH?p#QttOd!c@w&{6RkEb0F<+gVeVT9XNo}s$4k?UcXqZy? zuuo8)ebLn4YVUJDuC@~2-Ln~J5nh>U+~~aY(|(D3G$JS6canbNRB*d;eJPt{b#ZCr zebUF9Ht&r<)T#PS(4=2ek+s7nFRk;JRj)A_3d7_YYvwXuf`68;N8jStogR_oawLa@xUC%`*s^t2}qPxtPe1~l=u4&4`2x}vc z`D*N*W?2p-`r9;$Ed;>v{A*fXGa-y8jSw^W3o{;G|AI3jcO}JF7#BXRFU7hojM83Q z8a15hr_n9iV{K5*&0hi7nHLLFCJ$;b0f)LD>9~8T8p%FHgPR=5Nyo%aTer<}ND| zs8;B^_4Vj<>j>D^o)vst_)!S@;u`edrJilpZ)Ry7n0dL-NC;kvMJDx=y0F@S33SX$ z2I$wyl&J^rI0@Xuw;za{ZK%)845*Wc^!d|6rF`f*EugSel?oBEO!YA@p_N885hovC zny&?EpOt?mE|2v!8Y^Dak3RHEERj>npE;!moY=V3vLK*+9M=elSB9>^EEZGL9$b1X zFeA_5)V+*w!QudtfMANlj~kNJ+6Q8k!*_gGL_P&DI?+Vwwg&Fp zn6n!ur52K*z@>9Ioga+5PMC!`pJJ*BA+9T`G6QY6co(&=x2&1J(WCO0u|kQL3=4bk z=T0I8#C2k~nO+7_Rz9Xt9cWUc69La^5|#7~$FRW4S+p^W)I{DJ^-;|k%dgUkd^nO@ zRC^HZN&)qf&G(mKS;U)FCr%5QG)9X7wtYS-e{R}hyvPO%K0h~#tBI03b=981nP*(< zJq9M~9f2Dp7*6rWA*iAJ4l4=UyaLJUp)0iXuI8`c$i4@2;g7lfq9{FIaXV1>cqP{t zU*3Dp{C(?FZKyzw^SCH(0voP3N0(p+$>=U0Q7F7C8SL~icw;C2wcy)VXcFqNH(=ih zXMHw`S)ALc4PE;l;ei8|h;S2Wl*JR?`KKE>V~ker?*5NuG?fzH@2#~ zHV1X`30~WBp>`)dy*GNwWqhNJb5J>T$Fjq@I3NP}1d^JSWIKr!xJAucZVDb;%AL2? zP<;b+k8JUuljftUjasJoe4dyjS@0bz35CHfe<3`gMl4a#<{lzT=y+5{}#?0c77t?{vuezej9X@48HcVPfkZssz z{cB>+xKsBb7%-dmtc5a08##Hc9aV#10~oca@AWZl~(Z_Ma8fh7U@7 zod?*MqPMk|KvD(RY~KuDSb2i~V0O!5Rjx+&NucOX@?|K_()2wpbjLKP-utRgdpwR? zf2+Yae-E5(1+)HCNfwU@Geeh%weP9IR%9Qa2LFc`W?DA?o+D@w&lP4TIV_dKb{55Z zyx(&&Z7LTO!p*m4=`XH*ljB~SBV;}a>dNUsRD>}uT_Tt{6?$l{^Lvx?`ysz{w)2Q|WSuUYq%yGl)V>kR0Ysjfd zsrm5m%=L4FtbRgV9X(o7rs-3u98=Na`-k)KXE_*{j{R1V59bWA*+l3F9f(}E>)VbwY+J+)a| zpPm4)lrfb4q0V-E#@Pn|Vtu>HidDIvnV8J03{O_}8*#RU`d-QhxsPPzWP1g2yk=^x|^2|kvvebPwLv*FIoRS-)<>`6B%Mp7MF zgYs)1kk|Ie4Z;njrD7wDPy) zC-O{7v_EzgTl;E-LxF1z#K*m!K9%7~8x%+}9LuZX&;8DW<#_g5AW;%rC5hvI@!kM` zTf<^=tE(C2agWReoDorj1ZD2z%lxF#9ik1G#CIdXu*P;Fw%kP%q^0x4eeUBv7uCOo zU$w-UC&CCXxQaw#Qo?K+R)PpQ1ndg5pdv9lDUggPwzwp>--PMk%k_ScKJ0=j^wSsx z8Iyp_{M^0y<|T>W-ArN6PA+2KI(-;oKr-U37thzQ$tMeF_}*PIX(6ZNQ>6jPQ`ROz zNa5W_gFX9LL4wLpe3JKPhS9E_?z3%ZScj}$#^pq z+#QfdVyp!Epv}ONG;oLRUW8xg=BCkb0x4-GB}D68Mr%<-M$q+sf0D!YaTR^iZd-VJ zOIw3AUNcu6U)Pvl-VF2vdhpFMgRs9;E?P>7l=e>(Po^-e&5!NI2*Ex9cl{wprk;fz z?)jwy(ExvOoAJ^OBq34_9=V|j4@p`HxXanxS(|a7A^KhY{aP2ww7h%ujyG$9>9^UL zxy_gMt^DxfZSx$k8SiVbbsH1j=(I`St;Qq~Yf2I8e#^h@5l2m>1)D>B*pt2Lo3l#6 zZ(50{v4_^!Z%;J?Z_c={9aiCsFiA9>YjAqfwNnS})e5h}GzF+zjDqX=Ljl1}6s?rGTo_BZWg%;t2 z-UIx$m>-*x`Yr!#CMtsu$m*|)tQ*`(nl7xQsrP?ZG=3Z4QFj>(o$wufr>7^t1-LTE zSN0fWv_wz7BMsw_#?@JD6vPPZS%9hqhl~r`xM+nFfn>__61uwDCw>x~J`b-!riq_8 zh#{3WV3+gL!OeL00g?IHF9I(XV&!Mc(21D8@Y)unW#)8GLB`bnq0_~+aIwep1o02F zHvUK_p3Z*h*kmj7$-1;~^JwAXbFU_0raZ-M5sTSr=d9Pn>36-L8Bec{Ge4NCYBaAM zd-thcY4l*+WWX$pwG&gFGARbqHO`biTR~T4vg#I!?Vq=M8tQzuu=i$*1bwFOFxjvB zdSy3^GI8-N^uarW>a8)aj^R9)rTA3@RaxKMB`7sa57VmM9V?gEtAXl;rmAbTl^>1B z5*JxuR|C!>-{^jkjMIIn@=NVr=R*Fm>T_|!^8HfSeTpjw06*(iFe%%DXY(m5gR$3LJa90$($ww1qIv5( z5#oPc{1)a%yRdGpP`|-xyiSJ?Va!X#OmG8W9-FcTQJU?6rgIr|-7k0JwLQE)VZ7}2 zz3mcn@K{C`&>lvrm}FDyi6Cz^V%wJ1aZcVqjRjJ;Wvp2DS2xPj*?-2T0vvUCtP4wU zyjdfCp|5)aACE7v_#U5&JfPj(uA?rSu!m%S6#E@qC$_48$K>SJsC4XxM(rt&x5OQ-ZRJNIh4=dFJi+lQ$$@YM3c>ZjOvX16#rnhoO1HV)Z~LCTe#~ zHL!4QJf-iBAVWYilXsE*v;baJ2P!wbRd~S%WvX%HUyUyf58~m~f`|}(KhD6niQay2 z5(VG9&^(54?<^`M>TIf3ux=*4*)s4}(4*;)dUn-0lL{(n+e_@1aEGeNP%RDFgr`4{ z&=d!SD|}g?IFnQ)P4cA%zDkflvb2w}M%+3FH{&1%-dR4E_~ZHjk&T;^&HVdD=Cg*9 zWJygEo@T=KipvN9Z*{L0#U0g7&b&1nGgY)As9b*bEGlb8^Duw+37*V* z<(uOjy`Dm`u@NWwMu`M&YY#xNi4W8jrzOv}+knI!A%MIhS*5?3m**2X#kpYS@aW*0Z~#err8Mu{!a>>%+z&X=L0zwc)f@r89a^QLTBqblcnOq0YJ#c zJ-%%}C}*`|#JK!WJ9au~YR#4YI5S{LwOxK~!~J?$=oFUZ1Pf!aa%Ql}ewovnad~Dv zcTnQFgK-Q@0k7!K^mOmP?s%TW-lL`%bU~Yueu%7Q7j55MYYD?o+NAf_2Rh|Aa9T4cpsm#QI6o3MC7xX8asYvrH=E%zAI0w+}Vn{h#8!uhqw2R zH;*rocu1T5LMpc8RoR8qFMTTM;8y~TdHnM@N#KMgugVjf*7ChZp0gcS5Gx3H5?&I| zzh&c$jVdz;uu&_wN0lS@Msg)LWNZXH^TL3F9$EoK1Bb0QZ($$QQNXdE%H(`4fWA+@ z!?aCntuh&W7E%&khT<7H6k_i=hRVmYN90Nc9sA9yIrvDg>d*XgqmHj~Tl~oIt50lt z`=B&14M48s6TODPwG|Qh&0ZMX`})SD@C{|vp!C9vBA$f4W$0Jzy(v?q(UO5+YuZK~z*`JqX~R*I%5yMs4&7Ii;u@eKz<4 z`q3X=m7b-sHJkv+rlOMB#v9Jl2(+0Nbx7jo7r_2gTpWbNmN}YN4X&Fne0^y{iDTMP z&g|9NA$Ph#m{&dSJKv`K6BeE?H^z|KMfOKprA90NhS%-*-w@t<({CvbwybsM=cM5< zTta|tuhPr>tcqox$B9+j+ig^c%Zt;!Ib2hs0j&1p+HfA=JAX!d0~pfdE5`}RJD=e| z4%SU2RQM{9ZI(_C(~OMR<1*Pn-xs=L6!7RIg7*W-*Bqa)*l z@O^T90w)zNyH-_yeCzWs+w1F_V_S~=#w=8CGqHvt>o)+Hj*X3m>;aw0anIYUQk3LY z!ya71nFE}DP%)!+wXtS~B9M>%Hl212jE56j?-#6%8E z8y8^6ubqa~7c^##orJy$M`v+-t|F~+t>B}WN@Z;S_yhS?`yB42825TF9G8UIr z)U%1f3;0&yw)UD*cK_8C-W+gwIv?K$UEA3BpBGpovWuu1#INMrVfsijo)L5op=e>@ zmhe;@$T>cY*{)?Lgyo3&H1S~H8Iy?&F)SzUqYH7*x=Z*m9cqzKS9TdvLwd6$_D;XI zQ+mv1V*OKW6Ec}ne8eSLVs?+yavXrLbH!JH&=usR_e{?nia`g`qqa^3F;*o=Ln$R{ zT?S{y(xN%VBuhp8-VC7@6O#Dtd~j{<6q?Vp|WUUl=hP~ zdqsTt&eR*S@a*Rv`-WL!eTl6N?Dcpe;0B(ucWoBr zY@fvU_xAsV?Id<_ee%Vh;LF@SYS-X%|@=s=(R>!+0rmm(sI+Ojmw{rz# z08mwe&1dy49*{Twi1w!Y{6a<}ZE46^7(Q5-L!F3V+~!`W3h#}z1n}6i1sW97JYS`z zmK98cL|k$vm^!giv3+3vS_XbVu%yQD1EnplgQ_Egh}r=EhalL*&js!kgR=B|4m5`7 zsT0mcokV~u>-5n6ax04m8>gFS?8CF=hn7AbN^EN9jFD-*GDMH;ZZ&Obfwz;YlJ_fX zQn3Bi7-?!(vcQzy7``H*v^i5X=nj15@oz?rJWs)FujZ7m`P)0ib^VUQ0#;HZgj7u9 zt=jA4g4}g1jPXHKZ`ghN8;iT{bMi8vHuQtLNi%a496&vptN*IDbX8-@lRMzK0HCr6 zsBc}-PHqx`@=Nwg!R?-j_fr*;YvhGNBEe}v&w`fWkry8P&L8!iN>p1ot#J?7G3Bm= ze>Ad|AB;7P`riAzp}HtLxWzrif8kL&S8s6k22v{}cS|z~zj70UU9BzYih5M*!@l7> zO6RE@2}mDtZB+89hygj~dEAxxJ@!j~nUje$YKr;Y138b;r`8McxK#U z%+`@X6Wo%>Y{9(4+7di=uDaA4o^KpyM@qVj$8?Q9C*{gd$nEz1t*XSf7(Q!lj`<1< zM;$sNFdb}199UZlAT7mSr{#t~QMY*$J{<}(6kHGFkqJo(ondvZCAA=MlcpKn422Y9^vt1@jA>~d#Tm0Ha&uT4|U8TNqBsJXT_|VVB!wBPy=p}p&ch9m? zNJR0y@t?!t89d6&bO5nI)&iYvmy*=y^O@;1rIOZv+`nJE8sjpxUJx9i5qs)jDNB}U z+P}fKl05fmc$&SPrJ6jKlQ_<~v5Ixjqe_=yMdlO#PBwUkE z+|DwfK)C_nZFRA@lB3f++4j%_dG+-vb8~Zvam^9G6^P+T3t8xh$T}XY zD&)*eH7iT+iH}z?2KO_jnwYY~a$T+U+NDxL&}EzD+4&#t3y+F9q6VNdByv7P5_3+T z+6p6d^&DY|3-rTCE=c40Zhe3)S`oC#<{s`XSR9&PjI0(;c+9;AwFEg;-?tQz{T9+4 zyYN{J0nR!+e{oxb_z>kXNs-K7Fg&)l$W3nl?!jCla(e^OQ}>a2_35oA;ROM}x`+WK zc^1zZ=d03r$7hE4mpO27v4aR)W7S-nYwVZK=HNYZ^b_n7<2>^Hf||@;r^s7K@BU`i z4>sX}#5I*C^*X6TOn7L*z;;#H7?-uDY)7)&cu-M)8baFU+G;1$NiutjpGq$4Y_NSW z5TaRj!1Mk|V~4@$#XF6C_2qySUN{^rweUi9w@M);ZAqz?Ipl2;==it(n{32=K&WFZ zQ*oJg^mOOB`0Hl68fwJXyo9`J0}tiLLnWh&Tdle=Ku#uN#N_hi?c6!mb1z5GKjMm1 z1=nG7(;L3^9gb?dvB};y1le!*?RzkPZ@v|8sl1-j zfs94z)Uo|ut$kAGzaXS_?crUEPVnF*!CuTJ}&X=BAs^;s|G-u2J` z&LB<1v}1D`u)FcIp7UwaTMh9bB5MAMr_Q;;kwtUC5$z&+XOkX&=iGfHWIms%0qe6n zju)79%gYhv3(@Ot);zCG2yx5M4?&cgSCM_5x{FK)ZF`k}zaF+|D;Z~%4rU3Rnlr5n zOVr=5W2JwWun{a8%ADl&TZu$E|0Em(WLNo zl6sgeQv7w_g6Yfr{Hlp~KYOq-3A7$&h5cP|>U~|jBH5q$ zy665()-AuD1rJi=H~uq}=xXvbU;Z+cHXQ;6McoyR;FuTtGa7`|X3#&CC##Yp>lp5R z`$P9y&GB_jP{^k!2Sm`Oy|k?|Ox3hYza;w4@G!u_*a12lT&uM7fiQ-E+hWtiyrheK zAp=?cQ-0b;DC=0=S#b$7R}y9>bw?o?&rWdRuC1M$gZ0zb%xhS=N!nmUgmq~9k*(hM z%DQ4?bSehfndlcD+qHRSx;BI56Wd0J=ik%&+=?YHedaA8&}JW#l;iIDp=RCxmcc=# zC~zB$2_R(-zH;YRmx#p`C6qmEb8>QWTLenJ?2>fn4_cLr0GodYxd!LA{QH$48vi0{ z@{&GJj?>IUiv$t4bB@$d&}#X~1IM(hw^=GwQzUbV4LQ6oRCQqAa-<&6#-#?_ z0mUiP-mzzh$FhiWIMy`eM*WN!3gcBtv zx(@UGmd(;4aJ%P-CK1JTP)UYwoq1eG%{H*y(|7b8`TdUFjq%$fyD_I3=Pu{g>-Wpv z4RX}g)va!9Xzhx}9!(C886KdQgg6KKZ2e#+jjYj(Nj3Cdbck<0^ibXl64VH02kt(W zLTF$f(pqh*5Sg{FqZ;yk5{ZL!4U~9lJhkXDiXqKy5yl_>awf482{#U!#5&MdS`6Fz zK!%gMgdsczaT6!mK?fthRvkZKL?_?BJ9L3rpIU^lOyeh1xIWD^o41xeZST*lp*fP* zzu)~gL&#mjBF?8SYqgm7vkg^{w-HwOL$*`t=sncI)VV(wkj?v&1}evA0E_thk-->H ze6Pp>H;Dkz1Nv4id$@*k)k^i*x$y$a!i~PdTYy86##nPO%%qB}#^1A&`Ifk4#g_LB zGC9{whAOxaP^R#hetaFm3b8?HbUX=N@XAPKY~=Evxrfnu5x5ImaB5unX4-E zkTunfM^)NxV0|FgSRSmN`y6EDOK+P`=&R>^9^!#42>@&V969=ypbV8sHX_JUp{PIE zQAG#Zj>@|*lv~S|`5~)kUW0hn;!^bA`i+0RaP_Dh& zoYU_>t)J&I`FRj+Q#`Ma(yC7m2ELU;-}5*$QdJ_QKF!-hvY7h&JdsSqF&l+r*ksQx z@?nZmgqd#hn!F8paa-(@$wrj?{tqhWjpAxy;E_Na15g99{ujvueX0hXe$Mg{dWw9{ zhKW40(xt{~ed?I;0#hA(^7OzM?QZ?+ zi39N-V;vjfjCXCb%86&ndcT3b7>Q~M4liY|L-zK{94)+OaYEwzEfBJM*$BEuC4c6M zlm3LY2-&xQbpNqjU9kvR$QGTL9ZV;yEW%2v<{nsEmV2}Uu8(W+9!D2Z2^^enS z=fj_uI-RM6r*}9jMYi>Ar?0<6U)yq+C6=Kw97esQXnDGzU@P+T@e?0J_U+r>6&18* zmhZ*LojhnhTNbQc|5>P8@4>&+6=S_QQLfEPUo66)%;qUoasId8V(cy3HJQf_Oc~_Z z4CFYZ>rY8Fj0D#^=kR>Wz3ZMTDaw3-xg8;YQWz`(;jDUDM9(@<%f5Mgx_L7A9Zt?9 z^1ALO`mXvt)Nbm7@o_X{a*Haaj9giu`q^~n|k z6o0@>Ay*~kXd3FoZ0_;xLzs>B#Z3_-&(F8lomna!_UN+3jlGB(=bGO_7!T#yoQ+_u zmdzRJ4Z(%}m_5jbLl*fThq%U+KcYDGrGBDaA@m8TSRl7V%Z=ZAleuF0v{Wd^KSfAS zD|->i#{IXxcVK2ss@LC$RKMMB8QhGko2Ta$II?w0hI*l|p8g|tTe?SXf?i$k@&92YKfM+K4s z-ZRptKX%yonGG{o8tWDN^AcWw6~|X>*N)*2S}KfjSklR~9?%F6@Ht&Z#@QxytQXIF zvyArfXOYIsFI6d-6zHMl81Fsav^=bvic&5**;>&-TM^jSDr|cC(KKgq5dhGsJxYA; zH>LC@a?W?F50L2l{|~ggqUbQ#_#cGq({SS%k!@a=nJwzMhY|vEiQV~|$#Tp`+{fm( zjXO;dH!lf}G*sOsz64)ypc{GKMH0n>@@=FTR6ivdUL>q^E&4a3=>0IP=SGmc;_*`< zRzvnexiRkxg#q>=mB*wN!^KWaAjDxx z6xgQgA$ao|Cq?Sij3nZZtDpGDL+HWinYMRa{$kKHGb-*B*Vy0|@7K(av8xd&H_L7y z!aP{I{}v%2z1*U^w`D!|&$Or$53WJ!%ER>Y-gI~yM(=!UwSQR2JM`8b%J9UY_fcAJ zS{ub5%tcEe@tAnAf}kh$ij-q1Ve;G@V9iz+FvDts8xN;GW2)!VAC@-66=>xRjgNx~ zIYY)PK=Z`GO&juLRePZsiABmMzpczYk#l+g{UoH`kET2}Zkp3Yq=({qfo6VOOn{^u{hJHI8k&GgtfYCd&RzZV| zsF1I2F&pOtqBXriG3E+Sq&s+3om`2aJv#kwkk6@_(uA)R@=kDhsTmgBQ!ynz`Q z!UsE81Ex3a?PXl10xobet-3@opjv=M{jVTT)7mRf@82#=duOnqIVp!_}}{Ozih)xB!^JH9U!l<|FT zNH2b%od8^r<7L6X?mG7k5VlzWw*<^q`}tE(k-$XA@T?a6`vE0tf3i*JiLtcTwfI*X z8}M;a!o6gN(09@I&IuI;1@-Mp6=saWUtf88x4`^wXqg`U} zeGqaCSZ{~vytiGiu=xEJY0YU}>05`X^}izA@ewnYLY0jC#b-wMIJ5B@iH*R4YCy|w zEvC$$af2>|Ru$hQU>c|u8}H1Lta}VB+Q5q{o^jU z=;Sa&RW+|cAkM$Cd+UNB-tqyZw0U%WaeQPddS;q3W&kK6^27bRZgAbdStb(r3ppQD zOPz@0Q4P!aRqM%ytN$L-t+Gv(T+hEo-@laY$9)g#OtMt8b;kD{Ia*}F)vdy#JUhxeY^RTi=I%@5v5l@PeW zckhI!OBS9)_N{-u|8L2&0rR*5g|zQZkQl=1HyeYLtlh#-!2&Vqkq?9ek9$oftP+hT zfG@8(UP(#%UuhK&&?7AGh~v>_84uMseSuYPB!{du&Qru=&Y%8ej$kbzhNCvw@tVkF zK3+%N7%|q0ILTVUxI|BkQ>SC)C=uvW2cfZLLsb}|L!+1!w*0e?U8OMe!xXo&N-K;6 zYdymDdBfrX&h`JGLsx<59Qp&p=ruQiKk4&&!q1ax$jCxW9Sp51KVRj|Ad^v?0p|`+ zHA(oRpPWX{>p@`7+=-rSo8Kh5H&XMnOHA(U&(@541|upNBh2kQ5`|2GWU15>I&yYy zMM;gBjrEyC>4~43s6K;ARa)A-$IQ-z$L>8a@ePf2Pp-FX#?Z|g9?Um|N*ZgHm{sMP zE2PP-j@Xo0q-E+TdLMhg>2&j8d4+alUK2ywHOufj4qOyP>NorK?U?T^TDs_gfdynD z%UCoLXmbXo1v@~ZCL@GKym_E%3;xJHWEQ-!uggN%a5@Q(`36dn)~)7pAR1M#FwFQ* zt~xD5{z4^3wGJR?&6$OllY&{kwkSZ2DEP*~01Q zZ>f^Py?Tik-k6QN+Uf8~*Zu&iT%lT(i{D5)y%DSVU_INh7ki2Wv%=#;6MJ=|HC^Uv zY4eJ^7tdM0H@lg?;Z1l!ojAIi?z7GlEqkb|E`RO@=Jg>zT&KMaILA4!m3@;wllPgU z68)1`#6{y#6f5>icV0MP3LUbuAz9aDN1GdImReB7_3sP;~VMY)gM zt1~N9%w5PG3$$OI%Uh{lL_e(zIBWm}AK8b5g66+`5+fY7N7HGIkc>#H5$K8N$y9Y} z@OV>A?YO9Kf7<6Y7TAbnb-Bw!c;!~r@Q?@mQG6rTkNJpa#b?%L-1fFtnr@6F)h>Bz z)Pz%c)OQ>XH}JWzNC)Av{1ViN`XcV9|L#e62>3ZrM4woep@0@I;9I@0gOPvTo>l1HIpk`h4?ajvAD&DME9cI6FF!FGEZ%*BP zfPiWkelqs37jwJZg`7o}>Z!aV67@kzsH|n4XT49iT=@r*rH~pQ>y9-;@w3O;vw&{QRFpIVguz&48;YJ;g-BMtjUAgVI_W!~}0`o3E7 z{z`a{Jx`*c%k`_qX#kItg0ZduwDp@G*Y=2|-j#`YU9fMD*ci-g4X&H^a%Z+E_|teQ z5oLp%RM*9+G|Vyh)TsKhZ|_onXaOWggFJ?g#2n_cX~9(|(src`@v{>J5&u!Sw>2W| zBsZ%>a$>Vqw|7tKFU54vH=Q@z8}r)GPF{y$7&=$^uqeayS6hB|9*~=2x_Jhi1Bu&c z!5QUWJclRmE=y1A2Uq;^ag(1!h69e0?M*U#F^=t(19F~29@I{*6*cp|nh6XSs$!?E zi~;kQC56B+u36K0=h%!w=cw=2G6M!ie7D$%rKBFqgOa->=oG*5tN3ux$Cae2&^`ZL zf#+ICfU1JI67)TSz9vd|8t(>a)*^|1jgZttzIP+_zEctmLIYzNx$(R0Ac|KaEI8Pj zGi25WacyQ?f(g6#LHf;i=cvN%e1D1WOhv|r4P-Ix?ys{3WJ_DS`sAvfs2uG*N_N3C zYMc*f$9<4zJ}7yVhgUn0jWh8rOY-`Ls1uMeie0{9ac9l zgS3pe!YWyb^Nr#_2G6a}F(MEVH$?NMK~iI=Z@=sayDVGLpcv5m?2&?$fKvHdtU3JoSe_7{)c0ZD+LF>|`@gB-W zjCVVwwGP*3NwBq@pMAXSq`)$JJCwyN1(eR%g*Rd!?Ml7gGIZNoy4B=SXBWxr-pF2L zXpnyDijYr)h1rhG-&I~|qGC?DJNC*s@_X|>2ex6apA?WHkhednMxSEqV=~S+t*=PV zL6gG#SFQR$I3SipIp;Oq=Z;g}gdQo|Bv{J%@|eI(=TiyYuoIJ+l;kSPJOMTsUph`^&}gOq1`HW3im-%Pm)FGWO{fg(n-bCE_QKCK!z4 zn0R$)HY#|Oi(F|ozFMXQL?$z)QYuOZZn;faSH0=4&0mucjb$K;lAlWlEKU?R<*%g6 zF);L2B+;?yc*R$=;m-#z&^ax!o}Xnr)$0d1g8;U$t1#qxy5?3F*d2Fo>%pzhRA$1_ z(cH{cqMc4Y(+6x3K;5D@g5z7Xg`l)21!1B|!1005SH^k(0RP95s&2$MTmd1L2t9z7 zKcFK6z#hlfmpKm-UV0|>E?)u$v_jER!r+Zi=c{Rk)PHaMG2z_`xgk(S8b}G!G5TagX2+w_NR-B3p@XLDoC#f-4R$$xRS~zABwsZ zNE>M#yZ67?`{@9KVKzRU8n4z-OJOF3~FTi@1UG%OmJU7?w zo4Xh{FF$$!_3@3v?bBa<%Vd6je0wnC6Ad$(4y&MDz=%QsErdqIs|O7^iyswN0dXO%8- z5;z^*D*MSP&=_~Qf4c`3es#Dt0#AnhR-du|y=o_$s<62t^53~em-<;W0u4^n^67Z7 z0q*Uc0b~(|N%lX9j&HPG*QCfI&3s z0(s^?{`a7T5q3nZs0ThI*8C?A0omtDTVXT$>5uKY(6{D9W5ott*YBqyuR559a#XH* z)xgwgtycnZkR;VBO7&)=2WIMX&<=cXPna;T_DU8d{CV!E;vchx2X7aF8#j>hJ=`>D zHw;VEYx0v+WN{|C;?fqM6E7W8MUxo$mV?4U2C|eMSW+N`G?$zKOcb&hu!wlXok9Kwb)9S_w%; zTrERuZra;&!g>3PNyyj$2#?5AOh)G0op;1)`)pRW!1 zPg2Fk+gZaoZ0egGkLs@)z6A!dkB=_T(DIiJfabP2yG@4gIqS}#$m&i9PJ_@D_v}94 zlvWsK6MLnHp}h+e1&mIx;8t9NToFN;ykGSrurXF0z1g93V#e*_P~r$%@^TH?LYOV<-yIElD7!i zqp4glOq#xuh~e_Ul##F+H&Hf5PIB0sogMGJWdr#B=}^$YDtNBHU!GB#r8rbAf*R^HIviyssD-S^xAb^tFw|O-F)D4>o>kiGpI}Y z`5kUfCR!*=g;~utc&B==B&E8K>B)fO4l?TOk5S z9zY)I>apuRlKx^}3OQ|5`W*yJ;+ikd2?I{2=hJ0J?(5gN@m%pa!Dm}~;O|<)XdbQH zn?z5zNY$TbzM<$BG-~oYwhp=T+mxn_zCg`keDyzF7*RE8lGTH;EbGE%gB{RC@b7yY zfKvCPWS^Al{sWu81cU}G!GQxDcFZb3=hS_+P9xYM@dLcnMz}S=P95ivG!R||5(eKjHpbiE=?H-iCP^)kf zIbcO3^6CBh=L!$(23nfgPN4e)Y)v-L)T75>WRzRbau_(q_kq+;zH2ZW#5ai@ z$Pj=~n;#E!;S;M>WwuZELSNRx_s}ib%NbY0~y#3b&BSBN2ltjSQ2)W}G0PHbo zsX;ZC7o}rsqxw|BQ@_5R{yorg13xxDJtj&0A;GR&TFj3gnlY^p2h$g5uOq-KnJ?Dn zJqI3C@)3Qk=AKLp=t)q913|6WwoJsU6z`4T%bG@>w! zsoUo$`vttk6$p2k2qyLx0@TaYAC$E!%s>a<(wqR=tzQ|DCB!H+^uX0M{qjCp0+X-x#4F6frpt z0*tNU(NXuuQfUE3fSX2Zl&!q^P7=)O4y8yeHEF(x*%&LX$KRVw3%OpWGUB5Cp;~iK zD8u)Emnlvn?KTMVzK#&M)r-x}y@vB`@hrSBHR6s>8XX<2RQ&Pk$PJhi_AfU=@O)`w z-+|e{iP+xd-FUDofyULa**D-1oGAgO8$R%Jc6_F>Hdyk1l1#Bg8~^ZFN!Zn>Gy(?* zHiAZx6Ts_?`N=iA%4N*oO;dLSBgMNy702i+K9gshr}|!vsBgucyX3s~&ei6ftqC|k z2?QbK^uvT60+edvb$F08%hxc)z65f0a2uZMKg}aueRZQBvqVQo+x_vqJJ1#P8Q9~t z0&m#0cBX30?WFkFFW|E_ZzUiuHl|a*NqaG+UKwxq<|dIw!pj^*@V+?{UM|mr2Z%Xt zYQ8OES4$oU23A15SQ9Bzj9qeI-(Zgc^rdz2nMG5SN!z& zM$DJ`m{~3-0102+>*WWJspywx!p8IS#GLmaEj|(YalD=sMd2f8A&9a?m5+*u({mZW z8<)nzlmGog4$ouuYzcJJoYaAni==o^DeiIxO-IdnO_p+g23arsd#mlq|93rln(aeL zq4E}IGo1kvy4B5y=|^usA8lA(cN=oSFu2aG&dC(EMOr_4qq9v!iw^#uhaVZF#IJkE zLNtN=f2&D0e`O;!5qKc4RZdMy%;Kk@M6Kj}C695JC?DIQ#joGhW=*IEo>g@_YLE-dzv6#z$B7Rb0^lRV zGB}RT?0r2e24o0Uf{u z29p>dMJ7skB7Z>IV!!;OXk;vd$@? F2>=KAj|u<) literal 0 HcmV?d00001 diff --git a/assets/images/teoncreative_logo_white.png b/assets/images/teoncreative_logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..00e6d34f46d8b45bae5384b23adbbab645c3d557 GIT binary patch literal 80645 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 z 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 DUK2j_ literal 0 HcmV?d00001 diff --git a/src/GameCanvas.cpp b/src/GameCanvas.cpp deleted file mode 100644 index 9844ee4..0000000 --- a/src/GameCanvas.cpp +++ /dev/null @@ -1,304 +0,0 @@ -#include "GameCanvas.h" - -GameCanvas::GameCanvas(gApp* root, Ref connection, Ref thread) : gBaseCanvas(root), connection(connection), thread(thread) { - this->root = root; -} - -GameCanvas::~GameCanvas() { -} - -void GameCanvas::setup() { - if (!connection->IsLocal()) { - player_color = kPieceColorBlack; - flip_board = true; - } else { - player_color = kPieceColorWhite; - flip_board = false; - } - board_textures[0].loadImage("boards/board_persp_01.png"); - board_textures[0].setFiltering(2, 2); - board_textures[1].loadImage("boards/board_persp_01_flipped.png"); - board_textures[1].setFiltering(2, 2); - - board_width = board_textures[0].getWidth() * RenderUtil::kPixelScale; - board_height = board_textures[0].getHeight() * RenderUtil::kPixelScale; - board_pos_x = (getWidth() - board_width) / 2; - board_pos_y = (getHeight() - board_height) / 2; - white_pieces.loadImage("pieces/WhitePieces-Sheet.png"); - white_pieces.setFiltering(2, 2); - black_pieces.loadImage("pieces/BlackPieces-Sheet.png"); - black_pieces.setFiltering(2, 2); - outliner.loadImage("outliner.png"); - outliner.setFiltering(2, 2); - show_moves = false; - hover_piece_x = -1; - hover_piece_y = -1; - font.loadFont("PixeloidMono.ttf", 12, false); - animate = false; - piece_offset = white_pieces.getHeight() - 11; - input_lock = true; - game_time = 0.0; - fell_anim_dist = 1.0f; - wait_turn = false; - appmanager->setTargetFramerate(120); - chess_board = new ChessBoard(*connection->GetBoardData()); - connection->SetOnMove([this](int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) { - Move(x, y, to_x, to_y); - }); - connection->SetOnTurnChange([this](PieceColor color) { - if (color == player_color) { - wait_turn = false; - SetInfoText("Your turn!"); - } else { - wait_turn = true; - SetInfoText("Opponent's turn!"); - } - }); - connection->SetOnStartGame([this]() { - input_lock = false; - }); - connection->Ready(); -} - - -void GameCanvas::update() { - if (has_next_text) { - info_text = next_info_text; - info_pos_x = getWidth() / 2; - info_pos_y = board_pos_y + board_height + 50; - has_next_text = false; - } - if (!connection->IsOpen()) { - // todo disconnect screen - return; - } - game_time += appmanager->getElapsedTime(); - fell_anim_dist = Lerp(fell_anim_dist, 0.0f, 0.02f); - if (fell_anim_dist < 0.005f) { - input_lock = false; - } -} - -void GameCanvas::draw() { - clearColor(0x6f, 0x75, 0x83); - DrawBoard(); - if (!info_text.empty()) { - RenderUtil::DrawFont(info_text, info_pos_x, info_pos_y, {1.0f, 1.0f, 1.0f}, true); - } - /*for (int x = 0; x < 8; ++x) { - for (int y = 0; y < 8; ++y) { - RenderUtil::DrawFont(gToStr(x) + " " + gToStr(y), - board_pos_x + (7 + x * 16) * RenderUtil::kPixelScale, - board_pos_y + (10 + y * 12) * RenderUtil::kPixelScale, {1.0f, 0, 0}); - } - }*/ -} - -void GameCanvas::HighlightPosition(int board_x, int board_y, const gColor& color) { - int render_offset_x = (7 + board_x * 16) * RenderUtil::kPixelScale; - int render_offset_y = (6 + ConvertY(board_y) * 12) * RenderUtil::kPixelScale; - const gColor& og_color = renderer->getColor(); - renderer->setColor(color); - outliner.draw(board_pos_x + render_offset_x, board_pos_y + render_offset_y, 16 * RenderUtil::kPixelScale, 12 * RenderUtil::kPixelScale); - renderer->setColor(og_color); -} - -void GameCanvas::Move(int x, int y, int to_x, int to_y) { - animate_move_piece_x = to_x; - animate_move_piece_y = to_y; - animate_from_pos_x = (7 + x * 16) * RenderUtil::kPixelScale; - animate_from_pos_y = (6 + ConvertY(y) * 12 - piece_offset) * RenderUtil::kPixelScale; - animate_to_pos_x = (7 + to_x * 16) * RenderUtil::kPixelScale; - animate_to_pos_y = (6 + ConvertY(to_y) * 12 - piece_offset) * RenderUtil::kPixelScale; - animate = true; - - Ref piece = chess_board->GetPiece(x, y); - chess_board->SetPiece(to_x, to_y, piece); - chess_board->SetPiece(x, y, nullptr); -} - -void GameCanvas::DrawBoard() { - renderer->setColor(255, 255, 255); - board_textures[flip_board].draw(board_pos_x, board_pos_y, board_width, board_height); - if (flip_board) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - DrawPiece(x, y); - } - } - } else { - for (int x = 0; x < 8; x++) { - for (int y = 7; y >= 0; y--) { - DrawPiece(x, y); - } - } - } -} - -void GameCanvas::DrawPiece(int x, int y) { - Ref piece = chess_board->GetPiece(x, y); - if (hover_piece_x == x && hover_piece_y == y) { - if (!show_moves) { - HighlightPosition(x, y, {0.0f, 139 / 255.0f, 203 / 255.0f}); - } - } - if (show_moves) { - if (move_piece_x == x && move_piece_y == y) { - HighlightPosition(x, y, {250 / 255.0f, 100 / 255.0f, 20 / 255.0f}); - } - Ref hover_piece = chess_board->GetPiece(move_piece_x, move_piece_y); - if (hover_piece) { - if (hover_piece->GetColor() == connection->GetCurrentTurn()) { - if (chess_board->IsValidMove(move_piece_x, move_piece_y, x, y)) { - if (hover_piece_x == x && hover_piece_y == y) { - HighlightPosition(x, y, {0.3f, 0 / 255.0f, 203 / 255.0f}); - } else { - HighlightPosition(x, y, {0.0f, 139 / 255.0f, 203 / 255.0f}); - } - }/* else if (hover_piece->IsValidMove(move_piece_x, move_piece_y, x, y)) { - HighlightPosition(x, y, {1.0f, 0 / 255.0f, 0 / 255.0f}); - }*/ - } - } - } - - if (!piece) { - return; - } - auto& image = piece->GetColor() == kPieceColorWhite ? white_pieces : black_pieces; - int index = piece->GetType() - 1; - if (index < 0) { - return; - } - int render_offset_x = (7 + x * 16) * RenderUtil::kPixelScale; - int render_offset_y = (6 + ConvertY(y) * 12 - piece_offset) * RenderUtil::kPixelScale; - if (animate && animate_move_piece_x == x && animate_move_piece_y == y) { - image.drawSub(board_pos_x + animate_from_pos_x, board_pos_y + animate_from_pos_y, // render pos - 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size - index * 16, index * 32, // image pos - 16, 32 // image size - ); - animate_from_pos_x = Lerp(animate_from_pos_x, animate_to_pos_x, 0.15f); - animate_from_pos_y = Lerp(animate_from_pos_y, animate_to_pos_y, 0.15f); - if (std::abs(animate_to_pos_x - animate_from_pos_x) < 0.02f && std::abs(animate_to_pos_y - animate_from_pos_y) < 0.02f) { - animate = false; - } - } else { - int start_offset = fell_anim_dist * -400 * (x + 1); - image.drawSub(board_pos_x + render_offset_x, board_pos_y + render_offset_y + start_offset, // render pos - 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size - index * 16, index * 32, // image pos - 16, 32 // image size, - ); - } -} - -int GameCanvas::ConvertY(int y) { - return flip_board ? y : 7 - y; -} -void GameCanvas::keyPressed(int key) { -// gLogi("GameCanvas") << "keyPressed:" << key; -} - -void GameCanvas::keyReleased(int key) { -// gLogi("GameCanvas") << "keyReleased:" << key; -} - -void GameCanvas::charPressed(unsigned int codepoint) { -// gLogi("GameCanvas") << "charPressed:" << gCodepointToStr(codepoint); -} - -void GameCanvas::mouseMoved(int x, int y) { - if (input_lock || wait_turn) { - return; - } -// gLogi("GameCanvas") << "mouseMoved" << ", x:" << x << ", y:" << y; - int board_x = (x - board_pos_x) / RenderUtil::kPixelScale - 7; - int board_y = (y - board_pos_y) / RenderUtil::kPixelScale - 6; - int piece_x = board_x / 16; - int piece_y = ConvertY(board_y / 12); - if (piece_x < 0 || piece_x > 8 || piece_y < 0 || piece_y > 8) { - hover_piece_x = -1; - hover_piece_y = -1; - return; - } - hover_piece_x = piece_x; - hover_piece_y = piece_y; -} - -void GameCanvas::mouseDragged(int x, int y, int button) { -// gLogi("GameCanvas") << "mouseDragged" << ", x:" << x << ", y:" << y << ", b:" << button; -} - -void GameCanvas::mousePressed(int x, int y, int button) { -// gLogi("GameCanvas") << "mousePressed" << ", x:" << x << ", y:" << y << ", b:" << button; -} - -void GameCanvas::mouseReleased(int x, int y, int button) { - if (animate || input_lock || wait_turn) { - return; - } - int board_x = (x - board_pos_x) / RenderUtil::kPixelScale - 7; - int board_y = (y - board_pos_y) / RenderUtil::kPixelScale - 6; - int piece_x = board_x / 16; - int piece_y = ConvertY(board_y / 12); - if (piece_x < 0 || piece_x >= 8 || piece_y < 0 || piece_y >= 8) { - hover_piece_x = -1; - hover_piece_y = -1; - return; - } - hover_piece_x = piece_x; - hover_piece_y = piece_y; - - bool was_show_moves = show_moves; - show_moves = false; - Ref piece = chess_board->GetPiece(hover_piece_x, hover_piece_y); - if (!was_show_moves && piece && piece->GetColor() == player_color) { - show_moves = true; - move_piece_x = hover_piece_x; - move_piece_y = hover_piece_y; - } else if (was_show_moves && (piece == nullptr || piece->GetColor() != player_color)) { - if (animate || input_lock || wait_turn || !chess_board->IsValidMove(move_piece_x, move_piece_y, hover_piece_x, hover_piece_y)) { - show_moves = false; - hover_piece_x = -1; - hover_piece_y = -1; - return; - } - connection->Move(move_piece_x, move_piece_y, hover_piece_x, hover_piece_y, piece != nullptr ? piece->GetType() : kPieceTypeNone, false); - Move(move_piece_x, move_piece_y, hover_piece_x, hover_piece_y); - wait_turn = true; - - show_moves = false; - hover_piece_x = -1; - hover_piece_y = -1; - } -} - -void GameCanvas::SetInfoText(const std::string& text) { - next_info_text = text; - has_next_text = true; -} - -void GameCanvas::mouseScrolled(int x, int y) { - -} - -void GameCanvas::mouseEntered() { - -} - -void GameCanvas::mouseExited() { - -} - -void GameCanvas::windowResized(int w, int h) { - -} - -void GameCanvas::showNotify() { - -} - -void GameCanvas::hideNotify() { - -} diff --git a/src/GameCanvas.h b/src/GameCanvas.h deleted file mode 100644 index b248a7d..0000000 --- a/src/GameCanvas.h +++ /dev/null @@ -1,80 +0,0 @@ - -#pragma once - -#include -#include "app/gApp.h" -#include "chess/ChessBoard.h" -#include "gBaseCanvas.h" -#include "gImage.h" -#include "net/Packets.h" - -class GameCanvas : public gBaseCanvas { -public: - GameCanvas(gApp* root, Ref connection, Ref thread); - virtual ~GameCanvas(); - - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - void charPressed(unsigned int codepoint); - void mouseMoved(int x, int y ); - void mouseDragged(int x, int y, int button); - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseScrolled(int x, int y); - void mouseEntered(); - void mouseExited(); - void windowResized(int w, int h); - - void showNotify(); - void hideNotify(); - - void HighlightPosition(int board_x, int board_y, const gColor& color); - void Move(int x, int y, int to_x, int to_y); - void DrawBoard(); - void DrawPiece(int x, int y); - int ConvertY(int y); -private: - gApp* root; - gImage cursor; - gImage board_textures[2]; - gImage outliner; - int board_pos_x, board_pos_y; - int board_width, board_height; - gImage white_pieces; - gImage black_pieces; - ChessBoard* chess_board; - int hover_piece_x; - int hover_piece_y; - int move_piece_x; - int move_piece_y; - bool show_moves; - PieceColor player_color; - gFont font; - bool animate; - int animate_move_piece_x; - int animate_move_piece_y; - float animate_from_pos_x; - float animate_from_pos_y; - float animate_to_pos_x; - float animate_to_pos_y; - int piece_offset; - bool input_lock; - double game_time; - double fell_anim_dist; - std::string info_text; - int info_pos_x; - int info_pos_y; - bool wait_turn; - Ref connection; - Ref thread; - std::string next_info_text; - bool has_next_text = false; - bool flip_board; - - private: - void SetInfoText(const std::string& text); -}; diff --git a/src/app/Button.cpp b/src/app/Button.cpp deleted file mode 100644 index b079d40..0000000 --- a/src/app/Button.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Button.h" diff --git a/src/app/app.cpp b/src/app/app.cpp new file mode 100644 index 0000000..68e2290 --- /dev/null +++ b/src/app/app.cpp @@ -0,0 +1,38 @@ +/* +* gApp.cpp +* +* Created on: May 6, 2020 +* Author: noyan +*/ + +#include "app.h" +#include +#include "game_canvas.h" +#include "menu_canvas.h" + +gApp::gApp() { +} + +gApp::gApp(int argc, char **argv) : gBaseApp(argc, argv) { +} + +gApp::~gApp() { +} + +void gApp::setup() { + RenderUtil::Setup(); +// auto* cnv = new GameCanvas(this, CreateRef(), nullptr); + auto* cnv = new LoadingCanvas(this); + appmanager->setCurrentCanvas(cnv); +} + +void gApp::update() { +} + +void gApp::stop() { + auto* canvas = appmanager->getCurrentCanvas(); + if (canvas != nullptr) { + canvas->hideNotify(); + delete canvas; + } +} \ No newline at end of file diff --git a/src/app/gApp.h b/src/app/app.h similarity index 85% rename from src/app/gApp.h rename to src/app/app.h index 3421a19..fc378af 100644 --- a/src/app/gApp.h +++ b/src/app/app.h @@ -19,6 +19,10 @@ class gApp : public gBaseApp { void setup(); void update(); + + void stop(); + + bool loaded_ = false; }; #endif /* GAPP_H_ */ diff --git a/src/app/button.cpp b/src/app/button.cpp new file mode 100644 index 0000000..a501bf7 --- /dev/null +++ b/src/app/button.cpp @@ -0,0 +1 @@ +#include "button.h" diff --git a/src/app/Button.h b/src/app/button.h similarity index 98% rename from src/app/Button.h rename to src/app/button.h index ee2a7b9..af1e8b3 100644 --- a/src/app/Button.h +++ b/src/app/button.h @@ -3,8 +3,8 @@ #include #include -#include "Util.h" #include "gAppManager.h" +#include "util.h" class Button { public: diff --git a/src/app/gApp.cpp b/src/app/gApp.cpp deleted file mode 100644 index ae34748..0000000 --- a/src/app/gApp.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -* gApp.cpp -* -* Created on: May 6, 2020 -* Author: noyan -*/ - -#include "gApp.h" -#include "GameCanvas.h" -#include "MenuCanvas.h" - -gApp::gApp() { -} - -gApp::gApp(int argc, char **argv) : gBaseApp(argc, argv) { -} - -gApp::~gApp() { -} - -void gApp::setup() { - RenderUtil::Setup(); - MenuCanvas* cnv = new MenuCanvas(this); - appmanager->setCurrentCanvas(cnv); -} - -void gApp::update() { -} diff --git a/src/app/main.cpp b/src/app/main.cpp index be01e65..c474d9a 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -14,10 +14,8 @@ * limitations under the License. */ - +#include "app.h" #include "gAppManager.h" -#include "gApp.h" - int main(int argc, char **argv) { diff --git a/src/chess/ChessBoard.h b/src/chess/ChessBoard.h deleted file mode 100644 index 163db1a..0000000 --- a/src/chess/ChessBoard.h +++ /dev/null @@ -1,27 +0,0 @@ - -#pragma once - -#include -#include "Piece.h" -#include "Util.h" - -class ChessBoard { - public: - ChessBoard(); - ChessBoard(std::array board); - ~ChessBoard(); - - Ref GetPiece(int x, int y); - void SetPiece(int x, int y, Ref piece); - - bool IsValidMove(int x, int y, int to_x, int to_y); - - static int PosToIndex(int x, int y) { - return y * 8 + x; - } - private: - Ref pieces_[7]; - Ref board_[8 * 8]; - - void CreatePieces(); -}; \ No newline at end of file diff --git a/src/chess/ChessBoard.cpp b/src/chess/chess_board.cpp similarity index 56% rename from src/chess/ChessBoard.cpp rename to src/chess/chess_board.cpp index aa19f2e..e9a50ba 100644 --- a/src/chess/ChessBoard.cpp +++ b/src/chess/chess_board.cpp @@ -1,4 +1,4 @@ -#include "ChessBoard.h" +#include "chess_board.h" #include @@ -58,10 +58,36 @@ bool ChessBoard::IsValidMove(int x, int y, int to_x, int to_y) { return piece->IsValidMove(x, y, to_x, to_y); } +ChessState ChessBoard::CheckState(PieceColor current_turn) { + if (current_turn == kPieceColorNone) { + return ChessState::Playing; + } + for (int x = 0; x < 8; ++x) { + for (int y = 0; y < 8; ++y) { + Ref piece = GetPiece(x, y); + if (piece == nullptr) { + continue; + } + if (piece->GetType() == kPieceTypeKing && piece->GetColor() != current_turn) { + if (HasAnyValidMoveTo(x, y, piece->GetColor())) { + return ChessState::Checkmate; + } + return ChessState::Playing; + } + } + } + return ChessState::Playing; +} + void ChessBoard::CreatePieces() { pieces_[kPieceTypePawn] = CreateRef(kPieceTypePawn, kPieceColorWhite, [this](int x, int y, int to_x, int to_y, PieceColor team) -> bool { if (team == kPieceColorWhite) { - if ((to_y == y + 1 || to_y == y + 2) && x == to_x) { + bool double_jump = y == 1; + if ((to_y == y + 1 || (double_jump && to_y == y + 2)) && x == to_x) { + Ref front_piece = GetPiece(to_x, to_y); + if (front_piece) { + return false; + } return true; } if (x - 1 == to_x && y + 1 == to_y) { @@ -77,7 +103,12 @@ void ChessBoard::CreatePieces() { } } } else { - if ((to_y == y - 1 || to_y == y - 2) && x == to_x) { + bool double_jump = y == 6; + if ((to_y == y - 1 || (double_jump && to_y == y - 2)) && x == to_x) { + Ref front_piece = GetPiece(to_x, to_y); + if (front_piece) { + return false; + } return true; } if (x - 1 == to_x && y - 1 == to_y) { @@ -123,9 +154,6 @@ void ChessBoard::CreatePieces() { return false; }); pieces_[kPieceTypeBishop] = CreateRef(kPieceTypeBishop, kPieceColorWhite, [this](int x, int y, int to_x, int to_y, PieceColor team) -> bool { - if (x == to_x || y == to_y) { - return false; - } int rx = to_x - x; int ry = to_y - y; @@ -134,16 +162,16 @@ void ChessBoard::CreatePieces() { } int r = std::max(std::abs(rx), std::abs(ry)); for (int i = 1; i < r; i++) { - if (!CheckOccupation(this, x - i, y - i, to_x, to_y, x, y, team)) { + if (rx < 0 && ry < 0 && !CheckOccupation(this, x - i, y - i, to_x, to_y, x, y, team)) { return false; } - if (!CheckOccupation(this, x + i, y - i, to_x, to_y, x, y, team)) { + if (rx > 0 && ry < 0 && !CheckOccupation(this, x + i, y - i, to_x, to_y, x, y, team)) { return false; } - if (!CheckOccupation(this, x + i, y + i, to_x, to_y, x, y, team)) { + if (rx > 0 && ry > 0 && !CheckOccupation(this, x + i, y + i, to_x, to_y, x, y, team)) { return false; } - if (!CheckOccupation(this, x - i, y + i, to_x, to_y, x, y, team)) { + if (rx < 0 && ry > 0 && !CheckOccupation(this, x - i, y + i, to_x, to_y, x, y, team)) { return false; } } @@ -158,25 +186,70 @@ void ChessBoard::CreatePieces() { int ry = to_y - y; int r = std::max(std::abs(rx), std::abs(ry)); for (int i = 1; i < r; i++) { - if (rx > 0 && !CheckOccupation(this, x + i, y, to_x, to_y, x, y, team)) { + if (rx > 0 && ry == 0 && !CheckOccupation(this, x + i, y, to_x, to_y, x, y, team)) { return false; } - if (rx < 0 && !CheckOccupation(this, x - i, y, to_x, to_y, x, y, team)) { + if (rx < 0 && ry == 0 && !CheckOccupation(this, x - i, y, to_x, to_y, x, y, team)) { return false; } - if (ry > 0 && !CheckOccupation(this, x, y + i, to_x, to_y, x, y, team)) { + if (rx == 0 && ry > 0 && !CheckOccupation(this, x, y + i, to_x, to_y, x, y, team)) { return false; } - if (ry < 0 && !CheckOccupation(this, x, y - i, to_x, to_y, x, y, team)) { + if (rx == 0 && ry < 0 && !CheckOccupation(this, x, y - i, to_x, to_y, x, y, team)) { return false; } } return true; }); - pieces_[kPieceTypeQueen] = CreateRef(kPieceTypeQueen, kPieceColorWhite, [](int x, int y, int to_x, int to_y, PieceColor team) -> bool { - return false; + pieces_[kPieceTypeQueen] = CreateRef(kPieceTypeQueen, kPieceColorWhite, [this](int x, int y, int to_x, int to_y, PieceColor team) -> bool { + if ((to_x == x + 1 || to_x == x - 1 || to_x == x) && (to_y == y + 1 || to_y == y - 1 || to_y == y)) { + return true; + } + int rx = to_x - x; + int ry = to_y - y; + if (std::abs(rx) != std::abs(ry)) { + bool match = (x == to_x && y != to_y) || (x != to_x && y == to_y); + if (!match) { + return false; + } + int r = std::max(std::abs(rx), std::abs(ry)); + for (int i = 1; i < r; i++) { + if (rx > 0 && ry == 0 && !CheckOccupation(this, x + i, y, to_x, to_y, x, y, team)) { + return false; + } + if (rx < 0 && ry == 0 && !CheckOccupation(this, x - i, y, to_x, to_y, x, y, team)) { + return false; + } + if (rx == 0 && ry > 0 && !CheckOccupation(this, x, y + i, to_x, to_y, x, y, team)) { + return false; + } + if (rx == 0 && ry < 0 && !CheckOccupation(this, x, y - i, to_x, to_y, x, y, team)) { + return false; + } + } + return true; + } + int r = std::max(std::abs(rx), std::abs(ry)); + for (int i = 1; i < r; i++) { + if (rx < 0 && ry < 0 && !CheckOccupation(this, x - i, y - i, to_x, to_y, x, y, team)) { + return false; + } + if (rx > 0 && ry < 0 && !CheckOccupation(this, x + i, y - i, to_x, to_y, x, y, team)) { + return false; + } + if (rx > 0 && ry > 0 && !CheckOccupation(this, x + i, y + i, to_x, to_y, x, y, team)) { + return false; + } + if (rx < 0 && ry > 0 && !CheckOccupation(this, x - i, y + i, to_x, to_y, x, y, team)) { + return false; + } + } + return true; }); pieces_[kPieceTypeKing] = CreateRef(kPieceTypeKing, kPieceColorWhite, [](int x, int y, int to_x, int to_y, PieceColor team) -> bool { + if ((to_x == x + 1 || to_x == x - 1 || to_x == x) && (to_y == y + 1 || to_y == y - 1 || to_y == y)) { + return true; + } return false; }); } \ No newline at end of file diff --git a/src/chess/chess_board.h b/src/chess/chess_board.h new file mode 100644 index 0000000..dceab48 --- /dev/null +++ b/src/chess/chess_board.h @@ -0,0 +1,58 @@ + +#pragma once + +#include +#include "piece.h" +#include "util.h" + +enum class ChessState { + Playing, + Stalemate, + Checkmate +}; + +class ChessBoard { + public: + ChessBoard(); + ChessBoard(std::array board); + ~ChessBoard(); + + Ref GetPiece(int x, int y); + void SetPiece(int x, int y, Ref piece); + + bool IsValidMove(int x, int y, int to_x, int to_y); + + static int PosToIndex(int x, int y) { + return y * 8 + x; + } + + ChessState CheckState(PieceColor current_turn); + + bool HasValidMoves(int x, int y) { + for (int to_x = 0; to_x < 8; ++to_x) { + for (int to_y = 0; to_y < 8; ++to_y) { + if (IsValidMove(x, y, to_x, to_y)) { + return true; + } + } + } + return false; + } + + bool HasAnyValidMoveTo(int to_x, int to_y, PieceColor other_color) { + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + auto piece = GetPiece(x, y); + if (piece && piece->GetColor() != other_color && IsValidMove(x, y, to_x, to_y)) { + return true; + } + } + } + return false; + } + private: + Ref pieces_[7]; + Ref board_[8 * 8]; + + void CreatePieces(); +}; \ No newline at end of file diff --git a/src/chess/Piece.cpp b/src/chess/piece.cpp similarity index 100% rename from src/chess/Piece.cpp rename to src/chess/piece.cpp diff --git a/src/chess/Piece.h b/src/chess/piece.h similarity index 98% rename from src/chess/Piece.h rename to src/chess/piece.h index aa2a1ca..9ae4a3e 100644 --- a/src/chess/Piece.h +++ b/src/chess/piece.h @@ -3,7 +3,7 @@ #include #include -#include "Util.h" +#include "util.h" enum PieceType : uint8_t { kPieceTypeNone, @@ -40,6 +40,7 @@ class Piece { Ref CopyTeam(PieceColor color) { return CreateRef(type_, color, move_function_); } + private: PieceType type_; PieceColor color_; diff --git a/src/color.cpp b/src/color.cpp new file mode 100644 index 0000000..5b37711 --- /dev/null +++ b/src/color.cpp @@ -0,0 +1,85 @@ +#include "color.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) + +HSL rgb2hsl(float r, float g, float b) { + HSL result; + + r /= 255; + g /= 255; + b /= 255; + + float max = MAX(MAX(r,g),b); + float min = MIN(MIN(r,g),b); + + result.h = result.s = result.l = (max + min) / 2; + + if (max == min) { + result.h = result.s = 0; // achromatic + } else { + float d = max - min; + result.s = (result.l > 0.5) ? d / (2 - max - min) : d / (max + min); + + if (max == r) { + result.h = (g - b) / d + (g < b ? 6 : 0); + } else if (max == g) { + result.h = (b - r) / d + 2; + } else if (max == b) { + result.h = (r - g) / d + 4; + } + + result.h /= 6; + } + + return result; +} + +float hue2rgb(float p, float q, float t) { + if (t < 0) { + t += 1; + } + if (t > 1) { + t -= 1; + } + if (t < 1./6) { + return p + (q - p) * 6 * t; + } + if (t < 1./2) { + return q; + } + if (t < 2./3) { + return p + (q - p) * (2./3 - t) * 6; + } + return p; + +} + +RGB hsl2rgb(float h, float s, float l) { + RGB result; + + if (s == 0) { + result.r = result.g = result.b = l; // achromatic + } else { + float q = l < 0.5 ? l * (1 + s) : l + s - l * s; + float p = 2 * l - q; + result.r = hue2rgb(p, q, h + 1./3) * 255; + result.g = hue2rgb(p, q, h) * 255; + result.b = hue2rgb(p, q, h - 1./3) * 255; + } + + return result; +} + +// Function to perform a smooth color transition between two RGB colors +RGB interpolateColors(const RGB& a, const RGB& b, float t) { + RGB result; + result.r = (1.0f - t) * a.r + t * b.r; + result.g = (1.0f - t) * a.g + t * b.g; + result.b = (1.0f - t) * a.b + t * b.b; + return result; +} + +#undef MIN +#undef MAX + diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..99b423e --- /dev/null +++ b/src/color.h @@ -0,0 +1,38 @@ +#pragma once + +typedef struct rgb { + float r, g, b; +} RGB; + +typedef struct hsl { + float h, s, l; +} HSL; + +/* + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes r, g, and b are contained in the set [0, 255] and + * returns HSL in the set [0, 1]. + */ +HSL rgb2hsl(float r, float g, float b); + +//////////////////////////////////////////////////////////////////////// + +/* + * Converts an HUE to r, g or b. + * returns float in the set [0, 1]. + */ +float hue2rgb(float p, float q, float t); + +//////////////////////////////////////////////////////////////////////// + +/* + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns RGB in the set [0, 255]. + */ +RGB hsl2rgb(float h, float s, float l); + +// Function to perform a smooth color transition between two RGB colors +RGB interpolateColors(const RGB& a, const RGB& b, float t); \ No newline at end of file diff --git a/src/game_canvas.cpp b/src/game_canvas.cpp new file mode 100644 index 0000000..097d6b4 --- /dev/null +++ b/src/game_canvas.cpp @@ -0,0 +1,427 @@ +#include "game_canvas.h" +#include "message_canvas.h" + +GameCanvas::GameCanvas(gApp* root, Ref connection, Ref thread) : gBaseCanvas(root), connection_(connection), thread_(thread) { + this->root_ = root; +} + +GameCanvas::~GameCanvas() { + connection_->Close(); + if (thread_ && thread_->joinable()) { + thread_->join(); + } +} + +void GameCanvas::setup() { + if (!connection_->IsHost()) { + player_color_ = kPieceColorBlack; + flip_board_ = true; + } else { + player_color_ = kPieceColorWhite; + flip_board_ = false; + } + cursor_.loadImage("cursor.png"); + cursor_.setFiltering(2, 2); + cursor_height_ = cursor_.getHeight(); + cursor_width_ = 16; + board_textures_[0].loadImage("boards/board_persp_01.png"); + board_textures_[0].setFiltering(2, 2); + board_textures_[1].loadImage("boards/board_persp_01_flipped.png"); + board_textures_[1].setFiltering(2, 2); + + board_width_ = board_textures_[0].getWidth() * RenderUtil::kPixelScale; + board_height_ = board_textures_[0].getHeight() * RenderUtil::kPixelScale; + board_pos_x = (getWidth() - board_width_) / 2; + board_pos_y = (getHeight() - board_height_) / 2; + white_pieces_.loadImage("pieces/WhitePieces-Sheet.png"); + white_pieces_.setFiltering(2, 2); + black_pieces_.loadImage("pieces/BlackPieces-Sheet.png"); + black_pieces_.setFiltering(2, 2); + outliner_.loadImage("outliner.png"); + outliner_.setFiltering(2, 2); + ResetSelection(); + font_.loadFont("PixeloidMono.ttf", 12, false); + piece_offset_ = white_pieces_.getHeight() - 11; + input_lock_ = true; + game_started_ = false; + ended_ = false; + // todo move chess board spaghetti stuff to connection and handle everything there + chess_board_ = CreateRef(*connection_->GetBoardData()); + connection_->SetOnMove([this](int x, int y, int to_x, int to_y) { + Move(x, y, to_x, to_y); + }); + connection_->SetOnTurnChange([this](PieceColor color) { + if (color == kPieceColorNone) { + return; + } + auto state = chess_board_->CheckState(color); + if (state == ChessState::Checkmate) { + connection_->EndGame(color); + return; + } else if (state == ChessState::Stalemate) { + connection_->EndGame(kPieceColorNone); + return; + } + if (color == player_color_) { + SetInfoText("Your turn!"); + } else { + SetInfoText("Opponent's turn!"); + } + }); + connection_->SetOnStartGame([this]() { + game_started_ = true; + }); + connection_->SetOnEndGame([this](PieceColor color) { + input_lock_ = true; + ended_ = true; + winner_color_ = color; + if (color == kPieceColorNone) { + SetInfoText("Stalemate!"); + } else if (color == player_color_) { + SetInfoText("You won!"); + } else { + SetInfoText("You lost!"); + } + }); + appmanager->getWindow()->setCursorMode(0x00034002); // GLFW_CURSOR_HIDDEN + appmanager->setTargetFramerate(120); + + connection_->Ready(); +} + + +void GameCanvas::update() { + game_time_ += appmanager->getElapsedTime(); + UpdateInfoText(); + if (ended_) { + dance_anim_time_ += appmanager->getElapsedTime(); + return; + } + if (game_started_) { + UpdateFallAnimation(); + } +} + +void GameCanvas::UpdateInfoText() { + if (has_next_text_) { + info_text_ = next_info_text_; + info_pos_x_ = getWidth() / 2; + info_pos_y_ = board_pos_y + board_height_ + 50; + has_next_text_ = false; + } +} + +void GameCanvas::UpdateFallAnimation() { + if (fall_anim_dist_ > 0.0f) { + fall_anim_dist_ = Lerp(fall_anim_dist_, 0.0f, 0.01f + (game_time_ / 20.0f)); + if (fall_anim_dist_ < 0.001f) { + fall_anim_dist_ = 0.0f; + input_lock_ = false; + } + } +} + +void GameCanvas::draw() { + clearColor(0x6f, 0x75, 0x83); + if (!game_started_) { + return; + } + DrawBoard(); + DrawInfoText(); + // pos * 2 -> pos * 4 / 2 -> pos * pixelScale / 2 + cursor_.drawSub(cursor_pos_x_ - cursor_width_ * 2, cursor_pos_y_ - cursor_height_, + cursor_width_ * 4, cursor_height_ * 4, + cursor_type_ * 16, 0, + cursor_width_, cursor_height_); + /*for (int x = 0; x < 8; ++x) { + for (int y = 0; y < 8; ++y) { + RenderUtil::DrawFont(gToStr(x) + " " + gToStr(y), + board_pos_x + (7 + x * 16) * RenderUtil::kPixelScale, + board_pos_y + (10 + y * 12) * RenderUtil::kPixelScale, {1.0f, 0, 0}); + } + }*/ +} + +void GameCanvas::HighlightPosition(int board_x, int board_y, const gColor& color) { + int render_offset_x = (7 + board_x * 16) * RenderUtil::kPixelScale; + int render_offset_y = (6 + ConvertY(board_y) * 12) * RenderUtil::kPixelScale; + const gColor& og_color = renderer->getColor(); + renderer->setColor(color); + outliner_.draw(board_pos_x + render_offset_x, board_pos_y + render_offset_y, 16 * RenderUtil::kPixelScale, 12 * RenderUtil::kPixelScale); + renderer->setColor(og_color); +} + +bool GameCanvas::Move(int x, int y, int to_x, int to_y) { + animate_move_piece_x_ = to_x; + animate_move_piece_y_ = to_y; + animate_from_pos_x_ = (7 + x * 16) * RenderUtil::kPixelScale; + animate_from_pos_y_ = (6 + ConvertY(y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + animate_to_pos_x_ = (7 + to_x * 16) * RenderUtil::kPixelScale; + animate_to_pos_y_ = (6 + ConvertY(to_y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + animate_ = true; + + Ref piece = chess_board_->GetPiece(x, y); + chess_board_->SetPiece(to_x, to_y, piece); + chess_board_->SetPiece(x, y, nullptr); + + if (piece->GetType() == kPieceTypePawn) { + if (to_y == 0 && piece->GetColor() == kPieceColorBlack) { + // black promote + // promote after switch + if (player_color_ == kPieceColorBlack) { + SetInfoText("Promote your pawn!"); + promoting_ = true; + show_moves_ = false; + hover_piece_x_ = to_x; + hover_piece_y_ = to_y; + return false; + } else { + SetInfoText("Your opponent is promoting its pawn!"); + return false; + } + } else if (to_y == 7 && piece->GetColor() == kPieceColorWhite) { + // white promote + // promote after switch + if (player_color_ == kPieceColorWhite) { + SetInfoText("Promote your pawn!"); + promoting_ = true; + show_moves_ = false; + hover_piece_x_ = to_x; + hover_piece_y_ = to_y; + return false; + } else { + SetInfoText("Your opponent is promoting its pawn!"); + return false; + } + } else if (to_x == x && std::abs(to_y - y) == 2) { + int jump_y = to_y - y; + if (jump_y > 0) { + jump_y -= 1; + } else { + jump_y -= -1; + } + Ref jump_piece = chess_board_->GetPiece(x, y + jump_y); + if (jump_piece) { + chess_board_->SetPiece(x, y + jump_y, nullptr); + } + } + } + return true; +} + +void GameCanvas::DrawBoard() { + renderer->setColor(255, 255, 255); + board_textures_[flip_board_].draw(board_pos_x, board_pos_y, board_width_, + board_height_); + if (flip_board_) { + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + DrawPiece(x, y); + } + } + } else { + for (int x = 0; x < 8; x++) { + for (int y = 7; y >= 0; y--) { + DrawPiece(x, y); + } + } + } +} + +void GameCanvas::DrawInfoText() { + if (!info_text_.empty()) { + RenderUtil::DrawFont(info_text_, info_pos_x_, info_pos_y_, {1.0f, 1.0f, 1.0f}, true); + } +} + +void GameCanvas::DrawPiece(int x, int y) { + Ref piece = chess_board_->GetPiece(x, y); + if (hover_piece_x_ == x && hover_piece_y_ == y) { + if (!show_moves_) { + HighlightPosition(x, y, {0.0f, 139 / 255.0f, 203 / 255.0f}); + } + } + if (show_moves_) { + if (move_piece_x_ == x && move_piece_y_ == y) { + HighlightPosition(x, y, {250 / 255.0f, 100 / 255.0f, 20 / 255.0f}); + } + Ref hover_piece = + chess_board_->GetPiece(move_piece_x_, move_piece_y_); + if (hover_piece) { + if (chess_board_->IsValidMove(move_piece_x_, move_piece_y_, x, y)) { + if (hover_piece_x_ == x && hover_piece_y_ == y && hover_piece->GetColor() == connection_->GetCurrentTurn()) { + HighlightPosition(x, y, {0.3f, 0 / 255.0f, 203 / 255.0f}); + } else { + HighlightPosition(x, y, {0.0f, 139 / 255.0f, 203 / 255.0f}); + } + } + } + } + + if (!piece) { + return; + } + auto& image = piece->GetColor() == kPieceColorWhite ? white_pieces_ : black_pieces_; + int index = piece->GetType() - 1; + if (index < 0) { + return; + } + int render_offset_x = (7 + x * 16) * RenderUtil::kPixelScale; + int render_offset_y = (6 + ConvertY(y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + if (animate_ && animate_move_piece_x_ == x && animate_move_piece_y_ == y) { + image.drawSub(board_pos_x + animate_from_pos_x_, board_pos_y + animate_from_pos_y_, // render pos + 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); + animate_from_pos_x_ = Lerp(animate_from_pos_x_, animate_to_pos_x_, 0.15f); + animate_from_pos_y_ = Lerp(animate_from_pos_y_, animate_to_pos_y_, 0.15f); + if (std::abs(animate_to_pos_x_ - animate_from_pos_x_) < 0.02f && std::abs(animate_to_pos_y_ - animate_from_pos_y_) < 0.02f) { + animate_ = false; + } + } else if (ended_ && (piece->GetColor() == winner_color_ || winner_color_ == kPieceColorNone)) { + double stretch = std::sin(dance_anim_time_ * 6) * 30; + double compress = (std::cos(dance_anim_time_ * 6)) * 5; + image.drawSub(board_pos_x + render_offset_x + (compress / 2), board_pos_y + render_offset_y + stretch, // render pos + 16 * RenderUtil::kPixelScale - compress, 32 * RenderUtil::kPixelScale - stretch, // render size + index * 16, index * 32, // image pos + 16, 32, // image size + 8 * RenderUtil::kPixelScale - compress, 32 * RenderUtil::kPixelScale - stretch - 3 * RenderUtil::kPixelScale, // pivot center + (int) gRadToDeg(std::cos(dance_anim_time_ * 3) * 0.25f) // rotation + ); + } else { + int start_offset = -fall_anim_dist_ * 800 * (x + 1); + image.drawSub(board_pos_x + render_offset_x, board_pos_y + render_offset_y + start_offset, // render pos + 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); + } +} + +int GameCanvas::ConvertY(int y) { + return flip_board_ ? y : 7 - y; +} + +void GameCanvas::ResetSelection() { + show_moves_ = false; + hover_piece_x_ = -1; + hover_piece_y_ = -1; +} + +void GameCanvas::keyPressed(int key) { +// gLogi("GameCanvas") << "keyPressed:" << key; +} + +void GameCanvas::keyReleased(int key) { +// gLogi("GameCanvas") << "keyReleased:" << key; +} + +void GameCanvas::charPressed(unsigned int codepoint) { +// gLogi("GameCanvas") << "charPressed:" << gCodepointToStr(codepoint); +} + +void GameCanvas::mouseMoved(int x, int y) { + cursor_pos_x_ = x; + cursor_pos_y_ = y; + if (input_lock_ || promoting_ || connection_->GetCurrentTurn() != player_color_) { + return; + } +// gLogi("GameCanvas") << "mouseMoved" << ", x:" << x << ", y:" << y; + int board_x = (x - board_pos_x) / RenderUtil::kPixelScale - 7; + int board_y = (y - board_pos_y) / RenderUtil::kPixelScale - 6; + int piece_x = board_x / 16; + int piece_y = ConvertY(board_y / 12); + if (piece_x < 0 || piece_x >= 8 || piece_y < 0 || piece_y >= 8) { + ResetSelection(); + return; + } + hover_piece_x_ = piece_x; + hover_piece_y_ = piece_y; + Ref piece = chess_board_->GetPiece(hover_piece_x_, hover_piece_y_); + if (!show_moves_ && piece != nullptr && piece->GetColor() != player_color_) { + ResetSelection(); + } +} + +void GameCanvas::mouseDragged(int x, int y, int button) { +// gLogi("GameCanvas") << "mouseDragged" << ", x:" << x << ", y:" << y << ", b:" << button; + cursor_pos_x_ = x; + cursor_pos_y_ = y; + cursor_type_ = CursorType::kHandClosed; +} + +void GameCanvas::mousePressed(int x, int y, int button) { +// gLogi("GameCanvas") << "mousePressed" << ", x:" << x << ", y:" << y << ", b:" << button; + cursor_type_ = CursorType::kHandClosed; +} + +void GameCanvas::mouseReleased(int x, int y, int button) { + cursor_type_ = CursorType::kArrow; + if (animate_ || input_lock_ || connection_->GetCurrentTurn() != player_color_) { + return; + } + if (promoting_) { + return; + } + + int board_x = (x - board_pos_x) / RenderUtil::kPixelScale - 7; + int board_y = (y - board_pos_y) / RenderUtil::kPixelScale - 6; + int piece_x = board_x / 16; + int piece_y = ConvertY(board_y / 12); + if (piece_x < 0 || piece_x >= 8 || piece_y < 0 || piece_y >= 8) { + ResetSelection(); + return; + } + hover_piece_x_ = piece_x; + hover_piece_y_ = piece_y; + + bool was_show_moves = show_moves_; + show_moves_ = false; + Ref piece = chess_board_->GetPiece(hover_piece_x_, hover_piece_y_); + if (!was_show_moves && piece && piece->GetColor() == player_color_) { + show_moves_ = true; + move_piece_x_ = hover_piece_x_; + move_piece_y_ = hover_piece_y_; + } else if (was_show_moves && (piece == nullptr || piece->GetColor() != player_color_)) { + if (animate_ || input_lock_ || !chess_board_->IsValidMove(move_piece_x_, move_piece_y_, hover_piece_x_, + hover_piece_y_)) { + ResetSelection(); + return; + } + bool switch_turn = Move(move_piece_x_, move_piece_y_, hover_piece_x_, hover_piece_y_); + connection_->Move(move_piece_x_, move_piece_y_, hover_piece_x_, + hover_piece_y_, switch_turn); + + ResetSelection(); + } +} + +void GameCanvas::SetInfoText(const std::string& text) { + next_info_text_ = text; + has_next_text_ = true; +} + +void GameCanvas::mouseScrolled(int x, int y) { + +} + +void GameCanvas::mouseEntered() { + +} + +void GameCanvas::mouseExited() { + +} + +void GameCanvas::windowResized(int w, int h) { + +} + +void GameCanvas::showNotify() { + +} + +void GameCanvas::hideNotify() { + connection_->Close(); +} diff --git a/src/game_canvas.h b/src/game_canvas.h new file mode 100644 index 0000000..9da5b65 --- /dev/null +++ b/src/game_canvas.h @@ -0,0 +1,91 @@ + +#pragma once + +#include +#include "app/app.h" +#include "chess/chess_board.h" +#include "gBaseCanvas.h" +#include "gImage.h" +#include "net/packets.h" + +enum CursorType { + kArrow, + kHand, + kHandClosed +}; + +class GameCanvas : public gBaseCanvas { + public: + GameCanvas(gApp* root, Ref connection, Ref thread); + virtual ~GameCanvas(); + + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void charPressed(unsigned int codepoint); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseScrolled(int x, int y); + void mouseEntered(); + void mouseExited(); + void windowResized(int w, int h); + + void showNotify(); + void hideNotify(); + + void HighlightPosition(int board_x, int board_y, const gColor& color); + bool Move(int x, int y, int to_x, int to_y); + void DrawBoard(); + void DrawInfoText(); + void DrawPiece(int x, int y); + int ConvertY(int y); + void ResetSelection(); + + void UpdateInfoText(); + void UpdateFallAnimation(); + private: + gApp* root_; + gImage cursor_; + int cursor_width_, cursor_height_; + gImage board_textures_[2]; + gImage outliner_; + int board_pos_x, board_pos_y; + int board_width_, board_height_; + gImage white_pieces_; + gImage black_pieces_; + Ref chess_board_; + int hover_piece_x_, hover_piece_y_; + int move_piece_x_, move_piece_y_; + bool show_moves_; + PieceColor player_color_; + gFont font_; + bool animate_ = false; + int animate_move_piece_x_, animate_move_piece_y_; + float animate_from_pos_x_, animate_from_pos_y_; + float animate_to_pos_x_, animate_to_pos_y_; + int piece_offset_; + bool input_lock_; + double game_time_ = 0.0f; + double fall_anim_dist_ = 1.0f; + std::string info_text_; + int info_pos_x_, info_pos_y_; + Ref connection_; + Ref thread_; + std::string next_info_text_; + bool has_next_text_ = false; + bool flip_board_; + bool game_started_; + bool promoting_ = false; + bool ended_ = false; + PieceColor winner_color_; + double dance_anim_time_ = 0.0f; + int cursor_pos_x_ = -100, cursor_pos_y_ = -100; + CursorType cursor_type_ = CursorType::kArrow; + private: + void SetInfoText(const std::string& text); +}; diff --git a/src/loading_canvas.cpp b/src/loading_canvas.cpp new file mode 100644 index 0000000..a576240 --- /dev/null +++ b/src/loading_canvas.cpp @@ -0,0 +1,103 @@ +#include "loading_canvas.h" +#include "menu_canvas.h" + +LoadingCanvas::LoadingCanvas(gApp* root) : gBaseCanvas(root) { + this->root = root; +} + +LoadingCanvas::~LoadingCanvas() { +} + +void LoadingCanvas::setup() { + brand_logo_.loadImage("teoncreative_logo_white.png"); + brand_width_ = brand_logo_.getWidth() / 4; + brand_height_ = brand_logo_.getHeight() / 4; + brand_x_ = (getWidth() - brand_width_) / 2; + brand_y_ = (getHeight() - brand_height_) / 2; + glist_logo_.loadImage("glistengine_logo.png"); + glist_width_ = glist_logo_.getWidth(); + glist_height_ = glist_logo_.getHeight(); + glist_x_ = (getWidth() - glist_width_) / 2; + glist_y_ = (getHeight() - glist_height_) / 2; + delta_ = 0.0f; +} + +void LoadingCanvas::update() { + delta_ += appmanager->getElapsedTime(); +} + +void LoadingCanvas::draw() { + clearColor(0x1c, 0x1e, 0x25); + const gColor& old_color = renderer->getColor(); + if (delta_ < 4) { + int opacity = delta_ * delta_ * 255; + if (delta_ > 3) { + opacity = 255 - (delta_ - 3) * (delta_ - 3) * 255; + } + renderer->setColor(255, 255, 255, std::min(opacity, 255)); + brand_logo_.draw(brand_x_, brand_y_, brand_width_, brand_height_); + } else if (delta_ < 8) { + double delta = this->delta_ - 4; + int opacity = delta * delta * 255; + if (delta > 3) { + opacity = 255 - (delta - 3) * (delta - 3) * 255; + } + renderer->setColor(255, 255, 255, std::min(opacity, 255)); + glist_logo_.draw(glist_x_, glist_y_, glist_width_, glist_height_); + } else { + root->setCurrentCanvas(new MenuCanvas(root)); + } + renderer->setColor(old_color); +} + +void LoadingCanvas::keyPressed(int key) { + // gLogi("gCanvas") << "keyPressed:" << key; +} + +void LoadingCanvas::keyReleased(int key) { + // gLogi("gCanvas") << "keyReleased:" << key; +} + +void LoadingCanvas::charPressed(unsigned int codepoint) { + // gLogi("gCanvas") << "charPressed:" << gCodepointToStr(codepoint); +} + +void LoadingCanvas::mouseMoved(int x, int y) { + // gLogi("gCanvas") << "mouseMoved" << ", x:" << x << ", y:" << y; +} + +void LoadingCanvas::mouseDragged(int x, int y, int button) { + // gLogi("gCanvas") << "mouseDragged" << ", x:" << x << ", y:" << y << ", b:" << button; +} + +void LoadingCanvas::mousePressed(int x, int y, int button) { + // gLogi("gCanvas") << "mousePressed" << ", x:" << x << ", y:" << y << ", b:" << button; +} + +void LoadingCanvas::mouseReleased(int x, int y, int button) { + // gLogi("gCanvas") << "mouseReleased" << ", button:" << button; +} + +void LoadingCanvas::mouseScrolled(int x, int y) { + // gLogi("gCanvas") << "mouseScrolled" << ", x:" << x << ", y:" << y; +} + +void LoadingCanvas::mouseEntered() { + +} + +void LoadingCanvas::mouseExited() { + +} + +void LoadingCanvas::windowResized(int w, int h) { + +} + +void LoadingCanvas::showNotify() { + +} + +void LoadingCanvas::hideNotify() { + +} \ No newline at end of file diff --git a/src/loading_canvas.h b/src/loading_canvas.h new file mode 100644 index 0000000..d2f0d34 --- /dev/null +++ b/src/loading_canvas.h @@ -0,0 +1,42 @@ + +#pragma once + +#include +#include "app/app.h" +#include "app/button.h" +#include "gBaseCanvas.h" +#include "gImage.h" +#include "util.h" + +class LoadingCanvas : public gBaseCanvas { + public: + LoadingCanvas(gApp* root); + virtual ~LoadingCanvas(); + + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void charPressed(unsigned int codepoint); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseScrolled(int x, int y); + void mouseEntered(); + void mouseExited(); + void windowResized(int w, int h); + + void showNotify(); + void hideNotify(); + + private: + gApp* root; + gImage brand_logo_; + int brand_width_, brand_height_, brand_x_, brand_y_; + gImage glist_logo_; + int glist_width_, glist_height_, glist_x_, glist_y_; + double delta_; +}; \ No newline at end of file diff --git a/src/MenuCanvas.cpp b/src/menu_canvas.cpp similarity index 73% rename from src/MenuCanvas.cpp rename to src/menu_canvas.cpp index 0b49186..59e9113 100644 --- a/src/MenuCanvas.cpp +++ b/src/menu_canvas.cpp @@ -5,20 +5,22 @@ * Author: noyan */ -#include "MenuCanvas.h" +#include "menu_canvas.h" #include -#include "GameCanvas.h" -#include "MessageCanvas.h" +#include "game_canvas.h" +#include "message_canvas.h" HostTask::HostTask(gApp* root) : root(root) { title = "Creating server..."; znet::ServerConfig config{"127.0.0.1", 44025}; server = CreateRef(config); completed = false; + wait = false; thread = CreateRef([&]() { znet::Result result; title = "Binding server..."; if ((result = server->Bind()) != znet::Result::Success) { + wait = true; gLogi("HostTask") << "Failed to bind server! Result: " << (int) result; root->setCurrentCanvas(new MessageCanvas(root, "Failed to bind server!")); return; @@ -28,7 +30,13 @@ HostTask::HostTask(gApp* root) : root(root) { connection->SetOnConnect([this]() { completed = true; }); - if ((result = server->Listen()) != znet::Result::Success) { + connection->SetOnOpponentDisconnect([root]() { + // changing the canvas will close and cleanup the server + // no need to do here + root->setCurrentCanvas(new MessageCanvas(root, "Opponent disconnected from the game!")); + }); + if ((result = server->Listen()) != znet::Result::Completed) { + wait = true; gLogi("HostTask") << "Failed to listen server! Result: " << (int) result; root->setCurrentCanvas(new MessageCanvas(root, "Failed to listen server!")); return; @@ -37,6 +45,11 @@ HostTask::HostTask(gApp* root) : root(root) { } HostTask::~HostTask() { + if (wait) { + if (thread && thread->joinable()) { + thread->join(); + } + } } bool HostTask::Update() { @@ -59,20 +72,38 @@ JoinTask::JoinTask(gApp* root, std::string host, int port) : root(root), host(ho znet::ClientConfig config{host, port}; client_ = CreateRef(config); completed = false; - thread_ = CreateRef([host, port, this]() { + wait = false; + thread_ = CreateRef([root, host, port, this]() { connection = CreateRef(client_); connection->SetOnConnect([this]() { title = "Loading the board..."; completed = true; }); title = "Connecting to " + host + ":" + std::to_string(port) + "..."; - client_->Bind(); - client_->Connect(); + znet::Result result; + if ((result = client_->Bind()) != znet::Result::Success) { + wait = true; + gLogi("HostTask") << "Failed to bind client! Result: " << (int) result; + root->setCurrentCanvas(new MessageCanvas(root, "Failed to bind client!")); + return; + } + result = client_->Connect(); + if (result != znet::Result::Completed) { + wait = true; + gLogi("HostTask") << "Failed to connect to the server! Result: " << (int) result; + root->setCurrentCanvas(new MessageCanvas(root, "Failed to connect to the server!")); + return; + } + root->setCurrentCanvas(new MessageCanvas(root, "Opponent disconnected from the game!")); }); } JoinTask::~JoinTask() { - + if (wait) { + if (thread_ && thread_->joinable()) { + thread_->join(); + } + } } bool JoinTask::Update() { @@ -118,9 +149,24 @@ void MenuCanvas::setup() { title = ""; task = nullptr; appmanager->setTargetFramerate(120); + fade_in_ = !root->loaded_; + root->loaded_ = true; + fade_in_timer_ = 0.0f; + fade_color_ = RGB{0x1c / 255.0f, 0x1e / 255.0f, 0x25 / 255.0f}; + back_color_ = RGB{0x4c / 255.0f, 0x54 / 255.0f, 0x65 / 255.0f}; + clear_color_ = back_color_; } void MenuCanvas::update() { + fade_in_timer_ += appmanager->getElapsedTime(); + if (fade_in_) { + clear_color_ = interpolateColors(fade_color_, back_color_, std::min(fade_in_timer_, 1.0)); + if (fade_in_timer_ >= 1.5f) { + fade_in_ = false; + } + return; + } + if (task) { title = task->GetTitle(); } else { @@ -148,8 +194,15 @@ void MenuCanvas::update() { } void MenuCanvas::draw() { + clearColor(gColor{clear_color_.r, clear_color_.g, clear_color_.b}); + if (fade_in_ && fade_in_timer_ < 0.5f) { + return; + } + const gColor& og_color = renderer->getColor(); + if (fade_in_) { + setColor(255, 255, 255, std::min((int) ((fade_in_timer_ - 0.5f) * 255.0f), 255)); + } if (loading) { - clearColor(0x4c, 0x54, 0x65); int size = 80; int scale = 3; int offset_x = (getWidth() / 2) - (size / 2); @@ -163,15 +216,16 @@ void MenuCanvas::draw() { white_pieces.drawSub(x + 8, y + 16, 16 * scale, 32 * scale, 16 * i, 0, 16, 32, 8, 16, (int) (delta * 50.0f) % 360); } RenderUtil::DrawFont(title, getWidth() / 2, 150, {1.0f, 1.0f, 1.0f}, true); + setColor(og_color); return; } - clearColor(0x4c, 0x54, 0x65); // buttons join_button->Draw(); host_button->Draw(); settings_button->Draw(); // logo RenderUtil::DrawFont(&logo_font, "Chess Tacos", getWidth() / 2 - logo_font.getStringWidth("Chess Tacos") / 2, 150); + setColor(og_color); } void MenuCanvas::keyPressed(int key) { diff --git a/src/MenuCanvas.h b/src/menu_canvas.h similarity index 88% rename from src/MenuCanvas.h rename to src/menu_canvas.h index 1de9032..6be0c8b 100644 --- a/src/MenuCanvas.h +++ b/src/menu_canvas.h @@ -8,13 +8,14 @@ #ifndef GCANVAS_H_ #define GCANVAS_H_ -#include +#include #include -#include "Util.h" -#include "app/Button.h" -#include "app/gApp.h" +#include "app/app.h" +#include "app/button.h" +#include "color.h" #include "gBaseCanvas.h" #include "gImage.h" +#include "util.h" class Task { public: @@ -39,6 +40,7 @@ class HostTask : public Task { Ref thread; bool completed = false; Ref connection; + bool wait = false; }; class JoinTask : public Task { @@ -58,6 +60,7 @@ class JoinTask : public Task { Ref thread_; bool completed = false; Ref connection; + bool wait = false; }; class MenuCanvas : public gBaseCanvas { @@ -96,6 +99,11 @@ class MenuCanvas : public gBaseCanvas { double loading_anim; std::string title; Ref task; + bool fade_in_; + RGB fade_color_; + RGB back_color_; + RGB clear_color_; + double fade_in_timer_; }; #endif /* GCANVAS_H_ */ diff --git a/src/MessageCanvas.cpp b/src/message_canvas.cpp similarity index 97% rename from src/MessageCanvas.cpp rename to src/message_canvas.cpp index a730a9a..6ac934b 100644 --- a/src/MessageCanvas.cpp +++ b/src/message_canvas.cpp @@ -1,5 +1,5 @@ -#include "MessageCanvas.h" -#include "MenuCanvas.h" +#include "message_canvas.h" +#include "menu_canvas.h" MessageCanvas::MessageCanvas(gApp* root, std::string message) : gBaseCanvas(root), message(message) { this->root = root; diff --git a/src/MessageCanvas.h b/src/message_canvas.h similarity index 92% rename from src/MessageCanvas.h rename to src/message_canvas.h index 7ca4b6c..b94750f 100644 --- a/src/MessageCanvas.h +++ b/src/message_canvas.h @@ -1,12 +1,12 @@ #pragma once +#include +#include "app/app.h" +#include "app/button.h" #include "gBaseCanvas.h" -#include "app/gApp.h" #include "gImage.h" -#include "Util.h" -#include "app/Button.h" -#include +#include "util.h" class MessageCanvas : public gBaseCanvas { public: diff --git a/src/net/Packets.cpp b/src/net/Packets.cpp deleted file mode 100644 index 218f37d..0000000 --- a/src/net/Packets.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Packets.h" diff --git a/src/net/ChessConnection.cpp b/src/net/chess_connection.cpp similarity index 66% rename from src/net/ChessConnection.cpp rename to src/net/chess_connection.cpp index 0becb9e..1cd1bbc 100644 --- a/src/net/ChessConnection.cpp +++ b/src/net/chess_connection.cpp @@ -1,5 +1,5 @@ -#include "ChessConnection.h" -#include "chess/ChessBoard.h" +#include "chess_connection.h" +#include "chess/chess_board.h" ChessConnection::ChessConnection() { @@ -32,26 +32,26 @@ ChessConnectionLocal::ChessConnectionLocal(Ref server) : server_(s board_data[ChessBoard::PosToIndex(2, 7)] = {true, kPieceTypeBishop, kPieceColorBlack}; board_data[ChessBoard::PosToIndex(5, 7)] = {true, kPieceTypeBishop, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(4, 0)] = {true, kPieceTypeKing, kPieceColorWhite}; board_data[ChessBoard::PosToIndex(3, 0)] = {true, kPieceTypeQueen, kPieceColorWhite}; - board_data[ChessBoard::PosToIndex(3, 7)] = {true, kPieceTypeQueen, kPieceColorBlack}; - board_data[ChessBoard::PosToIndex(4, 0)] = {true, kPieceTypeKing, kPieceColorWhite}; board_data[ChessBoard::PosToIndex(4, 7)] = {true, kPieceTypeKing, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(3, 7)] = {true, kPieceTypeQueen, kPieceColorBlack}; } ChessConnectionLocal::~ChessConnectionLocal() { } -void ChessConnectionLocal::Move(int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) { +void ChessConnectionLocal::Move(int x, int y, int to_x, int to_y, bool switch_turn) { auto pk = CreateRef(); pk->x_ = x; pk->y_ = y; pk->to_x_ = to_x; pk->to_y_ = to_y; - pk->piece_type_ = piece_type; - pk->is_capture_ = is_capture; opponent_session_->SendPacket(pk); - SwitchTurn(); + if (switch_turn) { + SwitchTurn(); + } } void ChessConnectionLocal::Promote(int x, int y, PieceType piece_type) { @@ -63,7 +63,14 @@ bool ChessConnectionLocal::IsOpen() { } void ChessConnectionLocal::Ready() { + is_ready = true; + if (received_ready) { + StartGame(); + } +} +void ChessConnectionLocal::Close() { + server_->Stop(); } void ChessConnectionLocal::SwitchTurn() { @@ -74,12 +81,30 @@ void ChessConnectionLocal::SwitchTurn() { on_turn_change_(current_turn_); } +void ChessConnectionLocal::StartGame() { + auto turn_packet = CreateRef(); + turn_packet->color_ = current_turn_; + opponent_session_->SendPacket(turn_packet); + auto start_packet = CreateRef(); + opponent_session_->SendPacket(start_packet); + on_turn_change_(current_turn_); + on_start_game_(); +} + +void ChessConnectionLocal::EndGame(PieceColor winner) { + auto end_packet = CreateRef(); + end_packet->winner_ = winner; + opponent_session_->SendPacket(end_packet); + on_end_game_(winner); +} + void ChessConnectionLocal::OnEvent(znet::Event& event) { znet::EventDispatcher dispatcher{event}; - dispatcher.Dispatch(ZNET_BIND_FN(OnServerClientConnectedEvent)); + dispatcher.Dispatch(ZNET_BIND_FN(OnClientConnect)); + dispatcher.Dispatch(ZNET_BIND_FN(OnClientDisconnect)); } -bool ChessConnectionLocal::OnServerClientConnectedEvent(znet::ServerClientConnectedEvent& event) { +bool ChessConnectionLocal::OnClientConnect(znet::ServerClientConnectedEvent& event) { if (!accepting_connections_) { event.session()->Close(); return false; @@ -101,10 +126,18 @@ bool ChessConnectionLocal::OnServerClientConnectedEvent(znet::ServerClientConnec client_ready_handler->AddReceiveCallback(ZNET_BIND_FN(OnClientReadyPacket)); layer.AddPacketHandler(client_ready_handler); layer.AddPacketHandler(CreateRef>()); + auto end_game_handler = CreateRef>(); + end_game_handler->AddReceiveCallback(ZNET_BIND_FN(OnEndGamePacket)); + layer.AddPacketHandler(end_game_handler); on_connect_(); return false; } +bool ChessConnectionLocal::OnClientDisconnect(znet::ServerClientDisconnectedEvent& event) { + on_opponent_disconnect_(); + return false; +} + bool ChessConnectionLocal::OnBoardRequestPacket(znet::ConnectionSession&, Ref packet) { auto pk = CreateRef(); pk->board_ = board_data_; @@ -113,18 +146,20 @@ bool ChessConnectionLocal::OnBoardRequestPacket(znet::ConnectionSession&, Ref packet) { - auto turn_packet = CreateRef(); - turn_packet->color_ = current_turn_; - opponent_session_->SendPacket(turn_packet); - auto start_packet = CreateRef(); - opponent_session_->SendPacket(start_packet); - on_turn_change_(current_turn_); - on_start_game_(); + received_ready = true; + if (is_ready) { + StartGame(); + } + return false; +} + +bool ChessConnectionLocal::OnEndGamePacket(znet::ConnectionSession&, Ref packet) { + on_end_game_(packet->winner_); return true; } bool ChessConnectionLocal::OnMovePacket(znet::ConnectionSession&, Ref packet) { - on_move_(packet->x_, packet->y_, packet->to_x_, packet->to_y_, packet->piece_type_, packet->is_capture_); + on_move_(packet->x_, packet->y_, packet->to_x_, packet->to_y_); SwitchTurn(); return true; } @@ -138,15 +173,16 @@ ChessConnectionNetwork::~ChessConnectionNetwork() { } -void ChessConnectionNetwork::Move(int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) { +void ChessConnectionNetwork::Move(int x, int y, int to_x, int to_y, bool switch_turn) { auto pk = CreateRef(); pk->x_ = x; pk->y_ = y; pk->to_x_ = to_x; pk->to_y_ = to_y; - pk->piece_type_ = piece_type; - pk->is_capture_ = is_capture; client_->client_session()->SendPacket(pk); + if (switch_turn) { + current_turn_ = kPieceColorNone; + } } void ChessConnectionNetwork::Promote(int x, int y, PieceType piece_type) { @@ -162,6 +198,17 @@ void ChessConnectionNetwork::Ready() { client_->client_session()->SendPacket(pk); } +void ChessConnectionNetwork::Close() { + client_->Disconnect(); +} + +void ChessConnectionNetwork::EndGame(PieceColor winner) { + auto pk = CreateRef(); + pk->winner_ = winner; + client_->client_session()->SendPacket(pk); + on_end_game_(winner); +} + void ChessConnectionNetwork::OnEvent(znet::Event& event) { znet::EventDispatcher dispatcher{event}; dispatcher.Dispatch(ZNET_BIND_FN(OnClientConnectedToServerEvent)); @@ -185,6 +232,9 @@ bool ChessConnectionNetwork::OnClientConnectedToServerEvent(znet::ClientConnecte start_game_handler->AddReceiveCallback(ZNET_BIND_FN(OnStartGamePacket)); layer.AddPacketHandler(start_game_handler); layer.AddPacketHandler(CreateRef>()); + auto end_game_handler = CreateRef>(); + end_game_handler->AddReceiveCallback(ZNET_BIND_FN(OnEndGamePacket)); + layer.AddPacketHandler(end_game_handler); auto pk = CreateRef(); session->SendPacket(pk); @@ -193,7 +243,7 @@ bool ChessConnectionNetwork::OnClientConnectedToServerEvent(znet::ClientConnecte } bool ChessConnectionNetwork::OnMovePacket(znet::ConnectionSession&, Ref packet) { - on_move_(packet->x_, packet->y_, packet->to_x_, packet->to_y_, packet->piece_type_, packet->is_capture_); + on_move_(packet->x_, packet->y_, packet->to_x_, packet->to_y_); return true; } @@ -210,5 +260,40 @@ bool ChessConnectionNetwork::OnSetTurnPacket(znet::ConnectionSession&, Ref packet) { + on_start_game_(); return true; +} + +bool ChessConnectionNetwork::OnEndGamePacket(znet::ConnectionSession&, Ref packet) { + on_end_game_(packet->winner_); + return true; +} + +ChessConnectionDummy::ChessConnectionDummy() { + board_data_ = CreateRef>(); + std::array& board_data = *board_data_.get(); + for (int x = 0; x < 8; ++x) { + board_data[ChessBoard::PosToIndex(x, 1)] = {true, kPieceTypePawn, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(x, 6)] = {true, kPieceTypePawn, kPieceColorBlack}; + } + board_data[ChessBoard::PosToIndex(0, 0)] = {true, kPieceTypeRook, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(7, 0)] = {true, kPieceTypeRook, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(0, 7)] = {true, kPieceTypeRook, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(7, 7)] = {true, kPieceTypeRook, kPieceColorBlack}; + + board_data[ChessBoard::PosToIndex(1, 0)] = {true, kPieceTypeKnight, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(6, 0)] = {true, kPieceTypeKnight, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(1, 7)] = {true, kPieceTypeKnight, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(6, 7)] = {true, kPieceTypeKnight, kPieceColorBlack}; + + board_data[ChessBoard::PosToIndex(2, 0)] = {true, kPieceTypeBishop, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(5, 0)] = {true, kPieceTypeBishop, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(2, 7)] = {true, kPieceTypeBishop, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(5, 7)] = {true, kPieceTypeBishop, kPieceColorBlack}; + + board_data[ChessBoard::PosToIndex(4, 0)] = {true, kPieceTypeKing, kPieceColorWhite}; + board_data[ChessBoard::PosToIndex(3, 0)] = {true, kPieceTypeQueen, kPieceColorWhite}; + + board_data[ChessBoard::PosToIndex(4, 7)] = {true, kPieceTypeKing, kPieceColorBlack}; + board_data[ChessBoard::PosToIndex(3, 7)] = {true, kPieceTypeQueen, kPieceColorBlack}; } \ No newline at end of file diff --git a/src/net/ChessConnection.h b/src/net/chess_connection.h similarity index 57% rename from src/net/ChessConnection.h rename to src/net/chess_connection.h index 3955783..2f013e5 100644 --- a/src/net/ChessConnection.h +++ b/src/net/chess_connection.h @@ -1,25 +1,28 @@ #pragma once -#include "chess/Piece.h" -#include "Packets.h" +#include + +#include "chess/piece.h" +#include "packets.h" class ChessConnection { public: - using MoveFunction = std::function; + using MoveFunction = std::function; using TurnChangeFunction = std::function; using OnConnectFunction = std::function; using StartGameFunction = std::function; + using EndGameFunction = std::function; ChessConnection(); virtual ~ChessConnection(); - virtual void Move(int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) = 0; + virtual void Move(int x, int y, int to_x, int to_y, bool switch_turn) = 0; virtual void Promote(int x, int y, PieceType piece_type) = 0; virtual bool IsOpen() = 0; - virtual bool IsLocal() { return false; } + virtual bool IsHost() { return false; } virtual Ref> GetBoardData() { return nullptr; } @@ -27,6 +30,10 @@ class ChessConnection { virtual void Ready() = 0; + virtual void Close() = 0; + + virtual void EndGame(PieceColor winner) = 0; + void SetOnMove(MoveFunction on_move) { on_move_ = std::move(on_move); } @@ -43,24 +50,29 @@ class ChessConnection { on_start_game_ = std::move(on_start_game); } + void SetOnEndGame(EndGameFunction on_end_game) { + on_end_game_ = std::move(on_end_game); + } protected: TurnChangeFunction on_turn_change_; MoveFunction on_move_; OnConnectFunction on_connect_; StartGameFunction on_start_game_; + EndGameFunction on_end_game_; }; class ChessConnectionLocal : public ChessConnection { public: + using DisconnectFunction = std::function; ChessConnectionLocal(Ref server); ~ChessConnectionLocal() override; - void Move(int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) override; + void Move(int x, int y, int to_x, int to_y, bool switch_turn) override; void Promote(int x, int y, PieceType piece_type) override; bool IsOpen() override; - bool IsLocal() override { return true; } + bool IsHost() override { return true; } Ref> GetBoardData() override { return board_data_; } @@ -68,33 +80,46 @@ class ChessConnectionLocal : public ChessConnection { void Ready() override; + void Close() override; + + void EndGame(PieceColor winner) override; + + void SwitchTurn(); + + void SetOnOpponentDisconnect(DisconnectFunction on_disconnect) { + on_opponent_disconnect_ = std::move(on_disconnect); + } + private: Ref server_; bool accepting_connections_ = true; Ref opponent_session_; Ref> board_data_; PieceColor current_turn_ = kPieceColorWhite; + DisconnectFunction on_opponent_disconnect_; + bool is_ready = false, received_ready = false; private: - void SwitchTurn(); void OnEvent(znet::Event& event); - bool OnServerClientConnectedEvent(znet::ServerClientConnectedEvent& event); + bool OnClientConnect(znet::ServerClientConnectedEvent& event); + bool OnClientDisconnect(znet::ServerClientDisconnectedEvent& event); bool OnMovePacket(znet::ConnectionSession&, Ref packet); bool OnBoardRequestPacket(znet::ConnectionSession&, Ref packet); bool OnClientReadyPacket(znet::ConnectionSession&, Ref packet); + bool OnEndGamePacket(znet::ConnectionSession&, Ref packet); + void StartGame(); }; class ChessConnectionNetwork : public ChessConnection { public: - ChessConnectionNetwork(Ref client); ~ChessConnectionNetwork() override; - void Move(int x, int y, int to_x, int to_y, PieceType piece_type, bool is_capture) override; + void Move(int x, int y, int to_x, int to_y, bool switch_turn) override; void Promote(int x, int y, PieceType piece_type) override; bool IsOpen() override; - bool IsLocal() override { return false; } + bool IsHost() override { return false; } Ref> GetBoardData() override { return board_data_; } @@ -102,6 +127,10 @@ class ChessConnectionNetwork : public ChessConnection { void Ready() override; + void Close() override; + + void EndGame(PieceColor winner) override; + private: Ref client_; Ref opponent_session_; @@ -115,4 +144,36 @@ class ChessConnectionNetwork : public ChessConnection { bool OnUpdateBoardPacket(znet::ConnectionSession&, Ref packet); bool OnSetTurnPacket(znet::ConnectionSession&, Ref packet); bool OnStartGamePacket(znet::ConnectionSession&, Ref packet); + bool OnEndGamePacket(znet::ConnectionSession&, Ref packet); +}; + +class ChessConnectionDummy : public ChessConnection { + public: + ChessConnectionDummy(); + ~ChessConnectionDummy() override = default; + + void Move(int x, int y, int to_x, int to_y, bool switch_turn) override {} + void Promote(int x, int y, PieceType piece_type) override {} + bool IsOpen() override { return false; } + + Ref> GetBoardData() override { return board_data_; } + + PieceColor GetCurrentTurn() override { return current_turn_; } + + void Ready() override { + on_start_game_(); + current_turn_ = kPieceColorBlack; + on_turn_change_(kPieceColorBlack); + } + + void Close() override { + + } + + void EndGame(PieceColor winner) override { + on_end_game_(winner); + } + private: + PieceColor current_turn_ = kPieceColorNone; + Ref> board_data_; }; \ No newline at end of file diff --git a/src/net/packets.cpp b/src/net/packets.cpp new file mode 100644 index 0000000..e81d56e --- /dev/null +++ b/src/net/packets.cpp @@ -0,0 +1 @@ +#include "packets.h" diff --git a/src/net/Packets.h b/src/net/packets.h similarity index 86% rename from src/net/Packets.h rename to src/net/packets.h index d242b84..0f7a545 100644 --- a/src/net/Packets.h +++ b/src/net/packets.h @@ -1,7 +1,7 @@ #pragma once -#include +#include #include "znet/znet.h" struct PieceData { @@ -25,8 +25,6 @@ class MovePacket : public znet::Packet { int y_; int to_x_; int to_y_; - PieceType piece_type_; - bool is_capture_; }; class BoardRequestPacket : public znet::Packet { @@ -51,6 +49,13 @@ class ClientReadyPacket : public znet::Packet { ClientReadyPacket() : znet::Packet(6) { } }; +class EndGamePacket : public znet::Packet { + public: + EndGamePacket() : znet::Packet(7) { } + + PieceColor winner_; +}; + class UpdateBoardPacketSerializerV1 : public znet::PacketSerializer { public: UpdateBoardPacketSerializerV1() : PacketSerializer(1) {} @@ -92,8 +97,6 @@ class MovePacketSerializerV1 : public znet::PacketSerializer { buffer->WriteInt(packet->y_); buffer->WriteInt(packet->to_x_); buffer->WriteInt(packet->to_y_); - buffer->WriteInt((uint8_t) packet->piece_type_); - buffer->WriteBool(packet->is_capture_); return buffer; } @@ -103,8 +106,6 @@ class MovePacketSerializerV1 : public znet::PacketSerializer { packet->y_ = buffer->ReadInt(); packet->to_x_ = buffer->ReadInt(); packet->to_y_ = buffer->ReadInt(); - packet->piece_type_ = (PieceType) buffer->ReadInt(); - packet->is_capture_ = buffer->ReadBool(); return packet; } }; @@ -162,4 +163,20 @@ class ClientReadyPacketSerializerV1 : public znet::PacketSerializer Deserialize(Ref buffer) override { return CreateRef(); } +}; + +class EndGamePacketSerializerV1 : public znet::PacketSerializer { + public: + EndGamePacketSerializerV1() : PacketSerializer(7) {} + + Ref Serialize(Ref packet, Ref buffer) override { + buffer->WriteInt((uint8_t) packet->winner_); + return buffer; + } + + Ref Deserialize(Ref buffer) override { + auto packet = CreateRef(); + packet->winner_ = (PieceColor) buffer->ReadInt(); + return packet; + } }; \ No newline at end of file diff --git a/src/Util.cpp b/src/util.cpp similarity index 94% rename from src/Util.cpp rename to src/util.cpp index 2217ccd..52e56af 100644 --- a/src/Util.cpp +++ b/src/util.cpp @@ -1,4 +1,4 @@ -#include "Util.h" +#include "util.h" #include gFont* RenderUtil::font_; @@ -34,9 +34,9 @@ void RenderUtil::DrawFont(const std::string& text, int x, int y, const gColor& c void RenderUtil::DrawFont(gFont* render_font, const std::string& text, int x, int y, const gColor& color) { const gColor& og_color = gRenderObject::getRenderer()->getColor(); - gRenderObject::getRenderer()->setColor({color.r - color.r / 2.0f, color.g - color.g / 2.0f, color.b - color.b / 2.0f, color.a}); + gRenderObject::getRenderer()->setColor({color.r - color.r / 2.0f, color.g - color.g / 2.0f, color.b - color.b / 2.0f, og_color.a}); render_font->drawText(text, x, y + render_font->getStringHeight(text) / 6.5f); - gRenderObject::getRenderer()->setColor(color); + gRenderObject::getRenderer()->setColor({color.r, color.g, color.b, og_color.a}); render_font->drawText(text, x, y); gRenderObject::getRenderer()->setColor(og_color); } diff --git a/src/Util.h b/src/util.h similarity index 100% rename from src/Util.h rename to src/util.h diff --git a/znet b/znet index 795c576..e4233d7 160000 --- a/znet +++ b/znet @@ -1 +1 @@ -Subproject commit 795c576ea372d8847e78ca95f4c216bcb32073de +Subproject commit e4233d7a628ed12452d5d8b3f88f53c1c5a3cb65