y_areas.inc 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203
  1. /*----------------------------------------------------------------------------*-
  2. =============================
  3. Y Sever Includes - Areas Core
  4. =============================
  5. Description:
  6. Handles area checks for player location based code not involving CPs.
  7. Legal:
  8. Copyright (C) 2007 Alex "Y_Less" Cole
  9. This program is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU General Public License
  11. as published by the Free Software Foundation; either version 2
  12. of the License, or (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  20. MA 02110-1301, USA.
  21. Version:
  22. 0.1
  23. Changelog:
  24. 27/08/07:
  25. Made master compatible.
  26. 03/08/07:
  27. Updated timer system.
  28. 31/07/07:
  29. Made Area_GetPlayerArea safe.
  30. 08/05/07:
  31. First version.
  32. Functions:
  33. Public:
  34. Area_Loop - Main loop for checking who's where.
  35. Area_Remote - Does minor functions remotely.
  36. Area_AddRemote - Adds areas remotely.
  37. YSIM_Areas - Master system interface.
  38. Area_Broadcast - Recieves transmitted areas.
  39. Area_UpdateEmpty - Resets the empty array after master change.
  40. Core:
  41. Area_Area - Constructor.
  42. Area_CheckArea - Gets an area's type anx calls the relevant function.
  43. Area_OnPlayerConnect - Called when a player connects.
  44. Stock:
  45. Area_Delete - Deletes an area.
  46. Area_AddCube - Adds a cube.
  47. Area_AddBox - Adds a box.
  48. Area_AddCircle - Adds a circle.
  49. Area_AddSphere - Adds a sphere.
  50. Area_AddPoly - Adds a polygon.
  51. Area_GetPlayerArea - Gets the area a player is in.
  52. Area_SetPlayer - Sets wether a player can use this area.
  53. Area_SetAllPlayers - Sets wether all players can use this area.
  54. Area_SetAllWorlds - Sets wether all worlds have this are.
  55. Area_SetWorld - Sets wether this world has this area.
  56. Area_IsValid - Checks if an area is valid.
  57. Static:
  58. Area_IsInCircle - Checks if a player is in this circular area.
  59. Area_IsInSphere - Checks if a player is in this spherical area.
  60. Area_IsInPoly - Checks if a player is in this polygonal area.
  61. Area_IsInCube - Checks if a player is in this cubic area.
  62. Area_IsInBox - Checks if a player is in this rectangular area.
  63. Area_AddToUnused - Adds a area pointer to the unused list.
  64. Area_GetFreeSlot - Gets the next free area slot.
  65. Inline:
  66. Area_IsActive - Checks if an area is active.
  67. Area_GetEmptySlotCount - Gets the number of empty slots.
  68. Area_AddSlots - Removes slots from the unused count.
  69. API:
  70. -
  71. Callbacks:
  72. OnPlayerEnterArea - Called when a player enters an area.
  73. OnPlayerLeaveArea - Called when a player leaves an area.
  74. Definitions:
  75. MAX_AREAS - Max number of areas.
  76. NO_AREA - Fail return.
  77. SINGLE_SLOT_AREA - Marker for only one part to the area.
  78. AREA_NO_NEXT - Marker for end of a list.
  79. AREA_WORLDS - Number of worlds an area can be in.
  80. AREA_WORLD_COUNT - Number of cells required for a bit array of AREA_WORLDS.
  81. Enums:
  82. e_AREA_FLAGS - Flags for each area.
  83. E_AREA - Structure for part of an areas data.
  84. Macros:
  85. -
  86. Tags:
  87. -
  88. Variables:
  89. Global:
  90. -
  91. Static:
  92. YSI_g_sUnusedAreas - Pointer to the first unused area.
  93. YSI_g_sLastUnused - Pointer to the last unused area.
  94. YSI_g_sFreeCount - Number of unused slots.
  95. YSI_g_sAreas - Array of area data.
  96. YSI_g_sPlayerArea - Array of players' current areas.
  97. Commands:
  98. -
  99. Compile options:
  100. -
  101. Operators:
  102. -
  103. -*----------------------------------------------------------------------------*/
  104. #include "internal\y_version"
  105. #include "y_bit"
  106. #include "y_playerarray"
  107. #include "y_iterate"
  108. #include "y_debug"
  109. #include "y_inline"
  110. #include "y_remote"
  111. #if defined AREAS_USE_TIMER
  112. #include "y_timers"
  113. #endif
  114. #include "internal\y_natives"
  115. #if !defined MAX_AREAS
  116. #define MAX_AREAS (1024)
  117. #elseif MAX_AREAS >= 0x1FFF
  118. #error This version does not support more than 8190 areas
  119. #endif
  120. #define _GROUP_MAKE_NAME_AREAS<%0...%1> %0Area%1
  121. #define _GROUP_MAKE_LIMIT_AREAS MAX_AREAS
  122. #include "y_groups"
  123. #define YSIM_U_DISABLE
  124. #include "y_master"
  125. #include "y_hooks"
  126. #define NO_AREA (-1)
  127. #define SINGLE_SLOT_AREA (e_AREA_FLAGS_NEXT)
  128. #define AREA_NO_NEXT (_:e_AREA_FLAGS_NEXT)
  129. #if !defined AREAS_ZONE_SIZE
  130. #define AREAS_ZONE_SIZE 500
  131. #endif
  132. #if !defined AREAS_ZONE_BOUNDS
  133. #define AREAS_ZONE_BOUNDS 4000
  134. #endif
  135. #define AREAS_ZONE_ARRAY (ceildiv(AREAS_ZONE_BOUNDS * 2, AREAS_ZONE_SIZE))
  136. #if !defined AREA_WORLDS
  137. #define AREA_WORLDS 256
  138. #endif
  139. #define AREAS_ZONE_PARTS (ceildiv(AREAS_ZONE_BOUNDS, AREAS_ZONE_SIZE))
  140. #define Area_MakeZone(%0) (floatround((%0) / AREAS_ZONE_SIZE.0, floatround_floor)) // - AREAS_ZONE_PARTS)
  141. #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<<14)&e_AREA_FLAGS_COUNT),%0=%1
  142. //#define _AREAS_ZONES_O(%0) return e_AREA_ZONE_O_%0
  143. //#define _AREAS_ZONES_I(%0) return e_AREA_ZONE_I_%0
  144. //#define _AREAS_ZONES_X(%0) return e_AREA_ZONE_X_%0
  145. #define _AREAS_ZONES_O(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneO%0,area,last,e_AREA_ZONE_O_%0)
  146. #define _AREAS_ZONES_I(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneI%0,area,last,e_AREA_ZONE_I_%0)
  147. #define _AREAS_ZONES_X(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneX%0,area,last,e_AREA_ZONE_X_%0)
  148. #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)
  149. #define _AREAS_MAKE_ZONE(%0,%1) %1+=((%0)+AREAS_ZONE_PARTS)*AREAS_ZONE_ARRAY+AREAS_ZONE_PARTS
  150. #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))
  151. #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_REST|(e_AREA_FLAGS:%2&e_AREA_FLAGS_NEXT))))
  152. enum e_AREA_FLAGS
  153. {
  154. e_AREA_FLAGS_NEXT = 0x2000 - 1 << 0, //0x00001FFF,
  155. e_AREA_FLAGS_COUNT = 0x2000 - 1 << 14, //0x07FFC000,
  156. e_AREA_FLAGS_REST = ~(e_AREA_FLAGS_NEXT | e_AREA_FLAGS_COUNT),
  157. //e_AREA_FLAGS_TYPE = 0x38000000,
  158. e_AREA_FLAGS_SPHERE = 1 << 27, //0x08000000,
  159. e_AREA_FLAGS_POLY = 2 << 27, //0x10000000,
  160. e_AREA_FLAGS_CUBE = 3 << 27, //0x18000000,
  161. e_AREA_FLAGS_BOX = 4 << 27, //0x20000000,
  162. e_AREA_FLAGS_CIRCLE = 5 << 27, //0x28000000,
  163. e_AREA_FLAGS_RES_0 = 6 << 27, //0x28000000,
  164. e_AREA_FLAGS_TYPE = 7 << 27, //0x28000000,
  165. e_AREA_FLAGS_ACTIVE = 1 << 30,
  166. e_AREA_FLAGS_USED = 1 << 31
  167. }
  168. enum (+= -1)
  169. {
  170. e_AREA_ZONE_I_N = -1,
  171. e_AREA_ZONE_I_NE, // -2
  172. e_AREA_ZONE_I_E, // -3
  173. e_AREA_ZONE_I_SE, // -4
  174. e_AREA_ZONE_I_S, // -5
  175. e_AREA_ZONE_I_SW, // -6
  176. e_AREA_ZONE_I_W, // -7
  177. e_AREA_ZONE_I_NW, // -8
  178. e_AREA_ZONE_I_, // -9
  179. // "Outer" zones. -4000 > x, y > 4000;
  180. e_AREA_ZONE_O_N, // -10
  181. e_AREA_ZONE_O_NE, // -11
  182. e_AREA_ZONE_O_E, // -12
  183. e_AREA_ZONE_O_SE, // -13
  184. e_AREA_ZONE_O_S, // -14
  185. e_AREA_ZONE_O_SW, // -15
  186. e_AREA_ZONE_O_W, // -16
  187. e_AREA_ZONE_O_NW, // -17
  188. //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
  189. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  190. e_AREA_ZONE_X_N, // -18
  191. e_AREA_ZONE_X_NE, // -19
  192. e_AREA_ZONE_X_E, // -20
  193. e_AREA_ZONE_X_SE, // -21
  194. e_AREA_ZONE_X_S, // -22
  195. e_AREA_ZONE_X_SW, // -23
  196. e_AREA_ZONE_X_W, // -24
  197. e_AREA_ZONE_X_NW, // -25
  198. // Extra zones. For when areas are too big for a quadrant.
  199. e_AREA_ZONE_X_, // -26
  200. e_AREA_ZONE_NONE = cellmin
  201. }
  202. enum E_AREA
  203. {
  204. e_AREA_FLAGS:E_AREA_FLAGS,
  205. #if AREA_WORLDS > 0
  206. BitArray:E_AREA_WORLDS<AREA_WORLDS>,
  207. #endif
  208. #if YSIM_HAS_MASTER
  209. E_AREA_MASTER,
  210. #endif
  211. PlayerArray:E_AREA_PLAYERS<MAX_PLAYERS>,
  212. Float:E_AREA_POS[4]
  213. }
  214. static stock
  215. YSI_g_sUnusedAreas = 0,
  216. //YSI_g_sLastUnused = MAX_AREAS - 1,
  217. YSI_g_sFreeCount = MAX_AREAS,
  218. YSI_g_sAreas[MAX_AREAS][E_AREA],
  219. YSI_g_sPlayerArea[MAX_PLAYERS] = {NO_AREA, ...},
  220. YSI_g_sHasCallbacks,
  221. YSI_g_sZones[AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY] = {AREA_NO_NEXT, ...},
  222. // "Inner" zones. -4000 <= x, y <= 4000; Z(x) != Z(y)
  223. YSI_g_sZoneIN = AREA_NO_NEXT, // -1
  224. YSI_g_sZoneINE = AREA_NO_NEXT, // -2
  225. YSI_g_sZoneIE = AREA_NO_NEXT, // -3
  226. YSI_g_sZoneISE = AREA_NO_NEXT, // -4
  227. YSI_g_sZoneIS = AREA_NO_NEXT, // -5
  228. YSI_g_sZoneISW = AREA_NO_NEXT, // -6
  229. YSI_g_sZoneIW = AREA_NO_NEXT, // -7
  230. YSI_g_sZoneINW = AREA_NO_NEXT, // -8
  231. // "Outer" zones. -4000 > x, y > 4000;
  232. YSI_g_sZoneON = AREA_NO_NEXT, // -9
  233. YSI_g_sZoneONE = AREA_NO_NEXT, // -10
  234. YSI_g_sZoneOE = AREA_NO_NEXT, // -11
  235. YSI_g_sZoneOSE = AREA_NO_NEXT, // -12
  236. YSI_g_sZoneOS = AREA_NO_NEXT, // -13
  237. YSI_g_sZoneOSW = AREA_NO_NEXT, // -14
  238. YSI_g_sZoneOW = AREA_NO_NEXT, // -15
  239. YSI_g_sZoneONW = AREA_NO_NEXT, // -16
  240. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  241. YSI_g_sZoneXN = AREA_NO_NEXT, // -17
  242. YSI_g_sZoneXNE = AREA_NO_NEXT, // -18
  243. YSI_g_sZoneXE = AREA_NO_NEXT, // -19
  244. YSI_g_sZoneXSE = AREA_NO_NEXT, // -20
  245. YSI_g_sZoneXS = AREA_NO_NEXT, // -21
  246. YSI_g_sZoneXSW = AREA_NO_NEXT, // -22
  247. YSI_g_sZoneXW = AREA_NO_NEXT, // -23
  248. YSI_g_sZoneXNW = AREA_NO_NEXT, // -24
  249. // Extra zones. For when areas are too big for a quadrant.
  250. YSI_g_sZoneI = AREA_NO_NEXT, // -25
  251. //YSI_g_sZoneO = AREA_NO_NEXT, // -26
  252. YSI_g_sZoneX = AREA_NO_NEXT; // -27
  253. forward Area_Loop();
  254. /*----------------------------------------------------------------------------*-
  255. Function:
  256. OnScriptInit
  257. Params:
  258. -
  259. Return:
  260. -
  261. Notes:
  262. Sets up required variables. Note that this hooks "OnScriptInit",
  263. "OnGameModeInit" and "OnFilterScript". This is because ALL scripts need to
  264. initialise some things, and only the master needs to initialise others.
  265. -*----------------------------------------------------------------------------*/
  266. mhook OnScriptInit()
  267. {
  268. for (new i = 0; i != MAX_AREAS - 1; ++i)
  269. {
  270. YSI_g_sAreas[i][E_AREA_FLAGS] = e_AREA_FLAGS:(i + 1);
  271. }
  272. YSI_g_sAreas[MAX_AREAS - 1][E_AREA_FLAGS] = e_AREA_FLAGS:AREA_NO_NEXT;
  273. //for (new i = 0; i != AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY; ++i)
  274. //{
  275. // YSI_g_sZones[i] = -1;
  276. //}
  277. return 1;
  278. }
  279. #if !defined FILTERSCRIPT
  280. hook OnGameModeInit()
  281. {
  282. if (!YSI_FILTERSCRIPT)
  283. {
  284. new
  285. buffer;
  286. YSI_g_sHasCallbacks = 0;
  287. YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
  288. YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
  289. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
  290. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
  291. }
  292. }
  293. #endif
  294. hook OnFilterScriptInit()
  295. {
  296. new
  297. buffer;
  298. YSI_g_sHasCallbacks = 0;
  299. YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
  300. YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
  301. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
  302. YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
  303. }
  304. /*----------------------------------------------------------------------------*-
  305. Function:
  306. Area_GetEmptySlotCount
  307. Params:
  308. -
  309. Return:
  310. Number of unused area slots.
  311. Notes:
  312. -
  313. -*----------------------------------------------------------------------------*/
  314. #define Area_GetEmptySlotCount() \
  315. (YSI_g_sFreeCount)
  316. /*----------------------------------------------------------------------------*-
  317. Function:
  318. Area_AddSlots
  319. Params:
  320. num - Number of slots to add.
  321. Return:
  322. -
  323. Notes:
  324. Actually removes slots from the unused count.
  325. -*----------------------------------------------------------------------------*/
  326. #define Area_AddSlots(%1) \
  327. YSI_g_sFreeCount -= (%1)
  328. /*----------------------------------------------------------------------------*-
  329. Function:
  330. Area_IsActive
  331. Params:
  332. area - Area to check validity of
  333. Return:
  334. -
  335. Notes:
  336. An area slot could be used but still invalid if it's not the first slot in
  337. an area set.
  338. -*----------------------------------------------------------------------------*/
  339. #define Area_IsActive(%1) \
  340. ((%1) >= 0 && (%1) < MAX_AREAS && (YSI_g_sAreas[(%1)][E_AREA_FLAGS] & e_AREA_FLAGS_ACTIVE))
  341. /*----------------------------------------------------------------------------*-
  342. Function:
  343. Area_GetFreeSlot
  344. Params:
  345. -
  346. Return:
  347. Next available slot.
  348. Notes:
  349. Gets an empty slot, removes it from the unused list and returs a pointer.
  350. -*----------------------------------------------------------------------------*/
  351. static stock Area_GetFreeSlot()
  352. {
  353. P:4("Area_GetFreeSlot called");
  354. if (YSI_g_sUnusedAreas == AREA_NO_NEXT) return NO_AREA;
  355. P:7("Area_GetFreeSlot: 1");
  356. new
  357. old = YSI_g_sUnusedAreas;
  358. YSI_g_sUnusedAreas = YSI_g_sAreas[old][E_AREA_FLAGS];
  359. --YSI_g_sFreeCount;
  360. return old;
  361. }
  362. /*----------------------------------------------------------------------------*-
  363. Function:
  364. Area_Delete
  365. Params:
  366. area - Area to remove from the list.
  367. Return:
  368. -
  369. Notes:
  370. You can only remove areas which are at the start of a list.
  371. -*----------------------------------------------------------------------------*/
  372. foreign Area_Delete(area);
  373. global Area_Delete(area)
  374. {
  375. if (!Area_IsActive(area))
  376. {
  377. return 0;
  378. }
  379. new
  380. e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
  381. switch (flags & e_AREA_FLAGS_TYPE)
  382. {
  383. case e_AREA_FLAGS_CUBE:
  384. {
  385. // Two blocks used - simple.
  386. new
  387. second = _:(flags & e_AREA_FLAGS_NEXT);
  388. flags = YSI_g_sAreas[second][E_AREA_FLAGS];
  389. YSI_g_sAreas[second][E_AREA_FLAGS] = e_AREA_FLAGS:YSI_g_sUnusedAreas;
  390. YSI_g_sAreas[area][E_AREA_FLAGS] = e_AREA_FLAGS:second;
  391. YSI_g_sUnusedAreas = area;
  392. YSI_g_sFreeCount += 2;
  393. // Remove this one from the zone it was in.
  394. }
  395. case e_AREA_FLAGS_POLY:
  396. {
  397. // Many blocks used - hard.
  398. new
  399. count = _:(flags & e_AREA_FLAGS_COUNT) >> 14,
  400. next = _:(YSI_g_sAreas[area][E_AREA_FLAGS] = flags & e_AREA_FLAGS_NEXT);
  401. count = ceildiv(count, 4);
  402. YSI_g_sFreeCount += count;
  403. while (--count)
  404. {
  405. next = _:(YSI_g_sAreas[next][E_AREA_FLAGS] = YSI_g_sAreas[next][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);
  406. }
  407. flags = YSI_g_sAreas[next][E_AREA_FLAGS];
  408. YSI_g_sAreas[next][E_AREA_FLAGS] = e_AREA_FLAGS:YSI_g_sUnusedAreas;
  409. YSI_g_sUnusedAreas = area;
  410. }
  411. default:
  412. {
  413. // Only one block used - easy.
  414. YSI_g_sAreas[area][E_AREA_FLAGS] = e_AREA_FLAGS:YSI_g_sUnusedAreas;
  415. YSI_g_sUnusedAreas = area;
  416. ++YSI_g_sFreeCount;
  417. // Remove this one from the zone it was in.
  418. }
  419. }
  420. Area_DoRemove(_:(flags & e_AREA_FLAGS_COUNT), area, _:(flags & e_AREA_FLAGS_NEXT));
  421. return 1;
  422. }
  423. /*----------------------------------------------------------------------------*-
  424. Function:
  425. Area_DoRemove
  426. Params:
  427. zone - The zone this area is in (right shifted 14).
  428. start - The first of the allocated areas being removed.
  429. end - The area in this zone after the last removed one.
  430. Return:
  431. -
  432. Notes:
  433. Very tightly integrated with "Area_Delete", to the point where I could just
  434. make them one function if I wanted (but I won't).
  435. -*----------------------------------------------------------------------------*/
  436. static stock Area_DoRemove(zone, start, end)
  437. {
  438. //printf("remove %d %d %d %d", zone << 14, start, end, (e_AREA_ZONE_I_ << 14 & _:e_AREA_FLAGS_COUNT));
  439. // Actually "zone << 14", but that's not important.
  440. switch (zone)
  441. {
  442. case (e_AREA_ZONE_I_N << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneIN, start, end);}
  443. case (e_AREA_ZONE_I_NE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneINE, start, end);}
  444. case (e_AREA_ZONE_I_E << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneIE, start, end);}
  445. case (e_AREA_ZONE_I_SE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneISE, start, end);}
  446. case (e_AREA_ZONE_I_S << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneIS, start, end);}
  447. case (e_AREA_ZONE_I_SW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneISW, start, end);}
  448. case (e_AREA_ZONE_I_W << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneIW, start, end);}
  449. case (e_AREA_ZONE_I_NW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneINW, start, end);}
  450. case (e_AREA_ZONE_I_ << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneI, start, end);}
  451. // "Outer" zones. -4000 > x, y > 4000;
  452. case (e_AREA_ZONE_O_N << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneON, start, end);}
  453. case (e_AREA_ZONE_O_NE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneONE, start, end);}
  454. case (e_AREA_ZONE_O_E << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneOE, start, end);}
  455. case (e_AREA_ZONE_O_SE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneOSE, start, end);}
  456. case (e_AREA_ZONE_O_S << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneOS, start, end);}
  457. case (e_AREA_ZONE_O_SW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneOSW, start, end);}
  458. case (e_AREA_ZONE_O_W << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneOW, start, end);}
  459. case (e_AREA_ZONE_O_NW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneONW, start, end);}
  460. //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
  461. // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
  462. case (e_AREA_ZONE_X_N << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXN, start, end);}
  463. case (e_AREA_ZONE_X_NE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXNE, start, end);}
  464. case (e_AREA_ZONE_X_E << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXE, start, end);}
  465. case (e_AREA_ZONE_X_SE << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXSE, start, end);}
  466. case (e_AREA_ZONE_X_S << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXS, start, end);}
  467. case (e_AREA_ZONE_X_SW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXSW, start, end);}
  468. case (e_AREA_ZONE_X_W << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXW, start, end);}
  469. case (e_AREA_ZONE_X_NW << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneXNW, start, end);}
  470. // Extra zones. For when areas are too big for a quadrant.
  471. case (e_AREA_ZONE_X_ << 14 & _:e_AREA_FLAGS_COUNT): {_AREAS_DO_REMOVE(YSI_g_sZoneX, start, end);}
  472. default: {_AREAS_DO_REMOVE(YSI_g_sZones[zone], start, end);}
  473. }
  474. return 0;
  475. }
  476. /*----------------------------------------------------------------------------*-
  477. Function:
  478. Area_GetZones
  479. Params:
  480. Float:x - Start of an area.
  481. Float:y - Start of an area.
  482. Return:
  483. All the zones this position overlaps.
  484. Notes:
  485. The most zones you can be in at once is 9 - I_, I_S, I_E, I_SE, X_, X_S,
  486. X_E, X_SE, Z_ (or similar corners - NOT in O_ though).
  487. -*----------------------------------------------------------------------------*/
  488. static stock Area_GetZones(Float:x, Float:y)
  489. {
  490. // Always end with e_AREA_ZONE_X_ as they will ALWAYS be in that one (that's
  491. // basically everywhere and means the area exists somewhere ever). Once
  492. // that zone is detected, stop next loop.
  493. static const
  494. scZones[16][9] =
  495. {
  496. {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},
  497. {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},
  498. {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},
  499. {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},
  500. {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},
  501. {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_ },
  502. {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_ },
  503. {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},
  504. {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},
  505. {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_ },
  506. {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_ },
  507. {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},
  508. {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},
  509. {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},
  510. {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},
  511. {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}
  512. };
  513. if (AREAS_ZONE_BOUNDS.0 <= x)
  514. {
  515. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 0];
  516. else if (0.0 <= y) return scZones[ 1];
  517. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 2];
  518. else return scZones[ 3];
  519. }
  520. else if (0.0 <= x)
  521. {
  522. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 4];
  523. else if (0.0 <= y) return scZones[ 5]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  524. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 6]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  525. else return scZones[ 7];
  526. }
  527. else if (-AREAS_ZONE_BOUNDS.0 <= x)
  528. {
  529. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 8];
  530. else if (0.0 <= y) return scZones[ 9]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  531. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[10]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
  532. else return scZones[11];
  533. }
  534. else
  535. {
  536. if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[12];
  537. else if (0.0 <= y) return scZones[13];
  538. else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[14];
  539. else return scZones[15];
  540. }
  541. }
  542. /*----------------------------------------------------------------------------*-
  543. Function:
  544. Area_DetermineZone
  545. Params:
  546. Float:minx - Start of an area.
  547. Float:miny - Start of an area.
  548. Float:maxx - End of an area.
  549. Float:maxy - End of an area.
  550. area - The area to add to the determined zone.
  551. last - The last slot that makes up the current zone.
  552. Return:
  553. -
  554. Notes:
  555. Finds the smallest zone that this area will fit in completely.
  556. -*----------------------------------------------------------------------------*/
  557. static stock Area_DetermineZone(Float:minx, Float:miny, Float:maxx, Float:maxy, area, last)
  558. {
  559. new
  560. zx,
  561. zy;
  562. // This optimises based on the fact that (by definition) maxx can't be lower
  563. // than minx and maxy can't be lower than miny, meaning we can skip certain
  564. // checks in some cases.
  565. if (AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
  566. {
  567. if (0.0 <= miny) // Southern edge.
  568. {
  569. _AREAS_ZONES_O(NE);
  570. //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<<14)&e_AREA_FLAGS_COUNT),YSI_g_sZoneXNE=area;
  571. //return _AREAS_ADD_TO_ZONE(YSI_g_sZoneXNE,area,last,e_AREA_ZONE_X_NE)
  572. }
  573. else // Southern edge.
  574. {
  575. if (0.0 <= maxy) // Northern edge.
  576. {
  577. _AREAS_ZONES_O(E);
  578. }
  579. else // Northern edge.
  580. {
  581. _AREAS_ZONES_O(SE);
  582. }
  583. }
  584. }
  585. else if (0.0 <= minx) // Western edge.
  586. {
  587. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  588. {
  589. _AREAS_ZONES_O(NE);
  590. }
  591. else if (0.0 <= miny) // Southern edge.
  592. {
  593. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  594. {
  595. _AREAS_ZONES_X(NE);
  596. }
  597. else // Eastern edge.
  598. {
  599. // Interesting case - y > 0, 0 <= x < 4000.
  600. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  601. {
  602. _AREAS_ZONES_X(NE);
  603. }
  604. else // Northern edge.
  605. {
  606. //_AREAS_ZONES_I_GRID;
  607. zx = Area_MakeZone(minx);
  608. zy = Area_MakeZone(miny);
  609. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  610. {
  611. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  612. YSI_g_sAreas[last][E_AREA_FLAGS] =
  613. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  614. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  615. (e_AREA_FLAGS:(zy << 14) & e_AREA_FLAGS_COUNT);
  616. P:7("Area_DetermineZone: Added to North-Eastern square");
  617. return YSI_g_sZones[zy] = area;
  618. }
  619. _AREAS_ZONES_I(NE);
  620. }
  621. }
  622. }
  623. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  624. {
  625. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  626. {
  627. if (0.0 <= maxy) // Northern edge.
  628. {
  629. _AREAS_ZONES_X(E);
  630. }
  631. else // Northern edge.
  632. {
  633. _AREAS_ZONES_X(SE);
  634. }
  635. }
  636. else // Eastern edge.
  637. {
  638. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  639. {
  640. _AREAS_ZONES_X(E);
  641. }
  642. if (0.0 <= maxy) // Northern edge.
  643. {
  644. _AREAS_ZONES_I(E);
  645. }
  646. else // Northern edge.
  647. {
  648. zx = Area_MakeZone(minx);
  649. zy = Area_MakeZone(miny);
  650. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  651. {
  652. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  653. YSI_g_sAreas[last][E_AREA_FLAGS] =
  654. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  655. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  656. (e_AREA_FLAGS:(zy << 14) & e_AREA_FLAGS_COUNT);
  657. return YSI_g_sZones[zy] = area;
  658. }
  659. _AREAS_ZONES_I(SE);
  660. }
  661. }
  662. }
  663. else // Southern edge.
  664. {
  665. if (0.0 <= maxy) // Northern edge.
  666. {
  667. _AREAS_ZONES_X(E);
  668. }
  669. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  670. {
  671. _AREAS_ZONES_X(SE);
  672. }
  673. else // Northern edge.
  674. {
  675. _AREAS_ZONES_O(SE);
  676. }
  677. }
  678. }
  679. else if (-AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
  680. {
  681. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  682. {
  683. if (0.0 <= maxx) // Eastern edge.
  684. {
  685. _AREAS_ZONES_O(N);
  686. }
  687. else // Eastern edge.
  688. {
  689. _AREAS_ZONES_O(NW);
  690. }
  691. }
  692. else if (0.0 <= miny) // Southern edge.
  693. {
  694. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  695. {
  696. _AREAS_ZONES_X(N);
  697. }
  698. else if (0.0 <= maxx) // Eastern edge.
  699. {
  700. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  701. {
  702. _AREAS_ZONES_X(N);
  703. }
  704. else // Northern edge.
  705. {
  706. _AREAS_ZONES_I(N);
  707. }
  708. }
  709. else // Eastern edge.
  710. {
  711. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  712. {
  713. _AREAS_ZONES_X(NW);
  714. }
  715. else // Northern edge.
  716. {
  717. zx = Area_MakeZone(minx);
  718. zy = Area_MakeZone(miny);
  719. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  720. {
  721. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  722. YSI_g_sAreas[last][E_AREA_FLAGS] =
  723. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  724. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  725. (e_AREA_FLAGS:(zy << 14) & e_AREA_FLAGS_COUNT);
  726. return YSI_g_sZones[zy] = area;
  727. }
  728. _AREAS_ZONES_I(NW);
  729. }
  730. }
  731. }
  732. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  733. {
  734. if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  735. {
  736. if (0.0 <= maxy) // Northern edge.
  737. {
  738. _AREAS_ZONES_X();
  739. }
  740. else // Northern edge.
  741. {
  742. _AREAS_ZONES_X(S);
  743. }
  744. }
  745. else if (0.0 <= maxx) // Eastern edge.
  746. {
  747. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  748. {
  749. _AREAS_ZONES_X();
  750. }
  751. else if (0.0 <= maxy) // Northern edge.
  752. {
  753. _AREAS_ZONES_I();
  754. }
  755. else // Northern edge.
  756. {
  757. _AREAS_ZONES_I(S);
  758. }
  759. }
  760. else // Eastern edge.
  761. {
  762. if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  763. {
  764. _AREAS_ZONES_X(W);
  765. }
  766. else if (0.0 <= maxy) // Northern edge.
  767. {
  768. _AREAS_ZONES_I(W);
  769. }
  770. else // Northern edge.
  771. {
  772. zx = Area_MakeZone(minx);
  773. zy = Area_MakeZone(miny);
  774. if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
  775. {
  776. zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
  777. YSI_g_sAreas[last][E_AREA_FLAGS] =
  778. (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
  779. (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
  780. (e_AREA_FLAGS:(zy << 14) & e_AREA_FLAGS_COUNT);
  781. return YSI_g_sZones[zy] = area;
  782. }
  783. _AREAS_ZONES_I(SW);
  784. }
  785. }
  786. }
  787. else // Southern edge.
  788. {
  789. if (0.0 <= maxx) // Eastern edge.
  790. {
  791. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  792. {
  793. _AREAS_ZONES_X(S);
  794. }
  795. else // Northern edge.
  796. {
  797. _AREAS_ZONES_O(S);
  798. }
  799. }
  800. else // Eastern edge.
  801. {
  802. if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  803. {
  804. _AREAS_ZONES_X(SW);
  805. }
  806. else // Northern edge.
  807. {
  808. _AREAS_ZONES_O(SW);
  809. }
  810. }
  811. }
  812. }
  813. else // Western edge.
  814. {
  815. if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  816. {
  817. if (0.0 <= maxx) // Eastern edge.
  818. {
  819. _AREAS_ZONES_O(N);
  820. }
  821. else // Eastern edge.
  822. {
  823. // I missed this one and the compiler didn't complain about the
  824. // path not returning - I think I confused it!
  825. _AREAS_ZONES_O(NW);
  826. }
  827. }
  828. else if (0.0 <= miny) // Southern edge.
  829. {
  830. if (0.0 <= maxx) // Eastern edge.
  831. {
  832. _AREAS_ZONES_X(N);
  833. }
  834. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  835. {
  836. _AREAS_ZONES_X(NW);
  837. }
  838. else // Eastern edge.
  839. {
  840. _AREAS_ZONES_O(NW);
  841. }
  842. }
  843. else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
  844. {
  845. if (0.0 <= maxx) // Eastern edge.
  846. {
  847. if (0.0 <= maxy) // Northern edge.
  848. {
  849. _AREAS_ZONES_X();
  850. }
  851. else
  852. {
  853. _AREAS_ZONES_X(S);
  854. }
  855. }
  856. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  857. {
  858. if (0.0 <= maxy) // Northern edge.
  859. {
  860. _AREAS_ZONES_X(W);
  861. }
  862. else // Northern edge.
  863. {
  864. _AREAS_ZONES_X(SW);
  865. }
  866. }
  867. else // Eastern edge.
  868. {
  869. if (0.0 <= maxy) // Northern edge.
  870. {
  871. _AREAS_ZONES_O(W);
  872. }
  873. else // Northern edge.
  874. {
  875. _AREAS_ZONES_O(SW);
  876. }
  877. }
  878. }
  879. else // Southern edge.
  880. {
  881. if (0.0 <= maxx) // Eastern edge.
  882. {
  883. if (0.0 <= maxy) // Northern edge.
  884. {
  885. _AREAS_ZONES_X();
  886. }
  887. else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  888. {
  889. _AREAS_ZONES_X(S);
  890. }
  891. else // Northern edge.
  892. {
  893. _AREAS_ZONES_O(S);
  894. }
  895. }
  896. else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
  897. {
  898. if (0.0 <= maxy) // Northern edge.
  899. {
  900. _AREAS_ZONES_X(W);
  901. }
  902. else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
  903. {
  904. _AREAS_ZONES_X(SW);
  905. }
  906. else // Northern edge.
  907. {
  908. _AREAS_ZONES_O(SW);
  909. }
  910. }
  911. else // Eastern edge.
  912. {
  913. if (0.0 <= maxy) // Northern edge.
  914. {
  915. _AREAS_ZONES_O(W);
  916. }
  917. else // Northern edge.
  918. {
  919. _AREAS_ZONES_O(SW);
  920. }
  921. }
  922. }
  923. }
  924. }
  925. /*----------------------------------------------------------------------------*-
  926. Function:
  927. Area_AddTo
  928. Params:
  929. area - Area to set for.
  930. set - Wether or not this area is usable in all worlds.
  931. Return:
  932. -
  933. Notes:
  934. -
  935. -*----------------------------------------------------------------------------*/
  936. /*----------------------------------------------------------------------------*-
  937. Function:
  938. Area_SetAllWorlds
  939. Params:
  940. area - Area to set for.
  941. set - Wether or not this area is usable in all worlds.
  942. Return:
  943. -
  944. Notes:
  945. -
  946. -*----------------------------------------------------------------------------*/
  947. foreign Area_SetAllWorlds(area, bool:set);
  948. global Area_SetAllWorlds(area, bool:set)
  949. {
  950. #if AREA_WORLDS > 0
  951. if (Area_IsActive(area))
  952. {
  953. Bit_SetAll(YSI_g_sAreas[area][E_AREA_WORLDS], set, bits<AREA_WORLDS>);
  954. return 1;
  955. }
  956. #else
  957. #pragma unused area, set
  958. #endif
  959. return 0;
  960. }
  961. /*----------------------------------------------------------------------------*-
  962. Function:
  963. Area_AddCube
  964. Params:
  965. Float:minx - Lowest X corner of box
  966. Float:miny - Lowest Y corner of box.
  967. Float:minx - Lowest Z corner of box.
  968. Float:maxx - Highest X corner of box.
  969. Float:maxy - Highest Y corner of box.
  970. Float:maxz - Highest Z corner of box.
  971. Return:
  972. Area slot or NO_AREA
  973. Notes:
  974. -
  975. -*----------------------------------------------------------------------------*/
  976. foreign Area_AddCube(Float:x0, Float:y0, Float:z0, Float:x1, Float:y1, Float:z1);
  977. global Area_AddCube(Float:x0, Float:y0, Float:z0, Float:x1, Float:y1, Float:z1)
  978. {
  979. if (Area_GetEmptySlotCount() < 2) return NO_AREA;
  980. new
  981. slot = Area_GetFreeSlot(),
  982. next = Area_GetFreeSlot();
  983. YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_CUBE | e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS_USED | e_AREA_FLAGS:next | e_AREA_FLAGS:(2 << 14);
  984. YSI_g_sAreas[slot][E_AREA_POS][0] = x0;
  985. YSI_g_sAreas[slot][E_AREA_POS][1] = y0;
  986. YSI_g_sAreas[slot][E_AREA_POS][2] = z0;
  987. YSI_g_sAreas[next][E_AREA_FLAGS] = SINGLE_SLOT_AREA | e_AREA_FLAGS_USED;
  988. YSI_g_sAreas[next][E_AREA_POS][0] = x1;
  989. YSI_g_sAreas[next][E_AREA_POS][1] = y1;
  990. YSI_g_sAreas[next][E_AREA_POS][2] = z1;
  991. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  992. NO_GROUPS()
  993. {
  994. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  995. }
  996. #if YSIM_HAS_MASTER
  997. YSI_g_sAreas[slot][E_AREA_MASTER] = YSI_g_sAreas[next][E_AREA_MASTER] = Master_Caller();
  998. #endif
  999. Area_SetAllWorlds(slot, true);
  1000. Area_DetermineZone(x0, y0, x1, y1, slot, next);
  1001. return slot;
  1002. }
  1003. /*----------------------------------------------------------------------------*-
  1004. Function:
  1005. Area_AddBox
  1006. Params:
  1007. Float:minx - Lowest X corner of box
  1008. Float:miny - Lowest Y corner of box.
  1009. Float:maxx - Highest X corner of box.
  1010. Float:maxy - Highest Y corner of box.
  1011. Return:
  1012. Area slot or NO_AREA
  1013. Notes:
  1014. -
  1015. -*----------------------------------------------------------------------------*/
  1016. foreign Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy);
  1017. global Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy)
  1018. {
  1019. new
  1020. slot;
  1021. if (minx > maxx)
  1022. {
  1023. slot = _:minx;
  1024. minx = maxx;
  1025. maxx = Float:slot;
  1026. }
  1027. if (miny > maxy)
  1028. {
  1029. slot = _:miny;
  1030. miny = maxy;
  1031. maxy = Float:slot;
  1032. }
  1033. slot = Area_GetFreeSlot();
  1034. if (slot == NO_AREA) return NO_AREA;
  1035. 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 << 14);
  1036. YSI_g_sAreas[slot][E_AREA_POS][0] = minx;
  1037. YSI_g_sAreas[slot][E_AREA_POS][1] = miny;
  1038. YSI_g_sAreas[slot][E_AREA_POS][2] = maxx;
  1039. YSI_g_sAreas[slot][E_AREA_POS][3] = maxy;
  1040. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1041. NO_GROUPS()
  1042. {
  1043. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1044. }
  1045. #if YSIM_HAS_MASTER
  1046. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1047. #endif
  1048. Area_SetAllWorlds(slot, true);
  1049. Area_DetermineZone(minx, miny, maxx, maxy, slot, slot);
  1050. return slot;
  1051. }
  1052. /*----------------------------------------------------------------------------*-
  1053. Function:
  1054. Area_AddCircle
  1055. Params:
  1056. Float:x - X position of circle.
  1057. Float:y - Y position of circle.
  1058. Float:r - Radius of circle.
  1059. Float:h - Ceiling of circle.
  1060. Return:
  1061. Area slot or NO_AREA
  1062. Notes:
  1063. Technically a cylinder, no lower bound (ceiling added cos there was a
  1064. spare slot in the 4 float design which may as well have been used).
  1065. -*----------------------------------------------------------------------------*/
  1066. stock Area_AddCircle(Float:x, Float:y, Float:r, Float:h = FLOAT_INFINITY)
  1067. {
  1068. return _Area_AddCircle(x, y, r, h);
  1069. }
  1070. foreign _Area_AddCircle(Float:x, Float:y, Float:r, Float:h);
  1071. global _Area_AddCircle(Float:x, Float:y, Float:r, Float:h)
  1072. {
  1073. new
  1074. slot = Area_GetFreeSlot();
  1075. if (slot == NO_AREA) return NO_AREA;
  1076. printf("%f %f %f %f", x - r, y - r, x + r, y + r);
  1077. YSI_g_sAreas[slot][E_AREA_FLAGS] = SINGLE_SLOT_AREA | e_AREA_FLAGS_CIRCLE | e_AREA_FLAGS_USED | e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS:(1 << 14);
  1078. YSI_g_sAreas[slot][E_AREA_POS][0] = x;
  1079. YSI_g_sAreas[slot][E_AREA_POS][1] = y;
  1080. YSI_g_sAreas[slot][E_AREA_POS][2] = r * r;
  1081. YSI_g_sAreas[slot][E_AREA_POS][3] = h;
  1082. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1083. NO_GROUPS()
  1084. {
  1085. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1086. }
  1087. #if YSIM_HAS_MASTER
  1088. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1089. #endif
  1090. Area_SetAllWorlds(slot, true);
  1091. Area_DetermineZone(x - r, y - r, x + r, y + r, slot, slot);
  1092. return slot;
  1093. }
  1094. /*----------------------------------------------------------------------------*-
  1095. Function:
  1096. Area_AddSphere
  1097. Params:
  1098. Float:x - X position of sphere.
  1099. Float:y - Y position of sphere.
  1100. Float:z - Z position of sphere.
  1101. Float:r - Radius of sphere.
  1102. Return:
  1103. Area slot or NO_AREA
  1104. Notes:
  1105. -
  1106. -*----------------------------------------------------------------------------*/
  1107. foreign Area_AddSphere(Float:x, Float:y, Float:z, Float:r);
  1108. global Area_AddSphere(Float:x, Float:y, Float:z, Float:r)
  1109. {
  1110. new
  1111. slot = Area_GetFreeSlot();
  1112. if (slot == NO_AREA) return NO_AREA;
  1113. YSI_g_sAreas[slot][E_AREA_FLAGS] = SINGLE_SLOT_AREA | e_AREA_FLAGS_SPHERE | e_AREA_FLAGS_USED | e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS:(1 << 14);
  1114. YSI_g_sAreas[slot][E_AREA_POS][0] = x;
  1115. YSI_g_sAreas[slot][E_AREA_POS][1] = y;
  1116. YSI_g_sAreas[slot][E_AREA_POS][2] = z;
  1117. YSI_g_sAreas[slot][E_AREA_POS][3] = r * r;
  1118. PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
  1119. NO_GROUPS()
  1120. {
  1121. PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
  1122. }
  1123. #if YSIM_HAS_MASTER
  1124. YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
  1125. #endif
  1126. Area_SetAllWorlds(slot, true);
  1127. Area_DetermineZone(x - r, y - r, x + r, y + r, slot, slot);
  1128. return slot;
  1129. }
  1130. /*----------------------------------------------------------------------------*-
  1131. Function:
  1132. Area_AddPoly
  1133. Params:
  1134. Float:... - X/Ys of points
  1135. Return:
  1136. Area slot or NO_AREA
  1137. Notes:
  1138. Creates an irregular shape to detect players in. This is a 2d area made
  1139. up of a load of XY points. If an odd number of parameters is passed the
  1140. extra one is assumed to be a ceiling so you can ignore interiors or planes.
  1141. Checks that there is enough space to store the data first (as the array
  1142. is split up into 4 float sections for general efficiency) so this check
  1143. uses at least 2 slots (smallest 2d shape is a triangle - 3 points, 6 co-
  1144. ordinates, 2 slots).
  1145. The height parameter goes first as it's easiest to check.
  1146. This is one of a few functions still written using the master system at a
  1147. low level (the other obvious one is "Class_Add").
  1148. -*----------------------------------------------------------------------------*/
  1149. #if YSIM_HAS_MASTER
  1150. #if _YSIM_IS_SERVER
  1151. forward Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...);
  1152. forward Area_AddPoly@(Float:points[], size, count);
  1153. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1154. {
  1155. new
  1156. args = numargs();
  1157. if (args > 128)
  1158. {
  1159. return NO_AREA;
  1160. }
  1161. new
  1162. Float:points[128];
  1163. points[0] = x1;
  1164. points[1] = y1;
  1165. points[2] = x2;
  1166. points[3] = y2;
  1167. points[4] = x3;
  1168. points[5] = y3;
  1169. for (new i = 6; i != args; ++i)
  1170. {
  1171. points[i] = Float:getarg(i);
  1172. }
  1173. return Area_AddPoly@(points, sizeof (points), args);
  1174. }
  1175. public Area_AddPoly@(Float:points[], size, count)
  1176. #else
  1177. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <>
  1178. {
  1179. new
  1180. args = numargs();
  1181. if (args > 128)
  1182. {
  1183. return NO_AREA;
  1184. }
  1185. new
  1186. Float:points[128];
  1187. points[0] = x1;
  1188. points[1] = y1;
  1189. points[2] = x2;
  1190. points[3] = y2;
  1191. points[4] = x3;
  1192. points[5] = y3;
  1193. for (new i = 6; i != args; ++i)
  1194. {
  1195. points[i] = Float:getarg(i);
  1196. }
  1197. new
  1198. p = getproperty(8, YSIM_CALLER);
  1199. setproperty(8, YSIM_CALLER, _@);
  1200. CallRemoteFunction("Area_AddPoly@", "aii", points, sizeof (points), args);
  1201. setproperty(8, YSIM_CALLER, p);
  1202. return getproperty(8, YSIM_RETURN);
  1203. }
  1204. forward Area_AddPoly@(Float:points[], size, count);
  1205. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : m>
  1206. {
  1207. #pragma unused x1, y1, x2, y2, x3, y3
  1208. return NO_AREA;
  1209. }
  1210. #if _YSIM_IS_CLIENT
  1211. static stock Area_AddPoly_(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1212. #else
  1213. #if _YSIM_IS_STUB
  1214. #error _YSIM_IS_STUB set in y_areas.
  1215. #else
  1216. public Area_AddPoly@(Float:points[], size, count) <>
  1217. {
  1218. return 0;
  1219. }
  1220. /*{
  1221. X@(_:@Zk:_YM@CP:%0(%1,,));
  1222. setproperty(8, YSIM_RETURN, n);
  1223. }*/
  1224. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : y>
  1225. {
  1226. new
  1227. args = numargs();
  1228. if (args > 128)
  1229. {
  1230. return NO_AREA;
  1231. }
  1232. new
  1233. Float:points[128];
  1234. points[0] = x1;
  1235. points[1] = y1;
  1236. points[2] = x2;
  1237. points[3] = y2;
  1238. points[4] = x3;
  1239. points[5] = y3;
  1240. for (new i = 6; i != args; ++i)
  1241. {
  1242. points[i] = Float:getarg(i);
  1243. }
  1244. return Area_AddPoly@(points, sizeof (points), args);
  1245. }
  1246. public Area_AddPoly@(Float:points[], size, count) <_YCM : y>
  1247. #endif
  1248. #endif
  1249. #endif
  1250. #else
  1251. stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
  1252. {
  1253. new
  1254. args = numargs();
  1255. if (args > 128)
  1256. {
  1257. return NO_AREA;
  1258. }
  1259. new
  1260. Float:points[128];
  1261. points[0] = x1;
  1262. points[1] = y1;
  1263. points[2] = x2;
  1264. points[3] = y2;
  1265. points[4] = x3;
  1266. points[5] = y3;
  1267. for (new i = 6; i != args; ++i)
  1268. {
  1269. points[i] = Float:getarg(i);
  1270. }
  1271. return Area_AddPoly_(points, sizeof (points), args);
  1272. }
  1273. static stock Area_AddPoly_(Float:points[], size, count)
  1274. #endif
  1275. {
  1276. if (Area_GetEmptySlotCount() < ceildiv(count, 4)) return NO_AREA;
  1277. new
  1278. first = Area_GetFreeSlot(),
  1279. done = 4,
  1280. real = first,
  1281. Float:cur,
  1282. Float:minx = FLOAT_INFINITY,
  1283. Float:miny = FLOAT_INFINITY,
  1284. Float:maxx = FLOAT_NEGATIVE_INFINITY,
  1285. Float:maxy = FLOAT_NEGATIVE_INFINITY;
  1286. YSI_g_sAreas[real][E_AREA_FLAGS] = e_AREA_FLAGS_USED | e_AREA_FLAGS_POLY | e_AREA_FLAGS_ACTIVE | (e_AREA_FLAGS:(count << 14) & e_AREA_FLAGS_COUNT);
  1287. PA_FastInit(YSI_g_sAreas[real][E_AREA_PLAYERS]);
  1288. NO_GROUPS()
  1289. {
  1290. PA_Init(YSI_g_sAreas[real][E_AREA_PLAYERS], true);
  1291. }
  1292. #if YSIM_HAS_MASTER
  1293. YSI_g_sAreas[real][E_AREA_MASTER] = Master_Caller();
  1294. #endif
  1295. if (count & 1)
  1296. {
  1297. YSI_g_sAreas[real][E_AREA_POS][0] = points[count - 1];
  1298. minx = maxx = YSI_g_sAreas[real][E_AREA_POS][2] = points[0];
  1299. miny = maxy = YSI_g_sAreas[real][E_AREA_POS][3] = points[1];
  1300. done = 2;
  1301. // If 1 AND 2 are set, make "size" 0 as we've used a full empty slot.
  1302. size = ~count & 2;
  1303. // Strip the odd value, but leave the odd points value.
  1304. count &= ~1;
  1305. }
  1306. else
  1307. {
  1308. minx = maxx = YSI_g_sAreas[real][E_AREA_POS][0] = points[0];
  1309. miny = maxy = YSI_g_sAreas[real][E_AREA_POS][1] = points[1];
  1310. // X point.
  1311. cur = points[2];
  1312. if (cur > maxx) maxx = cur;
  1313. else if (cur < minx) minx = cur;
  1314. YSI_g_sAreas[real][E_AREA_POS][2] = cur;
  1315. // Y point.
  1316. cur = points[3];
  1317. if (cur > maxx) maxx = cur;
  1318. else if (cur < minx) minx = cur;
  1319. YSI_g_sAreas[real][E_AREA_POS][3] = cur;
  1320. size = count & 2;
  1321. count &= ~2;
  1322. }
  1323. while (done < count)
  1324. {
  1325. new
  1326. next = Area_GetFreeSlot();
  1327. YSI_g_sAreas[real][E_AREA_FLAGS] |= e_AREA_FLAGS:next;
  1328. real = next;
  1329. YSI_g_sAreas[real][E_AREA_FLAGS] = e_AREA_FLAGS_USED;
  1330. // X point.
  1331. cur = points[done];
  1332. if (cur > maxx) maxx = cur;
  1333. else if (cur < minx) minx = cur;
  1334. YSI_g_sAreas[real][E_AREA_POS][0] = cur;
  1335. // Y point.
  1336. cur = points[done + 1];
  1337. if (cur > maxx) maxx = cur;
  1338. else if (cur < minx) minx = cur;
  1339. YSI_g_sAreas[real][E_AREA_POS][1] = cur;
  1340. // X point.
  1341. cur = points[done + 2];
  1342. if (cur > maxx) maxx = cur;
  1343. else if (cur < minx) minx = cur;
  1344. YSI_g_sAreas[real][E_AREA_POS][2] = cur;
  1345. // Y point.
  1346. cur = points[done + 3];
  1347. if (cur > maxx) maxx = cur;
  1348. else if (cur < minx) minx = cur;
  1349. YSI_g_sAreas[real][E_AREA_POS][3] = cur;
  1350. #if YSIM_HAS_MASTER
  1351. YSI_g_sAreas[real][E_AREA_MASTER] = Master_Caller();
  1352. #endif
  1353. done += 4;
  1354. }
  1355. if (size)
  1356. {
  1357. // EITHER height XOR odd number of points. Not both or neither (set above).
  1358. new
  1359. next = Area_GetFreeSlot();
  1360. YSI_g_sAreas[real][E_AREA_FLAGS] |= e_AREA_FLAGS:next;
  1361. real = next;
  1362. YSI_g_sAreas[real][E_AREA_FLAGS] = SINGLE_SLOT_AREA | e_AREA_FLAGS_USED;
  1363. // X point.
  1364. cur = points[done];
  1365. if (cur > maxx) maxx = cur;
  1366. else if (cur < minx) minx = cur;
  1367. YSI_g_sAreas[real][E_AREA_POS][0] = cur;
  1368. // Y point.
  1369. cur = points[done + 1];
  1370. if (cur > maxx) maxx = cur;
  1371. else if (cur < minx) minx = cur;
  1372. YSI_g_sAreas[real][E_AREA_POS][1] = cur;
  1373. #if YSIM_HAS_MASTER
  1374. YSI_g_sAreas[real][E_AREA_MASTER] = Master_Caller();
  1375. #endif
  1376. }
  1377. else
  1378. {
  1379. YSI_g_sAreas[real][E_AREA_FLAGS] |= SINGLE_SLOT_AREA;
  1380. }
  1381. #if YSIM_HAS_MASTER
  1382. setproperty(8, YSIM_RETURN, first);
  1383. #endif
  1384. Area_SetAllWorlds(first, true);
  1385. Area_DetermineZone(minx, miny, maxx, maxy, first, real);
  1386. return first;
  1387. }
  1388. /*----------------------------------------------------------------------------*-
  1389. Function:
  1390. Area_OnPlayerConnect
  1391. Params:
  1392. playerid - Player who connected
  1393. Return:
  1394. -
  1395. Notes:
  1396. -
  1397. -*----------------------------------------------------------------------------*/
  1398. mhook OnPlayerConnect(playerid)
  1399. {
  1400. YSI_g_sPlayerArea[playerid] = NO_AREA;
  1401. NO_GROUPS()
  1402. {
  1403. new
  1404. slot = Bit_Slot(playerid) + 1,
  1405. Bit:mask = Bit_Mask(playerid);
  1406. for (new i = 0; i != MAX_AREAS; ++i)
  1407. {
  1408. YSI_g_sAreas[i][E_AREA_PLAYERS][slot] |= mask;
  1409. }
  1410. }
  1411. return 1;
  1412. }
  1413. /*----------------------------------------------------------------------------*-
  1414. Function:
  1415. Area_loop
  1416. Params:
  1417. playerid - The player to check for.
  1418. Return:
  1419. -
  1420. Notes:
  1421. Main processing for the system. Takes one player and checks if they're in
  1422. some sort of range of somewhere.
  1423. -*----------------------------------------------------------------------------*/
  1424. #if defined AREAS_USE_TIMER
  1425. ptask Area_Loop[200](playerid)
  1426. {
  1427. new
  1428. Float:x,
  1429. Float:y,
  1430. Float:z,
  1431. area = YSI_g_sPlayerArea[playerid],
  1432. world = GetPlayerVirtualWorld(playerid);
  1433. GetPlayerPos(playerid, x, y, z);
  1434. if (area != NO_AREA)
  1435. {
  1436. if (Area_CheckArea(playerid, world, area, x, y, z)) continue;
  1437. YSI_g_sPlayerArea[playerid] = NO_AREA;
  1438. #if defined _YSI_GAMEMODE_PROPERTIES
  1439. if (!Property_OnPlayerLeaveArea(playerid, area))
  1440. #endif
  1441. CallRemoteFunction("OnPlayerLeaveArea", "ii", playerid, area);
  1442. }
  1443. for (area = 0; area < MAX_AREAS; area++)
  1444. {
  1445. if (Area_CheckArea(playerid, world, area, x, y, z))
  1446. {
  1447. YSI_g_sPlayerArea[playerid] = area;
  1448. CallRemoteFunction("OnPlayerEnterArea", "ii", playerid, area);
  1449. break;
  1450. }
  1451. }
  1452. }
  1453. #else
  1454. hook OnPlayerUpdate(playerid)
  1455. {
  1456. static
  1457. sZones[9],
  1458. Float:sX,
  1459. Float:sY,
  1460. Float:sZ,
  1461. sCur,
  1462. sW;
  1463. new
  1464. idx;
  1465. // Get all the zones for this player.
  1466. GetPlayerPos(playerid, sX, sY, sZ);
  1467. #if AREA_WORLDS > 0
  1468. sW = GetPlayerVirtualWorld(playerid);
  1469. #endif
  1470. if ((sCur = YSI_g_sPlayerArea[playerid]) != NO_AREA)
  1471. {
  1472. if (Area_CheckArea(playerid, sW, sCur, sX, sY, sZ))
  1473. {
  1474. // Still in the old area, don't check for new ones.
  1475. return 1;
  1476. }
  1477. else
  1478. {
  1479. // No longer in the area they used to be in.
  1480. YSI_g_sPlayerArea[playerid] = NO_AREA;
  1481. Area_DoLeave(playerid, sCur);
  1482. }
  1483. }
  1484. sZones = Area_GetZones(sX, sY);
  1485. for ( ; ; )
  1486. {
  1487. switch (sZones[idx++])
  1488. {
  1489. case e_AREA_ZONE_I_N:
  1490. {
  1491. _AREA_DO_ALL(YSI_g_sZoneIN);
  1492. }
  1493. case e_AREA_ZONE_I_NE:
  1494. {
  1495. _AREA_DO_ALL(YSI_g_sZoneINE);
  1496. }
  1497. case e_AREA_ZONE_I_E:
  1498. {
  1499. _AREA_DO_ALL(YSI_g_sZoneIE);
  1500. }
  1501. case e_AREA_ZONE_I_SE:
  1502. {
  1503. _AREA_DO_ALL(YSI_g_sZoneISE);
  1504. }
  1505. case e_AREA_ZONE_I_S:
  1506. {
  1507. _AREA_DO_ALL(YSI_g_sZoneIS);
  1508. }
  1509. case e_AREA_ZONE_I_SW:
  1510. {
  1511. _AREA_DO_ALL(YSI_g_sZoneISW);
  1512. }
  1513. case e_AREA_ZONE_I_W:
  1514. {
  1515. _AREA_DO_ALL(YSI_g_sZoneIW);
  1516. }
  1517. case e_AREA_ZONE_I_NW:
  1518. {
  1519. _AREA_DO_ALL(YSI_g_sZoneINW);
  1520. }
  1521. case e_AREA_ZONE_I_:
  1522. {
  1523. _AREA_DO_ALL(YSI_g_sZoneI);
  1524. }
  1525. // "Outer" zones.
  1526. case e_AREA_ZONE_O_N:
  1527. {
  1528. _AREA_DO_ALL(YSI_g_sZoneON);
  1529. }
  1530. case e_AREA_ZONE_O_NE:
  1531. {
  1532. _AREA_DO_ALL(YSI_g_sZoneONE);
  1533. }
  1534. case e_AREA_ZONE_O_E:
  1535. {
  1536. _AREA_DO_ALL(YSI_g_sZoneOE);
  1537. }
  1538. case e_AREA_ZONE_O_SE:
  1539. {
  1540. _AREA_DO_ALL(YSI_g_sZoneOSE);
  1541. }
  1542. case e_AREA_ZONE_O_S:
  1543. {
  1544. _AREA_DO_ALL(YSI_g_sZoneOS);
  1545. }
  1546. case e_AREA_ZONE_O_SW:
  1547. {
  1548. _AREA_DO_ALL(YSI_g_sZoneOSW);
  1549. }
  1550. case e_AREA_ZONE_O_W:
  1551. {
  1552. _AREA_DO_ALL(YSI_g_sZoneOW);
  1553. }
  1554. case e_AREA_ZONE_O_NW:
  1555. {
  1556. _AREA_DO_ALL(YSI_g_sZoneONW);
  1557. }
  1558. //case e_AREA_ZONE_O_:
  1559. //{
  1560. // _AREA_DO_ALL(YSI_g_sZoneO);
  1561. //}
  1562. case e_AREA_ZONE_X_N:
  1563. {
  1564. _AREA_DO_ALL(YSI_g_sZoneXN);
  1565. }
  1566. case e_AREA_ZONE_X_NE:
  1567. {
  1568. _AREA_DO_ALL(YSI_g_sZoneXNE);
  1569. }
  1570. case e_AREA_ZONE_X_E:
  1571. {
  1572. _AREA_DO_ALL(YSI_g_sZoneXE);
  1573. }
  1574. case e_AREA_ZONE_X_SE:
  1575. {
  1576. _AREA_DO_ALL(YSI_g_sZoneXSE);
  1577. }
  1578. case e_AREA_ZONE_X_S:
  1579. {
  1580. _AREA_DO_ALL(YSI_g_sZoneXS);
  1581. }
  1582. case e_AREA_ZONE_X_SW:
  1583. {
  1584. _AREA_DO_ALL(YSI_g_sZoneXSW);
  1585. }
  1586. case e_AREA_ZONE_X_W:
  1587. {
  1588. _AREA_DO_ALL(YSI_g_sZoneXW);
  1589. }
  1590. case e_AREA_ZONE_X_NW:
  1591. {
  1592. _AREA_DO_ALL(YSI_g_sZoneXNW);
  1593. }
  1594. case e_AREA_ZONE_X_:
  1595. {
  1596. _AREA_DO_ALL(YSI_g_sZoneX);
  1597. break;
  1598. }
  1599. case e_AREA_ZONE_NONE:
  1600. {
  1601. // Specific zone (which).
  1602. _AREA_DO_ALL(YSI_g_sZones[((Area_MakeZone(sX) + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS + Area_MakeZone(sY)]);
  1603. }
  1604. }
  1605. }
  1606. return 1;
  1607. }
  1608. #endif
  1609. /*----------------------------------------------------------------------------*-
  1610. Function:
  1611. Area_CheckArea
  1612. Params:
  1613. playerid - Player being checked for.
  1614. world - VW the player is in.
  1615. area - Area to check against.
  1616. Float:x - X position to check.
  1617. Float:y - Y position to check.
  1618. Float:z - Z position to check.
  1619. Return:
  1620. -
  1621. Notes:
  1622. Checks if the given position is in the give area. All parameters are passed
  1623. to avoid calling functions over and over and over again. If the return is
  1624. not true, "area" is updated to the next one in the chain.
  1625. -*----------------------------------------------------------------------------*/
  1626. static stock Area_CheckArea(playerid, world, &area, Float:x, Float:y, Float:z)
  1627. {
  1628. new
  1629. e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS],
  1630. next,
  1631. ret;
  1632. if ((flags & e_AREA_FLAGS_ACTIVE))
  1633. {
  1634. switch (flags & e_AREA_FLAGS_TYPE)
  1635. {
  1636. case e_AREA_FLAGS_CIRCLE:
  1637. {
  1638. ret = Area_IsInCircle(x, y, z, YSI_g_sAreas[area][E_AREA_POS]);
  1639. next = _:(flags & e_AREA_FLAGS_NEXT);
  1640. }
  1641. case e_AREA_FLAGS_SPHERE:
  1642. {
  1643. ret = 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]);
  1644. next = _:(flags & e_AREA_FLAGS_NEXT);
  1645. }
  1646. case e_AREA_FLAGS_POLY:
  1647. {
  1648. ret = Area_IsInPoly(x, y, z, area, _:(flags & e_AREA_FLAGS_COUNT) >> 14, next);
  1649. }
  1650. case e_AREA_FLAGS_CUBE:
  1651. {
  1652. next = _:(flags & e_AREA_FLAGS_NEXT);
  1653. ret = Area_IsInCube(x, y, z, YSI_g_sAreas[area][E_AREA_POS], YSI_g_sAreas[next][E_AREA_POS]);
  1654. next = _:(YSI_g_sAreas[next][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);
  1655. }
  1656. case e_AREA_FLAGS_BOX:
  1657. {
  1658. ret = Area_IsInBox(x, y, YSI_g_sAreas[area][E_AREA_POS]);
  1659. next = _:(flags & e_AREA_FLAGS_NEXT);
  1660. }
  1661. }
  1662. }
  1663. #if AREA_WORLDS > 0
  1664. if (!Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world))
  1665. {
  1666. area = next;
  1667. return 0;
  1668. }
  1669. #else
  1670. #pragma unused world
  1671. #endif
  1672. if (!ret || !PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid))
  1673. {
  1674. area = next;
  1675. return 0;
  1676. }
  1677. return ret;
  1678. }
  1679. /*----------------------------------------------------------------------------*-
  1680. Function:
  1681. Area_IsInCircle
  1682. Params:
  1683. Float:x - X position to check.
  1684. Float:y - Y position to check.
  1685. Float:z - Z position to check.
  1686. Float:bounds[] - Data for the area position.
  1687. Return:
  1688. -
  1689. Notes:
  1690. Checks if a point is in a given circle.
  1691. -*----------------------------------------------------------------------------*/
  1692. static stock Area_IsInCircle(Float:x, Float:y, Float:z, Float:bounds[])
  1693. {
  1694. x -= bounds[0];
  1695. y -= bounds[1];
  1696. return (z < bounds[3] && ((x * x) + (y * y)) < bounds[2]);
  1697. }
  1698. /*----------------------------------------------------------------------------*-
  1699. Function:
  1700. Area_IsInSphere
  1701. Params:
  1702. Float:x - X position to check.
  1703. Float:y - Y position to check.
  1704. Float:z - Z position to check.
  1705. Float:bounds[] - Data for the area position.
  1706. Return:
  1707. -
  1708. Notes:
  1709. Checks if a point is in a given sphere.
  1710. -*----------------------------------------------------------------------------*/
  1711. static stock Area_IsInSphere(Float:x, Float:y, Float:z, Float:bounds[])
  1712. {
  1713. x -= bounds[0];
  1714. y -= bounds[1];
  1715. z -= bounds[2];
  1716. return (((x * x) + (y * y) + (z * z)) < bounds[3]);
  1717. }
  1718. /*----------------------------------------------------------------------------*-
  1719. Function:
  1720. Area_IsInPoly
  1721. Params:
  1722. Float:x - X position to check.
  1723. Float:y - Y position to check.
  1724. Float:z - Z position to check.
  1725. pointer - Pointer to the start of the polygon data in the array.
  1726. count - Number of points in the polygon (x/y are counted separate).
  1727. &next - Return for the area after this one.
  1728. Return:
  1729. -
  1730. Notes:
  1731. Based on IsPlayerInAreaEx by koolk in the useful functions topic. The
  1732. passed pointer is the pointer to the first set of co-ordinates in a one-
  1733. way not looping linked list of points in the polygod as the data may be
  1734. spread throughout the areas array. This is as otherwise there may be
  1735. enough free spaces but not in one block.
  1736. The code first checks if there is a height component as it's the easiest
  1737. to check thus may save a load of pointless processing. If this passes it
  1738. then does the main loop. This loops till there are no points left to do
  1739. (monitored by decreasing count). When 2 points (four pieces of data) have
  1740. been checked the poiner for the data is moved on to the next group and the
  1741. checking continues.
  1742. For simplicity's sake (and thus speed's sake) the lower pointes from the
  1743. last check are saved amd used as the upper points for the next check to
  1744. avoid loads of repeated array accesses and saving the last array position.
  1745. -*----------------------------------------------------------------------------*/
  1746. static stock Area_IsInPoly(Float:x, Float:y, Float:z, pointer, count, &next)
  1747. {
  1748. new
  1749. slot;
  1750. if (isodd(count))
  1751. {
  1752. if (YSI_g_sAreas[pointer][E_AREA_POS][0] < z)
  1753. {
  1754. count = ceildiv(count, 4);
  1755. while (count--)
  1756. {
  1757. pointer = _:(YSI_g_sAreas[pointer][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);
  1758. }
  1759. next = pointer;
  1760. return 0;
  1761. }
  1762. slot = 2;
  1763. count--;
  1764. }
  1765. new
  1766. lines,
  1767. Float:fx = YSI_g_sAreas[pointer][E_AREA_POS][slot++],
  1768. Float:fy = YSI_g_sAreas[pointer][E_AREA_POS][slot++],
  1769. Float:minx = fx,
  1770. Float:miny = fy,
  1771. Float:maxx,
  1772. Float:maxy;
  1773. while (count)
  1774. {
  1775. if (slot == 4)
  1776. {
  1777. pointer = _:(YSI_g_sAreas[pointer][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);
  1778. slot = 0;
  1779. }
  1780. if (count == 2)
  1781. {
  1782. maxx = fx;
  1783. maxy = fy;
  1784. }
  1785. else
  1786. {
  1787. maxx = YSI_g_sAreas[pointer][E_AREA_POS][slot++];
  1788. maxy = YSI_g_sAreas[pointer][E_AREA_POS][slot++];
  1789. }
  1790. if (((y >= miny && y <= maxy) || (y >= maxy && y <= miny)) && (minx + ((y - miny) * (maxx - minx) / (maxy - miny))) < x) lines++;
  1791. count -= 2;
  1792. minx = maxx;
  1793. miny = maxy;
  1794. }
  1795. next = _:(YSI_g_sAreas[pointer][E_AREA_FLAGS] & e_AREA_FLAGS_NEXT);
  1796. return isodd(lines);
  1797. }
  1798. /*----------------------------------------------------------------------------*-
  1799. Function:
  1800. Area_IsInCube
  1801. Params:
  1802. Float:x - X position to check.
  1803. Float:y - Y position to check.
  1804. Float:z - Z position to check.
  1805. Float:lower[] - The lower corner of the cube.
  1806. Float:upper[] - The upper corner of the cube.
  1807. Return:
  1808. -
  1809. Notes:
  1810. Checks if a point is in a given cube. This is another multi slot shape
  1811. but is much simpler than the poly as it's always 2 slots so we can easilly
  1812. get the data in one lump.
  1813. -*----------------------------------------------------------------------------*/
  1814. static stock Area_IsInCube(Float:x, Float:y, Float:z, Float:lower[], Float:upper[])
  1815. {
  1816. return (x > lower[0] && x < upper[0] && y > lower[1] && y < upper[1] && z > lower[2] && z < upper[2]);
  1817. }
  1818. /*----------------------------------------------------------------------------*-
  1819. Function:
  1820. Area_IsInBox
  1821. Params:
  1822. Float:x - X position to check.
  1823. Float:y - Y position to check.
  1824. Float:bounds[] - Data for the area position.
  1825. Return:
  1826. -
  1827. Notes:
  1828. Checks if a point is in a given box. There is no height check with this
  1829. one as any one area slot has 4 points which for this are upper and lower
  1830. x and y, adding a height check would make it require 2 slots and basically
  1831. make it a cube check.
  1832. -*----------------------------------------------------------------------------*/
  1833. static stock Area_IsInBox(Float:x, Float:y, Float:bounds[])
  1834. {
  1835. return (x > bounds[0] && x < bounds[2] && y > bounds[1] && y < bounds[3]);
  1836. }
  1837. /*----------------------------------------------------------------------------*-
  1838. Function:
  1839. Area_GetPlayerArea
  1840. Params:
  1841. playerid - Player to get area of.
  1842. Return:
  1843. The area a player is in or -1.
  1844. Notes:
  1845. -
  1846. -*----------------------------------------------------------------------------*/
  1847. foreign Area_GetPlayerArea(playerid);
  1848. global Area_GetPlayerArea(playerid)
  1849. {
  1850. if (playerid >= 0 && playerid < MAX_PLAYERS)
  1851. {
  1852. return YSI_g_sPlayerArea[playerid];
  1853. }
  1854. return NO_AREA;
  1855. }
  1856. /*----------------------------------------------------------------------------*-
  1857. Function:
  1858. Area_SetPlayer
  1859. Params:
  1860. area - Area to set for.
  1861. playerid - Player to set for.
  1862. set - Wether or not the player can use the area.
  1863. Return:
  1864. -
  1865. Notes:
  1866. -
  1867. -*----------------------------------------------------------------------------*/
  1868. foreign Area_SetPlayer(area, playerid, bool:set);
  1869. global Area_SetPlayer(area, playerid, bool:set)
  1870. {
  1871. if (Area_IsActive(area))
  1872. {
  1873. PA_Set(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid, set);
  1874. return 1;
  1875. }
  1876. return 0;
  1877. }
  1878. /*----------------------------------------------------------------------------*-
  1879. Function:
  1880. Area_GetPlayer
  1881. Params:
  1882. area - Area to set for.
  1883. playerid - Player to set for.
  1884. Return:
  1885. -
  1886. Notes:
  1887. -
  1888. -*----------------------------------------------------------------------------*/
  1889. foreign bool:Area_GetPlayer(area, playerid);
  1890. global bool:Area_GetPlayer(area, playerid)
  1891. {
  1892. if (Area_IsActive(area))
  1893. {
  1894. return PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid);
  1895. }
  1896. return false;
  1897. }
  1898. /*----------------------------------------------------------------------------*-
  1899. Function:
  1900. Area_SetWorld
  1901. Params:
  1902. area - Area to set for.
  1903. world - World to set for.
  1904. set - Wether or not the area is active in this world.
  1905. Return:
  1906. -
  1907. Notes:
  1908. -
  1909. -*----------------------------------------------------------------------------*/
  1910. foreign Area_SetWorld(area, world, bool:set);
  1911. global Area_SetWorld(area, world, bool:set)
  1912. {
  1913. #if AREA_WORLDS > 0
  1914. if (Area_IsActive(area))
  1915. {
  1916. Bit_Set(YSI_g_sAreas[area][E_AREA_WORLDS], world, set);
  1917. return 1;
  1918. }
  1919. #else
  1920. #pragma unused area, world, set
  1921. #endif
  1922. return 0;
  1923. }
  1924. /*----------------------------------------------------------------------------*-
  1925. Function:
  1926. Area_GetWorld
  1927. Params:
  1928. area - Area to set for.
  1929. world - World to set for.
  1930. Return:
  1931. -
  1932. Notes:
  1933. -
  1934. -*----------------------------------------------------------------------------*/
  1935. foreign bool:Area_GetWorld(area, world);
  1936. global bool:Area_GetWorld(area, world)
  1937. {
  1938. if (Area_IsActive(area))
  1939. {
  1940. return Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world);
  1941. }
  1942. return false;
  1943. }
  1944. /*----------------------------------------------------------------------------*-
  1945. Function:
  1946. Area_SetAllPlayers
  1947. Params:
  1948. area - Area to set for.
  1949. set - Wether or not all players can use this area.
  1950. Return:
  1951. -
  1952. Notes:
  1953. -
  1954. -*----------------------------------------------------------------------------*/
  1955. foreign Area_SetAllPlayers(area, bool:set);
  1956. global Area_SetAllPlayers(area, bool:set)
  1957. {
  1958. if (Area_IsActive(area))
  1959. {
  1960. PA_Init(YSI_g_sAreas[area][E_AREA_PLAYERS], set);
  1961. return 1;
  1962. }
  1963. return 0;
  1964. }
  1965. /*----------------------------------------------------------------------------*-
  1966. Function:
  1967. Area_IsValid
  1968. Params:
  1969. area - Area to check.
  1970. Return:
  1971. Is the passed area valid and active.
  1972. Notes:
  1973. -
  1974. -*----------------------------------------------------------------------------*/
  1975. foreign bool:Area_IsValid(area);
  1976. global bool:Area_IsValid(area)
  1977. {
  1978. return bool:Area_IsActive(area);
  1979. }
  1980. /*----------------------------------------------------------------------------*-
  1981. Function:
  1982. Area_IsEmpty
  1983. Params:
  1984. area - Area to check.
  1985. Return:
  1986. Is the passed area valid and empty.
  1987. Notes:
  1988. -
  1989. -*----------------------------------------------------------------------------*/
  1990. foreign bool:Area_IsEmpty(area);
  1991. global bool:Area_IsEmpty(area)
  1992. {
  1993. if (Area_IsActive(area))
  1994. {
  1995. foreach (new playerid : Player)
  1996. {
  1997. if (YSI_g_sPlayerArea[playerid] == area) return false;
  1998. }
  1999. }
  2000. return true;
  2001. }
  2002. /*----------------------------------------------------------------------------*-
  2003. Function:
  2004. Area_SetCallback
  2005. Params:
  2006. area - Area to set for.
  2007. callback:callback - Callback to use.
  2008. Return:
  2009. -
  2010. Notes:
  2011. Adds a y_inline style callback (publics included) to an area to be called
  2012. when a player enters it. This is NOT a remote function and instead records
  2013. the data locally to call functions in the correct script (or they'll just
  2014. end up crashing as you will be jumping to an arbitrary address in a script
  2015. that doesn't have sensible code at that address.
  2016. -*----------------------------------------------------------------------------*/
  2017. /*----------------------------------------------------------------------------*-
  2018. Function:
  2019. Area_DoEnter
  2020. Params:
  2021. playerid - The player that just entered the area.
  2022. areaid - The area they entered.
  2023. Return:
  2024. -
  2025. Notes:
  2026. -
  2027. -*----------------------------------------------------------------------------*/
  2028. remotefunc Area_DoEnter(playerid, areaid)
  2029. {
  2030. if (YSI_g_sHasCallbacks & 1)
  2031. {
  2032. CallLocalFunction("OnPlayerEnterArea", "ii", playerid, areaid);
  2033. }
  2034. if (YSI_g_sHasCallbacks & 4)
  2035. {
  2036. //Hook_OnPlayerEnterArea(playerid, areaid);
  2037. }
  2038. return 1;
  2039. }
  2040. forward OnPlayerEnterArea(playerid, areaid);
  2041. /*----------------------------------------------------------------------------*-
  2042. Function:
  2043. Area_DoLeave
  2044. Params:
  2045. playerid - The player that just left the area.
  2046. areaid - The area they left.
  2047. Return:
  2048. -
  2049. Notes:
  2050. -
  2051. -*----------------------------------------------------------------------------*/
  2052. remotefunc Area_DoLeave(playerid, areaid)
  2053. {
  2054. if (YSI_g_sHasCallbacks & 2)
  2055. {
  2056. CallLocalFunction("OnPlayerLeaveArea", "ii", playerid, areaid);
  2057. }
  2058. if (YSI_g_sHasCallbacks & 8)
  2059. {
  2060. //Hook_OnPlayerLeaveArea(playerid, areaid);
  2061. }
  2062. return 1;
  2063. }
  2064. forward OnPlayerLeaveArea(playerid, areaid);
  2065. //#define YSI_SET_LAST_GROUP 19
  2066. #include "internal\y_grouprevert"