y_utils.inc 46 KB

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