impl.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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. db 88888888ba 88 ,ad8888ba, 88
  66. d88b 88 "8b 88 d8"' `"8b 88
  67. d8'`8b 88 ,8P 88 d8' 88
  68. d8' `8b 88aaaaaa8P' 88 88 ,adPPYba, ,adPPYb,88 ,adPPYba,
  69. d8YaaaaY8b 88""""""' 88 88 a8" "8a a8" `Y88 a8P_____88
  70. d8""""""""8b 88 88 Y8, 8b d8 8b 88 8PP"""""""
  71. d8' `8b 88 88 Y8a. .a8P "8a, ,a8" "8a, ,d88 "8b, ,aa
  72. d8' `8b 88 88 `"Y8888Y"' `"YbbdP"' `"8bbdP"Y8 `"Ybbd8"'
  73. */
  74. /*-------------------------------------------------------------------------*//**
  75. * <param name="count">Number of items in the iterator.</param>
  76. * <param name="array">iterator data.</param>
  77. * <param name="start">Size of the iterator.</param>
  78. * <remarks>
  79. * Returns a random value from an iterator.
  80. * </remarks>
  81. *//*------------------------------------------------------------------------**/
  82. stock Iter_Random_Internal(count, array[], start)
  83. {
  84. if (count)
  85. {
  86. count = random(count);
  87. do
  88. {
  89. start = array[start];
  90. }
  91. while (count--);
  92. return start;
  93. }
  94. return INVALID_ITERATOR_SLOT;
  95. }
  96. /*-------------------------------------------------------------------------*//**
  97. * <param name="count">Number of items in the iterator.</param>
  98. * <param name="array">iterator data.</param>
  99. * <param name="start">Size of the iterator.</param>
  100. * <param name="slots">Number of multi-iterator values.</param>
  101. * <remarks>
  102. * Returns a random unused value from an iterator.
  103. * </remarks>
  104. *//*------------------------------------------------------------------------**/
  105. stock Iter_RandomAdd_InternalC(&count, array[], start)
  106. {
  107. return Iter_Add_InternalC(count, array, start, Iter_RandomFree_InternalC(count, array, start));
  108. }
  109. stock Iter_RandomAdd_InternalD(counts[], array[], size, slots, start, slot)
  110. {
  111. // This is subtly different to the "C" version - it operates on multi
  112. // iterators, which have many counts, and thus we need to sum those first.
  113. return Iter_Add_InternalD(counts[slot], array, start, size, Iter_RandomFree_InternalD(counts, array, size, slots));
  114. }
  115. /*-------------------------------------------------------------------------*//**
  116. * <param name="count">Number of items in the iterator.</param>
  117. * <param name="array">iterator data.</param>
  118. * <param name="start">Size of the iterator.</param>
  119. * <param name="slots">Number of multi-iterator values.</param>
  120. * <remarks>
  121. * Returns a random unused value from an iterator.
  122. * </remarks>
  123. *//*------------------------------------------------------------------------**/
  124. stock Iter_RandomRemove_InternalC(&count, array[], start)
  125. {
  126. return Iter_Remove_InternalC(count, array, start, Iter_Random_Internal(count, array, start));
  127. }
  128. stock Iter_RandomRemove_InternalD(&count, array[], size, start)
  129. {
  130. // This is subtly different to the "C" version - it operates on multi
  131. // iterators, which have many counts, and thus we need to sum those first.
  132. return Iter_Remove_InternalD(count, array, start, size, Iter_Random_Internal(count, array, start));
  133. }
  134. /*-------------------------------------------------------------------------*//**
  135. * <param name="count">Number of items in the iterator.</param>
  136. * <param name="array">iterator data.</param>
  137. * <param name="start">Size of the iterator.</param>
  138. * <param name="slots">Number of multi-iterator values.</param>
  139. * <remarks>
  140. * Returns a random unused value from an iterator.
  141. * </remarks>
  142. *//*------------------------------------------------------------------------**/
  143. stock Iter_RandomFree_InternalC(count, array[], start)
  144. {
  145. count = start - count;
  146. if (count)
  147. {
  148. count = random(count);
  149. while (start--)
  150. {
  151. // Check if this value is not included in any iterator. If it isn't
  152. // then decrement the count until we have run out of values to test.
  153. if (array[start] <= start && !count--)
  154. return start;
  155. }
  156. }
  157. return INVALID_ITERATOR_SLOT;
  158. }
  159. stock Iter_RandomFree_InternalD(counts[], array[], start, slots)
  160. {
  161. // This is subtly different to the "C" version - it operates on multi
  162. // iterators, which have many counts, and thus we need to sum those first.
  163. new
  164. count = 0;
  165. while (slots--)
  166. count += counts[slots];
  167. return Iter_RandomFree_InternalC(count, array, start);
  168. }
  169. /*-------------------------------------------------------------------------*//**
  170. * <param name="count">Number of items in the iterator.</param>
  171. * <param name="array">iterator data.</param>
  172. * <param name="size">Array start index.</param>
  173. * <remarks>
  174. * Finds the first free slot in the iterator and add it.
  175. * </remarks>
  176. *//*------------------------------------------------------------------------**/
  177. stock Iter_Alloc_InternalC(&count, array[], size)
  178. {
  179. for (new value = 0; value != size; ++value)
  180. {
  181. if (array[value] <= value)
  182. {
  183. new
  184. last = size++,
  185. next = array[last];
  186. while (next < value)
  187. {
  188. last = next,
  189. next = array[last];
  190. }
  191. return
  192. ++count,
  193. array[(value - 1) % size] = (last + 1) % size,
  194. array[next - 1] = value + 1,
  195. array[value] = next,
  196. array[last] = value;
  197. }
  198. }
  199. return INVALID_ITERATOR_SLOT;
  200. }
  201. stock Iter_Alloc_InternalD(&count, array[], start, size)
  202. {
  203. if (start >= size)
  204. {
  205. for (new value = 0; value != size; ++value)
  206. {
  207. if (array[value] <= value)
  208. {
  209. new
  210. last = start,
  211. next = array[last];
  212. while (next < value)
  213. {
  214. last = next,
  215. next = array[last];
  216. }
  217. return
  218. ++count,
  219. array[value] = next,
  220. array[last] = value;
  221. }
  222. }
  223. }
  224. return INVALID_ITERATOR_SLOT;
  225. }
  226. /*-------------------------------------------------------------------------*//**
  227. * <param name="array">iterator data.</param>
  228. * <param name="size">Size of the iterator.</param>
  229. * <remarks>
  230. * Finds the first free slot in the iterator.
  231. * </remarks>
  232. *//*------------------------------------------------------------------------**/
  233. stock Iter_Free_Internal(array[], size)
  234. {
  235. // I tried to rewrite this to use the internal structure of a linked list to
  236. // find a free slot. The logic being that if the next used slot in the list
  237. // is not the same as the next theoretical slot, the theoretical slot must
  238. // be available. Bascially something like:
  239. //
  240. // if (array[i] != i + 1)
  241. // return i + 1;
  242. //
  243. // However, that doesn't work with multi-iterators, since the next slot
  244. // consecutively may not be in the same iterator, but will still be in use.
  245. // I wrote all the code and had to back it out again. This comment is in
  246. // case I ever have the same "clever" idea again - DON'T DO IT. Fortunately
  247. // the existing tests caught the problem and saved me everything but time.
  248. for (new i = 0; i != size; ++i)
  249. {
  250. if (array[i] <= i)
  251. {
  252. return i;
  253. }
  254. }
  255. return INVALID_ITERATOR_SLOT;
  256. }
  257. /*-------------------------------------------------------------------------*//**
  258. * <param name="array">multi-iterator data.</param>
  259. * <param name="trueSize">Size of the multi-iterator.</param>
  260. * <param name="start">End [?, since start points are backwards] of the multi-iterator.</param>
  261. * <remarks>
  262. * Finds the first free multi index in the multi-iterator.
  263. * </remarks>
  264. *//*------------------------------------------------------------------------**/
  265. stock Iter_FreeMulti_Internal(array[], trueSize, start)
  266. {
  267. for (new i = 0; trueSize-- > start; ++i)
  268. {
  269. if (array[trueSize] >= start)
  270. return i;
  271. }
  272. return INVALID_ITERATOR_SLOT;
  273. }
  274. /*-------------------------------------------------------------------------*//**
  275. * <param name="count">Number of items in the iterator.</param>
  276. * <param name="array">iterator data.</param>
  277. * <param name="size">Array start index.</param>
  278. * <param name="value">Item to add.</param>
  279. * <remarks>
  280. * Adds a value to a given iterator set. Now detects when you try and add the
  281. * last item multiple times, as well as all the other items. Now simplified
  282. * even further with the new internal representation. The modulo code is for
  283. * iterator reversal.
  284. * </remarks>
  285. *//*------------------------------------------------------------------------**/
  286. stock Iter_Add_InternalC(&count, array[], size, value)
  287. {
  288. if (0 <= value < size && array[value] <= value)
  289. {
  290. new
  291. last = size++,
  292. next = array[last];
  293. while (next < value)
  294. {
  295. last = next,
  296. next = array[last];
  297. }
  298. return
  299. ++count,
  300. array[(value - 1) % size] = (last + 1) % size,
  301. array[next - 1] = value + 1,
  302. array[value] = next,
  303. array[last] = value;
  304. }
  305. return INVALID_ITERATOR_SLOT;
  306. }
  307. stock Iter_Add_InternalD(&count, array[], start, size, value)
  308. {
  309. if (0 <= value < size && start >= size && array[value] <= value)
  310. {
  311. new
  312. last = start,
  313. next = array[last];
  314. while (next < value)
  315. {
  316. last = next,
  317. next = array[last];
  318. }
  319. return
  320. ++count,
  321. array[value] = next,
  322. array[last] = value;
  323. }
  324. return INVALID_ITERATOR_SLOT;
  325. }
  326. /*-------------------------------------------------------------------------*//**
  327. * <param name="count">Number of items in the iterator.</param>
  328. * <param name="array">iterator data.</param>
  329. * <param name="start">Array start index.</param>
  330. * <param name="size">Array size.</param>
  331. * <param name="index">Index to find Nth value.</param>
  332. * <param name="wrap">Keep going around until a value is found?</param>
  333. * <remarks>
  334. * Allows you to find the Nth value in the iterator. DO NOT call this in a
  335. * loop to get all values - that totally defeats the purpose of "foreach", just
  336. * use a normal "foreach" loop with an index counter for that case.
  337. * </remarks>
  338. *//*------------------------------------------------------------------------**/
  339. stock Iter_Index_Internal(count, array[], start, size, index, bool:wrap = false)
  340. {
  341. // If there are no elements in the iterator, we can't ever return the Nth
  342. // item. Also if the parameters are invalid.
  343. if (index < 0 || start < size || array[start] >= size)
  344. return INVALID_ITERATOR_SLOT;
  345. // We could wrap around in the loop (it would work), but it is better to set
  346. // the limit first.
  347. if (wrap)
  348. index %= count;
  349. else if (index >= count)
  350. return INVALID_ITERATOR_SLOT;
  351. start = array[start];
  352. while (index--)
  353. start = array[start];
  354. return start;
  355. }
  356. /*-------------------------------------------------------------------------*//**
  357. * <param name="count">Number of items in the iterator.</param>
  358. * <param name="array">iterator data.</param>
  359. * <param name="size">Number of iterator elements.</param>
  360. * <param name="value">Item to remove.</param>
  361. * <remarks>
  362. * Removes a value from an iterator.
  363. * </remarks>
  364. *//*------------------------------------------------------------------------**/
  365. stock Iter_Remove_InternalC(&count, array[], size, value)
  366. {
  367. new
  368. last;
  369. return Iter_SafeRemove_InternalC(count, array, size, value, last);
  370. }
  371. stock Iter_Remove_InternalD(&count, array[], start, size, value)
  372. {
  373. new
  374. last;
  375. return Iter_SafeRemove_InternalD(count, array, start, size, value, last);
  376. }
  377. /*-------------------------------------------------------------------------*//**
  378. * <param name="count">Number of items in the iterator.</param>
  379. * <param name="array">Iterator data.</param>
  380. * <param name="size">Number of iterator elements.</param>
  381. * <param name="value">Item to remove.</param>
  382. * <param name="last">Pointer in which to store the last pointer.</param>
  383. * <remarks>
  384. * Removes a value from an iterator safely.
  385. * </remarks>
  386. *//*------------------------------------------------------------------------**/
  387. stock Iter_SafeRemove_InternalC(&count, array[], size, value, &last)
  388. {
  389. if (0 <= value < size++ && array[value] > value)
  390. {
  391. // This version has reverse iterators, which need maintaining, and can
  392. // be used in place of a loop to jump backwards in the list.
  393. return
  394. --count,
  395. last = (array[(value - 1) % size] - 1) % size,
  396. array[last] = array[value],
  397. array[value] = value,
  398. array[(array[last] - 1) % size] = (last + 1) % size;
  399. }
  400. return INVALID_ITERATOR_SLOT;
  401. }
  402. stock Iter_SafeRemove_InternalD(&count, array[], start, size, value, &last)
  403. {
  404. if (0 <= value < size && start >= size && count && array[value] > value)
  405. {
  406. // This version doesn't have reverse iterators, so we need to
  407. // manually loop through the list.
  408. last = start;
  409. while ((start = array[last]) < size)
  410. {
  411. if (start == value)
  412. {
  413. return
  414. --count,
  415. array[last] = array[value],
  416. array[value] = value;
  417. }
  418. last = start;
  419. }
  420. }
  421. return INVALID_ITERATOR_SLOT;
  422. }
  423. /*-------------------------------------------------------------------------*//**
  424. * <param name="array">iterator data.</param>
  425. * <param name="value">Item to check.</param>
  426. * <param name="size">Size of the iterator.</param>
  427. * <remarks>
  428. * Checks if this item is in the iterator.
  429. * </remarks>
  430. *//*------------------------------------------------------------------------**/
  431. stock Iter_Contains_InternalC(array[], size, value)
  432. {
  433. // Only need to know that this element is in ANY list, because there is only
  434. // one list it can be in.
  435. return 0 <= value < size && array[value] > value;
  436. }
  437. stock Iter_Contains_InternalD(count, array[], size, start, value)
  438. {
  439. // Check the count first, and that this element is in ANY list. There is no
  440. // point searching an empty list for this element, hence the count check.
  441. if (0 <= value < size && start >= size && count && array[value] > value)
  442. {
  443. // Then loop over that list to check if this element is in it.
  444. size = start;
  445. while ((size = array[size]) != start)
  446. {
  447. if (size == value)
  448. {
  449. return 1;
  450. }
  451. }
  452. }
  453. return 0;
  454. }
  455. /*-------------------------------------------------------------------------*//**
  456. * <param name="array">multi-iterator data.</param>
  457. * <param name="trueSize">Size of the multi-iterator per index.</param>
  458. * <param name="size">Size of the multi-iterator.</param>
  459. * <param name="value">Item to check.</param>
  460. * <returns>
  461. * INVALID_ITERATOR_SLOT on failure.
  462. * Index of the multi-iterator the value is contained.
  463. * </returns>
  464. * <remarks>
  465. * Checks if this item is in the multi-iterator at all, and if it is returns which index it is in.
  466. * </remarks>
  467. *//*------------------------------------------------------------------------**/
  468. stock Iter_GetMulti_Internal(array[], trueSize, size, value)
  469. {
  470. if (0 <= value < size && array[value] > value)
  471. {
  472. // Find the end of this list.
  473. while ((value = array[value]) < size) {}
  474. // Start points are actually backwards.
  475. return trueSize - value - 1;
  476. }
  477. return INVALID_ITERATOR_SLOT;
  478. }
  479. /*-------------------------------------------------------------------------*//**
  480. * <param name="array">iterator data.</param>
  481. * <param name="size">Size of base array.</param>
  482. * <param name="entries">Size of the count data.</param>
  483. * <param name="count">Number of items in the iterator.</param>
  484. * <param name="elems">Number of iterator elements.</param>
  485. * <param name="lst">Last valid index in the iterator array.</param>
  486. * <param name="start">Optional single multi-iterator to clear.</param>
  487. * <remarks>
  488. * Resets an iterator.
  489. * </remarks>
  490. *//*------------------------------------------------------------------------**/
  491. stock Iter_Clear_InternalC(array[], size, entries, lst, ...)
  492. {
  493. // Clear an entire iterator.
  494. while (size--)
  495. {
  496. array[size] = size;
  497. }
  498. array[lst] = 0;
  499. while (entries--)
  500. {
  501. setarg(4, entries, 0);
  502. }
  503. }
  504. stock Iter_Clear_InternalD(array[], size, entries, elems, counts[], start)
  505. {
  506. // Clear just one part of a multi-iterator.
  507. if (0 <= start < entries)
  508. {
  509. counts[start] = 0,
  510. start = size - 1 - start,
  511. entries = array[start],
  512. array[start] = start;
  513. while (entries < elems)
  514. {
  515. start = array[entries],
  516. array[entries] = 0,
  517. entries = start;
  518. }
  519. }
  520. }
  521. /*-------------------------------------------------------------------------*//**
  522. * <param name="array">Iterator array to initialise.</param>
  523. * <param name="first">First iterator slot.</param>
  524. * <param name="s0">Size of first dimension.</param>
  525. * <param name="s1">Size of second dimension.</param>
  526. * <param name="entries">Number of start points.</param>
  527. * <remarks>
  528. * Multi-dimensional arrays can't be initialised at compile time, so need to be
  529. * done at run time, which is slightly annoying.
  530. * </remarks>
  531. *//*------------------------------------------------------------------------**/
  532. stock
  533. Iter_Init_Internal(arr[][], first[], s0, s1, entries)
  534. {
  535. new
  536. elems = s1 - entries,
  537. i = s1;
  538. entries *= elems;
  539. while (i--)
  540. {
  541. first[i] = entries,
  542. entries -= elems;
  543. }
  544. while (++i != s0)
  545. {
  546. memcpy(arr[i], first, 0, s1 * 4, s1);
  547. }
  548. }
  549. /*-------------------------------------------------------------------------*//**
  550. * <param name="array">iterator data.</param>
  551. * <param name="elems">Number of elements in the iterator.</param>
  552. * <param name="size">Size of the iterator.</param>
  553. * <param name="slot">The current slot.</param>
  554. * <remarks>
  555. * Gets the element in an iterator that points to the current element.
  556. * </remarks>
  557. *//*------------------------------------------------------------------------**/
  558. stock
  559. Iter_Prev_Internal(array[], elems, size, slot)
  560. {
  561. if ((slot < elems) ?
  562. (0 <= slot < array[slot]) :
  563. (slot < size && array[slot] < elems))
  564. {
  565. for (new last = slot; last--; )
  566. {
  567. if (array[last] == slot)
  568. {
  569. return last;
  570. }
  571. }
  572. }
  573. return elems;
  574. }