y_utils.inc 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  1. #if defined _INC_y_utils
  2. #endinput
  3. #endif
  4. #define _INC_y_utils
  5. /**
  6. * <library name="y_utils">
  7. * <section>
  8. * Description
  9. * </section>
  10. * Misc functions used throughout.
  11. * <section>
  12. * Version
  13. * </section>
  14. * 0.1.3
  15. * <section>
  16. * Functions
  17. * </section>
  18. * <subsection>Stock</subsection>
  19. * <ul>
  20. * <symbol name="StrToLower">Convert a whole string to lower-case.</symbol>
  21. * <symbol name="StrToUpper">Convert a whole string to upper-case.</symbol>
  22. * <symbol name="Random">Generate a random number, optionally takes lower and upper bounds.</symbol>
  23. * <symbol name="RandomFloat">Same as <symbolref name="Random" />, but for floats.</symbol>
  24. * <symbol name="StripNL">Strips the newline characters from the end of a string.</symbol>
  25. * <symbol name="StripL">Remove whitespace from the start of a string.</symbol>
  26. * <symbol name="Strip">Remove whitespace from both ends of a string.</symbol>
  27. * <symbol name="endofline">Check if the given position is the end of a string (ignoring whitespace).</symbol>
  28. * <symbol name="chrfind">Return the first position (after <symbolref name="start" />) of the given character.</symbol>
  29. * <symbol name="chrfindp">Like <symbolref name="chrfind" />, but without the upper-bounds check.</symbol>
  30. * <symbol name="bernstein">Generate the Bernstein hash of the given string.</symbol>
  31. * <symbol name="ishex">Is the given string hexadecimal?</symbol>
  32. * <symbol name="unpack">Version of <symbolref name="strunpack" /> that returns the result.</symbol>
  33. * <symbol name="returnstringarg">Get the string passed as a variable argument from the given index.</symbol>
  34. * <symbol name="va_return">Like <symbolref name="sprintf" />, formats a string and returns the result.</symbol>
  35. * <symbol name="isnumeric">Is the given string a number?</symbol>
  36. * <symbol name="hexstr">Return the value of the given hexadecimal string.</symbol>
  37. * <symbol name="boolstr">Return the value of the given boolean string.</symbol>
  38. * <symbol name="binstr">Return the value of the given binary string.</symbol>
  39. * <symbol name="rawMemcpy">Copy memory between two address, instead of two arrays.</symbol>
  40. * <symbol name="memset">Set all of an array to a value.</symbol>
  41. * <symbol name="rawMemset">Set all of a given memory region to a value.</symbol>
  42. * <symbol name="ReturnPlayerName">Return a player's name.</symbol>
  43. * <symbol name="ftouch">Ensures that a file exists, but nothing more.</symbol>
  44. * <symbol name="InterpolateColour">Get the colour (in 3D RGB space) between two other colours.</symbol>
  45. * <symbol name="SkipWhitespace">Return the first position in a string of a non-whitespace character.</symbol>
  46. * <symbol name="Trim">Get the first and last positions of non-whitespace characters in the string. Like <symbolref name="Strip" />, but doesn't modify the string.</symbol>
  47. * <symbol name="Sum">Get the total (sum) of an array.</symbol>
  48. * <symbol name="Mean">Get the mathematical mean of an array.</symbol>
  49. * <symbol name="Mode">Get the mathematical mode of an array.</symbol>
  50. * <symbol name="Median">Get the mathematical median of an array.</symbol>
  51. * <symbol name="Range">Get the mathematical range of an array.</symbol>
  52. * </ul>
  53. * <subsection>Inline</subsection>
  54. * <ul>
  55. * <symbol name="UCMP">Unsigned compare.</symbol>
  56. * <symbol name="VALID_PLAYERID">Check if a player ID is valid (in range).</symbol>
  57. * <symbol name="IS_IN_RANGE">Check if a number is in range.</symbol>
  58. * <symbol name="NOT_IN_RANGE">Check if a number is outside a range.</symbol>
  59. * <symbol name="ceildiv">Divide two numbers and round up.</symbol>
  60. * <symbol name="floordiv">Divide two numbers and round down.</symbol>
  61. * <symbol name="isnull">Checks if a string is NULL (<c>\1\0</c> or <c>\0</c>).</symbol>
  62. * <symbol name="isodd">Checks if a number is odd.</symbol>
  63. * <symbol name="iseven">Checks if a number is even.</symbol>
  64. * <symbol name="strcpy">Copy one string to another.</symbol>
  65. * <symbol name="GetIP">Return the encoded (32-bit) version of a player's IP.</symbol>
  66. * <synonym name="getstring" for="returnstringarg"> (there are a lot)</synonym>
  67. * <synonym name="GetString" for="returnstringarg"> (there are a lot)</synonym>
  68. * <synonym name="getstringarg" for="returnstringarg"> (there are a lot)</synonym>
  69. * <synonym name="GetStringArg" for="returnstringarg"> (there are a lot)</synonym>
  70. * <synonym name="ReturnStringArg" for="returnstringarg"> (there are a lot)</synonym>
  71. * <synonym name="InterpolateColor" for="InterpolateColour" />
  72. * <synonym name="StripR" for="StripNL" />
  73. * </ul>
  74. * <section>
  75. * Variables
  76. * </section>
  77. * <subsection>Global</subsection>
  78. * <ul>
  79. * <symbol name="TRUE">True hack for infinate loops.</symbol>
  80. * <symbol name="FALSE">False hack for one-time loops.</symbol>
  81. * <symbol name="NULL">1 long string for passing via Call(Remote|Local)Function.</symbol>
  82. * </ul>
  83. * </library>
  84. *//** *//*
  85. Legal:
  86. Version: MPL 1.1
  87. The contents of this file are subject to the Mozilla Public License Version
  88. 1.1 (the "License"); you may not use this file except in compliance with
  89. the License. You may obtain a copy of the License at
  90. http://www.mozilla.org/MPL/
  91. Software distributed under the License is distributed on an "AS IS" basis,
  92. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  93. for the specific language governing rights and limitations under the
  94. License.
  95. The Original Code is the YSI framework.
  96. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  97. Portions created by the Initial Developer are Copyright (C) 2011
  98. the Initial Developer. All Rights Reserved.
  99. Contributors:
  100. Y_Less
  101. koolk
  102. JoeBullet/Google63
  103. g_aSlice/Slice
  104. Misiur
  105. samphunter
  106. tianmeta
  107. maddinat0r
  108. spacemud
  109. Crayder
  110. Dayvison
  111. Ahmad45123
  112. Zeex
  113. irinel1996
  114. Yiin-
  115. Chaprnks
  116. Konstantinos
  117. Masterchen09
  118. Southclaws
  119. PatchwerkQWER
  120. m0k1
  121. paulommu
  122. udan111
  123. Thanks:
  124. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  125. ZeeX - Very productive conversations.
  126. koolk - IsPlayerinAreaEx code.
  127. TheAlpha - Danish translation.
  128. breadfish - German translation.
  129. Fireburn - Dutch translation.
  130. yom - French translation.
  131. 50p - Polish translation.
  132. Zamaroht - Spanish translation.
  133. Los - Portuguese translation.
  134. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  135. me to strive to better.
  136. Pixels^ - Running XScripters where the idea was born.
  137. Matite - Pestering me to release it and using it.
  138. Very special thanks to:
  139. Thiadmer - PAWN, whose limits continue to amaze me!
  140. Kye/Kalcor - SA:MP.
  141. SA:MP Team past, present and future - SA:MP.
  142. Optional plugins:
  143. Gamer_Z - GPS.
  144. Incognito - Streamer.
  145. Me - sscanf2, fixes2, Whirlpool.
  146. */
  147. #include "..\YSI_Internal\y_compilerdata"
  148. #include "..\YSI_Internal\y_version"
  149. #include "..\YSI_Core\y_debug"
  150. #include "..\YSI_Storage\y_amx"
  151. //#tryinclude <sscanf>
  152. #include "..\YSI_Internal\y_thirdpartyinclude"
  153. #include "..\YSI_Internal\y_funcinc"
  154. // Add new tags to the START of this list.
  155. #include "..\YSI_Internal\y_globaltags"
  156. // VERY VERY VERY IMPORTANT!!! y_inline uses "130" instead of "YSI_MAX_STRING"
  157. // for two lines (one is "520" for "130 * 4").
  158. #define YSI_MAX_STRING (130)
  159. #define FUNCTION_LENGTH (32)
  160. // Better handling of operator precedences and floating point numbers. This
  161. // will now work for ALL regular numbers (including -0.5 which broke the old
  162. // version). I don't know of any complex expressions that break it with
  163. // operator precedences, but I'm not ruling it out. The brackets do try and
  164. // account for that possibility, but I just don't know.
  165. #define NO_VALUE(%0) ((2*%0-1)==2*(%0-1))
  166. #if !defined TRUE
  167. new stock
  168. bool:TRUE = true;
  169. #endif
  170. #if !defined FALSE
  171. new stock
  172. bool:FALSE = false;
  173. #endif
  174. #if !defined NULL
  175. new stock
  176. NULL[2] = "\1";
  177. #endif
  178. #if !defined cellbytes
  179. #define cellbytes (cellbits / 8)
  180. #endif
  181. #define UNSIGNED(%0) ((%0) - cellmin)
  182. // Define "volatile" as nothing.
  183. #if !defined volatile
  184. #define volatile
  185. #endif
  186. #define YSIM_MASTER #M
  187. #define YSIM_RETURN #R
  188. #define YSIM_CALLER #C
  189. #define YSIM_TEXT_D #T
  190. #define YSIM_TXTFND #X
  191. #define YSIM_TXTIND #I
  192. #define YSIM_TXTLEN #E
  193. #define YSIM_LOG_IN #U
  194. #define YSIM_VARARG #V
  195. #if !defined YSIM_STRING
  196. #define YSIM_STRING (42)
  197. #endif
  198. #define FLOAT_INFINITY (Float:0x7F800000)
  199. #define FLOAT_NEG_INFINITY (Float:0xFF800000)
  200. #define FLOAT_NEGATIVE_INFINITY (Float:0xFF800000)
  201. #define FLOAT_NAN (Float:0x7FFFFFFF)
  202. #define FLOAT_NOT_A_NUMBER (Float:0x7FFFFFFF)
  203. #define FLOAT_QNAN (Float:0x7FFFFFFF)
  204. #define FLOAT_QUIET_NAN (Float:0x7FFFFFFF)
  205. #define FLOAT_QUIET_NOT_A_NUMBER (Float:0x7FFFFFFF)
  206. #define FLOAT_SNAN (Float:0x7FBFFFFF)
  207. #define FLOAT_SIGNALING_NAN (Float:0x7FBFFFFF)
  208. #define FLOAT_SIGNALING_NOT_A_NUMBER (Float:0x7FBFFFFF)
  209. //#pragma unused TRUE, FALSE, NULL
  210. #define __TY|||%0||| (1000000)
  211. #define __TX:__TY|||%0,%1||| (%1)
  212. #define __TF=fopen(%0,%2"%3",%4) __TF=fopen(%0".csv",%4)
  213. #if !defined TIMING_ITERATIONS
  214. #define TIMING_ITERATIONS (10)
  215. #endif
  216. /*-------------------------------------------------------------------------*//**
  217. * <param name="t">The time in ms.</param>
  218. * <param name="iters">The number of iterations completed in this time.</param>
  219. * <remarks>
  220. * Formats and returns a string representing the time taken for one iteration,
  221. * given the time required for many iterations. This attempts to format the
  222. * number using a reasonable fraction of a second.
  223. * </remarks>
  224. *//*------------------------------------------------------------------------**/
  225. stock __TU(t, iters)
  226. {
  227. // Number of times run. Accounts for the string and optional count.
  228. new
  229. ret[20];
  230. if (iters > 1000000000)
  231. format(ret, sizeof (ret), "%.2fps", float(t) / (float(iters) / 1000000000.0));
  232. else if (iters == 1000000000)
  233. format(ret, sizeof (ret), "%d.00ps", t);
  234. else if (iters > 1000000)
  235. format(ret, sizeof (ret), "%.2fns", float(t) / (float(iters) / 1000000.0));
  236. else if (iters == 1000000)
  237. format(ret, sizeof (ret), "%d.00ns", t);
  238. else if (iters > 1000)
  239. format(ret, sizeof (ret), "%.2fus", float(t) / (float(iters) / 1000.0));
  240. else if (iters == 1000)
  241. format(ret, sizeof (ret), "%d.00us", t);
  242. else if (iters > 1)
  243. format(ret, sizeof (ret), "%.2fms", float(t) / float(iters));
  244. else
  245. format(ret, sizeof (ret), "%d.00ms", t);
  246. return ret;
  247. }
  248. #define RUN_TIMING(%0) \
  249. for(new __TA[TIMING_ITERATIONS],__TC=sizeof __TA,__TE=_:__TX:__TY|||%0|||,__TS=printf("Timing \"%s\"...",%0);__TC; \
  250. printf("\t Mean = %s\n\t Mode = %s\n\tMedian = %s\n\t Range = %s", \
  251. __TU(Mean(__TA),__TE),__TU(Mode(__TA),__TE),__TU(Median(__TA),__TE),__TU(Range(__TA),__TE))) \
  252. for(;(__TS=GetTickCount(),__TC);__TA[--__TC]=GetTickCount()-__TS) \
  253. for(new __TI;__TI!=__TE;++__TI)
  254. #define CSV_TIMING(%0) \
  255. for(new __TA[TIMING_ITERATIONS],__TC=sizeof __TA,__TE=_:__TX:__TY|||%0|||,__TS=printf("Timing \"%s\"...",%0),File:__TF=fopen(%0".csv",io_append);__TF&&__TC;\
  256. va_fprintf(__TF,"%d,%d,%s,%s,%s,%s\n",gettime(),__TE,__TU(Mean(__TA),__TE),__TU(Mode(__TA),__TE),__TU(Median(__TA),__TE),__TU(Range(__TA),__TE)),fclose(__TF))\
  257. for(;(__TS=GetTickCount(),__TC);__TA[--__TC]=GetTickCount()-__TS)\
  258. for(new __TI;__TI!=__TE;++__TI)
  259. stock
  260. YSI_gPlayerIP[MAX_PLAYERS + 1] = {-1, ...};
  261. public OnPlayerConnect(playerid)
  262. {
  263. new
  264. ip[16];
  265. GetPlayerIp(playerid, ip, sizeof (ip)),
  266. YSI_gPlayerIP[playerid] = IPToInt(ip);
  267. #if defined _y_utils_OnPlayerConnect
  268. _y_utils_OnPlayerConnect(playerid);
  269. #endif
  270. return 1;
  271. }
  272. #if defined _ALS_OnPlayerConnect
  273. #undef OnPlayerConnect
  274. #else
  275. #define _ALS_OnPlayerConnect
  276. #endif
  277. #define OnPlayerConnect _y_utils_OnPlayerConnect
  278. #if defined _y_utils_OnPlayerConnect
  279. forward _y_utils_OnPlayerConnect(playerid);
  280. #endif
  281. public OnPlayerDisconnect(playerid, reason)
  282. {
  283. YSI_gPlayerIP[playerid] = -1;
  284. #if defined _y_utils_OnPlayerDisconnect
  285. _y_utils_OnPlayerDisconnect(playerid, reason);
  286. #endif
  287. return 1;
  288. }
  289. #if defined _ALS_OnPlayerDisconnect
  290. #undef OnPlayerDisconnect
  291. #else
  292. #define _ALS_OnPlayerDisconnect
  293. #endif
  294. #define OnPlayerDisconnect _y_utils_OnPlayerDisconnect
  295. #if defined _y_utils_OnPlayerDisconnect
  296. forward _y_utils_OnPlayerDisconnect(playerid, reason);
  297. #endif
  298. /*-------------------------------------------------------------------------*//**
  299. * <param name="value">The unsigned number to compare.</param>
  300. * <param name="upper">The upper limit.</param>
  301. * <returns>
  302. * An unsigned comparison between the two values.
  303. * </returns>
  304. *//*------------------------------------------------------------------------**/
  305. P:D(bool:UCMP(value, upper));
  306. #define UCMP(%0,%1) IS_IN_RANGE(%0,0,(%1))
  307. /*-------------------------------------------------------------------------*//**
  308. * <param name="playerid">The player to check.</param>
  309. * <returns>
  310. * Is this a valid playerid (NOT, is the player connected).
  311. * </returns>
  312. *//*------------------------------------------------------------------------**/
  313. P:D(bool:VALID_PLAYERID(playerid));
  314. #define VALID_PLAYERID(%0) UCMP((%0), MAX_PLAYERS)
  315. /*-------------------------------------------------------------------------*//**
  316. * <param name="value">The number to compare.</param>
  317. * <param name="lower">The lower limit.</param>
  318. * <param name="upper">The upper limit.</param>
  319. * <returns>
  320. * Is the value in the given range.
  321. * </returns>
  322. * <remarks>
  323. * Equivalent to:
  324. *
  325. * <code> (%1) &lt;= (%0) &lt; (%2)</code>
  326. *
  327. * </remarks>
  328. *//*------------------------------------------------------------------------**/
  329. P:D(bool:IS_IN_RANGE(value, lower, upper));
  330. #define IS_IN_RANGE(%0,%1,%2) (((%0)-((%1)+cellmin))<((%2)-((%1)+cellmin)))
  331. /*-------------------------------------------------------------------------*//**
  332. * <param name="value">The number to compare.</param>
  333. * <param name="lower">The lower limit.</param>
  334. * <param name="upper">The upper limit.</param>
  335. * <returns>
  336. * Is the value outside the given range.
  337. * </returns>
  338. * <remarks>
  339. * Equivalent to:
  340. *
  341. * <code> (%1) &lt;= (%0) &lt; (%2)</code>
  342. *
  343. * </remarks>
  344. *//*------------------------------------------------------------------------**/
  345. P:D(bool:NOT_IN_RANGE(value, lower, upper));
  346. #define NOT_IN_RANGE(%0,%1,%2) (((%0)-((%1)+cellmin))>=((%2)-((%1)+cellmin)))
  347. /*-------------------------------------------------------------------------*//**
  348. * <param name="numerator">The top of the division.</param>
  349. * <param name="denominator">The bottom of the division.</param>
  350. * <returns>
  351. * (numerator / denominator) rounded up.
  352. * </returns>
  353. * <remarks>
  354. * Normal integer division ALWAYS rounds down - this always rounds up.
  355. * </remarks>
  356. *//*------------------------------------------------------------------------**/
  357. P:D(ceildiv(numerator, denominator));
  358. #define ceildiv(%0,%1) (((%0)-1)/(%1)+1)
  359. /*-------------------------------------------------------------------------*//**
  360. * <summary>
  361. * floordiv(numerator, denominator);
  362. * </summary>
  363. * <param name="numerator">The top of the division.</param>
  364. * <param name="denominator">The bottom of the division.</param>
  365. * <returns>
  366. * (numerator / denominator) rounded down.
  367. * </returns>
  368. * <remarks>
  369. * Normal integer division ALWAYS rounds down - this also always rounds down,
  370. * making it a little pointless, but also more explicit in function.
  371. * </remarks>
  372. *//*------------------------------------------------------------------------**/
  373. P:D(floordiv(numerator, denominator));
  374. #define floordiv(%0,%1) ((%0)/(%1))
  375. /*-------------------------------------------------------------------------*//**
  376. * <param name="str">String to check if is null.</param>
  377. *//*------------------------------------------------------------------------**/
  378. P:D(bool:isnull(str[]));
  379. #define isnull(%1) \
  380. ((%1[0] == 0) || (%1[0] == 1 && %1[1] == 0))
  381. /*-------------------------------------------------------------------------*//**
  382. * <param name="value">Value to check if is odd.</param>
  383. *//*------------------------------------------------------------------------**/
  384. P:D(bool:isodd(value));
  385. #define isodd(%1) \
  386. ((%1) & 1)
  387. /*-------------------------------------------------------------------------*//**
  388. * <param name="value">Value to check if is even.</param>
  389. *//*------------------------------------------------------------------------**/
  390. P:D(bool:iseven(value));
  391. #define iseven(%1) \
  392. (!isodd(%1))
  393. /*-------------------------------------------------------------------------*//**
  394. * <param name="dest">Destination string.</param>
  395. * <param name="src">Source string.</param>
  396. * <param name="len">(Implicit) maximum length of the destination.</param>
  397. *//*------------------------------------------------------------------------**/
  398. P:D(strcpy(dest[], const src[], len = sizeof (dest)));
  399. #define strcpy(%0,%1) \
  400. strcat((%0[0] = '\0', %0), %1)
  401. /*-------------------------------------------------------------------------*//**
  402. * <param name="str">String to convert.</param>
  403. * <param name="len">How much of the string to convert.</param>
  404. *//*------------------------------------------------------------------------**/
  405. stock StrToLower(str[], len = sizeof (str))
  406. {
  407. new
  408. i = -1,
  409. ch;
  410. while ((ch = str[++i]) && len--)
  411. str[i] = tolower(ch);
  412. }
  413. /*-------------------------------------------------------------------------*//**
  414. * <param name="str">String to convert.</param>
  415. * <param name="len">How much of the string to convert.</param>
  416. *//*------------------------------------------------------------------------**/
  417. stock StrToUpper(str[], len = sizeof (str))
  418. {
  419. new
  420. i = -1,
  421. ch;
  422. while ((ch = str[++i]) && len--)
  423. str[i] = toupper(ch);
  424. }
  425. /*-------------------------------------------------------------------------*//**
  426. * <param name="minmax">Lower bound, or upper bound when only parameter.</param>
  427. * <param name="max">Upper bound.</param>
  428. * <remarks>
  429. * Generate a random float between the given numbers (min &lt;= n &lt; max).
  430. * Default minimum is 0 (changes the parameter order).
  431. * </remarks>
  432. *//*------------------------------------------------------------------------**/
  433. stock Random(min, max = cellmin)
  434. {
  435. if (max == cellmin)
  436. {
  437. if (min < 0)
  438. return -random(-min);
  439. return random(min);
  440. }
  441. if (max < min)
  442. return random(min - max) + max;
  443. return random(max - min) + min;
  444. }
  445. /*-------------------------------------------------------------------------*//**
  446. * <param name="minmax">Lower bound, or upper bound when only parameter.</param>
  447. * <param name="max">Upper bound.</param>
  448. * <param name="dp">How small to make the differences</param>
  449. * <remarks>
  450. * Generate a random float between the given numbers (min &lt;= n &lt; max). Default
  451. * minimum is 0.0 (changes the parameter order).
  452. * </remarks>
  453. *//*------------------------------------------------------------------------**/
  454. stock Float:RandomFloat(Float:min, Float:max = FLOAT_NAN, dp = 2)
  455. {
  456. new
  457. Float:mul = floatpower(10.0, float(dp));
  458. switch (dp)
  459. {
  460. case 0: mul = 1.0;
  461. case 1: mul = 10.0;
  462. case 2: mul = 100.0;
  463. case 3: mul = 1000.0;
  464. default: mul = floatpower(10.0, float(dp));
  465. }
  466. if (max != max)
  467. {
  468. if (min < 0.0)
  469. return -(float(random(floatround(-min * mul))) / mul);
  470. return float(random(floatround(min * mul))) / mul;
  471. }
  472. // Parameters are the wrong way around - do it anyway.
  473. if (max < min)
  474. return float(random(floatround(min * mul - max * mul))) / mul + max;
  475. // NOT a silly check - "IsNaN".
  476. return float(random(floatround(max * mul - min * mul))) / mul + min;
  477. }
  478. /*-------------------------------------------------------------------------*//**
  479. * <param name="str">The string to remove whitespace from the end of.</param>
  480. * <remarks>
  481. * Updated from old versions, should be more efficient
  482. * </remarks>
  483. *//*------------------------------------------------------------------------**/
  484. stock StripNL(str[])
  485. {
  486. P:7("StripNL called: \"%s\"", str);
  487. new
  488. i = strlen(str);
  489. while (i-- && str[i] <= ' ') str[i] = '\0';
  490. }
  491. #define StripR StripNL
  492. /*-------------------------------------------------------------------------*//**
  493. * <param name="str">The string to remove whitespace from the start of.</param>
  494. *//*------------------------------------------------------------------------**/
  495. stock StripL(str[])
  496. {
  497. P:7("StripL called: \"%s\"", str);
  498. new
  499. len = strlen(str),
  500. i = 0;
  501. while ('\0' < str[i] <= ' ') ++i;
  502. if (i) memcpy(str[0], str[i], 0, (len - i) * 4, len);
  503. }
  504. /*-------------------------------------------------------------------------*//**
  505. * <param name="str">The string to remove whitespace from the start and end of.</param>
  506. *//*------------------------------------------------------------------------**/
  507. stock Strip(str[])
  508. {
  509. P:7("Strip called: \"%s\"", str);
  510. new
  511. len = strlen(str),
  512. i = len;
  513. while (i-- && str[i] <= ' ') str[i] = '\0';
  514. i = 0;
  515. while ('\0' < str[i] <= ' ') ++i;
  516. if (i) memcpy(str[0], str[i], 0, (len - i) * 4, len);
  517. }
  518. /*-------------------------------------------------------------------------*//**
  519. * <param name="line">String to check.</param>
  520. * <param name="pos">Postion to start from.</param>
  521. * <remarks>
  522. * Checks if the current point in a line is the end of non-whitespace data.
  523. * </remarks>
  524. *//*------------------------------------------------------------------------**/
  525. stock endofline(line[], pos)
  526. {
  527. P:7("endofline called: \"%s\", %i", line, pos);
  528. if (NOT_IN_RANGE(pos, 0, strlen(line))) return 0;
  529. //if (pos < 0 || pos > strlen(line)) return 0;
  530. while (line[pos]) if (line[pos++] > ' ') return 0;
  531. return 1;
  532. }
  533. /*-------------------------------------------------------------------------*//**
  534. * <param name="needle">The character to find.</param>
  535. * <param name="haystack">The string to find it in.</param>
  536. * <param name="start">The offset to start from.</param>
  537. * <returns>
  538. * Fail - -1, Success - pos
  539. * </returns>
  540. *//*------------------------------------------------------------------------**/
  541. stock chrfind(needle, haystack[], start = 0)
  542. {
  543. P:7("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  544. if (start < 0)
  545. {
  546. start = 0;
  547. }
  548. else if (start > strlen(haystack)) return -1;
  549. while (haystack[start]) if (haystack[start++] == needle) return start - 1;
  550. return -1;
  551. }
  552. /*-------------------------------------------------------------------------*//**
  553. * <param name="needle">The character to find.</param>
  554. * <param name="haystack">The string to find it in.</param>
  555. * <param name="start">The offset to start from.</param>
  556. * <returns>
  557. * Fail - -1, Success - pos
  558. * </returns>
  559. * <remarks>
  560. * Like <symbolref name="chrfind" />, but with no upper-bounds check on
  561. * <paramref name="start" />.
  562. * </remarks>
  563. *//*------------------------------------------------------------------------**/
  564. stock chrfindp(needle, haystack[], start = 0)
  565. {
  566. P:7("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  567. if (start < 0)
  568. {
  569. start = 0;
  570. }
  571. while (haystack{start}) if (haystack{start++} == needle) return start - 1;
  572. return -1;
  573. }
  574. /*-------------------------------------------------------------------------*//**
  575. * <param name="ip">Dot notation IP to convert to an integer.</param>
  576. *//*------------------------------------------------------------------------**/
  577. stock IPToInt(ip[])
  578. {
  579. new
  580. ipv = strval(ip) << 24,
  581. pos = 0;
  582. while (pos < 15 && ip[pos++] != '.') {}
  583. ipv += strval(ip[pos]) << 16;
  584. while (pos < 15 && ip[pos++] != '.') {}
  585. ipv += strval(ip[pos]) << 8;
  586. while (pos < 15 && ip[pos++] != '.') {}
  587. return ipv + strval(ip[pos]);
  588. }
  589. /*-------------------------------------------------------------------------*//**
  590. * <param name="string">the string to hash.</param>
  591. * <returns>
  592. * the bernstein hash of the input string
  593. * </returns>
  594. * <remarks>
  595. * This is a 32bit hash system so is not very secure, however we're only
  596. * using this as a string enumerator to uniquely identify strings easilly
  597. * and allow for a binary search of strings based on the hash of their name.
  598. * crc32, then jenkins were originally used however this is far faster, if a
  599. * little collision prone, but we're checking the strings manually anyway.
  600. * This doesn't matter as it would be done regardless of hash method, so this
  601. * doesn't need to be accounted for. Speed is all that matters with at
  602. * least a bit of non collision (the number of strings we're dealing with,
  603. * this should have none-few collisions).
  604. *
  605. * I modified it slightly from the original code pasted by aru, to code
  606. * closer to the code <a href="http://www.burtleburtle.net/bob/hash/doobs.html" />
  607. * and to work with PAWN (and shaved 0.2�s off the time for one call :D).
  608. *
  609. * Uber reduced version (just for fun):
  610. * b(s[]){new h=-1,i,j;while((j=s[i++]))h=h*33+j;return h;}
  611. *
  612. * Update: Contrary to what I said above this is also used to identify colour
  613. * strings for the updated text system involving file based styling and this
  614. * is not checked for collisions as it's unimportant. But this doesn't affect
  615. * the function at all, I just mentioned it here for "interest".
  616. *
  617. * Rewritten in self-generating assembly.
  618. * </remarks>
  619. *//*------------------------------------------------------------------------**/
  620. stock bernstein(string[] /* 12 */)
  621. {
  622. // Only shown the very first time this function is run.
  623. P:7("bernstein called: \"%s\"", string);
  624. #pragma unused string
  625. new
  626. base,
  627. ctx[AsmContext];
  628. // Get this function.
  629. #emit CONST.pri bernstein
  630. #emit LOAD.alt AMX_HEADER_COD
  631. #emit ADD
  632. #emit STOR.S.pri base
  633. AsmInitPtr(ctx, base, 128), // Don't need any more than that.
  634. // Setup.
  635. @emit PROC
  636. @emit CONST.alt -1
  637. @emit PUSH.S 12 // string
  638. @emit LREF.S.pri 12 // string
  639. @emit JZER.rel 12 * 4 // bernstein_end
  640. // bernstein_loop:
  641. @emit XCHG
  642. @emit SMUL.C 33
  643. @emit ADD
  644. @emit MOVE.alt
  645. // Update the next pointer.
  646. @emit POP.pri
  647. @emit ADD.C 4
  648. @emit PUSH.pri
  649. // Load the data for the current pointer.
  650. @emit LOAD.I
  651. @emit JNZ.rel -(12 * 4) // bernstein_loop
  652. // bernstein_end:
  653. @emit MOVE.pri
  654. @emit STACK 4
  655. @emit RETN
  656. // Now actually CALL the written function.
  657. #emit LCTRL 5
  658. #emit SCTRL 4
  659. #emit CONST.pri bernstein
  660. #emit ADD.C 4
  661. #emit SCTRL 6
  662. return 0; // Make the compiler happy.
  663. }
  664. /*-------------------------------------------------------------------------*//**
  665. * <param name="str">String to check.</param>
  666. * <returns>
  667. * true/false.
  668. * </returns>
  669. *//*------------------------------------------------------------------------**/
  670. stock ishex(str[])
  671. {
  672. P:7("ishex called: \"%s\"", str);
  673. new
  674. i,
  675. cur;
  676. if (str[0] == '0' && (str[1] | 0x20) == 'x') i = 2;
  677. do
  678. {
  679. cur = str[i++];
  680. }
  681. while (IS_IN_RANGE(cur, '0', '9' + 1) || IS_IN_RANGE(cur | 0x20, 'a', 'f' + 1));
  682. //while (('0' <= cur <= '9') || ('a' <= (cur | 0x20) <= 'f'));
  683. return !cur; // Valid if this is the end of the string.
  684. }
  685. /*-------------------------------------------------------------------------*//**
  686. * <param name="str">String to unpack</param>
  687. * <returns>
  688. * unpacked string
  689. * </returns>
  690. * <remarks>
  691. * Mainly used for debugging.
  692. * </remarks>
  693. *//*------------------------------------------------------------------------**/
  694. stock unpack(const str[])
  695. {
  696. P:7("unpack called: \"%s\"", str);
  697. new
  698. ret[YSI_MAX_STRING] = {0};
  699. if (strlen(str) <= YSI_MAX_STRING)
  700. {
  701. strunpack(ret, str);
  702. }
  703. return ret;
  704. }
  705. /*-------------------------------------------------------------------------*//**
  706. * <param name="playerid">Player to get IP of.</param>
  707. * <returns>
  708. * IP as a 32bit int.
  709. * </returns>
  710. *//*------------------------------------------------------------------------**/
  711. // Cunning macro only uses "%0" once, yet is still safe.
  712. P:D(GetIP(playerid));
  713. #define GetIP(%0) (YSI_gPlayerIP[min((%0) + cellmin, MAX_PLAYERS + cellmin) - cellmin])
  714. /*-------------------------------------------------------------------------*//**
  715. * <param name="idx">Index of the string in the parameters.</param>
  716. * <returns>
  717. * string
  718. * </returns>
  719. * <remarks>
  720. * Is passed the result of getarg, which will be the address of a string (in
  721. * theory) and uses that for DMA to get the string.
  722. * </remarks>
  723. *//*------------------------------------------------------------------------**/
  724. #define getstring returnstringarg
  725. #define GetString getstring
  726. #define getstringarg va_getstring
  727. #define GetStringArg va_getstring
  728. #define ReturnStringArg returnstringarg
  729. stock returnstringarg(idx)
  730. {
  731. static
  732. scSize = YSI_MAX_STRING;
  733. // Get the address of the previous function's stack. First get the index of
  734. // the argument required.
  735. #emit LOAD.S.pri idx
  736. // Then convert that number to bytes from cells.
  737. #emit SMUL.C 4
  738. // Get the previous function's frame. Stored in variable 0 (in the current
  739. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  740. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  741. // checks that "idx * 4 < *(*(FRM + 0) + 8)", for the previous frame
  742. // parameter count (in C pointer speak).
  743. #emit LOAD.S.alt 0
  744. // Add the frame pointer to the argument offset in bytes.
  745. #emit ADD
  746. // Add 12 to skip over the function header.
  747. #emit ADD.C 12
  748. // Load the address stored in the specified address.
  749. #emit LOAD.I
  750. // Push the length for "strcat".
  751. #emit PUSH scSize
  752. // Push the address we just determined was the source.
  753. #emit PUSH.pri
  754. // Load the address of the secret destination.
  755. #emit LOAD.S.alt 16
  756. // Blank the first cell so "strcat" behaves like "strcpy".
  757. #emit CONST.pri 0
  758. // Store the loaded number 0 to the loaded address.
  759. #emit STOR.I
  760. // Push the loaded address.
  761. #emit PUSH.alt
  762. // Push the number of parameters passed (in bytes) to the function.
  763. #emit PUSH.C 12
  764. // Call the function.
  765. #emit SYSREQ.C strcat
  766. // Restore the stack to its level before we called this native.
  767. #emit STACK 16
  768. // Return without more string copying.
  769. #emit RETN
  770. // Fake return to define the API.
  771. new
  772. ret[YSI_MAX_STRING];
  773. return ret;
  774. }
  775. /*-------------------------------------------------------------------------*//**
  776. * <param name="fmat">String format.</param>
  777. * <param name="">Parameters.</param>
  778. * <returns>
  779. * Formatted string.
  780. * </returns>
  781. * <remarks>
  782. * Just wraps `format` and returns a string instead.
  783. *
  784. * Has extra code to ensure that it works correct on the old compiler.
  785. * </remarks>
  786. *//*------------------------------------------------------------------------**/
  787. stock va_return(const fmat[], GLOBAL_TAG_TYPES:...)
  788. {
  789. #pragma unused fmat
  790. static
  791. sFrm,
  792. sRet,
  793. sCnt,
  794. scSize = YSI_MAX_STRING;
  795. // Store the function preamble.
  796. #emit POP.pri
  797. #emit STOR.pri sFrm
  798. #emit STACK 0 // Load the stack pointer for later.
  799. #emit POP.pri
  800. #emit STOR.pri sRet
  801. #emit POP.pri
  802. #emit ADD.C 8
  803. #emit STOR.pri sCnt
  804. // Put the secret return parameter on the stack again to format in to.
  805. #emit PUSH scSize
  806. #emit ADD
  807. #emit LOAD.I
  808. #emit PUSH.pri
  809. // Call the native.
  810. #emit PUSH sCnt
  811. #emit SYSREQ.C format
  812. // Return directly. This will clean up our entire stack, even the extra
  813. // parameters we put on it. The parameter count is already there!
  814. #emit PUSH sRet
  815. #emit PUSH sFrm
  816. #emit RETN
  817. // Fake return to define the API.
  818. new
  819. ret[YSI_MAX_STRING];
  820. return ret;
  821. }
  822. /*-------------------------------------------------------------------------*//**
  823. * <param name="str">String to check</param>
  824. * <remarks>
  825. * Checks if a given string is numeric.
  826. * </remarks>
  827. *//*------------------------------------------------------------------------**/
  828. stock isnumeric(str[])
  829. {
  830. P:7("isnumeric called: \"%s\"", str);
  831. new
  832. i;
  833. while (IS_IN_RANGE(str[i], '0', '9' + 1)) ++i;
  834. //while ((ch = str[i++])) if (!('0' <= ch <= '9')) return 0;
  835. return !str[i];
  836. }
  837. #if !defined _inc_sscanf || 1
  838. /*---------------------------------------------------------------------*//**
  839. *
  840. * <param name="string">String to convert to a number.</param>
  841. * <returns>
  842. * value of the passed hex string.
  843. * </returns>
  844. * <remarks>
  845. * Now stops on invalid characters.
  846. * </remarks>
  847. *//*--------------------------------------------------------------------**/
  848. stock hexstr(string[])
  849. {
  850. new
  851. ret,
  852. val,
  853. i;
  854. if (string[0] == '0' && string[1] | 0x20 == 'x') i = 2;
  855. for ( ; ; )
  856. {
  857. switch ((val = string[i++]))
  858. {
  859. case '0' .. '9':
  860. {
  861. val -= '0';
  862. }
  863. case 'a' .. 'f':
  864. {
  865. val -= 'a' - 10;
  866. }
  867. case 'A' .. 'F':
  868. {
  869. val -= 'A' - 10;
  870. }
  871. default: break;
  872. }
  873. ret = ret << 4 | val;
  874. }
  875. return ret;
  876. }
  877. /*---------------------------------------------------------------------*//**
  878. *
  879. * <param name="string">String to try convert to a boolean.</param>
  880. * <returns>
  881. * bool: passed boolean.
  882. * </returns>
  883. * <remarks>
  884. * This can take a number of ways of representing booleans - 0, false and
  885. * nothing there. Anything not one of those things (false is not case
  886. * sensitive) is assumed true.
  887. * </remarks>
  888. *//*--------------------------------------------------------------------**/
  889. stock bool:boolstr(string[])
  890. {
  891. // Hooray for De Morgan's rules!
  892. return string[0] && string[0] != '0' && strcmp(string, "false", true);
  893. }
  894. /*---------------------------------------------------------------------*//**
  895. *
  896. * <param name="string">String to try convert to a boolean.</param>
  897. * <returns>
  898. * bool: passed boolean.
  899. * </returns>
  900. * <remarks>
  901. * This takes a value in 0110101 (boolean) format and returns it as a
  902. * regular value.
  903. * </remarks>
  904. *//*--------------------------------------------------------------------**/
  905. stock binstr(string[])
  906. {
  907. new
  908. pos = 0;
  909. switch (string[0])
  910. {
  911. case '0':
  912. {
  913. if (string[1] | 0x20 == 'b')
  914. {
  915. pos = 2;
  916. }
  917. }
  918. case '1':
  919. {
  920. }
  921. default:
  922. {
  923. return 0;
  924. }
  925. }
  926. new
  927. value = 0;
  928. for ( ; ; )
  929. {
  930. switch (string[pos++])
  931. {
  932. case '0':
  933. {
  934. value <<= 1;
  935. }
  936. case '1':
  937. {
  938. value = (value << 1) | 1;
  939. }
  940. default:
  941. {
  942. break;
  943. }
  944. }
  945. }
  946. return value;
  947. }
  948. #endif
  949. /*-------------------------------------------------------------------------*//**
  950. * <summary>
  951. * rawMemcpy
  952. * </summary>
  953. * <param name="dest">Destination address.</param>
  954. * <param name="src">Source data.</param>
  955. * <param name="bytes">Number of bytes to copy.</param>
  956. * <remarks>
  957. * Like memcpy, but takes addresses instead of arrays. Also far less secure.
  958. * </remarks>
  959. *//*------------------------------------------------------------------------**/
  960. stock rawMemcpy(dest, src, bytes)
  961. {
  962. // Don't use "MOVS" as these blocks might overlap.
  963. #emit PUSH.S bytes
  964. #emit PUSH.S bytes
  965. #emit PUSH.C 0
  966. #emit PUSH.S src
  967. #emit PUSH.S dest
  968. #emit PUSH.C 20
  969. #emit SYSREQ.C memcpy
  970. #emit STACK 24
  971. #emit RETN
  972. return 0;
  973. }
  974. /*-------------------------------------------------------------------------*//**
  975. * <param name="arr">Array or address to set to a value.</param>
  976. * <param name="iValue">What to set the cells to.</param>
  977. * <param name="iSize">Number of cells to fill.</param>
  978. * <remarks>
  979. * Based on code by Slice:
  980. *
  981. * <a href="http://forum.sa-mp.com/showthread.php?p=1606781#post1606781" />
  982. *
  983. * Modified to use binary flags instead of a loop.
  984. *
  985. * "memset" takes an array, the size of the array, and a value to fill it with
  986. * and sets the whole array to that value.
  987. *
  988. * "rawmemset" is similar, but takes an AMX data segment address instead and
  989. * the size is in bytes, not cells. However, the size must still be a multiple
  990. * of 4.
  991. * </remarks>
  992. *//*------------------------------------------------------------------------**/
  993. stock memset(arr[], val = 0, size = sizeof (arr))
  994. {
  995. new
  996. addr;
  997. #emit LOAD.S.pri arr
  998. #emit STOR.S.pri addr
  999. // Convert the size from cells to bytes.
  1000. return rawMemset(addr, val, size * 4);
  1001. }
  1002. /*-------------------------------------------------------------------------*//**
  1003. * <param name="iAddress">Array or address to set to a value.</param>
  1004. * <param name="iValue">What to set the cells to.</param>
  1005. * <param name="iSize">Number of cells to fill.</param>
  1006. * <remarks>
  1007. * Based on code by Slice:
  1008. *
  1009. * <a href="http://forum.sa-mp.com/showthread.php?p=1606781#post1606781" />
  1010. *
  1011. * Modified to use binary flags instead of a loop.
  1012. *
  1013. * "memset" takes an array, the size of the array, and a value to fill it with
  1014. * and sets the whole array to that value.
  1015. *
  1016. * "rawmemset" is similar, but takes an AMX data segment address instead and
  1017. * the size is in bytes, not cells. However, the size must still be a multiple
  1018. * of 4.
  1019. * </remarks>
  1020. *//*------------------------------------------------------------------------**/
  1021. stock rawMemset(iAddress /* 12 */, iValue /* 16 */, iSize /* 20 */)
  1022. {
  1023. // They are really, trust me!
  1024. #pragma unused iAddress, iSize, iValue
  1025. // The first time this is called it rewrites itself. Any other times it is
  1026. // called it just uses the new code. This is like doing:
  1027. //
  1028. // static
  1029. // bInitialised = false;
  1030. // if (!bInitialised)
  1031. // {
  1032. // // Do something
  1033. // bInitialised = true;
  1034. // }
  1035. // // Do rest.
  1036. //
  1037. // But better (though FAR more complex).
  1038. // There is NO checking here that we don't write the function bigger than
  1039. // the space available, or even that we don't overwrite "CIP", which would
  1040. // be bad. The only way to make sure that doesn't happen is write a little
  1041. // with a lot of code!
  1042. new
  1043. base,
  1044. ctx[AsmContext];
  1045. // Get this function.
  1046. #emit CONST.pri rawMemset
  1047. #emit LOAD.alt AMX_HEADER_COD
  1048. #emit ADD
  1049. #emit STOR.S.pri base
  1050. AsmInitPtr(ctx, base, 80), // Don't need any more than that.
  1051. // Frankly by this point we have probably already written more code than
  1052. // will be generated!
  1053. @emit PROC
  1054. @emit LOAD.S.pri 20
  1055. @emit CONST.alt 0xFFFFFFC
  1056. @emit AND
  1057. @emit STOR.pri (ctx[AsmContext_buffer] + 13 * 4)
  1058. // The documentation says "PRI" should be a pointer, but that's not true!
  1059. @emit LOAD.S.alt 12
  1060. @emit LOAD.S.pri 16
  1061. @emit FILL 0
  1062. // Return the bytes filled.
  1063. @emit LOAD.pri (ctx[AsmContext_buffer] + 13 * 4)
  1064. @emit RETN
  1065. // Do the second version.
  1066. #emit CONST.pri memset
  1067. #emit LOAD.alt AMX_HEADER_COD
  1068. #emit ADD
  1069. #emit STOR.S.pri base
  1070. AsmInitPtr(ctx, base, 80),
  1071. @emit PROC
  1072. @emit LOAD.S.pri 20
  1073. @emit SHL.C.pri 2
  1074. @emit STOR.pri (ctx[AsmContext_buffer] + 12 * 4)
  1075. @emit LOAD.S.alt 12
  1076. @emit LOAD.S.pri 16
  1077. @emit FILL 0
  1078. // Return the bytes filled.
  1079. @emit LOAD.pri (ctx[AsmContext_buffer] + 12 * 4)
  1080. @emit RETN
  1081. // Call this function again (the new version), but don't let the compiler
  1082. // know... First clear the stack.
  1083. #emit LCTRL 5
  1084. #emit SCTRL 4
  1085. #emit CONST.pri rawMemset
  1086. #emit ADD.C 4
  1087. #emit SCTRL 6
  1088. // Never hit because of going to an earlier "RETN".
  1089. return 0; //memset("", 0, 0);
  1090. }
  1091. /*-------------------------------------------------------------------------*//**
  1092. * <summary>
  1093. * ReturnPlayerName
  1094. * </summary>
  1095. * <param name="playerid">Player whose name you want to get.</param>
  1096. * <remarks>
  1097. * Now uses a global array to avoid repeated function calls. Actually doesn't
  1098. * because that causes issues with multiple scripts.
  1099. * </remarks>
  1100. *//*------------------------------------------------------------------------**/
  1101. stock ReturnPlayerName(playerid)
  1102. {
  1103. new
  1104. str[MAX_PLAYER_NAME];
  1105. GetPlayerName(playerid, str, sizeof (str));
  1106. return str;
  1107. }
  1108. /*-------------------------------------------------------------------------*//**
  1109. * <summary>
  1110. * ftouch(filename);
  1111. * </summary>
  1112. * <param name="filename">The file to "touch".</param>
  1113. * <returns>
  1114. * 0 - File already exists.
  1115. * 1 - File was created.
  1116. * -1 - File was not created.
  1117. * </returns>
  1118. * <remarks>
  1119. * This "touches" a file in the Unix sense of creating it but not opening or
  1120. * editing it in any way.
  1121. * </remarks>
  1122. *//*------------------------------------------------------------------------**/
  1123. stock ftouch(const filename[])
  1124. {
  1125. if (fexist(filename))
  1126. {
  1127. return 0;
  1128. }
  1129. else
  1130. {
  1131. new
  1132. File:f = fopen(filename, io_write);
  1133. if (f)
  1134. {
  1135. fclose(f);
  1136. return 1;
  1137. }
  1138. else
  1139. {
  1140. return -1;
  1141. }
  1142. }
  1143. }
  1144. /*-------------------------------------------------------------------------*//**
  1145. * <summary>
  1146. * InterpolateColour(startcolor, endcolor, value, maxvalue, minvalue = 0);
  1147. * </summary>
  1148. * <param name="startcolor">One of the two colours.</param>
  1149. * <param name="endcolor">The other of the two colours.</param>
  1150. * <param name="value">The interpolation value between the endpoints.</param>
  1151. * <param name="maxvalue">One of the two numbers.</param>
  1152. * <param name="minvalue">The other of the two numbers.</param>
  1153. * <remarks>
  1154. * This function takes two endpoint values (minvalue and maxvalue, with
  1155. * minvalue defaulting to 0), along with a third value (value) whose distance
  1156. * between the two endpoints is calculated (as a percentage). This percentage
  1157. * value is then applied to the two colours given to find a third colour at
  1158. * some point between those two colours.
  1159. *
  1160. * For example, if the endpoints given are "0" and "10", and the value given is
  1161. * "3", then that is "30%" of the way between the two endpoints. We therefore
  1162. * want to find a colour that is 30% of the way between the two given colours.
  1163. * </remarks>
  1164. *//*------------------------------------------------------------------------**/
  1165. // "Interpolation" is the technical name for what you are doing here.
  1166. #define InterpolateColor InterpolateColour
  1167. stock InterpolateColour(startcolor, endcolor, value, maxvalue, minvalue = 0)
  1168. {
  1169. if (value >= maxvalue) return endcolor;
  1170. if (value <= minvalue) return startcolor;
  1171. static r, g, b, a;
  1172. new
  1173. time = maxvalue - minvalue,
  1174. stage = value - minvalue;
  1175. return
  1176. // Step 1: Get the starting colour components.
  1177. r = startcolor >>> 24 ,
  1178. g = startcolor >>> 16 & 0xFF,
  1179. b = startcolor >>> 8 & 0xFF,
  1180. a = startcolor & 0xFF,
  1181. // Step 2: Interpolate between the end points, and add to the start.
  1182. r += ((endcolor >>> 24 ) - r) * stage / time,
  1183. g += ((endcolor >>> 16 & 0xFF) - g) * stage / time,
  1184. b += ((endcolor >>> 8 & 0xFF) - b) * stage / time,
  1185. a += ((endcolor & 0xFF) - a) * stage / time,
  1186. // Step 3: Combine the individual components.
  1187. (r << 24) | ((g & 0xFF) << 16) | ((b & 0xFF) << 8) | (a & 0xFF);
  1188. }
  1189. /*-------------------------------------------------------------------------*//**
  1190. * <param name="str">The string to skip over part of.</param>
  1191. * <param name="pos">The start of the whitespace.</param>
  1192. * <returns>
  1193. * The end of the whitespace.
  1194. * </returns>
  1195. * <remarks>
  1196. * Doesn't skip over NULL terminators.
  1197. * </remarks>
  1198. *//*------------------------------------------------------------------------**/
  1199. stock SkipWhitespace(const str[], pos)
  1200. {
  1201. while (IS_IN_RANGE(str[pos], '\0' + 1, ' ' + 1)) ++pos;
  1202. //while ('\0' < str[pos] <= ' ') ++pos;
  1203. return pos;
  1204. }
  1205. /*-------------------------------------------------------------------------*//**
  1206. * <param name="str">The string to trim.</param>
  1207. * <param name="start">Start of the substring.</param>
  1208. * <param name="end">End of the substring.</param>
  1209. * <remarks>
  1210. * Modifies "start" and "end" to be tight on text in "str".
  1211. * </remarks>
  1212. *//*------------------------------------------------------------------------**/
  1213. stock Trim(const str[], &start, &end)
  1214. {
  1215. while (IS_IN_RANGE(str[start], '\0' + 1, ' ' + 1)) ++start;
  1216. //while ('\0' < str[start] <= ' ') ++start;
  1217. if (str[start])
  1218. {
  1219. while (end-- > start && str[end] <= ' ') {}
  1220. ++end;
  1221. }
  1222. else
  1223. {
  1224. end = start;
  1225. }
  1226. }
  1227. /*-------------------------------------------------------------------------*//**
  1228. * <param name="arr">The array to sort.</param>
  1229. * <param name="num">The size of the array.</param>
  1230. * <remarks>
  1231. * Sorts the array in place. Uses bubble sort because it is easy and fast for
  1232. * pre-sorted arrays (which the callers are likely to be).
  1233. * </remarks>
  1234. *//*------------------------------------------------------------------------**/
  1235. //#define ftell(%0) fseek((%0), 0, seek_current)
  1236. static stock Utils_PreSort(arr[], num = sizeof (arr))
  1237. {
  1238. // Very simple bubble sort (fast for pre-sorted arrays).
  1239. new
  1240. bool:sort;
  1241. do
  1242. {
  1243. sort = false;
  1244. for (new j = 1, temp; j != num; ++j)
  1245. {
  1246. if ((temp = arr[j]) < arr[j - 1])
  1247. {
  1248. arr[j] = arr[j - 1],
  1249. arr[j - 1] = temp,
  1250. sort = true;
  1251. }
  1252. }
  1253. }
  1254. while (sort);
  1255. }
  1256. /*-------------------------------------------------------------------------*//**
  1257. * <param name="arr">The array whose values need summing.</param>
  1258. * <param name="num">The size of the array.</param>
  1259. * <returns>
  1260. * All the values in the array added together.
  1261. * </returns>
  1262. *//*------------------------------------------------------------------------**/
  1263. stock Sum(const arr[], num = sizeof (arr))
  1264. {
  1265. new
  1266. tot;
  1267. while (num) tot += arr[--num];
  1268. return tot;
  1269. }
  1270. /*-------------------------------------------------------------------------*//**
  1271. * <param name="arr">The array whose values need averaging.</param>
  1272. * <param name="num">The size of the array.</param>
  1273. * <returns>
  1274. * The mathematical mean value of the array.
  1275. * </returns>
  1276. *//*------------------------------------------------------------------------**/
  1277. stock Mean(const arr[], num = sizeof (arr))
  1278. {
  1279. return Sum(arr, num) / num;
  1280. }
  1281. /*-------------------------------------------------------------------------*//**
  1282. * <param name="arr">The array whose values need averaging.</param>
  1283. * <param name="num">The size of the array.</param>
  1284. * <returns>
  1285. * The mathematical modal value of the array.
  1286. * </returns>
  1287. *//*------------------------------------------------------------------------**/
  1288. stock Mode(arr[], num = sizeof (arr))
  1289. {
  1290. Utils_PreSort(arr, num);
  1291. new
  1292. ret,
  1293. count = 0,
  1294. cn,
  1295. cc;
  1296. for (new i = 0; i != num; ++i)
  1297. {
  1298. if (arr[i] == cn) ++cc;
  1299. else
  1300. {
  1301. if (cc > count) count = cc, ret = cn;
  1302. cc = 1, cn = arr[i];
  1303. }
  1304. }
  1305. if (cc > count) return cn;
  1306. else return ret;
  1307. }
  1308. /*-------------------------------------------------------------------------*//**
  1309. * <param name="arr">The array whose values need averaging.</param>
  1310. * <param name="num">The size of the array.</param>
  1311. * <returns>
  1312. * The mathematical median value of the array.
  1313. * </returns>
  1314. *//*------------------------------------------------------------------------**/
  1315. stock Median(arr[], num = sizeof (arr))
  1316. {
  1317. Utils_PreSort(arr, num);
  1318. new
  1319. idx = num >>> 1;
  1320. if (num & 1) return arr[idx];
  1321. else return (arr[idx] + arr[idx - 1]) / 2;
  1322. }
  1323. /*-------------------------------------------------------------------------*//**
  1324. * <param name="arr">The array whose values need averaging.</param>
  1325. * <param name="num">The size of the array.</param>
  1326. * <returns>
  1327. * The mathematical range of the values of the array.
  1328. * </returns>
  1329. *//*------------------------------------------------------------------------**/
  1330. stock Range(arr[], num = sizeof (arr))
  1331. {
  1332. new
  1333. min = cellmax,
  1334. max = cellmin,
  1335. cur;
  1336. while (num)
  1337. {
  1338. cur = arr[--num];
  1339. if (cur < min)
  1340. min = cur;
  1341. if (cur > max)
  1342. max = cur;
  1343. }
  1344. return max - min;
  1345. }
  1346. #include "..\YSI_Coding\y_va"
  1347. #include "..\YSI_Internal\y_shortfunc"
  1348. #if defined YSI_TESTS
  1349. #include "y_testing"
  1350. #include "y_utils/tests"
  1351. #endif