_funcs.inc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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. ad88888ba
  66. d8" "8b ,d
  67. Y8, 88
  68. `Y8aaaaa, ,adPPYba, MM88MMM 88 88 8b,dPPYba,
  69. `"""""8b, a8P_____88 88 88 88 88P' "8a
  70. `8b 8PP""""""" 88 88 88 88 d8
  71. Y8a a8P "8b, ,aa 88, "8a, ,a88 88b, ,a8"
  72. "Y88888P" `"Ybbd8"' "Y888 `"YbbdP'Y8 88`YbbdP"'
  73. 88
  74. 88
  75. */
  76. #include "..\..\YSI_Internal\y_compilerdata"
  77. #if defined _inc__funcs
  78. #undef _inc__funcs
  79. #endif
  80. #if !defined _INC_y_groups__funcs
  81. #define _INC_y_groups__funcs
  82. #include "setup"
  83. #include "..\..\YSI_Internal\y_shortfunc"
  84. #include "..\..\YSI_Data\y_iterate"
  85. #endif
  86. #if !defined _GROUP_MAKE_TAG
  87. #define _GROUP_MAKE_TAG _
  88. #endif
  89. // Start of the multi-use file.
  90. static stock
  91. YSI_g_sMaxEncountered = -1,
  92. BitArray:YSI_g_sElementMembership[_GROUP_MAKE_LIMIT]<_:_MAX_GROUPS_G>,
  93. BitArray:YSI_g_sDefaultMembership<_:_MAX_GROUPS_G>,
  94. BitArray:YSI_g_sEmpty<_:_MAX_GROUPS_G>,
  95. _yGI,
  96. _yGU,
  97. _yGA;
  98. // Define the callback chaining for the current
  99. #if defined _YSI_HAS_y_groups
  100. #define gforeign%1(%2); _GROUP_MAKE_NAME<foreign%1>(%2);
  101. #define gglobal%1(%2) _GROUP_MAKE_NAME<global%1>(%2)
  102. #define gpublic master_func
  103. #if YSIM_HAS_MASTER
  104. #if _YSIM_IS_CLIENT
  105. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)
  106. // Should never be needed.
  107. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Client_Set>
  108. #elseif _YSIM_IS_SERVER
  109. #define _gchain%0(%2) _GROUP_MAKE_NAME<%0...>(%2);public _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  110. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  111. #elseif _YSIM_IS_STUB
  112. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)
  113. // Because of the interaction between the various things that the
  114. // groups and master systems this will NEVER be called in a stub
  115. // script - and if it is we now get a nice compile-time error
  116. // telling us so! It may, however, prove difficult to trace!
  117. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Stub_Set>
  118. #else
  119. #define _gchain%0(%2) _GROUP_MAKE_NAME<%0...>(%2);public _GROUP_MAKE_NAME<%0...>(%2)<>GROUP_CHAIN?<%0>(%2);public _GROUP_MAKE_NAME<%0...>(%2)<_YCM:y>for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  120. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  121. #endif
  122. #else
  123. #define _gchain%0(%2) _GROUP_MAKE_NAME<%0...>(%2);public _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  124. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  125. #endif
  126. #elseif __COMPILER_1ST_PASS
  127. #if YSIM_HAS_MASTER
  128. #if _YSIM_IS_CLIENT
  129. #define gforeign%0...%1(%2); stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;stock _GROUP_MAKE_NAME<%0...%1>(%2)<>_UNUSED(%2);
  130. #define gglobal%0...%1(%2) stock _GROUP_MAKE_NAME<%0...%1_>(%2)
  131. #define gpublic static stock
  132. #define _gchain%0(%2) stock _GROUP_MAKE_NAME<%0...>(%2)
  133. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Client_Set>
  134. #elseif _YSIM_IS_SERVER
  135. #define gforeign%0...%1(%2); _GROUP_MAKE_NAME<%0...%1>(%2);static stock _GROUP_MAKE_NAME<%0...%1@>(%2)(_GROUP_MAKE_NAME<%0...%1>(%2));
  136. #define gglobal%0...%1(%2) stock _GROUP_MAKE_NAME<%0...%1>(%2)
  137. #define gpublic stock
  138. #define _gchain%0(%2) stock _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  139. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  140. #elseif _YSIM_IS_STUB
  141. #define gforeign%0...%1(%2); stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;stock _GROUP_MAKE_NAME<%0...%1>(%2)<>;
  142. #define gglobal%0...%1(%2)
  143. #define gpublic static stock
  144. #define _gchain%0(%2) stock _GROUP_MAKE_NAME<%0...>(%2)
  145. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Stub_Set>
  146. #else
  147. #define gforeign%0...%1(%2); stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;stock _GROUP_MAKE_NAME<%0...%1>(%2)<>_UNUSED(%2);static stock _GROUP_MAKE_NAME<%0...%1@>(%2)<_YCM:y>(_GROUP_MAKE_NAME<%0...%1>(%2));
  148. #define gglobal%0...%1(%2) static stock _GROUP_MAKE_NAME<%0...%1@>(%2)<>(_GROUP_MAKE_NAME<%0...%1>(%2)); stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:y>
  149. #define gpublic%0(%1)<%9> stock%0(%1)<>{}stock%0(%1)<_YCM:%9>
  150. #define _gchain%0(%2) stock _GROUP_MAKE_NAME<%0...>(%2)<>GROUP_CHAIN?<%0>(%2);stock _GROUP_MAKE_NAME<%0...>(%2)<_YCM:y>for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  151. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  152. #endif
  153. #else
  154. #define gforeign%0...%1(%2);
  155. #define gglobal%0...%1(%2) stock _GROUP_MAKE_NAME<%0...%1>(%2)
  156. #define gglobal%0...%1(%2) stock _GROUP_MAKE_NAME<%0...%1>(%2)
  157. #define gpublic stock
  158. #define _gchain%0(%2) stock _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  159. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  160. #endif
  161. #else
  162. #if YSIM_HAS_MASTER
  163. #if _YSIM_IS_CLIENT
  164. #define gforeign%0...%1(%2); static stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;static stock _GROUP_MAKE_NAME<%0...%1>(%2)<>_UNUSED(%2);
  165. #define gglobal%0...%1(%2) static stock _GROUP_MAKE_NAME<%0...%1_>(%2)
  166. #define gpublic static stock
  167. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)
  168. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Client_Set>
  169. #elseif _YSIM_IS_SERVER
  170. #define gforeign%0...%1(%2); _GROUP_MAKE_NAME<%0...%1>(%2);static stock _GROUP_MAKE_NAME<%0...%1@>(%2)(_GROUP_MAKE_NAME<%0...%1>(%2));
  171. #define gglobal%0...%1(%2) static stock _GROUP_MAKE_NAME<%0...%1>(%2)
  172. #define gpublic static stock
  173. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  174. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  175. #elseif _YSIM_IS_STUB
  176. #define gforeign%0...%1(%2); static stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;static stock _GROUP_MAKE_NAME<%0...%1>(%2)<>;
  177. #define gglobal%0...%1(%2)
  178. #define gpublic static stock
  179. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)
  180. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<_Error_..._Stub_Set>
  181. #else
  182. #define gforeign%0...%1(%2); static stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:m>;static stock _GROUP_MAKE_NAME<%0...%1>(%2)<>_UNUSED(%2);static stock _GROUP_MAKE_NAME<%0...%1@>(%2)<_YCM:y>(_GROUP_MAKE_NAME<%0...%1>(%2));
  183. #define gglobal%0...%1(%2) static stock _GROUP_MAKE_NAME<%0...%1@>(%2)<>(_GROUP_MAKE_NAME<%0...%1>(%2));static stock _GROUP_MAKE_NAME<%0...%1>(%2)<_YCM:y>
  184. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)<>GROUP_CHAIN?<%0>(%2);static stock _GROUP_MAKE_NAME<%0...>(%2)<_YCM:y>for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  185. #define gpublic%0(%1)<%9> static stock%0(%1)<>{}static stock%0(%1)<_YCM:%9>
  186. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  187. #endif
  188. #else
  189. #define gforeign%0...%1(%2);
  190. #define gglobal%0...%1(%2) static stock _GROUP_MAKE_NAME<%0...%1>(%2)
  191. #define gpublic static stock
  192. #define _gchain%0(%2) static stock _GROUP_MAKE_NAME<%0...>(%2)for(J@=1;J@;GROUP_CHAIN?<%0>(%2))
  193. #define _GROUP_SET_PLAYER _GROUP_MAKE_NAME<..._SetPlayer>
  194. #endif
  195. #endif
  196. /*-------------------------------------------------------------------------*//**
  197. * <param name="x">The element that was added (maybe).</param>
  198. * <remarks>
  199. * The name is a macro, so this function isn't actually called this. This is
  200. * called when a new element is created, and as such it is NOT chained to other
  201. * parts of the groups system because each part handles one type of element.
  202. * Loop through all players and set up the element for them if they are in a
  203. * group that this is also in by default.
  204. *
  205. * If x is "_GROUP_MAKE_LIMIT" then this is the test used in OnPlayerConnect in
  206. * various libraries to see if the groups system exists, and if not locally
  207. * initialise the player instead of leaving it up to this system.
  208. * </remarks>
  209. *//*------------------------------------------------------------------------**/
  210. stock bool:_GROUP_INITIALISE(_GROUP_MAKE_TAG:x = _GROUP_MAKE_TAG:_GROUP_MAKE_LIMIT)
  211. {
  212. #if defined _YSI_HAS_y_groups
  213. P:4(#_GROUP_INITIALISE " called: %i", x);
  214. // A new item has been added to the system - update all players according to
  215. // the default settings for a group.
  216. if (x != _GROUP_MAKE_TAG:_GROUP_MAKE_LIMIT)
  217. {
  218. YSI_g_sElementMembership[_:x] = YSI_g_sDefaultMembership,
  219. YSI_g_sMaxEncountered = max(YSI_g_sMaxEncountered, _:x);
  220. foreach (new playerid : Player)
  221. {
  222. Group_FullPlayerUpdate(playerid, _:x, YSI_g_sEmpty, YSI_g_sDefaultMembership, YSI_gGroupPlayers[playerid]);
  223. }
  224. }
  225. #endif
  226. #pragma unused x
  227. return false;
  228. }
  229. /*
  230. ad88888ba 88 88
  231. d8" "8b "" 88
  232. Y8, 88
  233. `Y8aaaaa, 88 8b,dPPYba, ,adPPYb,d8 88 ,adPPYba,
  234. `"""""8b, 88 88P' `"8a a8" `Y88 88 a8P_____88
  235. `8b 88 88 88 8b 88 88 8PP"""""""
  236. Y8a a8P 88 88 88 "8a, ,d88 88 "8b, ,aa
  237. "Y88888P" 88 88 88 `"YbbdP"Y8 88 `"Ybbd8"'
  238. aa, ,88
  239. "Y8bbdP"
  240. */
  241. /*-------------------------------------------------------------------------*//**
  242. * <summary>Group_Set...</summary>
  243. * <param name="g">Group to set for.</param>
  244. * <param name="el">Element to set.</param>
  245. * <param name="s">Set or unset?</param>
  246. * <remarks>
  247. * If "s" is true, then one element is added to the current group. False it is
  248. * removed.
  249. * </remarks>
  250. *//*------------------------------------------------------------------------**/
  251. gforeign Group_Set...(Group:g,_GROUP_MAKE_TAG:el,bool:s);
  252. gglobal Group_Set...(Group:g,_GROUP_MAKE_TAG:el,bool:s)
  253. {
  254. P:2(#_GROUP_MAKE_NAME<Group_Set...> " called: %i, %i, %i", _:g, _:el, s);
  255. // Set wether a group can use this item.
  256. if (0 <= _:el < _GROUP_MAKE_LIMIT && GROUP_MASK <= g <= GROUP_GLOBAL)
  257. {
  258. // There is now NO validity check for reasons of distruibution.
  259. GROUP_FIX(g);
  260. new
  261. slot = Bit_Slot(g),
  262. Bit:mask = Bit_Mask(g);
  263. if (s)
  264. {
  265. YSI_gTempGroups = YSI_g_sElementMembership[_:el];
  266. if (YSI_gTempGroups[slot] & mask)
  267. {
  268. // No point adding an element to a group that it is already in.
  269. return 1;
  270. }
  271. // Is this element NOT in the current group?
  272. Bit_Let(YSI_gTempGroups, _:g);
  273. }
  274. else
  275. {
  276. YSI_gTempGroups = YSI_g_sElementMembership[_:el];
  277. if (!(YSI_gTempGroups[slot] & mask))
  278. {
  279. return 1;
  280. }
  281. // Is this element in the current group?
  282. Bit_Vet(YSI_gTempGroups, _:g);
  283. }
  284. foreach (new playerid : Player)
  285. {
  286. if (YSI_gGroupPlayers[playerid][slot] & mask)
  287. {
  288. // The player is in the group in question, so they need a full
  289. // update.
  290. Group_FullPlayerUpdate(playerid, _:el, YSI_g_sElementMembership[_:el], YSI_gTempGroups, YSI_gGroupPlayers[playerid]);
  291. }
  292. }
  293. YSI_g_sElementMembership[_:el] = YSI_gTempGroups;
  294. return 1;
  295. }
  296. return 0;
  297. }
  298. /*-------------------------------------------------------------------------*//**
  299. * <summary>Group_Get...</summary>
  300. * <param name="g">Group to get from.</param>
  301. * <param name="el">Element to get.</param>
  302. * <returns>
  303. * bool: Does the group have the element?
  304. * </returns>
  305. *//*------------------------------------------------------------------------**/
  306. gforeign bool:Group_Get...(Group:g,_GROUP_MAKE_TAG:el);
  307. gglobal bool:Group_Get...(Group:g,_GROUP_MAKE_TAG:el)
  308. {
  309. P:2(#_GROUP_MAKE_NAME<Group_Get...> " called: %i, %i", _:g, _:el);
  310. return (0 <= _:el < _GROUP_MAKE_LIMIT && GROUP_MASK <= g <= GROUP_GLOBAL && Bit_Get(YSI_g_sElementMembership[_:el], _:GROUP_TEMP_FIX(g)));
  311. }
  312. /*-------------------------------------------------------------------------*//**
  313. * <summary>Group_Set...Default</summary>
  314. * <param name="g">Group to set for.</param>
  315. * <param name="s">Set or unset?</param>
  316. * <remarks>
  317. * If "s" is true, then all elements are added to this group (i.e. the default
  318. * is set to true and all previous settings are wiped out). If it is false
  319. * then all elements are removed and a full update is done.
  320. * </remarks>
  321. *//*------------------------------------------------------------------------**/
  322. gforeign Group_Set...Default(Group:g,bool:s);
  323. gglobal Group_Set...Default(Group:g,bool:s)
  324. {
  325. P:2(#_GROUP_MAKE_NAME<Group_Set...Default> " called: %i, %i", _:g, s);
  326. if (GROUP_MASK <= g <= GROUP_GLOBAL)
  327. {
  328. // There is now NO validity check for reasons of distruibution.
  329. GROUP_FIX(g);
  330. new
  331. slot = Bit_Slot(g),
  332. Bit:mask = Bit_Mask(g),
  333. Iterator:GP<MAX_PLAYERS>;
  334. foreach (new playerid : Player)
  335. {
  336. // Do this check here so it is only done once per player. This is a
  337. // good argument for moving iterators to be duplicated in every
  338. // script; however, the default "Group()" iterator implementation is
  339. // a function, not a standard iterator - actually it now isn't...
  340. if (YSI_gGroupPlayers[playerid][slot] & mask)
  341. {
  342. // Make a fast local iterator of all the players.
  343. Iter_Add(GP, playerid);
  344. }
  345. }
  346. static
  347. BitArray:sNext<_MAX_GROUPS_G>;
  348. if (s)
  349. {
  350. Bit_Let(YSI_g_sDefaultMembership, _:g);
  351. for (new el = 0; el <= YSI_g_sMaxEncountered; ++el)
  352. {
  353. sNext = YSI_g_sElementMembership[el];
  354. if (sNext[slot] & mask)
  355. {
  356. continue;
  357. }
  358. // Is this element NOT in the current group?
  359. Bit_Let(sNext, _:g);
  360. foreach (new playerid : GP)
  361. {
  362. Group_FullPlayerUpdate(playerid, el, YSI_g_sElementMembership[el], sNext, YSI_gGroupPlayers[playerid]);
  363. }
  364. YSI_g_sElementMembership[el] = sNext;
  365. }
  366. }
  367. else
  368. {
  369. Bit_Vet(YSI_g_sDefaultMembership, _:g);
  370. for (new el = 0; el <= YSI_g_sMaxEncountered; ++el)
  371. {
  372. sNext = YSI_g_sElementMembership[el];
  373. if (!(sNext[slot] & mask))
  374. {
  375. continue;
  376. }
  377. // Is this element in the current group?
  378. Bit_Vet(sNext, _:g);
  379. foreach (new playerid : GP)
  380. {
  381. Group_FullPlayerUpdate(playerid, el, YSI_g_sElementMembership[el], sNext, YSI_gGroupPlayers[playerid]);
  382. }
  383. YSI_g_sElementMembership[el] = sNext;
  384. }
  385. }
  386. return 1;
  387. }
  388. return 0;
  389. }
  390. /*-------------------------------------------------------------------------*//**
  391. * <summary>Group_Set...New</summary>
  392. * <param name="g">Group to set for.</param>
  393. * <param name="s">Set or unset?</param>
  394. * <remarks>
  395. * Similar to "Group_Set...Default", but doesn't reset all existing elements,
  396. * just sets the permissions for any future items.
  397. * </remarks>
  398. *//*------------------------------------------------------------------------**/
  399. gforeign Group_Set...New(Group:g,bool:s);
  400. gglobal Group_Set...New(Group:g,bool:s)
  401. {
  402. P:2(#_GROUP_MAKE_NAME<Group_Set...New> " called: %i, %i", _:g, s);
  403. if (GROUP_MASK <= g <= GROUP_GLOBAL)
  404. {
  405. // There is now NO validity check for reasons of distruibution.
  406. Bit_Set(YSI_g_sDefaultMembership, _:GROUP_TEMP_FIX(g), s);
  407. return 1;
  408. }
  409. return 0;
  410. }
  411. /*-------------------------------------------------------------------------*//**
  412. * <summary>Group_Exclusive...</summary>
  413. * <param name="g">Group to add this to.</param>
  414. * <param name="el">Element to add.</param>
  415. * <remarks>
  416. * Add this element to ONLY this group and remove it from any others it might
  417. * already be in. This is basically a simplified version of "GROUP_ADD".
  418. * </remarks>
  419. *//*------------------------------------------------------------------------**/
  420. gforeign Group_Exclusive...(Group:g, _GROUP_MAKE_TAG:el);
  421. gglobal Group_Exclusive...(Group:g, _GROUP_MAKE_TAG:el)
  422. {
  423. if (GROUP_MASK <= g <= GROUP_GLOBAL)
  424. {
  425. GROUP_FIX(g);
  426. YSI_gTempGroups = YSI_g_sDefaultMembership;
  427. YSI_g_sDefaultMembership = YSI_g_cEmptyGroups;
  428. Bit_Let(YSI_g_sDefaultMembership, _:g);
  429. for (new i = 0; i != bits<_MAX_GROUPS_G>; ++i)
  430. {
  431. YSI_g_sEmpty[i] = ~YSI_g_sDefaultMembership[i];
  432. }
  433. _GROUP_INITIALISE(el);
  434. YSI_g_sDefaultMembership = YSI_gTempGroups;
  435. YSI_g_sEmpty = YSI_g_cEmptyGroups;
  436. return 1;
  437. }
  438. return 0;
  439. }
  440. /*
  441. ,ad8888ba, 88 88 88
  442. d8"' `"8b 88 88 88
  443. d8' 88 88 88
  444. 88 88 ,adPPYba, 88,dPPYba, ,adPPYYba, 88
  445. 88 88888 88 a8" "8a 88P' "8a "" `Y8 88
  446. Y8, 88 88 8b d8 88 d8 ,adPPPPP88 88
  447. Y8a. .a88 88 "8a, ,a8" 88b, ,a8" 88, ,88 88
  448. `"Y88888P" 88 `"YbbdP"' 8Y"Ybbd8"' `"8bbdP"Y8 88
  449. */
  450. /*-------------------------------------------------------------------------*//**
  451. * <summary>Group_SetGlobal...</summary>
  452. * <param name="el">Element to set.</param>
  453. * <param name="s">Set or unset?</param>
  454. * <remarks>
  455. * If "s" is true, then one element is added to the global group. False it is
  456. * removed.
  457. * </remarks>
  458. *//*------------------------------------------------------------------------**/
  459. gforeign Group_SetGlobal...(_GROUP_MAKE_TAG:el,bool:s);
  460. gglobal Group_SetGlobal...(_GROUP_MAKE_TAG:el,bool:s)
  461. {
  462. P:2(#_GROUP_MAKE_NAME<Group_SetGlobal...> " called: %i, %i", _:el, s);
  463. return _GROUP_MAKE_NAME<Group_Set...>(GROUP_GLOBAL, el, s);
  464. }
  465. /*-------------------------------------------------------------------------*//**
  466. * <summary>Group_GetGlobal...</summary>
  467. * <param name="el">Element to get.</param>
  468. * <returns>
  469. * bool: Does the global group have the element?
  470. * </returns>
  471. *//*------------------------------------------------------------------------**/
  472. gforeign bool:Group_GetGlobal...(_GROUP_MAKE_TAG:el);
  473. gglobal bool:Group_GetGlobal...(_GROUP_MAKE_TAG:el)
  474. {
  475. P:2(#_GROUP_MAKE_NAME<Group_GetGlobal...> " called: %i", _:el);
  476. return _GROUP_MAKE_NAME<Group_Get...>(GROUP_GLOBAL, el);
  477. }
  478. /*-------------------------------------------------------------------------*//**
  479. * <summary>Group_SetGlobal...Default</summary>
  480. * <param name="s">Set or unset?</param>
  481. * <remarks>
  482. * If "s" is true, then all elements are added to the global group (i.e. the
  483. * default is set to true and all previous settings are wiped out). If it is
  484. * false then all elements are removed and a full update is done.
  485. * </remarks>
  486. *//*------------------------------------------------------------------------**/
  487. gforeign Group_SetGlobal...Default(bool:s);
  488. gglobal Group_SetGlobal...Default(bool:s)
  489. {
  490. P:2(#_GROUP_MAKE_NAME<Group_SetGlobal...Default> " called: %i", s);
  491. return _GROUP_MAKE_NAME<Group_Set...Default>(GROUP_GLOBAL, s);
  492. }
  493. /*-------------------------------------------------------------------------*//**
  494. * <summary>Group_SetGlobal...New</summary>
  495. * <param name="s">Set or unset?</param>
  496. * <remarks>
  497. * All elements created FROM THIS POINT ON will have this default setting.
  498. * </remarks>
  499. *//*------------------------------------------------------------------------**/
  500. gforeign Group_SetGlobal...New(bool:s);
  501. gglobal Group_SetGlobal...New(bool:s)
  502. {
  503. P:2(#_GROUP_MAKE_NAME<Group_SetGlobal...New> " called: %i", s);
  504. return _GROUP_MAKE_NAME<Group_Set...New>(GROUP_GLOBAL, s);
  505. }
  506. /*-------------------------------------------------------------------------*//**
  507. * <summary>Group_GlobalExclusive...</summary>
  508. * <param name="el">Element to add.</param>
  509. * <remarks>
  510. * Add this element to ONLY the global group and remove it from any others it
  511. * might already be in.
  512. * </remarks>
  513. *//*------------------------------------------------------------------------**/
  514. gforeign Group_GlobalExclusive...(_GROUP_MAKE_TAG:el);
  515. gglobal Group_GlobalExclusive...(_GROUP_MAKE_TAG:el)
  516. {
  517. P:2(#_GROUP_MAKE_NAME<Group_GlobalExclusive...> " called: %i", el);
  518. return _GROUP_MAKE_NAME<Group_Exclusive...>(GROUP_GLOBAL, el);
  519. }
  520. /*
  521. 88 88
  522. 88 ,d 88
  523. 88 88 88
  524. 88 8b,dPPYba, MM88MMM ,adPPYba, 8b,dPPYba, 8b,dPPYba, ,adPPYYba, 88
  525. 88 88P' `"8a 88 a8P_____88 88P' "Y8 88P' `"8a "" `Y8 88
  526. 88 88 88 88 8PP""""""" 88 88 88 ,adPPPPP88 88
  527. 88 88 88 88, "8b, ,aa 88 88 88 88, ,88 88
  528. 88 88 88 "Y888 `"Ybbd8"' 88 88 88 `"8bbdP"Y8 88
  529. */
  530. static stock void:Group_Handoff(i,a[],s)
  531. {
  532. s = min(s, bits<_:_MAX_GROUPS_G>);
  533. if (i == -1)
  534. {
  535. memcpy(_:YSI_g_sDefaultMembership, a, 0, s * 4);
  536. }
  537. else if (i < sizeof (YSI_g_sElementMembership))
  538. {
  539. memcpy(_:YSI_g_sElementMembership[i], a, 0, s * 4);
  540. }
  541. }
  542. gpublic MAKE_YCM<HANDOFF_SOURCE...Group>()<p>
  543. {
  544. // Pass data to the new group controller.
  545. Group_Handoff(-1, _:YSI_g_sDefaultMembership, sizeof (YSI_g_sDefaultMembership));
  546. for (new i = 0; i != sizeof (YSI_g_sElementMembership); ++i)
  547. {
  548. Group_Handoff(i, _:YSI_g_sElementMembership[i], sizeof (YSI_g_sElementMembership[]));
  549. }
  550. }
  551. /*-------------------------------------------------------------------------*//**
  552. * <param name="playerid">Player to check.</param>
  553. * <param name="el">Element to show or hide.</param>
  554. * <param name="previous">(p) The old state of affairs.</param>
  555. * <param name="current">(c) The new state of affairs.</param>
  556. * <param name="reference">(r) What to compare changes to.</param>
  557. * <remarks>
  558. * I did have a good reason for calling this "FU", but I forgot it! Anyway,
  559. * the state of some groups has changed - either a player's groups or an
  560. * elements groups have changed. If the player could previously see the
  561. * element but now can't, hide it. If the player previously couldn't see it
  562. * but now can, show it. If there is no change do nothing. The old version of
  563. * this library would just re-show the element even if they could already see
  564. * it, but this was a bad design as it could incur large overheads in other
  565. * libraries when they had to do IO to enable or disable something for a
  566. * player.
  567. *
  568. * The change can be in either the player's groups or the element's groups,
  569. * either way this code will work regardless.
  570. * </remarks>
  571. *//*------------------------------------------------------------------------**/
  572. static stock Group_FullPlayerUpdate(playerid, el, Bit:p[], Bit:c[], Bit:r[])
  573. {
  574. // "_GROUPS_CHECK" is a macro that expands to a massive unrolled "if"
  575. // statement checking up to 512 groups at once. Any more than that and this
  576. // code resorts to a loop instead. I say "at once"; it does 32 AT ONCE
  577. // (as in truly in parallel), starting with the most likely match (the
  578. // default group that every player and every element is usually in), and
  579. // loops over all the groups in 32 group chunks. When I say "loop", this
  580. // could be in the form of a huge "if" statement with every iteration put in
  581. // explicitly.
  582. // r = Reference (valid groups).
  583. // c = Current (new groups).
  584. // p = Previous (old groups).
  585. #if _DEBUG >= 7
  586. new debugA[] = "false", debugB[] = "false";
  587. _GROUPS_CHECK_ANY(p,r)
  588. debugA = "true";
  589. _GROUPS_CHECK_ANY(c,r)
  590. debugB = "true";
  591. printf("Group_FullPlayerUpdate ("#_GROUP_MAKE_NAME<...>") called:\r\n\t%d, %d,\r\n\t%s,\r\n\t%s,\r\n\t%s,\r\n\t%s, %s",
  592. playerid, el, Bit_Display(p, bits<_MAX_GROUPS_G>), Bit_Display(c, bits<_MAX_GROUPS_G>), Bit_Display(r, bits<_MAX_GROUPS_G>), debugA, debugB);
  593. #endif
  594. _GROUPS_CHECK_ANY(p,r)
  595. {
  596. // Could previously see this thing. The thing about this design is that
  597. // it can (best case) take just 2 comparisons to end - and that should
  598. // be the common case!
  599. _GROUPS_CHECK_ANY(c,r)
  600. {
  601. // Still can.
  602. P:7("Group_FullPlayerUpdate: %d %d could, still can", playerid, el);
  603. return;
  604. }
  605. // Now can't.
  606. P:7("Group_FullPlayerUpdate: %d %d could, now can't", playerid, el);
  607. _GROUP_SET_PLAYER(_GROUP_MAKE_TAG:el, playerid, false);
  608. return;
  609. }
  610. // Couldn't see it before.
  611. _GROUPS_CHECK_ANY(c,r)
  612. {
  613. P:7("Group_FullPlayerUpdate: %d %d now can", playerid, el);
  614. // They have whatever this thing is. Note that this may be called
  615. // MULTIPLE times for an element, without anything actually changing.
  616. // I.e. this could be set to "true" repeatedly while never being set
  617. // to "false".
  618. _GROUP_SET_PLAYER(_GROUP_MAKE_TAG:el, playerid, true);
  619. // We use "return" here because "_GROUPS_CHECK_ANY" MAY be a loop.
  620. return;
  621. }
  622. P:7("Group_FullPlayerUpdate: %d %d can't", playerid, el);
  623. }
  624. /*
  625. ,ad8888ba, 88 88
  626. d8"' `"8b 88 ""
  627. d8' 88
  628. 88 88,dPPYba, ,adPPYYba, 88 8b,dPPYba, ,adPPYba,
  629. 88 88P' "8a "" `Y8 88 88P' `"8a I8[ ""
  630. Y8, 88 88 ,adPPPPP88 88 88 88 `"Y8ba,
  631. Y8a. .a8P 88 88 88, ,88 88 88 88 aa ]8I
  632. `"Y8888Y"' 88 88 `"8bbdP"Y8 88 88 88 `"YbbdP"'
  633. */
  634. /*-------------------------------------------------------------------------*//**
  635. * <param name="ni">Next init function variable as returned by y_amx.</param>
  636. * <param name="na">Next add function variable as returned by y_amx.</param>
  637. * <param name="nu">Next update function variable as returned by y_amx.</param>
  638. * <remarks>
  639. * This function is called when the group system first starts up to initialise
  640. * the global group and all the various function pointers. The way the
  641. * "_gchain" macro works means that the fact that "ni" etc are references is
  642. * irrelevant; however, it does make the code LOOK much nicer and like
  643. * assigning to the variables does have some wider meaning.
  644. *
  645. * If this is called with "ni = -1", it is special code to temporarily set or
  646. * restore the defaults for use with the "GROUP_ADD" macro. So basically, it
  647. * is poor design giving two distinct uses to a single function.
  648. * </remarks>
  649. *//*------------------------------------------------------------------------**/
  650. _gchain _yGI(&ni, &na, &nu)
  651. {
  652. P:2(#_GROUP_MAKE_NAME<_yGI...> " called: %i, %i, %i", ni, na, nu);
  653. if (ni == -1)
  654. {
  655. P:4(#_GROUP_MAKE_NAME<_yGI...> " INIT");
  656. static
  657. BitArray:sStack<_MAX_GROUPS_G>;
  658. if (na)
  659. {
  660. // Called to "push" the default settings.
  661. sStack = YSI_g_sDefaultMembership;
  662. YSI_g_sDefaultMembership = YSI_g_cEmptyGroups;
  663. Bit_Let(YSI_g_sDefaultMembership, nu);
  664. for (new i = 0; i != bits<_MAX_GROUPS_G>; ++i)
  665. {
  666. YSI_g_sEmpty[i] = ~YSI_g_sDefaultMembership[i];
  667. }
  668. }
  669. else
  670. {
  671. // Called to "pop" the default settings.
  672. YSI_g_sDefaultMembership = sStack;
  673. YSI_g_sEmpty = YSI_g_cEmptyGroups;
  674. }
  675. }
  676. else
  677. {
  678. P:4(#_GROUP_MAKE_NAME<_yGI...> " SETUP");
  679. // Enable the default group. If I'm right, this way is actually better than
  680. // using variables as in most cases because "_MAX_GROUPS" is a constant so
  681. // all the other maths will be constant.
  682. Bit_Let(YSI_g_sDefaultMembership, _MAX_GROUPS);
  683. // Set up the function chaining.
  684. new
  685. x;
  686. ni = AMX_GetPublicPointerPrefix(ni, x, _A<_yGI>);
  687. _yGI = x;
  688. na = AMX_GetPublicPointerPrefix(na, x, _A<_yGA>);
  689. _yGA = x;
  690. nu = AMX_GetPublicPointerPrefix(nu, x, _A<_yGU>);
  691. _yGU = x;
  692. }
  693. }
  694. /*-------------------------------------------------------------------------*//**
  695. * <param name="group">The group that was just created.</param>
  696. * <remarks>
  697. * The given group was just created, loop over all elements and make sure they
  698. * are NOT in this group - only the global group has a "default default" of
  699. * true. We don't need to update any players with this as no-one will ever be
  700. * in a brand new group.
  701. * </remarks>
  702. *//*------------------------------------------------------------------------**/
  703. _gchain _yGA(&group)
  704. {
  705. P:4(#_GROUP_MAKE_NAME<_yGA...> " called: %i", _:group);
  706. // Adding a new group is now a lot harder than it was before, but on the
  707. // other hand, adding and using elements is vastly simpler so that's OK.
  708. new
  709. s = Bit_Slot(group),
  710. Bit:m = ~Bit_Mask(group);
  711. // Set the default "contains" for this group to false.
  712. YSI_g_sDefaultMembership[s] &= m;
  713. // Disable every element in this group. DOESN'T use "YSI_g_sMaxEncountered"
  714. // because we need to set up for the future too.
  715. for (new i = 0; i != _GROUP_MAKE_LIMIT; ++i)
  716. {
  717. YSI_g_sElementMembership[i][s] &= m;
  718. }
  719. }
  720. /*-------------------------------------------------------------------------*//**
  721. * <param name="pid">The player who joined or left groups.</param>
  722. * <param name="p">Their previous groups.</param>
  723. * <param name="c">Their new groups.</param>
  724. * <remarks>
  725. * The player "pid" just joined or left a group (or groups - can do multiple).
  726. * Update their visibility accordingly. This function is ONLY called if there
  727. * is a CHANGE - earlier functions confirm that they weren't already in (or
  728. * not) this group(s) before the call.
  729. * </remarks>
  730. *//*------------------------------------------------------------------------**/
  731. _gchain _yGU(&pid, Bit:p[], Bit:c[])
  732. {
  733. P:4(#_GROUP_MAKE_NAME<_yGU...> " called: %i, %s, %s", pid, Bit_Display(p, bits<_MAX_GROUPS_G>), Bit_Display(c, bits<_MAX_GROUPS_G>));
  734. // This code loops over every "thing" controlled by this script. For every
  735. // one it checks to see if the player can or can't see something that they
  736. // previously could or couldn't see. If their ability to see it has
  737. // changed then the "_GROUP_SET_PLAYER" function in the controlling library
  738. // is called to do the actual internal function of updating their state.
  739. for (new el = 0; el <= YSI_g_sMaxEncountered; ++el)
  740. {
  741. Group_FullPlayerUpdate(pid, el, p, c, YSI_g_sElementMembership[el]);
  742. }
  743. //printf("Player membership: %s", Bit_Display(c));
  744. }
  745. /*
  746. ,ad8888ba, 88
  747. d8"' `"8b 88
  748. d8' 88
  749. 88 88 ,adPPYba, ,adPPYYba, 8b,dPPYba, 88 88 8b,dPPYba,
  750. 88 88 a8P_____88 "" `Y8 88P' `"8a 88 88 88P' "8a
  751. Y8, 88 8PP""""""" ,adPPPPP88 88 88 88 88 88 d8
  752. Y8a. .a8P 88 "8b, ,aa 88, ,88 88 88 "8a, ,a88 88b, ,a8"
  753. `"Y8888Y"' 88 `"Ybbd8"' `"8bbdP"Y8 88 88 `"YbbdP'Y8 88`YbbdP"'
  754. 88
  755. 88
  756. */
  757. /*-------------------------------------------------------------------------*//**
  758. * <remarks>
  759. * Calls all functions to correctly include them in the AMX when required.
  760. * Also all variables as it turns out they were a problem too.
  761. * </remarks>
  762. *//*------------------------------------------------------------------------**/
  763. #if !defined _GROUP_STOP_INCLUDES
  764. static stock _GROUP_PREVIOUS_FUNCTION()
  765. {
  766. #if defined _GROUP_INCLUDE_ALL_PREVIOUS
  767. _GROUP_UNIQUE_FUNCTION();
  768. #endif
  769. }
  770. #include "_unique"
  771. stock _GROUP_UNIQUE_FUNCTION()
  772. {
  773. #if YSIM_HAS_MASTER
  774. // Force the compiler to add the functions correctly.
  775. #if !(_YSIM_IS_CLIENT || _YSIM_IS_STUB)
  776. new
  777. a = _yGI, b = _yGA, c = _yGU;
  778. _GROUP_MAKE_NAME<_yGI...>(a, YSI_g_sMaxEncountered, c);
  779. _GROUP_MAKE_NAME<Group_Exclusive...@>(Group:0, _GROUP_MAKE_TAG:0);
  780. _GROUP_MAKE_NAME<Group_GlobalExclusive...@>(_GROUP_MAKE_TAG:0);
  781. _GROUP_MAKE_NAME<_yGA...>(b);
  782. _GROUP_MAKE_NAME<_yGU...>(c, Bit:"", Bit:"");
  783. _GROUP_MAKE_NAME<Group_Set...Default@>(Group:0, false);
  784. _GROUP_MAKE_NAME<Group_SetGlobal...Default@>(false);
  785. _GROUP_MAKE_NAME<Group_Set...New@>(Group:0, false);
  786. _GROUP_MAKE_NAME<Group_SetGlobal...New@>(false);
  787. _GROUP_MAKE_NAME<Group_Set...@>(Group:0, _GROUP_MAKE_TAG:0, false);
  788. _GROUP_MAKE_NAME<Group_SetGlobal...@>(_GROUP_MAKE_TAG:0, false);
  789. _GROUP_MAKE_NAME<Group_Get...@>(Group:0, _GROUP_MAKE_TAG:0);
  790. _GROUP_MAKE_NAME<Group_GetGlobal...@>(_GROUP_MAKE_TAG:0);
  791. for (new i = 0; i != _GROUP_MAKE_LIMIT; ++i)
  792. {
  793. YSI_g_sElementMembership[i] = Bit:"";
  794. }
  795. YSI_g_sDefaultMembership = Bit:"";
  796. YSI_g_sEmpty = Bit:"";
  797. printf("", _:YSI_g_sElementMembership);
  798. printf("", _yGI);
  799. printf("", _:YSI_g_sDefaultMembership);
  800. printf("", _yGU);
  801. printf("", _:YSI_g_sEmpty);
  802. printf("", _yGA);
  803. _GROUP_SET_PLAYER(_GROUP_MAKE_TAG:0, 0, false);
  804. MAKE_YCM<HANDOFF_SOURCE...Group>();
  805. #endif
  806. #else
  807. new
  808. a = _yGI, b = _yGA, c = _yGU;
  809. _GROUP_MAKE_NAME<_yGI...>(a, YSI_g_sMaxEncountered, c);
  810. _GROUP_MAKE_NAME<_yGA...>(b);
  811. _GROUP_MAKE_NAME<_yGU...>(c, Bit:"", Bit:"");
  812. printf("", YSI_g_sMaxEncountered);
  813. printf("", _:YSI_g_sElementMembership);
  814. printf("", _:YSI_g_sDefaultMembership);
  815. printf("", _:YSI_g_sEmpty);
  816. printf("", _yGI);
  817. printf("", _yGA);
  818. printf("", _yGU);
  819. #endif
  820. _GROUP_PREVIOUS_FUNCTION();
  821. }
  822. #define _GROUP_INCLUDE_ALL_PREVIOUS
  823. #endif
  824. #undef _GROUP_MAKE_TAG
  825. #undef _gchain
  826. #undef _GROUP_SET_PLAYER
  827. #undef gforeign
  828. #undef gglobal
  829. #undef gpublic