y_classes - Copy (2).inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /*----------------------------------------------------------------------------*\
  2. ======================================
  3. y_classes - Advanced class selection
  4. ======================================
  5. Description:
  6. Allows greater control over classes so not everyone has every class. Uses
  7. a form of compression for locations.
  8. Legal:
  9. Version: MPL 1.1
  10. The contents of this file are subject to the Mozilla Public License Version
  11. 1.1 (the "License"); you may not use this file except in compliance with
  12. the License. You may obtain a copy of the License at
  13. http://www.mozilla.org/MPL/
  14. Software distributed under the License is distributed on an "AS IS" basis,
  15. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  16. for the specific language governing rights and limitations under the
  17. License.
  18. The Original Code is the YSI classes include.
  19. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  20. Portions created by the Initial Developer are Copyright (C) 2011
  21. the Initial Developer. All Rights Reserved.
  22. Contributors:
  23. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  24. Thanks:
  25. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  26. ZeeX - Very productive conversations.
  27. koolk - IsPlayerinAreaEx code.
  28. TheAlpha - Danish translation.
  29. breadfish - German translation.
  30. Fireburn - Dutch translation.
  31. yom - French translation.
  32. 50p - Polish translation.
  33. Zamaroht - Spanish translation.
  34. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  35. for me to strive to better.
  36. Pixels^ - Running XScripters where the idea was born.
  37. Matite - Pestering me to release it and using it.
  38. Very special thanks to:
  39. Thiadmer - PAWN, whose limits continue to amaze me!
  40. Kye/Kalcor - SA:MP.
  41. SA:MP Team past, present and future - SA:MP.
  42. Version:
  43. 0.1
  44. Changelog:
  45. 02/01/08:
  46. First '08 edit - Fixed minus numbers in spawn points.
  47. 18/11/07:
  48. Improved location compression to allow larger areas.
  49. Moved position code to Class_OnPlayerSpawn to reduce overhead.
  50. 10/10/07:
  51. Fixed spawn data problem.
  52. 31/08/07:
  53. Added cheap master system - YSI_SLAVE_CLASSs can't be master.
  54. 05/08/07:
  55. Fixed a few bugs with repeated selection.
  56. 04/08/07:
  57. First version.
  58. Functions:
  59. Public:
  60. Class_AddRemote - Adds a class to the remote master.
  61. Class_Remote - Updates settings remotely.
  62. Core:
  63. Class_Class - Sets up the system.
  64. Class_OnPlayerRequestSpawn - Called when a player requests a spawn.
  65. Class_OnPlayerRequestClass - Called when a player requests a class.
  66. Class_OnPlayerConnect - Called when a player connects.
  67. Stock:
  68. Class_Delete - Removes a class.
  69. Class_SetPlayer - Sets whether or not a player can use a class.
  70. Class_Disable - Disables a class.
  71. Class_Enable - Enables a disabled class.
  72. Class_AddForGroup - Adds a class to the system for only one group.
  73. Class_Add - Adds a class to the system.
  74. Class_AddEx - Adds a class to the system with group selection and setting.
  75. Class_AddWithGroupSet - Adds a class and sets their group on selection.
  76. Class_AllowReselection - Allows or disallows people to return to reselect a class.
  77. Class_RequireSpawnLogin - Require people to login before spawning.
  78. Class_RequireSelectionLogin - Require people to login before selecting.
  79. Class_RequireSelectionReg - Require people to register before selecting.
  80. Class_RequireSpawnReg - Require people to register before spawning.
  81. Static:
  82. Class_AddClass - Adds a class, wrapped by API and remote functions.
  83. Inline:
  84. Class_IsActive - Checks a class is active.
  85. Class_Enabled - Checks a class is enabled.
  86. Class_IsValid - Checks a class is valid.
  87. Class_X - Gets a classes x position.
  88. Class_Y - Gets a classes y position.
  89. Class_Z - Gets a classes z position.
  90. Class_A - Gets a classes angle.
  91. Class_Skin - Gets a classes skin.
  92. API:
  93. -
  94. Callbacks:
  95. -
  96. Definitions:
  97. MAX_CLASSES - Maximum number of classes storeable by the system.
  98. CLASS_LEFT - Flag for last internal class viewed.
  99. CLASS_MIDDLE - Flag for last internal class viewed.
  100. CLASS_RIGHT - Flag for last internal class viewed.
  101. Enums:
  102. e_CLASS_FLAGS - Small data for individual classes.
  103. E_CLASS - Class data structure.
  104. Macros:
  105. -
  106. Tags:
  107. -
  108. Variables:
  109. Global:
  110. -
  111. Static:
  112. YSI_g_sClasses - Data for classes.
  113. YSI_g_sPlayerClass - Player's current classes.
  114. YSI_g_sLeft - Handle for the first internal class.
  115. YSI_g_sMiddle - Handle for the second internal class.
  116. YSI_g_sRight - Handle for the third internal class.
  117. YSI_g_sClassCount - Number of classes stored.
  118. Commands:
  119. -
  120. Compile options:
  121. -
  122. Operators:
  123. -
  124. \*----------------------------------------------------------------------------*/
  125. #include "y_bit"
  126. #include "y_debug"
  127. #include "y_master"
  128. #include "y_hooks"
  129. #include "y_playerarray"
  130. #include "y_iterate"
  131. #if !defined MAX_CLASSES
  132. #define MAX_CLASSES (256)
  133. #endif
  134. #if !defined MAX_CLASS_SPAWN_WEAPONS
  135. #define MAX_CLASS_SPAWN_WEAPONS (13)
  136. #endif
  137. #if !defined WEAPON_ARMOUR
  138. #define WEAPON_ARMOUR (100)
  139. #endif
  140. #define OnPlayerRequestClassEx(%0) OnPlayerRequestClassEx_(%0)if(!YSI_gOPRCE)return 0;else
  141. #define OnPlayerRequestSpawnEx(%0) OnPlayerRequestSpawnEx_(%0)if(!YSI_gOPRSE)return 0;else
  142. #define INFINATE_ARMOUR (0x00800000)
  143. #define _CLASS_WEAPON_CODE if((n-w)&0x01)while(w!=n&&s<MAX_CLASS_SPAWN_WEAPONS){cw=getarg(w++);if(cw==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);}else while(w!=n&&s<MAX_CLASS_SPAWN_WEAPONS){cw=getarg(w++);if(cw==WEAPON_ARMOUR)weapons[MAX_CLASS_SPAWN_WEAPONS]=WEAPON_ARMOUR|(getarg(w++)<<8);else weapons[s++]=(cw&0xFF)|(getarg(w++)<<8);}
  144. #define _GROUP_MAKE_NAME_CLASSES<%0...%1> %0Class%1
  145. #define _GROUP_MAKE_LIMIT_CLASSES MAX_CLASSES
  146. enum e_CLASS_FLAGS (<<= 1)
  147. {
  148. e_CLASS_FLAGS_SKIN = 0x0000FFFF,
  149. e_CLASS_FLAGS_ACTIVE = 0x01000000,
  150. e_CLASS_FLAGS_ENABLED,
  151. e_CLASS_FLAGS_DEFAULT
  152. }
  153. enum E_CLASS
  154. {
  155. e_CLASS_FLAGS:E_CLASS_FLAGS,
  156. Float:E_CLASS_X,
  157. Float:E_CLASS_Y,
  158. Float:E_CLASS_Z,
  159. Float:E_CLASS_A,
  160. E_CLASS_WEAPONS[MAX_CLASS_SPAWN_WEAPONS + 1],
  161. //#if defined _YSI_SYSTEM_GROUPS
  162. Group:E_CLASS_GROUP,
  163. //#endif
  164. PlayerArray:E_CLASS_PLAYERS<MAX_PLAYERS>
  165. //Bit:E_CLASS_PLAYERS[PLAYER_BIT_ARRAY]
  166. }
  167. enum e_CLASS_OPTION (<<= 1)
  168. {
  169. e_CLASS_OPTION_PAUSED = 0x0000FFFF,
  170. e_CLASS_OPTION_NORE = 0x00010000,
  171. e_CLASS_OPTION_LOGIN_SELECT,
  172. e_CLASS_OPTION_LOGIN_SPAWN,
  173. e_CLASS_OPTION_REG_SELECT,
  174. e_CLASS_OPTION_REG_SPAWN,
  175. e_CLASS_OPTION_HAS_RC_CALLBACK,
  176. e_CLASS_OPTION_HAS_RS_CALLBACK,
  177. e_CLASS_OPTION_REFRESH_PAUSE
  178. }
  179. enum e_PLAYER_CLASS (<<= 1)
  180. {
  181. e_PLAYER_CLASS_SKIN = 0x000FFFFF,
  182. e_PLAYER_CLASS_PRESS = 0x00E00000,
  183. e_PLAYER_CLASS_RIGHT = 0x00200000,
  184. e_PLAYER_CLASS_MIDDLE,
  185. e_PLAYER_CLASS_LEFT,
  186. e_PLAYER_CLASS_EVER, // Has this player EVER spawned?
  187. e_PLAYER_CLASS_DENY, // Is this player not allowed to see class selection?
  188. e_PLAYER_CLASS_SPAWNED, // Should this player NOT be allowed to reselect?
  189. e_PLAYER_CLASS_SELECT,
  190. e_PLAYER_CLASS_RETURN, // Player is returning to class selection.
  191. e_PLAYER_CLASS_AFTER_RETURN, // Prevent the double class selection screen.
  192. e_PLAYER_CLASS_TEMP_SPAWN // Player has spawned once, respawn them.
  193. }
  194. #define e_PLAYER_CLASS_SPAWN_CHECK (e_PLAYER_CLASS_AFTER_RETURN | e_PLAYER_CLASS_TEMP_SPAWN)
  195. #define CLASS_MOVE_LEFT (e_PLAYER_CLASS:-1)
  196. #define CLASS_MOVE_RIGHT (e_PLAYER_CLASS:1)
  197. static stock
  198. YSI_g_sClasses[MAX_CLASSES][E_CLASS],
  199. e_PLAYER_CLASS:YSI_g_sPlayerClass[MAX_PLAYERS],
  200. YSI_g_sLeft,
  201. YSI_g_sMiddle,
  202. YSI_g_sRight,
  203. YSI_g_sClassCount,
  204. e_CLASS_OPTION:YSI_g_sClassOptions,
  205. YSI_g_sLastRefuse[MAX_PLAYERS];
  206. static
  207. bool:YSI_g_sIsFirst = false;
  208. stock
  209. bool:YSI_gOPRCE = true,
  210. bool:YSI_gOPRSE = true;
  211. /*----------------------------------------------------------------------------*\
  212. Function:
  213. Class_IsActive
  214. Params:
  215. classid - Class to check.
  216. Return:
  217. -
  218. Notes:
  219. Checks if a class is currently in use.
  220. \*----------------------------------------------------------------------------*/
  221. #define Class_IsActive(%1) \
  222. (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_ACTIVE)
  223. /*----------------------------------------------------------------------------*\
  224. Function:
  225. Class_Enabled
  226. Params:
  227. classid - Class to check.
  228. Return:
  229. -
  230. Notes:
  231. Checks if a class is currently available for viewing.
  232. \*----------------------------------------------------------------------------*/
  233. #define Class_Enabled(%1) \
  234. (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_ENABLED)
  235. /*----------------------------------------------------------------------------*\
  236. Function:
  237. Class_IsValid
  238. Params:
  239. classid - Class to check.
  240. Return:
  241. -
  242. Notes:
  243. Checks if a number is a valid classid and active.
  244. \*----------------------------------------------------------------------------*/
  245. #define Class_IsValid(%1) \
  246. ((%1) >= 0 && (%1) < MAX_CLASSES && Class_IsActive((%1)))
  247. /*----------------------------------------------------------------------------*\
  248. Function:
  249. Class_X
  250. Params:
  251. classid - Class to get X location for.
  252. Return:
  253. -
  254. Notes:
  255. -
  256. \*----------------------------------------------------------------------------*/
  257. #define Class_X(%1) \
  258. YSI_g_sClasses[(%1)][E_CLASS_X]
  259. //(float(YSI_g_sClasses[(%1)][E_CLASS_XY] >> 16) / 10.0)
  260. /*----------------------------------------------------------------------------*\
  261. Function:
  262. Class_Y
  263. Params:
  264. classid - Class to get Y location for.
  265. Return:
  266. -
  267. Notes:
  268. -
  269. \*----------------------------------------------------------------------------*/
  270. #define Class_Y(%1) \
  271. YSI_g_sClasses[(%1)][E_CLASS_Y]
  272. //(float((YSI_g_sClasses[(%1)][E_CLASS_XY] & 0x7FFF) | ((YSI_g_sClasses[(%1)][E_CLASS_XY] & 0x8000) ? (0xFFFF8000) : (0))) / 10.0)
  273. /*----------------------------------------------------------------------------*\
  274. Function:
  275. Class_Z
  276. Params:
  277. classid - Class to get Z location for.
  278. Return:
  279. -
  280. Notes:
  281. -
  282. \*----------------------------------------------------------------------------*/
  283. #define Class_Z(%1) \
  284. YSI_g_sClasses[(%1)][E_CLASS_Z]
  285. //(float(YSI_g_sClasses[(%1)][E_CLASS_ZA] >> 16) / 10.0)
  286. /*----------------------------------------------------------------------------*\
  287. Function:
  288. Class_A
  289. Params:
  290. classid - Class to get angle for.
  291. Return:
  292. -
  293. Notes:
  294. -
  295. \*----------------------------------------------------------------------------*/
  296. #define Class_A(%1) \
  297. YSI_g_sClasses[(%1)][E_CLASS_A]
  298. //(float((YSI_g_sClasses[(%1)][E_CLASS_ZA] & 0x7FFF) | (YSI_g_sClasses[(%1)][E_CLASS_ZA] & 0x8000) ? (0xFFFF8000) : (0)) / 10.0)
  299. /*----------------------------------------------------------------------------*\
  300. Function:
  301. Class_Skin
  302. Params:
  303. classid - Class to get skin for.
  304. Return:
  305. -
  306. Notes:
  307. -
  308. \*----------------------------------------------------------------------------*/
  309. #define Class_Skin(%1) \
  310. (YSI_g_sClasses[(%1)][E_CLASS_FLAGS] & e_CLASS_FLAGS_SKIN)
  311. //mhook OnScriptInit()
  312. hook OnScriptInit()
  313. {
  314. // This code placement is not generic.
  315. YSI_g_sLeft = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  316. YSI_g_sMiddle = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  317. YSI_g_sRight = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  318. return 1;
  319. }
  320. mhook OnPlayerRequestSpawn(playerid)
  321. {
  322. P:2("hook Class_OnPlayerRequestSpawn called: %d", playerid);
  323. //P:2("Class_OnPlayerRequestSpawn called");
  324. if (YSI_g_sClassCount)
  325. {
  326. P:5("Class_OnPlayerRequestSpawn: Has class count");
  327. new
  328. e_PLAYER_CLASS:playerclass = YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN;
  329. if (!(Class_Enabled(playerclass) && PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid)))
  330. {
  331. // Class_ResumeRefresh(playerid);
  332. return 1;
  333. }
  334. P:5("Class_OnPlayerRequestSpawn: Can spawn");
  335. // Don't need this line anymore - it's all done in OnPlayerRequestClass
  336. // OnPlayerSpawn.
  337. //SetSpawnInfo(playerid, NO_TEAM, Class_Skin(playerclass), Class_X(playerclass), Class_Y(playerclass), Class_Z(playerclass), Class_A(playerclass), 0, 0, 0, 0, 0, 0);
  338. new
  339. time = GetTickCount();
  340. if ((time - YSI_g_sLastRefuse[playerid]) >= 1000)
  341. {
  342. YSI_gOPRSE = false;
  343. CallRemoteFunction("OnPlayerRequestSpawnEx_", "ii", playerid, playerclass);
  344. new
  345. ret = 1;
  346. if (YSI_g_sClassOptions & e_CLASS_OPTION_HAS_RS_CALLBACK)
  347. {
  348. YSI_gOPRSE = true;
  349. ret = CallLocalFunction("OnPlayerRequestSpawnEx_", "ii", playerid, playerclass);
  350. }
  351. P:4("Class_OnPlayerRequestSpawn() return: %d", ret);
  352. if (ret)
  353. {
  354. //#if defined _YSI_SYSTEM_GROUPS
  355. new
  356. Group:newgroup = YSI_g_sClasses[playerclass][E_CLASS_GROUP];
  357. P:4("Class_OnPlayerRequestSpawn() newgroup: %d", _:newgroup);
  358. // if (newgroup != Group:-1) Class_ResolveGroups(playerid, newgroup, true); //Group_AddPlayer(newgroup, playerid);
  359. //#endif
  360. if (ret == 1)
  361. {
  362. //ALS_CALL<PlayerRequestSpawn>
  363. // Class_ResumeRefresh(playerid);
  364. return 1;
  365. }
  366. else if(ret == -1)
  367. {
  368. YSI_g_sPlayerClass[playerid] |= e_PLAYER_CLASS_SKIN;
  369. // The order is VERY important here - this will actually
  370. // call the function further down (directly below in fact).
  371. //OnPlayerRequestClass(playerid, YSI_g_sLeft);
  372. // Class_DoOnPlayerRequestClass(playerid, YSI_g_sLeft);
  373. }
  374. }
  375. }
  376. YSI_g_sLastRefuse[playerid] = time;
  377. // Class_ResumeRefresh(playerid);
  378. P:5("Class_OnPlayerRequestSpawn: Return 0");
  379. return 0;
  380. }
  381. //ALS_CALL<PlayerRequestSpawn>
  382. // Class_ResumeRefresh(playerid);
  383. P:5("Class_OnPlayerRequestSpawn: Return 1");
  384. return 1;
  385. }
  386. /*----------------------------------------------------------------------------*\
  387. Function:
  388. Class_OnPlayerRequestClass
  389. Params:
  390. playerid - Player who requested a class.
  391. class - Class they requested.
  392. Return:
  393. -
  394. Notes:
  395. The input is one of the three real classes used to detect selected
  396. direction of alteration. Scans for a class the player is allowed to use
  397. and hot swaps it out. Uses SetPlayerSkin AND SetSpawnInfo to combat bugs
  398. with calling this from OnPlayerRequestSpawn (e.g. the example team script).
  399. Calls OnPlayerRequestClassEx with the current internal class not the real
  400. one.
  401. \*----------------------------------------------------------------------------*/
  402. static stock e_PLAYER_CLASS:Class_FindNew(playerid, e_PLAYER_CLASS:playerclass, e_PLAYER_CLASS:dir)
  403. {
  404. P:4("e_PLAYER_CLASS:Class_FindNew called: %i, %i, %i", playerid, _:playerclass, _:dir);
  405. if (playerclass >= e_PLAYER_CLASS:YSI_g_sClassCount)
  406. {
  407. playerclass = -dir;
  408. }
  409. new
  410. e_PLAYER_CLASS:old = playerclass;
  411. //do
  412. {
  413. playerclass = (playerclass + dir) % e_PLAYER_CLASS:YSI_g_sClassCount;
  414. //P:4("Class_OnPlayerRequestClass() playerclass: %d", playerclass);
  415. /*if (playerclass < e_PLAYER_CLASS:0)
  416. {
  417. playerclass = e_PLAYER_CLASS:(YSI_g_sClassCount - 1);
  418. }
  419. else if (playerclass >= e_PLAYER_CLASS:YSI_g_sClassCount)
  420. {
  421. playerclass = e_PLAYER_CLASS:0;
  422. }*/
  423. P:4("Class_FindNew: %d %d", playerclass, playerid);
  424. }
  425. //while (playerclass != old && !(Class_Enabled(playerclass) && PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid)));
  426. return playerclass;
  427. }
  428. mhook OnPlayerRequestClass(playerid, classid)
  429. {
  430. P:1("Class_OnPlayerRequestClass called: %d, %d", playerid, classid);
  431. new
  432. e_PLAYER_CLASS:playerclass = YSI_g_sPlayerClass[playerid],
  433. e_PLAYER_CLASS:dir = CLASS_MOVE_RIGHT;
  434. switch (playerclass & e_PLAYER_CLASS_PRESS)
  435. {
  436. case e_PLAYER_CLASS_RIGHT:
  437. {
  438. if (classid == YSI_g_sMiddle)
  439. {
  440. // Went from the right to the middle - that's a move left.
  441. dir = CLASS_MOVE_LEFT;
  442. }
  443. }
  444. case e_PLAYER_CLASS_MIDDLE:
  445. {
  446. if (classid == YSI_g_sLeft)
  447. {
  448. // Went from the middle to the left - that's a move left.
  449. dir = CLASS_MOVE_LEFT;
  450. }
  451. }
  452. default:
  453. {
  454. if (classid == YSI_g_sRight)
  455. {
  456. // Went from the left to the right - that's a wrap move left.
  457. dir = CLASS_MOVE_LEFT;
  458. }
  459. }
  460. }
  461. if (classid == YSI_g_sMiddle) YSI_g_sPlayerClass[playerid] = e_PLAYER_CLASS_MIDDLE;
  462. else if (classid == YSI_g_sLeft) YSI_g_sPlayerClass[playerid] = e_PLAYER_CLASS_LEFT;
  463. else if (classid == YSI_g_sRight) YSI_g_sPlayerClass[playerid] = e_PLAYER_CLASS_RIGHT;
  464. playerclass &= e_PLAYER_CLASS_SKIN;
  465. if (!YSI_g_sClassCount)
  466. {
  467. SetSpawnInfo(playerid, NO_TEAM, 0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  468. SetPlayerSkin(playerid, 0);
  469. P:E("No YSI classes found");
  470. }
  471. else
  472. {
  473. // Find the next available skin for this player. I'm still not sure how
  474. // this handles the case where you can't use any skin. I'll have to
  475. // look in to that.
  476. playerclass = Class_FindNew(playerid, playerclass, dir);
  477. P:5("Class_OnPlayerRequestClass() selected: %d", playerclass);
  478. }
  479. //Class_ResumeRefresh(playerid);
  480. return Class_Goto(playerid, _:playerclass);
  481. //ALS_CALL_EX<PlayerRequestClass, ret>
  482. }
  483. foreign Class_Goto(playerid, playerclass);
  484. global Class_Goto(playerid, playerclass)
  485. {
  486. P:2("Class_Goto called: %i, %i", playerid, playerclass);
  487. // This now sets the REAL spawn information, including spawn location.
  488. // 0.2 code
  489. //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), weapon1 & 0xFF, weapon1 >>> 8, weapon2 & 0xFF, weapon2 >>> 8, weapon3 & 0xFF, weapon3 >>> 8);
  490. // 0.3 code
  491. 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);
  492. SetPlayerSkin(playerid, Class_Skin(e_PLAYER_CLASS:playerclass));
  493. YSI_g_sPlayerClass[playerid] = e_PLAYER_CLASS:playerclass;
  494. // Save the last viewed class so that we know which direction the person
  495. // went next time OnPlayerRequestClass is called.
  496. P:2("Class_Goto() end");
  497. // Call the OnPlayerRequestClassEx functions.
  498. YSI_gOPRCE = false;
  499. CallRemoteFunction("OnPlayerRequestClassEx_", "ii", playerid, playerclass);
  500. if (YSI_g_sClassOptions & e_CLASS_OPTION_HAS_RC_CALLBACK)
  501. {
  502. YSI_gOPRCE = true;
  503. return CallLocalFunction("OnPlayerRequestClassEx_", "ii", playerid, playerclass);
  504. }
  505. return 0;
  506. }
  507. /*----------------------------------------------------------------------------*\
  508. Function:
  509. Class_OnPlayerConnect
  510. Params:
  511. playerid - Player who joined.
  512. Return:
  513. -
  514. Notes:
  515. Resets the player's current class.
  516. \*----------------------------------------------------------------------------*/
  517. mhook OnPlayerConnect(playerid)
  518. {
  519. P:2("Class_OnPlayerConnect called: %d", playerid);
  520. //P:2("Class_OnPlayerConnect called");
  521. YSI_g_sPlayerClass[playerid] = 0;
  522. }
  523. foreign Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,w[],c,Group:f,Group:g);
  524. global Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,w[],c,Group:f,Group:g)
  525. {
  526. P:2("Class_AddClass called: %i, %f, %f, %f, %f, %a, %i, %i, %i", s, x, y, z, a, w, c, _:f, _:g);
  527. new
  528. i;
  529. while (i < MAX_CLASSES)
  530. {
  531. if (!Class_IsActive(i)) break;
  532. i++;
  533. }
  534. if (i == MAX_CLASSES) return -1;
  535. YSI_g_sClasses[i][E_CLASS_FLAGS] = e_CLASS_FLAGS_ACTIVE | e_CLASS_FLAGS_ENABLED | e_CLASS_FLAGS:s;
  536. YSI_g_sClasses[i][E_CLASS_X] = x;
  537. YSI_g_sClasses[i][E_CLASS_Y] = y;
  538. YSI_g_sClasses[i][E_CLASS_Z] = z;
  539. YSI_g_sClasses[i][E_CLASS_A] = a;
  540. new
  541. j;
  542. // This may be better with a memcpy.
  543. while (j < c)
  544. {
  545. P:5("Class_AddClass: weapon %d %d %d", j, c, w[j]);
  546. YSI_g_sClasses[i][E_CLASS_WEAPONS][j] = w[j];
  547. ++j;
  548. }
  549. //Bit_SetAll(YSI_g_sClasses[class][E_CLASS_PLAYERS], false, bits<MAX_PLAYERS>);
  550. PA_FastInit(YSI_g_sClasses[i][E_CLASS_PLAYERS]);
  551. //Class_ResolveGroups(i, f, false);
  552. YSI_g_sClasses[i][E_CLASS_GROUP] = g;
  553. //YSI_g_sClasses[i][E_CLASS_WEAPONS][MAX_CLASS_SPAWN_WEAPONS] = w[MAX_CLASS_SPAWN_WEAPONS];
  554. YSI_g_sClassCount++;
  555. //setproperty(0, "LReqClass", i);
  556. //#if !defined YSI_CLASS_INVERT
  557. // Bit_SetAll(YSI_g_sClasses[i][E_CLASS_PLAYERS], true, bits<MAX_PLAYERS>);
  558. //#endif
  559. return i;
  560. }
  561. /*----------------------------------------------------------------------------*\
  562. Function:
  563. Class_OnPlayerDeath
  564. Params:
  565. playerid - Player who dies.
  566. reason - The reason they died.
  567. Return:
  568. -1 on fake deaths.
  569. Notes:
  570. Catches and hides fake deaths caused by the spawn system. Called first.
  571. \*----------------------------------------------------------------------------*/
  572. // We need this definition as we are using "mhook" instead of "hook", which
  573. // can't handle the extra number used to force a call order.
  574. //#define ALS_R_PlayerDeath0 ALS_R_PlayerDeath
  575. hook OnPlayerDeath0(playerid, killerid, reason)
  576. {
  577. // For consistency all scripts return -1 if the class system thinks this is
  578. // a fake death caused by the weird respawn selection system.
  579. if (YSI_g_sIsFirst)
  580. {
  581. new
  582. ret = Class_DoPlayerDeath(playerid, killerid, reason);
  583. setproperty(8, YSIM_OPDRET, ret);
  584. return ret;
  585. }
  586. return getproperty(8, YSIM_OPDRET);
  587. }
  588. foreign Class_DoPlayerDeath(playerid, killerid, reason);
  589. global Class_DoPlayerDeath(playerid, killerid, reason)
  590. {
  591. P:2("Class_OnPlayerDeath called: %d, %d, %d", playerid, killerid, reason);
  592. #pragma unused killerid, reason
  593. P:2("Class_OnPlayerDeath called");
  594. //new
  595. // time = GetTickCount();
  596. //new
  597. // e_PLAYER_CLASS:playerclass = YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN;
  598. //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);
  599. //return -1;
  600. //if ((YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SPAWN_CHECK) == e_PLAYER_CLASS_SPAWN_CHECK)// || (time - YSI_g_sLastRefuse[playerid]) < 200)
  601. if ((YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_AFTER_RETURN) == e_PLAYER_CLASS_AFTER_RETURN)// || (time - YSI_g_sLastRefuse[playerid]) < 200)
  602. {
  603. P:2("Class_OnPlayerDeath: Inner");
  604. new
  605. e_PLAYER_CLASS:playerclass = YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN;
  606. // Fake death to get the ForceClassSelection out the system.
  607. //SetTimerEx("_Class_DoRespawn", 0, 0, "i", playerid);
  608. //SetPlayerHealth(playerid, 100.0);
  609. if ((YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_TEMP_SPAWN) == e_PLAYER_CLASS_TEMP_SPAWN)
  610. {
  611. 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);
  612. SpawnPlayer(playerid);
  613. YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_AFTER_RETURN | e_PLAYER_CLASS_TEMP_SPAWN);
  614. }
  615. //YSI_g_sLastRefuse[playerid] = time;
  616. // Cancel all other callbacks.
  617. return -1;
  618. }
  619. //TogglePlayerControllable(playerid, false);
  620. if (YSI_g_sClassOptions & e_CLASS_OPTION_NORE)
  621. {
  622. /*new
  623. e_PLAYER_CLASS:playerclass = YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN;
  624. 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);
  625. SpawnPlayer(playerid);
  626. SetPlayerHealth(playerid, 100.0);*/
  627. SetTimerEx("_Class_DoRespawn", 2500, 0, "i", playerid);
  628. //ForceClassSelection(playerid);
  629. }
  630. return 1;
  631. }
  632. /*----------------------------------------------------------------------------*\
  633. Function:
  634. Class_OnPlayerSpawn
  635. Params:
  636. playerid - Player who spawned.
  637. Return:
  638. -
  639. Notes:
  640. Sets a player's position based on skin.
  641. \*----------------------------------------------------------------------------*/
  642. mhook OnPlayerSpawn(playerid)
  643. {
  644. P:2("Class_OnPlayerSpawn called: %d", playerid);
  645. //P:2("Class_OnPlayerSpawn called: %d %d", YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_AFTER_RETURN, e_PLAYER_CLASS_AFTER_RETURN);
  646. if (YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_AFTER_RETURN)
  647. {
  648. // Fake spawn.
  649. //SetPlayer
  650. YSI_g_sPlayerClass[playerid] |= e_PLAYER_CLASS_TEMP_SPAWN;
  651. return -1;
  652. }
  653. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] | e_PLAYER_CLASS_SPAWNED | e_PLAYER_CLASS_EVER) & ~e_PLAYER_CLASS_SELECT;
  654. new
  655. playerclass = YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN,
  656. weapon;
  657. for (new i = 0; i != MAX_CLASS_SPAWN_WEAPONS; ++i)
  658. {
  659. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][i];
  660. //if (weapon == WEAPON_ARMOUR) SetPlayerArmour(playerid, 100.0);
  661. if (weapon)
  662. {
  663. GivePlayerWeapon(playerid, weapon & 0xFF, weapon >>> 8);
  664. }
  665. else
  666. {
  667. break;
  668. }
  669. }
  670. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][MAX_CLASS_SPAWN_WEAPONS];
  671. P:5("Class_OnPlayerSpawn: Armour %d %d %d", weapon, weapon & 0xFF, WEAPON_ARMOUR);
  672. if ((weapon & 0xFF) == WEAPON_ARMOUR)
  673. {
  674. weapon >>>= 8;
  675. if (weapon == 0x00800000)
  676. {
  677. // INFINITY
  678. SetPlayerArmour(playerid, Float:0x7F800000);
  679. }
  680. else
  681. {
  682. SetPlayerArmour(playerid, weapon);
  683. }
  684. }
  685. /*if (YSI_g_sClassOptions & e_CLASS_OPTION_NORE)
  686. {
  687. // Yes, if they're NOT allowed to change class, send them back to class
  688. // selection! This is so the message doesn't appear.
  689. ForceClassSelection(playerid);
  690. }*/
  691. return 1;
  692. }