aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/resource
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/resource')
-rw-r--r--engines/kyra/resource/resource.cpp372
-rw-r--r--engines/kyra/resource/resource.h1165
-rw-r--r--engines/kyra/resource/resource_intern.cpp1351
-rw-r--r--engines/kyra/resource/resource_intern.h146
-rw-r--r--engines/kyra/resource/staticres.cpp2046
-rw-r--r--engines/kyra/resource/staticres_eob.cpp1379
-rw-r--r--engines/kyra/resource/staticres_lol.cpp857
-rw-r--r--engines/kyra/resource/staticres_rpg.cpp99
8 files changed, 7415 insertions, 0 deletions
diff --git a/engines/kyra/resource/resource.cpp b/engines/kyra/resource/resource.cpp
new file mode 100644
index 0000000000..e13e644372
--- /dev/null
+++ b/engines/kyra/resource/resource.cpp
@@ -0,0 +1,372 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/resource/resource.h"
+#include "kyra/resource/resource_intern.h"
+
+#include "common/config-manager.h"
+#include "common/fs.h"
+
+namespace Kyra {
+
+Resource::Resource(KyraEngine_v1 *vm) : _archiveCache(), _files(), _archiveFiles(), _protectedFiles(), _loaders(), _vm(vm) {
+ initializeLoaders();
+
+ // Initialize directories for playing from CD or with original
+ // directory structure
+ if (_vm->game() == GI_KYRA3)
+ SearchMan.addSubDirectoryMatching(Common::FSNode(ConfMan.get("path")), "malcolm");
+
+ _files.add("global_search", &Common::SearchManager::instance(), 3, false);
+ // compressed installer archives are added at level '2',
+ // but that's done in Resource::reset not here
+ _files.add("protected", &_protectedFiles, 1, false);
+ _files.add("archives", &_archiveFiles, 0, false);
+}
+
+Resource::~Resource() {
+ _loaders.clear();
+
+ for (ArchiveMap::iterator i = _archiveCache.begin(); i != _archiveCache.end(); ++i)
+ delete i->_value;
+ _archiveCache.clear();
+}
+
+bool Resource::reset() {
+ unloadAllPakFiles();
+
+ Common::FSNode dir(ConfMan.get("path"));
+
+ if (!dir.exists() || !dir.isDirectory())
+ error("invalid game path '%s'", dir.getPath().c_str());
+
+ if (_vm->game() == GI_KYRA1 || _vm->game() == GI_EOB1) {
+ // We only need kyra.dat for the demo.
+ if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
+ return true;
+
+ if (!_vm->gameFlags().isDemo && _vm->gameFlags().isTalkie) {
+ // List of files in the talkie version, which can never be unload.
+ static const char *const list[] = {
+ "ADL.PAK", "CHAPTER1.VRM", "COL.PAK", "FINALE.PAK", "INTRO1.PAK", "INTRO2.PAK",
+ "INTRO3.PAK", "INTRO4.PAK", "MISC.PAK", "SND.PAK", "STARTUP.PAK", "XMI.PAK",
+ "CAVE.APK", "DRAGON1.APK", "DRAGON2.APK", "LAGOON.APK", 0
+ };
+
+ loadProtectedFiles(list);
+ } else {
+ // We only search in the game path to avoid any invalid PAK or
+ // APK files from being picked up. This might happen, for example,
+ // when the user has an Android package file in the CWD.
+ Common::FSDirectory gameDir(dir);
+ Common::ArchiveMemberList files;
+
+ gameDir.listMatchingMembers(files, "*.PAK");
+ gameDir.listMatchingMembers(files, "*.APK");
+
+ for (Common::ArchiveMemberList::const_iterator i = files.begin(); i != files.end(); ++i) {
+ Common::String name = (*i)->getName();
+ name.toUppercase();
+
+ // No PAK file
+ if (name == "TWMUSIC.PAK" || name == "EYE.PAK")
+ continue;
+
+ // We need to only load the script archive for the language the user specified
+ if (name == ((_vm->gameFlags().lang == Common::EN_ANY) ? "JMC.PAK" : "EMC.PAK"))
+ continue;
+
+ Common::Archive *archive = loadArchive(name, *i);
+ if (archive)
+ _files.add(name, archive, 0, false);
+ else
+ error("Couldn't load PAK file '%s'", name.c_str());
+ }
+ }
+ } else if (_vm->game() == GI_KYRA2) {
+ if (_vm->gameFlags().useInstallerPackage)
+ _files.add("installer", loadInstallerArchive("WESTWOOD", "%03d", 6), 2, false);
+
+ // mouse pointer, fonts, etc. required for initialization
+ if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
+ loadPakFile("GENERAL.PAK");
+ } else {
+ loadPakFile("INTROGEN.PAK");
+ loadPakFile("OTHER.PAK");
+ }
+ } else if (_vm->game() == GI_KYRA3) {
+ if (_vm->gameFlags().useInstallerPackage) {
+ if (!loadPakFile("WESTWOOD.001"))
+ error("Couldn't load file: 'WESTWOOD.001'");
+ }
+
+ if (!loadFileList("FILEDATA.FDT"))
+ error("Couldn't load file: 'FILEDATA.FDT'");
+ } else if (_vm->game() == GI_LOL) {
+ if (_vm->gameFlags().useInstallerPackage)
+ _files.add("installer", loadInstallerArchive("WESTWOOD", "%d", 0), 2, false);
+
+ if (!_vm->gameFlags().isTalkie && !_vm->gameFlags().isDemo) {
+ static const char *const list[] = {
+ "GENERAL.PAK", 0
+ };
+
+ loadProtectedFiles(list);
+ }
+ } else if (_vm->game() != GI_EOB2) {
+ error("Unknown game id: %d", _vm->game());
+ return false; // for compilers that don't support NORETURN
+ }
+
+ return true;
+}
+
+bool Resource::loadPakFile(Common::String filename) {
+ filename.toUppercase();
+
+ Common::ArchiveMemberPtr file = _files.getMember(filename);
+ if (!file)
+ return false;
+
+ return loadPakFile(filename, file);
+}
+
+bool Resource::loadPakFile(Common::String name, Common::ArchiveMemberPtr file) {
+ name.toUppercase();
+
+ if (_archiveFiles.hasArchive(name) || _protectedFiles.hasArchive(name))
+ return true;
+
+ Common::Archive *archive = loadArchive(name, file);
+ if (!archive)
+ return false;
+
+ _archiveFiles.add(name, archive, 0, false);
+
+ return true;
+}
+
+bool Resource::loadFileList(const Common::String &filedata) {
+ Common::SeekableReadStream *f = createReadStream(filedata);
+
+ if (!f)
+ return false;
+
+ uint32 filenameOffset = 0;
+ while ((filenameOffset = f->readUint32LE()) != 0) {
+ uint32 offset = f->pos();
+ f->seek(filenameOffset, SEEK_SET);
+
+ uint8 buffer[13];
+ f->read(buffer, sizeof(buffer) - 1);
+ buffer[12] = 0;
+ f->seek(offset + 16, SEEK_SET);
+
+ Common::String filename = Common::String((char *)buffer);
+ filename.toUppercase();
+
+ if (filename.hasSuffix(".PAK")) {
+ if (!exists(filename.c_str()) && _vm->gameFlags().isDemo) {
+ // the demo version supplied with Kyra3 does not
+ // contain all pak files listed in filedata.fdt
+ // so we don't do anything here if they are non
+ // existent.
+ } else if (!loadPakFile(filename)) {
+ delete f;
+ error("couldn't load file '%s'", filename.c_str());
+ return false; // for compilers that don't support NORETURN
+ }
+ }
+ }
+
+ delete f;
+ return true;
+}
+
+bool Resource::loadFileList(const char *const *filelist, uint32 numFiles) {
+ if (!filelist)
+ return false;
+
+ while (numFiles--) {
+ if (!loadPakFile(filelist[numFiles])) {
+ error("couldn't load file '%s'", filelist[numFiles]);
+ return false; // for compilers that don't support NORETURN
+ }
+ }
+
+ return true;
+}
+
+bool Resource::loadProtectedFiles(const char *const *list) {
+ for (uint i = 0; list[i]; ++i) {
+ Common::ArchiveMemberPtr file = _files.getMember(list[i]);
+ if (!file)
+ error("Couldn't find PAK file '%s'", list[i]);
+
+ Common::Archive *archive = loadArchive(list[i], file);
+ if (archive)
+ _protectedFiles.add(list[i], archive, 0, false);
+ else
+ error("Couldn't load PAK file '%s'", list[i]);
+ }
+
+ return true;
+}
+
+void Resource::unloadPakFile(Common::String filename, bool remFromCache) {
+ filename.toUppercase();
+
+ // We do not remove files from '_protectedFiles' here, since
+ // those are protected against unloading.
+ if (_archiveFiles.hasArchive(filename)) {
+ _archiveFiles.remove(filename);
+ if (remFromCache) {
+ ArchiveMap::iterator iter = _archiveCache.find(filename);
+ if (iter != _archiveCache.end()) {
+ delete iter->_value;
+ _archiveCache.erase(filename);
+ }
+ }
+ }
+}
+
+bool Resource::isInPakList(Common::String filename) {
+ filename.toUppercase();
+ return (_archiveFiles.hasArchive(filename) || _protectedFiles.hasArchive(filename));
+}
+
+bool Resource::isInCacheList(Common::String name) {
+ name.toUppercase();
+ return (_archiveCache.find(name) != _archiveCache.end());
+}
+
+void Resource::unloadAllPakFiles() {
+ _archiveFiles.clear();
+ _protectedFiles.clear();
+}
+
+void Resource::listFiles(const Common::String &pattern, Common::ArchiveMemberList &list) {
+ _files.listMatchingMembers(list, pattern);
+}
+
+uint8 *Resource::fileData(const char *file, uint32 *size) {
+ Common::SeekableReadStream *stream = createReadStream(file);
+ if (!stream)
+ return 0;
+
+ uint32 bufferSize = stream->size();
+ uint8 *buffer = new uint8[bufferSize];
+ assert(buffer);
+ if (size)
+ *size = bufferSize;
+ stream->read(buffer, bufferSize);
+ delete stream;
+ return buffer;
+}
+
+bool Resource::exists(const char *file, bool errorOutOnFail) {
+ if (_files.hasFile(file))
+ return true;
+ else if (errorOutOnFail)
+ error("File '%s' can't be found", file);
+ return false;
+}
+
+uint32 Resource::getFileSize(const char *file) {
+ Common::SeekableReadStream *stream = createReadStream(file);
+ if (!stream)
+ return 0;
+
+ uint32 size = stream->size();
+ delete stream;
+ return size;
+}
+
+bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
+ Common::SeekableReadStream *stream = createReadStream(file);
+ if (!stream)
+ return false;
+
+ memset(buf, 0, maxSize);
+ stream->read(buf, ((int32)maxSize <= stream->size()) ? maxSize : stream->size());
+ delete stream;
+ return true;
+}
+
+Common::SeekableReadStream *Resource::createReadStream(const Common::String &file) {
+ return _files.createReadStreamForMember(file);
+}
+
+Common::Archive *Resource::loadArchive(const Common::String &name, Common::ArchiveMemberPtr member) {
+ ArchiveMap::iterator cachedArchive = _archiveCache.find(name);
+ if (cachedArchive != _archiveCache.end())
+ return cachedArchive->_value;
+
+ Common::SeekableReadStream *stream = member->createReadStream();
+
+ if (!stream)
+ return 0;
+
+ Common::Archive *archive = 0;
+ for (LoaderList::const_iterator i = _loaders.begin(); i != _loaders.end(); ++i) {
+ if ((*i)->checkFilename(name)) {
+ if ((*i)->isLoadable(name, *stream)) {
+ stream->seek(0, SEEK_SET);
+ archive = (*i)->load(member, *stream);
+ break;
+ } else {
+ stream->seek(0, SEEK_SET);
+ }
+ }
+ }
+
+ delete stream;
+
+ if (!archive)
+ return 0;
+
+ _archiveCache[name] = archive;
+ return archive;
+}
+
+Common::Archive *Resource::loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset) {
+ ArchiveMap::iterator cachedArchive = _archiveCache.find(file);
+ if (cachedArchive != _archiveCache.end())
+ return cachedArchive->_value;
+
+ Common::Archive *archive = InstallerLoader::load(this, file, ext, offset);
+ if (!archive)
+ return 0;
+
+ _archiveCache[file] = archive;
+ return archive;
+}
+
+#pragma mark -
+
+void Resource::initializeLoaders() {
+ _loaders.push_back(LoaderList::value_type(new ResLoaderPak()));
+ _loaders.push_back(LoaderList::value_type(new ResLoaderInsMalcolm()));
+ _loaders.push_back(LoaderList::value_type(new ResLoaderTlk()));
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/resource/resource.h b/engines/kyra/resource/resource.h
new file mode 100644
index 0000000000..077b4eab7a
--- /dev/null
+++ b/engines/kyra/resource/resource.h
@@ -0,0 +1,1165 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_RESOURCE_H
+#define KYRA_RESOURCE_H
+
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/file.h"
+#include "common/list.h"
+#include "common/hash-str.h"
+#include "common/hashmap.h"
+#include "common/stream.h"
+#include "common/ptr.h"
+#include "common/archive.h"
+
+#include "kyra/kyra_v1.h"
+#include "kyra/engine/darkmoon.h"
+#include "kyra/engine/lol.h"
+#include "kyra/engine/kyra_hof.h"
+
+namespace Kyra {
+
+class Resource;
+
+class ResArchiveLoader;
+
+class Resource {
+public:
+ Resource(KyraEngine_v1 *vm);
+ ~Resource();
+
+ bool reset();
+
+ bool loadPakFile(Common::String filename);
+ bool loadPakFile(Common::String name, Common::ArchiveMemberPtr file);
+
+ void unloadPakFile(Common::String filename, bool remFromCache = false);
+
+ bool isInPakList(Common::String filename);
+
+ bool isInCacheList(Common::String name);
+
+ bool loadFileList(const Common::String &filedata);
+ bool loadFileList(const char *const *filelist, uint32 numFiles);
+
+ // This unloads *all* pakfiles, even kyra.dat and protected ones.
+ // It does not remove files from cache though!
+ void unloadAllPakFiles();
+
+ void listFiles(const Common::String &pattern, Common::ArchiveMemberList &list);
+
+ bool exists(const char *file, bool errorOutOnFail=false);
+ uint32 getFileSize(const char *file);
+ uint8 *fileData(const char *file, uint32 *size);
+ Common::SeekableReadStream *createReadStream(const Common::String &file);
+
+ bool loadFileToBuf(const char *file, void *buf, uint32 maxSize);
+protected:
+ typedef Common::HashMap<Common::String, Common::Archive *, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> ArchiveMap;
+ ArchiveMap _archiveCache;
+
+ Common::SearchSet _files;
+ Common::SearchSet _archiveFiles;
+ Common::SearchSet _protectedFiles;
+
+ Common::Archive *loadArchive(const Common::String &name, Common::ArchiveMemberPtr member);
+ Common::Archive *loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset);
+
+ bool loadProtectedFiles(const char *const * list);
+
+ void initializeLoaders();
+
+ typedef Common::List<Common::SharedPtr<ResArchiveLoader> > LoaderList;
+ LoaderList _loaders;
+
+ KyraEngine_v1 *_vm;
+};
+
+enum KyraResources {
+ kLoadAll = -1,
+
+ // This list has to match orderwise (and thus value wise) the static data list of "devtools/create_kyradat/create_kyradat.h"!
+ k1ForestSeq = 1,
+ k1KallakWritingSeq,
+ k1KyrandiaLogoSeq,
+ k1KallakMalcolmSeq,
+ k1MalcolmTreeSeq,
+ k1WestwoodLogoSeq,
+
+ k1Demo1Seq,
+ k1Demo2Seq,
+ k1Demo3Seq,
+ k1Demo4Seq,
+
+ k1AmuleteAnimSeq,
+
+ k1OutroReunionSeq,
+
+ k1IntroCPSStrings,
+ k1IntroCOLStrings,
+ k1IntroWSAStrings,
+ k1IntroStrings,
+
+ k1OutroHomeString,
+
+ k1RoomFilenames,
+ k1RoomList,
+
+ k1CharacterImageFilenames,
+
+ k1ItemNames,
+ k1TakenStrings,
+ k1PlacedStrings,
+ k1DroppedStrings,
+ k1NoDropStrings,
+
+ k1PutDownString,
+ k1WaitAmuletString,
+ k1BlackJewelString,
+ k1PoisonGoneString,
+ k1HealingTipString,
+ k1WispJewelStrings,
+ k1MagicJewelStrings,
+
+ k1ThePoisonStrings,
+ k1FluteStrings,
+
+ k1FlaskFullString,
+ k1FullFlaskString,
+
+ k1VeryCleverString,
+ k1NewGameString,
+
+ k1DefaultShapes,
+ k1Healing1Shapes,
+ k1Healing2Shapes,
+ k1PoisonDeathShapes,
+ k1FluteShapes,
+ k1Winter1Shapes,
+ k1Winter2Shapes,
+ k1Winter3Shapes,
+ k1DrinkShapes,
+ k1WispShapes,
+ k1MagicAnimShapes,
+ k1BranStoneShapes,
+
+ k1SpecialPalette1,
+ k1SpecialPalette2,
+ k1SpecialPalette3,
+ k1SpecialPalette4,
+ k1SpecialPalette5,
+ k1SpecialPalette6,
+ k1SpecialPalette7,
+ k1SpecialPalette8,
+ k1SpecialPalette9,
+ k1SpecialPalette10,
+ k1SpecialPalette11,
+ k1SpecialPalette12,
+ k1SpecialPalette13,
+ k1SpecialPalette14,
+ k1SpecialPalette15,
+ k1SpecialPalette16,
+ k1SpecialPalette17,
+ k1SpecialPalette18,
+ k1SpecialPalette19,
+ k1SpecialPalette20,
+ k1SpecialPalette21,
+ k1SpecialPalette22,
+ k1SpecialPalette23,
+ k1SpecialPalette24,
+ k1SpecialPalette25,
+ k1SpecialPalette26,
+ k1SpecialPalette27,
+ k1SpecialPalette28,
+ k1SpecialPalette29,
+ k1SpecialPalette30,
+ k1SpecialPalette31,
+ k1SpecialPalette32,
+ k1SpecialPalette33,
+
+ k1GUIStrings,
+ k1ConfigStrings,
+
+ k1AudioTracks,
+ k1AudioTracksIntro,
+
+ k1CreditsStrings,
+
+ k1TownsMusicFadeTable,
+ k1TownsSFXwdTable,
+ k1TownsSFXbtTable,
+ k1TownsCDATable,
+
+ k1PC98StoryStrings,
+ k1PC98IntroSfx,
+
+ k1AmigaIntroSFXTable,
+ k1AmigaGameSFXTable,
+
+ k2SeqplayPakFiles,
+ k2SeqplayCredits,
+ k2SeqplayCreditsSpecial,
+ k2SeqplayStrings,
+ k2SeqplaySfxFiles,
+ k2SeqplayTlkFiles,
+ k2SeqplaySeqData,
+ k2SeqplayIntroTracks,
+ k2SeqplayFinaleTracks,
+ k2SeqplayIntroCDA,
+ k2SeqplayFinaleCDA,
+ k2SeqplayShapeAnimData,
+
+ k2IngamePakFiles,
+ k2IngameSfxFiles,
+ k2IngameSfxIndex,
+ k2IngameTracks,
+ k2IngameCDA,
+ k2IngameTalkObjIndex,
+ k2IngameTimJpStrings,
+ k2IngameShapeAnimData,
+ k2IngameTlkDemoStrings,
+
+ k3MainMenuStrings,
+ k3MusicFiles,
+ k3ScoreTable,
+ k3SfxFiles,
+ k3SfxMap,
+ k3ItemAnimData,
+ k3ItemMagicTable,
+ k3ItemStringMap,
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ kRpgCommonMoreStrings,
+ kRpgCommonDscShapeIndex,
+ kRpgCommonDscX,
+ kRpgCommonDscTileIndex,
+ kRpgCommonDscDoorShapeIndex,
+ kRpgCommonDscDimData1,
+ kRpgCommonDscDimData2,
+ kRpgCommonDscBlockMap,
+ kRpgCommonDscDimMap,
+ kRpgCommonDscDoorY2,
+ kRpgCommonDscDoorFrameY1,
+ kRpgCommonDscDoorFrameY2,
+ kRpgCommonDscDoorFrameIndex1,
+ kRpgCommonDscDoorFrameIndex2,
+ kRpgCommonDscDoorScaleOffs,
+ kRpgCommonDscBlockIndex,
+
+ kEoBBaseChargenStrings1,
+ kEoBBaseChargenStrings2,
+ kEoBBaseChargenStartLevels,
+ kEoBBaseChargenStatStrings,
+ kEoBBaseChargenRaceSexStrings,
+ kEoBBaseChargenClassStrings,
+ kEoBBaseChargenAlignmentStrings,
+ kEoBBaseChargenEnterGameStrings,
+ kEoBBaseChargenClassMinStats,
+ kEoBBaseChargenRaceMinStats,
+ kEoBBaseChargenRaceMaxStats,
+
+ kEoBBaseSaveThrowTable1,
+ kEoBBaseSaveThrowTable2,
+ kEoBBaseSaveThrowTable3,
+ kEoBBaseSaveThrowTable4,
+ kEoBBaseSaveThrwLvlIndex,
+ kEoBBaseSaveThrwModDiv,
+ kEoBBaseSaveThrwModExt,
+
+ kEoBBasePryDoorStrings,
+ kEoBBaseWarningStrings,
+
+ kEoBBaseItemSuffixStringsRings,
+ kEoBBaseItemSuffixStringsPotions,
+ kEoBBaseItemSuffixStringsWands,
+
+ kEoBBaseRipItemStrings,
+ kEoBBaseCursedString,
+ kEoBBaseEnchantedString,
+ kEoBBaseMagicObjectStrings,
+ kEoBBaseMagicObjectString5,
+ kEoBBasePatternSuffix,
+ kEoBBasePatternGrFix1,
+ kEoBBasePatternGrFix2,
+ kEoBBaseValidateArmorString,
+ kEoBBaseValidateCursedString,
+ kEoBBaseValidateNoDropString,
+ kEoBBasePotionStrings,
+ kEoBBaseWandStrings,
+ kEoBBaseItemMisuseStrings,
+
+ kEoBBaseTakenStrings,
+ kEoBBasePotionEffectStrings,
+
+ kEoBBaseYesNoStrings,
+ kEoBBaseNpcMaxStrings,
+ kEoBBaseOkStrings,
+ kEoBBaseNpcJoinStrings,
+ kEoBBaseCancelStrings,
+ kEoBBaseAbortStrings,
+
+ kEoBBaseMenuStringsMain,
+ kEoBBaseMenuStringsSaveLoad,
+ kEoBBaseMenuStringsOnOff,
+ kEoBBaseMenuStringsSpells,
+ kEoBBaseMenuStringsRest,
+ kEoBBaseMenuStringsDrop,
+ kEoBBaseMenuStringsExit,
+ kEoBBaseMenuStringsStarve,
+ kEoBBaseMenuStringsScribe,
+ kEoBBaseMenuStringsDrop2,
+ kEoBBaseMenuStringsHead,
+ kEoBBaseMenuStringsPoison,
+ kEoBBaseMenuStringsMgc,
+ kEoBBaseMenuStringsPrefs,
+ kEoBBaseMenuStringsRest2,
+ kEoBBaseMenuStringsRest3,
+ kEoBBaseMenuStringsRest4,
+ kEoBBaseMenuStringsDefeat,
+ kEoBBaseMenuStringsTransfer,
+ kEoBBaseMenuStringsSpec,
+ kEoBBaseMenuStringsSpellNo,
+ kEoBBaseMenuYesNoStrings,
+
+ kEoBBaseSpellLevelsMage,
+ kEoBBaseSpellLevelsCleric,
+ kEoBBaseNumSpellsCleric,
+ kEoBBaseNumSpellsWisAdj,
+ kEoBBaseNumSpellsPal,
+ kEoBBaseNumSpellsMage,
+
+ kEoBBaseCharGuiStringsHp,
+ kEoBBaseCharGuiStringsWp1,
+ kEoBBaseCharGuiStringsWp2,
+ kEoBBaseCharGuiStringsWr,
+ kEoBBaseCharGuiStringsSt1,
+ kEoBBaseCharGuiStringsSt2,
+ kEoBBaseCharGuiStringsIn,
+
+ kEoBBaseCharStatusStrings7,
+ kEoBBaseCharStatusStrings81,
+ kEoBBaseCharStatusStrings82,
+ kEoBBaseCharStatusStrings9,
+ kEoBBaseCharStatusStrings12,
+ kEoBBaseCharStatusStrings131,
+ kEoBBaseCharStatusStrings132,
+
+ kEoBBaseLevelGainStrings,
+ kEoBBaseExperienceTable0,
+ kEoBBaseExperienceTable1,
+ kEoBBaseExperienceTable2,
+ kEoBBaseExperienceTable3,
+ kEoBBaseExperienceTable4,
+
+ kEoBBaseClassModifierFlags,
+
+ kEoBBaseMonsterStepTable01,
+ kEoBBaseMonsterStepTable02,
+ kEoBBaseMonsterStepTable1,
+ kEoBBaseMonsterStepTable2,
+ kEoBBaseMonsterStepTable3,
+ kEoBBaseMonsterCloseAttPosTable1,
+ kEoBBaseMonsterCloseAttPosTable21,
+ kEoBBaseMonsterCloseAttPosTable22,
+ kEoBBaseMonsterCloseAttUnkTable,
+ kEoBBaseMonsterCloseAttChkTable1,
+ kEoBBaseMonsterCloseAttChkTable2,
+ kEoBBaseMonsterCloseAttDstTable1,
+ kEoBBaseMonsterCloseAttDstTable2,
+
+ kEoBBaseMonsterProximityTable,
+ kEoBBaseFindBlockMonstersTable,
+ kEoBBaseMonsterDirChangeTable,
+ kEoBBaseMonsterDistAttStrings,
+
+ kEoBBaseEncodeMonsterDefs,
+ kEoBBaseNpcPresets,
+
+ kEoBBaseWllFlagPreset,
+ kEoBBaseDscShapeCoords,
+
+ kEoBBaseDscDoorScaleMult1,
+ kEoBBaseDscDoorScaleMult2,
+ kEoBBaseDscDoorScaleMult3,
+ kEoBBaseDscDoorScaleMult4,
+ kEoBBaseDscDoorScaleMult5,
+ kEoBBaseDscDoorScaleMult6,
+ kEoBBaseDscDoorType5Offs,
+ kEoBBaseDscDoorXE,
+ kEoBBaseDscDoorY1,
+ kEoBBaseDscDoorY3,
+ kEoBBaseDscDoorY4,
+ kEoBBaseDscDoorY5,
+ kEoBBaseDscDoorY6,
+ kEoBBaseDscDoorY7,
+ kEoBBaseDscDoorCoordsExt,
+
+ kEoBBaseDscItemPosIndex,
+ kEoBBaseDscItemShpX,
+ kEoBBaseDscItemScaleIndex,
+ kEoBBaseDscItemTileIndex,
+ kEoBBaseDscItemShapeMap,
+
+ kEoBBaseDscMonsterFrmOffsTbl1,
+ kEoBBaseDscMonsterFrmOffsTbl2,
+
+ kEoBBaseInvSlotX,
+ kEoBBaseInvSlotY,
+ kEoBBaseSlotValidationFlags,
+
+ kEoBBaseProjectileWeaponTypes,
+ kEoBBaseWandTypes,
+
+ kEoBBaseDrawObjPosIndex,
+ kEoBBaseFlightObjFlipIndex,
+ kEoBBaseFlightObjShpMap,
+ kEoBBaseFlightObjSclIndex,
+
+ kEoBBaseDscTelptrShpCoords,
+
+ kEoBBasePortalSeqData,
+ kEoBBaseManDef,
+ kEoBBaseManWord,
+ kEoBBaseManPrompt,
+
+ kEoBBaseBookNumbers,
+ kEoBBaseMageSpellsList,
+ kEoBBaseClericSpellsList,
+ kEoBBaseSpellNames,
+ kEoBBaseMagicStrings1,
+ kEoBBaseMagicStrings2,
+ kEoBBaseMagicStrings3,
+ kEoBBaseMagicStrings4,
+ kEoBBaseMagicStrings6,
+ kEoBBaseMagicStrings7,
+ kEoBBaseMagicStrings8,
+
+ kEoBBaseExpObjectTlMode,
+ kEoBBaseExpObjectTblIndex,
+ kEoBBaseExpObjectShpStart,
+ kEoBBaseExpObjectTbl1,
+ kEoBBaseExpObjectTbl2,
+ kEoBBaseExpObjectTbl3,
+ kEoBBaseExpObjectY,
+
+ kEoBBaseSparkDefSteps,
+ kEoBBaseSparkDefSubSteps,
+ kEoBBaseSparkDefShift,
+ kEoBBaseSparkDefAdd,
+ kEoBBaseSparkDefX,
+ kEoBBaseSparkDefY,
+ kEoBBaseSparkOfFlags1,
+ kEoBBaseSparkOfFlags2,
+ kEoBBaseSparkOfShift,
+ kEoBBaseSparkOfX,
+ kEoBBaseSparkOfY,
+
+ kEoBBaseSpellProperties,
+ kEoBBaseMagicFlightProps,
+ kEoBBaseTurnUndeadEffect,
+ kEoBBaseBurningHandsDest,
+ kEoBBaseConeOfColdDest1,
+ kEoBBaseConeOfColdDest2,
+ kEoBBaseConeOfColdDest3,
+ kEoBBaseConeOfColdDest4,
+ kEoBBaseConeOfColdGfxTbl,
+
+ kEoB1MainMenuStrings,
+ kEoB1BonusStrings,
+
+ kEoB1IntroFilesOpening,
+ kEoB1IntroFilesTower,
+ kEoB1IntroFilesOrb,
+ kEoB1IntroFilesWdEntry,
+ kEoB1IntroFilesKing,
+ kEoB1IntroFilesHands,
+ kEoB1IntroFilesWdExit,
+ kEoB1IntroFilesTunnel,
+ kEoB1IntroOpeningFrmDelay,
+ kEoB1IntroWdEncodeX,
+ kEoB1IntroWdEncodeY,
+ kEoB1IntroWdEncodeWH,
+ kEoB1IntroWdDsX,
+ kEoB1IntroWdDsY,
+ kEoB1IntroTvlX1,
+ kEoB1IntroTvlY1,
+ kEoB1IntroTvlX2,
+ kEoB1IntroTvlY2,
+ kEoB1IntroTvlW,
+ kEoB1IntroTvlH,
+
+ kEoB1DoorShapeDefs,
+ kEoB1DoorSwitchShapeDefs,
+ kEoB1DoorSwitchCoords,
+ kEoB1MonsterProperties,
+
+ kEoB1EnemyMageSpellList,
+ kEoB1EnemyMageSfx,
+ kEoB1BeholderSpellList,
+ kEoB1BeholderSfx,
+ kEoB1TurnUndeadString,
+
+ kEoB1CgaMappingDefault,
+ kEoB1CgaMappingAlt,
+ kEoB1CgaMappingInv,
+ kEoB1CgaMappingItemsL,
+ kEoB1CgaMappingItemsS,
+ kEoB1CgaMappingThrown,
+ kEoB1CgaMappingIcons,
+ kEoB1CgaMappingDeco,
+ kEoB1CgaLevelMappingIndex,
+ kEoB1CgaMappingLevel0,
+ kEoB1CgaMappingLevel1,
+ kEoB1CgaMappingLevel2,
+ kEoB1CgaMappingLevel3,
+ kEoB1CgaMappingLevel4,
+
+ kEoB1NpcShpData,
+ kEoB1NpcSubShpIndex1,
+ kEoB1NpcSubShpIndex2,
+ kEoB1NpcSubShpY,
+ kEoB1Npc0Strings,
+ kEoB1Npc11Strings,
+ kEoB1Npc12Strings,
+ kEoB1Npc21Strings,
+ kEoB1Npc22Strings,
+ kEoB1Npc31Strings,
+ kEoB1Npc32Strings,
+ kEoB1Npc4Strings,
+ kEoB1Npc5Strings,
+ kEoB1Npc6Strings,
+ kEoB1Npc7Strings,
+
+ kEoB2MainMenuStrings,
+ kEoB2MainMenuUtilStrings,
+
+ kEoB2TransferPortraitFrames,
+ kEoB2TransferConvertTable,
+ kEoB2TransferItemTable,
+ kEoB2TransferExpTable,
+ kEoB2TransferStrings1,
+ kEoB2TransferStrings2,
+ kEoB2TransferLabels,
+
+ kEoB2IntroStrings,
+ kEoB2IntroCPSFiles,
+ kEoB2IntroAnimData00,
+ kEoB2IntroAnimData01,
+ kEoB2IntroAnimData02,
+ kEoB2IntroAnimData03,
+ kEoB2IntroAnimData04,
+ kEoB2IntroAnimData05,
+ kEoB2IntroAnimData06,
+ kEoB2IntroAnimData07,
+ kEoB2IntroAnimData08,
+ kEoB2IntroAnimData09,
+ kEoB2IntroAnimData10,
+ kEoB2IntroAnimData11,
+ kEoB2IntroAnimData12,
+ kEoB2IntroAnimData13,
+ kEoB2IntroAnimData14,
+ kEoB2IntroAnimData15,
+ kEoB2IntroAnimData16,
+ kEoB2IntroAnimData17,
+ kEoB2IntroAnimData18,
+ kEoB2IntroAnimData19,
+ kEoB2IntroAnimData20,
+ kEoB2IntroAnimData21,
+ kEoB2IntroAnimData22,
+ kEoB2IntroAnimData23,
+ kEoB2IntroAnimData24,
+ kEoB2IntroAnimData25,
+ kEoB2IntroAnimData26,
+ kEoB2IntroAnimData27,
+ kEoB2IntroAnimData28,
+ kEoB2IntroAnimData29,
+ kEoB2IntroAnimData30,
+ kEoB2IntroAnimData31,
+ kEoB2IntroAnimData32,
+ kEoB2IntroAnimData33,
+ kEoB2IntroAnimData34,
+ kEoB2IntroAnimData35,
+ kEoB2IntroAnimData36,
+ kEoB2IntroAnimData37,
+ kEoB2IntroAnimData38,
+ kEoB2IntroAnimData39,
+ kEoB2IntroAnimData40,
+ kEoB2IntroAnimData41,
+ kEoB2IntroAnimData42,
+ kEoB2IntroAnimData43,
+
+ kEoB2IntroShapes00,
+ kEoB2IntroShapes01,
+ kEoB2IntroShapes04,
+ kEoB2IntroShapes07,
+
+ kEoB2FinaleStrings,
+ kEoB2CreditsData,
+ kEoB2FinaleCPSFiles,
+ kEoB2FinaleAnimData00,
+ kEoB2FinaleAnimData01,
+ kEoB2FinaleAnimData02,
+ kEoB2FinaleAnimData03,
+ kEoB2FinaleAnimData04,
+ kEoB2FinaleAnimData05,
+ kEoB2FinaleAnimData06,
+ kEoB2FinaleAnimData07,
+ kEoB2FinaleAnimData08,
+ kEoB2FinaleAnimData09,
+ kEoB2FinaleAnimData10,
+ kEoB2FinaleAnimData11,
+ kEoB2FinaleAnimData12,
+ kEoB2FinaleAnimData13,
+ kEoB2FinaleAnimData14,
+ kEoB2FinaleAnimData15,
+ kEoB2FinaleAnimData16,
+ kEoB2FinaleAnimData17,
+ kEoB2FinaleAnimData18,
+ kEoB2FinaleAnimData19,
+ kEoB2FinaleAnimData20,
+ kEoB2FinaleShapes00,
+ kEoB2FinaleShapes03,
+ kEoB2FinaleShapes07,
+ kEoB2FinaleShapes09,
+ kEoB2FinaleShapes10,
+
+ kEoB2NpcShapeData,
+ kEoB2Npc1Strings,
+ kEoB2Npc2Strings,
+ kEoB2MonsterDustStrings,
+
+ kEoB2DreamSteps,
+ kEoB2KheldranStrings,
+ kEoB2HornStrings,
+ kEoB2HornSounds,
+
+ kEoB2WallOfForceDsX,
+ kEoB2WallOfForceDsY,
+ kEoB2WallOfForceNumW,
+ kEoB2WallOfForceNumH,
+ kEoB2WallOfForceShpId,
+
+ kEoB2IntroCpsDataStreet1,
+ kEoB2IntroCpsDataStreet2,
+ kEoB2IntroCpsDataDoorway1,
+ kEoB2IntroCpsDataDoorway2,
+ kEoB2IntroCpsDataWestwood,
+ kEoB2IntroCpsDataWinding,
+ kEoB2IntroCpsDataKhelban2,
+ kEoB2IntroCpsDataKhelban1,
+ kEoB2IntroCpsDataKhelban3,
+ kEoB2IntroCpsDataKhelban4,
+ kEoB2IntroCpsDataCoin,
+ kEoB2IntroCpsDataKhelban5,
+ kEoB2IntroCpsDataKhelban6,
+
+ kEoB2FinaleCpsDataDragon1,
+ kEoB2FinaleCpsDataDragon2,
+ kEoB2FinaleCpsDataHurry1,
+ kEoB2FinaleCpsDataHurry2,
+ kEoB2FinaleCpsDataDestroy0,
+ kEoB2FinaleCpsDataDestroy1,
+ kEoB2FinaleCpsDataDestroy2,
+ kEoB2FinaleCpsDataMagic,
+ kEoB2FinaleCpsDataDestroy3,
+ kEoB2FinaleCpsDataCredits2,
+ kEoB2FinaleCpsDataCredits3,
+ kEoB2FinaleCpsDataHeroes,
+ kEoB2FinaleCpsDataThanks,
+
+ kEoB2ItemIconShapeData00,
+ kEoB2ItemIconShapeData01,
+ kEoB2ItemIconShapeData02,
+ kEoB2ItemIconShapeData03,
+ kEoB2ItemIconShapeData04,
+ kEoB2ItemIconShapeData05,
+ kEoB2ItemIconShapeData06,
+ kEoB2ItemIconShapeData07,
+ kEoB2ItemIconShapeData08,
+ kEoB2ItemIconShapeData09,
+ kEoB2ItemIconShapeData10,
+ kEoB2ItemIconShapeData11,
+ kEoB2ItemIconShapeData12,
+ kEoB2ItemIconShapeData13,
+ kEoB2ItemIconShapeData14,
+ kEoB2ItemIconShapeData15,
+ kEoB2ItemIconShapeData16,
+ kEoB2ItemIconShapeData17,
+ kEoB2ItemIconShapeData18,
+ kEoB2ItemIconShapeData19,
+ kEoB2ItemIconShapeData20,
+ kEoB2ItemIconShapeData21,
+ kEoB2ItemIconShapeData22,
+ kEoB2ItemIconShapeData23,
+ kEoB2ItemIconShapeData24,
+ kEoB2ItemIconShapeData25,
+ kEoB2ItemIconShapeData26,
+ kEoB2ItemIconShapeData27,
+ kEoB2ItemIconShapeData28,
+ kEoB2ItemIconShapeData29,
+ kEoB2ItemIconShapeData30,
+ kEoB2ItemIconShapeData31,
+ kEoB2ItemIconShapeData32,
+ kEoB2ItemIconShapeData33,
+ kEoB2ItemIconShapeData34,
+ kEoB2ItemIconShapeData35,
+ kEoB2ItemIconShapeData36,
+ kEoB2ItemIconShapeData37,
+ kEoB2ItemIconShapeData38,
+ kEoB2ItemIconShapeData39,
+ kEoB2ItemIconShapeData40,
+ kEoB2ItemIconShapeData41,
+ kEoB2ItemIconShapeData42,
+ kEoB2ItemIconShapeData43,
+ kEoB2ItemIconShapeData44,
+ kEoB2ItemIconShapeData45,
+ kEoB2ItemIconShapeData46,
+ kEoB2ItemIconShapeData47,
+ kEoB2ItemIconShapeData48,
+ kEoB2ItemIconShapeData49,
+ kEoB2ItemIconShapeData50,
+ kEoB2ItemIconShapeData51,
+ kEoB2ItemIconShapeData52,
+ kEoB2ItemIconShapeData53,
+ kEoB2ItemIconShapeData54,
+ kEoB2ItemIconShapeData55,
+ kEoB2ItemIconShapeData56,
+ kEoB2ItemIconShapeData57,
+ kEoB2ItemIconShapeData58,
+ kEoB2ItemIconShapeData59,
+ kEoB2ItemIconShapeData60,
+ kEoB2ItemIconShapeData61,
+ kEoB2ItemIconShapeData62,
+ kEoB2ItemIconShapeData63,
+ kEoB2ItemIconShapeData64,
+ kEoB2ItemIconShapeData65,
+ kEoB2ItemIconShapeData66,
+ kEoB2ItemIconShapeData67,
+ kEoB2ItemIconShapeData68,
+ kEoB2ItemIconShapeData69,
+ kEoB2ItemIconShapeData70,
+ kEoB2ItemIconShapeData71,
+ kEoB2ItemIconShapeData72,
+ kEoB2ItemIconShapeData73,
+ kEoB2ItemIconShapeData74,
+ kEoB2ItemIconShapeData75,
+ kEoB2ItemIconShapeData76,
+ kEoB2ItemIconShapeData77,
+ kEoB2ItemIconShapeData78,
+ kEoB2ItemIconShapeData79,
+ kEoB2ItemIconShapeData80,
+ kEoB2ItemIconShapeData81,
+ kEoB2ItemIconShapeData82,
+ kEoB2ItemIconShapeData83,
+ kEoB2ItemIconShapeData84,
+ kEoB2ItemIconShapeData85,
+ kEoB2ItemIconShapeData86,
+ kEoB2ItemIconShapeData87,
+ kEoB2ItemIconShapeData88,
+ kEoB2ItemIconShapeData89,
+ kEoB2ItemIconShapeData90,
+ kEoB2ItemIconShapeData91,
+ kEoB2ItemIconShapeData92,
+ kEoB2ItemIconShapeData93,
+ kEoB2ItemIconShapeData94,
+ kEoB2ItemIconShapeData95,
+ kEoB2ItemIconShapeData96,
+ kEoB2ItemIconShapeData97,
+ kEoB2ItemIconShapeData98,
+ kEoB2ItemIconShapeData99,
+ kEoB2ItemIconShapeData100,
+ kEoB2ItemIconShapeData101,
+ kEoB2ItemIconShapeData102,
+ kEoB2ItemIconShapeData103,
+ kEoB2ItemIconShapeData104,
+ kEoB2ItemIconShapeData105,
+ kEoB2ItemIconShapeData106,
+ kEoB2ItemIconShapeData107,
+ kEoB2ItemIconShapeData108,
+ kEoB2ItemIconShapeData109,
+ kEoB2ItemIconShapeData110,
+ kEoB2ItemIconShapeData111,
+
+ kEoB2LargeItemsShapeData00,
+ kEoB2LargeItemsShapeData01,
+ kEoB2LargeItemsShapeData02,
+ kEoB2LargeItemsShapeData03,
+ kEoB2LargeItemsShapeData04,
+ kEoB2LargeItemsShapeData05,
+ kEoB2LargeItemsShapeData06,
+ kEoB2LargeItemsShapeData07,
+ kEoB2LargeItemsShapeData08,
+ kEoB2LargeItemsShapeData09,
+ kEoB2LargeItemsShapeData10,
+
+ kEoB2SmallItemsShapeData00,
+ kEoB2SmallItemsShapeData01,
+ kEoB2SmallItemsShapeData02,
+ kEoB2SmallItemsShapeData03,
+ kEoB2SmallItemsShapeData04,
+ kEoB2SmallItemsShapeData05,
+ kEoB2SmallItemsShapeData06,
+ kEoB2SmallItemsShapeData07,
+ kEoB2SmallItemsShapeData08,
+ kEoB2SmallItemsShapeData09,
+ kEoB2SmallItemsShapeData10,
+ kEoB2SmallItemsShapeData11,
+ kEoB2SmallItemsShapeData12,
+ kEoB2SmallItemsShapeData13,
+ kEoB2SmallItemsShapeData14,
+ kEoB2SmallItemsShapeData15,
+ kEoB2SmallItemsShapeData16,
+ kEoB2SmallItemsShapeData17,
+ kEoB2SmallItemsShapeData18,
+ kEoB2SmallItemsShapeData19,
+ kEoB2SmallItemsShapeData20,
+ kEoB2SmallItemsShapeData21,
+ kEoB2SmallItemsShapeData22,
+ kEoB2SmallItemsShapeData23,
+ kEoB2SmallItemsShapeData24,
+ kEoB2SmallItemsShapeData25,
+
+ kEoB2ThrownShapeData00,
+ kEoB2ThrownShapeData01,
+ kEoB2ThrownShapeData02,
+ kEoB2ThrownShapeData03,
+ kEoB2ThrownShapeData04,
+ kEoB2ThrownShapeData05,
+ kEoB2ThrownShapeData06,
+ kEoB2ThrownShapeData07,
+ kEoB2ThrownShapeData08,
+
+ kEoB2SpellShapeData00,
+ kEoB2SpellShapeData01,
+ kEoB2SpellShapeData02,
+ kEoB2SpellShapeData03,
+
+ kEoB2TeleporterShapeData00,
+ kEoB2TeleporterShapeData01,
+ kEoB2TeleporterShapeData02,
+ kEoB2TeleporterShapeData03,
+ kEoB2TeleporterShapeData04,
+ kEoB2TeleporterShapeData05,
+
+ kEoB2LightningColumnShapeData,
+ kEoB2DeadCharShapeData,
+ kEoB2DisabledCharGridShapeData,
+ kEoB2WeaponSlotGridShapeData,
+ kEoB2SmallGridShapeData,
+ kEoB2WideGridShapeData,
+ kEoB2RedSplatShapeData,
+ kEoB2GreenSplatShapeData,
+
+ kEoB2FirebeamShapeData00,
+ kEoB2FirebeamShapeData01,
+ kEoB2FirebeamShapeData02,
+
+ kEoB2SparkShapeData00,
+ kEoB2SparkShapeData01,
+ kEoB2SparkShapeData02,
+
+ kEoB2CompassShapeData00,
+ kEoB2CompassShapeData01,
+ kEoB2CompassShapeData02,
+ kEoB2CompassShapeData03,
+ kEoB2CompassShapeData04,
+ kEoB2CompassShapeData05,
+ kEoB2CompassShapeData06,
+ kEoB2CompassShapeData07,
+ kEoB2CompassShapeData08,
+ kEoB2CompassShapeData09,
+ kEoB2CompassShapeData10,
+ kEoB2CompassShapeData11,
+
+ kEoB2WallOfForceShapeData00,
+ kEoB2WallOfForceShapeData01,
+ kEoB2WallOfForceShapeData02,
+ kEoB2WallOfForceShapeData03,
+ kEoB2WallOfForceShapeData04,
+ kEoB2WallOfForceShapeData05,
+
+ kEoB2UtilMenuStrings,
+ kEoB2Config2431Strings,
+ kEoB2KatakanaLines,
+ kEoB2KanaSelectStrings,
+ kEoB2FontDmpSearchTbl,
+ kEoB2Ascii2SjisTables,
+ kEoB2Ascii2SjisTables2,
+ kEoB2SaveNamePatterns,
+ kEoB2PcmSoundEffectsIngame,
+ kEoB2PcmSoundEffectsIntro,
+ kEoB2PcmSoundEffectsFinale,
+
+ kLoLIngamePakFiles,
+ kLoLCharacterDefs,
+ kLoLIngameSfxFiles,
+ kLoLIngameSfxIndex,
+ kLoLMusicTrackMap,
+ kLoLIngameGMSfxIndex,
+ kLoLIngameMT32SfxIndex,
+ kLoLIngamePcSpkSfxIndex,
+ kLoLSpellProperties,
+ kLoLGameShapeMap,
+ kLoLSceneItemOffs,
+ kLoLCharInvIndex,
+ kLoLCharInvDefs,
+ kLoLCharDefsMan,
+ kLoLCharDefsWoman,
+ kLoLCharDefsKieran,
+ kLoLCharDefsAkshel,
+ kLoLExpRequirements,
+ kLoLMonsterModifiers1,
+ kLoLMonsterModifiers2,
+ kLoLMonsterModifiers3,
+ kLoLMonsterModifiers4,
+ kLoLMonsterShiftOffsets,
+ kLoLMonsterDirFlags,
+ kLoLMonsterScaleY,
+ kLoLMonsterScaleX,
+ kLoLMonsterScaleWH,
+ kLoLFlyingObjectShp,
+ kLoLInventoryDesc,
+
+ kLoLLevelShpList,
+ kLoLLevelDatList,
+ kLoLCompassDefs,
+ kLoLItemPrices,
+ kLoLStashSetup,
+
+ kLoLDscWalls,
+ kLoLDscOvlMap,
+ kLoLDscScaleWidthData,
+ kLoLDscScaleHeightData,
+ kLoLBaseDscY,
+
+ kLoLDscDoorScale,
+ kLoLDscDoor4,
+ kLoLDscDoorX,
+ kLoLDscDoorY,
+ kLoLDscOvlIndex,
+
+ kLoLScrollXTop,
+ kLoLScrollYTop,
+ kLoLScrollXBottom,
+ kLoLScrollYBottom,
+
+ kLoLButtonDefs,
+ kLoLButtonList1,
+ kLoLButtonList2,
+ kLoLButtonList3,
+ kLoLButtonList4,
+ kLoLButtonList5,
+ kLoLButtonList6,
+ kLoLButtonList7,
+ kLoLButtonList8,
+
+ kLoLLegendData,
+ kLoLMapCursorOvl,
+ kLoLMapStringId,
+
+ kLoLSpellbookAnim,
+ kLoLSpellbookCoords,
+ kLoLHealShapeFrames,
+ kLoLLightningDefs,
+ kLoLFireballCoords,
+
+ kLoLCredits,
+
+ kLoLHistory,
+#endif // ENABLE_EOB || ENABLE_LOL
+
+ kMaxResIDs
+};
+
+struct Shape;
+struct Room;
+struct AmigaSfxTable;
+struct HoFSeqData;
+struct HoFSeqItemAnimData;
+
+class StaticResource {
+public:
+ static const Common::String staticDataFilename() { return "KYRA.DAT"; }
+
+ StaticResource(KyraEngine_v1 *vm) : _vm(vm), _resList(), _fileLoader(0), _dataTable() {}
+ ~StaticResource() { deinit(); }
+
+ bool loadStaticResourceFile();
+
+ bool init();
+ void deinit();
+
+ const char *const *loadStrings(int id, int &strings);
+ const uint8 *loadRawData(int id, int &size);
+ const Shape *loadShapeTable(int id, int &entries);
+ const AmigaSfxTable *loadAmigaSfxTable(int id, int &entries);
+ const Room *loadRoomTable(int id, int &entries);
+ const HoFSeqData *loadHoFSequenceData(int id, int &entries);
+ const HoFSeqItemAnimData *loadHoFSeqItemAnimData(int id, int &entries);
+ const ItemAnimDefinition *loadItemAnimDefinition(int id, int &entries);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ const uint16 *loadRawDataBe16(int id, int &entries);
+ const uint32 *loadRawDataBe32(int id, int &entries);
+#endif // (ENABLE_EOB || ENABLE_LOL)
+#ifdef ENABLE_LOL
+ const LoLCharacter *loadCharData(int id, int &entries);
+ const SpellProperty *loadSpellData(int id, int &entries);
+ const CompassDef *loadCompassData(int id, int &entries);
+ const FlyingObjectShape *loadFlyingObjectData(int id, int &entries);
+ const LoLButtonDef *loadButtonDefs(int id, int &entries);
+#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ const DarkMoonAnimCommand *loadEoB2SeqData(int id, int &entries);
+ const DarkMoonShapeDef *loadEoB2ShapeData(int id, int &entries);
+ const EoBCharacter *loadEoBNpcData(int id, int &entries);
+#endif // ENABLE_EOB
+
+ // use '-1' to prefetch/unload all ids
+ // prefetchId retruns false if only on of the resources
+ // can't be loaded and it breaks then the first res
+ // can't be loaded
+ bool prefetchId(int id);
+ void unloadId(int id);
+private:
+ bool tryKyraDatLoad();
+
+ KyraEngine_v1 *_vm;
+
+ struct FileType;
+
+ bool checkResList(int id, int &type, const void *&ptr, int &size);
+ const FileType *getFiletype(int type);
+ const void *getData(int id, int requesttype, int &size);
+
+ bool loadDummy(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadStringTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadRawData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadShapeTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadAmigaSfxTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadRoomTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadHoFSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadHoFSeqItemAnimData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadItemAnimDefinition(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ bool loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#endif // (ENABLE_LOL || ENABLE_EOB)
+#ifdef ENABLE_LOL
+ bool loadCharData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadSpellData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadCompassData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadFlyingObjectData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadButtonDefs(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ bool loadEoB2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadEoB2ShapeData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadEoBNpcData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#endif // ENABLE_EOB
+
+ void freeDummy(void *&ptr, int &size);
+ void freeRawData(void *&ptr, int &size);
+ void freeStringTable(void *&ptr, int &size);
+ void freeShapeTable(void *&ptr, int &size);
+ void freeAmigaSfxTable(void *&ptr, int &size);
+ void freeRoomTable(void *&ptr, int &size);
+ void freeHoFSequenceData(void *&ptr, int &size);
+ void freeHoFSeqItemAnimData(void *&ptr, int &size);
+ void freeItemAnimDefinition(void *&ptr, int &size);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ void freeRawDataBe16(void *&ptr, int &size);
+ void freeRawDataBe32(void *&ptr, int &size);
+#endif // (ENABLE_EOB || ENABLE_LOL)
+#ifdef ENABLE_LOL
+ void freeCharData(void *&ptr, int &size);
+ void freeSpellData(void *&ptr, int &size);
+ void freeCompassData(void *&ptr, int &size);
+ void freeFlyingObjectData(void *&ptr, int &size);
+ void freeButtonDefs(void *&ptr, int &size);
+#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ void freeEoB2SeqData(void *&ptr, int &size);
+ void freeEoB2ShapeData(void *&ptr, int &size);
+ void freeEoBNpcData(void *&ptr, int &size);
+#endif // ENABLE_EOB
+
+ enum ResTypes {
+ kStringList = 0,
+ kRawData = 1,
+ kRoomList = 2,
+ kShapeList = 3,
+ kAmigaSfxTable = 4,
+
+ k2SeqData = 5,
+ k2SeqItemAnimData = 6,
+ k2ItemAnimDefinition = 7,
+
+ kLoLCharData = 8,
+ kLoLSpellData = 9,
+ kLoLCompassData = 10,
+ kLoLFlightShpData = 11,
+ kLoLButtonData = 12,
+ kRawDataBe16 = 13,
+ kRawDataBe32 = 14,
+
+ kEoB2SequenceData = 15,
+ kEoB2ShapeData = 16,
+ kEoBNpcData = 17
+ };
+
+ struct FileType {
+ int type;
+ typedef bool (StaticResource::*LoadFunc)(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ typedef void (StaticResource::*FreeFunc)(void *&ptr, int &size);
+
+ LoadFunc load;
+ FreeFunc free;
+ };
+
+ struct ResData {
+ int id;
+ int type;
+ int size;
+ void *data;
+ };
+
+ Common::List<ResData> _resList;
+
+ const FileType *_fileLoader;
+
+ struct DataDescriptor {
+ DataDescriptor() : filename(0), type(0) {}
+ DataDescriptor(uint32 f, uint8 t) : filename(f), type(t) {}
+
+ uint32 filename;
+ uint8 type;
+ };
+ typedef Common::HashMap<uint16, DataDescriptor> DataMap;
+ DataMap _dataTable;
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/resource/resource_intern.cpp b/engines/kyra/resource/resource_intern.cpp
new file mode 100644
index 0000000000..c32de44bc2
--- /dev/null
+++ b/engines/kyra/resource/resource_intern.cpp
@@ -0,0 +1,1351 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/resource/resource_intern.h"
+#include "kyra/resource/resource.h"
+
+#include "common/endian.h"
+#include "common/memstream.h"
+#include "common/substream.h"
+
+namespace Kyra {
+
+// Implementation of various Archive subclasses
+
+// -> PlainArchive implementation
+
+PlainArchive::PlainArchive(Common::ArchiveMemberPtr file)
+ : _file(file), _files() {
+}
+
+bool PlainArchive::hasFile(const Common::String &name) const {
+ return (_files.find(name) != _files.end());
+}
+
+int PlainArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int count = 0;
+
+ for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
+ ++count;
+ }
+
+ return count;
+}
+
+const Common::ArchiveMemberPtr PlainArchive::getMember(const Common::String &name) const {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *PlainArchive::createReadStreamForMember(const Common::String &name) const {
+ FileMap::const_iterator fDesc = _files.find(name);
+ if (fDesc == _files.end())
+ return 0;
+
+ Common::SeekableReadStream *parent = _file->createReadStream();
+ if (!parent)
+ return 0;
+
+ return new Common::SeekableSubReadStream(parent, fDesc->_value.offset, fDesc->_value.offset + fDesc->_value.size, DisposeAfterUse::YES);
+}
+
+void PlainArchive::addFileEntry(const Common::String &name, const Entry entry) {
+ _files[name] = entry;
+}
+
+PlainArchive::Entry PlainArchive::getFileEntry(const Common::String &name) const {
+ FileMap::const_iterator fDesc = _files.find(name);
+ if (fDesc == _files.end())
+ return Entry();
+ return fDesc->_value;
+}
+
+// -> TlkArchive implementation
+
+TlkArchive::TlkArchive(Common::ArchiveMemberPtr file, uint16 entryCount, const uint32 *fileEntries)
+ : _file(file), _entryCount(entryCount), _fileEntries(fileEntries) {
+}
+
+TlkArchive::~TlkArchive() {
+ delete[] _fileEntries;
+}
+
+bool TlkArchive::hasFile(const Common::String &name) const {
+ return (findFile(name) != 0);
+}
+
+int TlkArchive::listMembers(Common::ArchiveMemberList &list) const {
+ uint count = 0;
+
+ for (; count < _entryCount; ++count) {
+ const Common::String name = Common::String::format("%08u.AUD", _fileEntries[count * 2 + 0]);
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(name, this)));
+ }
+
+ return count;
+}
+
+const Common::ArchiveMemberPtr TlkArchive::getMember(const Common::String &name) const {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *TlkArchive::createReadStreamForMember(const Common::String &name) const {
+ const uint32 *fileDesc = findFile(name);
+ if (!fileDesc)
+ return 0;
+
+ Common::SeekableReadStream *parent = _file->createReadStream();
+ if (!parent)
+ return 0;
+
+ parent->seek(fileDesc[1], SEEK_SET);
+ const uint32 size = parent->readUint32LE();
+ const uint32 fileStart = fileDesc[1] + 4;
+
+ return new Common::SeekableSubReadStream(parent, fileStart, fileStart + size, DisposeAfterUse::YES);
+}
+
+const uint32 *TlkArchive::findFile(const Common::String &name) const {
+ Common::String uppercaseName = name;
+ uppercaseName.toUppercase();
+
+ if (!uppercaseName.hasSuffix(".AUD"))
+ return 0;
+
+ uint32 id;
+ if (sscanf(uppercaseName.c_str(), "%08u.AUD", &id) != 1)
+ return 0;
+
+ // Binary search for the file entry
+ int leftIndex = 0;
+ int rightIndex = _entryCount - 1;
+
+ while (leftIndex <= rightIndex) {
+ int mid = (leftIndex + rightIndex) / 2;
+
+ const uint32 key = _fileEntries[mid * 2];
+ if (key == id) {
+ // Found
+ return &_fileEntries[mid * 2];
+ } else if (key > id) {
+ // Take the left sub-tree
+ rightIndex = mid - 1;
+ } else {
+ // Take the right sub-tree
+ leftIndex = mid + 1;
+ }
+ }
+
+ return 0;
+}
+
+// -> CachedArchive implementation
+
+CachedArchive::CachedArchive(const FileInputList &files)
+ : _files() {
+ for (FileInputList::const_iterator i = files.begin(); i != files.end(); ++i) {
+ Entry entry;
+
+ entry.data = i->data;
+ entry.size = i->size;
+
+ Common::String name = i->name;
+ name.toLowercase();
+ _files[name] = entry;
+ }
+}
+
+CachedArchive::~CachedArchive() {
+ for (FileMap::iterator i = _files.begin(); i != _files.end(); ++i)
+ delete[] i->_value.data;
+ _files.clear();
+}
+
+bool CachedArchive::hasFile(const Common::String &name) const {
+ return (_files.find(name) != _files.end());
+}
+
+int CachedArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int count = 0;
+
+ for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
+ ++count;
+ }
+
+ return count;
+}
+
+const Common::ArchiveMemberPtr CachedArchive::getMember(const Common::String &name) const {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *CachedArchive::createReadStreamForMember(const Common::String &name) const {
+ FileMap::const_iterator fDesc = _files.find(name);
+ if (fDesc == _files.end())
+ return 0;
+
+ return new Common::MemoryReadStream(fDesc->_value.data, fDesc->_value.size, DisposeAfterUse::NO);
+}
+
+// ResFileLoader implementations
+
+// -> ResLoaderPak implementation
+
+bool ResLoaderPak::checkFilename(Common::String filename) const {
+ filename.toUppercase();
+ return (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK") || filename.hasSuffix(".VRM") || filename.hasSuffix(".CMP") || filename.hasSuffix(".TLK") || filename.equalsIgnoreCase(StaticResource::staticDataFilename()));
+}
+
+namespace {
+
+Common::String readString(Common::SeekableReadStream &stream) {
+ Common::String result;
+ char c = 0;
+
+ while ((c = stream.readByte()) != 0)
+ result += c;
+
+ return result;
+}
+
+} // end of anonymous namespace
+
+bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ int32 filesize = stream.size();
+ if (filesize < 0)
+ return false;
+
+ int32 offset = 0;
+ bool switchEndian = false;
+ bool firstFile = true;
+
+ offset = stream.readUint32LE();
+ if (offset > filesize || offset < 0) {
+ switchEndian = true;
+ offset = SWAP_BYTES_32(offset);
+ }
+
+ int32 firstOffset = offset;
+
+ Common::String file;
+ while (!stream.eos()) {
+ // The start offset of a file should never be in the filelist
+ if (offset < stream.pos() || offset > filesize || offset < 0)
+ return false;
+
+ file = readString(stream);
+
+ if (stream.eos())
+ return false;
+
+ // Quit now if we encounter an empty string
+ if (file.empty()) {
+ if (firstFile)
+ return false;
+ else
+ break;
+ }
+
+ firstFile = false;
+ offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
+
+ if (!offset || offset == filesize || firstOffset == stream.pos())
+ break;
+ }
+
+ return true;
+}
+
+Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const {
+ int32 filesize = stream.size();
+ if (filesize < 0)
+ return 0;
+
+ Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile));
+ if (!result)
+ return 0;
+
+ int32 startoffset = 0, endoffset = 0;
+ bool switchEndian = false;
+ bool firstFile = true;
+
+ startoffset = stream.readUint32LE();
+ int32 firstOffset = startoffset;
+ if (startoffset > filesize || startoffset < 0) {
+ switchEndian = true;
+ startoffset = SWAP_BYTES_32(startoffset);
+ }
+
+ Common::String file;
+ while (!stream.eos()) {
+ // The start offset of a file should never be in the filelist
+ if (startoffset < stream.pos() || startoffset > filesize || startoffset < 0) {
+ warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
+ return 0;
+ }
+
+ file = readString(stream);
+
+ if (stream.eos()) {
+ warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
+ return 0;
+ }
+
+ // Quit now if we encounter an empty string
+ if (file.empty()) {
+ if (firstFile) {
+ warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
+ return 0;
+ } else {
+ break;
+ }
+ }
+
+ firstFile = false;
+ endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
+
+ if (endoffset < 0 && stream.pos() != firstOffset) {
+ warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
+ return 0;
+ }
+
+ if (!endoffset || stream.pos() == firstOffset)
+ endoffset = filesize;
+
+ if (startoffset != endoffset)
+ result->addFileEntry(file, PlainArchive::Entry(startoffset, endoffset - startoffset));
+
+ if (endoffset == filesize)
+ break;
+
+ startoffset = endoffset;
+ }
+
+ PlainArchive::Entry linklistFile = result->getFileEntry("LINKLIST");
+ if (linklistFile.size != 0) {
+ stream.seek(linklistFile.offset, SEEK_SET);
+
+ const uint32 magic = stream.readUint32BE();
+
+ if (magic != MKTAG('S', 'C', 'V', 'M'))
+ error("LINKLIST file does not contain 'SCVM' header");
+
+ const uint32 links = stream.readUint32BE();
+ for (uint32 i = 0; i < links; ++i) {
+ const Common::String linksTo = readString(stream);
+ const uint32 sources = stream.readUint32BE();
+
+ PlainArchive::Entry destination = result->getFileEntry(linksTo);
+ if (destination.size == 0)
+ error("PAK file link destination '%s' not found", linksTo.c_str());
+
+ for (uint32 j = 0; j < sources; ++j) {
+ const Common::String dest = readString(stream);
+ result->addFileEntry(dest, destination);
+ }
+ }
+ }
+
+ return result.release();
+}
+
+// -> ResLoaderInsMalcolm implementation
+
+bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const {
+ filename.toUppercase();
+ if (!filename.hasSuffix(".001"))
+ return false;
+ return true;
+}
+
+bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ stream.seek(3, SEEK_SET);
+ int32 size = stream.readUint32LE();
+
+ if (size + 7 > stream.size())
+ return false;
+
+ stream.seek(size + 5, SEEK_SET);
+ uint8 buffer[2];
+ stream.read(&buffer, 2);
+
+ return (buffer[0] == 0x0D && buffer[1] == 0x0A);
+}
+
+Common::Archive *ResLoaderInsMalcolm::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const {
+ Common::List<Common::String> filenames;
+ Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile));
+ if (!result)
+ return 0;
+
+ // thanks to eriktorbjorn for this code (a bit modified though)
+ stream.seek(3, SEEK_SET);
+
+ // first file is the index table
+ uint32 size = stream.readUint32LE();
+ Common::String temp;
+
+ for (uint32 i = 0; i < size; ++i) {
+ byte c = stream.readByte();
+
+ if (c == '\\') {
+ temp.clear();
+ } else if (c == 0x0D) {
+ // line endings are CRLF
+ c = stream.readByte();
+ assert(c == 0x0A);
+ ++i;
+
+ filenames.push_back(temp);
+ } else {
+ temp += (char)c;
+ }
+ }
+
+ stream.seek(3, SEEK_SET);
+
+ for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const uint32 fileSize = stream.readUint32LE();
+ const uint32 fileOffset = stream.pos();
+
+ result->addFileEntry(*file, PlainArchive::Entry(fileOffset, fileSize));
+ stream.seek(fileSize, SEEK_CUR);
+ }
+
+ return result.release();
+}
+
+bool ResLoaderTlk::checkFilename(Common::String filename) const {
+ filename.toUppercase();
+ return (filename.hasSuffix(".TLK"));
+}
+
+bool ResLoaderTlk::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ uint16 entries = stream.readUint16LE();
+ int32 entryTableSize = (entries * 8);
+
+ if (entryTableSize + 2 > stream.size())
+ return false;
+
+ int32 offset = 0;
+
+ for (uint i = 0; i < entries; ++i) {
+ stream.readUint32LE();
+ offset = stream.readUint32LE();
+
+ if (offset > stream.size())
+ return false;
+ }
+
+ return true;
+}
+
+Common::Archive *ResLoaderTlk::load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const {
+ const uint16 entryCount = stream.readUint16LE();
+
+ uint32 *fileEntries = new uint32[entryCount * 2];
+ assert(fileEntries);
+ stream.read(fileEntries, sizeof(uint32) * entryCount * 2);
+
+ for (uint i = 0; i < entryCount; ++i) {
+ fileEntries[i * 2 + 0] = READ_LE_UINT32(&fileEntries[i * 2 + 0]);
+ fileEntries[i * 2 + 1] = READ_LE_UINT32(&fileEntries[i * 2 + 1]);
+ }
+
+
+ return new TlkArchive(file, entryCount, fileEntries);
+}
+
+// InstallerLoader implementation
+
+class FileExpanderSource {
+public:
+ FileExpanderSource(const uint8 *data, int dataSize) : _dataPtr(data), _endofBuffer(data + dataSize), _bitsLeft(8), _key(0), _index(0) {}
+ ~FileExpanderSource() {}
+
+ void advSrcRefresh();
+ void advSrcBitsBy1();
+ void advSrcBitsByIndex(uint8 newIndex);
+
+ uint8 getKeyLower() const { return _key & 0xFF; }
+ void setIndex(uint8 index) { _index = index; }
+ uint16 getKeyMasked(uint8 newIndex);
+ uint16 keyMaskedAlign(uint16 val);
+
+ void copyBytes(uint8 *& dst);
+
+private:
+ const uint8 *_dataPtr;
+ const uint8 *_endofBuffer;
+ uint16 _key;
+ int8 _bitsLeft;
+ uint8 _index;
+};
+
+void FileExpanderSource::advSrcBitsBy1() {
+ _key >>= 1;
+ if (!--_bitsLeft) {
+ if (_dataPtr < _endofBuffer)
+ _key = ((*_dataPtr++) << 8) | (_key & 0xFF);
+ _bitsLeft = 8;
+ }
+}
+
+void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) {
+ _index = newIndex;
+ _bitsLeft -= _index;
+ if (_bitsLeft <= 0) {
+ _key >>= (_index + _bitsLeft);
+ _index = -_bitsLeft;
+ _bitsLeft = 8 - _index;
+ if (_dataPtr < _endofBuffer)
+ _key = (*_dataPtr++ << 8) | (_key & 0xFF);
+ }
+ _key >>= _index;
+}
+
+uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) {
+ static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
+ _index = newIndex;
+ uint16 res = 0;
+
+ if (_index > 8) {
+ newIndex = _index - 8;
+ res = (_key & 0xFF) & mskTable[8];
+ advSrcBitsByIndex(8);
+ _index = newIndex;
+ res |= (((_key & 0xFF) & mskTable[_index]) << 8);
+ advSrcBitsByIndex(_index);
+ } else {
+ res = (_key & 0xFF) & mskTable[_index];
+ advSrcBitsByIndex(_index);
+ }
+
+ return res;
+}
+
+void FileExpanderSource::copyBytes(uint8 *& dst) {
+ advSrcBitsByIndex(_bitsLeft);
+ uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1;
+ _dataPtr += 2;
+
+ if (r)
+ error("decompression failure");
+
+ memcpy(dst, _dataPtr, _key);
+ _dataPtr += _key;
+ dst += _key;
+}
+
+uint16 FileExpanderSource::keyMaskedAlign(uint16 val) {
+ val -= 0x101;
+ _index = (val & 0xFF) >> 2;
+ int16 b = ((_bitsLeft << 8) | _index) - 1;
+ _bitsLeft = b >> 8;
+ _index = b & 0xFF;
+ uint16 res = (((val & 3) + 4) << _index) + 0x101;
+ return res + getKeyMasked(_index);
+}
+
+void FileExpanderSource::advSrcRefresh() {
+ _key = READ_LE_UINT16(_dataPtr);
+ if (_dataPtr < _endofBuffer - 1)
+ _dataPtr += 2;
+ _bitsLeft = 8;
+}
+
+class FileExpander {
+public:
+ FileExpander();
+ ~FileExpander();
+
+ bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize);
+
+private:
+ void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt);
+ uint8 calcCmdAndIndex(const uint8 *tbl, int16 &para);
+
+ FileExpanderSource *_src;
+ uint8 *_tables[9];
+ uint16 *_tables16[3];
+};
+
+FileExpander::FileExpander() : _src(0) {
+ _tables[0] = new uint8[3914];
+ assert(_tables[0]);
+
+ _tables[1] = _tables[0] + 320;
+ _tables[2] = _tables[0] + 352;
+ _tables[3] = _tables[0] + 864;
+ _tables[4] = _tables[0] + 2016;
+ _tables[5] = _tables[0] + 2528;
+ _tables[6] = _tables[0] + 2656;
+ _tables[7] = _tables[0] + 2736;
+ _tables[8] = _tables[0] + 2756;
+
+ _tables16[0] = (uint16 *)(_tables[0] + 3268);
+ _tables16[1] = (uint16 *)(_tables[0] + 3302);
+ _tables16[2] = (uint16 *)(_tables[0] + 3338);
+}
+
+FileExpander::~FileExpander() {
+ delete _src;
+ delete[] _tables[0];
+}
+
+bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) {
+ static const uint8 indexTable[] = {
+ 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A,
+ 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F
+ };
+
+ memset(_tables[0], 0, 3914);
+
+ uint8 *d = dst;
+ uint16 tableSize0 = 0;
+ uint16 tableSize1 = 0;
+ bool needrefresh = true;
+ bool postprocess = false;
+
+ _src = new FileExpanderSource(src, compressedSize);
+
+ while (d < dst + outsize) {
+
+ if (needrefresh) {
+ needrefresh = false;
+ _src->advSrcRefresh();
+ }
+
+ _src->advSrcBitsBy1();
+
+ int mode = _src->getKeyMasked(2) - 1;
+ if (mode == 1) {
+ tableSize0 = _src->getKeyMasked(5) + 257;
+ tableSize1 = _src->getKeyMasked(5) + 1;
+ memset(_tables[7], 0, 19);
+
+ const uint8 *itbl = indexTable;
+ int numbytes = _src->getKeyMasked(4) + 4;
+
+ while (numbytes--)
+ _tables[7][*itbl++] = _src->getKeyMasked(3);
+
+ generateTables(7, 8, 255, 19);
+
+ int cnt = tableSize0 + tableSize1;
+ uint8 *tmp = _tables[0];
+
+ while (cnt) {
+ uint16 cmd = _src->getKeyLower();
+ cmd = READ_LE_UINT16(&_tables[8][cmd << 1]);
+ _src->advSrcBitsByIndex(_tables[7][cmd]);
+
+ if (cmd < 16) {
+ *tmp++ = cmd;
+ cnt--;
+ } else {
+ uint8 tmpI = 0;
+ if (cmd == 16) {
+ cmd = _src->getKeyMasked(2) + 3;
+ tmpI = *(tmp - 1);
+ } else if (cmd == 17) {
+ cmd = _src->getKeyMasked(3) + 3;
+ } else {
+ cmd = _src->getKeyMasked(7) + 11;
+ }
+ _src->setIndex(tmpI);
+ memset(tmp, tmpI, cmd);
+ tmp += cmd;
+
+ cnt -= cmd;
+ if (cnt < 0)
+ error("decompression failure");
+ }
+ }
+
+ memcpy(_tables[1], _tables[0] + tableSize0, tableSize1);
+ generateTables(0, 2, 3, tableSize0);
+ generateTables(1, 4, 5, tableSize1);
+ postprocess = true;
+ } else if (mode < 0) {
+ _src->copyBytes(d);
+ postprocess = false;
+ needrefresh = true;
+ } else if (mode == 0) {
+ uint8 *d2 = _tables[0];
+ memset(d2, 8, 144);
+ memset(d2 + 144, 9, 112);
+ memset(d2 + 256, 7, 24);
+ memset(d2 + 280, 8, 8);
+ d2 = _tables[1];
+ memset(d2, 5, 32);
+ tableSize0 = 288;
+ tableSize1 = 32;
+
+ generateTables(0, 2, 3, tableSize0);
+ generateTables(1, 4, 5, tableSize1);
+ postprocess = true;
+ } else {
+ error("decompression failure");
+ }
+
+ if (!postprocess)
+ continue;
+
+ int16 cmd = 0;
+
+ do {
+ cmd = ((int16 *)_tables[2])[_src->getKeyLower()];
+ _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]);
+
+ if (cmd == 0x11D) {
+ cmd = 0x200;
+ } else if (cmd > 0x108) {
+ cmd = _src->keyMaskedAlign(cmd);
+ }
+
+ if (!(cmd >> 8)) {
+ *d++ = cmd & 0xFF;
+ } else if (cmd != 0x100) {
+ cmd -= 0xFE;
+ int16 offset = ((int16 *)_tables[4])[_src->getKeyLower()];
+ _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]);
+ if ((offset & 0xFF) >= 4) {
+ uint8 newIndex = ((offset & 0xFF) >> 1) - 1;
+ offset = (((offset & 1) + 2) << newIndex);
+ offset += _src->getKeyMasked(newIndex);
+ }
+
+ uint8 *s2 = d - 1 - offset;
+ if (s2 >= dst) {
+ while (cmd--)
+ *d++ = *s2++;
+ } else {
+ uint32 pos = dst - s2;
+ s2 += (d - dst);
+
+ if (pos < (uint32) cmd) {
+ cmd -= pos;
+ while (pos--)
+ *d++ = *s2++;
+ s2 = dst;
+ }
+ while (cmd--)
+ *d++ = *s2++;
+ }
+ }
+ } while (cmd != 0x100);
+ }
+
+ delete _src;
+ _src = 0;
+
+ return true;
+}
+
+void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) {
+ uint8 *tbl1 = _tables[srcIndex];
+ uint8 *tbl2 = _tables[dstIndex];
+ uint8 *tbl3 = dstIndex2 == 0xFF ? 0 : _tables[dstIndex2];
+
+ if (!cnt)
+ return;
+
+ const uint8 *s = tbl1;
+ memset(_tables16[0], 0, 32);
+
+ for (int i = 0; i < cnt; i++)
+ _tables16[0][(*s++)]++;
+
+ _tables16[1][1] = 0;
+
+ for (uint16 i = 1, r = 0; i < 16; i++) {
+ r = (r + _tables16[0][i]) << 1;
+ _tables16[1][i + 1] = r;
+ }
+
+ if (_tables16[1][16]) {
+ uint16 r = 0;
+ for (uint16 i = 1; i < 16; i++)
+ r += _tables16[0][i];
+ if (r > 1)
+ error("decompression failure");
+ }
+
+ s = tbl1;
+ uint16 *d = _tables16[2];
+ for (int i = 0; i < cnt; i++) {
+ uint16 t = *s++;
+ if (t) {
+ _tables16[1][t]++;
+ t = _tables16[1][t] - 1;
+ }
+ *d++ = t;
+ }
+
+ s = tbl1;
+ d = _tables16[2];
+ for (int i = 0; i < cnt; i++) {
+ int8 t = ((int8)(*s++)) - 1;
+ if (t > 0) {
+ uint16 v1 = *d;
+ uint16 v2 = 0;
+
+ do {
+ v2 = (v2 << 1) | (v1 & 1);
+ v1 >>= 1;
+ } while (--t && v1);
+
+ t++;
+ uint8 c1 = (v1 & 1);
+ while (t--) {
+ uint8 c2 = v2 >> 15;
+ v2 = (v2 << 1) | c1;
+ c1 = c2;
+ };
+
+ *d++ = v2;
+ } else {
+ d++;
+ }
+ }
+
+ memset(tbl2, 0, 512);
+
+ cnt--;
+ s = tbl1 + cnt;
+ d = &_tables16[2][cnt];
+ uint16 *bt = (uint16 *)tbl3;
+ uint16 inc = 0;
+ uint16 cnt2 = 0;
+
+ do {
+ uint8 t = *s--;
+ uint16 *s2 = (uint16 *)tbl2;
+
+ if (t && t < 9) {
+ inc = 1 << t;
+ uint16 o = *d;
+
+ do {
+ s2[o] = cnt;
+ o += inc;
+ } while (!(o & 0xF00));
+
+ } else if (t > 8) {
+ if (!bt)
+ error("decompression failure");
+
+ t -= 8;
+ uint8 shiftCnt = 1;
+ uint8 v = (*d) >> 8;
+ s2 = &((uint16 *)tbl2)[*d & 0xFF];
+
+ do {
+ if (!*s2) {
+ *s2 = (uint16)(~cnt2);
+ *(uint32 *)&bt[cnt2] = 0;
+ cnt2 += 2;
+ }
+
+ s2 = &bt[(uint16)(~*s2)];
+ if (v & shiftCnt)
+ s2++;
+
+ shiftCnt <<= 1;
+ } while (--t);
+ *s2 = cnt;
+ }
+ d--;
+ } while (--cnt >= 0);
+}
+
+uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 &para) {
+ const uint16 *t = (const uint16 *)tbl;
+ _src->advSrcBitsByIndex(8);
+ uint8 newIndex = 0;
+ uint16 v = _src->getKeyLower();
+
+ do {
+ newIndex++;
+ para = t[((~para) & 0xFFFE) | (v & 1)];
+ v >>= 1;
+ } while (para < 0);
+
+ return newIndex;
+}
+
+namespace {
+
+struct InsArchive {
+ Common::String filename;
+ uint32 firstFile;
+ uint32 startOffset;
+ uint32 lastFile;
+ uint32 endOffset;
+ uint32 totalSize;
+};
+
+} // end of anonymouse namespace
+
+class CmpVocDecoder {
+public:
+ CmpVocDecoder();
+ ~CmpVocDecoder();
+ uint8 *process(uint8 *src, uint32 insize, uint32 *outsize, bool disposeInput = true);
+
+private:
+ void decodeHelper(int p);
+
+ int32 *_vtbl;
+ int32 *_tbl1, *_p1, *_tbl2, *_p2, *_tbl3, *_p3, *_tbl4, *_p4, *_floatArray, *_stTbl;
+ uint8 *_sndArray;
+};
+
+Common::Archive *InstallerLoader::load(Resource *owner, const Common::String &filename, const Common::String &extension, const uint8 containerOffset) {
+ uint32 pos = 0;
+ uint32 bytesleft = 0;
+ bool startFile = true;
+
+ Common::String filenameBase = filename;
+ Common::String filenameTemp;
+ char filenameExt[4];
+
+ if (filenameBase.lastChar() != '.')
+ filenameBase += '.';
+
+ InsArchive newArchive;
+ Common::List<InsArchive> archives;
+
+ Common::SeekableReadStream *tmpFile = 0;
+
+ for (int8 currentFile = 1; currentFile; currentFile++) {
+ sprintf(filenameExt, extension.c_str(), currentFile);
+ filenameTemp = filenameBase + Common::String(filenameExt);
+
+ if (!(tmpFile = owner->createReadStream(filenameTemp))) {
+ debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
+ break;
+ }
+
+ tmpFile->seek(pos, SEEK_SET);
+ uint8 fileId = tmpFile->readByte();
+ pos++;
+
+ uint32 size = tmpFile->size() - 1;
+ if (startFile) {
+ size -= 4;
+ if (fileId == currentFile) {
+ size -= containerOffset;
+ pos += containerOffset;
+ tmpFile->seek(containerOffset, SEEK_CUR);
+ } else {
+ size = size + 1 - pos;
+ }
+ newArchive.filename = filenameBase;
+ bytesleft = newArchive.totalSize = tmpFile->readUint32LE();
+ pos += 4;
+ newArchive.firstFile = currentFile;
+ newArchive.startOffset = pos;
+ startFile = false;
+ }
+
+ uint32 cs = MIN(size, bytesleft);
+ bytesleft -= cs;
+
+ delete tmpFile;
+ tmpFile = 0;
+
+ pos += cs;
+ if (cs == size) {
+ if (!bytesleft) {
+ newArchive.lastFile = currentFile;
+ newArchive.endOffset = --pos;
+ archives.push_back(newArchive);
+ currentFile = -1;
+ } else {
+ pos = 0;
+ }
+ } else {
+ startFile = true;
+ bytesleft = size - cs;
+ newArchive.lastFile = currentFile--;
+ newArchive.endOffset = --pos;
+ archives.push_back(newArchive);
+ }
+ }
+
+ FileExpander exp;
+ CmpVocDecoder cvdec;
+ CachedArchive::InputEntry newEntry;
+ uint32 insize = 0;
+ uint32 outsize = 0;
+ uint8 *inbuffer = 0;
+ uint8 *outbuffer = 0;
+ uint32 inPart1 = 0;
+ uint32 inPart2 = 0;
+ uint8 compressionType = 0;
+ Common::String entryStr;
+
+ CachedArchive::FileInputList fileList;
+
+ pos = 0;
+
+ const uint32 kExecSize = 0x0BBA;
+ const uint32 kHeaderSize = 30;
+ const uint32 kHeaderSize2 = 46;
+
+ for (Common::List<InsArchive>::iterator a = archives.begin(); a != archives.end(); ++a) {
+ startFile = true;
+ for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) {
+ sprintf(filenameExt, extension.c_str(), i);
+ filenameTemp = a->filename + Common::String(filenameExt);
+
+ if (!(tmpFile = owner->createReadStream(filenameTemp))) {
+ debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
+ break;
+ }
+
+ uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile->size();
+
+ if (startFile) {
+ startFile = false;
+ pos = a->startOffset + kExecSize;
+ if (pos > size) {
+ pos -= size;
+ delete tmpFile;
+ tmpFile = 0;
+ continue;
+ }
+ } else {
+ if (inPart2) {
+ tmpFile->seek(1, SEEK_SET);
+ tmpFile->read(inbuffer + inPart1, inPart2);
+ inPart2 = 0;
+
+ if (compressionType > 0)
+ exp.process(outbuffer, inbuffer, outsize, insize);
+ else
+ memcpy(outbuffer, inbuffer, outsize);
+
+ delete[] inbuffer;
+ inbuffer = 0;
+
+ newEntry.data = outbuffer;
+ newEntry.size = outsize;
+ newEntry.name = entryStr;
+
+ entryStr.toUppercase();
+ if (entryStr.hasSuffix(".CMP")) {
+ entryStr.deleteLastChar();
+ entryStr.deleteLastChar();
+ entryStr.deleteLastChar();
+ entryStr += "PAK";
+ newEntry.data = cvdec.process(outbuffer, outsize, &outsize);
+ newEntry.size = outsize;
+ newEntry.name = entryStr;
+ }
+
+ fileList.push_back(newEntry);
+ }
+ pos++;
+ }
+
+ while (pos < size) {
+ uint8 hdr[43];
+ uint32 m = 0;
+ tmpFile->seek(pos, SEEK_SET);
+
+ if (pos + 42 > size) {
+ m = size - pos;
+ uint32 b = 42 - m;
+
+ if (m >= 4) {
+ uint32 id = tmpFile->readUint32LE();
+ if (id == 0x06054B50) {
+ startFile = true;
+ break;
+ } else {
+ tmpFile->seek(pos, SEEK_SET);
+ }
+ }
+
+ sprintf(filenameExt, extension.c_str(), i + 1);
+ filenameTemp = a->filename + Common::String(filenameExt);
+
+ Common::SeekableReadStream *tmpFile2 = owner->createReadStream(filenameTemp);
+ tmpFile->read(hdr, m);
+ tmpFile2->read(hdr + m, b);
+ delete tmpFile2;
+ } else {
+ tmpFile->read(hdr, 42);
+ }
+
+ uint32 id = READ_LE_UINT32(hdr);
+
+ if (id == 0x04034B50) {
+ compressionType = hdr[8];
+ insize = READ_LE_UINT32(hdr + 18);
+ outsize = READ_LE_UINT32(hdr + 22);
+
+ uint16 filestrlen = READ_LE_UINT16(hdr + 26);
+ *(hdr + 30 + filestrlen) = 0;
+ entryStr = Common::String((const char *)(hdr + 30));
+ pos += (kHeaderSize + filestrlen - m);
+ tmpFile->seek(pos, SEEK_SET);
+
+ outbuffer = new uint8[outsize];
+ if (!outbuffer)
+ error("Out of memory: Can't uncompress installer files");
+
+ if (!inbuffer) {
+ inbuffer = new uint8[insize];
+ if (!inbuffer)
+ error("Out of memory: Can't uncompress installer files");
+ }
+
+ if ((pos + insize) > size) {
+ // this is for files that are split between two archive files
+ inPart1 = size - pos;
+ inPart2 = insize - inPart1;
+ tmpFile->read(inbuffer, inPart1);
+ } else {
+ tmpFile->read(inbuffer, insize);
+ inPart2 = 0;
+
+ if (compressionType > 0)
+ exp.process(outbuffer, inbuffer, outsize, insize);
+ else
+ memcpy(outbuffer, inbuffer, outsize);
+
+ delete[] inbuffer;
+ inbuffer = 0;
+ newEntry.data = outbuffer;
+ newEntry.size = outsize;
+ newEntry.name = entryStr;
+
+ entryStr.toUppercase();
+ if (entryStr.hasSuffix(".CMP")) {
+ entryStr.deleteLastChar();
+ entryStr.deleteLastChar();
+ entryStr.deleteLastChar();
+ entryStr += "PAK";
+ newEntry.data = cvdec.process(outbuffer, outsize, &outsize);
+ newEntry.size = outsize;
+ newEntry.name = entryStr;
+ }
+
+ fileList.push_back(newEntry);
+ }
+
+ pos += insize;
+ if (pos > size) {
+ pos -= size;
+ break;
+ }
+ } else {
+ uint32 filestrlen = READ_LE_UINT32(hdr + 28);
+ pos += (kHeaderSize2 + filestrlen - m);
+ }
+ }
+ delete tmpFile;
+ tmpFile = 0;
+ }
+ }
+
+ archives.clear();
+ return new CachedArchive(fileList);
+}
+
+CmpVocDecoder::CmpVocDecoder() {
+ _tbl1 = new int32[4000];
+ _p1 = _tbl1 + 2000;
+ _tbl2 = new int32[4000];
+ _p2 = _tbl2 + 2000;
+ _tbl3 = new int32[4000];
+ _p3 = _tbl3 + 2000;
+ _tbl4 = new int32[4000];
+ _p4 = _tbl4 + 2000;
+
+ _vtbl = new int32[8193];
+ _floatArray = new int32[8193];
+ _sndArray = new uint8[8192];
+ _stTbl = new int32[256];
+
+ assert(_tbl1);
+ assert(_tbl2);
+ assert(_tbl3);
+ assert(_tbl4);
+ assert(_vtbl);
+ assert(_floatArray);
+ assert(_sndArray);
+ assert(_stTbl);
+
+ for (int32 i = -2000; i < 2000; i++) {
+ int32 x = i + 2000;
+ _tbl1[x] = (int32)(0.4829629131445341 * (double)i * 256.0);
+ _tbl2[x] = (int32)(0.8365163037378079 * (double)i * 256.0);
+ _tbl3[x] = (int32)(0.2241438680420134 * (double)i * 256.0);
+ _tbl4[x] = (int32)(-0.1294095225512604 * (double)i * 256.0);
+ }
+}
+
+CmpVocDecoder::~CmpVocDecoder() {
+ delete[] _stTbl;
+ delete[] _sndArray;
+ delete[] _floatArray;
+ delete[] _vtbl;
+ delete[] _tbl1;
+ delete[] _tbl2;
+ delete[] _tbl3;
+ delete[] _tbl4;
+}
+
+uint8 *CmpVocDecoder::process(uint8 *src, uint32 insize, uint32 *outsize, bool disposeInput) {
+ *outsize = 0;
+ uint8 *outTemp = new uint8[insize];
+
+ uint8 *inPosH = src;
+ uint8 *outPosH = outTemp;
+ uint8 *outPosD = outTemp + READ_LE_UINT32(src);
+ uint8 *end = outPosD;
+
+ while (outPosH < end) {
+ uint8 *spos = inPosH;
+ uint32 offset = READ_LE_UINT32(inPosH);
+ inPosH += 4;
+ char *name = (char *)inPosH;
+ inPosH += strlen(name) + 1;
+
+ if (!name[0]) {
+ *outsize = outPosD - outTemp;
+ WRITE_LE_UINT32(outPosH, *outsize);
+ memset(outPosH + 4, 0, 5);
+ break;
+ }
+
+ uint32 fileSize = READ_LE_UINT32(inPosH) - offset;
+ int headerEntryLen = inPosH - spos;
+
+ if (scumm_stricmp(name + strlen(name) - 4, ".voc")) {
+ memcpy(outPosH, spos, headerEntryLen);
+ WRITE_LE_UINT32(outPosH, outPosD - outTemp);
+ outPosH += headerEntryLen;
+ memcpy(outPosD, src + offset, fileSize);
+ outPosD += fileSize;
+ continue;
+ }
+
+ uint8 *vocPtr = src + offset;
+ uint32 vocLen = (vocPtr[27] | (vocPtr[28] << 8) | (vocPtr[29] << 16)) - 2;
+
+ uint8 *vocOutEnd = outPosD + vocLen + 32;
+ uint8 *vocInEnd = src + offset + fileSize;
+ memcpy(outPosD, vocPtr, 32);
+ uint8 *dst = outPosD + 32;
+ vocPtr += 32;
+ float t = 0.0f;
+
+ while (dst < vocOutEnd) {
+ memcpy(&t, vocPtr, 4);
+ vocPtr += 4;
+ uint32 readSize = MIN<uint32>(8192, vocInEnd - vocPtr);
+ memcpy(_sndArray, vocPtr, readSize);
+ vocPtr += readSize;
+
+ for (int i = -128; i < 128; i++)
+ _stTbl[i + 128] = (int32)((float)i / t + 0.5f);
+
+ int8 *ps = (int8 *)_sndArray;
+ for (int i = 0; i < 8192; i++)
+ _floatArray[i + 1] = _stTbl[128 + *ps++];
+
+ for (int i = 4; i <= 8192; i <<= 1)
+ decodeHelper(i);
+
+ for (int i = 1; i <= 8192; i++) {
+ int32 v = CLIP<int32>(_floatArray[i] + 128, 0, 255);
+ _sndArray[i - 1] = v;
+ }
+
+ uint32 numBytesOut = MIN<uint32>(vocOutEnd - dst, 8192);
+ memcpy(dst, _sndArray, numBytesOut);
+ dst += numBytesOut;
+ }
+
+ *dst++ = 0;
+ memcpy(outPosH, spos, headerEntryLen);
+ WRITE_LE_UINT32(outPosH, outPosD - outTemp);
+ outPosH += headerEntryLen;
+ outPosD += (vocLen + 33);
+ }
+
+ if (disposeInput)
+ delete[] src;
+
+ uint8 *outFinal = new uint8[*outsize];
+ memcpy(outFinal, outTemp, *outsize);
+ delete[] outTemp;
+
+ return outFinal;
+}
+
+void CmpVocDecoder::decodeHelper(int p1) {
+ int p2 = p1 >> 1;
+ int p3 = p2 + 1;
+
+ int16 fi1 = _floatArray[1];
+ int16 fi2 = _floatArray[p2];
+ int16 fi3 = _floatArray[p3];
+ int16 fi4 = _floatArray[p1];
+
+ _vtbl[1] = (*(_p3 + fi2) + *(_p2 + fi4) + *(_p1 + fi1) + *(_p4 + fi3)) >> 8;
+ _vtbl[2] = (*(_p4 + fi2) - *(_p1 + fi4) + *(_p2 + fi1) - *(_p3 + fi3)) >> 8;
+
+ int d = 3;
+ int s = 1;
+
+ while (s < p2) {
+ fi2 = _floatArray[s];
+ fi1 = _floatArray[s + 1];
+ fi4 = _floatArray[s + p2];
+ fi3 = _floatArray[s + p3];
+
+ _vtbl[d++] = (*(_p3 + fi2) + *(_p2 + fi4) + *(_p1 + fi1) + *(_p4 + fi3)) >> 8;
+ _vtbl[d++] = (*(_p4 + fi2) - *(_p1 + fi4) + *(_p2 + fi1) - *(_p3 + fi3)) >> 8;
+ s++;
+ }
+
+ memcpy(&_floatArray[1], &_vtbl[1], p1 * sizeof(int32));
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/resource/resource_intern.h b/engines/kyra/resource/resource_intern.h
new file mode 100644
index 0000000000..530df51f35
--- /dev/null
+++ b/engines/kyra/resource/resource_intern.h
@@ -0,0 +1,146 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_RESOURCE_INTERN_H
+#define KYRA_RESOURCE_INTERN_H
+
+#include "common/archive.h"
+#include "common/hash-str.h"
+#include "common/hashmap.h"
+#include "common/str.h"
+#include "common/list.h"
+
+namespace Kyra {
+
+class Resource;
+
+class PlainArchive : public Common::Archive {
+public:
+ struct Entry {
+ Entry() : offset(0), size(0) {}
+ Entry(uint32 o, uint32 s) : offset(o), size(s) {}
+
+ uint32 offset;
+ uint32 size;
+ };
+
+ PlainArchive(Common::ArchiveMemberPtr file);
+
+ void addFileEntry(const Common::String &name, const Entry entry);
+ Entry getFileEntry(const Common::String &name) const;
+
+ // Common::Archive API implementation
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+private:
+ typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+
+ Common::ArchiveMemberPtr _file;
+ FileMap _files;
+};
+
+class TlkArchive : public Common::Archive {
+public:
+ TlkArchive(Common::ArchiveMemberPtr file, uint16 entryCount, const uint32 *fileEntries);
+ ~TlkArchive();
+
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+private:
+ Common::ArchiveMemberPtr _file;
+
+ const uint32 *findFile(const Common::String &name) const;
+
+ const uint16 _entryCount;
+ const uint32 *const _fileEntries;
+};
+
+class CachedArchive : public Common::Archive {
+public:
+ struct InputEntry {
+ Common::String name;
+
+ byte *data;
+ uint32 size;
+ };
+
+ typedef Common::List<InputEntry> FileInputList;
+
+ CachedArchive(const FileInputList &files);
+ ~CachedArchive();
+
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+private:
+ struct Entry {
+ byte *data;
+ uint32 size;
+ };
+
+ typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+ FileMap _files;
+};
+
+
+class ResArchiveLoader {
+public:
+ virtual ~ResArchiveLoader() {}
+ virtual bool checkFilename(Common::String filename) const = 0;
+ virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0;
+ virtual Common::Archive *load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const = 0;
+};
+
+class ResLoaderPak : public ResArchiveLoader {
+public:
+ bool checkFilename(Common::String filename) const;
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ Common::Archive *load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const;
+};
+
+class ResLoaderInsMalcolm : public ResArchiveLoader {
+public:
+ bool checkFilename(Common::String filename) const;
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ Common::Archive *load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const;
+};
+
+class ResLoaderTlk : public ResArchiveLoader {
+public:
+ bool checkFilename(Common::String filename) const;
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ Common::Archive *load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const;
+};
+
+class InstallerLoader {
+public:
+ static Common::Archive *load(Resource *owner, const Common::String &filename, const Common::String &extension, const uint8 offset);
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/resource/staticres.cpp b/engines/kyra/resource/staticres.cpp
new file mode 100644
index 0000000000..fb6d14dd4b
--- /dev/null
+++ b/engines/kyra/resource/staticres.cpp
@@ -0,0 +1,2046 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/resource/resource.h"
+#include "kyra/engine/kyra_lok.h"
+#include "kyra/engine/kyra_hof.h"
+#include "kyra/engine/kyra_mr.h"
+#include "kyra/graphics/screen.h"
+#include "kyra/graphics/screen_lok.h"
+#include "kyra/graphics/screen_hof.h"
+#include "kyra/graphics/screen_mr.h"
+#include "kyra/gui/gui_lok.h"
+#include "kyra/gui/gui_hof.h"
+#include "kyra/gui/gui_mr.h"
+#include "kyra/sequence/sequences_hof.h"
+#include "kyra/sound/sound_intern.h"
+
+#include "common/endian.h"
+#include "common/md5.h"
+
+namespace Kyra {
+
+#define RESFILE_VERSION 92
+
+namespace {
+bool checkKyraDat(Common::SeekableReadStream *file) {
+ if (!file)
+ return false;
+
+ uint32 size = file->size() - 16;
+ uint8 digest[16];
+ file->seek(size, SEEK_SET);
+ if (file->read(digest, 16) != 16)
+ return false;
+
+ uint8 digestCalc[16];
+ file->seek(0, SEEK_SET);
+ if (!Common::computeStreamMD5(*file, digestCalc, size))
+ return false;
+
+ for (int i = 0; i < 16; ++i)
+ if (digest[i] != digestCalc[i])
+ return false;
+ return true;
+}
+
+struct IndexTable {
+ int type;
+ int value;
+
+ bool operator==(int t) const {
+ return (type == t);
+ }
+};
+
+const IndexTable iGameTable[] = {
+ { GI_KYRA1, 0 },
+ { GI_KYRA2, 1 },
+ { GI_KYRA3, 2 },
+ { GI_EOB1, 3 },
+ { GI_EOB2, 4 },
+ { GI_LOL, 5 },
+ { -1, -1 }
+};
+
+byte getGameID(const GameFlags &flags) {
+ return Common::find(iGameTable, ARRAYEND(iGameTable) - 1, flags.gameID)->value;
+}
+
+const IndexTable iLanguageTable[] = {
+ { Common::EN_ANY, 1 },
+ { Common::FR_FRA, 2 },
+ { Common::DE_DEU, 3 },
+ { Common::ES_ESP, 4 },
+ { Common::IT_ITA, 5 },
+ { Common::JA_JPN, 6 },
+ { Common::RU_RUS, 7 },
+ { -1, -1 }
+};
+
+byte getLanguageID(const GameFlags &flags) {
+ return Common::find(iLanguageTable, ARRAYEND(iLanguageTable) - 1, flags.lang)->value;
+}
+
+const IndexTable iPlatformTable[] = {
+ { Common::kPlatformDOS, 0 },
+ { Common::kPlatformAmiga, 1 },
+ { Common::kPlatformFMTowns, 2 },
+ { Common::kPlatformPC98, 3 },
+ { Common::kPlatformMacintosh, 0 }, // HACK: Should be type "4", but as long as we can't extract Macintosh data, we need to use DOS data.
+ { -1, -1 }
+};
+
+byte getPlatformID(const GameFlags &flags) {
+ return Common::find(iPlatformTable, ARRAYEND(iPlatformTable) - 1, flags.platform)->value;
+}
+
+byte getSpecialID(const GameFlags &flags) {
+ if (flags.isOldFloppy)
+ return 4;
+ else if (flags.isDemo && flags.isTalkie)
+ return 3;
+ else if (flags.isDemo)
+ return 2;
+ else if (flags.isTalkie)
+ return 1;
+ else
+ return 0;
+}
+
+} // end of anonymous namespace
+
+bool StaticResource::loadStaticResourceFile() {
+ Resource *res = _vm->resource();
+
+ if (res->isInCacheList(staticDataFilename()))
+ return true;
+
+ Common::ArchiveMemberList kyraDatFiles;
+ res->listFiles(staticDataFilename(), kyraDatFiles);
+
+ bool foundWorkingKyraDat = false;
+ for (Common::ArchiveMemberList::iterator i = kyraDatFiles.begin(); i != kyraDatFiles.end(); ++i) {
+ Common::SeekableReadStream *file = (*i)->createReadStream();
+ if (!checkKyraDat(file)) {
+ delete file;
+ continue;
+ }
+
+ delete file; file = 0;
+
+ if (!res->loadPakFile(staticDataFilename(), *i))
+ continue;
+
+ if (tryKyraDatLoad()) {
+ foundWorkingKyraDat = true;
+ break;
+ }
+
+ res->unloadPakFile(staticDataFilename(), true);
+ unloadId(-1);
+ }
+
+ if (!foundWorkingKyraDat) {
+ Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' engine data file or it got corrupted.";
+ GUIErrorMessage(errorMessage);
+ error("%s", errorMessage.c_str());
+ }
+
+ return true;
+}
+
+bool StaticResource::tryKyraDatLoad() {
+ Common::SeekableReadStream *index = _vm->resource()->createReadStream("INDEX");
+ if (!index)
+ return false;
+
+ const uint32 version = index->readUint32BE();
+
+ if (version != RESFILE_VERSION) {
+ delete index;
+ return false;
+ }
+
+ const uint32 includedGames = index->readUint32BE();
+
+ if (includedGames * 2 + 8 != (uint32)index->size()) {
+ delete index;
+ return false;
+ }
+
+ const GameFlags &flags = _vm->gameFlags();
+ const byte game = getGameID(flags) & 0xF;
+ const byte platform = getPlatformID(flags) & 0xF;
+ const byte special = getSpecialID(flags) & 0xF;
+ const byte lang = getLanguageID(flags) & 0xF;
+
+ const uint16 gameDef = (game << 12) | (platform << 8) | (special << 4) | (lang << 0);
+
+ bool found = false;
+ for (uint32 i = 0; i < includedGames; ++i) {
+ if (index->readUint16BE() == gameDef) {
+ found = true;
+ break;
+ }
+ }
+
+ delete index;
+ index = 0;
+
+ if (!found)
+ return false;
+
+ // load the ID map for our game
+ const Common::String filenamePattern = Common::String::format("0%01X%01X%01X000%01X", game, platform, special, lang);
+ Common::SeekableReadStream *idMap = _vm->resource()->createReadStream(filenamePattern);
+ if (!idMap)
+ return false;
+
+ uint16 numIDs = idMap->readUint16BE();
+ while (numIDs--) {
+ uint16 id = idMap->readUint16BE();
+ uint8 type = idMap->readByte();
+ uint32 filename = idMap->readUint32BE();
+
+ _dataTable[id] = DataDescriptor(filename, type);
+ }
+
+ const bool fileError = idMap->err();
+ delete idMap;
+ if (fileError)
+ return false;
+
+ // load all tables for now
+ if (!prefetchId(-1))
+ return false;
+
+ return true;
+}
+
+bool StaticResource::init() {
+#define proc(x) &StaticResource::x
+ static const FileType fileTypeTable[] = {
+ { kStringList, proc(loadStringTable), proc(freeStringTable) },
+ { StaticResource::kRoomList, proc(loadRoomTable), proc(freeRoomTable) },
+ { kShapeList, proc(loadShapeTable), proc(freeShapeTable) },
+ { kAmigaSfxTable, proc(loadAmigaSfxTable), proc(freeAmigaSfxTable) },
+ { kRawData, proc(loadRawData), proc(freeRawData) },
+
+ { k2SeqData, proc(loadHoFSequenceData), proc(freeHoFSequenceData) },
+ { k2SeqItemAnimData, proc(loadHoFSeqItemAnimData), proc(freeHoFSeqItemAnimData) },
+ { k2ItemAnimDefinition, proc(loadItemAnimDefinition), proc(freeItemAnimDefinition) },
+
+#ifdef ENABLE_LOL
+ { kLoLCharData, proc(loadCharData), proc(freeCharData) },
+ { kLoLSpellData, proc(loadSpellData), proc(freeSpellData) },
+ { kLoLCompassData, proc(loadCompassData), proc(freeCompassData) },
+ { kLoLFlightShpData, proc(loadFlyingObjectData), proc(freeFlyingObjectData) },
+#else
+ { kLoLCharData, proc(loadDummy), proc(freeDummy) },
+ { kLoLSpellData, proc(loadDummy), proc(freeDummy) },
+ { kLoLCompassData, proc(loadDummy), proc(freeDummy) },
+ { kLoLFlightShpData, proc(loadDummy), proc(freeDummy) },
+#endif
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ { kRawDataBe16, proc(loadRawDataBe16), proc(freeRawDataBe16) },
+ { kRawDataBe32, proc(loadRawDataBe32), proc(freeRawDataBe32) },
+#endif
+#ifdef ENABLE_LOL
+ { kLoLButtonData, proc(loadButtonDefs), proc(freeButtonDefs) },
+#else
+ { kLoLButtonData, proc(loadDummy), proc(freeDummy) },
+#endif
+
+#ifdef ENABLE_EOB
+ { kEoB2SequenceData, proc(loadEoB2SeqData), proc(freeEoB2SeqData) },
+ { kEoB2ShapeData, proc(loadEoB2ShapeData), proc(freeEoB2ShapeData) },
+ { kEoBNpcData, proc(loadEoBNpcData), proc(freeEoBNpcData) },
+#endif
+
+ { 0, 0, 0 }
+ };
+#undef proc
+ _fileLoader = fileTypeTable;
+
+ return loadStaticResourceFile();
+}
+
+void StaticResource::deinit() {
+ unloadId(-1);
+}
+
+const char *const *StaticResource::loadStrings(int id, int &strings) {
+ return (const char *const *)getData(id, kStringList, strings);
+}
+
+const uint8 *StaticResource::loadRawData(int id, int &size) {
+ return (const uint8 *)getData(id, kRawData, size);
+}
+
+const Shape *StaticResource::loadShapeTable(int id, int &entries) {
+ return (const Shape *)getData(id, kShapeList, entries);
+}
+
+const AmigaSfxTable *StaticResource::loadAmigaSfxTable(int id, int &entries) {
+ return (const AmigaSfxTable *)getData(id, kAmigaSfxTable, entries);
+}
+
+const Room *StaticResource::loadRoomTable(int id, int &entries) {
+ return (const Room *)getData(id, StaticResource::kRoomList, entries);
+}
+
+const HoFSeqData *StaticResource::loadHoFSequenceData(int id, int &entries) {
+ return (const HoFSeqData *)getData(id, k2SeqData, entries);
+}
+
+const HoFSeqItemAnimData *StaticResource::loadHoFSeqItemAnimData(int id, int &entries) {
+ return (const HoFSeqItemAnimData *)getData(id, k2SeqItemAnimData, entries);
+}
+
+const ItemAnimDefinition *StaticResource::loadItemAnimDefinition(int id, int &entries) {
+ return (const ItemAnimDefinition *)getData(id, k2ItemAnimDefinition, entries);
+}
+
+bool StaticResource::prefetchId(int id) {
+ if (id == -1) {
+ for (DataMap::const_iterator i = _dataTable.begin(); i != _dataTable.end(); ++i) {
+ if (!prefetchId(i->_key))
+ return false;
+ }
+ return true;
+ }
+
+ const void *ptr = 0;
+ int type = -1, size = -1;
+
+ if (checkResList(id, type, ptr, size))
+ return true;
+
+ DataMap::const_iterator dDesc = _dataTable.find(id);
+ if (dDesc == _dataTable.end())
+ return false;
+
+ const FileType *filetype = getFiletype(dDesc->_value.type);
+ if (!filetype)
+ return false;
+
+ ResData data;
+ data.id = id;
+ data.type = dDesc->_value.type;
+ Common::SeekableReadStream *fileStream = _vm->resource()->createReadStream(Common::String::format("%08X", dDesc->_value.filename));
+ if (!fileStream)
+ return false;
+
+ if (!(this->*(filetype->load))(*fileStream, data.data, data.size)) {
+ delete fileStream;
+ return false;
+ }
+ delete fileStream;
+ _resList.push_back(data);
+
+ return true;
+}
+
+void StaticResource::unloadId(int id) {
+ Common::List<ResData>::iterator pos = _resList.begin();
+ for (; pos != _resList.end();) {
+ if (pos->id == id || id == -1) {
+ const FileType *filetype = getFiletype(pos->type);
+ (this->*(filetype->free))(pos->data, pos->size);
+ pos = _resList.erase(pos);
+ if (id != -1)
+ break;
+ } else {
+ ++pos;
+ }
+ }
+}
+
+bool StaticResource::checkResList(int id, int &type, const void *&ptr, int &size) {
+ Common::List<ResData>::iterator pos = _resList.begin();
+ for (; pos != _resList.end(); ++pos) {
+ if (pos->id == id) {
+ size = pos->size;
+ type = pos->type;
+ ptr = pos->data;
+ return true;
+ }
+ }
+ return false;
+}
+
+const StaticResource::FileType *StaticResource::getFiletype(int type) {
+ if (!_fileLoader)
+ return 0;
+
+ for (int i = 0; _fileLoader[i].load; ++i) {
+ if (_fileLoader[i].type == type)
+ return &_fileLoader[i];
+ }
+
+ return 0;
+}
+
+const void *StaticResource::getData(int id, int requesttype, int &size) {
+ const void *ptr = 0;
+ int type = -1;
+ size = 0;
+
+ if (checkResList(id, type, ptr, size)) {
+ if (type == requesttype)
+ return ptr;
+ return 0;
+ }
+
+ if (!prefetchId(id))
+ return 0;
+
+ if (checkResList(id, type, ptr, size)) {
+ if (type == requesttype)
+ return ptr;
+ }
+
+ return 0;
+}
+
+bool StaticResource::loadDummy(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ return true;
+}
+
+bool StaticResource::loadStringTable(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ uint32 count = stream.readUint32BE();
+ size = count;
+ char **output = new char *[count];
+ assert(output);
+
+ for (uint32 i = 0; i < count; ++i) {
+ Common::String string;
+ char c = 0;
+ while ((c = (char)stream.readByte()) != 0)
+ string += c;
+
+ output[i] = new char[string.size() + 1];
+ strcpy(output[i], string.c_str());
+ }
+
+ ptr = output;
+ return true;
+}
+
+bool StaticResource::loadRawData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ ptr = new uint8[stream.size()];
+ stream.read(ptr, stream.size());
+ size = stream.size();
+ return true;
+}
+
+bool StaticResource::loadShapeTable(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ uint32 count = stream.readUint32BE();
+ size = count;
+ Shape *loadTo = new Shape[count];
+ assert(loadTo);
+
+ for (uint32 i = 0; i < count; ++i) {
+ loadTo[i].imageIndex = stream.readByte();
+ loadTo[i].x = stream.readByte();
+ loadTo[i].y = stream.readByte();
+ loadTo[i].w = stream.readByte();
+ loadTo[i].h = stream.readByte();
+ loadTo[i].xOffset = stream.readSByte();
+ loadTo[i].yOffset = stream.readSByte();
+ }
+
+ ptr = loadTo;
+ return true;
+}
+
+bool StaticResource::loadAmigaSfxTable(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.readUint32BE();
+ AmigaSfxTable *loadTo = new AmigaSfxTable[size];
+ assert(loadTo);
+
+ for (int i = 0; i < size; ++i) {
+ loadTo[i].note = stream.readByte();
+ loadTo[i].patch = stream.readByte();
+ loadTo[i].duration = stream.readUint16BE();
+ loadTo[i].volume = stream.readByte();
+ loadTo[i].pan = stream.readByte();
+ }
+
+ ptr = loadTo;
+ return true;
+}
+
+bool StaticResource::loadRoomTable(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ uint32 count = stream.readUint32BE();
+ size = count;
+ Room *loadTo = new Room[count];
+ assert(loadTo);
+
+ for (uint32 i = 0; i < count; ++i) {
+ loadTo[i].nameIndex = stream.readByte();
+ loadTo[i].northExit = stream.readUint16BE();
+ loadTo[i].eastExit = stream.readUint16BE();
+ loadTo[i].southExit = stream.readUint16BE();
+ loadTo[i].westExit = stream.readUint16BE();
+ memset(&loadTo[i].itemsTable[0], 0xFF, sizeof(byte) * 6);
+ memset(&loadTo[i].itemsTable[6], 0, sizeof(byte) * 6);
+ memset(loadTo[i].itemsXPos, 0, sizeof(uint16) * 12);
+ memset(loadTo[i].itemsYPos, 0, sizeof(uint8) * 12);
+ memset(loadTo[i].needInit, 0, sizeof(loadTo[i].needInit));
+ }
+
+ ptr = loadTo;
+ return true;
+}
+
+bool StaticResource::loadHoFSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ int numSeq = stream.readUint16BE();
+ uint32 offset = 2;
+ HoFSequence *tmp_s = new HoFSequence[numSeq];
+
+ size = sizeof(HoFSeqData) + numSeq * (sizeof(HoFSequence) + 28);
+
+ for (int i = 0; i < numSeq; i++) {
+ stream.seek(offset, SEEK_SET); offset += 2;
+ stream.seek(stream.readUint16BE(), SEEK_SET);
+
+ tmp_s[i].flags = stream.readUint16BE();
+ tmp_s[i].wsaFile = new char[14];
+ stream.read(const_cast<char *>(tmp_s[i].wsaFile), 14);
+ tmp_s[i].cpsFile = new char[14];
+ stream.read(const_cast<char *>(tmp_s[i].cpsFile), 14);
+ tmp_s[i].fadeInTransitionType = stream.readByte();
+ tmp_s[i].fadeOutTransitionType = stream.readByte();
+ tmp_s[i].stringIndex1 = stream.readUint16BE();
+ tmp_s[i].stringIndex2 = stream.readUint16BE();
+ tmp_s[i].startFrame = stream.readUint16BE();
+ tmp_s[i].numFrames = stream.readUint16BE();
+ tmp_s[i].duration = stream.readUint16BE();
+ tmp_s[i].xPos = stream.readUint16BE();
+ tmp_s[i].yPos = stream.readUint16BE();
+ tmp_s[i].timeout = stream.readUint16BE();
+ }
+
+ stream.seek(offset, SEEK_SET); offset += 2;
+ int numSeqN = stream.readUint16BE();
+ HoFNestedSequence *tmp_n = new HoFNestedSequence[numSeqN];
+ size += (numSeqN * (sizeof(HoFNestedSequence) + 14));
+
+ for (int i = 0; i < numSeqN; i++) {
+ stream.seek(offset, SEEK_SET); offset += 2;
+ stream.seek(stream.readUint16BE(), SEEK_SET);
+
+ tmp_n[i].flags = stream.readUint16BE();
+ tmp_n[i].wsaFile = new char[14];
+ stream.read(const_cast<char *>(tmp_n[i].wsaFile), 14);
+ tmp_n[i].startframe = stream.readUint16BE();
+ tmp_n[i].endFrame = stream.readUint16BE();
+ tmp_n[i].frameDelay = stream.readUint16BE();
+ tmp_n[i].x = stream.readUint16BE();
+ tmp_n[i].y = stream.readUint16BE();
+ uint16 ctrlOffs = stream.readUint16BE();
+ tmp_n[i].fadeInTransitionType = stream.readUint16BE();
+ tmp_n[i].fadeOutTransitionType = stream.readUint16BE();
+
+ if (ctrlOffs) {
+ stream.seek(ctrlOffs, SEEK_SET);
+ int num_c = stream.readByte();
+ FrameControl *tmp_f = new FrameControl[num_c];
+
+ for (int ii = 0; ii < num_c; ii++) {
+ tmp_f[ii].index = stream.readUint16BE();
+ tmp_f[ii].delay = stream.readUint16BE();
+ }
+
+ tmp_n[i].wsaControl = (const FrameControl *)tmp_f;
+ size += (num_c * sizeof(FrameControl));
+
+ } else {
+ tmp_n[i].wsaControl = 0;
+ }
+ }
+
+ HoFSeqData *loadTo = new HoFSeqData;
+ assert(loadTo);
+
+ loadTo->seq = tmp_s;
+ loadTo->nestedSeq = tmp_n;
+ loadTo->numSeq = numSeq;
+ loadTo->numNestedSeq = numSeqN;
+
+ ptr = loadTo;
+ return true;
+}
+
+bool StaticResource::loadHoFSeqItemAnimData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.readByte();
+ HoFSeqItemAnimData *loadTo = new HoFSeqItemAnimData[size];
+ assert(loadTo);
+
+ for (int i = 0; i < size; i++) {
+ loadTo[i].itemIndex = stream.readSint16BE();
+ loadTo[i].y = stream.readUint16BE();
+ uint16 *tmp_f = new uint16[20];
+ for (int ii = 0; ii < 20; ii++)
+ tmp_f[ii] = stream.readUint16BE();
+ loadTo[i].frames = tmp_f;
+ }
+
+ ptr = loadTo;
+ return true;
+}
+
+bool StaticResource::loadItemAnimDefinition(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.readByte();
+ ItemAnimDefinition *loadTo = new ItemAnimDefinition[size];
+ assert(loadTo);
+
+ for (int i = 0; i < size; i++) {
+ loadTo[i].itemIndex = stream.readSint16BE();
+ loadTo[i].numFrames = stream.readByte();
+ FrameControl *tmp_f = new FrameControl[loadTo[i].numFrames];
+ for (int ii = 0; ii < loadTo[i].numFrames; ii++) {
+ tmp_f[ii].index = stream.readUint16BE();
+ tmp_f[ii].delay = stream.readUint16BE();
+ }
+ loadTo[i].frames = tmp_f;
+ }
+
+ ptr = loadTo;
+ return true;
+}
+
+void StaticResource::freeDummy(void *&ptr, int &size) {
+}
+
+void StaticResource::freeRawData(void *&ptr, int &size) {
+ uint8 *data = (uint8 *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeStringTable(void *&ptr, int &size) {
+ char **data = (char **)ptr;
+ while (size--)
+ delete[] data[size];
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeShapeTable(void *&ptr, int &size) {
+ Shape *data = (Shape *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeAmigaSfxTable(void *&ptr, int &size) {
+ AmigaSfxTable *data = (AmigaSfxTable *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeRoomTable(void *&ptr, int &size) {
+ Room *data = (Room *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeHoFSequenceData(void *&ptr, int &size) {
+ HoFSeqData *h = (HoFSeqData *)ptr;
+
+ for (int i = 0; i < h->numSeq; i++) {
+ delete[] h->seq[i].wsaFile;
+ delete[] h->seq[i].cpsFile;
+ }
+ delete[] h->seq;
+
+ for (int i = 0; i < h->numNestedSeq; i++) {
+ delete[] h->nestedSeq[i].wsaFile;
+ delete[] h->nestedSeq[i].wsaControl;
+ }
+ delete[] h->nestedSeq;
+
+ delete h;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeHoFSeqItemAnimData(void *&ptr, int &size) {
+ HoFSeqItemAnimData *d = (HoFSeqItemAnimData *)ptr;
+ for (int i = 0; i < size; i++)
+ delete[] d[i].frames;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeItemAnimDefinition(void *&ptr, int &size) {
+ ItemAnimDefinition *d = (ItemAnimDefinition *)ptr;
+ for (int i = 0; i < size; i++)
+ delete[] d[i].frames;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+#pragma mark -
+
+void KyraEngine_LoK::initStaticResource() {
+ int temp = 0;
+ _seq_Forest = _staticres->loadRawData(k1ForestSeq, temp);
+ _seq_KallakWriting = _staticres->loadRawData(k1KallakWritingSeq, temp);
+ _seq_KyrandiaLogo = _staticres->loadRawData(k1KyrandiaLogoSeq, temp);
+ _seq_KallakMalcolm = _staticres->loadRawData(k1KallakMalcolmSeq, temp);
+ _seq_MalcolmTree = _staticres->loadRawData(k1MalcolmTreeSeq, temp);
+ _seq_WestwoodLogo = _staticres->loadRawData(k1WestwoodLogoSeq, temp);
+ _seq_Demo1 = _staticres->loadRawData(k1Demo1Seq, temp);
+ _seq_Demo2 = _staticres->loadRawData(k1Demo2Seq, temp);
+ _seq_Demo3 = _staticres->loadRawData(k1Demo3Seq, temp);
+ _seq_Demo4 = _staticres->loadRawData(k1Demo4Seq, temp);
+ _seq_Reunion = _staticres->loadRawData(k1OutroReunionSeq, temp);
+
+ _seq_WSATable = _staticres->loadStrings(k1IntroWSAStrings, _seq_WSATable_Size);
+ _seq_CPSTable = _staticres->loadStrings(k1IntroCPSStrings, _seq_CPSTable_Size);
+ _seq_COLTable = _staticres->loadStrings(k1IntroCOLStrings, _seq_COLTable_Size);
+ _seq_textsTable = _staticres->loadStrings(k1IntroStrings, _seq_textsTable_Size);
+
+ _itemList = _staticres->loadStrings(k1ItemNames, _itemList_Size);
+ _takenList = _staticres->loadStrings(k1TakenStrings, _takenList_Size);
+ _placedList = _staticres->loadStrings(k1PlacedStrings, _placedList_Size);
+ _droppedList = _staticres->loadStrings(k1DroppedStrings, _droppedList_Size);
+ _noDropList = _staticres->loadStrings(k1NoDropStrings, _noDropList_Size);
+ _putDownFirst = _staticres->loadStrings(k1PutDownString, _putDownFirst_Size);
+ _waitForAmulet = _staticres->loadStrings(k1WaitAmuletString, _waitForAmulet_Size);
+ _blackJewel = _staticres->loadStrings(k1BlackJewelString, _blackJewel_Size);
+ _poisonGone = _staticres->loadStrings(k1PoisonGoneString, _poisonGone_Size);
+ _healingTip = _staticres->loadStrings(k1HealingTipString, _healingTip_Size);
+ _thePoison = _staticres->loadStrings(k1ThePoisonStrings, _thePoison_Size);
+ _fluteString = _staticres->loadStrings(k1FluteStrings, _fluteString_Size);
+ _wispJewelStrings = _staticres->loadStrings(k1WispJewelStrings, _wispJewelStrings_Size);
+ _magicJewelString = _staticres->loadStrings(k1MagicJewelStrings, _magicJewelString_Size);
+ _flaskFull = _staticres->loadStrings(k1FlaskFullString, _flaskFull_Size);
+ _fullFlask = _staticres->loadStrings(k1FullFlaskString, _fullFlask_Size);
+ _veryClever = _staticres->loadStrings(k1VeryCleverString, _veryClever_Size);
+ _homeString = _staticres->loadStrings(k1OutroHomeString, _homeString_Size);
+ _newGameString = _staticres->loadStrings(k1NewGameString, _newGameString_Size);
+
+ _healingShapeTable = _staticres->loadShapeTable(k1Healing1Shapes, _healingShapeTableSize);
+ _healingShape2Table = _staticres->loadShapeTable(k1Healing2Shapes, _healingShape2TableSize);
+ _posionDeathShapeTable = _staticres->loadShapeTable(k1PoisonDeathShapes, _posionDeathShapeTableSize);
+ _fluteAnimShapeTable = _staticres->loadShapeTable(k1FluteShapes, _fluteAnimShapeTableSize);
+ _winterScrollTable = _staticres->loadShapeTable(k1Winter1Shapes, _winterScrollTableSize);
+ _winterScroll1Table = _staticres->loadShapeTable(k1Winter2Shapes, _winterScroll1TableSize);
+ _winterScroll2Table = _staticres->loadShapeTable(k1Winter3Shapes, _winterScroll2TableSize);
+ _drinkAnimationTable = _staticres->loadShapeTable(k1DrinkShapes, _drinkAnimationTableSize);
+ _brandonToWispTable = _staticres->loadShapeTable(k1WispShapes, _brandonToWispTableSize);
+ _magicAnimationTable = _staticres->loadShapeTable(k1MagicAnimShapes, _magicAnimationTableSize);
+ _brandonStoneTable = _staticres->loadShapeTable(k1BranStoneShapes, _brandonStoneTableSize);
+
+ _characterImageTable = _staticres->loadStrings(k1CharacterImageFilenames, _characterImageTableSize);
+
+ _roomFilenameTable = _staticres->loadStrings(k1RoomFilenames, _roomFilenameTableSize);
+
+ _amuleteAnim = _staticres->loadRawData(k1AmuleteAnimSeq, temp);
+
+ const uint8 **palTable = new const uint8 *[k1SpecialPalette33 - k1SpecialPalette1 + 1];
+ for (int i = k1SpecialPalette1; i <= k1SpecialPalette33; ++i)
+ palTable[i - k1SpecialPalette1] = _staticres->loadRawData(i, temp);
+ _specialPalettes = palTable;
+
+ _guiStrings = _staticres->loadStrings(k1GUIStrings, _guiStringsSize);
+ _configStrings = _staticres->loadStrings(k1ConfigStrings, _configStringsSize);
+
+ _storyStrings = _staticres->loadStrings(k1PC98StoryStrings, _storyStringsSize);
+
+ // room list
+ const Room *tempRoomList = _staticres->loadRoomTable(k1RoomList, _roomTableSize);
+
+ if (_roomTableSize > 0) {
+ _roomTable = new Room[_roomTableSize];
+ assert(_roomTable);
+
+ memcpy(_roomTable, tempRoomList, _roomTableSize * sizeof(Room));
+ tempRoomList = 0;
+
+ _staticres->unloadId(k1RoomList);
+ }
+
+ // default shape table
+ const Shape *tempShapeTable = _staticres->loadShapeTable(k1DefaultShapes, _defaultShapeTableSize);
+
+ if (_defaultShapeTableSize > 0) {
+ _defaultShapeTable = new Shape[_defaultShapeTableSize];
+ assert(_defaultShapeTable);
+
+ memcpy(_defaultShapeTable, tempShapeTable, _defaultShapeTableSize * sizeof(Shape));
+ tempShapeTable = 0;
+
+ _staticres->unloadId(k1DefaultShapes);
+ }
+
+ // audio resource assignment
+ int soundFilesSize;
+ const char *const *soundFiles = _staticres->loadStrings(k1AudioTracks, soundFilesSize);
+ int soundFilesIntroSize = 0;
+ int cdaTableSize = 0;
+
+ const char *const *soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, soundFilesIntroSize);
+ const int32 *cdaTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, cdaTableSize);
+
+ // FIXME: It seems Kyra1 MAC CD includes AdLib and MIDI music and sfx, thus we enable
+ // support for those for now. (Based on patch #2767489 "Support for Mac Kyrandia 1 CD" by satz).
+ if (_flags.platform == Common::kPlatformDOS || _flags.platform == Common::kPlatformMacintosh) {
+ SoundResourceInfo_PC resInfoIntro(soundFilesIntro, soundFilesIntroSize);
+ SoundResourceInfo_PC resInfoIngame(soundFiles, soundFilesSize);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ } else if (_flags.platform == Common::kPlatformFMTowns) {
+ SoundResourceInfo_Towns resInfoIntro(soundFiles, soundFilesSize, cdaTable, cdaTableSize);
+ SoundResourceInfo_Towns resInfoIngame(soundFiles, soundFilesSize, cdaTable, cdaTableSize);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ SoundResourceInfo_PC98 resInfoIntro("INTRO%d.DAT");
+ SoundResourceInfo_PC98 resInfoIngame("KYRAM%d.DAT");
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ }
+}
+
+void KyraEngine_LoK::loadMouseShapes() {
+ _screen->loadBitmap("MOUSE.CPS", 3, 3, 0);
+ _screen->_curPage = 2;
+ _shapes[0] = _screen->encodeShape(0, 0, 8, 10, 0);
+ _shapes[1] = _screen->encodeShape(0, 0x17, 0x20, 7, 0);
+ _shapes[2] = _screen->encodeShape(0x50, 0x12, 0x10, 9, 0);
+ _shapes[3] = _screen->encodeShape(0x60, 0x12, 0x10, 11, 0);
+ _shapes[4] = _screen->encodeShape(0x70, 0x12, 0x10, 9, 0);
+ _shapes[5] = _screen->encodeShape(0x80, 0x12, 0x10, 11, 0);
+ _shapes[6] = _screen->encodeShape(0x90, 0x12, 0x10, 10, 0);
+ _shapes[360] = _screen->encodeShape(0x28, 0, 0x10, 13, 0);
+ _screen->setMouseCursor(1, 1, 0);
+ _screen->setMouseCursor(1, 1, _shapes[0]);
+ _screen->setShapePages(5, 3);
+}
+
+void KyraEngine_LoK::loadCharacterShapes() {
+ int curImage = 0xFF;
+ int videoPage = _screen->_curPage;
+ _screen->_curPage = 2;
+ for (int i = 0; i < 115; ++i) {
+ assert(i < _defaultShapeTableSize);
+ Shape *shape = &_defaultShapeTable[i];
+ if (shape->imageIndex == 0xFF) {
+ _shapes[i + 7] = 0;
+ continue;
+ }
+ if (shape->imageIndex != curImage) {
+ assert(shape->imageIndex < _characterImageTableSize);
+ _screen->loadBitmap(_characterImageTable[shape->imageIndex], 3, 3, 0);
+ curImage = shape->imageIndex;
+ }
+ _shapes[i + 7] = _screen->encodeShape(shape->x << 3, shape->y, shape->w << 3, shape->h, 1);
+ }
+ _screen->_curPage = videoPage;
+}
+
+void KyraEngine_LoK::loadSpecialEffectShapes() {
+ _screen->loadBitmap("EFFECTS.CPS", 3, 3, 0);
+ _screen->_curPage = 2;
+
+ int currShape;
+ for (currShape = 173; currShape < 183; currShape++)
+ _shapes[currShape] = _screen->encodeShape((currShape - 173) * 24, 0, 24, 24, 1);
+
+ for (currShape = 183; currShape < 190; currShape++)
+ _shapes[currShape] = _screen->encodeShape((currShape - 183) * 24, 24, 24, 24, 1);
+
+ for (currShape = 190; currShape < 201; currShape++)
+ _shapes[currShape] = _screen->encodeShape((currShape - 190) * 24, 48, 24, 24, 1);
+
+ for (currShape = 201; currShape < 206; currShape++)
+ _shapes[currShape] = _screen->encodeShape((currShape - 201) * 16, 106, 16, 16, 1);
+}
+
+void KyraEngine_LoK::loadItems() {
+ int shape;
+
+ _screen->loadBitmap("JEWELS3.CPS", 3, 3, 0);
+ _screen->_curPage = 2;
+
+ _shapes[323] = 0;
+
+ for (shape = 1; shape < 6; shape++)
+ _shapes[323 + shape] = _screen->encodeShape((shape - 1) * 32, 0, 32, 17, 0);
+
+ for (shape = 330; shape <= 334; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 330) * 32, 102, 32, 17, 0);
+
+ for (shape = 335; shape <= 339; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 335) * 32, 17, 32, 17, 0);
+
+ for (shape = 340; shape <= 344; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 340) * 32, 34, 32, 17, 0);
+
+ for (shape = 345; shape <= 349; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 345) * 32, 51, 32, 17, 0);
+
+ for (shape = 350; shape <= 354; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 350) * 32, 68, 32, 17, 0);
+
+ for (shape = 355; shape <= 359; shape++)
+ _shapes[shape] = _screen->encodeShape((shape - 355) * 32, 85, 32, 17, 0);
+
+
+ _screen->loadBitmap("ITEMS.CPS", 3, 3, 0);
+ _screen->_curPage = 2;
+
+ for (int i = 0; i < 107; i++) {
+ shape = findDuplicateItemShape(i);
+
+ if (shape != -1)
+ _shapes[216 + i] = _shapes[216 + shape];
+ else
+ _shapes[216 + i] = _screen->encodeShape((i % 20) * 16, i / 20 * 16, 16, 16, 0);
+ }
+
+ _res->loadFileToBuf("_ITEM_HT.DAT", &_itemHtDat, sizeof(_itemHtDat));
+}
+
+void KyraEngine_LoK::loadButtonShapes() {
+ _screen->loadBitmap("BUTTONS2.CPS", 3, 3, 0);
+ _screen->_curPage = 2;
+ _gui->_scrollUpButton.data0ShapePtr = _screen->encodeShape(0, 0, 24, 14, 1);
+ _gui->_scrollUpButton.data1ShapePtr = _screen->encodeShape(24, 0, 24, 14, 1);
+ _gui->_scrollUpButton.data2ShapePtr = _screen->encodeShape(48, 0, 24, 14, 1);
+ _gui->_scrollDownButton.data0ShapePtr = _screen->encodeShape(0, 15, 24, 14, 1);
+ _gui->_scrollDownButton.data1ShapePtr = _screen->encodeShape(24, 15, 24, 14, 1);
+ _gui->_scrollDownButton.data2ShapePtr = _screen->encodeShape(48, 15, 24, 14, 1);
+ _screen->_curPage = 0;
+}
+
+void KyraEngine_LoK::loadMainScreen(int page) {
+ _screen->clearPage(page);
+
+ if (((_flags.lang == Common::EN_ANY || _flags.lang == Common::RU_RUS) && !_flags.isTalkie && _flags.platform == Common::kPlatformDOS) || _flags.platform == Common::kPlatformAmiga)
+ _screen->loadBitmap("MAIN15.CPS", page, page, &_screen->getPalette(0));
+ else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN || (_flags.isTalkie && _flags.lang == Common::IT_ITA))
+ _screen->loadBitmap("MAIN_ENG.CPS", page, page, 0);
+ else if (_flags.lang == Common::FR_FRA)
+ _screen->loadBitmap("MAIN_FRE.CPS", page, page, 0);
+ else if (_flags.lang == Common::DE_DEU)
+ _screen->loadBitmap("MAIN_GER.CPS", page, page, 0);
+ else if (_flags.lang == Common::ES_ESP)
+ _screen->loadBitmap("MAIN_SPA.CPS", page, page, 0);
+ else if (_flags.lang == Common::IT_ITA)
+ _screen->loadBitmap("MAIN_ITA.CPS", page, page, 0);
+ else
+ warning("no main graphics file found");
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, page, 0, Screen::CR_NO_P_CHECK);
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->copyPalette(1, 0);
+ _screen->setInterfacePalette(_screen->getPalette(1), 0x3F, 0x3F, 0x3F);
+
+ // TODO: Move this to a better place
+ _screen->enableInterfacePalette(true);
+ }
+}
+
+void KyraEngine_HoF::initStaticResource() {
+ _ingamePakList = _staticres->loadStrings(k2IngamePakFiles, _ingamePakListSize);
+ _ingameSoundList = _staticres->loadStrings(k2IngameSfxFiles, _ingameSoundListSize);
+ _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(k2IngameSfxIndex, _ingameSoundIndexSize);
+ _musicFileListIntro = _staticres->loadStrings(k2SeqplayIntroTracks, _musicFileListIntroSize);
+ _musicFileListIngame = _staticres->loadStrings(k2IngameTracks, _musicFileListIngameSize);
+ _musicFileListFinale = _staticres->loadStrings(k2SeqplayFinaleTracks, _musicFileListFinaleSize);
+ _cdaTrackTableIntro = _staticres->loadRawData(k2SeqplayIntroCDA, _cdaTrackTableIntroSize);
+ _cdaTrackTableIngame = _staticres->loadRawData(k2IngameCDA, _cdaTrackTableIngameSize);
+ _cdaTrackTableFinale = _staticres->loadRawData(k2SeqplayFinaleCDA, _cdaTrackTableFinaleSize);
+ _ingameTalkObjIndex = (const uint16 *)_staticres->loadRawData(k2IngameTalkObjIndex, _ingameTalkObjIndexSize);
+ _ingameTimJpStr = _staticres->loadStrings(k2IngameTimJpStrings, _ingameTimJpStrSize);
+ _itemAnimDefinition = _staticres->loadItemAnimDefinition(k2IngameShapeAnimData, _itemAnimDefinitionSize);
+
+ // assign music data
+ if (_flags.platform == Common::kPlatformDOS) {
+ SoundResourceInfo_PC resInfoIntro(_musicFileListIntro, _musicFileListIntroSize);
+ SoundResourceInfo_PC resInfoIngame(_musicFileListIngame, _musicFileListIngameSize);
+ SoundResourceInfo_PC resInfoFinale(_musicFileListFinale, _musicFileListFinaleSize);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ } else if (_flags.platform == Common::kPlatformFMTowns) {
+ SoundResourceInfo_TownsPC98V2 resInfoIntro(0, 0, "intro%d.twn", (const uint16*)_cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1);
+ SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "km%02d.twn", (const uint16*)_cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1);
+ SoundResourceInfo_TownsPC98V2 resInfoFinale(0, 0, "finale%d.twn", (const uint16*)_cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ SoundResourceInfo_TownsPC98V2 resInfoIntro(0, 0, "intro%d.86", 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "km%02d.86", 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoFinale(0, 0, "finale%d.86", 0, 0);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ }
+}
+
+void KyraEngine_MR::initStaticResource() {
+ int tmp = 0;
+ _mainMenuStrings = _staticres->loadStrings(k3MainMenuStrings, _mainMenuStringsSize);
+ _soundList = _staticres->loadStrings(k3MusicFiles, _soundListSize);
+ _scoreTable = _staticres->loadRawData(k3ScoreTable, _scoreTableSize);
+ _sfxFileList = _staticres->loadStrings(k3SfxFiles, _sfxFileListSize);
+ _sfxFileMap = _staticres->loadRawData(k3SfxMap, _sfxFileMapSize);
+ _itemAnimDefinition = _staticres->loadItemAnimDefinition(k3ItemAnimData, tmp);
+ _itemMagicTable = _staticres->loadRawData(k3ItemMagicTable, tmp);
+ _itemStringMap = _staticres->loadRawData(k3ItemStringMap, _itemStringMapSize);
+}
+
+const uint8 Screen_LoK_16::_palette16[48] = {
+ 0x00, 0x00, 0x00, 0x02, 0x07, 0x0B, 0x0C, 0x06, 0x04,
+ 0x0E, 0x09, 0x07, 0x00, 0x06, 0x03, 0x00, 0x0C, 0x07,
+ 0x0A, 0x0A, 0x0A, 0x08, 0x03, 0x03, 0x02, 0x02, 0x02,
+ 0x08, 0x0B, 0x0E, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x05, 0x05, 0x05, 0x00, 0x0F, 0x0F, 0x0F, 0x0D, 0x00,
+ 0x0F, 0x0F, 0x0F
+};
+
+const ScreenDim Screen_LoK::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x08, 0x48, 0x18, 0x38, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x01, 0x08, 0x26, 0x80, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x00, 0xC2, 0x28, 0x06, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x00, 0x90, 0x28, 0x38, 0x04, 0x0C, 0x00, 0x00 },
+ { 0x01, 0x94, 0x26, 0x30, 0x04, 0x1B, 0x00, 0x00 },
+ { 0x00, 0x90, 0x28, 0x38, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x01, 0x96, 0x26, 0x32, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x00, 0x00, 0x28, 0x88, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x01, 0x20, 0x26, 0x80, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x03, 0x28, 0x22, 0x46, 0x0F, 0x0D, 0x00, 0x00 }
+};
+
+const int Screen_LoK::_screenDimTableCount = ARRAYSIZE(Screen_LoK::_screenDimTable);
+
+const ScreenDim Screen_HoF::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x08, 0x48, 0x18, 0x38, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x00, 0x00, 0x28, 0x90, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x00, 0xC2, 0x28, 0x06, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x00, 0x90, 0x28, 0x38, 0x96, 0xCF, 0x00, 0x00 },
+ { 0x01, 0x94, 0x26, 0x30, 0x96, 0x1B, 0x00, 0x00 },
+ { 0x00, 0x90, 0x28, 0x38, 0xC7, 0xCC, 0x00, 0x00 },
+ { 0x01, 0x96, 0x26, 0x32, 0xC7, 0xCC, 0x00, 0x00 },
+ { 0x00, 0x00, 0x28, 0x88, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x00, 0x08, 0x28, 0xB8, 0xC7, 0xCF, 0x00, 0x00 },
+ { 0x01, 0x28, 0x26, 0x46, 0xC7, 0xCC, 0x00, 0x00 },
+ { 0x0A, 0x96, 0x14, 0x30, 0x19, 0xF0, 0x00, 0x00 } // menu, just present for current menu code
+};
+
+const int Screen_HoF::_screenDimTableCount = ARRAYSIZE(Screen_HoF::_screenDimTable);
+
+const ScreenDim Screen_MR::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0xFF, 0xF0, 0x00, 0x00 },
+ { 0x08, 0x48, 0x18, 0x38, 0xFF, 0xF0, 0x00, 0x00 },
+ { 0x00, 0x00, 0x28, 0xBC, 0xFF, 0xF0, 0x00, 0x00 },
+ { 0x0A, 0x96, 0x14, 0x30, 0x19, 0xF0, 0x00, 0x00 }
+};
+
+const int Screen_MR::_screenDimTableCount = ARRAYSIZE(Screen_MR::_screenDimTable);
+
+const int8 KyraEngine_v1::_addXPosTable[] = {
+ 4, 4, 0, -4, -4, -4, 0, 4
+};
+
+const int8 KyraEngine_v1::_addYPosTable[] = {
+ 0, -2, -2, -2, 0, 2, 2, 2
+};
+
+const int8 KyraEngine_v1::_charAddXPosTable[] = {
+ 0, 4, 4, 4, 0, -4, -4, -4
+};
+
+const int8 KyraEngine_v1::_charAddYPosTable[] = {
+ -2, -2, 0, 2, 2, 2, 0, -2
+};
+
+const uint16 KyraEngine_LoK::_itemPosX[] = {
+ 95, 115, 135, 155, 175, 95, 115, 135, 155, 175
+};
+
+const uint8 KyraEngine_LoK::_itemPosY[] = {
+ 160, 160, 160, 160, 160, 181, 181, 181, 181, 181
+};
+
+void GUI_LoK::initStaticResource() {
+ GUI_V1_BUTTON(_scrollUpButton, 0x12, 1, 1, 1, 0x483, 0, 0, 0, 0x18, 0x0F, 0);
+ GUI_V1_BUTTON(_scrollDownButton, 0x13, 1, 1, 1, 0x483, 0, 0, 0, 0x18, 0x0F, 0);
+
+ GUI_V1_BUTTON(_menuButtonData[0], 0x0C, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+ GUI_V1_BUTTON(_menuButtonData[1], 0x0D, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+ GUI_V1_BUTTON(_menuButtonData[2], 0x0E, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+ GUI_V1_BUTTON(_menuButtonData[3], 0x0F, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+ GUI_V1_BUTTON(_menuButtonData[4], 0x10, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+ GUI_V1_BUTTON(_menuButtonData[5], 0x11, 1, 1, 1, 0x487, 0, 0, 0, 0, 0, 0);
+
+ delete[] _menu;
+ _menu = new Menu[6];
+ assert(_menu);
+
+ Button::Callback quitPlayingFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::quitPlaying);
+ Button::Callback loadGameMenuFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::loadGameMenu);
+ Button::Callback cancelSubMenuFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::cancelSubMenu);
+
+ GUI_V1_MENU(_menu[0], -1, -1, 0x100, 0x8B, 248, 249, 250, 0, 251, -1, 8, 0, 5, -1, -1, -1, -1);
+ GUI_V1_MENU_ITEM(_menu[0].item[0], 1, 0, 0, 0, -1, -1, 0x1E, 0xDC, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[0].item[1], 1, 0, 0, 0, -1, -1, 0x2F, 0xDC, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[0].item[2], 1, 0, 0, 0, -1, -1, 0x40, 0xDC, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[0].item[3], 1, 0, 0, 0, -1, -1, 0x51, 0xDC, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[0].item[4], 1, 0, 0, 0, -1, 0, 0x6E, 0xDC, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[0].item[0].callback = loadGameMenuFunctor;
+ _menu[0].item[1].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::saveGameMenu);
+ _menu[0].item[2].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::gameControlsMenu);
+ _menu[0].item[3].callback = quitPlayingFunctor;
+ _menu[0].item[4].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::resumeGame);
+
+ GUI_V1_MENU(_menu[1], -1, -1, 0x140, 0x38, 248, 249, 250, 0, 254, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V1_MENU_ITEM(_menu[1].item[0], 1, 0, 0, 0, 0x18, 0, 0x1E, 0x48, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[1].item[1], 1, 0, 0, 0, 0xD8, 0, 0x1E, 0x48, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[1].item[0].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::quitConfirmYes);
+ _menu[1].item[1].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::quitConfirmNo);
+
+ GUI_V1_MENU(_menu[2], -1, -1, 0x120, 0xA0, 248, 249, 250, 0, 251, -1, 8, 0, 6, 132, 22, 132, 124);
+ GUI_V1_MENU_ITEM(_menu[2].item[0], 1, 0, 0, 0, -1, 255, 0x27, 0x100, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[2].item[1], 1, 0, 0, 0, -1, 255, 0x38, 0x100, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[2].item[2], 1, 0, 0, 0, -1, 255, 0x49, 0x100, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[2].item[3], 1, 0, 0, 0, -1, 255, 0x5A, 0x100, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[2].item[4], 1, 0, 0, 0, -1, 255, 0x6B, 0x100, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[2].item[5], 1, 0, 0, 0, 0xB8, 0, 0x86, 0x58, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[2].item[5].callback = cancelSubMenuFunctor;
+
+ GUI_V1_MENU(_menu[3], -1, -1, 288, 67, 248, 249, 250, 0, 251, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V1_MENU_ITEM(_menu[3].item[0], 1, 0, 0, 0, 24, 0, 44, 85, 15, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[3].item[1], 1, 0, 0, 0, 179, 0, 44, 85, 15, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[3].item[0].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::savegameConfirm);
+ _menu[3].item[1].callback = cancelSubMenuFunctor;
+
+ GUI_V1_MENU(_menu[4], -1, -1, 0xD0, 0x4C, 248, 249, 250, 0, 251, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V1_MENU_ITEM(_menu[4].item[0], 1, 0, 0, 0, -1, -1, 0x1E, 0xB4, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[4].item[1], 1, 0, 0, 0, -1, -1, 0x2F, 0xB4, 0x0F, 252, 253, -1, 0, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[4].item[0].callback = loadGameMenuFunctor;
+ _menu[4].item[1].callback = quitPlayingFunctor;
+
+ GUI_V1_MENU(_menu[5], -1, -1, 0x130, 0x99, 248, 249, 250, 0, 251, -1, 8, 0, 6, -1, -1, -1, -1);
+ GUI_V1_MENU_ITEM(_menu[5].item[0], 1, 0, 0, 0, 0xA5, 0, 0x1E, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x20, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[5].item[1], 1, 0, 0, 0, 0xA5, 0, 0x2F, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x31, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[5].item[2], 1, 0, 0, 0, 0xA5, 0, 0x40, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x42, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[5].item[3], 1, 0, 0, 0, 0xA5, 0, 0x51, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x53, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[5].item[4], 1, 0, 0, 0, 0xA5, 0, 0x62, 0x80, 0x0F, 252, 253, 5, 0, 248, 249, 250, -1, 0, 0x10, 0x65, 0, 0);
+ GUI_V1_MENU_ITEM(_menu[5].item[5], 1, 0, 0, 0, -1, 0, 0x7F, 0x6C, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
+ _menu[5].item[0].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeMusic);
+ _menu[5].item[1].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeSounds);
+ _menu[5].item[2].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeWalk);
+ _menu[5].item[4].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsChangeText);
+ _menu[5].item[5].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::controlsApply);
+
+ // The AMIGA version uses different colors, due to its 32 color nature. We did setup the 256 color version
+ // colors above, so we need to overwrite those with the correct values over here.
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
+ for (int i = 0; i < 6; ++i) {
+ _menu[i].bkgdColor = 17;
+ _menu[i].color1 = 31;
+ _menu[i].color2 = 18;
+
+ for (int j = 0; j < _menu[i].numberOfItems; ++j) {
+ _menu[i].item[j].bkgdColor = 17;
+ _menu[i].item[j].color1 = 31;
+ _menu[i].item[j].color2 = 18;
+ }
+ }
+ }
+}
+
+void KyraEngine_LoK::setupButtonData() {
+ delete[] _buttonData;
+ delete[] _buttonDataListPtr;
+
+ _buttonData = new Button[15];
+ assert(_buttonData);
+ _buttonDataListPtr = new Button *[15];
+ assert(_buttonDataListPtr);
+
+ GUI_V1_BUTTON(_buttonData[1], 0x01, 1, 1, 1, 0x0487, 0, 0x009, 0xA4, 0x36, 0x1E, 0);
+ _buttonData[1].buttonCallback = BUTTON_FUNCTOR(GUI_LoK, _gui, &GUI_LoK::buttonMenuCallback);
+
+ Button::Callback inventoryFunctor = BUTTON_FUNCTOR(KyraEngine_LoK, this, &KyraEngine_LoK::buttonInventoryCallback);
+ for (int i = 2; i <= 10; ++i)
+ _buttonData[i].buttonCallback = inventoryFunctor;
+ _buttonData[0].buttonCallback = inventoryFunctor;
+ GUI_V1_BUTTON(_buttonData[0], 0x02, 0, 0, 0, 0x0400, 0, 0x05D, 0x9E, 0x13, 0x13, 0);
+ GUI_V1_BUTTON(_buttonData[2], 0x03, 0, 0, 0, 0x0400, 0, 0x071, 0x9E, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[3], 0x04, 0, 0, 0, 0x0400, 0, 0x085, 0x9E, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[4], 0x05, 0, 0, 0, 0x0400, 0, 0x099, 0x9E, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[5], 0x06, 0, 0, 0, 0x0400, 0, 0x0AD, 0x9E, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[6], 0x07, 0, 0, 0, 0x0400, 0, 0x05D, 0xB3, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[7], 0x08, 0, 0, 0, 0x0400, 0, 0x071, 0xB3, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[8], 0x09, 0, 0, 0, 0x0400, 0, 0x085, 0xB3, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[9], 0x0A, 0, 0, 0, 0x0400, 0, 0x099, 0xB3, 0x13, 0x14, 0);
+ GUI_V1_BUTTON(_buttonData[10], 0x0B, 0, 0, 0, 0x0400, 0, 0x0AD, 0xB3, 0x13, 0x14, 0);
+
+ Button::Callback amuletFunctor = BUTTON_FUNCTOR(KyraEngine_LoK, this, &KyraEngine_LoK::buttonAmuletCallback);
+ GUI_V1_BUTTON(_buttonData[11], 0x15, 1, 1, 1, 0x0487, 0, 0x0FD, 0x9C, 0x1A, 0x12, 0);
+ GUI_V1_BUTTON(_buttonData[12], 0x16, 1, 1, 1, 0x0487, 0, 0x0E7, 0xAA, 0x1A, 0x12, 0);
+ GUI_V1_BUTTON(_buttonData[13], 0x17, 1, 1, 1, 0x0487, 0, 0x0FD, 0xB5, 0x1A, 0x12, 0);
+ GUI_V1_BUTTON(_buttonData[14], 0x18, 1, 1, 1, 0x0487, 0, 0x113, 0xAA, 0x1A, 0x12, 0);
+ for (int i = 11; i <= 14; ++i)
+ _buttonData[i].buttonCallback = amuletFunctor;
+
+ for (int i = 1; i < 15; ++i)
+ _buttonDataListPtr[i - 1] = &_buttonData[i];
+ _buttonDataListPtr[14] = 0;
+}
+
+const uint8 KyraEngine_LoK::_magicMouseItemStartFrame[] = {
+ 0xAD, 0xB7, 0xBE, 0x00
+};
+
+const uint8 KyraEngine_LoK::_magicMouseItemEndFrame[] = {
+ 0xB1, 0xB9, 0xC2, 0x00
+};
+
+const uint8 KyraEngine_LoK::_magicMouseItemStartFrame2[] = {
+ 0xB2, 0xBA, 0xC3, 0x00
+};
+
+const uint8 KyraEngine_LoK::_magicMouseItemEndFrame2[] = {
+ 0xB6, 0xBD, 0xC8, 0x00
+};
+
+const uint16 KyraEngine_LoK::_amuletX[] = { 231, 275, 253, 253 };
+const uint16 KyraEngine_LoK::_amuletY[] = { 170, 170, 159, 181 };
+
+const uint16 KyraEngine_LoK::_amuletX2[] = { 0x000, 0x0FD, 0x0E7, 0x0FD, 0x113, 0x000 };
+const uint16 KyraEngine_LoK::_amuletY2[] = { 0x000, 0x09F, 0x0AA, 0x0B5, 0x0AA, 0x000 };
+
+const int8 KyraEngine_LoK::_dosTrackMap[] = {
+ -1, 0, -1, 1, 0, 3, 0, 2,
+ 0, 4, 1, 2, 1, 3, 1, 4,
+ 1, 92, 1, 6, 1, 7, 2, 2,
+ 2, 3, 2, 4, 2, 5, 2, 6,
+ 2, 7, 3, 3, 3, 4, 1, 8,
+ 1, 9, 4, 2, 4, 3, 4, 4,
+ 4, 5, 4, 6, 4, 7, 4, 8,
+ 1, 11, 1, 12, 1, 14, 1, 13,
+ 4, 9, 5, 12, 6, 2, 6, 6,
+ 6, 7, 6, 8, 6, 9, 6, 3,
+ 6, 4, 6, 5, 7, 2, 7, 3,
+ 7, 4, 7, 5, 7, 6, 7, 7,
+ 7, 8, 7, 9, 8, 2, 8, 3,
+ 8, 4, 8, 5, 6, 11, 5, 11
+};
+
+const int KyraEngine_LoK::_dosTrackMapSize = ARRAYSIZE(KyraEngine_LoK::_dosTrackMap);
+
+const int8 KyraEngine_LoK::_amigaTrackMap[] = {
+ 0, 1, 32, 26, 31, 30, 33, 33,
+ 32, 17, 27, 32, 25, 29, 25, 24,
+ 23, 26, 26, 30, 28, 21, 21, 15,
+ 3, 15, 23, 25, 33, 21, 30, 22,
+ 15, 3, 33, 11, 12, 13, 14, 22,
+ 22, 22, 3, 3, 3, 23, 3, 3,
+ 23, 3, 3, 3, 3, 3, 3, 33
+};
+
+const int KyraEngine_LoK::_amigaTrackMapSize = ARRAYSIZE(KyraEngine_LoK::_amigaTrackMap);
+
+// kyra engine v2 static data
+
+const int GUI_v2::_sliderBarsPosition[] = {
+ 0x92, 0x1F, 0x92, 0x30, 0x92, 0x41, 0x92, 0x52
+};
+
+// kyra 2 static res
+
+const char *const KyraEngine_HoF::_languageExtension[] = {
+ "ENG",
+ "FRE",
+ "GER",/*,
+ "ITA", Italian and Spanish were never included
+ "SPA"*/
+ "JPN",
+};
+
+const char *const KyraEngine_HoF::_scriptLangExt[] = {
+ "EMC",
+ "FMC",
+ "GMC",/*,
+ "IMC", Italian and Spanish were never included
+ "SMC"*/
+ "JMC"
+};
+
+const uint8 KyraEngine_HoF::_characterFrameTable[] = {
+ 0x19, 0x09, 0x09, 0x12, 0x12, 0x12, 0x09, 0x09
+};
+
+const int KyraEngine_HoF::_inventoryX[] = {
+ 0x4F, 0x63, 0x77, 0x8B, 0x9F, 0x4F, 0x63, 0x77, 0x8B, 0x9F
+};
+
+const int KyraEngine_HoF::_inventoryY[] = {
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
+};
+
+const byte KyraEngine_HoF::_itemStringMap[] = {
+ 2, 2, 0, 0, 2, 2, 2, 0,
+ 2, 2, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 1, 0, 2, 2, 2, 2, 0,
+ 3, 0, 3, 2, 2, 2, 3, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 2,
+ 2, 0, 0, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 0,
+ 2, 2, 2, 0, 0, 1, 3, 2,
+ 2, 2, 2, 2, 2, 0, 0, 0,
+ 0, 2, 2, 1, 0, 1, 2, 0,
+ 0, 0, 0, 0, 0, 2, 2, 2,
+ 2, 2, 2, 2, 0, 2, 2, 2,
+ 2, 3, 2, 0, 0, 0, 0, 1,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 0, 2,
+ 0, 2, 0, 0, 0, 0, 0, 0
+};
+
+const int KyraEngine_HoF::_itemStringMapSize = ARRAYSIZE(KyraEngine_HoF::_itemStringMap);
+
+const int8 KyraEngine_HoF::_dosTrackMap[] = {
+ -1, 0, -1, 1, 9, 6, 5, 4,
+ 8, 3, -2, 0, -2, 0, 2, 3,
+ -2, 0, -2, 0, -2, 0, -2, 0,
+ 0, 2, 0, 3, 1, 2, 1, 3,
+ 2, 2, 2, 0, 3, 2, 3, 3,
+ 3, 4, 4, 2, 5, 2, 5, 3,
+ 5, 4, 6, 2, 6, 3, 6, 4,
+ 6, 5, 6, 6, 6, 7, 6, 8,
+ 6, 0, 6, 9, 7, 2, 7, 3,
+ 7, 4, 7, 5, 8, 6, 7, 6,
+ 7, 7, 7, 8, 7, 9, 8, 2,
+ 14, 2, 8, 4, 8, 7, 8, 8,
+ 8, 9, 9, 2, 9, 3, 9, 4,
+ 9, 5, 9, 7, 9, 8, 9, 9,
+ 10, 2, 10, 3, 10, 4, 10, 5,
+ 10, 6, 10, 7, 11, 2, 11, 3,
+ 11, 4, 11, 5, 11, 6, 11, 7,
+ 11, 8, 11, 9, 12, 2, 12, 3,
+ 12, 4, 12, 5, 12, 6, 12, 7,
+ 12, 8, 12, 9, 13, 2, 4, 7,
+ 14, 3, 14, 4, 14, 5, 4, 2,
+ 4, 3, 4, 4, 4, 5, 4, 6
+};
+
+const int KyraEngine_HoF::_dosTrackMapSize = ARRAYSIZE(KyraEngine_HoF::_dosTrackMap);
+
+const int8 KyraEngine_HoF::_mt32SfxMap[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 49, 27, 5, 36, 13,
+ -1, -1, 68, 55, 37, 73, 43, 61,
+ 49, -1, 56, -1, 62, 38, -1, -1,
+ 61, -1, -1, 31, 70, 2, 45, -1,
+ 45, -1, -1, -1, 10, 14, 24, 25,
+ -1, -1, 59, 9, 26, -1, 71, 79,
+ 12, 9, -1, -1, 61, -1, -1, 65,
+ 66, 50, 27, 24, 29, 29, 15, 16,
+ 17, 18, 19, 20, 21, 57, -1, -1,
+ 34, 3, -1, 56, 56, -1, -1, 50,
+ 43, 68, 32, 33, 67, 25, 60, 40,
+ 39, 11, 24, 2, 60, 3, 46, 54,
+ 1, 8, -1, -1, 41, 42, 37, 74,
+ 69, 62, 58, 27, -1, -1, -1, -1,
+ 48, 4, -1, 25, 39, 40, 24, 58,
+ 35, 4, 4, 4, -1, 50, -1, 6,
+ 8, -1, -1, -1, -1, -1, 53, 52,
+ -1, 63, 47, -1, -1, -1, 53, -1,
+ 29, -1, -1, 79, -1, 41, 12, -1,
+ -1, -1, 26, -1, 7, 27, 72, 51,
+ 23, 51, 64, -1, -1, -1, 27, 76,
+ 77, 78, 28, 47, -1, -1, 53, -1,
+ -1, -1, -1, -1, 2, 22, -1, 51,
+ 58, -1, -1, 30, -1, 79, -1, -1,
+ 22, 36, 1, -1, 12, 1, -1, -1,
+ 41, -1, 76, 77, 47
+};
+
+const int KyraEngine_HoF::_mt32SfxMapSize = ARRAYSIZE(KyraEngine_HoF::_mt32SfxMap);
+
+const int8 KyraEngine_HoF::_gmSfxMap[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 31, 25, 19, 12, 4,
+ -1, -1, 46, 18, -1, 21, 15, -1,
+ 31, -1, -1, -1, -1, -1, 47, -1,
+ 33, -1, 36, -1, -1, 23, 48, -1,
+ 48, -1, -1, 49, -1, 50, 22, 24,
+ 51, -1, 52, 20, -1, -1, 22, 53,
+ 3, 20, 47, 54, 33, -1, 55, 56,
+ 57, 33, -1, 51, 58, -1, 5, 6,
+ 7, 8, 9, 10, 11, 22, -1, -1,
+ -1, 24, -1, 26, 17, -1, -1, 33,
+ 15, -1, 23, 23, -1, 22, -1, 23,
+ 24, 21, 22, -1, -1, 24, 16, -1,
+ 1, 48, -1, -1, 13, 14, -1, 29,
+ 64, -1, -1, 25, -1, -1, -1, -1,
+ -1, 2, 13, 24, 23, 23, 22, -1,
+ 60, 2, 2, 2, -1, 33, -1, 61,
+ 48, 62, -1, 39, -1, -1, 28, 63,
+ 33, -1, 17, -1, 45, 45, 28, 55,
+ 34, -1, -1, 34, 55, 13, -1, 47,
+ 54, -1, -1, 33, 44, 25, -1, -1,
+ -1, 32, -1, -1, -1, -1, 25, 37,
+ 37, 37, 26, 43, -1, 42, 24, -1,
+ -1, -1, -1, -1, 23, 32, -1, 32,
+ -1, -1, -1, 27, 41, 34, -1, 40,
+ 32, -1, 16, 40, -1, 16, 38, 39,
+ 13, -1, 37, 28, 33
+};
+
+const int KyraEngine_HoF::_gmSfxMapSize = ARRAYSIZE(KyraEngine_HoF::_gmSfxMap);
+
+const int8 KyraEngine_HoF::_pcSpkSfxMap[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 0, 1, 2, 3, 4,
+ 5, 6, -1, 7, 8, 9, 10, -1,
+ 6, -1, -1, 11, -1, 12, -1, -1,
+ -1, -1, -1, 13, -1, 39, 14, 15,
+ 3, 16, 16, -1, -1, -1, 17, 18,
+ 5, -1, -1, -1, -1, -1, 19, 20,
+ 21, -1, 22, 23, -1, -1, -1, -1,
+ -1, -1, 39, -1, 24, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1,
+ -1, 2, -1, -1, -1, -1, -1, 21,
+ 10, -1, -1, -1, -1, 17, -1, 17,
+ 40, -1, 18, 38, -1, 40, 33, -1,
+ 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 42, 43, 44, 45, -1, -1,
+ -1, -1, -1, -1, 46, -1, 5, 47,
+ 48, -1, -1, -1, -1, -1, 49, 50,
+ -1, 40, -1, 24, -1, -1, 43, -1,
+ -1, 38, -1, -1, -1, 51, -1, -1,
+ -1, -1, -1, -1, -1, 9, -1, 52,
+ 53, 40, -1, -1, -1, -1, -1, -1,
+ -1, -1, 50, -1, -1, -1, 11, 54,
+ 5, -1, -1, -1, -1, 11, 7, 55,
+ 8, 36, -1, -1, -1, -1, -1, -1,
+ 11, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 24
+};
+
+const int KyraEngine_HoF::_pcSpkSfxMapSize = ARRAYSIZE(KyraEngine_HoF::_pcSpkSfxMap);
+
+void KyraEngine_HoF::initInventoryButtonList() {
+ delete[] _inventoryButtons;
+
+ _inventoryButtons = new Button[15];
+ assert(_inventoryButtons);
+
+ GUI_V2_BUTTON(_inventoryButtons[0], 0x1, 0x4F, 0, 1, 1, 1, 0x4487, 0, 0x00A, 0x95, 0x39, 0x1D, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ _inventoryButtons[0].buttonCallback = BUTTON_FUNCTOR(GUI_HoF, _gui, &GUI_HoF::optionsButton);
+
+ GUI_V2_BUTTON(_inventoryButtons[1], 0x2, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x104, 0x90, 0x3C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ _inventoryButtons[1].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::cauldronButton);
+
+ GUI_V2_BUTTON(_inventoryButtons[2], 0x5, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0FA, 0x90, 0x0A, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ _inventoryButtons[2].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::cauldronClearButton);
+
+ GUI_V2_BUTTON(_inventoryButtons[3], 0x3, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0CE, 0x90, 0x2C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ _inventoryButtons[3].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::bookButton);
+
+ GUI_V2_BUTTON(_inventoryButtons[4], 0x4, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0B6, 0x9D, 0x18, 0x1E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ _inventoryButtons[4].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::scrollInventory);
+
+ Button::Callback inventoryCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::buttonInventory);
+ GUI_V2_BUTTON(_inventoryButtons[5], 0x6, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x04D, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[6], 0x7, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x061, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[7], 0x8, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x075, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[8], 0x9, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x089, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[9], 0xA, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x09D, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[10], 0xB, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x04D, 0xA8, 0x13, 0x14, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[11], 0xC, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x061, 0xA8, 0x13, 0x14, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[12], 0xD, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x075, 0xA8, 0x13, 0x14, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[13], 0xE, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x089, 0xA8, 0x13, 0x14, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[14], 0xF, 0x00, 0, 0, 0, 0, 0x1100, 0, 0x09D, 0xA8, 0x13, 0x14, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+
+ for (int i = 5; i <= 14; ++i)
+ _inventoryButtons[i].buttonCallback = inventoryCallback;
+
+ _buttonList = &_inventoryButtons[0];
+ for (int i = 1; i < 15; ++i)
+ _buttonList = _gui->addButtonToList(_buttonList, &_inventoryButtons[i]);
+}
+
+void GUI_HoF::initStaticData() {
+ GUI_V2_BUTTON(_scrollUpButton, 0x17, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_scrollDownButton, 0x18, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[0][i], 0x18 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[2][i], 0x20 + i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+
+ for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i)
+ GUI_V2_BUTTON(_menuButtons[i], 0x10 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+
+ Button::Callback clickLoadSlotFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::clickLoadSlot);
+ Button::Callback clickSaveSlotFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::clickSaveSlot);
+ Button::Callback clickLoadMenuFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::loadMenu);
+ Button::Callback clickQuitGameFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::quitGame);
+ Button::Callback clickQuitOptionsFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::quitOptionsMenu);
+
+ const uint16 *menuStr = _vm->gameFlags().isTalkie ? _menuStringsTalkie : _menuStringsOther;
+
+ GUI_V2_MENU(_mainMenu, -1, -1, 0x100, 0xAC, 0xF8, 0xF9, 0xFA, menuStr[0 * 8], 0xFB, -1, 8, 0, 7, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_mainMenu.item[0], 1, 0x02, -1, 0x1E, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[0].callback = clickLoadMenuFunctor;
+ GUI_V2_MENU_ITEM(_mainMenu.item[1], 1, 0x03, -1, 0x2F, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[1].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::saveMenu);
+ GUI_V2_MENU_ITEM(_mainMenu.item[2], 1, 0x23, -1, 0x40, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[2].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::deleteMenu);
+ GUI_V2_MENU_ITEM(_mainMenu.item[3], 1, 0x04, -1, 0x51, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[3].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::gameOptionsTalkie);
+ GUI_V2_MENU_ITEM(_mainMenu.item[4], 1, 0x25, -1, 0x62, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[4].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::audioOptions);
+ GUI_V2_MENU_ITEM(_mainMenu.item[5], 1, 0x05, -1, 0x73, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[5].callback = clickQuitGameFunctor;
+ GUI_V2_MENU_ITEM(_mainMenu.item[6], 1, 0x06, -1, 0x90, 0xDC, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _mainMenu.item[6].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::resumeGame);
+ for (int i = 0; i < 7; ++i)
+ _mainMenu.item[i].itemId = menuStr[0 * 8 + i + 1];
+
+ if (!_vm->gameFlags().isTalkie) {
+ _mainMenu.height = 0x9C;
+ _mainMenu.numberOfItems = 6;
+ _mainMenu.item[6].enabled = false;
+ for (int i = 4; i < 6; ++i)
+ _mainMenu.item[i].callback = _mainMenu.item[i + 1].callback;
+ _mainMenu.item[3].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::gameOptions);
+ _mainMenu.item[6].callback = Button::Callback();
+ _mainMenu.item[5].y = 0x7F;
+ }
+
+ GUI_V2_MENU(_gameOptions, -1, -1, 0x120, 0x88, 0xF8, 0xF9, 0xFA, menuStr[1 * 8], 0xFB, -1, 8, 4, 4, -1, -1, -1, -1);
+ if (_vm->gameFlags().isTalkie) {
+ GUI_V2_MENU_ITEM(_gameOptions.item[0], 1, 0, 0xA0, 0x1E, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x15, 8, 0x20, 0);
+ _gameOptions.item[0].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::toggleWalkspeed);
+ GUI_V2_MENU_ITEM(_gameOptions.item[1], 1, 0, 0xA0, 0x2F, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x26, 8, 0x31, 0);
+ _gameOptions.item[1].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::changeLanguage);
+ GUI_V2_MENU_ITEM(_gameOptions.item[2], 1, 0, 0xA0, 0x40, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x16, 8, 0x42, 0);
+ _gameOptions.item[2].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::toggleText);
+ GUI_V2_MENU_ITEM(_gameOptions.item[3], 1, 0x10, -1, 0x6E, 0x6C, 0x0F, 0xFD, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _gameOptions.item[3].callback = clickQuitOptionsFunctor;
+ } else {
+ _gameOptions.numberOfItems = 5;
+ GUI_V2_MENU_ITEM(_gameOptions.item[0], 0, 0x2B, 0xA0, 0x1E, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x1F, 0x10, 0x20, 0);
+ GUI_V2_MENU_ITEM(_gameOptions.item[1], 0, 0x2C, 0xA0, 0x2F, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x20, 0x10, 0x31, 0);
+ GUI_V2_MENU_ITEM(_gameOptions.item[2], 0, 0x2D, 0xA0, 0x40, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x1D, 0x10, 0x42, 0);
+ GUI_V2_MENU_ITEM(_gameOptions.item[3], 0, 0x2E, 0xA0, 0x51, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x1E, 0x10, 0x53, 0);
+ GUI_V2_MENU_ITEM(_gameOptions.item[4], 1, 0x18, -1, 0x6E, 0x6C, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _gameOptions.item[4].callback = clickQuitOptionsFunctor;
+ }
+
+ for (int i = _gameOptions.numberOfItems; i <= 6; ++i)
+ _gameOptions.item[i].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _gameOptions.item[i].itemId = menuStr[1 * 8 + i + 1];
+
+ GUI_V2_MENU(_audioOptions, -1, -1, 0x120, 0x88, 0xF8, 0xF9, 0xFA, menuStr[2 * 8], 0xFB, -1, 8, 3, 4, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_audioOptions.item[0], 0, 0, 0xA0, 0x1E, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x17, 8, 0x20, 0);
+ GUI_V2_MENU_ITEM(_audioOptions.item[1], 0, 0, 0xA0, 0x2F, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x18, 8, 0x31, 0);
+ GUI_V2_MENU_ITEM(_audioOptions.item[2], 0, 0, 0xA0, 0x40, 0x74, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0x27, 8, 0x42, 0);
+ GUI_V2_MENU_ITEM(_audioOptions.item[3], 1, 0x10, -1, 0x6E, 0x5C, 0x0F, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _audioOptions.item[3].callback = clickQuitOptionsFunctor;
+ for (int i = 4; i <= 6; ++i)
+ _audioOptions.item[i].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _audioOptions.item[i].itemId = menuStr[2 * 8 + i + 1];
+
+ GUI_V2_MENU(_choiceMenu, -1, -1, 0x140, 0x38, 0xF8, 0xF9, 0xFA, 0, 0xFE, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_choiceMenu.item[0], 1, 0x14, 0x18, 0x1E, 0x48, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _choiceMenu.item[0].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::choiceYes);
+ GUI_V2_MENU_ITEM(_choiceMenu.item[1], 1, 0x13, 0xD8, 0x1E, 0x48, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _choiceMenu.item[1].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::choiceNo);
+ for (int i = 2; i <= 6; ++i)
+ _choiceMenu.item[i].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _choiceMenu.item[i].itemId = menuStr[3 * 8 + i + 1];
+
+ GUI_V2_MENU(_loadMenu, -1, -1, 0x120, 0xA0, 0xF8, 0xF9, 0xFA, menuStr[4 * 8], 0xFB, -1, 8, 0, 6, 0x84, 0x16, 0x84, 0x7C);
+ GUI_V2_MENU_ITEM(_loadMenu.item[0], 1, 0x29, -1, 0x27, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_loadMenu.item[1], 1, 0x2A, -1, 0x38, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_loadMenu.item[2], 1, 0x2B, -1, 0x49, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_loadMenu.item[3], 1, 0x2C, -1, 0x5A, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_loadMenu.item[4], 1, 0x2D, -1, 0x6B, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ for (int i = 0; i <= 4; ++i)
+ _loadMenu.item[i].callback = clickLoadSlotFunctor;
+ GUI_V2_MENU_ITEM(_loadMenu.item[5], 1, 0x0B, 0xB8, 0x86, 0x58, 0xF, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _loadMenu.item[5].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::cancelLoadMenu);
+ _loadMenu.item[6].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _loadMenu.item[i].itemId = menuStr[4 * 8 + i + 1];
+
+ GUI_V2_MENU(_saveMenu, -1, -1, 0x120, 0xA0, 0xF8, 0xF9, 0xFA, menuStr[5 * 8], 0xFB, -1, 8, 0, 6, 0x84, 0x16, 0x84, 0x7C);
+ GUI_V2_MENU_ITEM(_saveMenu.item[0], 1, 0x29, -1, 0x27, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_saveMenu.item[1], 1, 0x2A, -1, 0x38, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_saveMenu.item[2], 1, 0x2B, -1, 0x49, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_saveMenu.item[3], 1, 0x2C, -1, 0x5A, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ GUI_V2_MENU_ITEM(_saveMenu.item[4], 1, 0x2D, -1, 0x6B, 0x100, 0xF, 0xFC, 0xFD, 5, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ for (int i = 0; i <= 4; ++i)
+ _saveMenu.item[i].callback = clickSaveSlotFunctor;
+ GUI_V2_MENU_ITEM(_saveMenu.item[5], 1, 0x0B, 0xB8, 0x86, 0x58, 0xF, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _saveMenu.item[5].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::cancelSaveMenu);
+ _saveMenu.item[6].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _saveMenu.item[i].itemId = menuStr[5 * 8 + i + 1];
+
+ GUI_V2_MENU(_savenameMenu, -1, -1, 0x140, 0x43, 0xF8, 0xF9, 0xFA, menuStr[6 * 8], 0xFB, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_savenameMenu.item[0], 1, 0xD, 0x18, 0x2C, 0x58, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _savenameMenu.item[0].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::finishSavename);
+ GUI_V2_MENU_ITEM(_savenameMenu.item[1], 1, 0xB, 0xD0, 0x2C, 0x58, 0x0F, 0xFC, 0xFD, -1, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _savenameMenu.item[1].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::cancelSavename);
+ for (int i = 2; i <= 6; ++i)
+ _savenameMenu.item[i].enabled = false;
+ for (int i = 0; i < 7; ++i)
+ _savenameMenu.item[i].itemId = menuStr[6 * 8 + i + 1];
+
+ GUI_V2_MENU(_deathMenu, -1, -1, 0xD0, 0x4C, 0xF8, 0xF9, 0xFA, menuStr[7 * 8], 0xFB, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_deathMenu.item[0], 1, 2, -1, 0x1E, 0xB4, 0x0F, 0xFC, 0xFD, 8, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _deathMenu.item[0].callback = clickLoadMenuFunctor;
+ GUI_V2_MENU_ITEM(_deathMenu.item[1], 1, 5, -1, 0x2F, 0xB4, 0x0F, 0xFC, 0xFD, 8, 0xF8, 0xF9, 0xFA, -1, 0, 0, 0, 0);
+ _deathMenu.item[1].callback = clickQuitGameFunctor;
+ for (int i = 2; i <= 6; ++i)
+ _deathMenu.item[i].enabled = false;
+ for (int i = 0; i < 2; ++i)
+ _deathMenu.item[i].itemId = menuStr[7 * 8 + i + 1];
+}
+
+const uint16 GUI_HoF::_menuStringsTalkie[] = {
+ 0x001, 0x002, 0x003, 0x023, 0x004, 0x025, 0x005, 0x006, // Main Menu String IDs
+ 0x025, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Options Menu String IDs
+ 0x007, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Audio Menu String IDs
+ 0x000, 0x014, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
+ 0x008, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Load Menu String IDs
+ 0x009, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Save Menu String IDs
+ 0x00C, 0x00D, 0x00B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu6 Menu String IDs
+ 0x00E, 0x002, 0x005, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
+};
+
+const uint16 GUI_HoF::_menuStringsOther[] = {
+ 0x009, 0x00A, 0x00B, 0x001, 0x00C, 0x00D, 0x00E, 0x000, // Main Menu String IDs
+ 0x00F, 0x02B, 0x02C, 0x02D, 0x02E, 0x018, 0x000, 0x000, // Options Menu String IDs
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // Dummy
+ 0x000, 0x01C, 0x01B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
+ 0x010, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Load Menu String IDs
+ 0x011, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Save Menu String IDs
+ 0x014, 0x015, 0x013, 0x3E8, 0x000, 0x000, 0x000, 0x000, // Menu6 String IDs
+ 0x016, 0x00A, 0x00D, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
+};
+
+const uint16 KyraEngine_HoF::_itemMagicTable[] = {
+ 0x0D, 0x0A, 0x0B, 0,
+ 0x0D, 0x0B, 0x0A, 0,
+ 0x0D, 0x38, 0x37, 0,
+ 0x0D, 0x37, 0x38, 0,
+ 0x0D, 0x35, 0x36, 0,
+ 0x0D, 0x36, 0x35, 0,
+ 0x34, 0x27, 0x33, 0,
+ 0x41, 0x29, 0x49, 0,
+ 0x45, 0x29, 0x4A, 1,
+ 0x46, 0x29, 0x4A, 1,
+ 0x3C, 0x29, 0x4B, 1,
+ 0x34, 0x29, 0x4C, 0,
+ 0x3C, 0x49, 0x3B, 1,
+ 0x41, 0x4B, 0x3B, 0,
+ 0x3C, 0x4A, 0x3B, 1,
+ 0x34, 0x49, 0x3B, 0,
+ 0x41, 0x4C, 0x3B, 0,
+ 0x45, 0x4C, 0x3B, 1,
+ 0x46, 0x4C, 0x3B, 1,
+ 0x34, 0x4A, 0x3B, 0,
+ 0x0D, 0x67, 0x68, 0,
+ 0x0D, 0x68, 0x67, 0,
+ 0x0D, 0x69, 0x6A, 0,
+ 0x0D, 0x6A, 0x69, 0,
+ 0x0D, 0x6B, 0x6C, 0,
+ 0x0D, 0x6C, 0x6B, 0,
+ 0x0D, 0x88, 0x87, 0,
+ 0x0D, 0x87, 0x88, 0,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
+};
+
+const int KyraEngine_HoF::_bookPageYOffset[] = {
+ 0, 0, 2, 2,
+ 0, 0, 2, 2,
+ 0, 0, 2, 2
+};
+
+const byte KyraEngine_HoF::_bookTextColorMap[] = {
+ 0x00, 0xC7, 0xCF, 0x00
+};
+
+const int16 KyraEngine_HoF::_cauldronProtectedItems[] = {
+ 0x07, 0x0D, 0x47, 0x48,
+ 0x29, 0x1A, 0x1C, 0x6D,
+ 0x4D, 0x3A, 0x0E, 0x0F,
+ 0x10, 0x11, 0x26, 0x3E,
+ 0x35, 0x40, 0x42, 0xA6,
+ 0xA4, 0xA5, 0x91, 0x95,
+ 0x99, 0xAC, 0xAE, 0xAF,
+ 0x8A, 0x79, 0x61, -1
+};
+
+const int16 KyraEngine_HoF::_cauldronBowlTable[] = {
+ 0x0027, 0x0029,
+ 0x0028, 0x0029,
+ 0x0033, 0x0029,
+ 0x0049, 0x0029,
+ 0x004A, 0x0029,
+ 0x004B, 0x0029,
+ 0x004C, 0x0029,
+ 0x003B, 0x0029,
+ 0x0034, 0x0034,
+ -1, -1
+};
+
+const int16 KyraEngine_HoF::_cauldronMagicTable[] = {
+ 0x0, 0x16, 0x2, 0x1A,
+ 0x7, 0xA4, 0x5, 0x4D,
+ 0x1, 0xA5, 0x3, 0xA6,
+ 0x6, 0x6D, 0x4, 0x91,
+ 0xA, 0x99, 0xC, 0x95,
+ 0x9, 0xAC, -1, -1
+};
+
+const int16 KyraEngine_HoF::_cauldronMagicTableScene77[] = {
+ 0x0, 0x16, 0x2, 0x1A,
+ 0x7, 0xAB, 0x5, 0x4D,
+ 0x1, 0xAE, 0x3, 0xAF,
+ 0x6, 0x6D, 0x4, 0x91,
+ 0xA, 0x99, 0xC, 0x95,
+ 0x9, 0xAC, -1, -1
+};
+
+const uint8 KyraEngine_HoF::_cauldronStateTable[] = {
+ 3, 1, 3, 1, 1, 4, 4, 2,
+ 3, 1, 1, 3, 1, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3
+};
+
+const Item KyraEngine_HoF::_flaskTable[] = {
+ 0x19, 0x14, 0x15, 0x16, 0x17, 0x18, 0x34,
+ 0x1B, 0x39, 0x1A, 0x3A, 0x4D, 0x72, kItemNone
+};
+
+const uint8 KyraEngine_HoF::_rainbowRoomData[] = {
+ 0x02, 0xA9, 0x9E, 0x75, 0x73, 0x17, 0x00, 0xA0,
+ 0x08, 0x01, 0x19, 0x9F, 0x66, 0x05, 0x22, 0x7D,
+ 0x20, 0x25, 0x1D, 0x64, 0xA0, 0x78, 0x85, 0x3B,
+ 0x3C, 0x5E, 0x38, 0x45, 0x8F, 0x61, 0xA1, 0x71,
+ 0x47, 0x77, 0x86, 0x41, 0xA2, 0x5F, 0x03, 0x72,
+ 0x83, 0x9E, 0x84, 0x8E, 0xAD, 0xA8, 0x04, 0x79,
+ 0xAA, 0xA3, 0x06, 0x27, 0x8F, 0x9F, 0x0A, 0x76,
+ 0x46, 0x1E, 0x24, 0x63, 0x18, 0x69, 0x39, 0x1F,
+ 0x7E, 0xAD, 0x28, 0x60, 0x67, 0x21, 0x84, 0x34
+};
+
+// kyra 3 static res
+
+const char *const KyraEngine_MR::_languageExtension[] = {
+ "TRE",
+ "TRF",
+ "TRG"/*,
+ "TRI", Italian and Spanish were never included, the supported fan translations are using
+ "TRS" English/French extensions thus overwriting these languages */
+};
+
+const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension);
+
+const char *const KyraEngine_MR::_mainMenuSpanishFan[] = {
+ "Nueva Partida",
+ "Ver Intro",
+ "Restaurar",
+ "Finalizar"
+};
+
+const char *const KyraEngine_MR::_mainMenuItalianFan[] = {
+ "Nuova Partita",
+ "Introduzione",
+ "Carica una partita",
+ "Esci dal gioco"
+};
+
+const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = {
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 82, 96, -43, -86 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 69, 91, -31, -82 },
+ { 57, 91, -31, -82 },
+ { 57, 91, -31, -82 }
+};
+
+const int KyraEngine_MR::_shapeDescsSize = ARRAYSIZE(KyraEngine_MR::_shapeDescs);
+
+const uint8 KyraEngine_MR::_characterFrameTable[] = {
+ 0x36, 0x35, 0x35, 0x33, 0x32, 0x32, 0x34, 0x34
+};
+
+const uint8 KyraEngine_MR::_badConscienceFrameTable[] = {
+ 0x13, 0x13, 0x13, 0x18, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x10, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x18, 0x13, 0x13, 0x13, 0x13,
+ 0x15, 0x15, 0x14, 0x18, 0x14, 0x14, 0x14, 0x14,
+ 0x24, 0x24, 0x24, 0x24, 0x24, 0x1D, 0x1D, 0x1D
+};
+
+const uint8 KyraEngine_MR::_goodConscienceFrameTable[] = {
+ 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x1E, 0x1E, 0x1E, 0x1E, 0x1E
+};
+
+const uint8 KyraEngine_MR::_chapterLowestScene[] = {
+ 0x00, 0x00, 0x19, 0x2B, 0x33, 0x3B
+};
+
+const uint8 KyraEngine_MR::_vocHighTable[] = {
+ 0x64, 0x76, 0x82, 0x83, 0x92
+};
+
+const uint8 KyraEngine_MR::_inventoryX[] = {
+ 0x45, 0x61, 0x7D, 0x99, 0xB5,
+ 0x45, 0x61, 0x7D, 0x99, 0xB5
+};
+
+const uint8 KyraEngine_MR::_inventoryY[] = {
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2
+};
+
+const Item KyraEngine_MR::_trashItemList[] = {
+ 0x1E, 0x1D, 0x1C, 0x1F, 0x0F, 0x05, 0x04, 0x00,
+ 0x03, 0x22, 0x0B, 0x20, 0x21, 0x10, 0x11, 0x3A,
+ 0x39, 0x40, 0x3E, 0x3D, 0x3C, 0x3F, kItemNone
+};
+
+const uint8 KyraEngine_MR::_itemStringPickUp[] = {
+ 0x4, 0x7, 0x0, 0xA
+};
+
+const uint8 KyraEngine_MR::_itemStringDrop[] = {
+ 0x5, 0x8, 0x1, 0xB
+};
+
+const uint8 KyraEngine_MR::_itemStringInv[] = {
+ 0x6, 0x9, 0x2, 0xC
+};
+
+void KyraEngine_MR::initMainButtonList(bool disable) {
+ if (!_mainButtonListInitialized) {
+ _mainButtonData = new Button[14];
+ assert(_mainButtonData);
+
+ GUI_V2_BUTTON(_mainButtonData[0], 1, 0, 0, 4, 4, 4, 0x4487, 0, 5, 162, 50, 25, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[0].buttonCallback = BUTTON_FUNCTOR(GUI_MR, _gui, &GUI_MR::optionsButton);
+ GUI_V2_BUTTON(_mainButtonData[1], 2, 0, 0, 1, 1, 1, 0x4487, 0, 245, 156, 69, 33, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[1].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::buttonMoodChange);
+ GUI_V2_BUTTON(_mainButtonData[2], 3, 0, 0, 1, 1, 1, 0x4487, 0, 215, 191, 24, 9, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[2].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::buttonShowScore);
+ GUI_V2_BUTTON(_mainButtonData[3], 4, 0, 0, 1, 1, 1, 0x4487, 0, 215, 155, 25, 36, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[3].buttonCallback = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::buttonJesterStaff);
+
+ Button::Callback buttonInventoryFunctor = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::buttonInventory);
+ for (int i = 0; i < 5; ++i) {
+ GUI_V2_BUTTON(_mainButtonData[i + 4], i + 5, 0, 0, 0, 0, 0, 0x1100, 0, 67 + i * 28, 155, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[i + 4].buttonCallback = buttonInventoryFunctor;
+ }
+
+ for (int i = 0; i < 5; ++i) {
+ GUI_V2_BUTTON(_mainButtonData[i + 9], i + 10, 0, 0, 0, 0, 0, 0x1100, 0, 67 + i * 28, 177, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[i + 9].buttonCallback = buttonInventoryFunctor;
+ }
+
+ for (int i = 0; i < 14; ++i)
+ _mainButtonList = _gui->addButtonToList(_mainButtonList, &_mainButtonData[i]);
+
+ _mainButtonListInitialized = true;
+ }
+
+ for (int i = 0; i < 14; ++i) {
+ if (disable)
+ _gui->flagButtonDisable(&_mainButtonData[i]);
+ else
+ _gui->flagButtonEnable(&_mainButtonData[i]);
+ }
+}
+
+void GUI_MR::initStaticData() {
+ GUI_V2_BUTTON(_scrollUpButton, 22, 0, 0, 4, 4, 4, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ GUI_V2_BUTTON(_scrollDownButton, 23, 0, 0, 4, 4, 4, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[0][i], 0x18 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ for (int i = 0; i < 4; ++i)
+ GUI_V2_BUTTON(_sliderButtons[2][i], 0x20 + i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+
+ for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i)
+ GUI_V2_BUTTON(_menuButtons[i], 0x0F + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+
+ Button::Callback clickLoadSlotFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::clickLoadSlot);
+ Button::Callback clickSaveSlotFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::clickSaveSlot);
+ Button::Callback clickLoadMenuFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::loadMenu);
+ Button::Callback clickQuitOptionsFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::quitOptionsMenu);
+
+ GUI_V2_MENU(_mainMenu, -1, -1, 256, 172, 0xD0, 0xD1, 0xCF, 1, 0xBD, -1, 8, 0, 7, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_mainMenu.item[0], 1, 2, -1, 30, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[0].callback = clickLoadMenuFunctor;
+ GUI_V2_MENU_ITEM(_mainMenu.item[1], 1, 3, -1, 47, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[1].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::saveMenu);
+ GUI_V2_MENU_ITEM(_mainMenu.item[2], 1, 35, -1, 64, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[2].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::deleteMenu);
+ GUI_V2_MENU_ITEM(_mainMenu.item[3], 1, 4, -1, 81, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[3].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::gameOptions);
+ GUI_V2_MENU_ITEM(_mainMenu.item[4], 1, 37, -1, 98, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[4].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::audioOptions);
+ GUI_V2_MENU_ITEM(_mainMenu.item[5], 1, 5, -1, 115, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[5].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::quitGame);
+ GUI_V2_MENU_ITEM(_mainMenu.item[6], 1, 6, -1, 144, 220, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _mainMenu.item[6].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::resumeGame);
+
+ GUI_V2_MENU(_audioOptions, -1, -1, 288, 136, 0xD0, 0xD1, 0xCF, 37, 0xBD, -1, 8, 4, 5, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_audioOptions.item[0], 0, 0, 160, 30, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 23, 8, 32, 0x0000);
+ GUI_V2_MENU_ITEM(_audioOptions.item[1], 0, 0, 160, 47, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 24, 8, 49, 0x0000);
+ GUI_V2_MENU_ITEM(_audioOptions.item[2], 0, 0, 160, 64, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 39, 8, 66, 0x0000);
+ GUI_V2_MENU_ITEM(_audioOptions.item[3], 1, 0, 152, 81, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 47, 8, 83, 0x0000);
+ _audioOptions.item[3].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::toggleHeliumMode);
+ GUI_V2_MENU_ITEM(_audioOptions.item[4], 1, 16, -1, 110, 92, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _audioOptions.item[4].callback = clickQuitOptionsFunctor;
+ for (int i = 5; i < 7; ++i)
+ _audioOptions.item[i].enabled = false;
+
+ GUI_V2_MENU(_gameOptions, -1, -1, 288, 154, 0xD0, 0xD1, 0xCF, 7, 0xBD, -1, 8, 0, 6, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_gameOptions.item[0], 1, 0, 160, 30, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 21, 8, 32, 0x0000);
+ _gameOptions.item[0].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::toggleWalkspeed);
+ GUI_V2_MENU_ITEM(_gameOptions.item[1], 1, 0, 160, 47, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 26, 8, 49, 0x0000);
+ _gameOptions.item[1].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::changeLanguage);
+ GUI_V2_MENU_ITEM(_gameOptions.item[2], 1, 0, 160, 64, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 40, 8, 66, 0x0000);
+ _gameOptions.item[2].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::toggleStudioSFX);
+ GUI_V2_MENU_ITEM(_gameOptions.item[3], 1, 0, 160, 81, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 46, 8, 83, 0x0000);
+ _gameOptions.item[3].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::toggleSkipSupport);
+ GUI_V2_MENU_ITEM(_gameOptions.item[4], 1, 0, 160, 98, 116, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 22, 8, 100, 0x0000);
+ _gameOptions.item[4].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::toggleText);
+ GUI_V2_MENU_ITEM(_gameOptions.item[5], 1, 16, -1, 127, 125, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _gameOptions.item[5].callback = clickQuitOptionsFunctor;
+ _gameOptions.item[6].enabled = false;
+
+ GUI_V2_MENU(_choiceMenu, -1, -1, 320, 56, 0xD0, 0xD1, 0xCF, 0, 0xBA, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_choiceMenu.item[0], 1, 20, 24, 30, 72, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _choiceMenu.item[0].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::choiceYes);
+ GUI_V2_MENU_ITEM(_choiceMenu.item[1], 1, 19, 216, 30, 72, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _choiceMenu.item[1].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::choiceNo);
+ for (int i = 2; i < 7; ++i)
+ _choiceMenu.item[i].enabled = false;
+
+ GUI_V2_MENU(_loadMenu, -1, -1, 288, 160, 0xD0, 0xD1, 0xCF, 8, 0xBD, -1, 8, 0, 6, 132, 22, 132, 124);
+ GUI_V2_MENU_ITEM(_loadMenu.item[0], 1, 41, -1, 39, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_loadMenu.item[1], 1, 42, -1, 56, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_loadMenu.item[2], 1, 43, -1, 73, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_loadMenu.item[3], 1, 44, -1, 90, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_loadMenu.item[4], 1, 45, -1, 107, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ for (int i = 0; i <= 4; ++i)
+ _loadMenu.item[i].callback = clickLoadSlotFunctor;
+ GUI_V2_MENU_ITEM(_loadMenu.item[5], 1, 11, 184, 134, 88, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _loadMenu.item[5].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::cancelLoadMenu);
+ _loadMenu.item[6].enabled = false;
+
+ GUI_V2_MENU(_saveMenu, -1, -1, 288, 160, 0xD0, 0xD1, 0xCF, 9, 0xBD, -1, 8, 0, 6, 132, 22, 132, 124);
+ GUI_V2_MENU_ITEM(_saveMenu.item[0], 1, 41, -1, 39, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_saveMenu.item[1], 1, 42, -1, 56, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_saveMenu.item[2], 1, 43, -1, 73, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_saveMenu.item[3], 1, 44, -1, 90, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ GUI_V2_MENU_ITEM(_saveMenu.item[4], 1, 45, -1, 107, 256, 15, 0xFA, 0xFF, 5, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ for (int i = 0; i <= 4; ++i)
+ _saveMenu.item[i].callback = clickSaveSlotFunctor;
+ GUI_V2_MENU_ITEM(_saveMenu.item[5], 1, 11, 184, 134, 88, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _saveMenu.item[5].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::cancelSaveMenu);
+ _saveMenu.item[6].enabled = false;
+
+ GUI_V2_MENU(_savenameMenu, -1, -1, 320, 67, 0xD0, 0xD1, 0xCF, 12, 0xBD, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_savenameMenu.item[0], 1, 13, 24, 44, 88, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _savenameMenu.item[0].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::finishSavename);
+ GUI_V2_MENU_ITEM(_savenameMenu.item[1], 1, 11, 208, 44, 88, 15, 0xFA, 0xFF, -1, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _savenameMenu.item[1].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::cancelSavename);
+ for (int i = 2; i < 7; ++i)
+ _savenameMenu.item[i].enabled = false;
+
+ GUI_V2_MENU(_deathMenu, -1, -1, 208, 76, 0xD0, 0xD1, 0xCF, 14, 0xBD, -1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V2_MENU_ITEM(_deathMenu.item[0], 1, 2, -1, 30, 180, 15, 0xFA, 0xFF, 8, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _deathMenu.item[0].callback = clickLoadMenuFunctor;
+ GUI_V2_MENU_ITEM(_deathMenu.item[1], 1, 38, -1, 47, 180, 15, 0xFA, 0xFF, 8, 0xD0, 0xD1, 0xCF, -1, 0, 0, 0, 0x0000);
+ _deathMenu.item[1].callback = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::loadSecondChance);
+ for (int i = 2; i < 7; ++i)
+ _deathMenu.item[i].enabled = false;
+}
+
+const int8 KyraEngine_MR::_albumWSAX[] = {
+ 0, 77, -50, 99, -61, 82, -58, 85,
+ -64, 80, -63, 88, -63, 88, -64, 0
+};
+
+const int8 KyraEngine_MR::_albumWSAY[] = {
+ 0, -1, 3, 0, -1, 0, -2, 0,
+ -1, -2, 2, 2, -6, -6, -6, 0
+};
+
+} // End of namespace Kyra
diff --git a/engines/kyra/resource/staticres_eob.cpp b/engines/kyra/resource/staticres_eob.cpp
new file mode 100644
index 0000000000..4a94c8448a
--- /dev/null
+++ b/engines/kyra/resource/staticres_eob.cpp
@@ -0,0 +1,1379 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/eob.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound_intern.h"
+
+
+namespace Kyra {
+
+#ifdef ENABLE_EOB
+const DarkMoonAnimCommand *StaticResource::loadEoB2SeqData(int id, int &entries) {
+ return (const DarkMoonAnimCommand *)getData(id, kEoB2SequenceData, entries);
+}
+
+const DarkMoonShapeDef *StaticResource::loadEoB2ShapeData(int id, int &entries) {
+ return (const DarkMoonShapeDef *)getData(id, kEoB2ShapeData, entries);
+}
+
+const EoBCharacter *StaticResource::loadEoBNpcData(int id, int &entries) {
+ return (const EoBCharacter *)getData(id, kEoBNpcData, entries);
+}
+
+bool StaticResource::loadEoB2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 11;
+
+ DarkMoonAnimCommand *s = new DarkMoonAnimCommand[size];
+
+ for (int i = 0; i < size; i++) {
+ s[i].command = stream.readByte();
+ s[i].obj = stream.readByte();
+ s[i].x1 = stream.readSint16BE();
+ s[i].y1 = stream.readByte();
+ s[i].delay = stream.readByte();
+ s[i].pal = stream.readByte();
+ s[i].x2 = stream.readByte();
+ s[i].y2 = stream.readByte();
+ s[i].w = stream.readByte();
+ s[i].h = stream.readByte();
+ }
+
+ ptr = s;
+ return true;
+}
+
+bool StaticResource::loadEoB2ShapeData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 6;
+
+ DarkMoonShapeDef *s = new DarkMoonShapeDef[size];
+
+ for (int i = 0; i < size; i++) {
+ s[i].index = stream.readSint16BE();
+ s[i].x = stream.readByte();
+ s[i].y = stream.readByte();
+ s[i].w = stream.readByte();
+ s[i].h = stream.readByte();
+ }
+
+ ptr = s;
+ return true;
+}
+
+bool StaticResource::loadEoBNpcData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.readUint16BE();
+
+ EoBCharacter *e = new EoBCharacter[size];
+ memset(e, 0, size * sizeof(EoBCharacter));
+ EoBCharacter *s = e;
+
+ for (int i = 0; i < size; i++, s++) {
+ s->id = stream.readByte();
+ s->flags = stream.readByte();
+ stream.read(s->name, 11);
+ s->strengthCur = stream.readSByte();
+ s->strengthMax = stream.readSByte();
+ s->strengthExtCur = stream.readSByte();
+ s->strengthExtMax = stream.readSByte();
+ s->intelligenceCur = stream.readSByte();
+ s->intelligenceMax = stream.readSByte();
+ s->wisdomCur = stream.readSByte();
+ s->wisdomMax = stream.readSByte();
+ s->dexterityCur = stream.readSByte();
+ s->dexterityMax = stream.readSByte();
+ s->constitutionCur = stream.readSByte();
+ s->constitutionMax = stream.readSByte();
+ s->charismaCur = stream.readSByte();
+ s->charismaMax = stream.readSByte();
+ s->hitPointsCur = stream.readSint16BE();
+ s->hitPointsMax = stream.readSint16BE();
+ s->armorClass = stream.readSByte();
+ s->disabledSlots = stream.readByte();
+ s->raceSex = stream.readByte();
+ s->cClass = stream.readByte();
+ s->alignment = stream.readByte();
+ s->portrait = stream.readSByte();
+ s->food = stream.readByte();
+ stream.read(s->level, 3);
+ s->experience[0] = stream.readUint32BE();
+ s->experience[1] = stream.readUint32BE();
+ s->experience[2] = stream.readUint32BE();
+ s->mageSpellsAvailableFlags = stream.readUint32BE();
+ for (int ii = 0; ii < 27; ii++)
+ s->inventory[ii] = stream.readSint16BE();
+ }
+
+ ptr = e;
+ return true;
+}
+
+void StaticResource::freeEoB2SeqData(void *&ptr, int &size) {
+ DarkMoonAnimCommand *d = (DarkMoonAnimCommand *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeEoB2ShapeData(void *&ptr, int &size) {
+ DarkMoonShapeDef *d = (DarkMoonShapeDef *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeEoBNpcData(void *&ptr, int &size) {
+ EoBCharacter *d = (EoBCharacter *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+const ScreenDim Screen_EoB::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x08, 0x48, 0x18, 0x38, 0x0E, 0x0C, 0x00, 0x00 },
+ { 0x13, 0x40, 0x14, 0x80, 0x06, 0x0C, 0x00, 0x00 },
+ { 0x1D, 0x78, 0x08, 0x40, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x02, 0x18, 0x14, 0x78, 0x0F, 0x02, 0x03, 0x00 },
+ { 0x00, 0x00, 0x16, 0x78, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x0A, 0x6C, 0x15, 0x28, 0x0F, 0x00, 0x00, 0x00 },
+ { 0x01, 0xB4, 0x22, 0x12, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x02, 0x18, 0x14, 0x00, 0x0F, 0x02, 0x03, 0x00 },
+ { 0x01, 0x7D, 0x26, 0x40, 0x0F, 0x00, 0x03, 0x00 },
+ { 0x00, 0x00, 0x16, 0x90, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x14, 0x14, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x04, 0x14, 0x9C, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x19, 0x26, 0x64, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x14, 0x14, 0x58, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x02, 0x06, 0x23, 0x78, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x09, 0x14, 0x16, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x96, 0x26, 0x32, 0x0F, 0x00, 0x00, 0x00 },
+ { 0x01, 0x08, 0x26, 0x80, 0x0C, 0x0F, 0x00, 0x00 },
+ { 0x01, 0x10, 0x26, 0x14, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x10, 0x0C, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x17, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x10, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x07, 0x04, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x11, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x15, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x11, 0x08, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x15, 0x03, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x0A, 0xA8, 0x15, 0x18, 0x0F, 0x0C, 0x00, 0x00 }
+};
+
+const int Screen_EoB::_screenDimTableCount = ARRAYSIZE(Screen_EoB::_screenDimTable);
+
+const uint8 EoBCoreEngine::_hpIncrPerLevel[] = { 10, 4, 8, 6, 10, 10, 9, 10, 9, 10, 9, 9, 3, 1, 2, 2, 3, 3 };
+
+const uint8 EoBCoreEngine::_numLevelsPerClass[] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 2, 2, 3, 2, 2 };
+
+const int8 EoBCoreEngine::_characterClassType[] = {
+ 0, -1, -1, 5, -1, -1, 4, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1, 0,
+ 2, -1, 0, 3, -1, 0, 1, -1, 0, 1, 3, 3, 1, -1, 2, 3, -1, 0, 2, 1, 5,
+ 2, -1, 2, 1, -1
+};
+
+const int16 EoBCoreEngine::_hpConstModifiers[] = { -1, -3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7 };
+
+const uint8 EoBCoreEngine::_charClassModifier[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02,
+ 0x00, 0x00, 0x02
+};
+
+const uint8 EoBCoreEngine::_itemsOverlayCGA[] = {
+ 0x00, 0x55, 0x55, 0xFF
+};
+
+const uint8 EoBCoreEngine::_teleporterShapeDefs[] = {
+ 0x0C, 0x58, 0x02, 0x0E,
+ 0x0C, 0x67, 0x01, 0x07,
+ 0x0C, 0x6F, 0x01, 0x07,
+ 0x0C, 0x77, 0x01, 0x05,
+ 0x0C, 0x7D, 0x01, 0x05,
+ 0x0C, 0x83, 0x01, 0x03
+};
+
+const uint8 EoBCoreEngine::_wallOfForceShapeDefs[] = {
+ 0x00, 0x00, 0x04, 0x08,
+ 0x00, 0x08, 0x04, 0x08,
+ 0x04, 0x00, 0x04, 0x08,
+ 0x04, 0x08, 0x04, 0x08,
+ 0x08, 0x00, 0x05, 0x10,
+ 0x0C, 0x00, 0x05, 0x10
+};
+
+const uint8 EoBCoreEngine::_buttonList1[] = {
+ 58, 0, 1, 2, 3, 90, 91, 4, 5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14, 15, 16,
+ 80, 81, 17, 18, 19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList2[] = {
+ 58, 61, 62, 63, 64, 65, 93, 94, 66, 67, 68, 69, 70, 71, 76, 77, 88, 0, 1, 2, 3,
+ 90, 91, 4, 5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14, 15, 16, 80, 81, 17, 18,
+ 19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList3[] = {
+ 58, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 84, 85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50,
+ 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList4[] = {
+ 58, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList5[] = {
+ 58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 84,
+ 85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList6[] = {
+ 58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 46, 47, 48, 60, 59, 92,
+ 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList7[] = {
+ 17, 18, 19, 20, 82, 83, 55, 255
+};
+
+const uint8 EoBCoreEngine::_buttonList8[] = {
+ 72, 73, 74, 75, 86, 87, 89, 255
+};
+
+const uint8 EoBCoreEngine::_clock2Timers[] = {
+ 0x00, 0x01, 0x20, 0x21, 0x22, 0x22,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x04, 0x05, 0x06, 0x07
+};
+
+const uint8 EoBCoreEngine::_numClock2Timers = ARRAYSIZE(EoBCoreEngine::_clock2Timers);
+
+void EoBCoreEngine::initStaticResource() {
+ int temp;
+ _chargenStatStrings = _staticres->loadStrings(kEoBBaseChargenStatStrings, temp);
+ _chargenRaceSexStrings = _staticres->loadStrings(kEoBBaseChargenRaceSexStrings, temp);
+ _chargenClassStrings = _staticres->loadStrings(kEoBBaseChargenClassStrings, temp);
+ _chargenAlignmentStrings = _staticres->loadStrings(kEoBBaseChargenAlignmentStrings, temp);
+
+ _pryDoorStrings = _staticres->loadStrings(kEoBBasePryDoorStrings, temp);
+ _warningStrings = _staticres->loadStrings(kEoBBaseWarningStrings, temp);
+
+ _suffixStringsRings = _staticres->loadStrings(kEoBBaseItemSuffixStringsRings, temp);
+ _suffixStringsPotions = _staticres->loadStrings(kEoBBaseItemSuffixStringsPotions, temp);
+ _suffixStringsWands = _staticres->loadStrings(kEoBBaseItemSuffixStringsWands, temp);
+
+ _ripItemStrings = _staticres->loadStrings(kEoBBaseRipItemStrings, temp);
+ _cursedString = _staticres->loadStrings(kEoBBaseCursedString, temp);
+ _enchantedString = _staticres->loadStrings(kEoBBaseEnchantedString, temp);
+ _magicObjectStrings = _staticres->loadStrings(kEoBBaseMagicObjectStrings, temp);
+ _magicObjectString5 = _staticres->loadStrings(kEoBBaseMagicObjectString5, temp);
+ _patternSuffix = _staticres->loadStrings(kEoBBasePatternSuffix, temp);
+ _patternGrFix1 = _staticres->loadStrings(kEoBBasePatternGrFix1, temp);
+ _patternGrFix2 = _staticres->loadStrings(kEoBBasePatternGrFix2, temp);
+ _validateArmorString = _staticres->loadStrings(kEoBBaseValidateArmorString, temp);
+ _validateCursedString = _staticres->loadStrings(kEoBBaseValidateCursedString, temp);
+ _validateNoDropString = _staticres->loadStrings(kEoBBaseValidateNoDropString, temp);
+ _potionStrings = _staticres->loadStrings(kEoBBasePotionStrings, temp);
+ _wandStrings = _staticres->loadStrings(kEoBBaseWandStrings, temp);
+ _itemMisuseStrings = _staticres->loadStrings(kEoBBaseItemMisuseStrings, temp);
+
+ _takenStrings = _staticres->loadStrings(kEoBBaseTakenStrings, temp);
+ _potionEffectStrings = _staticres->loadStrings(kEoBBasePotionEffectStrings, temp);
+
+ _yesNoStrings = _staticres->loadStrings(kEoBBaseYesNoStrings, temp);
+ _npcMaxStrings = _staticres->loadStrings(kEoBBaseNpcMaxStrings, temp);
+ _okStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseOkStrings : kRpgCommonMoreStrings, temp);
+ _npcJoinStrings = _staticres->loadStrings(kEoBBaseNpcJoinStrings, temp);
+ _cancelStrings = _staticres->loadStrings(kEoBBaseCancelStrings, temp);
+ _abortStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseAbortStrings : kEoBBaseCancelStrings, temp);
+
+ _menuStringsMain = _staticres->loadStrings(kEoBBaseMenuStringsMain, temp);
+ _menuStringsSaveLoad = _staticres->loadStrings(kEoBBaseMenuStringsSaveLoad, temp);
+ _menuStringsOnOff = _staticres->loadStrings(kEoBBaseMenuStringsOnOff, temp);
+ _menuStringsSpells = _staticres->loadStrings(kEoBBaseMenuStringsSpells, temp);
+ _menuStringsRest = _staticres->loadStrings(kEoBBaseMenuStringsRest, temp);
+ _menuStringsDrop = _staticres->loadStrings(kEoBBaseMenuStringsDrop, temp);
+ _menuStringsExit = _staticres->loadStrings(kEoBBaseMenuStringsExit, temp);
+ _menuStringsStarve = _staticres->loadStrings(kEoBBaseMenuStringsStarve, temp);
+ _menuStringsScribe = _staticres->loadStrings(kEoBBaseMenuStringsScribe, temp);
+ _menuStringsDrop2 = _staticres->loadStrings(kEoBBaseMenuStringsDrop2, temp);
+ _menuStringsHead = _staticres->loadStrings(kEoBBaseMenuStringsHead, temp);
+ _menuStringsPoison = _staticres->loadStrings(kEoBBaseMenuStringsPoison, temp);
+ _menuStringsMgc = _staticres->loadStrings(kEoBBaseMenuStringsMgc, temp);
+ _menuStringsPrefs = _staticres->loadStrings(kEoBBaseMenuStringsPrefs, temp);
+ _menuStringsRest2 = _staticres->loadStrings(kEoBBaseMenuStringsRest2, temp);
+ _menuStringsRest3 = _staticres->loadStrings(kEoBBaseMenuStringsRest3, temp);
+ _menuStringsRest4 = _staticres->loadStrings(kEoBBaseMenuStringsRest4, temp);
+ _menuStringsDefeat = _staticres->loadStrings(kEoBBaseMenuStringsDefeat, temp);
+ _menuStringsTransfer = _staticres->loadStrings(kEoBBaseMenuStringsTransfer, temp);
+ _menuStringsSpec = _staticres->loadStrings(kEoBBaseMenuStringsSpec, temp);
+ _menuStringsSpellNo = _staticres->loadStrings(kEoBBaseMenuStringsSpellNo, temp);
+ _menuYesNoStrings = _staticres->loadStrings(kEoBBaseMenuYesNoStrings, temp);
+
+ _spellLevelsMage = _staticres->loadRawData(kEoBBaseSpellLevelsMage, _spellLevelsMageSize);
+ _spellLevelsCleric = _staticres->loadRawData(kEoBBaseSpellLevelsCleric, _spellLevelsClericSize);
+ _numSpellsCleric = _staticres->loadRawData(kEoBBaseNumSpellsCleric, temp);
+ _numSpellsWisAdj = _staticres->loadRawData(kEoBBaseNumSpellsWisAdj, temp);
+ _numSpellsPal = _staticres->loadRawData(kEoBBaseNumSpellsPal, temp);
+ _numSpellsMage = _staticres->loadRawData(kEoBBaseNumSpellsMage, temp);
+
+ _characterGuiStringsHp = _staticres->loadStrings(kEoBBaseCharGuiStringsHp, temp);
+ _characterGuiStringsWp = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharGuiStringsWp2 : kEoBBaseCharGuiStringsWp1, temp);
+ _characterGuiStringsWr = _staticres->loadStrings(kEoBBaseCharGuiStringsWr, temp);
+ _characterGuiStringsSt = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharGuiStringsSt2 : kEoBBaseCharGuiStringsSt1, temp);
+ _characterGuiStringsIn = _staticres->loadStrings(kEoBBaseCharGuiStringsIn, temp);
+
+ _characterStatusStrings7 = _staticres->loadStrings(kEoBBaseCharStatusStrings7, temp);
+ _characterStatusStrings8 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharStatusStrings82 : kEoBBaseCharStatusStrings81, temp);
+ _characterStatusStrings9 = _staticres->loadStrings(kEoBBaseCharStatusStrings9, temp);
+ _characterStatusStrings12 = _staticres->loadStrings(kEoBBaseCharStatusStrings12, temp);
+ _characterStatusStrings13 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharStatusStrings132 : kEoBBaseCharStatusStrings131, temp);
+
+ _levelGainStrings = _staticres->loadStrings(kEoBBaseLevelGainStrings, temp);
+ for (int i = 0; i < 5; i++)
+ _expRequirementTables[i] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable0 + i, temp);
+ _expRequirementTables[5] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable4, temp);
+
+ _classModifierFlags = _staticres->loadRawData(kEoBBaseClassModifierFlags, temp);
+
+ _saveThrowTables[0] = _saveThrowTables[4] = _saveThrowTables[5] = _staticres->loadRawData(kEoBBaseSaveThrowTable1, temp);
+ _saveThrowTables[1] = _staticres->loadRawData(kEoBBaseSaveThrowTable2, temp);
+ _saveThrowTables[2] = _staticres->loadRawData(kEoBBaseSaveThrowTable3, temp);
+ _saveThrowTables[3] = _staticres->loadRawData(kEoBBaseSaveThrowTable4, temp);
+ _saveThrowLevelIndex = _staticres->loadRawData(kEoBBaseSaveThrwLvlIndex, temp);
+ _saveThrowModDiv = _staticres->loadRawData(kEoBBaseSaveThrwModDiv, temp);
+ _saveThrowModExt = _staticres->loadRawData(kEoBBaseSaveThrwModExt, temp);
+
+ _encodeMonsterShpTable = _staticres->loadRawDataBe16(kEoBBaseEncodeMonsterDefs, temp);
+ _npcPreset = _staticres->loadEoBNpcData(kEoBBaseNpcPresets, temp);
+
+ _teleporterShapeCoords = _staticres->loadRawData(kEoBBaseDscTelptrShpCoords, temp);
+ _portalSeq = (const int8 *)_staticres->loadRawData(kEoBBasePortalSeqData, temp);
+ _mnDef = _staticres->loadRawData(kEoBBaseManDef, temp);
+ _mnWord = _staticres->loadStrings(kEoBBaseManWord, _mnNumWord);
+ _mnPrompt = _staticres->loadStrings(kEoBBaseManPrompt, temp);
+
+ _monsterStepTable0 = (const int8 *)_staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterStepTable02 : kEoBBaseMonsterStepTable01, temp);
+ _monsterStepTable1 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable1, temp);
+ _monsterStepTable2 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable2, temp);
+ _monsterStepTable3 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable3, temp);
+ _monsterCloseAttPosTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttPosTable1, temp);
+ _monsterCloseAttPosTable2 = _staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterCloseAttPosTable22 : kEoBBaseMonsterCloseAttPosTable21, temp);
+ _monsterCloseAttUnkTable = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterCloseAttUnkTable, temp);
+ _monsterCloseAttChkTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttChkTable1, temp);
+ _monsterCloseAttChkTable2 = _staticres->loadRawData(kEoBBaseMonsterCloseAttChkTable2, temp);
+ _monsterCloseAttDstTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttDstTable1, temp);
+ _monsterCloseAttDstTable2 = _staticres->loadRawData(kEoBBaseMonsterCloseAttDstTable2, temp);
+
+ _monsterProximityTable = _staticres->loadRawData(kEoBBaseMonsterProximityTable, temp);
+ _findBlockMonstersTable = _staticres->loadRawData(kEoBBaseFindBlockMonstersTable, temp);
+ _monsterDirChangeTable = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterDirChangeTable, temp);
+ _monsterSpecAttStrings = _staticres->loadStrings(kEoBBaseMonsterDistAttStrings, temp);
+
+ _monsterFrmOffsTable1 = (const int8 *)_staticres->loadRawData(kEoBBaseDscMonsterFrmOffsTbl1, temp);
+ _monsterFrmOffsTable2 = (const int8 *)_staticres->loadRawData(kEoBBaseDscMonsterFrmOffsTbl2, temp);
+
+ _inventorySlotsX = _staticres->loadRawDataBe16(kEoBBaseInvSlotX, temp);
+ _inventorySlotsY = _staticres->loadRawData(kEoBBaseInvSlotY, temp);
+ _slotValidationFlags = _staticres->loadRawDataBe16(kEoBBaseSlotValidationFlags, temp);
+
+ _projectileWeaponAmmoTypes = (const int8 *)_staticres->loadRawData(kEoBBaseProjectileWeaponTypes, temp);
+ _wandTypes = _staticres->loadRawData(kEoBBaseWandTypes, temp);
+
+ _drawObjPosIndex = _staticres->loadRawData(kEoBBaseDrawObjPosIndex, temp);
+ _flightObjFlipIndex = _staticres->loadRawData(kEoBBaseFlightObjFlipIndex, temp);
+ _flightObjShpMap = (const int8 *)_staticres->loadRawData(kEoBBaseFlightObjShpMap, temp);
+ _flightObjSclIndex = (const int8 *)_staticres->loadRawData(kEoBBaseFlightObjSclIndex, temp);
+
+ _wllFlagPreset = _staticres->loadRawData(kEoBBaseWllFlagPreset, _wllFlagPresetSize);
+ _dscShapeCoords = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscShapeCoords, temp);
+
+ _dscDoorScaleMult1 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult1, temp);
+ _dscDoorScaleMult2 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult2, temp);
+ _dscDoorScaleMult3 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult3, temp);
+ _dscDoorY1 = _staticres->loadRawData(kEoBBaseDscDoorY1, temp);
+ _dscDoorXE = _staticres->loadRawData(kEoBBaseDscDoorXE, temp);
+
+ _dscItemPosIndex = _staticres->loadRawData(kEoBBaseDscItemPosIndex, temp);
+ _dscItemShpX = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscItemShpX, temp);
+ _dscItemScaleIndex = _staticres->loadRawData(kEoBBaseDscItemScaleIndex, temp);
+ _dscItemTileIndex = _staticres->loadRawData(kEoBBaseDscItemTileIndex, temp);
+ _dscItemShapeMap = _staticres->loadRawData(kEoBBaseDscItemShapeMap, temp);
+
+ _bookNumbers = _staticres->loadStrings(kEoBBaseBookNumbers, temp);
+ _mageSpellList = _staticres->loadStrings(kEoBBaseMageSpellsList, _mageSpellListSize);
+ _clericSpellList = _staticres->loadStrings(kEoBBaseClericSpellsList, temp);
+ _spellNames = _staticres->loadStrings(kEoBBaseSpellNames, temp);
+
+ _magicStrings1 = _staticres->loadStrings(kEoBBaseMagicStrings1, temp);
+ _magicStrings2 = _staticres->loadStrings(kEoBBaseMagicStrings2, temp);
+ _magicStrings3 = _staticres->loadStrings(kEoBBaseMagicStrings3, temp);
+ _magicStrings4 = _staticres->loadStrings(kEoBBaseMagicStrings4, temp);
+ _magicStrings6 = _staticres->loadStrings(kEoBBaseMagicStrings6, temp);
+ _magicStrings7 = _staticres->loadStrings(kEoBBaseMagicStrings7, temp);
+ _magicStrings8 = _staticres->loadStrings(kEoBBaseMagicStrings8, temp);
+
+ _expObjectTlMode = _staticres->loadRawData(kEoBBaseExpObjectTlMode, temp);
+ _expObjectTblIndex = _staticres->loadRawData(kEoBBaseExpObjectTblIndex, temp);
+ _expObjectShpStart = _staticres->loadRawData(kEoBBaseExpObjectShpStart, temp);
+ _expObjectAnimTbl1 = _staticres->loadRawData(kEoBBaseExpObjectTbl1, _expObjectAnimTbl1Size);
+ _expObjectAnimTbl2 = _staticres->loadRawData(kEoBBaseExpObjectTbl2, _expObjectAnimTbl2Size);
+ _expObjectAnimTbl3 = _staticres->loadRawData(kEoBBaseExpObjectTbl3, _expObjectAnimTbl3Size);
+
+ _sparkEffectDefSteps = _staticres->loadRawData(kEoBBaseSparkDefSteps, temp);
+ _sparkEffectDefSubSteps = _staticres->loadRawData(kEoBBaseSparkDefSubSteps, temp);
+ _sparkEffectDefShift = _staticres->loadRawData(kEoBBaseSparkDefShift, temp);
+ _sparkEffectDefAdd = _staticres->loadRawData(kEoBBaseSparkDefAdd, temp);
+ _sparkEffectDefX = _staticres->loadRawData(kEoBBaseSparkDefX, temp);
+ _sparkEffectDefY = _staticres->loadRawData(kEoBBaseSparkDefY, temp);
+ _sparkEffectOfFlags1 = _staticres->loadRawDataBe32(kEoBBaseSparkOfFlags1, temp);
+ _sparkEffectOfFlags2 = _staticres->loadRawDataBe32(kEoBBaseSparkOfFlags2, temp);
+ _sparkEffectOfShift = _staticres->loadRawData(kEoBBaseSparkOfShift, temp);
+ _sparkEffectOfX = _staticres->loadRawData(kEoBBaseSparkOfX, temp);
+ _sparkEffectOfY = _staticres->loadRawData(kEoBBaseSparkOfY, temp);
+ _magicFlightObjectProperties = _staticres->loadRawData(kEoBBaseMagicFlightProps, temp);
+ _turnUndeadEffect = _staticres->loadRawData(kEoBBaseTurnUndeadEffect, temp);
+ _burningHandsDest = _staticres->loadRawData(kEoBBaseBurningHandsDest, temp);
+ _coneOfColdDest1 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest1, temp);
+ _coneOfColdDest2 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest2, temp);
+ _coneOfColdDest3 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest3, temp);
+ _coneOfColdDest4 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest4, temp);
+ _coneOfColdGfxTbl = _staticres->loadRawData(kEoBBaseConeOfColdGfxTbl, _coneOfColdGfxTblSize);
+
+ // Hard code the following strings, since EOB I doesn't have them in the original.
+ // EOB I doesn't have load and save menus, because there is only one single
+ // save slot. Instead of emulating this we provide a menu similiar to EOB II.
+
+ static const char *const saveLoadStrings[4][4] = {
+ { "Cancel", "Empty Slot", "Save Game", "Load Game" },
+ { "Abbr.", "Leerer Slot", "Speichern", " Laden" },
+ { " < < ", "Posizione Vuota", "Salva", "Carica" },
+ { 0, 0, 0, 0 }
+ };
+
+ static const char *const errorSlotEmptyString[5] = {
+ "There is no game\rsaved in that slot!",
+ "Hier ist noch kein\rSpiel gespeichert!",
+ "Non c'\x0E alcun gioco\rsalvato in quella\rposizione!",
+ "\r ""\x82\xBB\x82\xCC\x83""X""\x83\x8D\x83""b""\x83""g""\x82\xC9\x82\xCD\x83""Q""\x81""[""\x83\x80\x82\xAA\x83""Z""\x81""[""\x83""u\r ""\x82\xB3\x82\xEA\x82\xC4\x82\xA2\x82\xDC\x82\xB9\x82\xF1\x81""B",
+ 0
+ };
+
+ if (_flags.lang == Common::EN_ANY) {
+ _saveLoadStrings = saveLoadStrings[0];
+ _errorSlotEmptyString = errorSlotEmptyString[0];
+ } else if (_flags.lang == Common::DE_DEU) {
+ _saveLoadStrings = saveLoadStrings[1];
+ _errorSlotEmptyString = errorSlotEmptyString[1];
+ } else if (_flags.lang == Common::IT_ITA) {
+ _saveLoadStrings = saveLoadStrings[2];
+ _errorSlotEmptyString = errorSlotEmptyString[2];
+ } else if (_flags.lang == Common::JA_JPN) {
+ // EOB II FM-Towns uses English here.
+ // Only the empty slot warning is in Japanese.
+ _saveLoadStrings = saveLoadStrings[0];
+ _errorSlotEmptyString = errorSlotEmptyString[3];
+ } else {
+ _saveLoadStrings = saveLoadStrings[4];
+ _errorSlotEmptyString = errorSlotEmptyString[4];
+ }
+
+ _menuOkString = "OK";
+}
+
+void EoBCoreEngine::initButtonData() {
+ static const EoBGuiButtonDef buttonDefs[] = {
+ { 112, 0, 0x1100, 184, 2, 63, 50, 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, 3 },
+ { 48, 110, 0x1100, 289, 177, 31, 21, 0 },
+ { 0, 0, 0x1100, 0, 102, 88, 18, 0 },
+ { 0, 0, 0x1100, 89, 102, 88, 18, 1 },
+ { 0, 0, 0x1100, 0, 72, 88, 29, 2 },
+ { 0, 0, 0x1100, 89, 72, 88, 29, 3 },
+ { 24, 0, 0x1100, 184, 10, 33, 33, 0 },
+ { 0, 0, 0x1100, 256, 10, 33, 33, 1 },
+ { 0, 0, 0x1100, 184, 62, 33, 33, 2 },
+ { 0, 0, 0x1100, 256, 62, 33, 33, 3 },
+ { 0, 0, 0x1100, 216, 10, 31, 33, 0 },
+ { 0, 0, 0x1100, 288, 10, 31, 33, 1 },
+ { 0, 0, 0x1100, 216, 62, 31, 33, 2 },
+ { 0, 0, 0x1100, 288, 62, 31, 33, 3 },
+ { 368, 0, 0x1000, 184, 2, 63, 8, 0 },
+ { 369, 0, 0x1000, 256, 2, 63, 8, 1 },
+ { 370, 0, 0x1000, 184, 54, 63, 8, 2 },
+ { 371, 0, 0x1000, 256, 54, 63, 8, 3 },
+ { 0, 0, 0x1100, 230, 116, 16, 16, 0 },
+ { 0, 0, 0x1100, 278, 116, 16, 16, 1 },
+ { 0, 0, 0x1100, 181, 40, 16, 16, 2 },
+ { 0, 0, 0x1100, 199, 40, 16, 16, 3 },
+ { 0, 0, 0x1100, 181, 58, 16, 16, 4 },
+ { 0, 0, 0x1100, 199, 58, 16, 16, 5 },
+ { 0, 0, 0x1100, 181, 76, 16, 16, 6 },
+ { 0, 0, 0x1100, 199, 76, 16, 16, 7 },
+ { 0, 0, 0x1100, 181, 94, 16, 16, 8 },
+ { 0, 0, 0x1100, 199, 94, 16, 16, 9 },
+ { 0, 0, 0x1100, 181, 112, 16, 16, 10 },
+ { 0, 0, 0x1100, 199, 112, 16, 16, 11 },
+ { 0, 0, 0x1100, 181, 130, 16, 16, 12 },
+ { 0, 0, 0x1100, 199, 130, 16, 16, 13 },
+ { 0, 0, 0x1100, 181, 148, 16, 16, 14 },
+ { 0, 0, 0x1100, 199, 148, 16, 16, 15 },
+ { 0, 0, 0x1100, 225, 55, 16, 16, 16 },
+ { 0, 0, 0x1100, 224, 76, 16, 16, 17 },
+ { 0, 0, 0x1100, 225, 96, 16, 16, 18 },
+ { 0, 0, 0x1100, 298, 55, 16, 16, 19 },
+ { 0, 0, 0x1100, 287, 75, 16, 16, 20 },
+ { 0, 0, 0x1100, 277, 137, 16, 16, 21 },
+ { 0, 0, 0x1100, 300, 94, 16, 16, 22 },
+ { 0, 0, 0x1100, 300, 112, 16, 16, 23 },
+ { 0, 0, 0x1100, 300, 130, 16, 16, 24 },
+ { 0, 0, 0x1100, 236, 37, 31, 16, 25 },
+ { 26, 0, 0x1100, 291, 149, 25, 17, 25 },
+ { 110, 24, 0x1100, 181, 3, 32, 32, 25 },
+ { 96, 352, 0x1100, 24, 128, 21, 16, 25 },
+ { 98, 97, 0x1100, 24, 144, 21, 16, 25 },
+ { 92, 348, 0x1100, 3, 144, 21, 16, 25 },
+ { 102, 358, 0x1100, 45, 144, 21, 16, 25 },
+ { 91, 0, 0x1100, 3, 128, 21, 16, 25 },
+ { 101, 0, 0x1100, 45, 128, 21, 16, 25 },
+ { 110, 0, 0x1100, 184, 0, 136, 120, 0 },
+ { 0, 0, 0x1100, 0, 8, 88, 48, 0 },
+ { 0, 0, 0x1100, 88, 8, 88, 48, 1 },
+ { 0, 0, 0x1100, 24, 8, 128, 96, 1 },
+ { 112, 113, 0x1100, 274, 35, 20, 15, 1 },
+ { 114, 115, 0x1100, 297, 35, 20, 15, 1 },
+ { 2, 0, 0x1100, 68, 121, 18, 10, 0 },
+ { 3, 0, 0x1100, 86, 121, 18, 10, 1 },
+ { 4, 0, 0x1100, 104, 121, 15, 10, 2 },
+ { 5, 0, 0x1100, 122, 121, 15, 10, 3 },
+ { 6, 0, 0x1100, 140, 121, 15, 10, 4 },
+ { 0, 0, 0x1100, 75, 131, 97, 6, 0 },
+ { 0, 0, 0x1100, 75, 137, 97, 6, 1 },
+ { 0, 0, 0x1100, 75, 143, 97, 6, 2 },
+ { 0, 0, 0x1100, 75, 149, 97, 6, 3 },
+ { 0, 0, 0x1100, 75, 155, 97, 6, 4 },
+ { 0, 0, 0x1100, 75, 161, 97, 6, 5 },
+ { 112, 0, 0x1100, 184, 2, 63, 50, 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, 3 },
+ { 53, 54, 0x1100, 320, 200, 0, 0, 6 },
+ { 61, 0, 0x1100, 320, 200, 0, 0, 7 },
+ { 0, 0, 0x1100, 184, 114, 33, 33, 4 },
+ { 0, 0, 0x1100, 256, 114, 33, 33, 5 },
+ { 0, 0, 0x1100, 216, 114, 31, 33, 4 },
+ { 0, 0, 0x1100, 288, 114, 31, 33, 5 },
+ { 372, 0, 0x1000, 184, 106, 63, 8, 4 },
+ { 373, 0, 0x1000, 256, 106, 63, 8, 5 },
+ { 0, 0, 0x1100, 227, 135, 10, 10, 25 },
+ { 0, 0, 0x1100, 239, 135, 10, 10, 26 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, 5 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, 0 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, 65535 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, 5 },
+ { 116, 117, 0x1100, 320, 200, 1, 1, 2 },
+ { 7, 0, 0x1100, 158, 121, 15, 10, 5 },
+ { 0, 0, 0x1100, 146, 168, 32, 10, 0 },
+
+ // EOB1 spellbook modifications
+ { 2, 0, 0x1100, 71, 122, 20, 8, 0 },
+ { 3, 0, 0x1100, 92, 122, 20, 8, 1 },
+ { 4, 0, 0x1100, 113, 122, 20, 8, 2 },
+ { 5, 0, 0x1100, 134, 122, 20, 8, 3 },
+ { 6, 0, 0x1100, 155, 122, 20, 8, 4 },
+ { 110, 0, 0x1100, 75, 168, 97, 6, 0 }
+ };
+
+ _buttonDefs = new EoBGuiButtonDef[ARRAYSIZE(buttonDefs)];
+ memcpy(_buttonDefs, buttonDefs, sizeof(buttonDefs));
+
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ static const uint16 keyCodesFMTowns[] = {
+ 93, 94, 95, 96, 67, 27, 24, 349, 350, 351, 352, 80, 27, 24, 30, 0, 31, 0, 29, 0, 28, 0, 127, 18, 27, 93, 94, 95, 96,
+ 49, 50, 51, 52, 53, 93, 94, 95, 96, 60, 62, 32, 353, 354, 97, 98, 27, 27, 97, 98, 97, 98, 54, 49, 50, 51, 52, 53, 27
+ };
+
+ const uint16 *c = keyCodesFMTowns;
+ for (int i = 0; i < ARRAYSIZE(buttonDefs); ++i) {
+ if (_buttonDefs[i].keyCode)
+ _buttonDefs[i].keyCode = *c++;
+ if (_buttonDefs[i].keyCode2)
+ _buttonDefs[i].keyCode2 = *c++;
+ }
+ }
+
+ _buttonCallbacks.clear();
+ _buttonCallbacks.reserve(ARRAYSIZE(buttonDefs));
+
+#define EOB_CBN(x, y) _buttonCallbacks.push_back(BUTTON_FUNCTOR(EoBCoreEngine, this, &EoBCoreEngine::y)); for (int l = 0; l < (x - 1); l++) { _buttonCallbacks.push_back(_buttonCallbacks[_buttonCallbacks.size() - 1 - l]); }
+#define EOB_CBI(x, y) for (int l = x; l; l--) { _buttonCallbacks.push_back(_buttonCallbacks[y]); }
+ EOB_CBN(4, clickedCharPortraitDefault);
+ EOB_CBN(1, clickedCamp);
+ EOB_CBN(4, clickedSceneDropPickupItem);
+ EOB_CBN(4, clickedCharPortrait2);
+ EOB_CBN(4, clickedWeaponSlot);
+ EOB_CBN(4, clickedCharNameLabelRight);
+ EOB_CBN(25, clickedInventorySlot);
+ EOB_CBN(1, clickedEatItem);
+ EOB_CBN(1, clickedInventoryNextPage);
+ EOB_CBN(1, clickedPortraitRestore);
+ EOB_CBN(1, clickedUpArrow);
+ EOB_CBN(1, clickedDownArrow);
+ EOB_CBN(1, clickedLeftArrow);
+ EOB_CBN(1, clickedRightArrow);
+ EOB_CBN(1, clickedTurnLeftArrow);
+ EOB_CBN(1, clickedTurnRightArrow);
+ EOB_CBN(1, clickedAbortCharSwitch);
+ EOB_CBN(2, clickedSceneThrowItem);
+ EOB_CBN(1, clickedSceneSpecial);
+ EOB_CBN(1, clickedInventoryPrevChar);
+ EOB_CBN(1, clickedInventoryNextChar);
+ EOB_CBN(5, clickedSpellbookTab);
+ EOB_CBN(6, clickedSpellbookList);
+ EOB_CBN(4, clickedCastSpellOnCharacter);
+ EOB_CBI(2, 66);
+ EOB_CBI(2, 9);
+ EOB_CBI(2, 13);
+ EOB_CBI(2, 17);
+ EOB_CBI(2, 21);
+ EOB_CBI(2, 72);
+ EOB_CBN(1, clickedSpellbookAbort);
+ EOB_CBI(1, 72);
+ EOB_CBI(2, 0);
+ EOB_CBI(1, 60);
+ EOB_CBI(1, 61);
+ EOB_CBN(1, clickedSpellbookScroll);
+ EOB_CBI(5, 61);
+ EOB_CBI(1, 88);
+#undef EOB_CBI
+#undef EOB_CBN
+}
+
+void EoBCoreEngine::initMenus() {
+ static const EoBMenuButtonDef buttonDefs[] = {
+ { 2, 12, 20, 158, 14, 20, 3 },
+ { 3, 12, 37, 158, 14, 52, 3 },
+ { 4, 12, 54, 158, 14, 26, 3 },
+ { 5, 12, 71, 158, 14, 32, 3 },
+ { 6, 12, 88, 158, 14, 0, 3 },
+ { 7, 12, 105, 158, 14, 35, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 9, 12, 20, 158, 14, 39, 3 },
+ { 10, 12, 37, 158, 14, 32, 3 },
+ { 11, 12, 54, 158, 14, 33, 3 },
+ { 12, 12, 71, 158, 14, 17, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 18, 12, 20, 158, 14, 32, 3 },
+ { 19, 12, 37, 158, 14, 50, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 8, 128, 122, 40, 14, 19, 5 },
+ { 0, 184, 0, 64, 48, 112, 0 },
+ { 0, 256, 0, 64, 48, 113, 0 },
+ { 0, 184, 56, 64, 48, 114, 0 },
+ { 0, 256, 56, 64, 48, 115, 0 },
+ { 0, 184, 112, 64, 48, 116, 0 },
+ { 0, 256, 112, 64, 48, 117, 0 },
+ { 36, 8, 126, 48, 14, 48, 5 },
+ { 8, 128, 126, 40, 14, 19, 5 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ { 31, 11, 16, 20, 18, 2, 5 },
+ { 32, 38, 16, 20, 18, 3, 5 },
+ { 33, 65, 16, 20, 18, 4, 5 },
+ { 34, 92, 16, 20, 18, 5, 5 },
+ { 35, 119, 16, 20, 18, 6, 5 },
+ { 60, 146, 16, 20, 18, 7, 5 },
+ { 61, 150, 16, 20, 18, 8, 5 },
+ { 38, 16, 57, 32, 14, 22, 7 },
+ { 39, 128, 57, 32, 14, 51, 7 },
+ { 8, 128, 126, 40, 14, 19, 7 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ // EOB 1 memorize/pray menu:
+ { 36, 8, 126, 48, 14, 48, 5 },
+ { 8, 128, 126, 40, 14, 19, 5 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ { 31, 8, 16, 24, 20, 2, 5 },
+ { 32, 40, 16, 24, 20, 3, 5 },
+ { 33, 72, 16, 24, 20, 4, 5 },
+ { 34, 104, 16, 24, 20, 5, 5 },
+ { 35, 136, 16, 24, 20, 6, 5 },
+ // FM-Towns options menu
+ { 18, 12, 20, 158, 14, 32, 3 },
+ { 19, 12, 37, 158, 14, 50, 3 },
+ { 20, 12, 54, 158, 14, 21, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 }
+ };
+
+ _menuButtonDefs = buttonDefs;
+
+ static const EoBMenuDef menuDefs[] = {
+ { 1, 10, 0, 7, 9 },
+ { 1, 10, 7, 5, 9 },
+ { 1, 10, 12, 3, 9 },
+ { 0, 10, 15, 7, 15 },
+ { 37, 10, 22, 9, 9 },
+ { 0, 11, 32, 2, 15 },
+ { 48, 10, 34, 2, 9 }
+ };
+
+ delete[] _menuDefs;
+ _menuDefs = new EoBMenuDef[ARRAYSIZE(menuDefs)];
+ memcpy(_menuDefs, menuDefs, sizeof(menuDefs));
+
+ if (_flags.gameID == GI_EOB1) {
+ // assign EOB 1 style memorize/pray menu
+ _menuDefs[4].numButtons = 8;
+ _menuDefs[4].firstButtonStrId = 36;
+ }
+
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ // assign FM-Towns style options menu
+ _menuDefs[2].numButtons = 4;
+ _menuDefs[2].firstButtonStrId = 44;
+ }
+}
+
+
+void EoBCoreEngine::initSpells() {
+#define mpn magicTimingParaAssign.push_back(0);
+#define mp1n if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(0);
+#define mp2n if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(0);
+#define mp(x) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+#define mp1(x) if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+#define mp2(x) if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+
+#define sc(x) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
+#define sc1(x) if (_flags.gameID == GI_EOB1) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
+#define sc2(x) if (_flags.gameID == GI_EOB2) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
+#define ec(x) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
+#define ec1(x) if (_flags.gameID == GI_EOB1) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
+#define ec2(x) if (_flags.gameID == GI_EOB2) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
+
+ static const uint16 magicTimingPara[] = {
+ 0, 546, 2, 1, // 0 detect magic
+ 0, 546, 5, 1, // 1 shield, detect invis, magical vestment
+ 0, 546, 1, 1, // 2 shocking grasp, vamp touch, true seeing, prayer
+ 3, 546, 1, 1, // 3 blur, haste
+ 5, 546, 1, 1, // 4 imp invisibility
+ 6, 546, 0, 1, // 5 bless
+ 0, 546, 3, 1, // 6 prot from evil
+ 1, 546, 1, 1, // 7 aid
+ 4, 546, 1, 1, // 8 flame blade
+ 0, 32760, 1, 1, // 9 slow poison
+ 1, 546, 0, 1, // 10 mystic defense
+ };
+
+ Common::Array<const uint16 *> magicTimingParaAssign;
+ mpn;
+ mpn;
+ mpn;
+ mp(0); // Detect Magic
+ mpn; // Magic Missile
+ mp1n;
+ mp(1); // Shield
+ mp(2); // Shocking Grasp
+ mp2(3); // Blur
+ mp2(1); // Detect Invis
+ mp2n; // Imp Identify
+ mpn; // Invis
+ mp1n;
+ mpn; // Melf
+ mp1n; // Stinking Cloud
+ mpn; // Dispel Magic
+ mpn; // Fireball
+ mp1n; // Flame Arrow
+ mp(3); // Haste
+ mpn; // Hold Person
+ mpn; // Invisibility
+ mpn; // Lightning Bolt
+ mp(2); // Vampiric Touch
+ mpn; // Fear
+ mpn; // Ice Storm
+ mp1n; // Stone Skin
+ mp1n; // Cloud Kill
+ mp2(4); // Improved Invisibility
+ mp2n; // remove Curse
+ mpn; // Cone of Cold
+ mpn; // Hold Monster
+ mp2n; // Wall of Force
+ mp2n; // Disintegrate
+ mp2n; // Flesh To Stone
+ mp2n; // Stone To Flesh
+ mp2(2); // True Seeing
+ mp2n; // Finger of Death
+ mp2n; // Power Word Stun
+ mp2n; // Bigby's Fist
+ mp2n; // empty
+ mp(5); // Bless
+ mpn; // EOB1: cure, EOB2: cause
+ mpn; // EOB1: cause, EOB2: cure
+ mp(0); // Detect Magic
+ mp(6); // Prot from Evil
+ mp(7); // Aid
+ mp(8); // Flame Blad
+ mpn; // Hold Person
+ mp(9); // Slow Poison
+ mpn; // Create Food
+ mpn; // Dispel Magic
+ mp(1); // Magical Vestment
+ mp(2); // Prayer
+ mpn; // Remove Paralysis
+ mpn; // EOB1: cure, EOB2: cause
+ mpn; // EOB1: cause, EOB2: cure
+ mpn; // Neutral Poison
+ mp(6); // Prot From Evil 10'
+ mp1n; // Prot From Lightning
+ mpn; // EOB1: cure, EOB2: cause
+ mpn; // EOB1: cause, EOB2: cure
+ mpn; // Flame Strike
+ mpn; // Raise Dead
+ mp2n; // Slay Living
+ mp2(2); // True Seeing
+ mp2n; // Harm
+ mp2n; // Heal
+ mp2n; // Resurrect
+ mpn; // Lay on Hands
+ mp2n; // Turn Undead
+ mpn; // Lightning Bolt (EOB1) / Fireball 1(EOB2) passive
+ mp2(10);// Mystic Defense
+ mp2n; // Fireball 2 passive
+ mpn; // death spell passive
+ mpn; // disintegrate passive
+ mp2n; // cause critical passive
+ mp2n; // flesh to stone passive
+
+ Common::Array<SpellStartCallback> startCallback;
+ sc(empty);
+ sc(armor);
+ sc(burningHands);
+ sc(detectMagic);
+ sc(magicMissile);
+ sc1(empty);
+ sc(empty);
+ sc(shockingGrasp);
+ sc(empty);
+ sc2(empty);
+ sc2(improvedIdentify);
+ sc(empty);
+ sc(melfsAcidArrow);
+ sc1(empty); // Stinking Cloud
+ sc(dispelMagic);
+ sc(fireball);
+ sc1(flameArrow);
+ sc(empty);
+ sc(holdPerson);
+ sc(empty);
+ sc(lightningBolt);
+ sc(vampiricTouch);
+ sc(fear);
+ sc(iceStorm);
+ sc1(stoneSkin); // stone skin
+ sc2(empty); // imp invisibility
+ sc1(empty); // Cloudkill
+ sc2(removeCurse);
+ sc(coneOfCold);
+ sc(holdMonster);
+ sc2(wallOfForce);
+ sc2(disintegrate);
+ sc2(fleshToStone);
+ sc2(stoneToFlesh);
+ sc2(trueSeeing);
+ sc2(slayLiving);
+ sc2(powerWordStun);
+ sc2(empty);
+ sc2(empty);
+ sc(empty); // Bless
+ sc2(causeLightWounds);
+ sc(cureLightWounds);
+ sc1(causeLightWounds);
+ sc(detectMagic);
+ sc(empty);
+ sc(aid);
+ sc(flameBlade);
+ sc(holdPerson);
+ sc(slowPoison);
+ sc(createFood);
+ sc(dispelMagic);
+ sc(empty);
+ sc(empty);
+ sc(removeParalysis);
+ sc2(causeSeriousWounds);
+ sc(cureSeriousWounds);
+ sc1(causeSeriousWounds);
+ sc(neutralizePoison);
+ sc(empty);
+ sc1(empty);
+ sc2(causeCriticalWounds);
+ sc(cureCriticalWounds);
+ sc1(causeCriticalWounds);
+ sc(flameStrike);
+ sc(raiseDead);
+ sc2(slayLiving);
+ sc2(trueSeeing);
+ sc2(harm);
+ sc2(heal);
+ sc2(empty);
+ sc(layOnHands);
+ sc2(turnUndead);
+ sc(empty);
+ sc2(empty);
+ sc2(empty);
+ sc(empty);
+ sc(empty);
+ sc2(empty);
+ sc2(empty);
+
+ Common::Array<SpellEndCallback> endCallback;
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(detectMagic);
+ ec(magicMissile);
+ ec1(empty);
+ ec(empty);
+ ec(shockingGraspFlameBlade);
+ ec(empty);
+ ec(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(melfsAcidArrow);
+ ec1(empty); // Stinking Cloud
+ ec(empty);
+ ec(fireball);
+ ec1(flameArrow);
+ ec(empty);
+ ec(holdPerson);
+ ec(empty);
+ ec(lightningBolt);
+ ec(vampiricTouch);
+ ec(empty);
+ ec(iceStorm);
+ ec(empty); // EOB1: stone skin, EOB2: imp invisibility
+ ec(empty); // EOB1: cloud kill, EOB2: remove curse
+ ec(empty);
+ ec(holdMonster);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(trueSeeing);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(empty); // Bless
+ ec(empty);
+ ec(empty);
+ ec(detectMagic);
+ ec(empty);
+ ec(aid);
+ ec(shockingGraspFlameBlade);
+ ec(holdPerson);
+ ec(slowPoison);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec1(empty); // Prot from Lightning
+ ec(empty);
+ ec(empty);
+ ec(flameStrike);
+ ec(empty);
+ ec2(empty);
+ ec2(trueSeeing);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(empty);
+ ec2(empty);
+ ec1(monster_lightningBolt);
+ ec2(monster_fireball1);
+ ec2(empty);
+ ec2(monster_fireball2);
+ ec(monster_deathSpell);
+ ec(monster_disintegrate);
+ ec2(monster_causeCriticalWounds);
+ ec2(monster_fleshToStone);
+
+ _spells = new EoBSpell[_numSpells];
+ memset(_spells, 0, _numSpells * sizeof(EoBSpell));
+
+ for (int i = 0, n = 0; i < _numSpells; i++, n++) {
+ EoBSpell *s = &_spells[i];
+
+ // Fix EoB 1 spell names
+ bool skip = false;
+ if (i == 5 || i == 9) {
+ n--;
+ skip = true;
+ }
+
+ s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : (skip ? _spellNames[0] : _spellNames[n]);
+ s->startCallback = startCallback[i];
+ s->timingPara = magicTimingParaAssign[i];
+ s->endCallback = endCallback[i];
+ }
+
+ magicTimingParaAssign.clear();
+ startCallback.clear();
+ endCallback.clear();
+
+ _clericSpellOffset = _mageSpellListSize;
+
+#undef mpn
+#undef mp1n
+#undef mp2n
+#undef mp
+#undef mp1
+#undef mp2
+#undef sc
+#undef sc1
+#undef sc2
+#undef ec
+#undef ec1
+#undef ec2
+}
+
+void EoBEngine::initStaticResource() {
+ int temp;
+ _mainMenuStrings = _staticres->loadStrings(kEoB1MainMenuStrings, temp);
+ _finBonusStrings = _staticres->loadStrings(kEoB1BonusStrings, temp);
+
+ _doorShapeEncodeDefs = _staticres->loadRawData(kEoB1DoorShapeDefs, temp);
+ _doorSwitchShapeEncodeDefs = _staticres->loadRawData(kEoB1DoorSwitchShapeDefs, temp);
+ _doorSwitchCoords = _staticres->loadRawData(kEoB1DoorSwitchCoords, temp);
+
+ _dscDoorScaleMult4 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult4, temp);
+ _dscDoorScaleMult5 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult5, temp);
+ _dscDoorScaleMult6 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult6, temp);
+ _dscDoorY3 = _staticres->loadRawData(kEoBBaseDscDoorY3, temp);
+ _dscDoorY4 = _staticres->loadRawData(kEoBBaseDscDoorY4, temp);
+ _dscDoorY5 = _staticres->loadRawData(kEoBBaseDscDoorY5, temp);
+ _dscDoorY6 = _staticres->loadRawData(kEoBBaseDscDoorY6, temp);
+ _dscDoorY7 = _staticres->loadRawData(kEoBBaseDscDoorY7, temp);
+ _dscDoorCoordsExt = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscDoorCoordsExt, temp);
+
+ _enemyMageSpellList = _staticres->loadRawData(kEoB1EnemyMageSpellList, temp);
+ _enemyMageSfx = _staticres->loadRawData(kEoB1EnemyMageSfx, temp);
+ _beholderSpellList = _staticres->loadRawData(kEoB1BeholderSpellList, temp);
+ _beholderSfx = _staticres->loadRawData(kEoB1BeholderSfx, temp);
+
+ _cgaMappingDefault = _staticres->loadRawData(kEoB1CgaMappingDefault, temp);
+ _cgaMappingAlt = _staticres->loadRawData(kEoB1CgaMappingAlt, temp);
+ _cgaMappingInv = _staticres->loadRawData(kEoB1CgaMappingInv, temp);
+ _cgaMappingItemsL = _staticres->loadRawData(kEoB1CgaMappingItemsL, temp);
+ _cgaMappingItemsS = _staticres->loadRawData(kEoB1CgaMappingItemsS, temp);
+ _cgaMappingThrown = _staticres->loadRawData(kEoB1CgaMappingThrown, temp);
+ _cgaMappingIcons = _staticres->loadRawData(kEoB1CgaMappingIcons, temp);
+ _cgaMappingDeco = _staticres->loadRawData(kEoB1CgaMappingDeco, temp);
+ _cgaLevelMappingIndex = _staticres->loadRawData(kEoB1CgaLevelMappingIndex, temp);
+ for (int i = 0; i < 5; i++)
+ _cgaMappingLevel[i] = _staticres->loadRawData(kEoB1CgaMappingLevel0 + i, temp);
+
+ _turnUndeadString = _staticres->loadStrings(kEoB1TurnUndeadString, temp);
+
+ _npcShpData = _staticres->loadRawData(kEoB1NpcShpData, temp);
+ _npcSubShpIndex1 = _staticres->loadRawData(kEoB1NpcSubShpIndex1, temp);
+ _npcSubShpIndex2 = _staticres->loadRawData(kEoB1NpcSubShpIndex2, temp);
+ _npcSubShpY = _staticres->loadRawData(kEoB1NpcSubShpY, temp);
+ for (int i = 0; i < 11; i++)
+ _npcStrings[i] = _staticres->loadStrings(kEoB1Npc0Strings + i, temp);
+
+ const uint8 *ps = _staticres->loadRawData(kEoB1MonsterProperties, temp);
+ temp /= 27;
+ _monsterProps = new EoBMonsterProperty[temp];
+ memset(_monsterProps, 0, temp * sizeof(EoBMonsterProperty));
+ // Convert EOB1 (hard coded) monster properties to EOB2 type monster properties.
+ for (int i = 0; i < temp; i++) {
+ EoBMonsterProperty *p = &_monsterProps[i];
+ p->armorClass = (int8)*ps++;
+ p->hitChance = (int8)*ps++;
+ p->level = (int8)*ps++;
+ p->attacksPerRound = *ps++;
+ p->dmgDc[0].times = *ps++;
+ p->dmgDc[0].pips = *ps++;
+ p->dmgDc[0].base = (int8)*ps++;
+ p->dmgDc[1].times = *ps++;
+ p->dmgDc[1].pips = *ps++;
+ p->dmgDc[1].base = (int8)*ps++;
+ p->dmgDc[2].times = *ps++;
+ p->dmgDc[2].pips = *ps++;
+ p->dmgDc[2].base = (int8)*ps++;
+ ps++;
+ p->capsFlags = *ps++;
+ p->typeFlags = READ_LE_UINT16(ps);
+ ps += 2;
+ ps++;
+ ps++;
+ p->experience = READ_LE_UINT16(ps);
+ ps += 2;
+ p->u30 = *ps++;
+ p->sound1 = (int8)*ps++;
+ p->sound2 = (int8)*ps++;
+ p->numRemoteAttacks = *ps++;
+ p->tuResist = (int8)*ps++;
+ p->dmgModifierEvade = *ps++;
+ }
+
+ _monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1;
+ _monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2;
+
+ static const char *const errorSlotNoNameString[3] = {
+ " You must specify\r a name for your\r save game!",
+ " Spielstaende mues-\r sen einen Namen\r haben!",
+ 0
+ };
+
+ _errorSlotNoNameString = errorSlotNoNameString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+}
+
+void EoBEngine::initSpells() {
+ EoBCoreEngine::initSpells();
+
+ struct FlagTableEntry {
+ uint16 typeFlag;
+ uint32 effectFlag;
+ uint8 damageFlag;
+ };
+
+ static const FlagTableEntry flagTable[] = {
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x0033, 0x000001, 0x00 }, // armor
+ { 0x0100, 0x000000, 0x21 }, // burning hands
+ { 0x004C, 0x000002, 0x00 }, // detect magic
+ { 0x0100, 0x000000, 0x01 }, // magic missile
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x008B, 0x000008, 0x00 }, // shield
+ { 0x0488, 0x000000, 0x03 }, // shocking grasp
+ { 0x0021, 0x000040, 0x00 }, // invisibility
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x0100, 0x000000, 0x11 }, // melf's acid arrow
+ { 0x0000, 0x000000, 0x00 }, // STINKING CLOUD
+ { 0x1000, 0x000000, 0x00 }, // dispel magic
+ { 0x0100, 0x000000, 0x21 }, // fireball
+ { 0x0100, 0x000000, 0x11 }, // FLAME ARROW
+ { 0x0248, 0x010000, 0x00 }, // haste
+ { 0x0100, 0x000000, 0x00 }, // hold person
+ { 0x0240, 0x000040, 0x00 }, // inv 10'
+ { 0x0100, 0x000000, 0x03 }, // lightning bolt
+ { 0x0488, 0x000000, 0x01 }, // vampiric touch
+ { 0x0100, 0x000000, 0x00 }, // fear
+ { 0x0100, 0x000000, 0x41 }, // ice storm
+ { 0x0033, 0x000001, 0x00 }, // STONE SKIN
+ { 0x0000, 0x000000, 0x00 }, // CLOUD KILL
+ { 0x0100, 0x000000, 0x41 }, // cone of cold
+ { 0x0100, 0x000000, 0x00 }, // hold monster
+ { 0x005C, 0x000400, 0x00 }, // bless
+ { 0x0020, 0x000000, 0x00 }, // cure light wounds
+ { 0x0100, 0x000000, 0x01 }, // cause light wounds
+ { 0x004C, 0x000002, 0x00 }, // detect magic
+ { 0x0029, 0x000800, 0x00 }, // prot from evil
+ { 0x0039, 0x000000, 0x00 }, // aid
+ { 0x2408, 0x000000, 0x21 }, // flame blade
+ { 0x0100, 0x000000, 0x00 }, // hold person
+ { 0x0028, 0x002000, 0x00 }, // slow poison
+ { 0x0040, 0x000000, 0x00 }, // create food
+ { 0x1000, 0x000000, 0x00 }, // dispel magic
+ { 0x0099, 0x004000, 0x00 }, // magical vestment
+ { 0x004C, 0x008000, 0x00 }, // prayer
+ { 0x0040, 0x000000, 0x00 }, // remove paralysis
+ { 0x0020, 0x000000, 0x00 }, // cure serious
+ { 0x0100, 0x000000, 0x01 }, // cause serious
+ { 0x0020, 0x000000, 0x00 }, // neutralize poison
+ { 0x0248, 0x000800, 0x00 }, // prot from evil 10'
+ { 0x0000, 0x000000, 0x00 }, // PROT FROM LIGHTNING
+ { 0x0020, 0x000000, 0x00 }, // cure critical
+ { 0x0100, 0x000000, 0x01 }, // cause critical
+ { 0x0100, 0x000000, 0x21 }, // flame strike
+ { 0x0020, 0x000000, 0x00 }, // raise dead
+ { 0x0020, 0x000000, 0x00 }, // lay on hands
+ { 0x0000, 0x000000, 0x00 }, // obj hit passive
+ { 0x0000, 0x000000, 0x00 }, // disintegrate passive
+ { 0x0000, 0x000000, 0x00 } // death spell passive
+ };
+
+ int temp;
+ const uint8 *src = _staticres->loadRawData(kEoBBaseSpellProperties, temp);
+ _clericSpellOffset -= 1;
+
+ for (int i = 0; i < _numSpells; i++) {
+ EoBSpell *s = &_spells[i];
+ src += 4;
+ s->flags = flagTable[i].typeFlag;
+ s->damageFlags = flagTable[i].damageFlag;
+ s->effectFlags = flagTable[i].effectFlag;
+ s->sound = src[13];
+ src += 15;
+ }
+}
+
+const KyraRpgGUISettings EoBEngine::_guiSettingsVGA = {
+ { 9, 15, 95, 9, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
+ { 135, 130, 132, 133, 133, 17, 23, 20, 184, 177, 180, 184, 177, 180 }
+};
+
+const KyraRpgGUISettings EoBEngine::_guiSettingsEGA = {
+ { 9, 15, 95, 9, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
+ { 13, 9, 2, 133, 2, 6, 13, 8, 13, 15, 14, 13, 15, 14 }
+};
+
+const uint8 EoBEngine::_egaDefaultPalette[] = {
+ 0, 5, 3, 2, 10, 14, 12, 6, 4, 11, 9, 1, 0, 8, 7, 15
+};
+
+const uint8 EoBEngine::_monsterAcHitChanceTbl1[] = {
+ 3, 2, 1, 3
+};
+
+const uint8 EoBEngine::_monsterAcHitChanceTbl2[] = {
+ 2, 1, 1, 1
+};
+
+void DarkMoonEngine::initStaticResource() {
+ int temp;
+ _mainMenuStrings = _staticres->loadStrings(kEoB2MainMenuStrings, temp);
+
+ _dscDoorType5Offs = _staticres->loadRawData(kEoBBaseDscDoorType5Offs, temp);
+
+ _npcShpData = _staticres->loadRawData(kEoB2NpcShapeData, temp);
+ _npcStrings[0] = _staticres->loadStrings(kEoB2Npc1Strings, temp);
+ _npcStrings[1] = _staticres->loadStrings(kEoB2Npc2Strings, temp);
+ _monsterDustStrings = _staticres->loadStrings(kEoB2MonsterDustStrings, temp);
+ _dreamSteps = (const int8 *)_staticres->loadRawData(kEoB2DreamSteps, temp);
+ _kheldranStrings = _staticres->loadStrings(kEoB2KheldranStrings, temp);
+ _hornStrings = _staticres->loadStrings(kEoB2HornStrings, temp);
+ _hornSounds = _staticres->loadRawData(kEoB2HornSounds, temp);
+
+ _wallOfForceDsX = (const int16 *)_staticres->loadRawDataBe16(kEoB2WallOfForceDsX, temp);
+ _wallOfForceDsY = _staticres->loadRawData(kEoB2WallOfForceDsY, temp);
+ _wallOfForceDsNumW = _staticres->loadRawData(kEoB2WallOfForceNumW, temp);
+ _wallOfForceDsNumH = _staticres->loadRawData(kEoB2WallOfForceNumH, temp);
+ _wallOfForceShpId = _staticres->loadRawData(kEoB2WallOfForceShpId, temp);
+
+ _utilMenuStrings = _staticres->loadStrings(kEoB2UtilMenuStrings, temp);
+ _2431Strings = _staticres->loadStrings(kEoB2Config2431Strings, temp);
+ _katakanaLines = _staticres->loadStrings(kEoB2KatakanaLines, temp);
+ _katakanaSelectStrings = _staticres->loadStrings(kEoB2KanaSelectStrings, temp);
+
+ _ascii2SjisTables = _staticres->loadStrings(kEoB2Ascii2SjisTables, temp);
+ _ascii2SjisTables2 = _staticres->loadStrings(kEoB2Ascii2SjisTables2, temp);
+ _saveNamePatterns = _staticres->loadStrings(kEoB2SaveNamePatterns, temp);
+
+ const uint8 *data = _staticres->loadRawData(kEoB2PcmSoundEffectsIngame, temp);
+ SoundResourceInfo_TownsEoB ingame(data, temp, 127);
+ data = _staticres->loadRawData(kEoB2PcmSoundEffectsIntro, temp);
+ SoundResourceInfo_TownsEoB intro(data, temp, 40);
+ data = _staticres->loadRawData(kEoB2PcmSoundEffectsFinale, temp);
+ SoundResourceInfo_TownsEoB finale(data, temp, 40);
+
+ _sound->initAudioResourceInfo(kMusicIngame, &ingame);
+ _sound->initAudioResourceInfo(kMusicIntro, &intro);
+ _sound->initAudioResourceInfo(kMusicFinale, &finale);
+
+ _monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1;
+ _monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2;
+
+ static const char *const errorSlotNoNameString[3] = {
+ " You must specify\r a name for your\r save game!",
+ " Spielst[nde m]ssen\r einen Namen haben!",
+ 0
+ };
+
+ _errorSlotNoNameString = errorSlotNoNameString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+
+ // ScummVM specific
+ static const char *const transferStringsScummVM[3][5] = {
+ {
+ "\r We cannot find any EOB save game\r file. Please make sure that the\r save game file with the party\r you wish to transfer is located\r in your ScummVM save game\r directory. If you have set up\r multiple save directories you\r have to copy the EOB save file\r into your EOB II save directory.\r Do you wish to try again?",
+ "Game ID",
+ "\r It seems that you have already\r defeated Xanathar here. Do you\r wish to transfer the party that\r finished the game? If not, you\r will be able to select a save\r game from the save game\r dialogue.",
+ "Select File",
+ "\r\r Please wait..."
+ },
+ {
+ "\r Kein EOB-Spielstand zu finden.\r Bitte Spielstandsdatei mit der\r zu ]bernehmenden Gruppe in das\r ScummVM Spielstands-Verzeichnis\r kopieren. Bei mehreren Spiel-\r stands-Verzeichnissen bitte\r den EOB-Spielstand in das\r EOB II-Spielstands-Verzeichnis\r kopieren. Nochmal versuchen?",
+ "Game ID",
+ "\r Wie es scheint, wurde Xanathar\r hier bereits besiegt. Soll die\r Gruppe, mit der das Spiel be-\r endet wurde, ]bernommen werden?\r Falls nicht, kann ein Spielstand\r aus der Spielstandsliste gew[hlt\r werden.",
+ "Spiel W[hlen",
+ "\r\r Bitte warten..."
+ },
+ {
+ 0, 0, 0, 0
+ }
+ };
+
+ _transferStringsScummVM = transferStringsScummVM[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+}
+
+void DarkMoonEngine::initSpells() {
+ EoBCoreEngine::initSpells();
+
+ int temp;
+ const uint8 *src = _staticres->loadRawData(kEoBBaseSpellProperties, temp);
+
+ for (int i = 0; i < _numSpells; i++) {
+ EoBSpell *s = &_spells[i];
+ src += 8;
+ s->flags = READ_LE_UINT16(src);
+ src += 10;
+ s->sound = *src++;
+ s->effectFlags = READ_LE_UINT32(src);
+ src += 4;
+ s->damageFlags = READ_LE_UINT16(src);
+ src += 2;
+ }
+}
+
+const KyraRpgGUISettings DarkMoonEngine::_guiSettingsFMTowns = {
+ { 9, 15, 95, 11, 7, { 221, 76 }, { 187, 162 }, { 95, 95 } },
+ { 186, 181, 183, 133, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180 }
+};
+
+const KyraRpgGUISettings DarkMoonEngine::_guiSettingsDOS = {
+ { 9, 15, 95, 9, 7, { 221, 76 }, { 189, 162 }, { 95, 95 } },
+ { 186, 181, 183, 133, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180 }
+};
+
+const uint8 DarkMoonEngine::_egaDefaultPalette[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+const uint8 DarkMoonEngine::_monsterAcHitChanceTbl1[] = {
+ 1, 3, 3, 2
+};
+
+const uint8 DarkMoonEngine::_monsterAcHitChanceTbl2[] = {
+ 1, 1, 2, 1
+};
+
+#endif // ENABLE_EOB
+
+} // End of namespace Kyra
diff --git a/engines/kyra/resource/staticres_lol.cpp b/engines/kyra/resource/staticres_lol.cpp
new file mode 100644
index 0000000000..b4093cee46
--- /dev/null
+++ b/engines/kyra/resource/staticres_lol.cpp
@@ -0,0 +1,857 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/resource/resource.h"
+#include "kyra/engine/lol.h"
+#include "kyra/graphics/screen_lol.h"
+#include "kyra/gui/gui_lol.h"
+#include "kyra/sound/sound_intern.h"
+
+#ifdef ENABLE_LOL
+
+namespace Kyra {
+
+const LoLCharacter *StaticResource::loadCharData(int id, int &entries) {
+ return (const LoLCharacter *)getData(id, kLoLCharData, entries);
+}
+
+const SpellProperty *StaticResource::loadSpellData(int id, int &entries) {
+ return (const SpellProperty *)getData(id, kLoLSpellData, entries);
+}
+
+const CompassDef *StaticResource::loadCompassData(int id, int &entries) {
+ return (const CompassDef *)getData(id, kLoLCompassData, entries);
+}
+
+const FlyingObjectShape *StaticResource::loadFlyingObjectData(int id, int &entries) {
+ return (const FlyingObjectShape *)getData(id, kLoLFlightShpData, entries);
+}
+
+const LoLButtonDef *StaticResource::loadButtonDefs(int id, int &entries) {
+ return (const LoLButtonDef *)getData(id, kLoLButtonData, entries);
+}
+
+bool StaticResource::loadCharData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 130;
+ LoLCharacter *charData = new LoLCharacter[size];
+
+ for (int i = 0; i < size; i++) {
+ LoLCharacter *t = &charData[i];
+
+ t->flags = stream.readUint16LE();
+ stream.read(t->name, 11);
+ t->raceClassSex = stream.readByte();
+ t->id = stream.readSint16LE();
+ t->curFaceFrame = stream.readByte();
+ t->tempFaceFrame = stream.readByte();
+ t->screamSfx = stream.readByte();
+ stream.readUint32LE();
+ for (int ii = 0; ii < 8; ii++)
+ t->itemsMight[ii] = stream.readUint16LE();
+ for (int ii = 0; ii < 8; ii++)
+ t->protectionAgainstItems[ii] = stream.readUint16LE();
+ t->itemProtection = stream.readUint16LE();
+ t->hitPointsCur = stream.readSint16LE();
+ t->hitPointsMax = stream.readUint16LE();
+ t->magicPointsCur = stream.readSint16LE();
+ t->magicPointsMax = stream.readUint16LE();
+ t->field_41 = stream.readByte();
+ t->damageSuffered = stream.readUint16LE();
+ t->weaponHit = stream.readUint16LE();
+ t->totalMightModifier = stream.readUint16LE();
+ t->totalProtectionModifier = stream.readUint16LE();
+ t->might = stream.readUint16LE();
+ t->protection = stream.readUint16LE();
+ t->nextAnimUpdateCountdown = stream.readSint16LE();
+ for (int ii = 0; ii < 11; ii++)
+ t->items[ii] = stream.readUint16LE();
+ for (int ii = 0; ii < 3; ii++)
+ t->skillLevels[ii] = stream.readByte();
+ for (int ii = 0; ii < 3; ii++)
+ t->skillModifiers[ii] = stream.readByte();
+ for (int ii = 0; ii < 3; ii++)
+ t->experiencePts[ii] = stream.readUint32LE();
+ for (int ii = 0; ii < 5; ii++)
+ t->characterUpdateEvents[ii] = stream.readByte();
+ for (int ii = 0; ii < 5; ii++)
+ t->characterUpdateDelay[ii] = stream.readByte();
+ };
+
+ ptr = charData;
+ return true;
+}
+
+bool StaticResource::loadSpellData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 28;
+ SpellProperty *spellData = new SpellProperty[size];
+
+ for (int i = 0; i < size; i++) {
+ SpellProperty *t = &spellData[i];
+
+ t->spellNameCode = stream.readUint16LE();
+ for (int ii = 0; ii < 4; ii++)
+ t->mpRequired[ii] = stream.readUint16LE();
+ t->field_a = stream.readUint16LE();
+ t->field_c = stream.readUint16LE();
+ for (int ii = 0; ii < 4; ii++)
+ t->hpRequired[ii] = stream.readUint16LE();
+ t->field_16 = stream.readUint16LE();
+ t->field_18 = stream.readUint16LE();
+ t->flags = stream.readUint16LE();
+ };
+
+ ptr = spellData;
+ return true;
+}
+
+bool StaticResource::loadCompassData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 4;
+ CompassDef *defs = new CompassDef[size];
+
+ for (int i = 0; i < size; i++) {
+ CompassDef *t = &defs[i];
+ t->shapeIndex = stream.readByte();
+ t->x = stream.readByte();
+ t->y = stream.readByte();
+ t->flags = stream.readByte();
+ };
+
+
+ ptr = defs;
+ return true;
+}
+
+bool StaticResource::loadFlyingObjectData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 5;
+ FlyingObjectShape *defs = new FlyingObjectShape[size];
+
+ for (int i = 0; i < size; i++) {
+ FlyingObjectShape *t = &defs[i];
+ t->shapeFront = stream.readByte();
+ t->shapeBack = stream.readByte();
+ t->shapeLeft = stream.readByte();
+ t->drawFlags = stream.readByte();
+ t->flipFlags = stream.readByte();
+ };
+
+ ptr = defs;
+ return true;
+}
+
+bool StaticResource::loadButtonDefs(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 18;
+
+ LoLButtonDef *r = new LoLButtonDef[size];
+
+ for (int i = 0; i < size; i++) {
+ r[i].buttonflags = stream.readUint16BE();
+ r[i].keyCode = stream.readUint16BE();
+ r[i].keyCode2 = stream.readUint16BE();
+ r[i].x = stream.readSint16BE();
+ r[i].y = stream.readSint16BE();
+ r[i].w = stream.readUint16BE();
+ r[i].h = stream.readUint16BE();
+ r[i].index = stream.readUint16BE();
+ r[i].screenDim = stream.readUint16BE();
+ }
+
+ ptr = r;
+ return true;
+}
+
+void StaticResource::freeCharData(void *&ptr, int &size) {
+ LoLCharacter *d = (LoLCharacter *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeSpellData(void *&ptr, int &size) {
+ SpellProperty *d = (SpellProperty *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeCompassData(void *&ptr, int &size) {
+ CompassDef *d = (CompassDef *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeFlyingObjectData(void *&ptr, int &size) {
+ FlyingObjectShape *d = (FlyingObjectShape *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeButtonDefs(void *&ptr, int &size) {
+ LoLButtonDef *d = (LoLButtonDef *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void LoLEngine::initStaticResource() {
+ // assign music resource data.
+ if (_flags.platform == Common::kPlatformDOS) {
+ if (_flags.isDemo) {
+ static const char *const file[] = { "LOREDEMO" };
+ SoundResourceInfo_PC resInfoDemo(file, ARRAYSIZE(file));
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoDemo);
+ } else {
+ static const char *const intro[] = { "LOREINTR" };
+ static const char *const finale[] = { "LOREFINL" };
+ SoundResourceInfo_PC resInfoIntro(intro, ARRAYSIZE(intro));
+ SoundResourceInfo_PC resInfoFinale(finale, ARRAYSIZE(finale));
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ // In game music file handling is different, thus does not need a file list.
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ }
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ static const char *const fileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" };
+ static const char *const fileListFinale[] = { 0, 0, "lore85.86", "lore86.86", "lore87.86" };
+ SoundResourceInfo_TownsPC98V2 resInfoIntro(fileListIntro, ARRAYSIZE(fileListIntro), 0, 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "lore%02d.86", 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoFinale(fileListFinale, ARRAYSIZE(fileListFinale), 0, 0, 0);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ } else if (_flags.platform == Common::kPlatformFMTowns) {
+ static const char *const fileListIntro[] = { 0, "lore84.twn", "lore82.twn", 0, 0, 0, "lore83.twn", "lore81.twn" };
+ static const char *const fileListFinale[] = { 0, 0, "lore85.twn", "lore86.twn", "lore87.twn" };
+ SoundResourceInfo_TownsPC98V2 resInfoIntro(fileListIntro, ARRAYSIZE(fileListIntro), 0, 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "lore%02d.twn", 0, 0);
+ SoundResourceInfo_TownsPC98V2 resInfoFinale(fileListFinale, ARRAYSIZE(fileListFinale), 0, 0, 0);
+ _sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+ _sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+ _sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
+ }
+
+ if (_flags.isDemo)
+ return;
+
+ int tempSize;
+ _pakFileList = _staticres->loadStrings(kLoLIngamePakFiles, _pakFileListSize);
+ _charDefaults = _staticres->loadCharData(kLoLCharacterDefs, _charDefaultsSize);
+ _ingameSoundIndex = (const int16 *)_staticres->loadRawDataBe16(kLoLIngameSfxIndex, _ingameSoundIndexSize);
+ _musicTrackMap = _staticres->loadRawData(kLoLMusicTrackMap, tempSize);
+ _ingameGMSoundIndex = _staticres->loadRawData(kLoLIngameGMSfxIndex, _ingameGMSoundIndexSize);
+ _ingameMT32SoundIndex = _staticres->loadRawData(kLoLIngameMT32SfxIndex, _ingameMT32SoundIndexSize);
+ _ingamePCSpeakerSoundIndex = _staticres->loadRawData(kLoLIngamePcSpkSfxIndex, _ingamePCSpeakerSoundIndexSize);
+ _spellProperties = _staticres->loadSpellData(kLoLSpellProperties, tempSize);
+ _gameShapeMap = (const int8 *)_staticres->loadRawData(kLoLGameShapeMap, tempSize);
+ _sceneItemOffs = (const int8 *)_staticres->loadRawData(kLoLSceneItemOffs, tempSize);
+ _charInvIndex = _staticres->loadRawData(kLoLCharInvIndex, tempSize);
+ _charInvDefs = _staticres->loadRawData(kLoLCharInvDefs, tempSize);
+ _charDefsMan = _staticres->loadRawDataBe16(kLoLCharDefsMan, tempSize);
+ _charDefsWoman = _staticres->loadRawDataBe16(kLoLCharDefsWoman, tempSize);
+ _charDefsKieran = _staticres->loadRawDataBe16(kLoLCharDefsKieran, tempSize);
+ _charDefsAkshel = _staticres->loadRawDataBe16(kLoLCharDefsAkshel, tempSize);
+ _expRequirements = (const int32 *)_staticres->loadRawDataBe32(kLoLExpRequirements, tempSize);
+ _monsterModifiers1 = _staticres->loadRawDataBe16(kLoLMonsterModifiers1, tempSize);
+ _monsterModifiers2 = _staticres->loadRawDataBe16(kLoLMonsterModifiers2, tempSize);
+ _monsterModifiers3 = _staticres->loadRawDataBe16(kLoLMonsterModifiers3, tempSize);
+ _monsterModifiers4 = _staticres->loadRawDataBe16(kLoLMonsterModifiers4, tempSize);
+ _monsterShiftOffs = (const int8 *)_staticres->loadRawData(kLoLMonsterShiftOffsets, tempSize);
+ _monsterDirFlags = _staticres->loadRawData(kLoLMonsterDirFlags, tempSize);
+ _monsterScaleX = _staticres->loadRawData(kLoLMonsterScaleX, tempSize);
+ _monsterScaleY = _staticres->loadRawData(kLoLMonsterScaleY, tempSize);
+ _monsterScaleWH = _staticres->loadRawDataBe16(kLoLMonsterScaleWH, tempSize);
+ _inventorySlotDesc = _staticres->loadRawDataBe16(kLoLInventoryDesc, tempSize);
+ _levelShpList = _staticres->loadStrings(kLoLLevelShpList, tempSize);
+ _levelDatList = _staticres->loadStrings(kLoLLevelDatList, tempSize);
+ _compassDefs = _staticres->loadCompassData(kLoLCompassDefs, tempSize);
+ _flyingItemShapes = _staticres->loadFlyingObjectData(kLoLFlyingObjectShp, tempSize);
+ _itemCost = _staticres->loadRawDataBe16(kLoLItemPrices, tempSize);
+ _stashSetupData = _staticres->loadRawData(kLoLStashSetup, tempSize);
+
+ _dscWalls = (const int8 *)_staticres->loadRawData(kLoLDscWalls, tempSize);
+
+ _dscOvlMap = _staticres->loadRawData(kLoLDscOvlMap, tempSize);
+ _dscShapeOvlIndex = _staticres->loadRawData(kLoLDscOvlIndex, tempSize);
+ _dscShapeScaleW = _staticres->loadRawDataBe16(kLoLDscScaleWidthData, tempSize);
+ _dscShapeScaleH = _staticres->loadRawDataBe16(kLoLDscScaleHeightData, tempSize);
+ _dscShapeY = (const int8 *)_staticres->loadRawData(kLoLBaseDscY, tempSize);
+
+ _dscDoorMonsterScaleTable = _staticres->loadRawDataBe16(kLoLDscDoorScale, tempSize);
+ _dscDoor4 = _staticres->loadRawDataBe16(kLoLDscDoor4, tempSize);
+ _dscDoorMonsterX = (const int16 *)_staticres->loadRawDataBe16(kLoLDscDoorX, tempSize);
+ _dscDoorMonsterY = (const int16 *)_staticres->loadRawDataBe16(kLoLDscDoorY, tempSize);
+
+ _scrollXTop = _staticres->loadRawData(kLoLScrollXTop, tempSize);
+ _scrollYTop = _staticres->loadRawData(kLoLScrollYTop, tempSize);
+ _scrollXBottom = _staticres->loadRawData(kLoLScrollXBottom, tempSize);
+ _scrollYBottom = _staticres->loadRawData(kLoLScrollYBottom, tempSize);
+
+ const char *const *tmpSndList = _staticres->loadStrings(kLoLIngameSfxFiles, _ingameSoundListSize);
+ if (tmpSndList) {
+ _ingameSoundList = new char*[_ingameSoundListSize];
+ for (int i = 0; i < _ingameSoundListSize; i++) {
+ _ingameSoundList[i] = new char[strlen(tmpSndList[i]) + 1];
+ strcpy(_ingameSoundList[i], tmpSndList[i]);
+ }
+ _staticres->unloadId(kLoLIngameSfxFiles);
+ }
+
+ _buttonData = _staticres->loadButtonDefs(kLoLButtonDefs, tempSize);
+ _buttonList1 = _staticres->loadRawData(kLoLButtonList1, tempSize);
+ _buttonList2 = _staticres->loadRawData(kLoLButtonList2, tempSize);
+ _buttonList3 = _staticres->loadRawData(kLoLButtonList3, tempSize);
+ _buttonList4 = _staticres->loadRawData(kLoLButtonList4, tempSize);
+ _buttonList5 = _staticres->loadRawData(kLoLButtonList5, tempSize);
+ _buttonList6 = _staticres->loadRawData(kLoLButtonList6, tempSize);
+ _buttonList7 = _staticres->loadRawData(kLoLButtonList7, tempSize);
+ _buttonList8 = _staticres->loadRawData(kLoLButtonList8, tempSize);
+
+ _autoMapStrings = _staticres->loadRawDataBe16(kLoLMapStringId, tempSize);
+
+ const uint8 *tmp = _staticres->loadRawData(kLoLLegendData, tempSize);
+ uint8 entrySize = tempSize / 12;
+ tempSize /= entrySize;
+ if (tempSize) {
+ _defaultLegendData = new MapLegendData[tempSize];
+ for (int i = 0; i < tempSize; i++) {
+ _defaultLegendData[i].shapeIndex = *tmp++;
+ _defaultLegendData[i].enable = *tmp++ ? true : false;
+ _defaultLegendData[i].y = (entrySize == 5) ? (int8)*tmp++ : (i == 10 ? -5 : 0);
+ _defaultLegendData[i].stringId = READ_LE_UINT16(tmp);
+ tmp += 2;
+ }
+ _staticres->unloadId(kLoLLegendData);
+ }
+
+ tmp = _staticres->loadRawData(kLoLMapCursorOvl, tempSize);
+ if (tmp) {
+ _mapCursorOverlay = new uint8[tempSize];
+ memcpy(_mapCursorOverlay, tmp, tempSize);
+ _staticres->unloadId(kLoLMapCursorOvl);
+ }
+
+ _updateSpellBookCoords = _staticres->loadRawData(kLoLSpellbookCoords, tempSize);
+ _updateSpellBookAnimData = _staticres->loadRawData(kLoLSpellbookAnim, tempSize);
+ _healShapeFrames = _staticres->loadRawData(kLoLHealShapeFrames, tempSize);
+
+ tmp = _staticres->loadRawData(kLoLLightningDefs, tempSize);
+ if (tmp) {
+ _lightningProps = new LightningProperty[5];
+ for (int i = 0; i < 5; i++) {
+ _lightningProps[i].lastFrame = tmp[i << 2];
+ _lightningProps[i].frameDiv = tmp[(i << 2) + 1];
+ _lightningProps[i].sfxId = READ_LE_UINT16(&tmp[(i << 2) + 2]);
+ }
+ _staticres->unloadId(kLoLLightningDefs);
+ }
+
+ _fireBallCoords = (const int16 *)_staticres->loadRawDataBe16(kLoLFireballCoords, tempSize);
+
+ _buttonCallbacks.clear();
+ _buttonCallbacks.reserve(95);
+#define cb(x) _buttonCallbacks.push_back(BUTTON_FUNCTOR(LoLEngine, this, &LoLEngine::x))
+ // 0x00
+ cb(clickedUpArrow);
+ cb(clickedDownArrow);
+ _buttonCallbacks.push_back(_buttonCallbacks[1]);
+ cb(clickedLeftArrow);
+
+ // 0x04
+ cb(clickedRightArrow);
+ cb(clickedTurnLeftArrow);
+ cb(clickedTurnRightArrow);
+ cb(clickedAttackButton);
+
+ // 0x08
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[7]);
+ cb(clickedMagicButton);
+
+ // 0x0C
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[11]);
+ cb(clickedMagicSubmenu);
+
+ // 0x10
+ cb(clickedScreen);
+ cb(clickedPortraitLeft);
+ for (int i = 0; i < 7; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[17]);
+
+ // 0x19
+ cb(clickedLiveMagicBarsLeft);
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[25]);
+
+ // 0x1D
+ cb(clickedPortraitEtcRight);
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[29]);
+
+ // 0x21
+ cb(clickedCharInventorySlot);
+ for (int i = 0; i < 10; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[33]);
+
+ // 0x2C
+ cb(clickedExitCharInventory);
+ cb(clickedSceneDropItem);
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[45]);
+
+ // 0x31
+ cb(clickedScenePickupItem);
+ cb(clickedInventorySlot);
+ for (int i = 0; i < 9; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[50]);
+
+ // 0x3C
+ cb(clickedInventoryScroll);
+ cb(clickedInventoryScroll);
+ cb(clickedWall);
+ _buttonCallbacks.push_back(_buttonCallbacks[62]);
+
+ // 0x40
+ cb(clickedSequenceWindow);
+ _buttonCallbacks.push_back(_buttonCallbacks[0]);
+ _buttonCallbacks.push_back(_buttonCallbacks[1]);
+ _buttonCallbacks.push_back(_buttonCallbacks[3]);
+
+ // 0x44
+ _buttonCallbacks.push_back(_buttonCallbacks[4]);
+ _buttonCallbacks.push_back(_buttonCallbacks[5]);
+ _buttonCallbacks.push_back(_buttonCallbacks[6]);
+ cb(clickedScroll);
+
+ // 0x48
+ for (int i = 0; i < 9; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[71]);
+
+ // 0x51
+ cb(clickedSpellTargetCharacter);
+ for (int i = 0; i < 3; ++i)
+ _buttonCallbacks.push_back(_buttonCallbacks[81]);
+
+ // 0x55
+ cb(clickedSpellTargetScene);
+ cb(clickedSceneThrowItem);
+ _buttonCallbacks.push_back(_buttonCallbacks[86]);
+
+ // 0x58
+ cb(clickedOptions);
+ cb(clickedRestParty);
+ cb(clickedMoneyBox);
+ cb(clickedCompass);
+
+ // 0x5C
+ cb(clickedAutomap);
+ cb(clickedLamp);
+ cb(clickedStatusIcon);
+#undef cb
+}
+
+void GUI_LoL::initStaticData() {
+ GUI_V2_BUTTON(_scrollUpButton, 20, 96, 0, 1, 1, 1, 0x4487, 0, 0, 0, 25, 16, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0);
+ GUI_V2_BUTTON(_scrollDownButton, 21, 98, 0, 1, 1, 1, 0x4487, 0, 0, 0, 25, 16, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0);
+
+ for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i)
+ GUI_V2_BUTTON(_menuButtons[i], i, 0, 0, 0, 0, 0, 0x4487, 0, 0, 0, 0, 0, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0);
+
+ if (_vm->gameFlags().isTalkie)
+ GUI_LOL_MENU(_mainMenu, 9, 0x4000, 0, 7, -1, -1, -1, -1);
+ else
+ GUI_LOL_MENU(_mainMenu, 17, 0x4000, 0, 6, -1, -1, -1, -1);
+
+ GUI_LOL_MENU_ITEM(_mainMenu.item[0], 0x4001, 16, 23, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[1], 0x4002, 16, 40, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[2], 0x4003, 16, 57, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[3], 0x4004, 16, 74, 176, 15, 0, 0);
+
+ if (_vm->gameFlags().isTalkie) {
+ GUI_LOL_MENU_ITEM(_mainMenu.item[4], 0x42D9, 16, 91, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[5], 0x4006, 16, 108, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[6], 0x4005, 88, 127, 104, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ } else {
+ GUI_LOL_MENU_ITEM(_mainMenu.item[4], 0x4006, 16, 91, 176, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_mainMenu.item[5], 0x4005, 88, 110, 104, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ }
+
+ Button::Callback mainMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedMainMenu);
+ for (int i = 0; i < _mainMenu.numberOfItems; ++i)
+ _mainMenu.item[i].callback = mainMenuFunctor;
+
+ GUI_LOL_MENU(_loadMenu, 10, 0x400E, 1, 5, 128, 20, 128, 118);
+ GUI_LOL_MENU_ITEM(_loadMenu.item[0], 0xFFFE, 8, 39, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_loadMenu.item[1], 0xFFFD, 8, 56, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_loadMenu.item[2], 0xFFFC, 8, 73, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_loadMenu.item[3], 0xFFFB, 8, 90, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_loadMenu.item[4], 0x4011, 168, 118, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ Button::Callback loadMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedLoadMenu);
+ for (int i = 0; i < 5; ++i)
+ _loadMenu.item[i].callback = loadMenuFunctor;
+
+ GUI_LOL_MENU(_saveMenu, 10, 0x400D, 1, 5, 128, 20, 128, 118);
+ GUI_LOL_MENU_ITEM(_saveMenu.item[0], 0xFFFE, 8, 39, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_saveMenu.item[1], 0xFFFD, 8, 56, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_saveMenu.item[2], 0xFFFC, 8, 73, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_saveMenu.item[3], 0xFFFB, 8, 90, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_saveMenu.item[4], 0x4011, 168, 118, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ Button::Callback saveMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedSaveMenu);
+ for (int i = 0; i < 5; ++i)
+ _saveMenu.item[i].callback = saveMenuFunctor;
+
+ GUI_LOL_MENU(_deleteMenu, 10, 0x400F, 1, 5, 128, 20, 128, 118);
+ GUI_LOL_MENU_ITEM(_deleteMenu.item[0], 0xFFFE, 8, 39, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_deleteMenu.item[1], 0xFFFD, 8, 56, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_deleteMenu.item[2], 0xFFFC, 8, 73, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_deleteMenu.item[3], 0xFFFB, 8, 90, 256, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_deleteMenu.item[4], 0x4011, 168, 118, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ Button::Callback deleteMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedDeleteMenu);
+ for (int i = 0; i < 5; ++i)
+ _deleteMenu.item[i].callback = deleteMenuFunctor;
+
+ GUI_LOL_MENU(_gameOptions, 17, 0x400C, 0, 6, -1, -1, -1, -1);
+ if (_vm->gameFlags().isTalkie) {
+ GUI_LOL_MENU_ITEM(_gameOptions.item[0], 0xFFF7, 120, 22, 80, 15, 0x406E, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[1], 0xFFF6, 120, 39, 80, 15, 0x406C, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[2], 0xFFF5, 120, 56, 80, 15, 0x406D, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[3], 0xFFF4, 120, 73, 80, 15, 0x42D5, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[4], 0xFFF3, 120, 90, 80, 15, 0x42D2, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[5], 0x4072, 104, 110, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ } else {
+ GUI_LOL_MENU_ITEM(_gameOptions.item[0], 0xFFF9, 120, 22, 80, 15, 0x406A, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[1], 0xFFF8, 120, 39, 80, 15, 0x406B, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[2], 0xFFF7, 120, 56, 80, 15, 0x406E, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[3], 0xFFF6, 120, 73, 80, 15, 0x406C, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[4], 0xFFF5, 120, 90, 80, 15, 0x406D, 0);
+ GUI_LOL_MENU_ITEM(_gameOptions.item[5], 0x4072, 104, 110, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ }
+ Button::Callback optionsMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedOptionsMenu);
+ for (int i = 0; i < _gameOptions.numberOfItems; ++i)
+ _gameOptions.item[i].callback = optionsMenuFunctor;
+
+ GUI_LOL_MENU(_audioOptions, 18, 0x42D9, 2, 1, -1, -1, -1, -1);
+ GUI_LOL_MENU_ITEM(_audioOptions.item[0], 0x4072, 152, 76, 96, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ GUI_LOL_MENU_ITEM(_audioOptions.item[1], 3, 128, 22, 114, 14, 0x42DB, 0);
+ GUI_LOL_MENU_ITEM(_audioOptions.item[2], 4, 128, 39, 114, 14, 0x42DA, 0);
+ GUI_LOL_MENU_ITEM(_audioOptions.item[3], 5, 128, 56, 114, 14, 0x42DC, 0);
+ Button::Callback audioMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedAudioMenu);
+ for (int i = 0; i < 4; ++i)
+ _audioOptions.item[i].callback = audioMenuFunctor;
+
+ GUI_LOL_MENU(_deathMenu, 11, 0x4013, 0, 2, -1, -1, -1, -1);
+ GUI_LOL_MENU_ITEM(_deathMenu.item[0], 0x4006, 8, 30, 104, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_deathMenu.item[1], 0x4001, 176, 30, 104, 15, 0, 0);
+ Button::Callback deathMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedDeathMenu);
+ for (int i = 0; i < 2; ++i)
+ _deathMenu.item[i].callback = deathMenuFunctor;
+
+ GUI_LOL_MENU(_savenameMenu, 7, 0x4053, 0, 2, -1, -1, -1, -1);
+ GUI_LOL_MENU_ITEM(_savenameMenu.item[0], 0x4012, 8, 38, 72, 15, 0, _vm->_keyMap[Common::KEYCODE_RETURN]);
+ GUI_LOL_MENU_ITEM(_savenameMenu.item[1], 0x4011, 176, 38, 72, 15, 0, _vm->_keyMap[Common::KEYCODE_ESCAPE]);
+ Button::Callback savenameMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedSavenameMenu);
+ for (int i = 0; i < 2; ++i)
+ _savenameMenu.item[i].callback = savenameMenuFunctor;
+
+ GUI_LOL_MENU(_choiceMenu, 11, 0, 0, 2, -1, -1, -1, -1);
+ GUI_LOL_MENU_ITEM(_choiceMenu.item[0], 0x4007, 8, 30, 72, 15, 0, 0);
+ GUI_LOL_MENU_ITEM(_choiceMenu.item[1], 0x4008, 208, 30, 72, 15, 0, 0);
+ Button::Callback choiceMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedChoiceMenu);
+ for (int i = 0; i < 2; ++i)
+ _choiceMenu.item[i].callback = choiceMenuFunctor;
+}
+
+const ScreenDim Screen_LoL::_screenDimTable256C[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 }, // Taken from Intro
+ { 0x08, 0x48, 0x18, 0x38, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x0E, 0x00, 0x16, 0x78, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x0B, 0x7B, 0x1C, 0x12, 0xFE, 0xFC, 0x00, 0x00 },
+ { 0x0B, 0x7B, 0x1C, 0x2D, 0xFE, 0xFC, 0x00, 0x00 },
+ { 0x55, 0x7B, 0xE9, 0x37, 0xFE, 0xFC, 0x00, 0x00 },
+ { 0x0B, 0x8C, 0x10, 0x2B, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (4 entries)
+ { 0x04, 0x59, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x05, 0x6E, 0x1E, 0x0C, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x07, 0x19, 0x1A, 0x97, 0x00, 0x00, 0x00, 0x00 }, // Ingame main menu box CD version
+ { 0x03, 0x1E, 0x22, 0x8C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x02, 0x48, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0E, 0x00, 0x16, 0x78, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x0D, 0xA2, 0x18, 0x0C, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x0F, 0x06, 0x14, 0x6E, 0x01, 0x00, 0x00, 0x00 },
+ { 0x1A, 0xBE, 0x0A, 0x07, 0xFE, 0x01, 0x00, 0x00 },
+ { 0x07, 0x21, 0x1A, 0x85, 0x00, 0x00, 0x00, 0x00 },
+ { 0x03, 0x32, 0x22, 0x62, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0B, 0x8C, 0x10, 0x33, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (5 entries, CD version only)
+ { 0x0B, 0x8C, 0x10, 0x23, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (3 entries, floppy version only)
+
+ { 0x01, 0x20, 0x26, 0x80, 0xDC, 0xFD, 0x00, 0x00 }, // Credits
+ { 0x09, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x19, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x01, 0x02, 0x26, 0x14, 0x00, 0x0F, 0x0E, 0x00 },
+};
+
+const ScreenDim Screen_LoL::_screenDimTable16C[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0x33, 0x44, 0x00, 0x00 }, // Taken from Intro
+ { 0x08, 0x48, 0x18, 0x38, 0x33, 0x44, 0x00, 0x00 },
+ { 0x0E, 0x00, 0x16, 0x78, 0x33, 0x44, 0x00, 0x00 },
+ { 0x0B, 0x7B, 0x1C, 0x11, 0x33, 0x11, 0x00, 0x00 },
+ { 0x0B, 0x7B, 0x1C, 0x2D, 0x33, 0x11, 0x00, 0x00 },
+ { 0x55, 0x7B, 0xE9, 0x37, 0x33, 0x11, 0x00, 0x00 },
+ { 0x0B, 0x92, 0x10, 0x2A, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (4 entries)
+ { 0x04, 0x58, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x05, 0x6C, 0x1E, 0x0D, 0x33, 0x44, 0x00, 0x00 },
+ { 0x07, 0x20, 0x1A, 0x86, 0x00, 0x00, 0x00, 0x00 },
+ { 0x03, 0x20, 0x22, 0x8C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x02, 0x48, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0E, 0x00, 0x16, 0x78, 0x33, 0x44, 0x00, 0x00 },
+ { 0x0D, 0xA2, 0x18, 0x0C, 0x33, 0x44, 0x00, 0x00 },
+ { 0x0F, 0x06, 0x14, 0x6E, 0x44, 0x00, 0x00, 0x00 },
+ { 0x1A, 0xBE, 0x0A, 0x07, 0x33, 0x44, 0x00, 0x00 },
+ { 0x07, 0x21, 0x1A, 0x85, 0x00, 0x00, 0x00, 0x00 },
+ { 0x03, 0x32, 0x22, 0x62, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0B, 0x8C, 0x10, 0x33, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (5 entries, not used here)
+ { 0x0B, 0x8C, 0x10, 0x23, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (3 entries)
+
+ { 0x01, 0x20, 0x26, 0x80, 0xDC, 0xFD, 0x00, 0x00 }, // Credits (TODO: Check this!)
+ { 0x09, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x19, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x01, 0x02, 0x26, 0x14, 0x00, 0x0F, 0x0E, 0x00 },
+};
+
+const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable256C);
+
+const char *const LoLEngine::_languageExt[] = {
+ "ENG",
+ "FRE",
+ "GER"
+};
+
+const char *const LoLEngine::_charPreviewNamesDefault[] = {
+ "Ak\'shel",
+ "Michael",
+ "Kieran",
+ "Conrad"
+};
+
+const char *const LoLEngine::_charPreviewNamesRussianFloppy[] = {
+ "\x80\xAA\xE8\xA5\xAB\0",
+ "\x8C\xA0\xA9\xAA\xAB\0",
+ "\x8A\xA8\xE0\xA0\xAD\0",
+ "\x8A\xAE\xAD\xE0\xA0\xA4\0"
+};
+
+const LoLEngine::CharacterPrev LoLEngine::_charPreviews[] = {
+ { 0x060, 0x7F, { 0x0F, 0x08, 0x05 } },
+ { 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } },
+ { 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } },
+ { 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } }
+};
+
+const uint16 LoLEngine::_charPosXPC98[] = {
+ 92, 152, 212, 268
+};
+
+const char *const LoLEngine::_charNamesJapanese[] = {
+ "\x83\x41\x83\x4E\x83\x56\x83\x46\x83\x8B\0",
+ "\x83\x7D\x83\x43\x83\x50\x83\x8B\x00\x00\0",
+ "\x83\x4C\x81\x5B\x83\x89\x83\x93\x00\x00\0",
+ "\x83\x52\x83\x93\x83\x89\x83\x62\x83\x68\0"
+};
+
+const uint8 LoLEngine::_chargenFrameTableTalkie[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12
+};
+
+const uint8 LoLEngine::_chargenFrameTableFloppy[] = {
+ 0, 1, 2, 3, 4, 5, 4, 3, 2,
+ 1, 0, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+const uint16 LoLEngine::_selectionPosTable[] = {
+ 0x6F, 0x00, 0x8F, 0x00, 0xAF, 0x00, 0xCF, 0x00,
+ 0xEF, 0x00, 0x6F, 0x20, 0x8F, 0x20, 0xAF, 0x20,
+ 0xCF, 0x20, 0xEF, 0x20, 0x6F, 0x40, 0x8F, 0x40,
+ 0xAF, 0x40, 0xCF, 0x40, 0xEF, 0x40, 0x10F, 0x00
+};
+
+const uint8 LoLEngine::_selectionChar1IdxTable[] = {
+ 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 5, 5,
+ 5, 5, 5
+};
+
+const uint8 LoLEngine::_selectionChar2IdxTable[] = {
+ 1, 1, 6, 6, 1, 1, 6, 6,
+ 6, 6, 6, 6, 6, 1, 1, 6,
+ 6, 6, 1, 1, 6, 6, 6, 6,
+ 6, 6, 6
+};
+
+const uint8 LoLEngine::_selectionChar3IdxTable[] = {
+ 2, 2, 7, 7, 7, 7, 2, 2,
+ 7, 7, 7, 7, 7, 7, 7, 2,
+ 2, 7, 7, 7, 7, 2, 2, 7,
+ 7, 7, 7
+};
+
+const uint8 LoLEngine::_selectionChar4IdxTable[] = {
+ 3, 3, 8, 8, 8, 8, 3, 3,
+ 8, 8, 3, 3, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 3, 3, 8,
+ 8, 8, 8
+};
+
+const uint8 LoLEngine::_reminderChar1IdxTable[] = {
+ 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5
+};
+
+const uint8 LoLEngine::_reminderChar2IdxTable[] = {
+ 9, 9, 9, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6
+};
+
+const uint8 LoLEngine::_reminderChar3IdxTable[] = {
+ 0xE, 0xE, 0xE, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7
+};
+
+const uint8 LoLEngine::_reminderChar4IdxTable[] = {
+ 0xF, 0xF, 0xF, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8
+};
+
+const uint8 LoLEngine::_selectionAnimIndexTable[] = {
+ 0, 5, 1, 6, 2, 7, 3, 8
+};
+
+const uint8 LoLEngine::_charInfoFrameTable[] = {
+ 0x0, 0x7, 0x8, 0x9, 0xA, 0xB, 0xA, 0x9,
+ 0x8, 0x7, 0x0, 0x0, 0x7, 0x8, 0x9, 0xA,
+ 0xB, 0xA, 0x9, 0x8, 0x7, 0x0, 0x0, 0x7,
+ 0x8, 0x9, 0xA, 0xB, 0xA, 0x9, 0x8, 0x7
+};
+
+const uint8 LoLEngine::_clock2Timers[] = {
+ 0x00, 0x10, 0x11, 0x03, 0x04, 0x50,
+ 0x51, 0x52, 0x08, 0x09, 0x0A
+};
+
+const uint8 LoLEngine::_numClock2Timers = ARRAYSIZE(LoLEngine::_clock2Timers);
+
+const int8 LoLEngine::_mapCoords[12][4] = {
+ { 0, 7, 0, -5 }, { -5, 0, 6, 0 }, { 7, 5, 7, 1 },
+ { 5, 6, 4, 6 }, { 0, 7, 0, -1 }, { -3, 0, 6, 0 },
+ { 6, 7, 6, -3 }, { -3, 5, 6, 5 }, { 1, 5, 1, 1 },
+ { 3, 1, 3, 1 }, { -1, 6, -1, -8 }, { -7, -1, 5, -1 }
+};
+
+const KyraRpgGUISettings LoLEngine::_guiSettings = {
+ { 144, 254, 74, 9, 80, { 0, 0 }, { 0, 0 }, { 0, 0 } },
+ { 136, 251, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+const MistOfDoomAnimData LoLEngine::_mistAnimData[] = {
+ { 0, 7, 7, 13, 155 },
+ { 0, 16, 16, 17, 155 },
+ { 0, 24, 24, 24, 174 },
+ { 0, 19, 19, 19, 174 },
+ { 0, 16, 16, 17, 175 },
+};
+
+const char *const LoLEngine::_outroShapeFileTable[] = {
+ "AMAZON.SHP", "ARCHRSLG.SHP", "AVIANWRM.SHP", "BANDIT.SHP", "BOAR.SHP", "CABAL.SHP",
+ "GUARD.SHP", "HAG.SHP", "HORNET.SHP", "HURZELL.SHP", "IRONGRZR.SHP", "KNOWLES.SHP",
+ "LIZARD.SHP", "MANTHA.SHP", "MINOTAUR.SHP", "MORIBUND.SHP", "ORC.SHP", "ORCLDR.SHP",
+ "PENTROG.SHP", "RATMAN.SHP", "ROCKLING.SHP", "SCAVNGR.SHP", "STARK.SHP",
+ "SWAMPCIT.SHP", "SWAMPMON.SHP", "THUG.SHP", "VIPER.SHP", "XEOB.SHP"
+};
+
+const uint8 LoLEngine::_outroFrameTable[] = {
+ 0, 0, 0, 0, 0, 1, 2, 3,
+ 0, 1, 2, 3, 8, 9, 10, 11,
+ 8, 9, 10, 11, 4, 5, 6, 7
+};
+
+const int16 LoLEngine::_outroRightMonsterPos[] = {
+ 205, 55, 205, 55, 205, 55, 205, 55,
+ 205, 56, 207, 57, 208, 58, 210, 59,
+ 213, 60, 216, 61, 220, 61, 225, 61,
+ 230, 61, 235, 61, 240, 61, 240, 61,
+ 240, 61, 240, 61, 240, 61, 240, 61,
+ 240, 61, 265, 61, 290, 61, 315, 61
+};
+
+const int16 LoLEngine::_outroLeftMonsterPos[] = {
+ 92, 55, 92, 55, 92, 55, 92, 55,
+ 92, 56, 90, 57, 85, 58, 77, 59,
+ 67, 60, 57, 61, 47, 61, 35, 61,
+ 35, 61, 35, 61, 35, 61, 35, 61,
+ 35, 61, 35, 61, 35, 61, 35, 61,
+ 35, 61, 10, 61, -20, 61, -45, 61
+};
+
+const int16 LoLEngine::_outroRightDoorPos[] = {
+ 200, 41, 200, 29, 200, 17, 200, 5,
+ 200, -7, 200, -7, 200, -7, 200, -7,
+ 200, 5, 200, 17, 200, 29, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41
+};
+
+const int16 LoLEngine::_outroLeftDoorPos[] = {
+ 72, 41, 72, 29, 72, 17, 72, 5,
+ 72, -7, 72, -7, 72, -7, 72, -7,
+ 72, 5, 72, 17, 72, 29, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41
+};
+
+const int LoLEngine::_outroMonsterScaleTableX[] = {
+ 0x050, 0x050, 0x050, 0x050, 0x050, 0x05D, 0x070, 0x085,
+ 0x0A0, 0x0C0, 0x0E2, 0x100, 0x100, 0x100, 0x100, 0x100,
+ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100
+};
+
+const int LoLEngine::_outroMonsterScaleTableY[] = {
+ 0x04C, 0x04C, 0x04C, 0x04C, 0x04C, 0x059, 0x06B, 0x080,
+ 0x099, 0x0B8, 0x0D9, 0x100, 0x100, 0x100, 0x100, 0x100,
+ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/resource/staticres_rpg.cpp b/engines/kyra/resource/staticres_rpg.cpp
new file mode 100644
index 0000000000..d0156e3340
--- /dev/null
+++ b/engines/kyra/resource/staticres_rpg.cpp
@@ -0,0 +1,99 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/resource/resource.h"
+
+
+namespace Kyra {
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+const uint16 *StaticResource::loadRawDataBe16(int id, int &entries) {
+ return (const uint16 *)getData(id, kRawDataBe16, entries);
+}
+
+const uint32 *StaticResource::loadRawDataBe32(int id, int &entries) {
+ return (const uint32 *)getData(id, kRawDataBe32, entries);
+}
+
+bool StaticResource::loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() >> 1;
+
+ uint16 *r = new uint16[size];
+
+ for (int i = 0; i < size; i++)
+ r[i] = stream.readUint16BE();
+
+ ptr = r;
+ return true;
+}
+
+bool StaticResource::loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() >> 2;
+
+ uint32 *r = new uint32[size];
+
+ for (int i = 0; i < size; i++)
+ r[i] = stream.readUint32BE();
+
+ ptr = r;
+ return true;
+}
+
+void StaticResource::freeRawDataBe16(void *&ptr, int &size) {
+ uint16 *data = (uint16 *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeRawDataBe32(void *&ptr, int &size) {
+ uint32 *data = (uint32 *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+const uint8 KyraRpgEngine::_dropItemDirIndex[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
+
+void KyraRpgEngine::initStaticResource() {
+ int temp;
+ _dscShapeX = (const int16 *)_staticres->loadRawDataBe16(kRpgCommonDscX, temp);
+ _dscShapeIndex = (const int8 *)_staticres->loadRawData(kRpgCommonDscShapeIndex, temp);
+ _dscTileIndex = _staticres->loadRawData(kRpgCommonDscTileIndex, temp);
+ _dscDim1 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData1, temp);
+ _dscDim2 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData2, temp);
+ _dscDoorScaleOffs = _staticres->loadRawData(kRpgCommonDscDoorScaleOffs, temp);
+ _dscBlockMap = _staticres->loadRawData(kRpgCommonDscBlockMap, temp);
+ _dscBlockIndex = (const int8 *)_staticres->loadRawData(kRpgCommonDscBlockIndex, temp);
+ _dscDimMap = _staticres->loadRawData(kRpgCommonDscDimMap, temp);
+ _dscDoorShpIndex = _staticres->loadRawData(kRpgCommonDscDoorShapeIndex, _dscDoorShpIndexSize);
+ _dscDoorY2 = _staticres->loadRawData(kRpgCommonDscDoorY2, temp);
+ _dscDoorFrameY1 = _staticres->loadRawData(kRpgCommonDscDoorFrameY1, temp);
+ _dscDoorFrameY2 = _staticres->loadRawData(kRpgCommonDscDoorFrameY2, temp);
+ _dscDoorFrameIndex1 = _staticres->loadRawData(kRpgCommonDscDoorFrameIndex1, temp);
+ _dscDoorFrameIndex2 = _staticres->loadRawData(kRpgCommonDscDoorFrameIndex2, temp);
+ _moreStrings = _staticres->loadStrings(kRpgCommonMoreStrings, temp);
+}
+
+#endif // (ENABLE_EOB || ENABLE_LOL)
+
+} // End of namespace Kyra