y_classes_multiclass.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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. forward Class_ResolveGroups(class, Group:forgroup, bool:cp);
  65. enum e_CLASS_FLAGS:(<<= 1)
  66. {
  67. e_CLASS_FLAGS_SKIN = 0x0000FFFF,
  68. e_CLASS_FLAGS_ENABLED = 0x00010000,
  69. e_CLASS_FLAGS_ACTIVE
  70. }
  71. enum E_CLASS
  72. {
  73. e_CLASS_FLAGS:E_CLASS_FLAGS,
  74. Float:E_CLASS_X,
  75. Float:E_CLASS_Y,
  76. Float:E_CLASS_Z,
  77. Float:E_CLASS_A,
  78. E_CLASS_WEAPONS[MAX_CLASS_SPAWN_WEAPONS + 1],
  79. Group:E_CLASS_GROUP,
  80. PlayerArray:E_CLASS_PLAYERS<MAX_PLAYERS>
  81. }
  82. static stock
  83. YSI_g_sClasses[MAX_CLASSES][E_CLASS],
  84. YSI_g_sPlayerClass[MAX_PLAYERS],
  85. YSI_g_sInternalClass[MAX_PLAYERS],
  86. YSI_g_sClassCount,
  87. YSI_g_sLastRefuse[MAX_PLAYERS];
  88. stock Class_ResolveGroups(class, Group:forgroup, bool:cp) <YSI_has_groups : n>
  89. {
  90. #pragma unused forgroup
  91. P:2("Class_ResolveGroups<n>: call Resolve %d %d %d", class, _:forgroup, cp);
  92. if (!cp) PA_Init(YSI_g_sClasses[class][E_CLASS_PLAYERS], true);
  93. }
  94. stock Class_ResolveGroups(class, Group:forgroup, bool:cp) <>
  95. {
  96. #pragma unused forgroup
  97. P:2("Class_ResolveGroups<>: call Resolve %d %d %d", class, _:forgroup, cp);
  98. if (!cp) PA_Init(YSI_g_sClasses[class][E_CLASS_PLAYERS], true);
  99. }
  100. /*-------------------------------------------------------------------------*//**
  101. * <param name="classid">Class to check if active.</param>
  102. *//*------------------------------------------------------------------------**/
  103. P:D(bool:_Class_IsActive(classid));
  104. #define _Class_IsActive(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_ACTIVE)
  105. /*-------------------------------------------------------------------------*//**
  106. * <param name="classid">Class to check if valid.</param>
  107. *//*------------------------------------------------------------------------**/
  108. P:D(bool:_Class_IsValid(classid));
  109. #define _Class_IsValid(%1) (IS_IN_RANGE((%1), 0, MAX_CLASSES) && _Class_IsActive(%1))
  110. /*-------------------------------------------------------------------------*//**
  111. * <param name="classid">Class to check.</param>
  112. *//*------------------------------------------------------------------------**/
  113. P:D(bool:_Class_Enabled(classid));
  114. #define _Class_Enabled(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_ENABLED)
  115. /*-------------------------------------------------------------------------*//**
  116. * <param name="classid">Class to get X location for.</param>
  117. *//*------------------------------------------------------------------------**/
  118. P:D(Float:Class_X(classid));
  119. #define Class_X(%1) YSI_g_sClasses[(%1)][E_CLASS_X]
  120. /*-------------------------------------------------------------------------*//**
  121. * <param name="classid">Class to get Y location for.</param>
  122. *//*------------------------------------------------------------------------**/
  123. P:D(Float:Class_Y(classid));
  124. #define Class_Y(%1) YSI_g_sClasses[(%1)][E_CLASS_Y]
  125. /*-------------------------------------------------------------------------*//**
  126. * <param name="classid">Class to get Z location for.</param>
  127. *//*------------------------------------------------------------------------**/
  128. P:D(Float:Class_Z(classid));
  129. #define Class_Z(%1) YSI_g_sClasses[(%1)][E_CLASS_Z]
  130. /*-------------------------------------------------------------------------*//**
  131. * <param name="classid">Class to get angle for.</param>
  132. *//*------------------------------------------------------------------------**/
  133. P:D(Float:Class_A(classid));
  134. #define Class_A(%1) YSI_g_sClasses[(%1)][E_CLASS_A]
  135. /*-------------------------------------------------------------------------*//**
  136. * <param name="classid">Class to get skin for.</param>
  137. *//*------------------------------------------------------------------------**/
  138. P:D(Class_Skin(classid));
  139. #define Class_Skin(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_SKIN)
  140. /*-------------------------------------------------------------------------*//**
  141. * <remarks>
  142. * Creates three real player classes so you can scroll correctly with the
  143. * direction being detected.
  144. * </remarks>
  145. * <transition keep="true" target="_YCM : u"/>
  146. * <transition keep="true" target="_YCM : y"/>
  147. *//*------------------------------------------------------------------------**/
  148. HOOK__ OnScriptInit()
  149. {
  150. #if !_YSIM_IS_CLIENT
  151. if (!YSI_FILTERSCRIPT)
  152. {
  153. // This code placement is not generic.
  154. new
  155. classLeft = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0),
  156. classMiddle = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0),
  157. classRight = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  158. if (classLeft != 0 || classMiddle != 1 || classRight != 2)
  159. {
  160. P:E("y_classes assumptions failed. Do you have \"AddPlayerClass\" in your modes?");
  161. }
  162. //printf("==========================");
  163. P:4("Class_OnScriptInit: classes = %d %d %d", classLeft, classMiddle, classRight);
  164. //printf("==========================");
  165. #if !defined YSI_NO_MASTER
  166. if (_Master_Get(#_YCM, true))
  167. {
  168. // Nothing changed, or we took it without force.
  169. state _YCM:y;
  170. _YCM@ = _E_YCM@y;
  171. }
  172. else
  173. {
  174. // Something changed, tell other scripts.
  175. state _YCM:u;
  176. _YCM@ = _E_YCM@u;
  177. // Determine the next unique name.
  178. CallRemoteFunction(#_YCM, "");
  179. // There is a note in y_master about this being safe
  180. // because servers always get the data. This is the server
  181. // code, but may be in use by cloud systems. This, however,
  182. // is still not a problem because we never fully pass off.
  183. }
  184. #endif
  185. }
  186. #endif
  187. return 1;
  188. }
  189. static stock Class_FindNew(playerid, playerclass, dir)
  190. {
  191. P:4("Class_FindNew called: %i, %i, %i", playerid, playerclass, dir);
  192. if (dir == 0)
  193. {
  194. // No change, check the current skin is still valid. There are plenty
  195. // of reasons for this: Removed skin, returned -1, disabled, returned to
  196. // class selection. This used to not be handled explicitly, but now it
  197. // is.
  198. if (_Class_Enabled(playerclass) && PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid)) return playerclass;
  199. ++dir;
  200. }
  201. new
  202. old = playerclass % YSI_g_sClassCount;
  203. do
  204. {
  205. playerclass = (playerclass + dir) % YSI_g_sClassCount;
  206. P:4("Class_FindNew: %d %d", playerclass, playerid);
  207. }
  208. while (playerclass != old && (!_Class_Enabled(playerclass) || !PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid)));
  209. // (!(playerclass == old || (_Class_Enabled(playerclass) && PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid))))
  210. return playerclass;
  211. }
  212. /*-------------------------------------------------------------------------*//**
  213. * <param name="playerid">Player who is changing class.</param>
  214. * <param name="playerclass">The internal class they are switching to.</param>
  215. * <remarks>
  216. * Does the visual faking through "SetPlayerSkin", and also calls
  217. * "SetSpawnInfo" to avoid any lag from "SetPlayerPos" under "OnPlayerSpawn".
  218. * </remarks>
  219. *//*------------------------------------------------------------------------**/
  220. FOREIGN__ void:Class_Goto(playerid, playerclass);
  221. GLOBAL__ void:Class_Goto(playerid, playerclass)
  222. {
  223. P:2("Class_Goto called: %i, %i", playerid, playerclass);
  224. // This now sets the REAL spawn information, including spawn location.
  225. SetSpawnInfo(playerid, NO_TEAM, Class_Skin(e_PLAYER_CLASS:playerclass), Class_X(e_PLAYER_CLASS:playerclass), Class_Y(e_PLAYER_CLASS:playerclass), Class_Z(e_PLAYER_CLASS:playerclass), Class_A(e_PLAYER_CLASS:playerclass), 0, 0, 0, 0, 0, 0);
  226. SetPlayerSkin(playerid, Class_Skin(e_PLAYER_CLASS:playerclass));
  227. YSI_g_sPlayerClass[playerid] = playerclass; //(YSI_g_sPlayerClass[playerid] & ~e_PLAYER_CLASS_SKIN) | (e_PLAYER_CLASS:playerclass);
  228. }
  229. /*-------------------------------------------------------------------------*//**
  230. * <param name="playerid">Player who selected a spawn.</param>
  231. * <remarks>
  232. * Has inbuilt protection for a bug where selections aren't correctly
  233. * debounced so you can press shift twice at once which can mess up some
  234. * scripts (e.g. the example team selection script). Calls
  235. * OnPlayerRequestSpawnEx with an additional class parameter.
  236. * </remarks>
  237. *//*------------------------------------------------------------------------**/
  238. #if !defined YSI_NO_MASTER && (_YSIM_IS_CLIENT || _YSIM_IS_STUB)
  239. public OnPlayerRequestSpawn(playerid)
  240. {
  241. return 1;
  242. }
  243. #else
  244. #if !defined YSI_NO_MASTER && _YSIM_IS_CLOUD
  245. public OnPlayerRequestSpawn(playerid) <>
  246. {
  247. return 1;
  248. }
  249. public OnPlayerRequestSpawn(playerid) <_YCM:y>
  250. #else
  251. public OnPlayerRequestSpawn(playerid)
  252. #endif
  253. {
  254. P:1("Class_OnPlayerRequestSpawn called: %d", playerid);
  255. new
  256. time = GetTickCount();
  257. if ((time - YSI_g_sLastRefuse[playerid]) >= 500)
  258. {
  259. new
  260. ret = CallRemoteFunction("Class_OnPlayerRequestSpawn", "i", playerid);
  261. P:4("Class_OnPlayerRequestSpawn() return: %d", ret);
  262. if (ret)
  263. {
  264. new
  265. Group:newgroup = YSI_g_sClasses[YSI_g_sPlayerClass[playerid]][E_CLASS_GROUP];
  266. P:4("Class_OnPlayerRequestSpawn() newgroup: %d", _:newgroup);
  267. if (newgroup != Group:-1) Class_ResolveGroups(playerid, newgroup, true);
  268. if (ret == -1)
  269. {
  270. // Send the player back to class selection.
  271. _Class_OnPlayerRequestClass(playerid, YSI_g_sInternalClass[playerid]);
  272. }
  273. else
  274. {
  275. return 1;
  276. }
  277. }
  278. }
  279. P:5("Class_OnPlayerRequestSpawn: Return 0");
  280. return
  281. YSI_g_sLastRefuse[playerid] = time,
  282. 0;
  283. }
  284. #endif
  285. CHAIN_FORWARD:Class_OnPlayerRequestSpawn(playerid) = 1;
  286. #if defined _ALS_OnPlayerRequestSpawn
  287. #undef OnPlayerRequestSpawn
  288. #else
  289. #define _ALS_OnPlayerRequestSpawn
  290. #endif
  291. #define OnPlayerRequestSpawn(%0) CHAIN_PUBLIC:Class_OnPlayerRequestSpawn(%0)
  292. /*-------------------------------------------------------------------------*//**
  293. * <param name="playerid">Player who spawned.</param>
  294. * <remarks>
  295. * Sets a player's position based on skin.
  296. * </remarks>
  297. *//*------------------------------------------------------------------------**/
  298. MASTER_HOOK__ OnPlayerSpawn(playerid)
  299. {
  300. P:2("Class_OnPlayerSpawn called: %d", playerid);
  301. new
  302. playerclass = YSI_g_sPlayerClass[playerid],
  303. weapon;
  304. for (new i = 0; i != MAX_CLASS_SPAWN_WEAPONS; ++i)
  305. {
  306. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][i];
  307. if (weapon)
  308. {
  309. GivePlayerWeapon(playerid, weapon & 0xFF, weapon >>> 8);
  310. }
  311. else
  312. {
  313. break;
  314. }
  315. }
  316. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][MAX_CLASS_SPAWN_WEAPONS];
  317. P:5("Class_OnPlayerSpawn: Armour %d %d %d", weapon, weapon & 0xFF, WEAPON_ARMOUR);
  318. if ((weapon & 0xFF) == WEAPON_ARMOUR)
  319. {
  320. weapon >>>= 8;
  321. if (weapon == 0x00800000)
  322. {
  323. // INFINITY
  324. SetPlayerArmour(playerid, Float:0x7F800000);
  325. }
  326. else
  327. {
  328. SetPlayerArmour(playerid, weapon);
  329. }
  330. }
  331. return 1;
  332. }
  333. /*-------------------------------------------------------------------------*//**
  334. * <param name="playerid">Player who joined the server.</param>
  335. * <remarks>
  336. * Reset all the data on this player's current classes.
  337. * </remarks>
  338. *//*------------------------------------------------------------------------**/
  339. MASTER_HOOK__ OnPlayerConnect(playerid)
  340. {
  341. YSI_g_sPlayerClass[playerid] = -1,
  342. YSI_g_sInternalClass[playerid] = -1;
  343. NO_GROUPS<Class>()
  344. {
  345. new
  346. slot = PA_Slot(playerid),
  347. Bit:mask = PA_Mask(playerid);
  348. for (new i = 0; i != MAX_CLASSES; ++i)
  349. {
  350. YSI_g_sClasses[i][E_CLASS_PLAYERS][slot] |= mask;
  351. }
  352. }
  353. return 1;
  354. }
  355. /*-------------------------------------------------------------------------*//**
  356. * <remarks>
  357. * Converts the variable arguments to an array.
  358. * </remarks>
  359. *//*------------------------------------------------------------------------**/
  360. #define _CLASS_WEAPON_CODE \
  361. {if((n-w+1)/2>MAX_CLASS_SPAWN_WEAPONS) P:E("Excessive class weapon data."); \
  362. if((n-w)&0x01){while(w!=n)if((cw=getarg(w++))==WEAPON_ARMOUR)weapons[MAX_CLASS_SPAWN_WEAPONS]=WEAPON_ARMOUR|(100<<8);else if(w==n)P:E(": Insufficient class weapon data.");else weapons[s++]=(cw&0xFF)|(getarg(w++)<<8);} \
  363. else{while(w!=n)weapons[((cw=getarg(w++))==WEAPON_ARMOUR)?MAX_CLASS_SPAWN_WEAPONS:(s++)]=(cw&0xFF)|(getarg(w++)<<8);}}
  364. /*-------------------------------------------------------------------------*//**
  365. * <param name="skin">Skin of the class.</param>
  366. * <param name="x">X spawn location.</param>
  367. * <param name="y">Y spawn location.</param>
  368. * <param name="z">Z spawn location.</param>
  369. * <param name="a">A spawn location.</param>
  370. * <param name="">Spawn weapons and ammo (weapon then ammo)</param>
  371. * <remarks>
  372. * Pretty much AddPlayerClass but allows greater control over the classes.
  373. * Now has infinate (MAX_CLASS_SPAWN_WEAPONS) spawn weapons. This is one of
  374. * the few API functions which is not entirely remote. This is because it has
  375. * variable parameters which is need to collect in to a single array to pass to
  376. * the remote function.
  377. * </remarks>
  378. *//*------------------------------------------------------------------------**/
  379. stock Class_Add(skin, Float:x, Float:y, Float:z, Float:a, ...)
  380. {
  381. P:3("Class_Add called: %i, %f, %f, %f, %f, (+%i)", skin, x, y, z, a, numargs() - 5);
  382. new
  383. n = numargs(),
  384. w = 5,
  385. s,
  386. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  387. cw;
  388. _CLASS_WEAPON_CODE
  389. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, Group:-1, Group:-1);
  390. }
  391. /*-------------------------------------------------------------------------*//**
  392. * <param name="forgroup">Group that can use the skin.</param>
  393. * <param name="setgroup">Group to add the player to on selection.</param>
  394. * <param name="skin">Skin of the class.</param>
  395. * <param name="x">X spawn location.</param>
  396. * <param name="y">Y spawn location.</param>
  397. * <param name="z">Z spawn location.</param>
  398. * <param name="a">A spawn location.</param>
  399. * <param name="">Spawn weapons and ammo (weapon then ammo)</param>
  400. * <remarks>
  401. * Pretty much AddPlayerClass but allows greater control over the classes.
  402. * Now has infinate (MAX_CLASS_SPAWN_WEAPONS) spawn weapons.
  403. * </remarks>
  404. *//*------------------------------------------------------------------------**/
  405. stock Class_AddEx(Group:forgroup, Group:setgroup, skin, Float:x, Float:y, Float:z, Float:a, ...)
  406. {
  407. P:3("Class_AddEx called: %i, %i, %i, %f, %f, %f, %f (+%i)", _:forgroup, _:setgroup, skin, x, y, z, a, numargs() - 7);
  408. new
  409. n = numargs(),
  410. w = 7,
  411. s,
  412. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  413. cw;
  414. _CLASS_WEAPON_CODE
  415. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, forgroup, setgroup);
  416. }
  417. /*-------------------------------------------------------------------------*//**
  418. * <param name="group">Group to allow to use the class.</param>
  419. * <param name="skin">Skin of the class.</param>
  420. * <param name="x">X spawn location.</param>
  421. * <param name="y">Y spawn location.</param>
  422. * <param name="z">Z spawn location.</param>
  423. * <param name="a">A spawn location.</param>
  424. * <param name="">Weapon data.</param>
  425. * <remarks>
  426. * Adds a class only people in the specified group can use.
  427. * </remarks>
  428. *//*------------------------------------------------------------------------**/
  429. stock Class_AddForGroup(Group:group, skin, Float:x, Float:y, Float:z, Float:a, ...)
  430. {
  431. P:3("Class_AddForGroup called: %i, %i, %f, %f, %f, %f (+%i)", _:group, skin, x, y, z, a, numargs() - 6);
  432. new
  433. n = numargs(),
  434. w = 6,
  435. s,
  436. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  437. cw;
  438. _CLASS_WEAPON_CODE
  439. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, group, Group:-1);
  440. }
  441. /*-------------------------------------------------------------------------*//**
  442. * <param name="group">Group to make players who use this group.</param>
  443. * <param name="skin">Skin of the class.</param>
  444. * <param name="x">X spawn location.</param>
  445. * <param name="y">Y spawn location.</param>
  446. * <param name="z">Z spawn location.</param>
  447. * <param name="a">A spawn location.</param>
  448. * <param name="">Spawn weapons.</param>
  449. * <remarks>
  450. * Adds a class which puts you in the specified group when selected.
  451. * </remarks>
  452. *//*------------------------------------------------------------------------**/
  453. stock Class_AddWithGroupSet(Group:group, skin, Float:x, Float:y, Float:z, Float:a, ...)
  454. {
  455. P:3("Class_AddWithGroupSet called: %i, %i, %f, %f, %f, %f (+%i)", _:group, skin, x, y, z, a, numargs() - 6);
  456. new
  457. n = numargs(),
  458. w = 6,
  459. s,
  460. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  461. cw;
  462. _CLASS_WEAPON_CODE
  463. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, Group:-1, group);
  464. }
  465. /*-------------------------------------------------------------------------*//**
  466. * <param name="skin">Skin of the class.</param>
  467. * <param name="x">X spawn location.</param>
  468. * <param name="y">Y spawn location.</param>
  469. * <param name="z">Z spawn location.</param>
  470. * <param name="a">A spawn location.</param>
  471. * <param name="weapons">Array of spawn weapon data.</param>
  472. * <param name="count">Number of weapons added.</param>
  473. * <param name="forgroup">Group that can use the class.</param>
  474. * <param name="asgroup">Group to assign people to with this class.</param>
  475. * <remarks>
  476. * Does the hard work. This took a long time to get working correctly with the
  477. * new master system, infact getting just this one function to compile took a
  478. * major re-working of the macros to reduce the length of intermediate stages.
  479. * </remarks>
  480. *//*------------------------------------------------------------------------**/
  481. FOREIGN__ Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,const w[],c,Group:f,Group:g);
  482. GLOBAL__ Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,const w[],c,Group:f,Group:g)
  483. {
  484. #pragma unused c
  485. P:2("Class_AddClass called: %i, %f, %f, %f, %f, %s, %i, %i, %i", s, x, y, z, a, Debug_PrintArray(w, c), c, _:f, _:g);
  486. new
  487. i;
  488. while (i != MAX_CLASSES && _Class_IsActive(i)) ++i;
  489. if (i == MAX_CLASSES) return -1;
  490. YSI_g_sClasses[i][E_CLASS_FLAGS] = e_CLASS_FLAGS_ACTIVE | e_CLASS_FLAGS_ENABLED | e_CLASS_FLAGS:s,
  491. YSI_g_sClasses[i][E_CLASS_X] = x,
  492. YSI_g_sClasses[i][E_CLASS_Y] = y,
  493. YSI_g_sClasses[i][E_CLASS_Z] = z,
  494. YSI_g_sClasses[i][E_CLASS_A] = a,
  495. memcpy(YSI_g_sClasses[i][E_CLASS_WEAPONS], w, 0, (MAX_CLASS_SPAWN_WEAPONS + 1) * 4, MAX_CLASS_SPAWN_WEAPONS + 1);
  496. // P:7("Class_AddClass: weapon %d %d %d", j, c, i);
  497. PA_FastInit(YSI_g_sClasses[i][E_CLASS_PLAYERS]);
  498. // P:7("Class_AddClass: weapon %d %d %d", j, c, f);
  499. Class_ResolveGroups(i, f, false);
  500. // P:7("Class_AddClass: weapon %d %d %d", j, c, g);
  501. YSI_g_sClasses[i][E_CLASS_GROUP] = g;
  502. YSI_g_sClassCount++;
  503. // P:7("Class_AddClass: weapon %d %d %d", j, c, YSI_g_sClassCount);
  504. return i;
  505. }
  506. /*-------------------------------------------------------------------------*//**
  507. * <param name="classid">The class to test.</param>
  508. * <param name="group">The group to test setting of.</param>
  509. * <returns>
  510. * Does this class add players to the given group on spawn?
  511. * </returns>
  512. *//*------------------------------------------------------------------------**/
  513. FOREIGN__ Class_HasGroup(classid, Group:group);
  514. GLOBAL__ Class_HasGroup(classid, Group:group)
  515. {
  516. return YSI_g_sClasses[classid][E_CLASS_GROUP] == group;
  517. }
  518. /*-------------------------------------------------------------------------*//**
  519. *//*------------------------------------------------------------------------**/
  520. FOREIGN__ Class_Enable(classid, bool:toggle);
  521. GLOBAL__ Class_Enable(classid, bool:toggle)
  522. {
  523. if (_Class_IsValid(classid))
  524. {
  525. if (toggle)
  526. {
  527. YSI_g_sClasses[classid][E_CLASS_FLAGS] |= e_CLASS_FLAGS_ENABLED;
  528. }
  529. else
  530. {
  531. YSI_g_sClasses[classid][E_CLASS_FLAGS] &= ~e_CLASS_FLAGS_ENABLED;
  532. // Hide the class for anyone currently viewing it.
  533. FOREACH__ (new playerid : Player)
  534. {
  535. P:5("Class_Enable: %d %d %d", playerid, _:YSI_g_sPlayerClass[playerid], _:e_PLAYER_CLASS_IN_SELECTION);
  536. if (Player_InSelection(playerid))
  537. {
  538. _Class_OnPlayerRequestClass(playerid, YSI_g_sInternalClass[playerid]);
  539. }
  540. }
  541. }
  542. return 1;
  543. }
  544. return 0;
  545. }
  546. /*-------------------------------------------------------------------------*//**
  547. * <param name="classid">Class to delete.</param>
  548. * <remarks>
  549. * Completely removes a class from the system.
  550. * </remarks>
  551. *//*------------------------------------------------------------------------**/
  552. FOREIGN__ void:Class_Delete(classid);
  553. GLOBAL__ void:Class_Delete(classid)
  554. {
  555. P:2("Class_Delete called: %i", classid);
  556. if (Class_Enable(classid, false))
  557. {
  558. YSI_g_sClasses[classid][E_CLASS_FLAGS] = e_CLASS_FLAGS:0;
  559. }
  560. }
  561. /*-------------------------------------------------------------------------*//**
  562. * <param name="classid">Class to set permissions for.</param>
  563. * <param name="playerid">Player to set for.</param>
  564. * <param name="set">Whether or not they can use this class.</param>
  565. *//*------------------------------------------------------------------------**/
  566. FOREIGN__ void:Class_SetPlayer(cl, pid, bool:s);
  567. GLOBAL__ void:Class_SetPlayer(cl, pid, bool:s)
  568. {
  569. PA_Set(YSI_g_sClasses[cl][E_CLASS_PLAYERS], pid, s);
  570. }
  571. /*-------------------------------------------------------------------------*//**
  572. * <param name="classid">Class to set permissions for.</param>
  573. * <param name="playerid">Player to set for.</param>
  574. *//*------------------------------------------------------------------------**/
  575. FOREIGN__ bool:Class_GetPlayer(cl,pid);
  576. GLOBAL__ bool:Class_GetPlayer(cl,pid)
  577. {
  578. return PA_Get(YSI_g_sClasses[cl][E_CLASS_PLAYERS], pid);
  579. }
  580. /*-------------------------------------------------------------------------*//**
  581. * <param name="playerid">Player to get the current class of.</param>
  582. *//*------------------------------------------------------------------------**/
  583. FOREIGN__ Class_Get(playerid);
  584. GLOBAL__ Class_Get(playerid)
  585. {
  586. if (VALID_PLAYERID(playerid))
  587. {
  588. return YSI_g_sPlayerClass[playerid];
  589. }
  590. return -1;
  591. }
  592. #if defined _ALS_AddPlayerClass
  593. #undef AddPlayerClass
  594. #else
  595. #define _ALS_AddPlayerClass
  596. #endif
  597. #define AddPlayerClass Class_Add
  598. /*-------------------------------------------------------------------------*//**
  599. * <param name="playerid">Player whose current class view may need to change.</param>
  600. * <remarks>
  601. * If you change a player's groups while they are in class selection, call this
  602. * function to potentially update the currently displayed class.
  603. * </remarks>
  604. *//*------------------------------------------------------------------------**/
  605. stock Class_Reprocess(playerid)
  606. {
  607. if (!Player_InSelection(playerid))
  608. return 0;
  609. new
  610. classid = -1;
  611. if (YSI_g_sClassCount)
  612. {
  613. // Find the next available skin for this player. I'm still not
  614. // sure how this handles the case where you can't use any skin.
  615. // I'll have to look in to that - don't want to get stuck
  616. // constantly adding "0".
  617. classid = Class_FindNew(playerid, YSI_g_sPlayerClass[playerid], 0),
  618. Class_Goto(playerid, classid);
  619. P:5("Class_Reprocess() selected: %d", classid);
  620. }
  621. else
  622. {
  623. P:E("No YSI classes found");
  624. SetSpawnInfo(playerid, NO_TEAM, 0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0),
  625. SetPlayerSkin(playerid, 0);
  626. }
  627. return CallRemoteFunction("Class_OnPlayerRequestClass", "ii", playerid, classid);
  628. }
  629. /*-------------------------------------------------------------------------*//**
  630. * <param name="playerid">Player who requested a class.</param>
  631. * <param name="class">Class they requested.</param>
  632. * <remarks>
  633. * The input is one of the three real classes used to detect selected
  634. * direction of alteration. Scans for a class the player is allowed to use
  635. * and hot swaps it out. Uses SetPlayerSkin AND SetSpawnInfo to combat bugs
  636. * with calling this from OnPlayerRequestSpawn (e.g. the example team script).
  637. * Calls OnPlayerRequestClassEx with the current internal class not the real
  638. * one.
  639. *
  640. * Last thing in the file to be simpler to call directly. If we ever have a
  641. * more complex ALS hook on this callback the main body of this code will have
  642. * to be moved in to its own function. As indeed it now does!
  643. * </remarks>
  644. *//*------------------------------------------------------------------------**/
  645. public OnPlayerRequestClass(playerid, classid)
  646. {
  647. return _Class_OnPlayerRequestClass(playerid, classid);
  648. }
  649. // Pre-empt y_hooks.
  650. #if !defined YSI_NO_MASTER && _YSIM_IS_CLIENT
  651. static stock _Class_OnPlayerRequestClass(playerid, classid)
  652. {
  653. #pragma unused playerid, classid
  654. return 1;
  655. }
  656. #else
  657. #if !defined YSI_NO_MASTER && _YSIM_IS_CLOUD
  658. static stock _Class_OnPlayerRequestClass(playerid, classid) <>
  659. {
  660. #pragma unused playerid, classid
  661. return 1;
  662. }
  663. static stock _Class_OnPlayerRequestClass(playerid, classid) <_YCM:y>
  664. #else
  665. static stock _Class_OnPlayerRequestClass(playerid, classid)
  666. #endif
  667. {
  668. P:1("Class_OnPlayerRequestClass called: %d %d", playerid, classid);
  669. // Find which direction they pressed.
  670. if (YSI_g_sClassCount)
  671. {
  672. // Find the next available skin for this player. I'm still not
  673. // sure how this handles the case where you can't use any skin.
  674. // I'll have to look in to that - don't want to get stuck
  675. // constantly adding "0".
  676. new
  677. cid = classid;
  678. classid = Class_FindNew(playerid, YSI_g_sPlayerClass[playerid], ((classid - YSI_g_sInternalClass[playerid]) + 1) % 3 - 1),
  679. YSI_g_sInternalClass[playerid] = cid,
  680. Class_Goto(playerid, classid);
  681. P:5("Class_OnPlayerRequestClass() selected: %d", classid);
  682. }
  683. else
  684. {
  685. P:E("No YSI classes found");
  686. SetSpawnInfo(playerid, NO_TEAM, 0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0),
  687. SetPlayerSkin(playerid, 0),
  688. classid = -1;
  689. }
  690. return CallRemoteFunction("Class_OnPlayerRequestClass", "ii", playerid, classid);
  691. }
  692. #endif
  693. // Use the special pre-y_hooks hook method.
  694. CHAIN_FORWARD:Class_OnPlayerRequestClass(playerid, classid) = 1;
  695. #if defined _ALS_OnPlayerRequestClass
  696. #undef OnPlayerRequestClass
  697. #else
  698. #define _ALS_OnPlayerRequestClass
  699. #endif
  700. #define OnPlayerRequestClass(%0) CHAIN_PUBLIC:Class_OnPlayerRequestClass(%0)