text.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  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_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. if (gpGlobals->fIsWIN95)
  466. {
  467. urect.w++;
  468. if (urect.x + urect.w > 320)
  469. {
  470. urect.w = 320 - urect.x;
  471. }
  472. }
  473. VIDEO_UpdateScreen(&urect);
  474. }
  475. }
  476. VOID
  477. PAL_DialogSetDelayTime(
  478. INT iDelayTime
  479. )
  480. /*++
  481. Purpose:
  482. Set the delay time for dialog.
  483. Parameters:
  484. [IN] iDelayTime - the delay time to be set.
  485. Return value:
  486. None.
  487. --*/
  488. {
  489. g_TextLib.iDelayTime = iDelayTime;
  490. }
  491. VOID
  492. PAL_StartDialog(
  493. BYTE bDialogLocation,
  494. BYTE bFontColor,
  495. INT iNumCharFace,
  496. BOOL fPlayingRNG
  497. )
  498. /*++
  499. Purpose:
  500. Start a new dialog.
  501. Parameters:
  502. [IN] bDialogLocation - the location of the text on the screen.
  503. [IN] bFontColor - the font color of the text.
  504. [IN] iNumCharFace - number of the character face in RGM.MKF.
  505. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  506. Return value:
  507. None.
  508. --*/
  509. {
  510. PAL_LARGE BYTE buf[16384];
  511. SDL_Rect rect;
  512. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  513. {
  514. //
  515. // Update the screen in battle, or the graphics may seem messed up
  516. //
  517. VIDEO_UpdateScreen(NULL);
  518. g_fUpdatedInBattle = TRUE;
  519. }
  520. g_TextLib.bIcon = 0;
  521. g_TextLib.posIcon = 0;
  522. g_TextLib.nCurrentDialogLine = 0;
  523. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  524. g_TextLib.fUserSkip = FALSE;
  525. if (bFontColor != 0)
  526. {
  527. g_TextLib.bCurrentFontColor = bFontColor;
  528. }
  529. if (fPlayingRNG && iNumCharFace)
  530. {
  531. VIDEO_BackupScreen();
  532. g_TextLib.fPlayingRNG = TRUE;
  533. }
  534. switch (bDialogLocation)
  535. {
  536. case kDialogUpper:
  537. if (iNumCharFace > 0)
  538. {
  539. //
  540. // Display the character face at the upper part of the screen
  541. //
  542. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  543. {
  544. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  545. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  546. rect.x = 48 - rect.w / 2;
  547. rect.y = 55 - rect.h / 2;
  548. if (rect.x < 0)
  549. {
  550. rect.x = 0;
  551. }
  552. if (rect.y < 0)
  553. {
  554. rect.y = 0;
  555. }
  556. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  557. if (rect.x < 0)
  558. {
  559. rect.x = 0;
  560. }
  561. if (rect.y < 0)
  562. {
  563. rect.y = 0;
  564. }
  565. VIDEO_UpdateScreen(&rect);
  566. }
  567. }
  568. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  569. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  570. break;
  571. case kDialogCenter:
  572. g_TextLib.posDialogText = PAL_XY(80, 40);
  573. break;
  574. case kDialogLower:
  575. if (iNumCharFace > 0)
  576. {
  577. //
  578. // Display the character face at the lower part of the screen
  579. //
  580. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  581. {
  582. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  583. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  584. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  585. VIDEO_UpdateScreen(NULL);
  586. }
  587. }
  588. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  589. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  590. break;
  591. case kDialogCenterWindow:
  592. g_TextLib.posDialogText = PAL_XY(160, 40);
  593. break;
  594. }
  595. g_TextLib.bDialogPosition = bDialogLocation;
  596. }
  597. static VOID
  598. PAL_DialogWaitForKey(
  599. VOID
  600. )
  601. /*++
  602. Purpose:
  603. Wait for player to press a key after showing a dialog.
  604. Parameters:
  605. None.
  606. Return value:
  607. None.
  608. --*/
  609. {
  610. PAL_LARGE SDL_Color palette[256];
  611. SDL_Color *pCurrentPalette, t;
  612. int i;
  613. //
  614. // get the current palette
  615. //
  616. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  617. memcpy(palette, pCurrentPalette, sizeof(palette));
  618. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  619. g_TextLib.bDialogPosition != kDialogCenter)
  620. {
  621. //
  622. // show the icon
  623. //
  624. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  625. if (p != NULL)
  626. {
  627. SDL_Rect rect;
  628. rect.x = PAL_X(g_TextLib.posIcon);
  629. rect.y = PAL_Y(g_TextLib.posIcon);
  630. rect.w = 16;
  631. rect.h = 16;
  632. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  633. VIDEO_UpdateScreen(&rect);
  634. }
  635. }
  636. PAL_ClearKeyState();
  637. while (TRUE)
  638. {
  639. UTIL_Delay(100);
  640. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  641. g_TextLib.bDialogPosition != kDialogCenter)
  642. {
  643. //
  644. // palette shift
  645. //
  646. t = palette[0xF9];
  647. for (i = 0xF9; i < 0xFE; i++)
  648. {
  649. palette[i] = palette[i + 1];
  650. }
  651. palette[0xFE] = t;
  652. VIDEO_SetPalette(palette);
  653. }
  654. if (g_InputState.dwKeyPress != 0)
  655. {
  656. break;
  657. }
  658. }
  659. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  660. g_TextLib.bDialogPosition != kDialogCenter)
  661. {
  662. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  663. }
  664. PAL_ClearKeyState();
  665. g_TextLib.fUserSkip = FALSE;
  666. }
  667. VOID
  668. PAL_ShowDialogText(
  669. #ifdef PAL_UNICODE
  670. LPCWSTR lpszText
  671. #else
  672. LPCSTR lpszText
  673. #endif
  674. )
  675. /*++
  676. Purpose:
  677. Show one line of the dialog text.
  678. Parameters:
  679. [IN] lpszText - the text to be shown.
  680. Return value:
  681. None.
  682. --*/
  683. {
  684. SDL_Rect rect;
  685. #ifdef PAL_UNICODE
  686. int x, y;
  687. #else
  688. int x, y, len = strlen(lpszText);
  689. #endif
  690. PAL_ClearKeyState();
  691. g_TextLib.bIcon = 0;
  692. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  693. {
  694. //
  695. // Update the screen in battle, or the graphics may seem messed up
  696. //
  697. VIDEO_UpdateScreen(NULL);
  698. g_fUpdatedInBattle = TRUE;
  699. }
  700. if (g_TextLib.nCurrentDialogLine > 3)
  701. {
  702. //
  703. // The rest dialogs should be shown in the next page.
  704. //
  705. PAL_DialogWaitForKey();
  706. g_TextLib.nCurrentDialogLine = 0;
  707. VIDEO_RestoreScreen();
  708. VIDEO_UpdateScreen(NULL);
  709. }
  710. x = PAL_X(g_TextLib.posDialogText);
  711. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  712. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  713. {
  714. //
  715. // The text should be shown in a small window at the center of the screen
  716. //
  717. #ifndef PAL_CLASSIC
  718. if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  719. {
  720. PAL_BattleUIShowText(lpszText, 1400);
  721. }
  722. else
  723. #endif
  724. {
  725. PAL_POS pos;
  726. LPBOX lpBox;
  727. # ifdef PAL_UNICODE
  728. int i, w = wcslen(lpszText), len = 0;
  729. for (i = 0; i < w; i++)
  730. len += PAL_CharWidth(lpszText[i]) >> 3;
  731. # endif
  732. //
  733. // Create the window box
  734. //
  735. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  736. lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE);
  737. rect.x = PAL_X(pos);
  738. rect.y = PAL_Y(pos);
  739. rect.w = 320 - rect.x * 2 + 32;
  740. rect.h = 64;
  741. //
  742. // Show the text on the screen
  743. //
  744. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  745. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE);
  746. VIDEO_UpdateScreen(&rect);
  747. PAL_DialogWaitForKey();
  748. //
  749. // Delete the box
  750. //
  751. PAL_DeleteBox(lpBox);
  752. VIDEO_UpdateScreen(&rect);
  753. PAL_EndDialog();
  754. }
  755. }
  756. else
  757. {
  758. # ifdef PAL_UNICODE
  759. int len = wcslen(lpszText);
  760. # endif
  761. if (g_TextLib.nCurrentDialogLine == 0 &&
  762. g_TextLib.bDialogPosition != kDialogCenter &&
  763. # ifdef PAL_UNICODE
  764. (lpszText[len - 1] == 0xff1a ||
  765. # else
  766. (((BYTE)lpszText[len - 1] == 0x47 && (BYTE)lpszText[len - 2] == 0xA1) ||
  767. ((BYTE)lpszText[len - 1] == 0xBA && (BYTE)lpszText[len - 2] == 0xA3) ||
  768. ((BYTE)lpszText[len - 1] == 0xC3 && (BYTE)lpszText[len - 2] == 0xA1) ||
  769. # endif
  770. lpszText[len - 1] == ':'))
  771. {
  772. //
  773. // name of character
  774. //
  775. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE);
  776. }
  777. else
  778. {
  779. //
  780. // normal texts
  781. //
  782. # ifdef PAL_UNICODE
  783. WCHAR text[2];
  784. # else
  785. char text[3];
  786. # endif
  787. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  788. {
  789. //
  790. // Save the screen before we show the first line of dialog
  791. //
  792. VIDEO_BackupScreen();
  793. }
  794. while (lpszText != NULL && *lpszText != '\0')
  795. {
  796. switch (*lpszText)
  797. {
  798. case '-':
  799. //
  800. // Set the font color to Cyan
  801. //
  802. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  803. {
  804. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  805. }
  806. else
  807. {
  808. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  809. }
  810. lpszText++;
  811. break;
  812. case '\'':
  813. // !PAL_WIN95
  814. //
  815. // Set the font color to Red
  816. //
  817. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  818. {
  819. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  820. }
  821. else
  822. {
  823. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  824. }
  825. lpszText++;
  826. break;
  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. LPCSTR mbs,
  1009. int mbslength,
  1010. LPWSTR wcs,
  1011. int wcslength
  1012. )
  1013. /*++
  1014. Purpose:
  1015. Convert multi-byte string into the corresponding unicode string.
  1016. Parameters:
  1017. [IN] mbs - Pointer to the multi-byte string.
  1018. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1019. [IN] wcs - Pointer to the wide string buffer.
  1020. [IN] wcslength - Length of the wide string buffer.
  1021. Return value:
  1022. The length of converted wide string. If mbslength is set to -1, the returned
  1023. value includes the terminal null-char; otherwise, the null-char is not included.
  1024. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1025. required length of the wide string buffer.
  1026. --*/
  1027. {
  1028. int i = 0, j = 0, state = 0, wlen = 0, null = 0;
  1029. if (mbslength == -1)
  1030. {
  1031. mbslength = strlen(mbs);
  1032. null = 1;
  1033. }
  1034. if (!wcs)
  1035. {
  1036. switch (gpGlobals->iCodePage)
  1037. {
  1038. case CP_SHIFTJIS:
  1039. for (i = 0; i < mbslength && mbs[i]; i++)
  1040. {
  1041. if (state == 0)
  1042. {
  1043. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] >= 0xfd || ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf))
  1044. wlen++;
  1045. else
  1046. state = 1;
  1047. }
  1048. else
  1049. {
  1050. wlen++;
  1051. state = 0;
  1052. }
  1053. }
  1054. return wlen + null + state;
  1055. case CP_GBK:
  1056. case CP_BIG5:
  1057. for (i = 0; i < mbslength && mbs[i]; i++)
  1058. {
  1059. if (state == 0)
  1060. {
  1061. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] == 0xff)
  1062. wlen++;
  1063. else
  1064. state = 1;
  1065. }
  1066. else
  1067. {
  1068. wlen++;
  1069. state = 0;
  1070. }
  1071. }
  1072. return wlen + null + state;
  1073. default:
  1074. return -1;
  1075. }
  1076. }
  1077. else
  1078. {
  1079. WCHAR invalid_char;
  1080. switch (gpGlobals->iCodePage)
  1081. {
  1082. case CP_SHIFTJIS:
  1083. invalid_char = 0x30fb;
  1084. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1085. {
  1086. if (state == 0)
  1087. {
  1088. if ((BYTE)mbs[i] <= 0x80)
  1089. wcs[wlen++] = mbs[i];
  1090. else if ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf)
  1091. wcs[wlen++] = cptbl_jis_half[(BYTE)mbs[i] - 0xa0];
  1092. else if ((BYTE)mbs[i] == 0xfd)
  1093. wcs[wlen++] = 0xf8f1;
  1094. else if ((BYTE)mbs[i] == 0xfe)
  1095. wcs[wlen++] = 0xf8f2;
  1096. else if ((BYTE)mbs[i] == 0xff)
  1097. wcs[wlen++] = 0xf8f3;
  1098. else
  1099. state = 1;
  1100. }
  1101. else
  1102. {
  1103. if ((BYTE)mbs[i] < 0x40)
  1104. wcs[wlen++] = 0x30fb;
  1105. else if ((BYTE)mbs[i - 1] < 0xa0)
  1106. wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1107. else
  1108. wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0xc1][(BYTE)mbs[i] - 0x40];
  1109. state = 0;
  1110. }
  1111. }
  1112. break;
  1113. case CP_GBK:
  1114. invalid_char = 0x3f;
  1115. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1116. {
  1117. if (state == 0)
  1118. {
  1119. if ((BYTE)mbs[i] < 0x80)
  1120. wcs[wlen++] = mbs[i];
  1121. else if ((BYTE)mbs[i] == 0x80)
  1122. wcs[wlen++] = 0x20ac;
  1123. else if ((BYTE)mbs[i] == 0xff)
  1124. wcs[wlen++] = 0xf8f5;
  1125. else
  1126. state = 1;
  1127. }
  1128. else
  1129. {
  1130. if ((BYTE)mbs[i] < 0x40)
  1131. wcs[wlen++] = invalid_char;
  1132. else
  1133. wcs[wlen++] = cptbl_gbk[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1134. state = 0;
  1135. }
  1136. }
  1137. break;
  1138. case CP_BIG5:
  1139. invalid_char = 0x3f;
  1140. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1141. {
  1142. if (state == 0)
  1143. {
  1144. if ((BYTE)mbs[i] <= 0x80)
  1145. wcs[wlen++] = mbs[i];
  1146. else if ((BYTE)mbs[i] == 0xff)
  1147. wcs[wlen++] = 0xf8f8;
  1148. else
  1149. state = 1;
  1150. }
  1151. else
  1152. {
  1153. if ((BYTE)mbs[i] < 0x40 || ((BYTE)mbs[i] >= 0x7f && (BYTE)mbs[i] <= 0xa0))
  1154. wcs[wlen++] = invalid_char;
  1155. else if ((BYTE)mbs[i] <= 0x7e)
  1156. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1157. else
  1158. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x60];
  1159. state = 0;
  1160. }
  1161. }
  1162. break;
  1163. default:
  1164. return -1;
  1165. }
  1166. if (state == 1 && wlen < wcslength)
  1167. {
  1168. wcs[wlen++] = invalid_char;
  1169. }
  1170. if (null)
  1171. {
  1172. if (wlen < wcslength)
  1173. wcs[wlen++] = 0;
  1174. else
  1175. wcs[wlen - 1] = 0;
  1176. }
  1177. return wlen;
  1178. }
  1179. }
  1180. WCHAR
  1181. PAL_GetInvalidChar(
  1182. CODEPAGE iCodePage
  1183. )
  1184. {
  1185. switch(iCodePage)
  1186. {
  1187. case CP_BIG5: return 0x3f;
  1188. case CP_GBK: return 0x3f;
  1189. case CP_SHIFTJIS: return 0x30fb;
  1190. default: return 0;
  1191. }
  1192. }
  1193. #endif