iterators.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. /**--------------------------------------------------------------------------**\
  2. ===========================
  3. foreach efficient looping
  4. ===========================
  5. Description:
  6. Provides efficient looping through sparse data sets, such as connected
  7. players. Significantly improved from the original version to be a generic
  8. loop system, rather then purely a player loop system. When used for
  9. players this has constant time O(n) for number of connected players (n),
  10. unlike standard player loops which are O(MAX_PLAYERS), regardless of the
  11. actual number of connected players. Even when n is MAX_PLAYERS this is
  12. still faster.
  13. For extensive documentation on writing and using iterators, see this topic:
  14. http://forum.sa-mp.com/showthread.php?t=481877
  15. Legal:
  16. Version: MPL 1.1
  17. The contents of this file are subject to the Mozilla Public License Version
  18. 1.1 (the "License"); you may not use this file except in compliance with
  19. the License. You may obtain a copy of the License at
  20. [url]http://www.mozilla.org/MPL/[/url]
  21. Software distributed under the License is distributed on an "AS IS" basis,
  22. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  23. for the specific language governing rights and limitations under the
  24. License.
  25. The Original Code is the YSI foreach include.
  26. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  27. Portions created by the Initial Developer are Copyright (C) 2011
  28. the Initial Developer. All Rights Reserved.
  29. Contributors:
  30. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  31. Thanks:
  32. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  33. ZeeX - Very productive conversations.
  34. koolk - IsPlayerinAreaEx code.
  35. TheAlpha - Danish translation.
  36. breadfish - German translation.
  37. Fireburn - Dutch translation.
  38. yom - French translation.
  39. 50p - Polish translation.
  40. Zamaroht - Spanish translation.
  41. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  42. for me to strive to better.
  43. Pixels^ - Running XScripters where the idea was born.
  44. Matite - Pestering me to release it and using it.
  45. Very special thanks to:
  46. Thiadmer - PAWN, whose limits continue to amaze me!
  47. Kye/Kalcor - SA:MP.
  48. SA:MP Team past, present and future - SA:MP.
  49. Version:
  50. 0.4
  51. Changelog:
  52. 29/03/15:
  53. More testing.
  54. Repaired special iterators.
  55. 28/03/15:
  56. Breaking change: "Iter_Add" returns value added, not true/false.
  57. Breaking change: Special iterators take "cellmin", not "-1".
  58. Wrote many tests.
  59. Split in to multiple files.
  60. Added multi-iterators.
  61. Officially deprecated "foreach (Player, i)".
  62. 26/03/15:
  63. Re-added reverse iterators.
  64. Added support for extra spaces in "foreach".
  65. 26/12/13:
  66. Added sections.
  67. 17/10/12:
  68. Fixed a bug that was here but not in "foreach.inc".
  69. 04/10/12:
  70. Added a tiny tweak to detect tag-returning iterator functions.
  71. Added Iter_InternalSize.
  72. 13/01/12:
  73. Fixed the count thanks to AndreT.
  74. 05/01/12:
  75. Fixed multi-dimensional iterators.
  76. Fixed "FOREACH_NO_BOTS".
  77. Made "Iterator:" support multi-dimensional arrays.
  78. 24/12/11:
  79. Added _YSI_SPECIAL_DEBUG support.
  80. Added fix for function iterators.
  81. Ported back to YSI.
  82. Changed to use internal YSI "__" natives.
  83. Fixed calls order by using ALS.
  84. 31/10/11:
  85. Changed the underlying loop code to be slightly faster.
  86. Added support for Iter_SafeRemove, prompting refactoring.
  87. 17/09/11:
  88. Fixed arrays under the new syntax.
  89. 28/04/11:
  90. Moved iterator identifiers to end of variables.
  91. Rewrote "foreach" to accept two syntaxes for "foreach (new i : Iter)".
  92. 16/08/10:
  93. Removed all the "2" versions of the functions.
  94. 14/08/10:
  95. Added Iter_Clear to reset an array.
  96. 06/08/10:
  97. Added special array declaration format.
  98. 18/12/09:
  99. Added Iter_Func2 functions for multi-dimensional iterators.
  100. Renamed foreact et al as keywords in the documentation.
  101. Changed licensing from GPL to MPL.
  102. 02/09/09:
  103. Fixed (again) for 0.3.
  104. Added free slot finding.
  105. 21/08/09:
  106. Updated to include random functions.
  107. Made entirely stand alone.
  108. Ported to 0.3 (separate version).
  109. Added automatic callback hook code.
  110. Removed debug information from stand alone version.
  111. 06/01/08:
  112. Added debug information.
  113. 09/10/07:
  114. Moved to system.
  115. 16/09/07:
  116. Added list sorting.
  117. Made this part of Y SeRver Includes, not Y Sever Includes.
  118. Made list sorting optional.
  119. Fixed version number.
  120. 08/09/07:
  121. First version.
  122. Functions:
  123. Public:
  124. OnPlayerDisconnect - Called when a player leaves to remove them.
  125. OnPlayerConnect - Called when a player connects to add them.
  126. Core:
  127. -
  128. Stock:
  129. Iter_ShowArray - Displays the contents of the array.
  130. Iter_AddInternal - Add a value to an iterator.
  131. Iter_RemoveInternal - Remove a value from an iterator.
  132. Iter_RandomInternal - Get a random item from an iterator.
  133. Iter_FreeInternal - Gets the first free slot in the iterator.
  134. Iter_InitInternal - Initialises a multi-dimensional iterator.
  135. Static:
  136. -
  137. Inline:
  138. Iter_Create - Create a new iterator value set.
  139. Iter_Add - Wraps Iter_AddInternal.
  140. Iter_Remove - Wraps Iter_RemoveInternal.
  141. Iter_Random - Wraps Iter_RandomInternal.
  142. Iter_Count - Gets the number of items in an iterator.
  143. Iter_Debug - Wraps around Iter_ShowArray.
  144. Iter_Free - Wraps around Iter_FreeInternal.
  145. Iter_Create2 - Create a new iterator array value set.
  146. Iter_Add2 - Wraps Iter_AddInternal for arrays.
  147. Iter_Remove2 - Wraps Iter_RemoveInternal for arrays.
  148. Iter_Random2 - Wraps Iter_RandomInternal for arrays.
  149. Iter_Count2 - Gets the number of items in an iterator array.
  150. Iter_Debug2 - Wraps around Iter_ShowArray for arrays.
  151. Iter_Free2 - Wraps around Iter_FreeInternal for arrays.
  152. API:
  153. -
  154. Callbacks:
  155. -
  156. Hooks:
  157. Iter_OnPlayerConnect - Hook for the OnPlayerConnect callback.
  158. Iter_OnPlayerDisconnect - Hook for the OnPlayerDisconnect callback.
  159. Iter_OnGameModeInit - Only exists to make the code compile correctly...
  160. Definitions:
  161. -
  162. Enums:
  163. -
  164. Macros:
  165. -
  166. Keywords:
  167. foreach - Command to loop an iterator.
  168. foreachex - Like foreach but without a new variable.
  169. foreach2 - Command to loop through an iterator array.
  170. foreachex - Like foreach2 but without a new variable.
  171. Tags:
  172. Iterator - Declare an iterator.
  173. Variables:
  174. Global:
  175. -
  176. Static:
  177. YSI_g_OPC - Records wether Iter_OnPlayerConnect exists for speed.
  178. YSI_g_OPDC - Records wether Iter_OnPlayerDisconnect exists for speed.
  179. Commands:
  180. -
  181. Compile options:
  182. YSI_ITTER_NO_SORT - Removed.
  183. FOREACH_NO_BOTS - Remove the bot iterators for smaller code.
  184. FOREACH_NO_PLAYERS - Remove all default code for player itteration.
  185. Operators:
  186. -
  187. Iterators:
  188. Player - List of all players connected.
  189. Bot - List of all bots (npcs) connected.
  190. NPC - Alias of Bot.
  191. Character - All players and bots.
  192. \**--------------------------------------------------------------------------**/
  193. /*
  194. 88
  195. 88 ,d ,d
  196. 88 88 88
  197. 88 MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYYba, MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYba,
  198. 88 88 a8P_____88 88P' "Y8 "" `Y8 88 a8" "8a 88P' "Y8 I8[ ""
  199. 88 88 8PP""""""" 88 ,adPPPPP88 88 8b d8 88 `"Y8ba,
  200. 88 88, "8b, ,aa 88 88, ,88 88, "8a, ,a8" 88 aa ]8I
  201. 88 "Y888 `"Ybbd8"' 88 `"8bbdP"Y8 "Y888 `"YbbdP"' 88 `"YbbdP"'
  202. */
  203. /**--------------------------------------------------------------------------**\
  204. Create the internal iterators.
  205. \**--------------------------------------------------------------------------**/
  206. #if _FOREACH_PLAYERS
  207. new
  208. Iterator:Player<MAX_PLAYERS>;
  209. #endif
  210. #if _FOREACH_BOTS
  211. new
  212. Iterator:Bot<MAX_PLAYERS>,
  213. Iterator:Character<MAX_PLAYERS>;
  214. #define Iter_Single@NPC Iter_Single@Bot
  215. #define Iterator@NPC Iterator@Bot
  216. #endif
  217. #if _FOREACH_ACTORS
  218. new
  219. #if _FOREACH_LOCALS
  220. Iterator:LocalActor<MAX_ACTORS>,
  221. #endif
  222. Iterator:Actor<MAX_ACTORS>;
  223. #endif
  224. #if _FOREACH_VEHICLES
  225. new
  226. #if _FOREACH_LOCALS
  227. Iterator:LocalVehicle<MAX_VEHICLES>,
  228. #endif
  229. Iterator:Vehicle<MAX_VEHICLES>;
  230. #endif
  231. stock iterfunc Range(cur, min, max, step = 1)
  232. {
  233. if (cur == cellmin) cur = min;
  234. else cur += step;
  235. return (min <= cur < max || max < cur <= min) ? cur : cellmin;
  236. }
  237. #define iterstart@Range cellmin
  238. stock iterfunc Powers(&iterstate, cur, base)
  239. {
  240. // Returns all the powers of the given number that can be stored in a PAWN
  241. // cell.
  242. //
  243. // foreach (new i : Powers(3))
  244. // {
  245. // // 3^0, 3^1, 3^2, 3^3, etc...
  246. // }
  247. //
  248. if (cur)
  249. {
  250. return
  251. iterstate = base * cur,
  252. _:(iterstate > cur) * iterstate;
  253. }
  254. return 1;
  255. }
  256. #define iterstart@Powers iterstate(0, 0)
  257. stock iterfunc Fib(&iterstate, cur)
  258. {
  259. // Returns every number in the Fibaonacci sequence that can be stored in a
  260. // PAWN cell.
  261. //
  262. // foreach (new i : Fib())
  263. // {
  264. // }
  265. //
  266. switch (cur)
  267. {
  268. case -1:
  269. return 0;
  270. case 1836311903:
  271. // End point (statically calculated largest Fibaonacci number that can
  272. // be stored in a signed 32-bit integer. Does make this not totally
  273. // portable, because it can't be used in the 64-bit version quickly.
  274. return -1;
  275. }
  276. // Based on the "+--" swap method (like "^^^"), but without the last one.
  277. return (iterstate = iterstate + cur) - cur;
  278. }
  279. #define iterstart@Fib iterstate(-1, 1)
  280. stock iterfunc Random(&iterstate, cur, count, min = cellmax, max = 0)
  281. {
  282. // Return a given count of random numbers:
  283. //
  284. // foreach (new i : Random(5))
  285. // {
  286. // // 5 random numbers.
  287. // }
  288. //
  289. // foreach (new i : Random(12, 10))
  290. // {
  291. // // 12 random numbers between 0 and 10 (0 to 9 inclusive).
  292. // }
  293. //
  294. // foreach (new i : Random(100, -10, 10))
  295. // {
  296. // // 100 random numbers between -10 and 10 (-10 to 9 inclusive).
  297. // }
  298. //
  299. // Note that this function has internal state, so you cannot call this in a
  300. // nested manner. This will probably fail:
  301. //
  302. // foreach (new i : Random(10, 70))
  303. // {
  304. // foreach (new j : Random(10, 80))
  305. // {
  306. // // Will NOT get 100 randoms 0 to 80, plus 10 randoms 0 to 70.
  307. // }
  308. // }
  309. //
  310. if (cur == cellmin)
  311. {
  312. iterstate = 0;
  313. }
  314. if (++iterstate > count)
  315. {
  316. return cellmin;
  317. }
  318. if (min >= max)
  319. {
  320. return random(min);
  321. }
  322. else
  323. {
  324. return random(max - min) + min;
  325. }
  326. }
  327. #define iterstart@Random iterstate(cellmin, 0)
  328. stock iterfunc Null(cur, arr[], size = sizeof (arr))
  329. {
  330. // Loop over all the indexes of this array that are zero.
  331. //
  332. // new array[] = { ... };
  333. // foreach (new i : Null(array))
  334. // {
  335. // }
  336. //
  337. while (++cur < size)
  338. {
  339. if (!arr[cur])
  340. {
  341. return cur;
  342. }
  343. }
  344. return -1;
  345. }
  346. #define iterstart@Null (-1)
  347. stock iterfunc NonNull(cur, arr[], size = sizeof (arr))
  348. {
  349. // Loop over all the indexes of this array that are not zero.
  350. //
  351. // new array[] = { ... };
  352. // foreach (new i : NonNull(array))
  353. // {
  354. // }
  355. //
  356. while (++cur < size)
  357. {
  358. if (arr[cur])
  359. {
  360. return cur;
  361. }
  362. }
  363. return -1;
  364. }
  365. #define iterstart@NonNull (-1)
  366. stock iterfunc Until(cur, val, arr[], size = sizeof (arr))
  367. {
  368. // Loop over all the indexes of this array until one equals the given value:
  369. //
  370. // new array[] = { ... };
  371. // foreach (new i : Until(5, array))
  372. // {
  373. // }
  374. //
  375. return (++cur >= size || arr[cur] == val) ? -1 : cur;
  376. }
  377. #define iterstart@Until (-1)
  378. stock iterfunc Filter(cur, val, arr[], size = sizeof (arr))
  379. {
  380. while (++cur < size)
  381. {
  382. if (arr[cur] == val)
  383. {
  384. return cur;
  385. }
  386. }
  387. return -1;
  388. }
  389. #define iterstart@Filter (-1)
  390. #define Iter_Func@None(%0,%1) _ITER<None>(%1,%0)
  391. #define iterstart@None (-1)
  392. #define Iter_None_InternalA(%0,%1,%9) Iter_None_Internal(%1,F@s(%1)-1,%9)
  393. #define Iter_None_InternalB(%0,%2,%1,%9) Iter_None_Internal(%1,F@s(%1)-F@s(%0),%9)
  394. stock Iter_None_Internal(array[], size, value)
  395. {
  396. // Loop over all values NOT in any iterator. Similar to repeatedly calling
  397. // "Iter_Free", though that will return the same value twice if called twice
  398. // in a row. Instead, this function will loop through the missing ones.
  399. while (++value < size)
  400. {
  401. if (array[value] <= value)
  402. {
  403. return value;
  404. }
  405. }
  406. return -1;
  407. }
  408. #define Iter_Func@All(%0,%1) _ITER<All>(%1,%0)
  409. #define iterstart@All (-1)
  410. #define Iter_All_InternalA(%0,%1,%9) Iter_All_Internal(%1,F@s(%1)-1,%9)
  411. #define Iter_All_InternalB(%0,%2,%1,%9) Iter_All_Internal(%1,F@s(%1)-F@s(%0),%9)
  412. stock Iter_All_Internal(array[], size, value)
  413. {
  414. // Loop over all values in any iterator. This is different to looping over
  415. // the iterator normally for multi-dimensional iterators, since it will
  416. // return all values in ANY iterator in their numerical order. For single-
  417. // dimensional iterators it is exactly the same, just a little slower.
  418. while (++value < size)
  419. {
  420. if (array[value] > value)
  421. {
  422. return value;
  423. }
  424. }
  425. return -1;
  426. }
  427. /*
  428. 88 88 88
  429. 88 88 88
  430. 88 88 88
  431. 88aaaaaaaa88 ,adPPYba, ,adPPYba, 88 ,d8 ,adPPYba,
  432. 88""""""""88 a8" "8a a8" "8a 88 ,a8" I8[ ""
  433. 88 88 8b d8 8b d8 8888[ `"Y8ba,
  434. 88 88 "8a, ,a8" "8a, ,a8" 88`"Yba, aa ]8I
  435. 88 88 `"YbbdP"' `"YbbdP"' 88 `Y8a `"YbbdP"'
  436. */
  437. /**--------------------------------------------------------------------------**\
  438. <summary>Iter_OnScriptInit</summary>
  439. <returns>
  440. -
  441. </returns>
  442. <remarks>
  443. Sets up all existing iterators. Does nothing for "XXLocal" ones, since they
  444. are by definition empty when a script starts.
  445. </remarks>
  446. \**--------------------------------------------------------------------------**/
  447. #if _FOREACH_CHARACTERS || _FOREACH_VEHICLES || _FOREACH_ACTORS
  448. hook OnScriptInit()
  449. {
  450. #if _FOREACH_VEHICLES
  451. Iter_Clear(Vehicle);
  452. for (new i = 1; i <= MAX_VEHICLES; ++i)
  453. {
  454. if (GetVehicleModel(i))
  455. {
  456. Iter_Add(Vehicle, i);
  457. }
  458. }
  459. #endif
  460. #if _FOREACH_ACTORS
  461. Iter_Clear(Actor);
  462. for (new i = 0; i != MAX_ACTORS; ++i)
  463. {
  464. if (IsValidActor(i))
  465. {
  466. Iter_Add(Actor, i);
  467. }
  468. }
  469. #endif
  470. #if _FOREACH_CHARACTERS
  471. #if _FOREACH_BOTS
  472. Iter_Clear(Bot);
  473. Iter_Clear(Character);
  474. #endif
  475. #if _FOREACH_PLAYERS
  476. Iter_Clear(Player);
  477. #endif
  478. for (new i = 0; i != MAX_PLAYERS; ++i)
  479. {
  480. if (IsPlayerConnected(i))
  481. {
  482. #if _FOREACH_BOTS
  483. Iter_Add(Character, i);
  484. if (IsPlayerNPC(i))
  485. {
  486. Iter_Add(Bot, i);
  487. }
  488. else
  489. #endif
  490. {
  491. #if _FOREACH_PLAYERS
  492. Iter_Add(Player, i);
  493. #endif
  494. }
  495. }
  496. }
  497. #endif
  498. return 1;
  499. }
  500. #endif
  501. /*
  502. 88888888ba 88
  503. 88 "8b 88
  504. 88 ,8P 88
  505. 88aaaaaa8P' 88 ,adPPYYba, 8b d8 ,adPPYba, 8b,dPPYba, ,adPPYba,
  506. 88""""""' 88 "" `Y8 `8b d8' a8P_____88 88P' "Y8 I8[ ""
  507. 88 88 ,adPPPPP88 `8b d8' 8PP""""""" 88 `"Y8ba,
  508. 88 88 88, ,88 `8b,d8' "8b, ,aa 88 aa ]8I
  509. 88 88 `"8bbdP"Y8 Y88' `"Ybbd8"' 88 `"YbbdP"'
  510. d8'
  511. d8'
  512. */
  513. /**--------------------------------------------------------------------------**\
  514. <summary>Iter_OnPlayerConnect</summary>
  515. <param name="playerid">Player who joined.</param>
  516. <returns>
  517. -
  518. </returns>
  519. <remarks>
  520. Adds a player to the loop data. Now sorts the list too. Note that I found
  521. the most bizzare bug ever (I *think* it may be a compiler but, but it
  522. requires further investigation), basically it seems that multiple variables
  523. were being treated as the same variable (namely @YSII_EgotS and
  524. @YSII_CgharacterS were the same and @YSII_EgotC and @YSII_CgharacterC were the
  525. same). Adding print statements which reference these variables seem to fix
  526. the problem, and I've tried to make sure that the values will never actually
  527. get printed.
  528. </remarks>
  529. \**--------------------------------------------------------------------------**/
  530. #if _FOREACH_CHARACTERS
  531. hook OnPlayerConnect(playerid)
  532. {
  533. P:1("Iter_OnPlayerConnect called: %d, %d", playerid, IsPlayerNPC(playerid));
  534. #if _FOREACH_BOTS
  535. Iter_Add(Character, playerid);
  536. if (IsPlayerNPC(playerid))
  537. {
  538. Iter_Add(Bot, playerid);
  539. }
  540. else
  541. #endif
  542. {
  543. #if _FOREACH_PLAYERS
  544. Iter_Add(Player, playerid);
  545. #endif
  546. }
  547. P:2("Iter_OnPlayerConnect end");
  548. return 1;
  549. }
  550. /**----------------------------------------------------------------------**\
  551. <summary>Iter_OnPlayerDisconnect</summary>
  552. <param name="playerid">Player who left.</param>
  553. <returns>
  554. -
  555. </returns>
  556. <remarks>
  557. Removes a player from the loop data. No longer uses "hook" to ENSURE
  558. that this is always last. Previously I think that the order of
  559. evaluation in y_hooks meant that this got called before the user
  560. "OnPlayerDisconnect".
  561. </remarks>
  562. \**----------------------------------------------------------------------**/
  563. hook OnPlayerDisconnect(playerid, reason)
  564. {
  565. SetTimerEx("Iter_OPDCInternal", 0, false, "i", playerid);
  566. return 1;
  567. }
  568. /**----------------------------------------------------------------------**\
  569. <summary>Iter_OPDCInternal</summary>
  570. <param name="playerid">Player who left.</param>
  571. <returns>
  572. -
  573. </returns>
  574. <remarks>
  575. Called AFTER "OnPlayerDisconnect" so that using "Kick" inside a
  576. "foreach" loop doesn't crash the server due to an OOB error.
  577. </remarks>
  578. \**----------------------------------------------------------------------**/
  579. public Iter_OPDCInternal(playerid)
  580. {
  581. if (IsPlayerConnected(playerid))
  582. {
  583. return;
  584. }
  585. #if _FOREACH_BOTS
  586. Iter_Remove(Character, playerid);
  587. if (IsPlayerNPC(playerid))
  588. {
  589. Iter_Remove(Bot, playerid);
  590. }
  591. else
  592. #endif
  593. {
  594. #if _FOREACH_PLAYERS
  595. Iter_Remove(Player, playerid);
  596. #endif
  597. }
  598. }
  599. #endif
  600. /*
  601. db
  602. d88b ,d
  603. d8'`8b 88
  604. d8' `8b ,adPPYba, MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYba,
  605. d8YaaaaY8b a8" "" 88 a8" "8a 88P' "Y8 I8[ ""
  606. d8""""""""8b 8b 88 8b d8 88 `"Y8ba,
  607. d8' `8b "8a, ,aa 88, "8a, ,a8" 88 aa ]8I
  608. d8' `8b `"Ybbd8"' "Y888 `"YbbdP"' 88 `"YbbdP"'
  609. */
  610. #if _FOREACH_ACTORS
  611. remotefunc void:Iter_ActorDo(bool:add, actorid)
  612. {
  613. // Because there may be multiple scripts running, we need to tell all of
  614. // them when an actor is created or destroyed.
  615. if (add)
  616. Iter_Add(Actor, actorid);
  617. else
  618. Iter_Remove(Actor, actorid);
  619. }
  620. stock Iter_CreateActor(modelid, Float:X, Float:Y, Float:Z, Float:Rotation)
  621. {
  622. new
  623. ret = CreateActor(modelid, X, Y, Z, Rotation);
  624. broadcastfunc Iter_ActorDo(true, ret);
  625. #if _FOREACH_LOCALS
  626. Iter_Add(LocalActor, ret);
  627. #endif
  628. return ret;
  629. }
  630. #if defined _ALS_CreateActor
  631. #undef CreateActor
  632. #else
  633. #define _ALS_CreateActor
  634. #endif
  635. #define CreateActor Iter_CreateActor
  636. stock Iter_DestroyActor(actorid)
  637. {
  638. broadcastfunc Iter_ActorDo(false, actorid);
  639. #if _FOREACH_LOCALS
  640. Iter_Remove(LocalActor, actorid);
  641. #endif
  642. return DestroyActor(actorid);
  643. }
  644. #if defined _ALS_DestroyActor
  645. #undef DestroyActor
  646. #else
  647. #define _ALS_DestroyActor
  648. #endif
  649. #define DestroyActor Iter_DestroyActor
  650. #endif
  651. /*
  652. 8b d8 88 88 88
  653. `8b d8' 88 "" 88
  654. `8b d8' 88 88
  655. `8b d8' ,adPPYba, 88,dPPYba, 88 ,adPPYba, 88 ,adPPYba, ,adPPYba,
  656. `8b d8' a8P_____88 88P' "8a 88 a8" "" 88 a8P_____88 I8[ ""
  657. `8b d8' 8PP""""""" 88 88 88 8b 88 8PP""""""" `"Y8ba,
  658. `888' "8b, ,aa 88 88 88 "8a, ,aa 88 "8b, ,aa aa ]8I
  659. `8' `"Ybbd8"' 88 88 88 `"Ybbd8"' 88 `"Ybbd8"' `"YbbdP"'
  660. */
  661. #if _FOREACH_VEHICLES
  662. remotefunc void:Iter_VehicleDo(bool:add, vehicleid)
  663. {
  664. // Because there may be multiple scripts running, we need to tell all of
  665. // them when a vehicle is created or destroyed.
  666. if (add)
  667. Iter_Add(Vehicle, vehicleid);
  668. else
  669. Iter_Remove(Vehicle, vehicleid);
  670. }
  671. stock Iter_CreateVehicle(modelid, Float:x, Float:y, Float:z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
  672. {
  673. #if _FOREACH_ACTORS
  674. new
  675. ret = CreateVehicle(modelid, x, y, z, angle, color1, color2, respawn_delay, addsiren);
  676. #else
  677. #pragma unused addsiren
  678. new
  679. ret = CreateVehicle(modelid, x, y, z, angle, color1, color2, respawn_delay);
  680. #endif
  681. broadcastfunc Iter_VehicleDo(true, ret);
  682. #if _FOREACH_LOCALS
  683. Iter_Add(LocalVehicle, ret);
  684. #endif
  685. return ret;
  686. }
  687. #if defined _ALS_CreateVehicle
  688. #undef CreateVehicle
  689. #else
  690. #define _ALS_CreateVehicle
  691. #endif
  692. #define CreateVehicle Iter_CreateVehicle
  693. stock Iter_AddStaticVehicle(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2)
  694. {
  695. new
  696. ret = AddStaticVehicle(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2);
  697. broadcastfunc Iter_VehicleDo(true, ret);
  698. #if _FOREACH_LOCALS
  699. Iter_Add(LocalVehicle, ret);
  700. #endif
  701. return ret;
  702. }
  703. #if defined _ALS_AddStaticVehicle
  704. #undef AddStaticVehicle
  705. #else
  706. #define _ALS_AddStaticVehicle
  707. #endif
  708. #define AddStaticVehicle Iter_AddStaticVehicle
  709. stock Iter_AddStaticVehicleEx(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
  710. {
  711. #if _FOREACH_ACTORS
  712. new
  713. ret = AddStaticVehicleEx(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2, respawn_delay, addsiren);
  714. #else
  715. #pragma unused addsiren
  716. new
  717. ret = AddStaticVehicleEx(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2, respawn_delay);
  718. #endif
  719. broadcastfunc Iter_VehicleDo(true, ret);
  720. #if _FOREACH_LOCALS
  721. Iter_Add(LocalVehicle, ret);
  722. #endif
  723. return ret;
  724. }
  725. #if defined _ALS_AddStaticVehicleEx
  726. #undef AddStaticVehicleEx
  727. #else
  728. #define _ALS_AddStaticVehicleEx
  729. #endif
  730. #define AddStaticVehicleEx Iter_AddStaticVehicleEx
  731. stock Iter_DestroyVehicle(vehicleid)
  732. {
  733. broadcastfunc Iter_VehicleDo(false, vehicleid);
  734. #if _FOREACH_LOCALS
  735. Iter_Remove(LocalVehicle, vehicleid);
  736. #endif
  737. return DestroyVehicle(vehicleid);
  738. }
  739. #if defined _ALS_DestroyVehicle
  740. #undef DestroyVehicle
  741. #else
  742. #define _ALS_DestroyVehicle
  743. #endif
  744. #define DestroyVehicle Iter_DestroyVehicle
  745. #endif