text.c 40 KB

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