iterators.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  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. 88
  66. 88 ,d ,d
  67. 88 88 88
  68. 88 MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYYba, MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYba,
  69. 88 88 a8P_____88 88P' "Y8 "" `Y8 88 a8" "8a 88P' "Y8 I8[ ""
  70. 88 88 8PP""""""" 88 ,adPPPPP88 88 8b d8 88 `"Y8ba,
  71. 88 88, "8b, ,aa 88 88, ,88 88, "8a, ,a8" 88 aa ]8I
  72. 88 "Y888 `"Ybbd8"' 88 `"8bbdP"Y8 "Y888 `"YbbdP"' 88 `"YbbdP"'
  73. */
  74. /*-------------------------------------------------------------------------*//**
  75. * Create the internal iterators.
  76. *//*------------------------------------------------------------------------**/
  77. #if _FOREACH_PLAYERS
  78. new
  79. Iterator:Player<MAX_PLAYERS>;
  80. #endif
  81. #if _FOREACH_BOTS
  82. new
  83. Iterator:Bot<MAX_PLAYERS>,
  84. Iterator:Character<MAX_PLAYERS>;
  85. #define Iter_Single@NPC Iter_Single@Bot
  86. #define Iterator@NPC Iterator@Bot
  87. #endif
  88. #if _FOREACH_ACTORS
  89. new
  90. #if _FOREACH_LOCALS
  91. Iterator:LocalActor<MAX_ACTORS>,
  92. #endif
  93. Iterator:Actor<MAX_ACTORS>;
  94. #endif
  95. #if _FOREACH_VEHICLES
  96. new
  97. #if _FOREACH_LOCALS
  98. Iterator:LocalVehicle<MAX_VEHICLES>,
  99. #endif
  100. Iterator:Vehicle<MAX_VEHICLES>;
  101. #endif
  102. iterfunc stock Range[cellmin](cur, min, max, step = 1)
  103. {
  104. if (cur == cellmin) cur = min;
  105. else cur += step;
  106. return (min <= cur < max || max < cur <= min) ? cur : cellmin;
  107. }
  108. iterfunc stock Powers(&iterstate, cur, base)
  109. {
  110. // Returns all the powers of the given number that can be stored in a PAWN
  111. // cell.
  112. //
  113. // foreach (new i : Powers(3))
  114. // {
  115. // // 3^0, 3^1, 3^2, 3^3, etc...
  116. // }
  117. //
  118. if (cur)
  119. {
  120. return
  121. iterstate = base * cur,
  122. _:(iterstate > cur) * iterstate;
  123. }
  124. return 1;
  125. }
  126. #define iterstart@Powers iterstate(0, 0)
  127. iterfunc stock Fib(&iterstate, cur)
  128. {
  129. // Returns every number in the Fibaonacci sequence that can be stored in a
  130. // PAWN cell.
  131. //
  132. // foreach (new i : Fib())
  133. // {
  134. // }
  135. //
  136. switch (cur)
  137. {
  138. case -1:
  139. return 0;
  140. case 1836311903:
  141. // End point (statically calculated largest Fibaonacci number that can
  142. // be stored in a signed 32-bit integer. Does make this not totally
  143. // portable, because it can't be used in the 64-bit version quickly.
  144. return -1;
  145. }
  146. // Based on the "+--" swap method (like "^^^"), but without the last one.
  147. return (iterstate = iterstate + cur) - cur;
  148. }
  149. #define iterstart@Fib iterstate(-1, 1)
  150. iterfunc stock Random(&iterstate, cur, count, min = cellmax, max = 0)
  151. {
  152. // Return a given count of random numbers:
  153. //
  154. // foreach (new i : Random(5))
  155. // {
  156. // // 5 random numbers.
  157. // }
  158. //
  159. // foreach (new i : Random(12, 10))
  160. // {
  161. // // 12 random numbers between 0 and 10 (0 to 9 inclusive).
  162. // }
  163. //
  164. // foreach (new i : Random(100, -10, 10))
  165. // {
  166. // // 100 random numbers between -10 and 10 (-10 to 9 inclusive).
  167. // }
  168. //
  169. // Note that this function has internal state, so you cannot call this in a
  170. // nested manner. This will probably fail:
  171. //
  172. // foreach (new i : Random(10, 70))
  173. // {
  174. // foreach (new j : Random(10, 80))
  175. // {
  176. // // Will NOT get 100 randoms 0 to 80, plus 10 randoms 0 to 70.
  177. // }
  178. // }
  179. //
  180. if (cur == cellmin)
  181. {
  182. iterstate = 0;
  183. }
  184. if (++iterstate > count)
  185. {
  186. return cellmin;
  187. }
  188. if (min >= max)
  189. {
  190. return random(min);
  191. }
  192. else
  193. {
  194. return random(max - min) + min;
  195. }
  196. }
  197. #define iterstart@Random iterstate(cellmin, 0)
  198. iterfunc stock Null(cur, arr[], size = sizeof (arr))
  199. {
  200. // Loop over all the indexes of this array that are zero.
  201. //
  202. // new array[] = { ... };
  203. // foreach (new i : Null(array))
  204. // {
  205. // }
  206. //
  207. while (++cur < size)
  208. {
  209. if (!arr[cur])
  210. {
  211. return cur;
  212. }
  213. }
  214. return -1;
  215. }
  216. iterfunc stock NonNull(cur, arr[], size = sizeof (arr))
  217. {
  218. // Loop over all the indexes of this array that are not zero.
  219. //
  220. // new array[] = { ... };
  221. // foreach (new i : NonNull(array))
  222. // {
  223. // }
  224. //
  225. while (++cur < size)
  226. {
  227. if (arr[cur])
  228. {
  229. return cur;
  230. }
  231. }
  232. return -1;
  233. }
  234. iterfunc stock Until(cur, val, arr[], size = sizeof (arr))
  235. {
  236. // Loop over all the indexes of this array until one equals the given value:
  237. //
  238. // new array[] = { ... };
  239. // foreach (new i : Until(5, array))
  240. // {
  241. // }
  242. //
  243. return (++cur >= size || arr[cur] == val) ? -1 : cur;
  244. }
  245. iterfunc stock Filter(cur, val, arr[], size = sizeof (arr))
  246. {
  247. while (++cur < size)
  248. {
  249. if (arr[cur] == val)
  250. {
  251. return cur;
  252. }
  253. }
  254. return -1;
  255. }
  256. #define Iter_Func@None(%0,%1) _ITER<None>(%1,%0)
  257. #define Iterator@None iterstart(-1)
  258. #define Iter_None_InternalA(%0,%1,%9) Iter_None_Internal(%1,F@s(%1)-1,%9)
  259. #define Iter_None_InternalB(%0,%2,%1,%9) Iter_None_Internal(%1,F@s(%1)-F@s(%0),%9)
  260. stock Iter_None_Internal(array[], size, value)
  261. {
  262. // Loop over all values NOT in any iterator. Similar to repeatedly calling
  263. // "Iter_Free", though that will return the same value twice if called twice
  264. // in a row. Instead, this function will loop through the missing ones.
  265. while (++value < size)
  266. {
  267. if (array[value] <= value)
  268. {
  269. return value;
  270. }
  271. }
  272. return -1;
  273. }
  274. #define Iter_Func@All(%0,%1) _ITER<All>(%1,%0)
  275. #define Iterator@All iterstart(-1)
  276. #define Iter_All_InternalA(%0,%1,%9) Iter_All_Internal(%1,F@s(%1)-1,%9)
  277. #define Iter_All_InternalB(%0,%2,%1,%9) Iter_All_Internal(%1,F@s(%1)-F@s(%0),%9)
  278. stock Iter_All_Internal(array[], size, value)
  279. {
  280. // Loop over all values in any iterator. This is different to looping over
  281. // the iterator normally for multi-dimensional iterators, since it will
  282. // return all values in ANY iterator in their numerical order. For single-
  283. // dimensional iterators it is exactly the same, just a little slower.
  284. while (++value < size)
  285. {
  286. if (array[value] > value)
  287. {
  288. return value;
  289. }
  290. }
  291. return -1;
  292. }
  293. /*
  294. 88 88 88
  295. 88 88 88
  296. 88 88 88
  297. 88aaaaaaaa88 ,adPPYba, ,adPPYba, 88 ,d8 ,adPPYba,
  298. 88""""""""88 a8" "8a a8" "8a 88 ,a8" I8[ ""
  299. 88 88 8b d8 8b d8 8888[ `"Y8ba,
  300. 88 88 "8a, ,a8" "8a, ,a8" 88`"Yba, aa ]8I
  301. 88 88 `"YbbdP"' `"YbbdP"' 88 `Y8a `"YbbdP"'
  302. */
  303. /*-------------------------------------------------------------------------*//**
  304. * <remarks>
  305. * Sets up all existing iterators. Does nothing for "XXLocal" ones, since they
  306. * are by definition empty when a script starts.
  307. * </remarks>
  308. *//*------------------------------------------------------------------------**/
  309. #if _FOREACH_CHARACTERS || _FOREACH_VEHICLES || _FOREACH_ACTORS
  310. hook OnScriptInit()
  311. {
  312. #if _FOREACH_VEHICLES
  313. Iter_Clear(Vehicle);
  314. for (new i = 1; i <= MAX_VEHICLES; ++i)
  315. {
  316. if (GetVehicleModel(i))
  317. {
  318. Iter_Add(Vehicle, i);
  319. }
  320. }
  321. #endif
  322. #if _FOREACH_ACTORS
  323. Iter_Clear(Actor);
  324. for (new i = 0; i != MAX_ACTORS; ++i)
  325. {
  326. if (IsValidActor(i))
  327. {
  328. Iter_Add(Actor, i);
  329. }
  330. }
  331. #endif
  332. #if _FOREACH_CHARACTERS
  333. #if _FOREACH_BOTS
  334. Iter_Clear(Bot);
  335. Iter_Clear(Character);
  336. #endif
  337. #if _FOREACH_PLAYERS
  338. Iter_Clear(Player);
  339. #endif
  340. for (new i = 0; i != MAX_PLAYERS; ++i)
  341. {
  342. if (IsPlayerConnected(i))
  343. {
  344. #if _FOREACH_BOTS
  345. Iter_Add(Character, i);
  346. if (IsPlayerNPC(i))
  347. {
  348. Iter_Add(Bot, i);
  349. }
  350. else
  351. #endif
  352. {
  353. #if _FOREACH_PLAYERS
  354. Iter_Add(Player, i);
  355. #endif
  356. }
  357. }
  358. }
  359. #endif
  360. return 1;
  361. }
  362. #endif
  363. /*
  364. 88888888ba 88
  365. 88 "8b 88
  366. 88 ,8P 88
  367. 88aaaaaa8P' 88 ,adPPYYba, 8b d8 ,adPPYba, 8b,dPPYba, ,adPPYba,
  368. 88""""""' 88 "" `Y8 `8b d8' a8P_____88 88P' "Y8 I8[ ""
  369. 88 88 ,adPPPPP88 `8b d8' 8PP""""""" 88 `"Y8ba,
  370. 88 88 88, ,88 `8b,d8' "8b, ,aa 88 aa ]8I
  371. 88 88 `"8bbdP"Y8 Y88' `"Ybbd8"' 88 `"YbbdP"'
  372. d8'
  373. d8'
  374. */
  375. /*-------------------------------------------------------------------------*//**
  376. * <param name="playerid">Player who joined.</param>
  377. * <remarks>
  378. * Adds a player to the loop data. Now sorts the list too. Note that I found
  379. * the most bizzare bug ever (I *think* it may be a compiler but, but it
  380. * requires further investigation), basically it seems that multiple variables
  381. * were being treated as the same variable (namely @YSII_EgotS and
  382. * @YSII_CgharacterS were the same and @YSII_EgotC and @YSII_CgharacterC were the
  383. * same). Adding print statements which reference these variables seem to fix
  384. * the problem, and I've tried to make sure that the values will never actually
  385. * get printed.
  386. * </remarks>
  387. *//*------------------------------------------------------------------------**/
  388. #if _FOREACH_CHARACTERS
  389. hook OnPlayerConnect(playerid)
  390. {
  391. P:1("Iter_OnPlayerConnect called: %d, %d", playerid, IsPlayerNPC(playerid));
  392. #if _FOREACH_BOTS
  393. Iter_Add(Character, playerid);
  394. if (IsPlayerNPC(playerid))
  395. {
  396. Iter_Add(Bot, playerid);
  397. }
  398. else
  399. #endif
  400. {
  401. #if _FOREACH_PLAYERS
  402. Iter_Add(Player, playerid);
  403. #endif
  404. }
  405. P:2("Iter_OnPlayerConnect end");
  406. return 1;
  407. }
  408. /*---------------------------------------------------------------------*//**
  409. *
  410. * <param name="playerid">Player who left.</param>
  411. * <remarks>
  412. * Removes a player from the loop data. No longer uses "hook" to ENSURE
  413. * that this is always last. Previously I think that the order of
  414. * evaluation in y_hooks meant that this got called before the user
  415. * "OnPlayerDisconnect".
  416. * </remarks>
  417. *//*--------------------------------------------------------------------**/
  418. hook OnPlayerDisconnect(playerid, reason)
  419. {
  420. SetTimerEx("Iter_OPDCInternal", 0, false, "i", playerid);
  421. return 1;
  422. }
  423. /*---------------------------------------------------------------------*//**
  424. *
  425. * <param name="playerid">Player who left.</param>
  426. * <remarks>
  427. * Called AFTER "OnPlayerDisconnect" so that using "Kick" inside a
  428. * "foreach" loop doesn't crash the server due to an OOB error.
  429. * </remarks>
  430. *//*--------------------------------------------------------------------**/
  431. public Iter_OPDCInternal(playerid)
  432. {
  433. if (IsPlayerConnected(playerid))
  434. {
  435. return;
  436. }
  437. #if _FOREACH_BOTS
  438. Iter_Remove(Character, playerid);
  439. if (IsPlayerNPC(playerid))
  440. {
  441. Iter_Remove(Bot, playerid);
  442. }
  443. else
  444. #endif
  445. {
  446. #if _FOREACH_PLAYERS
  447. Iter_Remove(Player, playerid);
  448. #endif
  449. }
  450. }
  451. #endif
  452. /*
  453. db
  454. d88b ,d
  455. d8'`8b 88
  456. d8' `8b ,adPPYba, MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYba,
  457. d8YaaaaY8b a8" "" 88 a8" "8a 88P' "Y8 I8[ ""
  458. d8""""""""8b 8b 88 8b d8 88 `"Y8ba,
  459. d8' `8b "8a, ,aa 88, "8a, ,a8" 88 aa ]8I
  460. d8' `8b `"Ybbd8"' "Y888 `"YbbdP"' 88 `"YbbdP"'
  461. */
  462. #if _FOREACH_ACTORS
  463. remotefunc void:Iter_ActorDo(bool:add, actorid)
  464. {
  465. // Because there may be multiple scripts running, we need to tell all of
  466. // them when an actor is created or destroyed.
  467. if (add)
  468. Iter_Add(Actor, actorid);
  469. else
  470. Iter_Remove(Actor, actorid);
  471. }
  472. stock Iter_CreateActor(modelid, Float:X, Float:Y, Float:Z, Float:Rotation)
  473. {
  474. new
  475. ret = CreateActor(modelid, X, Y, Z, Rotation);
  476. broadcastfunc Iter_ActorDo(true, ret);
  477. #if _FOREACH_LOCALS
  478. Iter_Add(LocalActor, ret);
  479. #endif
  480. return ret;
  481. }
  482. #if defined _ALS_CreateActor
  483. #undef CreateActor
  484. #else
  485. #define _ALS_CreateActor
  486. #endif
  487. #define CreateActor Iter_CreateActor
  488. stock Iter_DestroyActor(actorid)
  489. {
  490. broadcastfunc Iter_ActorDo(false, actorid);
  491. #if _FOREACH_LOCALS
  492. Iter_Remove(LocalActor, actorid);
  493. #endif
  494. return DestroyActor(actorid);
  495. }
  496. #if defined _ALS_DestroyActor
  497. #undef DestroyActor
  498. #else
  499. #define _ALS_DestroyActor
  500. #endif
  501. #define DestroyActor Iter_DestroyActor
  502. #endif
  503. /*
  504. 8b d8 88 88 88
  505. `8b d8' 88 "" 88
  506. `8b d8' 88 88
  507. `8b d8' ,adPPYba, 88,dPPYba, 88 ,adPPYba, 88 ,adPPYba, ,adPPYba,
  508. `8b d8' a8P_____88 88P' "8a 88 a8" "" 88 a8P_____88 I8[ ""
  509. `8b d8' 8PP""""""" 88 88 88 8b 88 8PP""""""" `"Y8ba,
  510. `888' "8b, ,aa 88 88 88 "8a, ,aa 88 "8b, ,aa aa ]8I
  511. `8' `"Ybbd8"' 88 88 88 `"Ybbd8"' 88 `"Ybbd8"' `"YbbdP"'
  512. */
  513. #if _FOREACH_VEHICLES
  514. remotefunc void:Iter_VehicleDo(bool:add, vehicleid)
  515. {
  516. // Because there may be multiple scripts running, we need to tell all of
  517. // them when a vehicle is created or destroyed.
  518. if (add)
  519. Iter_Add(Vehicle, vehicleid);
  520. else
  521. Iter_Remove(Vehicle, vehicleid);
  522. }
  523. stock Iter_CreateVehicle(modelid, Float:x, Float:y, Float:z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
  524. {
  525. #if _FOREACH_ACTORS
  526. new
  527. ret = CreateVehicle(modelid, x, y, z, angle, color1, color2, respawn_delay, addsiren);
  528. #else
  529. #pragma unused addsiren
  530. new
  531. ret = CreateVehicle(modelid, x, y, z, angle, color1, color2, respawn_delay);
  532. #endif
  533. broadcastfunc Iter_VehicleDo(true, ret);
  534. #if _FOREACH_LOCALS
  535. Iter_Add(LocalVehicle, ret);
  536. #endif
  537. return ret;
  538. }
  539. #if defined _ALS_CreateVehicle
  540. #undef CreateVehicle
  541. #else
  542. #define _ALS_CreateVehicle
  543. #endif
  544. #define CreateVehicle Iter_CreateVehicle
  545. stock Iter_AddStaticVehicle(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2)
  546. {
  547. new
  548. ret = AddStaticVehicle(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2);
  549. broadcastfunc Iter_VehicleDo(true, ret);
  550. #if _FOREACH_LOCALS
  551. Iter_Add(LocalVehicle, ret);
  552. #endif
  553. return ret;
  554. }
  555. #if defined _ALS_AddStaticVehicle
  556. #undef AddStaticVehicle
  557. #else
  558. #define _ALS_AddStaticVehicle
  559. #endif
  560. #define AddStaticVehicle Iter_AddStaticVehicle
  561. stock Iter_AddStaticVehicleEx(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
  562. {
  563. #if _FOREACH_ACTORS
  564. new
  565. ret = AddStaticVehicleEx(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2, respawn_delay, addsiren);
  566. #else
  567. #pragma unused addsiren
  568. new
  569. ret = AddStaticVehicleEx(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2, respawn_delay);
  570. #endif
  571. broadcastfunc Iter_VehicleDo(true, ret);
  572. #if _FOREACH_LOCALS
  573. Iter_Add(LocalVehicle, ret);
  574. #endif
  575. return ret;
  576. }
  577. #if defined _ALS_AddStaticVehicleEx
  578. #undef AddStaticVehicleEx
  579. #else
  580. #define _ALS_AddStaticVehicleEx
  581. #endif
  582. #define AddStaticVehicleEx Iter_AddStaticVehicleEx
  583. stock Iter_DestroyVehicle(vehicleid)
  584. {
  585. broadcastfunc Iter_VehicleDo(false, vehicleid);
  586. #if _FOREACH_LOCALS
  587. Iter_Remove(LocalVehicle, vehicleid);
  588. #endif
  589. return DestroyVehicle(vehicleid);
  590. }
  591. #if defined _ALS_DestroyVehicle
  592. #undef DestroyVehicle
  593. #else
  594. #define _ALS_DestroyVehicle
  595. #endif
  596. #define DestroyVehicle Iter_DestroyVehicle
  597. #endif