global.c 58 KB

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