classcontrol.inc 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  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. 14/04/12:
  46. Readded OnRequestSpawn logic.
  47. Fixed Class_AddWithGroupSet.
  48. Improved GM/FS interaction.
  49. 02/01/08:
  50. First '08 edit - Fixed minus numbers in spawn points.
  51. 18/11/07:
  52. Improved location compression to allow larger areas.
  53. Moved position code to Class_OnPlayerSpawn to reduce overhead.
  54. 10/10/07:
  55. Fixed spawn data problem.
  56. 31/08/07:
  57. Added cheap master system - YSI_SLAVE_CLASSs can't be master.
  58. 05/08/07:
  59. Fixed a few bugs with repeated selection.
  60. 04/08/07:
  61. First version.
  62. Functions:
  63. Public:
  64. Class_AddRemote - Adds a class to the remote master.
  65. Class_Remote - Updates settings remotely.
  66. Core:
  67. Class_Class - Sets up the system.
  68. Class_OnPlayerRequestSpawn - Called when a player requests a spawn.
  69. Class_OnPlayerRequestClass - Called when a player requests a class.
  70. Class_OnPlayerConnect - Called when a player connects.
  71. Stock:
  72. Class_Delete - Removes a class.
  73. Class_SetPlayer - Sets whether or not a player can use a class.
  74. Class_Disable - Disables a class.
  75. Class_Enable - Enables a disabled class.
  76. Class_AddForGroup - Adds a class to the system for only one group.
  77. Class_Add - Adds a class to the system.
  78. Class_AddEx - Adds a class to the system with group selection and setting.
  79. Class_AddWithGroupSet - Adds a class and sets their group on selection.
  80. Class_AllowReselection - Allows or disallows people to return to reselect a class.
  81. Class_RequireSpawnLogin - Require people to login before spawning.
  82. Class_RequireSelectionLogin - Require people to login before selecting.
  83. Class_RequireSelectionReg - Require people to register before selecting.
  84. Class_RequireSpawnReg - Require people to register before spawning.
  85. Static:
  86. Class_AddClass - Adds a class, wrapped by API and remote functions.
  87. Inline:
  88. Class_IsActive - Checks a class is active.
  89. Class_Enabled - Checks a class is enabled.
  90. Class_IsValid - Checks a class is valid.
  91. Class_X - Gets a classes x position.
  92. Class_Y - Gets a classes y position.
  93. Class_Z - Gets a classes z position.
  94. Class_A - Gets a classes angle.
  95. Class_Skin - Gets a classes skin.
  96. API:
  97. -
  98. Callbacks:
  99. -
  100. Definitions:
  101. MAX_CLASSES - Maximum number of classes storeable by the system.
  102. CLASS_LEFT - Flag for last internal class viewed.
  103. CLASS_MIDDLE - Flag for last internal class viewed.
  104. CLASS_RIGHT - Flag for last internal class viewed.
  105. Enums:
  106. e_CLASS_FLAGS - Small data for individual classes.
  107. E_CLASS - Class data structure.
  108. Macros:
  109. -
  110. Tags:
  111. -
  112. Variables:
  113. Global:
  114. -
  115. Static:
  116. YSI_g_sClasses - Data for classes.
  117. YSI_g_sPlayerClass - Player's current classes.
  118. YSI_g_sLeft - Handle for the first internal class.
  119. YSI_g_sMiddle - Handle for the second internal class.
  120. YSI_g_sRight - Handle for the third internal class.
  121. YSI_g_sClassCount - Number of classes stored.
  122. Commands:
  123. -
  124. Compile options:
  125. -
  126. Operators:
  127. -
  128. \**--------------------------------------------------------------------------**/
  129. #if defined _INC_y_classes
  130. #endinput
  131. #endif
  132. #define _INC_y_classes
  133. #include "..\YSI_Internal\y_version"
  134. #if !defined MAX_CLASSES
  135. #define MAX_CLASSES (256)
  136. #endif
  137. #if !defined MAX_CLASS_SPAWN_WEAPONS
  138. #define MAX_CLASS_SPAWN_WEAPONS (13)
  139. #endif
  140. #if !defined WEAPON_ARMOUR
  141. #define WEAPON_ARMOUR (100)
  142. #endif
  143. #include "..\YSI_Data\y_bit"
  144. #include "..\YSI_Core\y_debug"
  145. #include "..\YSI_Data\y_iterate"
  146. #include "..\YSI_Data\y_playerarray"
  147. #include "..\YSI_Data\y_iterate"
  148. #include "..\YSI_Internal\y_natives"
  149. #define MASTER 61
  150. #define YSIM_U_DISABLE
  151. #include "..\YSI_Core\y_master"
  152. #define _GROUP_MAKE_NAME<%0...%1> %0Class%1
  153. #define _GROUP_MAKE_LIMIT MAX_CLASSES
  154. #include "..\YSI_Players\y_groups\_funcs"
  155. #include "..\YSI_Players\y_groups\y_classes"
  156. #include "..\YSI_Coding\y_hooks"
  157. //#define OnPlayerRequestClassEx(%0) OnPlayerRequestClassEx_(%0)if(!YSI_gOPRCE)return 0;else
  158. //#define OnPlayerRequestSpawnEx(%0) OnPlayerRequestSpawnEx_(%0)if(!YSI_gOPRCE)return 0;else
  159. //forward OnPlayerRequestClassEx_(playerid, classid);
  160. //forward OnPlayerRequestSpawnEx_(playerid, classid);
  161. forward _Class_OnPlayerRequestClass(playerid, classid);
  162. forward _Class_OnPlayerRequestSpawn(playerid);
  163. forward _Class_OtherRequestClass(playerid, classid);
  164. forward _Class_OtherRequestSpawn(playerid);
  165. #define INFINATE_ARMOUR (0x00800000)
  166. #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);}
  167. forward Class_ResolveGroups(class, Group:forgroup, bool:cp);
  168. stock _YSI_HAS_y_classes(_do_not_call_me_ever_, _like_never_)
  169. {
  170. P:E("You called _YSI_HAS_y_classes! Bad, don't do that!", _do_not_call_me_ever_, _like_never_);
  171. assert(false);
  172. return 0;
  173. }
  174. enum e_CLASS_FLAGS (<<= 1)
  175. {
  176. e_CLASS_FLAGS_SKIN = 0x0000FFFF,
  177. e_CLASS_FLAGS_ENABLED = 0x00010000,
  178. e_CLASS_FLAGS_ACTIVE
  179. }
  180. enum E_CLASS
  181. {
  182. e_CLASS_FLAGS:E_CLASS_FLAGS,
  183. Float:E_CLASS_X,
  184. Float:E_CLASS_Y,
  185. Float:E_CLASS_Z,
  186. Float:E_CLASS_A,
  187. E_CLASS_WEAPONS[MAX_CLASS_SPAWN_WEAPONS + 1],
  188. Group:E_CLASS_GROUP,
  189. PlayerArray:E_CLASS_PLAYERS<MAX_PLAYERS>
  190. }
  191. enum e_PLAYER_CLASS (<<= 1)
  192. {
  193. e_PLAYER_CLASS_NONE = 0,
  194. e_PLAYER_CLASS_SKIN = 0x000FFFFF,
  195. e_PLAYER_CLASS_PRESS = 0x00700000,
  196. e_PLAYER_CLASS_RIGHT = 0x00100000,
  197. e_PLAYER_CLASS_MIDDLE,
  198. e_PLAYER_CLASS_LEFT,
  199. // Control flags.
  200. e_PLAYER_CLASS_RETURNED, // Back in class selection.
  201. e_PLAYER_CLASS_SPAWNSINCE, // Spawned after class selection.
  202. e_PLAYER_CLASS_DISABLED, // Class selection disabled.
  203. e_PLAYER_CLASS_HADFIRST, // Spawned ever.
  204. e_PLAYER_CLASS_INSTANT, // Sent straight to class selection.
  205. e_PLAYER_CLASS_INSELECT, // In class selection.
  206. e_PLAYER_CLASS_IGNORE_ONCE
  207. }
  208. enum e_CLASS_SETTINGS (<<= 1)
  209. {
  210. e_CLASS_SETTING_NORE = 1,
  211. e_CLASS_SETTING_OPRCE,
  212. e_CLASS_SETTING_OPRSE
  213. }
  214. #define CLASS_MOVE_LEFT (-1)
  215. #define CLASS_MOVE_RIGHT (1)
  216. #define CLASS_MOVE_NONE (0)
  217. static stock
  218. YSI_g_sClasses[MAX_CLASSES][E_CLASS],
  219. e_PLAYER_CLASS:YSI_g_sPlayerClass[MAX_PLAYERS],
  220. YSI_g_sTimer[MAX_PLAYERS],
  221. YSI_g_sLeft,
  222. YSI_g_sMiddle,
  223. YSI_g_sRight,
  224. e_CLASS_SETTINGS:YSI_g_sSettings,
  225. YSI_g_sClassCount,
  226. YSI_g_sHookC,
  227. YSI_g_sHookS,
  228. YSI_g_sLastRefuse[MAX_PLAYERS];
  229. stock
  230. bool:YSI_gOPRCE = true;
  231. stock Class_ResolveGroups(class, Group:forgroup, bool:cp) <YSI_has_groups : n>
  232. {
  233. #pragma unused forgroup
  234. P:2("Class_ResolveGroups<n>: call Resolve %d %d %d", class, _:forgroup, cp);
  235. if (!cp) PA_Init(YSI_g_sClasses[class][E_CLASS_PLAYERS], true);
  236. //else if (forgroup) {}
  237. //Bit_SetAll(YSI_g_sClasses[class][E_CLASS_PLAYERS], true, bits<MAX_PLAYERS>);
  238. }
  239. stock Class_ResolveGroups(class, Group:forgroup, bool:cp) <>
  240. {
  241. #pragma unused forgroup
  242. P:2("Class_ResolveGroups<>: call Resolve %d %d %d", class, _:forgroup, cp);
  243. if (!cp) PA_Init(YSI_g_sClasses[class][E_CLASS_PLAYERS], true);
  244. //else if (forgroup) {}
  245. //Bit_SetAll(YSI_g_sClasses[class][E_CLASS_PLAYERS], true, bits<MAX_PLAYERS>);
  246. }
  247. /**--------------------------------------------------------------------------**\
  248. <summary>Class_IsValid</summary>
  249. <param name="classid">Class to check if valid.</param>
  250. <returns>
  251. -
  252. </returns>
  253. <remarks>
  254. -
  255. </remarks>
  256. \**--------------------------------------------------------------------------**/
  257. #define Class_IsValid(%1) (0<=(%1)<MAX_CLASSES&&Class_IsActive(%1))
  258. /**--------------------------------------------------------------------------**\
  259. <summary>Class_IsValid</summary>
  260. <param name="classid">Class to check if active.</param>
  261. <returns>
  262. -
  263. </returns>
  264. <remarks>
  265. -
  266. </remarks>
  267. \**--------------------------------------------------------------------------**/
  268. #define Class_IsActive(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS]&e_CLASS_FLAGS_ACTIVE)
  269. /**--------------------------------------------------------------------------**\
  270. <summary>Class_Enabled</summary>
  271. <param name="classid">Class to check.</param>
  272. <returns>
  273. -
  274. </returns>
  275. <remarks>
  276. -
  277. </remarks>
  278. \**--------------------------------------------------------------------------**/
  279. #define Class_Enabled(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS]&e_CLASS_FLAGS_ENABLED)
  280. /**--------------------------------------------------------------------------**\
  281. <summary>Class_X</summary>
  282. <param name="classid">Class to get X location for.</param>
  283. <returns>
  284. -
  285. </returns>
  286. <remarks>
  287. -
  288. </remarks>
  289. \**--------------------------------------------------------------------------**/
  290. #define Class_X(%1) YSI_g_sClasses[(%1)][E_CLASS_X]
  291. /**--------------------------------------------------------------------------**\
  292. <summary>Class_Y</summary>
  293. <param name="classid">Class to get Y location for.</param>
  294. <returns>
  295. -
  296. </returns>
  297. <remarks>
  298. -
  299. </remarks>
  300. \**--------------------------------------------------------------------------**/
  301. #define Class_Y(%1) YSI_g_sClasses[(%1)][E_CLASS_Y]
  302. /**--------------------------------------------------------------------------**\
  303. <summary>Class_Z</summary>
  304. <param name="classid">Class to get Z location for.</param>
  305. <returns>
  306. -
  307. </returns>
  308. <remarks>
  309. -
  310. </remarks>
  311. \**--------------------------------------------------------------------------**/
  312. #define Class_Z(%1) YSI_g_sClasses[(%1)][E_CLASS_Z]
  313. /**--------------------------------------------------------------------------**\
  314. <summary>Class_A</summary>
  315. <param name="classid">Class to get angle for.</param>
  316. <returns>
  317. -
  318. </returns>
  319. <remarks>
  320. -
  321. </remarks>
  322. \**--------------------------------------------------------------------------**/
  323. #define Class_A(%1) YSI_g_sClasses[(%1)][E_CLASS_A]
  324. /**--------------------------------------------------------------------------**\
  325. <summary>Class_Skin</summary>
  326. <param name="classid">Class to get skin for.</param>
  327. <returns>
  328. -
  329. </returns>
  330. <remarks>
  331. -
  332. </remarks>
  333. \**--------------------------------------------------------------------------**/
  334. #define Class_Skin(%1) (YSI_g_sClasses[(%1)][E_CLASS_FLAGS]&e_CLASS_FLAGS_SKIN)
  335. /**--------------------------------------------------------------------------**\
  336. <summary>Class_Class</summary>
  337. <returns>
  338. -
  339. </returns>
  340. <remarks>
  341. Creates three real player classes so you can scroll correctly with the
  342. direction being detected.
  343. </remarks>
  344. \**--------------------------------------------------------------------------**/
  345. hook OnScriptInit()
  346. {
  347. #if !_YSIM_IS_CLIENT
  348. if (!YSI_FILTERSCRIPT)
  349. {
  350. // This code placement is not generic.
  351. YSI_g_sLeft = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  352. YSI_g_sMiddle = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  353. YSI_g_sRight = AddPlayerClass(0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  354. //printf("==========================");
  355. //printf("%d %d %d", YSI_g_sLeft, YSI_g_sMiddle, YSI_g_sRight);
  356. //printf("==========================");
  357. YSI_g_sSettings = ((funcidx("OnPlayerRequestClassEx_") == -1) ? (e_CLASS_SETTINGS:0) : (e_CLASS_SETTING_OPRCE)) | ((funcidx("OnPlayerRequestSpawnEx_") == -1) ? (e_CLASS_SETTINGS:0) : (e_CLASS_SETTING_OPRSE));
  358. #if !defined YSI_NO_MASTER
  359. // Steal the master system.
  360. _Master_Get(#_YCM, true);
  361. #if _YSIM_IS_CLOUD
  362. // Set to uninitialised.
  363. state _YCM:u;
  364. //_YCM = _YCM@u;
  365. _YCM@ = _E_YCM@u;
  366. #endif
  367. CallRemoteFunction(#_YCM, "");
  368. #if _YSIM_IS_CLOUD
  369. // Fully master.
  370. state _YCM:y;
  371. //_YCM = _YCM@y;
  372. _YCM@ = _E_YCM@y;
  373. #endif
  374. #endif
  375. }
  376. #endif
  377. //Hooks_RedirectPublic("OnPlayerRequestClass", "_Class_OnPlayerRequestClass");
  378. //Hooks_RedirectPublic("OnPlayerRequestSpawn", "_Class_OnPlayerRequestSpawn");
  379. YSI_g_sHookC = Hooks_RedirectPublic("OnPlayerRequestClass", "_Class_OnPlayerRequestClass");
  380. YSI_g_sHookS = Hooks_RedirectPublic("OnPlayerRequestSpawn", "_Class_OnPlayerRequestSpawn");
  381. return 1;
  382. }
  383. /**--------------------------------------------------------------------------**\
  384. <summary>Class_OnPlayerRequestClass</summary>
  385. <param name="playerid">Player who requested a class.</param>
  386. <param name="class">Class they requested.</param>
  387. <returns>
  388. -
  389. </returns>
  390. <remarks>
  391. The input is one of the three real classes used to detect selected
  392. direction of alteration. Scans for a class the player is allowed to use
  393. and hot swaps it out. Uses SetPlayerSkin AND SetSpawnInfo to combat bugs
  394. with calling this from OnPlayerRequestSpawn (e.g. the example team script).
  395. Calls OnPlayerRequestClassEx with the current internal class not the real
  396. one.
  397. </remarks>
  398. \**--------------------------------------------------------------------------**/
  399. static stock Class_FindNew(playerid, playerclass, dir)
  400. {
  401. P:4("Class_FindNew called: %i, %i, %i", playerid, playerclass, dir);
  402. // Handles the special case where "dir" = 0 very nicely with no extra code
  403. // slowing down the common case (as it should be)! This is simply because
  404. // "playerclass != old" will fail on the first loop with "+ 0";
  405. new
  406. old = playerclass % YSI_g_sClassCount;
  407. do
  408. {
  409. playerclass = (playerclass + dir) % YSI_g_sClassCount;
  410. P:4("Class_FindNew: %d %d", playerclass, playerid);
  411. }
  412. while (playerclass != old && (!Class_Enabled(playerclass) || !PA_Get(YSI_g_sClasses[playerclass][E_CLASS_PLAYERS], playerid)));
  413. return playerclass;
  414. }
  415. public _Class_OtherRequestClass(playerid, classid)
  416. {
  417. if (YSI_g_sHookC)
  418. {
  419. #emit PUSH.S classid
  420. #emit PUSH.S playerid
  421. #emit PUSH.C 8
  422. #emit LCTRL 6
  423. #emit ADD.C 28
  424. #emit PUSH.pri
  425. #emit LOAD.pri YSI_g_sHookC
  426. #emit SCTRL 6
  427. #emit RETN
  428. }
  429. }
  430. #if !defined YSI_NO_MASTER && _YSIM_IS_CLIENT
  431. public _Class_OnPlayerRequestClass(playerid, classid)
  432. {
  433. return 1;
  434. }
  435. #else
  436. #if !defined YSI_NO_MASTER && _YSIM_IS_CLOUD
  437. //mhook OnPlayerRequestClass(playerid, classid)
  438. public _Class_OnPlayerRequestClass(playerid, classid) <>
  439. {
  440. return 1;
  441. }
  442. //mhook OnPlayerRequestClass(playerid, classid)
  443. public _Class_OnPlayerRequestClass(playerid, classid) <_YCM:y>
  444. {
  445. #else
  446. //mhook OnPlayerRequestClass(playerid, classid)
  447. public _Class_OnPlayerRequestClass(playerid, classid)
  448. {
  449. #endif
  450. if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_IGNORE_ONCE))
  451. {
  452. SetTimerEx("_Class_SpawnPlayer3", 10, 0, "i", playerid);
  453. return 1;
  454. }
  455. P:1("_Class_OnPlayerRequestClass called: %d %d", playerid, classid);
  456. Class_TK(playerid);
  457. new
  458. dir = CLASS_MOVE_RIGHT;
  459. // Spawned from returning to class selection but not meant to.
  460. //P:5("Class_OnPlayerRequestClass(): Spawn check %d %d", playerclass, playerclass); //(playerclass & e_PLAYER_CLASS_SPAWN_CHECK), e_PLAYER_CLASS_SPAWN_CHECK);
  461. // Find which direction they pressed.
  462. switch (YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_PRESS)
  463. {
  464. case e_PLAYER_CLASS_RIGHT:
  465. {
  466. if (classid == YSI_g_sMiddle)
  467. {
  468. // Went from the right to the middle - that's a move left.
  469. dir = CLASS_MOVE_LEFT;
  470. }
  471. else if (classid != YSI_g_sLeft)
  472. {
  473. dir = CLASS_MOVE_NONE;
  474. }
  475. }
  476. case e_PLAYER_CLASS_MIDDLE:
  477. {
  478. if (classid == YSI_g_sLeft)
  479. {
  480. // Went from the middle to the left - that's a move left.
  481. dir = CLASS_MOVE_LEFT;
  482. }
  483. else if (classid != YSI_g_sRight)
  484. {
  485. dir = CLASS_MOVE_NONE;
  486. }
  487. }
  488. default:
  489. {
  490. if (classid == YSI_g_sRight)
  491. {
  492. // Went from the left to the right - that's a wrap move left.
  493. dir = CLASS_MOVE_LEFT;
  494. }
  495. else if (classid != YSI_g_sMiddle)
  496. {
  497. dir = CLASS_MOVE_NONE;
  498. }
  499. }
  500. }
  501. // Store which class they are now on.
  502. //printf("%d %d %d %d", classid, YSI_g_sMiddle, YSI_g_sLeft, YSI_g_sRight);
  503. if (classid == YSI_g_sMiddle)
  504. {
  505. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~e_PLAYER_CLASS_PRESS) | e_PLAYER_CLASS_MIDDLE | e_PLAYER_CLASS_INSELECT;
  506. }
  507. else if (classid == YSI_g_sLeft)
  508. {
  509. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~e_PLAYER_CLASS_PRESS) | e_PLAYER_CLASS_LEFT | e_PLAYER_CLASS_INSELECT;
  510. }
  511. else if (classid == YSI_g_sRight)
  512. {
  513. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~e_PLAYER_CLASS_PRESS) | e_PLAYER_CLASS_RIGHT | e_PLAYER_CLASS_INSELECT;
  514. }
  515. P:C(else {P:E("y_classes unidentified classid.");YSI_g_sPlayerClass[playerid] |= e_PLAYER_CLASS_INSELECT;});
  516. classid = (YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN);
  517. if (YSI_g_sClassCount)
  518. {
  519. // Find the next available skin for this player. I'm still not sure how
  520. // this handles the case where you can't use any skin. I'll have to
  521. // look in to that.
  522. // Don't want to get stuck constantly adding "0".
  523. classid = Class_FindNew(playerid, classid, dir);
  524. P:5("Class_OnPlayerRequestClass() selected: %d", classid);
  525. Class_Goto(playerid, _:classid);
  526. }
  527. else
  528. {
  529. SetSpawnInfo(playerid, NO_TEAM, 0, 1958.0, 1343.0, 15.0, 269.0, 0, 0, 0, 0, 0, 0);
  530. SetPlayerSkin(playerid, 0);
  531. P:E("No YSI classes found");
  532. classid = -1;
  533. }
  534. // Now sort out if they actually should be spawned.
  535. /*if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_IGNORE_ONCE))
  536. {
  537. YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_IGNORE_ONCE);
  538. return 1;
  539. }
  540. else*/
  541. if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_SPAWNSINCE) == (e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_SPAWNSINCE))
  542. {
  543. YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_SPAWNSINCE);
  544. Class_Spectate(playerid);
  545. //SpawnPlayer(playerid);
  546. //printf("0");
  547. SetTimerEx("_Class_SpawnPlayer2", 10, 0, "i", playerid);
  548. YSI_g_sTimer[playerid] = SetTimerEx("_Class_SpawnPlayer4", 50, 0, "i", playerid);
  549. /*if (YSI_g_sHookC)
  550. {
  551. #emit PUSH.C 0xFFFFFFFF
  552. #emit PUSH.S playerid
  553. #emit PUSH.C 8
  554. #emit LCTRL 6
  555. #emit ADD.C 28
  556. #emit PUSH.pri
  557. #emit LOAD.pri YSI_g_sHookC
  558. #emit SCTRL 6
  559. //#emit RETN
  560. }*/
  561. CallRemoteFunction("_Class_OtherRequestClass", "ii", playerid, -1);
  562. }
  563. else if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_DISABLED | e_PLAYER_CLASS_HADFIRST) == (e_PLAYER_CLASS_DISABLED | e_PLAYER_CLASS_HADFIRST))
  564. {
  565. // If class selection is disabled for this player, they have already selected
  566. // a class and we haven't manually sent them back to the menu.
  567. //YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_SPAWNSINCE);
  568. Class_Spectate(playerid);
  569. //SpawnPlayer(playerid);
  570. //printf("1");
  571. SetTimerEx("_Class_SpawnPlayer1", 10, 0, "i", playerid);
  572. /*if (YSI_g_sHookC)
  573. {
  574. #emit PUSH.C 0xFFFFFFFF
  575. #emit PUSH.S playerid
  576. #emit PUSH.C 8
  577. #emit LCTRL 6
  578. #emit ADD.C 28
  579. #emit PUSH.pri
  580. #emit LOAD.pri YSI_g_sHookC
  581. #emit SCTRL 6
  582. //#emit RETN
  583. }*/
  584. CallRemoteFunction("_Class_OtherRequestClass", "ii", playerid, -1);
  585. }
  586. else
  587. {
  588. /*if (YSI_g_sHookC)
  589. {
  590. #emit PUSH.S classid
  591. #emit PUSH.S playerid
  592. #emit PUSH.C 8
  593. #emit LCTRL 6
  594. #emit ADD.C 28
  595. #emit PUSH.pri
  596. #emit LOAD.pri YSI_g_sHookC
  597. #emit SCTRL 6
  598. //#emit RETN
  599. }*/
  600. CallRemoteFunction("_Class_OtherRequestClass", "ii", playerid, classid);
  601. }
  602. return 1;
  603. }
  604. #endif
  605. foreign void:Class_Goto(playerid, playerclass);
  606. global void:Class_Goto(playerid, playerclass)
  607. {
  608. P:2("Class_Goto called: %i, %i", playerid, playerclass);
  609. // This now sets the REAL spawn information, including spawn location.
  610. 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);
  611. SetPlayerSkin(playerid, Class_Skin(e_PLAYER_CLASS:playerclass));
  612. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~(e_PLAYER_CLASS_SKIN)) | (e_PLAYER_CLASS:playerclass);
  613. // Save the last viewed class so that we know which direction the person
  614. // went next time OnPlayerRequestClass is called.
  615. P:2("Class_Goto() end %08h %08h %d", YSI_g_sSettings, _:e_CLASS_SETTING_OPRCE, playerclass);
  616. //return 1;
  617. }
  618. /**--------------------------------------------------------------------------**\
  619. <summary>Class_OnPlayerRequestSpawn</summary>
  620. <param name="playerid">Player who selected a spawn.</param>
  621. <returns>
  622. -
  623. </returns>
  624. <remarks>
  625. Has inbuilt protection for a bug where selections aren't correctly
  626. debounced so you can press shift twice at once which can mess up some
  627. scripts (e.g. the example team selection script). Calls
  628. OnPlayerRequestSpawnEx with an additional class parameter.
  629. </remarks>
  630. \**--------------------------------------------------------------------------**/
  631. public _Class_OtherRequestSpawn(playerid)
  632. {
  633. if (YSI_g_sHookS)
  634. {
  635. #emit PUSH.S playerid
  636. #emit PUSH.C 4
  637. #emit LCTRL 6
  638. #emit ADD.C 28
  639. #emit PUSH.pri
  640. #emit LOAD.pri YSI_g_sHookS
  641. #emit SCTRL 6
  642. #emit RETN
  643. }
  644. }
  645. //mhook OnPlayerRequestSpawn(playerid)
  646. #if !defined YSI_NO_MASTER && (_YSIM_IS_CLIENT || _YSIM_IS_STUB)
  647. public _Class_OnPlayerRequestSpawn(playerid)
  648. {
  649. return 1;
  650. }
  651. #else
  652. #if !defined YSI_NO_MASTER && _YSIM_IS_CLOUD
  653. //mhook OnPlayerRequestClass(playerid, classid)
  654. public _Class_OnPlayerRequestSpawn(playerid) <>
  655. {
  656. return 1;
  657. }
  658. //mhook OnPlayerRequestClass(playerid, classid)
  659. public _Class_OnPlayerRequestSpawn(playerid) <_YCM:y>
  660. {
  661. #else
  662. //mhook OnPlayerRequestClass(playerid, classid)
  663. public _Class_OnPlayerRequestSpawn(playerid)
  664. {
  665. #endif
  666. P:2("hook Class_OnPlayerRequestSpawn called: %d", playerid);
  667. new
  668. time = GetTickCount();
  669. if ((time - YSI_g_sLastRefuse[playerid]) >= 1000)
  670. {
  671. //YSI_gOPRSE = false;
  672. //new
  673. // ret = 1;
  674. //if (YSI_g_sClassOptions & e_CLASS_OPTION_HAS_RS_CALLBACK)
  675. //{
  676. // YSI_gOPRSE = true;
  677. // ret = CallLocalFunction("OnPlayerRequestSpawnEx_", "ii", playerid, playerclass);
  678. //}
  679. new
  680. ret = CallRemoteFunction("_Class_OtherRequestSpawn", "i", playerid);
  681. P:4("Class_OnPlayerRequestSpawn() return: %d", ret);
  682. if (ret)
  683. {
  684. //#if defined _YSI_SYSTEM_GROUPS
  685. new
  686. Group:newgroup = YSI_g_sClasses[(YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN)][E_CLASS_GROUP];
  687. P:4("Class_OnPlayerRequestSpawn() newgroup: %d", _:newgroup);
  688. if (newgroup != Group:-1) Class_ResolveGroups(playerid, newgroup, true); //Group_AddPlayer(newgroup, playerid);
  689. //#endif
  690. if (ret == -1)
  691. {
  692. YSI_g_sPlayerClass[playerid] |= e_PLAYER_CLASS_SKIN;
  693. // The order is VERY important here - this will actually
  694. // call the function further down (directly below in fact).
  695. //OnPlayerRequestClass(playerid, YSI_g_sLeft);
  696. //Class_DoOnPlayerRequestClass(playerid, YSI_g_sLeft);
  697. switch (YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_PRESS)
  698. {
  699. case e_PLAYER_CLASS_RIGHT:
  700. {
  701. _Class_OnPlayerRequestClass(playerid, YSI_g_sLeft);
  702. }
  703. case e_PLAYER_CLASS_MIDDLE:
  704. {
  705. _Class_OnPlayerRequestClass(playerid, YSI_g_sRight);
  706. }
  707. case e_PLAYER_CLASS_LEFT:
  708. {
  709. _Class_OnPlayerRequestClass(playerid, YSI_g_sMiddle);
  710. }
  711. }
  712. }
  713. else
  714. {
  715. return 1;
  716. }
  717. }
  718. }
  719. YSI_g_sLastRefuse[playerid] = time;
  720. //Class_ResumeRefresh(playerid);
  721. P:5("Class_OnPlayerRequestSpawn: Return 0");
  722. return 0;
  723. }
  724. #endif
  725. /**--------------------------------------------------------------------------**\
  726. <summary>Class_OnPlayerSpawn</summary>
  727. <param name="playerid">Player who spawned.</param>
  728. <returns>
  729. -
  730. </returns>
  731. <remarks>
  732. Sets a player's position based on skin.
  733. </remarks>
  734. \**--------------------------------------------------------------------------**/
  735. mhook OnPlayerSpawn(playerid)
  736. {
  737. P:2("Class_OnPlayerSpawn called: %d", playerid);
  738. Class_TK(playerid);
  739. new
  740. playerclass = _:(YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN),
  741. weapon;
  742. //YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~(e_PLAYER_CLASS_NOT_FIRST | e_PLAYER_CLASS_ALLOW_ONE)) | e_PLAYER_CLASS_HAS_EVER_SPAWNED | e_PLAYER_CLASS_IS_SPAWNED;
  743. for (new i = 0; i != MAX_CLASS_SPAWN_WEAPONS; ++i)
  744. {
  745. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][i];
  746. //if (weapon == WEAPON_ARMOUR) SetPlayerArmour(playerid, 100.0);
  747. if (weapon)
  748. {
  749. GivePlayerWeapon(playerid, weapon & 0xFF, weapon >>> 8);
  750. }
  751. else
  752. {
  753. break;
  754. }
  755. }
  756. weapon = YSI_g_sClasses[playerclass][E_CLASS_WEAPONS][MAX_CLASS_SPAWN_WEAPONS];
  757. P:5("Class_OnPlayerSpawn: Armour %d %d %d", weapon, weapon & 0xFF, WEAPON_ARMOUR);
  758. if ((weapon & 0xFF) == WEAPON_ARMOUR)
  759. {
  760. weapon >>>= 8;
  761. if (weapon == 0x00800000)
  762. {
  763. // INFINITY
  764. SetPlayerArmour(playerid, Float:0x7F800000);
  765. }
  766. else
  767. {
  768. SetPlayerArmour(playerid, weapon);
  769. }
  770. }
  771. // Now update reselection variables.
  772. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] & ~(e_PLAYER_CLASS_INSELECT | e_PLAYER_CLASS_IGNORE_ONCE)) | (e_PLAYER_CLASS_HADFIRST);
  773. if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_RETURNED))
  774. {
  775. if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_INSTANT))
  776. {
  777. YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_SPAWNSINCE);
  778. }
  779. else
  780. {
  781. YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_RETURNED);
  782. }
  783. }
  784. //if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_DISABLED))
  785. //{
  786. // I know it may seem odd to force class selection when it is explicitly
  787. // disabled, but this will disable the "F4" message too.
  788. //ForceClassSelection(playerid);
  789. //}
  790. return 1;
  791. }
  792. forward _Class_SpawnPlayer1(playerid);
  793. public _Class_SpawnPlayer1(playerid)
  794. {
  795. P:1("_Class_SpawnPlayer1 called: %d", playerid);
  796. //SpawnPlayer(playerid);
  797. YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_IGNORE_ONCE);
  798. TogglePlayerSpectating(playerid, false);
  799. //SpawnPlayer(playerid);
  800. //YSI_g_sTimer[playerid] = SetTimerEx("_Class_SpawnPlayer3", 20, 0, "i", playerid);
  801. //Class_TK(playerid);
  802. }
  803. forward _Class_SpawnPlayer2(playerid);
  804. public _Class_SpawnPlayer2(playerid)
  805. {
  806. P:1("_Class_SpawnPlayer2 called: %d", playerid);
  807. //SpawnPlayer(playerid);
  808. //YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_IGNORE_ONCE);
  809. TogglePlayerSpectating(playerid, false);
  810. //Class_TK(playerid);
  811. }
  812. forward _Class_SpawnPlayer3(playerid);
  813. public _Class_SpawnPlayer3(playerid)
  814. {
  815. P:1("_Class_SpawnPlayer3 called: %d", playerid);
  816. SpawnPlayer(playerid);
  817. //Class_TK(playerid);
  818. //YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_IGNORE_ONCE);
  819. //TogglePlayerSpectating(playerid, false);
  820. //Class_TK(playerid);
  821. }
  822. forward _Class_SpawnPlayer4(playerid);
  823. public _Class_SpawnPlayer4(playerid)
  824. {
  825. P:1("_Class_SpawnPlayer4 called: %d", playerid);
  826. //SpawnPlayer(playerid);
  827. Class_Spectate(playerid);
  828. if (YSI_g_sPlayerClass[playerid] & (e_PLAYER_CLASS_DISABLED))
  829. {
  830. YSI_g_sTimer[playerid] = SetTimerEx("_Class_SpawnPlayer1", 10, 0, "i", playerid);
  831. }
  832. else
  833. {
  834. YSI_g_sTimer[playerid] = SetTimerEx("_Class_SpawnPlayer2", 10, 0, "i", playerid);
  835. }
  836. //Class_TK(playerid);
  837. //YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_IGNORE_ONCE);
  838. //TogglePlayerSpectating(playerid, false);
  839. //Class_TK(playerid);
  840. }
  841. forward _Class_Return(playerid);
  842. public _Class_Return(playerid)
  843. {
  844. P:1("_Class_Return called: %d", playerid);
  845. Class_ReturnToSelection(playerid);
  846. //Class_TK(playerid);
  847. //YSI_g_sTimer[playerid] = SetTimerEx("_Class_NotSpawned", 500, 0, "i", playerid);
  848. }
  849. forward _Class_NotSpawned(playerid);
  850. public _Class_NotSpawned(playerid)
  851. {
  852. P:1("_Class_NotSpawned called: %d", playerid);
  853. // Called if they don't connect properly.
  854. Class_DisableSelection(playerid);
  855. //SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
  856. //SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
  857. SetTimerEx("_Class_Return", 10, 0, "i", playerid);
  858. YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_RETURNED | e_PLAYER_CLASS_INSTANT);
  859. }
  860. static stock Class_TK(playerid)
  861. {
  862. // "Timer Kill".
  863. if (YSI_g_sTimer[playerid])
  864. {
  865. KillTimer(YSI_g_sTimer[playerid]);
  866. YSI_g_sTimer[playerid] = 0;
  867. }
  868. }
  869. mhook OnPlayerConnect(playerid)
  870. {
  871. //printf("OnPlayerConnect %d", playerid);
  872. YSI_g_sPlayerClass[playerid] = (e_PLAYER_CLASS_NONE);
  873. YSI_g_sTimer[playerid] = SetTimerEx("_Class_NotSpawned", 500, 0, "i", playerid);
  874. NO_GROUPS()
  875. {
  876. new
  877. slot = Bit_Slot(playerid) + 1,
  878. Bit:mask = Bit_Mask(playerid); //Bit:(1 << (playerid & (cellbits - 1)));
  879. for (new i = 0; i != MAX_CLASSES; ++i)
  880. {
  881. YSI_g_sClasses[i][E_CLASS_PLAYERS][slot] |= mask;
  882. }
  883. }
  884. return 1;
  885. }
  886. /*mhook OnPlayerDeath(playerid, killerid, reason)
  887. {
  888. }
  889. mhook OnPlayerRequestSpawn(playerid)
  890. {
  891. }
  892. mhook OnPlayerDisconnect(playerid, reason)
  893. {
  894. }*/
  895. /**--------------------------------------------------------------------------**\
  896. <summary>Class_Add</summary>
  897. <param name="skin">Skin of the class.</param>
  898. <param name="Float:x">X spawn location.</param>
  899. <param name="Float:y">Y spawn location.</param>
  900. <param name="Float:z">Z spawn location.</param>
  901. <param name="Float:a">A spawn location.</param>
  902. <param name="...">Spawn weapons and ammo (weapon then ammo)</param>
  903. <returns>
  904. -
  905. </returns>
  906. <remarks>
  907. Pretty much AddPlayerClass but allows greater control over the classes.
  908. Now has infinate (MAX_CLASS_SPAWN_WEAPONS) spawn weapons. This is one of
  909. the few API functions which is not entirely remote. This is because it has
  910. variable parameters which is need to collect in to a single array to pass to
  911. the remote function.
  912. </remarks>
  913. \**--------------------------------------------------------------------------**/
  914. stock Class_Add(skin, Float:x, Float:y, Float:z, Float:a, ...)
  915. {
  916. //printf("Class_Add called: %i, %f, %f, %f, %f, (+%i)", skin, x, y, z, a, numargs() - 5);
  917. P:3("Class_Add called: %i, %f, %f, %f, %f, (+%i)", skin, x, y, z, a, numargs() - 5);
  918. new
  919. n = numargs(),
  920. w = 5,
  921. s,
  922. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  923. cw;
  924. _CLASS_WEAPON_CODE
  925. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, Group:-1, Group:-1);
  926. }
  927. /**--------------------------------------------------------------------------**\
  928. <summary>Class_AddEx</summary>
  929. <param name="forgroup">Group that can use the skin.</param>
  930. <param name="setgroup">Group to add the player to on selection.</param>
  931. <param name="skin">Skin of the class.</param>
  932. <param name="Float:x">X spawn location.</param>
  933. <param name="Float:y">Y spawn location.</param>
  934. <param name="Float:z">Z spawn location.</param>
  935. <param name="Float:a">A spawn location.</param>
  936. <param name="...">Spawn weapons and ammo (weapon then ammo)</param>
  937. <returns>
  938. -
  939. </returns>
  940. <remarks>
  941. Pretty much AddPlayerClass but allows greater control over the classes.
  942. Now has infinate (MAX_CLASS_SPAWN_WEAPONS) spawn weapons.
  943. </remarks>
  944. \**--------------------------------------------------------------------------**/
  945. stock Class_AddEx(Group:forgroup, Group:setgroup, skin, Float:x, Float:y, Float:z, Float:a, ...)
  946. {
  947. P:3("Class_AddEx called: %i, %i, %i, %f, %f, %f, %f (+%i)", _:forgroup, _:setgroup, skin, x, y, z, a, numargs() - 7);
  948. new
  949. n = numargs(),
  950. w = 7,
  951. s,
  952. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  953. cw;
  954. _CLASS_WEAPON_CODE
  955. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, forgroup, setgroup);
  956. }
  957. /**--------------------------------------------------------------------------**\
  958. <summary>Class_AddForGroup</summary>
  959. <param name="group">Group to allow to use the class.</param>
  960. <param name="skin">Skin of the class.</param>
  961. <param name="Float:x">X spawn location.</param>
  962. <param name="Float:y">Y spawn location.</param>
  963. <param name="Float:z">Z spawn location.</param>
  964. <param name="Float:a">A spawn location.</param>
  965. <param name="...">Weapon data.</param>
  966. <returns>
  967. -
  968. </returns>
  969. <remarks>
  970. Adds a class only people in the specified group can use.
  971. </remarks>
  972. \**--------------------------------------------------------------------------**/
  973. stock Class_AddForGroup(Group:group, skin, Float:x, Float:y, Float:z, Float:a, ...)
  974. {
  975. P:3("Class_AddForGroup called: %i, %i, %f, %f, %f, %f (+%i)", _:group, skin, x, y, z, a, numargs() - 6);
  976. new
  977. n = numargs(),
  978. w = 6,
  979. s,
  980. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  981. cw;
  982. _CLASS_WEAPON_CODE
  983. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, group, Group:-1);
  984. }
  985. /**--------------------------------------------------------------------------**\
  986. <summary>Class_AddWithGroupSet</summary>
  987. <param name="group">Group to make players who use this group.</param>
  988. <param name="skin">Skin of the class.</param>
  989. <param name="Float:x">X spawn location.</param>
  990. <param name="Float:y">Y spawn location.</param>
  991. <param name="Float:z">Z spawn location.</param>
  992. <param name="Float:a">A spawn location.</param>
  993. <param name="...">Spawn weapons.</param>
  994. <returns>
  995. -
  996. </returns>
  997. <remarks>
  998. Adds a class which puts you in the specified group when selected.
  999. </remarks>
  1000. \**--------------------------------------------------------------------------**/
  1001. stock Class_AddWithGroupSet(Group:group, skin, Float:x, Float:y, Float:z, Float:a, ...)
  1002. {
  1003. P:3("Class_AddWithGroupSet called: %i, %i, %f, %f, %f, %f (+%i)", _:group, skin, x, y, z, a, numargs() - 6);
  1004. new
  1005. n = numargs(),
  1006. w = 6,
  1007. s,
  1008. weapons[MAX_CLASS_SPAWN_WEAPONS + 1],
  1009. cw;
  1010. _CLASS_WEAPON_CODE
  1011. return Class_AddClass(skin, x, y, z, a, weapons, MAX_CLASS_SPAWN_WEAPONS + 1, Group:-1, group);
  1012. }
  1013. /**--------------------------------------------------------------------------**\
  1014. <summary>Class_AddClass</summary>
  1015. <param name="skin">Skin of the class.</param>
  1016. <param name="Float:x">X spawn location.</param>
  1017. <param name="Float:y">Y spawn location.</param>
  1018. <param name="Float:z">Z spawn location.</param>
  1019. <param name="Float:a">A spawn location.</param>
  1020. <param name="weapons[]">Array of spawn weapon data.</param>
  1021. <param name="count">Number of weapons added.</param>
  1022. <param name="forgroup">Group that can use the class.</param>
  1023. <param name="asgroup">Group to assign people to with this class.</param>
  1024. <returns>
  1025. -
  1026. </returns>
  1027. <remarks>
  1028. Does the hard work. This took a long time to get working correctly with the
  1029. new master system, infact getting just this one function to compile took a
  1030. major re-working of the macros to reduce the length of intermediate stages.
  1031. </remarks>
  1032. \**--------------------------------------------------------------------------**/
  1033. foreign Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,w[],c,Group:f,Group:g);
  1034. global Class_AddClass(s,Float:x,Float:y,Float:z,Float:a,w[],c,Group:f,Group:g)
  1035. {
  1036. //printf("Class_AddClass called: %i, %f, %f, %f, %f, %s, %i, %i, %i", s, x, y, z, a, Debug_PrintArray(w, c), c, _:f, _:g);
  1037. 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);
  1038. new
  1039. i;
  1040. while (i < MAX_CLASSES)
  1041. {
  1042. if (!Class_IsActive(i)) break;
  1043. i++;
  1044. }
  1045. if (i == MAX_CLASSES) return -1;
  1046. YSI_g_sClasses[i][E_CLASS_FLAGS] = e_CLASS_FLAGS_ACTIVE | e_CLASS_FLAGS_ENABLED | e_CLASS_FLAGS:s;
  1047. YSI_g_sClasses[i][E_CLASS_X] = x;
  1048. YSI_g_sClasses[i][E_CLASS_Y] = y;
  1049. YSI_g_sClasses[i][E_CLASS_Z] = z;
  1050. YSI_g_sClasses[i][E_CLASS_A] = a;
  1051. new
  1052. j;
  1053. // This may be better with a memcpy.
  1054. while (j < c)
  1055. {
  1056. P:5("Class_AddClass: weapon %d %d %d", j, c, w[j]);
  1057. YSI_g_sClasses[i][E_CLASS_WEAPONS][j] = w[j];
  1058. ++j;
  1059. }
  1060. //printf("Class_AddClass: weapon %d %d %d", j, c, i);
  1061. PA_FastInit(YSI_g_sClasses[i][E_CLASS_PLAYERS]);
  1062. //printf("Class_AddClass: weapon %d %d %d", j, c, f);
  1063. Class_ResolveGroups(i, f, false);
  1064. //printf("Class_AddClass: weapon %d %d %d", j, c, g);
  1065. YSI_g_sClasses[i][E_CLASS_GROUP] = g;
  1066. YSI_g_sClassCount++;
  1067. //printf("Class_AddClass: weapon %d %d %d", j, c, YSI_g_sClassCount);
  1068. return i;
  1069. }
  1070. /**--------------------------------------------------------------------------**\
  1071. <summary>Class_HasGroup</summary>
  1072. <param name="classid">The class to test.</param>
  1073. <param name="Group:group">The group to test setting of.</param>
  1074. <returns>
  1075. Does this class add players to the given group on spawn?
  1076. </returns>
  1077. <remarks>
  1078. -
  1079. </remarks>
  1080. \**--------------------------------------------------------------------------**/
  1081. foreign Class_HasGroup(classid, Group:group);
  1082. global Class_HasGroup(classid, Group:group)
  1083. {
  1084. return YSI_g_sClasses[classid][E_CLASS_GROUP] == group;
  1085. }
  1086. /**--------------------------------------------------------------------------**\
  1087. <summary>Class_Enable</summary>
  1088. <returns>
  1089. -
  1090. </returns>
  1091. <remarks>
  1092. -
  1093. </remarks>
  1094. \**--------------------------------------------------------------------------**/
  1095. foreign Class_Enable(classid, bool:toggle);
  1096. global Class_Enable(classid, bool:toggle)
  1097. {
  1098. if (Class_IsValid(classid))
  1099. {
  1100. if (toggle)
  1101. {
  1102. YSI_g_sClasses[classid][E_CLASS_FLAGS] |= e_CLASS_FLAGS_ENABLED;
  1103. }
  1104. else
  1105. {
  1106. YSI_g_sClasses[classid][E_CLASS_FLAGS] &= ~e_CLASS_FLAGS_ENABLED;
  1107. // TODO! Hide the class for anyone currently viewing it.
  1108. // foreach (new playerid : Player)
  1109. // {
  1110. // new
  1111. // e_PLAYER_CLASS:curclass = YSI_g_sPlayerClass[playerid];
  1112. // P:4("Class_Delete: %d %d %d", playerid, curclass, e_PLAYER_CLASS_SELECT);
  1113. // if (curclass & e_PLAYER_CLASS_SELECT)
  1114. // {
  1115. // if (e_PLAYER_CLASS:classid == curclass & e_PLAYER_CLASS_SKIN) Class_Goto(playerid, Class_FindNew(playerid, e_PLAYER_CLASS:classid, CLASS_MOVE_RIGHT));
  1116. // }
  1117. // }
  1118. }
  1119. return 1;
  1120. }
  1121. return 0;
  1122. }
  1123. /**--------------------------------------------------------------------------**\
  1124. <summary>Class_Delete</summary>
  1125. <param name="classid">Class to delete.</param>
  1126. <returns>
  1127. -
  1128. </returns>
  1129. <remarks>
  1130. Completely removes a class from the system.
  1131. </remarks>
  1132. \**--------------------------------------------------------------------------**/
  1133. foreign void:Class_Delete(classid);
  1134. global void:Class_Delete(classid)
  1135. {
  1136. P:2("Class_Delete called: %i", classid);
  1137. if (Class_Enable(classid, false))
  1138. {
  1139. YSI_g_sClasses[classid][E_CLASS_FLAGS] = e_CLASS_FLAGS:0;
  1140. }
  1141. //return 1;
  1142. }
  1143. /**--------------------------------------------------------------------------**\
  1144. <summary>Class_SetPlayer</summary>
  1145. <param name="classid">Class to set permissions for.</param>
  1146. <param name="playerid">Player to set for.</param>
  1147. <param name="set">Whether or not they can use this class.</param>
  1148. <returns>
  1149. -
  1150. </returns>
  1151. <remarks>
  1152. -
  1153. </remarks>
  1154. \**--------------------------------------------------------------------------**/
  1155. foreign void:Class_SetPlayer(cl, pid, bool:s);
  1156. global void:Class_SetPlayer(cl, pid, bool:s)
  1157. {
  1158. //printf("CLASS SET PLAYER: %d %d %d", cl, pid, s);
  1159. PA_Set(YSI_g_sClasses[cl][E_CLASS_PLAYERS], pid, s);
  1160. }
  1161. /**--------------------------------------------------------------------------**\
  1162. <summary>Class_GetPlayer</summary>
  1163. <param name="classid">Class to set permissions for.</param>
  1164. <param name="playerid">Player to set for.</param>
  1165. <returns>
  1166. -
  1167. </returns>
  1168. <remarks>
  1169. -
  1170. </remarks>
  1171. \**--------------------------------------------------------------------------**/
  1172. foreign bool:Class_GetPlayer(cl,pid);
  1173. global bool:Class_GetPlayer(cl,pid)
  1174. {
  1175. return PA_Get(YSI_g_sClasses[cl][E_CLASS_PLAYERS], pid);
  1176. }
  1177. /**--------------------------------------------------------------------------**\
  1178. <summary>Class_Get</summary>
  1179. <param name="playerid">Player to get the current class of.</param>
  1180. <returns>
  1181. -
  1182. </returns>
  1183. <remarks>
  1184. -
  1185. </remarks>
  1186. \**--------------------------------------------------------------------------**/
  1187. foreign Class_Get(playerid);
  1188. global Class_Get(playerid)
  1189. {
  1190. if (VALID_PLAYERID(playerid))
  1191. {
  1192. return _:(YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_SKIN);
  1193. }
  1194. return -1;
  1195. }
  1196. foreign void:Class_DisableSelection(playerid);
  1197. global void:Class_DisableSelection(playerid)
  1198. {
  1199. if (YSI_g_sPlayerClass[playerid] & e_PLAYER_CLASS_INSELECT)
  1200. {
  1201. Class_Spectate(playerid);
  1202. Class_TK(playerid);
  1203. }
  1204. //return 1;
  1205. }
  1206. foreign void:Class_DisableReselection(playerid);
  1207. global void:Class_DisableReselection(playerid)
  1208. {
  1209. YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_DISABLED);
  1210. // Disable "F4".
  1211. //ForceClassSelection(playerid);
  1212. //return 1;
  1213. }
  1214. foreign void:Class_EnableReselection(playerid);
  1215. global void:Class_EnableReselection(playerid)
  1216. {
  1217. YSI_g_sPlayerClass[playerid] &= ~(e_PLAYER_CLASS_DISABLED);
  1218. //return 1;
  1219. }
  1220. foreign void:Class_ForceReselection(playerid);
  1221. global void:Class_ForceReselection(playerid)
  1222. {
  1223. YSI_g_sPlayerClass[playerid] = (YSI_g_sPlayerClass[playerid] | e_PLAYER_CLASS_RETURNED) & ~(e_PLAYER_CLASS_SPAWNSINCE);
  1224. ForceClassSelection(playerid);
  1225. //return 1;
  1226. }
  1227. foreign void:Class_ReturnToSelection(playerid);
  1228. global void:Class_ReturnToSelection(playerid)
  1229. {
  1230. YSI_g_sPlayerClass[playerid] |= (e_PLAYER_CLASS_INSTANT);
  1231. Class_ForceReselection(playerid);
  1232. TogglePlayerSpectating(playerid, false);
  1233. //return 1;
  1234. }
  1235. static stock Class_Spectate(playerid)
  1236. {
  1237. new
  1238. Float:x1,
  1239. Float:y1,
  1240. Float:z1;
  1241. GetPlayerCameraPos(playerid, x1, y1, z1);
  1242. new
  1243. Float:x2,
  1244. Float:y2,
  1245. Float:z2;
  1246. GetPlayerCameraFrontVector(playerid, x2, y2, z2);
  1247. TogglePlayerSpectating(playerid, true);
  1248. SetPlayerCameraPos(playerid, x1, y1, z1);
  1249. SetPlayerCameraLookAt(playerid, x2, y2, z2);
  1250. PlayerSpectatePlayer(playerid, playerid, SPECTATE_MODE_FIXED);
  1251. }
  1252. #if defined _ALS_AddPlayerClass
  1253. #undef AddPlayerClass
  1254. #else
  1255. #define _ALS_AddPlayerClass
  1256. #endif
  1257. #define AddPlayerClass Class_Add
  1258. // Reset.
  1259. #undef _GROUP_MAKE_LIMIT
  1260. #undef _GROUP_MAKE_NAME
  1261. #include "..\YSI_Core\y_master"