global.c 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // This file is part of SDLPAL.
  7. //
  8. // SDLPAL is free software: you can redistribute it and/or modify
  9. // it under the terms of the GNU General Public License as published by
  10. // the Free Software Foundation, either version 3 of the License, or
  11. // (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. //
  21. // Modified by Lou Yihua <louyihua@21cn.com> with Unicode support, 2015
  22. //
  23. #include "main.h"
  24. LPGLOBALVARS gpGlobals = NULL;
  25. extern BOOL g_fUseMidi;
  26. #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  27. #define DO_BYTESWAP(buf, size)
  28. #else
  29. #define DO_BYTESWAP(buf, size) \
  30. do { \
  31. int i; \
  32. for (i = 0; i < (size) / 2; i++) \
  33. { \
  34. ((LPWORD)(buf))[i] = SWAP16(((LPWORD)(buf))[i]); \
  35. } \
  36. } while(0)
  37. #endif
  38. #define LOAD_DATA(buf, size, chunknum, fp) \
  39. do { \
  40. PAL_MKFReadChunk((LPBYTE)(buf), (size), (chunknum), (fp)); \
  41. DO_BYTESWAP(buf, size); \
  42. } while(0)
  43. INT
  44. PAL_InitGlobals(
  45. VOID
  46. )
  47. /*++
  48. Purpose:
  49. Initialize global data.
  50. Parameters:
  51. [IN] iCodePage - the code page for text conversion.
  52. [IN] dwWordLength - the length of each word.
  53. Return value:
  54. 0 = success, -1 = error.
  55. --*/
  56. {
  57. FILE *fp;
  58. CODEPAGE iCodePage = CP_UNKNOWN;
  59. DWORD dwWordLength = 10; // Default for PAL DOS/WIN95
  60. DWORD dwExtraMagicDescLines = 0; // Default for PAL DOS/WIN95
  61. DWORD dwExtraItemDescLines = 0; // Default for PAL DOS/WIN95
  62. DWORD dwIsDOS = 1; // Default for DOS
  63. DWORD dwUseEmbeddedFonts = 1; // Default for using embedded fonts in DOS version
  64. DWORD dwUseSurroundOPL = 1; // Default for using surround opl
  65. DWORD dwUseStereo = 1; // Default for stereo audio
  66. INT iSampleRate = 44100; // Default for 44KHz
  67. MUSICTYPE eMusicType = g_fUseMidi ? MUSIC_MIDI : MUSIC_RIX;
  68. MUSICTYPE eCDType = PAL_HAS_SDLCD ? MUSIC_SDLCD : MUSIC_OGG;
  69. OPLTYPE eOPLType = OPL_DOSBOX;
  70. if (gpGlobals == NULL)
  71. {
  72. gpGlobals = (LPGLOBALVARS)calloc(1, sizeof(GLOBALVARS));
  73. if (gpGlobals == NULL)
  74. {
  75. return -1;
  76. }
  77. }
  78. if (fp = UTIL_OpenFile("sdlpal.cfg"))
  79. {
  80. PAL_LARGE char buf[512];
  81. //
  82. // Load the configuration data
  83. //
  84. while (fgets(buf, 512, fp) != NULL)
  85. {
  86. char *p = buf;
  87. //
  88. // Skip leading spaces
  89. //
  90. while (*p && isspace(*p)) p++;
  91. //
  92. // Skip comments
  93. //
  94. if (*p && *p != '#')
  95. {
  96. char *ptr;
  97. if (ptr = strchr(p, '='))
  98. {
  99. char *end = ptr - 1;
  100. *ptr++ = 0;
  101. //
  102. // Skip tailing & leading spaces
  103. //
  104. while (isspace(*end) && end >= p) *end-- = 0;
  105. if (SDL_strcasecmp(p, "CODEPAGE") == 0)
  106. {
  107. sscanf(ptr, "%d", &iCodePage);
  108. }
  109. else if (SDL_strcasecmp(p, "WORDLENGTH") == 0)
  110. {
  111. sscanf(ptr, "%u", &dwWordLength);
  112. }
  113. else if (SDL_strcasecmp(p, "EXTRAMAGICDESCLINES") == 0)
  114. {
  115. sscanf(ptr, "%u", &dwExtraMagicDescLines);
  116. }
  117. else if (SDL_strcasecmp(p, "EXTRAITEMDESCLINES") == 0)
  118. {
  119. sscanf(ptr, "%u", &dwExtraItemDescLines);
  120. }
  121. else if (SDL_strcasecmp(p, "DOS") == 0)
  122. {
  123. sscanf(ptr, "%u", &dwIsDOS);
  124. }
  125. else if (SDL_strcasecmp(p, "USEEMBEDDEDFONTS") == 0)
  126. {
  127. sscanf(ptr, "%u", &dwUseEmbeddedFonts);
  128. }
  129. else if (SDL_strcasecmp(p, "USESURROUNDOPL") == 0)
  130. {
  131. sscanf(ptr, "%u", &dwUseSurroundOPL);
  132. }
  133. else if (SDL_strcasecmp(p, "STEREO") == 0)
  134. {
  135. sscanf(ptr, "%u", &dwUseStereo);
  136. }
  137. else if (SDL_strcasecmp(p, "SAMPLERATE") == 0)
  138. {
  139. sscanf(ptr, "%d", &iSampleRate);
  140. if (iSampleRate > PAL_MAX_SAMPLERATE) iSampleRate = PAL_MAX_SAMPLERATE;
  141. }
  142. else if (SDL_strcasecmp(p, "CD") == 0)
  143. {
  144. char cd_type[32];
  145. sscanf(ptr, "%31s", cd_type);
  146. if (PAL_HAS_MP3 && SDL_strcasecmp(cd_type, "MP3") == 0)
  147. eCDType = MUSIC_MP3;
  148. else if (PAL_HAS_OGG && SDL_strcasecmp(cd_type, "OGG") == 0)
  149. eCDType = MUSIC_OGG;
  150. else if (PAL_HAS_SDLCD && SDL_strcasecmp(cd_type, "RAW") == 0)
  151. eCDType = MUSIC_SDLCD;
  152. }
  153. else if (SDL_strcasecmp(p, "MUSIC") == 0)
  154. {
  155. char music_type[32];
  156. sscanf(ptr, "%31s", music_type);
  157. if (PAL_HAS_NATIVEMIDI && SDL_strcasecmp(music_type, "MIDI") == 0)
  158. eMusicType = MUSIC_MIDI;
  159. else if (PAL_HAS_MP3 && SDL_strcasecmp(music_type, "MP3") == 0)
  160. eMusicType = MUSIC_MP3;
  161. else if (PAL_HAS_OGG && SDL_strcasecmp(music_type, "OGG") == 0)
  162. eMusicType = MUSIC_OGG;
  163. else if (SDL_strcasecmp(music_type, "RIX") == 0)
  164. eMusicType = MUSIC_RIX;
  165. }
  166. else if (SDL_strcasecmp(p, "OPL") == 0)
  167. {
  168. char opl_type[32];
  169. sscanf(ptr, "%31s", opl_type);
  170. if (SDL_strcasecmp(opl_type, "DOSBOX") == 0)
  171. eOPLType = OPL_DOSBOX;
  172. else if (PAL_HAS_MAME && SDL_strcasecmp(opl_type, "MAME") == 0)
  173. eOPLType = OPL_MAME;
  174. }
  175. }
  176. }
  177. }
  178. UTIL_CloseFile(fp);
  179. }
  180. // Codepage auto detect
  181. if (CP_UNKNOWN == iCodePage)
  182. {
  183. // Try to convert the content of word.dat with different codepages,
  184. // and use the codepage with minimal inconvertible characters
  185. // Works fine currently with SC/TC/JP.
  186. if (fp = UTIL_OpenFile("word.dat"))
  187. {
  188. char *buf;
  189. long len;
  190. int i, j, c, m = INT_MAX, m_i;
  191. fseek(fp, 0, SEEK_END);
  192. len = ftell(fp);
  193. buf = (char *)malloc(len);
  194. fseek(fp, 0, SEEK_SET);
  195. fread(buf, 1, len, fp);
  196. UTIL_CloseFile(fp);
  197. for (i = CP_MIN; i < CP_MAX; i++)
  198. {
  199. int wlen = PAL_MultiByteToWideChar(buf, len, NULL, 0);
  200. WCHAR *wbuf = (WCHAR *)malloc(wlen * sizeof(WCHAR));
  201. PAL_MultiByteToWideChar(buf, len, wbuf, wlen);
  202. for (j = c = 0; j < wlen; j++)
  203. {
  204. c += (wbuf[j] == PAL_GetInvalidChar(i)) ? 1 : 0;
  205. }
  206. if (c < m)
  207. {
  208. m = c;
  209. m_i = i;
  210. }
  211. free(wbuf);
  212. }
  213. free(buf);
  214. iCodePage = m_i;
  215. }
  216. else
  217. {
  218. iCodePage = CP_BIG5;
  219. }
  220. }
  221. // Choose version
  222. gpGlobals->fIsWIN95 = dwIsDOS ? FALSE : TRUE;
  223. gpGlobals->fUseEmbeddedFonts = dwIsDOS && dwUseEmbeddedFonts ? TRUE : FALSE;
  224. gpGlobals->fUseSurroundOPL = dwUseStereo && dwUseSurroundOPL ? TRUE : FALSE;
  225. gpGlobals->iAudioChannels = dwUseStereo ? 2 : 1;
  226. gpGlobals->iSampleRate = iSampleRate;
  227. gpGlobals->eMusicType = eMusicType;
  228. gpGlobals->eCDType = eCDType;
  229. gpGlobals->eOPLType = eOPLType;
  230. // Set decompress function
  231. Decompress = gpGlobals->fIsWIN95 ? YJ2_Decompress : YJ1_Decompress;
  232. //
  233. // Open files
  234. //
  235. gpGlobals->f.fpFBP = UTIL_OpenRequiredFile("fbp.mkf");
  236. gpGlobals->f.fpMGO = UTIL_OpenRequiredFile("mgo.mkf");
  237. gpGlobals->f.fpBALL = UTIL_OpenRequiredFile("ball.mkf");
  238. gpGlobals->f.fpDATA = UTIL_OpenRequiredFile("data.mkf");
  239. gpGlobals->f.fpF = UTIL_OpenRequiredFile("f.mkf");
  240. gpGlobals->f.fpFIRE = UTIL_OpenRequiredFile("fire.mkf");
  241. gpGlobals->f.fpRGM = UTIL_OpenRequiredFile("rgm.mkf");
  242. gpGlobals->f.fpSSS = UTIL_OpenRequiredFile("sss.mkf");
  243. gpGlobals->lpObjectDesc = gpGlobals->fIsWIN95 ? NULL : PAL_LoadObjectDesc(va("%s%s", PAL_PREFIX, "desc.dat"));
  244. gpGlobals->bCurrentSaveSlot = 1;
  245. gpGlobals->iCodePage = iCodePage;
  246. gpGlobals->dwWordLength = dwWordLength;
  247. gpGlobals->dwExtraMagicDescLines = dwExtraMagicDescLines;
  248. gpGlobals->dwExtraItemDescLines = dwExtraItemDescLines;
  249. return 0;
  250. }
  251. VOID
  252. PAL_FreeGlobals(
  253. VOID
  254. )
  255. /*++
  256. Purpose:
  257. Free global data.
  258. Parameters:
  259. None.
  260. Return value:
  261. None.
  262. --*/
  263. {
  264. if (gpGlobals != NULL)
  265. {
  266. //
  267. // Close all opened files
  268. //
  269. UTIL_CloseFile(gpGlobals->f.fpFBP);
  270. UTIL_CloseFile(gpGlobals->f.fpMGO);
  271. UTIL_CloseFile(gpGlobals->f.fpBALL);
  272. UTIL_CloseFile(gpGlobals->f.fpDATA);
  273. UTIL_CloseFile(gpGlobals->f.fpF);
  274. UTIL_CloseFile(gpGlobals->f.fpFIRE);
  275. UTIL_CloseFile(gpGlobals->f.fpRGM);
  276. UTIL_CloseFile(gpGlobals->f.fpSSS);
  277. //
  278. // Free the game data
  279. //
  280. free(gpGlobals->g.lprgEventObject);
  281. free(gpGlobals->g.lprgScriptEntry);
  282. free(gpGlobals->g.lprgStore);
  283. free(gpGlobals->g.lprgEnemy);
  284. free(gpGlobals->g.lprgEnemyTeam);
  285. free(gpGlobals->g.lprgMagic);
  286. free(gpGlobals->g.lprgBattleField);
  287. free(gpGlobals->g.lprgLevelUpMagic);
  288. //
  289. // Free the object description data
  290. //
  291. if (!gpGlobals->fIsWIN95)
  292. PAL_FreeObjectDesc(gpGlobals->lpObjectDesc);
  293. //
  294. // Delete the instance
  295. //
  296. free(gpGlobals);
  297. }
  298. gpGlobals = NULL;
  299. }
  300. static VOID
  301. PAL_ReadGlobalGameData(
  302. VOID
  303. )
  304. /*++
  305. Purpose:
  306. Read global game data from data files.
  307. Parameters:
  308. None.
  309. Return value:
  310. None.
  311. --*/
  312. {
  313. const GAMEDATA *p = &gpGlobals->g;
  314. LOAD_DATA(p->lprgScriptEntry, p->nScriptEntry * sizeof(SCRIPTENTRY),
  315. 4, gpGlobals->f.fpSSS);
  316. LOAD_DATA(p->lprgStore, p->nStore * sizeof(STORE), 0, gpGlobals->f.fpDATA);
  317. LOAD_DATA(p->lprgEnemy, p->nEnemy * sizeof(ENEMY), 1, gpGlobals->f.fpDATA);
  318. LOAD_DATA(p->lprgEnemyTeam, p->nEnemyTeam * sizeof(ENEMYTEAM),
  319. 2, gpGlobals->f.fpDATA);
  320. LOAD_DATA(p->lprgMagic, p->nMagic * sizeof(MAGIC), 4, gpGlobals->f.fpDATA);
  321. LOAD_DATA(p->lprgBattleField, p->nBattleField * sizeof(BATTLEFIELD),
  322. 5, gpGlobals->f.fpDATA);
  323. LOAD_DATA(p->lprgLevelUpMagic, p->nLevelUpMagic * sizeof(LEVELUPMAGIC_ALL),
  324. 6, gpGlobals->f.fpDATA);
  325. LOAD_DATA(p->rgwBattleEffectIndex, sizeof(p->rgwBattleEffectIndex),
  326. 11, gpGlobals->f.fpDATA);
  327. PAL_MKFReadChunk((LPBYTE)&(p->EnemyPos), sizeof(p->EnemyPos),
  328. 13, gpGlobals->f.fpDATA);
  329. DO_BYTESWAP(&(p->EnemyPos), sizeof(p->EnemyPos));
  330. PAL_MKFReadChunk((LPBYTE)(p->rgLevelUpExp), sizeof(p->rgLevelUpExp),
  331. 14, gpGlobals->f.fpDATA);
  332. DO_BYTESWAP(p->rgLevelUpExp, sizeof(p->rgLevelUpExp));
  333. }
  334. static VOID
  335. PAL_InitGlobalGameData(
  336. VOID
  337. )
  338. /*++
  339. Purpose:
  340. Initialize global game data.
  341. Parameters:
  342. None.
  343. Return value:
  344. None.
  345. --*/
  346. {
  347. int len;
  348. #define PAL_DOALLOCATE(fp, num, type, lptype, ptr, n) \
  349. { \
  350. len = PAL_MKFGetChunkSize(num, fp); \
  351. ptr = (lptype)malloc(len); \
  352. n = len / sizeof(type); \
  353. if (ptr == NULL) \
  354. { \
  355. TerminateOnError("PAL_InitGlobalGameData(): Memory allocation error!"); \
  356. } \
  357. }
  358. //
  359. // If the memory has not been allocated, allocate first.
  360. //
  361. if (gpGlobals->g.lprgEventObject == NULL)
  362. {
  363. PAL_DOALLOCATE(gpGlobals->f.fpSSS, 0, EVENTOBJECT, LPEVENTOBJECT,
  364. gpGlobals->g.lprgEventObject, gpGlobals->g.nEventObject);
  365. PAL_DOALLOCATE(gpGlobals->f.fpSSS, 4, SCRIPTENTRY, LPSCRIPTENTRY,
  366. gpGlobals->g.lprgScriptEntry, gpGlobals->g.nScriptEntry);
  367. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 0, STORE, LPSTORE,
  368. gpGlobals->g.lprgStore, gpGlobals->g.nStore);
  369. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 1, ENEMY, LPENEMY,
  370. gpGlobals->g.lprgEnemy, gpGlobals->g.nEnemy);
  371. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 2, ENEMYTEAM, LPENEMYTEAM,
  372. gpGlobals->g.lprgEnemyTeam, gpGlobals->g.nEnemyTeam);
  373. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 4, MAGIC, LPMAGIC,
  374. gpGlobals->g.lprgMagic, gpGlobals->g.nMagic);
  375. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 5, BATTLEFIELD, LPBATTLEFIELD,
  376. gpGlobals->g.lprgBattleField, gpGlobals->g.nBattleField);
  377. PAL_DOALLOCATE(gpGlobals->f.fpDATA, 6, LEVELUPMAGIC_ALL, LPLEVELUPMAGIC_ALL,
  378. gpGlobals->g.lprgLevelUpMagic, gpGlobals->g.nLevelUpMagic);
  379. PAL_ReadGlobalGameData();
  380. }
  381. #undef PAL_DOALLOCATE
  382. }
  383. static VOID
  384. PAL_LoadDefaultGame(
  385. VOID
  386. )
  387. /*++
  388. Purpose:
  389. Load the default game data.
  390. Parameters:
  391. None.
  392. Return value:
  393. None.
  394. --*/
  395. {
  396. GAMEDATA *p = &gpGlobals->g;
  397. UINT32 i;
  398. //
  399. // Load the default data from the game data files.
  400. //
  401. LOAD_DATA(p->lprgEventObject, p->nEventObject * sizeof(EVENTOBJECT),
  402. 0, gpGlobals->f.fpSSS);
  403. PAL_MKFReadChunk((LPBYTE)(p->rgScene), sizeof(p->rgScene), 1, gpGlobals->f.fpSSS);
  404. DO_BYTESWAP(p->rgScene, sizeof(p->rgScene));
  405. if (gpGlobals->fIsWIN95)
  406. {
  407. PAL_MKFReadChunk((LPBYTE)(p->rgObject), sizeof(p->rgObject), 2, gpGlobals->f.fpSSS);
  408. DO_BYTESWAP(p->rgObject, sizeof(p->rgObject));
  409. }
  410. else
  411. {
  412. OBJECT_DOS objects[MAX_OBJECTS];
  413. PAL_MKFReadChunk((LPBYTE)(objects), sizeof(objects), 2, gpGlobals->f.fpSSS);
  414. DO_BYTESWAP(objects, sizeof(objects));
  415. //
  416. // Convert the DOS-style data structure to WIN-style data structure
  417. //
  418. for (int i = 0; i < MAX_OBJECTS; i++)
  419. {
  420. memcpy(&p->rgObject[i], &objects[i], sizeof(OBJECT_DOS));
  421. if (i >= OBJECT_ITEM_START && i <= OBJECT_MAGIC_END)
  422. {
  423. p->rgObject[i].rgwData[6] = objects[i].rgwData[5]; // wFlags
  424. p->rgObject[i].rgwData[5] = 0; // wScriptDesc or wReserved2
  425. }
  426. else
  427. {
  428. p->rgObject[i].rgwData[6] = 0;
  429. }
  430. }
  431. }
  432. PAL_MKFReadChunk((LPBYTE)(&(p->PlayerRoles)), sizeof(PLAYERROLES),
  433. 3, gpGlobals->f.fpDATA);
  434. DO_BYTESWAP(&(p->PlayerRoles), sizeof(PLAYERROLES));
  435. //
  436. // Set some other default data.
  437. //
  438. gpGlobals->dwCash = 0;
  439. gpGlobals->wNumMusic = 0;
  440. gpGlobals->wNumPalette = 0;
  441. gpGlobals->wNumScene = 1;
  442. gpGlobals->wCollectValue = 0;
  443. gpGlobals->fNightPalette = FALSE;
  444. gpGlobals->wMaxPartyMemberIndex = 0;
  445. gpGlobals->viewport = PAL_XY(0, 0);
  446. gpGlobals->wLayer = 0;
  447. gpGlobals->wChaseRange = 1;
  448. #ifndef PAL_CLASSIC
  449. gpGlobals->bBattleSpeed = 2;
  450. #endif
  451. memset(gpGlobals->rgInventory, 0, sizeof(gpGlobals->rgInventory));
  452. memset(gpGlobals->rgPoisonStatus, 0, sizeof(gpGlobals->rgPoisonStatus));
  453. memset(gpGlobals->rgParty, 0, sizeof(gpGlobals->rgParty));
  454. memset(gpGlobals->rgTrail, 0, sizeof(gpGlobals->rgTrail));
  455. memset(&(gpGlobals->Exp), 0, sizeof(gpGlobals->Exp));
  456. for (i = 0; i < MAX_PLAYER_ROLES; i++)
  457. {
  458. gpGlobals->Exp.rgPrimaryExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  459. gpGlobals->Exp.rgHealthExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  460. gpGlobals->Exp.rgMagicExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  461. gpGlobals->Exp.rgAttackExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  462. gpGlobals->Exp.rgMagicPowerExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  463. gpGlobals->Exp.rgDefenseExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  464. gpGlobals->Exp.rgDexterityExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  465. gpGlobals->Exp.rgFleeExp[i].wLevel = p->PlayerRoles.rgwLevel[i];
  466. }
  467. gpGlobals->fEnteringScene = TRUE;
  468. }
  469. typedef struct tagSAVEDGAME_COMMON
  470. {
  471. WORD wSavedTimes; // saved times
  472. WORD wViewportX, wViewportY; // viewport location
  473. WORD nPartyMember; // number of members in party
  474. WORD wNumScene; // scene number
  475. WORD wPaletteOffset;
  476. WORD wPartyDirection; // party direction
  477. WORD wNumMusic; // music number
  478. WORD wNumBattleMusic; // battle music number
  479. WORD wNumBattleField; // battle field number
  480. WORD wScreenWave; // level of screen waving
  481. WORD wBattleSpeed; // battle speed
  482. WORD wCollectValue; // value of "collected" items
  483. WORD wLayer;
  484. WORD wChaseRange;
  485. WORD wChasespeedChangeCycles;
  486. WORD nFollower;
  487. WORD rgwReserved2[3]; // unused
  488. DWORD dwCash; // amount of cash
  489. PARTY rgParty[MAX_PLAYABLE_PLAYER_ROLES]; // player party
  490. TRAIL rgTrail[MAX_PLAYABLE_PLAYER_ROLES]; // player trail
  491. ALLEXPERIENCE Exp; // experience data
  492. PLAYERROLES PlayerRoles;
  493. POISONSTATUS rgPoisonStatus[MAX_POISONS][MAX_PLAYABLE_PLAYER_ROLES]; // poison status
  494. INVENTORY rgInventory[MAX_INVENTORY]; // inventory status
  495. SCENE rgScene[MAX_SCENES];
  496. } SAVEDGAME_COMMON, *LPSAVEDGAME_COMMON;
  497. typedef struct tagSAVEDGAME_DOS
  498. {
  499. WORD wSavedTimes; // saved times
  500. WORD wViewportX, wViewportY; // viewport location
  501. WORD nPartyMember; // number of members in party
  502. WORD wNumScene; // scene number
  503. WORD wPaletteOffset;
  504. WORD wPartyDirection; // party direction
  505. WORD wNumMusic; // music number
  506. WORD wNumBattleMusic; // battle music number
  507. WORD wNumBattleField; // battle field number
  508. WORD wScreenWave; // level of screen waving
  509. WORD wBattleSpeed; // battle speed
  510. WORD wCollectValue; // value of "collected" items
  511. WORD wLayer;
  512. WORD wChaseRange;
  513. WORD wChasespeedChangeCycles;
  514. WORD nFollower;
  515. WORD rgwReserved2[3]; // unused
  516. DWORD dwCash; // amount of cash
  517. PARTY rgParty[MAX_PLAYABLE_PLAYER_ROLES]; // player party
  518. TRAIL rgTrail[MAX_PLAYABLE_PLAYER_ROLES]; // player trail
  519. ALLEXPERIENCE Exp; // experience data
  520. PLAYERROLES PlayerRoles;
  521. POISONSTATUS rgPoisonStatus[MAX_POISONS][MAX_PLAYABLE_PLAYER_ROLES]; // poison status
  522. INVENTORY rgInventory[MAX_INVENTORY]; // inventory status
  523. SCENE rgScene[MAX_SCENES];
  524. OBJECT_DOS rgObject[MAX_OBJECTS];
  525. EVENTOBJECT rgEventObject[MAX_EVENT_OBJECTS];
  526. } SAVEDGAME_DOS, *LPSAVEDGAME_DOS;
  527. typedef struct tagSAVEDGAME_WIN
  528. {
  529. WORD wSavedTimes; // saved times
  530. WORD wViewportX, wViewportY; // viewport location
  531. WORD nPartyMember; // number of members in party
  532. WORD wNumScene; // scene number
  533. WORD wPaletteOffset;
  534. WORD wPartyDirection; // party direction
  535. WORD wNumMusic; // music number
  536. WORD wNumBattleMusic; // battle music number
  537. WORD wNumBattleField; // battle field number
  538. WORD wScreenWave; // level of screen waving
  539. WORD wBattleSpeed; // battle speed
  540. WORD wCollectValue; // value of "collected" items
  541. WORD wLayer;
  542. WORD wChaseRange;
  543. WORD wChasespeedChangeCycles;
  544. WORD nFollower;
  545. WORD rgwReserved2[3]; // unused
  546. DWORD dwCash; // amount of cash
  547. PARTY rgParty[MAX_PLAYABLE_PLAYER_ROLES]; // player party
  548. TRAIL rgTrail[MAX_PLAYABLE_PLAYER_ROLES]; // player trail
  549. ALLEXPERIENCE Exp; // experience data
  550. PLAYERROLES PlayerRoles;
  551. POISONSTATUS rgPoisonStatus[MAX_POISONS][MAX_PLAYABLE_PLAYER_ROLES]; // poison status
  552. INVENTORY rgInventory[MAX_INVENTORY]; // inventory status
  553. SCENE rgScene[MAX_SCENES];
  554. OBJECT rgObject[MAX_OBJECTS];
  555. EVENTOBJECT rgEventObject[MAX_EVENT_OBJECTS];
  556. } SAVEDGAME_WIN, *LPSAVEDGAME_WIN;
  557. static VOID
  558. PAL_LoadGame_Common(
  559. const LPSAVEDGAME_COMMON s
  560. )
  561. {
  562. gpGlobals->viewport = PAL_XY(s->wViewportX, s->wViewportY);
  563. gpGlobals->wMaxPartyMemberIndex = s->nPartyMember;
  564. gpGlobals->wNumScene = s->wNumScene;
  565. gpGlobals->fNightPalette = (s->wPaletteOffset != 0);
  566. gpGlobals->wPartyDirection = s->wPartyDirection;
  567. gpGlobals->wNumMusic = s->wNumMusic;
  568. gpGlobals->wNumBattleMusic = s->wNumBattleMusic;
  569. gpGlobals->wNumBattleField = s->wNumBattleField;
  570. gpGlobals->wScreenWave = s->wScreenWave;
  571. gpGlobals->sWaveProgression = 0;
  572. gpGlobals->wCollectValue = s->wCollectValue;
  573. gpGlobals->wLayer = s->wLayer;
  574. gpGlobals->wChaseRange = s->wChaseRange;
  575. gpGlobals->wChasespeedChangeCycles = s->wChasespeedChangeCycles;
  576. gpGlobals->nFollower = s->nFollower;
  577. gpGlobals->dwCash = s->dwCash;
  578. #ifndef PAL_CLASSIC
  579. gpGlobals->bBattleSpeed = s->wBattleSpeed;
  580. if (gpGlobals->bBattleSpeed > 5 || gpGlobals->bBattleSpeed == 0)
  581. {
  582. gpGlobals->bBattleSpeed = 2;
  583. }
  584. #endif
  585. memcpy(gpGlobals->rgParty, s->rgParty, sizeof(gpGlobals->rgParty));
  586. memcpy(gpGlobals->rgTrail, s->rgTrail, sizeof(gpGlobals->rgTrail));
  587. gpGlobals->Exp = s->Exp;
  588. gpGlobals->g.PlayerRoles = s->PlayerRoles;
  589. memset(gpGlobals->rgPoisonStatus, 0, sizeof(gpGlobals->rgPoisonStatus));
  590. memcpy(gpGlobals->rgInventory, s->rgInventory, sizeof(gpGlobals->rgInventory));
  591. memcpy(gpGlobals->g.rgScene, s->rgScene, sizeof(gpGlobals->g.rgScene));
  592. }
  593. static INT
  594. PAL_LoadGame_DOS(
  595. LPCSTR szFileName
  596. )
  597. /*++
  598. Purpose:
  599. Load a saved game.
  600. Parameters:
  601. [IN] szFileName - file name of saved game.
  602. Return value:
  603. 0 if success, -1 if failed.
  604. --*/
  605. {
  606. FILE *fp;
  607. PAL_LARGE SAVEDGAME_DOS s;
  608. //
  609. // Try to open the specified file
  610. //
  611. fp = fopen(szFileName, "rb");
  612. if (fp == NULL)
  613. {
  614. return -1;
  615. }
  616. //
  617. // Read all data from the file and close.
  618. //
  619. fread(&s, sizeof(SAVEDGAME_DOS), 1, fp);
  620. fclose(fp);
  621. //
  622. // Adjust endianness
  623. //
  624. DO_BYTESWAP(&s, sizeof(SAVEDGAME_DOS));
  625. //
  626. // Cash amount is in DWORD, so do a wordswap in Big-Endian.
  627. //
  628. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  629. s.dwCash = ((s.dwCash >> 16) | (s.dwCash << 16));
  630. #endif
  631. //
  632. // Get all the data from the saved game struct.
  633. //
  634. PAL_LoadGame_Common((LPSAVEDGAME_COMMON)&s);
  635. //
  636. // Convert the DOS-style data structure to WIN-style data structure
  637. //
  638. for (int i = 0; i < MAX_OBJECTS; i++)
  639. {
  640. memcpy(&gpGlobals->g.rgObject[i], &s.rgObject[i], sizeof(OBJECT_DOS));
  641. if (i >= OBJECT_ITEM_START && i <= OBJECT_MAGIC_END)
  642. {
  643. gpGlobals->g.rgObject[i].rgwData[6] = s.rgObject[i].rgwData[5]; // wFlags
  644. gpGlobals->g.rgObject[i].rgwData[5] = 0; // wScriptDesc or wReserved2
  645. }
  646. else
  647. {
  648. gpGlobals->g.rgObject[i].rgwData[6] = 0;
  649. }
  650. }
  651. memcpy(gpGlobals->g.lprgEventObject, s.rgEventObject,
  652. sizeof(EVENTOBJECT) * gpGlobals->g.nEventObject);
  653. gpGlobals->fEnteringScene = FALSE;
  654. PAL_CompressInventory();
  655. //
  656. // Success
  657. //
  658. return 0;
  659. }
  660. static INT
  661. PAL_LoadGame_WIN(
  662. LPCSTR szFileName
  663. )
  664. /*++
  665. Purpose:
  666. Load a saved game.
  667. Parameters:
  668. [IN] szFileName - file name of saved game.
  669. Return value:
  670. 0 if success, -1 if failed.
  671. --*/
  672. {
  673. FILE *fp;
  674. PAL_LARGE SAVEDGAME_WIN s;
  675. //
  676. // Try to open the specified file
  677. //
  678. fp = fopen(szFileName, "rb");
  679. if (fp == NULL)
  680. {
  681. return -1;
  682. }
  683. //
  684. // Read all data from the file and close.
  685. //
  686. fread(&s, sizeof(SAVEDGAME_WIN), 1, fp);
  687. fclose(fp);
  688. //
  689. // Adjust endianness
  690. //
  691. DO_BYTESWAP(&s, sizeof(SAVEDGAME_WIN));
  692. //
  693. // Cash amount is in DWORD, so do a wordswap in Big-Endian.
  694. //
  695. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  696. s.dwCash = ((s.dwCash >> 16) | (s.dwCash << 16));
  697. #endif
  698. //
  699. // Get all the data from the saved game struct.
  700. //
  701. PAL_LoadGame_Common((LPSAVEDGAME_COMMON)&s);
  702. memcpy(gpGlobals->g.rgObject, s.rgObject, sizeof(gpGlobals->g.rgObject));
  703. memcpy(gpGlobals->g.lprgEventObject, s.rgEventObject,
  704. sizeof(EVENTOBJECT) * gpGlobals->g.nEventObject);
  705. gpGlobals->fEnteringScene = FALSE;
  706. PAL_CompressInventory();
  707. //
  708. // Success
  709. //
  710. return 0;
  711. }
  712. static INT
  713. PAL_LoadGame(
  714. LPCSTR szFileName
  715. )
  716. {
  717. return gpGlobals->fIsWIN95 ? PAL_LoadGame_WIN(szFileName) : PAL_LoadGame_DOS(szFileName);
  718. }
  719. static VOID
  720. PAL_SaveGame_Common(
  721. const LPSAVEDGAME_COMMON s
  722. )
  723. {
  724. s->wViewportX = PAL_X(gpGlobals->viewport);
  725. s->wViewportY = PAL_Y(gpGlobals->viewport);
  726. s->nPartyMember = gpGlobals->wMaxPartyMemberIndex;
  727. s->wNumScene = gpGlobals->wNumScene;
  728. s->wPaletteOffset = (gpGlobals->fNightPalette ? 0x180 : 0);
  729. s->wPartyDirection = gpGlobals->wPartyDirection;
  730. s->wNumMusic = gpGlobals->wNumMusic;
  731. s->wNumBattleMusic = gpGlobals->wNumBattleMusic;
  732. s->wNumBattleField = gpGlobals->wNumBattleField;
  733. s->wScreenWave = gpGlobals->wScreenWave;
  734. s->wCollectValue = gpGlobals->wCollectValue;
  735. s->wLayer = gpGlobals->wLayer;
  736. s->wChaseRange = gpGlobals->wChaseRange;
  737. s->wChasespeedChangeCycles = gpGlobals->wChasespeedChangeCycles;
  738. s->nFollower = gpGlobals->nFollower;
  739. s->dwCash = gpGlobals->dwCash;
  740. #ifndef PAL_CLASSIC
  741. s->wBattleSpeed = gpGlobals->bBattleSpeed;
  742. #else
  743. s->wBattleSpeed = 2;
  744. #endif
  745. memcpy(s->rgParty, gpGlobals->rgParty, sizeof(gpGlobals->rgParty));
  746. memcpy(s->rgTrail, gpGlobals->rgTrail, sizeof(gpGlobals->rgTrail));
  747. s->Exp = gpGlobals->Exp;
  748. s->PlayerRoles = gpGlobals->g.PlayerRoles;
  749. memcpy(s->rgPoisonStatus, gpGlobals->rgPoisonStatus, sizeof(gpGlobals->rgPoisonStatus));
  750. memcpy(s->rgInventory, gpGlobals->rgInventory, sizeof(gpGlobals->rgInventory));
  751. memcpy(s->rgScene, gpGlobals->g.rgScene, sizeof(gpGlobals->g.rgScene));
  752. }
  753. static VOID
  754. PAL_SaveGame_DOS(
  755. LPCSTR szFileName,
  756. WORD wSavedTimes
  757. )
  758. /*++
  759. Purpose:
  760. Save the current game state to file.
  761. Parameters:
  762. [IN] szFileName - file name of saved game.
  763. Return value:
  764. None.
  765. --*/
  766. {
  767. FILE *fp;
  768. PAL_LARGE SAVEDGAME_DOS s;
  769. UINT32 i;
  770. //
  771. // Put all the data to the saved game struct.
  772. //
  773. PAL_SaveGame_Common((LPSAVEDGAME_COMMON)&s);
  774. //
  775. // Convert the WIN-style data structure to DOS-style data structure
  776. //
  777. for (int i = 0; i < MAX_OBJECTS; i++)
  778. {
  779. memcpy(&s.rgObject[i], &gpGlobals->g.rgObject[i], sizeof(OBJECT_DOS));
  780. if (i >= OBJECT_ITEM_START && i <= OBJECT_MAGIC_END)
  781. {
  782. s.rgObject[i].rgwData[5] = gpGlobals->g.rgObject[i].rgwData[6]; // wFlags
  783. }
  784. }
  785. memcpy(s.rgEventObject, gpGlobals->g.lprgEventObject,
  786. sizeof(EVENTOBJECT) * gpGlobals->g.nEventObject);
  787. s.wSavedTimes = wSavedTimes;
  788. //
  789. // Adjust endianness
  790. //
  791. DO_BYTESWAP(&s, sizeof(SAVEDGAME));
  792. //
  793. // Cash amount is in DWORD, so do a wordswap in Big-Endian.
  794. //
  795. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  796. s.dwCash = ((s.dwCash >> 16) | (s.dwCash << 16));
  797. #endif
  798. //
  799. // Try writing to file
  800. //
  801. fp = fopen(szFileName, "wb");
  802. if (fp == NULL)
  803. {
  804. return;
  805. }
  806. i = PAL_MKFGetChunkSize(0, gpGlobals->f.fpSSS);
  807. i += sizeof(SAVEDGAME_DOS) - sizeof(EVENTOBJECT) * MAX_EVENT_OBJECTS;
  808. fwrite(&s, i, 1, fp);
  809. fclose(fp);
  810. }
  811. static VOID
  812. PAL_SaveGame_WIN(
  813. LPCSTR szFileName,
  814. WORD wSavedTimes
  815. )
  816. /*++
  817. Purpose:
  818. Save the current game state to file.
  819. Parameters:
  820. [IN] szFileName - file name of saved game.
  821. Return value:
  822. None.
  823. --*/
  824. {
  825. FILE *fp;
  826. PAL_LARGE SAVEDGAME_WIN s;
  827. UINT32 i;
  828. //
  829. // Put all the data to the saved game struct.
  830. //
  831. PAL_SaveGame_Common((LPSAVEDGAME_COMMON)&s);
  832. memcpy(s.rgObject, gpGlobals->g.rgObject, sizeof(gpGlobals->g.rgObject));
  833. memcpy(s.rgEventObject, gpGlobals->g.lprgEventObject,
  834. sizeof(EVENTOBJECT) * gpGlobals->g.nEventObject);
  835. s.wSavedTimes = wSavedTimes;
  836. //
  837. // Adjust endianness
  838. //
  839. DO_BYTESWAP(&s, sizeof(SAVEDGAME));
  840. //
  841. // Cash amount is in DWORD, so do a wordswap in Big-Endian.
  842. //
  843. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  844. s.dwCash = ((s.dwCash >> 16) | (s.dwCash << 16));
  845. #endif
  846. //
  847. // Try writing to file
  848. //
  849. fp = fopen(szFileName, "wb");
  850. if (fp == NULL)
  851. {
  852. return;
  853. }
  854. i = PAL_MKFGetChunkSize(0, gpGlobals->f.fpSSS);
  855. i += sizeof(SAVEDGAME_WIN) - sizeof(EVENTOBJECT) * MAX_EVENT_OBJECTS;
  856. fwrite(&s, i, 1, fp);
  857. fclose(fp);
  858. }
  859. VOID
  860. PAL_SaveGame(
  861. LPCSTR szFileName,
  862. WORD wSavedTimes
  863. )
  864. {
  865. if (gpGlobals->fIsWIN95)
  866. PAL_SaveGame_WIN(szFileName, wSavedTimes);
  867. else
  868. PAL_SaveGame_DOS(szFileName, wSavedTimes);
  869. }
  870. VOID
  871. PAL_InitGameData(
  872. INT iSaveSlot
  873. )
  874. /*++
  875. Purpose:
  876. Initialize the game data (used when starting a new game or loading a saved game).
  877. Parameters:
  878. [IN] iSaveSlot - Slot of saved game.
  879. Return value:
  880. None.
  881. --*/
  882. {
  883. PAL_InitGlobalGameData();
  884. gpGlobals->bCurrentSaveSlot = (BYTE)iSaveSlot;
  885. //
  886. // try loading from the saved game file.
  887. //
  888. if (iSaveSlot == 0 || PAL_LoadGame(va("%s%d%s", PAL_SAVE_PREFIX, iSaveSlot, ".rpg")) != 0)
  889. {
  890. //
  891. // Cannot load the saved game file. Load the defaults.
  892. //
  893. PAL_LoadDefaultGame();
  894. }
  895. gpGlobals->fGameStart = TRUE;
  896. gpGlobals->fNeedToFadeIn = FALSE;
  897. gpGlobals->iCurInvMenuItem = 0;
  898. gpGlobals->fInBattle = FALSE;
  899. memset(gpGlobals->rgPlayerStatus, 0, sizeof(gpGlobals->rgPlayerStatus));
  900. PAL_UpdateEquipments();
  901. }
  902. BOOL
  903. PAL_AddItemToInventory(
  904. WORD wObjectID,
  905. INT iNum
  906. )
  907. /*++
  908. Purpose:
  909. Add or remove the specified kind of item in the inventory.
  910. Parameters:
  911. [IN] wObjectID - object number of the item.
  912. [IN] iNum - number to be added (positive value) or removed (negative value).
  913. Return value:
  914. TRUE if succeeded, FALSE if failed.
  915. --*/
  916. {
  917. int index;
  918. BOOL fFound;
  919. if (wObjectID == 0)
  920. {
  921. return FALSE;
  922. }
  923. if (iNum == 0)
  924. {
  925. iNum = 1;
  926. }
  927. index = 0;
  928. fFound = FALSE;
  929. //
  930. // Search for the specified item in the inventory
  931. //
  932. while (index < MAX_INVENTORY)
  933. {
  934. if (gpGlobals->rgInventory[index].wItem == wObjectID)
  935. {
  936. fFound = TRUE;
  937. break;
  938. }
  939. else if (gpGlobals->rgInventory[index].wItem == 0)
  940. {
  941. break;
  942. }
  943. index++;
  944. }
  945. if (iNum > 0)
  946. {
  947. //
  948. // Add item
  949. //
  950. if (index >= MAX_INVENTORY)
  951. {
  952. //
  953. // inventory is full. cannot add item
  954. //
  955. return FALSE;
  956. }
  957. if (fFound)
  958. {
  959. gpGlobals->rgInventory[index].nAmount += iNum;
  960. if (gpGlobals->rgInventory[index].nAmount > 99)
  961. {
  962. //
  963. // Maximum number is 99
  964. //
  965. gpGlobals->rgInventory[index].nAmount = 99;
  966. }
  967. }
  968. else
  969. {
  970. gpGlobals->rgInventory[index].wItem = wObjectID;
  971. if (iNum > 99)
  972. {
  973. iNum = 99;
  974. }
  975. gpGlobals->rgInventory[index].nAmount = iNum;
  976. }
  977. return TRUE;
  978. }
  979. else
  980. {
  981. //
  982. // Remove item
  983. //
  984. if (fFound)
  985. {
  986. iNum *= -1;
  987. if (gpGlobals->rgInventory[index].nAmount < iNum)
  988. {
  989. //
  990. // This item has been run out
  991. //
  992. gpGlobals->rgInventory[index].nAmount = 0;
  993. return FALSE;
  994. }
  995. gpGlobals->rgInventory[index].nAmount -= iNum;
  996. return TRUE;
  997. }
  998. return FALSE;
  999. }
  1000. }
  1001. INT
  1002. PAL_GetItemAmount(
  1003. WORD wItem
  1004. )
  1005. /*++
  1006. Purpose:
  1007. Get the amount of the specified item in the inventory.
  1008. Parameters:
  1009. [IN] wItem - the object ID of the item.
  1010. Return value:
  1011. The amount of the item in the inventory.
  1012. --*/
  1013. {
  1014. int i;
  1015. for (i = 0; i < MAX_INVENTORY; i++)
  1016. {
  1017. if (gpGlobals->rgInventory[i].wItem == 0)
  1018. {
  1019. break;
  1020. }
  1021. if (gpGlobals->rgInventory[i].wItem == wItem)
  1022. {
  1023. return gpGlobals->rgInventory[i].nAmount;
  1024. }
  1025. }
  1026. return 0;
  1027. }
  1028. VOID
  1029. PAL_CompressInventory(
  1030. VOID
  1031. )
  1032. /*++
  1033. Purpose:
  1034. Remove all the items in inventory which has a number of zero.
  1035. Parameters:
  1036. None.
  1037. Return value:
  1038. None.
  1039. --*/
  1040. {
  1041. int i, j;
  1042. j = 0;
  1043. for (i = 0; i < MAX_INVENTORY; i++)
  1044. {
  1045. if (gpGlobals->rgInventory[i].wItem == 0)
  1046. {
  1047. break;
  1048. }
  1049. if (gpGlobals->rgInventory[i].nAmount > 0)
  1050. {
  1051. gpGlobals->rgInventory[j] = gpGlobals->rgInventory[i];
  1052. j++;
  1053. }
  1054. }
  1055. for (; j < MAX_INVENTORY; j++)
  1056. {
  1057. gpGlobals->rgInventory[j].nAmount = 0;
  1058. gpGlobals->rgInventory[j].nAmountInUse = 0;
  1059. gpGlobals->rgInventory[j].wItem = 0;
  1060. }
  1061. }
  1062. BOOL
  1063. PAL_IncreaseHPMP(
  1064. WORD wPlayerRole,
  1065. SHORT sHP,
  1066. SHORT sMP
  1067. )
  1068. /*++
  1069. Purpose:
  1070. Increase or decrease player's HP and/or MP.
  1071. Parameters:
  1072. [IN] wPlayerRole - the number of player role.
  1073. [IN] sHP - number of HP to be increased (positive value) or decrased
  1074. (negative value).
  1075. [IN] sMP - number of MP to be increased (positive value) or decrased
  1076. (negative value).
  1077. Return value:
  1078. TRUE if the operation is succeeded, FALSE if not.
  1079. --*/
  1080. {
  1081. BOOL fSuccess = FALSE;
  1082. //
  1083. // Only care about alive players
  1084. //
  1085. if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0)
  1086. {
  1087. //
  1088. // change HP
  1089. //
  1090. gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] += sHP;
  1091. if ((SHORT)(gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole]) < 0)
  1092. {
  1093. gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] = 0;
  1094. }
  1095. else if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] >
  1096. gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole])
  1097. {
  1098. gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] =
  1099. gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole];
  1100. }
  1101. //
  1102. // Change MP
  1103. //
  1104. gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] += sMP;
  1105. if ((SHORT)(gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole]) < 0)
  1106. {
  1107. gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] = 0;
  1108. }
  1109. else if (gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] >
  1110. gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole])
  1111. {
  1112. gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] =
  1113. gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole];
  1114. }
  1115. fSuccess = TRUE;
  1116. }
  1117. return fSuccess;
  1118. }
  1119. VOID
  1120. PAL_UpdateEquipments(
  1121. VOID
  1122. )
  1123. /*++
  1124. Purpose:
  1125. Update the effects of all equipped items for all players.
  1126. Parameters:
  1127. None.
  1128. Return value:
  1129. None.
  1130. --*/
  1131. {
  1132. int i, j;
  1133. WORD w;
  1134. memset(&(gpGlobals->rgEquipmentEffect), 0, sizeof(gpGlobals->rgEquipmentEffect));
  1135. for (i = 0; i < MAX_PLAYER_ROLES; i++)
  1136. {
  1137. for (j = 0; j < MAX_PLAYER_EQUIPMENTS; j++)
  1138. {
  1139. w = gpGlobals->g.PlayerRoles.rgwEquipment[j][i];
  1140. if (w != 0)
  1141. {
  1142. gpGlobals->g.rgObject[w].item.wScriptOnEquip =
  1143. PAL_RunTriggerScript(gpGlobals->g.rgObject[w].item.wScriptOnEquip, (WORD)i);
  1144. }
  1145. }
  1146. }
  1147. }
  1148. VOID
  1149. PAL_RemoveEquipmentEffect(
  1150. WORD wPlayerRole,
  1151. WORD wEquipPart
  1152. )
  1153. /*++
  1154. Purpose:
  1155. Remove all the effects of the equipment for the player.
  1156. Parameters:
  1157. [IN] wPlayerRole - the player role.
  1158. [IN] wEquipPart - the part of the equipment.
  1159. Return value:
  1160. None.
  1161. --*/
  1162. {
  1163. WORD *p;
  1164. int i, j;
  1165. p = (WORD *)(&gpGlobals->rgEquipmentEffect[wEquipPart]); // HACKHACK
  1166. for (i = 0; i < sizeof(PLAYERROLES) / sizeof(PLAYERS); i++)
  1167. {
  1168. p[i * MAX_PLAYER_ROLES + wPlayerRole] = 0;
  1169. }
  1170. //
  1171. // Reset some parameters to default when appropriate
  1172. //
  1173. if (wEquipPart == kBodyPartHand)
  1174. {
  1175. //
  1176. // reset the dual attack status
  1177. //
  1178. gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] = 0;
  1179. }
  1180. else if (wEquipPart == kBodyPartWear)
  1181. {
  1182. //
  1183. // Remove all poisons leveled 99
  1184. //
  1185. for (i = 0; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++)
  1186. {
  1187. if (gpGlobals->rgParty[i].wPlayerRole == wPlayerRole)
  1188. {
  1189. wPlayerRole = i;
  1190. break;
  1191. }
  1192. }
  1193. if (i <= (short)gpGlobals->wMaxPartyMemberIndex)
  1194. {
  1195. j = 0;
  1196. for (i = 0; i < MAX_POISONS; i++)
  1197. {
  1198. WORD w = gpGlobals->rgPoisonStatus[i][wPlayerRole].wPoisonID;
  1199. if (w == 0)
  1200. {
  1201. break;
  1202. }
  1203. if (gpGlobals->g.rgObject[w].poison.wPoisonLevel < 99)
  1204. {
  1205. gpGlobals->rgPoisonStatus[j][wPlayerRole] =
  1206. gpGlobals->rgPoisonStatus[i][wPlayerRole];
  1207. j++;
  1208. }
  1209. }
  1210. while (j < MAX_POISONS)
  1211. {
  1212. gpGlobals->rgPoisonStatus[j][wPlayerRole].wPoisonID = 0;
  1213. gpGlobals->rgPoisonStatus[j][wPlayerRole].wPoisonScript = 0;
  1214. j++;
  1215. }
  1216. }
  1217. }
  1218. }
  1219. VOID
  1220. PAL_AddPoisonForPlayer(
  1221. WORD wPlayerRole,
  1222. WORD wPoisonID
  1223. )
  1224. /*++
  1225. Purpose:
  1226. Add the specified poison to the player.
  1227. Parameters:
  1228. [IN] wPlayerRole - the player role ID.
  1229. [IN] wPoisonID - the poison to be added.
  1230. Return value:
  1231. None.
  1232. --*/
  1233. {
  1234. int i, index;
  1235. WORD w;
  1236. for (index = 0; index <= gpGlobals->wMaxPartyMemberIndex; index++)
  1237. {
  1238. if (gpGlobals->rgParty[index].wPlayerRole == wPlayerRole)
  1239. {
  1240. break;
  1241. }
  1242. }
  1243. if (index > gpGlobals->wMaxPartyMemberIndex)
  1244. {
  1245. return; // don't go further
  1246. }
  1247. for (i = 0; i < MAX_POISONS; i++)
  1248. {
  1249. w = gpGlobals->rgPoisonStatus[i][index].wPoisonID;
  1250. if (w == 0)
  1251. {
  1252. break;
  1253. }
  1254. if (w == wPoisonID)
  1255. {
  1256. return; // already poisoned
  1257. }
  1258. }
  1259. if (i < MAX_POISONS)
  1260. {
  1261. gpGlobals->rgPoisonStatus[i][index].wPoisonID = wPoisonID;
  1262. gpGlobals->rgPoisonStatus[i][index].wPoisonScript =
  1263. gpGlobals->g.rgObject[wPoisonID].poison.wPlayerScript;
  1264. }
  1265. }
  1266. VOID
  1267. PAL_CurePoisonByKind(
  1268. WORD wPlayerRole,
  1269. WORD wPoisonID
  1270. )
  1271. /*++
  1272. Purpose:
  1273. Remove the specified poison from the player.
  1274. Parameters:
  1275. [IN] wPlayerRole - the player role ID.
  1276. [IN] wPoisonID - the poison to be removed.
  1277. Return value:
  1278. None.
  1279. --*/
  1280. {
  1281. int i, index;
  1282. for (index = 0; index <= gpGlobals->wMaxPartyMemberIndex; index++)
  1283. {
  1284. if (gpGlobals->rgParty[index].wPlayerRole == wPlayerRole)
  1285. {
  1286. break;
  1287. }
  1288. }
  1289. if (index > gpGlobals->wMaxPartyMemberIndex)
  1290. {
  1291. return; // don't go further
  1292. }
  1293. for (i = 0; i < MAX_POISONS; i++)
  1294. {
  1295. if (gpGlobals->rgPoisonStatus[i][index].wPoisonID == wPoisonID)
  1296. {
  1297. gpGlobals->rgPoisonStatus[i][index].wPoisonID = 0;
  1298. gpGlobals->rgPoisonStatus[i][index].wPoisonScript = 0;
  1299. }
  1300. }
  1301. }
  1302. VOID
  1303. PAL_CurePoisonByLevel(
  1304. WORD wPlayerRole,
  1305. WORD wMaxLevel
  1306. )
  1307. /*++
  1308. Purpose:
  1309. Remove the poisons which have a maximum level of wMaxLevel from the player.
  1310. Parameters:
  1311. [IN] wPlayerRole - the player role ID.
  1312. [IN] wMaxLevel - the maximum level of poisons to be removed.
  1313. Return value:
  1314. None.
  1315. --*/
  1316. {
  1317. int i, index;
  1318. WORD w;
  1319. for (index = 0; index <= gpGlobals->wMaxPartyMemberIndex; index++)
  1320. {
  1321. if (gpGlobals->rgParty[index].wPlayerRole == wPlayerRole)
  1322. {
  1323. break;
  1324. }
  1325. }
  1326. if (index > gpGlobals->wMaxPartyMemberIndex)
  1327. {
  1328. return; // don't go further
  1329. }
  1330. for (i = 0; i < MAX_POISONS; i++)
  1331. {
  1332. w = gpGlobals->rgPoisonStatus[i][index].wPoisonID;
  1333. if (gpGlobals->g.rgObject[w].poison.wPoisonLevel <= wMaxLevel)
  1334. {
  1335. gpGlobals->rgPoisonStatus[i][index].wPoisonID = 0;
  1336. gpGlobals->rgPoisonStatus[i][index].wPoisonScript = 0;
  1337. }
  1338. }
  1339. }
  1340. BOOL
  1341. PAL_IsPlayerPoisonedByLevel(
  1342. WORD wPlayerRole,
  1343. WORD wMinLevel
  1344. )
  1345. /*++
  1346. Purpose:
  1347. Check if the player is poisoned by poisons at a minimum level of wMinLevel.
  1348. Parameters:
  1349. [IN] wPlayerRole - the player role ID.
  1350. [IN] wMinLevel - the minimum level of poison.
  1351. Return value:
  1352. TRUE if the player is poisoned by poisons at a minimum level of wMinLevel;
  1353. FALSE if not.
  1354. --*/
  1355. {
  1356. int i, index;
  1357. WORD w;
  1358. for (index = 0; index <= gpGlobals->wMaxPartyMemberIndex; index++)
  1359. {
  1360. if (gpGlobals->rgParty[index].wPlayerRole == wPlayerRole)
  1361. {
  1362. break;
  1363. }
  1364. }
  1365. if (index > gpGlobals->wMaxPartyMemberIndex)
  1366. {
  1367. return FALSE; // don't go further
  1368. }
  1369. for (i = 0; i < MAX_POISONS; i++)
  1370. {
  1371. w = gpGlobals->rgPoisonStatus[i][index].wPoisonID;
  1372. w = gpGlobals->g.rgObject[w].poison.wPoisonLevel;
  1373. if (w >= 99)
  1374. {
  1375. //
  1376. // Ignore poisons which has a level of 99 (usually effect of equipment)
  1377. //
  1378. continue;
  1379. }
  1380. if (w >= wMinLevel)
  1381. {
  1382. return TRUE;
  1383. }
  1384. }
  1385. return FALSE;
  1386. }
  1387. BOOL
  1388. PAL_IsPlayerPoisonedByKind(
  1389. WORD wPlayerRole,
  1390. WORD wPoisonID
  1391. )
  1392. /*++
  1393. Purpose:
  1394. Check if the player is poisoned by the specified poison.
  1395. Parameters:
  1396. [IN] wPlayerRole - the player role ID.
  1397. [IN] wPoisonID - the poison to be checked.
  1398. Return value:
  1399. TRUE if player is poisoned by the specified poison;
  1400. FALSE if not.
  1401. --*/
  1402. {
  1403. int i, index;
  1404. for (index = 0; index <= gpGlobals->wMaxPartyMemberIndex; index++)
  1405. {
  1406. if (gpGlobals->rgParty[index].wPlayerRole == wPlayerRole)
  1407. {
  1408. break;
  1409. }
  1410. }
  1411. if (index > gpGlobals->wMaxPartyMemberIndex)
  1412. {
  1413. return FALSE; // don't go further
  1414. }
  1415. for (i = 0; i < MAX_POISONS; i++)
  1416. {
  1417. if (gpGlobals->rgPoisonStatus[i][index].wPoisonID == wPoisonID)
  1418. {
  1419. return TRUE;
  1420. }
  1421. }
  1422. return FALSE;
  1423. }
  1424. WORD
  1425. PAL_GetPlayerAttackStrength(
  1426. WORD wPlayerRole
  1427. )
  1428. /*++
  1429. Purpose:
  1430. Get the player's attack strength, count in the effect of equipments.
  1431. Parameters:
  1432. [IN] wPlayerRole - the player role ID.
  1433. Return value:
  1434. The total attack strength of the player.
  1435. --*/
  1436. {
  1437. WORD w;
  1438. int i;
  1439. w = gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole];
  1440. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1441. {
  1442. w += gpGlobals->rgEquipmentEffect[i].rgwAttackStrength[wPlayerRole];
  1443. }
  1444. return w;
  1445. }
  1446. WORD
  1447. PAL_GetPlayerMagicStrength(
  1448. WORD wPlayerRole
  1449. )
  1450. /*++
  1451. Purpose:
  1452. Get the player's magic strength, count in the effect of equipments.
  1453. Parameters:
  1454. [IN] wPlayerRole - the player role ID.
  1455. Return value:
  1456. The total magic strength of the player.
  1457. --*/
  1458. {
  1459. WORD w;
  1460. int i;
  1461. w = gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole];
  1462. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1463. {
  1464. w += gpGlobals->rgEquipmentEffect[i].rgwMagicStrength[wPlayerRole];
  1465. }
  1466. return w;
  1467. }
  1468. WORD
  1469. PAL_GetPlayerDefense(
  1470. WORD wPlayerRole
  1471. )
  1472. /*++
  1473. Purpose:
  1474. Get the player's defense value, count in the effect of equipments.
  1475. Parameters:
  1476. [IN] wPlayerRole - the player role ID.
  1477. Return value:
  1478. The total defense value of the player.
  1479. --*/
  1480. {
  1481. WORD w;
  1482. int i;
  1483. w = gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole];
  1484. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1485. {
  1486. w += gpGlobals->rgEquipmentEffect[i].rgwDefense[wPlayerRole];
  1487. }
  1488. return w;
  1489. }
  1490. WORD
  1491. PAL_GetPlayerDexterity(
  1492. WORD wPlayerRole
  1493. )
  1494. /*++
  1495. Purpose:
  1496. Get the player's dexterity, count in the effect of equipments.
  1497. Parameters:
  1498. [IN] wPlayerRole - the player role ID.
  1499. Return value:
  1500. The total dexterity of the player.
  1501. --*/
  1502. {
  1503. WORD w;
  1504. int i;
  1505. w = gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole];
  1506. #ifdef PAL_CLASSIC
  1507. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1508. #else
  1509. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS - 1; i++)
  1510. #endif
  1511. {
  1512. w += gpGlobals->rgEquipmentEffect[i].rgwDexterity[wPlayerRole];
  1513. }
  1514. return w;
  1515. }
  1516. WORD
  1517. PAL_GetPlayerFleeRate(
  1518. WORD wPlayerRole
  1519. )
  1520. /*++
  1521. Purpose:
  1522. Get the player's flee rate, count in the effect of equipments.
  1523. Parameters:
  1524. [IN] wPlayerRole - the player role ID.
  1525. Return value:
  1526. The total flee rate of the player.
  1527. --*/
  1528. {
  1529. WORD w;
  1530. int i;
  1531. w = gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole];
  1532. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1533. {
  1534. w += gpGlobals->rgEquipmentEffect[i].rgwFleeRate[wPlayerRole];
  1535. }
  1536. return w;
  1537. }
  1538. WORD
  1539. PAL_GetPlayerPoisonResistance(
  1540. WORD wPlayerRole
  1541. )
  1542. /*++
  1543. Purpose:
  1544. Get the player's resistance to poisons, count in the effect of equipments.
  1545. Parameters:
  1546. [IN] wPlayerRole - the player role ID.
  1547. Return value:
  1548. The total resistance to poisons of the player.
  1549. --*/
  1550. {
  1551. WORD w;
  1552. int i;
  1553. w = gpGlobals->g.PlayerRoles.rgwPoisonResistance[wPlayerRole];
  1554. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1555. {
  1556. w += gpGlobals->rgEquipmentEffect[i].rgwPoisonResistance[wPlayerRole];
  1557. }
  1558. if (w > 100)
  1559. {
  1560. w = 100;
  1561. }
  1562. return w;
  1563. }
  1564. WORD
  1565. PAL_GetPlayerElementalResistance(
  1566. WORD wPlayerRole,
  1567. INT iAttrib
  1568. )
  1569. /*++
  1570. Purpose:
  1571. Get the player's resistance to attributed magics, count in the effect
  1572. of equipments.
  1573. Parameters:
  1574. [IN] wPlayerRole - the player role ID.
  1575. [IN] iAttrib - the attribute of magics.
  1576. Return value:
  1577. The total resistance to the attributed magics of the player.
  1578. --*/
  1579. {
  1580. WORD w;
  1581. int i;
  1582. w = gpGlobals->g.PlayerRoles.rgwElementalResistance[iAttrib][wPlayerRole];
  1583. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1584. {
  1585. w += gpGlobals->rgEquipmentEffect[i].rgwElementalResistance[iAttrib][wPlayerRole];
  1586. }
  1587. if (w > 100)
  1588. {
  1589. w = 100;
  1590. }
  1591. return w;
  1592. }
  1593. WORD
  1594. PAL_GetPlayerBattleSprite(
  1595. WORD wPlayerRole
  1596. )
  1597. /*++
  1598. Purpose:
  1599. Get player's battle sprite.
  1600. Parameters:
  1601. [IN] wPlayerRole - the player role ID.
  1602. Return value:
  1603. Number of the player's battle sprite.
  1604. --*/
  1605. {
  1606. int i;
  1607. WORD w;
  1608. w = gpGlobals->g.PlayerRoles.rgwSpriteNumInBattle[wPlayerRole];
  1609. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1610. {
  1611. if (gpGlobals->rgEquipmentEffect[i].rgwSpriteNumInBattle[wPlayerRole] != 0)
  1612. {
  1613. w = gpGlobals->rgEquipmentEffect[i].rgwSpriteNumInBattle[wPlayerRole];
  1614. }
  1615. }
  1616. return w;
  1617. }
  1618. WORD
  1619. PAL_GetPlayerCooperativeMagic(
  1620. WORD wPlayerRole
  1621. )
  1622. /*++
  1623. Purpose:
  1624. Get player's cooperative magic.
  1625. Parameters:
  1626. [IN] wPlayerRole - the player role ID.
  1627. Return value:
  1628. Object ID of the player's cooperative magic.
  1629. --*/
  1630. {
  1631. int i;
  1632. WORD w;
  1633. w = gpGlobals->g.PlayerRoles.rgwCooperativeMagic[wPlayerRole];
  1634. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1635. {
  1636. if (gpGlobals->rgEquipmentEffect[i].rgwCooperativeMagic[wPlayerRole] != 0)
  1637. {
  1638. w = gpGlobals->rgEquipmentEffect[i].rgwCooperativeMagic[wPlayerRole];
  1639. }
  1640. }
  1641. return w;
  1642. }
  1643. BOOL
  1644. PAL_PlayerCanAttackAll(
  1645. WORD wPlayerRole
  1646. )
  1647. /*++
  1648. Purpose:
  1649. Check if the player can attack all of the enemies in one move.
  1650. Parameters:
  1651. [IN] wPlayerRole - the player role ID.
  1652. Return value:
  1653. TRUE if player can attack all of the enemies in one move, FALSE if not.
  1654. --*/
  1655. {
  1656. int i;
  1657. BOOL f;
  1658. f = FALSE;
  1659. for (i = 0; i <= MAX_PLAYER_EQUIPMENTS; i++)
  1660. {
  1661. if (gpGlobals->rgEquipmentEffect[i].rgwAttackAll[wPlayerRole] != 0)
  1662. {
  1663. f = TRUE;
  1664. break;
  1665. }
  1666. }
  1667. return f;
  1668. }
  1669. BOOL
  1670. PAL_AddMagic(
  1671. WORD wPlayerRole,
  1672. WORD wMagic
  1673. )
  1674. /*++
  1675. Purpose:
  1676. Add a magic to the player.
  1677. Parameters:
  1678. [IN] wPlayerRole - the player role ID.
  1679. [IN] wMagic - the object ID of the magic.
  1680. Return value:
  1681. TRUE if succeeded, FALSE if failed.
  1682. --*/
  1683. {
  1684. int i;
  1685. for (i = 0; i < MAX_PLAYER_MAGICS; i++)
  1686. {
  1687. if (gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] == wMagic)
  1688. {
  1689. //
  1690. // already have this magic
  1691. //
  1692. return FALSE;
  1693. }
  1694. }
  1695. for (i = 0; i < MAX_PLAYER_MAGICS; i++)
  1696. {
  1697. if (gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] == 0)
  1698. {
  1699. break;
  1700. }
  1701. }
  1702. if (i >= MAX_PLAYER_MAGICS)
  1703. {
  1704. //
  1705. // Not enough slots
  1706. //
  1707. return FALSE;
  1708. }
  1709. gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] = wMagic;
  1710. return TRUE;
  1711. }
  1712. VOID
  1713. PAL_RemoveMagic(
  1714. WORD wPlayerRole,
  1715. WORD wMagic
  1716. )
  1717. /*++
  1718. Purpose:
  1719. Remove a magic to the player.
  1720. Parameters:
  1721. [IN] wPlayerRole - the player role ID.
  1722. [IN] wMagic - the object ID of the magic.
  1723. Return value:
  1724. None.
  1725. --*/
  1726. {
  1727. int i;
  1728. for (i = 0; i < MAX_PLAYER_MAGICS; i++)
  1729. {
  1730. if (gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] == wMagic)
  1731. {
  1732. gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] = 0;
  1733. break;
  1734. }
  1735. }
  1736. }
  1737. VOID
  1738. PAL_SetPlayerStatus(
  1739. WORD wPlayerRole,
  1740. WORD wStatusID,
  1741. WORD wNumRound
  1742. )
  1743. /*++
  1744. Purpose:
  1745. Set one of the statuses for the player.
  1746. Parameters:
  1747. [IN] wPlayerRole - the player ID.
  1748. [IN] wStatusID - the status to be set.
  1749. [IN] wNumRound - the effective rounds of the status.
  1750. Return value:
  1751. None.
  1752. --*/
  1753. {
  1754. #ifndef PAL_CLASSIC
  1755. if (wStatusID == kStatusSlow &&
  1756. gpGlobals->rgPlayerStatus[wPlayerRole][kStatusHaste] > 0)
  1757. {
  1758. //
  1759. // Remove the haste status
  1760. //
  1761. PAL_RemovePlayerStatus(wPlayerRole, kStatusHaste);
  1762. return;
  1763. }
  1764. if (wStatusID == kStatusHaste &&
  1765. gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] > 0)
  1766. {
  1767. //
  1768. // Remove the slow status
  1769. //
  1770. PAL_RemovePlayerStatus(wPlayerRole, kStatusSlow);
  1771. return;
  1772. }
  1773. #endif
  1774. switch (wStatusID)
  1775. {
  1776. case kStatusConfused:
  1777. case kStatusSleep:
  1778. case kStatusSilence:
  1779. #ifdef PAL_CLASSIC
  1780. case kStatusParalyzed:
  1781. #else
  1782. case kStatusSlow:
  1783. #endif
  1784. //
  1785. // for "bad" statuses, don't set the status when we already have it
  1786. //
  1787. if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] != 0 &&
  1788. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] == 0)
  1789. {
  1790. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] = wNumRound;
  1791. }
  1792. break;
  1793. case kStatusPuppet:
  1794. //
  1795. // only allow dead players for "puppet" status
  1796. //
  1797. if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 &&
  1798. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] < wNumRound)
  1799. {
  1800. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] = wNumRound;
  1801. }
  1802. break;
  1803. case kStatusBravery:
  1804. case kStatusProtect:
  1805. case kStatusDualAttack:
  1806. case kStatusHaste:
  1807. //
  1808. // for "good" statuses, reset the status if the status to be set lasts longer
  1809. //
  1810. if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] != 0 &&
  1811. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] < wNumRound)
  1812. {
  1813. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] = wNumRound;
  1814. }
  1815. break;
  1816. default:
  1817. assert(FALSE);
  1818. break;
  1819. }
  1820. }
  1821. VOID
  1822. PAL_RemovePlayerStatus(
  1823. WORD wPlayerRole,
  1824. WORD wStatusID
  1825. )
  1826. /*++
  1827. Purpose:
  1828. Remove one of the status for player.
  1829. Parameters:
  1830. [IN] wPlayerRole - the player ID.
  1831. [IN] wStatusID - the status to be set.
  1832. Return value:
  1833. None.
  1834. --*/
  1835. {
  1836. //
  1837. // Don't remove effects of equipments
  1838. //
  1839. if (gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] <= 999)
  1840. {
  1841. gpGlobals->rgPlayerStatus[wPlayerRole][wStatusID] = 0;
  1842. }
  1843. }
  1844. VOID
  1845. PAL_ClearAllPlayerStatus(
  1846. VOID
  1847. )
  1848. /*++
  1849. Purpose:
  1850. Clear all player status.
  1851. Parameters:
  1852. None.
  1853. Return value:
  1854. None.
  1855. --*/
  1856. {
  1857. int i, j;
  1858. for (i = 0; i < MAX_PLAYER_ROLES; i++)
  1859. {
  1860. for (j = 0; j < kStatusAll; j++)
  1861. {
  1862. //
  1863. // Don't remove effects of equipments
  1864. //
  1865. if (gpGlobals->rgPlayerStatus[i][j] <= 999)
  1866. {
  1867. gpGlobals->rgPlayerStatus[i][j] = 0;
  1868. }
  1869. }
  1870. }
  1871. }
  1872. VOID
  1873. PAL_PlayerLevelUp(
  1874. WORD wPlayerRole,
  1875. WORD wNumLevel
  1876. )
  1877. /*++
  1878. Purpose:
  1879. Increase the player's level by wLevels.
  1880. Parameters:
  1881. [IN] wPlayerRole - player role ID.
  1882. [IN] wNumLevel - number of levels to be increased.
  1883. Return value:
  1884. None.
  1885. --*/
  1886. {
  1887. WORD i;
  1888. //
  1889. // Add the level
  1890. //
  1891. gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] += wNumLevel;
  1892. if (gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] > MAX_LEVELS)
  1893. {
  1894. gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole] = MAX_LEVELS;
  1895. }
  1896. for (i = 0; i < wNumLevel; i++)
  1897. {
  1898. //
  1899. // Increase player's stats
  1900. //
  1901. gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole] += 10 + RandomLong(0, 8);
  1902. gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole] += 8 + RandomLong(0, 6);
  1903. gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole] += 4 + RandomLong(0, 1);
  1904. gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole] += 4 + RandomLong(0, 1);
  1905. gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole] += 2 + RandomLong(0, 1);
  1906. gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole] += 2 + RandomLong(0, 1);
  1907. gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole] += 2;
  1908. }
  1909. #define STAT_LIMIT(t) { if ((t) > 999) (t) = 999; }
  1910. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole]);
  1911. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole]);
  1912. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwAttackStrength[wPlayerRole]);
  1913. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwMagicStrength[wPlayerRole]);
  1914. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDefense[wPlayerRole]);
  1915. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwDexterity[wPlayerRole]);
  1916. STAT_LIMIT(gpGlobals->g.PlayerRoles.rgwFleeRate[wPlayerRole]);
  1917. #undef STAT_LIMIT
  1918. //
  1919. // Reset experience points to zero
  1920. //
  1921. gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wExp = 0;
  1922. gpGlobals->Exp.rgPrimaryExp[wPlayerRole].wLevel =
  1923. gpGlobals->g.PlayerRoles.rgwLevel[wPlayerRole];
  1924. }