global.c 59 KB

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