y_commands_impl.inc 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702
  1. /*
  2. Legal:
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version
  5. 1.1 the "License"; you may not use this file except in compliance with
  6. the License. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/
  8. Software distributed under the License is distributed on an "AS IS" basis,
  9. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. for the specific language governing rights and limitations under the
  11. License.
  12. The Original Code is the YSI framework.
  13. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  14. Portions created by the Initial Developer are Copyright C 2011
  15. the Initial Developer. All Rights Reserved.
  16. Contributors:
  17. Y_Less
  18. koolk
  19. JoeBullet/Google63
  20. g_aSlice/Slice
  21. Misiur
  22. samphunter
  23. tianmeta
  24. maddinat0r
  25. spacemud
  26. Crayder
  27. Dayvison
  28. Ahmad45123
  29. Zeex
  30. irinel1996
  31. Yiin-
  32. Chaprnks
  33. Konstantinos
  34. Masterchen09
  35. Southclaws
  36. PatchwerkQWER
  37. m0k1
  38. paulommu
  39. udan111
  40. Thanks:
  41. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  42. ZeeX - Very productive conversations.
  43. koolk - IsPlayerinAreaEx code.
  44. TheAlpha - Danish translation.
  45. breadfish - German translation.
  46. Fireburn - Dutch translation.
  47. yom - French translation.
  48. 50p - Polish translation.
  49. Zamaroht - Spanish translation.
  50. Los - Portuguese translation.
  51. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  52. me to strive to better.
  53. Pixels^ - Running XScripters where the idea was born.
  54. Matite - Pestering me to release it and using it.
  55. Very special thanks to:
  56. Thiadmer - PAWN, whose limits continue to amaze me!
  57. Kye/Kalcor - SA:MP.
  58. SA:MP Team past, present and future - SA:MP.
  59. Optional plugins:
  60. Gamer_Z - GPS.
  61. Incognito - Streamer.
  62. Me - sscanf2, fixes2, Whirlpool.
  63. */
  64. /*
  65. ad88888ba
  66. d8" "8b ,d
  67. Y8, 88
  68. `Y8aaaaa, ,adPPYba, MM88MMM 88 88 8b,dPPYba,
  69. `"""""8b, a8P_____88 88 88 88 88P' "8a
  70. `8b 8PP""""""" 88 88 88 88 d8
  71. Y8a a8P "8b, ,aa 88, "8a, ,a88 88b, ,a8"
  72. "Y88888P" `"Ybbd8"' "Y888 `"YbbdP'Y8 88`YbbdP"'
  73. 88
  74. 88
  75. */
  76. enum E_COMMAND
  77. {
  78. // HASH_MAP_DATA<MAX_COMMAND_LENGTH char>,
  79. // Share a memory location with the hashmap stored name.
  80. E_COMMAND_NAME[MAX_COMMAND_LENGTH char] = 0,
  81. // IGNORE THESE, THEY COVER HASH MAP DATA.
  82. E_COMMAND_HASH_MAP[HASH_MAP_DATA],
  83. // _E_COMMAND_PAD_0, _E_COMMAND_PAD_1,
  84. // Who can use this command?
  85. PlayerArray:E_COMMAND_USERS<MAX_PLAYERS>,
  86. #if defined Y_COMMANDS_USE_CHARS
  87. E_COMMAND_PREFIX,
  88. #endif
  89. // Function pointer.
  90. E_COMMAND_POINTER
  91. }
  92. enum e_COMMAND_ERRORS
  93. {
  94. // The majority of these are even - odd numbers return "1" not "0".
  95. COMMAND_ZERO_RET = 0 , // The command returned 0.
  96. COMMAND_OK = 1 , // Called corectly.
  97. COMMAND_UNDEFINED = 2 , // Command doesn't exist.
  98. COMMAND_DENIED = 3 , // Can't use the command.
  99. COMMAND_HIDDEN = 4 , // Can't use the command don't let them know it exists.
  100. COMMAND_NO_PLAYER = 6 , // Used by a player who shouldn't exist.
  101. COMMAND_DISABLED = 7 , // All commands are disabled for this player.
  102. COMMAND_BAD_PREFIX = 8 , // Used "/" instead of "#", or something similar.
  103. COMMAND_INVALID_INPUT = 10, // Didn't type "/something".
  104. }
  105. enum e_COMMAND_FLAGS:(<<= 1)
  106. {
  107. e_COMMAND_FLAGS_ZERO_RET = 1, // The command returned 0.
  108. e_COMMAND_FLAGS_OK, // Called corectly.
  109. e_COMMAND_FLAGS_NOT_FOUND, // Command doesn't exist.
  110. e_COMMAND_FLAGS_DENIED, // Can't use the command.
  111. e_COMMAND_FLAGS_HIDDEN,
  112. _e_COMMAND_FLAGS_unused,
  113. e_COMMAND_FLAGS_NO_PLAYER, // Used by a player who shouldn't exist.
  114. e_COMMAND_FLAGS_DISABLED, // All commands are disabled for this player.
  115. e_COMMAND_FLAGS_BAD_PREFIX,
  116. e_COMMAND_FLAGS_INVALID_INPUT, // Didn't type "/something".
  117. // Save counts for callbacks.
  118. e_COMM_FLAG_OPCP = 0x00FF0000,
  119. e_COMM_FLAG_OPCP_ADD = 0x00010000,
  120. e_COMM_FLAG_OPCR = 0xFF000000,
  121. e_COMM_FLAG_OPCR_ADD = 0x01000000
  122. }
  123. // Store which script(s) own which commands.
  124. MASTER_DATA<MAX_COMMANDS>
  125. // Information for returning error messages.
  126. static stock __declspec(dist_tagged) e_COMMAND_FLAGS:YSI_g_sCommandFlags;
  127. static stock __declspec(distributed) YSI_g_sErrorMessages[e_COMMAND_ERRORS][144];
  128. // Who has had ALL their commands disabled?
  129. static stock __declspec(dist_special) PlayerArray:YSI_g_sDisabledPlayers<MAX_PLAYERS>;
  130. static stock
  131. YSI_g_sCurrentID = COMMAND_NOT_FOUND,
  132. BitArray:YSI_g_sPrefixes<128>,
  133. YSI_g_sHighestID,
  134. YSI_g_sReturnBuffer[YSI_MAX_STRING],
  135. // Quickly reference and store commands by name.
  136. HashMap:YSI_g_sCommandMap<>;
  137. static stock __declspec(dist_master) YSI_g_sCommands[MAX_COMMANDS][E_COMMAND];
  138. static stock const
  139. YSI_gscOPCR[] = "OnPlayerCommandReceived",
  140. YSI_gscOPCP[] = "OnPlayerCommandPerformed",
  141. YSI_gscISI[] = "isi",
  142. YSI_gscISII[] = "isii";
  143. // "YCMD:" macros. The true core is "YSIM_COMMAND", which is in "y_master".
  144. #define _YCMD_0:(_:_YCMD_1:_YCMD_2:_YCMD_3:%0(%1[]%2) YSIM_COMMAND %0(%1[]%2)
  145. #define _YCMD_1:_YCMD_2:_YCMD_3:%0, Command_GetID(#%0)),
  146. #define _YCMD_2:_YCMD_3:%0) Command_GetID(#%0)))
  147. #define _YCMD_3:%0; Command_GetID(#%0));
  148. #define @YCMD:%0; Command_TouchNamed(#%0);
  149. #define COMMAND__ YSIM_COMMAND
  150. #if YSI_KEYWORD(YCMD)
  151. #define YCMD: _YCMD_0:(_:_YCMD_1:_YCMD_2:_YCMD_3:
  152. #else
  153. // If we don't want the keyword, we still want the ID tag.
  154. #define YCMD: (_:_YCMD_1:_YCMD_2:_YCMD_3:
  155. #endif
  156. // ZCMD compatibility.
  157. #define CMD:%0(%1) YSIM_COMMAND %0(%1,__help)if(__help)return 0;else
  158. #define COMMAND CMD
  159. // Alt commands:
  160. #define _YCMD_4:@yC_%0(%9);%9(%9)%9;%9(%9);%9(%1)=%2; POSTINIT__%0(){Command_AddAltNamed(#%0,#%2);}
  161. #define @_yC%0\32; @_yC
  162. #define @y_C%0\32; @y_C
  163. #define @yC_%0\32; @yC_
  164. #define _@yC%0\32; _@yC
  165. // Forwards for optional command callbacks.
  166. forward e_COMMAND_ERRORS:OnPlayerCommandReceived(playerid, cmdtext[], e_COMMAND_ERRORS:success);
  167. forward e_COMMAND_ERRORS:OnPlayerCommandPerformed(playerid, cmdtext[], e_COMMAND_ERRORS:success);
  168. /*
  169. 88b d88
  170. 888b d888
  171. 88`8b d8'88
  172. 88 `8b d8' 88 ,adPPYYba, ,adPPYba, 8b,dPPYba, ,adPPYba, ,adPPYba,
  173. 88 `8b d8' 88 "" `Y8 a8" "" 88P' "Y8 a8" "8a I8[ ""
  174. 88 `8b d8' 88 ,adPPPPP88 8b 88 8b d8 `"Y8ba,
  175. 88 `888' 88 88, ,88 "8a, ,aa 88 "8a, ,a8" aa ]8I
  176. 88 `8' 88 `"8bbdP"Y8 `"Ybbd8"' 88 `"YbbdP"' `"YbbdP"'
  177. */
  178. #define _Command_GetPlayer(%0,%1) (PA_Get(YSI_g_sCommands[(%0)][E_COMMAND_USERS], (%1)))
  179. /*-------------------------------------------------------------------------*//**
  180. * <param name="idx">Command to test.</param>
  181. * <remarks>
  182. * Tests if the given slot is empty.
  183. * </remarks>
  184. *//*------------------------------------------------------------------------**/
  185. P:D(bool:_Command_IsEmptySlot(idx));
  186. #define _Command_IsEmptySlot(%0) (!YSI_g_sCommands[(%0)][E_COMMAND_NAME])
  187. /*-------------------------------------------------------------------------*//**
  188. * <param name="idx">Command to test.</param>
  189. * <remarks>
  190. * Tests if the given slot is an alternate command.
  191. * </remarks>
  192. *//*------------------------------------------------------------------------**/
  193. P:D(bool:_Command_IsAlt(idx));
  194. #define _Command_IsAlt(%0) (YSI_g_sCommands[(%0)][E_COMMAND_POINTER] & cellmin)
  195. /*-------------------------------------------------------------------------*//**
  196. * <param name="ptr">AMX function pointer.</param>
  197. * <param name="idx">Index of the parent command data.</param>
  198. * <param name="name">Destination for the parent function name.</param>
  199. * <remarks>
  200. * Finds the original version of an alt command. Updated to not contain long
  201. * chains (along with "Command_AddAlt").
  202. * </remarks>
  203. *//*------------------------------------------------------------------------**/
  204. P:D(_Command_GetReal(&ptr,&idx,name[]));
  205. #define _Command_GetReal(%0,%1,%2); \
  206. if((%0=YSI_g_sCommands[(%1)][E_COMMAND_POINTER])&cellmin) \
  207. %1=(%0)&~cellmin, \
  208. %0=YSI_g_sCommands[(%1)][E_COMMAND_POINTER], \
  209. strunpack(%2,YSI_g_sCommands[(%1)][E_COMMAND_NAME]);
  210. /*-------------------------------------------------------------------------*//**
  211. * <param name="error">Which error to show.</param>
  212. * <param name="playerid">Player who typed the command.</param>
  213. * <param name="cmdtext">What they typed.</param>
  214. * <remarks>
  215. * Call OnPlayerCommandReceived once the system knows how the player can use
  216. * this command (if they can). The order of the parameters is such that the
  217. * error comes first. This is because it is compile-time concatenated to make
  218. * the error enum value, and putting that parameter first means that we don't
  219. * need to ommit the space after any comma.
  220. * </remarks>
  221. *//*------------------------------------------------------------------------**/
  222. #define Command_ErrorRet(%2) (YSI_g_sCommandFlags&e_COMMAND_FLAGS:(1<<_:(%2)))
  223. #if defined COMMAND_USE_ERRORS
  224. #define Command_ErrorMsg(%2) YSI_g_sErrorMessages[%2]
  225. #if defined _Text_Send
  226. #define Command_Error(%0,%2) (Command_ErrorMsg(%2)[0]?(Text_Send((%0),Command_ErrorMsg(%2)),Command_ErrorRet(%2)):Command_ErrorRet(%2))
  227. #else
  228. #define Command_Error(%0,%2) (Command_ErrorMsg(%2)[0]?(SendClientMessage((%0),0xFF0000AA,Command_ErrorMsg(%2)),Command_ErrorRet(%2)):Command_ErrorRet(%2))
  229. #endif
  230. #else
  231. #define Command_Error(%0,%2) Command_ErrorRet(%2)
  232. #endif
  233. #define Command_OnReceived(%2,%0,%1) ((sErr=(YSI_g_sCommandFlags&e_COMM_FLAG_OPCR)?(e_COMMAND_ERRORS:W@(YSI_gscOPCR,YSI_gscISI,(%0),(%1),(_:COMMAND_%2))):(COMMAND_%2)),Command_Error(%0,sErr))
  234. /*-------------------------------------------------------------------------*//**
  235. * <param name="command">Command to get for.</param>
  236. * <returns>
  237. * Is this command ID active?
  238. * </returns>
  239. * <remarks>
  240. * Doesn't do any bounds checks - use "_Command_IsValid" for that.
  241. * </remarks>
  242. *//*------------------------------------------------------------------------**/
  243. P:D(bool:_Command_IsActive(command));
  244. #define _Command_IsActive(%0) (YSI_g_sCommands[(%0)][E_COMMAND_NAME])
  245. /*-------------------------------------------------------------------------*//**
  246. * <param name="command">Command to get for.</param>
  247. * <returns>
  248. * Is this command ID valid?
  249. * </returns>
  250. * <remarks>
  251. * Internal direct-access check.
  252. * </remarks>
  253. *//*------------------------------------------------------------------------**/
  254. //#define _Command_IsValid(%0) ((0 <= (%0) < YSI_g_sHighestID) && _Command_IsActive(%0))
  255. #define _Command_IsValid(%0) (IS_IN_RANGE((%0), 0, MAX_COMMANDS) && _Command_IsActive(%0))
  256. /*-------------------------------------------------------------------------*//**
  257. * <param name="idx">Command to test.</param>
  258. * <remarks>
  259. * Checks to see if a character is a possible prefix character. May use an
  260. * unsigned comparison.
  261. * </remarks>
  262. *//*------------------------------------------------------------------------**/
  263. #if defined Y_COMMANDS_USE_CHARS
  264. #define _Command_IsPrefix(%0) (IS_IN_RANGE((%0), 0, 128) && Bit_Get(YSI_g_sPrefixes, (%0)))
  265. #else
  266. #define _Command_IsPrefix(%0) ((%0) == '/')
  267. #endif
  268. /*-------------------------------------------------------------------------*//**
  269. * <param name="c">Command to get.</param>
  270. * <returns>
  271. * The prefix for this command.
  272. * </returns>
  273. *//*------------------------------------------------------------------------**/
  274. P:D(_Command_GetPrefix(c));
  275. #define _Command_GetPrefix(%0) (YSI_g_sCommands[(%0)][E_COMMAND_PREFIX])
  276. /*-------------------------------------------------------------------------*//**
  277. * <param name="f">Command to get the name of.</param>
  278. *//*------------------------------------------------------------------------**/
  279. P:D(Command_Name(f));
  280. #define Command_Name(%0) (YSI_g_sCommands[(%0)][E_COMMAND_NAME])
  281. /*
  282. 88b d88 88 db 88888888ba 88
  283. 888b d888 "" d88b 88 "8b 88
  284. 88`8b d8'88 d8'`8b 88 ,8P 88
  285. 88 `8b d8' 88 ,adPPYYba, 88 8b,dPPYba, d8' `8b 88aaaaaa8P' 88
  286. 88 `8b d8' 88 "" `Y8 88 88P' `"8a d8YaaaaY8b 88""""""' 88
  287. 88 `8b d8' 88 ,adPPPPP88 88 88 88 d8""""""""8b 88 88
  288. 88 `888' 88 88, ,88 88 88 88 d8' `8b 88 88
  289. 88 `8' 88 `"8bbdP"Y8 88 88 88 d8' `8b 88 88
  290. */
  291. /*-------------------------------------------------------------------------*//**
  292. * <param name="function">Function name to find.</param>
  293. * <returns>
  294. * The ID of the passed function.
  295. * </returns>
  296. * <remarks>
  297. * -
  298. *
  299. * native Command_GetID(function[])
  300. *
  301. * </remarks>
  302. *//*------------------------------------------------------------------------**/
  303. FOREIGN__ Command_GetID(const string:function[]);
  304. GLOBAL__ Command_GetID(const string:function[])
  305. {
  306. P:2("Command_GetID called: \"%s\"", function);
  307. return Command_Find(function);
  308. }
  309. /*-------------------------------------------------------------------------*//**
  310. * <param name="oidx">The function this is an alternate to.</param>
  311. * <param name="cmd">The new name.</param>
  312. * <returns>
  313. * The command's ID.
  314. * </returns>
  315. *//*------------------------------------------------------------------------**/
  316. FOREIGN__ Command_AddAlt(oidx, const string:cmd[]);
  317. GLOBAL__ Command_AddAlt(oidx, const string:cmd[])
  318. {
  319. static
  320. sCmd[64],
  321. sHash;
  322. if (!_Command_IsValid(oidx)) return COMMAND_NOT_FOUND;
  323. // Check the pointer is valid.
  324. new
  325. id = YSI_g_sCommands[oidx][E_COMMAND_POINTER];
  326. // The command we are pointing to is already an alternate for a third
  327. // command - point this new command at the parent.
  328. if (id & cellmin) oidx = id & ~cellmin;
  329. Puny_EncodeHash(sCmd, cmd, sHash, .delimiter = '@');
  330. // Now point this new command at the real (software) command.
  331. strpack(sCmd, sCmd, cellmax);
  332. if ((id = Command_Find(sCmd)) == COMMAND_NOT_FOUND)
  333. {
  334. // Command doesn't already exist, add it.
  335. if ((id = Command_GetEmptySlot()) == COMMAND_NOT_FOUND)
  336. {
  337. P:E("Could not add alt command to array.");
  338. return COMMAND_NOT_FOUND;
  339. }
  340. #if defined Y_COMMANDS_USE_CHARS
  341. YSI_g_sCommands[id][E_COMMAND_PREFIX] = '/',
  342. #endif
  343. // Save the new highest ID for loops later.
  344. YSI_g_sHighestID = max(YSI_g_sHighestID, id + 1),
  345. // Save the command's pointer.
  346. YSI_g_sCommands[id][E_COMMAND_POINTER] = cellmin | oidx,
  347. // Add this command to the hash map (does the name too).
  348. HashMap_Add(YSI_g_sCommandMap, sCmd, id),
  349. // Add all players, or defer to y_groups.
  350. PA_FastInit(YSI_g_sCommands[id][E_COMMAND_USERS]);
  351. NO_GROUPS<Command>(id)
  352. {
  353. PA_Init(YSI_g_sCommands[id][E_COMMAND_USERS], true);
  354. }
  355. // Copy the master script information. Note that this won't be kept up
  356. // to date with new scripts unfortunately.
  357. MASTER_COPY<id, oidx>
  358. }
  359. return id;
  360. }
  361. /*-------------------------------------------------------------------------*//**
  362. * <param name="p">(playerid) - Player who entered the command.</param>
  363. * <param name="c">(cmdtext) - Text entered.</param>
  364. * <param name="h">
  365. * 1 - Called from the help commmand or OnPlayerCommandText.
  366. * 2 - Bypass permissions checks.
  367. * </param>
  368. * <returns>
  369. * true - success or hidden fail.
  370. * false - fail.
  371. * </returns>
  372. * <remarks>
  373. * Does all the command and error handling. The macro version takes four
  374. * parameters:
  375. *
  376. * <code>Command_ReProcess(playerid,cmdtext,help,force);</code>
  377. *
  378. * <c>help</c> and <c>force</c> are combined together in to a bitmap.
  379. * </remarks>
  380. *//*------------------------------------------------------------------------**/
  381. //P:D(Command_ReProcess(playerid,cmdtext,help,force));
  382. #define Command_ReProcess(%0,%1,%2,%3) Command_ReProcess(%0,%1, _:(%2)|(_:(%3)<<1))
  383. FOREIGN__ Command_ReProcess(p,string:c[],h);
  384. GLOBAL__ Command_ReProcess(p,string:c[],h)
  385. {
  386. static
  387. sCmd[64] = "@yC_",
  388. sPos,
  389. sRet,
  390. sHash,
  391. e_COMMAND_ERRORS:sErr;
  392. // Check that the input is a valid command. Note that changing the command
  393. // prefix here would be VERY trivial!
  394. if ((sRet = _:_Command_IsPrefix(c[0]))) // Relies on "true = 1" later on!
  395. {
  396. if (!c[1]) return Command_OnReceived(INVALID_INPUT, p, c);
  397. }
  398. else
  399. {
  400. if (isnull(c)) return Command_OnReceived(INVALID_INPUT, p, NULL);
  401. }
  402. // Check for a valid player.
  403. #if !defined Y_COMMANDS_NO_IPC
  404. if (!IsPlayerConnected(p)) return Command_OnReceived(NO_PLAYER, p, c);
  405. #endif
  406. P:1("Commands_OnPlayerCommandText called: %d %s", p, c);
  407. new
  408. prevID = YSI_g_sCurrentID;
  409. if (PA_Get(YSI_g_sDisabledPlayers, p))
  410. {
  411. sRet = Command_OnReceived(DISABLED, p, c);
  412. if (sErr != COMMAND_OK)
  413. return sRet;
  414. }
  415. // Get the hashed version of the decoded string, skipping the possible "/".
  416. sPos = Puny_EncodeHash(sCmd[4], c[sRet], sHash, .delimiter = '@') + sRet;
  417. while (c[sPos] == ' ') ++sPos; // Better/slower: ('\0' < c[sPos] <= ' ').
  418. // Find the command in the array.
  419. YSI_g_sCurrentID = HashMap_GetWithHash(YSI_g_sCommandMap, sCmd[4], sHash);
  420. P:5("Commands_OnPlayerCommandText: %s, %d, %d, %d", sCmd[4], sPos, sHash, YSI_g_sCurrentID);
  421. if (YSI_g_sCurrentID == COMMAND_NOT_FOUND)
  422. {
  423. return
  424. YSI_g_sCurrentID = prevID,
  425. Command_OnReceived(UNDEFINED, p, c);
  426. }
  427. #if defined Y_COMMANDS_USE_CHARS
  428. if (sRet && _Command_GetPrefix(YSI_g_sCurrentID) != c[0])
  429. {
  430. // Have a prefix, but not the right one. Calling this function
  431. // directly always works for all possible command prefixes.
  432. return Command_OnReceived(BAD_PREFIX, p, c);
  433. }
  434. #endif
  435. P:5("Commands_OnPlayerCommandText: Use %d", _Command_GetPlayer(YSI_g_sCurrentID, p));
  436. // Can the player use this command? `Command_OnReceived` sets "sErr".
  437. if ((h&2) || _Command_GetPlayer(YSI_g_sCurrentID, p))
  438. sRet = Command_OnReceived(OK, p, c);
  439. else
  440. sRet = Command_OnReceived(DENIED, p, c);
  441. if (sErr != COMMAND_OK)
  442. {
  443. return
  444. YSI_g_sCurrentID = prevID,
  445. sRet;
  446. }
  447. // Find the true version of the command (alts etc).
  448. _Command_GetReal(sHash, YSI_g_sCurrentID, sCmd[4]);
  449. P:5("Commands_OnPlayerCommandText: Read %d", YSI_g_sCurrentID);
  450. P:5("Commands_OnPlayerCommandText: Master %d %d", Master_ID(), _:MASTER_GET<YSI_g_sCurrentID>);
  451. #if YSIM_HAS_MASTER
  452. if (MASTER_EXCLUSIVE<YSI_g_sCurrentID>)
  453. #endif
  454. {
  455. P:5("Commands_OnPlayerCommandText: Local %08x (%d, \"%s\", %d)", sHash, p, c[sPos], h & 1);
  456. // In this script. More to the point, in ONLY this script, so
  457. // we can't have another script as the master. I tried updating
  458. // this code but then realised that the update would ignore the
  459. // case where a command was in both the current script and
  460. // another script, but the other script was the master script.
  461. #emit LOAD.S.pri h
  462. #emit CONST.alt 1
  463. #emit AND
  464. #emit PUSH.pri
  465. #emit LOAD.pri sPos
  466. #emit LOAD.S.alt c
  467. #emit IDXADDR
  468. #emit PUSH.pri
  469. #emit PUSH.S p
  470. #emit PUSH.C 12
  471. #emit LCTRL 6
  472. #emit ADD.C 44
  473. #emit LCTRL 8
  474. #emit PUSH.pri
  475. #emit LOAD.pri sHash
  476. #emit SCTRL 8
  477. #emit SCTRL 6
  478. #emit STOR.pri sRet
  479. P:5("Command_ReProces: Result = %d %d %d", sRet, Command_Error(p, e_COMMAND_ERRORS:sRet), _:COMMAND_OK);
  480. }
  481. #if YSIM_HAS_MASTER
  482. else
  483. {
  484. // This is in another script, or multiple scripts.
  485. // Call the command in another script. If no particular script
  486. // is set up as the "master", call it in the first one found...
  487. if (c[sPos]) CallRemoteFunction(sCmd, YSI_gscISII, p, c[sPos], h&1, Cell_GetLowestBit(_:MASTER_GET<YSI_g_sCurrentID>));
  488. else CallRemoteFunction(sCmd, YSI_gscISII, p, NULL, h&1, Cell_GetLowestBit(_:MASTER_GET<YSI_g_sCurrentID>));
  489. sRet = getproperty(8, YSIM_RETURN);
  490. }
  491. #endif
  492. if (YSI_g_sCommandFlags & e_COMM_FLAG_OPCP) sRet = CallRemoteFunction(YSI_gscOPCP, YSI_gscISI, p, c, sRet);
  493. return
  494. YSI_g_sCurrentID = prevID,
  495. Command_Error(p, e_COMMAND_ERRORS:sRet);
  496. }
  497. /*
  498. 88888888ba 88 88
  499. 88 "8b "" ""
  500. 88 ,8P
  501. 88aaaaaa8P' ,adPPYba, 8b,dPPYba, 88,dPYba,,adPYba, 88 ,adPPYba, ,adPPYba, 88 ,adPPYba, 8b,dPPYba, ,adPPYba,
  502. 88""""""' a8P_____88 88P' "Y8 88P' "88" "8a 88 I8[ "" I8[ "" 88 a8" "8a 88P' `"8a I8[ ""
  503. 88 8PP""""""" 88 88 88 88 88 `"Y8ba, `"Y8ba, 88 8b d8 88 88 `"Y8ba,
  504. 88 "8b, ,aa 88 88 88 88 88 aa ]8I aa ]8I 88 "8a, ,a8" 88 88 aa ]8I
  505. 88 `"Ybbd8"' 88 88 88 88 88 `"YbbdP"' `"YbbdP"' 88 `"YbbdP"' 88 88 `"YbbdP"'
  506. */
  507. /*-------------------------------------------------------------------------*//**
  508. * <param name="playerid">Player to set.</param>
  509. * <param name="set">Can they use any commands at all.</param>
  510. * <remarks>
  511. * Enables or disables using commands for this player. Enabling commands does
  512. * not enable ALL commands, just allows them to use the ones for which they
  513. * have otherwise set permissions. Disabling prevents them from using ANY
  514. * commands at all (though this can be overridden by returning `COMMAND_OK` in
  515. * `OnPlayerCommandReceived`).
  516. * </remarks>
  517. *//*------------------------------------------------------------------------**/
  518. FOREIGN__ void:Command_SetPlayerDisabled(playerid, bool:set);
  519. GLOBAL__ void:Command_SetPlayerDisabled(playerid, bool:set)
  520. {
  521. PA_Set(YSI_g_sDisabledPlayers, playerid, set);
  522. }
  523. /*-------------------------------------------------------------------------*//**
  524. * <param name="playerid">Player to get.</param>
  525. * <returns>
  526. * Can this player use any commands?
  527. * </returns>
  528. *//*------------------------------------------------------------------------**/
  529. FOREIGN__ bool:Command_GetPlayerDisabled(playerid);
  530. GLOBAL__ bool:Command_GetPlayerDisabled(playerid)
  531. {
  532. return PA_Get(YSI_g_sDisabledPlayers, playerid);
  533. }
  534. /*-------------------------------------------------------------------------*//**
  535. * <param name="command">Command to get for.</param>
  536. * <param name="playerid">Player to get.</param>
  537. * <returns>
  538. * Can this player use this command?
  539. * </returns>
  540. * <remarks>
  541. *
  542. * native bool:Command_GetPlayer(command, playerid);
  543. *
  544. * </remarks>
  545. *//*------------------------------------------------------------------------**/
  546. FOREIGN__ bool:Command_GetPlayer(cmd, pid);
  547. GLOBAL__ bool:Command_GetPlayer(cmd, pid)
  548. {
  549. if (_Command_IsValid(cmd) && VALID_PLAYERID(pid)) return _Command_GetPlayer(cmd, pid);
  550. return false;
  551. }
  552. /*-------------------------------------------------------------------------*//**
  553. * <param name="funcname">Command to get for.</param>
  554. * <param name="playerid">Player to get.</param>
  555. * <remarks>
  556. * Like Command_GetPlayer but for a function name.
  557. *
  558. * native bool:Command_GetPlayerNamed(funcname[], playerid);
  559. *
  560. * </remarks>
  561. *//*------------------------------------------------------------------------**/
  562. FOREIGN__ bool:Command_GetPlayerNamed(const string:func[], playerid);
  563. GLOBAL__ bool:Command_GetPlayerNamed(const string:func[], playerid)
  564. {
  565. return Command_GetPlayer(Command_Find(func), playerid);
  566. }
  567. /*-------------------------------------------------------------------------*//**
  568. * <param name="command">Command to set for.</param>
  569. * <param name="playerid">Player to set.</param>
  570. * <param name="set">Wether or not this player can use this command.</param>
  571. * <remarks>
  572. *
  573. * native bool:Command_SetPlayer(command, playerid, bool:set);
  574. *
  575. * </remarks>
  576. *//*------------------------------------------------------------------------**/
  577. FOREIGN__ void:Command_SetPlayer(c, p, bool:s);
  578. GLOBAL__ void:Command_SetPlayer(c, p, bool:s)
  579. {
  580. P:2("Command_SetPlayer called: %i, %i, %i", c, p, s);
  581. if (_Command_IsValid(c) && VALID_PLAYERID(p)) PA_Set(YSI_g_sCommands[c][E_COMMAND_USERS], p, s);
  582. }
  583. /*-------------------------------------------------------------------------*//**
  584. * <param name="funcname">Command to set for.</param>
  585. * <param name="playerid">Player to set.</param>
  586. * <param name="set">Wether or not this player can use this command.</param>
  587. * <remarks>
  588. * Like Command_SetPlayer but for a function name.
  589. *
  590. * native bool:Command_SetPlayerNamed(funcname[], playerid, bool:set);
  591. *
  592. * </remarks>
  593. *//*------------------------------------------------------------------------**/
  594. FOREIGN__ void:Command_SetPlayerNamed(const string:f[],p,bool:s);
  595. GLOBAL__ void:Command_SetPlayerNamed(const string:f[],p,bool:s)
  596. {
  597. Command_SetPlayer(Command_Find(f), p, s);
  598. }
  599. /*-------------------------------------------------------------------------*//**
  600. * <param name="cmd">The command name to find.</param>
  601. * <returns>
  602. * The array slot of this command, or -1.
  603. * </returns>
  604. *//*------------------------------------------------------------------------**/
  605. FOREIGN__ Command_Find(const string:cmd[]);
  606. GLOBAL__ Command_Find(const string:cmd[])
  607. {
  608. static
  609. sCmd[64] = "",
  610. sHash;
  611. Puny_EncodeHash(sCmd, cmd, sHash, .delimiter = '@');
  612. return HashMap_Get(YSI_g_sCommandMap, sCmd);
  613. }
  614. /*-------------------------------------------------------------------------*//**
  615. * <param name="command">Command to "touch".</param>
  616. * <remarks>
  617. * Used within "GROUP_ADD" to quickly assign a load of commands to just one
  618. * group.
  619. * </remarks>
  620. *//*------------------------------------------------------------------------**/
  621. FOREIGN__ void:Command_TouchNamed(const string:command[]);
  622. GLOBAL__ void:Command_TouchNamed(const string:command[])
  623. {
  624. new
  625. id = Command_Find(command);
  626. if (id != COMMAND_NOT_FOUND)
  627. {
  628. NO_GROUPS<Command>(id)
  629. {
  630. return;
  631. }
  632. }
  633. }
  634. /*-------------------------------------------------------------------------*//**
  635. * <param name="command">Command to "touch".</param>
  636. * <remarks>
  637. * Used within "GROUP_ADD" to quickly assign a load of commands to just one
  638. * group.
  639. * </remarks>
  640. *//*------------------------------------------------------------------------**/
  641. FOREIGN__ void:Command_Touch(command);
  642. GLOBAL__ void:Command_Touch(command)
  643. {
  644. if (_Command_IsValid(command))
  645. {
  646. NO_GROUPS<Command>(command)
  647. {
  648. return;
  649. }
  650. }
  651. }
  652. /*-------------------------------------------------------------------------*//**
  653. *//*------------------------------------------------------------------------**/
  654. FOREIGN__ void:Command_SetDeniedReturn(bool:set);
  655. GLOBAL__ void:Command_SetDeniedReturn(bool:set)
  656. {
  657. if (set)
  658. YSI_g_sCommandFlags |= e_COMMAND_FLAGS_DENIED;
  659. else
  660. YSI_g_sCommandFlags &= ~e_COMMAND_FLAGS_DENIED;
  661. }
  662. /*-------------------------------------------------------------------------*//**
  663. *//*------------------------------------------------------------------------**/
  664. FOREIGN__ bool:Command_GetDeniedReturn();
  665. GLOBAL__ bool:Command_GetDeniedReturn()
  666. {
  667. return bool:(YSI_g_sCommandFlags & e_COMMAND_FLAGS_DENIED);
  668. }
  669. /*-------------------------------------------------------------------------*//**
  670. *//*------------------------------------------------------------------------**/
  671. FOREIGN__ void:Command_SetIllegalReturn(bool:set);
  672. GLOBAL__ void:Command_SetIllegalReturn(bool:set)
  673. {
  674. if (set)
  675. YSI_g_sCommandFlags |= e_COMMAND_FLAGS_INVALID_INPUT;
  676. else
  677. YSI_g_sCommandFlags &= ~e_COMMAND_FLAGS_INVALID_INPUT;
  678. }
  679. /*-------------------------------------------------------------------------*//**
  680. *//*------------------------------------------------------------------------**/
  681. FOREIGN__ bool:Command_GetIllegalReturn();
  682. GLOBAL__ bool:Command_GetIllegalReturn()
  683. {
  684. return bool:(YSI_g_sCommandFlags & e_COMMAND_FLAGS_INVALID_INPUT);
  685. }
  686. /*-------------------------------------------------------------------------*//**
  687. *//*------------------------------------------------------------------------**/
  688. FOREIGN__ void:Command_SetUnknownReturn(bool:set);
  689. GLOBAL__ void:Command_SetUnknownReturn(bool:set)
  690. {
  691. if (set)
  692. YSI_g_sCommandFlags |= e_COMMAND_FLAGS_NOT_FOUND;
  693. else
  694. YSI_g_sCommandFlags &= ~e_COMMAND_FLAGS_NOT_FOUND;
  695. }
  696. /*-------------------------------------------------------------------------*//**
  697. *//*------------------------------------------------------------------------**/
  698. FOREIGN__ bool:Command_GetUnknownReturn();
  699. GLOBAL__ bool:Command_GetUnknownReturn()
  700. {
  701. return bool:(YSI_g_sCommandFlags & e_COMMAND_FLAGS_NOT_FOUND);
  702. }
  703. /*-------------------------------------------------------------------------*//**
  704. *//*------------------------------------------------------------------------**/
  705. FOREIGN__ void:Command_SetDisconnectReturn(bool:set);
  706. GLOBAL__ void:Command_SetDisconnectReturn(bool:set)
  707. {
  708. if (set)
  709. YSI_g_sCommandFlags |= e_COMMAND_FLAGS_NO_PLAYER;
  710. else
  711. YSI_g_sCommandFlags &= ~e_COMMAND_FLAGS_NO_PLAYER;
  712. }
  713. /*-------------------------------------------------------------------------*//**
  714. *//*------------------------------------------------------------------------**/
  715. FOREIGN__ bool:Command_GetDisconnectReturn();
  716. GLOBAL__ bool:Command_GetDisconnectReturn()
  717. {
  718. return bool:(YSI_g_sCommandFlags & e_COMMAND_FLAGS_NO_PLAYER);
  719. }
  720. /*
  721. 88888888888 db 88888888ba 88
  722. 88 ,d d88b 88 "8b 88
  723. 88 88 d8'`8b 88 ,8P 88
  724. 88aaaaa 8b, ,d8 MM88MMM 8b,dPPYba, ,adPPYYba, d8' `8b 88aaaaaa8P' 88
  725. 88""""" `Y8, ,8P' 88 88P' "Y8 "" `Y8 d8YaaaaY8b 88""""""' 88
  726. 88 )888( 88 88 ,adPPPPP88 d8""""""""8b 88 88
  727. 88 ,d8" "8b, 88, 88 88, ,88 d8' `8b 88 88
  728. 88888888888 8P' `Y8 "Y888 88 `"8bbdP"Y8 d8' `8b 88 88
  729. */
  730. /*-------------------------------------------------------------------------*//**
  731. * <param name="function">The function this is an alternate to.</param>
  732. * <param name="altname">The new name.</param>
  733. * <remarks>
  734. * Add an alternate command for an existing command.
  735. *
  736. * native Command_AddAltNamed(function[], altname[]);
  737. *
  738. * </remarks>
  739. *//*------------------------------------------------------------------------**/
  740. FOREIGN__ Command_AddAltNamed(const string:function[], const string:altname[]);
  741. GLOBAL__ Command_AddAltNamed(const string:function[], const string:altname[])
  742. {
  743. return Command_AddAlt(Command_Find(function), altname);
  744. }
  745. /*-------------------------------------------------------------------------*//**
  746. * <param name="func">The slot of the command to remove.</param>
  747. * <remarks>
  748. *
  749. * native Command_Remove(func);
  750. *
  751. * </remarks>
  752. *//*------------------------------------------------------------------------**/
  753. FOREIGN__ void:Command_Remove(func);
  754. GLOBAL__ void:Command_Remove(func)
  755. {
  756. // Annoyingly, this is actually better with "HashMap_RemoveKey", but then we
  757. // don't have the ID for later use.
  758. if (HashMap_RemoveValue(YSI_g_sCommandMap, func))
  759. {
  760. #if defined Y_COMMANDS_USE_CHARS
  761. Command_FlushPrefixes(_Command_GetPrefix(func)),
  762. #endif
  763. YSI_g_sCommands[func][E_COMMAND_POINTER] = -1;
  764. }
  765. }
  766. /*-------------------------------------------------------------------------*//**
  767. * <param name="func">The name of the command to remove.</param>
  768. * <remarks>
  769. *
  770. * native Command_RemoveNamed(string:func[]);
  771. *
  772. * </remarks>
  773. *//*------------------------------------------------------------------------**/
  774. FOREIGN__ void:Command_RemoveNamed(const string:func[]);
  775. GLOBAL__ void:Command_RemoveNamed(const string:func[])
  776. {
  777. Command_Remove(Command_Find(func));
  778. }
  779. /*-------------------------------------------------------------------------*//**
  780. * <param name="command">Command to get for.</param>
  781. * <returns>
  782. * Is this command ID valid?
  783. * </returns>
  784. *//*------------------------------------------------------------------------**/
  785. FOREIGN__ bool:Command_IsValid(cmd);
  786. GLOBAL__ bool:Command_IsValid(cmd)
  787. {
  788. return _Command_IsValid(cmd);
  789. }
  790. /*-------------------------------------------------------------------------*//**
  791. * <returns>
  792. * The command currently being processed, or "COMMAND_NOT_FOUND".
  793. * </returns>
  794. *//*------------------------------------------------------------------------**/
  795. FOREIGN__ Command_GetCurrent();
  796. GLOBAL__ Command_GetCurrent()
  797. {
  798. return YSI_g_sCurrentID;
  799. }
  800. /*-------------------------------------------------------------------------*//**
  801. * <param name="playerid">Player to count for.</param>
  802. * <remarks>
  803. * Gets the number of comamnds this player can use.
  804. *
  805. * native Command_GetPlayerCommandCount(playerid);
  806. *
  807. * </remarks>
  808. *//*------------------------------------------------------------------------**/
  809. FOREIGN__ Command_GetPlayerCommandCount(playerid);
  810. GLOBAL__ Command_GetPlayerCommandCount(playerid)
  811. {
  812. P:2("Command_GetPlayerCommandCount called: %i", playerid);
  813. new
  814. slot = PA_Slot(playerid),
  815. Bit:mask = PA_Mask(playerid),
  816. count = 0;
  817. for (new i = 0; i != YSI_g_sHighestID; ++i)
  818. {
  819. if (_Command_IsActive(i) && YSI_g_sCommands[i][E_COMMAND_USERS][slot] & mask)
  820. {
  821. ++count;
  822. }
  823. }
  824. return count;
  825. }
  826. /*
  827. 888b 88
  828. 8888b 88
  829. 88 `8b 88
  830. 88 `8b 88 ,adPPYYba, 88,dPYba,,adPYba, ,adPPYba, ,adPPYba,
  831. 88 `8b 88 "" `Y8 88P' "88" "8a a8P_____88 I8[ ""
  832. 88 `8b 88 ,adPPPPP88 88 88 88 8PP""""""" `"Y8ba,
  833. 88 `8888 88, ,88 88 88 88 "8b, ,aa aa ]8I
  834. 88 `888 `"8bbdP"Y8 88 88 88 `"Ybbd8"' `"YbbdP"'
  835. */
  836. /*-------------------------------------------------------------------------*//**
  837. * <param name="f">Command to get the name of.</param>
  838. * <remarks>
  839. *
  840. * native Command_GetName(funcid);
  841. *
  842. * </remarks>
  843. *//*------------------------------------------------------------------------**/
  844. FOREIGN__ string:Command_GetName(f);
  845. GLOBAL__ string:Command_GetName(f)
  846. {
  847. YSI_g_sReturnBuffer[0] = '\0';
  848. if (_Command_IsValid(f)) strunpack(YSI_g_sReturnBuffer, Command_Name(f));
  849. return YSI_g_sReturnBuffer;
  850. }
  851. /*-------------------------------------------------------------------------*//**
  852. * <param name="f">Command to get the real name of.</param>
  853. * <param name="p">Player to get the name for.</param>
  854. * <returns>
  855. * The name of a command for a single player.
  856. * </returns>
  857. * <remarks>
  858. * Abstracted because there's a crash when chain returning a string from a
  859. * foreign function (see "Command_GetDisplayNamed").
  860. *
  861. * native Command_GetDisplay(funcid, playerid);
  862. *
  863. * </remarks>
  864. *//*------------------------------------------------------------------------**/
  865. FOREIGN__ string:Command_GetDisplay(funcid, playerid);
  866. GLOBAL__ string:Command_GetDisplay(funcid, playerid)
  867. {
  868. return
  869. _Command_GetDisplay(funcid, playerid),
  870. YSI_g_sReturnBuffer;
  871. }
  872. /*-------------------------------------------------------------------------*//**
  873. * <param name="f">Command to get the real name of.</param>
  874. * <param name="p">Player to get the name for.</param>
  875. * <returns>
  876. * The name of a named function for one player.
  877. * </returns>
  878. * <remarks>
  879. * Remote function call for Command_GetDisplayNameNamed - avoids needing to
  880. * expose users to the master system's odd way of returning strings. This is
  881. * the only part I've not yet fixed up to be nice and hidden.
  882. *
  883. * native string:Command_GetDisplayNamed(string:funcid[], playerid);
  884. *
  885. * </remarks>
  886. *//*------------------------------------------------------------------------**/
  887. FOREIGN__ string:Command_GetDisplayNamed(const string:func[], playerid);
  888. GLOBAL__ string:Command_GetDisplayNamed(const string:func[], playerid)
  889. {
  890. return
  891. _Command_GetDisplay(Command_Find(func), playerid),
  892. YSI_g_sReturnBuffer;
  893. }
  894. /*-------------------------------------------------------------------------*//**
  895. * <param name="index">Index of the next command for this player.</param>
  896. * <param name="playerid">Player to get the name for.</param>
  897. * <returns>
  898. * The name of a command for a single player.
  899. * </returns>
  900. * <remarks>
  901. * -
  902. *
  903. * native Command_GetNext(index, playerid);
  904. *
  905. * </remarks>
  906. *//*------------------------------------------------------------------------**/
  907. FOREIGN__ string:Command_GetNext(index, playerid);
  908. GLOBAL__ string:Command_GetNext(index, playerid)
  909. {
  910. P:2("Command_GetNext called: %i, %i", index, playerid);
  911. YSI_g_sReturnBuffer[0] = '\0';
  912. if (0 <= index < YSI_g_sHighestID)
  913. {
  914. // Don't recalculate this every loop.
  915. new
  916. slot = PA_Slot(playerid),
  917. Bit:mask = PA_Mask(playerid);
  918. for (new i = 0; i != YSI_g_sHighestID; ++i)
  919. {
  920. if (_Command_IsActive(i) && YSI_g_sCommands[i][E_COMMAND_USERS][slot] & mask)
  921. {
  922. // Skip already displayed ones.
  923. if (index)
  924. {
  925. --index;
  926. }
  927. else
  928. {
  929. strunpack(YSI_g_sReturnBuffer, Command_Name(i));
  930. return YSI_g_sReturnBuffer;
  931. }
  932. }
  933. }
  934. }
  935. return YSI_g_sReturnBuffer;
  936. }
  937. /*
  938. 88
  939. 88 ,d ,d
  940. 88 88 88
  941. 88 MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYYba, MM88MMM ,adPPYba, 8b,dPPYba, ,adPPYba,
  942. 88 88 a8P_____88 88P' "Y8 "" `Y8 88 a8" "8a 88P' "Y8 I8[ ""
  943. 88 88 8PP""""""" 88 ,adPPPPP88 88 8b d8 88 `"Y8ba,
  944. 88 88, "8b, ,aa 88 88, ,88 88, "8a, ,a8" 88 aa ]8I
  945. 88 "Y888 `"Ybbd8"' 88 `"8bbdP"Y8 "Y888 `"YbbdP"' 88 `"YbbdP"'
  946. */
  947. /*-------------------------------------------------------------------------*//**
  948. * <param name="start">Last value.</param>
  949. * <returns>
  950. * The next command.
  951. * </returns>
  952. * <remarks>
  953. * Internal implementation of the "Command()" iterator for "foreach". Returns
  954. * all the commands that exist. Normally iterator functions take two
  955. * parameters, but this needs only one. Really quite simple, but probably
  956. * faster this way as it has access to internal information.
  957. * </remarks>
  958. *//*------------------------------------------------------------------------**/
  959. FOREIGN__ Iter_Func@Command(start);
  960. GLOBAL__ Iter_Func@Command(start)
  961. {
  962. for (new i = start + 1; i < YSI_g_sHighestID; ++i)
  963. {
  964. if (_Command_IsActive(i)) return i;
  965. }
  966. return COMMAND_NOT_FOUND;
  967. }
  968. #define Iterator@Command iterstart(-1)
  969. /*-------------------------------------------------------------------------*//**
  970. * <param name="pid">Player to check for.</param>
  971. * <param name="start">Last value.</param>
  972. * <returns>
  973. * The next command.
  974. * </returns>
  975. * <remarks>
  976. * Internal implementation of the "PlayerCommand()" iterator for "foreach".
  977. * Returns all the commands this player can use.
  978. *
  979. * This is similar to "Command_GetNext", but returns an ID not a string - I
  980. * actually think this way is slightly better.
  981. * </remarks>
  982. *//*------------------------------------------------------------------------**/
  983. FOREIGN__ Iter_Func@PlayerCommand(start, pid);
  984. GLOBAL__ Iter_Func@PlayerCommand(start, pid)
  985. {
  986. new
  987. slot = PA_Slot(pid),
  988. Bit:mask = PA_Mask(pid);
  989. for (new i = start + 1; i < YSI_g_sHighestID; ++i)
  990. {
  991. if (_Command_IsActive(i) && YSI_g_sCommands[i][E_COMMAND_USERS][slot] & mask) return i;
  992. }
  993. return COMMAND_NOT_FOUND;
  994. }
  995. #define Iterator@PlayerCommand iterstart(-1)
  996. /*
  997. 88888888ba ad88 88
  998. 88 "8b d8" ""
  999. 88 ,8P 88
  1000. 88aaaaaa8P' 8b,dPPYba, ,adPPYba, MM88MMM 88 8b, ,d8 ,adPPYba, ,adPPYba,
  1001. 88""""""' 88P' "Y8 a8P_____88 88 88 `Y8, ,8P' a8P_____88 I8[ ""
  1002. 88 88 8PP""""""" 88 88 )888( 8PP""""""" `"Y8ba,
  1003. 88 88 "8b, ,aa 88 88 ,d8" "8b, "8b, ,aa aa ]8I
  1004. 88 88 `"Ybbd8"' 88 88 8P' `Y8 `"Ybbd8"' `"YbbdP"'
  1005. */
  1006. /*-------------------------------------------------------------------------*//**
  1007. * <param name="c">Command to get.</param>
  1008. * <returns>
  1009. * The prefix for this command ('/' by default).
  1010. * </returns>
  1011. *//*------------------------------------------------------------------------**/
  1012. #if defined Y_COMMANDS_USE_CHARS
  1013. FOREIGN__ Command_GetPrefix(c);
  1014. GLOBAL__ Command_GetPrefix(c)
  1015. {
  1016. if (_Command_IsValid(c)) return _Command_GetPrefix(c);
  1017. return '/';
  1018. }
  1019. FOREIGN__ Command_GetPrefixNamed(string:c[]);
  1020. GLOBAL__ Command_GetPrefixNamed(string:c[])
  1021. {
  1022. return Command_GetPrefix(Command_Find(c));
  1023. }
  1024. // Don't compile at all if it is disabled.
  1025. #endif
  1026. /*-------------------------------------------------------------------------*//**
  1027. * <param name="prefix">Possible prefix character.</param>
  1028. * <returns>
  1029. * Is this a valid character for a prefix?
  1030. * </returns>
  1031. * <remarks>
  1032. * This is the ONLY place the list of valid prefixes is defined! They are
  1033. * symbols, not an alphanumerics, and under 128.
  1034. * </remarks>
  1035. *//*------------------------------------------------------------------------**/
  1036. #if defined Y_COMMANDS_USE_CHARS
  1037. stock bool:Command_IsValidPrefix(prefix)
  1038. {
  1039. return (
  1040. '!' <= prefix <= '/' ||
  1041. ':' <= prefix <= '@' ||
  1042. '[' <= prefix <= '`' ||
  1043. '{' <= prefix <= '~');
  1044. }
  1045. #endif
  1046. /*-------------------------------------------------------------------------*//**
  1047. * <param name="prefix">Possible prefix character.</param>
  1048. * <returns>
  1049. * Is this a prefix used for any command?
  1050. * </returns>
  1051. *//*------------------------------------------------------------------------**/
  1052. #if defined Y_COMMANDS_USE_CHARS
  1053. FOREIGN__ bool:Command_IsPrefixUsed(prefix);
  1054. GLOBAL__ bool:Command_IsPrefixUsed(prefix)
  1055. {
  1056. return Command_IsValidPrefix(prefix) && Bit_Get(YSI_g_sPrefixes, prefix);
  1057. }
  1058. #endif
  1059. /*-------------------------------------------------------------------------*//**
  1060. * <param name="prefix">Prefix to maybe remove.</param>
  1061. * <remarks>
  1062. * If one command uses a prefix, then STOPS using said prefix, the global list
  1063. * of valid prefixes will need to be updated.
  1064. * </remarks>
  1065. *//*------------------------------------------------------------------------**/
  1066. #if defined Y_COMMANDS_USE_CHARS
  1067. static stock Command_FlushPrefixes(prefix)
  1068. {
  1069. if (prefix == '/') return 1;
  1070. for (new i = 0; i != YSI_g_sHighestID; ++i)
  1071. {
  1072. if (_Command_IsActive(i) && _Command_GetPrefix(i) == prefix) return 1;
  1073. }
  1074. Bit_Vet(YSI_g_sPrefixes, prefix);
  1075. return 0;
  1076. }
  1077. #endif
  1078. /*-------------------------------------------------------------------------*//**
  1079. * <param name="c">Command to set.</param>
  1080. * <param name="prefix">First character of the command.</param>
  1081. * <remarks>
  1082. * Change what command to type "/x" vs "#x" for example.
  1083. * </remarks>
  1084. *//*------------------------------------------------------------------------**/
  1085. #if defined Y_COMMANDS_USE_CHARS
  1086. FOREIGN__ bool:Command_SetPrefix(c, prefix);
  1087. GLOBAL__ bool:Command_SetPrefix(c, prefix)
  1088. {
  1089. if (Command_IsValidPrefix(prefix))
  1090. {
  1091. if (_Command_IsValid(c))
  1092. {
  1093. // Set this command's prefix, and add the prefix to the list.
  1094. new
  1095. tmp = YSI_g_sCommands[c][E_COMMAND_PREFIX];
  1096. return
  1097. Bit_Let(YSI_g_sPrefixes, prefix),
  1098. YSI_g_sCommands[c][E_COMMAND_PREFIX] = prefix,
  1099. Command_FlushPrefixes(tmp),
  1100. true;
  1101. }
  1102. }
  1103. return false;
  1104. }
  1105. #endif
  1106. /*-------------------------------------------------------------------------*//**
  1107. * <param name="c">Named command to set.</param>
  1108. * <param name="prefix">First character of the command.</param>
  1109. * <remarks>
  1110. * Change what command to type "/x" vs "#x" for example.
  1111. * </remarks>
  1112. *//*------------------------------------------------------------------------**/
  1113. #if defined Y_COMMANDS_USE_CHARS
  1114. FOREIGN__ bool:Command_SetPrefixNamed(string:c[], prefix);
  1115. GLOBAL__ bool:Command_SetPrefixNamed(string:c[], prefix)
  1116. {
  1117. return Command_SetPrefix(Command_Find(c), prefix);
  1118. }
  1119. #endif
  1120. /*
  1121. 88 88 88
  1122. 88 88 88
  1123. 88 88 88
  1124. 88aaaaaaaa88 ,adPPYba, ,adPPYba, 88 ,d8 ,adPPYba,
  1125. 88""""""""88 a8" "8a a8" "8a 88 ,a8" I8[ ""
  1126. 88 88 8b d8 8b d8 8888[ `"Y8ba,
  1127. 88 88 "8a, ,a8" "8a, ,a8" 88`"Yba, aa ]8I
  1128. 88 88 `"YbbdP"' `"YbbdP"' 88 `Y8a `"YbbdP"'
  1129. */
  1130. /*-------------------------------------------------------------------------*//**
  1131. * <param name="playerid">Player who typed something.</param>
  1132. * <param name="text">What they typed.</param>
  1133. * <returns>
  1134. * 0 - Could not process the command.
  1135. * 1 - Called the command.
  1136. * </returns>
  1137. * <remarks>
  1138. * Used to implement alternate command prefixes.
  1139. * </remarks>
  1140. *//*------------------------------------------------------------------------**/
  1141. MASTER_HOOK__ OnPlayerText(playerid, text[])
  1142. {
  1143. // Is this prefix used anywhere?
  1144. if (_Command_IsPrefix(text[0]))
  1145. {
  1146. // The default return for OnPlayerText is opposite OnPlayerCommandText.
  1147. return !Command_ReProcess(playerid, text, 0);
  1148. }
  1149. // Default return, do nothing.
  1150. return 1;
  1151. }
  1152. /*-------------------------------------------------------------------------*//**
  1153. * <param name="playerid">Player who typed a command.</param>
  1154. * <param name="cmdtext">What they typed.</param>
  1155. * <returns>
  1156. * 0 - Could not process the command.
  1157. * 1 - Called the command.
  1158. * </returns>
  1159. * <remarks>
  1160. * The core of the command processor. Now vsatly simplified.
  1161. *
  1162. * This function first finds the command in our hash map. If it exists, it
  1163. * checks if the player can use it. If they can, it checks if it is only in
  1164. * the current script. If it is it calls it directly, if it isn't it calls it
  1165. * using "CallRemoteFunction", which takes in to account master states in
  1166. * multiple scripts and the special master 23, which calls it in only one
  1167. * other script.
  1168. * </remarks>
  1169. *//*------------------------------------------------------------------------**/
  1170. MASTER_HOOK__ OnPlayerCommandText(playerid, cmdtext[])
  1171. {
  1172. // An interesting side-effect of this code is that, in theory, hacks that
  1173. // submit commands without the "/" will still work. Or you could hook
  1174. // "OnPlayerText" to call "Command_ReProcess" and still work as well.
  1175. return Command_ReProcess(playerid, cmdtext, 0);
  1176. }
  1177. /*-------------------------------------------------------------------------*//**
  1178. * <remarks>
  1179. * Add all local commands in to the system.
  1180. * </remarks>
  1181. *//*------------------------------------------------------------------------**/
  1182. HOOK__ OnScriptInit()
  1183. {
  1184. P:1("Command_OnScriptInit called");
  1185. YSI_g_sCommandFlags = e_COMMAND_FLAGS_OK;
  1186. #if YSIM_NOT_CLIENT
  1187. #if defined Y_COMMANDS_USE_CHARS
  1188. Bit_SetAll(YSI_g_sPrefixes, false),
  1189. Bit_Let(YSI_g_sPrefixes, '/'),
  1190. #endif
  1191. HashMap_Init(YSI_g_sCommandMap, YSI_g_sCommands, E_COMMAND_HASH_MAP);
  1192. for (new func = 0; func != MAX_COMMANDS; ++func)
  1193. {
  1194. YSI_g_sCommands[func][E_COMMAND_POINTER] = -1;
  1195. }
  1196. #endif
  1197. P:2("_Command_DoInit <> called");
  1198. new
  1199. entry,
  1200. buffer[32 char],
  1201. idx,
  1202. id2;
  1203. P:5("Command_OnScriptInit: Pre-loop");
  1204. while ((idx = AMX_GetPublicEntryPrefix(idx, entry, _A<@yC_>)))
  1205. {
  1206. // Add the command name and pointer, but skip the leading "@yC_".
  1207. P:6("Command_OnScriptInit: Adding %d", entry);
  1208. AMX_ReadString(AMX_BASE_ADDRESS + AMX_Read(entry + 4), buffer),
  1209. // buffer[0] = ('@' << 24) | ('_' << 16) | ('y' << 08) | ('C' << 00),
  1210. buffer[0] = _C<@_yC>,
  1211. id2 = funcidx(buffer);
  1212. if (id2 != -1) entry = AMX_HEADER_PUBLICS + id2 * 8;
  1213. // Check that the function name is all lower-case.
  1214. for (id2 = 4; buffer{id2}; ++id2)
  1215. {
  1216. if (buffer{id2} != tolower(buffer{id2})) P:E("Commands must be in lower-case in your source code.");
  1217. }
  1218. // Add the command regardless.
  1219. Command_Add(buffer[1], ResolveJITAddress(AMX_Read(entry)));
  1220. P:6("Command_OnScriptInit: Name %s", unpack(buffer[1]));
  1221. }
  1222. if (funcidx(YSI_gscOPCR) != -1) Command_IncOPCR();
  1223. if (funcidx(YSI_gscOPCP) != -1) Command_IncOPCP();
  1224. }
  1225. /*-------------------------------------------------------------------------*//**
  1226. * <remarks>
  1227. * Passes additional commands data to the new master.
  1228. * </remarks>
  1229. *//*------------------------------------------------------------------------**/
  1230. HANDOFF()
  1231. {
  1232. P:1("Commands_OnScriptExit <_YCM:p> called");
  1233. // Copy settings.
  1234. DISTRIBUTE(YSI_g_sCommandFlags);
  1235. DISTRIBUTE(YSI_g_sErrorMessages);
  1236. DISTRIBUTE(YSI_g_sDisabledPlayers);
  1237. // This accounts for master IDs.
  1238. DISTRIBUTE(YSI_g_sCommands);
  1239. // Now we've sent over the remaining valid commands, build the hash map.
  1240. _Command_Rebuild();
  1241. }
  1242. /*-------------------------------------------------------------------------*//**
  1243. * <remarks>
  1244. * When a script ends, update the status of any new callback hooks.
  1245. * </remarks>
  1246. *//*------------------------------------------------------------------------**/
  1247. HOOK__ OnScriptExit()
  1248. {
  1249. P:1("Commands_OnScriptExit <> called");
  1250. if (funcidx(YSI_gscOPCR) != -1) Command_DecOPCR();
  1251. if (funcidx(YSI_gscOPCP) != -1) Command_DecOPCP();
  1252. }
  1253. #if YSIM_HAS_MASTER
  1254. MASTER_HOOK__ OnMasterSystemClose(id)
  1255. {
  1256. new
  1257. cmdname[32 char] = {_C<@_yC>, 0, 0, ...},
  1258. Bit:cur = Bit:Master_ID(),
  1259. Bit:bit = Bit:(1 << id),
  1260. Bit:rem = ~bit;
  1261. for (new i = 0; i != MAX_COMMANDS; ++i)
  1262. {
  1263. if (_Command_IsActive(i))
  1264. {
  1265. if (YSI_g_sMasterData[i] == bit)
  1266. {
  1267. // Only existed in one (other) script. Remove it.
  1268. Command_Remove(i);
  1269. }
  1270. if ((YSI_g_sMasterData[i] &= rem) == cur)
  1271. {
  1272. if(YSI_g_sCommands[i][E_COMMAND_POINTER] & cellmin) continue;
  1273. // Existed in multiple, now only one.
  1274. strpack(cmdname[1], Command_Name(i), 31);
  1275. new
  1276. id2 = funcidx(cmdname);
  1277. if (id2 == -1)
  1278. {
  1279. P:W("Command marked EXCLUSIVE, but doesn't exist");
  1280. Command_Remove(i);
  1281. continue;
  1282. }
  1283. // Store the new pointer.
  1284. YSI_g_sCommands[i][E_COMMAND_POINTER] = ResolveJITAddress(AMX_Read(AMX_HEADER_PUBLICS + id2 * 8));
  1285. }
  1286. }
  1287. }
  1288. return 1;
  1289. }
  1290. #endif
  1291. /*
  1292. 88 88
  1293. 88 ,d 88
  1294. 88 88 88
  1295. 88 8b,dPPYba, MM88MMM ,adPPYba, 8b,dPPYba, 8b,dPPYba, ,adPPYYba, 88
  1296. 88 88P' `"8a 88 a8P_____88 88P' "Y8 88P' `"8a "" `Y8 88
  1297. 88 88 88 88 8PP""""""" 88 88 88 ,adPPPPP88 88
  1298. 88 88 88 88, "8b, ,aa 88 88 88 88, ,88 88
  1299. 88 88 88 "Y888 `"Ybbd8"' 88 88 88 `"8bbdP"Y8 88
  1300. */
  1301. /*-------------------------------------------------------------------------*//**
  1302. * <remarks>
  1303. * Rebuilds the hashmap of command pointers after a master script hands off.
  1304. * </remarks>
  1305. *//*------------------------------------------------------------------------**/
  1306. FOREIGN__ void:_Command_Rebuild();
  1307. GLOBAL__ void:_Command_Rebuild()
  1308. {
  1309. new
  1310. cmdname[32 char] = {('@' << 24) | ('_' << 16) | ('y' << 08) | ('C' << 00), 0, 0, ...};
  1311. HashMap_Init(YSI_g_sCommandMap, YSI_g_sCommands, E_COMMAND_HASH_MAP);
  1312. for (new i = 0; i != MAX_COMMANDS; ++i)
  1313. {
  1314. #if defined Y_COMMANDS_USE_CHARS
  1315. Bit_SetAll(YSI_g_sPrefixes, false),
  1316. Bit_Let(YSI_g_sPrefixes, '/');
  1317. #endif
  1318. if (_Command_IsActive(i))
  1319. {
  1320. #if defined Y_COMMANDS_USE_CHARS
  1321. Bit_Let(YSI_g_sPrefixes, _Command_GetPrefix(i)),
  1322. #endif
  1323. strpack(cmdname[1], Command_Name(i), 31),
  1324. HashMap_Add(YSI_g_sCommandMap, cmdname[1], i),
  1325. YSI_g_sHighestID = i + 1;
  1326. }
  1327. }
  1328. }
  1329. /*-------------------------------------------------------------------------*//**
  1330. * <remarks>
  1331. * This function, and the three other related ones, increment and decrement the
  1332. * number of callbacks known to exist on the server. If they are 0, there's no
  1333. * point trying to call them on errors etc.
  1334. * </remarks>
  1335. *//*------------------------------------------------------------------------**/
  1336. FOREIGN__ void:Command_IncOPCR();
  1337. GLOBAL__ void:Command_IncOPCR()
  1338. {
  1339. P:2("Command_IncOPCR called");
  1340. YSI_g_sCommandFlags += e_COMM_FLAG_OPCR_ADD;
  1341. }
  1342. FOREIGN__ void:Command_DecOPCR();
  1343. GLOBAL__ void:Command_DecOPCR()
  1344. {
  1345. P:2("Command_DecOPCR called");
  1346. YSI_g_sCommandFlags -= e_COMM_FLAG_OPCR_ADD;
  1347. }
  1348. FOREIGN__ void:Command_IncOPCP();
  1349. GLOBAL__ void:Command_IncOPCP()
  1350. {
  1351. P:2("Command_IncOPCP called");
  1352. YSI_g_sCommandFlags += e_COMM_FLAG_OPCP_ADD;
  1353. }
  1354. FOREIGN__ void:Command_DecOPCP();
  1355. GLOBAL__ void:Command_DecOPCP()
  1356. {
  1357. P:2("Command_DecOPCP called");
  1358. YSI_g_sCommandFlags -= e_COMM_FLAG_OPCP_ADD;
  1359. }
  1360. /*-------------------------------------------------------------------------*//**
  1361. * <returns>
  1362. * The first available slot in "YSI_g_sCommands".
  1363. * </returns>
  1364. *//*------------------------------------------------------------------------**/
  1365. static stock Command_GetEmptySlot()
  1366. {
  1367. for (new i = 0; i != MAX_COMMANDS; ++i)
  1368. {
  1369. // No name for the command, can't exist.
  1370. if (_Command_IsEmptySlot(i)) return i;
  1371. }
  1372. return COMMAND_NOT_FOUND;
  1373. }
  1374. /*-------------------------------------------------------------------------*//**
  1375. * <param name="cmd">The command name to add.</param>
  1376. * <param name="ptr">The command's pointer.</param>
  1377. * <param name="id">Where to store the command (default -1 = find).</param>
  1378. * <returns>
  1379. * The command's ID.
  1380. * </returns>
  1381. * <remarks>
  1382. * This was an external API function, but there is no reason for it to be as it
  1383. * is called for all found commands at mode start.
  1384. * </remarks>
  1385. *//*------------------------------------------------------------------------**/
  1386. FOREIGN__ Command_Add(string:cmd[], ptr);
  1387. GLOBAL__ Command_Add(string:cmd[], ptr)
  1388. {
  1389. // The commands all need to be stored packed.
  1390. strpack(cmd, cmd, cellmax);
  1391. P:2("Command_Add: %s, %d", unpack(cmd), ptr);
  1392. new
  1393. id = Command_Find(cmd);
  1394. P:5("Command_Add: found %d", id);
  1395. if (id == COMMAND_NOT_FOUND)
  1396. {
  1397. // Command doesn't already exist, add it.
  1398. if ((id = Command_GetEmptySlot()) == COMMAND_NOT_FOUND)
  1399. {
  1400. P:E("Could not add command to array.");
  1401. return COMMAND_NOT_FOUND;
  1402. }
  1403. #if defined Y_COMMANDS_USE_CHARS
  1404. YSI_g_sCommands[id][E_COMMAND_PREFIX] = '/',
  1405. #endif
  1406. YSI_g_sHighestID = max(YSI_g_sHighestID, id + 1),
  1407. // Save the command's pointer.
  1408. YSI_g_sCommands[id][E_COMMAND_POINTER] = ptr,
  1409. // Add this command to the hash map (does the name too).
  1410. HashMap_Add(YSI_g_sCommandMap, cmd, id),
  1411. // Add all players, or defer to y_groups.
  1412. PA_FastInit(YSI_g_sCommands[id][E_COMMAND_USERS]);
  1413. NO_GROUPS<Command>(id)
  1414. {
  1415. PA_Init(YSI_g_sCommands[id][E_COMMAND_USERS], true);
  1416. }
  1417. // Add the calling script as having this command.
  1418. MASTER_SET<id>
  1419. }
  1420. else
  1421. {
  1422. // Add this script to the list of providers.
  1423. MASTER_ADD<id>
  1424. }
  1425. return id;
  1426. }
  1427. /*-------------------------------------------------------------------------*//**
  1428. * <param name="f">Command to get the real name of.</param>
  1429. * <param name="p">Player to get the name for.</param>
  1430. * <returns>
  1431. * The name of a command for a single player.
  1432. * </returns>
  1433. *//*------------------------------------------------------------------------**/
  1434. static stock _Command_GetDisplay(funcid, playerid)
  1435. {
  1436. YSI_g_sReturnBuffer[0] = '\0';
  1437. if (_Command_IsValid(funcid) && VALID_PLAYERID(playerid))
  1438. {
  1439. new
  1440. slot = PA_Slot(playerid),
  1441. Bit:mask = PA_Mask(playerid);
  1442. // Check if they can use the original version.
  1443. if (YSI_g_sCommands[funcid][E_COMMAND_USERS][slot] & mask)
  1444. {
  1445. return strunpack(YSI_g_sReturnBuffer, Command_Name(funcid));
  1446. }
  1447. // BAD REUSE OF THE "playerid" VARIABLE.
  1448. if ((playerid = YSI_g_sCommands[funcid][E_COMMAND_POINTER]) & cellmin)
  1449. {
  1450. // The given function is an alternate version of a real function -
  1451. // test the parent function first.
  1452. // BAD REUSE OF THE "playerid" VARIABLE.
  1453. if (YSI_g_sCommands[(funcid = playerid & ~cellmin)][E_COMMAND_USERS][slot] & mask)
  1454. {
  1455. return strunpack(YSI_g_sReturnBuffer, Command_Name(funcid));
  1456. }
  1457. }
  1458. // Now we have a root command, check all alternates to this one.
  1459. funcid |= cellmin;
  1460. for (new i = 0; i != YSI_g_sHighestID; ++i)
  1461. {
  1462. if (_Command_IsActive(i) && YSI_g_sCommands[i][E_COMMAND_POINTER] == funcid && (YSI_g_sCommands[i][E_COMMAND_USERS][slot] & mask))
  1463. {
  1464. return strunpack(YSI_g_sReturnBuffer, Command_Name(i));
  1465. }
  1466. }
  1467. }
  1468. return 0;
  1469. }