y_commands.inc 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252
  1. /*----------------------------------------------------------------------------*-
  2. ================================
  3. Y Sever Includes - Commands Core
  4. ================================
  5. Description:
  6. Runs commands registered with the system and calls the required functions.
  7. Also handles alternate names and prefixes. Theory based very loosely on dcmd.
  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 SA:MP script information include.
  19. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  20. Portions created by the Initial Developer are Copyright (C) 2008
  21. the Initial Developer. All Rights Reserved.
  22. Contributors:
  23. ZeeX, koolk
  24. Thanks:
  25. Peter, Cam - Support.
  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.
  40. Kye/Kalcor - SA:MP.
  41. SA:MP Team past, present and future - SA:MP.
  42. Version:
  43. 0.1.4
  44. Changelog:
  45. 20/10/10:
  46. Fixed a bug with insensitive commands - my fault for not testing.
  47. 06/01/08:
  48. Improved master and /help support.
  49. 04/01/08:
  50. Fixed bad element in Command_SetDeniedReturn.
  51. 12/08/07:
  52. Added master support.
  53. 24/06/07:
  54. Modifed a few functions to use Bit_GetBit for speed.
  55. 04/05/07:
  56. Completed command use support.
  57. Added invalid character protection.
  58. 02/05/07:
  59. Added YSI_ prefix to all globals.
  60. 14/04/07:
  61. Updated header documentation with more than changelog/functions.
  62. Added function name requesting.
  63. 13/04/07:
  64. Added function documentation.
  65. Added wrapped functions for e_COMM_FLAG values missing them.
  66. Added header function list.
  67. 12/04/07:
  68. Added command removal.
  69. 11/04/07:
  70. Changed system slightly to handle names and alt names separately. Still need
  71. a better way of ignoring names when alt names are used.
  72. 10/04/07:
  73. First version.
  74. Functions:
  75. Public:
  76. Command_Add - Adds a command to the array for processing.
  77. Command_Remove - Removes a command.
  78. Command_Name - Gets the name of a command in a property.
  79. Core:
  80. Command_Process - Called from OnPlayerCommandText to process entered commands.
  81. Command_Parse - Sorts added commands into a binary tree.
  82. Command_Hash - Hashes a word for command hashing.
  83. Command_ProcRem - Processes a help command in the master script.
  84. Stock:
  85. Command_SetDisconnectReturn - Sets the return value for unconnected players.
  86. Command_UseShortCuts - Toggles use of per-player command shortcuts.
  87. Command_SetDeniedReturn - Sets the return value for denied use commands.
  88. Command_UseDeniedMessage - Toggles the use of an error message for denied.
  89. Command_SetIllegalReturn - Sets the return value for illegal characters.
  90. Command_UseAltNames - Toggles the use of ini defined alternate names.
  91. Command_UsePrefix - Toggles the use of a global prefix.
  92. Command_UseSpace - Toggles the use of a space between prefix and command.
  93. Command_SetAltName - Sets the alternate name of a function.
  94. Command_SetPrefix - Sets the pfexix to be typed.
  95. Comamnd_SetPlayerUse - Sets wether or not a player can use a command.
  96. Comamnd_SetPlayerUseByID - Sets wether or not a player can use a command.
  97. Command_FindByName - Finds a command in a possibly sorted list.
  98. Static:
  99. Command_FindFast - Finds a function by binary search of function name.
  100. Command_FindAlt - Finds a function by binary search of alternate name.
  101. Command_SetSorted - Marks the binary tree as sorted.
  102. Command_FindSlow - Finds a function by linear search of function name.
  103. Command_Find - Finds a function from entered text.
  104. Command_Prefix - Checks the entered prefix.
  105. Command_ReturnName - Returns the name of a function.
  106. Command_GetPlayerCount - Gets the number of commands a player can use.
  107. Inline:
  108. Command_Command - Not used, constructor.
  109. Command_IsCleared - Checks a player is cleared to use a command.
  110. Command_DisconnectReturn - Gets the return value for disconnected players.
  111. Command_UsingShortCuts - Checks if short cuts are being used.
  112. Command_DeniedReturn - Gets the return value for prohibited commands.
  113. Command_IllegalReturn - Gets the return value for invalid characters.
  114. Command_DeniedMessage - Checks if a level error message should be sent.
  115. Command_IsSorted - Checks if the binary tree has been initialised.
  116. Command_UsingAltNames - Checks if alt names are being used.
  117. Command_UsingPrefix - Checks if the prefix is being used.
  118. Command_UsingSpace - Checks if the space option is being used.
  119. Command_CallFunction - Calls the required function.
  120. ycmd - Adds a command to the system.
  121. API:
  122. -
  123. Callbacks:
  124. -
  125. Definitions:
  126. MAX_COMMAND_LENGTH - The maximum length of a command string.
  127. COMMAND_NOT_FOUND - Indicates that a searched for string is not a function.
  128. Enums:
  129. e_COMM_FLAG - Bit mappings for command options.
  130. E_COMMANDS - Structure of the array holding the string data.
  131. Macros:
  132. Command_(%1) - Forwards and declares a standard command for calling.
  133. ycmd(%1) - Adds a command to the array (wrapper for Command_Add).
  134. Tags:
  135. e_COMM_FLAG - Flag type.
  136. Variables:
  137. Global:
  138. -
  139. Static:
  140. YSI_g_sCommands - Holds all the textual data of the commands.
  141. YSI_g_sSearchTree - Tree of hashes for function names.
  142. YSI_g_sAltTree - Tree of hashes for alternate names.
  143. YSI_g_sPrefix - The command prefix.
  144. YSI_g_sPrefixLength - Length of the prefix.
  145. YSI_g_sCommandIndex - Pointer to the next free index in the function array.
  146. YSI_g_sAltCount - The number of commands with altnames.
  147. YSI_g_sCommandFlags - Bit array of command options.
  148. Commands:
  149. commands - Lists all commands available to you.
  150. Compile options:
  151. COMMAND_SENSITIVE - Make commands case sensitive.
  152. COMMAND_ACCURATE - Can use '@' in command names.
  153. MAX_COMMANDS - The maximum number of commands which can be used.
  154. -*----------------------------------------------------------------------------*/
  155. #include <YSI\internal\y_version>
  156. #if !defined MAX_COMMANDS
  157. #define MAX_COMMANDS (1024)
  158. #endif
  159. #define _GROUP_MAKE_NAME_CMD<%0...%1> %0Command%1
  160. #define _GROUP_MAKE_LIMIT_CMD MAX_COMMANDS
  161. #include <YSI\y_master>
  162. #include <YSI\y_groups>
  163. #include <YSI\y_debug>
  164. #include <YSI\y_bintree>
  165. #include <YSI\y_scripting>
  166. #include <YSI\y_playerarray>
  167. #include <YSI\y_utils>
  168. // Define the CMD: macro. This uses the prefix "@yC_" as it's 32 bits so allows
  169. // for fast command string searching in the publics table and makes the commands
  170. // public without the need for the public keyword.
  171. /*#if YSIM_HAS_MASTER
  172. #if YSIM_IS_CLIENT
  173. #define YCMD:%1(%2) static stock yC@_%1(%2)
  174. #else
  175. #if YSIM_IS_SERVER
  176. #define YCMD:%1(%2) forward @yC_%1(a,b[],c);@yC_%1(a,b[],c)U@(8,YSIM_RETURN,yC@_%1(a,b,c));static yC@_%1(%2)
  177. #else
  178. #define YCMD:%1(%2) forward @yC_%1(a,b[],c);@yC_%1(a,b[],c)<>{}@yC_%1(a,b[],c)<_YCM:y>U@(8,YSIM_RETURN,yC@_%1(a,b,c));static yC@_%1(%2)
  179. #endif
  180. #endif
  181. #else
  182. #define YCMD:%1(%2) forward @yC_%1(%2);@yC_%1(%2)
  183. #endif*/
  184. #define YCMD:%0(%1) RC:%0(%1)
  185. // ZCMD compatibility.
  186. #define CMD:%0(%1) RC:%0(%1,_h_e_l_p_)if(_h_e_l_p_)return 0;else
  187. #define COMMAND CMD
  188. // This is opposite Scripting_FastString as that's in C, not packed, order.
  189. #define Command_FastString(%1,%2,%3,%4) \
  190. (((%1) << 24) | ((%2) << 16) | ((%3) << 8) | ((%4) << 0))
  191. #define MAX_COMMAND_LENGTH (32)
  192. #define COMMAND_NOT_FOUND (-1)
  193. #if defined COMMAND_SENSITIVE
  194. #define TOLOWER(%0) (%0)
  195. #define COMMAND_END_CMP (0)
  196. #else
  197. #if defined COMMAND_ACCURATE
  198. #define TOLOWER(%0) tolower(%0)
  199. #define COMMAND_END_CMP (0)
  200. #else
  201. #define TOLOWER(%0) ((%0) | 0x20)
  202. #define COMMAND_END_CMP (0x20)
  203. #endif
  204. #endif
  205. // Don't forget the Scripting_FastString below if you change this.
  206. #define COMMAND_FUNCTION_PREFIX (Command_FastString('@', 'y', 'C', '_'))
  207. // Reset both of these when you remove a command.
  208. #define _Command_IsValid(%0) ((Command_GetPointer(%0)==(%0))||(YSI_g_sCommands[(%0)][E_COMMANDS_MASTERS]==-1))
  209. #define Command_IsValid(%0) ((0<=(%0)<MAX_COMMANDS)&&_Command_IsValid(%0))
  210. enum e_COMM_FLAG (<<= 1)
  211. {
  212. e_COMM_FLAG_PROVIDER = 0x000000FF,
  213. e_COMM_FLAG_SORTED = 0x00000100,
  214. e_COMM_FLAG_PERMISSION_WARN,
  215. e_COMM_FLAG_USE_ALTNAMES,
  216. e_COMM_FLAG_PERMISSION_RET,
  217. e_COMM_FLAG_USE_PREFIX,
  218. e_COMM_FLAG_USE_SPACE,
  219. e_COMM_FLAG_USE_SHORTCUTS,
  220. e_COMM_FLAG_DISCONNECT,
  221. e_COMM_FLAG_ILLEGAL,
  222. e_COMM_FLAG_OPCT,
  223. e_COMM_FLAG_OPC,
  224. e_COMM_FLAG_COLLISION,
  225. e_COMM_FLAG_UNKNOWN,
  226. e_COMM_FLAG_MULPRO
  227. }
  228. enum E_COMMANDS
  229. {
  230. E_COMMANDS_FUNCTION[MAX_COMMAND_LENGTH char],
  231. PlayerArray:E_COMMANDS_PLAYERS<MAX_PLAYERS>,
  232. E_COMMANDS_FUNC_POINTER,
  233. E_COMMANDS_MASTERS
  234. }
  235. static stock
  236. YSI_g_sCommands[MAX_COMMANDS][E_COMMANDS],
  237. BinaryTree:YSI_g_sSearchTree<MAX_COMMANDS>,
  238. e_COMM_FLAG:YSI_g_sCommandFlags = e_COMM_FLAG:0xFF,
  239. YSI_g_sCommandIndex,
  240. YSI_g_sCommandCount,
  241. //YSI_g_sCommandDialog[MAX_PLAYERS] = {-1, ...},
  242. YSI_g_sMaster23,
  243. YSI_g_sPlayerProvider[MAX_PLAYERS char] = {-1, ...};
  244. /*Group:Command_InitialiseFromGroups(x)
  245. {
  246. //Bit_SetAll(YSI_g_sCommands[x][E_COMMANDS_PLAYERS], true, bits<MAX_PLAYERS>);
  247. PA_Init(YSI_g_sCommands[x][E_COMMANDS_PLAYERS], true, bits<MAX_PLAYERS>);
  248. }*/
  249. /*----------------------------------------------------------------------------*-
  250. Function:
  251. Command_Name
  252. Params:
  253. index - Index of the command to operate on.
  254. Return:
  255. -
  256. Notes:
  257. Gets the name of a function from the array.
  258. -*----------------------------------------------------------------------------*/
  259. #define Command_Name(%1) \
  260. (YSI_g_sCommands[(%1)][E_COMMANDS_FUNCTION][1])
  261. /*----------------------------------------------------------------------------*-
  262. Function:
  263. Command_GetFuncName
  264. Params:
  265. index - Index of the command to operate on.
  266. Return:
  267. -
  268. Notes:
  269. Gets the full function name for a slot - note that this may not be the right
  270. function if this slot points to another one.
  271. -*----------------------------------------------------------------------------*/
  272. #define Command_GetFuncName(%1) \
  273. (YSI_g_sCommands[(%1)][E_COMMANDS_FUNCTION])
  274. /*----------------------------------------------------------------------------*-
  275. Function:
  276. Command_GetPointer
  277. Params:
  278. index - Index of the command to operate on.
  279. Return:
  280. -
  281. Notes:
  282. Gets the pointer for a function from the array.
  283. -*----------------------------------------------------------------------------*/
  284. #define Command_GetPointer(%1) \
  285. (YSI_g_sCommands[(%1)][E_COMMANDS_FUNC_POINTER]&0x00FFFFFF)
  286. /*----------------------------------------------------------------------------*-
  287. Function:
  288. Command_GetProvider
  289. Params:
  290. index - Index of the command to operate on.
  291. Return:
  292. -
  293. Notes:
  294. Gets the unique script in which this version of the command is.
  295. -*----------------------------------------------------------------------------*/
  296. #define Command_Provider(%1) \
  297. (YSI_g_sCommands[(%1)][E_COMMANDS_FUNC_POINTER]>>>24)
  298. /*----------------------------------------------------------------------------*-
  299. Function:
  300. Command_GetProvider
  301. Params:
  302. index - Index of the command to operate on.
  303. Return:
  304. -
  305. Notes:
  306. Gets the unique script in which this version of the command is.
  307. -*----------------------------------------------------------------------------*/
  308. #define Command_DefaultProvider() \
  309. (YSI_g_sCommandFlags & e_COMM_FLAG_PROVIDER)
  310. /*----------------------------------------------------------------------------*-
  311. Function:
  312. Command_GetFunction
  313. Params:
  314. index - Index of the command to operate on.
  315. Return:
  316. -
  317. Notes:
  318. Gets the real function for this slot.
  319. -*----------------------------------------------------------------------------*/
  320. #define Command_GetFunction(%1) \
  321. (Command_GetFuncName(Command_GetPointer((%1))))
  322. /*----------------------------------------------------------------------------*-
  323. Function:
  324. Command_CheckPlayer
  325. Params:
  326. index - Index of the command to operate on.
  327. playerid - The player to check for.
  328. Return:
  329. -
  330. Notes:
  331. Gets wether a player can use a command.
  332. -*----------------------------------------------------------------------------*/
  333. #define Command_CheckPlayer(%1,%2) \
  334. (YSI_g_sCommands[(%1)][E_COMMANDS_PLAYERS][Bit_Slot(%2)+1]&Bit_Mask(%2))
  335. //(PA=([E_COMMANDS_PLAYERS], (%2)))
  336. //(Bit_Get(YSI_g_sCommands[(%1)][E_COMMANDS_PLAYERS], (%2)))
  337. /*----------------------------------------------------------------------------*-
  338. Function:
  339. Command_DeniedReturn
  340. Params:
  341. -
  342. Return:
  343. e_COMM_FLAG_PERMISSION_RET
  344. Notes:
  345. -
  346. -*----------------------------------------------------------------------------*/
  347. #define Command_DeniedReturn() \
  348. (YSI_g_sCommandFlags & e_COMM_FLAG_PERMISSION_RET)
  349. /*----------------------------------------------------------------------------*-
  350. Function:
  351. Command_SetDeniedReturn
  352. Params:
  353. -
  354. Return:
  355. -
  356. Notes:
  357. -
  358. -*----------------------------------------------------------------------------*/
  359. RF@v:Command_SetDeniedReturn[i](bool:set)
  360. {
  361. if (set)
  362. {
  363. YSI_g_sCommandFlags |= e_COMM_FLAG_PERMISSION_RET;
  364. }
  365. else
  366. {
  367. YSI_g_sCommandFlags &= ~e_COMM_FLAG_PERMISSION_RET;
  368. }
  369. }
  370. RF@v:Command_SetProvider[i](p)
  371. {
  372. YSI_g_sCommandFlags = (YSI_g_sCommandFlags & ~e_COMM_FLAG_PROVIDER) | (e_COMM_FLAG:p & e_COMM_FLAG_PROVIDER) | e_COMM_FLAG_MULPRO;
  373. }
  374. RF:Command_GetProvider[]()
  375. {
  376. return _:Command_DefaultProvider();
  377. }
  378. RF@v:Command_SetPlayerProvider[ii](playerid,p)
  379. {
  380. if (0 <= playerid < MAX_PLAYERS)
  381. {
  382. YSI_g_sPlayerProvider{playerid} = p & 0xFF;
  383. }
  384. }
  385. RF:Command_GetPlayerProvider[i](playerid)
  386. {
  387. return YSI_g_sPlayerProvider{playerid};
  388. }
  389. /*----------------------------------------------------------------------------*-
  390. Function:
  391. Command_GetDeniedReturn
  392. Params:
  393. -
  394. Return:
  395. -
  396. Notes:
  397. -
  398. -*----------------------------------------------------------------------------*/
  399. RF@t:bool:Command_GetDeniedReturn[]()
  400. {
  401. return bool:Command_DeniedReturn();
  402. }
  403. /*----------------------------------------------------------------------------*-
  404. Function:
  405. Command_HasCollisions
  406. Params:
  407. -
  408. Return:
  409. e_COMM_FLAG_COLLISION
  410. Notes:
  411. -
  412. -*----------------------------------------------------------------------------*/
  413. #define Command_HasCollisions() \
  414. (YSI_g_sCommandFlags & e_COMM_FLAG_COLLISION)
  415. /*----------------------------------------------------------------------------*-
  416. Function:
  417. Command_HasCollisions
  418. Params:
  419. -
  420. Return:
  421. e_COMM_FLAG_MULPRO
  422. Notes:
  423. -
  424. -*----------------------------------------------------------------------------*/
  425. #define Command_HasMultipleProviders() \
  426. (YSI_g_sCommandFlags & e_COMM_FLAG_MULPRO)
  427. /*----------------------------------------------------------------------------*-
  428. Function:
  429. Command_SetCollisions
  430. Params:
  431. -
  432. Return:
  433. -
  434. Notes:
  435. -
  436. -*----------------------------------------------------------------------------*/
  437. #define Command_SetCollisions() \
  438. YSI_g_sCommandFlags |= e_COMM_FLAG_COLLISION
  439. /*----------------------------------------------------------------------------*-
  440. Function:
  441. Command_IllegalReturn
  442. Params:
  443. -
  444. Return:
  445. e_COMM_FLAG_ILLEGAL
  446. Notes:
  447. -
  448. -*----------------------------------------------------------------------------*/
  449. #define Command_IllegalReturn() \
  450. (YSI_g_sCommandFlags & e_COMM_FLAG_ILLEGAL)
  451. /*----------------------------------------------------------------------------*-
  452. Function:
  453. Command_SetIllegalReturn
  454. Params:
  455. -
  456. Return:
  457. -
  458. Notes:
  459. -
  460. -*----------------------------------------------------------------------------*/
  461. RF@v:Command_SetIllegalReturn[i](bool:set)
  462. {
  463. if (set)
  464. {
  465. YSI_g_sCommandFlags |= e_COMM_FLAG_ILLEGAL;
  466. }
  467. else
  468. {
  469. YSI_g_sCommandFlags &= ~e_COMM_FLAG_ILLEGAL;
  470. }
  471. }
  472. /*----------------------------------------------------------------------------*-
  473. Function:
  474. Command_GetIllegalReturn
  475. Params:
  476. -
  477. Return:
  478. -
  479. Notes:
  480. -
  481. -*----------------------------------------------------------------------------*/
  482. RF@t:bool:Command_GetIllegalReturn[]()
  483. {
  484. return bool:Command_IllegalReturn();
  485. }
  486. /*----------------------------------------------------------------------------*-
  487. Function:
  488. Command_IllegalReturn
  489. Params:
  490. -
  491. Return:
  492. e_COMM_FLAG_ILLEGAL
  493. Notes:
  494. -
  495. -*----------------------------------------------------------------------------*/
  496. #define Command_UnknownReturn() \
  497. (YSI_g_sCommandFlags & e_COMM_FLAG_UNKNOWN)
  498. /*----------------------------------------------------------------------------*-
  499. Function:
  500. Command_SetIllegalReturn
  501. Params:
  502. -
  503. Return:
  504. -
  505. Notes:
  506. -
  507. -*----------------------------------------------------------------------------*/
  508. RF@v:Command_SetUnknownReturn[i](bool:set)
  509. {
  510. if (set)
  511. {
  512. YSI_g_sCommandFlags |= e_COMM_FLAG_UNKNOWN;
  513. }
  514. else
  515. {
  516. YSI_g_sCommandFlags &= ~e_COMM_FLAG_UNKNOWN;
  517. }
  518. }
  519. /*----------------------------------------------------------------------------*-
  520. Function:
  521. Command_GetIllegalReturn
  522. Params:
  523. -
  524. Return:
  525. -
  526. Notes:
  527. -
  528. -*----------------------------------------------------------------------------*/
  529. RF@t:bool:Command_GetUnknownReturn[]()
  530. {
  531. return bool:Command_UnknownReturn();
  532. }
  533. /*----------------------------------------------------------------------------*-
  534. Function:
  535. Command_DisconnectReturn
  536. Params:
  537. -
  538. Return:
  539. e_COMM_FLAG_DISCONNECT
  540. Notes:
  541. -
  542. -*----------------------------------------------------------------------------*/
  543. #define Command_DisconnectReturn() \
  544. (YSI_g_sCommandFlags & e_COMM_FLAG_DISCONNECT)
  545. /*----------------------------------------------------------------------------*-
  546. Function:
  547. Command_SetDisconnectReturn
  548. Params:
  549. -
  550. Return:
  551. -
  552. Notes:
  553. -
  554. -*----------------------------------------------------------------------------*/
  555. RF@v:Command_SetDisconnectReturn[i](bool:set)
  556. {
  557. if (set)
  558. {
  559. YSI_g_sCommandFlags |= e_COMM_FLAG_DISCONNECT;
  560. }
  561. else
  562. {
  563. YSI_g_sCommandFlags &= ~e_COMM_FLAG_DISCONNECT;
  564. }
  565. }
  566. /*----------------------------------------------------------------------------*-
  567. Function:
  568. Command_GetDisconnectReturn
  569. Params:
  570. -
  571. Return:
  572. -
  573. Notes:
  574. -
  575. -*----------------------------------------------------------------------------*/
  576. RF@t:bool:Command_GetDisconnectReturn[]()
  577. {
  578. return bool:Command_DisconnectReturn();
  579. }
  580. /*----------------------------------------------------------------------------*-
  581. Function:
  582. Command_DeniedDisplay
  583. Params:
  584. -
  585. Return:
  586. e_COMM_FLAG_PERMISSION_WARN
  587. Notes:
  588. -
  589. -*----------------------------------------------------------------------------*/
  590. #define Command_DeniedDisplay() \
  591. (YSI_g_sCommandFlags & e_COMM_FLAG_PERMISSION_WARN)
  592. /*----------------------------------------------------------------------------*-
  593. Function:
  594. Command_SetDeniedDisplay
  595. Params:
  596. -
  597. Return:
  598. -
  599. Notes:
  600. -
  601. -*----------------------------------------------------------------------------*/
  602. RF@v:Command_SetDeniedDisplay[i](bool:set)
  603. {
  604. if (set)
  605. {
  606. YSI_g_sCommandFlags |= e_COMM_FLAG_PERMISSION_WARN;
  607. }
  608. else
  609. {
  610. YSI_g_sCommandFlags &= ~e_COMM_FLAG_PERMISSION_WARN;
  611. }
  612. }
  613. /*----------------------------------------------------------------------------*-
  614. Function:
  615. Command_GetDeniedDisplay
  616. Params:
  617. -
  618. Return:
  619. -
  620. Notes:
  621. -
  622. -*----------------------------------------------------------------------------*/
  623. RF@t:bool:Command_GetDeniedDisplay[]()
  624. {
  625. return bool:Command_DeniedDisplay();
  626. }
  627. /*----------------------------------------------------------------------------*-
  628. Function:
  629. Command_GetNameInt
  630. Params:
  631. f - Command to get the name of.
  632. Return:
  633. -
  634. Notes:
  635. -
  636. -*----------------------------------------------------------------------------*/
  637. /*RF:Command_GetNameInt[i](f)
  638. {
  639. if (f >= 0 && f < YSI_g_sCommandIndex)
  640. {
  641. setproperty(8, "", YSIM_STRING, Command_Name(f));
  642. return 1;
  643. }
  644. return 0;
  645. }*/
  646. /*----------------------------------------------------------------------------*-
  647. Function:
  648. Command_GetName
  649. Params:
  650. funcid - Command to get the name of.
  651. Return:
  652. -
  653. Notes:
  654. native Command_GetName(funcid);
  655. -*----------------------------------------------------------------------------*/
  656. /*stock Command_GetName(funcid)
  657. {
  658. new
  659. buffer[32] = "";
  660. if (Command_GetNameInt(funcid))
  661. {
  662. getproperty(8, "", YSIM_STRING, buffer);
  663. strunpack(buffer, buffer);
  664. }
  665. return buffer;
  666. }*/
  667. /*----------------------------------------------------------------------------*-
  668. Function:
  669. Command_IsSorted
  670. Params:
  671. -
  672. Return:
  673. e_COMM_FLAG_SORTED
  674. Notes:
  675. -
  676. -*----------------------------------------------------------------------------*/
  677. #define Command_IsSorted() \
  678. (YSI_g_sCommandFlags & e_COMM_FLAG_SORTED)
  679. /*----------------------------------------------------------------------------*-
  680. Function:
  681. Command_Generate
  682. Params:
  683. -
  684. Return:
  685. -
  686. Notes:
  687. -
  688. -*----------------------------------------------------------------------------*/
  689. RF@v:Command_Generate[]()
  690. {
  691. P:2("Command_Generate called");
  692. if (!Command_IsSorted())
  693. {
  694. P:3("Command_Generate: Count = %d", YSI_g_sCommandCount);
  695. new
  696. data[MAX_COMMANDS][E_BINTREE_INPUT];
  697. // This is only called once, so we know YSI_g_sCommandCount will be
  698. // accurate WRT the locations of commands.
  699. for (new i = 0; i != YSI_g_sCommandCount; ++i)
  700. {
  701. data[i][E_BINTREE_INPUT_POINTER] = i;
  702. new
  703. hash = Command_PackHash(Command_Name(i));
  704. // Check for an existing command with this hash.
  705. if (!Command_HasCollisions())
  706. {
  707. for (new j = 0; j != i; ++j)
  708. {
  709. if (hash == data[j][E_BINTREE_INPUT_VALUE])
  710. {
  711. Command_SetCollisions();
  712. break;
  713. }
  714. }
  715. }
  716. C:3(else printf("Command_Generate: Hash = %d", hash););
  717. P:3("Command_Generate: Hash = %d", hash);
  718. data[i][E_BINTREE_INPUT_VALUE] = hash;
  719. }
  720. Bintree_Generate(YSI_g_sSearchTree, data, YSI_g_sCommandCount);
  721. P:4("Command_Generate: %d %d %d %d %d", YSI_g_sSearchTree[0][E_BINTREE_TREE_VALUE], YSI_g_sSearchTree[0][E_BINTREE_TREE_LEFT], YSI_g_sSearchTree[0][E_BINTREE_TREE_RIGHT], YSI_g_sSearchTree[0][E_BINTREE_TREE_PARENT], YSI_g_sSearchTree[0][E_BINTREE_TREE_POINTER]);
  722. // Set sorted to true.
  723. YSI_g_sCommandFlags |= e_COMM_FLAG_SORTED;
  724. }
  725. }
  726. /*----------------------------------------------------------------------------*-
  727. Function:
  728. OnScriptInit
  729. Params:
  730. -
  731. Return:
  732. -
  733. Notes:
  734. -
  735. -*----------------------------------------------------------------------------*/
  736. #if defined FILTERSCRIPT
  737. public OnFilterScriptInit()
  738. #else
  739. public OnGameModeInit()
  740. #endif
  741. {
  742. // Set the default provider as any script.
  743. //YSI_g_sCommandFlags = 0xFF;
  744. P:1("Command_OnScriptInit called");
  745. // Initialise the tree.
  746. #if YSIM_NOT_CLIENT
  747. Bintree_Reset(YSI_g_sSearchTree);
  748. YSI_g_sMaster23 = getproperty(8, "x@");
  749. #endif
  750. // Make a list of unused commands.
  751. for (new i = 0; i != MAX_COMMANDS - 1; ++i)
  752. {
  753. YSI_g_sCommands[i][E_COMMANDS_FUNC_POINTER] = i + 1;
  754. }
  755. YSI_g_sCommands[MAX_COMMANDS - 1][E_COMMANDS_FUNC_POINTER] = -1;
  756. // Loop through all the possible commands. Note that this may need to add
  757. // commands to the remote command system if this is not the master system.
  758. // The way the master system is designed means that we will know if we are
  759. // master or not by the time this function is called.
  760. new
  761. buffer[32],
  762. idx;
  763. // This is the only place where Scripting_FastString is used instead of
  764. // Commands_FastString as the strings in the AMX are not the same as packed
  765. // strings - they are in different memory orders.
  766. while ((idx = Scripting_GetPublicFast(idx, buffer, (Scripting_FastString('@', 'y', 'C', '_')))))
  767. {
  768. Command_Add(buffer, _@);
  769. P:2("Command_OnScriptInit: Adding %s", buffer);
  770. }
  771. Command_Generate();
  772. // Now that all commands have been added to the array, sort it.
  773. // Now call the next constructor.
  774. if (funcidx("Command_OnPlayerCommandText") != -1)
  775. {
  776. YSI_g_sCommandFlags |= e_COMM_FLAG_OPCT;
  777. }
  778. if (funcidx("Command_OnPlayerConnect") != -1)
  779. {
  780. YSI_g_sCommandFlags |= e_COMM_FLAG_OPC;
  781. }
  782. CallLocalFunction("Command_OnScriptInit", "");
  783. }
  784. #if defined FILTERSCRIPT
  785. #if defined _ALS_OnFilterScriptInit
  786. #undef OnFilterScriptInit
  787. #else
  788. #define _ALS_OnFilterScriptInit
  789. #endif
  790. #define OnFilterScriptInit Command_OnScriptInit
  791. #else
  792. #if defined _ALS_OnGameModeInit
  793. #undef OnGameModeInit
  794. #else
  795. #define _ALS_OnGameModeInit
  796. #endif
  797. #define OnGameModeInit Command_OnScriptInit
  798. #endif
  799. forward Command_OnScriptInit();
  800. /*----------------------------------------------------------------------------*-
  801. Function:
  802. OnScriptClose
  803. Params:
  804. script - ID of the closing script.
  805. Return:
  806. -
  807. Notes:
  808. Called when a script under the control of the master system ends.
  809. -*----------------------------------------------------------------------------*/
  810. #if YSIM_NOT_CLIENT
  811. #if YSIM_CLOUD
  812. public OnScriptClose(script) <>
  813. {
  814. CallLocalFunction("Command_OnScriptClose", "i", script);
  815. }
  816. public OnScriptClose(script) <_YCM:y>
  817. #elseif YSIM_IS_STUB
  818. #error y_commands called with YSIM_IS_STUB.
  819. #else
  820. public OnScriptClose(script)
  821. #endif
  822. {
  823. new
  824. mask = ~(1 << script);
  825. for (new i = 0; i != MAX_COMMANDS; ++i)
  826. {
  827. if (Command_GetPointer(i) == i && (YSI_g_sCommands[i][E_COMMANDS_MASTERS] &= mask) == 0)
  828. {
  829. for (new j = 0; j != MAX_COMMANDS; ++j)
  830. {
  831. // Remove all alternate names.
  832. if (Command_GetPointer(j) == i)
  833. {
  834. YSI_g_sCommands[j][E_COMMANDS_FUNC_POINTER] = YSI_g_sCommandIndex;
  835. YSI_g_sCommandIndex = j;
  836. YSI_g_sCommands[j][E_COMMANDS_MASTERS] = 0;
  837. //Bintree_Delete(YSI_g_sSearchTree, j, YSI_g_sCommandCount);
  838. Command_RemoveFromBintree(j);
  839. --YSI_g_sCommandCount;
  840. //Bintree_Add(YSI_g_sSearchTree, YSI_g_sCommandIndex, hash, YSI_g_sCommandIndex);
  841. }
  842. }
  843. }
  844. /*new
  845. p = i;
  846. while (YSI_g_sCommands[p][E_COMMANDS_MASTERS] == -1)
  847. {
  848. p = Command_GetPointer(p);
  849. }
  850. if (YSI_g_sCommands[p][E_COMMANDS_FUNC_POINTER] == p && (YSI_g_sCommands[p][E_COMMANDS_MASTERS] &= mask) == 0)
  851. {
  852. // Remove all alternate versions of commands - done backwards by
  853. // an alternate command checking its parent. Can also handle
  854. // alternate versions of alternate commands (note this is the
  855. // only code that can currently).
  856. YSI_g_sCommands[i][E_COMMANDS_MASTERS] = 0;
  857. YSI_g_sCommands[i][E_COMMANDS_FUNC_POINTER] = YSI_g_sCommandIndex;
  858. YSI_g_sCommandIndex = i;
  859. // Mark it as invalid in this instance.
  860. YSI_g_sCommands[i][E_COMMANDS_MASTERS] = 0;
  861. // Reduce the number of commands.
  862. --YSI_g_sCommandCount;
  863. }*/
  864. }
  865. YSI_g_sMaster23 = getproperty(8, "x@");
  866. // I can add better removal code later. Done ^
  867. CallLocalFunction("Command_OnScriptClose", "i", script);
  868. }
  869. // Don't need ALS here as we did it supporting it at the start.
  870. #undef OnScriptClose
  871. #define OnScriptClose Command_OnScriptClose
  872. forward Command_OnScriptClose(script);
  873. #endif
  874. /*----------------------------------------------------------------------------*-
  875. Function:
  876. OnPlayerConnect
  877. Params:
  878. -
  879. Return:
  880. -
  881. Notes:
  882. -
  883. -*----------------------------------------------------------------------------*/
  884. // TODO: Rewrite!
  885. //RA:Command_OnPlayerConnect(playerid)
  886. #if YSIM_NOT_CLIENT
  887. #if YSIM_CLOUD
  888. public OnPlayerConnect(playerid) <>
  889. {
  890. YSI_g_sPlayerProvider{playerid} = 0xFF;
  891. if (YSI_g_sCommandFlags & e_COMM_FLAG_OPC)
  892. {
  893. return CallLocalFunction("Command_OnPlayerConnect", "i", playerid);
  894. }
  895. return 1;
  896. }
  897. public OnPlayerConnect(playerid) <_YCM:y>
  898. #elseif YSIM_IS_STUB
  899. #error y_commands called with YSIM_IS_STUB.
  900. #else
  901. public OnPlayerConnect(playerid)
  902. #endif
  903. {
  904. //#if YSIM_NOT_CLIENT
  905. //YSI_g_sCommandDialog[playerid] = -1;
  906. YSI_g_sPlayerProvider{playerid} = 0xFF;
  907. NO_GROUPS()
  908. {
  909. new
  910. slot = Bit_Slot(playerid) + 1,
  911. Bit:mask = Bit_Mask(playerid); //Bit:(1 << (playerid & (cellbits - 1)));
  912. for (new i = 0; i != MAX_COMMANDS; ++i)
  913. {
  914. YSI_g_sCommands[i][E_COMMANDS_PLAYERS][slot] |= mask;
  915. //PA+(YSI_g_sCommands[i][E_COMMANDS_PLAYERS], mask);
  916. }
  917. }
  918. //#endif
  919. // Groups will ALWAYS be called after this function - so this can reset
  920. // player permissions however it likes with the group system then being
  921. // able to override anything set in here.
  922. if (YSI_g_sCommandFlags & e_COMM_FLAG_OPC)
  923. {
  924. return CallLocalFunction("Command_OnPlayerConnect", "i", playerid);
  925. }
  926. return 1;
  927. //ALS_CALL<PlayerConnect, i>(playerid)
  928. }
  929. #if defined _ALS_OnPlayerConnect
  930. #undef OnPlayerConnect
  931. #else
  932. #define _ALS_OnPlayerConnect
  933. #endif
  934. #define OnPlayerConnect Command_OnPlayerConnect
  935. forward Command_OnPlayerConnect(playerid);
  936. #endif
  937. /*----------------------------------------------------------------------------*-
  938. Function:
  939. Command_
  940. Params:
  941. command - Command to declare.
  942. Return:
  943. -
  944. Notes:
  945. Deprecated!
  946. -*----------------------------------------------------------------------------*/
  947. #define Command_(%1) \
  948. CMD:%1(playerid,params[],help)
  949. /*----------------------------------------------------------------------------*-
  950. Function:
  951. ycmd
  952. Params:
  953. command[] - Command to register.
  954. Return:
  955. -
  956. Notes:
  957. Deprecated!
  958. -*----------------------------------------------------------------------------*/
  959. #define ycmd(%1);
  960. /*----------------------------------------------------------------------------*-
  961. Function:
  962. Command_FindFast
  963. Params:
  964. data[] - Function name to find.
  965. value - Hash of function name.
  966. Return:
  967. Position in functions array or COMMAND_NOT_FOUND.
  968. Notes:
  969. -
  970. -*----------------------------------------------------------------------------*/
  971. static stock Command_FindFast(data[], value, provider = 0xFF)
  972. {
  973. new
  974. leaf,
  975. pointer;
  976. P:5("Command_FindFast: Searching for %s", data);
  977. while ((pointer = Bintree_FindValue(YSI_g_sSearchTree, value, leaf)) != BINTREE_NOT_FOUND)
  978. {
  979. new
  980. p = YSI_g_sCommands[pointer][E_COMMANDS_FUNC_POINTER];
  981. if (Command_HasMultipleProviders() && (p & 0xFF000000 != 0xFF000000) && (p >>> 24 != provider)) continue;
  982. // Don't do an strcmp if there are no collisions.
  983. if (!Command_HasCollisions()) return pointer;
  984. //if (!strcmp(YSI_g_sCommands[i][E_COMMANDS_FUNCTION][1], funcname) &&
  985. if (!strcmp(Command_Name(pointer), data)) return pointer;
  986. //if (!strcmp(Command_Name(pointer), data) && (Command_GetProvider(pointer) == 0xFF || Command_GetProvider(pointer) == provider)) return pointer;
  987. }
  988. P:5("Command_FindFast: Not found");
  989. return COMMAND_NOT_FOUND;
  990. }
  991. static stock Command_FindFastStrict(data[], value, provider)
  992. {
  993. new
  994. leaf,
  995. pointer;
  996. P:5("Command_FindFast: Searching for %s", data);
  997. while ((pointer = Bintree_FindValue(YSI_g_sSearchTree, value, leaf)) != BINTREE_NOT_FOUND)
  998. {
  999. if (Command_HasMultipleProviders() && (YSI_g_sCommands[pointer][E_COMMANDS_FUNC_POINTER] >>> 24 != provider)) continue;
  1000. // Don't do an strcmp if there are no collisions.
  1001. if (!Command_HasCollisions()) return pointer;
  1002. if (!strcmp(Command_Name(pointer), data)) return pointer;
  1003. }
  1004. P:5("Command_FindFast: Not found");
  1005. return COMMAND_NOT_FOUND;
  1006. }
  1007. /*----------------------------------------------------------------------------*-
  1008. Function:
  1009. Command_FindSlow
  1010. Params:
  1011. funcname[] - Function to find.
  1012. Return:
  1013. -
  1014. Notes:
  1015. Searches through the array for function linearly - used to set altnames
  1016. before the data has been sorted.
  1017. -*----------------------------------------------------------------------------*/
  1018. static stock Command_FindSlow(funcname[], provider = 0xFF)
  1019. {
  1020. for (new i = 0; i != MAX_COMMANDS; ++i)
  1021. {
  1022. new
  1023. p = YSI_g_sCommands[i][E_COMMANDS_FUNC_POINTER];
  1024. if (((p & 0x00FFFFFF == i) || (YSI_g_sCommands[i][E_COMMANDS_MASTERS] == -1)) &&
  1025. (!Command_HasMultipleProviders() || (p & 0xFF000000 == 0xFF000000) || (p >>> 24 == provider)) &&
  1026. !strcmp(Command_Name(i), funcname))
  1027. {
  1028. return i;
  1029. }
  1030. }
  1031. return COMMAND_NOT_FOUND;
  1032. }
  1033. /*----------------------------------------------------------------------------*-
  1034. Function:
  1035. Command_FindSlowStrict
  1036. Params:
  1037. funcname[] - Function to find.
  1038. Return:
  1039. -
  1040. Notes:
  1041. Searches through the array for function linearly - used to set altnames
  1042. before the data has been sorted.
  1043. -*----------------------------------------------------------------------------*/
  1044. static stock Command_FindSlowStrict(funcname[], provider)
  1045. {
  1046. for (new i = 0; i != MAX_COMMANDS; ++i)
  1047. {
  1048. new
  1049. p = YSI_g_sCommands[i][E_COMMANDS_FUNC_POINTER];
  1050. // This needs additional checks that the item is valid.
  1051. if (((p & 0x00FFFFFF == i) || (YSI_g_sCommands[i][E_COMMANDS_MASTERS] == -1)) &&
  1052. (!Command_HasMultipleProviders() || (p >>> 24 == provider)) &&
  1053. !strcmp(Command_Name(i), funcname))
  1054. {
  1055. return i;
  1056. }
  1057. }
  1058. return COMMAND_NOT_FOUND;
  1059. }
  1060. /*----------------------------------------------------------------------------*-
  1061. Function:
  1062. Command_AddHash
  1063. Params:
  1064. command[] - Command text to hash.
  1065. dest[] - Array to copy to.
  1066. idx - Point to start copying from.
  1067. Return:
  1068. hash value.
  1069. Notes:
  1070. Hashes a string and copies it to a destination at the same time.
  1071. -*----------------------------------------------------------------------------*/
  1072. static stock Command_AddHash(command[], dest[], idx)
  1073. {
  1074. // Skip the function name prefix.
  1075. new
  1076. hash = -1,
  1077. ch,
  1078. dx = 1,
  1079. end = idx + 28;
  1080. // Copy and hash at the same time.
  1081. do
  1082. {
  1083. /*ch = TOLOWER(command[idx++]);
  1084. // Always NULL terminate.
  1085. if ((dest[dx] = ch << 24) == COMMAND_END_CMP << 24)
  1086. {
  1087. // Fixes a bug with commands multiples of 4 chars long.
  1088. dest[dx] = 0;
  1089. break;
  1090. }*/
  1091. ch = TOLOWER(command[idx++]);
  1092. if (ch == COMMAND_END_CMP) break;
  1093. dest[dx] = ch << 24;
  1094. hash = hash * 33 + ch; //Command_ToUpper(ch);
  1095. ch = TOLOWER(command[idx++]);
  1096. if (ch == COMMAND_END_CMP) break;
  1097. dest[dx] |= ch << 16;
  1098. hash = hash * 33 + ch; //Command_ToUpper(ch);
  1099. ch = TOLOWER(command[idx++]);
  1100. if (ch == COMMAND_END_CMP) break;
  1101. dest[dx] |= ch << 8;
  1102. hash = hash * 33 + ch; //Command_ToUpper(ch);
  1103. ch = TOLOWER(command[idx++]);
  1104. if (ch == COMMAND_END_CMP) break;
  1105. dest[dx] |= ch << 0;
  1106. hash = hash * 33 + ch; //Command_ToUpper(ch);
  1107. ++dx;
  1108. }
  1109. while (idx < end);
  1110. return hash;
  1111. }
  1112. /*----------------------------------------------------------------------------*-
  1113. Function:
  1114. Command_FastHash
  1115. Params:
  1116. command[] - Command text to hash.
  1117. Return:
  1118. hash value.
  1119. Notes:
  1120. Just hashes the passed string.
  1121. -*----------------------------------------------------------------------------*/
  1122. static stock Command_FastHash(command[])
  1123. {
  1124. new
  1125. index = 0,
  1126. hash = -1,
  1127. ch;
  1128. while ((ch = command[index++])) hash = hash * 33 + TOLOWER(ch);
  1129. return hash;
  1130. }
  1131. /*----------------------------------------------------------------------------*-
  1132. Function:
  1133. Command_PackHash
  1134. Params:
  1135. command[] - Command text to hash.
  1136. Return:
  1137. hash value.
  1138. Notes:
  1139. Hashes packed strings.
  1140. -*----------------------------------------------------------------------------*/
  1141. static stock Command_PackHash(command[])
  1142. {
  1143. new
  1144. index = 0,
  1145. hash = -1,
  1146. ch;
  1147. while ((ch = command[index++]))
  1148. {
  1149. P:4("Commands_PackHash: ch = 0x%04x%04x", ch >>> 16, ch & 0xFFFF);
  1150. if (ch & 0xFF000000)
  1151. {
  1152. hash = hash * 33 + TOLOWER(ch >>> 24);
  1153. P:5("Command_PackHash: Hash1 = %d", hash);
  1154. }
  1155. else
  1156. {
  1157. break;
  1158. }
  1159. if (ch & 0x00FF0000)
  1160. {
  1161. hash = hash * 33 + TOLOWER(ch >> 16 & 0xFF);
  1162. P:5("Command_PackHash: Hash2 = %d", hash);
  1163. }
  1164. else
  1165. {
  1166. break;
  1167. }
  1168. if (ch & 0x0000FF00)
  1169. {
  1170. hash = hash * 33 + TOLOWER(ch >> 8 & 0xFF);
  1171. P:5("Command_PackHash: Hash3 = %d", hash);
  1172. }
  1173. else
  1174. {
  1175. break;
  1176. }
  1177. if (ch & 0x000000FF)
  1178. {
  1179. hash = hash * 33 + TOLOWER(ch & 0xFF);
  1180. P:5("Command_PackHash: Hash4 = %d", hash);
  1181. }
  1182. else
  1183. {
  1184. break;
  1185. }
  1186. }
  1187. return hash;
  1188. }
  1189. /*----------------------------------------------------------------------------*-
  1190. Function:
  1191. Command_Hash
  1192. Params:
  1193. command[] - Command text to hash.
  1194. &index - Start point and variable to store end point to.
  1195. &length - Length of the hashed word.
  1196. Return:
  1197. hash value.
  1198. Notes:
  1199. Hashes a string using space delimiters and returns information such as the
  1200. length of the string hased and the start point of the next word.
  1201. -*----------------------------------------------------------------------------*/
  1202. static stock Command_Hash(command[], &index, &length)
  1203. {
  1204. new
  1205. hash = -1,
  1206. ch;
  1207. length = index;
  1208. while ((ch = command[index++]) > ' ') hash = hash * 33 + TOLOWER(ch);
  1209. length = index - length - 1;
  1210. while (ch)
  1211. {
  1212. if (ch > ' ')
  1213. {
  1214. break;
  1215. }
  1216. ch = command[index++];
  1217. }
  1218. --index;
  1219. return hash;
  1220. }
  1221. /*----------------------------------------------------------------------------*-
  1222. Function:
  1223. Command_Find
  1224. Params:
  1225. function[] - Function name to find.
  1226. Return:
  1227. Position in functions array or COMMAND_NOT_FOUND.
  1228. Notes:
  1229. Used by API functions to avoid repeated sorting checks.
  1230. -*----------------------------------------------------------------------------*/
  1231. static stock Command_Find(function[], provider = -1)
  1232. {
  1233. if (provider == -1)
  1234. {
  1235. provider = _:Command_DefaultProvider();
  1236. // Find the ID of the command.
  1237. if (Command_IsSorted())
  1238. {
  1239. return Command_FindFast(function, Command_FastHash(function), provider);
  1240. }
  1241. else
  1242. {
  1243. return Command_FindSlow(function, provider);
  1244. }
  1245. }
  1246. else
  1247. {
  1248. provider &= 0xFF;
  1249. // Find the ID of the command.
  1250. if (Command_IsSorted())
  1251. {
  1252. return Command_FindFastStrict(function, Command_FastHash(function), provider);
  1253. }
  1254. else
  1255. {
  1256. return Command_FindSlowStrict(function, provider);
  1257. }
  1258. }
  1259. }
  1260. /*----------------------------------------------------------------------------*-
  1261. Function:
  1262. Command_GetID
  1263. Params:
  1264. function[] - Function name to find.
  1265. Return:
  1266. The ID of the passed function.
  1267. Notes:
  1268. -
  1269. native Command_GetID(function[])
  1270. -*----------------------------------------------------------------------------*/
  1271. RF@p:Command_GetID[s](function[])<function>
  1272. {
  1273. return Command_Find(function);
  1274. }
  1275. /*----------------------------------------------------------------------------*-
  1276. Function:
  1277. Command_SetPlayer
  1278. Params:
  1279. command - Command to set for.
  1280. playerid - Player to set.
  1281. bool:set - Wether or not this player can use this command.
  1282. Return:
  1283. -
  1284. Notes:
  1285. -
  1286. native bool:Command_SetPlayer(command, playerid, bool:set);
  1287. -*----------------------------------------------------------------------------*/
  1288. RF@pv:Command_SetPlayer[iii](c,p,bool:s)<c,p,s>
  1289. {
  1290. // if (c < 0 || c >= YSI_g_sCommandIndex)
  1291. if (0 <= c < MAX_COMMANDS)
  1292. {
  1293. //Bit_Set(YSI_g_sCommands[c][E_COMMANDS_PLAYERS], p, s, bits<MAX_PLAYERS>);
  1294. if (s) PA+(YSI_g_sCommands[c][E_COMMANDS_PLAYERS], p);
  1295. else PA-(YSI_g_sCommands[c][E_COMMANDS_PLAYERS], p);
  1296. // Not in range,
  1297. // return false;
  1298. }
  1299. // return s;
  1300. }
  1301. /*----------------------------------------------------------------------------*-
  1302. Function:
  1303. Command_SetPlayerNamed
  1304. Params:
  1305. funcname[] - Command to set for.
  1306. playerid - Player to set.
  1307. set - Wether or not this player can use this command.
  1308. Return:
  1309. -
  1310. Notes:
  1311. Like Command_SetPlayer but for a function name.
  1312. native bool:Command_SetPlayerNamed(funcname[], playerid, bool:set);
  1313. -*----------------------------------------------------------------------------*/
  1314. RF@pv:Command_SetPlayerNamed[sii](f[],p,bool:s)<f,p,s>
  1315. {
  1316. Command_SetPlayer(Command_Find(f), p, s);
  1317. }
  1318. /*----------------------------------------------------------------------------*-
  1319. Function:
  1320. Command_GetPlayer
  1321. Params:
  1322. command - Command to get for.
  1323. playerid - Player to get.
  1324. Return:
  1325. Wether this player can use this command.
  1326. Notes:
  1327. -
  1328. native bool:Command_GetPlayer(command, playerid);
  1329. -*----------------------------------------------------------------------------*/
  1330. RF@t:bool:Command_GetPlayer[ii](command, playerid)
  1331. {
  1332. if (0 <= command < MAX_COMMANDS)
  1333. {
  1334. return bool:Command_CheckPlayer(command, playerid);
  1335. }
  1336. // Not in range,
  1337. return false;
  1338. }
  1339. /*----------------------------------------------------------------------------*-
  1340. Function:
  1341. Command_GetPlayerNamed
  1342. Params:
  1343. funcname[] - Command to get for.
  1344. playerid - Player to get.
  1345. Return:
  1346. -
  1347. Notes:
  1348. Like Command_GetPlayer but for a function name.
  1349. native bool:Command_GetPlayerNamed(funcname[], playerid);
  1350. -*----------------------------------------------------------------------------*/
  1351. RF@pt:bool:Command_GetPlayerNamed[si](func[], playerid)<func, playerid>
  1352. {
  1353. return Command_GetPlayer(Command_Find(func), playerid);
  1354. }
  1355. /*----------------------------------------------------------------------------*-
  1356. Function:
  1357. Command_Remove
  1358. Params:
  1359. func - The slot of the command to remove.
  1360. Return:
  1361. -
  1362. Notes:
  1363. native Command_Remove(func);
  1364. -*----------------------------------------------------------------------------*/
  1365. static stock Command_RemoveFromBintree(func)
  1366. {
  1367. if (!Command_IsSorted()) return;
  1368. // This function has to find the right index in the binary tree, as that's
  1369. // not in the same order at all.
  1370. new
  1371. leaf,
  1372. hash = Command_PackHash(Command_Name(func));
  1373. // Find where in the binary tree this is referenced from.
  1374. while (Bintree_FindValue(YSI_g_sSearchTree, hash, _, leaf) != BINTREE_NOT_FOUND)
  1375. {
  1376. if (YSI_g_sSearchTree[leaf][E_BINTREE_TREE_POINTER] == func)
  1377. {
  1378. P:2("Command_RemoveFromBintree: Delete branch");
  1379. Bintree_Delete(YSI_g_sSearchTree, leaf, YSI_g_sCommandCount);
  1380. return;
  1381. }
  1382. }
  1383. }
  1384. RF:Command_Remove[i](func)
  1385. {
  1386. P:2("Command_Remove called (%d)", func);
  1387. if (0 <= func < MAX_COMMANDS)
  1388. {
  1389. if (Command_GetPointer(func) == func)
  1390. {
  1391. for (new i = 0; i != MAX_COMMANDS; ++i)
  1392. {
  1393. // Remove all alternate names.
  1394. if (Command_GetPointer(i) == func)
  1395. {
  1396. // Add this to the list of unused functions.
  1397. YSI_g_sCommands[i][E_COMMANDS_FUNC_POINTER] = YSI_g_sCommandIndex;
  1398. YSI_g_sCommandIndex = i;
  1399. // Mark it as invalid in this instance.
  1400. YSI_g_sCommands[i][E_COMMANDS_MASTERS] = 0;
  1401. // Reduce the number of commands.
  1402. //Bintree_Delete(YSI_g_sSearchTree, i, YSI_g_sCommandCount);
  1403. Command_RemoveFromBintree(i);
  1404. --YSI_g_sCommandCount;
  1405. }
  1406. }
  1407. }
  1408. else if (YSI_g_sCommands[func][E_COMMANDS_MASTERS] == -1)
  1409. {
  1410. // Remove a single alternate name.
  1411. YSI_g_sCommands[func][E_COMMANDS_FUNC_POINTER] = YSI_g_sCommandIndex;
  1412. YSI_g_sCommandIndex = func;
  1413. YSI_g_sCommands[func][E_COMMANDS_MASTERS] = 0;
  1414. //Bintree_Delete(YSI_g_sSearchTree, func, YSI_g_sCommandCount);
  1415. Command_RemoveFromBintree(func);
  1416. --YSI_g_sCommandCount;
  1417. }
  1418. return 1;
  1419. }
  1420. return 0;
  1421. }
  1422. RF@p:Command_RemoveNamed[s](func[])<func>
  1423. {
  1424. P:2("Command_RemoveNamed called (%s)", func);
  1425. return Command_Remove(Command_Find(func));
  1426. }
  1427. /*----------------------------------------------------------------------------*-
  1428. Function:
  1429. Command_Add
  1430. Params:
  1431. funcname[] - The function to add to the array.
  1432. script - The script ID with the function.
  1433. Return:
  1434. -
  1435. Notes:
  1436. If the list of commands have already been sorted into the binary tree the
  1437. new commands will be appended, otherwise they will just be added to the
  1438. array.
  1439. native Command_Add(funcname[], script);
  1440. -*----------------------------------------------------------------------------*/
  1441. RF@pv:Command_Add[si](f[],s)<f,s>
  1442. {
  1443. P:2("Command_Add called");
  1444. if (YSI_g_sCommandCount < MAX_COMMANDS && YSI_g_sCommandIndex != -1)
  1445. {
  1446. new
  1447. hash = Command_AddHash(f, YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION], 4),
  1448. provider = _:Command_DefaultProvider();
  1449. if (Command_IsSorted())
  1450. {
  1451. new
  1452. idx = Command_FindFastStrict(f[4], hash, provider);
  1453. if (idx != COMMAND_NOT_FOUND)
  1454. {
  1455. YSI_g_sCommands[idx][E_COMMANDS_MASTERS] |= 1 << s;
  1456. return;
  1457. }
  1458. if (!Command_HasCollisions())
  1459. {
  1460. // Check for an existing command with this hash.
  1461. if (Bintree_FindValue(YSI_g_sSearchTree, hash) != BINTREE_NOT_FOUND)
  1462. {
  1463. Command_SetCollisions();
  1464. }
  1465. }
  1466. // Command doesn't exist already - good!
  1467. Bintree_Add(YSI_g_sSearchTree, YSI_g_sCommandIndex, hash, YSI_g_sCommandIndex);
  1468. }
  1469. else
  1470. {
  1471. new
  1472. idx = Command_FindSlowStrict(f[4], provider);
  1473. if (idx != COMMAND_NOT_FOUND)
  1474. {
  1475. YSI_g_sCommands[idx][E_COMMANDS_MASTERS] |= 1 << s;
  1476. return;
  1477. }
  1478. }
  1479. YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][0] = COMMAND_FUNCTION_PREFIX;
  1480. //Bit_SetAll(YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_PLAYERS], true, bits<MAX_PLAYERS>);
  1481. //Command_InitialiseFromGroups(YSI_g_sCommandIndex);
  1482. NO_GROUPS(YSI_g_sCommandIndex)
  1483. {
  1484. PA_Init(YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_PLAYERS], true);
  1485. }
  1486. // Swap these.
  1487. YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_MASTERS] = 1 << s;
  1488. hash = YSI_g_sCommandIndex;
  1489. // Set this command as usable in any script.
  1490. YSI_g_sCommandIndex = YSI_g_sCommands[hash][E_COMMANDS_FUNC_POINTER];
  1491. YSI_g_sCommands[hash][E_COMMANDS_FUNC_POINTER] = hash | (provider << 24);
  1492. // Now some complex debug rubbish.
  1493. P:2("Command_Add: Command added in %d", YSI_g_sCommandIndex);
  1494. P:4("Command_Add: %08x%08x%08x%08x", YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][0], YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][1], YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][2], YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][3]);
  1495. C:4(new str[32];strpack(str, f);printf("Command_Add: %08x%08x%08x%08x", str[0], str[1], str[2], str[3]););
  1496. ++YSI_g_sCommandCount;
  1497. }
  1498. /*else
  1499. {
  1500. // Not all hope is lost - check if this command name already exists.
  1501. if (Command_IsSorted())
  1502. {
  1503. new
  1504. pos = Command_FindFast(funcname[4], Command_FastHash(funcname[4]));
  1505. if (pos != COMMAND_NOT_FOUND)
  1506. {
  1507. // Found it already in the array.
  1508. return pos;
  1509. }
  1510. }
  1511. else
  1512. {
  1513. new
  1514. pos = Command_FindSlow(funcname[4]);
  1515. if (pos != COMMAND_NOT_FOUND)
  1516. {
  1517. // Command already exists.
  1518. return pos;
  1519. }
  1520. }
  1521. }
  1522. return COMMAND_NOT_FOUND;*/
  1523. }
  1524. /*----------------------------------------------------------------------------*-
  1525. Function:
  1526. Command_AddAlt
  1527. Params:
  1528. funcidx - The function this is an alternate to.
  1529. altname[] - The new name.
  1530. Return:
  1531. -
  1532. Notes:
  1533. If the list of commands have already been sorted into the binary tree the
  1534. new commands will be appended, otherwise they will just be added to the
  1535. array.
  1536. native Command_AddAlt(funcidx, altname[]);
  1537. -*----------------------------------------------------------------------------*/
  1538. RF@p:Command_AddAlt[is](oidx, altname[])<oidx, altname>
  1539. {
  1540. if (!Command_IsValid(oidx))
  1541. {
  1542. return COMMAND_NOT_FOUND;
  1543. }
  1544. new
  1545. provider = _:Command_DefaultProvider();
  1546. if (YSI_g_sCommandCount < MAX_COMMANDS && YSI_g_sCommandIndex != -1)
  1547. {
  1548. new
  1549. hash = Command_AddHash(altname, YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION], 0);
  1550. if (Command_IsSorted())
  1551. {
  1552. // Find the function this mirrors.
  1553. //oidx = Command_FindFast(function, Command_FastHash(function));
  1554. new
  1555. pos = Command_FindFastStrict(altname, hash, provider);
  1556. if (pos != COMMAND_NOT_FOUND)
  1557. {
  1558. if (Command_GetPointer(pos) != oidx)
  1559. {
  1560. // Same altname, different function.
  1561. return COMMAND_NOT_FOUND;
  1562. }
  1563. return pos;
  1564. }
  1565. // Command doesn't exist already - good!
  1566. Bintree_Add(YSI_g_sSearchTree, YSI_g_sCommandIndex, hash, YSI_g_sCommandIndex);
  1567. }
  1568. else
  1569. {
  1570. new
  1571. pos = Command_FindSlowStrict(altname, provider);
  1572. if (pos != COMMAND_NOT_FOUND)
  1573. {
  1574. if (Command_GetPointer(pos) != oidx)
  1575. {
  1576. // Same altname, different function.
  1577. return COMMAND_NOT_FOUND;
  1578. }
  1579. // Command already exists.
  1580. return pos;
  1581. }
  1582. }
  1583. YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_FUNCTION][0] = COMMAND_FUNCTION_PREFIX;
  1584. //Bit_SetAll(YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_PLAYERS], true, bits<MAX_PLAYERS>);
  1585. //Command_InitialiseFromGroups(YSI_g_sCommandIndex);
  1586. NO_GROUPS(YSI_g_sCommandIndex)
  1587. {
  1588. PA_Init(YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_PLAYERS], true);
  1589. }
  1590. ++YSI_g_sCommandCount;
  1591. // This doesn't have real masters.
  1592. YSI_g_sCommands[YSI_g_sCommandIndex][E_COMMANDS_MASTERS] = -1;
  1593. hash = YSI_g_sCommandIndex;
  1594. YSI_g_sCommandIndex = YSI_g_sCommands[hash][E_COMMANDS_FUNC_POINTER];
  1595. YSI_g_sCommands[hash][E_COMMANDS_FUNC_POINTER] = oidx | (provider << 24);
  1596. return hash;
  1597. }
  1598. else
  1599. {
  1600. // Not all hope is lost - check if this command name already exists.
  1601. new
  1602. pos;
  1603. if (Command_IsSorted())
  1604. {
  1605. pos = Command_FindFastStrict(altname, Command_FastHash(altname), provider);
  1606. }
  1607. else
  1608. {
  1609. pos = Command_FindSlowStrict(altname, provider);
  1610. }
  1611. if (pos != COMMAND_NOT_FOUND)
  1612. {
  1613. // Found it already in the array. Check if the element it points to
  1614. // has the correct name so we know this is the correct pair, not
  1615. // just the correct single element. I.e. check that this is the
  1616. // correct original/altname combo, not the right altname on a
  1617. // different original name.
  1618. if (oidx == Command_GetPointer(pos))
  1619. {
  1620. return pos;
  1621. }
  1622. }
  1623. }
  1624. return COMMAND_NOT_FOUND;
  1625. }
  1626. /*----------------------------------------------------------------------------*-
  1627. Function:
  1628. Command_AddAltNamed
  1629. Params:
  1630. function[] - The function this is an alternate to.
  1631. altname[] - The new name.
  1632. Return:
  1633. -
  1634. Notes:
  1635. Add an alternate command for an existing command.
  1636. native Command_AddAltNamed(function[], altname[]);
  1637. -*----------------------------------------------------------------------------*/
  1638. RF@p:Command_AddAltNamed[ss](function[], altname[])<function, altname>
  1639. {
  1640. return Command_AddAlt(Command_Find(function), altname);
  1641. }
  1642. /*----------------------------------------------------------------------------*-
  1643. Function:
  1644. Command_Debug
  1645. Params:
  1646. -
  1647. Return:
  1648. -
  1649. Notes:
  1650. Print some random information about commands if _DEBUG is set.
  1651. -*----------------------------------------------------------------------------*/
  1652. stock Command_Debug()
  1653. {
  1654. #if _DEBUG > 0
  1655. printf("Command_Debug: Start");
  1656. for (new i = 0; i != MAX_COMMANDS; ++i)
  1657. {
  1658. if (Command_IsValid(i))
  1659. {
  1660. printf("Command_Debug: Loop start %d", i);
  1661. new buffer[MAX_COMMAND_LENGTH];
  1662. strunpack(buffer, Command_Name(i));
  1663. printf("%08x%08x%08x", YSI_g_sCommands[i][E_COMMANDS_FUNCTION][0], YSI_g_sCommands[i][E_COMMANDS_FUNCTION][1], YSI_g_sCommands[i][E_COMMANDS_FUNCTION][2]);
  1664. new pointer = Command_GetPointer(i);
  1665. printf("Command %d:", i);
  1666. printf("\t%s", buffer);
  1667. printf("\t%d", pointer);
  1668. printf("\t%d %d %d", YSI_g_sSearchTree[i][E_BINTREE_TREE_LEFT], YSI_g_sSearchTree[i][E_BINTREE_TREE_RIGHT], YSI_g_sSearchTree[i][E_BINTREE_TREE_VALUE]);
  1669. CallLocalFunction(Command_GetFunction(Command_GetPointer(i)), "isi", 0, "hi", 0);
  1670. printf("Command_Debug: Loop end");
  1671. }
  1672. }
  1673. printf("Command_Debug: End");
  1674. #endif
  1675. }
  1676. /*----------------------------------------------------------------------------*-
  1677. Function:
  1678. OnPlayerCommandText
  1679. Params:
  1680. playerid - Player who entered the command.
  1681. cmdtext[] - Text entered.
  1682. Return:
  1683. true - success or hidden fail, false - fail.
  1684. Notes:
  1685. Calls the Command_Process function if this is not a client.
  1686. -*----------------------------------------------------------------------------*/
  1687. #if YSIM_NOT_CLIENT
  1688. #if YSIM_CLOUD
  1689. public OnPlayerCommandText(playerid, cmdtext[]) <>
  1690. {
  1691. if (YSI_g_sCommandFlags & e_COMM_FLAG_OPCT)
  1692. {
  1693. return CallLocalFunction("Command_OnPlayerCommandText", "is", playerid, cmdtext);
  1694. }
  1695. return 0;
  1696. }
  1697. public OnPlayerCommandText(playerid, cmdtext[]) <_YCM:y>
  1698. #elseif YSIM_IS_STUB
  1699. #error y_commands called with YSIM_IS_STUB.
  1700. #else
  1701. public OnPlayerCommandText(playerid, cmdtext[])
  1702. #endif
  1703. {
  1704. if (Command_Process(playerid, cmdtext, 0))
  1705. {
  1706. return 1;
  1707. }
  1708. if (YSI_g_sCommandFlags & e_COMM_FLAG_OPCT)
  1709. {
  1710. return CallLocalFunction("Command_OnPlayerCommandText", "is", playerid, cmdtext);
  1711. }
  1712. return 0;
  1713. }
  1714. #if defined _ALS_OnPlayerCommandText
  1715. #undef OnPlayerCommandText
  1716. #else
  1717. #define _ALS_OnPlayerCommandText
  1718. #endif
  1719. #define OnPlayerCommandText Command_OnPlayerCommandText
  1720. forward Command_OnPlayerCommandText(playerid, cmdtext[]);
  1721. #endif
  1722. /*----------------------------------------------------------------------------*-
  1723. Function:
  1724. Command_ReProcess
  1725. Params:
  1726. playerid - Player who entered the command.
  1727. cmdtext[] - Text entered.
  1728. help - Called from the help commmand or OnPlayerCommandText.
  1729. Return:
  1730. true - success or hidden fail, false - fail.
  1731. Notes:
  1732. -
  1733. -*----------------------------------------------------------------------------*/
  1734. RF@p:Command_ReProcess[isi](p,c[],h)<p,c,h>
  1735. {
  1736. return Command_Process(p,c,h);
  1737. }
  1738. /*----------------------------------------------------------------------------*-
  1739. Function:
  1740. Command_Process
  1741. Params:
  1742. playerid - Player who entered the command.
  1743. cmdtext[] - Text entered.
  1744. help - Called from the help commmand or OnPlayerCommandText.
  1745. Return:
  1746. true - success or hidden fail, false - fail.
  1747. Notes:
  1748. -
  1749. -*----------------------------------------------------------------------------*/
  1750. #define Command_CallR(%1,%2) \
  1751. CallRemoteFunction(Command_GetFunction((%1)), "isii", playerid, %2, help, master)
  1752. #define Command_CallL(%1,%2) \
  1753. CallLocalFunction(Command_GetFunction((%1)), "isi", playerid, %2, help)
  1754. static stock Command_Process(playerid, cmdtext[], help)
  1755. {
  1756. // Support for very old problems!
  1757. // TODO: Add back.
  1758. P:2("Command_Process called: %d %s", playerid, cmdtext);
  1759. #if !_DEBUG && !defined _YSI_SPECIAL_DEBUG
  1760. // For testing purposes.
  1761. if (!IsPlayerConnected(playerid))
  1762. {
  1763. return Command_DisconnectReturn();
  1764. }
  1765. #endif
  1766. P:4("Command_Process: Connected");
  1767. new
  1768. idx,
  1769. prelen = help ? 0 : 1,
  1770. index = prelen;
  1771. /*// Shortcuts.
  1772. if (cmdtext[2] <= ' ')
  1773. {
  1774. // Get a player's shortcut information for this letter.
  1775. }
  1776. else*/
  1777. {
  1778. // No more faffing about with random alternate code - it's all done in
  1779. // one nice function instead of having to handle both separately.
  1780. new
  1781. length,
  1782. hash = Command_Hash(cmdtext, index, length);
  1783. P:3("Command_Process: Hash = %d, Length = %d", hash, length);
  1784. // NOTE: No prefix support here.
  1785. cmdtext[length + prelen] = '\0';
  1786. P:3("Command_Process: Provider: %d", YSI_g_sPlayerProvider{playerid});
  1787. idx = Command_FindFast(cmdtext[prelen], hash, YSI_g_sPlayerProvider{playerid});
  1788. // TODO: Replace!
  1789. //idx = Command_FindSlow(cmdtext[prelen]);//, hash);
  1790. }
  1791. P:3("Command_Process: Index = %d", idx);
  1792. if (idx != COMMAND_NOT_FOUND)
  1793. {
  1794. // Get the master data for the underlying command, not the possibly
  1795. // changed name.
  1796. new
  1797. pointer = Command_GetPointer(idx),
  1798. master = YSI_g_sCommands[pointer][E_COMMANDS_MASTERS];
  1799. if (!master)
  1800. {
  1801. // No scripts can serve the code.
  1802. return Command_UnknownReturn();
  1803. }
  1804. P:4("Command_Process: Found %d", idx);
  1805. // Found a command with this name - check the permissions.
  1806. //if (Bit_Get(YSI_g_sCommands[idx][E_COMMANDS_PLAYERS], playerid))
  1807. if (Command_CheckPlayer(idx, playerid))
  1808. {
  1809. P:4("Command_Process: Allowed");
  1810. // Allowed to use the command, get the real function. Note that
  1811. // this may well be the same as "idx", but we loose no time.
  1812. #if YSIM_HAS_MASTER
  1813. P:4("Command_Process: %08x%08x%08x%08x", YSI_g_sCommands[idx][E_COMMANDS_FUNCTION][0], YSI_g_sCommands[idx][E_COMMANDS_FUNCTION][1], YSI_g_sCommands[idx][E_COMMANDS_FUNCTION][2], YSI_g_sCommands[idx][E_COMMANDS_FUNCTION][3]);
  1814. if (master & 1 << YSI_g_sMaster23)
  1815. {
  1816. master = YSI_g_sMaster23;
  1817. }
  1818. else
  1819. {
  1820. // Find the lowest set bit.
  1821. static const
  1822. scDeBruijn[] =
  1823. {
  1824. 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
  1825. 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
  1826. };
  1827. // http://supertech.csail.mit.edu/papers/debruijn.pdf
  1828. master = scDeBruijn[((master & -master) * 0x077CB531) >>> 27];
  1829. }
  1830. P:3("Command_Process: master = %d", master);
  1831. if (cmdtext[index])
  1832. {
  1833. // Call it!
  1834. Command_CallR(pointer, cmdtext[index]);
  1835. }
  1836. else
  1837. {
  1838. Command_CallR(pointer, NULL);
  1839. }
  1840. // Get the real return.
  1841. P:1("Command_Process: return: %d", getproperty(8, YSIM_RETURN));
  1842. return getproperty(8, YSIM_RETURN);
  1843. #else
  1844. if (cmdtext[index])
  1845. {
  1846. // Call it!
  1847. return Command_CallL(pointer, cmdtext[index]);
  1848. }
  1849. else
  1850. {
  1851. return Command_CallL(pointer, NULL);
  1852. }
  1853. #endif
  1854. }
  1855. else
  1856. {
  1857. return Command_DeniedReturn();
  1858. }
  1859. }
  1860. P:5("Command_Process: Not found");
  1861. return Command_UnknownReturn();
  1862. }
  1863. /*----------------------------------------------------------------------------*-
  1864. Function:
  1865. Command_GetName
  1866. Params:
  1867. funcid - Command to get the name of.
  1868. Return:
  1869. -
  1870. Notes:
  1871. native Command_GetName(funcid);
  1872. -*----------------------------------------------------------------------------*/
  1873. RS:Command_GetName[i](funcid)
  1874. {
  1875. new
  1876. buffer[YSI_MAX_STRING] = "";
  1877. if (Command_IsValid(funcid))
  1878. {
  1879. strunpack(buffer, Command_Name(funcid));
  1880. }
  1881. return buffer;
  1882. }
  1883. /*----------------------------------------------------------------------------*-
  1884. Function:
  1885. Command_GetDisplay
  1886. Params:
  1887. f - Command to get the real name of.
  1888. p - Player to get the name for.
  1889. Return:
  1890. The name of a command for a single player.
  1891. Notes:
  1892. -
  1893. native Command_GetDisplay(funcid, playerid);
  1894. -*----------------------------------------------------------------------------*/
  1895. RS:Command_GetDisplay[ii](funcid, playerid)
  1896. {
  1897. new
  1898. buffer[YSI_MAX_STRING] = "";
  1899. if (Command_IsValid(funcid))
  1900. {
  1901. // Don't recalculate this every loop.
  1902. new
  1903. slot = Bit_Slot(playerid) + 1,
  1904. Bit:mask = Bit_Mask(playerid);
  1905. // Check if they can use the original version.
  1906. if (YSI_g_sCommands[funcid][E_COMMANDS_PLAYERS][slot] & mask)
  1907. {
  1908. //setproperty(8, "", YSIM_STRING, Command_Name(f));
  1909. strunpack(buffer, Command_Name(funcid));
  1910. return buffer;
  1911. //return 1;
  1912. }
  1913. // Search for a command pointing to that command which the player can use.
  1914. for (new i = 0; i != MAX_COMMANDS; ++i)
  1915. {
  1916. if (Command_GetPointer(i) == funcid && (YSI_g_sCommands[i][E_COMMANDS_PLAYERS][slot] & mask))
  1917. {
  1918. //setproperty(8, "", YSIM_STRING, Command_Name(i));
  1919. strunpack(buffer, Command_Name(i));
  1920. return buffer;
  1921. }
  1922. }
  1923. }
  1924. return buffer;
  1925. }
  1926. /*----------------------------------------------------------------------------*-
  1927. Function:
  1928. Command_GetDisplayNamed
  1929. Params:
  1930. f[] - Command to get the real name of.
  1931. p - Player to get the name for.
  1932. Return:
  1933. The name of a named function for one player.
  1934. Notes:
  1935. Remote function call for Command_GetDisplayNameNamed - avoids needing to
  1936. expose users to the master system's odd way of returning strings. This is
  1937. the only part I've not yet fixed up to be nice and hidden.
  1938. native Command_GetDisplayNamed(funcid[], playerid);
  1939. -*----------------------------------------------------------------------------*/
  1940. RS@p:Command_GetDisplayNamed[si](func[], playerid)<func, playerid>
  1941. {
  1942. P:1("Command_GetDisplayNamed called %d", _@);
  1943. new
  1944. pointer = Command_Find(func),
  1945. buffer[YSI_MAX_STRING] = "";
  1946. if (pointer != COMMAND_NOT_FOUND)
  1947. {
  1948. // Don't recalculate this every loop.
  1949. new
  1950. slot = Bit_Slot(playerid) + 1, //playerid >>> CELLSHIFT) + 1,
  1951. Bit:mask = Bit_Mask(playerid); //Bit:(1 << (playerid & (cellbits - 1)));
  1952. // Check if they can use the original version.
  1953. if (YSI_g_sCommands[pointer][E_COMMANDS_PLAYERS][slot] & mask)
  1954. {
  1955. //setproperty(8, "", YSIM_STRING, Command_Name(pointer));
  1956. strunpack(buffer, Command_Name(pointer));
  1957. return buffer;
  1958. }
  1959. // Search for a command pointing to that command which the player can use.
  1960. for (new i = 0; i != MAX_COMMANDS; ++i)
  1961. {
  1962. if (Command_GetPointer(i) == pointer && (YSI_g_sCommands[i][E_COMMANDS_PLAYERS][slot] & mask))
  1963. {
  1964. //setproperty(8, "", YSIM_STRING, Command_Name(i));
  1965. strunpack(buffer, Command_Name(i));
  1966. return buffer;
  1967. }
  1968. }
  1969. }
  1970. return buffer;
  1971. }
  1972. /*----------------------------------------------------------------------------*-
  1973. Function:
  1974. Command_GetPlayerCommandCount
  1975. Params:
  1976. playerid - Player to count for.
  1977. Return:
  1978. -
  1979. Notes:
  1980. Gets the number of comamnds this player can use.
  1981. native Command_GetPlayerCommandCount(playerid);
  1982. -*----------------------------------------------------------------------------*/
  1983. RF:Command_GetPlayerCommandCount[i](playerid)
  1984. {
  1985. new
  1986. slot = Bit_Slot(playerid) + 1,
  1987. Bit:mask = Bit_Mask(playerid),
  1988. count = 0;
  1989. for (new i = 0; i != MAX_COMMANDS; ++i)
  1990. {
  1991. if (_Command_IsValid(i) && YSI_g_sCommands[i][E_COMMANDS_PLAYERS][slot] & mask)
  1992. {
  1993. ++count;
  1994. }
  1995. }
  1996. return count;
  1997. }
  1998. /*----------------------------------------------------------------------------*-
  1999. Function:
  2000. Command_GetNext
  2001. Params:
  2002. index - Index of the next command for this player.
  2003. playerid - Player to get the name for.
  2004. Return:
  2005. The name of a command for a single player.
  2006. Notes:
  2007. -
  2008. native Command_GetNext(index, playerid);
  2009. -*----------------------------------------------------------------------------*/
  2010. RS:Command_GetNext[ii](index, playerid)
  2011. {
  2012. new
  2013. buffer[YSI_MAX_STRING] = "";
  2014. if (0 <= index < MAX_COMMANDS)
  2015. {
  2016. // Don't recalculate this every loop.
  2017. new
  2018. slot = Bit_Slot(playerid) + 1,
  2019. Bit:mask = Bit_Mask(playerid);
  2020. for (new i = 0; i != MAX_COMMANDS; ++i)
  2021. {
  2022. if (_Command_IsValid(i) && YSI_g_sCommands[i][E_COMMANDS_PLAYERS][slot] & mask)
  2023. {
  2024. // Skip already displayed ones.
  2025. if (index)
  2026. {
  2027. --index;
  2028. }
  2029. else
  2030. {
  2031. strunpack(buffer, Command_Name(i));
  2032. return buffer;
  2033. }
  2034. }
  2035. }
  2036. }
  2037. return buffer;
  2038. }
  2039. //#tryinclude <YSI\y_groups>
  2040. //#undef _YCM
  2041. #if defined _YSIM_MANUAL_SET
  2042. // This is to allow callback chaining. When the user includes y_groups and
  2043. // other libraries, the function names will be reset to their custom ones
  2044. // after every inclusion, however if you then include another YSI library
  2045. // you need to revert to the previous library names to get the chaining to
  2046. // work.
  2047. #define YSI_GROUPS_LAST 25
  2048. #include <YSI\internal\y_grouprevert>
  2049. #else
  2050. // Define a numbered master to use for user commands, without them needing
  2051. // to know about the master system. This should default to cloud mode,
  2052. // unless global settings have been applied.
  2053. #define MASTER 23
  2054. #include <YSI\y_master>
  2055. //#define _YSIM_FAKE_MANUAL_SET
  2056. #endif