y_playerset_entry.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #if defined _INC_y_playerset
  2. #endinput
  3. #endif
  4. #define _INC_y_playerset
  5. /*
  6. Legal:
  7. Version: MPL 1.1
  8. The contents of this file are subject to the Mozilla Public License Version
  9. 1.1 the "License"; you may not use this file except in compliance with
  10. the License. You may obtain a copy of the License at
  11. http://www.mozilla.org/MPL/
  12. Software distributed under the License is distributed on an "AS IS" basis,
  13. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. for the specific language governing rights and limitations under the
  15. License.
  16. The Original Code is the YSI framework.
  17. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  18. Portions created by the Initial Developer are Copyright C 2011
  19. the Initial Developer. All Rights Reserved.
  20. Contributors:
  21. Y_Less
  22. koolk
  23. JoeBullet/Google63
  24. g_aSlice/Slice
  25. Misiur
  26. samphunter
  27. tianmeta
  28. maddinat0r
  29. spacemud
  30. Crayder
  31. Dayvison
  32. Ahmad45123
  33. Zeex
  34. irinel1996
  35. Yiin-
  36. Chaprnks
  37. Konstantinos
  38. Masterchen09
  39. Southclaws
  40. PatchwerkQWER
  41. m0k1
  42. paulommu
  43. udan111
  44. Thanks:
  45. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  46. ZeeX - Very productive conversations.
  47. koolk - IsPlayerinAreaEx code.
  48. TheAlpha - Danish translation.
  49. breadfish - German translation.
  50. Fireburn - Dutch translation.
  51. yom - French translation.
  52. 50p - Polish translation.
  53. Zamaroht - Spanish translation.
  54. Los - Portuguese translation.
  55. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  56. me to strive to better.
  57. Pixels^ - Running XScripters where the idea was born.
  58. Matite - Pestering me to release it and using it.
  59. Very special thanks to:
  60. Thiadmer - PAWN, whose limits continue to amaze me!
  61. Kye/Kalcor - SA:MP.
  62. SA:MP Team past, present and future - SA:MP.
  63. Optional plugins:
  64. Gamer_Z - GPS.
  65. Incognito - Streamer.
  66. Me - sscanf2, fixes2, Whirlpool.
  67. */
  68. #include "..\..\YSI_Core\y_utils"
  69. #include "..\y_playerarray"
  70. #include "..\y_iterate"
  71. #if !defined MAX_PLAYER_SET_STACK
  72. #define MAX_PLAYER_SET_STACK (3)
  73. #endif
  74. #define ALL_PLAYERS (0x7FFFFFF1)
  75. #define ALL_HUMANS (0x7FFFFFF1)
  76. #define ALL_CHARACTERS (0x7FFFFFF2)
  77. #define ALL_BOTS (0x7FFFFFF3)
  78. enum e_PLAYER_SET_HACK
  79. {
  80. e_PLAYER_SET_HACK_PA[bits<MAX_PLAYERS> + 1] = 0,
  81. e_PLAYER_SET_HACK_DATA[MAX_PLAYERS] = 0,
  82. e_PLAYER_SET_HACK_EXCESS[MAX_PLAYERS - (bits<MAX_PLAYERS> + 1)]
  83. }
  84. enum e_PLAYER_SET_TYPE:
  85. {
  86. e_PLAYER_SET_TYPE_NONE = 0,
  87. // "GROUP" is a YSI group.
  88. e_PLAYER_SET_TYPE_GROUP,
  89. // "ID" is just a single player.
  90. e_PLAYER_SET_TYPE_ID,
  91. // "PA" is a YSI player array.
  92. e_PLAYER_SET_TYPE_PA,
  93. // "BOOL" is an array of true/false.
  94. e_PLAYER_SET_TYPE_BOOL,
  95. // "ARRAY" is just an array of elements.
  96. e_PLAYER_SET_TYPE_ARRAY,
  97. // "CUSTOM" is used to identify fields in an enum.
  98. e_PLAYER_SET_TYPE_CUSTOM,
  99. e_PLAYER_SET_TYPE_PLAYERS,
  100. e_PLAYER_SET_TYPE_BOTS,
  101. e_PLAYER_SET_TYPE_CHARACTERS
  102. }
  103. // ========================================================================== //
  104. // ========================================================================== //
  105. // WARNING: THE CODE BELOW IS VERY FRAGILE - DO NOT TOUCH IT! //
  106. // ========================================================================== //
  107. // ========================================================================== //
  108. // DO NOT change the order of these variables!
  109. stock
  110. e_PLAYER_SET_TYPE:__ps_type[MAX_PLAYER_SET_STACK char],
  111. __ps_stack[MAX_PLAYER_SET_STACK][MAX_PLAYERS],
  112. __ps_data[e_PLAYER_SET_HACK],
  113. __ps_pointer = -1;
  114. #define @PlayerVar:%0) __ps_addr_t:__ps_addr,__ps_drop_t:%0)FOREACH__(new %0:PS(__ps_addr))
  115. // More than one parameter. This removes the need to redefine "for", which I'm
  116. // very happy about, by doing all detection in one go.
  117. #define __ps_addr_t:__ps_addr,__ps_drop_t:%0,%1)FOREACH__(%2,%3:PS(__ps_addr)) __ps_addr_t:__ps_addr,%1)FOREACH__(%2:PS(__ps_addr))
  118. // Only one parameter (not caught by the above statement). The one is the
  119. // variable name we steal for the "foreach" loop.
  120. #define __ps_addr,__ps_drop_t:%0) __ps_addr)
  121. // This is not affected by any of the macros above.
  122. #define @PlayerArray:%0<%1>%2) __ps_addr_t:__ps_addr%2)for(new PlayerArray:%0<MAX_PLAYERS>;__PS_A(__ps_addr,%0); )
  123. #define @PlayerSet __ps_addr_t
  124. // This code is now less fragile than before (and I understand it far more
  125. // having done much more work with this style of macro in the interim).
  126. // This is the master function, and a long one at that. This function looks at
  127. // the parameters passed to it and determines what SORT of parameter has been
  128. // passed from the long list of possibilities. If "cur" is -1 then this is the
  129. // first call of the function and we need to determine the type. If "cur" is
  130. // not -1 then we are mid-loop and we can just use the stored determined type
  131. // and use "cur" (as the last player done) to figure out the next player. This
  132. // code only loops through connected players.
  133. stock Iter_Func@PS(cur, __ps_addr_t:addr)
  134. {
  135. if (cur == -1)
  136. {
  137. P:3("__PS_S called: %i", _:addr);
  138. // Increment the "stack" pointer.
  139. if (__ps_pointer == MAX_PLAYER_SET_STACK - 1)
  140. {
  141. P:E("y_playerset stack overflow - increase \"MAX_PLAYER_SET_STACK\"");
  142. return -1;
  143. }
  144. ++__ps_pointer;
  145. new
  146. begin = __ps_data[e_PLAYER_SET_HACK_DATA][0];
  147. // Is this a single value element (group or ID).
  148. if (_:addr == begin)
  149. {
  150. // Increase the stack pointer for recursive/multi-layered calls.
  151. // Should really add error-checking code for overflows.
  152. __ps_stack[__ps_pointer][0] = _:addr;
  153. // Single value - either a playerid or a groupid.
  154. #if defined _YSI_HAS_y_groups
  155. if (Group:addr & (Group:0x80000000))//GROUP_MASK)
  156. {
  157. // Use the pre-made iterator functionality.
  158. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_GROUP;
  159. cur = Iter_Func@GroupMember(-1, Group:addr);
  160. if (cur == -1)
  161. {
  162. --__ps_pointer;
  163. }
  164. return cur;
  165. }
  166. #endif
  167. // May not always want this check - tough, they can't really have one
  168. // inside the function because that's just silly.
  169. switch (_:addr)
  170. {
  171. case ALL_PLAYERS:
  172. {
  173. // Uses the new "foreach" format of the infinate loop.
  174. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_PLAYERS;
  175. cur = Iter_First(Player);
  176. if (cur == Iter_End(Player))
  177. {
  178. --__ps_pointer;
  179. cur = -1;
  180. }
  181. return cur;
  182. }
  183. #if defined _FOREACH_BOT && !defined FOREACH_NO_BOTS
  184. case ALL_BOTS:
  185. {
  186. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_BOTS;
  187. cur = Iter_First(Bot);
  188. if (cur == Iter_End(Bot))
  189. {
  190. --__ps_pointer;
  191. cur = -1;
  192. }
  193. return cur;
  194. }
  195. case ALL_CHARACTERS:
  196. {
  197. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_CHARACTERS;
  198. cur = Iter_First(Character);
  199. if (cur == Iter_End(Character))
  200. {
  201. --__ps_pointer;
  202. cur = -1;
  203. }
  204. return cur;
  205. }
  206. #endif
  207. default:
  208. {
  209. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_ID;
  210. if (PS_IS_PLAYER_CONNECTED(_:addr))
  211. {
  212. return _:addr;
  213. }
  214. else
  215. {
  216. --__ps_pointer;
  217. return -1;
  218. }
  219. }
  220. }
  221. }
  222. else
  223. {
  224. // It's an array - _:addr contains the address of the target.
  225. memcpy(__ps_stack[__ps_pointer], __ps_data[e_PLAYER_SET_HACK_DATA], 0, MAX_PLAYERS * 4);
  226. // Try to determine what sort of array it is. Note that there are three
  227. // possible types.
  228. if (begin == PA_TYPE_PA)
  229. {
  230. // Easy to handle - the systems were designed for each other.
  231. // This one needs work... Err - what work?
  232. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_PA;
  233. cur = Iter_Func@PA(-1, Bit:__ps_stack[__ps_pointer]);
  234. if (cur == -1)
  235. {
  236. --__ps_pointer;
  237. }
  238. return cur;
  239. }
  240. else if (begin & 0xFF0000FF == 0x0F0000F0)
  241. {
  242. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_CUSTOM;
  243. cur = begin >>> 8 & 0x0000FFFF;
  244. if (cur == INVALID_PLAYER_ID & 0x0000FFFF)
  245. {
  246. --__ps_pointer;
  247. return -1;
  248. }
  249. if (PS_IS_PLAYER_CONNECTED(cur))
  250. {
  251. return cur;
  252. }
  253. addr = __ps_addr_t:0;
  254. while (++_:addr != MAX_PLAYERS)
  255. {
  256. cur = __ps_stack[__ps_pointer][_:addr];
  257. if (cur == INVALID_PLAYER_ID)
  258. {
  259. --__ps_pointer;
  260. return -1;
  261. }
  262. if (PS_IS_PLAYER_CONNECTED(cur))
  263. {
  264. return cur;
  265. }
  266. }
  267. --__ps_pointer;
  268. return -1;
  269. }
  270. else if (begin > 1 || __ps_data[e_PLAYER_SET_HACK_DATA][1] > 1 || __ps_data[e_PLAYER_SET_HACK_DATA][2] > 1)
  271. {
  272. // List of players. One of the first three will normally be greater
  273. // than 1 in a list of players.
  274. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_ARRAY;
  275. cur = begin;
  276. if (cur == INVALID_PLAYER_ID)
  277. {
  278. --__ps_pointer;
  279. return -1;
  280. }
  281. if (PS_IS_PLAYER_CONNECTED(cur))
  282. {
  283. return cur;
  284. }
  285. addr = __ps_addr_t:0;
  286. while (++_:addr != MAX_PLAYERS)
  287. {
  288. cur = __ps_stack[__ps_pointer][_:addr];
  289. if (cur == INVALID_PLAYER_ID)
  290. {
  291. --__ps_pointer;
  292. return -1;
  293. }
  294. if (PS_IS_PLAYER_CONNECTED(cur))
  295. {
  296. return cur;
  297. }
  298. }
  299. --__ps_pointer;
  300. return -1;
  301. }
  302. else
  303. {
  304. // Boolean array.
  305. __ps_type{__ps_pointer} = e_PLAYER_SET_TYPE_BOOL;
  306. // Find the first set player.
  307. FOREACH__ (cur : Player)
  308. {
  309. // Now ANY true value is true.
  310. if (__ps_data[e_PLAYER_SET_HACK_DATA][cur])
  311. {
  312. //_:addr = i;
  313. return cur;
  314. }
  315. }
  316. // No players specified.
  317. --__ps_pointer;
  318. return -1;
  319. }
  320. }
  321. // Will have returned by this point.
  322. }
  323. P:3("__PS_N called: %i, %i", _:addr, cur);
  324. // Each mode has a different end condition.
  325. switch (__ps_type{__ps_pointer})
  326. {
  327. #if defined _YSI_HAS_y_groups
  328. case e_PLAYER_SET_TYPE_GROUP:
  329. {
  330. cur = Iter_Func@GroupMember(cur, Group:_:addr);
  331. if (cur == -1)
  332. {
  333. --__ps_pointer;
  334. }
  335. return cur;
  336. }
  337. #endif
  338. case e_PLAYER_SET_TYPE_PLAYERS:
  339. {
  340. cur = Iter_Next(Player, cur);
  341. if (cur == Iter_End(Player))
  342. {
  343. --__ps_pointer;
  344. cur = -1;
  345. }
  346. return cur;
  347. }
  348. #if defined _FOREACH_BOT && !defined FOREACH_NO_BOTS
  349. case e_PLAYER_SET_TYPE_BOTS:
  350. {
  351. cur = Iter_Next(Bot, cur);
  352. if (cur == Iter_End(Bot))
  353. {
  354. --__ps_pointer;
  355. cur = -1;
  356. }
  357. return cur;
  358. }
  359. case e_PLAYER_SET_TYPE_CHARACTERS:
  360. {
  361. cur = Iter_Next(Character, cur);
  362. if (cur == Iter_End(Character))
  363. {
  364. --__ps_pointer;
  365. cur = -1;
  366. }
  367. return cur;
  368. }
  369. #endif
  370. case e_PLAYER_SET_TYPE_PA:
  371. {
  372. cur = Iter_Func@PA(cur, Bit:__ps_stack[__ps_pointer]);
  373. if (cur == -1)
  374. {
  375. --__ps_pointer;
  376. }
  377. return cur;
  378. }
  379. case e_PLAYER_SET_TYPE_BOOL:
  380. {
  381. for ( ; ; )
  382. {
  383. cur = Iter_Next(Player, cur);
  384. if (cur == Iter_End(Player))
  385. {
  386. --__ps_pointer;
  387. return -1;
  388. }
  389. if (__ps_stack[__ps_pointer][cur])
  390. {
  391. // Don't need to check if they're connected as the data
  392. // comes directly from "foreach".
  393. break;
  394. }
  395. // Could add extra late checks here (Error, not Warning, now).
  396. }
  397. return cur;
  398. }
  399. case e_PLAYER_SET_TYPE_ID:
  400. {
  401. --__ps_pointer;
  402. return -1;
  403. }
  404. case e_PLAYER_SET_TYPE_ARRAY:
  405. {
  406. addr = __ps_addr_t:-1;
  407. while (++_:addr != MAX_PLAYERS)
  408. {
  409. if (__ps_stack[__ps_pointer][_:addr] == cur)
  410. {
  411. break;
  412. }
  413. }
  414. if (_:addr != MAX_PLAYERS)
  415. {
  416. while (++_:addr != MAX_PLAYERS)
  417. {
  418. cur = __ps_stack[__ps_pointer][_:addr];
  419. if (cur == INVALID_PLAYER_ID)
  420. {
  421. --__ps_pointer;
  422. return -1;
  423. }
  424. if (PS_IS_PLAYER_CONNECTED(cur))
  425. {
  426. return cur;
  427. }
  428. }
  429. }
  430. --__ps_pointer;
  431. return -1;
  432. }
  433. case e_PLAYER_SET_TYPE_CUSTOM:
  434. {
  435. if (cur == __ps_stack[__ps_pointer][0] >>> 8 & 0x0000FFFF)
  436. {
  437. addr = __ps_addr_t:0;
  438. while (++_:addr != MAX_PLAYERS)
  439. {
  440. cur = __ps_stack[__ps_pointer][_:addr];
  441. if (cur == INVALID_PLAYER_ID)
  442. {
  443. --__ps_pointer;
  444. return -1;
  445. }
  446. if (PS_IS_PLAYER_CONNECTED(cur))
  447. {
  448. return cur;
  449. }
  450. }
  451. --__ps_pointer;
  452. return -1;
  453. }
  454. else
  455. {
  456. addr = __ps_addr_t:0;
  457. while (++_:addr != MAX_PLAYERS)
  458. {
  459. if (__ps_stack[__ps_pointer][_:addr] == cur)
  460. {
  461. break;
  462. }
  463. }
  464. if (_:addr != MAX_PLAYERS)
  465. {
  466. while (++_:addr != MAX_PLAYERS)
  467. {
  468. cur = __ps_stack[__ps_pointer][_:addr];
  469. if (cur == INVALID_PLAYER_ID)
  470. {
  471. --__ps_pointer;
  472. return -1;
  473. }
  474. if (PS_IS_PLAYER_CONNECTED(cur))
  475. {
  476. return cur;
  477. }
  478. }
  479. }
  480. --__ps_pointer;
  481. return -1;
  482. }
  483. }
  484. }
  485. --__ps_pointer;
  486. return -1;
  487. }
  488. #define Iterator@PS iterstart(-1)
  489. // This function gets the required data from custom format (enum) arrays.
  490. stock __PS_C(source[MAX_PLAYERS][], idx)
  491. {
  492. static
  493. sFake[MAX_PLAYERS] = {(INVALID_PLAYER_ID << 8) | 0x0F0000F0};
  494. new
  495. ret = (__ps_data[e_PLAYER_SET_HACK_DATA] = sFake),
  496. e_PLAYER_SET_HACK:i = e_PLAYER_SET_HACK:0;
  497. FOREACH__ (new playerid : Player)
  498. {
  499. if (source[playerid][idx])
  500. {
  501. if (i)
  502. {
  503. __ps_data[i++] = playerid;
  504. }
  505. else
  506. {
  507. __ps_data[i++] = (playerid << 8) | 0x0F0000F0;
  508. }
  509. }
  510. }
  511. if (i < e_PLAYER_SET_HACK:MAX_PLAYERS)
  512. {
  513. __ps_data[i] = INVALID_PLAYER_ID;
  514. }
  515. return ret;
  516. }
  517. stock bool:__PS_A(@PlayerSet:addr, PlayerArray:ret<MAX_PLAYERS>)
  518. {
  519. if (ret[0])
  520. {
  521. return false;
  522. }
  523. PA_FastInit(ret);
  524. FOREACH__ (new a : PS(addr))
  525. {
  526. PA_Let(ret, a);
  527. }
  528. return true;
  529. }
  530. // This SHOULD handle excess parameters correctly, simply because I left out the
  531. // extra brackets.
  532. #define PSF:%0(%1) %0(__ps_addr_t:__ps_data[e_PLAYER_SET_HACK_PA]=__ps_addr_t:%1)
  533. // This redefines e_PLAYER_SET_HACK_DATA in the case of passing player arrays.
  534. #define e_PLAYER_SET_HACK_PA]=__ps_addr_t:@%0) e_PLAYER_SET_HACK_DATA]=__ps_addr_t:%0)
  535. // Don't actually need the "@".
  536. #define __ps_data[e_PLAYER_SET_HACK_DATA]=%0<%1> __ps_addr_t:__PS_C(%0,%1)
  537. #define __PS_C(@%0,%1) __PS_C(%0,%1)