text.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2008, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // Portions based on PALx Project by palxex.
  7. // Copyright (c) 2006-2008, Pal Lockheart <palxex@gmail.com>.
  8. //
  9. // This file is part of SDLPAL.
  10. //
  11. // SDLPAL is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. // Modified by Lou Yihua <louyihua@21cn.com> with Unicode support, 2015
  25. //
  26. #include "main.h"
  27. #define FONT_COLOR_DEFAULT 0x4F
  28. #define FONT_COLOR_YELLOW 0x2D
  29. #define FONT_COLOR_RED 0x1A
  30. #define FONT_COLOR_CYAN 0x8D
  31. #define FONT_COLOR_CYAN_ALT 0x8C
  32. BOOL g_fUpdatedInBattle = FALSE;
  33. #define MESSAGE_MAX_BUFFER_SIZE 512
  34. #define INCLUDE_CODEPAGE_H
  35. #include "codepage.h"
  36. # define ATB_WORD_COUNT 6
  37. static LPWSTR gc_rgszAdditionalWords[CP_MAX][ATB_WORD_COUNT] = {
  38. { L"\x6230\x9B25\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  39. { L"\x6218\x6597\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  40. //{ L"\x6226\x95D8\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  41. };
  42. static LPWSTR gc_rgszDefaultAdditionalWords[ATB_WORD_COUNT] = { NULL, L"\xFF11", L"\xFF12", L"\xFF13", L"\xFF14", L"\xFF15" };
  43. LPWSTR g_rcCredits[12];
  44. typedef struct tagTEXTLIB
  45. {
  46. LPWSTR *lpWordBuf;
  47. LPWSTR *lpMsgBuf;
  48. int **lpIndexBuf;
  49. int nWords;
  50. int nMsgs;
  51. int nIndices;
  52. int nCurrentDialogLine;
  53. BYTE bCurrentFontColor;
  54. PAL_POS posIcon;
  55. PAL_POS posDialogTitle;
  56. PAL_POS posDialogText;
  57. BYTE bDialogPosition;
  58. BYTE bIcon;
  59. int iDelayTime;
  60. BOOL fUserSkip;
  61. BOOL fPlayingRNG;
  62. BYTE bufDialogIcons[282];
  63. } TEXTLIB, *LPTEXTLIB;
  64. static TEXTLIB g_TextLib;
  65. PAL_FORCE_INLINE int
  66. PAL_ParseLine(
  67. char *line,
  68. char **value,
  69. int *length,
  70. int deltrail
  71. )
  72. {
  73. //
  74. // Remove the leading spaces
  75. //
  76. while (*line && iswspace(*line)) line++;
  77. //
  78. // Skip comments starting with '#'
  79. //
  80. if (*line && *line != '#')
  81. {
  82. //
  83. // Split the index and value
  84. //
  85. LPSTR val = strchr(line, '=');
  86. if (val)
  87. {
  88. //
  89. // Remove the trailing spaces
  90. //
  91. LPSTR end = line + strlen(line);
  92. int index;
  93. if (deltrail) while (end > line && iswspace(end[-1])) *(--end) = 0;
  94. //
  95. // Parse the index and pass out value
  96. //
  97. if (sscanf(line, "%d", &index) == 1)
  98. {
  99. *value = val + 1;
  100. *length = end - *value;
  101. return index;
  102. }
  103. }
  104. }
  105. return 0;
  106. }
  107. PAL_FORCE_INLINE char *
  108. PAL_ReadOneLine(
  109. char *temp,
  110. int limit,
  111. FILE *fp
  112. )
  113. {
  114. if (fgets(temp, limit, fp))
  115. {
  116. int n = strlen(temp);
  117. if (n == limit - 1 && temp[n - 1] != '\n' && !feof(fp))
  118. {
  119. // Line too long, try to read it as a whole
  120. int nn = 2;
  121. char *tmp = strdup(temp);
  122. while (!feof(fp))
  123. {
  124. if (!(tmp = (char *)realloc(tmp, nn * limit)))
  125. {
  126. TerminateOnError("PAL_ReadOneLine(): failed to allocate memory for long line!");
  127. }
  128. if (fgets(tmp + n, limit + 1, fp))
  129. {
  130. n += strlen(tmp + n);
  131. if (n < limit - 1 || temp[n - 1] == '\n')
  132. break;
  133. else
  134. nn++;
  135. }
  136. }
  137. if (tmp[n - 1] == '\n') tmp[n - 1] = 0;
  138. if (tmp[n - 2] == '\r') tmp[n - 2] = 0;
  139. return tmp;
  140. }
  141. else
  142. {
  143. if (n > 0 && temp[n - 1] == '\n') temp[--n] = 0;
  144. if (n > 0 && temp[n - 1] == '\r') temp[--n] = 0;
  145. return temp;
  146. }
  147. }
  148. else
  149. return NULL;
  150. }
  151. static void *
  152. PAL_ParseOneDescriptionLine(
  153. char *buffer,
  154. void *_head,
  155. void *_item
  156. )
  157. {
  158. struct _msg_entry
  159. {
  160. struct _msg_entry *next;
  161. wchar_t *value;
  162. };
  163. struct _msg_list_entry
  164. {
  165. struct _msg_list_entry *next;
  166. struct _msg_entry *value;
  167. int index, count;
  168. } *head = (struct _msg_list_entry *)_head, *item = (struct _msg_list_entry *)_item;
  169. char *v;
  170. int l, i = PAL_ParseLine(buffer, &v, &l, TRUE);
  171. if (i > 0)
  172. {
  173. int len = PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, NULL, 0);
  174. struct _msg_entry *e = (struct _msg_entry *)UTIL_malloc(sizeof(struct _msg_entry));
  175. e->value = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t)); e->next = NULL;
  176. PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, e->value, len);
  177. if (item && item->index != i)
  178. {
  179. if (head->next == NULL || head->next->index > i)
  180. {
  181. item = NULL;
  182. }
  183. else
  184. {
  185. if (item->index > i) item = head->next;
  186. while (item->next && item->next->index < i) item = item->next;
  187. }
  188. }
  189. if (item && item->index != i)
  190. {
  191. item->next = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  192. item = item->next; item->next = NULL;
  193. item->value = e; item->count = 1; item->index = i;
  194. }
  195. else if (!item)
  196. {
  197. item = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  198. item->next = head->next; head->next = item; item->next = NULL;
  199. item->value = e; item->count = 1; item->index = i;
  200. }
  201. else
  202. {
  203. struct _msg_entry *tmp = item->value;
  204. while (tmp->next) tmp = tmp->next;
  205. tmp->next = e; item->count++;
  206. }
  207. return item;
  208. }
  209. else
  210. return _item;
  211. }
  212. static VOID
  213. PAL_ParseObjectDesc(
  214. void *_head
  215. )
  216. {
  217. struct _msg_entry
  218. {
  219. struct _msg_entry *next;
  220. wchar_t *value;
  221. };
  222. struct _msg_list_entry
  223. {
  224. struct _msg_list_entry *next;
  225. struct _msg_entry *value;
  226. int index, count;
  227. } *head = (struct _msg_list_entry *)_head, *item;
  228. int count = 0;
  229. for (item = head->next; item; count++)
  230. {
  231. struct _msg_list_entry *next = item->next;
  232. struct _msg_entry *tmp = item->value;
  233. if (item->index < MAX_OBJECTS)
  234. {
  235. int i = 0;
  236. gpGlobals->rgObjectDesc[item->index] = (LPWSTR *)calloc(item->count + 1, sizeof(LPWSTR));
  237. while (tmp)
  238. {
  239. struct _msg_entry *nxt = tmp->next;
  240. gpGlobals->rgObjectDesc[item->index][i++] = tmp->value;
  241. free(tmp); tmp = nxt;
  242. }
  243. }
  244. else
  245. {
  246. while (tmp)
  247. {
  248. struct _msg_entry *nxt = tmp->next;
  249. free(tmp->value); free(tmp); tmp = nxt;
  250. }
  251. }
  252. free(item); item = next;
  253. }
  254. gpGlobals->rgObjectDesc[0] = (LPWSTR *)count;
  255. }
  256. static int
  257. PAL_ReadMessageFile(
  258. FILE *fp
  259. )
  260. {
  261. char temp[MESSAGE_MAX_BUFFER_SIZE];
  262. struct _msg_entry
  263. {
  264. struct _msg_entry *next;
  265. wchar_t *value;
  266. } *cur_val = NULL;
  267. struct _msg_list_entry
  268. {
  269. struct _msg_list_entry *next;
  270. struct _msg_entry *value;
  271. int index;
  272. int count;
  273. } *head = NULL, *item = NULL, dhead = { NULL }, *ditem = NULL;
  274. struct _word_list_entry
  275. {
  276. struct _word_list_entry *next;
  277. wchar_t *value;
  278. int index;
  279. } whead = { NULL }, *witem = NULL;
  280. enum _message_state
  281. {
  282. ST_OUTSIDE,
  283. ST_DIALOG,
  284. ST_WORD,
  285. ST_CREDIT,
  286. ST_LAYOUT,
  287. ST_DESCRIPTION
  288. } state = ST_OUTSIDE;
  289. int idx_cnt = 0, msg_cnt = 0, word_cnt = 0, sid, eid = -1;
  290. while (!feof(fp))
  291. {
  292. char *buffer;
  293. if (buffer = PAL_ReadOneLine(temp, MESSAGE_MAX_BUFFER_SIZE, fp))
  294. {
  295. switch(state)
  296. {
  297. case ST_OUTSIDE:
  298. //
  299. // Skip comments starting with '#'
  300. //
  301. if (*buffer && *buffer != '#')
  302. {
  303. if (strncmp(buffer, "[BEGIN MESSAGE]", 15) == 0 &&
  304. sscanf(buffer + 15, "%d", &sid) == 1 && sid > eid)
  305. {
  306. state = ST_DIALOG;
  307. //
  308. // First save values (converted wide string) into a linked list
  309. //
  310. if (head)
  311. {
  312. item->next = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  313. item = item->next;
  314. }
  315. else
  316. {
  317. head = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  318. item = head;
  319. }
  320. item->value = NULL; item->index = sid;
  321. item->count = 0; item->next = NULL; cur_val = NULL;
  322. if (idx_cnt < item->index) idx_cnt = item->index;
  323. }
  324. else if (strncmp(buffer, "[BEGIN WORDS]", 13) == 0 && !witem)
  325. {
  326. state = ST_WORD;
  327. //
  328. // First save values (converted wide string) into a linked list
  329. //
  330. witem = &whead;
  331. }
  332. else if (strncmp(buffer, "[BEGIN CREDITS]", 15) == 0)
  333. {
  334. state = ST_CREDIT;
  335. }
  336. else if (strncmp(buffer, "[BEGIN LAYOUT]", 14) == 0)
  337. {
  338. state = ST_LAYOUT;
  339. gConfig.fUseCustomScreenLayout = TRUE;
  340. }
  341. else if (strncmp(buffer, "[BEGIN DESCRIPTION]", 19) == 0 && !ditem)
  342. {
  343. state = ST_DESCRIPTION;
  344. }
  345. else
  346. {
  347. // Just ignore invalid lines
  348. #ifdef ENABLE_LOG
  349. UTIL_WriteLog(LOG_ERR, "PAL_ReadMessageFile(): encounter invalid line '%s'!\n", line);
  350. #endif
  351. }
  352. }
  353. break;
  354. case ST_DIALOG:
  355. //
  356. // Check if to end one dialog
  357. //
  358. if (strncmp(buffer, "[END MESSAGE]", 13) == 0 &&
  359. sscanf(buffer + 13, "%d", &eid) == 1 && eid >= sid)
  360. {
  361. // End dialog
  362. state = ST_OUTSIDE;
  363. }
  364. else
  365. {
  366. if (cur_val)
  367. {
  368. cur_val->next = (struct _msg_entry *)UTIL_malloc(sizeof(struct _msg_entry));
  369. cur_val = cur_val->next;
  370. }
  371. else
  372. cur_val = (struct _msg_entry *)UTIL_malloc(sizeof(struct _msg_entry));
  373. if (strncmp(buffer, "[CLEAR MESSAGE]", 15) == 0)
  374. {
  375. cur_val->value = NULL;
  376. }
  377. else
  378. {
  379. int len = PAL_MultiByteToWideCharCP(CP_UTF_8, buffer, -1, NULL, 0);
  380. cur_val->value = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  381. PAL_MultiByteToWideCharCP(CP_UTF_8, buffer, -1, cur_val->value, len);
  382. msg_cnt++;
  383. }
  384. if (!item->value) item->value = cur_val;
  385. cur_val->next = NULL; item->count++;
  386. }
  387. break;
  388. case ST_WORD:
  389. //
  390. // Check if to end word list
  391. //
  392. if (strncmp(buffer, "[END WORDS]", 11) == 0)
  393. {
  394. // End word list
  395. state = ST_OUTSIDE;
  396. }
  397. else
  398. {
  399. char *v;
  400. int l, i = PAL_ParseLine(buffer, &v, &l, TRUE);
  401. if (i > 0)
  402. {
  403. int len = PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, NULL, 0);
  404. struct _word_list_entry *val = (struct _word_list_entry *)UTIL_malloc(sizeof(struct _word_list_entry));
  405. val->value = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  406. PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, val->value, len);
  407. val->index = i; val->next = NULL;
  408. witem->next = val; witem = witem->next;
  409. if (word_cnt < i) word_cnt = i;
  410. }
  411. }
  412. break;
  413. case ST_DESCRIPTION:
  414. //
  415. // Check if to end description list
  416. //
  417. if (strncmp(buffer, "[END DESCRIPTION]", 17) == 0)
  418. {
  419. // End description list
  420. state = ST_OUTSIDE;
  421. }
  422. else if (!gConfig.fIsWIN95)
  423. {
  424. item = PAL_ParseOneDescriptionLine(buffer, &dhead, item);
  425. }
  426. break;
  427. case ST_CREDIT:
  428. //
  429. // Check if to end credit list
  430. //
  431. if (strncmp(buffer, "[END CREDITS]", 13) == 0)
  432. {
  433. // End credit list
  434. state = ST_OUTSIDE;
  435. }
  436. else
  437. {
  438. char *v;
  439. int l, i = PAL_ParseLine(buffer, &v, &l, FALSE);
  440. if ((i == 1 || (i >= 6 && i <= 11)) && !g_rcCredits[i])
  441. {
  442. int limit = (i == 1) ? 24 * 8 : 40 * 8, w = 0, j = 0, len;
  443. if (i == 6 || i == 7)
  444. {
  445. if (PAL_PLATFORM && PAL_CREDIT && PAL_PORTYEAR)
  446. {
  447. const char *templates[] = { "${platform}", "${author}", "${year}" };
  448. const char *values[] = { PAL_PLATFORM, PAL_CREDIT, PAL_PORTYEAR };
  449. const int matchlen[] = { 11, 9, 7 };
  450. const int valuelen[] = { sizeof(PAL_PLATFORM) - 1, sizeof(PAL_CREDIT) - 1, sizeof(PAL_PORTYEAR) - 1 };
  451. char *tmp = (char *)alloca(valuelen[0] + valuelen[1] + valuelen[2] + l + 1);
  452. char *dst = tmp, *src = v;
  453. while (*src)
  454. {
  455. if (*src == '$')
  456. {
  457. int k;
  458. for (k = 0; k < 3 && strncmp(src, templates[k], matchlen[k]); k++);
  459. if (k < 3)
  460. {
  461. strcpy(dst, values[k]);
  462. dst += valuelen[k];
  463. src += matchlen[k];
  464. continue;
  465. }
  466. }
  467. *dst++ = *src++;
  468. }
  469. *dst = 0;
  470. len = PAL_MultiByteToWideCharCP(CP_UTF_8, tmp, -1, NULL, 0);
  471. g_rcCredits[i] = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  472. PAL_MultiByteToWideCharCP(CP_UTF_8, tmp, -1, g_rcCredits[i], len);
  473. }
  474. }
  475. else
  476. {
  477. len = PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, NULL, 0);
  478. g_rcCredits[i] = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  479. PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, g_rcCredits[i], len);
  480. }
  481. if (g_rcCredits[i])
  482. {
  483. // Limit the length of texts
  484. while (w < limit && j < len - 1) w += PAL_CharWidth(g_rcCredits[i][j++]);
  485. if (w >= limit) g_rcCredits[i][w > limit ? j - 1 : j] = 0;
  486. }
  487. }
  488. }
  489. break;
  490. case ST_LAYOUT:
  491. if (strncmp(buffer, "[END LAYOUT]", 12) == 0)
  492. {
  493. // End layout
  494. state = ST_OUTSIDE;
  495. }
  496. else
  497. {
  498. char *v;
  499. int x, y, f, n, l, i = PAL_ParseLine(buffer, &v, &l, FALSE);
  500. if (i >= 1 && i <= 80)
  501. {
  502. PAL_POS *poses = (PAL_POS *)&gConfig.ScreenLayout;
  503. if ((n = sscanf(v, "%d,%d,%d", &x, &y, &f)) >= 2 && x < 320 && y < 200)
  504. {
  505. poses[i - 1] = PAL_XY(x, y);
  506. if (n == 3) gConfig.ScreenLayoutFlag[i - 1] = f;
  507. }
  508. }
  509. }
  510. break;
  511. default:
  512. TerminateOnError("PAL_ReadMessageFile(): Reached an unknown state. Something really wrong may have happened!");
  513. break;
  514. }
  515. if (buffer != temp) free(buffer);
  516. }
  517. }
  518. if (msg_cnt > 0)
  519. {
  520. //
  521. // Move values from linked list to array
  522. //
  523. int idx_msg = 1;
  524. g_TextLib.nIndices = (idx_cnt += 1);
  525. g_TextLib.nMsgs = (msg_cnt += 1);
  526. g_TextLib.lpIndexBuf = (int **)UTIL_calloc(idx_cnt, sizeof(int *));
  527. g_TextLib.lpMsgBuf = (LPWSTR *)UTIL_calloc(msg_cnt, sizeof(LPWSTR));
  528. for (item = head; item; )
  529. {
  530. struct _msg_list_entry *temp = item->next;
  531. struct _msg_entry *msg = item->value;
  532. int index = 0;
  533. g_TextLib.lpIndexBuf[item->index] = (int *)UTIL_calloc(item->count + 1, sizeof(int));
  534. while (msg)
  535. {
  536. struct _msg_entry *tmp = msg->next;
  537. if (msg->value)
  538. {
  539. g_TextLib.lpIndexBuf[item->index][index++] = idx_msg;
  540. g_TextLib.lpMsgBuf[idx_msg++] = msg->value;
  541. }
  542. else
  543. g_TextLib.lpIndexBuf[item->index][index++] = 0;
  544. free(msg); msg = tmp;
  545. }
  546. g_TextLib.lpIndexBuf[item->index][item->count] = -1;
  547. free(item); item = temp;
  548. }
  549. }
  550. if (word_cnt > 0)
  551. {
  552. //
  553. // Move values from linked list to array
  554. //
  555. int i;
  556. if (word_cnt < MINIMAL_WORD_COUNT - 1) word_cnt = MINIMAL_WORD_COUNT - 1;
  557. g_TextLib.nWords = (word_cnt += 1);
  558. g_TextLib.lpWordBuf = (LPWSTR *)UTIL_calloc(word_cnt, sizeof(LPWSTR));
  559. for (witem = whead.next; witem; )
  560. {
  561. struct _word_list_entry *temp = witem->next;
  562. g_TextLib.lpWordBuf[witem->index] = witem->value;
  563. free(witem); witem = temp;
  564. }
  565. if (!gConfig.fIsClassic)
  566. {
  567. for (i = 1; i < ATB_WORD_COUNT; i++)
  568. if (!g_TextLib.lpWordBuf[i + SYSMENU_LABEL_BATTLEMODE])
  569. g_TextLib.lpWordBuf[i + SYSMENU_LABEL_BATTLEMODE] = gc_rgszDefaultAdditionalWords[i];
  570. }
  571. }
  572. if (dhead.next) PAL_ParseObjectDesc(&dhead);
  573. fclose(fp);
  574. return (msg_cnt > 0 && word_cnt > 0) ? 1 : 0;
  575. }
  576. INT
  577. PAL_InitText(
  578. VOID
  579. )
  580. /*++
  581. Purpose:
  582. Initialize the in-game texts.
  583. Parameters:
  584. None.
  585. Return value:
  586. 0 = success.
  587. -1 = memory allocation error.
  588. --*/
  589. {
  590. if (gConfig.pszMsgName)
  591. {
  592. //
  593. // Open the message, index and word data files.
  594. //
  595. FILE *fp = UTIL_OpenRequiredFileForMode(gConfig.pszMsgName, "r");
  596. //
  597. // Read the contents of the message, index and word data files.
  598. //
  599. if (!PAL_ReadMessageFile(fp))
  600. {
  601. return -1;
  602. }
  603. else
  604. {
  605. DWORD dwWordLength = 0;
  606. int i;
  607. for (i = 1; i < g_TextLib.nWords; i++)
  608. {
  609. if (g_TextLib.lpWordBuf[i])
  610. {
  611. LPWSTR ptr = g_TextLib.lpWordBuf[i];
  612. DWORD n = 0;
  613. while (*ptr) n += PAL_CharWidth(*ptr++) >> 3;
  614. if (dwWordLength < n) dwWordLength = n;
  615. }
  616. }
  617. gConfig.dwWordLength = dwWordLength;
  618. for (i = 0; i < 12; i++)
  619. {
  620. if (!g_rcCredits[i])
  621. g_rcCredits[i] = L"";
  622. }
  623. }
  624. }
  625. else
  626. {
  627. FILE *fpMsg, *fpWord;
  628. DWORD *offsets;
  629. LPWSTR tmp;
  630. LPBYTE temp;
  631. int wpos, wlen, i;
  632. //
  633. // Open the message and word data files.
  634. //
  635. fpMsg = UTIL_OpenRequiredFile("m.msg");
  636. fpWord = UTIL_OpenRequiredFile("word.dat");
  637. //
  638. // See how many words we have
  639. //
  640. fseek(fpWord, 0, SEEK_END);
  641. i = ftell(fpWord);
  642. //
  643. // Each word has 10 bytes
  644. //
  645. g_TextLib.nWords = (i + (gConfig.dwWordLength - 1)) / gConfig.dwWordLength;
  646. if (g_TextLib.nWords < MINIMAL_WORD_COUNT) g_TextLib.nWords = MINIMAL_WORD_COUNT;
  647. //
  648. // Read the words
  649. //
  650. temp = (LPBYTE)malloc(i);
  651. if (temp == NULL)
  652. {
  653. fclose(fpWord);
  654. fclose(fpMsg);
  655. return -1;
  656. }
  657. fseek(fpWord, 0, SEEK_SET);
  658. fread(temp, i, 1, fpWord);
  659. //
  660. // Close the words file
  661. //
  662. fclose(fpWord);
  663. // Split the words and do code page conversion
  664. for (i = 0, wlen = 0; i < g_TextLib.nWords; i++)
  665. {
  666. int base = i * gConfig.dwWordLength;
  667. int pos = base + gConfig.dwWordLength - 1;
  668. while (pos >= base && temp[pos] == ' ') temp[pos--] = 0;
  669. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + base, gConfig.dwWordLength, NULL, 0) + 1;
  670. }
  671. g_TextLib.lpWordBuf = (LPWSTR*)malloc(g_TextLib.nWords * sizeof(LPWSTR));
  672. if (g_TextLib.lpWordBuf == NULL)
  673. {
  674. free(temp);
  675. fclose(fpWord);
  676. fclose(fpMsg);
  677. return -1;
  678. }
  679. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  680. if (tmp == NULL)
  681. {
  682. free(g_TextLib.lpWordBuf);
  683. free(temp);
  684. fclose(fpWord);
  685. fclose(fpMsg);
  686. return -1;
  687. }
  688. for (i = 0, wpos = 0; i < g_TextLib.nWords; i++)
  689. {
  690. int l;
  691. g_TextLib.lpWordBuf[i] = tmp + wpos;
  692. l = PAL_MultiByteToWideChar((LPCSTR)temp + i * gConfig.dwWordLength, gConfig.dwWordLength, g_TextLib.lpWordBuf[i], wlen - wpos);
  693. if (l > 0 && g_TextLib.lpWordBuf[i][l - 1] == '1')
  694. g_TextLib.lpWordBuf[i][l - 1] = 0;
  695. g_TextLib.lpWordBuf[i][l] = 0;
  696. wpos += l + 1;
  697. }
  698. free(temp);
  699. //
  700. // Read the message offsets. The message offsets are in SSS.MKF #3
  701. //
  702. i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD);
  703. g_TextLib.nMsgs = i - 1;
  704. offsets = (LPDWORD)malloc(i * sizeof(DWORD));
  705. if (offsets == NULL)
  706. {
  707. free(g_TextLib.lpWordBuf);
  708. fclose(fpMsg);
  709. return -1;
  710. }
  711. PAL_MKFReadChunk((LPBYTE)(offsets), i * sizeof(DWORD), 3, gpGlobals->f.fpSSS);
  712. //
  713. // Read the messages.
  714. //
  715. fseek(fpMsg, 0, SEEK_END);
  716. i = ftell(fpMsg);
  717. temp = (LPBYTE)malloc(i);
  718. if (temp == NULL)
  719. {
  720. free(offsets);
  721. free(g_TextLib.lpWordBuf[0]);
  722. free(g_TextLib.lpWordBuf);
  723. fclose(fpMsg);
  724. return -1;
  725. }
  726. fseek(fpMsg, 0, SEEK_SET);
  727. fread(temp, 1, i, fpMsg);
  728. fclose(fpMsg);
  729. // Split messages and do code page conversion here
  730. for (i = 0, wlen = 0; i < g_TextLib.nMsgs; i++)
  731. {
  732. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), NULL, 0) + 1;
  733. }
  734. g_TextLib.lpMsgBuf = (LPWSTR*)malloc(g_TextLib.nMsgs * sizeof(LPWSTR));
  735. if (g_TextLib.lpMsgBuf == NULL)
  736. {
  737. free(g_TextLib.lpWordBuf);
  738. free(offsets);
  739. return -1;
  740. }
  741. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  742. if (tmp == NULL)
  743. {
  744. free(g_TextLib.lpMsgBuf);
  745. free(g_TextLib.lpWordBuf);
  746. free(offsets);
  747. return -1;
  748. }
  749. for (i = 0, wpos = 0; i < g_TextLib.nMsgs; i++)
  750. {
  751. int l;
  752. g_TextLib.lpMsgBuf[i] = tmp + wpos;
  753. l = PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), g_TextLib.lpMsgBuf[i], wlen - wpos);
  754. g_TextLib.lpMsgBuf[i][l] = 0;
  755. wpos += l + 1;
  756. }
  757. free(temp);
  758. free(offsets);
  759. g_TextLib.lpIndexBuf = NULL;
  760. if (!gConfig.fIsClassic) memcpy(g_TextLib.lpWordBuf + SYSMENU_LABEL_BATTLEMODE, gc_rgszAdditionalWords[gConfig.iCodePage], ATB_WORD_COUNT * sizeof(LPCWSTR));
  761. }
  762. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  763. g_TextLib.bIcon = 0;
  764. g_TextLib.posIcon = 0;
  765. g_TextLib.nCurrentDialogLine = 0;
  766. g_TextLib.iDelayTime = 3;
  767. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  768. g_TextLib.posDialogText = PAL_XY(44, 26);
  769. g_TextLib.bDialogPosition = kDialogUpper;
  770. g_TextLib.fUserSkip = FALSE;
  771. PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA);
  772. return 0;
  773. }
  774. VOID
  775. PAL_FreeText(
  776. VOID
  777. )
  778. /*++
  779. Purpose:
  780. Free the memory used by the texts.
  781. Parameters:
  782. None.
  783. Return value:
  784. None.
  785. --*/
  786. {
  787. int i;
  788. if (g_TextLib.lpMsgBuf != NULL)
  789. {
  790. if (gConfig.pszMsgName)
  791. for(i = 0; i < g_TextLib.nMsgs; i++) free(g_TextLib.lpMsgBuf[i]);
  792. else
  793. free(g_TextLib.lpMsgBuf[0]);
  794. free(g_TextLib.lpMsgBuf);
  795. g_TextLib.lpMsgBuf = NULL;
  796. }
  797. if (g_TextLib.lpWordBuf != NULL)
  798. {
  799. if (gConfig.pszMsgName)
  800. for(i = 0; i < g_TextLib.nWords; i++) free(g_TextLib.lpWordBuf[i]);
  801. else
  802. free(g_TextLib.lpWordBuf[0]);
  803. free(g_TextLib.lpWordBuf);
  804. g_TextLib.lpWordBuf = NULL;
  805. }
  806. if (g_TextLib.lpIndexBuf != NULL)
  807. {
  808. if (gConfig.pszMsgName)
  809. for(i = 0; i < g_TextLib.nIndices; i++) free(g_TextLib.lpIndexBuf[i]);
  810. else
  811. free(g_TextLib.lpIndexBuf[0]);
  812. free(g_TextLib.lpIndexBuf);
  813. g_TextLib.lpIndexBuf = NULL;
  814. }
  815. }
  816. LPCWSTR
  817. PAL_GetWord(
  818. int iNumWord
  819. )
  820. /*++
  821. Purpose:
  822. Get the specified word.
  823. Parameters:
  824. [IN] wNumWord - the number of the requested word.
  825. Return value:
  826. Pointer to the requested word. NULL if not found.
  827. --*/
  828. {
  829. return (iNumWord >= g_TextLib.nWords || !g_TextLib.lpWordBuf[iNumWord]) ? L"" : g_TextLib.lpWordBuf[iNumWord];
  830. }
  831. LPCWSTR
  832. PAL_GetMsg(
  833. int iNumMsg
  834. )
  835. /*++
  836. Purpose:
  837. Get the specified message.
  838. Parameters:
  839. [IN] wNumMsg - the number of the requested message.
  840. Return value:
  841. Pointer to the requested message. NULL if not found.
  842. --*/
  843. {
  844. return (iNumMsg >= g_TextLib.nMsgs || !g_TextLib.lpMsgBuf[iNumMsg]) ? L"" : g_TextLib.lpMsgBuf[iNumMsg];
  845. }
  846. int
  847. PAL_GetMsgNum(
  848. int iIndex,
  849. int iOrder
  850. )
  851. /*++
  852. Purpose:
  853. Get the number of specified message from index & order.
  854. Parameters:
  855. [IN] iMsgIndex - index.
  856. [IN] iOrder - order inside the index.
  857. Return value:
  858. The number of message. Zero means pausing for key, and -1 means end.
  859. --*/
  860. {
  861. return (iIndex >= g_TextLib.nMsgs || !g_TextLib.lpIndexBuf[iIndex]) ? -1 : g_TextLib.lpIndexBuf[iIndex][iOrder];
  862. }
  863. VOID
  864. PAL_DrawText(
  865. LPCWSTR lpszText,
  866. PAL_POS pos,
  867. BYTE bColor,
  868. BOOL fShadow,
  869. BOOL fUpdate,
  870. BOOL fUse8x8Font
  871. )
  872. /*++
  873. Purpose:
  874. Draw text on the screen.
  875. Parameters:
  876. [IN] lpszText - the text to be drawn.
  877. [IN] pos - Position of the text.
  878. [IN] bColor - Color of the text.
  879. [IN] fShadow - TRUE if the text is shadowed or not.
  880. [IN] fUpdate - TRUE if update the screen area.
  881. [IN] fUse8x8Font - TRUE if use 8x8 font.
  882. Return value:
  883. None.
  884. --*/
  885. {
  886. SDL_Rect rect, urect;
  887. urect.x = rect.x = PAL_X(pos);
  888. urect.y = rect.y = PAL_Y(pos);
  889. urect.h = (fUse8x8Font ? 8 : PAL_FontHeight()) + (fShadow ? 1 : 0);
  890. urect.w = 0;
  891. while (*lpszText)
  892. {
  893. //
  894. // Draw the character
  895. //
  896. int char_width = fUse8x8Font ? 8 : PAL_CharWidth(*lpszText);
  897. if (fShadow)
  898. {
  899. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0, fUse8x8Font);
  900. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0, fUse8x8Font);
  901. }
  902. PAL_DrawCharOnSurface(*lpszText++, gpScreen, PAL_XY(rect.x, rect.y), bColor, fUse8x8Font);
  903. rect.x += char_width; urect.w += char_width;
  904. }
  905. //
  906. // Update the screen area
  907. //
  908. if (fUpdate && urect.w > 0)
  909. {
  910. if (fShadow) urect.w++;
  911. if (urect.x + urect.w > 320)
  912. {
  913. urect.w = 320 - urect.x;
  914. }
  915. VIDEO_UpdateScreen(&urect);
  916. }
  917. }
  918. VOID
  919. PAL_DialogSetDelayTime(
  920. INT iDelayTime
  921. )
  922. /*++
  923. Purpose:
  924. Set the delay time for dialog.
  925. Parameters:
  926. [IN] iDelayTime - the delay time to be set.
  927. Return value:
  928. None.
  929. --*/
  930. {
  931. g_TextLib.iDelayTime = iDelayTime;
  932. }
  933. VOID
  934. PAL_StartDialog(
  935. BYTE bDialogLocation,
  936. BYTE bFontColor,
  937. INT iNumCharFace,
  938. BOOL fPlayingRNG
  939. )
  940. /*++
  941. Purpose:
  942. Start a new dialog.
  943. Parameters:
  944. [IN] bDialogLocation - the location of the text on the screen.
  945. [IN] bFontColor - the font color of the text.
  946. [IN] iNumCharFace - number of the character face in RGM.MKF.
  947. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  948. Return value:
  949. None.
  950. --*/
  951. {
  952. PAL_LARGE BYTE buf[16384];
  953. SDL_Rect rect;
  954. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  955. {
  956. //
  957. // Update the screen in battle, or the graphics may seem messed up
  958. //
  959. VIDEO_UpdateScreen(NULL);
  960. g_fUpdatedInBattle = TRUE;
  961. }
  962. g_TextLib.bIcon = 0;
  963. g_TextLib.posIcon = 0;
  964. g_TextLib.nCurrentDialogLine = 0;
  965. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  966. g_TextLib.fUserSkip = FALSE;
  967. if (bFontColor != 0)
  968. {
  969. g_TextLib.bCurrentFontColor = bFontColor;
  970. }
  971. if (fPlayingRNG && iNumCharFace)
  972. {
  973. VIDEO_BackupScreen();
  974. g_TextLib.fPlayingRNG = TRUE;
  975. }
  976. switch (bDialogLocation)
  977. {
  978. case kDialogUpper:
  979. if (iNumCharFace > 0)
  980. {
  981. //
  982. // Display the character face at the upper part of the screen
  983. //
  984. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  985. {
  986. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  987. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  988. rect.x = 48 - rect.w / 2;
  989. rect.y = 55 - rect.h / 2;
  990. if (rect.x < 0)
  991. {
  992. rect.x = 0;
  993. }
  994. if (rect.y < 0)
  995. {
  996. rect.y = 0;
  997. }
  998. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  999. if (rect.x < 0)
  1000. {
  1001. rect.x = 0;
  1002. }
  1003. if (rect.y < 0)
  1004. {
  1005. rect.y = 0;
  1006. }
  1007. VIDEO_UpdateScreen(&rect);
  1008. }
  1009. }
  1010. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  1011. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  1012. break;
  1013. case kDialogCenter:
  1014. g_TextLib.posDialogText = PAL_XY(80, 40);
  1015. break;
  1016. case kDialogLower:
  1017. if (iNumCharFace > 0)
  1018. {
  1019. //
  1020. // Display the character face at the lower part of the screen
  1021. //
  1022. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  1023. {
  1024. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  1025. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  1026. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  1027. VIDEO_UpdateScreen(NULL);
  1028. }
  1029. }
  1030. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  1031. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  1032. break;
  1033. case kDialogCenterWindow:
  1034. g_TextLib.posDialogText = PAL_XY(160, 40);
  1035. break;
  1036. }
  1037. g_TextLib.bDialogPosition = bDialogLocation;
  1038. }
  1039. static VOID
  1040. PAL_DialogWaitForKey(
  1041. VOID
  1042. )
  1043. /*++
  1044. Purpose:
  1045. Wait for player to press a key after showing a dialog.
  1046. Parameters:
  1047. None.
  1048. Return value:
  1049. None.
  1050. --*/
  1051. {
  1052. PAL_LARGE SDL_Color palette[256];
  1053. SDL_Color *pCurrentPalette, t;
  1054. int i;
  1055. //
  1056. // get the current palette
  1057. //
  1058. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  1059. memcpy(palette, pCurrentPalette, sizeof(palette));
  1060. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  1061. g_TextLib.bDialogPosition != kDialogCenter)
  1062. {
  1063. //
  1064. // show the icon
  1065. //
  1066. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  1067. if (p != NULL)
  1068. {
  1069. SDL_Rect rect;
  1070. rect.x = PAL_X(g_TextLib.posIcon);
  1071. rect.y = PAL_Y(g_TextLib.posIcon);
  1072. rect.w = 16;
  1073. rect.h = 16;
  1074. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  1075. VIDEO_UpdateScreen(&rect);
  1076. }
  1077. }
  1078. PAL_ClearKeyState();
  1079. while (TRUE)
  1080. {
  1081. UTIL_Delay(100);
  1082. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  1083. g_TextLib.bDialogPosition != kDialogCenter)
  1084. {
  1085. //
  1086. // palette shift
  1087. //
  1088. t = palette[0xF9];
  1089. for (i = 0xF9; i < 0xFE; i++)
  1090. {
  1091. palette[i] = palette[i + 1];
  1092. }
  1093. palette[0xFE] = t;
  1094. VIDEO_SetPalette(palette);
  1095. }
  1096. if (g_InputState.dwKeyPress != 0)
  1097. {
  1098. break;
  1099. }
  1100. }
  1101. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  1102. g_TextLib.bDialogPosition != kDialogCenter)
  1103. {
  1104. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  1105. }
  1106. PAL_ClearKeyState();
  1107. g_TextLib.fUserSkip = FALSE;
  1108. }
  1109. VOID
  1110. PAL_ShowDialogText(
  1111. LPCWSTR lpszText
  1112. )
  1113. /*++
  1114. Purpose:
  1115. Show one line of the dialog text.
  1116. Parameters:
  1117. [IN] lpszText - the text to be shown.
  1118. Return value:
  1119. None.
  1120. --*/
  1121. {
  1122. SDL_Rect rect;
  1123. int x, y;
  1124. PAL_ClearKeyState();
  1125. g_TextLib.bIcon = 0;
  1126. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  1127. {
  1128. //
  1129. // Update the screen in battle, or the graphics may seem messed up
  1130. //
  1131. VIDEO_UpdateScreen(NULL);
  1132. g_fUpdatedInBattle = TRUE;
  1133. }
  1134. if (g_TextLib.nCurrentDialogLine > 3)
  1135. {
  1136. //
  1137. // The rest dialogs should be shown in the next page.
  1138. //
  1139. PAL_DialogWaitForKey();
  1140. g_TextLib.nCurrentDialogLine = 0;
  1141. VIDEO_RestoreScreen();
  1142. VIDEO_UpdateScreen(NULL);
  1143. }
  1144. x = PAL_X(g_TextLib.posDialogText);
  1145. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  1146. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  1147. {
  1148. //
  1149. // The text should be shown in a small window at the center of the screen
  1150. //
  1151. if (!gConfig.fIsClassic && gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  1152. {
  1153. PAL_BattleUIShowText(lpszText, 1400);
  1154. }
  1155. else
  1156. {
  1157. PAL_POS pos;
  1158. LPBOX lpBox;
  1159. int i, w = wcslen(lpszText), len = 0;
  1160. for (i = 0; i < w; i++)
  1161. len += PAL_CharWidth(lpszText[i]) >> 3;
  1162. //
  1163. // Create the window box
  1164. //
  1165. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  1166. lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE);
  1167. rect.x = PAL_X(pos);
  1168. rect.y = PAL_Y(pos);
  1169. rect.w = 320 - rect.x * 2 + 32;
  1170. rect.h = 64;
  1171. //
  1172. // Show the text on the screen
  1173. //
  1174. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  1175. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE, FALSE);
  1176. VIDEO_UpdateScreen(&rect);
  1177. PAL_DialogWaitForKey();
  1178. //
  1179. // Delete the box
  1180. //
  1181. PAL_DeleteBox(lpBox);
  1182. VIDEO_UpdateScreen(&rect);
  1183. PAL_EndDialog();
  1184. }
  1185. }
  1186. else
  1187. {
  1188. int len = wcslen(lpszText);
  1189. if (g_TextLib.nCurrentDialogLine == 0 &&
  1190. g_TextLib.bDialogPosition != kDialogCenter &&
  1191. (lpszText[len - 1] == 0xff1a ||
  1192. lpszText[len - 1] == 0x2236 || // Special case for Pal WIN95 Simplified Chinese version
  1193. lpszText[len - 1] == ':')
  1194. )
  1195. {
  1196. //
  1197. // name of character
  1198. //
  1199. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE, FALSE);
  1200. }
  1201. else
  1202. {
  1203. //
  1204. // normal texts
  1205. //
  1206. WCHAR text[2];
  1207. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  1208. {
  1209. //
  1210. // Save the screen before we show the first line of dialog
  1211. //
  1212. VIDEO_BackupScreen();
  1213. }
  1214. while (lpszText != NULL && *lpszText != '\0')
  1215. {
  1216. switch (*lpszText)
  1217. {
  1218. case '-':
  1219. //
  1220. // Set the font color to Cyan
  1221. //
  1222. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  1223. {
  1224. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1225. }
  1226. else
  1227. {
  1228. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  1229. }
  1230. lpszText++;
  1231. break;
  1232. #if 0
  1233. /* Not used */
  1234. case '\'':
  1235. //
  1236. // Set the font color to Red
  1237. //
  1238. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  1239. {
  1240. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1241. }
  1242. else
  1243. {
  1244. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  1245. }
  1246. lpszText++;
  1247. break;
  1248. #endif
  1249. case '\"':
  1250. //
  1251. // Set the font color to Yellow
  1252. //
  1253. if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW)
  1254. {
  1255. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1256. }
  1257. else
  1258. {
  1259. g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW;
  1260. }
  1261. lpszText++;
  1262. break;
  1263. case '$':
  1264. //
  1265. // Set the delay time of text-displaying
  1266. //
  1267. g_TextLib.iDelayTime = wcstol(lpszText + 1, NULL, 10) * 10 / 7;
  1268. lpszText += 3;
  1269. break;
  1270. case '~':
  1271. //
  1272. // Delay for a period and quit
  1273. //
  1274. UTIL_Delay(wcstol(lpszText + 1, NULL, 10) * 80 / 7);
  1275. g_TextLib.nCurrentDialogLine = 0;
  1276. g_TextLib.fUserSkip = FALSE;
  1277. return; // don't go further
  1278. case ')':
  1279. //
  1280. // Set the waiting icon
  1281. //
  1282. g_TextLib.bIcon = 1;
  1283. lpszText++;
  1284. break;
  1285. case '(':
  1286. //
  1287. // Set the waiting icon
  1288. //
  1289. g_TextLib.bIcon = 2;
  1290. lpszText++;
  1291. break;
  1292. case '\\':
  1293. lpszText++;
  1294. default:
  1295. text[0] = *lpszText++;
  1296. text[1] = 0;
  1297. PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE, FALSE);
  1298. x += PAL_CharWidth(text[0]);
  1299. if (!g_TextLib.fUserSkip)
  1300. {
  1301. PAL_ClearKeyState();
  1302. UTIL_Delay(g_TextLib.iDelayTime * 8);
  1303. if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu))
  1304. {
  1305. //
  1306. // User pressed a key to skip the dialog
  1307. //
  1308. g_TextLib.fUserSkip = TRUE;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. g_TextLib.posIcon = PAL_XY(x, y);
  1314. g_TextLib.nCurrentDialogLine++;
  1315. }
  1316. }
  1317. }
  1318. VOID
  1319. PAL_ClearDialog(
  1320. BOOL fWaitForKey
  1321. )
  1322. /*++
  1323. Purpose:
  1324. Clear the state of the dialog.
  1325. Parameters:
  1326. [IN] fWaitForKey - whether wait for any key or not.
  1327. Return value:
  1328. None.
  1329. --*/
  1330. {
  1331. if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey)
  1332. {
  1333. PAL_DialogWaitForKey();
  1334. }
  1335. g_TextLib.nCurrentDialogLine = 0;
  1336. if (g_TextLib.bDialogPosition == kDialogCenter)
  1337. {
  1338. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1339. g_TextLib.posDialogText = PAL_XY(44, 26);
  1340. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1341. g_TextLib.bDialogPosition = kDialogUpper;
  1342. }
  1343. }
  1344. VOID
  1345. PAL_EndDialog(
  1346. VOID
  1347. )
  1348. /*++
  1349. Purpose:
  1350. Ends a dialog.
  1351. Parameters:
  1352. None.
  1353. Return value:
  1354. None.
  1355. --*/
  1356. {
  1357. PAL_ClearDialog(TRUE);
  1358. //
  1359. // Set some default parameters, as there are some parts of script
  1360. // which doesn't have a "start dialog" instruction before showing the dialog.
  1361. //
  1362. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1363. g_TextLib.posDialogText = PAL_XY(44, 26);
  1364. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1365. g_TextLib.bDialogPosition = kDialogUpper;
  1366. g_TextLib.fUserSkip = FALSE;
  1367. g_TextLib.fPlayingRNG = FALSE;
  1368. }
  1369. BOOL
  1370. PAL_IsInDialog(
  1371. VOID
  1372. )
  1373. /*++
  1374. Purpose:
  1375. Check if there are dialog texts on the screen.
  1376. Parameters:
  1377. None.
  1378. Return value:
  1379. TRUE if there are dialog texts on the screen, FALSE if not.
  1380. --*/
  1381. {
  1382. return (g_TextLib.nCurrentDialogLine != 0);
  1383. }
  1384. BOOL
  1385. PAL_DialogIsPlayingRNG(
  1386. VOID
  1387. )
  1388. /*++
  1389. Purpose:
  1390. Check if the script used the RNG playing parameter when displaying texts.
  1391. Parameters:
  1392. None.
  1393. Return value:
  1394. TRUE if the script used the RNG playing parameter, FALSE if not.
  1395. --*/
  1396. {
  1397. return g_TextLib.fPlayingRNG;
  1398. }
  1399. INT
  1400. PAL_MultiByteToWideCharCP(
  1401. CODEPAGE cp,
  1402. LPCSTR mbs,
  1403. int mbslength,
  1404. LPWSTR wcs,
  1405. int wcslength
  1406. )
  1407. /*++
  1408. Purpose:
  1409. Convert multi-byte string into the corresponding unicode string.
  1410. Parameters:
  1411. [IN] cp - Code page for conversion.
  1412. [IN] mbs - Pointer to the multi-byte string.
  1413. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1414. [IN] wcs - Pointer to the wide string buffer.
  1415. [IN] wcslength - Length of the wide string buffer.
  1416. Return value:
  1417. The length of converted wide string. If mbslength is set to -1, the returned
  1418. value includes the terminal null-char; otherwise, the null-char is not included.
  1419. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1420. required length of the wide string buffer.
  1421. --*/
  1422. {
  1423. int i = 0, state = 0, wlen = 0, null = 0;
  1424. if (mbslength == -1)
  1425. {
  1426. mbslength = strlen(mbs);
  1427. null = 1;
  1428. }
  1429. if (!wcs)
  1430. {
  1431. switch (cp)
  1432. {
  1433. //case CP_SHIFTJIS:
  1434. // for (i = 0; i < mbslength && mbs[i]; i++)
  1435. // {
  1436. // if (state == 0)
  1437. // {
  1438. // if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] >= 0xfd || ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf))
  1439. // wlen++;
  1440. // else
  1441. // state = 1;
  1442. // }
  1443. // else
  1444. // {
  1445. // wlen++;
  1446. // state = 0;
  1447. // }
  1448. // }
  1449. // break;
  1450. case CP_GBK:
  1451. case CP_BIG5:
  1452. for (i = 0; i < mbslength && mbs[i]; i++)
  1453. {
  1454. if (state == 0)
  1455. {
  1456. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] == 0xff)
  1457. wlen++;
  1458. else
  1459. state = 1;
  1460. }
  1461. else
  1462. {
  1463. wlen++;
  1464. state = 0;
  1465. }
  1466. }
  1467. break;
  1468. case CP_UTF_8:
  1469. for (i = 0; i < mbslength && mbs[i]; i++)
  1470. {
  1471. if (state == 0)
  1472. {
  1473. if ((BYTE)mbs[i] >= 0x80)
  1474. {
  1475. BYTE s = (BYTE)mbs[i] << 1;
  1476. while (s >= 0x80) { state++; s <<= 1; }
  1477. if (state < 1 || state > 3)
  1478. {
  1479. state = 0;
  1480. wlen++;
  1481. }
  1482. }
  1483. else
  1484. wlen++;
  1485. }
  1486. else
  1487. {
  1488. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1489. {
  1490. if (--state == 0) wlen++;
  1491. }
  1492. else
  1493. {
  1494. state = 0; wlen++;
  1495. }
  1496. }
  1497. }
  1498. break;
  1499. default:
  1500. return -1;
  1501. }
  1502. if (i < mbslength && !mbs[i]) null = 1;
  1503. return wlen + null + (state != 0);
  1504. }
  1505. else
  1506. {
  1507. WCHAR invalid_char;
  1508. switch (cp)
  1509. {
  1510. //case CP_SHIFTJIS:
  1511. // invalid_char = 0x30fb;
  1512. // for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1513. // {
  1514. // if (state == 0)
  1515. // {
  1516. // if ((BYTE)mbs[i] <= 0x80)
  1517. // wcs[wlen++] = mbs[i];
  1518. // else if ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf)
  1519. // wcs[wlen++] = cptbl_jis_half[(BYTE)mbs[i] - 0xa0];
  1520. // else if ((BYTE)mbs[i] == 0xfd)
  1521. // wcs[wlen++] = 0xf8f1;
  1522. // else if ((BYTE)mbs[i] == 0xfe)
  1523. // wcs[wlen++] = 0xf8f2;
  1524. // else if ((BYTE)mbs[i] == 0xff)
  1525. // wcs[wlen++] = 0xf8f3;
  1526. // else
  1527. // state = 1;
  1528. // }
  1529. // else
  1530. // {
  1531. // if ((BYTE)mbs[i] < 0x40)
  1532. // wcs[wlen++] = 0x30fb;
  1533. // else if ((BYTE)mbs[i - 1] < 0xa0)
  1534. // wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1535. // else
  1536. // wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0xc1][(BYTE)mbs[i] - 0x40];
  1537. // state = 0;
  1538. // }
  1539. // }
  1540. // break;
  1541. case CP_GBK:
  1542. invalid_char = 0x3f;
  1543. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1544. {
  1545. if (state == 0)
  1546. {
  1547. if ((BYTE)mbs[i] < 0x80)
  1548. wcs[wlen++] = mbs[i];
  1549. else if ((BYTE)mbs[i] == 0x80)
  1550. wcs[wlen++] = 0x20ac;
  1551. else if ((BYTE)mbs[i] == 0xff)
  1552. wcs[wlen++] = 0xf8f5;
  1553. else
  1554. state = 1;
  1555. }
  1556. else
  1557. {
  1558. if ((BYTE)mbs[i] < 0x40)
  1559. wcs[wlen++] = invalid_char;
  1560. else
  1561. wcs[wlen++] = cptbl_gbk[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1562. state = 0;
  1563. }
  1564. }
  1565. break;
  1566. case CP_BIG5:
  1567. invalid_char = 0x3f;
  1568. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1569. {
  1570. if (state == 0)
  1571. {
  1572. if ((BYTE)mbs[i] <= 0x80)
  1573. wcs[wlen++] = mbs[i];
  1574. else if ((BYTE)mbs[i] == 0xff)
  1575. wcs[wlen++] = 0xf8f8;
  1576. else
  1577. state = 1;
  1578. }
  1579. else
  1580. {
  1581. if ((BYTE)mbs[i] < 0x40 || ((BYTE)mbs[i] >= 0x7f && (BYTE)mbs[i] <= 0xa0))
  1582. wcs[wlen++] = invalid_char;
  1583. else if ((BYTE)mbs[i] <= 0x7e)
  1584. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1585. else
  1586. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x60];
  1587. state = 0;
  1588. }
  1589. }
  1590. break;
  1591. case CP_UTF_8:
  1592. invalid_char = 0x3f;
  1593. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1594. {
  1595. if (state == 0)
  1596. {
  1597. if ((BYTE)mbs[i] >= 0x80)
  1598. {
  1599. BYTE s = (BYTE)mbs[i] << 1;
  1600. while (s >= 0x80) { state++; s <<= 1; }
  1601. if (state < 1 || state > 3)
  1602. {
  1603. state = 0;
  1604. wcs[wlen++] = invalid_char;
  1605. }
  1606. else
  1607. {
  1608. wcs[wlen] = s >> (state + 1);
  1609. }
  1610. }
  1611. else
  1612. wcs[wlen++] = mbs[i];
  1613. }
  1614. else
  1615. {
  1616. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1617. {
  1618. wcs[wlen] <<= 6;
  1619. wcs[wlen] |= (BYTE)mbs[i] & 0x3f;
  1620. if (--state == 0) wlen++;
  1621. }
  1622. else
  1623. {
  1624. state = 0;
  1625. wcs[wlen++] = invalid_char;
  1626. }
  1627. }
  1628. }
  1629. break;
  1630. default:
  1631. return -1;
  1632. }
  1633. if (state != 0 && wlen < wcslength)
  1634. {
  1635. wcs[wlen++] = invalid_char;
  1636. }
  1637. if (null || (i < mbslength && !mbs[i]))
  1638. {
  1639. if (wlen < wcslength)
  1640. wcs[wlen++] = 0;
  1641. else
  1642. wcs[wlen - 1] = 0;
  1643. }
  1644. return wlen;
  1645. }
  1646. }
  1647. INT
  1648. PAL_MultiByteToWideChar(
  1649. LPCSTR mbs,
  1650. int mbslength,
  1651. LPWSTR wcs,
  1652. int wcslength
  1653. )
  1654. /*++
  1655. Purpose:
  1656. Convert multi-byte string into the corresponding unicode string.
  1657. Parameters:
  1658. [IN] mbs - Pointer to the multi-byte string.
  1659. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1660. [IN] wcs - Pointer to the wide string buffer.
  1661. [IN] wcslength - Length of the wide string buffer.
  1662. Return value:
  1663. The length of converted wide string. If mbslength is set to -1, the returned
  1664. value includes the terminal null-char; otherwise, the null-char is not included.
  1665. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1666. required length of the wide string buffer.
  1667. --*/
  1668. {
  1669. return PAL_MultiByteToWideCharCP(gConfig.iCodePage, mbs, mbslength, wcs, wcslength);
  1670. }
  1671. WCHAR
  1672. PAL_GetInvalidChar(
  1673. CODEPAGE iCodePage
  1674. )
  1675. {
  1676. switch(iCodePage)
  1677. {
  1678. case CP_BIG5: return 0x3f;
  1679. case CP_GBK: return 0x3f;
  1680. //case CP_SHIFTJIS: return 0x30fb;
  1681. case CP_UTF_8: return 0x3f;
  1682. default: return 0;
  1683. }
  1684. }
  1685. INT
  1686. PAL_WordMaxWidth(
  1687. INT nFirstWord,
  1688. INT nWordNum
  1689. )
  1690. /*++
  1691. Purpose:
  1692. Calculate the maximal text width of a specific range of words in number of full width characters.
  1693. Parameters:
  1694. [IN] nFirstWord - First index of word.
  1695. [IN] nWordNum - Number of words.
  1696. Return value:
  1697. Maximal text width.
  1698. --*/
  1699. {
  1700. int i, r = 0;
  1701. for (i = 0; i < nWordNum; i++)
  1702. {
  1703. LPCWSTR itemText = PAL_GetWord(nFirstWord + i);
  1704. int j = 0, l = wcslen(itemText), w = 0;
  1705. for (j = 0; j < l; j++)
  1706. {
  1707. w += PAL_CharWidth(itemText[j]);
  1708. }
  1709. w = (w + 8) >> 4;
  1710. if (r < w)
  1711. {
  1712. r = w;
  1713. }
  1714. }
  1715. return r;
  1716. }
  1717. INT
  1718. PAL_WordWidth(
  1719. INT nWordIndex
  1720. )
  1721. /*++
  1722. Purpose:
  1723. Calculate the text width of a specific word.
  1724. Parameters:
  1725. [IN] nWordNum - Index of the word.
  1726. Return value:
  1727. Text width.
  1728. --*/
  1729. {
  1730. LPCWSTR itemText = PAL_GetWord(nWordIndex);
  1731. int i, l = wcslen(itemText), w = 0;
  1732. for (i = 0; i < l; i++)
  1733. {
  1734. w += PAL_CharWidth(itemText[i]);
  1735. }
  1736. return (w + 8) >> 4;
  1737. }
  1738. VOID
  1739. PAL_LoadObjectDesc(
  1740. LPCSTR lpszFileName
  1741. )
  1742. {
  1743. char temp[MESSAGE_MAX_BUFFER_SIZE];
  1744. struct _msg_entry
  1745. {
  1746. struct _msg_entry *next;
  1747. wchar_t *value;
  1748. };
  1749. struct _msg_list_entry
  1750. {
  1751. struct _msg_list_entry *next;
  1752. struct _msg_entry *value;
  1753. int index, count;
  1754. } head = { NULL }, *item = NULL;
  1755. int count = 0;
  1756. FILE *fp = UTIL_OpenFileForMode(lpszFileName, "r");
  1757. if (!fp) return;
  1758. while (!feof(fp))
  1759. {
  1760. char *buffer;
  1761. if (buffer = PAL_ReadOneLine(temp, MESSAGE_MAX_BUFFER_SIZE, fp))
  1762. {
  1763. item = PAL_ParseOneDescriptionLine(buffer, &head, item);
  1764. if (buffer != temp) free(buffer);
  1765. }
  1766. }
  1767. PAL_ParseObjectDesc(&head);
  1768. fclose(fp);
  1769. }