From 600bf0351476a5a21aabb5429132ddf7f52ac0b9 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 15 May 2019 16:52:37 +0200 Subject: [PATCH] first commit --- README.md | 101 ++ premake5.cmd | 1 + premake5.exe | Bin 0 -> 1156608 bytes premake5.lua | 38 + src/Camera.cpp | 63 ++ src/Camera.h | 420 +++++++ src/Clock.cpp | 116 ++ src/Clock.h | 27 + src/Collision.cpp | 1629 ++++++++++++++++++++++++++++ src/Collision.h | 152 +++ src/CullZones.cpp | 323 ++++++ src/CullZones.h | 93 ++ src/Game.cpp | 5 + src/Game.h | 15 + src/General.h | 15 + src/Glass.cpp | 15 + src/Glass.h | 10 + src/Lists.cpp | 26 + src/Lists.h | 130 +++ src/MenuManager.cpp | 4 + src/MenuManager.h | 5 + src/NodeName.cpp | 15 + src/NodeName.h | 3 + src/Pad.cpp | 37 + src/Pad.h | 116 ++ src/ParticleObject.cpp | 5 + src/ParticleObject.h | 31 + src/PathFind.cpp | 591 ++++++++++ src/PathFind.h | 130 +++ src/Placeable.cpp | 81 ++ src/Placeable.h | 26 + src/Pools.cpp | 19 + src/Pools.h | 34 + src/References.cpp | 22 + src/References.h | 17 + src/RwHelper.cpp | 19 + src/RwHelper.h | 3 + src/Streaming.cpp | 10 + src/Streaming.h | 54 + src/SurfaceTable.cpp | 44 + src/SurfaceTable.h | 99 ++ src/Timecycle.cpp | 92 ++ src/Timecycle.h | 111 ++ src/Timer.cpp | 14 + src/Timer.h | 19 + src/TxdStore.cpp | 158 +++ src/TxdStore.h | 34 + src/Weather.cpp | 27 + src/Weather.h | 35 + src/World.cpp | 39 + src/World.h | 66 ++ src/Zones.cpp | 614 +++++++++++ src/Zones.h | 107 ++ src/common.h | 97 ++ src/config.h | 56 + src/debugmenu_public.h | 154 +++ src/entities/Building.cpp | 7 + src/entities/Building.h | 15 + src/entities/CutsceneHead.cpp | 2 + src/entities/CutsceneHead.h | 10 + src/entities/CutsceneObject.cpp | 2 + src/entities/CutsceneObject.h | 9 + src/entities/Entity.cpp | 391 +++++++ src/entities/Entity.h | 146 +++ src/entities/Object.cpp | 9 + src/entities/Object.h | 50 + src/entities/Ped.h | 35 + src/entities/Physical.cpp | 916 ++++++++++++++++ src/entities/Physical.h | 137 +++ src/entities/Treadable.cpp | 7 + src/entities/Treadable.h | 16 + src/entities/Vehicle.h | 21 + src/main.cpp | 98 ++ src/math/Matrix.h | 245 +++++ src/math/Rect.h | 31 + src/math/Vector.h | 82 ++ src/math/Vector2D.h | 37 + src/modelinfo/BaseModelInfo.cpp | 117 ++ src/modelinfo/BaseModelInfo.h | 66 ++ src/modelinfo/ClumpModelInfo.cpp | 156 +++ src/modelinfo/ClumpModelInfo.h | 60 + src/modelinfo/ModelIndices.cpp | 32 + src/modelinfo/ModelIndices.h | 224 ++++ src/modelinfo/ModelInfo.cpp | 124 +++ src/modelinfo/ModelInfo.h | 35 + src/modelinfo/PedModelInfo.cpp | 197 ++++ src/modelinfo/PedModelInfo.h | 47 + src/modelinfo/SimpleModelInfo.cpp | 174 +++ src/modelinfo/SimpleModelInfo.h | 57 + src/modelinfo/TimeModelInfo.cpp | 36 + src/modelinfo/TimeModelInfo.h | 18 + src/modelinfo/VehicleModelInfo.cpp | 917 ++++++++++++++++ src/modelinfo/VehicleModelInfo.h | 115 ++ src/patcher.cpp | 22 + src/patcher.h | 171 +++ src/render/2dEffect.h | 39 + src/render/Clouds.cpp | 430 ++++++++ src/render/Clouds.h | 20 + src/render/Coronas.cpp | 10 + src/render/Coronas.h | 13 + src/render/Draw.cpp | 6 + src/render/Draw.h | 16 + src/render/Lights.cpp | 171 +++ src/render/Lights.h | 9 + src/render/Particle.cpp | 10 + src/render/Particle.h | 82 ++ src/render/RenderBuffer.cpp | 59 + src/render/RenderBuffer.h | 10 + src/render/Renderer.cpp | 1165 ++++++++++++++++++++ src/render/Renderer.h | 59 + src/render/Sprite.cpp | 553 ++++++++++ src/render/Sprite.h | 37 + src/render/VisibilityPlugins.cpp | 849 +++++++++++++++ src/render/VisibilityPlugins.h | 129 +++ src/rw.cpp | 285 +++++ src/templates.h | 179 +++ 116 files changed, 15132 insertions(+) create mode 100644 README.md create mode 100644 premake5.cmd create mode 100644 premake5.exe create mode 100644 premake5.lua create mode 100644 src/Camera.cpp create mode 100644 src/Camera.h create mode 100644 src/Clock.cpp create mode 100644 src/Clock.h create mode 100644 src/Collision.cpp create mode 100644 src/Collision.h create mode 100644 src/CullZones.cpp create mode 100644 src/CullZones.h create mode 100644 src/Game.cpp create mode 100644 src/Game.h create mode 100644 src/General.h create mode 100644 src/Glass.cpp create mode 100644 src/Glass.h create mode 100644 src/Lists.cpp create mode 100644 src/Lists.h create mode 100644 src/MenuManager.cpp create mode 100644 src/MenuManager.h create mode 100644 src/NodeName.cpp create mode 100644 src/NodeName.h create mode 100644 src/Pad.cpp create mode 100644 src/Pad.h create mode 100644 src/ParticleObject.cpp create mode 100644 src/ParticleObject.h create mode 100644 src/PathFind.cpp create mode 100644 src/PathFind.h create mode 100644 src/Placeable.cpp create mode 100644 src/Placeable.h create mode 100644 src/Pools.cpp create mode 100644 src/Pools.h create mode 100644 src/References.cpp create mode 100644 src/References.h create mode 100644 src/RwHelper.cpp create mode 100644 src/RwHelper.h create mode 100644 src/Streaming.cpp create mode 100644 src/Streaming.h create mode 100644 src/SurfaceTable.cpp create mode 100644 src/SurfaceTable.h create mode 100644 src/Timecycle.cpp create mode 100644 src/Timecycle.h create mode 100644 src/Timer.cpp create mode 100644 src/Timer.h create mode 100644 src/TxdStore.cpp create mode 100644 src/TxdStore.h create mode 100644 src/Weather.cpp create mode 100644 src/Weather.h create mode 100644 src/World.cpp create mode 100644 src/World.h create mode 100644 src/Zones.cpp create mode 100644 src/Zones.h create mode 100644 src/common.h create mode 100644 src/config.h create mode 100644 src/debugmenu_public.h create mode 100644 src/entities/Building.cpp create mode 100644 src/entities/Building.h create mode 100644 src/entities/CutsceneHead.cpp create mode 100644 src/entities/CutsceneHead.h create mode 100644 src/entities/CutsceneObject.cpp create mode 100644 src/entities/CutsceneObject.h create mode 100644 src/entities/Entity.cpp create mode 100644 src/entities/Entity.h create mode 100644 src/entities/Object.cpp create mode 100644 src/entities/Object.h create mode 100644 src/entities/Ped.h create mode 100644 src/entities/Physical.cpp create mode 100644 src/entities/Physical.h create mode 100644 src/entities/Treadable.cpp create mode 100644 src/entities/Treadable.h create mode 100644 src/entities/Vehicle.h create mode 100644 src/main.cpp create mode 100644 src/math/Matrix.h create mode 100644 src/math/Rect.h create mode 100644 src/math/Vector.h create mode 100644 src/math/Vector2D.h create mode 100644 src/modelinfo/BaseModelInfo.cpp create mode 100644 src/modelinfo/BaseModelInfo.h create mode 100644 src/modelinfo/ClumpModelInfo.cpp create mode 100644 src/modelinfo/ClumpModelInfo.h create mode 100644 src/modelinfo/ModelIndices.cpp create mode 100644 src/modelinfo/ModelIndices.h create mode 100644 src/modelinfo/ModelInfo.cpp create mode 100644 src/modelinfo/ModelInfo.h create mode 100644 src/modelinfo/PedModelInfo.cpp create mode 100644 src/modelinfo/PedModelInfo.h create mode 100644 src/modelinfo/SimpleModelInfo.cpp create mode 100644 src/modelinfo/SimpleModelInfo.h create mode 100644 src/modelinfo/TimeModelInfo.cpp create mode 100644 src/modelinfo/TimeModelInfo.h create mode 100644 src/modelinfo/VehicleModelInfo.cpp create mode 100644 src/modelinfo/VehicleModelInfo.h create mode 100644 src/patcher.cpp create mode 100644 src/patcher.h create mode 100644 src/render/2dEffect.h create mode 100644 src/render/Clouds.cpp create mode 100644 src/render/Clouds.h create mode 100644 src/render/Coronas.cpp create mode 100644 src/render/Coronas.h create mode 100644 src/render/Draw.cpp create mode 100644 src/render/Draw.h create mode 100644 src/render/Lights.cpp create mode 100644 src/render/Lights.h create mode 100644 src/render/Particle.cpp create mode 100644 src/render/Particle.h create mode 100644 src/render/RenderBuffer.cpp create mode 100644 src/render/RenderBuffer.h create mode 100644 src/render/Renderer.cpp create mode 100644 src/render/Renderer.h create mode 100644 src/render/Sprite.cpp create mode 100644 src/render/Sprite.h create mode 100644 src/render/VisibilityPlugins.cpp create mode 100644 src/render/VisibilityPlugins.h create mode 100644 src/rw.cpp create mode 100644 src/templates.h diff --git a/README.md b/README.md new file mode 100644 index 00000000..812b9c83 --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# Intro + +The aim of this project is to reverse GTA III for PC by replacing +parts of the game [one by one](https://en.wikipedia.org/wiki/Ship_of_Theseus) +such that we have a working game at all times. + +# Strategy + +A good approach is to start at the fringes of the code base, +i.e. classes that don't depend on code that we don't have reversed yet. +If a function uses only few unreversed functions that would be inconvenient +to reverse at the time, calling the original functions is acceptable. + +# Progress + +This is a list of some things that have been reversed to some non-trivial extent. +Not everything is listed, check the code. + +``` +CPool +CTxdStore +CVector +CVector2D +CMatrix +CModelInfo +CBaseModelInfo +CSimpleModelInfo +CTimeModelInfo +CClumpModelInfo +CPedModelInfo +CVehicleModelInfo +CVisibilityPlugins +CRenderer +CEntity +CPhysical +CCollision +CCullZones +CTheZones +CPathFind +``` + +# Low hanging fruit + +There are a couple of things that have been reversed for other projects +already that could probably be put into this project without too much effort. +Again, the list is not complete: + +* Animation (https://github.com/aap/iii_anim) +* File Loader (https://github.com/aap/librwgta/tree/master/tools/IIItest) +* ... + +# Coding style + +I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), +but realize that this is not the most popular style, so I'm willing to compromise. +Try not to deviate too much so the code will look similar across the whole project. + +To give examples, these two styles (or anything in between) are fine: + +``` +type +functionname(args) +{ + if(a == b){ + s1; + s2; + } + if(x != y) + s3; +} + +type functionname(args) +{ + if (a == b) { + s1; + s2; + } + if (x != y) + s3; +} +``` + +This one (or anything more extreme) is heavily discouraged: + +``` +type functionname ( args ) +{ + if ( a == b ) + { + s1; + s2; + } + if ( x != y ) + { + s3; + } +} +``` + +Indentation is done with TABS. + diff --git a/premake5.cmd b/premake5.cmd new file mode 100644 index 00000000..6d0726fa --- /dev/null +++ b/premake5.cmd @@ -0,0 +1 @@ +premake5 vs2015 \ No newline at end of file diff --git a/premake5.exe b/premake5.exe new file mode 100644 index 0000000000000000000000000000000000000000..a4bd472486aa22d0e20062dda6863e8ab35fa0bb GIT binary patch literal 1156608 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%0ApkNFxjL} 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 z zXJ1wryr=tYc>|BF&b|NU9s|apME}k=_cUSu-d!dj3%`)`Y>3-Zlj*_fo!bhEFtA$f z;^E-soz?w2xAz~d?-E)lsSrMI6-wT_TPj%xF&0gQiNF)al1_^F@N1_MaYlRGbaA2# zkuNNlFBx1hV$F|VG!UAy`_of85ijWS>b$ZypRYB$ou}JjsnLMnR?8OT!ct#cO&HgF zfBVUDw}a8ZBkV$%dFl(C`>|CnSS$M*%bSm%;Q{6_a$5Y=@ci3vMZ+MM_TC@$#=MJ< zm+6jSdVo+9HDhh9*f@c9Hf5n-+1}oV(CEl3@QKz!EUYIJgkrcVsGZ&2^}H)J zCeuqr=;o+{7s8i^$56}ksW!1|k$-rJJowR3q-X8r_sJdm>r zUmC7Aw{Xon@7xv!;pzHcsp7YR$GbO#lu2_kYy4XR;@tF6LO86~y#t2WtRn69%9AQ4 zfSR|m^>mwyglc^IPddwZ4P1v%=$WHfE=A4@ZC5ZaYG7$WT;%T7&i*R2%FT6Jot4#C z`55Ztus4mgXp%iK3mTcFJlwX{7kG zO>6;H_kY0C=A2#$d}SSfwO+$3C+bkRbs+TA6+;)Fq>35gHN2s@wWZk%1i<=98m#Uh z8FY4u*Z;?JTy#Bdy;c1);;*CbyO_9vQ3XcME(&lJH-ubH+Nwg2)u35Ia;w{2@|~l0 zC0ZDyaFh^xu(AGVXL;wRau<>Y^#~)Q9&=CJp*}-0OZ@~?i}i~nU)zCJ_IzvS_thw8 z)lHLzQ_Jc{Y_!-nR6(!!NR`IZ*_(%a<3gp9MF6Imn;SpvL&b1)LrO6)jWdub$o;8E zF;R87>%o-}k-qqY$>~nR5+765nZ4%X3FY4+?qS8SeWJd|5b)Wa_S)&_;A{=07}pNv z`MJojf4va?4!m3_-$m%8BdakQ^v@QBa*N{;f)Dj3A~0f&&CwbMds{P;Xk=_3us>Mn z4T=?T`0L)0gc;I^N!lGT>2ZOP%<^%YNF>Bh0|XuNT(E5IK7ol~MPgG6b(1M(Rf(=B zvlR63Zo{-HpojZxmka%15iKcb zHlpQ~8~NR>ojfCp4&=&Brsld>n@kQc1pnpwHe-Sx`^ z1p_MQlmGifWWqpS9h>dquG>*C>0-j}3Rg6$I(w<*8V@8pQN@Vi4lb7i`*_neEp7?F zAeI!CvSgNr$Wf+8K;u3*KRsJHc}05^%9hR(B75*IqAW(>3}4s1V_YybR23E^6(Bi_ zVc06X9KHIUR$*`e^Gqy^E+`SKMxttb)fGbrEy~z9_rSit1JBp&eJ}Yx&O4=1+ziW4)F8y5_HPAo0 z)Bm_qqR*xBD-Cd!I_O;ri~Mp;H@mcs*v7#mkI{?iZt}OBAfqHNd|9p^ALs)e3Y{+U zaGRH7h48G0C(ikg_-Y3^$j>AO_$Zf%t}p`}0oY5a5}t3|K0iD8M)`XF!S4_~yg|Dv zwDX6}TkV@oJh=>Tus%F&KHFVe{HFQ4@53$#*SM$0hiI_b6hb~&0pc4#eE+$}0BmqV zK9p+$t1x9yuhp;a^WBZ-51X5#=Jya}3=&9@MfpXTE|29!w?MMCc*D!Vir~&)bd@8* zJZq_OW^rI}Bm}O*!tfxKdL(kjIPQvX9%6&wCE=QsltN)1qXeZBS#c;5z0<0A>wG8f ztvtq}yH0(OkJd+a9$N5(SFCAH$5yjJuiCdD)lYc33-qB^D4yE8g zWP;dSeo4ODuOtc|$_8cP)hPs>-SGWTe1Umv721YT4~LPbCy+$#_)cGl5QhoD2QJ^yn+-Uvog*p<9@w_GC%fn4F`_rl$oV~-BUs)VlKZKh_t2}8 z#2*-oeY!sE9*xETUZRWDy&_etw9_OJC_(9v5V}XAJu8JNcIC}6=>D-8OfQ`<1vb!{ zDGx}=ga@<)Nao$w1SeOXdRh0iZbU0^FRU#30DHosTG%^ZKzxF?&r-Dcos4yf@XWtr zyDXZv>g)uCp@6@PGUKbCodps_I;|W~@_{6Cw8@!UwSm$2}{ z!W-6F33G-f!Yw@g(n2w4g9sfv-@vkfdqwi|xPOAjOQwwzc*c0*cZkMz(KzhULPGzp z#t5;`NL{$RE8NHoilZrNQYh<+WW+g2b`OkKlu?{?jD#IJIyNEJo|+V6u6WYfkZbQ+ z&GVs^z>)47K+&$9Pw`3V;xd#SMi(4NR52rhwaB?>y#j*t7^W1Sfut9?98oWM39`zy zCeKv0GCLY1pE@53$Bf%}MFG#rGitWnITa=t;w*gHI8fSQS}QaQdLcN1Yy{+jUiEUO z@K+`I6hl5^9TOFCWoCU*mWQo_ z^&i{m0@R`csV@g;_s`G!av#y`u>hybXV4HU9}U11mWq2M8-Lk$u{euOmea9B=Ch0_ zhQ2Z7-s{=3^;HaN0a8(*6tZosNX$URL^uY#!G$YAF~kDmLkT8zXbs4u$dt4Dvx;P_ zxi@tI54{S&wKsuL0gy@ncGVZTh~mTG1fBCN9-R#s%OM+H{lJjnn5;LXX{a^kGNx}? zavtC}k>npL0(O#SO5<3lpo0k@;;128{rmWu(&xK{XPTUANxl1woC(!uQ3Gd64W#>H zPDUs}>@^HZMXZb_gv9k6`GNtedGo~*jurBKKc-kGoe#|rE^R;sn#9#vaxo+Q5Vtk< zoi?fL)jdE%$fO8hf%|m2X4Kpk+`?fH!!1l` zt`p{>p0z(t8eghx98~NhR)#*-Bw|b2CTYFpFn)bZ^aLYxX9hwOM!yfp9KF6pLK!C@ z)~xc+(QA5pYVz$HU=N@pY2Z3M0xvS#`VR>8t%bp4i}W?+|HPafE` zibyM|v2gzs&nHb_F$P8wUm_HMjgQk`&L3?sxVGU4Eff*iEw6NiB()3zn6~>cDV&aH zu&yPXW-rYqJ#UqOpj)g_CI(a?+ItJ{`be*<==1^hU_9!C|59c)+k<8UW~oZB<<4E8D?KtZXB1Pg0csms40I1F+%>U8;Ox13YQ!Ci>F+HHvC`Y?{rj)z53{U?C8YC>Zk$}x!ltI7|6}` zu0e-PuLb- zkf06)LyHQYT%KgPd*f`2MX({sYHyg)Z?52g%S9?nwqGs$$TvTZXVh<)?ui=b$Yq?jp+QOX0D zT=9VfqLZ6$oUB`Dk1m5;-4$pai9CE}dX; z$8VHVpG&ESM0$_leJrU?t2=5#lZLIz&j;pKj(bOZ->13s_!#8~afKdYk|M9*ogK%7 zzebTCMDL1eeCrt4x$C1I%`C59q%hhY?>8dJwhEB;J*_7M>)!}2O(>zu!(;UDwNRFXs#e$@kAHyf}~vueox^mkQBNJL`5YE#rN-pDD352#RVIrnsgCH>^zzBjZd4M_SNk?u}r=$ z56;vZMr2Ey(vNo*YZ%j-SDAfP*0f3$!^+Ww0~9ZyNRN*27%98}=qe!tnRMm@Mq{

%8Woxw~{s#CCpAGcm>7$h{z(_g%Mj>9T|8PfxdA!}!?6%Sj`$iQ3$ZC|2=5)SiPJZ!1q+f`#*p{>S}GOjK2RZ;rjxkeq5 zR``{7n8XZ@hh8SZ&y#f1RDQP1wam<=X4YBqy?x!`Cnt*y&Bji1Nc&7YGY^i&LOmk`Kdw9D>0v4)DwGV@UaaBtO{tl1Lxp{Sj0Ap3dngvaV5su@#v;nBaPw*lQ70y@qH zq}t|aeRu>cpamVAvM74iTw32;+37s(Y~ot|{mm^Y_Vi%bKhY=Bv8*j`uCH~vyP8>} zs%=92tSvv=*u^ygm7j9*K!Kdz{BJI;ZV;2|m0u!FsEkz#@QEFS@A*g~R0*upV_6|m z5e;<#{ijP8Iatue-CQ3f+=19#UqNqFM@UA)6H?@y@q8JomTd>vZeDv~yzlDKq)LEa z+WBjW2s z$qLSps6v+ptsbv#&0seviX*QYhVyKayo%*KKW92>046V`KqV9LTB*B-EBja#yjfpa zfe*}!EmxKleucHjt5n$qbYZOW1Ge>$ee<=k)&!tX+*MGj3~)sOCy6i;s5^1=9FBm) z9LW5JEkACa90Zr_jmQi}kdNR3(Y<_2mO|~qzaQJ{D+AZ!Vv0?ejNqfk5U7Cu4cdss zBcX|~jJ!IM7vm6Kpn;!QL*OSPFB&!F2NJ-GsMo}egLCXX zsTxpJMZ{2}))71pj^hTfjjsS~30Um&-aKxUw}Ca}Ii-@|K<5%TXS7!sJ;7MQGsrCR zdyoGON5!5k+OwVYuMg#{w&8j6O&le(>Kk1^c5~hgjWE86lr)zOvHY*(M=(x#!^9pd zDAxkHvZI?wY_Ex7%{Yf%>}PZVf@x_|B%E$=oC@{bNoe?|Ba=-LBeC?tG~qZ4l508p zIF*oRE9II@CU!tK*#|MP!UsgXJz9)fYuB2R7_+)=UeYj4&ZoR^1rR}UWvvQQbR~xy z6i<3KN5ft-x|ygPFz1)5o^T9jA~A$J4fJ-qZCZ(l2^$`gij5oyQn=HW9-PLngvbEF z1h5?*9-K0Qx<$O0TM3VDPzu-=CU_p9D#>_?WrB#XILc*us_7w2PC`>PJvlQ^we9dm zoGHXz`6Dl5=;Pm|UWo?;^->9{!J8WI;R?OtH#N3Pw+Yr0s>rQ^{7M0j{FI#%Q8qq3 z$3yet>>;k&Smbe0K@;KFT`GT!Tgwb&ExrWw9&x|z)tFILkA${Xl#j%B-IgoLge3Ns z5VHD;h+cod1_m)j5`S#QtHNFop=R*5C@_*=?8y)P$r)CIRX;S3-u0wS40FZl9j{mP z-uG!~aWY9btV-}pMfgTBf~tC=FaS{+z*cp74vNMQUBQUJ*^BL{6DYZnLF#a4svuB~ zOAxRPYqBNj9JEPGa9m$F3^or%4pV?x_fRC9+MKXF7ApQVt7qr(Xkw-Ahz3sdl#M7v zc=A&!mp$PT#%_&sa}%}o-jN|dw#VcK-kL184`d*5yhTltH<4i8jVXBHqg9a0<9}nRHwX&alEKhM68{9NO4zU8d z2-Y_L0EQIK+->k%LtN?};z$zsNC^SG|CpAv1*Rq%(6 zTGbXC5Vu@pqDeo*CTUPaIhL~0HHb3qe|l$A?E}jYJzms4exwq9R2tB`0FwWxfZP%r1T=^NXL6-n{X~m->uPkDo{! zF%|g;9JW402H*VyzhiyC=ro>9d#mEu5A6UY)<^)&iC=n&&Im~wvJmcATBqO;!IvFP z=0#g`BJ)U{n4yLv^tetapi?5H5^*2AFbK-hVeV6bLgSJxDOi4aSf_^-(K5|i=~;(2 z4q5>iANoZ_6G@@a)a@$tScZiotI@$xPD4A^$Z~%z3hUN~P9cojL59 zPaNZ7`m-eVblrXxNpsMLSwxP}$>H5Q2D;#bR;yUbj!2k)0qy%Ko z%_wP84V6WeiEPdR%4e4~p73^PII5U|t(CeJ>tJzt32O+g=Q)d4>}m6LV#acrh_YY9 z*EZ7wOZ5kM+4~q*=Ht3xMOq2#Co)3W9i4WW!F7V}3g7WRVZE@q5ZW>2nSe+z)s6}b zT;KcaQ?f;z*?xW5aDY#n0u1bD(yzdRg&su_36X7>C21PI%UN~3te^#H7*+4;36fw_ zl$OOlS1_1HX*dmhmGcy$oYm_ck0rpvX+t*hgWhrf;0$Y;`Fm5tY&=JJ1{hoO#O(uI z_vyUv9X)^D8*XC}*zHXQ{UIvr0w}6mNpXRS#(5bRA(MlB+;HK368XVc)l7^idSNlm zTnUyJ*9bJcjSOeCKmu?bL(w!W8V=-|y0*JO#R&(}M7OvEjF$9z3ePr2RZDMW^A?HQ zfk4Tmg2C4Hm{17A-6h|rCh&9u;ms?gPb*3%dr_U22(`+hsNHDFY+Pt8E;e?zR=4gq zrmsimr^k>o{V8u`9WySgz-5?os6fB7LE`r&ivZP}n;gJ$}vPqr<2Qi_{@)h=r$A0?XUoLbI4mM5>yC2WAELJRHM zz^rockc~;m%Kn*_E>CBcoH?IaV14@d**YdVsb@$}J4z1uQbEVA9Aj(2jk~p|2(b$S)g>k~yR|eA}OlhNO^6L|>shF{6Rsc!UM}$W5{K z{Ke_ncc3FECg(iGn zsau6&$*w&?t3tL5U0(UYg?B|p7O5DQo!$V^Y;{cZ_Y*vqrQPDl#k6gNC`cFs)u~p| z0I?1MjAQ#_ZaYzjn7WsOv=0vswDB5n^O>OnwNQjRU#|BV1cpc8-cn<%aa^#az=$(l zCwZZQcme<+%-FNh(daa9I4Y+CW!j_rDTRNcrGi#62CHlbo$X2?c6s{!_2~ncf6D3T zc(!?U-wbYMssvWDmL;@E&{<&TUJMcGGg$xXkdif%<_=oX0)eoW53xkqG^*&{HfRdj z$3i9_w0l+Qv$|K;Voe7sz*l!bq7|Kw>pOts4p_{`8S=%nD%E+%1k*dvAes5X(WR1l6A;}^pKY= zhe8-yh9Q2H|Hy}IZ|Gu;w;aF!_Q&aMMtV=bGFR>(* z+br;GQr9O!W&dAl^-lsr>hBFDt4i%p7!!e<+P-NpXjP;M~i-Jtv)XSu=~0{Io^f@ zyx7GCo6Gk150)wtlPX0O4i!pCT3m$BQZkSgGVS0P?@a)2+>)UOP!Mfccwz+5iUaz5 zGA!p%M5-qHKj*1JF{0zkv|`C+MOa866!J`pdY1OC0%Sp`9pT936pp;Oi;meQElO34 zl%?DJT^WyW-BJxnMJyBUmQ*6q`S+S|_qm1pD7j)1wV0&T-D0Vv*K{db8R#{V74Mnw z;!2uT&e`5(THMFI>oo@bSFiEJFJ7O7rX^uzridlfhiejTVN}Jvzk`FL37!saw|^Jt zpQuMUVAW>CWex#spxhOJ2?*n~(1J5sa&&`31zxG5hU_bjjz@B6LliM%Cp?^?Jx+ho z9+aLS$c zYRJynU9LV@AE1(RF##icB*_3gMajLe;h!%X%`n0Cx#0_Rr7~dp> zlC*&!d~)_926z;)y(`Nk_(>JPkH5&7Bmhte^x0=dE6o)HjuoWITee@ung#a3T0wX( zRpGP=DSc355-*eC5`L@cF3J-0&#?$0s|Z7Fg|M$!%i`dy)H;C;oXo5d17U8*bkr&+ z&P-y7ziq^PMMwmDUyEJB+W@GUWbIk1$aMQH8*S>PwiDBPYBu@^s{}ZTTva~U%1UY( z#hBF9@#e2~!b$#9CS)5CYSY=?cE=>fZ@?(?WgP*)5tm8EzkcO`Ik}O5DHI^>szFuE z-oZq2bTD!MT?CiJr97zLz?L(3?j54b_8JJnjc7$Y>;;8M09>KRK1icH!E%3wvkD#a z6adr1_Z+JMs@6szsISb-rg$(Ek7UsSxP_oUa`8!;Wt$26^|c{ONdRKuuy{$urus=J z9q%yO6E2r{60PPJNrQZA7)&dCABqeA8DNaY>$c}0%va!uJh~=%$QLE)oX4D+n2xns4=AjE7zXv3MuU-4!?r&ZD^Y)`_|KtDg>wA0qR9B9kG+Q)Kr19?qN!@|HFhhik9 zETvQuu-eh_;=>$m&&k^LLEa=q$M9;@;LdHtmyuUW^-)qu#G|B4#Q$yaDqLAyoZ|j< zkMSIIBY=GZ(83#33|a#PB3Xh$cObD0r&RNlO(^OrsS5E5Lfzo;VT>iUWL#qr^}|@T z^HO?mqK9=|Z!T^uZs?=Rg0jBEDt$;YC^0VLXpaOs~RQ^m!96 z5VnLRGTu!?X+0-~A)gW}lhQ&ixM;G|a{tgcnc%9A`vJ}jvn7hV`q>Di&yiA`;Ol+i zDg<`NA>M+{1L*@L9ED}9pfXM}BTMAan|wNjn{*zY;s_6&j>|r4CNvX3F2C6l6MW8w z$IP@*;3B!o?{Nx;JFi+SBdhiccr0$%9d3!GT2EDJf&bBS$hM!Z+nP`ZJUs0N?33Ca zkx!Rgw<7Z|3z7Y8QWYt9fn)Ol>6hF!GsTHD>nJGlKYx*K_{J8%8q`C4Eu8BkW`#fi zHjX(Sl>-FrJ(oK!F#V~HDs^bhzXIh2j-FrDV6tIEtVIE2OI9u&+9+XM(*B*2s*V)L zw|tlTa>?rT>!oWx*S$R2yPE8?4THp2`4b2;tTwp8CyaHO`x52Z6)zr(SWCJplPQ(# zHR7yxzNI_u-%M(W^(WaK5X=7XWK_a}i8_xcZ&@sOFu9s?6&ZKwis1;PLe1vX$A}~s z4ObKDA1^V8W-f5DpnS|0g;dl#U76GlroUhEZ5voV!FsZQNC4ScGSJ$ql`a?)+azk3 zwg!yem|ym4QEMTy-!#nU3{DdZrmm}S^pO-(KwH(;l#f+3)|P_4D5B1kRMC1%h3BZH zs+a+j&CslKl5I@?7!5hfsDH1@d?vF(T6@W|CdRP%bL0*B$@cn+w(S9| zBsa0-FTU%e06cdz+?jp?P&vZc;wwT*_YJZq!bLDy#!~S+b6tx(D*ISdfNH{yWvYVd z$Y48q-9Y@vUAXEZ(3yKMv9J&(Hl{GNak~FvRnSVSwibA^@?&?WZETE*a>EzZT zAaau+t3VCF;~4;>j$i79PZ6C=SvS_gUT+|Z(WSJ zOv+AM{sVUldT)EMfv6-*S9(*Btz@Djd)@N3%l8NKi&o~LC@c06m`9qd7{!|EhGEh{ zEhxMg6gHneWM;maf@KTOI9=X9FPe1Fll1CA#%K{mnKjx!FaHr8Olp5r_u!)f_dGC- zcm=>mlW}Y62antpx71RYdu1kb$9Ku@4aEvUZesT}o|Uhe7Q~AclnBO&GX_d`ge}gi z5Ul{~hfX7=%J6bjshRj;jR@St*kYre7D+{CQVoNI#* zYDWz&%p?A4vEY{v5L3BJ4G`qiFtt^QeLBxJHHfpD6X6k!r(6$fQD9)D5$Z zdoi7Ng@_PdSPtD{aUhX6v(aCzWhHHsSin+FoAUD$bTca?>YdS7NzqQ45H*#QQQMhD zk&)03lzrA{p|<)m6l!8^ib3CJ1K7#Eom5lK+u$BWR;={N4CRiBk)W3M5QDMBx&C(~IHJ>*sH#Kj@prRYfv) z4-FDv9WKsIry4wi>N=`I7~Uy(-u(e?pA_gImlP_J;W)#q6(LsD@e$4*WIiHio-8l1 zMlk3l9LfaEaKH`50=>T{xCcuW8F0)ZUzM6Dk4x6Xc4^qGiHeN6CTPT3^#hp<`lB@G z`!>9hvxGW;&Myi}<(;QNUVWf~^RT)4bQP8t_|6?YY(8Ga-W)fj@e}{y86W*9IgZZ7 zGJ4^I&Q9jzw3iH=T$SOn{<5@mrtIm@#A1S~w6w4jGp8x!a!IIjuWQpbmt9rURdx-u zZ&pnNyjM6rKcgikPCGZWJmumNCb*tAOv8ZTsivB%hXZIb^echyDx`8lrG{VJ{apYk zcx_M@tU`?Uh8U*{gqn`<7H6oYTY%&{I9^wQ(f(~h$j2JdNp#C@CkNoiFigZAhGY{q z^31Kv0YP6=N)jlxumMYHY-L7481*m@@$fo?byY`X(eCgWg7DOCCb5J~WOXP_<#arC zpX0L1ENUERl~QSf$tUufSbf@VjC1J}#FcH|N(~oTCf#Hq4;w$K@Rw~UiGY?i2f_IV zTXLcqc~OurC87he-ovgooWg0V*D^3QA}=yzMx|962ZT?*zkY1j&Ga*&kkpk;xwtaI z9*s)&eY1`}wwslqQ)#7V zU==5#O~Mp8*n-9T0YYD?j|6x(O{qeECYj&+V|$i^4rF_L7J@K`gOe0<%(iJOG6CMTYCP%YAUS-?K}n876gC+n1Os0 z^#OAkQ%mP^BsRhrMa7UYZ4)a3-FA_92N>pwZX8XlYotmMw3tW%;4T1k@fywWmGsSi zqEl}be`{kYZ^Y0kq;jCD2aAFVNawv3@m1ef5s7(E(>RT$K&!z&yaFs+U~SE+^c$x1LIB!Uz|Eq^;S!8C6V+Z~3?yFUF= z&2bg&jc~UF(@M(i^GbkQv2r8=Mn_JRNwH}w1rR*U-X_!4YYOuk9aV}a z??aTvh0y99y+k66;KWOPJ!A9`=o#maM_DgM$ORN#xbQ?|I&uHcN0n(i zmtb03g1`E7#JHp<%|H{fY&utEWw$m{o-MIsXh?k^LF3kEGAK}0Y&&UVB!7qm-dV+; zw`#+(Onlj*lK#!u+o-8*g&SZx^72O+Nqg==AJFmU5{Q1^T~6%>CpXh$-|yW$?4Pw_ z@aIY}3-xfeD2% z;5{kMY0i0lQ&m?7Gnyymt&q>cazz<~ay=Uwivwm*FgD~y{<|O5*w$yEy~q?Z7$uaB zG-T&8e(^GaZH!k>24~6SFqTQ?g`7@3bpIdCZ=sS1J~7|gx~AubDz@0VUU-$mLRAFC zj$)-aTX5kV_mucYJa1DrPM2?<358`oSbawFM)&?!wzH_9qw_N2aCv3f_W|Lp5|U(N*GuoT7=~6a7KSN?k}}iTz5@%E-7gpnM+$KIJ zj5nMe&Dn^0o{WuufHU;CgNzJlp5B5S)NPS<1qJ2AL9FsoL`kDtT{+eA#Z)VDjw|1V z<#K0hrPJ+h?d&h_Am-?9XJz-^Lt;s07$8kOuNFc$@Bx7Qd@4_c%3>@B}+lo7&r?D zg{w6*J3)S`d(GsSOWjPK9Coon5Ls*%#a;U-5gHQ>mdrQ*#XN7Z&4vCU?Uwf=tBwxF>e5?QU&8*>v7q3S zNeX2N`xRu0{7J5L z)B@2yf@-0wvHM0qS$TDq$QWFac5z@5&;n+G)GTeM0`)_2Sp|c};hhU~$5>=KKzX+% zkf@WHz$#802Wi>VX?R`nvw#X_;NmU29cf%C>$*K|IK?|xMq*_ntk@(Em= zNWqdMMGAWmKxyHhYZQv-2+s0&ehGce`Yr{fE#V8lBxIv3H=|K2Ft7I3&}=TLSBVu? zbp_mFRlK zmp%CSfTClZY-h^MU=6~mYcv|YQ6gEFtVUo2Qz28-(j8y9dEgI2UXd3e4L-VM(3!L@ z&~u=yNr3#BQ!y#i7K7pek`hNw3x7%^ue2GNePvV3RtLL8jUjO zlLBa|7htRGl`;z4C#-ag-C*~t_f(KTxZCinHf!h}+zV)1-W|Qc^PA|;hq-le1gLkl0~W>Q~9 zMk6Ra%pAd>4c7=Ciir?dW*C6pPTJPyp>Kxzns@zY-rZoxr*vY zB7pW6*Siqa&Nl07jn0qj-CZ35R-^Ui#fwJky|B>IKW{8`8cRPlmey^QbV2yOF+4wA zXmmEZowR68Ia#M}%*|voWNHg#k_Z8RTc(>eRI@mc%n54Dsy>@1IfIwF4bXKKj4DR0 zW)~Ys;|9o1FiWc`J9~^!@+^{zhFd^RqGg5E?JL|Ua?qeouYKxL$dg;mol3B&6mkS0~Zm-fP|AE zS`PD9v>Kf;XOx!6Lz2H4`}2qPm%m^|A!3p%T7?&szp|f0)UD4nmAk26DN(ray`>B$ zSgIdZ@XN+sU(Se(QUi|jz@ff7mQQ@7lAuE!OMBE}Q@Xlvg|U%EzL3GGi*KcFy51|Q zK{2!2#N32n>+uf2Fv0F{DDqM=t!TOEw=CB}EPR9p_xgC+(6+0Jf~4>WlD8bBysy%{cDFS= z>cJ=rZSmQ&^;HBXg`Eab^3UG&z&DsA1SRt#YXKpa=p8K7$uiI{=A>jp7ddd({ujhg z`4|7iqig>XfB&bOF@DOw`7gJw-Tbe%B$$eJT5Pz`z;ICo-v4r7&Hqp#0sMHA0%;Nx zkWm4(oSR0xbj%SjgkVL?xk^I{);uWenLHNizp{#ip$XDz{KWiM9D}>DB3nuhs4#!7 zsW;DP0v^8}4KE}{DZjklinI>V6q9zv^<7J*hG13+&>??@xE~wBt|>v=z0qk);&lgQ zjll;GCX<5;?9|`j)ZZHp{Rkj=WQPkD9L{nfC5kz2YS*yygb*a=WZ`3%nM{xhvHf;;!X+0N2FbWr$SHC+xvIL#9dn zyTH%}=(gddsT|BhqLMCfz?ko!^#0greJ)3k{Z|V&u1^=>o5C7+iee(qT*Tvt%c-9c zR^Y(H0CzWVk4pUh=Fx8dgswH?);#_Y4gT}>Kn667VZuAXvv~gV*6#AoHW&>UJ*Ie;)D@^lm_ zC$()0pnhnY8=T0zFvL-Lk(Nv)(2KLb6s2kBd^m&yk@|ztcUc@)LievvF=T3Y@<7%C zgxhNS_hR@0v14r5r6=fgj{{Nee8%n-oew0e?7Y-=6v?Zf{YIS^z<+|ySITjFfE_9{ zLiMI{oO3kXgOhCd7w`Yj+3CtvDP;Nw(%n^DA(-1qt0~nO_ziC5?bGuEDmd!&VtIEN z&FziEeXPvicZs5vZGj)mUHh}Ot!w`|{{27y{gZ1A{JnvH5Ag2^{=LAzQ~YDz&0Dwc z-2Lj_*WY}*{Agvhv&IFjOb1Ol7*h)wxA7M%+$w%ISDSPAVw~P(Ml9p1H+-v zLMcDH+E1?37pN=B;YB{=W3fr&CQuB=hzatQMoVBqevdm%VL*iR`>8}h00v1I1ma)HS@Sm>`xxc`KYvlOOnR^IRyU5CKFo=p z1A-Qv2T^zmeV?pnmkf|%;mMkOv=Ww5x)dT+G*;?vv>r0907s_23Grs02_7#0Jw&8M znOa!KnGfJhXrG3xH1OM?Dscm5qR8zk3S5?<;qZ6+5&jkCCm@3d;fh;1a zs-rMsY=htUZVMQaH(uuujPRVHJAPQ+c-Fypau*A!E3Zdj`Nly5TDsk|K^X~eh)X3@ zCE>1SH)vP;ull%C)_4jh$VLl^3lfhH1?+AuV`SrsPostJkjD$RkRlr!KRj(<J4>pk))Cyh3ER`Q^7g#)t6^X@#Fv`UW|I_{m4brNPh8?gubBL`G+9*~F*{t%1 zY)4xBWyjs`a8Lm)E=hspUudM~nQ9#r`$={NZnn&5b%y4khbyR2vN)?Ui2vSzD_Bsm ztn=bmlHrSv!)EKgs5m-!$DpFzEXaLM@((n*5yZj}N}MhV%*8mOupBe+Q_D5qeR-%G zb}1stDSzD;pj0yzjHLOgf}s}9KQf&JZSaJG6#_n&qcJIAp@hs3>MM)u@bzOeJg*oC=;Q>Yn~PgFA!|G;5H1NK)Dm3QV^)j~bO)I+ zED*P?-53vunIRBRf-WKhLHvnx3a__GR4lH)Ns(eM%+N4jpf`nbo|;ApO2Am?pmf(9 z2f22Ll`pV|(q}9v>@a=Fjy7gsb$J}xufd4RgAS9G0~0xFA~=J!SxV(whJaC4!v!#V zQ-oGi-(SgAQEg(z5H&D)krLaMrvj#?IK$iDAU1NarBYXbjQCjwJN&AF9`ak^*OllA z1Hw_yUDan0rJ~#w@HfC%K9X=Ua5K7~w_=DZIMhL>Dj%%+uwSt?rLl@fVNvfe^Ub zQseM&zzgbYC6*EiGMal7y0-!Ig^KOX(Yi$N*+3*mSr%=_uEEE#R?ja!KfSTIhy(vc zZsYrh4>jPUXe;QsTBxuXo>D>JDb74jl4Ld+;l<71#$0|yFz-AzTGYAiK`{u2iZH6wHw%-pYHEZ8N}_(K|}$eg}x@j=e45c5J`+>)*G-fbQTdJare z@@_Rp3=0;HJb9-35azTnkW!1$suIezS3+~dkH;6`^fBb{5HcWp(TZ4y^T({C1(=1Y zVYLN}_ZeQnll~#qWKwj@2WVPOCYd#Yu?<){QUGSd%oPqF)^9sSBu{jm5;!9STO@^a z5mnUXw+xta)rxlhLIxR3eL8G8l3amx@QsdMwwR5ZOV4v!LJmrTw@A0@US6Y8b4|Ckr{Y(@q}|vM)@VoG0ALZ81+}DO^eMA*aFO zOe#4Pry2S`(5fnuCi2uVg%yhH;0dXE(>)}-Oqrm(c4-HtU>)(jr&dT@@hg`?9jgo? z=TACD`Wq`;It&$(scKFJ8mM^md007!b$$6*MyeA#1zb|OG!vg5T+I*8M$id#c@ca( zQFxmHMufV*dJKlq_JMs7A}-iP%*4s+LZ%EZ!@O0ggi9bv?XX_t$o*c|2^c zF(_du^FyDHnIKt1$B?0F=XmU%X@3Wh0s)+z@SR9&dg_w_cYN_g@UDwH9r z+Ca{rm#*`%v4&yuU@2YqodlRRmq9iaqgX6TdBwA!X#5HUijYm|$PuWR;ORyn8#sGt zHI)wqQ8!)Y6+GKSQ0!$YcN`yAe!aSZeA^eDJk+=8Hj6#8!L2~>(h=6TW_u06ymoM} z1ldNovTSiM3d0Pu^-&*><;g>MSeNL^q|XDx(&TO<^2l!guhnXXux^v{VM7KBq4{c< z@=CbOz#Fqv2BmAy&t~N2e3S)m8!Ms@rB2e$dx-%Ormhrw*!=l=#v%XR&pd`_G#Fi< zBDauNletyZjhU!bRagz1=d2eo*}JgKh?O|thqvNG`V?^Qz6Ps7=nYK?G#5N_o)twaCU3T_|Jd34NG|b)>G$_(`YP%l zHxHu9l{18zi&HVzPIPoF`&-Rl9k0Jn6F6g%zppd+@5*$Aa|LZZsc|lwwE1G~0!n3U zVh?hISP(~v{i2`^IgFss~slC}AkPX+>YP>?ravqcW^LKiN=c zg`*G-d(oJ$>qo&v5Ur;fhP3Fl<0_ELg0N;d@*lA{)Z!JkS`|$faIP}FX4uc-5Y=sR zyKOa#gp$}G1QTy4`djl#W`fUp!(}!Y=bhxrFJCxAuy#1OHx)7AvcxuV2|uXCJZoR6 zS-!E_`G@Mv< z`bwETWeinaDVMC!R_u)7qlREhVkN@@Y(t+3jbi3+&AAiE3eqRT*d>u;bY=PGT5qL@ zs}y15nvM#EwC{qVIR*$o)G$vOG9E zy?8i)yX*u<<}x8D1FQU*qvLiG&l`5UVAso^L`e$4py_ViC_lr;+iZ(+#3?27Q%tu# z*1nc9JsqO^Uu9J-&Fb0^N(uXIIaor?Lrh}KrM_W<_ESWyUezaCFupb}t#@x=p5)Dj z7iW(VZt>u>i@gd2eyg(h0vnz5x{RBELf}^zrU3$Wc7$1Q#MI>v#$4RL5qoDlIXD9<37N~qZ#G2g3;U&(s_#CWTwf!Lx9A-;z zE`9Ta&J#QYB^x4@}X-6OP?=53F#9BRS1F_A911Q z-P&X{z}kgjukI7y9v|MheTA-B%gyECMPp_ASr(TfpcBA>(iv99qHvFqpc-HfV;IR%ciE0BNwUT2UcEWeCqR*zi@`1;2$0B1CM&bFKoDf2i?2(7nb}QN zQy>r^qX^<)1{!Lpkw*FueTx1>+IyRsKh8N30Q1q+cdf2&CgS+h+}zCE z+}zwe9ns_9ve+2M9MV~@*GZ+!c!(DUhle0^?!8%b>FW>$dVL`21eYT+mRL9vWBKB$ zhoMWOEK=>TK)!a7%3BT#I1>;jFNG*hDyguZX~7Acs!a#NbrJ4dgo_V_Fa#Qf52pr5h!b`f}TQOrl zl;M5I+P?d|;8U#V(*-;qPUd3-Cgh;wG$;CDBFJxWFk^8{Yb+%PSY6h>Oz;rB-F5h! z3nLFMsQ47Qm^wS3%^=lN-_f>%lQEL#-yH<2$G2YCdo#_eO20{{4F@4yIDGdSho!XK z;d09yaq}LVFA#3^Ud3esiPsg|U#$3$Cmi65$4|B&Z2oaO*67qg%Gi4J_@AEa-1}}X zW#O2{E(=E`G}BRvv+BS+oxykHR`_3kx$8SJil!F8qsOs|F({0KR_ zQAp>Yi-k2|mqb0>wHno3QG`ZK$M6UHydK(n^q5a_?XIk@+;ayIuAkOQIFWoXN@~?m zxPnH}--~V01WLOD$}{}*qs7WYu~8yo$QuP+YUBdekJgn*Ua}a+ix^6lJj+L+xvIwN z=tfwQt?2I361Cf)|AEDxfcUUf|!9d3AsstV^L$Pu1S!`UeFd(^=Ul@K>R z?H##Yq!#5lqs}+FB5l-fDFyXMjTJ!jl|$r(5+?k+LP!IgXyz_^O-G*~B!Gc<8&Fu_ z@G%^&_}&I$9H%AI(d2A~DbdEprIZg1_dSfMOSeO~EWytMZz3yKL zEP{;;T?$Ys$;F(Hdstg6lA_>FvB)qw7H$vk@}6LF*j7tuNBux8gahdSwHf40w|A89 zy0%3>u$0qd96TIz=ZVVPX5F$B$YLuHz#MLsuv%UL2Wl5z((To=iKI%N7)S|a(Xj3+ z%rGF%VDvf-6g?ws^mbFvp>Nm+D|92TuL2PW!X|DuJf>q)6H!+#0c9t+^eI^J{^#)# zZ?pms$7Y>}E7dGw;3cq>L`adsKURj?Su4?3vu{^k>~1~TdAw&u={*BKd{oCpFJ9?+ zcZiu#vou}tNhRc299%LI?%*I~0cVD?F=LJUt*w-2XppRAQ_pfOY-wWtmHYtIb7VomSt$=X)aVeZvPvufiKvnY!`ql)sz;z*IJZM94bTxUC)q^ET zNC|D0XoDxIol9jJo{EXo5`8Wp%^)4Ns|uR&JgER|@tiUM>{5Qe6FJ1s8;Y4+uU-Z^l8@+KNT;o6naaENrd}?9V^$&V1`036v1SU z7coXLdF2)#=p5`$2apEW( zitTQ@*?uzU%bMp%DrTzgiu$CPJQSCPOk6;7Tf}l94ymv$0fch|{Xhd-0tQ;q7=%+& zosBb?2HF}${h4GoYY3KjOr$_t(^{}!;Uv;k_Hg)bz`ZGp}6nc81~L=voWvl zF#4ghy-%5F)RwZJG)Q5I#Aw7W=_EG32$-E~T5Pd0H(A>;y3j7X90_qPw1-6LSYnwm zVvKHz$I;3+hyfh@Qz14I=@T6sBf@K=HNjg6x;DTRNzWW3c{Tn!01SO&i+C*It#zju zJ&?5kYM;m`Xlk3SA#Dt?Lop;tDw(}v>KeM=qDJtJa0k?!TU$E?$^vmvj#Nt!CZ9F? zsIg(gTXDiq67loS#m+`Y!%WogP&7f=}{ zx#mQmx)@5wKFU_c`Y?uc_F@jRt}}$j+deFa!sR<>xQR&%#R@yer2zDX2wK>#rwV=(^Xdxh>>QQv zFH}-sspP;F{1yqd1ZSU^wMt1s0Lo6W#-?90SVD?cFBQ8HUDiARbTR(aS z!rF%sixi7AsYi=e>RgU0M`xpXMqx>;rU23WqG#&SX^m?DI-2dKS*w6`AyUq2*<>vV zPGC*_o_yEmMCFn4Yry~9b-{B*@xX(FoaI^z4-pkLNi4z=wuX4XozC3ty!mi{ikG?K zDom?EPe@1z0AyL7?~01C02N~Q#kr;;2q~6@1nFyg3hVM_05$dIw3fk^ro92XL z>mKLB_Q%N*US4NsJh@82*&78hrSLXXQVkRj=M_u zod+8UyB1|i`4kCeT!kHQExc0lr^>B!*6TQHdV7FFs`pqi;`CC7QJ|2Jdv>KgNdT_T zh|;p_j^c4*8>Nf$Hy&HX;aeQHF}Pu9)Vykk_qEYgvcS&p3@EQU#ZZB<>hvs_BR+``i#(tuis_NTZ zrM4AMCuRzM7l5`NLxwwDCM<_&YLa^~78ilw&|Y;L9$#Lvk*h(aEO=_Q@DcSZmOCGH zT}@$>x@Pp)TnhH&y>A6qwh%P|`DmDq|8So1vb#9X+&n(!%)o!i?mb020a`)dq?T&< z4XjsrY6sz4$;NTx>=dCDL=QpPRzuA=NYQPh*%rx_a=g0r;qLN z+tG9~CcSp>a@A>!vy+FalFm$x`BV{hZVibV;f$kXoXE~fY6QxB2&iCZwSm55V1c&J zmU07F$#I--RNK|Jx0t$5mEjPltN2=_5d9%_9(@*5hLA37Ktr^yz4nrhf&F%;JU7T4 z{(wND&`(ejZY-1OhYR(LCYJPCOl|62uWJkAcxSeW@uEU>-;He61+wW&A*n({TJW4Z zTpZBO><$FUgCXuW6=N*gS60DnoUZtXGrRv5|NHOszf1qafAe4eSH=JSudILl^_Q!NTXKV83g4`39vE2s|NMXd>;Jy} zoBs#@{$Kq2@6pfyh=1YM;7nPrM>(lc$k(v)P|>wblRH|9+*Kp5cMY$H@BmR8J#0~q}82H!k8(8GaMg7 z*}z+osDuCNG`UQ`8--Rv4@SO!IeCBMcWbQjBYv*ncdM`UwTtu>A!L$7E#d3Kg%obL za3X=zTxbd&BOmf2JkkCDFw9jaZ43355l&QGvRZBp58OTuUjK=^!lk7Q1Tz=9+G7wj zYc_G)-F~Z7*?s`>;s7rLB8G;vp-azt`$s*hGi&eH)^7ansuEWJc{9>BEN%9eNLX9n zVxiezRyXfQ+J>beJW#Z>wyu_@t9Sm{)7Cdq+U@T=?Z#G0+rAfdbK1^-inN=l+&@0@ zwClOtAAgAUav%3^N7`Ddd;gz2Z9S(wh>@=6J{~=YK61JL6y-K@+HRz+<$iagkL$U; zy@%0nhIw;4;LGLyDblWcd#^uup|!Q^w~5f#A67R5xU~&S+y84Wq^a5e>+05r>GA4j zpnmP<^~kutKOYwv8)-quWu5V*VEPSoz@^+Rc>q zu;5gcL%iC=sb90=5LEFr(zezj?RLNpYL2w6pnBji($=nj?Ug~gk+>6(fVCp+AA@?a zTtwQ#=mb+5X^)eL$Z1I^t!DuD_M+dMb}v{TX-AVl)7p)jMBUM3^==U5+J>j)DZVZcj`mk~GO>8tD7CaE?mil=-rb3`4NuEt zwiP@?Kw4OY_y8 zg!heSnYCTgwS5a4g#to||BAIxKE zlU(XcO~aeXo3gD)Ol_@esd+P5{bQa{Ps=OlhQ|En!|ESn5m?)>wBsymuZy&g->%-z zvewfw_O1)4ySWe!oKFFfo)AEeo&=jA{R&OUNyP47+XXb` zmNqN8(`?P^?ksI;+SFF!xh-4kXVX<_Q#s?NXJjH+7bnc#tnOwa@U)D`>zaYt@#<~} zH>@>E!!5bAOiSk&&Q>=Akx+mm?RE?w%4wu+#jM=e$Z1gyt8^+C?LneO+MOtel{V70 zW0AmW8EL!0Bw(aSyBCv+g(K3wi#go5nbIEo7-P$64+8-kx!=c|UJi>>wD&kT0~?5x z7OMqRm6R4^`!d6l_1au_d-nx=W)7)NX(NB-5wo|&YJW4O?dFP}_F-Kex z^X+K$`#g506%GWkrRHWoU%NAtonNvuQ_W~LhC{iYK+TtGEQzJVI2%?7wudb_|KO1G zKoKulEG!oMU1rKK#uGJFl%da?;7MV04l9~WFe~XopP4UV>@X`0<5Ndr`IlKEZmBWj znz!5gfp-Y28-dJ`T`gH#n&^ppdi}U88RNBaVZ>qj;(IkZTgK`A8J^?z@W1d^I6lPH zQa9W*n{n8p^zuenIFO68R#^CO7;=&h+so|AQbfy4l#WLw4UesHyP@UoWO{!BL-w#Q zVzAdh?5E+>Xv9kc3xT&}sd;9l)A3~#HIuF*hq3nc8e;FhdecFqRYZ`(r(^nlApRh{ zU@URPgVNcT4Z&?t-hQ%@wnhe*1H>1JfY&_d9vzI}V4=2Fj+upV;H(X_6}diE&pXgr z6#dv$+IXhNcyN3Y0cYg!&OKI8bH80-O(#lOP+yeMsLeyJ54JnLV1#;Wlq>9cdlt@Q$@#%ntkSBbOT;Y zH>8{0dt@=+nGJh4|5Q_=^ltVV%^tx0m^TT`^zM@=!D8=2Wya!-xVt;|w@Jm6BF+4V zj~;F>pyu&#csSekslE^RtT#s(8+*|zQquR3UhFJZguWNqu&uy53W=y~wsG6>(4No> zsfoEj3as~tq=g^?8l&d{sYKEv#9hw^zelgUfo^&!+alFWUh;A<=Y_z27X8D;f`=Jw zN>i|4u-}5#l^<->iIeV0B&~2X?#qum4mg%IeEIl%%ACh=977fpiKX`fAt>##F3^N0 z0kq_ljb^t2R+pdQWl`T{!@4(W1POw|trCRyo`2}8csVpCEEtG^kk1)w1AB;0z#d}G zfqv{F*vQHVpp?R>Apu|5)cM_9cg?rPXCU=PSCRiLiC8wdbOiZiJsomCwy|9(=*6K0 zRv1pNoy<}Ij2kHyMN6bQ7R1K9`s?!yZ*B`KPY#Lc?YJYH$^lL3e(-r0dCN-F6w;Z8 z9eJ$XBu@<99=vDA{#!pQ(G=?~K_BCI$u23Uwik#KA4}J)r&)9Qcft?`{C6cKjuC1? z3R6&2&_&sJiqN13x1x(UFgtp+povV!VxH6JOQ5NaEy4j8E_aQNMOQpx`%to0StL3=qpGLjYrmVr3 z2~)=JaM(_YvfbRs>3R#dOhjA;!Ois@9AgeV-El=Y?35GU+?ktP6DQjllqDSIo!Pt* z-@2sFDgrTibEY-SM0s=v*=&oE@d-f-Qm}*mgi>SqKeKwhD2nc~0F6m;TE#F>CG80u zP1ZzwP$T%Wu;+LEBLlPLIn4^a2c!2;9v?eB&vKlEWt2{_VyJ;A@$HB09UvDBsnK=G zAgmVYys9MviuZF;d)5$K6pa#6i#``D&!4vSDx2>Zi^1YGtFk%#37wgpfXfXK$G?yv ziR5xg%K*h?%|zlxQ{c9e%6+a$CP5f-S;H*-{V6^{oQNKrpGW8u;H4_0b`ldR*SpwX zoP{Wu#2(fD*+|_n-CRT(T*b*Q|9LI_;YP#hT{H)h4-zf*+)hEP(XD`lEO#*>W_C=( zV$zW0j<_HY8&CSmk|J7W-$s-iiUZ_c%iIRT+X=hF|BUc>CX%v%ibfZ#>I~pQxn_%{ zYoi_NN^sHL&F!^~?X9)d8*A%#SJ&6?+*rMRcjNXd4xQFE?tb<4_TAfC5HwBcTgM}b z#%|u;`g&{o_RZCsw>LJ~*xKsNJL~IcY;$ev>viOAxXFT}zW;wc`pskf+rz&f@$WhQ z{V(`;h<}c4u%atBu~xbQi1e`8cn575cT>M|PTWnJ7XK}~lv{RZz}R|NZqk6+CG z_RY0cGTK6bgR?W-+Nm4yVDr|0(D2_7EsBo{2tY;n24W?BlKXM#>*;aHci{MSj~v2g zn*PYq6kLz1a-6ZotQj$?rDB5N)xQt@%Vq^dm}c*;s928_`Oo&8Hvv#( zpS3UGn(cU@G&j%bZ(1-}_)4JfJg8zafGrCST45{Yx^1+Q!HlGst^u^&D!r_Px&QX5 zGzpH3s=2j7+E*E0UP6==m!Rpb?C^b*(;!_b5#ee&=eF6LB;9}9ocLF;Vz5jR#Rk2n zSM68Yg+odheWB`vR-)cJT#A^y!)neqx<`jEX!e^qD0oyGDh@P*;pXWnH~COmPDVB&j({2yj&r3WJ{f~T$E;oYQfDi!-Jd$kP19RC2PR>c8Dog~2&a4$_t9V2bm zLsnYAOHd43@fEggL)uK)1|BMm*lMvLtBg1C1o2$U`cr&gxwN1G7VcXKufD~%v(6vP z0gH7GK@FTY4pr}hUbQV;e>sQ>394*mZ2b}F6!zcqy>|a!W|PPP^_j~oTE_i8$G__e zNb9X%CxzOL30+2FQ%H9694jNn&)x ze@i@zYZe}y&gG*d+X2*Mte03iE6#NxwuRjLmRs_y=UTK!Tug~#EpGkv#lBq9tF^w; z0xrJDbI~>^>gAn7(38Vh$nhjHl>tOz;M>E#+(QO0U)6Kq?!aMMmDB2Zp{0FELklT7 z^#Gw>D;piHX}L@_Dwwp|E?TP>HMJ0`1;R0VA|)?RoozjvUQl0T6@8w63y7O zF;->2_YeQDvWNGr3=-GAVUd(!@dH-*mqSFKGe-yq9*e!Lx?0|URWU{*bjzs!=t9UK#9co z1%m`|%{-_%C+>8i`isH^7J&>=4(2^t4FK4S7bkGw@VQ1#z159Ui0x6O`$| z8k<^$5dpg+y1~*2A}T^B4E=!H1x6G7iKtY-ML^0FV>PcL4T<*0=OM!buh)N=Q5 z5WVYzjR&p-9MEivyY;Chn+|Th-&}nwYrEd*L?P=*JMUEb*&Fp{fS1;tK;8-OD7L%% z#oG5Nw~_dVjpjwBhWLd+5%S0>WDp@%NkO3#_=Jdq)1g>OF(ZlV@uXbL`E>ss_8FxUI8EMX~A^EAHAqGc>#~M9|`0Q)y-SW%xkT^810Rdt>!l;Hth+_CK zd$H*Psrm`qS&UV(v#3!FLp>v_9UHPWsF)jy2eQMZ7cUrKLB2dLIWo$%Z^AX#4tbiE zgKj;jcvk}|!0PJC-lIE@ZmsNGK3t)#Vjm7sZ?H7raYDt*yNstmut1D$J9&9!fA(&8 zd^{Koy0oa`MS#ZUr>RI4C9nNxJ*>DT=F~0!*igbNJCvGVz>bnNq@Qmnp(fQbli-mL z)2c3LF3I=Lb*VQ8mG4$z&evXwxlJnCLLDY`0%A*Qi1u9>F0JjU;HM~5X#-9TWFZU- z^{A?POMUWOaft=!x94&S1BczL1}z<)9n2%0RESDF*p={q+zB)+Baz=_9q~L^NV>K( zp4)9DNtwD{O~+>E{)Bf3_9Tic^{<#xSE9)E`F=aO#Do{I5!bLw{VD`yQO=%{uxeSY zqH=;pnhFXm<88r^iuTQ2=tPe?)UE4A6xaR#Ln^ zuEc2A1-cIb$%?2^XmycODjBTgEk|}%sVuWcXn61{FhY@89PAgJhGHmv#8tz#Z1)Tv zCQ5Y%C<>-c?Jw4Af`G2@-#FhShNpkFB%2%8GF52*C2X#9I;#uX)Ly6}HY9?`3Fmnx zLsl0$s1+zCfC*AXeJS+jeU7=5zGaf(TAkX$rgB)HE3mZCDMgh4rv7TV4q_)7Dn+LN z26JO$?i-xKjsb=-arQH!oMb~YFX)~`$Fja&UXW5y2}?SsBPv$t^m;l+W}opGtx~vB225t3$+lyCkg{xpfLP*P!JCR@=wc)`BFzVX{uwRG|XGc zLK1*Zqq{_aLenw=RDoj7*^LNr5mA5y4T_Q|3TleL@S2H*q=h}{mR?`JeTKNIItQ@H zELxHZ*Z)j7Fc%C99;09?S6aFL^c~MT8`^O(JoI}P0w6*)X$*yMG1Zi>FKDY18+#>N zC~h5IQma)YV+E`;ivV?1_wsYzb$y!fKT``9S(@jcrcaAM&)GO4`!g$@jz}Fv$>~TZ zimgOHuH`faPI*$S88H9}n5_l{f;>?Y51H5)hr*lIMHbQKSE5I|Uauvo+Zn($K(H=V z&T(G=7}QH`J34kM)BZsu*;>t_B)B4jD6)=C$Ik!}?HDon0J=fUz13V}qeaa1nYjiN zO-ZGo$fiKAazhL>DcDMtv^Y=c zN`abkxod0CIe3x)uiI^bQ|ON%WEVX2?ScLnVkq8aLV@&*)A!p?cJcnvrPKX`H+YN* zipKuo@bFpB>*z|L|4!|kKmj+mjH2=6u}%didi0XMxZ`C>98V(qa6*aEzibHuJY;n_ z%y?}r_XV$J@mdoqCS~}AcCvB}DPY*5Qtto5mH@tQ0m#-@k!}YEUlm#RHy_^1mCTTy zE8=aaNB6fkA3s*bt$fy>i!d)Yz|;AhxBK1Z6VE0@pXIE3TNzwrarc?3eYd&u$EUf; z*ZZS4XF2!&&cmla=3Ly{IeVXTA8c+t+VyO-d$NBpnN`_-hY1ZJI~`f1z8~D)+V#d& z0H3*W-f${1<+qS(-r2sp`Skvt^3n92;n6;VCFRPG9!6Dl{b*cd-MyRgQ1#K#QOmwyfspZrw@0w z9^J7)qYXG*(R!czKt6eB^S<=~Pc$CE?;jT>_IB>??ERCVWDD-&k$U)H=i!}4KWyJ2 zjUm5uAZe7bc|n=*NJ;rWdR#Def_yrBmw5^imh?#a_K$HjiRL71N%)LIkpT!!2MCchIet6bWRX@?NqYscWmUY7=1o?S!h2`q z{g>Em%_m{E(iNms*uum99%mC4>o!(zZ2mlMcu0w7f{^y*W{L^OM(Q(-i^Wr4HpZM0 zef42AOKXIBDF$PiTwtn2Ca5zXo@hNi1}Yl6V87 zyX3r85(T^3eAR064-49S)oSw(3)PN zl3u}FakpU`rJzc$2C_7S=^L$BI&TwaL~@FheoGG{&)y+gd%yRGZ+m{@h*OQKuZ9Lp zv~mlIb^iva!w$kaT4**f?`VL+WKjd(G(kB2R1m&tfN=b&AT%Ku{^b+L@GlJrj1U$# zA~9mvCS%0BIa%m4@f0T}D8(7Bjt-s~jBPnHrLAdZVRuEP@p}4$D}->MZzzWn1Hqyp zXHB#~0`av`mtLLX28Z9<)9GY-%O0ApYFuqu1)_P1rpKn{?;cD?r*pG_rd0v%*d%1U zUE-Ee{n6q@%@@3(?U&v$_7b6ef2jgjmXz4A5{>O1uhC$qc{s9X7>UmBX-&XxgL`=W z))b{emC#G&>#b9&+TJ$>F4Cjgt`bo2UxkP~MFjpL3B=Q_Ah3Mw1SW_R3r7Y%%V!HK zGt;_}a*NfYP#6M`6^k;@s^_Zgfy5=Z@rts)2m-MOK%pJ6*WtX6c7{HCa?>~E^asmMFo)=xCJJ)h9rUP z$Utaqr1?WFK^Gl}AztfAwx?rHX0Vh=Ej0g}dVDFj!TwmPUruJjqkbyDiBCB7Y$MGJ zv`fHrK4t51xkHC@6oO|A&TLDAc}*L1rfW;V{fHIw^*jnAH*%r@FA+9rFX5k|Cg@aO zO|v>A7!0SODkS5cn$Bj)OWtW>Hv_eqs?o3(voG~t4`BnCEIrdAn4 z4_+dbBCJu(Ozu5y>*Dil)~|}>y?~q; z&B@F8ODVMUTfi9Pp*fjClAw=DrJUax!=ydJTcGqzMa912hN^MJ{R*9R@Dp?T!RHF$!Y&G=3;aNn-+iL52uFz zItij68bc{7ecs>Od~$Dl@5(K2<@x;cKHg-%{dDL4ovjCVcCVD_k9PN38Qv`!x6QYf za-sLYGR*144#Xsa6?uq@V%84)1o2V?SuP>)lu@_v!Y(Ckq>{u_l@Sl0t>Ud$SOajQ zw$~r5UeOl6su5L&suF!yl^EXMVSzDhI6mXZ)&sh^j==Xvyl`m%4=o8TBFWZ3C1L4< zpzP~6tk3%>=Gy8BR-zF&wExB76~<)J_-{QQ<0jY`^7-Z2eC6H#%o7-Ui3jic#3JJ` z;cy!bV%uu}71E40GSKmh?bO&YQ^i{BZ5Zg)RXrKS&MoB2pj$r)Z)OC#q$Gs>q>qkGpn_~=9 zq!XFQF(Zj|EI&Y_P#VFtvbgJ)3uBUTMKzj#o7)u>d4Q(0rGnNw<}iqV0osJ!64<3mtDs?;^q;roN*GkB=~N<&S}cMtVbhbdSO{R9%jywDKEJf`fqK4Xli+p(bW z8^NnnI)!`$NBxbQXa{f75p9ye*)Opo8|tI7{rxQT$07-k%givaoy*58)+NK;=k3S{G2Vy+~Z zS{~;>Tx6!T!!apU%yFo;LCC4BNFBHQA^pHHF5J=BXQ{+D;5yS7mNxVS!fE27Iqc$W z>kEp})CL*1SU<_om5+J!CHEY@V~I260z>dM4-(VQkRUD}fM)4il3I4M+^W~+Y8-q3RbfjWT?N;FZ1O#o zcXkHz2<7O4k#Nb(MAML1BiQc{9xWi#1j-|>q*N0*H2Rmcm8p|W*xI!SN5o%=B*L^5 z{j89%ues=M`UC?=cnk8=^rqFpq_I(U+zhD)ayE|fw^v}F*$!ojLfnW8#VD@BW7e-qgbA>xbVN+rWt?R7H&Z;+s#QByVybH zPRhfhmj^KPV#TWTj0u8Q`PclI>RX;`V;s1?Q0v8ko0QO%9Rjwgf#LzLzgnh-S8Z_!Yl0j*%D zHH|#cJZSs9$=`Z?ZZ@ucyQxTi8rMOFfXYD4P>@tw=<0&L0=KsvDuylGE8ur)nWw?y zVOqz@i3?EI8bQ}YeFDy`|9C!prZdXlb5qzjHC67;~GYzBwe z*Ay;3r|ARf@n$G0BoiGXJgYwbX3GR3g18w6ai`24;Y*dgKyk_R45uiinfs3TGMNc< zn1Q<5in_Fk7U;1C^)0yy#fb>6u@1PtVExpsJRsKbsG@K_`3 z)#1UStmCdMNLVZpvuiLsz0MXA9vI`%6Bh3s`RQDp$J{iIhak9vs zT25>9?%@vd9O^YuKXJmJ)8TafK|ypdn=uX0e7&!anEmPS2(f74Q}-A%5RXST8r+)D zGIp`{1g0Jke8m?w^(5nFy#5&N2PhCkaR)U&G;0F|Nd@4r*%`&D1FT@HN*+GS9TFiHXZMIN|i#AU-LJtVOV)GyxVD?q2l z;yFeyq;OqX3rvcoR8d74^eH+FXc6?ORhD#51wE|9Nx*d2i3vwckh$U~U(aq}AY2(4 zNd_G|?o?nt!h@yZcua$Des}mhFbS&Bj17c$WFl0Sh7m{04VE%FX*A7YQYt%+>G^qt zaL?iN4vfW)k&;r*k|{bHQ`nYSrV-=ZB1da>RJg##JA|ZrQu4K;OVugBOwuiBc~FlK zv%g>P_Ucl;wupzCA(+i&a)1q@`7-G@2z4->Ct)C<8c9v4XoXMB0lM;K*oEg#ws**aquAN)6ax!rqK0ZPZU z7?8ZT5^Tue0ABzDX%v06Z3ns1UR7c=vj}zAuxulS_LS%Fk_iU`uHO3gV@)!KuQdl! z1zz04i+EnhJoW-(MB`HEP_-V4!{6?;>M=YNU)+-=!r*Iny)^R{)}Ij$n-R4TcB8a> z3Olui<12j((Uh3LF>U``Wl3*NjSC$_7Gl~lYkMkArnd{xyPgIC9sm;2ULRdETa8NcurG9o7qwGrUvoVQ{A z!R>TD$r@jqW<6S;Ym3GxdFL7pJIxEsXPV7?jfSk1%89&7S_9dPtr10Id%X%X4TVJrzdRlz__=%vlN&kwzGUQdp3=5G*Y^7e?W z05!VN#M{wfB=H;}Re2VvIGGC?qUeic;v{~15xLtmdTutOGF3amuQO56zB7lwEZE4n z)rX_Znq8NpOKKd+WlQT3@3|E#9Q8RNShOk4qvMhn&Hu{Zne==%Uhh;nEys94&v>J&OM!KuvQ&_H3`3DOEk zJCR8Bp}YHwb#Wijp-;-7Z$SjmJ-bfmvQMxh8L!;&3Z!h}DeLv?S0tDE>E6{LsFfKN!NGKKr5 zwQD;q{Z5LHG`bi&L25z40d$oj6t!qIf7e)$xat-J8|S6v=FlB>RmI@X{vmq65 zyiDhPh4qMm^ba84;J}Ecpt!3a=dQmtvBT#Z3m^qv6R?TRl;D%thIN6`^m17!42Jc|}I@q5cCLM{| zITXu={llA=i2=MIbBBh6yF9Zu;%3zl7sj+R#rH^Df4EOF0GvD}XQA}zR;TV;a9t3? ze=nt3>{|-iT2MQUGSNs8kTp5pe%D@%xlTh{EFtB`63(!*?EQ#DozL79ZxmY7>p{FN_n(zdq=gO z!dE1DDr*F;bmpearUmTjoH2Sfv;|J1>B0sW2ylh3t0$EXxkOZuNqcTTG68jIVZ9cF zB*Shfv#yOrVB}ZBgdVrB+HW}#@{)jUIBZN@UxaxyZ7HE2!U>#mvYA+f_b?pUlr339 z(-8j@n`0iF^i#43B$m?u5?0Fu`A=Ojs|gEycj)8QdKoK3P^dD43hj_`h!q9Gf>Z1Z z8@!V)a8hyV$Cnb!C_b zHgu^L8nLewE==jSG@%3Q1Pf+xpUC$L{j@7%oKZEjKi7B+5)Qs?kM|~EqSG&3bIDx= zEZB2894KIN&atjq#Q0T&h(wr>&Y>`JNOJ%Ri^9Duz(N#H+t=dvXZsw_XD^M1ycao7 z+q`lVz?N?4`28Hpr-YpVc^{CXTf)1bDas9RpPt%k9!q=IY`w%4PDD2Tsq+=u!s#iz zCII}$OV4`d53XYZhEKSPBm|VMzPW3z6UO=`v@FlRRl*0{LS_XkkS|L4By-Y(K@l-lHW>vl;mbtnNKa#l-0eV!1Mib=nDt@l5}~ zJbr=*xk$U8z|b8C!b3oK`ErJrb(cyvsK|+TCD~l=nS*uSeRvP>AdtFD|F_r!R08Q^ zXz)&Z3#N%)GXFk9zvc`P!#{6|d_nwqQdjpqKb$6x;o7McGnmEo)NZ*Jg$ltoUm(~}VTgtH^~d1{xb{gsO9p^0y~{-tByIeHHbNU4{wz9(1Co+_v$gFl>Zhbeuex;j z)&!dO5r=n$y5c#~SQ_I|Ec1(w$5(fsu=B@qF^IYpDA?g-M$hVQMm*1=@PH5X5dIbL zpTtZ+ai=y}?xbrC@(m5_7KwX5Ofd_zNL~nii8=TLE%K+Xd=&(h9@Jda+63oQqrp_u z)S@(8_NNZ?Y~A+vzOFWVz_Qt(EKS&bctq{M8Wl^g*|*AdTOK^_6k*05H<~z9aVmjb z(D3~P(a6l+<_#I;S4N_`z@-=*ZDQ1Q`L~M^61WWx>*8y!33-Xov6w*cr2*N^Na@;4 zp?7XWjEk^?a?p@`PUqU1q=~827jHu&B3L|s;w@!fEDsS|(sfy$5+cJ8zl^QXR_f5j z5G{j%H6;h4@@CH<`-QNRa8lEcu$Oj~Zkr}2EFSu@mJDQXrdWv1uj7nRBDBE)5>MoS zz?7HmBB@29HTJHFXqEw%(9!{0my|sQY?Ypn8o!$T0E)Cq?s8zih}Z?e{arWlzrOf2 zy1=A>eSG<+3yByiyE-~`NF-BUD~mFI8bpWd=fP~i}f$C#dn?gCmQdJcouF;evU%!WBAn(K*ITDHqT2)fJUK2 z0?m9N2Y%yNq3oz|fMJ zbi+&hXC4U_LgrVeFB{`8gJEFi0><$sef<>CLCGdL1j0%COFKLCFpGU0VV}VBoJ62! zWhLJ5WxgGjTdJRwqMun&u*15}o%9LqUFCQ4ap>)>yO(=bedoVaeD4ozjY|tsCtDtY_ zpl`$rf7qEZ%z>wPzM)GS0}pyB@2?E7buyrRZ!|ud`13Oc0253pvhQ?Jkym-+Au`Lt zElGAl0}|GB-kBUT_`YA7tj@1lS?_ci8b#*_F2LtPP)5Ly?J_ijAuPaqXIeREFM*5QKuolq(DMxc78u80 z1t583)l;Nd=H403Mz3(WyC`Oq8sh}HS|zHh&{J2}an;j`%!jkNJks#kg1^Zn=QMc5 z@rfNk>P*HcC*&M)O>iD;B3?hhBSJRM=97DfrG#Pa@ubfX0nb2;2sbjHp2ANRXMJ8% zLM1+sUW0-2?>WvMXa72&XjTlJd!v(~y{@w}K1JNRG#JXWh2UbMelE_q>;-NA>Sh0OP}!=DXaJ*6Z(Vk)D@QMhETL*6uroD5x%a1#exdZVbb`I@*luuf%9 zvqVl!9zd~$)A-X76*Ki|R9v%SfqvpG2WPCOh)+IdaQuP9G;|Jn2&jk##V$}>c8cxWh?SEvs^ zLUSHcc%%$3cz=I3N19Os3Ws(;xrBXyt&7=EwSdaBs&|t?TDvMzh?db~Ew|R!EOc&# z@SldAG*seX*O$;;tfR-c4|n`?G10+mORzv$dNBli`HPLegEYISs|_>sgJ)lV?Wr{vktdHZ*DCF zwe-u&Qk~x5`nGmq{O=|NW~-yL2lg!`_JQ2lN^)QogIbKQkn9JxhnwnN%cYZ|OnL%@UA=Ug^O$LlaA-<96jmq=W!g(?8=c-k@oh9@AKy!Y%h70t;9IsE zwl^7f@$^zpFu)GlWA6xz;KNIRKJ%t=&`L$hvvCD{_6ou66RKlBtreWkfd|JFx*sn+ z9nbcUq!V5{(@&1&>Lpw1S>P_;!1=-6yyEDu@!kuzAM{|iva}+cAaIe|d!)U@wMavW zUCZiKX{SS+Pq4M3AiAA>IC+UjHOiJ0n@b2T0%hg76rdIy%$Dzf+)NB`p@E5>M+&_@0NdXKtFi{YcKN6FPaaL1E)T0 zDD=n4GoL?~PWP_GoX=?VgLq+cnOBbucQ!OBf$s5h-*!C2;z}>*)dVgE!a$ii`vRj4 zF)~rggfk;<^#?*90@)lH}QZzy!w$axm zW5@&W(kt8;%s);Nh!-s?eptYCXh1N!C)=q}oE>U5pWtH?iiM5Fu~f3k>;1Pw5i9XtfDTo3Bjf%kjlBQ8CQ`(Zhe;>xPZm-ouKx%Wn^^udS~Yv9lF- z8M76Vty-5DW?707Hb}C;enJ>z5Z%9}ki=4$a6~mYot*aV{0pylnhvQyzlHkaAS+03 zut*(l_+;?@wsL0Di?Mj7}w z$JCDSzh&-{u)ql4HhpYIZy2AERXU)G&4nKm`pGKFmE+T?-5$0vv+wPl>Tjujt^k+g z*|)vd^ZDtmYu9GDa*CV8gOkz0bTXS9;Ue|q>L=zN%oU=xJCO~g!hh03mAY_`#cvsD7H zR$5B}oSl_>$_7;)m&DWL&jfpFjngmPSM@kwq=q_ZISLnu)0CbL@a|?!4$Z#WV{DbU zD1j7AokozcKODa;w&^wwrG@h5dS4ndGl4-pEa?m@vj)t~m`rqr_}B<~fhQ@28E;E} zxCMJY{=8q!E^35O;v;feZd%+@6l!Cp%mh-{m6R}o+yLzk7H3Ji%n;YFHm0H}3ICw0 z6W?5`pl%f^1j{m-YSvpeBNTUkuQ5OwTpwH?+@w;7|Hb+otK{1m*3X+Dc6k39&7_p> zqN&vU>~KU&Wuw@oLG`3LbL0U`yel+9bs=L-C0YaI>;Y?4> z!w$r{Zjm3ZvrHP+&Y}R<2QB`qr(^6u+1D4gmT-;b|P>=X#v6~ z!uiif2e9JMZk4S(_;>)T4f|n+9df{;XdN8;%Q3Pnq5~G$`Yo*)y{*si=1Y{5W)gs0 zIyi`*w8O%pyTX!gxW&ALb(X34|H+v0V}|z;xht)v@k_WL>8NYC%d53O9E-cEhGrKQ z_aZF4#oOUsJuqtWxNKJ?yBb%?W|Mo6*Dy_2P^h3~05!89D430Br?Bi=GTL@!Hu=Au78apx>=0jmt|07oz>r(#`%y&qxc`&Hliz)#v=E| z;7e5f8~)FDq_)SsD<-66luMZ)gQjIJvMk;bLRN z-7@xM_^+BqAk6XLC7ADrK$8rMu>t9{%VFEmFw6a6maGiL@kUv2 zq0KIhaX`>Xws=qFe8?794ArGKQUh0z2b~Pdj&R{Dt8dkkm4V~cg}M$cURS~%#*gHu zNc)Lyc>KAz+fhN5E*g@FU^>KeE;1uV6BSyKnKbnh)6fq(2;kLpa(0R{j-lfaiix^T z=~dfxmbx(potyr~hD59uF$JJ-NEt1yIV;UWf97t0w8u?>PAND}0m6$bHsqkcF-|^2 zr|OcyZ{`TQgi@>xJR>`H|19P>ImKoJ5Mswcu>>ar)cFW0jKhQR0s9UN_1SHAE-y3fw6*{cOM+Q16X%-oJ&t7#Te z^cKBWoFSrZHYlrw^nz3=H%<)x<~M1QY}cjWKCpm)=uci!vIV(!;6!HI0x4dB9A%{; zLxDuM?xM5CXi9mIwtNvHy5!OJ>E%%n^M^&RxW~C|{1RUKrFNpYH zEjtcA+4M6@`cp+QWkw-M@#-}mn-uYvC6J;Vix|*hZ4aO@J1Y1LCU4HaM&Pr_8G!}= z1kqrG4!oy<&hS`jndS{8sbJj}lUd<}=?PngW2iKEHJopfL%Pa;rA@`SXlToxNXuV% zK!vVriyl8~d0>-ozJ{t4j#wpxtc=-5` zCn`xa;9o*oh>SLNu&~WmeQO1ZsE)}St*SA+% zk~Z39zz92_e{00qJ;YjSMP&`){F!JWScpYs>(La5Pa2iON-Xs~t|CA>Vp0rA^LQ=#2pq!C`8&v{7E*eMc`nVgi$y_N zeMcXqU{CmnmO{+=GVbMI!}0=}q=fu3n}E@^;4S|n_`IxQT3X4jDTcPKkP!2ih&BfS zW(!xnXdo}9P)iqz1)ysEjT#O*N*q|ufgtLu6Gxs4R--2}V-zpoQBl$SsDsDUnj9I@ zqT8N(74p88LP*v$09D$|dG?bs09&qd%)$Fo%e+EcRM_@J*#%Wc@djBp0C2&k0|l*A7D4y?K9fpl?YnCzw!;j8xmNft`ppR zBAKJwdL-??kEAp@dp|4{{sw`Tybxx}>C~G^g??K`V?sD#uduojC9bSo9t;pBQ)Dqt)1L!vLXcTQ2^zOvNb9^+z=3{P+SYKj=uDP>4ebH#t zEae6u?IbFXjRGaxsSl5)gEX~Th6_Z@jWf2krGvpBaFL|gM`$#L9vI#*vX3YfIu0KM zj909X8&XJIXT4STjN4Mzl(IH$_vNdiLi!veCkCdD#Q6o>~3IBu#r*2uCQfR{)Z zJ9qw)Zx%=>h1Z7y2pP%AGdTj}0P@S12?Q}}xi(||o34=r(<(r2z{~hW3@LEYry3-i zr4^tj5gK-fPf$(2_nfhRVAMoUZ@dGy)mU8l;0&EhGH(6lXCnSTT~_y1yTu1|xHobX z#oJ&i=p%9U-O*H6xZH>2y@GZzJt%IPiA}D$jLT$r3(;OSkmeb`lPccb_Ve*&!efk^ zCIQIt`m5L>jDEZB#L?MC?;F+rgL@jcp$xP;pq-86uC1%aK?Gp*e!>Ejmm{`_-GXLufvX2voW&0arYVZcTR@fr3(ZI9_S z&jL0SufkO9;zq;SJsvtS-)i0WbNuj-%Q@Q-+oQ|^Wb&oleLcj*!Dx!&@WDP^7g>Fx z8^&Ed!Z?$oNT{|d;63Hx$;;ypPliWBJm!pe`D}*Mp&#gz=J-0dhTaa=RoXHV@I?-M z*UzTIhiCV2>tO%j4Z>CE7Tu1phq^7-!SFD!89N=E&5v%%yR*}M(81I}7*C&p2KY-| z10D!{_?-q7z%$V+SnEdJ*|pT8fW(73T~4Jw;XcA|dm2q|Zg2(5!fV%d2Ir3!=;4{PhMPC9 z3AREdha_Qh*ie{5Nsv^D5{)&MSRcVNtLUpsGf_vjXcshmdNz9vBJLW|%Fg)U`0Q{f zcV@UGp9=$df*ynwUgQ^7r?i`T>@*{{v+zreM75AUP}v3y*x~J-`LEGO-tciHN`=#0 zcChPQUOjiGI1c5ZdP&sF*w#qL+@O-?Z|YP3a+_H>fCH)ogP7COO(*szM*#&_Bb?5g z2USi51vOi#p{MDqw*em`jGcaqCPdQU+?nVPZ@-v*b8SH$AWa<_I*Vn`S0{iM!ol!W zEPF2g?%`Zti_WVtR3l!Cy>n)Pi*#F`r^3vJB?DMjNw4_Ob8KFM0vz%#X?{F;i8nh8 z4oTm9D}Wmxcn{sPA}|Lma1oD1mq=%!Ok=sNAe{mm#$m0cxWo?lO@a%52X^U-dd$YoQ21 zafj-qufOESpcyQZ6~t)9wHWh2ZO$T)NB_f8S6V!m3tFyj%b5IV&+YjDYDF+wqdW&> z=d5w(43%i%zk;fode%=TC$xkq;EW)~zyE?c)?eC1S;K+ z!}pJ*f3iR*a1Zv!qa&KOk+x)9%!FY>dV@7;Dq({p4e%x{`X)A{_GlK)vm#aF;0}6S zC~BI$T!=2uf%GR3WfP2GJh5&Q2SKC-dvulqu09=4SzI7~Q3Zxyq_~gE`%Jfs3%W3M zVE1q6`fu7X@2m-=&N@?E2H=B`xz-cgBS4BQt0(8)qL$o+C3%)D5Dj+b(RE{Y^wT+- zw<~#XoD{DyZNsH>ZbG)XCL9A749du|uoWmUVv$7N##uEoag`~tQPn6nlg4{2b_iqm z(-A!u>(D_E zP>Wm(%>%X`FbK))@Vnvup%D}VpTHu1pZ6R|FR-)h&pk5A=4_h*QAALq8IOB*PlpGi zqtSsE5N)eQGsCMI@$b(@2T#t%2&gjLdObXNqtpcQW7y#1g}zKUb(yCyD>5+1Mapib z=Ujbzgw+(g|H;(Vs?>2V_;glWr}Sc&rh}okAYcx8O=$-aczDc!-N9Y`AaVdcRV&7F zx{V+*Tu)=|^hhvC-3qZRd_!9D9w(c?qK|k2z|&nfajHw6>YnT$KQWoea+8zMTw8?4 z6TSsx(#6g)9^-C9omuo)i0lBnJA(br+-yaMW_2fGo_%$k0o#jYb?&aALOhUUn zZ5YizX#SXNbg~8I^Tm8~M#(4JJ|tvkx;!cRm7kI{5MSqaSblZcWB#c~0Yk17oz3`dJA^I6AVA zX3-#xi7sxFEhp~i6QQRBsGlIo=C+0Sj+PzN3hUYqYde?jt!MLin$;)uT5EF)ed~DK z$66ui*t@F`9i>ASHzpNih6TGZm$+g0p4;kC_PF3il4VJ%P^In9_>D7egbF*5NNSO) zbz&1_7>)MPaVU3V#H5;m*VONQbQN^nX+X6mg~$@xj?pa{n-fdkLhtTv?(J;d-?`n| zL?Z;xu4sxQkFA1s!iAt^p3Bi;X@PF1$@nZR$q3=uD%tWUsxxhq&O883gexxi7Vq;{U>Pn(LD=gx#m#6%=HpZ7E- znM&!Qg{C1rOwz?Zs5rxby(0I(5PWW2PjMeFQ7riXuvDJr&_HcK`O@1PR$cs7;nV;hlOcxX6A zuF~WPqaAQB9sMFsR%FLjKF@=iq2Oph>oW`K1&0TO#8M~^gn)~a;2BR|>O%h9JIWC4 z)=)YZk9KjHEuE}GdjM_@5jc*W@~&4zs^rRVr!TgF<#?zL*b$0q`QeHE#va#c#{JE` zMMWdTeDt1A8T~+7$q7K0pM^E|00JA^cQqHkxn-WgB+a=-Ku6kU?kt}J@)MYk3&v!HCrDylD+({WPhTh4DVXb2 zW?HqQlSt_OGXE+pU~%+jL99-#ARvfx7O9FLidPYD%%~OK5PG*y^uiErm`+iNWkA^A z2*M@>q=VMeDL{{M!=*yB5(*ZxIBuN2v3*Pz#dwrzL+4@FGI+V7iHZsu-RiTHM8sJ{ z5Lp_Ai-gNx%s?~&2bv2C`4mxZ6h`>eGzos8M%*eJ9X5!o?OtGZd7BtukHnP4YH6&| zF^`p-4v#4B&5A>sqXywYPBwjxVV8mNJU$Hd*V?8q)l30P9T z$|t|^m{X?u{URmVgWGzj4GwfV{|?r6@$n?QDq1JDu^>gnb9c`SDf1mR`Hw+hk_+hr zbF6wvgcY^YR>l1|B-BZfCTF@KS-D30+(KAlQj-v>5Ei*<5pchea)w{gO@(uZ9XXyg ze+6UAUlBEe@4pmQF|6P!SghbyQB1F&QT@YUNJ|LUL-ykp^ZJ$hksGNTf}-c)Y_N6g z+hTy^Q5r4$0^Fce9zrlAJwbW~V$t*UHvHHBAm*z+-{bum#L76GjxaC;;A4b{b<_?J z@fp~upamyKks=*UW*9W2)D$c}i`#;xgZz6$_0raG%2%QX$nXtxCo(**3mFH95e;k{ zI2sOs27T+l)Khwc6Z`K;8$Z|6pfp3B_%XJp2Df$e>Mkr}<>2|M19aBO*fwqAaHh33 znXq)xOX858Dq8%w2eNCPB%mJWeKIaI)g%6m0qJ%8d&U z-NNCixnE)&xuGU2HY`keG)X!&N;KKBH<*GcYe}?mfkAh18jVw3bg&RXE!bLAP&lxH zQ_S=;&KMAcay@*qC1uf;6 z{0pO5AtlUg(m?T$)FLmWI99pc@B*7DBeHrH5UwSfQblje6TEl{7# zHU`nZ5nd56-T2&}F`92vU3!4zHa;z}!sl22YWP&=|5orxU;E+V`zSBOSzs&>BkKQ@VR;UmPW?IB3I442++TQ_QO z9_G^6Vmal_sDS`e-;i209=hlZp@eXC3>+2%^Z-f*5;h*l$~yO7bwq4Bx&>M?5TBu- zStU@sl?3AmLe<&siJ@We6Hl5z;JOVouDAFdm1cc+=EpT3Ms||Cw9PKfAjQVZuD4ok z?YqpR#e3d;rA9+B)D^q89X^ixI6>6*oATkRysyXTz~cTsP2*AlSM zlEU&53k!%XwtXhbes8;=Tx8KITy2svgxnhEMO)(_r8sAG8~xx1aTgs51~*2L%Vt8v`U7AQ{D4 zNj%YZ1S1CWWy0KtPi?KK9e3q`PgU53w;1-Y`9ksVqmqQ-}nb*eqFAOZ#~NYa0)4&{|>jQPslI3o8E! zo&s#eh62v9K7K8ZE-q9FflU2L>wX2slIJrX!}pJzuTopy7wi$n~y zNraWGYVa#X$lr-dOLvxE?VN)RbCqC}3Rhrw)72LVYA^W+N2aoiEhlV}EX^v+lBknWP2RXc7(`f*iC=?dcOL54dnc-5- zXZ3Ux|LE@B#zIbiF+XYWJqisEMcU{sG}bE33>KSy;k3%yLfFFljHJJdO7PX2551VX zx1@G?su`X*{;an-NfmuRoei5sc(11IHI!OSBj|L#aE^KsLr8(jEUDcinF|14W! zv)hVIh>iwhN5`jM^iZWq!h!Dd4gCfKroz9CwpA1S;E9cMMy~X^FRgu1A#jb!zn>2# zi^5pMIqz0Jt;JEjv5ebh2mnLDL-;-%bmBba_w*h}h%a44N{ryl#V*r*G5dYxAyO8i zgNT~V;v*ygwyGJ`ZU0e2_{i>_9x7%5hgBqG9~YYp76L{CK_XAAC5-i8M>DArl}xDV z9BCV%h2w1(ZMns;!$554C;Z!qi;yST`A^G_W))3_J1a5)8MA^fIU4 z{Afnp@V((f*>hD}I=44hJl`$%XsiRaS`~DMyC)4;gYbIpE9?g)4f!Ur*i639c1+Z# zmR=Bmn3icqMWZop0L}#AXRXvEzYR-Xw({^vj+3hFYLo4O%MKP0sDap`Pf%h-^VV@w zx)+jNBaaic_J|Gq13z)YEO)vM=HW+4Xg_g;dF4_hwiq%F@-EXW5K^I-Ne8KGfYF?> zTXQV9+*c8v26#NN?OT=`Oi7cJ6hToQTA*H50P`5iWFjQIn^%OHpqgo95_Exoqq|0Z((G!ph&6*9e} zE^sT-^|~eP7I-@-?)<0ure+!|?}Dq(zW?j@cyB9$2E^R*#dh*{YFsKakK-TQ-r5Bu z4|oad_J_INB6>Q;JKl#w>Z2VKyC~v70+t<_ROG_2hns;e0Cj@Zn&lrBL@)^0dt6z& zrCV~@DJ7h=&O1#t?jmY00k5>yhA{2uuBn|E63WiHN7TLFnfffG1*Nuznb+Wmckg zPE^v00iCV)Xxx*9wn%z9p6wqE8xFokQ!;NBE!1|9uzPv?Vg(eoWVv@2f^_Tt6OY>w zWUF$W3GQ`C-*5Rk*$+giXSWxx(Pr<7=%f#Nl^c4h=|U{3r- z9iD46lAg{-uo>}ewC6ujt_TGOxz`+KAV@>x%e(UV_E#24iEH;IORU7)hs-^&A~+7a zPZO3o!)yJ(8PQ^*uv!5}Z|(gTYa8^V%t12cR^CY^-B*%ZKo({YwmUiY2t7bly1Cgj zi4YYtU0uV>v)rSHCY7BR)HUqQxC<>RJou`~K97zMcjq7Qa$U(nj0^>{-U07=s^0sX zzkBh!4RYiq9P~LKWox4+FVm89%^^HNVMB)0!sTPS`U`H@EUiet96D{y#W&t_-=EHB z??%vQdiU>t|6uj)jBA^CIA)q*#p0qj9ky*`$=AQPjs7>shafWbZ!uB}wrpN(1gQXh zG4&w~AbB0fHU7i)df^7m|8W7~Fg}D4O6m-^Rp8)5oWlgVU$<=fBuJB)%smGue@D9N;#VeimZmigQgN7X`T8sS^#DTbpb(Y{rL zfpmB~Bf}$)lJ5H-?Rkh7n_GK3;G#d+!<2X(&=`s@mf)_}TU~wsUhO0&p;=;{)Y$dz z){tzpx~#S9sX4-2@gml>UhtwCN(0#4-A3cstQrXTyit8NzqdCA>m@L_@G`_YF@CkX z^WaV%S%xLGdx2WUQ=CJ<=P`XVWnJE0;ysPsAtZx2i(?Pd$rm86>e_C_A<8^u+=Z5Y zy4|Q3f!wS782J1ta+ zh8ElkE@6mt-r<5qEC@Rhh614<6ow*8ZINLKRTPbg6@lfR)I&m(WoLq*Y`3?&{hbrp zh1%VmeHb4UqbwAHmSeR1H87%r%Czirig@gTEKaNc^cmZ>s|o35LYuIfcNZ|`f{K^y zd$KHQ1P@CzEqj3CCgrl(EKtl9M2c-ran1c0n?6x*qayZ){{Yxvw#I*evI@WM^4JVx z7V~H8D{pvy-p>M}0rr*dc_2Qyh7cy~6Yy2_eb=+2tKOZ-!5LQ(Z>^ZocF>Z9DH3XA zcME{Kt%xVlW2SZg2_CPjPD&mfdZRnbH26Q+Z=z`J%dt(D=AG?+REOAOAu|hXu+bn#IOaJ6zTxm zmFkA1fC`zz?ARnG`WF9)N>$3Y-7Rx>O7A*h68hOkl(I(SE7N;Hu+YmCg+^8aQV`XR z1Xat(sAAZpUjF^%!WshkmOGw^NZC>l$rACkC>V$VQH=bazd_wpuA`5%k0K@18ude;u0jYzw{a&vk2$Tf z4=0h?lGXuB6bKmd0)>^if$7|%qJngEhe$Hf4 zHwU}lZ9dt)!-zf5$_fqh;Uv{=5x-$E<(t{Z9TApLrAIBS0C634$zD|3JOmo$ZqzkN zOcIXLj)0C9Xj{ti;J-vzLYB@mIQCrIwRF3G(W=P~Js@Cb9=Y4{v%ML?({#RB)LoS6 z*SE{zvBieWKv1|M%<9EZS5i||y~YJpFq~1qG=AmtzFiS{NGIpP`{Db7c}fb`4V8Gq zz^b@w)J3nbJQ(rag2~Z*uyqQ-VAosn#g(i}&iuuMBqzK(@P9yLT;-0?yov>#6;~JT z@m92#rpuY7(zmpgsMiTvsXEE3ui1DRdX!;`0suJASmR9~4YG9FW{e`ZB5HlJh62_v zaJlO4Lw;9<*`w%$#McRDi5i2^q`Z7*Y4*+Tr^*mD2o-TgiFrcX&H)! z#b2-q$@jS+f6UhtjpmJkO+cckG2hE@YNPZrG@RN48tD>kdW>bz2@*##n;f4}5?zhw zuYeV-t$oBd(PJFAIR=;4=Q|r;pgTEny-%*67nQBW-hZ{@aL=Cvv_KH@Pvg`*XA zW5S;>QTI>TfLPh2xZR4da+GDoV*)j_mAU**Ta*+$_n6JIbq%? z$BG5R;T@yb^ZDtmYu8>)1~@kJ6%U|#8YtolYOv9fipZm!MaNJics`+K}{%%*Q!uERg70_J;LOxn8q zS?!4i49tHuy(hXoU-5~O1n}aTPg$#uXhm85ucP`H?S7)-)8eK@1ZWc`0r#t|o0`|E{! zj9joAnk<@yy#sAy5AH@%7Bd5+Dx^g|Nuz#mCwEW){d*k8=8OwDWtRk?cTfz2#+iuO z1PGeCcY@fmEA#)3+9*JJ{v01su(@F15U-BGo~Q3qES~7J(M|$ju^q%8S1JY3Xodql z+>w~UoX8+{_VW#Vv~Y`&q>qtPTLhglI7HX0ZEhMV?I|AI(nOEC0740uc86h0Y2Elr zP&7)%HmK9%FejF^h<5a2eTxC~6}~+NSwUQXw0EZx5?PR%K31YX(&OVh_QSAbJ z>Vk!hCv@VH(C7Uk<5T&RLI`Xg4-aLY35%j!<{D9a3uH;_&Gieo@H1QQjROz%$Bpvp zuX_VS$b4Ys%_r6uI@tQEg(HeKx&^iL1+W<|( zA2Nu_fejQv(GMx>Y`%K*P6fMTwos_KZsL&%7<8bd7lG6hJTmeg;woYnKse|aHP9f( zq>T1+P}TxvQHu$l#jC)Acah?%z{)8jMA%x4jpGT7^TnZJN?CAGA@VPDJ>hgPoE_kL zigkhuX-JqH_odJAwZey#!e7j`tN?h@Vi$KLV|OR8d5q$*%VHcI^C1kF1v>k_E?s00 z%TWevn=qJM3cX=T2gM6k$t_;cqjTh?$x8O{bW|Ya&($tk`;4v%&83blsY?Z#GhIkP zCM(g!(Jm-pMwQT{qem|(d$`bXDFHm?t#?&5KH+6SDq1qy%UXvnP`vD|ll1wPjBjfp z#X9KyQB{DeQj72EA`Ylsw^~f)tw(G+`hGYmpSkJmw=9qy0+)2_SFDma&jjWYr~4XK zb7IWNZ0pg3JDYoVC&!1d86|4*-it*dE_UT!n}s`w6!+118!QQ;;s`R7_mh3T%>8lY z(b3Vjg>T2oqw%-ByNG~{UUVd0WilgW@8Y`Iw>`-4T~||Z0y;cI%Km%(Ld;h8atsGp z^eLAP2d|8t4Rut`Xkk2U&e-Mheg{MXFrHlT6qg$fP@ud^n zG*CpyN^TdKZM(UbSWC~}#%)(`FD6i>A=Y`Hsw6gEB`x8mBLL0|@Rk)$CNO}7F6p}9 z@M0qt2O@r!E-nKt{^l-c7nmKr| z`N!?MJNLJZ;!!CL0E=}{i(3#zGXzVfPSd`<8L#K=S+IgYzC+{;!L3d~Ru`(%)-U03 zilw-C2+rvwSQ3X-dez$e>41ZBR`8@Ko+N|lusOtdIUW`Yq*>*`>A`CYokx#OFEiMG zi9ON$wcH9gpI$a}*2i1lwFC!_0cvP#>2Z0BFV^W=wRwL=S3jrChm*N{sr<||wwMbb zrjJA(^lQDX*Bk~#E}HJzP{ggZ z1q~UiMWOSsn95~5=A;HDQwH=w-hJrAWh#VuNWZ)BnX<+G+zq6ZjMJyfFZ0#7J*RMu z$eKc~hjhlljBs-c;^(c@-jEXR6q;v(Mlw?DE|Z zhZEs+znz_Wx~;?oRNYn!FU?2UTPCZ=)&ujR+up}7W`Dy6B*Nef=`FRz+Y@?FNQA+{ zW8a1FH)W>2o4T%d$jYh15I_;fs%wF<7hB|7VibS8|B@l)Y{{mqaJMaEaVCJw@a!X$ z=>cq;JSDumqM%;owg=dBq=CBCq}8{d?FR0%*KZNWi?YH&psXt`Joy;;iS+(;U-X-Qcwo&QWe_3ELGMR^}Dwus)jl>CI;A1l{zJ@ZDlGRc4Ly9Y67L0|{YkF<=;q+53@TK;cjQB=L1-)Xw2&>W+bRaGh{2ABE zSf`9FVCw|}4vp*(O&hqD5JJA*(OIHz5RlVu<;R4xX=DioS8r1Pq3!@!oD;Pns9qbk zk(-?N;5B}Cd=7KQfou|bAjjfK?7fEij>lP)jyooHZTtyLa#+@}B-EvJ38iWqMWUBy zklPHV!{ygN5-fV+%M)5!`I8FvAUH2=BW*A@1K?qif?V}Sgl)iBk2rmv3rIY-)#FyP zestPdy%PinkJp~~Olk$dbUw$sZE^8Aytk{HfXy}DaS+Y@|Lnc_bDT$#CCI&Zu~*OR z?(aD%ahRAQl9!}bvjlZRASrR02aKSOHi`oSfdrW?AQOd5P~@=nzwdj`-Q)O<1gNTN z+p(QeNysk_4-XFy4-XFykH9BiTCjZ;@hhPFb?`!D_Q5FxSA&)vZ%dc#W0nE__lJwE z14J*jeBZR+tmeM`cU%B(4POW7Ho@8&k!d#mM0XyrRVO;lVKOHw2a($BCvJKSH#Y|o zxwT4Xa+S5pW)&)hJ!=pFVX^@v-%!OK12X{rq*M!s7Qdl!V|zE=_6=MU>`taOgF0M; zOAdg07$!J}wzTCTb)u)kwZ}mbYV7TMozLZ)35bCJ^*|o{;r(Upmdz={R0G)VDL_jW)xg%P&(#z*Dfa-%_c06eRuC2>zanOXK4Dz& z_WVuUggFa63Haa-o2%_l&xyy7b`!wiwOnsvYayr2%bd0F&j0d9hMC%1ZY{onWApOi zj4MnzS<(>(N5bv`UgvoRzfAY)J%KRa^j{gPs$kuw$W%wVu!xa}m>X?@Z5=SudcXSy zVcTq}X&hqF{WS(g!ZyWDF6We}R5cQqt+*Q5^UNF3!vu-_o|)k|kGyS_< zaIE!tP<6g+^{@sn%UnZ!-hP2-PHp}cK><{4{-OAMJS#oEy)t7mph3{9i! zU*Vk$*#53AzPe#1z&_Mmv*F3k3Ro>b-m$C~@otO(@a}TJuJC`*s}y@C2+C)-ZXzHL z-^y|p#7B22FF-d0FW@N-jOkCQ`0s#XBdHu$%5oiWMpVI1PuDr0xJG&T zGmA1A9*XIZ9zH;g;1E;xiVLIQ^!xTs0&hpWoi5Jt9>Mbba5~4-rb`Z!PyPH@?=EtO z`T%;jKG3bq$Vy4pDSZ)7{dj#me}yoM?W+_K5x_7zg-Hm{2;h?5&kS19a~;%4regpW z@+(0w7p$%0Ba{2PEP#k@gp9@dF&b7sZ7OxoV?ndoV}eM z@T$bS_Z=l3KfL!Sm*0NmTiF7J-#x*7SDiAn3-srp6SOWg`d|i!+~^h)^5;)?zPPFA z7dh#h#Q~j-a{|j0aVJxMcjk*_n{3+3yq#$AFXSi!L!^4GKO+Y9IgxkK;6|~1w!~EgMfc^x;%dvQBIA{1KxXIXY_$XL*0|&^a7yRej5v|*AXKfoF>*Dpfsrz3dpg26ER?2>YLi^U^ab))pn?Nr z7%JW>5^$&sbObBz@bV$#;@WJ&(xw*J3=E<&&WD#&*=-h7x{GT!XwL|o6hvYiJuK7_ zQoRDOwS;5TE5xGUhBinM0Y_5+n9hgiL;H$aPWK9YiJ$eJ7;ul^j=OViX*mxM^h<YG&$)v#qklAc_n1Dhqjgx5@0d&|=SV%8!K0-r8;Yj$nhlS1P3;3ZaF94U<=v-a zc#ddXy!*jquIuJ9a`_I7gOGTbk8Efyy8SJ9l7hP6OSf2*JXo!$tyR)1G?vJ3&G2E% zQs-*#^_q)gQL(Xv{IE@hWW)`DD+#jdr7>VG$ZpKaQV+0zpdTkM_@Of{j>hn%7a>+r zByA~FR;Nt~f(Ah#Y}3s;Hk;Hwv6NgP@DM{R9-F(KjYK&=0+q5~23IP>jToz9oJx(i z94zfBL;YzDR#{7&$BnE>)-p@n+uQUH+ex3le9J{8Ynanh13E0Suv)4E4W>kiS_A#4 zcI&FvI_5n0bvlIC(Oo(=wV7RER|6<nxW?h%m1e`G;3cA>#f`SQaNBu~`F$@4F%Q;e z$Vt1nd@o)3RWso=j=g7J5uCmwe&X@7$t&)#2@g&Ljfc~e+IAvha^=axgcNB!!jd!5 z56IjZQN`D_7`Yv~sS32<5{3h(5i;@bkFrJQ4l9mGInRLFmZc z2k*>;-3Em5rR(rJT~uK@NY&*{&#dxfD!%=Im7j+bKIZYoXWvYhJJ755U+D#wowGS2 zMxSUz4ngPFbW@{GH+ud+KUmlC*s@|4sk(Vw%5tdM2*=FS`u3{SoQ9bz^COK>XS4m| z4!+EVy7}GV*m}Yok>Qs?NHWp;c zAvh zDXX`|Y~X7&S&-_YB{q~4%yTH#T|V>_0Tx`j3Yo;@Jf#hlVin3+Wk3*#lXOFuUu+ce zAYz&{p(;X4*w5i;!Tghs2oy|@)4VXXm1)we3faiKLKf4xjk-CL;XJwfo-g$9qxDuT z6XQ~LHX$(;-fO-znju|M8a`DJJHA9wKZd{ zHO}}f%}SP%)M#jJ&QcHx?jN&1%Ob-oUu2v|Ws02Kya}*E;8a;%!X_73A!u@;i-pVz z1ASxutrR#bz_f+Hio(5OA^4v}??ntuml+~za0+0Gbx6r5L70YR$pshb?q%%~?Uo#m zQ<7C^+g!OndpkXw&-lPdC%%5%(m_$rDe>2(r>wBrwDH-c?SQul+8Q%hv-lxNN0pXk7$ORBBT= zW%ZIcovSrS%xK9t(#+Eb-2pb4$Q_)SV1kA=rNo#0w0Zvsm}fR$r1L zgSP8;ZwUOE$4+?^En{Lax`K`z+l1&U)ytHt&TxCl(ZP_b;IvU(Rk|0|_OWa)f}rBcu@ z_oJE*X?qdvB3Q20(Q?l0Z@0tM;G+=esNaD}N2wB}LNfYgdV_(rpC@qqh`axB&);vv zxDI$z9x<*eXupls3Dyag&Nu(P@GWzn@zNJOG3s0A?l@98L?5r?rAq-hx%93w%yC@^ zucKPrJ;&!x<<9e&wzJe&8cK3z(hx?@r$#H=`_E68Jgp(YUeOqaZ`$h`UfLb;?A#&A zeB==`b#k^G5g1mT8;^JLndT>IAze67jP|W`CHAQ`7l!f5Q^cW=2uP%>m+`P+!m&{^C<(FF1JG z06l3ObTY@zgyaaOf+)3w(hR#VkM)#f#N!MivLp@=`ov22jbKUq&S6w_aK)v@5wFWq zb9S~cvJ(gLXI?JA8D!FYZ{s7lsuR+s(CaZFHaO1MshmqBGSSVB z9kIT9SLQV5W-`+=!!AWUnKNus+&V(or7{9hHAPFr5IbjM1NO;1RA8)r4e)b2M z5nqQRQ3Ci~15g6E6y3`uw&sW_UorY~nV|%7IehFceqsD+V3qIcX95{p9Igt`=9?y# z;mPc~(X}im+lpxCTw`7I0XMXKwqptxYh@OhZA(kthhvK+{89LOofhuxw*Fk)d0(** z5oz+o@vbHXWtUGj6P`-#os7qa%{fQG<;(?Y@?;?(aN-rYNm5#VpQLn*J3FtMm*T!K zS;!<}gJ!&i&8QstxSYFpIlQ-zW>7scxS6@5nmS9|p>toy1 zo=qhoeUcV3n_Vepr%s{aH&jLC&{CwZ*ci;3cn zBGD{wj7QK{AL{eA{xbES(nt2FzM8&k;Ho9!ByjG1i8&q?A-UY^t@Dp;>I9 zDh-bi+LT1*Z!iXZ(4mLgI6}Rj@c#XXunO-%zy6#293py7GNH@a0kZfK?qmildDVnp zhKb@*3_DS>*~{2ZejfSf4gZ9ngo##mI*8*6KX}+6NKCD3$6{6q};e=kaBVCZ!P$2|At$v0(9pL zKR_Gc;GfTap2a#|3_S01`1jD--0CttCX1?3o6 zvM7Y79~JKWKD!+7eC_u4+r1v++v(qu+Zyu$-K8mW%lEOaQw538>x(@HjGA<}3t^8ixHhjq ziV##H2fn3}pa9dukH8#>X)-x5vK8elo^GS0fLXh7c~`vdENxDCAd_`1h~&#bNCn$1 zGuB;rdv3`zQt6e6KIq=?W^!n7JgeMWX4nVrIk}jhO>9!3ETWZY1;{+hS}3E}^^~UG=QaHO^KdcSxm)xRS(2ua`*T?EJ9C z`zquXeB8Xg_GCWuU%QZa6A1BF$haMm#q9Gl+GZUW`ZgEMMAyOEYC@rM=nJU(@weLY z1?Dk2I-`8dieR}A%6??hD3>sMK;pl{Sh$xC(h(dte#3}^;miH&G;wl(> z3XP@d9fSD;BYg}NKxM&L%!zC$%tFJ#ow|XM8JlR=HNdL!DtE?metiTjB5c%G7B%YT zm&0VND>dnq7y&u*5kY9@&Ss%Hh(@ar4qBzSEmH9do$0rl4&%{@{uW))njhgAQNivhSB&Vp_7Gz_6>0 zO^bciy+6bG03Ju97xbL=t8tXc*1`zI51b0zG_<3ni0OlCR0F6xNkDdUx}&$e)gPzuS6t|K6jA-*hA3LJ`(4oos>& zNje_lncHqWOB53%Y|9B-V>qCc0LV<0BBtXa9FAsSiQ^S>>_vI*HcG`^wNBq?Kc-fe z$|=|Pc@Il({NSRZ5a(J$*12TPhX*8^OH)5!%6Xk~3JX{}tdK!58d^t5r=%*S@Hdv% z**TKivQ76`OJ(7C5K(gJGlzFA8nFPCYL+uutl+26MltA<+5mA1LC%o|0pdDGgPW{p zva&?Ssu>jK99a;}Jks+F?I7%nG95-exSIhT2_%?gOGEZY)dEFT*U zD{E|s_`>K-1m>P?-ns5?isDmGi6TL-h{913H+S)P=D_w7ff`IWZU}jKy zAOu#ym?lx7;oQuFR0zyyA|2m153MMpLX0^4$zd%@Bq%EJZxnUxGw6QXk=c!nKdiEh z%;Y|poA2TACfmqR*vMe)N(dR*`c?Kxbx}zsqxa>6LpxA9F#EfV-~^rw;LVm$&A_>? z0kq11fI)7}vUKV=vi4k=X`z_KftG0l$;6`HoOL|WXyUV?=Y+t?QcX8`?GZalc}C}V zw&847SE5!=PuPBf(QWul0bb2zr8K$e)am0Qc(Qt-81a+ljBPO^yM`@>p4I_}O4!R~ z6ui2GIcYJfTKCYI)@R!cy9ahxG3g$re|RvDP`4D2(&}T$H2;_egcxKYKwfEpfQe2F zZqm%gmLOD=VVtrT4C-23r>gnJ!qRi^ERDT;0_*)rxh_Ezg!0q1NdE}M1l)S67Z~gP^2%n)s;io!!odi_5lRRK93UI1oAwAIBnysZx}OLGMOa#* zM9yUzgOYJsb=D<=(SFdw^g^!Tyfq5tT9kf>3i&;$ZH=!{uzb_;m^p!!gX= z5}CP;;TSKe@?L=_`JN>vyiqTaASQlFIP}qY$WYY^2ARhM==hjOSUf92vpt`Cy_k&N zdP{&LF%}{TM~2>I9rO8+X11_1J_`dq*#5&GVzW`yZ{Liyi3`sK>~T6gksuq+ENV;? z!4x##8Iv^6?3QN7k#D-ha{~ix&Y0;%>e`-O|jF{ zPz*pN4OxAKl&L~_my-e!L15*hd9%cg2Nw6W^lg0f)4Q_hdlRoyfA&h8 zI=}l}Ih*3v-vCtF6Y{}R`z^Wdx>Sr}_BIBrip6B(b&-mnHyFEmY}VgXTe(3>u{YR6 zy|}e@=IX<41nY?5km(4#9Tv;-SW?%#Zg*>;wlgTA3gk`#TB)t^jIiSz__@7-mctVC zJKS1Z&EWgxw067xztTxXtZZG1UGM3G%{PC?3-jbAm%(&wfK`_RR-I4evbX;3i!W~B zdSw{vjCM_eU`Xxs+#Wn=33MZ)2Ti#w!&p;ZDOw1o=^JJ+&foSr=u+$AE-0%Y{lXHf z=2y?7yoF_C(v2#OWNA#l-dJPCr8XAHitrbGuut=eKirIi z!1l?01Uh`L7l|HhH;2V+J|?_H>5Z`pJ5{xYBUTYf-LdcC--)me&zAZrxyQ z``G8c080~PWNheaobZV3{QNbpF&YdfjJ1miN;E&J;lkMgBBRkYcu*KFF(VqRIjusg_KHy%kg9aTE<3^X5yuZ_`|iM!%72!ew%ghp+a=69$#vVR z=+sz6+NGxOiDXwVdwhs4c=bG=84<^^{c>gfs>v<}| zLC@y1DV(22)3iejJ2RrSFXdRDv#Qk?HZ}&&pWb_V7i5?&28%cIbKKo{HQ_cI zQVJI%4*z~lz=#BHfh`W;?v#P@6&Q&Ewud4)=kDYkd_xZ>qu~Z>P~qgdN`@1-7q?$l zhQ^eB3%BjT9c)O)8O!eeEqx9L(e= zGx3@Dm97-!Wl#etgd81-O}LGbnWs zzN?VKCv#k?5(S~V;hY;+d?v?ux1Mc+tPE0Q8A=CGm-~S4zgCpR?JqW66eaMa0u0J8 zE_-9EfWW_Jd`@AsKAtb=UV^JgaB;vu^kS86WfmZ#$2_EA_y&^`00*xezvDn#*y%oQ zfsXc`?mU0^^vP~v4&$jmDxoyzrJV%vj5jVPTeeE^n%1T!gNli#&90F{l@JF^b=0!) z@9j&V0=hZsD?08a%CePq04*fA${5gwclF?lh!fkwk!)*VIs9ev^|i$@=cN7qEscn) zN6tM0Kz<|Ty|nJ1=o>?z0yGrkU?{=xZ|AfM2K6u!EYGCvH@MpfF7X!AB*Nh<&aQ%u z1q2mwo?SX13%{xKlr&@p%oJt^(bfQ7_;s;l7HG(a@jC*Cv&r zW@-`ADcsTg_)wflmd|&^Bnm&^nHyo1jteOuKm4}7X1uK>&sMx*9_auyIAjlv9pgP0 z5T`L89wF6h5uqkW;oQ?`Z)g<~b&u=$^o)}N5_M`KRcJgg}%%##Oa(xhhfs8+vX&RM3^W=-m;{5a!fx{Qp32d6|J<{gVBa*q^qn>!D zUyPy|5`Op}pc_H@kD^5-4%f@)4=G)Y7U&gp8T&ovMx>HSn9(qvFxSwI5w zFwtOtv4Gp8`I_ub{&Wr{I#p+r4WV|1DA}b%`^Xi5)qy^->z_@wAQz5~N3N2Cs6gh8OF5#~JN zg&@Z7LI|shtq{b-`t$;+tcF*7*hTw9p_}VuEs=l&68{n~8nQq#S!H${gn4h<$_46W zOW48Q>R^2!we|`I)?ZS?34z$$rwP05`dcw!gG)#|F3X0V-?R3$(`QNWV-(HbqLi2N z{sCOtfckpHdd5pys#D8(;ei-&lC;;w08$J&s0)yd-r3TI`JEP5tdsfoZJ6Fb*v9(x zJ65-9R(Pjv^-BZc6T~x>oaCcnUFsbN%Xg@c$R2`{Bx++oO0xQLO}f&SgHZq@lPFo6 zz*h<)h2J2Bu}}y0G3Ek+f)QoI_FZH~)Q1&AGpVYd7{RK-8sY&uvQ@+6Dz|Z&3l1lf zQ|ja+^n9!=h$@z7GGQ1U14A#BnnnN9Z;=6;&phD@O1n{`V4;XBatg%)_6}{BQCmD> zW=6&xG2yX%_X1gz0B8HZa%Zg(Q)$_&tdF+ib-M~TPzc?4gcsQmRZ3&4c5FwBWdR`6 zmep#ulefh&r}?+RLoiotYhFtaH7=4GN``>*N)JPjGdv7s60R`u7`s{5jA3F>Z7{8q zY3>^9Sz;Q4iXYoEnJpJX5U@CkrVU@D*n$^zo?AQL1sqT{e!3!BF>B}n$N%3@8SU^uN1gsVo{WE_^!+|`T`gP6j6?mOL3%;Es)66PWs&2sOF zp`pTL8Q~{pX(iRfzGXwO_~FsggI|8wKR$>0WOHocmaL5NI(0y+x7KJD#;qP8Wx)oh zGHWfP+YigjG{AVOM$Wo^+1)co2AgNAgc%9?VP45HIGg;+6DRgqdoTxy-93b$Ye1X{ zXaB5}WCTGP$}6ofltfZ8j&KQgiwFS*v!izWw1$Gwv*c8|ZRb$ht(54y9!eNfh@cb8 zcZEeDTT_tk#+2x0Hh?M*(U@k%mK+*=pwng6uqtU5p>+KAwfmo4BDbuqR`Ym&_WGP* zolp^Hr}60qM35!%D9Xo2X2HHbSSDPg9Ug2je_Ys@b&3+LswEF&r3gAZ$E{U8d3oe9la zcR7dL97!-k>)2lh0;y6+Q!qz^1EeXwEnU)M32B4^)iP0x3FW!wk&D!+*iypSu4Bmbu>r0m0N; z5GsiN$~Z&F5BG-av29W%Z?WtGWdgrLO$Y}N%4c5@qf6%9hCa(wkENG88%vzxjYsoi zAS|uJmI1G1MP^m4kYT8XWQgFm77oqRjb3HtxY1`sPgk}ZDDZ}FjQ~@AZ~H~v)I28} z|E2dsxBr6l)_X~YeO$0&TVe=uLX!zcEj)5AUXdg1NEWn&wsvhZtRKpwEJ z`H)+D9(<;Fe#|q!J9s_wBO(CuH{<^y@=`PqN}7Z@8ekD#2goI)u>=Zh2aHn*OkN+* zd1QFN`YH^F^I1C3N1+fBvMXYsB3^@SqK4yl2T94k0oj0y&&x%bcnIGsG;!)L2Qm)? zPGC|~5=m@)#|c_Atre?i8s9+LAd&tzd=SQ`uio+JiuN43xAt2Yv{NrJsnfEW0u0gn z#ks~Lr!7aNUy!BH1s60!XYnI8d}k9&gCvMF$5%!DceYEgZlcd#qHYYp1dqTC88&xK z1GL>M<7ie^4a;2=Cv88L5LE5R zoPJD6#e>)qZSMw%!|v2MbZ5f(O`<1H1ptNTJ}8ebzug-tX=&uXo3-q;4y~|63CUNP zs2Iqo*xKGZIG>t^L80VkdM^Y+Q%z9b%y4mtGGdWermGhO12-j8OD6HsgE`d~J;*+){r6NGq=cfNc2n2oeum1cDq{wvH8{Vum#DuuEes%q zEkv8qfJf!SyKw^VjPhJplBy9AZdE#GHP0BdO35W~29vM(n60m2xxifBxC>+)7%%YUtQdll2FPG;1XJbbO-KkcJn-;R-#S(Z}1Hta4=UxYFR}!xPfnOay1FWqz4I%(F5sZ9+AX6oN5I@ zSpFBSI>=PGSyH8~NMx!|dVw9J!MQ*qAM#)AuiZfQVGVB6i^+|>Be+Ij!vvqD@$osf zO`dMkzDhE7DhrYDRS`Ham-*9q^{M?}ox%m7tYIf1HI&8V1Pex0%#MD`ig@M$#)0X6 zRqPNhO~1fFzA7kk@{G5Us>7aUn)%_Dspg1WRd$!UvJ`C#<+t^#N=l1sl`6?qrMS$f z(oD&(lF0QP$rLqJIUTN-sL5Q=W`Gb1Wl=7z0ZfB=<8Z#5Wl~xiHu!ZR+~TMc7PCfz zi~&)`$ho+|nR{c;q>yoDmBWm@Rqd>-A_u1l=XU*r1ulQD$cKOP@pSpVA3B>L>6<0| zj_r-TxNPfm3=|??7uP=TtF7EGSLVLkdwW0@xm2M&+?7l-sT-BOIILU=@bkTc#f7a# zp$l8Rb#ql?w{Gsu&LP1sDD(C}hM3Ehx&%s~s{rm{cp+MnOzI*VP}G{f2b!E-uB7eE zE>{*e$yRpj_R8ElD|1`CCoTHMp8iBl^h;~&9?sxm9DcL)B;*7q0v6%yLY7x#-<^Aj z%2MURjb)Qw*=I+kB@tG!*Mx(0Ds3&9j{nhK`sDk;W6LcqsgXOu6(-ze8?YFGaNaHk z)WCM0?mqnK`T*etzx@$WpkSQee*YSm*?*rkRWT>rfLfVWzc*<@^C!_{`-Qo*&!CFZ z+n*HWT4q)2A55!eQ$=~&SZRkf@eI=N(%yVFXUiuGNNoN%^zivVnMo}YQ}nsVb=Df-_Q>ZB+~#eVX)5zm&`Y6yz}sdv2nE)*tuR;oj|GU8wt(nbCp1sm*tcmg z{4wrmVTfX9WTt_@*u)M;k?Dz7YRg~2O^Im)f5+^oC3N;7acTh_={?Yu<90==&BbL& zv6Wk)Oxc2=1y5h#s-v-Bb|3%_ym4>YA=|i(F#_j;NGmKRIXys9uLZE2(P)w;V6=r& zxH!lSdTA2IRt)HRSREQM5WWYtGTTyU^Vcv0uh>4sfZ61tkxAZ;JiA!HDhDL=?MI{t zdIcHtGyaETgH*zPL=k%;4JCSu=%DrIpLs6Z4dd#_ni=(%Sho`Ey(KH#<*{69Iny_<%`JK|M9bn~io;=!7H)CLuhD#i;F4@_HUt3}W&W*|87$tHWAJb@T zG5MD~XqYAccXuhttDfB#k7S))Ss(xcsEO>SP4ztUGu^HkHuO$$)YBddV^7ZhgtmD6 zKcwnl|9m+Qk%b%Y?*}`!#%PD#ePJq}_*@?ljb!yfzeC^`4ciE?@$r+V&v&+-Z9RH) z|B>79!=SiAuCS)hV!xc}w#dO?7fZ>L=U{+;@FWngx$m!OdGZTRAD+qjgdb+)W&^MU zp~qFy&r3U9*k&jgGtD%M*rC|zd@+3oThH!y_a8la{!csiVe2uP{Jcb}a9kg#<-x`& zsNV#`1+%xtrz2bi!X3UF*C|T;+^s_N!cNPC<)R8>^of2JhQEm>d6yYcCBa4%KXMok zhVA23J8AQ_tesjaz8Gx0BxAyNgy;0<)K&D?MdFLmy7DEfgqLzVWRG24GPe+u>QBG< zkM|xv13)+GB?DnP^P;Tx*&%~bM2^=Y+L(5Le=m3iV!=;o3kG7)UA0I_*`BtiamMR$ zk~9O{Sg&Om;>esg_=A2S&I9<kpQsf66OFwDj2pDz21I&Zx_s^ z%)7Y#$Q3bG(Rl3>)nBN9Ea*6nQ9#0uCr5Lkl~0Za-2PWYK{>r+%Kt(RyI~C?8K*^~ zA>tb`6byw@LZ<3p%tH;T9xr9De_ra_ZR&lGkIsHx##6UODiC%ON4vFTz!=B~n`x|V z1~nTAr^Wz4$lBm_kG%skNh9uI`%x!^ALYZ&v-{tC|M1a0j$O!&P7XljM_`hVz>hrD zhaN$-v15$}a*rN9`NxZKn=h6hM?F*!MLY2eZzkjQG!B$qoWUHAD3ZmPukj{Ss_R5m z1*sPp43)E)#@S}tt5t@sVX-hEb@$Sz3?X;d?#fvqDwYBhgZS*0ndnHS{p)X^7FQMOT&zglme40agS3Z~8QW6Cu7nz;wb%w^&|ZDA;gN3M#yV zS=fc>jK`c<5t(%Yr*n}@a63N*V31Amh0r1?xWQM#t#vd)S6X16`VpazXt2tODHd{0 zqCv#_&YRXX5cL11X{qg7sVmR}V%|-l-8mE-y<@!c#u3akQ1_jZ41goTB9J)LOi!KR z$P%ed>ZveD5G2$fvaFAt15<4d9X3Y@U_YYUv`VSG3V}kEyZC^q>H_Pgs2J*`$9+)#7{p7#lZ!2S}JSW^(N|8O_ip>S! zb2vCL^O}sM{1u)D^yI+Nq1S{7Hq{vISY12Y9qj5I_QAJiaGIa3L*oe`a)Dt)Hnt5i zL6gj_wg=VKnR3=KNf1Vmu+U*PJ6Ejn{Ct8PQ6xtFWeXvo<*b7aedA&qs0 zh_xK$$}&75E($TrVL%EI0K-I$Jx-JXA#!84gG1@aod7{ze^r zYD~N&@swlB8tmAI+`w7`gm4`*mj5MsMa6W#x{L%bIK@>~Hy88Vn!bQ=H`M%9vh*86 z^x)0;4A-9~l2)X?*o^-%lN+;5g!;Tx1Mw!;zk zI+%UjT&4MGDo>l8QUNG)kGG!O%eGjSC3Cq^U!UZhKZ+cw9sw80kGCE^+1uTI_HgI< z9b7v}} z`?9%IPUo7GzHFFEA@PE(^ZvR&KnD}Qi4SuA0{4+;y7z;U|^FNQE<-^3O3SivzG`- zVEyPbeSfBAU9F2{Ak{S2I1J)+q1hi9TnudF_6p|2m=y&Y@jiU$s`9p*>Vbf`QS2$| zMbJFmlk04@DxqpsJ6YzZC^=<5rgVV=rx<$DF|CV2tu+UuMj^7LsEFVKqP?|E$6_6= z`tQ5wk!v-$2;wC40T=H+MWCm+4*^~f2jiIn#3eCW4TERpw0<-y z^f=Hgl&&A{KikEq;R5brJb5==j{J2nP@n)QeK5l_t2q?PUzq_!qcUPSkplCykj5Ce zOBL)0Q+T3b%p*o+$hf&Lu0nP+yw6qhZdx{5EdV`A#sJf%WE60wG0IsBcy#5G&)92Kr~*Rc6+&l z@32Qe)K_dax%*>(S2CrM&iBYz6lHvTGLQ3)fyv_mTrbz5j0ce35&v_V~2yDSzbt@A(iF84Mah9 zCld|6qARv<3`F^tkWI_6YwK!4&flf_5WvYy)mG#1g;jnjUTab!P%sU_N@nrY7_ca^n$=l0ToQ5@zq=(5w-=}=M&_Ybo!&?`TT4|ect!mupXq%_4?pH z3~t@Ld2=1nohciSM#Fo!!U7R-c(Pb0DFR$3{>c~*>zwdDCYtzw{cgvm_BxV@&T^7h zRi3?vk2yZtTf)fUJDEL> zLxF(E_Z;~n77ELV?o1ytc^l|ZzAzUNz81>|q27y)>Vkm1$KhbbaC=h4#W~zjOf2-* z*kvIz4s;jV!odL`Tc|>paCJ%VL?vQ`QB(zqjY_A8OCg&}*l>?v#H$j7Guifp#~wm1 z_K(VXf;A8pS@n!DLnJ+|QYkmV@{3)Vyx}u~261?ePO_@&hK3D^WCN4Q#X?9+6%aBF zLtyQBviC)4JL-@l^dLHuhGUoQI(bsx{l_1y5reRn2;o0G*FYw<)yZ!V=*dUw)$4s{ z+ZR)xOB1_l^yRO_a*52D6e6`gqYh{mKaFJkN+2vVKFQe}pdYAd8g-KP)EGFmkp{!e zO48Jn5iM4uIy=R-`3U$VO7srE?6iaKv!mZdZg0dW{boK_2=l#=yw5=m7^}ZyI%dP( z^ZUEccYRxz`#8?&YlU^iX=_|KE;5`Gvns#G9n|?LTXTFs>QLLuVv~2114L#m3Uc=P zv|vGOdT3JFgY?-y!$WtHE)Ej_VQl$DV}_d@YgUy16%)aN2GUPXpyO5D7Ez>c1V+xz zF!Msh(!RmvNBX~?JGp|4$mej4p{bgP#eB@HDiLX)z#^ZB;2oPBUi2tLXy2gJLkDp! zgk9e!Eo^h($sP%x>Ap{j3`(!Pr@Q_+o$nzM22IhphQnV)x}Ng&9Q{rp_I~9>8X7qE z;B_=#!tS$A8!dE%t{ks-x_7=j;&VE9j}kv3l_X^%|N0o8FoEaFh|(+D_6XQ5mM~}Y zVwesy!LNn|N}epO*|qqAH1OK;{MDXSvXW~-3S@(R;Kd9-vaZ+78jYQp7&#|WhVS%K zM$pTfW|onyhb$S&e9=i!Q>k(>Bau-rr;3)|Pn^5rXp&0=1N%X7fIsb-zmdb4eLBuj z8t~hlwNaK?IEdr!bVz>?d`f|)4*}|(IQ94H2BhhnPsBnKnY(AUK(Y09Cba%QEi$1} zVg)280cRbk#zB-w-&#C+=dH6ppp^5X9P(-`k+GY~&hh+>aeqqc8dn2wnPK&&`bJgk zpPI61k;dBUUV1iEEYDN^G%=dA>yW*=!ka~wiD$df8}i7{ZCn<^qnljwhI;r6XLm;S9K}(US5eV`=TDc>xjJSQG#iOPq*Utm7R>(GSym zQov{us$)%|vP<`rqT^BOC9x;zVdDOS*UBw=V2Gv6^JgkcE@9%daowF4N& zU?ZHo!mqnnqp+aKaou!pt7~S%RE)s+%9==HZP3)6!M@mjd6)KqG@RFL7_JrYiOjTY zgw_2Rnz7vPl;Cwtj(s8G5b(SbC111XH9IiJe<^)ovZEu$?H-^BJ*$=a$*}S2iH|+X zHOE|wg-`kjwnuSA(TCk!myAS zMQH43)P755wQM1(ySb z{rNZF^ibTOb>&T0-I#j89k(E63U-Xzx|~I( zBM5q)f)!$pdGLrH04(e!yt=MBr5ht9AlRefR}OIj&X9&U>+FI6IAUdWdFocxyRcX7 z=eqW^y0Voidd~BNANKL;ga0qjhRET|oyOO+AI4SWAI!@LtqpJ8CWqQLH(r8-be{(1 z=$Kv>W{uCrpQDOgS_6)}i~tI6GQxR8hsn?B@*4T7#k`1OtlSB=F2lFCZr>c@PMBYR zZOaeNT1tSG^25s{@c}Wyq>v(s2B|>EqIAJ6-xTX6{ZKw^1?f%B(DR3mjKLf{rSRz^8^!m#nNr-=8 zB%7Yb@aHl&WntW)WP5B(6clu9!mH7}B)kV$SxQPafzsV91HL5C5+Ii@90Qb4idl03 zz^fzT$M%CA1b=~5 zt?9umJ;b2r6O6<($p%X_dWLDo0zLxGZ9s#&3-#)E@OHr=XVBBgBIw_#A;%RR=VNeI zwZvl7I_jC~(yHmntLq{_h{#d2$e1BP!N#sFPtLdor0ptZkN*1h{NKZ!eK7p@`zNP= z#MJI8@s*W0UiKCE+6uf@0pDH%%ga-um49uUnsL+fnTn z$Q1u|>r?EUT%D9;ijCX9-qy#KyXeh1GFkQO{`T#{G(DQ=#&25FQ8~bl@xJ}o( zhs(*yw~R{7R9wzI#ku9f8UDLSspkuvtv=sh{K6uX^v|^|E-F0LIZ-4xOn-DWumCJ0 zV0Su(%>Lf2Q{9ds(XHzP6+fNRy;7RT=-O8|oMFHAtBM6R+Fj}+jC@G-mgx>Ini%`F zh(ZmSA@rd&mENcAR;*X2=ZiPMFOic7_Vlj}qUb8RSixZPMJL-M)Za-j3)i1hsOUDR zHb!__ISn=(Xn*O?d)3Hl(W8w}MGp*@2rXt>L6bI^nkFqc4Z38u+*;yv`xUsD2gRN9 z;$&fc*gC~dFWLZ1M^Vfv$_x1S`w`^Yj$OG;8cn0@y{$>LmES%frP?=!`w?siT zlB{cQ0ZtZw_p)>bnaN)apj0zf_E};y(G0N-MKli!__Y;WlA9@jW5yV~4w*pG^b?o4 zyYut2gG9MJe#~>G!yUs8DzZSu>eaMOT}6~vmV}OY=5d1IAUnGDaCUHfemL12UcCx$ zNln8 zV12EUR(00-53{k-v8pa(IH-^}%h(c$J}Qt%SBdpMYIQ{s2N9F&k4gF$l6yrnZML%J z8cJg~){R14Xg7-dPP`jXI>yhb&7L-u;V#^}%C*t&D)qa1&;_WY6HTQu@!`FOwrQ-G zQrG{;2Ea(c1zE>)AG-7-?HRQwzqUAttg_y#5w^17IJPo-aj+`;c=`%!u4yFbkoM-JkJG56 zpxOLG<=;Lg3xfQA)xICBL>>&Vs&5DH-mT2;?Rc?FxMGy1%~$jdfu=OTzdA~U#=1GA z4&x)e@wJBO*?g{3XQ=p5@;wF=r&dt@dgrKb0*lsgAp<6jko|)}R(3as-%Ve?;Tt?+ zqru=gg382vzAslsFws36W}Qu?L^s=3q@bd!K1*}ssZRyM-d4r54Gr$&b}tEbCW^OF zPo%u1YEv+o1)#6yjYJkyxYJH;`YbZvBY`o&L7z%osT^juiMJUI_?x^C&j;)!RE^YE zG2*s$gXT)f%aVb98HAuoVaM%#wo+wc``)z3%Ojg8@#*OCuJ(Y>5m%Kagv?v5EUH`U zG|u_#Zbt9mVd`$F^(QH`-mwh?_c_noB8M zUm8=D%-f?b7&y}s2+QUKM9kSfCPgxY|Gue(T6t!1Ek=S{*zh9Ids~sKAVO-GvBhvJ z18-T!O&1wkFbn^PgT%0b5Ef@79CS${{p)BO$b-3_TM|fTn;vcGk2cNoM$I%Zd$nl& zk5?CI)?xb6bk8|i>=80j-dN|Dai*r>;>YF?Tbv8W#uuDa)4xMD`DcMm<3QC6jd_GA zc86ct_t#_;C_LD8zm%h!p-op4-!VL8m)@>gUItr0M_e4PX_ZCPAeWB4=eb4vUw zIHTTW(?CXRYwpAU7dc)QNZj%Iv)TSDnVF&FP8QGSVb$i7En*1fd^o-(yLh4R2<^?`e-Z~62F9tK6EnP!Y)V^kx+ZZm zQfo%gp{}s!o(qQf)TJ;J=mLH7 zTpEs?ba*IN;PNcl7HK~vMxk_K?8|qqo^r;X<|R(k5j1v#_SZNGh7g2WWAV6@=qF|br#a7SvYd^bgz@%&=Tn(jI*D!rIXn7 zMBlBQCO#G8r$-dVdYn$~dKz`P_CdZAjr^P|?xj*C4F=|8u4oX?mf9SULdn}e-6+gB z2`wxt`3}L}e#PUYlL68d=Ln;V&|k$H1ZI-WOBBw@^F`lb%o<;R*6f+C-|ynT_f!8dmgugo(2vssiaj9Hi?~h z4>S17Q8@w`&6x=mxmKfcDuPeu<%ehx{K=oh#`V=G?!P?B^QZP`ianWf_3G7ISFg$k z7(uIdY^+Da4_6nz;rbT5i*$$H|Ep9?glL{#MM6!jibGQSmUMnTg@>+7fR=zT<8S!_ zY8C>H3d9BYiI;CWpBr|_1>(1FeSY))ojZ3nzIawHjfDC16JFT#`pAg#R~sFdIpsYAk& zqm6p}qfG^Fxnnd{$BDv@w?@p-uz?e8f+XPw7M$O`^r6WhrUlZ+W|ePz7H(hxkYe@i zWE(F_q=kz2tq*UuPI05gsnNT;Wv*)2VB;u#qHdbqa88e85@cxWQiIIhpn~ABuwa7y ztH=@)j~HA&PBa}wUrK@oCQeq4@NaAWfsvtX!hg#Y5Lk)nVG@*v&cc~*&yk4exWr*! zartUJ!I-?0YY1Z}+qKtsOSUAqii<$oet`lq#z)8duNPzAP-V{#PJ_B6*CYftu$8cx z6`sRzKA#tBZe;rc`v%#Z9DSvL{5xLGheY60!$36A=x>sOlhm zUNn|CmdZ;c8rki2Kt#|ERrATyC-E{M59ui{**n`d-TbTet&{dZw_`_PDtjzGiGzV& zvSgaHuoSKjU~U}+X6>SkYDiVG(B^#Sg4)5np&w`FKYESO!j0L33QdzHSpoZDG;fEe z_yKLg8)&F`A>mNQhT9|{lRKp!BK)8zf)Dr(tbxwWmv@inzcPaR;H&0Dzm@XH^IDLp z3&Wzek7x7(Ka)eDmsFEw6sy5@=Ll)dIGaQvET9)ia|l!Rni3JDN(i`)-h&r76bA(U z*i@tUFS)oU){t;BqN=|p6o&V^MZmvuk2zVpsBdhWiGg|ARm@Lv{~E*y$@_a%jm|j@ zV01dBZJF~fWd5~o{@O{U+dL%+{N400@!1m#0rX(&(e8cloQ*OS-3m5xIuV22v@l1M zLgu1f6WCT8(ejSj5_j;bL-q=XQEmHZ_pN(lJF^ZZ9Vl&VwIS6i6OFp~rU*2xca*ki zR8eN@z9u0xS58xeyWZ90>m;GCBVA@3qbDdu9-hD>bk2}mlh=3-ndT0W%0xPjzBsEP z%U!caLZR93Z9V(;hce#b2>EwqN$^uuL^L<^s>A5)<`^rS1dc&9^t+$I*m;~NP$p2WgK(U zO#;f++3WKNWh#}z@WrZ#*rn_?PjvMO>v zcR$kAQaOpFdRSQ2wio+Aw@9=HBnfgz(!gkChpv;Uf?-7r+he9CTl>s>)9-9||5wJkiv|-c6707!jvS<3 zPw2oliTr61$*fKRX+#GNyuHFS3E|-}yf&eqMldTXU{jODMn4uSf@(q8j9a*oGv$L) zm~#v;mg=NZLwn~5U^x<{kiG%=ETJF$dZ7}C%5{64&yDycUAw&Ath}+&Tl-E~8`LF* z=~*A)ZbS0Hy9i$1BXD6@5l*HHo8U zQyqMP--x{;q=M^7N+fe&nd_Rg8M1+EB7RZzWn)~bEI|t}sV4VX`vV!Bv8@;aI)2h+REdPc?z0AM!ovpp>##zuQoZcxFeX6~2g=lv+KN8^q5NM_WQ zG}8NWDCJD#GR~uI45u?S9rUxu9#B;Qg|DUg$(dlm=)@etLQ*wmS_3TJkgzffyp%Zw zV;|~eHY4?*uN5|e_}y_m#D~Wl71^X))Q$P3A}?-%$z5O=&;Tbt zWqy74_H4zhr)orh?gxD z1M-&mNUtjnhjRS%v2&ZU5Ezi!4q9=!u^Wppa)aUaAO0|0(_`#B7YA`BTc>!l&`H@r zMa<|lbfI~bPlZIy@oSxnWHd7eg7E(N%eVbCQE(O z3g&Mg)SR$*KRbA{dpv73S?mX5GtFU$F53l$E;hzM-MW75s~uy^_bL7Y(r+VuyX4-| zawAZxegB2b6PMmL`q}|Nk913t`v|&b$z-`Um zZ|{6Bdq}p^tl|RsPpElzn)9rVI$`oSS$Gc0{&`_oi%VXL!vY_3=OrB-*d(r1;mlKt zL_M7y&GYEOri06OJ8(Z~rqO#arx{v%G&$r%Xyw3xFW$}1FhBhsiY{{-6E76OAl>Z9 zHTg6qWJOVwO6AG)Kg%AP%h7UkHrqc&^Hd^o26nHy^io}`w?=aoue?3g#;Is1XZu~0 zKo3;zf{$BrXRv%;P^xs&$WSCe?!V=GOg&SiXSnS^sB5C&fR%hGA#Ws5SuV?+{Mgfg zPR}mj%3>x1O3_&8aSa*09ff>G;X9k~*8c^b&~fw^(-w!tHlL8dO9F~tIEr&e=kKUx z{WP&#pjND8CtB9zBxm~1(1)1n#FP09R&hu|Rw&E(Q?wS#_B5qL4HW*?W&+{^e0w~wqje6o%yQ!L4G8` zqQ%x!HC^?9FyW`ao`wjG_^=^!cUT;EH>=yAJd`t2ue2h= zu5t($T4@1K%$r-&wz@Ch_#G=8(4N*L#jfhLBx7IE}GD=Q-dR4NPQzVqLS^#tXWs& zqP|@$Zr63CnqBR$?d;j8ja$-MRxi2HxK>aXbs-GcLtbZ6m z@W;5=bnUUyp5?~0^s*vvs`p{dg&<&jKy-NTtAClW^$()xKN}tL)MAu8Ak3oq*&11~F!Xq#8fX{R zpuVOM;HINsZxzNw51sFgi^TyHLf56(jtx`lcteC!`Zff&H%kzw5|s|(YkCG0``*$Y z7A3h8iA`~8Eq2G3UCX+*a^*;wFeXLfap8Q=!Epe##Xe9XzLAs`oUmv#_Kqg&i>d9p zc^TUBBay1YVhX1^rHxWYIL#isPHlv_lTG}_!SG>YdOdVX;kaYQn~!&6U9hb@qs)!2vfrGBnsV{pl397|=%Sp}F(CwvC3beS2^awe)#ROfHG=#=5 zZU8~gsV}phRlDK1&o?duI+Ng|C4R$zO@Jll9 zY1*T!6U8SmY)Ct6mr81Fim^F>T&UOF*&D7dR1G4Niw5+G28gWGJ;#pqd8Q=boOyKmrYb%^~mzJ}?8n`_*M+r@K)(}T#256{F-($5fB6H)8h+wVL+ZjqbB5R~H+ zdEqT#vyQg5u;Jy=X{Q!LlmM+@Ob3g7yY(SEvUMtXSo!!A4*U+Q5Ua8>!*~ z)+$bG2Y9wz!VN>K+=Vb$)@v6K-fCSTH5HUgYvyow_x^2n8tX*q1eeKg6PEcRk)8YC zTm;53@&(dJElDXFCozdH4g!d72)USa8u6JE@6#tlMoUvvNieJpRhzQz~DKmk!@nk3^HKTv;9yCx5C*qIJhedjO>7n z1_a(x?lLzQ=5OO@^iMPcJN^wp3|Y~%nGkc5)93hO z>Eq2+wDG1yoA?bjXeh474casi6m811OVFk~lPN_yd3h0s^n7+s56hYII@SXVa4!SX zOCb2S32oJ+V6s|N>XpROFuBqYYLap-N;=fK;1Et=SagR+9<-$pX;v>yO6O*DyfISx zj8TF{ogKvlq2x_e4%&C{6qm%aQ?5id$r-56$~&;2zBWtYL1US? z#@x;=1*DnvAR!qMI8Y*|wlka(2L&A{wVDW&WO2B9e0Xzcp>e;VS$l|kf@-qZ`yZIV z>T9OimHu`VZup{RLO!(n>HKh`ofD&TB`pYtbDGZ}(CyJ(<7U3JZ12=km#Cb^?fqKn zIx6s+h5W;C(fboV(w`_fduE28A)a98a?3Lk?hP6Alq+e&(XhX?TrtPT=lgjY6b_2k zi;+^2S8Z}Cj9%llO*qTj<>UwGwN$p^MK#Y0N|<`U=|>@m?txJl9usGSDK3CrVu>2o zcRF-<9neK-(bX0PFO=;Ha&InV2`mk9pcZ;jrP8U@Hm_N=^Um4 z$dMTF5g*FK?q`0;`Y@*2Gc)Pj1_uYY->3rYGLMU`iq}ZPW(7^;nNv1_!ufh&(*UE3 zZ}XJ(HuS+E4`g9oJox1Y%N?Qgc<+b%&vqX^eNy06wosoX4^e}sOE{y${}1OFPy#=h zKva9T2DoGd-G91|5-Qo`k)&c#ms%bcy}2_GW+j z%Q=1xHy%H}haUbq6}XhkWgzEE88+7sc%|Rgys`snda8!BJ7oue4{PP6ZuRlq zmtUxdCwH(VUBlPj7oSVcsWP@ zler$I-I??59gTC?am`Pr%Z;NmOqh*ROGiN%r(|2g%dJyJf~Gh@I}0Tv|9jlap*7~v z0&v3r8!D)ZoHGX{g!vpMt=VgVMec{S2m88*fmV<3YXkn0&Kx8XHe329j07 zGSS58RI@e!9_>8bMmc1(x3M7Z)(=0SCqseMXCB5LL`?K*aJQ*4#`6Z-&b;l^=d|1=gN@ae8tR8^Txn)GbV1Zw)QZiqY zJ7oFUcx_K4x8}E|)5pzjRl$u7PI@3?8|i<>Tp1||-T@{%0(C*}kOfU#s`4%&edR&t z)BRUCd|(DP6gx`{2vWBy>qRVe*EW8#u@?lIu-OI8W9^v zEA3K{CD1knT$K#8uU6K#EMDKei=p|jmW)T)>eP@JsRTpImE!fu{G0P5948|z&N)`r z_uE{+#eB3%!Kdcnmklg!jBPSM1K+)%lRuubGbUav4>u3=9XX#ha$KI98LNSm>{Z_VH2 zSLy5>*S;KJ`PznK3U!gz2Uqz2bPkR_gqFW<-A*i1%(CXt#6|;lCsTrGVL`m9_Y3}r z4wOXjeIv4q0a9UZrn=b$jEXjbq&@R;Yv$8_I?P$Co>p2&vNtWpBO8%?8#pB1nBqCJ>8s75hLIp>Rq_Mi@Z;fwc#JvA zEouxXKbl9gb?32nB)p7r4C0RupWJ);ozFXE#u* zxlu|Pv0-Y{X5&%XAYz}04Pxg?3$|!r^l{y7RkusNj7?aH9Vb}BB5GKZzfs!!ABJW{ zu4KE2NKSpUTEIA$srdMrM;zho^^@FAf!u@H^c9%@H8vM*+{{*hQF(wFh5;OIJksG% z@brc27do4)F4j>XvD}CMU?|rP+?`sxh!G{kTRuzT7IB00Ht|pa=^c8(WvT14Q^nP4 zO!3$XP+IufXahS(=u5gfn%`yD66qGhT-;>TMFW{fz^#5441%O3ZMgZz4MOW&N(lH}oqOB2=8CtbW1xWevht15Q@XUh%M1m$`E zE_UGU4dCS}NTnmN#f2^Su%db&m2CKX)E2q4o(k!-XwXEB!zvn;NXg1tXzSpM z7i)vT^l0*@!RXTw`Sx`1>FD15AO7*-^PQdT_4VuP$R8k0J4{@Nk1Xtv-%iiwGX`A3 zm3}jO4W?#xMVrI*Yp99QoF1_SGqqQ+ZvcZmUI|!SLkx(nRkTFETw97RIdimajAh-l zq$Y_;H>!YQGm4A4thS<)47Wq1VeP|HT9nkUaYOw&)?5DG=YIB#W+LfN;C)(8nnI1> zG**~J2-%4*iEd3QfQHOJn!eLKOO3x^DFi}+ip^g-aydJ2KM9wjjrz1$L#RMJG@ytJ zybj!@^htYltTk)^F~w(R?P|6S&Kh8j42SLL+R!M6m;IsXTU{#o zGWyubl$i>N9Xr;;fW5+s0ZW%Ja>+E4jW;HsJH(mVqHO-@;18RrqBcDywN8d`(hNLIvVfSH=Mp$D7q~XLI`ZYxr8z9 zD0d<36}rDWg>jpuS)A;!{p)I?Q0z}z?FY-`Qz1t_&So?L(HXZt<=%Nhu*4d_ADg)Cla3Lg<)FD*==E}dh@^2wq|K}_J)0O|_%Kvy}?aKdf<$t~M-(UIP zuKagb{`V{Y?Un!I%71g^|D^E6{|ue-ywFnWxHj()9ASdXr|F(|3NnH|#7a}eo8h%> z1T45WIXK?8Fp<1hoT^nHR9A6HMfaCeiRb&%V{Y}Rf<+6u1Uj1lUJ*_QQAsT5#Du{x ze}rbVINd)`fX3cy#i^Ad_Fd6P%0@gKoPwS&-XLg1f()a9LQBR;F4hQ!km$G=k>Id1 zgyl;SY!rNHCP9p5afDFbeSYY6jDaX5Za7alF9|dhis9E#+<}C> z(&Lqaat$s?u!ACYF~jf;XNXhXrPlle39uTC#pdicH&@I6)kDus*B^L^Cc!t~5ja=E z5X=hB8f-`r&%hhnbKJFnA6}+`Z9Pv!F(iGzJo<7(_X<-9F<1Yl@z1}(Jm)|E*8lmx zuGl~S_Z9o+|G8rS{LPi`t~}9f@0#xzGwo^6*W?`FW6$ni=me1FjVl`RiZWwcTz5fy zEg1GdB8Jclw&9M28+^NZ5VnS(ob#5!L9x&>P9p$@T&+@e43rM`95M_ouW$p%?tnzS z;zkHG0^28Hqr=cHhK$C$7mT@lsUqZ(@e}Hq$;Y~4@dL+Wnu2hMgb7B~BR7GB^x+U< z^VR@BhH63(S31m~8PgmRBn;Jf(KI1qiA_je6tED_#(J{A5n8LZB{pk&(Xuv-S2hc4556Nmvq8!UBYq~ZvX3Pc;dzRT~@88?n*)g58 zYAOu^WzBe>0lzHY8!Z?kVF;nI?b7eYX`)BuTzX)G@_ z&b;&iOpMM}NMp|pFbnzcp@@K&brM~zTKZ(Q^kI4XudrBxrUnwf#$x@19d3aTb+(M{ zB7cT~Lp7A*Ff6+!X(Cja*`jCBTBf)+=iPJ!#oY$W8PGDEO0E(St6Fbx(R8psdj!Rg zx*WE^n)KIY$HEOo?S>VT)-u+4aisDvqzJOS^!7r&2WCeWt?al7R&Sau=0Ii?;PZHY z1|)c+C1&+>aX4Sj%$GNWu=e6o)(?))h#(AL4<3X>UB1SnBE4W7HwSN!Jgo-iRAe&= z92_SSaAR>0V>PA{&<-nkJo>~~B*6ZLJj8F}%#mTWE_=iH5YEOLn`x@Vt2~_iM7zFH z;>~6HMqg58L6yA<tOMlzqd&DG3V=HU!+%s*Gi;h&P`+V#9!)??}opZWetnUo%AktYY zZIpsNoG59e;2jQl8t^Zgi+5k7ki z;6eJ{fo4_BeiH%QJcM^O2Z~tJ-PM;renOt59Jp4;!U!i(|H;h<#aPy;$;plhStaKf zStJWsD~+?{v>Z>J3`R7RLG?nQqFXj(+zixuV67uY6RgfwM!`-9B7F)Dx0m9EQtfP_ zR||_ZjN?B^K(cgOtxoZ*^pxyH-pNXy#4tp7nxRoW1OU$0omlBS%>|{31##G7ZS6M-;{HDya%ueNsQsaCEhgiRz zZ?lk$p_MlIirBhm>*X`605#gac}i`bC${E?q;|lDt&87)ObwVfm1D`3?L9BIfT$FL z#!3%<%+qw zs8pYh;_H+L!imS-Pdk~S5|ME;c!Y?Z$FS{E5f{@*LY9e=<59&0Ws#4L7GI``630>i zf{AhGjA-ED`LaEA1}cxNSY|QRPgzT!@?C1UV(Mhycp6N`-+svFsOctRtodRu|8H;M*qvZ4=P?nv_JVU+9NQh~X#* zV10R^Z1tebbB0!jsy4+At)U}=_*Y{{8DCTp2vz`r#(Orysc7oCg|bPStoNbXvS9dA ze8RU8!e0cxt5-|*LcL)jdtQdmqudr2Mh3nDp$7>#I};{FtF=<%-3VbKrs$E>j2U&&OErBD)tHa7_XY4wNcaWK6|dApmbz`DM;XMf9HbX#+yHC0B^#dS z)(ySDJ&0Fr%nRL=0B>MDT}!kIMv@mrBO>2HV}bUQ5P7 z77so|+wfelur7vSQOXY80!{AAE^+W?gEpV};_isXm!sudD#I%B0w*-o!pY0zh-D$n zI29EewMjumDJ|Bw`HU%!j($2WtZj%WHLzfE3k{YSF((Te5OyEsaFJ&@i81z1A7ho6 z&+cP`lXw6ho-6X6&+w`*o*WAPIzL0C$t6m-Wc74xS}@lol$?DU6EEZ2yR>4;tMpb|=nb+iC_6@k?FRH6(^8Z;S{ z`OChcR5rTe@gy(CO~lN?Y2!Mab~kD9=T^tYQNJXZIPX(1NlGUyEgV-20t<1@7xU7S zVrm*Nr+3mvbJdt00P8h<_H@!x z&+&Z0-tIl!jqb7xS&o^0tz1?70zH=&PtP-`h2Z(=DPAImS2kWE!qeV~^#0x5Z<9Mc zW5SW(s;X>92%u-KWcpY|341|nFJeyNVKlc*i2l&MriXjn9lL*f-_TjX3`Ok%5#x6# zN@n3GfTprgaJ}!{oh_NGh0n?+g!g5@_w!MhnlYAS{DlvfX?`gfIrO(Qa8|PFO6E_X z+X<;E-dQ5=h?+wXC`O3eg9RQI`5a7}biPt2G}h^VuEuMldV0uaY-v7cVnVXO|4ZC= z07hLb|9=srL_zEg^*jg(B}eGJq>^YLfrKIiA-TJdBjrLaAs~u8LB$SM^!XG!JQV>& zQ4kTaJ$;IbA{L6z0yZqz+y65&yWesx0rmIiz4M#zes^bgXJ=<;XJ=>B-|CAXg-gnx zdZz>Bi0vCGLmc1bFpbNx5bTkJ1gX}vY?2;@CF&;7#{{?2Tm$BvZq>r9O5T}L3i)8+ z62mmYR$oQ`rF=fCv{G_iqnz+ST2U52WF!T2MUCv^tV*HYZsr5?ER0uDlEsCAQ5t{8 zmc&|Rh@+`Vp^2OcMR@^{$s<6+B;>GQJ!0w;2b3^sAkcIRoEVCT5X2hHKOOW3?UmXT zx=aH;HAEIM3T?}jsTYgA3>^`JXiyu_I1?T2ohh3mzz>&`@gq0K^a{H!_;4+PBOiJL zt!Mf}f$6a6(*Y_#?ZF^Bd1W&`&IM-#Ri%}4Mq^E-cOf8lhC#ZjwnGPfLcOrqp24;vm&tMpnZirD+G|RJ@9EJGxHFq3|b1?(bFN!OjQ%bcp(K5 z_M{Soh-OD*Jf85eb_}YFGdgCKBXs!4(I!D-9weh=zJi<80DrYQAreuJD%8}bjRfI> z_7Oq^(c*on#yS94%aB8skDXP|>Bd=|qn@T9)0CxD?KT$J)ZvzVdg{plq}A62NBWt& zleWAln9matUbq|>9hfJCwlNdI*Y`;6txtX+w-9?eCLuleqhnc z{37xxqFc;jYb8=|QmhMAxvT|LwXT!1vB)kxptB)-6B&cgYWTEBAwo9<{WmRV)vDwz zsUZnH*(5tG{Wz;IQ7P3l*4?zGXa`=k} zaN@`DEN7uVt^EUL9iyY8*+4p-ytlY_pxvWQHS6fLIV7!6=y?U;Zina zMHf=O2t&BChhmT-J<1lR3miaEln(87hsQxXOVtc?+)d?q&C$775jfC`K50(NajWDs6M zmjp8p{4Oe5sflpG7=MM2zAV}nX<0!PLg6d`u2?d#zo;vLoj&6KGshPg<(K(RZZQH9`-cs78C_fuzNc1V>%fZ-`dEALEwoZW_<2( z)uECyZCRl}q*1(S`H+sWtq2Vxea?^`k?DX(SWz(LBs%JqKFu>|julb7WYx@&=@4D2 zi2hAgqb3zgO^W;raL=U*W{l!iMOqU+3FGD0B*}Sj%n<1nSXBguNLO7{Wx|HUO+0-w;5LTvb9xgDFCBtsUefE9v7N0LPuoJ>;4Ffv>k(!+Wu z{MwkH^`XXBO4sni^J2&qspzwJMu_=Bi;>+rM1QauWC9b^SYk%ZKQ&guF(UKUh7w^m zNQO}nc%0rf()vX>lVyO}i|kk|3viRy<=cZ}6c-QaVM{>M1-2F!U_KVFCi%?MO6wtq zx!kj8uRlN?7AuC3j;j~B2a35ol<5!0fe?GfiUTV(v7a?nYVmst)^O(`5nE&TbY>&Tt$B(*^)i` zi!NO(^2qvI1Th7O9#D{$DnSJf9#Z<6oZkc-#{^ML0dv?QWLK(z=O+oLIe}^pFUw5D zd;x`VtD(LC+O39jq9wVS&B58ITMXHGc9K?Hq1J9(1-%#MmWfK@Ny=^u9FBz0g4)0= z;C5IxNqM9hlUHR)rr2N)vuAuaj(MrfCG&%$%OY1wr`2?czIKICyHFCw&*U|@EYO!oixIRg=7`FYDo=xbIZUPN>G6m~{qfXxC5gs|g zqYtCR399AE4VouuBN#2QF&JpeABiC*5qS1gQRE`}H=2O!9-3ST9fd2_(Zq|wyO12- z`z~>y+pw3=h5v`4=#5Ks<|MF3v(B0w2;o4fI0=17>LSsr?ejw;3n!0?feKYIDFdb^ z-Xa#~^qZCtkRgnY6(f(vT zC?mkCxNjZ<~|!nvH!4_B&X-OyN~>fkz=^vkNiM6_ZkhDU}jgT2LYYed2e$&go?pqh={j zr2-)=ts}R!MvZWRy0&W1t*TaRh~DHYPQ2vCIk08bW1oCcLdnO7PffEEH>WYmx@~0C z1UHl$x{^-msgVHQ_po*wUE%Ry4+PKBxX=pN4WWtKBRFB4aQ0k!KiWet! zN*1zICoExM#fJ_Re#*hbl|s-T@`i^L7Z6M=Y6BNeq4C!=ePXITNf9$Nk8zb$2)#w@ z^9!MNIpJbPDvm7Gk(X(=q3Q`cu0a9X^^0oMT%d^d!jH_D$jmjZ2`jp0t0q*n=$rnw z!atCZ8QwgWT}q)CsNl)(u%$7}WBY9WttyfAEoSzxYD_~U6HF*7uW8ciZUS@Tz9>6q zGohMVaMra&m+T@=;e-!?A(M^-)5Up4H%v`7oJK(r6Y-UHaB=n`wCXtF+fMgne%cc- zIf+{AyJ&q`CVD-j$+Mrln+(R3Q^UkmweE;_Q5X6~$IU~@C1;_i9reB>R6yqr#l_|q zQU{0h=oc4{3V3USpWcahjcRn^KbrBkRvWC)tZ6c)>+9yn{!H-4z)W zfOFUxmSU0)mSk^klywHn3Fb_35-%%skl-jx3ynEk_#^rdk+@@?#R@IN+eaum%(j;r z*0*P`Aw8T)agYE#iaK?6ke=v0SPw;AvAv=n>g)#V99j5qx#-=|D{DA%W%}s#F#@mp zLzf7Y>Mx8<5N3%4wNZ7Q=Sfk5n!G#hn7GtWbaDPWq|DiT4!nFI{R z1s9uQQ7uhDI+b^f7V6aLPBB-9P$tTY5<*!CSPHCp;4iSzYbqxC;t2)W;k~39%_76* z_Dl772lVXSC&gb{(l@0~@6rJ&rC#sAl+w~ZrQV+XyuJGN8F0bix!Gx1seQ6CQd4@T z_RLP{*)y|uN_uvm^pw=pjMP5a{Rd`cr)OBvyDj)}NZ4T&;lRsSyS)Stg)>FXNs`>< zU`x*B4}zyUj5_`-RYi%V?LfLS7B|gHXG$btMS&Qby293B#l8=&Q!=H@HTIAt8W5ia z#I8v%a*95xk;7&YHe!4OT1;3??meay?>(7S+juYq*K+7`6b}xoTNP({Tew|#>ufn_ zaf-G;$$+R$yI>Y>dw^5Y+v`Pph}9tI($va~NXoP%lVqb(ctz$kQ<{%l*Aqin#BGZ; zSx?{&45J*&HCEH^F0{aeaAryhEW9XY6tqOHIfy(g;WJ5r;Pr%$Q5r0 z@;5FA;Kzo|O2iDgO8q#^V%t|}P9Y;e@r1j(6r)OQYX$_F99Fd2bmV6|uYYjJTP zo)8kCc){tX-|w>ZK?Dxf2Mgd3888^7z~%Iq0lLtzm%; zlCtP4ZZ_+WNigYdsCG#Y>Z=2=`KF>Fcop@NwUxf=U^|H*hjuEt5DlQJfHy+!1=LWw zFN$g$4JDWFuly^d)uH1@5l{_`SfbNJD zPIgmn>5|0cqjJn8@kg+hoB($xyB$J{AQ$J`wRL1K1@JIX@FKOsthrF7zWCVD zP8D7CrUoQaMY@UbwqApL4hXIkSVSn$(Dvd?pbUmZxO{?gAsht=U?eEmU|)%;p447+ zS-}gDn~YO*F3CdnHe3(S235>dFQV<3=5@*HWWzD38pUxH@gQ~L!p@wgj!MfNJ+&}n zY;Hl()XdzmV3%FH_TaYn;Aw*hh#bC9kO+S`GHQYX=$5_Zv`ElJ%Md(%ORl;g&qX@c ziB(CI8Zh(GH#ocoykvk-=Npbqvsr(4Iys?#X3#UNochGlP<`+;= z1EJ02v_9~qS%FY}NhM7Xlh>*Z17}r#D>5PbToF16jQOU%VgV)jn#-xb)fdbf>{|JQ z{He*V7V92?B3ne(2vu~SMLKw~ibK>mKJV^JGJ!hzR)67GO8*5v%SycIZT{64G2Lv+ z`&oQIpiJ0^Q6-K`5 zw)wYuURUo61OZM8e^z(E1I-PI{_HLdjZiVRC-)KZx&L=2=P@6KyNe^gVmC#D3m&A z3Bg8-xs~)NnmxR*UDTtsK+NuMIw|5e zK7X=$gx!l(74LmWr39;@VW~rU&_gyvlt`zrl*&&e3w8pb37{neiXzGy?Zv1s zDtemI+=;FO$j8AhXGvm58svmPLlna>k^E%I0Sk>{Ev79DNhwIG&>Bw$gw_1KEYqu~ z+AHH=Us_&j>klkf#C&F0&mldm7uq?Y8(?IljIux%YTt7X4GBR;ae7#ovVZ|y)=Nyt zrbj%x-hn_uui8Y&L>z@V`Q!33T}3&$g|750S5mJeSF#Fv)n)i_hb$54i7C9xis218P> z{yU=dc*zvCd|hRTIzEe@R%c+v=_6xJ))tyCHo)O#p2E76npBy1=79}lgk!<^4dlSB zf&r8RA+&*|z`0z%`J(FA(~fs*k;wGc)Kib>VRa}Fn#j?Y8KC)M0%R5!4L^ZUUZA>u zHUZRs+JPc2pM0V}>>m{WQPt@;vp$s&y~b>auIYuD0$9J;f#YgBLfG)Q1w#78%0Sv! z3NKzu5Udv~Lw(4f>4)7p?700tZlW_qHIrD4kgkA2D3)6nfHR@UlZDQDs+?~EX4 zN(6!sU6u=QRM}`aLc0nZ0@x{Mk!nJ<&z@pcj;!OL1S%rkfgT(yA);#iDMqci)mR#3 z9s#g=ivS|&q{nGwa>1;KJmhh^^xqNC#!4mvN2ZL*xmvUaf(WsVo#iK$EDwn@!9t3T zdBYW(FA+6IGw6?2FI}oJp^(ztkzfO>GqF;ZCWM(lb}n{;P-5uLxatP zWF}bMf;1k^oNB^dV;G$r(b_8c}DKDP3QZlJCaMLD( zwvuqa7_D%1ki)ez0R6WEh&}#0-G>u?VNa!Fg3(wrqc$!RRfnL!Ac4aC+v+i{;=)fY zu6BsC1HZ2T4TXk@uoUwfii^Ak?K$5_g{U{zg>CduH*N2+ksj(s{3RE*(nH-8-`%#~ zQO4h}X>if?d@hcx`p?N)??}6IwcPP;9X6|Y<-IyIIF_VuhZiKBedef4LIf867`d=F zm<~dqObBZ>Dl?ZZO0$@eP7QtP2tv z6nGTzI3{pX$H6Q*`gh2oaliY5nL#fEM>?J%&8<_+!?$|+!ZM{}UPZ6X7xbdF07E#F zmskzMS8kY@m)>G!7GE%-sXmm7*;V?;d-m8lf;qn0k)j*IWR2*q`sB|M{ehhcMelF9 zuh#0X?8|AiVvGfH+qx{-iDXx(P!wn^2>w$Be{vl1#Le41DAOY&4YH6N;5c`fJ&W@|3YYm;!NhByvV}N+4uIvN|@UU>6|CSh!UD zHoP_Vk)3B26?3N-2sTuBW8U~3bon?t$a z!_j)Tvcc&-WLR)6+B?!Z?ntn$R=j1#l3nAmT)itME~}v}d^GcDCJ$?erkuwr)*u#D zx<7>cXdh$-LNsQNy^b=_v{SF>VRZ&?V348kj2W|f;cgpk=#fFaKs|xIb%Wp45U8wl z&A{bk7v!>8UE?;TcB< zGjU={yKpP7EiF8IR&{+9+h>`8&6M!0q^rRcaiAAV1+za#BI%MS)B%Jxm0M&APFM1U ze>OScVYQf6qOtG8ER~L3BZm>u@`#ocVB5;dQ|&%eG;J6Soq@G2ToXhWl}Jk~CsA(P zXogI!>leL{YE%d=km>Y;_>9f~VFn@un2)}eg%(l&kWID337ladw{{q>E)PX#L!f$D zJ-|1J)+kaGT@L0N0E91)#w<$YLhC0je1L>i0IbWLRERVL=YedxsM4@ku+n5mM51u? zMUsf91-Gg&2$TvB>y(ULp|Ek{7djcNLP;mGx~NjLZL9O;1xgFhR+@s&1dy1t12dBx zo1-DAr2pd!T+C0*t#L_hL-Wl% zwT{RSbUDa|2*F-dD2VlX8ZuE<1Ym1=q9H`t>ex+r6A=0`%K>Ui9`&7mpipXcWYc&a zMkd1vUwE%6m@VMwkk`}%8HmW75CBOH1mG^B7zvh(umEc!fK{Uom@Tz&dHalpR)^Ok(P+9>oZE29XVh zSQOdf@WePxMpg$(8f|kJY^%`kLPUXtX$Y}_#_^%tTPmKYNCQ~DTYXvGqxR>$XRq4 zE}-Zy+Pjf-1`7)q$jnU$R)Z;3W3{6j*C?(Vqx|lmJLFCWXyCsf7!8Tm683*1%o9CA zAY=^{hAK@0+C!i!v=9KGx~xe>vuUZIF$DyZ*-5x z#?gpa<01p7?&uI=X;Jn;i=uE9V@S0|K;e;)WxCh#cs!b~20}%&n4;%(@PLra##$2L zgQuojuP|c81t~UJmmn=nM`hfFrO3J+Y>pg!@i2DOK+$@ENvX>-)6>Rb(YOJBvrQ%K z_rnICd5gHNadgmGBh1QR*pZynF{wNCoDRxTWzln1&u=nZxQw8x(T8_@u@xu4mdhe6 z@EEnE&(e@G{I$OfezS{6|{jp=@Z9#u%#5p?B#^ z7lFsPmE&pMIjjGO>n&Bs?ffinSm$SXF*LKy>2ffg4=Z{IotM@eMCTQ2(P+|y#a0;< zTmu$fD#nK5UF>^Kanq#EU|TMC=aQ-#@KZAtbYaCt;Wf2xO}m zS(1hbl*(8zl1QQejOj5m6xSk$yK~3cshP1VDW-_JoF$F2C@#UB;Yk?Hj#`3rnx=Vn zLu$-;w`d<+g>3TWqA43`t2|P%L04pEEf0yEC5pm_HlQk%x|l!)^5z67sV|LJm9gzLVmn;U84Wn+3aj4Q9bZ{iPRSYN@W+gZ3F@LdI$j5lT4Y(RMv_E5#H3W2p(E3^QUVxB@dAxFff&Yl2EdA5%bqkFU@31(9;0p z72ZxL+ZZPZx^OUPAp~&mLmYvK8EFjAxU@mrp=9=|Nje+Ymg}nEiHHV(Bri0?@=GKh zICbPMHk+n$WQiCtm}F89L5Eaa44V!=MP;DqHN@dMAdAvx*_@jCE>0r$Xx2@VKQ)V` z14XNp%OS8uBQJEoUwbVyym+^bZq#`!Q`C9Ah?Hw|4+z*d_ZL2u zAYT;4sx(;CBezO}1jW;al00}($zXH`X&g_8#~^9LdFxd{#PK>e5m=CmzUXbTD~Xen zV5N>>S6MhdlZ+XReQ?*t<<6FCGj&0}$b`r&5Cvh)h65bff=a9v1<4IiG@=YE+#()5 z6>8$GLDVeJS%4R0x-I}5dj?)Nl{BM%tB2JyJ8v*Fcz>9;6J$XHcVP_UWCNUu@4P&qC?3Q^Bn9+v84wRWDT(&v zvdy6m(q>9;Y9v+Xqk9IbtZZuay1?`jZs>0B7?q-aX}f{&PGJa`erYJw#PMi(j03r6 zO1R#}M@m}3@YJ|af6OZx+;?dSP8r4$_l<>P#^;P^&1i%=xxqZdLOf2y5U%J5SZSL` z)&xSb)-Jzx_8q^2fc$|d7~nepaJwmvK z>jxvH=7eyIsgln9%+|>1jcy_3krX`$$ViE3WLOFqDvPR86phbxvEYfb8C=q(9c)F~jE`wa1k_+?4jm^l)&dtjz?1I<4%*?EU!Y-njPAaY&;rEsY zUEC?yK}!rb5Qb7P6SU$w073E5MN~e0Ty9=w#;8mSLZ{?{{K6ug&Y+{UlTLBsG&4W_ ztgMWpI87uRH>rhrxuefMlm^5(2|mogWezJKPRuBq z|5&AMEI<_xBLF^>Y1%Rc?P?OPbIU%*CTQMB2+@7gcI!avv6Ov3w-o@f`e43MKCL3Zle8m z9Ck2X_2ljZsO*lo(-8ZtwdQnY2F>iWyu7KI*?DOrc@pN2D=HXQM6WPA@wz$M6b2Fm~M_XK@X8%ah1r+zUrTcTpfO-YjALc}~R|phvW7)bkImz8=gq!XbshJpo0Xumzyq2 zmJ%WLN+l@Ng6W}FWYrU+TDyR4lVZY|kX`@|8D#)K^1NV!WC6S=setq@JZkg@4UL(P z7JO}{lN1RdemSsG!Xe~{L8@cnol^ThyD+9SzH?n-hC)(JXy{znU8ubH8&@!7)~Qtv zLxbIF(^ffEWHJbqVn;Vp4Y44_=o>MT5$_R^W-@W@QB2;!Uh_>YAGy6ZHAbqZ97_ld z7VS>c`YJ^UgXk@lrN6{_5FARR=#R8d*8IV2PL;Yp|9in5@A zJ(W$@2vr3VBvO&HQrHGaY$Gnrn>m$T5t;6|Q-y_Qv2moJfJFV!IqgqPI_Ecaa=OzHeGv!%5R>xSa~Q z50Vu(iQsJ$qoy@+pkVXr5EKs3NeZ2-<%hF}CifICPl`~a2b3{c;HfQ=V=Q9ynE{GW zqNODLyg;9oMBQ|2DKg4OC7$bWStK(lB*TIWc6O8?(g9ZN;$keuNH)U|NLD6R9J;6& zZd`=UTS#&)uG8hLywU~Y%Zew1Y@#%c^@U(V%B8uzX-T#f%Qa{yTE$0AHcFQ|;sCa7 zkR6bf7RLrv;R6rmd4WD6sdH{P7!K^G z+29qL85}s)mShL~l|Bh#hx0WMg@=y-}d04#>?`y$O0Zio3kpO4q{(ONo4}_f!{KtvmV^CgnQ$gokkB?u zRvWeQD0G{7q70*>z1XBsN5fWN>5GXgGZWg&*;%12%?-;cXyxzJIL^&&kaCh6ALI{B zZB{l@CT0|3PiFND8=mXTl2##e<|xlBdVy8x zmRRU)U;ye)nqJ8;1!cVIHqsfmeH0QJF!DHMRt@55tAay>S4~9`G=t$XUK(iwcoEL? z)QH(8EZPM~_VMEeA(#jNkvtrbK#b#a8$yV3_ek~R1L04 z$xe)gpxI=`RtA@}OfeAk6(;bs+4GllFE!0}OJouZah1v+dU%*{BQ6MVqivArT~9i$ z-_cU6NN5T{#8yvEd?TA})j`?OZ3z)8ral2UzzD#Jpj5Xbls1 zs;r(ufsi0t?Q?_zxQ)nBR_zH^Gbo;A=BwIJDNxi0WbWwbt3~h{j{P!)1)Pqa2N3yCh4*O2dJ7xUCQDAaenr@M$1QS$$ zfRM#BpgVz{(^6_DKb74^kSLj|DaS^&l2J7Y=4wLJb~jXjJGN3$C>fiw`hp@gW}!#yNoHkFq_K`^H$q(O$gLnqYk#RTBzb+ z-eGH9t-l7B$jPD>|3?*;Rz@*&2?1_4Rgt5!c453YgA<{Sq)CXAv;}b@LWYLtl(a8; z$1y$!-*H6{dQ{8~iBXXvE4nmV$wV&Sso}aHH|t;)0G=-Bw3=j=G{eKluQUVoMGuuq z%R38^a%jjX!*W5K$6k*A7EwsGU0>L;7RYFJw1QU{&;k)`NUH`vGe2YMxUqRibr)g} zQeIbA6B^W`$8>m?t}lhLZB-Ao3DM6KM4|NeXb4mUdbktFAh*^(9h-REzA$$nZi>4B z3pX#tWGBmFbpsm?Wccn%_XP3PM`yus3q2iKu=NZ!u>a_}32u1%rjwEqT+qhxF1w9)Hs{lnfX=*OG78`28n!tiH;Nyc+MgGoah=a@WGj zhwlt%gpiV8kU0)@!3qRR#n8~?2T=iA<4bC-g!qUPg>T?I#sKWs%qD1WyGV*&Z+y6r zP{5h})n0^#vOz`1{?_hP25I6&qLD6A=x#7Qbx-(nctZe{5WHzctqkYK5uN;thD)8# z*{U@O#q8f-Ngkqa4I9D6Nb@g2aG)BBV|&FhI{KGX#>0gRQTRt@ffn=BloVMxZ|N`& zVPq6@R(N642rfmJu{nUmK`tN4s{|@^k4n!dq$k_~lHnr$q{}KXxFZ`lM&U4#9r}yN zhAV_7NCG%FVF1mU5vLE16+)ArN$@5F$AYVtB=VP+;4Y9w+g(^v#_Sr-=H#zFnp!i5 z#jLn3WgJumX8Ym9zR5F!O*hC5Qsbb_c7|c1>5HAR9bumsaqIiD{6rh6R6|ny^Ybp| zxNtRLqEiF`{Uv?zSI_#t8zE*KKEDt2S{L-P{A5nOi0+lbSO-@TF`V(y1f?cIm&6@) zlfWD-#7kEQFUT?#358UN=;DrXh?gr{P_|g z$UUm08j_4py*5@o(Nq{uj2IXjON>r}@yCk{IOBE?QFr`;_4t5D4_N0fhh=75aOU8L zahLeOLw?#3QvaGTJq`s8FtV$ytFQUHnFtwQ{hxASs!(+*?yyA18KpLDf1@1v>F@*g zx+0fDlLq1pdKqr$HeswyP)#Q%+AG1MkiCh~C)J_At_;p0FQtEa>ku0=fe@J(YJbUp zM=x+zR9QkhaC0>fkv&odjM+*k8puc=c!dde{h{zr8_O1{Qbf#n3xt2R7aDhXJ1Ixi zFwwK`P9sHdb95c6P>gEbg;_aJi^N&{#4F_AI4q#r0I$F1s6ffh+St)S|}@lx8=VPF(lfXdmwvT51MKT5@|+lK%hf0`PV^c8e$^@ zRWyOEsqIQrnHrlH+gcq)?W9U{?l>JZp8-9bQoix7T>j(So4Yf~9y|-;X(s0MD7rd` z`mEI4YIx!f(9-YDV*jXxg;}_kWBm&QXJ+bU&lR32%$Aa&la0xQlGra~y2z4mNj)e>Y1g9uNA6lTLzbSk0G0Y6;% z0m%?S%hASB+3;Y32ZdTGkVvP&S{fqR!76!jLIzYEHh^I*86E7`Cp}QdaT6Ho=pboT z^WYAO)TGd)W`RSeRr@kb4voG?0D&>9a8wJ^k(t=ZenF7rM3T(`n;i$ki!0&7Oo5!q zzFas%H5>}FH}6U-53s}m5T(Q@92QoURE`y+Ye^GP+S&DpHWy^%NN(lG(~g6&MMb$b zr15Y^07$PdEA!VD`n~la=s8?m09r(2(Mee8NS~xsRM7)wj8!lK+d5Mr;j+t3z7?jK$JRINhyQkds1!G?+gH>zu~A@ z|2dwm57k?owm=8s^(zwwqUqS}I3!&jgRiHUT1^0cu#!YgecT2|7cmQiWpxd(10#Ip z;AXD+I}VC)N)GQ@X5{py)frQ&n(l?4J8+ZPO@q@^u}XP$7a!BO&I%vX&J(sUIZKOK z2dkXL(Sn0qO^MUoaUJ9+V&$Cf4~nDcxF~T-g-yl_fma%X*t8v8r4VxraRm@4J~S4r1?QnvMo)aoC0-k|fM2b8v9~7J_CRhalkm3^9C7;7Q0OcHE%NrXmFa zdj3A(bXpyEo|t3kSScYq!{?p&GK9pg9EkvsX{liIVW_P%lo0Ijd$F)Z$KdmXn*#N_rb(hQ)!W) zH-XF#b{QbB(`$qEybp}cSIy=+XwiNG8)x0+<3(Dhn*iTL2b=DJGGm>46VNb`s}a4) zL9PvShef+{h}-r^SqvM2uJg#l(w5=x!iu1Uux2nG}6QZF0Cn0~&iA zs_Stz!d_Ek9}W#cxRZprYKI)rhl3nZ5>6-*X}+Gfq7<-g1es)wG(LN?iae_X*>IJ;-rE(z>V4C>@j$ z!DIfaF~p^4RQZ3^KM7aL$}W!UV;{q?BMR=IHg=0i`2Qbh0x_aQTlXghC{BMUl3Haw zOi})}?E^aS_w9#k;b_V}su6@6oomKg;NwVIL@$mZIAre01`k$gQyeti_o74Eh}Ud> zQB-%@n6`0Q_yxwYzWXSv;`n=&n^wl?%j{v*T>scODmOYE#x&DYfX=cnGlni ziBF}!SXvgKf0G(ZfdBPsEP?xXsIdg{-=W4*&av!75HTB~P^`XGsDes`#TucDNwvxP z!ZlR^CnXXP0cShPhakevzzGI9^wmJ<1{w0oB|&wy+KTr9bC5XegxoZt;!*duvHKL0 zuItrtT@yHkiJ*w(!WF}Co)0trzQw=3KHyOA#hKR@7YZL!)||M46&NzU`G?_2Rzbnw z2BLRA@m?Ysf<4iCXVM6Vo3A)p z+fkP!;J}|Ee1_nulz5muuk-eu%AaY!k{4OV+_iFd{a4Hdp=rAIh4UwY96+30u*XRWr? zsK2;o?QVKtkZ%ag=48h%lespjiFWHfhm~H;HahHMYz^!etAUOJ2iZKQ$r{cD?FliP zD6$4_en3!|>#`NWyPFOJTn<2-T2_W(feSCXZNf(m$tXXWsdfsvWHZsqR24Z4wvtxf zCJlkMYa$}ie=93C>z&o|P3*7+V)j-iD03;L?01>T%1lZr|AB^}I$m&vBZ1bc7zi-S zxG7VUdLCw27qffnq`{S>3M3Kq$RTLTl$1V)$V5;f7qQgEWYBs)cx1DMnvj;RAu6&_ z+5azOvrsX?6jLY;p!pUP^Uj&%072Bn2|S%NDBE0uRKg-r1QBUTCk7#z<;*G9I5Fvq zVQ5QKF7BYHYY49EdWl{-QKZdW)F^WXTRkX~4*G5~b%!j3&r1WjPX;!Z2tx?~b)Bv&2 zjfo}te2`e;TP@L9kscU*m*!yB1laH@^IT~xlc!3H*Ft-~=;*RfgGPqSvLjZFu=xaV znO4Sen-jG}jD|V#Y6d}h8)>FxD=p1b+GL(W@fv5(7rjYl4rgl+!je|HU^U`KLrp&& zcRSgN8r;xJXTK~lD7$K;jZe!PmxW}z;EUvp@?a3NwZz4do8UZ_?N_ldynbey2*FiCC6#8Y*7xr)t=E= zMU6CC!oQM5yn9r@TN@0)#?{5;lD!BNu3KLPUwLRgWg89ehHy$g3Mp7JydmVlKWLuG z7=~iWO11*rgy1Lv)CPh@z$jZIeJ!JVRFNZ5R0}s-E_2N(gX3}S0NN#cm5{3>?chH8jH(KE{fdg zlC4)PxS)K#=R*6bSyABT(j^%ANaRH-0~(B~nz~pJi9`T3Na~)ZO+B;iyt{P)7eGH; z1mn^QEZ<$UTgD~;^UOSb37d|5xI*=UW^>a=xzchcYHH>K7xgJ07iH56GqKn3*YOh- zWy6In{?^&m!3;yn;X@il?&bBh(6}-nn%F&Z=v{qNhd5j)j}LUz2Ysl6FK%)b<#&xL z@w)O0U1syl!ye>7yih*)QH9O0)A(e~SFy4Tan+4XFEv*phoK;?h;9^xQDhK%2X)sXik>;u1c+*b3y#xe)}=@~ zO};LTG{ZUr3+t_(fBM)WYzo@_?brkbn^+1AIh1oEIVD69#>~}9L?iPxayir1uvk|R z?mGd~ft|>?+;mzu$TGdfe$ajvMRy@f-6{!FUNmIzEEvKKlW-t)m`YwU*=;J25<3jR z{2-8Vej&8Pv0G+uhHnnH&uWQ+qG*}+^1A1P$dFe-%`lCTDTm#>*lfDJ7XNI2l$K7^ z2c~}|P+P;p;l~-IXd~okP?Wa3w*k>rps0ZePp!af#*=4mz`3E>gI4bTQ`j9aL&)^5+R8inPB(*$O*II zpb<-CN>y(D@sB?b%&3&p_~_bchT(ns05w*Wd^Pbofa1h4?lpCHmx^TS_S>d&~V^x+y!>Pl4MD==6s&1xXSrl*^QP0YrzV#OWlY zV{=niR|Ji?u$H39h`+(U;aIrR1MSZ(5C% zl20GeRH9;rE&ySqr_9PzKtle?p<k)OG;YL(9!j3lHaPAj6U@78R+l^a^4r%FoOnL;^0(J!@$%)Ibty&;=uGao}%C z<--ZOUchX9WFHI=VYNcTMN>iorZJko5;@l}x4@8idlH@|k`VWv1S=(td6`ae` z_6@`;VZ)|cHY-*n9bJ|qP&md`iX$WqC`;uU%HikK3#(2E^;~I`p^OPYwUYXzIw@JB z_L7O30`J1yu^NF&8||acicO{t7o?Ly@q5WtNgs8IgX*NM{6TdwJai(N(Zm@~<4Zd2ylw3=D8RS-XLt*Cx!gO#I z#t<Jqb)CQ+<|{wyqque!DdiJTpT)4pg^NeR)^eqv!HjavnTmoY31Sd8ulN|Ay6 z*SIC#6V_BxJZnXYCiZD2VQz$ z0x^@#pPGb2%IOJ&OiPwzswSFjWVPMQ>kNaV~|t@GOpOn`I}IK!aX;o zX=vnHqBTMxF_PO7Q?Xy9WOfqC$?RF|EI{ACv<4(n2(_0r*_zB?3?d9}k~I{WlGG$N zx#hO-Ce@8J630tuJwhA+Vz?2)i#BYf_8}Aw_PAzkCdkQ@JcS9$u;Qf63f0y70zuEL zP_NXUsUE&hL6uuO=4d%+zSS`Q)jMbe@i2F|u}dUWc_1>=?$c4211HG_-Iha7YCzVU zDH*G+8pyc_WS}cjOfO47Q}lIZ5j~P_57Rr$g)oys`PF6$^;ErtMLVhjEmxDy*iY5f zcxG2sj;kvh0E6Wi0mD`Gh-pY!YJxSK6^irZq#->DM1&ZoA`w~$aI`U2AFDj2e(*tm z5eMC-0PvoYGO#%FJ)-UQo=f{1&sr=-0C6ff zM+^kp`((qiVAtwb6dXIpJvNrjd^Ed==W2>WBu?`iBTsND*mI(ls*lkDCy0aVf=Q^c zTMq)%#(#9i#AKpQTk_yhs>lyF7a(U&SEh7CNluKmSEh9drFjIe@X|vjlf*G@E z4y5GbiVKtl$_$Z_Ca6(JOAKM?8yj*Hv=dq3Wofd33}RFnHjv?HqE;*YoWG11QZ4f} zr*Wk{q)Ntf*`XP7M_G~vPV%_J?0 z#KNj@a8!F84$e1hRKQnB(4DD`gO4`xs20#cM}*TOv-El`|Lhk6y{0W7Kmnr2O!$oP7$sept#%5E-NI|nR1RkJh>F6cFuxKb6JETsL zid$2qkQ3He6Gyi15erSz)`+QvkQWfR!k0~!%Y$isGOOuAqhr3&azd?fE-5jIAR6ye zqolB1B_`-HHwA@RQ5YuUFzN?J16vy_P*KsT_;DD8s8p$3IEzlgbsM&pPy(cCt!C@? zS(z`U@!UfFHyRbjUsOq(t_fk$@2s5JxNuxM0t0xyr3%$K-|zn$FTR+0!9FuqUA1`pC2$BY!X_2qEi!GPRdl(IC?e>#7BH2)Kp@kg={&Tc(bi4inHi8n<>kdp ziQ*{57$Pj`pV^fNY-Q^!6JgyF6i~;^TB7%#+NJjf*tmLYYB(mk%oWunw^(n(JQQ2- zumWNuWh)~!W9!6ZtNKhE+A^pP5l4fBS&z^g_RPAXFd1tI^u|UFXh@iF zGPdSg5(4D_3rMgiOZ6HNC&@LZHTi`S)JBddjmGXTAj+83NO~n|#biZKT^rX67kaU7R=%t3b>+8x=2Dpbi4@+ z>=OP_Q>xdji2kxdcdDqJoLGvf%>)gqmNz)DEnCp|(Q0V2xurT_`wN7$O<3rg=47{~?a zjxb)Ej1r8R3^OZ6)StNdOe4Zcd})^n!Rnm7-!WuhhmA8yKlb$2gaF5Iw^@$7*I;s>cN+19<%Pp1^!5NTKGAhZz>O2i7 zfAUOKNPz2KzH_0lB!JUj zxdHk`b-^=LjG-5)h3Z>8+Z3+$K}{Bl-+Oo^NZQR9lUWI!#X;mZ=2Wd6}7o zCTx@FLc;*Thf{|7)KuEAL82p~28uTeZ`dK-?k2fv-lL$NRog|C52V_+T8`An3or7){KZ4?nG_T ziCGzngp;$4`kGA6|DTvVIDGYA$KZh_JKGN9#!+~-jX~4bNIw5Jv2ELkHH}NFt_a=W z)`zwHs3cyny_Gg^|Wv2LJSGV4DI>;sJV|MQ{NA(A4>_t762|c+`@l)tgQ+ z*Qzlrn+U^7zpd9CHN`Z{DiWJ@Mm>EQq7=|8L!5OEL@t(sJRJK zr{We7tnB?H*=sJHTvrMgEf8hQ#>*Jfsex`e#EE3&U^yA9K3OeDCKzbd)nmtsI}ONg zQDzAD2K-94Ei(ZF)0C0R^UbDY{I|QSm+C$X$t4XC@FLq3Z2|9&4#n(^-hegI4F%U~ zxnt9WhS?-{V!?Wh!p`5U@;JEQ$)h@tg|7^;V2MLh)>?ug29dh@95&faGn%V-5r+k-alE;I@rlf)+lhzm6=b3*pDN zR<+1&tCnOi+OX>Zi;G#wYBfV+StHfleCgKd49;OVB#aJ@MU)OkAUX)e@ial%@FRp} zAtP)q&AmVvg-}_HjiNQwcFc#dE8(9Qof>#YN19u`45^N(QJ4#NHo99eMqMR)rfS)TnNoP_ zWLeAUfSM$2ffAKsO|r5mTIm4v%IKKfYLG!M49>ar zjF8stkZgjwa0|6+MHIsF4-zMiXQKncu&o2?lU=JKnYDCm@)0nc2qlhIz%)TNXMEY! zEz}5^Ghv_X^bhpthS&sIO} zP!3P9c6xVL!MKc+v4NngQ$i=i?kW$~h6cIDdR)2w+WHW@r&Wc#<&YEeJgyuMEF)am zu%Gh7^w$@3b#_hgxH51K9-_kI#^w!jH8eEP^;Lq5G}6a^dr^)tZBLrgzjwN^ z4bN3Y>Bf6_er2Q^doRl|zB)SHa4pC&3LZ-{b|XFY;xwZM@2PXr2t@RM%?>-PIsUa! z{|*oP*Rqj+t^VY{*8iXXMMsL2+M!#%(FwoSghxCF;5P!l9Q+FKn~2{u{L1mG!EZKx z^YL4R-(vi3#gG2ojpqaSJ%ZmR{9eFs8-Ba-`y9U?@oUjN-)N6t2mCtWmyBO`{8I7j zgWmxBhTt~>zfAmc@GHQt2)~K=72`JzzjFL)@SBa_Lj118?|S@h#cw%&tMFTg-zNO@ zKcbUmwQ0t!9(!4c^bkbJ}@n#zH(@crK#%3)74%=^f9-cy2y6OEcEtxeU(@c(%U?{laqeXxs%n;C<6ozyqGUFGc_HT!wtt z)AI_e{`q~7?-k_3vt|qMgXajmFQfPMzz?3ONT>0yc}m82+6LeY>6`uoJmES2W#9+T zRWAZBc#e23&3K!hucsL=pgr@6@8G@W=``bWJYAcC7kWMeyx?iPCUmkJ@QE%)Jc(yt zzYDl$`gOsgm#TUKfl6L|H~VI_O(toitt>PkZu&yd;4^w9MAU6(~TND zH-T@@#`CL|>Bf9KYmmMO&-pFVjm4CX{F!*JYL{-@O5c%B|NDF}=rBFqIDlvB;B@0x zdJarCS`R__Vd+MDJVy*oH%`KH)o_8obws-1!h3tXC*$cVwBV)Uy$^mv@Ed_&4t@jB z*CO<*0Du436@TM7k^WA~H{Qm3G5(&0pAWxnDfvbvo_WY$hv)h9Ta;rQ*#*1^e=oxC zO8ge%cRhZ~@LP`GBlyw3R<1#v2Y2>&F6->=Jgu|a^>*S*i8~V0JCEo*qjN>)A)TK{ z+>&_1nL}KU8uu9wBrZR5$(h%kdF`2t&pg9@{h4bLHzc}@GYz-V(dc9(8l8VT-uTA&#rVni!+6Vh z&$!dL%ecq5&vk9HJ;oQtx5m%L*T!qczl|r1r;PR;A26OYHW+sp_Z#btC5hK2UYB@S zVyDEC#L~p^iQ^KziDMEcBu+^zPMnHAzGI3Gj!o({R7bnh7T-|(^ab5FG&F^ad zO!KwImge_1U)p>{^GBMW?tZTM+U8x{CGORR-wod=9nb9egOTH2Wt{AO%s9n;p=*t? zEO8l;0RL--|Azn6C-b4dA7-Y+{)6&H`}as1<{y50@oSxqbr-)>{D$C{gI^JTv+-Mm z->vvPfZta9-ox*6{90sSoyKnfetGy!!>#_x0dT4V~1-PRJFS1z>J!{_jvc+b%XD=UW?vsclWyY=A6Fo&E1Q3yna)+yhqzSdH(8o zty0!~vgEX<7W>*icG@?tRWovCKK|{_w2ccd*!IpTpMCg#)tI&04m^MH8wo#6-{-Vc!-F4dgrMW5Z z9RKb4Z(Qlm+xE-Ek~O1V8MAg!ow4Dr4^r1}OS@;+S=(=TduY{`*Y5u1z*}$3*cZt7 zbw_od>_yWb+`4YsJE4>onIE0jy!X_+gnz$ye%tql%sjl{-)V;>wQqmK#!FmBzL>bS ze8R&Q2VHHpl|6p@hb6DH`)TL7OJCg4#l3Xvsz;V@fBwXw51;dowvTuQ7eD#fgOyKg zaxGZ*#iI{Db<2?-Jlg!0*H_mK9Qo#_4>i30uj4zv+hV~9?}d&z!u!94gMHTzn^Dzv z`J@@=9r0?r5C8Q?o9mKR8VRd!Yjr{9bw_>m`dzIrE&rz3>A!Do8JIGm^oN(G`{&Q> zS9$U$Ei0;Lox1J!-QC`}Y|?q}w14@m_ooMUJ^s^A`!`;lvGK7J-@JO&w7qw|_13)W zUb|z<=C=oo{bpDG*VEU(Hhsc|d*5%lcKF%-*5tg?t?k=+rzSk~{aMZXO*^ke+B5s7 z?Hadh`tto(SNEK=F_3-b!zC}BvY>3kve$!&{XQrkdqcyKFE<}~#QMiiILzIn^Woz* z4u0a<J4$J$8a|_(f+ub;EJzt@~hQx7Bk8ocidI|GfJ3Yuj#o^P|W1 zzjywbyWTxw+v{&!lK#QAuYY{_{qpJs@0{`96E^;1a_7gt-_x)v*f8?3lRlo*dQr`c zqyG5M;Fe{@M>IS7kK6p$1Xh;*_{JX8%}QN9-E$)!?`L7p~l};@R8Q@4WEUH6!=^u{O2C zH%~r!`Q|77lX~65h45`d=sB>vHUsT$!*E5AF-C8_b>B~CMaKR<_O&b6F zjcNIP(?)uHIUA}k!&oAvb@V_JT*FG?6-paLCr!2Vb)ecK99dpd)v)XsuQTRs9 zf!Wul?JpU(eWmBPkJt9!zIJJc8y7A({G6qyUUbq5>8f7?Y4H4{(EPqg*W`~_}i~^Wv{ufq+!Lzd-v@9`jf5S?(MW-=QI8_&%X2Tl~bmC zc6)Ya^2-&$z;89PR#x;JxPMYtSNArpj;I>Y;h1mxW$#+kYRYpni)y||^;aDD;oGk3 zAKl#Z&iW-CF6*c9#mmpX{_~#C zuY2j|?~1pV)}Hq9oQj=mi$>hOF#nv1$Fw`)`uP0B zHZM)^4cI#Ru9ZugeQ^8bC!P87eZ8mswxR1odpbS%<<{Ykq%1h*_R2MFF1f!`&WoQO zU%0hP_Pk%p8~h)9KWBK4$8tLLt2?#LX??pM)8d;Ag=ar}RnFL&o&GsJ_s^U5`?nu| z^3>+vem{T7);EVPd+Ft$`(3_ZeXAw6%r4rndZ7QlcW+*C>hvWGQ#&uaz010l&wlvR?K^)P z^zyfF&HZifs~aj-%>QlDnwy8UxqZ!r0~X%Ds#AyVUmxG9Z?EjGr-vGPwt8ewP0n{) zE5`I&kbPdmnknAV+kbxPsE_x&{_@(Ff4XYn_T6V4bK^rtbiC@(7iyOM>$0@<3$v$m zY~HGJz$sgXAK&xhcI}eWm*!7zzM^Q}rl04G`^QVAd1pL3;2-B6=(zM>_qBWYy&I4J z_o+tFN0WNy|9W$2>Grn^=e%-a{+`_N^L{S4A!YmAZ5>`NJ@)deQpT>ovCopd>(AJ_ zV_D13znypPgPZ*$tC!?d_E=U}zqj8pgI2U^({V;or`Fy4!;k)O&V4uDle6KPvQwAb zoz(U6CwFgn>6<&Q+WJ}P&fhk5-2d^8C--bP?$@pNwH?0T^3L!+V9{*Bc zaQ4UP=QaE`d2NONy#tfxJ=?!c;g_=p{f~M9p2DJB)ns!_!W0xbuuIr%gNkfg^gH`p=RtPT9Qc{*%628#wue zZ~7kd$I>5;y|?q~qnG4`+8;M*$nhOhe?RWLtJj?{>cjI++?_pY!1nIf47~c<7Y9H7 z;}L^~e3?1?h=rF78#`#z5P!j8LnoeiZol9KxAyP%%sYLXtvIRA!lx$meE7{9Qa`PD zqu2Y*j_$qqql!-VU9%$b_n!NcUYwlLId4>H$GJ(%-0qt{b{+q1r!$iuncek_olkVj zp7v{(nF+&^4|JHB^31GiKuq&7X7K>FKlov#iB=zy0UAxvM-I zDlg5PSGDu!0l|HXf3B{)WNpRd&l_eOHnwMZ-vQqST3`53>G0#Lyk+-yD;e|jzG>UG z-|PS1lRn=Q&D~{J1$Iw&y|g{<199eqaO*>mcbob{`BXZ}lVI*h*du}OLNyuWnR z(p$D8IVk@a+^i!w8N{WmQ%@u(49Kh8}*?aC`M3d+AOntoXCalD?3iEct9o^Iy6YPs$3O zTh-&isq;_myXUc)KkWYU)zu&DxF__#;)jQPT(RT#PkK#X_tD{P&--w|S)KPE<@)f; z@weUidC7rkUwrsMkG*d!`eNVZ{qFzl$>PALU#&a#x94Af?bq8XZ~A>j%W;2nZ-2_q zr=IurFX>xu`>B3q@sBzCjBhVou=$(LLl=H^^n~oMuTN`p;I3{jefRSXSN-tcKk~ny zHf8pX3H_gVyWM5KzBBND!`|KS-OQa=-2U*c*U$X!{g2M>|K8h2R&3v2w&JZv-`>CN zA8S(HY;kw#*50oydu>L|$8StIrPJ%}e?Rxxr0Z|pGOz19&*hFd>G_w(PuTp+kQ<)4 z^P)GNzG3gto0dN`>ZRMCy#^!o;tO9NeZ-4(tukNEsJi68r@XQ0)s)8%du7Cp4=ri< zwQ8{^z1y`XC-1xN)?xSFcz==arf)uV-|+1G-Piy4{D#|KeQ@4wHy%6S);s3>{I5>I zwM&mZyy51v*7yA91+RU3OKRWCu4*;)>?_aR)As7X6|Y|N`M>60{_YRyS6r0a;jE&?fkp`b<@T>w}!T?{p949k8Hee#G{w}_oBy+eD}X=2CqKq;nJgWSC8{wv8vp? zef`v&8UUJEZs=+-#>lBx+`92^Y1SoT6@fd zn@X?g_0`V)?@g^pe0;$6f9+3xH@zEn?H=FW zJMs1jCl~yjde7eDZg2nd%pV^}e__+yT@T*({Pc|0we_8Yul%>>!Uu0S{-mQ*etGQf z;kRu)>C&XVubz^AP3X=CT+gj~apZZehdtD5+2j|lK56ar!3kT9OVgP9o z@YOjNUwYF=Ltne}68|H+2faTj|C(2aC--i+r2U7V{;y%;*tTzfF{1pbF+bk%W4Eui z+e-WSynWe)U6W28 z`P&ocyV4H3_L>9jf7qL|eCWjE{yA~@@{W%#KCR~)KiqNIj8|tJchvI#Jg}$Lg&P-6 zd#2^fL`_xPAJ- zC9_}ecHoTa>ze=2d2rd{TNW%D-ebuZ6R+!1G%fRyo~?d7a@X=vr$6!P*Y|$D>)PKh zTj$B1e&Roi4y#G}e0|PWGk5mLdogwXPw$TVB+Gm2vf&j!J-^_M6U+NOU3=8!b6)B{ z<-?T)dx}T=Q8YSn>E7={i>_FC!v6jz{5ayG7XL~bwxQD*`_4?8J?`d*w(q{;KdXv+ z4}SEVFV21Kqj9U|6^wlIY8o0eUZHSr!kACj{oqY zK|Lo9TF~a2`#!GjeMal2FKJtK@1V7J?-}vr)0g~uc#kf*C!RI>yNAA=M;mLi&&swtkf5(1b zJo&eC_T?@eHty>)TV7O|Su$+fzhAlHxmQ>8pEn@w!ndY$ex~~2%VwSb)|da;5`62l za}rkHvFF3nkNfr?bC#dIJ@C@8YuYv3Uwp^r#|J()ui5JC@v^U59=?<2e?zO(8^3H<(*5Q(W1eVLwdLfR83(S}=e?)z zZN3}sYWMDpK>;c{H!vyw&GF`N_JJR*RoHZOLhmwfD_f<@)B^ z$7kj&+?clWly|mWQ1$+YpB>n?cFck|E`I*l%BACd70WmMR{GOz=&lsN}=e-8S{`MXjGZa>tt0N9^m=BY6I$6U+0Ce!Aqe`yVY! z89M8|w8hQdo!N5f>#hy^-)!G?=IVuv*J8gLzWzvb#b9^GrUhtTKi+Qf)&T!`{moX=RQ1Ew5;Oy zt?RqbG#LL=M%6lRTf0xFo;#xF=n;b!UaWDr>I}a}ANos617EB>XT^=0GooLu^2xDh zeE!I`SK9ILPI}tVv9_#(jU8P^I&&)h{P3G5qb411cfQtlqX%XE(C5(I4d+}_w_Ly5 zaNU-u;mfCfd*Z|=S3WvAV@$VGJ9Zh){gHBXQ`XJTHm7B2*Hro;er1=wr>eL6Zkd0R zgf36@`Ab)E^zd`TukT!#buKmBIrVz1eM`wf%c?gvXO4e5z;$e1O7@Rk4pl39XH(U< zr&?5Kup!mAb?EMm-M6g#vT9Jf)q~y|vT8)d9VZ_xSaalXc>B|HULSmRX|wmOJC^^J z@ki^z5ubceA$NxV2Y!_n{aT}oHotP#E51@%-FLS3dHKinqw77tqTSMJYnya?>)6!y zFMYeE`U_{SudDj~x#km(AN%I!H$V2y{$bVM&we-FIc`gXum0N5da!GG(S=6q;)-6Y zGU)Q7nj`WuD|J6m+o$S~X|_3!{!U+Nx8yuJ-oSA~8R_$1j z)!K4oc!N87dt72qXVLddkB;bb`oy3!z0Ot5?0TyEjYXT68qaQ;vpa6(;g`bJJi7Yj zmwz-puyMy^?Rf3y4tP1`}&t5)`FU#Dre+;g#AZtWRbdFAhUrjfUEY+;+)-n#Q~_>Q%cnoci#v+}%7 z4d-tDr^bXS8v_=dEs0!ty_@@1$)gch;bFa*E)y{YM* zx9d;#nNnj@ug_Xu8NapL=^fqX?XKQ@)9nQRnG2@Xoig+5A%`Ttn3Li0&U@*v7hNzO z*tlt^>63Ym`masVo|rzf#;mg^XD9DHw5axP7w#SV^WMQ3`RONz_EeW zxeaR68Bnu+%f_v`<$c$qrS5&(gPa8~Kmm|;&@UkANH?p`^rfFPnmqT%jtdSoZ@c-y z@FlG-EL*KTa&2y%@xc@QRyy{_xBB9UvHmarjEQaYqpc`AR9o^_msauXn)x*;s92|M z=f1|xf271uSyf^?n>T#S_3)oB-+K7)!H%up9-02ap@Z{!jGx@)-h0z4Z(6b0RJ?G3 z?YZvbXZLL}dy&82ntS_eEj{>}`T9^p>}^Ml+|$~x3U<_Z>Lx#(J!sS5sG=*g2RTlkt{-f8rdpRV=D;SwAM})( z{;*-TRA=7!aO3Ms)8Bk+jq&IYw|6(#b^UhQ^&Jb|{_FJ2ZG}s}=iWVW>rlkuD-WI@yC`S#yDJAhSUK0P=NA*Yz0|&GtL2?5*T4Bp+t?13 z!;9SUc^6jq%Q^Dr=-BaHGKQ`!I(YA7(ykCTji{})wVS!1 z2R|qpea4ovX7`vux33xfy55QJHfp`!(iI=onR{ch_E5(etsdml`1jc{qU%!=zHwHF z-7>JU-@-GM4(|B1;*=Lw`WhO%QloCa^)-)npH_X=D<`U@Uccb?^j&L}Q!|YIbAtV= z4vFj0wDl)>%`Wbbd-mg^XPz0}tWA^9s*9ig-SU2;FV5{~Y+v(doz8#kt9xhmquMK4 ze^$$#Fui`{pnCNlhP7<4e(LCkqc0|QON>4L+_d&5yYGK%YDCq)H)x};MfRLHp=#u| zh?E``l5JgvH5}0OgBM+$zuVcRQ=>&b;b~hZguV0ast(6 z{JHPF(5@dZ$$M|gwvhvVzTzuyqr79V@^|h9EUt|uyy1k$6vy+2W~wBs z?%w*#ZKGa)qnYVuc5-UR3R!7|n|twa8u_}WkIPfuTtTs7q9 zho^Hct#h5AyLM4i^S6)Z^#6VMZOfI=A1_}0{k7x2e$i#}FZLl{KB&9? z#{Hwm_CB2DnDZ#L(xQ7$*J}UIsnJdD&e_%b?;%SIZ%J3<|JX79r5h7^w7waeR{OS} z?(IJhw)^DHly~m^Wq9<}>EfZoPi^d)_TBwSHNNlp({pD>{<-)Y@-@SB^W9KELA8d0%%temQT%u~ttH-97AKtz93y9k}Pawqy1- z>ZRY2*8kAXcOw7Ue*EQ+x7EJ#&cVcG3lB`&J$K*!=lATdTKndq=*k6OP0WotyzThY zUsu==Jbl^BUT@~!FM6w8?~oZ+gBs8Ltmg-_tfnvCY4OV+Z=WB#d+z4Ff6p1SdyS|UdczZ*SK1}TjX2!{qRkF-n(`5#VM0IhrQ9)TzP8s3&W-ze%(HK?1#U--uuq? zlPc<8er-?7HRIp2zV`Bf8e7Lcv;6Y7Gv6JZFyoNvm42UPyxOo)#Kdp&t1tTT$h?J` zjk7+_toZd8^PP8>{#yLPvNm=4E^#fcvv|p#fCV?lHTtaMuc7k`Q%8NePOF>ucbi=w zMMT~Di2qe)WB|RW(<1U!kv=zWjAt>ZX$| zvNzU`H?KGTRcXWY55hN}oxJ+Xrsv0R9W?B_EwelQPUC<5<}BOie*0dpvu4?~Y3Z}l zx}Lq!At1+m=EIZSHtb#fZ@j@v)4!?K=@rtTZ;-#u&1%2#3DlHAQc>o;??R|ekrvB#xZui7TQ zdh~~g^Q#X}GYl%~7^MB>Vy%fO1B!m?_4}#nfA`y(eWTsqAH~m_yK7L3u(m(WNi)2p zcm1{Z&nh#%?X}>=-22-ab)I`9X-dm=?dHyGv^%ivOY=59h-+Lyr+J~)?P+fv|Oki5Z>&~wUa)&bG+WD!y^_SSXgt*OO-EF+Btl}uz7jME;nts?)IYf0~6|> zi#)pH=U41w#-4xvU}%kXJbi}q+1uS)-+5~Mdv9h=57oZb zX2yWuS4R&wRr|Yg_%n$M&wY0D@WzL4o%<~|Wc?)5`wg>x3(Tu9@<#lo{RyFGzrQ;+ zEFO z!_}YjrcQl1==V9_yxH&WikC0;H%ANzk619xZ~U_zotLXm++Jl(#Amr*_PQ|N_x{A~ z4fSn8m;IU4r$dWTwC4TAtdISvY*OPp$mJOCKI^?|(mS{>>KG8_kS+u;jT#F|~&s8kKmh($_a9 zWt@p_J;nOB?#kWJl76}w&vY`jUh&h7MaRbxJSqw$Rz=^rK7D@VTHZ_9+h zF5l05>)p;FArF&Vn>M^V=gQgpZwwt-r_+T7MT@$Gd|i98{)?xymt!`KAE){0{PaW7N!QJ}v-QvyMon6^>%g@W1Dl<2 zUHE8)|E+q@TumeCk8jZXRUCI?#rn(dd{SNie3KO+&qN*T8UK%SVDQ!N|JvCvYx-x0 zmM?m?pxW1?GdEb?KI>cQCWb%zX_BL)iukJnkc{-~E7gLJKUb18_~XwN5nfAL-aiU& zYq4fwpQF)PaS;IOgWvGV_^(Pbpq5mxid(8v`B^;Y0m3B7 zZ<|!BGR#%03Q?TK=VCxN_>V}nE7!(zHXsQ8 z<#3TfmDd3A@ZUgs;H!!WP*18~^wsff1+;>HAzX?-0T2!U6{M&9 zh5(wvKU=C-*@)*C0Fm&YLVFtG*#T$||9ZI90B-;i;Qt%xpTctrpbpCa1m(BHGsL>e;egT;dwM50{(AMeqB6|0JMdF zHC)2yWI!MIZzH`gp8EqDNWIXMx|KWPc@&@v-XB8wHSwGYXbt~jxPfrt@|)n<2?&9IGu#@0semN-?~DHL2Y+p}f4u1bk?@D({SM?$ z^|b(+!~Zc{AHX<(4*nnUp6W9Y&=~%=ME{q-{~Y|sME~32Zv+2IxK!Us06qMFAU*YG zDxkhpt4akQ-v5R0cgFhzqW^912f+V1T*B8YfEf6HL3--{p@3%azbE?tMfiKb|DEXn zT=;|G-w2oJX$l|_{(DGI{ZBMg7wz9E`ri#d`oV9H=zqd#OZY#7OYz48qTs)b^wj@@ z0l>50Ows?(!`~hL6Qcif;0Im%t%XbU^g5s~{C^=mwI>bGP}ToM@OQ=guSNf7!5;|! zQn*y!tAIH8uOU6*(+t44^_wI5|0Vdf@Shd^?}9%R{w;8co~8i|@IQRQ_}`BFssD!q zG>HEZTnR81&7xIO;qM0jQPKa|@CU)a0xtE}Yk+w8Zz4VQ|KrC0 ze$oF{#A${2i{MiH34mz$uOdC=Hw4fW{&z+HzW{$E{HI0#JK%2*{|30#0B-;i;J=IX z)Sr(V|GP#1rz1`a#Qzj-1;ERI-tb>Sdg_lsfT!VqNA&+__#@!|R`mY}_}jw21}@=q zGN2Fqe)<`BQx@faZw*30xn*IDiiRpYWdQGZ4@i{u!ml|8dd(cD!$c z_p9JieJ26*@ZUmu>d(iG|AV6cZHNJpRv#{&yixDB^F0TN5x1V1WOTRLj>#YUu0ZQ`fh))Wp}PR&8Hjsj;t5#rnQF zshO`&uUfuONsWAcD%A6BE;aS_(bVzvlb-hVsnWoAoYV_dujN|->Bk{`V@ltswr^!h zU#Y&Yh0+hNHqj^ z_CNku|NB-#zx(<5`&X?>-AP?W-9o6XC4RNVua5ZD6+gn8`bRia|73j1u8ddNErs4P z-csl;<9!19pMDbhCALoR#kA@xH3HDOp&pYjU>H?|)ngA*T8Um`J#5Vv5fJ1=xfW-g@;5R^1zz2XKfHQzdz-GV; zfct<7fR_Qi0XqOK03QR=0Y3uj0Nw(m0FD7V09FF>0e=Ae0h0lJ00#hV0iOd#0Db{H z4R{YQ2=E;s0$qn0$2+e1^5e4127ek z1o#>d0$2)g0Zj)zyi1cs12A7=m$6o z2nVbHj0D^S_yHyX^nm?qWZVucWxWB^v6>bx_P2j!{_kFm7;SPrTJ>2i%c8A*??k2dK;64xc zdAR?;{ReJkxRv3)3inmGad6|{?uEM-ZXn!1xC`JefSUz33+~Twe}>x-ZbP`U;Ld`Z z1~(1vNw_EBc7@v&?mD>Z;18g*zAST)1YqX1M3zo`b7}tA)E2?pC-j!F>ttBe;*?;>#SV7eE6T z4yXl42803f0963-fFM9Npb=mIpc|kVP!SLfXa%qW>H$oEPJjZyQ^;XFfV3Pt0WATa z05SkS0ZRWMRkH6xAYFsENJ!5C(jm$sF3ADXCdNM1o&)7XKrJGGw8{Wd7HCWYpW^_j z4>ZqzRF+(ZoVT1OrbGUF+QE>?teV`4TQqe}`deZ57M@7fP z#>MOV^i4=iG9>p)F`82Qrwtf5h|(>#Kpy`ee{D5Vq(nKx>0zH$djJa1QLflq-S1f z4W6T-c;)E1k4Ss*0n&>23)wS|@4$1Mh(qB?gLv97_RL@KXCD9d{YQ_`-WX~xh3n`6 zKkC!o?1|HkObx3MCXYz!N0tyS^lXw1_u0ngAFvtKPdLwm-4-vC$8q_E#?Jaa5a65$pa9`+-A zLfgfDgiqG#@Dbhyh;YIuG)nA8_+cF?{7vWKn@&I&pc^1sxCwAgfZ>2_Kmp(dz`oB6 zOm+Yoq$A=PO_WaInRsDEz(qXMoKOB6c&7QR7T|9YM}y~iWAMEv++Ki+3k*#D7>j51 z&z+wUY8GeAn{#myGM)K>2p;~#xeTR=$r+$}GJrM|hZ--SHrr>(z(q_9EV>jABpa9@hp>JWu8RLtJz| z4ptN#@L%H7h;?Ir!%dP;Y!{C!?g9J{?c?!rqsJ5Dc6dVB9iQ;N92(8Qt?tT$QsH^v?^RB zOJO#iuw0iD^&F+-QEFr;;etEn%6W2s7Tr$`u4ok;k**{qzsMEM&MQ?b$?KgeUYT^N zcV@4#ZgXS?Ll7wlb<0mIt>O!%mu8C_Bc3KcdBQIB-f9C|&X;+aoD)w=GlPfDz2D^* zI+ZC_DyF_D)j}S|{%7@4`8$>BQjwm;Fymx8G?^vw3Rm|sjX6viPJ1Sr$fGh|V9s?} zY0QZr$qA7UhjfxKCoTq{n^`3aXD2n1ycg7#1T`03g-vP*smI``q2$t9f<#h!PC#Em zrf|@6k05$t`Lg)zfJ20H5kZoe$OC_29xp-&f5rO%A||-95=aa#FAi!@gp5!V zybo|k1Xv^Zv$zolZBBRC@XqccTohzeK1{}Tx(c(hHMuyWKfeTFK~7xAjCKU%0pJe_ z36cDvJRHpBRZRf&~;e3#pejx4|drZ}_F8X6T$1!>aR8iYERke}{y5yzKEdZ1Mi)kAK*d{QZe6=Y+9 zWu?3ITm>K*J_g{5v$o;Nhlo=c1}iFMHrrr4MJ|r)WiD>2V{UFCHP~#n+DCD}i@(n! z5&2W{P$sx&AXp!xwhWMJmQBrAHLgremK{qHx?TfgCn8EFl2L^==YGnFfa#-92YJX9-h4sBSotIvL zKJysgqoa9|Tq0MFN3%O>fM~p4^q$uVLxoy_6a2G~il2(g%ceLP7!_0yn*qd2urORu z0``#Ya^+Ayg%-2bmR^_zwK6S5Nv+T$h=pJ*=3>^evU!7#VqArqVN1tIk3clZ-;X#a zx#%aSgLtw8rYsSAQ1D0d2jWl|%}<()>_R6B)@XT{5)aqtf}_Kz33C(gI&xVp;o6;< zF7nIM7d_|OvYagL(yS>LPVJ-1 zvfbG<9r2WsG^|zIcG{4j!2!X5Bnj(uEa~Ta-rnOVvvNMv2_GSF#+i>l7 zhK)!@%+5@%661?hWuY<_LrXKXAs~(+VPQl9QgAy>OL~y=CFEIf&@u8Sg`rgg%keCC zn={gN==we7)hTToK0LZ<}>LBOG`5GZ6AR~~vnFI@zKy4vyBGm!xl*tlA0purC zFqg%|7#0Coz2Js9`1v#mzU2fBLmP?6s4sx7TeL~^x-btCBfcQJJzF43 z5RzDp^6*3z@m;1_VP64Jc83~D7gI?ho2M}^_vOdEV1Rt!N3&3w3beS^3fe3nUE6B4z zXc5m8%!CSsjxhnS?iF`95IvIw10q)H!dg%YVU%BwAX?0}k(33NP!c!CJ4|<;vBFQ> z##PuZ4KBq1tEcwUJu2P^Hk;*6LR#G4L1nP(8d-i2%+VqthjEH?6_=={P*D$>qZkgd zEcxlUT3C|UJwI@nc!|8SG8pRz%~-6Y#iDZPS#~)|pg%CNQ5d`C0B*je$TqUjLLwPG zV~SudP)vAcXh)l6sSs_z{caRjZga87h!&1azLh0Z#BmahBWEj<9;ppNW>qy%=`&@L zAdGU6m&);$fw8nvGAX|=6;3!^P2K%-o99ON_P zfm6~YbN`qWquu}s41Jtu!R5NZA9ti22(gfUF;t3a$>eDx#dYQt60$)N>;W@3TZqN# z6Jpv@T!+g|T!^|$?lYAv4+_U}L>-CJ2q}${Vw__p!^LDg3zCf~nB}Dj;t7diQQn%M zfINCuk^q$~9P>7h2^`>kfFsjG<4T`+#y010B2T2XIA~;H>R@eQV^e~>CShVi|05oj zkjNJEb|IV0xpYQzF%~iiFUZYfO~))uVit|s@OKhBX z7f~R7CBn74t#0a9TDsA=q&0ko7#K*4RTo=6(^?95#AZkZb}p*|N5m#j2A>u8w+#4Uav2Rm;En})=&LdjSG@-0QWFeA~L(+N@1jRhq(B|z!_vSy&^ zAduhY1TjXDF}T(yC;<1xLwMjbZ-5mKVu?%gMIcudP%*ztreH3w5yq7Wr%Wgw7_yX(R~*$y48S`W~Q zNMR7A!)d)t3R@D>h(lnBICwCY$U}z`O;~Ltc9VQg^;D%*_>Ikt-Fr%fVQK(}`C3Tut;uwUO_5=8N(|2vJ71**+0zHF{Xqsj8Kq_>WD_wVs`tkRqA>+^4OfJQ<-HBO4L7CJ8>wczE zmWx7srWa5oSn3}rYLPoMHe{y27>e?mL~3Y4=tX%kz4F!sVUV#IoU>_9S`rx~4;27s zq%g(B=UCXX`GQSGsvw~lVDHMIBXn8MDI6CtSGjM?* z(LT{TiOPYXm_U^zNn;Vh3x1YdbYUSea8aD+Ixp1Up(zHr7Xj6vF``4(Mi1U(WrZhe zRey6E6OWk=-h1|jRmHn?@#XQTZ!76+_zF?a!rPml$a#b zAboOjOf>if!r6Q8@B!k7F&Ng(LAFo>OJMWsZ^!BP}(4HaMM>_|T%i_z2ucVR|0s|2-! z+#=nE zJh>(q{4ENdEO$EJPhirD8huhS1XZl0KsPalSd^m|dqVOOg33;Uh+|P>ki`>vRxvsT zc{&MXPn;CGOPVb3;+)!7eAA2Ea*z z)eo|v+YO@>2#NWwQ5eq1Ns`i-KC|pAs$V{4hXM`f;=q`V1bob%PFE3K9a$Q0p82T= zW7-8Kgb|~}7r8L46lOQpW;y5l3=P&XTuCI)aqNmPc9ozfUv?{@xJ({wmUhAzpY`x? zu{)Np!Jxn_h53^+HMb<^%f_-uE7wDQmyW$K{z@Z@E#B#ZgQ=oytYC5sc4Y>$Y7!ph zJjiY!-{J^W7a_lsD+S)o5Fm$prvYj)h05>bG(6N(juK9d&xC+O8hKU^x!-8lOYSvF zCx?p`ivDy$Lkw)O`#@=F2Oep&U@b*+KUcJ;M%KmUmdO z&ds!erONTCd~EX;*hyON>532!!wn}#KJ5Irma6AzPiq4+AWiObdHb;0#yb?_n=x_Dz)W-hE)%n;~92neuP4-Um^9Lz!s_sV#PM2XS`80l@>7Op>bP)b9q3DF+;uWeNlMM5Rjy1HL6D@uWb+F`(`~>nws?pTT`&O1%xoi% zN#sOxcqo{P6#^iM*sKIaSyH+T1K-V5>@-ZEAnGB$!Ge`5rY+Y0a?_IyDJD@R8dF~H zQn2x?dY7V%Znjy<@+2ChH5BL_txt!MheH3D=f(VuaS67S3kok_*urr;j9?8$6P0N+ zCMY9B#;a7;;Y^PD^P@h5+XuF&uMG*KmUJc~QoFIvQgt^|*N7;Nz4j`ZCcx`sD4I)Ta!(8D3)S-ZXwh| zxqQ=F=hVofU&VPzRzZttIATq~c`amNW&g0i=75?~@M_jKc{VV!46-T1B!!g&v2vp^ z9z@SrAer{aEZxu-I5Kkfrwl4|LpC)g2&zCXv*3<%JQF3;0*m!ONo0`ComsRnrHe#1YEI0~TQ*V8J{`eIv#svXQ4Uu&y$Rlz497lBy*SSt3blD$9pBTM=|FVq`1v z*uYa_VqGCfn^{#+IPWo5st02#nx$2thZnJU_PlJy1d~hSStemj?YLeQ(g8!im78#J z@`=)^d&XV1K2(B;qzNMBsg}(dn9JDJu5N7`$OWXv$Z|s7#AHLFkX6I@UlbN2B$FUa z=E1=bo?V1C;9D=`cp6(8Ap|4}8f3B$Tl3k9Gaw_8wCv#@R4KlxCx)V`@7&p7S2Wxi zk6;Mm(=?NKJblb~X%s{hR#dr7!+q9l;zAqsZg(M3F-hSXOBR+`5C_T-wp<&cVW+~W zAp$`X&bN_VPJ{rR6!kQt8zI*z2@_l(U?CV-Up`GIpJQC6y0VZhFW&6*m0Gzv`NW0m1b-j@+eMUhTk zRf0ev2cheQlqqvdgrPpbq1YZJ!x8wR(D8<3lNm-#{mly76YRt7Rjy}L%is10nShvy zkOYj_2EkCLs5Ix5P!D3>a9S}1W?;`F#biv@L>X-(l_d`$N|yHNg^1%8ng}tWq$>6n zkRLDv(Jh>C9B2mc6UFqJqyi$Y?P;?K9Sy!J&rigHxzQg4RaB78r$nQ9h3WKp5%EIh zyCk+E)8yG9WMa{%L}2_*7WO3pQW;5Vd@n_{U`UTGC!iGXf}F)z9r&o z(cT!h)WJkw^h~m$8!J5aEKe|aCy!fs(xFA5kQ*3%SfNDCw}TyH4}8DZv--D4@`@q*1*u^+M28sZjM?PW4pQMv{(K3q+7>hZ4a1rMe!E zi6Ez!#~Cn$L51~^$d_Sd6l4&w*_dR5=`M~OB&J90l>LR^%b+k8OAez|0n@+$akL1= zIHe^F(TYkSDHASYBX8&r`O?yjy)K*N!Hry7A#8x8JnyK+Wx|!JC>$GgH_7%w`8G)G zq=I)#B!lu*j90x7gI21NlmNx17CP-DEZj&0#vID#mv~yT38b)RH9`nasFiG22HIc? zG(I@xk*TT=u{ALkMnd+tAidE=>K`IxkOo9?8aaYb%EL?oKlU^nY0@xpfSeTp5h)2d zj91}xnfLV4BaK*<_cC*(_a4f_H>qryia;T8di&dJNDIfNFO&Snr7{m$kqn(48&#T4dQtIKv9UOa|22Z91x7DGUbN*M?SA7f65>2K%@Ze)y! zf=`zaXGqbT;uFn@dSjx_6vg%d`Mch_Xmf9UQnWrP&ImlS_!O4hHx9Fr@TbPc#-x}{ z27?*N$+DG)N9mH13?{Qa$!HSxu3q7^zlrvUu$UB7Y(TO;g_xu&EH$Zbk|8b0D=aO= zkQ8T5HL~4N5!aApiW#8FLe3+_U^J%0=n@jm(J=`zaXJ%BJj}$5$!=DpC9I(C_|iKj z5!HnOvC_8a7>+YJgs$Lo^Bx7-|e0$bQUPSN4(^%&eP%xFXoH-XNQIiOt&Fe<*Qj>JB z2M5h!EP!~G_Vag)Jps0Z;z#h@c-iWhYdh{yN> zUf2s>J}k&hdi0%H7ZqgyCX8}?V8q-zhBsS;(EtM3D0odWn02Y9cCj5yyp$B+;A{9a&I@Aywo1jm^7?SH&&O4BV zr>)2VtdC_Ii@sCn7vZVY3FdwVBV#YB{x-&^nxfH(AV@+|9HCh*4-7NK6s1dvE=Aps zd9P4;+4r16JxqtU)o5b8k}(%UDQw7jnDFgDj0r_$CDZgX1Xm!Wc_1>g1y2cIq*(l49ZvVE!g~9O=zQeH;cj z<~OBa-sVzsi6$tlI3TRk0D?A}V2z1X_Do!YkPBl`2+Xbw=SS5^qMHNfpvS@H*K0^E|mV+Tp!r4#HKtx^d6hhG$S9L#wz z*n{DV#tQuuoLqMsc0xq59Tp|&`K}yWguK-fkk?*AdlWs8AB&@Rvh^FYsbIPwCzM&( zo1ssVob91fp>J#o3z}2p6t-PKawqL+Fv(ch(W5e0*W&X_k}Y7M8xexN zTNAFqvW=OgHAh~uy?|I)(Ao_h@2_6V5h1`-4`wb9B=|-|? z!N4q%@(6)Ou6rdN1nrE88bD`5rVdyGX-aGb?a={te5LfnxIu`FArR$RW45G<*;&@m zJCQn?J_~J+4&?iAD8XN1;{`*U)L88`?i_5}2L+5SWP>RgwiMW6v|0HJ*5}L)gG@y* z7F0N46he(wmCp!;*ay#>Od{Ag0xNLgGasM=Hnt(2G{_MMBt}5ifVAyKsMZ8gJ6L`6 z(MbxDXe~y@44?$LMO;~w>a??cZ+saR4oQ$!|>LiQTzKj9;=Lxg*7gO?F4} zr{Fs`?AKC#fmyOy_m=`Xbe57aP(fW3j72{U(|`aX`T)E{SKDlwl-MXumu_7bh7B1|<$lnQPts?cjj6 zojMQpoM6OHVdLi*MT86`Q*w#56WNf_H>N|m#iRfc-OqS3ZPj7tiFBZDsXHyqd$8m< zV-)28Fw#K{Fv!M3Kz1R2LU=Nfwx}j$LJNHUMI((Lv8_tq6UhvNN~IYT-{%&2GR3w3(dfAFCWYrad?L$w#7&C1Do$(@W=dF|}zvGBwFGU+9 zVQd_er1(249hM?0ZiPOo%3epqUig9zy|k7cM8LPnC`f^T3P}m(9i; zFPMn=dm=Z)@z6&3u_+p-N!pH}*_vq06h-TGEE{zLMLwz!ioyEDZK1;kXs77EU=Asz0%05-Q_CuT0KWOSequWlHAun$fTn zu<`Mr#D$DP3jFfKVnROS>DUS<@fn7|IWVDs6vS{K+jOyZV!9PVgw;deT#Av!RVWe+ z2^g15UdCL6@eZXj(LVZ4l|F)=3E|2(DL)^t^zt4Dn$CwCZFp*g?HKaMdvGv@DSYKZ zgVY&rKrNV{Vb`v*?yhHO^lJ`;bdK^F@~=_y|4oYBIrxD*-3X{ zdy(c4O>-Kiz4qIIQ}ikAr1H;Jgn7m&yG7Yr#ri_|$`JP8E+%^r`Ju@f zY%OA@Ee1i1=)>@^4jl&%>t5Yo(_^TnM?k0No_mgYQ9mp!fkk|;4ta@8T&WFQtd($n zJl;cE2W^UcIoC_aJ{+yW`FJPcliPm5}hgrOk z?|dUK`os5Q@;_SI@@J_C@mgxIo5sHr5oQjwp3}qvq5ds3gc-x$BKlv(uHa6l4x1T%yZVt;c@j1_$YW3Lhz3Tnu%As>7E zA^!eSOJoqsv?H>85L?Kyajejh=w}QRw*?GVln*`zWFV#+r`c!V#Cm)=gfqoUa7Mos z_Y*L)PSv}PxLd&UMh{{!5*=W@%hu2|g{Bb}`H%QF`j^&80eNjS7=EOw;W8IYBeSwG z-vu#!K`0Fy^o_iz<5XcJ({?t*iARyB#=bU5$A|klwB1g_K&(B{?TF&_2H(WW77c3q zDtV}*iYa6aC;PF;_zy#0q76Eam6u|g1cNM`Z6FS12q@^lK^UW zWfVBdi9}+~7l#w9cZ&^kH~C-jh^FXEX{mS?99bciJc1Y5!T z>01@P1Sg{T_qbRetKz08)-1w;1tx6hz0pLvbk-?^HqvjQe}YEa@?F8g>X~>ZTQ{RP zDF!wvup?5YEJ)i(Cik}$^|nA#BKsf2A{J{^bY|t|s+V~iAs9@A*`5Ydk^Zc0XgGKa zn1Tlh@}@QI63d?uN^DR=mIZG@WT6OwGKFRvSs_BLPCk!{e!y#5b!BK^ zwL%AF2m^=aQX0=2OI55`Vb)lpDP$J7;LlV9R>NH9$j>qeCG9Wj;B5&UO-n3Nmr=!N zN(v7P!z2JobQV%-#mb6*ogcL=^9QWG6u zeMtHhprkq14QX44a_vxt1l0y?IJy025Gl7%mTViEiH6all=5J9aA-bEGBG*?XQ8Sw zgd_V1Cbuz~G-6Rg*0S`;aWZK(5e-{D>|J~eX+v?IHqNDjjRYyX+$>UiO%|QY%+@nv zoy^wOOr}t5Rk&`Gw3>*IF6Ik$;F>b0`A68aSYfc;o;rmKty8Xw?cm1*v+3{sj75W+NXVyPCG4ZQ0_M$+cn~0glfH7b~CE7wiKd))Q>ti0)ME zKg9tKBs75hC>{C!-B^<7}IC3*fh)a1z!1;$zMj3hYpAoRapc#WyQ!%VRV7tmCPoNj zNkTKoJ#3<<@y0p~u5OfzK5K(vI_b_p(u}JT(-U8s1%a;T0wGcr zC8B=zjwq9{Y}AFw2uJ&nZr1{JBgqV6R9Hg-NEHUTfGHQakV5SvT}D3Jy<)x5fih=l zGyxrnacju%H8g;yM~GbM_K<&7h~Pp77nxv3$WLD)cFBm73vq%NNNLD-Pk17ECX;3J z2q}j~Hg;?1j1g8VAW0~|k)zC_#SBf6!3YtVnk&Z-FF!u(H5Sj)PZ4sOFqys6##ni| zLqE;VRms8!wH*A0zXXi4Tm{Wx8M+o z7#$OcOlCw%rH1H#8AEJ-N1rqDrnLi=0|)bS7IwzudQ&?+b*A^;tsuKwGy~zRopAYD zjq!F$EOrUN>DeR?r8_?!f||ziA~~I7k9r@HL2igfCEMHGq)(G&eJi*Y|Ek2ws>wCm zoZ%o|3~p2?0l&aEcw7+SLk2P`ow5)isl_oWUxa&!X~bojoPhT-jW9l~^7A=IEqhRV zIe(VzrA@GGfsUFfGe{*75Y~ZIS(*R{d-NQk{HI}8*61@8$_qBqHw47!kR`%Xoj8Dn z(WKX#()7yX)2v2qOHMUODjhxeC7Iaf6NxI%JcTmH3YjNZJtWG6$!SbbRMB^K>eymM z!|mf`0a{*uDu%0&KQuB&0>3YlkGwGA_*Bbm6cQX9!TwP@0y@w{MVM5(2=7RKhG%-n zW^uc+Fe#ujxroz=+#HcdNI)2QF#>paqIYJrWwmXqNuguG zXl%-yk`p9bNn*v0B?9;r8@FsEkPaDppeEQFJJ@9*0mwm2a0nj&L|Zi)9hvXK=G_QQ zKfD?fbiEW?cEtnCQ(#P8z-}F(*N^>0v(I8Q;!{K9BZ^1LSVFwjfJ8RWRJBzKXn8$G!rp!T6uhSU`Jl zmR|-09O5l}hlr~+JTi?4*C@(J?`*IsPPXpsFdOzp%yguom#qiD8ddrN5>iN*@XiP2 zvu~!6pSowm1Y0|9{kjNSbF)WB^>^D@=5? zC?7pU+w*j$8+{W|K%ax;2ivV~)*b&teT2n6&xX@O=Li`coPe2JDqEv4Szhc;LC2Sg zJzRDkdQT0udNhNvlM4$z3hV(b6uTaY(HQb1S==M@L3aQFLw=`vA-1YK@3<(Ndh~po#m0yDT!Qy)XPKtZMqVBX%j}~K^e-*Dm2kFJmn$IRvM}#DsLRV2 zs_imGa@`}!R9LqBiJ2H(r0sirDs>t1fA6zt&>9(>957p*OuL}>@f4Qzu^8Jgl-Z8<4dmy-1(MlvTT=$lC11HsBnRveeY zzBFP=71H})@avgIdSoFf{vGxlQng_Yz#<64!n*)6%K#l%*bpFI8A=;obgT;L5a~Nh z+RD#7ltX#VWMP) z6w>dj`7}3t@tz|(%XRb6tlZ~d4s>iTF;QCc!M;voC+#FD^}&4AbAXx_L|aufpss^z zu271Wqk7F1G?++`{!ep7XV%{Gc(zi=zsv=M=l_(J_RRV8@!#Tyb%6PChhmZt|ECAJ zP}Gx~KtXO`T13cge*W0c#9>fQn zDIrM)VcJOGz>t)Lk9I`f^ir%vAcK%JBi_TuGW61$5e`K^6EP6ul%s?9v7-4JO$oM$ z^9Zc`=oFb5BA;YdQ8{_3cxnYWW0s}kd&U}9xNsdyxp|^2wq^jSaczFIAt}Zmd=%?j z)%H@RtlA+iD0Jy;O^BUC65EAFlg!w>H-eCV*=(3C60pgC-u05T-!zcDQo8aibTTX{ zZ9+8B_+JAR5^T<~?a9w*!ioNxmK~pCb^$Wxcx^~aCRRo$Rp>?nh;>p8OsVMe1T(&0 zGsS4!Oo@*8%vzEmE=mX}ko4K7d>SwS7*DeLEAtH_FK$SQtqM}Xvkn)k1W_HipJ-SU zr!@2>BJ|XiNtP^MrgLDcceH>`9TBz&ES$~{;>P##?BGe`c}IdA>Cu9i*%ec^(dk57 zZZ0FUvy3^7hlYeoq2MN=A$Y(Kt|SYO5Fw=iM=|{D98I#(p~I?!Ix2=&B(unpJ@&il zW-52Vv(6v#TKJRq{09p&eNzJ!$jHTKl2jX`+Mp!%tHJ20ZZFYvQ1d_n%0^Byxla>Y2*!|bEgm6z92pRUwl59w7NX5@gfnhRz+<;FV1O_-! zkd)3XXY7h+i9Z_`OE=O2cW08_R`*bLP<-1t^h-qJB9>1j!zs+;FT zVWuA@lPGc8Od@O$GGK||g5`k=C%hL(8YxwBA~X{KUJAdll)ZumwvoOX(|E?6$e zA)}DSir6r=@hTrRqGg4;3mA%3wq#!Mbs3OL@@-K{2fO1z?$87iJwqo5;_`~m%|P|Z zvW;$g4V4IigDGicV=Lk&1|vg_3OBMusF#n@vdMN981p3Tc@^sEZ<)Qz={W* z?s@W9>`-PbdguwGvNTDlaO-KKEcGf_f&!hiC(Ia^>dLs6x?TU8ww%iI_}+Afof|r% z2IWu@Vv{)nsLUiCHSOAq#S|WKx2wXZL~Y5;TUk=$!)!X~pqzSp(&6wqwqEt3bmg0S zu^M1p+>=J86S6NYum6|~q4Yc>A}`wa;EB=E+I(~0n@7p7sOenv3zNk}9^R z{-xuhewqBsBkY{8kB=T7SM08d5dzU$MPsG&6?P&}^J74>eGKn9gA`$xfOnu~JbBN2 zkhn4x0}&EfJar-)qO$SHOoL8OApH;j1WQf-s=DDs5vWN@m#4~KoKRUN3ZJa_(XtuJ zw_@e=vLf-SMOrMjd5h6Z3t(pV%2X3x#y*~UaGNgBkQd7Vo@Gk|iU%8QBcefDR|?*REIs5kCloCsh0^NG;w&wiv1 z;}`NABucjF#+DDHB39|4P(u%$LgUJg-*mdft|PXi5vyPp6^vh$gWb|Avr=@fgQl+}3L-L&88_iOYu;zFxxc3z4_=vk z!gtSe-DFLP9Uac4$-EzC0Gv^mDu;h2g)Jv$`z&iMOV^i4=iG9>p)F`82Qrwtf5h=1Xjm2Dr9r?-Z47aJC_?^5dPdXO@jG34vleK3f&vElTqDv6!7?;#9|y1u@lGm0%p~FhXvF zOuUoM3a5XF3hK_j;H33F`+CCL&VhgaO0(svDYQr_xxL~>?CUJa*HJYu}(@8q<%Pkv?NMd`sfPq z1v$P{wo$)%+DD7VeAt-S*!CD3WI%xT4jRW2_K;xsfW-=JCDZK3W>~S!1ho|DXtU@8 zALI{y=(Wo9&QBQexRrfLWX1#*=$plY7y0q}(=abCP*>hlcLX)p2?!%OiW6w>; z$&U29AzZ0fqu^-MKh6DmvEW|Qn7i%KIp&U?5Taw@(v7X$mH)q?d&GY)$*y=aR(31O z7ynW~g$B~?)p1hnr8w!_MefcQuI&E-euBz~LoUTt$LINWi;~>|AN}ytp?eo2rSMDs zn_Dc`HVpi8;{EQsBc+|oTK|x~T>EbOXL7RcUyGEQH|q1~4txiQs=_hlmSyyV` z$XeE~!5)JJ|>S0ym&GW8CO0`ZOd9&3j?amYS zI8yrl`vo^Ht=8tx`25U)u{$EA*abC%TCdR#`s+Ps#S6zGrNC>4hG(wPb~;h9>xdt> zMM`Uq{Pf;uYqag`s~-8K?u?Xva}79gd5t!9?)8wq-A_hJ(|-@C8@N_GF#G=QN%c@( zCr3`dthL&|y0@E?x&!#_ShLRb1#7iuj(p&k+wD@MwCP^!V?VFe{yO#6>@V&fij)o+ zm(~kfr+vEKz|%d>6+}uAy%rD1UZ-t;(b=oh@ZTe)<(FH{S-4L7{n4h^Z~7v?wa%uO zuB_8OeEYc@XO^Cel$J=dg4?XuRvz;Chnu$Uij+?5o?T>LuRZ_K)l0Q|T#uAet_18{ zv|jrl^Vw6q9(@`qwVlzs)-UU|mL>a77j6C}Qi}WIk6~>$XqV*%&4|2nIZ_(eq5HBC z8?^H(-AbMpb2d_%J?>ebFE(f+PlS$Ncn0w!YRotNx1BKR=w$T&TXW|~j*Z&o_hG3w0Qp%eH5<5iqjqSo-!__G{2)^L%bBq1w~g9=Hh=J5 zoZse1=|Hvcn!%g2mNQph`X~tXO|5s>k-JH2H~Iapoeuh{y{YY?C7ZPUe>&Xu6V;A@+-OBzfWFgSK~q*Q5pyEj8NYX?l#)X#Aue$1PvZ#y?@zc(!kn$iyV-g7o} z@UqR?6O)>JQ|SYYm%yLr@4UWQJEE|8r}gik{tYf22oC#Fd!pgOJ0D*Mef6t<=-s?8 zwZ0oKP24*9$4F`En#Gk@e5rl4!rIx-pZOK^=R30K=9gM?+QN&oZ|skhW=1u;8oosv z_-2JY_m2BSO8S*+hU9P29{qi3^r4CwpuZVCkFDII-Fx+m6UVlrKa1LK*5BHqUHRz@ zXJ9Mz*ZEByc6QvV9lhY=I`_Mtj+6#Z`K)KbR;_RUV4eLN(AUmOO*XIIs;xYHWwa?B z^?RoJtnPnq)f#KheJx}X=*?6qe~6Ug=Un^Xw{6-%#aV|kFZ~rM-KaD?GtQks?YfU!t?}s(es#9f^DW&wwW-tg-Ochx`+YC`b8*#9?Yrxq zEn2Y(_3IPz))%*TYW4FP532ST+TZpULs92l+TUM&5Yp>Slt1=bZ2YKQ+9bd4FHO9K z@v^@8q-WOc(*EQ-V(Xf}ZbeG>M+M!xvrD^d_ULO3TA)Ae*SdV)ZMRmMq;3A?m-iy2 z$anT^FWIe)TYSOw%uhE!-xIGc*|=M~v)C59?+)_+>B@?^|LoR&6LMTrPp}i!}t2yd5`vJ zKWiHH>02|mM@sV!9a`3FulA#Q)qf6ehVp;x_}8v+d$ki5hFG3XMgGlK#GK!;SNoy< zorSO627fww?kk^)`?PmY?Dbps)6qz2+lY_a#O%`=>OEY&c>6=pU$x_D6ZdJ;W{3S? zYlHSqom%+D-hJAKAHV&xziD5jwCLdbd#mi%etUTPeC?#a(Z5Ru`1RSZZC*Lq(Dk|d zk ze_=En&~`Fe8wP%c{`4PEwC>FV+9P8Jo_)#(`PKV7p~bNSTI+_}KP)mLz4=A$+jS3W z*O?l9Sg9EC_Y6+2o_bLG$&jB%w;Xo|{JZh~DKigh!#CHcJ8KL2dqvW#^-mqt{#0an zrQv$u=k90A=Qlp2eelc8CQ1K?y*H1i;{D^l$G&7=QnH1JBBZn&-Y03%hKkZg+6z%B zMLCvKQb`+HXd&&Sl9D;JsqAFWzGgX=lC-$5nYqsA`}uZ%Kabyi|8f6yf6k*kz2-gF z{=Tkx&&-)I9kq9T-O8D(b0FqLgtPwIMi#-&Ia6^d2UPE6t98#o>7DF+0%~$#?6M0l zIV(|lvTpK5TDdU$;fzSJdgT9HIsb7bdLye9LhjIzD-n zOK)n<1uI9iZ3W7|ATCF2TOQ2&RVtTKisnaM&CcfAd7xEQ znHTMe#&>$k>JOcH&@OS@ziHiDw0@`GNHfldV5^;~+wY?JYMkVfblt4R4K*qc_c|m0?j7WI%k;<;}Mob!u~k<2gPuBT8e&DAew&* zeNN2oD~9bq70RNm+k*-qaQXwzP=a;ys3*+bhlq?f?W zai>;)nJ#WgG{`^b8!mwzOXZ5^oS?Sjpk&lpl_1F#( zL$rTb{@~;fAK`@I1mA7r(eW#JUYnk5DZGEXOVWM6uq830>FwlYrEoxANb<<`UuZpe zD!BSWDI`bh2R2tA|C>2hw(kz2x7yD-@UPAVJ$)k2}ECZSA zDxH&)Q2%Fwg!rv8@VhkDl0azYi56 ze~XViHFs?#q+h zAxmPO_N4>1)u5YkaQVI|X#FdZlUf~74Yjv9_f_0T77?~kbA4Ggj9EWd&>{`>uaorl z6B?i3?D7X{G5gVau(UR)Zqp}Nyw<3*U=xZ5bQ1+v-}?lU8?Su6_YJLQ_0L0oefb2J zzBsJf*@XJvvoj%^RRg9*lC}fB)huFjjKqtO8W6F)_hju&RNupI?5c8VpzA}Wuf|c- z{uCWeUFBLh?iq04SUH++XAQKX*4Dz!py-yZuaUo#`oAp_YGMD{tz1=E0W?3Hw+QoU zVMNWc!VNNL{c}4gIy|Nh#G)VTR^CDOnfD7L*>zxNb29C;!5B*-_E(SPraGA6khIoj z4O)*H-)9nGbuia+e(o%16hEkGU$44f2Nw;j<-DGZwj>OewmG!aL1#~jUq){)if1~AVP%4)(w1VR?av;PGHC*5 zv6=0?&8Yv?wbq^wXabF}>$g09q486_ob)Ka3C_%Fo_2gc8vi=abrp`ACjj%)|oa z3u@4OU*%zYE29-edUx7)u#r8f()qJ;8#DwY=aWKc{Sgxgk@9Q{`$BBCWYR4QYNoqN%*Dj-aWb#oSgK&ssy0^uGA^mai|kk zM~lZvsG|9Lu|fDtQzz`TR+s*9^COFxI&f5HaToNRk?$E>iPjHE4LPOMF7S34+$XPt z;;H8sD(khop(r`}+R`R8pMsJV??!aPj?tD6G-spo6jH6v5j>DPTIX`>zVe>PpIO>t947SucR17gr?-J6(H_2Yje8H&82pHD zUap5utd2 zZa-4mdC=wa^3)i_@vDk81KW7e*|FzN6RNl0!7#JAi0^)WeH7oq1DF0NGa*E)(B*g5 zHS-|LM?&*y6AuE_qfW>on(wI_*x1N}lOwWLJ#9ew$*HADAg-{@m3OY^fzs$l8x!hy zQ0{j>xwn=F{^Bu%GZ0mJmQ4?;;X%!>r@P;N;(_3W_?wc5C!T#RSy;^j5IFoJtcnNj zmyO3{SMs22RqkXV#8X#h&S6#X;Qi)hcDu`Y@M=M~Lt+^ZA`dh#sw(AyFe%TLLiF3e zaKg-wJa~D1yUf-S9`N$#wnrB8z-WBx^XEl8xaJvoxS@~->|giiiXq0nZuo6bz=L9Y zq5BK+c`%!7UbZcd2LajZdJgCEK>4|Ka9j=#w)t<8O8dZr(4#TO^WXE}Tkj*H=^YQw ztv|A3Ae#ppMmBvAMO@i@X{_>F9!#4a>^}Al4>l`oy*uGG50XUH>Lup0S~I@c^%txj|aWC&4Tpqp!y7apI(s2 z1MAU!_q`L4KMX^yzXdwv{yFdS_cj&-yOBq?an46a~{appV%5|g8D=1EB zqZ{;W`Y*>Rbc4I&^O|95>kCk>oZ1f=(f^(tjc*A{(48WORbN?z}@4 z_dB7YW5QJ4l}_m0GuOQQWGBew6iqyfjx&$r!-}*$J3*OssWfaC^R!_nyzu`xWjZ=ey%&m~ku25;^FtS2`~I~9c3Vg(C^U6I?+06>p~4Ob z(mil4ne2eB>1$55UGIRCrB?pNhdMx{!RYku6&(<v{v)AOAeTHni#IrskpP|$v^O(n zYk|3Gx3XDRTOh|lf59==7Vxbo+2o?p0)|?%ijymw;iC4XWxLKbgYUjEQKy$Q!;Yo` z-C>btkPKcn>DKcmcyWEdum8>_u)i`@Yvb4^kYBZbmu+DqJo$0$j$%L~ocdM#@TOrS zNG`8@+gjWJz196=Qw}shxn_Z1vql44zHf5WiCYgxr>WaktgDB6Z4YM69I6BExtx8o zBkSP(f_WCndUcSYFE8TbSqsU@K?X`kYQSS4;o|=DpI}HR?PB`HYPfyEzc~9`6-?C5 zXmtp#gpNs3GFfgFVDB{fhZZ`I5zAP1th>7uq`ext+Rl9hr@-~k?rWF8Guh?tYNv|8 z-n(PFT2TRr{~l53{45vbz2tgsOne8?3hvsa$6mq)=age#W1gVvol2AS5>B(2>-XQW zzM77&=W`kRRcy!C_X&c-TtBCO4pP_d(QkYb+~MJXzuDpANcqFz`yqg{=Gl&@BM*)?+^TYf8gKy1OMJ1`1k(6zxN0Jy+82p{ege)5Bz(7 z;QwFu2bk;Q|L5!f{OkAp>-zlb_y6Bs@Be>%ogZKK?+M`FKj4#p9|V(JN;l*qzK=i< zdvDK;)V0lmyOGrWhj(OH&1C1oIjNxI96aW&cRKmrGqwAxTrxyQ&6J#;oI(-_jgxGf zZo}4vO2R5?_sI;^V;iq(#=|tzkB;gpiR86wYV*g=y8s{hj_Ty;UM1t7)|vRrZH5;M zlb1SqhLRo2sS5n3{6n@%5mfo3wp^ggmz{5YeI_bjCYkJhg~}H{A?w$E@jkrq9Skmw zNg)LUh4GO69sK7o`1eV)*o>9Wa@^iHOt#hITvPw^f{XEU6LS2_1o^-GZ}xzxhlh%B z+HP{5R8>CFB;@MD{jfatw5K95Ks zMPol2i=Hi_>~SZGeEzcMpW6|7)jx&YaO-|T!$G>pf4whVs2$;CwGMW5>)BA8*CuQd(*X{i)z0ayS zn|#DG$hjxX@^?gZ(fPNm*z;FiRKu)P32ZgG~;RKH6m zt@)OJ!Hq|!S8?ER#J zlem2Nhw@2WfASydPvZ8&KeV63{RjWhe zkNvCX&+;idHUIyz|51O+PR;+n?0>YM&L7SHzwCeXA7!WJe>x)i^!(ZXv>na=zwCdE zA8kkT|1bL=<4@bs{Kw_j{pmln9nJs0?0@(lWvAvp&cE(Y|E28I{QoQcAO270kLLeh z>HnBNbpB}mV|&4$^N&uC=Ko*zKjtrGr{+H{pG)b#efYfxAycHvaI(@q@Pi z&41vJ;}32BoBzQd$1mFcH~)n{j(?P$I{xAD>486vpOpRY^XJdwFJ=Gx{QL9xP3Ql& z`OE*F2DKf1>PUI|6NtCRgKC@r`e#V0xMz-Z&vYWq-#W!Ns=u{jwhvhaXTS3>anWVd z$qDLv7p|)7A4Q<=tMbW4&y}XZZZ9F@u+bZ4GW)sWIE2Gu;x_uYM432@oqrtaA^C9~ zv;D81c)!2)AI9m1(N{?5-~U6#!o_ObEPVYCVEZxhzHmth%uo#d)uR)77cB!Z9BF>ZzL7qICcLS?nVuL;BrgxpMYd z#Y`j!#epqTmKKGx_8e9&PC|b@eSLPz`X%37S=kqTM$I`w5bl1#YZGEFuw;*YcVGFK zAPO%{^0LgZVqGgNHtTF8i1PFe8lDcwZfH?6o!DiOZ zFji@}+tHb#g2dUx#KvDI&$Fhv`FI|fCP?(PYDP_%$6jLQM&Wiv)=$caj$SEDmNVrL4Q{^=BJc;v>1 z;w&M;;NYm7@JUx$?{CepxaloK9A9^Qw?WZO)GSy`7mP5zh*=yX-WYXYF?BZ1d3+BNA?^oYY<)$I9Mf?bP8SMuf&{%)M)KjTI`;v0Le?7~$w% zdZ)f)6U%K${?z^kF`{70@blQ;=UEDQi=vN>6DMi~vXzuH&#^iqZ7x=96(=5j?#Y~# zdV*CIXK3AgSDdhM>30qu@MBHgryPC1SDavt7rpe%^*XERb#9V{g#>Zi?YmZC+c}oq zlA73{gA#;(-suTHA9%AOdaehZekDP?FpgPi?s1W|v3afEW+_R66ZJI4U;i9y%{Z%v zLXMI|%BtO-A=^S&vj^I<`%cIInJ0y;=7fYe?Dd>9xrt zi2EYvl8xoBvgWS)(YH5X1d;p6MY3#o534A1VT4A`2qH!5fysT(-KE`+tPaD{R27Aa!u=t%d8JGQX4MewS%Ql*HL=-R0gUT0W-$HW#GiAfVT#VivJ zU*E$za^pw!sFl*h-N?+3_Nz{^4x3d8wcL^>A}=gZ+xweF(dDUyuWuU=Ei8JC{$B-%8Iq$}Ci>92f7To?5 zzD18Z6nkeRdrI=Y>b?Vgr1&gj(*3|HrhR`FOY0`dL?M3|^Uc9%nurx@PtB9dD~^MR z$&cR>JEmC@obxsJz0QJq{b?!RpVN`u>ZEaH45)f}UMUel+txV#Bz5hAdY{wb!w2Ia zgF^J2Z=8GPBkK%kUwoopws{;Xe|xgX2@-DZOT89<($JF7V!giT!G$?P_1z}|&8Yso zYbBit_j`gr%n3u!wG`}8hNqcOGJK|Y^a%9aR)L+!Z-*@4?iH?{z+r2P^=vI; zOTt7#!N=`27^&P&>8wTRi2+sBzSp3*-pXhU50H)+dF{j-D2P7)bK+U_+zc_^eWli0 z$X(8MOVmPd^0HSOKKJM?yqqG(6zPP;2*B~2Wb&iB)zR|KIdYq(WaZdDFQ`1P@BS@EKftayUu~UX)L(4lXN{sc;QzugSNQ|gf9@rhPv^j{yDewu zK0(jTMJTTSA)gB)&fh;>WsaT$lKXYXIW`w|yO*Ww_@Vl_9$IQSG7p;0824?vY>MhH zSUoW&503N(Mtto+_K354S8C=15ux(A;{kf^)T>I96P*uR&-Z;hxLX^wM`F%u$pQ!% zw@hdC4%FXmKP))&3*e1HTH2ZI$R88OI+-3RfcyRA!OHcheowcnd%r0FvrLl{3))e8 z6N_>yh6{jmxpzQj3i5Z~tc*$QLOA|R+ggi->JzbT^o0Y35WU7|?EXIF|10mB9C%y^ zheC$ktnyKRJe{Fj)l&$yGEzFmEA=gj`POzadPVSE^Tv3&L&_*W`2;sN^qlNyDPz?n z1xuoQHrG3<2=-fCxw~!p1mwRX_GW%80#aNyqvrDroA(nf~FF>JU(3$7|rL_9gOC4a3Z7m^!-{)r{|ONjM01&!Hni}a0#RN^i{#>F})h; z>xKlMbq^WMXZayU^ErPBqxpP_p3|oMg3mbQpOohF=u1ZP>2;pbe6HNaXg;3;qxpGXVZFEE-!h zVeJ#_hhdwj_>97uPiw6C>}+T9<1+?pKIdc2=Ma6J9-XpdqUVz6_VVe5 zHJ_uf<`X@qMDNdM7}k8w#hOn+toh8M?;{WdpFvpjX^l0XqFD3!zL_bX&y!g5>4Y_( z8d&q$Lf_{g2tJdr=JNp7e9pz1PbIARY-nWa!{lpnC zLloZ;TR1Mp{vEuTvUv3t4HW+u$T=MwK=09+ApERjH9CLd#C-U6A_qJ* zPJXrSM)lF!ao~ty9;k{R*%zpT;zg5g&+^oKnEgX%biO9qKgq9MIKBXEq_(x3H9_@_ z`fy)uGm3Awi%Ah`Mkv1I{RlKDg6N;O4jy=b&cC$k(;M20AWQv(f|Lnr|NQ4pYB!4^ zI3)4$&R6LCaOI_}5$j9fZSKtA#V)8kw%i$Y^^b7!lJvEqBot5g#J*B5_z1=8hQjZ# zQ9L}jNO#oXQW)KPd~njP@s@;mH8F}+2Hd^Nzg20W^NXk(aI_u0C#7%pmhTTxdrgjo z6-SlBib)z`n+H(;xC)IIUQhuxJHnIFTT%VDl3#RsD?pRor>u31I{&M>^E0{<Z>${+2`O zUq;AG{RE}5HY=+pnxpZq7rtHc34W>e7&(-q^M#|nZbf@)AbrKzt~qJwd@sq^T~@9Z z%KI%Y@5`Hr>K}6{`))0`zm<`bwnFC*1@Gd6#??W1ebf^7iRk>Kn!QG57kYjYl88MG zsK2I7X-r_wXZlS~@GZ}WUl(Vr+i>z&4xeGRbx z;*{N!m!ker3;Aw9Hb7@;@%m|D=)Dh8cIGR@8o|8B&8h7o<-g|=Ig1+Mh56l|XV~hN zL{9T3c4Q-@tW5n}bq4jva@8F%<&9vak?4~97L6Yf`Xzr%6NDJbq?PVO=VR6E{M8$p z;NE+Ml8v0*e<3~xuzgHv|)Y0MS>9T#w$nK*!h;{xtJMssIjN-<>PxPW_u zi37Oa3_0-MaRK`ijsxy7WVbTMdCoh0yuZtk%a03oF`Dg& z?b9*U@pb{Maa_QC&m8Bu4;Zq~;p4s^-tLO^Jcb-2tod=l59YYe#&H4X9oEVCcpr^* zAVbbJyqzBx%*2`>7f9p%a9qHy!^d@gT=0m|Y#bMGk7B(Wa~-BFra42dCe|Yu65sIg zyAd;=A^SN)?oF)EVtXK_C+2EwpU;px1#2B_m&Y8&$LTJH>?($wcX<0#tZ`hxK8N?i zaRGZb);KQUIN)@%a5@ug=f?$d*#1A`0?N~ze3^LK*ijjSJ3f*IAA)iuda8tbsrBh4F);J z$3G`Q^O#9zFQ_a*``>cwxs?JotCWp-@@PFH2JN)Ggd%AGvp zRCOjS+T(F2+!^i9exQF~!b?cj-t_D09kl)udlosN_a1tkx~Lob64l=|V&i=7YuGx~ zU(L~bhlsNoE4_=M z=1Ze>;Yie9NiH@aq9x$*^T)!g7w4km@2IOKF(nY6Be>flm+CM1hSf$NVWHJg*^R;I z`Wh!_OC$LaRvr9oxyHv9>D^}!Ih4YyEi<&ohoSM5<3;K>l*06gLo&K{DE=S{1IoS2 zpvtq@^g-A-bp6p_$8n+@_Ex+Pe=35G_pb3PXPhjDT5sbO!xzx?O8af-I(r3dc{9*t z^&E|dT*jT%i4{=#aJ^*AQA&SsDVkgfr6(p<_^d?Z;rj06q>M@k&S{7+-G|y+V5Prl zeigWCUXfVv7`0E%SLRSb6=>y4t7TE~i=5{(SLbT@9r)q=i$`euOimvkSziqeqt}XD zzlW};%jsxEZ}|kmK5ggiyGEh$9hPqB`~m){^>)C9Z z;*^0J7*ZN(v^s^2+PCM5`GH!{I$aUy!^R* z7JSNK*F$E}q0yD^Q9M3>kL3nVJF+aX&2*W|fiB zqk3Y$jAOqb*tc7wKa`S&#LbVZCd_(46fA4|y1bOUxobf<@fMZOEfnJHI&`U`>xUK=}5Le9Ovu*jo-8cIKVtZQ%yX}aGm#`#iRI>D9> zOOq=h4Tamrv$iXv{Y9ICFBg+e!kM#22B7@C9uF!{EGA7O)$1BOrC$&|r^VHt6_I8M zmhNKbEKvL6?)BLgk#^@F|CaDIMCl{k*%gJP8TY1D*<94VB)j4%+X~4WAt%h=IE+Q* z!wiWZ1!Vke3F7YE2`K-{@Ri{OT7;}Ag4XHmWc?_M>_aNoZbgAb(>~;^y&pD|L3c^?B0`_Z`?SZ7f^jUHVtzQ zz9R*59k*;yL;W8&U*g`aY|?R6-^ORh7NPoS-_ZK_mb8o)FRIL-!Xh|!)x-T_E|9t@x{nLhJ)hIy&}I{@lrhV0{KUr z!MG=HUXp9b^Fc{P)~J3(+kL-hkvdc7XB~Bz`GRoWBiL`0MOv=4&uW}+g6cPOdHDKF zvT)3k>!nXoeF?p5&F8t~zQ{LD9V`kngQDgo@@>fEud&-#0w!2<}b{jm_IOwFu!9C zVt&IM!2F8&1+yQs53?7u2NS)oj;bBI8xy^sj@F%+=)H8b{*2j<*@oGQ*@B7QJ4f%| zgo)laN9zX6dQ9}5IeI&KzZ}gP%ukrrm{pjSnCN|S^#08EXbCoYpB$}AF+XCKV50ZP zQFab`j~q?({y3TinCSg+w9dms?~kK(4kmhk9IfADzQfGMe2e)86TLT%-v1RQdT$)9 zvoJFm5^~J=b7k>)A|@M?z~stcJ0=^Gz~o9}J0=^Gz~o9{J0=^Gz~qj=c1$)VfytG` zc1$)VfytG?c1$)Vfyouec1$)Vfyouac1$)Vfyoucc1$)VfyouYc1$)Vfyoudc1$)V zfyouZc1$)Vfyoubc1$)VfyouXc1$)Vfyu>x-+_b4#zbod?H819{NFzue*^om;JDso zKtf`yC9>B|m~0N}U(D*l9VC$Ey2fSzSj?1Kk^Tj{-o(xWD4r$cHVXPLgN%i@mh0D|_!$M1OI@6xQ_1bZ zu^tp35nk(_Svx~m$A5Y0|8%Zk9=5yzVASI)#XXJK<&LbZf0v|AwAgf zV!##D6jDEK*0DvpZYXxE8`zmesLXdo*VBl&%O@%~z$UW`sq256BHdFGx@Z%aWdxCe zOHuquL|r|eu^DC!OjbSNg5qIx!SRyGR#=@LY_@Ha9nwj^Qm<`;8a2~haUxWG<4)Ep z?SK%@^^m;lMo4p06^^(=deiruqpMLoPZaET`0fE#$r}DErcw1f`tjn9oseav;Qi?# ziuZ_;=0Q&{IG`oq;U`U%zvsTecyEyNnD}+sZxqj=Kjqouu+FsMV9+0~7UnVuGrv@{^MHyx9ZIn+hK-ImxE> zUzQ!<1M9qCr+FlGej@&Q?DW0REx)4e7EtwJi3RrUg$bcL5%Zj>`pj2txw8+v#b$Gk zy`<6~{cXR=7fcjJ=v76c_>@@rC{trUycT@?Y8rv==Mze-Y32K2tjc&l%iQ@$Yn^{| z`T#uJIB}k4rZv(fSyLDKLDA*D&vPWG{Lf}(2>ZjnjLAn$TPgo~bZ$|GKahj#cI~O%Aa(_Mt2;7XZ<^lZ5E^I7cwE^MgUw= zdFB@ENcmqxr1>Nc7@k<@@_}WDG%Kcb4+lPq=A7^yLHUP_S#lu<_BrP}jhlt89}+(w zoiq*vU(E@-EwZToou;$%cpzkMD&}3@Oz9r~rEP(*P-J(_(_@rgo;7Vw5L~j9Q%W16 zuKz{!kG&QIVP6fzFVxOMx>QbPI0$s+%9J0Gru@Z8_1EfP2&lhMGFuV7XPuZK$9ozK zJH9*dzI>zV^Q5m)IRu9KR0cmfQ~fuXS+y$!l)TASbA9Uk!T3;Veh6Ic(6EeHhT?zX zsD8=B!(j1jFmYv^4$|fsCC3iK?Dy3>IG${ck_%Jctd6^i;wR$LynKhfhpQ$Ob;9loU`+K2QHfBN?NI9sI87M580kQom_NObN(q-Uh$ z^y9rH#%fXfI~N|_LnaLfayPFIYxMdXuS_EFmZ!-~^LOK0EbPNL$+IvtxSUZmado%~6YDcv)A-NT)vQjnBw#{IEK zyGol5d6L3P*KCq!Q}q+q7O?gtkNJ$2TsM}|1uOE7d61vJXBZjfqIj5yx*t{OPKGRb z)Y0cf#e4R8uA|+_$Zs6^tY{S96Kxr~>vxd1QjXqSk|dAxG~brQ?c~GNGQ!eEDBdNe zEsgKlM(z*0f9SRb)xX(`)=%3;u0B<9_rP2#9xT|R%GpZpVD%TXr%~fE|9ZjOE#yIq z;L6C(aY%~~2g`0DJ+_pX>fNE@eZtRt#b)yNY2luE;uP2|BeyBp6EXCXbU zIJ{*e+3&I@Jv?YJ()JI`jW?1bU#29gPNl|+eW$`_0~uW-{LQSL@`u4UelOg}#>dOE zR=hy*G~p^ZM#PP*Gd{bk|KLcZSFTN6w4ThJy7={#UFdv?C@8Z(>q_?K&U_OuL#6j> z%u974Z|#-&%;FePcE^Fa>&TB^9-Tivohm;`bX4gY^2KqH>p9ox@%cJ=(`xeQr{_0! zSfTStLQ7}C7iUsQPh6zhh^n9c$yLECNsr&<=7(*m^9i=aCWRHG+IzcSan~kM`KfQe z>PTLEWE<`Ni^?xz);5#nWZ(+#5x0G)`ovvxBbSn`BmF(vW>EdfWjif#Ai;lLR>nqZ zJY6l0KC>gIJ<2mL@2AFtvw3CtBJ$dS@N#PlYJB5l)CX)yFLUj2$G=nl?>ebeaUNMb z#GJG)|>-7GRKZC2lOZOYDh>07}feGETO)!tZ;j&#;Z zB@0r>SA1SmE#006C+tkghnMWe=g&mvX9P#SLrI@JJZVOG9+rSuEx3w z>k5YKa)#VetUqF1%#c&WkSN4DAL~4Z+#H7N4_Lp$IveXZ3^}hE60fk%!a9>7mt@G! zz&ai4=M0Hw3^`A+PR05$){hu+A2MVoWBmZ@`wWSD3^{kOzKwMvL-tLE+<2^SV0{hi zs|<-ahMX%{U&i_(Lv{>9ZWPuRus+9-bCw}-2J6#UM__%O@jLD{hHOmERlGe8`z0nj zmeHIm*nSz?G1-^!_KSEsCOd}FoM>#1!gfsd1#CZ$w_~!;;q7M`a?fBpCOZ<_Ph)!o zwqtTm;q52!c1-pOMsvck{W!K`vcs_b7~YP_K8m*=VaN@|c1-qRY!AWqU~I?a1mW$0 zcsnMW!)Q(bwjaWFO!h&%-5+nqWcx9ia{$}-V>>3>7u)w?`(B1@OpXuUzK0=!$==Oq z&Ms{C#&%4$7v8=TZ^vYNGMeLo?e5r)$=-qO+wpcx_BOnID?{!UY{z78#`aCvz7g9o zIUDeHH@qE_y`Iq=S8R8|c1-p9q@L0yd9Hm$7s$HY+sD+nCwN^z7X3NFl1wLZ1MK_3<*sB@&C`b zfUmjeo3vKW?H7q2ZR&i7h!Y^Pt&FRmxUXoT&W|WvXtllS_$@av>U@SEgorY$=(p=^ z7pYR`D@2ko@yY6X?)YsXder$3u~mpuZ?&c6Q>?u{o!(2BXtJtoF*GRrVME!=MTk}_ zpU^K*k>v2KL@sT(nign8 z>2OhYuhr6!Pgifupw54Yr()bbD~TT?l1{M zR2%_!a;9bGtB6wiw-j3d!sN6{&Xy;aN?=so*)NZ%Dz&TD+u=6tWWx_qsxzy z;|RgLy=4~P&zn*9CV93nc;9!gAMlt!X+gz0VHkVEc)P{-NtE8G6ej{ja*MQHoTSs2 zD7%V6hsV!`G6{NrdlfA)m|~~7aa^uXxBBjDJ=*pJ5( z>G9sBttAC5HeL^1y%nkb7wOhX!Oy-!?*_`~{xa8#lZJ=V&+A26=>1Fd*)ovdQKAxZ znf9L&140(`?R!K5-hZX)S2KYt3!A^1XC-f-+xKH6TMoQe2o-wzQRml0txAL(@V3m> zy0VSBenJe4>XCy{@+&JAM$-8!soKlKyqU=|ZA-N&yTzC!d5D{q7dV-q z)~>llM;B6how}<6@LWV3-)Yk0bykC`09i8wmWS1&?;oKP7)>ojD2b7O)As@W-6w*O zAInh$@2C}qIzqHRYHJrL!qx3*l0j=|?WJR)1pc-bt8@nF@p`Enp#^tLV4#xzj{C-a4jszQCimbwK+P`NS%c+2Fp<8AUp+MO)CV8pA7K8Dt{a2#z z+oAbqTA%`Vt+qIQA5^DwnVHEbP_(PD&K;!F8=7-Qft&ql;aP*hRC`}fsT&1>GWRy! z3_NcX4A^tjRRJAQOaMH)SxduH^EhIwmC8-5+5$4{SSuL?PS z9?yNo(*0d;nWPFF$-QgxxpaP4L2eAhw->imdJ5C|&+-}rKm9BojQvR0r^T8(27ZmX z(-Qktin6ELXsN+tOP?IATzY<%m})=gfzdQAc=zU{?bS21oiyI61wA*XeE0Z3k8jbWC@rYW*NPUer~RqT zBwGvaCMPH)9j5D7WZI(z5!%nv>J@3-ZKgFA(z`hO<8{&fe1aooj;;syyC_JsYEb^g zF`mL13u}*m@oAnzT`%QmPfZ*P?qNC_p9H2LO)Rh|9}5$2CupRfrsucMG;wW6`ZjjI zjt=^}Zv^Ms^l94gMbo!ne=>Ewk5fEjt2VgJR;;|trTw>LW`s8Q2sEoVE~V_~FI{o9 z!7Qw_df!26J>b|_^=N}&4txBMsdV~4(9(e~`j;-$C(`AGv*+u8`Q(uyq%@^Dd9!?V zz-P%pL*bK@|8taPC+dJf#x4uzUDWk5&RUyt9Z(kvH(qE-&+lDx2wf1pclrG;4&@&l z?pzaHm~3g<9lVNOpB3i2>cUq4G9fP8=(vJpQ~>z>8JXGAQy0T;jsCpxDi?O ze6L&BrVGQ3ej%&`>iRXua`C8f;Nu)`zwbSDeB@kNGJhOA4^%WVtfJN*j-b8oI0)XK zp*gqDn9@cLapPdkbg5S}l_w%iTv%E#4$QKqull)>_8;NpgdQAnUg)nWEk^CX+tEZ1 zR=j%tqJ2Ew-bAOBdeFZ#tMiyGU0;orN0D8fD=VQ$`|kzkr+Oe1vL#zzfvO*&xVlXb zq?K&?wAa!8FIOb1LUzZP8QgfU`vTeXifTua7S(QtJ<_P_b;ROgawPebynL}(fz zOFUL5b1^)hnlmW7@26o!ve5Wr@VYD`N~_o8 zE0Xp2jJ1|_)b$u5uhveH)Y<2*DUb`tRwsr# z)Agxta8V$YWT%w%D$Jwodm1MxkoB{NP9D*v%PVh`RUmu5>vRv_n@`z2nrh|A^G2PL zb%AvM3p78FCzG9`d7nJ#{yEbeAWu3t%B>sNLzk!9Vkb|^E2fIR4C$l#<6(=YJoz%C zt9Dxsou1vwlOq@2p4RO@(~QbLri3D2VY)2Z#09Ca-SQ#=wH`MsoydPA3!^=U2JQzB8>HAak_07)MQ1TDN`Dlp$Pa0z-NcLc=%da=|c!f2A1Ub_5(weP~%~X3mxGKWRnY>RYEiX{(e4rKhz8h>?pfzumib)Er6=wP}ix z(N0mHq@L61pSF{tq(F+bD0eSi|6QM5M9J0-SHHF-)8!d<42zKGr|5}~%B1ICT}P}4 z>0PMsy|$1}AK3{aj}H7R+y|l8LKNRLS4@$I=cddNtuO_p9Bl_DZQo} z{k68hg4=%Q-01cT@@j?1xIW!E_x95MlfVlQB5m9EO*_4m-hXb7rVu%A&}I9>i3U{q zh8|Loygy-kr*$RW|Ngx$g5(I-9U@JEw0|q~4GWOt^mpBqvZm{s&=)H}N~AA8o2E*) zU$oyvfRtBwGbA{V9`E!0!vxu=qp^+5(V_C!`Vvc!Gs9}um8a74EAa~u*S9sD@H@jH@u9d3N!M?ASHQ1~Pb?>! zx*v3Z*mRRWGZyDR+%dzEp5IOAuX<%DDPNhWpCU-*m(2_Kk@0lvxw2eG+J6#z$e|3! z=xcAXqv-h&(mVV;V^72pA$A*G{>nc1o-wNb+_|`X+CO#s0|qlf>yB+G?Wgna>?glv z?5{19o)ks*@7*uM0~v3{_KYZ7PLJ=_uP~6&K6;kM2Lrl)>b{a+GY&K-ZOBhtLe=N& z!0?w0ztHc6Mn|aoEd=Wue94#>s>1mT<$pe-Z1rRh>nCG8JehlX1+7Pfagn{es%P3uQMb4E_A_p5@>npFAOKZYAK z?(J>2-n@yP4<^{5U^{D>8g)6&D}nh*6sTYq&Hc`u_B$>s;FZdwvZUX9(mCJ)fRA zmEQmNa6!fn6_#X+FFhW_@8J&_eZjN6moKH)BhK&Pw;9g|8xGfRr27LsXqcIipfInT zyM=Badw4iC!)0rM^f(c^KAhp{&CB4WDlg~K8-P0f04DGe(y~WtQB9qEI7hD z{cwP1oAT@)@O-y#wA%HEbml!cJ+SGK&y9xNCs;KDpA2?*^?)8LxuN!Scslc5oE{hs zdAKkmbUiD$|IK@=D?Kn}z3C|5`KR%Fa(X~=ef0w4gecaxdAlY==JbHKUBk#~jR^eS zoE})}_gY_N2Aege`1ga&KYGCL#gbQD7k8vP(C^Xdh3OYPR3_Pt?C7dJKbs9*+DEn`aL_n;1gDsHY*}9{qu?N zY2U+oVTbI6LLIr&>CAg~dZB5nt>2>6Cs`$HghT3{_k!4f@s!YI(do>4czS`g@fzVN zaD}B_@l)Hrs~3)^`UytWo=#`p%hLyELly-3ygk7>Uw!bjt!5u|#h*QU=vEMZPfs80 z5_$XNP*OAt5+2&+IrPDeFJCeo|1b9bJf5nrjUR`%P)MdUkg2F7Q&Ad@bDbomR5XZ2 zLuryUs}xB}5g~JtD3uJ63@7JEh72JxmpPPqIEKh?oqhK9`P}#Y_4+-}AJ0GEr}HZB zbG`REYhQcqYpuP8y{;?$F5$PQ7b@Fm0UGa}C^swz>T8{Q;o1yvTVoJN=lJpIh23JW zV_L;rD4vy7MGi^5@KkbDS&hItI>)b1FO;sU-nDUxC&gHe`XZ*i7jDXb-5{KMhVb*# z2Te}PzMSZHp)9K~7`2_>2lhO3@3#csCH(&ML4@f_=lP4hDLo-xhcb=(Kv8eo{?7gP z=y|vwpgz=})?xfy<4d=y;5`-X)(3Q+0E+v=$MiwmFHj#e449X#Y`Q>ij+~jHlFwu>f>%v{;InaDaRZKT)f36nD8sq58W1?iBHqd zQNEXycPl;Z2jjHjK8w5n!p~4YH0ZR)_^rQ2nelBb;7v_GXxN>gSGW69p5uOp`k`@; z=@0 zmk1sAmgZ7U4WNu=`<05h4?v4_;J*5YPK2K#bbO;8ufcL($~!&NyNf;zK$y$%8}qhM z2){)GaNvid`tY+L3V+STY#4)Dl-blk0J|pAAU1a^IH&|Q8oR7 z7?TBp)5nh*yPl=1;eL-;@bV4?x%E6rclI$FzBbMRmXOOrVagr)dE5`uAOu{wxsbzai6+G#1;QRLDj)R~)dx}7kl|SV+?k8yw z)B<=qFU@kMBfl109qEJcb?fY61F;aoZ_*%KzdS2t$^l!7m?U-AVxA#T@;hbWV(&$t ziThC+g7W3FN~H}R(O+lF>q%}Lg5L$}o;sJ^p?BbZm4+aNRT?yu6+#cNx?7ojcL>(J zweS1j6F~S`8iGYzT#S3#d?{|aZ)Yzr9DnrFXn z?jw52v|QVs&|z5qN6i-9)T>&%-rjF zL4;qY5m+`hDD-K>lX9i6gmE%s1d6O%ay7j?=o~*!BXA@CfM&rHKZ;eN`;uuwzd@nN z(O}?v5dAmq_vtrGD|c2u=x9M-W7_O~*7P?to=QorJrhjdi2H&14QrxyUEgkUfxda_ z6ZP1L-=Ml=mr%**V>-t#)NgQpta7DD+lj(2Q@-y*?{7F8d=hfU9@9B~qDJA{CPUXF zA~z^kipCGUqK$$;*3CMt4MBw8s8LkEHjQt+<3)MfGS%ml$0+FTcicpeIz#x88ii{8 zw&FbQ3zU(J1G}f!j>6eTPCM6DxYO-%zfxlmeC6_bEqXA$*L4QpZM8ADbnDTXtD7Ft zIew@+loo6#tu_W;Z&HL2GTty>yuebdKMtF@?=0FD zx6ze9Q1337yWp!Ar3&{`^#{BagXhQxKc@E_y|1#V@DI4X7ES2$4yJSbR{eq4#Bi7X z>_-&8l#^OZ7mmaF`!g63PrL~~R^xE@Nrg&%NdQGWE%^1=)p6ioF||l6^%0%p*J>PO zyd(N{Zn{nBIpeYPL&-R_Tt4D^{uk-@^B@0u91jZr_+$9b{sDT9b3P6vE<1X+#i3$1 zFhY6C`A$Z`rEMvvU%j~r_cNWw-!nb~Ck`aOAC8Py$zHEukbb6!{2d4!=OF1Pu#S-H zh~uOmks*_KV;mW@?U?*|7U;N|Lu<#P)(Bimp|^m{*XET(1Gyh%s}Py zZ-1`;?GKuL{NMgy|GWIy$N&06{_78!g6sf&>i+se{?B*>?E3M4l|N+sHvj9-h=}r? z{=>fTFX}(OYJd2#yK#{d;m?`l=k4DK>aNWa(mr(xIDVhg|0kcu3rjbwtl9%oDNp95 zJbCp$$2ocZGvD*?yxHG_4z1sI6CO_dPVc@A<>&dJ30d^QzADStw;*V`e2vM4WVoZ1 zw}@}%9k``GdhwG|8Km%~Ub2ZD1Jm_FQg0aP~W-M;DY0o3>LiauyO z404uMRQ?}Np|PrMMlF{mOwE;+jgE|gFqM67sVkEqV(`v3-fJdAJ?VzZ1KyDh-)>Im zLF)bV@#4MHG+$2eBS%!$@8o(uAy3hhbnW7P1Va(ZWtEq5(Y(c>_#+=Ed5K`MYUzB3cDLJH@|(Ma#r5uS@v`rHV@r_3Vg%QpewaxJ22*AC173d*hiFKADgdesiu=q7TqqZbFh!2Gm&YU%_{x z1hfM_OK-J3#a@3vpKh>x<+Rl6{<{f1I6T^oVB2SGJeohj8?82exsdDAgnYnWNLzz9 z6I6pbf-2Djsr|>6Lx#QS(7Z6+x3Z%FDpIHHJ+nUz! zQdx1oW7m2 z6RXf1Cw#L~S}^}@KU}}`V!<4~Ua;95y2E4604&2^e$$%Y3-+ZOb-C;ZK-wW#M%23( zJcr*YC7Cxv&$VE=%t$g$NjGHCZP!&GKSTf4mHmD1)>qjI2l;3uf8aT_P1|?+guJ)+ zxleb#l|3~xO7`U6yI4byL zHqFE~d8=3*M*F5)t8ge-g7(?w+Ho6&^Ya{HjUH%iqd4|Rz3fmszaN)FP3*->?|6m{oP38w7>I+ zeE+AtCC`Wb_opOj)Ar$?8WY!X+GJ4hXOi5+eGqkBSk#vyz-S9;l6TwtilMq-r^>7u zEUJ;u?D=obJ^}jHg{f~#>eKG89j>mkcrCH%m7CKJb)k6!xL%RhT|tb;El<>wjiQXq|U6OOnwh^((a8G|$JWoX~@F zJ?sI!XT{!~a^6cP^p&mk;F2zzJ)v(}k12Q4YA(hp`(@#Cu0LZ4s~mOWP54EXv6!c} zZ$k*I>diNrv-4|ORI*lo=N3oC+pq`O-fc|k8|lCY9~^B#Xx|BquuU)1Ol~d`SRcNd z(PURyE1T#;HMw%JeCpiw=sZ7_T2ntU%zw&XIxdf|uj49@`(CQm`N8qC%5LA-BwOFl z)5eqSq~s^`bvk1dQP(Xzp)cKF`sD}ath6k>yUt9>FviG=!*T5;_0;8&l1e|%1VdNA zmodq2pVDGd+`&@gGUI1fh}IXamM9T=H2zlVRdLi=lB9Uw^{&weFO?-EH;1`Wi?0Uo%-PIiW9C&7DUd zc&1J0yHx4?xy`&CX}32xo6J-SM*E76?Oyb>oLbhS(b$FQ_=c)>`xOoegRT-)lEfVR&> z&g^6|>bHbxhup*0gK>S2TNj9qas98pep_Zqa-9^N&{zGUjtXNV*Mz<~a;uU{4>zRE zO|?#Sd*#FM+UkDio^cV?Uih3@P@F%A{*G%h9Db8_KBRC#!TghqXWg**v3>~k^UbAW zb?h>(U0{viTL#i8RftL#{FSlV-P&)vNiX*F%3&5!iu8Q+|_ zMU|!YQ4_UGj|C(tBm2#@5&sy0mpo2ln$X}d{$T^b^MB|8so*!^^VUs`gN)cWHWG zdcX94j+6Ot+V}s}mnh!}{U#}2Dp9^LN%>NV@`Xvtmr9f`Oj5o;l<$N+Ojf>x{Z3rx zB=$=s>=!1nUn*h0Fp2$A3Hyaf>=y|8ov??=?3ZXCCiI=8eV`KU15DCBP>J>dCTSn2 zMEd}fv=2bE4-@)M);Ag%4JLWM0r7mB(08)u8_|E5(07vl0}%ZOn56$e zCHfCAN&kUL^dDf7{sR#GhY5Wr>pu|vvk84C>7N17KZ8m7XH=qp29xy9s6_t^Ch4C6 z(LZ}nwr7*|&xrmnlT0^B|Cc<@oTUHDB>KP1N&3G`qW{aBr2oqx&rcxjzvKy#7+)|+ zVv_L%lNetxCK+EaiSY$vlJNzT7+)|a8DB7n@dYv7oP2yijNc}%Z<6sFgBZUtCK_!z?fwIfkDhaFeaIQU=Z^Uj7jDn7{vU;MEOoO z|3J*|Oz1nw{0@Vd-(gHLzr!HrcNmk*?=Xn@9mXW{I}BoeXQF&3o8KYk&nEPpWd4jn z%%3qPnLlF?^Jk1n=Fb?!{261C`7;JFe>PFRlg*zI^OF<$PBK5qAm%3-lgv*ti1|sz zB=eIDVt$e_$^0aPn4g@`ce43OGTt7EoOaEQh`)r^-D$dbygdvfkaqNFatr&tMFRtQ zH$Cmmn$xuE!XnpfzytENt%=dVj}y-+_Bdt~Uy3K&O9CA^_)pwEjvPwbg9DL{0M2-b zJxR-WD3UuV?c<*N@aeq{@pS z39ESokNY3?Kd`VKbot+IeE1y*9`}13IlZnPZtf2X85pDzJnnDV#qI?{2zI&nMPiQt>qo%lS zC6T^|ozKu+&z~Ua9JcLe#c~esi1VwqbN>RrvvZo}FXkuGla!dwH^)(M|zW z9~*=^;PbUNhfmxg^~d@AJvJRserM)ZV>_}O2H5G9hjKe$nY+ZQ(~`=BJ~*%YO`#L` zE#Ir92$1%`VyCCc*>{4^fSs0o6RsuXDe5 zL7PaA^F`Cob-^7wtTI7ZlSn_r&fhi;`I$d**ov{}6H$*Gab9^Q@{`B7ZIv4PY#ot) zn4SI@L#Z1s_DoADVv*&K^9o0|q4%;k>`xLZ+CrosVW2Y4!qofUtb^JJcRdH1)x|oZT4~@g`Y3YU9Y!#=?N9Bn8asH0aa4*pREHJM!B0 z1juo664LKr6Tp!UpYP23HaFk%sfm z$uIlBGEd&vTUduEADmb3OX>rysz}wJrgJ$w6Xy+oWFh^f_x<9tUBuzBY3%$fd`kP^ zn5Ns-&LP4cXgD8*HT1!TGTTgRjMN|JgO_%p^~lq+0u{Olo{96v=8X2i{nHXnn~zM!+FD1v--hD(VA&rNtBx-&WGC0?}rQ7&Be4vqTVrao@T4k z5AQ^c#oC97b`p7pK>CNTTHOy%njK1e5>{}oi-z-*Jl%d6Oq`kJSWem}&L3N1*bjU= z%ye_N6ZL|L^Nzdr^~36gg_wIFslNa_|Dvr{{U8zF=%ZFg+CR?w%s$f(^b9ZQ?;T{j zg!4SHSNlQp$Gx)U8;SHxoHv-~(hnIGKmJJ4yS&c^|ix129iD{8M2YX`dqO{Q0I*2S9b%vGRG3c(G@ue>)%1pK-+bRW*ADKp@BI`I%R1 zIeLcTd{mM70Bn%*z{#-QxZ?CH|duj=NXgGgNtZo1rMlJ-}*Anf68O|qdXdZxd(yJ~TND_A9 zi1W;2KL>yrrMYY@mDC^S^RIRdfXeXAlBK7~^2d1vhyDSu^YI=M<01MRbvQ464!!@8 z_w~`KTf2zo6!N5l^sm|T2i3dp-8{FnB?MY5EfNO3y%ca!``@#8-Q)O8YaLjINzkI&4T>!EqddZMhW}DdEKq+SWqy+BR%NfK+FTo zX6rxKYy%6-Z6D~XM-%-PIh^-Ds?UP(fHjXQGKlt#hV$)~TUij%yKt6~m=LFY%y6Ez z+lU1QmseB;o+kCj`JA=8S#YuHXsEge@mveV`N%n@EI4uTyWnoJelc-gq-{S7idw!j zj$bC)+d78z}oEMwJ)?ez>VHR}%?u>Z+htwbEMdXgLAlxlD?f6lVNKWJ#mwNZi(#d+-B zMHVc*H8A72FKItGPZPSrf?pOrI*YXld#l5Fvpd&Vu$S*sQ$Z8ie$HjxUxzgBLWhKJ?aemc& ze-_jZx%oK#BBa!=yw9NPj`;lbpkG+mZ_4M%3gn&UJA32;C z_fKR&{o0)uV`;>7(Quw(pN#C`XO8TkGohy$&ik06-Cg$A{6yC>$Z;{wE2}eD@QiX% z@OK0890|pF1?&T=r!hCwY%>;c^kL$>+oz8#@cuo%Ur~x|e{kO3Et>`V&MCZd8z9OJ z!`~+p(a&YUtHZZTe2j^HogB{Z8qa4z%Ik3TB?e@_1?P{&6tZA&iN}hKIb{2T^CqTW zSa8?AN;3Bf`TWIs+E^(I_PqU`7Gyy5V?%LXJ*b=o?p4EWk5&@nK_<>qG^$t-ddJA? z9i6bxI-Ix5tYLxH>8NJ4S46pCQta{{HL7L7^DUNDdn1YKmBabcih36OzM|r{j*INK zNAX^k09lpj_s=nSP)um3?0^N1T^4XhZFiZ2y$QZ3{VkD9#JM z|Aq1?w_b2buAfscm^dG)*vSIPSSXk3ozF>Mhx0rh-7N69b>iT-BvC$?G!30)Rd+9% zk12e-Y2+5EKh7H%46q>3>G{Ij4#ablhV#3g4zl2hY{urorDXpN=MN7IvtX^1HH$h% z5vsl)lGgUG*WvEde`kuJtbkIAz2SH3WN5Ds2#6_!6w)C)PB zx4%7i5E>6^ZYj745;=KQJxk2QoO68oeE!qF!@DU3J!O(2Oiswto_LIn8VGy+ajiwvrk?p4( zZLSJ?oo5)P?H5N=qYo(T`++`=;|`oJ=-YVB^YY|dR%hbyQ4pfX$7j$6SK==`Kg4IQ z5LXA>N9=5g-=OskactSZKkFCftc??g*kAtH-)ZvXTVwu669rq=EI?ln3v(6^xQwpN zq+l5_i@sUJLV&W&$)ls46m0(7&EsLQ@X_hWu4SF|6ztKm%L^J~VMOGL+vuDY3MMU* zq$eK-#_qF2KA5*tFohfeYs)y8@zlH2?hT5A`Nigf*V8z#{CaW4F9{?!ON=Hr#(}!u zn8Y?oB&XGeHORjK{`B+(d6;FPB0qd0l|`Nk@o-?bv>XWMP_R|^b~6sgqxSe(-%~(wH&?Wab%n>n z^`$|4HN7amxpQX7HOIpeb!v>x>pTkfeDS6o3lrd#1oMXeqIe2+a81swBMCsApL<^{ zx0QmOvwn~gkpM?BEG@2|DWqW4)z7<|6X2}(%bHxr4-`!Axv(ON(YluvXv0(gg@P^a z%r~<_FwI=bQMSE)3iQmbTkoIYnMLW{Q;G)hOpR!=ZR2L6wH5WRWk)k9a;3HB@uqz@AH2( zoKL~>cSegVz5_{d(@O2y^Av0iEz0EBJ5X-2p=p{SKaa6L6dp&ugX&_bt{z^LU!sjv zbL%_!)`b}_l3>hA zwt_YuLBW)~bwqw9f%)rCm6zy0DcHu|-h)cX5OYe=n=<%=g56lYHs(Y!gih@<4Bdd@ z82jIl<$9G2lrpuOku@m&8lmuAzmh@kyhqxc=PxK2A78A1xeLv;VWLLOt* zDG)mNOFFurmz3!GeQEF}!rNxC0=i#ysmn7o7;xoznAoURB?a5({)~E_0lda4>yDQq z`^spZM^9kDG_yClyDX4?GBfAii_GI0$^BV4EIy2DdX|uiepnt7a4zqkF2Eno2tG4G!Ju zlSlXWyQ@~#sdUJ`H1$T*3}jzFoLtPK)8Wv9y7kOI==|0u2f4b^;eJdojrRqLgXnp+ zC_?Q6C`7KB+j|iC{XB52bDQl4u#lpgD0z%iu)c^-qp=_0h14~_LxpJ+EG6q)OwR`x zOyRT5J>O5kT#x;+TAl&#!W7e>*Q@>v&<~Z^E676Euk>^Kr4=8creMqy zPnK-Rf$idd5~9*kTxfm4l07atu*YBh+mR*cdhg%A;Fg^Of5LoP1a{?6uornj*?gbi zYhijgxDKKF``Uzm^Cy@;&2YQc>QM^zM~z{0?-LBHm2NW$N7u9YKtpK$Coo=fWKC&L zFFJ1Yl{F(5y7ruktT99Fsm0n?JGbY8=B~qY7C%GxQ^4fXJI`Dway0$U&4uz4A2L|* z1;q_d?*H~;C;I)NYv40858myX`)H~iN}sjQV#e+~c)Gvkiu{d1)P75Ra`(-HWptsL zerf1_$8Ebkt0E5?FPYz(lZ47=_*rbYL_UoD?3uT1HM(B&I+L~g@*(iOr|IGY$j>D$ z-@7t6A0%JrNOf*Nzc=1~!Qp#8%-`vk;b?-+Cu||AB3A(G->mVPR*&qTDPrGXUI04L zl$cnB-xRFn>Zg#W1+diQ=ZoDN(evq4#f&4(1wh?BwfgQfWRK0K4=i8&8KyqDkLg#U z{EI^Kryc(c8^_8-;>%F|sQZ4p`Q>MjtFHPSV1w@O>iB(m?Vq8I|DJu*!EDri)5DWh z3*jd9wB(5>R9{tN55?LR!m^#+@d4@R`jbqa#Jnj4DeuQWGpteh_4!?Y*Ix*yRqfu? z%tFT(YD_&muLvHw49$Fh71PEv#soIzY*JpW;B5?2KlB6Bw*T!T7 zh0TkLU}LlJl<+G^zH=Zec4jef`G!7Pd3%O7cDicwOygqMe7{fbjRmhZwpg?Oj(;(z zz4bi*orSpY!ITDY8#yjX3LM z3E0+|3jI=@u8lpr94Z=90=HJhFZREI>fe?N?(2I?;Kb-mAIeohZESfc#cf3?_;HtK zyg!W2Cs8WgZdVGe3(V)ZR-@yzk>i&1Qh2`5V_*MjK5eW)G^TgF6i)6CDbaIB&+np@ zx`FGzLS~3SP1GUO-&qmqvG?{@$a&&=l2-|(zgsw@k@pqcm6qBaS47XRxQ(rggv%f| z`>cTVWgcy8O;fhU&N8?n$}MpF1d3zcm^5XdUm3&&EWXiPiR^FfeBMXZWiaiSbBK2q z%FiK(G9ruO$_MqWnHh|ZzmA)G?r=E>J)P685sS({9r*cPl*85F`KMBKPFtGTxU)6jm#-(fzpqZ3 zDblOqLCtu4yBMlpn$FscDK)Ug_8#|?bZ%{Is$P4yFaXRj7J}j<1a_ z_M+9ncHR5Q50=c+#zMxrwbA=4Ym8zK=|!dg$?bx4TFhJs)QtuHSaG9+FebEK8T6 z>#-UOIhj=t$G0cAa4iwn#vW*GzCvd3aS?6ol3M)X zmkp3MB%QSWCeklZ@zeIf2DsovU)J=EE#Fd0(rpA@F}W0pMbg^XyW4VMUX5`4&-!K4 z4AlcC8x}bU!m`+>U*3*p2Us~>fuR{~a+$rp1C@uJ>pI%878tlSFSY19s_%PG>Ay&80p6a|hQDa&cx;vF&snX| z;1E~H;70AwG%jaBn^w3`P~;Ess5};Wos`IKg}ocLsw_T;^byhBH4nW%vu5vyTpMjk zR6Yah()MjIt!VrA(dQ_x+t}L#rHVEpO~bs%BSUu^C~`9gE-bDBfwug$$2*2o?91$lgG4PuqW; zf7OKazIyHMay^8fMh6liQ2f(Feg4b25mH@ty*h~EpnkZ(FPntopx%)7cNa#edA^Qy z7{x=qKmEhrBoq%-QA8@4AK@PT0#Q>G7gby$;qWsQ7q#MQbX*ULi)zmoIJ5@gobH{g zoltz#?_){lvQd20DSi>p1rWNY43us`aZ-Wn*6+J0PO9}I)pR;td;(EKhqZhu5D8O2X^xf6J=5XDa&>`B0yQ2f+~=C@C>Q2bQO*-d#< z5t=jy&!3gu1*=xyw4RURs9K2~i&~1}sK!o}s@FhqRF|wfEwBc~QSH02Op%J>sEWxf zUqeH2RH@@YqoMbn7U9mACF{#?sMwxM>+dDP0g=!XxdF)CF2ASJ3t*c0p6% zqNOScU2w^7am`>HvV(dDqm-B~sM%=idj546^t@c|wCEMmhc&#qD6$K5BzmLIJVW*{ z4z&W|U2yRZ*QcN-T@dB8^@Ku57qooPJWt4O>fJ6_{!&@Q{&p7>)dZi4b4KYL6Hk7>(FIev zR`YQ?Ap6y?p~>2JL3*;`OpVLveK0AwM!nbtzK=KAuS4&F$$y+GM6pHr9h$DLda4V~ zJJ;3DIf3rG6W_dHD|8>fj(sn-MD{DAu_Vl_3-V{r96WxY3*wzIy(N3Q;NEiMnRUip z@T}fy|NWildf}RkrePN}R8$)m8z8$7c|XNUzY8vi?3C@@fb5Zx{o;a77c5JlgmhE8 z;E`h9sKr`ze>-k6^0m-=X$MX>sc3eAkfHlA7j;w~f?qe4DR)7@niWpcOS(Y6(pz-@ zLUezXKleSD-vvKolNK_hyI`A;Yo)Hk>x7}zm*bNLJ7M*#8LM}6b;3fgmK`}iIzcby zX`|$K)Dmx3Gv+A>XeL5kX_DqVm!GMtuMW}{y4T1<|ro{NIdTZ zTFap~ryq5K))NW$C*GY9vN%3D+O-qBjW>$>IdnpcF2!!|g-$TrPh$?9=!7K)HfEhM z>xAhBw=FYwcS7{$3$}fmJ7K-)hmXIZ6MkVPTHiH0Vcw5jj{}!49(7W~}-TTItud|e$dyoSfQrlA99MZpZ$vJMF8G;k6|?;Xnb z90@%2z5`@c^u9ig?SMYrUE^_2(ff;gMjHKmJ3wj1ldZd5J0SncOWvPXJ3zR}x^y>s zk5Rx#<%Yi*dXZ&R;!E6)4lsVG>-I#q15WP=K6i9w2kh=?+03oj0duL0lJgQBusq-S zbE-fG+*o#Kr2Ka~C@3wT^{E{_FC6`saOFp+lpjU&jUs^j@D{Q=88Ql(* zzm~4-dfW~@=k+uz?ze+T{ugB*^qhGcarestn|7E*2`;;NpdIXMLt7IK(C=1yC#J4# zhm}g1?GKdN;l2IW6|2#6DwjKAP29A0*yOS$YnBgMbKN#V-F zIL0sNSiS##>(gIwzl>_Hdi@vhHmE#!x#t&n9^8M9UF}cU zIHI}u+}od^|K)O2&fTA|aLUVX+J}BZ7w`K0pO^oHob8c57kGa{*{Spt)$%r&{by@d z|MNDud%MNv1M(-aWlQ8@FTFOn(Pu4rP#itaUqvjCt8axKzZcoXQLW%ob#0~frB;xZ z9$(W+L+|%$?OjFXZv};0@8ztDTHwgyCDwa)~~4%(}HBb-;X>e`&o} z9prA_s1>)U4$>Bj@?Nm1g}6AUCE~Zg!ztFYpv%7BV1zq4h#ph}FWv1+avoNL@`AJ$ zqnlOmOU+;CgGD768f*NPL*tlfX**pzJIi2(Z9_-v!>?d`!#pK=K`EpN@3NNi_yUG! zew~o|QUrW|rWc#06o9C$NO!pMCkPO;UQp(m0hXrmt^IS>DY&XM_18wSRm7M0!v-YiDN{c^d))*dI6G?1v!Ehfd5nA^!d}`ij5bj!*>S z_+50Nq3|y6ms{`&66yX+&u%S(2Zt%-{sk)S|LZ*$oJ{`p_wRbc-}Q#S>kWU`8~(00 z{9SMOyWa43z2WbA!{7CWzv~Tu*Bkz>H~d|1_`BZlcfH~7dc)uKhQI3#f7cuSt~dN$ zZ}|VO^#)>+-0@$N<>Wd7iTHW~v3@YIPC%{){Qq|S;Q!-w17aPa+ksqntszuIJQNcXO2`fBTdrv@DtexSheiyZs|FZjIc1NP4hSUL0<12`OgYZ7!gTz z>h>a5@P13&4r3b^#;;v$1^zkzb$xM9_W9=?^~29Eyh-QjT6BJ)I7a73bbdZ};j3*y z(U4^~bh9ilp20PR=U=yq{7U-6BG+ByXq+P?;(m+}h5L0vNTa?jSZ41#W$SuQIuQ<_ zSlHy3|1>KN5{N}{Zf$7hVQ<8>q z*vJ1JKZmjRZ~Q6;<;{;E?!9Brn^o=X@^Or-yGWE@9pl2@4M#5UrGcLN^1_pz9qi+B zKlYrbBSfD%hRRUX#bu%4j4G8Z<8>jOc=^ZujbBBU-{1IE|Ch(FBKvim`Y`d=k@!Yn z_c%xH9!IaF;NSm2&JiY&f+PL&eh5caC+ta`^2cfEk&UzV&`89vkv}@BE)D$B693qvn;x$ zjE&J#iXk3{oC~|Us(aC{%y3FA9(SAzON1R3JB?mYt{7dTB%S5L7&~Wzo9jIaC$2ab zc1Udvb+A2xHd1i8$Zf*yf><1FOGz5OKY^u_f2$ z=DVpqq2%Imyt%P^2k)I*^5r>&g~#pY#!eY1J>L{^i^7T1&5iMTJzA)j6iHcv$K~e1 z#G*c!by%*aaN=SB5^=V9Fn%S)p!}PmlxKKcZ60h| z%ggjw{s_tqJdQRmcE5aVF7FC&3MXzhFUG%1s-fP}lZcbei>+WDUixFX4-pre7ZY&n z4saF=r8whpu%}{EYtCV}y8|c+c--r$*qPm-Gq$=1Q1aJ0SUnD%in(n3?2^1Rf})DY zwVsN-nsHjrOYSM<93IDd8usk@ocjyRLn%3U-0EqVONfkKlx`Ts1&>ob4cl#9_NxBZ z5h5=2G_2_8cxuQWUy2wWhnf$o<;oEkmwiZS$Ky`(VF^FG)79R&Q>sIibeg01Fx^9a zrZ-tvDV(^{d>BP>YH*6#Q%VyaN17jdX)!EU-1?BR9giE$k1hWEVCiVg844#(G(YxU zHPA%!R1oDb9v4~wbM#LNv|s#?vLBBFEr7-EJ!j*5+?j~`EP&nC$n&}+=|+aZDS@$(c;+~(<6ykLxaw9PpRCr+~< z7G=s`>`~`T#AO!5j!Ae~E1x_{#9(Z1|LkbFNI9nYTPNqq?} zB}F-VzRXAa_A*p7mcIsB-O8crE9m#3WwxSCBUKY0X$$-OWB`-r8vbWHLo#&T)1kEk3nu*d|JIWObeYtip9mZW5FCd@Ras?6&GBzw*dbI*dJ0N+t% zAG8k#Q?xdb%Z7qoG>b?%ZFD}V@rMc7kg4(Dm@*f-zR=HBVUPnM^0!^mv*fg~Zeu~A z{2ZtaEqs#Dh{~&|rK{HT6ExS2UzsAOfb{vYQMT<9$SL$%3uz$xpmE;|x5)*EeM^(0 zercfJ@5p?I<-xg^hYgPRqx0Dg+yA(e2WLa=7RZmI@}jAxG)~P2`}eyGX63QV&${%{ zgM2s}^}|Om5$(hCoN4}Bv;e02Mn9<5MEi#_a=QFgq@UUK9on-$LzA~^ z@9{^=kp5F@lmkD*?VcN+1HaI5PoIk>vV|xf;GCboV$eQT+iF?IfI>Lt+dFve+yZnx z{2TTO6oJFSo$~umqVjJ2t>w6>2(rYIlf6$MdyJfKyzF)nME5bSRhc9Gl1@mU$tr^7 z>FVyA+tBq!ekrINF9OF$JuIOW$lmQfq^Z%0;a7Z{ceR}{HE3*{&J%)$cg zyOj`Bm5deB#wyk`&-j0V%UX}4j;~&d?05Rb^sirl!6%&d{pT8F52?@N1xsLgMWRH2 z7pl+yr}pb#?H}GG7!mCuf!(dR|89)LI!BI7B2$(llNg#-iMKZ-Iv(K2BpPyaWD@0G zaOT@ctlQ0zNmLx?#H}OIEQTYK=zoYKlUO9okx6vSD8uz3G4cvWCb4K4M<&s>oipD^ zqR4ZOOrqiuj!Ys=o+Fc3)P(y@$4E4L#*s-pc9J8LIHb&xNwga%!SyB4F@+5> zZGAa1i6+N6GKopRkx2{{-(;?d#Ue-I}3PAZm{!;i$7YY04e+=bqvnA{_FfsT^xN#EI>JT!C744kkB%UQ?5`_qv#3WLb zOrj1Ulh}^O7r-zQ0|}YLO@vJ12p*>Z4cQ4q`<(FWCDDSANt{c_B%*y!czP1=5;BQ; zgiPWTLMHJ89#;XwNOU4(5_Jff#HoZ#VlE!90mDeVPsk)16EcZ1giPWOJPrhgkr+$J zBwit867>j~L~%kUu>p@afng-RA!HJr2${qkgiN9WA(P0$<65Au9f7(3g^vlD#Pftq z;$}i7QI3#F9IEHsKN5=wnZ!s!CeewIN!(A!B(5Z662%Ca#CBre6N$NmOyV;_CefLY zNwgqj5_JffL^(nxablkp!E+h~;x8pGGR*^KZo3}0_|tdPKen44bR`7JTjnjUR6_k* z?1Oxz)pJN!kW!26M*TyYXu7&!4A9o4>~x7l{X3>*(3}nNP-JLc!mWe)b7s75JGv4< z_k_C9nmz3PaW3`L!xV`5IK|+yCF;M|DcMe2m^9xlCS16wiV^)c>3(U?H?f_XzBWJ7Lr3-F2-_YL32)RY55LxenX?#{IS{a zbn1^1M+@XffW{LVX!r@TR&3pOR0j3`i$siFS;#NXQl6Aw`_TBwF)(k?Js)gj?hoj6 zB7NjeUb(IG86^2`U%DZW`ittFHWlv*Vf}A;i9%VFKK5!GPec*u3LgLAqmK0T&x@9_ zLjBtl(*!Xo71Y1%`h8=`7YG=AaqUVB8h^>v(;M2pzz1n}F+p{7{hLyarJk3-P3OqB zr$3_cp-J$E>E@-7U9k4%)9243@vTFW*xMvb5e=a<1(0U-hfefGQAudizjtt0?lD zBW~}fTMgBVkZ-sX=zh#y{J7v}H5dimuC}?0{1ot|mc2u9wm(?k9uN5=f_|UjDYWt% zlnLvaR4Z$u`(4lTvh*8_Np`CkRiN?09XpFJ=f4Aek59*jWHjE3RkaotsfCI@tw)zW zDbQbN$gjno+11hgoD_V9i z>Y(IyNwDi%nRc{BM&iU}G|(bFno)f?cd)h3&%qv-el4}0$&6~*$c4L1S`1|*pi z3W5nGDQTD*G6)JtG!h3y$w5I;hM>oQii%kg1Lho2$LSHXqM{&R1Oyc`0wPhqUEMVt z=ttczV~auG&>yUA?OsHk`XdGZ(%=@jE6)>raFJ8JyZUntp>mUo7x7 zS_N?=dO8_+cB?=J)qWmTJMj43bV%S>fvy@HYuU&fVn*e?eZ|{QfzEne{P5O?Sy?+3Tx{!z>89u2BQsbdr_6@|lk>?QBfO#e!B{GM{*(<4FkWbeU&I6 z_2(1?A0Qxpfp{S+i_Ho5WSK|&0`Y#<4-iMPEI@zy1-w_p4>-=U zUBf7W!`)CJukRR-uK5?7EAnsC|2gV6TLCvAtYUj$iy!Y-(%nN z;*%`%Hj(%KVv_DdWLuU6+C-N41`~?!hwklf1tx2tQ((cZFr~K_X`m zeG=g?!ZV59j%D#gBC8X<65%%Te*VHT?*+?(yCgk_$iy$;Z6f)IU%-ndGVu!pF626M za-9y*OZ);wqHp&P@aXDzJn^k-U5EmHpnlS<$reSF(hAf@9Ku6$sp?sR)0K&-VU0Ov8CTs z$bZTYolqW8}bn6Q8 z(&SrIU4;4tFUzB%L}=Dtef7iRp?tAIa&ej%b?tIa>82&TPsREs>t0?%jxnJ})22gy z-bt-RW3QvrBlxX*j>7y)#W;FE9L0!rJ2ZA*2m5`}1MI{%(cDSiOABwpeC-qWZGX4h zsNvm^=^vLnL4DVoraRt23n!m;DVSvm*?3} zhOj>LIiaH0D-V5nv--5Kj|0d>MUD0k&}i*Fxt`~7`?OcxO?ilF`uBSLV~iDCzq!In z_y`%g1&(SwYYXxu`NFt-)MdJ|T>W>L|I^QmdB@c!+;r*L~A%FgQ&ZTJB9m(rV=+E0-KcSY}j6xd%ABnMT{PtlAe zAI)aP+JhXOvDBpq-3T%nF=`duPsMK=wB8gU&N!B8$o{*}b$JS$N<3WP6#cEkUJ`<2~E9z<#B3FzmBGLqWIdE4f$Tekh8L&OG!C z6`k?zzI_Fj?|VPde~yaQjC&UA1^2_}?%D~W=O`ubO}g$vXm37Oi*NS=`3%dHpL`zL zrx>TOH2(!sd(>-iF7{s(!!G+we~Er2-QRrm9Na&h^{e}qzeH~a%$D7E9QM-{)z!8I zy+SgvRhyl^^oRS~*6YpZSLn#9FXKYqK>q59$3I2BM&+Bp{cN69!P)xPs7bZ2 z_RO<9XkSdG!J<;6w*FaCL>L~AX_+CdrD#|1^6}O|5ZAFfe(7OUhQ6+LdapbO{JT+Z zYhnat=tcL3ai(de&|i<7`(7(U+0&FhP3s5uLvUJCPO2PvJ?XaU?mp<>s>!eNc;)EY zlcfWm-vfW#F2>AXP>#$Om38aq4)6D^Yr`z)a^&tU8`3rp{MW3rv%j^LqsS7eWv?w@ zd?~8knag>D7G;lKAJY@+7tF{~hxix=RL|&qJmm=OnK*dYy63d(Rwt()GB#JKQxzw= z_IXYV($2it*k*N=(#c*`x&0aaqt%Qm4pX>Fsg-&f4}V4{qCw(${kfo*SvBHt37t~1 z=8>Av{wgJQp~G}a=*_ZrVVZZWuTtrWvL-pjw6&qt?w@rNuTohph6l`x>0bS-ch`;N zU8Q(O-fz2KM312kKAkbv{3@02TJ^)Nh&~uKIgPpv_45kWx0ODnH(gFInCgb0yoLJP z=0ByQ-e1-g4>7(>(fJc&mPly;)C2`8))Atr-F&WkLmrXYYc9=42SxWiF|WD zooy*k9XmD_%732bm6lKMDUEX)ciR%KuS**-B%d~at8ynQm;?P0x%7zlBl_C3n`#UC zm_h%U$uC|0kQTSJ)gB0+1nm#~<$UY`Ew8rjN@@UiG|Fi7mj~~86yU(ZzxV+L4>>IIP?dfgWEL$$$Y96$QO1ySK<~IGc$Rku>0{4e^ zVW*G&Eqd^^rTs>J*9ZOlw&VUc>FXmhx*5t%f$`CnoW1D=U6&c5vhga6kF3!nFWkCL z&!RUcpL${e_C1*w*O*JIPqNEh;bMA~@`>qEtDQ@m&34YMu+stiOx@CauhEYOUD#KY z1NKsyd*5yr)AhdE>RVqsfZk(PkDWB_;g@|e#Q^H#ecg~DC!&`pK5bd)4(*}5-d>Iq z(p#?mB|T&!j5l6=)9TNcX)A?~NAIiP{tdQ2Gv^X*TfFT|lNQ`xL6-T(!i%)~k)Ohb zuT$arjYl|BFVOe6L#3Y_(FOg-C$_iF(HEU&Dc!LA1mkIM##oE9bpMJV6Z=8X9^Q;c zvBJ~zmXu7DGfTi8!OMn2Ca368ZYMts*M;#WSXZ|;>^Lo)y}*St8pbCzw^$T@gw`ld zco8@l-_PW0t#JowJ=c>ps|*c5?>=ID;(q!;=*^8b7BJofld|oT_s|ZmrQW>;!FZ+A zzD^vpi=I+*PW$38Jf0TmF0t4`Z#*UK@SU;+S+Um>|MfJga0^gw=i*PI97Q)Shn+P`&ZXo=Va6RE4 zgzE^`60RZqop3c_h<}Hz<9#Iz@$MM;Ghv8x$H*TEe;`~%_&wowgdvU{lfRNM#IIxI zH-yUxL)KGApD###HVBOLwq`hAwC_$MTDOcE+h9Ae^ap@R_ zcytWs6NY$njQo%=#G_;6Ji-udlEfi9$|{GxChY_<`Jd{i@Os&VIEDWWILBi#9S3#PRRqn(E%cVC@)dHLaH zkWw~Q-vAA%(<@7Jkq24qvs;9ap=nP~;a%{DD4%_X+161b79)2}*fO_0UCj5TMW#JbYI?oWl^cc3E59?E;8(&N^Cdb7kdt0|KRX}TPouJSt$FT`_$qceCVtcdJma5K2se*l} z5BF(^X8^yAW}nrm_S`K6k@V$e9v>g~xdas8)G$J~lRZ~2eUOgl%Au|0MJ-yL0uBD+}%R$j-~ulVK6 zk3%}jJv3iz0RNQoI(KboJi6KC{0$=tzUNb_9HWwWG`!!a#byueKvvs)Zv7&3IbfXa zuxl0|7v@fKSd5 zbOxtq4qt}*KkH(=?oyO6;>O8l7d)Ocx()cW6kV>JzcR2Jwl8(8Xn!Kw+3&JniaQ>E z=^G3t2+)`{4&L`UV?gF?FNzVMr(N^b#Pz`ALqYHKV*y$?{gKB=bJ#zmTF$KIu zjg2#g+ZBlA>V#=kNytGq`gP7qEW70zStp~NW{Rqpn(+Q#dhPJN z$!OJ&(Q;c#Z9y(lRA@^^>NW}`fAzxS#baRW%oLPZzNOGo1>&|-CW_y3QqcTHk8gE9 zu{{@RD*B|NrkZ{YPp9MlYq<6zDix_l((etl@cLo=(xOMHXwRpiX6dfr|5Gcp3db!& zhL;--d1a}CY#=IJxeQs}dpZAeF4p^5l)PJpZqyvJ9uk53!{Xd)%jHPxs9xNF`LKUV zby2O#T8{E^Jl%H;#N(%_AQnD%=)JC#2=v-Z#=7DL-5d z=b!#~Sq!c0Xq1qpjIR$^_+WGlePqXi9qQe%e;T5B=Rq``Bz2g(Dh2yPTLZ5}M$9oz0WcS5dgFI^c$xBgm?1J$_%dN+O9J6Ns>?r!31+U)A;rxZt^S(sTGKYFM zAF9D}!hO&6Aosd+LOcQck7eps6C-G+wxf?G=wrEhz??JTv}$rsd(nyEAp7*vZ3?4h zRQFn)w#4?yjgYbkqgTcb=sssSmh(Lyt_-DLHHx&gAAmnhZ9TE|aR{9{_1veL2<-1U zYx)cbp*Q>#DCKSg|DLK6Y52~k51(CeaOx=~kd5Nr9hygcr9`LvjD!ar89`rf05uc5IOi_6PHW1`6iV^EtHzJR^KR?Dpl~4x*PBraa&9c_hek zZ7IEj=+K}-UCpD|-=`KEcm~qHc3rSnX~q6*|9)>W`Sg-YPWvw(G6&hHAnjcMUF$td zn3g;RWapCx;{)iv*UugrI0@e`-qB~V{`9ujGC%b`;PKFKYw=Y-y5hWBuIE+orzxK< zgJk{avhf*FwM+Vf>^1wMqc8nn(v+K-QLtX3@{64_eCY2FOmAf?;OiqQ9$xgO4=+&o z$Ps8`y?edQ9QtY9xy`GMas8*d_Ai=6UtKM`FK;h%e}3rmXVNQPT{$?P3+qWrO?`6R zbXrwYPWGiXw$FL(j1(_A^jC?&GJCw9;2H9jJ?X*soLaN?PQc|2nYYKC-f_-;TSzM| zFWo#?$Bj<%jO=kF7Tc4x*N>h?zwet6T4jR!Q_S<2>O!Lg+gwoqzMnpZD=s_HM&}+H zl+@z;Aqey;aisSyN-ME2#P>H#VMx6_9bqtHv_*cI+@d#E}7RDkHC7t^|)soI(E#*Nh1RCg&^myRW+ogX9j|&nSV?Csi$anbEXYB^kIql<9yz{pep~R_o0!=!fNw2hX<8Pwe-I zty$(-u}oRAEHEcBkH}n>d1fq&O^IwmWFwXZhAdN)h-^S)eIo0!%+q06Jf6tfL>|ks zU<}LDXd-J7S(9b42FpBkA`d6B8j**xEEvKvHJHc)i9CR1aX*%MeTl3}WECPSu`Ezz znd(jCUPSK6vba0TJb5B_BXU=kDOr{U(nRh;WQxdb@PEkg{b*&G*FxkbA~&*3HLxtG zC-M&>*Rss3VOd;F9b*d&{!8g2-=(T*k7Xlx6BQkzW$| z1(Bbz%qwA8TtwujL@r=i@PuXRF_9k;`60{VJeGO)iF}vHcZht8Wx-9BsT)MjCGs_v z#Wc%25s`&NzQQtfnPou^kuMVYJdw|_EIz|B?=+E568Qwn)Nz&tM~Qrd$cI?w9b{RY zP2~MV-b>^?EK^x53o?nki^w}z=51$Lyp_mXh`fnqK?cjzMk22#aypUsvExp>mt`Jd z!5)&HMaCsz-fmVFWD@-@q9@GTNz!+abi%yttSs0@^jnFZFmDUdZzk!4d7DUj2Fv1& zL{FHvf#}y0eLB$-7OW%bYe_m`-WpaGq!ImUq9@E-Mf594I$_=llKvOV;^jn7n754R zQ;9x>=m`swNqQ1VC(IMDvLKP@ml8c;-V&0YK+*~G7PGQo5z)sJJz-uP(Jv(W1uXLj z3t~xn49gT@UNkEUqKH0{=n3;8NP0L)C(H|DWkD#>hY&qs-h85;N74!Nf=T*Zmc>Ct zPnZ`-^n9WZAbP?Af0FJ;(h2i?Sy|vi^xi~Im^X*$XOncoyjdiDCd=X(L{FGEo#?%Y z-jnDF3p_}=J4q+Zb7N(JE74CQdcr&xlI~2>3Gim>GU-_b9S$YS_STJH1@JE-arc)deqNl|yW<6m9~@qCBZM_7K$o%dq(VZUy8 zJws8_R55qk?K$?21Mzx=IweEB;_iDeDmYaWuYahy(t>hs(7RW=owbOEJwRrAc?M!a67;<`~Ex#LZ5>`L2$*MF3qJoSa^693^!>eUP zzHw!D`tP}vq>bgYuDtKuX{oRF>^H&dA1bGtxP~j=+(SvUcnX#&d0riNx#ETG_nYy0 ziSp?#{=xN2|5=(b1g~GItv#rp+`V!!0UvT0y+$uV1GliX-1uRM6V~S`P)%G5q1x1( z?TkK6QP9lIowrjnrIo2qRaxA^Et3&E7{3p%Utz_}`^A;@3E3ERj_E(SzT!6S@U`En zLZb2h1f|+Di$X{9jIKTE*A>gZdh(>uDn+#-rBJ5*nhI1Gv?j+rCfP*;>%Dr5yCCOa zi?xgAF!gU$6i6f61;vJqoAt21Qi&&nB2R>r*N2Y9au<~{88m$V_<4qn6R;ehnk9># zC_1WLUCUfw*vF?U`V`vordXcI@7zzV8=B}eEMVj|d7OW9e{nZdu_CIvt{MOR1vP4* zKn{($XBXs~#ng9e5KkT*wY18v=cPcrge zHJ=`6rNi#0s}C{vJ8FblPxQ_z;*3wE3eNASQPvZ+)GWPQU(EEEfo4`Obf(vpa@luG z{z5ID0($hRuwUvfX8aV6rg|eS=W5x+d+>jz;15{FihHBL9|pOn{h9VP_vI;~NKfg< zVTaXPW%wYplzUn|{C1h)QTA^y%2&^|8bV>UB8E=E({NEYBI@ql~_J%evnk#@w%rp<-o}Ynte`svLg*2o^BI z)KpO6cBNZ2_u>CYQIyhffeMP;>N!STni-EHM&zrYJ@YPgPoBld5$ZasD8b%vhI&17 zzpiVftD-rV2EFsOnvBaEqFJqqs&l#Hv~(GJEwp%jkV=wC=Gdvs_&qo(s}BkRX}EF0_77cJcAZh%%w;qqF>iTfg}Z)bZe|6<0s>3GF{NaL~J zwPZ>e>qQeH`k|oFqh=;}!SCC_^QW8N4;|wMc{DZ*!E&*lPJg80^xEP<19SZt13`b} z=e%CVyded*_vXa1{wPV|IR9WOd|#)iKttXDlrVE~^3pL(e<~Pf4M4xL2fTZBiMgLK zCe;Iw?d+mAtt*-Pr^Rs|i1HSPUWpyf^mn=0sewq)eZj0pVy3)3NO2I#{!sAld6*1S zzIntT)Uw#{41m*8~{$SQJyuU`3OsO7%bYk+i zNWEmn|3fF|p{V;Ct*dv3F!sl~WDQ08e;JJAonYp#1+LUEH0F5s$c0VJ_+IMnGYmPX zsg$3)$~=FoJ;lS2%@gM^(=~WJ2p)}7R6`$T@9El7fZH!Pscoc&?%rB!zh@((r^nA# zL)8Z-Hiq73?(dTcTh-9>M{3*T%9-(0rE^CO9XowM`P4GTz9+iXYAAigj+&v&em+z52)=kR!Sb@)GWlwhy1(FjyGEG|F(G~VwM6qw8% zf&460p6?PfeFTb?dOM_I8rH*q&JvG6daH_FE?k1=1A!H{dIai{#~al=iMc)r zsi~tnt({xS4>9$n@$A&$|0MTKrF&sn@X$O?9mP&vGDc=C9{&PW%R}mDv?$7OdKBI- z6U??MQAb0h)5bfPG0%6DHKl>N9^Z8@N`S|QKy0I1 zGvfkI^7{*Sg&q4f3&-fCi1*-!WhD$MxZGCfBVNv8(g(Nf0tQ7SX5G*K^AtC|sWnDMXpq<261>vp}-`|oL7 z1^vS(rG06`mwwAaFX8<3ng=P7|b$#iZgQZ;eU&G%!sq2N_eQBXQ z_r|~?CV#@y34Q6yhk78_PppKT@G~O;n-JshG?*bHe*E)WcFI6B~orwN}IWp5@<^ zY3+|5OB1|@VEIrvtxSI!VzK0gw>g$A->g%n9frR=ls28Q=j9u3Wm>iO#NzMDwpbri zF+rIww`^Mbmj+W`NkwmEy1G&QYuj-MWA-&HCb z-HR@}kh&y!1*0GO0`;P8N6ZWD&V}D!fDZ;QOMBAG$CO?>vB3$;EiV&$(mK7=_L}Tw zQ0deXah9M^ML$>h&}P4}Q(d~Q4`k!9>ZSL)q^?sHJBu*VE5eEsIKw(fNA!)24C zGMMo@rkw6hUs-;#=D;Z%tnd29yE`rCrhjj5odcH3-n7Zn8>fsvU9^|EpBE~2%hSAu zi{7obnESP=63Nqjb$8C1>;4wE$LnpW9DV)$-qMH`=Kg5DOO&IR-JYDYC5~xd^}Atm zbn%m8w+0>@jLX099!6_i*^miydm3Wds4B4=?YQgqg4zA8vD{QOtQ)<}W9zG)SD5Q_ zKG0ohsk0Vc#S0kwqdt0frQiGS`SI>FQ{R|RZL;*{iJEf#uQAVG*{9vIbmU{@#?r^k z^&37TS=waa`e`S!nfZkGrBsG~xpuckZ&|#bO@027C_^haYu@;tReTD!2mXv>F z@g_f}{awD5O4C_28rH`bFyrUIw?t{${=-6}_0yRAHr2zVY1;1-enz7IAOJb|&701J>teNQ# ztFLs6Xv(8A^G)2D=erXAOPENtPv$tSvt4j`cfKVyi*n{}Dt_S3jGsf*bd$(^+umDu zwldF0>i4!rQB3+@(!46BeyP5G^#q=n4WA5+VAE;jRVSxG2`=gouDf>bH5G{Ip%Ky=!so0*3`nEdJ z;^mExwg1B3TPV&?R41}st}Z}IjD2N46Kh2WmS``0_JNTF4RnpD=fcye*XA+zuYY6P zcackFTwAxH{qXgN8qs%A{nZs?6uaZ^1C&8iVzuZ{<%iYsP2;c}@gwn@Xz5Fl`*by? zzxvlFeiap7e|&%YMW#K9KifWwl9%mhi^yTdcf-%bPomIQMvBe4OnLbYZ68EhdsiKJ z7s}Y5)tFc%+V-w;XZ3StJj`usdna=E@O8S5n3>#KJz^2w6whujT~@hm)>oreRoL#3VxMd?g;M5yk=5Mx zQgpvr$=WQTJ1$Sq()LUgTdFc;g`gXjd97_lqHQOPEBA?+@n7BARv?mk*mTAC+9W3b zueN;A{C=G7@8X#ILH%mGFRDqgjC7mE%twM>ZMQ{N8s01`4`BKO{?PE6=zy|qi8zR9 zAFr+LqR4x0ey@?Tj6H(3wu7Rc3Ts_m&olE2nDF<}H|MNhVd4$+)iYr8f$Q;H|8uLy z*gBu5yO{^uSdK5E*_`a}9pLkc`pt*U`c|Wh4|2AT_T9npW#ZmcquFvZT~pE{h07Ad zs`^+~qp-UR2MpeqE@b22R3rYm*!^#!*Kl6fzZyM1q8e#(PQNK#pC)AE;#8xy)H4pE z<-VMh+FSRynbl~buWtW1yY(baPBrT8`*QO516w&iZKK9+$g4(?PH+0Y9GXtz=2W9; zi*IW6GvRRt75q9G*j$YkU!8j6%Z~X%7bcF*cVxW7%2@H{W?`Ogi1_N5@91`R$XV6% zF2XVapqc1;VhZdvMb+FxBBrDm%DBgvT=C6BTm3xDoiSq zGvryz2|Epcp#7+#AKWcsgtzjGCd`%{aur%y^9uC4Ly-oi-a=UIBPa#3V$+jfojp4AHGGCDr1Fj z52;+&zFv#2kDhJV(3UA=;{?^BE1A_w^3PXs1`CeKSU1(8+D4B?_53ZuF-+W`Iuy4- zXK--s9O0Hj&d+}6)}gKO-W9KICkfd&LUrho;G4{%9d;Z~YRDJ!d39*Ps({B189PZ_ zp*mFUmwsX2wP?=kg5v5i`|6N~=y9#z{cR-9P#t<>@%iKy%O#v%uUfaAd0B__?+vr> z?RWWsw!i)IZRgxILN+cD=r<0L8h2$Ir}g%hLgh6-(EB0VXO?eDCUJ^DZ)+p#sJEGO z(PsK8&AUI)-sQnbgB&;{ZqW}k`<+0i@xTs_{L2NG%4O@3?Q4%67H>8RmoagS>e1$N zyrtJtHVW0Q=NZ^o)+4=@yJ9(ZX~L0AT%&rVKY03I@)vdpqYpb4x+m460Pat#6GlFq z2TYu!dgLB(M#bRO4k7)#N362A9`)?e7UZ!qN;rXudsL5(tl-Qw5zQB-X1FviX{$%| z3d=|K=ByCLFmaH6qHT*-EVm6y62>HD+igcbk?B)@$g@M~!n;gdq@SoDRM&I5M!FEq ze(e-2_=(2#?b1Cba4Y98CQi~%G+~>}*M)sjg%H<5>dUpC=;@Tcj~$hFlekGg(bD)n zm%Gf4;3yB|x@pNYpfOuQ{gx+e5UMb7lp0X6UZ27tj=O}%Z>!r3v~57m56t(a7OfC| zVd5$^pv(1zI~s277H$h%_3ZYl24r$Rp*A;T8;P^jfHWPJdwl<}nUiL9zOUY+26Uw2 zgWjB{5kfZZQUeOvQn6PhZyD!S+xi|eRU47|NU!nnMZ1J=nK(?1=*rUbNw>X&guSQT zxoB&vx# zWs{J=fi?F4|Efk5=J+n|o<f8P*UD(g9m%IZ~`x^8Qo2x8EI4s9DlstA#7&iJ~g9m#i=@T1b#x3>2KFW zO>agOp_i|eM(z~aGI5}qk;yT)rA}V4!pU9t=$y)KM&n1jDHOD13fZ_&%_ucfdr`hw zGDm)B@yy(sW)!t^KDyVMDP-eBwV+pa&MWzfNt{LbZQe(DEvWmglrlr>9VBj43p`(T zZBtfk;GBQoH6wIg3$mIeuoE7OBypr#&Me&w~!kxmJmA&Ntn$U_CF54Bk*lw4QjWgAXx*Evo+;z-wHu1sw(}m z`r6R-LN@MHE7Ch38ceD0A!0~3{P_?3&4*i`TWUm*F-t$A% zM)Mcithy*k>%tZx8<*-AT9&)*#L z$&bUn|NoA!$3{^2J08QI{sFwl*&|WHx`WyGyOmDk+b%rPU1Tw5+9oGBtA4E{YQ5aU;01sk^di$kIX(tfB$S!9Jit_ zU^DtV<qAGXed%*j%)uYry_Q&^`z&XXz=AdgD&qm z`VT!@*5CU-zn6{AcX(S)O+lO5ud`Vj#`zetqg_^to%!7V_%gJkhx$ve*h^@I;eAax zl@(~2eanKoV~Wsaxho5oCB&lPu^JbK8l6Tx`;C~sX=*IewzK&wB{3K2%#>AHUlD-R z`~$i2@AjdJ=O22NO8KL%_l68Rap)x4t35OA%A`vu`{#+xT0qZ@4-HX_gVhlEvU&$&(h^l z36g)d?tI0Hb?D>Zg;H*(bJ5xf9<`q9Rv`6*qr|-pZ=>qQi)xN_0`y_7_S+S6T(J&uf&y4x<# zPEat@m%WL`@A$Ig8Elv)+<5QpTyqV*9eHi@voCK@$(1fMB4>$^+PF!}FUmbfUnW{P zSQK1B>v{GLSCyV2kyqgP+m+|hg4VqoH;4;RMnA3Rirdbhv8B@bqLq)4-nW)*@yX9o zkZRh639BR8``6I2=hgxBH{0!y*emr`I9G7surIzD3`c>{PpX=&$zvy(Nq=FM+s2zuSt> zXG}SITVswKPm(_SAoqjW<{s_xjGBWPZw!0$?)&;Vq&EIQ$|bvIoI0Y!>rY*e$^OxV zDyqgMuKuOMYjRur%OJWHt?}&@)N@Z?o>#=BDavIO@0C@lhWE|^yoX^+g2O0jUh?YE zDN|Yo^NP|72MkD)SOBK=G8a;)_$G~X7|61yZEIDIpJ`sU&7 z_ObJ?X1lCz_#nk1Wt>FjvGcDUj|uPRF3U3>U~RB@up#g05qxy#vGcDPkDY&&c*E3; z4nDkM!RtEnln_GEwuRWs58fQGT ze@G87j7js!8EPi6?~%XVpp4{VVh7tEyueQ{nc=FoacsN2!%Ejl4Jqo|Zm;P3bm>ZC zDLOPkcYnX72k73~LCLb`K5>Wo4Vp01dN(qv$#d!F`c!o6l40Ff2LXM4@A}&tKZv_P_DYte$@uKg{co{wXyuH2=4KdLVb zR%gDqGbXofURY}JuIL~3KJ3WOyS>SgF4<+(z1!^-I`)WP?^`drWwR<(Ja8}F zG%?`x=Yn#s-l2hGK1S|D-?lwz9r)_5=;Y-!$X`F6{&;J*PEnt8+(?;sqRT1s(Ut>Q z8A>O1iOvSi;x5j2qPg64+heaT=kC8K+JAbe8KT6GMnAN_NqcSVL+dYQzDF_khI}3N zS9Rb&?e)msy2Q(PV7t9iFIVi!mFd=Q@7OUh(UWDri2kxp^->wL6aLOL#u{Sv6fl{l~KkeP(&}X33 ze5H1Kbrx7?)3#FW_TEu5x>OkOM%4dG$d$CC8T5uJYgVlG$mb^Xj`rDcdMi?DK3(bD zct#Yn`_YI8!{^fns?p?3``z4!DPvoUj|8BT(Tn{P>{3Jnr;m8ML5yf&mDipVCSlyB z2~}?=?9u~!Clw{yUZRCha&sH!sNnB!%%Og|wI=Yq#Gm?m{07_~cw>!~Y`eYTW~W{} zS=7vxT&KO+A~XBMQ_;7E_>o)HSJTgit{P>odWU;+&45!T+qWRsH>DE_60$|%`hlKD z5`5|FR`NbYQ#WxNj+E`Ux#fp;o>@14Uqy^aUdHj|v_^fJU(vSXvy?yADsy>G;LQn$ z;+2*A<(;Av)8|VGcPh2p+f;Jt-Py!{+IwKc$=SuD>qHX!th0q(m+bx7ZtwPMN>SXw zH$>d0VVmkI7ST}(v0n$JU+4a?EL^Yhb2ADV8aPQlY@;Y?W4LqG2>83G!qEHhA&lF0 zW^3T>Q@&{I_xYZyX84I-e#m;e%U+#+l`5??ZtzU*1+&7r+j7Ri_`MgVdLxTYd%EO7 zZ)g1bUhL6)XYaBy?|<4W(MwpQ@N?|CdG+n~O422qsA*LsJ1UpkFXUR^kZYUU$Bjhq zx4!Jgnb0-dpgvN%O(AbI_Y07>0i`I|02@A?c<@d{w3qLy`7zmUoIKHsFU%_CF2)$GJd&a{Gv|A zFCyc&eLQqFe#!jMZf_^^1DDJXsFV4DOXdgE$^5`2^8@N+en4b?Xt%es`GL&8?e=yu z|8mLvi#nNqxn%xDoy@;nGXJ7Z=3hkS-*$UDn}5mst=-;E-fvv;enXwS-?-%chB|q_ zamo7)b@F~g@7h*|5C+iC_SzpkdtS`i5eL;7!z7Ui3g}9UT z1x?l$WIfdR`hu+A+S}L3`i&;*H@cJc8%@@4bSLXKnylaGPS$TUS--WfH#=Luk@a!A zy`8L&X|g`1J6RvoWPMC`vOcEC`k3xyeN2<}ar=6+v-L6Ae`vS2ll=#p>_5<*>_5Z|-Xz$<7_8-XpPP@IG?C;QIe~0d5e}^XfJ9H=eJ2ctfp*z{% zp~?PEd;fN}zeD!V+U@OR|BNR4XLKj~XEfPAqdVC@qsjgm-O2tLP4>^)`?s_GGqOL~ zZf__1lQh|%q&wN4q{;py-O2tWP4*}0PWC5hvOn2wZ)f|HDR=IM>UeALB+SlhapeCo z!FPC`m0R=hONgQf^MZmdy~n@D=;)}PW@9$lpqpXY-a{tV(Gk+)SA8%!sn6)idkU{( zT9{AslKGObfMp+2kARGWEXjCCl;pRQocv#K^+XryR38`k`@z4DGW)I&BCsnZzR>mW z#NW<-fwfr7BaG!$*Q}{b06rx8{NMCA-SNi1>s#~w)C)UYAA0XkeaG@k?)<4Q>~Ou& z!$0-E+mG!V^oZ5t^S6*!(vCYF%9)w}XE`0~34Q$U`k;b8^&Q(0^yE){$MTO0oI@Abdy3*Y>^{$u68>*e45yWZ>Dzv~05|6Skq z^WXKuy4v6&(mp;qj-y(+KlL5^FT2~H`i}i~t;e5ws}B8tQ}IuI$MK`5{HMO8!}X;d z^x_VB?vOvP?^ynJ&41UA9`&cbWBs$n{HgEQ{uyIgeI>Cgrh|Q&I)7f@vHV&yoA!It z_S<>KeA?*me4O9T6FSs)#OlxbI`+qB=Rfrw>lr%jPkqPnvTw$p`i|u)5WySAXg|+E-J?>Twyj;apPAxentqt>SOpw%^Www-=Z3{q3Li{cbPTpXi`J z)uEo?kAGg@vA@*1+2UfDV_H|+c6&S4vsjkRCuvW|e!1*#OZ6YFBq@s0f%6bOIVx}H z-)S30C{b!U@V{5p{!TjwX>yQH_*>dXNK=HgW4~S7bu3&1*Zx;W{TL-G18@W&1mpwW z01^QBI0Cj@2HXR@27CojP{&qa4PX<1BftwV7mxs04!Q+^Ie=*Z6M!P5hd`Ng05$+U zfEu7Xpl-AhRS9?k$OW7NWCGFvQ2;-HBY*=K4^Rbk1=K^CGU`fHUw|fH62J=J2ABtk z0jvUS0PF{x1LOnV0a^eG8cNhafF^(o@Bjn?768@)b^^`;asefPkAPo*?jxa2fF{5I zU<2?1L;=zOM*um1JAg7k13*C&>H_EhECBNW$$$*N3BV1&Yd`~_rxA1KV=zi8O8UF;oHUr2T)Xa2wz`sd_YJD^;O1|A7dFC6~zyWu?mjj`^SVw#hXJs zN4O#)-X=JNZ%z&FV*6j_ag>?H_YJTN4~vHK;2Jq5A1h7?58y*k2B!4iQ(oabt}y|2 zzF`3&kmH@KXH;+uzrBzotcQzZL-=eKPl{5PhBOa;RCI87n01^dbspz&jtciT4+x0j zM?<5(GNr~x$M8e#!ve!8bu5!s;fy$wJx*g96cZB_>=zruj|Q7pNZAC31=s{fMYB4H zM9HLBhJ;7+scp>pRDK*$W@2Lb_E^9F^eX4IL?h6O&X;ZBoNhec>r67+h zW8V}$)b0;9ySrLXljuz-PgisMaQ~PPirPd4M)9Fv1EPX)Q>e{U5I?3}^mNtpmRyx1 zWdk`KgZ-j>qvENvQa0gHp}sLwps~I|*oJx7GDqL&80)C0@F)m9ChZvR3;*zx$q)KU z=_$|_Y_xTpIn_@VM#68o56D87l(u6M_9*EN3cFPFrM5P z-0yI&yjeY^gzuSKu>X9^@Yt}JNe1u-=JEQTLt2?H+J-#5e+20Jv1qOM9i@_iTZ|B=pt{QfYGox_9i zbyPnoEB^2Dqu)liWlU5EJ7A+IH>S>Me74q5X?uJ%7%-n700l(xaZ}+BxS{>Q%rM5I zQ}FjFVvE58of=1(M=>|ZJR&&Se5$KG<;{%Z*pLus-F3-^01#f)n5=ow2{#YTicN5qgPjrv5fa|C%};EFn28#`{@f?-@o z<4W)u6$eiSd+HYM7!JKD5h-WJLQvunfd?e?u|+(ol=75l-Qpwo)KD2`K7T%LMu2lL z$nn3G`ggSy75RG~+K09G;V4`hdCuMD!UPv!56%A0&M8cXEWtVcd^(|DFXL3wOgvT~ zd+9W8W9}E3}k93jDZk7OjsQTQ86yjHO4n8CN_e76gV<2vHYlb zXMPmZ4PpK;$-$!l<4EH-tBDa{HV>!%^I-sMFEY>hf2B&1wvV>r`^5$Y@uQq!D#Qb8 z1*DNu!=r3q&X0}aOLWJjY(iqA=i;8Rhz$&cDHQ_cu+I-OiCa2Dq+4e6xN*Z>6A2to1tME{WR4hq}vGa|d>+Bol8%kYg)7a@4 zCo>}qYO&%+$3%t0Yzj$K37ZQGR=zR5l)06MxwE~*J765Y|DXI&^KfBWidjnPw?-@e zc1}*gZ>E0F(lH0tWBlj%PY?X>_5dDFeF2iOgTHm)a~VK?fGnUF0M>65tj#D`t5H1x zc!vNpPQwgqKt|UCSfaz_;%hO(8jvX$4{Mx;S9h>pWPs}%4#4RX0a!LCGXB7WWq2_% z*Gwbnu7qK_V#=QmjO&JF2vbfduo@r&Fc<)@ea2SY4s4GAfNf49oD7WHk^;c`Q~x%(c-yb>*_YcP3yDHV~->2jZT&VG&lL0QX z`ClWE9A1#W67qKjT;^B+Y*R7cqc96_ga4a{)Nj{I&Lu2SNn{Ckmfo5E|1`g(90^OV z|DV7uqnxM=3%hnxroQ7{IX!^JpDo%#2HH~pJHQu@GKTj<7a6(z@PPUx$0rXbB_1ec zPxfT9oV2^F1)uSj3K%{F`LFGJzE6!+|Kn%UFE)us`27E7eshxl0_1h0dD zy)!#6f9W3P3Ky7AT%ON)u10x3pZ8qvpZN<)UY9jelA@DH*6Hzo zSkeFN?7n{f0sO$Axxw@1hlGZOM?}KDQS5?+aq){-yUi^ut*mWq?d&HzI8K@B_*(`)*S|Jm*OZ(G;t@E{&or^7?-zg_kJhywmIF#bo}24aNN|KjM<;gBYWqz#tj zBp}m?as)U7+yGvHSpXlve!yHn1RxHO3P=ZR1snsM0-OWn0E7TB;0E9hAP#>S4x-xF9BFc_c#&;b|$tN_jcH-Hx)01yX|yth-~JPnWm*a_GVI0iTe z5CZZ5F9Dwclr7W&&;S?#cmO+qGr$Yr1DFel0K@?VfE9prz*fK^fDmv8fb$mu$^f4M zEdWJ3J4y{;0I&l%1H1qsfDFJPfY=P)$&!x$7k1{bYdlGo|Bj67>sTlDAtgsnDD*`X z*cJ`;cBog92Q#*v@hRXOe`^$mvp!1fR*H%SNDejGjRPd-n9(4>FiDEUk8Qy23>@Ex zUrVM=aI;k*YuW@SY6x&1@Ic@kU?_$<1&oWT0#*S|03Ht90;~W$3mE&>Zoqi`5CV)# z4gkjMk~-j_z}3KbEs+YW1}vlF#Q57WAY&gq9T>hnQKu%um;}B7GH%o%VC=K!KssLQ zh=H;1zZKH^0cQb^0KNn1>cDxx8o>F$BY_KnHGy9OlS80r)qZ~jln#6T`#r-Sy|7&U zo%PF|UEL(t{$H`P)qn4LiswS{0Ql}n4Cr`{``844*H{Yyn*rwl1%MiWA~a|MUzqu=z zmp{98p`y=iP#eyqeJyQj;{TMk)3? z(r`kt;^vJet4{|DYkz(!pS)<(BWr%%?ez)=PGk+J*k{v=->+wE((>2^ckQNlSyUd} zXlyz$=gb$^DF@%qHoH07bam#28Evxt`aW)5J!5sr$k{6!Uj!Z5)KIHM z@4Ykol_1RV?v5>LtGZ0{xiK;p+DkpidyvN-%_!2Wd-1*q{G$QQ2rw;mTC*igIpqhs zUNDY7;Eh+mi;usf{NC!Rwu5Ys-8}de@eW)F4ml}%)o}SIh<7ctSoHR323_mr9KIMieW7E64Xu}Ox(^#tqs-o>D(d(eg8OGMfhn{|vfi%=_y%AnE z)%9Jy2>H5Czqa(WYl89>Z&dts!kVt44a@p8TOkdI&~BWq^)d0#7_{Wro=Rarf=&J_ zcdq~9u6gQi3sc(GCz-8pG8wSQf25_Z_!wvS%Ev~@wp((j)?(9_E4<_eovx}_en8sv zR;sl{w+q{14PT5m(T^PbME!-{SNrrC#s~fqi9MfZCm+~*UhmD^GfD@i?Y5eJQE}Wz z`%3Le22QRg9?l=RZo15V@$1|r%~iLCX1-rB!*e}{c1{`5f2srDuQg@e$*vholq$7f z?|%5?j?AkACCutwC&i9(9O8t#nsV;LGM+o}zRcX-@P1ci)9~|$=gcxl%YuAT@Qe)w z;Iyz@YbxTk4g9A+YicI^zM~GvZt#0!bAz3z0Ko6hzpsCIG+fet_(sE@E&q1F?(H9P zhwM~Hc#tkkgY5^%?dN}=l%a@lJhQ;N=g;D)=*Xy;zw<$GX;K}+6ZHRchZOT3f_Y5v zXVavZcLwz1Khou4PQe=a}NH(EP1 z*gq;fIy^8&+dn+i#5X#0`~qDqHTaGl90=R|o~X+fA@3bFW`r$h2WoN zTE5ZtVGF|N^P{xXVuQ{7@h@1IX$AU*MDw-OCbXBsnb3JHoC$x}#F^0EIJlfMLDFv^ zbi5h=m8=NA`wi*ebST|!x(d1~x(2$-bT8ZNnufuK9}OdomKp6bYBsVl zE;Al%qGqCDGRkC}3CG0VWSdEW$w1R6(_5xbOv_ChOanQ|obwzxv(si%xre!zxi`6a z+{fG>+`h;Stwv8!8TyF87#OtaK+!teb(C~NbeDiV>vS`8PwKwa)zI_N%Y-(n=sWAL z)4!=NW3biWlfi_EUK7(Mewz4pQa8iBh6RTGj6#i)jW!x(8f6+O5)LEgkPRCO>Sa%Wh`Z`?$=p9%6>-t~xjVHMoRv7LzdS$F=l3}vd zWT#1%$$pb^(-zJqvtMSrxPy^CnvA?qG=dls&fqgbnfgqb?{rq{Ue>*(yIikKZ?b-X z{#E?}(9_NnD<(Ef44<@p(t}C;4D}3`816G1Z4_^mV^nP9U@SJSGUk~aG|4v^YN~H) zW$I+=VLH<^&UD%T*WQ`O`B<<2|6>d@$}(h`5JO~?<=*#YNEu5SvZay1gfuZSGTEA< zP?EI>HMW|NrjiJyD6(Wig)BpowMGr8q~G(tr<~66UC#HnJbr)7`6G|hw0b1&HmP|>hy84oypD|=Ot%}v(5R@Y2)7Q4t7VlW8BBw@7!!}q4&KP>tFBR?2EqU zr}|I$hy05{?bGQ0{1GG66mAe23U}~rj|x8viDG+ku((w`FZ!H``=m^1q%=laByE>& zkR|z6xs%*Y?j?_sC(7T+%apxJLseIk)w|SQY9Dp9x>8-Qexx2#e^D!Fae7_7iGG*< z9^Yk_ahuuROfh?ylg-b~GFCM!(|W?1VLean)>#{^{nlaYC+o6R!>(;Nvv0RM*q!a3 z_E7svJK}V5`a4<9qt27g)6OAhq?^n4D(hAE>U%eNw|L2%@Qq$&o}}XY{_TDTe~^DX z_G<$L7aa*pzb^1D)9ZLA7>a!1YJGw)Y_R$tUkX}aE4AEiHU zY&0sHH=2s+o41=C%n|03Rea=lj(CxkOXtXM-FDJ~Sh7o(*bQi9Y(Y9{4K z^Q6^MOWBrhmmiW3$#*O3)X`dzrWtLGPDVGQmyu(8RnwxDFPXc{OXd}G zzID*L%kFDGX1{OOccyU8Yr40)8{Hl5mu`%Am$%Y;-`mFh`@$Q@yIkN>lxHeE;2N>M zD2TS$T5KymC_X2i6QiW-q1OE-={ISvyhQm`si@Xc>!~-Y+q4S$gZd--Q~GRu zzP?RAp^q{0jY8vy6>In6S>@PI+cWIv?Vs$L&Mj^~x0yHIo8`Uaz3eUbdUM0R<^2Tk zDt>oOp$_M5i?ByHEX0VacrQ18lekwrBAyV>h_6aDl_p9HMO7?ig7UPItY)d%>KJvK zx`&hXt$I=YRlP>5qSe!G)Fe&UZr3_!y|g~s6WU_!2Told?#~Xom1*=arWlL)jK3SM z`GtARJZDB*v#qUGXM3r=*}lek#5w5LZod1Od)OW1iT(%v7H-E`KayWEOsfhBf-EEp zy@Usa$AxLaeBpQcL6-QuxKzAWGNo6gEmAf4Hg1EUI7(aPgi?pkS*$kT^JHslwDsCX zZL_vjYofoTAJZEe8ojE!x!BxoKFgV}Y~N@rwjZAMVf4)jym@NAzu3?7BO6P2(NN(L z;Thq1;WgnMVW;q=a8CG17$)Y5iBezsVt3_LWr5mMdr!MVzfT{puhEa{EsZvul{90Z zkzvd*))|$|hNf(KW^nu7GGnZ{j^$>$S#CD{A;(?L={@Kcy2ssqoy(NE&6cb&If z$s6v?_j0`@UY=Lh58uvFRN@W3Bz!A;Cq#>v#G2AlDO(;R=g1S}N%9nVnmk&0Q`w~K zS0ZXhwX6EEwcF}wr`TQTK3_92Iyxy%SEr|Q%(uIahvN zNl+W9iE1t)ME9DdYoQee^>uN-^JY@Wjtm) zYrJf90}C8yLY?I#6w{3^oA+B^SvmF>c0*^dv)#GNtLV@8%XeDuZwzi&Nbmz}+F5u? z=qG+AHk4Y(d*sH-bmc>3r24%+)97lx%^d&P%;wJKTOV3cb`N{66QScj=so7O^HZ4E zA2YMdgur*EP?0W{Ax5OS{G=^%D@9XN)igC-9Yl}M{G*5Ds1wvlAc$$|EOm}LU(HpQ zsCnuNHD6t&u3>gOR14MP>PhviTBJ4x>2$KPtZZwHm1B)_&O2Fd zMgMi?dznZg-($KQqc&8N)Ni%3+5&LMc&jX3v97bgo#rp_dAC?vnaC9WcQ*=}@SdQG zw~IaKd-pMGH*wGEDt(m4m0ij=N^L&FVYN`ZUT?0udI~4#aeayYvHpdANsp(a4KQ9a zCYsNgUo%B3TSMvjGwiu`E*!(HS4NJpFQed}HHn)to^fqu3>*`Mam z_22V(KXGQ65Lea`ZxXwS!^O4Id1zX18As5fc0_JFofYpyTQH|n42 z$MxUznucnm8ru!Sbj=~=XrFhv<&=p`;(Iyb!{P*Sw)l#;Qk*Y+Asv@4NHKC{d9nO~ z{EPg!vO`HyZ&Q2lB$iWSLu;p{Xg#!4ZMXKdc3L~HUDPyvnO@Df(YV6CApo6K$I zXY}pi^v194)Ao7$qCL|+??!nQn6@=M$q(jiXTQ5Y#($H!Rwl%fA8t0%4gD_w^L+7c#+;V}$ke@V&xULLqZERU9Fv zFgNBZr#S8N)zfN3tE$Co^|eM?du=Fl;|uLu?K|y)_KVho&rodCqK{8D-!TigZzs&M zRs|~q3>BQmx2=z@o%E9Z*6&uLJ=T8Ce#KsGZ?HeK&oJZqI}dx4yt(wnSH0i8^31l9 zI@J&o1w(LzB%zJ4LpUpR1C@Tx{5>ZYi%-xQXaB>k$k6h%^3|F&N$F$RksHybhJCgo$0>dzT|Fl54p9xCf;ni^QYbqUTt6S zZ}ac+FEi`PM9xyKNFSHz=bcoxi`HMu(nf2KYZJlOl71`C z_#VBVK2V>jzpYUOfjIw5Rvkr5!iFp^;?;xn5*!^e@mGtb%J>;R8`=Ui|ug9f{UxyQSmy#nu$_p{f~Z{>G^0X*qHPw#u(U(HQ9>PHGn zYF}9xEG!j{35}VC_wgNTNj;==X_mA@>LB-&7tjZDlxOIJUn$Y*&CI2{=wOqWyt!c2 zzxAh~+EMKReYF0h-pCkYTsCT(IcBOg%zD`R){3`v`?B4_`N}B^4_NC~02{aQ2m6!! z4gQCqoIUaM&Peg!C+U^nzr{t-$*uWK}s#Z@Pzi z-mXp63bhna;H&x;x>94KgOO=0G`=^Y%^GF`b!%pJF&{D4ncK|-tF!fzwaWU4+I`8a zi?W;A57?vapY27?E6!2pqI09W)LrJj=l1YMdUL!LVEJQSBWkxQxI;xH^G{M9QbsDT zEAOavv}A3QX6kq9&**RJ-{{x#n~xaD<_3^(A=Bc#nF8ZGVpXu~+k&k!F&?&Gwts~u z$xfy-8jiFDZ2TISJ>qo-Eqvr%4)6)7oIL)SB)mx#YSYO^i%)@vSBh6e6-=^UN`UX= z%U9&Ca+4*Z_6`!2&Q~ajnb|Imp0aJ=B&l&qW-8pOJAzz>+jG- z1{#};>&#@cCXDB(b-~KC%Q~WStJBRH$S0dgJ=Qss;mP07vt#_qeht62-_OsYZ@=ij zF^iyjc7=-ju6zPJla^Bdge9%+j7I_IY$IH`yHgj_=zqdca>t1Z>L)km2q z=T%?ps@s)J1&i+n>)Ppj z?KE*y+!x)q+|BMT_Y3zc_oCa*>*V$JwtDA1A4Y$lpXraJ3qS9(lb;Y3>I@Bpp~3`V zwva2lBCHU6bcWBE&7$-u=X|M@A1Vz;q(oVjXMkb~aoWCU})WZ!FkQvm#ZxWtzVr^# z?VjVj|LRACsL)$bg=NAzy4@b(08A_*z6k%?Eqy7SmY$M#$!Fz8N>in$lBjl5`>NHo zCpqUYYJ0#?hv0_aX+JWPEq$0iQ5TGH#$+RxUXg6xZ4Nevnc3!8a}D$AD_F)U^E?QMQXx@4dvO!PPVpEFs``NjUv!C6R(3Ug=*z2pQPGgho3))ecAoyFC|sb*`xY4!Dm`d9iHJ;NAd zROf__HD5Iot=5)rKWV>X@3HT8?nhY|#|b#&j`iO5PJ8wJrKmV8MMP5hC~d?c)N+mJ zNIfMPyxvVt<@XGdkI2X6-{m-^fg&lUlBC?GtWh?=DBG)VsaLdWdLpXQSi0~|w5wDj z%Y4dCa6D%r_?;h`78PROA;Ku(F=3W42lkaKED>gibGen}r1r|)%3w~+7$pam7;uv! zrC7P7Tn5QUtFdZD^#jh&EW4aD)&1+NUIjK<4>#WI3IW1KCx{9?sJ6lsen$(jzc^H! zEY_EvgZ-9QswvGBLusR=De1}}B}2(nqSVFeCt73fb_czO-k;AuS@&R9-OYX=qEY6P z<_z;iGtaD!KGxnEXT3+~J8qq}8qtx5Imgiso^hvn0=OxPJs9#)oWwQa40)0Kn*0N- z=2LF!8(JfMvN6?o+g=?YTtu>{kh8Z3F+Lz(6wgZM*P9bI3GHDo&C-x_Y)>Q-yy%`d43~&A)XeqVPDV4HPpHx<}RbfYJ#rlhVJM| zdK*1iFF|6t`YRyL;F~Qp_n01YZKl1LpS;~^s{bv$Sb=qG}Pae#6jI>bBRI>g!J1dnxS;FmLgi*}2eBCjUzyry~NbdP%BVtCI zv8E1--fHduf9*B*nO&K)ldLbe;n8-iUD1xStK0E*T|2>k+nw+KJ&Ow%&t`wCzr!!^ z_ksbULZ7*o&`xM04wqKTJLGJ06HIW88!3#6RHsxei+91Sd!y+L7jKjjr4uGUG_GtQ0Y^ru zo1DS!JhzRXOm8Wv-_+oYC6o;$!H6z;qN#7tzcvIEFvE1r_xWujt-tceOgqayVb22R z&F4ukp_8ou6MyN{^%A^BUZU5`6TBXO$7T7!LfMf291?Cq#Xc^dq~8|F#quTj7#hZ3 zk#|}1emf0>HOR?eW@kAcI}ta=t?4GXI;vI|HqSh=jpk%~n*9R&AjYfXHTMRfoi1Tg{_0f&Yc%o`{T9CD8@}VWMoA4$ zM|Zem8aHdI&s(|uO`wo3{3Fbup916#$0-|0$77EXDhaiO2JneZLS1npEU>L~St=vP z$d%;l8&}-bfv%7R2(o~ z8&vL&u;Q*b5Px=z{}Z}GG0OjC*k3d~u%Z^HRfh%E)e_)=iCQyF&=k$k94$#}1M=+% zXYQ)?gf*w3F+C4DS**RLy`y~qp8H%o0!sOjX&$3j)$4E~TIwbU?+&I^U;P1n1Xy%3 zvvvVJ^$mTU{t+t9eq4-m`cL{5y_`|exX!4}X-_m-{=tVj80p3X#zV$5)cZNceDKZ^ zBhOfYp1KNWVm&JPW@D?d!zeKJ8vBfcD8a{#lg3%Jk7DD})xKHLjDt_bn{{CZjm$*2 z!JmC4$!r7GSZh{A3wsbA`&!5lPM{qAVny4P>8B0x0yI0xZjT;!FUr+J_89J3aDtcE zEA2Hf+#Tplg=hoC_7ywUsm3I`$q^jOX@hIf)9FVCdDzKuo^ob6FVdynbk@^N3Y-JX z;qRPFPLx|Q>?=3BitD+_VQ(3LK03;s;7)btz!MI+ZBd)XqGQj4LBE2M{|v97Lr!E}RrzhMn%G;}xL_d@WrAw(B7G1qm(CQvc94OEi*f zeT<%?PtYgnQ}k(ikzNchysSrzXd{-B6=zg8;{SqD(v3mr)0sw=kqzR^F(w$3jE{{A zMxu3%U4`enz`o?X6!e#kWkYT6T6l6-uw^QqV7fF&%8=fd8puQCH{=+l5{#^)vPj8O z-iM)9gDHXq?Wkal-FTFw+`WT&f8!A{jYGHrS_oLjNMAV$;;aW~c z6!UP4qor%53F;6t#~$ZCfmhYbd)lku_YUeCiH^)67w{tLcnkFSX*}&qVw_Y%E(@aV zY#uPL2hptJrmeR(;+SmZz7^Pe?S1w^Zr$X~P&A5$phJ#GOpOs;8%-RQ_$k zXFFrKr4yVN}>^ftqMcl-qU(t{AtNZbI%n9LS zZHD5dgtIjXB_{bQ_Da2qUH|MEJeIiVP|N)9-Q6iXw^`yGaX!va8J@KzwUOrF-))n= zW(wDU`?ZzRn6fkE8%YRk;%^kgrry2dZzVZ=z_&84Zo5hJ>Qf9UeawHnZG3WL|42 z-0Tmm47AjF_6mC)=l*AVkh9EL%enjBsp!^m)6lFoqlO&BjgIydkmhv%yWle>MTh!_ zLD&5PjqehlvXN+s14%dR7Eg-Jac>Hw6I8F7+#Q#q9}IRj&*5Y87KfD!$`vJ6tqKBZ zh?BS&T;OSUY9FE2Saj4VdTCALC!+yQ`mDJYP(H1 z<)^)FOr6()&y*4!?!Gk;s*Anopqr$fBrEQd10U@tB2Fe>slj8QiOz z!4CK8BT@MZ^`G^!MosgKnU3O;6J{#DvZ~pQ$W)BvcgCXe?#AuC8BO2=e2(a_XGer< zgzJUoLVIC+=v{s*Tub6)2O9Gi(m|;snqsaT0mpSycBr?ZmhI89=&sAaCadYO+x5fx zZX*Fz?>log4w+(mV1VuRbp0OADnBP$n+R52=;48?+|ir^8xjw7H7->aQ5}%-*t7NW^4^*W{Bquu5m1@F`dx>MvK(>nec*d8+SWaPY z=F~&dXlcImn)H?Qt#na}l^e=8qj=eP#&^oE$Un%V)QRdc^<8Gc0hHCB)vnt2+GX^Z zmb#C|*+(D3Y&frH8e>6U`5>+W=EV0#L%73ac-cwx&R_5XDq1zHdR7yw1-|QzcB0+F z?q@#(LfVWIU&m=cHYCU^WS~%wb0@mf+_~-|yx%w7DxBN4OoLlUO^iTcn(nWKGen2E zkSanqp%2V?HK<@W8Hx({^sU7Q=__X?O@2y#7j%9?jzZb#r_56pDyx~l2ROS8)mFG} z1JwJpVVtMQ+HB6$YuZ}e$jjsh>imPhG7B{NmVQW&M!V<<-+qekd5w7u4(tGXDiirv zJKCw_)O6}QiD;#k)5^KSS;`52hk5Xcvm1T;xO2v7=K5}LzTYFDw%L5QH<*yS-2HAH z&-J=^k9d>4*S&aufPWx(X1URk9sJQj=!<4Hf~PiFtSH4v)unix!vv`je7PA;>!Z>d zdA+=mj=2?vUO)%gCm)mxQMCTXTrYEilj$i*|EZrCtzC=enxjq7CTUZ&c__j0A5cx+}BaA4!JA6U%aY* z_;&yN=rFHzuP_94Y=_VUXZ;>j>#5R9Jf{f!t2UoFLVm+iuhrf#)*5~A3ct2XFmesI zt=o$`G|Rn#Q(*by0yh)PRq``kT$hU^!=6R2oy#OSDV>w1%Wr}H<|uu&8QQyaiCEnO z1%9euYxFn9!D5f%ke#vm*r)7k;O9+9o)vq^{wOq$=n(tdDLx_|7CXZH9#dwKDX6dZ zLxp@tJpw*!rah=Vr5(i6IE@o{C+KmtvCa6&Y++e+wy*3j@ma2Mo49@GHrw3GZhdso z8Nuf*j1Do{ez88E?38j|xrj!0om!FP(L8R<=SEW!7sse*1Ix4SwuYinEkzsafo5^o z5vai^PRu=M*!-*_@DP8@66TVUyGMMF`+U9BTvC`Qqv)CYxW&cNH|lrlOsy@vDpk+c zpCe^)h=fV1+1%2}!reUjcn?SSe(R@*>ro1m|CBPr6|7(qvwL|*PYl1|sb z&0OVL(pjDx3xpbAL1b%EEA=mD#g3$Z~t zp^4Cii8nx80_t2L=8IjJ!KdkZ{g}V|<(*1d&S8eyQoBxnnmd0GmJnm~1^qu^%%iV; zZk#Zxnl-@)?aWT*Nc4~2&6}({z{D>x-)h-5Js}(KbsC?i3hv?)?%QsG+nuVVc{{z$ z_zva5Gqz4BD;^bZlO7>ow_E-SPw*Iu^Q}zNU1~Y48)xi&?Sz&{is8KeuXt%^GYi%9 ziq*q@9mTtx7awSsLb*^Q-be=HcjhC=9ny3di zYqy~h%m6hs;*{R2k7Lp;(+}{CYmyGyX}pIz9S`eH_#?q7fOibeZj#l;O13)w2khom zQg9vr$i}2z&6522ZF1}h_9S}>>}{4k$DU6jVTqjwb}F(<)WLrb#S6IVtF9{bTS>AN zxO@L0tyJt@q7Ov8XfM{QNFty*n7*I)leYx7b*FzSs9#FC$Qu4AN2)~fa>sO7VaOo>Xtl84k%(iBKwDU7&6n$wWS%D9%&&gVz zw5os;3=%4RK~=l$Mve+YyTj?>q%v8Hon&_;$%b>T%x8Vf+YQ3{)w|yBhRXgDxyGF+ z6(QEmEEnSOs=|#zEAZBHIx0SDza%wyE5pK^~wG15H*Y45=!$X##XO#ghoX|HL$Ib6e-D+j^v0i7o%(p8z z-;yk@?5gfCdcZlll0-e<^iFtjRI(%U=2;Z@mGsUK59X8$@pvEj@O|Po(gZP5e=-E` zF&|sWz2yg(@zG52EY!jU%3EZNE0P_^R}-~+wYk~>uvn`87$`VbUxj{q2_#$#g{+$~ z+gQo7zhcCjH&Nx`W*=OZCY<=U?Dt3r6p+pR0Zl5J&fmmo?sP|kn&G&la#{z^cUrk{ z&SVQV*|&*d27A4Dz1kF&@lG{IovJ2j?UfMp77ud4>ach6|(*rNi726=t=F+U=JsDSeeG%39pFmguB2 zQCzB^UOMoJ8QK=D4gF_78G&we`lm=~zsFQ>Z9c&%tY+T?Yss+l?ceRrROk_=&5!iL zinyVt@tCWjq$}P)Zv^;l1CHnk&_oitMJ9UMmXds5ez{0R`s0oG_Vr*{X(UG0aZ3ut zpF!a9k|ec;2}bZDSAc`Qm!G9q<|?o8Sqo8p8{zV1fj_pX9XNBln2*iz#9QNur-Hk) z^%-FAH}p;VXY}(6Ak^x{O@?B$2Cofdeg^5cmB#yEx37%TWa2BKaVDCr$P4!*HIjpd z|F-!d>iv)AZ+NM<@!TE(7tFTa;Rb$Tea%cOV_!?2yES?4RJ`H0d1}Ae_o6@@2JO{w z8{=`Tbho?TGlLp>mUo-i*Lw&oJC17PlBj(TU*imVLp8sFzaC{ivawvK6aGyhe3E~0LGR9!40Pmqq-*z+XDttYwT)IF*e>MKQjPnl$wX42&!H7B;yGV2f=T`i ze&{@y>Z|5T5+U(cL(6AhV2$;?bw3Dc5_k)#2k`tPQ4$y*}-7NhD{bd-)1$_h<+#o4C%p7elGMAxJtS9}G zz>b4$-HuAp8>R0-^u4M0s~=e%;8;VsZ%^CP?M3znB-M|GcfN*G8x8svr@d3jm3fBq z-4EPkPH)(Y3d@C9wW;8eDDDb2x>;$UJ_&kwU0toVLgDYN4b--BqJA*S;W6IJEqTkn z878_Bt*f^CsJqy`1@);6+Ayy!3$wbTg#_gm>pN9zcd(m*ieLIrf|3&s)&YzCi_#a@*5KPm!zp)C)bGNcr&R9v6NUWO*U!Qc+!` zzN&6lcdG*EX_5ApHdx;bbFM*}Wf_@=0x~1DVa{_o(R=Lx&BTCipJICd?z(tz7rZG! z&xPaXX?3KIT2c?fTZc&A$gmyo>xu z`N#@>U0#^tA1=;gXQmtdZ;Cuqo`;UHM9z~x!=0)DDoj9+P9!xTC<@7e$2n(Hlxg&x zUzl_WYLh>5y4^_Syzx(o(|T83pBO57hc&=1z*X%*R{KfRrjKD%&6&r;=m0^E?vrqb zC6#RFB-p}wrgHcA`WeAVyd_rTM9jQybn{wvHYy!4dv5hC7^ z6j0rxc&)Dq?+WjuHbwFM8jCH(+i<~$uxT+K9P$>~#tWpiZ6~z)-Fw{z zUVC;oUIr;X3DeyW;==NgHhkYvXlf(GapGWUm9&A+Zjj2DDL>C_D?^@nx%wG1IOru4 zv}5KjE6~b@IwR24UvN~s>GF||%*;MQe~|D4q_l>UP8}^2ia(LT?g1hiz;mC8?y)z_ z?%bd>B=M%eFXO^{m7{&8)zBN@g51hI+GFk~?{uCWfb!(pYg&!@PO8GH$q&>PUqK9>)pAXOl((q6}Uu&_655E?#dk`2p`Z*(Av*$7f*q7iKtKSlLDgGU-At>HdyVk>AT?!%X;zDK#8r`cyI28Udc zqUBf;@zqe#dh^`d@tpUlE3~Tm4e*QC+21*!-@@!O!I-ZZXV|T2PWmR9XWpNAwEzV5 zJ}OqUbuIJo2GYna!6j|2yU2n(3bNeJG~0uN{uSxhuSrUs0b%{fPTjA}w`;js6JR4v zNSWRTJC1BDAHE-?4nF@v-OmR z>Y%_<(*kPBA5+;vndTgErU$dQuzaW+cg1fWEi4c|6>8FhWf12;@fooWJ7qmltTLrH znf2SG+U)kE$oHeIo|Tuw19#&e9cIU1AITar^QvRJ;t-D$;>9>O=;iPBkDGueF@ z3B%22L+l65(%XYlp1?QXr=QZB7&@QKfg9Vv%j+kz=GzG;C~&T=@V}A zVP^jYIC&Yrf?tKC@D1!8Hf6)pf&sUK&!v++c$`T&-Jj>bT%v`<#e_Ot8KJiDx{%K_ zY$3Tg>PciZzemTeuH2|}Cp|NqJmo&plsB;Z+XcP)C2bNJ#-X6w>z&rlom6PL^O+;N z?Z9~VpdOC~<4#1!oD*)*9S`r~b*LOZjHQP+7+3Xa(8@egMk)R?!F^1K3E$Tk&E9Ee z(v~COmvhDCXfM0a?S3TLSxagP(^UEWOYuZ5vX5Y6i9IOTT6wjy&uU3Pz zD8z)%FzQJPU_9&h2i1H@_1X?t8m2 zu6ckGhp^vM@-rjkMFIx662G(^?07a#M+;e#4=b7U^J_>O)zg}X-b^`m)V?N@-kw}{ z7cgcodUik5g2CPpSm(om2AUHS3Ci6=Udee`s-|nR&DTKxvF!4mC9gBaF7H&v>%Wza zxfx__=8{u517dwJP_(ASg!zPOq!TKL!?-)o!8;eSpL0<;p-m)z^aPul&De0c-<-?F zPbD0xGr{l7jR~`ON7!>*&0g^dwJo@df1e){W;|aJMsZrF<3GKjtYcr|6J-w`)KSoB zHMIq)k0`Bjup_7~#epi&PHNBMHU-||mw1{z&{rP7aXQJAxkPt}BjI_sIo^7jt?}hN zyN0-EQ@|P@QQaat1zwtqW3U6(bdue#9&UfI!7kk2lkC{vg$muD`?=76m7E-(Z(~fz z#UCQOJe5@OYT-lr;Q^-X4d4P*Y{gW$n~5@vDUyd${u%r35vi(F8^yxIIqWV?1c$E< z9sIM>6nIe{z2-CdOS)xMZfQUIrKjEwR_M+xSp-h~R{c@!%-LuU{v6L{L<3xHkxA0Z z=tCF$1a`~94Z4PFB{(okl~hs^e4!FMl+3H7$BZ1PMO9KPvT zw&#zcyH$~7-1)ZBQ_?yq9{+a$8{`+|S}==Y^qYEQ>rSgz)S8@0pIh}J&uI_OX$RS| zlO)QjnzhJ|b!PKzky+WQh1;16XIM`rSi^Ao(bH~g?^2n=i7T@QSG?qVMe|Mh}>~OrPs-XO-D1Xbf549+2Ihzx6n9lqw zyJ=l;&^A%apJ1o;P04%+^c!p_Mq484c_*tM`tLqGyB{oxO1^{tT5QLMj&*C^hj0#F zT-|Mh4m_OQ+ZlM~Pm#ZT1s(XMU}L=~Ce+@d*v0P`vb9ras0~Q;dgMD6v1xiv{9UXj zb&=LepMWe*knBicBfleQ$!64Vs`@?(su3czEE0jOISbvz1EV2-_N8ykBj*by7Kez&bK(}k+|5z!!~_6Sz%-C19^z@Xt2wq)MTr^ z4cn>1=*91|W7c8VvVlupCzox@u|@}w2apMUncqm@{tq7nyIi2o<0!{OPsK}YYXq$picqf-B} zGm&+5Pa{x6_=QQak)B}k&3M*($r>KVF(?);lW?ynR!605#Hm+sW!m6*bcK_ogT1rF zt9!ctW%9Jd%?cP_SNx20`dAjYZUX7DSWYMI@s*@aR zL~2ZN9d2qzw<~G$bhM!?G?)o&GtNTKTY@vP3MYOuuGC&8z;Sq1F-}x8E>v}|E^cl! zbZZAb(vgH&D(SKel4WDqw4OquY(C1(3hw-Rbi5txSsWzYbQWd%GB>OuiLtt*#hQ^6 zb4ZDGWV<01ESCXN7(2O5J8nHY1v}6{4$?c$qTPquT}o^ukC&oFGxw{r z$K8m0sDgvkhFoY@GNI|9(=1re1hyh(;ejpT^sYi3`uCp081{UpkT{!<)4M`kC9bEB z?!X~9C>|Hjk`uj5;;ko|^HP6s=*uZflq{Eu?1^ zp%g{Pa>tS5P9O~@(36u;cK^m(xz#1@D%ex7O;{1wgPy5AsD4dyF_v>mR0qr>$sn`^XlRprHu+E^+u72{;-8ns^c{ zGzDKH4c#u2&4nEN&S`8c6so+08n36qd)dZ6OLe2EZCxs>P}hzy z!*qDz7%Do8dai&|ZKjq7sbn#AtVk6bQA39ccBOt9p;kGK_m|``8#n5i+^b34s$A~W z8g5hp_vvKdgwYgZOJ2svU5e)>3EZP(Zc!R{C|lU~$9pr1xcUF+LMPAx1Ui86e=%$N zk2%x-EMuDX$8J=RT?_K))50#28@`ia72i78PTIjY-xv0hlVSFpZZa)4cx3_nDoC9N z?}bPR`-u>y&D&6mAZeaTJ%W^ZkTDMu=2O_VniF=Gyf9fF(; zLD#tif)4slT$tkuQd~mVdy=H&u>153v*Q^k5ZPe|niNjE`BH8;?N*`OYz+HQ0V$uL z6P*lIn;_#F8+N03&{oio1lb5XQZo9*pFJr<&I-HIgz$|bb9gUD;0WY{*@Fbx-hZ7O z+ZY>aC|$3<1BF@_#fE$*gIkhy)!pUa^S2Mg@y|bX=SWf3cSm$u0T+m!v-UK^w0LKf~W=o%#0#CI9~Kx1fT5UpX>|*_B2L?myd++V__? zrWE}py&rpZ3on6WY9gB>0!p%BJM53NVGsA;Pp;&nF#k_e@5cY*#QUFVcLC&LfL)S6 zFUjDS6c9{LFiaXKW)L_g^Xj{QCXfo4g6B2sFYmGV_Y*hq;GLk~C5AhH|GMY>JK6gG zPOd)w-^kSecXn{L{;`=E^uNM?-oGiV97*SR{@43AYd|tV57`QuDFDv|eWWn#Bxl23 z@@HZ`=qGXDn|KgT&{KjRUM0L&0-Yt9u97Ba&`&0SapudBxGJGmo{8dKpzmeEpAGkG zF5|!o^1G}PIedGW*3R88s?qmgQ$Y{?Zh(OlhJ!8fsa-(&5L-emjD9F1oh-og(7nM z0*EFP6q65fDT3DuAe2l{Nj^xV$czJbq|imj@OHi>Y(N*{uqDt5($J}L!gSh3+>;1< z&q=U^p1ebEj~4Wi*Ujo>vYe{9ZV!)hk| zZ}68$Qq@ow43I-C+%G@`jlcteckYBtG7U}luM;fr(u4a_`k&GYlvbd$0;Lrwtw3o7 zN-I!Wfzk?;R-m*3r4=ZxKxqX^D^Oa2(h8JTptJ&|6)3GhX$49vP+Eb~3Y1o$v;w6S jD6K$g1xhPWT7l9Elvbd$0;Lrwtw3o7N-OaHX9fNjq8<3@ literal 0 HcmV?d00001 diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 00000000..f7e54d31 --- /dev/null +++ b/premake5.lua @@ -0,0 +1,38 @@ +workspace "re3" + configurations { "Release","Debug" } + location "build" + + files { "src/*.*" } + files { "src/math/*.*" } + files { "src/modelinfo/*.*" } + files { "src/entities/*.*" } + files { "src/render/*.*" } + + includedirs { "src", "src/modelinfo" } + includedirs { "src", "src/entities" } + includedirs { "src", "src/render" } + includedirs { os.getenv("RWSDK33") } + +project "re3" + kind "SharedLib" + language "C++" + targetname "re3" + targetdir "bin/%{cfg.buildcfg}" + targetextension ".dll" + characterset ("MBCS") + + filter "configurations:Debug" + defines { "DEBUG" } + flags { "StaticRuntime" } + symbols "On" + debugdir "C:/Users/aap/games/gta3_re" + debugcommand "C:/Users/aap/games/gta3_re/gta3.exe" + postbuildcommands "copy /y \"$(TargetPath)\" \"C:\\Users\\aap\\games\\gta3_re\\plugins\\re3.dll\"" + + filter "configurations:Release" + defines { "NDEBUG" } + optimize "On" + flags { "StaticRuntime" } + debugdir "C:/Users/aap/games/gta3_re" + debugcommand "C:/Users/aap/games/gta3_re/gta3.exe" + postbuildcommands "copy /y \"$(TargetPath)\" \"C:\\Users\\aap\\games\\gta3_re\\plugins\\re3.dll\"" diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 00000000..f4cea966 --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,63 @@ +#include "common.h" +#include "patcher.h" +#include "Draw.h" +#include "Camera.h" + +CCamera &TheCamera = *(CCamera*)0x6FACF8; + +bool +CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) +{ + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y + radius < CDraw::GetNearClipZ()) return false; + if(c.y - radius > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false; + return true; +} + +bool +CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) +{ + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y < CDraw::GetNearClipZ()) return false; + if(c.y > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false; + return true; +} + +bool +CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) +{ + int i; + int frustumTests[6] = { 0 }; + RwV3dTransformPoints(box, box, 8, &mat->m_matrix); + + for(i = 0; i < 8; i++){ + if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; + if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++; + if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++; + if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++; +// Why not test z? +// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++; +// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++; + } + for(i = 0; i < 6; i++) + if(frustumTests[i] == 8) + return false; // Box is completely outside of one plane + return true; +} + + +STARTPATCHES + InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP); +ENDPATCHES diff --git a/src/Camera.h b/src/Camera.h new file mode 100644 index 00000000..46396ec4 --- /dev/null +++ b/src/Camera.h @@ -0,0 +1,420 @@ +#pragma once + +#include "Placeable.h" + +class CEntity; +class CPed; +class CAutomobile; + +#define NUMBER_OF_VECTORS_FOR_AVERAGE 2 + +struct CCam +{ + enum CamMode + { + MODE_TOPDOWN1 = 1, + MODE_TOPDOWN2, + MODE_BEHINDCAR, + MODE_FOLLOWPED, + MODE_AIMING, + MODE_DEBUG, + MODE_SNIPER, + MODE_ROCKET, + MODE_MODELVIEW, + MODE_BILL, + MODE_SYPHON, + MODE_CIRCLE, + MODE_CHEESYZOOM, + MODE_WHEELCAM, + MODE_FIXED, + MODE_FIRSTPERSON, + MODE_FLYBY, + MODE_CAMONASTRING, + MODE_REACTIONCAM, + MODE_FOLLOWPEDWITHBINDING, + MODE_CHRISWITHBINDINGPLUSROTATION, + MODE_BEHINDBOAT, + MODE_PLAYERFALLENWATER, + MODE_CAMONTRAINROOF, + MODE_CAMRUNNINGSIDETRAIN, + MODE_BLOODONTHETRACKS, + MODE_IMTHEPASSENGERWOOWOO, + MODE_SYPHONCRIMINFRONT, + MODE_PEDSDEADBABY, + MODE_CUSHYPILLOWSARSE, + MODE_LOOKATCARS, + MODE_ARRESTCAMONE, + MODE_ARRESTCAMTWO, + MODE_M16FIRSTPERSON_34, + MODE_SPECIALFIXEDFORSYPHON, + MODE_FIGHT, + MODE_TOPDOWNPED, + MODE_FIRSTPERSONPEDONPC_38, + MODE_FIRSTPERSONPEDONPC_39, + MODE_FIRSTPERSONPEDONPC_40, + MODE_FIRSTPERSONPEDONPC_41, + MODE_FIRSTPERSONPEDONPC_42, + MODE_EDITOR, + MODE_M16FIRSTPERSON_44 + }; + + bool bBelowMinDist; //used for follow ped mode + bool bBehindPlayerDesired; //used for follow ped mode + bool m_bCamLookingAtVector; + bool m_bCollisionChecksOn; + bool m_bFixingBeta; //used for camera on a string + bool m_bTheHeightFixerVehicleIsATrain; + bool LookBehindCamWasInFront; + bool LookingBehind; + bool LookingLeft; // 32 + bool LookingRight; + bool ResetStatics; //for interpolation type stuff to work + bool Rotating; + + int16 Mode; // CameraMode + uint32 m_uiFinishTime; // 52 + + int m_iDoCollisionChecksOnFrameNum; + int m_iDoCollisionCheckEveryNumOfFrames; + int m_iFrameNumWereAt; // 64 + int m_iRunningVectorArrayPos; + int m_iRunningVectorCounter; + int DirectionWasLooking; + + float f_max_role_angle; //=DEGTORAD(5.0f); + float f_Roll; //used for adding a slight roll to the camera in the + float f_rollSpeed; + float m_fSyphonModeTargetZOffSet; +float m_unknownZOffset; + float m_fAmountFractionObscured; + float m_fAlphaSpeedOverOneFrame; // 100 + float m_fBetaSpeedOverOneFrame; + float m_fBufferedTargetBeta; + float m_fBufferedTargetOrientation; + float m_fBufferedTargetOrientationSpeed; + float m_fCamBufferedHeight; + float m_fCamBufferedHeightSpeed; + float m_fCloseInPedHeightOffset; + float m_fCloseInPedHeightOffsetSpeed; // 132 + float m_fCloseInCarHeightOffset; + float m_fCloseInCarHeightOffsetSpeed; + float m_fDimensionOfHighestNearCar; + float m_fDistanceBeforeChanges; + float m_fFovSpeedOverOneFrame; + float m_fMinDistAwayFromCamWhenInterPolating; + float m_fPedBetweenCameraHeightOffset; + float m_fPlayerInFrontSyphonAngleOffSet; // 164 + float m_fRadiusForDead; + float m_fRealGroundDist; //used for follow ped mode + float m_fTargetBeta; + float m_fTimeElapsedFloat; + + float m_fTransitionBeta; + float m_fTrueBeta; + float m_fTrueAlpha; // 200 + float m_fInitialPlayerOrientation; //used for first person + + float Alpha; + float AlphaSpeed; + float FOV; + float FOVSpeed; + float Beta; + float BetaSpeed; + float Distance; // 232 + float DistanceSpeed; + float CA_MIN_DISTANCE; + float CA_MAX_DISTANCE; + float SpeedVar; + + // ped onfoot zoom distance + float m_fTargetZoomGroundOne; + float m_fTargetZoomGroundTwo; // 256 + float m_fTargetZoomGroundThree; + // ped onfoot alpha angle offset + float m_fTargetZoomOneZExtra; + float m_fTargetZoomTwoZExtra; + float m_fTargetZoomThreeZExtra; + + float m_fTargetZoomZCloseIn; + float m_fMinRealGroundDist; + float m_fTargetCloseInDist; + + CVector m_cvecTargetCoorsForFudgeInter; // 360 + CVector m_cvecCamFixedModeVector; // 372 + CVector m_cvecCamFixedModeSource; // 384 + CVector m_cvecCamFixedModeUpOffSet; // 396 + CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water + CVector m_vecBufferedPlayerBodyOffset; // 420 + + // The three vectors that determine this camera for this frame + CVector Front; // 432 // Direction of looking in + CVector Source; // Coors in world space + CVector SourceBeforeLookBehind; + CVector Up; // Just that + CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff + CEntity *CamTargetEntity; + + float m_fCameraDistance; + float m_fIdealAlpha; + float m_fPlayerVelocity; + CAutomobile *m_pLastCarEntered; // So interpolation works + CPed *m_pLastPedLookedAt;// So interpolation works + bool m_bFirstPersonRunAboutActive; + + + void Process_Debug(float *vec, float a, float b, float c); + void Process_Kalvin(float*, float, float, float); + void GetVectorsReadyForRW(void); +}; +static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size"); +static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error"); +static_assert(offsetof(CCam, Front) == 0x140, "CCam: error"); + +struct CCamPathSplines +{ + float m_arr_PathData[800]; +}; + +struct CTrainCamNode +{ + CVector m_cvecCamPosition; + CVector m_cvecPointToLookAt; + CVector m_cvecMinPointInRange; + CVector m_cvecMaxPointInRange; + float m_fDesiredFOV; + float m_fNearClip; +}; + +struct CQueuedMode +{ + int16 Mode; + float Duration; + int16 MinZoom; + int16 MaxZoom; +}; + +enum +{ + LOOKING_BEHIND, + LOOKING_LEFT, + LOOKING_RIGHT, + LOOKING_FORWARD, +}; + +struct CCamera : public CPlaceable +{ + bool m_bAboveGroundTrainNodesLoaded; + bool m_bBelowGroundTrainNodesLoaded; + bool m_bCamDirectlyBehind; + bool m_bCamDirectlyInFront; + bool m_bCameraJustRestored; + bool m_bcutsceneFinished; + bool m_bCullZoneChecksOn; + bool m_bFirstPersonBeingUsed; + bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; + bool m_bIdleOn; + bool m_bInATunnelAndABigVehicle; + bool m_bInitialNodeFound; + bool m_bInitialNoNodeStaticsSet; + bool m_bIgnoreFadingStuffForMusic; + bool m_bPlayerIsInGarage; + bool m_bJustCameOutOfGarage; + bool m_bJustInitalised; + bool m_bJust_Switched; + bool m_bLookingAtPlayer; + bool m_bLookingAtVector; + bool m_bMoveCamToAvoidGeom; + bool m_bObbeCinematicPedCamOn; + bool m_bObbeCinematicCarCamOn; + bool m_bRestoreByJumpCut; + bool m_bUseNearClipScript; + bool m_bStartInterScript; + bool m_bStartingSpline; + bool m_bTargetJustBeenOnTrain; + bool m_bTargetJustCameOffTrain; + bool m_bUseSpecialFovTrain; + bool m_bUseTransitionBeta; + bool m_bUseScriptZoomValuePed; + bool m_bUseScriptZoomValueCar; + bool m_bWaitForInterpolToFinish; + bool m_bItsOkToLookJustAtThePlayer; + bool m_bWantsToSwitchWidescreenOff; + bool m_WideScreenOn; + bool m_1rstPersonRunCloseToAWall; + bool m_bHeadBob; + bool m_bFailedCullZoneTestPreviously; + +bool m_FadeTargetIsSplashScreen; + + bool WorldViewerBeingUsed; + uint8 ActiveCam; + uint32 m_uiCamShakeStart; + uint32 m_uiFirstPersonCamLastInputTime; +// where are those? +//bool m_bVehicleSuspenHigh; +//bool m_bEnable1rstPersonCamCntrlsScript; +//bool m_bAllow1rstPersonWeaponsCamera; + + uint32 m_uiLongestTimeInMill; + uint32 m_uiNumberOfTrainCamNodes; + uint8 m_uiTransitionJUSTStarted; + uint8 m_uiTransitionState; // 0:one mode 1:transition + + uint32 m_uiTimeLastChange; + uint32 m_uiTimeWeEnteredIdle; + uint32 m_uiTimeTransitionStart; + uint32 m_uiTransitionDuration; + int m_BlurBlue; + int m_BlurGreen; + int m_BlurRed; + int m_BlurType; + +uint32 unknown; + int m_iWorkOutSpeedThisNumFrames; + int m_iNumFramesSoFar; + + + int m_iCurrentTrainCamNode; + int m_motionBlur; + int m_imotionBlurAddAlpha; + int m_iCheckCullZoneThisNumFrames; + int m_iZoneCullFrameNumWereAt; + int WhoIsInControlOfTheCamera; + + float CamFrontXNorm; + float CamFrontYNorm; + float CarZoomIndicator; + float CarZoomValue; + float CarZoomValueSmooth; + + float DistanceToWater; + float FOVDuringInter; + float LODDistMultiplier; + float GenerationDistMultiplier; + float m_fAlphaSpeedAtStartInter; + float m_fAlphaWhenInterPol; + float m_fAlphaDuringInterPol; + float m_fBetaDuringInterPol; + float m_fBetaSpeedAtStartInter; + float m_fBetaWhenInterPol; + float m_fFOVWhenInterPol; + float m_fFOVSpeedAtStartInter; + float m_fStartingBetaForInterPol; + float m_fStartingAlphaForInterPol; + float m_PedOrientForBehindOrInFront; + float m_CameraAverageSpeed; + float m_CameraSpeedSoFar; + float m_fCamShakeForce; + float m_fCarZoomValueScript; + float m_fFovForTrain; + float m_fFOV_Wide_Screen; + float m_fNearClipScript; + float m_fOldBetaDiff; + float m_fPedZoomValue; + + float m_fPedZoomValueScript; + float m_fPedZoomValueSmooth; + float m_fPositionAlongSpline; + float m_ScreenReductionPercentage; + float m_ScreenReductionSpeed; + float m_AlphaForPlayerAnim1rstPerson; + float Orientation; + float PedZoomIndicator; + float PlayerExhaustion; + float SoundDistUp, SoundDistLeft, SoundDistRight; + float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; + float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; + float m_fWideScreenReductionAmount; + float m_fStartingFOVForInterPol; + + // not static yet + float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls + float m_fMouseAccelVertical;// acceleration multiplier for 1st person controls + float m_f3rdPersonCHairMultX; + float m_f3rdPersonCHairMultY; + + + CCam Cams[3]; + void *pToGarageWeAreIn; + void *pToGarageWeAreInForHackAvoidFirstPerson; + CQueuedMode m_PlayerMode; + CQueuedMode PlayerWeaponMode; + CVector m_PreviousCameraPosition; + CVector m_RealPreviousCameraPosition; + CVector m_cvecAimingTargetCoors; + CVector m_vecFixedModeVector; + + // one of those has to go + CVector m_vecFixedModeSource; + CVector m_vecFixedModeUpOffSet; +// CVector m_vecCutSceneOffset; + CVector m_cvecStartingSourceForInterPol; + CVector m_cvecStartingTargetForInterPol; + CVector m_cvecStartingUpForInterPol; + CVector m_cvecSourceSpeedAtStartInter; + CVector m_cvecTargetSpeedAtStartInter; + CVector m_cvecUpSpeedAtStartInter; + CVector m_vecSourceWhenInterPol; + CVector m_vecTargetWhenInterPol; + CVector m_vecUpWhenInterPol; + CVector m_vecClearGeometryVec; + + CVector m_vecGameCamPos; + CVector SourceDuringInter; + CVector TargetDuringInter; + CVector UpDuringInter; + RwCamera *m_pRwCamera; + CEntity *pTargetEntity; + CCamPathSplines m_arrPathArray[4]; + CTrainCamNode m_arrTrainCamNode[800]; + CMatrix m_cameraMatrix; + bool m_bGarageFixedCamPositionSet; + bool m_vecDoingSpecialInterPolation; + bool m_bScriptParametersSetForInterPol; + bool m_bFading; + bool m_bMusicFading; + CMatrix m_viewMatrix; + CVector m_vecFrustumNormals[4]; + CVector m_vecOldSourceForInter; + CVector m_vecOldFrontForInter; + CVector m_vecOldUpForInter; + + float m_vecOldFOVForInter; + float m_fFLOATingFade; + float m_fFLOATingFadeMusic; + float m_fTimeToFadeOut; + float m_fTimeToFadeMusic; + float m_fFractionInterToStopMovingTarget; + float m_fFractionInterToStopCatchUpTarget; + float m_fGaitSwayBuffer; + float m_fScriptPercentageInterToStopMoving; + float m_fScriptPercentageInterToCatchUp; + +uint32 m_fScriptTimeForInterPolation; + + +int16 m_iFadingDirection; +int m_iModeObbeCamIsInForCar; + int16 m_iModeToGoTo; + int16 m_iMusicFadingDirection; + int16 m_iTypeOfSwitch; + + uint32 m_uiFadeTimeStarted; + uint32 m_uiFadeTimeStartedMusic; + + + CMatrix &GetCameraMatrix(void) { return m_cameraMatrix; } + CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } + bool IsPointVisible(const CVector ¢er, const CMatrix *mat); + bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); + bool IsBoxVisible(RwV3d *box, const CMatrix *mat); +}; +static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error"); +static_assert(offsetof(CCamera, WorldViewerBeingUsed) == 0x75, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiNumberOfTrainCamNodes) == 0x84, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error"); +static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error"); +static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error"); +static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size"); +extern CCamera &TheCamera; diff --git a/src/Clock.cpp b/src/Clock.cpp new file mode 100644 index 00000000..dc8e1599 --- /dev/null +++ b/src/Clock.cpp @@ -0,0 +1,116 @@ +#include "common.h" +#include "patcher.h" +#include "Timer.h" +#include "Pad.h" +#include "Clock.h" + +uint8 &CClock::ms_nGameClockHours = *(uint8*)0x95CDA6; +uint8 &CClock::ms_nGameClockMinutes = *(uint8*)0x95CDC8; +uint16 &CClock::ms_nGameClockSeconds = *(uint16*)0x95CC7C; +uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B; +uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B; +uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C; +uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64; +int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4; +bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82; + +void +CClock::Initialise(uint32 scale) +{ + debug("Initialising CClock...\n"); + ms_nGameClockHours = 12; + ms_nGameClockMinutes = 0; + ms_nGameClockSeconds = 0; + ms_nMillisecondsPerGameMinute = scale; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); + ms_bClockHasBeenStored = false; + debug("CClock ready\n"); +} + +void +CClock::Update(void) +{ + if(CPad::GetPad(1)->NewState.r1){ + ms_nGameClockMinutes += 8; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); + if(ms_nGameClockMinutes >= 60){ + ms_nGameClockHours++; + ms_nGameClockMinutes = 0; + if(ms_nGameClockHours >= 24) + ms_nGameClockHours = 0; + } + }else + if(CTimer::GetTimeInMilliseconds() - ms_nLastClockTick > + ms_nMillisecondsPerGameMinute){ + ms_nGameClockMinutes++; + ms_nLastClockTick += ms_nMillisecondsPerGameMinute; + if(ms_nGameClockMinutes >= 60){ + ms_nGameClockHours++; + ms_nGameClockMinutes = 0; + if(ms_nGameClockHours >= 24) + ms_nGameClockHours = 0; + // TODO: stats days passed + } + } + ms_nGameClockSeconds += + 60 + * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) + / ms_nMillisecondsPerGameMinute; +} + +void +CClock::SetGameClock(uint8 h, uint8 m) +{ + ms_nGameClockHours = h; + ms_nGameClockMinutes = m; + ms_nGameClockSeconds = 0; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); +} + +int32 +CClock::GetGameClockMinutesUntil(uint8 h, uint8 m) +{ + int32 now, then; + now = ms_nGameClockHours*60 + ms_nGameClockMinutes; + then = h*60 + m; + if(then < now) + then += 24*60; + return then-now; +} + +bool +CClock::GetIsTimeInRange(uint8 h1, uint8 h2) +{ + if(h1 > h2) + return ms_nGameClockHours >= h1 || ms_nGameClockHours < h2; + else + return ms_nGameClockHours >= h1 && ms_nGameClockHours < h2; +} + +void +CClock::StoreClock(void) +{ + ms_Stored_nGameClockHours = ms_nGameClockHours; + ms_Stored_nGameClockMinutes = ms_nGameClockMinutes; + ms_Stored_nGameClockSeconds = ms_nGameClockSeconds; + ms_bClockHasBeenStored = true; +} + +void +CClock::RestoreClock(void) +{ + ms_nGameClockHours = ms_Stored_nGameClockHours; + ms_nGameClockMinutes = ms_Stored_nGameClockMinutes; + ms_nGameClockSeconds = ms_Stored_nGameClockSeconds; +} + + +STARTPATCHES + InjectHook(0x473370, CClock::Initialise, PATCH_JUMP); + InjectHook(0x473460, CClock::Update, PATCH_JUMP); + InjectHook(0x4733C0, CClock::SetGameClock, PATCH_JUMP); + InjectHook(0x4733F0, CClock::GetGameClockMinutesUntil, PATCH_JUMP); + InjectHook(0x473420, CClock::GetIsTimeInRange, PATCH_JUMP); + InjectHook(0x473540, CClock::StoreClock, PATCH_JUMP); + InjectHook(0x473570, CClock::RestoreClock, PATCH_JUMP); +ENDPATCHES diff --git a/src/Clock.h b/src/Clock.h new file mode 100644 index 00000000..0b6ba304 --- /dev/null +++ b/src/Clock.h @@ -0,0 +1,27 @@ +#pragma once + +class CClock +{ + static uint8 &ms_nGameClockHours; + static uint8 &ms_nGameClockMinutes; + static uint16 &ms_nGameClockSeconds; + static uint8 &ms_Stored_nGameClockHours; + static uint8 &ms_Stored_nGameClockMinutes; + static uint16 &ms_Stored_nGameClockSeconds; + static uint32 &ms_nMillisecondsPerGameMinute; + static int32 &ms_nLastClockTick; + static bool &ms_bClockHasBeenStored; +public: + + static void Initialise(uint32 scale); + static void Update(void); + static void SetGameClock(uint8 h, uint8 m); + static int32 GetGameClockMinutesUntil(uint8 h, uint8 m); + static bool GetIsTimeInRange(uint8 h1, uint8 h2); + static void StoreClock(void); + static void RestoreClock(void); + + static int8 GetHours(void) { return ms_nGameClockHours; } + static int8 GetMinutes(void) { return ms_nGameClockMinutes; } + static int16 GetSeconds(void) { return ms_nGameClockSeconds; } +}; diff --git a/src/Collision.cpp b/src/Collision.cpp new file mode 100644 index 00000000..14b3adcd --- /dev/null +++ b/src/Collision.cpp @@ -0,0 +1,1629 @@ +#include "common.h" +#include "patcher.h" +#include "Game.h" +#include "General.h" +#include "RenderBuffer.h" +#include "SurfaceTable.h" +#include "Collision.h" + +enum Direction +{ + DIR_X_POS, + DIR_X_NEG, + DIR_Y_POS, + DIR_Y_NEG, + DIR_Z_POS, + DIR_Z_NEG, +}; + +eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250; +CLinkList &CCollision::ms_colModelCache = *(CLinkList*)0x95CB58; + +#if 0 + +void +CCollision::Init(void) +{ + ms_colModelCache.Init(NUMCOLCACHELINKS); + ms_collisionInMemory = LEVEL_NONE; +} + +void +CCollision::Update(void) +{ + CVector pos = FindPlayerCoors(); + eLevelName level = CTheZones::m_CurrLevel; + bool changeLevel = false; + + // hardcode a level if there are no zones + if(level == LEVEL_NONE){ + if(CGame::currLevel == LEVEL_INDUSTRIAL && + pos.x < 400.0f){ + level = LEVEL_COMMERCIAL; + changeLevel = true; + }else if(CGame::currLevel == LEVEL_SUBURBAN && + pos.x > -450.0f && pos.y < -1400.0f){ + level = LEVEL_COMMERCIAL; + changeLevel = true; + }else{ + if(pos.x > 800.0f){ + level = LEVEL_INDUSTRIAL; + changeLevel = true; + }else if(pos.x < -800.0f){ + level = LEVEL_SUBURBAN; + changeLevel = true; + } + } + } + if(level != LEVEL_NONE && level != CGame::currLevel){ + debug("changing level %d -> %d\n", CGame::currLevel, level); + CGame::currLevel = level; + } + if(ms_collisionInMemory != CGame::currLevel) + LoadCollisionWhenINeedIt(changeLevel); + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); +} + +void +CCollision::LoadCollisionWhenINeedIt(bool changeLevel) +{ + eLevelName level; + level = LEVEL_NONE; + if(!changeLevel){ + //assert(0 && "unimplemented"); + } + + if(level != CGame::currLevel || changeLevel){ + CTimer::Stop(); + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + ms_collisionInMemory = CGame::currLevel; + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestBigBuildings(CGame::currLevel); + CStreaming::LoadAllRequestedModels(); + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); + CTimer::Update(); + } +} + +#endif + +// +// Test +// + + +bool +CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) +{ + float d = s1.radius + s2.radius; + return (s1.center - s2.center).MagnitudeSqr() < d*d; +} + +bool +CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) +{ + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + return true; +} + +bool +CCollision::TestLineBox(const CColLine &line, const CColBox &box) +{ + float t, x, y, z; + // If either line point is in the box, we have a collision + if(line.p0.x > box.min.x && line.p0.x < box.max.x && + line.p0.y > box.min.y && line.p0.y < box.max.y && + line.p0.z > box.min.z && line.p0.z < box.max.z) + return true; + if(line.p1.x > box.min.x && line.p1.x < box.max.x && + line.p1.y > box.min.y && line.p1.y < box.max.y && + line.p1.z > box.min.z && line.p1.z < box.max.z) + return true; + + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // same test with max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + return false; +} + +bool +CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) +{ + if(line.p0.x <= box.min.x) return false; + if(line.p0.y <= box.min.y) return false; + if(line.p0.x >= box.max.x) return false; + if(line.p0.y >= box.max.y) return false; + if(line.p0.z < line.p1.z){ + if(line.p0.z > box.max.z) return false; + if(line.p1.z < box.min.z) return false; + }else{ + if(line.p1.z > box.max.z) return false; + if(line.p0.z < box.min.z) return false; + } + return true; +} + +bool +CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + CVector2D vec1, vec2, vec3, vect; + + // We do the test in 2D. With the plane direction we + // can figure out how to project the vectors. + // normal = (c-a) x (b-a) + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + // This is our triangle: + // 3-------2 + // \ P / + // \ / + // \ / + // 1 + // We can use the "2d cross product" to check on which side + // a vector is of another. Test is true if point is inside of all edges. + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + return true; +} + +// Test if line segment intersects with sphere. +// If the first point is inside the sphere this test does not register a collision! +// The code is reversed from the original code and rather ugly, see Process for a clear version. +// TODO: actually rewrite this mess +bool +CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) +{ + CVector v01 = line.p1 - line.p0; // vector from p0 to p1 + CVector v0c = sph.center - line.p0; // vector from p0 to center + float linesq = v01.MagnitudeSqr(); + // I leave in the strange -2 factors even though they serve no real purpose + float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line + // Square of tangent from p0 multiplied by line length so we can compare with projline. + // The length of the tangent would be this: sqrt((c-p0)^2 - r^2). + // Negative if p0 is inside the sphere! This breaks the test! + float tansq = 4.0f * linesq * + (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); + float diffsq = projline*projline - tansq; + // if diffsq < 0 that means the line is a passant, so no intersection + if(diffsq < 0.0f) + return false; + // projline (negative in GTA for some reason) is the point on the line + // in the middle of the two intersection points (startin from p0). + // sqrt(diffsq) somehow works out to be the distance from that + // midpoint to the intersection points. + // So subtract that and get rid of the awkward scaling: + float f = (-projline - sqrt(diffsq)) / (2.0f*linesq); + // f should now be in range [0, 1] for [p0, p1] + return f >= 0.0f && f <= 1.0f; +} + +bool +CCollision::TestSphereTriangle(const CColSphere &sphere, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ + // If sphere and plane don't intersect, no collision + if(fabs(plane.CalcPoint(sphere.center)) > sphere.radius) + return false; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // calculate two orthogonal basis vectors for the triangle + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, plane.normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + if(testcase == 1){ + // closest to a vertex + if(insideAB) dist = (sphere.center - vc).Magnitude(); + else if(insideAC) dist = (sphere.center - vb).Magnitude(); + else if(insideBC) dist = (sphere.center - va).Magnitude(); + else assert(0); + }else if(testcase == 2){ + // closest to an edge + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); + else assert(0); + }else if(testcase == 3){ + // center is in triangle + return true; + }else + assert(0); // front fell off + + return dist < sphere.radius; +} + +bool +CCollision::TestLineOfSight(CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSurf78) +{ + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8) + if(TestLineSphere(newline, model.spheres[i])) + return true; + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8) + if(TestLineBox(newline, model.boxes[i])) + return true; + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8) + if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) + return true; + + return false; +} + + +// +// Process +// + +// For Spheres mindist is the squared distance to its center +// For Lines mindist is between [0,1] + +bool +CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) +{ + CVector dist = s1.center - s2.center; + float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 + float dc = d < 0.0f ? 0.0f : d; // clamp to zero, i.e. if s1's center is inside s2 + // no collision if sphere is not close enough + if(mindistsq <= dc*dc || s1.radius <= dc) + return false; + dist.Normalise(); + point.point = s1.center - dist*dc; + point.normal = dist; + point.surfaceA = s1.surface; + point.pieceA = s1.piece; + point.surfaceB = s2.surface; + point.pieceB = s2.piece; + point.depth = s1.radius - d; // sphere overlap + mindistsq = dc*dc; // collision radius + return true; +} + +bool +CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) +{ + CVector p; + CVector dist; + + // GTA's code is too complicated, uses a huge 3x3x3 if statement + // we can simplify the structure a lot + + // first make sure we have a collision at all + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + + // Now find out where the sphere center lies in relation to all the sides + int xpos = sph.center.x < box.min.x ? 1 : + sph.center.x > box.max.x ? 2 : + 0; + int ypos = sph.center.y < box.min.y ? 1 : + sph.center.y > box.max.y ? 2 : + 0; + int zpos = sph.center.z < box.min.z ? 1 : + sph.center.z > box.max.z ? 2 : + 0; + + if(xpos == 0 && ypos == 0 && zpos == 0){ + // sphere is inside the box + p = (box.min + box.max)*0.5f; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + point.normal = dist * (1.0f/sqrt(lensq)); + point.point = sph.center - point.normal; + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; + + // find absolute distance to the closer side in each dimension + float dx = dist.x > 0.0f ? + box.max.x - sph.center.x : + sph.center.x - box.min.x; + float dy = dist.y > 0.0f ? + box.max.y - sph.center.y : + sph.center.y - box.min.y; + float dz = dist.z > 0.0f ? + box.max.z - sph.center.z : + sph.center.z - box.min.z; + // collision depth is maximum of that: + if(dx > dy && dx > dz) + point.depth = dx; + else if(dy > dz) + point.depth = dy; + else + point.depth = dz; + return true; + } + }else{ + // sphere is outside. + // closest point on box: + p.x = xpos == 1 ? box.min.x : + xpos == 2 ? box.max.x : + sph.center.x; + p.y = ypos == 1 ? box.min.y : + ypos == 2 ? box.max.y : + sph.center.y; + p.z = zpos == 1 ? box.min.z : + zpos == 2 ? box.max.z : + sph.center.z; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + float len = sqrt(lensq); + point.point = p; + point.normal = dist * (1.0f/len); + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; + point.depth = sph.radius - len; + mindistsq = lensq; + return true; + } + } + return false; +} + +bool +CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) +{ + float mint, t, x, y, z; + CVector normal; + CVector p; + + mint = 1.0f; + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.min.x, y, z); + normal = CVector(-1.0f, 0.0f, 0.0f); + } + } + } + + // max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.max.x, y, z); + normal = CVector(1.0f, 0.0f, 0.0f); + } + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.min.y, z); + normal = CVector(0.0f, -1.0f, 0.0f); + } + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.max.y, z); + normal = CVector(0.0f, 1.0f, 0.0f); + } + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.min.z); + normal = CVector(0.0f, 0.0f, -1.0f); + } + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.max.z); + normal = CVector(0.0f, 0.0f, 1.0f); + } + } + } + + if(mint >= mindist) + return false; + + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = box.surface; + point.pieceB = box.piece; + mindist = mint; + + return true; +} + +// If line.p0 lies inside sphere, no collision is registered. +bool +CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) +{ + CVector v01 = line.p1 - line.p0; + CVector v0c = sphere.center - line.p0; + float linesq = v01.MagnitudeSqr(); + // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections + float projline = DotProduct(v01, v0c); + // tangent of p0 to sphere, scaled by linesq just like projline^2 + float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; + // this works out to be the square of the distance between the midpoint and the intersections + float diffsq = projline*projline - tansq; + // no intersection + if(diffsq < 0.0f) + return false; + // point of first intersection, in range [0,1] between p0 and p1 + float t = (projline - sqrt(diffsq)) / linesq; + // if not on line or beyond mindist, no intersection + if(t < 0.0f || t > 1.0f || t >= mindist) + return false; + point.point = line.p0 + v01*t; + point.normal = point.point - sphere.center; + point.normal.Normalise(); + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = sphere.surface; + point.pieceB = sphere.piece; + mindist = t; + return true; +} + +bool +CCollision::ProcessVerticalLineTriangle(const CColLine &line, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist, CStoredCollPoly *poly) +{ + float t; + CVector normal; + + const CVector &p0 = line.p0; + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // early out bound rect test + if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; + if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; + if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; + if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; + + plane.GetNormal(normal); + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + float h = (line.p1 - p0).z; + t = -plane.CalcPoint(p0) / (h * normal.z); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + CVector p(p0.x, p0.y, p0.z + h*t); + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + if(poly){ + poly->verts[0] = va; + poly->verts[1] = vb; + poly->verts[2] = vc; + poly->valid = true; + } + mindist = t; + return true; +} + +bool +CCollision::ProcessLineTriangle(const CColLine &line , + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist) +{ + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + CVector2D vec1, vec2, vec3, vect; + + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + mindist = t; + return true; +} + +bool +CCollision::ProcessSphereTriangle(const CColSphere &sphere, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindistsq) +{ + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + float distsq = planedist*planedist; + if(fabs(planedist) > sphere.radius || distsq > mindistsq) + return false; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // calculate two orthogonal basis vectors for the triangle + CVector normal; + plane.GetNormal(normal); + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + CVector p; + if(testcase == 1){ + // closest to a vertex + if(insideAB) p = vc; + else if(insideAC) p = vb; + else if(insideBC) p = va; + else assert(0); + dist = (sphere.center - p).Magnitude(); + }else if(testcase == 2){ + // closest to an edge + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); + else assert(0); + }else if(testcase == 3){ + // center is in triangle + dist = fabs(planedist); + p = sphere.center - normal*planedist; + }else + assert(0); // front fell off + + if(dist >= sphere.radius || dist*dist >= mindistsq) + return false; + + point.point = p; + point.normal = sphere.center - p; + point.normal.Normalise(); + point.surfaceA = sphere.surface; + point.pieceA = sphere.piece; + point.surfaceB = tri.surface; + point.pieceB = 0; + point.depth = sphere.radius - dist; + mindistsq = dist*dist; + return true; +} + +bool +CCollision::ProcessLineOfSight(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSurf78) +{ + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8) + ProcessLineSphere(newline, model.spheres[i], point, coldist); + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8) + ProcessLineBox(newline, model.boxes[i], point, coldist); + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8) + ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist = coldist; + return true; + } + return false; +} + +bool +CCollision::ProcessVerticalLine(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSurf78, CStoredCollPoly *poly) +{ + static CStoredCollPoly TempStoredPoly; + int i; + + // transform line to model space + // Why does the game seem to do this differently than above? + CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); + newline.p1.x = newline.p0.x; + newline.p1.y = newline.p0.y; + + if(!TestVerticalLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8) + ProcessLineSphere(newline, model.spheres[i], point, coldist); + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8) + ProcessLineBox(newline, model.boxes[i], point, coldist); + + CalculateTrianglePlanes(&model); + TempStoredPoly.valid = false; + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8) + ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + if(poly && TempStoredPoly.valid){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * poly->verts[0]; + poly->verts[1] = matrix * poly->verts[1]; + poly->verts[2] = matrix * poly->verts[2]; + } + mindist = coldist; + return true; + } + return false; +} + +enum { + MAXNUMSPHERES = 128, + MAXNUMBOXES = 32, + MAXNUMLINES = 16, + MAXNUMTRIS = 600 +}; + +// This checks model A's spheres and lines against model B's spheres, boxes and triangles. +// Returns the number of A's spheres that collide. +// Returned ColPoints are in world space. +// NB: lines do not seem to be supported very well, use with caution +int32 +CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, + const CMatrix &matrixB, CColModel &modelB, + CColPoint *spherepoints, CColPoint *linepoints, float *linedists) +{ + static int aSphereIndicesA[MAXNUMSPHERES]; + static int aLineIndicesA[MAXNUMLINES]; + static int aSphereIndicesB[MAXNUMSPHERES]; + static int aBoxIndicesB[MAXNUMBOXES]; + static int aTriangleIndicesB[MAXNUMTRIS]; + static bool aCollided[MAXNUMLINES]; + static CColSphere aSpheresA[MAXNUMSPHERES]; + static CColLine aLinesA[MAXNUMLINES]; + static CMatrix matAB, matBA; + CColSphere s; + int i, j; + + assert(modelA.numSpheres <= MAXNUMSPHERES); + assert(modelA.numLines <= MAXNUMLINES); + + // From model A space to model B space + matAB = Invert(matrixB, matAB) * matrixA; + + CColSphere bsphereAB; // bounding sphere of A in B space + bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); + if(!TestSphereBox(bsphereAB, modelB.boundingBox)) + return 0; + // B to A space + matBA = Invert(matrixA, matBA) * matrixB; + + // transform modelA's spheres and lines to B space + for(i = 0; i < modelA.numSpheres; i++){ + CColSphere &s = modelA.spheres[i]; + aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); + } + for(i = 0; i < modelA.numLines; i++) + aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + int numLinesA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // no actual check??? + for(i = 0; i < modelA.numLines; i++) + aLineIndicesA[numLinesA++] = i; + // No collision + if(numSpheresA == 0 && numLinesA == 0) + return 0; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++){ + s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); + if(TestSphereBox(s, modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + } + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + for(i = 0; i < modelB.numTriangles; i++) + if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) + aTriangleIndicesB[numTrianglesB++] = i; + assert(numSpheresB <= MAXNUMSPHERES); + assert(numBoxesB <= MAXNUMBOXES); + assert(numTrianglesB <= MAXNUMTRIS); + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + + for(j = 0; j < numSpheresB; j++) + hasCollided |= ProcessSphereSphere( + aSpheresA[aSphereIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numBoxesB; j++) + hasCollided |= ProcessSphereBox( + aSpheresA[aSphereIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numTrianglesB; j++) + hasCollided |= ProcessSphereTriangle( + aSpheresA[aSphereIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + spherepoints[numCollisions], coldist); + if(hasCollided) + numCollisions++; + } + for(i = 0; i < numCollisions; i++){ + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < numLinesA; i++){ + aCollided[i] = false; + + for(j = 0; j < numSpheresB; j++) + aCollided[i] |= ProcessLineSphere( + aLinesA[aLineIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numBoxesB; j++) + aCollided[i] |= ProcessLineBox( + aLinesA[aLineIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numTrianglesB; j++) + aCollided[i] |= ProcessLineTriangle( + aLinesA[aLineIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + } + for(i = 0; i < numLinesA; i++) + if(aCollided[i]){ + j = aLineIndicesA[i]; + linepoints[j].point = matrixB * linepoints[j].point; + linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); + } + + return numCollisions; // sphere collisions +} + + +// +// Misc +// + +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // Between 0 and len we're above the line. + // if not, calculate distance to endpoint + if(dot <= 0.0f) + return (*point - *l0).Magnitude(); + if(dot >= lensq) + return (*point - *l1).Magnitude(); + // distance to line + return sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); +} + +// same as above but also return the point on the line +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // find out which point we're closest to + if(dot <= 0.0f) + closest = *l0; + else if(dot >= lensq) + closest = *l1; + else + closest = *l0 + (*l1 - *l0)*(dot/lensq); + // this is the distance + return (*point - closest).Magnitude(); +} + +void +CCollision::CalculateTrianglePlanes(CColModel *model) +{ + if(model->numTriangles == 0) + return; + + CLink *lptr; + if(model->trianglePlanes){ + // re-insert at front so it's not removed again soon + lptr = model->GetLinkPtr(); + lptr->Remove(); + ms_colModelCache.head.Insert(lptr); + }else{ + assert(model); + lptr = ms_colModelCache.Insert(model); + if(lptr == nil){ + // make room if we have to, remove last in list + lptr = ms_colModelCache.tail.prev; + assert(lptr); + assert(lptr->item); + lptr->item->RemoveTrianglePlanes(); + ms_colModelCache.Remove(lptr); + // now this cannot fail + lptr = ms_colModelCache.Insert(model); + assert(lptr); + } + model->CalculateTrianglePlanes(); + model->SetLinkPtr(lptr); + } +} + +void +CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) +{ +} + +void +CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) +{ + int i; + int s; + float f; + CVector verts[8]; + CVector min, max; + int r, g, b; + RwImVertexIndex *iptr; + RwIm3DVertex *vptr; + + RenderBuffer::ClearRenderBuffer(); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + + // TODO: surface + r = 255; + g = 128; + b = 0; + + s = colModel.triangles[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + // TODO: make some surface types flicker? + + if(s > SURFACE_32){ + r = CGeneral::GetRandomNumber(); + g = CGeneral::GetRandomNumber(); + b = CGeneral::GetRandomNumber(); + printf("Illegal surfacetype:%d on MI:%d\n", s, id); + } + + RenderBuffer::StartStoring(6, 3, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; + RenderBuffer::StopStoring(); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + s = colModel.boxes[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + // TODO: make some surface types flicker? + + RenderBuffer::StartStoring(36, 8, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetU(&vptr[3], 0.0f); + RwIm3DVertexSetV(&vptr[3], 0.0f); + RwIm3DVertexSetU(&vptr[4], 0.0f); + RwIm3DVertexSetV(&vptr[4], 1.0f); + RwIm3DVertexSetU(&vptr[5], 1.0f); + RwIm3DVertexSetV(&vptr[5], 1.0f); + RwIm3DVertexSetU(&vptr[6], 0.0f); + RwIm3DVertexSetV(&vptr[6], 1.0f); + RwIm3DVertexSetU(&vptr[7], 1.0f); + RwIm3DVertexSetV(&vptr[7], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); + RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); + RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); + RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); + RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; + iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; + iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; + iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; + iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; + iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; + iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; + iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; + iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; + iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; + iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; + RenderBuffer::StopStoring(); + } + + RenderBuffer::RenderStuffInBuffer(); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} + + +/* + * ColModel code + */ + +void +CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) +{ + this->radius = radius; + this->center = center; + this->surface = surf; + this->piece = piece; +} + +void +CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) +{ + this->min = min; + this->max = max; + this->surface = surf; + this->piece = piece; +} + +void +CColLine::Set(const CVector &p0, const CVector &p1) +{ + this->p0 = p0; + this->p1 = p1; +} + +void +CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece) +{ + this->a = a; + this->b = b; + this->c = c; + this->surface = surf; +} + +void +CColTrianglePlane::Set(const CVector *v, CColTriangle &tri) +{ + const CVector &va = v[tri.a]; + const CVector &vb = v[tri.b]; + const CVector &vc = v[tri.c]; + + normal = CrossProduct(vc-va, vb-va); + normal.Normalise(); + dist = DotProduct(normal, va); + CVector an(fabs(normal.x), fabs(normal.y), fabs(normal.z)); + // find out largest component and its direction + if(an.x > an.y && an.x > an.z) + dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; + else if(an.y > an.z) + dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; + else + dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; +} + +CColModel::CColModel(void) +{ + numSpheres = 0; + spheres = nil; + numLines = 0; + lines = nil; + numBoxes = 0; + boxes = nil; + numTriangles = 0; + vertices = nil; + triangles = nil; + trianglePlanes = nil; + level = CGame::currLevel; + ownsCollisionVolumes = true; +} + +CColModel::~CColModel(void) +{ + RemoveCollisionVolumes(); + RemoveTrianglePlanes(); +} + +void +CColModel::RemoveCollisionVolumes(void) +{ + if(ownsCollisionVolumes){ + RwFree(spheres); + RwFree(lines); + RwFree(boxes); + RwFree(vertices); + RwFree(triangles); + } + numSpheres = 0; + numLines = 0; + numBoxes = 0; + numTriangles = 0; + spheres = nil; + lines = nil; + boxes = nil; + vertices = nil; + triangles = nil; +} + +void +CColModel::CalculateTrianglePlanes(void) +{ + // HACK: allocate space for one more element to stuff the link pointer into + trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); + for(int i = 0; i < numTriangles; i++) + trianglePlanes[i].Set(vertices, triangles[i]); +} + +void +CColModel::RemoveTrianglePlanes(void) +{ + RwFree(trianglePlanes); + trianglePlanes = nil; +} + +void +CColModel::SetLinkPtr(CLink *lptr) +{ + assert(trianglePlanes); + *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; +} + +CLink* +CColModel::GetLinkPtr(void) +{ + assert(trianglePlanes); + return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); +} + +void +CColModel::GetTrianglePoint(CVector &v, int i) const +{ + v = vertices[i]; +} + +STARTPATCHES + InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP); + + InjectHook(0x40BB70, CCollision::TestSphereBox, PATCH_JUMP); + InjectHook(0x40E130, CCollision::TestLineBox, PATCH_JUMP); + InjectHook(0x40E5C0, CCollision::TestVerticalLineBox, PATCH_JUMP); + InjectHook(0x40EC10, CCollision::TestLineTriangle, PATCH_JUMP); + InjectHook(0x40DAA0, CCollision::TestLineSphere, PATCH_JUMP); + InjectHook(0x40C580, CCollision::TestSphereTriangle, PATCH_JUMP); + InjectHook(0x40F720, CCollision::TestLineOfSight, PATCH_JUMP); + + InjectHook(0x40B9F0, CCollision::ProcessSphereSphere, PATCH_JUMP); + InjectHook(0x40BC00, CCollision::ProcessSphereBox, PATCH_JUMP); + InjectHook(0x40E670, CCollision::ProcessLineBox, PATCH_JUMP); + InjectHook(0x40DE80, CCollision::ProcessLineSphere, PATCH_JUMP); + InjectHook(0x40FB50, CCollision::ProcessVerticalLineTriangle, PATCH_JUMP); + InjectHook(0x40F140, CCollision::ProcessLineTriangle, PATCH_JUMP); + InjectHook(0x40CE30, CCollision::ProcessSphereTriangle, PATCH_JUMP); + + InjectHook(0x40F910, CCollision::ProcessLineOfSight, PATCH_JUMP); + InjectHook(0x410120, CCollision::ProcessVerticalLine, PATCH_JUMP); + InjectHook(0x410BE0, CCollision::ProcessColModels, PATCH_JUMP); + + InjectHook(0x40B960, CCollision::CalculateTrianglePlanes, PATCH_JUMP); + InjectHook(0x411640, &CLink::Remove, PATCH_JUMP); + InjectHook(0x411620, &CLink::Insert, PATCH_JUMP); + InjectHook(0x4115C0, &CLinkList::Insert, PATCH_JUMP); + InjectHook(0x411600, &CLinkList::Remove, PATCH_JUMP); +// InjectHook(0x411530, &CLinkList::Init, PATCH_JUMP); + + InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP); + InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP); + InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP); + InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP); + InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP); + + InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP); + InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP); + + InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP); + InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP); + InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP); + InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP); + InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP); + InjectHook(0x411D40, &CColModel::SetLinkPtr, PATCH_JUMP); + InjectHook(0x411D60, &CColModel::GetLinkPtr, PATCH_JUMP); +ENDPATCHES diff --git a/src/Collision.h b/src/Collision.h new file mode 100644 index 00000000..9d23524f --- /dev/null +++ b/src/Collision.h @@ -0,0 +1,152 @@ +#pragma once + +#include "templates.h" +#include "Game.h" // for eLevelName + +struct CColSphere +{ + CVector center; + float radius; + uint8 surface; + uint8 piece; + + void Set(float radius, const CVector ¢er, uint8 surf, uint8 piece); + void Set(float radius, const CVector ¢er) { this->center = center; this->radius = radius; } +}; + +struct CColBox +{ + CVector min; + CVector max; + uint8 surface; + uint8 piece; + + void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece); +}; + +struct CColLine +{ + CVector p0; + int pad0; + CVector p1; + int pad1; + + CColLine(void) { }; + CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; + void Set(const CVector &p0, const CVector &p1); + + CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); } +}; + +struct CColTriangle +{ + uint16 a; + uint16 b; + uint16 c; + uint8 surface; + + void Set(const CVector *v, int a, int b, int c, uint8 surf, uint8 piece); +}; + +struct CColTrianglePlane +{ + CVector normal; + float dist; + uint8 dir; + + void Set(const CVector *v, CColTriangle &tri); + void GetNormal(CVector &n) const { n = normal; } + float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; +}; + +struct CColPoint +{ + CVector point; + int pad1; + // the surface normal on the surface of point + CVector normal; + int pad2; + uint8 surfaceA; + uint8 pieceA; + uint8 surfaceB; + uint8 pieceB; + float depth; +}; + +struct CStoredCollPoly +{ + CVector verts[3]; + bool valid; +}; + +struct CColModel +{ + CColSphere boundingSphere; + CColBox boundingBox; + short numSpheres; + short numLines; + short numBoxes; + short numTriangles; + int level; + bool ownsCollisionVolumes; + CColSphere *spheres; + CColLine *lines; + CColBox *boxes; + CVector *vertices; + CColTriangle *triangles; + CColTrianglePlane *trianglePlanes; + + CColModel(void); + ~CColModel(void); + void RemoveCollisionVolumes(void); + void CalculateTrianglePlanes(void); + void RemoveTrianglePlanes(void); + CLink *GetLinkPtr(void); + void SetLinkPtr(CLink*); + void GetTrianglePoint(CVector &v, int i) const; + + CColModel *ctor(void) { return ::new (this) CColModel(); } + void dtor(void) { this->CColModel::~CColModel(); } +}; + +class CCollision +{ +public: + static eLevelName &ms_collisionInMemory; + static CLinkList &ms_colModelCache; + + static void Init(void); + static void Update(void); + static void LoadCollisionWhenINeedIt(bool changeLevel); + static void DrawColModel(const CMatrix &mat, const CColModel &colModel); + static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); + + static void CalculateTrianglePlanes(CColModel *model); + + // all these return true if there's a collision + static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); + static bool TestSphereBox(const CColSphere &sph, const CColBox &box); + static bool TestLineBox(const CColLine &line, const CColBox &box); + static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); + static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineSphere(const CColLine &line, const CColSphere &sph); + static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineOfSight(CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSurf78); + + static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); + static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); + static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); + static bool ProcessVerticalLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); + static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); + static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); + static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); + static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSurf78); + static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSurf78, CStoredCollPoly *poly); + static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists); + + // TODO: + // CCollision::IsStoredPolyStillValidVerticalLine + + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); +}; diff --git a/src/CullZones.cpp b/src/CullZones.cpp new file mode 100644 index 00000000..dc30790b --- /dev/null +++ b/src/CullZones.cpp @@ -0,0 +1,323 @@ +#include "common.h" +#include "patcher.h" +#include "Building.h" +#include "Treadable.h" +#include "Pools.h" +#include "Timer.h" +#include "Camera.h" +#include "World.h" +#include "CullZones.h" + +int32 &CCullZones::NumCullZones = *(int*)0x8F2564; +CCullZone *CCullZones::aZones = (CCullZone*)0x864750; // [NUMCULLZONES]; +int32 &CCullZones::NumAttributeZones = *(int*)0x8E29D0; +CAttributeZone *CCullZones::aAttributeZones = (CAttributeZone*)0x709C60; // [NUMATTRIBZONES]; +uint16 *CCullZones::aIndices = (uint16*)0x847330; // [NUMZONEINDICES]; +int16 *CCullZones::aPointersToBigBuildingsForBuildings = (int16*)0x86C9D0; // [NUMBUILDINGS]; +int16 *CCullZones::aPointersToBigBuildingsForTreadables = (int16*)0x8F1B8C; // [NUMTREADABLES]; + +int32 &CCullZones::CurrentWantedLevelDrop_Player = *(int32*)0x880DA8; +int32 &CCullZones::CurrentFlags_Camera = *(int32*)0x940718; +int32 &CCullZones::CurrentFlags_Player = *(int32*)0x9415F0; +int32 &CCullZones::OldCullZone = *(int32*)0x8E2C90; +int32 &CCullZones::EntityIndicesUsed = *(int32*)0x8F2508; +bool &CCullZones::bCurrentSubwayIsInvisible = *(bool*)0x95CDA5; +bool &CCullZones::bCullZonesDisabled = *(bool*)0x95CD4A; + + +void +CCullZones::Init(void) +{ + int i; + + NumAttributeZones = 0; + NumCullZones = 0; + CurrentWantedLevelDrop_Player = 0; + CurrentFlags_Camera = 0; + CurrentFlags_Player = 0; + OldCullZone = -1; + EntityIndicesUsed = 0; + bCurrentSubwayIsInvisible = false; + + for(i = 0; i < NUMBUILDINGS; i++) + aPointersToBigBuildingsForBuildings[i] = -1; + for(i = 0; i < NUMTREADABLES; i++) + aPointersToBigBuildingsForTreadables[i] = -1; +} + +void +CCullZones::Update(void) +{ + bool invisible; + CVector v; + + if(bCullZonesDisabled) + return; + + switch(CTimer::GetFrameCounter() & 7){ + case 0: + case 4: + /* Update Cull zone */ + ForceCullZoneCoors(TheCamera.GetGameCamPosition()); + break; + + case 2: + /* Update camera attributes */ + CurrentFlags_Camera = FindAttributesForCoors(TheCamera.GetGameCamPosition(), nil); + invisible = (CurrentFlags_Camera & ATTRZONE_SUBWAYVISIBLE) == 0; + if(invisible != bCurrentSubwayIsInvisible){ + MarkSubwayAsInvisible(!invisible); + bCurrentSubwayIsInvisible = invisible; + } + break; + + case 6: + /* Update player attributes */ + CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(v), + &CurrentWantedLevelDrop_Player); + break; + } +} + +void +CCullZones::ForceCullZoneCoors(CVector coors) +{ + int32 z; + z = FindCullZoneForCoors(coors); + if(z != OldCullZone){ + if(OldCullZone >= 0) + aZones[OldCullZone].DoStuffLeavingZone(); + if(z >= 0) + aZones[z].DoStuffEnteringZone(); + OldCullZone = z; + } +} + +int32 +CCullZones::FindCullZoneForCoors(CVector coors) +{ + int i; + + for(i = 0; i < NumCullZones; i++) + if(coors.x >= aZones[i].minx && coors.x <= aZones[i].maxx && + coors.y >= aZones[i].miny && coors.y <= aZones[i].maxy && + coors.z >= aZones[i].minz && coors.z <= aZones[i].maxz) + return i; + return -1; +} + +int32 +CCullZones::FindAttributesForCoors(CVector coors, int32 *wantedLevel) +{ + int i; + int32 attribs; + + attribs = 0; + for(i = 0; i < NumAttributeZones; i++) + if(coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && + coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && + coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz){ + attribs |= aAttributeZones[i].attributes; + if(wantedLevel && *wantedLevel <= aAttributeZones[i].wantedLevel) + *wantedLevel = aAttributeZones[i].wantedLevel; + } + return attribs; +} + +CAttributeZone* +CCullZones::FindZoneWithStairsAttributeForPlayer(void) +{ + int i; + CVector coors; + + FindPlayerCoors(coors); + for(i = 0; i < NumAttributeZones; i++) + if(aAttributeZones[i].attributes & ATTRZONE_STAIRS && + coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && + coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && + coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz) + return &aAttributeZones[i]; + return nil; +} + +WRAPPER void +CCullZones::MarkSubwayAsInvisible(bool visible) +{ EAXJMP(0x525AF0); +} + +void +CCullZones::AddCullZone(CVector const &position, + float minx, float maxx, + float miny, float maxy, + float minz, float maxz, + uint16 flag, int16 wantedLevel) +{ + CCullZone *cull; + CAttributeZone *attrib; + + CVector v; + if((flag & ATTRZONE_NOTCULLZONE) == 0){ + cull = &aZones[NumCullZones++]; + v = position; + // WTF is this? + if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f) + v = CVector(1061.7f, -613.0f, 19.0f); + if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f) + v = CVector(1061.4f, -506.0f, 18.5f); + cull->position.x = clamp(v.x, minx, maxx); + cull->position.y = clamp(v.y, miny, maxy); + cull->position.z = clamp(v.z, minz, maxz); + cull->minx = minx; + cull->maxx = maxx; + cull->miny = miny; + cull->maxy = maxy; + cull->minz = minz; + cull->maxz = maxz; + cull->unk2 = 0; + cull->unk3 = 0; + cull->unk4 = 0; + cull->m_indexStart = 0; + } + if(flag & ~ATTRZONE_NOTCULLZONE){ + attrib = &aAttributeZones[NumAttributeZones++]; + attrib->minx = minx; + attrib->maxx = maxx; + attrib->miny = miny; + attrib->maxy = maxy; + attrib->minz = minz; + attrib->maxz = maxz; + attrib->attributes = flag; + attrib->wantedLevel = wantedLevel; + } +} + + + +void +CCullZone::DoStuffLeavingZone(void) +{ + int i; + + for(i = 0; i < m_numBuildings; i++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables ; i++) + DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[m_indexStart + i]); +} + +void +CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetBuildingPool()->GetSlot(i)->m_bZoneCulled = false; + bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->m_bZoneCulled = false; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled = false; + CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled2 = false; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->m_bZoneCulled = false; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone(void) +{ + int i; + + for(i = 0; i < m_numBuildings; i++) + DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m; i++) + DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables; i++) + DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[m_indexStart + i]); +} + +void +CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetBuildingPool()->GetSlot(i)->m_bZoneCulled = true; + bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->m_bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled = true;; + CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled2 = true;; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->m_bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->m_bZoneCulled = true;; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->m_bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +STARTPATCHES + InjectHook(0x524BC0, &CCullZones::Init, PATCH_JUMP); + InjectHook(0x524F80, &CCullZones::Update, PATCH_JUMP); + InjectHook(0x525370, &CCullZones::AddCullZone, PATCH_JUMP); + InjectHook(0x5250D0, &CCullZones::ForceCullZoneCoors, PATCH_JUMP); + InjectHook(0x525130, &CCullZones::FindCullZoneForCoors, PATCH_JUMP); + InjectHook(0x5251C0, &CCullZones::FindAttributesForCoors, PATCH_JUMP); + InjectHook(0x525290, &CCullZones::FindZoneWithStairsAttributeForPlayer, PATCH_JUMP); + + InjectHook(0x525610, &CCullZone::DoStuffLeavingZone, PATCH_JUMP); + InjectHook(0x525810, &CCullZone::DoStuffEnteringZone, PATCH_JUMP); +ENDPATCHES diff --git a/src/CullZones.h b/src/CullZones.h new file mode 100644 index 00000000..4641f6ad --- /dev/null +++ b/src/CullZones.h @@ -0,0 +1,93 @@ +class CCullZone +{ +public: + CVector position; + float minx; + float maxx; + float miny; + float maxy; + float minz; + float maxz; + + // TODO: figure these out: + int32 m_indexStart; + int16 unk2; + int16 unk3; + int16 unk4; + int16 m_numBuildings; + int16 m_numTreadablesPlus10m; + int16 m_numTreadables; + + void DoStuffLeavingZone(void); + static void DoStuffLeavingZone_OneBuilding(uint16 i); + static void DoStuffLeavingZone_OneTreadableBoth(uint16 i); + void DoStuffEnteringZone(void); + static void DoStuffEnteringZone_OneBuilding(uint16 i); + static void DoStuffEnteringZone_OneTreadablePlus10m(uint16 i); + static void DoStuffEnteringZone_OneTreadable(uint16 i); +}; + +enum eZoneAttribs +{ + ATTRZONE_CAMCLOSEIN = 1, + ATTRZONE_STAIRS = 2, + ATTRZONE_1STPERSON = 4, + ATTRZONE_NORAIN = 8, + ATTRZONE_NOPOLICE = 0x10, + ATTRZONE_NOTCULLZONE = 0x20, + ATTRZONE_DOINEEDCOLLISION = 0x40, + ATTRZONE_SUBWAYVISIBLE = 0x80, +}; + +struct CAttributeZone +{ + float minx; + float maxx; + float miny; + float maxy; + float minz; + float maxz; + int16 attributes; + int16 wantedLevel; +}; + +class CCullZones +{ +public: + static int32 &NumCullZones; + static CCullZone *aZones; // [NUMCULLZONES]; + static int32 &NumAttributeZones; + static CAttributeZone *aAttributeZones; // [NUMATTRIBZONES]; + static uint16 *aIndices; // [NUMZONEINDICES]; + static int16 *aPointersToBigBuildingsForBuildings; // [NUMBUILDINGS]; + static int16 *aPointersToBigBuildingsForTreadables; // [NUMTREADABLES]; + + static int32 &CurrentWantedLevelDrop_Player; + static int32 &CurrentFlags_Camera; + static int32 &CurrentFlags_Player; + static int32 &OldCullZone; + static int32 &EntityIndicesUsed; + static bool &bCurrentSubwayIsInvisible; + static bool &bCullZonesDisabled; + + static void Init(void); + static void Update(void); + static void ForceCullZoneCoors(CVector coors); + static int32 FindCullZoneForCoors(CVector coors); + static int32 FindAttributesForCoors(CVector coors, int32 *wantedLevel); + static CAttributeZone *FindZoneWithStairsAttributeForPlayer(void); + static void MarkSubwayAsInvisible(bool visible); + static void AddCullZone(CVector const &position, + float minx, float maxx, + float miny, float maxy, + float minz, float maxz, + uint16 flag, int16 wantedLevel); + static bool CamCloseInForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_CAMCLOSEIN) != 0; } + static bool CamStairsForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_STAIRS) != 0; } + static bool Cam1stPersonForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_1STPERSON) != 0; } + static bool NoPolice(void) { return (CurrentFlags_Player & ATTRZONE_NOPOLICE) != 0; } + static bool DoINeedToLoadCollision(void) { return (CurrentFlags_Player & ATTRZONE_DOINEEDCOLLISION) != 0; } + static bool PlayerNoRain(void) { return (CurrentFlags_Player & ATTRZONE_NORAIN) != 0; } + static bool CamNoRain(void) { return (CurrentFlags_Camera & ATTRZONE_NORAIN) != 0; } + static int32 GetWantedLevelDrop(void) { return CurrentWantedLevelDrop_Player; } +}; diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 00000000..7f9d86a0 --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "Game.h" + +int &CGame::currLevel = *(int*)0x941514; diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 00000000..83a51fab --- /dev/null +++ b/src/Game.h @@ -0,0 +1,15 @@ +#pragma once + +enum eLevelName +{ + LEVEL_NONE = 0, + LEVEL_INDUSTRIAL, + LEVEL_COMMERCIAL, + LEVEL_SUBURBAN +}; + +class CGame +{ +public: + static int &currLevel; +}; diff --git a/src/General.h b/src/General.h new file mode 100644 index 00000000..7aacee39 --- /dev/null +++ b/src/General.h @@ -0,0 +1,15 @@ +class CGeneral +{ +public: + static float GetATanOfXY(float x, float y){ + if(y >= 0.0f) return atan2(x, y); + return atan2(x, y) + 2*M_PI; + } + + // not too sure about all these... + static uint16 GetRandomNumber(void) + { return myrand() & 0xFFFF; } + // Probably don't want to ever reach high + static float GetRandomNumberInRange(float low, float high) + { return low + (high - low)*(GetRandomNumber()/65536.0f); } +}; diff --git a/src/Glass.cpp b/src/Glass.cpp new file mode 100644 index 00000000..7b02cb6c --- /dev/null +++ b/src/Glass.cpp @@ -0,0 +1,15 @@ +#include "common.h" +#include "patcher.h" +#include "Glass.h" + +WRAPPER void +CGlass::WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo) +{ + EAXJMP(0x503F10); +} + +WRAPPER void +CGlass::WindowRespondsToSoftCollision(CEntity *ent, float amount) +{ + EAXJMP(0x504630); +} diff --git a/src/Glass.h b/src/Glass.h new file mode 100644 index 00000000..5347467b --- /dev/null +++ b/src/Glass.h @@ -0,0 +1,10 @@ +#pragma once + +class CEntity; + +class CGlass +{ +public: + static void WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo); + static void WindowRespondsToSoftCollision(CEntity *ent, float amount); +}; diff --git a/src/Lists.cpp b/src/Lists.cpp new file mode 100644 index 00000000..448a0ff1 --- /dev/null +++ b/src/Lists.cpp @@ -0,0 +1,26 @@ +#include "common.h" +#include "Pools.h" +#include "Lists.h" + +void* +CPtrNode::operator new(size_t){ + CPtrNode *node = CPools::GetPtrNodePool()->New(); + assert(node); + return node; +} + +void +CPtrNode::operator delete(void *p, size_t){ + CPools::GetPtrNodePool()->Delete((CPtrNode*)p); +} + +void* +CEntryInfoNode::operator new(size_t){ + CEntryInfoNode *node = CPools::GetEntryInfoNodePool()->New(); + assert(node); + return node; +} +void +CEntryInfoNode::operator delete(void *p, size_t){ + CPools::GetEntryInfoNodePool()->Delete((CEntryInfoNode*)p); +} diff --git a/src/Lists.h b/src/Lists.h new file mode 100644 index 00000000..7572e882 --- /dev/null +++ b/src/Lists.h @@ -0,0 +1,130 @@ +#pragma once + +class CPtrNode +{ +public: + void *item; + CPtrNode *prev; + CPtrNode *next; + + void *operator new(size_t); + void operator delete(void *p, size_t); +}; + +class CPtrList +{ +public: + CPtrNode *first; + + CPtrList(void) { first = nil; } + ~CPtrList(void) { Flush(); } + CPtrNode *FindItem(void *item){ + CPtrNode *node; + for(node = first; node; node = node->next) + if(node->item == item) + return node; + return nil; + } + CPtrNode *InsertNode(CPtrNode *node){ + node->prev = nil; + node->next = first; + if(first) + first->prev = node; + first = node; + return node; + } + CPtrNode *InsertItem(void *item){ + CPtrNode *node = new CPtrNode; + node->item = item; + InsertNode(node); + return node; + } + void RemoveNode(CPtrNode *node){ + if(node == first) + first = node->next; + if(node->prev) + node->prev->next = node->next; + if(node->next) + node->next->prev = node->prev; + } + void DeleteNode(CPtrNode *node){ + RemoveNode(node); + delete node; + } + void RemoveItem(void *item){ + CPtrNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + if(node->item == item) + DeleteNode(node); + } + } + void Flush(void){ + CPtrNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + DeleteNode(node); + } + } +}; + +class CSector; + +// This records in which sector list a Physical is +class CEntryInfoNode +{ +public: + CPtrList *list; // list in sector + CPtrNode *listnode; // node in list + CSector *sector; + + CEntryInfoNode *prev; + CEntryInfoNode *next; + + void *operator new(size_t); + void operator delete(void *p, size_t); +}; + +class CEntryInfoList +{ +public: + CEntryInfoNode *first; + + CEntryInfoList(void) { first = nil; } + ~CEntryInfoList(void) { Flush(); } + CEntryInfoNode *InsertNode(CEntryInfoNode *node){ + node->prev = nil; + node->next = first; + if(first) + first->prev = node; + first = node; + return node; + } + CEntryInfoNode *InsertItem(CPtrList *list, CPtrNode *listnode, CSector *sect){ + CEntryInfoNode *node = new CEntryInfoNode; + node->list = list; + node->listnode = listnode; + node->sector = sect; + InsertNode(node); + return node; + } + void RemoveNode(CEntryInfoNode *node){ + if(node == first) + first = node->next; + if(node->prev) + node->prev->next = node->next; + if(node->next) + node->next->prev = node->prev; + } + void DeleteNode(CEntryInfoNode *node){ + RemoveNode(node); + delete node; + } + void Flush(void){ + CEntryInfoNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + DeleteNode(node); + } + } +}; diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp new file mode 100644 index 00000000..0e335546 --- /dev/null +++ b/src/MenuManager.cpp @@ -0,0 +1,4 @@ +#include "common.h" +#include "MenuManager.h" + +int &CMenuManager::m_PrefsBrightness = *(int*)0x5F2E50; diff --git a/src/MenuManager.h b/src/MenuManager.h new file mode 100644 index 00000000..803e4d8d --- /dev/null +++ b/src/MenuManager.h @@ -0,0 +1,5 @@ +class CMenuManager +{ +public: + static int &m_PrefsBrightness; +}; diff --git a/src/NodeName.cpp b/src/NodeName.cpp new file mode 100644 index 00000000..c2ffe048 --- /dev/null +++ b/src/NodeName.cpp @@ -0,0 +1,15 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" + +int &gPluginOffset = *(int*)0x64C610; + +#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset)) + +char* +GetFrameNodeName(RwFrame *frame) +{ + if(gPluginOffset < 0) + return nil; + return NODENAMEEXT(frame); +} diff --git a/src/NodeName.h b/src/NodeName.h new file mode 100644 index 00000000..a4dcf0cf --- /dev/null +++ b/src/NodeName.h @@ -0,0 +1,3 @@ +#pragma once + +char *GetFrameNodeName(RwFrame *frame); diff --git a/src/Pad.cpp b/src/Pad.cpp new file mode 100644 index 00000000..ab6bf154 --- /dev/null +++ b/src/Pad.cpp @@ -0,0 +1,37 @@ +#include "common.h" +#include "Pad.h" + +CPad *CPad::Pads = (CPad*)0x6F0360; + +uint16 *CPad::OldKeyState = (uint16*)0x6F1E70; +uint16 *CPad::NewKeyState = (uint16*)0x6E60D0; +uint16 *CPad::TempKeyState = (uint16*)0x774DE8; + +CMouseControllerState &CPad::OldMouseControllerState = *(CMouseControllerState*)0x8472A0; +CMouseControllerState &CPad::NewMouseControllerState = *(CMouseControllerState*)0x8809F0; +CMouseControllerState &CPad::PCTempMouseControllerState = *(CMouseControllerState*)0x6F1E60; + +void +CControllerState::Clear(void) +{ + leftX = 0; + leftY = 0; + rightX = 0; + rightY = 0; + l1 = 0; + l2 = 0; + r1 = 0; + r2 = 0; + up = 0; + down = 0; + left = 0; + right = 0; + start = 0; + select = 0; + square = 0; + triangle = 0; + cross = 0; + circle = 0; + leftshock = 0; + rightshock = 0; +} diff --git a/src/Pad.h b/src/Pad.h new file mode 100644 index 00000000..ddcfad8d --- /dev/null +++ b/src/Pad.h @@ -0,0 +1,116 @@ +#pragma once + +// same as RW skeleton +enum Key +{ + // ascii... + + KEY_ESC = 128, + + KEY_F1 = 129, + KEY_F2 = 130, + KEY_F3 = 131, + KEY_F4 = 132, + KEY_F5 = 133, + KEY_F6 = 134, + KEY_F7 = 135, + KEY_F8 = 136, + KEY_F9 = 137, + KEY_F10 = 138, + KEY_F11 = 139, + KEY_F12 = 140, + + KEY_INS = 141, + KEY_DEL = 142, + KEY_HOME = 143, + KEY_END = 144, + KEY_PGUP = 145, + KEY_PGDN = 146, + + KEY_UP = 147, + KEY_DOWN = 148, + KEY_LEFT = 149, + KEY_RIGHT = 150, + + // some stuff ommitted + + KEY_BACKSP = 168, + KEY_TAB = 169, + KEY_CAPSLK = 170, + KEY_ENTER = 171, + KEY_LSHIFT = 172, + KEY_RSHIFT = 173, + KEY_LCTRL = 174, + KEY_RCTRL = 175, + KEY_LALT = 176, + KEY_RALT = 177, + + KEY_NULL, // unused + KEY_NUMKEYS, +}; + + +class CControllerState +{ +public: + int16 leftX, leftY; + int16 rightX, rightY; + int16 l1, l2; + int16 r1, r2; + int16 up, down, left, right; + int16 start, select; + int16 square, triangle, cross, circle; + int16 leftshock, rightshock; + int16 networktalk; + float getLeftX(void) { return leftX/32767.0f; }; + float getLeftY(void) { return leftY/32767.0f; }; + float getRightX(void) { return rightX/32767.0f; }; + float getRightY(void) { return rightY/32767.0f; }; + + void Clear(void); +}; +static_assert(sizeof(CControllerState) == 0x2A, "CControllerState: error"); + +struct CMouseControllerState +{ + uint32 btns; // bit 0-2 button 1-3 + int x, y; +}; + +class CPad +{ +public: + CControllerState NewState; + CControllerState OldState; + CControllerState PCTempKeyState; + CControllerState PCTempJoyState; + CControllerState PCTempMouseState; + // straight out of my IDB + int16 Phase; + int16 Mode; + int16 ShakeDur; + int8 ShakeFreq; + int8 bHornHistory[5]; + int8 iCurrHornHistory; + int8 DisablePlayerControls; + int8 JustOutOfFrontEnd; + int8 bApplyBrakes; + int32 unk[3]; + int32 LastTimeTouched; + int32 AverageWeapon; + int32 AverageEntries; + + static CPad *Pads; //[2]; + static uint16 *OldKeyState; //[KEY_NUMKEYS]; + static uint16 *NewKeyState; //[KEY_NUMKEYS]; + static uint16 *TempKeyState; //[KEY_NUMKEYS]; + static CMouseControllerState &OldMouseControllerState; + static CMouseControllerState &NewMouseControllerState; + static CMouseControllerState &PCTempMouseControllerState; + + static CPad *GetPad(int n) { return &Pads[n]; } +}; +static_assert(sizeof(CPad) == 0xFC, "CPad: error"); + +#define IsButtonJustDown(pad, btn) \ + (!(pad)->OldState.btn && (pad)->NewState.btn) diff --git a/src/ParticleObject.cpp b/src/ParticleObject.cpp new file mode 100644 index 00000000..fc15c2f7 --- /dev/null +++ b/src/ParticleObject.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "ParticleObject.h" + +void CParticleObject::AddObject(uint16, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } diff --git a/src/ParticleObject.h b/src/ParticleObject.h new file mode 100644 index 00000000..b2cfadb8 --- /dev/null +++ b/src/ParticleObject.h @@ -0,0 +1,31 @@ +#pragma once + +enum eParticleObjectType +{ + POBJECT_PAVEMENT_STEAM, + POBJECT_PAVEMENT_STEAM_SLOWMOTION, + POBJECT_WALL_STEAM, + POBJECT_WALL_STEAM_SLOWMOTION, + POBJECT_DARK_SMOKE, + POBJECT_FIRE_HYDRANT, + POBJECT_CAR_WATER_SPLASH, + POBJECT_PED_WATER_SPLASH, + POBJECT_SPLASHES_AROUND, + POBJECT_SMALL_FIRE, + POBJECT_BIG_FIRE, + POBJECT_DRY_ICE, + POBJECT_DRY_ICE_SLOWMOTION, + POBJECT_FIRE_TRAIL, + POBJECT_SMOKE_TRAIL, + POBJECT_FIREBALL_AND_SMOKE, + POBJECT_ROCKET_TRAIL, + POBJECT_EXPLOSION_ONCE, + POBJECT_CATALINAS_GUNFLASH, + POBJECT_CATALINAS_SHOTGUNFLASH, +}; + +class CParticleObject +{ +public: + static void AddObject(uint16, const CVector &pos, bool remove); +}; diff --git a/src/PathFind.cpp b/src/PathFind.cpp new file mode 100644 index 00000000..c337ca88 --- /dev/null +++ b/src/PathFind.cpp @@ -0,0 +1,591 @@ +#include "common.h" +#include "patcher.h" +#include "PathFind.h" + +CPathFind &ThePaths = *(CPathFind*)0x8F6754; + +int TempListLength; + +enum +{ + NodeTypeExtern = 1, + NodeTypeIntern = 2, + + PathTypeCar = 0, + PathTypePed = 1, + + PathNodeFlag1 = 1, // used? + PathNodeFlag2 = 2, + PathNodeDeadEnd = 4, + PathNodeDisabled = 8, + PathNodeBetweenLevels = 0x10, +}; + +// link flags: +// 1: crosses road +// 2: ped traffic light +// pathnode flags: +// 1: +// 2: +// 4: dead end +// 8: switched off +// 10: road between levels?? +// navi node flags: +// 1: bridge light +// object flags: +// 1 +// 2 east/west road(?) + +CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C; +CPathInfoForObject *&InfoForTilePeds = *(CPathInfoForObject**)0x8F1AE4; +// unused +CTempDetachedNode *&DetachedNodesCars = *(CTempDetachedNode**)0x8E2824; +CTempDetachedNode *&DetachedNodesPeds = *(CTempDetachedNode**)0x8E28A0; + +void +CPathFind::PreparePathData(void) +{ + int i, j, k; + int numExtern, numIntern, numLanes; + float maxX, maxY; + CTempNode *tempNodes; + + printf("PreparePathData\n"); + // UNUSED: CPathFind::LoadPathFindData + if(InfoForTileCars && InfoForTilePeds && + DetachedNodesCars && DetachedNodesPeds){ + tempNodes = new CTempNode[4000]; + + m_numLinks = 0; + for(i = 0; i < PATHNODESIZE; i++) + m_pathNodes[i].flags &= ~(PathNodeFlag1 | PathNodeFlag2); + + for(i = 0; i < PATHNODESIZE; i++){ + numExtern = 0; + numIntern = 0; + for(j = 0; j < 12; j++){ + if(InfoForTileCars[i*12 + j].type == NodeTypeExtern) + numExtern++; + if(InfoForTileCars[i*12 + j].type == NodeTypeIntern) + numIntern++; + } + if(numIntern > 1 && numExtern != 2) + printf("ILLEGAL BLOCK. MORE THAN 1 INTERNALS AND NOT 2 EXTERNALS (Modelindex:%d)\n", i); + } + + for(i = 0; i < PATHNODESIZE; i++) + for(j = 0; j < 12; j++) + if(InfoForTileCars[i*12 + j].type == NodeTypeExtern){ + if(InfoForTileCars[i*12 + j].numLeftLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(InfoForTileCars[i*12 + j].numRightLanes < 0) + printf("ILLEGAL BLOCK. NEGATIVE NUMBER OF LANES (Obj:%d)\n", i); + if(InfoForTileCars[i*12 + j].numLeftLanes + InfoForTileCars[i*12 + j].numRightLanes <= 0) + printf("ILLEGAL BLOCK. NO LANES IN NODE (Obj:%d)\n", i); + } + + m_numPathNodes = 0; + PreparePathDataForType(PathTypeCar, tempNodes, InfoForTileCars, 1.0f, DetachedNodesCars, 100); + m_numCarPathNodes = m_numPathNodes; + PreparePathDataForType(PathTypePed, tempNodes, InfoForTilePeds, 1.0f, DetachedNodesPeds, 50); + m_numPedPathNodes = m_numPathNodes - m_numCarPathNodes; + + // TODO: figure out what exactly is going on here + // Some roads seem to get a west/east flag + for(i = 0; i < m_numMapObjects; i++){ + numExtern = 0; + numIntern = 0; + numLanes = 0; + maxX = 0.0f; + maxY = 0.0f; + for(j = 0; j < 12; j++){ + k = i*12 + j; + if(InfoForTileCars[k].type == NodeTypeExtern){ + numExtern++; + if(InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes > numLanes) + numLanes = InfoForTileCars[k].numLeftLanes + InfoForTileCars[k].numRightLanes; + maxX = max(maxX, fabs(InfoForTileCars[k].x)); + maxY = max(maxY, fabs(InfoForTileCars[k].y)); + }else if(InfoForTileCars[k].type == NodeTypeIntern) + numIntern++; + } + + if(numIntern == 1 && numExtern == 2){ + if(numLanes < 4){ + if((i & 7) == 4){ // WHAT? + m_objectFlags[i] |= 1; + if(maxX > maxY) + m_objectFlags[i] |= 2; + else + m_objectFlags[i] &= ~2; + } + }else{ + m_objectFlags[i] |= 1; + if(maxX > maxY) + m_objectFlags[i] |= 2; + else + m_objectFlags[i] &= ~2; + } + } + } + + delete[] tempNodes; + + CountFloodFillGroups(PathTypeCar); + CountFloodFillGroups(PathTypePed); + + delete[] InfoForTileCars; + InfoForTileCars = nil; + delete[] InfoForTilePeds; + InfoForTilePeds = nil; + delete[] DetachedNodesCars; + DetachedNodesCars = nil; + delete[] DetachedNodesPeds; + DetachedNodesPeds = nil; + } + printf("Done with PreparePathData\n"); +} + +/* String together connected nodes in a list by a flood fill algorithm */ +void +CPathFind::CountFloodFillGroups(uint8 type) +{ + int start, end; + int i, l; + uint16 n; + CPathNode *node, *prev; + + switch(type){ + case PathTypeCar: + start = 0; + end = m_numCarPathNodes; + break; + case PathTypePed: + start = m_numCarPathNodes; + end = start + m_numPedPathNodes; + break; + } + + for(i = start; i < end; i++) + m_pathNodes[i].group = 0; + + n = 0; + for(;;){ + n++; + if(n > 1500){ + for(i = start; m_pathNodes[i].group && i < end; i++); + printf("NumNodes:%d Accounted for:%d\n", end - start, i - start); + } + + // Look for unvisited node + for(i = start; m_pathNodes[i].group && i < end; i++); + if(i == end) + break; + + node = &m_pathNodes[i]; + node->next = nil; + node->group = n; + + if(node->numLinks == 0){ + if(type == PathTypeCar) + printf("Single car node: %f %f %f (%d)\n", + node->pos.x, node->pos.y, node->pos.z, + m_mapObjects[node->objectIndex]->m_modelIndex); + else + printf("Single ped node: %f %f %f\n", + node->pos.x, node->pos.y, node->pos.z); + } + + while(node){ + prev = node; + node = node->next; + for(i = 0; i < prev->numLinks; i++){ + l = m_linkTo[prev->firstLink + i]; + if(m_pathNodes[l].group == 0){ + m_pathNodes[l].group = n; + if(m_pathNodes[l].group == 0) + m_pathNodes[l].group = 0x80; // ??? + m_pathNodes[l].next = node; + node = &m_pathNodes[l]; + } + } + } + } + + m_numGroups[type] = n-1; + printf("GraphType:%d. FloodFill groups:%d\n", type, n); +} + +void +CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, + float maxdist, CTempDetachedNode *detachednodes, int unused) +{ + static CVector CoorsXFormed; + int i, j, k, l; + int l1, l2; + int start, typeoff; + float posx, posy; + float dx, dy, mag; + float nearestDist; + int nearestId; + int next; + int oldNumPathNodes, oldNumLinks; + CVector dist; + int iseg, jseg; + int istart, jstart; + int done, cont; + + typeoff = 12*type; + oldNumPathNodes = m_numPathNodes; + oldNumLinks = m_numLinks; + + // Initialize map objects + for(i = 0; i < m_numMapObjects; i++) + for(j = 0; j < 12; j++) + m_mapObjects[i]->m_nodeIndicesCars[typeoff + j] = -1; + + // Calculate internal nodes, store them and connect them to defining object + for(i = 0; i < m_numMapObjects; i++){ + start = 12*m_mapObjects[i]->m_modelIndex; + for(j = 0; j < 12; j++){ + if(objectpathinfo[start + j].type != NodeTypeIntern) + continue; + CalcNodeCoors( + objectpathinfo[start + j].x, + objectpathinfo[start + j].y, + objectpathinfo[start + j].z, + i, + &CoorsXFormed); + m_pathNodes[m_numPathNodes].pos = CoorsXFormed; + m_pathNodes[m_numPathNodes].objectIndex = i; + m_pathNodes[m_numPathNodes].flags |= 1; + m_mapObjects[i]->m_nodeIndicesCars[typeoff + j] = m_numPathNodes++; + } + } + + // Insert external nodes into TempList + TempListLength = 0; + for(i = 0; i < m_numMapObjects; i++){ + start = 12*m_mapObjects[i]->m_modelIndex; + + for(j = 0; j < 12; j++){ + if(objectpathinfo[start + j].type != NodeTypeExtern) + continue; + CalcNodeCoors( + objectpathinfo[start + j].x, + objectpathinfo[start + j].y, + objectpathinfo[start + j].z, + i, + &CoorsXFormed); + + // find closest unconnected node + nearestId = -1; + nearestDist = maxdist; + for(k = 0; k < TempListLength; k++){ + if(tempnodes[k].linkState != 1) + continue; + dx = tempnodes[k].pos.x - CoorsXFormed.x; + if(fabs(dx) < nearestDist){ + dy = tempnodes[k].pos.y - CoorsXFormed.y; + if(fabs(dy) < nearestDist){ + nearestDist = max(fabs(dx), fabs(dy)); + nearestId = k; + } + } + } + + if(nearestId < 0){ + // None found, add this one to temp list + tempnodes[TempListLength].pos = CoorsXFormed; + next = objectpathinfo[start + j].next; + if(next < 0){ + // no link from this node, find link to this node + next = 0; + for(k = start; j != objectpathinfo[k].next; k++) + next++; + } + // link to connecting internal node + tempnodes[TempListLength].link1 = m_mapObjects[i]->m_nodeIndicesCars[typeoff + next]; + if(type == PathTypeCar){ + tempnodes[TempListLength].numLeftLanes = objectpathinfo[start + j].numLeftLanes; + tempnodes[TempListLength].numRightLanes = objectpathinfo[start + j].numRightLanes; + } + tempnodes[TempListLength++].linkState = 1; + }else{ + // Found nearest, connect it to our neighbour + next = objectpathinfo[start + j].next; + if(next < 0){ + // no link from this node, find link to this node + next = 0; + for(k = start; j != objectpathinfo[k].next; k++) + next++; + } + tempnodes[nearestId].link2 = m_mapObjects[i]->m_nodeIndicesCars[typeoff + next]; + tempnodes[nearestId].linkState = 2; + + // collapse this node with nearest we found + dx = m_pathNodes[tempnodes[nearestId].link1].pos.x - m_pathNodes[tempnodes[nearestId].link2].pos.x; + dy = m_pathNodes[tempnodes[nearestId].link1].pos.y - m_pathNodes[tempnodes[nearestId].link2].pos.y; + tempnodes[nearestId].pos.x = (tempnodes[nearestId].pos.x + CoorsXFormed.x)*0.5f; + tempnodes[nearestId].pos.y = (tempnodes[nearestId].pos.y + CoorsXFormed.y)*0.5f; + tempnodes[nearestId].pos.z = (tempnodes[nearestId].pos.z + CoorsXFormed.z)*0.5f; + mag = sqrt(dx*dx + dy*dy); + tempnodes[nearestId].dirX = dx/mag; + tempnodes[nearestId].dirY = dy/mag; + // do something when number of lanes doesn't agree + if(type == PathTypeCar) + if(tempnodes[nearestId].numLeftLanes != 0 && tempnodes[nearestId].numRightLanes != 0 && + (objectpathinfo[start + j].numLeftLanes == 0 || objectpathinfo[start + j].numRightLanes == 0)){ + tempnodes[nearestId].numLeftLanes = objectpathinfo[start + j].numLeftLanes; + tempnodes[nearestId].numRightLanes = objectpathinfo[start + j].numRightLanes; + } + } + } + } + + // Loop through previously added internal nodes and link them + for(i = oldNumPathNodes; i < m_numPathNodes; i++){ + // Init link + m_pathNodes[i].numLinks = 0; + m_pathNodes[i].firstLink = m_numLinks; + + // See if node connects to external nodes + for(j = 0; j < TempListLength; j++){ + if(tempnodes[j].linkState != 2) + continue; + + // Add link to other side of the external + if(tempnodes[j].link1 == i) + m_linkTo[m_numLinks] = tempnodes[j].link2; + else if(tempnodes[j].link2 == i) + m_linkTo[m_numLinks] = tempnodes[j].link1; + else + continue; + + dist = m_pathNodes[i].pos - m_pathNodes[m_linkTo[m_numLinks]].pos; + m_distTo[m_numLinks] = dist.Magnitude(); + m_linkFlags[m_numLinks] = 0; + + if(type == PathTypeCar){ + // IMPROVE: use a goto here + // Find existing navi node + for(k = 0; k < m_numNaviNodes; k++){ + if(m_naviNodes[k].dirX == tempnodes[j].dirX && + m_naviNodes[k].dirY == tempnodes[j].dirY && + m_naviNodes[k].posX == tempnodes[j].pos.x && + m_naviNodes[k].posY == tempnodes[j].pos.y){ + m_naviNodeLinks[m_numLinks] = k; + k = m_numNaviNodes; + } + } + // k is m_numNaviNodes+1 if we found one + if(k == m_numNaviNodes){ + m_naviNodes[m_numNaviNodes].dirX = tempnodes[j].dirX; + m_naviNodes[m_numNaviNodes].dirY = tempnodes[j].dirY; + m_naviNodes[m_numNaviNodes].posX = tempnodes[j].pos.x; + m_naviNodes[m_numNaviNodes].posY = tempnodes[j].pos.y; + m_naviNodes[m_numNaviNodes].pathNodeIndex = i; + m_naviNodes[m_numNaviNodes].numLeftLanes = tempnodes[j].numLeftLanes; + m_naviNodes[m_numNaviNodes].numRightLanes = tempnodes[j].numRightLanes; + m_naviNodes[m_numNaviNodes].trafficLightType = 0; + m_naviNodeLinks[m_numLinks] = m_numNaviNodes++; + } + } + + m_pathNodes[i].numLinks++; + m_numLinks++; + } + + // Find i inside path segment + iseg = 0; + for(j = max(oldNumPathNodes, i-12); j < i; j++) + if(m_pathNodes[j].objectIndex == m_pathNodes[i].objectIndex) + iseg++; + + istart = 12*m_mapObjects[m_pathNodes[i].objectIndex]->m_modelIndex; + // Add links to other internal nodes + for(j = max(oldNumPathNodes, i-12); j < min(m_numPathNodes, i+12); j++){ + if(m_pathNodes[i].objectIndex != m_pathNodes[j].objectIndex || i == j) + continue; + // N.B.: in every path segment, the externals have to be at the end + jseg = j-i + iseg; + + jstart = 12*m_mapObjects[m_pathNodes[j].objectIndex]->m_modelIndex; + if(objectpathinfo[istart + iseg].next == jseg || + objectpathinfo[jstart + jseg].next == iseg){ + // Found a link between i and j + m_linkTo[m_numLinks] = j; + dist = m_pathNodes[i].pos - m_pathNodes[j].pos; + m_distTo[m_numLinks] = dist.Magnitude(); + + if(type == PathTypeCar){ + posx = (m_pathNodes[i].pos.x + m_pathNodes[j].pos.x)*0.5f; + posy = (m_pathNodes[i].pos.y + m_pathNodes[j].pos.y)*0.5f; + dx = m_pathNodes[j].pos.x - m_pathNodes[i].pos.x; + dy = m_pathNodes[j].pos.y - m_pathNodes[i].pos.y; + mag = sqrt(dx*dx + dy*dy); + dx /= mag; + dy /= mag; + if(i < j){ + dx = -dx; + dy = -dy; + } + // IMPROVE: use a goto here + // Find existing navi node + for(k = 0; k < m_numNaviNodes; k++){ + if(m_naviNodes[k].dirX == dx && + m_naviNodes[k].dirY == dy && + m_naviNodes[k].posX == posx && + m_naviNodes[k].posY == posy){ + m_naviNodeLinks[m_numLinks] = k; + k = m_numNaviNodes; + } + } + // k is m_numNaviNodes+1 if we found one + if(k == m_numNaviNodes){ + m_naviNodes[m_numNaviNodes].dirX = dx; + m_naviNodes[m_numNaviNodes].dirY = dy; + m_naviNodes[m_numNaviNodes].posX = posx; + m_naviNodes[m_numNaviNodes].posY = posy; + m_naviNodes[m_numNaviNodes].pathNodeIndex = i; + m_naviNodes[m_numNaviNodes].numLeftLanes = -1; + m_naviNodes[m_numNaviNodes].numRightLanes = -1; + m_naviNodes[m_numNaviNodes].trafficLightType = 0; + m_naviNodeLinks[m_numLinks] = m_numNaviNodes++; + } + }else{ + // Crosses road + if(objectpathinfo[istart + iseg].next == jseg && objectpathinfo[istart + iseg].flag & 1 || + objectpathinfo[jstart + jseg].next == iseg && objectpathinfo[jstart + jseg].flag & 1) + m_linkFlags[m_numLinks] |= 1; + else + m_linkFlags[m_numLinks] &= ~1; + } + + m_pathNodes[i].numLinks++; + m_numLinks++; + } + } + } + + if(type == PathTypeCar){ + done = 0; + // Set number of lanes for all nodes somehow + // very strange code + for(k = 0; !done && k < 10; k++){ + done = 1; + for(i = 0; i < m_numPathNodes; i++){ + if(m_pathNodes[i].numLinks != 2) + continue; + l1 = m_naviNodeLinks[m_pathNodes[i].firstLink]; + l2 = m_naviNodeLinks[m_pathNodes[i].firstLink+1]; + + if(m_naviNodes[l1].numLeftLanes == -1 && + m_naviNodes[l2].numLeftLanes != -1){ + done = 0; + if(m_naviNodes[l2].pathNodeIndex == i){ + // why switch left and right here? + m_naviNodes[l1].numLeftLanes = m_naviNodes[l2].numRightLanes; + m_naviNodes[l1].numRightLanes = m_naviNodes[l2].numLeftLanes; + }else{ + m_naviNodes[l1].numLeftLanes = m_naviNodes[l2].numLeftLanes; + m_naviNodes[l1].numRightLanes = m_naviNodes[l2].numRightLanes; + } + m_naviNodes[l1].pathNodeIndex = i; + }else if(m_naviNodes[l1].numLeftLanes != -1 && + m_naviNodes[l2].numLeftLanes == -1){ + done = 0; + if(m_naviNodes[l1].pathNodeIndex == i){ + // why switch left and right here? + m_naviNodes[l2].numLeftLanes = m_naviNodes[l1].numRightLanes; + m_naviNodes[l2].numRightLanes = m_naviNodes[l1].numLeftLanes; + }else{ + m_naviNodes[l2].numLeftLanes = m_naviNodes[l1].numLeftLanes; + m_naviNodes[l2].numRightLanes = m_naviNodes[l1].numRightLanes; + } + m_naviNodes[l2].pathNodeIndex = i; + }else if(m_naviNodes[l1].numLeftLanes == -1 && + m_naviNodes[l2].numLeftLanes == -1) + done = 0; + } + } + + // Fall back to default values for number of lanes + for(i = 0; i < m_numPathNodes; i++) + for(j = 0; j < m_pathNodes[i].numLinks; j++){ + k = m_naviNodeLinks[m_pathNodes[i].firstLink + j]; + if(m_naviNodes[k].numLeftLanes < 0) + m_naviNodes[k].numLeftLanes = 1; + if(m_naviNodes[k].numRightLanes < 0) + m_naviNodes[k].numRightLanes = 1; + } + } + + // Set flags for car nodes + if(type == PathTypeCar){ + do{ + cont = 0; + for(i = 0; i < m_numPathNodes; i++){ + m_pathNodes[i].flags &= ~PathNodeDisabled; + m_pathNodes[i].flags &= ~PathNodeBetweenLevels; + // See if node is a dead end, if so, we're not done yet + if((m_pathNodes[i].flags & PathNodeDeadEnd) == 0){ + k = 0; + for(j = 0; j < m_pathNodes[i].numLinks; j++) + if((m_pathNodes[m_linkTo[m_pathNodes[i].firstLink + j]].flags & PathNodeDeadEnd) == 0) + k++; + if(k < 2){ + m_pathNodes[i].flags |= PathNodeDeadEnd; + cont = 1; + } + } + } + }while(cont); + } + + // Remove isolated ped nodes + if(type == PathTypePed) + for(i = oldNumPathNodes; i < m_numPathNodes; i++){ + if(m_pathNodes[i].numLinks != 0) + continue; + + // Remove node + for(j = i; j < m_numPathNodes-1; j++) + m_pathNodes[j] = m_pathNodes[j+1]; + + // Fix links + for(j = oldNumLinks; j < m_numLinks; j++) + if(m_linkTo[j] >= i) + m_linkTo[j]--; + + // Also in treadables + for(j = 0; j < m_numMapObjects; j++) + for(k = 0; k < 12; k++){ + if(m_mapObjects[j]->m_nodeIndicesPeds[k] == i){ + // remove this one + for(l = k; l < 12-1; l++) + m_mapObjects[j]->m_nodeIndicesPeds[l] = m_mapObjects[j]->m_nodeIndicesPeds[l+1]; + m_mapObjects[j]->m_nodeIndicesPeds[11] = -1; + }else if(m_mapObjects[j]->m_nodeIndicesPeds[k] > i) + m_mapObjects[j]->m_nodeIndicesPeds[k]--; + } + + i--; + m_numPathNodes--; + } +} + +void +CPathFind::CalcNodeCoors(int16 x, int16 y, int16 z, int id, CVector *out) +{ + CVector pos; + pos.x = x / 16.0f; + pos.y = y / 16.0f; + pos.z = z / 16.0f; + *out = m_mapObjects[id]->GetMatrix() * pos; +} + +STARTPATCHES + InjectHook(0x429610, &CPathFind::PreparePathData, PATCH_JUMP); + InjectHook(0x429C20, &CPathFind::PreparePathDataForType, PATCH_JUMP); +ENDPATCHES diff --git a/src/PathFind.h b/src/PathFind.h new file mode 100644 index 00000000..f4857ce2 --- /dev/null +++ b/src/PathFind.h @@ -0,0 +1,130 @@ +#pragma once + +#include "Treadable.h" + +struct CPathNode +{ + CVector pos; + CPathNode *prev; //? + CPathNode *next; + int16 unknown; + int16 objectIndex; + int16 firstLink; + uint8 numLinks; + uint8 flags; + uint8 group; +/* VC: + int16 unk1; + int16 nextIndex; + int16 x; + int16 y; + int16 z; + int16 unknown; + int16 firstLink; + int8 width; + int8 group; + int8 numLinks : 4; + int8 bDeadEnd : 1; + int8 bTurnedOff : 1; // flag 8 in node info + int8 flagA40 : 1; // flag 20 in node info + int8 flagA80 : 1; // flag 4 in node info + int8 flagB1 : 1; // flag 10 in node info + int8 flagB2 : 1; // flag 2 in node info + int8 flagB4 : 1; + int8 speedLimit : 2; // speed limit + int8 flagB20 : 1; + int8 flagB40 : 1; + int8 flagB80 : 1; + int8 spawnRate : 4; + int8 flagsC : 4; +*/ +}; + +// TODO: name? +struct NaviNode +{ + float posX; + float posY; + float dirX; + float dirY; + int16 pathNodeIndex; + int8 numLeftLanes; + int8 numRightLanes; + int8 trafficLightType; + // probably only padding + int8 field15; + int8 field16; + int8 field17; +}; + +struct CPathInfoForObject +{ + int16 x; + int16 y; + int16 z; + int8 type; + int8 next; + int8 numLeftLanes; + int8 numRightLanes; + uint8 flag; +}; + +struct CTempNode +{ + CVector pos; + float dirX; + float dirY; + int16 link1; + int16 link2; + int8 numLeftLanes; + int8 numRightLanes; + int8 linkState; + // probably padding + int8 field1B; +}; + +struct CTempDetachedNode // unused +{ + uint8 foo[20]; +}; + +class CPathFind +{ +public: +/* For reference VC: + CPathNode pathNodes[9650]; + NaviNode naviNodes[3500]; + CBuilding *mapObjects[1250]; + // 0x8000 is cross road flag + // 0x4000 is traffic light flag + uint16 linkTo[20400]; + uint8 distTo[20400]; + int16 naviNodeLinks[20400]; +*/ + CPathNode m_pathNodes[4930]; + NaviNode m_naviNodes[2076]; + CTreadable *m_mapObjects[1250]; + uint8 m_objectFlags[1250]; + int16 m_linkTo[10260]; + int16 m_distTo[10260]; + uint8 m_linkFlags[10260]; + int16 m_naviNodeLinks[10260]; + int32 m_numPathNodes; + int32 m_numCarPathNodes; + int32 m_numPedPathNodes; + int16 m_numMapObjects; + int16 m_numLinks; + int32 m_numNaviNodes; + int32 h; + uint8 m_numGroups[2]; + CPathNode m_aExtraPaths[872]; + + void PreparePathData(void); + void CountFloodFillGroups(uint8 type); + void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, + float unk, CTempDetachedNode *detachednodes, int unused); + void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out); +}; +static_assert(sizeof(CPathFind) == 0x4c8f4, "CPathFind: error"); + +extern CPathFind &ThePaths; diff --git a/src/Placeable.cpp b/src/Placeable.cpp new file mode 100644 index 00000000..43708d3e --- /dev/null +++ b/src/Placeable.cpp @@ -0,0 +1,81 @@ +#include "common.h" +#include "Placeable.h" +#include "patcher.h" + +CPlaceable::CPlaceable(void) +{ + m_matrix.SetScale(1.0f); +} + +CPlaceable::~CPlaceable(void) { } + +void +CPlaceable::SetHeading(float angle) +{ + CVector pos = GetPosition(); + m_matrix.SetRotateZ(angle); + GetPosition() += pos; +} + +bool +CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2) +{ + float x, xmin, xmax; + float y, ymin, ymax; + xmin = x1; + xmax = x2; + ymin = y1; + ymax = y2; + if(x2 > x1){ + xmin = x2; + xmax = x1; + } + if(y2 > y1){ + ymin = y2; + ymax = y1; + } + x = GetPosition().x; + y = GetPosition().y; + return xmin <= x && x <= xmax && + ymin <= y && y <= ymax; +} + +bool +CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2) +{ + float x, xmin, xmax; + float y, ymin, ymax; + float z, zmin, zmax; + xmin = x1; + xmax = x2; + ymin = y1; + ymax = y2; + zmin = z1; + zmax = z2; + if(x2 > x1){ + xmin = x2; + xmax = x1; + } + if(y2 > y1){ + ymin = y2; + ymax = y1; + } + if(z2 > z1){ + zmin = z2; + zmax = z1; + } + x = GetPosition().x; + y = GetPosition().y; + z = GetPosition().z; + return xmin <= x && x <= xmax && + ymin <= y && y <= ymax && + zmin <= z && z <= zmax; +} + +STARTPATCHES + InjectHook(0x49F9A0, &CPlaceable::ctor, PATCH_JUMP); + InjectHook(0x49F9E0, &CPlaceable::dtor, PATCH_JUMP); + InjectHook(0x49FA00, &CPlaceable::SetHeading, PATCH_JUMP); + InjectHook(0x49FA50, (bool (CPlaceable::*)(float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); + InjectHook(0x49FAF0, (bool (CPlaceable::*)(float, float, float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); +ENDPATCHES diff --git a/src/Placeable.h b/src/Placeable.h new file mode 100644 index 00000000..bca9462d --- /dev/null +++ b/src/Placeable.h @@ -0,0 +1,26 @@ +#pragma once + +class CPlaceable +{ + // disable allocation + static void *operator new(size_t) { assert(0); return nil; } + static void operator delete(void*, size_t) { assert(0); } +public: + CMatrix m_matrix; + + CPlaceable(void); + virtual ~CPlaceable(void); + CVector &GetPosition(void) { return *m_matrix.GetPosition(); } + CVector &GetRight(void) { return *m_matrix.GetRight(); } + CVector &GetForward(void) { return *m_matrix.GetForward(); } + CVector &GetUp(void) { return *m_matrix.GetUp(); } + CMatrix &GetMatrix(void) { return m_matrix; } + void SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); } + void SetHeading(float angle); + bool IsWithinArea(float x1, float y1, float x2, float y2); + bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2); + + CPlaceable *ctor(void) { return ::new (this) CPlaceable(); } + void dtor(void) { this->CPlaceable::~CPlaceable(); } +}; +static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error"); diff --git a/src/Pools.cpp b/src/Pools.cpp new file mode 100644 index 00000000..106715e4 --- /dev/null +++ b/src/Pools.cpp @@ -0,0 +1,19 @@ +#include "common.h" +#include "Pools.h" + +CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044; +CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448; +CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04; +CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568; +CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28; + +void +CPools::Initialise(void) +{ + // TODO: unused right now + ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES); + ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS); + ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS); + ms_pTreadablePool = new CTreadablePool(NUMTREADABLES); + ms_pObjectPool = new CObjectPool(NUMOBJECTS); +} diff --git a/src/Pools.h b/src/Pools.h new file mode 100644 index 00000000..aa804788 --- /dev/null +++ b/src/Pools.h @@ -0,0 +1,34 @@ +#pragma once + +#include "templates.h" +#include "Lists.h" +#include "Treadable.h" +#include "Object.h" +#include "CutsceneHead.h" + +typedef CPool CCPtrNodePool; +typedef CPool CEntryInfoNodePool; +typedef CPool CBuildingPool; +typedef CPool CTreadablePool; +typedef CPool CObjectPool; + +class CPools +{ + static CCPtrNodePool *&ms_pPtrNodePool; + static CEntryInfoNodePool *&ms_pEntryInfoNodePool; + // ms_pPedPool + // ms_pVehiclePool + static CBuildingPool *&ms_pBuildingPool; + static CTreadablePool *&ms_pTreadablePool; + static CObjectPool *&ms_pObjectPool; + // ms_pDummyPool + // ms_pAudioScriptObjectPool +public: + static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; } + static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; } + static CBuildingPool *GetBuildingPool(void) { return ms_pBuildingPool; } + static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; } + static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; } + + static void Initialise(void); +}; diff --git a/src/References.cpp b/src/References.cpp new file mode 100644 index 00000000..187f4ffa --- /dev/null +++ b/src/References.cpp @@ -0,0 +1,22 @@ +#include "common.h" +#include "patcher.h" +#include "References.h" + +CReference *CReferences::aRefs = (CReference*)0x70BBE0; //[NUMREFERENCES]; +CReference *&CReferences::pEmptyList = *(CReference**)0x8F1AF8; + +void +CReferences::Init(void) +{ + int i; + pEmptyList = &aRefs[0]; + for(i = 0; i < NUMREFERENCES; i++){ + aRefs[i].pentity = nil; + aRefs[i].next = &aRefs[i+1]; + } + aRefs[NUMREFERENCES-1].next = nil; +} + +STARTPATCHES + InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP); +ENDPATCHES diff --git a/src/References.h b/src/References.h new file mode 100644 index 00000000..5ee20d38 --- /dev/null +++ b/src/References.h @@ -0,0 +1,17 @@ +#pragma once + +class CEntity; + +struct CReference +{ + CReference *next; + CEntity **pentity; +}; + +class CReferences +{ + static CReference *aRefs; //[NUMREFERENCES]; +public: + static CReference *&pEmptyList; + static void Init(void); +}; diff --git a/src/RwHelper.cpp b/src/RwHelper.cpp new file mode 100644 index 00000000..c8782f9e --- /dev/null +++ b/src/RwHelper.cpp @@ -0,0 +1,19 @@ +#include "common.h" + + +RwObject* +GetFirstObjectCallback(RwObject *object, void *data) +{ + *(RwObject**)data = object; + return nil; +} + +RwObject* +GetFirstObject(RwFrame *frame) +{ + RwObject *obj; + + obj = nil; + RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj); + return obj; +} diff --git a/src/RwHelper.h b/src/RwHelper.h new file mode 100644 index 00000000..90852b08 --- /dev/null +++ b/src/RwHelper.h @@ -0,0 +1,3 @@ +#pragma once + +RwObject *GetFirstObject(RwFrame *frame); diff --git a/src/Streaming.cpp b/src/Streaming.cpp new file mode 100644 index 00000000..47258c9d --- /dev/null +++ b/src/Streaming.cpp @@ -0,0 +1,10 @@ +#include "common.h" +#include "patcher.h" +#include "Streaming.h" + +bool &CStreaming::ms_disableStreaming = *(bool*)0x95CD6E; +int32 &CStreaming::ms_numModelsRequested = *(int32*)0x8E2C10; +CStreamingInfo *CStreaming::ms_aInfoForModel = (CStreamingInfo*)0x6C7088; + +WRAPPER void CStreaming::RemoveModel(int32 id) { EAXJMP(0x408830); } +WRAPPER void CStreaming::RequestModel(int32 model, int32 flags) { EAXJMP(0x407EA0); } diff --git a/src/Streaming.h b/src/Streaming.h new file mode 100644 index 00000000..1acfc261 --- /dev/null +++ b/src/Streaming.h @@ -0,0 +1,54 @@ +#pragma once + +enum { + STREAM_OFFSET_MODEL = 0, + STREAM_OFFSET_TXD = STREAM_OFFSET_MODEL+MODELINFOSIZE, + NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE +}; + +enum StreamFlags +{ + STREAM_DONT_REMOVE = 0x01, + STREAM_SCRIPTOWNED = 0x02, + STREAM_DEPENDENCY = 0x04, + STREAM_PRIORITY = 0x08, + STREAM_NOFADE = 0x10, +}; + +enum StreamLoadState +{ + STREAM_NOTLOADED = 0, + STREAM_LOADED = 1, + STREAM_INQUEUE = 2, + STREAM_READING = 3, // what is this? + STREAM_BIGFILE = 4, +}; + +class CStreamingInfo +{ +public: + CStreamingInfo *m_next; + CStreamingInfo *m_prev; + uint8 m_loadState; + uint8 m_flags; + + int16 m_nextID; + uint32 m_position; + uint32 m_size; + +// bool GetCdPosnAndSize(uint32 *pos, uint32 *size); +// void SetCdPosnAndSize(uint32 pos, uint32 size); +// void AddToList(CStreamingInfo *link); +// void RemoveFromList(void); +}; + +class CStreaming +{ +public: + static bool &ms_disableStreaming; + static int32 &ms_numModelsRequested; + static CStreamingInfo *ms_aInfoForModel; //[NUMSTREAMINFO] + + static void RemoveModel(int32 id); + static void RequestModel(int32 model, int32 flags); +}; diff --git a/src/SurfaceTable.cpp b/src/SurfaceTable.cpp new file mode 100644 index 00000000..e9ef459a --- /dev/null +++ b/src/SurfaceTable.cpp @@ -0,0 +1,44 @@ +#include "common.h" +#include "patcher.h" +#include "SurfaceTable.h" + +int +CSurfaceTable::GetAdhesionGroup(uint8 surfaceType) +{ + switch(surfaceType){ + case SURFACE_0: return ADHESIVE_ROAD; + case SURFACE_1: return ADHESIVE_ROAD; + case SURFACE_2: return ADHESIVE_LOOSE; + case SURFACE_3: return ADHESIVE_LOOSE; + case SURFACE_4: return ADHESIVE_HARD; + case SURFACE_5: return ADHESIVE_ROAD; + case SURFACE_6: return ADHESIVE_HARD; + case SURFACE_7: return ADHESIVE_HARD; + case SURFACE_8: return ADHESIVE_HARD; + case SURFACE_9: return ADHESIVE_HARD; + case SURFACE_10: return ADHESIVE_HARD; + case SURFACE_11: return ADHESIVE_HARD; + case SURFACE_12: return ADHESIVE_HARD; + case SURFACE_13: return ADHESIVE_HARD; + case SURFACE_14: return ADHESIVE_HARD; + case SURFACE_15: return ADHESIVE_HARD; + case SURFACE_16: return ADHESIVE_HARD; + case SURFACE_17: return ADHESIVE_RUBBER; + case SURFACE_18: return ADHESIVE_LOOSE; + case SURFACE_19: return ADHESIVE_WET; + case SURFACE_20: return ADHESIVE_ROAD; + case SURFACE_21: return ADHESIVE_ROAD; + case SURFACE_22: return ADHESIVE_ROAD; + case SURFACE_23: return ADHESIVE_RUBBER; + case SURFACE_24: return ADHESIVE_HARD; + case SURFACE_25: return ADHESIVE_LOOSE; + case SURFACE_26: return ADHESIVE_LOOSE; + case SURFACE_27: return ADHESIVE_HARD; + case SURFACE_28: return ADHESIVE_HARD; + case SURFACE_29: return ADHESIVE_RUBBER; + case SURFACE_30: return ADHESIVE_LOOSE; + case SURFACE_31: return ADHESIVE_HARD; + case SURFACE_32: return ADHESIVE_HARD; + default: return ADHESIVE_ROAD; + } +} diff --git a/src/SurfaceTable.h b/src/SurfaceTable.h new file mode 100644 index 00000000..556a6e04 --- /dev/null +++ b/src/SurfaceTable.h @@ -0,0 +1,99 @@ +#pragma once + + +enum +{ + SURFACE_0, + SURFACE_1, + SURFACE_2, + SURFACE_3, + SURFACE_4, + SURFACE_5, + SURFACE_6, + SURFACE_7, + SURFACE_8, + SURFACE_9, + SURFACE_10, + SURFACE_11, + SURFACE_12, + SURFACE_13, + SURFACE_14, + SURFACE_15, + SURFACE_16, + SURFACE_17, + SURFACE_18, + SURFACE_19, + SURFACE_20, + SURFACE_21, + SURFACE_22, + SURFACE_23, + SURFACE_24, + SURFACE_25, + SURFACE_26, + SURFACE_27, + SURFACE_28, + SURFACE_29, + SURFACE_30, + SURFACE_31, + SURFACE_32, + + NUMSURFACETYPES +}; + +// From nick +// TODO: check and use this +enum eSurfaceType +{ + SURFACE_ROAD0, + SURFACE_ROAD1, + SURFACE_GRASS, + SURFACE_DIRT, + SURFACE_MUD, + SURFACE_PAVEMENT, + SURFACE_METAL6, + SURFACE_GLASS, + SURFACE_HARD8, + SURFACE_METAL_DOOR, + SURFACE_METAL10, + SURFACE_METAL11, + SURFACE_METAL12, + SURFACE_METAL13, + SURFACE_METAL14, + SURFACE_METAL15, + SURFACE_METAL_FENCE, + SURFACE_FLESH, + SURFACE_SAND18, + SURFACE_WATER, + SURFACE_WOOD, + SURFACE_WOOD_BOX, + SURFACE_WOOD_PLANK, + SURFACE_TIRE, + SURFACE_HARD24, + SURFACE_HEDGE, + SURFACE_STONE, + SURFACE_METAL27, + SURFACE_METAL28, + SURFACE_RUBBER29, + SURFACE_LOOSE30, + SURFACE_BOLLARD, + SURFACE_GATE, + SURFACE_SAND33, + SURFACE_ROAD34, +}; + +enum +{ + ADHESIVE_RUBBER, + ADHESIVE_HARD, + ADHESIVE_ROAD, + ADHESIVE_LOOSE, + ADHESIVE_WET, + + NUMADHESIVEGROUPS +}; + +class CSurfaceTable +{ +public: + static int GetAdhesionGroup(uint8 surfaceType); +}; diff --git a/src/Timecycle.cpp b/src/Timecycle.cpp new file mode 100644 index 00000000..10fd6bf6 --- /dev/null +++ b/src/Timecycle.cpp @@ -0,0 +1,92 @@ +#include "common.h" +#include "Timecycle.h" + +int (*CTimeCycle::m_nAmbientRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86AF78; +int (*CTimeCycle::m_nAmbientGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x665308; +int (*CTimeCycle::m_nAmbientBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72CF88; +int (*CTimeCycle::m_nDirectionalRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FAB78; +int (*CTimeCycle::m_nDirectionalGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F4528; +int (*CTimeCycle::m_nDirectionalBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83CE58; +int (*CTimeCycle::m_nSkyTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FB90; +int (*CTimeCycle::m_nSkyTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x8460A8; +int (*CTimeCycle::m_nSkyTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87B158; +int (*CTimeCycle::m_nSkyBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FA960; +int (*CTimeCycle::m_nSkyBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70D6A8; +int (*CTimeCycle::m_nSkyBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83D288; +int (*CTimeCycle::m_nSunCoreRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x878360; +int (*CTimeCycle::m_nSunCoreGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE088; +int (*CTimeCycle::m_nSunCoreBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x773A68; +int (*CTimeCycle::m_nSunCoronaRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x664B60; +int (*CTimeCycle::m_nSunCoronaGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F01E0; +int (*CTimeCycle::m_nSunCoronaBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E6340; +float (*CTimeCycle::m_fSunSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733510; +float (*CTimeCycle::m_fSpriteSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87F820; +float (*CTimeCycle::m_fSpriteBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x6E96F0; +short (*CTimeCycle::m_nShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x83CFD8; +short (*CTimeCycle::m_nLightShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x72B0F8; +short (*CTimeCycle::m_nTreeShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x733450; +float (*CTimeCycle::m_fFogStart)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8806C8; +float (*CTimeCycle::m_fFarClip)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8804E0; +float (*CTimeCycle::m_fLightsOnGroundBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x83D108; +int (*CTimeCycle::m_nLowCloudsRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x726770; +int (*CTimeCycle::m_nLowCloudsGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87BF08; +int (*CTimeCycle::m_nLowCloudsBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FA10; +int (*CTimeCycle::m_nFluffyCloudsTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70F2B0; +int (*CTimeCycle::m_nFluffyCloudsTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72D288; +int (*CTimeCycle::m_nFluffyCloudsTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86B108; +int (*CTimeCycle::m_nFluffyCloudsBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E8DA8; +int (*CTimeCycle::m_nFluffyCloudsBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x715AA8; +int (*CTimeCycle::m_nFluffyCloudsBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE2D0; +float (*CTimeCycle::m_fBlurRed)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87C7E0; +float (*CTimeCycle::m_fBlurGreen)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x774C10; +float (*CTimeCycle::m_fBlurBlue)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8784E0; +float (*CTimeCycle::m_fBlurAlpha)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733690; + +float &CTimeCycle::m_fCurrentAmbientRed = *(float*)0x8F29B4; +float &CTimeCycle::m_fCurrentAmbientGreen = *(float*)0x94144C; +float &CTimeCycle::m_fCurrentAmbientBlue = *(float*)0x942FC0; +float &CTimeCycle::m_fCurrentDirectionalRed = *(float*)0x8F29D8; +float &CTimeCycle::m_fCurrentDirectionalGreen = *(float*)0x940594; +float &CTimeCycle::m_fCurrentDirectionalBlue = *(float*)0x942FAC; +int &CTimeCycle::m_nCurrentSkyTopRed = *(int*)0x9403C0; +int &CTimeCycle::m_nCurrentSkyTopGreen = *(int*)0x943074; +int &CTimeCycle::m_nCurrentSkyTopBlue = *(int*)0x8F29B8; +int &CTimeCycle::m_nCurrentSkyBottomRed = *(int*)0x9414D0; +int &CTimeCycle::m_nCurrentSkyBottomGreen = *(int*)0x8F2BD0; +int &CTimeCycle::m_nCurrentSkyBottomBlue = *(int*)0x8F625C; +int &CTimeCycle::m_nCurrentSunCoreRed = *(int*)0x8F2534; +int &CTimeCycle::m_nCurrentSunCoreGreen = *(int*)0x8F6264; +int &CTimeCycle::m_nCurrentSunCoreBlue = *(int*)0x94149C; +int &CTimeCycle::m_nCurrentSunCoronaRed = *(int*)0x8F2C1C; +int &CTimeCycle::m_nCurrentSunCoronaGreen = *(int*)0x885B54; +int &CTimeCycle::m_nCurrentSunCoronaBlue = *(int*)0x880F60; +float &CTimeCycle::m_fCurrentSunSize = *(float*)0x940588; +float &CTimeCycle::m_fCurrentSpriteSize = *(float*)0x8F1AA8; +float &CTimeCycle::m_fCurrentSpriteBrightness = *(float*)0x8F5FDC; +int &CTimeCycle::m_nCurrentShadowStrength = *(int*)0x95CC76; +int &CTimeCycle::m_nCurrentLightShadowStrength = *(int*)0x95CC66; +int &CTimeCycle::m_nCurrentTreeShadowStrength = *(int*)0x95CC86; +float &CTimeCycle::m_fCurrentFogStart = *(float*)0x8F1AE0; +float &CTimeCycle::m_fCurrentFarClip = *(float*)0x8F5FD8; +float &CTimeCycle::m_fCurrentLightsOnGroundBrightness = *(float*)0x8F1B60; +int &CTimeCycle::m_nCurrentLowCloudsRed = *(int*)0x95CB54; +int &CTimeCycle::m_nCurrentLowCloudsGreen = *(int*)0x95CB48; +int &CTimeCycle::m_nCurrentLowCloudsBlue = *(int*)0x95CC1C; +int &CTimeCycle::m_nCurrentFluffyCloudsTopRed = *(int*)0x8F2550; +int &CTimeCycle::m_nCurrentFluffyCloudsTopGreen = *(int*)0x8F59CC; +int &CTimeCycle::m_nCurrentFluffyCloudsTopBlue = *(int*)0x941434; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomRed = *(int*)0x8F1A38; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomGreen = *(int*)0x8E28B8; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomBlue = *(int*)0x8F3960; +float &CTimeCycle::m_fCurrentBlurRed = *(float*)0x8F6000; +float &CTimeCycle::m_fCurrentBlurGreen = *(float*)0x9405A0; +float &CTimeCycle::m_fCurrentBlurBlue = *(float*)0x8F250C; +float &CTimeCycle::m_fCurrentBlurAlpha = *(float*)0x940728; +int &CTimeCycle::m_nCurrentFogColourRed = *(int*)0x940714; +int &CTimeCycle::m_nCurrentFogColourGreen = *(int*)0x8E2A60; +int &CTimeCycle::m_nCurrentFogColourBlue = *(int*)0x8F57EC; + +int &CTimeCycle::m_FogReduction = *(int*)0x880FB8; + +int &CTimeCycle::m_CurrentStoredValue = *(int*)0x94057C; +CVector *CTimeCycle::m_VectorToSun = (CVector*)0x665548; // [16] diff --git a/src/Timecycle.h b/src/Timecycle.h new file mode 100644 index 00000000..6946cc7c --- /dev/null +++ b/src/Timecycle.h @@ -0,0 +1,111 @@ +class CTimeCycle +{ + static int (*m_nAmbientRed)[NUMWEATHERS]; + static int (*m_nAmbientGreen)[NUMWEATHERS]; + static int (*m_nAmbientBlue)[NUMWEATHERS]; + + static int (*m_nDirectionalRed)[NUMWEATHERS]; + static int (*m_nDirectionalGreen)[NUMWEATHERS]; + static int (*m_nDirectionalBlue)[NUMWEATHERS]; + static int (*m_nSkyTopRed)[NUMWEATHERS]; + static int (*m_nSkyTopGreen)[NUMWEATHERS]; + static int (*m_nSkyTopBlue)[NUMWEATHERS]; + static int (*m_nSkyBottomRed)[NUMWEATHERS]; + static int (*m_nSkyBottomGreen)[NUMWEATHERS]; + static int (*m_nSkyBottomBlue)[NUMWEATHERS]; + static int (*m_nSunCoreRed)[NUMWEATHERS]; + static int (*m_nSunCoreGreen)[NUMWEATHERS]; + static int (*m_nSunCoreBlue)[NUMWEATHERS]; + static int (*m_nSunCoronaRed)[NUMWEATHERS]; + static int (*m_nSunCoronaGreen)[NUMWEATHERS]; + static int (*m_nSunCoronaBlue)[NUMWEATHERS]; + static float (*m_fSunSize)[NUMWEATHERS]; + static float (*m_fSpriteSize)[NUMWEATHERS]; + static float (*m_fSpriteBrightness)[NUMWEATHERS]; + static short (*m_nShadowStrength)[NUMWEATHERS]; + static short (*m_nLightShadowStrength)[NUMWEATHERS]; + static short (*m_nTreeShadowStrength)[NUMWEATHERS]; + static float (*m_fFogStart)[NUMWEATHERS]; + static float (*m_fFarClip)[NUMWEATHERS]; + static float (*m_fLightsOnGroundBrightness)[NUMWEATHERS]; + static int (*m_nLowCloudsRed)[NUMWEATHERS]; + static int (*m_nLowCloudsGreen)[NUMWEATHERS]; + static int (*m_nLowCloudsBlue)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopRed)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopGreen)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopBlue)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomRed)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomGreen)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomBlue)[NUMWEATHERS]; + static float (*m_fBlurRed)[NUMWEATHERS]; + static float (*m_fBlurGreen)[NUMWEATHERS]; + static float (*m_fBlurBlue)[NUMWEATHERS]; + static float (*m_fBlurAlpha)[NUMWEATHERS]; + + static float &m_fCurrentAmbientRed; + static float &m_fCurrentAmbientGreen; + static float &m_fCurrentAmbientBlue; + static float &m_fCurrentDirectionalRed; + static float &m_fCurrentDirectionalGreen; + static float &m_fCurrentDirectionalBlue; + static int &m_nCurrentSkyTopRed; + static int &m_nCurrentSkyTopGreen; + static int &m_nCurrentSkyTopBlue; + static int &m_nCurrentSkyBottomRed; + static int &m_nCurrentSkyBottomGreen; + static int &m_nCurrentSkyBottomBlue; + static int &m_nCurrentSunCoreRed; + static int &m_nCurrentSunCoreGreen; + static int &m_nCurrentSunCoreBlue; + static int &m_nCurrentSunCoronaRed; + static int &m_nCurrentSunCoronaGreen; + static int &m_nCurrentSunCoronaBlue; + static float &m_fCurrentSunSize; + static float &m_fCurrentSpriteSize; + static float &m_fCurrentSpriteBrightness; + static int &m_nCurrentShadowStrength; + static int &m_nCurrentLightShadowStrength; + static int &m_nCurrentTreeShadowStrength; + static float &m_fCurrentFogStart; + static float &m_fCurrentFarClip; + static float &m_fCurrentLightsOnGroundBrightness; + static int &m_nCurrentLowCloudsRed; + static int &m_nCurrentLowCloudsGreen; + static int &m_nCurrentLowCloudsBlue; + static int &m_nCurrentFluffyCloudsTopRed; + static int &m_nCurrentFluffyCloudsTopGreen; + static int &m_nCurrentFluffyCloudsTopBlue; + static int &m_nCurrentFluffyCloudsBottomRed; + static int &m_nCurrentFluffyCloudsBottomGreen; + static int &m_nCurrentFluffyCloudsBottomBlue; + static float &m_fCurrentBlurRed; + static float &m_fCurrentBlurGreen; + static float &m_fCurrentBlurBlue; + static float &m_fCurrentBlurAlpha; + static int &m_nCurrentFogColourRed; + static int &m_nCurrentFogColourGreen; + static int &m_nCurrentFogColourBlue; + + static int &m_FogReduction; + +public: + static int &m_CurrentStoredValue; + static CVector *m_VectorToSun; // [16] + + static float GetAmbientRed(void) { return m_fCurrentAmbientRed; } + static float GetAmbientGreen(void) { return m_fCurrentAmbientGreen; } + static float GetAmbientBlue(void) { return m_fCurrentAmbientBlue; } + static float GetDirectionalRed(void) { return m_fCurrentDirectionalRed; } + static float GetDirectionalGreen(void) { return m_fCurrentDirectionalGreen; } + static float GetDirectionalBlue(void) { return m_fCurrentDirectionalBlue; } + static int GetLowCloudsRed(void) { return m_nCurrentLowCloudsRed; } + static int GetLowCloudsGreen(void) { return m_nCurrentLowCloudsGreen; } + static int GetLowCloudsBlue(void) { return m_nCurrentLowCloudsBlue; } + static int GetFluffyCloudsTopRed(void) { return m_nCurrentFluffyCloudsTopRed; } + static int GetFluffyCloudsTopGreen(void) { return m_nCurrentFluffyCloudsTopGreen; } + static int GetFluffyCloudsTopBlue(void) { return m_nCurrentFluffyCloudsTopBlue; } + static int GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; } + static int GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; } + static int GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; } + +}; diff --git a/src/Timer.cpp b/src/Timer.cpp new file mode 100644 index 00000000..9cc35e42 --- /dev/null +++ b/src/Timer.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "patcher.h" +#include "Timer.h" + +uint32 &CTimer::m_snTimeInMilliseconds = *(uint32*)0x885B48; +uint32 &CTimer::m_snTimeInMillisecondsPauseMode = *(uint32*)0x5F7614; +uint32 &CTimer::m_snTimeInMillisecondsNonClipped = *(uint32*)0x9412E8; +uint32 &CTimer::m_snPreviousTimeInMilliseconds = *(uint32*)0x8F29E4; +uint32 &CTimer::m_FrameCounter = *(uint32*)0x9412EC; +float &CTimer::ms_fTimeScale = *(float*)0x8F2C20; +float &CTimer::ms_fTimeStep = *(float*)0x8E2CB4; +float &CTimer::ms_fTimeStepNonClipped = *(float*)0x8E2C4C; +bool &CTimer::m_UserPause = *(bool*)0x95CD7C; +bool &CTimer::m_CodePause = *(bool*)0x95CDB1; diff --git a/src/Timer.h b/src/Timer.h new file mode 100644 index 00000000..a96574ce --- /dev/null +++ b/src/Timer.h @@ -0,0 +1,19 @@ +#pragma once + +class CTimer +{ + static uint32 &m_snTimeInMilliseconds; + static uint32 &m_snTimeInMillisecondsPauseMode; + static uint32 &m_snTimeInMillisecondsNonClipped; + static uint32 &m_snPreviousTimeInMilliseconds; + static uint32 &m_FrameCounter; + static float &ms_fTimeScale; + static float &ms_fTimeStep; + static float &ms_fTimeStepNonClipped; + static bool &m_UserPause; + static bool &m_CodePause; +public: + static float GetTimeStep(void) { return ms_fTimeStep; } + static uint32 GetFrameCounter(void) { return m_FrameCounter; } + static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } +}; diff --git a/src/TxdStore.cpp b/src/TxdStore.cpp new file mode 100644 index 00000000..ba8eecb9 --- /dev/null +++ b/src/TxdStore.cpp @@ -0,0 +1,158 @@ +#include "common.h" +#include "patcher.h" +#include "templates.h" +#include "Streaming.h" +#include "TxdStore.h" + +CPool *&CTxdStore::ms_pTxdPool = *(CPool**)0x8F5FB8; +RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC; + +void +CTxdStore::Initialize(void) +{ + if(ms_pTxdPool == nil) + ms_pTxdPool = new CPool(TXDSTORESIZE); +} + +void +CTxdStore::Shutdown(void) +{ + if(ms_pTxdPool) + delete ms_pTxdPool; +} + +int +CTxdStore::AddTxdSlot(const char *name) +{ + TxdDef *def = ms_pTxdPool->New(); + assert(def); + def->texDict = nil; + def->refCount = 0; + strcpy(def->name, name); + return ms_pTxdPool->GetJustIndex(def); +} + +int +CTxdStore::FindTxdSlot(const char *name) +{ + char *defname; + int size = ms_pTxdPool->GetSize(); + for(int i = 0; i < size; i++){ + defname = GetTxdName(i); + if(defname && _strcmpi(defname, name) == 0) + return i; + } + return -1; +} + +char* +CTxdStore::GetTxdName(int slot) +{ + TxdDef *def = GetSlot(slot); + return def ? def->name : nil; +} + +void +CTxdStore::PushCurrentTxd(void) +{ + ms_pStoredTxd = RwTexDictionaryGetCurrent(); +} + +void +CTxdStore::PopCurrentTxd(void) +{ + RwTexDictionarySetCurrent(ms_pStoredTxd); + ms_pStoredTxd = nil; +} + +void +CTxdStore::SetCurrentTxd(int slot) +{ + TxdDef *def = GetSlot(slot); + if(def) + RwTexDictionarySetCurrent(def->texDict); +} + +void +CTxdStore::Create(int slot) +{ + GetSlot(slot)->texDict = RwTexDictionaryCreate(); +} + +void +CTxdStore::AddRef(int slot) +{ + GetSlot(slot)->refCount++; +} + +void +CTxdStore::RemoveRef(int slot) +{ + if(--GetSlot(slot)->refCount <= 0) + CStreaming::RemoveModel(slot + STREAM_OFFSET_TXD); +} + +void +CTxdStore::RemoveRefWithoutDelete(int slot) +{ + GetSlot(slot)->refCount--; +} + +/* +bool +CTxdStore::LoadTxd(int slot, RwStream *stream) +{ + TxdDef *def = GetSlot(slot); + if(!rw::findChunk(stream, rw::ID_TEXDICTIONARY, nil, nil)){ + return false; + }else{ + def->texDict = rw::TexDictionary::streamRead(stream); + convertTxd(def->texDict); + return def->texDict != nil; + } +} + +bool +CTxdStore::LoadTxd(int slot, const char *filename) +{ + rw::StreamFile stream; + if(stream.open(getPath(filename), "rb")){ + LoadTxd(slot, &stream); + stream.close(); + return true; + } + printf("Failed to open TXD\n"); + return false; +} +*/ + +void +CTxdStore::RemoveTxd(int slot) +{ + TxdDef *def = GetSlot(slot); + if(def->texDict) + RwTexDictionaryDestroy(def->texDict); + def->texDict = nil; +} + +//bool +//CTxdStore::isTxdLoaded(int slot) +//{ +// return GetSlot(slot)->texDict != nil; +//} + +STARTPATCHES + InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP); + InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP); + InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP); + InjectHook(0x5275D0, CTxdStore::FindTxdSlot, PATCH_JUMP); + InjectHook(0x527590, CTxdStore::GetTxdName, PATCH_JUMP); + InjectHook(0x527900, CTxdStore::PushCurrentTxd, PATCH_JUMP); + InjectHook(0x527910, CTxdStore::PopCurrentTxd, PATCH_JUMP); + InjectHook(0x5278C0, CTxdStore::SetCurrentTxd, PATCH_JUMP); + InjectHook(0x527830, CTxdStore::Create, PATCH_JUMP); + InjectHook(0x527930, CTxdStore::AddRef, PATCH_JUMP); + InjectHook(0x527970, CTxdStore::RemoveRef, PATCH_JUMP); + InjectHook(0x5279C0, CTxdStore::RemoveRefWithoutDelete, PATCH_JUMP); + InjectHook(0x527870, CTxdStore::RemoveTxd, PATCH_JUMP); +ENDPATCHES diff --git a/src/TxdStore.h b/src/TxdStore.h new file mode 100644 index 00000000..2cfef0e0 --- /dev/null +++ b/src/TxdStore.h @@ -0,0 +1,34 @@ +#pragma once + +#include "templates.h" + +struct TxdDef { + RwTexDictionary *texDict; + int refCount; + char name[20]; +}; + +class CTxdStore +{ + static CPool *&ms_pTxdPool; + static RwTexDictionary *&ms_pStoredTxd; +public: + static void Initialize(void); + static void Shutdown(void); + static int AddTxdSlot(const char *name); + static int FindTxdSlot(const char *name); + static char *GetTxdName(int slot); + static void PushCurrentTxd(void); + static void PopCurrentTxd(void); + static void SetCurrentTxd(int slot); + static void Create(int slot); + static void AddRef(int slot); + static void RemoveRef(int slot); + static void RemoveRefWithoutDelete(int slot); + static bool LoadTxd(int slot, RwStream *stream); + static bool LoadTxd(int slot, const char *filename); + static void RemoveTxd(int slot); + + static TxdDef *GetSlot(int slot) { return ms_pTxdPool->GetSlot(slot); } + static bool isTxdLoaded(int slot); +}; diff --git a/src/Weather.cpp b/src/Weather.cpp new file mode 100644 index 00000000..73421932 --- /dev/null +++ b/src/Weather.cpp @@ -0,0 +1,27 @@ +#include "common.h" +#include "Weather.h" + +int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4; + +int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C; +int16 &CWeather::OldWeatherType = *(int16*)0x95CCEC; +int16 &CWeather::NewWeatherType = *(int16*)0x95CC70; +int16 &CWeather::ForcedWeatherType = *(int16*)0x95CC80; + +bool &CWeather::LightningFlash = *(bool*)0x95CDA3; +bool &CWeather::LightningBurst = *(bool*)0x95CDAC; +uint32 &CWeather::LightningStart = *(uint32*)0x8F5F84; +uint32 &CWeather::LightningFlashLastChange = *(uint32*)0x8E2C0C; +uint32 &CWeather::WhenToPlayLightningSound = *(uint32*)0x8F57E4; +uint32 &CWeather::LightningDuration = *(uint32*)0x940578; + +float &CWeather::Foggyness = *(float*)0x885AF4; +float &CWeather::CloudCoverage = *(float*)0x8E2818; +float &CWeather::Wind = *(float*)0x8E2BF8; +float &CWeather::Rain = *(float*)0x8E2BFC; +float &CWeather::InterpolationValue = *(float*)0x8F2520; +float &CWeather::WetRoads = *(float*)0x8F5FF8; +float &CWeather::Rainbow = *(float*)0x940598; + +bool &CWeather::bScriptsForceRain = *(bool*)0x95CD7D; +bool &CWeather::Stored_StateStored = *(bool*)0x95CDC1; diff --git a/src/Weather.h b/src/Weather.h new file mode 100644 index 00000000..41e07d93 --- /dev/null +++ b/src/Weather.h @@ -0,0 +1,35 @@ +enum { + WEATHER_SUNNY, + WEATHER_CLOUDY, + WEATHER_RAINY, + WEATHER_FOGGY +}; + +class CWeather +{ +public: + static int32 &SoundHandle; + + static int32 &WeatherTypeInList; + static int16 &OldWeatherType; + static int16 &NewWeatherType; + static int16 &ForcedWeatherType; + + static bool &LightningFlash; + static bool &LightningBurst; + static uint32 &LightningStart; + static uint32 &LightningFlashLastChange; + static uint32 &WhenToPlayLightningSound; + static uint32 &LightningDuration; + + static float &Foggyness; + static float &CloudCoverage; + static float &Wind; + static float &Rain; + static float &InterpolationValue; + static float &WetRoads; + static float &Rainbow; + + static bool &bScriptsForceRain; + static bool &Stored_StateStored; +}; diff --git a/src/World.cpp b/src/World.cpp new file mode 100644 index 00000000..761d8bf6 --- /dev/null +++ b/src/World.cpp @@ -0,0 +1,39 @@ +#include "common.h" +#include "patcher.h" +#include "Entity.h" +#include "World.h" + +CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; +CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; +CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; +uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64; + +bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC; + +void +CWorld::ClearScanCodes(void) +{ + CPtrNode *node; + for(int i = 0; i < NUMSECTORS_Y; i++) + for(int j = 0; j < NUMSECTORS_X; j++){ + CSector *s = &ms_aSectors[i][j]; + for(node = s->m_lists[ENTITYLIST_BUILDINGS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_VEHICLES].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_PEDS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_OBJECTS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_DUMMIES].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + } +} + +STARTPATCHES + InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP); +ENDPATCHES + +WRAPPER CVector &FindPlayerCoors(CVector &v) { EAXJMP(0x4A1030); } +WRAPPER CVehicle *FindPlayerVehicle(void) { EAXJMP(0x4A10C0); } +WRAPPER CVehicle *FindPlayerTrain(void) { EAXJMP(0x4A1120); } diff --git a/src/World.h b/src/World.h new file mode 100644 index 00000000..ecd8feb3 --- /dev/null +++ b/src/World.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Game.h" +#include "Lists.h" + +/* Sectors span from -2000 to 2000 in x and y. + * With 100x100 sectors, each is 40x40 units. */ + +#define NUMSECTORS_X 100 +#define NUMSECTORS_Y 100 + +enum +{ + ENTITYLIST_BUILDINGS, + ENTITYLIST_BUILDINGS_OVERLAP, + ENTITYLIST_OBJECTS, + ENTITYLIST_OBJECTS_OVERLAP, + ENTITYLIST_VEHICLES, + ENTITYLIST_VEHICLES_OVERLAP, + ENTITYLIST_PEDS, + ENTITYLIST_PEDS_OVERLAP, + ENTITYLIST_DUMMIES, + ENTITYLIST_DUMMIES_OVERLAP, + + NUMSECTORENTITYLISTS +}; + +class CSector +{ +public: + CPtrList m_lists[NUMSECTORENTITYLISTS]; +}; +static_assert(sizeof(CSector) == 0x28, "CSector: error"); + +class CWorld +{ + static CPtrList *ms_bigBuildingsList; // [4]; + static CPtrList &ms_listMovingEntityPtrs; + static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; + static uint16 &ms_nCurrentScanCode; + +public: + static bool &bNoMoreCollisionTorque; + + static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } + static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; } + static CPtrList &GetMovingEntityList(void) { return ms_listMovingEntityPtrs; } + static uint16 GetCurrentScanCode(void) { return ms_nCurrentScanCode; } + static void AdvanceCurrentScanCode(void){ + if(++CWorld::ms_nCurrentScanCode == 0){ + CWorld::ClearScanCodes(); + CWorld::ms_nCurrentScanCode = 1; + } + } + static void ClearScanCodes(void); + + static float GetSectorX(float f) { return ((f + 2000.0f)/40.0f); } + static float GetSectorY(float f) { return ((f + 2000.0f)/40.0f); } + static int GetSectorIndexX(float f) { return (int)GetSectorX(f); } + static int GetSectorIndexY(float f) { return (int)GetSectorY(f); } +}; + +CVector &FindPlayerCoors(CVector &v); +class CVehicle; +CVehicle *FindPlayerVehicle(void); +CVehicle *FindPlayerTrain(void); diff --git a/src/Zones.cpp b/src/Zones.cpp new file mode 100644 index 00000000..6c8f66ce --- /dev/null +++ b/src/Zones.cpp @@ -0,0 +1,614 @@ +#include "common.h" +#include "patcher.h" +#include "World.h" +#include "Clock.h" +#include "Zones.h" + +eLevelName &CTheZones::m_CurrLevel = *(eLevelName*)0x8F2BC8; +CZone *&CTheZones::m_pPlayersZone = *(CZone**)0x8F254C; +int16 &CTheZones::FindIndex = *(int16*)0x95CC40; + +uint16 &CTheZones::NumberOfAudioZones = *(uint16*)0x95CC84; +int16 *CTheZones::AudioZoneArray = (int16*)0x713BC0; +uint16 &CTheZones::TotalNumberOfMapZones = *(uint16*)0x95CC74; +uint16 &CTheZones::TotalNumberOfZones = *(uint16*)0x95CC36; +CZone *CTheZones::ZoneArray = (CZone*)0x86BEE0; +CZone *CTheZones::MapZoneArray = (CZone*)0x663EC0; +uint16 &CTheZones::TotalNumberOfZoneInfos = *(uint16*)0x95CC3C; +CZoneInfo *CTheZones::ZoneInfoArray = (CZoneInfo*)0x714400; + +#define SWAPF(a, b) { float t; t = a; a = b; b = t; } + + +void +CTheZones::Init(void) +{ + int i; + for(i = 0; i < NUMAUDIOZONES; i++) + AudioZoneArray[i] = -1; + NumberOfAudioZones = 0; + + CZoneInfo *zonei; + int x = 1000/6; + for(i = 0; i < 2*NUMZONES; i++){ + zonei = &ZoneInfoArray[i]; + zonei->carDensity = 10; + zonei->carThreshold[0] = x; + zonei->carThreshold[1] = zonei->carThreshold[0] + x; + zonei->carThreshold[2] = zonei->carThreshold[1] + x; + zonei->carThreshold[3] = zonei->carThreshold[2] + x; + zonei->carThreshold[4] = zonei->carThreshold[3]; + zonei->carThreshold[5] = zonei->carThreshold[4]; + zonei->copThreshold = zonei->carThreshold[5] + x; + zonei->gangThreshold[0] = zonei->copThreshold; + zonei->gangThreshold[1] = zonei->gangThreshold[0]; + zonei->gangThreshold[2] = zonei->gangThreshold[1]; + zonei->gangThreshold[3] = zonei->gangThreshold[2]; + zonei->gangThreshold[4] = zonei->gangThreshold[3]; + zonei->gangThreshold[5] = zonei->gangThreshold[4]; + zonei->gangThreshold[6] = zonei->gangThreshold[5]; + zonei->gangThreshold[7] = zonei->gangThreshold[6]; + zonei->gangThreshold[8] = zonei->gangThreshold[7]; + } + TotalNumberOfZoneInfos = 1; // why 1? + + for(i = 0; i < NUMZONES; i++) + memset(&ZoneArray[i], 0, sizeof(CZone)); + strcpy(ZoneArray[0].name, "CITYZON"); + ZoneArray[0].minx = -4000.0f; + ZoneArray[0].miny = -4000.0f; + ZoneArray[0].minz = -500.0f; + ZoneArray[0].maxx = 4000.0f; + ZoneArray[0].maxy = 4000.0f; + ZoneArray[0].maxz = 500.0f; + ZoneArray[0].level = LEVEL_NONE; + TotalNumberOfZones = 1; + + m_CurrLevel = LEVEL_NONE; + m_pPlayersZone = &ZoneArray[0]; + + for(i = 0; i < NUMMAPZONES; i++){ + memset(&MapZoneArray[i], 0, sizeof(CZone)); + MapZoneArray[i].type = ZONE_MAPZONE; + } + strcpy(MapZoneArray[0].name, "THEMAP"); + MapZoneArray[0].minx = -4000.0f; + MapZoneArray[0].miny = -4000.0f; + MapZoneArray[0].minz = -500.0f; + MapZoneArray[0].maxx = 4000.0f; + MapZoneArray[0].maxy = 4000.0f; + MapZoneArray[0].maxz = 500.0f; + MapZoneArray[0].level = LEVEL_NONE; + TotalNumberOfMapZones = 1; +} + +void +CTheZones::Update(void) +{ + CVector pos; + FindPlayerCoors(pos); + m_pPlayersZone = FindSmallestZonePosition(&pos); + m_CurrLevel = GetLevelFromPosition(pos); +} + +void +CTheZones::CreateZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level) +{ + CZone *zone; + char *p; + + if(minx > maxx) SWAPF(minx, maxx); + if(miny > maxy) SWAPF(miny, maxy); + if(minz > maxz) SWAPF(minz, maxz); + + // make upper case + for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); + + // add zone + zone = &ZoneArray[TotalNumberOfZones++]; + strncpy(zone->name, name, 7); + zone->name[7] = '\0'; + zone->type = type; + zone->minx = minx; + zone->miny = miny; + zone->minz = minz; + zone->maxx = maxx; + zone->maxy = maxy; + zone->maxz = maxz; + zone->level = level; + if(type == ZONE_AUDIO || type == ZONE_TYPE1 || type == ZONE_TYPE2){ + zone->zoneinfoDay = TotalNumberOfZoneInfos++; + zone->zoneinfoNight = TotalNumberOfZoneInfos++; + } +} + +void +CTheZones::CreateMapZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level) +{ + CZone *zone; + char *p; + + if(minx > maxx) SWAPF(minx, maxx); + if(miny > maxy) SWAPF(miny, maxy); + if(minz > maxz) SWAPF(minz, maxz); + + // make upper case + for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); + + // add zone + zone = &MapZoneArray[TotalNumberOfMapZones++]; + strncpy(zone->name, name, 7); + zone->name[7] = '\0'; + zone->type = type; + zone->minx = minx; + zone->miny = miny; + zone->minz = minz; + zone->maxx = maxx; + zone->maxy = maxy; + zone->maxz = maxz; + zone->level = level; +} + +void +CTheZones::PostZoneCreation(void) +{ + int i; + for(i = 1; i < TotalNumberOfZones; i++) + InsertZoneIntoZoneHierarchy(&ZoneArray[i]); + InitialiseAudioZoneArray(); +} + +void +CTheZones::InsertZoneIntoZoneHierarchy(CZone *zone) +{ + zone->child = nil; + zone->parent = nil; + zone->next = nil; + InsertZoneIntoZoneHierRecursive(zone, &ZoneArray[0]); +} + +bool +CTheZones::InsertZoneIntoZoneHierRecursive(CZone *inner, CZone *outer) +{ + int n; + CZone *child, *next, *insert; + + // return false if inner was not inserted into outer + if(outer == nil || + !ZoneIsEntirelyContainedWithinOtherZone(inner, outer)) + return false; + + // try to insert inner into children of outer + for(child = outer->child; child; child = child->next) + if(InsertZoneIntoZoneHierRecursive(inner, child)) + return true; + + // insert inner as child of outer + // count number of outer's children contained within inner + n = 0; + for(child = outer->child; child; child = child->next) + if(ZoneIsEntirelyContainedWithinOtherZone(child, inner)) + n++; + inner->next = outer->child; + inner->parent = outer; + outer->child = inner; + // move children from outer to inner + if(n){ + insert = inner; + for(child = inner->next; child; child = next){ + next = child->next; + if(ZoneIsEntirelyContainedWithinOtherZone(child,inner)){ + insert->next = child->next; + child->parent = inner; + child->next = inner->child; + inner->child = child; + }else + insert = child; + } + } + + return true; +} + +bool +CTheZones::ZoneIsEntirelyContainedWithinOtherZone(CZone *inner, CZone *outer) +{ + char tmp[100]; + + if(inner->minx < outer->minx || + inner->maxx > outer->maxx || + inner->miny < outer->miny || + inner->maxy > outer->maxy || + inner->minz < outer->minz || + inner->maxz > outer->maxz){ + CVector vmin(inner->minx, inner->miny, inner->minz); + if(PointLiesWithinZone(vmin, outer)) + sprintf(tmp, "Overlapping zones %s and %s\n", + inner->name, outer->name); + CVector vmax(inner->maxx, inner->maxy, inner->maxz); + if(PointLiesWithinZone(vmax, outer)) + sprintf(tmp, "Overlapping zones %s and %s\n", + inner->name, outer->name); + return false; + } + return true; +} + +bool +CTheZones::PointLiesWithinZone(const CVector &v, CZone *zone) +{ + return zone->minx <= v.x && v.x <= zone->maxx && + zone->miny <= v.y && v.y <= zone->maxy && + zone->minz <= v.z && v.z <= zone->maxz; +} + +eLevelName +CTheZones::GetLevelFromPosition(CVector const &v) +{ + int i; +// char tmp[116]; +// if(!PointLiesWithinZone(v, &MapZoneArray[0])) +// sprintf(tmp, "x = %.3f y= %.3f z = %.3f\n", v.x, v.y, v.z); + for(i = 1; i < TotalNumberOfMapZones; i++) + if(PointLiesWithinZone(v, &MapZoneArray[i])) + return MapZoneArray[i].level; + return MapZoneArray[0].level; +} + +CZone* +CTheZones::FindSmallestZonePosition(const CVector *v) +{ + CZone *best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +CZone* +CTheZones::FindSmallestZonePositionType(const CVector *v, eZoneType type) +{ + CZone *best = nil; + if(ZoneArray[0].type == type) + best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + if(zone->type == type) + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +CZone* +CTheZones::FindSmallestZonePositionILN(const CVector *v) +{ + CZone *best = nil; + if(ZoneArray[0].type == ZONE_AUDIO || + ZoneArray[0].type == ZONE_TYPE1 || + ZoneArray[0].type == ZONE_TYPE2) + best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + if(zone->type == ZONE_AUDIO || + zone->type == ZONE_TYPE1 || + zone->type == ZONE_TYPE2) + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +int16 +CTheZones::FindZoneByLabelAndReturnIndex(char *name) +{ + char str[8]; + memset(str, 0, 8); + strncpy(str, name, 8); + for(FindIndex = 0; FindIndex < TotalNumberOfZones; FindIndex++) + if(strcmp(GetZone(FindIndex)->name, name) == 0) + return FindIndex; + return -1; +} + +CZoneInfo* +CTheZones::GetZoneInfo(const CVector *v, uint8 day) +{ + CZone *zone; + zone = FindSmallestZonePositionILN(v); + if(zone == nil) + return &ZoneInfoArray[0]; + return &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; +} + +void +CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info) +{ + CZoneInfo *day, *night; + float d, n; + + day = GetZoneInfo(pos, 1); + night = GetZoneInfo(pos, 0); + + if(CClock::GetIsTimeInRange(8, 19)) + *info = *day; + else if(CClock::GetIsTimeInRange(22, 5)) + *info = *night; + else{ + if(CClock::GetIsTimeInRange(19, 22)){ + n = (CClock::GetHours() - 19) / 3.0f; + d = n - 1.0f; + }else{ + d = (CClock::GetHours() - 5) / 3.0f; + n = d - 1.0f; + } + info->carDensity = day->carDensity * d + night->carDensity * n; + info->carThreshold[0] = day->carThreshold[0] * d + night->carThreshold[0] * n; + info->carThreshold[1] = day->carThreshold[1] * d + night->carThreshold[1] * n; + info->carThreshold[2] = day->carThreshold[2] * d + night->carThreshold[2] * n; + info->carThreshold[3] = day->carThreshold[3] * d + night->carThreshold[3] * n; + info->carThreshold[4] = day->carThreshold[4] * d + night->carThreshold[4] * n; + info->carThreshold[5] = day->carThreshold[5] * d + night->carThreshold[5] * n; + info->copThreshold = day->copThreshold * d + night->copThreshold * n; + info->gangThreshold[0] = day->gangThreshold[0] * d + night->gangThreshold[0] * n; + info->gangThreshold[1] = day->gangThreshold[1] * d + night->gangThreshold[1] * n; + info->gangThreshold[2] = day->gangThreshold[2] * d + night->gangThreshold[2] * n; + info->gangThreshold[3] = day->gangThreshold[3] * d + night->gangThreshold[3] * n; + info->gangThreshold[4] = day->gangThreshold[4] * d + night->gangThreshold[4] * n; + info->gangThreshold[5] = day->gangThreshold[5] * d + night->gangThreshold[5] * n; + info->gangThreshold[6] = day->gangThreshold[6] * d + night->gangThreshold[6] * n; + info->gangThreshold[7] = day->gangThreshold[7] * d + night->gangThreshold[7] * n; + info->gangThreshold[8] = day->gangThreshold[8] * d + night->gangThreshold[8] * n; + + info->pedDensity = day->pedDensity * d + night->pedDensity * n; + info->copDensity = day->copDensity * d + night->copDensity * n; + info->gangDensity[0] = day->gangDensity[0] * d + night->gangDensity[0] * n; + info->gangDensity[1] = day->gangDensity[1] * d + night->gangDensity[1] * n; + info->gangDensity[2] = day->gangDensity[2] * d + night->gangDensity[2] * n; + info->gangDensity[3] = day->gangDensity[3] * d + night->gangDensity[3] * n; + info->gangDensity[4] = day->gangDensity[4] * d + night->gangDensity[4] * n; + info->gangDensity[5] = day->gangDensity[5] * d + night->gangDensity[5] * n; + info->gangDensity[6] = day->gangDensity[6] * d + night->gangDensity[6] * n; + info->gangDensity[7] = day->gangDensity[7] * d + night->gangDensity[7] * n; + info->gangDensity[8] = day->gangDensity[8] * d + night->gangDensity[8] * n; + } + if(CClock::GetIsTimeInRange(5, 19)) + info->pedGroup = day->pedGroup; + else + info->pedGroup = night->pedGroup; +} + +void +CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, + int16 gang0Num, int16 gang1Num, int16 gang2Num, + int16 gang3Num, int16 gang4Num, int16 gang5Num, + int16 gang6Num, int16 gang7Num, int16 gang8Num, + int16 copNum, + int16 car0Num, int16 car1Num, int16 car2Num, + int16 car3Num, int16 car4Num, int16 car5Num) +{ + CZone *zone; + CZoneInfo *info; + zone = GetZone(zoneid); + info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; + + if(carDensity != -1) info->carDensity = carDensity; + int16 oldCar1Num = info->carThreshold[1] - info->carThreshold[0]; + int16 oldCar2Num = info->carThreshold[2] - info->carThreshold[1]; + int16 oldCar3Num = info->carThreshold[3] - info->carThreshold[2]; + int16 oldCar4Num = info->carThreshold[4] - info->carThreshold[3]; + int16 oldCar5Num = info->carThreshold[5] - info->carThreshold[4]; + int16 oldCopNum = info->copThreshold - info->carThreshold[5]; + int16 oldGang0Num = info->gangThreshold[0] - info->copThreshold; + int16 oldGang1Num = info->gangThreshold[1] - info->gangThreshold[0]; + int16 oldGang2Num = info->gangThreshold[2] - info->gangThreshold[1]; + int16 oldGang3Num = info->gangThreshold[3] - info->gangThreshold[2]; + int16 oldGang4Num = info->gangThreshold[4] - info->gangThreshold[3]; + int16 oldGang5Num = info->gangThreshold[5] - info->gangThreshold[4]; + int16 oldGang6Num = info->gangThreshold[6] - info->gangThreshold[5]; + int16 oldGang7Num = info->gangThreshold[7] - info->gangThreshold[6]; + int16 oldGang8Num = info->gangThreshold[8] - info->gangThreshold[7]; + + if(car0Num != -1) info->carThreshold[0] = car0Num; + if(car1Num != -1) info->carThreshold[1] = info->carThreshold[0] + car1Num; + else info->carThreshold[1] = info->carThreshold[0] + oldCar1Num; + if(car2Num != -1) info->carThreshold[2] = info->carThreshold[1] + car2Num; + else info->carThreshold[2] = info->carThreshold[1] + oldCar2Num; + if(car3Num != -1) info->carThreshold[3] = info->carThreshold[2] + car3Num; + else info->carThreshold[3] = info->carThreshold[2] + oldCar3Num; + if(car4Num != -1) info->carThreshold[4] = info->carThreshold[3] + car4Num; + else info->carThreshold[4] = info->carThreshold[3] + oldCar4Num; + if(car5Num != -1) info->carThreshold[5] = info->carThreshold[4] + car5Num; + else info->carThreshold[5] = info->carThreshold[4] + oldCar5Num; + if(copNum != -1) info->copThreshold = info->carThreshold[5] + copNum; + else info->copThreshold = info->carThreshold[5] + oldCopNum; + if(gang0Num != -1) info->gangThreshold[0] = info->copThreshold + gang0Num; + else info->gangThreshold[0] = info->copThreshold + oldGang0Num; + if(gang1Num != -1) info->gangThreshold[1] = info->gangThreshold[0] + gang1Num; + else info->gangThreshold[1] = info->gangThreshold[0] + oldGang1Num; + if(gang2Num != -1) info->gangThreshold[2] = info->gangThreshold[1] + gang2Num; + else info->gangThreshold[2] = info->gangThreshold[1] + oldGang2Num; + if(gang3Num != -1) info->gangThreshold[3] = info->gangThreshold[2] + gang3Num; + else info->gangThreshold[3] = info->gangThreshold[2] + oldGang3Num; + if(gang4Num != -1) info->gangThreshold[4] = info->gangThreshold[3] + gang4Num; + else info->gangThreshold[4] = info->gangThreshold[3] + oldGang4Num; + if(gang5Num != -1) info->gangThreshold[5] = info->gangThreshold[4] + gang5Num; + else info->gangThreshold[5] = info->gangThreshold[4] + oldGang5Num; + if(gang6Num != -1) info->gangThreshold[6] = info->gangThreshold[5] + gang6Num; + else info->gangThreshold[6] = info->gangThreshold[5] + oldGang6Num; + if(gang7Num != -1) info->gangThreshold[7] = info->gangThreshold[6] + gang7Num; + else info->gangThreshold[7] = info->gangThreshold[6] + oldGang7Num; + if(gang8Num != -1) info->gangThreshold[8] = info->gangThreshold[7] + gang8Num; + else info->gangThreshold[8] = info->gangThreshold[7] + oldGang8Num; +} + +void +CTheZones::SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, + int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, + int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, + int16 gang8Density, int16 copDensity) +{ + CZone *zone; + CZoneInfo *info; + zone = GetZone(zoneid); + info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; + if(pedDensity != -1) info->pedDensity = pedDensity; + if(copDensity != -1) info->copDensity = copDensity; + if(gang0Density != -1) info->gangThreshold[0] = gang0Density; + if(gang1Density != -1) info->gangThreshold[1] = gang1Density; + if(gang2Density != -1) info->gangThreshold[2] = gang2Density; + if(gang3Density != -1) info->gangThreshold[3] = gang3Density; + if(gang4Density != -1) info->gangThreshold[4] = gang4Density; + if(gang5Density != -1) info->gangThreshold[5] = gang5Density; + if(gang6Density != -1) info->gangThreshold[6] = gang6Density; + if(gang7Density != -1) info->gangThreshold[7] = gang7Density; + if(gang8Density != -1) info->gangThreshold[8] = gang8Density; +} + +void +CTheZones::SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].carDensity = cardensity; +} + +void +CTheZones::SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedDensity = peddensity; +} + +void +CTheZones::SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedGroup = pedgroup; +} + +int16 +CTheZones::FindAudioZone(CVector *pos) +{ + int i; + + for(i = 0; i < NumberOfAudioZones; i++) + if(PointLiesWithinZone(*pos, GetZone(AudioZoneArray[i]))) + return i; + return -1; +} + +eLevelName +CTheZones::FindZoneForPoint(const CVector &pos) +{ + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("IND_ZON")))) + return LEVEL_INDUSTRIAL; + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("COM_ZON")))) + return LEVEL_COMMERCIAL; + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("SUB_ZON")))) + return LEVEL_SUBURBAN; + return LEVEL_NONE; +} + +void +CTheZones::AddZoneToAudioZoneArray(CZone *zone) +{ + int i, z; + + if(zone->type != ZONE_AUDIO) + return; + + /* This is a bit stupid */ + z = -1; + for(i = 0; i < NUMZONES; i++) + if(&ZoneArray[i] == zone) + z = i; + AudioZoneArray[NumberOfAudioZones++] = z; +} + +void +CTheZones::InitialiseAudioZoneArray(void) +{ + bool gonext; + CZone *zone; + + gonext = false; + zone = &ZoneArray[0]; + // Go deep first, + // set gonext when backing up a level to visit the next child + while(zone) + if(gonext){ + AddZoneToAudioZoneArray(zone); + if(zone->next){ + gonext = false; + zone = zone->next; + }else + zone = zone->parent; + }else if(zone->child) + zone = zone->child; + else{ + AddZoneToAudioZoneArray(zone); + if(zone->next) + zone = zone->next; + else{ + gonext = true; + zone = zone->parent; + } + } +} + +STARTPATCHES + InjectHook(0x4B5DE0, CTheZones::Init, PATCH_JUMP); + InjectHook(0x4B61D0, CTheZones::Update, PATCH_JUMP); + InjectHook(0x4B6210, CTheZones::CreateZone, PATCH_JUMP); + InjectHook(0x4B6380, CTheZones::CreateMapZone, PATCH_JUMP); + InjectHook(0x4B64C0, CTheZones::PostZoneCreation, PATCH_JUMP); + InjectHook(0x4B6500, CTheZones::InsertZoneIntoZoneHierarchy, PATCH_JUMP); + InjectHook(0x4B6530, CTheZones::InsertZoneIntoZoneHierRecursive, PATCH_JUMP); + InjectHook(0x4B65F0, CTheZones::ZoneIsEntirelyContainedWithinOtherZone, PATCH_JUMP); + InjectHook(0x4B6710, CTheZones::PointLiesWithinZone, PATCH_JUMP); + InjectHook(0x4B6910, CTheZones::GetLevelFromPosition, PATCH_JUMP); + InjectHook(0x4B69B0, CTheZones::FindSmallestZonePosition, PATCH_JUMP); + InjectHook(0x4B6790, CTheZones::FindSmallestZonePositionType, PATCH_JUMP); + InjectHook(0x4B6890, CTheZones::FindSmallestZonePositionILN, PATCH_JUMP); + InjectHook(0x4B6800, CTheZones::FindZoneByLabelAndReturnIndex, PATCH_JUMP); + InjectHook(0x4B6A10, CTheZones::GetZoneInfo, PATCH_JUMP); + InjectHook(0x4B6FB0, CTheZones::GetZoneInfoForTimeOfDay, PATCH_JUMP); + InjectHook(0x4B6A50, CTheZones::SetZoneCarInfo, PATCH_JUMP); + InjectHook(0x4B6DC0, CTheZones::SetZonePedInfo, PATCH_JUMP); + InjectHook(0x4B6EB0, CTheZones::SetCarDensity, PATCH_JUMP); + InjectHook(0x4B6F00, CTheZones::SetPedDensity, PATCH_JUMP); + InjectHook(0x4B6F50, CTheZones::SetPedGroup, PATCH_JUMP); + InjectHook(0x4B83E0, CTheZones::FindAudioZone, PATCH_JUMP); + InjectHook(0x4B8430, CTheZones::FindZoneForPoint, PATCH_JUMP); + InjectHook(0x4B8340, CTheZones::AddZoneToAudioZoneArray, PATCH_JUMP); + InjectHook(0x4B8380, CTheZones::InitialiseAudioZoneArray, PATCH_JUMP); +ENDPATCHES diff --git a/src/Zones.h b/src/Zones.h new file mode 100644 index 00000000..c7745e29 --- /dev/null +++ b/src/Zones.h @@ -0,0 +1,107 @@ +#pragma once + +#include "Game.h" + +enum eZoneType +{ + ZONE_AUDIO, + ZONE_TYPE1, // this should be NAVIG + ZONE_TYPE2, // this should be INFO...but all except MAPINFO get zoneinfo?? + ZONE_MAPZONE, +}; + +class CZone +{ +public: + char name[8]; + float minx; + float miny; + float minz; + float maxx; + float maxy; + float maxz; + eZoneType type; + eLevelName level; + int16 zoneinfoDay; + int16 zoneinfoNight; + CZone *child; + CZone *parent; + CZone *next; +}; + +class CZoneInfo +{ +public: + // Car data + uint16 carDensity; + uint16 carThreshold[6]; + uint16 copThreshold; + uint16 gangThreshold[9]; + + // Ped data + uint16 pedDensity; + uint16 copDensity; + uint16 gangDensity[9]; + uint16 pedGroup; +}; + + +class CTheZones +{ +public: + static eLevelName &m_CurrLevel; + static CZone *&m_pPlayersZone; + static int16 &FindIndex; + + static uint16 &NumberOfAudioZones; + static int16 *AudioZoneArray; //[NUMAUDIOZONES]; + static uint16 &TotalNumberOfMapZones; + static uint16 &TotalNumberOfZones; + static CZone *ZoneArray; //[NUMZONES]; + static CZone *MapZoneArray; //[NUMMAPZONES]; + static uint16 &TotalNumberOfZoneInfos; + static CZoneInfo *ZoneInfoArray; //[2*NUMZONES]; + + static void Init(void); + static void Update(void); + static void CreateZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level); + static void CreateMapZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level); + static CZone *GetZone(uint16 i) { return &ZoneArray[i]; } + static void PostZoneCreation(void); + static void InsertZoneIntoZoneHierarchy(CZone *zone); + static bool InsertZoneIntoZoneHierRecursive(CZone *z1, CZone *z2); + static bool ZoneIsEntirelyContainedWithinOtherZone(CZone *z1, CZone *z2); + static bool PointLiesWithinZone(const CVector &v, CZone *zone); + static eLevelName GetLevelFromPosition(CVector const &v); + static CZone *FindSmallestZonePosition(const CVector *v); + static CZone *FindSmallestZonePositionType(const CVector *v, eZoneType type); + static CZone *FindSmallestZonePositionILN(const CVector *v); + static int16 FindZoneByLabelAndReturnIndex(char *name); + static CZoneInfo *GetZoneInfo(const CVector *v, uint8 day); + static void GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info); + static void SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, + int16 gang0Num, int16 gang1Num, int16 gang2Num, + int16 gang3Num, int16 gang4Num, int16 gang5Num, + int16 gang6Num, int16 gang7Num, int16 gang8Num, + int16 copNum, + int16 car0Num, int16 car1Num, int16 car2Num, + int16 car3Num, int16 car4Num, int16 car5Num); + static void SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, + int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, + int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, + int16 gang8Density, int16 copDensity); + static void SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity); + static void SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity); + static void SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup); + static int16 FindAudioZone(CVector *pos); + static eLevelName FindZoneForPoint(const CVector &pos); + static CZone *GetPointerForZoneIndex(int32 i) { return i == -1 ? nil : &ZoneArray[i]; } + static void AddZoneToAudioZoneArray(CZone *zone); + static void InitialiseAudioZoneArray(void); +}; diff --git a/src/common.h b/src/common.h new file mode 100644 index 00000000..e55e5b52 --- /dev/null +++ b/src/common.h @@ -0,0 +1,97 @@ +#pragma once + +#define _CRT_SECURE_NO_WARNINGS +#define _USE_MATH_DEFINES +#pragma warning(disable: 4244) // int to float +#pragma warning(disable: 4800) // int to bool +#pragma warning(disable: 4838) // narrowing conversion + +#include +#include +#include +#include + +#include +#include + +#define rwVENDORID_ROCKSTAR 0x0253F2 + +typedef uint8_t uint8; +typedef int8_t int8; +typedef uint16_t uint16; +typedef int16_t int16; +typedef uint32_t uint32; +typedef int32_t int32; +typedef uintptr_t uintptr; + +#define nil NULL + +#include "config.h" + +#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1)) + +// little hack +extern void **rwengine; +#define RwEngineInstance (*rwengine) + +// TODO +struct RsInputDevice +{ + int inputDeviceType; + int used; + void *inputEventHandler; +}; + +struct RsGlobalType +{ + const char *appName; + int width; + int height; + int maximumWidth; + int maximumHeight; + int maxFPS; + int quit; + void *ps; + RsInputDevice keyboard; + RsInputDevice mouse; + RsInputDevice pad; +}; +extern RsGlobalType &RsGlobal; + +#define SCREENW (RsGlobal.maximumWidth) +#define SCREENH (RsGlobal.maximumHeight) + +struct GlobalScene +{ + RpWorld *world; + RwCamera *camera; +}; +extern GlobalScene &Scene; + +#include "math/Vector.h" +#include "math/Vector2D.h" +#include "math/Matrix.h" +#include "math/Rect.h" + +class CRGBA +{ +public: + uint8 r, g, b, a; + CRGBA(void) { } + CRGBA(uint8 r, uint8 g, uint8 b, uint8 a) : r(r), g(g), b(b), a(a) { } +}; + +inline float +clamp(float v, float min, float max){ return vmax ? max : v; } +inline float +sq(float x) { return x*x; } +#define PI M_PI +#define DEGTORAD(d) (d/180.0f*PI) + +int myrand(void); +void mysrand(unsigned int seed); + +#define debug printf + +//#define min(a, b) ((a) < (b) ? (a) : (b)) +//#define max(a, b) ((a) > (b) ? (a) : (b)) diff --git a/src/config.h b/src/config.h new file mode 100644 index 00000000..df99487f --- /dev/null +++ b/src/config.h @@ -0,0 +1,56 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +enum Config { + NUMCDIMAGES = 50, // was 12 + + MODELINFOSIZE = 5500, + TXDSTORESIZE = 850, + EXTRADIRSIZE = 128, + + SIMPLEMODELSIZE = 5000, + TIMEMODELSIZE = 30, + CLUMPMODELSIZE = 5, + PEDMODELSIZE = 90, + VEHICLEMODELSIZE = 120, + TWODFXSIZE = 2000, + + NUMOBJECTINFO = 168, // object.dat + + // Pool sizes + NUMPTRNODES = 30000, // 26000 on PS2 + NUMENTRYINFOS = 5400, // 3200 on PS2 + NUMPEDS = 140, // 90 on PS2 + NUMVEHICLES = 110, // 70 on PS2 + NUMBUILDINGS = 5500, // 4915 on PS2 + NUMTREADABLES = 1214, + NUMOBJECTS = 450, + NUMDUMMIES = 2802, // 2368 on PS2 + NUMAUDIOSCRIPTOBJECTS = 256, + + // Link list lengths + // TODO: alpha list + NUMCOLCACHELINKS = 200, + NUMREFERENCES = 800, + + // Zones + NUMAUDIOZONES = 36, + NUMZONES = 50, + NUMMAPZONES = 25, + + // Cull zones + NUMCULLZONES = 512, + NUMATTRIBZONES = 288, + NUMZONEINDICES = 55000, + + + NUMPEDSTATS = 35, + NUMHANDLINGS = 57, + + PATHNODESIZE = 4500, + + NUMWEATHERS = 4, + NUMHOURS = 24, +}; + +#endif diff --git a/src/debugmenu_public.h b/src/debugmenu_public.h new file mode 100644 index 00000000..3671caca --- /dev/null +++ b/src/debugmenu_public.h @@ -0,0 +1,154 @@ + +extern "C" { + +typedef void (*TriggerFunc)(void); + +struct DebugMenuEntry; + +typedef DebugMenuEntry *(*DebugMenuAddInt8_TYPE)(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt16_TYPE)(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt32_TYPE)(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt64_TYPE)(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt8_TYPE)(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt16_TYPE)(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt32_TYPE)(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt64_TYPE)(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddFloat32_TYPE)(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound); +typedef DebugMenuEntry *(*DebugMenuAddFloat64_TYPE)(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound); +typedef DebugMenuEntry *(*DebugMenuAddCmd_TYPE)(const char *path, const char *name, TriggerFunc triggerFunc); +typedef void (*DebugMenuEntrySetWrap_TYPE)(DebugMenuEntry *e, bool wrap); +typedef void (*DebugMenuEntrySetStrings_TYPE)(DebugMenuEntry *e, const char **strings); +typedef void (*DebugMenuEntrySetAddress_TYPE)(DebugMenuEntry *e, void *addr); + +struct DebugMenuAPI +{ + bool isLoaded; + HMODULE module; + DebugMenuAddInt8_TYPE addint8; + DebugMenuAddInt16_TYPE addint16; + DebugMenuAddInt32_TYPE addint32; + DebugMenuAddInt64_TYPE addint64; + DebugMenuAddUInt8_TYPE adduint8; + DebugMenuAddUInt16_TYPE adduint16; + DebugMenuAddUInt32_TYPE adduint32; + DebugMenuAddUInt64_TYPE adduint64; + DebugMenuAddFloat32_TYPE addfloat32; + DebugMenuAddFloat64_TYPE addfloat64; + DebugMenuAddCmd_TYPE addcmd; + DebugMenuEntrySetWrap_TYPE setwrap; + DebugMenuEntrySetStrings_TYPE setstrings; + DebugMenuEntrySetAddress_TYPE setaddress; +}; +extern DebugMenuAPI gDebugMenuAPI; + +inline DebugMenuEntry *DebugMenuAddInt8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt64(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt8(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt16(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt32(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt64(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddFloat32(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) +{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddFloat64(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) +{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddCmd(const char *path, const char *name, TriggerFunc triggerFunc) +{ return gDebugMenuAPI.addcmd(path, name, triggerFunc); } +inline void DebugMenuEntrySetWrap(DebugMenuEntry *e, bool wrap) +{ gDebugMenuAPI.setwrap(e, wrap); } +inline void DebugMenuEntrySetStrings(DebugMenuEntry *e, const char **strings) +{ gDebugMenuAPI.setstrings(e, strings); } +inline void DebugMenuEntrySetAddress(DebugMenuEntry *e, void *addr) +{ gDebugMenuAPI.setaddress(e, addr); } + +inline bool DebugMenuLoad(void) +{ + if(gDebugMenuAPI.isLoaded) + return true; + HMODULE mod = LoadLibraryA("debugmenu"); + if(mod == 0){ + char modulePath[MAX_PATH]; + HMODULE dllModule; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&gDebugMenuAPI, &dllModule); + GetModuleFileNameA(dllModule, modulePath, MAX_PATH); + char *p = strchr(modulePath, '\\'); + if(p) p[1] = '\0'; + strcat(modulePath, "debugmenu"); + mod = LoadLibraryA(modulePath); + } + if(mod == 0) + return false; + gDebugMenuAPI.addint8 = (DebugMenuAddInt8_TYPE)GetProcAddress(mod, "DebugMenuAddInt8"); + gDebugMenuAPI.addint16 = (DebugMenuAddInt16_TYPE)GetProcAddress(mod, "DebugMenuAddInt16"); + gDebugMenuAPI.addint32 = (DebugMenuAddInt32_TYPE)GetProcAddress(mod, "DebugMenuAddInt32"); + gDebugMenuAPI.addint64 = (DebugMenuAddInt64_TYPE)GetProcAddress(mod, "DebugMenuAddInt64"); + gDebugMenuAPI.adduint8 = (DebugMenuAddUInt8_TYPE)GetProcAddress(mod, "DebugMenuAddUInt8"); + gDebugMenuAPI.adduint16 = (DebugMenuAddUInt16_TYPE)GetProcAddress(mod, "DebugMenuAddUInt16"); + gDebugMenuAPI.adduint32 = (DebugMenuAddUInt32_TYPE)GetProcAddress(mod, "DebugMenuAddUInt32"); + gDebugMenuAPI.adduint64 = (DebugMenuAddUInt64_TYPE)GetProcAddress(mod, "DebugMenuAddUInt64"); + gDebugMenuAPI.addfloat32 = (DebugMenuAddFloat32_TYPE)GetProcAddress(mod, "DebugMenuAddFloat32"); + gDebugMenuAPI.addfloat64 = (DebugMenuAddFloat64_TYPE)GetProcAddress(mod, "DebugMenuAddFloat64"); + gDebugMenuAPI.addcmd = (DebugMenuAddCmd_TYPE)GetProcAddress(mod, "DebugMenuAddCmd"); + gDebugMenuAPI.setwrap = (DebugMenuEntrySetWrap_TYPE)GetProcAddress(mod, "DebugMenuEntrySetWrap"); + gDebugMenuAPI.setstrings = (DebugMenuEntrySetStrings_TYPE)GetProcAddress(mod, "DebugMenuEntrySetStrings"); + gDebugMenuAPI.setaddress = (DebugMenuEntrySetAddress_TYPE)GetProcAddress(mod, "DebugMenuEntrySetAddress"); + gDebugMenuAPI.isLoaded = true; + gDebugMenuAPI.module = mod; + return true; +} + +} + +// Also overload them for simplicity + +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) +{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) +{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } + +inline DebugMenuEntry *DebugMenuAddVarBool32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} +inline DebugMenuEntry *DebugMenuAddVarBool16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} +inline DebugMenuEntry *DebugMenuAddVarBool8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp new file mode 100644 index 00000000..e8f19b01 --- /dev/null +++ b/src/entities/Building.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "rpworld.h" +#include "Building.h" +#include "Pools.h" + +void *CBuilding::operator new(size_t sz) { return CPools::GetBuildingPool()->New(); } +void CBuilding::operator delete(void *p, size_t sz) { CPools::GetBuildingPool()->Delete((CBuilding*)p); } diff --git a/src/entities/Building.h b/src/entities/Building.h new file mode 100644 index 00000000..d33aaa4f --- /dev/null +++ b/src/entities/Building.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Entity.h" + +class CBuilding : public CEntity +{ +public: + // TODO: ReplaceWithNewModel + // TODO: ctor + static void *operator new(size_t); + static void operator delete(void*, size_t); + + virtual bool GetIsATreadable(void) { return false; } +}; +static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error"); diff --git a/src/entities/CutsceneHead.cpp b/src/entities/CutsceneHead.cpp new file mode 100644 index 00000000..6a8874f5 --- /dev/null +++ b/src/entities/CutsceneHead.cpp @@ -0,0 +1,2 @@ +#include "common.h" +#include "CutsceneHead.h" diff --git a/src/entities/CutsceneHead.h b/src/entities/CutsceneHead.h new file mode 100644 index 00000000..5784ffc9 --- /dev/null +++ b/src/entities/CutsceneHead.h @@ -0,0 +1,10 @@ +#pragma once + +#include "CutsceneObject.h" + +class CCutsceneHead : public CCutsceneObject +{ +public: + RwFrame *m_pHeadNode; +}; +static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error"); diff --git a/src/entities/CutsceneObject.cpp b/src/entities/CutsceneObject.cpp new file mode 100644 index 00000000..6aa0f4b3 --- /dev/null +++ b/src/entities/CutsceneObject.cpp @@ -0,0 +1,2 @@ +#include "common.h" +#include "CutsceneObject.h" diff --git a/src/entities/CutsceneObject.h b/src/entities/CutsceneObject.h new file mode 100644 index 00000000..c5cbf83f --- /dev/null +++ b/src/entities/CutsceneObject.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Object.h" + +class CCutsceneObject : public CObject +{ +public: +}; +static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error"); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp new file mode 100644 index 00000000..11fa9ab2 --- /dev/null +++ b/src/entities/Entity.cpp @@ -0,0 +1,391 @@ +#include "common.h" +#include "rpworld.h" +#include "Placeable.h" +#include "Entity.h" +#include "Lights.h" +#include "World.h" +#include "Camera.h" +#include "References.h" +#include "TxdStore.h" +#include "Zones.h" +#include "patcher.h" + +int gBuildings; + +void +CEntity::GetBoundCentre(CVector &out) +{ + out = m_matrix * CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.center; +}; + +bool +CEntity::GetIsTouching(CVector const ¢er, float radius) +{ + return sq(GetBoundRadius()+radius) > (GetBoundCentre()-center).MagnitudeSqr(); +} + +bool +CEntity::GetIsOnScreen(void) +{ + return TheCamera.IsSphereVisible(GetBoundCentre(), GetBoundRadius(), + &TheCamera.GetCameraMatrix()); +} + +bool +CEntity::GetIsOnScreenComplex(void) +{ + RwV3d boundBox[8]; + + if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix())) + return true; + + CRect rect = GetBoundRect(); + CColModel *colmodel = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); + float z = GetPosition().z; + float minz = z + colmodel->boundingBox.min.z; + float maxz = z + colmodel->boundingBox.max.z; + boundBox[0].x = rect.left; + boundBox[0].y = rect.top; + boundBox[0].z = minz; + boundBox[1].x = rect.left; + boundBox[1].y = rect.bottom; + boundBox[1].z = minz; + boundBox[2].x = rect.right; + boundBox[2].y = rect.top; + boundBox[2].z = minz; + boundBox[3].x = rect.right; + boundBox[3].y = rect.bottom; + boundBox[3].z = minz; + boundBox[4].x = rect.left; + boundBox[4].y = rect.top; + boundBox[4].z = maxz; + boundBox[5].x = rect.left; + boundBox[5].y = rect.bottom; + boundBox[5].z = maxz; + boundBox[6].x = rect.right; + boundBox[6].y = rect.top; + boundBox[6].z = maxz; + boundBox[7].x = rect.right; + boundBox[7].y = rect.bottom; + boundBox[7].z = maxz; + + return TheCamera.IsBoxVisible(boundBox, &TheCamera.GetCameraMatrix()); +} + +void +CEntity::Add(void) +{ + int x, xstart, xmid, xend; + int y, ystart, ymid, yend; + CSector *s; + CPtrList *list; + + CRect bounds = GetBoundRect(); + xstart = CWorld::GetSectorIndexX(bounds.left); + xend = CWorld::GetSectorIndexX(bounds.right); + xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f); + ystart = CWorld::GetSectorIndexY(bounds.bottom); + yend = CWorld::GetSectorIndexY(bounds.top); + ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f); + assert(xstart >= 0); + assert(xend < NUMSECTORS_X); + assert(ystart >= 0); + assert(yend < NUMSECTORS_Y); + + for(y = ystart; y <= yend; y++) + for(x = xstart; x <= xend; x++){ + s = CWorld::GetSector(x, y); + if(x == xmid && y == ymid) switch(m_type){ + case ENTITY_TYPE_BUILDING: + list = &s->m_lists[ENTITYLIST_BUILDINGS]; + break; + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS]; + break; + case ENTITY_TYPE_DUMMY: + list = &s->m_lists[ENTITYLIST_DUMMIES]; + break; + }else switch(m_type){ + case ENTITY_TYPE_BUILDING: + list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]; + break; + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP]; + break; + case ENTITY_TYPE_DUMMY: + list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP]; + break; + } + list->InsertItem(this); + } +} + +void +CEntity::Remove(void) +{ + int x, xstart, xmid, xend; + int y, ystart, ymid, yend; + CSector *s; + CPtrList *list; + + CRect bounds = GetBoundRect(); + xstart = CWorld::GetSectorIndexX(bounds.left); + xend = CWorld::GetSectorIndexX(bounds.right); + xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f); + ystart = CWorld::GetSectorIndexY(bounds.bottom); + yend = CWorld::GetSectorIndexY(bounds.top); + ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f); + assert(xstart >= 0); + assert(xend < NUMSECTORS_X); + assert(ystart >= 0); + assert(yend < NUMSECTORS_Y); + + for(y = ystart; y <= yend; y++) + for(x = xstart; x <= xend; x++){ + s = CWorld::GetSector(x, y); + if(x == xmid && y == ymid) switch(m_type){ + case ENTITY_TYPE_BUILDING: + list = &s->m_lists[ENTITYLIST_BUILDINGS]; + break; + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS]; + break; + case ENTITY_TYPE_DUMMY: + list = &s->m_lists[ENTITYLIST_DUMMIES]; + break; + }else switch(m_type){ + case ENTITY_TYPE_BUILDING: + list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]; + break; + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP]; + break; + case ENTITY_TYPE_DUMMY: + list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP]; + break; + } + list->RemoveItem(this); + } +} + +void +CEntity::CreateRwObject(void) +{ + CBaseModelInfo *mi; + + mi = CModelInfo::GetModelInfo(m_modelIndex); + m_rwObject = mi->CreateInstance(); + if(m_rwObject){ + if(IsBuilding()) + gBuildings++; + if(RwObjectGetType(m_rwObject) == rpATOMIC) + m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false); + else if(RwObjectGetType(m_rwObject) == rpCLUMP) + m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false); + mi->AddRef(); + } +} + +void +CEntity::DeleteRwObject(void) +{ + RwFrame *f; + + m_matrix.Detach(); + if(m_rwObject){ + if(RwObjectGetType(m_rwObject) == rpATOMIC){ + f = RpAtomicGetFrame(m_rwObject); + RpAtomicDestroy((RpAtomic*)m_rwObject); + RwFrameDestroy(f); + }else if(RwObjectGetType(m_rwObject) == rpCLUMP) + RpClumpDestroy((RpClump*)m_rwObject); + m_rwObject = nil; + CModelInfo::GetModelInfo(m_modelIndex)->RemoveRef(); + if(IsBuilding()) + gBuildings--; + } +} + +void +CEntity::UpdateRwFrame(void) +{ + if(m_rwObject){ + if(RwObjectGetType(m_rwObject) == rpATOMIC) + RwFrameUpdateObjects(RpAtomicGetFrame(m_rwObject)); + else if(RwObjectGetType(m_rwObject) == rpCLUMP) + RwFrameUpdateObjects(RpClumpGetFrame(m_rwObject)); + } +} + +void +CEntity::SetupBigBuilding(void) +{ + CSimpleModelInfo *mi; + + mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); + bIsBIGBuilding = true; + m_flagC20 = true; + bUsesCollision = false; + m_level = CTheZones::GetLevelFromPosition(GetPosition()); + if(m_level == LEVEL_NONE){ + if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){ + mi->SetTexDictionary("generic"); + printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetName()); + } + } + if(mi->m_lodDistances[0] > 2000.0f) + m_level = LEVEL_NONE; +} + +CRect +CEntity::GetBoundRect(void) +{ + CRect rect; + CVector v; + CColModel *col = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); + + rect.ContainPoint(m_matrix * col->boundingBox.min); + rect.ContainPoint(m_matrix * col->boundingBox.max); + + v = col->boundingBox.min; + v.x = col->boundingBox.max.x; + rect.ContainPoint(m_matrix * v); + + v = col->boundingBox.max; + v.x = col->boundingBox.min.x; + rect.ContainPoint(m_matrix * v); + + return rect; +} + +void +CEntity::PreRender(void) +{ +} + +void +CEntity::Render(void) +{ + if(m_rwObject){ + bImBeingRendered = true; + if(RwObjectGetType(m_rwObject) == rpATOMIC) + RpAtomicRender((RpAtomic*)m_rwObject); + else + RpClumpRender((RpClump*)m_rwObject); + bImBeingRendered = false; + } +} + +bool +CEntity::SetupLighting(void) +{ + DeActivateDirectional(); + SetAmbientColours(); + return false; +} + +void +CEntity::RegisterReference(CEntity **pent) +{ + if(IsBuilding()) + return; + CReference *ref; + // check if already registered + for(ref = m_pFirstReference; ref; ref = ref->next) + if(ref->pentity == pent) + return; + // have to allocate new reference + ref = CReferences::pEmptyList; + if(ref){ + CReferences::pEmptyList = ref->next; + + ref->pentity = pent; + ref->next = m_pFirstReference; + m_pFirstReference = ref; + return; + } + return; +} + +// Clear all references to this entity +void +CEntity::ResolveReferences(void) +{ + CReference *ref; + // clear pointers to this entity + for(ref = m_pFirstReference; ref; ref = ref->next) + if(*ref->pentity == this) + *ref->pentity = nil; + // free list + if(m_pFirstReference){ + for(ref = m_pFirstReference; ref->next; ref = ref->next) + ; + ref->next = CReferences::pEmptyList; + CReferences::pEmptyList = ref; + m_pFirstReference = nil; + } +} + +// Free all references that no longer point to this entity +void +CEntity::PruneReferences(void) +{ + CReference *ref, *next, **lastnextp; + lastnextp = &m_pFirstReference; + for(ref = m_pFirstReference; ref; ref = next){ + next = ref->next; + if(*ref->pentity == this) + lastnextp = &ref->next; + else{ + *lastnextp = ref->next; + ref->next = CReferences::pEmptyList; + CReferences::pEmptyList = ref; + } + } +} + +STARTPATCHES + InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP); + InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP); + InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP); + InjectHook(0x474CC0, &CEntity::GetIsOnScreen, PATCH_JUMP); + InjectHook(0x474D20, &CEntity::GetIsOnScreenComplex, PATCH_JUMP); + InjectHook(0x474CA0, &CEntity::IsVisible, PATCH_JUMP); + InjectHook(0x474330, &CEntity::UpdateRwFrame, PATCH_JUMP); + InjectHook(0x4755E0, &CEntity::SetupBigBuilding, PATCH_JUMP); + InjectHook(0x4A7480, &CEntity::RegisterReference, PATCH_JUMP); + InjectHook(0x4A74E0, &CEntity::ResolveReferences, PATCH_JUMP); + InjectHook(0x4A7530, &CEntity::PruneReferences, PATCH_JUMP); + + InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP); + InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP); + InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP); + InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP); + InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP); + InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP); +ENDPATCHES diff --git a/src/entities/Entity.h b/src/entities/Entity.h new file mode 100644 index 00000000..8bcd7348 --- /dev/null +++ b/src/entities/Entity.h @@ -0,0 +1,146 @@ +#pragma once + +#include "ModelInfo.h" +#include "Placeable.h" + +struct CReference; + +enum eEntityType +{ + ENTITY_TYPE_NOTHING = 0, + ENTITY_TYPE_BUILDING, + ENTITY_TYPE_VEHICLE, + ENTITY_TYPE_PED, + ENTITY_TYPE_OBJECT, + ENTITY_TYPE_DUMMY, + ENTITY_TYPE_6, + ENTITY_TYPE_7, +}; + +enum eEntityStatus +{ + // from SA MTA! let's hope they didn't change from III + STATUS_PLAYER = 0, + STATUS_PLAYER_PLAYBACKFROMBUFFER, + STATUS_SIMPLE, + STATUS_PHYSICS, + STATUS_ABANDONED, + STATUS_WRECKED, + STATUS_TRAIN_MOVING, + STATUS_TRAIN_NOT_MOVING, + STATUS_HELI, + STATUS_PLANE, + STATUS_PLAYER_REMOTE, + STATUS_PLAYER_DISABLED, + //STATUS_TRAILER, + //STATUS_SIMPLE_TRAILER +}; + +class CEntity : public CPlaceable +{ +public: + RwObject *m_rwObject; + uint32 m_type : 3; + uint32 m_status : 5; + + // flagsA + uint32 bUsesCollision : 1; + uint32 bCollisionProcessed : 1; + uint32 bIsStatic : 1; + uint32 bHasContacted : 1; + uint32 bPedPhysics : 1; + uint32 bIsStuck : 1; + uint32 bIsInSafePosition : 1; + uint32 bUseCollisionRecords : 1; + + // flagsB + uint32 bWasPostponed : 1; + uint32 m_flagB2 : 1; // explosion proof? + uint32 bIsVisible : 1; + uint32 bHasCollided : 1; // + uint32 bRenderScorched : 1; + uint32 m_flagB20 : 1; // bFlashing? + uint32 bIsBIGBuilding : 1; + // VC inserts one more flag here: if drawdist <= 2000 + uint32 bRenderDamaged : 1; + + // flagsC + uint32 m_flagC1 : 1; // bullet proof? + uint32 m_flagC2 : 1; // fire proof? + uint32 m_flagC4 : 1; // collision proof? + uint32 m_flagC8 : 1; // melee proof? + uint32 m_flagC10 : 1; // bOnlyDamagedByPlayer? + uint32 m_flagC20 : 1; + uint32 m_bZoneCulled : 1; + uint32 m_bZoneCulled2 : 1; // only treadables+10m + + // flagsD + uint32 bRemoveFromWorld : 1; + uint32 bHasHitWall : 1; + uint32 bImBeingRendered : 1; + uint32 m_flagD8 : 1; + uint32 m_flagD10 : 1; + uint32 bDrawLast : 1; + uint32 m_flagD40 : 1; + uint32 m_flagD80 : 1; + + // flagsE + uint32 bDistanceFade : 1; + uint32 m_flagE2 : 1; + + uint16 m_scanCode; + int16 m_randomSeed; + int16 m_modelIndex; + uint16 m_level; // int16 + CReference *m_pFirstReference; + + virtual void Add(void); + virtual void Remove(void); + virtual void SetModelIndex(uint32 i) { m_modelIndex = i; CreateRwObject(); } + virtual void SetModelIndexNoCreate(uint32 i) { m_modelIndex = i; } + virtual void CreateRwObject(void); + virtual void DeleteRwObject(void); + virtual CRect GetBoundRect(void); + virtual void ProcessControl(void) {} + virtual void ProcessCollision(void) {} + virtual void ProcessShift(void) {} + virtual void Teleport(CVector v) {} + virtual void PreRender(void); + virtual void Render(void); + virtual bool SetupLighting(void); + virtual void RemoveLighting(bool) {} + virtual void FlagToDestroyWhenNextProcessed(void) {} + + bool IsBuilding(void) { return m_type == ENTITY_TYPE_BUILDING; } + bool IsVehicle(void) { return m_type == ENTITY_TYPE_VEHICLE; } + bool IsPed(void) { return m_type == ENTITY_TYPE_PED; } + bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; } + bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; } + + void GetBoundCentre(CVector &out); + CVector GetBoundCentre(void) { CVector v; GetBoundCentre(v); return v; } + float GetBoundRadius(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.radius; } + bool GetIsTouching(CVector const ¢er, float r); + bool GetIsOnScreen(void); + bool GetIsOnScreenComplex(void); + bool IsVisible(void) { return m_rwObject && bIsVisible && GetIsOnScreen(); } + bool IsVisibleComplex(void) { return m_rwObject && bIsVisible && GetIsOnScreenComplex(); } + int GetModelIndex(void) { return m_modelIndex; } + void UpdateRwFrame(void); + void SetupBigBuilding(void); + + void RegisterReference(CEntity **pent); + void ResolveReferences(void); + void PruneReferences(void); + + + // to make patching virtual functions possible + void Add_(void) { CEntity::Add(); } + void Remove_(void) { CEntity::Remove(); } + void CreateRwObject_(void) { CEntity::CreateRwObject(); } + void DeleteRwObject_(void) { CEntity::DeleteRwObject(); } + CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); } + void Render_(void) { CEntity::Render(); } + bool SetupLighting_(void) { return CEntity::SetupLighting(); } +}; +static_assert(sizeof(CEntity) == 0x64, "CEntity: error"); diff --git a/src/entities/Object.cpp b/src/entities/Object.cpp new file mode 100644 index 00000000..8ce1250f --- /dev/null +++ b/src/entities/Object.cpp @@ -0,0 +1,9 @@ +#include "common.h" +#include "patcher.h" +#include "Object.h" +#include "Pools.h" + +void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); } +void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); } + +WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); } diff --git a/src/entities/Object.h b/src/entities/Object.h new file mode 100644 index 00000000..6992b92d --- /dev/null +++ b/src/entities/Object.h @@ -0,0 +1,50 @@ +#pragma once + +#include "Physical.h" + +enum { + GAME_OBJECT = 1, + MISSION_OBJECT = 2, + TEMP_OBJECT = 3, +}; + +class CObject : public CPhysical +{ +public: + CMatrix m_objectMatrix; + float m_fUprootLimit; + int8 ObjectCreatedBy; +// int8 m_nObjectFlags; + int8 m_obj_flag1 : 1; + int8 m_obj_flag2 : 1; + int8 m_obj_flag4 : 1; + int8 m_obj_flag8 : 1; + int8 m_obj_flag10 : 1; + int8 bHasBeenDamaged : 1; + int8 m_obj_flag40 : 1; + int8 m_obj_flag80 : 1; + int8 field_172; + int8 field_173; + float m_fCollisionDamageMultiplier; + int8 m_nCollisionDamageEffect; + int8 m_bSpecialCollisionResponseCases; + int8 m_bCameraToAvoidThisObject; + int8 field_17B; + int8 field_17C; + int8 field_17D; + int8 field_17E; + int8 field_17F; + int32 m_nEndOfLifeTime; + int16 m_nRefModelIndex; + int8 field_186; + int8 field_187; + CEntity *m_pCurSurface; + CEntity *field_18C; + int8 m_colour1, m_colour2; + + static void *operator new(size_t); + static void operator delete(void*, size_t); + + void ObjectDamage(float amount); +}; +static_assert(sizeof(CObject) == 0x198, "CObject: error"); diff --git a/src/entities/Ped.h b/src/entities/Ped.h new file mode 100644 index 00000000..fd71b616 --- /dev/null +++ b/src/entities/Ped.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Physical.h" + +enum PedAction +{ + PED_PASSENGER = 44, +}; + +class CVehicle; + +class CPed : public CPhysical +{ +public: + // 0x128 + uint8 stuff1[252]; + int32 m_nPedState; + uint8 stuff2[196]; + CEntity *m_pCurrentPhysSurface; + CVector m_vecOffsetFromPhysSurface; + CEntity *m_pCurSurface; + uint8 stuff3[16]; + CVehicle *m_pMyVehicle; + bool bInVehicle; + uint8 stuff4[23]; + int32 m_nPedType; + uint8 stuff5[528]; + + bool IsPlayer(void) { return m_nPedType == 0 || m_nPedType== 1 || m_nPedType == 2 || m_nPedType == 3; } +}; +static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error"); +static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error"); +static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error"); +static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error"); +static_assert(sizeof(CPed) == 0x540, "CPed: error"); diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp new file mode 100644 index 00000000..f235cb42 --- /dev/null +++ b/src/entities/Physical.cpp @@ -0,0 +1,916 @@ +#include "common.h" +#include "patcher.h" +#include "World.h" +#include "Timer.h" +#include "ModelIndices.h" +#include "Vehicle.h" +#include "Ped.h" +#include "Object.h" +#include "Glass.h" +#include "ParticleObject.h" +#include "Particle.h" +#include "SurfaceTable.h" +#include "Physical.h" + +void +CPhysical::Add(void) +{ + int x, xstart, xmid, xend; + int y, ystart, ymid, yend; + CSector *s; + CPtrList *list; + + CRect bounds = GetBoundRect(); + xstart = CWorld::GetSectorIndexX(bounds.left); + xend = CWorld::GetSectorIndexX(bounds.right); + xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f); + ystart = CWorld::GetSectorIndexY(bounds.bottom); + yend = CWorld::GetSectorIndexY(bounds.top); + ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f); + assert(xstart >= 0); + assert(xend < NUMSECTORS_X); + assert(ystart >= 0); + assert(yend < NUMSECTORS_Y); + + for(y = ystart; y <= yend; y++) + for(x = xstart; x <= xend; x++){ + s = CWorld::GetSector(x, y); + if(x == xmid && y == ymid) switch(m_type){ + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS]; + break; + default: + assert(0); + }else switch(m_type){ + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP]; + break; + default: + assert(0); + } + CPtrNode *node = list->InsertItem(this); + assert(node); + m_entryInfoList.InsertItem(list, node, s); + } +} + +void +CPhysical::Remove(void) +{ + CEntryInfoNode *node, *next; + for(node = m_entryInfoList.first; node; node = next){ + next = node->next; + node->list->DeleteNode(node->listnode); + m_entryInfoList.DeleteNode(node); + } +} + +void +CPhysical::RemoveAndAdd(void) +{ + int x, xstart, xmid, xend; + int y, ystart, ymid, yend; + CSector *s; + CPtrList *list; + + CRect bounds = GetBoundRect(); + xstart = CWorld::GetSectorIndexX(bounds.left); + xend = CWorld::GetSectorIndexX(bounds.right); + xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f); + ystart = CWorld::GetSectorIndexY(bounds.bottom); + yend = CWorld::GetSectorIndexY(bounds.top); + ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f); + assert(xstart >= 0); + assert(xend < NUMSECTORS_X); + assert(ystart >= 0); + assert(yend < NUMSECTORS_Y); + + // we'll try to recycle nodes from here + CEntryInfoNode *next = m_entryInfoList.first; + + for(y = ystart; y <= yend; y++) + for(x = xstart; x <= xend; x++){ + s = CWorld::GetSector(x, y); + if(x == xmid && y == ymid) switch(m_type){ + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS]; + break; + }else switch(m_type){ + case ENTITY_TYPE_VEHICLE: + list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]; + break; + case ENTITY_TYPE_PED: + list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP]; + break; + case ENTITY_TYPE_OBJECT: + list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP]; + break; + } + if(next){ + // If we still have old nodes, use them + next->list->RemoveNode(next->listnode); + list->InsertNode(next->listnode); + next->list = list; + next->sector = s; + next = next->next; + }else{ + CPtrNode *node = list->InsertItem(this); + m_entryInfoList.InsertItem(list, node, s); + } + } + + // Remove old nodes we no longer need + CEntryInfoNode *node; + for(node = next; node; node = next){ + next = node->next; + node->list->DeleteNode(node->listnode); + m_entryInfoList.DeleteNode(node); + } +} + +CRect +CPhysical::GetBoundRect(void) +{ + CVector center; + float radius; + GetBoundCentre(center); + radius = GetBoundRadius(); + return CRect(center.x-radius, center.y-radius, center.x+radius, center.y+radius); +} + +void +CPhysical::AddToMovingList(void) +{ + m_movingListNode = CWorld::GetMovingEntityList().InsertItem(this); +} + +void +CPhysical::RemoveFromMovingList(void) +{ + if(m_movingListNode){ + CWorld::GetMovingEntityList().DeleteNode(m_movingListNode); + m_movingListNode = nil; + } +} + + +/* + * Some quantities (german in parens): + * + * acceleration: distance/time^2: a + * velocity: distance/time: v (GTA: speed) + * momentum (impuls): velocity*mass: p + * impulse (kraftstoss): delta momentum, force*time: J + * + * angular equivalents: + * velocity -> angular velocity (GTA: turn speed) + * momentum -> angular momentum (drehimpuls): L = r cross p + * force -> torque (drehmoment): tau = r cross F + * mass -> moment of inertia, angular mass (drehmoment, drehmasse): I = L/omega (GTA: turn mass) + */ + +CVector +CPhysical::GetSpeed(const CVector &r) +{ + return m_vecMoveSpeed + m_vecMoveFriction + CrossProduct(m_vecTurnFriction + m_vecTurnSpeed, r); +} + +void +CPhysical::ApplyMoveSpeed(void) +{ + GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep(); +} + +void +CPhysical::ApplyTurnSpeed(void) +{ + // Move the coordinate axes by their speed + // Note that this denormalizes the matrix + CVector turnvec = m_vecTurnSpeed*CTimer::GetTimeStep(); + GetRight() += CrossProduct(turnvec, GetRight()); + GetForward() += CrossProduct(turnvec, GetForward()); + GetUp() += CrossProduct(turnvec, GetUp()); +} + +void +CPhysical::ApplyMoveForce(float jx, float jy, float jz) +{ + m_vecMoveSpeed += CVector(jx, jy, jz)*(1.0f/m_fMass); +} + +void +CPhysical::ApplyTurnForce(float jx, float jy, float jz, float px, float py, float pz) +{ + CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass); + CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz)); + m_vecTurnSpeed += turnimpulse*(1.0f/m_fTurnMass); +} + +void +CPhysical::ApplyFrictionMoveForce(float jx, float jy, float jz) +{ + m_vecMoveFriction += CVector(jx, jy, jz)*(1.0f/m_fMass); +} + +void +CPhysical::ApplyFrictionTurnForce(float jx, float jy, float jz, float px, float py, float pz) +{ + CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass); + CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz)); + m_vecTurnFriction += turnimpulse*(1.0f/m_fTurnMass); +} + +void +CPhysical::ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3) +{ + if(1.0f - f2 <= 0.0f) + return; + float step = min(CTimer::GetTimeStep(), 3.0f); + float strength = -0.008f*m_fMass*2.0f*step * f1 * (1.0f-f2) * f3; + ApplyMoveForce(v.x*strength, v.y*strength, v.z*strength); + ApplyTurnForce(v.x*strength, v.y*strength, v.z*strength, p.x, p.y, p.z); +} + +void +CPhysical::ApplyGravity(void) +{ + if(bAffectedByGravity) + m_vecMoveSpeed.z -= 0.008f * CTimer::GetTimeStep(); +} + +void +CPhysical::ApplyFriction(void) +{ + m_vecMoveSpeed += m_vecMoveFriction; + m_vecTurnSpeed += m_vecTurnFriction; + m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); +} + +void +CPhysical::ApplyAirResistance(void) +{ + if(m_fAirResistance > 0.1f){ + float f = powf(m_fAirResistance, CTimer::GetTimeStep()); + m_vecMoveSpeed *= f; + m_vecTurnSpeed *= f; + }else{ + float f = powf(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); + m_vecMoveSpeed *= f; + m_vecTurnSpeed *= 0.99f; + } +} + + +bool +CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB) +{ + float eA, eB; + CPhysical *A = this; + CObject *Bobj = (CObject*)B; + + bool ispedcontactA = false; + bool ispedcontactB = false; + + float timestepA; + if(B->bPedPhysics){ + timestepA = 10.0f; + if(B->IsPed() && ((CPed*)B)->m_pCurrentPhysSurface == A) + ispedcontactA = true; + }else + timestepA = A->m_phy_flagA1 ? 2.0f : 1.0f; + + float timestepB; + if(A->bPedPhysics){ + if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() && + (B->m_status == STATUS_ABANDONED || B->m_status == STATUS_WRECKED || A->bHasHitWall)) + timestepB = 2200.0f / B->m_fMass; + else + timestepB = 10.0f; + + if(A->IsPed() && ((CPed*)A)->m_pCurrentPhysSurface == B) + ispedcontactB = true; + }else + timestepB = B->m_phy_flagA1 ? 2.0f : 1.0f; + + float speedA, speedB; + if(B->bIsStatic){ + if(A->bPedPhysics){ + speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); + if(speedA < 0.0f){ + if(B->IsObject()){ + impulseA = -speedA * A->m_fMass; + impulseB = impulseA; + if(impulseA > Bobj->m_fUprootLimit){ + if(IsGlass(B->GetModelIndex())) + CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false); + else if(!B->bInfiniteMass) + B->bIsStatic = false; + }else{ + if(IsGlass(B->GetModelIndex())) + CGlass::WindowRespondsToSoftCollision(B, impulseA); + if(!A->bInfiniteMass) + A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA); + return true; + } + }else if(!B->bInfiniteMass) + B->bIsStatic = false; + + if(B->bInfiniteMass){ + impulseA = -speedA * A->m_fMass; + impulseB = 0.0f; + if(!A->bInfiniteMass) + A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA); + return true; + } + } + }else{ + CVector pointposA = colpoint.point - A->GetPosition(); + speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); + if(speedA < 0.0f){ + if(B->IsObject()){ + if(A->bHasHitWall) + eA = -1.0f; + else + eA = -(1.0f + A->m_fElasticity); + impulseA = eA * speedA * A->GetMass(pointposA, colpoint.normal); + impulseB = impulseA; + + if(Bobj->m_nCollisionDamageEffect && impulseA > 20.0f){ + Bobj->ObjectDamage(impulseA); + if(!B->bUsesCollision){ + if(!A->bInfiniteMass){ + A->ApplyMoveForce(colpoint.normal*0.2f*impulseA); + A->ApplyTurnForce(colpoint.normal*0.2f*impulseA, pointposA); + } + return false; + } + } + + if((impulseA > Bobj->m_fUprootLimit || A->bIsStuck) && + !B->bInfiniteMass){ + if(IsGlass(B->GetModelIndex())) + CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false); + else + B->bIsStatic = false; + int16 model = B->GetModelIndex(); + if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){ + CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true); + Bobj->bHasBeenDamaged = true; + }else if(B->IsObject() && model != MI_EXPLODINGBARREL && model != MI_PETROLPUMP) + Bobj->bHasBeenDamaged = true; + }else{ + if(IsGlass(B->GetModelIndex())) + CGlass::WindowRespondsToSoftCollision(B, impulseA); + CVector f = colpoint.normal * impulseA; + if(A->IsVehicle() && colpoint.normal.z < 0.7f) + f.z *= 0.3f; + if(!A->bInfiniteMass){ + A->ApplyMoveForce(f); + if(!A->IsVehicle() || !CWorld::bNoMoreCollisionTorque) + A->ApplyTurnForce(f, pointposA); + } + return true; + } + }else if(!B->bInfiniteMass) + B->bIsStatic = false; + } + } + + if(B->bIsStatic) + return false; + if(!B->bInfiniteMass) + B->AddToMovingList(); + } + + // B is not static + + if(A->bPedPhysics && B->bPedPhysics){ + // negative if A is moving towards B + speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); + // positive if B is moving towards A + // not interested in how much B moves into A apparently? + // only interested in cases where A collided into B + speedB = max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal)); + // A has moved into B + if(speedA < speedB){ + if(!A->bHasHitWall) + speedB -= (speedA - speedB) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + impulseA = (speedB-speedA) * A->m_fMass * timestepA; + if(!A->bInfiniteMass) + A->ApplyMoveForce(colpoint.normal*(impulseA/timestepA)); + return true; + } + }else if(A->bPedPhysics){ + CVector pointposB = colpoint.point - B->GetPosition(); + speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); + speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal); + + float a = A->m_fMass*timestepA; + float b = B->GetMassTime(pointposB, colpoint.normal, timestepB); + float speedSum = (b*speedB + a*speedA)/(a + b); + if(speedA < speedSum){ + if(A->bHasHitWall) + eA = speedSum; + else + eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + if(B->bHasHitWall) + eB = speedSum; + else + eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + impulseA = (eA - speedA) * a; + impulseB = -(eB - speedB) * b; + CVector fA = colpoint.normal*(impulseA/timestepA); + CVector fB = colpoint.normal*(-impulseB/timestepB); + if(!A->bInfiniteMass){ + if(fA.z < 0.0f) fA.z = 0.0f; + if(ispedcontactB){ + fA.x *= 2.0f; + fA.y *= 2.0f; + } + A->ApplyMoveForce(fA); + } + if(!B->bInfiniteMass && !ispedcontactB){ + B->ApplyMoveForce(fB); + B->ApplyTurnForce(fB, pointposB); + } + return true; + } + }else if(B->bPedPhysics){ + CVector pointposA = colpoint.point - A->GetPosition(); + speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); + speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); + + float a = A->GetMassTime(pointposA, colpoint.normal, timestepA); + float b = B->m_fMass*timestepB; + float speedSum = (b*speedB + a*speedA)/(a + b); + if(speedA < speedSum){ + if(A->bHasHitWall) + eA = speedSum; + else + eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + if(B->bHasHitWall) + eB = speedSum; + else + eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + impulseA = (eA - speedA) * a; + impulseB = -(eB - speedB) * b; + CVector fA = colpoint.normal*(impulseA/timestepA); + CVector fB = colpoint.normal*(-impulseB/timestepB); + if(!A->bInfiniteMass && !ispedcontactA){ + if(fA.z < 0.0f) fA.z = 0.0f; + A->ApplyMoveForce(fA); + A->ApplyTurnForce(fA, pointposA); + } + if(!B->bInfiniteMass){ + if(fB.z < 0.0f){ + fB.z = 0.0f; + if(fabs(speedA) < 0.01f) + fB *= 0.5f; + } + if(ispedcontactA){ + fB.x *= 2.0f; + fB.y *= 2.0f; + } + B->ApplyMoveForce(fB); + } + return true; + } + }else{ + CVector pointposA = colpoint.point - A->GetPosition(); + CVector pointposB = colpoint.point - B->GetPosition(); + speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); + speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal); + float a = A->GetMassTime(pointposA, colpoint.normal, timestepA); + float b = B->GetMassTime(pointposB, colpoint.normal, timestepB); + float speedSum = (b*speedB + a*speedA)/(a + b); + if(speedA < speedSum){ + if(A->bHasHitWall) + eA = speedSum; + else + eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + if(B->bHasHitWall) + eB = speedSum; + else + eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; + impulseA = (eA - speedA) * a; + impulseB = -(eB - speedB) * b; + CVector fA = colpoint.normal*(impulseA/timestepA); + CVector fB = colpoint.normal*(-impulseB/timestepB); + if(A->IsVehicle() && !A->bHasHitWall){ + fA.x *= 1.4f; + fA.y *= 1.4f; + if(colpoint.normal.z < 0.7f) + fA.z *= 0.3f; + if(A->m_status == STATUS_PLAYER) + pointposA *= 0.8f; + if(CWorld::bNoMoreCollisionTorque){ + A->ApplyFrictionMoveForce(fA*-0.3f); + A->ApplyFrictionTurnForce(fA*-0.3f, pointposA); + } + } + if(B->IsVehicle() && !B->bHasHitWall){ + fB.x *= 1.4f; + fB.y *= 1.4f; + if(colpoint.normal.z < 0.7f) + fB.z *= 0.3f; + if(B->m_status == STATUS_PLAYER) + pointposB *= 0.8f; + if(CWorld::bNoMoreCollisionTorque){ + // BUG: the game actually uses A here, but this can't be right + B->ApplyFrictionMoveForce(fB*-0.3f); + B->ApplyFrictionTurnForce(fB*-0.3f, pointposB); + } + } + if(!A->bInfiniteMass){ + A->ApplyMoveForce(fA); + A->ApplyTurnForce(fA, pointposA); + } + if(!B->bInfiniteMass){ + if(B->bIsInSafePosition) + B->UnsetIsInSafePosition(); + B->ApplyMoveForce(fB); + B->ApplyTurnForce(fB, pointposB); + } + return true; + } + } + return false; +} + +bool +CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed) +{ + float normalSpeed; + float e; + CVector speed; + CVector vImpulse; + + if(bPedPhysics){ + normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal); + if(normalSpeed < 0.0f){ + impulse = -normalSpeed * m_fMass; + ApplyMoveForce(colpoint.normal * impulse); + return true; + } + }else{ + CVector pointpos = colpoint.point - GetPosition(); + speed = GetSpeed(pointpos); + normalSpeed = DotProduct(speed, colpoint.normal); + if(normalSpeed < 0.0f){ + float minspeed = 0.0104f * CTimer::GetTimeStep(); + if((IsObject() || IsVehicle() && GetUp().z < -0.3f) && + !bHasContacted && + fabs(m_vecMoveSpeed.x) < minspeed && + fabs(m_vecMoveSpeed.y) < minspeed && + fabs(m_vecMoveSpeed.z) < minspeed*2.0f) + e = -1.0f; + else + e = -(m_fElasticity + 1.0f); + impulse = normalSpeed * e * GetMass(pointpos, colpoint.normal); + + // ApplyMoveForce + vImpulse = colpoint.normal*impulse; + if(IsVehicle() && + (!bHasHitWall || + !(m_vecMoveSpeed.MagnitudeSqr() > 0.1 || !(B->IsBuilding() || ((CPhysical*)B)->bInfiniteMass)))) + moveSpeed += vImpulse * 1.2f * (1.0f/m_fMass); + else + moveSpeed += vImpulse * (1.0f/m_fMass); + + // ApplyTurnForce + CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass); + CVector turnimpulse = CrossProduct(pointpos-com, vImpulse); + turnSpeed += turnimpulse*(1.0f/m_fTurnMass); + + return true; + } + } + return false; +} + +bool +CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint) +{ + CVector speedA, speedB; + float normalSpeedA, normalSpeedB; + CVector vOtherSpeedA, vOtherSpeedB; + float fOtherSpeedA, fOtherSpeedB; + float speedSum; + CVector frictionDir; + float impulseA, impulseB; + float impulseLimit; + CPhysical *A = this; + + if(A->bPedPhysics && B->bPedPhysics){ + normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); + normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); + vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA; + vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB; + + fOtherSpeedA = vOtherSpeedA.Magnitude(); + fOtherSpeedB = vOtherSpeedB.Magnitude(); + + frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); + speedSum = (B->m_fMass*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(B->m_fMass + A->m_fMass); + if(fOtherSpeedA > speedSum){ + impulseA = (speedSum - fOtherSpeedA) * A->m_fMass; + impulseB = (speedSum - fOtherSpeedB) * B->m_fMass; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); + if(impulseA < -impulseLimit) impulseA = -impulseLimit; + if(impulseB > impulseLimit) impulseB = impulseLimit; // BUG: game has A's clamp again here, but this can't be right + A->ApplyFrictionMoveForce(frictionDir*impulseA); + B->ApplyFrictionMoveForce(frictionDir*impulseB); + return true; + } + }else if(A->bPedPhysics){ + if(B->IsVehicle()) + return false; + CVector pointposB = colpoint.point - B->GetPosition(); + speedB = B->GetSpeed(pointposB); + + normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); + normalSpeedB = DotProduct(speedB, colpoint.normal); + vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA; + vOtherSpeedB = speedB - colpoint.normal*normalSpeedB; + + fOtherSpeedA = vOtherSpeedA.Magnitude(); + fOtherSpeedB = vOtherSpeedB.Magnitude(); + + frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); + float massB = B->GetMass(pointposB, frictionDir); + speedSum = (massB*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(massB + A->m_fMass); + if(fOtherSpeedA > speedSum){ + impulseA = (speedSum - fOtherSpeedA) * A->m_fMass; + impulseB = (speedSum - fOtherSpeedB) * massB; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); + if(impulseA < -impulseLimit) impulseA = -impulseLimit; + if(impulseB > impulseLimit) impulseB = impulseLimit; + A->ApplyFrictionMoveForce(frictionDir*impulseA); + B->ApplyFrictionMoveForce(frictionDir*impulseB); + B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB); + return true; + } + }else if(B->bPedPhysics){ + if(A->IsVehicle()) + return false; + CVector pointposA = colpoint.point - A->GetPosition(); + speedA = A->GetSpeed(pointposA); + + normalSpeedA = DotProduct(speedA, colpoint.normal); + normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); + vOtherSpeedA = speedA - colpoint.normal*normalSpeedA; + vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB; + + fOtherSpeedA = vOtherSpeedA.Magnitude(); + fOtherSpeedB = vOtherSpeedB.Magnitude(); + + frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); + float massA = A->GetMass(pointposA, frictionDir); + speedSum = (B->m_fMass*fOtherSpeedB + massA*fOtherSpeedA)/(B->m_fMass + massA); + if(fOtherSpeedA > speedSum){ + impulseA = (speedSum - fOtherSpeedA) * massA; + impulseB = (speedSum - fOtherSpeedB) * B->m_fMass; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); + if(impulseA < -impulseLimit) impulseA = -impulseLimit; + if(impulseB > impulseLimit) impulseB = impulseLimit; + A->ApplyFrictionMoveForce(frictionDir*impulseA); + A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA); + B->ApplyFrictionMoveForce(frictionDir*impulseB); + return true; + } + }else{ + CVector pointposA = colpoint.point - A->GetPosition(); + CVector pointposB = colpoint.point - B->GetPosition(); + speedA = A->GetSpeed(pointposA); + speedB = B->GetSpeed(pointposB); + + normalSpeedA = DotProduct(speedA, colpoint.normal); + normalSpeedB = DotProduct(speedB, colpoint.normal); + vOtherSpeedA = speedA - colpoint.normal*normalSpeedA; + vOtherSpeedB = speedB - colpoint.normal*normalSpeedB; + + fOtherSpeedA = vOtherSpeedA.Magnitude(); + fOtherSpeedB = vOtherSpeedB.Magnitude(); + + frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA); + float massA = A->GetMass(pointposA, frictionDir); + float massB = B->GetMass(pointposB, frictionDir); + speedSum = (massB*fOtherSpeedB + massA*fOtherSpeedA)/(massB + massA); + if(fOtherSpeedA > speedSum){ + impulseA = (speedSum - fOtherSpeedA) * massA; + impulseB = (speedSum - fOtherSpeedB) * massB; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep(); + if(impulseA < -impulseLimit) impulseA = -impulseLimit; + if(impulseB > impulseLimit) impulseB = impulseLimit; + A->ApplyFrictionMoveForce(frictionDir*impulseA); + A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA); + B->ApplyFrictionMoveForce(frictionDir*impulseB); + B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB); + return true; + } + } + return false; +} + +bool +CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint) +{ + CVector speed; + float normalSpeed; + CVector vOtherSpeed; + float fOtherSpeed; + CVector frictionDir; + float fImpulse; + float impulseLimit; + + if(bPedPhysics){ + normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal); + vOtherSpeed = m_vecMoveSpeed - colpoint.normal*normalSpeed; + + fOtherSpeed = vOtherSpeed.Magnitude(); + if(fOtherSpeed > 0.0f){ + frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); + // not really impulse but speed + // maybe use ApplyFrictionMoveForce instead? + fImpulse = -fOtherSpeed; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep() / m_fMass; + if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; + CVector vImpulse = frictionDir*fImpulse; + m_vecMoveFriction += CVector(vImpulse.x, vImpulse.y, 0.0f); + return true; + } + }else{ + CVector pointpos = colpoint.point - GetPosition(); + speed = GetSpeed(pointpos); + normalSpeed = DotProduct(speed, colpoint.normal); + vOtherSpeed = speed - colpoint.normal*normalSpeed; + + fOtherSpeed = vOtherSpeed.Magnitude(); + if(fOtherSpeed > 0.0f){ + frictionDir = vOtherSpeed * (1.0f/fOtherSpeed); + fImpulse = -fOtherSpeed * m_fMass; + impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5f; + if(fImpulse < -impulseLimit) fImpulse = -impulseLimit; + ApplyFrictionMoveForce(frictionDir*fImpulse); + ApplyFrictionTurnForce(frictionDir*fImpulse, pointpos); + + if(fOtherSpeed > 0.1f && + colpoint.surfaceB != SURFACE_2 && colpoint.surfaceB != SURFACE_4 && + CSurfaceTable::GetAdhesionGroup(colpoint.surfaceA) == ADHESIVE_HARD){ + CVector v = frictionDir * fOtherSpeed * 0.25f; + for(int i = 0; i < 4; i++) + CParticle::AddParticle(PARTICLE_SPARK_SMALL, colpoint.point, v); + } + return true; + } + } + return false; +} + + +void +CPhysical::AddCollisionRecord(CEntity *ent) +{ + AddCollisionRecord_Treadable(ent); + this->bHasCollided = true; + ent->bHasCollided = true; + if(IsVehicle() && ent->IsVehicle()){ + if(((CVehicle*)this)->m_nAlarmState == -1) + ((CVehicle*)this)->m_nAlarmState = 15000; + if(((CVehicle*)ent)->m_nAlarmState == -1) + ((CVehicle*)ent)->m_nAlarmState = 15000; + } + if(bUseCollisionRecords){ + int i; + for(i = 0; i < m_nCollisionRecords; i++) + if(m_aCollisionRecords[i] == ent) + return; + if(m_nCollisionRecords < PHYSICAL_MAX_COLLISIONRECORDS) + m_aCollisionRecords[m_nCollisionRecords++] = ent; + m_nLastTimeCollided = CTimer::GetTimeInMilliseconds(); + } +} + +void +CPhysical::AddCollisionRecord_Treadable(CEntity *ent) +{ + if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ + CTreadable *t = (CTreadable*)ent; + if(t->m_nodeIndicesPeds[0] >= 0 || + t->m_nodeIndicesPeds[1] >= 0 || + t->m_nodeIndicesPeds[2] >= 0 || + t->m_nodeIndicesPeds[3] >= 0) + m_pedTreadable = t; + if(t->m_nodeIndicesCars[0] >= 0 || + t->m_nodeIndicesCars[1] >= 0 || + t->m_nodeIndicesCars[2] >= 0 || + t->m_nodeIndicesCars[3] >= 0) + m_carTreadable = t; + } +} + +bool +CPhysical::GetHasCollidedWith(CEntity *ent) +{ + int i; + if(bUseCollisionRecords) + for(i = 0; i < m_nCollisionRecords; i++) + if(m_aCollisionRecords[i] == ent) + return true; + return false; +} + +void +CPhysical::ProcessControl(void) +{ + if(!IsPed()) + m_phy_flagA8 = false; + bHasContacted = false; + bIsInSafePosition = false; + bWasPostponed = false; + bHasHitWall = false; + + if(m_status == STATUS_SIMPLE) + return; + + m_nCollisionRecords = 0; + bHasCollided = false; + m_nCollisionPieceType = 0; + m_fCollisionImpulse = 0.0f; + m_pCollidingEntity = nil; + + if(!bIsStuck){ + if(IsObject() || + IsPed() && !bPedPhysics){ + m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f; + m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f; + float step = CTimer::GetTimeStep() * 0.003; + if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step && + m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){ + m_nStaticFrames++; + if(m_nStaticFrames > 10){ + m_nStaticFrames = 10; + bIsStatic = true; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecMoveFriction = m_vecMoveSpeed; + m_vecTurnFriction = m_vecTurnSpeed; + return; + } + }else + m_nStaticFrames = 0; + } + } + ApplyGravity(); + ApplyFriction(); + ApplyAirResistance(); +} + +STARTPATCHES + InjectHook(0x4951F0, &CPhysical::Add_, PATCH_JUMP); + InjectHook(0x4954B0, &CPhysical::Remove_, PATCH_JUMP); + InjectHook(0x495540, &CPhysical::RemoveAndAdd, PATCH_JUMP); + InjectHook(0x495F10, &CPhysical::ProcessControl_, PATCH_JUMP); + InjectHook(0x4958F0, &CPhysical::AddToMovingList, PATCH_JUMP); + InjectHook(0x495940, &CPhysical::RemoveFromMovingList, PATCH_JUMP); + + InjectHook(0x497180, &CPhysical::AddCollisionRecord, PATCH_JUMP); + InjectHook(0x4970C0, &CPhysical::AddCollisionRecord_Treadable, PATCH_JUMP); + InjectHook(0x497240, &CPhysical::GetHasCollidedWith, PATCH_JUMP); + +#define F3 float, float, float + InjectHook(0x495B10, &CPhysical::ApplyMoveSpeed, PATCH_JUMP); + InjectHook(0x497280, &CPhysical::ApplyTurnSpeed, PATCH_JUMP); + InjectHook(0x4959A0, (void (CPhysical::*)(F3))&CPhysical::ApplyMoveForce, PATCH_JUMP); + InjectHook(0x495A10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyTurnForce, PATCH_JUMP); + InjectHook(0x495D90, (void (CPhysical::*)(F3))&CPhysical::ApplyFrictionMoveForce, PATCH_JUMP); + InjectHook(0x495E10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyFrictionTurnForce, PATCH_JUMP); + InjectHook(0x499890, &CPhysical::ApplySpringCollision, PATCH_JUMP); + InjectHook(0x495B50, &CPhysical::ApplyGravity, PATCH_JUMP); + InjectHook(0x495B80, (void (CPhysical::*)(void))&CPhysical::ApplyFriction, PATCH_JUMP); + InjectHook(0x495C20, &CPhysical::ApplyAirResistance, PATCH_JUMP); + + InjectHook(0x4973A0, &CPhysical::ApplyCollision, PATCH_JUMP); + InjectHook(0x4992A0, &CPhysical::ApplyCollisionAlt, PATCH_JUMP); + InjectHook(0x499BE0, (bool (CPhysical::*)(float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP); + InjectHook(0x49A180, (bool (CPhysical::*)(CPhysical*, float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP); +ENDPATCHES diff --git a/src/entities/Physical.h b/src/entities/Physical.h new file mode 100644 index 00000000..681ab5c8 --- /dev/null +++ b/src/entities/Physical.h @@ -0,0 +1,137 @@ +#pragma once + +#include "Lists.h" +#include "Entity.h" +#include "Treadable.h" + +enum { + PHYSICAL_MAX_COLLISIONRECORDS = 6 +}; + +class CPhysical : public CEntity +{ +public: + // The not properly indented fields haven't been checked properly yet + + int uAudioEntityId; + float unk1; + CTreadable *m_carTreadable; + CTreadable *m_pedTreadable; + uint32 m_nLastTimeCollided; + CVector m_vecMoveSpeed; // velocity + CVector m_vecTurnSpeed; // angular velocity + CVector m_vecMoveFriction; + CVector m_vecTurnFriction; + CVector m_vecMoveSpeedAvg; + CVector m_vecTurnSpeedAvg; + float m_fMass; + float m_fTurnMass; // moment of inertia + float fForceMultiplier; + float m_fAirResistance; + float m_fElasticity; + float fPercentSubmerged; + CVector m_vecCentreOfMass; + CEntryInfoList m_entryInfoList; + CPtrNode *m_movingListNode; + + char field_EC; + uint8 m_nStaticFrames; + uint8 m_nCollisionRecords; + char field_EF; + CEntity *m_aCollisionRecords[PHYSICAL_MAX_COLLISIONRECORDS]; + + float m_fDistanceTravelled; + + // damaged piece + float m_fCollisionImpulse; + CEntity *m_pCollidingEntity; + CVector m_vecCollisionDirection; + int16 m_nCollisionPieceType; + + uint8 m_phy_flagA1 : 1; + uint8 bAffectedByGravity : 1; + uint8 bInfiniteMass : 1; + uint8 m_phy_flagA8 : 1; + uint8 m_phy_flagA10 : 1; + uint8 m_phy_flagA20 : 1; + uint8 m_phy_flagA40 : 1; + uint8 m_phy_flagA80 : 1; + + uint8 m_phy_flagB1 : 1; + uint8 m_phy_flagB2 : 1; + uint8 m_phy_flagB4 : 1; + uint8 m_phy_flagB8 : 1; + uint8 m_phy_flagB10 : 1; + uint8 m_phy_flagB20 : 1; + uint8 m_phy_flagB40 : 1; + uint8 m_phy_flagB80 : 1; + + char byteLastCollType; + char byteZoneLevel; + int16 pad; + + + // from CEntity + void Add(void); + void Remove(void); + CRect GetBoundRect(void); + void ProcessControl(void); + + void RemoveAndAdd(void); + void AddToMovingList(void); + void RemoveFromMovingList(void); + + // get speed of point p relative to entity center + CVector GetSpeed(const CVector &r); + CVector GetSpeed(void) { return GetSpeed(CVector(0.0f, 0.0f, 0.0f)); } + float GetMass(const CVector &pos, const CVector &dir) { + return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/m_fTurnMass + + 1.0f/m_fMass); + } + float GetMassTime(const CVector &pos, const CVector &dir, float t) { + return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/(m_fTurnMass*t) + + 1.0f/(m_fMass*t)); + } + void UnsetIsInSafePosition(void) { + m_vecMoveSpeed *= -1.0f; + m_vecTurnSpeed *= -1.0f; + ApplyTurnSpeed(); + ApplyMoveSpeed(); + m_vecMoveSpeed *= -1.0f; + m_vecTurnSpeed *= -1.0f; + bIsInSafePosition = false; + } + + void ApplyMoveSpeed(void); + void ApplyTurnSpeed(void); + // Force actually means Impulse here + void ApplyMoveForce(float jx, float jy, float jz); + void ApplyMoveForce(const CVector &j) { ApplyMoveForce(j.x, j.y, j.z); } + // v(x,y,z) is direction of force, p(x,y,z) is point relative to model center where force is applied + void ApplyTurnForce(float jx, float jy, float jz, float rx, float ry, float rz); + // v is direction of force, p is point relative to model center where force is applied + void ApplyTurnForce(const CVector &j, const CVector &p) { ApplyTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); } + void ApplyFrictionMoveForce(float jx, float jy, float jz); + void ApplyFrictionMoveForce(const CVector &j) { ApplyFrictionMoveForce(j.x, j.y, j.z); } + void ApplyFrictionTurnForce(float jx, float jy, float jz, float rx, float ry, float rz); + void ApplyFrictionTurnForce(const CVector &j, const CVector &p) { ApplyFrictionTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); } + void ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3); + void ApplyGravity(void); + void ApplyFriction(void); + void ApplyAirResistance(void); + bool ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB); + bool ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed); + bool ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint); + bool ApplyFriction(float adhesiveLimit, CColPoint &colpoint); + + void AddCollisionRecord(CEntity *ent); + void AddCollisionRecord_Treadable(CEntity *ent); + bool GetHasCollidedWith(CEntity *ent); + + // to make patching virtual functions possible + void Add_(void) { CPhysical::Add(); } + void Remove_(void) { CPhysical::Remove(); } + CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); } + void ProcessControl_(void) { CPhysical::ProcessControl(); } +}; +static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error"); diff --git a/src/entities/Treadable.cpp b/src/entities/Treadable.cpp new file mode 100644 index 00000000..e2eca36a --- /dev/null +++ b/src/entities/Treadable.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "rpworld.h" +#include "Treadable.h" +#include "Pools.h" + +void *CTreadable::operator new(size_t sz) { return CPools::GetTreadablePool()->New(); } +void CTreadable::operator delete(void *p, size_t sz) { CPools::GetTreadablePool()->Delete((CTreadable*)p); } diff --git a/src/entities/Treadable.h b/src/entities/Treadable.h new file mode 100644 index 00000000..df5c9ee0 --- /dev/null +++ b/src/entities/Treadable.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Building.h" + +class CTreadable : public CBuilding +{ +public: + static void *operator new(size_t); + static void operator delete(void*, size_t); + + int16 m_nodeIndicesCars[12]; + int16 m_nodeIndicesPeds[12]; + + virtual bool GetIsATreadable(void) { return true; } +}; +static_assert(sizeof(CTreadable) == 0x94, "CTreadable: error"); diff --git a/src/entities/Vehicle.h b/src/entities/Vehicle.h new file mode 100644 index 00000000..598b4a57 --- /dev/null +++ b/src/entities/Vehicle.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Physical.h" + +class CPed; + +class CVehicle : public CPhysical +{ +public: + // 0x128 + uint8 stuff1[120]; + int16 m_nAlarmState; + CPed *pDriver; + CPed *pPassengers[8]; + uint8 stuff2[24]; + CEntity *m_pCurSurface; + uint8 stuff3[160]; + int32 m_vehType; +}; +static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error"); +static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error"); diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..b17a30a3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,98 @@ +#include "common.h" +#include +#include "patcher.h" +#include "Renderer.h" +#include "debugmenu_public.h" + +void **rwengine = *(void***)0x5A10E1; + +RsGlobalType &RsGlobal = *(RsGlobalType*)0x8F4360; + +GlobalScene &Scene = *(GlobalScene*)0x726768; + +DebugMenuAPI gDebugMenuAPI; + +WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); } +WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); } + +// overload our own new/delete with GTA's functions +void *operator new(size_t sz) { return gtanew(sz); } +void operator delete(void *ptr) noexcept { gtadelete(ptr); } + +// Use our own implementation of rand, stolen from PS2 + +unsigned __int64 myrand_seed = 1; + +int +myrand(void) +{ + myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1; + return ((myrand_seed >> 32) & 0x7FFFFFFF); +} + +void +mysrand(unsigned int seed) +{ + myrand_seed = seed; +} + + +int (*open_script_orig)(const char *path, const char *mode); +int +open_script(const char *path, const char *mode) +{ + if(GetAsyncKeyState('D') & 0x8000) + return open_script_orig("main_d.scm", mode); +// if(GetAsyncKeyState('R') & 0x8000) + return open_script_orig("main_freeroam.scm", mode); + return open_script_orig(path, mode); +} + +int (*RsEventHandler_orig)(int a, int b); +int +delayedPatches10(int a, int b) +{ + if(DebugMenuLoad()){ + DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil); + DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil); + DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil); + DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil); + DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil); + DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil); + DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); + } + + return RsEventHandler_orig(a, b); +} + +void +patch() +{ + StaticPatcher::Apply(); + + Patch(0x46BC61+6, 1.0f); // car distance + InjectHook(0x59E460, printf, PATCH_JUMP); + + InterceptCall(&open_script_orig, open_script, 0x438869); + + InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E); +} + +BOOL WINAPI +DllMain(HINSTANCE hInst, DWORD reason, LPVOID) +{ + if(reason == DLL_PROCESS_ATTACH){ + + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + + if (*(DWORD*)0x5C1E75 == 0xB85548EC) // 1.0 + patch(); + else + return FALSE; + } + + return TRUE; +} diff --git a/src/math/Matrix.h b/src/math/Matrix.h new file mode 100644 index 00000000..cc15da09 --- /dev/null +++ b/src/math/Matrix.h @@ -0,0 +1,245 @@ +#pragma once + +class CMatrix +{ +public: + RwMatrix m_matrix; + RwMatrix *m_attachment; + bool m_hasRwMatrix; // are we the owner? + + CMatrix(void){ + m_attachment = nil; + m_hasRwMatrix = false; + } + CMatrix(CMatrix const &m){ + m_attachment = nil; + m_hasRwMatrix = false; + *this = m; + } + CMatrix(RwMatrix *matrix, bool attach){ + m_attachment = nil; + Attach(matrix, attach); + } + ~CMatrix(void){ + if(m_hasRwMatrix && m_attachment) + RwMatrixDestroy(m_attachment); + } + void Attach(RwMatrix *matrix, bool attach){ + if(m_hasRwMatrix && m_attachment) + RwMatrixDestroy(m_attachment); + m_attachment = matrix; + m_hasRwMatrix = attach; + Update(); + } + void AttachRW(RwMatrix *matrix, bool attach){ + if(m_hasRwMatrix && m_attachment) + RwMatrixDestroy(m_attachment); + m_attachment = matrix; + m_hasRwMatrix = attach; + UpdateRW(); + } + void Detach(void){ + if(m_hasRwMatrix && m_attachment) + RwMatrixDestroy(m_attachment); + m_attachment = nil; + } + void Update(void){ + m_matrix = *m_attachment; + } + void UpdateRW(void){ + if(m_attachment){ + *m_attachment = m_matrix; + RwMatrixUpdate(m_attachment); + } + } + void operator=(CMatrix const &rhs){ + m_matrix = rhs.m_matrix; + if(m_attachment) + UpdateRW(); + } + + CVector *GetPosition(void){ return (CVector*)&m_matrix.pos; } + CVector *GetRight(void) { return (CVector*)&m_matrix.right; } + CVector *GetForward(void) { return (CVector*)&m_matrix.up; } + CVector *GetUp(void) { return (CVector*)&m_matrix.at; } + void SetScale(float s){ + m_matrix.right.x = s; + m_matrix.right.y = 0.0f; + m_matrix.right.z = 0.0f; + + m_matrix.up.x = 0.0f; + m_matrix.up.y = s; + m_matrix.up.z = 0.0f; + + m_matrix.at.x = 0.0f; + m_matrix.at.y = 0.0f; + m_matrix.at.z = s; + + m_matrix.pos.x = 0.0f; + m_matrix.pos.y = 0.0f; + m_matrix.pos.z = 0.0f; + } + void SetRotateXOnly(float angle){ + float c = cos(angle); + float s = sin(angle); + + m_matrix.right.x = 1.0f; + m_matrix.right.y = 0.0f; + m_matrix.right.z = 0.0f; + + m_matrix.up.x = 0.0f; + m_matrix.up.y = c; + m_matrix.up.z = s; + + m_matrix.at.x = 0.0f; + m_matrix.at.y = -s; + m_matrix.at.z = c; + } + void SetRotateX(float angle){ + SetRotateXOnly(angle); + m_matrix.pos.x = 0.0f; + m_matrix.pos.y = 0.0f; + m_matrix.pos.z = 0.0f; + } + void SetRotateYOnly(float angle){ + float c = cos(angle); + float s = sin(angle); + + m_matrix.right.x = c; + m_matrix.right.y = 0.0f; + m_matrix.right.z = -s; + + m_matrix.up.x = 0.0f; + m_matrix.up.y = 1.0f; + m_matrix.up.z = 0.0f; + + m_matrix.at.x = s; + m_matrix.at.y = 0.0f; + m_matrix.at.z = c; + } + void SetRotateY(float angle){ + SetRotateYOnly(angle); + m_matrix.pos.x = 0.0f; + m_matrix.pos.y = 0.0f; + m_matrix.pos.z = 0.0f; + } + void SetRotateZOnly(float angle){ + float c = cos(angle); + float s = sin(angle); + + m_matrix.right.x = c; + m_matrix.right.y = s; + m_matrix.right.z = 0.0f; + + m_matrix.up.x = -s; + m_matrix.up.y = c; + m_matrix.up.z = 0.0f; + + m_matrix.at.x = 0.0f; + m_matrix.at.y = 0.0f; + m_matrix.at.z = 1.0f; + } + void SetRotateZ(float angle){ + SetRotateZOnly(angle); + m_matrix.pos.x = 0.0f; + m_matrix.pos.y = 0.0f; + m_matrix.pos.z = 0.0f; + } + void Reorthogonalise(void){ + CVector &r = *GetRight(); + CVector &f = *GetForward(); + CVector &u = *GetUp(); + u = CrossProduct(r, f); + u.Normalise(); + r = CrossProduct(f, u); + r.Normalise(); + f = CrossProduct(u, r); + } +}; + +inline CMatrix& +Invert(const CMatrix &src, CMatrix &dst) +{ + // GTA handles this as a raw 4x4 orthonormal matrix + // and trashes the RW flags, let's not do that + // actual copy of librw code: + RwMatrix *d = &dst.m_matrix; + const RwMatrix *s = &src.m_matrix; + d->right.x = s->right.x; + d->right.y = s->up.x; + d->right.z = s->at.x; + d->up.x = s->right.y; + d->up.y = s->up.y; + d->up.z = s->at.y; + d->at.x = s->right.z; + d->at.y = s->up.z; + d->at.z = s->at.z; + d->pos.x = -(s->pos.x*s->right.x + + s->pos.y*s->right.y + + s->pos.z*s->right.z); + d->pos.y = -(s->pos.x*s->up.x + + s->pos.y*s->up.y + + s->pos.z*s->up.z); + d->pos.z = -(s->pos.x*s->at.x + + s->pos.y*s->at.y + + s->pos.z*s->at.z); + d->flags = rwMATRIXTYPEORTHONORMAL; + return dst; +} + +inline CMatrix +Invert(const CMatrix &matrix) +{ + CMatrix inv; + return Invert(matrix, inv); +} + +inline CVector +operator*(const CMatrix &mat, const CVector &vec) +{ + return CVector( + mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x, + mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y, + mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z); +} + +inline CMatrix +operator*(const CMatrix &m1, const CMatrix &m2) +{ + CMatrix out; + RwMatrix *dst = &out.m_matrix; + const RwMatrix *src1 = &m1.m_matrix; + const RwMatrix *src2 = &m2.m_matrix; + dst->right.x = src1->right.x*src2->right.x + src1->up.x*src2->right.y + src1->at.x*src2->right.z; + dst->right.y = src1->right.y*src2->right.x + src1->up.y*src2->right.y + src1->at.y*src2->right.z; + dst->right.z = src1->right.z*src2->right.x + src1->up.z*src2->right.y + src1->at.z*src2->right.z; + dst->up.x = src1->right.x*src2->up.x + src1->up.x*src2->up.y + src1->at.x*src2->up.z; + dst->up.y = src1->right.y*src2->up.x + src1->up.y*src2->up.y + src1->at.y*src2->up.z; + dst->up.z = src1->right.z*src2->up.x + src1->up.z*src2->up.y + src1->at.z*src2->up.z; + dst->at.x = src1->right.x*src2->at.x + src1->up.x*src2->at.y + src1->at.x*src2->at.z; + dst->at.y = src1->right.y*src2->at.x + src1->up.y*src2->at.y + src1->at.y*src2->at.z; + dst->at.z = src1->right.z*src2->at.x + src1->up.z*src2->at.y + src1->at.z*src2->at.z; + dst->pos.x = src1->right.x*src2->pos.x + src1->up.x*src2->pos.y + src1->at.x*src2->pos.z + src1->pos.x; + dst->pos.y = src1->right.y*src2->pos.x + src1->up.y*src2->pos.y + src1->at.y*src2->pos.z + src1->pos.y; + dst->pos.z = src1->right.z*src2->pos.x + src1->up.z*src2->pos.y + src1->at.z*src2->pos.z + src1->pos.z; + return out; +} + +inline CVector +MultiplyInverse(const CMatrix &mat, const CVector &vec) +{ + CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z); + return CVector( + mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z, + mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z, + mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z); +} + +inline CVector +Multiply3x3(const CMatrix &mat, const CVector &vec) +{ + return CVector( + mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z, + mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z, + mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z); +} diff --git a/src/math/Rect.h b/src/math/Rect.h new file mode 100644 index 00000000..212645fa --- /dev/null +++ b/src/math/Rect.h @@ -0,0 +1,31 @@ +#pragma once + +#pragma once + +class CRect +{ +public: + float left; // x min + float top; // y max + float right; // x max + float bottom; // y min + + CRect(void){ + left = 1000000.0f; + bottom = 1000000.0f; + right = -1000000.0f; + top = -1000000.0f; + } + CRect(float l, float b, float r, float t){ + left = l; + bottom = b; + right = r; + top = t; + } + void ContainPoint(CVector const &v){ + if(v.x < left) left = v.x; + if(v.x > right) right = v.x; + if(v.y < bottom) bottom = v.y; + if(v.y > top) top = v.y; + } +}; diff --git a/src/math/Vector.h b/src/math/Vector.h new file mode 100644 index 00000000..98c3f0ec --- /dev/null +++ b/src/math/Vector.h @@ -0,0 +1,82 @@ +#pragma once + +class CVector +{ +public: + float x, y, z; + CVector(void) {} + CVector(float x, float y, float z) : x(x), y(y), z(z) {} +// CVector(rw::V3d const &v) : x(v.x), y(v.y), z(v.z) {} + float Magnitude(void) const { return sqrt(x*x + y*y + z*z); } + float MagnitudeSqr(void) const { return x*x + y*y + z*z; } + float Magnitude2D(void) const { return sqrt(x*x + y*y); } + void Normalise(void){ + float sq = MagnitudeSqr(); + if(sq > 0.0f){ + float invsqrt = 1.0f/sqrt(sq); + x *= invsqrt; + y *= invsqrt; + z *= invsqrt; + }else + x = 1.0f; + } +// rw::V3d ToRW(void){ +// return rw::makeV3d(x, y, z); +// } +// void operator=(rw::V3d const &rhs){ +// x = rhs.x; +// y = rhs.y; +// z = rhs.z; +// } + CVector operator-(const CVector &rhs) const { + return CVector(x-rhs.x, y-rhs.y, z-rhs.z); + } + CVector operator+(const CVector &rhs) const { + return CVector(x+rhs.x, y+rhs.y, z+rhs.z); + } + CVector operator*(float t) const { + return CVector(x*t, y*t, z*t); + } + CVector operator/(float t) const { + return CVector(x/t, y/t, z/t); + } + CVector &operator-=(const CVector &rhs) { + this->x -= rhs.x; + this->y -= rhs.y; + this->z -= rhs.z; + return *this; + } + CVector &operator+=(const CVector &rhs) { + this->x += rhs.x; + this->y += rhs.y; + this->z += rhs.z; + return *this; + } + CVector &operator*=(float t) { + this->x *= t; + this->y *= t; + this->z *= t; + return *this; + } + CVector &operator/=(float t) { + this->x /= t; + this->y /= t; + this->z /= t; + return *this; + } +}; + +inline float +DotProduct(const CVector &v1, const CVector &v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + +inline CVector +CrossProduct(const CVector &v1, const CVector &v2) +{ + return CVector( + v1.y*v2.z - v1.z*v2.y, + v1.z*v2.x - v1.x*v2.z, + v1.x*v2.y - v1.y*v2.x); +} diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h new file mode 100644 index 00000000..3c0013d4 --- /dev/null +++ b/src/math/Vector2D.h @@ -0,0 +1,37 @@ +#pragma once + +class CVector2D +{ +public: + float x, y; + CVector2D(void) {} + CVector2D(float x, float y) : x(x), y(y) {} + CVector2D(const CVector &v) : x(v.x), y(v.y) {} + float Magnitude(void) const { return sqrt(x*x + y*y); } + float MagnitudeSqr(void) const { return x*x + y*y; } + + void Normalise(void){ + float sq = MagnitudeSqr(); + if(sq > 0.0f){ + float invsqrt = 1.0f/sqrt(sq); + x *= invsqrt; + y *= invsqrt; + }else + x = 0.0f; + } + CVector2D operator-(const CVector2D &rhs) const { + return CVector2D(x-rhs.x, y-rhs.y); + } + CVector2D operator+(const CVector2D &rhs) const { + return CVector2D(x+rhs.x, y+rhs.y); + } + CVector2D operator*(float t) const { + return CVector2D(x*t, y*t); + } +}; + +inline float +CrossProduct2D(const CVector2D &v1, const CVector2D &v2) +{ + return v1.x*v2.y - v1.y*v2.x; +} diff --git a/src/modelinfo/BaseModelInfo.cpp b/src/modelinfo/BaseModelInfo.cpp new file mode 100644 index 00000000..f44c86b6 --- /dev/null +++ b/src/modelinfo/BaseModelInfo.cpp @@ -0,0 +1,117 @@ +#include "common.h" +#include "patcher.h" +#include "templates.h" +#include "TxdStore.h" +#include "2dEffect.h" +#include "BaseModelInfo.h" + + +CBaseModelInfo::CBaseModelInfo(ModeInfoType type) +{ + m_colModel = nil; + m_twodEffects = 0; + m_objectId = -1; + m_refCount = 0; + m_txdSlot = -1; + m_type = type; + m_num2dEffects = 0; + m_freeCol = false; +} + +void +CBaseModelInfo::Shutdown(void) +{ + DeleteCollisionModel(); + DeleteRwObject(); + m_twodEffects = 0; + m_num2dEffects = 0; + m_txdSlot = -1; +} + +void +CBaseModelInfo::DeleteCollisionModel(void) +{ + if(m_colModel && m_freeCol){ + if(m_colModel) + delete m_colModel; + m_colModel = nil; + } +} + +void +CBaseModelInfo::AddRef(void) +{ + m_refCount++; + AddTexDictionaryRef(); +} + +void +CBaseModelInfo::RemoveRef(void) +{ + m_refCount--; + RemoveTexDictionaryRef(); +} + +void +CBaseModelInfo::SetTexDictionary(const char *name) +{ + int slot = CTxdStore::FindTxdSlot(name); + if(slot < 0) + slot = CTxdStore::AddTxdSlot(name); + m_txdSlot = slot; +} + +void +CBaseModelInfo::AddTexDictionaryRef(void) +{ + CTxdStore::AddRef(m_txdSlot); +} + +void +CBaseModelInfo::RemoveTexDictionaryRef(void) +{ + CTxdStore::RemoveRef(m_txdSlot); +} + +void +CBaseModelInfo::Init2dEffects(void) +{ + m_twodEffects = nil; + m_num2dEffects = 0; +} + +void +CBaseModelInfo::Add2dEffect(C2dEffect *fx) +{ + if(m_twodEffects) + m_num2dEffects++; + else{ + m_twodEffects = fx; + m_num2dEffects = 1; + } +} + +C2dEffect* +CBaseModelInfo::Get2dEffect(int n) +{ + if(m_twodEffects) + return &m_twodEffects[n]; + else + return nil; +} + + +STARTPATCHES + // can't easily replace ctor at 4F6A50 + InjectHook(0x4F6A90, &CBaseModelInfo::Shutdown_, PATCH_JUMP); + InjectHook(0x4F6AC0, &CBaseModelInfo::DeleteCollisionModel, PATCH_JUMP); + InjectHook(0x4F6B70, &CBaseModelInfo::ClearTexDictionary, PATCH_JUMP); + InjectHook(0x4F6BA0, &CBaseModelInfo::AddRef, PATCH_JUMP); + InjectHook(0x4F6BB0, &CBaseModelInfo::RemoveRef, PATCH_JUMP); + InjectHook(0x4F6B40, &CBaseModelInfo::SetTexDictionary, PATCH_JUMP); + InjectHook(0x4F6B80, &CBaseModelInfo::AddTexDictionaryRef, PATCH_JUMP); + InjectHook(0x4F6B90, &CBaseModelInfo::RemoveTexDictionaryRef, PATCH_JUMP); + InjectHook(0x4F6B20, &CBaseModelInfo::Add2dEffect, PATCH_JUMP); + InjectHook(0x4F6AF0, &CBaseModelInfo::Init2dEffects, PATCH_JUMP); + InjectHook(0x4F6B00, &CBaseModelInfo::Get2dEffect, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h new file mode 100644 index 00000000..fadea18a --- /dev/null +++ b/src/modelinfo/BaseModelInfo.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Collision.h" + +enum ModeInfoType : uint8 +{ + MITYPE_NA = 0, + MITYPE_SIMPLE = 1, + MITYPE_MLO = 2, + MITYPE_TIME = 3, + MITYPE_CLUMP = 4, + MITYPE_VEHICLE = 5, + MITYPE_PED = 6, + MITYPE_XTRACOMPS = 7, +}; +static_assert(sizeof(ModeInfoType) == 1, "ModeInfoType: error"); + +class C2dEffect; + +class CBaseModelInfo +{ +protected: + // TODO?: make more things protected + char m_name[24]; + CColModel *m_colModel; + C2dEffect *m_twodEffects; + int16 m_objectId; +public: + uint16 m_refCount; + int16 m_txdSlot; + ModeInfoType m_type; + uint8 m_num2dEffects; + bool m_freeCol; + + CBaseModelInfo(ModeInfoType type); + virtual ~CBaseModelInfo() {} + virtual void Shutdown(void); + virtual void DeleteRwObject(void) = 0; + virtual RwObject *CreateInstance(RwMatrix *) = 0; + virtual RwObject *CreateInstance(void) = 0; + virtual RwObject *GetRwObject(void) = 0; + + bool IsSimple(void) { return m_type == MITYPE_SIMPLE || m_type == MITYPE_TIME; } + char *GetName(void) { return m_name; } + void SetName(const char *name) { strncpy(m_name, name, 24); } + void SetColModel(CColModel *col, bool free = false){ + m_colModel = col; m_freeCol = free; } + CColModel *GetColModel(void) { return m_colModel; } + void DeleteCollisionModel(void); + void ClearTexDictionary(void) { m_txdSlot = -1; } + short GetObjectID(void) { return m_objectId; } + void SetObjectID(short id) { m_objectId = id; } + short GetTxdSlot(void) { return m_txdSlot; } + void AddRef(void); + void RemoveRef(void); + void SetTexDictionary(const char *name); + void AddTexDictionaryRef(void); + void RemoveTexDictionaryRef(void); + void Init2dEffects(void); + void Add2dEffect(C2dEffect *fx); + C2dEffect *Get2dEffect(int n); + + void Shutdown_(void) { this->CBaseModelInfo::Shutdown(); } +}; + +static_assert(sizeof(CBaseModelInfo) == 0x30, "CBaseModelInfo: error"); diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp new file mode 100644 index 00000000..4a19f1df --- /dev/null +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -0,0 +1,156 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +void +CClumpModelInfo::DeleteRwObject(void) +{ + if(m_clump){ + RpClumpDestroy(m_clump); + m_clump = nil; + RemoveTexDictionaryRef(); + } +} + +RwObject* +CClumpModelInfo::CreateInstance(void) +{ + if(m_clump) + return (RwObject*)RpClumpClone(m_clump); + return nil; +} + +RwObject* +CClumpModelInfo::CreateInstance(RwMatrix *m) +{ + if(m_clump){ + RpClump *clump = (RpClump*)CreateInstance(); + *RwFrameGetMatrix(RpClumpGetFrame(clump)) = *m; + return (RwObject*)clump; + } + return nil; +} + +RpAtomic* +CClumpModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicRenderCallback(atomic, (RpAtomicCallBackRender)data); + return atomic; +} + +void +CClumpModelInfo::SetClump(RpClump *clump) +{ + m_clump = clump; + CVisibilityPlugins::SetClumpModelInfo(m_clump, this); + AddTexDictionaryRef(); + RpClumpForAllAtomics(clump, SetAtomicRendererCB, nil); + if(strncmp(GetName(), "playerh", 8) == 0) + RpClumpForAllAtomics(clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB); +} + +void +CClumpModelInfo::SetFrameIds(RwObjectNameIdAssocation *assocs) +{ + int32 i; + RwObjectNameAssociation objname; + + for(i = 0; assocs[i].name; i++) + if((assocs[i].flags & CLUMP_FLAG_NO_HIERID) == 0){ + objname.frame = nil; + objname.name = assocs[i].name; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindFrameFromNameWithoutIdCB, &objname); + if(objname.frame) + CVisibilityPlugins::SetFrameHierarchyId(objname.frame, assocs[i].hierId); + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromIdCB(RwFrame *frame, void *data) +{ + RwObjectIdAssociation *assoc = (RwObjectIdAssociation*)data; + + if(CVisibilityPlugins::GetFrameHierarchyId(frame) != assoc->id){ + RwFrameForAllChildren(frame, FindFrameFromIdCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromNameCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(_strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + RwFrameForAllChildren(frame, FindFrameFromNameCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(CVisibilityPlugins::GetFrameHierarchyId(frame) || + _strcmpi(GetFrameNodeName(frame), assoc->name) != 0){ + RwFrameForAllChildren(frame, FindFrameFromNameWithoutIdCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +RwFrame* +CClumpModelInfo::FillFrameArrayCB(RwFrame *frame, void *data) +{ + int32 id; + RwFrame **frames = (RwFrame**)data; + id = CVisibilityPlugins::GetFrameHierarchyId(frame); + if(id > 0) + frames[id] = frame; + RwFrameForAllChildren(frame, FillFrameArrayCB, data); + return frame; +} + +void +CClumpModelInfo::FillFrameArray(RpClump *clump, RwFrame **frames) +{ + RwFrameForAllChildren(RpClumpGetFrame(clump), FillFrameArrayCB, frames); +} + +RwFrame* +CClumpModelInfo::GetFrameFromId(RpClump *clump, int32 id) +{ + RwObjectIdAssociation assoc; + assoc.id = id; + assoc.frame = nil; + RwFrameForAllChildren(RpClumpGetFrame(clump), FindFrameFromIdCB, &assoc); + return assoc.frame; +} + + +STARTPATCHES + InjectHook(0x4F8800, &CClumpModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x4F8920, &CClumpModelInfo::CreateInstance_1, PATCH_JUMP); + InjectHook(0x4F88A0, &CClumpModelInfo::CreateInstance_2, PATCH_JUMP); + InjectHook(0x50C1C0, &CClumpModelInfo::GetRwObject_, PATCH_JUMP); + InjectHook(0x4F8830, &CClumpModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x4F8940, &CClumpModelInfo::SetAtomicRendererCB, PATCH_JUMP); + InjectHook(0x4F8960, &CClumpModelInfo::FindFrameFromNameCB, PATCH_JUMP); + InjectHook(0x4F8A10, &CClumpModelInfo::FindFrameFromNameWithoutIdCB, PATCH_JUMP); + InjectHook(0x4F8AD0, &CClumpModelInfo::FindFrameFromIdCB, PATCH_JUMP); + InjectHook(0x4F8BB0, &CClumpModelInfo::SetFrameIds, PATCH_JUMP); + InjectHook(0x4F8B20, &CClumpModelInfo::FillFrameArrayCB, PATCH_JUMP); + InjectHook(0x4F8B90, &CClumpModelInfo::FillFrameArray, PATCH_JUMP); + InjectHook(0x4F8B50, &CClumpModelInfo::GetFrameFromId, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ClumpModelInfo.h b/src/modelinfo/ClumpModelInfo.h new file mode 100644 index 00000000..909d241b --- /dev/null +++ b/src/modelinfo/ClumpModelInfo.h @@ -0,0 +1,60 @@ +#pragma once + +#include "BaseModelInfo.h" + +struct RwObjectNameIdAssocation +{ + char *name; + int32 hierId; + uint32 flags; +}; + +struct RwObjectNameAssociation +{ + char *name; + RwFrame *frame; +}; + +struct RwObjectIdAssociation +{ + int32 id; + RwFrame *frame; +}; + +enum { + CLUMP_FLAG_NO_HIERID = 0x1, +}; + + +class CClumpModelInfo : public CBaseModelInfo +{ +public: + RpClump *m_clump; + + CClumpModelInfo(void) : CBaseModelInfo(MITYPE_CLUMP) {} + CClumpModelInfo(ModeInfoType id) : CBaseModelInfo(id) {} + ~CClumpModelInfo() {} + void DeleteRwObject(void); + RwObject *CreateInstance(void); + RwObject *CreateInstance(RwMatrix *); + RwObject *GetRwObject(void) { return (RwObject*)m_clump; } + + virtual void SetClump(RpClump *); + + static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data); + void SetFrameIds(RwObjectNameIdAssocation *assocs); + static RwFrame *FindFrameFromNameCB(RwFrame *frame, void *data); + static RwFrame *FindFrameFromNameWithoutIdCB(RwFrame *frame, void *data); + static RwFrame *FindFrameFromIdCB(RwFrame *frame, void *data); + static void FillFrameArray(RpClump *clump, RwFrame **frames); + static RwFrame *FillFrameArrayCB(RwFrame *frame, void *data); + static RwFrame *GetFrameFromId(RpClump *clump, int32 id); + + + void DeleteRwObject_(void) { this->CClumpModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return this->CClumpModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return this->CClumpModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return this->CClumpModelInfo::GetRwObject(); } + void SetClump_(RpClump *clump) { this->CClumpModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CClumpModelInfo) == 0x34, "CClumpModelInfo: error"); diff --git a/src/modelinfo/ModelIndices.cpp b/src/modelinfo/ModelIndices.cpp new file mode 100644 index 00000000..9a8aaead --- /dev/null +++ b/src/modelinfo/ModelIndices.cpp @@ -0,0 +1,32 @@ +#include "common.h" +#include "patcher.h" +#include "ModelIndices.h" + +#define X(name, var, addr) int16 &var = *(int16*)addr; + MODELINDICES +#undef X + +void +InitModelIndices(void) +{ +#define X(name, var, addr) var = -1; + MODELINDICES +#undef X +} + +void +MatchModelString(const char *modelname, int16 id) +{ +#define X(name, var, addr) \ + if(strcmp(name, modelname) == 0){ \ + var = id; \ + return; \ + } + MODELINDICES +#undef X +} + +STARTPATCHES + InjectHook(0x48EB60, InitModelIndices, PATCH_JUMP); + InjectHook(0x48F030, MatchModelString, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h new file mode 100644 index 00000000..5de10558 --- /dev/null +++ b/src/modelinfo/ModelIndices.h @@ -0,0 +1,224 @@ +#define MODELINDICES \ + X("fire_hydrant", MI_FIRE_HYDRANT, 0x5F5A00) \ + X("bagelstnd02", MI_BAGELSTAND2, 0x5F59FC) \ + X("fish01", MI_FISHSTALL01, 0x5F59EC) \ + X("fishstall02", MI_FISHSTALL02, 0x5F59F0) \ + X("fishstall03", MI_FISHSTALL03, 0x5F59F4) \ + X("fishstall04", MI_FISHSTALL04, 0x5F59F8) \ + X("taxisign", MI_TAXISIGN, 0x5F59E8) \ + X("phonesign", MI_PHONESIGN, 0x5F59E4) \ + X("noparkingsign1", MI_NOPARKINGSIGN1, 0x5F59E0) \ + X("bussign1", MI_BUSSIGN1, 0x5F59DC) \ + X("roadworkbarrier1", MI_ROADWORKBARRIER1, 0x5F59D8) \ + X("dump1", MI_DUMP1, 0x5F59D4) \ + X("trafficcone", MI_TRAFFICCONE, 0x5F59D0) \ + X("newsstand1", MI_NEWSSTAND, 0x5F59CC) \ + X("postbox1", MI_POSTBOX1, 0x5F59C8) \ + X("bin1", MI_BIN, 0x5F59C4) \ + X("wastebin", MI_WASTEBIN, 0x5F59C0) \ + X("phonebooth1", MI_PHONEBOOTH1, 0x5F59BC) \ + X("parkingmeter", MI_PARKINGMETER, 0x5F59B8) \ + X("trafficlight1", MI_TRAFFICLIGHTS, 0x5F5958) \ + X("lamppost1", MI_SINGLESTREETLIGHTS1, 0x5F595C) \ + X("lamppost2", MI_SINGLESTREETLIGHTS2, 0x5F5960) \ + X("lamppost3", MI_SINGLESTREETLIGHTS3, 0x5F5964) \ + X("doublestreetlght1", MI_DOUBLESTREETLIGHTS, 0x5F5968) \ + X("rd_Road2A10", MI_ROADSFORROADBLOCKSSTART, 0x5F596C) \ + X("rd_Road1A30", MI_ROADSFORROADBLOCKSEND, 0x5F5970) \ + X("veg_tree1", MI_TREE1, 0x5F5974) \ + X("veg_tree3", MI_TREE2, 0x5F5978) \ + X("veg_treea1", MI_TREE3, 0x5F597C) \ + X("veg_treenew01", MI_TREE4, 0x5F5980) \ + X("veg_treenew05", MI_TREE5, 0x5F5984) \ + X("veg_treeb1", MI_TREE6, 0x5F5988) \ + X("veg_treenew10", MI_TREE7, 0x5F598C) \ + X("veg_treea3", MI_TREE8, 0x5F5990) \ + X("veg_treenew09", MI_TREE9, 0x5F5994) \ + X("veg_treenew08", MI_TREE10, 0x5F5998) \ + X("veg_treenew03", MI_TREE11, 0x5F599C) \ + X("veg_treenew16", MI_TREE12, 0x5F59A0) \ + X("veg_treenew17", MI_TREE13, 0x5F59A4) \ + X("veg_treenew06", MI_TREE14, 0x5F59A8) \ + X("doc_crane_cab", MODELID_CRANE_1, 0x5F59AC) \ + X("cranetopb", MODELID_CRANE_2, 0x5F59B0) \ + X("cranetopa", MODELID_CRANE_3, 0x5F59B4) \ + X("package1", MI_COLLECTABLE1, 0x5F5A04) \ + X("Money", MI_MONEY, 0x5F5A08) \ + X("barrel1", MI_CARMINE, 0x5F5A0C) \ + X("oddjgaragdoor", MI_GARAGEDOOR1, 0x5F5A10) \ + X("bombdoor", MI_GARAGEDOOR2, 0x5F5A14) \ + X("door_bombshop", MI_GARAGEDOOR3, 0x5F5A18) \ + X("vheistlocdoor", MI_GARAGEDOOR4, 0x5F5A1C) \ + X("door2_garage", MI_GARAGEDOOR5, 0x5F5A20) \ + X("ind_slidedoor", MI_GARAGEDOOR6, 0x5F5A24) \ + X("bankjobdoor", MI_GARAGEDOOR7, 0x5F5A28) \ + X("door_jmsgrage", MI_GARAGEDOOR9, 0x5F5A2C) \ + X("jamesgrge_kb", MI_GARAGEDOOR10, 0x5F5A30) \ + X("door_sfehousegrge", MI_GARAGEDOOR11, 0x5F5A34) \ + X("shedgaragedoor", MI_GARAGEDOOR12, 0x5F5A38) \ + X("door4_garage", MI_GARAGEDOOR13, 0x5F5A3C) \ + X("door_col_compnd_01", MI_GARAGEDOOR14, 0x5F5A40) \ + X("door_col_compnd_02", MI_GARAGEDOOR15, 0x5F5A44) \ + X("door_col_compnd_03", MI_GARAGEDOOR16, 0x5F5A48) \ + X("door_col_compnd_04", MI_GARAGEDOOR17, 0x5F5A4C) \ + X("door_col_compnd_05", MI_GARAGEDOOR18, 0x5F5A50) \ + X("impex_door", MI_GARAGEDOOR19, 0x5F5A54) \ + X("SalvGarage", MI_GARAGEDOOR20, 0x5F5A58) \ + X("door3_garage", MI_GARAGEDOOR21, 0x5F5A5C) \ + X("leveldoor2", MI_GARAGEDOOR22, 0x5F5A60) \ + X("double_garage_dr", MI_GARAGEDOOR23, 0x5F5A64) \ + X("amcogaragedoor", MI_GARAGEDOOR24, 0x5F5A68) \ + X("towergaragedoor1", MI_GARAGEDOOR25, 0x5F5A6C) \ + X("towergaragedoor2", MI_GARAGEDOOR26, 0x5F5A70) \ + X("towergaragedoor3", MI_GARAGEDOOR27, 0x5F5A74) \ + X("plysve_gragedoor", MI_GARAGEDOOR28, 0x5F5A78) \ + X("impexpsubgrgdoor", MI_GARAGEDOOR29, 0x5F5A7C) \ + X("Sub_sprayshopdoor", MI_GARAGEDOOR30, 0x5F5A80) \ + X("ind_plyrwoor", MI_GARAGEDOOR31, 0x5F5A84) \ + X("8ballsuburbandoor", MI_GARAGEDOOR32, 0x5F5A88) \ + X("barrel2", MI_NAUTICALMINE, 0x5F5A8C) \ + X("crushercrush", MI_CRUSHERBODY, 0x5F5A90) \ + X("crushertop", MI_CRUSHERLID, 0x5F5A94) \ + X("donkeymag", MI_DONKEYMAG, 0x5F5A98) \ + X("bullion", MI_BULLION, 0x5F5A9C) \ + X("floatpackge1", MI_FLOATPACKAGE1, 0x5F5AA0) \ + X("briefcase", MI_BRIEFCASE, 0x5F5AA4) \ + X("chinabanner1", MI_CHINABANNER1, 0x5F5AA8) \ + X("chinabanner2", MI_CHINABANNER2, 0x5F5AAC) \ + X("chinabanner3", MI_CHINABANNER3, 0x5F5AB0) \ + X("chinabanner4", MI_CHINABANNER4, 0x5F5AB4) \ + X("iten_chinatown5", MI_CHINABANNER5, 0x5F5AB8) \ + X("iten_chinatown7", MI_CHINABANNER6, 0x5F5ABC) \ + X("iten_chinatown3", MI_CHINABANNER7, 0x5F5AC0) \ + X("iten_chinatown2", MI_CHINABANNER8, 0x5F5AC4) \ + X("iten_chinatown4", MI_CHINABANNER9, 0x5F5AC8) \ + X("iten_washline01", MI_CHINABANNER10, 0x5F5ACC) \ + X("iten_washline02", MI_CHINABANNER11, 0x5F5AD0) \ + X("iten_washline03", MI_CHINABANNER12, 0x5F5AD4) \ + X("chinalanterns", MI_CHINALANTERN, 0x5F5AD8) \ + X("glassfx1", MI_GLASS1, 0x5F5ADC) \ + X("glassfx2", MI_GLASS2, 0x5F5AE0) \ + X("glassfx3", MI_GLASS3, 0x5F5AE4) \ + X("glassfx4", MI_GLASS4, 0x5F5AE8) \ + X("glassfx55", MI_GLASS5, 0x5F5AEC) \ + X("glassfxsub1", MI_GLASS6, 0x5F5AF0) \ + X("glassfxsub2", MI_GLASS7, 0x5F5AF4) \ + X("glassfx_composh", MI_GLASS8, 0x5F5AF8) \ + X("bridge_liftsec", MI_BRIDGELIFT, 0x5F5AFC) \ + X("bridge_liftweight", MI_BRIDGEWEIGHT, 0x5F5B00) \ + X("subbridge_lift", MI_BRIDGEROADSEGMENT, 0x5F5B04) \ + X("barrel4", MI_EXPLODINGBARREL, 0x5F5B08) \ + X("flagsitaly", MI_ITALYBANNER1, 0x5F5B0C) \ + X("adrenaline", MI_PICKUP_ADRENALINE, 0x5F5B10) \ + X("bodyarmour", MI_PICKUP_BODYARMOUR, 0x5F5B14) \ + X("info", MI_PICKUP_INFO, 0x5F5B18) \ + X("health", MI_PICKUP_HEALTH, 0x5F5B1C) \ + X("bonus", MI_PICKUP_BONUS, 0x5F5B20) \ + X("bribe", MI_PICKUP_BRIBE, 0x5F5B24) \ + X("killfrenzy", MI_PICKUP_KILLFRENZY, 0x5F5B28) \ + X("camerapickup", MI_PICKUP_CAMERA, 0x5F5B2C) \ + X("bollardlight", MI_BOLLARDLIGHT, 0x5F5B30) \ + X("magnet", MI_MAGNET, 0x5F5B34) \ + X("streetlamp1", MI_STREETLAMP1, 0x5F5B38) \ + X("streetlamp2", MI_STREETLAMP2, 0x5F5B3C) \ + X("railtrax_lo4b", MI_RAILTRACKS, 0x5F5B40) \ + X("bar_barrier10", MI_FENCE, 0x5F5B44) \ + X("bar_barrier12", MI_FENCE2, 0x5F5B48) \ + X("petrolpump", MI_PETROLPUMP, 0x5F5B4C) \ + X("bodycast", MI_BODYCAST, 0x5F5B50) \ + X("backdoor", MI_BACKDOOR, 0x5F5B54) \ + X("coffee", MI_COFFEE, 0x5F5B58) \ + X("bouy", MI_BUOY, 0x5F5B5C) \ + X("parktable1", MI_PARKTABLE, 0x5F5B60) \ + X("sbwy_tunl_start", MI_SUBWAY1, 0x5F5B64) \ + X("sbwy_tunl_bit", MI_SUBWAY2, 0x5F5B68) \ + X("sbwy_tunl_bend", MI_SUBWAY3, 0x5F5B6C) \ + X("sbwy_tunl_cstm6", MI_SUBWAY4, 0x5F5B70) \ + X("sbwy_tunl_cstm7", MI_SUBWAY5, 0x5F5B74) \ + X("sbwy_tunl_cstm8", MI_SUBWAY6, 0x5F5B78) \ + X("sbwy_tunl_cstm10", MI_SUBWAY7, 0x5F5B7C) \ + X("sbwy_tunl_cstm9", MI_SUBWAY8, 0x5F5B80) \ + X("sbwy_tunl_cstm11", MI_SUBWAY9, 0x5F5B84) \ + X("sbwy_tunl_cstm1", MI_SUBWAY10, 0x5F5B88) \ + X("sbwy_tunl_cstm2", MI_SUBWAY11, 0x5F5B8C) \ + X("sbwy_tunl_cstm4", MI_SUBWAY12, 0x5F5B90) \ + X("sbwy_tunl_cstm3", MI_SUBWAY13, 0x5F5B94) \ + X("sbwy_tunl_cstm5", MI_SUBWAY14, 0x5F5B98) \ + X("subplatform_n2", MI_SUBWAY15, 0x5F5B9C) \ + X("suby_tunl_start", MI_SUBWAY16, 0x5F5BA0) \ + X("sbwy_tunl_start2", MI_SUBWAY17, 0x5F5BA4) \ + X("indy_tunl_start", MI_SUBWAY18, 0x5F5BA8) \ + X("indsubway03", MI_SUBPLATFORM_IND, 0x5F5BAC) \ + X("comerside_subway", MI_SUBPLATFORM_COMS, 0x5F5BB0) \ + X("subplatform", MI_SUBPLATFORM_COMS2, 0x5F5BB4) \ + X("subplatform_n", MI_SUBPLATFORM_COMN, 0x5F5BB8) \ + X("Otherside_subway", MI_SUBPLATFORM_SUB, 0x5F5BBC) \ + X("subplatform_sub", MI_SUBPLATFORM_SUB2, 0x5F5BC0) \ + X("files", MI_FILES, 0x5F5BC4) + +#define X(name, var, addr) extern int16 &var; + MODELINDICES +#undef X + +// and some hardcoded ones +// expand as needed +enum +{ + MI_COP = 1, + MI_SWAT, + MI_FBI, + MI_ARMY, + MI_MEDIC, + MI_FIREMAN, + MI_MALE01, + MI_TAXI_D, + MI_PIMP, + MI_GANG01, + MI_GANG02, + MI_GANG03, + MI_GANG04, + MI_GANG05, + MI_GANG06, + MI_GANG07, + MI_GANG08, + MI_GANG09, + MI_GANG10, + MI_GANG11, + MI_GANG12, + MI_GANG13, + MI_GANG14, + MI_CRIMINAL01, + MI_CRIMINAL02, + MI_SPECIAL01, + MI_SPECIAL02, + MI_SPECIAL03, + MI_SPECIAL04, + MI_MALE02, + MI_MALE03, + MI_FATMALE01, + MI_FATMALE02, + MI_FEMALE01, + MI_FEMALE02, + MI_FEMALE03, + MI_FATFEMALE01, + MI_FATFEMALE02, + + MI_RHINO = 122, + MI_COACH = 127, +}; + +void InitModelIndices(void); +void MatchModelString(const char *name, int16 id); + +inline bool +IsGlass(int16 id) +{ + return id == MI_GLASS1 || + id == MI_GLASS2 || + id == MI_GLASS3 || + id == MI_GLASS4 || + id == MI_GLASS5 || + id == MI_GLASS6 || + id == MI_GLASS7 || + id == MI_GLASS8; +} diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp new file mode 100644 index 00000000..89fcdee5 --- /dev/null +++ b/src/modelinfo/ModelInfo.cpp @@ -0,0 +1,124 @@ +#include "common.h" +#include "patcher.h" +#include "ModelInfo.h" + +CBaseModelInfo **CModelInfo::ms_modelInfoPtrs = (CBaseModelInfo**)0x83D408; + +//CStore &CModelInfo::ms_simpleModelStore = *(CStore*)0x885BB4; +//CStore &CModelInfo::ms_timeModelStore = *(CStore*)0x94076C; +//CStore &CModelInfo::ms_2dEffectStore = *(CStore*)0x9434F8; +CStore CModelInfo::ms_simpleModelStore; +CStore CModelInfo::ms_timeModelStore; +CStore CModelInfo::ms_clumpModelStore; +CStore CModelInfo::ms_pedModelStore; +CStore CModelInfo::ms_vehicleModelStore; +CStore CModelInfo::ms_2dEffectStore; + +void +CModelInfo::Initialise(void) +{ + int i; + for(i = 0; i < MODELINFOSIZE; i++) + ms_modelInfoPtrs[i] = nil; + ms_2dEffectStore.clear(); + ms_simpleModelStore.clear(); + ms_timeModelStore.clear(); + ms_clumpModelStore.clear(); + ms_pedModelStore.clear(); + ms_vehicleModelStore.clear(); +} + +void +CModelInfo::Shutdown(void) +{ + int i; + for(i = 0; i < ms_simpleModelStore.allocPtr; i++) + ms_simpleModelStore.store[i].Shutdown(); + for(i = 0; i < ms_timeModelStore.allocPtr; i++) + ms_timeModelStore.store[i].Shutdown(); + for(i = 0; i < ms_clumpModelStore.allocPtr; i++) + ms_clumpModelStore.store[i].Shutdown(); + for(i = 0; i < ms_pedModelStore.allocPtr; i++) + ms_pedModelStore.store[i].Shutdown(); + for(i = 0; i < ms_vehicleModelStore.allocPtr; i++) + ms_vehicleModelStore.store[i].Shutdown(); +} + +CSimpleModelInfo* +CModelInfo::AddSimpleModel(int id) +{ + CSimpleModelInfo *modelinfo; + modelinfo = CModelInfo::ms_simpleModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->Init(); + return modelinfo; +} + +CTimeModelInfo* +CModelInfo::AddTimeModel(int id) +{ + CTimeModelInfo *modelinfo; + modelinfo = CModelInfo::ms_timeModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->Init(); + return modelinfo; +} + +CClumpModelInfo* +CModelInfo::AddClumpModel(int id) +{ + CClumpModelInfo *modelinfo; + modelinfo = CModelInfo::ms_clumpModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + return modelinfo; +} + +CPedModelInfo* +CModelInfo::AddPedModel(int id) +{ + CPedModelInfo *modelinfo; + modelinfo = CModelInfo::ms_pedModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + return modelinfo; +} + +CVehicleModelInfo* +CModelInfo::AddVehicleModel(int id) +{ + CVehicleModelInfo *modelinfo; + modelinfo = CModelInfo::ms_vehicleModelStore.alloc(); + CModelInfo::ms_modelInfoPtrs[id] = modelinfo; + modelinfo->m_clump = nil; + modelinfo->m_vehicleType = -1; + modelinfo->m_wheelId = -1; + modelinfo->m_materials1[0] = nil; + modelinfo->m_materials2[0] = nil; + modelinfo->m_bikeSteerAngle = 999.99f; + return modelinfo; +} + +CBaseModelInfo* +CModelInfo::GetModelInfo(const char *name, int *id) +{ + CBaseModelInfo *modelinfo; + for(int i = 0; i < MODELINFOSIZE; i++){ + modelinfo = CModelInfo::ms_modelInfoPtrs[i]; + if(modelinfo && _strcmpi(modelinfo->GetName(), name) == 0){ + if(id) + *id = i; + return modelinfo; + } + } + return nil; +} + +STARTPATCHES +// InjectHook(0x50B920, CModelInfo::AddSimpleModel, PATCH_JUMP); +// InjectHook(0x50B9C0, CModelInfo::AddTimeModel, PATCH_JUMP); +// InjectHook(0x50BA10, CModelInfo::AddClumpModel, PATCH_JUMP); +// InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP); +// InjectHook(0x50BA60, CModelInfo::AddPedModel, PATCH_JUMP); + InjectHook(0x50B860, (CBaseModelInfo *(*)(const char*, int*))CModelInfo::GetModelInfo, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h new file mode 100644 index 00000000..a0d30dea --- /dev/null +++ b/src/modelinfo/ModelInfo.h @@ -0,0 +1,35 @@ +#pragma once + +#include "2dEffect.h" +#include "BaseModelInfo.h" +#include "SimpleModelInfo.h" +#include "TimeModelInfo.h" +#include "ClumpModelInfo.h" +#include "PedModelInfo.h" +#include "VehicleModelInfo.h" + +class CModelInfo +{ + static CBaseModelInfo **ms_modelInfoPtrs; //[MODELINFOSIZE]; + static CStore ms_simpleModelStore; + static CStore ms_timeModelStore; + static CStore ms_clumpModelStore; + static CStore ms_pedModelStore; + static CStore ms_vehicleModelStore; + static CStore ms_2dEffectStore; + +public: + static void Initialise(void); + static void Shutdown(void); + + static CSimpleModelInfo *AddSimpleModel(int id); + static CTimeModelInfo *AddTimeModel(int id); + static CClumpModelInfo *AddClumpModel(int id); + static CPedModelInfo *AddPedModel(int id); + static CVehicleModelInfo *AddVehicleModel(int id); + + static CBaseModelInfo *GetModelInfo(const char *name, int *id); + static CBaseModelInfo *GetModelInfo(int id){ + return ms_modelInfoPtrs[id]; + } +}; diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp new file mode 100644 index 00000000..e095902e --- /dev/null +++ b/src/modelinfo/PedModelInfo.cpp @@ -0,0 +1,197 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +void +CPedModelInfo::DeleteRwObject(void) +{ + CClumpModelInfo::DeleteRwObject(); + if(m_hitColModel) + delete m_hitColModel; + m_hitColModel = nil; +} + +RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = { + { "Smid", PED_TORSO, 0, }, // that is strange... + { "Shead", PED_HEAD, 0, }, + { "Supperarml", PED_UPPERARML, 0, }, + { "Supperarmr", PED_UPPERARMR, 0, }, + { "SLhand", PED_HANDL, 0, }, + { "SRhand", PED_HANDR, 0, }, + { "Supperlegl", PED_UPPERLEGL, 0, }, + { "Supperlegr", PED_UPPERLEGR, 0, }, + { "Sfootl", PED_FOOTL, 0, }, + { "Sfootr", PED_FOOTR, 0, }, + { "Slowerlegr", PED_LOWERLEGR, 0, }, + { NULL, 0, 0, }, +}; + +void +CPedModelInfo::SetClump(RpClump *clump) +{ + CClumpModelInfo::SetClump(clump); + SetFrameIds(m_pPedIds); + if(m_hitColModel == nil) + CreateHitColModel(); + if(strncmp(GetName(), "player", 7) == 0) + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB); +} + +RpAtomic* +CountAtomicsCB(RpAtomic *atomic, void *data) +{ + (*(int32*)data)++; + return atomic; +} + +RpAtomic* +GetAtomicListCB(RpAtomic *atomic, void *data) +{ + **(RpAtomic***)data = atomic; + (*(RpAtomic***)data)++; + return atomic; +} + +RwFrame* +FindPedFrameFromNameCB(RwFrame *frame, void *data) +{ + RwObjectNameAssociation *assoc = (RwObjectNameAssociation*)data; + + if(_strcmpi(GetFrameNodeName(frame)+1, assoc->name+1) != 0){ + RwFrameForAllChildren(frame, FindPedFrameFromNameCB, assoc); + return assoc->frame ? nil : frame; + }else{ + assoc->frame = frame; + return nil; + } +} + +void +CPedModelInfo::SetLowDetailClump(RpClump *lodclump) +{ + RpAtomic *atomics[16]; + RpAtomic **pAtm; + int32 numAtm, numLodAtm; + int i; + RwObjectNameAssociation assoc; + + numAtm = 0; + numLodAtm = 0; + RpClumpForAllAtomics(m_clump, CountAtomicsCB, &numAtm); // actually unused + RpClumpForAllAtomics(lodclump, CountAtomicsCB, &numLodAtm); + + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedHiDetailCB); + RpClumpForAllAtomics(lodclump, SetAtomicRendererCB, CVisibilityPlugins::RenderPedLowDetailCB); + + pAtm = atomics; + RpClumpForAllAtomics(lodclump, GetAtomicListCB, &pAtm); + + for(i = 0; i < numLodAtm; i++){ + assoc.name = GetFrameNodeName(RpAtomicGetFrame(atomics[i])); + assoc.frame = nil; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), FindPedFrameFromNameCB, &assoc); + if(assoc.frame){ + RpAtomicSetFrame(atomics[i], assoc.frame); + RpClumpRemoveAtomic(lodclump, atomics[i]); + RpClumpAddAtomic(m_clump, atomics[i]); + } + } +} + +struct ColNodeInfo +{ + char *name; + int pedNode; + int pieceType; + float x, z; + float radius; +}; + +// TODO: find out piece types +#define NUMPEDINFONODES 8 +ColNodeInfo m_pColNodeInfos[NUMPEDINFONODES] = { + { NULL, PED_HEAD, 6, 0.0f, 0.05f, 0.2f }, + { "Storso", 0, 0, 0.0f, 0.15f, 0.2f }, + { "Storso", 0, 0, 0.0f, -0.05f, 0.3f }, + { NULL, PED_TORSO, 1, 0.0f, -0.07f, 0.3f }, + { NULL, PED_UPPERARML, 2, 0.07f, -0.1f, 0.2f }, + { NULL, PED_UPPERARMR, 3, -0.07f, -0.1f, 0.2f }, + { "Slowerlegl", 0, 4, 0.0f, 0.07f, 0.25f }, + { NULL, PED_LOWERLEGR, 5, 0.0f, 0.07f, 0.25f }, +}; + +RwObject* +FindHeadRadiusCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + *(float*)data = RpAtomicGetBoundingSphere(atomic)->radius; + return nil; +} + +void +CPedModelInfo::CreateHitColModel(void) +{ + RwObjectNameAssociation nameAssoc; + RwObjectIdAssociation idAssoc; + CVector center; + RwFrame *nodeFrame; + CColModel *colmodel = new CColModel; + CColSphere *spheres = (CColSphere*)RwMalloc(NUMPEDINFONODES*sizeof(CColSphere)); + RwFrame *root = RpClumpGetFrame(m_clump); + RwMatrix *mat = RwMatrixCreate(); + for(int i = 0; i < NUMPEDINFONODES; i++){ + nodeFrame = nil; + if(m_pColNodeInfos[i].name){ + nameAssoc.name = m_pColNodeInfos[i].name; + nameAssoc.frame = nil; + RwFrameForAllChildren(root, FindFrameFromNameCB, &nameAssoc); + nodeFrame = nameAssoc.frame; + }else{ + idAssoc.id = m_pColNodeInfos[i].pedNode; + idAssoc.frame = nil; + RwFrameForAllChildren(root, FindFrameFromIdCB, &idAssoc); + nodeFrame = idAssoc.frame; + } + if(nodeFrame){ + float radius = m_pColNodeInfos[i].radius; + if(m_pColNodeInfos[i].pieceType == 6) + RwFrameForAllObjects(nodeFrame, FindHeadRadiusCB, &radius); + RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEREPLACE); + const char *name = GetFrameNodeName(nodeFrame); + for(nodeFrame = RwFrameGetParent(nodeFrame); + nodeFrame; + nodeFrame = RwFrameGetParent(nodeFrame)){ + name = GetFrameNodeName(nodeFrame); + RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEPOSTCONCAT); + if(RwFrameGetParent(nodeFrame) == root) + break; + } + center.x = mat->pos.x + m_pColNodeInfos[i].x; + center.y = mat->pos.y + 0.0f; + center.z = mat->pos.z + m_pColNodeInfos[i].z; + spheres[i].Set(radius, center, 17, m_pColNodeInfos[i].pieceType); + } + } + RwMatrixDestroy(mat); + colmodel->spheres = spheres; + colmodel->numSpheres = NUMPEDINFONODES; + center.x = center.y = center.z = 0.0f; + colmodel->boundingSphere.Set(2.0f, center, 0, 0); + CVector min, max; + min.x = min.y = -0.5f; + min.z = -1.2f; + max.x = max.y = 0.5f; + max.z = 1.2f; + colmodel->boundingBox.Set(min, max, 0, 0); + colmodel->level = 0; + m_hitColModel = colmodel; +} + +STARTPATCHES + InjectHook(0x510210, &CPedModelInfo::SetClump_, PATCH_JUMP); + InjectHook(0x510280, &CPedModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x510390, &CPedModelInfo::SetLowDetailClump, PATCH_JUMP); + InjectHook(0x5104D0, &CPedModelInfo::CreateHitColModel, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h new file mode 100644 index 00000000..e917b6b2 --- /dev/null +++ b/src/modelinfo/PedModelInfo.h @@ -0,0 +1,47 @@ +#pragma once + +#include "ClumpModelInfo.h" + +enum PedNode { + PED_WAIST, + PED_TORSO, // Smid on PS2/PC, Storso on mobile/xbox + PED_HEAD, + PED_UPPERARML, + PED_UPPERARMR, + PED_HANDL, + PED_HANDR, + PED_UPPERLEGL, + PED_UPPERLEGR, + PED_FOOTL, + PED_FOOTR, + PED_LOWERLEGR, + // This is not valid apparently + PED_LOWERLEGL, +}; + +class CPedModelInfo : public CClumpModelInfo +{ +public: + void *m_animGroup; // TODO + int32 m_pedType; + int32 m_pedStatType; + uint32 m_carsCanDrive; + CColModel *m_hitColModel; + RpAtomic *m_head; + RpAtomic *m_lhand; + RpAtomic *m_rhand; + + static RwObjectNameIdAssocation m_pPedIds[12]; + + CPedModelInfo(void) : CClumpModelInfo(MITYPE_PED) { } + void DeleteRwObject(void); + void SetClump(RpClump *); + + void SetLowDetailClump(RpClump*); + void CreateHitColModel(void); + + + void DeleteRwObject_(void) { this->CPedModelInfo::DeleteRwObject(); } + void SetClump_(RpClump *clump) { this->CPedModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error"); diff --git a/src/modelinfo/SimpleModelInfo.cpp b/src/modelinfo/SimpleModelInfo.cpp new file mode 100644 index 00000000..a5853d6f --- /dev/null +++ b/src/modelinfo/SimpleModelInfo.cpp @@ -0,0 +1,174 @@ +#include "common.h" +#include "patcher.h" +#include "Camera.h" +#include "ModelInfo.h" + +#define LOD_DISTANCE (300.0f) + +void +CSimpleModelInfo::DeleteRwObject(void) +{ + int i; + RwFrame *f; + for(i = 0; i < m_numAtomics; i++) + if(m_atomics[i]){ + f = RpAtomicGetFrame(m_atomics[i]); + RpAtomicDestroy(m_atomics[i]); + RwFrameDestroy(f); + m_atomics[i] = nil; + RemoveTexDictionaryRef(); + } +} + +RwObject* +CSimpleModelInfo::CreateInstance(void) +{ + RpAtomic *atomic; + if(m_atomics[0] == nil) + return nil; + atomic = RpAtomicClone(m_atomics[0]); + RpAtomicSetFrame(atomic, RwFrameCreate()); + return (RwObject*)atomic; +} + +RwObject* +CSimpleModelInfo::CreateInstance(RwMatrix *matrix) +{ + RpAtomic *atomic; + RwFrame *frame; + + if(m_atomics[0] == nil) + return nil; + atomic = RpAtomicClone(m_atomics[0]); + frame = RwFrameCreate(); + *RwFrameGetMatrix(frame) = *matrix; + RpAtomicSetFrame(atomic, frame); + return (RwObject*)atomic; +} + +void +CSimpleModelInfo::Init(void) +{ + m_atomics[0] = nil; + m_atomics[1] = nil; + m_atomics[2] = nil; + m_numAtomics = 0; + m_furthest = 0; + m_normalCull = 0; + m_isDamaged = 0; + m_isBigBuilding = 0; + m_noFade = 0; + m_drawLast = 0; + m_additive = 0; + m_isSubway = 0; + m_ignoreLight = 0; + m_noZwrite = 0; +} + +void +CSimpleModelInfo::SetAtomic(int n, RpAtomic *atomic) +{ + AddTexDictionaryRef(); + m_atomics[n] = atomic; + if(m_ignoreLight){ + RpGeometry *geo = RpAtomicGetGeometry(atomic); + RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) & ~rpGEOMETRYLIGHT); + } +} + +void +CSimpleModelInfo::SetLodDistances(float *dist) +{ + m_lodDistances[0] = dist[0]; + m_lodDistances[1] = dist[1]; + m_lodDistances[2] = dist[2]; +} + +void +CSimpleModelInfo::IncreaseAlpha(void) +{ + if(m_alpha >= 0xEF) + m_alpha = 0xFF; + else + m_alpha += 0x10; +} + +float +CSimpleModelInfo::GetNearDistance(void) +{ + return m_lodDistances[2] * TheCamera.LODDistMultiplier; +} + +float +CSimpleModelInfo::GetLargestLodDistance(void) +{ + float d; + // TODO: what exactly is going on here? + if(m_furthest != 0 && !m_isDamaged) + d = m_lodDistances[m_furthest-1]; + else + d = m_lodDistances[m_numAtomics-1]; + return d * TheCamera.LODDistMultiplier; +} + +RpAtomic* +CSimpleModelInfo::GetAtomicFromDistance(float dist) +{ + int i; + i = 0; + // TODO: what exactly is going on here? + if(m_isDamaged) + i = m_furthest; + for(; i < m_numAtomics; i++) + if(dist < m_lodDistances[i] *TheCamera.LODDistMultiplier) + return m_atomics[i]; + return nil; +} + +void +CSimpleModelInfo::FindRelatedModel(void) +{ + int i; + CBaseModelInfo *mi; + for(i = 0; i < MODELINFOSIZE; i++){ + mi = CModelInfo::GetModelInfo(i); + if(mi && mi != this && + strcmp(GetName()+3, mi->GetName()+3) == 0){ + assert(mi->IsSimple()); + this->SetRelatedModel((CSimpleModelInfo*)mi); + return; + } + } +} + +void +CSimpleModelInfo::SetupBigBuilding(void) +{ + CSimpleModelInfo *related; + if(m_lodDistances[0] > LOD_DISTANCE && m_atomics[2] == nil){ + m_isBigBuilding = 1; + FindRelatedModel(); + related = GetRelatedModel(); + if(related) + m_lodDistances[2] = related->GetLargestLodDistance()/TheCamera.LODDistMultiplier; + else + m_lodDistances[2] = 100.0f; + } +} + + +STARTPATCHES + InjectHook(0x5179B0, &CSimpleModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x517B60, &CSimpleModelInfo::CreateInstance_1, PATCH_JUMP); + InjectHook(0x517AC0, &CSimpleModelInfo::CreateInstance_2, PATCH_JUMP); + InjectHook(0x4A9BA0, &CSimpleModelInfo::GetRwObject_, PATCH_JUMP); + InjectHook(0x517990, &CSimpleModelInfo::Init, PATCH_JUMP); + InjectHook(0x517C60, &CSimpleModelInfo::IncreaseAlpha, PATCH_JUMP); + InjectHook(0x517950, &CSimpleModelInfo::SetAtomic, PATCH_JUMP); + InjectHook(0x517AA0, &CSimpleModelInfo::SetLodDistances, PATCH_JUMP); + InjectHook(0x517A90, &CSimpleModelInfo::GetNearDistance, PATCH_JUMP); + InjectHook(0x517A60, &CSimpleModelInfo::GetLargestLodDistance, PATCH_JUMP); + InjectHook(0x517A00, &CSimpleModelInfo::GetAtomicFromDistance, PATCH_JUMP); + InjectHook(0x517C00, &CSimpleModelInfo::FindRelatedModel, PATCH_JUMP); + InjectHook(0x517B90, &CSimpleModelInfo::SetupBigBuilding, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h new file mode 100644 index 00000000..186a517c --- /dev/null +++ b/src/modelinfo/SimpleModelInfo.h @@ -0,0 +1,57 @@ +#pragma once + +#include "BaseModelInfo.h" + +class CSimpleModelInfo : public CBaseModelInfo +{ +public: + // atomics[2] is often a pointer to the non-LOD modelinfo + RpAtomic *m_atomics[3]; + // m_lodDistances[2] holds the near distance for LODs + float m_lodDistances[3]; + uint8 m_numAtomics; + uint8 m_alpha; + uint16 m_furthest : 2; // 0: numAtomics-1 is furthest visible + // 1: atomic 0 is furthest + // 2: atomic 1 is furthest + uint16 m_normalCull : 1; + uint16 m_isDamaged : 1; + uint16 m_isBigBuilding : 1; + uint16 m_noFade : 1; + uint16 m_drawLast : 1; + uint16 m_additive : 1; + uint16 m_isSubway : 1; + uint16 m_ignoreLight : 1; + uint16 m_noZwrite : 1; + + CSimpleModelInfo(void) : CBaseModelInfo(MITYPE_SIMPLE) {} + CSimpleModelInfo(ModeInfoType id) : CBaseModelInfo(id) {} + ~CSimpleModelInfo() {} + void DeleteRwObject(void); + RwObject *CreateInstance(void); + RwObject *CreateInstance(RwMatrix *); + RwObject *GetRwObject(void) { return (RwObject*)m_atomics[0]; } + + void Init(void); + void IncreaseAlpha(void); + void SetAtomic(int n, RpAtomic *atomic); + void SetLodDistances(float *dist); + float GetLodDistance(int i) { return m_lodDistances[i]; } + float GetNearDistance(void); + float GetLargestLodDistance(void); + RpAtomic *GetAtomicFromDistance(float dist); + void FindRelatedModel(void); + void SetupBigBuilding(void); + + void SetNumAtomics(int n) { m_numAtomics = n; } + CSimpleModelInfo *GetRelatedModel(void){ + return (CSimpleModelInfo*)m_atomics[2]; } + void SetRelatedModel(CSimpleModelInfo *m){ + m_atomics[2] = (RpAtomic*)m; } + + void DeleteRwObject_(void) { this->CSimpleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_1(void) { return this->CSimpleModelInfo::CreateInstance(); } + RwObject *CreateInstance_2(RwMatrix *m) { return this->CSimpleModelInfo::CreateInstance(m); } + RwObject *GetRwObject_(void) { return this->CSimpleModelInfo::GetRwObject(); } +}; +static_assert(sizeof(CSimpleModelInfo) == 0x4C, "CSimpleModelInfo: error"); diff --git a/src/modelinfo/TimeModelInfo.cpp b/src/modelinfo/TimeModelInfo.cpp new file mode 100644 index 00000000..3ab3e13a --- /dev/null +++ b/src/modelinfo/TimeModelInfo.cpp @@ -0,0 +1,36 @@ +#include "common.h" +#include "patcher.h" +#include "Camera.h" +#include "ModelInfo.h" + +CTimeModelInfo* +CTimeModelInfo::FindOtherTimeModel(void) +{ + char name[40]; + char *p; + int i; + + strcpy(name, GetName()); + // change _nt to _dy + if(p = strstr(name, "_nt")) + strncpy(p, "_dy", 4); + // change _dy to _nt + else if(p = strstr(name, "_dy")) + strncpy(p, "_nt", 4); + else + return nil; + + for(i = 0; i < MODELINFOSIZE; i++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); + if(mi && mi->m_type == MITYPE_TIME && + strncmp(name, mi->GetName(), 24) == 0){ + m_otherTimeModelID = i; + return (CTimeModelInfo*)mi; + } + } + return nil; +} + +STARTPATCHES + InjectHook(0x517C80, &CTimeModelInfo::FindOtherTimeModel, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/TimeModelInfo.h b/src/modelinfo/TimeModelInfo.h new file mode 100644 index 00000000..08e46bd3 --- /dev/null +++ b/src/modelinfo/TimeModelInfo.h @@ -0,0 +1,18 @@ +#pragma once + +#include "SimpleModelInfo.h" + +class CTimeModelInfo : public CSimpleModelInfo +{ + int32 m_timeOn; + int32 m_timeOff; + int32 m_otherTimeModelID; +public: + CTimeModelInfo(void) : CSimpleModelInfo(MITYPE_TIME) { m_otherTimeModelID = -1; } + + int32 GetTimeOn(void) { return m_timeOn; } + int32 GetTimeOff(void) { return m_timeOff; } + int32 GetOtherTimeModel(void) { return m_otherTimeModelID; } + CTimeModelInfo *FindOtherTimeModel(void); +}; +static_assert(sizeof(CTimeModelInfo) == 0x58, "CTimeModelInfo: error"); diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp new file mode 100644 index 00000000..575d0360 --- /dev/null +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -0,0 +1,917 @@ +#include "common.h" +#include +#include "patcher.h" +#include "RwHelper.h" +#include "General.h" +#include "NodeName.h" +#include "TxdStore.h" +#include "Weather.h" +#include "VisibilityPlugins.h" +#include "ModelInfo.h" + +int8 *CVehicleModelInfo::ms_compsToUse = (int8*)0x5FF2EC; // -2, -2 +int8 *CVehicleModelInfo::ms_compsUsed = (int8*)0x95CCB2; +RwTexture **CVehicleModelInfo::ms_pEnvironmentMaps = (RwTexture **)0x8F1A30; +RwRGBA *CVehicleModelInfo::ms_vehicleColourTable = (RwRGBA*)0x86BA88; +RwTexture **CVehicleModelInfo::ms_colourTextureTable = (RwTexture**)0x711C40; + +RwTexture *&gpWhiteTexture = *(RwTexture**)0x64C4F8; +RwFrame *&pMatFxIdentityFrame = *(RwFrame**)0x64C510; + +// TODO This depends on handling +WRAPPER void CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags) { EAXJMP(0x5203C0); } + +enum { + CAR_WHEEL_RF = 1, + CAR_WHEEL_RM = 2, + CAR_WHEEL_RB = 3, + CAR_WHEEL_LF = 4, + CAR_WHEEL_LM = 5, + CAR_WHEEL_LB = 6, + CAR_BUMP_FRONT = 7, + CAR_BUMP_REAR = 8, + CAR_WING_RF = 9, + CAR_WING_RR = 10, + CAR_DOOR_RF = 11, + CAR_DOOR_RR = 12, + CAR_WING_LF = 13, + CAR_WING_LR = 14, + CAR_DOOR_LF = 15, + CAR_DOOR_LR = 16, + CAR_BONNET = 17, + CAR_BOOT = 18, + CAR_WINDSCREEN = 19, + + CAR_POS_HEADLIGHTS = 0, + CAR_POS_TAILLIGHTS = 1, + CAR_POS_FRONTSEAT = 2, + CAR_POS_BACKSEAT = 3, + CAR_POS_EXHAUST = 9, +}; + +enum { + VEHICLE_FLAG_COLLAPSE = 0x2, + VEHICLE_FLAG_ADD_WHEEL = 0x4, + VEHICLE_FLAG_POS = 0x8, + VEHICLE_FLAG_DOOR = 0x10, + VEHICLE_FLAG_LEFT = 0x20, + VEHICLE_FLAG_RIGHT = 0x40, + VEHICLE_FLAG_FRONT = 0x80, + VEHICLE_FLAG_REAR = 0x100, + VEHICLE_FLAG_COMP = 0x200, + VEHICLE_FLAG_DRAWLAST = 0x400, + VEHICLE_FLAG_WINDSCREEN = 0x800, + VEHICLE_FLAG_ANGLECULL = 0x1000, + VEHICLE_FLAG_REARDOOR = 0x2000, + VEHICLE_FLAG_FRONTDOOR = 0x4000, +}; + +RwObjectNameIdAssocation carIds[] = { + { "wheel_rf_dummy", CAR_WHEEL_RF, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_rm_dummy", CAR_WHEEL_RM, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_rb_dummy", CAR_WHEEL_RB, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lf_dummy", CAR_WHEEL_LF, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lm_dummy", CAR_WHEEL_LM, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "wheel_lb_dummy", CAR_WHEEL_LB, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_ADD_WHEEL }, + { "bump_front_dummy", CAR_BUMP_FRONT, VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE }, + { "bonnet_dummy", CAR_BONNET, VEHICLE_FLAG_COLLAPSE }, + { "wing_rf_dummy", CAR_WING_RF, VEHICLE_FLAG_COLLAPSE }, + { "wing_rr_dummy", CAR_WING_RR, VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_COLLAPSE }, + { "door_rf_dummy", CAR_DOOR_RF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "door_rr_dummy", CAR_DOOR_RR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_RIGHT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "wing_lf_dummy", CAR_WING_LF, VEHICLE_FLAG_COLLAPSE }, + { "wing_lr_dummy", CAR_WING_LR, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "door_lf_dummy", CAR_DOOR_LF, VEHICLE_FLAG_FRONTDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "door_lr_dummy", CAR_DOOR_LR, VEHICLE_FLAG_REARDOOR | VEHICLE_FLAG_ANGLECULL | VEHICLE_FLAG_REAR | VEHICLE_FLAG_LEFT | VEHICLE_FLAG_DOOR | VEHICLE_FLAG_COLLAPSE }, + { "boot_dummy", CAR_BOOT, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE }, + { "bump_rear_dummy", CAR_BUMP_REAR, VEHICLE_FLAG_REAR | VEHICLE_FLAG_COLLAPSE }, + { "windscreen_dummy", CAR_WINDSCREEN, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_FRONT | VEHICLE_FLAG_COLLAPSE }, + + { "ped_frontseat", CAR_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_backseat", CAR_POS_BACKSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "headlights", CAR_POS_HEADLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "taillights", CAR_POS_TAILLIGHTS, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "exhaust", CAR_POS_EXHAUST, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation boatIds[] = { + { "boat_moving_hi", 1, VEHICLE_FLAG_COLLAPSE }, + { "boat_rudder_hi", 3, VEHICLE_FLAG_COLLAPSE }, + { "windscreen", 2, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE }, + { "ped_frontseat", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation trainIds[] = { + { "door_lhs_dummy", 1, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "door_rhs_dummy", 2, VEHICLE_FLAG_LEFT | VEHICLE_FLAG_COLLAPSE }, + { "light_front", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_rear", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_left_entry", 2, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_mid_entry", 3, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "ped_right_entry", 4, VEHICLE_FLAG_DOOR | VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation heliIds[] = { + { "chassis_dummy", 1, VEHICLE_FLAG_COLLAPSE }, + { "toprotor", 2, 0 }, + { "backrotor", 3, 0 }, + { "tail", 4, 0 }, + { "topknot", 5, 0 }, + { "skid_left", 6, 0 }, + { "skid_right", 7, 0 }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation planeIds[] = { + { "wheel_front_dummy", 2, 0 }, + { "wheel_rear_dummy", 3, 0 }, + { "light_tailplane", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_left", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "light_right", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation bikeIds[] = { + { "chassis_dummy", 1, 0 }, + { "forks_front", 2, 0 }, + { "forks_rear", 3, 0 }, + { "wheel_front", 4, 0 }, + { "wheel_rear", 5, 0 }, + { "mudguard", 6, 0 }, + { "ped_frontseat", 2, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "headlights", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "taillights", 1, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "exhaust", 9, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID }, + { "extra1", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra2", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra3", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra4", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra5", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { "extra6", 0, VEHICLE_FLAG_DRAWLAST | VEHICLE_FLAG_COMP | CLUMP_FLAG_NO_HIERID }, + { nil, 0, 0 } +}; + +RwObjectNameIdAssocation *CVehicleModelInfo::ms_vehicleDescs[] = { + carIds, + boatIds, + trainIds, + heliIds, + planeIds, + bikeIds +}; + + +CVehicleModelInfo::CVehicleModelInfo(void) + : CClumpModelInfo(MITYPE_VEHICLE) +{ + int32 i; + for(i = 0; i < NUM_VEHICLE_POSITIONS; i++){ + m_positions[i].x = 0.0f; + m_positions[i].y = 0.0f; + m_positions[i].z = 0.0f; + } + m_numColours = 0; +} + +void +CVehicleModelInfo::DeleteRwObject(void) +{ + int32 i; + RwFrame *f; + + for(i = 0; i < m_numComps; i++){ + f = RpAtomicGetFrame(m_comps[i]); + RpAtomicDestroy(m_comps[i]); + RwFrameDestroy(f); + } + m_numComps = 0; + CClumpModelInfo::DeleteRwObject(); +} + +RwObject* +CVehicleModelInfo::CreateInstance(void) +{ + RpClump *clump; + RpAtomic *atomic; + RwFrame *clumpframe, *f; + int32 comp1, comp2; + + clump = (RpClump*)CClumpModelInfo::CreateInstance(); + if(m_numComps != 0){ + clumpframe = RpClumpGetFrame(clump); + + comp1 = ChooseComponent(); + if(comp1 != -1){ + atomic = RpAtomicClone(m_comps[comp1]); + f = RwFrameCreate(); + RwFrameTransform(f, + RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp1])), + rwCOMBINEREPLACE); + RpAtomicSetFrame(atomic, f); + RpClumpAddAtomic(clump, atomic); + RwFrameAddChild(clumpframe, f); + } + ms_compsUsed[0] = comp1; + + comp2 = ChooseSecondComponent(); + if(comp2 != -1){ + atomic = RpAtomicClone(m_comps[comp2]); + f = RwFrameCreate(); + RwFrameTransform(f, + RwFrameGetMatrix(RpAtomicGetFrame(m_comps[comp2])), + rwCOMBINEREPLACE); + RpAtomicSetFrame(atomic, f); + RpClumpAddAtomic(clump, atomic); + RwFrameAddChild(clumpframe, f); + } + ms_compsUsed[1] = comp2; + }else{ + ms_compsUsed[0] = -1; + ms_compsUsed[1] = -1; + } + return (RwObject*)clump; +} + +void +CVehicleModelInfo::SetClump(RpClump *clump) +{ + CClumpModelInfo::SetClump(clump); + SetAtomicRenderCallbacks(); + SetFrameIds(ms_vehicleDescs[m_vehicleType]); + PreprocessHierarchy(); + FindEditableMaterialList(); + m_envMap = nil; + SetEnvironmentMap(); +} + +RwFrame* +CVehicleModelInfo::CollapseFramesCB(RwFrame *frame, void *data) +{ + RwFrameForAllChildren(frame, CollapseFramesCB, data); + RwFrameForAllObjects(frame, MoveObjectsCB, data); + RwFrameDestroy(frame); + return frame; +} + +RwObject* +CVehicleModelInfo::MoveObjectsCB(RwObject *object, void *data) +{ + RpAtomicSetFrame((RpAtomic*)object, (RwFrame*)data); + return object; +} + +RpAtomic* +CVehicleModelInfo::HideDamagedAtomicCB(RpAtomic *atomic, void *data) +{ + if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_dam")){ + RpAtomicSetFlags(atomic, 0); + CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_DAM); + }else if(strstr(GetFrameNodeName(RpAtomicGetFrame(atomic)), "_ok")) + CVisibilityPlugins::SetAtomicFlag(atomic, ATOMIC_FLAG_OK); + return atomic; +} + +RpMaterial* +CVehicleModelInfo::HasAlphaMaterialCB(RpMaterial *material, void *data) +{ + if(RpMaterialGetColor(material)->alpha != 0xFF){ + *(bool*)data = true; + return nil; + } + return material; +} + + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB(RpAtomic *atomic, void *data) +{ + RpClump *clump; + char *name; + bool alpha; + + clump = (RpClump*)data; + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){ + if(alpha || strncmp(name, "windscreen", 10) == 0) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB); + }else if(strstr(name, "_lo")){ + RpClumpRemoveAtomic(clump, atomic); + RpAtomicDestroy(atomic); + return atomic; // BUG: not done by gta + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data) +{ + char *name; + bool alpha; + + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi") || strncmp(name, "extra", 5) == 0){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle); + }else if(strstr(name, "_lo")){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle); + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Train(RpAtomic *atomic, void *data) +{ + char *name; + bool alpha; + + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + alpha = false; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), HasAlphaMaterialCB, &alpha); + if(strstr(name, "_hi")){ + if(alpha) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailAlphaCB); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderTrainHiDetailCB); + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data) +{ + RpClump *clump; + char *name; + + clump = (RpClump*)data; + name = GetFrameNodeName(RpAtomicGetFrame(atomic)); + if(strcmp(name, "boat_hi") == 0 || strncmp(name, "extra", 5) == 0) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB_Boat); + else if(strstr(name, "_hi")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleHiDetailCB); + else if(strstr(name, "_lo")){ + RpClumpRemoveAtomic(clump, atomic); + RpAtomicDestroy(atomic); + return atomic; // BUG: not done by gta + }else if(strstr(name, "_vlo")) + CVisibilityPlugins::SetAtomicRenderCallback(atomic, CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle); + else + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + HideDamagedAtomicCB(atomic, nil); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + return atomic; +} + +void +CVehicleModelInfo::SetAtomicRenderCallbacks(void) +{ + switch(m_vehicleType){ + case VEHICLE_TYPE_TRAIN: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Train, nil); + break; + case VEHICLE_TYPE_HELI: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Heli, nil); + break; + case VEHICLE_TYPE_PLANE: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_BigVehicle, nil); + break; + case VEHICLE_TYPE_BOAT: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB_Boat, m_clump); + break; + default: + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, m_clump); + break; + } +} + +RpAtomic* +CVehicleModelInfo::SetAtomicFlagCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::SetAtomicFlag(atomic, (int)data); + return atomic; +} + +RpAtomic* +CVehicleModelInfo::ClearAtomicFlagCB(RpAtomic *atomic, void *data) +{ + CVisibilityPlugins::ClearAtomicFlag(atomic, (int)data); + return atomic; +} + +RwObject* +GetOkAndDamagedAtomicCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_OK) + ((RpAtomic**)data)[0] = atomic; + else if(CVisibilityPlugins::GetAtomicId(atomic) & ATOMIC_FLAG_DAM) + ((RpAtomic**)data)[1] = atomic; + return object; +} + +void +CVehicleModelInfo::PreprocessHierarchy(void) +{ + int32 i; + RwObjectNameIdAssocation *desc; + RwFrame *f; + RpAtomic *atomic; + RwV3d *rwvec; + + desc = ms_vehicleDescs[m_vehicleType]; + m_numDoors = 0; + m_numComps = 0; + + for(i = 0; desc[i].name; i++){ + RwObjectNameAssociation assoc; + + if((desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS)) == 0) + continue; + assoc.frame = nil; + assoc.name = desc[i].name; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), + FindFrameFromNameWithoutIdCB, &assoc); + if(assoc.frame == nil) + continue; + + if(desc[i].flags & VEHICLE_FLAG_DOOR) + m_numDoors++; + + if(desc[i].flags & VEHICLE_FLAG_POS){ + f = assoc.frame; + rwvec = (RwV3d*)&m_positions[desc[i].hierId]; + *rwvec = *RwMatrixGetPos(RwFrameGetMatrix(f)); + for(f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) + RwV3dTransformPoints(rwvec, rwvec, 1, RwFrameGetMatrix(f)); + RwFrameDestroy(assoc.frame); + }else{ + atomic = (RpAtomic*)GetFirstObject(assoc.frame); + RpClumpRemoveAtomic(m_clump, atomic); + RwFrameRemoveChild(assoc.frame); + SetVehicleComponentFlags(assoc.frame, desc[i].flags); + m_comps[m_numComps++] = atomic; + } + } + + for(i = 0; desc[i].name; i++){ + RwObjectIdAssociation assoc; + + if(desc[i].flags & (VEHICLE_FLAG_COMP|VEHICLE_FLAG_POS)) + continue; + assoc.frame = nil; + assoc.id = desc[i].hierId; + RwFrameForAllChildren(RpClumpGetFrame(m_clump), + FindFrameFromIdCB, &assoc); + if(assoc.frame == nil) + continue; + + if(desc[i].flags & VEHICLE_FLAG_DOOR) + m_numDoors++; + + if(desc[i].flags & VEHICLE_FLAG_COLLAPSE){ + RpAtomic *okdam[2] = { nil, nil }; + RwFrameForAllChildren(assoc.frame, CollapseFramesCB, assoc.frame); + RwFrameUpdateObjects(assoc.frame); + RwFrameForAllObjects(assoc.frame, GetOkAndDamagedAtomicCB, okdam); + if(okdam[0] && okdam[1]) + RpAtomicSetRenderCallBack(okdam[1], RpAtomicGetRenderCallBack(okdam[0])); + } + + SetVehicleComponentFlags(assoc.frame, desc[i].flags); + + if(desc[i].flags & VEHICLE_FLAG_ADD_WHEEL){ + if(m_wheelId == -1) + RwFrameDestroy(assoc.frame); + else{ + RwV3d scale; + atomic = (RpAtomic*)CModelInfo::GetModelInfo(m_wheelId)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atomic)); + RpAtomicSetFrame(atomic, assoc.frame); + RpClumpAddAtomic(m_clump, atomic); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, + CVisibilityPlugins::RenderWheelAtomicCB); + scale.x = m_wheelScale; + scale.y = m_wheelScale; + scale.z = m_wheelScale; + RwFrameScale(assoc.frame, &scale, rwCOMBINEPRECONCAT); + } + } + } +} + + +#define COMPRULE_RULE(comprule) (((comprule) >> 12) & 0xF) +#define COMPRULE_COMPS(comprule) ((comprule) & 0xFFF) +#define COMPRULE_COMPN(comps, n) (((comps) >> 4*(n)) & 0xF) +#define COMPRULE2_RULE(comprule) (((comprule) >> (12+16)) & 0xF) +#define COMPRULE2_COMPS(comprule) ((comprule >> 16) & 0xFFF) +#define COMPRULE2_COMPN(comps, n) (((comps >> 16) >> 4*(n)) & 0xF) + +bool +IsValidCompRule(int rule) +{ + if(rule == 2) + return CWeather::OldWeatherType == WEATHER_RAINY || + CWeather::NewWeatherType == WEATHER_RAINY; + return true; +} + +int32 +CountCompsInRule(int comps) +{ + int32 n; + for(n = 0; comps != 0; comps >>= 4) + if((comps & 0xF) != 0xF) + n++; + return n; +} + +int32 +ChooseComponent(int32 rule, int32 comps) +{ + int32 n; + switch(rule){ + // identical cases.... + case 1: + n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps)); + return COMPRULE_COMPN(comps, n); + case 2: + // only valid in rain + n = CGeneral::GetRandomNumberInRange(0, CountCompsInRule(comps)); + return COMPRULE_COMPN(comps, n); + } + return -1; +} + +int32 +GetListOfComponentsNotUsedByRules(uint32 comprules, int32 numComps, int32 *comps) +{ + int32 i, n; + int32 unused[6] = { 0, 1, 2, 3, 4, 5 }; + + // first comprule + if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules))) + for(i = 0; i < 3; i++){ + n = COMPRULE_COMPN(comprules, i); + if(n != 0xF) + unused[n] = 0xF; + } + // second comprule + comprules >>= 16; + if(COMPRULE_RULE(comprules) && IsValidCompRule(COMPRULE_RULE(comprules))) + for(i = 0; i < 3; i++){ + n = COMPRULE_COMPN(comprules, i); + if(n != 0xF) + unused[n] = 0xF; + } + + n = 0; + for(i = 0; i < numComps; i++) + if(unused[i] != 0xF) + comps[n++] = unused[i]; + return n; +} + +int32 wheelIds[] = { CAR_WHEEL_LF, CAR_WHEEL_LB, CAR_WHEEL_RF, CAR_WHEEL_RB }; + +void +CVehicleModelInfo::GetWheelPosn(int32 n, CVector &pos) +{ + RwMatrix *m = RwFrameGetMatrix(GetFrameFromId(m_clump, wheelIds[n])); + pos.x = RwMatrixGetPos(m)->x; + pos.y = RwMatrixGetPos(m)->y; + pos.z = RwMatrixGetPos(m)->z; +} + + +int32 +CVehicleModelInfo::ChooseComponent(void) +{ + int32 comp; + int32 comps[8]; + int32 n; + + comp = -1; + if(ms_compsToUse[0] == -2){ + if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules))) + comp = ::ChooseComponent(COMPRULE_RULE(m_compRules), COMPRULE_COMPS(m_compRules)); + else if(CGeneral::GetRandomNumberInRange(0, 3) < 2){ + n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps); + if(n) + comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)]; + } + }else{ + comp = ms_compsToUse[0]; + ms_compsToUse[0] = -2; + } + return comp; +} + +int32 +CVehicleModelInfo::ChooseSecondComponent(void) +{ + int32 comp; + int32 comps[8]; + int32 n; + + comp = -1; + if(ms_compsToUse[1] == -2){ + if(COMPRULE2_RULE(m_compRules) && IsValidCompRule(COMPRULE2_RULE(m_compRules))) + comp = ::ChooseComponent(COMPRULE2_RULE(m_compRules), COMPRULE2_COMPS(m_compRules)); + else if(COMPRULE_RULE(m_compRules) && IsValidCompRule(COMPRULE_RULE(m_compRules)) && + CGeneral::GetRandomNumberInRange(0, 3) < 2){ + + n = GetListOfComponentsNotUsedByRules(m_compRules, m_numComps, comps); + if(n) + comp = comps[(int)CGeneral::GetRandomNumberInRange(0, n)]; + } + }else{ + comp = ms_compsToUse[1]; + ms_compsToUse[1] = -2; + } + return comp; +} + +struct editableMatCBData +{ + CVehicleModelInfo *vehicle; + int32 numMats1; + int32 numMats2; +}; + +RpMaterial* +CVehicleModelInfo::GetEditableMaterialListCB(RpMaterial *material, void *data) +{ + static RwRGBA white = { 255, 255, 255, 255 }; + RwRGBA *col; + editableMatCBData *cbdata; + + cbdata = (editableMatCBData*)data; + col = RpMaterialGetColor(material); + if(col->red == 0x3C && col->green == 0xFF && col->blue == 0){ + cbdata->vehicle->m_materials1[cbdata->numMats1++] = material; + RpMaterialSetColor(material, &white); + }else if(col->red == 0xFF && col->green == 0 && col->blue == 0xAF){ + cbdata->vehicle->m_materials2[cbdata->numMats2++] = material; + RpMaterialSetColor(material, &white); + } + return material; +} + +RpAtomic* +CVehicleModelInfo::GetEditableMaterialListCB(RpAtomic *atomic, void *data) +{ + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), GetEditableMaterialListCB, data); + return atomic; +} + +void +CVehicleModelInfo::FindEditableMaterialList(void) +{ + editableMatCBData cbdata; + int32 i; + + cbdata.vehicle = this; + cbdata.numMats1 = 0; + cbdata.numMats2 = 0; + RpClumpForAllAtomics(m_clump, GetEditableMaterialListCB, &cbdata); + for(i = 0; i < m_numComps; i++) + GetEditableMaterialListCB(m_comps[i], &cbdata); + m_materials1[cbdata.numMats1] = nil; + m_materials2[cbdata.numMats2] = nil; + m_currentColour1 = -1; + m_currentColour2 = -1; +} + +void +CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2) +{ + RwRGBA col, *colp; + RwTexture *coltex; + RpMaterial **matp; + + if(c1 != m_currentColour1){ + col = ms_vehicleColourTable[c1]; + coltex = ms_colourTextureTable[c1]; + for(matp = m_materials1; *matp; matp++){ + if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){ + colp = RpMaterialGetColor(*matp); + colp->red = col.red; + colp->green = col.green; + colp->blue = col.blue; + }else + RpMaterialSetTexture(*matp, coltex); + } + m_currentColour1 = c1; + } + + if(c2 != m_currentColour2){ + col = ms_vehicleColourTable[c2]; + coltex = ms_colourTextureTable[c2]; + for(matp = m_materials2; *matp; matp++){ + if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){ + colp = RpMaterialGetColor(*matp); + colp->red = col.red; + colp->green = col.green; + colp->blue = col.blue; + }else + RpMaterialSetTexture(*matp, coltex); + } + m_currentColour2 = c2; + } +} + + +RpMaterial* +CVehicleModelInfo::HasSpecularMaterialCB(RpMaterial *material, void *data) +{ + if(RpMaterialGetSurfaceProperties(material)->specular <= 0.0f) + return material; + *(bool*)data = true; + return nil; +} + +RpMaterial* +CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial *material, void *data) +{ + float spec; + + spec = RpMaterialGetSurfaceProperties(material)->specular; + if(spec <= 0.0f) + RpMatFXMaterialSetEffects(material, rpMATFXEFFECTNULL); + else{ + if(RpMaterialGetTexture(material) == 0) + RpMaterialSetTexture(material, gpWhiteTexture); + RpMatFXMaterialSetEffects(material, rpMATFXEFFECTENVMAP); + spec *= 0.5f; // Tone down a bit for PC + RpMatFXMaterialSetupEnvMap(material, (RwTexture*)data, pMatFxIdentityFrame, false, spec); + } + return material; +} + +RpAtomic* +CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data) +{ + bool hasSpec; + RpGeometry *geo; + + geo = RpAtomicGetGeometry(atomic); + hasSpec = 0; + RpGeometryForAllMaterials(geo, HasSpecularMaterialCB, &hasSpec); + if(hasSpec){ + RpGeometryForAllMaterials(geo, SetEnvironmentMapCB, data); + RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) | rpGEOMETRYMODULATEMATERIALCOLOR); + RpMatFXAtomicEnableEffects(atomic); + // PS2 sets of PS2Manager lighting CB here + } + return atomic; +} + +void +CVehicleModelInfo::SetEnvironmentMap(void) +{ + CSimpleModelInfo *wheelmi; + int32 i; + + if(pMatFxIdentityFrame == nil){ + pMatFxIdentityFrame = RwFrameCreate(); + RwMatrixSetIdentity(RwFrameGetMatrix(pMatFxIdentityFrame)); + RwFrameUpdateObjects(pMatFxIdentityFrame); + RwFrameGetLTM(pMatFxIdentityFrame); + } + + if(m_envMap != ms_pEnvironmentMaps[0]){ + m_envMap = ms_pEnvironmentMaps[0]; + RpClumpForAllAtomics(m_clump, SetEnvironmentMapCB, m_envMap); + if(m_wheelId != -1){ + wheelmi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_wheelId); + for(i = 0; i < wheelmi->m_numAtomics; i++) + SetEnvironmentMapCB(wheelmi->m_atomics[i], m_envMap); + } + } +} + +void +CVehicleModelInfo::LoadEnvironmentMaps(void) +{ + char *texnames[] = { + "reflection01", // only one used + "reflection02", + "reflection03", + "reflection04", + "reflection05", + "reflection06", + }; + int32 txdslot; + int32 i; + + txdslot = CTxdStore::FindTxdSlot("particle"); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(txdslot); + for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++){ + ms_pEnvironmentMaps[i] = RwTextureRead(texnames[i], nil); + RwTextureSetFilterMode(ms_pEnvironmentMaps[i], rwFILTERLINEAR); + } + if(gpWhiteTexture == nil){ + gpWhiteTexture = RwTextureRead("white", nil); + gpWhiteTexture->name[0] = '@'; + RwTextureSetFilterMode(gpWhiteTexture, rwFILTERLINEAR); + } + CTxdStore::PopCurrentTxd(); +} + +void +CVehicleModelInfo::ShutdownEnvironmentMaps(void) +{ + int32 i; + + // ignoring "initialised" as that's a PS2 thing only + RwTextureDestroy(gpWhiteTexture); + gpWhiteTexture = nil; + for(i = 0; i < NUM_VEHICLE_ENVMAPS; i++) + if(ms_pEnvironmentMaps[i]) + RwTextureDestroy(ms_pEnvironmentMaps[i]); + RwFrameDestroy(pMatFxIdentityFrame); + pMatFxIdentityFrame = nil; +} + +STARTPATCHES + InjectHook(0x51FDC0, &CVehicleModelInfo::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x51FCB0, &CVehicleModelInfo::CreateInstance_, PATCH_JUMP); + InjectHook(0x51FC60, &CVehicleModelInfo::SetClump_, PATCH_JUMP); + + InjectHook(0x51FE10, &CVehicleModelInfo::CollapseFramesCB, PATCH_JUMP); + InjectHook(0x51FE50, &CVehicleModelInfo::MoveObjectsCB, PATCH_JUMP); + InjectHook(0x51FE70, &CVehicleModelInfo::HideDamagedAtomicCB, PATCH_JUMP); + InjectHook(0x51FEF0, &CVehicleModelInfo::HasAlphaMaterialCB, PATCH_JUMP); + + InjectHook(0x51FF10, &CVehicleModelInfo::SetAtomicRendererCB, PATCH_JUMP); + InjectHook(0x520030, &CVehicleModelInfo::SetAtomicRendererCB_BigVehicle, PATCH_JUMP); + InjectHook(0x520230, &CVehicleModelInfo::SetAtomicRendererCB_Train, PATCH_JUMP); + InjectHook(0x520120, &CVehicleModelInfo::SetAtomicRendererCB_Boat, PATCH_JUMP); + InjectHook(0x520210, &CVehicleModelInfo::SetAtomicRendererCB_Heli, PATCH_JUMP); + InjectHook(0x5202C0, &CVehicleModelInfo::SetAtomicRenderCallbacks, PATCH_JUMP); + + InjectHook(0x520340, &CVehicleModelInfo::SetAtomicFlagCB, PATCH_JUMP); + InjectHook(0x520360, &CVehicleModelInfo::ClearAtomicFlagCB, PATCH_JUMP); + + InjectHook(0x5204D0, &CVehicleModelInfo::PreprocessHierarchy, PATCH_JUMP); + + InjectHook(0x520840, &CVehicleModelInfo::GetWheelPosn, PATCH_JUMP); + + InjectHook(0x520880, IsValidCompRule, PATCH_JUMP); + InjectHook(0x520990, CountCompsInRule, PATCH_JUMP); + InjectHook(0x5209C0, ChooseComponent, PATCH_JUMP); + InjectHook(0x5208C0, GetListOfComponentsNotUsedByRules, PATCH_JUMP); + InjectHook(0x520AB0, &CVehicleModelInfo::ChooseComponent, PATCH_JUMP); + InjectHook(0x520BE0, &CVehicleModelInfo::ChooseSecondComponent, PATCH_JUMP); + + InjectHook(0x520DC0, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP); + InjectHook(0x520D30, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::GetEditableMaterialListCB, PATCH_JUMP); + InjectHook(0x520DE0, &CVehicleModelInfo::FindEditableMaterialList, PATCH_JUMP); + InjectHook(0x520E70, &CVehicleModelInfo::SetVehicleColour, PATCH_JUMP); + + InjectHook(0x521820, (RpAtomic *(*)(RpAtomic*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP); + InjectHook(0x5217A0, (RpMaterial *(*)(RpMaterial*, void*))CVehicleModelInfo::SetEnvironmentMapCB, PATCH_JUMP); + InjectHook(0x521770, CVehicleModelInfo::HasSpecularMaterialCB, PATCH_JUMP); + InjectHook(0x521890, &CVehicleModelInfo::SetEnvironmentMap, PATCH_JUMP); + InjectHook(0x521680, CVehicleModelInfo::LoadEnvironmentMaps, PATCH_JUMP); + InjectHook(0x521720, CVehicleModelInfo::ShutdownEnvironmentMaps, PATCH_JUMP); +ENDPATCHES diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h new file mode 100644 index 00000000..ccc46f73 --- /dev/null +++ b/src/modelinfo/VehicleModelInfo.h @@ -0,0 +1,115 @@ +#pragma once + +#include "ClumpModelInfo.h" + +enum { + NUM_VEHICLE_POSITIONS = 10, + NUM_FIRST_MATERIALS = 26, + NUM_SECOND_MATERIALS = 26, + NUM_VEHICLE_COLOURS = 8, + NUM_VEHICLE_ENVMAPS = 1 +}; + +enum { + ATOMIC_FLAG_OK = 0x1, + ATOMIC_FLAG_DAM = 0x2, + ATOMIC_FLAG_LEFT = 0x4, + ATOMIC_FLAG_RIGHT = 0x8, + ATOMIC_FLAG_FRONT = 0x10, + ATOMIC_FLAG_REAR = 0x20, + ATOMIC_FLAG_DRAWLAST = 0x40, + ATOMIC_FLAG_WINDSCREEN = 0x80, + ATOMIC_FLAG_ANGLECULL = 0x100, + ATOMIC_FLAG_REARDOOR = 0x200, + ATOMIC_FLAG_FRONTDOOR = 0x400, + ATOMIC_FLAG_NOCULL = 0x800, +}; + +enum { + VEHICLE_TYPE_CAR, + VEHICLE_TYPE_BOAT, + VEHICLE_TYPE_TRAIN, + VEHICLE_TYPE_HELI, + VEHICLE_TYPE_PLANE, + VEHICLE_TYPE_BIKE, + NUM_VEHICLE_TYPES +}; + +class CVehicleModelInfo : public CClumpModelInfo +{ +public: + uint8 m_lastColour1; + uint8 m_lastColour2; + char m_gameName[32]; + int32 m_vehicleType; + int32 m_wheelId; + float m_wheelScale; + int32 m_numDoors; + int32 m_handlingId; + int32 m_vehicleClass; + int32 m_level; + CVector m_positions[NUM_VEHICLE_POSITIONS]; + uint32 m_compRules; + float m_bikeSteerAngle; + RpMaterial *m_materials1[NUM_FIRST_MATERIALS]; + RpMaterial *m_materials2[NUM_SECOND_MATERIALS]; + uint8 m_colours1[NUM_VEHICLE_COLOURS]; + uint8 m_colours2[NUM_VEHICLE_COLOURS]; + uint8 m_numColours; + uint8 m_bLastColorVariation; // + uint8 m_currentColour1; + uint8 m_currentColour2; + RwTexture *m_envMap; + RpAtomic *m_comps[6]; + int32 m_numComps; + + static int8 *ms_compsToUse; // [2]; + static int8 *ms_compsUsed; // [2]; + static RwTexture **ms_pEnvironmentMaps; // [NUM_VEHICLE_ENVMAPS] + static RwRGBA *ms_vehicleColourTable; // [256] + static RwTexture **ms_colourTextureTable; // [256] + static RwObjectNameIdAssocation *ms_vehicleDescs[NUM_VEHICLE_TYPES]; + + CVehicleModelInfo(void); + void DeleteRwObject(void); + RwObject *CreateInstance(void); + void SetClump(RpClump *); + + static RwFrame *CollapseFramesCB(RwFrame *frame, void *data); + static RwObject *MoveObjectsCB(RwObject *object, void *data); + static RpAtomic *HideDamagedAtomicCB(RpAtomic *atomic, void *data); + static RpMaterial *HasAlphaMaterialCB(RpMaterial *material, void *data); + + static RpAtomic *SetAtomicRendererCB(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_BigVehicle(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Train(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Boat(RpAtomic *atomic, void *data); + static RpAtomic *SetAtomicRendererCB_Heli(RpAtomic *atomic, void *data); + void SetAtomicRenderCallbacks(void); + + static RpAtomic *SetAtomicFlagCB(RpAtomic *atomic, void *data); + static RpAtomic *ClearAtomicFlagCB(RpAtomic *atomic, void *data); + void SetVehicleComponentFlags(RwFrame *frame, uint32 flags); + void PreprocessHierarchy(void); + void GetWheelPosn(int32 n, CVector &pos); + + int32 ChooseComponent(void); + int32 ChooseSecondComponent(void); + + static RpMaterial *GetEditableMaterialListCB(RpMaterial *material, void *data); + static RpAtomic *GetEditableMaterialListCB(RpAtomic *atomic, void *data); + void FindEditableMaterialList(void); + void SetVehicleColour(uint8 c1, uint8 c2); + + static RpAtomic *SetEnvironmentMapCB(RpAtomic *atomic, void *data); + static RpMaterial *SetEnvironmentMapCB(RpMaterial *material, void *data); + static RpMaterial *HasSpecularMaterialCB(RpMaterial *material, void *data); + void SetEnvironmentMap(void); + static void LoadEnvironmentMaps(void); + static void ShutdownEnvironmentMaps(void); + + void DeleteRwObject_(void) { this->CVehicleModelInfo::DeleteRwObject(); } + RwObject *CreateInstance_(void) { return this->CVehicleModelInfo::CreateInstance(); } + void SetClump_(RpClump *clump) { this->CVehicleModelInfo::SetClump(clump); } +}; +static_assert(sizeof(CVehicleModelInfo) == 0x1F8, "CVehicleModelInfo: error"); diff --git a/src/patcher.cpp b/src/patcher.cpp new file mode 100644 index 00000000..5fdbdf8b --- /dev/null +++ b/src/patcher.cpp @@ -0,0 +1,22 @@ +#include "common.h" +#include "patcher.h" + +StaticPatcher *StaticPatcher::ms_head; + +StaticPatcher::StaticPatcher(Patcher func) + : m_func(func) +{ + m_next = ms_head; + ms_head = this; +} + +void +StaticPatcher::Apply() +{ + StaticPatcher *current = ms_head; + while(current){ + current->Run(); + current = current->m_next; + } + ms_head = nil; +} diff --git a/src/patcher.h b/src/patcher.h new file mode 100644 index 00000000..4ac1111b --- /dev/null +++ b/src/patcher.h @@ -0,0 +1,171 @@ +#pragma once + +#define WRAPPER __declspec(naked) +#define DEPRECATED __declspec(deprecated) +#define EAXJMP(a) { _asm mov eax, a _asm jmp eax } +#define VARJMP(a) { _asm jmp a } +#define WRAPARG(a) UNREFERENCED_PARAMETER(a) + +#define NOVMT __declspec(novtable) +#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a + +enum +{ + PATCH_CALL, + PATCH_JUMP, + PATCH_NOTHING, +}; + +enum +{ + III_10 = 1, + III_11, + III_STEAM, + VC_10, + VC_11, + VC_STEAM +}; + +extern int gtaversion; + +template +inline T AddressByVersion(uint32_t addressIII10, uint32_t addressIII11, uint32_t addressIIISteam, uint32_t addressvc10, uint32_t addressvc11, uint32_t addressvcSteam) +{ + if(gtaversion == -1){ + if(*(uint32_t*)0x5C1E75 == 0xB85548EC) gtaversion = III_10; + else if(*(uint32_t*)0x5C2135 == 0xB85548EC) gtaversion = III_11; + else if(*(uint32_t*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM; + else if(*(uint32_t*)0x667BF5 == 0xB85548EC) gtaversion = VC_10; + else if(*(uint32_t*)0x667C45 == 0xB85548EC) gtaversion = VC_11; + else if(*(uint32_t*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM; + else gtaversion = 0; + } + switch(gtaversion){ + case III_10: + return (T)addressIII10; + case III_11: + return (T)addressIII11; + case III_STEAM: + return (T)addressIIISteam; + case VC_10: + return (T)addressvc10; + case VC_11: + return (T)addressvc11; + case VC_STEAM: + return (T)addressvcSteam; + default: + return (T)0; + } +} + +inline bool +is10(void) +{ + return gtaversion == III_10 || gtaversion == VC_10; +} + +inline bool +isIII(void) +{ + return gtaversion >= III_10 && gtaversion <= III_STEAM; +} + +inline bool +isVC(void) +{ + return gtaversion >= VC_10 && gtaversion <= VC_STEAM; +} + +#define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5) +#define INTERCEPT(saved, func, a) \ +{ \ + saved = PTRFROMCALL(a); \ + InjectHook(a, func); \ +} + +template inline void +Patch(AT address, T value) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(T*)address = value; + VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); +} + +template inline void +Nop(AT address, unsigned int nCount) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + memset((void*)address, 0x90, nCount); + VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); +} + +template inline void +InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING) +{ + DWORD dwProtect[2]; + switch ( nType ) + { + case PATCH_JUMP: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE9; + break; + case PATCH_CALL: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE8; + break; + default: + VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + break; + } + DWORD dwHook; + _asm + { + mov eax, hook + mov dwHook, eax + } + + *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; + if ( nType == PATCH_NOTHING ) + VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); + else + VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); +} + +inline void ExtractCall(void *dst, uint32_t a) +{ + *(uint32_t*)dst = (uint32_t)(*(uint32_t*)(a+1) + a + 5); +} +template +inline void InterceptCall(void *dst, T func, uint32_t a) +{ + ExtractCall(dst, a); + InjectHook(a, func); +} +template +inline void InterceptVmethod(void *dst, T func, uint32_t a) +{ + *(uint32_t*)dst = *(uint32_t*)a; + Patch(a, func); +} + + + +class StaticPatcher +{ +private: + using Patcher = void(*)(); + + Patcher m_func; + StaticPatcher *m_next; + static StaticPatcher *ms_head; + + void Run() { m_func(); } +public: + StaticPatcher(Patcher func); + static void Apply(); +}; + +#define STARTPATCHES static StaticPatcher Patcher([](){ +#define ENDPATCHES }); diff --git a/src/render/2dEffect.h b/src/render/2dEffect.h new file mode 100644 index 00000000..6cba85d1 --- /dev/null +++ b/src/render/2dEffect.h @@ -0,0 +1,39 @@ +class C2dEffect +{ +public: + struct Light { + float dist; + float outerRange; + float size; + float innerRange; + uint8 flash; + uint8 wet; + uint8 flare; + uint8 shadowIntens; + uint8 flag; + RwTexture *corona; + RwTexture *shadow; + }; + struct Particle { + int particleType; + float dir[3]; + float scale; + }; + struct Attractor { + CVector dir; + uint8 flag; + uint8 probability; + }; + + CVector pos; + RwRGBA col; + uint8 type; + union { + Light light; + Particle particle; + Attractor attractor; + }; + + C2dEffect(void) {} +}; +static_assert(sizeof(C2dEffect) == 0x34, "C2dEffect: error"); diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp new file mode 100644 index 00000000..64bc93e8 --- /dev/null +++ b/src/render/Clouds.cpp @@ -0,0 +1,430 @@ +#include "common.h" +#include "patcher.h" +#include "Sprite.h" +#include "General.h" +#include "Coronas.h" +#include "Camera.h" +#include "TxdStore.h" +#include "Weather.h" +#include "Clock.h" +#include "Timer.h" +#include "Timecycle.h" +#include "Renderer.h" +#include "Clouds.h" + +#define SMALLSTRIPHEIGHT 4.0f +#define HORIZSTRIPHEIGHT 48.0f + +RwTexture **gpCloudTex = (RwTexture**)0x9411C0; //[5]; + +float &CClouds::CloudRotation = *(float*)0x8F5F40; +uint32 &CClouds::IndividualRotation = *(uint32*)0x943078; + +float &CClouds::ms_cameraRoll = *(float*)0x8F29CC; +float &CClouds::ms_horizonZ = *(float*)0x8F31C0; +CRGBA &CClouds::ms_colourTop = *(CRGBA*)0x94143C; +CRGBA &CClouds::ms_colourBottom = *(CRGBA*)0x8F2C38; + +void +CClouds::Init(void) +{ + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle")); + gpCloudTex[0] = RwTextureRead("cloud1", nil); + gpCloudTex[1] = RwTextureRead("cloud2", nil); + gpCloudTex[2] = RwTextureRead("cloud3", nil); + gpCloudTex[3] = RwTextureRead("cloudhilit", nil); + gpCloudTex[4] = RwTextureRead("cloudmasked", nil); + CTxdStore::PopCurrentTxd(); + CloudRotation = 0.0f; +} + +void +CClouds::Update(void) +{ + float s = sin(TheCamera.Orientation - 0.85f); + CloudRotation += CWeather::Wind*s*0.0025f; + IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f) * 60.0f; +} + + +void +CClouds::Render(void) +{ + int i; + float szx, szy; + RwV3d screenpos; + RwV3d worldpos; + + CCoronas::SunBlockedByClouds = false; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + CSprite::InitSpriteBuffer(); + + int minute = CClock::GetHours()*60 + CClock::GetMinutes(); + RwV3d campos = *(RwV3d*)&TheCamera.GetPosition(); + + float coverage = CWeather::CloudCoverage <= CWeather::Foggyness ? CWeather::Foggyness : CWeather::CloudCoverage; + + // Moon + int moonfadeout = abs(minute - 180); // fully visible at 3AM + if(moonfadeout < 180){ // fade in/out 3 hours + int brightness = (1.0f - coverage) * (180 - moonfadeout); + RwV3d pos = { 0.0f, -100.0f, 15.0f }; + RwV3dAdd(&worldpos, &campos, &pos); + if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){ + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[2]->raster); + if(CCoronas::bSmallMoon){ + szx *= 4.0f; + szy *= 4.0f; + }else{ + szx *= 10.0f; + szy *= 10.0f; + } + CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z, + szx, szy, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255); + } + } + + // The R* logo + int starintens = 0; + if(CClock::GetHours() < 22 && CClock::GetHours() > 5) + starintens = 0; + else if(CClock::GetHours() > 22 || CClock::GetHours() < 5) + starintens = 255; + else if(CClock::GetHours() == 22) + starintens = 255 * CClock::GetMinutes()/60.0f; + else if(CClock::GetHours() == 5) + starintens = 255 * (60 - CClock::GetMinutes())/60.0f; + if(starintens != 0){ + // R + static float StarCoorsX[9] = { 0.0f, 0.05f, 0.12f, 0.5f, 0.8f, 0.6f, 0.27f, 0.55f, 0.75f }; + static float StarCoorsY[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f }; + static float StarSizes[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f }; + int brightness = (1.0f - coverage) * starintens; + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster); + for(i = 0; i < 11; i++){ + RwV3d pos = { 100.0f, 0.0f, 10.0f }; + if(i >= 9) pos.x = -pos.x; + RwV3dAdd(&worldpos, &campos, &pos); + worldpos.y -= 90.0f*StarCoorsX[i%9]; + worldpos.z += 80.0f*StarCoorsY[i%9]; + if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){ + float sz = 0.8f*StarSizes[i%9]; + CSprite::RenderBufferedOneXLUSprite(screenpos.x, screenpos.y, screenpos.z, + szx*sz, szy*sz, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255); + } + } + CSprite::FlushSpriteBuffer(); + + // * + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster); + RwV3d pos = { 100.0f, 0.0f, 10.0f }; + RwV3dAdd(&worldpos, &campos, &pos); + worldpos.y -= 90.0f; + if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){ + brightness *= (CGeneral::GetRandomNumber()&127) / 640.0f + 0.5f; + CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z, + szx*5.0f, szy*5.0f, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255); + } + } + + // Low clouds + static float LowCloudsX[12] = { 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f, + 0.0f, 0.7f, 0.8f, -0.8f, 0.4f, -0.4f }; + static float LowCloudsY[12] = { 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, + 1.0f, 0.7f, 0.4f, 0.4f, -0.8f, -0.8f }; + static float LowCloudsZ[12] = { 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f, + 0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f }; + float lowcloudintensity = 1.0f - coverage; + int r = CTimeCycle::GetLowCloudsRed() * lowcloudintensity; + int g = CTimeCycle::GetLowCloudsGreen() * lowcloudintensity; + int b = CTimeCycle::GetLowCloudsBlue() * lowcloudintensity; + for(int cloudtype = 0; cloudtype < 3; cloudtype++){ + for(i = cloudtype; i < 12; i += 3){ + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[cloudtype]->raster); + RwV3d pos = { 800.0f*LowCloudsX[i], 800.0f*LowCloudsY[i], 60.0f*LowCloudsZ[i] }; + worldpos.x = campos.x + pos.x; + worldpos.y = campos.y + pos.y; + worldpos.z = 40.0f + pos.z; + if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)) + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(screenpos.x, screenpos.y, screenpos.z, + szx*320.0f, szy*40.0f, r, g, b, 255, 1.0f/screenpos.z, ms_cameraRoll, 255); + } + CSprite::FlushSpriteBuffer(); + } + + // Fluffy clouds + float rot_sin = sin(CloudRotation); + float rot_cos = cos(CloudRotation); + int fluffyalpha = 160 * (1.0f - CWeather::Foggyness); + if(fluffyalpha != 0){ + static float CoorsOffsetX[37] = { + 0.0f, 60.0f, 72.0f, 48.0f, 21.0f, 12.0f, + 9.0f, -3.0f, -8.4f, -18.0f, -15.0f, -36.0f, + -40.0f, -48.0f, -60.0f, -24.0f, 100.0f, 100.0f, + 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, + 100.0f, 100.0f, -30.0f, -20.0f, 10.0f, 30.0f, + 0.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f + }; + static float CoorsOffsetY[37] = { + 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, + 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, + 100.0f, 100.0f, 100.0f, 100.0f, -30.0f, 10.0f, + -25.0f, -5.0f, 28.0f, -10.0f, 10.0f, 0.0f, + 15.0f, 40.0f, -100.0f, -100.0f, -100.0f, -100.0f, + -100.0f, -40.0f, -20.0f, 0.0f, 10.0f, 30.0f, 35.0f + }; + static float CoorsOffsetZ[37] = { + 2.0f, 1.0f, 0.0f, 0.3f, 0.7f, 1.4f, + 1.7f, 0.24f, 0.7f, 1.3f, 1.6f, 1.0f, + 1.2f, 0.3f, 0.7f, 1.4f, 0.0f, 0.1f, + 0.5f, 0.4f, 0.55f, 0.75f, 1.0f, 1.4f, + 1.7f, 2.0f, 2.0f, 2.3f, 1.9f, 2.4f, + 2.0f, 2.0f, 1.5f, 1.2f, 1.7f, 1.5f, 2.1f + }; + static bool bCloudOnScreen[37]; + float hilight; + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[4]->raster); + for(i = 0; i < 37; i++){ + RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f }; + worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x; + worldpos.y = pos.x*rot_sin - pos.y*rot_cos + campos.y; + worldpos.z = pos.z; + + if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){ + float sundist = sqrt(sq(screenpos.x-CCoronas::SunScreenX) + sq(screenpos.y-CCoronas::SunScreenY)); + int tr = CTimeCycle::GetFluffyCloudsTopRed(); + int tg = CTimeCycle::GetFluffyCloudsTopGreen(); + int tb = CTimeCycle::GetFluffyCloudsTopBlue(); + int br = CTimeCycle::GetFluffyCloudsBottomRed(); + int bg = CTimeCycle::GetFluffyCloudsBottomGreen(); + int bb = CTimeCycle::GetFluffyCloudsBottomBlue(); + if(sundist < SCREENW/2){ + hilight = (1.0f - coverage) * (1.0f - sundist/(SCREENW/2)); + tr = tr*(1.0f-hilight) + 255*hilight; + tg = tg*(1.0f-hilight) + 190*hilight; + tb = tb*(1.0f-hilight) + 190*hilight; + br = br*(1.0f-hilight) + 255*hilight; + bg = bg*(1.0f-hilight) + 190*hilight; + bb = bb*(1.0f-hilight) + 190*hilight; + if(sundist < SCREENW/10) + CCoronas::SunBlockedByClouds = true; + }else + hilight = 0.0f; + CSprite::RenderBufferedOneXLUSprite_Rota