From 989ba6cdb230a86506309f025791568bd2218437 Mon Sep 17 00:00:00 2001 From: oz Date: Sun, 8 Nov 2020 18:37:59 +0300 Subject: [PATCH] gdrv, render v1. --- Doc/FuncStats.xlsx | Bin 0 -> 31455 bytes FuncStats.xlsx | Bin 31323 -> 0 bytes SpaceCadetPinball/SpaceCadetPinball.cpp | 20 ++- SpaceCadetPinball/SpaceCadetPinball.vcxproj | 4 + .../SpaceCadetPinball.vcxproj.filters | 12 ++ SpaceCadetPinball/TLight.h | 2 +- SpaceCadetPinball/TPinballComponent.cpp | 109 ++++++------- SpaceCadetPinball/TPinballComponent.h | 7 +- SpaceCadetPinball/TPinballTable.h | 4 +- SpaceCadetPinball/TSound.h | 2 +- SpaceCadetPinball/TTextBox.h | 2 +- SpaceCadetPinball/TTimer.h | 2 +- SpaceCadetPinball/gdrv.cpp | 154 ++++++++++++++++++ SpaceCadetPinball/gdrv.h | 90 +++++++++- SpaceCadetPinball/loader.cpp | 59 ++++--- SpaceCadetPinball/loader.h | 6 +- SpaceCadetPinball/maths.cpp | 36 ++++ SpaceCadetPinball/maths.h | 18 ++ SpaceCadetPinball/partman.cpp | 44 ++--- SpaceCadetPinball/partman.h | 2 +- SpaceCadetPinball/render.cpp | 84 +++++++++- SpaceCadetPinball/render.h | 48 +++++- SpaceCadetPinball/score.cpp | 4 +- SpaceCadetPinball/zdrv.cpp | 2 + SpaceCadetPinball/zdrv.h | 22 +++ 25 files changed, 598 insertions(+), 135 deletions(-) create mode 100644 Doc/FuncStats.xlsx delete mode 100644 FuncStats.xlsx create mode 100644 SpaceCadetPinball/maths.cpp create mode 100644 SpaceCadetPinball/maths.h create mode 100644 SpaceCadetPinball/zdrv.cpp create mode 100644 SpaceCadetPinball/zdrv.h diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bfd49e47d4211c1ff309854b4e306c175f1494e3 GIT binary patch literal 31455 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%0DhaAINafHL2Gm|rdli#7Ss|->L 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

&zX0tUlfT%omE?_2{MD$)$RoGtKKcQw%< ztAcUqsnU{XxhZMGN_w9lgNNYsd*TvQ;Xyf~SloOo;e}iHA{l!JVKv2|@^)~4!zs}{ zBW51WWR`-E&=+yByr{GLE@3JU5v;#WxrU}_< zX8|$;dnQ!bCveMjy!A{ttKj)eBA2%j*~%D(ouz=IRkmMq&8No80WN{^g6~%($)7#> z8_ffsn%sXVJpWK8uP1K6O{fS&rsiD%DEzc&xssNKGrewktJa6fzTcMmT zKwOIr3x;mrElpF{x8{ozQ0VCaST420J7#nw5+{{C398w-E-}!g_Ge?Q>z=Ry2JwuF zEVu%W3EGqyxzY&>aFsF+hm1o8@jUDxugQ4KLd>L?q6u^G4DCxwc_1@3m^^$SUzamHiJdOu>)>aix`dDGXqb=QjbeS?AhdKXfJIR0T+88^E8?I%fP_hSue7&?=f3CNToOD`t4gxnfhqOdRw2_~=a z5(zm1ok{-RQZi%}ymN^7&ws8T~Td2Qe+Dx?^wpnCwC6eEgYkED8%Vf(bjq zBOs6*(~F3F%AY)2u$>_1Upl^ZG@r%o??Qj+CW<^ng!;GUZyk%r&Orjqb}iw7^n8bk z1IOX0*^BC0K>2R{fB>Y3Lwyf&pe3r=TAE%xKyDrvZ9(E}pPhvNVTs!kpc2RlolAC2 zpf1T@|EcMNv^eoiA z=^bnK3H{}PNG<#0^-In_CklX5KYW7b<2IQK4_p@t9M~J;T(j1}s10`c1qYhou+RKK zfq_>=E~Abxjwm|m(*NZdLuG9v5-8&|R2D~}S_)i+52OzJmb6H3j0X*Go&$n9FL;nZ z{VGR=9Cec+Z2S7X=L}OgujP1d2Z-li%J8|=Q)?!fF!1J6AgBWq5aKKldDy_TS`9U! zVxQ@QVdlv=ZGtEP*)AtkY{dda9-vCha%HBWrz_P-PzR7BjA10a;#g|!Afei;zlTbp z`v^rCOGRf$UUDefx&-!IFd72cJ`ny9>UHq+>6OFE2m3GI@_1L_$MY?+Yh$3G+Gl~A zliXZ^UE>HklRz@gj*EHe9f}@Ur1@|Vd27XkOGV(p>u$e+4TrZ)n0hozC36<)K-FfG zy;wT}Xthfe3HttI>4X)q)ubJ(uVlXGb;VLL^*=BG|5L(5QJKvyc@GJF_d@Kxh;@&eluER=X%e&=^T`Qd%_|m8sx+WZXRvu>IGBkTsUlqVsXGk#ul{qbE~k-YetrL{oBLal+jVonSdeX z1e0^19e6K1A^&&T+%9nqHbMVYF9<_q4htvF0w=*U$v0^H`B%5tcbR{c$E3-oXQ$Tx zY41C{qR^Rmm0ktuRX_nLOINxGN|D}S0cnf$CcUemAYEkv>Ae?WsiG7?7Nkp+x(L#% z6hT0)FS~fX-}U?6`wJfDa5$SyCNs%o<~Ng&I9q5SL=17!6A<={jT{Lytk+}R_q=v; zY=ZDdNuoRj!Y4V>d(+2`@?f4`3T4WzvupQaX^#zZTdqzAA>{vpUfw@3_f$sDyDU|; zXTHt0(q0F2KV$U`1T)R7CCe)rejUOGR)olP6(c3E(yL-+0&ZrBEs38Ty{*Wbt>s!@ z0iuo#E_aCxKph@HlD+wWf>g@Jd+kr0?7R_547K$?!Qb>AowQE2_O*Orv@!d5T~e_%d#g&_E(O4o?92H zKO4O`&_{$M4x3+B$DKW;w=(iCU@^>?qP`3JZ9F_BdM*`7i$R``76(2B^&wOObdiUb zuEGY7wX443S6n@=i4Amtr~c$wE=RRhTs^2BjGwfxKH=R!ocoI_;^;l^{8B_sKQ-az zO5~F;!-X3k+F{350*@Y=I6t0c^)gCd&!#Tg;b^@d;@2ep{q}lOO^}kbkKXI2lJoi7 zYoSllSjKUJ6^Fzr4v?aoDyR$@SW6cT?*rR}+6m(e zIQh5U3kS3qigwJOsJU*m-@*nze>Y zT=+RU1=m%Y_!(7yK8stwspDVL)7_vISkdEu^Py-*9iheX4wJ;FwYA83s@e4_l%{Je zf+f!O7~#8>At;kh$bZ8iHETouqZ;G((Y3nmcU)3LkIMRIx|qq)ApELaqlHBXs^Vpg zpFr@tnXV?%dtMlLo{r)+VZ4@b=x^(E<*{}hmpH}45})pd`~9jnk=+3U2m~pa;za%D zJJP3zPHQEnf=^U%Z|9rkMsJ1)cH7|LtN0k`^N@4#(Q$oy&}H9iLX(!+XT$P@I8(0W zhY4|>Iki`vVpjTenoka*{G#I9>mk4%`iO#sF{6KiWqt5~$UfRR=H337+d6h;S+X?? z4xL}XEHUxZhEMB_EaZ$<0bGKo&>zKSSEqQgzMEC-J-BDzJ9Qan$*wS}c+*B@QL0P> zxDgF+d)dx!4?e(pPp;y$`@DfFp><_;)vGG~_7#-lh+l5#qwgBD>*3o#n?d!1AiMSe zvId0nCB=#I^DfBP@48JI{h=PspVnzAw3mYzuo9LJJb$@6;A5S5%yRn~CDUjHPHr-V zgB+u;W$^cqY~Ko>PSGSf>ve*_nB0S^i*Ji-CYy-8OaFps3$CfvUM;Se`wWLUeTmRM zcqTr=Gw`TZ|J6x$mcDP%sN))flv{Daa9*plM(!gIogFnvt^YtRB8EqC!W9&H-uP8G zR(o3nzmA6b^+aCoV9Nnvo#&F{v$2MmCwRNKw~tWk^W$c;xlTrIPzU=UEr(WFbok=< z6mdgPabgBdNAhptGXiyD9b6`NnH&;0@r-e?%R{maDkhKzy@3Cy+vP*mplKF5Q2JIk zZpM)76ycUvJLC|+l{97y3TvyzFEQpiCAbwO9IqVUnSZKfA~FueHy#zUAMAjcxJFk! z?#MPczMrcv2s(85W^Cl76ss*dCO$H0Z@sAXanjMc-i)`0(JsxEtZKF+drX6u_i4zO z8Lw{Xn#~2L^eb7lpK_ge;WLt7GOUEWs=NG}wH5jcAh>nUm>QPX3~2DFR%u<0IJ>omoMbUz#(Cmc zRrW7b-2`hD=1VlR*wC*cX9i|_1IAid_ov0jhHaAppr)U?Q zNYh26I{q)rfvR?N+KbW_Eh{3j`~Lc^UN{dLUH~ky-FS6qynrUxNm85oIoB2$^>2_< zVU?;MU1g-84-m~oJv0nJ;|w#aSm#?pDa=>-X#f^h@Dj~VYU*q59OtA`>x^(Y$Y<5w zH~?`^S^Ou%y$2VUPf8}-LU@puUOgRfxup%|>UPZX^9X;$<-Jt$NWPX_Ka#D8>bCL7 zymPB~hiJBizewPZUTv>9Of+Onb^7YLRR%(xOR@S3jy@WiV0;!wyJ$AuCMOkuPrz$| zfX5hX5G%?QUB^M{@g;3A5_*wr$IIaIfx@81xv4Z!!9kM~PHl8pgM~(0pD08NNy8mB zQvnANFamiY;7L`({}2n>=p5RC7V8sbxIDtpQMEEvi;70Co3sfq`m1|H*X?{TCa9qs zb%aPevFu9nh^koB)RQ(+_~Pm1eoarn6KSTG=UYMrOUwMm1Y6WR8*53eD+ulMxWg>I zOU7=6b-|>Rqi53DOYpm;lGF7wZE-_x#?eG?#m{Kdy6Tn-)hXc&Pi@1Y`PV!bek>U3 z2M4j~9)@$#dYbo>nUg?Y%^+r-Bn1yP)>u_f>*TpTEUERcG1IjP6NgzJj4>n1fniFU zyTdJpV^Q29xV+A`(|c*(eYBvqK%L(FzfkA(t zBI%gHU8jpP{4Bw}2P>Z>Tc=gFxW03QYDy+#wNs_xcJLX^5uhE5w zJ>*)xwG+s$G1Ka&FN!?K04#hTnvQ2idx`hLQt3{S&Uact_XY3-Y;F4rxL<0t8p4zZ z-TvgFn(0(scUQ{b;UtaeJqs^E>*MU9bbTdr)?>rgt)4E1e6y)ZyX8+px&_0toAzO& z-x4+}O;e0m;;XeU8F$U%3|@U+JgWIslq>@#WiFVm(Y(RpyK1o>J8C57l`y6dWJ#;o zk}>hnR1oRiV&TuLCaFcO+J=K|8ImpN^RC{-&3{g^3q=DJvKMDn6C~%PBic*km|`ip z+?MxJ@8Y$1yxd4ayf&QMmM9)}SL2ICN&AH4Hi8tKbOe-Y#3qe>g@xlTbZV~4Ni~r? ziBHf~huc5S+Mp_sai6K+L95#70zWj zb%}@W8TEzZuP&;&ZgmF|y}Lt~01P=0r7Y=F98Bt#TJnX<{LIl$ywX}MxOyFx5i^%K zCpNR2!#PZyR;Vu{9@A@ezK1c2s#RIu21aANm-p`lS3!+DxSMouAQUWm z#0$f}ZAr#d=YdYrn*i<+;w3{%)5IVR-V@Fh+|F&yk*Zc2h$bquUNGX3gz1*W!s$n)R_3 z!PQ&y>KgALggbekyY0OFHeLVH)#8GobXl+*MjTTSrWBkL$j^7UeXbT2OUFObY1JzJ zq-14sS#5^z;>L={L$u~I6NITWEip{}w1_(;bQpdE4G)_<5DNBW0aKn*INpq>_VngO zlW_T+y$F|ASoYfcQDgnW>~-d?>?hQ+`LFwan_See3hL75Mz(GjEd5q%;g80wd@8__ zdaRD~NBHdb$m)vB(@ z>dSgWIyV6lm>8qv)zgPOQJV~c$|Ws4z?6Uf?GEbi#cbjUDjTDVoyL9_FRvitf3kD` z02BM~u$5FO5tYgAW)7T6-8K=(M6F;2bGg>Xb0>D&zTqbZc9Nf5uUqn1*x!Svb80~9 zP2QZN5kEY542(qEP=aw|g_62N=OuDv2T2ZyLD7a@!LLbx=4B>3KUvOrDUbvNuXzfC znsBMoCs6(ead!jtW#8K}o3he1$L0o{Ak`4(q=(&dR5_d1@_spr>kED!lkd`i<>vv( zHH_~89_a(($1(fSH)9$KYtWi})NLOL%Ce5x<-Euh3}?kbz(ZACsgsf0NwErNACdzR zm1QuOO*U7>Au?wfERw{E){Cx@S}_PAbmpLZ%_ zs1J^f-AD5vuclH@oj#=SFABcS6n_+B)CK)`f)FcW1G%QiiG?P)yEp@pA>UbEdemnowwyxi0@5;ev2{efeL1$jUOibqPa^As_ zA5W{xarjI#ZGh4@=z%L12m7ndEDPfw?#l@hG)$T77tuK*DKbSqkBGR(ItAHoeyKTX zh;i{@H+p`zuWv-5#Hs=~PjHFPTetU(ccvshX)F!txyMR@WF|smj*=xBAc+~h4K{m%oOb+aa)s7YM#eg zOTkFI)}COl?(z{ERImin%)B#_)1O#7pDsiNK!C91Ji9#HdB(O^8KJj35)dN&i@a&r~*&*yPd*NBVqD_)xZ;(-FZR#XH^)QECSUXHe zrLR5O@VhCN>`GyMI^FS(ST)LcdV6ZA-CI`A5yf5-TBI{JfQzNQ<>PE6^tG$w9aJ*UFZ8voO~p@!Ix1L`b5A{|EPIO1*Ak?(Mpa^Ane{lzF6;fatPC>10Dx5V z9EED2X50{-_P$(9E-~?zj13r<`tr$m%CTUT+5`3XpU}t%q)}K^I0`HK+HXz4amurG z#s))ibCPg#8r5fXAklrEGeH7q_$g0KAYUwSBA2fN@#zCVIKYeVQiO1<87tLd*^Ukb zhAx{D3kM|^aI{e}KHP}~HXwmh_K}!4tYWVpIkn7>3>gO57kVWD2>Gbr^86+$5k_wh z@;=eIARn^U=+WRYsTPUMPDX{pPQoOtnZRb3N4LEQH;o6N1QI#SO_f3~^e zX-ap~(ICk*(-Z<-Gn>LbumY>wJ_fr*+I01Hor_HRylJ?Sun}*58UzdA*h2kQ*=umWASz?wk zX{9_!H{Tc&wXBIBe{Q^{iufpq5v4wR&Ye}mb3ocEd+r`Zn;!RZR>z>T-Rnw_WzRr- zydS3}pymnkSRr%k;&1A+6(dh8C5Kbzs$=2(v<%(Dvn=cQ|S0E$~ z8#sBa9l7X-nRGlLJV#?xj&x?^q9?rFxilmStS6^gtzzJ10+tG)>@UG|Y%rKs)v=a* zS;<}2MeIArk@ErP1{?=k4@j$YA$C3c1we~AVu^Er@cyI{iN)%1#i3_ux3#iCrGY`K zor!y2s%df}`Z>vR=-S>6cXRJ@pGdama~ z0~1%p2b}}!Dr<@~0=?6u_o9)u@R$K(J3bKN!8_;nGHhUHw86f@Ag}`{pAa30OwYc} z_p;on?@kir@*HQ~S5?shb2#2?2_h32zeMt=0Zw=V2WW(*o}~k~B}9C85;igdjuLQ0 zOsvpAnQj;ClflWWno}pTVz2nVlbnR*_Wr=>TmIZb(%5*ba-h{}28kH|E$=n9f~uF+ z1zmfZ0%!YaMO4NFs#VH7?WSM(6;Hm=Po>WDAhn(r& z&V)Owp2I=ndxuTJUvh&)Tyfm1dJP^HV6)*6a!jvc2 zgFiXUVsfxr+%~~Q6R9f*b3=_dD_k(rfDuVoQyZV}AVeiGcbo;=4mopH=omG@y*V%i z)?iTZW#;Nl|GQC2IpYg*dduZK8|8(ti(~9JP3}@_0lNS)`bnV)yI|7oN7?Q5$uUbC z4Pmt655*Rsg4dM=spTiGpDCwp1zYEXa&c>akwVatSl$cu27*fKKI-4|$!wSN$|tGe z46fk{zW*JqRd?Wda(|;A0Op?NP^m@>Gd~^RR7AIA3fkfHzuTPYlh=WCF z7l^%ALc=fh=tOLU4ys$^sT4M4Q>|;t3R?dOc);Ry6(~gW@S8d;AMnYc2v?5=+K-+G zAxZzP0}PwI)|9#E!HwP8w1H!&=WH;{a4Pl$3kIS(u5%~SS^Hlpx$egx19onhm0ETT z2odde!aERs8m!Pfb!gPaW$TJ$_*Mp`Sv`=S9RMrR*37}A@WXJ#WI zfDbh#B{3l#ur{0E^!ctz0Xd?3Hy$1)KU(3S#{lR%WV60sA}4={|4Kms08A$XwzKLL z2aNh3aUD3E3Ob0Or6C4jNWlyulHz1D0^ISjldvDi(r|SLz-fD;Ie}=vdZGnGubB)T zh)DPT(iWyL@vAXh$EC?uz+6-#G)bCt3f4K z+DB+ol95%(gKgl{K=R<=RJ-L_C14>$au;QpWNdF-KV!g1sXlqooi%cIs~KwJnRu

i33A@WMz3V6WT4JqqA?{3e$JeU^ywU=M8G@G*Z>s- znxqM4uo|o{svxZ|E21LC7e;b81x%$d{e=xkzUc$2Ks)}E4J>)kXedhyc*wI#9a5Tl z{q7kLwo=t)_t6=`NeaMxm#WhMdK%omJK5BL4I9&3O|uJr{}Sg$AiRDC$`V~x<3w&!v}IAG^}Q;YDm{5JboIhZGGr! ztog}IH+B&;d2*|^taNG`2wb{&!v^V|TTK|DgIIaYU|8QU*anhhy6zA$$*Jk0P`h&z zE3Gsel0mx%YDrcNU|@W*yu4Bw`S5S$H$rxqdSZl`6(*+bELT;$+;icy9GRF(IUACu zw{n1wT{DXh1YH94se0w&fteWBZ}dGe{c!}Ni56M4z*Bjr%lHX=UxvD%=V3!~W(kZj zl>6^mp(+zzZ~9`;<5^!237Ai1tR*MS4BESl-pBo$%{x>xCe{DFR^#EY9Gdg2fa`_u? z_q$F=_azb;t^N0UAZx@jKfV~6CLT4x+j0yYtT_T&tn^Ob-1;Wm;{h@6_B>_|xN%oi z>4pz>p4Y?!MyQ{=#( zR2}A(@u9TvY8N3cjI|K-YMdR-@F4m2V;xtyJfuuxwRma7>(TH1uw!2cwv_4{YOtx} z;e+*i>)nJNSyfe?XHjn$f6}P^){Cl>Z9>n_f{*#ztt+i3U5Tm2OM#;9Y}qefY}IrT z#}6RV_=Xva4?@`W0zBnHy-THQEV59i zt&b6UTZwvh9QuOKdFWKWp$OXB-d4A}Th>T)>LFUB#j#Xhdv| z5&4^aT1JzoBO>pXOwxS+?P9CBFGj-c`1<8#mmO!Gjp*}9$FDWGLgJ)VtG?fHC@f64 zBIi(1=x4Ifi^vilCcF9wCt)sxhWbKR4-?NdeUJ5_EHgo_n)>yROdx7t&a77dkbKYW zq(p2oDEI^Jnt$(%c4O=%)oTNygHCKEK$X?KFmW@37i3U+O1>KGp4Ah9lJMOj z3J=I&ujiYYZ{`;`TFM0DILdQ&SMaE!UHbg-{UahI3S$OlgDEr&F7pQxk-zn>1gFa^ z!Sx-9P8l54(QWN0N3T0ct#^_@Zg3rn@Z5uF+fZ@#lVY-yw=FYVkre&a?aA77K|^CU zvcD>tJnPWuuU>eWK#*d!n|JM?2P&Y*%FzM!3 z0!pC+M@@GQm{e~9P?Cg`nlN7b{_U(#(fG#ouTU)i#MjjnZmSmTWnX^aVq2O`Ka9=K zN=6yed8Cpc$`oX(!!0RP5w>sH?ywmnx& zk1i5qXZ`!PH}Ql!DF)SCd2Q}yJfV+%@-5B$#@w7^0hGr-@xI6}x`gWzKj&-npu+x% zy&^;+{F>+idDFkmM`g9T0!~JAopn#RF4sQr)e$#Tjgz4b#HIl0<}s7K02B3IM9sC~Z>kXh)X)SpJ}96H zUwRnixhMS21Hy-nmQx!Za99ivp&fboH;>4p#xJRM*YqP}m_RB9U@ir}^&d=57s6qk zuZX~@wZX5yPPAlq3=LIBD8ji!zm~u;J4IO9^(cqyiHRA`#*-k`CiB)W_X>IVo1IIN zF#FXB`P^b1r)e#2^dXsGE-@EIRn>vG$ABhPsyB$P&W_pakydadCfZ0sLjaWE)&_yg zn(N+2mqe&>3UKeDj{3zQtOm}!UZd0qW{(cq$D8FqunqjOd!R!^em)vt0RIj^b~ab% z;LEdiUsldg;HkqNg{ta*#OtovctHpg!24XP`HFSSH@tc`O=j!N4pqO3(uq1=arMU6)VW)ifK%U2k8%x0sI^|XXG zkIVX>e13psZ9|Yi6sG&hMAYeFA=x-Mulq7Nm4wS0U8>Slr>==)%XeOGfE8g1{$TmKNw0Vi;iCFABTv$EuK(J`g)^eAd5uwpW+1 zYY-&yA_!H;{>~HxJmY1*liIGqw8VY_q6^L-|JO{GgKm%2pbA;&1Cj2^T52aT<1Rlw zEI*A_5mSiHMxaYVxCA&F+i#%&`UJR+Z5xg266X=m4`CEDn2^+?gmPEo6UxIAve0xV zFf~#)lWgR#-d)detBKmOO1qhSO@n3nLXB>vwp~%b7OIx^-8nT^nwa!;Zq17-cHjsU z8&*Z3q*_Bpf3@PSHy#u==w9$et!{9)EkxPsi!au-3IG8&Nx{zr8CCA20DtT3}Z!Y@VQsCtx_m+j4W7Q5xCv&Nfos>z__;O} zniFbMV6)aoimH!vj3e&ee-&K z-KPZcEQ6 zcv1DyWCo%UUp9SHDUwYwjP>#0$G+|;@9MgXU)j9QNAA3iD5by(9{t$Y(IbPnc5E}$ z*BvwMXaU)87uLv+p4*kGJYT%y{+x$$Q`b2+h=FH&UcOtcCvu0H1N0Eft?g=ir>x23ZZ0nxtJd+pkR|h_});=-}4(c zB`$T^iktoWmzPBbaI|<>o@eNA67h%+u5-;a6AZhNy|jaAK(>a}|9VRrG0@ zyW8)c{Osw8&WF%mj)9Eb8|GhUnx7+ipKcVu37Z+bT=2!Jk5l8khu@1e+1iu&=lSuatEPRo|3rX<-B?a8G_J&Crv zO;|YBuI$0;A1=67!TDwl4pl#6RjN?sb1g{4l5_P$M%_)E|Be$ete9@p@Wsv-mq}nM z@W;wtqUF>9vSlpe^Tzsdf@OL?^C@swnOoU{Q&!keG`P-ok}NJKKj&}m!$kF zqE?R~))SA6g+-U`JC|~(8RLl)NsBmuHYN6Dflua`Pa=1Ema3>3^m z9@7rOmzp>+Yz?oXxRWZqV`G|{q^KI~Y2|S#)wLwB@8JS0W{7ucmpZZtMGq_E8e`mR zfs{U`etB4-)4e;v3PXh>OSHWHO~^+D2a#+$sH=~ z>DDg1CC9Uig*%IP@X(9!b-F&X$U}RU-gog9jpi$bX{sV38Rh zboLB}s%T>w(;2Os2BS)@o8`3Qzv6I>4#Q$@&DHk{fD@+@e))`~C*~jd48JoZLs=(# zLhhs(P8*;#T{xJX`}(@Z4*4?|B?zr~ApSkY)etU%ySwj{@!P%Gb0~EpFWR@54rAxB zetd+*EN#hs6Qac zWbKwW$GL*bW!3a-pBg{O9*EH#%5ZI$7Pev$S_X>)gFqIU>wEQ6WAA)%EtK;dh2}s5P_j30Cc} zyYlXZtZc^I()Zl6L}ecBtsg9MD1 zjZA5bcL8G!#|z4EY7*`kM(zocmFu*Y^4WJ)Bi0NY1lh9Iq=Oi_`P~2)_w5m zlBc!1uC=Ep`uQb+KRyfb!|YvPS>%FMg4HwUQ|5j&2dBRXhFj9q6Dkp5U%{5Tjdz9e zdD!z<5>Beg$7SgkyU!1*$&%#!#6GV_rvb+He{kU`-^&#NzPbqBaU=iF6>WL{{{LUl zV90*`q{Yd(P6?8PZet&?kj#Kv5rjyB%V2k;_A4#V$JN=Y7g%Liv4@wv*!c9U?nTFh z_higMfbX%q@(i=2`Tp}kq*laY4izpAqa*D>g70Kd(=mjIozmfp)gu+A^T_nSzRNkg zt3B^JPs4Pvl7dg$SUI9DwEuI+;yV>e58Lpm#+L~Dw9pf~SxEx+ik@Bg6KuJn>}Hki zV3^9?Z~HCTUNzV(GTX5c!L`S6aXw?@vpNrbM3tgRsmbt(&AJ+jl3a)n_@pG)bh`XX z>&ASc9+fW9N?NK zy48Kmv1I6Uo*?1g`)f=+4L)XXO`4cU@7`s2`iSsJsA_xq6|(QS6G>`6S z+9oap4kvpw?{o(au}rLwb5O=Y8VzUf`XUQ!q7K78*Yx*fPu6kX?i08_G=Tl>Lu&5> z0;77)jcggezi7fbA7(swZHD6SPK^U_KzH}Y%Wtk=BF+}kc`QEgTG{`8X7}&u`up$y zcyw1w_1^^k{od!_4bgvJgEjFVuYdm8@ZV1${%1oJxE&HaX7_)25b;kse?Eiv52efC z{z*XRKOe>Wv+Omk87NzaDh^lfs`Ddj3P<6Z`M(J^mlpd;UrA&-*d|AvnQ- zA^7KQnST=a^KP<#2xLIcWcqzm*`H1Sy#42&ranS{3WJdeb6w}3RQ?Tf{-JU1+{pcN z=l%=y{Mr0ZhxHEuWe*G!|8ie{w*J#E{L`A%6Vv(+ukb&;#Ggd}ZRYauOywr!(JUAFD2F59+k`&Pf-%-orEzyDzF^Fywckr6x2 zKKq=A%;$uhBoHt%04M-B00001fD@}mkuM+sKoAH301^QB4^1Ik8z*BMCtW3XJ7Y&} zS~qJe{5;?v>UU`f z5O`D%fjChRg}It5wG1nANa%QR_UX2&O28EOI);a z9-OkhORN1YSHS^wkg<>Y{%WOp6M1#g1K1YY^TZH&hUV3v=&4tkhmu3&x*JkVTk5k{!4QS;erf!+2T&-H zhN>$elmH>rkdQ~!N~|z0#}be%D8f9`gday=$^EC{3ghYJNA=BS5;01Q*OLx- zLb`F~Xt)=8Ex^G%!OD1FxnJsaxph~CKN`48Bi3g(G zWzHdtyb&4#Ws|OI$=-i8vD*_$hEI!a-*In6IP#yJ`P1f@l|FY)a_<%g?MNFv>-P@8 zDe3;(EJ*-MItTvV-S~h205Ac-0o|JJ z!M!GhI@W0%(o$k{*60hYP*PV4&neL&F`M}-{>M7dEt9N0Im)w;J5(O}YubBvb9tHQ zT>Ts#&Was@pac3UyC3=V5;F4pDKTR}2X?nQ6K{XxbP}%wN7o9XP!nli>fKLPVf|h9 zWVM(qk+e4!edeau5j{h)G(~fBB3Dbn8Ufh@&Fh=PqhQ6f9z9X2baaL(^nOrnQgoB_?s+E3)-z|p)CY2Kg?F~= zhs0$)DL~B~#hDmA8b>9hshkR#(*;*UBv073x+aCL9?{1py8Zs?d)=$xL7FKA)|nGH z(O@)ODUP^tAvilwC4vaPr#7N2{v(u#*<^(|D#5MK=pRKSDI251dQkVIdi_7#)n94Prs+X76@^#ltSwOIxyG=zq zD;p)N)=8exu=;a5rB18Rp>8rjT5&yP@K81mg+M#n2){t;{;+qp#MiwVWdFKLK6=_9 z*j~NW;cl-~e8XpHUxfQHbhbpd*-5kKYFqA_>Wry;yuGHn(B52qobG|UK6rw1oVhVx zq^zdoY$E_{n)8R8>f&fFGS+{1k682O>Xy)O>w{;se2l$RSbq;Bc(^_fQssa#DzOb7 zT8tvEEv&p4UuKUotnQrFq$iKMa@wDS3I7H?yaRGEEm0VmZ$+BAoVqqg!SVQh&?hlJ zUp|eVy|4t;0Ao=+_$AUHA)fcOP9}koa&|kggdQvMd`GGP+7YuwL@VS@Sc{UIU>%vI zAkQN`sQi|jb_&U|3v-t6p&-isqEKV;ZhPXJw|1BN2420#!{Pbv{n2N6Jux+nexQ{~ z6A5TDm_86kdD)7utkEBvpRgqT8 zVRhUwa}j~*#!KSQz=_vQGmnj{56 ziShb+DrCm5d$X`X$tq)XR(V$QbcN1L;a1ow#Zfmxo_3LauOzbhp32QzMv$Ubu2)Yd zC`ivb@Tm%l2RyNh?Ui*R1sktnD z=1r3}t+^-_<3#KwzfxDR*#-aAN?6RH6}|clc0AL13y)W4C9vw0C6G-0vcSKjug&^8 z2yh_&C@gworLAg^qMan42K5qKUD^VZ16qHpbuT7S&-qIYqWE37Ne)BM1Q^kPl5&~v zx!i~ai5^dX0Au3L%}2DYBsx->Iy-RM*0{w%NX`s3e9u#Wl(!_?!T#QsUhT`-fJc9r zYG3blij%rOPr4x5hR9^4NGnKIRlgx-PCm~yTltzJlCx~Jk`Pl0L3tI(jHlUCs3_H{ zhIx;Oxsk+Zj=d9$+5jz989@PzH}2jdC1mDn2oIdZCoZassLST$c?Wbw~U40E3#IEqp1Tn=Y67})GP z8W3}Yp#lD!8ZB#SJi|-y-6!f&Ho;e?jJurCtv+HMudc4w`=_<1Ze4olH(TL_xJmmI zER|=<@twV$Q9?34zEClp3JNRQ=o^f2d67NPm=6FY4W20BocP$_UuO3L7SHO`R2PIH z&9LjSJIys}*m^=GK*Xcbws)>ln)7hrbD*wYl*kYRff)>5mT?r!-Dbh4fh}9P4j5Y* z0@(b-BT``E!`0V4pmTDfAcpz z0<3w8JQMLeDr+hHvTLa#?*O`gr}RMv0SPyXu+GL0$2bzhMhT@aB4AA6l0_ElDJ3lE z5#&h0U~Fm!y%xn+A91UqOZRdlVhvMchcw&&tu^7SP+X3{de_F^h7d2O3J*&00`mxo z&p+m7+@GZn0JssR3=Q-a zVsR~L-3j5Cw&)#aGCHh|873F1p<+pbInEUvDYCe4HyW$pKwuxf*_Q|rA;m$wh{#Zr zjGzPjl5PiI+}gDu6=l2lK6{s=-&?nan%_<=Aw(@1CC1Bk6ZI8oAvByqX|B>wfzMg= zeC}4VD1YUy2J%AfK~%{(9=D)|4Vfq^x`Ft%H#en#k#W&tCkC>~hVi^E?94_`yf7g} z994zv^y}@;AY%H8F@JGHrZG(YQbass{4la4wZ*t&23cD=p(UIGtn?X~)~MP&Q*_yY zV;Hh;5T(X@l+Kqw$td%+X0oYt9lY+Wp_U_i@GHQ6*$7*Nw6_3vJGE$;FmNGMR;$8BN6}JdrCa4V0WF zXUg#Wv>IE-s%^6F^aGNr+kVV&oA0?==YGe$3-4aRnJDf4TRkyV7TpvG$glQkIwKxG$qr+vRB`Pph(C+G54bL}uu+Nz5H}FY z=vAMIF&9>!j;N#3OpGX#sO0Rk-t=ce?afIw?GR|S>rQyaIN^V+)%Nr2l^A(pk><%u zu!%1M*Kh_*AewGiCrB^pW#y(^m6)XP{$xglTgK{%wlgP=pp3I$l#Y0Nm@8N4SPWyu z_q`Jo4DSX*i3Z?i)PbZ&7>y^8qLYH8(8%^;Ixw`WRn%nb&iE8#5lxig6BBjdWsjl@ z?{M$}anG%pd>~}n72<=sF{Te-$!l>RGFW3vh$6-=>kmg?kL*Ls=&HcuNb1nHd(o}6 z#|-x8oEs+=`G!}ukV*u)Nq2-~m3sTiHlY{vYN>})lE>E$?S@t+&1|Ge#XZ^rW!H?d za79LvBP2qEtK{sgnyxxn#hH253J8`auWE#}m3bSt!xo#%e6eS<99Q0EC4y72NSRjl z3lA<_WLboQ{?a)h*Fqpqfl?8P;;~Rcx-iL+-E3)cau&K9Rqao2rPr9Hhi_Y)w#IcZ z7_qE~hEmVN91ua^h1NTAtwO6>nJ(0HI2xM5Wg(hl*R7+};eF9e=jHWSy96Ghi+Qom z9NEVs=M%?ohuUW(M;wAP%CMkpe4ewPz#O)zPlTwgl%DUsaWoRlmNi0gmVlWK8MJZi z3{Hk}z|+I4FB|qjfNRK)92XOD_B5jL#+)t{%Tl=QO_TTZNv!gC)Z`4}fm{t0Xs~~b zLMk8jl=l0Pl{Kd;J86dei!|cwDD2FYDQA7s{1H5{(3hjX)Bi10VhDPs2K1@@Cy}at zgcuydj4^e>07#i-UfKL&E1J#np`V5Y!tw>Stdi1Q9a^;=f_!Kdc92bBXaB+pWvJtM zf*+^1pCj-QMF>8hUdoV)txVHp#|eYwFegnEeGtyOT`f3p3x<+9z3qd8u9Yc*`YiKf zX-TM{Ocj&TNt_^Fz|VmTo;jH~S)Dlh2q%nzTV_GIt*Hgt!9=hSM0X;Zj;BKZQ{~`A zp%1#)<8c$vGuxL?zF0k1 z6K+}wBw+lQY<44s8FFcTOWHV2#H!WsG=^*rs)G4}27@9Oo@v2{av_s8_lqYNG|AbD z)}9P+Y^F9E*jY;qQJwsFk{Vyu^Y}bP2Bih`;BzRm7O-fm`eIt3V#j1=MN#s8l=4cx zPxmvX&a37liqA<#dcF){^D;lNb2v%kWL_hh(KoZO&hyqw_W)r5?0|TPhkmlFYx7(!8v_x6 z6rTL1J2NtL0P{@)7vmnWf8Rx)G&TSA8Es~5>oo)a6iKshlaoU;^E*K{=2$Xtd|x+) zph*P_`O2tF^!MFRBxf%rP+GrF=t1gsF}s*b(2EBnL-)J-7ST45B2Q8$Hd9srs*4<$ zot>nCaLv4V(yUq*So@&||E%mRcKWsD-sM4&jS!6Bry&3y%q_kByqckU^^9VLbwCiL z=a0+^8J_3OKP8TE&p(vqG_3zH5BhsU61!5wT&9n26Z~N$_flKTCZQ2R^i>@i|J=KC zM_MVjX4-sh7m-ge`sCqHgB~>sC}4C^37SG(HO;KUYUz<9?^8vEygG9TpPr)uoyV!c zf6(A=2sn8}^s9dhJZ?(Gd5jnM*mdFc`nHW@ zRxM|yIGSM)(Iujqfh%^TeP_CB1#6=hr1jS}NZ0?2tFpz6kj?&5yP|<1bw4 zRQ})$D=nAJ5NxK_=!!AGwnGUV*57*E;@QL% zLuKuh=+xnTls^&z#zuV4q40H%!)VA2#^|}l! zY@E*%djp+^v)dY+9b^apHEFm938VC#W5v>O}GwZ^Y}(XBmd$x9Y3-L?}}Ye zzR2Q51Zy*!j_Z7cfbQ=}_K;3_IE^Z>iyL;Rh2dHw**9EooJ8Cw9T~%++ffc3~Op?0$>_CC)G~vR6e_Fhjittp3O-ueDF*EOS%<<7wKc zIK53LaJlW>g+6*4nN6c$>2?}}tleqs_639K6yNMJdC*12DO8F?n|eZEl*kOw-R4QN zZh2f2X;RclHlGvRK1k@C(f*SR!+x3r54ay0IV&!e&%@p6{TA%w6wHzly7!_t!u#Gu z9ttSa*9p%I7R`6w7-e51>P`ivD!jIh32u!2$Jt<(Qax*%)oWcIO=Mny4*2<5N;1th zf<##SxJW!N89>@PJj$S4^zWX53Fx*=@77B4Cx<`~&o0(KjSPoYl;wG82AsvVRTxjI zK!Gj2)*|Qz5gEzRkHZgu`5f}`JD29rskO%~z*^Zt`FXb5ORno>`dgn3Y1WWnlI&6V z31E9M3wYYZn^ZA;H>E^Z@H7VlrIaoz|z{MzpT0%_5zIk0k{^mcq#!F-)qJT&6k;8xKwC`1^k4d z{-Wmv*GwGt7M=`Me%sPA%qX`<5)7X8V)21xZ$bvf6s*Ft4P9IFgzl0CbOx za?XCcm?m6h&QhyI;zNN==ghOuiag1EglLnn2jddH*?kTTKaE1m7O-^8$xG`O`;)Z; z4KzCEGCeYf8MhM@s{}=F741wX2=$Ui10KAJI7$;la-w6;$#$$47Uf)Ts}xvt@hN{1#G{PuhPp$xP?QeC6vNKKD1vXjhKnH2D4_6>e5o|a^h#L1&W3j-iqou@J zJkLIh?dhHPokRn#Fp)y+MF7DNXq=v#Hfq7MFzm!|l-8kSk?tD_M^CKaQ41&1Pfe8J z>M96{0yWInX(iKo@-;k%6hfy6n&a1_F|&=MbJ7bSPR1{$;+oT0Nz9$V_s}jV_%<5R ziT{B1I!;jRx4_!D2ym<^atE2gO-}qdI&+!Fk$S|htpJM$UwLKsU304Zqt;HsFZT-1 z+irY4p$vu1UOAxBu)eKByO-Br93+<*N!!~|PcQam=MX+=W9VoiAM&Iy!TyUL)8WKc zlB?!AVWMMCnUK!~-+lOzrB}5h$TAt+OF~!9;@2&`)fyy#K(T~$4SkFe#PHGm3x$+i z1P_JRPz+XURf)8n08gGSZh%#YMyCB$X#uMkQxu4&0C$flbwFWeQ&U`zTJ84iwH|~& zmUYV$ZF}Gi?=T!As3;4@c?o6BA6=towR6_+bu#E6u8wm5aiMEm&Mv zj$pSHRTRWpm8x&>82$pPk!W$t)+$TP%T%n})vSBd*TeuttC4(T$vB;N^*PJjq7Zb4 zzi0$?C=KGKVG>RDSC}0ui~OM$x1<-O-Z?-^ct%;Ihk;kW_$zSCwcOYwPqa3)HS1D&uLSg7F&3Py*#Iqa)pZA;89jvp{p=*`;>beSTso9bCvM_TVN3}Uz3fSg%l2S(W0Xr2^SCSc$!9ChT~+={ z>UeZ=%S+mJ-*1^e7;;$5>Qni+JauZ+Ldh$zRV|c6~>GQ|2CW-g* z`?7Dqh-;#~dyGswFh4}Q&^U)R5&_5QnKVoHsskm`H*ge1g%F9x$#Ga`TmxhF8U1Ma z+`=&{XswjXi!|TKGA(_exREV=uy$80o>Ai9xb^uMl14H53SM!!&+ zP&q_Mi~14D_;bZK%>*UpDk8Y1M_Hu}u9`{YV~C=UCd=wL@KD7z{*d5o2~4U!-^!WT z^TYBh3v%IA)_8o@mpm5b9?zoHl^gaL*T-nV_CP}}bzcK7KS#%lo07`Qr%9INr^w!n zca%ZQ%mu9yQu@#j5qF5EECvx z>iM=G!TW}2W;NHIt2EsLwd|+s$PhH#ar$$#UB7^2WF*3e;?z)}YJ=s8KhXPp`d4aW zAWGwS4_Cy)-RVbOBC)0`$}FsJb-^0wWE!ui_q|mEIe8S+KhI;l@wjdByC=nNr-H;e z;`Dg)#5jgUE^hq{1kPL^vn{=0fs3ri$L<~>{+$Qj3<|B2Kmh=XvHqUr`lnLqWM*t_ zO!v?AAKK^YvbJli$lY+uuJ}&2)?`gsV9pWCwHcMtSp7DkxaR38YKnRMv*O-Zt9yQc zeQo-wfbAFbR#ekJ+MRMpHA5?bUQr&!B#-&@rY64Udlm>s`{r&HEv24MF#3^7-xId|MCJHE5_9C<3q;V>QQ<(Z15U-&RGcjCJD0&Jc>8j4cd&lVF0_3I? z8bhOjwZ8V&`>gXxz>U+yHF7Vxsm9rormBm>D`?L=W7X1`vu9&wHlW@Xm~6%$G#WNDdwZbsNyo;&VSPLfJo)f)TaRY2A*AJ5} z&1+8AphhRnxgS0fJfTwTYc#>O0ABgO{-BYEg>bhqM?%Cd zl&M8td(*xGO!J4JM92RkGYaqy+og>W4KSDhutn5Ls}<_f!kq1hy9be0T6?4KjYEL) zsLuBNI(<>RKYdBu3!RF=`*eCgp1JA6qoFa~p^XXL{gb-o^LVs`m(Q2&b9Z}#cHpMo z|Ml8O*8TqO&H>M8Mlcgem-GI3J`!2Y`|;5}L~?EI|5M~SPE3 zRszOO=#Em&jXg5Z;m|;(A4ktiZLmGkaHz3U{f9CWl*G{EMjX4rB@;Fkc3c{H!O?S4 z9OA{L{OPiD>}!A|ulzBt2#%DbG-Ck~SsZGli#f1Qdg=*um5WuqE1EMq)tpBtcAJD>J3gnzL`R+)LI>MLN=4}1)3L!Yt?9>K)af;ybQID;ZfmilyLib$HfJ0Op z-l>Q~8^ve=T+DXD8o*)M>EVdFI%MnNTfLdm^bE?N5^aj5M3`UND<;UNO$XOiR?VH( z%l)GXrcc7PI>B#nDaSb6kxvjt1GlITRf65+)0>*QxvB@Z14{=Y6d{zAScq$u8IxQZ zD{ivnhCnQ)`$f#1%|S3`>!AXjlh~Z%KJb!)Zu9BT(AZk|HR^%Ds(A7!u!5QVTRL~l z@%%*vK;ekAI~`^rlIE7&_n)KLtXQwu22`Q_7O}Ax*KN3yF<2ZJM9O-T4H)^((%Ti| zi`50f0?kYMDszHa>6#N^CJ}jkG^*+u%b8=n`>huAX_`o!Sim3fYON4MJ`$N{S*H>3+~TB2o=NO@|mH1v67Lv+~qQHCrgeTA>ds@o|q;DBI;P-^dcH@V>c296f z_7$*X5-$M4#QmNC7F7c#dy~ZP=BB!e??b<85~j>&2SJ zKq5`wTTJPn8;YC8?YG~IJuzGPcOUm&FFA=r@0{}c>0sz4LYZG&HaPM215J?6uN3AEmKS4Y2@n4_hBGYcjaF0;9^ zGx16Jd|79P;|$1BMFj(r&W^LG3Re6~Ne-sU{Cyr%X%FdYFo;CFoj_MrK9h#LxtsaxtAW{e?flyrnTX-cnpxS|8dd^(D^U!b?B@M)6LgDY%% zAo6MUQkIOc7{=@HJP7RWpI&5l|=9w9OEi4*kOGfVL&+_PbD16BeV z>qDhLb+M3HM1h{uCpJgTvSs9Qf#WgEw>CVp*_=T8cBapqvvgz+rU_l63J^AThuOe5 z0VZ1uI|6w$=y3()D;zr0ennBlfb=7ijU~U+En|MtroqbzknV;3CXqx4&Ml0_wh&|p zZac{^0CBD^f#Nt&RQ;rM*(ZF#q+vnE1t~840YGQhJU=bdH9KVZn8D4RVtak1)-lp< z_@enzM6^%cI|T1TxgSa33V2_tgLJMKEva=R4n%=&AdzEK_l}h6z8sviGAP<69w6)$ zq!i*J!V4WqkW}PV;wY=@$K@6$WuB9-^?^qyQf?PL$;MFKlY;0ff1Z_6CniA&tt%d<3=CVQfR?FID+ zf7?oJw=!?aD##e+dZnK_)paoOa@M-$SSBcuwq{sTs5*G7UGOH(*gfwP?Bv$Ey#hFw z30nrur_T$}7YCtMak*OyCk7ShWLx-2#`)BE;HN9i(PwuLr!ZgYeir%rApm}vixl{4 zQZJ-=JMU(7I2H5oX0|N~7%oRbZ8n8i3b0){x!86(6`X9qz~f4OdY)6MWqaD)1iu62 z%mMDlthR#{bX9XPwYn*Ru&kD5Rwp9^;prSZDf-t|c*9imsb>FJV4Ak#avkVm zFf2k}{Vp^#t0z9jv2eTEJT-Q8 zSyGI+-fU;3KjFK<1?aZf4Qqf7$PLG0pL!KkY|GgaVdul3OdUvXRSf#>gjpey*SF4_ z-u?+<+{su_lXS1^*sFX_>g6DQXWI_iVEgh;+w{B(?YV%yIH{RC+w~bblRe7vv1QGg z0-AEUSaBskzKxs)=Z)3684&Tt2w)Q^W*a5Py|rTx29x*Se!SsfKIkp` zRnq#XB#X}Wq=FbmXJx5JnYv`JRVHkt*)%q_e>8Ucz};mUnHcRexF3qt2?=a&j~HbV zpNVeTe%@5$ZFaxjjTKK_@qRvEY+NsVY?PfZSeU#ZGEk=`Mx}#@bP`!92|^MarDLJba%e(rPA?vf4n{%HT!zK zTp!-4;`w^K$bXK(;qiI9-HCi&74vm`zRwk>vTYRy@^<+0Y;ILo^L4mC?PX=}oXM(A z-rR)ZZFYLQe?C9T;_3Lj=aIeK-+oS@&3wJYUirLcPCf2iB+q?go$!6#&sA^wyk93~ z?mk^@cE8;=JI%JM;%)kTtns}+-^^ufb*G+vp3!%^XG~>%!exE-wKwPR`g}h3rB?4d zRV$P0-p!pAFF6!lb-jFMY4z$ns^;kUd^2C_Tbeq1b$WVjw^a!KoN7<)_Nw}PDyOsc z`D#ynqO@`eve zp7!4M`MTNjy~MlLwNt@2xas2_&U(#`#kXN=y>bH>mClJQ|Ri9(DnUlK1!XkHGbaj>&8s|NZ9i6 zqAQN`?Rveo$q7~XWb>8&`W$P&>VCgjYqx*3aBs;0%^mZ4U-OBc+bG}a_WHcdaD5xO z(&_w|JEFtmdk>uj<0{RzX_y=7zHpNL3a%eMB9XtfI`wk+((aI$`7NSZJmfH0TpjY_6I^$ZUjia)`0{=@mhtV@`y0CIeb{xd z_hPoU4{k3SvJ<$psQJl{2N{_?e4^`@F|u?qJ}=iNTfFWL_pgVIsZFov6Fi-dv+nny zE1yqp-w*Eft*x(J)wS;TH@>g6iyWVisjqs!t&Y!~cH7VQEZnB5Gq&olj* ztr^NlXsj3^mF@) znw~l(n&3}Y@X2z%Y4?({I%2vsy)(^1ezcDnrKH;@^o40uQl;A`!`mJL8(Jm6;RXXY zp~r(&+7-fhNS}&JxKxukRh8S9Ybgh-(>LdU%<*zuAAf3TXLIDu;^Izwv0ra_Y2sy2L>*iW$9QG3}4e;-3}nr6vlKJj!)fO7-MMdv?xO-}WD% zP8v)tc7#Iv(F{H?u8`W`4HxRm*CpKuJnK7r2(oY|&}Ip4g4GfSq0G64KkY~oF+`27 zLyT6x_RmKvXaQnGhj+-~-lkTt8=G>uONe;EQ z`m;~!`%E}wI(C~s?hdQZHLhc4qm9kk6j!xsFTIqbFoFj%ceszZ?%J&`O3X!!G?n`} zh-WGZ=!!Geay-B9&YfE2O*Wi2!Z#j6R9s_)+oF}uCgD$M7l9qU@b3LCvuNlfPZb@> z#Ez`gD>__h+qCamPe=A(dN)bwWV7r|BZmz;Y=f*qjv)9=vzCyL8~>F<_Vux+*tIf%RnK$%QFF zvGS@GBG=xQ1-Ynvr=>mV&yHLy^O z<|jf)%p6wnhBe(*a(J}E@JzJgnEub4%tiJK8&7SSv#n+)FB&_hf|R}(-l>>S8HGN- z>@02HR~j5$q6~sYTpmc#a(0|e4Fbs=4WMp>ztieV=5XUdtG^bAYCY%*vI<#ncpxhc zVN`G!jfHE&O+?2{#7V>ue3N%`98USRB#s8FIAyNZxL9(WKvTvlX%6$@n-A<--P5im z?23ayK6ah)-n_$dO6SnvUyN@nQ~p}1nQdx&8|39~qx~#8Y$8?}>h12*wupUu&_8(F zAk&HQ4SHi-Y&p?xtYd@pJ?e4K@>_12pBxWayi=Q9_#jc8_eOYDIw9Xi|=7f$YOml`KEE|83MKK^@rSxiU| zvu0+y9fZ1@K|XGs-QK(hCu$da^A6(eb-yUj{?1_OgA=!x{ow~9{sde>A z8Ui@kZ^CV_--Km``mz>Q{~5yZcgVr_kektZtaD=|-T9dE1tNlf`TLUA^r0n)o4dA_ zyRzK&pMLA=0M!2=<$r3OHvU80uDGv~07}*>PUxEt$xxg}O-D>!NG31fZ=AvHFI9U8%FT;IJCY zhN=2TF`*`_zk=QFI)yvCj*nGkE|Z(`b&0ZmtCpm=rCwi7W;AAL`G@UqFz{H7Mb44z zN3O-+HjsKr4jH;9{nb(@llBI_?x4Sl@BOa=e=Tl6EtcdC`tS4AvuVH)=*n2l3w3=@ z_*XVq)!{Te4Xm!efp?~Fn7wfW$#Exi*7vWe&d1B|GSj+Xd{;aXu|gv=SN^8J;ljx& z9D(U~pb1U>HJj`1l>39{yvn_k^R(7D*imw5=?B~2pjGm&p1L#(&U_KzQK`6ayVN;> z^WZ_`S-^tmZWHyL9;3F8y!D@SJnyqt;MmMkT3HdZ}icw{g-{f_su zzwvJI8>aMNeABz;XG~QpS*<)=Yn#0V502`SP0&zWIT`CIfhwC!W%1r=Ig>Z8P*wJF zN%6zW1bZW{%fo_u)h3gG{|=#|?0*=Bqv(p76x+U|)76UD{&|h{H!d<`O1Yp~hT=-e zSVsvI*<@&n4NoV3T-vj(pDnDckQe{8tOi%;)U%UO`59=>aCq)J@k++fY}ca{Rey3c zW`datT%&)7yC{dz__y}tVEgP)0mX3)WURvkMoa|>hTy~YsKBy+y`S`t_hH{|0}TUZ z|A+p8b0Rr{f7K7w`p4A=U_;6OYAAj<`KE*I@?R|zIYwn|XU(;+3ZFJRCSo5?sn8=0 zoGHfj&F~(O?#>1|5lWUaH)q72^?m#W3D;wKI_=&Gnh$M(WRIo8A4xE!4pwuO#9E-L zeU)35^;3b87#$Rtj9+Ap_V!bT_^R1RIEcF836oX*Y7gTW9V;lh^kO~n-1AG9fmOa=v2e1{& zO@3u~^tvuc#8x=6aL8>1xtl{Z<6S7TmNH9L`6FDeU$UT{2ul&*^+8(Se_N_@p;3}d zKVyMzLGz@pxTNM;?{!zIVy*R`jf!P6ZEWfM+Kpsc7CdGP*!WTnm?0XSB(f2ZU=0?U zoC_Y)l$Al@Dt&V0cWBcD1A#yqjeD8jUH>)N?}u9I{a+mLmU zq>s%!Mr*Lx68Mkt&GcfuTW5|v4u4D?e@~BM>z%s~qgy<9oP3r7;)&hgwV`ShI)4>7 znGOEK!qZDEcZ*;9pyJiPkix~oDh6xGJCb3>qFAU>XG;QM$8RzJ<=wlI2a^uYF{D*1 zVfd=C?sTfi45l{fHcqjhY%E=HOi`~Kb|TH}qOtC0b@G71NL&4OFol%0WCJ3phG*sZ zjHNM!9(Ee)Prlc;x!vCfm=WI|w5(3%@u;LOjQwW%6sCwPDfbEWr5A6a=S*6YZK>O; zN=9`?>)BPCctN!r$f~ODZz40anpK!3K;dnue_YGCl;3%I?-3QUwAa|Lmgi9u=J>L< z9!-$Wx_WXtgdb=mRz~RANq3M^EsGf;xHY?3*lw*Fi+~+FS)nl>=sGv>V-|?40OLCh z&_-c_r8g&%87KTX)$ceW2%RkmW(wfV6iOENtH2E9PyFj=p~FcpxPFThOz%tIs_A%a z_b?0PiN8UaDS$J#I(jv~_bjW2mJC$|3nvQx7SGj~d*7$oH<&r`Pnc!Qt>D7u6iE`q zm&nza&o38Oix<4Of1N~=rXl`?{6iXYgpVrpRwbU|78{+%Q;MUEFi%5Fm;yKtSx|n{ zfdM23C~v+n@@GT|Dx&=P0cdW?tZJ=(QO%vRd{R!=NKF4km<>i5)dGa_)IxiW==|p} zJbdGvy^Q?4hA;(`Fhx-EEvFQ<7LQ%qF9L)C8yonDTMa2{10K70Z%UEpFk7$VVmZxCKM3kXMO@3XmVolF`G@Je7At}dT z{=_q|KM`iDCli%Rf_dNmDTsT&t8skVp#v!da<-_{Je?QJ3*T7BpWbily=(`Ru5^qn zLPeCeIt2A6oq|@lerY2e6JLS}`E5;Kg3I;Kdew zU^41V#K8tsY~L<-UX^B(BYQAI@A$?#-~Yz4MZkvAgv)F)5o4}R!~*`+@nAx2&ttd$ zi(sZ-)CS({mQ#n?g~#slzwT8sD9CZrWF2M)hdI1>>|QyAeveqv*1kXV09u6<$XNXa zy_ztf4&t$c%=k}`Uy>5yx_DfWI$NLtP0$OXo8pFi?h_=aL%8g*6LDs{EUg00S^HcT zlW2tox##|hE70NOtPX(|@?)JxziQ1MdseJMgps*g1;|J1C)D^ow}V)P2qP-j@sST+ zOsI=^>|`>&RnhsYQWO*FA})0}4cmKdoOU@~*jg&L2enVI6}5YC=GG10(Ouu$)xoCY zvRZ>@&H7`y8%5?lsGf5_71RJ0Y4eMG*1=}|Zqh33ayBO4@TpQ)-)WdCY6KhfKzlX~ z=Z`ZssPLTdEm;p8cjH{QKDiFlONuY=&RbM8K7=hp`-5nZT_(`o4c)6Sl3B3GjGXY) zDc-%{o3*T|DXxA5tAI^zY^OA7H90=e8s%I4P_Pef&sUwa9j$aw46n z;9VG@8=aq043BU{})%OYfj%2@N?kf z)`9vDpBm;@#qI4D-E&7>&27j|!wshuCZNqV_gHr$vs8t2R^&= z90CLqkobrI@?fJf+;V>L5x2ZYROFH*mx@;rbZapDyd;pn8L3krcJKwZ3E=lF)07iv zE_pRXzY8Eb`8}PZM1~ASc9;SW&g7C%`3WR`L@{5R@bdl8<^ugqaV?*vd&IwIPav@>n6Y6_6(V^@oaD6A92C8VtG`Dt(7+T4-UuKB*a6t5b49 z-_C{q*2Y0&D~%NaJZ!c|1=UHR^m|#Ie`N&D>%gZ0c&*45tRGu)x8cw>dxwW(IieDrT;Jq_ia!ORQDvB zoW=6n#P1*yaX)Nz?eKFa<%}RS!}?x*F@o~A@79-~5acVpw+5X;G>ZR<3oh(Fm1jt; zR(-GG|Ia;T;rH&g`?0-_E;&uri7*gj)9VIbNR51uZVFkh%Qls1&G-38ll;%n+I+gr z*r{lWWL)@#)&JApclcxdz5jjdl{AyeWp&4oV)o_7Z5i2{snYQ= zhp-(R$t}^Zb{jAMK^v>4OP)7lKX1;f;b-)C{e;Mpk_mB1qZx8F!V**oT0}Ip(L+YNrxXDKH{y|d8rymdTsgUGidGZ%gwz2pNT93Aa?E-h*BUH8T44s>i-sfSni- z6K1&`uwoyL*-6BW2dWn86|#~FR&(uZH?d8G3wcs*ml+NO)*Sy~lv?X=V1k?{(6%k_ z^|^dnykqDG;->hWd9+<>b#*iii$T|vcX-s`ShB3K}>G5qAt($peb3mW2kNoZ{ zvQ=~lyN4iCL?iQ}SA&HotxoVDC=9giC}I7K0N@_lsy8y;$m*}5XuUS5_2S!P4kVOD5MYRUi)v*VMoV{#ScP)>->ih41;;&4Dn>wHMzEWCE- z;%XM z?qfad@0wJeZF#e@XhOYr1J*LO(!|cd_(qm2sK?${isqg9uNh~6vmdrqyuUK*_~Sm! z*WdFza>vKhAtVA@7yEMT;s{dQqm$lv3CHAH@*V!@{F1tA-i@M@VVaSZF+3_$muK~g zWeAcCp0nN$Hu#WZP+s^nh7&)&bw4d-RXe;^cPzwUWJLHi6nd01r8Rs$>Or}_h zbG3J%h{k%PQ_`;2(WhX>8vC5_>Fs9ir>>I|>b!^48noHHc#KY|vz5|9E;w zc->Zq%_W<3yF?0}-$HsUF1bY4Rdy7PYVh~o4<1GG7k{@H9d>u-9-9hTt-n)L`=)0- zC%bm6r%2yD&wY&rue6yBqjr3%lt3uL#3(=L8z>>0^XP>{{M~PPs)y5b8n|`>r+Oew zI=vOiALaPz{A354VOtSpU5`Lb&uOVr_{LE?54@ryGQTaYjcwUj(v^w|NKFd_;`i({ zm`pxCD=ZLOr@yqEu%E4u{_G|(#dzz7%KOS#WK;8eXN_)$d#N{y?D@6Wcu)GJP=gw) zl9p)^5aNBNpL&Yw^R-X6U3IJXgW0UQ*YgnvjZ#h}p=ul@2b}5^ikJB?Qd zYs2rl>I5X@5~}R9*Q3r3T-qAvX3BGn)26+Gu34hJ0^E`#yE0f-*)OCrRgnv$)Sfgw zbuO0{A6igJJZljb>IyM7X&SVIoCsf)ASEbdIYT?QwK8r+m*;4pO&bn#BqyZShAf^| z!dMC_O)I+QLwih)fMRXI05@$^{lpIA)IEhIuN`a)Ehl1{?I`@n1ZI_L?0|3e;+aGp zit_spByzfdK@xjC&P{vPS>e?~J;Wh1ALQa})!k$PLSfBJvi|dT5l{?Nq}=UHEIH3K zbFR`I0_Eg>m2)Iy z(FtRL8`9N!Is0cKZoKL1DZ2HEF8H#vHL3lwfQZF`RCFCpTdIzG;7$EN4UMt0zr5`M z3-C$%ne5H#liG%=siJ!PGQxVxC0hC8E#!#H*ZHzybS2os5s9Pf(=KOUs^#(4O@s^$ zCfZ#tbgJ^>;L|tG8#d}yuVm#&2q@D#AcyG_C!P+=TZ7-uAFrbX0*Ve#Ch!5=CqU!E zbaWlciP2g7BOb>QbPDLO93AVC^BD1mTKms+{3-F!r*d@Kv^Ocf4zi$nBqV?6XRHA~^xJ>F#zAz|pYdBs3CzQCgq_K%ei-p^_MKLxI-__sMek?kjU*P^OObMz z63x59tx7589DNnWT0WOLOZ0!qH55<}c=aajTVp8^pOtBL_`{rY>i3vV zK*Di?C*M?D@|8;w!>3e9Ar>XQ#}wAu6nbs)(@aA}lZ28$bfsgDp#U5O>oe(W-%d<% z=p?Qn=}<~}E)6n=diN%cXHvzlo(O8~!>Z9KgGQ7re5=kjsAF2ddV1nz5g z+&s)2)09LzwPIe?%vNE+x-ckBIqLd-!v1QdKMVJiPEM0W^Z9dIIuFWm4=oFjja?Le zQf%~7k>*vUjB*K&z5juZ+T3xcQ}L_$S^$HFyGVXwO%7~u71el7ecF_|hj7KWTrjFd zB+;ni`|4_31$o)-bUr~xahc!`>CwCPTXaw1zXL|~k_x}O^?6gYQ(W>(tEdzDnVwg> zh=PYerxYhwr&~0h12d#hoRpDN(A7Hmo?n2U%6iLd5sb%GFvGkY`7mPjejG^?J`@_n z<-8ppS5q9U31A$9^C5}sLrR5WnftEVeKBADGogN1qtfPMi=S- zVSe5qPJK6Xeq5(1r+qt(7z8y@BJ`2#nR*rnB6h0N&%Jg@B?^w3pHO&ZQT3mP>g`Hmy$5D78 z)@~>mSal<=kqB2xfg7;mn7L&D5COrMSgnI97hCVeYM( zkrNFRh|h=`m==y4%)UvWUdGe5>*D|rO?#;UP$VnLKKcsVBQL4;izL(n+*7Qk(nXzTG#ZsddQgcifUCP!fuR z^*XW5tVa2U$4!^|)8mSrS*C-RIS@vMyn|Sj(MEUGycVyA8!8B92?G5cjKW-eXpcN- zTcsROrNT!oIpJN4ELPyNX%weT8YvW{C9Y4Z!?|UR)NcqjHj(01AdzKdn3q?b^VSz(lh!osrw;WM*%eVr zZ!NsOI6Az6qn!fqYIa$7()_CgnTrKWPl>9y<+ij`XdS`q$dAExYXg0&(2Bk=^VDXZ zLfS!c*hv2E{0r55zi@S7zS3s*meFTX^rYr{Ze0kc5i(H^2-|p~9J6>wxCwq?^4QLt z;#rT1H&e+Y4wb3;F)a{FuV*|EMlr@4;_shne9J_3wqh+YP5uEUkf!VF+9bJ%L6lim zlSn7$O#EEKV0*9i(^oLdfuP%3MHemzIyc7i(i2~oD*FKcW;%Mp#A<{D5A{kRTV&Si z6Y5&;?3D5=M=*@G_kj}2dA-Vw-pD$b8#r7bkyDwV-lFOVF6g7I@#B3HOwxRDPZ~*?&p+>F|o0(Gwkk zb8Sy4LC{S*S88cNwHC4dmJ^ZDvPk>O{?|K10HLv7qBWKU^dk{oLJZYfA0UMkqkk4V2L;vz^kRCxquF_#oH*UwJT6K=pF&Oxu8Jq= zOD1eUAg?oQ;N)6gk=S#ya}k71Jmg-Y=iDtWuMsw}n<`Q+;jKKmP)}=jSy3hv5EjpN zARmULH)r2+#Y$yW)^~c4w_gAdvXbvJjA{!;4qF_1EQpk9=a1Y8On?(*xXTNBW)d$= zmM>N|y;?GU&3AV`HIG6SA&#{8v;ac%^Yq#di!5ITfDb2dL#J!MfyVz!PAjZVZtAj;VR z;K&`V;>?^b$rUD4{xksxc%FJj5%53znhaoSqO3{C+P(lBBmrRfU}wO7T$1Z9L89HN z$-Ev(x6*ZDC>dwP;R@F)*|gfdm3bl7>5&Bh?Q~sa+STrNa%kg&Bt$Ln!p~4*Vr6lc z%FP!HQw*1`p~tZT2+~}i*w1@y z0p=*E;8o*+1>WpL@GIq4F<|v>lO--++<(8P2bY#MfiXg0O`_z^;(r_YxWDp!#ZcM| zO0|AmI2_8A<(fS zcxL6|{vy!G|B}f*{cnw?r}lkf2^|x0eZX8qeF!cXIPJfA+6AtA$t0hi4`UBZ2uM20 zg|P+$i{N(tu*j0tPc*Bv!y-eUl_5Y#0-$4I*8u>QH~*lapU3Ps zbG91c48Tx7V zJE0yCj>NKyRlj`lw%Mm{Bhn1@^p^4XqF4Ex`J8f>VxouT*)-(y0{>BpDEDi=6w3 zuq5{f5BLq>DN-iFbibzM=wcM`cU~w;Pf-wsz>r6a57$tFOGoSttaxT&nfsx|z)l&-WMn2NwH9J%A> z{2&1m?j!04wcpj^0(*GdLaDUwGf`oz$q^ip0$dj`jL>QSkv2yOI-^jylq@L4ekNS!6pj;c5tIkuS2*iV!TbJqCX zFhrq$+ZT71!&fF;PtGlDH9nZlsZRwSCK&7r9pqY+vWj)j{YcPduD32!YbDfoMOms? z4@8UnTsA0GvuU1>v}>fKSvUB`>%lI-PfB5L;VYZJd)7nUCQ*)}T4$;eg(C=|oNLL7 z1m#bKAFYsVohB8t>3YG+zQw*&?J%&52yVEK=~-7EW1${oQ-O`}@#Pb!>?;_Or&Tlwp?~sq0};QEi%hLEuA_@;aM7Yo z720O^?w^|tZw`{6Dq~*hMHXLEZ(WB-d1htb{yGCUYEF3WJ818Z0=0DpB@VC!K zmh%3fk>-(h%mDAxnV^Ydy;SwH;Q%A8z*NnZR()Wp!k`wCl<5NCjIs|*RNuy9aHy^{ z#IH<8k$`A}mYg2wvVl}A08*R}UlNlkoa|H^5Bu;%DQmD?Y74s6#=u+v1p&4lH9*92u1cbqO% zFGt|IV>FNnen*+YXC;KbRTo3T!A9BJ#n$K0x|T=pn(lu*Jh2ZIYu>X=S|*X*|8U)u z{t$Q7s++&IN};xW>3dvpiB@ypI(2U{pJ~#-*6mW(ExW@jD_xgu68+jfnkj!@lr)1! zG#GZ!y1RdzYGp60I{PDAf1ONm5BV;}(ttrNFOq;2y+mimOnS73uG=Y`B86MC6XFf? zIot|H8^{|x-PCclRr+U3&Ua14f@vHxR0?+Ek&QI}?7ZW8U`dIlaKgqHxzh93YE4u< zSRM%^5{*u3J71vkOLy>xS!!7O%F60SZ)RUZW&_n75^-1NNUF3}CkQPkQFA#=1Y1Zi zmk2_a#DFqnelWSJc=GB+>L;fup7=D%!z)wDh6d4g^$7~sb;t+`!*cZ2V&vdWjfQXr zl}1sX&54uf(CO85l&bZ zP`3!0#pJeH>y&l}>9rjtPxV_wV4^``yjUwkqe<+Z$hKcP8QN#95H<4wBht>JFHi!v zzZ6?i{MZ{d;`+|;oOk7|uc^Ztn!T#Q!${4Ix-KINc}sMb#xXUnHo{WjOVA_%lQby!K75D-`6K`Co^7m{p{7qNX0!-wkdj}9QHKHz%Hpm9O;T<*te%c77YD!u>} zF&|3P4{U`a9TZi~p}CR_bB&fd(`Xew1giir@Xxz*4yq&JZP8`3#uJ%!tuVtzOhR@8SmKiWUYvK#m3(yB9GcgNDDWlX_9F6^+hgAd$=y{?!7I z#1_T%grQgVpCrk^Ezh&*sLF&*3v+8qu+=#u!_L@ON#qPeU0uT95B{n5$NSPflNQQ)emUCn!gKk|FrL`mY#&XD3Add5+*yiK(p2bV?Oi=q#FWF8w|OqZ=X4W)Z513 z@EBLtbQAVGv674z1#4x^rUKTcFyXWW2qVD>7LJ~nsg9u`66HMQgva8)2*`A2uhPnz znxR+J|3vlQ#VJ;;V$f*dCg@a`@g*La?PaX3m_1ye6r7NllnCck9Rw!0^XaIeu`%!o zw(KZ>M)klqgoH6`FOP6Uvd937z@lb|vW4P&wdzl_ft(oD>c|6HP@8zN`hQIU^Kjtnim9;K~zKK84z_a=n_ zT8|l@4^YNZLTjUj_$EsWVk3fhVn@3rhzy=1Huht_<<5PtjuBQ3k#X?qdWZ2J8i9vfeUBFxEJy#L?#dl|b?;oUo$_|Fmm=72 zk*{52);swA=@7a5SY#rZy*&ZR4|e>lmaT44hA&?@ySCFhX876!bg55M7n~CFfT5b9 z#}p+G=rh2x$)S(71=}R_cc{xgqU6^SLvWD8t?V9*tKK;~Zx3HAbt|DIY8E9?>h|a9 z&2G@CuJ?XM7#azDH zM13xCXcRxG6zrpJ2kZsJDEB7DCeGS;LvAj1ePT+{97@844~Ye)9+*HLd3?}L?~Xm( zxD5DNmzfNYv4R7mVS`ag-5MfQ82~M0u9eubt3dU19&lr?7pps9YVfnBqVHLRLhWUft~{lRi7X zeu*jupQ(jD4)HZU=qJ~oQu|Hgcod+0e{wN^Nat%dj(g4~8(h~{bbrtg9E%eP=gOY* zukMXzmTOY2N)EM_U)WE#>?H^07EDLtEPA0_c-}%DrNGZxprEF(OYdgl;TOnwv zo}8S@U%HPgl6k}_W;cAMVV~mWCyx6Sju_RlMsWep>rd>o^Bbkz`)_(G^NCsPmAw-i zY?Vrl@ez%iD_bn17JGBo@mAOm@ma;|RP>|O=@a4~tlHg`j?K+;1GVfzhUgp&`CaBW zS=)4+oT@l2c=MFy-RaEDOS@91B0ojmNX3g4I zEz`mPpoG~t#%~3bs1}^U6E&3rjbZhg5ZDqg28M71}j7Q?9 z@1KbJzz(Z@+|&IvsqVo$Ddb=16*rY;`{q8mx6y2A`@tf(fRgRU&35L}N8$pE$Zl-Chcu&e(WX?K-1+UkU&C za~n6o*&(KV?3tWnx^yuE!h#uULQ?0bvsIV zdzVd#o$@Wue>Pn_43ZGk|N1teD-FLk$ItM|e$L)^vonEfQE$5g|L5o0L*+{~<-q-0 z+Tg7mD)8RYEoYRLi}P()A(XR=<*&B{|Nk>fpzHkNwAI>#X+z%;{!r}pO}mA91NH5Z5F(Q4{%QsC&7D=)9vWaVKZlQZg zo9WVa*^~!d1-z$ix?WSU7%$XI6bh?fphr5OUhbc|L3?HLytzot4o)~aV?1P5@FY2F zyD5rpXU0y=;o0si*L$WjY9%jSyJb3Ag~iWOWjxf0zOv!C!p1=ucAC~^P52t@`-V?N zkE!EgVuY^#cbnEUjXO^rcu(AMW4|GGdaCZ)q&NH7k56||2j3KiZM*sI!IAmcj&&Y$nyaiu8Kh?SoUOaNMbkVhR zbAz5f68h`+^MV$(P8Qje!d1f6(|C_(zO@8pJPL|8r>{S$dWzsI!6n5LXK5aWJ&Yyg zrkxBa$)M`N!>Y@X=KdhS(__>C3-^Dt!cD0U76JZ51>R7j{LeLQe*5W5*}x^XV^~kn)Gkpho3q}WA_1d7r}yu$@so2@93ibup5t_ zg{p#DK->6gL|y2>`{22k2pU)G@TsQcO560%1DkhJ#OKO;*W>RI$QR_aAl8B`5I43q zU*x#g5U|Ux#YP0x?#IP>j#9qU3G@_KjV7a`AR<9_KQBmeBH0$WB(<#5?Oj|q>SgE( zPIRkktxIb?xEY3ajP5Pa*DPj(V{T+0VC);|F`6O5@AYyeCQ{|1#m4ikO8gai_POS- zJKzx~-fFwR()-*K*=W+tLU!ZE>HBw2-V0T0&p1o5n>Uf7{(}QK5TP0t;n_Mt?)N6u zwdHG%-w^x6$~YHIEWGLZyBl7Zr!`SKVee}OdUGc0xE1?_ZVwF-Y;~pe1rQt6bAQT_ z_5MyD))|-?@C=C)>`9Az=Ps_h{w;aS84SeFMTCbh0A33F-%s5B9MvIzm@rO5zpUJ{_W`ek#X#p#_eOr{>$z8yZGM*>yH48 z%TXi#WxoC{{kL8CQ##%CsPtb};eT3*zlHuA=KqL1c8t^QKQ#IU`dVs)UXV M1s1`K2lU(j1EUnr8~^|S diff --git a/SpaceCadetPinball/SpaceCadetPinball.cpp b/SpaceCadetPinball/SpaceCadetPinball.cpp index 2fb6f8d..ba9a1f9 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.cpp +++ b/SpaceCadetPinball/SpaceCadetPinball.cpp @@ -7,6 +7,7 @@ #include "objlist_class.h" #include "partman.h" #include "DatParser.h" +#include "gdrv.h" #include "loader.h" #include "pinball.h" #include "score.h" @@ -18,8 +19,11 @@ int main() std::cout << "Hello World!\n"; pinball::hinst = GetModuleHandleA(nullptr); - char cmdLine[1]; - WinMain(pinball::hinst, 0, cmdLine, 10); + char cmdLine[1]{}; + //WinMain(pinball::hinst, 0, cmdLine, 10); + + auto dib = gdrv::DibCreate(8, 1, 1); + gdrv::DibSetUsage(dib, 0, 1); objlist_class d = objlist_class(2, 4); for (int i = 0; i < 100; i++) @@ -35,17 +39,17 @@ int main() auto datFile = partman::load_records(dataFileName); assert(datFile); - assert(partman::field_size_nth(datFile, 0, String, 0) == 43); - assert(partman::field_size_nth(datFile, 2, Palette, 0) == 1024); - assert(partman::field_size_nth(datFile, 101, FloatArray, 4) == 32); + assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43); + assert(partman::field_size_nth(datFile, 2, datFieldTypes::Palette, 0) == 1024); + assert(partman::field_size_nth(datFile, 101, datFieldTypes::FloatArray, 4) == 32); - assert(strcmp(partman::field(datFile, 0, String), "3D-Pinball: Copyright 1994, Cinematronics") == 0); - assert(strcmp(partman::field(datFile, 540, GroupName), "table_objects") == 0); + assert(strcmp(partman::field(datFile, 0, datFieldTypes::String), "3D-Pinball: Copyright 1994, Cinematronics") == 0); + assert(strcmp(partman::field(datFile, 540, datFieldTypes::GroupName), "table_objects") == 0); assert(partman::record_labeled(datFile, "background") == 2); assert(partman::record_labeled(datFile, "a_bump1") == 372); - assert(memcmp(partman::field_labeled(datFile, "table_size", ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0); + assert(memcmp(partman::field_labeled(datFile, "table_size", datFieldTypes::ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0); //loader::error(25, 26); loader::loadfrom(datFile); diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index c05b169..5bcbfb4 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -157,6 +157,7 @@ + @@ -200,12 +201,14 @@ + + @@ -253,6 +256,7 @@ + diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index 7b6d392..514302a 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -162,6 +162,12 @@ Header Files + + Header Files + + + Header Files + @@ -302,6 +308,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/SpaceCadetPinball/TLight.h b/SpaceCadetPinball/TLight.h index b824302..e60d80b 100644 --- a/SpaceCadetPinball/TLight.h +++ b/SpaceCadetPinball/TLight.h @@ -4,7 +4,7 @@ class TLight : public TPinballComponent { public: - TLight(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) + TLight(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true) { } }; diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index 63f4344..cc777b2 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -2,6 +2,7 @@ #include "TPinballComponent.h" #include "loader.h" #include "objlist_class.h" +#include "render.h" #include "TZmapList.h" #include "TPinballTable.h" @@ -9,75 +10,69 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool { visualStruct visual{}; // [esp+Ch] [ebp-6Ch] - //this->VfTable = (int)&TPinballComponent::`vftable'; - this->MessageField = 0; - this->UnknownBaseFlag1 = 0; - this->UnknownBaseFlag2 = 0; - this->PinballTable = table; - this->Unknown7 = 0; - this->List1Bitmap8 = nullptr; - this->List2Bitmap16 = nullptr; + MessageField = 0; + UnknownBaseFlag1 = 0; + UnknownBaseFlag2 = 0; + PinballTable = table; + RenderSprite = nullptr; + ListBitmap = nullptr; + ListZMap = nullptr; if (table) table->ListP1->Add(this); if (groupIndex >= 0) - this->GroupName = loader::query_name(groupIndex); + GroupName = loader::query_name(groupIndex); if (loadVisuals && groupIndex >= 0) { int visualCount = loader::query_visual_states(groupIndex); for (int index = 0; index < visualCount; ++index) { loader::query_visual(groupIndex, index, &visual); - if (visual.Bitmap8) + if (visual.Bitmap) { - if (!this->List1Bitmap8) - this->List1Bitmap8 = new TZmapList(visualCount, 4); - if (this->List1Bitmap8) - this->List1Bitmap8->Add(visual.Bitmap8); + if (!ListBitmap) + ListBitmap = new TZmapList(visualCount, 4); + if (ListBitmap) + ListBitmap->Add(visual.Bitmap); } - if (visual.Bitmap16) + if (visual.ZMap) { - if (!this->List2Bitmap16) - this->List2Bitmap16 = new TZmapList(visualCount, 4); - if (this->List2Bitmap16) - this->List2Bitmap16->Add(visual.Bitmap16); + if (!ListZMap) + ListZMap = new TZmapList(visualCount, 4); + if (ListZMap) + ListZMap->Add(visual.ZMap); } } - if (this->List2Bitmap16) - int listVal0 = (int)this->List2Bitmap16->Get(0); - if (this->List1Bitmap8) + zmap_header_type* zMap = nullptr; + if (ListZMap) + zMap = static_cast(ListZMap->Get(0)); + if (ListBitmap) { - /*listVal0_2 = (int*)this->List1Bitmap8->Get(0); - v24 = *(int*)((char*)listVal0_2 + 29) - table->UnknownP49; - v15 = 1; - v25 = *(int*)((char*)listVal0_2 + 33) - table->UnknownP50; - v26 = listVal0_2[3]; - v27 = listVal0_2[4]; - if (List1Bitmap8->Count() > 1) + visual_rect bmp1Rect{}, tmpRect{}; + auto rootBmp = static_cast(ListBitmap->Get(0)); + bmp1Rect.XPosition = rootBmp->XPosition - table->XOffset; + bmp1Rect.YPosition = rootBmp->YPosition - table->YOffset; + bmp1Rect.Width = rootBmp->Width; + bmp1Rect.Height = rootBmp->Height; + for (int index = 1; index < ListBitmap->Count(); index++) { - index = 12; - do - { - v16 = *(int**)((char*)&this->List1Bitmap8->ListPtr->Size + index); - v20 = *(int*)((char*)v16 + 29) - table->UnknownP49; - v21 = *(int*)((char*)v16 + 33) - table->UnknownP50; - v22 = v16[3]; - v23 = v16[4]; - enclosing_box(&v24, &v20, &v24); - index += 4; - ++v15; - } while (v15 < this->List1Bitmap8->ListPtr->Count); + auto bmp = static_cast(ListBitmap->Get(index)); + tmpRect.XPosition = bmp->XPosition - table->XOffset; + tmpRect.YPosition = bmp->YPosition - table->YOffset; + tmpRect.Width = bmp->Width; + tmpRect.Height = bmp->Height; + maths::enclosing_box(&bmp1Rect, &tmpRect, &bmp1Rect); } - v17 = this->List1Bitmap8->ListPtr->Array[0]; - this->Unknown7 = (int)render_create_sprite( - visualCount > 0, - this->List1Bitmap8->ListPtr->Array[0], - listVal0, - *(int*)(v17 + 29) - table->UnknownP49, - *(int*)(v17 + 33) - table->UnknownP50, - &v24);*/ + + RenderSprite = render::create_sprite( + visualCount > 0 ? VisualType::Sprite :VisualType::None, + rootBmp, + zMap, + rootBmp->XPosition - table->XOffset, + rootBmp->YPosition - table->YOffset, + &bmp1Rect); } } - this->GroupIndex = groupIndex; + GroupIndex = groupIndex; } @@ -87,25 +82,25 @@ TPinballComponent::~TPinballComponent() if (table) table->ListP1->Delete(this); - delete List1Bitmap8; - delete List2Bitmap16; + delete ListBitmap; + delete ListZMap; } int TPinballComponent::Message(int message1, float message2) { - this->MessageField = message1; + MessageField = message1; if (message1 == 1024) - this->MessageField = 0; + MessageField = 0; return 0; } -void TPinballComponent::put_scoring( int score1, int score2) -{ +void TPinballComponent::put_scoring(int score1, int score2) +{ } int TPinballComponent::get_scoring(int score1) { return 0; -} \ No newline at end of file +} diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index 434b550..42ded2f 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -1,4 +1,5 @@ #pragma once +#include "render.h" #include "TZmapList.h" @@ -19,8 +20,8 @@ public: int Unknown4; int Unknown5; int GroupIndex; - int Unknown7; + render_sprite_type_struct* RenderSprite; TPinballTable* PinballTable; - TZmapList* List1Bitmap8; - TZmapList* List2Bitmap16; + TZmapList* ListBitmap; + TZmapList* ListZMap; }; diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index 0c3a498..b5304da 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -63,8 +63,8 @@ public: TPlunger* Plunger; TDrain* Drain; int UnknownP48; - int UnknownP49; - int UnknownP50; + int XOffset; + int YOffset; int UnknownP51; int UnknownP52; objlist_class* ListP1; diff --git a/SpaceCadetPinball/TSound.h b/SpaceCadetPinball/TSound.h index 9f8074b..3a3a3fe 100644 --- a/SpaceCadetPinball/TSound.h +++ b/SpaceCadetPinball/TSound.h @@ -4,7 +4,7 @@ class TSound : public TPinballComponent { public: - TSound(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) + TSound(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true) { } }; diff --git a/SpaceCadetPinball/TTextBox.h b/SpaceCadetPinball/TTextBox.h index 2a66046..bf27bcd 100644 --- a/SpaceCadetPinball/TTextBox.h +++ b/SpaceCadetPinball/TTextBox.h @@ -5,7 +5,7 @@ class TTextBox : public TPinballComponent { public: - TTextBox(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) + TTextBox(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true) { } diff --git a/SpaceCadetPinball/TTimer.h b/SpaceCadetPinball/TTimer.h index 985e43b..6ed87a1 100644 --- a/SpaceCadetPinball/TTimer.h +++ b/SpaceCadetPinball/TTimer.h @@ -4,7 +4,7 @@ class TTimer : public TPinballComponent { public: - TTimer(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) + TTimer(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true) { } }; diff --git a/SpaceCadetPinball/gdrv.cpp b/SpaceCadetPinball/gdrv.cpp index 846ea09..5d7ab17 100644 --- a/SpaceCadetPinball/gdrv.cpp +++ b/SpaceCadetPinball/gdrv.cpp @@ -1,6 +1,160 @@ #include "pch.h" #include "gdrv.h" +#include "memory.h" + +HPALETTE gdrv::palette_handle=0; void gdrv::get_focus() { } + + +gdrv_dib* gdrv::DibCreate(__int16 bpp, int width, int height) +{ + auto sizeBytes = height * ((width * bpp / 8 + 3) & 0xFFFFFFFC); + auto buf = GlobalAlloc(0x42u, sizeBytes + 1064); + auto dib = static_cast(GlobalLock(buf)); + + if (!dib) + return nullptr; + dib->BufferSize = sizeBytes; + dib->Width = width; + dib->PaletteOffset = 40; + dib->Height = height; + dib->Unknown3_1 = 1; + dib->Bpp = bpp; + dib->Unknown4 = 0; + dib->Unknown6 = 0; + dib->Unknown7 = 0; + dib->NumberOfColors = 0; + dib->Unknown9 = 0; + if (bpp == 4) + { + dib->NumberOfColors = 16; + } + else if (bpp == 8) + { + dib->NumberOfColors = 256; + } + + auto pltPtr = &dib->Palette0; + for (auto index = 0; index < dib->NumberOfColors / 16; ++index, pltPtr++) + { + *pltPtr = gdrv_dib_palette{ + {0}, + {0x800000}, + {0x8000}, + {8421376}, + {128}, + {8388736}, + {32896}, + {12632256}, + {8421504}, + {16711680}, + {65280}, + {16776960}, + {255}, + {16711935}, + {0xFFFF}, + {0xFFFFFF}, + }; + } + return dib; +} + + +void gdrv::DibSetUsage(gdrv_dib* dib, HPALETTE hpal, int someFlag) +{ + tagPALETTEENTRY pPalEntries[256]; // [esp+4h] [ebp-400h] + + if (!hpal) + hpal = static_cast(GetStockObject(DEFAULT_PALETTE)); + if (!dib) + return; + int numOfColors = dib->NumberOfColors; + if (!numOfColors) + { + auto bpp = dib->Bpp; + if (bpp <= 8u) + numOfColors = 1 << bpp; + } + if (numOfColors > 0 && (dib->Unknown4 != 3 || numOfColors == 3)) + { + if (someFlag && someFlag <= 2) + { + auto pltPtr = (short*)((char*)dib + dib->PaletteOffset); + for (int i = 0; i < numOfColors; ++i) + { + *pltPtr++ = i; + } + } + else + { + assertm(false, "Entered bad code"); + char* dibPtr = (char*)dib + dib->PaletteOffset; + if (numOfColors >= 256) + numOfColors = 256; + GetPaletteEntries(hpal, 0, numOfColors, pPalEntries); + int index = 0; + char* dibPtr2 = dibPtr + 1; + do + { + char v9 = pPalEntries[index++].peRed; + dibPtr2[1] = v9; + *dibPtr2 = dibPtr2[(char*)pPalEntries - dibPtr]; + *(dibPtr2 - 1) = dibPtr2[&pPalEntries[0].peGreen - (unsigned char*)dibPtr]; + dibPtr2[2] = 0; + dibPtr2 += 4; + } + while (index < numOfColors); + } + } +} + + +int gdrv::create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height) +{ + char* bmpBufPtr; // ecx + gdrv_dib* dib = DibCreate(8, width, height); + DibSetUsage(dib, palette_handle, 1); + + bmp->Dib = dib; + bmp->Width = width; + bmp->Stride = width; + if (width % 4) + bmp->Stride = 4 - width % 4 + width; + gdrv_dib* dib2 = bmp->Dib; + bmp->Height = height; + bmp->SomeByte = 2; + + if (dib2->Unknown4 == 3) + bmpBufPtr = (char*)&dib2->Unknown3_1 + dib2->PaletteOffset; + else + bmpBufPtr = (char*)&dib2->PaletteOffset + 4 * dib2->NumberOfColors + dib2->PaletteOffset; + bmp->BmpBufPtr1 = bmpBufPtr; + bmp->BmpBufPtr2 = bmpBufPtr; + return 0; +} + +int gdrv::create_bitmap(gdrv_bitmap8* bmp, int width, int height) +{ + return create_bitmap_dib(bmp, width, height); +} + +int gdrv::create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag) +{ + bmp->Dib = nullptr; + bmp->Width = width; + bmp->Stride = width; + if (flag && width % 4) + bmp->Stride = width - width % 4 + 4; + unsigned int sizeInBytes = height * bmp->Stride; + bmp->Height = height; + bmp->SomeByte = 1; + char* buf = memory::allocate(sizeInBytes); + bmp->BmpBufPtr1 = buf; + if (!buf) + return -1; + bmp->BmpBufPtr2 = buf; + return 0; +} diff --git a/SpaceCadetPinball/gdrv.h b/SpaceCadetPinball/gdrv.h index 70a44dc..10312aa 100644 --- a/SpaceCadetPinball/gdrv.h +++ b/SpaceCadetPinball/gdrv.h @@ -1,7 +1,93 @@ #pragma once + +union tagPALETTEENTRY2 +{ + unsigned __int32 PltInt; + tagPALETTEENTRY Plt; +}; + +struct gdrv_dib_palette +{ + tagPALETTEENTRY2 Color0; + tagPALETTEENTRY2 Color1; + tagPALETTEENTRY2 Color2; + tagPALETTEENTRY2 Color3; + tagPALETTEENTRY2 Color4; + tagPALETTEENTRY2 Color5; + tagPALETTEENTRY2 Color6; + tagPALETTEENTRY2 Color7; + tagPALETTEENTRY2 Color8; + tagPALETTEENTRY2 Color9; + tagPALETTEENTRY2 Color10; + tagPALETTEENTRY2 Color11; + tagPALETTEENTRY2 Color12; + tagPALETTEENTRY2 Color13; + tagPALETTEENTRY2 Color14; + tagPALETTEENTRY2 Color15; +}; + +struct __declspec(align(4)) gdrv_dib +{ + int PaletteOffset; + int Width; + int Height; + __int16 Unknown3_1; + unsigned __int16 Bpp; + int Unknown4; + int BufferSize; + int Unknown6; + int Unknown7; + int NumberOfColors; + int Unknown9; + gdrv_dib_palette Palette0; + gdrv_dib_palette Palette1; + gdrv_dib_palette Palette2; + gdrv_dib_palette Palette3; + gdrv_dib_palette Palette4; + gdrv_dib_palette Palette5; + gdrv_dib_palette Palette6; + gdrv_dib_palette Palette7; + gdrv_dib_palette Palette8; + gdrv_dib_palette Palette9; + gdrv_dib_palette Palette10; + gdrv_dib_palette Palette11; + gdrv_dib_palette Palette12; + gdrv_dib_palette Palette13; + gdrv_dib_palette Palette14; + gdrv_dib_palette Palette15; + char BmpBuffer[1]; +}; + +#pragma pack(push, 1) +struct __declspec(align(1)) gdrv_bitmap8 +{ + gdrv_dib* Dib; + char* BmpBufPtr2; + char* BmpBufPtr1; + int Width; + int Height; + int Stride; + char SomeByte; + int Color6; + int XPosition; + int YPosition; +}; +#pragma pack(pop) + +static_assert(sizeof(tagPALETTEENTRY2) == 4, "Wrong size of tagPALETTEENTRY2"); +static_assert(sizeof(gdrv_dib_palette) == 4 * 16, "Wrong size of gdrv_dib_palette"); +static_assert(sizeof(gdrv_dib) == (10 * 4) + sizeof(gdrv_dib_palette) * 16 + 4, "Wrong size of gdrv_dib"); +static_assert(sizeof(gdrv_bitmap8) == 37, "Wrong size of gdrv_bitmap8"); + class gdrv { public: - static void get_focus(); + static HPALETTE palette_handle; + static void get_focus(); + static gdrv_dib* DibCreate(__int16 bpp, int width, int height); + static void DibSetUsage(gdrv_dib* dib, HPALETTE hpal, int someFlag); + static int create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height); + static int create_bitmap(gdrv_bitmap8* bmp, int width, int height); + static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag); +private: }; - diff --git a/SpaceCadetPinball/loader.cpp b/SpaceCadetPinball/loader.cpp index 3ffb67e..fb7ba3b 100644 --- a/SpaceCadetPinball/loader.cpp +++ b/SpaceCadetPinball/loader.cpp @@ -1,10 +1,9 @@ #include "pch.h" #include "loader.h" - - #include "memory.h" #include "partman.h" #include "pinball.h" +#include "zdrv.h" /*_loader_errors dd 0, offset aBadHandle, 1, offset aNoTypeField, 2, offset aNoAttributesFi @@ -91,8 +90,8 @@ void loader::default_vsi(visualStruct* visual) visual->Unknown2F = 0.60000002f; visual->FloatArrSizeDiv8Sub2 = 0; visual->SoundIndex2 = 0; - visual->Bitmap8 = 0; - visual->Bitmap16 = 0; + visual->Bitmap = 0; + visual->ZMap = 0; visual->SoundIndex3 = 0; visual->SoundIndex4 = 0; } @@ -107,7 +106,7 @@ void loader::loadfrom(datFileStruct* datFile) { do { - __int16* value = (__int16*)partman::field(datFile, groupIndex, ShortValue); + __int16* value = (__int16*)partman::field(datFile, groupIndex, datFieldTypes::ShortValue); if (value && *value == 202) { soundIndex = sound_count; @@ -170,10 +169,10 @@ int loader::get_sound_id(int groupIndex) sound_list[soundIndex].Volume = 0.0; if (soundGroupId > 0 && !pinball::quickFlag) { - __int16* value = (__int16*)partman::field(loader_table, soundGroupId, ShortValue); + __int16* value = (__int16*)partman::field(loader_table, soundGroupId, datFieldTypes::ShortValue); if (value && *value == 202) { - const CHAR* fileName = partman::field(loader_table, soundGroupId, String); + const CHAR* fileName = partman::field(loader_table, soundGroupId, datFieldTypes::String); HFILE hFile = _lopen(fileName, 0); sound_list[soundIndex].Volume = (float)((double)(_llseek(hFile, 0, 2)) * 0.0000909090909090909); _lclose(hFile); @@ -198,7 +197,7 @@ short loader::query_visual_states(int groupIndex) short result; if (groupIndex < 0) return error(0, 17); - __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, ShortArray); + __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, datFieldTypes::ShortArray); if (shortArr && *shortArr == 100) result = shortArr[1]; else @@ -209,7 +208,7 @@ short loader::query_visual_states(int groupIndex) char* loader::query_name(int groupIndex) { if (groupIndex >= 0) - return partman::field(loader_table, groupIndex, GroupName); + return partman::field(loader_table, groupIndex, datFieldTypes::GroupName); error(0, 19); return nullptr; } @@ -222,12 +221,12 @@ __int16* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize { while (true) { - __int16* shortArr = (__int16*)partman::field_nth(loader_table, groupIndex, ShortArray, skipIndex); + __int16* shortArr = (__int16*)partman::field_nth(loader_table, groupIndex, datFieldTypes::ShortArray, skipIndex); if (!shortArr) break; if (*shortArr == firstValue) { - *arraySize = partman::field_size(loader_table, groupIndex, ShortArray) / 2 - 1; + *arraySize = partman::field_size(loader_table, groupIndex, datFieldTypes::ShortArray) / 2 - 1; return shortArr + 1; } ++skipIndex; @@ -255,7 +254,7 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f { while (true) { - float* floatArr = (float*)partman::field_nth(loader_table, groupIndexSum, FloatArray, skipIndex); + float* floatArr = (float*)partman::field_nth(loader_table, groupIndexSum, datFieldTypes::FloatArray, skipIndex); if (!floatArr) break; if (static_cast<__int16>(static_cast<__int64>(floor(*floatArr))) == firstValue) @@ -283,16 +282,16 @@ int loader::material(int groupIndex, visualStruct* visual) { if (groupIndex < 0) return error(0, 21); - __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, ShortValue); + __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, datFieldTypes::ShortValue); if (!shortArr) return error(1, 21); if (*shortArr != 300) return error(3, 21); - float* floatArr = (float*)partman::field(loader_table, groupIndex, FloatArray); + float* floatArr = (float*)partman::field(loader_table, groupIndex, datFieldTypes::FloatArray); if (!floatArr) return error(11, 21); int index = 0; - int floatArrLength = partman::field_size(loader_table, groupIndex, FloatArray) >> 2; + int floatArrLength = partman::field_size(loader_table, groupIndex, datFieldTypes::FloatArray) >> 2; if (floatArrLength > 0) { do @@ -336,7 +335,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset) __int16 visualState = query_visual_states(groupIndex); if (visualState <= 0) return error(12, 24); - __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, ShortValue); + __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, datFieldTypes::ShortValue); if (!shortArr) return error(1, 24); if (*shortArr != 200) @@ -347,7 +346,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset) return groupIndex2; groupIndex2 = groupIndexOffset + groupIndex; - shortArr = (__int16*)partman::field(loader_table, groupIndexOffset + groupIndex, ShortValue); + shortArr = (__int16*)partman::field(loader_table, groupIndexOffset + groupIndex, datFieldTypes::ShortValue); if (!shortArr) return error(1, 24); if (*shortArr != 201) @@ -361,15 +360,15 @@ int loader::kicker(int groupIndex, visualKickerStruct* kicker) { if (groupIndex < 0) return error(0, 20); - __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, ShortValue); + __int16* shortArr = (__int16*)partman::field(loader_table, groupIndex, datFieldTypes::ShortValue); if (!shortArr) return error(1, 20); if (*shortArr != 400) return error(4, 20); - float* floatArr = (float*)partman::field(loader_table, groupIndex, FloatArray); + float* floatArr = (float*)partman::field(loader_table, groupIndex, datFieldTypes::FloatArray); if (!floatArr) return error(11, 20); - int floatArrLength = partman::field_size(loader_table, groupIndex, FloatArray) >> 2; + int floatArrLength = partman::field_size(loader_table, groupIndex, datFieldTypes::FloatArray) >> 2; int index = 0; if (floatArrLength <= 0) return 0; @@ -418,7 +417,7 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vi visualStruct* visual2; // edi int groupIndexSum; // eax int groupIndexSum2; // ebx - char* bitmap16; // eax + zmap_header_type* bitmap16; // eax __int16* shortArr; // esi unsigned int shortArrSize; // eax int index; // ebx @@ -447,18 +446,18 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vi groupIndexSum3 = groupIndexSum; if (groupIndexSum < 0) return error(16, 18); - visual->Bitmap8 = partman::field(loader_table, groupIndexSum, Bitmap8bit); - bitmap16 = partman::field(loader_table, groupIndexSum2, Bitmap16bit); - visual->Bitmap16 = bitmap16; + visual->Bitmap = (gdrv_bitmap8*)partman::field(loader_table, groupIndexSum, datFieldTypes::Bitmap8bit); + bitmap16 = (zmap_header_type*)partman::field(loader_table, groupIndexSum2, datFieldTypes::Bitmap16bit); + visual->ZMap = bitmap16; if (bitmap16) { - //*(int*)(bitmap16 + 6) = bitmap16 + 14; - //*(int*)(visual->Bitmap16 + 10) = *(int*)(visual->Bitmap16 + 6); + bitmap16->BmpBufPtr1 = bitmap16->BmpBuffer; + visual->ZMap->bmpBufPtr2 = visual->ZMap->BmpBufPtr1; } - shortArr = (__int16*)partman::field(loader_table, groupIndexSum2, ShortArray); + shortArr = (__int16*)partman::field(loader_table, groupIndexSum2, datFieldTypes::ShortArray); if (shortArr) { - shortArrSize = partman::field_size(loader_table, groupIndexSum2, ShortArray); + shortArrSize = partman::field_size(loader_table, groupIndexSum2, datFieldTypes::ShortArray); index = 0; shortArrLength = shortArrSize >> 1; if ((__int16)(shortArrSize >> 1) > 0) @@ -540,13 +539,13 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vi LABEL_33: if (!visual2->Unknown14Flag) visual2->Unknown14Flag = 1; - floatArr = (float*)partman::field(loader_table, groupIndexSum3, FloatArray); + floatArr = (float*)partman::field(loader_table, groupIndexSum3, datFieldTypes::FloatArray); if (!floatArr) return 0; nextFloatVal = floatArr + 1; if (*floatArr != 600.0) return 0; - visual2->FloatArrSizeDiv8Sub2 = (partman::field_size(loader_table, groupIndexSum3, FloatArray) >> 2)/ 2- 2; + visual2->FloatArrSizeDiv8Sub2 = (partman::field_size(loader_table, groupIndexSum3, datFieldTypes::FloatArray) >> 2)/ 2- 2; floatVal = (__int64)(floor(*nextFloatVal) - 1.0); floatArrPtr = nextFloatVal + 1; if ((int)floatVal) diff --git a/SpaceCadetPinball/loader.h b/SpaceCadetPinball/loader.h index 0b0f966..aaadbbe 100644 --- a/SpaceCadetPinball/loader.h +++ b/SpaceCadetPinball/loader.h @@ -1,4 +1,6 @@ #pragma once +#include "gdrv.h" +#include "zdrv.h" struct datFileStruct; @@ -42,8 +44,8 @@ struct __declspec(align(4)) visualStruct int Unknown14Flag; int SoundIndex4; int SoundIndex3; - char* Bitmap8; - char* Bitmap16; + gdrv_bitmap8* Bitmap; + zmap_header_type* ZMap; }; diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp new file mode 100644 index 0000000..7171477 --- /dev/null +++ b/SpaceCadetPinball/maths.cpp @@ -0,0 +1,36 @@ +#include "pch.h" +#include "maths.h" + + +void maths::enclosing_box(visual_rect* rect1, visual_rect* rect2, visual_rect* dstRect) +{ + int xPos1 = rect1->XPosition; + int yPos1 = rect1->YPosition; + int width1 = rect1->Width; + int height1 = rect1->Height; + int xPos2 = rect2->XPosition; + bool rect2XPosLessRect1 = rect2->XPosition < rect1->XPosition; + int yPos2 = rect2->YPosition; + int width2 = rect2->Width; + int height2 = rect2->Height; + int xPos2_2 = rect2->XPosition; + if (rect2XPosLessRect1) + { + width1 += xPos1 - xPos2; + xPos1 = xPos2; + } + if (yPos2 < yPos1) + { + height1 += yPos1 - yPos2; + yPos1 = yPos2; + } + if (width2 + xPos2 > xPos1 + width1) + width1 = xPos2_2 + width2 - xPos1; + int height1_2 = height1; + if (height2 + yPos2 > height1 + yPos1) + height1_2 = yPos2 + height2 - yPos1; + dstRect->YPosition = yPos1; + dstRect->Height = height1_2; + dstRect->XPosition = xPos1; + dstRect->Width = width1; +} \ No newline at end of file diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h new file mode 100644 index 0000000..18e6c26 --- /dev/null +++ b/SpaceCadetPinball/maths.h @@ -0,0 +1,18 @@ +#pragma once + + +struct __declspec(align(4)) visual_rect +{ + int XPosition; + int YPosition; + int Width; + int Height; +}; + +class maths +{ +public: + static void enclosing_box(visual_rect* rect1, visual_rect* rect2, visual_rect* dstRect); + +}; + diff --git a/SpaceCadetPinball/partman.cpp b/SpaceCadetPinball/partman.cpp index 409852f..1d77b4c 100644 --- a/SpaceCadetPinball/partman.cpp +++ b/SpaceCadetPinball/partman.cpp @@ -1,6 +1,6 @@ #include "pch.h" #include "partman.h" - +#include "gdrv.h" #include "memory.h" short partman::_field_size[] = { @@ -39,7 +39,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName) else { int lenOfStr = lstrlenA(Buffer.Description); - auto descriptionBuf = (char*)memory::allocate(lenOfStr + 1); + auto descriptionBuf = static_cast(memory::allocate(lenOfStr + 1)); datFile->Description = descriptionBuf; if (!descriptionBuf) { @@ -52,7 +52,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName) if (Buffer.Unknown) { - auto unknownBuf = (char*)memory::allocate(Buffer.Unknown); + auto unknownBuf = static_cast(memory::allocate(Buffer.Unknown)); if (!unknownBuf) { _lclose(fileHandle); @@ -99,30 +99,30 @@ datFileStruct* partman::load_records(LPCSTR lpFileName) { auto entryType = static_cast(_lread_char(fileHandle)); entryData->EntryType = entryType; - int fieldSize = _field_size[entryType]; + int fieldSize = _field_size[(int)entryType]; if (fieldSize < 0) { fieldSize = _lread_long(fileHandle); } - if (entryType == Bitmap8bit) + if (entryType == datFieldTypes::Bitmap8bit) { _hread(fileHandle, &bmpHeader, 14); - char* bmpBuffer = (char*)memory::allocate(0x25u); - entryData->Buffer = bmpBuffer; - if (!bmpBuffer) + auto bmp = (gdrv_bitmap8*)memory::allocate(sizeof(gdrv_bitmap8)); + entryData->Buffer = (char*)bmp; + if (!bmp) goto LABEL_41; - /*if (bmpHeader.Unknown2 & 2 ? gdrv_create_bitmap((int)bmpBuffer, bmpHeader.Width, bmpHeader.Height) : gdrv_create_raw_bitmap((int)bmpBuffer, bmpHeader.Width, bmpHeader.Height, bmpHeader.Unknown2 & 1)) - goto LABEL_41;*/ - //_hread(fileHandle, *(LPVOID*)(entryData->Buffer + 8), bmpHeader.Size); - char* tempBuff = (char*)memory::allocate(bmpHeader.Size); - _hread(fileHandle, tempBuff, bmpHeader.Size); - memory::free(tempBuff); - //*((int*)entryData->Buffer + 29) = bmpHeader.XPosition; - //*((int*)entryData->Buffer + 33) = bmpHeader.YPosition; + if (bmpHeader.Unknown2 & 2 + ? gdrv::create_bitmap(bmp, bmpHeader.Width, bmpHeader.Height) + : gdrv::create_raw_bitmap(bmp, bmpHeader.Width, bmpHeader.Height, + bmpHeader.Unknown2 & 1)) + goto LABEL_41; + _hread(fileHandle, bmp->BmpBufPtr1, bmpHeader.Size); + bmp->XPosition = bmpHeader.XPosition; + bmp->YPosition = bmpHeader.YPosition; } else - { - char* entryBuffer = (char*)memory::allocate(fieldSize); + { + char* entryBuffer = static_cast(memory::allocate(fieldSize)); entryData->Buffer = entryBuffer; if (!entryBuffer) goto LABEL_41; @@ -193,7 +193,7 @@ char* partman::field(datFileStruct* datFile, int groupIndex, datFieldTypes targe datEntryData* entry = groupData->Entries; while (true) { - int entryType = entry->EntryType; + auto entryType = entry->EntryType; if (entryType == targetEntryType) break; if (entryType > targetEntryType) @@ -217,7 +217,7 @@ char* partman::field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes t datEntryData* entry = groupData->Entries; do { - int entryType = entry->EntryType; + auto entryType = entry->EntryType; if (entryType == targetEntryType) { if (skipCount == skipFirstN) @@ -250,7 +250,7 @@ int partman::field_size_nth(datFileStruct* datFile, int groupIndex, datFieldType datEntryData* entry = groupData->Entries; do { - int entryType = entry->EntryType; + auto entryType = entry->EntryType; if (entryType == targetEntryType) { if (skipCount == skipFirstN) @@ -287,7 +287,7 @@ int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName) { if (--groupIndex < 0) return -1; - char* groupName = field(datFile, groupIndex, GroupName); + char* groupName = field(datFile, groupIndex, datFieldTypes::GroupName); if (groupName) { int index = 0; diff --git a/SpaceCadetPinball/partman.h b/SpaceCadetPinball/partman.h index 2b1decf..f54c573 100644 --- a/SpaceCadetPinball/partman.h +++ b/SpaceCadetPinball/partman.h @@ -1,6 +1,6 @@ #pragma once -enum datFieldTypes : __int16 +enum class datFieldTypes : __int16 { ShortValue = 0, //, does not have the 32bits size value, but a 16bits value(see above). diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index 71beaa0..68548d2 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -1,7 +1,15 @@ #include "pch.h" #include "render.h" +#include "memory.h" + int render::blit = 0; +int render::many_dirty, render::many_sprites, render::many_balls; +render_sprite_type_struct **render::dirty_list = new render_sprite_type_struct*[1000], **render::sprite_list = new + render_sprite_type_struct* [1000], **render::ball_list = new render_sprite_type_struct* [ + 1000]; +zmap_header_type* render::background_zmap; +int render::zmap_offset, render::zmap_offsetY; void render::update() { @@ -13,4 +21,78 @@ void render::paint() /*render_paint_balls(); gdrv_blat((int)&vscreen, xDest, yDest); render_unpaint_balls();*/ -} \ No newline at end of file +} + + +int render::sprite_modified(render_sprite_type_struct* sprite) +{ + int result = 0; // eax + + if (sprite->VisualType == VisualType::Ball) + return result; + result = many_dirty; + if (many_dirty < 999) + dirty_list[many_dirty++] = sprite; + return result; +} + +render_sprite_type_struct* render::create_sprite(VisualType visualType, gdrv_bitmap8* rootBmp8, zmap_header_type* zMap, + int xPosition, int yPosition, visual_rect* rect) +{ + render_sprite_type_struct* sprite = (render_sprite_type_struct*)memory::allocate(0x5Cu); + render_sprite_type_struct* result = nullptr; + if (!sprite) + return result; + sprite->YPosition = yPosition; + sprite->RootBmp8 = rootBmp8; + sprite->XPosition = xPosition; + sprite->VisualType = visualType; + sprite->Unknown6_0 = 0; + sprite->Unknown17 = 0; + sprite->Unknown18 = 0; + if (rect) + { + sprite->Rect = *rect; + } + else + { + sprite->Rect.Width = -1; + sprite->Rect.Height = -1; + sprite->Rect.XPosition = 0; + sprite->Rect.YPosition = 0; + } + if (rootBmp8) + { + sprite->Bmp8Width = rootBmp8->Width; + sprite->Bmp8Height = rootBmp8->Height; + } + else + { + sprite->Bmp8Width = 0; + sprite->Bmp8Height = 0; + } + sprite->ZMap = zMap; + sprite->ZMapOffestX = 0; + sprite->ZMapOffestY = 0; + if (!zMap && visualType != VisualType::Ball) + { + sprite->ZMap = background_zmap; + sprite->ZMapOffestY = xPosition - zmap_offset; + sprite->ZMapOffestX = yPosition - zmap_offsetY; + } + sprite->XPosition2 = sprite->XPosition; + sprite->YPosition2 = sprite->YPosition; + sprite->Bmp8Width2 = sprite->Bmp8Width; + sprite->Bmp8Height2 = sprite->Bmp8Height; + if (visualType == VisualType::Ball) + { + ball_list[many_balls++] = sprite; + } + else + { + sprite_list[many_sprites++] = sprite; + sprite_modified(sprite); + } + result = sprite; + return result; +} diff --git a/SpaceCadetPinball/render.h b/SpaceCadetPinball/render.h index 8555168..78c85ed 100644 --- a/SpaceCadetPinball/render.h +++ b/SpaceCadetPinball/render.h @@ -1,9 +1,55 @@ #pragma once +#include "gdrv.h" +#include "maths.h" +#include "zdrv.h" + +enum class VisualType : char +{ + None = 0, + Sprite = 1, + Ball = 2 +}; + +struct __declspec(align(4)) render_sprite_type_struct +{ + int XPosition; + int YPosition; + int Bmp8Width; + int Bmp8Height; + gdrv_bitmap8* RootBmp8; + zmap_header_type* ZMap; + char Unknown6_0; + VisualType VisualType; + char Unknown6_2; + char Unknown6_3; + int XPosition2; + int YPosition2; + int Bmp8Width2; + int Bmp8Height2; + int ZMapOffestY; + int ZMapOffestX; + int Unknown13; + int Unknown14; + int Unknown15; + int Unknown16; + int Unknown17; + int Unknown18; + visual_rect Rect; +}; + class render { public: static int blit; + static int many_dirty, many_sprites, many_balls; + static render_sprite_type_struct **dirty_list, **sprite_list, **ball_list; + static zmap_header_type* background_zmap; + static int zmap_offset, zmap_offsetY; + static void update(); static void paint(); + static int sprite_modified(render_sprite_type_struct* sprite); + static render_sprite_type_struct* create_sprite(VisualType visualType, gdrv_bitmap8* rootBmp8, + zmap_header_type* zMap, + int xPosition, int yPosition, visual_rect* rect); }; - diff --git a/SpaceCadetPinball/score.cpp b/SpaceCadetPinball/score.cpp index 5fbbbe3..101ad74 100644 --- a/SpaceCadetPinball/score.cpp +++ b/SpaceCadetPinball/score.cpp @@ -17,7 +17,7 @@ scoreStruct* score::create(LPCSTR fieldName, int renderBgBmp) return nullptr; score->Unknown1 = -9999; score->RenderBgBmp = renderBgBmp; - __int16* shortArr = (__int16*)partman::field_labeled(loader::loader_table, fieldName, ShortArray); + __int16* shortArr = (__int16*)partman::field_labeled(loader::loader_table, fieldName, datFieldTypes::ShortArray); if (!shortArr) { memory::free(score); @@ -32,7 +32,7 @@ scoreStruct* score::create(LPCSTR fieldName, int renderBgBmp) int index = 10; do { - *bmpPtr = partman::field(loader::loader_table, groupIndex, Bitmap8bit); + *bmpPtr = partman::field(loader::loader_table, groupIndex, datFieldTypes::Bitmap8bit); ++bmpPtr; ++groupIndex; --index; diff --git a/SpaceCadetPinball/zdrv.cpp b/SpaceCadetPinball/zdrv.cpp new file mode 100644 index 0000000..01f2c4d --- /dev/null +++ b/SpaceCadetPinball/zdrv.cpp @@ -0,0 +1,2 @@ +#include "pch.h" +#include "zdrv.h" diff --git a/SpaceCadetPinball/zdrv.h b/SpaceCadetPinball/zdrv.h new file mode 100644 index 0000000..cd26bdf --- /dev/null +++ b/SpaceCadetPinball/zdrv.h @@ -0,0 +1,22 @@ +#pragma once + +#pragma pack(push, 1) +struct __declspec(align(1)) zmap_header_type +{ + __int16 Width; + __int16 Height; + __int16 Stride; + char* BmpBufPtr1; + char* bmpBufPtr2; + char BmpBuffer[1]; +}; +#pragma pack(pop) + +static_assert(sizeof(zmap_header_type) == 15, "Wrong size of zmap_header_type"); + +class zdrv +{ +public: + +}; +