impl.inc 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271
  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. enum e_TEXT_DISPLAY_TYPE
  65. {
  66. text_type_print = cellmin,
  67. text_type_3d = -4,
  68. text_type_player = -3,
  69. text_type_alert = -2,
  70. text_type_td = -1,
  71. text_type_client = 0,
  72. text_type_game1,
  73. text_type_game2,
  74. text_type_game3,
  75. text_type_game4,
  76. text_type_game5,
  77. text_type_game6
  78. }
  79. //#include "..\y_master"
  80. // End conditions for the recursive calls (strings and publics).
  81. #define _YT@LE@E%0>
  82. #define _YT@LT@E%0> ;
  83. // Recursive wanted text definition. Needs two levels of indirection to strip
  84. // the excess commas (,%0,%1).
  85. #if defined Y_TEXT_UNIQUE
  86. #define _YT@LO(,%0,%1) UNIQUE_FUNCTION<%0@%1@...@yX_>();public UNIQUE_FUNCTION<%0@%1@...@yX_>(){}
  87. #else
  88. #define _YT@LO(,%0,%1) %0@%1@yX_();public %0@%1@yX_(){}
  89. #endif
  90. #define _YT@LE%0[%1]%2> _YT@LO(%0,%1) _YT@LE%2>
  91. // Recursive local default string definition.
  92. #define _YT@LJ(,%0,%1) #%0":"#%1"|"
  93. #define _YT@LT%0[%1]%2> _YT@LJ(%0,%1)_YT@LT%2>
  94. // Recursive macro with clever ending to load many items from 1 "loadtext"
  95. // keyword. NOW RENAMED FROM JUST "text" - WORST NAMING EVER!
  96. #define loadtext%0[%1]%2; _YT@LE,%0[%1]%2@E>static stock DEFAULT_TEXT_SET[]=_YT@LT,%0[%1]%2@E>
  97. #define Text_RegisterTag(%1) \
  98. loadtext core[%1]
  99. // Clever macros to load default values when not specified.
  100. //#define Text_Send(%0,%1) _Text_Send(%0,DEFAULT_TEXT_SET,#%1)
  101. #define DO_TEXT_SET: _:HAS_TEXT_SET:NO_TEXT_SET:
  102. #define HAS_TEXT_SET:NO_TEXT_SET:%0$%1||| DEFAULT_TEXT_SET,#%1|||
  103. #define NO_TEXT_SET: "\3",
  104. #define DEFAULT_TEXT_SET,#%1->%2||| #core#:#%1#|,#%2|||
  105. // WTF does this do? I can't even remember what slots are!
  106. //#define core":"#%1:%2"|",%3) %1":"#%2"|",%3)
  107. #define core#:#%1[%2]%9#|,%3) %1#:#%2#|,%3)
  108. /*#if defined _inc_y_languages
  109. #define Text_GetLanguageCodes() Langs_GetLanguageCodes()
  110. #define Text_GetPlayerLanguage(%0) Langs_GetPlayerLanguage(%0)
  111. #else
  112. // y_languages doesn't really do much TBH... This used to have three
  113. // langugages, but then I realised that without the "y_languages"
  114. // library there was no way for a player to select their language.
  115. // "XX" is used as a dummy to ensure that the array in the enum is always
  116. // valid and that the compiler doesn't optimise it out.
  117. #define Text_GetLanguageCodes() "EN|XX|" //|NL|ES|"
  118. // Number of "|" separated strings above (always 1).
  119. #define YSI_MAX_LANGUAGES (Language:2)
  120. #define Text_GetPlayerLanguage(%0) (Language:0)
  121. #endif*/
  122. // Return types
  123. enum E_TEXT_FIND
  124. {
  125. E_TEXT_FIND_NONE,
  126. E_TEXT_FIND_JUST,
  127. E_TEXT_FIND_MANY
  128. }
  129. // This holds the data for all entry points.
  130. enum e_TEXT_SETS
  131. {
  132. e_TEXT_SETS_NAME[28],
  133. e_TEXT_SETS_HASH,
  134. e_TEXT_SETS_INDEX,
  135. e_TEXT_SETS_LOADED
  136. }
  137. enum e_TEXT_ENTRY
  138. {
  139. e_TEXT_ENTRY_NAME[MAX_INI_ENTRY_NAME],// char],
  140. e_TEXT_ENTRY_HASH,
  141. e_TEXT_ENTRY_LEFT,
  142. e_TEXT_ENTRY_RIGHT,
  143. e_TEXT_ENTRY_POINTERS[YSI_MAX_LANGUAGES]
  144. }
  145. #define TEXT_MASTER YSI_g_sDistributionID
  146. #if !defined MAX_SINGLE_TEXT_ITEM
  147. #define MAX_SINGLE_TEXT_ITEM (1024)
  148. #endif
  149. static stock
  150. YSI_g_sTextSets[Y_TEXT_MAX_SETS][e_TEXT_SETS],
  151. YSI_g_sTextEntries[MAX_TEXT_ENTRIES][e_TEXT_ENTRY],
  152. YSI_g_sTextStrings[MAX_TEXT_ENTRIES * _:YSI_MAX_LANGUAGES][MAX_INI_ENTRY_TEXT / 4],// char],
  153. YSI_g_sReturnText[MAX_SINGLE_TEXT_ITEM],
  154. YSI_g_sExtraText[MAX_SINGLE_TEXT_ITEM],
  155. YSI_g_sUnusedEntry = 0,
  156. YSI_g_sDistributionID = -1,
  157. YSI_g_sUnusedSlot = 0,
  158. YSI_g_sCurLoadTextFile[64],
  159. //YSI_g_sCallbacks,
  160. YSI_g_sRemaining = sizeof (YSI_g_sTextStrings) * sizeof (YSI_g_sTextStrings[]),
  161. Language:YSI_g_sLangIndex;
  162. // OnFilterScriptInit
  163. // =============================================================================
  164. // | ========================================================================= |
  165. // | | | |
  166. // | | HERE STARTS THE LOADING CODE | |
  167. // | | | |
  168. // | ========================================================================= |
  169. // =============================================================================
  170. /*-------------------------------------------------------------------------*//**
  171. * <remarks>
  172. * This callback is hard coded in to YSI to be called absolutely last! Note
  173. * that this WAS hard coded, but now uses a more generic chaining method not
  174. * based on y_scriptinit and instead just uses the regular ALS method.
  175. * </remarks>
  176. *//*------------------------------------------------------------------------**/
  177. public OnGameModeInit()
  178. {
  179. P:1("TextInt_OnGameModeInit called");
  180. #if defined TextInt_OnGameModeInit
  181. TextInt_OnGameModeInit();
  182. #endif
  183. if (!YSI_FILTERSCRIPT)
  184. {
  185. //Text_SpecialInit();
  186. Text_RefreshLoaded();
  187. _Styles_SpecialInit();
  188. }
  189. P:1("TextInt_OnGameModeInit ended");
  190. return 1;
  191. }
  192. #if defined _ALS_OnGameModeInit
  193. #undef OnGameModeInit
  194. #else
  195. #define _ALS_OnGameModeInit
  196. #endif
  197. #define OnGameModeInit TextInt_OnGameModeInit
  198. #if defined TextInt_OnGameModeInit
  199. forward TextInt_OnGameModeInit();
  200. #endif
  201. public OnFilterScriptInit()
  202. {
  203. P:1("TextInt_OnFilterScriptInit called");
  204. // DO ALL (MOST) OTHER INITS FIRST. ENSURE WE COME LATER.
  205. #if defined TextInt_OnFilterScriptInit
  206. TextInt_OnFilterScriptInit();
  207. #endif
  208. //Text_SpecialInit();
  209. Text_RefreshLoaded();
  210. _Styles_SpecialInit();
  211. P:1("TextInt_OnFilterScriptInit ended");
  212. return 1;
  213. }
  214. #if defined _ALS_OnFilterScriptInit
  215. #undef OnFilterScriptInit
  216. #else
  217. #define _ALS_OnFilterScriptInit
  218. #endif
  219. #define OnFilterScriptInit TextInt_OnFilterScriptInit
  220. #if defined TextInt_OnFilterScriptInit
  221. forward TextInt_OnFilterScriptInit();
  222. #endif
  223. //forward Text_SpecialInit();
  224. //
  225. //public Text_SpecialInit()
  226. //static stock Text_SpecialInit()
  227. //{
  228. // P:1("Text_SpecialInit called");
  229. // // Scan the AMX for all public functions of the type "XX@YY@NN@yX_". These
  230. // // are the declarations for included texts.
  231. // Text_RefreshLoaded();
  232. // _Styles_SpecialInit();
  233. // P:2("Text_SpecialInit ended");
  234. //}
  235. /*-------------------------------------------------------------------------*//**
  236. * <transition keep="true" target="y_text_ending : n" />
  237. * <transition keep="true" target="y_text_get_text : n" />
  238. * <transition keep="true" target="y_render_show : y_render_show_print" />
  239. *//*------------------------------------------------------------------------**/
  240. //static stock Text_GetDistributionID()
  241. hook OnScriptInit()
  242. {
  243. P:1("Text_OnScriptInit called");
  244. // Initialise.
  245. new
  246. i;
  247. for (i = 0; i != Y_TEXT_MAX_SETS; ++i)
  248. {
  249. YSI_g_sTextSets[i][e_TEXT_SETS_NAME][0] = '\1';
  250. YSI_g_sTextSets[i][e_TEXT_SETS_INDEX] = -1;
  251. }
  252. for (i = 0; i != MAX_TEXT_ENTRIES; ++i)
  253. {
  254. YSI_g_sTextEntries[i][e_TEXT_ENTRY_HASH] = i + 1;
  255. }
  256. // Redirect all the pointers to the last cell.
  257. new
  258. offset = (sizeof (YSI_g_sTextStrings) - 1) * 4;
  259. i = (sizeof (YSI_g_sTextStrings[]) - 1) * 4;
  260. // Get the absolute address of the pointer to the last array.
  261. #emit CONST.pri YSI_g_sTextStrings
  262. #emit LOAD.S.alt offset
  263. #emit ADD
  264. // Get the data at that address (i.e. the RELATIVE pointer).
  265. #emit LOAD.I
  266. // Get the RELATIVE address of the last element.
  267. #emit LOAD.S.alt i
  268. #emit ADD
  269. #emit STOR.S.pri offset
  270. for (i = sizeof (YSI_g_sTextStrings) - 1; i != 0; --i)
  271. {
  272. //YSI_g_sTextStrings[i][0] = i + 1;
  273. #emit CONST.pri YSI_g_sTextStrings
  274. #emit LOAD.S.alt i
  275. #emit SHL.C.alt 2
  276. #emit ADD
  277. #emit MOVE.alt
  278. #emit LOAD.S.pri offset
  279. #emit STOR.I
  280. #emit ADD.C 4
  281. #emit STOR.S.pri offset
  282. }
  283. offset = getproperty(8, YSIM_TEXT_D);
  284. i = 0;
  285. while (i != 32)
  286. {
  287. if (!(offset & (1 << i)))
  288. {
  289. YSI_g_sDistributionID = i;
  290. offset |= 1 << i;
  291. break;
  292. }
  293. ++i;
  294. }
  295. if (i != 32)
  296. {
  297. setproperty(8, YSIM_TEXT_D, offset);
  298. }
  299. P:C(else P:E("y_text distribution ID not set"););
  300. CallRemoteFunction("Text_ResetLoaded", "");
  301. state y_text_ending : n;
  302. state y_text_get_text : n;
  303. state y_render_show : y_render_show_print;
  304. }
  305. /*-------------------------------------------------------------------------*//**
  306. * <transition keep="true" target="y_text_ending : y" />
  307. *//*------------------------------------------------------------------------**/
  308. hook OnScriptExit()
  309. {
  310. P:1("Textint_OnScriptExit called");
  311. new
  312. idx = 0,
  313. buffer[32],
  314. pos;
  315. while ((idx = AMX_GetPublicNameSuffix(idx, buffer, _A<@yX_>)))
  316. {
  317. pos = chrfind('@', buffer);
  318. if (pos != -1)
  319. {
  320. buffer[pos] = ':';
  321. pos = chrfind('@', buffer, pos);
  322. if (pos != -1)
  323. {
  324. buffer[pos] = '\0';
  325. if (existproperty(7, buffer) && getproperty(7, buffer) == TEXT_MASTER)
  326. {
  327. deleteproperty(7, buffer);
  328. }
  329. }
  330. }
  331. }
  332. state y_text_ending:y;
  333. CallRemoteFunction("Text_RefreshLoaded", "");
  334. }
  335. /*-------------------------------------------------------------------------*//**
  336. * <remarks>
  337. * When a mode ends this is called so that other scripts can know to re-load
  338. * any text which was previously owned by this script that they still need.
  339. * </remarks>
  340. *//*------------------------------------------------------------------------**/
  341. forward Text_ResetLoaded();
  342. public Text_ResetLoaded() <>
  343. {
  344. }
  345. public Text_ResetLoaded() <y_text_ending:n>
  346. {
  347. // Called to reset the owners of texts after a gamemode restart.
  348. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  349. {
  350. if (YSI_g_sTextSets[i][e_TEXT_SETS_NAME][0] != '\1')
  351. {
  352. setproperty(7, YSI_g_sTextSets[i][e_TEXT_SETS_NAME], TEXT_MASTER);
  353. }
  354. }
  355. }
  356. /*-------------------------------------------------------------------------*//**
  357. * <remarks>
  358. * Loops through all text definition functions in the mode (defined as:
  359. * "file@section@unique@yX_" (note that "@unique" is optional but irrelevant).
  360. * If any are found and the property "file:section" isn't defined claims
  361. * ownership of that section so that the text can be loaded in to this mode.
  362. * </remarks>
  363. *//*------------------------------------------------------------------------**/
  364. forward Text_RefreshLoaded();
  365. public Text_RefreshLoaded() <y_text_ending:y>
  366. {
  367. //printf("Text_RefreshLoaded: y");
  368. // Do nothing, only called for other scripts to check that all their text
  369. // items are still loaded.
  370. }
  371. public Text_RefreshLoaded() <y_text_ending:n>
  372. {
  373. //printf("Text_RefreshLoaded: n");
  374. if (Langs_GetLanguageCount() == Language:0)
  375. {
  376. P:E("No languages found - Did you add \"Langs_AddLanguage\" to the script init (NOT \"main\")?");
  377. }
  378. new
  379. idx = 0,
  380. buffer[32],
  381. pos;
  382. while ((idx = AMX_GetPublicNameSuffix(idx, buffer, _A<@yX_>)))
  383. {
  384. strunpack(buffer, buffer);
  385. pos = chrfind('@', buffer);
  386. //printf("%d, %x", pos, buffer[0]);
  387. if (pos != -1)
  388. {
  389. // Get rid of the end parts, doesn't matter if "Y_TEXT_UNIQUE" is
  390. // defined or not as EVERYTHING later is dropped.
  391. buffer[pos] = ':';
  392. pos = chrfind('@', buffer, pos);
  393. if (pos != -1)
  394. {
  395. buffer[pos] = '\0';
  396. //printf("buffer: %s %d", buffer, existproperty(7, buffer));
  397. //buffer[pos + 1] = '\0';
  398. if (!existproperty(7, buffer))
  399. {
  400. setproperty(7, buffer, TEXT_MASTER);
  401. Text_AddLocal(buffer, bernstein(buffer));
  402. }
  403. }
  404. }
  405. }
  406. Text_LoadLocals();
  407. }
  408. /*-------------------------------------------------------------------------*//**
  409. *//*------------------------------------------------------------------------**/
  410. static stock Text_AddLocal(buffer[], hash)
  411. {
  412. P:4("Text_AddLocal called: \"%s\", %i", buffer, hash);
  413. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  414. {
  415. if (YSI_g_sTextSets[i][e_TEXT_SETS_NAME][0] == '\1')
  416. {
  417. YSI_g_sTextSets[i][e_TEXT_SETS_HASH] = hash;
  418. strcpy(YSI_g_sTextSets[i][e_TEXT_SETS_NAME], buffer, 28);
  419. return;
  420. }
  421. }
  422. }
  423. /*-------------------------------------------------------------------------*//**
  424. *//*------------------------------------------------------------------------**/
  425. forward Text_INILoad(offset, tag[], name[], value[]);
  426. public Text_INILoad(offset, tag[], name[], value[])
  427. {
  428. // Get the path.
  429. // Get the file.
  430. // Get the extension.
  431. P:5("Text_INILoad called: %d, %s, %s, %s", offset, tag, name, value);
  432. P:5("Text_INILoad: IsPacked? %08x%08x", value[0], value[1]);
  433. new
  434. fname[sizeof (YSI_g_sCurLoadTextFile) - (3 + 9)],
  435. len = strlen(YSI_g_sCurLoadTextFile);
  436. //format(fname, sizeof (fname
  437. strcpy(fname, YSI_g_sCurLoadTextFile[9], len - (3 + 9 - 1));
  438. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  439. {
  440. //printf("fname: %s, %d, %d, %s", fname, len, offset, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]);
  441. if (!strcmp(YSI_g_sTextSets[i][e_TEXT_SETS_NAME], fname, true, offset - 1) && !strcmp(YSI_g_sTextSets[i][e_TEXT_SETS_NAME][offset], tag, true))
  442. {
  443. //printf("%d \"%s\" \"%s\" \"%s\"", len, fname, YSI_g_sCurLoadTextFile[len - 2], tag);
  444. len = strlen(name);
  445. new
  446. slot = name[--len],
  447. number,
  448. hash = 1;
  449. P:6("Text_INILoad: Get Number");
  450. while ('0' <= slot <= '9')
  451. {
  452. name[len] = '\0';
  453. number += (slot - '0') * hash;
  454. hash *= 10;
  455. slot = name[--len];
  456. }
  457. // So "MY_TEXT_1" becomes "MY_TEXT", not "MY_TEXT_".
  458. if (slot == '_')
  459. {
  460. name[len] = '\0';
  461. }
  462. hash = bernstein(name);
  463. slot = Text_FindEntry(YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], hash);
  464. P:6("Text_INILoad: Check slot %d", slot);
  465. if (slot == -1)
  466. {
  467. Text_AddEntry(i, name, value, hash);
  468. //P:5("%d,%d,%d,%d,%d", YSI_g_sTextStrings[ss][0], YSI_g_sTextStrings[ss][1], YSI_g_sTextStrings[ss][2], YSI_g_sTextStrings[ss][3], YSI_g_sTextStrings[ss][4]);
  469. }
  470. else
  471. {
  472. P:6("Text_INILoad: Check Collision");
  473. if (strcmp(name, YSI_g_sTextEntries[slot][e_TEXT_ENTRY_NAME], true))
  474. {
  475. P:E("Text collision on \"%s\" and \"%s\"!", name, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]);
  476. return;
  477. }
  478. else if (YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex] == -1)
  479. {
  480. new
  481. ss = Text_GetFreeSlot();
  482. if (ss == -1)
  483. {
  484. P:E("Text buffer full!");
  485. return;
  486. }
  487. //strpack(YSI_g_sTextStrings[ss], value, MAX_INI_ENTRY_TEXT * 4);
  488. Text_UpdateFreeSlot(Format_Standardise(value, YSI_g_sTextStrings[ss], MAX_INI_ENTRY_TEXT));
  489. //P:5("%d,%d,%d,%d,%d", YSI_g_sTextStrings[ss][0], YSI_g_sTextStrings[ss][1], YSI_g_sTextStrings[ss][2], YSI_g_sTextStrings[ss][3], YSI_g_sTextStrings[ss][4]);
  490. //strcpy(YSI_g_sTextStrings[ss], value, MAX_INI_ENTRY_TEXT * 4);
  491. YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex] = ss;
  492. }
  493. else if (number)
  494. {
  495. // Found a string with multiple entries in the INI file to
  496. // be linked together dynamically.
  497. new
  498. ss = Text_GetFreeSlot();
  499. if (ss == -1)
  500. {
  501. P:E("Text buffer full!");
  502. return;
  503. }
  504. Text_UpdateFreeSlot(Format_Standardise(value, YSI_g_sTextStrings[ss], MAX_INI_ENTRY_TEXT));
  505. hash = YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex];
  506. if (hash == -1)
  507. {
  508. // Will happen when the text entry exists in other
  509. // languages but not yet in this one.
  510. YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex] = ss;
  511. }
  512. else if (number == 1)
  513. {
  514. YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex] = ss;
  515. len = strlen(YSI_g_sTextStrings[ss]);
  516. //if (len < sizeof (YSI_g_sTextStrings[]) - 2)
  517. //{
  518. // Add the linked list.
  519. Text_DoLinkedText(YSI_g_sTextStrings[ss], hash, len);
  520. //}
  521. //else
  522. //{
  523. // P:W("Text size error on \"%s\"!", name);
  524. //}
  525. }
  526. else
  527. {
  528. // Add the string to the chain.
  529. slot = 2;
  530. len = strlen(YSI_g_sTextStrings[hash]);
  531. // Loop through existing strings in this list till we
  532. // find the right position (either the specified ID or
  533. // the last item) at which to add the new string.
  534. while (slot < number)
  535. {
  536. if (len < 2)
  537. {
  538. break;
  539. }
  540. //if (YSI_g_sTextStrings[hash][len - 2] != '\05')
  541. //{
  542. // break;
  543. //}
  544. //hash = YSI_g_sTextStrings[hash][len - 1];
  545. if (!Text_GetLinkedText(YSI_g_sTextStrings[hash], hash, len))
  546. {
  547. break;
  548. }
  549. len = strlen(YSI_g_sTextStrings[hash]);
  550. ++slot;
  551. }
  552. if (len < 2)
  553. {
  554. Text_DoLinkedText(YSI_g_sTextStrings[hash], ss, len);
  555. }
  556. //else if (YSI_g_sTextStrings[hash][len - 2] == '\05')
  557. else if (Text_HasLinkedText(YSI_g_sTextStrings[hash], len))
  558. {
  559. slot = Text_UpdateLinkedText(YSI_g_sTextStrings[hash], ss, len);
  560. //slot = YSI_g_sTextStrings[hash][len - 1];
  561. //YSI_g_sTextStrings[hash][len - 1] = ss;
  562. len = strlen(YSI_g_sTextStrings[ss]);
  563. //if (len < sizeof (YSI_g_sTextStrings[]) - 2)
  564. //{
  565. // // Add the linked list.
  566. // YSI_g_sTextStrings[ss][len] = '\05';
  567. // YSI_g_sTextStrings[ss][len + 1] = slot;
  568. // YSI_g_sTextStrings[ss][len + 2] = '\0';
  569. Text_DoLinkedText(YSI_g_sTextStrings[ss], slot, len);
  570. //}
  571. //else
  572. //{
  573. // P:W("Text size error on \"%s\"!", name);
  574. //}
  575. }
  576. else
  577. {
  578. //if (len < sizeof (YSI_g_sTextStrings[]) - 2)
  579. //{
  580. // // Add the linked list.
  581. // YSI_g_sTextStrings[hash][len] = '\05';
  582. // YSI_g_sTextStrings[hash][len + 1] = ss;
  583. // YSI_g_sTextStrings[hash][len + 2] = '\0';
  584. Text_DoLinkedText(YSI_g_sTextStrings[hash], ss, len);
  585. //}
  586. //else
  587. //{
  588. // P:W("Text size error on \"%s\"!", name);
  589. //}
  590. }
  591. }
  592. }
  593. else
  594. {
  595. P:W("Text repeat on \"%s\"!", name);
  596. }
  597. }
  598. // Add the current value to the current tag.
  599. break;
  600. }
  601. }
  602. }
  603. /*-------------------------------------------------------------------------*//**
  604. *//*------------------------------------------------------------------------**/
  605. static stock Text_LoadLocals()
  606. {
  607. //printf("Text_LoadLocals called");
  608. P:4("Text_LoadLocals called");
  609. // This is the interesting part. Load all the sets which have a name not
  610. // '\1' and an index of -1.
  611. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  612. {
  613. P:6("Text_LoadLocals: i = %d, text = %s, %d, %d", i, YSI_g_sTextSets[i][e_TEXT_SETS_NAME], YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], YSI_g_sTextSets[i][e_TEXT_SETS_HASH]);
  614. if (YSI_g_sTextSets[i][e_TEXT_SETS_INDEX] == -1 && YSI_g_sTextSets[i][e_TEXT_SETS_HASH])
  615. {
  616. new
  617. offset = chrfind(':', YSI_g_sTextSets[i][e_TEXT_SETS_NAME]) + 1,
  618. j = i + 1;
  619. while (j != Y_TEXT_MAX_SETS)
  620. {
  621. if (YSI_g_sTextSets[j][e_TEXT_SETS_INDEX] == -1 && YSI_g_sTextSets[j][e_TEXT_SETS_HASH] && !strcmp(YSI_g_sTextSets[i][e_TEXT_SETS_NAME], YSI_g_sTextSets[j][e_TEXT_SETS_NAME], false, offset))
  622. {
  623. break;
  624. }
  625. ++j;
  626. }
  627. // Only load a file one.
  628. if (j != Y_TEXT_MAX_SETS)
  629. {
  630. continue;
  631. }
  632. --offset;
  633. //YSI_g_sTextSets[i][e_TEXT_SETS_NAME][offset] = '\0';
  634. YSI_g_sLangIndex = Language:0;
  635. new
  636. langs[YSI_MAX_STRING],
  637. pos;
  638. langs = Langs_GetLanguageCodes();
  639. while ((pos = chrfind('|', langs, pos)) != -1)
  640. {
  641. format(YSI_g_sCurLoadTextFile, sizeof (YSI_g_sCurLoadTextFile), "YSI/text/%.*s.%.2s", offset, YSI_g_sTextSets[i][e_TEXT_SETS_NAME], langs[pos - 2]);
  642. INI_ParseFile(YSI_g_sCurLoadTextFile, "Text_INILoad", _, true, offset + 1, _, true);
  643. ++YSI_g_sLangIndex;
  644. ++pos;
  645. // We can add code here to load the data from y_styles.
  646. }
  647. //format(YSI_g_sCurLoadTextFile, sizeof (YSI_g_sCurLoadTextFile), "%.*s", offset, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]);
  648. P:6("Text_LoadLocals: Loading style %s (%d)", YSI_g_sCurLoadTextFile, offset);
  649. //_Styles_ParseOne(YSI_g_sCurLoadTextFile);
  650. //YSI_g_sTextSets[i][e_TEXT_SETS_NAME][offset] = ':';
  651. }
  652. }
  653. }
  654. /*-------------------------------------------------------------------------*//**
  655. *//*------------------------------------------------------------------------**/
  656. /*-------------------------------------------------------------------------*//**
  657. *//*------------------------------------------------------------------------**/
  658. forward Text_CheckLoad(buffer[], hash);
  659. public Text_CheckLoad(buffer[], hash) <y_text_ending:y>
  660. {
  661. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  662. {
  663. YSI_g_sTextSets[i][e_TEXT_SETS_HASH] = 0;
  664. YSI_g_sTextSets[i][e_TEXT_SETS_NAME][0] = '\1';
  665. YSI_g_sTextSets[i][e_TEXT_SETS_NAME][1] = '\0';
  666. }
  667. }
  668. public Text_CheckLoad(buffer[], hash) <y_text_ending:n>
  669. {
  670. // Check if another script is already in charge of this set.
  671. if (getproperty(8, "T_CL"))
  672. {
  673. return;
  674. }
  675. // Nope, are we?
  676. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  677. {
  678. if (hash == YSI_g_sTextSets[i][e_TEXT_SETS_HASH] && !strcmp(buffer, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]))
  679. {
  680. setproperty(8, "T_CL", 1);
  681. return;
  682. }
  683. }
  684. }
  685. /*-------------------------------------------------------------------------*//**
  686. * <param name="master">The script which owns this string.</param>
  687. * <param name="index">The slot in which this string is stored.</param>
  688. * <param name="str">The string to display.</param>
  689. * <param name="len0">The length of the string array.</param>
  690. * <param name="style">The style of the string.</param>
  691. * <param name="len1">The length of the style array.</param>
  692. * <param name="label">The 3D label style of the string.</param>
  693. * <param name="len2">The length of the 3D array.</param>
  694. * <remarks>
  695. * This function is used to pass data from the owner script to the script
  696. * which is doing the display. It passes the string to format (as an array,
  697. * not as a string, to keep the non-standard characters). A copy of the style
  698. * data, any 3D text label style data, the index and the master ID. Note that
  699. * TD data isn't handled here - if there is need to use a text draw the script
  700. * will have to call to the remote script for display functions. TD data is
  701. * loaded in all scripts where it is relevant. This does mean that if people
  702. * modify a style we need to modify it in ALL scripts.
  703. *
  704. * TODO: Modify the y_text system to store copies of required strings in all
  705. * modes, just because it's slightly better.
  706. * </remarks>
  707. *//*------------------------------------------------------------------------**/
  708. forward Text_ReturnTheText(master, index, str[], len0, style[E_STYLE_DATA], len1, label[E_3D_DATA], len2);
  709. public Text_ReturnTheText(master, index, str[], len0, style[E_STYLE_DATA], len1, label[E_3D_DATA], len2) <y_text_get_text:n>
  710. {
  711. }
  712. public Text_ReturnTheText(master, index, str[], len0, style[E_STYLE_DATA], len1, label[E_3D_DATA], len2) <y_text_get_text:y>
  713. {
  714. P:4("Text_ReturnTheText called: %d,%d,%d,%d,%d len = %d (%s)", str[0], str[1], str[2], str[3], str[4], len0, str);
  715. strcpy(YSI_g_sReturnText, str, len0);
  716. setproperty(8, YSIM_TXTLEN, _Format_SetStyleData(master, index, style, label));
  717. }
  718. /*-------------------------------------------------------------------------*//**
  719. * <param name="file">File to check.</param>
  720. * <param name="str">Section name to check.</param>
  721. * <returns>
  722. * Does this script own the named section in the current file?
  723. * </returns>
  724. * <remarks>
  725. * Sets "YSI_g_sReturnText" for use in "_Text_LookupName" too.
  726. * </remarks>
  727. *//*------------------------------------------------------------------------**/
  728. stock _Text_CheckOwnership(file[], str[])
  729. {
  730. P:4("_Text_CheckOwnership called: %s, %s", file, str);
  731. format(YSI_g_sReturnText, sizeof (YSI_g_sReturnText), "%s:%s", file, str);
  732. return existproperty(7, YSI_g_sReturnText) && (getproperty(7, YSI_g_sReturnText) == TEXT_MASTER);
  733. }
  734. /*-------------------------------------------------------------------------*//**
  735. * <param name="name">Name of the string to look up.</param>
  736. * <returns>
  737. * Slot storing the pointers for the named section.
  738. * </returns>
  739. * <remarks>
  740. * Assumes this script owns the section based on previously having called
  741. * "_Text_CheckOwnership". This is assumed as both functions are called from
  742. * only y_styles (hence the private naming convention). Note that the string
  743. * "YSI_g_sReturnText" is set in "_Text_CheckOwnership" because we make
  744. * guarantees about the order in which these functions are called.
  745. * </remarks>
  746. *//*------------------------------------------------------------------------**/
  747. stock _Text_LookupName(name[])
  748. {
  749. P:4("_Text_LookupName called: %s, %s", name, YSI_g_sReturnText);
  750. //format(YSI_g_sReturnText, sizeof (YSI_g_sReturnText), "%s:%s", YSI_g_sCurLoadTextFile, str);
  751. new
  752. sh = bernstein(YSI_g_sReturnText);
  753. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  754. {
  755. if (sh == YSI_g_sTextSets[i][e_TEXT_SETS_HASH] && !strcmp(YSI_g_sReturnText, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]))
  756. {
  757. // Got the start slot.
  758. return Text_FindEntry(YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], bernstein(name));
  759. }
  760. }
  761. return -1;
  762. }
  763. /*-------------------------------------------------------------------------*//**
  764. * <param name="str">String to be returned.</param>
  765. * <param name="len0">The length of the string.</param>
  766. * <remarks>
  767. * This function, along with _Text_RemoteSingle, is used to get a single string
  768. * from a remote script when the exact ID is known in advance and no other data
  769. * like stlyes are required.
  770. * </remarks>
  771. *//*------------------------------------------------------------------------**/
  772. forward _Text_ReturnSingle(str[], len0);
  773. public _Text_ReturnSingle(str[], len0) <y_text_get_text : n>
  774. {
  775. }
  776. public _Text_ReturnSingle(str[], len0) <y_text_get_text : y>
  777. {
  778. #pragma unused len0
  779. strcpy(YSI_g_sExtraText, str);
  780. }
  781. forward _Text_RemoteSingle(master, id);
  782. public _Text_RemoteSingle(master, id)
  783. {
  784. if (master == TEXT_MASTER)
  785. {
  786. CallRemoteFunction("_Text_ReturnSingle", "ai", YSI_g_sTextStrings[id], MAX_SINGLE_TEXT_ITEM); //sizeof (YSI_g_sTextStrings[]));
  787. }
  788. }
  789. /*-------------------------------------------------------------------------*//**
  790. * <transition keep="true" target="y_text_get_text : y" />
  791. * <transition keep="true" target="y_text_get_text : n" />
  792. *//*------------------------------------------------------------------------**/
  793. stock _Text_GetPointer(master, id)
  794. {
  795. if (master == TEXT_MASTER)
  796. {
  797. //new
  798. // ret = id * sizeof (YSI_g_sTextStrings[]);
  799. //printf("%d", ret);
  800. #emit CONST.alt YSI_g_sTextStrings
  801. #emit LOAD.S.pri id
  802. #emit IDXADDR
  803. #emit MOVE.alt
  804. #emit LOAD.i
  805. #emit ADD
  806. #emit RETN
  807. }
  808. state y_text_get_text : y;
  809. CallRemoteFunction("_Text_RemoteSingle", "ii", master, id);
  810. state y_text_get_text : n;
  811. #emit CONST.pri YSI_g_sExtraText
  812. #emit RETN
  813. //#emit STOR.S.pri ret
  814. //printf("%d", ret);
  815. // Never actually called, but shuts up the compiler
  816. return id;
  817. }
  818. /*-------------------------------------------------------------------------*//**
  819. * <param name="search">Search blocks to look in.</param>
  820. * <param name="nh">Hash of the string name to find.</param>
  821. * <param name="l">Language in which to get the text.</param>
  822. * <remarks>
  823. * Gets a string in a language from a hash and a text set.
  824. * </remarks>
  825. *//*------------------------------------------------------------------------**/
  826. forward Text_GetStandard(search[], nh, Language:l);
  827. public Text_GetStandard(search[], nh, Language:l)
  828. {
  829. if (getproperty(8, YSIM_TXTFND) != -1)
  830. {
  831. return;
  832. }
  833. if (getproperty(7, search) != TEXT_MASTER)
  834. {
  835. return;
  836. }
  837. P:4("Text_GetStandard called");
  838. new
  839. sh = bernstein(search);//,
  840. //fail[MAX_INI_ENTRY_TEXT] = "String not found";
  841. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  842. {
  843. P:7("Text_GetStandard: %d, %d, %d", i, sh, YSI_g_sTextSets[i][e_TEXT_SETS_HASH]);
  844. if (sh == YSI_g_sTextSets[i][e_TEXT_SETS_HASH] && !strcmp(search, YSI_g_sTextSets[i][e_TEXT_SETS_NAME]))
  845. {
  846. // Got the start slot.
  847. new
  848. slot = Text_FindEntry(YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], nh);
  849. P:7("Text_GetStandard: found %d, %d, %d", YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], nh, slot);
  850. if (slot != -1)
  851. {
  852. new
  853. pointer = YSI_g_sTextEntries[slot][e_TEXT_ENTRY_POINTERS][l];
  854. P:5("Text_GetStandard: %d, %d, %d, %d", slot, pointer, getproperty(8, YSIM_TXTIND), _@);
  855. if (pointer != -1)
  856. {
  857. //P:5("Text_GetStandard: %08x%08x%08x%08x%08x", YSI_g_sTextStrings[pointer][0], YSI_g_sTextStrings[pointer][1], YSI_g_sTextStrings[pointer][2], YSI_g_sTextStrings[pointer][3], YSI_g_sTextStrings[pointer][4]);
  858. //setproperty(9, "", YSIM_STRING, YSI_g_sTextStrings[pointer]);
  859. setproperty(8, YSIM_TXTFND, _@);
  860. // I reckon this is the only time these functions have ever
  861. // been used together directly...
  862. P:5("Text_GetStandard: %s", YSI_g_sTextStrings[pointer]);
  863. //SetPVarString(getproperty(8, YSIM_TXTIND), "YSI_g_sString", YSI_g_sTextStrings[pointer]);
  864. //printf("%d %d %d %d %d = %d", YSI_g_sTextStrings[pointer][0], YSI_g_sTextStrings[pointer][1], YSI_g_sTextStrings[pointer][2], YSI_g_sTextStrings[pointer][3], YSI_g_sTextStrings[pointer][4], strlen(YSI_g_sTextStrings[pointer]));
  865. // TODO: Fix this for the new parameter list.
  866. new
  867. style[E_STYLE_DATA],
  868. label[E_3D_DATA];
  869. Styles_GetData(slot, style, label);
  870. CallRemoteFunction("Text_ReturnTheText", "iiaiaiai", TEXT_MASTER, pointer, YSI_g_sTextStrings[pointer], MAX_SINGLE_TEXT_ITEM /*sizeof (YSI_g_sTextStrings[])*/, style, _:E_STYLE_DATA, label, _:E_3D_DATA);
  871. //format(fail, sizeof (fail), "%s", YSI_g_sTextStrings[pointer]);
  872. //printf("fail: %s", fail);
  873. //break;
  874. return;
  875. }
  876. }
  877. break;
  878. }
  879. }
  880. //static const
  881. // fail[MAX_INI_ENTRY_TEXT] = "\1";
  882. //setproperty(9, "", YSIM_STRING, "\1");
  883. //return fail;
  884. }
  885. /*-------------------------------------------------------------------------*//**
  886. * <param name="search">A "|" separated list of files and sections to search in.</param>
  887. * <param name="name">The text entry to look for.</param>
  888. * <param name="l">The language to get.</param>
  889. * <returns>
  890. * The specified string in the specified language.
  891. * </returns>
  892. * <remarks>
  893. * Uses "YSI_g_sReturnText" instead of a normal return because this may call
  894. * remote scripts which will need to return a standardised string as an array
  895. * to preserve all the non-standard characters (passing data as a string using
  896. * __CallRemoteFunction packs the string, which we don't want).
  897. * </remarks>
  898. * <transition keep="true" target="y_text_get_text : y" />
  899. * <transition keep="true" target="y_text_get_text : n" />
  900. * <transition keep="true" target="y_text_get_text : n" />
  901. *//*------------------------------------------------------------------------**/
  902. // Get the loaded standardised version of this string.
  903. //forward Text_GetStandard(start[] name[], Language:l);
  904. static stock Text_GetText(search[], name[], Language:l)
  905. {
  906. /*new
  907. start = Text_GetProvider(search),
  908. slot = Text_FindEntry(*/
  909. // TODO: Parse multiple search strings.
  910. //search[strlen(search) - 1] = '\0';
  911. //new loops = 0;
  912. //static
  913. // ret[MAX_INI_ENTRY_TEXT];
  914. new
  915. pos,
  916. lst;
  917. state y_text_get_text:y;
  918. setproperty(8, YSIM_TXTFND, -1);
  919. //setproperty(8, YSIM_TXTIND, index);
  920. while (search[lst])
  921. {
  922. pos = strfind(search[lst], "|");
  923. P:7("Text_GetText: loop1 %s %d %d %s %d", search, lst, pos, search[lst], search[lst + pos + 1]);
  924. search[lst + pos] = '\0';
  925. if (existproperty(7, search[lst]))
  926. {
  927. // Only call other scripts if ANYONE owns this search.
  928. CallRemoteFunction("Text_GetStandard", "sii", search[lst], bernstein(name), _:l);
  929. //P:7("Text_GetText: loop2 %s %d %d %s %d %d", search, lst, pos, search[lst], search[pos + 1], ret[0]);
  930. search[lst + pos] = '|';
  931. //if (ret[0] != '\1')
  932. if (getproperty(8, YSIM_TXTFND) != -1)
  933. {
  934. //getproperty(9, "", YSIM_STRING, ret);
  935. //strunpack(ret, ret)
  936. //GetPVarString(index, "YSI_g_sString", ret, MAX_INI_ENTRY_TEXT);
  937. state y_text_get_text:n;
  938. return;// ret;
  939. }
  940. }
  941. lst += pos + 1;
  942. //if (++loops == 10) break;
  943. //break;
  944. }
  945. //if (ret[0] == '\1')
  946. {
  947. // Need better error reporting here.
  948. YSI_g_sReturnText = "Text Not Found";
  949. }
  950. state y_text_get_text:n;
  951. return;// ret;
  952. }
  953. /*-------------------------------------------------------------------------*//**
  954. *//*------------------------------------------------------------------------**/
  955. // To be public.
  956. //stock Text_GetProvider(search[])
  957. //{
  958. //}
  959. static stock Text_FindEntry(start, hash)
  960. {
  961. P:4("Text_FindEntry called: %i, %i", start, hash);
  962. while (start != -1)
  963. {
  964. new
  965. cmp = YSI_g_sTextEntries[start][e_TEXT_ENTRY_HASH] - hash;
  966. if (cmp < 0)
  967. {
  968. start = YSI_g_sTextEntries[start][e_TEXT_ENTRY_RIGHT];
  969. }
  970. else if (cmp > 0)
  971. {
  972. start = YSI_g_sTextEntries[start][e_TEXT_ENTRY_LEFT];
  973. }
  974. else
  975. {
  976. return start;
  977. }
  978. }
  979. return -1;
  980. }
  981. /*-------------------------------------------------------------------------*//**
  982. *//*------------------------------------------------------------------------**/
  983. static stock Text_AddEntry(set, name[], value[], hash)
  984. {
  985. P:4("Text_AddEntry called: %i, \"%s\", \"%s\", %i", set, name, value, hash);
  986. new
  987. entry = Text_GetFreeEntry(),
  988. slot = Text_GetFreeSlot();
  989. if (entry == -1 || slot == -1)
  990. {
  991. P:E("Text buffer full!");
  992. return;
  993. }
  994. // Save the string.
  995. //strpack(YSI_g_sTextStrings[slot], value, MAX_INI_ENTRY_TEXT * 4);
  996. Text_UpdateFreeSlot(Format_Standardise(value, YSI_g_sTextStrings[slot], YSI_g_sRemaining));
  997. //strpack(YSI_g_sTextStrings[slot], value, MAX_INI_ENTRY_TEXT * 4);
  998. //strcpy(YSI_g_sTextStrings[slot], value, MAX_INI_ENTRY_TEXT * 4);
  999. // Save the identifier.
  1000. P:5("Text_AddEntry: slot = %d %d,%d,%d,%d,%d", slot, YSI_g_sTextStrings[slot][0], YSI_g_sTextStrings[slot][1], YSI_g_sTextStrings[slot][2], YSI_g_sTextStrings[slot][3], YSI_g_sTextStrings[slot][4]);
  1001. strpack(YSI_g_sTextEntries[entry][e_TEXT_ENTRY_NAME], name, MAX_INI_ENTRY_NAME * 4);
  1002. //strcpy(YSI_g_sTextEntries[entry][e_TEXT_ENTRY_NAME], name, MAX_INI_ENTRY_NAME * 4);
  1003. YSI_g_sTextEntries[entry][e_TEXT_ENTRY_HASH] = hash;
  1004. YSI_g_sTextEntries[entry][e_TEXT_ENTRY_POINTERS][YSI_g_sLangIndex] = slot;
  1005. // Set the default style.
  1006. _Style_Init(entry);
  1007. // Insert the identifier.
  1008. new
  1009. idx = YSI_g_sTextSets[set][e_TEXT_SETS_INDEX],
  1010. next;
  1011. if (idx == -1)
  1012. {
  1013. YSI_g_sTextSets[set][e_TEXT_SETS_INDEX] = entry;
  1014. }
  1015. else
  1016. {
  1017. for ( ; ; )
  1018. {
  1019. new
  1020. cmp = YSI_g_sTextEntries[idx][e_TEXT_ENTRY_HASH] - hash;
  1021. if (cmp < 0)
  1022. {
  1023. next = YSI_g_sTextEntries[idx][e_TEXT_ENTRY_RIGHT];
  1024. if (next == -1)
  1025. {
  1026. YSI_g_sTextEntries[idx][e_TEXT_ENTRY_RIGHT] = entry;
  1027. return;
  1028. }
  1029. }
  1030. else if (cmp > 0)
  1031. {
  1032. next = YSI_g_sTextEntries[idx][e_TEXT_ENTRY_LEFT];
  1033. if (next == -1)
  1034. {
  1035. YSI_g_sTextEntries[idx][e_TEXT_ENTRY_LEFT] = entry;
  1036. return;
  1037. }
  1038. }
  1039. idx = next;
  1040. }
  1041. }
  1042. }
  1043. /*-------------------------------------------------------------------------*//**
  1044. *//*------------------------------------------------------------------------**/
  1045. static stock Text_GetFreeSlot()
  1046. {
  1047. if (YSI_g_sUnusedSlot == MAX_TEXT_ENTRIES * _:YSI_MAX_LANGUAGES)
  1048. {
  1049. return -1;
  1050. }
  1051. return YSI_g_sUnusedSlot++;
  1052. /*P:4("Text_GetFreeSlot called");
  1053. if (YSI_g_sUnusedSlot == MAX_TEXT_ENTRIES * _:YSI_MAX_LANGUAGES)
  1054. {
  1055. return -1;
  1056. }
  1057. new
  1058. ret = YSI_g_sUnusedSlot;
  1059. YSI_g_sUnusedSlot = YSI_g_sTextStrings[ret][0];
  1060. YSI_g_sTextStrings[ret][0] = '\0';
  1061. return ret;*/
  1062. }
  1063. /*-------------------------------------------------------------------------*//**
  1064. * <param name="len">Length to make the array slot.</param>
  1065. * <remarks>
  1066. * Adjusts the first index table in "YSI_g_sTextStrings" such that the next
  1067. * call to "Text_GetFreeSlot" will point to a non-zero length target string.
  1068. * </remarks>
  1069. *//*------------------------------------------------------------------------**/
  1070. static stock Text_UpdateFreeSlot(len)
  1071. {
  1072. YSI_g_sRemaining -= len + 3;
  1073. // Get the address of the previous slot's pointer.
  1074. #emit LOAD.pri YSI_g_sUnusedSlot
  1075. #emit ADD.C 0xFFFFFFFF
  1076. #emit SHL.C.pri 2
  1077. #emit CONST.alt YSI_g_sTextStrings
  1078. #emit ADD
  1079. // Get the pointer to the start of the data.
  1080. #emit LOAD.I
  1081. // Get the pointer to the end of the data.
  1082. #emit LOAD.S.alt len
  1083. #emit SHL.C.alt 2
  1084. #emit ADD
  1085. // Add an offset for "\05" (NULL is implicit in the code because we get an
  1086. // extra four bytes of offset from shifting the index up a slot).
  1087. #emit ADD.C 12
  1088. // Temporarily store the data on the stack.
  1089. #emit PUSH.pri
  1090. // Now get the address of the slot of the CURRENT data.
  1091. #emit LOAD.pri YSI_g_sUnusedSlot
  1092. #emit SHL.C.pri 2
  1093. #emit CONST.alt YSI_g_sTextStrings
  1094. #emit ADD
  1095. #emit MOVE.alt
  1096. // Retrieve the data and store it in the new index.
  1097. #emit POP.pri
  1098. #emit STOR.I
  1099. #emit RETN
  1100. //printf("%d %d", len, YSI_g_sUnusedSlot - 1);
  1101. // Bypass compiler warnings.
  1102. return len;
  1103. }
  1104. /*-------------------------------------------------------------------------*//**
  1105. * <remarks>
  1106. * Prints all the strings loaded by the system, including their data offsets
  1107. * and storage array lengths (cunning tightly packed array).
  1108. * </remarks>
  1109. *//*------------------------------------------------------------------------**/
  1110. stock Text_DebugAllText()
  1111. {
  1112. for (new i = 0; i != YSI_g_sUnusedSlot; ++i)
  1113. {
  1114. new
  1115. next,
  1116. cur;
  1117. printf("%d %d %d %d", i, cur, next, YSI_g_sUnusedSlot);
  1118. Text_GetCurNextOffset(i, cur, next);
  1119. printf("Offset: %d, Length: %d", cur, (next - cur) / 4);
  1120. printf("Text: %s", YSI_g_sTextStrings[i]);
  1121. }
  1122. }
  1123. static stock Text_GetCurNextOffset(i, &cur, &next)
  1124. {
  1125. // Get the address of the previous slot's pointer.
  1126. #emit LOAD.S.pri i
  1127. #emit SHL.C.pri 2
  1128. #emit CONST.alt YSI_g_sTextStrings
  1129. #emit ADD
  1130. // Get the pointer to the start of the data.
  1131. #emit LOAD.I
  1132. #emit SREF.S.pri cur
  1133. // Get the address of the previous slot's pointer.
  1134. #emit LOAD.S.pri i
  1135. #emit ADD.C 0x1
  1136. #emit SHL.C.pri 2
  1137. #emit CONST.alt YSI_g_sTextStrings
  1138. #emit ADD
  1139. // Get the pointer to the start of the data.
  1140. #emit LOAD.I
  1141. #emit SREF.S.pri next
  1142. }
  1143. /*-------------------------------------------------------------------------*//**
  1144. * <remarks>
  1145. * Bypass run-time OOB errors when -d0 is disabled. Set the initial "next"
  1146. * pointer on the end of the string.
  1147. * </remarks>
  1148. *//*------------------------------------------------------------------------**/
  1149. static stock Text_DoLinkedText(entry[], add, len)
  1150. {
  1151. entry[len] = '\05';
  1152. entry[len + 1] = add;
  1153. entry[len + 2] = '\0';
  1154. }
  1155. /*-------------------------------------------------------------------------*//**
  1156. * <remarks>
  1157. * Bypass run-time OOB errors when -d0 is disabled. Get and set the "next"
  1158. * pointer on the end of the string.
  1159. * </remarks>
  1160. *//*------------------------------------------------------------------------**/
  1161. static stock Text_UpdateLinkedText(entry[], add, len)
  1162. {
  1163. new
  1164. ret = entry[len - 1];
  1165. entry[len - 1] = add;
  1166. return ret;
  1167. }
  1168. /*-------------------------------------------------------------------------*//**
  1169. * <remarks>
  1170. * Bypass run-time OOB errors when -d0 is disabled. Get the "next" pointer on
  1171. * the end of the string.
  1172. * </remarks>
  1173. *//*------------------------------------------------------------------------**/
  1174. static stock Text_GetLinkedText(entry[], &ret, len)
  1175. {
  1176. if (entry[len - 2] != '\05')
  1177. {
  1178. return 0;
  1179. }
  1180. ret = entry[len - 1];
  1181. return 1;
  1182. }
  1183. /*-------------------------------------------------------------------------*//**
  1184. * <remarks>
  1185. * Bypass run-time OOB errors when -d0 is disabled. Check if there is a "next"
  1186. * pointer.
  1187. * </remarks>
  1188. *//*------------------------------------------------------------------------**/
  1189. static stock Text_HasLinkedText(entry[], len)
  1190. {
  1191. return (entry[len - 2] == '\05');
  1192. }
  1193. /*-------------------------------------------------------------------------*//**
  1194. *//*------------------------------------------------------------------------**/
  1195. static stock Text_GetFreeEntry()
  1196. {
  1197. P:4("Text_GetFreeEntry called");
  1198. if (YSI_g_sUnusedEntry == MAX_TEXT_ENTRIES)
  1199. {
  1200. return -1;
  1201. }
  1202. new
  1203. ret = YSI_g_sUnusedEntry;
  1204. YSI_g_sUnusedEntry = YSI_g_sTextEntries[ret][e_TEXT_ENTRY_HASH];
  1205. YSI_g_sTextEntries[ret][e_TEXT_ENTRY_HASH] = 0;
  1206. YSI_g_sTextEntries[ret][e_TEXT_ENTRY_LEFT] = -1;
  1207. YSI_g_sTextEntries[ret][e_TEXT_ENTRY_RIGHT] = -1;
  1208. // Reset text storage pointers.
  1209. for (new Language:i = Language:0; i != YSI_MAX_LANGUAGES; ++i)
  1210. {
  1211. YSI_g_sTextEntries[ret][e_TEXT_ENTRY_POINTERS][i] = -1;
  1212. }
  1213. return ret;
  1214. }
  1215. /*-------------------------------------------------------------------------*//**
  1216. * <remarks>
  1217. * Checks if the string we are trying to display is owned by the local script,
  1218. * and if so just use that pointer and text directly.
  1219. * </remarks>
  1220. *//*------------------------------------------------------------------------**/
  1221. static stock Text_IsLocalOwner(search[], ident[], &len)
  1222. {
  1223. // First, find out if this script owns it's own text for speed reasons, and
  1224. // if it does, save the handle to the text set.
  1225. switch (search[0])
  1226. {
  1227. case '\1', '\2':
  1228. {
  1229. return -1;
  1230. }
  1231. case '\3':
  1232. {
  1233. // TODO...
  1234. }
  1235. default:
  1236. {
  1237. //Text_GetText(search, ident, lang);
  1238. new
  1239. pos,
  1240. lst,
  1241. hash;
  1242. while (search[lst])
  1243. {
  1244. pos = strfind(search[lst], "|");
  1245. search[lst + pos] = '\0';
  1246. if (existproperty(7, search[lst]) && (getproperty(7, search[lst]) == TEXT_MASTER))
  1247. {
  1248. hash = bernstein(search[lst]);
  1249. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  1250. {
  1251. if (hash == YSI_g_sTextSets[i][e_TEXT_SETS_HASH] && !strcmp(search[lst], YSI_g_sTextSets[i][e_TEXT_SETS_NAME]))
  1252. {
  1253. new
  1254. ret = Text_FindEntry(YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], bernstein(ident));
  1255. if (ret != -1)
  1256. {
  1257. search[lst + pos] = '|';
  1258. new
  1259. style[E_STYLE_DATA],
  1260. label[E_3D_DATA];
  1261. Styles_GetData(ret, style, label);
  1262. len = _Format_SetStyleData(TEXT_MASTER, -1, style, label) - 1;
  1263. return ret;
  1264. }
  1265. }
  1266. }
  1267. }
  1268. search[lst + pos] = '|';
  1269. lst += pos + 1;
  1270. }
  1271. }
  1272. }
  1273. return -1;
  1274. }
  1275. static stock
  1276. YSI_g_sLangBuffer[YSI_MAX_LANGUAGES][MAX_SINGLE_TEXT_ITEM];
  1277. /*-------------------------------------------------------------------------*//**
  1278. * <param name="players">A representation of players to show to.</param>
  1279. * <param name="search">Text sets to look in for this string.</param>
  1280. * <param name="ident">The name of the string to look for (or the string itself).</param>
  1281. * <param name="">All the parameters to pass to the string.</param>
  1282. * <remarks>
  1283. * Main entry point for showing any sort of code to anyone.
  1284. *
  1285. * TODO: Change the code to push the parameters to Format_Render only once and
  1286. * reuse the resulting stack.
  1287. * </remarks>
  1288. *//*------------------------------------------------------------------------**/
  1289. stock _Text_Send(@PlayerSet:players, search[], ident[], GLOBAL_TAG_TYPES:...)
  1290. {
  1291. setproperty(8, YSIM_TXTLEN, 1023);
  1292. new
  1293. bool:wasOnce[YSI_MAX_LANGUAGES] = {false, ...},
  1294. n = (numargs() - 3) * 4,
  1295. maxlen,
  1296. owned = Text_IsLocalOwner(search, ident, maxlen);
  1297. // Loop through all the players passed to the function (however they were
  1298. // passed to the function). This uses "@PlayerArray" instead of
  1299. // "@PlayerVar" so that we can optimised for multiple languages. Now it
  1300. // uses "@PlayerSet" instead because that's the new one designed for
  1301. // situations like this in which we want direct access to the variable.
  1302. if (n)
  1303. {
  1304. new
  1305. arg_start,
  1306. arg_end;
  1307. // Load the real address of the last static parameter. Do this by
  1308. // loading the address of the parameter and then adding the value of
  1309. // [FRM] (frame pointer).
  1310. #emit CONST.alt ident
  1311. #emit LCTRL 5
  1312. #emit ADD
  1313. #emit STOR.S.pri arg_start
  1314. // Load the address of the last variable parameter. Do this by adding
  1315. // the number of variables on the value just loaded.
  1316. #emit LOAD.S.alt n
  1317. #emit ADD
  1318. #emit STOR.S.pri arg_end
  1319. // Push the variable arguments. This is done by loading the value of
  1320. // each one in reverse order and pushing them. I'd love to be able to
  1321. // rewrite this to use the values of pri and alt for comparison, instead
  1322. // of having or constantly reload two variables.
  1323. foreach (new playerid : PS(players))
  1324. //new playerid = 0;
  1325. {
  1326. new
  1327. Language:lang = Langs_GetPlayerLanguage(playerid);
  1328. if (lang == NO_LANGUAGE)
  1329. {
  1330. lang = Language:0;
  1331. }
  1332. if (wasOnce[lang])
  1333. {
  1334. // Optimisation for sending messages to multiple players.
  1335. Format_JustShow(playerid, YSI_g_sLangBuffer[lang]);
  1336. continue;
  1337. }
  1338. new
  1339. arg_cur = arg_end,
  1340. ret;
  1341. do
  1342. {
  1343. #emit LOAD.S.pri arg_cur
  1344. #emit LOAD.I
  1345. #emit PUSH.pri
  1346. arg_cur -= 4;
  1347. }
  1348. while (arg_cur > arg_start);
  1349. switch (search[0])
  1350. {
  1351. case '\1':
  1352. {
  1353. // Null - error.
  1354. P:E("Text_Send called with NULL");
  1355. }
  1356. case '\2':
  1357. {
  1358. // None - just print the string directly.
  1359. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, ident, n / 4);
  1360. }
  1361. case '\3':
  1362. {
  1363. if (owned == -1)
  1364. {
  1365. new
  1366. pos = strfind(ident, ">"),
  1367. br = strfind(ident, "[");
  1368. if (pos > 1 && br != -1)
  1369. {
  1370. ident[pos - 2] = '\0';
  1371. if (br)
  1372. {
  1373. ident[br] = ':';
  1374. Text_GetText(ident, ident[pos + 1], lang);
  1375. }
  1376. else
  1377. {
  1378. Text_GetText(ident[1], ident[pos + 1], lang);
  1379. }
  1380. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, YSI_g_sReturnText, n / 4);
  1381. }
  1382. else
  1383. {
  1384. // Var - May contain location search information in
  1385. // "name". Maybe add an "all" search parameter...
  1386. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, "Could not find text source", n / 4);
  1387. // The code generated messes up the pushing.
  1388. }
  1389. }
  1390. else
  1391. {
  1392. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1393. if (ret == -1)
  1394. {
  1395. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, "Language text not found", n / 4);
  1396. }
  1397. else
  1398. {
  1399. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, YSI_g_sTextStrings[ret], n / 4);
  1400. }
  1401. }
  1402. }
  1403. default:
  1404. {
  1405. if (owned == -1)
  1406. {
  1407. Text_GetText(search, ident, lang);
  1408. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, YSI_g_sReturnText, n / 4);
  1409. }
  1410. else
  1411. {
  1412. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1413. if (ret == -1)
  1414. {
  1415. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, "Language text not found", n / 4);
  1416. }
  1417. else
  1418. {
  1419. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, YSI_g_sTextStrings[ret], n / 4);
  1420. }
  1421. }
  1422. }
  1423. }
  1424. #emit LCTRL 4
  1425. #emit LOAD.S.alt n
  1426. #emit ADD
  1427. #emit SCTRL 4
  1428. wasOnce[lang] = !ret;
  1429. }
  1430. }
  1431. else
  1432. {
  1433. foreach (new playerid : PS(players))
  1434. {
  1435. new
  1436. Language:lang = Langs_GetPlayerLanguage(playerid);
  1437. if (wasOnce[lang])
  1438. {
  1439. // Optimisation for sending messages to multiple players.
  1440. Format_JustShow(playerid, YSI_g_sLangBuffer[lang]);
  1441. continue;
  1442. }
  1443. switch (search[0])
  1444. {
  1445. case '\1':
  1446. {
  1447. // Null - error.
  1448. P:E("Text_Send called with NULL");
  1449. }
  1450. case '\2':
  1451. {
  1452. // None - just print the string directly.
  1453. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, ident, 0);
  1454. }
  1455. case '\3':
  1456. {
  1457. new
  1458. pos = strfind(ident, ">"),
  1459. br = strfind(ident, "[");
  1460. if (pos > 1 && br != -1)
  1461. {
  1462. ident[pos - 2] = '\0';
  1463. if (br)
  1464. {
  1465. ident[br] = ':';
  1466. Text_GetText(ident, ident[pos + 1], lang);
  1467. }
  1468. else
  1469. {
  1470. Text_GetText(ident[1], ident[pos + 1], lang);
  1471. }
  1472. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, YSI_g_sReturnText, 0);
  1473. }
  1474. else
  1475. {
  1476. // Var - May contain location search information in
  1477. // "name". Maybe add an "all" search parameter...
  1478. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, "Could not find text source", 0);
  1479. }
  1480. }
  1481. default:
  1482. {
  1483. if (owned == -1)
  1484. {
  1485. Text_GetText(search, ident, lang);
  1486. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, 0, YSI_g_sReturnText, 0);
  1487. }
  1488. else
  1489. {
  1490. new
  1491. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1492. if (ret == -1)
  1493. {
  1494. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, "Language text not found", 0);
  1495. }
  1496. else
  1497. {
  1498. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, 0, YSI_g_sTextStrings[ret], 0);
  1499. }
  1500. }
  1501. }
  1502. }
  1503. }
  1504. }
  1505. Format_SetListSeparator(", ");
  1506. return Text_GetLastID();
  1507. }
  1508. /*-------------------------------------------------------------------------*//**
  1509. * <param name="search">Text sets to look in for this string.</param>
  1510. * <param name="ident">The name of the string to look for (or the string itself).</param>
  1511. * <param name="">All the parameters to pass to the string.</param>
  1512. * <remarks>
  1513. * This function renders some text to an array, but doesn't display it.
  1514. * </remarks>
  1515. *//*------------------------------------------------------------------------**/
  1516. stock Text_GetPreRender(Language:lang)
  1517. {
  1518. return YSI_g_sLangBuffer[lang];
  1519. }
  1520. stock _Text_Render(playerid, search[], ident[], GLOBAL_TAG_TYPES:...)
  1521. {
  1522. setproperty(8, YSIM_TXTLEN, 1023);
  1523. new
  1524. bool:wasOnce[YSI_MAX_LANGUAGES] = {false, ...},
  1525. n = (numargs() - 3) * 4,
  1526. maxlen,
  1527. owned = Text_IsLocalOwner(search, ident, maxlen);
  1528. // Loop through all the players passed to the function (however they were
  1529. // passed to the function). This uses "@PlayerArray" instead of
  1530. // "@PlayerVar" so that we can optimised for multiple languages. Now it
  1531. // uses "@PlayerSet" instead because that's the new one designed for
  1532. // situations like this in which we want direct access to the variable.
  1533. if (n)
  1534. {
  1535. new
  1536. arg_start,
  1537. arg_end;
  1538. // Load the real address of the last static parameter. Do this by
  1539. // loading the address of the parameter and then adding the value of
  1540. // [FRM] (frame pointer).
  1541. #emit CONST.alt ident
  1542. #emit LCTRL 5
  1543. #emit ADD
  1544. #emit STOR.S.pri arg_start
  1545. // Load the address of the last variable parameter. Do this by adding
  1546. // the number of variables on the value just loaded.
  1547. #emit LOAD.S.alt n
  1548. #emit ADD
  1549. #emit STOR.S.pri arg_end
  1550. // Push the variable arguments. This is done by loading the value of
  1551. // each one in reverse order and pushing them. I'd love to be able to
  1552. // rewrite this to use the values of pri and alt for comparison, instead
  1553. // of having or constantly reload two variables.
  1554. for (new Language:lang; lang != YSI_MAX_LANGUAGES; ++lang) if (Langs_IsValid(lang))
  1555. {
  1556. new
  1557. arg_cur = arg_end,
  1558. ret;
  1559. do
  1560. {
  1561. #emit LOAD.S.pri arg_cur
  1562. #emit LOAD.I
  1563. #emit PUSH.pri
  1564. arg_cur -= 4;
  1565. }
  1566. while (arg_cur > arg_start);
  1567. switch (search[0])
  1568. {
  1569. case '\1':
  1570. {
  1571. // Null - error.
  1572. P:E("Text_Send called with NULL");
  1573. }
  1574. case '\2':
  1575. {
  1576. // None - just print the string directly.
  1577. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, ident, n / 4);
  1578. }
  1579. case '\3':
  1580. {
  1581. if (owned == -1)
  1582. {
  1583. new
  1584. pos = strfind(ident, ">"),
  1585. br = strfind(ident, "[");
  1586. if (pos > 1 && br != -1)
  1587. {
  1588. ident[pos - 2] = '\0';
  1589. if (br)
  1590. {
  1591. ident[br] = ':';
  1592. Text_GetText(ident, ident[pos + 1], lang);
  1593. }
  1594. else
  1595. {
  1596. Text_GetText(ident[1], ident[pos + 1], lang);
  1597. }
  1598. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, n / 4);
  1599. }
  1600. else
  1601. {
  1602. // Var - May contain location search information in
  1603. // "name". Maybe add an "all" search parameter...
  1604. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, "Could not find text source", n / 4);
  1605. // The code generated messes up the pushing.
  1606. }
  1607. }
  1608. else
  1609. {
  1610. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1611. if (ret == -1)
  1612. {
  1613. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, "Language text not found", n / 4);
  1614. }
  1615. else
  1616. {
  1617. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, YSI_g_sTextStrings[ret], n / 4);
  1618. }
  1619. }
  1620. }
  1621. default:
  1622. {
  1623. if (owned == -1)
  1624. {
  1625. Text_GetText(search, ident, lang);
  1626. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, n / 4);
  1627. }
  1628. else
  1629. {
  1630. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1631. if (ret == -1)
  1632. {
  1633. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, "Language text not found", n / 4);
  1634. }
  1635. else
  1636. {
  1637. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, YSI_g_sTextStrings[ret], n / 4);
  1638. }
  1639. }
  1640. }
  1641. }
  1642. #emit LCTRL 4
  1643. #emit LOAD.S.alt n
  1644. #emit ADD
  1645. #emit SCTRL 4
  1646. wasOnce[lang] = !ret;
  1647. }
  1648. }
  1649. else
  1650. {
  1651. for (new Language:lang; lang != YSI_MAX_LANGUAGES; ++lang) if (Langs_IsValid(lang))
  1652. {
  1653. switch (search[0])
  1654. {
  1655. case '\1':
  1656. {
  1657. // Null - error.
  1658. P:E("Text_Send called with NULL");
  1659. }
  1660. case '\2':
  1661. {
  1662. // None - just print the string directly.
  1663. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, ident, 0);
  1664. }
  1665. case '\3':
  1666. {
  1667. new
  1668. pos = strfind(ident, ">"),
  1669. br = strfind(ident, "[");
  1670. if (pos > 1 && br != -1)
  1671. {
  1672. ident[pos - 2] = '\0';
  1673. if (br)
  1674. {
  1675. ident[br] = ':';
  1676. Text_GetText(ident, ident[pos + 1], lang);
  1677. }
  1678. else
  1679. {
  1680. Text_GetText(ident[1], ident[pos + 1], lang);
  1681. }
  1682. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1683. }
  1684. else
  1685. {
  1686. // Var - May contain location search information in
  1687. // "name". Maybe add an "all" search parameter...
  1688. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, "Could not find text source", 0);
  1689. }
  1690. }
  1691. default:
  1692. {
  1693. if (owned == -1)
  1694. {
  1695. Text_GetText(search, ident, lang);
  1696. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], getproperty(8, YSIM_TXTLEN) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1697. }
  1698. else
  1699. {
  1700. new
  1701. ret = YSI_g_sTextEntries[owned][e_TEXT_ENTRY_POINTERS][lang];
  1702. if (ret == -1)
  1703. {
  1704. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, "Language text not found", 0);
  1705. }
  1706. else
  1707. {
  1708. wasOnce[lang] = !Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], maxlen, 0, e_FORMAT_FLAGS_NONE, YSI_g_sTextStrings[ret], 0);
  1709. }
  1710. }
  1711. }
  1712. }
  1713. }
  1714. }
  1715. //return Text_GetLastID();
  1716. Format_SetListSeparator(", ");
  1717. }
  1718. static stock
  1719. YSI_g_sCaptionText[YSI_MAX_LANGUAGES][64],
  1720. YSI_g_sButton1Text[YSI_MAX_LANGUAGES][32],
  1721. YSI_g_sButton2Text[YSI_MAX_LANGUAGES][32];
  1722. /*-------------------------------------------------------------------------*//**
  1723. *//*------------------------------------------------------------------------**/
  1724. //stock @PlayerArray:players<MAX_PLAYERS>, callback[], csearch[], cident[], isearch[], iident[], b1search[], b1ident[], b2search[], b2ident[], GLOBAL_TAG_TYPES:...)
  1725. //stock _Text_MessageBox(@PlayerArray:players<MAX_PLAYERS>, callback[], csearch[], cident[], isearch[], iident[], b1search[], b1ident[], b2search[], b2ident[], GLOBAL_TAG_TYPES:...)
  1726. //stock _Text_MessageBox(@PlayerArray:players<MAX_PLAYERS>, callback[], csearch[], cident[], isearch[], iident[], b1search[], b1ident[], b2search[], b2ident[], GLOBAL_TAG_TYPES:...)
  1727. stock _Text_DialogBox(@PlayerSet:players, style, callback:callback, csearch[], cident[], isearch[], iident[], b1search[], b1ident[], b2search[], b2ident[], GLOBAL_TAG_TYPES:...)
  1728. //stock _Text_MessageBox(__ps_addr_t:__ps_addr, callback[], csearch[], cident[], isearch[], iident[], b1search[], b1ident[], b2search[], b2ident[], GLOBAL_TAG_TYPES:...)
  1729. {
  1730. // This is what the "@PlayerArray" macro expands to, but I needed more
  1731. // control to allow me to return a value. The fact that I can't ATM is a
  1732. // serious problem, but not serious enough to warrant fixing.
  1733. new
  1734. bool:wasOnce[YSI_MAX_LANGUAGES] = {false, ...},
  1735. bool:gotExtras[YSI_MAX_LANGUAGES] = {false, ...},
  1736. n = (numargs() - 11) * 4,
  1737. dialog = Dialog_ObtainID();//,
  1738. //maxlen,
  1739. //owned = Text_IsLocalOwner(isearch, iident, maxlen);
  1740. // Loop through all the players passed to the function (however they were
  1741. // passed to the function). This uses "@PlayerArray" instead of
  1742. // "@PlayerVar" so that we can optimised for multiple languages.
  1743. if (n)
  1744. {
  1745. new
  1746. arg_start,
  1747. arg_end;
  1748. // Load the real address of the last static parameter. Do this by
  1749. // loading the address of the parameter and then adding the value of
  1750. // [FRM] (frame pointer).
  1751. #emit CONST.alt b2ident
  1752. #emit LCTRL 5
  1753. #emit ADD
  1754. #emit STOR.S.pri arg_start
  1755. // Load the address of the last variable parameter. Do this by adding
  1756. // the number of variables on the value just loaded.
  1757. #emit LOAD.S.alt n
  1758. #emit ADD
  1759. #emit STOR.S.pri arg_end
  1760. // Push the variable arguments. This is done by loading the value of
  1761. // each one in reverse order and pushing them. I'd love to be able to
  1762. // rewrite this to use the values of pri and alt for comparison, instead
  1763. // of having or constantly reload two variables.
  1764. //for (new PlayerArray:players<MAX_PLAYERS>; __PS_A(_:__ps_addr, players); )
  1765. foreach (new playerid : PS(players))
  1766. {
  1767. new
  1768. Language:lang = Langs_GetPlayerLanguage(playerid);
  1769. if (lang == NO_LANGUAGE)
  1770. {
  1771. lang = Language:0;
  1772. }
  1773. // Only ever do this part once per language.
  1774. if (!gotExtras[lang])
  1775. {
  1776. // Get the text for the caption in this language.
  1777. switch (csearch[0])
  1778. {
  1779. case '\1': P:E("Text_Send called with NULL");
  1780. case '\2': strcpy(YSI_g_sCaptionText[lang], cident, sizeof (YSI_g_sCaptionText[]));
  1781. case '\3':
  1782. {
  1783. new pos = strfind(cident, ">"), br = strfind(cident, "[");
  1784. if (pos > 1 && br != -1)
  1785. {
  1786. cident[pos - 2] = '\0';
  1787. if (br) cident[br] = ':', Text_GetText(cident, cident[pos + 1], lang);
  1788. else Text_GetText(cident[1], cident[pos + 1], lang);
  1789. _Text_SetDialogMode();
  1790. Format_Render(playerid, lang, YSI_g_sCaptionText[lang], sizeof (YSI_g_sCaptionText[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1791. }
  1792. else YSI_g_sCaptionText[lang] = "Could not find title source";
  1793. }
  1794. default:
  1795. {
  1796. Text_GetText(csearch, cident, lang);
  1797. _Text_SetDialogMode();
  1798. Format_Render(playerid, lang, YSI_g_sCaptionText[lang], sizeof (YSI_g_sCaptionText[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1799. }
  1800. }
  1801. // Get the text for button 1 in this language.
  1802. switch (b1search[0])
  1803. {
  1804. case '\1': P:E("Text_Send called with NULL");
  1805. case '\2': strcpy(YSI_g_sButton1Text[lang], b1ident, sizeof (YSI_g_sButton1Text[]));
  1806. case '\3':
  1807. {
  1808. new pos = strfind(b1ident, ">"), br = strfind(b1ident, "[");
  1809. if (pos > 1 && br != -1)
  1810. {
  1811. b1ident[pos - 2] = '\0';
  1812. if (br) b1ident[br] = ':', Text_GetText(b1ident, b1ident[pos + 1], lang);
  1813. else Text_GetText(b1ident[1], b1ident[pos + 1], lang);
  1814. _Text_SetDialogMode();
  1815. Format_Render(playerid, lang, YSI_g_sButton1Text[lang], sizeof (YSI_g_sButton1Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1816. }
  1817. else YSI_g_sButton1Text[lang] = "???";
  1818. }
  1819. default:
  1820. {
  1821. Text_GetText(b1search, b1ident, lang);
  1822. _Text_SetDialogMode();
  1823. Format_Render(playerid, lang, YSI_g_sButton1Text[lang], sizeof (YSI_g_sButton1Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1824. }
  1825. }
  1826. // Get the text for button 1 in this language.
  1827. if (b2ident[0])
  1828. {
  1829. switch (b2search[0])
  1830. {
  1831. case '\1': P:E("Text_Send called with NULL");
  1832. case '\2': strcpy(YSI_g_sButton2Text[lang], b2ident, sizeof (YSI_g_sButton2Text[]));
  1833. case '\3':
  1834. {
  1835. new pos = strfind(b2ident, ">"), br = strfind(b2ident, "[");
  1836. if (pos > 1 && br != -1)
  1837. {
  1838. b2ident[pos - 2] = '\0';
  1839. if (br) b2ident[br] = ':', Text_GetText(b2ident, b2ident[pos + 1], lang);
  1840. else Text_GetText(b2ident[1], b2ident[pos + 1], lang);
  1841. _Text_SetDialogMode();
  1842. Format_Render(playerid, lang, YSI_g_sButton2Text[lang], sizeof (YSI_g_sButton2Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1843. }
  1844. else YSI_g_sButton2Text[lang] = "";
  1845. }
  1846. default:
  1847. {
  1848. Text_GetText(b2search, b2ident, lang);
  1849. _Text_SetDialogMode();
  1850. Format_Render(playerid, lang, YSI_g_sButton2Text[lang], sizeof (YSI_g_sButton2Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1851. }
  1852. }
  1853. }
  1854. else YSI_g_sButton2Text[lang] = "";
  1855. gotExtras[lang] = true;
  1856. }
  1857. if (!wasOnce[lang])
  1858. {
  1859. // Optimisation for sending messages to multiple players.
  1860. //Format_DoDisplay(playerid, 0xFF0000AA, YSI_g_sLangBuffer[lang]);
  1861. //continue;
  1862. new
  1863. arg_cur = arg_end,
  1864. ret;
  1865. do
  1866. {
  1867. #emit LOAD.S.pri arg_cur
  1868. #emit LOAD.I
  1869. #emit PUSH.pri
  1870. arg_cur -= 4;
  1871. }
  1872. while (arg_cur > arg_start);
  1873. switch (isearch[0])
  1874. {
  1875. case '\1':
  1876. {
  1877. // Null - error.
  1878. P:E("Text_Send called with NULL");
  1879. }
  1880. case '\2':
  1881. {
  1882. // None - just print the string directly.
  1883. _Text_SetDialogMode();
  1884. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, iident, n / 4);
  1885. }
  1886. case '\3':
  1887. {
  1888. new
  1889. pos = strfind(iident, ">"),
  1890. br = strfind(iident, "[");
  1891. if (pos > 1 && br != -1)
  1892. {
  1893. iident[pos - 2] = '\0';
  1894. if (br)
  1895. {
  1896. iident[br] = ':';
  1897. Text_GetText(iident, iident[pos + 1], lang);
  1898. }
  1899. else
  1900. {
  1901. Text_GetText(iident[1], iident[pos + 1], lang);
  1902. }
  1903. _Text_SetDialogMode();
  1904. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, n / 4);
  1905. }
  1906. else
  1907. {
  1908. // Var - May contain location isearch information in
  1909. // "name". Maybe add an "all" isearch parameter...
  1910. _Text_SetDialogMode();
  1911. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, "Could not find text source", n / 4);
  1912. // The code generated messes up the pushing.
  1913. }
  1914. }
  1915. default:
  1916. {
  1917. Text_GetText(isearch, iident, lang);
  1918. _Text_SetDialogMode();
  1919. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, n / 4);
  1920. }
  1921. }
  1922. #emit LCTRL 4
  1923. #emit LOAD.S.alt n
  1924. #emit ADD
  1925. #emit SCTRL 4
  1926. wasOnce[lang] = !ret;
  1927. }
  1928. // Display the message.
  1929. Dialog_Show(playerid, style, YSI_g_sCaptionText[lang], YSI_g_sLangBuffer[lang], YSI_g_sButton1Text[lang], YSI_g_sButton2Text[lang], dialog);
  1930. }
  1931. }
  1932. else
  1933. {
  1934. // Push the variable arguments. This is done by loading the value of
  1935. // each one in reverse order and pushing them. I'd love to be able to
  1936. // rewrite this to use the values of pri and alt for comparison, instead
  1937. // of having or constantly reload two variables.
  1938. foreach (new playerid : PS(players))
  1939. //for (new PlayerArray:players<MAX_PLAYERS>; __PS_A(_:__ps_addr, players); )
  1940. {
  1941. new
  1942. Language:lang = Langs_GetPlayerLanguage(playerid);
  1943. if (lang == NO_LANGUAGE)
  1944. {
  1945. lang = Language:0;
  1946. }
  1947. // Only ever do this part once per language.
  1948. if (!gotExtras[lang])
  1949. {
  1950. // Get the text for the caption in this language.
  1951. switch (csearch[0])
  1952. {
  1953. case '\1': P:E("Text_Send called with NULL");
  1954. case '\2': strcpy(YSI_g_sCaptionText[lang], cident, sizeof (YSI_g_sCaptionText[]));
  1955. case '\3':
  1956. {
  1957. new pos = strfind(cident, ">"), br = strfind(cident, "[");
  1958. if (pos > 1 && br != -1)
  1959. {
  1960. cident[pos - 2] = '\0';
  1961. if (br) cident[br] = ':', Text_GetText(cident, cident[pos + 1], lang);
  1962. else Text_GetText(cident[1], cident[pos + 1], lang);
  1963. _Text_SetDialogMode();
  1964. Format_Render(playerid, lang, YSI_g_sCaptionText[lang], sizeof (YSI_g_sCaptionText[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1965. }
  1966. else YSI_g_sCaptionText[lang] = "Could not find title source";
  1967. }
  1968. default:
  1969. {
  1970. Text_GetText(csearch, cident, lang);
  1971. _Text_SetDialogMode();
  1972. Format_Render(playerid, lang, YSI_g_sCaptionText[lang], sizeof (YSI_g_sCaptionText[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1973. }
  1974. }
  1975. // Get the text for button 1 in this language.
  1976. switch (b1search[0])
  1977. {
  1978. case '\1': P:E("Text_Send called with NULL");
  1979. case '\2': strcpy(YSI_g_sButton1Text[lang], b1ident, sizeof (YSI_g_sButton1Text[]));
  1980. case '\3':
  1981. {
  1982. new pos = strfind(b1ident, ">"), br = strfind(b1ident, "[");
  1983. if (pos > 1 && br != -1)
  1984. {
  1985. b1ident[pos - 2] = '\0';
  1986. if (br) b1ident[br] = ':', Text_GetText(b1ident, b1ident[pos + 1], lang);
  1987. else Text_GetText(b1ident[1], b1ident[pos + 1], lang);
  1988. _Text_SetDialogMode();
  1989. Format_Render(playerid, lang, YSI_g_sButton1Text[lang], sizeof (YSI_g_sButton1Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1990. }
  1991. else YSI_g_sButton1Text[lang] = "???";
  1992. }
  1993. default:
  1994. {
  1995. Text_GetText(b1search, b1ident, lang);
  1996. _Text_SetDialogMode();
  1997. Format_Render(playerid, lang, YSI_g_sButton1Text[lang], sizeof (YSI_g_sButton1Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  1998. }
  1999. }
  2000. // Get the text for button 1 in this language.
  2001. if (b2ident[0])
  2002. {
  2003. switch (b2search[0])
  2004. {
  2005. case '\1': P:E("Text_Send called with NULL");
  2006. case '\2': strcpy(YSI_g_sButton2Text[lang], b2ident, sizeof (YSI_g_sButton2Text[]));
  2007. case '\3':
  2008. {
  2009. new pos = strfind(b2ident, ">"), br = strfind(b2ident, "[");
  2010. if (pos > 1 && br != -1)
  2011. {
  2012. b2ident[pos - 2] = '\0';
  2013. if (br) b2ident[br] = ':', Text_GetText(b2ident, b2ident[pos + 1], lang);
  2014. else Text_GetText(b2ident[1], b2ident[pos + 1], lang);
  2015. _Text_SetDialogMode();
  2016. Format_Render(playerid, lang, YSI_g_sButton2Text[lang], sizeof (YSI_g_sButton2Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  2017. }
  2018. else YSI_g_sButton2Text[lang] = "";
  2019. }
  2020. default:
  2021. {
  2022. Text_GetText(b2search, b2ident, lang);
  2023. _Text_SetDialogMode();
  2024. Format_Render(playerid, lang, YSI_g_sButton2Text[lang], sizeof (YSI_g_sButton2Text[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  2025. }
  2026. }
  2027. }
  2028. else YSI_g_sButton2Text[lang] = "";
  2029. gotExtras[lang] = true;
  2030. }
  2031. if (!wasOnce[lang])
  2032. {
  2033. new
  2034. ret;
  2035. switch (isearch[0])
  2036. {
  2037. case '\1':
  2038. {
  2039. // Null - error.
  2040. P:E("Text_Send called with NULL");
  2041. }
  2042. case '\2':
  2043. {
  2044. // None - just print the string directly.
  2045. _Text_SetDialogMode();
  2046. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, iident, 0);
  2047. }
  2048. case '\3':
  2049. {
  2050. new
  2051. pos = strfind(iident, ">"),
  2052. br = strfind(iident, "[");
  2053. if (pos > 1 && br != -1)
  2054. {
  2055. iident[pos - 2] = '\0';
  2056. if (br)
  2057. {
  2058. iident[br] = ':';
  2059. Text_GetText(iident, iident[pos + 1], lang);
  2060. }
  2061. else
  2062. {
  2063. Text_GetText(iident[1], iident[pos + 1], lang);
  2064. }
  2065. _Text_SetDialogMode();
  2066. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  2067. }
  2068. else
  2069. {
  2070. // Var - May contain location isearch information in
  2071. // "name". Maybe add an "all" isearch parameter...
  2072. _Text_SetDialogMode();
  2073. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, "Could not find text source", 0);
  2074. // The code generated messes up the pushing.
  2075. }
  2076. }
  2077. default:
  2078. {
  2079. Text_GetText(isearch, iident, lang);
  2080. _Text_SetDialogMode();
  2081. ret = Format_Render(playerid, lang, YSI_g_sLangBuffer[lang], sizeof (YSI_g_sLangBuffer[]) - 1, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, 0);
  2082. }
  2083. }
  2084. wasOnce[lang] = !ret;
  2085. }
  2086. // Display the message.
  2087. Dialog_Show(playerid, style, YSI_g_sCaptionText[lang], YSI_g_sLangBuffer[lang], YSI_g_sButton1Text[lang], YSI_g_sButton2Text[lang], dialog);
  2088. }
  2089. }
  2090. // Sort out the callbacks etc for the dialog return.
  2091. new
  2092. cd[E_CALLBACK_DATA];
  2093. Callback_Get(callback, cd, _F<iiiis>);
  2094. Dialog_SetCallbackData(dialog, cd); //AMX_GetPublicPointer(callback));
  2095. // Automatically free the dialog when we're done.
  2096. Dialog_Garbage(dialog);
  2097. Format_SetListSeparator(", ");
  2098. return dialog;
  2099. }
  2100. stock _Text_Format(dest[], size, Language:lang, e_STYLE_TYPE:style, search[], ident[], ...)
  2101. {
  2102. P:4("Text_Format: %s %d %d %d %s %s", dest, size, _:lang, style, search, ident);
  2103. Text_GetText(search, ident, lang);
  2104. new
  2105. styleData[E_STYLE_DATA],
  2106. label[E_3D_DATA],
  2107. argCount = numargs() - 6,
  2108. bool:foundStyle = false
  2109. ;
  2110. if (style != e_STYLE_TYPE_DIALOG)
  2111. {
  2112. new hash = bernstein(ident);
  2113. for (new i = 0; i != Y_TEXT_MAX_SETS; ++i)
  2114. {
  2115. new
  2116. ret = Text_FindEntry(YSI_g_sTextSets[i][e_TEXT_SETS_INDEX], hash)
  2117. ;
  2118. P:7("Text_Format: Textset %d entry %d", i, ret);
  2119. if (ret != -1)
  2120. {
  2121. Styles_GetData(ret, styleData, label);
  2122. if ((styleData[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK) != style)
  2123. {
  2124. P:7("Text_Format: No matching style data. Types differ 0x%08x == 0x%08x", (styleData[E_STYLE_DATA_TYPE] & e_STYLE_TYPE_MASK), style);
  2125. break;
  2126. }
  2127. foundStyle = true;
  2128. break;
  2129. }
  2130. }
  2131. if (!foundStyle)
  2132. {
  2133. P:7("Text_Format: Style not found, using default");
  2134. }
  2135. _Format_SetStyleData(TEXT_MASTER, 0, styleData, label);
  2136. }
  2137. else
  2138. {
  2139. P:7("Text_Format: Toggling dialog mode");
  2140. _Text_SetDialogMode();
  2141. }
  2142. Format_Render(INVALID_PLAYER_ID, lang, dest, size, 0, e_FORMAT_FLAGS_NONE, YSI_g_sReturnText, argCount, ___(6));
  2143. return 1;
  2144. }