y_groups_impl.inc 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. /*
  2. Legal:
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version
  5. 1.1 the "License"; you may not use this file except in compliance with
  6. the License. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/
  8. Software distributed under the License is distributed on an "AS IS" basis,
  9. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. for the specific language governing rights and limitations under the
  11. License.
  12. The Original Code is the YSI framework.
  13. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  14. Portions created by the Initial Developer are Copyright C 2011
  15. the Initial Developer. All Rights Reserved.
  16. Contributors:
  17. Y_Less
  18. koolk
  19. JoeBullet/Google63
  20. g_aSlice/Slice
  21. Misiur
  22. samphunter
  23. tianmeta
  24. maddinat0r
  25. spacemud
  26. Crayder
  27. Dayvison
  28. Ahmad45123
  29. Zeex
  30. irinel1996
  31. Yiin-
  32. Chaprnks
  33. Konstantinos
  34. Masterchen09
  35. Southclaws
  36. PatchwerkQWER
  37. m0k1
  38. paulommu
  39. udan111
  40. Thanks:
  41. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  42. ZeeX - Very productive conversations.
  43. koolk - IsPlayerinAreaEx code.
  44. TheAlpha - Danish translation.
  45. breadfish - German translation.
  46. Fireburn - Dutch translation.
  47. yom - French translation.
  48. 50p - Polish translation.
  49. Zamaroht - Spanish translation.
  50. Los - Portuguese translation.
  51. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  52. me to strive to better.
  53. Pixels^ - Running XScripters where the idea was born.
  54. Matite - Pestering me to release it and using it.
  55. Very special thanks to:
  56. Thiadmer - PAWN, whose limits continue to amaze me!
  57. Kye/Kalcor - SA:MP.
  58. SA:MP Team past, present and future - SA:MP.
  59. Optional plugins:
  60. Gamer_Z - GPS.
  61. Incognito - Streamer.
  62. Me - sscanf2, fixes2, Whirlpool.
  63. */
  64. /*-------------------------------------------------------------------------*//**
  65. * <param name="%9">Check if the function exists?</param>
  66. * <param name="%0">Variable holding the function.</param>
  67. * <param name="%1">Parameters.</param>
  68. * <remarks>
  69. * Calls the correct function to chain a function with the given number of
  70. * parameters, calls the function stored in a variable and passes parameters
  71. * BY REFERENCE - ALL of them!
  72. * </remarks>
  73. *//*------------------------------------------------------------------------**/
  74. /*
  75. New groups check:
  76. if (ALL A == ALL B)
  77. {
  78. if (ALL A == P)
  79. {
  80. // Add.
  81. }
  82. else
  83. {
  84. // Remove.
  85. }
  86. }
  87. else
  88. {
  89. if (ANY A == P && NO B == P)
  90. {
  91. // Add.
  92. }
  93. else
  94. {
  95. // Remove.
  96. }
  97. }
  98. */
  99. enum e_GROUP_FLAGS:(<<= 1)
  100. {
  101. e_GROUP_FLAGS_NONE = 0,
  102. e_GROUP_FLAGS_GANG = 1,
  103. // I can't remember why I had this!
  104. //e_GROUP_FLAGS_CHAT,
  105. e_GROUP_FLAGS_ACTIVE,
  106. // Only ever set for one group.
  107. e_GROUP_FLAGS_GLOBAL,
  108. // Has no name.
  109. e_GROUP_FLAGS_TEMP,
  110. e_GROUP_FLAGS_COLOR = 0xFFFFFF00
  111. }
  112. enum E_GROUP_DATA
  113. {
  114. E_GROUP_DATA_NAME[MAX_GROUP_NAME char],
  115. //E_GROUP_DATA_COUNT,
  116. E_GROUP_DATA_HASH,
  117. e_GROUP_FLAGS:E_GROUP_DATA_FLAGS,
  118. }
  119. stock PlayerGroups(a, b)
  120. {
  121. return 0;
  122. }
  123. // Define the groups iterator in terms of the underlying bits, but without the
  124. // need for users to know about the "YSI_gGroupPlayers" array, just the player.
  125. #define Iter_Func@PlayerGroups(%1,%0) GROUP_MANGLE(Iter_Func@Bits(_:%1,YSI_gGroupPlayers[%0]))
  126. #define Iterator@PlayerGroups Iterator@Bits
  127. static
  128. // Function pointers for chaining.
  129. YSI_g_sNextInitFunc,
  130. YSI_g_sNextUpdFunc,
  131. YSI_g_sNextAddFunc,
  132. YSI_g_sGroupCount;
  133. static stock const
  134. YSI_g_scGlobalName[] = "__GLOBAL",
  135. BitArray:RG@<_MAX_GROUPS_G>;
  136. MASTER_DATA<_MAX_GROUPS_G>
  137. static stock __declspec(dist_master) YSI_gGroupData[_MAX_GROUPS_G][E_GROUP_DATA];
  138. static stock __declspec(dist_tagged) Bit:YSI_g_sChildGroups[_MAX_GROUPS_G][bits<_MAX_GROUPS_G>];
  139. static stock
  140. BitArray:YSI_g_sDefaultGroups<_MAX_GROUPS_G>,
  141. // Create group hierarchys.
  142. Iterator:GroupPlayers[_MAX_GROUPS_G]<MAX_PLAYERS>;
  143. //#define GROUP_BITS<%0> BitArray:%0<_MAX_GROUPS_G>,
  144. #define _Group_HasPlayer(%0,%1) \
  145. Bit_Get(YSI_gGroupPlayers[(%1)],(%0)) //, _MAX_GROUPS_G)
  146. //PA_Get(YSI_gGroupPlayers[(%0)],(%1))
  147. //Bit_Get(YSI_gGroupPlayers[(%0)], (%1), MAX_PLAYERS)
  148. #define _Group_GetColor(%0) \
  149. (_:(YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] & e_GROUP_FLAGS_COLOR) | 0xAA)
  150. #define _Group_SetColor(%0,%1) \
  151. (YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] = (YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] & ~e_GROUP_FLAGS_COLOR) | (e_GROUP_FLAGS:(%1) & e_GROUP_FLAGS_COLOR))
  152. #define _Group_GetGang(%0) \
  153. (bool:(YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] & e_GROUP_FLAGS_GANG))
  154. #define _Group_LetGang(%0) \
  155. (YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] |= e_GROUP_FLAGS_GANG)
  156. #define _Group_VetGang(%0) \
  157. (YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] &= ~e_GROUP_FLAGS_GANG)
  158. #define _Group_IsActive(%0) \
  159. (YSI_gGroupData[_:(%0)][E_GROUP_DATA_FLAGS] & e_GROUP_FLAGS_ACTIVE)
  160. //#define _Group_IsValid(%0)
  161. // (0 <= (%0) < _MAX_GROUPS && Group_IsActive(%0))
  162. #define _Group_IsValid(%0) \
  163. ((_:GROUP_MASK<=_:(%0)<=_:GROUP_GLOBAL)&&(_Group_IsActive(GROUP_TEMP_FIX(%0))))
  164. //#define Group_IsActive(%0)
  165. // (YSI_gGroupData[_:GROUP_FIX(%0)][E_GROUP_DATA_FLAGS] & e_GROUP_FLAGS_ACTIVE)
  166. FOREIGN__ void:_Group_ReInitPlayers();
  167. GLOBAL__ void:_Group_ReInitPlayers()
  168. {
  169. Iter_Init(GroupPlayers);
  170. for (new i = 0; i != _MAX_GROUPS_G; ++i) if (_Group_IsActive(i))
  171. {
  172. FOREACH__ (new playerid : Player)
  173. {
  174. if (_Group_HasPlayer(i, playerid)) Iter_Add(GroupPlayers[i], playerid);
  175. }
  176. }
  177. }
  178. HANDOFF()
  179. {
  180. P:1("y_groups HANDOFF called");
  181. DISTRIBUTE(YSI_gGroupData);
  182. DISTRIBUTE(YSI_g_sChildGroups);
  183. _Group_ReInitPlayers();
  184. P:1("y_groups HANDOFF ended");
  185. }
  186. /*-------------------------------------------------------------------------*//**
  187. * <param name="g">Group to add the following items to.</param>
  188. * <remarks>
  189. * This sets up a temporary environment, during which all items are ONLY added
  190. * to the specified group and no others, with no complex extra code required.
  191. * </remarks>
  192. *//*------------------------------------------------------------------------**/
  193. #define GROUP_ADD<%0> for(J@=_Group_AddInternal(1,(%0));J@;J@=_Group_AddInternal(0,(%0)))
  194. remotefunc static stock void:Group_AddInternal_(a,g)
  195. {
  196. GROUP_CHAIN?<YSI_g_sNextInitFunc>(-1, a, g);
  197. }
  198. stock _Group_AddInternal(a, Group:g)
  199. {
  200. //printf("_Group_AddInternal %d %d", a, _:g);
  201. if (_Group_IsValid(g))
  202. {
  203. broadcastfunc Group_AddInternal_(a, _:GROUP_TEMP_FIX(g));
  204. return a;
  205. }
  206. else
  207. {
  208. return 0;
  209. }
  210. }
  211. /*-------------------------------------------------------------------------*//**
  212. * <param name="p">Player who connected.</param>
  213. * <param name="g">The player's new groups.</param>
  214. * <param name="s">Size of "g".</param>
  215. * <remarks>
  216. * Pretend the player is in all the groups they won't be in shortly so that
  217. * they have a complete blank slate when they connect - the system KNOWS they
  218. * are not in some groups and are in others.
  219. *
  220. * Uses an unusual size in "g" to reduce the string length.
  221. * </remarks>
  222. *//*------------------------------------------------------------------------**/
  223. remotefunc static void:_Group_FakePlayer(p,Bit:g[sizeof RG@],s)
  224. {
  225. for (new i = 0; i != sizeof (g); ++i)
  226. {
  227. // Set their current groups to the inverse of what they are now in.
  228. YSI_gGroupPlayers[p][i] = ~g[i];
  229. }
  230. _Group_SetPlayer(p, g, s);
  231. }
  232. /*-------------------------------------------------------------------------*//**
  233. * <param name="g">Group to check.</param>
  234. * <returns>
  235. * bool: - Is the group active and valid?
  236. * </returns>
  237. *//*------------------------------------------------------------------------**/
  238. FOREIGN__ bool:Group_IsValid(Group:g);
  239. GLOBAL__ bool:Group_IsValid(Group:g)
  240. {
  241. //GROUP_FIX(g);
  242. return _Group_IsValid(g);
  243. }
  244. static stock Group_DefineStates_() <YSI_has_groups : y>
  245. {
  246. }
  247. static stock Group_DefineStates_() <YSI_has_groups : n>
  248. {
  249. }
  250. static stock Group_DefineStates_() <YSI_has_groups : other>
  251. {
  252. }
  253. /*-------------------------------------------------------------------------*//**
  254. * <remarks>
  255. * Finds three functions by prefix:
  256. *
  257. * _yGI - An init function to set up a script using groups.
  258. * _yGA - An add function called when a new group is created.
  259. * _yGU - An update function called when a player's groups change.
  260. * </remarks>
  261. *//*------------------------------------------------------------------------**/
  262. HOOK__ OnScriptInit()
  263. {
  264. P:1("Group_OnScriptInit called");
  265. state YSI_has_groups : y;
  266. // Set up the global groups.
  267. #if !(YSIM_HAS_MASTER && (_YSIM_IS_STUB || _YSIM_IS_CLIENT))
  268. #if _YSIM_IS_CLOUD
  269. if (_YCM@y)
  270. #endif
  271. {
  272. P:5("Group_OnScriptInit: Master");
  273. Iter_Init(GroupPlayers);
  274. strpack(YSI_gGroupData[_MAX_GROUPS][E_GROUP_DATA_NAME], YSI_g_scGlobalName, MAX_GROUP_NAME char);
  275. YSI_gGroupData[_MAX_GROUPS][E_GROUP_DATA_FLAGS] = e_GROUP_FLAGS_ACTIVE | e_GROUP_FLAGS_GLOBAL;
  276. YSI_gGroupData[_MAX_GROUPS][E_GROUP_DATA_HASH] = YHash(YSI_g_scGlobalName);
  277. // Store the default groups away from the actual global group.
  278. // The default groups include the global group, but it itself
  279. // doesn't.
  280. Bit_Let(YSI_g_sDefaultGroups, _:_MAX_GROUPS);
  281. }
  282. #endif
  283. // Call the other group init functions.
  284. new
  285. ni = AMX_GetPublicPointerPrefix(0, YSI_g_sNextInitFunc, _A<_yGI>),
  286. na = AMX_GetPublicPointerPrefix(0, YSI_g_sNextAddFunc, _A<_yGA>),
  287. nu = AMX_GetPublicPointerPrefix(0, YSI_g_sNextUpdFunc, _A<_yGU>);
  288. //printf("Group_OnScriptInit: %d, %d, %d", ni, na, nu);
  289. P:4("Group_OnScriptInit: %d, %d, %d", ni, na, nu);
  290. P:4("Group_OnScriptInit: %d, %d, %d", AMX_HEADER_COD - AMX_BASE_ADDRESS, YSI_g_sNextInitFunc, AMX_HEADER_DAT - AMX_BASE_ADDRESS);
  291. // So just below the call to `GROUP_CHAIN` is this code:
  292. //
  293. // heapspace(); // I'm sure there's a reason this is here. But I forgot it!
  294. //
  295. // I just spent another long debugging session tracking down another bug
  296. // where the solution, in another totally unrelated file entirely, was
  297. // adding this line here:
  298. format(Q@, sizeof (Q@), "", AMX_HEADER_COD - AMX_BASE_ADDRESS);
  299. // WHY!?
  300. GROUP_CHAIN?<YSI_g_sNextInitFunc>(ni, na, nu);
  301. //CallLocalFunction("_Group_SpecialInit", "");
  302. heapspace(); // I'm sure there's a reason this is here. But I forgot it!
  303. P:1("Group_OnScriptInit end");
  304. return 1;
  305. }
  306. /*-------------------------------------------------------------------------*//**
  307. * <remarks>
  308. * Destroy all this script's groups. This is an instance of "_YSI_SpecialExit"
  309. * which can't be y_hooked and is called after (almost) every other callback,
  310. * at least after every one controlled via y_scriptinit.
  311. * </remarks>
  312. *//*------------------------------------------------------------------------**/
  313. public OnScriptExit()
  314. {
  315. #if defined _Group_SpecialExit
  316. _Group_SpecialExit();
  317. #endif
  318. _Group_TryRemove();
  319. return 1;
  320. }
  321. #undef OnScriptExit
  322. #define OnScriptExit _Group_SpecialExit
  323. #if defined _Group_SpecialExit
  324. forward _Group_SpecialExit();
  325. #endif
  326. /*-------------------------------------------------------------------------*//**
  327. * <param name="group">Group to destroy from the system.</param>
  328. *//*------------------------------------------------------------------------**/
  329. remotefunc static void:_Group_Destroy(g, const Iterator@gp[MAX_PLAYERS + 1], s)
  330. {
  331. #pragma unused s
  332. new
  333. ps = Bit_Slot(g),
  334. Bit:pm = ~Bit_Mask(g);
  335. if (YSI_g_sNextUpdFunc)
  336. {
  337. // Update all players who were in this group as they may have lost
  338. // some permissions. This is the simplest update because we don't
  339. // need to worry about the effect of removing this group on the
  340. // players' memberships in other groups. Maybe they were added to
  341. // that other group as a direct result of being added to this group,
  342. // but maybe they weren't - there's no way to know!
  343. // Check it! Local parameter iterator!
  344. FOREACH__ (new p : gp)
  345. {
  346. YSI_gTempGroups = YSI_gGroupPlayers[p];
  347. // If these parameters were the other way round I could do this:
  348. //GROUP_CHAIN<YSI_g_sNextUpdFunc>(p, (YSI_gGroupPlayers[p], YSI_gGroupPlayers[p][ps] &= pm), YSI_gGroupPlayers[p]);
  349. // But they're currently not so I can't.
  350. GROUP_CHAIN<YSI_g_sNextUpdFunc>(p, YSI_gTempGroups, YSI_gGroupPlayers[p]);
  351. YSI_gGroupPlayers[p][ps] &= pm;
  352. }
  353. }
  354. else
  355. {
  356. FOREACH__ (new p : gp)
  357. {
  358. // Remove all players from this group.
  359. YSI_gGroupPlayers[p][ps] &= pm;
  360. }
  361. }
  362. }
  363. // Added for the fun of it.
  364. FOREIGN__ void:Group_Destroy(Group:group);
  365. GLOBAL__ void:Group_Destroy(Group:group)
  366. {
  367. P:2("Group_Destroy called: %i", _:group);
  368. P:2("Group_Destroy called in %d", Master_ID());
  369. // You can't destroy the global group.
  370. if (_Group_IsValid(group) && group != GROUP_GLOBAL)
  371. {
  372. GROUP_FIX(group);
  373. broadcastfunc _Group_Destroy(_:group, Iter_TrueArray(GroupPlayers[_:group]), Iter_TrueSize(GroupPlayers[]));
  374. YSI_gGroupData[_:group][E_GROUP_DATA_FLAGS] = e_GROUP_FLAGS:0;
  375. YSI_gGroupData[_:group][E_GROUP_DATA_HASH] = 0;
  376. Iter_Clear(GroupPlayers[_:group]);
  377. MASTER_RESET<_:group>
  378. // This group no longer exists, so can't be the child of another group.
  379. new
  380. ps = Bit_Slot(_:group),
  381. Bit:pm = ~Bit_Mask(_:group);
  382. for (new i = 0; i != _MAX_GROUPS; ++i)
  383. {
  384. YSI_g_sChildGroups[i][ps] &= pm;
  385. }
  386. // Nor can it have groups (saves some later checks).
  387. YSI_g_sChildGroups[_: group] = YSI_g_cEmptyGroups;
  388. }
  389. }
  390. /*-------------------------------------------------------------------------*//**
  391. * <remarks>
  392. * Removes all groups purely owned by the calling script.
  393. * </remarks>
  394. *//*------------------------------------------------------------------------**/
  395. FOREIGN__ void:_Group_TryRemove();
  396. GLOBAL__ void:_Group_TryRemove()
  397. {
  398. for (new i = 0; i != _MAX_GROUPS; ++i) if (_Group_IsActive(i))
  399. {
  400. MASTER_REMOVE<i>
  401. MASTER_EMPTY<i>
  402. {
  403. //printf("removing i");
  404. broadcastfunc _Group_Destroy(i, Iter_TrueArray(GroupPlayers[i]), Iter_TrueSize(GroupPlayers[]));
  405. YSI_gGroupData[i][E_GROUP_DATA_FLAGS] = e_GROUP_FLAGS:0;
  406. YSI_gGroupData[i][E_GROUP_DATA_HASH] = 0;
  407. Iter_Clear(GroupPlayers[i]);
  408. }
  409. }
  410. //return 1;
  411. }
  412. /*-------------------------------------------------------------------------*//**
  413. * <param name="playerid">The player that left.</param>
  414. * <param name="reason">Why they left (unused).</param>
  415. * <remarks>
  416. * Removes this player from all groups. Unfortunately there's no way to
  417. * combine multiple iterator removals to improve their efficiency - currently
  418. * they have to loop through all previous ones to find the one to modify to
  419. * skip over that player. I did debate updating foreach to doubly-linked
  420. * lists for this reason - that would make reverse traversal and removal faster
  421. * by doubling memory consumption but only very slightly affecting adds.
  422. * </remarks>
  423. *//*------------------------------------------------------------------------**/
  424. HOOK__ OnPlayerDisconnect(playerid, reason)
  425. {
  426. #pragma unused reason
  427. P:2("hook OnPlayerDisconnect called: %d, %d", playerid, reason);
  428. // Can't - can't what? Don't stop typing mid comment!
  429. //foreach (new Group:g : PlayerGroups(playerid))
  430. #if !(YSIM_HAS_MASTER && (_YSIM_IS_STUB || _YSIM_IS_CLIENT))
  431. #if _YSIM_IS_CLOUD
  432. if (_YCM@y)
  433. #endif
  434. {
  435. FOREACH__ (new g : Bits(YSI_gGroupPlayers[playerid]))
  436. {
  437. Iter_Remove(GroupPlayers[g], playerid);
  438. Bit_Vet(YSI_gGroupPlayers[playerid], g);
  439. }
  440. }
  441. #endif
  442. // Remove them from everything ever.
  443. //static const
  444. // BitArray:scEmpty<_MAX_GROUPS_G>;
  445. //GROUP_CHAIN?<YSI_g_sNextUpdFunc>(playerid, YSI_gGroupPlayers[p], scEmpty);
  446. YSI_gGroupPlayers[playerid] = YSI_g_cEmptyGroups;
  447. return 1;
  448. }
  449. /*-------------------------------------------------------------------------*//**
  450. * <param name="playerid">The player that joined.</param>
  451. * <remarks>
  452. * The player may not have ACTUALLY joined the server, they may have just been
  453. * added to this newly loaded script. In that case we need to initialise the
  454. * locally stored group data to the new data. Of course, if this script is the
  455. * group master, then we need to do significantly more! This is more complex
  456. * than other scripts with master as they don't have some things to do in non-
  457. * master scripts as well, whereas this one does.
  458. * </remarks>
  459. *//*------------------------------------------------------------------------**/
  460. HOOK__ OnPlayerConnect@9(playerid)
  461. {
  462. P:1("Groups_OnPlayerConnect called: %d, %d", playerid, !(YSIM_HAS_MASTER && (_YSIM_IS_STUB || _YSIM_IS_CLIENT)));
  463. #if !(YSIM_HAS_MASTER && (_YSIM_IS_STUB || _YSIM_IS_CLIENT))
  464. #if _YSIM_IS_CLOUD
  465. if (_YCM@y)
  466. #endif
  467. {
  468. //printf("0");
  469. P:6("Group_OnPlayerConnect: Master %d", playerid);
  470. // Is master. ALWAYS reset all players - if they start screwing
  471. // around with loading orders then that's their own fault!
  472. broadcastfunc _Group_FakePlayer(playerid, YSI_g_sDefaultGroups, bits<_MAX_GROUPS_G>);
  473. //printf("1");
  474. }
  475. #if _YSIM_IS_CLOUD
  476. else
  477. #endif
  478. #endif
  479. #if YSIM_HAS_MASTER
  480. {
  481. P:6("Group_OnPlayerConnect: Slave %d", playerid);
  482. static const
  483. BitArray:scF<_MAX_GROUPS_G> = {Bit:-1, ...};
  484. _GROUPS_CHECK_ANY(scF, YSI_gGroupPlayers[playerid])
  485. {
  486. // Already been set up - return.
  487. return 1;
  488. }
  489. //_Group_
  490. _Group_InitPlayer(playerid, Master_ID());
  491. }
  492. #endif
  493. return 1;
  494. }
  495. /*-------------------------------------------------------------------------*//**
  496. * <param name="p">The player that joined.</param>
  497. * <param name="master">The script that just started.</param>
  498. * <remarks>
  499. * Request all a player's groups from the master system.
  500. * </remarks>
  501. *//*------------------------------------------------------------------------**/
  502. FOREIGN__ void:_Group_InitPlayer(p, master);
  503. GLOBAL__ void:_Group_InitPlayer(p, master)
  504. {
  505. targetfunc _Group_FakePlayer<master>(p, YSI_gGroupPlayers[p], bits<_MAX_GROUPS_G>);
  506. }
  507. /*-------------------------------------------------------------------------*//**
  508. * <param name="playerid">Player to add to multiple groups.</param>
  509. * <param name="group">Parent group to add to.</param>
  510. * <returns>
  511. * A new array of groups.
  512. * </returns>
  513. * <remarks>
  514. * Takes a group and adds a player to that group and every child group of
  515. * which they are not already a member.
  516. * </remarks>
  517. *//*------------------------------------------------------------------------**/
  518. // If you overflow this stack there is something VERY wrong! The manual stack
  519. // is intended to help us combat very long inheritance chains. This code also
  520. // neatly ignores recursion by only doing any one group if the player doesn't
  521. // already have it.
  522. static
  523. YSI_g_sRecursionStack[_MAX_GROUPS_G][2];
  524. static stock Bit:_Group_SetSome(playerid, group)
  525. {
  526. new
  527. g = -1,
  528. s = 0;
  529. YSI_gTempGroups = YSI_gGroupPlayers[playerid];
  530. Bit_Let(YSI_gTempGroups, group);
  531. for ( ; ; )
  532. {
  533. g = Iter_Func@Bits(g, YSI_g_sChildGroups[group], bits<_MAX_GROUPS_G>);
  534. if (g == -1)
  535. {
  536. // Finished this child group, pop off the stack.
  537. if (s--)
  538. {
  539. g = YSI_g_sRecursionStack[s][0];
  540. group = YSI_g_sRecursionStack[s][1];
  541. }
  542. else break;
  543. }
  544. else if (!Bit_Get(YSI_gTempGroups, g))
  545. {
  546. // This player isn't in this group, add them.
  547. Bit_Let(YSI_gTempGroups, g);
  548. YSI_g_sRecursionStack[s][0] = g;
  549. YSI_g_sRecursionStack[s][1] = group;
  550. ++s;
  551. group = g;
  552. g = -1;
  553. }
  554. }
  555. return YSI_gTempGroups;
  556. }
  557. /*-------------------------------------------------------------------------*//**
  558. * <param name="g">Group to modify.</param>
  559. * <param name="p">Player to modify the group for.</param>
  560. * <param name="s">Add the player (true) or remove them (false).</param>
  561. * <remarks>
  562. * Will in some cases update all settings, unless they are being added through
  563. * a recursive call due to being added to child groups.
  564. *
  565. * There is an internal version that ONLY adds them to the group and DOES NOT
  566. * update any of their other settings. As a result it has less checks in it.
  567. * </remarks>
  568. *//*------------------------------------------------------------------------**/
  569. FOREIGN__ void:Group_SetPlayer(Group:g,p,bool:s);
  570. GLOBAL__ void:Group_SetPlayer(Group:g,p,bool:s)
  571. {
  572. if (_Group_IsValid(g) && VALID_PLAYERID(p))
  573. {
  574. GROUP_FIX(g);
  575. if (s)
  576. {
  577. if (!_Group_HasPlayer(g, p))
  578. {
  579. // Added to a group they don't already have. Make a new list of
  580. // groups they're in, taking in to account the new groups
  581. // hierarchy and pass that new array about.
  582. broadcastfunc _Group_SetPlayer(p, _Group_SetSome(p, _:g), sizeof (YSI_gTempGroups));
  583. return; //1;
  584. }
  585. }
  586. else
  587. {
  588. if (_Group_HasPlayer(g, p))
  589. {
  590. YSI_gTempGroups = YSI_gGroupPlayers[p];
  591. Bit_Vet(YSI_gTempGroups, _:g);
  592. broadcastfunc _Group_SetPlayer(p, YSI_gTempGroups, sizeof (YSI_gTempGroups));
  593. return; //1;
  594. }
  595. }
  596. }
  597. //return 0;
  598. }
  599. /*-------------------------------------------------------------------------*//**
  600. * <param name="p">Player to set.</param>
  601. * <param name="g">The player's new groups.</param>
  602. * <param name="s">Size of "g".</param>
  603. * <remarks>
  604. * Pass a list of groups that the player is now in or not in. This is a
  605. * complete replacement for their existing list of groups, and so multiple
  606. * updates can be done at once.
  607. * </remarks>
  608. *//*------------------------------------------------------------------------**/
  609. remotefunc void:_Group_SetPlayer(p, Bit:g[sizeof RG@], s)
  610. {
  611. #pragma unused s
  612. #if !(YSIM_HAS_MASTER && (_YSIM_IS_STUB || _YSIM_IS_CLIENT))
  613. #if _YSIM_IS_CLOUD
  614. if (_YCM@y)
  615. #endif
  616. {
  617. P:2("_Group_SetPlayer called: %i, %s, %s, %i", p, Bit_Display(YSI_gGroupPlayers[p]), Bit_Display(g), s);
  618. // <a href="http://supertech.csail.mit.edu/papers/debruijn.pdf" />
  619. new
  620. Bit:cur,
  621. Bit:exor,
  622. Bit:bit,
  623. group;
  624. for (new i = 0; i != sizeof (g); ++i)
  625. {
  626. // Get the difference between the old and new groups.
  627. cur = YSI_gGroupPlayers[p][i];
  628. exor = g[i] ^ cur;
  629. P:6("_Group_SetPlayer: Loop %d 0x%04x%04x 0x%04x%04x", i, _:cur >>> 16, _:cur & 0xFFFF, _:exor >>> 16, _:exor & 0xFFFF);
  630. // Low-level bit twiddling.
  631. while ((bit = Bit:Cell_GetLowestComponent(exor)))
  632. {
  633. // group = i * cellbits + (scDeBruijn[(_:bit * 0x077CB531) >>> 27]);
  634. group = i * cellbits + Cell_GetLowestBit(exor);
  635. P:7("_Group_SetPlayer: %d %s %d", p, _:(cur & bit) ? ("remove from") : ("add to"), group);
  636. if (cur & bit)
  637. {
  638. // Used to have this group, now don't.
  639. Iter_Remove(GroupPlayers[group], p);
  640. }
  641. else
  642. {
  643. // Didn't have this group, now do.
  644. Iter_Add(GroupPlayers[group], p);
  645. }
  646. exor ^= bit;
  647. }
  648. }
  649. }
  650. #endif
  651. #pragma tabsize 4
  652. GROUP_CHAIN?<YSI_g_sNextUpdFunc>(p, YSI_gGroupPlayers[p], g);
  653. // NOW save the new version, after everything else has had a chance to
  654. // update according to the changes.
  655. YSI_gGroupPlayers[p] = g;
  656. }
  657. /*-------------------------------------------------------------------------*//**
  658. * <param name="p">Player to add to the smallest group.</param>
  659. * <param name="gs">An array of possible groups.</param>
  660. * <param name="c">The number of USED items in the array.</param>
  661. * <returns>
  662. * The group they have been added to.
  663. * </returns>
  664. * <remarks>
  665. * Chains the call with "Group_SetPlayer" to use its hierarchy code.
  666. * </remarks>
  667. *//*------------------------------------------------------------------------**/
  668. FOREIGN__ Group:_Group_SetBalancedInternal(p,const Group:gs[],c);
  669. GLOBAL__ Group:_Group_SetBalancedInternal(p,const Group:gs[],c)
  670. {
  671. // Find which of the listed groups has the least players in.
  672. new
  673. count = cellmax,
  674. Group:id = INVALID_GROUP;
  675. for (new i = 0; i != c; ++i)
  676. {
  677. // Find the group with the least players.
  678. new
  679. gi = _:gs[i];
  680. if (_Group_IsValid(Group:gi))
  681. {
  682. new
  683. g2 = _:GROUP_TEMP_FIX(Group:gi),
  684. cc = Iter_Count(GroupPlayers[g2]);
  685. if (_Group_HasPlayer(g2, p))
  686. {
  687. // The player is already in this group - just return.
  688. return Group:gi;
  689. }
  690. else if (cc < count)
  691. {
  692. count = cc,
  693. id = Group:gi;
  694. }
  695. }
  696. }
  697. if (id == INVALID_GROUP)
  698. {
  699. P:W("Group_SetBalanced(Array) requires at least 1 valid group.");
  700. }
  701. else
  702. {
  703. Group_SetPlayer(id, p, true);
  704. }
  705. return id;
  706. }
  707. /*-------------------------------------------------------------------------*//**
  708. * <param name="p">Player to add to the smallest group.</param>
  709. * <param name="gs">An array of possible groups.</param>
  710. * <param name="c">The number of USED items in the array.</param>
  711. * <returns>
  712. * The group they have been added to.
  713. * </returns>
  714. * <remarks>
  715. * Puts a player in whichever of the given groups currently has the least
  716. * players.
  717. *
  718. * Now ONLY takes a list - arrays should use "Group_SetBalancedArray". As a
  719. * result, has more error-checking.
  720. * </remarks>
  721. *//*------------------------------------------------------------------------**/
  722. stock Group:Group_SetBalancedArray(p, const Group:gs[], c = sizeof (gs))
  723. {
  724. if (!(0 <= p < MAX_PLAYERS)) return INVALID_GROUP;
  725. return _Group_SetBalancedInternal(p, gs, c);
  726. }
  727. /*-------------------------------------------------------------------------*//**
  728. * <param name="playerid">Player to put in one of a number of groups</param>
  729. * <param name="">A list of groups.</param>
  730. * <remarks>
  731. * Puts a player in whichever of the given groups currently has the least
  732. * players.
  733. *
  734. * Now ONLY takes a list - arrays should use "Group_SetBalancedArray". As a
  735. * result, has more error-checking.
  736. * </remarks>
  737. *//*------------------------------------------------------------------------**/
  738. stock Group:Group_SetBalanced(playerid, Group:g0, Group:g1, Group:...)
  739. {
  740. new
  741. Group:possible[_MAX_GROUPS_G],
  742. count = min(_MAX_GROUPS_G + 1, numargs()),
  743. i = 2,
  744. j = 3;
  745. possible[0] = g0,
  746. possible[1] = g1;
  747. while (j != count)
  748. {
  749. possible[i++] = Group:getarg(j++);
  750. }
  751. return Group_SetBalancedArray(playerid, possible, i);
  752. }
  753. /*-------------------------------------------------------------------------*//**
  754. * <param name="g">Group to check.</param>
  755. * <param name="p">Player to check.</param>
  756. * <returns>
  757. * Is this player in this group?
  758. * </returns>
  759. *//*------------------------------------------------------------------------**/
  760. FOREIGN__ bool:Group_GetPlayer(Group:g,p);
  761. GLOBAL__ bool:Group_GetPlayer(Group:g,p)
  762. {
  763. P:2("bool:Group_GetPlayer called: %i, %i", _:g, p);
  764. if (_Group_IsValid(g) && VALID_PLAYERID(p))
  765. {
  766. GROUP_FIX(g);
  767. return Bit_Get(YSI_gGroupPlayers[p], _:g);
  768. //Bit_Set(YSI_gGroupPlayers[g], p, s, bits<MAX_PLAYERS>);
  769. }
  770. return false;
  771. }
  772. stock Group:operator+(Group:g, o)
  773. {
  774. Group_SetPlayer(g, o, true);
  775. return g;
  776. }
  777. stock Group:operator-(Group:g, o)
  778. {
  779. Group_SetPlayer(g, o, false);
  780. return g;
  781. }
  782. stock bool:operator==(Group:g, o)
  783. {
  784. return Group_GetPlayer(g, o);
  785. }
  786. stock bool:operator!=(Group:g, o)
  787. {
  788. return !Group_GetPlayer(g, o);
  789. }
  790. /*-------------------------------------------------------------------------*//**
  791. * <summary></summary>
  792. * <param name="g">Group to set the name of.</param>
  793. * <param name="n">The new name of the group.</param>
  794. * <remarks>
  795. * Sets the name of a group.
  796. * </remarks>
  797. *//*------------------------------------------------------------------------**/
  798. FOREIGN__ void:Group_SetName(Group:g,const string:n[]);
  799. GLOBAL__ void:Group_SetName(Group:g,const string:n[])
  800. {
  801. P:2("Group_SetName called: %i, \"%s\"", _:g, n);
  802. if (_Group_IsValid(g))
  803. {
  804. GROUP_FIX(g);
  805. if (isnull(n))
  806. {
  807. YSI_gGroupData[_:g][E_GROUP_DATA_NAME][0] = 0;
  808. YSI_gGroupData[_:g][E_GROUP_DATA_HASH] = 0;
  809. }
  810. else
  811. {
  812. strpack(YSI_gGroupData[_:g][E_GROUP_DATA_NAME], n, MAX_GROUP_NAME char);
  813. YSI_gGroupData[_:g][E_GROUP_DATA_HASH] = YHash(n);
  814. }
  815. }
  816. //return 1;
  817. }
  818. /*-------------------------------------------------------------------------*//**
  819. * <param name="g">Group to get the name of.</param>
  820. * <returns>
  821. * string:
  822. * </returns>
  823. * <remarks>
  824. * Gets the name of a group.
  825. * </remarks>
  826. *//*------------------------------------------------------------------------**/
  827. FOREIGN__ string:Group_GetName(Group:g);
  828. GLOBAL__ string:Group_GetName(Group:g)
  829. {
  830. //printf("Group_GetName called: %04x%04x", _:g >>> 16, _:g & 0xFFFF);
  831. P:2("Group_GetName called: %04x%04x", _:g >>> 16, _:g & 0xFFFF);
  832. static
  833. ret[YSI_MAX_STRING];
  834. if (_Group_IsValid(g))
  835. {
  836. //printf("Is Valid");
  837. //return Bit_Get(YSI_gGroupPlayers[g], p);
  838. //Bit_Set(YSI_gGroupPlayers[g], p, s, bits<MAX_PLAYERS>);
  839. strunpack(ret, YSI_gGroupData[_:GROUP_TEMP_FIX(g)][E_GROUP_DATA_NAME], YSI_MAX_STRING);
  840. //printf("Is Valid: %s", ret);
  841. }
  842. return ret;
  843. }
  844. /*-------------------------------------------------------------------------*//**
  845. * <param name="name">Name of a group to get.</param>
  846. * <returns>
  847. * Group: - The ID of the group with this name.
  848. * </returns>
  849. *//*------------------------------------------------------------------------**/
  850. FOREIGN__ Group:Group_GetID(const string:name[]);
  851. GLOBAL__ Group:Group_GetID(const string:name[])
  852. {
  853. P:2("Group_GetID called: %s", name);
  854. new
  855. i,
  856. hash = YHash(name);
  857. while (i != _MAX_GROUPS)
  858. {
  859. if (_Group_IsActive(i) && YSI_gGroupData[i][E_GROUP_DATA_HASH] == hash)
  860. {
  861. break;
  862. }
  863. ++i;
  864. }
  865. if (i == _MAX_GROUPS) return INVALID_GROUP;
  866. return GROUP_MANGLE(i);
  867. }
  868. /*-------------------------------------------------------------------------*//**
  869. * <param name="g">Group to set for.</param>
  870. * <param name="n">Set or not?</param>
  871. * <remarks>
  872. * I actually can't remember what the "Gang" setting on a group does - I don't
  873. * think it actually does anything in the latest code version!
  874. * </remarks>
  875. *//*------------------------------------------------------------------------**/
  876. FOREIGN__ void:Group_SetGang(Group:g,bool:n);
  877. GLOBAL__ void:Group_SetGang(Group:g,bool:n)
  878. {
  879. P:2("Group_SetGang called: %i, %i", _:g, n);
  880. if (_Group_IsValid(g))
  881. {
  882. if (n)
  883. {
  884. _Group_LetGang(GROUP_TEMP_FIX(g));
  885. }
  886. else
  887. {
  888. _Group_VetGang(GROUP_TEMP_FIX(g));
  889. }
  890. }
  891. //return 1;
  892. }
  893. /*-------------------------------------------------------------------------*//**
  894. * <param name="g">Group to get the gang status of.</param>
  895. * <returns>
  896. * bool:
  897. * </returns>
  898. * <remarks>
  899. * I still don't remember what this once did!
  900. * </remarks>
  901. *//*------------------------------------------------------------------------**/
  902. FOREIGN__ bool:Group_GetGang(Group:g);
  903. GLOBAL__ bool:Group_GetGang(Group:g)
  904. {
  905. P:2("bool:Group_GetGang called: %i", _:g);
  906. if (_Group_IsValid(g))
  907. {
  908. return _Group_GetGang(GROUP_TEMP_FIX(g));
  909. }
  910. return false;
  911. }
  912. /*-------------------------------------------------------------------------*//**
  913. * <summary>
  914. * Group_SetColor
  915. * Group_SetColour
  916. * </summary>
  917. * <param name="g">The group to set the colour of.</param>
  918. * <param name="c">An RGBA colour.</param>
  919. * <remarks>
  920. * This colour is not actually currently used anywhere.
  921. * </remarks>
  922. *//*------------------------------------------------------------------------**/
  923. FOREIGN__ void:Group_SetColour(Group:g,c);
  924. GLOBAL__ void:Group_SetColour(Group:g,c)
  925. {
  926. P:2("Group_SetColour called: %i, %i", _:g, c);
  927. if (_Group_IsValid(g))
  928. {
  929. GROUP_FIX(g);
  930. _Group_SetColor(g, c);
  931. }
  932. //return 1;
  933. }
  934. /*-------------------------------------------------------------------------*//**
  935. * <summary>
  936. * Group_GetColor
  937. * Group_GetColour
  938. * </summary>
  939. * <param name="g">The group to get the colour of.</param>
  940. * <returns>
  941. * An RGBA colour.
  942. * </returns>
  943. * <remarks>
  944. * This colour is not actually currently used anywhere.
  945. * </remarks>
  946. *//*------------------------------------------------------------------------**/
  947. FOREIGN__ Group_GetColour(Group:g);
  948. GLOBAL__ Group_GetColour(Group:g)
  949. {
  950. P:2("Group_GetColour called: %i", _:g);
  951. if (_Group_IsValid(g))
  952. {
  953. return _Group_GetColor(GROUP_TEMP_FIX(g));
  954. //Bit_Set(YSI_gGroupPlayers[g], p, s, bits<MAX_PLAYERS>);
  955. }
  956. return 0;
  957. }
  958. #define Group_SetColor Group_SetColour
  959. #define Group_GetColor Group_GetColour
  960. /*-------------------------------------------------------------------------*//**
  961. * <param name="g">The group to get the membership for.</param>
  962. * <returns>
  963. * The number of players in the group.
  964. * </returns>
  965. *//*------------------------------------------------------------------------**/
  966. FOREIGN__ Group_GetCount(Group:g);
  967. GLOBAL__ Group_GetCount(Group:g)
  968. {
  969. P:2("Group_GetCount called: %i", _:g);
  970. if (_Group_IsValid(g))
  971. {
  972. GROUP_FIX(g);
  973. return Iter_Count(GroupPlayers[_:g]);
  974. }
  975. return 0;
  976. }
  977. /*-------------------------------------------------------------------------*//**
  978. * <param name="name">The optional name of the new group.</param>
  979. * <returns>
  980. * The group ID with a tag of "Group:", or "INVALID_GROUP".
  981. * </returns>
  982. * <remarks>
  983. * Group_Create - Local function to detect and "NULL"ify empty strings.
  984. * _Group_Create - Global function that does most of the work.
  985. * _Group_CreateChain - Remote function that updates all master scripts with
  986. * the new group's existence.
  987. * </remarks>
  988. *//*------------------------------------------------------------------------**/
  989. remotefunc static void:_Group_CreateChain(Group:g)
  990. {
  991. GROUP_CHAIN?<YSI_g_sNextAddFunc>(g);
  992. }
  993. FOREIGN__ Group:_Group_Create(const string:name[]);
  994. GLOBAL__ Group:_Group_Create(const string:name[])
  995. {
  996. P:2("Group:Group_Create called: \"%s\"", name);
  997. P:2("Group_Create called in %d", Master_ID());
  998. new
  999. i;
  1000. if (!isnull(name))
  1001. {
  1002. // Get a group of the same name if it already exists.
  1003. i = _:Group_GetID(name);
  1004. if (i != _:INVALID_GROUP)
  1005. {
  1006. MASTER_ADD<_:GROUP_TEMP_FIX(Group:i)>
  1007. return Group:i;
  1008. }
  1009. }
  1010. i = 0;
  1011. while (i != _MAX_GROUPS && _Group_IsActive(i))
  1012. {
  1013. ++i;
  1014. }
  1015. if (i == _MAX_GROUPS) return INVALID_GROUP;
  1016. if (isnull(name))
  1017. {
  1018. YSI_gGroupData[i][E_GROUP_DATA_NAME][0] = 0;
  1019. YSI_gGroupData[i][E_GROUP_DATA_FLAGS] = e_GROUP_FLAGS_TEMP | e_GROUP_FLAGS_ACTIVE;
  1020. YSI_gGroupData[i][E_GROUP_DATA_HASH] = 0;
  1021. }
  1022. else
  1023. {
  1024. strpack(YSI_gGroupData[i][E_GROUP_DATA_NAME], name, MAX_GROUP_NAME char);
  1025. YSI_gGroupData[i][E_GROUP_DATA_FLAGS] = e_GROUP_FLAGS_ACTIVE;
  1026. if (!(YSI_gGroupData[i][E_GROUP_DATA_HASH] = YHash(name)))
  1027. {
  1028. P:E("Group %d has hash 0.", name);
  1029. }
  1030. }
  1031. MASTER_SET<i>
  1032. ++YSI_g_sGroupCount;
  1033. // Set the child groups to only this group.
  1034. //Bit_Let(YSI_g_sChildGroups[i], i);
  1035. // Add this group to other groups.
  1036. broadcastfunc _Group_CreateChain(Group:i);
  1037. return GROUP_MANGLE(i);
  1038. }
  1039. stock Group:Group_Create(const string:name[] = "")
  1040. {
  1041. if (name[0])
  1042. {
  1043. return _Group_Create(name);
  1044. }
  1045. else
  1046. {
  1047. return _Group_Create(NULL);
  1048. }
  1049. }
  1050. /*-------------------------------------------------------------------------*//**
  1051. * <param name="group">Group to loop over.</param>
  1052. * <param name="start">Last value.</param>
  1053. * <returns>
  1054. * The next player.
  1055. * </returns>
  1056. * <remarks>
  1057. * Internal implementation of the "Group()" iterator for "foreach". Returns
  1058. * all the players in a group one at a time. Now just wraps the "GroupPlayers"
  1059. * iterator that is only stored in the GROUP master script.
  1060. * </remarks>
  1061. *//*------------------------------------------------------------------------**/
  1062. #pragma deprecated use "GroupMember"
  1063. stock Iter_Func@Group(start, Group:group)
  1064. {
  1065. static
  1066. sOnce = true;
  1067. if (sOnce)
  1068. {
  1069. P:I("The \"Group\" iterator is deprecated, please use \"GroupMember\" instead.");
  1070. sOnce = false;
  1071. }
  1072. return Iter_Func@GroupMember(start, Group:group);
  1073. }
  1074. // Else. VERY similar to the `iterstart` macro, but without the first `J@`,
  1075. // which is used both for `sizeof` (we already gave it `I@`) and for detecting
  1076. // state functions, which this is not one of (so doesn't need the detection -
  1077. // and even if it was a state function, we would know that here and could
  1078. // adapt).
  1079. #define Iterator@GroupElse_(%1)%9$%9))-1);_:(%9=Iterator@%0$[_:%2]%9; ))-1+(%1));_:(%1)!=_:F@k:F@l:(%2=Iter_Func@%0$(_:%2));
  1080. FOREIGN__ Iter_Func@GroupMember(start, Group:group);
  1081. GLOBAL__ Iter_Func@GroupMember(start, Group:group)
  1082. {
  1083. GROUP_FIX(group);
  1084. if (start == -1)
  1085. {
  1086. //start = Iter_Begin(GroupPlayers[]);
  1087. start = Iter_First(GroupPlayers[_:GROUP_TEMP_FIX(group)]);
  1088. }
  1089. else
  1090. {
  1091. start = Iter_Next(GroupPlayers[_:GROUP_TEMP_FIX(group)], start);
  1092. }
  1093. if (start == Iter_End(GroupPlayers[]))
  1094. {
  1095. return -1;
  1096. }
  1097. return start;
  1098. }
  1099. #define Iterator@GroupMember iterstart(-1)
  1100. /*-------------------------------------------------------------------------*//**
  1101. * <param name="start">Last value.</param>
  1102. * <returns>
  1103. * The next group.
  1104. * </returns>
  1105. * <remarks>
  1106. * Internal implementation of the "CreatedGroup()" iterator for "foreach".
  1107. * Returns all the groups that exist.
  1108. * </remarks>
  1109. *//*------------------------------------------------------------------------**/
  1110. // Bypass y_iterate restrictions.
  1111. FOREIGN__ Group:Iter_Func@CreatedGroup(group);
  1112. GLOBAL__ Group:Iter_Func@CreatedGroup(group)
  1113. {
  1114. // In most iterators the inital value is implicitly handled by the first
  1115. // "++", but it isn't here because we need to correct for the "Group" flag.
  1116. if (Group:group != INVALID_GROUP) GROUP_FIX(Group:group);
  1117. while (++group < (_MAX_GROUPS_G - 1))
  1118. {
  1119. // DO NOT include the global group in this loop!
  1120. if (_Group_IsActive(Group:group)) return GROUP_MANGLE(Group:group);
  1121. }
  1122. return INVALID_GROUP;
  1123. }
  1124. #define Iterator@CreatedGroup iterstart(-1)
  1125. /*-------------------------------------------------------------------------*//**
  1126. * <param name="parent">Group to get the children of.</param>
  1127. * <param name="start">Last value.</param>
  1128. * <returns>
  1129. * The next group.
  1130. * </returns>
  1131. * <remarks>
  1132. * Internal implementation of the "ChildGroup()" iterator for "foreach".
  1133. * Returns all the groups that are a child of the provided group.
  1134. * </remarks>
  1135. *//*------------------------------------------------------------------------**/
  1136. FOREIGN__ Group:Iter_Func@GroupChild(start, Group:parent);
  1137. GLOBAL__ Group:Iter_Func@GroupChild(start, Group:parent)
  1138. {
  1139. if (!_Group_IsValid(parent)) return INVALID_GROUP;
  1140. // In most iterators the inital value is implicitly handled by the first
  1141. // "++", but it isn't here because we need to correct for the "Group" flag.
  1142. if (Group:start != INVALID_GROUP) GROUP_FIX(Group:start);
  1143. // Use the existing "Bits" iterator with fixed identifiers.
  1144. return GROUP_MANGLE(Iter_Func@Bits(start, YSI_g_sChildGroups[_:GROUP_TEMP_FIX(parent)], bits<_MAX_GROUPS_G>));
  1145. }
  1146. #define Iterator@GroupChild Iterator@Bits
  1147. /*-------------------------------------------------------------------------*//**
  1148. * <summary>
  1149. * _Y_G@C_0
  1150. * _Y_G@C_1
  1151. * _Y_G@C_2
  1152. * _Y_G@C_3
  1153. * </summary>
  1154. * <param name="func">Function to call.</param>
  1155. * <param name="">0, 1, 2, or 3 parameters.</param>
  1156. * <returns>
  1157. * 0 - ALWAYS zero to make "GCHAIN__" work properly.
  1158. * </returns>
  1159. * <remarks>
  1160. * Basically function indirection, call a function through a pointer and use
  1161. * the compiler to figure out the assembly to generate instead of having a
  1162. * run-time loop inside a single instance of this function. Using just one
  1163. * macro ("GROUP_CHAIN") one of these four functions are selected and called.
  1164. * Adding more is fairly trivial too, the parameters are just:
  1165. *
  1166. * #emit PUSH.S <16 + n * 4>
  1167. * #emit PUSH.S ...
  1168. * #emit PUSH.S 20
  1169. * #emit PUSH.S 16
  1170. * #emit PUSH.C <n * 4>
  1171. *
  1172. * This code is now, of course, SERIOUSLY outdated - function pointers have
  1173. * advanced way beyond this (see indirection.inc), but this code works, and
  1174. * because we have one function for each number of parameters, it is actually
  1175. * very fast because it is so specialised.
  1176. * </remarks>
  1177. *//*------------------------------------------------------------------------**/
  1178. stock _Y_G@C_0(func)
  1179. {
  1180. #emit PUSH.C 0
  1181. #emit LCTRL 6
  1182. #emit ADD.C 36
  1183. #emit LCTRL 8
  1184. #emit PUSH.pri
  1185. #emit LOAD.S.pri func
  1186. #emit SCTRL 6
  1187. // ALWAYS return 0;
  1188. return 0;
  1189. }
  1190. stock _Y_G@C_1(func, GLOBAL_TAG_TYPES:...)
  1191. {
  1192. #emit PUSH.S 16
  1193. #emit PUSH.C 4
  1194. #emit LCTRL 6
  1195. #emit ADD.C 36
  1196. #emit LCTRL 8
  1197. #emit PUSH.pri
  1198. #emit LOAD.S.pri func
  1199. #emit SCTRL 6
  1200. //#emit RETN
  1201. return 0;
  1202. }
  1203. stock _Y_G@C_2(func, GLOBAL_TAG_TYPES:...)
  1204. {
  1205. #emit PUSH.S 20
  1206. #emit PUSH.S 16
  1207. #emit PUSH.C 8
  1208. #emit LCTRL 6
  1209. #emit ADD.C 36
  1210. #emit LCTRL 8
  1211. #emit PUSH.pri
  1212. #emit LOAD.S.pri func
  1213. #emit SCTRL 6
  1214. //#emit RETN
  1215. return 0;
  1216. }
  1217. stock _Y_G@C_3(func, GLOBAL_TAG_TYPES:...)
  1218. {
  1219. #emit PUSH.S 24
  1220. #emit PUSH.S 20
  1221. #emit PUSH.S 16
  1222. #emit PUSH.C 12
  1223. #emit LCTRL 6
  1224. #emit ADD.C 36
  1225. #emit LCTRL 8
  1226. #emit PUSH.pri
  1227. #emit LOAD.S.pri func
  1228. #emit SCTRL 6
  1229. //#emit RETN
  1230. return 0;
  1231. }
  1232. /*-------------------------------------------------------------------------*//**
  1233. * <param name="g">Group to set for.</param>
  1234. * <param name="el">Element to set.</param>
  1235. * <param name="s">Set or unset?</param>
  1236. * <remarks>
  1237. * IMPORTANT NOTE: Groups are SLIGHTLY different to other systems - if you
  1238. * REMOVE a group from another group then players WILL NOT be removed from
  1239. * that second group, or any child groups.
  1240. * </remarks>
  1241. *//*------------------------------------------------------------------------**/
  1242. FOREIGN__ void:Group_SetGroup(Group:g,Group:el,bool:s);
  1243. GLOBAL__ void:Group_SetGroup(Group:g,Group:el,bool:s)
  1244. {
  1245. P:2(#Group_SetGroup " called: %i, %i, %i", _:g, _:el, s);
  1246. // Set wether a group can use this item.
  1247. if (g != el && _Group_IsValid(g) && _Group_IsValid(el))
  1248. {
  1249. GROUP_FIX(g);
  1250. GROUP_FIX(el);
  1251. if (s)
  1252. {
  1253. if (Bit_Get(YSI_g_sChildGroups[_:g], _:el))
  1254. {
  1255. // Child is already part of parent.
  1256. return;
  1257. }
  1258. Bit_Let(YSI_g_sChildGroups[_:g], _:el);
  1259. if (g == Group:_MAX_GROUPS) Bit_Let(YSI_g_sDefaultGroups, _:el);
  1260. FOREACH__ (new p : GroupPlayers[_:g])
  1261. {
  1262. if (!_Group_HasPlayer(el, p))
  1263. {
  1264. broadcastfunc _Group_SetPlayer(p, _Group_SetSome(p, _:el), bits<_MAX_GROUPS_G>);
  1265. }
  1266. }
  1267. }
  1268. else
  1269. {
  1270. if (Bit_Get(YSI_g_sChildGroups[_:g], _:el))
  1271. {
  1272. // Child is a part of parent (don't remove players though).
  1273. Bit_Vet(YSI_g_sChildGroups[_:g], _:el);
  1274. if (g == Group:_MAX_GROUPS) Bit_Vet(YSI_g_sDefaultGroups, _:el);
  1275. }
  1276. }
  1277. }
  1278. }
  1279. /*-------------------------------------------------------------------------*//**
  1280. * <param name="el">Element to set.</param>
  1281. * <param name="s">Set or unset?</param>
  1282. * <remarks>
  1283. * If "s" is true, then one element is added to the global group. False it is
  1284. * removed.
  1285. * </remarks>
  1286. *//*------------------------------------------------------------------------**/
  1287. FOREIGN__ void:Group_SetGlobalGroup(Group:el,bool:s);
  1288. GLOBAL__ void:Group_SetGlobalGroup(Group:el,bool:s)
  1289. {
  1290. P:2(#Group_SetGlobalGroup " called: %i, %i", _:el, s);
  1291. Group_SetGroup(GROUP_GLOBAL, el, s);
  1292. }
  1293. /*-------------------------------------------------------------------------*//**
  1294. * <summary>Group_Get...</summary>
  1295. * <param name="g">Group to get from.</param>
  1296. * <param name="el">Element to get.</param>
  1297. * <returns>
  1298. * bool: Does the group have the element?
  1299. * </returns>
  1300. * <remarks>
  1301. * This has no "active" checks on the groups as if they aren't active but are
  1302. * in range, then "YSI_g_sChildGroups" will return false anyway. Extra checks
  1303. * are therefore just a waste of time.
  1304. * </remarks>
  1305. *//*------------------------------------------------------------------------**/
  1306. FOREIGN__ bool:Group_GetGroup(Group:g,Group:el);
  1307. GLOBAL__ bool:Group_GetGroup(Group:g,Group:el)
  1308. {
  1309. P:2(#Group_GetGroup " called: %i, %i", _:g, _:el);
  1310. return (GROUP_MASK <= el <= GROUP_GLOBAL && GROUP_MASK <= g <= GROUP_GLOBAL && Bit_Get(YSI_g_sChildGroups[_:GROUP_TEMP_FIX(g)], _:GROUP_TEMP_FIX(el)));
  1311. }
  1312. /*-------------------------------------------------------------------------*//**
  1313. * <summary>Group_GetGlobal...</summary>
  1314. * <param name="el">Element to get.</param>
  1315. * <returns>
  1316. * bool: Does the global group have the element?
  1317. * </returns>
  1318. *//*------------------------------------------------------------------------**/
  1319. FOREIGN__ Group_GetGlobalGroup(Group:el);
  1320. GLOBAL__ Group_GetGlobalGroup(Group:el)
  1321. {
  1322. P:2(#Group_GetGlobalGroup " called: %i", _:el);
  1323. return Group_GetGroup(GROUP_GLOBAL, el);
  1324. }
  1325. #define Group_AddChild(%0,%1) Group_SetGroup((%0), (%1), true)
  1326. #define Group_RemoveChild(%0,%1) Group_SetGroup((%0), (%1), false)
  1327. #define Group_IsChild(%0,%1) Group_GetGroup((%0), (%1))
  1328. /*-------------------------------------------------------------------------*//**
  1329. * <param name="p">Ancestor group to check.</param>
  1330. * <param name="c">Other group to check.</param>
  1331. * <returns>
  1332. * bool: Is the second group related to the first?
  1333. * </returns>
  1334. * <remarks>
  1335. * Now uses implicit, not explicit, recursion.
  1336. * </remarks>
  1337. *//*------------------------------------------------------------------------**/
  1338. static stock
  1339. BitArray:YSI_g_sGroupDone<_MAX_GROUPS_G>;
  1340. FOREIGN__ bool:Group_IsDescendant(Group:p, Group:c);
  1341. GLOBAL__ bool:Group_IsDescendant(Group:p, Group:c)
  1342. {
  1343. // Groups that don't exist CAN'T be related, even if they're the same group.
  1344. if (_Group_IsValid(p) && _Group_IsValid(c))
  1345. {
  1346. if (p == c) return true; // Any group is related to itself.
  1347. GROUP_FIX(p);
  1348. GROUP_FIX(c);
  1349. // "g" = current child. "s" = current stack position. "c" = target
  1350. // child group. "p" = current parent.
  1351. Bit_SetAll(YSI_g_sGroupDone, false);
  1352. Bit_Let(YSI_g_sGroupDone, _:p);
  1353. new
  1354. g = -1,
  1355. s = 0;
  1356. for ( ; ; )
  1357. {
  1358. g = Iter_Func@Bits(g, YSI_g_sChildGroups[_:p], bits<_MAX_GROUPS_G>);
  1359. if (g == -1)
  1360. {
  1361. // Finished this child group, pop off the stack.
  1362. if (s--)
  1363. {
  1364. g = YSI_g_sRecursionStack[s][0];
  1365. p = Group:YSI_g_sRecursionStack[s][1];
  1366. }
  1367. else return false;
  1368. }
  1369. else if (!Bit_Get(YSI_g_sGroupDone, g))
  1370. {
  1371. if (Group:g == c) return true;
  1372. // We haven't tested this group yet.
  1373. Bit_Let(YSI_g_sGroupDone, g);
  1374. YSI_g_sRecursionStack[s][0] = g;
  1375. YSI_g_sRecursionStack[s][1] = _:p;
  1376. ++s;
  1377. p = Group:g;
  1378. g = -1;
  1379. }
  1380. }
  1381. }
  1382. return false;
  1383. }
  1384. //stock Group:operator+(Group:g, Group:o)
  1385. //{
  1386. // Group_SetGroup(g, o, true);
  1387. // return g;
  1388. //}
  1389. //
  1390. //stock Group:operator-(Group:g, Group:o)
  1391. //{
  1392. // Group_SetGroup(g, o, false);
  1393. // return g;
  1394. //}
  1395. //
  1396. //stock bool:operator>=(Group:g, Group:o)
  1397. //{
  1398. // return Group_IsDescendant(g, o);
  1399. //}
  1400. //
  1401. //stock bool:operator>(Group:g, Group:o)
  1402. //{
  1403. // return g != o && Group_IsDescendant(g, o);
  1404. //}
  1405. //
  1406. //stock bool:operator<=(Group:g, Group:o)
  1407. //{
  1408. // return Group_IsDescendant(o, g);
  1409. //}
  1410. //
  1411. //stock bool:operator<(Group:g, Group:o)
  1412. //{
  1413. // return g != o && Group_IsDescendant(o, g);
  1414. //}