render.inc 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742
  1. /*
  2. Legal:
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version
  5. 1.1 the "License"; you may not use this file except in compliance with
  6. the License. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/
  8. Software distributed under the License is distributed on an "AS IS" basis,
  9. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. for the specific language governing rights and limitations under the
  11. License.
  12. The Original Code is the YSI framework.
  13. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  14. Portions created by the Initial Developer are Copyright C 2011
  15. the Initial Developer. All Rights Reserved.
  16. Contributors:
  17. Y_Less
  18. koolk
  19. JoeBullet/Google63
  20. g_aSlice/Slice
  21. Misiur
  22. samphunter
  23. tianmeta
  24. maddinat0r
  25. spacemud
  26. Crayder
  27. Dayvison
  28. Ahmad45123
  29. Zeex
  30. irinel1996
  31. Yiin-
  32. Chaprnks
  33. Konstantinos
  34. Masterchen09
  35. Southclaws
  36. PatchwerkQWER
  37. m0k1
  38. paulommu
  39. udan111
  40. Thanks:
  41. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  42. ZeeX - Very productive conversations.
  43. koolk - IsPlayerinAreaEx code.
  44. TheAlpha - Danish translation.
  45. breadfish - German translation.
  46. Fireburn - Dutch translation.
  47. yom - French translation.
  48. 50p - Polish translation.
  49. Zamaroht - Spanish translation.
  50. Los - Portuguese translation.
  51. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  52. me to strive to better.
  53. Pixels^ - Running XScripters where the idea was born.
  54. Matite - Pestering me to release it and using it.
  55. Very special thanks to:
  56. Thiadmer - PAWN, whose limits continue to amaze me!
  57. Kye/Kalcor - SA:MP.
  58. SA:MP Team past, present and future - SA:MP.
  59. Optional plugins:
  60. Gamer_Z - GPS.
  61. Incognito - Streamer.
  62. Me - sscanf2, fixes2, Whirlpool.
  63. */
  64. #if !defined FORMAT_FADE_STEP
  65. #define FORMAT_FADE_STEP 2
  66. #endif
  67. #define Y_RENDER_SCM_COLOUR_LEN (8)
  68. //#define Y_RENDER_ONE_ARG
  69. // if ((arg = getarg(curArg++) || TRUE))
  70. // Loops through all possible arguments in lists, functions and singles. See
  71. // "case e_COMPRESS_FORMAT_DATA_CUSTOM:" for more details (an expanded macro
  72. // version can be found there).
  73. #define Y_RENDER_ARG for(new i,j,b=4;i!=2;++i)if(!i){if(ch&_:e_COMPRESS_FORMAT_DATA_FUNC){b=1,func="@yR_",va_getstring(func[4],curArg);if(funcidx(func)<0)func[b=2]='r';}else if(ch&_:e_COMPRESS_FORMAT_DATA_LIST)b=3;}else for(;(arg=b==1?W@(func,"iii",pid,(_:l),j):b==2?W@(func,"ii",(_:l),j):b==3?getarg(curArg,j++):getarg(curArg)),arg!=cellmin&&b||++curArg&0;b&=~4,++j)
  74. // Make the correct specifier string for the data stored in the compressed
  75. // specifier data.
  76. #define Y_RENDER_SPECIFIER(%0) ((ch&_:e_COMPRESS_FORMAT_DATA_ZERO)?((ch&_:e_COMPRESS_FORMAT_DATA_LEFT)?(scFormats[3][6]='%0',scFormats[3]):(scFormats[2][5]='%0',scFormats[2])):((ch&_:e_COMPRESS_FORMAT_DATA_LEFT)?(scFormats[1][5]='%0',scFormats[1]):(scFormats[0][4]='%0',scFormats[0])))
  77. // This makes hex and binary format specifiers display correctly with negative
  78. // numbers in all cases (e.g. %5x etc).
  79. #define Y_RENDER_FIX_NEGATIVE(%0:%1) if(width>%1)arg=(ch&_:e_COMPRESS_FORMAT_DATA_LEFT)?((ch&_:e_COMPRESS_FORMAT_DATA_ZERO)?format(ts,144,"%"#%0"%0-*"#%0,arg>>>32/%1,width-(%1-1),arg&(1<<32/%1)-1):format(ts,144,"%"#%0"%-*"#%0,arg>>>32/%1,width-(%1-1),arg&(1<<32/%1)-1)):(ch&_:e_COMPRESS_FORMAT_DATA_ZERO)?format(ts,144,"%0*"#%0"%"#%0,width-1,arg>>>32/%1,arg&(1<<32/%1)-1):format(ts,144,"%*"#%0"%"#%0,width-1,arg>>>32/%1,arg&(1<<32/%1)-1);else format(ts,144,"%"#%0"%"#%0,arg>>>32/%1,arg&(1<<32/%1)-1)
  80. // Try add a string to the current output. This needs modifying to reset the
  81. // whole function after a string is displayed. "onlyOne" is set in the case
  82. // where any line excess is cut off (e.g. in marquees).
  83. //#define Y_RENDER_ADD(%1) switch(Format_DoAddString(pid,output,%1,p,maxlen,llen,strlen(%1),fakepos,fade)){case 1:++one;case 2:Format_DoTryShow(output,fade);}
  84. #define Y_RENDER_DO_DISPLAY() {output[p]='\0';if(!none)Format_DoDisplay(pid,gInitialColour,output);if(onlyOne)return one;output[0]=p=0;llen=maxlen;++one;}
  85. #define Y_RENDER_ADD(%1) for(new __added,__len=strlen((%1)),__done;(__added=Format_DoAddString(output,%1[__done],p,__len,llen,fakePos));__done+=__added,__len-=__added){if(fade)state y_render_fade:y_render_fade_fake;else Y_RENDER_DO_DISPLAY()}
  86. //#define Y_RENDER_ADD_EX(%1,%2,%3) for(new __added,__len=(%3),__done=%2;(__added=Format_DoAddString(output,%1[__done],p,__len,llen,fakePos));__done+=__added,__len-=__added){if(fade)state y_render_fade:y_render_fade_fake;else Y_RENDER_DO_DISPLAY()}
  87. #define Y_RENDER_CHAR(%1) while(!Format_DoAddChar(output,(%1),p,llen,fakePos)){if(fade)state y_render_fade:y_render_fade_fake;else Y_RENDER_DO_DISPLAY()}
  88. // Helper macros to determine what a character is. This could be modified to
  89. // take in to account unicode letters, but that's hard. I don't know enough
  90. // about unicode, and frankly there are WAY too many characters to be listed
  91. // here. If other people want to modify this to support their language then
  92. // good on them.
  93. #define Y_TEXT_LETTER(%0) ('a'<=(%0)<='z'||'A'<=(%0)<='Z')
  94. #define Y_TEXT_NUMBER(%0) ('0'<=(%0)<='9')
  95. #define Y_RENDER_SCM_COLOUR_LEN (8)
  96. #define e_FORMAT_FLAGS_INDEX (0x00FFFFFF)
  97. #define e_FORMAT_FLAGS_REDO (0x01000000)
  98. #define e_FORMAT_FLAGS_ONE (0x02000000)
  99. #define e_FORMAT_FLAGS_NONE (0x04000000)
  100. static stock
  101. YSI_g_sListSep[4] = ", ",
  102. YSI_g_sFadeRedoTarget,
  103. YSI_g_sFadeLength,
  104. YSI_g_sFadeColour,
  105. bool:YSI_g_sJustOne,
  106. YSI_g_sTempStyle[E_STYLE_DATA],
  107. YSI_g_sTemp3D[E_3D_DATA],
  108. YSI_g_sTempMaster,
  109. Text:YSI_g_sBaseTD = TEXT_DRAW_NO_NEXT,
  110. //YSI_g_sExtraText[MAX_INI_ENTRY_TEXT],
  111. gInitialColour;
  112. /*-------------------------------------------------------------------------*//**
  113. * <transition keep="true" target="y_render_show : y_render_show_scm" />
  114. *//*------------------------------------------------------------------------**/
  115. stock _Text_SetDialogMode()
  116. {
  117. YSI_g_sTempStyle[E_STYLE_DATA_TYPE] = e_STYLE_TYPE_DIALOG;
  118. state y_render_show : y_render_show_scm;
  119. YSI_g_sJustOne = true;
  120. }
  121. stock Format_SetListSeparator(string:lst[])
  122. {
  123. strcpy(YSI_g_sListSep, lst);
  124. }
  125. /*-------------------------------------------------------------------------*//**
  126. * <transition keep="true" target="y_render_show : y_render_show_gt" />
  127. * <transition keep="true" target="y_render_show : y_render_show_scm" />
  128. * <transition keep="true" target="y_render_show : y_render_show_td" />
  129. * <transition keep="true" target="y_render_show : y_render_show_print" />
  130. *//*------------------------------------------------------------------------**/
  131. stock _Format_SetStyleData(master, index, style[E_STYLE_DATA], label[E_3D_DATA])
  132. {
  133. // =========================================================================
  134. //
  135. #pragma unused index
  136. //
  137. // MAJOR WARNING:
  138. //
  139. // "Text_IsLocalOwner" DOES NOT PASS "INDEX" CORRECTLY AS IT DOESN'T KNOW
  140. // WHAT IT SHOULD BE, DON'T FORGET THIS IF YOU EVER USE "index"...
  141. //
  142. // =========================================================================
  143. YSI_g_sTempMaster = master;
  144. YSI_g_sTempStyle = style;
  145. YSI_g_sTemp3D = label;
  146. switch (style[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK)
  147. {
  148. case e_STYLE_TYPE_GT_0, e_STYLE_TYPE_GT_1, e_STYLE_TYPE_GT_2, e_STYLE_TYPE_GT_3, e_STYLE_TYPE_GT_4, e_STYLE_TYPE_GT_5, e_STYLE_TYPE_GT_6:
  149. {
  150. state y_render_show : y_render_show_gt;
  151. // Now that we know the style, we can store only the exact style.
  152. YSI_g_sTempStyle[E_STYLE_DATA_TYPE] = ((style[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) >>> e_STYLE_TYPE_SHIFT) - e_STYLE_TYPE:1;
  153. YSI_g_sJustOne = true;
  154. return 144;
  155. }
  156. case e_STYLE_TYPE_CLIENT:
  157. {
  158. state y_render_show : y_render_show_scm;
  159. YSI_g_sJustOne = false;
  160. return 256;
  161. }
  162. case e_STYLE_TYPE_TD:
  163. {
  164. state y_render_show : y_render_show_td;
  165. YSI_g_sJustOne = true;
  166. // Anything with the ability to be longer than 1024 will require a
  167. // modification to the declaration of variables.
  168. return 1024;
  169. }
  170. }
  171. state y_render_show : y_render_show_print;
  172. return 1023;
  173. }
  174. static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <y_render_show : y_render_show_scm>
  175. {
  176. // This code doesn't yet deal with colours which are too close to have their
  177. // differences detected by the human eye (especially when there are spaces).
  178. curCol = newCol & 0x00FFFFFF;
  179. if (pos == 0)
  180. {
  181. gInitialColour = curCol;
  182. // Don't add the colour - this is handled in the text display function.
  183. return 0;
  184. }
  185. // Now try add the string version of the colour.
  186. //printf("rem: %d, required: %d", rem, Y_RENDER_SCM_COLOUR_LEN);
  187. if (rem < Y_RENDER_SCM_COLOUR_LEN + step)
  188. {
  189. // Not enough space to add a new colour.
  190. str[pos] = '\0';
  191. return -1;
  192. }
  193. // This may well cut characters off the end of the string, but don't worry,
  194. // well, you can worry because it may mean that some characters are parsed
  195. // multiple times, but there's not a lot you can do about it... This is one
  196. // of the few places where the extra "+ 1" is taken in to account as format
  197. // uses it internally.
  198. format(str[pos], rem + 1, "{%06x}%s", curCol, str[pos]);
  199. rem -= Y_RENDER_SCM_COLOUR_LEN;
  200. return Y_RENDER_SCM_COLOUR_LEN;
  201. }
  202. static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <>
  203. {
  204. #pragma unused str, pos, rem, step
  205. curCol = newCol;
  206. return 0;
  207. }
  208. static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <y_render_show : y_render_show_gt, y_render_show : y_render_show_td>
  209. {
  210. // First get the closest GameText colour for the true colour. I wrote a
  211. // function for this a LONG time ago, finally got around to using it!
  212. new
  213. ot = curCol & 0xFF,
  214. oc = curCol >>> 8;
  215. if (ot == 0 || ot == 'x')
  216. {
  217. // Still near the start, allow some of the special start colours.
  218. newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, oc);
  219. }
  220. else
  221. {
  222. // Can't use the oragey colour used at the start.
  223. newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, 3);
  224. }
  225. new
  226. nt = newCol & 0xFF,
  227. nc = (newCol >>> 8) * 3;
  228. curCol = newCol;
  229. // Compare them.
  230. static
  231. cs_hTags[] = "~x~~h~~h~~h~~h~~h~%s";
  232. if (nt == ot)
  233. {
  234. ot = nc - (oc * 3);
  235. if (ot == 0)
  236. {
  237. // No change, return 0 if there are enough charaters to show the
  238. // text that should come after this new colour.
  239. return rem >= step ? 0 : -1;
  240. }
  241. else if (ot > 0)
  242. {
  243. if (rem >= ot + step)
  244. {
  245. // Add enough "lighter" tags to change the old colour in to the
  246. // new colour.
  247. format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 3 - ot], str[pos]);
  248. rem -= ot;
  249. return ot;
  250. }
  251. else
  252. {
  253. return -1;
  254. }
  255. }
  256. }
  257. if (rem < nc + step)
  258. {
  259. return -1;
  260. }
  261. // Subtract six from the size : 3 for "%s\0" and 3 for the extra "~x~"
  262. // needed as placeholder for the colour tag (added on the next line).
  263. format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 6 - nc], str[pos]);
  264. str[pos + 1] = nt;
  265. rem -= nc + 3;
  266. return nc + 3;
  267. }
  268. static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <y_render_show : y_render_show_scm>
  269. {
  270. // This code doesn't yet deal with colours which are too close to have their
  271. // differences detected by the human eye (especially when there are spaces).
  272. new
  273. rgb = newCol & 0x00FFFFFF;
  274. // Don't add the colour if there's no change from the last one.
  275. if (rgb == curCol)
  276. {
  277. return 0;
  278. }
  279. if (-0x5 <= ((rgb & 0x0FF) - (curCol & 0xFF)) <= 0x5)
  280. {
  281. if (-0x500 <= ((rgb & 0xFF00) - (curCol & 0xFF00)) <= 0x500)
  282. {
  283. if (-0x50000 <= ((rgb & 0xFF0000) - (curCol & 0xFF0000)) <= 0x50000)
  284. {
  285. // Haven't changed the colour.
  286. return 0;
  287. }
  288. }
  289. }
  290. if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] != e_STYLE_TYPE_DIALOG && pos == 0)
  291. {
  292. gInitialColour = newCol;
  293. // Don't add the colour - this is handled in the text display function.
  294. curCol = rgb;
  295. return 0;
  296. }
  297. // Now try add the string version of the colour.
  298. if (rem < Y_RENDER_SCM_COLOUR_LEN)
  299. {
  300. // Not enough space to add a new colour.
  301. str[pos] = '\0';
  302. return -1;
  303. }
  304. format(str[pos], rem + 1, "{%06x}", rgb);
  305. rem -= Y_RENDER_SCM_COLOUR_LEN;
  306. curCol = newCol;
  307. return Y_RENDER_SCM_COLOUR_LEN;
  308. }
  309. static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <>
  310. {
  311. #pragma unused str, pos, rem
  312. curCol = newCol;
  313. return 0;
  314. }
  315. static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <y_render_show : y_render_show_gt, y_render_show : y_render_show_td>
  316. {
  317. // First get the closest GameText colour for the true colour. I wrote a
  318. // function for this a LONG time ago, finally got around to using it!
  319. new
  320. ot = curCol & 0xFF,
  321. oc = curCol >>> 8;
  322. if (ot == 0 || ot == 'x')
  323. {
  324. // Still near the start, allow some of the special start colours.
  325. newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, oc);
  326. }
  327. else
  328. {
  329. // Can't use the oragey colour used at the start.
  330. newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, 3);
  331. }
  332. new
  333. nt = newCol & 0xFF,
  334. nc = (newCol >>> 8) * 3;
  335. curCol = newCol;
  336. // Compare them.
  337. static
  338. cs_hTags[] = "~x~~h~~h~~h~~h~~h~";
  339. if (nt == ot)
  340. {
  341. ot = nc - (oc * 3);
  342. if (ot == 0)
  343. {
  344. return 0;
  345. }
  346. else if (ot > 0)
  347. {
  348. if (rem >= ot)
  349. {
  350. // Add enough "lighter" tags to change the old colour in to the
  351. // new colour.
  352. str[pos] = '\0';
  353. strcat(str[pos], cs_hTags[sizeof (cs_hTags) - 1 - ot], rem + 1);
  354. rem -= ot;
  355. return ot;
  356. }
  357. else
  358. {
  359. return -1;
  360. }
  361. }
  362. }
  363. if (rem < nc)
  364. {
  365. return -1;
  366. }
  367. // Subtract six from the size : 3 for "%s\0" and 3 for the extra "~x~"
  368. // needed as placeholder for the colour tag (added on the next line).
  369. //format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 6 - nc], str[pos]);
  370. str[pos] = '\0';
  371. strcat(str[pos], cs_hTags[sizeof (cs_hTags) - 4 - nc], rem + 1);
  372. str[pos + 1] = nt;
  373. rem -= nc + 3;
  374. return nc + 3;
  375. }
  376. // str = input and output write array.
  377. // pos = start position of the string to be faded.
  378. // len = total remaining space in the string.
  379. // endColour = target colour.
  380. // gInitialColour = start and current colour.
  381. // step = number of characters for each colour.
  382. // offset = number of characters in the fade not being shown.
  383. static stock Format_AddFade(str[], &pos, &len, endColour, &initialColour, step, offset) //<y_render_display : send_client_message>
  384. {
  385. // Add a fade for a SendClientMessage. This is called if a string is filled
  386. // up during a fade or the end of a fade is reached correctly. In either
  387. // case the current fade will constiture the end of the known current string
  388. // so in actual fact no additionl text after the end of the fade will be
  389. // dropped. This is also where we can save the data to appear in the fade
  390. // on the next line and re-show it.
  391. // Work out how many colours can be inserted at the specified step value
  392. // (i.e. how often a new colour appears) within the length from "pos" to the
  393. // end of "str". This may be more than is required. "len" is from "pos" to
  394. // the end of the string, NOT to the end of the characters requiring the
  395. // fade. The length of the required fade is in "YSI_g_sFadeLength" so that the
  396. // value can be used in the future.
  397. new
  398. parts = (YSI_g_sFadeLength + step - 1) / step + offset,
  399. // We can insert all the colours and their texts in the given space.
  400. // Now we just need to figure out how...
  401. // First get the start and end colours.
  402. start = str[pos + 1] & 0x00FFFFFF; //~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET);
  403. // Remove the start and end colour markers.
  404. strdel(str, pos, pos + 2);
  405. // Find the colour components and component deltas.
  406. endColour &= 0x00FFFFFF; //~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET);
  407. new
  408. red = start >>> 16 & 0xFF,
  409. dred = ((endColour >>> 16 & 0xFF) - red) / parts,
  410. pred = initialColour >>> 16 & 0xFF,
  411. green = start >>> 8 & 0xFF,
  412. dgreen = ((endColour >>> 8 & 0xFF) - green) / parts,
  413. pgreen = initialColour >>> 8 & 0xFF,
  414. blue = start >>> 0 & 0xFF,
  415. dblue = ((endColour >>> 0 & 0xFF) - blue) / parts,
  416. pblue = initialColour >>> 0 & 0xFF;
  417. // Take old strings in to account.
  418. red += dred * offset;
  419. blue += dblue * offset;
  420. green += dgreen * offset;
  421. //strdel(str, pmax, pmax + 2);
  422. //startColour = gInitialColour;
  423. do
  424. {
  425. // Insert the new colour, if it is sufficiently different from the
  426. // existing colour to warrant being added new.
  427. if (-3 <= red - pred <= 3 && -3 <= blue - pblue <= 3 && -3 <= green - pgreen <= 3)
  428. {
  429. pos += step;
  430. }
  431. else
  432. {
  433. new
  434. upd = Format_InsertColour(str, pos, len, initialColour, red << 16 | green << 8 | blue, step);
  435. if (upd == -1)
  436. {
  437. // Didn't quite finish everything. This is the number of
  438. // characters left to process.
  439. return YSI_g_sFadeLength;
  440. }
  441. //initial += step;
  442. pos += step + upd;
  443. pred = red;
  444. pgreen = green;
  445. pblue = blue;
  446. }
  447. YSI_g_sFadeLength -= step;
  448. len -= step;
  449. red = red + dred & 0xFF;
  450. green = green + dgreen & 0xFF;
  451. blue = blue + dblue & 0xFF;
  452. // Could do something with "len" here if it runs out to signify that
  453. // more text needs to go on the next line of output.
  454. }
  455. while (YSI_g_sFadeLength > 0);
  456. // Correct for any excess characters.
  457. pos += YSI_g_sFadeLength;
  458. // This doesn't add the actual destination colour - that is added by virtue
  459. // of the fact that it is actually just a normal colour, so we can use the
  460. // standard colour code (whatever that may be) to add it in a more generic
  461. // way.
  462. return 0;
  463. }
  464. static stock Format_GetKeyString(output[YSI_MAX_STRING], key)
  465. {
  466. output[0] = '\0';
  467. switch (key)
  468. {
  469. case e_PED_ANSWER_PHONE:
  470. output = "~k~~PED_ANSWER_PHONE~";
  471. case e_PED_DUCK:
  472. output = "~k~~PED_DUCK~";
  473. case e_PED_FIREWEAPON:
  474. output = "~k~~PED_FIREWEAPON~";
  475. case e_PED_FIREWEAPON_ALT:
  476. output = "~k~~PED_FIREWEAPON_ALT~";
  477. case e_PED_SPRINT:
  478. output = "~k~~PED_SPRINT~";
  479. case e_VEHICLE_ENTER_EXIT:
  480. output = "~k~~VEHICLE_ENTER_EXIT~";
  481. case e_PED_JUMPING:
  482. output = "~k~~PED_JUMPING~";
  483. case e_PED_LOCK_TARGET:
  484. output = "~k~~PED_LOCK_TARGET~";
  485. case e_PED_LOOKBEHIND:
  486. output = "~k~~PED_LOOKBEHIND~";
  487. case e_SNEAK_ABOUT:
  488. output = "~k~~SNEAK_ABOUT~";
  489. case e_VEHICLE_LOOKLEFT:
  490. output = "~k~~VEHICLE_LOOKLEFT~";
  491. case e_VEHICLE_LOOKRIGHT:
  492. output = "~k~~VEHICLE_LOOKRIGHT~";
  493. case e_GO_FORWARD:
  494. output = "~k~~GO_FORWARD~";
  495. case e_GO_BACK:
  496. output = "~k~~GO_BACK~";
  497. case e_GO_LEFT:
  498. output = "~k~~GO_LEFT~";
  499. case e_GO_RIGHT:
  500. output = "~k~~GO_RIGHT~";
  501. case e_VEHICLE_FIREWEAPON:
  502. output = "~k~~VEHICLE_FIREWEAPON~";
  503. case e_VEHICLE_HORN:
  504. output = "~k~~VEHICLE_HORN~";
  505. case e_VEHICLE_FIREWEAPON_ALT:
  506. output = "~k~~VEHICLE_FIREWEAPON_ALT~";
  507. case e_VEHICLE_ACCELERATE:
  508. output = "~k~~VEHICLE_ACCELERATE~";
  509. case e_VEHICLE_BRAKE:
  510. output = "~k~~VEHICLE_BRAKE~";
  511. case e_VEHICLE_HANDBRAKE:
  512. output = "~k~~VEHICLE_HANDBRAKE~";
  513. case e_VEHICLE_SUBMISSIONS:
  514. output = "~k~~VEHICLE_SUBMISSIONS~";
  515. case e_VEHICLE_LOOKBEHIND:
  516. output = "~k~~VEHICLE_LOOKBEHIND~" ;
  517. case e_VEHICLE_TURRETUP:
  518. output = "~k~~VEHICLE_TURRETUP~";
  519. case e_VEHICLE_TURRETDOWN:
  520. output = "~k~~VEHICLE_TURRETDOWN~";
  521. case e_VEHICLE_TURRETLEFT:
  522. output = "~k~~VEHICLE_TURRETLEFT~";
  523. case e_VEHICLE_TURRETRIGHT:
  524. output = "~k~~VEHICLE_TURRETRIGHT~";
  525. case e_VEHICLE_STEERUP:
  526. output = "~k~~VEHICLE_STEERUP~";
  527. case e_VEHICLE_STEERDOWN:
  528. output = "~k~~VEHICLE_STEERDOWN~";
  529. case e_VEHICLE_STEERLEFT:
  530. output = "~k~~VEHICLE_STEERLEFT~";
  531. case e_VEHICLE_STEERRIGHT:
  532. output = "~k~~VEHICLE_STEERRIGHT~";
  533. }
  534. }
  535. /*-------------------------------------------------------------------------*//**
  536. * <transition keep="true" target="y_render_fade : y_render_fade_fake" />
  537. *//*------------------------------------------------------------------------**/
  538. static stock Format_DoEndFade(output[], &start, end, &rem, colour, &initial) //<>
  539. {
  540. // If "colour" is 0 this is the end of a string before the close colour is
  541. // reached. This fact is enforced by "Y_FORMAT_ALWAYS_SET", which ensures
  542. // that all colours, including black, are not 0 in the string to avoid PAWN
  543. // treating the colour as a NULL terminator or, as here, a no-colour marker.
  544. if (colour)
  545. {
  546. new
  547. offset = 0;
  548. if (YSI_g_sFadeLength)
  549. {
  550. initial = YSI_g_sFadeColour;
  551. offset = end - start - YSI_g_sFadeLength;
  552. //printf("parts: %d, %d, %d", offset, YSI_g_sFadeLength, end - start);
  553. }
  554. else
  555. {
  556. YSI_g_sFadeLength = end - start;
  557. }
  558. // "rem" will hold the number of characters AFTER the fade string on
  559. // entry, this needs fixing here to exclude them as they're being messed
  560. // with.
  561. rem += YSI_g_sFadeLength;
  562. //printf("length: %d", YSI_g_sFadeLength);
  563. // I wrote this code for the case where too much data has been found and
  564. // we needed a fake render to get the full length, but then found that
  565. // exactly the same code was needed for the default case too...
  566. //printf("Format_DoEndFade: %d %d %x %x %d", YSI_g_sFadeLength, /*YSI_g_sFadeLength +*/ rem, colour, initial, start);
  567. // Default step value is 1 and there is currently no way to change it.
  568. new
  569. ret = Format_AddFade(output, start, /*YSI_g_sFadeLength +*/ rem, colour, initial, FORMAT_FADE_STEP, offset);
  570. //printf("Format_DoEndFade: %d %d %x %x %d", YSI_g_sFadeLength, /*YSI_g_sFadeLength +*/ rem, colour, initial, start);
  571. YSI_g_sFadeColour = initial;
  572. return ret;
  573. }
  574. else
  575. {
  576. //printf("colour: %d", YSI_g_sFadeColour);
  577. // Quite simply, we just change state and return to the calling
  578. // function. This allows this function to be called again when the true
  579. // fade end is reached and the length to be determined. After that some
  580. // re-parsing will need to be done I'm afraid, but that will be handled
  581. // by code dealing with fades which fall over the end of a string, be it
  582. // due to this or to a known length string being pushed over the end due
  583. // to the insertion of the colour codes. Note that this code is display
  584. // method independent - it works for SendClientMessage, GameText and
  585. // others.
  586. state y_render_fade : y_render_fade_fake;
  587. // The return here causes remaining code to continue as normal, but
  588. // makes certain functions just not run.
  589. }
  590. return 0;
  591. }
  592. /*-------------------------------------------------------------------------*//**
  593. * <param name="out">The destination string.</param>
  594. * <param name="in">The data to add.</param>
  595. * <param name="oidx">The index in "out" at which to add data.</param>
  596. * <param name="len">The length of "in".</param>
  597. * <param name="orem">Space remaining in "out".</param>
  598. * <param name="fakePos">Like "oidx", but cumulative over line breaks.</param>
  599. * <returns>
  600. * The amount of data from "in" not added to "out".
  601. * </returns>
  602. * <remarks>
  603. * Takes an input string and adds it to an output string. If the input string
  604. * is too long to fit in the remainder of the output string, what has been
  605. * added already (including part of the input string) is displayed and a new
  606. * string is added. Format_TryShow handles this, including adding formatting
  607. * of colour fades, which may involve fake rendering of more of the string to
  608. * determine how much of the remainder of the string needs processing to get
  609. * the right colour. This will also require a method of winding back the state
  610. * to the point just after the initial input string was added to continue on to
  611. * show the next string including newly determined fade data.
  612. * </remarks>
  613. * <transition keep="true" target="y_render_fade : y_render_fade_real" source="y_render_fade : y_render_fade_redo" />
  614. *//*------------------------------------------------------------------------**/
  615. static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_fake>
  616. {
  617. #pragma unused out, in, oidx, orem
  618. fakepos += len;
  619. return 0;
  620. }
  621. static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_redo>
  622. {
  623. new
  624. temp = fakepos + len - YSI_g_sFadeRedoTarget;
  625. if (temp > 0)
  626. {
  627. state y_render_fade : y_render_fade_real;
  628. // This is where the string passes the target point of re-rendering.
  629. new
  630. other = YSI_g_sFadeRedoTarget - fakepos;
  631. fakepos += other;
  632. return Format_DoAddString(out, in[other], oidx, temp, orem, fakepos);
  633. }
  634. else
  635. {
  636. fakepos += len;
  637. return 0;
  638. }
  639. }
  640. static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_real>
  641. {
  642. P:4("Format_DoAddString <y_render_fade : render_real> called: \"%s\", \"%s\", %i, %i, %i, %i", out, in, oidx, len, orem, fakepos);
  643. // For now don't worry about fades over boundaries - they're just too hard
  644. // to get the code working on to start with, maybe later once this is all
  645. // working they can be added in. It is a shame though as it will mean fades
  646. // don't always work. I can cheat slightly though and have the full fade on
  647. // both halves of the break. Or just warn people about fades like that.
  648. //
  649. // NOTE: This code assumes that orem (output remaining) is always 1 less
  650. // than the true value. This avoids awkward calculations when appending the
  651. // NULL terminator to strings. When we run out of space it simply appends
  652. // it regardless of wether it thinks there is space or not.
  653. //
  654. fakepos += len;
  655. if (len <= orem)
  656. {
  657. P:5("Format_DoStringSCM: p0.");
  658. memcpy(out[oidx], in, 0, len * 4, orem);
  659. orem -= len;
  660. oidx += len;
  661. // The whole string fit in - return true.
  662. return 0;
  663. }
  664. else
  665. {
  666. // Not the end of the string, but the end is required.
  667. // Change state to ignore future inputs.
  668. P:5("Format_DoStringSCM: p1.");
  669. // Copy as much data as possible.
  670. memcpy(out[oidx], in, 0, orem * 4, orem);
  671. //orem -= orem;
  672. //oidx += orem;
  673. // Don't need to adjust this further down as all the characters will be
  674. // added before the recursive call.
  675. oidx += orem;
  676. return len - orem;
  677. }
  678. }
  679. /*-------------------------------------------------------------------------*//**
  680. * <transition keep="true" target="y_render_fade : y_render_fade_real" source="y_render_fade : y_render_fade_redo" />
  681. *//*------------------------------------------------------------------------**/
  682. static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_fake>
  683. {
  684. #pragma unused out, in, oidx, orem
  685. ++fakepos;
  686. return true;
  687. }
  688. static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_redo>
  689. {
  690. if (fakepos == YSI_g_sFadeRedoTarget)
  691. {
  692. state y_render_fade : y_render_fade_real;
  693. // This should never actually fail...
  694. if (!orem) return false;
  695. --orem;
  696. out[oidx++] = in;
  697. }
  698. ++fakepos;
  699. return true;
  700. }
  701. static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_real>
  702. {
  703. P:4("Format_DoAddChar: %c %d %d", in, oidx, orem);
  704. if (!orem) return false;
  705. --orem;
  706. out[oidx++] = in;
  707. ++fakepos;
  708. return true;
  709. }
  710. static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_scm>
  711. {
  712. P:2("Format_DoDisplay a: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
  713. SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
  714. //idx = 0;
  715. //out[0] = '\0';
  716. }
  717. static stock Format_DoDisplay(playerid, colour, out[]) <> //y_render_show : y_render_show_print>
  718. {
  719. P:0("Format_DoDisplay b: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
  720. //idx = 0;
  721. //out[0] = '\0';
  722. }
  723. static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_gt>
  724. {
  725. #pragma unused colour
  726. P:2("Format_DoDisplay c: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
  727. GameTextForPlayer(playerid, out, YSI_g_sTempStyle[E_STYLE_DATA_TIME], YSI_g_sTempStyle[E_STYLE_DATA_STYLE]);
  728. //SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
  729. //GameTextForPlayer(playerid, out,
  730. //SendClientMessage(playerid, colour, out);
  731. //idx = 0;
  732. //out[0] = '\0';
  733. }
  734. static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_td>
  735. {
  736. #pragma unused colour
  737. P:2("Format_DoDisplay d: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
  738. new
  739. Text:tmp = TD_Display(out, YSI_g_sTempStyle[E_STYLE_DATA_TD_ID]);
  740. out[0] = _:tmp;
  741. out[1] = '\0';
  742. TD_ShowForPlayer(playerid, tmp);
  743. TD_Garbage(tmp);
  744. // Link these TDs together for future manipulations.
  745. if (YSI_g_sBaseTD == TEXT_DRAW_NO_NEXT)
  746. {
  747. YSI_g_sBaseTD = tmp;
  748. }
  749. else
  750. {
  751. TD_Link(YSI_g_sBaseTD, tmp);
  752. }
  753. //SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
  754. //GameTextForPlayer(playerid, out,
  755. //SendClientMessage(playerid, colour, out);
  756. //idx = 0;
  757. //out[0] = '\0';
  758. }
  759. /*-------------------------------------------------------------------------*//**
  760. * <param name="playerid">Player to show the text to.</param>
  761. * <param name="out">What the text to show is.</param>
  762. *//*------------------------------------------------------------------------**/
  763. stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_scm>
  764. {
  765. SendClientMessage(playerid, gInitialColour, out);
  766. }
  767. stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_print>
  768. {
  769. P:0("Format_DoDisplay: %d, \"%s\"", playerid, out);
  770. }
  771. stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_gt>
  772. {
  773. GameTextForPlayer(playerid, out, YSI_g_sTempStyle[E_STYLE_DATA_TIME], YSI_g_sTempStyle[E_STYLE_DATA_STYLE]);
  774. }
  775. stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_td>
  776. {
  777. TD_ShowForPlayer(playerid, Text:out[0]);
  778. }
  779. /*-------------------------------------------------------------------------*//**
  780. * <returns>
  781. * The basic ID linking all displayed elements together where appropriate (for
  782. * example SendClientMessage has no meaningful ID. 3D texts would, but that's
  783. * not implemented. So do game texts, but that's not implemented either, so
  784. * really it's just text draws.
  785. * </returns>
  786. *//*------------------------------------------------------------------------**/
  787. stock Text_GetLastID() <y_render_show : y_render_show_td>
  788. {
  789. return _:YSI_g_sBaseTD;
  790. }
  791. stock Text_GetLastID() <>
  792. {
  793. return -1;
  794. }
  795. /*-------------------------------------------------------------------------*//**
  796. * Generic function to handle rendering for all types of outputs. Other functions
  797. * such as Format_AddColour are specialised for different text styles. The faster
  798. * way to do this would be to store the characters removed from a string when
  799. * adding in fade data, but this is hard to code. The simpler method is to fake
  800. * re-render the string, having previously determined the length of the string
  801. * which will be faded across. Note that this may mean that some parts of the
  802. * string can get rendered many times, but we can just issue a performance warning
  803. * when the player uses fades which go over a line boundary. That is the only time
  804. * in which it is a problem, more specifically it is only a problem when text in a
  805. * fade goes over a line boundardy before the end fade marker has been reached.
  806. * <transition keep="true" target="y_render_fade : y_render_fade_redo" />
  807. * <transition keep="true" target="y_render_fade : y_render_fade_real" />
  808. * <transition keep="true" target="y_render_fade : y_render_fade_fake" />
  809. *//*------------------------------------------------------------------------**/
  810. //stock Format_Render(pid, Language:l, output[], maxlen, idx, target, string[], {Float,_}:...)
  811. stock Format_Render(pid, Language:l, output[], maxlen, idx, target, string[], argCount, GLOBAL_TAG_TYPES:...)
  812. {
  813. P:3("Format_Render called: %i, %i, %s, %i, %i, %i, %s (+%i)", pid, _:l, output, maxlen, idx, target, argCount, numargs() - 8);
  814. gInitialColour = (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF;
  815. new
  816. colour = gInitialColour;
  817. YSI_g_sFadeLength = 0;
  818. YSI_g_sBaseTD = TEXT_DRAW_NO_NEXT;
  819. // Now the (mostly) tail-recursive function call.
  820. Format_Render_start:
  821. static
  822. scFormats[][8] =
  823. {
  824. "%*.*d", // 6 (6)
  825. "%-*.*d", // 7 (13)
  826. "%0*.*d", // 7 (20)
  827. "%0-*.*d" // 8 (28)
  828. },
  829. scSpecifier[8],
  830. // =====================================================================
  831. // UPDATE Y_RENDER_FIX_NEGATIVE MACRO ON CHANGE!!!!!!!
  832. ts[144],
  833. // Max handleable input string length is 128 (hopefully sufficient).
  834. // =====================================================================
  835. func[32],
  836. scNewLineString[] = "~n~",
  837. scDialogLineString[] = "\r\n";
  838. new
  839. ch,
  840. llen = maxlen,
  841. //output[128], // Always 128.
  842. p = 0,
  843. curArg = 8, // Account for additionaly pushed arguments.
  844. numArgs = numargs() + argCount,
  845. //llen = sizeof (output) - 1,
  846. arg,
  847. none = (target & e_FORMAT_FLAGS_NONE),
  848. onlyOne = (target & e_FORMAT_FLAGS_ONE) | none | _:YSI_g_sJustOne,
  849. bool:fade = false,
  850. bool:nlInFade = false,
  851. // flags:
  852. // 1 = Just one output.
  853. // 2 = Newline found in fade.
  854. // 4 = In a fade.
  855. //flags = (target & e_FORMAT_FLAGS_ONE) ? 1 : 0,
  856. fakePos = 0,
  857. // Was only "one" string display used and is this not per-player text?
  858. one = 0,
  859. // Start location of the current fade.
  860. fadeStart,
  861. fadeStartIdx;//,
  862. //fadeStartText;
  863. //#emit LOAD.S.pri string
  864. //#emit STOR.S.pri fadeStartText
  865. if (target & e_FORMAT_FLAGS_REDO)
  866. {
  867. // We need to skip data, ignore everything before "target1".
  868. state y_render_fade : y_render_fade_redo;
  869. }
  870. else
  871. {
  872. state y_render_fade : y_render_fade_real;
  873. }
  874. target &= e_FORMAT_FLAGS_INDEX;
  875. /*new
  876. fadeCurArg,
  877. fadeArg,
  878. fadeIdx;*/
  879. if ((YSI_g_sFadeRedoTarget = target))
  880. {
  881. YSI_g_sFadeRedoTarget &= ~Y_FORMAT_ALWAYS_SET;
  882. state y_render_fade : y_render_fade_redo;
  883. }
  884. else
  885. {
  886. state y_render_fade : y_render_fade_real;
  887. }
  888. /*ch = string[idx];
  889. if (ch > 0)
  890. {
  891. // Copy strings.
  892. ++idx;
  893. Y_RENDER_ADD_EX(string, idx, ch - idx)
  894. idx = ch;
  895. }*/
  896. while ((ch = string[idx++]))
  897. {
  898. // TODO: Add {*} and #* format for variable colours.
  899. switch (ch)
  900. {
  901. case '\01':
  902. {
  903. // Null.
  904. break;
  905. }
  906. case '\02':
  907. {
  908. P:6("Text_Render: Format specifier %d", curArg);
  909. if (curArg == numArgs)
  910. {
  911. // Skip.
  912. P:W("Insufficient parameters to YSI format.");
  913. ts = "(null)";
  914. Y_RENDER_ADD(ts)
  915. continue;
  916. }
  917. // Format.
  918. ch = string[idx++];
  919. new
  920. width = (ch & _:e_COMPRESS_FORMAT_DATA_WIDTH),
  921. prec = (ch & _:e_COMPRESS_FORMAT_DATA_PREC) >>> 12;
  922. // Get the true values of the various data bits.
  923. if (width == 0x0800)
  924. {
  925. width = getarg(curArg++);
  926. }
  927. if (prec == 0x0800)
  928. {
  929. prec = getarg(curArg++);
  930. }
  931. else if (prec == 0x0FFF)
  932. {
  933. prec = -1;
  934. }
  935. // Output the correct data type.
  936. switch (ch & 0xF0000000)
  937. {
  938. case e_COMPRESS_FORMAT_DATA_DEC:
  939. {
  940. P:6("Text_Render: Add d");
  941. scSpecifier = Y_RENDER_SPECIFIER(d);
  942. Y_RENDER_ARG
  943. {
  944. //p += Format_AddInt(output[p], llen, arg, width, ch);
  945. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  946. Y_RENDER_ADD(ts)
  947. }
  948. }
  949. case e_COMPRESS_FORMAT_DATA_HEX:
  950. {
  951. // This completely fixes (I hope) the problems with
  952. // displaying negative numbers as %h/%x numbers.
  953. P:6("Text_Render: Add h");
  954. scSpecifier = Y_RENDER_SPECIFIER(x);
  955. Y_RENDER_ARG
  956. {
  957. if (arg & 0x80000000)
  958. {
  959. Y_RENDER_FIX_NEGATIVE(x:8);
  960. }
  961. else
  962. {
  963. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  964. }
  965. Y_RENDER_ADD(ts)
  966. }
  967. }
  968. case e_COMPRESS_FORMAT_DATA_BIN:
  969. {
  970. P:6("Text_Render: Add b");
  971. scSpecifier = Y_RENDER_SPECIFIER(b);
  972. Y_RENDER_ARG
  973. {
  974. if (arg & 0x80000000)
  975. {
  976. Y_RENDER_FIX_NEGATIVE(b:32);
  977. }
  978. else
  979. {
  980. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  981. }
  982. Y_RENDER_ADD(ts)
  983. }
  984. }
  985. case e_COMPRESS_FORMAT_DATA_CHAR:
  986. {
  987. scSpecifier = Y_RENDER_SPECIFIER(c);
  988. Y_RENDER_ARG
  989. {
  990. //p += Format_AddInt(output[p], llen, arg, width, ch);
  991. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  992. Y_RENDER_ADD(ts)
  993. }
  994. }
  995. case e_COMPRESS_FORMAT_DATA_FLOAT:
  996. {
  997. scSpecifier = Y_RENDER_SPECIFIER(f);
  998. Y_RENDER_ARG
  999. {
  1000. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1001. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  1002. Y_RENDER_ADD(ts)
  1003. }
  1004. }
  1005. case e_COMPRESS_FORMAT_DATA_IEEE:
  1006. {
  1007. Y_RENDER_ARG
  1008. {
  1009. if ((arg & 0x7F800000) == 0x7F800000)
  1010. {
  1011. scSpecifier = Y_RENDER_SPECIFIER(s);
  1012. // One of the special numbers.
  1013. if (arg & 0x007FFFFF)
  1014. {
  1015. // NAN.
  1016. if (arg & 0x00400000)
  1017. {
  1018. // QNAN
  1019. format(ts, sizeof (ts), scSpecifier, width, cellmax, "QNAN");
  1020. Y_RENDER_ADD(ts)
  1021. }
  1022. else
  1023. {
  1024. // SNAN
  1025. format(ts, sizeof (ts), scSpecifier, width, cellmax, "SNAN");
  1026. Y_RENDER_ADD(ts)
  1027. }
  1028. }
  1029. else
  1030. {
  1031. if (arg & 0x80000000)
  1032. {
  1033. // -INFINITY
  1034. format(ts, sizeof (ts), scSpecifier, width, cellmax, "-INFINITY");
  1035. Y_RENDER_ADD(ts)
  1036. }
  1037. else
  1038. {
  1039. // INFINITY
  1040. format(ts, sizeof (ts), scSpecifier, width, cellmax, "INFINITY");
  1041. Y_RENDER_ADD(ts)
  1042. }
  1043. }
  1044. }
  1045. else
  1046. {
  1047. scSpecifier = Y_RENDER_SPECIFIER(f);
  1048. format(ts, sizeof (ts), scSpecifier, width, prec, arg);
  1049. Y_RENDER_ADD(ts)
  1050. }
  1051. }
  1052. }
  1053. case e_COMPRESS_FORMAT_DATA_STRING:
  1054. {
  1055. scSpecifier = Y_RENDER_SPECIFIER(s);
  1056. if (ch & _:e_COMPRESS_FORMAT_DATA_FUNC)
  1057. {
  1058. func = "@yR_";
  1059. // Get the function name.
  1060. for (new _k = 4; _k != 32; ++_k)
  1061. {
  1062. if (!(func[_k] = getarg(curArg, _k - 4)))
  1063. {
  1064. break;
  1065. }
  1066. }
  1067. if (funcidx(func) == -1)
  1068. {
  1069. // Normal version. This is ended by a null.
  1070. // Other functions get the count in advance when
  1071. // an index of -1 is passed.
  1072. func[2] = 'r';
  1073. // This code mimicks much of the internal
  1074. // y_master code because wrapping this in a
  1075. // macro is a) pointless and b) hard. This code
  1076. // is ALWAYS like this because of the nature of
  1077. // it.
  1078. new
  1079. lst = setproperty(8, YSIM_CALLER),
  1080. _j = 0;
  1081. setproperty(8, YSIM_CALLER, _@);
  1082. for ( ; ; )
  1083. {
  1084. CallRemoteFunction(func, "ii", _:l, _j);
  1085. // Resolve the string.
  1086. getproperty(8, "", YSIM_STRING, Q@);
  1087. strunpack(Q@, Q@);
  1088. if (Q@[0])
  1089. {
  1090. if (_j)
  1091. {
  1092. // Separate the strings - hard coded
  1093. // list format currently I'm afraid.
  1094. //ts = ", ";
  1095. //Y_RENDER_ADD(ts)
  1096. Y_RENDER_ADD(YSI_g_sListSep)
  1097. }
  1098. format(ts, sizeof (ts), scSpecifier, width, prec, Q@);
  1099. Y_RENDER_ADD(ts)
  1100. }
  1101. else
  1102. {
  1103. break;
  1104. }
  1105. ++_j;
  1106. }
  1107. setproperty(8, YSIM_CALLER, lst);
  1108. }
  1109. else
  1110. {
  1111. // Player specific version.
  1112. // Normal version. This is ended by a null.
  1113. // Other functions get the count in advance when
  1114. // an index of -1 is passed.
  1115. //func[2] = 'r';
  1116. // This code mimicks much of the internal
  1117. // y_master code because wrapping this in a
  1118. // macro is a) pointless and b) hard. This code
  1119. // is ALWAYS like this because of the nature of
  1120. // it.
  1121. new
  1122. lst = setproperty(8, YSIM_CALLER),
  1123. _j = 0;
  1124. setproperty(8, YSIM_CALLER, _@);
  1125. for ( ; ; )
  1126. {
  1127. CallRemoteFunction(func, "iii", pid, _:l, _j);
  1128. // Resolve the string.
  1129. getproperty(8, "", YSIM_STRING, Q@);
  1130. strunpack(Q@, Q@);
  1131. if (Q@[0])
  1132. {
  1133. if (_j)
  1134. {
  1135. // Separate the strings - hard coded
  1136. // list format currently I'm afraid.
  1137. //ts = ", ";
  1138. //Y_RENDER_ADD(ts)
  1139. Y_RENDER_ADD(YSI_g_sListSep)
  1140. }
  1141. // Could do with configuring this to not
  1142. // need to call "Y_RENDER_SPECIFIER" every
  1143. // time.
  1144. format(ts, sizeof (ts), scSpecifier, width, prec, Q@);
  1145. Y_RENDER_ADD(ts)
  1146. }
  1147. else
  1148. {
  1149. break;
  1150. }
  1151. ++_j;
  1152. }
  1153. setproperty(8, YSIM_CALLER, lst);
  1154. // Force the string to be rebuilt every time.
  1155. ++one;
  1156. }
  1157. }
  1158. else
  1159. {
  1160. // Single parameter. Can do this FAR better by just
  1161. // using #emit to re-push the parameter directly.
  1162. for (new _k = 0; _k != sizeof (ts); ++_k)
  1163. {
  1164. if (!(ts[_k] = getarg(curArg, _k)))
  1165. {
  1166. break;
  1167. }
  1168. }
  1169. format(ts, sizeof (ts), scSpecifier, width, prec, ts);
  1170. Y_RENDER_ADD(ts)
  1171. }
  1172. ++curArg;
  1173. }
  1174. /*case e_COMPRESS_FORMAT_DATA_OCT:
  1175. {
  1176. Y_RENDER_ARG
  1177. {
  1178. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1179. //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
  1180. ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
  1181. Y_RENDER_ADD(ts)
  1182. }
  1183. }*/
  1184. case e_COMPRESS_FORMAT_DATA_COMM:
  1185. {
  1186. scSpecifier = Y_RENDER_SPECIFIER(s);
  1187. // Show a command.
  1188. /*for(new _i=0,_b=4;_i!=2;++_i)
  1189. if(_i==0)
  1190. {
  1191. if(ch&_:e_COMPRESS_FORMAT_DATA_FUNC)
  1192. {
  1193. _b=1,func="@yR_";
  1194. for(new _k=4;_k!=32;++_k)
  1195. if(!(func[_k]=getarg(curArg,_k-4)))
  1196. break;
  1197. if(funcidx(func)==-1)func[2]='r',_b=2;
  1198. }
  1199. else if(ch&_:e_COMPRESS_FORMAT_DATA_LIST)
  1200. _b=3;
  1201. }
  1202. else
  1203. for(new _j=0;(arg=_b==1?W@(func,"iii",pid,(_:l),_j):_b==2?W@(func,"ii",(_:l),_j):_b==3?getarg(curArg,_j++):getarg(curArg)),(_j!=-1&&_b)?TRUE:++curArg&&FALSE;_b=_b==4?0:_b)*/
  1204. Y_RENDER_ARG
  1205. {
  1206. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1207. //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
  1208. // "arg" has the ID of the command, not the NAME of
  1209. // the command which may change for different people
  1210. // (need to find a way to return a single name for a
  1211. // player which gets to the specified command).
  1212. #if defined _inc_y_commands
  1213. strcpy(ts, Command_GetDisplay(arg, pid));
  1214. if (ts[0])
  1215. {
  1216. format(ts, sizeof (ts), scSpecifier, width, prec, ts);
  1217. Y_RENDER_ADD(ts)
  1218. }
  1219. #endif
  1220. //ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
  1221. //Y_RENDER_ADD(ts)
  1222. }
  1223. }
  1224. /*case e_COMPRESS_FORMAT_DATA_SUFFIX:
  1225. {
  1226. scSpecifier = Y_RENDER_SPECIFIER(s);
  1227. // TODO: Add language to this.
  1228. //p += Format_AddSuffix(output[p], llen, getarg(curArg++), l);
  1229. Y_RENDER_ARG
  1230. {
  1231. format(ts, sizeof (ts), scSpecifier, width, cellmax, Format_AddSuffix(arg, l));
  1232. Y_RENDER_ADD(ts)
  1233. }
  1234. }
  1235. case e_COMPRESS_FORMAT_DATA_UNSIGNED:
  1236. {
  1237. if (prec < 0) prec = 10;
  1238. Y_RENDER_ARG
  1239. {
  1240. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1241. //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
  1242. //ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
  1243. ts[Format_AddNum(ts, sizeof (ts) - 1, arg, width, ch, prec, false)] = '\0';
  1244. Y_RENDER_ADD(ts)
  1245. }
  1246. }
  1247. case e_COMPRESS_FORMAT_DATA_SIGNED:
  1248. {
  1249. if (prec < 0) prec = 10;
  1250. Y_RENDER_ARG
  1251. {
  1252. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1253. //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
  1254. ts[Format_AddNum(ts, sizeof (ts) - 1, arg, width, ch, prec, true)] = '\0';
  1255. Y_RENDER_ADD(ts)
  1256. }
  1257. }*/
  1258. case e_COMPRESS_FORMAT_DATA_PLAYER:
  1259. {
  1260. Y_RENDER_ARG
  1261. {
  1262. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1263. GetPlayerName(arg, ts, sizeof (ts));
  1264. format(ts, sizeof (ts), scSpecifier, width, prec, ts);
  1265. Y_RENDER_ADD(ts)
  1266. }
  1267. }
  1268. case e_COMPRESS_FORMAT_DATA_LOGICAL:
  1269. {
  1270. scSpecifier = Y_RENDER_SPECIFIER(s);
  1271. Y_RENDER_ARG
  1272. {
  1273. //p += Format_AddInt(output[p], llen, arg, width, ch);
  1274. format(ts, sizeof (ts), scSpecifier, width, prec, arg ? ("true") : ("false"));
  1275. Y_RENDER_ADD(ts)
  1276. }
  1277. }
  1278. case e_COMPRESS_FORMAT_DATA_CUSTOM:
  1279. {
  1280. // Get the function we will be calling to do the format.
  1281. // Slice caches these, but we don't because of the
  1282. // extended versions (%k<DATE>) etc.
  1283. new
  1284. ffake[4 char],
  1285. fidx;
  1286. ffake[0] = string[idx];
  1287. if (ffake{1} == '@')
  1288. {
  1289. if (!AMX_GetPublicPointer(0, fidx, ffake))
  1290. {
  1291. continue;
  1292. }
  1293. ++idx;
  1294. }
  1295. else
  1296. {
  1297. static
  1298. sFunc2[32] = "F";
  1299. strunpack(sFunc2[1], string[idx], sizeof (sFunc2) - 1);
  1300. // Limit the function name to the function length.
  1301. sFunc2[sFunc2[1]] = '\0';
  1302. idx += ceildiv(sFunc2[1], 4);
  1303. sFunc2[1] = '@';
  1304. if (!AMX_GetPublicPointer(0, fidx, sFunc2))
  1305. {
  1306. continue;
  1307. }
  1308. }
  1309. //
  1310. // "b":
  1311. //
  1312. // "b" is the source type. "1" = function, "2" = per-
  1313. // player function, "3" = list, "4" = variable. "0" is
  1314. // a special case meaning "processed variable" and tells
  1315. // the system to stop "j != -1 && b".
  1316. //
  1317. // "i":
  1318. //
  1319. // "i" is the current processing stage - there are two.
  1320. // The first looks at all the arguments and collects the
  1321. // function or list data (if any). The second loops
  1322. // over all the passed arguments and does the format.
  1323. // This is where the "b" check comes in, to only do that
  1324. // inner loop once. It is done this way simply to allow
  1325. // us to use braces around the code to do the format.
  1326. //
  1327. // "j":
  1328. //
  1329. // "j" is the main loop variable for the inner loop and
  1330. // tracks which parameter part we are currently doing in
  1331. // the case of function or list inputs.
  1332. //
  1333. for (new i, j, b = 4; i != 2; ++i)
  1334. {
  1335. if (!i)
  1336. {
  1337. if (ch & _:e_COMPRESS_FORMAT_DATA_FUNC)
  1338. {
  1339. b = 1;
  1340. func = "@yR_";
  1341. va_getstring(func[4], curArg);
  1342. if (funcidx(func) == -1)
  1343. {
  1344. b = 2;
  1345. func[2] = 'r';
  1346. }
  1347. }
  1348. else if (ch & _:e_COMPRESS_FORMAT_DATA_LIST)
  1349. {
  1350. b = 3;
  1351. }
  1352. ch &= FORMAT_FLAG_LEFT | FORMAT_FLAG_ZERO;
  1353. }
  1354. else
  1355. {
  1356. for (;
  1357. // These lines ALWAYS get run because
  1358. // they come before a comma in the "for"
  1359. // conditional, but their result is
  1360. // ignored.
  1361. (arg = (b == 1)
  1362. ? W@(func, "iii", pid, (_:l), j)
  1363. : (b == 2)
  1364. ? W@(func, "ii", (_:l), j)
  1365. : (b == 3)
  1366. ? getarg(curArg, j++)
  1367. : getarg(curArg)
  1368. ),
  1369. // This is the true condition. If the
  1370. // first half fails then "curArg" is
  1371. // incremented and the whole check
  1372. // fails, otherwise, thanks to short-
  1373. // circuiting, "curArg" is NOT
  1374. // incremented.
  1375. (arg != cellmin && b) || (++curArg & 0);
  1376. // Only run the loop once when "b = 4".
  1377. b &= ~4, ++j
  1378. )
  1379. {
  1380. // Standard format code goes here.
  1381. #emit PUSH.S prec
  1382. #emit PUSH.S width
  1383. #emit PUSH.S ch
  1384. // Get the source (assume constant for now,
  1385. // i.e. no functions or lists yet).
  1386. #emit PUSH.S arg
  1387. // Get a string if there is one.
  1388. if (b == 1 || b == 2)
  1389. {
  1390. getproperty(8, "", YSIM_STRING, Q@);
  1391. strunpack(Q@, Q@);
  1392. if (isnull(Q@))
  1393. {
  1394. ++curArg;
  1395. // Fix the stack.
  1396. #emit POP.pri
  1397. #emit POP.pri
  1398. #emit POP.pri
  1399. #emit POP.pri
  1400. break;
  1401. }
  1402. #emit PUSH.C Q@
  1403. }
  1404. else
  1405. {
  1406. #emit LCTRL 5
  1407. #emit LOAD.S.alt curArg
  1408. #emit SHL.C.alt 2
  1409. #emit ADD
  1410. #emit LOAD.I
  1411. #emit PUSH.pri
  1412. }
  1413. #emit PUSH.C ts
  1414. // Far more parameters that Slice's.
  1415. #emit PUSH.C 24 // 4 * 6.
  1416. // This code is almost common now!
  1417. #emit LCTRL 6
  1418. #emit ADD.C 28
  1419. #emit PUSH.pri
  1420. #emit LOAD.S.pri fidx
  1421. #emit SCTRL 6
  1422. // Now we have returned from the custom
  1423. // function.
  1424. Y_RENDER_ADD(ts)
  1425. }
  1426. }
  1427. }
  1428. }
  1429. /*case e_COMPRESS_FORMAT_DATA_DATE:
  1430. {
  1431. // Hard one - needs more interaction.
  1432. }*/
  1433. }
  1434. }
  1435. case '\03', -1:
  1436. {
  1437. P:6("Text_Render: Colour %d %d %d %d %d %06x %s", p, llen, fadeStart, fakePos, idx, colour & 0xFFFFFF, string);
  1438. if (fade) //flags & 4)
  1439. {
  1440. p = fadeStart;
  1441. new
  1442. rem = Format_DoEndFade(output, p, fakePos, llen, string[idx], colour);
  1443. if (rem || nlInFade) //(flags & 2))
  1444. {
  1445. // "rem" is the number of characters not processed.
  1446. YSI_g_sFadeColour = colour;
  1447. Y_RENDER_DO_DISPLAY()
  1448. P:6("Format_Render: one stage: \"%s\"", output);
  1449. // Subtract 2 to get the index in to the fade where the
  1450. // letters start. This is not as easy as it used to be
  1451. // as we need to manipulate the stack to push the extra
  1452. // parameters somehow. Now changed to a fake tail-
  1453. // recursive call so that we don't need to worry about
  1454. // the stack. This also explains why labels generate
  1455. // extra stack manipulation code (to reset locals).
  1456. //return Format_Render(pid, l, output, maxlen, fadeStartIdx, fakePos - fadeStart - rem | e_FORMAT_FLAGS_REDO, string);
  1457. //#emit LOAD.S.pri fadeStartText
  1458. //#emit STOR.S.pri string
  1459. idx = fadeStartIdx;
  1460. target = (fakePos - fadeStart - rem) | e_FORMAT_FLAGS_REDO;
  1461. gInitialColour = colour;
  1462. //YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] = (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0xF000000F) | (gInitialColour << 4);
  1463. goto Format_Render_start;
  1464. // We don't need these as they are only set when you
  1465. // want less than 2 displays, and as to get to this
  1466. // point you need to have shown at least noe item there
  1467. // is no possible way they can be set the second time.
  1468. //| (onlyOne ? e_FORMAT_FLAGS_ONE : 0) | (none ? e_FORMAT_FLAGS_NONE : 0);
  1469. }
  1470. //flags &= ~4;
  1471. fade = false;
  1472. fakePos += p - fadeStart;
  1473. }
  1474. if (string[idx] & Y_FORMAT_CLOSE_CURR)
  1475. {
  1476. // Get the initial display colour.
  1477. //string[idx] |= (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF;
  1478. string[idx] = (string[idx] & 0xFF000000) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF);
  1479. }
  1480. if (string[idx] & Y_FORMAT_START_FADE)
  1481. {
  1482. //flags |= 4;
  1483. fade = true;
  1484. fadeStart = p;
  1485. fadeStartIdx = idx - 1;
  1486. string[fadeStartIdx] = -1;
  1487. //#emit LOAD.S.pri string
  1488. //#emit STOR.S.pri fadeStartText
  1489. if (p < maxlen - 1)
  1490. {
  1491. output[p++] = '\03';
  1492. output[p++] = string[idx++];
  1493. }
  1494. }
  1495. else
  1496. {
  1497. // Just add the colour here normally.
  1498. arg = Format_AddColour(output, p, llen, colour, string[idx++]); //& ~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET));
  1499. switch (arg)
  1500. {
  1501. case -1:
  1502. {
  1503. Y_RENDER_DO_DISPLAY()
  1504. }
  1505. case 0:
  1506. {
  1507. // Do nothing.
  1508. }
  1509. default:
  1510. {
  1511. p += arg;
  1512. fakePos += arg;
  1513. }
  1514. }
  1515. /*else
  1516. {
  1517. p += arg;
  1518. }
  1519. currentColour = string[idx++];
  1520. if (maxlen - pos > Y_RENDER_SCM_COLOUR_LEN)
  1521. {
  1522. format(output[pos], maxlen - pos, "{%06x}", currentColour & ~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET));
  1523. pos += Y_RENDER_SCM_COLOUR_LEN;
  1524. }
  1525. else
  1526. {
  1527. output[pos] = '\0';
  1528. printf("some stage: \"%s\"", output);
  1529. output[0] = '\0';
  1530. pos = 0;
  1531. }*/
  1532. //++idx;
  1533. }
  1534. }
  1535. case '\04':
  1536. {
  1537. P:6("Text_Render: Key");
  1538. Format_GetKeyString(ts, string[idx++] >>> 8);
  1539. new __len=strlen(ts);
  1540. if (llen < __len)
  1541. Y_RENDER_DO_DISPLAY()
  1542. llen -= __len,
  1543. output[p] = '\0',
  1544. p += __len,
  1545. strcat(output, ts, maxlen);
  1546. }
  1547. case '\05':
  1548. {
  1549. // String extension.
  1550. P:6("Text_Render: Extension %d %d %d", YSI_g_sTempMaster, string[idx], string[idx - 1]);
  1551. // TODO!
  1552. // This should change the current input to a new one. May
  1553. // require some more advanced hacking to support fades over
  1554. // these boundaries (or just ban them)... Actually, I don't
  1555. // think it will require extra work...
  1556. // Just use the text directly.
  1557. idx = _Text_GetPointer(YSI_g_sTempMaster, string[idx]);
  1558. #emit LOAD.S.pri idx
  1559. #emit STOR.S.pri string
  1560. idx = 0;
  1561. }
  1562. case '\n':
  1563. {
  1564. P:6("Text_Render: NL");
  1565. // Check for 2 character new lines (\n\r).
  1566. if (string[idx] == '\r') ++idx;
  1567. // Output the last string.
  1568. if (fade) //flags & 4)
  1569. {
  1570. //flags |= 2;
  1571. nlInFade = true;
  1572. state y_render_fade : y_render_fade_fake;
  1573. }
  1574. else if ((YSI_g_sTempStyle[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) < e_STYLE_TYPE_CLIENT)
  1575. {
  1576. // This works even for GTs which are always 0 by this point.
  1577. Y_RENDER_ADD(scNewLineString)
  1578. }
  1579. else if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] == e_STYLE_TYPE_DIALOG)
  1580. {
  1581. //printf("NL 1");
  1582. // This works even for GTs which are always 0 by this point.
  1583. Y_RENDER_ADD(scDialogLineString)
  1584. //printf("NL 2");
  1585. }
  1586. else
  1587. {
  1588. Y_RENDER_DO_DISPLAY()
  1589. gInitialColour = colour;
  1590. }
  1591. }
  1592. case '\r':
  1593. {
  1594. P:6("Text_Render: NL");
  1595. // Check for 2 character new lines (\r\n).
  1596. if (string[idx] == '\n') ++idx;
  1597. // Output the last string.
  1598. if (fade) //flags & 4)
  1599. {
  1600. //flags |= 2;
  1601. nlInFade = true;
  1602. state y_render_fade : y_render_fade_fake;
  1603. }
  1604. else if ((YSI_g_sTempStyle[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) < e_STYLE_TYPE_CLIENT)
  1605. {
  1606. // This works even for GTs which are always 0 by this point.
  1607. Y_RENDER_ADD(scNewLineString)
  1608. }
  1609. else if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] == e_STYLE_TYPE_DIALOG)
  1610. {
  1611. // This works even for GTs which are always 0 by this point.
  1612. //printf("NL 3");
  1613. Y_RENDER_ADD(scDialogLineString)
  1614. //printf("NL 4");
  1615. }
  1616. else
  1617. {
  1618. Y_RENDER_DO_DISPLAY()
  1619. }
  1620. }
  1621. case '\t':
  1622. {
  1623. // Omit this on dialogs.
  1624. if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] != e_STYLE_TYPE_DIALOG)
  1625. {
  1626. // Somehow display a tab. Maybe keep track of characters
  1627. // displayed and show "n % 4" spaces.
  1628. arg = 4 - (p & 0x03); // The number of spaces to add.
  1629. static
  1630. sTabs[] = " ";
  1631. for (new __added; (__added = Format_DoAddString(output, sTabs[4 - arg], p, arg, llen, fakePos)); arg -= __added)
  1632. {
  1633. if (fade) //flags & 4)
  1634. {
  1635. state y_render_fade : y_render_fade_fake;
  1636. }
  1637. else
  1638. {
  1639. Y_RENDER_DO_DISPLAY()
  1640. }
  1641. }
  1642. }
  1643. else
  1644. {
  1645. Y_RENDER_CHAR(ch)
  1646. }
  1647. }
  1648. case '\06' .. '\08', '\11', '\12', '\14' .. '\32':
  1649. {
  1650. // Whitespace. Just show a space, not the fancy character, no
  1651. // idea what it could do. Note that this range includes spaces.
  1652. P:6("Text_Render: Space");
  1653. Y_RENDER_CHAR(' ')
  1654. }
  1655. default:
  1656. {
  1657. P:6("Text_Render: Char");
  1658. Y_RENDER_CHAR(ch)
  1659. }
  1660. }
  1661. /*if (!(ch = string[idx]))
  1662. {
  1663. break;
  1664. }
  1665. // Copy strings.
  1666. ++idx;
  1667. Y_RENDER_ADD_EX(string, idx, ch - idx)
  1668. idx = ch;*/
  1669. P:6("Text_Render: Loop: p = %d, llen = %d, output = \"%s\"", p, llen, (output[p] = '\0', output));
  1670. }
  1671. P:5("Text_Render: Final render?");
  1672. if (p)
  1673. {
  1674. P:5("Text_Render: Yes!");
  1675. output[p] = '\0';
  1676. if (!none) Format_DoDisplay(pid, gInitialColour, output);
  1677. ++one;
  1678. }
  1679. P:5("Text_Render: p = %d, output = \"%s\"", p, output);
  1680. P:C(idx=0;while ((ch = output[idx++]))printf("%04x%04x = %c", ch >>> 16, ch & 0xFFFF, ch););
  1681. P:5("Text_Render end");
  1682. return one;
  1683. }