text.c 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  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. #include "main.h"
  25. #define WORD_LENGTH 10
  26. #define FONT_COLOR_DEFAULT 0x4F
  27. #define FONT_COLOR_YELLOW 0x2D
  28. #define FONT_COLOR_RED 0x1A
  29. #define FONT_COLOR_CYAN 0x8D
  30. #define FONT_COLOR_CYAN_ALT 0x8C
  31. BOOL g_fUpdatedInBattle = FALSE;
  32. static const char g_rgszAdditionalWords[][WORD_LENGTH + 1] = {
  33. {0xBE, 0xD4, 0xB0, 0xAB, 0xB3, 0x74, 0xAB, 0xD7, 0x00, 0x00, 0x00}, // Battle Speed
  34. {0xA4, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 1
  35. {0xA4, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 2
  36. {0xA4, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 3
  37. {0xA5, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 4
  38. {0xA4, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 5
  39. };
  40. typedef struct tagTEXTLIB
  41. {
  42. LPBYTE lpWordBuf;
  43. LPBYTE lpMsgBuf;
  44. LPDWORD lpMsgOffset;
  45. int nWords;
  46. int nMsgs;
  47. int nCurrentDialogLine;
  48. BYTE bCurrentFontColor;
  49. PAL_POS posIcon;
  50. PAL_POS posDialogTitle;
  51. PAL_POS posDialogText;
  52. BYTE bDialogPosition;
  53. BYTE bIcon;
  54. int iDelayTime;
  55. BOOL fUserSkip;
  56. BOOL fPlayingRNG;
  57. BYTE bufDialogIcons[282];
  58. } TEXTLIB, *LPTEXTLIB;
  59. static TEXTLIB g_TextLib;
  60. INT
  61. PAL_InitText(
  62. VOID
  63. )
  64. /*++
  65. Purpose:
  66. Initialize the in-game texts.
  67. Parameters:
  68. None.
  69. Return value:
  70. 0 = success.
  71. -1 = memory allocation error.
  72. --*/
  73. {
  74. FILE *fpMsg, *fpWord;
  75. int i;
  76. //
  77. // Open the message and word data files.
  78. //
  79. fpMsg = UTIL_OpenRequiredFile("m.msg");
  80. fpWord = UTIL_OpenRequiredFile("word.dat");
  81. //
  82. // See how many words we have
  83. //
  84. fseek(fpWord, 0, SEEK_END);
  85. i = ftell(fpWord);
  86. //
  87. // Each word has 10 bytes
  88. //
  89. g_TextLib.nWords = (i + (WORD_LENGTH - 1)) / WORD_LENGTH;
  90. //
  91. // Read the words
  92. //
  93. g_TextLib.lpWordBuf = (LPBYTE)malloc(i);
  94. if (g_TextLib.lpWordBuf == NULL)
  95. {
  96. fclose(fpWord);
  97. fclose(fpMsg);
  98. return -1;
  99. }
  100. fseek(fpWord, 0, SEEK_SET);
  101. fread(g_TextLib.lpWordBuf, i, 1, fpWord);
  102. //
  103. // Close the words file
  104. //
  105. fclose(fpWord);
  106. //
  107. // Read the message offsets. The message offsets are in SSS.MKF #3
  108. //
  109. i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD);
  110. g_TextLib.nMsgs = i - 1;
  111. g_TextLib.lpMsgOffset = (LPDWORD)malloc(i * sizeof(DWORD));
  112. if (g_TextLib.lpMsgOffset == NULL)
  113. {
  114. free(g_TextLib.lpWordBuf);
  115. fclose(fpMsg);
  116. return -1;
  117. }
  118. PAL_MKFReadChunk((LPBYTE)(g_TextLib.lpMsgOffset), i * sizeof(DWORD), 3,
  119. gpGlobals->f.fpSSS);
  120. //
  121. // Read the messages.
  122. //
  123. fseek(fpMsg, 0, SEEK_END);
  124. i = ftell(fpMsg);
  125. g_TextLib.lpMsgBuf = (LPBYTE)malloc(i);
  126. if (g_TextLib.lpMsgBuf == NULL)
  127. {
  128. free(g_TextLib.lpMsgOffset);
  129. free(g_TextLib.lpWordBuf);
  130. fclose(fpMsg);
  131. return -1;
  132. }
  133. fseek(fpMsg, 0, SEEK_SET);
  134. fread(g_TextLib.lpMsgBuf, 1, i, fpMsg);
  135. fclose(fpMsg);
  136. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  137. g_TextLib.bIcon = 0;
  138. g_TextLib.posIcon = 0;
  139. g_TextLib.nCurrentDialogLine = 0;
  140. g_TextLib.iDelayTime = 3;
  141. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  142. g_TextLib.posDialogText = PAL_XY(44, 26);
  143. g_TextLib.bDialogPosition = kDialogUpper;
  144. g_TextLib.fUserSkip = FALSE;
  145. PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA);
  146. return 0;
  147. }
  148. VOID
  149. PAL_FreeText(
  150. VOID
  151. )
  152. /*++
  153. Purpose:
  154. Free the memory used by the texts.
  155. Parameters:
  156. None.
  157. Return value:
  158. None.
  159. --*/
  160. {
  161. if (g_TextLib.lpMsgBuf != NULL)
  162. {
  163. free(g_TextLib.lpMsgBuf);
  164. g_TextLib.lpMsgBuf = NULL;
  165. }
  166. if (g_TextLib.lpMsgOffset != NULL)
  167. {
  168. free(g_TextLib.lpMsgOffset);
  169. g_TextLib.lpMsgOffset = NULL;
  170. }
  171. if (g_TextLib.lpWordBuf != NULL)
  172. {
  173. free(g_TextLib.lpWordBuf);
  174. g_TextLib.lpWordBuf = NULL;
  175. }
  176. }
  177. LPCSTR
  178. PAL_GetWord(
  179. WORD wNumWord
  180. )
  181. /*++
  182. Purpose:
  183. Get the specified word.
  184. Parameters:
  185. [IN] wNumWord - the number of the requested word.
  186. Return value:
  187. Pointer to the requested word. NULL if not found.
  188. --*/
  189. {
  190. static char buf[WORD_LENGTH + 1];
  191. if (wNumWord >= PAL_ADDITIONAL_WORD_FIRST)
  192. {
  193. return g_rgszAdditionalWords[wNumWord - PAL_ADDITIONAL_WORD_FIRST];
  194. }
  195. if (wNumWord >= g_TextLib.nWords)
  196. {
  197. return NULL;
  198. }
  199. memcpy(buf, &g_TextLib.lpWordBuf[wNumWord * WORD_LENGTH], WORD_LENGTH);
  200. buf[WORD_LENGTH] = '\0';
  201. //
  202. // Remove the trailing spaces
  203. //
  204. trim(buf);
  205. if ((strlen(buf) & 1) != 0 && buf[strlen(buf) - 1] == '1')
  206. {
  207. buf[strlen(buf) - 1] = '\0';
  208. }
  209. return buf;
  210. }
  211. LPCSTR
  212. PAL_GetMsg(
  213. WORD wNumMsg
  214. )
  215. /*++
  216. Purpose:
  217. Get the specified message.
  218. Parameters:
  219. [IN] wNumMsg - the number of the requested message.
  220. Return value:
  221. Pointer to the requested message. NULL if not found.
  222. --*/
  223. {
  224. static char buf[256];
  225. DWORD dwOffset, dwSize;
  226. if (wNumMsg >= g_TextLib.nMsgs)
  227. {
  228. return NULL;
  229. }
  230. dwOffset = SWAP32(g_TextLib.lpMsgOffset[wNumMsg]);
  231. dwSize = SWAP32(g_TextLib.lpMsgOffset[wNumMsg + 1]) - dwOffset;
  232. assert(dwSize < 255);
  233. memcpy(buf, &g_TextLib.lpMsgBuf[dwOffset], dwSize);
  234. buf[dwSize] = '\0';
  235. return buf;
  236. }
  237. VOID
  238. PAL_DrawText(
  239. LPCSTR lpszText,
  240. PAL_POS pos,
  241. BYTE bColor,
  242. BOOL fShadow,
  243. BOOL fUpdate
  244. )
  245. /*++
  246. Purpose:
  247. Draw text on the screen.
  248. Parameters:
  249. [IN] lpszText - the text to be drawn.
  250. [IN] pos - Position of the text.
  251. [IN] bColor - Color of the text.
  252. [IN] fShadow - TRUE if the text is shadowed or not.
  253. [IN] fUpdate - TRUE if update the screen area.
  254. Return value:
  255. None.
  256. --*/
  257. {
  258. SDL_Rect rect, urect;
  259. WORD wChar;
  260. rect.x = PAL_X(pos);
  261. rect.y = PAL_Y(pos);
  262. urect.x = rect.x;
  263. urect.y = rect.y;
  264. #ifdef PAL_WIN95
  265. urect.h = 17;
  266. #else
  267. urect.h = 16;
  268. #endif
  269. urect.w = 0;
  270. while (*lpszText)
  271. {
  272. //
  273. // Draw the character
  274. //
  275. if (*lpszText & 0x80)
  276. {
  277. //
  278. // Chinese Character
  279. //
  280. wChar = SWAP16(((LPBYTE)lpszText)[0] | (((LPBYTE)lpszText)[1] << 8));
  281. if (fShadow)
  282. {
  283. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  284. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  285. }
  286. PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  287. lpszText += 2;
  288. rect.x += 16;
  289. urect.w += 16;
  290. }
  291. else
  292. {
  293. //
  294. // ASCII character
  295. //
  296. if (fShadow)
  297. {
  298. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  299. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  300. }
  301. PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  302. lpszText++;
  303. rect.x += 8;
  304. urect.w += 8;
  305. }
  306. }
  307. //
  308. // Update the screen area
  309. //
  310. if (fUpdate && urect.w > 0)
  311. {
  312. #ifdef PAL_WIN95
  313. urect.w++;
  314. if (urect.x + urect.w > 320)
  315. {
  316. urect.w = 320 - urect.x;
  317. }
  318. #endif
  319. VIDEO_UpdateScreen(&urect);
  320. }
  321. }
  322. VOID
  323. PAL_DialogSetDelayTime(
  324. INT iDelayTime
  325. )
  326. /*++
  327. Purpose:
  328. Set the delay time for dialog.
  329. Parameters:
  330. [IN] iDelayTime - the delay time to be set.
  331. Return value:
  332. None.
  333. --*/
  334. {
  335. g_TextLib.iDelayTime = iDelayTime;
  336. }
  337. VOID
  338. PAL_StartDialog(
  339. BYTE bDialogLocation,
  340. BYTE bFontColor,
  341. INT iNumCharFace,
  342. BOOL fPlayingRNG
  343. )
  344. /*++
  345. Purpose:
  346. Start a new dialog.
  347. Parameters:
  348. [IN] bDialogLocation - the location of the text on the screen.
  349. [IN] bFontColor - the font color of the text.
  350. [IN] iNumCharFace - number of the character face in RGM.MKF.
  351. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  352. Return value:
  353. None.
  354. --*/
  355. {
  356. PAL_LARGE BYTE buf[16384];
  357. SDL_Rect rect;
  358. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  359. {
  360. //
  361. // Update the screen in battle, or the graphics may seem messed up
  362. //
  363. VIDEO_UpdateScreen(NULL);
  364. g_fUpdatedInBattle = TRUE;
  365. }
  366. g_TextLib.bIcon = 0;
  367. g_TextLib.posIcon = 0;
  368. g_TextLib.nCurrentDialogLine = 0;
  369. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  370. g_TextLib.fUserSkip = FALSE;
  371. if (bFontColor != 0)
  372. {
  373. g_TextLib.bCurrentFontColor = bFontColor;
  374. }
  375. if (fPlayingRNG && iNumCharFace)
  376. {
  377. VIDEO_BackupScreen();
  378. g_TextLib.fPlayingRNG = TRUE;
  379. }
  380. switch (bDialogLocation)
  381. {
  382. case kDialogUpper:
  383. if (iNumCharFace > 0)
  384. {
  385. //
  386. // Display the character face at the upper part of the screen
  387. //
  388. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  389. {
  390. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  391. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  392. rect.x = 48 - rect.w / 2;
  393. rect.y = 55 - rect.h / 2;
  394. if (rect.x < 0)
  395. {
  396. rect.x = 0;
  397. }
  398. if (rect.y < 0)
  399. {
  400. rect.y = 0;
  401. }
  402. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  403. if (rect.x < 0)
  404. {
  405. rect.x = 0;
  406. }
  407. if (rect.y < 0)
  408. {
  409. rect.y = 0;
  410. }
  411. VIDEO_UpdateScreen(&rect);
  412. }
  413. }
  414. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  415. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  416. break;
  417. case kDialogCenter:
  418. g_TextLib.posDialogText = PAL_XY(80, 40);
  419. break;
  420. case kDialogLower:
  421. if (iNumCharFace > 0)
  422. {
  423. //
  424. // Display the character face at the lower part of the screen
  425. //
  426. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  427. {
  428. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  429. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  430. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  431. VIDEO_UpdateScreen(NULL);
  432. }
  433. }
  434. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  435. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  436. break;
  437. case kDialogCenterWindow:
  438. g_TextLib.posDialogText = PAL_XY(160, 40);
  439. break;
  440. }
  441. g_TextLib.bDialogPosition = bDialogLocation;
  442. }
  443. static VOID
  444. PAL_DialogWaitForKey(
  445. VOID
  446. )
  447. /*++
  448. Purpose:
  449. Wait for player to press a key after showing a dialog.
  450. Parameters:
  451. None.
  452. Return value:
  453. None.
  454. --*/
  455. {
  456. PAL_LARGE SDL_Color palette[256];
  457. SDL_Color *pCurrentPalette, t;
  458. int i;
  459. //
  460. // get the current palette
  461. //
  462. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  463. memcpy(palette, pCurrentPalette, sizeof(palette));
  464. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  465. g_TextLib.bDialogPosition != kDialogCenter)
  466. {
  467. //
  468. // show the icon
  469. //
  470. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  471. if (p != NULL)
  472. {
  473. SDL_Rect rect;
  474. rect.x = PAL_X(g_TextLib.posIcon);
  475. rect.y = PAL_Y(g_TextLib.posIcon);
  476. rect.w = 16;
  477. rect.h = 16;
  478. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  479. VIDEO_UpdateScreen(&rect);
  480. }
  481. }
  482. PAL_ClearKeyState();
  483. while (TRUE)
  484. {
  485. UTIL_Delay(100);
  486. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  487. g_TextLib.bDialogPosition != kDialogCenter)
  488. {
  489. //
  490. // palette shift
  491. //
  492. t = palette[0xF9];
  493. for (i = 0xF9; i < 0xFE; i++)
  494. {
  495. palette[i] = palette[i + 1];
  496. }
  497. palette[0xFE] = t;
  498. VIDEO_SetPalette(palette);
  499. }
  500. if (g_InputState.dwKeyPress != 0)
  501. {
  502. break;
  503. }
  504. }
  505. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  506. g_TextLib.bDialogPosition != kDialogCenter)
  507. {
  508. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  509. }
  510. PAL_ClearKeyState();
  511. g_TextLib.fUserSkip = FALSE;
  512. }
  513. VOID
  514. PAL_ShowDialogText(
  515. LPCSTR lpszText
  516. )
  517. /*++
  518. Purpose:
  519. Show one line of the dialog text.
  520. Parameters:
  521. [IN] lpszText - the text to be shown.
  522. Return value:
  523. None.
  524. --*/
  525. {
  526. SDL_Rect rect;
  527. int x, y, len = strlen(lpszText);
  528. PAL_ClearKeyState();
  529. g_TextLib.bIcon = 0;
  530. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  531. {
  532. //
  533. // Update the screen in battle, or the graphics may seem messed up
  534. //
  535. VIDEO_UpdateScreen(NULL);
  536. g_fUpdatedInBattle = TRUE;
  537. }
  538. if (g_TextLib.nCurrentDialogLine > 3)
  539. {
  540. //
  541. // The rest dialogs should be shown in the next page.
  542. //
  543. PAL_DialogWaitForKey();
  544. g_TextLib.nCurrentDialogLine = 0;
  545. VIDEO_RestoreScreen();
  546. VIDEO_UpdateScreen(NULL);
  547. }
  548. x = PAL_X(g_TextLib.posDialogText);
  549. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  550. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  551. {
  552. //
  553. // The text should be shown in a small window at the center of the screen
  554. //
  555. #ifndef PAL_CLASSIC
  556. if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  557. {
  558. PAL_BattleUIShowText(lpszText, 1400);
  559. }
  560. else
  561. #endif
  562. {
  563. PAL_POS pos;
  564. LPBOX lpBox;
  565. //
  566. // Create the window box
  567. //
  568. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  569. lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE);
  570. rect.x = PAL_X(pos);
  571. rect.y = PAL_Y(pos);
  572. rect.w = 320 - rect.x * 2 + 32;
  573. rect.h = 64;
  574. //
  575. // Show the text on the screen
  576. //
  577. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  578. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE);
  579. VIDEO_UpdateScreen(&rect);
  580. PAL_DialogWaitForKey();
  581. //
  582. // Delete the box
  583. //
  584. PAL_DeleteBox(lpBox);
  585. VIDEO_UpdateScreen(&rect);
  586. PAL_EndDialog();
  587. }
  588. }
  589. else
  590. {
  591. if (g_TextLib.nCurrentDialogLine == 0 &&
  592. g_TextLib.bDialogPosition != kDialogCenter &&
  593. (((BYTE)lpszText[len - 1] == 0x47 && (BYTE)lpszText[len - 2] == 0xA1) ||
  594. ((BYTE)lpszText[len - 1] == 0xBA && (BYTE)lpszText[len - 2] == 0xA3) ||
  595. ((BYTE)lpszText[len - 1] == 0xC3 && (BYTE)lpszText[len - 2] == 0xA1) ||
  596. ((BYTE)lpszText[len - 1] == ':')))
  597. {
  598. //
  599. // name of character
  600. //
  601. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE);
  602. }
  603. else
  604. {
  605. //
  606. // normal texts
  607. //
  608. char text[3];
  609. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  610. {
  611. //
  612. // Save the screen before we show the first line of dialog
  613. //
  614. VIDEO_BackupScreen();
  615. }
  616. while (lpszText != NULL && *lpszText != '\0')
  617. {
  618. switch (*lpszText)
  619. {
  620. case '-':
  621. //
  622. // Set the font color to Cyan
  623. //
  624. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  625. {
  626. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  627. }
  628. else
  629. {
  630. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  631. }
  632. lpszText++;
  633. break;
  634. #ifndef PAL_WIN95
  635. case '\'':
  636. //
  637. // Set the font color to Red
  638. //
  639. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  640. {
  641. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  642. }
  643. else
  644. {
  645. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  646. }
  647. lpszText++;
  648. break;
  649. #endif
  650. case '\"':
  651. //
  652. // Set the font color to Yellow
  653. //
  654. if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW)
  655. {
  656. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  657. }
  658. else
  659. {
  660. g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW;
  661. }
  662. lpszText++;
  663. break;
  664. case '$':
  665. //
  666. // Set the delay time of text-displaying
  667. //
  668. g_TextLib.iDelayTime = atoi(lpszText + 1) * 10 / 7;
  669. lpszText += 3;
  670. break;
  671. case '~':
  672. //
  673. // Delay for a period and quit
  674. //
  675. UTIL_Delay(atoi(lpszText + 1) * 80 / 7);
  676. g_TextLib.nCurrentDialogLine = 0;
  677. g_TextLib.fUserSkip = FALSE;
  678. return; // don't go further
  679. case ')':
  680. //
  681. // Set the waiting icon
  682. //
  683. g_TextLib.bIcon = 1;
  684. lpszText++;
  685. break;
  686. case '(':
  687. //
  688. // Set the waiting icon
  689. //
  690. g_TextLib.bIcon = 2;
  691. lpszText++;
  692. break;
  693. case '\\':
  694. lpszText++;
  695. default:
  696. if (*lpszText & 0x80)
  697. {
  698. text[0] = lpszText[0];
  699. text[1] = lpszText[1];
  700. text[2] = '\0';
  701. lpszText += 2;
  702. }
  703. else
  704. {
  705. text[0] = *lpszText;
  706. text[1] = '\0';
  707. lpszText++;
  708. }
  709. PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE);
  710. x += ((text[0] & 0x80) ? 16 : 8);
  711. if (!g_TextLib.fUserSkip)
  712. {
  713. PAL_ClearKeyState();
  714. UTIL_Delay(g_TextLib.iDelayTime * 8);
  715. if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu))
  716. {
  717. //
  718. // User pressed a key to skip the dialog
  719. //
  720. g_TextLib.fUserSkip = TRUE;
  721. }
  722. }
  723. }
  724. }
  725. g_TextLib.posIcon = PAL_XY(x, y);
  726. g_TextLib.nCurrentDialogLine++;
  727. }
  728. }
  729. }
  730. VOID
  731. PAL_ClearDialog(
  732. BOOL fWaitForKey
  733. )
  734. /*++
  735. Purpose:
  736. Clear the state of the dialog.
  737. Parameters:
  738. [IN] fWaitForKey - whether wait for any key or not.
  739. Return value:
  740. None.
  741. --*/
  742. {
  743. if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey)
  744. {
  745. PAL_DialogWaitForKey();
  746. }
  747. g_TextLib.nCurrentDialogLine = 0;
  748. if (g_TextLib.bDialogPosition == kDialogCenter)
  749. {
  750. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  751. g_TextLib.posDialogText = PAL_XY(44, 26);
  752. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  753. g_TextLib.bDialogPosition = kDialogUpper;
  754. }
  755. }
  756. VOID
  757. PAL_EndDialog(
  758. VOID
  759. )
  760. /*++
  761. Purpose:
  762. Ends a dialog.
  763. Parameters:
  764. None.
  765. Return value:
  766. None.
  767. --*/
  768. {
  769. PAL_ClearDialog(TRUE);
  770. //
  771. // Set some default parameters, as there are some parts of script
  772. // which doesn't have a "start dialog" instruction before showing the dialog.
  773. //
  774. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  775. g_TextLib.posDialogText = PAL_XY(44, 26);
  776. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  777. g_TextLib.bDialogPosition = kDialogUpper;
  778. g_TextLib.fUserSkip = FALSE;
  779. g_TextLib.fPlayingRNG = FALSE;
  780. }
  781. BOOL
  782. PAL_IsInDialog(
  783. VOID
  784. )
  785. /*++
  786. Purpose:
  787. Check if there are dialog texts on the screen.
  788. Parameters:
  789. None.
  790. Return value:
  791. TRUE if there are dialog texts on the screen, FALSE if not.
  792. --*/
  793. {
  794. return (g_TextLib.nCurrentDialogLine != 0);
  795. }
  796. BOOL
  797. PAL_DialogIsPlayingRNG(
  798. VOID
  799. )
  800. /*++
  801. Purpose:
  802. Check if the script used the RNG playing parameter when displaying texts.
  803. Parameters:
  804. None.
  805. Return value:
  806. TRUE if the script used the RNG playing parameter, FALSE if not.
  807. --*/
  808. {
  809. return g_TextLib.fPlayingRNG;
  810. }