| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714 |
- /*----------------------------------------------------------------------------*\
- =================================
- y_textrender - Show text.
- =================================
- Description:
- Part of the y_text system. Handles formatting loaded text in the correct
- manner for display in the currently selected style.
- Legal:
- Version: MPL 1.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is the YSI utils include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
-
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
-
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
-
- Version:
- 0.1
- Changelog:
- 25/02/12:
- First version.
- Functions:
- Stock:
- -
- Inline:
- -
- Variables:
- Global:
- -
- \*----------------------------------------------------------------------------*/
- #include "..\y_utils"
- #include "..\y_colours"
- #include "..\y_debug"
- //#include "..\y_ini"
- #include "y_shortfunc"
- #include "y_natives"
- #include "..\y_va"
- #if !defined FORMAT_FADE_STEP
- #define FORMAT_FADE_STEP 2
- #endif
- #define Y_RENDER_SCM_COLOUR_LEN (8)
- //#define Y_RENDER_ONE_ARG
- // if ((arg = getarg(curArg++) || TRUE))
- // Loops through all possible arguments in lists, functions and singles. See
- // "case e_COMPRESS_FORMAT_DATA_CUSTOM:" for more details (an expanded macro
- // version can be found there).
- #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)
- // Make the correct specifier string for the data stored in the compressed
- // specifier data.
- #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])))
- // This makes hex and binary format specifiers display correctly with negative
- // numbers in all cases (e.g. %5x etc).
- #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,130,"%"#%0"%0-*"#%0,arg>>>32/%1,width-(%1-1),arg&(1<<32/%1)-1):format(ts,130,"%"#%0"%-*"#%0,arg>>>32/%1,width-(%1-1),arg&(1<<32/%1)-1)):(ch&_:e_COMPRESS_FORMAT_DATA_ZERO)?format(ts,130,"%0*"#%0"%"#%0,width-1,arg>>>32/%1,arg&(1<<32/%1)-1):format(ts,130,"%*"#%0"%"#%0,width-1,arg>>>32/%1,arg&(1<<32/%1)-1);else format(ts,130,"%"#%0"%"#%0,arg>>>32/%1,arg&(1<<32/%1)-1)
- // Try add a string to the current output. This needs modifying to reset the
- // whole function after a string is displayed. "onlyOne" is set in the case
- // where any line excess is cut off (e.g. in marquees).
- //#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);}
- #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;}
- #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()}
- //#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()}
- #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()}
- // Helper macros to determine what a character is. This could be modified to
- // take in to account unicode letters, but that's hard. I don't know enough
- // about unicode, and frankly there are WAY too many characters to be listed
- // here. If other people want to modify this to support their language then
- // good on them.
- #define Y_TEXT_LETTER(%0) ('a'<=(%0)<='z'||'A'<=(%0)<='Z')
- #define Y_TEXT_NUMBER(%0) ('0'<=(%0)<='9')
- #define Y_RENDER_SCM_COLOUR_LEN (8)
- #define e_FORMAT_FLAGS_INDEX (0x00FFFFFF)
- #define e_FORMAT_FLAGS_REDO (0x01000000)
- #define e_FORMAT_FLAGS_ONE (0x02000000)
- #define e_FORMAT_FLAGS_NONE (0x04000000)
- static stock
- YSI_g_sFadeRedoTarget,
- YSI_g_sFadeLength,
- YSI_g_sFadeColour,
- bool:YSI_g_sJustOne,
- YSI_g_sTempStyle[E_STYLE_DATA],
- YSI_g_sTemp3D[E_3D_DATA],
- YSI_g_sTempMaster,
- Text:YSI_g_sBaseTD = TEXT_DRAW_NO_NEXT,
- //YSI_g_sExtraText[MAX_INI_ENTRY_TEXT],
- gInitialColour;
- stock _Text_SetDialogMode()
- {
- YSI_g_sTempStyle[E_STYLE_DATA_TYPE] = e_STYLE_TYPE_DIALOG;
- }
- stock _Format_SetStyleData(master, index, style[E_STYLE_DATA], label[E_3D_DATA])
- {
- // =========================================================================
- //
- #pragma unused index
- //
- // MAJOR WARNING:
- //
- // "Text_IsLocalOwner" DOES NOT PASS "INDEX" CORRECTLY AS IT DOESN'T KNOW
- // WHAT IT SHOULD BE, DON'T FORGET THIS IF YOU EVER USE "index"...
- //
- // =========================================================================
- YSI_g_sTempMaster = master;
- YSI_g_sTempStyle = style;
- YSI_g_sTemp3D = label;
- switch (style[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK)
- {
- 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:
- {
- state y_render_show : y_render_show_gt;
- // Now that we know the style, we can store only the exact style.
- YSI_g_sTempStyle[E_STYLE_DATA_TYPE] = ((style[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) >>> e_STYLE_TYPE_SHIFT) - e_STYLE_TYPE:1;
- YSI_g_sJustOne = true;
- return 144;
- }
- case e_STYLE_TYPE_CLIENT:
- {
- state y_render_show : y_render_show_scm;
- YSI_g_sJustOne = false;
- return 256;
- }
- case e_STYLE_TYPE_TD:
- {
- state y_render_show : y_render_show_td;
- YSI_g_sJustOne = true;
- // Anything with the ability to be longer than 1024 will require a
- // modification to the declaration of variables.
- return 1024;
- }
- }
- state y_render_show : y_render_show_print;
- return 1023;
- }
- static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <y_render_show : y_render_show_scm>
- {
- // This code doesn't yet deal with colours which are too close to have their
- // differences detected by the human eye (especially when there are spaces).
- curCol = newCol & 0x00FFFFFF;
- if (pos == 0)
- {
- gInitialColour = curCol;
- // Don't add the colour - this is handled in the text display function.
- return 0;
- }
- // Now try add the string version of the colour.
- //printf("rem: %d, required: %d", rem, Y_RENDER_SCM_COLOUR_LEN);
- if (rem < Y_RENDER_SCM_COLOUR_LEN + step)
- {
- // Not enough space to add a new colour.
- str[pos] = '\0';
- return -1;
- }
- // This may well cut characters off the end of the string, but don't worry,
- // well, you can worry because it may mean that some characters are parsed
- // multiple times, but there's not a lot you can do about it... This is one
- // of the few places where the extra "+ 1" is taken in to account as format
- // uses it internally.
- format(str[pos], rem + 1, "{%06x}%s", curCol, str[pos]);
- rem -= Y_RENDER_SCM_COLOUR_LEN;
- return Y_RENDER_SCM_COLOUR_LEN;
- }
- #define _COLOUR_GT_SPACE_DEF_0(%0) SAMP_GAME_TEXT_%0
- #define _COLOUR_GT_SPACE_DEF_1(%0) SAMP_GAME_TEXT_%0H
- #define _COLOUR_GT_SPACE_DEF_2(%0) SAMP_GAME_TEXT_%0HH
- #define _COLOUR_GT_SPACE_DEF_3(%0) SAMP_GAME_TEXT_%0HHH
- #define _COLOUR_GT_SPACE_DEF_4(%0) SAMP_GAME_TEXT_%0HHHH
- #define _COLOUR_GT_SPACE_DEF_5(%0) SAMP_GAME_TEXT_%0HHHHH
- #define _COLOUR_GT_SPACE(%0,%1) {('%0'|0x20)|(%1<<8),_COLOUR_GT_SPACE_DEF_%1(%0)>>>24,_COLOUR_GT_SPACE_DEF_%1(%0)>>16&0xFF,_COLOUR_GT_SPACE_DEF_%1(%0)>>8&0xFF}
- #define COLOUR_FLOAT_INFINITY (Float:0x7F800000)
- static stock Colours_SAMPToGT(colour, start)
- {
- P:4("Colours_SAMPToGT called: %i", colour);
- // Find the closest matching game text colour to the given SA:MP colour.
- static const
- sc_aColours[][4] =
- {
- // These can't be used as you can't set text to them. You can
- // however use them at the start by not changing.
- _COLOUR_GT_SPACE(X,0), _COLOUR_GT_SPACE(X,1),
- _COLOUR_GT_SPACE(X,2),
-
- _COLOUR_GT_SPACE(R,0), _COLOUR_GT_SPACE(R,1),
- _COLOUR_GT_SPACE(R,2), _COLOUR_GT_SPACE(R,3),
- _COLOUR_GT_SPACE(R,4), _COLOUR_GT_SPACE(R,5),
-
- _COLOUR_GT_SPACE(G,0), _COLOUR_GT_SPACE(G,1),
- _COLOUR_GT_SPACE(G,2), _COLOUR_GT_SPACE(G,3),
- //_COLOUR_GT_SPACE(G,4), // Don't want this twice (see Y2).
-
- _COLOUR_GT_SPACE(B,0), _COLOUR_GT_SPACE(B,1),
- _COLOUR_GT_SPACE(B,2), _COLOUR_GT_SPACE(B,3),
-
- _COLOUR_GT_SPACE(Y,0), _COLOUR_GT_SPACE(Y,1),
- _COLOUR_GT_SPACE(Y,2),
-
- _COLOUR_GT_SPACE(P,0), _COLOUR_GT_SPACE(P,1),
- _COLOUR_GT_SPACE(P,2),
-
- _COLOUR_GT_SPACE(W,0),
-
- _COLOUR_GT_SPACE(L,0)
- };
- new
- Float:dist = COLOUR_FLOAT_INFINITY,
- found = '\0',
- r = colour >> 16,
- g = colour >> 8 & 0xFF,
- b = colour & 0xFF,
- tr, tg, tb, Float:cur;
- for ( ; start < sizeof (sc_aColours); ++start)
- {
- tr = r - sc_aColours[start][1];
- tg = g - sc_aColours[start][2];
- tb = b - sc_aColours[start][3];
- cur = (tr * tr) + (tg * tg) + (tb * tb);
- if (cur < dist)
- {
- // This may sometimes give odd results in fades for draw results.
- // Though I've not seen it happen yet.
- dist = cur;
- found = sc_aColours[start][0];
- }
- }
- return found;
- }
- static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <>
- {
- #pragma unused str, pos, rem, step
- curCol = newCol;
- return 0;
- }
- static stock Format_InsertColour(str[], pos, &rem, &curCol, newCol, step) <y_render_show : y_render_show_gt, y_render_show : y_render_show_td>
- {
- // First get the closest GameText colour for the true colour. I wrote a
- // function for this a LONG time ago, finally got around to using it!
- new
- ot = curCol & 0xFF,
- oc = curCol >>> 8;
- if (ot == 0 || ot == 'x')
- {
- // Still near the start, allow some of the special start colours.
- newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, oc);
- }
- else
- {
- // Can't use the oragey colour used at the start.
- newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, 3);
- }
- new
- nt = newCol & 0xFF,
- nc = (newCol >>> 8) * 3;
- curCol = newCol;
- // Compare them.
- static
- cs_hTags[] = "~x~~h~~h~~h~~h~~h~%s";
- if (nt == ot)
- {
- ot = nc - (oc * 3);
- if (ot == 0)
- {
- // No change, return 0 if there are enough charaters to show the
- // text that should come after this new colour.
- return rem >= step ? 0 : -1;
- }
- else if (ot > 0)
- {
- if (rem >= ot + step)
- {
- // Add enough "lighter" tags to change the old colour in to the
- // new colour.
- format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 3 - ot], str[pos]);
- rem -= ot;
- return ot;
- }
- else
- {
- return -1;
- }
- }
- }
- if (rem < nc + step)
- {
- return -1;
- }
- // Subtract six from the size : 3 for "%s\0" and 3 for the extra "~x~"
- // needed as placeholder for the colour tag (added on the next line).
- format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 6 - nc], str[pos]);
- str[pos + 1] = nt;
- rem -= nc + 3;
- return nc + 3;
- }
- static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <y_render_show : y_render_show_scm>
- {
- // This code doesn't yet deal with colours which are too close to have their
- // differences detected by the human eye (especially when there are spaces).
- new
- rgb = newCol & 0x00FFFFFF;
- // Don't add the colour if there's no change from the last one.
- if (rgb == curCol)
- {
- return 0;
- }
- if (-0x5 <= ((rgb & 0x0FF) - (curCol & 0xFF)) <= 0x5)
- {
- if (-0x500 <= ((rgb & 0xFF00) - (curCol & 0xFF00)) <= 0x500)
- {
- if (-0x50000 <= ((rgb & 0xFF0000) - (curCol & 0xFF0000)) <= 0x50000)
- {
- // Haven't changed the colour.
- return 0;
- }
- }
- }
- if (pos == 0)
- {
- gInitialColour = curCol;
- // Don't add the colour - this is handled in the text display function.
- curCol = rgb;
- return 0;
- }
- // Now try add the string version of the colour.
- if (rem < Y_RENDER_SCM_COLOUR_LEN)
- {
- // Not enough space to add a new colour.
- str[pos] = '\0';
- return -1;
- }
- format(str[pos], rem + 1, "{%06x}", rgb);
- rem -= Y_RENDER_SCM_COLOUR_LEN;
- curCol = newCol;
- return Y_RENDER_SCM_COLOUR_LEN;
- }
- static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <>
- {
- #pragma unused str, pos, rem
- curCol = newCol;
- return 0;
- }
- static stock Format_AddColour(str[], pos, &rem, &curCol, newCol) <y_render_show : y_render_show_gt, y_render_show : y_render_show_td>
- {
- // First get the closest GameText colour for the true colour. I wrote a
- // function for this a LONG time ago, finally got around to using it!
- new
- ot = curCol & 0xFF,
- oc = curCol >>> 8;
- if (ot == 0 || ot == 'x')
- {
- // Still near the start, allow some of the special start colours.
- newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, oc);
- }
- else
- {
- // Can't use the oragey colour used at the start.
- newCol = Colours_SAMPToGT(newCol & 0x00FFFFFF, 3);
- }
- new
- nt = newCol & 0xFF,
- nc = (newCol >>> 8) * 3;
- curCol = newCol;
- // Compare them.
- static
- cs_hTags[] = "~x~~h~~h~~h~~h~~h~";
- if (nt == ot)
- {
- ot = nc - (oc * 3);
- if (ot == 0)
- {
- return 0;
- }
- else if (ot > 0)
- {
- if (rem >= ot)
- {
- // Add enough "lighter" tags to change the old colour in to the
- // new colour.
- str[pos] = '\0';
- strcat(str[pos], cs_hTags[sizeof (cs_hTags) - 1 - ot], rem + 1);
- rem -= ot;
- return ot;
- }
- else
- {
- return -1;
- }
- }
- }
- if (rem < nc)
- {
- return -1;
- }
- // Subtract six from the size : 3 for "%s\0" and 3 for the extra "~x~"
- // needed as placeholder for the colour tag (added on the next line).
- //format(str[pos], rem + 1, cs_hTags[sizeof (cs_hTags) - 6 - nc], str[pos]);
- str[pos] = '\0';
- strcat(str[pos], cs_hTags[sizeof (cs_hTags) - 4 - nc], rem + 1);
- str[pos + 1] = nt;
- rem -= nc + 3;
- return nc + 3;
- }
- // str = input and output write array.
- // pos = start position of the string to be faded.
- // len = total remaining space in the string.
- // endColour = target colour.
- // gInitialColour = start and current colour.
- // step = number of characters for each colour.
- // offset = number of characters in the fade not being shown.
- static stock Format_AddFade(str[], &pos, &len, endColour, &initialColour, step, offset) //<y_render_display : send_client_message>
- {
- // Add a fade for a SendClientMessage. This is called if a string is filled
- // up during a fade or the end of a fade is reached correctly. In either
- // case the current fade will constiture the end of the known current string
- // so in actual fact no additionl text after the end of the fade will be
- // dropped. This is also where we can save the data to appear in the fade
- // on the next line and re-show it.
- // Work out how many colours can be inserted at the specified step value
- // (i.e. how often a new colour appears) within the length from "pos" to the
- // end of "str". This may be more than is required. "len" is from "pos" to
- // the end of the string, NOT to the end of the characters requiring the
- // fade. The length of the required fade is in "YSI_g_sFadeLength" so that the
- // value can be used in the future.
- new
- parts = (YSI_g_sFadeLength + step - 1) / step + offset,
- // We can insert all the colours and their texts in the given space.
- // Now we just need to figure out how...
- // First get the start and end colours.
- start = str[pos + 1] & 0x00FFFFFF; //~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET);
- // Remove the start and end colour markers.
- strdel(str, pos, pos + 2);
- // Find the colour components and component deltas.
- endColour &= 0x00FFFFFF; //~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET);
- new
- red = start >>> 16 & 0xFF,
- dred = ((endColour >>> 16 & 0xFF) - red) / parts,
- pred = initialColour >>> 16 & 0xFF,
- green = start >>> 8 & 0xFF,
- dgreen = ((endColour >>> 8 & 0xFF) - green) / parts,
- pgreen = initialColour >>> 8 & 0xFF,
- blue = start >>> 0 & 0xFF,
- dblue = ((endColour >>> 0 & 0xFF) - blue) / parts,
- pblue = initialColour >>> 0 & 0xFF;
- // Take old strings in to account.
- red += dred * offset;
- blue += dblue * offset;
- green += dgreen * offset;
- //strdel(str, pmax, pmax + 2);
- //startColour = gInitialColour;
- do
- {
- // Insert the new colour, if it is sufficiently different from the
- // existing colour to warrant being added new.
- if (-3 <= red - pred <= 3 && -3 <= blue - pblue <= 3 && -3 <= green - pgreen <= 3)
- {
- pos += step;
- }
- else
- {
- new
- upd = Format_InsertColour(str, pos, len, initialColour, red << 16 | green << 8 | blue, step);
- if (upd == -1)
- {
- // Didn't quite finish everything. This is the number of
- // characters left to process.
- return YSI_g_sFadeLength;
- }
- //initial += step;
- pos += step + upd;
- pred = red;
- pgreen = green;
- pblue = blue;
- }
- YSI_g_sFadeLength -= step;
- len -= step;
- red = red + dred & 0xFF;
- green = green + dgreen & 0xFF;
- blue = blue + dblue & 0xFF;
- // Could do something with "len" here if it runs out to signify that
- // more text needs to go on the next line of output.
- }
- while (YSI_g_sFadeLength > 0);
- // Correct for any excess characters.
- pos += YSI_g_sFadeLength;
- // This doesn't add the actual destination colour - that is added by virtue
- // of the fact that it is actually just a normal colour, so we can use the
- // standard colour code (whatever that may be) to add it in a more generic
- // way.
- return 0;
- }
- static stock Format_DoEndFade(output[], &start, end, &rem, colour, &initial) //<>
- {
- // If "colour" is 0 this is the end of a string before the close colour is
- // reached. This fact is enforced by "Y_FORMAT_ALWAYS_SET", which ensures
- // that all colours, including black, are not 0 in the string to avoid PAWN
- // treating the colour as a NULL terminator or, as here, a no-colour marker.
- if (colour)
- {
- new
- offset = 0;
- if (YSI_g_sFadeLength)
- {
- initial = YSI_g_sFadeColour;
- offset = end - start - YSI_g_sFadeLength;
- //printf("parts: %d, %d, %d", offset, YSI_g_sFadeLength, end - start);
- }
- else
- {
- YSI_g_sFadeLength = end - start;
- }
- // "rem" will hold the number of characters AFTER the fade string on
- // entry, this needs fixing here to exclude them as they're being messed
- // with.
- rem += YSI_g_sFadeLength;
- //printf("length: %d", YSI_g_sFadeLength);
- // I wrote this code for the case where too much data has been found and
- // we needed a fake render to get the full length, but then found that
- // exactly the same code was needed for the default case too...
- //printf("Format_DoEndFade: %d %d %x %x %d", YSI_g_sFadeLength, /*YSI_g_sFadeLength +*/ rem, colour, initial, start);
- // Default step value is 1 and there is currently no way to change it.
- new
- ret = Format_AddFade(output, start, /*YSI_g_sFadeLength +*/ rem, colour, initial, FORMAT_FADE_STEP, offset);
- //printf("Format_DoEndFade: %d %d %x %x %d", YSI_g_sFadeLength, /*YSI_g_sFadeLength +*/ rem, colour, initial, start);
- YSI_g_sFadeColour = initial;
- return ret;
- }
- else
- {
- //printf("colour: %d", YSI_g_sFadeColour);
- // Quite simply, we just change state and return to the calling
- // function. This allows this function to be called again when the true
- // fade end is reached and the length to be determined. After that some
- // re-parsing will need to be done I'm afraid, but that will be handled
- // by code dealing with fades which fall over the end of a string, be it
- // due to this or to a known length string being pushed over the end due
- // to the insertion of the colour codes. Note that this code is display
- // method independent - it works for SendClientMessage, GameText and
- // others.
- state y_render_fade : y_render_fade_fake;
- // The return here causes remaining code to continue as normal, but
- // makes certain functions just not run.
- }
- return 0;
- }
- /*----------------------------------------------------------------------------*\
- Function:
- Format_DoAddString
- Params:
- out[] - The destination string.
- in[] - The data to add.
- &oidx - The index in "out" at which to add data.
- len - The length of "in".
- &orem - Space remaining in "out".
- &fakePos - Like "oidx", but cumulative over line breaks.
- Return:
- The amount of data from "in" not added to "out".
- Notes:
- Takes an input string and adds it to an output string. If the input string
- is too long to fit in the remainder of the output string, what has been
- added already (including part of the input string) is displayed and a new
- string is added. Format_TryShow handles this, including adding formatting
- of colour fades, which may involve fake rendering of more of the string to
- determine how much of the remainder of the string needs processing to get
- the right colour. This will also require a method of winding back the state
- to the point just after the initial input string was added to continue on to
- show the next string including newly determined fade data.
- \*----------------------------------------------------------------------------*/
- static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_fake>
- {
- #pragma unused out, in, oidx, orem
- fakepos += len;
- return 0;
- }
- static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_redo>
- {
- new
- temp = fakepos + len - YSI_g_sFadeRedoTarget;
- if (temp > 0)
- {
- state y_render_fade : y_render_fade_real;
- // This is where the string passes the target point of re-rendering.
- new
- other = YSI_g_sFadeRedoTarget - fakepos;
- fakepos += other;
- return Format_DoAddString(out, in[other], oidx, temp, orem, fakepos);
- }
- else
- {
- fakepos += len;
- return 0;
- }
- }
- static stock Format_DoAddString(out[], const in[], &oidx, const len, &orem, &fakepos) <y_render_fade : y_render_fade_real>
- {
- P:4("Format_DoAddString <y_render_fade : render_real> called: \"%s\", \"%s\", %i, %i, %i, %i", out, in, oidx, len, orem, fakepos);
- // For now don't worry about fades over boundaries - they're just too hard
- // to get the code working on to start with, maybe later once this is all
- // working they can be added in. It is a shame though as it will mean fades
- // don't always work. I can cheat slightly though and have the full fade on
- // both halves of the break. Or just warn people about fades like that.
- //
- // NOTE: This code assumes that orem (output remaining) is always 1 less
- // than the true value. This avoids awkward calculations when appending the
- // NULL terminator to strings. When we run out of space it simply appends
- // it regardless of wether it thinks there is space or not.
- //
- fakepos += len;
- if (len <= orem)
- {
- P:5("Format_DoStringSCM: p0.");
- memcpy(out[oidx], in, 0, len * 4, orem);
- orem -= len;
- oidx += len;
- // The whole string fit in - return true.
- return 0;
- }
- else
- {
- // Not the end of the string, but the end is required.
- // Change state to ignore future inputs.
- P:5("Format_DoStringSCM: p1.");
- // Copy as much data as possible.
- memcpy(out[oidx], in, 0, orem * 4, orem);
- //orem -= orem;
- //oidx += orem;
- // Don't need to adjust this further down as all the characters will be
- // added before the recursive call.
- oidx += orem;
- return len - orem;
- }
- }
- static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_fake>
- {
- #pragma unused out, in, oidx, orem
- ++fakepos;
- return true;
- }
- static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_redo>
- {
- if (fakepos == YSI_g_sFadeRedoTarget)
- {
- state y_render_fade : y_render_fade_real;
- // This should never actually fail...
- if (!orem) return false;
- --orem;
- out[oidx++] = in;
- }
- ++fakepos;
- return true;
- }
- static stock bool:Format_DoAddChar(out[], const in, &oidx, &orem, &fakepos) <y_render_fade : y_render_fade_real>
- {
- P:4("Format_DoAddChar: %c %d %d", in, oidx, orem);
- if (!orem) return false;
- --orem;
- out[oidx++] = in;
- ++fakepos;
- return true;
- }
- static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_scm>
- {
- P:2("Format_DoDisplay a: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
- SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
- //idx = 0;
- //out[0] = '\0';
- }
- static stock Format_DoDisplay(playerid, colour, out[]) <> //y_render_show : y_render_show_print>
- {
- P:0("Format_DoDisplay b: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
- //idx = 0;
- //out[0] = '\0';
- }
- static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_gt>
- {
- #pragma unused colour
- P:2("Format_DoDisplay c: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
- GameTextForPlayer(playerid, out, YSI_g_sTempStyle[E_STYLE_DATA_TIME], YSI_g_sTempStyle[E_STYLE_DATA_STYLE]);
- //SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
- //GameTextForPlayer(playerid, out,
- //SendClientMessage(playerid, colour, out);
- //idx = 0;
- //out[0] = '\0';
- }
- static stock Format_DoDisplay(playerid, colour, out[]) <y_render_show : y_render_show_td>
- {
- #pragma unused colour
- P:2("Format_DoDisplay d: %d, %06x, \"%s\"", playerid, colour >>> 8, out);
- new
- Text:tmp = TD_Display(out, YSI_g_sTempStyle[E_STYLE_DATA_TD_ID]);
- out[0] = _:tmp;
- out[1] = '\0';
- TD_ShowForPlayer(playerid, tmp);
- TD_Garbage(tmp);
- // Link these TDs together for future manipulations.
- if (YSI_g_sBaseTD == TEXT_DRAW_NO_NEXT)
- {
- YSI_g_sBaseTD = tmp;
- }
- else
- {
- TD_Link(YSI_g_sBaseTD, tmp);
- }
- //SendClientMessage(playerid, (colour << 8) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0x0F) * 0x11), out);
- //GameTextForPlayer(playerid, out,
- //SendClientMessage(playerid, colour, out);
- //idx = 0;
- //out[0] = '\0';
- }
- /*----------------------------------------------------------------------------*\
- Function:
- Format_JustShow
- Params:
- playerid - Player to show the text to.
- out[] - What the text to show is.
- Return:
- -
- Notes:
- -
- \*----------------------------------------------------------------------------*/
- stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_scm>
- {
- SendClientMessage(playerid, gInitialColour, out);
- }
- stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_print>
- {
- P:0("Format_DoDisplay: %d, \"%s\"", playerid, out);
- }
- stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_gt>
- {
- GameTextForPlayer(playerid, out, YSI_g_sTempStyle[E_STYLE_DATA_TIME], YSI_g_sTempStyle[E_STYLE_DATA_STYLE]);
- }
- stock Format_JustShow(playerid, out[]) <y_render_show : y_render_show_td>
- {
- TD_ShowForPlayer(playerid, Text:out[0]);
- }
- /*----------------------------------------------------------------------------*\
- Function:
- Text_GetLastID
- Params:
- -
- Return:
- The basic ID linking all displayed elements together where appropriate (for
- example SendClientMessage has no meaningful ID. 3D texts would, but that's
- not implemented. So do game texts, but that's not implemented either, so
- really it's just text draws.
- Notes:
- -
- \*----------------------------------------------------------------------------*/
- stock Text_GetLastID() <y_render_show : y_render_show_td>
- {
- return _:YSI_g_sBaseTD;
- }
- stock Text_GetLastID() <>
- {
- return -1;
- }
- /*----------------------------------------------------------------------------*\
- Function:
- -
- Params:
- -
- Return:
- -
- Notes:
- -
- \*----------------------------------------------------------------------------*/
- // Generic function to handle rendering for all types of outputs. Other
- // functions such as Format_AddColour are specialised for different text styles.
- // The faster way to do this would be to store the characters removed from a
- // string when adding in fade data, but this is hard to code. The simpler
- // method is to fake re-render the string, having previously determined the
- // length of the string which will be faded across. Note that this may mean
- // that some parts of the string can get rendered many times, but we can just
- // issue a performance warning when the player uses fades which go over a line
- // boundary. That is the only time in which it is a problem, more specifically
- // it is only a problem when text in a fade goes over a line boundardy before
- // the end fade marker has been reached.
- //stock Format_Render(pid, Language:l, output[], maxlen, idx, target, string[], {Float,_}:...)
- stock Format_Render(pid, Language:l, output[], maxlen, idx, target, string[], argCount, GLOBAL_TAG_TYPES:...)
- {
- P:3("Format_Render called: %i, %i, %s, %i, %i, %i, %s (+%i)", pid, _:l, output, maxlen, idx, target, argCount, numargs() - 8);
- //state y_text_colour_fade:full_render;
- gInitialColour = (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF;
- new
- colour = gInitialColour;
- YSI_g_sFadeLength = 0;
- YSI_g_sBaseTD = TEXT_DRAW_NO_NEXT;
- // Now the (mostly) tail-recursive function call.
- Format_Render_start:
- static
- scFormats[][8] =
- {
- "%*.*d", // 6 (6)
- "%-*.*d", // 7 (13)
- "%0*.*d", // 7 (20)
- "%0-*.*d" // 8 (28)
- },
- scSpecifier[8],
- // =====================================================================
- // UPDATE Y_RENDER_FIX_NEGATIVE MACRO ON CHANGE!!!!!!!
- ts[130],
- // Max handleable input string length is 128 (hopefully sufficient).
- // =====================================================================
- func[32],
- scNewLineString[] = "~n~",
- scDialogLineString[] = "\r\n";
- new
- ch,
- llen = maxlen,
- //output[128], // Always 128.
- p = 0,
- curArg = 8, // Account for additionaly pushed arguments.
- numArgs = numargs() + argCount,
- //llen = sizeof (output) - 1,
- arg,
- none = (target & e_FORMAT_FLAGS_NONE),
- onlyOne = (target & e_FORMAT_FLAGS_ONE) | none | _:YSI_g_sJustOne,
- bool:fade = false,
- bool:nlInFade = false,
- // flags:
- // 1 = Just one output.
- // 2 = Newline found in fade.
- // 4 = In a fade.
- //flags = (target & e_FORMAT_FLAGS_ONE) ? 1 : 0,
- fakePos = 0,
- // Was only "one" string display used and is this not per-player text?
- one = 0,
- // Start location of the current fade.
- fadeStart,
- fadeStartIdx;//,
- //fadeStartText;
- //#emit LOAD.S.pri string
- //#emit STOR.S.pri fadeStartText
- if (target & e_FORMAT_FLAGS_REDO)
- {
- // We need to skip data, ignore everything before "target1".
- state y_render_fade : y_render_fade_redo;
- }
- else
- {
- state y_render_fade : y_render_fade_real;
- }
- target &= e_FORMAT_FLAGS_INDEX;
- /*new
- fadeCurArg,
- fadeArg,
- fadeIdx;*/
- if ((YSI_g_sFadeRedoTarget = target))
- {
- YSI_g_sFadeRedoTarget &= ~Y_FORMAT_ALWAYS_SET;
- state y_render_fade : y_render_fade_redo;
- }
- else
- {
- state y_render_fade : y_render_fade_real;
- }
- /*ch = string[idx];
- if (ch > 0)
- {
- // Copy strings.
- ++idx;
- Y_RENDER_ADD_EX(string, idx, ch - idx)
- idx = ch;
- }*/
- while ((ch = string[idx++]))
- {
- // TODO: Add {*} and #* format for variable colours.
- switch (ch)
- {
- case '\01':
- {
- // Null.
- break;
- }
- case '\02':
- {
- P:6("Text_Render: Format specifier %d", curArg);
- if (curArg == numArgs)
- {
- // Skip.
- P:W("Insufficient parameters to YSI format.");
- ts = "(null)";
- Y_RENDER_ADD(ts)
- continue;
- }
- // Format.
- ch = string[idx++];
- new
- width = (ch & _:e_COMPRESS_FORMAT_DATA_WIDTH),
- prec = (ch & _:e_COMPRESS_FORMAT_DATA_PREC) >>> 12;
- // Get the true values of the various data bits.
- if (width == 0x0800)
- {
- width = getarg(curArg++);
- }
- if (prec == 0x0800)
- {
- prec = getarg(curArg++);
- }
- else if (prec == 0x0FFF)
- {
- prec = -1;
- }
- // Output the correct data type.
- switch (ch & 0xF0000000)
- {
- case e_COMPRESS_FORMAT_DATA_DEC:
- {
- P:6("Text_Render: Add d");
- scSpecifier = Y_RENDER_SPECIFIER(d);
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_HEX:
- {
- // This completely fixes (I hope) the problems with
- // displaying negative numbers as %h/%x numbers.
- P:6("Text_Render: Add h");
- scSpecifier = Y_RENDER_SPECIFIER(x);
- Y_RENDER_ARG
- {
- if (arg & 0x80000000)
- {
- Y_RENDER_FIX_NEGATIVE(x:8);
- }
- else
- {
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- }
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_BIN:
- {
- P:6("Text_Render: Add b");
- scSpecifier = Y_RENDER_SPECIFIER(b);
- Y_RENDER_ARG
- {
- if (arg & 0x80000000)
- {
- Y_RENDER_FIX_NEGATIVE(b:32);
- }
- else
- {
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- }
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_CHAR:
- {
- scSpecifier = Y_RENDER_SPECIFIER(c);
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_FLOAT:
- {
- scSpecifier = Y_RENDER_SPECIFIER(f);
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_IEEE:
- {
- Y_RENDER_ARG
- {
- if ((arg & 0x7F800000) == 0x7F800000)
- {
- scSpecifier = Y_RENDER_SPECIFIER(s);
- // One of the special numbers.
- if (arg & 0x007FFFFF)
- {
- // NAN.
- if (arg & 0x00400000)
- {
- // QNAN
- format(ts, sizeof (ts), scSpecifier, width, cellmax, "QNAN");
- Y_RENDER_ADD(ts)
- }
- else
- {
- // SNAN
- format(ts, sizeof (ts), scSpecifier, width, cellmax, "SNAN");
- Y_RENDER_ADD(ts)
- }
- }
- else
- {
- if (arg & 0x80000000)
- {
- // -INFINITY
- format(ts, sizeof (ts), scSpecifier, width, cellmax, "-INFINITY");
- Y_RENDER_ADD(ts)
- }
- else
- {
- // INFINITY
- format(ts, sizeof (ts), scSpecifier, width, cellmax, "INFINITY");
- Y_RENDER_ADD(ts)
- }
- }
- }
- else
- {
- scSpecifier = Y_RENDER_SPECIFIER(f);
- format(ts, sizeof (ts), scSpecifier, width, prec, arg);
- Y_RENDER_ADD(ts)
- }
- }
- }
- case e_COMPRESS_FORMAT_DATA_STRING:
- {
- scSpecifier = Y_RENDER_SPECIFIER(s);
- if (ch & _:e_COMPRESS_FORMAT_DATA_FUNC)
- {
- func = "@yR_";
- // Get the function name.
- for (new _k = 4; _k != 32; ++_k)
- {
- if (!(func[_k] = getarg(curArg, _k - 4)))
- {
- break;
- }
- }
- if (funcidx(func) == -1)
- {
- // Normal version. This is ended by a null.
- // Other functions get the count in advance when
- // an index of -1 is passed.
- func[2] = 'r';
- // This code mimicks much of the internal
- // y_master code because wrapping this in a
- // macro is a) pointless and b) hard. This code
- // is ALWAYS like this because of the nature of
- // it.
- new
- lst = setproperty(8, YSIM_CALLER),
- _j = 0;
- setproperty(8, YSIM_CALLER, _@);
- for ( ; ; )
- {
- CallRemoteFunction(func, "ii", _:l, _j);
- // Resolve the string.
- getproperty(8, "", YSIM_STRING, Q@);
- strunpack(Q@, Q@);
- if (Q@[0])
- {
- if (_j)
- {
- // Separate the strings - hard coded
- // list format currently I'm afraid.
- ts = ", ";
- Y_RENDER_ADD(ts)
- }
- format(ts, sizeof (ts), scSpecifier, width, prec, Q@);
- Y_RENDER_ADD(ts)
- }
- else
- {
- break;
- }
- ++_j;
- }
- setproperty(8, YSIM_CALLER, lst);
- }
- else
- {
- // Player specific version.
- // Normal version. This is ended by a null.
- // Other functions get the count in advance when
- // an index of -1 is passed.
- func[2] = 'r';
- // This code mimicks much of the internal
- // y_master code because wrapping this in a
- // macro is a) pointless and b) hard. This code
- // is ALWAYS like this because of the nature of
- // it.
- new
- lst = setproperty(8, YSIM_CALLER),
- _j = 0;
- setproperty(8, YSIM_CALLER, _@);
- for ( ; ; )
- {
- CallRemoteFunction(func, "iii", pid, _:l, _j);
- // Resolve the string.
- getproperty(8, "", YSIM_STRING, Q@);
- strunpack(Q@, Q@);
- if (Q@[0])
- {
- if (_j)
- {
- // Separate the strings - hard coded
- // list format currently I'm afraid.
- ts = ", ";
- Y_RENDER_ADD(ts)
- }
- // Could do with configuring this to not
- // need to call "Y_RENDER_SPECIFIER" every
- // time.
- format(ts, sizeof (ts), scSpecifier, width, prec, Q@);
- Y_RENDER_ADD(ts)
- }
- else
- {
- break;
- }
- ++_j;
- }
- setproperty(8, YSIM_CALLER, lst);
- // Force the string to be rebuilt every time.
- ++one;
- }
- }
- else
- {
- // Single parameter. Can do this FAR better by just
- // using #emit to re-push the parameter directly.
- for (new _k = 0; _k != sizeof (ts); ++_k)
- {
- if (!(ts[_k] = getarg(curArg, _k)))
- {
- break;
- }
- }
- format(ts, sizeof (ts), scSpecifier, width, prec, ts);
- Y_RENDER_ADD(ts)
- }
- ++curArg;
- }
- /*case e_COMPRESS_FORMAT_DATA_OCT:
- {
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
- ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
- Y_RENDER_ADD(ts)
- }
- }*/
- case e_COMPRESS_FORMAT_DATA_COMM:
- {
- scSpecifier = Y_RENDER_SPECIFIER(s);
- // Show a command.
- /*for(new _i=0,_b=4;_i!=2;++_i)
- if(_i==0)
- {
- if(ch&_:e_COMPRESS_FORMAT_DATA_FUNC)
- {
- _b=1,func="@yR_";
- for(new _k=4;_k!=32;++_k)
- if(!(func[_k]=getarg(curArg,_k-4)))
- break;
- if(funcidx(func)==-1)func[2]='r',_b=2;
- }
- else if(ch&_:e_COMPRESS_FORMAT_DATA_LIST)
- _b=3;
- }
- else
- 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)*/
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
- // "arg" has the ID of the command, not the NAME of
- // the command which may change for different people
- // (need to find a way to return a single name for a
- // player which gets to the specified command).
- #if defined _inc_y_commands
- strcpy(ts, Command_GetDisplay(arg, pid));
- if (ts[0])
- {
- format(ts, sizeof (ts), scSpecifier, width, prec, ts);
- Y_RENDER_ADD(ts)
- }
- #endif
- //ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
- //Y_RENDER_ADD(ts)
- }
- }
- /*case e_COMPRESS_FORMAT_DATA_SUFFIX:
- {
- scSpecifier = Y_RENDER_SPECIFIER(s);
- // TODO: Add language to this.
- //p += Format_AddSuffix(output[p], llen, getarg(curArg++), l);
- Y_RENDER_ARG
- {
- format(ts, sizeof (ts), scSpecifier, width, cellmax, Format_AddSuffix(arg, l));
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_UNSIGNED:
- {
- if (prec < 0) prec = 10;
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
- //ts[Format_AddOct(ts, sizeof (ts) - 1, arg, width, ch)] = '\0';
- ts[Format_AddNum(ts, sizeof (ts) - 1, arg, width, ch, prec, false)] = '\0';
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_SIGNED:
- {
- if (prec < 0) prec = 10;
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- //format(ts, sizeof (ts), Y_RENDER_SPECIFIER(f), width, prec, arg);
- ts[Format_AddNum(ts, sizeof (ts) - 1, arg, width, ch, prec, true)] = '\0';
- Y_RENDER_ADD(ts)
- }
- }*/
- case e_COMPRESS_FORMAT_DATA_PLAYER:
- {
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- GetPlayerName(arg, ts, sizeof (ts));
- format(ts, sizeof (ts), scSpecifier, width, prec, ts);
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_LOGICAL:
- {
- scSpecifier = Y_RENDER_SPECIFIER(s);
- Y_RENDER_ARG
- {
- //p += Format_AddInt(output[p], llen, arg, width, ch);
- format(ts, sizeof (ts), scSpecifier, width, prec, arg ? ("true") : ("false"));
- Y_RENDER_ADD(ts)
- }
- }
- case e_COMPRESS_FORMAT_DATA_CUSTOM:
- {
- // Get the function we will be calling to do the format.
- // Slice caches these, but we don't because of the
- // extended versions (%k<DATE>) etc.
- new
- ffake[4 char],
- fidx;
- ffake[0] = string[idx];
- if (ffake{1} == '@')
- {
- if (!AMX_GetPublicPointer(0, fidx, ffake))
- {
- continue;
- }
- ++idx;
- }
- else
- {
- static
- sFunc2[32] = "F";
- strunpack(sFunc2[1], string[idx], sizeof (sFunc2) - 1);
- // Limit the function name to the function length.
- sFunc2[sFunc2[1]] = '\0';
- idx += ceildiv(sFunc2[1], 4);
- sFunc2[1] = '@';
- if (!AMX_GetPublicPointer(0, fidx, sFunc2))
- {
- continue;
- }
- }
- //
- // "b":
- //
- // "b" is the source type. "1" = function, "2" = per-
- // player function, "3" = list, "4" = variable. "0" is
- // a special case meaning "processed variable" and tells
- // the system to stop "j != -1 && b".
- //
- // "i":
- //
- // "i" is the current processing stage - there are two.
- // The first looks at all the arguments and collects the
- // function or list data (if any). The second loops
- // over all the passed arguments and does the format.
- // This is where the "b" check comes in, to only do that
- // inner loop once. It is done this way simply to allow
- // us to use braces around the code to do the format.
- //
- // "j":
- //
- // "j" is the main loop variable for the inner loop and
- // tracks which parameter part we are currently doing in
- // the case of function or list inputs.
- //
- 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) == -1)
- {
- b = 2;
- func[2] = 'r';
- }
- }
- else if (ch & _:e_COMPRESS_FORMAT_DATA_LIST)
- {
- b = 3;
- }
- ch &= FORMAT_FLAG_LEFT | FORMAT_FLAG_ZERO;
- }
- else
- {
- for (;
- // These lines ALWAYS get run because
- // they come before a comma in the "for"
- // conditional, but their result is
- // ignored.
- (arg = (b == 1)
- ? W@(func, "iii", pid, (_:l), j)
- : (b == 2)
- ? W@(func, "ii", (_:l), j)
- : (b == 3)
- ? getarg(curArg, j++)
- : getarg(curArg)
- ),
- // This is the true condition. If the
- // first half fails then "curArg" is
- // incremented and the whole check
- // fails, otherwise, thanks to short-
- // circuiting, "curArg" is NOT
- // incremented.
- (arg != cellmin && b) || (++curArg & 0);
- // Only run the loop once when "b = 4".
- b &= ~4, ++j
- )
- {
- // Standard format code goes here.
- #emit PUSH.S prec
- #emit PUSH.S width
- #emit PUSH.S ch
- // Get the source (assume constant for now,
- // i.e. no functions or lists yet).
- #emit PUSH.S arg
- // Get a string if there is one.
- if (b == 1 || b == 2)
- {
- getproperty(8, "", YSIM_STRING, Q@);
- strunpack(Q@, Q@);
- if (isnull(Q@))
- {
- ++curArg;
- // Fix the stack.
- #emit POP.pri
- #emit POP.pri
- #emit POP.pri
- #emit POP.pri
- break;
- }
- #emit PUSH.C Q@
- }
- else
- {
- #emit LCTRL 5
- #emit LOAD.S.alt curArg
- #emit SHL.C.alt 2
- #emit ADD
- #emit LOAD.I
- #emit PUSH.pri
- }
- #emit PUSH.C ts
- // Far more parameters that Slice's.
- #emit PUSH.C 24 // 4 * 6.
- // This code is almost common now!
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit LOAD.S.pri fidx
- #emit SCTRL 6
- // Now we have returned from the custom
- // function.
- Y_RENDER_ADD(ts)
- }
- }
- }
- }
- /*case e_COMPRESS_FORMAT_DATA_DATE:
- {
- // Hard one - needs more interaction.
- }*/
- }
- }
- case '\03', -1:
- {
- P:6("Text_Render: Colour %d %d %d %d %d %06x %s", p, llen, fadeStart, fakePos, idx, colour & 0xFFFFFF, string);
- if (fade) //flags & 4)
- {
- p = fadeStart;
- new
- rem = Format_DoEndFade(output, p, fakePos, llen, string[idx], colour);
- if (rem || nlInFade) //(flags & 2))
- {
- // "rem" is the number of characters not processed.
- YSI_g_sFadeColour = colour;
- Y_RENDER_DO_DISPLAY()
- P:6("Format_Render: one stage: \"%s\"", output);
- // Subtract 2 to get the index in to the fade where the
- // letters start. This is not as easy as it used to be
- // as we need to manipulate the stack to push the extra
- // parameters somehow. Now changed to a fake tail-
- // recursive call so that we don't need to worry about
- // the stack. This also explains why labels generate
- // extra stack manipulation code (to reset locals).
- //return Format_Render(pid, l, output, maxlen, fadeStartIdx, fakePos - fadeStart - rem | e_FORMAT_FLAGS_REDO, string);
- //#emit LOAD.S.pri fadeStartText
- //#emit STOR.S.pri string
- idx = fadeStartIdx;
- target = (fakePos - fadeStart - rem) | e_FORMAT_FLAGS_REDO;
- gInitialColour = colour;
- //YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] = (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] & 0xF000000F) | (gInitialColour << 4);
- goto Format_Render_start;
- // We don't need these as they are only set when you
- // want less than 2 displays, and as to get to this
- // point you need to have shown at least noe item there
- // is no possible way they can be set the second time.
- //| (onlyOne ? e_FORMAT_FLAGS_ONE : 0) | (none ? e_FORMAT_FLAGS_NONE : 0);
- }
- //flags &= ~4;
- fade = false;
- fakePos += p - fadeStart;
- }
- if (string[idx] & Y_FORMAT_CLOSE_CURR)
- {
- // Get the initial display colour.
- //string[idx] |= (YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF;
- string[idx] = (string[idx] & 0xFF000000) | ((YSI_g_sTempStyle[E_STYLE_DATA_COLOUR] >>> 4) & 0x00FFFFFF);
- }
- if (string[idx] & Y_FORMAT_START_FADE)
- {
- //flags |= 4;
- fade = true;
- fadeStart = p;
- fadeStartIdx = idx - 1;
- string[fadeStartIdx] = -1;
- //#emit LOAD.S.pri string
- //#emit STOR.S.pri fadeStartText
- if (p < maxlen - 1)
- {
- output[p++] = '\03';
- output[p++] = string[idx++];
- }
- }
- else
- {
- // Just add the colour here normally.
- arg = Format_AddColour(output, p, llen, colour, string[idx++]); //& ~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET));
- switch (arg)
- {
- case -1:
- {
- Y_RENDER_DO_DISPLAY()
- }
- case 0:
- {
- // Do nothing.
- }
- default:
- {
- p += arg;
- fakePos += arg;
- }
- }
- /*else
- {
- p += arg;
- }
- currentColour = string[idx++];
- if (maxlen - pos > Y_RENDER_SCM_COLOUR_LEN)
- {
- format(output[pos], maxlen - pos, "{%06x}", currentColour & ~(Y_FORMAT_START_FADE | Y_FORMAT_ALWAYS_SET));
- pos += Y_RENDER_SCM_COLOUR_LEN;
- }
- else
- {
- output[pos] = '\0';
- printf("some stage: \"%s\"", output);
- output[0] = '\0';
- pos = 0;
- }*/
- //++idx;
- }
- }
- case '\04':
- {
- P:6("Text_Render: Key");
- ++idx;
- }
- case '\05':
- {
- // String extension.
- P:6("Text_Render: Extension %d %d %d", YSI_g_sTempMaster, string[idx], string[idx - 1]);
- // TODO!
- // This should change the current input to a new one. May
- // require some more advanced hacking to support fades over
- // these boundaries (or just ban them)... Actually, I don't
- // think it will require extra work...
- // Just use the text directly.
- idx = _Text_GetPointer(YSI_g_sTempMaster, string[idx]);
- #emit LOAD.S.pri idx
- #emit STOR.S.pri string
- idx = 0;
- }
- case '\n':
- {
- P:6("Text_Render: NL");
- // Check for 2 character new lines (\n\r).
- if (string[idx] == '\r') ++idx;
- // Output the last string.
- if (fade) //flags & 4)
- {
- //flags |= 2;
- nlInFade = true;
- state y_render_fade : y_render_fade_fake;
- }
- else if ((YSI_g_sTempStyle[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) < e_STYLE_TYPE_CLIENT)
- {
- // This works even for GTs which are always 0 by this point.
- Y_RENDER_ADD(scNewLineString)
- }
- else if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] == e_STYLE_TYPE_DIALOG)
- {
- printf("NL 1");
- // This works even for GTs which are always 0 by this point.
- Y_RENDER_ADD(scDialogLineString)
- printf("NL 2");
- }
- else
- {
- Y_RENDER_DO_DISPLAY()
- }
- }
- case '\r':
- {
- P:6("Text_Render: NL");
- // Check for 2 character new lines (\r\n).
- if (string[idx] == '\n') ++idx;
- // Output the last string.
- if (fade) //flags & 4)
- {
- //flags |= 2;
- nlInFade = true;
- state y_render_fade : y_render_fade_fake;
- }
- else if ((YSI_g_sTempStyle[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) < e_STYLE_TYPE_CLIENT)
- {
- // This works even for GTs which are always 0 by this point.
- Y_RENDER_ADD(scNewLineString)
- }
- else if (YSI_g_sTempStyle[E_STYLE_DATA_TYPE] == e_STYLE_TYPE_DIALOG)
- {
- // This works even for GTs which are always 0 by this point.
- printf("NL 3");
- Y_RENDER_ADD(scDialogLineString)
- printf("NL 4");
- }
- else
- {
- Y_RENDER_DO_DISPLAY()
- }
- }
- case '\t':
- {
- // Somehow display a tab. Maybe keep track of characters
- // displayed and show "n % 4" spaces.
- arg = 4 - (p & 0x03); // The number of spaces to add.
- static
- sTabs[] = " ";
- for (new __added; (__added = Format_DoAddString(output, sTabs[4 - arg], p, arg, llen, fakePos)); arg -= __added)
- {
- if (fade) //flags & 4)
- {
- state y_render_fade : y_render_fade_fake;
- }
- else
- {
- Y_RENDER_DO_DISPLAY()
- }
- }
- }
- case '\06' .. '\08', '\11', '\12', '\14' .. '\32':
- {
- // Whitespace. Just show a space, not the fancy character, no
- // idea what it could do. Note that this range includes spaces.
- P:6("Text_Render: Space");
- Y_RENDER_CHAR(' ')
- }
- default:
- {
- P:6("Text_Render: Char");
- Y_RENDER_CHAR(ch)
- }
- }
- /*if (!(ch = string[idx]))
- {
- break;
- }
- // Copy strings.
- ++idx;
- Y_RENDER_ADD_EX(string, idx, ch - idx)
- idx = ch;*/
- P:6("Text_Render: Loop: p = %d, llen = %d, output = \"%s\"", p, llen, (output[p] = '\0', output));
- }
- P:5("Text_Render: Final render?");
- if (p)
- {
- P:5("Text_Render: Yes!");
- output[p] = '\0';
- if (!none) Format_DoDisplay(pid, gInitialColour, output);
- ++one;
- }
- P:5("Text_Render: p = %d, output = \"%s\"", p, output);
- P:C(idx=0;while ((ch = output[idx++]))printf("%04x%04x = %c", ch >>> 16, ch & 0xFFFF, ch););
- P:5("Text_Render end");
- return one;
- }
|