| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829 |
- /*----------------------------------------------------------------------------*-
- =============================
- Y Sever Includes - Areas Core
- =============================
- Description:
- Handles area checks for player location based code not involving CPs.
- Legal:
- Version: MPL 1.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is the YSI AMX include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
-
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
-
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
-
- Version:
- 0.3
- Changelog:
- 01/12/12:
- Added ovals and ovoids.
- Set cuboids to require only one slot in memory.
- Changed poly memory layout for vastly more efficient storage.
- 13/08/12:
- Added overlapping areas support.
- 01/01/12:
- Massive ground-up rewrite based on zones.
- 27/08/07:
- Made master compatible.
- 03/08/07:
- Updated timer system.
- 31/07/07:
- Made Area_GetPlayerArea safe.
- 08/05/07:
- First version.
- Functions:
- Public:
- Area_Loop - Main loop for checking who's where.
- Area_Remote - Does minor functions remotely.
- Area_AddRemote - Adds areas remotely.
- YSIM_Areas - Master system interface.
- Area_Broadcast - Recieves transmitted areas.
- Area_UpdateEmpty - Resets the empty array after master change.
- Core:
- Area_Area - Constructor.
- Area_CheckArea - Gets an area's type anx calls the relevant function.
- Area_OnPlayerConnect - Called when a player connects.
- Stock:
- Area_Delete - Deletes an area.
- Area_AddCube - Adds a cube.
- Area_AddBox - Adds a box.
- Area_AddCircle - Adds a circle.
- Area_AddSphere - Adds a sphere.
- Area_AddPoly - Adds a polygon.
- Area_GetPlayerArea - Gets the area a player is in.
- Area_SetPlayer - Sets wether a player can use this area.
- Area_SetAllPlayers - Sets wether all players can use this area.
- Area_SetAllWorlds - Sets wether all worlds have this are.
- Area_SetWorld - Sets wether this world has this area.
- Area_IsValid - Checks if an area is valid.
- Static:
- Area_IsInCircle - Checks if a player is in this circular area.
- Area_IsInSphere - Checks if a player is in this spherical area.
- Area_IsInPoly - Checks if a player is in this polygonal area.
- Area_IsInCube - Checks if a player is in this cubic area.
- Area_IsInBox - Checks if a player is in this rectangular area.
- Area_AddToUnused - Adds a area pointer to the unused list.
- Area_GetFreeSlot - Gets the next free area slot.
- Inline:
- Area_IsActive - Checks if an area is active.
- Area_GetEmptySlotCount - Gets the number of empty slots.
- Area_AddSlots - Removes slots from the unused count.
- API:
- -
- Callbacks:
- OnPlayerEnterArea - Called when a player enters an area.
- OnPlayerLeaveArea - Called when a player leaves an area.
- Definitions:
- MAX_AREAS - Max number of areas.
- NO_AREA - Fail return.
- AREA_NO_NEXT - Marker for end of a list.
- AREA_WORLDS - Number of worlds an area can be in.
- AREA_WORLD_COUNT - Number of cells required for a bit array of AREA_WORLDS.
- Enums:
- e_AREA_FLAGS - Flags for each area.
- E_AREA - Structure for part of an areas data.
- Macros:
- -
- Tags:
- -
- Variables:
- Global:
- -
- Static:
- YSI_g_sUnusedAreas - Pointer to the first unused area.
- YSI_g_sLastUnused - Pointer to the last unused area.
- YSI_g_sFreeCount - Number of unused slots.
- YSI_g_sAreas - Array of area data.
- YSI_g_sPlayerArea - Array of players' current areas.
- Commands:
- -
- Compile options:
- -
- Operators:
- -
- -*----------------------------------------------------------------------------*/
- #include "internal\y_version"
- #include "y_bit"
- #include "y_playerarray"
- #include "y_iterate"
- #include "y_debug"
- #include "y_inline"
- #include "y_remote"
- #if defined AREAS_USE_TIMER
- #include "y_timers"
- #endif
- #include "internal\y_natives"
- #if !defined MAX_AREAS
- #define MAX_AREAS (1024)
- // Now supports as many as you want (pretty much), and in a VASTLY better way!
- #elseif MAX_AREAS >= 0x3FFFF
- #error This version does not support more than 262142 areas.
- #endif
- #define _GROUP_MAKE_NAME_AREAS<%0...%1> %0Area%1
- #define _GROUP_MAKE_LIMIT_AREAS MAX_AREAS
- #include "y_groups"
- #define YSIM_U_DISABLE
- #include "y_master"
- #include "y_hooks"
- #define NO_AREA (-1)
- //#define SINGLE_SLOT_AREA (e_AREA_FLAGS_NEXT)
- #define AREA_NO_NEXT (_:e_AREA_FLAGS_NEXT)
- // This will divide the world up in to 400 blocks, the fact that 400=400 is
- // PURE fluke. Setting this to 500 would result in 256 blocks:
- //
- // ((AREAS_ZONE_BOUNDS / AREAS_ZONE_SIZE) ** 2) * 4
- //
- #if !defined AREAS_ZONE_SIZE
- #define AREAS_ZONE_SIZE 400
- #endif
- #if !defined AREAS_ZONE_BOUNDS
- #define AREAS_ZONE_BOUNDS 4000
- #endif
- // You can of course have more, but if you do have more the extras will be dealt
- // with separately. I can see three happening sometimes, but not often. More
- // than that will probably be very rare, and less will be more common, so we can
- // use the third slot usually to store the "NO_AREA" terminator.
- #if !defined AREAS_MAX_OVERLAPS
- #define AREAS_MAX_OVERLAPS (3)
- #endif
- #define AREAS_ZONE_ARRAY (ceildiv(AREAS_ZONE_BOUNDS * 2, AREAS_ZONE_SIZE))
- #if !defined AREA_WORLDS
- #define AREA_WORLDS 256
- #endif
- #define AREAS_ZONE_PARTS (ceildiv(AREAS_ZONE_BOUNDS, AREAS_ZONE_SIZE))
- #define Area_MakeZone(%0) (floatround((%0) / AREAS_ZONE_SIZE.0, floatround_floor)) // - AREAS_ZONE_PARTS)
- #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
- //#define _AREAS_ZONES_O(%0) return e_AREA_ZONE_O_%0
- //#define _AREAS_ZONES_I(%0) return e_AREA_ZONE_I_%0
- //#define _AREAS_ZONES_X(%0) return e_AREA_ZONE_X_%0
- #define _AREAS_ZONES_O(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneO%0,area,last,e_AREA_ZONE_O_%0)
- #define _AREAS_ZONES_I(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneI%0,area,last,e_AREA_ZONE_I_%0)
- #define _AREAS_ZONES_X(%0) return _AREAS_ADD_TO_ZONE(YSI_g_sZoneX%0,area,last,e_AREA_ZONE_X_%0)
- #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)
- #define _AREAS_MAKE_ZONE(%0,%1) %1+=((%0)+AREAS_ZONE_PARTS)*AREAS_ZONE_ARRAY+AREAS_ZONE_PARTS
- //#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))
- #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)
- /*#define _AREA_DO_ALL(%0)
- sCur = zone;
- while (sCur != AREA_NO_NEXT)
- if (Area_CheckArea(playerid, sW, sCur, sX, sY, sZ))
- return Area_DoEnter(playerid, (YSI_g_sPlayerArea[playerid] = sCur));
- */
- #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))))
- enum e_AREA_FLAGS
- {
- // These aren't used any more either, they get encoded in the "POS" array
- // (sort of) with polys.
- //e_AREA_FLAGS_NEXT = 0x2000 - 1 << 0, //0x00001FFF,
- e_AREA_FLAGS_NEXT = 0x0003FFFF,
- //e_AREA_FLAGS_ZONE = 1023 << 18, //0x0FFC0000,
- e_AREA_FLAGS_ZONE = 0x0FFC0000,
- e_AREA_FLAGS_I_NEXT = ~(e_AREA_FLAGS_NEXT),
- e_AREA_FLAGS_REST = ~(e_AREA_FLAGS_NEXT | e_AREA_FLAGS_ZONE),
- //e_AREA_FLAGS_TYPE = 0x38000000,
- e_AREA_FLAGS_SPHERE = 1 << 28, //0x08000000,
- e_AREA_FLAGS_POLY = 2 << 28, //0x10000000,
- e_AREA_FLAGS_CUBE = 3 << 28, //0x18000000,
- //e_AREA_FLAGS_BOX = 4 << 28, //0x20000000,
- e_AREA_FLAGS_OVOID = 4 << 28, //0x08000000,
- e_AREA_FLAGS_OVAL = 5 << 28, //0x28000000,
- // The reserved type is now in use as a poly area child.
- //e_AREA_FLAGS_RES_0 = 6 << 28, //0x28000000,
- e_AREA_FLAGS_CHILD = 6 << 28, //0x30000000,
- e_AREA_FLAGS_CIRCLE = 7 << 28, //0x30000000,
- // Type mask.
- e_AREA_FLAGS_UNUSED = 0b000 << 28, //0x00000000,
- e_AREA_FLAGS_TYPE = 0b111 << 28, //0x38000000,
- // The "USED" flag isn't really needed any more, it's encoded in the type.
- // It seems the "used" flag was never read anyway...
- e_AREA_FLAGS_ACTIVE = 1 << 31,
- //e_AREA_FLAGS_USED = 1 << 31
- // If this is true AND AREA_VERY_FAST is on, the bounds check is identical
- // to the sphere check, so only do one.
- //e_AREA_FLAGS_BOUNDS = 1 << 31
- //e_AREA_FLAGS_SPHERE = 1 << 31
- }
- // Go backwards, so these all have the upper bit set.
- enum (+= -1)
- {
- e_AREA_ZONE_I_N = -1,
- e_AREA_ZONE_I_NE, // -2
- e_AREA_ZONE_I_E, // -3
- e_AREA_ZONE_I_SE, // -4
- e_AREA_ZONE_I_S, // -5
- e_AREA_ZONE_I_SW, // -6
- e_AREA_ZONE_I_W, // -7
- e_AREA_ZONE_I_NW, // -8
- e_AREA_ZONE_I_, // -9
- // "Outer" zones. -4000 > x, y > 4000;
- e_AREA_ZONE_O_N, // -10
- e_AREA_ZONE_O_NE, // -11
- e_AREA_ZONE_O_E, // -12
- e_AREA_ZONE_O_SE, // -13
- e_AREA_ZONE_O_S, // -14
- e_AREA_ZONE_O_SW, // -15
- e_AREA_ZONE_O_W, // -16
- e_AREA_ZONE_O_NW, // -17
- //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
- // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
- e_AREA_ZONE_X_N, // -18
- e_AREA_ZONE_X_NE, // -19
- e_AREA_ZONE_X_E, // -20
- e_AREA_ZONE_X_SE, // -21
- e_AREA_ZONE_X_S, // -22
- e_AREA_ZONE_X_SW, // -23
- e_AREA_ZONE_X_W, // -24
- e_AREA_ZONE_X_NW, // -25
- // Extra zones. For when areas are too big for a quadrant.
- e_AREA_ZONE_X_, // -26
- e_AREA_ZONE_NONE = cellmin
- }
- // =============================================================================
- // =============================================================================
- // IMPORTANT NOTE: The order of elements in this enum is INCREDIBLY important.
- // Because this is three enums in one, they share some pieces of data that must
- // not get overridden.
- // =============================================================================
- // =============================================================================
- // This might just be the most complex enum I've ever made!
- enum E_AREA
- {
- //union
- //{
- // struct
- // {
- #if YSIM_HAS_MASTER
- E_AREA_MASTER,
- #endif
- // This has increased from 4 to 6, so we can store cubes and ovoids
- // in a single slot.
- Float:E_AREA_POS[6],
- PlayerArray:E_AREA_PLAYERS<MAX_PLAYERS>,
- // This MUST go between "E_AREA_PLAYERS" and "E_AREA_FLAGS" to
- // remain constant in subsequent unions.
- //#if defined AREA_VERY_FAST
- // Float:E_AREA_BOUNDING[4],
- //#endif
- // As must this.
- #if AREA_WORLDS > 0
- BitArray:E_AREA_WORLDS<AREA_WORLDS>,
- #endif
- // ALWAYS last (actually used by EVERY type).
- e_AREA_FLAGS:E_AREA_FLAGS,
- // }
- // // Start of poly data.
- // struct
- // {
- // Reset the enum counter to 0 (on the next item).
- _E_AREA_RESET_@1 = -1,
- // Now restart.
- #if YSIM_HAS_MASTER
- // Skip the master flag if it exists.
- _E_AREA_MASTER_@1,
- #endif
- // This is where polys differ from all others.
- E_AREA_POLY_COUNT,
- E_AREA_POLY_NEXT,
- //Float:E_AREA_POLY_POS[4],
- // This slot holds ONLY the polygon bounding data, it doesn't hold
- // any co-ordinates AT ALL.
- //Float:E_AREA_BOUNDING[4],
- Float:E_AREA_POLY_BOUND_X,
- Float:E_AREA_POLY_BOUND_Y,
- Float:E_AREA_POLY_BOUND_R,
- Float:E_AREA_POLY_BOUND_H,
- // Skip all the array and flag data, they stay the same.
- _E_AREA_ARRAYS_@1[E_AREA_FLAGS - E_AREA_PLAYERS],
- // Skip the flags.
- E_AREA_UNUSED_NEXT,
- // }
- // // Start of poly child data.
- // struct
- // {
- // Reset the enum counter to 0 (on the next item).
- _E_AREA_RESET_@2 = -1,
- // Now restart.
- #if YSIM_HAS_MASTER
- // Skip the master flag if it exists.
- _E_AREA_MASTER_@2,
- #endif
- // Store a link to the parent of this poly child.
- E_AREA_CHILD_PARENT,
- // And the next one in VERY rare cases (I hope).
- // THIS SHARES A SLOT WITH "E_AREA_POLY_NEXT", so we can always just
- // use that slot when iterating.
- #if _:(E_AREA_FLAGS - E_AREA_CHILD_PARENT) & 1
- // There are an ODD number of available slots. We can store an
- // extra pair iff we don't need to use "NEXT".
- //_E_AREA_SKIP_@2,
- E_AREA_CHILD_OPT_Y,
- #endif
- E_AREA_CHILD_OPT_X,
- // Just store a vast number of X/Y pairs in this child.
- Float:E_AREA_CHILD_ELEMS[_:E_AREA_FLAGS - _:E_AREA_CHILD_OPT_X - 1],
- // Skip the flags.
- _E_AREA_CHILD_ELEMS_END
- // }
- }
- #define CHILD_AREA_SLOTS ((_:_E_AREA_CHILD_ELEMS_END - _:E_AREA_CHILD_ELEMS))
- static stock
- YSI_g_sUnusedAreas = 0,
- //YSI_g_sLastUnused = MAX_AREAS - 1,
- YSI_g_sFreeCount = MAX_AREAS,
- YSI_g_sAreas[MAX_AREAS][E_AREA],
- YSI_g_sPlayerArea[MAX_PLAYERS][AREAS_MAX_OVERLAPS], // = {NO_AREA, ...},
- YSI_g_sHasCallbacks,
- YSI_g_sZones[AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY] = {AREA_NO_NEXT, ...},
- // "Inner" zones. -4000 <= x, y <= 4000; Z(x) != Z(y)
- YSI_g_sZoneIN = AREA_NO_NEXT, // -1
- YSI_g_sZoneINE = AREA_NO_NEXT, // -2
- YSI_g_sZoneIE = AREA_NO_NEXT, // -3
- YSI_g_sZoneISE = AREA_NO_NEXT, // -4
- YSI_g_sZoneIS = AREA_NO_NEXT, // -5
- YSI_g_sZoneISW = AREA_NO_NEXT, // -6
- YSI_g_sZoneIW = AREA_NO_NEXT, // -7
- YSI_g_sZoneINW = AREA_NO_NEXT, // -8
- // "Outer" zones. -4000 > x, y > 4000;
- YSI_g_sZoneON = AREA_NO_NEXT, // -9
- YSI_g_sZoneONE = AREA_NO_NEXT, // -10
- YSI_g_sZoneOE = AREA_NO_NEXT, // -11
- YSI_g_sZoneOSE = AREA_NO_NEXT, // -12
- YSI_g_sZoneOS = AREA_NO_NEXT, // -13
- YSI_g_sZoneOSW = AREA_NO_NEXT, // -14
- YSI_g_sZoneOW = AREA_NO_NEXT, // -15
- YSI_g_sZoneONW = AREA_NO_NEXT, // -16
- // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
- YSI_g_sZoneXN = AREA_NO_NEXT, // -17
- YSI_g_sZoneXNE = AREA_NO_NEXT, // -18
- YSI_g_sZoneXE = AREA_NO_NEXT, // -19
- YSI_g_sZoneXSE = AREA_NO_NEXT, // -20
- YSI_g_sZoneXS = AREA_NO_NEXT, // -21
- YSI_g_sZoneXSW = AREA_NO_NEXT, // -22
- YSI_g_sZoneXW = AREA_NO_NEXT, // -23
- YSI_g_sZoneXNW = AREA_NO_NEXT, // -24
- // Extra zones. For when areas are too big for a quadrant.
- YSI_g_sZoneI = AREA_NO_NEXT, // -25
- //YSI_g_sZoneO = AREA_NO_NEXT, // -26
- YSI_g_sZoneX = AREA_NO_NEXT; // -27
- forward Area_Loop();
- /*----------------------------------------------------------------------------*-
- Function:
- OnScriptInit
- Params:
- -
- Return:
- -
- Notes:
- Sets up required variables. Note that this hooks "OnScriptInit",
- "OnGameModeInit" and "OnFilterScript". This is because ALL scripts need to
- initialise some things, and only the master needs to initialise others.
- -*----------------------------------------------------------------------------*/
- mhook OnScriptInit()
- {
- for (new i = 0; i != MAX_AREAS - 1; ++i)
- {
- YSI_g_sAreas[i][E_AREA_UNUSED_NEXT] = (i + 1);
- }
- YSI_g_sAreas[MAX_AREAS - 1][E_AREA_UNUSED_NEXT] = AREA_NO_NEXT;
- //for (new i = 0; i != AREAS_ZONE_ARRAY * AREAS_ZONE_ARRAY; ++i)
- //{
- // YSI_g_sZones[i] = -1;
- //}
- return 1;
- }
- #if !defined FILTERSCRIPT
- hook OnGameModeInit()
- {
- if (!YSI_FILTERSCRIPT)
- {
- new
- buffer;
- YSI_g_sHasCallbacks = 0;
- YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
- YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
- YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
- YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
- }
- }
- #endif
- hook OnFilterScriptInit()
- {
- new
- buffer;
- YSI_g_sHasCallbacks = 0;
- YSI_g_sHasCallbacks |= funcidx("OnPlayerEnterArea") == -1 ? 0 : 1;
- YSI_g_sHasCallbacks |= funcidx("OnPlayerLeaveArea") == -1 ? 0 : 2;
- YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerEnterArea") ? 4 : 0;
- YSI_g_sHasCallbacks |= AMX_GetPublicEntry(0, buffer, "@yH_PlayerLeaveArea") ? 8 : 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetEmptySlotCount
- Params:
- -
- Return:
- Number of unused area slots.
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- #define Area_GetEmptySlotCount() \
- (YSI_g_sFreeCount)
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddSlots
- Params:
- num - Number of slots to add.
- Return:
- -
- Notes:
- Actually removes slots from the unused count.
- -*----------------------------------------------------------------------------*/
- #define Area_AddSlots(%1) \
- YSI_g_sFreeCount -= (%1)
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsActive
- Params:
- area - Area to check validity of
- Return:
- -
- Notes:
- An area slot could be used but still invalid if it's not the first slot in
- an area set.
- -*----------------------------------------------------------------------------*/
- #define Area_IsActive(%1) \
- ((%1) >= 0 && (%1) < MAX_AREAS && (YSI_g_sAreas[(%1)][E_AREA_FLAGS] & e_AREA_FLAGS_ACTIVE))
- /*----------------------------------------------------------------------------*-
- Function:
- Area_Debug
- Params:
- area - Area to print information about.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign void:Area_Debug(area);
- global void:Area_Debug(area)
- {
- new
- e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
- if ((flags & e_AREA_FLAGS_ACTIVE))
- {
- switch (flags & e_AREA_FLAGS_TYPE)
- {
- case e_AREA_FLAGS_POLY:
- {
- new
- count = YSI_g_sAreas[area][E_AREA_POLY_COUNT];
- printf("Poly Area %d:", area);
- printf("\tPoints = %d", count);
- printf("\tNext = %d", YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] & AREA_NO_NEXT);
- #if AREA_WORLDS > 0
- printf("\tWorlds = %s", Bit_Display(YSI_g_sAreas[area][E_AREA_WORLDS], bits<AREA_WORLDS>));
- #else
- printf("\tNo Worlds");
- #endif
- printf("\tPlayers = %s", Bit_Display(YSI_g_sAreas[area][E_AREA_PLAYERS][1], bits<MAX_PLAYERS>));
- 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]);
- new
- next = YSI_g_sAreas[area][E_AREA_POLY_NEXT];
- while (count > 0)
- {
- printf("\tPoints Set %d:", next);
- for (new i = 0, j = min(count, CHILD_AREA_SLOTS); i < j; i += 2)
- {
- printf("\t\t(%.2f, %.2f)", YSI_g_sAreas[next][E_AREA_CHILD_ELEMS][i], YSI_g_sAreas[next][E_AREA_CHILD_ELEMS][i + 1]);
- }
- next = YSI_g_sAreas[next][E_AREA_POLY_NEXT];
- count -= CHILD_AREA_SLOTS;
- }
- }
- }
- //return 1;
- }
- //return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetFreeSlot
- Params:
- -
- Return:
- Next available slot.
- Notes:
- Gets an empty slot, removes it from the unused list and returs a pointer.
- -*----------------------------------------------------------------------------*/
- static stock Area_GetFreeSlot()
- {
- P:4("Area_GetFreeSlot called");
- if (YSI_g_sUnusedAreas == AREA_NO_NEXT) return NO_AREA;
- P:7("Area_GetFreeSlot: 1");
- new
- old = YSI_g_sUnusedAreas;
- YSI_g_sUnusedAreas = YSI_g_sAreas[old][E_AREA_UNUSED_NEXT];
- --YSI_g_sFreeCount;
- return old;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_Delete
- Params:
- area - Area to remove from the list.
- Return:
- -
- Notes:
- You can only remove areas which are at the start of a list.
- -*----------------------------------------------------------------------------*/
- foreign void:Area_Delete(area);
- global void:Area_Delete(area)
- {
- if (!Area_IsActive(area))
- {
- return; //0;
- }
- new
- e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
- switch (flags & e_AREA_FLAGS_TYPE)
- {
- case e_AREA_FLAGS_UNUSED:
- {
- return; //0;
- }
- case e_AREA_FLAGS_CHILD:
- {
- // This is just part of a poly, remove the whole thing.
- Area_Delete(YSI_g_sAreas[area][E_AREA_CHILD_PARENT]);
- }
- case e_AREA_FLAGS_POLY:
- {
- // Many blocks used - hard.
- new
- count = YSI_g_sAreas[area][E_AREA_POLY_COUNT],
- next = YSI_g_sAreas[area][E_AREA_POLY_NEXT],
- prev = YSI_g_sUnusedAreas;
- // All all of this poly area to the old area.
- while (count > 0)
- {
- // Increase the free count.
- ++YSI_g_sFreeCount;
- // Decrease the stored points.
- count -= CHILD_AREA_SLOTS;
- // Change the poly list to an unused list.
- YSI_g_sAreas[next][E_AREA_UNUSED_NEXT] = prev;
- prev = next;
- next = YSI_g_sAreas[next][E_AREA_POLY_NEXT];
- }
- // Remove the poly header.
- ++YSI_g_sFreeCount;
- YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] = prev;
- YSI_g_sUnusedAreas = area;
- }
- default:
- {
- // Only one block used - easy.
- YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] = YSI_g_sUnusedAreas;
- YSI_g_sUnusedAreas = area;
- ++YSI_g_sFreeCount;
- }
- }
- // Remove this one from the zone it was in.
- Area_DoRemove(_:(flags & e_AREA_FLAGS_ZONE), area, _:(flags & e_AREA_FLAGS_NEXT));
- //return 1;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_DoRemove
- Params:
- zone - The zone this area is in (right shifted 18).
- start - The first of the allocated areas being removed.
- end - The area in this zone after the last removed one.
- Return:
- -
- Notes:
- Very tightly integrated with "Area_Delete", to the point where I could just
- make them one function if I wanted (but I won't).
- -*----------------------------------------------------------------------------*/
- static stock Area_DoRemove(zone, area, next)
- {
- //printf("remove %d %d %d %d", zone << 18, area, next, (e_AREA_ZONE_I_ << 18 & _:e_AREA_FLAGS_ZONE));
- // Actually "zone << 18", but that's not important.
- switch (zone)
- {
- case (e_AREA_ZONE_I_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIN, area, next);}
- case (e_AREA_ZONE_I_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneINE, area, next);}
- case (e_AREA_ZONE_I_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIE, area, next);}
- case (e_AREA_ZONE_I_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneISE, area, next);}
- case (e_AREA_ZONE_I_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIS, area, next);}
- case (e_AREA_ZONE_I_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneISW, area, next);}
- case (e_AREA_ZONE_I_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneIW, area, next);}
- case (e_AREA_ZONE_I_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneINW, area, next);}
- case (e_AREA_ZONE_I_ << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneI, area, next);}
- // "Outer" zones. -4000 > x, y > 4000;
- case (e_AREA_ZONE_O_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneON, area, next);}
- case (e_AREA_ZONE_O_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneONE, area, next);}
- case (e_AREA_ZONE_O_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOE, area, next);}
- case (e_AREA_ZONE_O_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOSE, area, next);}
- case (e_AREA_ZONE_O_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOS, area, next);}
- case (e_AREA_ZONE_O_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOSW, area, next);}
- case (e_AREA_ZONE_O_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneOW, area, next);}
- case (e_AREA_ZONE_O_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneONW, area, next);}
- //e_AREA_ZONE_O_, // Can't be in all of O, but none of I.
- // "Extra" zones. In a quadrant, but spanning the +-4000 boundary.
- case (e_AREA_ZONE_X_N << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXN, area, next);}
- case (e_AREA_ZONE_X_NE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXNE, area, next);}
- case (e_AREA_ZONE_X_E << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXE, area, next);}
- case (e_AREA_ZONE_X_SE << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXSE, area, next);}
- case (e_AREA_ZONE_X_S << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXS, area, next);}
- case (e_AREA_ZONE_X_SW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXSW, area, next);}
- case (e_AREA_ZONE_X_W << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXW, area, next);}
- case (e_AREA_ZONE_X_NW << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneXNW, area, next);}
- // Extra zones. For when areas are too big for a quadrant.
- case (e_AREA_ZONE_X_ << 18 & _:e_AREA_FLAGS_ZONE): {_AREAS_DO_REMOVE(YSI_g_sZoneX, area, next);}
- default: {_AREAS_DO_REMOVE(YSI_g_sZones[zone >> 18], area, next);}
- }
- return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetZones
- Params:
- Float:x - Start of an area.
- Float:y - Start of an area.
- Return:
- All the zones this position overlaps.
- Notes:
- The most zones you can be in at once is 9 - I_, I_S, I_E, I_SE, X_, X_S,
- X_E, X_SE, Z_ (or similar corners - NOT in O_ though).
- -*----------------------------------------------------------------------------*/
- static stock Area_GetZones(Float:x, Float:y)
- {
- // Always end with e_AREA_ZONE_X_ as they will ALWAYS be in that one (that's
- // basically everywhere and means the area exists somewhere ever). Once
- // that zone is detected, stop next loop.
- static const
- scZones[16][9] =
- {
- {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},
- {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},
- {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},
- {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},
-
- {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},
- {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_ },
- {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_ },
- {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},
-
- {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},
- {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_ },
- {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_ },
- {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},
-
- {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},
- {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},
- {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},
- {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}
- };
- if (AREAS_ZONE_BOUNDS.0 <= x)
- {
- if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 0];
- else if (0.0 <= y) return scZones[ 1];
- else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 2];
- else return scZones[ 3];
- }
- else if (0.0 <= x)
- {
- if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 4];
- else if (0.0 <= y) return scZones[ 5]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
- else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 6]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
- else return scZones[ 7];
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= x)
- {
- if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[ 8];
- else if (0.0 <= y) return scZones[ 9]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
- else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[10]; //, ret[0] = _AREAS_MAKE_ZONE(Area_MakeZone(x), Area_MakeZone(y)));
- else return scZones[11];
- }
- else
- {
- if (AREAS_ZONE_BOUNDS.0 <= y) return scZones[12];
- else if (0.0 <= y) return scZones[13];
- else if (-AREAS_ZONE_BOUNDS.0 <= y) return scZones[14];
- else return scZones[15];
- }
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_DetermineZone
- Params:
- Float:minx - Start of an area.
- Float:miny - Start of an area.
- Float:maxx - End of an area.
- Float:maxy - End of an area.
- area - The area to add to the determined zone.
- last - The last slot that makes up the current zone.
- Return:
- -
- Notes:
- Finds the smallest zone that this area will fit in completely. Note that
- due to a limitation in the code, any zones with a node touching the upper
- edge of a zone will spill in to the next zone too. Only lower zone edges
- are inclusive.
- -*----------------------------------------------------------------------------*/
- static stock Area_DetermineZone(Float:minx, Float:miny, Float:maxx, Float:maxy, area, last)
- {
- new
- zx,
- zy;
- // This optimises based on the fact that (by definition) maxx can't be lower
- // than minx and maxy can't be lower than miny, meaning we can skip certain
- // checks in some cases.
- if (AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
- {
- if (0.0 <= miny) // Southern edge.
- {
- _AREAS_ZONES_O(NE);
- //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;
- //return _AREAS_ADD_TO_ZONE(YSI_g_sZoneXNE,area,last,e_AREA_ZONE_X_NE)
- }
- else // Southern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_O(E);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SE);
- }
- }
- }
- else if (0.0 <= minx) // Western edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- _AREAS_ZONES_O(NE);
- }
- else if (0.0 <= miny) // Southern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_X(NE);
- }
- else // Eastern edge.
- {
- // Interesting case - y > 0, 0 <= x < 4000.
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(NE);
- }
- else // Northern edge.
- {
- //_AREAS_ZONES_I_GRID;
- zx = Area_MakeZone(minx);
- zy = Area_MakeZone(miny);
- if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
- {
- zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
- YSI_g_sAreas[last][E_AREA_FLAGS] =
- (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
- (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
- (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
- P:7("Area_DetermineZone: Added to North-Eastern square");
- return YSI_g_sZones[zy] = area;
- }
- _AREAS_ZONES_I(NE);
- }
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(E);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_X(SE);
- }
- }
- else // Eastern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(E);
- }
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_I(E);
- }
- else // Northern edge.
- {
- zx = Area_MakeZone(minx);
- zy = Area_MakeZone(miny);
- if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
- {
- zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
- YSI_g_sAreas[last][E_AREA_FLAGS] =
- (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
- (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
- (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
- return YSI_g_sZones[zy] = area;
- }
- _AREAS_ZONES_I(SE);
- }
- }
- }
- else // Southern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(E);
- }
- if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(SE);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SE);
- }
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= minx) // Western edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_O(N);
- }
- else // Eastern edge.
- {
- _AREAS_ZONES_O(NW);
- }
- }
- else if (0.0 <= miny) // Southern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_X(N);
- }
- else if (0.0 <= maxx) // Eastern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(N);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_I(N);
- }
- }
- else // Eastern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(NW);
- }
- else // Northern edge.
- {
- zx = Area_MakeZone(minx);
- zy = Area_MakeZone(miny);
- if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
- {
- zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
- YSI_g_sAreas[last][E_AREA_FLAGS] =
- (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
- (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
- (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
- return YSI_g_sZones[zy] = area;
- }
- _AREAS_ZONES_I(NW);
- }
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X();
- }
- else // Northern edge.
- {
- _AREAS_ZONES_X(S);
- }
- }
- else if (0.0 <= maxx) // Eastern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X();
- }
- else if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_I();
- }
- else // Northern edge.
- {
- _AREAS_ZONES_I(S);
- }
- }
- else // Eastern edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(W);
- }
- else if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_I(W);
- }
- else // Northern edge.
- {
- zx = Area_MakeZone(minx);
- zy = Area_MakeZone(miny);
- if (zx == Area_MakeZone(maxx) && zy == Area_MakeZone(maxy))
- {
- zy += ((zx + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS;
- YSI_g_sAreas[last][E_AREA_FLAGS] =
- (YSI_g_sAreas[last][E_AREA_FLAGS] & e_AREA_FLAGS_REST) |
- (e_AREA_FLAGS:YSI_g_sZones[zy] & e_AREA_FLAGS_NEXT) |
- (e_AREA_FLAGS:(zy << 18) & e_AREA_FLAGS_ZONE);
- return YSI_g_sZones[zy] = area;
- }
- _AREAS_ZONES_I(SW);
- }
- }
- }
- else // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(S);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(S);
- }
- }
- else // Eastern edge.
- {
- if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(SW);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SW);
- }
- }
- }
- }
- else // Western edge.
- {
- if (AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_O(N);
- }
- else // Eastern edge.
- {
- // I missed this one and the compiler didn't complain about the
- // path not returning - I think I confused it!
- _AREAS_ZONES_O(NW);
- }
- }
- else if (0.0 <= miny) // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_X(N);
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- _AREAS_ZONES_X(NW);
- }
- else // Eastern edge.
- {
- _AREAS_ZONES_O(NW);
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= miny) // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X();
- }
- else
- {
- _AREAS_ZONES_X(S);
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(W);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_X(SW);
- }
- }
- else // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_O(W);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SW);
- }
- }
- }
- else // Southern edge.
- {
- if (0.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X();
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(S);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(S);
- }
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= maxx) // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(W);
- }
- else if (-AREAS_ZONE_BOUNDS.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_X(SW);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SW);
- }
- }
- else // Eastern edge.
- {
- if (0.0 <= maxy) // Northern edge.
- {
- _AREAS_ZONES_O(W);
- }
- else // Northern edge.
- {
- _AREAS_ZONES_O(SW);
- }
- }
- }
- }
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddTo
- Params:
- area - Area to set for.
- set - Wether or not this area is usable in all worlds.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- /*----------------------------------------------------------------------------*-
- Function:
- Area_SetAllWorlds
- Params:
- area - Area to set for.
- set - Wether or not this area is usable in all worlds.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign void:Area_SetAllWorlds(area, bool:set);
- global void:Area_SetAllWorlds(area, bool:set)
- {
- #if AREA_WORLDS > 0
- if (Area_IsActive(area))
- {
- Bit_SetAll(YSI_g_sAreas[area][E_AREA_WORLDS], set, bits<AREA_WORLDS>);
- //return 1;
- }
- #else
- #pragma unused area, set
- #endif
- //return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_Add
- Params:
- type - Type of area.
- ... - Points.
- Return:
- -
- Notes:
- Types:
- CUBE, Cube
- CUBOID, Cuboid
- BOX, Box
- CIRCLE, Circle
- OVAL, Oval
- OVOID, Ovoid
- SPHERE, Sphere
- POLY, Poly
- -*----------------------------------------------------------------------------*/
- #define Area_Add(%0,%1) Area_Add%0(%1)
- #define Area_AddCUBE Area_AddCube
- #define Area_AddCUBOID Area_AddCuboid
- #define Area_AddBOX Area_AddBox
- #define Area_AddCIRCLE Area_AddCircle
- #define Area_AddOVAL Area_AddOval
- #define Area_AddOVOID Area_AddOvoid
- #define Area_AddSPHERE Area_AddSphere
- #define Area_AddPOLY Area_AddPoly
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddCube
- Params:
- Float:minx - Lowest X corner of box
- Float:miny - Lowest Y corner of box.
- Float:minx - Lowest Z corner of box.
- Float:maxx - Highest X corner of box.
- Float:maxy - Highest Y corner of box.
- Float:maxz - Highest Z corner of box.
- Return:
- Area slot or NO_AREA
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- #define _AREA_MIN(%0,%1) if (%1 < %0) %0 ^= %1, %1 ^= %0, %0 ^= %1
- @foreign Area_AddCuboid(Float:x0,Float:y0,Float:z0,Float:x1,Float:y1,Float:z1);
- @global Area_AddCuboid(Float:x0,Float:y0,Float:z0,Float:x1,Float:y1,Float:z1)
- {
- new
- slot = Area_GetFreeSlot();
- if (slot == NO_AREA) return NO_AREA;
- _AREA_MIN(x0, x1);
- _AREA_MIN(z0, y1);
- _AREA_MIN(z0, z1);
- YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_CUBE | e_AREA_FLAGS_ACTIVE;
- YSI_g_sAreas[slot][E_AREA_POS][0] = x0;
- YSI_g_sAreas[slot][E_AREA_POS][1] = y0;
- YSI_g_sAreas[slot][E_AREA_POS][2] = z0;
- YSI_g_sAreas[slot][E_AREA_POS][3] = x1;
- YSI_g_sAreas[slot][E_AREA_POS][4] = y1;
- YSI_g_sAreas[slot][E_AREA_POS][5] = z1;
- PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
- NO_GROUPS(slot)
- {
- PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
- }
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
- #endif
- Area_SetAllWorlds(slot, true);
- Area_DetermineZone(x0, y0, x1, y1, slot, slot);
- /*#if defined AREA_VERY_FAST
- new
- rx = (x1 - z0) / 2.0,
- ry = (y1 - y0) / 2.0,
- rz = (z1 - z0) / 2.0;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x0 + rx;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y0 + ry;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = z0 + rz;
- if (rx > ry && rx > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
- }
- else if (ry > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
- }
- else
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
- }
- #endif*/
- return slot;
- }
- #undef _AREA_MIN
- #define Area_AddCube Area_AddCuboid
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddBox
- Params:
- Float:minx - Lowest X corner of box
- Float:miny - Lowest Y corner of box.
- Float:maxx - Highest X corner of box.
- Float:maxy - Highest Y corner of box.
- Return:
- Area slot or NO_AREA
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- stock Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy)
- {
- return Area_AddCuboid(minx, miny, FLOAT_NEGATIVE_INFINITY, maxx, maxy, FLOAT_INFINITY);
- }
- /*
- @foreign Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy);
- @global Area_AddBox(Float:minx, Float:miny, Float:maxx, Float:maxy)
- {
-
- new
- slot;
- if (minx > maxx)
- {
- slot = _:minx;
- minx = maxx;
- maxx = Float:slot;
- }
- if (miny > maxy)
- {
- slot = _:miny;
- miny = maxy;
- maxy = Float:slot;
- }
- slot = Area_GetFreeSlot();
- if (slot == NO_AREA) return NO_AREA;
- 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);
- YSI_g_sAreas[slot][E_AREA_POS][0] = minx;
- YSI_g_sAreas[slot][E_AREA_POS][1] = miny;
- YSI_g_sAreas[slot][E_AREA_POS][2] = maxx;
- YSI_g_sAreas[slot][E_AREA_POS][3] = maxy;
- PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
- NO_GROUPS(slot)
- {
- PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
- }
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
- #endif
- Area_SetAllWorlds(slot, true);
- Area_DetermineZone(minx, miny, maxx, maxy, slot, slot);
- return slot;
- }
- */
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddCircle
- Params:
- Float:x - X position of circle.
- Float:y - Y position of circle.
- Float:r - Radius of circle.
- Float:height - Ceiling of circle.
- Float:depth - Bottom of circle.
- Return:
- Area slot or NO_AREA
- Notes:
- Technically a cylinder, no lower bound (ceiling added cos there was a
- spare slot in the 4 float design which may as well have been used).
- -*----------------------------------------------------------------------------*/
- stock Area_AddCircle(Float:x, Float:y, Float:r, Float:height = FLOAT_INFINITY)
- {
- return Area_AddOval(x, y, r, r, height, FLOAT_NEGATIVE_INFINITY);
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddOval
- Params:
- Float:x - X position of circle.
- Float:y - Y position of circle.
- Float:rx - X Radius of oval.
- Float:ry - Y Radius of oval.
- Float:height - Ceiling of circle.
- Float:depth - Bottom of circle.
- Return:
- Area slot or NO_AREA
- Notes:
- Technically a cylinder, no lower bound (ceiling added cos there was a
- spare slot in the 4 float design which may as well have been used).
- -*----------------------------------------------------------------------------*/
- @foreign Area_AddOval(Float:x,Float:y,Float:rx,Float:ry,Float:h,Float:d);
- @global Area_AddOval(Float:x,Float:y,Float:rx,Float:ry,Float:h,Float:d)
- {
- new
- slot = Area_GetFreeSlot();
- if (slot == NO_AREA) return NO_AREA;
- //printf("%f %f %f %f", x - r, y - r, x + r, y + r);
- YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE;
- YSI_g_sAreas[slot][E_AREA_POS][0] = x;
- YSI_g_sAreas[slot][E_AREA_POS][1] = y;
- YSI_g_sAreas[slot][E_AREA_POS][2] = rx * rx;
- YSI_g_sAreas[slot][E_AREA_POS][3] = ry * ry;
- YSI_g_sAreas[slot][E_AREA_POS][4] = h;
- YSI_g_sAreas[slot][E_AREA_POS][5] = d;
- PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
- NO_GROUPS(slot)
- {
- PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
- }
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
- #endif
- Area_SetAllWorlds(slot, true);
- Area_DetermineZone(x - rx, y - ry, x + rx, y + ry, slot, slot);
- if (rx == ry && h == FLOAT_INFINITY && d == FLOAT_NEGATIVE_INFINITY)
- {
- YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_CIRCLE;
- }
- else
- {
- YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_OVAL;
- }
- // Bounding sphere. I'm not convinced this is needed on the simple shapes,
- // I may only use it on polys and special-case
- /*#if defined AREA_VERY_FAST
- YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y;
- // Z radius of the bounding sphere (may be VERY huge).
- new
- rz = (h - d) / 2.0;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = h - rz;
- if (rx > ry && rx > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
- }
- else if (ry > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
- }
- else
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
- }
- #endif*/
- return slot;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddSphere
- Params:
- Float:x - X position of sphere.
- Float:y - Y position of sphere.
- Float:z - Z position of sphere.
- Float:r - Radius of sphere.
- Return:
- Area slot or NO_AREA
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- stock Area_AddSphere(Float:x, Float:y, Float:z, Float:r)
- {
- return Area_AddOvoid(x, y, z, r, r, r)
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddOvoid
- Params:
- Float:x - X position of sphere.
- Float:y - Y position of sphere.
- Float:z - Z position of sphere.
- Float:rx - X radius of ovoid.
- Float:ry - Y radius of ovoid.
- Float:rz - Z radius of ovoid.
- Return:
- Area slot or NO_AREA
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- @foreign Area_AddOvoid(Float:x,Float:y,Float:z,Float:rx,Float:ry,Float:rz);
- @global Area_AddOvoid(Float:x,Float:y,Float:z,Float:rx,Float:ry,Float:rz)
- {
- new
- slot = Area_GetFreeSlot();
- if (slot == NO_AREA) return NO_AREA;
- YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE;
- YSI_g_sAreas[slot][E_AREA_POS][0] = x;
- YSI_g_sAreas[slot][E_AREA_POS][1] = y;
- YSI_g_sAreas[slot][E_AREA_POS][2] = z;
- YSI_g_sAreas[slot][E_AREA_POS][3] = rx * rx;
- YSI_g_sAreas[slot][E_AREA_POS][4] = ry * ry;
- YSI_g_sAreas[slot][E_AREA_POS][5] = rz * rz;
- PA_FastInit(YSI_g_sAreas[slot][E_AREA_PLAYERS]);
- NO_GROUPS(slot)
- {
- PA_Init(YSI_g_sAreas[slot][E_AREA_PLAYERS], true);
- }
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
- #endif
- Area_SetAllWorlds(slot, true);
- Area_DetermineZone(x - rx, y - ry, x + rx, y + ry, slot, slot);
- // Create the bounding sphere for this zone. The player has to be inside
- // the bounding sphere before they can be inside the oval. Of course, if
- // the oval is also a sphere then these two checks are identical.
- #if defined AREA_VERY_FAST
- YSI_g_sAreas[slot][E_AREA_BOUNDING][0] = x;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][1] = y;
- YSI_g_sAreas[slot][E_AREA_BOUNDING][2] = z;
- if (rx > ry && rx > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rx * rx;
- }
- else if (ry > rz)
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = ry * ry;
- }
- else
- {
- YSI_g_sAreas[slot][E_AREA_BOUNDING][3] = rz * rz;
- }
- if (rx == ry && rx == rz)
- {
- YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_SPHERE;
- }
- else
- #endif
- {
- // Create the zone bounds.
- YSI_g_sAreas[slot][E_AREA_POS][0] = x;
- YSI_g_sAreas[slot][E_AREA_POS][1] = y;
- YSI_g_sAreas[slot][E_AREA_POS][2] = z;
- YSI_g_sAreas[slot][E_AREA_POS][3] = rx * rx;
- YSI_g_sAreas[slot][E_AREA_POS][4] = ry * ry;
- YSI_g_sAreas[slot][E_AREA_POS][5] = rz * rz;
- // Set this as not a sphere.
- YSI_g_sAreas[slot][E_AREA_FLAGS] |= e_AREA_FLAGS_OVOID;
- }
- #pragma tabsize 4
- return slot;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_AddPoly
- Params:
- Float:... - X/Ys of points
- Return:
- Area slot or NO_AREA
- Notes:
- Creates an irregular shape to detect players in. This is a 2d area made
- up of a load of XY points. If an odd number of parameters is passed the
- extra one is assumed to be a ceiling so you can ignore interiors or planes.
-
- The height parameter goes first as it's easiest to check.
-
- This is one of a few functions still written using the master system at a
- low level (the other obvious one is "Class_Add").
- -*----------------------------------------------------------------------------*/
- #if YSIM_HAS_MASTER
- #if _YSIM_IS_SERVER
- forward Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...);
-
- forward Area_AddPoly@(Float:points[], size, count);
-
- stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
- {
- new
- args = numargs();
- if (args > 128)
- {
- return NO_AREA;
- }
- new
- Float:points[128];
- points[0] = x1;
- points[1] = y1;
- points[2] = x2;
- points[3] = y2;
- points[4] = x3;
- points[5] = y3;
- for (new i = 6; i != args; ++i)
- {
- points[i] = Float:getarg(i);
- }
- return Area_AddPoly@(points, sizeof (points), args);
- }
-
- public Area_AddPoly@(Float:points[], size, count)
- #else
- stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <>
- {
- new
- args = numargs();
- if (args > 128)
- {
- return NO_AREA;
- }
- new
- Float:points[128];
- points[0] = x1;
- points[1] = y1;
- points[2] = x2;
- points[3] = y2;
- points[4] = x3;
- points[5] = y3;
- for (new i = 6; i != args; ++i)
- {
- points[i] = Float:getarg(i);
- }
- new
- p = getproperty(8, YSIM_CALLER);
- setproperty(8, YSIM_CALLER, _@);
- CallRemoteFunction("Area_AddPoly@", "aii", points, sizeof (points), args);
- setproperty(8, YSIM_CALLER, p);
- return getproperty(8, YSIM_RETURN);
- }
-
- forward Area_AddPoly@(Float:points[], size, count);
-
- stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : m>
- {
- #pragma unused x1, y1, x2, y2, x3, y3
- return NO_AREA;
- }
- #if _YSIM_IS_CLIENT
- static stock Area_AddPoly_(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
- #else
- #if _YSIM_IS_STUB
- #error _YSIM_IS_STUB set in y_areas.
- #else
- public Area_AddPoly@(Float:points[], size, count) <>
- {
- return 0;
- }
-
- /*{
- X@(_:@Zk:_YM@CP:%0(%1,,));
- setproperty(8, YSIM_RETURN, n);
- }*/
-
- stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...) <_YCM : y>
- {
- new
- args = numargs();
- if (args > 128)
- {
- return NO_AREA;
- }
- new
- Float:points[128];
- points[0] = x1;
- points[1] = y1;
- points[2] = x2;
- points[3] = y2;
- points[4] = x3;
- points[5] = y3;
- for (new i = 6; i != args; ++i)
- {
- points[i] = Float:getarg(i);
- }
- return Area_AddPoly@(points, sizeof (points), args);
- }
-
- public Area_AddPoly@(Float:points[], size, count) <_YCM : y>
- #endif
- #endif
- #endif
- #else
- stock Area_AddPoly(Float:x1, Float:y1, Float:x2, Float:y2, Float:x3, Float:y3, Float:...)
- {
- new
- args = numargs();
- if (args > 128)
- {
- return NO_AREA;
- }
- new
- Float:points[128];
- points[0] = x1;
- points[1] = y1;
- points[2] = x2;
- points[3] = y2;
- points[4] = x3;
- points[5] = y3;
- for (new i = 6; i != args; ++i)
- {
- points[i] = Float:getarg(i);
- }
- return Area_AddPoly_(points, sizeof (points), args);
- }
-
- static stock Area_AddPoly_(Float:points[], size, count)
- #endif
- {
- // This is the main chunk of the code.
- new
- Float:height = Float:isodd(count);
- count &= ~1;
- new
- reqSlots = ceildiv(count, CHILD_AREA_SLOTS) + 1;
- if (Area_GetEmptySlotCount() < reqSlots) return NO_AREA;
- if (_:height)
- {
- height = points[count];
- }
- else
- {
- height = FLOAT_INFINITY;
- }
- // Get the header. This stores meta-data about the poly area, and the
- // bounding cylinder, it doesn't actually store any points.
- new
- header = Area_GetFreeSlot();
- // Initialise the header. Area type, players, worlds, and count.
- // This stores the number of pairs, not the number of co-ordinates.
- YSI_g_sAreas[header][E_AREA_POLY_COUNT] = count;
- YSI_g_sAreas[header][E_AREA_FLAGS] = e_AREA_FLAGS_POLY | e_AREA_FLAGS_ACTIVE;
- PA_FastInit(YSI_g_sAreas[header][E_AREA_PLAYERS]);
- NO_GROUPS(header)
- {
- PA_Init(YSI_g_sAreas[header][E_AREA_PLAYERS], true);
- }
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[header][E_AREA_MASTER] = Master_Caller();
- #endif
- Area_SetAllWorlds(header, true);
- // Now loop through and store all the data points.
- new
- slot,
- prev = header,
- done = 0,
- Float:cur,
- Float:minx = FLOAT_INFINITY,
- Float:miny = FLOAT_INFINITY,
- Float:maxx = FLOAT_NEGATIVE_INFINITY,
- Float:maxy = FLOAT_NEGATIVE_INFINITY;
- while (done < count)
- //while (done < count)
- {
- slot = Area_GetFreeSlot();
- YSI_g_sAreas[slot][E_AREA_FLAGS] = e_AREA_FLAGS_ACTIVE | e_AREA_FLAGS_CHILD;
- // Rely purely on counts, not ended lists. This is because the system
- // MAY (if I get around to it) reuse this data in the last slot to
- //YSI_g_sAreas[slot][E_AREA_POLY_NEXT] = NO_AREA;
- YSI_g_sAreas[slot][E_AREA_CHILD_PARENT] = header;
- YSI_g_sAreas[prev][E_AREA_POLY_NEXT] = slot;
- #if YSIM_HAS_MASTER
- YSI_g_sAreas[slot][E_AREA_MASTER] = Master_Caller();
- #endif
- // Now loop and put points in this slot.
- size = min(count, done + CHILD_AREA_SLOTS);
- for (new idx = 0; done < size; )
- {
- // X point.
- cur = points[done++];
- //printf("%d X: %0.2f", done, cur);
- //printf("%04x%04x %04x%04x %.2f %d %d", _:minx >>> 16, _:minx & 0xFFFF, _:maxx >>> 16, _:maxx & 0xFFFF, cur, cur > maxx, cur < minx);
- if (cur > maxx) maxx = cur;
- if (cur < minx) minx = cur;
- YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][idx++] = cur;
- // Y point.
- cur = points[done++];
- //printf("%d Y: %0.2f", done, cur);
- // Can be both on the first loop (WILL be both on the first loop).
- if (cur > maxy) maxy = cur;
- if (cur < miny) miny = cur;
- YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][idx++] = cur;
- }
- prev = slot;
- //count -= CHILD_AREA_SLOTS * 2;
- }
- // Now clean up.
- #if YSIM_HAS_MASTER
- setproperty(8, YSIM_RETURN, header);
- #endif
- Area_DetermineZone(minx, miny, maxx, maxy, header, header);
- // Create the bounding cylinder so we can quickly determine if it is even
- // at all possible for the player to be in this polygon.
- // TODO: This doesn't YET create an accurate bounding cylinder as the
- // diagonals of a square are longer than the width and height, and that fact
- // isn't taken in to account by the radius. The question is, why are these
- // sums returning -0.0 for 20.0-0.0?
- // BIZZARE BUG FIX.
- //printf("%f %f %f %f", minx, miny, maxx, maxy);
- //printf("%f %f", maxx - minx, maxy - miny);
- //printf("%04x%04x", _:minx >>> 16, _:minx & 0xFFFF);
- //printf("%04x%04x", _:maxx >>> 16, _:maxx & 0xFFFF);
- //if (maxx && minx) printf("1: %d", (maxx = (maxx - minx) / 2.0));
- //else if (maxx) printf("2: %d", (maxx /= 2.0));
- //else printf("3: %d", (maxx = minx / 2.0));
- //if (maxx < 0.0) maxx = -maxx;
- //if (maxy && miny) maxy = (maxy - miny) / 2.0;
- //else if (maxy) maxy /= 2.0;
- //else maxy = miny / 2.0;
- //if (maxy < 0.0) maxy = -maxy;
- //printf("%f %f %f %f", (maxx - minx) / 2.0, (maxy - miny) / 2.0, minx + (maxx - minx) / 2.0, miny + (maxy - miny) / 2.0);
- maxx = (maxx - minx) / 2.0;
- maxy = (maxy - miny) / 2.0;
- //printf("%f %f %f %f", maxx, maxy, minx + maxx, miny + maxy);
- minx += maxx;
- miny += maxy;
- YSI_g_sAreas[header][E_AREA_POLY_BOUND_X] = minx;
- YSI_g_sAreas[header][E_AREA_POLY_BOUND_Y] = miny;
- // Now find the radius. Note that it might actually make more sense to not
- // use the dead centre but a point which minimises the R^2 distance, but
- // that will require a lot more work.
- slot = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
- count = YSI_g_sAreas[header][E_AREA_POLY_COUNT];
- cur = 0.0;
- while (count > 0)
- {
- for (new i = 0, j = min(count, CHILD_AREA_SLOTS); i < j; i += 2)
- {
- // Get the difference between the points.
- maxx = YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][i] - minx;
- maxy = YSI_g_sAreas[slot][E_AREA_CHILD_ELEMS][i + 1] - miny;
- maxx = maxx * maxx + maxy * maxy;
- if (maxx > cur) cur = maxx;
- }
- slot = YSI_g_sAreas[slot][E_AREA_POLY_NEXT];
- count -= CHILD_AREA_SLOTS;
- }
- YSI_g_sAreas[header][E_AREA_POLY_BOUND_R] = cur;
- YSI_g_sAreas[header][E_AREA_POLY_BOUND_H] = height;
- return header;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_OnPlayerConnect
- Params:
- playerid - Player who connected
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- mhook OnPlayerConnect(playerid)
- {
- for (new i = 0; i != AREAS_MAX_OVERLAPS; ++i)
- {
- YSI_g_sPlayerArea[playerid][i] = NO_AREA;
- }
- NO_GROUPS()
- {
- new
- slot = Bit_Slot(playerid) + 1,
- Bit:mask = Bit_Mask(playerid);
- for (new i = 0; i != MAX_AREAS; ++i)
- {
- YSI_g_sAreas[i][E_AREA_PLAYERS][slot] |= mask;
- }
- }
- return 1;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_loop
- Params:
- playerid - The player to check for.
- Return:
- -
- Notes:
- Main processing for the system. Takes one player and checks if they're in
- some sort of range of somewhere.
- -*----------------------------------------------------------------------------*/
- #if defined AREAS_USE_TIMER
-
- #error AREAS_USE_TIMER is currently unsupported sorry.
-
- ptask Area_Loop[200](playerid)
- {
- new
- Float:x,
- Float:y,
- Float:z,
- area = YSI_g_sPlayerArea[playerid],
- world = GetPlayerVirtualWorld(playerid);
- GetPlayerPos(playerid, x, y, z);
- if (area != NO_AREA)
- {
- if (Area_CheckArea(playerid, world, area, x, y, z)) continue;
- YSI_g_sPlayerArea[playerid] = NO_AREA;
- #if defined _YSI_GAMEMODE_PROPERTIES
- if (!Property_OnPlayerLeaveArea(playerid, area))
- #endif
- CallRemoteFunction("OnPlayerLeaveArea", "ii", playerid, area);
- }
- for (area = 0; area < MAX_AREAS; area++)
- {
- if (Area_CheckArea(playerid, world, area, x, y, z))
- {
- YSI_g_sPlayerArea[playerid] = area;
- CallRemoteFunction("OnPlayerEnterArea", "ii", playerid, area);
- break;
- }
- }
- }
- #else
- hook OnPlayerUpdate(playerid)
- {
- static
- // Another hard-coded limit (max areas we can actually be in, more
- // than the max that is globally stored, but still not infinate).
- sAreas[16],
- sZones[9],
- Float:sX,
- Float:sY,
- Float:sZ,
- sCur,
- sNext,
- sW,
- sAlready;
- new
- in,
- idx;
- // Get all the zones for this player.
- GetPlayerPos(playerid, sX, sY, sZ);
- P:7("Areas_OnPlayerUpdate: pos = %f %f %f", sX, sY, sZ);
- #if AREA_WORLDS > 0
- sW = GetPlayerVirtualWorld(playerid);
- #endif
- for ( ; (sCur = _Area_GetPlayerAreas(playerid, idx)) != NO_AREA; )
- {
- // In this zone too.
- if (Area_CheckArea(playerid, sW, sCur, sX, sY, sZ, sNext, sAreas, 0))
- {
- ++idx;
- sAreas[in++] = sCur;
- }
- else
- {
- // No longer in the area they used to be in.
- Area_DoLeave(playerid, sCur, idx);
- // "Area_DoLeave" shifts all the slots, so you end up with not
- // needing to change "idx" at all.
- }
- }
- sAlready = in;
- sZones = Area_GetZones(sX, sY);
- for (idx = 0; ; )
- {
- P:7("Areas_OnPlayerUpdate: zone = %d", sZones[idx]);
- switch (sZones[idx++])
- {
- case e_AREA_ZONE_I_N:
- {
- _AREA_DO_ALL(YSI_g_sZoneIN);
- }
- case e_AREA_ZONE_I_NE:
- {
- _AREA_DO_ALL(YSI_g_sZoneINE);
- }
- case e_AREA_ZONE_I_E:
- {
- _AREA_DO_ALL(YSI_g_sZoneIE);
- }
- case e_AREA_ZONE_I_SE:
- {
- _AREA_DO_ALL(YSI_g_sZoneISE);
- }
- case e_AREA_ZONE_I_S:
- {
- _AREA_DO_ALL(YSI_g_sZoneIS);
- }
- case e_AREA_ZONE_I_SW:
- {
- _AREA_DO_ALL(YSI_g_sZoneISW);
- }
- case e_AREA_ZONE_I_W:
- {
- _AREA_DO_ALL(YSI_g_sZoneIW);
- }
- case e_AREA_ZONE_I_NW:
- {
- _AREA_DO_ALL(YSI_g_sZoneINW);
- }
- case e_AREA_ZONE_I_:
- {
- _AREA_DO_ALL(YSI_g_sZoneI);
- }
- // "Outer" zones.
- case e_AREA_ZONE_O_N:
- {
- _AREA_DO_ALL(YSI_g_sZoneON);
- }
- case e_AREA_ZONE_O_NE:
- {
- _AREA_DO_ALL(YSI_g_sZoneONE);
- }
- case e_AREA_ZONE_O_E:
- {
- _AREA_DO_ALL(YSI_g_sZoneOE);
- }
- case e_AREA_ZONE_O_SE:
- {
- _AREA_DO_ALL(YSI_g_sZoneOSE);
- }
- case e_AREA_ZONE_O_S:
- {
- _AREA_DO_ALL(YSI_g_sZoneOS);
- }
- case e_AREA_ZONE_O_SW:
- {
- _AREA_DO_ALL(YSI_g_sZoneOSW);
- }
- case e_AREA_ZONE_O_W:
- {
- _AREA_DO_ALL(YSI_g_sZoneOW);
- }
- case e_AREA_ZONE_O_NW:
- {
- _AREA_DO_ALL(YSI_g_sZoneONW);
- }
- //case e_AREA_ZONE_O_:
- //{
- // _AREA_DO_ALL(YSI_g_sZoneO);
- //}
- case e_AREA_ZONE_X_N:
- {
- _AREA_DO_ALL(YSI_g_sZoneXN);
- }
- case e_AREA_ZONE_X_NE:
- {
- _AREA_DO_ALL(YSI_g_sZoneXNE);
- }
- case e_AREA_ZONE_X_E:
- {
- _AREA_DO_ALL(YSI_g_sZoneXE);
- }
- case e_AREA_ZONE_X_SE:
- {
- _AREA_DO_ALL(YSI_g_sZoneXSE);
- }
- case e_AREA_ZONE_X_S:
- {
- _AREA_DO_ALL(YSI_g_sZoneXS);
- }
- case e_AREA_ZONE_X_SW:
- {
- _AREA_DO_ALL(YSI_g_sZoneXSW);
- }
- case e_AREA_ZONE_X_W:
- {
- _AREA_DO_ALL(YSI_g_sZoneXW);
- }
- case e_AREA_ZONE_X_NW:
- {
- _AREA_DO_ALL(YSI_g_sZoneXNW);
- }
- case e_AREA_ZONE_X_:
- {
- // Always the last zone in the list.
- _AREA_DO_ALL(YSI_g_sZoneX);
- break;
- }
- case e_AREA_ZONE_NONE:
- {
- // Specific zone (which).
- _AREA_DO_ALL(YSI_g_sZones[((Area_MakeZone(sX) + AREAS_ZONE_PARTS) * AREAS_ZONE_ARRAY) + AREAS_ZONE_PARTS + Area_MakeZone(sY)]);
- }
- }
- }
- return 1;
- }
- #endif
- /*----------------------------------------------------------------------------*-
- Function:
- Area_CheckArea
- Params:
- playerid - Player being checked for.
- world - VW the player is in.
- area - Area to check against.
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- Return:
- -
- Notes:
- Checks if the given position is in the give area. All parameters are passed
- to avoid calling functions over and over and over again. If the return is
- not true, "area" is updated to the next one in the chain.
- -*----------------------------------------------------------------------------*/
- static stock Area_CheckArea(playerid, world, area, Float:x, Float:y, Float:z, &next, areas[16], already)
- {
- new
- e_AREA_FLAGS:flags = YSI_g_sAreas[area][E_AREA_FLAGS];
- next = YSI_g_sAreas[area][E_AREA_UNUSED_NEXT] & AREA_NO_NEXT;
- // Are they already in this area?
- while (already--)
- {
- if (areas[already] == area)
- {
- return 0;
- }
- }
- if ((flags & e_AREA_FLAGS_ACTIVE))
- {
- 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);
- switch (flags & e_AREA_FLAGS_TYPE)
- {
- case e_AREA_FLAGS_CIRCLE:
- {
- // In range of a sphere perfectly level with them.
- 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))
- {
- return 0;
- }
- }
- case e_AREA_FLAGS_OVAL:
- {
- if (!Area_IsInCircle(x, y, x, YSI_g_sAreas[area][E_AREA_POS]))
- {
- return 0;
- }
- }
- case e_AREA_FLAGS_OVOID:
- {
- if (!Area_IsInOvoid(x, y, z, YSI_g_sAreas[area][E_AREA_POS]))
- {
- return 0;
- }
- }
- case e_AREA_FLAGS_SPHERE:
- {
- 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]))
- {
- return 0;
- }
- }
- case e_AREA_FLAGS_POLY:
- {
- if (!Area_IsInPoly(x, y, z, area))
- {
- return 0;
- }
- }
- case e_AREA_FLAGS_CUBE:
- {
- if (!Area_IsInCube(x, y, z, YSI_g_sAreas[area][E_AREA_POS]))
- {
- return 0;
- }
- }
- }
- P:7("Area_CheckArea: MAYBE");
- if (PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid))
- {
- #if AREA_WORLDS > 0
- if (Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world))
- {
- return 1;
- }
- #else
- #pragma unused world
- return 1;
- #endif
- }
- }
- return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInCircle
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- Float:bounds[] - Data for the area position.
- Return:
- -
- Notes:
- Checks if a point is in a given circle.
- -*----------------------------------------------------------------------------*/
- static stock Area_IsInCircle(Float:x, Float:y, Float:z, Float:bounds[])
- {
- x -= bounds[0];
- y -= bounds[1];
- return (bounds[4] <= z <= bounds[5] && ((x * x) / bounds[2] + (y * y) / bounds[3]) < 1.0);
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInSphere
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- Float:bounds[] - Data for the area position.
- Return:
- -
- Notes:
- Checks if a point is in a given sphere.
- -*----------------------------------------------------------------------------*/
- /*static stock Area_IsInSphere(Float:x, Float:y, Float:z, Float:bounds[])
- {
- x -= bounds[0];
- y -= bounds[1];
- z -= bounds[2];
- return (((x * x) + (y * y) + (z * z)) < bounds[3]);
- }*/
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInOvoid
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- Float:bounds[] - Data for the area position.
- Return:
- -
- Notes:
- Checks if a point is in a given ovoid.
- -*----------------------------------------------------------------------------*/
- static stock Area_IsInOvoid(Float:x, Float:y, Float:z, Float:bounds[])
- {
- x -= bounds[0];
- y -= bounds[1];
- z -= bounds[2];
- return (((x * x) / bounds[3] + (y * y) / bounds[4] + (z * z) / bounds[5]) < 1.0);
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInPoly
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- header - Pointer to the start of the polygon data in the array.
- Return:
- -
- Notes:
- Based on IsPlayerInAreaEx by koolk in the useful functions topic. The
- passed pointer is the pointer to the first set of co-ordinates in a one-
- way not looping linked list of points in the polygod as the data may be
- spread throughout the areas array. This is as otherwise there may be
- enough free spaces but not in one block.
-
- The code first checks if there is a height component as it's the easiest
- to check thus may save a load of pointless processing. If this passes it
- then does the main loop. This loops till there are no points left to do
- (monitored by decreasing count). When 2 points (four pieces of data) have
- been checked the poiner for the data is moved on to the next group and the
- checking continues.
-
- For simplicity's sake (and thus speed's sake) the lower pointes from the
- last check are saved amd used as the upper points for the next check to
- avoid loads of repeated array accesses and saving the last array position.
- -*----------------------------------------------------------------------------*/
- /*static*/
- stock Area_IsInPoly(Float:x, Float:y, Float:z, header)
- {
- // First check the bounding zone.
- new
- Float:bx = x - YSI_g_sAreas[header][E_AREA_POLY_BOUND_X],
- Float:by = y - YSI_g_sAreas[header][E_AREA_POLY_BOUND_Y];
- P:7("Area_IsInPoly: %f %f %f %d", x, y, z, header);
- 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]));
- if (!(z <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_H] && (bx * bx + by * by) <= YSI_g_sAreas[header][E_AREA_POLY_BOUND_R]))
- {
- return 0;
- }
- // Within the bounding cylinder, do the more complex checks.
- new
- count = YSI_g_sAreas[header][E_AREA_POLY_COUNT];
- P:7("Area_IsInPoly: In the bounds: %d %d", count, CHILD_AREA_SLOTS);
- if (count <= CHILD_AREA_SLOTS)
- {
- // Only uses one single child slot.
- header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
- new
- lines,
- done = 2,
- Float:fx = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][0],
- Float:fy = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][1],
- Float:x0 = fx,
- Float:y0 = fy,
- Float:x1,
- Float:y1;
- while (done < count)
- {
- x1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
- y1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
- // Crosses this line.
- //P:7("Area_IsInPoly: %f %f %f", y0, y, y1);
- if (((y0 <= y <= y1) || (y1 <= y <= y0)) && ((x0 + ((y - y0) * (x1 - x0) / (y1 - y0))) <= x)) ++lines;
- //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);
- x0 = x1;
- y0 = y1;
- }
- //P:7("Area_IsInPoly: %f %f %f", y0, y, fy);
- if (((y0 <=y <= fy) || (fy <= y <= y0)) && (x0 + ((y - y0) * (fx - x0) / (fy - y0))) <= x) ++lines;
- //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);
- //P:7("Area_IsInPoly: Return %d", lines);
- return isodd(lines);
- }
- else
- {
- // Has multiple children
- header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
- new
- stp,
- lines,
- done = 2,
- Float:fx = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][0],
- Float:fy = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][1],
- Float:x0 = fx,
- Float:y0 = fy,
- Float:x1,
- Float:y1;
- while (count > 0)
- {
- stp = min(count, CHILD_AREA_SLOTS);
- while (done < stp)
- {
- x1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
- y1 = YSI_g_sAreas[header][E_AREA_CHILD_ELEMS][done++];
- // Crosses this line.
- if (((y0 <= y <= y1) || (y1 <= y <= y0)) && (x0 + ((y - y0) * (x1 - x0) / (y1 - y0))) <= x) ++lines;
- x0 = x1;
- y0 = y1;
- }
- count -= CHILD_AREA_SLOTS;
- done = 0;
- header = YSI_g_sAreas[header][E_AREA_POLY_NEXT];
- }
- //x1 = YSI_g_sAreas[pointer][E_AREA_CHILD_ELEMS][0];
- // Link the last and first points to complete the perimeter.
- if (((y0 <=y <= fy) || (fy <= y <= y0)) && (x0 + ((y - y0) * (fx - x0) / (fy - y0))) <= x) ++lines;
- //printf("Area_IsInPoly: Return %d", lines);
- return isodd(lines);
- }
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInCube
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:z - Z position to check.
- Float:lower[] - The lower corner of the cube.
- Float:upper[] - The upper corner of the cube.
- Return:
- -
- Notes:
- Checks if a point is in a given cube. This is another multi slot shape
- but is much simpler than the poly as it's always 2 slots so we can easilly
- get the data in one lump.
- -*----------------------------------------------------------------------------*/
- static stock Area_IsInCube(Float:x, Float:y, Float:z, Float:bounds[])
- {
- return (bounds[0] <= x <= bounds[3] && bounds[1] <= y <= bounds[4] && bounds[2] <= z <= bounds[5]);
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsInBox
- Params:
- Float:x - X position to check.
- Float:y - Y position to check.
- Float:bounds[] - Data for the area position.
- Return:
- -
- Notes:
- Checks if a point is in a given box. There is no height check with this
- one as any one area slot has 4 points which for this are upper and lower
- x and y, adding a height check would make it require 2 slots and basically
- make it a cube check.
- -*----------------------------------------------------------------------------*/
- /*static stock Area_IsInBox(Float:x, Float:y, Float:bounds[])
- {
- return (bounds[0] <= x <= bounds[2] && bounds[1] <= y <= bounds[3]);
- }*/
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetPlayerArea
- Params:
- playerid - Player to get area of.
- Return:
- The area a player is in or -1.
- Notes:
- Deprecated.
- -*----------------------------------------------------------------------------*/
- //foreign Area_GetPlayerArea(playerid);
- #pragma deprecated Use Area_GetPlayerAreas
- stock Area_GetPlayerArea(playerid)
- {
- if (0 <= playerid < MAX_PLAYERS)
- {
- return YSI_g_sPlayerArea[playerid][0];
- }
- return NO_AREA;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- _Area_SetPlayerAreas
- Params:
- playerid - Player to set areas of.
- idx - Which slot to set.
- area - The area to store in that slot.
- Return:
- -
- Notes:
- Sets a player as in a slot.
- -*----------------------------------------------------------------------------*/
- static stock
- _Area_SetPlayerAreas(playerid, idx, area)
- {
- if (idx < AREAS_MAX_OVERLAPS)
- {
- YSI_g_sPlayerArea[playerid][idx] = area;
- }
- else
- {
- // Use PVars to store extended areas.
- static
- sProp[12] = "y_areas_";
- valstr(sProp[8], idx);
- if (area == NO_AREA)
- {
- DeletePVar(playerid, sProp);
- }
- else
- {
- SetPVarInt(playerid, sProp, area);
- }
- }
- }
- /*----------------------------------------------------------------------------*-
- Function:
- _Area_GetPlayerAreas
- Area_GetPlayerAreas
- Params:
- playerid - Player to get areas of.
- idx - Which area to get.
- Return:
- The area a player is in or -1.
- Notes:
- Replaces Area_GetPlayerArea for multiple areas. Includes an internal
- version for tighter loops within this code to use once it is known that a
- player exists, and without using the global function system.
- -*----------------------------------------------------------------------------*/
- static stock
- _Area_GetPlayerAreas(playerid, idx)
- {
- if (idx < AREAS_MAX_OVERLAPS)
- {
- return YSI_g_sPlayerArea[playerid][idx];
- }
- else
- {
- // Use PVars to store extended areas.
- static
- sProp[12] = "y_areas_";
- valstr(sProp[8], idx);
- if (GetPVarType(playerid, sProp) == PLAYER_VARTYPE_INT)
- {
- return GetPVarInt(playerid, sProp);
- }
- }
- return NO_AREA;
- }
- foreign Area_GetPlayerAreas(playerid, idx);
- global Area_GetPlayerAreas(playerid, idx)
- {
- if (0 <= playerid < MAX_PLAYERS)
- {
- if (0 <= idx <= 999)
- {
- return _Area_GetPlayerAreas(playerid, idx);
- }
- }
- return NO_AREA;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_SetPlayer
- Params:
- area - Area to set for.
- playerid - Player to set for.
- set - Wether or not the player can use the area.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign void:Area_SetPlayer(area, playerid, bool:set);
- global void:Area_SetPlayer(area, playerid, bool:set)
- {
- if (Area_IsActive(area))
- {
- PA_Set(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid, set);
- //return 1;
- }
- //return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetPlayer
- Params:
- area - Area to get for.
- playerid - Player to get for.
- Return:
- -
- Notes:
- Can the player USE this area (not are they in it)?
- -*----------------------------------------------------------------------------*/
- foreign bool:Area_GetPlayer(area, playerid);
- global bool:Area_GetPlayer(area, playerid)
- {
- if (Area_IsActive(area))
- {
- return PA_Get(YSI_g_sAreas[area][E_AREA_PLAYERS], playerid);
- }
- return false;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_SetWorld
- Params:
- area - Area to set for.
- world - World to set for.
- set - Wether or not the area is active in this world.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign void:Area_SetWorld(area, world, bool:set);
- global void:Area_SetWorld(area, world, bool:set)
- {
- #if AREA_WORLDS > 0
- if (Area_IsActive(area))
- {
- Bit_Set(YSI_g_sAreas[area][E_AREA_WORLDS], world, set);
- //return 1;
- }
- #else
- #pragma unused area, world, set
- #endif
- //return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_GetWorld
- Params:
- area - Area to set for.
- world - World to set for.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign bool:Area_GetWorld(area, world);
- global bool:Area_GetWorld(area, world)
- {
- #if AREA_WORLDS > 0
- if (Area_IsActive(area))
- {
- return Bit_Get(YSI_g_sAreas[area][E_AREA_WORLDS], world);
- }
- return false;
- #else
- #pragma unused area, world
- return true;
- #endif
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_SetAllPlayers
- Params:
- area - Area to set for.
- set - Wether or not all players can use this area.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign void:Area_SetAllPlayers(area, bool:set);
- global void:Area_SetAllPlayers(area, bool:set)
- {
- if (Area_IsActive(area))
- {
- PA_Init(YSI_g_sAreas[area][E_AREA_PLAYERS], set);
- //return 1;
- }
- //return 0;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsValid
- Params:
- area - Area to check.
- Return:
- Is the passed area valid and active.
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- foreign bool:Area_IsValid(area);
- global bool:Area_IsValid(area)
- {
- return bool:Area_IsActive(area);
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_IsEmpty
- Params:
- area - Area to check.
- Return:
- Is the passed area valid and empty.
- Notes:
- Currently very slow as it has to loop through multiple players! I may add
- an entry counter to zones to make this O(1) instead of O(nm).
- -*----------------------------------------------------------------------------*/
- foreign bool:Area_IsEmpty(area);
- global bool:Area_IsEmpty(area)
- {
- new
- z;
- if (Area_IsActive(area))
- {
- foreach (new playerid : Player)
- {
- for (new i = 0; ; ++i)
- {
- z = _Area_GetPlayerAreas(playerid, i);
- if (z == NO_AREA)
- {
- break;
- }
- else if (z == area)
- {
- return false;
- }
- }
- }
- }
- return true;
- }
- /*----------------------------------------------------------------------------*-
- Function:
- Area_SetCallback
- Params:
- area - Area to set for.
- callback:callback - Callback to use.
- Return:
- -
- Notes:
- Adds a y_inline style callback (publics included) to an area to be called
- when a player enters it. This is NOT a remote function and instead records
- the data locally to call functions in the correct script (or they'll just
- end up crashing as you will be jumping to an arbitrary address in a script
- that doesn't have sensible code at that address.
- -*----------------------------------------------------------------------------*/
- /*----------------------------------------------------------------------------*-
- Function:
- Area_DoEnter
- Params:
- playerid - The player that just entered the area.
- areaid - The area they entered.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- static stock Area_DoEnter(playerid, areaid, &idx)
- {
- // Save their area to the list of areas that they are currently in.
- //YSI_g_sPlayerArea[playerid] = sCur;
- _Area_SetPlayerAreas(playerid, idx++, areaid);
- // Call the callback in all scripts.
- CallRemoteFunction("OnPlayerEnterArea", "ii", playerid, areaid);
- //broadcastfunc _Area_DoEnter(playerid, areaid);
- }
- /*remotefunc _Area_DoEnter(playerid, areaid)
- {
- if (YSI_g_sHasCallbacks & 1)
- {
- CallLocalFunction("OnPlayerEnterArea", "ii", playerid, areaid);
- }
- if (YSI_g_sHasCallbacks & 4)
- {
- //Hook_OnPlayerEnterArea(playerid, areaid);
- }
- return 1;
- }*/
- forward OnPlayerEnterArea(playerid, areaid);
- /*----------------------------------------------------------------------------*-
- Function:
- Area_DoLeave
- Params:
- playerid - The player that just left the area.
- areaid - The area they left.
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- //remotefunc Area_DoLeave(playerid, areaid)
- static stock Area_DoLeave(playerid, areaid, idx)
- {
- // Remove this area from the list of areas.
- new
- cur;
- // Shift up the zones.
- while ((cur = _Area_GetPlayerAreas(playerid, idx + 1)) != NO_AREA)
- {
- _Area_SetPlayerAreas(playerid, idx++, cur);
- }
- _Area_SetPlayerAreas(playerid, idx, NO_AREA);
- // Call the callback.
- CallRemoteFunction("OnPlayerLeaveArea", "ii", playerid, areaid);
- /*if (YSI_g_sHasCallbacks & 2)
- {
- CallLocalFunction("OnPlayerLeaveArea", "ii", playerid, areaid);
- }
- if (YSI_g_sHasCallbacks & 8)
- {
- //Hook_OnPlayerLeaveArea(playerid, areaid);
- }*/
- return 1;
- }
- forward OnPlayerLeaveArea(playerid, areaid);
- //#define YSI_SET_LAST_GROUP 19
- #include "internal\y_grouprevert"
|