From 973eef9302c9999ceb17eb2f5ca113556592660b Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Tue, 11 Apr 2023 12:39:53 -0500 Subject: [PATCH] Bullet spawning and rendering. --- Faceball2030/assets/enemies/bullet.mtl | 11 ++ Faceball2030/assets/enemies/bullet.png | Bin 0 -> 26472 bytes Faceball2030/assets/enemies/bullet.wings | Bin 0 -> 28674 bytes Faceball2030/main.cpp | 241 +++++++++++++---------- Faceball2030/main.h | 21 +- 5 files changed, 163 insertions(+), 110 deletions(-) create mode 100644 Faceball2030/assets/enemies/bullet.mtl create mode 100644 Faceball2030/assets/enemies/bullet.png create mode 100644 Faceball2030/assets/enemies/bullet.wings diff --git a/Faceball2030/assets/enemies/bullet.mtl b/Faceball2030/assets/enemies/bullet.mtl new file mode 100644 index 0000000..26644d3 --- /dev/null +++ b/Faceball2030/assets/enemies/bullet.mtl @@ -0,0 +1,11 @@ +# Exported from Wings 3D 2.2.9 +newmtl sphere1_auv +Ns 19.999999999999996 +d 1.0 +illum 2 +Kd 1.0 1.0 1.0 +Ka 0.0 0.0 0.0 +Ks 0.19 0.19 0.19 +Ke 0.0 0.0 0.0 +map_Kd sphere1_auv.png + diff --git a/Faceball2030/assets/enemies/bullet.png b/Faceball2030/assets/enemies/bullet.png new file mode 100644 index 0000000000000000000000000000000000000000..80784fff8ae4b3e56494b2f16aa4f2621674f7c6 GIT binary patch literal 26472 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 X@2C^9=D>Ll%2j$Tl!xTSx|UeOImBiiJL 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 literal 0 HcmV?d00001 diff --git a/Faceball2030/assets/enemies/bullet.wings b/Faceball2030/assets/enemies/bullet.wings new file mode 100644 index 0000000000000000000000000000000000000000..b0ed73674e741cdcd09509ecf677c91076ee15e8 GIT binary patch literal 28674 zcmb5VWmJ^i7dQO308vT>q)`Ns8iSo@i~C;988uoBmnoHdZ`TsSKtq96(`8DV z-rn9IEj4R3g-irRA$EdOWBF&4+_pB66LZ0soxpkOY*7gbs6sYywoIu9#84wWK}R7_ zmFl%q$tL6EKo@T`J)4BZ^Yr|^!!s2Bf!m+qcd3` z{(^yeI->T_QJ{<^_d{Mq8L^(7#-gYv<(P?ZU5;vIF#RdMUecB2d$elW0=S&`%J9x~ z1&MpirQ0@4{v03jnouVee?#<64MOj<%1ifriZb+S(1iQ~`5W`(`I?x^!}3P#M+#3x zHB21&T;CPez(;Gw34iQo5?h~SIirlrkN>cbSqTvOXb&`aj;r|ZwNdynufRs75 z^XLDo|F3aJ=3Y5XE+bY?^=3b6Ax;y1N;u-2?>^qSnTJs-gW(-&!+s99wx!(5+ znbMD-BIcPu>%^-y6ce!pGP!)B65&<*R=S$jLdS)casT~!EfbE6YFPp`^TcuPY}51u zcuw7B{h3RbBv7H8kKGG~j2Pqxt^1FHHC!G}?>VQZRS}0CAoD6&8?)_{K^H%qzms3g z&}z1@C@!`zjU;7LdLn!laV~58~qUP+}l#gACZ>A!|g@rohIY-Xg$d$=sEnMkwp7 zv@8j&LrIDC{BVDrA3BPV#(8#Ld8bagkAHs@rc-o8a;Ol?EtY)r;^H;w_wyw=i!;3p z*_0AqEVk6iuq}CUBrECa+|}MFWOY0_KQvy?Zi;DQyz8dOMj@e5JsEwxjIUEr@>k!^ z4pkA*oXP+Ry-hBV&FWpM7R%uj9T~Vn&k60e_YE~^*nHoDW~Dj%n><%yzijWvR+QGs zZlX{5MhaUB0VIzu>>qjx#bK;a+kJa?3YM&RKIA1MdbT2VI>h-pHo|Fi|K7)dcLuij zdhbhx_{4ti5hQDg*g*yBtg<@?qhm?@*`RbgNj;jW=6+GTvRlT*dBUpu7*6qBmde@^tW-|UcYa%eFF4abF7 ztwT_2w}w$Qx3m1HAD;R(S1OFqH}iaTpfBDonR`D2%Bo$m_?)UGJX_TKW36IO_$z13 z8-cg=JG`TmY71^Z>ypK|6sTc$WIz!zj4eds{^SspQlhV#)^iWcf)S6fAP9! zo4bf*I;3&+Csey&@5RM^((gT8h|&FYsqoJR1drHKb3Un(%ic8Z?p%Kr7>x}xKO$3~ zG9LbVOV3fwHsRsXE7G{9on77~I)j!IY2HO}-))rh24vQbszp9Sw8r}|C5B3J=XOp6 z>2`Lh91f+~UiI|{jBOtDvcp4YIu1RL+ARJOp01qAw7$u}`G!7P`GLXIJRDZVBB-5E z+f(OUxSjMPklYvg!N-oaCRPjbvW87V6rQQ04buNRE5Y%!d0rJpcEWmAFW7pt%(*PoVVd0nKelaAuSA-DohVD{p| zm1)BGw#aC?#NyQA)xlqh;v3(>ShTW(&y#cdYO=HphE@&$rTbwlliG>EE*|fHE-CqT zol$f{VF)I^c#)7wHNkwb@DX%ef;$H}ToJp)@+2+$+r;q1f!XH`d|CV$0{26t^RWQ@ z!behf@M5}K*cbZA$BxA{LJPv}%6p6C@heh7Pk*ySuY)l~ktY6gTTuTmY4jP&e~Tm* z7`xSwSq}XEq`6JB3nVnx;9YEU&7|ZmD{^eUa%5*pVNn8)u2#;>>R;@bl`2FY~m| zP=oeEk8)j_dC|wv?g4Q9$!pNg&kk1M#U06VU+uJZzs-DRp5X}$s|SDHe%&3(N@6z~ zBn5SWt197^S7QK@qCR#suHIUDP(eaw=9`Se<-zCI4hNfGEDUTWaE-3W<#6w}Zj&0_ z(hW`i&XZOgTW(*=bU!8*W;s}Q&IeaAaTTFz8ORVd|B##(qyH%x_jUqZu6gV!G3veP zuabG;EW&@t2--P=2^?+MD~^+16LWfJ>7CtE&xWAB;bI~zsB>HLz}&2?cA3FYYhioX z{)-D{((ehKBcuENM(;|-_<$2T=yLsW%8Q#hxvez=K8?Nyk&{9EA2JA!2lK_%aWX z-nYZE5cqUJfYc#`SBO*S@09z*zykQOL;^6D ziQazGg5bE)O?Ec{$9CIS2etCQQFEE()EIsF=R%w~!I7esLVYU0h(B-b2+@BpU1om3}byDLFlc z=cU-+!;qA4?i)~^eH9ZCGjRCfy%_5P9UgI;G^OmITdNx+-}A;I=gaiIkF$$qyE@;gGlys&m{z5$_YQp;K$c%lAiQ$$ z^?b})kV}lSxfVt z;3=4~>lalw%anCmuTnN1Ij_;fF#kk9P?)nV5UsoI*Hq!EJkUXpH!)rbciDc(B)t3L z;=P5l@;)}K?tv?d0>TS4a^xv-;gDCkwddyic*o7aZ#+Fzt-X(!_6h3ghH3SLHZdt=o6bibyXUjtHrj*k*kRzR%cKta-Y)R!&?v z8Z)NFwLP0%rGh0AMJ|5Nj=)?RH0QGgV!H_LNZz_yJTSF9$WGFCTNu?8_SOHe&H4(g zP=|a4evp^!rI$Y+Gl#B`(>`xn7;@ZUD!?yN5BND^A9Or=+|UI%ZV{oX+3q#0o5}8D zt2IM9O3Nk3d_=UWncdY znhPffuJYw)y6S8q7B$@HdeXUB&$WD@4w-FhQ3>U`=}70hV<{qMrZad<5=nV1Ng{RX z+u0)d_z+G$|DA-`i2l*zdtJ>yA!iN9&PW_0vja*zzKLL0e<|2|hPv8BR`5{fGZ@bh`4$EvRV#qr&9l@UOh+14z%)C<*42Qhto6$S% z&WFn+l{@2suI`<1)}Iw%dSZd!ZCi`CE7#RUINu}GR!^+jC_3UuFz=BQwjWvX2diO; zgptcTLwi0tTcGBbUc1ltOouRlP;0^P3$RI&$D!|253HsTxF@}9EF2LkgRO#xs6VmQ z4|Aytsw_ZG)XAM4UpK>2$|ZEKApj0}#wVdbPpUr-Leu11Jfd_ly7F>%D8tt0PPLj4 zOQupuX71;C1pc^fEla0Zhon=!`-7QBx7667{NA)hPZ(9*#ZP5Ybu5vui65OWdZgqn zQ0z-C?(+$BFy54*7$W$^@P=${V|{nPZci=(geBxjFVyM&H7|&aY8dY6)>{J~hT@_x zC#AK39Fd71!k5$|^hS>tyQGd=c=~r-r{aZJ$5!S>PKR-$oey4IU|TqA?^D81dT&`2 z=E1G*#e@wG3$H=zQN?+eqxoKbHVwbwVaahPsg=+Va;3zL21neU)5+xu3Hspnn9=|} zq}b_?(H$ovQW#2Di9Cn9>Z$`2Gj2WjUYj3v%;*E((tdGaq!hf8lHYl6^jNvm{J3QT z?Xa2MLli!=GLZ*4s5DeR#fK2W>Vz1woKEOC?)?}Tr)qRPlrDF(l#bkO)zooh_R-!fKeZ1vvmkalHoAjrL zOBHM4(Y|iy(UOz}>MSFuDXmU*vs|LkSy?nr!bUtSqNO{zXGg^ z{ehSdYRO8FJTu0NB-wC3L|5OErUgoMNh|v(1~cSf&{7|GbTP4Tb}sXV3w`q-H?vJ< z2~^p%NK8Hvsd`@xIg`M%d*qr7hp^N%8#EYyqFJ0lHxvo`&b{B>5f#pI5)l)ASOKvn zAE=9A3yhPq+l;VZzo=v<`2=eEI;IH#{&_r+totbYz(Sfx@_A?8$;Blh4VWkDp> zNkmfkQN`~*+#3C&;ZI-zk!HkM+S1m!xamvc&WlF`V!EYGwlfEOdut(0^uoxB$A?!$`sF@)|OBFBBg z@Lp7a9?asnP1v_8#Yse_G2N+241xuK?-=rE!mDX4b|>L!&NhXVsi;OH*mZ)kc&o6_ z=xMYzaNJ34??^*ZoWf~E9%#L;yaBD$&G%Vk;OKFGMm{yO01iup z;{7%x_QHhC!#tK{J9wuCuAyZNYKqu>IP5QzT{$P_hTWo6wpE6ZOw8*ex9cdY)dlaqsKFe)H(Zr5Wyd1bj9?kQ)EWaP(DFJ-b0zF#F~ ztI1wj+o8H9@^oE(WKD3RSuCTNnpa@k^QbO3&y2%88KTygwdsk4{OB_Rjh8ivoH{3K zZd0U{#1%N6uKb`q_@$VxBb+h{wg9pX&mSy)Pw|dF^1-N2oiiL^q#gZiDd_SoK!li>6vMsE4#{OsMER+V3~@upe_4rJ!7L1#zRz{a#H;~e%GheE-hzqi5+m2Eri6DM{S`NugC1=vvr=cQ>$OIG z!AhEF8b4+9P&2EEKu3M0tkTNy8a7Kv*o>^2A|6Imvz#<1aST-Aa$W2c!O1(oUf%V# z?7dgHdJ3Tl&_G+C)q1VK*>|@$ae|u_3iipicik=Jsaonr{s<2A(lK>*0Q|_R9Qp+m z{RoIHw&*RazyPN6|RqyY%D@d~8Z~@LQWc@k1dj`*R3g%v!jQ5=r^WpdoEPDZ62jgN@ ztlW0N>GgF+dRz(5Kgs~N1I;&Wp5NsQ#m+-6ik&v7tUcRBkcX0U12 z<9X7Cmz2g`r~i!!_gSJxDgYJIlspY(o)3=WcUVc! zo~BA;nptE#%mi8RM9VZ%(|j~fQT?*H&l3yQF+c=cQEzriFD<`o7r>gBSPnMd)qlC^ zK%6(-165pZ_M$XXlhz(PNGq?i?ySw~6os%cdRDWZy;1t~>5#`epGbE+t#BSlzF939 zF>CZRbg*YhRdjb1&-3(a`KDz)zp9s`RYSqWGIc!<&J~skH^Ym~BOY%{VqLY2!W~<} z^RXGWp^>8E9L(aVi3eS!m%E#o7d8o%8~zxr-7z~$VlGsqiLr50MnY3LO?<;@;-Y6+ zg~F!Lfp9+dO$<-9lWOeCpF5FDkbRt^KaTrZ4VN^;vnqC`O{DO=R?FlPFEo!QRudG% z^c6>f)vE+xYwhCd0y*ti1VCH&PV9R8BGE>3g3Z6cLLI}bA)xE52gd2Plewu!QUjMP8 z*~Djue}#|JpAT@)awZ3GPZHeY2D{;Y9L2T&<}BXrjep3~`=$#7lCk5HX`xiZCMN>& zO``$30p>P(h9=R-PCP);T$!x-<2Tp@At%=3QN^P^wnpC6ykuUrE@w6U7o*-C%NblCY$>k9qX@Wjr%hzh1^8}8&g(lju>i~tHb`_Uw_wkNCGrH=Rbc$>yEU_t9leb zGlqCOd%D{NZ9Zcmu_AUA%_$7#=;@kU(!cDh0dAOuly-#Y%k#*HY=^FCQb;c~6;_(c{_nof zB0+gF^hOj2&x6MD#e`^^GUq4co5ilC3>kp@*x+fcsx~RW_$nTc*R!RIdUaks(AZ12S`VR9&Xt5}zRRY(#qrx6%=$M9ypmTcEm7PJ#1DpJOok$4F8L#0TFU%GE zc(Ij-Esm!ws%&*pJJcNzl$-JP8!E>05t~rMc6*-65&ipBUhG-JeHHPACfl&>Uj>i2 z3XAN-&&QS*L)$Kr;>3(7HL0=G3&U0^>YVUEhoY>mB%Ubqyr(V)>g$$SVc2V zn$N3>Q1;^IM=MW5{4Vo)UzGjl@#`1tVBn`f(dmGRxX;ezBLoa-(b_9|najn-JclGrN66MrEzFn*# z6WC<)PH3-Yj?>m%4mz|PrYC)LRmTy~`K3$+zeu|dI^@-D+n$)`H126muJSl*{%0pp ziTZjWS!clt-l6YuZN(J|I&TG)arPu6v<85B{UZ z!5X}wre5>%^3yScgyLuY6?{!8HNFCYq_II>q<~=-9^t@{jjREX{didazWPcXbIENV z)7hjCyf5R$j0n$04RAJ4G3|UVJq276n1ll(HnPUo3x@QIs#I07J?~6+$67R&=riZp zTvz7gHSn5(qwyOJDZ*Eo)|B>gx#vTJ&DqQn+ zqG@_OsK$kGI0h5X&Wp9ZAuU?J2CW$YEtzlYkA7iT<;IS+dL{TG?y|Y5MYZUo{y9`G zDBdXDL$RA^;~q<@Hq(8bV2B^;ar%85-zz1b0vfWrd@CNyX zT2Uu#smh$C^m~hC7fi%VxZ4(2dG+&$@#Q=h74Xvya};o1w7C@DeZ>&_z~jbZg_oET zcNWZ6@TWdBmZ`Hh_IXFTKi0`*5%CyhN$~38ujkEi3H0B*2Uv6QBe3!`TMs5eql(PS z_pIOg4{GWOg((@`NUITQ{EQ~d7&o%GljoRmwtgoy6*Y=h)jl5kVaZ0C44Yj``SJ>f zxURP#qE1m6sK30+*kDep>QB(&=AH;A_R|hP{yav(4M8xj*uwma{zb<|t|x)2ep~>X zY$GlC}ja$B8XT?w3>RAg-p+Tc0q^@sJ*^^L38> z=b`03K@(=xlg3{`)nxR*o~!sZ&+Zmn49vF>T0QHQGHe^`m3~CR zaawpVZi2Ay5^YQ1)Oi%QHxoK?NZf4b7Nd9cB~t*Rqto~&8pdyNy}K7q$>3|J#6I$u zUJ*@Oss)n`OWwsh=7o+FN-F4r%kptna+P}V);89~tri5Y7*M!&N2bl^!eATmbL2hY zx7bvU09b7M;VG4NF2%S_PE$oGzl57K(#@6FgZwvXu9d|MDC-@0EVlO;;23nTDPK4NAqgH?@3iv)eqrEdb-aJA<|{Jq zHVLi_R$yf|TAlivMiVTP3@<75Xv#x+3e9a=vzW3BA}wv}h3s_I01MYSSRXvduL2gf zdecg1F5TTx{(4nbNNr7Zbtqx}Lj)FZqE$bU)O58bHYC7ly>&kAUc>S8>ZOZKh_-R_ z!W;F`a6#D^QralD85T9wJZ6PM;L8U6DNFZ4a6l`g2<)}xr^OVr$2bV3mAlUVgdFz= zJZy8>G$>YrlIbqH-lnT5LF?KWWxVNgibPV!oioL<%n%`FRJT~u2M*0iJvv*=ghE)l`G51hCY2Pc zO04;nWZ;L>9If`r!b{C=mC4z{5O3>bgJ;e}*B9&<$3*%LBZ^Q0k#Wa4m@v`liSJGg z3s}v|G94I#?`;zEhB@v zZI#AD3ukw6`r=tFx_66I=~fO7@TNPlZW`>z76*p%McLDi$w1-SO&0}-ZO^b$hL zq&q}RA08&J@#oKi9tkwK*RnT5c=N-_pUI}B8cwu|G$$Dt<2BzC)nO!13#dsm?Xq7| zPS3NWa1Q>Fe&2b@xW`hG!XWYLaUcI%-q$~6#7-ElcM78NHg&BYrMcNDa<$7;0xb2S!+$AQcT#pda&3 zyG9z7qvL2|!}ZTHo12#Wf!;5x2Z7Kjw)gX(Zi>;T5z`$r9g z^7r%sa!YwKV;aX&tvmTkW0EA|Xp<0A962;tI>+^Rp})lL+n;%2Rzhq`c7G<)PkPjr zAr{hxK#9t#_T7^9r=dw(F$kGRE(SNKzctQHPcOY!)v8Asu6tsOFj#t&zG6oP=pz5V ze4O!F&R8&u?|Sx9yy>(iTmM+Hn}v{y7Z4E?$S!%AHLS5nm1Iu z#Dnuh19WC^aDpn89WP%6K+jIq?$PVWa!WboK-msuC6p#nWx}SGOEQeyzd(LofHaX1bLtbr$1j$GPJQ!23?5@q_^C#M=gFvmr9R7l5>s`XnJl~0RFhXc* zI0|fDx@5HuCSi&kuN&MG#~f>>*Sio4mOZLC!f|e_ga2=&FIFNdw#zM@btI^+4O`2b zel`p_IDhgGJT}Pfpszc;)li`C&iDGKIKY+ZAvVC3{QUtpn_RPy`oogsBd~RDAz9tT zp8K{!&HJIACBm}ioc@Xx>(a8AKi1PoZh@6z8jHel?nIBS0ZX}t-hebb^EK`_*Pj0N z(gnj;TG#L}PzW>8=~xV2t2{1$?v}LImUTHB-%XzQK z{c68J?Yt#VTf&hY@#}(XpMT0~)RG? z&lDiUp|*&I&|pPt*vs@TqV%8kc)$>CzAwL@blEK@sWzLPTsdC>#Wi=E$D#@nPD`C` zxt;`R!GB1ISj8j6ynEmgF7x!R=_P^mtdZ!twjcv<_x=G_>xEEp zcXT0W%~N*q1W%wpAWfXpVXG=s84%^pOP5MNX#yjuF>Uq2%c9)M)QvcytO-s;(FJH9 z_iXm{<{5$37MyGh)W^{dDG4B2^?SFUb(#7omqEBxT_-dD?(wL`uqK3p&qZb-UDW9 z;tLgM-C*@LHK=|j8Z)kOIOo%coZuGbFdMJ;j8T70D%KuF6HiSHGCAdHK#d!Iz9QY@T!lWz+Ryu#6Rp(!jaC|e@yrOK)(%xH}jNv z8$(;bTnb3|%OLB)biDP2Kv)R92$^wG<4rw+nl9Ft`odeghs*FROUg@-Xl6k`8vko8 zIk6Lt>x1IDGmGy9@D51hsp~HAL$~|0Pc`mxLgg? z#1Y^UlF21jHI<__UmB@Br>^9G#&|aKW;3_J3hLnEk`zX0mBxL z?lju3QygC(KztF;u)J@NG?nNlJw9~+*;lcTa9<@kHaTO8LxDTQoH845qyyU2qy)4{ zGCe+BYztL~6=R+V?)khQp;)4eW>~^YFW`s(tn$&Do?>9q-LqLFHmMl2<9KjMHKx5F zHk8fj;B_;;fr{F%E9x%T#s=%cKA>tR;Ey0vbBDji8H^auMqY0|29AN3QGceMj)Wzi z?$og*7J+uOU{^FE#)VG=UY}o!%EW`@7Vawm?hxqNGJ&doa*?MlauZr7%+>UMNM)b$ ztmpNnAaD|hXGnNE`qv6sLOkSYKnJq)9>6bz5qrMYk`+54{wFE#lB3#t#r)0zPo_OM z^Lk)7dXp;JD2rDAvW4j50)<0LSLg-kyJPa|O=*E$(HQzQVhtOPu)Yq+xK-Uixmp$Z zGfz3df5d3^+tRRY8NBN`-BF~$#Dr%0T$Yv9t8G~Ut_|{8kzOHX{R+Swe)%xDac}1= zAbcwGavPq-(!+msY&HIUQgn!vwASlppaTvR`<;pP*6g%p00Wko4N7(%-XO@#+SJXC zTwl@$P!G95J=-p%$#&kDxKckKL^{-XJeaGQuZt9R{miH$OW(F60%-H)jW$KZNl=JnDzEX+nU(8hSJ@Ph-yf-h#)k(>nNEaP z`%CVI|B0tDbe?V~IQTOF3!R&@?;;B~$$WTy*BiEEL6eNdumLxyhXjINzcaZFSlVsG zIXY$Rauh)ZBA-4tJvT6>XfFS#BWR~^NXtM&icA-%=58LSHYs_Ua#9g0A1y5bLyQHa zDWwq{x00%P8H&GBb0(N+?aRda63VR38SU{7m!q4%c>nZTB(Aiqlzgul$Drl?_u3P$ zeXKj76GVM|o5t&8R%(5{S>F#x;8nA|%#7d@CdM(U$o}-(K+nm)ftpKVcGZgGuGf?P zqxWh;waZdUj*6E9e>kcAwWpm;>>0eTub9HG%DV_8G)%{a2r_lH&AisU*LoO+h(-h5k(mS8I5iOTmJ?UApZpt{|o#m z{IUaRCik`(=)bP#{xzeVc-zb&f#!!Wo^F1meU%1*)b0!sF>v+xu@UaOs%UsKXl89$ z#qqBnR$i9HC4Tu;$I*z{G!nS^omxmL-n9?dG?? zJ(x8@5+uJ|bG`PjYt-MaD-sK+fj4YPuD9?AxA)PM0u&M){ln4cAC97GQOW?|cW(fv ze7)#Y@bp@_x&wceo3!>PU-kBrS3X#`Vj%HQC)g!SF1R#*?p7J&}?SK5om|g zA^RYQ-Bbf1ZUg3zefbS|FkXAQ&%g)xi}`jWHgj6rgMofXYdKv0id-z|FWn4hA&KVS z9o2wKFhF+>Y1P4X=Ro8?h~)o8l4#2I16bzYV(Ah(%~zmt?J&)M7#04*NLHBM6u33W z-yZOZq0{_6H<45SBFq0qo+lQ(SOs7oyM_HvJBa0DLC$yo9rAx5>HGz$@P&Q^KVWa1 z8+(V>+iDjBxM!y3xBkWba`P|lY@J$mMF2?Gr^~BmF`JojmA0Ty=4<`Se+A6y#0tB4 z+Sb~qWoUZQ8hf+(MP(ZZp?$Nt;PvKAyZ4!H21{c`P(Mc=i)9TkHeCZ*Jiy8+`O^}y zRbphrH6?}w=7@sNtN;FMm#+hROvvE>aQ=V&c{1}KOrzuH`h?O}aRUTdt3C%w&#iQs zHBW%%i8z#OTMEry=w~{SmR1que~Mj;AFnCrRbsc-BQc$8)C-K?c_Q z`-P^IyPNR=`*dP*P`itfgxI)*km_3Z@PPsH-wEH*AnPwBF?)2&N`11A5iG9JcGJDG zkMa8d$aV{Ha^>1VVFRK@vvKI$00@>U7xnLVr0=FdFpIVK20P|HKa+6yD)^WtP?TB8iym) zh_r>fXYUbd2dKwgsD2 znLwjVf#cZZG^L=>$OrfHqs@u_wcVncF5f<|h%U0j%jIbTO>1?g^TnX^<=6TyGRbFs z8V5ZOSLh7mHb5@X`%M5e<5KlfHKSW=xIp0`4jy*FH~>6%GvP+gbI|GGCwYj{&?{8u z=a2D!s55!(e?Oa6vT|`q^pR|nAjc+OP}-tId_f7jwO>P%4IVSv+*8WVB%sG+ShoF{ z2`=I`EmP~goaX`s?2b` zPT{wSChP0*D|930h?=GE^c$A;d2>hY+Td9uXAf6&6Z&dh*-0iV@VGY_Q&0b(siRkR zmWe7No{rnzzw2HTagkjJ@c5tG7|Xv#>;+DJUmzGF=wWQyS0loKkib5RH-Z_ioNozPH~yzVdWYvMtxD z@6q{#$jaQ$`DTCb?wTF!Ef=x!Jf1UO<#CPP+WSJ`*fzD8SuY=>Wi=JofO%N%!YSk~ za^CYK){Ej68$sL{;d6jIn~KbAC=XA(VltWOGb>np!n3)(-l#dU@OfG2rJ-F?n!0nD zz$fFMlfAgvxaN@FA{vQ(I>Xgu`|)X()v3PBx3X4t|26*{0Kh<447WS*EXrEB!FN9s z&t}Ys9qjqlyN%|$^UThYQXS-QWNZOK@rdyV@L_55m$YZ5Y)BL`J?(tK+P2Ibutqd} zqL^9}=qZmhwf+()nS^`mBJ&9=Z2;uQ+8-+=i+AakZM(yIzRVhZ8K3&VXGsZ;64L8- zteTg7JiTFja(JgcaDHB3Wl{R1ZoqN=X%)A+hDx64ANN7!YHQC*VDvWY8f@pQNcu`*8s&ZM&f zTQ6uwej8jxnJ>KY>f*GGYcl%D+pGUu>GVR}>JhZbYCCfKLY$mf*o#22YO*ohYL!j< zq+Um9R1#O=PPZBj=mBAz{H`%m1+MF(pH`m}r zO;(7TADkSjZL%$w8*N{?O9(owrer#G5F7qD-Is~(<*!C0z8HB`$DL}taVMT``A5pu zns94^5%SJ*0UPgy1C?)0^2Z9*% zYxJ%5)^@jqK9`8;bmwCQ2zUU8csU*$WPxM$&GcDp5~r z{lJrLAa9gLjq7SXgMo%~Io5S11HJ0)tI{f2__@|cqbk^})JhDeon(JjSt1Hb(&H^y zp_^1?C=*rliN+F8@c8+hz?v6W9zLU}GFfTg(|yFTK`~o$*E9RrPqwatj)Flv!TG2P zkMivqX&sMO^LH?W;R$OWFwR8D2hsfV?aW!06)DrU=x zZ^QW$>IgGs4NQk?9Ti8;;m@+pT}>1_oOHD+IGN9D7Z!DEiJZ1{T-2kpwzaA@Cj%w& zbHt~eC?09AOA!POn!wL2-*2rf;NyZ~!WR+dPi!u!sQxWol+Y zELF4*`mh;cEEb5MhsE#;>5i}pPQS2vh*v`81BiIubV@Ub>lyB~SaS8V3;KZrbr%88G~ z<^Rs9KYFyhhsjHcx-wV7@r&0Ct)I>n2!DfP2qdkYxS(c>@D?iCtXrRVLfIoYUHG`+ zAie4MX~U4<@H^jPXP%=d2IAu+&7;-H22bqH5z@WU5$J8J_vqD?=O6DDlCa zm1V-p9@G18wj@D|v`{y{Xz&w9-+d9InI}WY7oL+FNRJKFt0Q;K_;YrA$2o1!-_I4G zh6~>`b+#`g5Hw>;)SI+mq0kWxvP*J|G@|Q;+#by<11$i z=(y{o{5Pfllf>=#-ID+b zmsTIXWZx@6uDgRj~^D|;p~!iwYR&-Le&?}RgMR&z$f(tphF9{gyk-+7OlZAS_HD=S)<&pZ*!|@FL<4bh+iz*0 z#7*C`8D|4t+l^1P@^pH6=R&X9)@vis>8s16z)IKt&R-t=RFW4)t4BElmxc8iNBWw* z9sgx)0^vl~7PsLGhh4vAmm8_R#~R7a)XL0!SP9KBjI6w13sQ_iy$Jy;+ANIzaDXz; zj2;3&4LfFDUf`XHkkec1(pkSez}Rm(IhNY#C~53k5{-=@b8iYL6(B~@^qo=Jqj$;u z>VL0cAImLf5iX&cb3yFgQ`4}Vzx&%6gsqDOkpWoW5WuQNvI zZ@REz)zr}^?Gs9;r?-U?1$OIc38j_%&824d0v!;lO1kgGdNBMs-7na%>6IR-RfUbc zFgiO`Ugh`j?@(HiSLQg><{2f= zA%$i3IU(Fq{3lh5ZHOv^?LNZf7DLzP*36fb?cyu)SPPDKwJso;+GLk&mFT4@2t0&+hyvECVm)V2X zRdkvB-O&kT+HXGR=VDihE(Won{KaodAWtM(x26-#up+g<*z-uyR%O*We)FCIA6@eB z3|0FTP|m8<0$nAN-DK&2*`xPTx%*KM*WQn1znpQLmZi0nIoGpUa9zsw0}r5w#s4dG z3&pVPxBT<8+s?ZSBX>JG5xv-dNkWo`;+I89YPlHH&_TYeoaWV-&jX9x=I~nk9Q8Dc z0;zbZ;`W0c3uM65Bhk@`C|NX97utL=%a1t5a$$9}ROB%aOMQvXQ>rr&Kj81+5QQ`9 z9lm#yItl(4Y=+SC?uelYQIOQr+bEIjb75Kj=$R8^S6+iR|7|&RYdngGr;3ib zE(jO8Dt;v&-Tw-DF9jLhb={l2HBgMKwg??9TDns5(=@fy`K4e1g#jFHD+KqxfKn$h zE?O=~BTq^yQ<3S5T1HEwja2>#m5>ktw7c$VSSvlrnTTON@dpFR2&X3wr~PO>LxOhh z_!*BO5}*efG}9o-$ywBA{r+4}pc`33IgE*(=dYO_ImvunApZqo7Dz%*@2RX_;iHUl zu8uh*KaD^VxsxC@5WD~8Ty37$8SNi5An$D@G#;ZfkSK%dnnCn95^>&RDU9{SG~&Xj zlu1RP$#r^jRWB^ScIgUVaQ&bmWUIurwS9cj#eBrP<7gUF?o5AlHW=V+t-9>Eocc_} zB7wQGty?y_&;$}!Eg6qy;eR<_Ly>)9=e>sC7mWa3`>GH%L>|{j;dvn+IL*9qTU?MR z906Z=Y{c--;aM6s9(yLDz6DZsHG-q4%ycqxsnW~1@;qlHyfR#=)9HWjb=i{@qrOcf zZvOy}lNs;C!rF$AiYpNnlmbSl^sRbiB&A25gU??%?ojg+bso#cG!O|NUq$=vpuJgK$k5y8qN^B8{eyHGL z^7h}t#tF6EqMFnTFj zAc#5BqyN>U**EDE;fNDc$ou;#X5obR#4f3(qq#MfG zr4o+3I#6v&&`DEu6W0!$4N_&1;?p~lJQxJrP}QeEEopoT*~Jb@_)=VoR#x_>jZq5r zuAwZ7s2AILSQa9zTTZyR-MH%k`G7dP#VNPJ#HeWQwc~Ht(B9w5?oU}GHFh3woav>PXc zj(xee5Z?v)mdjnv9PcyuYW})o@3P4#tj`V~u9iICOTko15PHgbaVtJWSYQuZi3n{; z!0`>H)KOFP*r1h_k)JQgTc`rwKucPE2{X`!eT*}{4ikjafy*L|gbc5beEKu-_EAQ* z*9{@^UhZLY1im09KaJnd;}Qc?*S2mX?j?)vPu{kUYMU@(N@Ii846@cfuhsrdjLb?= zS4vD7!z^wU!3?Z^DhkO&Ytc#7GaM34h&=ecI|dmUbZ{OZz7G(iH0FzLm;FK@Ll~|V}wm(sUd*MDK6!7t?PZRfb{kCZgcu{{cyQ{ zaOG$c<$YFtmsG%Tf*(@)_+WZ-tb-O!Q>&aOiUIO@cV93)7200yJY7o1i7dGz)5d5* zbVa9gLP>o{#kRFv=mn5uqfw}^TdVA#42Q6aq|C2pmnKGYpIK7X8+Xv6t$2!+Cf-5C z7UZl`T2RY#<6UktbZzMtXy51=UldeK)JsKAMQ?~$Hc6_;p4S{aNVv_3C0>dvtU0vh za5+9fSU?d_91o4mjW}26E_!a7bT`P}O7}&3Eq1o9Q%cAnlusfabl3Nzjf1@f z+B?i`K8lIuVA~B2S+QN#^u=lhv_5o&R1r89b^EM1 zGebR2h(y!158&ttV@ly#rk5q^S$8`px0*8$?0bV+Yv{)R!;YQ;@;* z_O3aF$n6*zhP&9Ubnt&}7A7S<;oNe_-d@13ZrXu9gNd?eiE4vRs$nnkE9hO>W`cLV z2^=2;hfx2@$tZ(|KNU+3^ZVgs^e41qtnIVE@4K8pyTvA^b@9*zd`KtHwhxha@k;fH zgJr6pTy?%|j1yrz!NyRbi<(5Jq5`9`)vm(k%D44JcgcZ|I)STy zggzLDSrHA4=wkCYw;bDPw+0QUI0~8du4M*B z3nVv7Xsa_?P*ZbkwKej)86I&L4qoWW6LUcGNAPBjEr?k{jD&$I`0SfVe*+(DSA40U z^vJWM*27GuC^dI^>>*FD$(A5qAH0HF?+qO6THw(ZSt{Yw#r@;ToP}g?N+D?$|6ddc6OH&q9 zA*Fk$PRlSmjCMzkvf48q4rK3{2VV%ZW<7i>gT|S6m{VMXGYoYdewpfxm7o%&7+KXOB+yS^L@w{OZ;&laKC1k(0Kr0{PpRGNR6Q{%*>x zg7s>VF<_(1QBvy*`*+5KEL@0~Uedcb;+&j6Y&-3=A4%;g=bXwq6s)}9m>OS^P6t{w z!}V*QDLI_M^JU>{heCqXDsu#Os;L&#tiJ&2e_ z1L!EH(wfF2!QWKD%6;R< z0@AN6>V>X@LWHoxMa)|q>6CeG688Qt=Ypnv%lTeXrnWIZHS`~)aWYy}&$wk~Lcw9q zeK)1>7IVIaM#nCF&%n5QQ`1p16T`kBBn?Pk%}tY1c;u`CmAWRk zyq@~wo?zNqKB9|lUq1KRY;@HAq#B2?6WF&7Fpvz1k0Zijq-JM9+gRJa(1G{n_%Q^# zBNTPX1^QD1zvM7T$e(ony@i_yV)0H{sx@*h%}rD$XP3!t=#t7CczPzpR_tO5ytb%d zf0-RQgPeU%v2JaIzR{}ZKQ!G>ey{8wU2LEah4646_;g`D?Nr-9{rutee7d&kP$CFg zUnK!z-CsO!{%4u2FM5!DDzBl9YhnLGaQaV^U=zL-GDWjYfxO}#5BHaR@T|v8pgVB1 zyZKe{B4)!-)nZ`kmwU2#;Ww9y$OEq!dt3_It?8=o+iz+O__p+)PjQsx5N`b^Au1H_ zw~}kK-W-$YQR|_u!%Gl#+}5{cB91k0;bSNy6(B1(Y)QBR)n18UL|aQwF~f0_qJqVv zswm5rWDA-*hIjT^fqsd(&FSm-`!#qojLnBhH|w4~9RyyUwh7 zZq(~f^SBPOjaZhZDJ?4S2U!cqh&mu=T;Y+?nZ}~S7A-@~_jH?>1awftx7i1JJMZ5~ zau8Ss2}0p8T$C(zLbzxCK+htk6kmSpwvb(>RWgJ=&x$nIY69h6TKKXMH0D zkQeb7Y6|T&iF^yB0Zw;r=#=l}HaR~9AFVFYa0{udoPC@{pahAi#E;$H7ZR@()Zh&@ z!m>sn@1Vo(UPY;(z{ArMzC7*()xdr3{v5xU>sBn&PpDG-pX`Ti5O#2Rz@&E5fQug$ zx;dt!-9?3NT`XbTTfotI-gN;lX>WO%g7zb02i}|A{5FK?h%%a5)!XOf+;5IO+OTs$ zjquRs`23Ae5BAACsnXwBRx-2p!^n0}hB}W!X2kVgO&4srgq#P4np!Q7w?VQ2Y?Ri# zc+F^FPfC+x`)2Hgd8*61jW5QU)h3G=`KYi}K2fKaB~Pn4r}3ce7w)uUWyxtmwHbR&Z6`#XpIhXfSWcd6~Z%#WbWf>J*n@w#eDQ&VU<8L|w!HhZjJ$bM`r z7uM>Rk6j2Bl+%Q4o|#g$S0xTqgyS;i&h1pl&l;Fni|IF^zAzV!8+UV-gh+@tr& zA3}TUAWUvDl2dG3cJJ+`b6r5c}^LVApR7czC^gfd^ z;nuk;iHUkIG3`W1i}e&-uDPj9&s*2ly)#-9QR%`{q=25B4`jtv33=2o$*1`pR1Dq4_Wk{Enb7+2)&pQLc1Jv zFA-`8U$u%Mj_h4?w}mCs{nlRWvO_}U0&FZGzx;#k_a>vfXfbnE$gVBTo)6=B0w2@$ zW0&wA944Ov>tyd z6pjlRf+Fy%i{3PYo}MZmeKT8Tv%beTNn6@AR(>>LcK#UiBBe6D-_5qRj?@orAwAtB z{q->JKVaXjqHyD?s^@yGTk-2J9uT{A8;7~>1>Hjq;C2zK44QRk>e?c1uEa8>juk}N zZyPMdD|hot9oh|1ZkK-ll2i9fGu)bdVF+4~ouBZSrM_ZYM53x$r*ybJRII`FCuaHB zlzmHUJUqOS`jLFZ^*h@21J4%cNXu*{yGc#%Lw!5dk^}W-@QmRGVMg{1yg8ji0F6|E z(H(PCw!qriGhiw@lgenTVnM5QOYx~$A`EEb3c~+2Pnh+4b@6naIR(=7bUVWmm#p>O zO1v%%sc^@sH=)+FhzskrBeZ{T&ac*P@ank>wTIWS$3A4vi!gFOj8qdRW3aQhGDeJX z&kG22LUXj@v)z196QZ;}L*g?$vbd~j9{(?md-CscpiUD;c>Newy5l|Gd|E)*)NIou z*jDO;;A5=R*SX+E66O2$slQ*O*d&D0$M*N|%FQlq8`fQiE^oF;GY^|I3d@{}J}QW) za3Mlt-EKyI3?M&JKSsoPjNQHbbgML}`B;%WzCg({;CnOzB)+mO?+(vxr0z}D^u+b@ z!X|!sh0y_BZ7GHV5$XkvdSzpU(M{5h-?OV&h$(1hf>?MMM@EDzl4{Vb-MYtoP_1J+ zt@s`B3FPb!#}ZGK`y3A`#@6s4uP$$eW}B-Qmycin@H;srF8%oHUHisK%cxe`K@e?F zd&N#+)MxM2+E1W|v-J4vm-zBm<)Y;Hy2Y&|WTJA|G-N$*I&Ro%bMpSmO~&%*u(8H+ zcEDz7Bi1V0v%fVRwxbAUw1V)#s>su#6rrN_+R9{6z!1gneRq49Myr65WJoL*72GVy zt|wLr3o5J%t=vWVDWc$H?|VD~itr`MgDD_?H?6Vl-e6pj-0n+V*qJmG+{@9I7 z1b;Z#4IvPSIN|Sumv-D$q~576n2c8n0aK`*3nYW;4piaEDP@<0jr`>5^8^@j=m0VA z_-{%M;YV?n9%=@GMb~XbcI0kh%}%b+>~D z5bKi?9C25TK|#9U1!o5m4c2Uefu8Y!p7AeB!C0kNg>N*IGVOo|2(?7x z6xngfdj`J_p6R($#F|-BKbL>cF#dB!UhdLYs=4G{M5T-~BMtTyts|Wgq`0bbFknD5 zK|#-Yx5XF72*C(3VYi9n30twNbu1Xh&1!rf05)3oZB>(TSZ0bAm_vEmh~1vSj}a%V zlVO;PQhcvc_{G7EZ?+6f^jxcAi0g2m@qeQ{W*^My1cF1k;;Bq(Ygq?ILpCI%+mx|~Dcz-@FgX9m6#ZN&f&0cc#y z!=b^=x>>SI;|?F=WRVJi4RPAb_?R5HWxjfRY&BSQP?;4HZHf9$q*K2;XL9w{dGXC) zPSd0VgAKb^)OX4EWZdq3Y`mJ*LuhN+1XhUZmpk2t8j$h-ux- zwQp-)J#zBzCoM_;*MsUTHkP?kD&mZ`>Q`t=Qn7H(R$wWx!|!mV6%T_QhQ~<4nFK{us9T^SAaTZUypc0M-hqCw& zJb1H$n_ekaVBKa5@U-J4eL-nI2@sh=P{yAh)=~S3v1IbEfQ~N#bDuO1@cUuGeXyA$ zfl7H32`OH_xWs?1GP2E5uXtnJdvNU;UPQLz$cmw}!m ze|_lC~KvAtYEY zlmQnvx^!_8fr5*(59nxG(v*QeERc^36}2P^6_D^PCZl;D=re8;eTNbPcwS&hQ zKXwmkj}yv0ipug`9ys4Cq{)30LZ;F9T2F<8Zmq)}jU= zh`UgbeY@+UUO?7N;!suqhr)Rq4$kT$aeg{IX0lYti{t;zpRNO51UzW&M7qP$2nSwd z-+k>ePKCtTZmvs4n_gBSbHbK}C4Gp-^maIs>;TXxzKyth&HbCtVvfKHHi77y8Rr}o zz`XY$7zFVB3#><|H8$ex_ND{|uzb0_AvA7^pu&N8F0an%yJIIg^x9d1rZxKqs7D?M%vV>d6x3hm-gR!`97JW|<1)GA+2Wn60bOpi_@;UPk1 zRM@bE2{R518rwB4x)5v5oWBbjD#GUC%254!meX(19q@G`Q0iC9ChR|1pDQigB{c&J zJWjhQk2{9#&epeVdb1CPK}=~_&|LmytvI-qD;e+pT+>`|m`~@BIQ=jgo1q`BgDI7V z*#5Ui&%CKzJ}W`}F22a4H~Tti852I1O_^45^z1@F0Z93SQ*baIV&IDr(-yYM!7}Gx zJl}LQ!9fc_-S7@yK;FY7HROlIYO1MH{Nj|;CSzQw8;`Z#HYq;X~4ZNHi z7x=(22T`=*7~=$Gx;G8N_dl)olF+=qM^xkDm){r?y|hbP^A2VDu&da#+HHgeZz|L} z_r3eV+OnLMo@N*Dwy(c$950b+j)w|O-R7jTbNk+9Ck>b|Y}|S3LJ-9Z+ruGru*6JW zn*bI!6+;z*+51WL&o!a;q%{&yn;~MVd(#h4#XL-uTbl7mG@`fe%T8X5E(af3toijC zCk$qhVKDmSQp*Xt%eT3BDL*~rW-w?QLkw_+Sm80MeB|9>p z1FC})0|asX^;S`i(|dgEaTZh;P67E+Jv={Q&%AFOkSA?7lfU}4Z&g(4!$%ZDj0t`KeXT`j3J@@9Ey=%R%dkO5N1%O7zED$wbj2D6CUz zvfQ_Ssbo0WB!sg|94Uu^X@c_*B;SMi4AX{ z*X)cS{7Kp%2`Qg97!hu(TxZqZIqi0wPk-K$vWpVr%h?6oIc!-D2EL3~uFAN2qk*bD zP8?E9Pics)eL*{U=Az!;K25_C%2wNdt*=xX&)!RG_gEJ?@Zg^G3S#l!Ddsg=;OA?> zMofeeZLz6Ku7l3cH#KX$tvRpbo{<7O2-NA&GhbT*_wifu_iL0NKxC&aQy=e&FacDP9`tD$Bo;^S3aOSpO>tPYL+WhIE%{M(C zZ_OPrDdEQ<$+@e`-T$oKxa4G|Gx=2KL(B$OOLPG!(;H$8e9E-7n*HQ9!cj5q$`f)k zW~JAmPI`CLgYGud7iEYijxs<6% z#PEPWImLoK*#9tQDFsoA5_eyS0(Y;yAoFnZFYj2*H?5Bp@<-Tb1U=&+_ zu2x}Z^$uHeIkkhV$e`oR17~k@ma>-kUh{xFTwA#T8rL5vR&wRe%$3hc0%s8FIe@O$-S>A`3A*%mzjFn#vBK4szB-t-8AC0+0JRN?5FCL>^+20YOK^78e}gDzT#KpZ8R>>TlS&My^wPbjD#o6UETy08zWx?FDzJ5`YxbWYZm}bRtpY`%74v)_%pwhmaptuW`zsK^;B#H4s zwXSMEVQ&yVm<9YU9=av1#nNt-lFnl4Tn~;Wrf2BbhPQ z-|Mb?On{SVBIRi6WM{5t{zz#9t$Xb z+;qAyPb=C}k(dwVUlgQzx7-Ze8YfBU?NTG&GAauvmq!-J=Ez^>54Oro@?yu7=I$ZF zVFn5hoV=f!S{vh0`+Xv!+}!#cnP((RT&tL~d8q`jRSwSpNtj^h`|BsrypL=D0yR%o zB58!$@>YE#E}1^LFf?%GOS=b`SK`&T4|OEy5#SB3a2;fX9tEmzNKYnt-Vu~x|H?oy zwhui-=Du7pAuI88jjL+&w!KuCw#O0!rTiEKOhFFiw%`nes5oxj2Qb7jY^tzZ{+jbA z4=k28$if~~U|b+OC=8*m)=kx)_SAf1ftQq*)~&Rq^8FlpV}nWwH^-hqTuE}Kg5 z`3>6m`r!cN_#7hE`ep3*TIbI?E`7g!ca?BpbKR`#Ktt%&wxmF(#@qVALnzMGU>#Ch z%SHqO3Sk9Dy8j-(JB}POLZBOzIBZxpIz!*cLgjb*$)sY7x_^~^9?&-+9=QJ+cWW)5 z;I`SEPBl5#d2q3MMdPb8FN^25)|ecQE?v8;)JjZF^@-a$hWMmt^K@WHZI~A@j8BPP z{5r#4e6ZI_pdgx{tw&7enuiSE6Sat1o|oYbj$X-2i@4pFKeu9`{NCj6t~Wu zY`&mb5%G*);G`c&E4T-xzB)HuY|U4+dECdAzC-QKndJH7C)vKwGsOhOM&9{W=s9~? zXIa2g%zRrc;-t}{RqaUkm@$oqYeB~4C&j3UJNaxfGVY@vK^3h9J*-Z>LQ-sWofSqp zSH%_!frR#Tetgxqg(heB?U!g@48o;v@lM<^-sflabi$M&O|j8nL`@fBM>DJuub=Xr z8(sV4sy?{dKvG1o zM%2s~t>Vw&+xb*HV!Nxc!YM;&+#2y=#}@hLyS+lqXtR_ph^f!#cM}rQ(b#;qv?cmw%V<(I)5QLysu7{TG>#!#@B3 literal 0 HcmV?d00001 diff --git a/Faceball2030/main.cpp b/Faceball2030/main.cpp index bbe4588..02967c4 100644 --- a/Faceball2030/main.cpp +++ b/Faceball2030/main.cpp @@ -75,7 +75,7 @@ void FaceBall::LoadLevel(int level) } } } - objects.push_back({ mapMesh }); + objects.push_back({ mapMesh,{0,0},0,0 }); } bool FaceBall::CheckCollision(vec3d movementVector,vf2d pos,float radius){ @@ -85,8 +85,8 @@ bool FaceBall::CheckCollision(vec3d movementVector,vf2d pos,float radius){ for (int x = -1; x <= 1; x++) { int offsetX = (int)pos.x + x; int offsetY = (int)pos.y + y; - if (offsetX >= 0 && offsetX < MAP_SIZE.x && offsetY >= 0 && offsetY < MAP_SIZE.y) { - MapSquare tile = map[offsetY][offsetX]; + if (offsetX >= 0 && offsetX < game->MAP_SIZE.x && offsetY >= 0 && offsetY < game->MAP_SIZE.y) { + MapSquare tile = game->map[offsetY][offsetX]; if (tile.wallN != NULL) { utils::geom2d::linewall{ {(float)offsetX,(float)offsetY},{(float)offsetX+1,(float)offsetY} }; if (((int)(newPos.pos.x-radius)==offsetX|| @@ -456,6 +456,106 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& } } +void FaceBall::RenderMesh(mat4x4&matView,std::vector&vecTrianglesToRaster, Object&o) { + for (auto& tri : o.mesh.tris) { + Triangle triProjected, triTransformed, triViewed; + mat4x4 localMat = Matrix_MakeIdentity(); + mat4x4 rotMat = Matrix_MakeRotationY(o.rot); + localMat = Matrix_MultiplyMatrix(localMat, rotMat); + mat4x4 matTrans = Matrix_MakeTranslation(o.pos.x-o.radius, o.pos.y-o.radius, o.pos.z - o.radius); + localMat = Matrix_MultiplyMatrix(localMat, matTrans); + + triTransformed.p[0] = Matrix_MultiplyVector(localMat, tri.p[0]); + triTransformed.p[1] = Matrix_MultiplyVector(localMat, tri.p[1]); + triTransformed.p[2] = Matrix_MultiplyVector(localMat, tri.p[2]); + triTransformed.uv[0] = tri.uv[0]; + triTransformed.uv[1] = tri.uv[1]; + triTransformed.uv[2] = tri.uv[2]; + triTransformed.col = tri.col; + + vec3d normal, line1, line2; + line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); + line2 = Vector_Sub(triTransformed.p[2], triTransformed.p[0]); + + normal = Vector_CrossProduct(line1, line2); + normal = Vector_Normalise(normal); + + vec3d vCameraRay = Vector_Sub(triTransformed.p[0], freeRoam ? freeRoamCamera : player.GetPos()); + + if (Vector_DotProduct(normal, vCameraRay) < 0) { + vec3d light_dir = Vector_Mul(vLookDir, -1); + light_dir = Vector_Normalise(light_dir); + + float dp = std::max(0.7f, Vector_DotProduct(light_dir, normal)); + + triViewed.p[0] = Matrix_MultiplyVector(matView, triTransformed.p[0]); + triViewed.p[1] = Matrix_MultiplyVector(matView, triTransformed.p[1]); + triViewed.p[2] = Matrix_MultiplyVector(matView, triTransformed.p[2]); + triViewed.uv[0] = triTransformed.uv[0]; + triViewed.uv[1] = triTransformed.uv[1]; + triViewed.uv[2] = triTransformed.uv[2]; + triViewed.col = Pixel(triTransformed.col.r * dp * dp, triTransformed.col.g * dp * dp, triTransformed.col.b * dp * dp); + float dist = std::sqrtf(std::powf((freeRoam ? freeRoamCamera : player.GetPos()).x - tri.p[0].x, 2) + std::powf((freeRoam ? freeRoamCamera : player.GetPos()).y - tri.p[0].y, 2) + std::powf((freeRoam ? freeRoamCamera : player.GetPos()).z - tri.p[0].z, 2)); + float colorMult = dist > 5 * PI / 3 ? 0 : std::sinf(0.3 * dist + PI / 2); + triViewed.col = Pixel(triViewed.col.r * colorMult, triViewed.col.g * colorMult, triViewed.col.b * colorMult); + //triViewed.col = triTransformed.col; + + int nClippedTriangles = 0; + Triangle clipped[2]; + nClippedTriangles = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triViewed, clipped[0], clipped[1]); + + for (int n = 0; n < nClippedTriangles; n++) { + // Project triangles from 3D --> 2D + triProjected.p[0] = Matrix_MultiplyVector(matProj, clipped[n].p[0]); + triProjected.p[1] = Matrix_MultiplyVector(matProj, clipped[n].p[1]); + triProjected.p[2] = Matrix_MultiplyVector(matProj, clipped[n].p[2]); + triProjected.col = clipped[n].col; + triProjected.uv[0] = clipped[n].uv[0]; + triProjected.uv[1] = clipped[n].uv[1]; + triProjected.uv[2] = clipped[n].uv[2]; + triProjected.uv[0].u = triProjected.uv[0].u / triProjected.p[0].w; + triProjected.uv[1].u = triProjected.uv[1].u / triProjected.p[1].w; + triProjected.uv[2].u = triProjected.uv[2].u / triProjected.p[2].w; + + triProjected.uv[0].v = triProjected.uv[0].v / triProjected.p[0].w; + triProjected.uv[1].v = triProjected.uv[1].v / triProjected.p[1].w; + triProjected.uv[2].v = triProjected.uv[2].v / triProjected.p[2].w; + + triProjected.uv[0].w = 1.0f / triProjected.p[0].w; + triProjected.uv[1].w = 1.0f / triProjected.p[1].w; + triProjected.uv[2].w = 1.0f / triProjected.p[2].w; + + + triProjected.p[0] = Vector_Div(triProjected.p[0], triProjected.p[0].w); + triProjected.p[1] = Vector_Div(triProjected.p[1], triProjected.p[1].w); + triProjected.p[2] = Vector_Div(triProjected.p[2], triProjected.p[2].w); + + triProjected.p[0].x *= -1.0f; + triProjected.p[1].x *= -1.0f; + triProjected.p[2].x *= -1.0f; + triProjected.p[0].y *= -1.0f; + triProjected.p[1].y *= -1.0f; + triProjected.p[2].y *= -1.0f; + + // Scale into view + vec3d vOffsetView = { 1,1,0 }; + triProjected.p[0] = Vector_Add(triProjected.p[0], vOffsetView); + triProjected.p[1] = Vector_Add(triProjected.p[1], vOffsetView); + triProjected.p[2] = Vector_Add(triProjected.p[2], vOffsetView); + triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); + triProjected.tex = o.mesh.texture; + + vecTrianglesToRaster.push_back(triProjected); + } + } + } +} + void FaceBall::RenderWorld() { // Set up rotation matrices mat4x4 matRotZ, matRotX, matWorld; @@ -470,115 +570,21 @@ void FaceBall::RenderWorld() { vec3d vUp = { 0,1,0 }; vec3d vTarget = { 0,sinf(pitch),cosf(pitch) }; - mat4x4 matCameraRot = Matrix_MakeRotationY(fYaw); + mat4x4 matCameraRot = Matrix_MakeRotationY(fYaw-PI/2); vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); - vTarget = Vector_Add(freeRoam?freeRoamCamera:player.GetPos(), vLookDir); - mat4x4 matCamera = Matrix_PointAt(freeRoam?freeRoamCamera:player.GetPos(), vTarget, vUp); + vec3d playerCenter = { player.GetPos().x, player.GetPos().y, player.GetPos().z }; + vTarget = Vector_Add(freeRoam ? freeRoamCamera : playerCenter, vLookDir); + mat4x4 matCamera = Matrix_PointAt(freeRoam?freeRoamCamera: playerCenter, vTarget, vUp); mat4x4 matView = Matrix_QuickInverse(matCamera); std::vectorvecTrianglesToRaster; // Draw Triangles for (auto& obj : objects) { - for (auto& tri : obj.mesh.tris) { - Triangle triProjected, triTransformed, triViewed; - //mat4x4 matTrans = Matrix_MakeTranslation(-mesh.size.x/2, 0, -mesh.size.x/2); - mat4x4 localMat = Matrix_MakeIdentity(); - //localMat = Matrix_MultiplyMatrix(localMat, matTrans); - mat4x4 rotMat = Matrix_MakeRotationY(obj.rot); - localMat = Matrix_MultiplyMatrix(localMat, rotMat); - mat4x4 matTrans = Matrix_MakeTranslation(obj.pos.x, 0, obj.pos.y); - localMat = Matrix_MultiplyMatrix(localMat, matTrans); - - triTransformed.p[0] = Matrix_MultiplyVector(localMat, tri.p[0]); - triTransformed.p[1] = Matrix_MultiplyVector(localMat, tri.p[1]); - triTransformed.p[2] = Matrix_MultiplyVector(localMat, tri.p[2]); - triTransformed.uv[0] = tri.uv[0]; - triTransformed.uv[1] = tri.uv[1]; - triTransformed.uv[2] = tri.uv[2]; - triTransformed.col = tri.col; - - vec3d normal, line1, line2; - line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); - line2 = Vector_Sub(triTransformed.p[2], triTransformed.p[0]); - - normal = Vector_CrossProduct(line1, line2); - normal = Vector_Normalise(normal); - - vec3d vCameraRay = Vector_Sub(triTransformed.p[0], freeRoam?freeRoamCamera:player.GetPos()); - - if (Vector_DotProduct(normal, vCameraRay) < 0) { - vec3d light_dir = Vector_Mul(vLookDir, -1); - light_dir = Vector_Normalise(light_dir); - - float dp = std::max(0.7f, Vector_DotProduct(light_dir, normal)); - - triViewed.p[0] = Matrix_MultiplyVector(matView, triTransformed.p[0]); - triViewed.p[1] = Matrix_MultiplyVector(matView, triTransformed.p[1]); - triViewed.p[2] = Matrix_MultiplyVector(matView, triTransformed.p[2]); - triViewed.uv[0] = triTransformed.uv[0]; - triViewed.uv[1] = triTransformed.uv[1]; - triViewed.uv[2] = triTransformed.uv[2]; - triViewed.col = Pixel(triTransformed.col.r * dp * dp, triTransformed.col.g * dp * dp, triTransformed.col.b * dp * dp); - float dist = std::sqrtf(std::powf((freeRoam ? freeRoamCamera : player.GetPos()).x - tri.p[0].x, 2) + std::powf((freeRoam ? freeRoamCamera : player.GetPos()).y - tri.p[0].y, 2) + std::powf((freeRoam ? freeRoamCamera : player.GetPos()).z - tri.p[0].z, 2)); - float colorMult = dist>5*PI/3?0:std::sinf(0.3 * dist + PI / 2); - triViewed.col = Pixel(triViewed.col.r * colorMult, triViewed.col.g * colorMult, triViewed.col.b * colorMult); - //triViewed.col = triTransformed.col; - - int nClippedTriangles = 0; - Triangle clipped[2]; - nClippedTriangles = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triViewed, clipped[0], clipped[1]); - - for (int n = 0; n < nClippedTriangles; n++) { - // Project triangles from 3D --> 2D - triProjected.p[0] = Matrix_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = Matrix_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = Matrix_MultiplyVector(matProj, clipped[n].p[2]); - triProjected.col = clipped[n].col; - triProjected.uv[0] = clipped[n].uv[0]; - triProjected.uv[1] = clipped[n].uv[1]; - triProjected.uv[2] = clipped[n].uv[2]; - triProjected.uv[0].u = triProjected.uv[0].u / triProjected.p[0].w; - triProjected.uv[1].u = triProjected.uv[1].u / triProjected.p[1].w; - triProjected.uv[2].u = triProjected.uv[2].u / triProjected.p[2].w; - - triProjected.uv[0].v = triProjected.uv[0].v / triProjected.p[0].w; - triProjected.uv[1].v = triProjected.uv[1].v / triProjected.p[1].w; - triProjected.uv[2].v = triProjected.uv[2].v / triProjected.p[2].w; - - triProjected.uv[0].w = 1.0f / triProjected.p[0].w; - triProjected.uv[1].w = 1.0f / triProjected.p[1].w; - triProjected.uv[2].w = 1.0f / triProjected.p[2].w; - - - triProjected.p[0] = Vector_Div(triProjected.p[0], triProjected.p[0].w); - triProjected.p[1] = Vector_Div(triProjected.p[1], triProjected.p[1].w); - triProjected.p[2] = Vector_Div(triProjected.p[2], triProjected.p[2].w); - - triProjected.p[0].x *= -1.0f; - triProjected.p[1].x *= -1.0f; - triProjected.p[2].x *= -1.0f; - triProjected.p[0].y *= -1.0f; - triProjected.p[1].y *= -1.0f; - triProjected.p[2].y *= -1.0f; - - // Scale into view - vec3d vOffsetView = { 1,1,0 }; - triProjected.p[0] = Vector_Add(triProjected.p[0], vOffsetView); - triProjected.p[1] = Vector_Add(triProjected.p[1], vOffsetView); - triProjected.p[2] = Vector_Add(triProjected.p[2], vOffsetView); - triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); - triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); - triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); - triProjected.tex = obj.mesh.texture; - - vecTrianglesToRaster.push_back(triProjected); - } - } - } + RenderMesh(matView,vecTrianglesToRaster,obj); + } + for (auto& bullet : bullets) { + RenderMesh(matView, vecTrianglesToRaster, bullet); } //std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;}); @@ -668,6 +674,9 @@ void FaceBall::HandleKeys(float fElapsedTime) { } else { pitch = 0; + if (GetMouse(0).bPressed) { + bullets.push_back({ bullet,{player.GetPos().x + player.GetRadius(),player.GetPos().y, player.GetPos().z + player.GetRadius()},fYaw,0.25f,{shotSpd * std::cosf(fYaw),shotSpd * std::sinf(fYaw)} }); + } } if (GetKey(W).bHeld) { if (freeRoam) { @@ -748,10 +757,12 @@ bool FaceBall::OnUserCreate() arrow = new Decal(new Sprite("assets/arrow.png")); enemy_ShootMe_tex = new Decal(new Sprite("assets/enemies/ShootMe.png")); YAZAWA = new Decal(new Sprite("assets/yazawa.png")); + bullet_tex = new Decal(new Sprite("assets/enemies/bullet.png")); InitializeEnemyData(); Mesh testEnemy("assets/enemies/ShootMe.obj", enemy_ShootMe_tex); + bullet = { "assets/enemies/bullet.obj",bullet_tex }; mapMesh.texture = YAZAWA; LoadLevel(1); @@ -759,8 +770,28 @@ bool FaceBall::OnUserCreate() return true; } +bool Bullet::Update(float fElapsedTime) { + if (!FaceBall::CheckCollision({ spd.x,0,spd.y }, {pos.x,pos.z}, radius)) { + pos.x += spd.x*fElapsedTime; + pos.z += spd.y*fElapsedTime; + } + else { + return false; + } + return true; +} + bool FaceBall::OnUserUpdate(float fElapsedTime) { + for (std::vector::iterator it = bullets.begin(); it != bullets.end(); ++it) { + Bullet& b = *it; + if (!b.Update(fElapsedTime)) { + it=bullets.erase(it); + if (it == bullets.end()) { + break; + } + } + } switch (mode) { case GAME: { HandleKeys(fElapsedTime); diff --git a/Faceball2030/main.h b/Faceball2030/main.h index fb6a417..fc02bb9 100644 --- a/Faceball2030/main.h +++ b/Faceball2030/main.h @@ -139,8 +139,14 @@ private: struct Object { Mesh mesh; - vf2d pos = { 0,0 }; + vec3d pos = { 0,0 }; float rot = 0; + float radius = 0.2f; +}; + +struct Bullet : Object{ + vf2d spd = { 0,0 }; + bool Update(float fElapsedTime); }; struct EnemyData { @@ -171,13 +177,14 @@ class FaceBall : public PixelGameEngine EnemyData GetData(EnemyID id); Decal* circle,*arrow,*YAZAWA; private: - Mesh mapMesh; + Mesh mapMesh,enemy_ShootMe,bullet; - Decal* dot, * enemy_ShootMe_tex; - vi2d MAP_SIZE = { 10,10 }; + Decal* dot, * enemy_ShootMe_tex,*bullet_tex; + vi2d MAP_SIZE; std::vector>map; std::mapenemyData; std::vectorobjects; + std::vectorbullets; GAMEMODE mode=GAMEMODE::GAME; Editor editor; int level=1; @@ -195,6 +202,8 @@ class FaceBall : public PixelGameEngine Player player = { {3.7,0.3,0.7}, {{0.5,0.5},0.2} }; vec3d freeRoamCamera = { 1,0.5,1 }; + float shotSpd = 1.5f; + vec3d Matrix_MultiplyVector(mat4x4& m, vec3d& i); mat4x4 Matrix_MakeIdentity(); mat4x4 Matrix_MakeRotationX(float fAngleRad); @@ -223,5 +232,7 @@ class FaceBall : public PixelGameEngine void OnTextEntryComplete(const std::string& sText) override; void InitializeEnemyData(); void LoadLevel(int level); - bool CheckCollision(vec3d movementVector,vf2d pos,float radius); + void RenderMesh(mat4x4&matView, std::vector&vecTrianglesToRaster,Object&o); + public: + static bool CheckCollision(vec3d movementVector,vf2d pos,float radius); }; \ No newline at end of file