text.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383
  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. #ifndef PAL_UNICODE
  28. #define WORD_LENGTH 10
  29. #endif
  30. #define FONT_COLOR_DEFAULT 0x4F
  31. #define FONT_COLOR_YELLOW 0x2D
  32. #define FONT_COLOR_RED 0x1A
  33. #define FONT_COLOR_CYAN 0x8D
  34. #define FONT_COLOR_CYAN_ALT 0x8C
  35. BOOL g_fUpdatedInBattle = FALSE;
  36. #ifdef PAL_UNICODE
  37. #define INCLUDE_CODEPAGE_H
  38. #include "codepage.h"
  39. static const WCHAR* gc_rgszAdditionalWords[CP_MAX][6] = {
  40. { L"\x6230\x9B25\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  41. { L"\x6218\x6597\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  42. { L"\x6226\x95D8\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  43. };
  44. static const WCHAR** g_rgszAdditionalWords;
  45. #else
  46. static const char g_rgszAdditionalWords[][WORD_LENGTH + 1] = {
  47. {0xBE, 0xD4, 0xB0, 0xAB, 0xB3, 0x74, 0xAB, 0xD7, 0x00, 0x00, 0x00}, // Battle Speed
  48. {0xA4, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 1
  49. {0xA4, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 2
  50. {0xA4, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 3
  51. {0xA5, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 4
  52. {0xA4, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 5
  53. };
  54. #endif
  55. typedef struct tagTEXTLIB
  56. {
  57. #ifdef PAL_UNICODE
  58. LPWSTR* lpWordBuf;
  59. LPWSTR* lpMsgBuf;
  60. #else
  61. LPBYTE lpWordBuf;
  62. LPBYTE lpMsgBuf;
  63. LPDWORD lpMsgOffset;
  64. #endif
  65. int nWords;
  66. int nMsgs;
  67. int nCurrentDialogLine;
  68. BYTE bCurrentFontColor;
  69. PAL_POS posIcon;
  70. PAL_POS posDialogTitle;
  71. PAL_POS posDialogText;
  72. BYTE bDialogPosition;
  73. BYTE bIcon;
  74. int iDelayTime;
  75. BOOL fUserSkip;
  76. BOOL fPlayingRNG;
  77. BYTE bufDialogIcons[282];
  78. } TEXTLIB, *LPTEXTLIB;
  79. static TEXTLIB g_TextLib;
  80. INT
  81. PAL_InitText(
  82. VOID
  83. )
  84. /*++
  85. Purpose:
  86. Initialize the in-game texts.
  87. Parameters:
  88. None.
  89. Return value:
  90. 0 = success.
  91. -1 = memory allocation error.
  92. --*/
  93. {
  94. FILE *fpMsg, *fpWord;
  95. #ifdef PAL_UNICODE
  96. DWORD *offsets;
  97. LPBYTE temp;
  98. LPWSTR tmp;
  99. int wlen, wpos;
  100. #endif
  101. int i;
  102. //
  103. // Open the message and word data files.
  104. //
  105. fpMsg = UTIL_OpenRequiredFile("m.msg");
  106. fpWord = UTIL_OpenRequiredFile("word.dat");
  107. //
  108. // See how many words we have
  109. //
  110. fseek(fpWord, 0, SEEK_END);
  111. i = ftell(fpWord);
  112. #ifdef PAL_UNICODE
  113. //
  114. // Each word has 10 or 16 bytes
  115. //
  116. g_TextLib.nWords = (i + (gpGlobals->dwWordLength - 1)) / gpGlobals->dwWordLength;
  117. #else
  118. //
  119. // Each word has 10 bytes
  120. //
  121. g_TextLib.nWords = (i + (WORD_LENGTH - 1)) / WORD_LENGTH;
  122. #endif
  123. //
  124. // Read the words
  125. //
  126. #ifdef PAL_UNICODE
  127. temp = (LPBYTE)malloc(i);
  128. if (temp == NULL)
  129. #else
  130. g_TextLib.lpWordBuf = (LPBYTE)malloc(i);
  131. if (g_TextLib.lpWordBuf == NULL)
  132. #endif
  133. {
  134. fclose(fpWord);
  135. fclose(fpMsg);
  136. return -1;
  137. }
  138. fseek(fpWord, 0, SEEK_SET);
  139. #ifdef PAL_UNICODE
  140. fread(temp, i, 1, fpWord);
  141. #else
  142. fread(g_TextLib.lpWordBuf, i, 1, fpWord);
  143. #endif
  144. //
  145. // Close the words file
  146. //
  147. fclose(fpWord);
  148. #ifdef PAL_UNICODE
  149. // Split the words and do code page conversion
  150. for (i = 0, wlen = 0; i < g_TextLib.nWords; i++)
  151. {
  152. int base = i * gpGlobals->dwWordLength;
  153. int pos = base + gpGlobals->dwWordLength - 1;
  154. while (pos >= base && temp[pos] == ' ') temp[pos--] = 0;
  155. wlen += PAL_MultiByteToWideChar(temp + base, gpGlobals->dwWordLength, NULL, 0) + 1;
  156. }
  157. g_TextLib.lpWordBuf = (LPWSTR*)malloc(g_TextLib.nWords * sizeof(LPWSTR));
  158. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  159. for (i = 0, wpos = 0; i < g_TextLib.nWords; i++)
  160. {
  161. int l;
  162. g_TextLib.lpWordBuf[i] = tmp + wpos;
  163. l = PAL_MultiByteToWideChar(temp + i * gpGlobals->dwWordLength, gpGlobals->dwWordLength, g_TextLib.lpWordBuf[i], wlen - wpos);
  164. if (l > 0 && g_TextLib.lpWordBuf[i][l - 1] == '1')
  165. g_TextLib.lpWordBuf[i][l - 1] = 0;
  166. g_TextLib.lpWordBuf[i][l] = 0;
  167. wpos += l + 1;
  168. }
  169. free(temp);
  170. #endif
  171. //
  172. // Read the message offsets. The message offsets are in SSS.MKF #3
  173. //
  174. i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD);
  175. g_TextLib.nMsgs = i - 1;
  176. #ifdef PAL_UNICODE
  177. offsets = (LPDWORD)malloc(i * sizeof(DWORD));
  178. if (offsets == NULL)
  179. #else
  180. g_TextLib.lpMsgOffset = (LPDWORD)malloc(i * sizeof(DWORD));
  181. if (g_TextLib.lpMsgOffset == NULL)
  182. #endif
  183. {
  184. free(g_TextLib.lpWordBuf);
  185. fclose(fpMsg);
  186. return -1;
  187. }
  188. #ifdef PAL_UNICODE
  189. PAL_MKFReadChunk((LPBYTE)(offsets), i * sizeof(DWORD), 3, gpGlobals->f.fpSSS);
  190. #else
  191. PAL_MKFReadChunk((LPBYTE)(g_TextLib.lpMsgOffset), i * sizeof(DWORD), 3,
  192. gpGlobals->f.fpSSS);
  193. #endif
  194. //
  195. // Read the messages.
  196. //
  197. fseek(fpMsg, 0, SEEK_END);
  198. i = ftell(fpMsg);
  199. #ifdef PAL_UNICODE
  200. temp = (LPBYTE)malloc(i);
  201. if (temp == NULL)
  202. #else
  203. g_TextLib.lpMsgBuf = (LPBYTE)malloc(i);
  204. if (g_TextLib.lpMsgBuf == NULL)
  205. #endif
  206. {
  207. #ifdef PAL_UNICODE
  208. free(offsets);
  209. free(g_TextLib.lpWordBuf[0]);
  210. #else
  211. free(g_TextLib.lpMsgOffset);
  212. #endif
  213. free(g_TextLib.lpWordBuf);
  214. fclose(fpMsg);
  215. return -1;
  216. }
  217. fseek(fpMsg, 0, SEEK_SET);
  218. #ifdef PAL_UNICODE
  219. fread(temp, 1, i, fpMsg);
  220. #else
  221. fread(g_TextLib.lpMsgBuf, 1, i, fpMsg);
  222. #endif
  223. fclose(fpMsg);
  224. #ifdef PAL_UNICODE
  225. // Split messages and do code page conversion here
  226. for (i = 0, wlen = 0; i < g_TextLib.nMsgs; i++)
  227. {
  228. wlen += PAL_MultiByteToWideChar(temp + SWAP32(offsets[i]), SWAP32(offsets[i + 1]) - SWAP32(offsets[i]), NULL, 0) + 1;
  229. }
  230. g_TextLib.lpMsgBuf = (LPWSTR*)malloc(g_TextLib.nMsgs * sizeof(LPWSTR));
  231. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  232. for (i = 0, wpos = 0; i < g_TextLib.nMsgs; i++)
  233. {
  234. int l;
  235. g_TextLib.lpMsgBuf[i] = tmp + wpos;
  236. l = PAL_MultiByteToWideChar(temp + SWAP32(offsets[i]), SWAP32(offsets[i + 1]) - SWAP32(offsets[i]), g_TextLib.lpMsgBuf[i], wlen - wpos);
  237. g_TextLib.lpMsgBuf[i][l] = 0;
  238. wpos += l + 1;
  239. }
  240. free(temp);
  241. free(offsets);
  242. g_rgszAdditionalWords = gc_rgszAdditionalWords[gpGlobals->iCodePage];
  243. #endif
  244. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  245. g_TextLib.bIcon = 0;
  246. g_TextLib.posIcon = 0;
  247. g_TextLib.nCurrentDialogLine = 0;
  248. g_TextLib.iDelayTime = 3;
  249. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  250. g_TextLib.posDialogText = PAL_XY(44, 26);
  251. g_TextLib.bDialogPosition = kDialogUpper;
  252. g_TextLib.fUserSkip = FALSE;
  253. PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA);
  254. return 0;
  255. }
  256. VOID
  257. PAL_FreeText(
  258. VOID
  259. )
  260. /*++
  261. Purpose:
  262. Free the memory used by the texts.
  263. Parameters:
  264. None.
  265. Return value:
  266. None.
  267. --*/
  268. {
  269. if (g_TextLib.lpMsgBuf != NULL)
  270. {
  271. # ifdef PAL_UNICODE
  272. free(g_TextLib.lpMsgBuf[0]);
  273. # endif
  274. free(g_TextLib.lpMsgBuf);
  275. g_TextLib.lpMsgBuf = NULL;
  276. }
  277. #ifndef PAL_UNICODE
  278. if (g_TextLib.lpMsgOffset != NULL)
  279. {
  280. free(g_TextLib.lpMsgOffset);
  281. g_TextLib.lpMsgOffset = NULL;
  282. }
  283. #endif
  284. if (g_TextLib.lpWordBuf != NULL)
  285. {
  286. # ifdef PAL_UNICODE
  287. free(g_TextLib.lpWordBuf[0]);
  288. # endif
  289. free(g_TextLib.lpWordBuf);
  290. g_TextLib.lpWordBuf = NULL;
  291. }
  292. }
  293. #ifdef PAL_UNICODE
  294. LPCWSTR
  295. #else
  296. LPCSTR
  297. #endif
  298. PAL_GetWord(
  299. WORD wNumWord
  300. )
  301. /*++
  302. Purpose:
  303. Get the specified word.
  304. Parameters:
  305. [IN] wNumWord - the number of the requested word.
  306. Return value:
  307. Pointer to the requested word. NULL if not found.
  308. --*/
  309. {
  310. #ifndef PAL_UNICODE
  311. static char buf[WORD_LENGTH + 1];
  312. #endif
  313. if (wNumWord >= PAL_ADDITIONAL_WORD_FIRST)
  314. {
  315. return g_rgszAdditionalWords[wNumWord - PAL_ADDITIONAL_WORD_FIRST];
  316. }
  317. if (wNumWord >= g_TextLib.nWords)
  318. {
  319. return NULL;
  320. }
  321. #ifdef PAL_UNICODE
  322. return g_TextLib.lpWordBuf[wNumWord];
  323. #else
  324. memcpy(buf, &g_TextLib.lpWordBuf[wNumWord * WORD_LENGTH], WORD_LENGTH);
  325. buf[WORD_LENGTH] = '\0';
  326. //
  327. // Remove the trailing spaces
  328. //
  329. trim(buf);
  330. if ((strlen(buf) & 1) != 0 && buf[strlen(buf) - 1] == '1')
  331. {
  332. buf[strlen(buf) - 1] = '\0';
  333. }
  334. return buf;
  335. #endif
  336. }
  337. #ifdef PAL_UNICODE
  338. LPCWSTR
  339. #else
  340. LPCSTR
  341. #endif
  342. PAL_GetMsg(
  343. WORD wNumMsg
  344. )
  345. /*++
  346. Purpose:
  347. Get the specified message.
  348. Parameters:
  349. [IN] wNumMsg - the number of the requested message.
  350. Return value:
  351. Pointer to the requested message. NULL if not found.
  352. --*/
  353. {
  354. #ifdef PAL_UNICODE
  355. return (wNumMsg >= g_TextLib.nMsgs) ? NULL : g_TextLib.lpMsgBuf[wNumMsg];
  356. #else
  357. static char buf[256];
  358. DWORD dwOffset, dwSize;
  359. if (wNumMsg >= g_TextLib.nMsgs)
  360. {
  361. return NULL;
  362. }
  363. dwOffset = SWAP32(g_TextLib.lpMsgOffset[wNumMsg]);
  364. dwSize = SWAP32(g_TextLib.lpMsgOffset[wNumMsg + 1]) - dwOffset;
  365. assert(dwSize < 255);
  366. memcpy(buf, &g_TextLib.lpMsgBuf[dwOffset], dwSize);
  367. buf[dwSize] = '\0';
  368. return buf;
  369. #endif
  370. }
  371. VOID
  372. PAL_DrawText(
  373. #ifdef PAL_UNICODE
  374. LPCWSTR lpszText,
  375. #else
  376. LPCSTR lpszText,
  377. #endif
  378. PAL_POS pos,
  379. BYTE bColor,
  380. BOOL fShadow,
  381. BOOL fUpdate
  382. )
  383. /*++
  384. Purpose:
  385. Draw text on the screen.
  386. Parameters:
  387. [IN] lpszText - the text to be drawn.
  388. [IN] pos - Position of the text.
  389. [IN] bColor - Color of the text.
  390. [IN] fShadow - TRUE if the text is shadowed or not.
  391. [IN] fUpdate - TRUE if update the screen area.
  392. Return value:
  393. None.
  394. --*/
  395. {
  396. SDL_Rect rect, urect;
  397. #ifndef PAL_UNICODE
  398. WORD wChar;
  399. #endif
  400. rect.x = PAL_X(pos);
  401. rect.y = PAL_Y(pos);
  402. urect.x = rect.x;
  403. urect.y = rect.y;
  404. #if defined(PAL_WIN95) || defined(PAL_UNICODE)
  405. urect.h = 17;
  406. #else
  407. urect.h = 16;
  408. #endif
  409. urect.w = 0;
  410. while (*lpszText)
  411. {
  412. //
  413. // Draw the character
  414. //
  415. # ifdef PAL_UNICODE
  416. int char_width = PAL_CharWidth(*lpszText);
  417. if (fShadow)
  418. {
  419. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  420. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  421. }
  422. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  423. lpszText++;
  424. rect.x += char_width;
  425. urect.w += char_width;
  426. # else
  427. if (*lpszText & 0x80)
  428. {
  429. //
  430. // Chinese Character
  431. //
  432. wChar = SWAP16(((LPBYTE)lpszText)[0] | (((LPBYTE)lpszText)[1] << 8));
  433. if (fShadow)
  434. {
  435. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  436. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  437. }
  438. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  439. lpszText += 2;
  440. rect.x += 16;
  441. urect.w += 16;
  442. }
  443. else
  444. {
  445. //
  446. // ASCII character
  447. //
  448. if (fShadow)
  449. {
  450. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  451. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  452. }
  453. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  454. lpszText++;
  455. rect.x += 8;
  456. urect.w += 8;
  457. }
  458. # endif
  459. }
  460. //
  461. // Update the screen area
  462. //
  463. if (fUpdate && urect.w > 0)
  464. {
  465. #ifdef PAL_WIN95
  466. urect.w++;
  467. if (urect.x + urect.w > 320)
  468. {
  469. urect.w = 320 - urect.x;
  470. }
  471. #endif
  472. VIDEO_UpdateScreen(&urect);
  473. }
  474. }
  475. VOID
  476. PAL_DialogSetDelayTime(
  477. INT iDelayTime
  478. )
  479. /*++
  480. Purpose:
  481. Set the delay time for dialog.
  482. Parameters:
  483. [IN] iDelayTime - the delay time to be set.
  484. Return value:
  485. None.
  486. --*/
  487. {
  488. g_TextLib.iDelayTime = iDelayTime;
  489. }
  490. VOID
  491. PAL_StartDialog(
  492. BYTE bDialogLocation,
  493. BYTE bFontColor,
  494. INT iNumCharFace,
  495. BOOL fPlayingRNG
  496. )
  497. /*++
  498. Purpose:
  499. Start a new dialog.
  500. Parameters:
  501. [IN] bDialogLocation - the location of the text on the screen.
  502. [IN] bFontColor - the font color of the text.
  503. [IN] iNumCharFace - number of the character face in RGM.MKF.
  504. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  505. Return value:
  506. None.
  507. --*/
  508. {
  509. PAL_LARGE BYTE buf[16384];
  510. SDL_Rect rect;
  511. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  512. {
  513. //
  514. // Update the screen in battle, or the graphics may seem messed up
  515. //
  516. VIDEO_UpdateScreen(NULL);
  517. g_fUpdatedInBattle = TRUE;
  518. }
  519. g_TextLib.bIcon = 0;
  520. g_TextLib.posIcon = 0;
  521. g_TextLib.nCurrentDialogLine = 0;
  522. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  523. g_TextLib.fUserSkip = FALSE;
  524. if (bFontColor != 0)
  525. {
  526. g_TextLib.bCurrentFontColor = bFontColor;
  527. }
  528. if (fPlayingRNG && iNumCharFace)
  529. {
  530. VIDEO_BackupScreen();
  531. g_TextLib.fPlayingRNG = TRUE;
  532. }
  533. switch (bDialogLocation)
  534. {
  535. case kDialogUpper:
  536. if (iNumCharFace > 0)
  537. {
  538. //
  539. // Display the character face at the upper part of the screen
  540. //
  541. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  542. {
  543. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  544. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  545. rect.x = 48 - rect.w / 2;
  546. rect.y = 55 - rect.h / 2;
  547. if (rect.x < 0)
  548. {
  549. rect.x = 0;
  550. }
  551. if (rect.y < 0)
  552. {
  553. rect.y = 0;
  554. }
  555. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  556. if (rect.x < 0)
  557. {
  558. rect.x = 0;
  559. }
  560. if (rect.y < 0)
  561. {
  562. rect.y = 0;
  563. }
  564. VIDEO_UpdateScreen(&rect);
  565. }
  566. }
  567. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  568. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  569. break;
  570. case kDialogCenter:
  571. g_TextLib.posDialogText = PAL_XY(80, 40);
  572. break;
  573. case kDialogLower:
  574. if (iNumCharFace > 0)
  575. {
  576. //
  577. // Display the character face at the lower part of the screen
  578. //
  579. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  580. {
  581. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  582. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  583. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  584. VIDEO_UpdateScreen(NULL);
  585. }
  586. }
  587. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  588. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  589. break;
  590. case kDialogCenterWindow:
  591. g_TextLib.posDialogText = PAL_XY(160, 40);
  592. break;
  593. }
  594. g_TextLib.bDialogPosition = bDialogLocation;
  595. }
  596. static VOID
  597. PAL_DialogWaitForKey(
  598. VOID
  599. )
  600. /*++
  601. Purpose:
  602. Wait for player to press a key after showing a dialog.
  603. Parameters:
  604. None.
  605. Return value:
  606. None.
  607. --*/
  608. {
  609. PAL_LARGE SDL_Color palette[256];
  610. SDL_Color *pCurrentPalette, t;
  611. int i;
  612. //
  613. // get the current palette
  614. //
  615. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  616. memcpy(palette, pCurrentPalette, sizeof(palette));
  617. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  618. g_TextLib.bDialogPosition != kDialogCenter)
  619. {
  620. //
  621. // show the icon
  622. //
  623. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  624. if (p != NULL)
  625. {
  626. SDL_Rect rect;
  627. rect.x = PAL_X(g_TextLib.posIcon);
  628. rect.y = PAL_Y(g_TextLib.posIcon);
  629. rect.w = 16;
  630. rect.h = 16;
  631. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  632. VIDEO_UpdateScreen(&rect);
  633. }
  634. }
  635. PAL_ClearKeyState();
  636. while (TRUE)
  637. {
  638. UTIL_Delay(100);
  639. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  640. g_TextLib.bDialogPosition != kDialogCenter)
  641. {
  642. //
  643. // palette shift
  644. //
  645. t = palette[0xF9];
  646. for (i = 0xF9; i < 0xFE; i++)
  647. {
  648. palette[i] = palette[i + 1];
  649. }
  650. palette[0xFE] = t;
  651. VIDEO_SetPalette(palette);
  652. }
  653. if (g_InputState.dwKeyPress != 0)
  654. {
  655. break;
  656. }
  657. }
  658. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  659. g_TextLib.bDialogPosition != kDialogCenter)
  660. {
  661. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  662. }
  663. PAL_ClearKeyState();
  664. g_TextLib.fUserSkip = FALSE;
  665. }
  666. VOID
  667. PAL_ShowDialogText(
  668. #ifdef PAL_UNICODE
  669. LPCWSTR lpszText
  670. #else
  671. LPCSTR lpszText
  672. #endif
  673. )
  674. /*++
  675. Purpose:
  676. Show one line of the dialog text.
  677. Parameters:
  678. [IN] lpszText - the text to be shown.
  679. Return value:
  680. None.
  681. --*/
  682. {
  683. SDL_Rect rect;
  684. #ifdef PAL_UNICODE
  685. int x, y;
  686. #else
  687. int x, y, len = strlen(lpszText);
  688. #endif
  689. PAL_ClearKeyState();
  690. g_TextLib.bIcon = 0;
  691. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  692. {
  693. //
  694. // Update the screen in battle, or the graphics may seem messed up
  695. //
  696. VIDEO_UpdateScreen(NULL);
  697. g_fUpdatedInBattle = TRUE;
  698. }
  699. if (g_TextLib.nCurrentDialogLine > 3)
  700. {
  701. //
  702. // The rest dialogs should be shown in the next page.
  703. //
  704. PAL_DialogWaitForKey();
  705. g_TextLib.nCurrentDialogLine = 0;
  706. VIDEO_RestoreScreen();
  707. VIDEO_UpdateScreen(NULL);
  708. }
  709. x = PAL_X(g_TextLib.posDialogText);
  710. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  711. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  712. {
  713. //
  714. // The text should be shown in a small window at the center of the screen
  715. //
  716. #ifndef PAL_CLASSIC
  717. if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  718. {
  719. PAL_BattleUIShowText(lpszText, 1400);
  720. }
  721. else
  722. #endif
  723. {
  724. PAL_POS pos;
  725. LPBOX lpBox;
  726. # ifdef PAL_UNICODE
  727. int i, w = wcslen(lpszText), len = 0;
  728. for (i = 0; i < w; i++)
  729. len += PAL_CharWidth(lpszText[i]) >> 3;
  730. # endif
  731. //
  732. // Create the window box
  733. //
  734. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  735. lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE);
  736. rect.x = PAL_X(pos);
  737. rect.y = PAL_Y(pos);
  738. rect.w = 320 - rect.x * 2 + 32;
  739. rect.h = 64;
  740. //
  741. // Show the text on the screen
  742. //
  743. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  744. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE);
  745. VIDEO_UpdateScreen(&rect);
  746. PAL_DialogWaitForKey();
  747. //
  748. // Delete the box
  749. //
  750. PAL_DeleteBox(lpBox);
  751. VIDEO_UpdateScreen(&rect);
  752. PAL_EndDialog();
  753. }
  754. }
  755. else
  756. {
  757. # ifdef PAL_UNICODE
  758. int len = wcslen(lpszText);
  759. # endif
  760. if (g_TextLib.nCurrentDialogLine == 0 &&
  761. g_TextLib.bDialogPosition != kDialogCenter &&
  762. # ifdef PAL_UNICODE
  763. (lpszText[len - 1] == 0xff1a ||
  764. # else
  765. (((BYTE)lpszText[len - 1] == 0x47 && (BYTE)lpszText[len - 2] == 0xA1) ||
  766. ((BYTE)lpszText[len - 1] == 0xBA && (BYTE)lpszText[len - 2] == 0xA3) ||
  767. ((BYTE)lpszText[len - 1] == 0xC3 && (BYTE)lpszText[len - 2] == 0xA1) ||
  768. # endif
  769. lpszText[len - 1] == ':'))
  770. {
  771. //
  772. // name of character
  773. //
  774. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE);
  775. }
  776. else
  777. {
  778. //
  779. // normal texts
  780. //
  781. # ifdef PAL_UNICODE
  782. WCHAR text[2];
  783. # else
  784. char text[3];
  785. # endif
  786. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  787. {
  788. //
  789. // Save the screen before we show the first line of dialog
  790. //
  791. VIDEO_BackupScreen();
  792. }
  793. while (lpszText != NULL && *lpszText != '\0')
  794. {
  795. switch (*lpszText)
  796. {
  797. case '-':
  798. //
  799. // Set the font color to Cyan
  800. //
  801. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  802. {
  803. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  804. }
  805. else
  806. {
  807. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  808. }
  809. lpszText++;
  810. break;
  811. #ifndef PAL_WIN95
  812. case '\'':
  813. //
  814. // Set the font color to Red
  815. //
  816. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  817. {
  818. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  819. }
  820. else
  821. {
  822. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  823. }
  824. lpszText++;
  825. break;
  826. #endif
  827. case '\"':
  828. //
  829. // Set the font color to Yellow
  830. //
  831. if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW)
  832. {
  833. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  834. }
  835. else
  836. {
  837. g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW;
  838. }
  839. lpszText++;
  840. break;
  841. case '$':
  842. //
  843. // Set the delay time of text-displaying
  844. //
  845. # ifdef PAL_UNICODE
  846. g_TextLib.iDelayTime = wcstol(lpszText + 1, NULL, 10) * 10 / 7;
  847. # else
  848. g_TextLib.iDelayTime = atoi(lpszText + 1) * 10 / 7;
  849. # endif
  850. lpszText += 3;
  851. break;
  852. case '~':
  853. //
  854. // Delay for a period and quit
  855. //
  856. # ifdef PAL_UNICODE
  857. UTIL_Delay(wcstol(lpszText + 1, NULL, 10) * 80 / 7);
  858. # else
  859. UTIL_Delay(atoi(lpszText + 1) * 80 / 7);
  860. # endif
  861. g_TextLib.nCurrentDialogLine = 0;
  862. g_TextLib.fUserSkip = FALSE;
  863. return; // don't go further
  864. case ')':
  865. //
  866. // Set the waiting icon
  867. //
  868. g_TextLib.bIcon = 1;
  869. lpszText++;
  870. break;
  871. case '(':
  872. //
  873. // Set the waiting icon
  874. //
  875. g_TextLib.bIcon = 2;
  876. lpszText++;
  877. break;
  878. case '\\':
  879. lpszText++;
  880. default:
  881. # ifdef PAL_UNICODE
  882. text[0] = *lpszText++;
  883. text[1] = 0;
  884. # else
  885. if (*lpszText & 0x80)
  886. {
  887. text[0] = lpszText[0];
  888. text[1] = lpszText[1];
  889. text[2] = '\0';
  890. lpszText += 2;
  891. }
  892. else
  893. {
  894. text[0] = *lpszText;
  895. text[1] = '\0';
  896. lpszText++;
  897. }
  898. # endif
  899. PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE);
  900. # ifdef PAL_UNICODE
  901. x += PAL_CharWidth(text[0]);
  902. # else
  903. x += ((text[0] & 0x80) ? 16 : 8);
  904. # endif
  905. if (!g_TextLib.fUserSkip)
  906. {
  907. PAL_ClearKeyState();
  908. UTIL_Delay(g_TextLib.iDelayTime * 8);
  909. if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu))
  910. {
  911. //
  912. // User pressed a key to skip the dialog
  913. //
  914. g_TextLib.fUserSkip = TRUE;
  915. }
  916. }
  917. }
  918. }
  919. g_TextLib.posIcon = PAL_XY(x, y);
  920. g_TextLib.nCurrentDialogLine++;
  921. }
  922. }
  923. }
  924. VOID
  925. PAL_ClearDialog(
  926. BOOL fWaitForKey
  927. )
  928. /*++
  929. Purpose:
  930. Clear the state of the dialog.
  931. Parameters:
  932. [IN] fWaitForKey - whether wait for any key or not.
  933. Return value:
  934. None.
  935. --*/
  936. {
  937. if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey)
  938. {
  939. PAL_DialogWaitForKey();
  940. }
  941. g_TextLib.nCurrentDialogLine = 0;
  942. if (g_TextLib.bDialogPosition == kDialogCenter)
  943. {
  944. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  945. g_TextLib.posDialogText = PAL_XY(44, 26);
  946. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  947. g_TextLib.bDialogPosition = kDialogUpper;
  948. }
  949. }
  950. VOID
  951. PAL_EndDialog(
  952. VOID
  953. )
  954. /*++
  955. Purpose:
  956. Ends a dialog.
  957. Parameters:
  958. None.
  959. Return value:
  960. None.
  961. --*/
  962. {
  963. PAL_ClearDialog(TRUE);
  964. //
  965. // Set some default parameters, as there are some parts of script
  966. // which doesn't have a "start dialog" instruction before showing the dialog.
  967. //
  968. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  969. g_TextLib.posDialogText = PAL_XY(44, 26);
  970. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  971. g_TextLib.bDialogPosition = kDialogUpper;
  972. g_TextLib.fUserSkip = FALSE;
  973. g_TextLib.fPlayingRNG = FALSE;
  974. }
  975. BOOL
  976. PAL_IsInDialog(
  977. VOID
  978. )
  979. /*++
  980. Purpose:
  981. Check if there are dialog texts on the screen.
  982. Parameters:
  983. None.
  984. Return value:
  985. TRUE if there are dialog texts on the screen, FALSE if not.
  986. --*/
  987. {
  988. return (g_TextLib.nCurrentDialogLine != 0);
  989. }
  990. BOOL
  991. PAL_DialogIsPlayingRNG(
  992. VOID
  993. )
  994. /*++
  995. Purpose:
  996. Check if the script used the RNG playing parameter when displaying texts.
  997. Parameters:
  998. None.
  999. Return value:
  1000. TRUE if the script used the RNG playing parameter, FALSE if not.
  1001. --*/
  1002. {
  1003. return g_TextLib.fPlayingRNG;
  1004. }
  1005. #ifdef PAL_UNICODE
  1006. INT
  1007. PAL_MultiByteToWideChar(
  1008. unsigned char *mbs,
  1009. int mbslength,
  1010. WCHAR *wcs,
  1011. int wcslength
  1012. )
  1013. /*++
  1014. Purpose:
  1015. Convert multi-byte string into the corresponding unicode string.
  1016. Parameters:
  1017. [IN] mbs - .
  1018. [IN] mbslength - .
  1019. [IN] wcs - .
  1020. [IN] wcslength - .
  1021. Return value:
  1022. The length
  1023. --*/
  1024. {
  1025. int i = 0, j = 0, state = 0, wlen = 0, null = 0;
  1026. if (mbslength == -1)
  1027. {
  1028. mbslength = strlen(mbs);
  1029. null = 1;
  1030. }
  1031. if (!wcs)
  1032. {
  1033. switch (gpGlobals->iCodePage)
  1034. {
  1035. case CP_SHIFTJIS:
  1036. for (i = 0; i < mbslength && mbs[i]; i++)
  1037. {
  1038. if (state == 0)
  1039. {
  1040. if (mbs[i] <= 0x80 || mbs[i] >= 0xfd || (mbs[i] >= 0xa0 && mbs[i] <= 0xdf))
  1041. wlen++;
  1042. else
  1043. state = 1;
  1044. }
  1045. else
  1046. {
  1047. wlen++;
  1048. state = 0;
  1049. }
  1050. }
  1051. return wlen + null + state;
  1052. case CP_GBK:
  1053. case CP_BIG5:
  1054. for (i = 0; i < mbslength && mbs[i]; i++)
  1055. {
  1056. if (state == 0)
  1057. {
  1058. if (mbs[i] <= 0x80 || mbs[i] == 0xff)
  1059. wlen++;
  1060. else
  1061. state = 1;
  1062. }
  1063. else
  1064. {
  1065. wlen++;
  1066. state = 0;
  1067. }
  1068. }
  1069. return wlen + null + state;
  1070. default:
  1071. return -1;
  1072. }
  1073. }
  1074. else
  1075. {
  1076. unsigned short invalid_char;
  1077. switch (gpGlobals->iCodePage)
  1078. {
  1079. case CP_SHIFTJIS:
  1080. invalid_char = 0x30fb;
  1081. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1082. {
  1083. if (state == 0)
  1084. {
  1085. if (mbs[i] <= 0x80)
  1086. wcs[wlen++] = mbs[i];
  1087. else if (mbs[i] >= 0xa0 && mbs[i] <= 0xdf)
  1088. wcs[wlen++] = cptbl_jis_half[mbs[i] - 0xa0];
  1089. else if (mbs[i] == 0xfd)
  1090. wcs[wlen++] = 0xf8f1;
  1091. else if (mbs[i] == 0xfe)
  1092. wcs[wlen++] = 0xf8f2;
  1093. else if (mbs[i] == 0xff)
  1094. wcs[wlen++] = 0xf8f3;
  1095. else
  1096. state = 1;
  1097. }
  1098. else
  1099. {
  1100. if (mbs[i] < 0x40)
  1101. wcs[wlen++] = 0x30fb;
  1102. else if (mbs[i - 1] < 0xa0)
  1103. wcs[wlen++] = cptbl_jis[mbs[i - 1] - 0x81][mbs[i] - 0x40];
  1104. else
  1105. wcs[wlen++] = cptbl_jis[mbs[i - 1] - 0xc1][mbs[i] - 0x40];
  1106. state = 0;
  1107. }
  1108. }
  1109. break;
  1110. case CP_GBK:
  1111. invalid_char = 0x3f;
  1112. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1113. {
  1114. if (state == 0)
  1115. {
  1116. if (mbs[i] < 0x80)
  1117. wcs[wlen++] = mbs[i];
  1118. else if (mbs[i] == 0x80)
  1119. wcs[wlen++] = 0x20ac;
  1120. else if (mbs[i] == 0xff)
  1121. wcs[wlen++] = 0xf8f5;
  1122. else
  1123. state = 1;
  1124. }
  1125. else
  1126. {
  1127. if (mbs[i] < 0x40)
  1128. wcs[wlen++] = invalid_char;
  1129. else
  1130. wcs[wlen++] = cptbl_gbk[mbs[i - 1] - 0x81][mbs[i] - 0x40];
  1131. state = 0;
  1132. }
  1133. }
  1134. break;
  1135. case CP_BIG5:
  1136. invalid_char = 0x3f;
  1137. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1138. {
  1139. if (state == 0)
  1140. {
  1141. if (mbs[i] <= 0x80)
  1142. wcs[wlen++] = mbs[i];
  1143. else if (mbs[i] == 0xff)
  1144. wcs[wlen++] = 0xf8f8;
  1145. else
  1146. state = 1;
  1147. }
  1148. else
  1149. {
  1150. if (mbs[i] < 0x40 || (mbs[i] >= 0x7f && mbs[i] <= 0xa0))
  1151. wcs[wlen++] = invalid_char;
  1152. else if (mbs[i] <= 0x7e)
  1153. wcs[wlen++] = cptbl_big5[mbs[i - 1] - 0x81][mbs[i] - 0x40];
  1154. else
  1155. wcs[wlen++] = cptbl_big5[mbs[i - 1] - 0x81][mbs[i] - 0x60];
  1156. state = 0;
  1157. }
  1158. }
  1159. break;
  1160. default:
  1161. return -1;
  1162. }
  1163. if (state == 1 && wlen < wcslength)
  1164. {
  1165. wcs[wlen++] = invalid_char;
  1166. }
  1167. if (null)
  1168. {
  1169. if (wlen < wcslength)
  1170. wcs[wlen++] = 0;
  1171. else
  1172. wcs[wlen - 1] = 0;
  1173. }
  1174. return wlen;
  1175. }
  1176. }
  1177. #endif