y_areas.inc 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700
  1. #if defined _INC_y_areas
  2. #endinput
  3. #endif
  4. #define _INC_y_areas
  5. /**
  6. * <library name="y_areas">
  7. * <section>
  8. * Description
  9. * </section>
  10. * Handles area checks for player location based code not involving CPs.
  11. * <section>
  12. * Version
  13. * </section>
  14. * 0.3
  15. * <section>
  16. * Functions
  17. * </section>
  18. * <subsection>
  19. * Public
  20. * </subsection><ul>
  21. * <symbol name="Area_Loop">Main loop for checking who's where.</symbol>
  22. * <symbol name="Area_Remote">Does minor functions remotely.</symbol>
  23. * <symbol name="Area_AddRemote">Adds areas remotely.</symbol>
  24. * <symbol name="YSIM_Areas">Master system interface.</symbol>
  25. * <symbol name="Area_Broadcast">Recieves transmitted areas.</symbol>
  26. * <symbol name="Area_UpdateEmpty">Resets the empty array after master change.</symbol>
  27. * </ul><subsection>
  28. * Core
  29. * </subsection><ul>
  30. * <symbol name="Area_Area">Constructor.</symbol>
  31. * <symbol name="Area_CheckArea">Gets an area's type anx calls the relevant function.</symbol>
  32. * <symbol name="Area_OnPlayerConnect">Called when a player connects.</symbol>
  33. * </ul><subsection>
  34. * Stock
  35. * </subsection><ul>
  36. * <symbol name="Area_Delete">Deletes an area.</symbol>
  37. * <symbol name="Area_AddCube">Adds a cube.</symbol>
  38. * <symbol name="Area_AddBox">Adds a box.</symbol>
  39. * <symbol name="Area_AddCircle">Adds a circle.</symbol>
  40. * <symbol name="Area_AddSphere">Adds a sphere.</symbol>
  41. * <symbol name="Area_AddPoly">Adds a polygon.</symbol>
  42. * <symbol name="Area_GetPlayerArea">Gets the area a player is in.</symbol>
  43. * <symbol name="Area_SetPlayer">Sets wether a player can use this area.</symbol>
  44. * <symbol name="Area_SetAllPlayers">Sets wether all players can use this area.</symbol>
  45. * <symbol name="Area_SetAllWorlds">Sets wether all worlds have this are.</symbol>
  46. * <symbol name="Area_SetWorld">Sets wether this world has this area.</symbol>
  47. * <symbol name="Area_IsValid">Checks if an area is valid.</symbol>
  48. * </ul><subsection>
  49. * Static
  50. * </subsection><ul>
  51. * <symbol name="Area_IsInCircle">Checks if a player is in this circular area.</symbol>
  52. * <symbol name="Area_IsInSphere">Checks if a player is in this spherical area.</symbol>
  53. * <symbol name="Area_IsInPoly">Checks if a player is in this polygonal area.</symbol>
  54. * <symbol name="Area_IsInCube">Checks if a player is in this cubic area.</symbol>
  55. * <symbol name="Area_IsInBox">Checks if a player is in this rectangular area.</symbol>
  56. * <symbol name="Area_AddToUnused">Adds a area pointer to the unused list.</symbol>
  57. * <symbol name="Area_GetFreeSlot">Gets the next free area slot.</symbol>
  58. * </ul><subsection>
  59. * Inline
  60. * </subsection><ul>
  61. * <symbol name="Area_IsActive">Checks if an area is active.</symbol>
  62. * <symbol name="Area_GetEmptySlotCount">Gets the number of empty slots.</symbol>
  63. * <symbol name="Area_AddSlots">Removes slots from the unused count.</symbol>
  64. * </ul><section>
  65. * Callbacks
  66. * </section><ul>
  67. * <symbol name="OnPlayerEnterArea">Called when a player enters an area.</symbol>
  68. * <symbol name="OnPlayerLeaveArea">Called when a player leaves an area.</symbol>
  69. * </ul><section>
  70. * Definitions
  71. * </section><ul>
  72. * <symbol name="MAX_AREAS">Max number of areas.</symbol>
  73. * <symbol name="NO_AREA">Fail return.</symbol>
  74. * <symbol name="AREA_NO_NEXT">Marker for end of a list.</symbol>
  75. * <symbol name="AREA_WORLDS">Number of worlds an area can be in.</symbol>
  76. * <symbol name="AREA_WORLD_COUNT">Number of cells required for a bit array of AREA_WORLDS.</symbol>
  77. * </ul><section>
  78. * Enums
  79. * </section><ul>
  80. * <symbol name="e_AREA_FLAGS">Flags for each area.</symbol>
  81. * <symbol name="E_AREA">Structure for part of an areas data.</symbol>
  82. * </ul><section>
  83. * Variables
  84. * </section>
  85. * <subsection>
  86. * Static
  87. * </subsection><ul>
  88. * <symbol name="YSI_g_sUnusedAreas">Pointer to the first unused area.</symbol>
  89. * <symbol name="YSI_g_sLastUnused">Pointer to the last unused area.</symbol>
  90. * <symbol name="YSI_g_sFreeCount">Number of unused slots.</symbol>
  91. * <symbol name="YSI_g_sAreas">Array of area data.</symbol>
  92. * <symbol name="YSI_g_sPlayerArea">Array of players' current areas.</symbol>
  93. * </ul>
  94. * </library>
  95. *//** *//*
  96. Legal:
  97. Version: MPL 1.1
  98. The contents of this file are subject to the Mozilla Public License Version
  99. 1.1 the "License"; you may not use this file except in compliance with
  100. the License. You may obtain a copy of the License at
  101. http://www.mozilla.org/MPL/
  102. Software distributed under the License is distributed on an "AS IS" basis,
  103. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  104. for the specific language governing rights and limitations under the
  105. License.
  106. The Original Code is the YSI framework.
  107. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  108. Portions created by the Initial Developer are Copyright C 2011
  109. the Initial Developer. All Rights Reserved.
  110. Contributors:
  111. Y_Less
  112. koolk
  113. JoeBullet/Google63
  114. g_aSlice/Slice
  115. Misiur
  116. samphunter
  117. tianmeta
  118. maddinat0r
  119. spacemud
  120. Crayder
  121. Dayvison
  122. Ahmad45123
  123. Zeex
  124. irinel1996
  125. Yiin-
  126. Chaprnks
  127. Konstantinos
  128. Masterchen09
  129. Southclaws
  130. PatchwerkQWER
  131. m0k1
  132. paulommu
  133. udan111
  134. Thanks:
  135. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  136. ZeeX - Very productive conversations.
  137. koolk - IsPlayerinAreaEx code.
  138. TheAlpha - Danish translation.
  139. breadfish - German translation.
  140. Fireburn - Dutch translation.
  141. yom - French translation.
  142. 50p - Polish translation.
  143. Zamaroht - Spanish translation.
  144. Los - Portuguese translation.
  145. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  146. me to strive to better.
  147. Pixels^ - Running XScripters where the idea was born.
  148. Matite - Pestering me to release it and using it.
  149. Very special thanks to:
  150. Thiadmer - PAWN, whose limits continue to amaze me!
  151. Kye/Kalcor - SA:MP.
  152. SA:MP Team past, present and future - SA:MP.
  153. Optional plugins:
  154. Gamer_Z - GPS.
  155. Incognito - Streamer.
  156. Me - sscanf2, fixes2, Whirlpool.
  157. */
  158. #include "..\YSI_Internal\y_compilerdata"
  159. #include "..\YSI_Internal\y_version"
  160. #include "..\YSI_Data\y_bit"
  161. #include "..\YSI_Data\y_playerarray"
  162. #include "..\YSI_Data\y_iterate"
  163. #include "..\YSI_Core\y_debug"
  164. #include "..\YSI_Coding\y_inline"
  165. #include "..\YSI_Coding\y_remote"
  166. #if defined AREAS_USE_TIMER
  167. #include "..\YSI_Coding\y_timers"
  168. #endif
  169. #include "..\YSI_Internal\y_natives"
  170. #if !defined MAX_AREAS
  171. #define MAX_AREAS (1024)
  172. // Now supports as many as you want (pretty much), and in a VASTLY better way!
  173. #elseif MAX_AREAS >= 0x3FFFF
  174. #error This version does not support more than 262142 areas.
  175. #endif
  176. // Set commands as master 25.
  177. #define YSIM_U_DISABLE
  178. #define MASTER 62
  179. #include "..\YSI_Core\y_master"
  180. #define _GROUP_MAKE_NAME<%0...%1> %0Area%1
  181. #define _GROUP_MAKE_LIMIT MAX_AREAS
  182. #include "..\YSI_Players\y_groups\_funcs"
  183. #include "..\YSI_Coding\y_hooks"
  184. stock _YSI_HAS_y_areas(_do_not_call_me_ever_, _like_never_)
  185. {
  186. P:E("You called _YSI_HAS_y_areas! Bad, don't do that!", _do_not_call_me_ever_, _like_never_);
  187. assert(false);
  188. return 0;
  189. }
  190. #define NO_AREA (-1)
  191. //#define SINGLE_SLOT_AREA (e_AREA_FLAGS_NEXT)
  192. #define AREA_NO_NEXT (_:e_AREA_FLAGS_NEXT)
  193. // This will divide the world up in to 400 blocks, the fact that 400=400 is
  194. // PURE fluke. Setting this to 500 would result in 256 blocks:
  195. //
  196. // ((AREAS_ZONE_BOUNDS / AREAS_ZONE_SIZE) ** 2) * 4
  197. //
  198. #if !defined AREAS_ZONE_SIZE
  199. #define AREAS_ZONE_SIZE 400
  200. #endif
  201. #if !defined AREAS_ZONE_BOUNDS
  202. #define AREAS_ZONE_BOUNDS 4000
  203. #endif
  204. // You can of course have more, but if you do have more the extras will be dealt
  205. // with separately. I can see three happening sometimes, but not often. More
  206. // than that will probably be very rare, and less will be more common, so we can
  207. // use the third slot usually to store the "NO_AREA" terminator.
  208. #if !defined AREAS_MAX_OVERLAPS
  209. #define AREAS_MAX_OVERLAPS (3)
  210. #endif
  211. #define AREAS_ZONE_ARRAY (ceildiv(AREAS_ZONE_BOUNDS * 2, AREAS_ZONE_SIZE))
  212. #if !defined AREA_WORLDS
  213. #define AREA_WORLDS 256
  214. #endif
  215. #define AREAS_ZONE_PARTS (ceildiv(AREAS_ZONE_BOUNDS, AREAS_ZONE_SIZE))
  216. #define Area_MakeZone(%0) (floatround((%0) / AREAS_ZONE_SIZE.0, floatround_floor)) // - AREAS_ZONE_PARTS)
  217. #define _AREAS_ADD_TO_ZONE(%0,%1,%2,%3) YSI_g_sAreas[%2][E_AREA_FLAGS]=(YSI_g_sAreas[%2][E_AREA_FLAGS]&e_AREA_FLAGS_REST)|(e_AREA_FLAGS:%0&e_AREA_FLAGS_NEXT|e_AREA_FLAGS:(%3<<18)&e_AREA_FLAGS_ZONE),%0=%1
  218. //#define _AREAS_ZONES_O(%0) return e_AREA_ZONE_O_%0
  219. //#define _AREAS_ZONES_I(%0) return e_AREA_ZONE_I_%0
  220. //#define _AREAS_ZONES_X(%0) return e_AREA_ZONE_X_%0
  221. #define _AREAS_ZONES_O(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneO%0,area,last,e_AREA_ZONE_O_%0)
  222. #define _AREAS_ZONES_I(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneI%0,area,last,e_AREA_ZONE_I_%0)
  223. #define _AREAS_ZONES_X(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneX%0,area,last,e_AREA_ZONE_X_%0)
  224. #define _AREAS_ZONES_I_GRID zx=1// zx=Area_MakeZone(minx);zy=Area_MakeZone(miny);if(zx==Area_MakeZone(maxx)&&zy==Area_MakeZone(maxy))return _AREAS_MAKE_ZONE(zx,zy),_AREAS_ADD_TO_ZONE(YSI_g_sZones[zy],area,last,zy)
  225. #define _AREAS_MAKE_ZONE(%0,%1) %1+=((%0)+AREAS_ZONE_PARTS)*AREAS_ZONE_ARRAY+AREAS_ZONE_PARTS
  226. //#define _AREA_DO_ALL(%0) sCur=%0;while(sCur!=AREA_NO_NEXT)if(Area_CheckArea(playerid,sW,sCur,sX,sY,sZ))return Area_DoEnter(playerid,(YSI_g_sPlayerArea[playerid]=sCur))
  227. #define _AREA_DO_ALL(%0) sNext=%0;while((sCur=sNext)!=AREA_NO_NEXT)if(Area_CheckArea(playerid,sW,sCur,sX,sY,sZ,sNext,sAreas,sAlready))Area_DoEnter(playerid,sCur,in)
  228. /*#define _AREA_DO_ALL(%0)
  229. sCur = zone;
  230. while (sCur != AREA_NO_NEXT)
  231. if (Area_CheckArea(playerid, sW, sCur, sX, sY, sZ))
  232. return Area_DoEnter(playerid, (YSI_g_sPlayerArea[playerid] = sCur));
  233. */
  234. #define _AREAS_DO_REMOVE(%0,%1,%2) new __z=-1,__y=%0;while(__y!=%1)__z=__y,__y=_:(YSI_g_sAreas[__z][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);return ((__z==-1)?(%0=%2):(_:(YSI_g_sAreas[__z][E_AREA_FLAGS]=YSI_g_sAreas[__z][E_AREA_FLAGS]&e_AREA_FLAGS_I_NEXT|(e_AREA_FLAGS:%2&e_AREA_FLAGS_NEXT))))
  235. enum e_AREA_FLAGS
  236. {
  237. // These aren't used any more either, they get encoded in the "POS" array
  238. // (sort of) with polys.
  239. //e_AREA_FLAGS_NEXT = 0x2000 - 1 << 0, //0x00001FFF,
  240. e_AREA_FLAGS_NEXT = 0x0003FFFF,
  241. //e_AREA_FLAGS_ZONE = 1023 << 18, //0x0FFC0000,
  242. e_AREA_FLAGS_ZONE = 0x0FFC0000,
  243. e_AREA_FLAGS_I_NEXT = ~(e_AREA_FLAGS_NEXT),
  244. e_AREA_FLAGS_REST = ~(e_AREA_FLAGS_NEXT | e_AREA_FLAGS_ZONE),
  245. //e_AREA_FLAGS_TYPE = 0x38000000,
  246. e_AREA_FLAGS_SPHERE = 1 << 28, //0x08000000,
  247. e_AREA_FLAGS_POLY = 2 << 28, //0x10000000,
  248. e_AREA_FLAGS_CUBE = 3 << 28, //0x18000000,
  249. //e_AREA_FLAGS_BOX = 4 << 28, //0x20000000,
  250. e_AREA_FLAGS_OVOID = 4 << 28, //0x08000000,
  251. e_AREA_FLAGS_OVAL = 5 << 28, //0x28000000,
  252. // The reserved type is now in use as a poly area child.
  253. //e_AREA_FLAGS_RES_0 = 6 << 28, //0x28000000,
  254. e_AREA_FLAGS_CHILD = 6 << 28, //0x30000000,
  255. e_AREA_FLAGS_CIRCLE = 7 << 28, //0x30000000,
  256. // Type mask.
  257. e_AREA_FLAGS_UNUSED = 0b000 << 28, //0x00000000,
  258. e_AREA_FLAGS_TYPE = 0b111 << 28, //0x38000000,
  259. // The "USED" flag isn't really needed any more, it's encoded in the type.
  260. // It seems the "used" flag was never read anyway...
  261. e_AREA_FLAGS_ACTIVE = 1 << 31,
  262. //e_AREA_FLAGS_USED = 1 << 31
  263. // If this is true AND AREA_VERY_FAST is on, the bounds check is identical
  264. // to the sphere check, so only do one.
  265. //e_AREA_FLAGS_BOUNDS = 1 << 31
  266. //e_AREA_FLAGS_SPHERE = 1 << 31
  267. }
  268. // Go backwards, so these all have the upper bit set.
  269. enum (+= -1)
  270. {
  271. e_AREA_ZONE_I_N = -1,
  272. e_AREA_ZONE_I_NE, // -2
  273. e_AREA_ZONE_I_E, // -3
  274. e_AREA_ZONE_I_SE, // -4
  275. e_AREA_ZONE_I_S, // -5
  276. e_AREA_ZONE_I_SW, // -6
  277. e_AREA_ZONE_I_W, // -7
  278. e_AREA_ZONE_I_NW, // -8
  279. e_AREA_ZONE_I_, // -9
  280. // "Outer" zones. -4000 > x, y > 4000;
  281. e_AREA_ZONE_O_N, // -10
  282. e_AREA_ZONE_O_NE, // -11
  283. e_AREA_ZONE_O_E, // -12
  284. e_AREA_ZONE_O_SE, // -13
  285. e_AREA_ZONE_O_S, // -14
  286. e_AREA_ZONE_O_SW, // -15
  287. e_AREA_ZONE_O_W, // -16
  288. e_AREA_ZONE_O_NW, // -17
  289. //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
  290. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  291. e_AREA_ZONE_X_N, // -18
  292. e_AREA_ZONE_X_NE, // -19
  293. e_AREA_ZONE_X_E, // -20
  294. e_AREA_ZONE_X_SE, // -21
  295. e_AREA_ZONE_X_S, // -22
  296. e_AREA_ZONE_X_SW, // -23
  297. e_AREA_ZONE_X_W, // -24
  298. e_AREA_ZONE_X_NW, // -25
  299. // Extra zones. For when areas are too big for a quadrant.
  300. e_AREA_ZONE_X_, // -26
  301. e_AREA_ZONE_NONE = cellmin
  302. }
  303. // =============================================================================
  304. // =============================================================================
  305. // IMPORTANT NOTE: The order of elements in this enum is INCREDIBLY important.
  306. // Because this is three enums in one, they share some pieces of data that must
  307. // not get overridden.
  308. // =============================================================================
  309. // =============================================================================
  310. // This might just be the most complex enum I've ever made!
  311. enum E_AREA
  312. {
  313. //union
  314. //{
  315. // struct
  316. // {
  317. #if YSIM_HAS_MASTER
  318. E_AREA_MASTER,
  319. #endif
  320. // This has increased from 4 to 6, so we can store cubes and ovoids
  321. // in a single slot.
  322. Float:E_AREA_POS[6],
  323. PlayerArray:E_AREA_PLAYERS<MAX_PLAYERS>,
  324. // This MUST go between "E_AREA_PLAYERS" and "E_AREA_FLAGS" to
  325. // remain constant in subsequent unions.
  326. //#if defined AREA_VERY_FAST
  327. // Float:E_AREA_BOUNDING[4],
  328. //#endif
  329. // As must this.
  330. #if AREA_WORLDS > 0
  331. BitArray:E_AREA_WORLDS<AREA_WORLDS>,
  332. #endif
  333. // ALWAYS last (actually used by EVERY type).
  334. e_AREA_FLAGS:E_AREA_FLAGS,
  335. // }
  336. // // Start of poly data.
  337. // struct
  338. // {
  339. // Reset the enum counter to 0 (on the next item).
  340. _E_AREA_RESET_@1 = -1,
  341. // Now restart.
  342. #if YSIM_HAS_MASTER
  343. // Skip the master flag if it exists.
  344. _E_AREA_MASTER_@1,
  345. #endif
  346. // This is where polys differ from all others.
  347. E_AREA_POLY_COUNT,
  348. E_AREA_POLY_NEXT,
  349. //Float:E_AREA_POLY_POS[4],
  350. // This slot holds ONLY the polygon bounding data, it doesn't hold
  351. // any co-ordinates AT ALL.
  352. //Float:E_AREA_BOUNDING[4],
  353. Float:E_AREA_POLY_BOUND_X,
  354. Float:E_AREA_POLY_BOUND_Y,
  355. Float:E_AREA_POLY_BOUND_R,
  356. Float:E_AREA_POLY_BOUND_H,
  357. // Skip all the array and flag data, they stay the same.
  358. _E_AREA_ARRAYS_@1[E_AREA_FLAGS - E_AREA_PLAYERS],
  359. // Skip the flags.
  360. E_AREA_UNUSED_NEXT,
  361. // }
  362. // // Start of poly child data.
  363. // struct
  364. // {
  365. // Reset the enum counter to 0 (on the next item).
  366. _E_AREA_RESET_@2 = -1,
  367. // Now restart.
  368. #if YSIM_HAS_MASTER
  369. // Skip the master flag if it exists.
  370. _E_AREA_MASTER_@2,
  371. #endif
  372. // Store a link to the parent of this poly child.
  373. E_AREA_CHILD_PARENT,
  374. // And the next one in VERY rare cases (I hope).
  375. // THIS SHARES A SLOT WITH "E_AREA_POLY_NEXT", so we can always just
  376. // use that slot when iterating.
  377. #if _:(E_AREA_FLAGS - E_AREA_CHILD_PARENT) & 1
  378. // There are an ODD number of available slots. We can store an
  379. // extra pair iff we don't need to use "NEXT".
  380. //_E_AREA_SKIP_@2,
  381. E_AREA_CHILD_OPT_Y,
  382. #endif
  383. E_AREA_CHILD_OPT_X,
  384. // Just store a vast number of X/Y pairs in this child.
  385. Float:E_AREA_CHILD_ELEMS[_:E_AREA_FLAGS - _:E_AREA_CHILD_OPT_X - 1],
  386. // Skip the flags.
  387. _E_AREA_CHILD_ELEMS_END
  388. // }
  389. }
  390. #define CHILD_AREA_SLOTS ((_:_E_AREA_CHILD_ELEMS_END - _:E_AREA_CHILD_ELEMS))
  391. static stock
  392. YSI_g_sUnusedAreas = 0,
  393. //YSI_g_sLastUnused = MAX_AREAS - 1,
  394. YSI_g_sFreeCount = MAX_AREAS,
  395. YSI_g_sAreas[MAX_AREAS][E_AREA],
  396. YSI_g_sPlayerArea[MAX_PLAYERS][AREAS_MAX_OVERLAPS], // = {NO_AREA, ...},
  397. YSI_g_sHasCallbacks,
  398. YSI_g_sZones[AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY] = {AREA_NO_NEXT, ...},
  399. // "Inner" zones. -4000 <= x, y <= 4000; Z(x) != Z(y)
  400. YSI_g_sZoneIN = AREA_NO_NEXT, // -1
  401. YSI_g_sZoneINE = AREA_NO_NEXT, // -2
  402. YSI_g_sZoneIE = AREA_NO_NEXT, // -3
  403. YSI_g_sZoneISE = AREA_NO_NEXT, // -4
  404. YSI_g_sZoneIS = AREA_NO_NEXT, // -5
  405. YSI_g_sZoneISW = AREA_NO_NEXT, // -6
  406. YSI_g_sZoneIW = AREA_NO_NEXT, // -7
  407. YSI_g_sZoneINW = AREA_NO_NEXT, // -8
  408. // "Outer" zones. -4000 > x, y > 4000;
  409. YSI_g_sZoneON = AREA_NO_NEXT, // -9
  410. YSI_g_sZoneONE = AREA_NO_NEXT, // -10
  411. YSI_g_sZoneOE = AREA_NO_NEXT, // -11
  412. YSI_g_sZoneOSE = AREA_NO_NEXT, // -12
  413. YSI_g_sZoneOS = AREA_NO_NEXT, // -13
  414. YSI_g_sZoneOSW = AREA_NO_NEXT, // -14
  415. YSI_g_sZoneOW = AREA_NO_NEXT, // -15
  416. YSI_g_sZoneONW = AREA_NO_NEXT, // -16
  417. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  418. YSI_g_sZoneXN = AREA_NO_NEXT, // -17
  419. YSI_g_sZoneXNE = AREA_NO_NEXT, // -18
  420. YSI_g_sZoneXE = AREA_NO_NEXT, // -19
  421. YSI_g_sZoneXSE = AREA_NO_NEXT, // -20
  422. YSI_g_sZoneXS = AREA_NO_NEXT, // -21
  423. YSI_g_sZoneXSW = AREA_NO_NEXT, // -22
  424. YSI_g_sZoneXW = AREA_NO_NEXT, // -23
  425. YSI_g_sZoneXNW = AREA_NO_NEXT, // -24
  426. // Extra zones. For when areas are too big for a quadrant.
  427. YSI_g_sZoneI = AREA_NO_NEXT, // -25
  428. //YSI_g_sZoneO = AREA_NO_NEXT, // -26
  429. YSI_g_sZoneX = AREA_NO_NEXT; // -27
  430. forward Area_Loop();
  431. /*-------------------------------------------------------------------------*//**
  432. * <remarks>
  433. * Sets up required variables. Note that this hooks "OnScriptInit",
  434. * "OnGameModeInit" and "OnFilterScript". This is because ALL scripts need to
  435. * initialise some things, and only the master needs to initialise others.
  436. * </remarks>
  437. *//*------------------------------------------------------------------------**/
  438. mhook OnScriptInit()
  439. {
  440. for (new i = 0; i != MAX_AREAS - 1; ++i)
  441. {
  442. YSI_g_sAreas[i][E_AREA_UNUSED_NEXT] = (i + 1);
  443. }
  444. YSI_g_sAreas[MAX_AREAS - 1][E_AREA_UNUSED_NEXT] = AREA_NO_NEXT;
  445. //for (new i = 0; i != AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY; ++i)
  446. //{
  447. // YSI_g_sZones[i] = -1;
  448. //}
  449. return 1;
  450. }
  451. #if !defined FILTERSCRIPT
  452. hook OnGameModeInit()
  453. {
  454. if (!YSI_FILTERSCRIPT)
  455. {
  456. new
  457. buffer;
  458. YSI_g_sHasCallbacks = 0;
  459. YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
  460. YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
  461. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
  462. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
  463. }
  464. }
  465. #endif
  466. hook OnFilterScriptInit()
  467. {
  468. new
  469. buffer;
  470. YSI_g_sHasCallbacks = 0;
  471. YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
  472. YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
  473. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
  474. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
  475. }
  476. /*-------------------------------------------------------------------------*//**
  477. * <returns>
  478. * Number of unused area slots.
  479. * </returns>
  480. *//*------------------------------------------------------------------------**/
  481. P:D(Area_GetEmptySlotCount());
  482. #define Area_GetEmptySlotCount() \
  483. (YSI_g_sFreeCount)
  484. /*-------------------------------------------------------------------------*//**
  485. * <param name="num">Number of slots to add.</param>
  486. * <remarks>
  487. * Actually removes slots from the unused count.
  488. * </remarks>
  489. *//*------------------------------------------------------------------------**/
  490. P:D(Area_AddSlots(num));
  491. #define Area_AddSlots(%1) \
  492. YSI_g_sFreeCount -= (%1)
  493. /*-------------------------------------------------------------------------*//**
  494. * <param name="area">Area to check validity of</param>
  495. * <remarks>
  496. * An area slot could be used but still invalid if it's not the first slot in
  497. * an area set.
  498. * </remarks>
  499. *//*------------------------------------------------------------------------**/
  500. P:D(bool:Area_IsActive(area));
  501. #define Area_IsActive(%1) \
  502. ((%1) >= 0 && (%1) < MAX_AREAS && (YSI_g_sAreas[(%1)][E_AREA_FLAGS] & e_AREA_FLAGS_ACTIVE))
  503. /*-------------------------------------------------------------------------*//**
  504. * <param name="area">Area to print information about.</param>
  505. *//*------------------------------------------------------------------------**/
  506. foreign void:Area_Debug(area);
  507. global void:Area_Debug(area)
  508. {
  509. new
  510. e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
  511. if ((flags & e_AREA_FLAGS_ACTIVE))
  512. {
  513. switch (flags & e_AREA_FLAGS_TYPE)
  514. {
  515. case e_AREA_FLAGS_POLY:
  516. {
  517. new
  518. count = YSI_g_sAreas[area][E_AREA_POLY_COUNT];
  519. printf("Poly Area %d:", area);
  520. printf("\tPoints = %d", count);
  521. printf("\tNext = %d", YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] & AREA_NO_NEXT);
  522. #if AREA_WORLDS > 0
  523. printf("\tWorlds = %s", Bit_Display(YSI_g_sAreas[area][E_AREA_WORLDS], bits<AREA_WORLDS>));
  524. #else
  525. printf("\tNo Worlds");
  526. #endif
  527. printf("\tPlayers = %s", Bit_Display(YSI_g_sAreas[area][E_AREA_PLAYERS][1], bits<MAX_PLAYERS>));
  528. printf("\tBounding Circle: %.2f, %.2f, %.2f, %.2f", YSI_g_sAreas[area][E_AREA_POLY_BOUND_X], YSI_g_sAreas[area][E_AREA_POLY_BOUND_Y], floatsqroot(YSI_g_sAreas[area][E_AREA_POLY_BOUND_R]), YSI_g_sAreas[area][E_AREA_POLY_BOUND_H]);
  529. new
  530. next = YSI_g_sAreas[area][E_AREA_POLY_NEXT];
  531. while (count > 0)
  532. {
  533. printf("\tPoints Set %d:", next);
  534. for (new i = 0, j = min(count, CHILD_AREA_SLOTS); i < j; i += 2)
  535. {
  536. printf("\t\t(%.2f, %.2f)", YSI_g_sAreas[next][E_AREA_CHILD_ELEMS][i], YSI_g_sAreas[next][E_AREA_CHILD_ELEMS][i + 1]);
  537. }
  538. next = YSI_g_sAreas[next][E_AREA_POLY_NEXT];
  539. count -= CHILD_AREA_SLOTS;
  540. }
  541. }
  542. }
  543. //return 1;
  544. }
  545. //return 0;
  546. }
  547. /*-------------------------------------------------------------------------*//**
  548. * <returns>
  549. * Next available slot.
  550. * </returns>
  551. * <remarks>
  552. * Gets an empty slot, removes it from the unused list and returs a pointer.
  553. * </remarks>
  554. *//*------------------------------------------------------------------------**/
  555. static stock Area_GetFreeSlot()
  556. {
  557. P:4("Area_GetFreeSlot called");
  558. if (YSI_g_sUnusedAreas == AREA_NO_NEXT) return NO_AREA;
  559. P:7("Area_GetFreeSlot: 1");
  560. new
  561. old = YSI_g_sUnusedAreas;
  562. YSI_g_sUnusedAreas = YSI_g_sAreas[old][E_AREA_UNUSED_NEXT];
  563. --YSI_g_sFreeCount;
  564. return old;
  565. }
  566. /*-------------------------------------------------------------------------*//**
  567. * <param name="area">Area to remove from the list.</param>
  568. * <remarks>
  569. * You can only remove areas which are at the start of a list.
  570. * </remarks>
  571. *//*------------------------------------------------------------------------**/
  572. foreign void:Area_Delete(area);
  573. global void:Area_Delete(area)
  574. {
  575. if (!Area_IsActive(area))
  576. {
  577. return; //0;
  578. }
  579. new
  580. e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
  581. switch (flags & e_AREA_FLAGS_TYPE)
  582. {
  583. case e_AREA_FLAGS_UNUSED:
  584. {
  585. return; //0;
  586. }
  587. case e_AREA_FLAGS_CHILD:
  588. {
  589. // This is just part of a poly, remove the whole thing.
  590. Area_Delete(YSI_g_sAreas[area][E_AREA_CHILD_PARENT]);
  591. }
  592. case e_AREA_FLAGS_POLY:
  593. {
  594. // Many blocks used - hard.
  595. new
  596. count = YSI_g_sAreas[area][E_AREA_POLY_COUNT],
  597. next = YSI_g_sAreas[area][E_AREA_POLY_NEXT],
  598. prev = YSI_g_sUnusedAreas;
  599. // All all of this poly area to the old area.
  600. while (count > 0)
  601. {
  602. // Increase the free count.
  603. ++YSI_g_sFreeCount;
  604. // Decrease the stored points.
  605. count -= CHILD_AREA_SLOTS;
  606. // Change the poly list to an unused list.
  607. YSI_g_sAreas[next][E_AREA_UNUSED_NEXT] = prev;
  608. prev = next;
  609. next = YSI_g_sAreas[next][E_AREA_POLY_NEXT];
  610. }
  611. // Remove the poly header.
  612. ++YSI_g_sFreeCount;
  613. YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] = prev;
  614. YSI_g_sUnusedAreas = area;
  615. }
  616. default:
  617. {
  618. // Only one block used - easy.
  619. YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] = YSI_g_sUnusedAreas;
  620. YSI_g_sUnusedAreas = area;
  621. ++YSI_g_sFreeCount;
  622. }
  623. }
  624. // Remove this one from the zone it was in.
  625. Area_DoRemove(_:(flags & e_AREA_FLAGS_ZONE), area, _:(flags & e_AREA_FLAGS_NEXT));
  626. //return 1;
  627. }
  628. /*-------------------------------------------------------------------------*//**
  629. * <param name="zone">The zone this area is in (right shifted 18).</param>
  630. * <param name="start">The first of the allocated areas being removed.</param>
  631. * <param name="end">The area in this zone after the last removed one.</param>
  632. * <remarks>
  633. * Very tightly integrated with "Area_Delete", to the point where I could just
  634. * make them one function if I wanted (but I won't).
  635. * </remarks>
  636. *//*------------------------------------------------------------------------**/
  637. static stock Area_DoRemove(zone, area, next)
  638. {
  639. //printf("remove %d %d %d %d", zone << 18, area, next, (e_AREA_ZONE_I_ << 18 & _:e_AREA_FLAGS_ZONE));
  640. // Actually "zone << 18", but that's not important.
  641. switch (zone)
  642. {
  643. case (e_AREA_ZONE_I_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIN, area, next);}
  644. case (e_AREA_ZONE_I_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneINE, area, next);}
  645. case (e_AREA_ZONE_I_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIE, area, next);}
  646. case (e_AREA_ZONE_I_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneISE, area, next);}
  647. case (e_AREA_ZONE_I_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIS, area, next);}
  648. case (e_AREA_ZONE_I_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneISW, area, next);}
  649. case (e_AREA_ZONE_I_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIW, area, next);}
  650. case (e_AREA_ZONE_I_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneINW, area, next);}
  651. case (e_AREA_ZONE_I_ << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneI, area, next);}
  652. // "Outer" zones. -4000 > x, y > 4000;
  653. case (e_AREA_ZONE_O_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneON, area, next);}
  654. case (e_AREA_ZONE_O_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneONE, area, next);}
  655. case (e_AREA_ZONE_O_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOE, area, next);}
  656. case (e_AREA_ZONE_O_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOSE, area, next);}
  657. case (e_AREA_ZONE_O_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOS, area, next);}
  658. case (e_AREA_ZONE_O_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOSW, area, next);}
  659. case (e_AREA_ZONE_O_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOW, area, next);}
  660. case (e_AREA_ZONE_O_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneONW, area, next);}
  661. //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
  662. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  663. case (e_AREA_ZONE_X_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXN, area, next);}
  664. case (e_AREA_ZONE_X_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXNE, area, next);}
  665. case (e_AREA_ZONE_X_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXE, area, next);}
  666. case (e_AREA_ZONE_X_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXSE, area, next);}
  667. case (e_AREA_ZONE_X_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXS, area, next);}
  668. case (e_AREA_ZONE_X_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXSW, area, next);}
  669. case (e_AREA_ZONE_X_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXW, area, next);}
  670. case (e_AREA_ZONE_X_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXNW, area, next);}
  671. // Extra zones. For when areas are too big for a quadrant.
  672. case (e_AREA_ZONE_X_ << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneX, area, next);}
  673. default: {_AREAS_DO_REMOVE(YSI_g_sZones[zone >> 18], area, next);}
  674. }
  675. return 0;
  676. }
  677. /*-------------------------------------------------------------------------*//**
  678. * <param name="x">Start of an area.</param>
  679. * <param name="y">Start of an area.</param>
  680. * <returns>
  681. * All the zones this position overlaps.
  682. * </returns>
  683. * <remarks>
  684. * The most zones you can be in at once is 9 - I_, I_S, I_E, I_SE, X_, X_S,
  685. * X_E, X_SE, Z_ (or similar corners - NOT in O_ though).
  686. * </remarks>
  687. *//*------------------------------------------------------------------------**/
  688. static stock Area_GetZones(Float:x, Float:y)
  689. {
  690. // Always end with e_AREA_ZONE_X_ as they will ALWAYS be in that one (that's
  691. // basically everywhere and means the area exists somewhere ever). Once
  692. // that zone is detected, stop next loop.
  693. static const
  694. scZones[16][9] =
  695. {
  696. {e_AREA_ZONE_O_N , e_AREA_ZONE_O_NE, e_AREA_ZONE_O_E , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  697. {e_AREA_ZONE_O_NE, e_AREA_ZONE_O_E , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  698. {e_AREA_ZONE_O_SE, e_AREA_ZONE_O_E , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  699. {e_AREA_ZONE_O_S , e_AREA_ZONE_O_SE, e_AREA_ZONE_O_E , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  700. {e_AREA_ZONE_O_N , e_AREA_ZONE_O_NE, e_AREA_ZONE_X_N , e_AREA_ZONE_X_NE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  701. {e_AREA_ZONE_NONE, e_AREA_ZONE_I_N , e_AREA_ZONE_I_NE, e_AREA_ZONE_I_E , e_AREA_ZONE_I_ , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ },
  702. {e_AREA_ZONE_NONE, e_AREA_ZONE_I_S , e_AREA_ZONE_I_SE, e_AREA_ZONE_I_E , e_AREA_ZONE_I_ , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ },
  703. {e_AREA_ZONE_O_S , e_AREA_ZONE_O_SE, e_AREA_ZONE_X_S , e_AREA_ZONE_X_SE, e_AREA_ZONE_X_E , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  704. {e_AREA_ZONE_O_N , e_AREA_ZONE_O_NW, e_AREA_ZONE_X_N , e_AREA_ZONE_X_NW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  705. {e_AREA_ZONE_NONE, e_AREA_ZONE_I_N , e_AREA_ZONE_I_NW, e_AREA_ZONE_I_W , e_AREA_ZONE_I_ , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ },
  706. {e_AREA_ZONE_NONE, e_AREA_ZONE_I_S , e_AREA_ZONE_I_SW, e_AREA_ZONE_I_W , e_AREA_ZONE_I_ , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ },
  707. {e_AREA_ZONE_O_S , e_AREA_ZONE_O_SW, e_AREA_ZONE_X_S , e_AREA_ZONE_X_SW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  708. {e_AREA_ZONE_O_N , e_AREA_ZONE_O_NW, e_AREA_ZONE_O_W , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  709. {e_AREA_ZONE_O_NW, e_AREA_ZONE_O_W , e_AREA_ZONE_X_N , e_AREA_ZONE_X_NW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  710. {e_AREA_ZONE_O_SW, e_AREA_ZONE_O_W , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE, e_AREA_ZONE_NONE},
  711. {e_AREA_ZONE_O_S , e_AREA_ZONE_O_SW, e_AREA_ZONE_O_W , e_AREA_ZONE_X_S , e_AREA_ZONE_X_SW, e_AREA_ZONE_X_W , e_AREA_ZONE_X_ , e_AREA_ZONE_NONE, e_AREA_ZONE_NONE}
  712. };
  713. if (AREAS_ZONE_BOUNDS.0 <= x)
  714. {
  715. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 0];
  716. else if (0.0 <= y) return scZones[ 1];
  717. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 2];
  718. else return scZones[ 3];
  719. }
  720. else if (0.0 <= x)
  721. {
  722. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 4];
  723. else if (0.0 <= y) return scZones[ 5]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  724. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 6]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  725. else return scZones[ 7];
  726. }
  727. else if (-AREAS_ZONE_BOUNDS.0 <= x)
  728. {
  729. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 8];
  730. else if (0.0 <= y) return scZones[ 9]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  731. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[10]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  732. else return scZones[11];
  733. }
  734. else
  735. {
  736. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[12];
  737. else if (0.0 <= y) return scZones[13];
  738. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[14];
  739. else return scZones[15];
  740. }
  741. }
  742. /*-------------------------------------------------------------------------*//**
  743. * <param name="minx">Start of an area.</param>
  744. * <param name="miny">Start of an area.</param>
  745. * <param name="maxx">End of an area.</param>
  746. * <param name="maxy">End of an area.</param>
  747. * <param name="area">The area to add to the determined zone.</param>
  748. * <param name="last">The last slot that makes up the current zone.</param>
  749. * <remarks>
  750. * Finds the smallest zone that this area will fit in completely. Note that
  751. * due to a limitation in the code, any zones with a node touching the upper
  752. * edge of a zone will spill in to the next zone too. Only lower zone edges
  753. * are inclusive.
  754. * </remarks>
  755. *//*------------------------------------------------------------------------**/
  756. static stock Area_DetermineZone(Float:minx, Float:miny, Float:maxx, Float:maxy, area, last)
  757. {
  758. new
  759. zx,
  760. zy;
  761. // This optimises based on the fact that (by definition) maxx can't be lower
  762. // than minx and maxy can't be lower than miny, meaning we can skip certain
  763. // checks in some cases.
  764. if (AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
  765. {
  766. if (0.0 <= miny) // Southern edge.
  767. {
  768. _AREAS_ZONES_O(NE);
  769. //YSI_g_sAreas[last][E_AREA_FLAGS]=(YSI_g_sAreas[last][E_AREA_FLAGS]&e_AREA_FLAGS_REST)|(e_AREA_FLAGS:YSI_g_sZoneXNE&e_AREA_FLAGS_NEXT|e_AREA_FLAGS(e_AREA_ZONE_X_NE<<18)&e_AREA_FLAGS_ZONE),YSI_g_sZoneXNE=area;
  770. //return _AREAS_ADD_TO_ZONE(YSI_g_sZoneXNE,area,last,e_AREA_ZONE_X_NE)
  771. }
  772. else // Southern edge.
  773. {
  774. if (0.0 <= maxy) // Northern edge.
  775. {
  776. _AREAS_ZONES_O(E);
  777. }
  778. else // Northern edge.
  779. {
  780. _AREAS_ZONES_O(SE);
  781. }
  782. }
  783. }
  784. else if (0.0 <= minx) // Western edge.
  785. {
  786. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  787. {
  788. _AREAS_ZONES_O(NE);
  789. }
  790. else if (0.0 <= miny) // Southern edge.
  791. {
  792. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  793. {
  794. _AREAS_ZONES_X(NE);
  795. }
  796. else // Eastern edge.
  797. {
  798. // Interesting case - y > 0, 0 <= x < 4000.
  799. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  800. {
  801. _AREAS_ZONES_X(NE);
  802. }
  803. else // Northern edge.
  804. {
  805. //_AREAS_ZONES_I_GRID;
  806. zx = Area_MakeZone(minx);
  807. zy = Area_MakeZone(miny);
  808. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  809. {
  810. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  811. YSI_g_sAreas[last][E_AREA_FLAGS] =
  812. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  813. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  814. (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
  815. P:7("Area_DetermineZone: Added to North-Eastern square");
  816. return YSI_g_sZones[zy] = area;
  817. }
  818. _AREAS_ZONES_I(NE);
  819. }
  820. }
  821. }
  822. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  823. {
  824. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  825. {
  826. if (0.0 <= maxy) // Northern edge.
  827. {
  828. _AREAS_ZONES_X(E);
  829. }
  830. else // Northern edge.
  831. {
  832. _AREAS_ZONES_X(SE);
  833. }
  834. }
  835. else // Eastern edge.
  836. {
  837. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  838. {
  839. _AREAS_ZONES_X(E);
  840. }
  841. if (0.0 <= maxy) // Northern edge.
  842. {
  843. _AREAS_ZONES_I(E);
  844. }
  845. else // Northern edge.
  846. {
  847. zx = Area_MakeZone(minx);
  848. zy = Area_MakeZone(miny);
  849. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  850. {
  851. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  852. YSI_g_sAreas[last][E_AREA_FLAGS] =
  853. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  854. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  855. (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
  856. return YSI_g_sZones[zy] = area;
  857. }
  858. _AREAS_ZONES_I(SE);
  859. }
  860. }
  861. }
  862. else // Southern edge.
  863. {
  864. if (0.0 <= maxy) // Northern edge.
  865. {
  866. _AREAS_ZONES_X(E);
  867. }
  868. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  869. {
  870. _AREAS_ZONES_X(SE);
  871. }
  872. else // Northern edge.
  873. {
  874. _AREAS_ZONES_O(SE);
  875. }
  876. }
  877. }
  878. else if (-AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
  879. {
  880. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  881. {
  882. if (0.0 <= maxx) // Eastern edge.
  883. {
  884. _AREAS_ZONES_O(N);
  885. }
  886. else // Eastern edge.
  887. {
  888. _AREAS_ZONES_O(NW);
  889. }
  890. }
  891. else if (0.0 <= miny) // Southern edge.
  892. {
  893. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  894. {
  895. _AREAS_ZONES_X(N);
  896. }
  897. else if (0.0 <= maxx) // Eastern edge.
  898. {
  899. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  900. {
  901. _AREAS_ZONES_X(N);
  902. }
  903. else // Northern edge.
  904. {
  905. _AREAS_ZONES_I(N);
  906. }
  907. }
  908. else // Eastern edge.
  909. {
  910. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  911. {
  912. _AREAS_ZONES_X(NW);
  913. }
  914. else // Northern edge.
  915. {
  916. zx = Area_MakeZone(minx);
  917. zy = Area_MakeZone(miny);
  918. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  919. {
  920. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  921. YSI_g_sAreas[last][E_AREA_FLAGS] =
  922. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  923. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  924. (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
  925. return YSI_g_sZones[zy] = area;
  926. }
  927. _AREAS_ZONES_I(NW);
  928. }
  929. }
  930. }
  931. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  932. {
  933. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  934. {
  935. if (0.0 <= maxy) // Northern edge.
  936. {
  937. _AREAS_ZONES_X();
  938. }
  939. else // Northern edge.
  940. {
  941. _AREAS_ZONES_X(S);
  942. }
  943. }
  944. else if (0.0 <= maxx) // Eastern edge.
  945. {
  946. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  947. {
  948. _AREAS_ZONES_X();
  949. }
  950. else if (0.0 <= maxy) // Northern edge.
  951. {
  952. _AREAS_ZONES_I();
  953. }
  954. else // Northern edge.
  955. {
  956. _AREAS_ZONES_I(S);
  957. }
  958. }
  959. else // Eastern edge.
  960. {
  961. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  962. {
  963. _AREAS_ZONES_X(W);
  964. }
  965. else if (0.0 <= maxy) // Northern edge.
  966. {
  967. _AREAS_ZONES_I(W);
  968. }
  969. else // Northern edge.
  970. {
  971. zx = Area_MakeZone(minx);
  972. zy = Area_MakeZone(miny);
  973. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  974. {
  975. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  976. YSI_g_sAreas[last][E_AREA_FLAGS] =
  977. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  978. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  979. (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
  980. return YSI_g_sZones[zy] = area;
  981. }
  982. _AREAS_ZONES_I(SW);
  983. }
  984. }
  985. }
  986. else // Southern edge.
  987. {
  988. if (0.0 <= maxx) // Eastern edge.
  989. {
  990. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  991. {
  992. _AREAS_ZONES_X(S);
  993. }
  994. else // Northern edge.
  995. {
  996. _AREAS_ZONES_O(S);
  997. }
  998. }
  999. else // Eastern edge.
  1000. {
  1001. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  1002. {
  1003. _AREAS_ZONES_X(SW);
  1004. }
  1005. else // Northern edge.
  1006. {
  1007. _AREAS_ZONES_O(SW);
  1008. }
  1009. }
  1010. }
  1011. }
  1012. else // Western edge.
  1013. {
  1014. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  1015. {
  1016. if (0.0 <= maxx) // Eastern edge.
  1017. {
  1018. _AREAS_ZONES_O(N);
  1019. }
  1020. else // Eastern edge.
  1021. {
  1022. // I missed this one and the compiler didn't complain about the
  1023. // path not returning - I think I confused it!
  1024. _AREAS_ZONES_O(NW);
  1025. }
  1026. }
  1027. else if (0.0 <= miny) // Southern edge.
  1028. {
  1029. if (0.0 <= maxx) // Eastern edge.
  1030. {
  1031. _AREAS_ZONES_X(N);
  1032. }
  1033. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  1034. {
  1035. _AREAS_ZONES_X(NW);
  1036. }
  1037. else // Eastern edge.
  1038. {
  1039. _AREAS_ZONES_O(NW);
  1040. }
  1041. }
  1042. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  1043. {
  1044. if (0.0 <= maxx) // Eastern edge.
  1045. {
  1046. if (0.0 <= maxy) // Northern edge.
  1047. {
  1048. _AREAS_ZONES_X();
  1049. }
  1050. else
  1051. {
  1052. _AREAS_ZONES_X(S);
  1053. }
  1054. }
  1055. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  1056. {
  1057. if (0.0 <= maxy) // Northern edge.
  1058. {
  1059. _AREAS_ZONES_X(W);
  1060. }
  1061. else // Northern edge.
  1062. {
  1063. _AREAS_ZONES_X(SW);
  1064. }
  1065. }
  1066. else // Eastern edge.
  1067. {
  1068. if (0.0 <= maxy) // Northern edge.
  1069. {
  1070. _AREAS_ZONES_O(W);
  1071. }
  1072. else // Northern edge.
  1073. {
  1074. _AREAS_ZONES_O(SW);
  1075. }
  1076. }
  1077. }
  1078. else // Southern edge.
  1079. {
  1080. if (0.0 <= maxx) // Eastern edge.
  1081. {
  1082. if (0.0 <= maxy) // Northern edge.
  1083. {
  1084. _AREAS_ZONES_X();
  1085. }
  1086. else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  1087. {
  1088. _AREAS_ZONES_X(S);
  1089. }
  1090. else // Northern edge.
  1091. {
  1092. _AREAS_ZONES_O(S);
  1093. }
  1094. }
  1095. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  1096. {
  1097. if (0.0 <= maxy) // Northern edge.
  1098. {
  1099. _AREAS_ZONES_X(W);
  1100. }
  1101. else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  1102. {
  1103. _AREAS_ZONES_X(SW);
  1104. }
  1105. else // Northern edge.
  1106. {
  1107. _AREAS_ZONES_O(SW);
  1108. }
  1109. }
  1110. else // Eastern edge.
  1111. {
  1112. if (0.0 <= maxy) // Northern edge.
  1113. {
  1114. _AREAS_ZONES_O(W);
  1115. }
  1116. else // Northern edge.
  1117. {
  1118. _AREAS_ZONES_O(SW);
  1119. }
  1120. }
  1121. }
  1122. }
  1123. }
  1124. /*-------------------------------------------------------------------------*//**
  1125. * <param name="area">Area to set for.</param>
  1126. * <param name="set">Wether or not this area is usable in all worlds.</param>
  1127. *//*------------------------------------------------------------------------**/
  1128. /*-------------------------------------------------------------------------*//**
  1129. * <param name="area">Area to set for.</param>
  1130. * <param name="set">Wether or not this area is usable in all worlds.</param>
  1131. *//*------------------------------------------------------------------------**/
  1132. foreign void:Area_SetAllWorlds(area, bool:set);
  1133. global void:Area_SetAllWorlds(area, bool:set)
  1134. {
  1135. #if AREA_WORLDS > 0
  1136. if (Area_IsActive(area))
  1137. {
  1138. Bit_SetAll(YSI_g_sAreas[area][E_AREA_WORLDS], set, bits<AREA_WORLDS>);
  1139. //return 1;
  1140. }
  1141. #else
  1142. #pragma unused area, set
  1143. #endif
  1144. //return 0;
  1145. }
  1146. /*-------------------------------------------------------------------------*//**
  1147. * <param name="type">Type of area.</param>
  1148. * <param name="">Points.</param>
  1149. * <remarks>
  1150. * Types:
  1151. * CUBE, Cube
  1152. * CUBOID, Cuboid
  1153. * BOX, Box
  1154. * CIRCLE, Circle
  1155. * OVAL, Oval
  1156. * OVOID, Ovoid
  1157. * SPHERE, Sphere
  1158. * POLY, Poly
  1159. * </remarks>
  1160. *//*------------------------------------------------------------------------**/
  1161. P:D(Area_Add(type,Float:...));
  1162. #define Area_Add(%0,%1) Area_Add%0(%1)
  1163. #define Area_AddCUBE Area_AddCube
  1164. #define Area_AddCUBOID Area_AddCuboid
  1165. #define Area_AddBOX Area_AddBox
  1166. #define Area_AddCIRCLE Area_AddCircle
  1167. #define Area_AddOVAL Area_AddOval
  1168. #define Area_AddOVOID Area_AddOvoid
  1169. #define Area_AddSPHERE Area_AddSphere
  1170. #define Area_AddPOLY Area_AddPoly
  1171. /*-------------------------------------------------------------------------*//**
  1172. * <param name="minx">Lowest X corner of box</param>
  1173. * <param name="miny">Lowest Y corner of box.</param>
  1174. * <param name="minx">Lowest Z corner of box.</param>
  1175. * <param name="maxx">Highest X corner of box.</param>
  1176. * <param name="maxy">Highest Y corner of box.</param>
  1177. * <param name="maxz">Highest Z corner of box.</param>
  1178. * <returns>
  1179. * Area slot or NO_AREA
  1180. * </returns>
  1181. *//*------------------------------------------------------------------------**/
  1182. P:D(_AREA_MIN(&Float:minx,&Float:miny));
  1183. #define _AREA_MIN(%0,%1) if (%1 < %0) %0 ^= %1, %1 ^= %0, %0 ^= %1
  1184. @foreign Area_AddCuboid(Float:x0,Float:y0,Float:z0,Float:x1,Float:y1,Float:z1);
  1185. @global Area_AddCuboid(Float:x0,Float:y0,Float:z0,Float:x1,Float:y1,Float:z1)
  1186. {
  1187. new
  1188. slot = Area_GetFreeSlot();
  1189. if (slot == NO_AREA) return NO_AREA;
  1190. _AREA_MIN(x0, x1);
  1191. _AREA_MIN(y0, y1);
  1192. _AREA_MIN(z0, z1);
  1193. YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_CUBE | e_AREA_FLAGS_ACTIVE;
  1194. YSI_g_sAreas[slot][E_AREA_POS][0] = x0;
  1195. YSI_g_sAreas[slot][E_AREA_POS][1] = y0;
  1196. YSI_g_sAreas[slot][E_AREA_POS][2] = z0;
  1197. YSI_g_sAreas[slot][E_AREA_POS][3] = x1;
  1198. YSI_g_sAreas[slot][E_AREA_POS][4] = y1;
  1199. YSI_g_sAreas[slot][E_AREA_POS][5] = z1;
  1200. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1201. NO_GROUPS(slot)
  1202. {
  1203. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1204. }
  1205. #if YSIM_HAS_MASTER
  1206. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1207. #endif
  1208. Area_SetAllWorlds(slot, true);
  1209. Area_DetermineZone(x0, y0, x1, y1, slot, slot);
  1210. /*#if defined AREA_VERY_FAST
  1211. new
  1212. rx = (x1 - z0) / 2.0,
  1213. ry = (y1 - y0) / 2.0,
  1214. rz = (z1 - z0) / 2.0;
  1215. YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x0 + rx;
  1216. YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y0 + ry;
  1217. YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = z0 + rz;
  1218. if (rx > ry && rx > rz)
  1219. {
  1220. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
  1221. }
  1222. else if (ry > rz)
  1223. {
  1224. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
  1225. }
  1226. else
  1227. {
  1228. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
  1229. }
  1230. #endif*/
  1231. return slot;
  1232. }
  1233. #undef _AREA_MIN
  1234. #define Area_AddCube Area_AddCuboid
  1235. /*-------------------------------------------------------------------------*//**
  1236. * <param name="minx">Lowest X corner of box</param>
  1237. * <param name="miny">Lowest Y corner of box.</param>
  1238. * <param name="maxx">Highest X corner of box.</param>
  1239. * <param name="maxy">Highest Y corner of box.</param>
  1240. * <returns>
  1241. * Area slot or NO_AREA
  1242. * </returns>
  1243. *//*------------------------------------------------------------------------**/
  1244. stock Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy)
  1245. {
  1246. return Area_AddCuboid(minx, miny, FLOAT_NEGATIVE_INFINITY, maxx, maxy, FLOAT_INFINITY);
  1247. }
  1248. /*
  1249. @foreign Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy);
  1250. @global Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy)
  1251. {
  1252. new
  1253. slot;
  1254. if (minx > maxx)
  1255. {
  1256. slot = _:minx;
  1257. minx = maxx;
  1258. maxx = Float:slot;
  1259. }
  1260. if (miny > maxy)
  1261. {
  1262. slot = _:miny;
  1263. miny = maxy;
  1264. maxy = Float:slot;
  1265. }
  1266. slot = Area_GetFreeSlot();
  1267. if (slot == NO_AREA) return NO_AREA;
  1268. YSI_g_sAreas[slot][E_AREA_FLAGS] = SINGLE_SLOT_AREA | e_AREA_FLAGS_BOX | e_AREA_FLAGS_USED | e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS:(1 << 18);
  1269. YSI_g_sAreas[slot][E_AREA_POS][0] = minx;
  1270. YSI_g_sAreas[slot][E_AREA_POS][1] = miny;
  1271. YSI_g_sAreas[slot][E_AREA_POS][2] = maxx;
  1272. YSI_g_sAreas[slot][E_AREA_POS][3] = maxy;
  1273. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1274. NO_GROUPS(slot)
  1275. {
  1276. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1277. }
  1278. #if YSIM_HAS_MASTER
  1279. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1280. #endif
  1281. Area_SetAllWorlds(slot, true);
  1282. Area_DetermineZone(minx, miny, maxx, maxy, slot, slot);
  1283. return slot;
  1284. }
  1285. */
  1286. /*-------------------------------------------------------------------------*//**
  1287. * <param name="x">X position of circle.</param>
  1288. * <param name="y">Y position of circle.</param>
  1289. * <param name="r">Radius of circle.</param>
  1290. * <param name="height">Ceiling of circle.</param>
  1291. * <param name="depth">Bottom of circle.</param>
  1292. * <returns>
  1293. * Area slot or NO_AREA
  1294. * </returns>
  1295. * <remarks>
  1296. * Technically a cylinder, no lower bound (ceiling added cos there was a
  1297. * spare slot in the 4 float design which may as well have been used).
  1298. * </remarks>
  1299. *//*------------------------------------------------------------------------**/
  1300. stock Area_AddCircle(Float:x, Float:y, Float:r, Float:height = FLOAT_INFINITY)
  1301. {
  1302. return Area_AddOval(x, y, r, r, height, FLOAT_NEGATIVE_INFINITY);
  1303. }
  1304. /*-------------------------------------------------------------------------*//**
  1305. * <param name="x">X position of circle.</param>
  1306. * <param name="y">Y position of circle.</param>
  1307. * <param name="rx">X Radius of oval.</param>
  1308. * <param name="ry">Y Radius of oval.</param>
  1309. * <param name="height">Ceiling of circle.</param>
  1310. * <param name="depth">Bottom of circle.</param>
  1311. * <returns>
  1312. * Area slot or NO_AREA
  1313. * </returns>
  1314. * <remarks>
  1315. * Technically a cylinder, no lower bound (ceiling added cos there was a
  1316. * spare slot in the 4 float design which may as well have been used).
  1317. * </remarks>
  1318. *//*------------------------------------------------------------------------**/
  1319. @foreign Area_AddOval(Float:x,Float:y,Float:rx,Float:ry,Float:h,Float:d);
  1320. @global Area_AddOval(Float:x,Float:y,Float:rx,Float:ry,Float:h,Float:d)
  1321. {
  1322. new
  1323. slot = Area_GetFreeSlot();
  1324. if (slot == NO_AREA) return NO_AREA;
  1325. //printf("%f %f %f %f", x - r, y - r, x + r, y + r);
  1326. YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE;
  1327. YSI_g_sAreas[slot][E_AREA_POS][0] = x;
  1328. YSI_g_sAreas[slot][E_AREA_POS][1] = y;
  1329. YSI_g_sAreas[slot][E_AREA_POS][2] = rx * rx;
  1330. YSI_g_sAreas[slot][E_AREA_POS][3] = ry * ry;
  1331. YSI_g_sAreas[slot][E_AREA_POS][4] = h;
  1332. YSI_g_sAreas[slot][E_AREA_POS][5] = d;
  1333. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1334. NO_GROUPS(slot)
  1335. {
  1336. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1337. }
  1338. #if YSIM_HAS_MASTER
  1339. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1340. #endif
  1341. Area_SetAllWorlds(slot, true);
  1342. Area_DetermineZone(x - rx, y - ry, x + rx, y + ry, slot, slot);
  1343. if (rx == ry && h == FLOAT_INFINITY && d == FLOAT_NEGATIVE_INFINITY)
  1344. {
  1345. YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_CIRCLE;
  1346. }
  1347. else
  1348. {
  1349. YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_OVAL;
  1350. }
  1351. // Bounding sphere. I'm not convinced this is needed on the simple shapes,
  1352. // I may only use it on polys and special-case
  1353. /*#if defined AREA_VERY_FAST
  1354. YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x;
  1355. YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y;
  1356. // Z radius of the bounding sphere (may be VERY huge).
  1357. new
  1358. rz = (h - d) / 2.0;
  1359. YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = h - rz;
  1360. if (rx > ry && rx > rz)
  1361. {
  1362. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
  1363. }
  1364. else if (ry > rz)
  1365. {
  1366. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
  1367. }
  1368. else
  1369. {
  1370. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
  1371. }
  1372. #endif*/
  1373. return slot;
  1374. }
  1375. /*-------------------------------------------------------------------------*//**
  1376. * <param name="x">X position of sphere.</param>
  1377. * <param name="y">Y position of sphere.</param>
  1378. * <param name="z">Z position of sphere.</param>
  1379. * <param name="r">Radius of sphere.</param>
  1380. * <returns>
  1381. * Area slot or NO_AREA
  1382. * </returns>
  1383. *//*------------------------------------------------------------------------**/
  1384. stock Area_AddSphere(Float:x, Float:y, Float:z, Float:r)
  1385. {
  1386. return Area_AddOvoid(x, y, z, r, r, r);
  1387. }
  1388. /*-------------------------------------------------------------------------*//**
  1389. * <param name="x">X position of sphere.</param>
  1390. * <param name="y">Y position of sphere.</param>
  1391. * <param name="z">Z position of sphere.</param>
  1392. * <param name="rx">X radius of ovoid.</param>
  1393. * <param name="ry">Y radius of ovoid.</param>
  1394. * <param name="rz">Z radius of ovoid.</param>
  1395. * <returns>
  1396. * Area slot or NO_AREA
  1397. * </returns>
  1398. *//*------------------------------------------------------------------------**/
  1399. @foreign Area_AddOvoid(Float:x,Float:y,Float:z,Float:rx,Float:ry,Float:rz);
  1400. @global Area_AddOvoid(Float:x,Float:y,Float:z,Float:rx,Float:ry,Float:rz)
  1401. {
  1402. new
  1403. slot = Area_GetFreeSlot();
  1404. if (slot == NO_AREA) return NO_AREA;
  1405. YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE;
  1406. YSI_g_sAreas[slot][E_AREA_POS][0] = x;
  1407. YSI_g_sAreas[slot][E_AREA_POS][1] = y;
  1408. YSI_g_sAreas[slot][E_AREA_POS][2] = z;
  1409. YSI_g_sAreas[slot][E_AREA_POS][3] = rx * rx;
  1410. YSI_g_sAreas[slot][E_AREA_POS][4] = ry * ry;
  1411. YSI_g_sAreas[slot][E_AREA_POS][5] = rz * rz;
  1412. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1413. NO_GROUPS(slot)
  1414. {
  1415. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1416. }
  1417. #if YSIM_HAS_MASTER
  1418. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1419. #endif
  1420. Area_SetAllWorlds(slot, true);
  1421. Area_DetermineZone(x - rx, y - ry, x + rx, y + ry, slot, slot);
  1422. // Create the bounding sphere for this zone. The player has to be inside
  1423. // the bounding sphere before they can be inside the oval. Of course, if
  1424. // the oval is also a sphere then these two checks are identical.
  1425. #if defined AREA_VERY_FAST
  1426. YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x;
  1427. YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y;
  1428. YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = z;
  1429. if (rx > ry && rx > rz)
  1430. {
  1431. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
  1432. }
  1433. else if (ry > rz)
  1434. {
  1435. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
  1436. }
  1437. else
  1438. {
  1439. YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
  1440. }
  1441. if (rx == ry && rx == rz)
  1442. {
  1443. YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_SPHERE;
  1444. }
  1445. else
  1446. #endif
  1447. {
  1448. // Create the zone bounds.
  1449. YSI_g_sAreas[slot][E_AREA_POS][0] = x;
  1450. YSI_g_sAreas[slot][E_AREA_POS][1] = y;
  1451. YSI_g_sAreas[slot][E_AREA_POS][2] = z;
  1452. YSI_g_sAreas[slot][E_AREA_POS][3] = rx * rx;
  1453. YSI_g_sAreas[slot][E_AREA_POS][4] = ry * ry;
  1454. YSI_g_sAreas[slot][E_AREA_POS][5] = rz * rz;
  1455. // Set this as not a sphere.
  1456. YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_OVOID;
  1457. }
  1458. #pragma tabsize 4
  1459. return slot;
  1460. }
  1461. /*-------------------------------------------------------------------------*//**
  1462. * <param name="">X/Ys of points</param>
  1463. * <returns>
  1464. * Area slot or NO_AREA
  1465. * </returns>
  1466. * <remarks>
  1467. * Creates an irregular shape to detect players in. This is a 2d area made
  1468. * up of a load of XY points. If an odd number of parameters is passed the
  1469. * extra one is assumed to be a ceiling so you can ignore interiors or planes.
  1470. *
  1471. * The height parameter goes first as it's easiest to check.
  1472. *
  1473. * This is one of a few functions still written using the master system at a
  1474. * low level (the other obvious one is "Class_Add").
  1475. * </remarks>
  1476. *//*------------------------------------------------------------------------**/
  1477. #if YSIM_HAS_MASTER
  1478. #if _YSIM_IS_SERVER
  1479. forward Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...);
  1480. forward Area_AddPoly@(Float:points[], size, count);
  1481. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1482. {
  1483. new
  1484. args = numargs();
  1485. if (args > 128)
  1486. {
  1487. return NO_AREA;
  1488. }
  1489. new
  1490. Float:points[128];
  1491. points[0] = x1;
  1492. points[1] = y1;
  1493. points[2] = x2;
  1494. points[3] = y2;
  1495. points[4] = x3;
  1496. points[5] = y3;
  1497. for (new i = 6; i != args; ++i)
  1498. {
  1499. points[i] = Float:getarg(i);
  1500. }
  1501. return Area_AddPoly@(points, sizeof (points), args);
  1502. }
  1503. public Area_AddPoly@(Float:points[], size, count)
  1504. #else
  1505. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <>
  1506. {
  1507. new
  1508. args = numargs();
  1509. if (args > 128)
  1510. {
  1511. return NO_AREA;
  1512. }
  1513. new
  1514. Float:points[128];
  1515. points[0] = x1;
  1516. points[1] = y1;
  1517. points[2] = x2;
  1518. points[3] = y2;
  1519. points[4] = x3;
  1520. points[5] = y3;
  1521. for (new i = 6; i != args; ++i)
  1522. {
  1523. points[i] = Float:getarg(i);
  1524. }
  1525. new
  1526. p = getproperty(8, YSIM_CALLER);
  1527. setproperty(8, YSIM_CALLER, _@);
  1528. CallRemoteFunction("Area_AddPoly@", "aii", points, sizeof (points), args);
  1529. setproperty(8, YSIM_CALLER, p);
  1530. return getproperty(8, YSIM_RETURN);
  1531. }
  1532. forward Area_AddPoly@(Float:points[], size, count);
  1533. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : m>
  1534. {
  1535. #pragma unused x1, y1, x2, y2, x3, y3
  1536. return NO_AREA;
  1537. }
  1538. #if _YSIM_IS_CLIENT
  1539. static stock Area_AddPoly_(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1540. #else
  1541. #if _YSIM_IS_STUB
  1542. #error _YSIM_IS_STUB set in y_areas.
  1543. #else
  1544. public Area_AddPoly@(Float:points[], size, count) <>
  1545. {
  1546. return 0;
  1547. }
  1548. /*{
  1549. X@(_:@Zk:_YM@CP:%0(%1,,));
  1550. setproperty(8, YSIM_RETURN, n);
  1551. }*/
  1552. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : y>
  1553. {
  1554. new
  1555. args = numargs();
  1556. if (args > 128)
  1557. {
  1558. return NO_AREA;
  1559. }
  1560. new
  1561. Float:points[128];
  1562. points[0] = x1;
  1563. points[1] = y1;
  1564. points[2] = x2;
  1565. points[3] = y2;
  1566. points[4] = x3;
  1567. points[5] = y3;
  1568. for (new i = 6; i != args; ++i)
  1569. {
  1570. points[i] = Float:getarg(i);
  1571. }
  1572. return Area_AddPoly@(points, sizeof (points), args);
  1573. }
  1574. public Area_AddPoly@(Float:points[], size, count) <_YCM : y>
  1575. #endif
  1576. #endif
  1577. #endif
  1578. #else
  1579. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1580. {
  1581. new
  1582. args = numargs();
  1583. if (args > 128)
  1584. {
  1585. return NO_AREA;
  1586. }
  1587. new
  1588. Float:points[128];
  1589. points[0] = x1;
  1590. points[1] = y1;
  1591. points[2] = x2;
  1592. points[3] = y2;
  1593. points[4] = x3;
  1594. points[5] = y3;
  1595. for (new i = 6; i != args; ++i)
  1596. {
  1597. points[i] = Float:getarg(i);
  1598. }
  1599. return Area_AddPoly_(points, sizeof (points), args);
  1600. }
  1601. static stock Area_AddPoly_(Float:points[], size, count)
  1602. #endif
  1603. {
  1604. // This is the main chunk of the code.
  1605. new
  1606. Float:height = Float:isodd(count);
  1607. count &= ~1;
  1608. new
  1609. reqSlots = ceildiv(count, CHILD_AREA_SLOTS) + 1;
  1610. if (Area_GetEmptySlotCount() < reqSlots) return NO_AREA;
  1611. if (_:height)
  1612. {
  1613. height = points[count];
  1614. }
  1615. else
  1616. {
  1617. height = FLOAT_INFINITY;
  1618. }
  1619. // Get the header. This stores meta-data about the poly area, and the
  1620. // bounding cylinder, it doesn't actually store any points.
  1621. new
  1622. header = Area_GetFreeSlot();
  1623. // Initialise the header. Area type, players, worlds, and count.
  1624. // This stores the number of pairs, not the number of co-ordinates.
  1625. YSI_g_sAreas[header][E_AREA_POLY_COUNT] = count;
  1626. YSI_g_sAreas[header][E_AREA_FLAGS] = e_AREA_FLAGS_POLY | e_AREA_FLAGS_ACTIVE;
  1627. PA_FastInit(YSI_g_sAreas[header][E_AREA_PLAYERS]);
  1628. NO_GROUPS(header)
  1629. {
  1630. PA_Init(YSI_g_sAreas[header][E_AREA_PLAYERS], true);
  1631. }
  1632. #if YSIM_HAS_MASTER
  1633. YSI_g_sAreas[header][E_AREA_MASTER] = Master_Caller();
  1634. #endif
  1635. Area_SetAllWorlds(header, true);
  1636. // Now loop through and store all the data points.
  1637. new
  1638. slot,
  1639. prev = header,
  1640. done = 0,
  1641. Float:cur,
  1642. Float:minx = FLOAT_INFINITY,
  1643. Float:miny = FLOAT_INFINITY,
  1644. Float:maxx = FLOAT_NEGATIVE_INFINITY,
  1645. Float:maxy = FLOAT_NEGATIVE_INFINITY;
  1646. while (done < count)
  1647. //while (done < count)
  1648. {
  1649. slot = Area_GetFreeSlot();
  1650. YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS_CHILD;
  1651. // Rely purely on counts, not ended lists. This is because the system
  1652. // MAY (if I get around to it) reuse this data in the last slot to
  1653. //YSI_g_sAreas[slot][E_AREA_POLY_NEXT] = NO_AREA;
  1654. YSI_g_sAreas[slot][E_AREA_CHILD_PARENT] = header;
  1655. YSI_g_sAreas[prev][E_AREA_POLY_NEXT] = slot;
  1656. #if YSIM_HAS_MASTER
  1657. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1658. #endif
  1659. // Now loop and put points in this slot.
  1660. size = min(count, done + CHILD_AREA_SLOTS);
  1661. for (new idx = 0; done < size; )
  1662. {
  1663. // X point.
  1664. cur = points[done++];
  1665. //printf("%d X: %0.2f", done, cur);
  1666. //printf("%04x%04x %04x%04x %.2f %d %d", _:minx >>> 16, _:minx & 0xFFFF, _:maxx >>> 16, _:maxx & 0xFFFF, cur, cur > maxx, cur < minx);
  1667. if (cur > maxx) maxx = cur;
  1668. if (cur < minx) minx = cur;
  1669. YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][idx++] = cur;
  1670. // Y point.
  1671. cur = points[done++];
  1672. //printf("%d Y: %0.2f", done, cur);
  1673. // Can be both on the first loop (WILL be both on the first loop).
  1674. if (cur > maxy) maxy = cur;
  1675. if (cur < miny) miny = cur;
  1676. YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][idx++] = cur;
  1677. }
  1678. prev = slot;
  1679. //count -= CHILD_AREA_SLOTS * 2;
  1680. }
  1681. // Now clean up.
  1682. #if YSIM_HAS_MASTER
  1683. setproperty(8, YSIM_RETURN, header);
  1684. #endif
  1685. Area_DetermineZone(minx, miny, maxx, maxy, header, header);
  1686. // Create the bounding cylinder so we can quickly determine if it is even
  1687. // at all possible for the player to be in this polygon.
  1688. // TODO: This doesn't YET create an accurate bounding cylinder as the
  1689. // diagonals of a square are longer than the width and height, and that fact
  1690. // isn't taken in to account by the radius. The question is, why are these
  1691. // sums returning -0.0 for 20.0-0.0?
  1692. // BIZZARE BUG FIX.
  1693. //printf("%f %f %f %f", minx, miny, maxx, maxy);
  1694. //printf("%f %f", maxx - minx, maxy - miny);
  1695. //printf("%04x%04x", _:minx >>> 16, _:minx & 0xFFFF);
  1696. //printf("%04x%04x", _:maxx >>> 16, _:maxx & 0xFFFF);
  1697. //if (maxx && minx) printf("1: %d", (maxx = (maxx - minx) / 2.0));
  1698. //else if (maxx) printf("2: %d", (maxx /= 2.0));
  1699. //else printf("3: %d", (maxx = minx / 2.0));
  1700. //if (maxx < 0.0) maxx = -maxx;
  1701. //if (maxy && miny) maxy = (maxy - miny) / 2.0;
  1702. //else if (maxy) maxy /= 2.0;
  1703. //else maxy = miny / 2.0;
  1704. //if (maxy < 0.0) maxy = -maxy;
  1705. //printf("%f %f %f %f", (maxx - minx) / 2.0, (maxy - miny) / 2.0, minx + (maxx - minx) / 2.0, miny + (maxy - miny) / 2.0);
  1706. maxx = (maxx - minx) / 2.0;
  1707. maxy = (maxy - miny) / 2.0;
  1708. //printf("%f %f %f %f", maxx, maxy, minx + maxx, miny + maxy);
  1709. minx += maxx;
  1710. miny += maxy;
  1711. YSI_g_sAreas[header][E_AREA_POLY_BOUND_X] = minx;
  1712. YSI_g_sAreas[header][E_AREA_POLY_BOUND_Y] = miny;
  1713. // Now find the radius. Note that it might actually make more sense to not
  1714. // use the dead centre but a point which minimises the R^2 distance, but
  1715. // that will require a lot more work.
  1716. slot = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
  1717. count = YSI_g_sAreas[header][E_AREA_POLY_COUNT];
  1718. cur = 0.0;
  1719. while (count > 0)
  1720. {
  1721. for (new i = 0, j = min(count, CHILD_AREA_SLOTS); i < j; i += 2)
  1722. {
  1723. // Get the difference between the points.
  1724. maxx = YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][i] - minx;
  1725. maxy = YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][i + 1] - miny;
  1726. maxx = maxx * maxx + maxy * maxy;
  1727. if (maxx > cur) cur = maxx;
  1728. }
  1729. slot = YSI_g_sAreas[slot][E_AREA_POLY_NEXT];
  1730. count -= CHILD_AREA_SLOTS;
  1731. }
  1732. YSI_g_sAreas[header][E_AREA_POLY_BOUND_R] = cur;
  1733. YSI_g_sAreas[header][E_AREA_POLY_BOUND_H] = height;
  1734. return header;
  1735. }
  1736. /*-------------------------------------------------------------------------*//**
  1737. * <param name="playerid">Player who connected</param>
  1738. *//*------------------------------------------------------------------------**/
  1739. mhook OnPlayerConnect(playerid)
  1740. {
  1741. for (new i = 0; i != AREAS_MAX_OVERLAPS; ++i)
  1742. {
  1743. YSI_g_sPlayerArea[playerid][i] = NO_AREA;
  1744. }
  1745. NO_GROUPS()
  1746. {
  1747. new
  1748. slot = Bit_Slot(playerid) + 1,
  1749. Bit:mask = Bit_Mask(playerid);
  1750. for (new i = 0; i != MAX_AREAS; ++i)
  1751. {
  1752. YSI_g_sAreas[i][E_AREA_PLAYERS][slot] |= mask;
  1753. }
  1754. }
  1755. return 1;
  1756. }
  1757. /*-------------------------------------------------------------------------*//**
  1758. * <param name="playerid">The player to check for.</param>
  1759. * <remarks>
  1760. * Main processing for the system. Takes one player and checks if they're in
  1761. * some sort of range of somewhere.
  1762. * </remarks>
  1763. *//*------------------------------------------------------------------------**/
  1764. #if defined AREAS_USE_TIMER
  1765. #error AREAS_USE_TIMER is currently unsupported sorry.
  1766. ptask Area_Loop[200](playerid)
  1767. {
  1768. new
  1769. Float:x,
  1770. Float:y,
  1771. Float:z,
  1772. area = YSI_g_sPlayerArea[playerid],
  1773. world = GetPlayerVirtualWorld(playerid);
  1774. GetPlayerPos(playerid, x, y, z);
  1775. if (area != NO_AREA)
  1776. {
  1777. if (Area_CheckArea(playerid, world, area, x, y, z)) continue;
  1778. YSI_g_sPlayerArea[playerid] = NO_AREA;
  1779. #if defined _YSI_GAMEMODE_PROPERTIES
  1780. if (!Property_OnPlayerLeaveArea(playerid, area))
  1781. #endif
  1782. CallRemoteFunction("OnPlayerLeaveArea", "ii", playerid, area);
  1783. }
  1784. for (area = 0; area < MAX_AREAS; area++)
  1785. {
  1786. if (Area_CheckArea(playerid, world, area, x, y, z))
  1787. {
  1788. YSI_g_sPlayerArea[playerid] = area;
  1789. CallRemoteFunction("OnPlayerEnterArea", "ii", playerid, area);
  1790. break;
  1791. }
  1792. }
  1793. }
  1794. #else
  1795. hook OnPlayerUpdate(playerid)
  1796. {
  1797. static
  1798. // Another hard-coded limit (max areas we can actually be in, more
  1799. // than the max that is globally stored, but still not infinate).
  1800. sAreas[16],
  1801. sZones[9],
  1802. Float:sX,
  1803. Float:sY,
  1804. Float:sZ,
  1805. sCur,
  1806. sNext,
  1807. sW,
  1808. sAlready;
  1809. new
  1810. in,
  1811. idx;
  1812. // Get all the zones for this player.
  1813. GetPlayerPos(playerid, sX, sY, sZ);
  1814. P:7("Areas_OnPlayerUpdate: pos = %f %f %f", sX, sY, sZ);
  1815. #if AREA_WORLDS > 0
  1816. sW = GetPlayerVirtualWorld(playerid);
  1817. #endif
  1818. for ( ; (sCur = _Area_GetPlayerAreas(playerid, idx)) != NO_AREA; )
  1819. {
  1820. // In this zone too.
  1821. if (Area_CheckArea(playerid, sW, sCur, sX, sY, sZ, sNext, sAreas, 0))
  1822. {
  1823. ++idx;
  1824. sAreas[in++] = sCur;
  1825. }
  1826. else
  1827. {
  1828. // No longer in the area they used to be in.
  1829. Area_DoLeave(playerid, sCur, idx);
  1830. // "Area_DoLeave" shifts all the slots, so you end up with not
  1831. // needing to change "idx" at all.
  1832. }
  1833. }
  1834. sAlready = in;
  1835. sZones = Area_GetZones(sX, sY);
  1836. for (idx = 0; ; )
  1837. {
  1838. P:7("Areas_OnPlayerUpdate: zone = %d", sZones[idx]);
  1839. switch (sZones[idx++])
  1840. {
  1841. case e_AREA_ZONE_I_N:
  1842. {
  1843. _AREA_DO_ALL(YSI_g_sZoneIN);
  1844. }
  1845. case e_AREA_ZONE_I_NE:
  1846. {
  1847. _AREA_DO_ALL(YSI_g_sZoneINE);
  1848. }
  1849. case e_AREA_ZONE_I_E:
  1850. {
  1851. _AREA_DO_ALL(YSI_g_sZoneIE);
  1852. }
  1853. case e_AREA_ZONE_I_SE:
  1854. {
  1855. _AREA_DO_ALL(YSI_g_sZoneISE);
  1856. }
  1857. case e_AREA_ZONE_I_S:
  1858. {
  1859. _AREA_DO_ALL(YSI_g_sZoneIS);
  1860. }
  1861. case e_AREA_ZONE_I_SW:
  1862. {
  1863. _AREA_DO_ALL(YSI_g_sZoneISW);
  1864. }
  1865. case e_AREA_ZONE_I_W:
  1866. {
  1867. _AREA_DO_ALL(YSI_g_sZoneIW);
  1868. }
  1869. case e_AREA_ZONE_I_NW:
  1870. {
  1871. _AREA_DO_ALL(YSI_g_sZoneINW);
  1872. }
  1873. case e_AREA_ZONE_I_:
  1874. {
  1875. _AREA_DO_ALL(YSI_g_sZoneI);
  1876. }
  1877. // "Outer" zones.
  1878. case e_AREA_ZONE_O_N:
  1879. {
  1880. _AREA_DO_ALL(YSI_g_sZoneON);
  1881. }
  1882. case e_AREA_ZONE_O_NE:
  1883. {
  1884. _AREA_DO_ALL(YSI_g_sZoneONE);
  1885. }
  1886. case e_AREA_ZONE_O_E:
  1887. {
  1888. _AREA_DO_ALL(YSI_g_sZoneOE);
  1889. }
  1890. case e_AREA_ZONE_O_SE:
  1891. {
  1892. _AREA_DO_ALL(YSI_g_sZoneOSE);
  1893. }
  1894. case e_AREA_ZONE_O_S:
  1895. {
  1896. _AREA_DO_ALL(YSI_g_sZoneOS);
  1897. }
  1898. case e_AREA_ZONE_O_SW:
  1899. {
  1900. _AREA_DO_ALL(YSI_g_sZoneOSW);
  1901. }
  1902. case e_AREA_ZONE_O_W:
  1903. {
  1904. _AREA_DO_ALL(YSI_g_sZoneOW);
  1905. }
  1906. case e_AREA_ZONE_O_NW:
  1907. {
  1908. _AREA_DO_ALL(YSI_g_sZoneONW);
  1909. }
  1910. //case e_AREA_ZONE_O_:
  1911. //{
  1912. // _AREA_DO_ALL(YSI_g_sZoneO);
  1913. //}
  1914. case e_AREA_ZONE_X_N:
  1915. {
  1916. _AREA_DO_ALL(YSI_g_sZoneXN);
  1917. }
  1918. case e_AREA_ZONE_X_NE:
  1919. {
  1920. _AREA_DO_ALL(YSI_g_sZoneXNE);
  1921. }
  1922. case e_AREA_ZONE_X_E:
  1923. {
  1924. _AREA_DO_ALL(YSI_g_sZoneXE);
  1925. }
  1926. case e_AREA_ZONE_X_SE:
  1927. {
  1928. _AREA_DO_ALL(YSI_g_sZoneXSE);
  1929. }
  1930. case e_AREA_ZONE_X_S:
  1931. {
  1932. _AREA_DO_ALL(YSI_g_sZoneXS);
  1933. }
  1934. case e_AREA_ZONE_X_SW:
  1935. {
  1936. _AREA_DO_ALL(YSI_g_sZoneXSW);
  1937. }
  1938. case e_AREA_ZONE_X_W:
  1939. {
  1940. _AREA_DO_ALL(YSI_g_sZoneXW);
  1941. }
  1942. case e_AREA_ZONE_X_NW:
  1943. {
  1944. _AREA_DO_ALL(YSI_g_sZoneXNW);
  1945. }
  1946. case e_AREA_ZONE_X_:
  1947. {
  1948. // Always the last zone in the list.
  1949. _AREA_DO_ALL(YSI_g_sZoneX);
  1950. break;
  1951. }
  1952. case e_AREA_ZONE_NONE:
  1953. {
  1954. // Specific zone (which).
  1955. _AREA_DO_ALL(YSI_g_sZones[((Area_MakeZone(sX) + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS + Area_MakeZone(sY)]);
  1956. }
  1957. }
  1958. }
  1959. return 1;
  1960. }
  1961. #endif
  1962. /*-------------------------------------------------------------------------*//**
  1963. * <param name="playerid">Player being checked for.</param>
  1964. * <param name="world">VW the player is in.</param>
  1965. * <param name="area">Area to check against.</param>
  1966. * <param name="x">X position to check.</param>
  1967. * <param name="y">Y position to check.</param>
  1968. * <param name="z">Z position to check.</param>
  1969. * <remarks>
  1970. * Checks if the given position is in the give area. All parameters are passed
  1971. * to avoid calling functions over and over and over again. If the return is
  1972. * not true, "area" is updated to the next one in the chain.
  1973. * </remarks>
  1974. *//*------------------------------------------------------------------------**/
  1975. static stock Area_CheckArea(playerid, world, area, Float:x, Float:y, Float:z, &next, areas[16], already)
  1976. {
  1977. new
  1978. e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
  1979. next = YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] & AREA_NO_NEXT;
  1980. // Are they already in this area?
  1981. while (already--)
  1982. {
  1983. if (areas[already] == area)
  1984. {
  1985. return 0;
  1986. }
  1987. }
  1988. if ((flags & e_AREA_FLAGS_ACTIVE))
  1989. {
  1990. P:7("Area_CheckArea: %d %d %d %f %f %f = %d", playerid, world, area, Float:x, Float:y, Float:z, _:(flags & e_AREA_FLAGS_TYPE) >>> 28);
  1991. switch (flags & e_AREA_FLAGS_TYPE)
  1992. {
  1993. case e_AREA_FLAGS_CIRCLE:
  1994. {
  1995. // In range of a sphere perfectly level with them.
  1996. if (!IsPlayerInRangeOfPoint(playerid, YSI_g_sAreas[area][E_AREA_POS][2], YSI_g_sAreas[area][E_AREA_POS][0], YSI_g_sAreas[area][E_AREA_POS][1], z))
  1997. {
  1998. return 0;
  1999. }
  2000. }
  2001. case e_AREA_FLAGS_OVAL:
  2002. {
  2003. if (!Area_IsInCircle(x, y, x, YSI_g_sAreas[area][E_AREA_POS]))
  2004. {
  2005. return 0;
  2006. }
  2007. }
  2008. case e_AREA_FLAGS_OVOID:
  2009. {
  2010. if (!Area_IsInOvoid(x, y, z, YSI_g_sAreas[area][E_AREA_POS]))
  2011. {
  2012. return 0;
  2013. }
  2014. }
  2015. case e_AREA_FLAGS_SPHERE:
  2016. {
  2017. if (!IsPlayerInRangeOfPoint(playerid, YSI_g_sAreas[area][E_AREA_POS][3], YSI_g_sAreas[area][E_AREA_POS][0], YSI_g_sAreas[area][E_AREA_POS][1], YSI_g_sAreas[area][E_AREA_POS][2]))
  2018. {
  2019. return 0;
  2020. }
  2021. }
  2022. case e_AREA_FLAGS_POLY:
  2023. {
  2024. if (!Area_IsInPoly(x, y, z, area))
  2025. {
  2026. return 0;
  2027. }
  2028. }
  2029. case e_AREA_FLAGS_CUBE:
  2030. {
  2031. if (!Area_IsInCube(x, y, z, YSI_g_sAreas[area][E_AREA_POS]))
  2032. {
  2033. return 0;
  2034. }
  2035. }
  2036. }
  2037. P:7("Area_CheckArea: MAYBE");
  2038. if (PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid))
  2039. {
  2040. #if AREA_WORLDS > 0
  2041. if (Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world))
  2042. {
  2043. return 1;
  2044. }
  2045. #else
  2046. #pragma unused world
  2047. return 1;
  2048. #endif
  2049. }
  2050. }
  2051. return 0;
  2052. }
  2053. /*-------------------------------------------------------------------------*//**
  2054. * <param name="x">X position to check.</param>
  2055. * <param name="y">Y position to check.</param>
  2056. * <param name="z">Z position to check.</param>
  2057. * <param name="bounds">Data for the area position.</param>
  2058. * <remarks>
  2059. * Checks if a point is in a given circle.
  2060. * </remarks>
  2061. *//*------------------------------------------------------------------------**/
  2062. static stock Area_IsInCircle(Float:x, Float:y, Float:z, Float:bounds[])
  2063. {
  2064. x -= bounds[0];
  2065. y -= bounds[1];
  2066. return (bounds[4] <= z <= bounds[5] && ((x * x) / bounds[2] + (y * y) / bounds[3]) < 1.0);
  2067. }
  2068. /*-------------------------------------------------------------------------*//**
  2069. * <param name="x">X position to check.</param>
  2070. * <param name="y">Y position to check.</param>
  2071. * <param name="z">Z position to check.</param>
  2072. * <param name="bounds">Data for the area position.</param>
  2073. * <remarks>
  2074. * Checks if a point is in a given sphere.
  2075. * </remarks>
  2076. *//*------------------------------------------------------------------------**/
  2077. /*static stock Area_IsInSphere(Float:x, Float:y, Float:z, Float:bounds[])
  2078. {
  2079. x -= bounds[0];
  2080. y -= bounds[1];
  2081. z -= bounds[2];
  2082. return (((x * x) + (y * y) + (z * z)) < bounds[3]);
  2083. }*/
  2084. /*-------------------------------------------------------------------------*//**
  2085. * <param name="x">X position to check.</param>
  2086. * <param name="y">Y position to check.</param>
  2087. * <param name="z">Z position to check.</param>
  2088. * <param name="bounds">Data for the area position.</param>
  2089. * <remarks>
  2090. * Checks if a point is in a given ovoid.
  2091. * </remarks>
  2092. *//*------------------------------------------------------------------------**/
  2093. static stock Area_IsInOvoid(Float:x, Float:y, Float:z, Float:bounds[])
  2094. {
  2095. x -= bounds[0];
  2096. y -= bounds[1];
  2097. z -= bounds[2];
  2098. return (((x * x) / bounds[3] + (y * y) / bounds[4] + (z * z) / bounds[5]) < 1.0);
  2099. }
  2100. /*-------------------------------------------------------------------------*//**
  2101. * <param name="x">X position to check.</param>
  2102. * <param name="y">Y position to check.</param>
  2103. * <param name="z">Z position to check.</param>
  2104. * <param name="header">Pointer to the start of the polygon data in the array.</param>
  2105. * <remarks>
  2106. * Based on IsPlayerInAreaEx by koolk in the useful functions topic. The
  2107. * passed pointer is the pointer to the first set of co-ordinates in a one-
  2108. * way not looping linked list of points in the polygod as the data may be
  2109. * spread throughout the areas array. This is as otherwise there may be
  2110. * enough free spaces but not in one block.
  2111. *
  2112. * The code first checks if there is a height component as it's the easiest
  2113. * to check thus may save a load of pointless processing. If this passes it
  2114. * then does the main loop. This loops till there are no points left to do
  2115. * (monitored by decreasing count). When 2 points (four pieces of data) have
  2116. * been checked the poiner for the data is moved on to the next group and the
  2117. * checking continues.
  2118. *
  2119. * For simplicity's sake (and thus speed's sake) the lower pointes from the
  2120. * last check are saved amd used as the upper points for the next check to
  2121. * avoid loads of repeated array accesses and saving the last array position.
  2122. * </remarks>
  2123. *//*------------------------------------------------------------------------**/
  2124. /*static*/
  2125. stock Area_IsInPoly(Float:x, Float:y, Float:z, header)
  2126. {
  2127. // First check the bounding zone.
  2128. new
  2129. Float:bx = x - YSI_g_sAreas[header][E_AREA_POLY_BOUND_X],
  2130. Float:by = y - YSI_g_sAreas[header][E_AREA_POLY_BOUND_Y];
  2131. P:7("Area_IsInPoly: %f %f %f %d", x, y, z, header);
  2132. P:7("Area_IsInPoly: %f %f %f %d", YSI_g_sAreas[header][E_AREA_POLY_BOUND_H], (bx * bx + by * by),YSI_g_sAreas[header][E_AREA_POLY_BOUND_R], (z <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_H] && (bx * bx + by * by) <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_R]));
  2133. if (!(z <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_H] && (bx * bx + by * by) <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_R]))
  2134. {
  2135. return 0;
  2136. }
  2137. // Within the bounding cylinder, do the more complex checks.
  2138. new
  2139. count = YSI_g_sAreas[header][E_AREA_POLY_COUNT];
  2140. P:7("Area_IsInPoly: In the bounds: %d %d", count, CHILD_AREA_SLOTS);
  2141. if (count <= CHILD_AREA_SLOTS)
  2142. {
  2143. // Only uses one single child slot.
  2144. header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
  2145. new
  2146. lines,
  2147. done = 2,
  2148. Float:fx = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][0],
  2149. Float:fy = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][1],
  2150. Float:x0 = fx,
  2151. Float:y0 = fy,
  2152. Float:x1,
  2153. Float:y1;
  2154. while (done < count)
  2155. {
  2156. x1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
  2157. y1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
  2158. // Crosses this line.
  2159. //P:7("Area_IsInPoly: %f %f %f", y0, y, y1);
  2160. if (((y0 <= y <= y1) || (y1 <= y <= y0)) && ((x0 + ((y - y0) * (x1 - x0) / (y1 - y0))) <= x)) ++lines;
  2161. //P:7("Area_IsInPoly: %d %d %d %d %d", (y0 <= y <= y1), (y1 <= y <= y0), (y0 <= y <= y1) || (y1 <= y <= y0), (x0 + ((y - y0) * (x1 - x0) / (y1 - y0))) <= x, lines);
  2162. x0 = x1;
  2163. y0 = y1;
  2164. }
  2165. //P:7("Area_IsInPoly: %f %f %f", y0, y, fy);
  2166. if (((y0 <=y <= fy) || (fy <= y <= y0)) && (x0 + ((y - y0) * (fx - x0) / (fy - y0))) <= x) ++lines;
  2167. //P:7("Area_IsInPoly: %d %d %d %d %d", (y0 <= y <= fy), (fy <= y <= y0), (y0 <= y <= fy) || (fy <= y <= y0), (x0 + ((y - y0) * (fx - x0) / (fy - y0))) <= x, lines);
  2168. //P:7("Area_IsInPoly: Return %d", lines);
  2169. return isodd(lines);
  2170. }
  2171. else
  2172. {
  2173. // Has multiple children
  2174. header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
  2175. new
  2176. stp,
  2177. lines,
  2178. done = 2,
  2179. Float:fx = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][0],
  2180. Float:fy = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][1],
  2181. Float:x0 = fx,
  2182. Float:y0 = fy,
  2183. Float:x1,
  2184. Float:y1;
  2185. while (count > 0)
  2186. {
  2187. stp = min(count, CHILD_AREA_SLOTS);
  2188. while (done < stp)
  2189. {
  2190. x1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
  2191. y1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
  2192. // Crosses this line.
  2193. if (((y0 <= y <= y1) || (y1 <= y <= y0)) && (x0 + ((y - y0) * (x1 - x0) / (y1 - y0))) <= x) ++lines;
  2194. x0 = x1;
  2195. y0 = y1;
  2196. }
  2197. count -= CHILD_AREA_SLOTS;
  2198. done = 0;
  2199. header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
  2200. }
  2201. //x1 = YSI_g_sAreas[pointer][E_AREA_CHILD_ELEMS][0];
  2202. // Link the last and first points to complete the perimeter.
  2203. if (((y0 <=y <= fy) || (fy <= y <= y0)) && (x0 + ((y - y0) * (fx - x0) / (fy - y0))) <= x) ++lines;
  2204. //printf("Area_IsInPoly: Return %d", lines);
  2205. return isodd(lines);
  2206. }
  2207. }
  2208. /*-------------------------------------------------------------------------*//**
  2209. * <param name="x">X position to check.</param>
  2210. * <param name="y">Y position to check.</param>
  2211. * <param name="z">Z position to check.</param>
  2212. * <param name="lower">The lower corner of the cube.</param>
  2213. * <param name="upper">The upper corner of the cube.</param>
  2214. * <remarks>
  2215. * Checks if a point is in a given cube. This is another multi slot shape
  2216. * but is much simpler than the poly as it's always 2 slots so we can easilly
  2217. * get the data in one lump.
  2218. * </remarks>
  2219. *//*------------------------------------------------------------------------**/
  2220. static stock Area_IsInCube(Float:x, Float:y, Float:z, Float:bounds[])
  2221. {
  2222. return (bounds[0] <= x <= bounds[3] && bounds[1] <= y <= bounds[4] && bounds[2] <= z <= bounds[5]);
  2223. }
  2224. /*-------------------------------------------------------------------------*//**
  2225. * <param name="x">X position to check.</param>
  2226. * <param name="y">Y position to check.</param>
  2227. * <param name="bounds">Data for the area position.</param>
  2228. * <remarks>
  2229. * Checks if a point is in a given box. There is no height check with this
  2230. * one as any one area slot has 4 points which for this are upper and lower
  2231. * x and y, adding a height check would make it require 2 slots and basically
  2232. * make it a cube check.
  2233. * </remarks>
  2234. *//*------------------------------------------------------------------------**/
  2235. /*static stock Area_IsInBox(Float:x, Float:y, Float:bounds[])
  2236. {
  2237. return (bounds[0] <= x <= bounds[2] && bounds[1] <= y <= bounds[3]);
  2238. }*/
  2239. /*-------------------------------------------------------------------------*//**
  2240. * <param name="playerid">Player to get area of.</param>
  2241. * <returns>
  2242. * The area a player is in or -1.
  2243. * </returns>
  2244. * <remarks>
  2245. * Deprecated.
  2246. * </remarks>
  2247. *//*------------------------------------------------------------------------**/
  2248. //foreign Area_GetPlayerArea(playerid);
  2249. #pragma deprecated Use Area_GetPlayerAreas
  2250. stock Area_GetPlayerArea(playerid)
  2251. {
  2252. if (VALID_PLAYERID(playerid))
  2253. {
  2254. return YSI_g_sPlayerArea[playerid][0];
  2255. }
  2256. return NO_AREA;
  2257. }
  2258. /*-------------------------------------------------------------------------*//**
  2259. * <param name="playerid">Player to set areas of.</param>
  2260. * <param name="idx">Which slot to set.</param>
  2261. * <param name="area">The area to store in that slot.</param>
  2262. * <remarks>
  2263. * Sets a player as in a slot.
  2264. * </remarks>
  2265. *//*------------------------------------------------------------------------**/
  2266. static stock
  2267. _Area_SetPlayerAreas(playerid, idx, area)
  2268. {
  2269. if (idx < AREAS_MAX_OVERLAPS)
  2270. {
  2271. YSI_g_sPlayerArea[playerid][idx] = area;
  2272. }
  2273. else
  2274. {
  2275. // Use PVars to store extended areas.
  2276. static
  2277. sProp[12] = "y_areas_";
  2278. valstr(sProp[8], idx);
  2279. if (area == NO_AREA)
  2280. {
  2281. DeletePVar(playerid, sProp);
  2282. }
  2283. else
  2284. {
  2285. SetPVarInt(playerid, sProp, area);
  2286. }
  2287. }
  2288. }
  2289. /*-------------------------------------------------------------------------*//**
  2290. * <summary>
  2291. * _Area_GetPlayerAreas
  2292. * Area_GetPlayerAreas
  2293. * </summary>
  2294. * <param name="playerid">Player to get areas of.</param>
  2295. * <param name="idx">Which area to get.</param>
  2296. * <returns>
  2297. * The area a player is in or -1.
  2298. * </returns>
  2299. * <remarks>
  2300. * Replaces Area_GetPlayerArea for multiple areas. Includes an internal
  2301. * version for tighter loops within this code to use once it is known that a
  2302. * player exists, and without using the global function system.
  2303. * </remarks>
  2304. *//*------------------------------------------------------------------------**/
  2305. static stock
  2306. _Area_GetPlayerAreas(playerid, idx)
  2307. {
  2308. if (idx < AREAS_MAX_OVERLAPS)
  2309. {
  2310. return YSI_g_sPlayerArea[playerid][idx];
  2311. }
  2312. else
  2313. {
  2314. // Use PVars to store extended areas.
  2315. static
  2316. sProp[12] = "y_areas_";
  2317. valstr(sProp[8], idx);
  2318. if (GetPVarType(playerid, sProp) == PLAYER_VARTYPE_INT)
  2319. {
  2320. return GetPVarInt(playerid, sProp);
  2321. }
  2322. }
  2323. return NO_AREA;
  2324. }
  2325. foreign Area_GetPlayerAreas(playerid, idx);
  2326. global Area_GetPlayerAreas(playerid, idx)
  2327. {
  2328. if (VALID_PLAYERID(playerid))
  2329. {
  2330. if (0 <= idx <= 999)
  2331. {
  2332. return _Area_GetPlayerAreas(playerid, idx);
  2333. }
  2334. }
  2335. return NO_AREA;
  2336. }
  2337. /*-------------------------------------------------------------------------*//**
  2338. * <param name="area">Area to set for.</param>
  2339. * <param name="playerid">Player to set for.</param>
  2340. * <param name="set">Wether or not the player can use the area.</param>
  2341. *//*------------------------------------------------------------------------**/
  2342. foreign void:Area_SetPlayer(area, playerid, bool:set);
  2343. global void:Area_SetPlayer(area, playerid, bool:set)
  2344. {
  2345. if (Area_IsActive(area))
  2346. {
  2347. PA_Set(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid, set);
  2348. //return 1;
  2349. }
  2350. //return 0;
  2351. }
  2352. /*-------------------------------------------------------------------------*//**
  2353. * <param name="area">Area to get for.</param>
  2354. * <param name="playerid">Player to get for.</param>
  2355. * <remarks>
  2356. * Can the player USE this area (not are they in it)?
  2357. * </remarks>
  2358. *//*------------------------------------------------------------------------**/
  2359. foreign bool:Area_GetPlayer(area, playerid);
  2360. global bool:Area_GetPlayer(area, playerid)
  2361. {
  2362. if (Area_IsActive(area))
  2363. {
  2364. return PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid);
  2365. }
  2366. return false;
  2367. }
  2368. /*-------------------------------------------------------------------------*//**
  2369. * <param name="area">Area to set for.</param>
  2370. * <param name="world">World to set for.</param>
  2371. * <param name="set">Wether or not the area is active in this world.</param>
  2372. *//*------------------------------------------------------------------------**/
  2373. foreign void:Area_SetWorld(area, world, bool:set);
  2374. global void:Area_SetWorld(area, world, bool:set)
  2375. {
  2376. #if AREA_WORLDS > 0
  2377. if (Area_IsActive(area))
  2378. {
  2379. Bit_Set(YSI_g_sAreas[area][E_AREA_WORLDS], world, set);
  2380. //return 1;
  2381. }
  2382. #else
  2383. #pragma unused area, world, set
  2384. #endif
  2385. //return 0;
  2386. }
  2387. /*-------------------------------------------------------------------------*//**
  2388. * <param name="area">Area to set for.</param>
  2389. * <param name="world">World to set for.</param>
  2390. *//*------------------------------------------------------------------------**/
  2391. foreign bool:Area_GetWorld(area, world);
  2392. global bool:Area_GetWorld(area, world)
  2393. {
  2394. #if AREA_WORLDS > 0
  2395. if (Area_IsActive(area))
  2396. {
  2397. return Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world);
  2398. }
  2399. return false;
  2400. #else
  2401. #pragma unused area, world
  2402. return true;
  2403. #endif
  2404. }
  2405. /*-------------------------------------------------------------------------*//**
  2406. * <param name="area">Area to set for.</param>
  2407. * <param name="set">Wether or not all players can use this area.</param>
  2408. *//*------------------------------------------------------------------------**/
  2409. foreign void:Area_SetAllPlayers(area, bool:set);
  2410. global void:Area_SetAllPlayers(area, bool:set)
  2411. {
  2412. if (Area_IsActive(area))
  2413. {
  2414. PA_Init(YSI_g_sAreas[area][E_AREA_PLAYERS], set);
  2415. //return 1;
  2416. }
  2417. //return 0;
  2418. }
  2419. /*-------------------------------------------------------------------------*//**
  2420. * <param name="area">Area to check.</param>
  2421. * <returns>
  2422. * Is the passed area valid and active.
  2423. * </returns>
  2424. *//*------------------------------------------------------------------------**/
  2425. foreign bool:Area_IsValid(area);
  2426. global bool:Area_IsValid(area)
  2427. {
  2428. return bool:Area_IsActive(area);
  2429. }
  2430. /*-------------------------------------------------------------------------*//**
  2431. * <param name="area">Area to check.</param>
  2432. * <returns>
  2433. * Is the passed area valid and empty.
  2434. * </returns>
  2435. * <remarks>
  2436. * Currently very slow as it has to loop through multiple players! I may add
  2437. * an entry counter to zones to make this O(1) instead of O(nm).
  2438. * </remarks>
  2439. *//*------------------------------------------------------------------------**/
  2440. foreign bool:Area_IsEmpty(area);
  2441. global bool:Area_IsEmpty(area)
  2442. {
  2443. new
  2444. z;
  2445. if (Area_IsActive(area))
  2446. {
  2447. foreach (new playerid : Player)
  2448. {
  2449. for (new i = 0; ; ++i)
  2450. {
  2451. z = _Area_GetPlayerAreas(playerid, i);
  2452. if (z == NO_AREA)
  2453. {
  2454. break;
  2455. }
  2456. else if (z == area)
  2457. {
  2458. return false;
  2459. }
  2460. }
  2461. }
  2462. }
  2463. return true;
  2464. }
  2465. /*-------------------------------------------------------------------------*//**
  2466. * <param name="area">Area to set for.</param>
  2467. * <param name="callback">Callback to use.</param>
  2468. * <remarks>
  2469. * Adds a y_inline style callback (publics included) to an area to be called
  2470. * when a player enters it. This is NOT a remote function and instead records
  2471. * the data locally to call functions in the correct script (or they'll just
  2472. * end up crashing as you will be jumping to an arbitrary address in a script
  2473. * that doesn't have sensible code at that address.
  2474. * </remarks>
  2475. *//*------------------------------------------------------------------------**/
  2476. /*-------------------------------------------------------------------------*//**
  2477. * <param name="playerid">The player that just entered the area.</param>
  2478. * <param name="areaid">The area they entered.</param>
  2479. *//*------------------------------------------------------------------------**/
  2480. static stock Area_DoEnter(playerid, areaid, &idx)
  2481. {
  2482. // Save their area to the list of areas that they are currently in.
  2483. //YSI_g_sPlayerArea[playerid] = sCur;
  2484. _Area_SetPlayerAreas(playerid, idx++, areaid);
  2485. // Call the callback in all scripts.
  2486. CallRemoteFunction("OnPlayerEnterArea", "ii", playerid, areaid);
  2487. //broadcastfunc _Area_DoEnter(playerid, areaid);
  2488. }
  2489. /*remotefunc _Area_DoEnter(playerid, areaid)
  2490. {
  2491. if (YSI_g_sHasCallbacks & 1)
  2492. {
  2493. CallLocalFunction("OnPlayerEnterArea", "ii", playerid, areaid);
  2494. }
  2495. if (YSI_g_sHasCallbacks & 4)
  2496. {
  2497. //Hook_OnPlayerEnterArea(playerid, areaid);
  2498. }
  2499. return 1;
  2500. }*/
  2501. forward OnPlayerEnterArea(playerid, areaid);
  2502. /*-------------------------------------------------------------------------*//**
  2503. * <param name="playerid">The player that just left the area.</param>
  2504. * <param name="areaid">The area they left.</param>
  2505. *//*------------------------------------------------------------------------**/
  2506. //remotefunc Area_DoLeave(playerid, areaid)
  2507. static stock Area_DoLeave(playerid, areaid, idx)
  2508. {
  2509. // Remove this area from the list of areas.
  2510. new
  2511. cur;
  2512. // Shift up the zones.
  2513. while ((cur = _Area_GetPlayerAreas(playerid, idx + 1)) != NO_AREA)
  2514. {
  2515. _Area_SetPlayerAreas(playerid, idx++, cur);
  2516. }
  2517. _Area_SetPlayerAreas(playerid, idx, NO_AREA);
  2518. // Call the callback.
  2519. CallRemoteFunction("OnPlayerLeaveArea", "ii", playerid, areaid);
  2520. /*if (YSI_g_sHasCallbacks & 2)
  2521. {
  2522. CallLocalFunction("OnPlayerLeaveArea", "ii", playerid, areaid);
  2523. }
  2524. if (YSI_g_sHasCallbacks & 8)
  2525. {
  2526. //Hook_OnPlayerLeaveArea(playerid, areaid);
  2527. }*/
  2528. return 1;
  2529. }
  2530. forward OnPlayerLeaveArea(playerid, areaid);
  2531. #undef _GROUP_MAKE_LIMIT
  2532. #undef _GROUP_MAKE_NAME
  2533. #include "..\YSI_Core\y_master"