diff options
Diffstat (limited to 'engines')
615 files changed, 31479 insertions, 17484 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index ac06e74e0a..9beba6ce4a 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -22,7 +22,6 @@ #include "common/debug.h" #include "common/util.h" -#include "common/hash-str.h" #include "common/file.h" #include "common/macresman.h" #include "common/md5.h" @@ -308,14 +307,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) return Common::kNoError; } -struct SizeMD5 { - int size; - Common::String md5; -}; - -typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map; - -static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSizeMD5) { +void AdvancedMetaEngine::reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps) const { // TODO: This message should be cleaned up / made more specific. // For example, we should specify at least which engine triggered this. // @@ -327,7 +319,7 @@ static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSiz report += _("of the game you tried to add and its version/language/etc.:"); report += "\n"; - for (SizeMD5Map::const_iterator file = filesSizeMD5.begin(); file != filesSizeMD5.end(); ++file) + for (ADFilePropertiesMap::const_iterator file = filesProps.begin(); file != filesProps.end(); ++file) report += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size); report += "\n"; @@ -375,8 +367,36 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL } } +bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const { + // FIXME/TODO: We don't handle the case that a file is listed as a regular + // file and as one with resource fork. + + if (game.flags & ADGF_MACRESFORK) { + Common::MacResManager macResMan; + + if (!macResMan.open(parent, fname)) + return false; + + fileProps.md5 = macResMan.computeResForkMD5AsString(_md5Bytes); + fileProps.size = macResMan.getResForkDataSize(); + return true; + } + + if (!allFiles.contains(fname)) + return false; + + Common::File testFile; + + if (!testFile.open(allFiles[fname])) + return false; + + fileProps.size = (int32)testFile.size(); + fileProps.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes); + return true; +} + ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { - SizeMD5Map filesSizeMD5; + ADFilePropertiesMap filesProps; const ADGameFileDescription *fileDesc; const ADGameDescription *g; @@ -391,39 +411,14 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { Common::String fname = fileDesc->fileName; - SizeMD5 tmp; + ADFileProperties tmp; - if (filesSizeMD5.contains(fname)) + if (filesProps.contains(fname)) continue; - // FIXME/TODO: We don't handle the case that a file is listed as a regular - // file and as one with resource fork. - - if (g->flags & ADGF_MACRESFORK) { - Common::MacResManager macResMan; - - if (macResMan.open(parent, fname)) { - tmp.md5 = macResMan.computeResForkMD5AsString(_md5Bytes); - tmp.size = macResMan.getResForkDataSize(); - debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); - filesSizeMD5[fname] = tmp; - } - } else { - if (allFiles.contains(fname)) { - debug(3, "+ %s", fname.c_str()); - - Common::File testFile; - - if (testFile.open(allFiles[fname])) { - tmp.size = (int32)testFile.size(); - tmp.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes); - } else { - tmp.size = -1; - } - - debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); - filesSizeMD5[fname] = tmp; - } + if (getFileProperties(parent, allFiles, *g, fname, tmp)) { + debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); + filesProps[fname] = tmp; } } } @@ -456,19 +451,19 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { Common::String tstr = fileDesc->fileName; - if (!filesSizeMD5.contains(tstr)) { + if (!filesProps.contains(tstr)) { fileMissing = true; allFilesPresent = false; break; } - if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) { - debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5.c_str()); + if (fileDesc->md5 != NULL && fileDesc->md5 != filesProps[tstr].md5) { + debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesProps[tstr].md5.c_str()); fileMissing = true; break; } - if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) { + if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesProps[tstr].size) { debug(3, "Size Mismatch. Skipping"); fileMissing = true; break; @@ -514,8 +509,8 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons // We didn't find a match if (matched.empty()) { - if (!filesSizeMD5.empty() && gotAnyMatchesWithAllFiles) { - reportUnknown(parent, filesSizeMD5); + if (!filesProps.empty() && gotAnyMatchesWithAllFiles) { + reportUnknown(parent, filesProps); } // Filename based fallback @@ -524,7 +519,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons return matched; } -const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const { +const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps) const { const ADFileBasedFallback *ptr; const char* const* filenames; @@ -554,6 +549,16 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap & maxNumMatchedFiles = numMatchedFiles; debug(4, "and overridden"); + + if (filesProps) { + for (filenames = ptr->filenames; *filenames; ++filenames) { + ADFileProperties tmp; + + if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp)) + (*filesProps)[*filenames] = tmp; + } + } + } } } diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 45a9f183e8..8c19d03691 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -26,6 +26,8 @@ #include "engines/metaengine.h" #include "engines/engine.h" +#include "common/hash-str.h" + #include "common/gui_options.h" // FIXME: Temporary hack? namespace Common { @@ -46,6 +48,20 @@ struct ADGameFileDescription { }; /** + * A record describing the properties of a file. Used on the existing + * files while detecting a game. + */ +struct ADFileProperties { + int32 size; + Common::String md5; +}; + +/** + * A map of all relevant existing files in a game directory while detecting. + */ +typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ADFilePropertiesMap; + +/** * A shortcut to produce an empty ADGameFileDescription record. Used to mark * the end of a list of these. */ @@ -286,9 +302,17 @@ protected: * In case of a tie, the entry coming first in the list is chosen. * * @param allFiles a map describing all present files + * @param fslist a list of nodes for all present files * @param fileBasedFallback a list of ADFileBasedFallback records, zero-terminated + * @param filesProps if not 0, return a map of properties for all detected files here + */ + const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps = 0) const; + + /** + * Log and print a report that we found an unknown game variant, together with the file + * names, sizes and MD5 sums. */ - const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const; + void reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps) const; // TODO void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const; @@ -298,6 +322,9 @@ protected: * Includes nifty stuff like removing trailing dots and ignoring case. */ void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth) const; + + /** Get the properties (size and MD5) of this file. */ + bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const; }; #endif diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 805fe7d366..5f7780bfe3 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "engines/advancedDetector.h" @@ -491,10 +488,14 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX g_fallbackDesc.desc.gameid = _gameid.c_str(); g_fallbackDesc.desc.extra = _extra.c_str(); - printf("Your game version has been detected using fallback matching as a\n"); - printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); - printf("If this is an original and unmodified version or new made Fanmade game,\n"); - printf("please report any, information previously printed by ScummVM to the team.\n"); + Common::String fallbackWarning; + + fallbackWarning = "Your game version has been detected using fallback matching as a\n"; + fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); + fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n"; + fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n"; + + g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str()); return (const ADGameDescription *)&g_fallbackDesc; } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 8e524c8d9a..3e63da756d 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -795,42 +795,33 @@ int AgiEngine::selectSlot() { } int AgiEngine::scummVMSaveLoadDialog(bool isSave) { - const EnginePlugin *plugin = NULL; - EngineMan.findGame(ConfMan.get("gameid"), &plugin); GUI::SaveLoadChooser *dialog; Common::String desc; int slot; if (isSave) { - dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); - dialog->setSaveMode(true); + dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); - slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + slot = dialog->runModalWithCurrentTarget(); desc = dialog->getResultString(); if (desc.empty()) { // create our own description for the saved game, the user didnt enter it -#if defined(USE_SAVEGAME_TIMESTAMP) - TimeDate curTime; - g_system->getTimeAndDate(curTime); - curTime.tm_year += 1900; // fixup year - curTime.tm_mon++; // fixup month - desc = Common::String::format("%04d.%02d.%02d / %02d:%02d:%02d", curTime.tm_year, curTime.tm_mon, curTime.tm_mday, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); -#else - desc = Common::String::format("Save %d", slot + 1); -#endif + desc = dialog->createDefaultSaveDescription(slot); } if (desc.size() > 28) desc = Common::String(desc.c_str(), 28); } else { - dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore")); - dialog->setSaveMode(false); - slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + slot = dialog->runModalWithCurrentTarget(); } delete dialog; + if (slot < 0) + return true; + if (isSave) return doSave(slot, desc); else diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 29d1b36e19..9176412e0e 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -260,9 +260,6 @@ bool MoviePlayerDXA::load() { debug(0, "Playing video %s", videoName.c_str()); CursorMan.showMouse(false); - - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -271,6 +268,10 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -281,7 +282,7 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerDXA::playVideo() { @@ -302,38 +303,11 @@ void MoviePlayerDXA::stopVideo() { } void MoviePlayerDXA::startSound() { - uint32 offset, size; - - if (getSoundTag() == MKTAG('W','A','V','E')) { - size = _fileStream->readUint32BE(); - - if (_sequenceNum) { - Common::File in; - - _fileStream->seek(size, SEEK_CUR); - - in.open("audio.wav"); - if (!in.isOpen()) { - error("Can't read offset file 'audio.wav'"); - } - - in.seek(_sequenceNum * 8, SEEK_SET); - offset = in.readUint32LE(); - size = in.readUint32LE(); - - in.seek(offset, SEEK_SET); - _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); - in.close(); - } else { - _bgSoundStream = Audio::makeWAVStream(_fileStream->readStream(size), DisposeAfterUse::YES); - } - } else { - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); - } + start(); if (_bgSoundStream != NULL) { _vm->_mixer->stopHandle(_bgSound); - _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream); + _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream, -1, getVolume(), getBalance()); } } @@ -344,8 +318,7 @@ void MoviePlayerDXA::nextFrame() { } if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; + rewind(); startSound(); } @@ -374,13 +347,15 @@ bool MoviePlayerDXA::processFrame() { copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); _vm->_system->unlockScreen(); - Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000); - if ((_bgSoundStream == NULL) || ((soundTime * getFrameRate()).toInt() / 1000 < getCurFrame() + 1)) { + uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound); + uint32 nextFrameStartTime = ((Video::VideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime(); + + if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) { if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) { - while (_mixer->isSoundHandleActive(_bgSound) && (soundTime * getFrameRate()).toInt() < getCurFrame()) { + while (_mixer->isSoundHandleActive(_bgSound) && soundTime < nextFrameStartTime) { _vm->_system->delayMillis(10); - soundTime = Common::Rational(_mixer->getSoundElapsedTime(_bgSound), 1000); + soundTime = _mixer->getSoundElapsedTime(_bgSound); } // In case the background sound ends prematurely, update // _ticks so that we can still fall back on the no-sound @@ -399,13 +374,44 @@ bool MoviePlayerDXA::processFrame() { return false; } +void MoviePlayerDXA::readSoundData(Common::SeekableReadStream *stream) { + uint32 tag = stream->readUint32BE(); + + if (tag == MKTAG('W','A','V','E')) { + uint32 size = stream->readUint32BE(); + + if (_sequenceNum) { + Common::File in; + + stream->skip(size); + + in.open("audio.wav"); + if (!in.isOpen()) { + error("Can't read offset file 'audio.wav'"); + } + + in.seek(_sequenceNum * 8, SEEK_SET); + uint32 offset = in.readUint32LE(); + size = in.readUint32LE(); + + in.seek(offset, SEEK_SET); + _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); + in.close(); + } else { + _bgSoundStream = Audio::makeWAVStream(stream->readStream(size), DisposeAfterUse::YES); + } + } else { + _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); + } +} + /////////////////////////////////////////////////////////////////////////////// // Movie player for Smacker movies /////////////////////////////////////////////////////////////////////////////// MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name) - : MoviePlayer(vm), SmackerDecoder(vm->_mixer) { + : MoviePlayer(vm), SmackerDecoder() { debug(0, "Creating SMK cutscene player"); memset(baseName, 0, sizeof(baseName)); @@ -425,8 +431,6 @@ bool MoviePlayerSMK::load() { CursorMan.showMouse(false); - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -435,6 +439,10 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -445,7 +453,7 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerSMK::playVideo() { @@ -458,6 +466,7 @@ void MoviePlayerSMK::stopVideo() { } void MoviePlayerSMK::startSound() { + start(); } void MoviePlayerSMK::handleNextFrame() { @@ -467,10 +476,8 @@ void MoviePlayerSMK::handleNextFrame() { } void MoviePlayerSMK::nextFrame() { - if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; - } + if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) + rewind(); if (!endOfVideo()) { decodeNextFrame(); @@ -493,7 +500,7 @@ bool MoviePlayerSMK::processFrame() { uint32 waitTime = getTimeToNextFrame(); - if (!waitTime) { + if (!waitTime && !endOfVideoTracks()) { warning("dropped frame %i", getCurFrame()); return false; } diff --git a/engines/agos/animation.h b/engines/agos/animation.h index 11936aa338..9e31fced6d 100644 --- a/engines/agos/animation.h +++ b/engines/agos/animation.h @@ -67,9 +67,6 @@ protected: virtual void handleNextFrame(); virtual bool processFrame() = 0; virtual void startSound() {} - -protected: - uint32 _firstFrameOffset; }; class MoviePlayerDXA : public MoviePlayer, Video::DXADecoder { @@ -83,6 +80,9 @@ public: void nextFrame(); virtual void stopVideo(); +protected: + void readSoundData(Common::SeekableReadStream *stream); + private: void handleNextFrame(); bool processFrame(); diff --git a/engines/agos/charset-fontdata.cpp b/engines/agos/charset-fontdata.cpp index 87f51cfad2..262ae44f01 100644 --- a/engines/agos/charset-fontdata.cpp +++ b/engines/agos/charset-fontdata.cpp @@ -681,6 +681,51 @@ static const byte feeble_windowFont[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +void AGOSEngine_Feeble::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { + const byte *src; + byte color, *dst; + uint dstPitch, h, w, i; + + if (_noOracleScroll) + return; + + _videoLockOut |= 0x8000; + + dst = getBackGround(); + dstPitch = _backGroundBuf->pitch; + h = 13; + w = getFeebleFontSize(chr); + + if (_language == Common::PL_POL) { + if (!strcmp(getExtra(), "4CD")) + src = polish4CD_feeble_windowFont + (chr - 32) * 13; + else + src = polish2CD_feeble_windowFont + (chr - 32) * 13; + } else { + src = feeble_windowFont + (chr - 32) * 13; + } + dst += y * dstPitch + x + window->textColumnOffset; + + color = window->textColor; + + do { + int8 b = *src++; + i = 0; + do { + if (b < 0) { + if (dst[i] == 0) + dst[i] = color; + } + + b <<= 1; + } while (++i != w); + dst += dstPitch; + } while (--h); + + _videoLockOut &= ~0x8000; +} +#endif + static const byte english_simon1AGAFontData[] = { 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x50,0x20,0x10,0x40,0x88,0x30,0x40,0x00,0x88,0x20,0x00,0x00,0x50,0x20,0x00,0x00,0x50,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x50,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x05, 0x00,0x00,0x00,0x30,0x00,0x10,0x20,0x48,0x10,0x20,0x00,0x48,0x20,0x40,0x00,0x90,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, @@ -1253,51 +1298,6 @@ void AGOSEngine::renderString(uint vgaSpriteId, uint color, uint width, uint hei } } -void AGOSEngine_Feeble::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { - const byte *src; - byte color, *dst; - uint dstPitch, h, w, i; - - if (_noOracleScroll) - return; - - _videoLockOut |= 0x8000; - - dst = getBackGround(); - dstPitch = _backGroundBuf->pitch; - h = 13; - w = getFeebleFontSize(chr); - - if (_language == Common::PL_POL) { - if (!strcmp(getExtra(), "4CD")) - src = polish4CD_feeble_windowFont + (chr - 32) * 13; - else - src = polish2CD_feeble_windowFont + (chr - 32) * 13; - } else { - src = feeble_windowFont + (chr - 32) * 13; - } - dst += y * dstPitch + x + window->textColumnOffset; - - color = window->textColor; - - do { - int8 b = *src++; - i = 0; - do { - if (b < 0) { - if (dst[i] == 0) - dst[i] = color; - } - - b <<= 1; - } while (++i != w); - dst += dstPitch; - } while (--h); - - _videoLockOut &= ~0x8000; -} -#endif - static const byte czech_simonFont[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x70, 0x20, 0x20, 0x00, 0x20, 0x00, diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index ed26b96381..cc1c40c207 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -467,11 +467,7 @@ void AGOSEngine::delay(uint amount) { memset(_saveLoadName, 0, sizeof(_saveLoadName)); sprintf(_saveLoadName, "Quick %d", _saveLoadSlot); _saveLoadType = (event.kbd.hasFlags(Common::KBD_ALT)) ? 1 : 2; - - // We should only allow a load or save when it was possible in original - // This stops load/save during copy protection, conversations and cut scenes - if (!_mouseHideCount && !_showPreposition) - quickLoadOrSave(); + quickLoadOrSave(); } else if (event.kbd.hasFlags(Common::KBD_CTRL)) { if (event.kbd.keycode == Common::KEYCODE_a) { GUI::Dialog *_aboutDialog; diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index b3ec916b47..c6bca1a6e6 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -142,23 +142,41 @@ void AGOSEngine_Feeble::quickLoadOrSave() { } #endif +// The function uses segments of code from the original game scripts +// to allow quick loading and saving, but isn't perfect. +// +// Unfortuntely this allows loading and saving in locations, +// which aren't supported, and will not restore correctly: +// Various locations in Elvira 1/2 and Waxworks where saving +// was disabled void AGOSEngine::quickLoadOrSave() { - // The function uses segments of code from the original game scripts - // to allow quick loading and saving, but isn't perfect. - // - // Unfortuntely this allows loading and saving in locations, - // which aren't supported, and will not restore correctly: - // Any overhead maps in Simon the Sorcerer 2 - // Various locations in Elvira 1/2 and Waxworks where saving - // was disabled - - // The floppy disk demo of Simon the Sorcerer 1 doesn't work. - if (getFeatures() & GF_DEMO) - return; - bool success; Common::String buf; + // Disable loading and saving when it was not possible in the original: + // In overhead maps areas in Simon the Sorcerer 2 + // In the floppy disk demo of Simon the Sorcerer 1 + // In copy protection, conversations and cut scenes + if ((getGameType() == GType_SIMON2 && _boxStarHeight == 200) || + (getGameType() == GType_SIMON1 && (getFeatures() & GF_DEMO)) || + _mouseHideCount || _showPreposition) { + buf = Common::String::format("Quick load or save game isn't supported in this location"); + GUI::MessageDialog dialog(buf, "OK"); + dialog.runModal(); + return; + } + + // Check if Simon is walking, and stop when required + if (getGameType() == GType_SIMON1 && getBitFlag(11)) { + vcStopAnimation(11, 1122); + animate(4, 11, 1122, 0, 0, 2); + waitForSync(1122); + } else if (getGameType() == GType_SIMON2 && getBitFlag(11)) { + vcStopAnimation(11, 232); + animate(4, 11, 232, 0, 0, 2); + waitForSync(1122); + } + char *filename = genSaveName(_saveLoadSlot); if (_saveLoadType == 2) { Subroutine *sub; diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp index 309b89bdda..4f85957b3d 100644 --- a/engines/cge/bitmap.cpp +++ b/engines/cge/bitmap.cpp @@ -123,12 +123,15 @@ Bitmap::~Bitmap() { Bitmap &Bitmap::operator=(const Bitmap &bmp) { debugC(1, kCGEDebugBitmap, "&Bitmap::operator ="); + if (this == &bmp) + return *this; uint8 *v0 = bmp._v; _w = bmp._w; _h = bmp._h; _m = NULL; _map = 0; + _vm = bmp._vm; delete[] _v; if (v0 == NULL) { diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp index 875ac34cd0..6cc0c45963 100644 --- a/engines/cge/cge.cpp +++ b/engines/cge/cge.cpp @@ -30,6 +30,8 @@ #include "common/fs.h" #include "engines/advancedDetector.h" #include "engines/util.h" +#include "gui/message.h" + #include "cge/cge.h" #include "cge/vga13h.h" #include "cge/cge_main.h" @@ -50,7 +52,6 @@ CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription) DebugMan.addDebugChannel(kCGEDebugEngine, "engine", "CGE Engine debug channel"); _startupMode = 1; - _demoText = kDemo; _oldLev = 0; _pocPtr = 0; _bitmapPalette = NULL; @@ -122,7 +123,7 @@ void CGEEngine::init() { _maxScene = 0; _dark = false; _game = false; - _finis = false; + _endGame = false; _now = 1; _lev = -1; _recentStep = -2; @@ -134,7 +135,6 @@ void CGEEngine::init() { _soundOk = 1; _sprTv = NULL; _gameCase2Cpt = 0; - _offUseCount = 0; _startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1; } @@ -196,6 +196,16 @@ Common::Error CGEEngine::run() { // Run the game cge_main(); + // If game is finished, display ending message + if (_flag[3]) { + Common::String msg = Common::String(_text->getText(kSayTheEnd)); + if (msg.size() != 0) { + g_system->delayMillis(10); + GUI::MessageDialog dialog(msg, "OK"); + dialog.runModal(); + } + } + // Remove game objects deinit(); diff --git a/engines/cge/cge.h b/engines/cge/cge.h index 4ebc836ee0..0e8c5a05bb 100644 --- a/engines/cge/cge.h +++ b/engines/cge/cge.h @@ -78,6 +78,8 @@ class Talk; #define kMapZCnt 20 #define kMapTop 80 +#define kSayTheEnd 41 + // our engine debug channels enum { kCGEDebugBitmap = 1 << 0, @@ -147,7 +149,6 @@ public: const ADGameDescription *_gameDescription; int _startupMode; - int _demoText; int _oldLev; int _pocPtr; bool _music; @@ -157,7 +158,7 @@ public: bool _flag[4]; bool _dark; bool _game; - bool _finis; + bool _endGame; int _now; int _lev; int _mode; diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp index 05a94df606..3ba5f7fed9 100644 --- a/engines/cge/cge_main.cpp +++ b/engines/cge/cge_main.cpp @@ -150,11 +150,11 @@ void CGEEngine::sndSetVolume() { void CGEEngine::syncHeader(Common::Serializer &s) { debugC(1, kCGEDebugEngine, "CGEEngine::syncHeader(s)"); - int i; + int i = kDemo; s.syncAsUint16LE(_now); s.syncAsUint16LE(_oldLev); - s.syncAsUint16LE(_demoText); + s.syncAsUint16LE(i); // unused Demo string id for (i = 0; i < 5; i++) s.syncAsUint16LE(_game); s.syncAsSint16LE(i); // unused VGA::Mono variable @@ -305,12 +305,21 @@ Common::Error CGEEngine::saveGameState(int slot, const Common::String &desc) { _hero->park(); _oldLev = _lev; + int x = _hero->_x; + int y = _hero->_y; + int z = _hero->_z; + // Write out the user's progress saveGame(slot, desc); + _commandHandler->addCommand(kCmdLevel, -1, _oldLev, &_sceneLight); // Reload the scene sceneUp(); + _hero->_x = x; + _hero->_y = y; + _hero->_z = z; + return Common::kNoError; } @@ -518,8 +527,8 @@ Square::Square(CGEEngine *vm) : Sprite(vm, NULL), _vm(vm) { setShapeList(MB); } -void Square::touch(uint16 mask, int x, int y) { - Sprite::touch(mask, x, y); +void Square::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) { + Sprite::touch(mask, x, y, keyCode); if (mask & kMouseLeftUp) { _vm->XZ(_x + x, _y + y).cell() = 0; _vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this); @@ -706,7 +715,7 @@ void CGEEngine::qGame() { saveGame(0, Common::String("Automatic Savegame")); _vga->sunset(); - _finis = true; + _endGame = true; } void CGEEngine::switchScene(int newScene) { @@ -758,11 +767,11 @@ void System::funTouch() { _funDel = n; } -void System::touch(uint16 mask, int x, int y) { +void System::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) { funTouch(); if (mask & kEventKeyb) { - if (x == Common::KEYCODE_ESCAPE) { + if (keyCode == Common::KEYCODE_ESCAPE) { // The original was calling keyClick() // The sound is uselessly annoying and noisy, so it has been removed _vm->killText(); @@ -926,7 +935,7 @@ void CGEEngine::optionTouch(int opt, uint16 mask) { } #pragma argsused -void Sprite::touch(uint16 mask, int x, int y) { +void Sprite::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) { _vm->_sys->funTouch(); if ((mask & kEventAttn) != 0) @@ -1312,7 +1321,7 @@ void CGEEngine::runGame() { _sceneLight->_flags._tran = true; _vga->_showQ->append(_sceneLight); - _sceneLight->_flags._hide = true; + _sceneLight->_flags._hide = false; const Seq pocSeq[] = { { 0, 0, 0, 0, 20 }, @@ -1403,14 +1412,14 @@ void CGEEngine::runGame() { _keyboard->setClient(_sys); // main loop - while (!_finis && !_quitFlag) { - if (_flag[3]) + while (!_endGame && !_quitFlag) { + if (_flag[3]) // Flag FINIS _commandHandler->addCallback(kCmdExec, -1, 0, kQGame); mainLoop(); } // If finishing game due to closing ScummVM window, explicitly save the game - if (!_finis && canSaveGameStateCurrently()) + if (!_endGame && canSaveGameStateCurrently()) qGame(); _keyboard->setClient(NULL); @@ -1507,22 +1516,9 @@ bool CGEEngine::showTitle(const char *name) { _vga->_showQ->clear(); _vga->copyPage(0, 2); - if (_mode == 0) { -// The auto-load of savegame #0 is currently disabled -#if 0 - if (savegameExists(0)) { - // Load the savegame - loadGame(0, NULL, true); // only system vars - _vga->setColors(_vga->_sysPal, 64); - _vga->update(); - if (_flag[3]) { //flag FINIS - _mode++; - _flag[3] = false; - } - } else -#endif - _mode++; - } + // The original was automatically loading the savegame when available + if (_mode == 0) + _mode++; } if (_mode < 2) diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h index 87199ee524..bde8306f36 100644 --- a/engines/cge/cge_main.h +++ b/engines/cge/cge_main.h @@ -78,7 +78,7 @@ namespace CGE { #define kScrHeight 200 #define kWorldHeight (kScrHeight - kPanHeight) #define kStackSize 2048 -#define kSavegameCheckSum (1956 + _now + _oldLev + _game + _music + _demoText) +#define kSavegameCheckSum (1956 + _now + _oldLev + _game + _music + kDemo) #define kSavegame0Name ("{{INIT}}" kSvgExt) #define kSavegameStrSize 11 #define kGameFrameDelay (1000 / 50) @@ -92,7 +92,7 @@ public: void setPal(); void funTouch(); - virtual void touch(uint16 mask, int x, int y); + virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode); void tick(); private: CGEEngine *_vm; @@ -101,7 +101,7 @@ private: class Square : public Sprite { public: Square(CGEEngine *vm); - virtual void touch(uint16 mask, int x, int y); + virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode); private: CGEEngine *_vm; }; diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index f723ec8fbd..2e04b82026 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -108,7 +108,7 @@ public: } virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { - return detectGameFilebased(allFiles, CGE::fileBasedFallback); + return detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback); } virtual const char *getName() const { @@ -217,8 +217,6 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl } else { // Create the return descriptor SaveStateDescriptor desc(slot, header.saveName); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); desc.setThumbnail(header.thumbnail); desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay); desc.setSaveTime(header.saveHour, header.saveMinutes); diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp index 3c561c5659..1530c870ef 100644 --- a/engines/cge/events.cpp +++ b/engines/cge/events.cpp @@ -55,7 +55,7 @@ Sprite *Keyboard::setClient(Sprite *spr) { bool Keyboard::getKey(Common::Event &event) { Common::KeyCode keycode = event.kbd.keycode; - if ((keycode == Common::KEYCODE_LALT) || (keycode == Common::KEYCODE_RALT)) + if (((keycode == Common::KEYCODE_LALT) || (keycode == Common::KEYCODE_RALT)) && event.type == Common::EVENT_KEYDOWN) _keyAlt = true; else _keyAlt = false; @@ -70,12 +70,8 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F5: if (_vm->canSaveGameStateCurrently()) { - const EnginePlugin *plugin = NULL; - EngineMan.findGame(_vm->_gameDescription->gameid, &plugin); - - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); - dialog->setSaveMode(true); - int16 savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + int16 savegameId = dialog->runModalWithCurrentTarget(); Common::String savegameDescription = dialog->getResultString(); delete dialog; @@ -85,12 +81,8 @@ bool Keyboard::getKey(Common::Event &event) { return false; case Common::KEYCODE_F7: if (_vm->canLoadGameStateCurrently()) { - const EnginePlugin *plugin = NULL; - EngineMan.findGame(_vm->_gameDescription->gameid, &plugin); - - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); - dialog->setSaveMode(false); - int16 savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + int16 savegameId = dialog->runModalWithCurrentTarget(); delete dialog; if (savegameId != -1) @@ -117,9 +109,19 @@ bool Keyboard::getKey(Common::Event &event) { case Common::KEYCODE_3: case Common::KEYCODE_4: if (event.kbd.flags & Common::KBD_ALT) { - _vm->_commandHandler->addCommand(kCmdLevel, -1, keycode - '0', NULL); + _vm->_commandHandler->addCommand(kCmdLevel, -1, keycode - Common::KEYCODE_0, NULL); return false; } + // Fallthrough intended + case Common::KEYCODE_5: + case Common::KEYCODE_6: + case Common::KEYCODE_7: + case Common::KEYCODE_8: + if (event.type == Common::EVENT_KEYDOWN && !(event.kbd.flags & Common::KBD_ALT) && keycode != Common::KEYCODE_0) { + _vm->selectPocket(keycode - Common::KEYCODE_1); + return false; + } + break; default: break; } @@ -133,9 +135,11 @@ void Keyboard::newKeyboard(Common::Event &event) { if ((event.type == Common::EVENT_KEYDOWN) && (_client)) { CGEEvent &evt = _vm->_eventManager->getNextEvent(); - evt._x = event.kbd.keycode; // Keycode - evt._mask = kEventKeyb; // Event mask - evt._spritePtr = _client; // Sprite pointer + evt._x = 0; + evt._y = 0; + evt._keyCode = event.kbd.keycode; // Keycode + evt._mask = kEventKeyb; // Event mask + evt._spritePtr = _client; // Sprite pointer } } @@ -202,6 +206,7 @@ void Mouse::newMouse(Common::Event &event) { CGEEvent &evt = _vm->_eventManager->getNextEvent(); evt._x = event.mouse.x; evt._y = event.mouse.y; + evt._keyCode = Common::KEYCODE_INVALID; evt._spritePtr = _vm->spriteAt(evt._x, evt._y); switch (event.type) { @@ -267,7 +272,7 @@ void EventManager::handleEvents() { CGEEvent e = _eventQueue[_eventQueueTail]; if (e._mask) { if (_vm->_mouse->_hold && e._spritePtr != _vm->_mouse->_hold) - _vm->_mouse->_hold->touch(e._mask | kEventAttn, e._x - _vm->_mouse->_hold->_x, e._y - _vm->_mouse->_hold->_y); + _vm->_mouse->_hold->touch(e._mask | kEventAttn, e._x - _vm->_mouse->_hold->_x, e._y - _vm->_mouse->_hold->_y, e._keyCode); // update mouse cursor position if (e._mask & kMouseRoll) @@ -276,11 +281,11 @@ void EventManager::handleEvents() { // activate current touched SPRITE if (e._spritePtr) { if (e._mask & kEventKeyb) - e._spritePtr->touch(e._mask, e._x, e._y); + e._spritePtr->touch(e._mask, e._x, e._y, e._keyCode); else - e._spritePtr->touch(e._mask, e._x - e._spritePtr->_x, e._y - e._spritePtr->_y); + e._spritePtr->touch(e._mask, e._x - e._spritePtr->_x, e._y - e._spritePtr->_y, e._keyCode); } else if (_vm->_sys) - _vm->_sys->touch(e._mask, e._x, e._y); + _vm->_sys->touch(e._mask, e._x, e._y, e._keyCode); if (e._mask & kMouseLeftDown) { _vm->_mouse->_hold = e._spritePtr; diff --git a/engines/cge/events.h b/engines/cge/events.h index 6bbd52e4a5..522aa67905 100644 --- a/engines/cge/events.h +++ b/engines/cge/events.h @@ -70,6 +70,7 @@ struct CGEEvent { uint16 _mask; uint16 _x; uint16 _y; + Common::KeyCode _keyCode; Sprite *_spritePtr; }; diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp index c50db4e929..f23105d823 100644 --- a/engines/cge/fileio.cpp +++ b/engines/cge/fileio.cpp @@ -201,9 +201,28 @@ EncryptedStream::EncryptedStream(CGEEngine *vm, const char *name) : _vm(vm) { _error = true; _vm->_resman->seek(kp->_pos); - byte *dataBuffer = (byte *)malloc(kp->_size); - _vm->_resman->read(dataBuffer, kp->_size); - _readStream = new Common::MemoryReadStream(dataBuffer, kp->_size, DisposeAfterUse::YES); + byte *dataBuffer; + int bufSize; + + if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) { + // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others + // do not have a carriage return at the end of the last line + // Therefore, we remove this ending 0x1A and add extra new lines. + // This fixes bug #3537527 + dataBuffer = (byte *)malloc(kp->_size + 2); + _vm->_resman->read(dataBuffer, kp->_size); + if (dataBuffer[kp->_size - 1] == 0x1A) + dataBuffer[kp->_size - 1] = '\n'; + dataBuffer[kp->_size] = '\n'; + dataBuffer[kp->_size + 1] = '\n'; + bufSize = kp->_size + 2; + } else { + dataBuffer = (byte *)malloc(kp->_size); + _vm->_resman->read(dataBuffer, kp->_size); + bufSize = kp->_size; + } + + _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES); } uint32 EncryptedStream::read(void *dataPtr, uint32 dataSize) { diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp index 7f74794474..b378898955 100644 --- a/engines/cge/sound.cpp +++ b/engines/cge/sound.cpp @@ -91,6 +91,12 @@ void Sound::sndDigiStart(SmpInfo *PSmpInfo) { // Start the new sound _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter)); + + // CGE pan: + // 8 = Center + // Less = Left + // More = Right + _vm->_mixer->setChannelBalance(_soundHandle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127)); } void Sound::stop() { diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp index 186de24036..e178795b7c 100644 --- a/engines/cge/vga13h.cpp +++ b/engines/cge/vga13h.cpp @@ -637,15 +637,6 @@ Vga::Vga(CGEEngine *vm) : _frmCnt(0), _msg(NULL), _name(NULL), _setPal(false), _ _page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); } -#if 0 - // This part was used to display credits at the beginning of the game - for (int i = 10; i < 20; i++) { - char *text = _text->getText(i); - if (text) { - debugN(1, "%s\n", text); - } - } -#endif _oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount); _newColors = (Dac *)malloc(sizeof(Dac) * kPalCount); getColors(_oldColors); @@ -834,7 +825,7 @@ void Vga::update() { } } - g_system->copyRectToScreen((const byte *)Vga::_page[0]->getBasePtr(0, 0), kScrWidth, 0, 0, kScrWidth, kScrHeight); + g_system->copyRectToScreen(Vga::_page[0]->getBasePtr(0, 0), kScrWidth, 0, 0, kScrWidth, kScrHeight); g_system->updateScreen(); } diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h index beca19f667..a816f7756f 100644 --- a/engines/cge/vga13h.h +++ b/engines/cge/vga13h.h @@ -29,6 +29,7 @@ #define CGE_VGA13H_H #include "common/serializer.h" +#include "common/events.h" #include "graphics/surface.h" #include "cge/general.h" #include "cge/bitmap.h" @@ -146,7 +147,7 @@ public: void step(int nr = -1); Seq *setSeq(Seq *seq); CommandHandler::Command *snList(SnList type); - virtual void touch(uint16 mask, int x, int y); + virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode); virtual void tick(); void sync(Common::Serializer &s); private: diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp index a317a765d4..910e54d267 100644 --- a/engines/cge/vmenu.cpp +++ b/engines/cge/vmenu.cpp @@ -63,7 +63,7 @@ Vmenu *Vmenu::_addr = NULL; int Vmenu::_recent = -1; Vmenu::Vmenu(CGEEngine *vm, Choice *list, int x, int y) - : Talk(vm, VMGather(list), kTBRect), _menu(list), _bar(NULL), _vm(vm) { + : Talk(vm, VMGather(list), kTBRect), _menu(list), _bar(NULL), _vmgt(NULL), _vm(vm) { Choice *cp; _addr = this; @@ -89,11 +89,11 @@ Vmenu::~Vmenu() { #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) -void Vmenu::touch(uint16 mask, int x, int y) { +void Vmenu::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) { if (!_items) return; - Sprite::touch(mask, x, y); + Sprite::touch(mask, x, y, keyCode); y -= kTextVMargin - 1; int n = 0; diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h index 89ef7a9484..928b48f11c 100644 --- a/engines/cge/vmenu.h +++ b/engines/cge/vmenu.h @@ -58,7 +58,7 @@ public: MenuBar *_bar; Vmenu(CGEEngine *vm, Choice *list, int x, int y); ~Vmenu(); - virtual void touch(uint16 mask, int x, int y); + virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode); private: char *_vmgt; CGEEngine *_vm; diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 410fcca1f3..60168831a1 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -682,9 +682,10 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) { * Load image set * @param resourceName Image set filename * @param idx Target index in animDataTable (-1 if any empty space will do) + * @param frameIndex frame of animation to load (-1 for all frames) * @return The number of the animDataTable entry after the loaded image set (-1 if error) */ -int loadSet(const char *resourceName, int16 idx) { +int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) { AnimHeader2Struct header2; uint16 numSpriteInAnim; int16 foundFileIdx = findFileInBundle(resourceName); @@ -708,7 +709,17 @@ int loadSet(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); - for (int16 i = 0; i < numSpriteInAnim; i++, entry++) { + int16 startFrame = 0; + int16 endFrame = numSpriteInAnim; + + if(frameIndex>=0) + { + startFrame = frameIndex; + endFrame = frameIndex+1; + ptr += 0x10 * frameIndex; + } + + for (int16 i = startFrame; i < endFrame; i++, entry++) { Common::MemoryReadStream readS(ptr, 0x10); header2.field_0 = readS.readUint32BE(); @@ -767,7 +778,7 @@ int loadSeq(const char *resourceName, int16 idx) { * @return The number of the animDataTable entry after the loaded resource (-1 if error) * @todo Implement loading of all resource types */ -int loadResource(const char *resourceName, int16 idx) { +int loadResource(const char *resourceName, int16 idx, int16 frameIndex) { int result = -1; // Return an error by default if (strstr(resourceName, ".SPL")) { result = loadSpl(resourceName, idx); @@ -778,7 +789,7 @@ int loadResource(const char *resourceName, int16 idx) { } else if (strstr(resourceName, ".ANM")) { result = loadAni(resourceName, idx); } else if (strstr(resourceName, ".SET")) { - result = loadSet(resourceName, idx); + result = loadSet(resourceName, idx, frameIndex); } else if (strstr(resourceName, ".SEQ")) { result = loadSeq(resourceName, idx); } else if (strstr(resourceName, ".H32")) { diff --git a/engines/cine/anim.h b/engines/cine/anim.h index 9c06c260ce..c5130aab82 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -98,7 +98,7 @@ public: void freeAnimDataTable(); void freeAnimDataRange(byte startIdx, byte numIdx); -int loadResource(const char *resourceName, int16 idx = -1); +int loadResource(const char *resourceName, int16 idx = -1, int16 frameIndex = -1); void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat); void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index 693fea3294..36ecf53dea 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -39,9 +39,9 @@ uint32 var8; * @param objIdx Sprite description */ void addToBGList(int16 objIdx) { - renderer->incrustSprite(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 0); + + renderer->incrustSprite(g_cine->_bgIncrustList.back()); } /** @@ -49,9 +49,9 @@ void addToBGList(int16 objIdx) { * @param objIdx Sprite description */ void addSpriteFilledToBGList(int16 objIdx) { - renderer->incrustMask(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 1); + + renderer->incrustMask(g_cine->_bgIncrustList.back()); } /** @@ -103,9 +103,9 @@ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { g_cine->_bgIncrustList.push_back(tmp); if (tmp.param == 0) { - renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustSprite(tmp); } else { - renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustMask(tmp); } } } diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 6b94c33c31..bbe2cd4896 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -189,6 +189,8 @@ void CineEngine::initialize() { g_cine->_messageTable.clear(); resetObjectTable(); + disableSystemMenu = 1; + var8 = 0; var2 = var3 = var4 = var5 = 0; diff --git a/engines/cine/detection_tables.h b/engines/cine/detection_tables.h index 0ec2768bae..bf02f0519c 100644 --- a/engines/cine/detection_tables.h +++ b/engines/cine/detection_tables.h @@ -251,7 +251,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs00", "d6752e7d25924cb866b61eb7cb0c8b56"), Common::EN_GRB, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -267,7 +267,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs1", "9629129b86979fa592c1787385bf3695"), Common::EN_GRB, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -281,7 +281,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs1", "d8c3a9d05a63e4cfa801826a7063a126"), Common::EN_USA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -295,7 +295,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs00", "862a75d76fb7fffec30e52be9ad1c474"), Common::EN_USA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -309,7 +309,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs1", "39b91ae35d1297ce0a76a1a803ca1593"), Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -323,7 +323,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs1", "74c2dabd9d212525fca8875a5f6d8994"), Common::ES_ESP, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -341,7 +341,7 @@ static const CINEGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -355,7 +355,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs00", "f143567f08cfd1a9b1c9a41c89eadfef"), Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -369,7 +369,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs1", "da066e6b8dd93f2502c2a3755f08dc12"), Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO0() }, GType_OS, @@ -383,7 +383,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "a9da5531ead0ebf9ad387fa588c0cbb0"), Common::EN_GRB, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -397,7 +397,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "8a429ced2f4acff8a15ae125174042e8"), Common::EN_GRB, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -411,7 +411,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "d5f27e33fc29c879f36f15b86ccfa58c"), Common::EN_USA, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -425,7 +425,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "8b7dce249821d3a62b314399c4334347"), Common::DE_DEU, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -439,7 +439,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "35fc295ddd0af9da932d256ba799a4b0"), Common::ES_ESP, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -453,7 +453,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "d4ea4a97e01fa67ea066f9e785050ed2"), Common::FR_FRA, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -467,7 +467,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("demo", "8d3a750d1c840b1b1071e42f9e6f6aa2"), Common::EN_GRB, Common::kPlatformAmiga, - ADGF_DEMO, + ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -481,7 +481,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "1501d5ae364b2814a33ed19347c3fcae"), Common::EN_GRB, Common::kPlatformAtariST, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, @@ -495,7 +495,7 @@ static const CINEGameDescription gameDescriptions[] = { AD_ENTRY1("procs0", "2148d25de3219dd4a36580ca735d0afa"), Common::FR_FRA, Common::kPlatformAtariST, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, GUIO1(GUIO_NOMIDI) }, GType_OS, diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 918d522606..7a988227f6 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -174,7 +174,8 @@ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) { * @param obj Object info * @param fillColor Sprite color */ -void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void FWRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -218,7 +219,9 @@ void FWRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite on background * @param obj Object info */ -void FWRenderer::incrustSprite(const ObjectStruct &obj) { +void FWRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[obj.frame].data(); const byte *mask = g_cine->_animDataTable[obj.frame].mask(); int x, y, width, height; @@ -246,14 +249,16 @@ void FWRenderer::drawCommand() { unsigned int i; int x = 10, y = _cmdY; - drawPlainBox(x, y, 301, 11, 0); - drawBorder(x - 1, y - 1, 302, 12, 2); + if(disableSystemMenu == 0) { + drawPlainBox(x, y, 301, 11, 0); + drawBorder(x - 1, y - 1, 302, 12, 2); - x += 2; - y += 2; + x += 2; + y += 2; - for (i = 0; i < _cmd.size(); i++) { - x = drawChar(_cmd[i], x, y); + for (i = 0; i < _cmd.size(); i++) { + x = drawChar(_cmd[i], x, y); + } } } @@ -298,7 +303,8 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color for (i = 0; str[i]; i++, line--) { // Fit line of text into textbox if (!line) { - while (str[i] == ' ') i++; + while (str[i] == ' ') + i++; line = fitLine(str + i, tw, words, cw); if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) { @@ -839,7 +845,7 @@ void OSRenderer::restorePalette(Common::SeekableReadStream &fHandle, int version fHandle.read(buf, kHighPalNumBytes); - if (colorCount == kHighPalNumBytes) { + if (colorCount == kHighPalNumColors) { // Load the active 256 color palette from file _activePal.load(buf, sizeof(buf), kHighPalFormat, kHighPalNumColors, CINE_LITTLE_ENDIAN); } else { @@ -1119,7 +1125,8 @@ void OSRenderer::clear() { * @param obj Object info * @param fillColor Sprite color */ -void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void OSRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -1154,15 +1161,16 @@ void OSRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite * @param obj Object info */ -void OSRenderer::incrustSprite(const ObjectStruct &obj) { - const byte *data = g_cine->_animDataTable[obj.frame].data(); +void OSRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[incrust.frame].data(); int x, y, width, height, transColor; - x = obj.x; - y = obj.y; + x = incrust.x; + y = incrust.y; transColor = obj.part; - width = g_cine->_animDataTable[obj.frame]._realWidth; - height = g_cine->_animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[incrust.frame]._realWidth; + height = g_cine->_animDataTable[incrust.frame]._height; if (_bgTable[_currentBg].bg) { drawSpriteRaw2(data, transColor, width, height, _bgTable[_currentBg].bg, x, y); @@ -1225,7 +1233,6 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int len, idx, width, height; ObjectStruct *obj; AnimData *sprite; - byte *mask; byte color; switch (it->type) { @@ -1235,14 +1242,8 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { break; } sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; - len = sprite->_realWidth * sprite->_height; - mask = new byte[len]; - generateMask(sprite->data(), mask, len, g_cine->_objectTable[it->objIdx].part); - remaskSprite(mask, it); - drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); - delete[] mask; + drawSprite(&(*it), sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, g_cine->_objectTable[it->objIdx].x, g_cine->_objectTable[it->objIdx].y, g_cine->_objectTable[it->objIdx].part, sprite->_bpp); break; - // game message case 2: if (it->objIdx >= g_cine->_messageTable.size()) { @@ -1290,14 +1291,6 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y); break; - // FIXME: Implement correct drawing of type 21 overlays. - // Type 21 overlays aren't just filled rectangles, I found their drawing routine - // from Operation Stealth's drawSprite routine. So they're likely some kind of sprites - // and it's just a coincidence that the oxygen meter during the first arcade sequence - // works even somehow currently. I tried the original under DOSBox and the oxygen gauge - // is a long red bar that gets shorter as the air runs out. - case 21: - // A filled rectangle: case 22: // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing). assert(it->objIdx < NUM_MAX_OBJECT); @@ -1752,6 +1745,82 @@ void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int1 } } +void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) { + byte *pMask = NULL; + + // draw the mask based on next objects in the list + Common::List<overlay>::iterator it; + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { + if(&(*it) == overlayPtr) { + break; + } + } + + while(it != g_cine->_overlayList.end()) { + overlay *pCurrentOverlay = &(*it); + if ((pCurrentOverlay->type == 5) || ((pCurrentOverlay->type == 21) && (pCurrentOverlay->x == overlayPtr->objIdx))) { + AnimData *sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; + + if (pMask == NULL) { + pMask = new byte[width*height]; + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + byte spriteColor= spritePtr[width * i + j]; + pMask[width * i + j] = spriteColor; + } + } + } + + for (int i = 0; i < sprite->_realWidth; i++) { + for (int j = 0; j < sprite->_height; j++) { + int inMaskX = (g_cine->_objectTable[it->objIdx].x + i) - x; + int inMaskY = (g_cine->_objectTable[it->objIdx].y + j) - y; + + if (inMaskX >=0 && inMaskX < width) { + if (inMaskY >= 0 && inMaskY < height) { + if (sprite->_bpp == 1) { + if (!sprite->getColor(i, j)) { + pMask[inMaskY * width + inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320]; + } + } + } + } + } + } + } + it++; + } + + // now, draw with the mask we created + if(pMask) { + spritePtr = pMask; + } + + // ignore transparent color in 1bpp + if (bpp == 1) { + transparentColor = 1; + } + + { + for (int i = 0; i < height; i++) { + byte *destPtr = page + x + y * 320; + destPtr += i * 320; + + for (int j = 0; j < width; j++) { + byte color= *(spritePtr++); + if ((transparentColor != color) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) { + *(destPtr++) = color; + } else { + destPtr++; + } + } + } + } + + delete[] pMask; +} + void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y) { int16 i, j; diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 737c49cc36..3434cf9fc2 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -27,6 +27,7 @@ #include "common/rect.h" #include "common/stack.h" #include "cine/object.h" +#include "cine/bg_list.h" namespace Cine { @@ -177,8 +178,8 @@ public: void drawFrame(); void setCommand(Common::String cmd); - virtual void incrustMask(const ObjectStruct &obj, uint8 color = 0); - virtual void incrustSprite(const ObjectStruct &obj); + virtual void incrustMask(const BGIncrust &incrust, uint8 color = 0); + virtual void incrustSprite(const BGIncrust &incrust); virtual void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); virtual void loadCt16(const byte *ct, const char *name); @@ -223,6 +224,7 @@ private: protected: void drawSprite(const ObjectStruct &obj); + void drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp); int drawChar(char character, int x, int y); void drawBackground(); void renderOverlay(const Common::List<overlay>::iterator &it); @@ -238,8 +240,8 @@ public: void clear(); - void incrustMask(const ObjectStruct &obj, uint8 color = 0); - void incrustSprite(const ObjectStruct &obj); + void incrustMask(const BGIncrust &incrust, uint8 color = 0); + void incrustSprite(const BGIncrust &incrust); void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); void loadCt16(const byte *ct, const char *name); diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 971830ce8f..f13f38a45e 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -56,6 +56,12 @@ static void processEvent(Common::Event &event) { case Common::EVENT_RBUTTONDOWN: mouseRight = 1; break; + case Common::EVENT_LBUTTONUP: + mouseLeft = 0; + break; + case Common::EVENT_RBUTTONUP: + mouseRight = 0; + break; case Common::EVENT_MOUSEMOVE: break; case Common::EVENT_KEYDOWN: @@ -115,7 +121,7 @@ static void processEvent(Common::Event &event) { } break; case Common::KEYCODE_F10: - if (!disableSystemMenu && !inMenu) { + if (!inMenu) { g_cine->makeSystemMenu(); } break; @@ -214,8 +220,6 @@ void manageEvents() { g_sound->update(); mouseData.left = mouseLeft; mouseData.right = mouseRight; - mouseLeft = 0; - mouseRight = 0; } void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) { @@ -311,6 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence. // This makes it possible to pass the arcade sequence for now. // FIXME: Remove the hack and make the first arcade sequence normally playable. + /* if (g_cine->getGameType() == Cine::GType_OS) { Common::String bgName(renderer->getBgName()); // Check if the background is one of the three backgrounds @@ -320,7 +325,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Force the amount of oxygen left to the maximum. g_cine->_objectTable[oxygenObjNum].x = maxOxygen; } - } + }*/ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck. // After the first arcade sequence the player comes up stairs from @@ -379,8 +384,8 @@ void CineEngine::mainLoop(int bootScriptIdx) { playerAction = false; _messageLen <<= 3; - if (_messageLen < 0x800) - _messageLen = 0x800; + if (_messageLen < 800) + _messageLen = 800; do { manageEvents(); diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index 223099a587..20952eea52 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -991,7 +991,7 @@ void CineEngine::makeSave(char *saveFileName) { * at a time. */ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) { - int16 currentAnim, foundFileIdx; + int16 foundFileIdx; char *animName, part[256], name[10]; strcpy(part, currentPartName); @@ -1001,10 +1001,10 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30); const int fileStartPos = fHandle.pos(); - currentAnim = 0; - while (currentAnim < NUM_MAX_ANIMDATA) { + + for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) { // Seek to the start of the current animation's entry - fHandle.seek(fileStartPos + currentAnim * entrySize); + fHandle.seek(fileStartPos + resourceIndex * entrySize); // Read in the current animation entry fHandle.readUint16BE(); // width fHandle.readUint16BE(); @@ -1019,7 +1019,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam } foundFileIdx = fHandle.readSint16BE(); - fHandle.readSint16BE(); // frame + int16 frameIndex = fHandle.readSint16BE(); // frame fHandle.read(name, 10); // Handle variables only present in animation entries of size 23 @@ -1029,7 +1029,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam // Don't try to load invalid entries. if (foundFileIdx < 0 || !validPtr) { - currentAnim++; // Jump over the invalid entry + //resourceIndex++; // Jump over the invalid entry continue; } @@ -1041,9 +1041,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam animName = g_cine->_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? - const int16 prevAnim = currentAnim; - currentAnim = loadResource(animName, currentAnim); - assert(currentAnim > prevAnim); // Make sure we advance forward + loadResource(animName, resourceIndex, frameIndex); } loadPart(part); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 66150cc5b2..9cbe3c3fab 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -533,7 +533,6 @@ void RawScript::setData(const FWScriptInfo &info, const byte *data) { * @return Precalculated script labels */ const ScriptVars &RawScript::labels() const { - assert(_data); return _labels; } @@ -687,7 +686,7 @@ const char *FWScript::getNextString() { * @param pos Restored script position */ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { - assert(pos < _script._size); + assert(pos <= _script._size); _labels = labels; _localVars = local; _compare = compare; @@ -705,13 +704,15 @@ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 co int FWScript::execute() { int ret = 0; - while (!ret) { - _line = _pos; - byte opcode = getNextByte(); - OpFunc handler = _info->opcodeHandler(opcode); + if(_script._size) { + while (!ret) { + _line = _pos; + byte opcode = getNextByte(); + OpFunc handler = _info->opcodeHandler(opcode); - if (handler) { - ret = (this->*handler)(); + if (handler) { + ret = (this->*handler)(); + } } } @@ -1861,7 +1862,7 @@ int FWScript::o1_disableSystemMenu() { byte param = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param); - disableSystemMenu = (param != 0); + disableSystemMenu = param; return 0; } diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index b2e992e8f6..52e1cdac7e 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -785,7 +785,6 @@ PCSoundFxPlayer::~PCSoundFxPlayer() { bool PCSoundFxPlayer::load(const char *song) { debug(9, "PCSoundFxPlayer::load('%s')", song); - Common::StackLock lock(_mutex); /* stop (w/ fade out) the previous song */ while (_fadeOutCounter != 0 && _fadeOutCounter < 100) { @@ -793,6 +792,8 @@ bool PCSoundFxPlayer::load(const char *song) { } _fadeOutCounter = 0; + Common::StackLock lock(_mutex); + stop(); _sfxData = readBundleSoundFile(song); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9b73ae1101..eccd71cf05 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -36,7 +36,7 @@ namespace Cine { -bool disableSystemMenu = false; +int16 disableSystemMenu = 0; bool inMenu; int16 commandVar3[4]; @@ -341,7 +341,7 @@ void CineEngine::makeSystemMenu() { int16 mouseX, mouseY, mouseButton; int16 selectedSave; - if (!disableSystemMenu) { + if (disableSystemMenu != 1) { inMenu = true; do { @@ -544,14 +544,16 @@ int16 buildObjectListCommand(int16 param) { int16 selectSubObject(int16 x, int16 y, int16 param) { int16 listSize = buildObjectListCommand(param); - int16 selectedObject; + int16 selectedObject = -1; bool osExtras = g_cine->getGameType() == Cine::GType_OS; if (!listSize) { return -2; } - selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + if (disableSystemMenu == 0) { + selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + } if (selectedObject == -1) return -1; @@ -691,9 +693,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, int16 var_4; SelectionMenu *menu; - if (disableSystemMenu) - return -1; - paramY = (height * 9) + 10; if (X + width > 319) { @@ -810,14 +809,18 @@ void makeActionMenu() { getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY); if (g_cine->getGameType() == Cine::GType_OS) { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + } if (playerCommand >= 8000) { playerCommand -= 8000; canUseOnObject = canUseOnItemTable[playerCommand]; } } else { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + } } inMenu = false; diff --git a/engines/cine/various.h b/engines/cine/various.h index 0c1883c323..813619816d 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -41,7 +41,7 @@ void makeActionMenu(); void waitPlayerInput(); void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4); -extern bool disableSystemMenu; +extern int16 disableSystemMenu; extern bool inMenu; extern CommandeType currentSaveName[10]; diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp index 556dad7e94..23a9d2ff85 100644 --- a/engines/composer/composer.cpp +++ b/engines/composer/composer.cpp @@ -381,11 +381,17 @@ void ComposerEngine::loadLibrary(uint id) { filename = getStringFromConfig(_bookGroup, Common::String::format("%d", id)); filename = mangleFilename(filename); + // bookGroup is the basename of the path. + // TODO: tidy this up. _bookGroup.clear(); for (uint i = 0; i < filename.size(); i++) { - if (filename[i] == '\\' || filename[i] == ':') + if (filename[i] == '~' || filename[i] == '/' || filename[i] == ':') continue; for (uint j = 0; j < filename.size(); j++) { + if (filename[j] == '/') { + _bookGroup.clear(); + continue; + } if (filename[j] == '.') break; _bookGroup += filename[j]; diff --git a/engines/configure.engines b/engines/configure.engines index 4d416381bf..57261e1f0d 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -7,11 +7,11 @@ add_engine agos "AGOS" yes "agos2" add_engine agos2 "AGOS 2 games" yes add_engine cge "CGE" yes add_engine cine "Cinematique evo 1" yes -add_engine composer "Magic Composer" no +add_engine composer "Magic Composer" yes add_engine cruise "Cinematique evo 2" yes add_engine draci "Dragon History" yes add_engine drascula "Drascula: The Vampire Strikes Back" yes -add_engine dreamweb "Dreamweb" no +add_engine dreamweb "Dreamweb" yes add_engine gob "Gobli*ns" yes add_engine groovie "Groovie" yes "groovie2" add_engine groovie2 "Groovie 2 games" no diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index cf01d9bdbc..2147419886 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -169,6 +169,9 @@ bool CruiseEngine::loadLanguageStrings() { case Common::DE_DEU: p = germanLanguageStrings; break; + case Common::IT_ITA: + p = italianLanguageStrings; + break; default: return false; } diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index eb7c1c524f..cbe17ea4d3 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -171,6 +171,19 @@ static const CRUISEGameDescription gameDescriptions[] = { GType_CRUISE, 0, }, + { // Amiga Italian US GOLD edition. + { + "cruise", + 0, + AD_ENTRY1("D1", "a0011075413b7335e003e8e3c9cf51b9"), + Common::IT_ITA, + Common::kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO0() + }, + GType_CRUISE, + 0, + }, { // AtariST English KixxXL edition. { "cruise", @@ -290,8 +303,6 @@ SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int // Create the return descriptor SaveStateDescriptor desc(slot, header.saveName); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); desc.setThumbnail(header.thumbnail); return desc; diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index e763e2b8a1..512259f7d7 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -207,16 +207,13 @@ int processMenu(menuStruct *pMenu) { } static void handleSaveLoad(bool saveFlag) { - const EnginePlugin *plugin = 0; - EngineMan.findGame(_vm->getGameId(), &plugin); GUI::SaveLoadChooser *dialog; if (saveFlag) - dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); + dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); else - dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); + dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); - dialog->setSaveMode(saveFlag); - int slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = dialog->runModalWithCurrentTarget(); if (slot >= 0) { if (!saveFlag) diff --git a/engines/cruise/staticres.cpp b/engines/cruise/staticres.cpp index 1565f254d0..a3fc4f884b 100644 --- a/engines/cruise/staticres.cpp +++ b/engines/cruise/staticres.cpp @@ -320,5 +320,9 @@ const char *germanLanguageStrings[13] = { " ", NULL, NULL, NULL, NULL, "Inventar", "Sprechen ""\xFC""ber", "Speilermen\xFC", "Speicherlaufwerk", "Speichern", "Laden", "Neu beginnen", "Ende" }; +const char *italianLanguageStrings[13] = { + "Pausa", NULL, NULL, NULL, NULL, "Inventario", "Parla di...", "Menu giocatore", NULL, + "Salva", "Carica", "Ricomincia", "Esci" +}; } // End of namespace Cruise diff --git a/engines/cruise/staticres.h b/engines/cruise/staticres.h index a3cf13e41c..acf0b640be 100644 --- a/engines/cruise/staticres.h +++ b/engines/cruise/staticres.h @@ -57,6 +57,7 @@ extern const byte mouseCursorMagnifyingGlass[]; extern const char *englishLanguageStrings[13]; extern const char *frenchLanguageStrings[13]; extern const char *germanLanguageStrings[13]; +extern const char *italianLanguageStrings[13]; } // End of namespace Cruise diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index 1b54c7e26a..cf3dfaa44b 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -111,10 +111,8 @@ MainMenuDialog::MainMenuDialog(Engine *engine) _aboutDialog = new GUI::AboutDialog(); _optionsDialog = new ConfigDialog(_engine->hasFeature(Engine::kSupportsSubtitleOptions)); - _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); - _loadDialog->setSaveMode(false); - _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); - _saveDialog->setSaveMode(true); + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); } MainMenuDialog::~MainMenuDialog() { @@ -216,26 +214,13 @@ void MainMenuDialog::reflowLayout() { } void MainMenuDialog::save() { - const Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int slot = _saveDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = _saveDialog->runModalWithCurrentTarget(); if (slot >= 0) { Common::String result(_saveDialog->getResultString()); if (result.empty()) { // If the user was lazy and entered no save name, come up with a default name. - #if defined(USE_SAVEGAME_TIMESTAMP) - TimeDate curTime; - g_system->getTimeAndDate(curTime); - curTime.tm_year += 1900; // fixup year - curTime.tm_mon++; // fixup month - result = Common::String::format("%04d.%02d.%02d / %02d:%02d:%02d", curTime.tm_year, curTime.tm_mon, curTime.tm_mday, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); - #else - result = Common::String::format("Save %d", slot + 1); - #endif + result = _saveDialog->createDefaultSaveDescription(slot); } Common::Error status = _engine->saveGameState(slot, result); @@ -252,12 +237,7 @@ void MainMenuDialog::save() { } void MainMenuDialog::load() { - const Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int slot = _loadDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = _loadDialog->runModalWithCurrentTarget(); _engine->setGameToLoadSlot(slot); diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index de76eb83e0..61705a1e59 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -161,8 +161,6 @@ SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int // Create the return descriptor SaveStateDescriptor desc(slot, header.saveName); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); desc.setThumbnail(header.thumbnail); int day = (header.date >> 24) & 0xFF; diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp index c08bcea01f..4b8db63bb7 100644 --- a/engines/drascula/interface.cpp +++ b/engines/drascula/interface.cpp @@ -28,10 +28,10 @@ namespace Drascula { void DrasculaEngine::setCursor(int cursor) { switch (cursor) { case kCursorCrosshair: - CursorMan.replaceCursor((const byte *)crosshairCursor, 40, 25, 20, 17, 255); + CursorMan.replaceCursor(crosshairCursor, 40, 25, 20, 17, 255); break; case kCursorCurrentItem: - CursorMan.replaceCursor((const byte *)mouseCursor, OBJWIDTH, OBJHEIGHT, 20, 17, 255); + CursorMan.replaceCursor(mouseCursor, OBJWIDTH, OBJHEIGHT, 20, 17, 255); default: break; } diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index 6468281ac2..f2e2f42216 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -172,8 +172,6 @@ SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, i saveName += (char)in->readByte(); SaveStateDescriptor desc(slot, saveName); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); // Check if there is a ScummVM data block if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) { diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h index 8ca24d1724..8a2f94f99b 100644 --- a/engines/dreamweb/detection_tables.h +++ b/engines/dreamweb/detection_tables.h @@ -41,11 +41,12 @@ static const DreamWebGameDescription gameDescriptions[] = { { {"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918}, {"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466}, + {"dreamweb.exe", 0, "56b1d73aa56e964b45872ff552402341", 64985}, AD_LISTEND }, Common::EN_ANY, Common::kPlatformPC, - ADGF_UNSTABLE, + 0, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -62,7 +63,28 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_CD | ADGF_UNSTABLE, + ADGF_CD, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + + // UK-V (Early UK) CD Release - From bug #3526483 + // Note: r00 and r02 files are identical to international floppy release + // so was misidentified as floppy, resulting in disabled CD speech. + // Added executable to detection to avoid this. + { + { + "dreamweb", + "CD", + { + {"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918}, + {"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466}, + {"dreamweb.exe", 0, "dd1c7793b151489e67b83cd1ecab51cd", -1}, + AD_LISTEND + }, + Common::EN_GRB, + Common::kPlatformPC, + ADGF_CD, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -96,7 +118,25 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformPC, - ADGF_CD | ADGF_UNSTABLE, + ADGF_CD, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + + // French CD release + // From bug #3524362 + { + { + "dreamweb", + "CD", + { + {"dreamwfr.r00", 0, "e354582a8564faf5c515df92f207e8d1", 154657}, + {"dreamwfr.r02", 0, "cb99f08d5aefd04184eac76927eced80", 200575}, + AD_LISTEND + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_CD, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -113,7 +153,7 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_UNSTABLE, + 0, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -130,7 +170,7 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_CD | ADGF_UNSTABLE, + ADGF_CD, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -147,7 +187,7 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_UNSTABLE, + 0, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -164,7 +204,25 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_CD | ADGF_UNSTABLE, + ADGF_CD, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + + // Spanish CD release + // From bug #3524362 + { + { + "dreamweb", + "CD", + { + {"dreamwsp.r00", 0, "2df07174321de39c4f17c9ff654b268a", 153608}, + {"dreamwsp.r02", 0, "f97d435ad5da08fb1bcf6ea3dd6e0b9e", 199499}, + AD_LISTEND + }, + Common::ES_ESP, + Common::kPlatformPC, + ADGF_CD, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -181,7 +239,7 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_UNSTABLE, + 0, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp index 0a35bcdecc..0ca98d5a7b 100644 --- a/engines/dreamweb/dreamweb.cpp +++ b/engines/dreamweb/dreamweb.cpp @@ -35,6 +35,7 @@ #include "graphics/palette.h" #include "graphics/surface.h" +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -46,31 +47,29 @@ DreamWebEngine::DreamWebEngine(OSystem *syst, const DreamWebGameDescription *gam _roomDesc(kNumRoomTexts), _freeDesc(kNumFreeTexts), _personText(kNumPersonTexts) { - // Setup mixer - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _vSyncInterrupt = false; _console = 0; + _sound = 0; DebugMan.addDebugChannel(kDebugAnimation, "Animation", "Animation Debug Flag"); DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function"); _speed = 1; _turbo = false; _oldMouseState = 0; - _channel0 = 0; - _channel1 = 0; _datafilePrefix = "DREAMWEB."; + _speechDirName = "SPEECH"; // ES and FR CD release use a different data file prefix + // and speech directory naming. if (isCD()) { switch(getLanguage()) { case Common::ES_ESP: _datafilePrefix = "DREAMWSP."; + _speechDirName = "SPANISH"; break; case Common::FR_FRA: _datafilePrefix = "DREAMWFR."; + _speechDirName = "FRENCH"; break; default: // Nothing to do @@ -81,16 +80,6 @@ DreamWebEngine::DreamWebEngine(OSystem *syst, const DreamWebGameDescription *gam _openChangeSize = kInventx+(4*kItempicsize); _quitRequested = false; - _currentSample = 0xff; - _channel0Playing = 0; - _channel0Repeat = 0; - _channel1Playing = 0xff; - - _volume = 0; - _volumeTo = 0; - _volumeDirection = 0; - _volumeCount = 0; - _speechLoaded = false; _backdropBlocks = 0; @@ -242,6 +231,7 @@ DreamWebEngine::DreamWebEngine(OSystem *syst, const DreamWebGameDescription *gam DreamWebEngine::~DreamWebEngine() { DebugMan.clearAllDebugChannels(); delete _console; + delete _sound; } static void vSyncInterrupt(void *refCon) { @@ -282,7 +272,7 @@ void DreamWebEngine::processEvents() { return; } - soundHandler(); + _sound->soundHandler(); Common::Event event; int softKey, hardKey; while (_eventMan->pollEvent(event)) { @@ -378,10 +368,11 @@ void DreamWebEngine::processEvents() { Common::Error DreamWebEngine::run() { syncSoundSettings(); _console = new DreamWebConsole(this); + _sound = new DreamWebSound(this); ConfMan.registerDefault("originalsaveload", "false"); ConfMan.registerDefault("bright_palette", true); - _hasSpeech = Common::File::exists("speech/r01c0000.raw") && !ConfMan.getBool("speech_mute"); + _hasSpeech = Common::File::exists(_speechDirName + "/r01c0000.raw") && !ConfMan.getBool("speech_mute"); _brightPalette = ConfMan.getBool("bright_palette"); _timer->installTimerProc(vSyncInterrupt, 1000000 / 70, this, "dreamwebVSync"); @@ -522,6 +513,7 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const { return c; } case Common::FR_FRA: + case Common::IT_ITA: switch(c) { case 133: return 'Z' + 1; diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h index 4065e5a860..1f6deb8566 100644 --- a/engines/dreamweb/dreamweb.h +++ b/engines/dreamweb/dreamweb.h @@ -99,10 +99,12 @@ enum { }; struct DreamWebGameDescription; +class DreamWebSound; class DreamWebEngine : public Engine { private: DreamWebConsole *_console; + DreamWebSound *_sound; bool _vSyncInterrupt; protected: @@ -142,7 +144,6 @@ public: void quit(); - void loadSounds(uint bank, const Common::String &suffix); bool loadSpeech(const Common::String &filename); void enableSavingOrLoading(bool enable = true) { _enableSavingOrLoading = enable; } @@ -151,41 +152,23 @@ public: uint8 modifyChar(uint8 c) const; Common::String modifyFileName(const char *); - void stopSound(uint8 channel); - - const Common::String& getDatafilePrefix() { return _datafilePrefix; }; + const Common::String& getDatafilePrefix() { return _datafilePrefix; } + const Common::String& getSpeechDirName() { return _speechDirName; } private: void keyPressed(uint16 ascii); void setSpeed(uint speed); - void soundHandler(); - void playSound(uint8 channel, uint8 id, uint8 loops); const DreamWebGameDescription *_gameDescription; Common::RandomSource _rnd; Common::String _datafilePrefix; + Common::String _speechDirName; uint _speed; bool _turbo; uint _oldMouseState; bool _enableSavingOrLoading; - struct Sample { - uint offset; - uint size; - Sample(): offset(), size() {} - }; - - struct SoundData { - Common::Array<Sample> samples; - Common::Array<uint8> data; - }; - SoundData _soundData[2]; - Common::Array<uint8> _speechData; - - Audio::SoundHandle _channelHandle[2]; - uint8 _channel0, _channel1; - protected: GameVars _vars; // saved variables @@ -326,16 +309,6 @@ public: // sound related uint8 _roomsSample; - uint8 _currentSample; - uint8 _channel0Playing; - uint8 _channel0Repeat; - uint8 _channel1Playing; - - uint8 _volume; - uint8 _volumeTo; - int8 _volumeDirection; - uint8 _volumeCount; - bool _speechLoaded; // misc variables @@ -714,15 +687,6 @@ public: void showSaveOps(); void showLoadOps(); - // from sound.cpp - bool loadSpeech(byte type1, int idx1, byte type2, int idx2); - void volumeAdjust(); - void cancelCh0(); - void cancelCh1(); - void loadRoomsSample(); - void playChannel0(uint8 index, uint8 repeat); - void playChannel1(uint8 index); - // from sprite.cpp void printSprites(); void printASprite(const Sprite *sprite); @@ -1134,7 +1098,6 @@ public: void frameOutBh(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); void frameOutFx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); void doShake(); - void vSync(); void setMode(); void showPCX(const Common::String &suffix); void showFrameInternal(const uint8 *pSrc, uint16 x, uint16 y, uint8 effectsFlag, uint8 width, uint8 height); diff --git a/engines/dreamweb/keypad.cpp b/engines/dreamweb/keypad.cpp index 2ab5835997..3580f8ad52 100644 --- a/engines/dreamweb/keypad.cpp +++ b/engines/dreamweb/keypad.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -62,11 +63,11 @@ void DreamWebEngine::enterCode(uint8 digit0, uint8 digit1, uint8 digit2, uint8 d readMouse(); showKeypad(); showPointer(); - vSync(); + waitForVSync(); if (_pressCount == 0) { _pressed = 255; _graphicPress = 255; - vSync(); + waitForVSync(); } else --_pressCount; @@ -85,7 +86,7 @@ void DreamWebEngine::enterCode(uint8 digit0, uint8 digit1, uint8 digit2, uint8 d if (_pressed == 11) { if (isItRight(digit0, digit1, digit2, digit3)) _vars._lockStatus = 0; - playChannel1(11); + _sound->playChannel1(11); _lightCount = 120; _pressPointer = 0; } @@ -180,7 +181,7 @@ void DreamWebEngine::buttonPress(uint8 buttonId) { _graphicPress = buttonId + 21; _pressCount = 40; if (buttonId != 11) - playChannel1(10); + _sound->playChannel1(10); } } @@ -252,7 +253,7 @@ void DreamWebEngine::useMenu() { showMenu(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpMenu(); dumpTextLine(); @@ -311,7 +312,7 @@ void DreamWebEngine::viewFolder() { delPointer(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); checkFolderCoords(); @@ -508,7 +509,7 @@ void DreamWebEngine::enterSymbol() { showSymbol(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); dumpSymbol(); @@ -532,7 +533,7 @@ void DreamWebEngine::enterSymbol() { _symbolGraphics.clear(); restoreReels(); workToScreenM(); - playChannel1(13); + _sound->playChannel1(13); } else { removeSetObject(46); placeSetObject(43); @@ -743,7 +744,7 @@ void DreamWebEngine::useDiary() { readMouse(); showDiaryKeys(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpDiaryKeys(); dumpTextLine(); @@ -820,7 +821,7 @@ void DreamWebEngine::diaryKeyP() { _pressCount) return; // notkeyp - playChannel1(16); + _sound->playChannel1(16); _pressCount = 12; _pressed = 'P'; _diaryPage--; @@ -837,7 +838,7 @@ void DreamWebEngine::diaryKeyN() { _pressCount) return; // notkeyn - playChannel1(16); + _sound->playChannel1(16); _pressCount = 12; _pressed = 'N'; _diaryPage++; diff --git a/engines/dreamweb/monitor.cpp b/engines/dreamweb/monitor.cpp index 95aa400c3a..4e9d8eecc1 100644 --- a/engines/dreamweb/monitor.cpp +++ b/engines/dreamweb/monitor.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -97,7 +98,7 @@ void DreamWebEngine::useMon() { _textFile3.clear(); _getBack = 1; - playChannel1(26); + _sound->playChannel1(26); _manIsOffScreen = 0; restoreAll(); redrawMainScrn(); @@ -180,7 +181,7 @@ void DreamWebEngine::monitorLogo() { printLogo(); //fadeUpMon(); // FIXME: Commented out in ASM printLogo(); - playChannel1(26); + _sound->playChannel1(26); randomAccess(20); } else { printLogo(); @@ -202,7 +203,7 @@ void DreamWebEngine::input() { _cursLocY = _monAdY; while (true) { printCurs(); - vSync(); + waitForVSync(); delCurs(); readKey(); if (_quitRequested) @@ -288,7 +289,7 @@ void DreamWebEngine::scrollMonitor() { printLogo(); printUnderMonitor(); workToScreen(); - playChannel1(25); + _sound->playChannel1(25); } void DreamWebEngine::showCurrentFile() { @@ -318,8 +319,8 @@ void DreamWebEngine::accessLightOff() { void DreamWebEngine::randomAccess(uint16 count) { for (uint16 i = 0; i < count; ++i) { - vSync(); - vSync(); + waitForVSync(); + waitForVSync(); uint16 v = _rnd.getRandomNumber(15); if (v < 10) accessLightOff(); @@ -626,15 +627,12 @@ void DreamWebEngine::signOn() { _monAdX = prevX; _monAdY = prevY; - inputLine = (const char *)_inputLine; - inputLine.toUppercase(); - // The entered line has zeroes in-between each character uint32 len = strlen(monitorKeyEntries[foundIndex].password); bool found = true; for (uint32 i = 0; i < len; i++) { - if (monitorKeyEntries[foundIndex].password[i] != inputLine[i * 2]) { + if (monitorKeyEntries[foundIndex].password[i] != _inputLine[i * 2]) { found = false; break; } diff --git a/engines/dreamweb/newplace.cpp b/engines/dreamweb/newplace.cpp index 529c45bd4a..5b4b0260f5 100644 --- a/engines/dreamweb/newplace.cpp +++ b/engines/dreamweb/newplace.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -55,7 +56,7 @@ void DreamWebEngine::selectLocation() { _pointerFrame = 0; showPointer(); workToScreen(); - playChannel0(9, 255); + _sound->playChannel0(9, 255); _newLocation = 255; while (_newLocation == 255) { @@ -65,7 +66,7 @@ void DreamWebEngine::selectLocation() { delPointer(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); diff --git a/engines/dreamweb/object.cpp b/engines/dreamweb/object.cpp index 443366561a..b42591ef91 100644 --- a/engines/dreamweb/object.cpp +++ b/engines/dreamweb/object.cpp @@ -147,7 +147,7 @@ void DreamWebEngine::examineOb(bool examineAgain) { readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); delPointer(); diff --git a/engines/dreamweb/people.cpp b/engines/dreamweb/people.cpp index dfb5c62618..36a756a49b 100644 --- a/engines/dreamweb/people.cpp +++ b/engines/dreamweb/people.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -149,7 +150,7 @@ void DreamWebEngine::madmanText() { if (hasSpeech()) { if (_speechCount > 15) return; - if (_channel1Playing != 255) + if (_sound->isChannel1Playing()) return; origCount = _speechCount; ++_speechCount; @@ -250,7 +251,7 @@ bool DreamWebEngine::checkSpeed(ReelRoutine &routine) { void DreamWebEngine::sparkyDrip(ReelRoutine &routine) { if (checkSpeed(routine)) - playChannel0(14, 0); + _sound->playChannel0(14, 0); } void DreamWebEngine::genericPerson(ReelRoutine &routine) { @@ -430,7 +431,7 @@ void DreamWebEngine::drinker(ReelRoutine &routine) { void DreamWebEngine::alleyBarkSound(ReelRoutine &routine) { uint16 prevReelPointer = routine.reelPointer() - 1; if (prevReelPointer == 0) { - playChannel1(14); + _sound->playChannel1(14); routine.setReelPointer(1000); } else { routine.setReelPointer(prevReelPointer); @@ -523,7 +524,7 @@ void DreamWebEngine::gates(ReelRoutine &routine) { if (checkSpeed(routine)) { uint16 nextReelPointer = routine.reelPointer() + 1; if (nextReelPointer == 116) - playChannel1(17); + _sound->playChannel1(17); if (nextReelPointer >= 110) routine.period = 2; if (nextReelPointer == 120) { @@ -579,12 +580,12 @@ void DreamWebEngine::carParkDrip(ReelRoutine &routine) { if (!checkSpeed(routine)) return; // cantdrip2 - playChannel1(14); + _sound->playChannel1(14); } void DreamWebEngine::foghornSound(ReelRoutine &routine) { if (randomNumber() == 198) - playChannel1(13); + _sound->playChannel1(13); } void DreamWebEngine::train(ReelRoutine &routine) { @@ -1027,8 +1028,7 @@ void DreamWebEngine::endGameSeq(ReelRoutine &routine) { fadeScreenDownHalf(); } else if (nextReelPointer == 324) { fadeScreenDowns(); - _volumeTo = 7; - _volumeDirection = 1; + _sound->volumeChange(7, 1); } if (nextReelPointer == 340) diff --git a/engines/dreamweb/print.cpp b/engines/dreamweb/print.cpp index a6b93a5590..3a2c45e07b 100644 --- a/engines/dreamweb/print.cpp +++ b/engines/dreamweb/print.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -197,7 +198,7 @@ uint8 DreamWebEngine::kernChars(uint8 firstChar, uint8 secondChar, uint8 width) uint16 DreamWebEngine::waitFrames() { readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); delPointer(); return _mouseButton; @@ -231,7 +232,7 @@ const char *DreamWebEngine::monPrint(const char *string) { _cursLocY = _monAdY; _mainTimer = 1; printCurs(); - vSync(); + waitForVSync(); lockMon(); delCurs(); } while (--count); @@ -246,10 +247,9 @@ const char *DreamWebEngine::monPrint(const char *string) { } void DreamWebEngine::rollEndCreditsGameWon() { - playChannel0(16, 255); - _volume = 7; - _volumeTo = 0; - _volumeDirection = -1; + _sound->playChannel0(16, 255); + _sound->volumeSet(7); + _sound->volumeChange(0, -1); multiGet(_mapStore, 75, 20, 160, 160); @@ -261,9 +261,9 @@ void DreamWebEngine::rollEndCreditsGameWon() { // then move it up one pixel until we shifted it by a complete // line of text. for (int j = 0; j < linespacing; ++j) { - vSync(); + waitForVSync(); multiPut(_mapStore, 75, 20, 160, 160); - vSync(); + waitForVSync(); // Output up to 18 lines of text uint16 y = 10 - j; @@ -273,7 +273,7 @@ void DreamWebEngine::rollEndCreditsGameWon() { y += linespacing; } - vSync(); + waitForVSync(); multiDump(75, 20, 160, 160); } @@ -300,9 +300,9 @@ void DreamWebEngine::rollEndCreditsGameLost() { // then move it up one pixel until we shifted it by a complete // line of text. for (int j = 0; j < linespacing; ++j) { - vSync(); + waitForVSync(); multiPut(_mapStore, 25, 20, 160, 160); - vSync(); + waitForVSync(); // Output up to 18 lines of text uint16 y = 10 - j; @@ -312,7 +312,7 @@ void DreamWebEngine::rollEndCreditsGameLost() { y += linespacing; } - vSync(); + waitForVSync(); multiDump(25, 20, 160, 160); if (_lastHardKey == 1) diff --git a/engines/dreamweb/rain.cpp b/engines/dreamweb/rain.cpp index 7db4744cbf..8e42e0c161 100644 --- a/engines/dreamweb/rain.cpp +++ b/engines/dreamweb/rain.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -50,7 +51,7 @@ void DreamWebEngine::showRain() { } } - if (_channel1Playing != 255) + if (_sound->isChannel1Playing()) return; if (_realLocation == 2 && _vars._beenMugged != 1) return; @@ -61,11 +62,11 @@ void DreamWebEngine::showRain() { return; uint8 soundIndex; - if (_channel0Playing != 6) + if (_sound->getChannel0Playing() != 6) soundIndex = 4; else soundIndex = 7; - playChannel1(soundIndex); + _sound->playChannel1(soundIndex); } uint8 DreamWebEngine::getBlockOfPixel(uint8 x, uint8 y) { diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp index 5d7f02c5cf..ea9cdc0249 100644 --- a/engines/dreamweb/saveload.cpp +++ b/engines/dreamweb/saveload.cpp @@ -20,7 +20,9 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" + #include "engines/metaengine.h" #include "graphics/thumbnail.h" #include "gui/saveload.h" @@ -136,7 +138,7 @@ void DreamWebEngine::doLoad(int savegameId) { delPointer(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); RectWithCallback loadlist[] = { @@ -156,12 +158,8 @@ void DreamWebEngine::doLoad(int savegameId) { if (savegameId == -1) { // Open dialog to get savegameId - const EnginePlugin *plugin = NULL; - Common::String gameId = ConfMan.get("gameid"); - EngineMan.findGame(gameId, &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore")); - dialog->setSaveMode(false); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } @@ -181,7 +179,7 @@ void DreamWebEngine::doLoad(int savegameId) { _saveGraphics.clear(); startLoading(g_madeUpRoomDat); - loadRoomsSample(); + _sound->loadRoomsSample(_roomsSample); _roomLoaded = 1; _newLocation = 255; clearSprites(); @@ -227,7 +225,7 @@ void DreamWebEngine::saveGame() { checkInput(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); @@ -243,12 +241,8 @@ void DreamWebEngine::saveGame() { } return; } else { - const EnginePlugin *plugin = NULL; - Common::String gameId = ConfMan.get("gameid"); - EngineMan.findGame(gameId, &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); - dialog->setSaveMode(true); - int savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + int savegameId = dialog->runModalWithCurrentTarget(); Common::String game_description = dialog->getResultString(); if (game_description.empty()) game_description = "Untitled"; @@ -348,7 +342,7 @@ void DreamWebEngine::doSaveLoad() { readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); delPointer(); @@ -429,7 +423,7 @@ void DreamWebEngine::discOps() { delPointer(); readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); checkCoords(discOpsList); @@ -839,8 +833,9 @@ void DreamWebEngine::showOpBox() { // This call displays half of the ops dialog in the CD version. It's not // in the floppy version, and if it's called, a stray red dot is shown in - // the game dialogs. - if (isCD()) + // the game dialogs. It is included in the early UK CD release, which had + // similar data files as the floppy release (bug #3528160). + if (isCD() && getLanguage() != Common::EN_GRB) showFrame(_saveGraphics, kOpsx, kOpsy + 55, 4, 0); } diff --git a/engines/dreamweb/sound.cpp b/engines/dreamweb/sound.cpp index b51527a8cd..570f76f2f9 100644 --- a/engines/dreamweb/sound.cpp +++ b/engines/dreamweb/sound.cpp @@ -20,28 +20,51 @@ * */ -#include "dreamweb/dreamweb.h" - -#include "audio/mixer.h" #include "audio/decoders/raw.h" - #include "common/config-manager.h" +#include "common/debug.h" +#include "common/file.h" + +#include "dreamweb/dreamweb.h" +#include "dreamweb/sound.h" namespace DreamWeb { -bool DreamWebEngine::loadSpeech(byte type1, int idx1, byte type2, int idx2) { +DreamWebSound::DreamWebSound(DreamWebEngine *vm) : _vm(vm) { + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); + + _currentSample = 0xff; + _channel0Playing = 255; + _channel0Repeat = 0; + _channel0NewSound = false; + _channel1Playing = 255; + _channel1NewSound = false; + + _volume = 0; + _volumeTo = 0; + _volumeDirection = 0; + _volumeCount = 0; +} + +DreamWebSound::~DreamWebSound() { +} + +bool DreamWebSound::loadSpeech(byte type1, int idx1, byte type2, int idx2) { cancelCh1(); Common::String name = Common::String::format("%c%02d%c%04d.RAW", type1, idx1, type2, idx2); - //debug("name = %s", name.c_str()); - bool result = loadSpeech(name); - - _speechLoaded = result; - return result; + debug(2, "loadSpeech() name:%s", name.c_str()); + return loadSpeech(name); } +void DreamWebSound::volumeChange(uint8 value, int8 direction) { + _volumeTo = value; + _volumeDirection = direction; +} -void DreamWebEngine::volumeAdjust() { +void DreamWebSound::volumeAdjust() { if (_volumeDirection == 0) return; if (_volume != _volumeTo) { @@ -54,36 +77,38 @@ void DreamWebEngine::volumeAdjust() { } } -void DreamWebEngine::playChannel0(uint8 index, uint8 repeat) { - _channel0Playing = index; - if (index >= 12) - index -= 12; +void DreamWebSound::playChannel0(uint8 index, uint8 repeat) { + debug(1, "playChannel0(index:%d, repeat:%d)", index, repeat); + _channel0Playing = index; _channel0Repeat = repeat; + _channel0NewSound = true; } -void DreamWebEngine::playChannel1(uint8 index) { +void DreamWebSound::playChannel1(uint8 index) { + debug(1, "playChannel1(index:%d)", index); if (_channel1Playing == 7) return; _channel1Playing = index; - if (index >= 12) - index -= 12; + _channel1NewSound = true; } -void DreamWebEngine::cancelCh0() { - _channel0Repeat = 0; +void DreamWebSound::cancelCh0() { + debug(1, "cancelCh0()"); _channel0Playing = 255; + _channel0Repeat = 0; stopSound(0); } -void DreamWebEngine::cancelCh1() { +void DreamWebSound::cancelCh1() { + debug(1, "cancelCh1()"); _channel1Playing = 255; stopSound(1); } -void DreamWebEngine::loadRoomsSample() { - uint8 sample = _roomsSample; +void DreamWebSound::loadRoomsSample(uint8 sample) { + debug(1, "loadRoomsSample(sample:%d)", sample); if (sample == 255 || _currentSample == sample) return; // loaded already @@ -101,13 +126,8 @@ void DreamWebEngine::loadRoomsSample() { loadSounds(1, sampleSuffix.c_str()); } -} // End of namespace DreamWeb - - -namespace DreamWeb { - -void DreamWebEngine::playSound(uint8 channel, uint8 id, uint8 loops) { - debug(1, "playSound(%u, %u, %u)", channel, id, loops); +void DreamWebSound::playSound(uint8 channel, uint8 id, uint8 loops) { + debug(1, "playSound(channel:%u, id:%u, loops:%u)", channel, id, loops); int bank = 0; bool speech = false; @@ -137,47 +157,38 @@ void DreamWebEngine::playSound(uint8 channel, uint8 id, uint8 loops) { error("out of memory: cannot allocate memory for sound(%u bytes)", sample.size); memcpy(buffer, data.data.begin() + sample.offset, sample.size); - raw = Audio::makeRawStream( - buffer, - sample.size, 22050, Audio::FLAG_UNSIGNED); + raw = Audio::makeRawStream(buffer, sample.size, 22050, Audio::FLAG_UNSIGNED); } else { uint8 *buffer = (uint8 *)malloc(_speechData.size()); if (!buffer) error("out of memory: cannot allocate memory for sound(%u bytes)", _speechData.size()); memcpy(buffer, _speechData.begin(), _speechData.size()); - raw = Audio::makeRawStream( - buffer, - _speechData.size(), 22050, Audio::FLAG_UNSIGNED); - + raw = Audio::makeRawStream(buffer, _speechData.size(), 22050, Audio::FLAG_UNSIGNED); } Audio::AudioStream *stream; if (loops > 1) { - stream = new Audio::LoopingAudioStream(raw, loops < 255? loops: 0); + stream = new Audio::LoopingAudioStream(raw, (loops < 255) ? loops : 0); } else stream = raw; - if (_mixer->isSoundHandleActive(_channelHandle[channel])) - _mixer->stopHandle(_channelHandle[channel]); - _mixer->playStream(type, &_channelHandle[channel], stream); + if (_vm->_mixer->isSoundHandleActive(_channelHandle[channel])) + _vm->_mixer->stopHandle(_channelHandle[channel]); + _vm->_mixer->playStream(type, &_channelHandle[channel], stream); } -void DreamWebEngine::stopSound(uint8 channel) { +void DreamWebSound::stopSound(uint8 channel) { debug(1, "stopSound(%u)", channel); assert(channel == 0 || channel == 1); - _mixer->stopHandle(_channelHandle[channel]); - if (channel == 0) - _channel0 = 0; - else - _channel1 = 0; + _vm->_mixer->stopHandle(_channelHandle[channel]); } -bool DreamWebEngine::loadSpeech(const Common::String &filename) { - if (!hasSpeech()) +bool DreamWebSound::loadSpeech(const Common::String &filename) { + if (!_vm->hasSpeech()) return false; Common::File file; - if (!file.open("speech/" + filename)) + if (!file.open(_vm->getSpeechDirName() + "/" + filename)) return false; debug(1, "loadSpeech(%s)", filename.c_str()); @@ -189,8 +200,8 @@ bool DreamWebEngine::loadSpeech(const Common::String &filename) { return true; } -void DreamWebEngine::soundHandler() { - _subtitles = ConfMan.getBool("subtitles"); +void DreamWebSound::soundHandler() { + _vm->_subtitles = ConfMan.getBool("subtitles"); volumeAdjust(); uint volume = _volume; @@ -207,41 +218,31 @@ void DreamWebEngine::soundHandler() { if (volume >= 8) volume = 7; volume = (8 - volume) * Audio::Mixer::kMaxChannelVolume / 8; - _mixer->setChannelVolume(_channelHandle[0], volume); + _vm->_mixer->setChannelVolume(_channelHandle[0], volume); - uint8 ch0 = _channel0Playing; - if (ch0 == 255) - ch0 = 0; - uint8 ch1 = _channel1Playing; - if (ch1 == 255) - ch1 = 0; - uint8 ch0loop = _channel0Repeat; - - if (_channel0 != ch0) { - _channel0 = ch0; - if (ch0) { - playSound(0, ch0, ch0loop); + if (_channel0NewSound) { + _channel0NewSound = false; + if (_channel0Playing != 255) { + playSound(0, _channel0Playing, _channel0Repeat); } } - if (_channel1 != ch1) { - _channel1 = ch1; - if (ch1) { - playSound(1, ch1, 1); + if (_channel1NewSound) { + _channel1NewSound = false; + if (_channel1Playing != 255) { + playSound(1, _channel1Playing, 1); } } - if (!_mixer->isSoundHandleActive(_channelHandle[0])) { + + if (!_vm->_mixer->isSoundHandleActive(_channelHandle[0])) { _channel0Playing = 255; - _channel0 = 0; } - if (!_mixer->isSoundHandleActive(_channelHandle[1])) { + if (!_vm->_mixer->isSoundHandleActive(_channelHandle[1])) { _channel1Playing = 255; - _channel1 = 0; } - } -void DreamWebEngine::loadSounds(uint bank, const Common::String &suffix) { - Common::String filename = getDatafilePrefix() + suffix; +void DreamWebSound::loadSounds(uint bank, const Common::String &suffix) { + Common::String filename = _vm->getDatafilePrefix() + suffix; debug(1, "loadSounds(%u, %s)", bank, filename.c_str()); Common::File file; if (!file.open(filename)) { @@ -249,9 +250,9 @@ void DreamWebEngine::loadSounds(uint bank, const Common::String &suffix) { return; } - uint8 header[0x60]; + uint8 header[96]; file.read(header, sizeof(header)); - uint tablesize = READ_LE_UINT16(header + 0x32); + uint tablesize = READ_LE_UINT16(header + 50); debug(1, "table size = %u", tablesize); SoundData &soundData = _soundData[bank]; @@ -261,8 +262,8 @@ void DreamWebEngine::loadSounds(uint bank, const Common::String &suffix) { uint8 entry[6]; Sample &sample = soundData.samples[i]; file.read(entry, sizeof(entry)); - sample.offset = entry[0] * 0x4000 + READ_LE_UINT16(entry + 1); - sample.size = READ_LE_UINT16(entry + 3) * 0x800; + sample.offset = entry[0] * 16384 + READ_LE_UINT16(entry + 1); + sample.size = READ_LE_UINT16(entry + 3) * 2048; total += sample.size; debug(1, "offset: %08x, size: %u", sample.offset, sample.size); } diff --git a/engines/dreamweb/sound.h b/engines/dreamweb/sound.h new file mode 100644 index 0000000000..1ab06dc694 --- /dev/null +++ b/engines/dreamweb/sound.h @@ -0,0 +1,91 @@ +/* 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 DREAMWEB_SOUND_H +#define DREAMWEB_SOUND_H + +#include "common/array.h" +#include "common/str.h" +#include "audio/mixer.h" + +namespace DreamWeb { + +class DreamWebEngine; + +class DreamWebSound { +public: + DreamWebSound(DreamWebEngine *vm); + ~DreamWebSound(); + + bool loadSpeech(byte type1, int idx1, byte type2, int idx2); + void volumeSet(uint8 value) { _volume = value; } + void volumeChange(uint8 value, int8 direction); + void playChannel0(uint8 index, uint8 repeat); + void playChannel1(uint8 index); + uint8 getChannel0Playing() { return _channel0Playing; } + bool isChannel1Playing() { return _channel1Playing != 255; } + void cancelCh0(); + void cancelCh1(); + void loadRoomsSample(uint8 sample); + void soundHandler(); + void loadSounds(uint bank, const Common::String &suffix); + +private: + DreamWebEngine *_vm; + + struct Sample { + uint offset; + uint size; + Sample(): offset(), size() {} + }; + + struct SoundData { + Common::Array<Sample> samples; + Common::Array<uint8> data; + }; + + SoundData _soundData[2]; + Common::Array<uint8> _speechData; + + Audio::SoundHandle _channelHandle[2]; + + uint8 _currentSample; + uint8 _channel0Playing; + uint8 _channel0Repeat; + bool _channel0NewSound; + uint8 _channel1Playing; + bool _channel1NewSound; + + uint8 _volume; + uint8 _volumeTo; + int8 _volumeDirection; + uint8 _volumeCount; + + void volumeAdjust(); + void playSound(uint8 channel, uint8 id, uint8 loops); + void stopSound(uint8 channel); + bool loadSpeech(const Common::String &filename); +}; + +} // End of namespace DreamWeb + +#endif diff --git a/engines/dreamweb/sprite.cpp b/engines/dreamweb/sprite.cpp index 3df324abe1..5b6cf6a6ac 100644 --- a/engines/dreamweb/sprite.cpp +++ b/engines/dreamweb/sprite.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -298,7 +299,7 @@ void DreamWebEngine::doDoor(Sprite *sprite, SetObject *objData, Common::Rect che soundIndex = 13; else soundIndex = 0; - playChannel1(soundIndex); + _sound->playChannel1(soundIndex); } if (objData->frames[sprite->animFrame] == 255) --sprite->animFrame; @@ -315,7 +316,7 @@ void DreamWebEngine::doDoor(Sprite *sprite, SetObject *objData, Common::Rect che soundIndex = 13; else soundIndex = 1; - playChannel1(soundIndex); + _sound->playChannel1(soundIndex); } if (sprite->animFrame != 0) --sprite->animFrame; @@ -346,7 +347,7 @@ void DreamWebEngine::lockedDoorway(Sprite *sprite, SetObject *objData) { if (openDoor) { if (sprite->animFrame == 1) { - playChannel1(0); + _sound->playChannel1(0); } if (sprite->animFrame == 6) @@ -367,7 +368,7 @@ void DreamWebEngine::lockedDoorway(Sprite *sprite, SetObject *objData) { // shut door if (sprite->animFrame == 5) { - playChannel1(1); + _sound->playChannel1(1); } if (sprite->animFrame != 0) @@ -505,7 +506,7 @@ void DreamWebEngine::intro1Text() { if (_introCount != 2 && _introCount != 4 && _introCount != 6) return; - if (hasSpeech() && _channel1Playing != 255) { + if (hasSpeech() && _sound->isChannel1Playing()) { _introCount--; } else { if (_introCount == 2) @@ -578,7 +579,7 @@ void DreamWebEngine::textForEnd() { } void DreamWebEngine::textForMonkHelper(uint8 textIndex, uint8 voiceIndex, uint8 x, uint8 y, uint16 countToTimed, uint16 timeCount) { - if (hasSpeech() && _channel1Playing != 255) + if (hasSpeech() && _sound->isChannel1Playing()) _introCount--; else setupTimedTemp(textIndex, voiceIndex, x, y, countToTimed, timeCount); @@ -614,8 +615,7 @@ void DreamWebEngine::textForMonk() { else if (_introCount == 53) { fadeScreenDowns(); if (hasSpeech()) { - _volumeTo = 7; - _volumeDirection = 1; + _sound->volumeChange(7, 1); } } } @@ -905,14 +905,14 @@ void DreamWebEngine::soundOnReels(uint16 reelPointer) { continue; _lastSoundReel = r->_reelPointer; if (r->_sample < 64) { - playChannel1(r->_sample); + _sound->playChannel1(r->_sample); return; } if (r->_sample < 128) { - playChannel0(r->_sample & 63, 0); + _sound->playChannel0(r->_sample & 63, 0); return; } - playChannel0(r->_sample & 63, 255); + _sound->playChannel0(r->_sample & 63, 255); } if (_lastSoundReel != reelPointer) @@ -955,9 +955,9 @@ void DreamWebEngine::getRidOfReels() { void DreamWebEngine::liftNoise(uint8 index) { if (_realLocation == 5 || _realLocation == 21) - playChannel1(13); // hiss noise + _sound->playChannel1(13); // hiss noise else - playChannel1(index); + _sound->playChannel1(index); } void DreamWebEngine::checkForExit(Sprite *sprite) { diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp index 750dafe7b4..f235f7c2fd 100644 --- a/engines/dreamweb/stubs.cpp +++ b/engines/dreamweb/stubs.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" #include "common/config-manager.h" @@ -578,7 +579,7 @@ void DreamWebEngine::dreamweb() { readSetData(); _wonGame = false; - loadSounds(0, "V99"); // basic sample + _sound->loadSounds(0, "V99"); // basic sample bool firstLoop = true; @@ -654,7 +655,7 @@ void DreamWebEngine::dreamweb() { _vars._location = 255; _vars._roomAfterDream = 1; _newLocation = 35; - _volume = 7; + _sound->volumeSet(7); loadRoom(); clearSprites(); initMan(); @@ -664,8 +665,7 @@ void DreamWebEngine::dreamweb() { initialInv(); _lastFlag = 32; startup1(); - _volumeTo = 0; - _volumeDirection = -1; + _sound->volumeChange(0, -1); _commandType = 255; } @@ -754,7 +754,7 @@ void DreamWebEngine::screenUpdate() { showPointer(); if ((_vars._watchingTime == 0) && (_newLocation != 0xff)) return; - vSync(); + waitForVSync(); uint16 mouseState = 0; mouseState |= readMouseState(); dumpPointer(); @@ -769,7 +769,7 @@ void DreamWebEngine::screenUpdate() { showPointer(); if (_wonGame) return; - vSync(); + waitForVSync(); mouseState |= readMouseState(); dumpPointer(); @@ -781,7 +781,7 @@ void DreamWebEngine::screenUpdate() { afterNewRoom(); showPointer(); - vSync(); + waitForVSync(); mouseState |= readMouseState(); dumpPointer(); @@ -790,7 +790,7 @@ void DreamWebEngine::screenUpdate() { delPointer(); showPointer(); - vSync(); + waitForVSync(); _oldButton = _mouseButton; mouseState |= readMouseState(); _mouseButton = mouseState; @@ -871,7 +871,7 @@ void DreamWebEngine::loadTextSegment(TextFile &file, Common::File &inFile, unsig void DreamWebEngine::hangOnCurs(uint16 frameCount) { for (uint16 i = 0; i < frameCount; ++i) { printCurs(); - vSync(); + waitForVSync(); delCurs(); } } @@ -930,7 +930,7 @@ void DreamWebEngine::processTrigger() { void DreamWebEngine::useTimedText() { if (_previousTimedTemp._string) { // TODO: It might be nice to make subtitles wait for the speech - // to finish (_channel1Playing) when we're in speech+subtitles mode, + // to finish (_sound->isChannel1Playing()) when we're in speech+subtitles mode, // instead of waiting the pre-specified amount of time. @@ -967,9 +967,9 @@ void DreamWebEngine::useTimedText() { void DreamWebEngine::setupTimedTemp(uint8 textIndex, uint8 voiceIndex, uint8 x, uint8 y, uint16 countToTimed, uint16 timeCount) { if (hasSpeech() && voiceIndex != 0) { - if (loadSpeech('T', voiceIndex, 'T', textIndex)) { - playChannel1(50+12); - } + _speechLoaded = _sound->loadSpeech('T', voiceIndex, 'T', textIndex); + if (_speechLoaded) + _sound->playChannel1(62); if (_speechLoaded && !_subtitles) return; @@ -1634,7 +1634,7 @@ bool DreamWebEngine::checkIfSet(uint8 x, uint8 y) { void DreamWebEngine::hangOn(uint16 frameCount) { while (frameCount) { - vSync(); + waitForVSync(); --frameCount; if (_quitRequested) break; @@ -1647,7 +1647,7 @@ void DreamWebEngine::hangOnW(uint16 frameCount) { readMouse(); animPointer(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); --frameCount; if (_quitRequested) @@ -1665,7 +1665,7 @@ void DreamWebEngine::hangOnP(uint16 count) { readMouse(); animPointer(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); count *= 3; @@ -1674,7 +1674,7 @@ void DreamWebEngine::hangOnP(uint16 count) { readMouse(); animPointer(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); if (_quitRequested) break; @@ -1846,7 +1846,7 @@ void DreamWebEngine::loadRoom() { _vars._location = _newLocation; const Room &room = g_roomData[_newLocation]; startLoading(room); - loadRoomsSample(); + _sound->loadRoomsSample(_roomsSample); switchRyanOn(); drawFlags(); @@ -2132,7 +2132,7 @@ void DreamWebEngine::workToScreenM() { animPointer(); readMouse(); showPointer(); - vSync(); + waitForVSync(); workToScreen(); delPointer(); } @@ -2146,12 +2146,12 @@ void DreamWebEngine::atmospheres() { continue; if (a->_mapX != _mapX || a->_mapY != _mapY) continue; - if (a->_sound != _channel0Playing) { + if (a->_sound != _sound->getChannel0Playing()) { if (_vars._location == 45 && _vars._reelToWatch == 45) continue; // "web" - playChannel0(a->_sound, a->_repeat); + _sound->playChannel0(a->_sound, a->_repeat); // NB: The asm here reads // cmp reallocation,2 @@ -2161,21 +2161,21 @@ void DreamWebEngine::atmospheres() { // I'm interpreting this as if the cmp reallocation is below the jz if (_mapY == 0) { - _volume = 0; // "fullvol" + _sound->volumeSet(0); // "fullvol" return; } if (_realLocation == 2 && _mapX == 22 && _mapY == 10) - _volume = 5; // "louisvol" + _sound->volumeSet(5); // "louisvol" if (hasSpeech() && _realLocation == 14) { if (_mapX == 33) { - _volume = 0; // "ismad2" + _sound->volumeSet(0); // "ismad2" return; } if (_mapX == 22) { - _volume = 5; + _sound->volumeSet(5); return; } @@ -2184,19 +2184,19 @@ void DreamWebEngine::atmospheres() { if (_realLocation == 2) { if (_mapX == 22) { - _volume = 5; // "louisvol" + _sound->volumeSet(5); // "louisvol" return; } if (_mapX == 11) { - _volume = 0; // "fullvol" + _sound->volumeSet(0); // "fullvol" return; } } return; } - cancelCh0(); + _sound->cancelCh0(); } void DreamWebEngine::readKey() { @@ -2607,7 +2607,7 @@ void DreamWebEngine::decide() { readMouse(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); delPointer(); @@ -2642,8 +2642,8 @@ void DreamWebEngine::showGun() { _numToFade = 128; hangOn(200); _roomsSample = 34; - loadRoomsSample(); - _volume = 0; + _sound->loadRoomsSample(_roomsSample); + _sound->volumeSet(0); GraphicsFile graphics; loadGraphicsFile(graphics, "G13"); createPanel2(); @@ -2653,7 +2653,7 @@ void DreamWebEngine::showGun() { graphics.clear(); fadeScreenUp(); hangOn(160); - playChannel0(12, 0); + _sound->playChannel0(12, 0); loadTempText("T83"); rollEndCreditsGameLost(); getRidOfTempText(); @@ -2920,9 +2920,7 @@ void DreamWebEngine::setupInitialVars() { _vars._progressPoints = 0; _vars._watchOn = 0; _vars._shadesOn = 0; - _vars._secondCount = 0; - _vars._minuteCount = 30; - _vars._hourCount = 19; + getTime(); _vars._zoomOn = 1; _vars._location = 0; _vars._exPos = 0; diff --git a/engines/dreamweb/talk.cpp b/engines/dreamweb/talk.cpp index 0f59cad895..2629c23355 100644 --- a/engines/dreamweb/talk.cpp +++ b/engines/dreamweb/talk.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -52,7 +53,7 @@ void DreamWebEngine::talk() { readMouse(); animPointer(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); _getBack = 0; @@ -67,9 +68,8 @@ void DreamWebEngine::talk() { redrawMainScrn(); workToScreenM(); if (_speechLoaded) { - cancelCh1(); - _volumeDirection = -1; - _volumeTo = 0; + _sound->cancelCh1(); + _sound->volumeChange(0, -1); } } @@ -99,12 +99,10 @@ void DreamWebEngine::startTalk() { printDirect(&str, 66, &y, 241, true); if (hasSpeech()) { - _speechLoaded = false; - loadSpeech('R', _realLocation, 'C', 64*(_character & 0x7F)); + _speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', 64*(_character & 0x7F)); if (_speechLoaded) { - _volumeDirection = 1; - _volumeTo = 6; - playChannel1(50 + 12); + _sound->volumeChange(6, 1); + _sound->playChannel1(62); } } } @@ -155,9 +153,9 @@ void DreamWebEngine::doSomeTalk() { printDirect(str, 164, 64, 144, false); - loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos); + _speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos); if (_speechLoaded) - playChannel1(62); + _sound->playChannel1(62); _pointerMode = 3; workToScreenM(); @@ -181,9 +179,9 @@ void DreamWebEngine::doSomeTalk() { convIcons(); printDirect(str, 48, 128, 144, false); - loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos); + _speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos); if (_speechLoaded) - playChannel1(62); + _sound->playChannel1(62); _pointerMode = 3; workToScreenM(); @@ -211,7 +209,7 @@ bool DreamWebEngine::hangOnPQ() { readMouse(); animPointer(); showPointer(); - vSync(); + waitForVSync(); dumpPointer(); dumpTextLine(); checkCoords(quitList); @@ -220,11 +218,11 @@ bool DreamWebEngine::hangOnPQ() { // Quit conversation delPointer(); _pointerMode = 0; - cancelCh1(); + _sound->cancelCh1(); return true; } - if (_speechLoaded && _channel1Playing == 255) { + if (_speechLoaded && !_sound->isChannel1Playing()) { speechFlag++; if (speechFlag == 40) break; @@ -237,7 +235,7 @@ bool DreamWebEngine::hangOnPQ() { } void DreamWebEngine::redes() { - if (_channel1Playing != 255 || _talkMode != 2) { + if (_sound->isChannel1Playing() || _talkMode != 2) { blank(); return; } diff --git a/engines/dreamweb/titles.cpp b/engines/dreamweb/titles.cpp index f7486ce687..f005279ba0 100644 --- a/engines/dreamweb/titles.cpp +++ b/engines/dreamweb/titles.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" #include "engines/util.h" @@ -32,38 +33,36 @@ void DreamWebEngine::endGame() { return; gettingShot(); getRidOfTempText(); - _volumeTo = 7; - _volumeDirection = 1; + _sound->volumeChange(7, 1); hangOn(200); } void DreamWebEngine::monkSpeaking() { _roomsSample = 35; - loadRoomsSample(); + _sound->loadRoomsSample(_roomsSample); GraphicsFile graphics; loadGraphicsFile(graphics, "G15"); clearWork(); showFrame(graphics, 160, 72, 0, 128); // show monk workToScreen(); - _volume = 7; - _volumeDirection = -1; - _volumeTo = hasSpeech() ? 5 : 0; - playChannel0(12, 255); + _sound->volumeSet(7); + _sound->volumeChange(hasSpeech() ? 5 : 0, -1); + _sound->playChannel0(12, 255); fadeScreenUps(); hangOn(300); // TODO: Subtitles+speech mode if (hasSpeech()) { for (int i = 40; i < 48; i++) { - loadSpeech('T', 83, 'T', i); + _speechLoaded = _sound->loadSpeech('T', 83, 'T', i); - playChannel1(50 + 12); + _sound->playChannel1(62); do { waitForVSync(); if (_quitRequested) return; - } while (_channel1Playing != 255); + } while (_sound->isChannel1Playing()); } } else { for (int i = 40; i <= 44; i++) { @@ -83,8 +82,7 @@ void DreamWebEngine::monkSpeaking() { } } - _volumeDirection = 1; - _volumeTo = 7; + _sound->volumeChange(7, 1); fadeScreenDowns(); hangOn(300); graphics.clear(); @@ -95,8 +93,7 @@ void DreamWebEngine::gettingShot() { clearPalette(); loadIntroRoom(); fadeScreenUps(); - _volumeTo = 0; - _volumeDirection = -1; + _sound->volumeChange(0, -1); runEndSeq(); clearBeforeLoad(); } @@ -127,14 +124,14 @@ void DreamWebEngine::bibleQuote() { return; // "biblequotearly" } - cancelCh0(); + _sound->cancelCh0(); _lastHardKey = 0; } void DreamWebEngine::hangOne(uint16 delay) { do { - vSync(); + waitForVSync(); if (_lastHardKey == 1) return; // "hangonearly" } while (--delay); @@ -147,10 +144,9 @@ void DreamWebEngine::intro() { _newLocation = 50; clearPalette(); loadIntroRoom(); - _volume = 7; - _volumeDirection = -1; - _volumeTo = hasSpeech() ? 4 : 0; - playChannel0(12, 255); + _sound->volumeSet(7); + _sound->volumeChange(hasSpeech() ? 4 : 0, -1); + _sound->playChannel0(12, 255); fadeScreenUps(); runIntroSeq(); @@ -200,13 +196,13 @@ void DreamWebEngine::runIntroSeq() { _getBack = 0; do { - vSync(); + waitForVSync(); if (_lastHardKey == 1) break; spriteUpdate(); - vSync(); + waitForVSync(); if (_lastHardKey == 1) break; @@ -216,14 +212,14 @@ void DreamWebEngine::runIntroSeq() { reelsOnScreen(); afterIntroRoom(); useTimedText(); - vSync(); + waitForVSync(); if (_lastHardKey == 1) break; dumpMap(); dumpTimedText(); - vSync(); + waitForVSync(); if (_lastHardKey == 1) break; @@ -247,18 +243,18 @@ void DreamWebEngine::runEndSeq() { _getBack = 0; do { - vSync(); + waitForVSync(); spriteUpdate(); - vSync(); + waitForVSync(); delEverything(); printSprites(); reelsOnScreen(); afterIntroRoom(); useTimedText(); - vSync(); + waitForVSync(); dumpMap(); dumpTimedText(); - vSync(); + waitForVSync(); } while (_getBack != 1 && !_quitRequested); } @@ -286,14 +282,14 @@ void DreamWebEngine::set16ColPalette() { void DreamWebEngine::realCredits() { _roomsSample = 33; - loadRoomsSample(); - _volume = 0; + _sound->loadRoomsSample(_roomsSample); + _sound->volumeSet(0); initGraphics(640, 480, true); hangOn(35); showPCX("I01"); - playChannel0(12, 0); + _sound->playChannel0(12, 0); hangOne(2); @@ -319,7 +315,7 @@ void DreamWebEngine::realCredits() { } showPCX("I02"); - playChannel0(12, 0); + _sound->playChannel0(12, 0); hangOne(2); if (_lastHardKey == 1) { @@ -344,7 +340,7 @@ void DreamWebEngine::realCredits() { } showPCX("I03"); - playChannel0(12, 0); + _sound->playChannel0(12, 0); hangOne(2); if (_lastHardKey == 1) { @@ -369,7 +365,7 @@ void DreamWebEngine::realCredits() { } showPCX("I04"); - playChannel0(12, 0); + _sound->playChannel0(12, 0); hangOne(2); if (_lastHardKey == 1) { @@ -394,7 +390,7 @@ void DreamWebEngine::realCredits() { } showPCX("I05"); - playChannel0(12, 0); + _sound->playChannel0(12, 0); hangOne(2); if (_lastHardKey == 1) { @@ -427,7 +423,7 @@ void DreamWebEngine::realCredits() { return; // "realcreditsearly" } - playChannel0(13, 0); + _sound->playChannel0(13, 0); hangOne(350); if (_lastHardKey == 1) { diff --git a/engines/dreamweb/use.cpp b/engines/dreamweb/use.cpp index e59843539f..995eef04cd 100644 --- a/engines/dreamweb/use.cpp +++ b/engines/dreamweb/use.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -201,13 +202,13 @@ void DreamWebEngine::edensCDPlayer() { } void DreamWebEngine::hotelBell() { - playChannel1(12); + _sound->playChannel1(12); showFirstUse(); putBackObStuff(); } void DreamWebEngine::playGuitar() { - playChannel1(14); + _sound->playChannel1(14); showFirstUse(); putBackObStuff(); } @@ -273,13 +274,13 @@ void DreamWebEngine::useHatch() { } void DreamWebEngine::wheelSound() { - playChannel1(17); + _sound->playChannel1(17); showFirstUse(); putBackObStuff(); } void DreamWebEngine::callHotelLift() { - playChannel1(12); + _sound->playChannel1(12); showFirstUse(); _vars._countToOpen = 8; _getBack = 1; @@ -382,7 +383,7 @@ void DreamWebEngine::sitDownInBar() { } void DreamWebEngine::useDryer() { - playChannel1(12); + _sound->playChannel1(12); showFirstUse(); _getBack = 1; } @@ -887,7 +888,7 @@ void DreamWebEngine::usePlate() { if (compare(_withObject, _withType, "SCRW")) { // Unscrew plate - playChannel1(20); + _sound->playChannel1(20); showFirstUse(); placeSetObject(28); placeSetObject(24); @@ -992,7 +993,7 @@ void DreamWebEngine::useCart() { removeSetObject(_command); placeSetObject(_command + 1); _vars._progressPoints++; - playChannel1(17); + _sound->playChannel1(17); showFirstUse(); _getBack = 1; } @@ -1035,7 +1036,7 @@ void DreamWebEngine::openHotelDoor() { if (defaultUseHandler("KEYA")) return; - playChannel1(16); + _sound->playChannel1(16); showFirstUse(); _vars._lockStatus = 0; _getBack = 1; @@ -1045,7 +1046,7 @@ void DreamWebEngine::openHotelDoor2() { if (defaultUseHandler("KEYA")) return; - playChannel1(16); + _sound->playChannel1(16); showFirstUse(); putBackObStuff(); } @@ -1067,7 +1068,7 @@ void DreamWebEngine::usePoolReader() { showSecondUse(); putBackObStuff(); } else { - playChannel1(17); + _sound->playChannel1(17); showFirstUse(); _vars._countToOpen = 6; _getBack = 1; @@ -1088,7 +1089,7 @@ void DreamWebEngine::useCardReader1() { putBackObStuff(); } else { // Get cash - playChannel1(16); + _sound->playChannel1(16); showPuzText(18, 300); _vars._progressPoints++; _vars._card1Money = 12432; @@ -1113,7 +1114,7 @@ void DreamWebEngine::useCardReader2() { showPuzText(22, 300); putBackObStuff(); } else { - playChannel1(18); + _sound->playChannel1(18); showPuzText(19, 300); placeSetObject(94); _vars._gunPassFlag = 1; @@ -1136,7 +1137,7 @@ void DreamWebEngine::useCardReader3() { showPuzText(26, 300); putBackObStuff(); } else { - playChannel1(16); + _sound->playChannel1(16); showPuzText(25, 300); _vars._progressPoints++; _vars._card1Money -= 8300; @@ -1232,7 +1233,7 @@ void DreamWebEngine::useControl() { } if (compare(_withObject, _withType, "KEYA")) { // Right key - playChannel1(16); + _sound->playChannel1(16); if (_vars._location == 21) { // Going down showPuzText(3, 300); _newLocation = 30; @@ -1257,7 +1258,7 @@ void DreamWebEngine::useControl() { placeSetObject(30); removeSetObject(16); removeSetObject(17); - playChannel1(14); + _sound->playChannel1(14); showPuzText(10, 300); _vars._progressPoints++; _getBack = 1; @@ -1375,7 +1376,7 @@ void DreamWebEngine::runTap() { // Fill cup from tap DynObject *exObject = getExAd(_withObject); exObject->objId[3] = 'F'-'A'; // CUPE (empty cup) -> CUPF (full cup) - playChannel1(8); + _sound->playChannel1(8); showPuzText(57, 300); putBackObStuff(); return; diff --git a/engines/dreamweb/vgafades.cpp b/engines/dreamweb/vgafades.cpp index e8999ab18c..c8f05641b5 100644 --- a/engines/dreamweb/vgafades.cpp +++ b/engines/dreamweb/vgafades.cpp @@ -20,6 +20,7 @@ * */ +#include "dreamweb/sound.h" #include "dreamweb/dreamweb.h" namespace DreamWeb { @@ -52,7 +53,7 @@ void DreamWebEngine::fadeDOS() { return; // FIXME later waitForVSync(); - //processEvents will be called from vsync + //processEvents will be called from waitForVSync uint8 *dst = _startPal; getPalette(dst, 0, 64); for (int fade = 0; fade < 64; ++fade) { @@ -123,7 +124,7 @@ void DreamWebEngine::fadeUpMonFirst() { _colourPos = 0; _numToFade = 128; hangOn(64); - playChannel1(26); + _sound->playChannel1(26); hangOn(64); } diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp index a66f156a1d..ec306c4924 100644 --- a/engines/dreamweb/vgagrafx.cpp +++ b/engines/dreamweb/vgagrafx.cpp @@ -144,10 +144,6 @@ void DreamWebEngine::doShake() { setShakePos(offset >= 0 ? offset : -offset); } -void DreamWebEngine::vSync() { - waitForVSync(); -} - void DreamWebEngine::setMode() { waitForVSync(); initGraphics(320, 200, false); diff --git a/engines/gob/anifile.cpp b/engines/gob/anifile.cpp index 2671fe0405..085ac800cd 100644 --- a/engines/gob/anifile.cpp +++ b/engines/gob/anifile.cpp @@ -37,30 +37,38 @@ ANIFile::ANIFile(GobEngine *vm, const Common::String &fileName, uint16 width, uint8 bpp) : _vm(vm), _width(width), _bpp(bpp), _hasPadding(false) { - Common::SeekableReadStream *ani = _vm->_dataIO->getFile(fileName); - if (ani) { - Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), false, DisposeAfterUse::YES); + bool bigEndian = false; + Common::String endianFileName = fileName; - load(sub, fileName); - return; - } + if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) && + !_vm->_dataIO->hasFile(fileName)) { + // If the game has alternate big-endian files, look if one exist - // File doesn't exist, try to open the big-endian'd alternate file - Common::String alternateFileName = fileName; - alternateFileName.setChar('_', 0); + Common::String alternateFileName = fileName; + alternateFileName.setChar('_', 0); - ani = _vm->_dataIO->getFile(alternateFileName); + if (_vm->_dataIO->hasFile(alternateFileName)) { + bigEndian = true; + endianFileName = alternateFileName; + } + } else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) || + ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) && + (_vm->getEndianness() == kEndiannessBE))) + // Game always little endian or it follows the system and it is big endian + bigEndian = true; + + Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName); if (ani) { - Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), true, DisposeAfterUse::YES); + Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES); // The big endian version pads a few fields to even size - _hasPadding = true; + _hasPadding = bigEndian; load(sub, fileName); return; } - warning("ANIFile::ANIFile(): No such file \"%s\"", fileName.c_str()); + warning("ANIFile::ANIFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str()); } ANIFile::~ANIFile() { @@ -281,4 +289,9 @@ void ANIFile::drawLayer(Surface &dest, uint16 layer, uint16 part, _layers[layer]->draw(dest, part, x, y, transp); } +void ANIFile::recolor(uint8 from, uint8 to) { + for (LayerArray::iterator l = _layers.begin(); l != _layers.end(); ++l) + (*l)->recolor(from, to); +} + } // End of namespace Gob diff --git a/engines/gob/anifile.h b/engines/gob/anifile.h index b6d9c735b5..c930aafc6b 100644 --- a/engines/gob/anifile.h +++ b/engines/gob/anifile.h @@ -92,6 +92,9 @@ public: /** Draw an animation frame. */ void draw(Surface &dest, uint16 animation, uint16 frame, int16 x, int16 y) const; + /** Recolor the animation sprites. */ + void recolor(uint8 from, uint8 to); + private: typedef Common::Array<CMPFile *> LayerArray; typedef Common::Array<Animation> AnimationArray; diff --git a/engines/gob/aniobject.cpp b/engines/gob/aniobject.cpp index 154f8e04ed..7e3668a0ce 100644 --- a/engines/gob/aniobject.cpp +++ b/engines/gob/aniobject.cpp @@ -28,23 +28,20 @@ namespace Gob { ANIObject::ANIObject(const ANIFile &ani) : _ani(&ani), _cmp(0), - _visible(false), _paused(false), _mode(kModeContinuous), - _x(0), _y(0), _background(0), _drawn(false) { + _visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) { setAnimation(0); setPosition(); } ANIObject::ANIObject(const CMPFile &cmp) : _ani(0), _cmp(&cmp), - _visible(false), _paused(false), _mode(kModeContinuous), - _x(0), _y(0), _background(0), _drawn(false) { + _visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) { setAnimation(0); setPosition(); } ANIObject::~ANIObject() { - delete _background; } void ANIObject::setVisible(bool visible) { @@ -76,6 +73,10 @@ void ANIObject::rewind() { _frame = 0; } +void ANIObject::setFrame(uint16 frame) { + _frame = frame % _ani->getAnimationInfo(_animation).frameCount; +} + void ANIObject::setPosition() { // CMP "animations" have no default position if (_cmp) @@ -100,7 +101,7 @@ void ANIObject::getPosition(int16 &x, int16 &y) const { y = _y; } -void ANIObject::getFramePosition(int16 &x, int16 &y) const { +void ANIObject::getFramePosition(int16 &x, int16 &y, uint16 n) const { // CMP "animations" have no specific frame positions if (_cmp) { getPosition(x, y); @@ -114,11 +115,24 @@ void ANIObject::getFramePosition(int16 &x, int16 &y) const { if (_frame >= animation.frameCount) return; - x = _x + animation.frameAreas[_frame].left; - y = _y + animation.frameAreas[_frame].top; + // If we're paused, we don't advance any frames + if (_paused) + n = 0; + + // Number of cycles run through after n frames + uint16 cycles = (_frame + n) / animation.frameCount; + // Frame position after n frames + uint16 frame = (_frame + n) % animation.frameCount; + + // Only doing one cycle? + if (_mode == kModeOnce) + cycles = MAX<uint16>(cycles, 1); + + x = _x + animation.frameAreas[frame].left + cycles * animation.deltaX; + y = _y + animation.frameAreas[frame].top + cycles * animation.deltaY; } -void ANIObject::getFrameSize(int16 &width, int16 &height) const { +void ANIObject::getFrameSize(int16 &width, int16 &height, uint16 n) const { if (_cmp) { width = _cmp->getWidth (_animation); height = _cmp->getHeight(_animation); @@ -133,8 +147,15 @@ void ANIObject::getFrameSize(int16 &width, int16 &height) const { if (_frame >= animation.frameCount) return; - width = animation.frameAreas[_frame].right - animation.frameAreas[_frame].left + 1; - height = animation.frameAreas[_frame].bottom - animation.frameAreas[_frame].top + 1; + // If we're paused, we don't advance any frames + if (_paused) + n = 0; + + // Frame position after n frames + uint16 frame = (_frame + n) % animation.frameCount; + + width = animation.frameAreas[frame].right - animation.frameAreas[frame].left + 1; + height = animation.frameAreas[frame].bottom - animation.frameAreas[frame].top + 1; } bool ANIObject::isIn(int16 x, int16 y) const { @@ -167,102 +188,78 @@ bool ANIObject::isIn(const ANIObject &obj) const { obj.isIn(frameX + frameWidth - 1, frameY + frameHeight - 1); } -void ANIObject::draw(Surface &dest, int16 &left, int16 &top, +bool ANIObject::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { if (!_visible) - return; + return false; if (_cmp) - drawCMP(dest, left, top, right, bottom); + return drawCMP(dest, left, top, right, bottom); else if (_ani) - drawANI(dest, left, top, right, bottom); + return drawANI(dest, left, top, right, bottom); + + return false; } -void ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top, +bool ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { - if (!_background) { + if (!hasBuffer()) { uint16 width, height; _cmp->getMaxSize(width, height); - _background = new Surface(width, height, dest.getBPP()); + resizeBuffer(width, height); } - const uint16 cR = _cmp->getWidth (_animation) - 1; - const uint16 cB = _cmp->getHeight(_animation) - 1; - - _backgroundLeft = CLIP<int16>( + _x, 0, dest.getWidth () - 1); - _backgroundTop = CLIP<int16>( + _y, 0, dest.getHeight() - 1); - _backgroundRight = CLIP<int16>(cR + _x, 0, dest.getWidth () - 1); - _backgroundBottom = CLIP<int16>(cB + _y, 0, dest.getHeight() - 1); + left = _x; + top = _y; + right = _x + _cmp->getWidth (_animation) - 1; + bottom = _y + _cmp->getHeight(_animation) - 1; - _background->blit(dest, _backgroundLeft , _backgroundTop, - _backgroundRight, _backgroundBottom, 0, 0); + if (!saveScreen(dest, left, top, right, bottom)) + return false; _cmp->draw(dest, _animation, _x, _y, 0); - _drawn = true; - - left = _backgroundLeft; - top = _backgroundTop; - right = _backgroundRight; - bottom = _backgroundBottom; + return true; } -void ANIObject::drawANI(Surface &dest, int16 &left, int16 &top, +bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { - if (!_background) { + if (!hasBuffer()) { uint16 width, height; _ani->getMaxSize(width, height); - _background = new Surface(width, height, dest.getBPP()); + resizeBuffer(width, height); } const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation); if (_frame >= animation.frameCount) - return; + return false; const ANIFile::FrameArea &area = animation.frameAreas[_frame]; - _backgroundLeft = CLIP<int16>(area.left + _x, 0, dest.getWidth () - 1); - _backgroundTop = CLIP<int16>(area.top + _y, 0, dest.getHeight() - 1); - _backgroundRight = CLIP<int16>(area.right + _x, 0, dest.getWidth () - 1); - _backgroundBottom = CLIP<int16>(area.bottom + _y, 0, dest.getHeight() - 1); + left = _x + area.left; + top = _y + area.top; + right = _x + area.right; + bottom = _y + area.bottom; - _background->blit(dest, _backgroundLeft , _backgroundTop, - _backgroundRight, _backgroundBottom, 0, 0); + if (!saveScreen(dest, left, top, right, bottom)) + return false; _ani->draw(dest, _animation, _frame, _x, _y); - _drawn = true; - - left = _backgroundLeft; - top = _backgroundTop; - right = _backgroundRight; - bottom = _backgroundBottom; + return true; } -void ANIObject::clear(Surface &dest, int16 &left, int16 &top, +bool ANIObject::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { - if (!_drawn) - return; - - const int16 bgRight = _backgroundRight - _backgroundLeft; - const int16 bgBottom = _backgroundBottom - _backgroundTop; - - dest.blit(*_background, 0, 0, bgRight, bgBottom, _backgroundLeft, _backgroundTop); - - _drawn = false; - - left = _backgroundLeft; - top = _backgroundTop; - right = _backgroundRight; - bottom = _backgroundBottom; + return restoreScreen(dest, left, top, right, bottom); } void ANIObject::advance() { diff --git a/engines/gob/aniobject.h b/engines/gob/aniobject.h index c101d747b7..d8c8edc2b8 100644 --- a/engines/gob/aniobject.h +++ b/engines/gob/aniobject.h @@ -25,6 +25,8 @@ #include "common/system.h" +#include "gob/backbuffer.h" + namespace Gob { class ANIFile; @@ -32,7 +34,7 @@ class CMPFile; class Surface; /** An ANI object, controlling an animation within an ANI file. */ -class ANIObject { +class ANIObject : public BackBuffer { public: enum Mode { kModeContinuous, ///< Play the animation continuously. @@ -61,17 +63,17 @@ public: void setMode(Mode mode); /** Set the current position to the animation's default. */ - void setPosition(); + virtual void setPosition(); /** Set the current position. */ - void setPosition(int16 x, int16 y); + virtual void setPosition(int16 x, int16 y); /** Return the current position. */ void getPosition(int16 &x, int16 &y) const; - /** Return the current frame position. */ - void getFramePosition(int16 &x, int16 &y) const; - /** Return the current frame size. */ - void getFrameSize(int16 &width, int16 &height) const; + /** Return the frame position after another n frames. */ + void getFramePosition(int16 &x, int16 &y, uint16 n = 0) const; + /** Return the current frame size after another n frames. */ + void getFrameSize(int16 &width, int16 &height, uint16 n = 0) const; /** Are there coordinates within the animation sprite? */ bool isIn(int16 x, int16 y) const; @@ -84,6 +86,9 @@ public: /** Rewind the current animation to the first frame. */ void rewind(); + /** Set the animation to a specific frame. */ + void setFrame(uint16 frame); + /** Return the current animation number. */ uint16 getAnimation() const; /** Return the current frame number. */ @@ -93,9 +98,9 @@ public: bool lastFrame() const; /** Draw the current frame onto the surface and return the affected rectangle. */ - void draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + virtual bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); /** Draw the current frame from the surface and return the affected rectangle. */ - void clear(Surface &dest, int16 &left , int16 &top, int16 &right, int16 &bottom); + virtual bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); /** Advance the animation to the next frame. */ virtual void advance(); @@ -115,16 +120,9 @@ private: int16 _x; ///< The current X position. int16 _y; ///< The current Y position. - Surface *_background; ///< The saved background. - bool _drawn; ///< Was the animation drawn? - - int16 _backgroundLeft; ///< The left position of the saved background. - int16 _backgroundTop; ///< The top of the saved background. - int16 _backgroundRight; ///< The right position of the saved background. - int16 _backgroundBottom; ///< The bottom position of the saved background. - void drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); - void drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + bool drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + bool drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); }; } // End of namespace Gob diff --git a/engines/gob/backbuffer.cpp b/engines/gob/backbuffer.cpp new file mode 100644 index 0000000000..752042d46e --- /dev/null +++ b/engines/gob/backbuffer.cpp @@ -0,0 +1,100 @@ +/* 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 "common/util.h" + +#include "gob/backbuffer.h" +#include "gob/surface.h" + +namespace Gob { + +BackBuffer::BackBuffer() : _background(0), _saved(false) { +} + +BackBuffer::~BackBuffer() { + delete _background; +} + +bool BackBuffer::hasBuffer() const { + return _background != 0; +} + +bool BackBuffer::hasSavedBackground() const { + return _saved; +} + +void BackBuffer::trashBuffer() { + _saved = false; +} + +void BackBuffer::resizeBuffer(uint16 width, uint16 height) { + trashBuffer(); + + if (_background && (_background->getWidth() == width) && (_background->getHeight() == height)) + return; + + delete _background; + + _background = new Surface(width, height, 1); +} + +bool BackBuffer::saveScreen(const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + if (!_background) + return false; + + const int16 width = MIN<int16>(right - left + 1, _background->getWidth ()); + const int16 height = MIN<int16>(bottom - top + 1, _background->getHeight()); + if ((width <= 0) || (height <= 0)) + return false; + + right = left + width - 1; + bottom = top + height - 1; + + _saveLeft = left; + _saveTop = top; + _saveRight = right; + _saveBottom = bottom; + + _background->blit(dest, _saveLeft, _saveTop, _saveRight, _saveBottom, 0, 0); + + _saved = true; + + return true; +} + +bool BackBuffer::restoreScreen(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + if (!_saved) + return false; + + left = _saveLeft; + top = _saveTop; + right = _saveRight; + bottom = _saveBottom; + + dest.blit(*_background, 0, 0, right - left, bottom - top, left, top); + + _saved = false; + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/backbuffer.h b/engines/gob/backbuffer.h new file mode 100644 index 0000000000..c978689e9f --- /dev/null +++ b/engines/gob/backbuffer.h @@ -0,0 +1,59 @@ +/* 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 GOB_BACKBUFFER_H +#define GOB_BACKBUFFER_H + +#include "common/system.h" + +namespace Gob { + +class Surface; + +class BackBuffer { +public: + BackBuffer(); + ~BackBuffer(); + +protected: + void trashBuffer(); + void resizeBuffer(uint16 width, uint16 height); + + bool saveScreen (const Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + bool restoreScreen( Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + + bool hasBuffer() const; + bool hasSavedBackground() const; + +private: + Surface *_background; ///< The saved background. + bool _saved; ///< Was the background saved? + + int16 _saveLeft; ///< The left position of the saved background. + int16 _saveTop; ///< The top of the saved background. + int16 _saveRight; ///< The right position of the saved background. + int16 _saveBottom; ///< The bottom position of the saved background. +}; + +} // End of namespace Gob + +#endif // GOB_BACKBUFFER_H diff --git a/engines/gob/cheater.h b/engines/gob/cheater.h index 334a5e88eb..bf6c1372fb 100644 --- a/engines/gob/cheater.h +++ b/engines/gob/cheater.h @@ -31,6 +31,7 @@ namespace Gob { namespace Geisha { class Diving; + class Penetration; } class GobEngine; @@ -48,13 +49,14 @@ protected: class Cheater_Geisha : public Cheater { public: - Cheater_Geisha(GobEngine *vm, Geisha::Diving *diving); + Cheater_Geisha(GobEngine *vm, Geisha::Diving *diving, Geisha::Penetration *penetration); ~Cheater_Geisha(); bool cheat(GUI::Debugger &console); private: - Geisha::Diving *_diving; + Geisha::Diving *_diving; + Geisha::Penetration *_penetration; }; } // End of namespace Gob diff --git a/engines/gob/cheater_geisha.cpp b/engines/gob/cheater_geisha.cpp index 3d8c56707d..567333c12f 100644 --- a/engines/gob/cheater_geisha.cpp +++ b/engines/gob/cheater_geisha.cpp @@ -27,11 +27,12 @@ #include "gob/inter.h" #include "gob/minigames/geisha/diving.h" +#include "gob/minigames/geisha/penetration.h" namespace Gob { -Cheater_Geisha::Cheater_Geisha(GobEngine *vm, Geisha::Diving *diving) : - Cheater(vm), _diving(diving) { +Cheater_Geisha::Cheater_Geisha(GobEngine *vm, Geisha::Diving *diving, Geisha::Penetration *penetration) : + Cheater(vm), _diving(diving), _penetration(penetration) { } @@ -45,6 +46,12 @@ bool Cheater_Geisha::cheat(GUI::Debugger &console) { return false; } + // A cheat to get around the Penetration minigame + if (_penetration->isPlaying()) { + _penetration->cheatWin(); + return false; + } + // A cheat to get around the mastermind puzzle if (_vm->isCurrentTot("hard.tot") && _vm->_inter->_variables) { uint32 digit1 = READ_VARO_UINT32(0x768); diff --git a/engines/gob/cmpfile.cpp b/engines/gob/cmpfile.cpp index 7b21c4c835..d304958f76 100644 --- a/engines/gob/cmpfile.cpp +++ b/engines/gob/cmpfile.cpp @@ -21,6 +21,7 @@ */ #include "common/stream.h" +#include "common/substream.h" #include "common/str.h" #include "gob/gob.h" @@ -143,7 +144,13 @@ void CMPFile::loadCMP(Common::SeekableReadStream &cmp) { } void CMPFile::loadRXY(Common::SeekableReadStream &rxy) { - _coordinates = new RXYFile(rxy); + bool bigEndian = (_vm->getEndiannessMethod() == kEndiannessMethodBE) || + ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) && + (_vm->getEndianness() == kEndiannessBE)); + + Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), bigEndian, DisposeAfterUse::NO); + + _coordinates = new RXYFile(sub); for (uint i = 0; i < _coordinates->size(); i++) { const RXYFile::Coordinates &c = (*_coordinates)[i]; @@ -243,4 +250,9 @@ uint16 CMPFile::addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom) return _coordinates->add(left, top, right, bottom); } +void CMPFile::recolor(uint8 from, uint8 to) { + if (_surface) + _surface->recolor(from, to); +} + } // End of namespace Gob diff --git a/engines/gob/cmpfile.h b/engines/gob/cmpfile.h index 2b669e4d38..9c858238af 100644 --- a/engines/gob/cmpfile.h +++ b/engines/gob/cmpfile.h @@ -70,6 +70,8 @@ public: uint16 addSprite(uint16 left, uint16 top, uint16 right, uint16 bottom); + void recolor(uint8 from, uint8 to); + private: GobEngine *_vm; diff --git a/engines/gob/decfile.cpp b/engines/gob/decfile.cpp index fb67c52627..85b4c09ca3 100644 --- a/engines/gob/decfile.cpp +++ b/engines/gob/decfile.cpp @@ -38,30 +38,38 @@ DECFile::DECFile(GobEngine *vm, const Common::String &fileName, uint16 width, uint16 height, uint8 bpp) : _vm(vm), _width(width), _height(height), _bpp(bpp), _hasPadding(false), _backdrop(0) { - Common::SeekableReadStream *dec = _vm->_dataIO->getFile(fileName); - if (dec) { - Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), false, DisposeAfterUse::YES); - - load(sub, fileName); - return; - } - - // File doesn't exist, try to open the big-endian'd alternate file - Common::String alternateFileName = fileName; - alternateFileName.setChar('_', 0); - - dec = _vm->_dataIO->getFile(alternateFileName); - if (dec) { - Common::SeekableSubReadStreamEndian sub(dec, 0, dec->size(), true, DisposeAfterUse::YES); + bool bigEndian = false; + Common::String endianFileName = fileName; + + if ((_vm->getEndiannessMethod() == kEndiannessMethodAltFile) && + !_vm->_dataIO->hasFile(fileName)) { + // If the game has alternate big-endian files, look if one exist + + Common::String alternateFileName = fileName; + alternateFileName.setChar('_', 0); + + if (_vm->_dataIO->hasFile(alternateFileName)) { + bigEndian = true; + endianFileName = alternateFileName; + } + } else if ((_vm->getEndiannessMethod() == kEndiannessMethodBE) || + ((_vm->getEndiannessMethod() == kEndiannessMethodSystem) && + (_vm->getEndianness() == kEndiannessBE))) + // Game always little endian or it follows the system and it is big endian + bigEndian = true; + + Common::SeekableReadStream *ani = _vm->_dataIO->getFile(endianFileName); + if (ani) { + Common::SeekableSubReadStreamEndian sub(ani, 0, ani->size(), bigEndian, DisposeAfterUse::YES); // The big endian version pads a few fields to even size - _hasPadding = true; + _hasPadding = bigEndian; load(sub, fileName); return; } - warning("DECFile::DECFile(): No such file \"%s\"", fileName.c_str()); + warning("DECFile::DECFile(): No such file \"%s\" (\"%s\")", endianFileName.c_str(), fileName.c_str()); } DECFile::~DECFile() { diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp new file mode 100644 index 0000000000..8fb0052a5b --- /dev/null +++ b/engines/gob/detection/detection.cpp @@ -0,0 +1,220 @@ +/* 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 "base/plugins.h" +#include "engines/advancedDetector.h" +#include "engines/obsolete.h" + +#include "gob/gob.h" +#include "gob/dataio.h" + +#include "gob/detection/tables.h" + +class GobMetaEngine : public AdvancedMetaEngine { +public: + GobMetaEngine(); + + virtual GameDescriptor findGame(const char *gameid) const; + + virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const; + + virtual const char *getName() const; + virtual const char *getOriginalCopyright() const; + + virtual bool hasFeature(MetaEngineFeature f) const; + + virtual Common::Error createInstance(OSystem *syst, Engine **engine) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + +private: + /** + * Inspect the game archives to detect which Once Upon A Time game this is. + */ + static const Gob::GOBGameDescription *detectOnceUponATime(const Common::FSList &fslist); +}; + +GobMetaEngine::GobMetaEngine() : + AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) { + + _singleid = "gob"; + _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); +} + +GameDescriptor GobMetaEngine::findGame(const char *gameid) const { + return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); +} + +const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { + ADFilePropertiesMap filesProps; + + const Gob::GOBGameDescription *game; + game = (const Gob::GOBGameDescription *)detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps); + if (!game) + return 0; + + if (game->gameType == Gob::kGameTypeOnceUponATime) { + game = detectOnceUponATime(fslist); + if (!game) + return 0; + } + + reportUnknown(fslist.begin()->getParent(), filesProps); + return (const ADGameDescription *)game; +} + +const Gob::GOBGameDescription *GobMetaEngine::detectOnceUponATime(const Common::FSList &fslist) { + // Add the game path to the search manager + SearchMan.clear(); + SearchMan.addDirectory(fslist.begin()->getParent().getPath(), fslist.begin()->getParent()); + + // Open the archives + Gob::DataIO dataIO; + if (!dataIO.openArchive("stk1.stk", true) || + !dataIO.openArchive("stk2.stk", true) || + !dataIO.openArchive("stk3.stk", true)) { + + SearchMan.clear(); + return 0; + } + + Gob::OnceUponATime gameType = Gob::kOnceUponATimeInvalid; + Gob::OnceUponATimePlatform platform = Gob::kOnceUponATimePlatformInvalid; + + // If these animal files are present, it's Abracadabra + if (dataIO.hasFile("arai.anm") && + dataIO.hasFile("crab.anm") && + dataIO.hasFile("crap.anm") && + dataIO.hasFile("drag.anm") && + dataIO.hasFile("guep.anm") && + dataIO.hasFile("loup.anm") && + dataIO.hasFile("mous.anm") && + dataIO.hasFile("rhin.anm") && + dataIO.hasFile("saut.anm") && + dataIO.hasFile("scor.anm")) + gameType = Gob::kOnceUponATimeAbracadabra; + + // If these animal files are present, it's Baba Yaga + if (dataIO.hasFile("abei.anm") && + dataIO.hasFile("arai.anm") && + dataIO.hasFile("drag.anm") && + dataIO.hasFile("fauc.anm") && + dataIO.hasFile("gren.anm") && + dataIO.hasFile("rena.anm") && + dataIO.hasFile("sang.anm") && + dataIO.hasFile("serp.anm") && + dataIO.hasFile("tort.anm") && + dataIO.hasFile("vaut.anm")) + gameType = Gob::kOnceUponATimeBabaYaga; + + // Detect the platform by endianness and existence of a MOD file + Common::SeekableReadStream *villeDEC = dataIO.getFile("ville.dec"); + if (villeDEC && (villeDEC->size() > 6)) { + byte data[6]; + + if (villeDEC->read(data, 6) == 6) { + if (!memcmp(data, "\000\000\000\001\000\007", 6)) { + // Big endian -> Amiga or Atari ST + + if (dataIO.hasFile("mod.babayaga")) + platform = Gob::kOnceUponATimePlatformAmiga; + else + platform = Gob::kOnceUponATimePlatformAtariST; + + } else if (!memcmp(data, "\000\000\001\000\007\000", 6)) + // Little endian -> DOS + platform = Gob::kOnceUponATimePlatformDOS; + } + + delete villeDEC; + } + + SearchMan.clear(); + + if ((gameType == Gob::kOnceUponATimeInvalid) || (platform == Gob::kOnceUponATimePlatformInvalid)) { + warning("GobMetaEngine::detectOnceUponATime(): Detection failed (%d, %d)", + (int) gameType, (int) platform); + return 0; + } + + return &Gob::fallbackOnceUpon[gameType][platform]; +} + +const char *GobMetaEngine::getName() const { + return "Gob"; +} + +const char *GobMetaEngine::getOriginalCopyright() const { + return "Goblins Games (C) Coktel Vision"; +} + +bool GobMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Gob::GobEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL); +} + +Common::Error GobMetaEngine::createInstance(OSystem *syst, Engine **engine) const { + Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable); + return AdvancedMetaEngine::createInstance(syst, engine); +} + +bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc; + if (gd) { + *engine = new Gob::GobEngine(syst); + ((Gob::GobEngine *)*engine)->initGame(gd); + } + return gd != 0; +} + + +#if PLUGIN_ENABLED_DYNAMIC(GOB) + REGISTER_PLUGIN_DYNAMIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine); +#else + REGISTER_PLUGIN_STATIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine); +#endif + +namespace Gob { + +void GobEngine::initGame(const GOBGameDescription *gd) { + if (gd->startTotBase == 0) + _startTot = "intro.tot"; + else + _startTot = gd->startTotBase; + + if (gd->startStkBase == 0) + _startStk = "intro.stk"; + else + _startStk = gd->startStkBase; + + _demoIndex = gd->demoIndex; + + _gameType = gd->gameType; + _features = gd->features; + _language = gd->desc.language; + _platform = gd->desc.platform; +} + +} // End of namespace Gob diff --git a/engines/gob/detection.cpp b/engines/gob/detection/tables.h index 17a2ae3da8..271f75af79 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection/tables.h @@ -20,11 +20,8 @@ * */ -#include "base/plugins.h" -#include "engines/advancedDetector.h" -#include "engines/obsolete.h" - -#include "gob/gob.h" +#ifndef GOB_DETECTION_TABLES_H +#define GOB_DETECTION_TABLES_H namespace Gob { @@ -42,6 +39,7 @@ struct GOBGameDescription { using namespace Common; +// Game IDs and proper names static const PlainGameDescriptor gobGames[] = { {"gob", "Gob engine game"}, {"gob1", "Gobliiins"}, @@ -50,8 +48,11 @@ static const PlainGameDescriptor gobGames[] = { {"gob2cd", "Gobliins 2 CD"}, {"ween", "Ween: The Prophecy"}, {"bargon", "Bargon Attack"}, - {"littlered", "Little Red Riding Hood"}, - {"ajworld", "A.J's World of Discovery"}, + {"babayaga", "Once Upon A Time: Baba Yaga"}, + {"abracadabra", "Once Upon A Time: Abracadabra"}, + {"littlered", "Once Upon A Time: Little Red Riding Hood"}, + {"onceupon", "Once Upon A Time"}, + {"ajworld", "A.J.'s World of Discovery"}, {"gob3", "Goblins Quest 3"}, {"gob3cd", "Goblins Quest 3 CD"}, {"lit1", "Lost in Time Part 1"}, @@ -79,87 +80,42 @@ static const PlainGameDescriptor gobGames[] = { {0, 0} }; +// Obsolete IDs we don't want anymore static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = { {"gob1", "gob", kPlatformUnknown}, {"gob2", "gob", kPlatformUnknown}, {0, 0, kPlatformUnknown} }; -#include "gob/detection_tables.h" - -class GobMetaEngine : public AdvancedMetaEngine { -public: - GobMetaEngine() : AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) { - _singleid = "gob"; - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); - } - - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); - } - - virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { - return detectGameFilebased(allFiles, Gob::fileBased); - } - - virtual const char *getName() const { - return "Gob"; - } - - virtual const char *getOriginalCopyright() const { - return "Goblins Games (C) Coktel Vision"; - } - - virtual bool hasFeature(MetaEngineFeature f) const; +namespace Gob { - virtual Common::Error createInstance(OSystem *syst, Engine **engine) const { - Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable); - return AdvancedMetaEngine::createInstance(syst, engine); - } - virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +// Detection tables +static const GOBGameDescription gameDescriptions[] = { + #include "gob/detection/tables_gob1.h" // Gobliiins + #include "gob/detection/tables_gob2.h" // Gobliins 2: The Prince Buffoon + #include "gob/detection/tables_gob3.h" // Goblins 3 / Goblins Quest 3 + #include "gob/detection/tables_ween.h" // Ween: The Prophecy + #include "gob/detection/tables_bargon.h" // Bargon Attack + #include "gob/detection/tables_littlered.h" // Once Upon A Time: Little Red Riding Hood + #include "gob/detection/tables_onceupon.h" // Once Upon A Time: Baba Yaga and Abracadabra + #include "gob/detection/tables_lit.h" // Lost in Time + #include "gob/detection/tables_fascin.h" // Fascination + #include "gob/detection/tables_geisha.h" // Geisha + #include "gob/detection/tables_inca2.h" // Inca II: Wiracocha + #include "gob/detection/tables_woodruff.h" // (The Bizarre Adventures of) Woodruff and the Schnibble (of Azimuth) + #include "gob/detection/tables_dynasty.h" // The Last Dynasty + #include "gob/detection/tables_urban.h" // Urban Runner + #include "gob/detection/tables_playtoons.h" // The Playtoons series + #include "gob/detection/tables_adi2.h" // The ADI / Addy 2 series + #include "gob/detection/tables_adi4.h" // The ADI / Addy 4 series + #include "gob/detection/tables_adibou.h" // The Adibou / Addy Junior series + #include "gob/detection/tables_ajworld.h" // A.J.'s World of Discovery / ADI Jr. + + { AD_TABLE_END_MARKER, kGameTypeNone, kFeaturesNone, 0, 0, 0} }; -bool GobMetaEngine::hasFeature(MetaEngineFeature f) const { - return false; -} - -bool Gob::GobEngine::hasFeature(EngineFeature f) const { - return - (f == kSupportsRTL); -} -bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { - const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc; - if (gd) { - *engine = new Gob::GobEngine(syst); - ((Gob::GobEngine *)*engine)->initGame(gd); - } - return gd != 0; +// File-based fallback tables +#include "gob/detection/tables_fallback.h" } -#if PLUGIN_ENABLED_DYNAMIC(GOB) - REGISTER_PLUGIN_DYNAMIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine); -#else - REGISTER_PLUGIN_STATIC(GOB, PLUGIN_TYPE_ENGINE, GobMetaEngine); -#endif - -namespace Gob { - -void GobEngine::initGame(const GOBGameDescription *gd) { - if (gd->startTotBase == 0) - _startTot = "intro.tot"; - else - _startTot = gd->startTotBase; - - if (gd->startStkBase == 0) - _startStk = "intro.stk"; - else - _startStk = gd->startStkBase; - - _demoIndex = gd->demoIndex; - - _gameType = gd->gameType; - _features = gd->features; - _language = gd->desc.language; - _platform = gd->desc.platform; -} -} // End of namespace Gob +#endif // GOB_DETECTION_TABLES_H diff --git a/engines/gob/detection/tables_adi2.h b/engines/gob/detection/tables_adi2.h new file mode 100644 index 0000000000..da05a31f40 --- /dev/null +++ b/engines/gob/detection/tables_adi2.h @@ -0,0 +1,203 @@ +/* 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. + * + */ + +/* Detection tables for the ADI / Addy 2 series. */ + +#ifndef GOB_DETECTION_TABLES_ADI2_H +#define GOB_DETECTION_TABLES_ADI2_H + +// -- French: Adi -- + +{ + { + "adi2", + "Adi 2.0 for Teachers", + AD_ENTRY1s("adi2.stk", "da6f1fb68bff32260c5eecdf9286a2f5", 1533168), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdi2, + kFeaturesNone, + "adi2.stk", "ediintro.tot", 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1. Exact version not specified. + { + "adi2", + "Adi 2", + AD_ENTRY1s("adi2.stk", "23f279615c736dc38320f1348e70c36e", 10817668), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, +{ // Found in french ADI 2 Francais-Maths CE2. Exact version not specified. + { + "adi2", + "Adi 2", + AD_ENTRY1s("adi2.stk", "d4162c4298f9423ecc1fb04965557e90", 11531214), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, +{ + { + "adi2", + "Adi 2.5", + AD_ENTRY1s("adi2.stk", "fcac60e6627f37aee219575b60859de9", 16944268), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, +{ + { + "adi2", + "Adi 2.5", + AD_ENTRY1s("adi2.stk", "072d5e2d7826a7c055865568ebf918bb", 16934596), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, +{ + { + "adi2", + "Adi 2.6", + AD_ENTRY1s("adi2.stk", "2fb940eb8105b12871f6b88c8c4d1615", 16780058), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, + +// -- German: Addy -- + +{ + { + "adi2", + "Adi 2.6", + AD_ENTRY1s("adi2.stk", "fde7d98a67dbf859423b6473796e932a", 18044780), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, +{ + { + "adi2", + "Adi 2.7.1", + AD_ENTRY1s("adi2.stk", "6fa5dffebf5c7243c6af6b8c188ee00a", 19278008), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, + +// -- Spanish: Adi -- + +{ + { + "adi2", + "Adi 2", + AD_ENTRY1s("adi2.stk", "2a40bb48ccbd4e6fb3f7f0fc2f069d80", 17720132), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", "ediintro.tot", 0 +}, + +// -- English: ADI (Amiga) -- + +{ + { + "adi2", + "Adi 2", + AD_ENTRY1s("adi2.stk", "29694c5a649298a42f87ae731d6d6f6d", 311132), + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdi2, + kFeaturesNone, + "adi2.stk", "ediintro.tot", 0 +}, + +// -- Demos -- + +{ + { + "adi2", + "Non-Interactive Demo", + { + {"demo.scn", 0, "8b5ba359fd87d586ad39c1754bf6ea35", 168}, + {"demadi2t.vmd", 0, "08a1b18cfe2015d3b43270da35cc813d", 7250723}, + {"demarch.vmd", 0, "4c4a4616585d40ef3df209e3c3911062", 5622731}, + {"demobou.vmd", 0, "2208b9855775564d15c4a5a559da0aec", 3550511}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 1 +}, + +#endif // GOB_DETECTION_TABLES_ADI2_H diff --git a/engines/gob/detection/tables_adi4.h b/engines/gob/detection/tables_adi4.h new file mode 100644 index 0000000000..4b967d76d3 --- /dev/null +++ b/engines/gob/detection/tables_adi4.h @@ -0,0 +1,222 @@ +/* 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. + * + */ + +/* Detection tables for the ADI / Addy 4 series. */ + +#ifndef GOB_DETECTION_TABLES_ADI4_H +#define GOB_DETECTION_TABLES_ADI4_H + +// -- French: Adi -- + +{ + { + "adi4", + "Adi 4.0", + AD_ENTRY1s("intro.stk", "a3c35d19b2d28ea261d96321d208cb5a", 6021466), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Adi 4.0", + AD_ENTRY1s("intro.stk", "44491d85648810bc6fcf84f9b3aa47d5", 5834944), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Adi 4.0", + AD_ENTRY1s("intro.stk", "29374c0e3c10b17dd8463b06a55ad093", 6012072), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Adi 4.0 Limited Edition", + AD_ENTRY1s("intro.stk", "ebbbc5e28a4adb695535ed989c1b8d66", 5929644), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "ADI 4.10", + AD_ENTRY1s("intro.stk", "6afc2590856433b9f5295b032f2b205d", 5923112), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adi4", + "ADI 4.11", + AD_ENTRY1s("intro.stk", "6296e4be4e0c270c24d1330881900c7f", 5921234), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adi4", + "ADI 4.21", + AD_ENTRY1s("intro.stk", "c5b9f6222c0b463f51dab47317c5b687", 5950490), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, + +// -- German: Addy -- + +{ + { + "adi4", + "Addy 4 Grundschule Basis CD", + AD_ENTRY1s("intro.stk", "d2f0fb8909e396328dc85c0e29131ba8", 5847588), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Addy 4 Sekundarstufe Basis CD", + AD_ENTRY1s("intro.stk", "367340e59c461b4fa36651cd74e32c4e", 5847378), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Addy 4.21", + AD_ENTRY1s("intro.stk", "534f0b674cd4830df94a9c32c4ea7225", 6878034), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, + +// -- English: ADI -- + +{ + { + "adi4", + "ADI 4.10", + AD_ENTRY1s("intro.stk", "3e3fa9656e37d802027635ace88c4cc5", 5359144), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "adi4", + "Adi 4.0 Interactive Demo", + AD_ENTRY1s("intro.stk", "89ace204dbaac001425c73f394334f6f", 2413102), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "adi4", + "Adi 4.0 / Adibou 2 Demo", + AD_ENTRY1s("intro.stk", "d41d8cd98f00b204e9800998ecf8427e", 0), + FR_FRA, + kPlatformPC, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_ADI4_H diff --git a/engines/gob/detection/tables_adibou.h b/engines/gob/detection/tables_adibou.h new file mode 100644 index 0000000000..0e652839bb --- /dev/null +++ b/engines/gob/detection/tables_adibou.h @@ -0,0 +1,247 @@ +/* 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. + * + */ + +/* Detection tables for Adibou / Addy Junior series. */ + +#ifndef GOB_DETECTION_TABLES_ADIBOU_H +#define GOB_DETECTION_TABLES_ADIBOU_H + +// -- French: Adibou -- + +{ + { + "adibou1", + "ADIBOU 1 Environnement 4-7 ans", + AD_ENTRY1s("intro.stk", "6db110188fcb7c5208d9721b5282682a", 4805104), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAdibou1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU 2", + AD_ENTRY1s("intro.stk", "94ae7004348dc8bf99c23a9a6ef81827", 956162), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "Le Jardin Magique d'Adibou", + AD_ENTRY1s("intro.stk", "a8ff86f3cc40dfe5898e0a741217ef27", 956328), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU Version Decouverte", + AD_ENTRY1s("intro.stk", "558c14327b79ed39214b49d567a75e33", 8737856), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU 2.10 Environnement", + AD_ENTRY1s("intro.stk", "f2b797819aeedee557e904b0b5ccd82e", 8736454), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU 2.11 Environnement", + AD_ENTRY1s("intro.stk", "7b1f1f6f6477f54401e95d913f75e333", 8736904), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU 2.12 Environnement", + AD_ENTRY1s("intro.stk", "1e49c39a4a3ce6032a84b712539c2d63", 8738134), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOU 2.13s Environnement", + AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "adibou2", + "ADIBOO 2.14 Environnement", + AD_ENTRY1s("intro.stk", "ff63637e3cb7f0a457edf79457b1c6b3", 9333874), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, + +// -- German: Addy Junior -- + +{ + { + "adibou2", + "ADIBOU 2", + AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Italian: Adibù -- +{ + { + "adibou2", + "ADIB\xD9 2", + AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO0() + }, + kGameTypeAdibou2, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "adibou2", + "Non-Interactive Demo", + { + {"demogb.scn", 0, "9291455a908ac0e6aaaca686e532609b", 105}, + {"demogb.vmd", 0, "bc9c1db97db7bec8f566332444fa0090", 14320840}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformPC, + ADGF_DEMO, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdibou2, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 9 +}, +{ + { + "adibou2", + "Non-Interactive Demo", + { + {"demoall.scn", 0, "c8fd308c037b829800006332b2c32674", 106}, + {"demoall.vmd", 0, "4672b2deacc6fca97484840424b1921b", 14263433}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformPC, + ADGF_DEMO, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdibou2, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 10 +}, +{ + { + "adibou2", + "Non-Interactive Demo", + { + {"demofra.scn", 0, "d1b2b1618af384ea1120def8b986c02b", 106}, + {"demofra.vmd", 0, "b494cdec1aac7e54c3f2480512d2880e", 14297100}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_DEMO, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdibou2, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 11 +}, + +#endif // GOB_DETECTION_TABLES_ADIBOU_H diff --git a/engines/gob/detection/tables_ajworld.h b/engines/gob/detection/tables_ajworld.h new file mode 100644 index 0000000000..d86bdb16be --- /dev/null +++ b/engines/gob/detection/tables_ajworld.h @@ -0,0 +1,45 @@ +/* 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. + * + */ + +/* Detection tables for A.J.'s World of Discovery / ADI Jr. */ + +#ifndef GOB_DETECTION_TABLES_AJWORLD_H +#define GOB_DETECTION_TABLES_AJWORLD_H + +// -- DOS VGA Floppy -- + +{ + { + "ajworld", + "", + AD_ENTRY1s("intro.stk", "e453bea7b28a67c930764d945f64d898", 3913628), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAJWorld, + kFeaturesAdLib, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_AJWORLD_H diff --git a/engines/gob/detection/tables_bargon.h b/engines/gob/detection/tables_bargon.h new file mode 100644 index 0000000000..ac90355476 --- /dev/null +++ b/engines/gob/detection/tables_bargon.h @@ -0,0 +1,135 @@ +/* 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. + * + */ + +/* Detection tables for Bargon Attack. */ + +#ifndef GOB_DETECTION_TABLES_BARGON_H +#define GOB_DETECTION_TABLES_BARGON_H + +// -- DOS VGA Floppy -- + +{ + { + "bargon", + "", + AD_ENTRY1("intro.stk", "da3c54be18ab73fbdb32db24624a9c23"), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by cesardark in bug #1681649 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "11103b304286c23945560b391fd37e7d", 3181890), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug #1692667 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "da3c54be18ab73fbdb32db24624a9c23", 3181825), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by kizkoool in bugreport #2089734 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "00f6b4e2ee26e5c40b488e2df5adcf03", 3975580), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by glorfindel in bugreport #1722142 + { + "bargon", + "Fanmade", + AD_ENTRY1s("intro.stk", "da3c54be18ab73fbdb32db24624a9c23", 3181825), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Amiga -- + +{ // Supplied by pwigren in bugreport #1764174 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "569d679fe41d49972d34c9fce5930dda", 269825), + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Atari ST -- + +{ // Supplied by Trekky in the forums + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "2f54b330d21f65b04b7c1f8cca76426c", 262109), + FR_FRA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_BARGON_H diff --git a/engines/gob/detection/tables_dynasty.h b/engines/gob/detection/tables_dynasty.h new file mode 100644 index 0000000000..147bf32075 --- /dev/null +++ b/engines/gob/detection/tables_dynasty.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. + * + */ + +/* Detection tables for The Last Dynasty. */ + +#ifndef GOB_DETECTION_TABLES_DYNASTY_H +#define GOB_DETECTION_TABLES_DYNASTY_H + +// -- Windows -- + +{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "6190e32404b672f4bbbc39cf76f41fda", 2511470), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "61e4069c16e27775a6cc6d20f529fb36", 2511300), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "61e4069c16e27775a6cc6d20f529fb36", 2511300), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "b3f8472484b7a1df94557b51e7b6fca0", 2322644), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "bdbdac8919200a5e71ffb9fb0709f704", 2446652), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "dynasty", + "Demo", + AD_ENTRY1s("intro.stk", "464538a17ed39755d7f1ba9c751af1bd", 1847864), + EN_USA, + kPlatformPC, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "dynasty", + "Demo", + AD_ENTRY1s("lda1.stk", "0e56a899357cbc0bf503260fd2dd634e", 15032774), + UNK_LANG, + kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + "lda1.stk", 0, 0 +}, +{ + { + "dynasty", + "Demo", + AD_ENTRY1s("lda1.stk", "8669ea2e9a8239c070dc73958fbc8753", 15567724), + DE_DEU, + kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeDynasty, + kFeatures640x480, + "lda1.stk", 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_DYNASTY_H diff --git a/engines/gob/detection/tables_fallback.h b/engines/gob/detection/tables_fallback.h new file mode 100644 index 0000000000..05f579c08c --- /dev/null +++ b/engines/gob/detection/tables_fallback.h @@ -0,0 +1,564 @@ +/* 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 GOB_DETECTION_TABLES_FALLBACK_H +#define GOB_DETECTION_TABLES_FALLBACK_H + +// -- Tables for the filename-based fallback -- + +static const GOBGameDescription fallbackDescs[] = { + { //0 + { + "gob1", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 + }, + { //1 + { + "gob1cd", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 + }, + { //2 + { + "gob2", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 + }, + { //3 + { + "gob2mac", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 + }, + { //4 + { + "gob2cd", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { //5 + { + "bargon", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBargon, + kFeaturesNone, + 0, 0, 0 + }, + { //6 + { + "gob3", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 + }, + { //7 + { + "gob3cd", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 + }, + { //8 + { + "woodruff", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 + }, + { //9 + { + "lostintime", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 + }, + { //10 + { + "lostintime", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 + }, + { //11 + { + "lostintime", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 + }, + { //12 + { + "urban", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 + }, + { //13 + { + "playtoons1", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //14 + { + "playtoons2", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //15 + { + "playtoons3", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //16 + { + "playtoons4", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //17 + { + "playtoons5", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //18 + { + "playtoons construction kit", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + 0, 0, 0 + }, + { //19 + { + "bambou", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeBambou, + kFeatures640x480, + 0, 0, 0 + }, + { //20 + { + "fascination", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 + }, + { //21 + { + "geisha", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 + }, + { //22 + { + "littlered", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 + }, + { //23 + { + "littlered", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesNone, + 0, 0, 0 + }, + { //24 + { + "onceupon", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformUnknown, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeOnceUponATime, + kFeaturesEGA, + 0, 0, 0 + }, + { //25 + { + "adi2", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdi2, + kFeatures640x480, + "adi2.stk", 0, 0 + }, + { //26 + { + "adi4", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeAdi4, + kFeatures640x480, + "adif41.stk", 0, 0 + }, + { //27 + { + "coktelplayer", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeaturesAdLib | kFeatures640x480 | kFeaturesSCNDemo, + "", "", 8 + } +}; + +static const ADFileBasedFallback fileBased[] = { + { &fallbackDescs[ 0].desc, { "intro.stk", "disk1.stk", "disk2.stk", "disk3.stk", "disk4.stk", 0 } }, + { &fallbackDescs[ 1].desc, { "intro.stk", "gob.lic", 0 } }, + { &fallbackDescs[ 2].desc, { "intro.stk", 0 } }, + { &fallbackDescs[ 2].desc, { "intro.stk", "disk2.stk", "disk3.stk", 0 } }, + { &fallbackDescs[ 3].desc, { "intro.stk", "disk2.stk", "disk3.stk", "musmac1.mid", 0 } }, + { &fallbackDescs[ 4].desc, { "intro.stk", "gobnew.lic", 0 } }, + { &fallbackDescs[ 5].desc, { "intro.stk", "scaa.imd", "scba.imd", "scbf.imd", 0 } }, + { &fallbackDescs[ 6].desc, { "intro.stk", "imd.itk", 0 } }, + { &fallbackDescs[ 7].desc, { "intro.stk", "mus_gob3.lic", 0 } }, + { &fallbackDescs[ 8].desc, { "intro.stk", "woodruff.itk", 0 } }, + { &fallbackDescs[ 9].desc, { "intro.stk", "commun1.itk", 0 } }, + { &fallbackDescs[10].desc, { "intro.stk", "commun1.itk", "musmac1.mid", 0 } }, + { &fallbackDescs[11].desc, { "intro.stk", "commun1.itk", "lost.lic", 0 } }, + { &fallbackDescs[12].desc, { "intro.stk", "cd1.itk", "objet1.itk", 0 } }, + { &fallbackDescs[13].desc, { "playtoon.stk", "archi.stk", 0 } }, + { &fallbackDescs[14].desc, { "playtoon.stk", "spirou.stk", 0 } }, + { &fallbackDescs[15].desc, { "playtoon.stk", "chato.stk", 0 } }, + { &fallbackDescs[16].desc, { "playtoon.stk", "manda.stk", 0 } }, + { &fallbackDescs[17].desc, { "playtoon.stk", "wakan.stk", 0 } }, + { &fallbackDescs[18].desc, { "playtoon.stk", "dan.itk" } }, + { &fallbackDescs[19].desc, { "intro.stk", "bambou.itk", 0 } }, + { &fallbackDescs[20].desc, { "disk0.stk", "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, + { &fallbackDescs[21].desc, { "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, + { &fallbackDescs[22].desc, { "intro.stk", "stk2.stk", "stk3.stk", 0 } }, + { &fallbackDescs[23].desc, { "intro.stk", "stk2.stk", "stk3.stk", "mod.babayaga", 0 } }, + { &fallbackDescs[24].desc, { "stk1.stk", "stk2.stk", "stk3.stk", 0 } }, + { &fallbackDescs[25].desc, { "adi2.stk", 0 } }, + { &fallbackDescs[26].desc, { "adif41.stk", "adim41.stk", 0 } }, + { &fallbackDescs[27].desc, { "coktelplayer.scn", 0 } }, + { 0, { 0 } } +}; + +// -- Tables for detecting the specific Once Upon A Time game -- + +enum OnceUponATime { + kOnceUponATimeInvalid = -1, + kOnceUponATimeAbracadabra = 0, + kOnceUponATimeBabaYaga = 1, + kOnceUponATimeMAX +}; + +enum OnceUponATimePlatform { + kOnceUponATimePlatformInvalid = -1, + kOnceUponATimePlatformDOS = 0, + kOnceUponATimePlatformAmiga = 1, + kOnceUponATimePlatformAtariST = 2, + kOnceUponATimePlatformMAX +}; + +static const GOBGameDescription fallbackOnceUpon[kOnceUponATimeMAX][kOnceUponATimePlatformMAX] = { + { // kOnceUponATimeAbracadabra + { // kOnceUponATimePlatformDOS + { + "abracadabra", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 + }, + { // kOnceUponATimePlatformAmiga + { + "abracadabra", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 + }, + { // kOnceUponATimePlatformAtariST + { + "abracadabra", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 + } + }, + { // kOnceUponATimeBabaYaga + { // kOnceUponATimePlatformDOS + { + "babayaga", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 + }, + { // kOnceUponATimePlatformAmiga + { + "babayaga", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 + }, + { // kOnceUponATimePlatformAtariST + { + "babayaga", + "", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 + } + } +}; + +#endif // GOB_DETECTION_TABLES_FALLBACK_H diff --git a/engines/gob/detection/tables_fascin.h b/engines/gob/detection/tables_fascin.h new file mode 100644 index 0000000000..1c9cced303 --- /dev/null +++ b/engines/gob/detection/tables_fascin.h @@ -0,0 +1,267 @@ +/* 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. + * + */ + +/* Detection tables for Fascination. */ + +#ifndef GOB_DETECTION_TABLES_FASCIN_H +#define GOB_DETECTION_TABLES_FASCIN_H + +// -- DOS VGA Floppy (1 disk) -- + +{ // Supplied by scoriae + { + "fascination", + "VGA", + AD_ENTRY1s("disk0.stk", "c14330d052fe4da5a441ac9d81bc5891", 1061955), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "VGA", + AD_ENTRY1s("disk0.stk", "e8ab4f200a2304849f462dc901705599", 183337), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 +}, + +// -- DOS VGA Floppy (3 disks) -- + +{ // Supplied by alex86r in bug report #3297633 + { + "fascination", + "VGA 3 disks edition", + AD_ENTRY1s("disk0.stk", "ab3dfdce43917bc806812959d692fc8f", 1061929), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "VGA 3 disks edition", + AD_ENTRY1s("disk0.stk", "a50a8495e1b2d67699fb562cb98fc3e2", 1064387), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "Hebrew edition (censored)", + AD_ENTRY1s("intro.stk", "d6e45ce548598727e2b5587a99718eba", 1055909), + HE_ISR, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "intro.stk", 0, 0 +}, +{ // Supplied by windlepoons in bug report #2809247 + { + "fascination", + "VGA 3 disks edition", + AD_ENTRY1s("disk0.stk", "3a24e60a035250189643c86a9ceafb97", 1062480), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesAdLib, + "disk0.stk", 0, 0 +}, + +// -- DOS VGA CD -- + +{ + { + "fascination", + "CD Version (Censored)", + AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSUBTITLES) + }, + kGameTypeFascination, + kFeaturesCD, + "intro.stk", 0, 0 +}, +{ + { + "fascination", + "CD Version (Censored)", + AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSUBTITLES) + }, + kGameTypeFascination, + kFeaturesCD, + "intro.stk", 0, 0 +}, +{ + { + "fascination", + "CD Version (Censored)", + AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSUBTITLES) + }, + kGameTypeFascination, + kFeaturesCD, + "intro.stk", 0, 0 +}, +{ + { + "fascination", + "CD Version (Censored)", + AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSUBTITLES) + }, + kGameTypeFascination, + kFeaturesCD, + "intro.stk", 0, 0 +}, +{ + { + "fascination", + "CD Version (Censored)", + AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSUBTITLES) + }, + kGameTypeFascination, + kFeaturesCD, + "intro.stk", 0, 0 +}, + +// -- Amiga -- + +{ + { + "fascination", + "", + AD_ENTRY1s("disk0.stk", "68b1c01564f774c0b640075fbad1b695", 189968), + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesNone, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "", + AD_ENTRY1s("disk0.stk", "7062117e9c5adfb6bfb2dac3ff74df9e", 189951), + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesNone, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "", + AD_ENTRY1s("disk0.stk", "55c154e5a3e8e98afebdcff4b522e1eb", 190005), + FR_FRA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesNone, + "disk0.stk", 0, 0 +}, +{ + { + "fascination", + "", + AD_ENTRY1s("disk0.stk", "7691827fff35df7799f14cfd6be178ad", 189931), + IT_ITA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesNone, + "disk0.stk", 0, 0 +}, + +// -- Atari ST -- + +{ + { + "fascination", + "", + AD_ENTRY1s("disk0.stk", "aff9fcc619f4dd19eae228affd0d34c8", 189964), + EN_ANY, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeFascination, + kFeaturesNone, + "disk0.stk", 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_FASCIN_H diff --git a/engines/gob/detection/tables_geisha.h b/engines/gob/detection/tables_geisha.h new file mode 100644 index 0000000000..a32d1ebf81 --- /dev/null +++ b/engines/gob/detection/tables_geisha.h @@ -0,0 +1,132 @@ +/* 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. + * + */ + +/* Detection tables for Geisha. */ + +#ifndef GOB_DETECTION_TABLES_GEISHA_H +#define GOB_DETECTION_TABLES_GEISHA_H + +// -- DOS EGA Floppy -- + +{ + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "6eebbb98ad90cd3c44549fc2ab30f632", 212153), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, +{ + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "6eebbb98ad90cd3c44549fc2ab30f632", 212153), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, +{ // Supplied by misterhands in bug report #3539797 + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "0c4c16090921664f50baefdfd24d7f5d", 211889), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, +{ // Supplied by einstein95 in bug report #3544449 + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "49107ac897e7c00af6c4ecd78a74a710", 212169), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, +{ // Supplied by einstein95 in bug report #3544449 + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "49107ac897e7c00af6c4ecd78a74a710", 212169), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, +{ + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "f4d4d9d20f7ad1f879fc417d47faba89", 336732), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA | kFeaturesAdLib, + "disk1.stk", "intro.tot", 0 +}, + +// -- Amiga -- + +{ + { + "geisha", + "", + AD_ENTRY1s("disk1.stk", "e5892f00917c62423e93f5fd9920cf47", 208120), + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGeisha, + kFeaturesEGA, + "disk1.stk", "intro.tot", 0 +}, + +#endif // GOB_DETECTION_TABLES_GEISHA_H diff --git a/engines/gob/detection/tables_gob1.h b/engines/gob/detection/tables_gob1.h new file mode 100644 index 0000000000..e6086e990a --- /dev/null +++ b/engines/gob/detection/tables_gob1.h @@ -0,0 +1,716 @@ +/* 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. + * + */ + +/* Detection tables for Gobliiins. */ + +#ifndef GOB_DETECTION_TABLES_GOB1_H +#define GOB_DETECTION_TABLES_GOB1_H + +// -- DOS EGA Floppy -- + +{ // Supplied by Florian Zeitz on scummvm-devel + { + "gob1", + "EGA", + AD_ENTRY1("intro.stk", "c65e9cc8ba23a38456242e1f2b1caad4"), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesEGA | kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "EGA", + AD_ENTRY1("intro.stk", "f9233283a0be2464248d83e14b95f09c"), + RU_RUS, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesEGA | kFeaturesAdLib, + 0, 0, 0 +}, + +// -- DOS VGA Floppy -- + +{ // Supplied by Theruler76 in bug report #1201233 + { + "gob1", + "VGA", + AD_ENTRY1("intro.stk", "26a9118c0770fa5ac93a9626761600b2"), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by raziel_ in bug report #1891864 + { + "gob1", + "VGA", + AD_ENTRY1s("intro.stk", "e157cb59c6d330ca70d12ab0ef1dd12b", 288972), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- DOS VGA CD -- + +{ // Provided by pykman in the forums. + { + "gob1cd", + "Polish", + AD_ENTRY1s("intro.stk", "97d2443948b2e367cf567fe7e101f5f2", 4049267), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.000 version. + { + "gob1cd", + "v1.000", + AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.000 version. + { + "gob1cd", + "v1.000", + AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.000 version. + { + "gob1cd", + "v1.000", + AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.000 version. + { + "gob1cd", + "v1.000", + AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.000 version. + { + "gob1cd", + "v1.000", + AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 +}, + +// -- Mac -- + +{ // Supplied by raina in the forums + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "6d837c6380d8f4d984c9f6cc0026df4f", 192712), + EN_ANY, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob1", + "", + AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), + EN_ANY, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob1", + "", + AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), + DE_DEU, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob1", + "", + AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), + FR_FRA, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob1", + "", + AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), + IT_ITA, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob1", + "", + AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), + ES_ESP, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Windows -- + +{ // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "gob1", + "Demo", + AD_ENTRY1("intro.stk", "972f22c6ff8144a6636423f0354ca549"), + UNK_LANG, + kPlatformAmiga, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "gob1", + "Interactive Demo", + AD_ENTRY1("intro.stk", "e72bd1e3828c7dec4c8a3e58c48bdfdb"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "gob1", + "Interactive Demo", + AD_ENTRY1s("intro.stk", "a796096280d5efd48cf8e7dfbe426eb5", 193595), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2785958 + { + "gob1", + "Interactive Demo", + AD_ENTRY1s("intro.stk", "35a098571af9a03c04e2303aec7c9249", 116582), + FR_FRA, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "0e022d3f2481b39e9175d37b2c6ad4c6", 2390121), + FR_FRA, + kPlatformCDi, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob1, + kFeaturesAdLib, + 0, "AVT003.TOT", 0 +}, + +#endif // GOB_DETECTION_TABLES_GOB1_H diff --git a/engines/gob/detection/tables_gob2.h b/engines/gob/detection/tables_gob2.h new file mode 100644 index 0000000000..659e6df063 --- /dev/null +++ b/engines/gob/detection/tables_gob2.h @@ -0,0 +1,641 @@ +/* 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. + * + */ + +/* Detection tables for Gobliins 2: The Prince Buffoon. */ + +#ifndef GOB_DETECTION_TABLES_GOB2_H +#define GOB_DETECTION_TABLES_GOB2_H + +// -- DOS VGA Floppy -- + +{ + { + "gob2", + "", + AD_ENTRY1("intro.stk", "b45b984ee8017efd6ea965b9becd4d66"), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + AD_ENTRY1("intro.stk", "dedb5d31d8c8050a8cf77abedcc53dae"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by raziel_ in bug report #1891867 + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "25a99827cd59751a80bed9620fb677a0", 893302), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "a13ecb4f6d8fd881ebbcc02e45cb5475", 837275), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by blackwhiteeagle in bug report #1605235 + { + "gob2", + "", + AD_ENTRY1("intro.stk", "3e4e7db0d201587dd2df4003b2993ef6"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + AD_ENTRY1("intro.stk", "a13892cdf4badda85a6f6fb47603a128"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2602017 + { + "gob2", + "", + AD_ENTRY1("intro.stk", "c47faf1d406504e6ffe63243610bb1f4"), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + AD_ENTRY1("intro.stk", "cd3e1df8b273636ee32e34b7064f50e8"), + RU_RUS, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by arcepi in bug report #1659884 + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "5f53c56e3aa2f1e76c2e4f0caa15887f", 829232), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- DOS VGA CD -- + +{ + { + "gob2cd", + "v1.000", + AD_ENTRY1("intro.stk", "9de5fbb41cf97182109e5fecc9d90347"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by pykman in bug report #3067489 + { + "gob2cd", + "v2.01 Polish", + AD_ENTRY1s("intro.stk", "3025f05482b646c18c2c79c615a3a1df", 5011726), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "gob2cd", + "v2.01", + AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "gob2cd", + "v2.01", + AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "gob2cd", + "v2.01", + AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "gob2cd", + "v2.01", + AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "gob2cd", + "v2.01", + AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 +}, + +// -- Windows -- + +{ + { + "gob2", + "", + { + {"intro.stk", 0, "285d7340f98ebad65d465585da12910b", 837286}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + { + {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + EN_USA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + { + {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + { + {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + { + {"intro.stk", 0, "6efac0a14c0de4d57dde8592456c8acf", 845172}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + EN_USA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "", + { + {"intro.stk", 0, "6efac0a14c0de4d57dde8592456c8acf", 845172}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "24489330a1d67ff978211f574822a5a6", 883756), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "285d7340f98ebad65d465585da12910b", 837286), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Mac -- + +{ // Supplied by fac76 in bug report #1673397 + { + "gob2", + "", + { + {"intro.stk", 0, "b45b984ee8017efd6ea965b9becd4d66", 828443}, + {"musmac1.mid", 0, "7f96f491448c7a001b32df89cf8d2af2", 1658}, + {0, 0, 0, 0} + }, + UNK_LANG, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by koalet in bug report #2478585 + { + "gob2", + "", + { + {"intro.stk", 0, "a13ecb4f6d8fd881ebbcc02e45cb5475", 837275}, + {"musmac1.mid", 0, "7f96f491448c7a001b32df89cf8d2af2", 1658}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Amiga -- + +{ // Supplied by fac76 in bug report #1883808 + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "eebf2810122cfd17399260cd1468e994", 554014), + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "gob2", + "", + AD_ENTRY1("intro.stk", "d28b9e9b41f31acfa58dcd12406c7b2c"), + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2602057 + { + "gob2", + "", + AD_ENTRY1("intro.stk", "686c88f7302a80b744aae9f8413e853d"), + IT_ITA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by aldozx in the forums + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "abc3e786cd78197773954c75815b278b", 554721), + ES_ESP, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Atari ST -- + +{ // Supplied by bgk in bug report #1706861 + { + "gob2", + "", + AD_ENTRY1s("intro.stk", "4b13c02d1069b86bcfec80f4e474b98b", 554680), + FR_FRA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "gob2", + "Non-Interactive Demo", + AD_ENTRY1("intro.stk", "8b1c98ff2ab2e14f47a1b891e9b92217"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, "usa.tot", 0 +}, +{ + { + "gob2", + "Interactive Demo", + AD_ENTRY1("intro.stk", "cf1c95b2939bd8ff58a25c756cb6125e"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob2", + "Interactive Demo", + AD_ENTRY1("intro.stk", "4b278c2678ea01383fd5ca114d947eea"), + UNK_LANG, + kPlatformAmiga, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by polluks in bug report #1895126 + { + "gob2", + "Interactive Demo", + AD_ENTRY1s("intro.stk", "9fa85aea959fa8c582085855fbd99346", 553063), + UNK_LANG, + kPlatformAmiga, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob2, + kFeaturesNone, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_GOB2_H diff --git a/engines/gob/detection/tables_gob3.h b/engines/gob/detection/tables_gob3.h new file mode 100644 index 0000000000..22ec69054b --- /dev/null +++ b/engines/gob/detection/tables_gob3.h @@ -0,0 +1,564 @@ +/* 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. + * + */ + +/* Detection tables for Goblins 3 / Goblins Quest 3. */ + +#ifndef GOB_DETECTION_TABLES_GOB3_H +#define GOB_DETECTION_TABLES_GOB3_H + +// -- DOS VGA Floppy -- + +{ + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "32b0f57f5ae79a9ae97e8011df38af42", 157084), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "904fc32032295baa3efb3a41f17db611", 178582), + HE_ISR, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by raziel_ in bug report #1891869 + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "16b014bf32dbd6ab4c5163c44f56fed1", 445104), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "1e2f64ec8dfa89f42ee49936a27e66e7"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by paul66 in bug report #1652352 + { + "gob3", + "", + AD_ENTRY1("intro.stk", "f6d225b25a180606fa5dbe6405c97380"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "e42a4f2337d6549487a80864d7826972"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by Paranoimia on #scummvm + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "fe8144daece35538085adb59c2d29613", 159402), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "4e3af248a48a2321364736afab868527"), + RU_RUS, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "8d28ce1591b0e9cc79bf41cad0fc4c9c"), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2098621 + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "d3b72938fbbc8159198088811f9e6d19", 160382), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Windows -- + +{ + { + "gob3", + "", + { + {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + { + {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + { + {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + { + {"intro.stk", 0, "edd7403e5dc2a14459d2665a4c17714d", 209534}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + { + {"intro.stk", 0, "428e2de130cf3b303c938924539dc50d", 324420}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "", + { + {"intro.stk", 0, "428e2de130cf3b303c938924539dc50d", 324420}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in Found in french ADI 2.5 Anglais Multimedia 5e + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "edd7403e5dc2a14459d2665a4c17714d", 209534), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Mac -- + +{ // Supplied by fac76 in bug report #1742716 + { + "gob3", + "", + { + {"intro.stk", 0, "32b0f57f5ae79a9ae97e8011df38af42", 157084}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Amiga -- + +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "bd679eafde2084d8011f247e51b5a805"), + EN_GRB, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesNone, + 0, "menu.tot", 0 +}, +{ + { + "gob3", + "", + AD_ENTRY1("intro.stk", "bd679eafde2084d8011f247e51b5a805"), + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesNone, + 0, "menu.tot", 0 +}, + +// -- DOS VGA CD -- + +{ + { + "gob3cd", + "v1.000", + AD_ENTRY1("intro.stk", "6f2c226c62dd7ab0ab6f850e89d3fc47"), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by pykman in bug report #3067489 + { + "gob3cd", + "v1.02 Polish", + AD_ENTRY1s("intro.stk", "978afddcac81bb95a04757b61f78471c", 619825), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 + { + "gob3cd", + "v1.02", + AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 + { + "gob3cd", + "v1.02", + AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 + { + "gob3cd", + "v1.02", + AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 + { + "gob3cd", + "v1.02", + AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 + { + "gob3cd", + "v1.02", + AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "gob3", + "Non-interactive Demo", + AD_ENTRY1("intro.stk", "b9b898fccebe02b69c086052d5024a55"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "Interactive Demo", + AD_ENTRY1("intro.stk", "7aebd94e49c2c5c518c9e7b74f25de9d"), + FR_FRA, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "Interactive Demo 2", + AD_ENTRY1("intro.stk", "e5dcbc9f6658ebb1e8fe26bc4da0806d"), + FR_FRA, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "gob3", + "Interactive Demo 3", + AD_ENTRY1s("intro.stk", "9e20ad7b471b01f84db526da34eaf0a2", 395561), + EN_ANY, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeGob3, + kFeaturesAdLib, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_GOB3_H diff --git a/engines/gob/detection/tables_inca2.h b/engines/gob/detection/tables_inca2.h new file mode 100644 index 0000000000..26989f7d1a --- /dev/null +++ b/engines/gob/detection/tables_inca2.h @@ -0,0 +1,249 @@ +/* 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. + * + */ + +/* Detection tables for Inca II: Wiracocha. */ + +#ifndef GOB_DETECTION_TABLES_INCA2_H +#define GOB_DETECTION_TABLES_INCA2_H + +// -- DOS VGA Floppy -- + +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- DOS VGA CD -- + +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesCD, + 0, 0, 0 +}, + +// -- Windows -- + +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + EN_USA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "inca2", + "Non-Interactive Demo", + { + {"cons.imd", 0, "f896ba0c4a1ac7f7260d342655980b49", 17804}, + {"conseil.imd", 0, "aaedd5482d5b271e233e86c5a03cf62e", 33999}, + {"int.imd", 0, "6308222fcefbcb20925f01c1aff70dee", 30871}, + {"inter.imd", 0, "39bd6d3540f3bedcc97293f352c7f3fc", 191719}, + {"machu.imd", 0, "c0bc8211d93b467bfd063b63fe61b85c", 34609}, + {"post.imd", 0, "d75cad0e3fc22cb0c8b6faf597f509b2", 1047709}, + {"posta.imd", 0, "2a5b3fe75681ddf4d21ac724db8111b4", 547250}, + {"postb.imd", 0, "24260ce4e80a4c472352b76637265d09", 868312}, + {"postc.imd", 0, "24accbcc8b83a9c2be4bd82849a2bd29", 415637}, + {"tum.imd", 0, "0993d4810ec9deb3f77c5e92095320fd", 20330}, + {"tumi.imd", 0, "bf53f229480d694de0947fe3366fbec6", 248952}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeInca2, + kFeaturesAdLib | kFeaturesBATDemo, + 0, 0, 7 +}, + +#endif // GOB_DETECTION_TABLES_INCA2_H diff --git a/engines/gob/detection/tables_lit.h b/engines/gob/detection/tables_lit.h new file mode 100644 index 0000000000..019d001f97 --- /dev/null +++ b/engines/gob/detection/tables_lit.h @@ -0,0 +1,484 @@ +/* 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. + * + */ + +/* Detection tables for Lost in Time. */ + +#ifndef GOB_DETECTION_TABLES_LIT_H +#define GOB_DETECTION_TABLES_LIT_H + +// -- DOS VGA Floppy (Part I and II) -- + +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "7b7f48490dedc8a7cb999388e2fadbe3", 3930674), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "e0767783ff662ed93665446665693aef", 4371238), + HE_ISR, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by cartman_ on #scummvm + { + "lit", + "", + AD_ENTRY1s("intro.stk", "f1f78b663893b58887add182a77df151", 3944090), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2105220 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "cd322cb3c64ef2ba2f2134aa2122cfe9", 3936700), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, +{ // Supplied by SiRoCs in bug report #2093672 + { + "lit", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesCD, + 0, 0, 0 +}, + +// -- Windows (Part I and II) -- + +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4219382), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4219382), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Found in french ADI 2.6 Francais-Maths 4e + { + "lit", + "", + AD_ENTRY1s("intro.stk", "58ee9583a4fb837f02d9a58e5f442656", 3937120), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Windows (Part I only) -- +{ + { + "lit1", + "Light install", + { + {"intro.stk", 0, "93c91bc9e783d00033042ae83144d7dd", 72318}, + {"partie2.itk", 0, "78f00bd8eb9e680e6289bba0130b1b33", 664064}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit1", + "Full install", + { + {"intro.stk", 0, "93c91bc9e783d00033042ae83144d7dd", 72318}, + {"partie2.itk", 0, "78f00bd8eb9e680e6289bba0130b1b33", 4396644}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Windows (Part II only) -- + +{ + { + "lit2", + "Light install", + AD_ENTRY1s("intro.stk", "17acbb212e62addbe48dc8f2282c98cb", 72318), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "lit2", + "Full install", + { + {"intro.stk", 0, "17acbb212e62addbe48dc8f2282c98cb", 72318}, + {"partie4.itk", 0, "6ce4967e0c79d7daeabc6c1d26783d4c", 2612087}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Mac (Part I and II) -- + +{ // Supplied by koalet in bug report #2479034 + { + "lit", + "", + { + {"intro.stk", 0, "af98bcdc70e1f1c1635577fd726fe7f1", 3937310}, + {"musmac1.mid", 0, "ae7229bb09c6abe4e60a2768b24bc890", 9398}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "lit", + "Demo", + AD_ENTRY1("demo.stk", "c06f8cc20eb239d4c71f225ce3093edf"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + "demo.stk", "demo.tot", 0 +}, +{ + { + "lit", + "Non-interactive Demo", + AD_ENTRY1("demo.stk", "2eba8abd9e3878c57307576012dd2fec"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + "demo.stk", "demo.tot", 0 +}, + +// -- Pirated! Do not re-add nor un-tag! -- + +{ + { + "lit", + "", + AD_ENTRY1s("intro.stk", "3712e7527ba8ce5637d2aadf62783005", 72318), + FR_FRA, + kPlatformPC, + ADGF_PIRATED, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLostInTime, + kFeaturesAdLib, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_LIT_H diff --git a/engines/gob/detection/tables_littlered.h b/engines/gob/detection/tables_littlered.h new file mode 100644 index 0000000000..2b41b65a71 --- /dev/null +++ b/engines/gob/detection/tables_littlered.h @@ -0,0 +1,265 @@ +/* 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. + * + */ + +/* Detection tables for Once Upon A Time: Little Red Riding Hood. */ + +#ifndef GOB_DETECTION_TABLES_LITTLERED_H +#define GOB_DETECTION_TABLES_LITTLERED_H + +// -- DOS EGA Floppy -- + +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, + +// -- Windows -- + +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ // Found in french ADI 2 Francais-Maths CM1 + { + "littlered", + "", + AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, + +// -- Amiga -- + +{ + { + "littlered", + "", + { + {"intro.stk", 0, "0b72992f5d8b5e6e0330572a5753ea25", 256490}, + {"mod.babayaga", 0, "43484cde74e0860785f8e19f0bc776d1", 60248}, + {0, 0, 0, 0} + }, + UNK_LANG, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeLittleRed, + kFeaturesNone, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_LITTLERED_H diff --git a/engines/gob/detection/tables_onceupon.h b/engines/gob/detection/tables_onceupon.h new file mode 100644 index 0000000000..366024d43c --- /dev/null +++ b/engines/gob/detection/tables_onceupon.h @@ -0,0 +1,518 @@ +/* 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. + * + */ + +/* Detection tables for Once Upon A Time: Baba Yaga and Abracadabra. */ + +#ifndef GOB_DETECTION_TABLES_ONCEUPON_H +#define GOB_DETECTION_TABLES_ONCEUPON_H + +// -- Once Upon A Time: Abracadabra, Amiga -- + +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106}, + {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106}, + {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106}, + {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106}, + {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "e4b21818af03930dc9cab2ad4c93cb5b", 362106}, + {"stk3.stk", 0, "76874ad92782f9b2de57beafc05ec877", 353482}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, + +// -- Once Upon A Time: Abracadabra, Atari ST -- + +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123}, + {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123}, + {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123}, + {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123}, + {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "abracadabra", + "", + { + {"stk1.stk", 0, "a8e963eea170155548e5bc1d0f07d50d", 209806}, + {"stk2.stk", 0, "c6440aaf068ec3149ae89bc5c41ebf02", 362123}, + {"stk3.stk", 0, "5af3c1202ba6fcf8dad2b2125e1c1383", 353257}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeAbracadabra, + kFeaturesEGA, + 0, 0, 0 +}, + +// -- Once Upon A Time: Baba Yaga, DOS EGA Floppy -- + +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813}, + {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582}, + {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813}, + {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582}, + {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813}, + {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582}, + {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813}, + {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582}, + {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "3c777f43e6fb49fde9222543447e135a", 204813}, + {"stk2.stk", 0, "6cf0b009dd185a8f589e91a1f9c33df5", 361582}, + {"stk3.stk", 0, "6473183ca4db1b5b5cea047f9af59a26", 328925}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesAdLib | kFeaturesEGA, + 0, 0, 0 +}, + +// -- Once Upon A Time: Baba Yaga, Amiga -- + +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090}, + {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090}, + {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090}, + {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090}, + {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "bcc823d2888057031e54716ed1b3c80e", 205090}, + {"stk2.stk", 0, "f76bf7c2ff60d816d69962d1a593207c", 362122}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, + +// -- Once Upon A Time: Baba Yaga, Atari ST -- + +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095}, + {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095}, + {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095}, + {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095}, + {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, +{ + { + "babayaga", + "", + { + {"stk1.stk", 0, "17a4e3e7a18cc97231c92d280c7878a1", 205095}, + {"stk2.stk", 0, "bfbc380e5461f63af28e9e6b10f334b5", 362128}, + {"stk3.stk", 0, "6227d1aefdf39d88dcf83e38bea2a9af", 328922}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeBabaYaga, + kFeaturesEGA, + 0, 0, 0 +}, + +#endif // GOB_DETECTION_TABLES_ONCEUPON_H diff --git a/engines/gob/detection/tables_playtoons.h b/engines/gob/detection/tables_playtoons.h new file mode 100644 index 0000000000..4eb5945b04 --- /dev/null +++ b/engines/gob/detection/tables_playtoons.h @@ -0,0 +1,517 @@ +/* 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. + * + */ + +/* Detection tables for the Playtoons series. */ + +#ifndef GOB_DETECTION_TABLES_PLAYTOONS_H +#define GOB_DETECTION_TABLES_PLAYTOONS_H + +// -- Playtoons 1: Uncle Archibald -- + +{ + { + "playtoons1", + "", + { + {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, + {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons1", + "Pack mes histoires anim\xE9""es", + { + {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, + {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons1", + "", + { + {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, + {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ // Supplied by scoriae in the forums + { + "playtoons1", + "", + { + {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, + {"archi.stk", 0, "00d8274519dfcf8a0d8ae3099daea0f8", 5532135}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons1", + "Non-Interactive Demo", + { + {"play123.scn", 0, "4689a31f543915e488c3bc46ea358add", 258}, + {"archi.vmd", 0, "a410fcc8116bc173f038100f5857191c", 5617210}, + {"chato.vmd", 0, "5a10e39cb66c396f2f9d8fb35e9ac016", 5445937}, + {"genedeb.vmd", 0, "3bb4a45585f88f4d839efdda6a1b582b", 1244228}, + {"generik.vmd", 0, "b46bdd64b063e86927fb2826500ad512", 603242}, + {"genespi.vmd", 0, "b7611916f32a370ae9832962fc17ef72", 758719}, + {"spirou.vmd", 0, "8513dbf7ac51c057b21d371d6b217b47", 2550788}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 3 +}, +{ + { + "playtoons1", + "Non-Interactive Demo", + { + {"e.scn", 0, "8a0db733c3f77be86e74e8242e5caa61", 124}, + {"demarchg.vmd", 0, "d14a95da7d8792faf5503f649ffcbc12", 5619415}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 4 +}, +{ + { + "playtoons1", + "Non-Interactive Demo", + { + {"i.scn", 0, "8b3294474d39970463663edd22341730", 285}, + {"demarita.vmd", 0, "84c8672b91c7312462603446e224bfec", 5742533}, + {"dembouit.vmd", 0, "7a5fdf0a4dbdfe72e31dd489ea0f8aa2", 3536786}, + {"demo5.vmd", 0, "2abb7b6a26406c984f389f0b24b5e28e", 13290970}, + {"demoita.vmd", 0, "b4c0622d14c8749965cd0f5dfca4cf4b", 1183566}, + {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 5 +}, +{ + { + "playtoons1", + "Non-Interactive Demo", + { + {"s.scn", 0, "1f527010626b5490761f16ba7a6f639a", 251}, + {"demaresp.vmd", 0, "3f860f944056842b35a5fd05416f208e", 5720619}, + {"demboues.vmd", 0, "3a0caa10c98ef92a15942f8274075b43", 3535838}, + {"demo5.vmd", 0, "2abb7b6a26406c984f389f0b24b5e28e", 13290970}, + {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 6 +}, + +// -- Playtoons 2: The Case of the Counterfeit Collaborator (Spirou) -- + +{ + { + "playtoons2", + "", + { + {"playtoon.stk", 0, "4772c96be88a57f0561519e4a1526c62", 24406262}, + {"spirou.stk", 0, "5d9c7644d0c47840169b4d016765cc1a", 9816201}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons2", + "", + { + {"playtoon.stk", 0, "55a85036dd93cce93532d8f743d90074", 17467154}, + {"spirou.stk", 0, "e3e1b6148dd72fafc3637f1a8e5764f5", 9812043}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons2", + "", + { + {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, + {"spirou.stk", 0, "91080dc148de1bbd6a97321c1a1facf3", 9817086}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ // Supplied by Hkz + { + "playtoons2", + "", + { + {"playtoon.stk", 0, "2572685400852d12759a2fbf09ec88eb", 9698780}, + {"spirou.stk", 0, "d3cfeff920b6343a2ece55088f530dba", 7076608}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ // Supplied by scoriae in the forums + { + "playtoons2", + "", + { + {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, + {"spirou.stk", 0, "993737f112ca6a9b33c814273280d832", 9825760}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons 3: The Secret of the Castle -- + +{ + { + "playtoons3", + "", + { + {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, + {"chato.stk", 0, "4fa4ed96a427c344e9f916f9f236598d", 6033793}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons3", + "", + { + {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, + {"chato.stk", 0, "8fc8d0da5b3e758908d1d7298d497d0b", 6041026}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons3", + "Pack mes histoires anim\xE9""es", + { + {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, + {"chato.stk", 0, "4fa4ed96a427c344e9f916f9f236598d", 6033793}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ + { + "playtoons3", + "", + { + {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, + {"chato.stk", 0, "3c6cb3ac8a5a7cf681a19971a92a748d", 6033791}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "playtoons3", + "", + { + {"playtoon.stk", 0, "4772c96be88a57f0561519e4a1526c62", 24406262}, + {"chato.stk", 0, "bdef407387112bfcee90e664865ac3af", 6033867}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons 4: The Mandarin Prince -- + +{ + { + "playtoons4", + "", + { + {"playtoon.stk", 0, "b7f5afa2dc1b0f75970b7c07d175db1b", 24340406}, + {"manda.stk", 0, "92529e0b927191d9898a34c2892e9a3a", 6485072}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, +{ //Supplied by goodoldgeorg in bug report #2820006 + { + "playtoons4", + "", + { + {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, + {"manda.stk", 0, "69a79c9f61b2618e482726f2ff68078d", 6499208}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons 5: The Stone of Wakan -- + +{ + { + "playtoons5", + "", + { + {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, + {"wakan.stk", 0, "f493bf82851bc5ba74d57de6b7e88df8", 5520153}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons Construction Kit 1: Monsters -- + +{ + { + "playtnck1", + "", + { + {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, + {"dan.itk", 0, "906d67b3e438d5e95ec7ea9e781a94f3", 3000320}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons Construction Kit 2: Knights -- + +{ + { + "playtnck2", + "", + { + {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, + {"dan.itk", 0, "74eeb075bd2cb47b243349730264af01", 3213312}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Playtoons Construction Kit 3: Far West -- + +{ + { + "playtnck3", + "", + { + {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, + {"dan.itk", 0, "9a8f62809eca5a52f429b5b6a8e70f8f", 2861056}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypePlaytoons, + kFeatures640x480, + "intro2.stk", 0, 0 +}, + +// -- Bambou le sauveur de la jungle -- + +{ + { + "bambou", + "", + { + {"intro.stk", 0, "2f8db6963ff8d72a8331627ebda918f4", 3613238}, + {"bambou.itk", 0, "0875914d31126d0749313428f10c7768", 114440192}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeBambou, + kFeatures640x480, + "intro.stk", "intro.tot", 0 +}, + +#endif // GOB_DETECTION_TABLES_PLAYTOONS_H diff --git a/engines/gob/detection/tables_urban.h b/engines/gob/detection/tables_urban.h new file mode 100644 index 0000000000..d24f6a5011 --- /dev/null +++ b/engines/gob/detection/tables_urban.h @@ -0,0 +1,151 @@ +/* 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. + * + */ + +/* Detection tables for Urban Runner. */ + +#ifndef GOB_DETECTION_TABLES_URBAN_H +#define GOB_DETECTION_TABLES_URBAN_H + +// -- Windows -- + +{ + { + "urban", + "", + AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by Collector9 in bug report #3228040 + { + "urban", + "", + AD_ENTRY1s("intro.stk", "6ce3d878178932053267237ec4843ce1", 1252518), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by gamin in the forums + { + "urban", + "", + AD_ENTRY1s("intro.stk", "b991ed1d31c793e560edefdb349882ef", 1276408), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "urban", + "", + AD_ENTRY1s("intro.stk", "4ec3c0864e2b54c5b4ccf9f6ad96528d", 1253328), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by Alex on the gobsmacked blog + { + "urban", + "", + AD_ENTRY1s("intro.stk", "9ea647085a16dd0fb9ecd84cd8778ec9", 1253436), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by alex86r in bug report #3297602 + { + "urban", + "", + AD_ENTRY1s("intro.stk", "4e4a3c017fe5475353bf94c455fe3efd", 1253448), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2770340 + { + "urban", + "", + AD_ENTRY1s("intro.stk", "4bd31979ea3d77a58a358c09000a85ed", 1253018), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "urban", + "Non-Interactive Demo", + { + {"wdemo.s24", 0, "14ac9bd51db7a075d69ddb144904b271", 87}, + {"demo.vmd", 0, "65d04715d871c292518b56dd160b0161", 9091237}, + {"urband.vmd", 0, "60343891868c91854dd5c82766c70ecc", 922461}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor | kFeaturesSCNDemo, + 0, 0, 2 +}, + +#endif // GOB_DETECTION_TABLES_URBAN_H diff --git a/engines/gob/detection/tables_ween.h b/engines/gob/detection/tables_ween.h new file mode 100644 index 0000000000..a02b931b85 --- /dev/null +++ b/engines/gob/detection/tables_ween.h @@ -0,0 +1,349 @@ +/* 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. + * + */ + +/* Detection tables for Ween: The Prophecy. */ + +#ifndef GOB_DETECTION_TABLES_WEEN_H +#define GOB_DETECTION_TABLES_WEEN_H + +// -- DOS VGA Floppy -- + +{ + { + "ween", + "", + AD_ENTRY1("intro.stk", "2bb8878a8042244dd2b96ff682381baa"), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "ween", + "", + AD_ENTRY1s("intro.stk", "de92e5c6a8c163007ffceebef6e67f7d", 7117568), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by cybot_tmin in bug report #1667743 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "6d60f9205ecfbd8735da2ee7823a70dc", 7014426), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "ween", + "", + AD_ENTRY1("intro.stk", "4b10525a3782aa7ecd9d833b5c1d308b"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by cartman_ on #scummvm + { + "ween", + "", + AD_ENTRY1("intro.stk", "63170e71f04faba88673b3f510f9c4c8"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by glorfindel in bugreport #1722142 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "8b57cd510da8a3bbd99e3a0297a8ebd1", 7018771), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Amiga -- + +{ // Supplied by vampir_raziel in bug report #1658373 + { + "ween", + "", + { + {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, + {"ween.ins", 0, "d2cb24292c9ddafcad07e23382027218", 87800}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by vampir_raziel in bug report #1658373 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "257fe669705ac4971efdfd5656eef16a", 457719), + FR_FRA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by vampir_raziel in bug report #1658373 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "dffd1ab98fe76150d6933329ca6f4cc4", 459458), + FR_FRA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by vampir_raziel in bug report #1658373 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "af83debf2cbea21faa591c7b4608fe92", 458192), + DE_DEU, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2563539 + { + "ween", + "", + { + {"intro.stk", 0, "dffd1ab98fe76150d6933329ca6f4cc4", 459458}, + {"ween.ins", 0, "d2cb24292c9ddafcad07e23382027218", 87800}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, + +// -- Atari ST -- + +{ // Supplied by pwigren in bug report #1764174 + { + "ween", + "", + { + {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, + {"music__5.snd", 0, "7d1819b9981ecddd53d3aacbc75f1cc8", 13446}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, +{ + { + "ween", + "", + AD_ENTRY1("intro.stk", "e6d13fb3b858cb4f78a8780d184d5b2c"), + FR_FRA, + kPlatformAtariST, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesNone, + 0, 0, 0 +}, + +// -- DOS VGA Floppy -- + +{ + { + "ween", + "", + AD_ENTRY1("intro.stk", "2bb8878a8042244dd2b96ff682381baa"), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "ween", + "", + AD_ENTRY1s("intro.stk", "de92e5c6a8c163007ffceebef6e67f7d", 7117568), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by cybot_tmin in bug report #1667743 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "6d60f9205ecfbd8735da2ee7823a70dc", 7014426), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ + { + "ween", + "", + AD_ENTRY1("intro.stk", "4b10525a3782aa7ecd9d833b5c1d308b"), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by cartman_ on #scummvm + { + "ween", + "", + AD_ENTRY1("intro.stk", "63170e71f04faba88673b3f510f9c4c8"), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, +{ // Supplied by glorfindel in bugreport #1722142 + { + "ween", + "", + AD_ENTRY1s("intro.stk", "8b57cd510da8a3bbd99e3a0297a8ebd1", 7018771), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "ween", + "Demo", + AD_ENTRY1("intro.stk", "2e9c2898f6bf206ede801e3b2e7ee428"), + UNK_LANG, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, "show.tot", 0 +}, +{ + { + "ween", + "Demo", + AD_ENTRY1("intro.stk", "15fb91a1b9b09684b28ac75edf66e504"), + EN_USA, + kPlatformPC, + ADGF_DEMO, + GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) + }, + kGameTypeWeen, + kFeaturesAdLib, + 0, "show.tot", 0 +}, + +#endif // GOB_DETECTION_TABLES_WEEN_H diff --git a/engines/gob/detection/tables_woodruff.h b/engines/gob/detection/tables_woodruff.h new file mode 100644 index 0000000000..e369539984 --- /dev/null +++ b/engines/gob/detection/tables_woodruff.h @@ -0,0 +1,402 @@ +/* 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. + * + */ + +/* Detection tables for (The Bizarre Adventures of) Woodruff and the Schnibble (of Azimuth). */ + +#ifndef GOB_DETECTION_TABLES_WOODRUFF_H +#define GOB_DETECTION_TABLES_WOODRUFF_H + +// -- Windows CD -- + +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "5f5f4e0a72c33391e67a47674b120cc6", 20296422), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + EN_GRB, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, +{ // Supplied by goodoldgeorg in bug report #2098838 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "08a96bf061af1fa4f75c6a7cc56b60a4", 20734979), + PL_POL, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480, + 0, 0, 0 +}, + +// -- Demos -- + +{ + { + "woodruff", + "Non-Interactive Demo", + { + {"demo.scn", 0, "16bb85fc5f8e519147b60475dbf33962", 89}, + {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) + }, + kGameTypeWoodruff, + kFeatures640x480 | kFeaturesSCNDemo, + 0, 0, 1 +}, + +#endif // GOB_DETECTION_TABLES_WOODRUFF_H diff --git a/engines/gob/detection_tables.h b/engines/gob/detection_tables.h deleted file mode 100644 index 7aa58b9b97..0000000000 --- a/engines/gob/detection_tables.h +++ /dev/null @@ -1,5276 +0,0 @@ -/* 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. - * - */ - -namespace Gob { - -static const GOBGameDescription gameDescriptions[] = { - { // Supplied by Florian Zeitz on scummvm-devel - { - "gob1", - "EGA", - AD_ENTRY1("intro.stk", "c65e9cc8ba23a38456242e1f2b1caad4"), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesEGA, - 0, 0, 0 - }, - { - { - "gob1", - "EGA", - AD_ENTRY1("intro.stk", "f9233283a0be2464248d83e14b95f09c"), - RU_RUS, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesEGA, - 0, 0, 0 - }, - { // Supplied by Theruler76 in bug report #1201233 - { - "gob1", - "VGA", - AD_ENTRY1("intro.stk", "26a9118c0770fa5ac93a9626761600b2"), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by raziel_ in bug report #1891864 - { - "gob1", - "VGA", - AD_ENTRY1s("intro.stk", "e157cb59c6d330ca70d12ab0ef1dd12b", 288972), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by raina in the forums - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "6d837c6380d8f4d984c9f6cc0026df4f", 192712), - EN_ANY, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob1", - "", - AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), - EN_ANY, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob1", - "", - AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), - DE_DEU, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob1", - "", - AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), - FR_FRA, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob1", - "", - AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), - IT_ITA, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob1", - "", - AD_ENTRY1("intro.stk", "00a42a7d2d22e6b6ab1b8c673c4ed267"), - ES_ESP, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "gob1", - "", - { - {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "gob1", - "", - { - {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "gob1", - "", - { - {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "gob1", - "", - { - {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "gob1", - "", - { - {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob1", - "", - { - {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob1", - "", - { - {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob1", - "", - { - {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob1", - "", - { - {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob1", - "", - { - {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, - {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "f5f028ee39c456fa51fa63b606583918", 313472), - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Provided by pykman in the forums. - { - "gob1cd", - "Polish", - AD_ENTRY1s("intro.stk", "97d2443948b2e367cf567fe7e101f5f2", 4049267), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.000 version. - { - "gob1cd", - "v1.000", - AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.000 version. - { - "gob1cd", - "v1.000", - AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.000 version. - { - "gob1cd", - "v1.000", - AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.000 version. - { - "gob1cd", - "v1.000", - AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.000 version. - { - "gob1cd", - "v1.000", - AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.02 version. Multilingual - { - "gob1cd", - "v1.02", - AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.02 version. Multilingual - { - "gob1cd", - "v1.02", - AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.02 version. Multilingual - { - "gob1cd", - "v1.02", - AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.02 version. Multilingual - { - "gob1cd", - "v1.02", - AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // CD 1.02 version. Multilingual - { - "gob1cd", - "v1.02", - AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob1cd", - "v1.02", - AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), - HU_HUN, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob1cd", - "v1.02", - AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob1cd", - "v1.02", - AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob1cd", - "v1.02", - AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob1", - "Demo", - AD_ENTRY1("intro.stk", "972f22c6ff8144a6636423f0354ca549"), - UNK_LANG, - kPlatformAmiga, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "gob1", - "Interactive Demo", - AD_ENTRY1("intro.stk", "e72bd1e3828c7dec4c8a3e58c48bdfdb"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "gob1", - "Interactive Demo", - AD_ENTRY1s("intro.stk", "a796096280d5efd48cf8e7dfbe426eb5", 193595), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2785958 - { - "gob1", - "Interactive Demo", - AD_ENTRY1s("intro.stk", "35a098571af9a03c04e2303aec7c9249", 116582), - FR_FRA, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "gob1", - "", - AD_ENTRY1s("intro.stk", "0e022d3f2481b39e9175d37b2c6ad4c6", 2390121), - FR_FRA, - kPlatformCDi, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesAdLib, - 0, "AVT003.TOT", 0 - }, - { // Supplied by fac76 in bug report #1883808 - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "eebf2810122cfd17399260cd1468e994", 554014), - EN_ANY, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1("intro.stk", "d28b9e9b41f31acfa58dcd12406c7b2c"), - DE_DEU, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2602057 - { - "gob2", - "", - AD_ENTRY1("intro.stk", "686c88f7302a80b744aae9f8413e853d"), - IT_ITA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by aldozx in the forums - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "abc3e786cd78197773954c75815b278b", 554721), - ES_ESP, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by bgk in bug report #1706861 - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "4b13c02d1069b86bcfec80f4e474b98b", 554680), - FR_FRA, - kPlatformAtariST, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by fac76 in bug report #1673397 - { - "gob2", - "", - { - {"intro.stk", 0, "b45b984ee8017efd6ea965b9becd4d66", 828443}, - {"musmac1.mid", 0, "7f96f491448c7a001b32df89cf8d2af2", 1658}, - {0, 0, 0, 0} - }, - UNK_LANG, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by koalet in bug report #2478585 - { - "gob2", - "", - { - {"intro.stk", 0, "a13ecb4f6d8fd881ebbcc02e45cb5475", 837275}, - {"musmac1.mid", 0, "7f96f491448c7a001b32df89cf8d2af2", 1658}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1("intro.stk", "b45b984ee8017efd6ea965b9becd4d66"), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1("intro.stk", "dedb5d31d8c8050a8cf77abedcc53dae"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by raziel_ in bug report #1891867 - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "25a99827cd59751a80bed9620fb677a0", 893302), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "a13ecb4f6d8fd881ebbcc02e45cb5475", 837275), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by blackwhiteeagle in bug report #1605235 - { - "gob2", - "", - AD_ENTRY1("intro.stk", "3e4e7db0d201587dd2df4003b2993ef6"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1("intro.stk", "a13892cdf4badda85a6f6fb47603a128"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2602017 - { - "gob2", - "", - AD_ENTRY1("intro.stk", "c47faf1d406504e6ffe63243610bb1f4"), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - AD_ENTRY1("intro.stk", "cd3e1df8b273636ee32e34b7064f50e8"), - RU_RUS, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by arcepi in bug report #1659884 - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "5f53c56e3aa2f1e76c2e4f0caa15887f", 829232), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "285d7340f98ebad65d465585da12910b", 837286}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - EN_USA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "6efac0a14c0de4d57dde8592456c8acf", 845172}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - EN_USA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "", - { - {"intro.stk", 0, "6efac0a14c0de4d57dde8592456c8acf", 845172}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "24489330a1d67ff978211f574822a5a6", 883756), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob2", - "", - AD_ENTRY1s("intro.stk", "285d7340f98ebad65d465585da12910b", 837286), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2cd", - "v1.000", - AD_ENTRY1("intro.stk", "9de5fbb41cf97182109e5fecc9d90347"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by pykman in bug report #3067489 - { - "gob2cd", - "v2.01 Polish", - AD_ENTRY1s("intro.stk", "3025f05482b646c18c2c79c615a3a1df", 5011726), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2cd", - "v2.01", - AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2cd", - "v2.01", - AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2cd", - "v2.01", - AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2cd", - "v2.01", - AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2cd", - "v2.01", - AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob2cd", - "v1.02", - AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), - HU_HUN, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob2cd", - "v1.02", - AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob2cd", - "v1.02", - AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob2cd", - "v1.02", - AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob2cd", - "v1.02", - AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob2", - "Non-Interactive Demo", - AD_ENTRY1("intro.stk", "8b1c98ff2ab2e14f47a1b891e9b92217"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, "usa.tot", 0 - }, - { - { - "gob2", - "Interactive Demo", - AD_ENTRY1("intro.stk", "cf1c95b2939bd8ff58a25c756cb6125e"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob2", - "Interactive Demo", - AD_ENTRY1("intro.stk", "4b278c2678ea01383fd5ca114d947eea"), - UNK_LANG, - kPlatformAmiga, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by polluks in bug report #1895126 - { - "gob2", - "Interactive Demo", - AD_ENTRY1s("intro.stk", "9fa85aea959fa8c582085855fbd99346", 553063), - UNK_LANG, - kPlatformAmiga, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by vampir_raziel in bug report #1658373 - { - "ween", - "", - { - {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, - {"ween.ins", 0, "d2cb24292c9ddafcad07e23382027218", 87800}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by vampir_raziel in bug report #1658373 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "257fe669705ac4971efdfd5656eef16a", 457719), - FR_FRA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by vampir_raziel in bug report #1658373 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "dffd1ab98fe76150d6933329ca6f4cc4", 459458), - FR_FRA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by vampir_raziel in bug report #1658373 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "af83debf2cbea21faa591c7b4608fe92", 458192), - DE_DEU, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2563539 - { - "ween", - "", - { - {"intro.stk", 0, "dffd1ab98fe76150d6933329ca6f4cc4", 459458}, - {"ween.ins", 0, "d2cb24292c9ddafcad07e23382027218", 87800}, - {0, 0, 0, 0} - }, - IT_ITA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by pwigren in bug report #1764174 - { - "ween", - "", - { - {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, - {"music__5.snd", 0, "7d1819b9981ecddd53d3aacbc75f1cc8", 13446}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformAtariST, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "ween", - "", - AD_ENTRY1("intro.stk", "e6d13fb3b858cb4f78a8780d184d5b2c"), - FR_FRA, - kPlatformAtariST, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "ween", - "", - AD_ENTRY1("intro.stk", "2bb8878a8042244dd2b96ff682381baa"), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "ween", - "", - AD_ENTRY1s("intro.stk", "de92e5c6a8c163007ffceebef6e67f7d", 7117568), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by cybot_tmin in bug report #1667743 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "6d60f9205ecfbd8735da2ee7823a70dc", 7014426), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "ween", - "", - AD_ENTRY1("intro.stk", "4b10525a3782aa7ecd9d833b5c1d308b"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by cartman_ on #scummvm - { - "ween", - "", - AD_ENTRY1("intro.stk", "63170e71f04faba88673b3f510f9c4c8"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by glorfindel in bugreport #1722142 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "8b57cd510da8a3bbd99e3a0297a8ebd1", 7018771), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "ween", - "Demo", - AD_ENTRY1("intro.stk", "2e9c2898f6bf206ede801e3b2e7ee428"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, "show.tot", 0 - }, - { - { - "ween", - "Demo", - AD_ENTRY1("intro.stk", "15fb91a1b9b09684b28ac75edf66e504"), - EN_USA, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, "show.tot", 0 - }, - { - { - "bargon", - "", - AD_ENTRY1("intro.stk", "da3c54be18ab73fbdb32db24624a9c23"), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by Trekky in the forums - { - "bargon", - "", - AD_ENTRY1s("intro.stk", "2f54b330d21f65b04b7c1f8cca76426c", 262109), - FR_FRA, - kPlatformAtariST, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by cesardark in bug #1681649 - { - "bargon", - "", - AD_ENTRY1s("intro.stk", "11103b304286c23945560b391fd37e7d", 3181890), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by paul66 in bug #1692667 - { - "bargon", - "", - AD_ENTRY1s("intro.stk", "da3c54be18ab73fbdb32db24624a9c23", 3181825), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by pwigren in bugreport #1764174 - { - "bargon", - "", - AD_ENTRY1s("intro.stk", "569d679fe41d49972d34c9fce5930dda", 269825), - EN_ANY, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by kizkoool in bugreport #2089734 - { - "bargon", - "", - AD_ENTRY1s("intro.stk", "00f6b4e2ee26e5c40b488e2df5adcf03", 3975580), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { // Supplied by glorfindel in bugreport #1722142 - { - "bargon", - "Fanmade", - AD_ENTRY1s("intro.stk", "da3c54be18ab73fbdb32db24624a9c23", 3181825), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "0b72992f5d8b5e6e0330572a5753ea25", 256490), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - { - {"intro.stk", 0, "0b72992f5d8b5e6e0330572a5753ea25", 256490}, - {"mod.babayaga", 0, "43484cde74e0860785f8e19f0bc776d1", 60248}, - {0, 0, 0, 0} - }, - UNK_LANG, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "113a16877e4f72037d9714be1c2b0221", 1187522), - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, - { // Found in french ADI 2 Francais-Maths CM1 - { - "littlered", - "", - AD_ENTRY1s("intro.stk", "5c15b37ed27ac2470854e9e09374d50e", 1248610), - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib | kFeaturesEGA, - 0, 0, 0 - }, -// This version is not detected on purpose: it's a pirated version. -// Tagged ADGF_PIRATED! Do not re-add nor un-tag! - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "3712e7527ba8ce5637d2aadf62783005", 72318), - FR_FRA, - kPlatformPC, - ADGF_PIRATED, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "7b7f48490dedc8a7cb999388e2fadbe3", 3930674), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "e0767783ff662ed93665446665693aef", 4371238), - HE_ISR, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by cartman_ on #scummvm - { - "lit", - "", - AD_ENTRY1s("intro.stk", "f1f78b663893b58887add182a77df151", 3944090), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2105220 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "cd322cb3c64ef2ba2f2134aa2122cfe9", 3936700), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by koalet in bug report #2479034 - { - "lit", - "", - { - {"intro.stk", 0, "af98bcdc70e1f1c1635577fd726fe7f1", 3937310}, - {"musmac1.mid", 0, "ae7229bb09c6abe4e60a2768b24bc890", 9398}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2093672 - { - "lit", - "", - AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4219382), - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "", - AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4219382), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in french ADI 2.6 Francais-Maths 4e - { - "lit", - "", - AD_ENTRY1s("intro.stk", "58ee9583a4fb837f02d9a58e5f442656", 3937120), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit1", - "Full install", - { - {"intro.stk", 0, "93c91bc9e783d00033042ae83144d7dd", 72318}, - {"partie2.itk", 0, "78f00bd8eb9e680e6289bba0130b1b33", 4396644}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit1", - "Light install", - { - {"intro.stk", 0, "93c91bc9e783d00033042ae83144d7dd", 72318}, - {"partie2.itk", 0, "78f00bd8eb9e680e6289bba0130b1b33", 664064}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit2", - "Light install", - AD_ENTRY1s("intro.stk", "17acbb212e62addbe48dc8f2282c98cb", 72318), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit2", - "Full install", - { - {"intro.stk", 0, "17acbb212e62addbe48dc8f2282c98cb", 72318}, - {"partie4.itk", 0, "6ce4967e0c79d7daeabc6c1d26783d4c", 2612087}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "lit", - "Demo", - AD_ENTRY1("demo.stk", "c06f8cc20eb239d4c71f225ce3093edf"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - "demo.stk", "demo.tot", 0 - }, - { - { - "lit", - "Non-interactive Demo", - AD_ENTRY1("demo.stk", "2eba8abd9e3878c57307576012dd2fec"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - "demo.stk", "demo.tot", 0 - }, - { // Supplied by scoriae - { - "fascination", - "VGA", - AD_ENTRY1s("disk0.stk", "c14330d052fe4da5a441ac9d81bc5891", 1061955), - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "disk0.stk", 0, 0 - }, - { // Supplied by alex86r in bug report #3297633 - { - "fascination", - "VGA 3 disks edition", - AD_ENTRY1s("disk0.stk", "ab3dfdce43917bc806812959d692fc8f", 1061929), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "VGA 3 disks edition", - AD_ENTRY1s("disk0.stk", "a50a8495e1b2d67699fb562cb98fc3e2", 1064387), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "Hebrew edition (censored)", - AD_ENTRY1s("intro.stk", "d6e45ce548598727e2b5587a99718eba", 1055909), - HE_ISR, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "intro.stk", 0, 0 - }, - { // Supplied by windlepoons in bug report #2809247 - { - "fascination", - "VGA 3 disks edition", - AD_ENTRY1s("disk0.stk", "3a24e60a035250189643c86a9ceafb97", 1062480), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "VGA", - AD_ENTRY1s("disk0.stk", "e8ab4f200a2304849f462dc901705599", 183337), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesAdLib, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "", - AD_ENTRY1s("disk0.stk", "68b1c01564f774c0b640075fbad1b695", 189968), - DE_DEU, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "", - AD_ENTRY1s("disk0.stk", "7062117e9c5adfb6bfb2dac3ff74df9e", 189951), - EN_ANY, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "", - AD_ENTRY1s("disk0.stk", "55c154e5a3e8e98afebdcff4b522e1eb", 190005), - FR_FRA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "", - AD_ENTRY1s("disk0.stk", "7691827fff35df7799f14cfd6be178ad", 189931), - IT_ITA, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "", - AD_ENTRY1s("disk0.stk", "aff9fcc619f4dd19eae228affd0d34c8", 189964), - EN_ANY, - kPlatformAtariST, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { - { - "fascination", - "CD Version (Censored)", - AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOSUBTITLES) - }, - kGameTypeFascination, - kFeaturesCD, - "intro.stk", 0, 0 - }, - { - { - "fascination", - "CD Version (Censored)", - AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOSUBTITLES) - }, - kGameTypeFascination, - kFeaturesCD, - "intro.stk", 0, 0 - }, - { - { - "fascination", - "CD Version (Censored)", - AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOSUBTITLES) - }, - kGameTypeFascination, - kFeaturesCD, - "intro.stk", 0, 0 - }, - { - { - "fascination", - "CD Version (Censored)", - AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOSUBTITLES) - }, - kGameTypeFascination, - kFeaturesCD, - "intro.stk", 0, 0 - }, - { - { - "fascination", - "CD Version (Censored)", - AD_ENTRY1s("intro.stk", "9c61e9c22077f72921f07153e37ccf01", 545953), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOSUBTITLES) - }, - kGameTypeFascination, - kFeaturesCD, - "intro.stk", 0, 0 - }, - { - { - "geisha", - "", - AD_ENTRY1s("disk1.stk", "6eebbb98ad90cd3c44549fc2ab30f632", 212153), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGeisha, - kFeaturesEGA | kFeaturesAdLib, - "disk1.stk", "intro.tot", 0 - }, - { - { - "geisha", - "", - AD_ENTRY1s("disk1.stk", "f4d4d9d20f7ad1f879fc417d47faba89", 336732), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGeisha, - kFeaturesEGA | kFeaturesAdLib, - "disk1.stk", "intro.tot", 0 - }, - { - { - "geisha", - "", - AD_ENTRY1s("disk1.stk", "e5892f00917c62423e93f5fd9920cf47", 208120), - UNK_LANG, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGeisha, - kFeaturesEGA, - "disk1.stk", "intro.tot", 0 - }, - { - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "32b0f57f5ae79a9ae97e8011df38af42", 157084), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "904fc32032295baa3efb3a41f17db611", 178582), - HE_ISR, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by raziel_ in bug report #1891869 - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "16b014bf32dbd6ab4c5163c44f56fed1", 445104), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by fac76 in bug report #1742716 - { - "gob3", - "", - { - {"intro.stk", 0, "32b0f57f5ae79a9ae97e8011df38af42", 157084}, - {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "1e2f64ec8dfa89f42ee49936a27e66e7"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by paul66 in bug report #1652352 - { - "gob3", - "", - AD_ENTRY1("intro.stk", "f6d225b25a180606fa5dbe6405c97380"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "e42a4f2337d6549487a80864d7826972"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by Paranoimia on #scummvm - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "fe8144daece35538085adb59c2d29613", 159402), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "4e3af248a48a2321364736afab868527"), - RU_RUS, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "8d28ce1591b0e9cc79bf41cad0fc4c9c"), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Supplied by SiRoCs in bug report #2098621 - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "d3b72938fbbc8159198088811f9e6d19", 160382), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "bd679eafde2084d8011f247e51b5a805"), - EN_GRB, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesNone, - 0, "menu.tot", 0 - }, - { - { - "gob3", - "", - AD_ENTRY1("intro.stk", "bd679eafde2084d8011f247e51b5a805"), - DE_DEU, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesNone, - 0, "menu.tot", 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "edd7403e5dc2a14459d2665a4c17714d", 209534}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "428e2de130cf3b303c938924539dc50d", 324420}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "", - { - {"intro.stk", 0, "428e2de130cf3b303c938924539dc50d", 324420}, - {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { // Found in Found in french ADI 2.5 Anglais Multimedia 5e - { - "gob3", - "", - AD_ENTRY1s("intro.stk", "edd7403e5dc2a14459d2665a4c17714d", 209534), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3cd", - "v1.000", - AD_ENTRY1("intro.stk", "6f2c226c62dd7ab0ab6f850e89d3fc47"), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by pykman in bug report #3067489 - { - "gob3cd", - "v1.02 Polish", - AD_ENTRY1s("intro.stk", "978afddcac81bb95a04757b61f78471c", 619825), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 - { - "gob3cd", - "v1.02", - AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 - { - "gob3cd", - "v1.02", - AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 - { - "gob3cd", - "v1.02", - AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 - { - "gob3cd", - "v1.02", - AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 - { - "gob3cd", - "v1.02", - AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob3cd", - "v1.02", - AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), - HU_HUN, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob3cd", - "v1.02", - AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob3cd", - "v1.02", - AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2810082 - { - "gob3cd", - "v1.02", - AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "gob3", - "Interactive Demo", - AD_ENTRY1("intro.stk", "7aebd94e49c2c5c518c9e7b74f25de9d"), - FR_FRA, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "Interactive Demo 2", - AD_ENTRY1("intro.stk", "e5dcbc9f6658ebb1e8fe26bc4da0806d"), - FR_FRA, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "Interactive Demo 3", - AD_ENTRY1s("intro.stk", "9e20ad7b471b01f84db526da34eaf0a2", 395561), - EN_ANY, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "gob3", - "Non-interactive Demo", - AD_ENTRY1("intro.stk", "b9b898fccebe02b69c086052d5024a55"), - UNK_LANG, - kPlatformPC, - ADGF_DEMO, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesCD, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "1fa92b00fe80a20f34ec34a8e2fa869e", 923072), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), - EN_USA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), - DE_DEU, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), - IT_ITA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), - ES_ESP, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "", - AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), - FR_FRA, - kPlatformWindows, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "inca2", - "Non-Interactive Demo", - { - {"cons.imd", 0, "f896ba0c4a1ac7f7260d342655980b49", 17804}, - {"conseil.imd", 0, "aaedd5482d5b271e233e86c5a03cf62e", 33999}, - {"int.imd", 0, "6308222fcefbcb20925f01c1aff70dee", 30871}, - {"inter.imd", 0, "39bd6d3540f3bedcc97293f352c7f3fc", 191719}, - {"machu.imd", 0, "c0bc8211d93b467bfd063b63fe61b85c", 34609}, - {"post.imd", 0, "d75cad0e3fc22cb0c8b6faf597f509b2", 1047709}, - {"posta.imd", 0, "2a5b3fe75681ddf4d21ac724db8111b4", 547250}, - {"postb.imd", 0, "24260ce4e80a4c472352b76637265d09", 868312}, - {"postc.imd", 0, "24accbcc8b83a9c2be4bd82849a2bd29", 415637}, - {"tum.imd", 0, "0993d4810ec9deb3f77c5e92095320fd", 20330}, - {"tumi.imd", 0, "bf53f229480d694de0947fe3366fbec6", 248952}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeInca2, - kFeaturesAdLib | kFeaturesBATDemo, - 0, 0, 7 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "5f5f4e0a72c33391e67a47674b120cc6", 20296422), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by DjDiabolik in bug report #1971294 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by DjDiabolik in bug report #1971294 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by DjDiabolik in bug report #1971294 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by DjDiabolik in bug report #1971294 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by DjDiabolik in bug report #1971294 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2098838 - { - "woodruff", - "", - AD_ENTRY1s("intro.stk", "08a96bf061af1fa4f75c6a7cc56b60a4", 20734979), - PL_POL, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "woodruff", - "Non-Interactive Demo", - { - {"demo.scn", 0, "16bb85fc5f8e519147b60475dbf33962", 89}, - {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 1 - }, - { - { - "dynasty", - "", - AD_ENTRY1s("intro.stk", "6190e32404b672f4bbbc39cf76f41fda", 2511470), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "", - AD_ENTRY1s("intro.stk", "61e4069c16e27775a6cc6d20f529fb36", 2511300), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "", - AD_ENTRY1s("intro.stk", "61e4069c16e27775a6cc6d20f529fb36", 2511300), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "", - AD_ENTRY1s("intro.stk", "b3f8472484b7a1df94557b51e7b6fca0", 2322644), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "", - AD_ENTRY1s("intro.stk", "bdbdac8919200a5e71ffb9fb0709f704", 2446652), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "Demo", - AD_ENTRY1s("intro.stk", "464538a17ed39755d7f1ba9c751af1bd", 1847864), - EN_USA, - kPlatformPC, - ADGF_DEMO, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "dynasty", - "Demo", - AD_ENTRY1s("lda1.stk", "0e56a899357cbc0bf503260fd2dd634e", 15032774), - UNK_LANG, - kPlatformWindows, - ADGF_DEMO, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - "lda1.stk", 0, 0 - }, - { - { - "dynasty", - "Demo", - AD_ENTRY1s("lda1.stk", "8669ea2e9a8239c070dc73958fbc8753", 15567724), - DE_DEU, - kPlatformWindows, - ADGF_DEMO, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeDynasty, - kFeatures640x480, - "lda1.stk", 0, 0 - }, - { - { - "urban", - "", - AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by Collector9 in bug report #3228040 - { - "urban", - "", - AD_ENTRY1s("intro.stk", "6ce3d878178932053267237ec4843ce1", 1252518), - EN_USA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by gamin in the forums - { - "urban", - "", - AD_ENTRY1s("intro.stk", "b991ed1d31c793e560edefdb349882ef", 1276408), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by jvprat on #scummvm - { - "urban", - "", - AD_ENTRY1s("intro.stk", "4ec3c0864e2b54c5b4ccf9f6ad96528d", 1253328), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by Alex on the gobsmacked blog - { - "urban", - "", - AD_ENTRY1s("intro.stk", "9ea647085a16dd0fb9ecd84cd8778ec9", 1253436), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by alex86r in bug report #3297602 - { - "urban", - "", - AD_ENTRY1s("intro.stk", "4e4a3c017fe5475353bf94c455fe3efd", 1253448), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { // Supplied by goodoldgeorg in bug report #2770340 - { - "urban", - "", - AD_ENTRY1s("intro.stk", "4bd31979ea3d77a58a358c09000a85ed", 1253018), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { - { - "urban", - "Non-Interactive Demo", - { - {"wdemo.s24", 0, "14ac9bd51db7a075d69ddb144904b271", 87}, - {"demo.vmd", 0, "65d04715d871c292518b56dd160b0161", 9091237}, - {"urband.vmd", 0, "60343891868c91854dd5c82766c70ecc", 922461}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor | kFeaturesSCNDemo, - 0, 0, 2 - }, - { - { - "playtoons1", - "", - { - {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, - {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons1", - "Pack mes histoires anim\xE9""es", - { - {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, - {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons1", - "", - { - {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, - {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { // Supplied by scoriae in the forums - { - "playtoons1", - "", - { - {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, - {"archi.stk", 0, "00d8274519dfcf8a0d8ae3099daea0f8", 5532135}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons1", - "Non-Interactive Demo", - { - {"play123.scn", 0, "4689a31f543915e488c3bc46ea358add", 258}, - {"archi.vmd", 0, "a410fcc8116bc173f038100f5857191c", 5617210}, - {"chato.vmd", 0, "5a10e39cb66c396f2f9d8fb35e9ac016", 5445937}, - {"genedeb.vmd", 0, "3bb4a45585f88f4d839efdda6a1b582b", 1244228}, - {"generik.vmd", 0, "b46bdd64b063e86927fb2826500ad512", 603242}, - {"genespi.vmd", 0, "b7611916f32a370ae9832962fc17ef72", 758719}, - {"spirou.vmd", 0, "8513dbf7ac51c057b21d371d6b217b47", 2550788}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 3 - }, - { - { - "playtoons1", - "Non-Interactive Demo", - { - {"e.scn", 0, "8a0db733c3f77be86e74e8242e5caa61", 124}, - {"demarchg.vmd", 0, "d14a95da7d8792faf5503f649ffcbc12", 5619415}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 4 - }, - { - { - "playtoons1", - "Non-Interactive Demo", - { - {"i.scn", 0, "8b3294474d39970463663edd22341730", 285}, - {"demarita.vmd", 0, "84c8672b91c7312462603446e224bfec", 5742533}, - {"dembouit.vmd", 0, "7a5fdf0a4dbdfe72e31dd489ea0f8aa2", 3536786}, - {"demo5.vmd", 0, "2abb7b6a26406c984f389f0b24b5e28e", 13290970}, - {"demoita.vmd", 0, "b4c0622d14c8749965cd0f5dfca4cf4b", 1183566}, - {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, - {0, 0, 0, 0} - }, - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 5 - }, - { - { - "playtoons1", - "Non-Interactive Demo", - { - {"s.scn", 0, "1f527010626b5490761f16ba7a6f639a", 251}, - {"demaresp.vmd", 0, "3f860f944056842b35a5fd05416f208e", 5720619}, - {"demboues.vmd", 0, "3a0caa10c98ef92a15942f8274075b43", 3535838}, - {"demo5.vmd", 0, "2abb7b6a26406c984f389f0b24b5e28e", 13290970}, - {"wooddem3.vmd", 0, "a1700596172c2d4e264760030c3a3d47", 8994250}, - {0, 0, 0, 0} - }, - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 6 - }, - { - { - "playtoons2", - "", - { - {"playtoon.stk", 0, "4772c96be88a57f0561519e4a1526c62", 24406262}, - {"spirou.stk", 0, "5d9c7644d0c47840169b4d016765cc1a", 9816201}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons2", - "", - { - {"playtoon.stk", 0, "55a85036dd93cce93532d8f743d90074", 17467154}, - {"spirou.stk", 0, "e3e1b6148dd72fafc3637f1a8e5764f5", 9812043}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons2", - "", - { - {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, - {"spirou.stk", 0, "91080dc148de1bbd6a97321c1a1facf3", 9817086}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { // Supplied by Hkz - { - "playtoons2", - "", - { - {"playtoon.stk", 0, "2572685400852d12759a2fbf09ec88eb", 9698780}, - {"spirou.stk", 0, "d3cfeff920b6343a2ece55088f530dba", 7076608}, - {0, 0, 0, 0} - }, - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { // Supplied by scoriae in the forums - { - "playtoons2", - "", - { - {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, - {"spirou.stk", 0, "993737f112ca6a9b33c814273280d832", 9825760}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons3", - "", - { - {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, - {"chato.stk", 0, "4fa4ed96a427c344e9f916f9f236598d", 6033793}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons3", - "", - { - {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, - {"chato.stk", 0, "8fc8d0da5b3e758908d1d7298d497d0b", 6041026}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons3", - "Pack mes histoires anim\xE9""es", - { - {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, - {"chato.stk", 0, "4fa4ed96a427c344e9f916f9f236598d", 6033793}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons3", - "", - { - {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, - {"chato.stk", 0, "3c6cb3ac8a5a7cf681a19971a92a748d", 6033791}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { // Supplied by Hkz on #scummvm - { - "playtoons3", - "", - { - {"playtoon.stk", 0, "4772c96be88a57f0561519e4a1526c62", 24406262}, - {"chato.stk", 0, "bdef407387112bfcee90e664865ac3af", 6033867}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons4", - "", - { - {"playtoon.stk", 0, "b7f5afa2dc1b0f75970b7c07d175db1b", 24340406}, - {"manda.stk", 0, "92529e0b927191d9898a34c2892e9a3a", 6485072}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { //Supplied by goodoldgeorg in bug report #2820006 - { - "playtoons4", - "", - { - {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, - {"manda.stk", 0, "69a79c9f61b2618e482726f2ff68078d", 6499208}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtoons5", - "", - { - {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, - {"wakan.stk", 0, "f493bf82851bc5ba74d57de6b7e88df8", 5520153}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "bambou", - "", - { - {"intro.stk", 0, "2f8db6963ff8d72a8331627ebda918f4", 3613238}, - {"bambou.itk", 0, "0875914d31126d0749313428f10c7768", 114440192}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeBambou, - kFeatures640x480, - "intro.stk", "intro.tot", 0 - }, - { - { - "playtnck1", - "", - { - {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, - {"dan.itk", 0, "906d67b3e438d5e95ec7ea9e781a94f3", 3000320}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtnck2", - "", - { - {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, - {"dan.itk", 0, "74eeb075bd2cb47b243349730264af01", 3213312}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "playtnck3", - "", - { - {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, - {"dan.itk", 0, "9a8f62809eca5a52f429b5b6a8e70f8f", 2861056}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - "intro2.stk", 0, 0 - }, - { - { - "adi2", - "Adi 2.0 for Teachers", - AD_ENTRY1s("adi2.stk", "da6f1fb68bff32260c5eecdf9286a2f5", 1533168), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdi2, - kFeaturesNone, - "adi2.stk", "ediintro.tot", 0 - }, - { // Found in french ADI 2 Francais-Maths CM1. Exact version not specified. - { - "adi2", - "Adi 2", - AD_ENTRY1s("adi2.stk", "23f279615c736dc38320f1348e70c36e", 10817668), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { // Found in french ADI 2 Francais-Maths CE2. Exact version not specified. - { - "adi2", - "Adi 2", - AD_ENTRY1s("adi2.stk", "d4162c4298f9423ecc1fb04965557e90", 11531214), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2", - AD_ENTRY1s("adi2.stk", "29694c5a649298a42f87ae731d6d6f6d", 311132), - EN_ANY, - kPlatformAmiga, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdi2, - kFeaturesNone, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2", - AD_ENTRY1s("adi2.stk", "2a40bb48ccbd4e6fb3f7f0fc2f069d80", 17720132), - ES_ESP, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2.5", - AD_ENTRY1s("adi2.stk", "fcac60e6627f37aee219575b60859de9", 16944268), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2.5", - AD_ENTRY1s("adi2.stk", "072d5e2d7826a7c055865568ebf918bb", 16934596), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2.6", - AD_ENTRY1s("adi2.stk", "2fb940eb8105b12871f6b88c8c4d1615", 16780058), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2.6", - AD_ENTRY1s("adi2.stk", "fde7d98a67dbf859423b6473796e932a", 18044780), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Adi 2.7.1", - AD_ENTRY1s("adi2.stk", "6fa5dffebf5c7243c6af6b8c188ee00a", 19278008), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", "ediintro.tot", 0 - }, - { - { - "adi2", - "Non-Interactive Demo", - { - {"demo.scn", 0, "8b5ba359fd87d586ad39c1754bf6ea35", 168}, - {"demadi2t.vmd", 0, "08a1b18cfe2015d3b43270da35cc813d", 7250723}, - {"demarch.vmd", 0, "4c4a4616585d40ef3df209e3c3911062", 5622731}, - {"demobou.vmd", 0, "2208b9855775564d15c4a5a559da0aec", 3550511}, - {0, 0, 0, 0} - }, - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 1 - }, - { - { - "adi4", - "Addy 4 Grundschule Basis CD", - AD_ENTRY1s("intro.stk", "d2f0fb8909e396328dc85c0e29131ba8", 5847588), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Addy 4 Sekundarstufe Basis CD", - AD_ENTRY1s("intro.stk", "367340e59c461b4fa36651cd74e32c4e", 5847378), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0", - AD_ENTRY1s("intro.stk", "a3c35d19b2d28ea261d96321d208cb5a", 6021466), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0", - AD_ENTRY1s("intro.stk", "44491d85648810bc6fcf84f9b3aa47d5", 5834944), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0", - AD_ENTRY1s("intro.stk", "29374c0e3c10b17dd8463b06a55ad093", 6012072), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0 Limited Edition", - AD_ENTRY1s("intro.stk", "ebbbc5e28a4adb695535ed989c1b8d66", 5929644), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "ADI 4.10", - AD_ENTRY1s("intro.stk", "3e3fa9656e37d802027635ace88c4cc5", 5359144), - EN_GRB, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adi4", - "ADI 4.10", - AD_ENTRY1s("intro.stk", "6afc2590856433b9f5295b032f2b205d", 5923112), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adi4", - "ADI 4.11", - AD_ENTRY1s("intro.stk", "6296e4be4e0c270c24d1330881900c7f", 5921234), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adi4", - "Addy 4.21", - AD_ENTRY1s("intro.stk", "534f0b674cd4830df94a9c32c4ea7225", 6878034), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "ADI 4.21", - AD_ENTRY1s("intro.stk", "c5b9f6222c0b463f51dab47317c5b687", 5950490), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0 Interactive Demo", - AD_ENTRY1s("intro.stk", "89ace204dbaac001425c73f394334f6f", 2413102), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "adi4", - "Adi 4.0 / Adibou 2 Demo", - AD_ENTRY1s("intro.stk", "d41d8cd98f00b204e9800998ecf8427e", 0), - FR_FRA, - kPlatformPC, - ADGF_DEMO, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - 0, 0, 0 - }, - { - { - "ajworld", - "", - AD_ENTRY1s("intro.stk", "e453bea7b28a67c930764d945f64d898", 3913628), - EN_ANY, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "adibou1", - "ADIBOU 1 Environnement 4-7 ans", - AD_ENTRY1s("intro.stk", "6db110188fcb7c5208d9721b5282682a", 4805104), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeAdibou1, - kFeaturesAdLib, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2", - AD_ENTRY1s("intro.stk", "94ae7004348dc8bf99c23a9a6ef81827", 956162), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "Le Jardin Magique d'Adibou", - AD_ENTRY1s("intro.stk", "a8ff86f3cc40dfe5898e0a741217ef27", 956328), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2", - AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), - DE_DEU, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIB\xD9 2", - AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), - IT_ITA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU Version Decouverte", - AD_ENTRY1s("intro.stk", "558c14327b79ed39214b49d567a75e33", 8737856), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2.10 Environnement", - AD_ENTRY1s("intro.stk", "f2b797819aeedee557e904b0b5ccd82e", 8736454), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2.11 Environnement", - AD_ENTRY1s("intro.stk", "7b1f1f6f6477f54401e95d913f75e333", 8736904), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2.12 Environnement", - AD_ENTRY1s("intro.stk", "1e49c39a4a3ce6032a84b712539c2d63", 8738134), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOU 2.13s Environnement", - AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "ADIBOO 2.14 Environnement", - AD_ENTRY1s("intro.stk", "ff63637e3cb7f0a457edf79457b1c6b3", 9333874), - FR_FRA, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO0() - }, - kGameTypeAdibou2, - kFeaturesNone, - 0, 0, 0 - }, - { - { - "adibou2", - "Non-Interactive Demo", - { - {"demogb.scn", 0, "9291455a908ac0e6aaaca686e532609b", 105}, - {"demogb.vmd", 0, "bc9c1db97db7bec8f566332444fa0090", 14320840}, - {0, 0, 0, 0} - }, - EN_GRB, - kPlatformPC, - ADGF_DEMO, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdibou2, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 9 - }, - { - { - "adibou2", - "Non-Interactive Demo", - { - {"demoall.scn", 0, "c8fd308c037b829800006332b2c32674", 106}, - {"demoall.vmd", 0, "4672b2deacc6fca97484840424b1921b", 14263433}, - {0, 0, 0, 0} - }, - DE_DEU, - kPlatformPC, - ADGF_DEMO, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdibou2, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 10 - }, - { - { - "adibou2", - "Non-Interactive Demo", - { - {"demofra.scn", 0, "d1b2b1618af384ea1120def8b986c02b", 106}, - {"demofra.vmd", 0, "b494cdec1aac7e54c3f2480512d2880e", 14297100}, - {0, 0, 0, 0} - }, - FR_FRA, - kPlatformPC, - ADGF_DEMO, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdibou2, - kFeatures640x480 | kFeaturesSCNDemo, - 0, 0, 11 - }, - { AD_TABLE_END_MARKER, kGameTypeNone, kFeaturesNone, 0, 0, 0} -}; - -static const GOBGameDescription fallbackDescs[] = { - { //0 - { - "gob1", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesNone, - 0, 0, 0 - }, - { //1 - { - "gob1cd", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob1, - kFeaturesCD, - 0, 0, 0 - }, - { //2 - { - "gob2", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { //3 - { - "gob2mac", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesAdLib, - 0, 0, 0 - }, - { //4 - { - "gob2cd", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob2, - kFeaturesCD, - 0, 0, 0 - }, - { //5 - { - "bargon", - "", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeBargon, - kFeaturesNone, - 0, 0, 0 - }, - { //6 - { - "gob3", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesAdLib, - 0, 0, 0 - }, - { //7 - { - "gob3cd", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGob3, - kFeaturesCD, - 0, 0, 0 - }, - { //8 - { - "woodruff", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeWoodruff, - kFeatures640x480, - 0, 0, 0 - }, - { //9 - { - "lostintime", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { //10 - { - "lostintime", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformMacintosh, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesAdLib, - 0, 0, 0 - }, - { //11 - { - "lostintime", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeLostInTime, - kFeaturesCD, - 0, 0, 0 - }, - { //12 - { - "urban", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeatures640x480 | kFeaturesTrueColor, - 0, 0, 0 - }, - { //13 - { - "playtoons1", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //14 - { - "playtoons2", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //15 - { - "playtoons3", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //16 - { - "playtoons4", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //17 - { - "playtoons5", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //18 - { - "playtoons construction kit", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypePlaytoons, - kFeatures640x480, - 0, 0, 0 - }, - { //19 - { - "bambou", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeBambou, - kFeatures640x480, - 0, 0, 0 - }, - { //20 - { - "fascination", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeFascination, - kFeaturesNone, - "disk0.stk", 0, 0 - }, - { //21 - { - "geisha", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeGeisha, - kFeaturesEGA, - "disk1.stk", "intro.tot", 0 - }, - { //22 - { - "adi2", - "", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdi2, - kFeatures640x480, - "adi2.stk", 0, 0 - }, - { //23 - { - "adi4", - "", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT) - }, - kGameTypeAdi4, - kFeatures640x480, - "adif41.stk", 0, 0 - }, - { //24 - { - "coktelplayer", - "unknown", - AD_ENTRY1(0, 0), - UNK_LANG, - kPlatformPC, - ADGF_NO_FLAGS, - GUIO1(GUIO_NOASPECT) - }, - kGameTypeUrban, - kFeaturesAdLib | kFeatures640x480 | kFeaturesSCNDemo, - "", "", 8 - } -}; - -static const ADFileBasedFallback fileBased[] = { - { &fallbackDescs[ 0].desc, { "intro.stk", "disk1.stk", "disk2.stk", "disk3.stk", "disk4.stk", 0 } }, - { &fallbackDescs[ 1].desc, { "intro.stk", "gob.lic", 0 } }, - { &fallbackDescs[ 2].desc, { "intro.stk", 0 } }, - { &fallbackDescs[ 2].desc, { "intro.stk", "disk2.stk", "disk3.stk", 0 } }, - { &fallbackDescs[ 3].desc, { "intro.stk", "disk2.stk", "disk3.stk", "musmac1.mid", 0 } }, - { &fallbackDescs[ 4].desc, { "intro.stk", "gobnew.lic", 0 } }, - { &fallbackDescs[ 5].desc, { "intro.stk", "scaa.imd", "scba.imd", "scbf.imd", 0 } }, - { &fallbackDescs[ 6].desc, { "intro.stk", "imd.itk", 0 } }, - { &fallbackDescs[ 7].desc, { "intro.stk", "mus_gob3.lic", 0 } }, - { &fallbackDescs[ 8].desc, { "intro.stk", "woodruff.itk", 0 } }, - { &fallbackDescs[ 9].desc, { "intro.stk", "commun1.itk", 0 } }, - { &fallbackDescs[10].desc, { "intro.stk", "commun1.itk", "musmac1.mid", 0 } }, - { &fallbackDescs[11].desc, { "intro.stk", "commun1.itk", "lost.lic", 0 } }, - { &fallbackDescs[12].desc, { "intro.stk", "cd1.itk", "objet1.itk", 0 } }, - { &fallbackDescs[13].desc, { "playtoon.stk", "archi.stk", 0 } }, - { &fallbackDescs[14].desc, { "playtoon.stk", "spirou.stk", 0 } }, - { &fallbackDescs[15].desc, { "playtoon.stk", "chato.stk", 0 } }, - { &fallbackDescs[16].desc, { "playtoon.stk", "manda.stk", 0 } }, - { &fallbackDescs[17].desc, { "playtoon.stk", "wakan.stk", 0 } }, - { &fallbackDescs[18].desc, { "playtoon.stk", "dan.itk" } }, - { &fallbackDescs[19].desc, { "intro.stk", "bambou.itk", 0 } }, - { &fallbackDescs[20].desc, { "disk0.stk", "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, - { &fallbackDescs[21].desc, { "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, - { &fallbackDescs[22].desc, { "adi2.stk", 0 } }, - { &fallbackDescs[23].desc, { "adif41.stk", "adim41.stk", 0 } }, - { &fallbackDescs[24].desc, { "coktelplayer.scn", 0 } }, - { 0, { 0 } } -}; - -} diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 4b659f51de..8c6919416d 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -117,6 +117,15 @@ Draw::Draw(GobEngine *vm) : _vm(vm) { _cursorAnimDelays[i] = 0; } + _cursorCount = 0; + _doCursorPalettes = 0; + _cursorPalettes = 0; + _cursorKeyColors = 0; + _cursorPaletteStarts = 0; + _cursorPaletteCounts = 0; + _cursorHotspotsX = 0; + _cursorHotspotsY = 0; + _palLoadData1[0] = 0; _palLoadData1[1] = 17; _palLoadData1[2] = 34; @@ -134,6 +143,14 @@ Draw::Draw(GobEngine *vm) : _vm(vm) { } Draw::~Draw() { + delete[] _cursorPalettes; + delete[] _doCursorPalettes; + delete[] _cursorKeyColors; + delete[] _cursorPaletteStarts; + delete[] _cursorPaletteCounts; + delete[] _cursorHotspotsX; + delete[] _cursorHotspotsY; + for (int i = 0; i < kFontCount; i++) delete _fonts[i]; } @@ -239,7 +256,7 @@ void Draw::blitInvalidated() { if (_cursorIndex == 4) blitCursor(); - if (_vm->_inter->_terminate) + if (_vm->_inter && _vm->_inter->_terminate) return; if (_noInvalidated && !_applyPal) @@ -254,7 +271,9 @@ void Draw::blitInvalidated() { return; } - _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1); + if (_cursorSprites) + _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1); + if (_applyPal) { clearPalette(); forceBlit(); @@ -408,28 +427,13 @@ int Draw::stringLength(const char *str, uint16 fontIndex) { return len; } -void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, - int16 transp, Surface &dest, const Font &font) { - - while (*str != '\0') { - const int16 charRight = x + font.getCharWidth(*str); - const int16 charBottom = y + font.getCharHeight(); - - if ((charRight <= dest.getWidth()) && (charBottom <= dest.getHeight())) - font.drawLetter(dest, *str, x, y, color1, color2, transp); - - x += font.getCharWidth(*str); - str++; - } -} - void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, int16 bottom, const char *str, int16 fontIndex, int16 color) { adjustCoords(1, &left, &top); adjustCoords(1, &right, &bottom); - uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter); + uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0; if (centerOffset != 0) { _vm->_game->_script->call(centerOffset); @@ -488,7 +492,7 @@ void Draw::oPlaytoons_sub_F_1B(uint16 id, int16 left, int16 top, int16 right, in adjustCoords(1, &left, &top); adjustCoords(1, &right, &bottom); - uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter); + uint16 centerOffset = _vm->_game->_script ? _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter) : 0; if (centerOffset != 0) { _vm->_game->_script->call(centerOffset); diff --git a/engines/gob/draw.h b/engines/gob/draw.h index 393822c33a..b51c6466e0 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -32,7 +32,8 @@ namespace Gob { #define RENDERFLAG_COLLISIONS 0x0004 #define RENDERFLAG_CAPTUREPOP 0x0008 #define RENDERFLAG_USEDELTAS 0x0010 -#define RENDERFLAG_UNKNOWN 0x0080 +#define RENDERFLAG_BORDERHOTSPOTS 0x0040 +#define RENDERFLAG_HASWINDOWS 0x0080 #define RENDERFLAG_NOBLITINVALIDATED 0x0200 #define RENDERFLAG_NOSUBTITLES 0x0400 #define RENDERFLAG_FROMSPLIT 0x0800 @@ -145,6 +146,15 @@ public: int8 _cursorAnimHigh[40]; int8 _cursorAnimDelays[40]; + int32 _cursorCount; + bool *_doCursorPalettes; + byte *_cursorPalettes; + byte *_cursorKeyColors; + uint16 *_cursorPaletteStarts; + uint16 *_cursorPaletteCounts; + int32 *_cursorHotspotsX; + int32 *_cursorHotspotsY; + int16 _palLoadData1[4]; int16 _palLoadData2[4]; @@ -184,8 +194,6 @@ public: adjustCoords(adjust, (int16 *)coord1, (int16 *)coord2); } int stringLength(const char *str, uint16 fontIndex); - void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, - int16 transp, Surface &dest, const Font &font); void printTextCentered(int16 id, int16 left, int16 top, int16 right, int16 bottom, const char *str, int16 fontIndex, int16 color); void oPlaytoons_sub_F_1B( uint16 id, int16 left, int16 top, int16 right, int16 bottom, char *paramStr, int16 var3, int16 var4, int16 shortId); @@ -249,6 +257,8 @@ public: private: uint8 _mayorWorkaroundStatus; + + void fixLittleRedStrings(); }; class Draw_Bargon: public Draw_v2 { diff --git a/engines/gob/draw_fascin.cpp b/engines/gob/draw_fascin.cpp index 69e04f74c9..12009d7ee5 100644 --- a/engines/gob/draw_fascin.cpp +++ b/engines/gob/draw_fascin.cpp @@ -222,8 +222,8 @@ void Draw_Fascination::spriteOperation(int16 operation) { _destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency); } } else { - drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor, - _backColor, _transparency, *_spritesArray[_destSurface], *font); + font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor, + _backColor, _transparency, *_spritesArray[_destSurface]); _destSpriteX += len * font->getCharWidth(); } } else { @@ -747,7 +747,7 @@ int16 Draw_Fascination::openWin(int16 id) { int16 Draw_Fascination::getWinFromCoord(int16 &dx, int16 &dy) { int16 bestMatch = -1; - if ((_renderFlags & 128) == 0) + if (!(_renderFlags & RENDERFLAG_HASWINDOWS)) return -1; for (int i = 0; i < 10; i++) { @@ -790,7 +790,7 @@ int16 Draw_Fascination::handleCurWin() { int8 matchNum = 0; int16 bestMatch = -1; - if ((_vm->_game->_mouseButtons != 1) || ((_renderFlags & 128) == 0)) + if ((_vm->_game->_mouseButtons != 1) || !(_renderFlags & RENDERFLAG_HASWINDOWS)) return 0; for (int i = 0; i < 10; i++) { diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp index a443f81ccf..76e2ae591c 100644 --- a/engines/gob/draw_playtoons.cpp +++ b/engines/gob/draw_playtoons.cpp @@ -283,8 +283,8 @@ void Draw_Playtoons::spriteOperation(int16 operation) { _destSpriteX, _destSpriteY, _frontColor, _backColor, _transparency); } } else { - drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor, - _backColor, _transparency, *_spritesArray[_destSurface], *font); + font->drawString(_textToPrint, _destSpriteX, _destSpriteY, _frontColor, + _backColor, _transparency, *_spritesArray[_destSurface]); _destSpriteX += len * font->getCharWidth(); } } else { diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index fb15fdbc19..878c1dc265 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -123,7 +123,7 @@ void Draw_v1::animateCursor(int16 cursor) { (cursorIndex + 1) * _cursorWidth - 1, _cursorHeight - 1, 0, 0); CursorMan.replaceCursor(_scummvmCursor->getData(), - _cursorWidth, _cursorHeight, hotspotX, hotspotY, 0, 1, &_vm->getPixelFormat()); + _cursorWidth, _cursorHeight, hotspotX, hotspotY, 0, false, &_vm->getPixelFormat()); if (_frontSurface != _backSurface) { _showCursor = 3; diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 78702f2ec9..f5475278c4 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -74,16 +74,19 @@ void Draw_v2::closeScreen() { } void Draw_v2::blitCursor() { - if (_cursorIndex == -1) + if (!_cursorSprites || (_cursorIndex == -1)) return; _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1); } void Draw_v2::animateCursor(int16 cursor) { + if (!_cursorSprites) + return; + int16 cursorIndex = cursor; int16 newX = 0, newY = 0; - uint16 hotspotX = 0, hotspotY = 0; + uint16 hotspotX, hotspotY; _showCursor |= 1; @@ -133,27 +136,42 @@ void Draw_v2::animateCursor(int16 cursor) { } // '------ - newX = _vm->_global->_inter_mouseX; - newY = _vm->_global->_inter_mouseY; + hotspotX = 0; + hotspotY = 0; + if (_cursorHotspotXVar != -1) { - newX -= hotspotX = (uint16) VAR(_cursorIndex + _cursorHotspotXVar); - newY -= hotspotY = (uint16) VAR(_cursorIndex + _cursorHotspotYVar); + hotspotX = (uint16) VAR(_cursorIndex + _cursorHotspotXVar); + hotspotY = (uint16) VAR(_cursorIndex + _cursorHotspotYVar); } else if (_cursorHotspotX != -1) { - newX -= hotspotX = _cursorHotspotX; - newY -= hotspotY = _cursorHotspotY; + hotspotX = _cursorHotspotX; + hotspotY = _cursorHotspotY; + } else if (_cursorHotspotsX != 0) { + hotspotX = _cursorHotspotsX[_cursorIndex]; + hotspotY = _cursorHotspotsY[_cursorIndex]; } + newX = _vm->_global->_inter_mouseX - hotspotX; + newY = _vm->_global->_inter_mouseY - hotspotY; + _scummvmCursor->clear(); _scummvmCursor->blit(*_cursorSprites, cursorIndex * _cursorWidth, 0, (cursorIndex + 1) * _cursorWidth - 1, _cursorHeight - 1, 0, 0); - if ((_vm->getGameType() != kGameTypeAdibou2) && - (_vm->getGameType() != kGameTypeAdi2) && - (_vm->getGameType() != kGameTypeAdi4)) - CursorMan.replaceCursor(_scummvmCursor->getData(), - _cursorWidth, _cursorHeight, hotspotX, hotspotY, 0, 1, &_vm->getPixelFormat()); + uint32 keyColor = 0; + if (_doCursorPalettes && _cursorKeyColors && _doCursorPalettes[cursorIndex]) + keyColor = _cursorKeyColors[cursorIndex]; + + CursorMan.replaceCursor(_scummvmCursor->getData(), + _cursorWidth, _cursorHeight, hotspotX, hotspotY, keyColor, false, &_vm->getPixelFormat()); + + if (_doCursorPalettes && _doCursorPalettes[cursorIndex]) { + CursorMan.replaceCursorPalette(_cursorPalettes + (cursorIndex * 256 * 3), + _cursorPaletteStarts[cursorIndex], _cursorPaletteCounts[cursorIndex]); + CursorMan.disableCursorPalette(false); + } else + CursorMan.disableCursorPalette(true); if (_frontSurface != _backSurface) { if (!_noInvalidated) { @@ -790,6 +808,10 @@ void Draw_v2::spriteOperation(int16 operation) { break; case DRAW_PRINTTEXT: + // WORKAROUND: There's mistakes in Little Red's animal names. + // See this function for details. + fixLittleRedStrings(); + len = strlen(_textToPrint); left = _destSpriteX; @@ -812,8 +834,8 @@ void Draw_v2::spriteOperation(int16 operation) { getColor(_backColor), _transparency); } } else { - drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor), - getColor(_backColor), _transparency, *_spritesArray[_destSurface], *font); + font->drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor), + getColor(_backColor), _transparency, *_spritesArray[_destSurface]); _destSpriteX += len * font->getCharWidth(); } } else { @@ -918,4 +940,39 @@ void Draw_v2::spriteOperation(int16 operation) { } } +/* WORKAROUND: Fix wrong German animal names in Once Upon A Time: Little Red Riding Hood. + * + * The DOS, Amiga and Atari version of Little Red come with a small screen, accessible + * through the main menu, that lets children read and listen to animal names in 5 + * languages: French, German, English, Spanish and Italian. + * Unfortunately, the German names are partially wrong. This is especially tragic + * because this is a game for small children and they're supposed to learn something + * here. We fix this. + * + * However, there's also problems with the recorded spoken German names: + * - "Der Rabe" has a far too short "a", sounding more like "Rabbe" + * - The wrong article for "Schmetterling" is very audible + * - In general, the words are way too overpronounced + * These are, of course, way harder to fix. + */ + +static const char *kLittleRedStrings[][2] = { + {"die Heule" , "die Eule"}, + {"das Schmetterling" , "der Schmetterling"}, + {"die Vespe" , "die Wespe"}, + {"das Eich\224rnchen" , "das Eichh\224rnchen"} +}; + +void Draw_v2::fixLittleRedStrings() { + if (!_textToPrint || (_vm->getGameType() != kGameTypeLittleRed)) + return; + + for (int i = 0; i < ARRAYSIZE(kLittleRedStrings); i++) { + if (!strcmp(_textToPrint, kLittleRedStrings[i][0])) { + _textToPrint = kLittleRedStrings[i][1]; + return; + } + } +} + } // End of namespace Gob diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index 502a440005..de0c3f2d5c 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -64,7 +64,7 @@ void Environments::clear() { // Deleting unique variables, script and resources for (uint i = 0; i < kEnvironmentCount; i++) { - if (_environments[i].variables == _vm->_inter->_variables) + if (_vm->_inter && (_environments[i].variables == _vm->_inter->_variables)) continue; if (!has(_environments[i].variables, i + 1)) @@ -167,6 +167,13 @@ bool Environments::has(Resources *resources, uint8 startEnv, int16 except) const return false; } +void Environments::deleted(Variables *variables) { + for (uint i = 0; i < kEnvironmentCount; i++) { + if (_environments[i].variables == variables) + _environments[i].variables = 0; + } +} + bool Environments::clearMedia(uint8 env) { if (env >= kEnvironmentCount) return false; @@ -947,6 +954,10 @@ void Game::switchTotSub(int16 index, int16 function) { _environments.get(_curEnvironment); } +void Game::deletedVars(Variables *variables) { + _environments.deleted(variables); +} + void Game::clearUnusedEnvironment() { if (!_environments.has(_script)) { delete _script; diff --git a/engines/gob/game.h b/engines/gob/game.h index b3057ac262..995baa5629 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -52,6 +52,8 @@ public: bool has(Script *script , uint8 startEnv = 0, int16 except = -1) const; bool has(Resources *resources, uint8 startEnv = 0, int16 except = -1) const; + void deleted(Variables *variables); + void clear(); bool setMedia(uint8 env); @@ -169,6 +171,8 @@ public: void totSub(int8 flags, const Common::String &totFile); void switchTotSub(int16 index, int16 function); + void deletedVars(Variables *variables); + bool loadFunctions(const Common::String &tot, uint16 flags); bool callFunction(const Common::String &tot, const Common::String &function, int16 param); diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index 1264c09860..87656a5fad 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -111,7 +111,6 @@ Global::Global(GobEngine *vm) : _vm(vm) { _dontSetPalette = false; _debugFlag = 0; - _inVM = 0; _inter_animDataSize = 10; diff --git a/engines/gob/global.h b/engines/gob/global.h index fa2f2c9637..175331dd83 100644 --- a/engines/gob/global.h +++ b/engines/gob/global.h @@ -127,7 +127,6 @@ public: SurfacePtr _primarySurfDesc; int16 _debugFlag; - int16 _inVM; int16 _inter_animDataSize; diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 4e7aa467b5..fcf98f0355 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -48,6 +48,10 @@ #include "gob/videoplayer.h" #include "gob/save/saveload.h" +#include "gob/pregob/pregob.h" +#include "gob/pregob/onceupon/abracadabra.h" +#include "gob/pregob/onceupon/babayaga.h" + namespace Gob { #define MAX_TIME_DELTA 100 @@ -115,7 +119,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst), _rnd("gob") { _vidPlayer = 0; _init = 0; _inter = 0; _map = 0; _palAnim = 0; _scenery = 0; _draw = 0; _util = 0; _video = 0; - _saveLoad = 0; + _saveLoad = 0; _preGob = 0; _pauseStart = 0; @@ -180,6 +184,10 @@ void GobEngine::validateVideoMode(int16 videoMode) { error("Video mode 0x%X is not supported", videoMode); } +EndiannessMethod GobEngine::getEndiannessMethod() const { + return _endiannessMethod; +} + Endianness GobEngine::getEndianness() const { if ((getPlatform() == Common::kPlatformAmiga) || (getPlatform() == Common::kPlatformMacintosh) || @@ -233,6 +241,10 @@ bool GobEngine::isDemo() const { return (isSCNDemo() || isBATDemo()); } +bool GobEngine::hasResourceSizeWorkaround() const { + return _resourceSizeWorkaround; +} + bool GobEngine::isCurrentTot(const Common::String &tot) const { return _game->_curTotFile.equalsIgnoreCase(tot); } @@ -270,15 +282,15 @@ void GobEngine::setTrueColor(bool trueColor) { } Common::Error GobEngine::run() { - if (!initGameParts()) { - GUIErrorMessage("GobEngine::init(): Unknown version of game engine"); - return Common::kUnknownError; - } + Common::Error err; - if (!initGraphics()) { - GUIErrorMessage("GobEngine::init(): Failed to set up graphics"); - return Common::kUnknownError; - } + err = initGameParts(); + if (err.getCode() != Common::kNoError) + return err; + + err = initGraphics(); + if (err.getCode() != Common::kNoError) + return err; // On some systems it's not safe to run CD audio games from the CD. if (isCD()) @@ -364,11 +376,12 @@ void GobEngine::pauseEngineIntern(bool pause) { _game->_startTimeKey += duration; _draw->_cursorTimeKey += duration; - if (_inter->_soundEndTimeKey != 0) + if (_inter && (_inter->_soundEndTimeKey != 0)) _inter->_soundEndTimeKey += duration; } - _vidPlayer->pauseAll(pause); + if (_vidPlayer) + _vidPlayer->pauseAll(pause); _mixer->pauseAll(pause); } @@ -388,10 +401,13 @@ void GobEngine::pauseGame() { pauseEngineIntern(false); } -bool GobEngine::initGameParts() { +Common::Error GobEngine::initGameParts() { + _resourceSizeWorkaround = false; + // just detect some devices some of which will be always there if the music is not disabled _noMusic = MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB)) == MT_NULL ? true : false; - _saveLoad = 0; + + _endiannessMethod = kEndiannessMethodSystem; _global = new Global(this); _util = new Util(this); @@ -423,6 +439,8 @@ bool GobEngine::initGameParts() { _goblin = new Goblin_v1(this); _scenery = new Scenery_v1(this); _saveLoad = new SaveLoad_Geisha(this, _targetName.c_str()); + + _endiannessMethod = kEndiannessMethodAltFile; break; case kGameTypeFascination: @@ -462,6 +480,33 @@ bool GobEngine::initGameParts() { _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; + case kGameTypeLittleRed: + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_LittleRed(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + + // WORKAROUND: Little Red Riding Hood has a small resource size glitch in the + // screen where Little Red needs to find the animals' homes. + _resourceSizeWorkaround = true; + break; + + case kGameTypeAJWorld: + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_AJWorld(this, _targetName.c_str()); + break; + case kGameTypeGob3: _init = new Init_v3(this); _video = new Video_v2(this); @@ -572,20 +617,45 @@ bool GobEngine::initGameParts() { _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; + + case kGameTypeAbracadabra: + _init = new Init_v2(this); + _video = new Video_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _preGob = new OnceUpon::Abracadabra(this); + break; + + case kGameTypeBabaYaga: + _init = new Init_v2(this); + _video = new Video_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _preGob = new OnceUpon::BabaYaga(this); + break; + default: deinitGameParts(); - return false; + return Common::kUnsupportedGameidError; } // Setup mixer syncSoundSettings(); - _inter->setupOpcodes(); + if (_inter) + _inter->setupOpcodes(); - return true; + return Common::kNoError; } void GobEngine::deinitGameParts() { + delete _preGob; _preGob = 0; delete _saveLoad; _saveLoad = 0; delete _mult; _mult = 0; delete _vidPlayer; _vidPlayer = 0; @@ -604,10 +674,10 @@ void GobEngine::deinitGameParts() { delete _dataIO; _dataIO = 0; } -bool GobEngine::initGraphics() { +Common::Error GobEngine::initGraphics() { if (is800x600()) { warning("GobEngine::initGraphics(): 800x600 games currently unsupported"); - return false; + return Common::kUnsupportedGameidError; } else if (is640x480()) { _width = 640; _height = 480; @@ -631,7 +701,7 @@ bool GobEngine::initGraphics() { _global->_primarySurfDesc = SurfacePtr(new Surface(_width, _height, _pixelFormat.bytesPerPixel)); - return true; + return Common::kNoError; } } // End of namespace Gob diff --git a/engines/gob/gob.h b/engines/gob/gob.h index ea2323807a..df73404596 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -50,6 +50,11 @@ class StaticTextWidget; * - Bargon Attack * - Lost in Time * - The Bizarre Adventures of Woodruff and the Schnibble + * - Fascination + * - Urban Runner + * - Bambou le sauveur de la jungle + * - Geisha + * - Once Upon A Time: Little Red Riding Hood */ namespace Gob { @@ -70,6 +75,7 @@ class Scenery; class Util; class SaveLoad; class GobConsole; +class PreGob; #define WRITE_VAR_UINT32(var, val) _vm->_inter->_variables->writeVar32(var, val) #define WRITE_VAR_UINT16(var, val) _vm->_inter->_variables->writeVar16(var, val) @@ -123,7 +129,12 @@ enum GameType { kGameTypeAdi2, kGameTypeAdi4, kGameTypeAdibou2, - kGameTypeAdibou1 + kGameTypeAdibou1, + kGameTypeAbracadabra, + kGameTypeBabaYaga, + kGameTypeLittleRed, + kGameTypeOnceUponATime, // Need more inspection to see if Baba Yaga or Abracadabra + kGameTypeAJWorld }; enum Features { @@ -138,6 +149,13 @@ enum Features { kFeaturesTrueColor = 1 << 7 }; +enum EndiannessMethod { + kEndiannessMethodLE, ///< Always little endian. + kEndiannessMethodBE, ///< Always big endian. + kEndiannessMethodSystem, ///< Follows system endianness. + kEndiannessMethodAltFile ///< Different endianness in alternate file. +}; + enum { kDebugFuncOp = 1 << 0, kDebugDrawOp = 1 << 1, @@ -161,6 +179,8 @@ private: int32 _features; Common::Platform _platform; + EndiannessMethod _endiannessMethod; + uint32 _pauseStart; // Engine APIs @@ -169,10 +189,10 @@ private: virtual void pauseEngineIntern(bool pause); virtual void syncSoundSettings(); - bool initGameParts(); - void deinitGameParts(); + Common::Error initGameParts(); + Common::Error initGraphics(); - bool initGraphics(); + void deinitGameParts(); public: static const Common::Language _gobToScummVMLang[]; @@ -195,6 +215,8 @@ public: GobConsole *_console; + bool _resourceSizeWorkaround; + Global *_global; Util *_util; DataIO *_dataIO; @@ -211,6 +233,7 @@ public: Inter *_inter; SaveLoad *_saveLoad; VideoPlayer *_vidPlayer; + PreGob *_preGob; const char *getLangDesc(int16 language) const; void validateLanguage(); @@ -218,6 +241,7 @@ public: void pauseGame(); + EndiannessMethod getEndiannessMethod() const; Endianness getEndianness() const; Common::Platform getPlatform() const; GameType getGameType() const; @@ -231,6 +255,8 @@ public: bool isTrueColor() const; bool isDemo() const; + bool hasResourceSizeWorkaround() const; + bool isCurrentTot(const Common::String &tot) const; void setTrueColor(bool trueColor); diff --git a/engines/gob/hotspots.cpp b/engines/gob/hotspots.cpp index 9a89f11923..ecab9bb906 100644 --- a/engines/gob/hotspots.cpp +++ b/engines/gob/hotspots.cpp @@ -532,34 +532,46 @@ void Hotspots::leave(uint16 index) { call(spot.funcLeave); } -int16 Hotspots::curWindow(int16 &dx, int16 &dy) const { - if ((_vm->_draw->_renderFlags & 0x80)==0) - return(0); +int16 Hotspots::windowCursor(int16 &dx, int16 &dy) const { + if (!(_vm->_draw->_renderFlags & RENDERFLAG_HASWINDOWS)) + return 0; + for (int i = 0; i < 10; i++) { - if (_vm->_draw->_fascinWin[i].id != -1) { - if (_vm->_global->_inter_mouseX >= _vm->_draw->_fascinWin[i].left && - _vm->_global->_inter_mouseX < _vm->_draw->_fascinWin[i].left + _vm->_draw->_fascinWin[i].width && - _vm->_global->_inter_mouseY >= _vm->_draw->_fascinWin[i].top && - _vm->_global->_inter_mouseY < _vm->_draw->_fascinWin[i].top + _vm->_draw->_fascinWin[i].height) { - if (_vm->_draw->_fascinWin[i].id == _vm->_draw->_winCount-1) { - dx = _vm->_draw->_fascinWin[i].left; - dy = _vm->_draw->_fascinWin[i].top; - if (_vm->_global->_inter_mouseX < _vm->_draw->_fascinWin[i].left + 12 && - _vm->_global->_inter_mouseY < _vm->_draw->_fascinWin[i].top + 12 && - (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 2)) - // Cursor on 'Close Window' - return(5); - if (_vm->_global->_inter_mouseX >= _vm->_draw->_fascinWin[i].left + _vm->_draw->_fascinWin[i].width - 12 && - _vm->_global->_inter_mouseY < _vm->_draw->_fascinWin[i].top + 12 && - (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 4)) - // Cursor on 'Move Window' - return(6); - return(-i); - } - } - } + if (_vm->_draw->_fascinWin[i].id == -1) + // No such windows + continue; + + const int left = _vm->_draw->_fascinWin[i].left; + const int top = _vm->_draw->_fascinWin[i].top; + const int right = _vm->_draw->_fascinWin[i].left + _vm->_draw->_fascinWin[i].width - 1; + const int bottom = _vm->_draw->_fascinWin[i].top + _vm->_draw->_fascinWin[i].height - 1; + + if ((_vm->_global->_inter_mouseX < left) || (_vm->_global->_inter_mouseX > right) || + (_vm->_global->_inter_mouseY < top ) || (_vm->_global->_inter_mouseY > bottom)) + // We're not inside that window + continue; + + if (_vm->_draw->_fascinWin[i].id != (_vm->_draw->_winCount - 1)) + // Only consider the top-most window + continue; + + dx = _vm->_draw->_fascinWin[i].left; + dy = _vm->_draw->_fascinWin[i].top; + + if ((_vm->_global->_inter_mouseX < (left + 12)) && (_vm->_global->_inter_mouseY < (top + 12)) && + (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 2)) + // Cursor on 'Close Window' + return 5; + + if ((_vm->_global->_inter_mouseX > (right - 12)) & (_vm->_global->_inter_mouseY < (top + 12)) && + (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 4)) + // Cursor on 'Move Window' + return 6; + + return -1; } - return(0); + + return 0; } uint16 Hotspots::checkMouse(Type type, uint16 &id, uint16 &index) const { @@ -1226,13 +1238,13 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, ids[i] = 0; // Type and window - byte type = _vm->_game->_script->readByte(); + byte type = _vm->_game->_script->readByte(); byte windowNum = 0; if ((type & 0x40) != 0) { // Got a window ID - type -= 0x40; + type -= 0x40; windowNum = _vm->_game->_script->readByte(); } @@ -1254,31 +1266,31 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, width = _vm->_game->_script->readUint16(); height = _vm->_game->_script->readUint16(); } - if (_vm->_draw->_renderFlags & 64) { - _vm->_draw->_invalidatedTops[0] = 0; - _vm->_draw->_invalidatedLefts[0] = 0; - _vm->_draw->_invalidatedRights[0] = 319; - _vm->_draw->_invalidatedBottoms[0] = 199; - _vm->_draw->_invalidatedCount = 1; + type &= 0x7F; + + // Draw a border around the hotspot + if (_vm->_draw->_renderFlags & RENDERFLAG_BORDERHOTSPOTS) { + Surface &surface = *_vm->_draw->_spritesArray[_vm->_draw->_destSurface]; + + _vm->_video->dirtyRectsAll(); + if (windowNum == 0) { - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left + width - 1, top, left + width - 1, top + height - 1, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top, left, top + height - 1, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top, left + width - 1, top, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top + height - 1, left + width - 1, top + height - 1, 0); + // The hotspot is not inside a window, just draw border it + surface.drawRect(left, top, left + width - 1, top + height - 1, 0); + } else { - if ((_vm->_draw->_fascinWin[windowNum].id != -1) && (_vm->_draw->_fascinWin[windowNum].id == _vm->_draw->_winCount - 1)) { - left += _vm->_draw->_fascinWin[windowNum].left; - top += _vm->_draw->_fascinWin[windowNum].top; - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left + width - 1, top, left + width - 1, top + height - 1, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top, left, top + height - 1, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top, left + width - 1, top, 0); - _vm->_draw->_spritesArray[_vm->_draw->_destSurface]->drawLine(left, top + height - 1, left + width - 1, top + height - 1, 0); - left -= _vm->_draw->_fascinWin[windowNum].left; - top -= _vm->_draw->_fascinWin[windowNum].top; + // The hotspot is inside a window, only draw it if it's the topmost window + + if ((_vm->_draw->_fascinWin[windowNum].id != -1) && + (_vm->_draw->_fascinWin[windowNum].id == (_vm->_draw->_winCount - 1))) { + + const uint16 wLeft = left + _vm->_draw->_fascinWin[windowNum].left; + const uint16 wTop = top + _vm->_draw->_fascinWin[windowNum].top; + + surface.drawRect(wLeft, wTop, wLeft + width - 1, wTop + height - 1, 0); } } } - type &= 0x7F; // Apply global drawing offset if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != 0xFFFF)) { @@ -1667,38 +1679,19 @@ int16 Hotspots::findCursor(uint16 x, uint16 y) const { int16 deltax = 0; int16 deltay = 0; - if (_vm->getGameType() == kGameTypeFascination) - cursor = curWindow(deltax, deltay); + // Fascination uses hard-coded windows + if (_vm->getGameType() == kGameTypeFascination) { + cursor = windowCursor(deltax, deltay); - if (cursor == 0) { - for (int i = 0; (i < kHotspotCount) && !_hotspots[i].isEnd(); i++) { - const Hotspot &spot = _hotspots[i]; + // We're in a window and in an area that forces a specific cursor + if (cursor > 0) + return cursor; - if ((spot.getWindow() != 0) || spot.isDisabled()) - // Ignore disabled and non-main-windowed hotspots - continue; - - if (!spot.isIn(x, y)) - // We're not in that hotspot, ignore it - continue; - - if (spot.getCursor() == 0) { - // Hotspot doesn't itself specify a cursor... - if (spot.getType() >= kTypeInput1NoLeave) { - // ...but the type has a generic one - cursor = 3; - break; - } else if ((spot.getButton() != kMouseButtonsRight) && (cursor == 0)) - // ...but there's a generic "click" cursor - cursor = 1; - } else if (cursor == 0) - // Hotspot had an attached cursor index - cursor = spot.getCursor(); - } - } else { + // We're somewhere else inside a window if (cursor < 0) { - int16 curType = - cursor * 256; + int16 curType = -cursor * 256; cursor = 0; + for (int i = 0; (i < kHotspotCount) && !_hotspots[i].isEnd(); i++) { const Hotspot &spot = _hotspots[i]; // this check is /really/ Fascination specific. @@ -1712,10 +1705,40 @@ int16 Hotspots::findCursor(uint16 x, uint16 y) const { break; } } + + if (_vm->_draw->_cursorAnimLow[cursor] == -1) + // If the cursor is invalid... there's a generic "click" cursor + cursor = 1; + + return cursor; } - if (_vm->_draw->_cursorAnimLow[cursor] == -1) - // If the cursor is invalid... there's a generic "click" cursor - cursor = 1; + + } + + // Normal, non-window cursor handling + for (int i = 0; (i < kHotspotCount) && !_hotspots[i].isEnd(); i++) { + const Hotspot &spot = _hotspots[i]; + + if ((spot.getWindow() != 0) || spot.isDisabled()) + // Ignore disabled and non-main-windowed hotspots + continue; + + if (!spot.isIn(x, y)) + // We're not in that hotspot, ignore it + continue; + + if (spot.getCursor() == 0) { + // Hotspot doesn't itself specify a cursor... + if (spot.getType() >= kTypeInput1NoLeave) { + // ...but the type has a generic one + cursor = 3; + break; + } else if ((spot.getButton() != kMouseButtonsRight) && (cursor == 0)) + // ...but there's a generic "click" cursor + cursor = 1; + } else if (cursor == 0) + // Hotspot had an attached cursor index + cursor = spot.getCursor(); } return cursor; diff --git a/engines/gob/hotspots.h b/engines/gob/hotspots.h index b348f9cd70..bd7b281c10 100644 --- a/engines/gob/hotspots.h +++ b/engines/gob/hotspots.h @@ -202,8 +202,8 @@ private: /** Handling hotspot leave events. */ void leave(uint16 index); - /** Which window is the mouse cursor currently in? (Fascination) */ - int16 curWindow(int16 &dx, int16 &dy) const; + /** Check whether a specific part of the window forces a certain cursor. */ + int16 windowCursor(int16 &dx, int16 &dy) const; /** Which hotspot is the mouse cursor currently at? */ uint16 checkMouse(Type type, uint16 &id, uint16 &index) const; diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index a61261f355..814d4d1821 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -34,9 +34,13 @@ #include "gob/inter.h" #include "gob/video.h" #include "gob/videoplayer.h" + +#include "gob/sound/sound.h" + #include "gob/demos/scnplayer.h" #include "gob/demos/batplayer.h" -#include "gob/sound/sound.h" + +#include "gob/pregob/pregob.h" namespace Gob { @@ -118,6 +122,14 @@ void Init::initGame() { return; } + if (_vm->_preGob) { + _vm->_preGob->run(); + delete _palDesc; + _vm->_video->initPrimary(-1); + cleanup(); + return; + } + Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf"); if (!infFile) { diff --git a/engines/gob/init.h b/engines/gob/init.h index 946a3fa4f1..ac460fd654 100644 --- a/engines/gob/init.h +++ b/engines/gob/init.h @@ -62,7 +62,6 @@ public: ~Init_Geisha(); void initVideo(); - void initGame(); }; class Init_v2 : public Init_v1 { diff --git a/engines/gob/init_fascin.cpp b/engines/gob/init_fascin.cpp index b87d816406..e6d82faa68 100644 --- a/engines/gob/init_fascin.cpp +++ b/engines/gob/init_fascin.cpp @@ -44,10 +44,10 @@ void Init_Fascination::updateConfig() { } void Init_Fascination::initGame() { -// HACK - Suppress ADLIB_FLAG as the MDY/TBR player is not working. suppress -// the PC Speaker too, as the script checks in the intro for it's presence +// HACK - Suppress +// the PC Speaker, as the script checks in the intro for it's presence // to play or not some noices. - _vm->_global->_soundFlags = MIDI_FLAG | BLASTER_FLAG; + _vm->_global->_soundFlags = MIDI_FLAG | BLASTER_FLAG | ADLIB_FLAG; Init::initGame(); } diff --git a/engines/gob/init_geisha.cpp b/engines/gob/init_geisha.cpp index b5bbcff400..01081a5af6 100644 --- a/engines/gob/init_geisha.cpp +++ b/engines/gob/init_geisha.cpp @@ -44,11 +44,4 @@ void Init_Geisha::initVideo() { _vm->_draw->_transparentCursor = 1; } -void Init_Geisha::initGame() { - // HACK - Since the MDY/TBR player is not working, claim we have no AdLib - _vm->_global->_soundFlags = 0; - - Init::initGame(); -} - } // End of namespace Gob diff --git a/engines/gob/init_v1.cpp b/engines/gob/init_v1.cpp index 25d521aca6..a8e8cbe2c3 100644 --- a/engines/gob/init_v1.cpp +++ b/engines/gob/init_v1.cpp @@ -41,8 +41,6 @@ void Init_v1::initVideo() { _vm->_global->_mousePresent = 1; - _vm->_global->_inVM = 0; - if ((_vm->_global->_videoMode == 0x13) && !_vm->isEGA()) _vm->_global->_colorCount = 256; diff --git a/engines/gob/init_v2.cpp b/engines/gob/init_v2.cpp index 1289d561ea..c204b04a40 100644 --- a/engines/gob/init_v2.cpp +++ b/engines/gob/init_v2.cpp @@ -45,8 +45,6 @@ void Init_v2::initVideo() { _vm->_global->_mousePresent = 1; - _vm->_global->_inVM = 0; - _vm->_global->_colorCount = 16; if (!_vm->isEGA() && ((_vm->getPlatform() == Common::kPlatformPC) || diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 9df3c06c74..4460274561 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -52,6 +52,7 @@ Inter::Inter(GobEngine *vm) : _vm(vm), _varStack(600) { _soundEndTimeKey = 0; _soundStopVal = 0; + _lastBusyWait = 0; _noBusyWait = false; _variables = 0; @@ -358,6 +359,9 @@ void Inter::allocateVars(uint32 count) { } void Inter::delocateVars() { + if (_vm->_game) + _vm->_game->deletedVars(_variables); + delete _variables; _variables = 0; } @@ -452,4 +456,15 @@ uint32 Inter::readValue(uint16 index, uint16 type) { return 0; } +void Inter::handleBusyWait() { + uint32 now = _vm->_util->getTimeKey(); + + if (!_noBusyWait) + if ((now - _lastBusyWait) <= 20) + _vm->_util->longDelay(1); + + _lastBusyWait = now; + _noBusyWait = false; +} + } // End of namespace Gob diff --git a/engines/gob/inter.h b/engines/gob/inter.h index c79b6e2260..63bf3eb1c6 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -31,6 +31,10 @@ #include "gob/iniconfig.h" #include "gob/databases.h" +namespace Common { + class PEResources; +} + namespace Gob { class Cheater_Geisha; @@ -138,8 +142,9 @@ protected: VariableStack _varStack; - // The busy-wait detection in o1_keyFunc breaks fast scrolling in Ween - bool _noBusyWait; + // Busy-wait detection + bool _noBusyWait; + uint32 _lastBusyWait; GobEngine *_vm; @@ -168,6 +173,8 @@ protected: void storeString(const char *value); uint32 readValue(uint16 index, uint16 type); + + void handleBusyWait(); }; class Inter_v1 : public Inter { @@ -509,6 +516,20 @@ protected: void oFascin_setWinFlags(); }; +class Inter_LittleRed : public Inter_v2 { +public: + Inter_LittleRed(GobEngine *vm); + virtual ~Inter_LittleRed() {} + +protected: + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); + + void oLittleRed_keyFunc(OpFuncParams ¶ms); + void oLittleRed_playComposition(OpFuncParams ¶ms); +}; + class Inter_v3 : public Inter_v2 { public: Inter_v3(GobEngine *vm); @@ -648,7 +669,7 @@ private: class Inter_v7 : public Inter_Playtoons { public: Inter_v7(GobEngine *vm); - virtual ~Inter_v7() {} + virtual ~Inter_v7(); protected: virtual void setupOpcodesDraw(); @@ -684,7 +705,12 @@ private: INIConfig _inis; Databases _databases; + Common::PEResources *_cursors; + Common::String findFile(const Common::String &mask); + + bool loadCursorFile(); + void resizeCursors(int16 width, int16 height, int16 count, bool transparency); }; } // End of namespace Gob diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index 134203fa9d..029f7c697b 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -119,7 +119,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { MouseButtons buttons; SurfacePtr surface; SoundDesc samples[4]; - int16 comp[5] = { 0, 1, 2, 3, -1 }; + static const int16 comp[5] = { 0, 1, 2, 3, -1 }; static const char *const sndFiles[] = {"1INTROII.snd", "2INTROII.snd", "1INTRO3.snd", "2INTRO3.snd"}; surface = _vm->_video->initSurfDesc(320, 200); @@ -167,8 +167,8 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { MouseButtons buttons; Video::Color *palBak; SoundDesc samples[2]; - int16 comp[3] = { 0, 1, -1 }; byte *palettes[4]; + static const int16 comp[3] = { 0, 1, -1 }; static const char *const sndFiles[] = {"1INTROIV.snd", "2INTROIV.snd"}; static const char *const palFiles[] = {"2ou2.clt", "2ou3.clt", "2ou4.clt", "2ou5.clt"}; diff --git a/engines/gob/inter_fascin.cpp b/engines/gob/inter_fascin.cpp index 081b48fbad..001ec06635 100644 --- a/engines/gob/inter_fascin.cpp +++ b/engines/gob/inter_fascin.cpp @@ -248,12 +248,11 @@ void Inter_Fascination::oFascin_playTira(OpGobParams ¶ms) { void Inter_Fascination::oFascin_loadExtasy(OpGobParams ¶ms) { _vm->_sound->adlibLoadTBR("extasy.tbr"); _vm->_sound->adlibLoadMDY("extasy.mdy"); + _vm->_sound->adlibSetRepeating(-1); } void Inter_Fascination::oFascin_adlibPlay(OpGobParams ¶ms) { -#ifdef ENABLE_FASCIN_ADLIB _vm->_sound->adlibPlay(); -#endif } void Inter_Fascination::oFascin_adlibStop(OpGobParams ¶ms) { diff --git a/engines/gob/inter_geisha.cpp b/engines/gob/inter_geisha.cpp index 7f21ceb91d..8d05cefa66 100644 --- a/engines/gob/inter_geisha.cpp +++ b/engines/gob/inter_geisha.cpp @@ -55,7 +55,7 @@ Inter_Geisha::Inter_Geisha(GobEngine *vm) : Inter_v1(vm), _diving = new Geisha::Diving(vm); _penetration = new Geisha::Penetration(vm); - _cheater = new Cheater_Geisha(vm, _diving); + _cheater = new Cheater_Geisha(vm, _diving, _penetration); _vm->_console->registerCheater(_cheater); } @@ -200,8 +200,12 @@ void Inter_Geisha::oGeisha_checkData(OpFuncParams ¶ms) { if (mode == SaveLoad::kSaveModeNone) { exists = _vm->_dataIO->hasFile(file); - if (!exists) - warning("File \"%s\" not found", file.c_str()); + if (!exists) { + // NOTE: Geisha looks if fin.tot exists to check if it needs to open disk3.stk. + // This is completely normal, so don't print a warning. + if (file != "fin.tot") + warning("File \"%s\" not found", file.c_str()); + } } else if (mode == SaveLoad::kSaveModeSave) exists = _vm->_saveLoad->getSize(file.c_str()) >= 0; @@ -272,12 +276,12 @@ void Inter_Geisha::oGeisha_writeData(OpFuncParams ¶ms) { } void Inter_Geisha::oGeisha_gamePenetration(OpGobParams ¶ms) { - uint16 var1 = _vm->_game->_script->readUint16(); - uint16 var2 = _vm->_game->_script->readUint16(); - uint16 var3 = _vm->_game->_script->readUint16(); - uint16 resultVar = _vm->_game->_script->readUint16(); + uint16 hasAccessPass = _vm->_game->_script->readUint16(); + uint16 hasMaxEnergy = _vm->_game->_script->readUint16(); + uint16 testMode = _vm->_game->_script->readUint16(); + uint16 resultVar = _vm->_game->_script->readUint16(); - bool result = _penetration->play(var1, var2, var3); + bool result = _penetration->play(hasAccessPass, hasMaxEnergy, testMode); WRITE_VAR_UINT32(resultVar, result ? 1 : 0); } @@ -298,9 +302,8 @@ void Inter_Geisha::oGeisha_loadTitleMusic(OpGobParams ¶ms) { } void Inter_Geisha::oGeisha_playMusic(OpGobParams ¶ms) { - // TODO: The MDYPlayer is still broken! - warning("Geisha Stub: oGeisha_playMusic"); - // _vm->_sound->adlibPlay(); + _vm->_sound->adlibSetRepeating(-1); + _vm->_sound->adlibPlay(); } void Inter_Geisha::oGeisha_stopMusic(OpGobParams ¶ms) { diff --git a/engines/gob/inter_littlered.cpp b/engines/gob/inter_littlered.cpp new file mode 100644 index 0000000000..01aa4c2158 --- /dev/null +++ b/engines/gob/inter_littlered.cpp @@ -0,0 +1,118 @@ +/* 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 "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/draw.h" +#include "gob/game.h" +#include "gob/script.h" +#include "gob/hotspots.h" +#include "gob/sound/sound.h" + +namespace Gob { + +#define OPCODEVER Inter_LittleRed +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) + +Inter_LittleRed::Inter_LittleRed(GobEngine *vm) : Inter_v2(vm) { +} + +void Inter_LittleRed::setupOpcodesDraw() { + Inter_v2::setupOpcodesDraw(); +} + +void Inter_LittleRed::setupOpcodesFunc() { + Inter_v2::setupOpcodesFunc(); + + OPCODEFUNC(0x14, oLittleRed_keyFunc); + + OPCODEFUNC(0x3D, oLittleRed_playComposition); +} + +void Inter_LittleRed::setupOpcodesGob() { + OPCODEGOB(1, o_gobNOP); // Sets some sound timer interrupt + OPCODEGOB(2, o_gobNOP); // Sets some sound timer interrupt + + OPCODEGOB(500, o2_playProtracker); + OPCODEGOB(501, o2_stopProtracker); +} + +void Inter_LittleRed::oLittleRed_keyFunc(OpFuncParams ¶ms) { + animPalette(); + _vm->_draw->blitInvalidated(); + + handleBusyWait(); + + int16 cmd = _vm->_game->_script->readInt16(); + int16 key; + uint32 keyState; + + switch (cmd) { + case -1: + break; + + case 0: + _vm->_draw->_showCursor &= ~2; + _vm->_util->longDelay(1); + key = _vm->_game->_hotspots->check(0, 0); + storeKey(key); + + _vm->_util->clearKeyBuf(); + break; + + case 1: + _vm->_util->forceMouseUp(true); + key = _vm->_game->checkKeys(&_vm->_global->_inter_mouseX, + &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons, 0); + storeKey(key); + break; + + case 2: + _vm->_util->processInput(true); + keyState = _vm->_util->getKeyState(); + + WRITE_VAR(0, keyState); + _vm->_util->clearKeyBuf(); + break; + + default: + _vm->_sound->speakerOnUpdate(cmd); + if (cmd < 20) { + _vm->_util->delay(cmd); + _noBusyWait = true; + } else + _vm->_util->longDelay(cmd); + break; + } +} + +void Inter_LittleRed::oLittleRed_playComposition(OpFuncParams ¶ms) { + o1_playComposition(params); + + _vm->_sound->blasterRepeatComposition(-1); +} + +} // End of namespace Gob diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 9aa190a456..dc533a210a 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -286,10 +286,40 @@ void Inter_v1::o1_loadMult() { } void Inter_v1::o1_playMult() { - int16 checkEscape; + // NOTE: The EGA version of Gobliiins has an MDY tune. + // While the original doesn't play it, we do. + bool isGob1EGAIntro = _vm->getGameType() == kGameTypeGob1 && + _vm->isEGA() && + _vm->_game->_script->pos() == 1010 && + _vm->isCurrentTot("intro.tot") && + VAR(57) != 0xFFFFFFFF && + _vm->_dataIO->hasFile("goblins.mdy") && + _vm->_dataIO->hasFile("goblins.tbr"); + + int16 checkEscape = _vm->_game->_script->readInt16(); + + if (isGob1EGAIntro) { + _vm->_sound->adlibLoadTBR("goblins.tbr"); + _vm->_sound->adlibLoadMDY("goblins.mdy"); + _vm->_sound->adlibSetRepeating(-1); + + _vm->_sound->adlibPlay(); + } - checkEscape = _vm->_game->_script->readInt16(); _vm->_mult->playMult(VAR(57), -1, checkEscape, 0); + + if (isGob1EGAIntro) { + + // User didn't escape the intro mult, wait for an escape here + if (VAR(57) != 0xFFFFFFFF) { + while (_vm->_util->getKey() != kKeyEscape) { + _vm->_util->processInput(); + _vm->_util->longDelay(1); + } + } + + _vm->_sound->adlibUnload(); + } } void Inter_v1::o1_freeMultKeys() { @@ -1159,26 +1189,15 @@ void Inter_v1::o1_palLoad(OpFuncParams ¶ms) { } void Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { - static uint32 lastCalled = 0; - int16 cmd; - int16 key; - uint32 now; - if (!_vm->_vidPlayer->isPlayingLive()) { _vm->_draw->forceBlit(); _vm->_video->retrace(); } - cmd = _vm->_game->_script->readInt16(); animPalette(); _vm->_draw->blitInvalidated(); - now = _vm->_util->getTimeKey(); - if (!_noBusyWait) - if ((now - lastCalled) <= 20) - _vm->_util->longDelay(1); - lastCalled = now; - _noBusyWait = false; + handleBusyWait(); // WORKAROUND for bug #1726130: Ween busy-waits in the intro for a counter // to become 5000. We deliberately slow down busy-waiting, so we shorten @@ -1187,6 +1206,9 @@ void Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { (_vm->_game->_script->pos() == 729) && _vm->isCurrentTot("intro5.tot")) WRITE_VAR(59, 4000); + int16 cmd = _vm->_game->_script->readInt16(); + int16 key; + switch (cmd) { case -1: break; @@ -1554,14 +1576,13 @@ void Inter_v1::o1_waitEndPlay(OpFuncParams ¶ms) { } void Inter_v1::o1_playComposition(OpFuncParams ¶ms) { - int16 composition[50]; - int16 dataVar; - int16 freqVal; + int16 dataVar = _vm->_game->_script->readVarIndex(); + int16 freqVal = _vm->_game->_script->readValExpr(); - dataVar = _vm->_game->_script->readVarIndex(); - freqVal = _vm->_game->_script->readValExpr(); + int16 composition[50]; + int maxEntries = MIN<int>(50, (_variables->getSize() - dataVar) / 4); for (int i = 0; i < 50; i++) - composition[i] = (int16) VAR_OFFSET(dataVar + i * 4); + composition[i] = (i < maxEntries) ? ((int16) VAR_OFFSET(dataVar + i * 4)) : -1; _vm->_sound->blasterPlayComposition(composition, freqVal); } @@ -1744,10 +1765,15 @@ void Inter_v1::o1_writeData(OpFuncParams ¶ms) { void Inter_v1::o1_manageDataFile(OpFuncParams ¶ms) { Common::String file = _vm->_game->_script->evalString(); - if (!file.empty()) + if (!file.empty()) { _vm->_dataIO->openArchive(file, true); - else + } else { _vm->_dataIO->closeArchive(true); + + // NOTE: Lost in Time might close a data file without explicitely closing a video in it. + // So we make sure that all open videos are still available. + _vm->_vidPlayer->reopenAll(); + } } void Inter_v1::o1_setState(OpGobParams ¶ms) { diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 1e5b7bb24c..cb58fe86f7 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -1002,6 +1002,10 @@ void Inter_v2::o2_openItk() { void Inter_v2::o2_closeItk() { _vm->_dataIO->closeArchive(false); + + // NOTE: Lost in Time might close a data file without explicitely closing a video in it. + // So we make sure that all open videos are still available. + _vm->_vidPlayer->reopenAll(); } void Inter_v2::o2_setImdFrontSurf() { @@ -1244,7 +1248,7 @@ void Inter_v2::o2_checkData(OpFuncParams ¶ms) { file = "EMAP2011.TOT"; int32 size = -1; - SaveLoad::SaveMode mode = _vm->_saveLoad->getSaveMode(file.c_str()); + SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file.c_str()) : SaveLoad::kSaveModeNone; if (mode == SaveLoad::kSaveModeNone) { size = _vm->_dataIO->fileSize(file); @@ -1273,7 +1277,7 @@ void Inter_v2::o2_readData(OpFuncParams ¶ms) { debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)", file, dataVar, size, offset); - SaveLoad::SaveMode mode = _vm->_saveLoad->getSaveMode(file); + SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file) : SaveLoad::kSaveModeNone; if (mode == SaveLoad::kSaveModeSave) { WRITE_VAR(1, 1); @@ -1345,7 +1349,7 @@ void Inter_v2::o2_writeData(OpFuncParams ¶ms) { WRITE_VAR(1, 1); - SaveLoad::SaveMode mode = _vm->_saveLoad->getSaveMode(file); + SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file) : SaveLoad::kSaveModeNone; if (mode == SaveLoad::kSaveModeSave) { if (!_vm->_saveLoad->save(file, dataVar, size, offset)) { diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp index c0e8978afd..24905b08d1 100644 --- a/engines/gob/inter_v5.cpp +++ b/engines/gob/inter_v5.cpp @@ -281,7 +281,7 @@ void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { Font *font; if ((font = _vm->_draw->loadFont("SPEED.LET"))) { - _vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface, *font); + font->drawString("100 %", 402, 89, 112, 144, 0, *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); delete font; @@ -293,7 +293,7 @@ void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { Font *font; if ((font = _vm->_draw->loadFont("SPEED.LET"))) { - _vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface, *font); + font->drawString("100 %", 402, 168, 112, 144, 0, *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); delete font; @@ -305,7 +305,7 @@ void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { Font *font; if ((font = _vm->_draw->loadFont("SPEED.LET"))) { - _vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface, *font); + font->drawString("100 %", 402, 248, 112, 144, 0, *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); delete font; @@ -317,7 +317,7 @@ void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { Font *font; if ((font = _vm->_draw->loadFont("SPEED.LET"))) { - _vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface, *font); + font->drawString("100 %", 402, 326, 112, 144, 0, *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); delete font; @@ -329,7 +329,7 @@ void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { Font *font; if ((font = _vm->_draw->loadFont("SPEED.LET"))) { - _vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface, *font); + font->drawString("100 %", 402, 405, 112, 144, 0, *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); delete font; diff --git a/engines/gob/inter_v7.cpp b/engines/gob/inter_v7.cpp index 81547f7362..6cf69ed9df 100644 --- a/engines/gob/inter_v7.cpp +++ b/engines/gob/inter_v7.cpp @@ -22,8 +22,11 @@ #include "common/endian.h" #include "common/archive.h" +#include "common/winexe.h" +#include "common/winexe_pe.h" #include "graphics/cursorman.h" +#include "graphics/wincursor.h" #include "gob/gob.h" #include "gob/global.h" @@ -42,7 +45,11 @@ namespace Gob { #define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) #define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) -Inter_v7::Inter_v7(GobEngine *vm) : Inter_Playtoons(vm) { +Inter_v7::Inter_v7(GobEngine *vm) : Inter_Playtoons(vm), _cursors(0) { +} + +Inter_v7::~Inter_v7() { + delete _cursors; } void Inter_v7::setupOpcodesDraw() { @@ -86,27 +93,121 @@ void Inter_v7::o7_draw0x0C() { WRITE_VAR(17, 0); } +void Inter_v7::resizeCursors(int16 width, int16 height, int16 count, bool transparency) { + if (width <= 0) + width = _vm->_draw->_cursorWidth; + if (height <= 0) + height = _vm->_draw->_cursorHeight; + + width = MAX<uint16>(width , _vm->_draw->_cursorWidth); + height = MAX<uint16>(height, _vm->_draw->_cursorHeight); + + _vm->_draw->_transparentCursor = transparency; + + // Cursors sprite already big enough + if ((_vm->_draw->_cursorWidth >= width) && (_vm->_draw->_cursorHeight >= height) && + (_vm->_draw->_cursorCount >= count)) + return; + + _vm->_draw->_cursorCount = count; + _vm->_draw->_cursorWidth = width; + _vm->_draw->_cursorHeight = height; + + _vm->_draw->freeSprite(Draw::kCursorSurface); + _vm->_draw->_cursorSprites.reset(); + _vm->_draw->_cursorSpritesBack.reset(); + _vm->_draw->_scummvmCursor.reset(); + + _vm->_draw->initSpriteSurf(Draw::kCursorSurface, width * count, height, 2); + + _vm->_draw->_cursorSpritesBack = _vm->_draw->_spritesArray[Draw::kCursorSurface]; + _vm->_draw->_cursorSprites = _vm->_draw->_cursorSpritesBack; + + _vm->_draw->_scummvmCursor = _vm->_video->initSurfDesc(width, height, SCUMMVM_CURSOR); + + for (int i = 0; i < 40; i++) { + _vm->_draw->_cursorAnimLow[i] = -1; + _vm->_draw->_cursorAnimDelays[i] = 0; + _vm->_draw->_cursorAnimHigh[i] = 0; + } + _vm->_draw->_cursorAnimLow[1] = 0; + + delete[] _vm->_draw->_doCursorPalettes; + delete[] _vm->_draw->_cursorPalettes; + delete[] _vm->_draw->_cursorKeyColors; + delete[] _vm->_draw->_cursorPaletteStarts; + delete[] _vm->_draw->_cursorPaletteCounts; + delete[] _vm->_draw->_cursorHotspotsX; + delete[] _vm->_draw->_cursorHotspotsY; + + _vm->_draw->_cursorPalettes = new byte[256 * 3 * count]; + _vm->_draw->_doCursorPalettes = new bool[count]; + _vm->_draw->_cursorKeyColors = new byte[count]; + _vm->_draw->_cursorPaletteStarts = new uint16[count]; + _vm->_draw->_cursorPaletteCounts = new uint16[count]; + _vm->_draw->_cursorHotspotsX = new int32[count]; + _vm->_draw->_cursorHotspotsY = new int32[count]; + + memset(_vm->_draw->_cursorPalettes , 0, count * 256 * 3); + memset(_vm->_draw->_doCursorPalettes , 0, count * sizeof(bool)); + memset(_vm->_draw->_cursorKeyColors , 0, count * sizeof(byte)); + memset(_vm->_draw->_cursorPaletteStarts, 0, count * sizeof(uint16)); + memset(_vm->_draw->_cursorPaletteCounts, 0, count * sizeof(uint16)); + memset(_vm->_draw->_cursorHotspotsX , 0, count * sizeof(int32)); + memset(_vm->_draw->_cursorHotspotsY , 0, count * sizeof(int32)); +} + void Inter_v7::o7_loadCursor() { int16 cursorIndex = _vm->_game->_script->readValExpr(); - Common::String cursorFile = _vm->_game->_script->evalString(); + Common::String cursorName = _vm->_game->_script->evalString(); + + // Clear the cursor sprite at that index + _vm->_draw->_cursorSprites->fillRect(cursorIndex * _vm->_draw->_cursorWidth, 0, + cursorIndex * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1, + _vm->_draw->_cursorHeight - 1, 0); + + // If the cursor name is empty, that cursor will be drawn by the scripts + if (cursorName.empty()) { + // Make sure the cursors sprite is big enough and set to non-extern palette + resizeCursors(-1, -1, cursorIndex + 1, true); + _vm->_draw->_doCursorPalettes[cursorIndex] = false; + return; + } + + Graphics::WinCursorGroup *cursorGroup = 0; + Graphics::Cursor *defaultCursor = 0; + + // Load the cursor file and cursor group + if (loadCursorFile()) + cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_cursors, Common::WinResourceID(cursorName)); + + // If the requested cursor does not exist, create a default one + const Graphics::Cursor *cursor = 0; + if (!cursorGroup || cursorGroup->cursors.empty() || !cursorGroup->cursors[0].cursor) { + defaultCursor = Graphics::makeDefaultWinCursor(); + + cursor = defaultCursor; + } else + cursor = cursorGroup->cursors[0].cursor; - warning("Addy Stub: Load cursor \"%s\" to %d", cursorFile.c_str(), cursorIndex); + // Make sure the cursors sprite it big enough + resizeCursors(cursor->getWidth(), cursor->getHeight(), cursorIndex + 1, true); - byte cursor[9]; - byte palette[6]; + Surface cursorSurf(cursor->getWidth(), cursor->getHeight(), 1, cursor->getSurface()); - cursor[0] = 0; cursor[1] = 0; cursor[2] = 0; - cursor[3] = 0; cursor[4] = 1; cursor[5] = 0; - cursor[6] = 0; cursor[7] = 0; cursor[8] = 0; + _vm->_draw->_cursorSprites->blit(cursorSurf, cursorIndex * _vm->_draw->_cursorWidth, 0); - palette[0] = 0; palette[1] = 0; palette[2] = 0; - palette[3] = 255; palette[4] = 255; palette[5] = 255; + memcpy(_vm->_draw->_cursorPalettes + cursorIndex * 256 * 3, cursor->getPalette(), cursor->getPaletteCount() * 3); - CursorMan.pushCursorPalette(palette, 0, 2); - CursorMan.disableCursorPalette(false); - CursorMan.replaceCursor(cursor, 3, 3, 1, 1, 255); + _vm->_draw->_doCursorPalettes [cursorIndex] = true; + _vm->_draw->_cursorKeyColors [cursorIndex] = cursor->getKeyColor(); + _vm->_draw->_cursorPaletteStarts[cursorIndex] = cursor->getPaletteStartIndex(); + _vm->_draw->_cursorPaletteCounts[cursorIndex] = cursor->getPaletteCount(); + _vm->_draw->_cursorHotspotsX [cursorIndex] = cursor->getHotspotX(); + _vm->_draw->_cursorHotspotsY [cursorIndex] = cursor->getHotspotY(); - CursorMan.showMouse(true); + delete cursorGroup; + delete defaultCursor; } void Inter_v7::o7_displayWarning() { @@ -529,4 +630,19 @@ Common::String Inter_v7::findFile(const Common::String &mask) { return files.front()->getName(); } +bool Inter_v7::loadCursorFile() { + if (_cursors) + return true; + + _cursors = new Common::PEResources(); + + if (_cursors->loadFromEXE("cursor32.dll")) + return true; + + delete _cursors; + _cursors = 0; + + return false; +} + } // End of namespace Gob diff --git a/engines/gob/minigames/geisha/diving.cpp b/engines/gob/minigames/geisha/diving.cpp index 6f4c6e168a..56c7b5213c 100644 --- a/engines/gob/minigames/geisha/diving.cpp +++ b/engines/gob/minigames/geisha/diving.cpp @@ -706,16 +706,16 @@ void Diving::updateAnims() { for (Common::List<ANIObject *>::iterator a = _anims.reverse_begin(); a != _anims.end(); --a) { - (*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom); - _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + if ((*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } // Draw the current animation frames for (Common::List<ANIObject *>::iterator a = _anims.begin(); a != _anims.end(); ++a) { - (*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom); - _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + if ((*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); (*a)->advance(); } diff --git a/engines/gob/minigames/geisha/evilfish.cpp b/engines/gob/minigames/geisha/evilfish.cpp index c7ef9d5622..05ae9d0ad4 100644 --- a/engines/gob/minigames/geisha/evilfish.cpp +++ b/engines/gob/minigames/geisha/evilfish.cpp @@ -171,7 +171,7 @@ void EvilFish::mutate(uint16 animSwimLeft, uint16 animSwimRight, } } -bool EvilFish::isDead() { +bool EvilFish::isDead() const { return !isVisible() || (_state == kStateNone) || (_state == kStateDie); } diff --git a/engines/gob/minigames/geisha/evilfish.h b/engines/gob/minigames/geisha/evilfish.h index 81efb676e2..4c82629461 100644 --- a/engines/gob/minigames/geisha/evilfish.h +++ b/engines/gob/minigames/geisha/evilfish.h @@ -58,7 +58,7 @@ public: uint16 animTurnLeft, uint16 animTurnRight, uint16 animDie); /** Is the fish dead? */ - bool isDead(); + bool isDead() const; private: enum State { diff --git a/engines/gob/minigames/geisha/meter.cpp b/engines/gob/minigames/geisha/meter.cpp index e3b9bd1ccf..7ec3119866 100644 --- a/engines/gob/minigames/geisha/meter.cpp +++ b/engines/gob/minigames/geisha/meter.cpp @@ -42,6 +42,10 @@ Meter::~Meter() { delete _surface; } +int32 Meter::getMaxValue() const { + return _maxValue; +} + int32 Meter::getValue() const { return _value; } @@ -59,22 +63,36 @@ void Meter::setMaxValue() { setValue(_maxValue); } -void Meter::increase(int32 n) { +int32 Meter::increase(int32 n) { + if (n < 0) + return decrease(-n); + + int32 overflow = MAX<int32>(0, (_value + n) - _maxValue); + int32 value = CLIP<int32>(_value + n, 0, _maxValue); if (_value == value) - return; + return overflow; _value = value; _needUpdate = true; + + return overflow; } -void Meter::decrease(int32 n) { +int32 Meter::decrease(int32 n) { + if (n < 0) + return increase(-n); + + int32 underflow = -MIN<int32>(0, _value - n); + int32 value = CLIP<int32>(_value - n, 0, _maxValue); if (_value == value) - return; + return underflow; _value = value; _needUpdate = true; + + return underflow; } void Meter::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { diff --git a/engines/gob/minigames/geisha/meter.h b/engines/gob/minigames/geisha/meter.h index a9bdb14d0f..30dc826de0 100644 --- a/engines/gob/minigames/geisha/meter.h +++ b/engines/gob/minigames/geisha/meter.h @@ -44,6 +44,8 @@ public: Direction direction); ~Meter(); + /** Return the max value the meter is measuring. */ + int32 getMaxValue() const; /** Return the current value the meter is measuring. */ int32 getValue() const; @@ -53,10 +55,10 @@ public: /** Set the current value the meter is measuring to the max value. */ void setMaxValue(); - /** Increase the current value the meter is measuring. */ - void increase(int32 n = 1); - /** Decrease the current value the meter is measuring. */ - void decrease(int32 n = 1); + /** Increase the current value the meter is measuring, returning the overflow. */ + int32 increase(int32 n = 1); + /** Decrease the current value the meter is measuring, returning the underflow. */ + int32 decrease(int32 n = 1); /** Draw the meter onto the surface and return the affected rectangle. */ void draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); diff --git a/engines/gob/minigames/geisha/mouth.cpp b/engines/gob/minigames/geisha/mouth.cpp new file mode 100644 index 0000000000..7ba9f86f8c --- /dev/null +++ b/engines/gob/minigames/geisha/mouth.cpp @@ -0,0 +1,169 @@ +/* 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 "common/util.h" + +#include "gob/minigames/geisha/mouth.h" + +namespace Gob { + +namespace Geisha { + +Mouth::Mouth(const ANIFile &ani, const CMPFile &cmp, + uint16 mouthAnim, uint16 mouthSprite, uint16 floorSprite) : ANIObject(ani) { + + _sprite = new ANIObject(cmp); + _sprite->setAnimation(mouthSprite); + _sprite->setVisible(true); + + for (int i = 0; i < kFloorCount; i++) { + _floor[i] = new ANIObject(cmp); + _floor[i]->setAnimation(floorSprite); + _floor[i]->setVisible(true); + } + + _state = kStateDeactivated; + + setAnimation(mouthAnim); + setMode(kModeOnce); + setPause(true); + setVisible(true); +} + +Mouth::~Mouth() { + for (int i = 0; i < kFloorCount; i++) + delete _floor[i]; + + delete _sprite; +} + +void Mouth::advance() { + if (_state != kStateActivated) + return; + + // Animation finished, set state to dead + if (isPaused()) { + _state = kStateDead; + return; + } + + ANIObject::advance(); +} + +void Mouth::activate() { + if (_state != kStateDeactivated) + return; + + _state = kStateActivated; + + setPause(false); +} + +bool Mouth::isDeactivated() const { + return _state == kStateDeactivated; +} + +void Mouth::setPosition(int16 x, int16 y) { + ANIObject::setPosition(x, y); + + int16 floorWidth, floorHeight; + _floor[0]->getFrameSize(floorWidth, floorHeight); + + _sprite->setPosition(x, y); + + for (int i = 0; i < kFloorCount; i++) + _floor[i]->setPosition(x + (i * floorWidth), y); +} + +bool Mouth::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + // If the mouth is deactivated, draw the default mouth sprite + if (_state == kStateDeactivated) + return _sprite->draw(dest, left, top, right, bottom); + + // If the mouth is activated, draw the current mouth animation sprite + if (_state == kStateActivated) + return ANIObject::draw(dest, left, top, right, bottom); + + // If the mouth is dead, draw the floor tiles + if (_state == kStateDead) { + int16 fLeft, fRight, fTop, fBottom; + bool drawn = false; + + left = 0x7FFF; + top = 0x7FFF; + right = 0; + bottom = 0; + + for (int i = 0; i < kFloorCount; i++) { + if (_floor[i]->draw(dest, fLeft, fTop, fRight, fBottom)) { + drawn = true; + left = MIN(left , fLeft); + top = MIN(top , fTop); + right = MAX(right , fRight); + bottom = MAX(bottom, fBottom); + } + } + + return drawn; + } + + return false; +} + +bool Mouth::clear(Surface &dest, int16 &left , int16 &top, int16 &right, int16 &bottom) { + // If the mouth is deactivated, clear the default mouth sprite + if (_state == kStateDeactivated) + return _sprite->clear(dest, left, top, right, bottom); + + // If the mouth is activated, clear the current mouth animation sprite + if (_state == kStateActivated) + return ANIObject::clear(dest, left, top, right, bottom); + + // If the mouth is clear, draw the floor tiles + if (_state == kStateDead) { + int16 fLeft, fRight, fTop, fBottom; + bool cleared = false; + + left = 0x7FFF; + top = 0x7FFF; + right = 0; + bottom = 0; + + for (int i = 0; i < kFloorCount; i++) { + if (_floor[i]->clear(dest, fLeft, fTop, fRight, fBottom)) { + cleared = true; + left = MIN(left , fLeft); + top = MIN(top , fTop); + right = MAX(right , fRight); + bottom = MAX(bottom, fBottom); + } + } + + return cleared; + } + + return false; +} + +} // End of namespace Geisha + +} // End of namespace Gob diff --git a/engines/gob/minigames/geisha/mouth.h b/engines/gob/minigames/geisha/mouth.h new file mode 100644 index 0000000000..2e0cfcd5d0 --- /dev/null +++ b/engines/gob/minigames/geisha/mouth.h @@ -0,0 +1,75 @@ +/* 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 GOB_MINIGAMES_GEISHA_MOUTH_H +#define GOB_MINIGAMES_GEISHA_MOUTH_H + +#include "gob/aniobject.h" + +namespace Gob { + +namespace Geisha { + +/** A kissing/biting mouth in Geisha's "Penetration" minigame. */ +class Mouth : public ANIObject { +public: + Mouth(const ANIFile &ani, const CMPFile &cmp, + uint16 mouthAnim, uint16 mouthSprite, uint16 floorSprite); + ~Mouth(); + + /** Advance the animation to the next frame. */ + void advance(); + + /** Active the mouth's animation. */ + void activate(); + + /** Is the mouth deactivated? */ + bool isDeactivated() const; + + /** Set the current position. */ + void setPosition(int16 x, int16 y); + + /** Draw the current frame onto the surface and return the affected rectangle. */ + bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + /** Draw the current frame from the surface and return the affected rectangle. */ + bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + +private: + static const int kFloorCount = 2; + + enum State { + kStateDeactivated, + kStateActivated, + kStateDead + }; + + ANIObject *_sprite; + ANIObject *_floor[kFloorCount]; + + State _state; +}; + +} // End of namespace Geisha + +} // End of namespace Gob + +#endif // GOB_MINIGAMES_GEISHA_MOUTH_H diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 121a45bc40..c8c4f2bba7 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -20,87 +20,1449 @@ * */ +#include "common/events.h" + #include "gob/global.h" #include "gob/util.h" +#include "gob/palanim.h" #include "gob/draw.h" #include "gob/video.h" #include "gob/decfile.h" +#include "gob/cmpfile.h" #include "gob/anifile.h" +#include "gob/aniobject.h" + +#include "gob/sound/sound.h" #include "gob/minigames/geisha/penetration.h" +#include "gob/minigames/geisha/meter.h" +#include "gob/minigames/geisha/mouth.h" namespace Gob { namespace Geisha { -static const byte kPalette[48] = { - 0x16, 0x16, 0x16, - 0x12, 0x14, 0x16, - 0x34, 0x00, 0x25, - 0x1D, 0x1F, 0x22, - 0x24, 0x27, 0x2A, - 0x2C, 0x0D, 0x22, - 0x2B, 0x2E, 0x32, - 0x12, 0x09, 0x20, - 0x3D, 0x3F, 0x00, - 0x3F, 0x3F, 0x3F, - 0x00, 0x00, 0x00, - 0x15, 0x15, 0x3F, - 0x25, 0x22, 0x2F, - 0x1A, 0x14, 0x28, - 0x3F, 0x00, 0x00, - 0x15, 0x3F, 0x15 +static const int kColorShield = 11; +static const int kColorHealth = 15; +static const int kColorBlack = 10; +static const int kColorFloor = 13; +static const int kColorFloorText = 14; +static const int kColorExitText = 15; + +enum Sprite { + kSpriteFloorShield = 25, + kSpriteExit = 29, + kSpriteFloor = 30, + kSpriteWall = 31, + kSpriteMouthBite = 32, + kSpriteMouthKiss = 33, + kSpriteBulletN = 65, + kSpriteBulletS = 66, + kSpriteBulletW = 67, + kSpriteBulletE = 68, + kSpriteBulletSW = 85, + kSpriteBulletSE = 86, + kSpriteBulletNW = 87, + kSpriteBulletNE = 88 +}; + +enum Animation { + kAnimationEnemyRound = 0, + kAnimationEnemyRoundExplode = 1, + kAnimationEnemySquare = 2, + kAnimationEnemySquareExplode = 3, + kAnimationMouthKiss = 33, + kAnimationMouthBite = 34 +}; + +static const int kMapTileWidth = 24; +static const int kMapTileHeight = 24; + +static const int kPlayAreaX = 120; +static const int kPlayAreaY = 7; +static const int kPlayAreaWidth = 192; +static const int kPlayAreaHeight = 113; + +static const int kPlayAreaBorderWidth = kPlayAreaWidth / 2; +static const int kPlayAreaBorderHeight = kPlayAreaHeight / 2; + +static const int kTextAreaLeft = 9; +static const int kTextAreaTop = 7; +static const int kTextAreaRight = 104; +static const int kTextAreaBottom = 107; + +static const int kTextAreaBigBottom = 142; + +const byte Penetration::kPalettes[kFloorCount][3 * kPaletteSize] = { + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x34, 0x00, 0x25, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x2C, 0x0D, 0x22, + 0x2B, 0x2E, 0x32, + 0x12, 0x09, 0x20, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x25, 0x22, 0x2F, + 0x1A, 0x14, 0x28, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + }, + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x37, 0x00, 0x24, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x30, 0x0E, 0x16, + 0x2B, 0x2E, 0x32, + 0x22, 0x0E, 0x26, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x36, 0x28, 0x36, + 0x30, 0x1E, 0x2A, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + }, + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x3F, 0x14, 0x22, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x30, 0x10, 0x10, + 0x2B, 0x2E, 0x32, + 0x2A, 0x12, 0x12, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x3F, 0x23, 0x31, + 0x39, 0x20, 0x2A, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + } +}; + +const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = { + { + { // Real mode, floor 0 + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 50, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50, + 50, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 0, 50, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 0, 0, 50, 50, 50, 50, 0, 54, 55, 0, 0, 50, 0, 50, + 50, 0, 50, 49, 0, 50, 0, 52, 53, 0, 50, 50, 50, 0, 0, 0, 50, + 50, 57, 0, 50, 0, 0, 0, 50, 50, 50, 0, 0, 56, 50, 54, 55, 50, + 50, 50, 0, 0, 50, 50, 50, 0, 0, 0, 0, 50, 0, 0, 50, 0, 50, + 50, 51, 50, 0, 54, 55, 0, 0, 50, 50, 50, 50, 52, 53, 50, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, 50, 0, 0, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 0, 50, + 50, 50, 0, 52, 53, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, 50, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0 + }, + { // Real mode, floor 1 + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 50, 51, 52, 53, 0, 0, 52, 53, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 50, 0, 50, 0, 50, 0, 50, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 52, 53, 0, 0, 0, 0, 0, 52, 53, 0, 52, 53, 50, + 50, 57, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 50, 52, 53, 0, 0, 52, 53, 0, 0, 0, 0, 0, 54, 55, 50, + 50, 0, 50, 0, 50, 0, 50, 50, 0, 50, 50, 0, 50, 0, 50, 50, 50, + 50, 0, 50, 49, 0, 0, 52, 53, 0, 52, 53, 0, 0, 0, 50, 56, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 0, 0, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0 + }, + { // Real mode, floor 2 + 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 52, 53, 0, 0, 0, 0, 50, 50, 50, 0, 0, 0, 0, 52, 53, 50, + 50, 0, 50, 50, 50, 0, 0, 0, 50, 0, 0, 0, 50, 50, 50, 0, 50, + 50, 0, 50, 52, 53, 50, 50, 52, 53, 0, 50, 50, 54, 55, 50, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 50, 0, 50, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 52, 53, 50, + 0, 50, 0, 50, 50, 50, 0, 57, 50, 51, 0, 50, 50, 50, 0, 50, 0, + 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 52, 53, 50, 0, 0, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 50, 56, 50, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 54, 55, 50, 50, 0, 0, 0, 50, 50, 54, 55, 50, 0, 50, + 50, 0, 50, 50, 50, 0, 0, 0, 50, 0, 0, 0, 50, 50, 50, 0, 50, + 50, 52, 53, 0, 0, 0, 0, 50, 50, 50, 0, 0, 0, 0, 52, 53, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0 + } + }, + { + { // Test mode, floor 0 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 56, 0, 50, 0, 0, 52, 53, 0, 0, 0, 0, 52, 53, 0, 51, 50, + 50, 0, 0, 50, 0, 0, 0, 50, 0, 54, 55, 50, 0, 50, 50, 50, 50, + 50, 52, 53, 50, 50, 0, 0, 50, 50, 50, 50, 50, 0, 50, 0, 0, 50, + 50, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 50, 49, 50, 0, 0, 50, + 50, 0, 54, 55, 0, 50, 50, 54, 55, 0, 50, 50, 50, 0, 0, 0, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, 54, 55, 50, + 50, 0, 50, 0, 50, 0, 0, 50, 0, 0, 0, 50, 0, 0, 0, 0, 50, + 50, 0, 50, 0, 50, 54, 55, 50, 0, 50, 50, 50, 0, 50, 0, 0, 50, + 50, 50, 50, 50, 50, 0, 0, 50, 0, 0, 0, 0, 0, 50, 54, 55, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 50, 50, 50, 50, 50, 0, 0, 0, 50, + 50, 57, 0, 52, 53, 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + }, + { // Test mode, floor 1 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, + 50, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 54, 55, 0, 50, + 50, 0, 50, 52, 53, 0, 0, 50, 0, 0, 54, 55, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 0, 52, 53, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 50, 50, 50, 50, 49, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 0, 50, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 51, 0, 0, 52, 53, 50, 0, 50, 0, 50, + 50, 57, 50, 0, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 0, 50, + 50, 50, 50, 0, 50, 56, 0, 0, 0, 54, 55, 0, 0, 0, 50, 0, 50, + 50, 56, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 50, + 50, 50, 50, 50, 0, 0, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + }, + { // Test mode, floor 2 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 57, 50, 54, 55, 0, 50, 54, 55, 0, 50, 0, 52, 53, 50, 51, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 0, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 52, 53, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 0, 50, 0, 50, 0, 0, 0, 50, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 52, 53, 0, 50, 52, 53, 56, 50, 0, 54, 55, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + } + } +}; + +static const int kLanguageCount = 5; +static const int kFallbackLanguage = 2; // English + +enum String { + kString3rdBasement = 0, + kString2ndBasement, + kString1stBasement, + kStringNoExit, + kStringYouHave, + kString2Exits, + kString1Exit, + kStringToReach, + kStringUpperLevel1, + kStringUpperLevel2, + kStringLevel0, + kStringPenetration, + kStringSuccessful, + kStringDanger, + kStringGynoides, + kStringActivated, + kStringCount }; -Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _objects(0) { +static const char *kStrings[kLanguageCount][kStringCount] = { + { // French + "3EME SOUS-SOL", + "2EME SOUS-SOL", + "1ER SOUS-SOL", + "SORTIE REFUSEE", + "Vous disposez", + "de deux sorties", + "d\'une sortie", + "pour l\'acc\212s au", + "niveau", + "sup\202rieur", + "- NIVEAU 0 -", + "PENETRATION", + "REUSSIE", + "DANGER", + "GYNOIDES", + "ACTIVEES" + }, + { // German + // NOTE: The original had very broken German there. We provide proper(ish) German instead. + // B0rken text in the comments after each line + "3. UNTERGESCHOSS", // "3. U.-GESCHOSS"" + "2. UNTERGESCHOSS", // "2. U.-GESCHOSS" + "1. UNTERGESCHOSS", // "1. U.-GESCHOSS" + "AUSGANG GESPERRT", + "Sie haben", + "zwei Ausg\204nge", // "zwei Ausgang" + "einen Ausgang", // "Fortsetztung" + "um das obere", // "" + "Stockwerk zu", // "" + "erreichen", // "" + "- STOCKWERK 0 -", // "0 - HOHE" + "PENETRATION", // "DURCHDRIGEN" + "ERFOLGREICH", // "ERFOLG" + "GEFAHR", + "GYNOIDE", + "AKTIVIERT", + }, + { // English + "3RD BASEMENT", + "2ND BASEMENT", + "1ST BASEMENT", + "NO EXIT", + "You have", + "2 exits", + "1 exit", + "to reach upper", + "level", + "", + "- 0 LEVEL -", + "PENETRATION", + "SUCCESSFUL", + "DANGER", + "GYNOIDES", + "ACTIVATED", + }, + { // Spanish + "3ER. SUBSUELO", + "2D. SUBSUELO", + "1ER. SUBSUELO", + "SALIDA RECHAZADA", + "Dispones", + "de dos salidas", + "de una salida", + "para acceso al", + "nivel", + "superior", + "- NIVEL 0 -", + "PENETRACION", + "CONSEGUIDA", + "PELIGRO", + "GYNOIDAS", + "ACTIVADAS", + }, + { // Italian + "SOTTOSUOLO 3", + "SOTTOSUOLO 2", + "SOTTOSUOLO 1", + "NON USCITA", + "avete", + "due uscite", + "un\' uscita", + "per accedere al", + "livello", + "superiore", + "- LIVELLO 0 -", + "PENETRAZIONE", + "RIUSCITA", + "PERICOLO", + "GYNOIDI", + "ATTIVATE", + } +}; + + +Penetration::MapObject::MapObject(uint16 tX, uint16 tY, uint16 mX, uint16 mY, uint16 w, uint16 h) : + tileX(tX), tileY(tY), mapX(mX), mapY(mY), width(w), height(h) { + + isBlocking = true; +} + +Penetration::MapObject::MapObject(uint16 tX, uint16 tY, uint16 w, uint16 h) : + tileX(tX), tileY(tY), width(w), height(h) { + + isBlocking = true; + + setMapFromTilePosition(); +} + +void Penetration::MapObject::setTileFromMapPosition() { + tileX = (mapX + (width / 2)) / kMapTileWidth; + tileY = (mapY + (height / 2)) / kMapTileHeight; +} + +void Penetration::MapObject::setMapFromTilePosition() { + mapX = tileX * kMapTileWidth; + mapY = tileY * kMapTileHeight; +} + +bool Penetration::MapObject::isIn(uint16 mX, uint16 mY) const { + if ((mX < mapX) || (mY < mapY)) + return false; + if ((mX > (mapX + width - 1)) || (mY > (mapY + height - 1))) + return false; + + return true; +} + +bool Penetration::MapObject::isIn(uint16 mX, uint16 mY, uint16 w, uint16 h) const { + return isIn(mX , mY ) || + isIn(mX + w - 1, mY ) || + isIn(mX , mY + h - 1) || + isIn(mX + w - 1, mY + h - 1); +} + +bool Penetration::MapObject::isIn(const MapObject &obj) const { + return isIn(obj.mapX, obj.mapY, obj.width, obj.height); +} + + +Penetration::ManagedMouth::ManagedMouth(uint16 tX, uint16 tY, MouthType t) : + MapObject(tX, tY, 0, 0), mouth(0), type(t) { + +} + +Penetration::ManagedMouth::~ManagedMouth() { + delete mouth; +} + + +Penetration::ManagedSub::ManagedSub(uint16 tX, uint16 tY) : + MapObject(tX, tY, kMapTileWidth, kMapTileHeight), sub(0) { + +} + +Penetration::ManagedSub::~ManagedSub() { + delete sub; +} + + +Penetration::ManagedEnemy::ManagedEnemy() : MapObject(0, 0, 0, 0), enemy(0), dead(false) { +} + +Penetration::ManagedEnemy::~ManagedEnemy() { + delete enemy; +} + +void Penetration::ManagedEnemy::clear() { + delete enemy; + + enemy = 0; +} + + +Penetration::ManagedBullet::ManagedBullet() : MapObject(0, 0, 0, 0), bullet(0) { +} + +Penetration::ManagedBullet::~ManagedBullet() { + delete bullet; +} + +void Penetration::ManagedBullet::clear() { + delete bullet; + + bullet = 0; +} + + +Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0), + _shieldMeter(0), _healthMeter(0), _floor(0), _isPlaying(false) { + _background = new Surface(320, 200, 1); + + _shieldMeter = new Meter(11, 119, 92, 3, kColorShield, kColorBlack, 920, Meter::kFillToRight); + _healthMeter = new Meter(11, 137, 92, 3, kColorHealth, kColorBlack, 920, Meter::kFillToRight); + + _map = new Surface(kMapWidth * kMapTileWidth + kPlayAreaWidth , + kMapHeight * kMapTileHeight + kPlayAreaHeight, 1); } Penetration::~Penetration() { deinit(); + delete _map; + + delete _shieldMeter; + delete _healthMeter; + delete _background; } -bool Penetration::play(uint16 var1, uint16 var2, uint16 var3) { +bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { + _hasAccessPass = hasAccessPass; + _hasMaxEnergy = hasMaxEnergy; + _testMode = testMode; + + _isPlaying = true; + init(); initScreen(); + drawFloorText(); + _vm->_draw->blitInvalidated(); _vm->_video->retrace(); - while (!_vm->_util->keyPressed() && !_vm->shouldQuit()) - _vm->_util->longDelay(1); + + while (!_vm->shouldQuit() && !_quit && !isDead() && !hasWon()) { + enemiesCreate(); + bulletsMove(); + updateAnims(); + + // Draw, fade in if necessary and wait for the end of the frame + _vm->_draw->blitInvalidated(); + fadeIn(); + _vm->_util->waitEndFrame(false); + + // Handle the input + checkInput(); + + // Handle the sub movement + handleSub(); + + // Handle the enemies movement + enemiesMove(); + + checkExited(); + + if (_shotCoolDown > 0) + _shotCoolDown--; + } deinit(); - return true; + drawEndText(); + + _isPlaying = false; + + return hasWon(); +} + +bool Penetration::isPlaying() const { + return _isPlaying; +} + +void Penetration::cheatWin() { + _floor = 3; } void Penetration::init() { + // Load sounds + _vm->_sound->sampleLoad(&_soundShield , SOUND_SND, "boucl.snd"); + _vm->_sound->sampleLoad(&_soundBite , SOUND_SND, "pervet.snd"); + _vm->_sound->sampleLoad(&_soundKiss , SOUND_SND, "baise.snd"); + _vm->_sound->sampleLoad(&_soundShoot , SOUND_SND, "tirgim.snd"); + _vm->_sound->sampleLoad(&_soundExit , SOUND_SND, "trouve.snd"); + _vm->_sound->sampleLoad(&_soundExplode, SOUND_SND, "virmor.snd"); + + _quit = false; + for (int i = 0; i < kKeyCount; i++) + _keys[i] = false; + _background->clear(); _vm->_video->drawPackedSprite("hyprmef2.cmp", *_background); + _sprites = new CMPFile(_vm, "tcifplai.cmp", 320, 200); _objects = new ANIFile(_vm, "tcite.ani", 320); + + // The shield starts down + _shieldMeter->setValue(0); + + // If we don't have the max energy tokens, the health starts at 1/3 strength + if (_hasMaxEnergy) + _healthMeter->setMaxValue(); + else + _healthMeter->setValue(_healthMeter->getMaxValue() / 3); + + _floor = 0; + + _shotCoolDown = 0; + + createMap(); } void Penetration::deinit() { + _soundShield.free(); + _soundBite.free(); + _soundKiss.free(); + _soundShoot.free(); + _soundExit.free(); + _soundExplode.free(); + + clearMap(); + delete _objects; + delete _sprites; _objects = 0; + _sprites = 0; +} + +void Penetration::clearMap() { + _mapAnims.clear(); + _anims.clear(); + + _blockingObjects.clear(); + + _walls.clear(); + _exits.clear(); + _shields.clear(); + _mouths.clear(); + + for (int i = 0; i < kEnemyCount; i++) + _enemies[i].clear(); + for (int i = 0; i < kMaxBulletCount; i++) + _bullets[i].clear(); + + delete _sub; + + _sub = 0; + + _map->fill(kColorBlack); +} + +void Penetration::createMap() { + if (_floor >= kFloorCount) + error("Geisha: Invalid floor %d in minigame penetration", _floor); + + clearMap(); + + const byte *mapTiles = kMaps[_testMode ? 1 : 0][_floor]; + + bool exitWorks; + + // Draw the map tiles + for (int y = 0; y < kMapHeight; y++) { + for (int x = 0; x < kMapWidth; x++) { + const byte mapTile = mapTiles[y * kMapWidth + x]; + + const int posX = kPlayAreaBorderWidth + x * kMapTileWidth; + const int posY = kPlayAreaBorderHeight + y * kMapTileHeight; + + switch (mapTile) { + case 0: // Floor + _sprites->draw(*_map, kSpriteFloor, posX, posY); + break; + + case 49: // Emergency exit (needs access pass) + + exitWorks = _hasAccessPass; + if (exitWorks) { + _sprites->draw(*_map, kSpriteExit, posX, posY); + _exits.push_back(MapObject(x, y, 0, 0)); + } else { + _sprites->draw(*_map, kSpriteWall, posX, posY); + _walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight)); + } + + break; + + case 50: // Wall + _sprites->draw(*_map, kSpriteWall, posX, posY); + _walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight)); + break; + + case 51: // Regular exit + + // A regular exit works always in test mode. + // But if we're in real mode, and on the last floor, it needs an access pass + exitWorks = _testMode || (_floor < 2) || _hasAccessPass; + + if (exitWorks) { + _sprites->draw(*_map, kSpriteExit, posX, posY); + _exits.push_back(MapObject(x, y, 0, 0)); + } else { + _sprites->draw(*_map, kSpriteWall, posX, posY); + _walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight)); + } + + break; + + case 52: // Left side of biting mouth + _mouths.push_back(ManagedMouth(x, y, kMouthTypeBite)); + + _mouths.back().mouth = + new Mouth(*_objects, *_sprites, kAnimationMouthBite, kSpriteMouthBite, kSpriteFloor); + + _mouths.back().mouth->setPosition(posX, posY); + break; + + case 53: // Right side of biting mouth + break; + + case 54: // Left side of kissing mouth + _mouths.push_back(ManagedMouth(x, y, kMouthTypeKiss)); + + _mouths.back().mouth = + new Mouth(*_objects, *_sprites, kAnimationMouthKiss, kSpriteMouthKiss, kSpriteFloor); + + _mouths.back().mouth->setPosition(posX, posY); + break; + + case 55: // Right side of kissing mouth + break; + + case 56: // Shield lying on the floor + _sprites->draw(*_map, kSpriteFloor , posX , posY ); // Floor + _sprites->draw(*_map, kSpriteFloorShield, posX + 4, posY + 8); // Shield + + _map->fillRect(posX + 4, posY + 8, posX + 7, posY + 18, kColorFloor); // Area left to shield + _map->fillRect(posX + 17, posY + 8, posX + 20, posY + 18, kColorFloor); // Area right to shield + + _shields.push_back(MapObject(x, y, 0, 0)); + break; + + case 57: // Start position + _sprites->draw(*_map, kSpriteFloor, posX, posY); + + delete _sub; + + _sub = new ManagedSub(x, y); + + _sub->sub = new Submarine(*_objects); + _sub->sub->setPosition(kPlayAreaX + kPlayAreaBorderWidth, kPlayAreaY + kPlayAreaBorderHeight); + break; + } + } + } + + if (!_sub) + error("Geisha: No starting position in floor %d (testmode: %d)", _floor, _testMode); + + // Walls + for (Common::List<MapObject>::iterator w = _walls.begin(); w != _walls.end(); ++w) + _blockingObjects.push_back(&*w); + + // Mouths + for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); ++m) + _mapAnims.push_back(m->mouth); + + // Sub + _blockingObjects.push_back(_sub); + _anims.push_back(_sub->sub); + + // Moving enemies + for (int i = 0; i < kEnemyCount; i++) { + _enemies[i].enemy = new ANIObject(*_objects); + + _enemies[i].enemy->setPause(true); + _enemies[i].enemy->setVisible(false); + + _enemies[i].isBlocking = false; + + _blockingObjects.push_back(&_enemies[i]); + _mapAnims.push_back(_enemies[i].enemy); + } + + // Bullets + for (int i = 0; i < kMaxBulletCount; i++) { + _bullets[i].bullet = new ANIObject(*_sprites); + + _bullets[i].bullet->setPause(true); + _bullets[i].bullet->setVisible(false); + + _bullets[i].isBlocking = false; + + _mapAnims.push_back(_bullets[i].bullet); + } +} + +void Penetration::drawFloorText() { + _vm->_draw->_backSurface->fillRect(kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBottom, kColorBlack); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBottom); + + const Font *font = _vm->_draw->_fonts[2]; + if (!font) + return; + + const char **strings = kStrings[getLanguage()]; + + const char *floorString = 0; + if (_floor == 0) + floorString = strings[kString3rdBasement]; + else if (_floor == 1) + floorString = strings[kString2ndBasement]; + else if (_floor == 2) + floorString = strings[kString1stBasement]; + + Surface &surface = *_vm->_draw->_backSurface; + + if (floorString) + font->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1, surface); + + if (_exits.size() > 0) { + int exitCount = kString2Exits; + if (_exits.size() == 1) + exitCount = kString1Exit; + + font->drawString(strings[kStringYouHave] , 10, 38, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[exitCount] , 10, 53, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[kStringToReach] , 10, 68, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1, surface); + + } else + font->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1, surface); +} + +void Penetration::drawEndText() { + // Only draw the end text when we've won and this isn't a test run + if (!hasWon() || _testMode) + return; + + _vm->_draw->_backSurface->fillRect(kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom, kColorBlack); + + const Font *font = _vm->_draw->_fonts[2]; + if (!font) + return; + + Surface &surface = *_vm->_draw->_backSurface; + + const char **strings = kStrings[getLanguage()]; + + font->drawString(strings[kStringLevel0] , 11, 21, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1, surface); + font->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1, surface); + + font->drawString(strings[kStringDanger] , 11, 82, kColorFloorText, kColorBlack, 1, surface); + font->drawString(strings[kStringGynoides] , 11, 98, kColorFloorText, kColorBlack, 1, surface); + font->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1, surface); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom); + _vm->_draw->blitInvalidated(); + _vm->_video->retrace(); +} + +void Penetration::fadeIn() { + if (!_needFadeIn) + return; + + // Fade to palette + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); + _needFadeIn = false; +} + +void Penetration::setPalette() { + // Fade to black + _vm->_palAnim->fade(0, 0, 0); + + // Set palette + memcpy(_vm->_draw->_vgaPalette , kPalettes[_floor], 3 * kPaletteSize); + memcpy(_vm->_draw->_vgaSmallPalette, kPalettes[_floor], 3 * kPaletteSize); + + _needFadeIn = true; } void Penetration::initScreen() { _vm->_util->setFrameRate(15); - memcpy(_vm->_draw->_vgaPalette , kPalette, 48); - memcpy(_vm->_draw->_vgaSmallPalette, kPalette, 48); + setPalette(); + + // Draw the shield meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 117, 0); // Meter frame + _sprites->draw(*_background, 271, 176, 282, 183, 9, 108, 0); // Shield - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + // Draw the health meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 135, 0); // Meter frame + _sprites->draw(*_background, 283, 176, 292, 184, 9, 126, 0); // Heart _vm->_draw->_backSurface->blit(*_background); _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); } +void Penetration::enemiesCreate() { + for (int i = 0; i < kEnemyCount; i++) { + ManagedEnemy &enemy = _enemies[i]; + + if (enemy.enemy->isVisible()) + continue; + + enemy.enemy->setAnimation((i & 1) ? kAnimationEnemySquare : kAnimationEnemyRound); + enemy.enemy->setMode(ANIObject::kModeContinuous); + enemy.enemy->setPause(false); + enemy.enemy->setVisible(true); + + int16 width, height; + enemy.enemy->getFrameSize(width, height); + + enemy.width = width; + enemy.height = height; + + do { + enemy.mapX = _vm->_util->getRandom(kMapWidth) * kMapTileWidth + 2; + enemy.mapY = _vm->_util->getRandom(kMapHeight) * kMapTileHeight + 4; + enemy.setTileFromMapPosition(); + } while (isBlocked(enemy, enemy.mapX, enemy.mapY)); + + const int posX = kPlayAreaBorderWidth + enemy.mapX; + const int posY = kPlayAreaBorderHeight + enemy.mapY; + + enemy.enemy->setPosition(posX, posY); + + enemy.isBlocking = true; + enemy.dead = false; + } +} + +void Penetration::enemyMove(ManagedEnemy &enemy, int x, int y) { + if ((x == 0) && (y == 0)) + return; + + MapObject *blockedBy; + findPath(enemy, x, y, &blockedBy); + + enemy.setTileFromMapPosition(); + + const int posX = kPlayAreaBorderWidth + enemy.mapX; + const int posY = kPlayAreaBorderHeight + enemy.mapY; + + enemy.enemy->setPosition(posX, posY); + + if (blockedBy == _sub) + enemyAttack(enemy); +} + +void Penetration::enemiesMove() { + for (int i = 0; i < kEnemyCount; i++) { + ManagedEnemy &enemy = _enemies[i]; + + if (!enemy.enemy->isVisible() || enemy.dead) + continue; + + int x = 0, y = 0; + + if (enemy.mapX > _sub->mapX) + x = -8; + else if (enemy.mapX < _sub->mapX) + x = 8; + + if (enemy.mapY > _sub->mapY) + y = -8; + else if (enemy.mapY < _sub->mapY) + y = 8; + + enemyMove(enemy, x, y); + } +} + +void Penetration::enemyAttack(ManagedEnemy &enemy) { + // If we have shields, the enemy explodes at them, taking a huge chunk of energy with it. + // Otherwise, the enemy nibbles a small amount of health away. + + if (_shieldMeter->getValue() > 0) { + enemyExplode(enemy); + + healthLose(80); + } else + healthLose(5); +} + +void Penetration::enemyExplode(ManagedEnemy &enemy) { + enemy.dead = true; + enemy.isBlocking = false; + + bool isSquare = enemy.enemy->getAnimation() == kAnimationEnemySquare; + + enemy.enemy->setAnimation(isSquare ? kAnimationEnemySquareExplode : kAnimationEnemyRoundExplode); + enemy.enemy->setMode(ANIObject::kModeOnce); + + _vm->_sound->blasterPlay(&_soundExplode, 1, 0); +} + +void Penetration::checkInput() { + Common::Event event; + Common::EventManager *eventMan = g_system->getEventManager(); + + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == Common::KEYCODE_ESCAPE) + _quit = true; + else if (event.kbd.keycode == Common::KEYCODE_UP) + _keys[kKeyUp ] = true; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keys[kKeyDown ] = true; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keys[kKeyLeft ] = true; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keys[kKeyRight] = true; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keys[kKeySpace] = true; + else if (event.kbd.keycode == Common::KEYCODE_d) { + _vm->getDebugger()->attach(); + _vm->getDebugger()->onFrame(); + } + break; + + case Common::EVENT_KEYUP: + if (event.kbd.keycode == Common::KEYCODE_UP) + _keys[kKeyUp ] = false; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keys[kKeyDown ] = false; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keys[kKeyLeft ] = false; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keys[kKeyRight] = false; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keys[kKeySpace] = false; + break; + + default: + break; + } + } +} + +void Penetration::handleSub() { + int x, y; + Submarine::Direction direction = getDirection(x, y); + + subMove(x, y, direction); + + if (_keys[kKeySpace]) + subShoot(); +} + +bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y, MapObject **blockedBy) { + + if ((x < 0) || (y < 0)) + return true; + if (((x + self.width - 1) >= (kMapWidth * kMapTileWidth)) || + ((y + self.height - 1) >= (kMapHeight * kMapTileHeight))) + return true; + + MapObject checkSelf(0, 0, self.width, self.height); + + checkSelf.mapX = x; + checkSelf.mapY = y; + + for (Common::List<MapObject *>::iterator o = _blockingObjects.begin(); o != _blockingObjects.end(); ++o) { + MapObject &obj = **o; + + if (&obj == &self) + continue; + + if (!obj.isBlocking) + continue; + + if (obj.isIn(checkSelf) || checkSelf.isIn(obj)) { + if (blockedBy && !*blockedBy) + *blockedBy = &obj; + + return true; + } + } + + return false; +} + +void Penetration::findPath(MapObject &obj, int x, int y, MapObject **blockedBy) { + if (blockedBy) + *blockedBy = 0; + + while ((x != 0) || (y != 0)) { + uint16 oldX = obj.mapX; + uint16 oldY = obj.mapY; + + uint16 newX = obj.mapX; + if (x > 0) { + newX++; + x--; + } else if (x < 0) { + newX--; + x++; + } + + if (!isBlocked(obj, newX, obj.mapY, blockedBy)) + obj.mapX = newX; + + uint16 newY = obj.mapY; + if (y > 0) { + newY++; + y--; + } else if (y < 0) { + newY--; + y++; + } + + if (!isBlocked(obj, obj.mapX, newY, blockedBy)) + obj.mapY = newY; + + if ((obj.mapX == oldX) && (obj.mapY == oldY)) + break; + } +} + +void Penetration::subMove(int x, int y, Submarine::Direction direction) { + if (!_sub->sub->canMove()) + return; + + if ((x == 0) && (y == 0)) + return; + + findPath(*_sub, x, y); + + _sub->setTileFromMapPosition(); + + _sub->sub->turn(direction); + + checkShields(); + checkMouths(); + checkExits(); +} + +void Penetration::subShoot() { + if (!_sub->sub->canMove() || _sub->sub->isShooting()) + return; + + if (_shotCoolDown > 0) + return; + + // Creating a bullet + int slot = findEmptyBulletSlot(); + if (slot < 0) + return; + + ManagedBullet &bullet = _bullets[slot]; + + bullet.bullet->setAnimation(directionToBullet(_sub->sub->getDirection())); + + setBulletPosition(*_sub, bullet); + + const int posX = kPlayAreaBorderWidth + bullet.mapX; + const int posY = kPlayAreaBorderHeight + bullet.mapY; + + bullet.bullet->setPosition(posX, posY); + bullet.bullet->setVisible(true); + + // Shooting + _sub->sub->shoot(); + _vm->_sound->blasterPlay(&_soundShoot, 1, 0); + + _shotCoolDown = 3; +} + +void Penetration::setBulletPosition(const ManagedSub &sub, ManagedBullet &bullet) const { + bullet.mapX = sub.mapX; + bullet.mapY= sub.mapY; + + int16 sWidth, sHeight; + sub.sub->getFrameSize(sWidth, sHeight); + + int16 bWidth, bHeight; + bullet.bullet->getFrameSize(bWidth, bHeight); + + switch (sub.sub->getDirection()) { + case Submarine::kDirectionN: + bullet.mapX += sWidth / 2; + bullet.mapY -= bHeight; + + bullet.deltaX = 0; + bullet.deltaY = -8; + break; + + case Submarine::kDirectionNE: + bullet.mapX += sWidth; + bullet.mapY -= bHeight * 2; + + bullet.deltaX = 8; + bullet.deltaY = -8; + break; + + case Submarine::kDirectionE: + bullet.mapX += sWidth; + bullet.mapY += sHeight / 2 - bHeight; + + bullet.deltaX = 8; + bullet.deltaY = 0; + break; + + case Submarine::kDirectionSE: + bullet.mapX += sWidth; + bullet.mapY += sHeight; + + bullet.deltaX = 8; + bullet.deltaY = 8; + break; + + case Submarine::kDirectionS: + bullet.mapX += sWidth / 2; + bullet.mapY += sHeight; + + bullet.deltaX = 0; + bullet.deltaY = 8; + break; + + case Submarine::kDirectionSW: + bullet.mapX -= bWidth; + bullet.mapY += sHeight; + + bullet.deltaX = -8; + bullet.deltaY = 8; + break; + + case Submarine::kDirectionW: + bullet.mapX -= bWidth; + bullet.mapY += sHeight / 2 - bHeight; + + bullet.deltaX = -8; + bullet.deltaY = 0; + break; + + case Submarine::kDirectionNW: + bullet.mapX -= bWidth; + bullet.mapY -= bHeight; + + bullet.deltaX = -8; + bullet.deltaY = -8; + break; + + default: + break; + } +} + +uint16 Penetration::directionToBullet(Submarine::Direction direction) const { + switch (direction) { + case Submarine::kDirectionN: + return kSpriteBulletN; + + case Submarine::kDirectionNE: + return kSpriteBulletNE; + + case Submarine::kDirectionE: + return kSpriteBulletE; + + case Submarine::kDirectionSE: + return kSpriteBulletSE; + + case Submarine::kDirectionS: + return kSpriteBulletS; + + case Submarine::kDirectionSW: + return kSpriteBulletSW; + + case Submarine::kDirectionW: + return kSpriteBulletW; + + case Submarine::kDirectionNW: + return kSpriteBulletNW; + + default: + break; + } + + return 0; +} + +int Penetration::findEmptyBulletSlot() const { + for (int i = 0; i < kMaxBulletCount; i++) + if (!_bullets[i].bullet->isVisible()) + return i; + + return -1; +} + +void Penetration::bulletsMove() { + for (int i = 0; i < kMaxBulletCount; i++) + if (_bullets[i].bullet->isVisible()) + bulletMove(_bullets[i]); +} + +void Penetration::bulletMove(ManagedBullet &bullet) { + MapObject *blockedBy; + findPath(bullet, bullet.deltaX, bullet.deltaY, &blockedBy); + + if (blockedBy) { + checkShotEnemy(*blockedBy); + bullet.bullet->setVisible(false); + return; + } + + const int posX = kPlayAreaBorderWidth + bullet.mapX; + const int posY = kPlayAreaBorderHeight + bullet.mapY; + + bullet.bullet->setPosition(posX, posY); +} + +void Penetration::checkShotEnemy(MapObject &shotObject) { + for (int i = 0; i < kEnemyCount; i++) { + ManagedEnemy &enemy = _enemies[i]; + + if ((&enemy == &shotObject) && !enemy.dead && enemy.enemy->isVisible()) { + enemyExplode(enemy); + return; + } + } +} + +Submarine::Direction Penetration::getDirection(int &x, int &y) const { + x = _keys[kKeyRight] ? 3 : (_keys[kKeyLeft] ? -3 : 0); + y = _keys[kKeyDown ] ? 3 : (_keys[kKeyUp ] ? -3 : 0); + + if ((x > 0) && (y > 0)) + return Submarine::kDirectionSE; + if ((x > 0) && (y < 0)) + return Submarine::kDirectionNE; + if ((x < 0) && (y > 0)) + return Submarine::kDirectionSW; + if ((x < 0) && (y < 0)) + return Submarine::kDirectionNW; + if (x > 0) + return Submarine::kDirectionE; + if (x < 0) + return Submarine::kDirectionW; + if (y > 0) + return Submarine::kDirectionS; + if (y < 0) + return Submarine::kDirectionN; + + return Submarine::kDirectionNone; +} + +void Penetration::checkShields() { + for (Common::List<MapObject>::iterator s = _shields.begin(); s != _shields.end(); ++s) { + if ((s->tileX == _sub->tileX) && (s->tileY == _sub->tileY)) { + // Charge shields + _shieldMeter->setMaxValue(); + + // Play the shield sound + _vm->_sound->blasterPlay(&_soundShield, 1, 0); + + // Erase the shield from the map + _sprites->draw(*_map, 30, s->mapX + kPlayAreaBorderWidth, s->mapY + kPlayAreaBorderHeight); + _shields.erase(s); + break; + } + } +} + +void Penetration::checkMouths() { + for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); ++m) { + if (!m->mouth->isDeactivated()) + continue; + + if ((( m->tileX == _sub->tileX) && (m->tileY == _sub->tileY)) || + (((m->tileX + 1) == _sub->tileX) && (m->tileY == _sub->tileY))) { + + m->mouth->activate(); + + // Play the mouth sound and do health gain/loss + if (m->type == kMouthTypeBite) { + _vm->_sound->blasterPlay(&_soundBite, 1, 0); + healthLose(230); + } else if (m->type == kMouthTypeKiss) { + _vm->_sound->blasterPlay(&_soundKiss, 1, 0); + healthGain(120); + } + } + } +} + +void Penetration::checkExits() { + if (!_sub->sub->canMove()) + return; + + for (Common::List<MapObject>::iterator e = _exits.begin(); e != _exits.end(); ++e) { + if ((e->tileX == _sub->tileX) && (e->tileY == _sub->tileY)) { + _sub->setMapFromTilePosition(); + + _sub->sub->leave(); + + _vm->_sound->blasterPlay(&_soundExit, 1, 0); + break; + } + } +} + +void Penetration::healthGain(int amount) { + if (_shieldMeter->getValue() > 0) + _healthMeter->increase(_shieldMeter->increase(amount)); + else + _healthMeter->increase(amount); +} + +void Penetration::healthLose(int amount) { + _healthMeter->decrease(_shieldMeter->decrease(amount)); + + if (_healthMeter->getValue() == 0) + _sub->sub->die(); +} + +void Penetration::checkExited() { + if (_sub->sub->hasExited()) { + _floor++; + + if (_floor >= kFloorCount) + return; + + setPalette(); + createMap(); + drawFloorText(); + } +} + +bool Penetration::isDead() const { + return _sub && _sub->sub->isDead(); +} + +bool Penetration::hasWon() const { + return _floor >= kFloorCount; +} + +int Penetration::getLanguage() const { + if (_vm->_global->_language < kLanguageCount) + return _vm->_global->_language; + + return kFallbackLanguage; +} + +void Penetration::updateAnims() { + int16 left = 0, top = 0, right = 0, bottom = 0; + + // Clear the previous map animation frames + for (Common::List<ANIObject *>::iterator a = _mapAnims.reverse_begin(); + a != _mapAnims.end(); --a) { + + (*a)->clear(*_map, left, top, right, bottom); + } + + // Draw the current map animation frames + for (Common::List<ANIObject *>::iterator a = _mapAnims.begin(); + a != _mapAnims.end(); ++a) { + + (*a)->draw(*_map, left, top, right, bottom); + (*a)->advance(); + } + + // Clear the previous animation frames + for (Common::List<ANIObject *>::iterator a = _anims.reverse_begin(); + a != _anims.end(); --a) { + + if ((*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + } + + if (_sub) { + // Draw the map + + _vm->_draw->_backSurface->blit(*_map, _sub->mapX, _sub->mapY, + _sub->mapX + kPlayAreaWidth - 1, _sub->mapY + kPlayAreaHeight - 1, kPlayAreaX, kPlayAreaY); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kPlayAreaX, kPlayAreaY, + kPlayAreaX + kPlayAreaWidth - 1, kPlayAreaY + kPlayAreaHeight - 1); + } + + // Draw the current animation frames + for (Common::List<ANIObject *>::iterator a = _anims.begin(); + a != _anims.end(); ++a) { + + if ((*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + (*a)->advance(); + } + + // Draw the meters + _shieldMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + _healthMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); +} + } // End of namespace Geisha } // End of namespace Gob diff --git a/engines/gob/minigames/geisha/penetration.h b/engines/gob/minigames/geisha/penetration.h index c346a7bf5a..50004eba8e 100644 --- a/engines/gob/minigames/geisha/penetration.h +++ b/engines/gob/minigames/geisha/penetration.h @@ -24,34 +24,229 @@ #define GOB_MINIGAMES_GEISHA_PENETRATION_H #include "common/system.h" +#include "common/list.h" + +#include "gob/sound/sounddesc.h" + +#include "gob/minigames/geisha/submarine.h" namespace Gob { class GobEngine; class Surface; +class CMPFile; class ANIFile; namespace Geisha { +class Meter; +class Mouth; + /** Geisha's "Penetration" minigame. */ class Penetration { public: Penetration(GobEngine *vm); ~Penetration(); - bool play(uint16 var1, uint16 var2, uint16 var3); + bool play(bool hasAccessPass, bool hasMaxEnergy, bool testMode); + + bool isPlaying() const; + void cheatWin(); private: + static const int kModeCount = 2; + static const int kFloorCount = 3; + + static const int kMapWidth = 17; + static const int kMapHeight = 13; + + static const int kPaletteSize = 16; + + static const byte kPalettes[kFloorCount][3 * kPaletteSize]; + static const byte kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight]; + + static const int kEnemyCount = 9; + static const int kMaxBulletCount = 10; + + struct MapObject { + uint16 tileX; + uint16 tileY; + + uint16 mapX; + uint16 mapY; + + uint16 width; + uint16 height; + + bool isBlocking; + + MapObject(uint16 tX, uint16 tY, uint16 mX, uint16 mY, uint16 w, uint16 h); + MapObject(uint16 tX, uint16 tY, uint16 w, uint16 h); + + void setTileFromMapPosition(); + void setMapFromTilePosition(); + + bool isIn(uint16 mX, uint16 mY) const; + bool isIn(uint16 mX, uint16 mY, uint16 w, uint16 h) const; + bool isIn(const MapObject &obj) const; + }; + + enum MouthType { + kMouthTypeBite, + kMouthTypeKiss + }; + + struct ManagedMouth : public MapObject { + Mouth *mouth; + + MouthType type; + + ManagedMouth(uint16 tX, uint16 tY, MouthType t); + ~ManagedMouth(); + }; + + struct ManagedSub : public MapObject { + Submarine *sub; + + ManagedSub(uint16 tX, uint16 tY); + ~ManagedSub(); + }; + + struct ManagedEnemy : public MapObject { + ANIObject *enemy; + + bool dead; + + ManagedEnemy(); + ~ManagedEnemy(); + + void clear(); + }; + + struct ManagedBullet : public MapObject { + ANIObject *bullet; + + int16 deltaX; + int16 deltaY; + + ManagedBullet(); + ~ManagedBullet(); + + void clear(); + }; + + enum Keys { + kKeyUp = 0, + kKeyDown, + kKeyLeft, + kKeyRight, + kKeySpace, + kKeyCount + }; + GobEngine *_vm; + bool _hasAccessPass; + bool _hasMaxEnergy; + bool _testMode; + + bool _needFadeIn; + + bool _quit; + bool _keys[kKeyCount]; + Surface *_background; + CMPFile *_sprites; ANIFile *_objects; + Common::List<ANIObject *> _anims; + Common::List<ANIObject *> _mapAnims; + + Meter *_shieldMeter; + Meter *_healthMeter; + + uint8 _floor; + + Surface *_map; + + ManagedSub *_sub; + + Common::List<MapObject> _walls; + Common::List<MapObject> _exits; + Common::List<MapObject> _shields; + Common::List<ManagedMouth> _mouths; + + ManagedEnemy _enemies[kEnemyCount]; + ManagedBullet _bullets[kMaxBulletCount]; + + Common::List<MapObject *> _blockingObjects; + + uint8 _shotCoolDown; + + SoundDesc _soundShield; + SoundDesc _soundBite; + SoundDesc _soundKiss; + SoundDesc _soundShoot; + SoundDesc _soundExit; + SoundDesc _soundExplode; + + bool _isPlaying; + void init(); void deinit(); + void clearMap(); + void createMap(); + void initScreen(); + + void setPalette(); + void fadeIn(); + + void drawFloorText(); + void drawEndText(); + + bool isBlocked(const MapObject &self, int16 x, int16 y, MapObject **blockedBy = 0); + void findPath(MapObject &obj, int x, int y, MapObject **blockedBy = 0); + + void updateAnims(); + + void checkInput(); + + Submarine::Direction getDirection(int &x, int &y) const; + + void handleSub(); + void subMove(int x, int y, Submarine::Direction direction); + void subShoot(); + + int findEmptyBulletSlot() const; + uint16 directionToBullet(Submarine::Direction direction) const; + void setBulletPosition(const ManagedSub &sub, ManagedBullet &bullet) const; + + void bulletsMove(); + void bulletMove(ManagedBullet &bullet); + void checkShotEnemy(MapObject &shotObject); + + void checkExits(); + void checkShields(); + void checkMouths(); + + void healthGain(int amount); + void healthLose(int amount); + + void checkExited(); + + void enemiesCreate(); + void enemiesMove(); + void enemyMove(ManagedEnemy &enemy, int x, int y); + void enemyAttack(ManagedEnemy &enemy); + void enemyExplode(ManagedEnemy &enemy); + + bool isDead() const; + bool hasWon() const; + + int getLanguage() const; }; } // End of namespace Geisha diff --git a/engines/gob/minigames/geisha/submarine.cpp b/engines/gob/minigames/geisha/submarine.cpp new file mode 100644 index 0000000000..bf15306e5a --- /dev/null +++ b/engines/gob/minigames/geisha/submarine.cpp @@ -0,0 +1,256 @@ +/* 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 "gob/minigames/geisha/submarine.h" + +namespace Gob { + +namespace Geisha { + +enum Animation { + kAnimationDriveS = 4, + kAnimationDriveE = 5, + kAnimationDriveN = 6, + kAnimationDriveW = 7, + kAnimationDriveSE = 8, + kAnimationDriveNE = 9, + kAnimationDriveSW = 10, + kAnimationDriveNW = 11, + kAnimationShootS = 12, + kAnimationShootN = 13, + kAnimationShootW = 14, + kAnimationShootE = 15, + kAnimationShootNE = 16, + kAnimationShootSE = 17, + kAnimationShootSW = 18, + kAnimationShootNW = 19, + kAnimationExplodeN = 28, + kAnimationExplodeS = 29, + kAnimationExplodeW = 30, + kAnimationExplodeE = 31, + kAnimationExit = 32 +}; + + +Submarine::Submarine(const ANIFile &ani) : ANIObject(ani), _state(kStateMove), _direction(kDirectionNone) { + turn(kDirectionN); +} + +Submarine::~Submarine() { +} + +Submarine::Direction Submarine::getDirection() const { + return _direction; +} + +void Submarine::turn(Direction to) { + // Nothing to do + if ((to == kDirectionNone) || ((_state == kStateMove) && (_direction == to))) + return; + + _direction = to; + + move(); +} + +void Submarine::move() { + uint16 frame = getFrame(); + uint16 anim = (_state == kStateShoot) ? directionToShoot(_direction) : directionToMove(_direction); + + setAnimation(anim); + setFrame(frame); + setPause(false); + setVisible(true); + + setMode((_state == kStateShoot) ? kModeOnce : kModeContinuous); +} + +void Submarine::shoot() { + _state = kStateShoot; + + setAnimation(directionToShoot(_direction)); + setMode(kModeOnce); + setPause(false); + setVisible(true); +} + +void Submarine::die() { + if (!canMove()) + return; + + _state = kStateDie; + + setAnimation(directionToExplode(_direction)); + setMode(kModeOnce); + setPause(false); + setVisible(true); +} + +void Submarine::leave() { + _state = kStateExit; + + setAnimation(kAnimationExit); + setMode(kModeOnce); + setPause(false); + setVisible(true); +} + +void Submarine::advance() { + ANIObject::advance(); + + switch (_state) { + case kStateShoot: + if (isPaused()) { + _state = kStateMove; + + move(); + } + break; + + case kStateExit: + if (isPaused()) + _state = kStateExited; + + break; + + case kStateDie: + if (isPaused()) + _state = kStateDead; + break; + + default: + break; + } +} + +bool Submarine::canMove() const { + return (_state == kStateMove) || (_state == kStateShoot); +} + +bool Submarine::isDead() const { + return _state == kStateDead; +} + +bool Submarine::isShooting() const { + return _state == kStateShoot; +} + +bool Submarine::hasExited() const { + return _state == kStateExited; +} + +uint16 Submarine::directionToMove(Direction direction) const { + switch (direction) { + case kDirectionN: + return kAnimationDriveN; + + case kDirectionNE: + return kAnimationDriveNE; + + case kDirectionE: + return kAnimationDriveE; + + case kDirectionSE: + return kAnimationDriveSE; + + case kDirectionS: + return kAnimationDriveS; + + case kDirectionSW: + return kAnimationDriveSW; + + case kDirectionW: + return kAnimationDriveW; + + case kDirectionNW: + return kAnimationDriveNW; + + default: + break; + } + + return 0; +} + +uint16 Submarine::directionToShoot(Direction direction) const { + switch (direction) { + case kDirectionN: + return kAnimationShootN; + + case kDirectionNE: + return kAnimationShootNE; + + case kDirectionE: + return kAnimationShootE; + + case kDirectionSE: + return kAnimationShootSE; + + case kDirectionS: + return kAnimationShootS; + + case kDirectionSW: + return kAnimationShootSW; + + case kDirectionW: + return kAnimationShootW; + + case kDirectionNW: + return kAnimationShootNW; + + default: + break; + } + + return 0; +} + +uint16 Submarine::directionToExplode(Direction direction) const { + // Only 4 exploding animations (spinning clockwise) + + switch (direction) { + case kDirectionNW: + case kDirectionN: + return kAnimationExplodeN; + + case kDirectionNE: + case kDirectionE: + return kAnimationExplodeE; + + case kDirectionSE: + case kDirectionS: + return kAnimationExplodeS; + + case kDirectionSW: + case kDirectionW: + return kAnimationExplodeW; + + default: + break; + } + + return 0; +} + +} // End of namespace Geisha + +} // End of namespace Gob diff --git a/engines/gob/minigames/geisha/submarine.h b/engines/gob/minigames/geisha/submarine.h new file mode 100644 index 0000000000..a6eae57095 --- /dev/null +++ b/engines/gob/minigames/geisha/submarine.h @@ -0,0 +1,107 @@ +/* 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 GOB_MINIGAMES_GEISHA_SUBMARINE_H +#define GOB_MINIGAMES_GEISHA_SUBMARINE_H + +#include "gob/aniobject.h" + +namespace Gob { + +namespace Geisha { + +/** The submarine Geisha's "Penetration" minigame. */ +class Submarine : public ANIObject { +public: + enum Direction { + kDirectionNone, + kDirectionN, + kDirectionNE, + kDirectionE, + kDirectionSE, + kDirectionS, + kDirectionSW, + kDirectionW, + kDirectionNW + }; + + Submarine(const ANIFile &ani); + ~Submarine(); + + Direction getDirection() const; + + /** Turn to the specified direction. */ + void turn(Direction to); + + /** Play the shoot animation. */ + void shoot(); + + /** Play the exploding animation. */ + void die(); + + /** Play the exiting animation. */ + void leave(); + + /** Advance the animation to the next frame. */ + void advance(); + + /** Can the submarine move at the moment? */ + bool canMove() const; + + /** Is the submarine dead? */ + bool isDead() const; + + /** Is the submarine shooting? */ + bool isShooting() const; + + /** Has the submarine finished exiting the level? */ + bool hasExited() const; + +private: + enum State { + kStateNone = 0, + kStateMove, + kStateShoot, + kStateExit, + kStateExited, + kStateDie, + kStateDead + }; + + State _state; + Direction _direction; + + /** Map the directions to move animation indices. */ + uint16 directionToMove(Direction direction) const; + /** Map the directions to shoot animation indices. */ + uint16 directionToShoot(Direction direction) const; + /** Map the directions to explode animation indices. */ + uint16 directionToExplode(Direction direction) const; + + void move(); +}; + +} // End of namespace Geisha + +} // End of namespace Gob + +#endif // GOB_MINIGAMES_GEISHA_SUBMARINE_H diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 9da5a82de2..d5ee6478be 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -3,6 +3,7 @@ MODULE := engines/gob MODULE_OBJS := \ anifile.o \ aniobject.o \ + backbuffer.o \ cheater.o \ cheater_geisha.o \ cmpfile.o \ @@ -11,7 +12,6 @@ MODULE_OBJS := \ databases.o \ dbase.o \ decfile.o \ - detection.o \ draw.o \ draw_v1.o \ draw_v2.o \ @@ -44,6 +44,7 @@ MODULE_OBJS := \ inter_v2.o \ inter_bargon.o \ inter_fascin.o \ + inter_littlered.o \ inter_inca2.o \ inter_playtoons.o \ inter_v3.o \ @@ -76,10 +77,24 @@ MODULE_OBJS := \ demos/demoplayer.o \ demos/scnplayer.o \ demos/batplayer.o \ + detection/detection.o \ + pregob/pregob.o \ + pregob/txtfile.o \ + pregob/gctfile.o \ + pregob/seqfile.o \ + pregob/onceupon/onceupon.o \ + pregob/onceupon/abracadabra.o \ + pregob/onceupon/babayaga.o \ + pregob/onceupon/title.o \ + pregob/onceupon/parents.o \ + pregob/onceupon/stork.o \ + pregob/onceupon/chargenchild.o \ minigames/geisha/evilfish.o \ minigames/geisha/oko.o \ minigames/geisha/meter.o \ minigames/geisha/diving.o \ + minigames/geisha/mouth.o \ + minigames/geisha/submarine.o \ minigames/geisha/penetration.o \ save/savefile.o \ save/savehandler.o \ @@ -91,6 +106,7 @@ MODULE_OBJS := \ save/saveload_v7.o \ save/saveload_geisha.o \ save/saveload_fascin.o \ + save/saveload_ajworld.o \ save/saveload_inca2.o \ save/saveload_playtoons.o \ save/saveconverter.o \ @@ -101,6 +117,8 @@ MODULE_OBJS := \ sound/sounddesc.o \ sound/pcspeaker.o \ sound/adlib.o \ + sound/musplayer.o \ + sound/adlplayer.o \ sound/infogrames.o \ sound/protracker.o \ sound/soundmixer.o \ diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 06a7130cef..b3d7ea6263 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -366,10 +366,11 @@ void Mult::doPalAnim() { palPtr->blue, 0, 0x13); palPtr = _vm->_global->_pPaletteDesc->vgaPal; - for (_counter = 0; _counter < 16; _counter++, palPtr++) + for (_counter = 0; _counter < 16; _counter++, palPtr++) { _vm->_global->_redPalette[_counter] = palPtr->red; _vm->_global->_greenPalette[_counter] = palPtr->green; _vm->_global->_bluePalette[_counter] = palPtr->blue; + } } else _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 6593565e6a..64b9d19e33 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -1082,7 +1082,7 @@ void Mult_v2::animate() { continue; for (int j = 0; j < numAnims; j++) { - Mult_Object &animObj2 = *_renderObjs[i]; + Mult_Object &animObj2 = *_renderObjs[j]; Mult_AnimData &animData2 = *(animObj2.pAnimData); if (i == j) diff --git a/engines/gob/palanim.cpp b/engines/gob/palanim.cpp index 8a5327c3f1..f90b141725 100644 --- a/engines/gob/palanim.cpp +++ b/engines/gob/palanim.cpp @@ -75,47 +75,28 @@ bool PalAnim::fadeStepColor(int color) { bool PalAnim::fadeStep(int16 oper) { bool stop = true; - byte newRed; - byte newGreen; - byte newBlue; if (oper == 0) { - if (_vm->_global->_setAllPalette) { - if (_vm->_global->_inVM != 0) - error("PalAnim::fadeStep(): _vm->_global->_inVM != 0 not supported"); - - for (int i = 0; i < 256; i++) { - newRed = fadeColor(_vm->_global->_redPalette[i], _toFadeRed[i]); - newGreen = fadeColor(_vm->_global->_greenPalette[i], _toFadeGreen[i]); - newBlue = fadeColor(_vm->_global->_bluePalette[i], _toFadeBlue[i]); - - if ((_vm->_global->_redPalette[i] != newRed) || - (_vm->_global->_greenPalette[i] != newGreen) || - (_vm->_global->_bluePalette[i] != newBlue)) { - - _vm->_video->setPalElem(i, newRed, newGreen, newBlue, 0, 0x13); - - _vm->_global->_redPalette[i] = newRed; - _vm->_global->_greenPalette[i] = newGreen; - _vm->_global->_bluePalette[i] = newBlue; - stop = false; - } - } - } else { - for (int i = 0; i < 16; i++) { - - _vm->_video->setPalElem(i, - fadeColor(_vm->_global->_redPalette[i], _toFadeRed[i]), - fadeColor(_vm->_global->_greenPalette[i], _toFadeGreen[i]), - fadeColor(_vm->_global->_bluePalette[i], _toFadeBlue[i]), - -1, _vm->_global->_videoMode); - - if ((_vm->_global->_redPalette[i] != _toFadeRed[i]) || - (_vm->_global->_greenPalette[i] != _toFadeGreen[i]) || - (_vm->_global->_bluePalette[i] != _toFadeBlue[i])) - stop = false; + int colorCount = _vm->_global->_setAllPalette ? _vm->_global->_colorCount : 256; + + for (int i = 0; i < colorCount; i++) { + byte newRed = fadeColor(_vm->_global->_redPalette [i], _toFadeRed [i]); + byte newGreen = fadeColor(_vm->_global->_greenPalette[i], _toFadeGreen[i]); + byte newBlue = fadeColor(_vm->_global->_bluePalette [i], _toFadeBlue [i]); + + if ((_vm->_global->_redPalette [i] != newRed ) || + (_vm->_global->_greenPalette[i] != newGreen) || + (_vm->_global->_bluePalette [i] != newBlue)) { + + _vm->_video->setPalElem(i, newRed, newGreen, newBlue, 0, 0x13); + + _vm->_global->_redPalette [i] = newRed; + _vm->_global->_greenPalette[i] = newGreen; + _vm->_global->_bluePalette [i] = newBlue; + stop = false; } } + } else if ((oper > 0) && (oper < 4)) stop = fadeStepColor(oper - 1); @@ -124,44 +105,18 @@ bool PalAnim::fadeStep(int16 oper) { void PalAnim::fade(Video::PalDesc *palDesc, int16 fadeV, int16 allColors) { bool stop; - int16 i; if (_vm->shouldQuit()) return; _fadeValue = (fadeV < 0) ? -fadeV : 2; - if (!_vm->_global->_setAllPalette) { - if (!palDesc) { - for (i = 0; i < 16; i++) { - _toFadeRed[i] = 0; - _toFadeGreen[i] = 0; - _toFadeBlue[i] = 0; - } - } else { - for (i = 0; i < 16; i++) { - _toFadeRed[i] = palDesc->vgaPal[i].red; - _toFadeGreen[i] = palDesc->vgaPal[i].green; - _toFadeBlue[i] = palDesc->vgaPal[i].blue; - } - } - } else { - if (_vm->_global->_inVM != 0) - error("PalAnim::fade(): _vm->_global->_inVM != 0 is not supported"); - - if (!palDesc) { - for (i = 0; i < 256; i++) { - _toFadeRed[i] = 0; - _toFadeGreen[i] = 0; - _toFadeBlue[i] = 0; - } - } else { - for (i = 0; i < 256; i++) { - _toFadeRed[i] = palDesc->vgaPal[i].red; - _toFadeGreen[i] = palDesc->vgaPal[i].green; - _toFadeBlue[i] = palDesc->vgaPal[i].blue; - } - } + int colorCount = _vm->_global->_setAllPalette ? _vm->_global->_colorCount : 256; + + for (int i = 0; i < colorCount; i++) { + _toFadeRed [i] = (palDesc == 0) ? 0 : palDesc->vgaPal[i].red; + _toFadeGreen[i] = (palDesc == 0) ? 0 : palDesc->vgaPal[i].green; + _toFadeBlue [i] = (palDesc == 0) ? 0 : palDesc->vgaPal[i].blue; } if (allColors == 0) { diff --git a/engines/gob/pregob/gctfile.cpp b/engines/gob/pregob/gctfile.cpp new file mode 100644 index 0000000000..08c32cda76 --- /dev/null +++ b/engines/gob/pregob/gctfile.cpp @@ -0,0 +1,306 @@ +/* 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 "common/random.h" +#include "common/stream.h" + +#include "gob/surface.h" +#include "gob/video.h" + +#include "gob/pregob/gctfile.h" + +namespace Gob { + +GCTFile::Chunk::Chunk() : type(kChunkTypeNone) { +} + + +GCTFile::GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd) : _rnd(&rnd), + _areaLeft(0), _areaTop(0), _areaRight(0), _areaBottom(0), _currentItem(0xFFFF) { + + load(gct); +} + +GCTFile::~GCTFile() { +} + +void GCTFile::load(Common::SeekableReadStream &gct) { + gct.skip(4); // Required buffer size + gct.skip(2); // Unknown + + // Read the selector and line counts for each item + const uint16 itemCount = gct.readUint16LE(); + _items.resize(itemCount); + + for (Items::iterator i = _items.begin(); i != _items.end(); ++i) { + const uint16 selector = gct.readUint16LE(); + const uint16 lineCount = gct.readUint16LE(); + + i->selector = selector; + i->lines.resize(lineCount); + } + + // Read all item lines + for (Items::iterator i = _items.begin(); i != _items.end(); ++i) { + for (Lines::iterator l = i->lines.begin(); l != i->lines.end(); ++l) { + const uint16 lineSize = gct.readUint16LE(); + + readLine(gct, *l, lineSize); + } + } + + if (gct.err()) + error("GCTFile::load(): Failed reading GCT"); +} + +void GCTFile::readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const { + line.chunks.push_back(Chunk()); + + while (lineSize > 0) { + byte c = gct.readByte(); + lineSize--; + + if (c == 0) { + // Command byte + + if (lineSize == 0) + break; + + byte cmd = gct.readByte(); + lineSize--; + + // Line end command + if (cmd == 0) + break; + + // Item reference command + if (cmd == 1) { + if (lineSize < 2) { + warning("GCTFile::readLine(): Item reference command is missing parameters"); + break; + } + + const uint32 itemRef = gct.readUint16LE(); + lineSize -= 2; + + line.chunks.push_back(Chunk()); + line.chunks.back().type = kChunkTypeItem; + line.chunks.back().item = itemRef; + + line.chunks.push_back(Chunk()); + continue; + } + + warning("GCTFile::readLine(): Invalid command 0x%02X", cmd); + break; + } + + // Text + line.chunks.back().type = kChunkTypeString; + line.chunks.back().text += (char)c; + } + + // Skip bytes we didn't read (because of errors) + gct.skip(lineSize); + + // Remove empty chunks from the end of the list + while (!line.chunks.empty() && (line.chunks.back().type == kChunkTypeNone)) + line.chunks.pop_back(); +} + +uint16 GCTFile::getLineCount(uint item) const { + if (item >= _items.size()) + return 0; + + return _items[item].lines.size(); +} + +void GCTFile::selectLine(uint item, uint16 line) { + if ((item >= _items.size()) && (item != kSelectorAll) && (item != kSelectorRandom)) + return; + + _items[item].selector = line; +} + +void GCTFile::setText(uint item, uint16 line, const Common::String &text) { + if ((item >= _items.size()) || (line >= _items[item].lines.size())) + return; + + _items[item].lines[line].chunks.clear(); + _items[item].lines[line].chunks.push_back(Chunk()); + + _items[item].lines[line].chunks.back().type = kChunkTypeString; + _items[item].lines[line].chunks.back().text = text; +} + +void GCTFile::setText(uint item, const Common::String &text) { + if (item >= _items.size()) + return; + + _items[item].selector = 0; + + _items[item].lines.resize(1); + + setText(item, 0, text); +} + +void GCTFile::reset() { + _currentItem = 0xFFFF; + _currentText.clear(); +} + +Common::String GCTFile::getLineText(const Line &line) const { + Common::String text; + + // Go over all chunks in this line + for (Chunks::const_iterator c = line.chunks.begin(); c != line.chunks.end(); ++c) { + // A chunk is either a direct string, or a reference to another item + + if (c->type == kChunkTypeItem) { + Common::List<Common::String> lines; + + getItemText(c->item, lines); + if (lines.empty()) + continue; + + if (lines.size() > 1) + warning("GCTFile::getLineText(): Referenced item has multiple lines"); + + text += lines.front(); + } else if (c->type == kChunkTypeString) + text += c->text; + } + + return text; +} + +void GCTFile::getItemText(uint item, Common::List<Common::String> &text) const { + text.clear(); + + if ((item >= _items.size()) || _items[item].lines.empty()) + return; + + uint16 line = _items[item].selector; + + // Draw all lines + if (line == kSelectorAll) { + for (Lines::const_iterator l = _items[item].lines.begin(); l != _items[item].lines.end(); ++l) + text.push_back(getLineText(*l)); + + return; + } + + // Draw random line + if (line == kSelectorRandom) + line = _rnd->getRandomNumber(_items[item].lines.size() - 1); + + if (line >= _items[item].lines.size()) + return; + + text.push_back(getLineText(_items[item].lines[line])); +} + +void GCTFile::setArea(int16 left, int16 top, int16 right, int16 bottom) { + trashBuffer(); + + _hasArea = false; + + const int16 width = right - left + 1; + const int16 height = bottom - top + 1; + if ((width <= 0) || (height <= 0)) + return; + + _areaLeft = left; + _areaTop = top; + _areaRight = right; + _areaBottom = bottom; + + _hasArea = true; + + resizeBuffer(width, height); +} + +bool GCTFile::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + return restoreScreen(dest, left, top, right, bottom); +} + +bool GCTFile::fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom) { + left = _areaLeft; + top = _areaTop; + right = _areaRight; + bottom = _areaBottom; + + if (!hasSavedBackground()) + saveScreen(dest, left, top, right, bottom); + + dest.fillRect(left, top, right, bottom, color); + + return true; +} + +bool GCTFile::finished() const { + return (_currentItem != 0xFFFF) && _currentText.empty(); +} + +bool GCTFile::draw(Surface &dest, uint16 item, const Font &font, uint8 color, + int16 &left, int16 &top, int16 &right, int16 &bottom) { + + if ((item >= _items.size()) || !_hasArea) + return false; + + left = _areaLeft; + top = _areaTop; + right = _areaRight; + bottom = _areaBottom; + + const int16 width = right - left + 1; + const int16 height = bottom - top + 1; + + const uint lineCount = height / font.getCharHeight(); + if (lineCount == 0) + return false; + + if (!hasSavedBackground()) + saveScreen(dest, left, top, right, bottom); + + if (item != _currentItem) { + _currentItem = item; + + getItemText(_currentItem, _currentText); + } + + if (_currentText.empty()) + return false; + + int16 y = top; + for (uint i = 0; (i < lineCount) && !_currentText.empty(); i++, y += font.getCharHeight()) { + const Common::String &line = _currentText.front(); + const int16 x = left + ((width - (line.size() * font.getCharWidth())) / 2); + + font.drawString(line, x, y, color, 0, true, dest); + _currentText.pop_front(); + } + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/pregob/gctfile.h b/engines/gob/pregob/gctfile.h new file mode 100644 index 0000000000..ed6351b7a8 --- /dev/null +++ b/engines/gob/pregob/gctfile.h @@ -0,0 +1,149 @@ +/* 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 GOB_PREGOB_GCTFILE_H +#define GOB_PREGOB_GCTFILE_H + +#include "common/str.h" +#include "common/array.h" +#include "common/list.h" + +#include "gob/backbuffer.h" + +namespace Common { + class RandomSource; + class SeekableReadStream; +} + +namespace Gob { + +class Surface; +class Font; + +class GCTFile : public BackBuffer { +public: + static const uint16 kSelectorAll = 0xFFFE; ///< Print all lines. + static const uint16 kSelectorRandom = 0xFFFF; ///< Print a random line. + + + GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd); + ~GCTFile(); + + /** Return the number of lines in an item. */ + uint16 getLineCount(uint item) const; + + /** Set the area the text will be printed in. */ + void setArea(int16 left, int16 top, int16 right, int16 bottom); + + /** Set which line of this item should be printed. */ + void selectLine(uint item, uint16 line); + + /** Change the text of an items' line. */ + void setText(uint item, uint16 line, const Common::String &text); + /** Change the item into one one line and set that line's text. */ + void setText(uint item, const Common::String &text); + + /** Reset the item drawing state. */ + void reset(); + + /** Clear the drawn text, restoring the original content. */ + bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + + /** Fill the text area with a color. */ + bool fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom); + + /** Draw an item onto the surface, until all text has been drawn or the area is filled. */ + bool draw(Surface &dest, uint16 item, const Font &font, uint8 color, + int16 &left, int16 &top, int16 &right, int16 &bottom); + + /** Did we draw all text? */ + bool finished() const; + +private: + /** The type of a chunk. */ + enum ChunkType { + kChunkTypeNone = 0, ///< Do nothing. + kChunkTypeString , ///< A direct string. + kChunkTypeItem ///< A reference to an item to print instead. + }; + + /** A chunk in an item text line. */ + struct Chunk { + ChunkType type; ///< The type of the chunk. + + Common::String text; ///< Text to print. + + int item; ///< Item to print instead. + + Chunk(); + }; + + typedef Common::List<Chunk> Chunks; + + /** A line in an item. */ + struct Line { + Chunks chunks; ///< The chunks that make up the line. + }; + + typedef Common::Array<Line> Lines; + + /** A GCT item. */ + struct Item { + Lines lines; ///< The text lines in the item + uint16 selector; ///< Which line to print. + }; + + typedef Common::Array<Item> Items; + + + Common::RandomSource *_rnd; + + Items _items; ///< All GCT items. + + // The area on which to print + bool _hasArea; + int16 _areaLeft; + int16 _areaTop; + int16 _areaRight; + int16 _areaBottom; + + /** Index of the current item we're drawing. */ + uint16 _currentItem; + /** Text left to draw. */ + Common::List<Common::String> _currentText; + + + // -- Loading helpers -- + + void load(Common::SeekableReadStream &gct); + void readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const; + + + // -- Draw helpers -- + + Common::String getLineText(const Line &line) const; + void getItemText(uint item, Common::List<Common::String> &text) const; +}; + +} // End of namespace Gob + +#endif // GOB_PREGOB_GCTFILE_H diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp new file mode 100644 index 0000000000..2cf6855ef8 --- /dev/null +++ b/engines/gob/pregob/onceupon/abracadabra.cpp @@ -0,0 +1,137 @@ +/* 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 "common/textconsole.h" + +#include "gob/gob.h" + +#include "gob/pregob/onceupon/abracadabra.h" + +static const uint8 kCopyProtectionColors[7] = { + 14, 11, 13, 1, 7, 12, 2 +}; + +static const uint8 kCopyProtectionShapes[7 * 20] = { + 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3, + 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4, + 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3, + 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1, + 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4, + 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2, + 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4 +}; + +static const uint8 kCopyProtectionObfuscate[4] = { + 1, 0, 2, 3 +}; + +namespace Gob { + +namespace OnceUpon { + +const OnceUpon::MenuButton Abracadabra::kAnimalsButtons = { + true, 131, 127, 183, 164, 193, 0, 243, 35, 132, 128, 0 +}; + +const OnceUpon::MenuButton Abracadabra::kAnimalButtons[] = { + {false, 37, 89, 95, 127, 37, 89, 95, 127, 131, 25, 0}, + {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1}, + {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2}, + {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3}, + {false, 180, 102, 234, 138, 180, 102, 234, 138, 133, 25, 4}, + {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5}, + {false, 113, 151, 171, 176, 113, 151, 171, 176, 131, 25, 6}, + {false, 114, 122, 151, 150, 114, 122, 151, 150, 141, 25, 7}, + {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8}, + {false, 243, 123, 295, 155, 243, 123, 295, 155, 136, 25, 9} +}; + +const char *Abracadabra::kAnimalNames[] = { + "loup", + "drag", + "arai", + "crap", + "crab", + "mous", + "saut", + "guep", + "rhin", + "scor" +}; + +// The houses where the stork can drop a bundle +const OnceUpon::MenuButton Abracadabra::kStorkHouses[] = { + {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady + {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers + {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters + {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen +}; + +// The stork bundle drop parameters +const Stork::BundleDrop Abracadabra::kStorkBundleDrops[] = { + { 14, 65, 127, true }, + { 14, 76, 152, true }, + { 14, 204, 137, true }, + { 11, 275, 179, false } +}; + +// Parameters for the stork section. +const OnceUpon::StorkParam Abracadabra::kStorkParam = { + "present.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops +}; + + +Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) { +} + +Abracadabra::~Abracadabra() { +} + +void Abracadabra::run() { + init(); + + // Copy protection + bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate); + if (_vm->shouldQuit() || !correctCP) + return; + + // Show the intro + showIntro(); + if (_vm->shouldQuit()) + return; + + // Handle the start menu + doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames); + if (_vm->shouldQuit()) + return; + + // Play the actual game + playGame(); +} + +const OnceUpon::StorkParam &Abracadabra::getStorkParameters() const { + return kStorkParam; +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h new file mode 100644 index 0000000000..8048213f5f --- /dev/null +++ b/engines/gob/pregob/onceupon/abracadabra.h @@ -0,0 +1,61 @@ +/* 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 GOB_PREGOB_ONCEUPON_ABRACADABRA_H +#define GOB_PREGOB_ONCEUPON_ABRACADABRA_H + +#include "gob/pregob/onceupon/onceupon.h" + +namespace Gob { + +namespace OnceUpon { + +class Abracadabra : public OnceUpon { +public: + Abracadabra(GobEngine *vm); + ~Abracadabra(); + + void run(); + +protected: + const StorkParam &getStorkParameters() const; + +private: + /** Definition of the menu button that leads to the animal names screen. */ + static const MenuButton kAnimalsButtons; + + /** Definition of the buttons that make up the animals in the animal names screen. */ + static const MenuButton kAnimalButtons[]; + /** File prefixes for the name of each animal. */ + static const char *kAnimalNames[]; + + // Parameters for the stork section. + static const MenuButton kStorkHouses[]; + static const Stork::BundleDrop kStorkBundleDrops[]; + static const struct StorkParam kStorkParam; +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_ABRACADABRA_H diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp new file mode 100644 index 0000000000..ef56b9dd0b --- /dev/null +++ b/engines/gob/pregob/onceupon/babayaga.cpp @@ -0,0 +1,137 @@ +/* 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 "common/textconsole.h" + +#include "gob/gob.h" + +#include "gob/pregob/onceupon/babayaga.h" + +static const uint8 kCopyProtectionColors[7] = { + 14, 11, 13, 1, 7, 12, 2 +}; + +static const uint8 kCopyProtectionShapes[7 * 20] = { + 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3, + 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4, + 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1, + 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4, + 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3, + 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4, + 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2 +}; + +static const uint8 kCopyProtectionObfuscate[4] = { + 0, 1, 2, 3 +}; + +namespace Gob { + +namespace OnceUpon { + +const OnceUpon::MenuButton BabaYaga::kAnimalsButtons = { + true, 131, 127, 183, 164, 193, 0, 245, 37, 131, 127, 0 +}; + +const OnceUpon::MenuButton BabaYaga::kAnimalButtons[] = { + {false, 34, 84, 92, 127, 34, 84, 92, 127, 131, 25, 0}, + {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1}, + {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2}, + {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3}, + {false, 180, 97, 234, 138, 180, 97, 234, 138, 133, 25, 4}, + {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5}, + {false, 113, 156, 171, 176, 113, 156, 171, 176, 131, 25, 6}, + {false, 114, 127, 151, 150, 114, 127, 151, 150, 141, 25, 7}, + {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8}, + {false, 245, 123, 293, 155, 245, 123, 293, 155, 136, 25, 9} +}; + +const char *BabaYaga::kAnimalNames[] = { + "vaut", + "drag", + "arai", + "gren", + "fauc", + "abei", + "serp", + "tort", + "sang", + "rena" +}; + +// The houses where the stork can drop a bundle +const OnceUpon::MenuButton BabaYaga::kStorkHouses[] = { + {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady + {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers + {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters + {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen +}; + +// The stork bundle drop parameters +const Stork::BundleDrop BabaYaga::kStorkBundleDrops[] = { + { 14, 35, 129, true }, + { 14, 70, 148, true }, + { 14, 206, 136, true }, + { 11, 260, 225, false } +}; + +// Parameters for the stork section. +const OnceUpon::StorkParam BabaYaga::kStorkParam = { + "present2.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops +}; + + +BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) { +} + +BabaYaga::~BabaYaga() { +} + +void BabaYaga::run() { + init(); + + // Copy protection + bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate); + if (_vm->shouldQuit() || !correctCP) + return; + + // Show the intro + showIntro(); + if (_vm->shouldQuit()) + return; + + // Handle the start menu + doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames); + if (_vm->shouldQuit()) + return; + + // Play the actual game + playGame(); +} + +const OnceUpon::StorkParam &BabaYaga::getStorkParameters() const { + return kStorkParam; +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h new file mode 100644 index 0000000000..0241f78f4e --- /dev/null +++ b/engines/gob/pregob/onceupon/babayaga.h @@ -0,0 +1,61 @@ +/* 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 GOB_PREGOB_ONCEUPON_BABAYAGA_H +#define GOB_PREGOB_ONCEUPON_BABAYAGA_H + +#include "gob/pregob/onceupon/onceupon.h" + +namespace Gob { + +namespace OnceUpon { + +class BabaYaga : public OnceUpon { +public: + BabaYaga(GobEngine *vm); + ~BabaYaga(); + + void run(); + +protected: + const StorkParam &getStorkParameters() const; + +private: + /** Definition of the menu button that leads to the animal names screen. */ + static const MenuButton kAnimalsButtons; + + /** Definition of the buttons that make up the animals in the animal names screen. */ + static const MenuButton kAnimalButtons[]; + /** File prefixes for the name of each animal. */ + static const char *kAnimalNames[]; + + // Parameters for the stork section. + static const MenuButton kStorkHouses[]; + static const Stork::BundleDrop kStorkBundleDrops[]; + static const struct StorkParam kStorkParam; +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_BABAYAGA_H diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h new file mode 100644 index 0000000000..89acb1c6bd --- /dev/null +++ b/engines/gob/pregob/onceupon/brokenstrings.h @@ -0,0 +1,60 @@ +/* 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 GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H +#define GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H + +struct BrokenString { + const char *wrong; + const char *correct; +}; + +struct BrokenStringLanguage { + const BrokenString *strings; + uint count; +}; + +static const BrokenString kBrokenStringsGerman[] = { + { "Zeichungen von Kaki," , "Zeichnungen von Kaki," }, + { "die es in seine Wachtr\204ume", "die es in seine Tagtr\204ume" }, + { " Spielerfahrung" , " Spielerfahren" }, + { " Fortgeschrittene" , " Fortgeschritten" }, + { "die Vespe" , "die Wespe" }, + { "das Rhinoceros" , "das Rhinozeros" }, + { "die Heusschrecke" , "die Heuschrecke" }, + { "Das, von Drachen gebrachte" , "Das vom Drachen gebrachte" }, + { "Am Waldesrand es sieht" , "Am Waldesrand sieht es" }, + { " das Kind den Palast." , "das Kind den Palast." }, + { "Am Waldessaum sieht" , "Am Waldesrand sieht" }, + { "tipp auf ESC!" , "dr\201cke ESC!" }, + { "Wohin fliegt der Drachen?" , "Wohin fliegt der Drache?" } +}; + +static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = { + { 0, 0 }, // French + { kBrokenStringsGerman, ARRAYSIZE(kBrokenStringsGerman) }, // German + { 0, 0 }, // English + { 0, 0 }, // Spanish + { 0, 0 }, // Italian +}; + +#endif // GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H diff --git a/engines/gob/pregob/onceupon/chargenchild.cpp b/engines/gob/pregob/onceupon/chargenchild.cpp new file mode 100644 index 0000000000..ba099e4937 --- /dev/null +++ b/engines/gob/pregob/onceupon/chargenchild.cpp @@ -0,0 +1,117 @@ +/* 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 "gob/surface.h" +#include "gob/anifile.h" + +#include "gob/pregob/onceupon/chargenchild.h" + +enum Animation { + kAnimWalkLeft = 0, + kAnimWalkRight = 1, + kAnimJumpLeft = 2, + kAnimJumpRight = 3, + kAnimTapFoot = 14 +}; + +namespace Gob { + +namespace OnceUpon { + +CharGenChild::CharGenChild(const ANIFile &ani) : ANIObject(ani) { + setPosition(265, 110); + setAnimation(kAnimWalkLeft); + setVisible(true); + setPause(false); +} + +CharGenChild::~CharGenChild() { +} + +void CharGenChild::advance() { + bool wasLastFrame = lastFrame(); + + ANIObject::advance(); + + int16 x, y, left, top, width, height; + getPosition(x, y); + getFramePosition(left, top); + getFrameSize(width, height); + + const int16 right = left + width - 1; + + switch (getAnimation()) { + case kAnimWalkLeft: + if (left <= 147) + setAnimation(kAnimWalkRight); + break; + + case kAnimWalkRight: + if (right >= 290) { + setAnimation(kAnimJumpLeft); + + setPosition(x, y - 14); + } + break; + + case kAnimJumpLeft: + if (wasLastFrame) { + setAnimation(kAnimTapFoot); + + setPosition(x, y - 10); + } + break; + + case kAnimTapFoot: + if (wasLastFrame) { + setAnimation(kAnimJumpRight); + + setPosition(x, y + 10); + } + break; + + case kAnimJumpRight: + if (wasLastFrame) { + setAnimation(kAnimWalkLeft); + + setPosition(x, y + 14); + } + break; + } +} + +CharGenChild::Sound CharGenChild::shouldPlaySound() const { + const uint16 anim = getAnimation(); + const uint16 frame = getFrame(); + + if (((anim == kAnimWalkLeft) || (anim == kAnimWalkRight)) && ((frame == 1) || (frame == 6))) + return kSoundWalk; + + if (((anim == kAnimJumpLeft) || (anim == kAnimJumpRight)) && (frame == 0)) + return kSoundJump; + + return kSoundNone; +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/chargenchild.h b/engines/gob/pregob/onceupon/chargenchild.h new file mode 100644 index 0000000000..3b09ef112a --- /dev/null +++ b/engines/gob/pregob/onceupon/chargenchild.h @@ -0,0 +1,60 @@ +/* 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 GOB_PREGOB_ONCEUPON_CHARGENCHILD_H +#define GOB_PREGOB_ONCEUPON_CHARGENCHILD_H + +#include "common/system.h" + +#include "gob/aniobject.h" + +namespace Gob { + +class Surface; +class ANIFile; + +namespace OnceUpon { + +/** The child running around on the character generator screen. */ +class CharGenChild : public ANIObject { +public: + enum Sound { + kSoundNone = 0, + kSoundWalk , + kSoundJump + }; + + CharGenChild(const ANIFile &ani); + ~CharGenChild(); + + /** Advance the animation to the next frame. */ + void advance(); + + /** Should we play a sound right now? */ + Sound shouldPlaySound() const; +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_CHARGENCHILD_H diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp new file mode 100644 index 0000000000..e4c2df34c0 --- /dev/null +++ b/engines/gob/pregob/onceupon/onceupon.cpp @@ -0,0 +1,1904 @@ +/* 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 "gob/gob.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/dataio.h" +#include "gob/surface.h" +#include "gob/draw.h" +#include "gob/video.h" +#include "gob/anifile.h" +#include "gob/aniobject.h" + +#include "gob/sound/sound.h" + +#include "gob/pregob/txtfile.h" +#include "gob/pregob/gctfile.h" + +#include "gob/pregob/onceupon/onceupon.h" +#include "gob/pregob/onceupon/palettes.h" +#include "gob/pregob/onceupon/title.h" +#include "gob/pregob/onceupon/parents.h" +#include "gob/pregob/onceupon/chargenchild.h" + +static const uint kLanguageCount = 5; + +static const uint kCopyProtectionHelpStringCount = 3; + +static const char *kCopyProtectionHelpStrings[Gob::OnceUpon::OnceUpon::kLanguageCount][kCopyProtectionHelpStringCount] = { + { // French + "Consulte le livret des animaux, rep\212re la", + "page correspondant \205 la couleur de l\'\202cran", + "et clique le symbole associ\202 \205 l\'animal affich\202.", + }, + { // German + "Suche im Tieralbum die Seite, die der Farbe auf", + "dem Bildschirm entspricht und klicke auf das", + "Tiersymbol.", + }, + { // English + "Consult the book of animals, find the page", + "corresponding to the colour of screen and click", + "the symbol associated with the animal displayed.", + }, + { // Spanish + "Consulta el libro de los animales, localiza la ", + "p\240gina que corresponde al color de la pantalla.", + "Cliquea el s\241mbolo asociado al animal que aparece.", + }, + { // Italian + "Guarda il libretto degli animali, trova la", + "pagina che corrisponde al colore dello schermo,", + "clicca il simbolo associato all\'animale presentato", + } +}; + +static const char *kCopyProtectionWrongStrings[Gob::OnceUpon::OnceUpon::kLanguageCount] = { + "Tu t\'es tromp\202, dommage...", // French + "Schade, du hast dich geirrt." , // German + "You are wrong, what a pity!" , // English + "Te equivocas, l\240stima..." , // Spanish + "Sei Sbagliato, peccato..." // Italian +}; + +static const uint kCopyProtectionShapeCount = 5; + +static const int16 kCopyProtectionShapeCoords[kCopyProtectionShapeCount][6] = { + { 0, 51, 26, 75, 60, 154}, + { 28, 51, 58, 81, 96, 151}, + { 60, 51, 94, 79, 136, 152}, + { 96, 51, 136, 71, 180, 155}, + {140, 51, 170, 77, 228, 153} +}; + +enum ClownAnimation { + kClownAnimationClownCheer = 0, + kClownAnimationClownStand = 1, + kClownAnimationClownCry = 6 +}; + +// 12 seconds delay for one area full of GCT text +static const uint32 kGCTDelay = 12000; + +namespace Gob { + +namespace OnceUpon { + +const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[] = { + {false, 29, 18, 77, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyBeginner}, + {false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyIntermediate}, + {false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyAdvanced}, +}; + +const OnceUpon::MenuButton OnceUpon::kSectionButtons[] = { + {false, 27, 121, 91, 179, 0, 0, 0, 0, 0, 0, 0}, + { true, 95, 121, 159, 179, 4, 1, 56, 49, 100, 126, 2}, + { true, 163, 121, 227, 179, 64, 1, 120, 49, 168, 126, 6}, + { true, 231, 121, 295, 179, 128, 1, 184, 49, 236, 126, 10} +}; + +const OnceUpon::MenuButton OnceUpon::kIngameButtons[] = { + {true, 108, 83, 139, 116, 0, 0, 31, 34, 108, 83, 0}, + {true, 144, 83, 175, 116, 36, 0, 67, 34, 144, 83, 1}, + {true, 180, 83, 211, 116, 72, 0, 103, 34, 180, 83, 2} +}; + +const OnceUpon::MenuButton OnceUpon::kAnimalNamesBack = { + true, 19, 13, 50, 46, 36, 0, 67, 34, 19, 13, 1 +}; + +const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = { + {true, 43, 80, 93, 115, 0, 55, 50, 90, 43, 80, 0}, + {true, 132, 80, 182, 115, 53, 55, 103, 90, 132, 80, 1}, + {true, 234, 80, 284, 115, 106, 55, 156, 90, 234, 80, 2}, + {true, 43, 138, 93, 173, 159, 55, 209, 90, 43, 138, 3}, + {true, 132, 138, 182, 173, 212, 55, 262, 90, 132, 138, 4}, + {true, 234, 138, 284, 173, 265, 55, 315, 90, 234, 138, 2} +}; + +const char *OnceUpon::kSound[kSoundCount] = { + "diamant.snd", // kSoundClick + "cigogne.snd", // kSoundStork + "saute.snd" // kSoundJump +}; + +const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = { + &OnceUpon::sectionStork, + &OnceUpon::sectionChapter1, + &OnceUpon::sectionParents, + &OnceUpon::sectionChapter2, + &OnceUpon::sectionForest0, + &OnceUpon::sectionChapter3, + &OnceUpon::sectionEvilCastle, + &OnceUpon::sectionChapter4, + &OnceUpon::sectionForest1, + &OnceUpon::sectionChapter5, + &OnceUpon::sectionBossFight, + &OnceUpon::sectionChapter6, + &OnceUpon::sectionForest2, + &OnceUpon::sectionChapter7, + &OnceUpon::sectionEnd +}; + + +OnceUpon::ScreenBackup::ScreenBackup() : palette(-1), changedCursor(false), cursorVisible(false) { + screen = new Surface(320, 200, 1); +} + +OnceUpon::ScreenBackup::~ScreenBackup() { + delete screen; +} + + +OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false), + _jeudak(0), _lettre(0), _plettre(0), _glettre(0) { + +} + +OnceUpon::~OnceUpon() { + deinit(); +} + +void OnceUpon::init() { + deinit(); + + // Open data files + + bool hasSTK1 = _vm->_dataIO->openArchive("stk1.stk", true); + bool hasSTK2 = _vm->_dataIO->openArchive("stk2.stk", true); + bool hasSTK3 = _vm->_dataIO->openArchive("stk3.stk", true); + + if (!hasSTK1 || !hasSTK2 || !hasSTK3) + error("OnceUpon::OnceUpon(): Failed to open archives"); + + _openedArchives = true; + + // Open fonts + + _jeudak = _vm->_draw->loadFont("jeudak.let"); + _lettre = _vm->_draw->loadFont("lettre.let"); + _plettre = _vm->_draw->loadFont("plettre.let"); + _glettre = _vm->_draw->loadFont("glettre.let"); + + if (!_jeudak || !_lettre || !_plettre || !_glettre) + error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)", + _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0); + + // Verify the language + + if (_vm->_global->_language == kLanguageAmerican) + _vm->_global->_language = kLanguageBritish; + + if ((_vm->_global->_language >= kLanguageCount)) + error("We do not support the language \"%s\".\n" + "If you are certain that your game copy includes this language,\n" + "please contact the ScummVM team with details about this version.\n" + "Thanks", _vm->getLangDesc(_vm->_global->_language)); + + // Load all our sounds and init the screen + + loadSounds(kSound, kSoundCount); + initScreen(); + + // We start with an invalid palette + _palette = -1; + + // No quit requested at start + _quit = false; + + // We start with no selected difficulty and at section 0 + _difficulty = kDifficultyCount; + _section = 0; + + // Default name + _name = "Nemo"; + + // Default character properties + _house = 0; + _head = 0; + _colorHair = 0; + _colorJacket = 0; + _colorTrousers = 0; +} + +void OnceUpon::deinit() { + // Free sounds + freeSounds(); + + // Free fonts + + delete _jeudak; + delete _lettre; + delete _plettre; + delete _glettre; + + _jeudak = 0; + _lettre = 0; + _plettre = 0; + _glettre = 0; + + // Close archives + + if (_openedArchives) { + _vm->_dataIO->closeArchive(true); + _vm->_dataIO->closeArchive(true); + _vm->_dataIO->closeArchive(true); + } + + _openedArchives = false; +} + +void OnceUpon::setGamePalette(uint palette) { + if (palette >= kPaletteCount) + return; + + _palette = palette; + + setPalette(kGamePalettes[palette], kPaletteSize); +} + +void OnceUpon::setGameCursor() { + Surface cursor(320, 16, 1); + + // Set the default game cursor + _vm->_video->drawPackedSprite("icon.cmp", cursor); + setCursor(cursor, 105, 0, 120, 15, 0, 0); +} + +void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom, + int16 x, int16 y) const { + + // A special way of drawing something: + // Draw every other line "downwards", wait a bit after each line + // Then, draw the remaining lines "upwards" and again wait a bit after each line. + + if (_vm->shouldQuit()) + return; + + const int16 width = right - left + 1; + const int16 height = bottom - top + 1; + + if ((width <= 0) || (height <= 0)) + return; + + // Draw the even lines downwards + for (int16 i = 0; i < height; i += 2) { + if (_vm->shouldQuit()) + return; + + _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1); + _vm->_draw->blitInvalidated(); + + _vm->_util->longDelay(1); + } + + // Draw the odd lines upwards + for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) { + if (_vm->shouldQuit()) + return; + + _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1); + _vm->_draw->blitInvalidated(); + + _vm->_util->longDelay(1); + } +} + +void OnceUpon::backupScreen(ScreenBackup &backup, bool setDefaultCursor) { + // Backup the screen and palette + backup.screen->blit(*_vm->_draw->_backSurface); + backup.palette = _palette; + + // Backup the cursor + + backup.cursorVisible = isCursorVisible(); + + backup.changedCursor = false; + if (setDefaultCursor) { + backup.changedCursor = true; + + addCursor(); + setGameCursor(); + } +} + +void OnceUpon::restoreScreen(ScreenBackup &backup) { + if (_vm->shouldQuit()) + return; + + // Restore the screen + _vm->_draw->_backSurface->blit(*backup.screen); + _vm->_draw->forceBlit(); + + // Restore the palette + if (backup.palette >= 0) + setGamePalette(backup.palette); + + // Restore the cursor + + if (!backup.cursorVisible) + hideCursor(); + + if (backup.changedCursor) + removeCursor(); + + backup.changedCursor = false; +} + +void OnceUpon::fixTXTStrings(TXTFile &txt) const { + TXTFile::LineArray &lines = txt.getLines(); + for (uint i = 0; i < lines.size(); i++) + lines[i].text = fixString(lines[i].text); +} + +#include "gob/pregob/onceupon/brokenstrings.h" +Common::String OnceUpon::fixString(const Common::String &str) const { + const BrokenStringLanguage &broken = kBrokenStrings[_vm->_global->_language]; + + for (uint i = 0; i < broken.count; i++) { + if (str == broken.strings[i].wrong) + return broken.strings[i].correct; + } + + return str; +} + +enum ClownAnimation { + kClownAnimationStand = 0, + kClownAnimationCheer = 1, + kClownAnimationCry = 2 +}; + +const PreGob::AnimProperties OnceUpon::kClownAnimations[] = { + { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 0, 0, ANIObject::kModeOnce , true, false, false, 0, 0}, + { 6, 0, ANIObject::kModeOnce , true, false, false, 0, 0} +}; + +enum CopyProtectionState { + kCPStateSetup, // Set up the screen + kCPStateWaitUser, // Waiting for the user to pick a shape + kCPStateWaitClown, // Waiting for the clown animation to finish + kCPStateFinish // Finishing +}; + +bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]) { + fadeOut(); + setPalette(kCopyProtectionPalette, kPaletteSize); + + // Load the copy protection sprites + Surface sprites[2] = {Surface(320, 200, 1), Surface(320, 200, 1)}; + + _vm->_video->drawPackedSprite("grille1.cmp", sprites[0]); + _vm->_video->drawPackedSprite("grille2.cmp", sprites[1]); + + // Load the clown animation + ANIFile ani (_vm, "grille.ani", 320); + ANIList anims; + + loadAnims(anims, ani, 1, &kClownAnimations[kClownAnimationStand]); + + // Set the copy protection cursor + setCursor(sprites[1], 5, 110, 20, 134, 3, 0); + + // We start with 2 tries left, not having a correct answer and the copy protection not set up yet + CopyProtectionState state = kCPStateSetup; + + uint8 triesLeft = 2; + int8 animalShape = -1; + bool hasCorrect = false; + + while (!_vm->shouldQuit() && (state != kCPStateFinish)) { + clearAnim(anims); + + // Set up the screen + if (state == kCPStateSetup) { + animalShape = cpSetup(colors, shapes, obfuscate, sprites); + + setAnim(*anims[0], kClownAnimations[kClownAnimationStand]); + state = kCPStateWaitUser; + } + + drawAnim(anims); + + // If we're waiting for the clown and he finished, evaluate if we're finished + if (!anims[0]->isVisible() && (state == kCPStateWaitClown)) + state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup; + + showCursor(); + fadeIn(); + + endFrame(true); + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + checkInput(mouseX, mouseY, mouseButtons); + + if (state == kCPStateWaitUser) { + // Look if we clicked a shaped and got it right + + int8 guessedShape = -1; + if (mouseButtons == kMouseButtonsLeft) + guessedShape = cpFindShape(mouseX, mouseY); + + if (guessedShape >= 0) { + hasCorrect = guessedShape == animalShape; + animalShape = -1; + + setAnim(*anims[0], kClownAnimations[hasCorrect ? kClownAnimationCheer : kClownAnimationCry]); + state = kCPStateWaitClown; + } + } + } + + freeAnims(anims); + + fadeOut(); + hideCursor(); + clearScreen(); + + // Display the "You are wrong" screen + if (!hasCorrect) + cpWrong(); + + return hasCorrect; +} + +int8 OnceUpon::cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4], + const Surface sprites[2]) { + + fadeOut(); + hideCursor(); + + // Get a random animal and animal color + int8 animalColor = _vm->_util->getRandom(7); + while ((colors[animalColor] == 1) || (colors[animalColor] == 7) || (colors[animalColor] == 11)) + animalColor = _vm->_util->getRandom(7); + + int8 animal = _vm->_util->getRandom(20); + + int8 animalShape = shapes[animalColor * 20 + animal]; + if (animal < 4) + animal = obfuscate[animal]; + + // Get the position of the animal sprite + int16 animalLeft = (animal % 4) * 80; + int16 animalTop = (animal / 4) * 50; + + uint8 sprite = 0; + if (animalTop >= 200) { + animalTop -= 200; + sprite = 1; + } + + int16 animalRight = animalLeft + 80 - 1; + int16 animalBottom = animalTop + 50 - 1; + + // Fill with the animal color + _vm->_draw->_backSurface->fill(colors[animalColor]); + + // Print the help line strings + for (uint i = 0; i < kCopyProtectionHelpStringCount; i++) { + const char * const helpString = kCopyProtectionHelpStrings[_vm->_global->_language][i]; + + const int x = 160 - (strlen(helpString) * _plettre->getCharWidth()) / 2; + const int y = i * 10 + 5; + + _plettre->drawString(helpString, x, y, 8, 0, true, *_vm->_draw->_backSurface); + } + + // White rectangle with black border + _vm->_draw->_backSurface->fillRect( 93, 43, 226, 134, 15); + _vm->_draw->_backSurface->drawRect( 92, 42, 227, 135, 0); + + // Draw the animal in the animal color + _vm->_draw->_backSurface->fillRect(120, 63, 199, 112, colors[animalColor]); + _vm->_draw->_backSurface->blit(sprites[sprite], animalLeft, animalTop, animalRight, animalBottom, 120, 63, 0); + + // Draw the shapes + for (uint i = 0; i < kCopyProtectionShapeCount; i++) { + const int16 * const coords = kCopyProtectionShapeCoords[i]; + + _vm->_draw->_backSurface->blit(sprites[1], coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], 0); + } + + _vm->_draw->forceBlit(); + + return animalShape; +} + +int8 OnceUpon::cpFindShape(int16 x, int16 y) const { + // Look through all shapes and check if the coordinates are inside one of them + for (uint i = 0; i < kCopyProtectionShapeCount; i++) { + const int16 * const coords = kCopyProtectionShapeCoords[i]; + + const int16 left = coords[4]; + const int16 top = coords[5]; + const int16 right = coords[4] + (coords[2] - coords[0] + 1) - 1; + const int16 bottom = coords[5] + (coords[3] - coords[1] + 1) - 1; + + if ((x >= left) && (x <= right) && (y >= top) && (y <= bottom)) + return i; + } + + return -1; +} + +void OnceUpon::cpWrong() { + // Display the "You are wrong" string, centered + + const char * const wrongString = kCopyProtectionWrongStrings[_vm->_global->_language]; + const int wrongX = 160 - (strlen(wrongString) * _plettre->getCharWidth()) / 2; + + _vm->_draw->_backSurface->clear(); + _plettre->drawString(wrongString, wrongX, 100, 15, 0, true, *_vm->_draw->_backSurface); + + _vm->_draw->forceBlit(); + + fadeIn(); + + waitInput(); + + fadeOut(); + clearScreen(); +} + +void OnceUpon::showIntro() { + // Show all intro parts + + // "Loading" + showWait(10); + if (_vm->shouldQuit()) + return; + + // Quote about fairy tales + showQuote(); + if (_vm->shouldQuit()) + return; + + // Once Upon A Time title + showTitle(); + if (_vm->shouldQuit()) + return; + + // Game title screen + showChapter(0); + if (_vm->shouldQuit()) + return; + + // "Loading" + showWait(17); +} + +void OnceUpon::showWait(uint palette) { + // Show the loading floppy + + fadeOut(); + clearScreen(); + setGamePalette(palette); + + Surface wait(320, 43, 1); + + _vm->_video->drawPackedSprite("wait.cmp", wait); + _vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84); + + _vm->_draw->forceBlit(); + + fadeIn(); +} + +void OnceUpon::showQuote() { + // Show the quote about fairytales + + fadeOut(); + clearScreen(); + setGamePalette(11); + + static const Font *fonts[3] = { _plettre, _glettre, _plettre }; + + TXTFile *quote = loadTXT(getLocFile("gene.tx"), TXTFile::kFormatStringPositionColorFont); + quote->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts)); + delete quote; + + _vm->_draw->forceBlit(); + + fadeIn(); + + waitInput(); + + fadeOut(); +} + +const PreGob::AnimProperties OnceUpon::kTitleAnimation = { + 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0 +}; + +void OnceUpon::showTitle() { + fadeOut(); + setGamePalette(10); + + Title title(_vm); + title.play(); +} + +void OnceUpon::showChapter(int chapter) { + // Display the intro text to a chapter + + fadeOut(); + clearScreen(); + setGamePalette(11); + + // Parchment background + _vm->_video->drawPackedSprite("parch.cmp", *_vm->_draw->_backSurface); + + static const Font *fonts[3] = { _plettre, _glettre, _plettre }; + + const Common::String chapterFile = getLocFile(Common::String::format("gene%d.tx", chapter)); + + TXTFile *gameTitle = loadTXT(chapterFile, TXTFile::kFormatStringPositionColorFont); + gameTitle->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts)); + delete gameTitle; + + _vm->_draw->forceBlit(); + + fadeIn(); + + waitInput(); + + fadeOut(); +} + +void OnceUpon::showByeBye() { + fadeOut(); + hideCursor(); + clearScreen(); + setGamePalette(1); + + _plettre->drawString("Bye Bye....", 140, 80, 2, 0, true, *_vm->_draw->_backSurface); + _vm->_draw->forceBlit(); + + fadeIn(); + + _vm->_util->longDelay(1000); + + fadeOut(); +} + +void OnceUpon::doStartMenu(const MenuButton *animalsButton, uint animalCount, + const MenuButton *animalButtons, const char * const *animalNames) { + clearScreen(); + + // Wait until we clicked on of the difficulty buttons and are ready to start playing + while (!_vm->shouldQuit()) { + MenuAction action = handleStartMenu(animalsButton); + if (action == kMenuActionPlay) + break; + + // If we pressed the "listen to animal names" button, handle that screen + if (action == kMenuActionAnimals) + handleAnimalNames(animalCount, animalButtons, animalNames); + } +} + +OnceUpon::MenuAction OnceUpon::handleStartMenu(const MenuButton *animalsButton) { + ScreenBackup screenBackup; + backupScreen(screenBackup, true); + + fadeOut(); + setGamePalette(17); + drawStartMenu(animalsButton); + showCursor(); + fadeIn(); + + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (action == kMenuActionNone)) { + endFrame(true); + + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + if (key == kKeyEscape) + // ESC -> Quit + return kMenuActionQuit; + + if (mouseButtons != kMouseButtonsLeft) + continue; + + playSound(kSoundClick); + + // If we clicked on a difficulty button, show the selected difficulty and start the game + int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY); + if (diff >= 0) { + _difficulty = (Difficulty)diff; + action = kMenuActionPlay; + + drawStartMenu(animalsButton); + _vm->_util->longDelay(1000); + } + + if (animalsButton && (checkButton(animalsButton, 1, mouseX, mouseY) != -1)) + action = kMenuActionAnimals; + + } + + fadeOut(); + restoreScreen(screenBackup); + + return action; +} + +OnceUpon::MenuAction OnceUpon::handleMainMenu() { + ScreenBackup screenBackup; + backupScreen(screenBackup, true); + + fadeOut(); + setGamePalette(17); + drawMainMenu(); + showCursor(); + fadeIn(); + + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (action == kMenuActionNone)) { + endFrame(true); + + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + if (key == kKeyEscape) + // ESC -> Quit + return kMenuActionQuit; + + if (mouseButtons != kMouseButtonsLeft) + continue; + + playSound(kSoundClick); + + // If we clicked on a difficulty button, change the current difficulty level + int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY); + if ((diff >= 0) && (diff != (int)_difficulty)) { + _difficulty = (Difficulty)diff; + + drawMainMenu(); + } + + // If we clicked on a section button, restart the game from this section + int section = checkButton(kSectionButtons, ARRAYSIZE(kSectionButtons), mouseX, mouseY); + if ((section >= 0) && (section <= _section)) { + _section = section; + action = kMenuActionRestart; + } + + } + + fadeOut(); + restoreScreen(screenBackup); + + return action; +} + +OnceUpon::MenuAction OnceUpon::handleIngameMenu() { + ScreenBackup screenBackup; + backupScreen(screenBackup, true); + + drawIngameMenu(); + showCursor(); + + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (action == kMenuActionNone)) { + endFrame(true); + + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight)) + // ESC or right mouse button -> Dismiss the menu + action = kMenuActionPlay; + + if (mouseButtons != kMouseButtonsLeft) + continue; + + int button = checkButton(kIngameButtons, ARRAYSIZE(kIngameButtons), mouseX, mouseY); + if (button == 0) + action = kMenuActionQuit; + else if (button == 1) + action = kMenuActionMainMenu; + else if (button == 2) + action = kMenuActionPlay; + + } + + clearIngameMenu(*screenBackup.screen); + restoreScreen(screenBackup); + + return action; +} + +void OnceUpon::drawStartMenu(const MenuButton *animalsButton) { + // Draw the background + _vm->_video->drawPackedSprite("menu2.cmp", *_vm->_draw->_backSurface); + + // Draw the "Listen to animal names" button + if (animalsButton) { + Surface elements(320, 38, 1); + _vm->_video->drawPackedSprite("elemenu.cmp", elements); + _vm->_draw->_backSurface->fillRect(animalsButton->left , animalsButton->top, + animalsButton->right, animalsButton->bottom, 0); + drawButton(*_vm->_draw->_backSurface, elements, *animalsButton); + } + + // Highlight the current difficulty + drawMenuDifficulty(); + + _vm->_draw->forceBlit(); +} + +void OnceUpon::drawMainMenu() { + // Draw the background + _vm->_video->drawPackedSprite("menu.cmp", *_vm->_draw->_backSurface); + + // Highlight the current difficulty + drawMenuDifficulty(); + + // Draw the section buttons + Surface elements(320, 200, 1); + _vm->_video->drawPackedSprite("elemenu.cmp", elements); + + for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) { + const MenuButton &button = kSectionButtons[i]; + + if (!button.needDraw) + continue; + + if (_section >= (int)button.id) + drawButton(*_vm->_draw->_backSurface, elements, button); + } + + _vm->_draw->forceBlit(); +} + +void OnceUpon::drawIngameMenu() { + Surface menu(320, 34, 1); + _vm->_video->drawPackedSprite("icon.cmp", menu); + + // Draw the menu in a special way, button by button + for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) { + const MenuButton &button = kIngameButtons[i]; + + drawLineByLine(menu, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, + button.dstX, button.dstY); + } + + _vm->_draw->forceBlit(); + _vm->_video->retrace(); +} + +void OnceUpon::drawMenuDifficulty() { + if (_difficulty == kDifficultyCount) + return; + + TXTFile *difficulties = loadTXT(getLocFile("diffic.tx"), TXTFile::kFormatStringPositionColor); + + // Draw the difficulty name + difficulties->draw((uint) _difficulty, *_vm->_draw->_backSurface, &_plettre, 1); + + // Draw a border around the current difficulty + drawButtonBorder(kMainMenuDifficultyButton[_difficulty], difficulties->getLines()[_difficulty].color); + + delete difficulties; +} + +void OnceUpon::clearIngameMenu(const Surface &background) { + if (_vm->shouldQuit()) + return; + + // Find the area encompassing the whole ingame menu + + int16 left = 0x7FFF; + int16 top = 0x7FFF; + int16 right = 0x0000; + int16 bottom = 0x0000; + + for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) { + const MenuButton &button = kIngameButtons[i]; + + if (!button.needDraw) + continue; + + left = MIN<int16>(left , button.dstX); + top = MIN<int16>(top , button.dstY); + right = MAX<int16>(right , button.dstX + (button.srcRight - button.srcLeft + 1) - 1); + bottom = MAX<int16>(bottom, button.dstY + (button.srcBottom - button.srcTop + 1) - 1); + } + + if ((left > right) || (top > bottom)) + return; + + // Clear it line by line + drawLineByLine(background, left, top, right, bottom, left, top); +} + +OnceUpon::MenuAction OnceUpon::doIngameMenu() { + // Show the ingame menu + MenuAction action = handleIngameMenu(); + + if ((action == kMenuActionQuit) || _vm->shouldQuit()) { + + // User pressed the quit button, or quit ScummVM + _quit = true; + action = kMenuActionQuit; + + } else if (action == kMenuActionPlay) { + + // User pressed the return to game button + action = kMenuActionPlay; + + } else if (kMenuActionMainMenu) { + + // User pressed the return to main menu button + action = handleMainMenu(); + } + + return action; +} + +OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 &key, MouseButtons &mouseButtons) { + if ((key != kKeyEscape) && (mouseButtons != kMouseButtonsRight)) + return kMenuActionNone; + + key = 0; + mouseButtons = kMouseButtonsNone; + + MenuAction action = doIngameMenu(); + if (action == kMenuActionPlay) + action = kMenuActionNone; + + return action; +} + +int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const { + // Look through all buttons, and return the ID of the button we're in + + for (uint i = 0; i < count; i++) { + const MenuButton &button = buttons[i]; + + if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom)) + return (int)button.id; + } + + // We're in none of these buttons, return the fail value + return failValue; +} + +void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button, int transp) const { + dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY, transp); +} + +void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp) const { + for (uint i = 0; i < count; i++) { + const MenuButton &button = buttons[i]; + + if (!button.needDraw) + continue; + + drawButton(dest, src, button, transp); + } +} + +void OnceUpon::drawButtonBorder(const MenuButton &button, uint8 color) { + _vm->_draw->_backSurface->drawRect(button.left, button.top, button.right, button.bottom, color); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, button.left, button.top, button.right, button.bottom); +} + +enum AnimalNamesState { + kANStateChoose, // We're in the animal chooser + kANStateNames, // We're in the language chooser + kANStateFinish // We're finished +}; + +void OnceUpon::handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names) { + fadeOut(); + clearScreen(); + setGamePalette(19); + + bool cursorVisible = isCursorVisible(); + + // Set the cursor + addCursor(); + setGameCursor(); + + anSetupChooser(); + + int8 _animal = -1; + + AnimalNamesState state = kANStateChoose; + while (!_vm->shouldQuit() && (state != kANStateFinish)) { + showCursor(); + fadeIn(); + + endFrame(true); + + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + checkInput(mouseX, mouseY, mouseButtons); + + // If we moused over an animal button, draw a border around it + int animal = checkButton(buttons, count, mouseX, mouseY); + if ((state == kANStateChoose) && (animal != _animal)) { + // Erase the old border + if (_animal >= 0) + drawButtonBorder(buttons[_animal], 15); + + _animal = animal; + + // Draw the new border + if (_animal >= 0) + drawButtonBorder(buttons[_animal], 10); + } + + if (mouseButtons != kMouseButtonsLeft) + continue; + + playSound(kSoundClick); + + // We clicked on a language button, play the animal name + int language = checkButton(kLanguageButtons, ARRAYSIZE(kLanguageButtons), mouseX, mouseY); + if ((state == kANStateNames) && (language >= 0)) + anPlayAnimalName(names[_animal], language); + + // We clicked on an animal + if ((state == kANStateChoose) && (_animal >= 0)) { + anSetupNames(buttons[_animal]); + + state = kANStateNames; + } + + // If we clicked on the back button, go back + if (checkButton(&kAnimalNamesBack, 1, mouseX, mouseY) != -1) { + if (state == kANStateNames) { + anSetupChooser(); + + state = kANStateChoose; + } else if (state == kANStateChoose) + state = kANStateFinish; + } + } + + fadeOut(); + + // Restore the cursor + if (!cursorVisible) + hideCursor(); + removeCursor(); +} + +void OnceUpon::anSetupChooser() { + fadeOut(); + + _vm->_video->drawPackedSprite("dico.cmp", *_vm->_draw->_backSurface); + + // Draw the back button + Surface menu(320, 34, 1); + _vm->_video->drawPackedSprite("icon.cmp", menu); + drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack); + + // "Choose an animal" + TXTFile *choose = loadTXT(getLocFile("choisi.tx"), TXTFile::kFormatStringPosition); + choose->draw(*_vm->_draw->_backSurface, &_plettre, 1, 14); + delete choose; + + _vm->_draw->forceBlit(); +} + +void OnceUpon::anSetupNames(const MenuButton &animal) { + fadeOut(); + + Surface background(320, 200, 1); + + _vm->_video->drawPackedSprite("dico.cmp", background); + + // Draw the background and clear what we don't need + _vm->_draw->_backSurface->blit(background); + _vm->_draw->_backSurface->fillRect(19, 19, 302, 186, 15); + + // Draw the back button + Surface menu(320, 34, 1); + _vm->_video->drawPackedSprite("icon.cmp", menu); + drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack); + + // Draw the animal + drawButton(*_vm->_draw->_backSurface, background, animal); + + // Draw the language buttons + Surface elements(320, 200, 1); + _vm->_video->drawPackedSprite("elemenu.cmp", elements); + drawButtons(*_vm->_draw->_backSurface, elements, kLanguageButtons, ARRAYSIZE(kLanguageButtons)); + + // Draw the language names + _plettre->drawString("Fran\207ais", 43, 70, 10, 15, true, *_vm->_draw->_backSurface); + _plettre->drawString("Deutsch" , 136, 70, 10, 15, true, *_vm->_draw->_backSurface); + _plettre->drawString("English" , 238, 70, 10, 15, true, *_vm->_draw->_backSurface); + _plettre->drawString("Italiano" , 43, 128, 10, 15, true, *_vm->_draw->_backSurface); + _plettre->drawString("Espa\244ol" , 136, 128, 10, 15, true, *_vm->_draw->_backSurface); + _plettre->drawString("English" , 238, 128, 10, 15, true, *_vm->_draw->_backSurface); + + _vm->_draw->forceBlit(); +} + +void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) { + // Sound file to play + Common::String soundFile = animal + "_" + kLanguageSuffixLong[language] + ".snd"; + + // Get the name of the animal + TXTFile *names = loadTXT(animal + ".anm", TXTFile::kFormatString); + Common::String name = names->getLines()[language].text; + delete names; + + // It should be centered on the screen + const int nameX = 160 - (name.size() * _plettre->getCharWidth()) / 2; + + // Backup the screen surface + Surface backup(162, 23, 1); + backup.blit(*_vm->_draw->_backSurface, 78, 123, 239, 145, 0, 0); + + // Draw the name border + Surface nameBorder(162, 23, 1); + _vm->_video->drawPackedSprite("mot.cmp", nameBorder); + _vm->_draw->_backSurface->blit(nameBorder, 0, 0, 161, 22, 78, 123); + + // Print the animal name + _plettre->drawString(name, nameX, 129, 10, 0, true, *_vm->_draw->_backSurface); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145); + + playSoundFile(soundFile); + + // Restore the screen + _vm->_draw->_backSurface->blit(backup, 0, 0, 161, 22, 78, 123); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145); +} + +void OnceUpon::playGame() { + while (!_vm->shouldQuit() && !_quit) { + // Play a section and advance to the next section if we finished it + if (playSection()) + _section = MIN(_section + 1, kSectionCount - 1); + } + + // If we quit through the game and not through ScummVM, show the "Bye Bye" screen + if (!_vm->shouldQuit()) + showByeBye(); +} + +bool OnceUpon::playSection() { + if ((_section < 0) || (_section >= ARRAYSIZE(kSectionFuncs))) { + _quit = true; + return false; + } + + return (this->*kSectionFuncs[_section])(); +} + +const PreGob::AnimProperties OnceUpon::kSectionStorkAnimations[] = { + { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 2, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 3, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 4, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 5, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 7, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + {17, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + {16, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + {15, 0, ANIObject::kModeContinuous, true, false, false, 0, 0} +}; + +enum StorkState { + kStorkStateWaitUser, + kStorkStateWaitBundle, + kStorkStateFinish +}; + +bool OnceUpon::sectionStork() { + fadeOut(); + hideCursor(); + setGamePalette(0); + setGameCursor(); + + const StorkParam ¶m = getStorkParameters(); + + Surface backdrop(320, 200, 1); + + // Draw the frame + _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface); + + // Draw the backdrop + _vm->_video->drawPackedSprite(param.backdrop, backdrop); + _vm->_draw->_backSurface->blit(backdrop, 0, 0, 288, 175, 16, 12); + + // "Where does the stork go?" + TXTFile *whereStork = loadTXT(getLocFile("ouva.tx"), TXTFile::kFormatStringPositionColor); + whereStork->draw(*_vm->_draw->_backSurface, &_plettre, 1); + + // Where the stork actually goes + GCTFile *thereStork = loadGCT(getLocFile("choix.gc")); + thereStork->setArea(17, 18, 303, 41); + + ANIFile ani(_vm, "present.ani", 320); + ANIList anims; + + Stork *stork = new Stork(_vm, ani); + + loadAnims(anims, ani, ARRAYSIZE(kSectionStorkAnimations), kSectionStorkAnimations); + anims.push_back(stork); + + drawAnim(anims); + + _vm->_draw->forceBlit(); + + int8 storkSoundWait = 0; + + StorkState state = kStorkStateWaitUser; + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (state != kStorkStateFinish)) { + // Play the stork sound + if (--storkSoundWait == 0) + playSound(kSoundStork); + if (storkSoundWait <= 0) + storkSoundWait = 50 - _vm->_util->getRandom(30); + + // Check if the bundle landed + if ((state == kStorkStateWaitBundle) && stork->hasBundleLanded()) + state = kStorkStateFinish; + + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + + action = doIngameMenu(key, mouseButtons); + if (action != kMenuActionNone) { + state = kStorkStateFinish; + break; + } + + clearAnim(anims); + + if (mouseButtons == kMouseButtonsLeft) { + stopSound(); + playSound(kSoundClick); + + int house = checkButton(param.houses, param.houseCount, mouseX, mouseY); + if ((state == kStorkStateWaitUser) && (house >= 0)) { + + _house = house; + + stork->dropBundle(param.drops[house]); + state = kStorkStateWaitBundle; + + // Remove the "Where does the stork go?" text + int16 left, top, right, bottom; + if (whereStork->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + // Print the text where the stork actually goes + thereStork->selectLine(3, house); // The house + thereStork->selectLine(4, house); // The house's inhabitants + if (thereStork->draw(*_vm->_draw->_backSurface, 2, *_plettre, 10, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + } + } + + drawAnim(anims); + showCursor(); + fadeIn(); + + endFrame(true); + } + + freeAnims(anims); + delete thereStork; + delete whereStork; + + fadeOut(); + hideCursor(); + + // Didn't complete the section + if (action != kMenuActionNone) + return false; + + // Move on to the character generator + + CharGenAction charGenAction = kCharGenRestart; + while (charGenAction == kCharGenRestart) + charGenAction = characterGenerator(); + + // Did we successfully create a character? + return charGenAction == kCharGenDone; +} + +const OnceUpon::MenuButton OnceUpon::kCharGenHeadButtons[] = { + {true, 106, 146, 152, 180, 0, 0, 47, 34, 106, 146, 0}, + {true, 155, 146, 201, 180, 49, 0, 96, 34, 155, 146, 1}, + {true, 204, 146, 250, 180, 98, 0, 145, 34, 204, 146, 2}, + {true, 253, 146, 299, 180, 147, 0, 194, 34, 253, 146, 3} +}; + +const OnceUpon::MenuButton OnceUpon::kCharGenHeads[] = { + {true, 0, 0, 0, 0, 29, 4, 68, 31, 40, 51, 0}, + {true, 0, 0, 0, 0, 83, 4, 113, 31, 45, 51, 1}, + {true, 0, 0, 0, 0, 132, 4, 162, 31, 45, 51, 2}, + {true, 0, 0, 0, 0, 182, 4, 211, 31, 45, 51, 3} +}; + +const OnceUpon::MenuButton OnceUpon::kCharGenHairButtons[] = { + {true, 105, 55, 124, 70, 271, 1, 289, 15, 105, 55, 0x04}, + {true, 105, 74, 124, 89, 271, 20, 289, 34, 105, 74, 0x07} +}; + +const OnceUpon::MenuButton OnceUpon::kCharGenJacketButtons[] = { + {true, 105, 90, 124, 105, 271, 39, 289, 53, 105, 90, 0x06}, + {true, 105, 109, 124, 124, 271, 58, 289, 72, 105, 109, 0x02} +}; + +const OnceUpon::MenuButton OnceUpon::kCharGenTrousersButtons[] = { + {true, 105, 140, 124, 155, 271, 77, 289, 91, 105, 140, 0x01}, + {true, 105, 159, 124, 174, 271, 96, 289, 110, 105, 159, 0x03} +}; + +const OnceUpon::MenuButton OnceUpon::kCharGenNameEntry[] = { + {true, 0, 0, 0, 0, 0, 38, 54, 48, 140, 145, 0}, + {true, 0, 0, 0, 0, 106, 38, 159, 48, 195, 145, 0}, + {true, 0, 0, 0, 0, 0, 105, 54, 121, 140, 156, 0}, + {true, 0, 0, 0, 0, 106, 105, 159, 121, 195, 156, 0} +}; + +enum CharGenState { + kCharGenStateHead = 0, // Choose a head + kCharGenStateHair , // Choose hair color + kCharGenStateJacket , // Choose jacket color + kCharGenStateTrousers , // Choose trousers color + kCharGenStateName , // Choose name + kCharGenStateSure , // "Are you sure?" + kCharGenStateStoryName , // "We're going to tell the story of $NAME" + kCharGenStateFinish // Finished +}; + +void OnceUpon::charGenSetup(uint stage) { + Surface choix(320, 200, 1), elchoix(320, 200, 1), paperDoll(65, 137, 1); + + _vm->_video->drawPackedSprite("choix.cmp" , choix); + _vm->_video->drawPackedSprite("elchoix.cmp", elchoix); + + paperDoll.blit(choix, 200, 0, 264, 136, 0, 0); + + GCTFile *text = loadGCT(getLocFile("choix.gc")); + text->setArea(17, 18, 303, 41); + text->setText(9, _name); + + // Background + _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface); + _vm->_draw->_backSurface->fillRect(16, 50, 303, 187, 5); + + // Character sprite frame + _vm->_draw->_backSurface->blit(choix, 0, 38, 159, 121, 140, 54); + + // Recolor the paper doll parts + if (_colorHair != 0xFF) + elchoix.recolor(0x0C, _colorHair); + + if (_colorJacket != 0xFF) + paperDoll.recolor(0x0A, _colorJacket); + + if (_colorTrousers != 0xFF) + paperDoll.recolor(0x09, _colorTrousers); + + _vm->_draw->_backSurface->blit(paperDoll, 32, 51); + + // Paper doll head + if (_head != 0xFF) + drawButton(*_vm->_draw->_backSurface, elchoix, kCharGenHeads[_head], 0); + + if (stage == kCharGenStateHead) { + // Head buttons + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons)); + + // "Choose a head" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 5, *_plettre, 10, left, top, right, bottom); + + } else if (stage == kCharGenStateHair) { + // Hair color buttons + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons)); + + // "What color is the hair?" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 6, *_plettre, 10, left, top, right, bottom); + + } else if (stage == kCharGenStateJacket) { + // Jacket color buttons + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons)); + + // "What color is the jacket?" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 7, *_plettre, 10, left, top, right, bottom); + + } else if (stage == kCharGenStateTrousers) { + // Trousers color buttons + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons)); + + // "What color are the trousers?" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 8, *_plettre, 10, left, top, right, bottom); + + } else if (stage == kCharGenStateName) { + // Name entry field + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry)); + + // "Enter name" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 10, *_plettre, 10, left, top, right, bottom); + + charGenDrawName(); + } else if (stage == kCharGenStateSure) { + // Name entry field + drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry)); + + // "Are you sure?" + TXTFile *sure = loadTXT(getLocFile("estu.tx"), TXTFile::kFormatStringPositionColor); + sure->draw(*_vm->_draw->_backSurface, &_plettre, 1); + delete sure; + + charGenDrawName(); + } else if (stage == kCharGenStateStoryName) { + + // "We're going to tell the story of $NAME" + int16 left, top, right, bottom; + text->draw(*_vm->_draw->_backSurface, 11, *_plettre, 10, left, top, right, bottom); + } + + delete text; +} + +bool OnceUpon::enterString(Common::String &name, int16 key, uint maxLength, const Font &font) { + if (key == 0) + return true; + + if (key == kKeyBackspace) { + name.deleteLastChar(); + return true; + } + + if (key == kKeySpace) + key = ' '; + + if ((key >= ' ') && (key <= 0xFF)) { + if (name.size() >= maxLength) + return false; + + if (!font.hasChar(key)) + return false; + + name += (char) key; + return true; + } + + return false; +} + +void OnceUpon::charGenDrawName() { + _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1); + + const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2); + const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2); + + _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface); + + const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth(); + const int16 cursorTop = nameY; + const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1; + const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1; + + _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166); +} + +OnceUpon::CharGenAction OnceUpon::characterGenerator() { + fadeOut(); + hideCursor(); + setGameCursor(); + + showWait(1); + + _name.clear(); + + _head = 0xFF; + _colorHair = 0xFF; + _colorJacket = 0xFF; + _colorTrousers = 0xFF; + + CharGenState state = kCharGenStateHead; + charGenSetup(state); + + ANIFile ani(_vm, "ba.ani", 320); + + ani.recolor(0x0F, 0x0C); + ani.recolor(0x0E, 0x0A); + ani.recolor(0x08, 0x09); + + CharGenChild *child = new CharGenChild(ani); + + ANIList anims; + anims.push_back(child); + + fadeOut(); + _vm->_draw->forceBlit(); + + CharGenAction action = kCharGenRestart; + while (!_vm->shouldQuit() && (state != kCharGenStateFinish)) { + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + + MenuAction menuAction = doIngameMenu(key, mouseButtons); + if (menuAction != kMenuActionNone) { + state = kCharGenStateFinish; + action = kCharGenAbort; + break; + } + + clearAnim(anims); + + if (state == kCharGenStateStoryName) { + if ((mouseButtons != kMouseButtonsNone) || (key != 0)) { + state = kCharGenStateFinish; + action = kCharGenDone; + break; + } + } + + if (state == kCharGenStateSure) { + // Not sure => restart + if ((key == 'N') || (key == 'n')) { // No / Nein / Non + state = kCharGenStateFinish; + action = kCharGenRestart; + break; + } + + if ((key == 'Y') || (key == 'y') || // Yes + (key == 'J') || (key == 'j') || // Ja + (key == 'S') || (key == 's') || // Si + (key == 'O') || (key == 'o')) { // Oui + + state = kCharGenStateStoryName; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + } + + if (state == kCharGenStateName) { + if (enterString(_name, key, 14, *_plettre)) { + _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1); + + const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2); + const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2); + + _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface); + + const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth(); + const int16 cursorTop = nameY; + const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1; + const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1; + + _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166); + } + + if ((key == kKeyReturn) && !_name.empty()) { + _name.trim(); + _name.setChar(Util::toCP850Upper(_name[0]), 0); + + state = kCharGenStateSure; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + } + + if (mouseButtons == kMouseButtonsLeft) { + stopSound(); + playSound(kSoundClick); + + int trousers = checkButton(kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons), mouseX, mouseY); + if ((state == kCharGenStateTrousers) && (trousers >= 0)) { + _colorTrousers = trousers; + + ani.recolor(0x09, _colorTrousers); + + state = kCharGenStateName; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + + int jacket = checkButton(kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons), mouseX, mouseY); + if ((state == kCharGenStateJacket) && (jacket >= 0)) { + _colorJacket = jacket; + + ani.recolor(0x0A, _colorJacket); + + state = kCharGenStateTrousers; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + + int hair = checkButton(kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons), mouseX, mouseY); + if ((state == kCharGenStateHair) && (hair >= 0)) { + _colorHair = hair; + + ani.recolor(0x0C, _colorHair); + + state = kCharGenStateJacket; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + + int head = checkButton(kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons), mouseX, mouseY); + if ((state == kCharGenStateHead) && (head >= 0)) { + _head = head; + + state = kCharGenStateHair; + charGenSetup(state); + _vm->_draw->forceBlit(); + } + } + + drawAnim(anims); + + // Play the child sounds + CharGenChild::Sound childSound = child->shouldPlaySound(); + if (childSound == CharGenChild::kSoundWalk) { + beep(50, 10); + } else if (childSound == CharGenChild::kSoundJump) { + stopSound(); + playSound(kSoundJump); + } + + showCursor(); + fadeIn(); + + endFrame(true); + } + + fadeOut(); + hideCursor(); + + freeAnims(anims); + + if (_vm->shouldQuit()) + return kCharGenAbort; + + return action; +} + +bool OnceUpon::sectionChapter1() { + showChapter(1); + return true; +} + +bool OnceUpon::sectionParents() { + fadeOut(); + setGamePalette(14); + clearScreen(); + + const Common::String seq = ((_house == 1) || (_house == 2)) ? "parents.seq" : "parents2.seq"; + const Common::String gct = getLocFile("mefait.gc"); + + Parents parents(_vm, seq, gct, _name, _house, *_plettre, kGamePalettes[14], kGamePalettes[13], kPaletteSize); + parents.play(); + + warning("OnceUpon::sectionParents(): TODO: Item search"); + return true; +} + +bool OnceUpon::sectionChapter2() { + showChapter(2); + return true; +} + +bool OnceUpon::sectionForest0() { + warning("OnceUpon::sectionForest0(): TODO"); + return true; +} + +bool OnceUpon::sectionChapter3() { + showChapter(3); + return true; +} + +bool OnceUpon::sectionEvilCastle() { + warning("OnceUpon::sectionEvilCastle(): TODO"); + return true; +} + +bool OnceUpon::sectionChapter4() { + showChapter(4); + return true; +} + +bool OnceUpon::sectionForest1() { + warning("OnceUpon::sectionForest1(): TODO"); + return true; +} + +bool OnceUpon::sectionChapter5() { + showChapter(5); + return true; +} + +bool OnceUpon::sectionBossFight() { + warning("OnceUpon::sectionBossFight(): TODO"); + return true; +} + +bool OnceUpon::sectionChapter6() { + showChapter(6); + return true; +} + +bool OnceUpon::sectionForest2() { + warning("OnceUpon::sectionForest2(): TODO"); + return true; +} + +bool OnceUpon::sectionChapter7() { + showChapter(7); + return true; +} + +const PreGob::AnimProperties OnceUpon::kSectionEndAnimations[] = { + { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 9, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + {11, 0, ANIObject::kModeContinuous, true, false, false, 0, 0} +}; + +bool OnceUpon::sectionEnd() { + fadeOut(); + setGamePalette(9); + + _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface); + + Surface endBackground(320, 200, 1); + _vm->_video->drawPackedSprite("fin.cmp", endBackground); + + _vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50); + + GCTFile *endText = loadGCT(getLocFile("final.gc")); + endText->setArea(17, 18, 303, 41); + endText->setText(1, _name); + + ANIFile ani(_vm, "fin.ani", 320); + ANIList anims; + + loadAnims(anims, ani, ARRAYSIZE(kSectionEndAnimations), kSectionEndAnimations); + drawAnim(anims); + + _vm->_draw->forceBlit(); + + uint32 textStartTime = 0; + + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (action == kMenuActionNone)) { + // Check user input + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + + action = doIngameMenu(key, mouseButtons); + if (action != kMenuActionNone) + break; + + clearAnim(anims); + + // Pressed a key or mouse button => Skip to next area-full of text + if ((mouseButtons == kMouseButtonsLeft) || (key != 0)) + textStartTime = 0; + + // Draw the next area-full of text + uint32 now = _vm->_util->getTimeKey(); + if (!endText->finished() && ((textStartTime == 0) || (now >= (textStartTime + kGCTDelay)))) { + textStartTime = now; + + int16 left, top, right, bottom; + if (endText->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + if (endText->draw(*_vm->_draw->_backSurface, 0, *_plettre, 10, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + } + + drawAnim(anims); + fadeIn(); + + endFrame(true); + } + + freeAnims(anims); + delete endText; + + // Restart requested + if (action == kMenuActionRestart) + return false; + + // Last scene. Even if we didn't explicitly request a quit, the game ends here + _quit = true; + return false; +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h new file mode 100644 index 0000000000..66ef877618 --- /dev/null +++ b/engines/gob/pregob/onceupon/onceupon.h @@ -0,0 +1,344 @@ +/* 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 GOB_PREGOB_ONCEUPON_ONCEUPON_H +#define GOB_PREGOB_ONCEUPON_ONCEUPON_H + +#include "common/system.h" +#include "common/str.h" + +#include "gob/pregob/pregob.h" + +#include "gob/pregob/onceupon/stork.h" + +namespace Gob { + +class Surface; +class Font; + +class ANIObject; + +namespace OnceUpon { + +class OnceUpon : public PreGob { +public: + /** Number of languages we support. */ + static const uint kLanguageCount = 5; + + + OnceUpon(GobEngine *vm); + ~OnceUpon(); + + +protected: + /** A description of a menu button. */ + struct MenuButton { + bool needDraw; ///< Does the button need drawing? + + int16 left; ///< Left coordinate of the button. + int16 top; ///< Top coordinate of the button. + int16 right; ///< Right coordinate of the button. + int16 bottom; ///< Bottom coordinate of the button. + + int16 srcLeft; ///< Left coordinate of the button's sprite. + int16 srcTop; ///< Top coordinate of the button's sprite. + int16 srcRight; ///< Right coordinate of the button's sprite. + int16 srcBottom; ///< Right coordinate of the button's sprite. + + int16 dstX; ///< Destination X coordinate of the button's sprite. + int16 dstY; ///< Destination Y coordinate of the button's sprite. + + uint id; ///< The button's ID. + }; + + /** Parameters for the stork section. */ + struct StorkParam { + const char *backdrop; ///< Backdrop image file. + + uint houseCount; ///< Number of houses. + const MenuButton *houses; ///< House button definitions. + + const Stork::BundleDrop *drops; ///< The bundle drop parameters. + }; + + void init(); + void deinit(); + + /** Handle the copy protection. + * + * @param colors Colors the copy protection animals can be. + * @param shapes The shape that's the correct answer for each animal in each color. + * @param obfuscate Extra obfuscate table. correctShape = shapes[colors][obfuscate[animal]]. + * @return true if the user guessed the correct shape, false otherwise. + */ + bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]); + + /** Show the intro. */ + void showIntro(); + + /** Handle the start menu. + * + * @param animalsButton Definition of the menu button that leads to the animal names screen. Can be 0. + * @param animalCount Number of animals in the animal names screen. + * @param animalButtons Definition of the buttons that make up the animals in the animal names screen. + * @param animalNames File prefixes for the name of each animal. + */ + void doStartMenu(const MenuButton *animalsButton, uint animalCount, + const MenuButton *animalButtons, const char * const *animalNames); + + /** Play the game proper. */ + void playGame(); + + + /** Return the parameters for the stork section. */ + virtual const StorkParam &getStorkParameters() const = 0; + + +private: + /** All actions a user can request in a menu. */ + enum MenuAction { + kMenuActionNone = 0, ///< No action. + kMenuActionAnimals , ///< Do the animal names. + kMenuActionPlay , ///< Play the game. + kMenuActionRestart , ///< Restart the section. + kMenuActionMainMenu, ///< Go to the main menu. + kMenuActionQuit ///< Quit the game. + }; + + /** Difficulty levels. */ + enum Difficulty { + kDifficultyBeginner = 0, + kDifficultyIntermediate = 1, + kDifficultyAdvanced = 2, + kDifficultyCount + }; + + /** The different sounds common in the game. */ + enum Sound { + kSoundClick = 0, + kSoundStork , + kSoundJump , + kSoundCount + }; + + /** Action the character generation wants us to take. */ + enum CharGenAction { + kCharGenDone = 0, ///< Created a character, move on. + kCharGenAbort , ///< Aborted the character generation. + kCharGenRestart ///< Restart the character generation. + }; + + /** A complete screen backup. */ + struct ScreenBackup { + Surface *screen; ///< Screen contents. + int palette; ///< Screen palette. + + bool changedCursor; ///< Did we change the cursor? + bool cursorVisible; ///< Was the cursor visible? + + ScreenBackup(); + ~ScreenBackup(); + }; + + + /** The number of game sections. */ + static const int kSectionCount = 15; + + static const MenuButton kMainMenuDifficultyButton[]; ///< Difficulty buttons. + static const MenuButton kSectionButtons[]; ///< Section buttons. + + static const MenuButton kIngameButtons[]; ///< Ingame menu buttons. + + static const MenuButton kAnimalNamesBack; ///< "Back" button in the animal names screens. + static const MenuButton kLanguageButtons[]; ///< Language buttons in the animal names screen. + + static const MenuButton kSectionStorkHouses[]; + + static const MenuButton kCharGenHeadButtons[]; + static const MenuButton kCharGenHeads[]; + static const MenuButton kCharGenHairButtons[]; + static const MenuButton kCharGenJacketButtons[]; + static const MenuButton kCharGenTrousersButtons[]; + static const MenuButton kCharGenNameEntry[]; + + /** All general game sounds we know about. */ + static const char *kSound[kSoundCount]; + + + static const AnimProperties kClownAnimations[]; + static const AnimProperties kTitleAnimation; + static const AnimProperties kSectionStorkAnimations[]; + static const AnimProperties kSectionEndAnimations[]; + + + /** Function pointer type for a section handler. */ + typedef bool (OnceUpon::*SectionFunc)(); + /** Section handler function. */ + static const SectionFunc kSectionFuncs[kSectionCount]; + + + /** Did we open the game archives? */ + bool _openedArchives; + + // Fonts + Font *_jeudak; + Font *_lettre; + Font *_plettre; + Font *_glettre; + + /** The current palette. */ + int _palette; + + bool _quit; ///< Did the user request a normal game quit? + + Difficulty _difficulty; ///< The current difficulty. + int _section; ///< The current game section. + + Common::String _name; ///< The name of the child. + + uint8 _house; + + uint8 _head; + uint8 _colorHair; + uint8 _colorJacket; + uint8 _colorTrousers; + + + // -- General helpers -- + + void setGamePalette(uint palette); ///< Set a game palette. + void setGameCursor(); ///< Set the default game cursor. + + /** Draw this sprite in a fancy, animated line-by-line way. */ + void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom, + int16 x, int16 y) const; + + /** Backup the screen contents. */ + void backupScreen(ScreenBackup &backup, bool setDefaultCursor = false); + /** Restore the screen contents with a previously made backup. */ + void restoreScreen(ScreenBackup &backup); + + Common::String fixString(const Common::String &str) const; ///< Fix a string if necessary. + void fixTXTStrings(TXTFile &txt) const; ///< Fix all strings in a TXT. + + + // -- Copy protection helpers -- + + /** Set up the copy protection. */ + int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], + const uint8 obfuscate[4], const Surface sprites[2]); + /** Find the shape under these coordinates. */ + int8 cpFindShape(int16 x, int16 y) const; + /** Display the "You are wrong" screen. */ + void cpWrong(); + + + // -- Show different game screens -- + + void showWait(uint palette = 0xFFFF); ///< Show the wait / loading screen. + void showQuote(); ///< Show the quote about fairytales. + void showTitle(); ///< Show the Once Upon A Time title. + void showChapter(int chapter); ///< Show a chapter intro text. + void showByeBye(); ///< Show the "bye bye" screen. + + /** Handle the "listen to animal names" part. */ + void handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names); + + + // -- Menu helpers -- + + MenuAction handleStartMenu(const MenuButton *animalsButton); ///< Handle the start menu. + MenuAction handleMainMenu(); ///< Handle the main menu. + MenuAction handleIngameMenu(); ///< Handle the ingame menu. + + void drawStartMenu(const MenuButton *animalsButton); ///< Draw the start menu. + void drawMainMenu(); ///< Draw the main menu. + void drawIngameMenu(); ///< Draw the ingame menu. + + /** Draw the difficulty label. */ + void drawMenuDifficulty(); + + /** Clear the ingame menu in an animated way. */ + void clearIngameMenu(const Surface &background); + + /** Handle the whole ingame menu. */ + MenuAction doIngameMenu(); + /** Handle the whole ingame menu if ESC or right mouse button was pressed. */ + MenuAction doIngameMenu(int16 &key, MouseButtons &mouseButtons); + + + // -- Menu button helpers -- + + /** Find the button under these coordinates. */ + int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const; + + /** Draw a menu button. */ + void drawButton (Surface &dest, const Surface &src, const MenuButton &button, int transp = -1) const; + /** Draw multiple menu buttons. */ + void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp = -1) const; + + /** Draw a border around a button. */ + void drawButtonBorder(const MenuButton &button, uint8 color); + + + // -- Animal names helpers -- + + /** Set up the animal chooser. */ + void anSetupChooser(); + /** Set up the language chooser for one animal. */ + void anSetupNames(const MenuButton &animal); + /** Play / Display the name of an animal in one language. */ + void anPlayAnimalName(const Common::String &animal, uint language); + + + // -- Game sections -- + + bool playSection(); + + bool sectionStork(); + bool sectionChapter1(); + bool sectionParents(); + bool sectionChapter2(); + bool sectionForest0(); + bool sectionChapter3(); + bool sectionEvilCastle(); + bool sectionChapter4(); + bool sectionForest1(); + bool sectionChapter5(); + bool sectionBossFight(); + bool sectionChapter6(); + bool sectionForest2(); + bool sectionChapter7(); + bool sectionEnd(); + + CharGenAction characterGenerator(); + void charGenSetup(uint stage); + void charGenDrawName(); + + static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font); +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_ONCEUPON_H diff --git a/engines/gob/pregob/onceupon/palettes.h b/engines/gob/pregob/onceupon/palettes.h new file mode 100644 index 0000000000..952581041c --- /dev/null +++ b/engines/gob/pregob/onceupon/palettes.h @@ -0,0 +1,411 @@ +/* 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 GOB_PREGOB_ONCEUPON_PALETTES_H +#define GOB_PREGOB_ONCEUPON_PALETTES_H + +static const int kPaletteSize = 16; +static const uint kPaletteCount = 20; + +static const byte kCopyProtectionPalette[3 * kPaletteSize] = { + 0x00, 0x00, 0x00, + 0x19, 0x00, 0x19, + 0x00, 0x3F, 0x00, + 0x00, 0x2A, 0x2A, + 0x2A, 0x00, 0x00, + 0x2A, 0x00, 0x2A, + 0x2A, 0x15, 0x00, + 0x00, 0x19, 0x12, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x15, 0x3F, 0x15, + 0x00, 0x20, 0x3F, + 0x3F, 0x00, 0x00, + 0x3F, 0x00, 0x20, + 0x3F, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F +}; + +static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = { + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, + 0x00, 0x00, 0x18, + 0x00, 0x00, 0x3C, + 0x1C, 0x28, 0x00, + 0x10, 0x18, 0x00, + 0x1C, 0x1C, 0x20, + 0x14, 0x14, 0x14, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x14, 0x20, 0x04, + 0x3C, 0x2C, 0x00, + 0x02, 0x00, 0x18, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x38, 0x20, 0x3C, + 0x2C, 0x10, 0x30, + 0x20, 0x08, 0x28, + 0x14, 0x00, 0x1C, + 0x20, 0x20, 0x38, + 0x18, 0x18, 0x2C, + 0x10, 0x10, 0x24, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x3C, 0x20, 0x20, + 0x24, 0x14, 0x14, + 0x1C, 0x10, 0x10, + 0x14, 0x0C, 0x0C, + 0x1C, 0x1C, 0x1C, + 0x18, 0x18, 0x18, + 0x10, 0x10, 0x10, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x10, 0x28, 0x1C, + 0x10, 0x1C, 0x10, + 0x10, 0x14, 0x0C, + 0x1C, 0x1C, 0x3C, + 0x24, 0x24, 0x3C, + 0x18, 0x18, 0x24, + 0x10, 0x10, 0x18, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x3F, 0x26, 0x3F, + 0x36, 0x1C, 0x36, + 0x2C, 0x12, 0x2A, + 0x27, 0x0C, 0x24, + 0x22, 0x07, 0x1E, + 0x1D, 0x03, 0x18, + 0x16, 0x00, 0x10, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3A, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x3F, 0x39, 0x26, + 0x38, 0x34, 0x1C, + 0x30, 0x2F, 0x13, + 0x27, 0x29, 0x0C, + 0x1D, 0x22, 0x07, + 0x14, 0x1B, 0x03, + 0x0C, 0x14, 0x00, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3A, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x24, 0x3C, 0x3C, + 0x1C, 0x34, 0x38, + 0x14, 0x2C, 0x30, + 0x0C, 0x20, 0x2C, + 0x08, 0x18, 0x28, + 0x04, 0x10, 0x20, + 0x00, 0x08, 0x1C, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x38, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x24, + 0x38, 0x24, 0x1C, + 0x30, 0x1C, 0x14, + 0x28, 0x18, 0x0C, + 0x20, 0x10, 0x04, + 0x1C, 0x0C, 0x00, + 0x14, 0x08, 0x00, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x38, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x3C, 0x34, 0x24, + 0x38, 0x2C, 0x1C, + 0x30, 0x24, 0x14, + 0x2C, 0x1C, 0x10, + 0x30, 0x30, 0x3C, + 0x1C, 0x1C, 0x38, + 0x0C, 0x0C, 0x38, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0C, + 0x02, 0x03, 0x14, + 0x07, 0x07, 0x1D, + 0x0E, 0x0E, 0x25, + 0x17, 0x17, 0x2E, + 0x21, 0x22, 0x36, + 0x2F, 0x2F, 0x3F, + 0x3F, 0x3F, 0x3F, + 0x3F, 0x3B, 0x0D, + 0x3A, 0x31, 0x0A, + 0x35, 0x28, 0x07, + 0x30, 0x21, 0x04, + 0x2B, 0x19, 0x02, + 0x26, 0x12, 0x01, + 0x16, 0x0B, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x21, 0x01, 0x00, + 0x2A, 0x02, 0x00, + 0x33, 0x03, 0x00, + 0x3D, 0x06, 0x00, + 0x2A, 0x19, 0x05, + 0x15, 0x14, 0x14, + 0x22, 0x1F, 0x1E, + 0x2F, 0x2C, 0x28, + 0x3F, 0x3C, 0x29, + 0x3F, 0x38, 0x0B, + 0x3B, 0x30, 0x0A, + 0x37, 0x29, 0x08, + 0x33, 0x23, 0x07, + 0x2F, 0x1D, 0x06 + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x38, + 0x34, 0x30, 0x28, + 0x2C, 0x24, 0x1C, + 0x24, 0x18, 0x10, + 0x1C, 0x10, 0x08, + 0x14, 0x04, 0x04, + 0x10, 0x00, 0x00, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x38, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x38, + 0x34, 0x30, 0x28, + 0x2C, 0x24, 0x1C, + 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x38, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x1A, 0x30, 0x37, + 0x14, 0x28, 0x31, + 0x10, 0x20, 0x2C, + 0x0C, 0x19, 0x27, + 0x08, 0x12, 0x21, + 0x05, 0x0C, 0x1C, + 0x03, 0x07, 0x16, + 0x01, 0x03, 0x11, + 0x00, 0x00, 0x0C, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x34, 0x30, 0x34, + 0x30, 0x24, 0x30, + 0x28, 0x1C, 0x28, + 0x24, 0x14, 0x24, + 0x1C, 0x0C, 0x1C, + 0x18, 0x08, 0x18, + 0x14, 0x04, 0x14, + 0x0C, 0x04, 0x0C, + 0x08, 0x00, 0x08, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x2C, 0x24, 0x0C, + 0x34, 0x34, 0x28, + 0x2C, 0x2C, 0x1C, + 0x24, 0x24, 0x10, + 0x1C, 0x18, 0x08, + 0x14, 0x14, 0x08, + 0x10, 0x10, 0x04, + 0x0C, 0x0C, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x38, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x14, 0x28, 0x31, + 0x10, 0x20, 0x2C, + 0x0C, 0x19, 0x27, + 0x08, 0x12, 0x21, + 0x05, 0x0C, 0x1C, + 0x03, 0x07, 0x16, + 0x01, 0x03, 0x11, + 0x00, 0x3C, 0x00, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x10, 0x28, 0x1C, + 0x10, 0x1C, 0x10, + 0x10, 0x14, 0x0C, + 0x1C, 0x1C, 0x3C, + 0x24, 0x24, 0x3C, + 0x18, 0x18, 0x24, + 0x10, 0x10, 0x18, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, + 0x10, 0x28, 0x1C, + 0x10, 0x1C, 0x10, + 0x10, 0x14, 0x0C, + 0x1C, 0x1C, 0x3C, + 0x24, 0x24, 0x3C, + 0x18, 0x18, 0x24, + 0x10, 0x10, 0x18, + 0x14, 0x20, 0x04, + 0x00, 0x00, 0x24, + 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, + 0x3C, 0x2C, 0x00, + 0x3C, 0x18, 0x00, + 0x3C, 0x04, 0x00, + 0x1C, 0x00, 0x00 + } +}; + +#endif // GOB_PREGOB_ONCEUPON_PALETTES_H diff --git a/engines/gob/pregob/onceupon/parents.cpp b/engines/gob/pregob/onceupon/parents.cpp new file mode 100644 index 0000000000..cdaee6a38d --- /dev/null +++ b/engines/gob/pregob/onceupon/parents.cpp @@ -0,0 +1,217 @@ +/* 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 "gob/gob.h" +#include "gob/global.h" +#include "gob/dataio.h" +#include "gob/palanim.h" +#include "gob/draw.h" +#include "gob/video.h" + +#include "gob/sound/sound.h" + +#include "gob/pregob/gctfile.h" + +#include "gob/pregob/onceupon/palettes.h" +#include "gob/pregob/onceupon/parents.h" + +namespace Gob { + +namespace OnceUpon { + +const char *Parents::kSound[kSoundCount] = { + "rire.snd", // kSoundCackle + "tonn.snd" // kSoundThunder +}; + +// So that every GCT line is displayed for 12 seconds +const uint16 Parents::kLoop[kLoopCount][3] = { + { 72, 77, 33}, + {105, 109, 38}, + {141, 145, 38}, + {446, 454, 23}, + {456, 464, 23}, + {466, 474, 23}, + {476, 484, 23} +}; + + +Parents::Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct, + const Common::String &childName, uint8 house, const Font &font, + const byte *normalPalette, const byte *brightPalette, uint paletteSize) : + SEQFile(vm, seq), + _gct(0), _house(house), _font(&font), + _paletteSize(paletteSize), _normalPalette(normalPalette), _brightPalette(brightPalette) { + + // Load sounds + for (int i = 0; i < kSoundCount; i++) + _vm->_sound->sampleLoad(&_sounds[i], SOUND_SND, kSound[i]); + + // Load GCT + Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gct); + if (gctStream) { + _gct = new GCTFile(*gctStream, _vm->_rnd); + + delete gctStream; + } else + error("Parents::Parents(): Failed to open \"%s\"", gct.c_str()); + + _gct->setArea(17, 18, 303, 41); + _gct->setText(1, childName); + + _gct->selectLine(2, _house); + _gct->selectLine(4, _house); + + for (uint i = 0; i < kLoopCount; i++) + _loopID[i] = addLoop(kLoop[i][0], kLoop[i][1], kLoop[i][2]); +} + +Parents::~Parents() { + delete _gct; +} + +void Parents::play() { + _currentLoop = 0; + + SEQFile::play(true, 496, 15); + + // After playback, fade out + if (!_vm->shouldQuit()) + _vm->_palAnim->fade(0, 0, 0); +} + +void Parents::handleFrameEvent() { + switch (getFrame()) { + case 0: + // On fame 0, fade in + _vm->_draw->forceBlit(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); + break; + + case 4: + drawGCT(0); + break; + + case 55: + drawGCT(3, 0); + break; + + case 79: + drawGCT(_house + 5, 1); + break; + + case 110: + drawGCT(_house + 9, 2); + break; + + case 146: + drawGCT(17); + break; + + case 198: + drawGCT(13); + break; + + case 445: + drawGCT(14, 3); + break; + + case 455: + drawGCT(18, 4); + break; + + case 465: + drawGCT(19, 5); + break; + + case 475: + drawGCT(20, 6); + break; + + case 188: + case 228: + case 237: + case 257: + case 275: + case 426: + lightningEffect(); + break; + + case 203: + case 243: + case 252: + case 272: + case 290: + case 441: + playSound(kSoundThunder); + break; + + case 340: + playSound(kSoundCackle); + break; + } +} + +void Parents::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) { + if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight)) + abortPlay(); + + if (((key == kKeySpace) || (mouseButtons == kMouseButtonsLeft)) && (_currentLoop < kLoopCount)) + skipLoop(_loopID[_currentLoop]); +} + +void Parents::playSound(Sound sound) { + _vm->_sound->blasterStop(0); + _vm->_sound->blasterPlay(&_sounds[sound], 0, 0); +} + +void Parents::lightningEffect() { + for (int i = 0; (i < 5) && !_vm->shouldQuit(); i++) { + + setPalette(_brightPalette, _paletteSize); + _vm->_util->delay(5); + + setPalette(_normalPalette, _paletteSize); + _vm->_util->delay(5); + } +} + +void Parents::setPalette(const byte *palette, uint size) { + memcpy(_vm->_draw->_vgaPalette, palette, 3 * size); + + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + _vm->_video->retrace(); +} + +void Parents::drawGCT(uint item, uint loop) { + int16 left, top, right, bottom; + if (_gct->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + if (_gct->draw(*_vm->_draw->_backSurface, item, *_font, 10, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + _currentLoop = loop; +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/parents.h b/engines/gob/pregob/onceupon/parents.h new file mode 100644 index 0000000000..f5c8307b73 --- /dev/null +++ b/engines/gob/pregob/onceupon/parents.h @@ -0,0 +1,94 @@ +/* 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 GOB_PREGOB_ONCEUPON_PARENTS_H +#define GOB_PREGOB_ONCEUPON_PARENTS_H + +#include "gob/sound/sounddesc.h" + +#include "gob/pregob/seqfile.h" + +namespace Gob { + +class Font; + +class GCTFile; + +namespace OnceUpon { + +/** The home / parents animation sequence. */ +class Parents : public SEQFile { +public: + Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct, + const Common::String &childName, uint8 house, const Font &font, + const byte *normalPalette, const byte *brightPalette, uint paletteSize); + ~Parents(); + + void play(); + +protected: + void handleFrameEvent(); + void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons); + +private: + static const uint kLoopCount = 7; + + static const uint16 kLoop[kLoopCount][3]; + + enum Sound { + kSoundCackle = 0, + kSoundThunder , + kSoundCount + }; + + static const char *kSound[kSoundCount]; + + + uint8 _house; + + const Font *_font; + + uint _paletteSize; + const byte *_normalPalette; + const byte *_brightPalette; + + SoundDesc _sounds[kSoundCount]; + + GCTFile *_gct; + + uint _loopID[kLoopCount]; + uint _currentLoop; + + + void lightningEffect(); + + void playSound(Sound sound); + void setPalette(const byte *palette, uint size); + + void drawGCT(uint item, uint loop = 0xFFFF); +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_PARENTS_H diff --git a/engines/gob/pregob/onceupon/stork.cpp b/engines/gob/pregob/onceupon/stork.cpp new file mode 100644 index 0000000000..3c38037d08 --- /dev/null +++ b/engines/gob/pregob/onceupon/stork.cpp @@ -0,0 +1,234 @@ +/* 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 "common/str.h" + +#include "gob/gob.h" +#include "gob/surface.h" +#include "gob/anifile.h" +#include "gob/video.h" + +#include "gob/pregob/onceupon/stork.h" + +enum Animation { + kAnimFlyNearWithBundle = 9, + kAnimFlyFarWithBundle = 12, + kAnimFlyNearWithoutBundle = 10, + kAnimFlyFarWithoutBundle = 13, + kAnimBundleNear = 11, + kAnimBundleFar = 14 +}; + +namespace Gob { + +namespace OnceUpon { + +Stork::Stork(GobEngine *vm, const ANIFile &ani) : ANIObject(ani), _shouldDrop(false) { + _frame = new Surface(320, 200, 1); + vm->_video->drawPackedSprite("cadre.cmp", *_frame); + + _bundle = new ANIObject(ani); + + _bundle->setVisible(false); + _bundle->setPause(true); + + setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80); +} + +Stork::~Stork() { + delete _frame; + + delete _bundle; +} + +bool Stork::hasBundleLanded() const { + if (!_shouldDrop || !_bundle->isVisible() || _bundle->isPaused()) + return false; + + int16 x, y, width, height; + _bundle->getFramePosition(x, y); + _bundle->getFrameSize(width, height); + + return (y + height) >= _bundleDrop.landY; +} + +void Stork::dropBundle(const BundleDrop &drop) { + if (_shouldDrop) + return; + + _shouldDrop = true; + _bundleDrop = drop; +} + +bool Stork::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + left = 0x7FFF; + top = 0x7FFF; + right = 0x0000; + bottom = 0x0000; + + bool drawn = ANIObject::draw(dest, left, top, right, bottom); + if (drawn) { + // Left frame edge + if (left <= 15) + dest.blit(*_frame, left, top, MIN<int16>(15, right), bottom, left, top); + + // Right frame edge + if (right >= 304) + dest.blit(*_frame, MAX<int16>(304, left), top, right, bottom, MAX<int16>(304, left), top); + } + + int16 bLeft, bTop, bRight, bBottom; + if (_bundle->draw(dest, bLeft, bTop, bRight, bBottom)) { + // Bottom frame edge + if (bBottom >= 188) + dest.blit(*_frame, bLeft, MAX<int16>(188, bTop), bRight, bBottom, bLeft, MAX<int16>(188, bTop)); + + left = MIN(left , bLeft ); + top = MIN(top , bTop ); + right = MAX(right , bRight ); + bottom = MAX(bottom, bBottom); + + drawn = true; + } + + return drawn; +} + +bool Stork::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { + left = 0x7FFF; + top = 0x7FFF; + right = 0x0000; + bottom = 0x0000; + + bool cleared = _bundle->clear(dest, left, top, right, bottom); + + int16 sLeft, sTop, sRight, sBottom; + if (ANIObject::clear(dest, sLeft, sTop, sRight, sBottom)) { + left = MIN(left , sLeft ); + top = MIN(top , sTop ); + right = MAX(right , sRight ); + bottom = MAX(bottom, sBottom); + + cleared = true; + } + + return cleared; +} + +void Stork::advance() { + _bundle->advance(); + + ANIObject::advance(); + + int16 curX, curY, curWidth, curHeight; + getFramePosition(curX, curY, 0); + getFrameSize(curWidth, curHeight, 0); + + const int16 curRight = curX + curWidth - 1; + + int16 nextX, nextY, nextWidth, nextHeight; + getFramePosition(nextX, nextY, 1); + getFrameSize(nextWidth, nextHeight, 1); + + const int16 nextRight = nextX + nextWidth - 1; + + switch (_state) { + case kStateFlyNearWithBundle: + if (curX >= 330) + setState(kStateFlyFarWithBundle, kAnimFlyFarWithBundle, 330); + + if ((curRight <= _bundleDrop.dropX) && + (nextRight >= _bundleDrop.dropX) && _shouldDrop && !_bundleDrop.dropWhileFar) + dropBundle(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle); + + break; + + case kStateFlyFarWithBundle: + if (curX <= -80) + setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80); + + if ((curX >= _bundleDrop.dropX) && + (nextX <= _bundleDrop.dropX) && _shouldDrop && _bundleDrop.dropWhileFar) + dropBundle(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle); + + break; + + case kStateFlyNearWithoutBundle: + if (curX >= 330) + setState(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle, 330); + break; + + case kStateFlyFarWithoutBundle: + if (curX <= -80) + setState(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle, -80); + break; + + default: + break; + } +} + +void Stork::dropBundle(State state, uint16 anim) { + setState(state, anim); + + int16 x, y, width, height; + getFramePosition(x, y); + getFrameSize(width, height); + + _bundle->setAnimation(_bundleDrop.anim); + _bundle->setPause(false); + _bundle->setVisible(true); + + int16 bWidth, bHeight; + _bundle->getFrameSize(bWidth, bHeight); + + // Drop position + x = _bundleDrop.dropX; + y = y + height - bHeight; + + // If the stork is flying near (from left to right), drop the bundle at the right edge + if (!_bundleDrop.dropWhileFar) + x = x - bWidth; + + _bundle->setPosition(x, y); +} + +void Stork::setState(State state, uint16 anim) { + setAnimation(anim); + setVisible(true); + setPause(false); + + _state = state; +} + +void Stork::setState(State state, uint16 anim, int16 x) { + setState(state, anim); + setPosition(); + + int16 pX, pY; + getPosition(pX, pY); + setPosition( x, pY); +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/stork.h b/engines/gob/pregob/onceupon/stork.h new file mode 100644 index 0000000000..756f5258c7 --- /dev/null +++ b/engines/gob/pregob/onceupon/stork.h @@ -0,0 +1,103 @@ +/* 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 GOB_PREGOB_ONCEUPON_STORK_H +#define GOB_PREGOB_ONCEUPON_STORK_H + +#include "common/system.h" + +#include "gob/aniobject.h" + +namespace Common { + class String; +} + +namespace Gob { + +class GobEngine; + +class Surface; +class ANIFile; + +namespace OnceUpon { + +/** The stork in Baba Yaga / dragon in Abracadabra. */ +class Stork : public ANIObject { +public: + /** Information on how to drop the bundle. */ + struct BundleDrop { + int16 anim; ///< Animation of the bundle floating down + + int16 dropX; ///< X position the stork drops the bundle + int16 landY; ///< Y position the bundle lands + + bool dropWhileFar; ///< Does the stork drop the bundle while far instead of near? + }; + + Stork(GobEngine *vm, const ANIFile &ani); + ~Stork(); + + /** Has the bundle landed? */ + bool hasBundleLanded() const; + + /** Drop the bundle. */ + void dropBundle(const BundleDrop &drop); + + /** Draw the current frame onto the surface and return the affected rectangle. */ + bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + /** Draw the current frame from the surface and return the affected rectangle. */ + bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom); + + /** Advance the animation to the next frame. */ + void advance(); + +private: + enum State { + kStateFlyNearWithBundle = 0, + kStateFlyFarWithBundle , + kStateFlyNearWithoutBundle , + kStateFlyFarWithoutBundle + }; + + + GobEngine *_vm; + + Surface *_frame; + ANIObject *_bundle; + + State _state; + + bool _shouldDrop; + BundleDrop _bundleDrop; + + + void setState(State state, uint16 anim); + void setState(State state, uint16 anim, int16 x); + + void dropBundle(State state, uint16 anim); +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_STORK_H diff --git a/engines/gob/pregob/onceupon/title.cpp b/engines/gob/pregob/onceupon/title.cpp new file mode 100644 index 0000000000..5163ff6822 --- /dev/null +++ b/engines/gob/pregob/onceupon/title.cpp @@ -0,0 +1,117 @@ +/* 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 "gob/gob.h" +#include "gob/global.h" +#include "gob/palanim.h" +#include "gob/draw.h" + +#include "gob/sound/sound.h" + +#include "gob/pregob/onceupon/title.h" + +namespace Gob { + +namespace OnceUpon { + +Title::Title(GobEngine *vm) : SEQFile(vm, "ville.seq") { +} + +Title::~Title() { +} + +void Title::play() { + SEQFile::play(true, 0xFFFF, 15); + + // After playback, fade out and stop the music + if (!_vm->shouldQuit()) + _vm->_palAnim->fade(0, 0, 0); + + stopMusic(); +} + +void Title::handleFrameEvent() { + // On fame 0, start the music and fade in + if (getFrame() == 0) { + playMusic(); + + _vm->_draw->forceBlit(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); + } +} + +void Title::playMusic() { + // Look at what platform this is and play the appropriate music type + + if (_vm->getPlatform() == Common::kPlatformPC) + playMusicDOS(); + else if (_vm->getPlatform() == Common::kPlatformAmiga) + playMusicAmiga(); + else if (_vm->getPlatform() == Common::kPlatformAtariST) + playMusicAtariST(); +} + +void Title::playMusicDOS() { + // Play an AdLib track + + _vm->_sound->adlibLoadTBR("babayaga.tbr"); + _vm->_sound->adlibLoadMDY("babayaga.mdy"); + _vm->_sound->adlibSetRepeating(-1); + _vm->_sound->adlibPlay(); +} + +void Title::playMusicAmiga() { + // Play a Protracker track + + _vm->_sound->protrackerPlay("mod.babayaga"); +} + +void Title::playMusicAtariST() { + // Play a Soundblaster composition + + static const int16 titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1}; + static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"}; + + for (uint i = 0; i < ARRAYSIZE(titleFiles); i++) + _vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]); + + _vm->_sound->blasterPlayComposition(titleMusic, 0); + _vm->_sound->blasterRepeatComposition(-1); +} + +void Title::stopMusic() { + // Just stop everything + + _vm->_sound->adlibSetRepeating(0); + _vm->_sound->blasterRepeatComposition(0); + + _vm->_sound->adlibStop(); + _vm->_sound->blasterStopComposition(); + _vm->_sound->protrackerStop(); + + for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++) + _vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i)); +} + +} // End of namespace OnceUpon + +} // End of namespace Gob diff --git a/engines/gob/pregob/onceupon/title.h b/engines/gob/pregob/onceupon/title.h new file mode 100644 index 0000000000..5e7ef76d40 --- /dev/null +++ b/engines/gob/pregob/onceupon/title.h @@ -0,0 +1,55 @@ +/* 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 GOB_PREGOB_ONCEUPON_TITLE_H +#define GOB_PREGOB_ONCEUPON_TITLE_H + +#include "gob/pregob/seqfile.h" + +namespace Gob { + +namespace OnceUpon { + +/** The Once Upon A Time title animation sequence. */ +class Title : public SEQFile { +public: + Title(GobEngine *vm); + ~Title(); + + void play(); + +protected: + void handleFrameEvent(); + +private: + void playMusic(); ///< Play the title music. + void playMusicDOS(); ///< Play the title music of the DOS version. + void playMusicAmiga(); ///< Play the title music of the Amiga version. + void playMusicAtariST(); ///< Play the title music of the Atari ST version. + void stopMusic(); ///< Stop the title music. +}; + +} // End of namespace OnceUpon + +} // End of namespace Gob + +#endif // GOB_PREGOB_ONCEUPON_TITLE_H diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp new file mode 100644 index 0000000000..54eb3c6795 --- /dev/null +++ b/engines/gob/pregob/pregob.cpp @@ -0,0 +1,351 @@ +/* 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 "graphics/cursorman.h" + +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/surface.h" +#include "gob/dataio.h" +#include "gob/palanim.h" +#include "gob/draw.h" +#include "gob/video.h" +#include "gob/aniobject.h" + +#include "gob/sound/sound.h" + +#include "gob/pregob/pregob.h" +#include "gob/pregob/gctfile.h" + + +namespace Gob { + +const char PreGob::kLanguageSuffixShort[5] = { 't', 'g', 'a', 'e', 'i'}; +const char *PreGob::kLanguageSuffixLong [5] = {"fr", "al", "an", "it", "es"}; + + +PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) { +} + +PreGob::~PreGob() { +} + +void PreGob::fadeOut() { + if (_fadedOut || _vm->shouldQuit()) + return; + + // Fade to black + _vm->_palAnim->fade(0, 0, 0); + + _fadedOut = true; +} + +void PreGob::fadeIn() { + if (!_fadedOut || _vm->shouldQuit()) + return; + + // Fade to palette + _vm->_draw->blitInvalidated(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); + + _fadedOut = false; +} + +void PreGob::clearScreen() { + _vm->_draw->_backSurface->clear(); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); + _vm->_draw->blitInvalidated(); + _vm->_video->retrace(); +} + +void PreGob::initScreen() { + _vm->_util->setFrameRate(15); + + _fadedOut = true; + + _vm->_draw->initScreen(); + + _vm->_draw->_backSurface->clear(); + _vm->_util->clearPalette(); + + _vm->_draw->forceBlit(); + _vm->_video->retrace(); + + _vm->_util->processInput(); +} + +void PreGob::setPalette(const byte *palette, uint16 size) { + memcpy(_vm->_draw->_vgaPalette, palette, 3 * size); + + // If we didn't fade out prior, immediately set the palette + if (!_fadedOut) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); +} + +void PreGob::addCursor() { + CursorMan.pushCursor(0, 0, 0, 0, 0, 0); +} + +void PreGob::removeCursor() { + CursorMan.popCursor(); +} + +void PreGob::setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY) { + CursorMan.replaceCursor(sprite.getData(), sprite.getWidth(), sprite.getHeight(), hotspotX, hotspotY, 0); +} + +void PreGob::setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom, + int16 hotspotX, int16 hotspotY) { + + const int width = right - left + 1; + const int height = bottom - top + 1; + + if ((width <= 0) || (height <= 0)) + return; + + Surface cursor(width, height, 1); + + cursor.blit(sprite, left, top, right, bottom, 0, 0); + + setCursor(cursor, hotspotX, hotspotX); +} + +void PreGob::showCursor() { + CursorMan.showMouse(true); + + _vm->_draw->_showCursor = 4; +} + +void PreGob::hideCursor() { + CursorMan.showMouse(false); + + _vm->_draw->_showCursor = 0; +} + +bool PreGob::isCursorVisible() const { + return CursorMan.isVisible(); +} + +void PreGob::loadSounds(const char * const *sounds, uint soundCount) { + freeSounds(); + + _sounds.resize(soundCount); + + for (uint i = 0; i < soundCount; i++) + loadSound(_sounds[i], sounds[i]); +} + +void PreGob::freeSounds() { + _sounds.clear(); +} + +bool PreGob::loadSound(SoundDesc &sound, const Common::String &file) const { + return _vm->_sound->sampleLoad(&sound, SOUND_SND, file.c_str()); +} + +void PreGob::playSound(uint sound, int16 frequency, int16 repCount) { + if (sound >= _sounds.size()) + return; + + _vm->_sound->blasterPlay(&_sounds[sound], repCount, frequency); +} + +void PreGob::stopSound() { + _vm->_sound->blasterStop(0); +} + +void PreGob::playSoundFile(const Common::String &file, int16 frequency, int16 repCount, bool interruptible) { + stopSound(); + + SoundDesc sound; + if (!loadSound(sound, file)) + return; + + _vm->_sound->blasterPlay(&sound, repCount, frequency); + + _vm->_util->forceMouseUp(); + + bool finished = false; + while (!_vm->shouldQuit() && !finished && _vm->_sound->blasterPlayingSound()) { + endFrame(true); + + finished = hasInput(); + } + + _vm->_util->forceMouseUp(); + + stopSound(); +} + +void PreGob::beep(int16 frequency, int32 length) { + _vm->_sound->speakerOn(frequency, length); +} + +void PreGob::endFrame(bool doInput) { + _vm->_draw->blitInvalidated(); + _vm->_util->waitEndFrame(); + + if (doInput) + _vm->_util->processInput(); +} + +int16 PreGob::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) { + _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons); + _vm->_util->forceMouseUp(); + + return _vm->_util->checkKey(); +} + +int16 PreGob::waitInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) { + bool finished = false; + + int16 key = 0; + while (!_vm->shouldQuit() && !finished) { + endFrame(true); + + key = checkInput(mouseX, mouseY, mouseButtons); + + finished = (mouseButtons != kMouseButtonsNone) || (key != 0); + } + + return key; +} + +int16 PreGob::waitInput() { + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + return waitInput(mouseX, mouseY, mouseButtons); +} + +bool PreGob::hasInput() { + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone); +} + +void PreGob::clearAnim(ANIObject &anim) { + int16 left, top, right, bottom; + + if (anim.clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); +} + +void PreGob::drawAnim(ANIObject &anim) { + int16 left, top, right, bottom; + + if (anim.draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + anim.advance(); +} + +void PreGob::redrawAnim(ANIObject &anim) { + clearAnim(anim); + drawAnim(anim); +} + +void PreGob::clearAnim(const ANIList &anims) { + for (int i = (anims.size() - 1); i >= 0; i--) + clearAnim(*anims[i]); +} + +void PreGob::drawAnim(const ANIList &anims) { + for (ANIList::const_iterator a = anims.begin(); a != anims.end(); ++a) + drawAnim(**a); +} + +void PreGob::redrawAnim(const ANIList &anims) { + clearAnim(anims); + drawAnim(anims); +} + +void PreGob::loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const { + freeAnims(anims); + + anims.resize(count); + for (uint i = 0; i < count; i++) { + anims[i] = new ANIObject(ani); + + setAnim(*anims[i], props[i]); + } +} + +void PreGob::freeAnims(ANIList &anims) const { + for (ANIList::iterator a = anims.begin(); a != anims.end(); ++a) + delete *a; + + anims.clear(); +} + +void PreGob::setAnim(ANIObject &anim, const AnimProperties &props) const { + anim.setAnimation(props.animation); + anim.setFrame(props.frame); + anim.setMode(props.mode); + anim.setPause(props.paused); + anim.setVisible(props.visible); + + if (props.hasPosition) + anim.setPosition(props.x, props.y); + else + anim.setPosition(); +} + +Common::String PreGob::getLocFile(const Common::String &file) const { + if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffixShort)) + return file; + + return file + kLanguageSuffixShort[_vm->_global->_language]; +} + +TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const { + Common::SeekableReadStream *txtStream = _vm->_dataIO->getFile(txtFile); + if (!txtStream) + error("PreGob::loadTXT(): Failed to open \"%s\"", txtFile.c_str()); + + TXTFile *txt = new TXTFile(*txtStream, format); + + delete txtStream; + + fixTXTStrings(*txt); + + return txt; +} + +void PreGob::fixTXTStrings(TXTFile &txt) const { +} + +GCTFile *PreGob::loadGCT(const Common::String &gctFile) const { + Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gctFile); + if (!gctStream) + error("PreGob::loadGCT(): Failed to open \"%s\"", gctFile.c_str()); + + GCTFile *gct = new GCTFile(*gctStream, _vm->_rnd); + + delete gctStream; + + return gct; +} + +} // End of namespace Gob diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h new file mode 100644 index 0000000000..632f85b88e --- /dev/null +++ b/engines/gob/pregob/pregob.h @@ -0,0 +1,194 @@ +/* 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 GOB_PREGOB_PREGOB_H +#define GOB_PREGOB_PREGOB_H + +#include "common/str.h" +#include "common/array.h" + +#include "gob/util.h" +#include "gob/aniobject.h" + +#include "gob/sound/sounddesc.h" + +#include "gob/pregob/txtfile.h" + +namespace Gob { + +class GobEngine; +class Surface; + +class GCTFile; + +class PreGob { +public: + PreGob(GobEngine *vm); + virtual ~PreGob(); + + virtual void run() = 0; + + struct AnimProperties { + uint16 animation; + uint16 frame; + + ANIObject::Mode mode; + + bool visible; + bool paused; + + bool hasPosition; + int16 x; + int16 y; + }; + +protected: + typedef Common::Array<ANIObject *> ANIList; + + static const char kLanguageSuffixShort[5]; + static const char *kLanguageSuffixLong [5]; + + + GobEngine *_vm; + + + // -- Graphics -- + + /** Initialize the game screen. */ + void initScreen(); + + void fadeOut(); ///< Fade to black. + void fadeIn(); ///< Fade to the current palette. + + void clearScreen(); + + /** Change the palette. + * + * @param palette The palette to change to. + * @param size Size of the palette in colors. + */ + void setPalette(const byte *palette, uint16 size); ///< Change the palette + + /** Add a new cursor that can be manipulated to the stack. */ + void addCursor(); + /** Remove the top-most cursor from the stack. */ + void removeCursor(); + + /** Set the current cursor. */ + void setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY); + /** Set the current cursor. */ + void setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom, + int16 hotspotX, int16 hotspotY); + + /** Show the cursor. */ + void showCursor(); + /** Hide the cursor. */ + void hideCursor(); + + /** Is the cursor currently visible? */ + bool isCursorVisible() const; + + /** Remove an animation from the screen. */ + void clearAnim(ANIObject &anim); + /** Draw an animation to the screen, advancing it. */ + void drawAnim(ANIObject &anim); + /** Clear and draw an animation to the screen, advancing it. */ + void redrawAnim(ANIObject &anim); + + /** Remove animations from the screen. */ + void clearAnim(const ANIList &anims); + /** Draw animations to the screen, advancing them. */ + void drawAnim(const ANIList &anims); + /** Clear and draw animations to the screen, advancing them. */ + void redrawAnim(const ANIList &anims); + + void loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const; + void freeAnims(ANIList &anims) const; + + void setAnim(ANIObject &anim, const AnimProperties &props) const; + + /** Wait for the frame to end, handling screen updates and optionally update input. */ + void endFrame(bool doInput); + + + // -- Sound -- + + /** Load all sounds that can be played interactively in the game. */ + void loadSounds(const char * const *sounds, uint soundCount); + /** Free all loaded sound. */ + void freeSounds(); + + /** Play a loaded sound. */ + void playSound(uint sound, int16 frequency = 0, int16 repCount = 0); + /** Stop all sound playback. */ + void stopSound(); + + /** Play a sound until it ends or is interrupted by a keypress. */ + void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true); + + /** Beep the PC speaker. */ + void beep(int16 frequency, int32 length); + + + // -- Input -- + + /** Check mouse and keyboard input. */ + int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons); + /** Wait for mouse or keyboard input. */ + int16 waitInput (int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons); + /** Wait for mouse or keyboard input, but don't care about what was done with the mouse. */ + int16 waitInput(); + /** Did we have mouse or keyboard input? */ + bool hasInput(); + + + // -- TXT helpers -- + + /** Get the name of a localized file. */ + Common::String getLocFile(const Common::String &file) const; + /** Open a TXT file. */ + TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const; + + /** Called by loadTXT() to fix strings within the TXT file. */ + virtual void fixTXTStrings(TXTFile &txt) const; + + + // -- GCT helpers -- + + GCTFile *loadGCT(const Common::String &gctFile) const; + + +private: + /** Did we fade out? */ + bool _fadedOut; + + /** All loaded sounds. */ + Common::Array<SoundDesc> _sounds; + + + /** Load a sound file. */ + bool loadSound(SoundDesc &sound, const Common::String &file) const; +}; + +} // End of namespace Gob + +#endif // GOB_PREGOB_PREGOB_H diff --git a/engines/gob/pregob/seqfile.cpp b/engines/gob/pregob/seqfile.cpp new file mode 100644 index 0000000000..91973bbb85 --- /dev/null +++ b/engines/gob/pregob/seqfile.cpp @@ -0,0 +1,384 @@ +/* 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 "common/str.h" +#include "common/stream.h" + +#include "gob/gob.h" +#include "gob/dataio.h" +#include "gob/draw.h" +#include "gob/decfile.h" +#include "gob/anifile.h" +#include "gob/aniobject.h" + +#include "gob/pregob/seqfile.h" + +namespace Gob { + +SEQFile::SEQFile(GobEngine *vm, const Common::String &fileName) : _vm(vm) { + for (uint i = 0; i < kObjectCount; i++) + _objects[i].object = 0; + + Common::SeekableReadStream *seq = _vm->_dataIO->getFile(Util::setExtension(fileName, ".SEQ")); + if (!seq) { + warning("SEQFile::SEQFile(): No such file \"%s\"", fileName.c_str()); + return; + } + + load(*seq); + + delete seq; +} + +SEQFile::~SEQFile() { + for (uint i = 0; i < kObjectCount; i++) + delete _objects[i].object; + + for (Backgrounds::iterator b = _backgrounds.begin(); b != _backgrounds.end(); ++b) + delete *b; + + for (Animations::iterator a = _animations.begin(); a != _animations.end(); ++a) + delete *a; +} + +void SEQFile::load(Common::SeekableReadStream &seq) { + const uint16 decCount = (uint16)seq.readByte() + 1; + const uint16 aniCount = (uint16)seq.readByte() + 1; + + // Load backgrounds + _backgrounds.reserve(decCount); + for (uint i = 0; i < decCount; i++) { + const Common::String dec = Util::readString(seq, 13); + + if (!_vm->_dataIO->hasFile(dec)) { + warning("SEQFile::load(): No such background \"%s\"", dec.c_str()); + return; + } + + _backgrounds.push_back(new DECFile(_vm, dec, 320, 200)); + } + + // Load animations + _animations.reserve(aniCount); + for (uint i = 0; i < aniCount; i++) { + const Common::String ani = Util::readString(seq, 13); + + if (!_vm->_dataIO->hasFile(ani)) { + warning("SEQFile::load(): No such animation \"%s\"", ani.c_str()); + return; + } + + _animations.push_back(new ANIFile(_vm, ani)); + } + + _frameRate = seq.readUint16LE(); + + // Load background change keys + + const uint16 bgKeyCount = seq.readUint16LE(); + _bgKeys.resize(bgKeyCount); + + for (uint16 i = 0; i < bgKeyCount; i++) { + const uint16 frame = seq.readUint16LE(); + const uint16 index = seq.readUint16LE(); + + _bgKeys[i].frame = frame; + _bgKeys[i].background = index < _backgrounds.size() ? _backgrounds[index] : 0; + } + + // Load animation keys for all 4 objects + + for (uint i = 0; i < kObjectCount; i++) { + const uint16 animKeyCount = seq.readUint16LE(); + _animKeys.reserve(_animKeys.size() + animKeyCount); + + for (uint16 j = 0; j < animKeyCount; j++) { + _animKeys.push_back(AnimationKey()); + + const uint16 frame = seq.readUint16LE(); + const uint16 index = seq.readUint16LE(); + + uint16 animation; + const ANIFile *ani = findANI(index, animation); + + _animKeys.back().object = i; + _animKeys.back().frame = frame; + _animKeys.back().ani = ani; + _animKeys.back().animation = animation; + _animKeys.back().x = seq.readSint16LE(); + _animKeys.back().y = seq.readSint16LE(); + _animKeys.back().order = seq.readSint16LE(); + } + } + +} + +const ANIFile *SEQFile::findANI(uint16 index, uint16 &animation) { + animation = 0xFFFF; + + // 0xFFFF = remove animation + if (index == 0xFFFF) + return 0; + + for (Animations::const_iterator a = _animations.begin(); a != _animations.end(); ++a) { + if (index < (*a)->getAnimationCount()) { + animation = index; + return *a; + } + + index -= (*a)->getAnimationCount(); + } + + return 0; +} + +void SEQFile::play(bool abortable, uint16 endFrame, uint16 frameRate) { + if (_bgKeys.empty() && _animKeys.empty()) + // Nothing to do + return; + + // Init + + _frame = 0; + _abortPlay = false; + + for (uint i = 0; i < kObjectCount; i++) { + delete _objects[i].object; + + _objects[i].object = 0; + _objects[i].order = 0; + } + + for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l) + l->currentLoop = 0; + + // Set the frame rate + + int16 frameRateBack = _vm->_util->getFrameRate(); + + if (frameRate == 0) + frameRate = _frameRate; + + _vm->_util->setFrameRate(frameRate); + + _abortable = abortable; + + while (!_vm->shouldQuit() && !_abortPlay) { + // Handle the frame contents + playFrame(); + + // Handle extra frame events + handleFrameEvent(); + + // Wait for the frame to end + _vm->_draw->blitInvalidated(); + _vm->_util->waitEndFrame(); + + // Handle input + + _vm->_util->processInput(); + + int16 key = _vm->_util->checkKey(); + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons); + _vm->_util->forceMouseUp(); + + handleInput(key, mouseX, mouseY, mouseButtons); + + // Loop + + bool looped = false; + for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l) { + if ((l->endFrame == _frame) && (l->currentLoop < l->loopCount)) { + _frame = l->startFrame; + + l->currentLoop++; + looped = true; + } + } + + // If we didn't loop, advance the frame and look if we should end here + + if (!looped) { + _frame++; + if (_frame >= endFrame) + break; + } + } + + // Restore the frame rate + _vm->_util->setFrameRate(frameRateBack); +} + +void SEQFile::playFrame() { + // Remove the current animation frames + clearAnims(); + + // Handle background keys, directly updating the background + for (BackgroundKeys::const_iterator b = _bgKeys.begin(); b != _bgKeys.end(); ++b) { + if (!b->background || (b->frame != _frame)) + continue; + + b->background->draw(*_vm->_draw->_backSurface); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); + } + + // Handle the animation keys, updating the objects + for (AnimationKeys::const_iterator a = _animKeys.begin(); a != _animKeys.end(); ++a) { + if (a->frame != _frame) + continue; + + Object &object = _objects[a->object]; + + delete object.object; + object.object = 0; + + // No valid animation => remove + if ((a->animation == 0xFFFF) || !a->ani) + continue; + + // Change the animation + + object.object = new ANIObject(*a->ani); + + object.object->setAnimation(a->animation); + object.object->setPosition(a->x, a->y); + object.object->setVisible(true); + object.object->setPause(false); + + object.order = a->order; + } + + // Draw the animations + drawAnims(); +} + +// NOTE: This is really not at all efficient. However, since there's only a +// small number of objects, it should matter. We really do need a stable +// sort, though, so Common::sort() is out. +SEQFile::Objects SEQFile::getOrderedObjects() { + int16 minOrder = (int16)0x7FFF; + int16 maxOrder = (int16)0x8000; + + Objects objects; + + // Find the span of order values + for (uint i = 0; i < kObjectCount; i++) { + if (!_objects[i].object) + continue; + + minOrder = MIN(minOrder, _objects[i].order); + maxOrder = MAX(maxOrder, _objects[i].order); + } + + // Stably sort the objects by order value + for (int16 o = minOrder; o <= maxOrder; o++) + for (uint i = 0; i < kObjectCount; i++) + if (_objects[i].object && (_objects[i].order == o)) + objects.push_back(_objects[i]); + + return objects; +} + +void SEQFile::clearAnims() { + Objects objects = getOrderedObjects(); + + // Remove the animation frames, in reverse drawing order + for (Objects::iterator o = objects.reverse_begin(); o != objects.end(); --o) { + int16 left, top, right, bottom; + + if (o->object->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + } +} + +void SEQFile::drawAnims() { + Objects objects = getOrderedObjects(); + + // Draw the animation frames and advance the animation + for (Objects::iterator o = objects.begin(); o != objects.end(); ++o) { + int16 left, top, right, bottom; + + if (o->object->draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + o->object->advance(); + } +} + +uint16 SEQFile::getFrame() const { + return _frame; +} + +void SEQFile::seekFrame(uint16 frame) { + _frame = frame; +} + +uint SEQFile::addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount) { + _loops.resize(_loops.size() + 1); + + _loops.back().startFrame = startFrame; + _loops.back().endFrame = endFrame; + _loops.back().loopCount = loopCount; + _loops.back().currentLoop = 0; + _loops.back().empty = false; + + return _loops.size() - 1; +} + +void SEQFile::skipLoop(uint loopID) { + if (loopID >= _loops.size()) + return; + + _loops[loopID].currentLoop = 0xFFFF; +} + +void SEQFile::delLoop(uint loopID) { + if (loopID >= _loops.size()) + return; + + _loops[loopID].empty = true; + + cleanLoops(); +} + +void SEQFile::cleanLoops() { + while (!_loops.empty() && _loops.back().empty) + _loops.pop_back(); +} + +void SEQFile::abortPlay() { + _abortPlay = true; +} + +void SEQFile::handleFrameEvent() { +} + +void SEQFile::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) { + if (_abortable && ((key != 0) || (mouseButtons != kMouseButtonsNone))) + abortPlay(); +} + +} // End of namespace Gob diff --git a/engines/gob/pregob/seqfile.h b/engines/gob/pregob/seqfile.h new file mode 100644 index 0000000000..5e12962ef9 --- /dev/null +++ b/engines/gob/pregob/seqfile.h @@ -0,0 +1,193 @@ +/* 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 GOB_PREGOB_SEQFILE_H +#define GOB_PREGOB_SEQFILE_H + +#include "common/system.h" +#include "common/array.h" +#include "common/list.h" + +#include "gob/util.h" + +namespace Common { + class String; + class SeekableReadStream; +} + +namespace Gob { + +class GobEngine; + +class DECFile; +class ANIFile; +class ANIObject; + +/** A SEQ file, describing a complex animation sequence. + * + * Used in early hardcoded gob games. + * The principle is similar to the Mult class (see mult.h), but instead + * of depending on all the externally loaded animations, backgrounds and + * objects, a SEQ file references animation and background directly by + * filename. + */ +class SEQFile { +public: + SEQFile(GobEngine *vm, const Common::String &fileName); + virtual ~SEQFile(); + + /** Play the SEQ. + * + * @param abortable If true, end playback on any user input. + * @param endFrame The frame on where to end, or 0xFFFF for infinite playback. + * @param frameRate The frame rate at which to play the SEQ, or 0 for playing at + * the speed the SEQ itself wants to. + */ + void play(bool abortable = true, uint16 endFrame = 0xFFFF, uint16 frameRate = 0); + + +protected: + GobEngine *_vm; + + + /** Returns the current frame number. */ + uint16 getFrame() const; + + /** Seek to a specific frame. */ + void seekFrame(uint16 frame); + + /** Add a frame loop. */ + uint addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount); + + /** Skip a frame loop. */ + void skipLoop(uint loopID); + + /** Delete a frame loop. */ + void delLoop(uint loopID); + + /** Ends SEQ playback. */ + void abortPlay(); + + /** Callback for special frame events. */ + virtual void handleFrameEvent(); + /** Callback for special user input handling. */ + virtual void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons); + + +private: + /** Number of animation objects that are visible at the same time. */ + static const uint kObjectCount = 4; + + /** A key for changing the background. */ + struct BackgroundKey { + uint16 frame; ///< Frame the change is to happen. + + const DECFile *background; ///< The background to use. + }; + + /** A key for playing an object animation. */ + struct AnimationKey { + uint object; ///< The object this key belongs to. + + uint16 frame; ///< Frame the change is to happen. + + const ANIFile *ani; ///< The ANI to use. + + uint16 animation; ///< The animation to use. + + int16 x; ///< X position of the animation. + int16 y; ///< Y position of the animation. + + int16 order; ///< Used to determine in which order to draw the objects. + }; + + /** A managed animation object. */ + struct Object { + ANIObject *object; ///< The actual animation object. + + int16 order; ///< The current drawing order. + }; + + /** A frame loop. */ + struct Loop { + uint16 startFrame; + uint16 endFrame; + + uint16 loopCount; + uint16 currentLoop; + + bool empty; + }; + + typedef Common::Array<DECFile *> Backgrounds; + typedef Common::Array<ANIFile *> Animations; + + typedef Common::Array<BackgroundKey> BackgroundKeys; + typedef Common::Array<AnimationKey> AnimationKeys; + + typedef Common::List<Object> Objects; + + typedef Common::Array<Loop> Loops; + + + uint16 _frame; ///< The current frame. + bool _abortPlay; ///< Was the end of the playback requested? + + uint16 _frameRate; + + Backgrounds _backgrounds; ///< All backgrounds in this SEQ. + Animations _animations; ///< All animations in this SEQ. + + BackgroundKeys _bgKeys; ///< The background change keyframes. + AnimationKeys _animKeys; ///< The animation change keyframes. + + Object _objects[kObjectCount]; ///< The managed animation objects. + + Loops _loops; + + /** Whether the playback should be abortable by user input. */ + bool _abortable; + + + // -- Loading helpers -- + + void load(Common::SeekableReadStream &seq); + + const ANIFile *findANI(uint16 index, uint16 &animation); + + // -- Playback helpers -- + + void playFrame(); + + /** Get a list of objects ordered by drawing order. */ + Objects getOrderedObjects(); + + void clearAnims(); ///< Remove all animation frames. + void drawAnims(); ///< Draw the animation frames. + + /** Look if we can compact the loop array. */ + void cleanLoops(); +}; + +} // End of namespace Gob + +#endif // GOB_PREGOB_SEQFILE_H diff --git a/engines/gob/pregob/txtfile.cpp b/engines/gob/pregob/txtfile.cpp new file mode 100644 index 0000000000..3ff0d4b039 --- /dev/null +++ b/engines/gob/pregob/txtfile.cpp @@ -0,0 +1,232 @@ +/* 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 "common/stream.h" + +#include "gob/draw.h" + +#include "gob/pregob/txtfile.h" + +namespace Gob { + +TXTFile::TXTFile(Common::SeekableReadStream &txt, Format format) { + load(txt, format); +} + +TXTFile::~TXTFile() { +} + +TXTFile::LineArray &TXTFile::getLines() { + return _lines; +} + +void TXTFile::load(Common::SeekableReadStream &txt, Format format) { + if (format == kFormatStringPositionColorFont) { + int numLines = getInt(txt); + + _lines.reserve(numLines); + } + + while (!txt.eos()) { + Line line; + + line.text = getStr(txt); + line.x = (format >= kFormatStringPosition) ? getInt(txt) : 0; + line.y = (format >= kFormatStringPosition) ? getInt(txt) : 0; + line.color = (format >= kFormatStringPositionColor) ? getInt(txt) : 0; + line.font = (format >= kFormatStringPositionColorFont) ? getInt(txt) : 0; + + _lines.push_back(line); + } + + while (!_lines.empty() && _lines.back().text.empty()) + _lines.pop_back(); +} + +bool TXTFile::draw(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount, int color) { + + trashBuffer(); + + if (!getArea(left, top, right, bottom, fonts, fontCount)) + return false; + + resizeBuffer(right - left + 1, bottom - top + 1); + saveScreen(surface, left, top, right, bottom); + + for (LineArray::const_iterator l = _lines.begin(); l != _lines.end(); ++l) { + if (l->font >= fontCount) + continue; + + fonts[l->font]->drawString(l->text, l->x, l->y, (color < 0) ? l->color : color, 0, true, surface); + } + + return true; +} + +bool TXTFile::draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount, int color) { + + trashBuffer(); + + if (!getArea(line, left, top, right, bottom, fonts, fontCount)) + return false; + + resizeBuffer(right - left + 1, bottom - top + 1); + saveScreen(surface, left, top, right, bottom); + + const Line &l = _lines[line]; + + fonts[l.font]->drawString(l.text, l.x, l.y, (color < 0) ? l.color : color, 0, true, surface); + + return true; +} + +bool TXTFile::draw(Surface &surface, const Font * const *fonts, uint fontCount, int color) { + int16 left, top, right, bottom; + + return draw(surface, left, top, right, bottom, fonts, fontCount, color); +} + +bool TXTFile::draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color) { + int16 left, top, right, bottom; + + return draw(line, surface, left, top, right, bottom, fonts, fontCount, color); +} + +bool TXTFile::clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom) { + return restoreScreen(surface, left, top, right, bottom); +} + +bool TXTFile::getArea(int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount) const { + + bool hasLine = false; + + left = 0x7FFF; + top = 0x7FFF; + right = 0x0000; + bottom = 0x0000; + + for (uint i = 0; i < _lines.size(); i++) { + int16 lLeft, lTop, lRight, lBottom; + + if (getArea(i, lLeft, lTop, lRight, lBottom, fonts, fontCount)) { + left = MIN(left , lLeft ); + top = MIN(top , lTop ); + right = MAX(right , lRight ); + bottom = MAX(bottom, lBottom); + + hasLine = true; + } + } + + return hasLine; +} + +bool TXTFile::getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount) const { + + + if ((line >= _lines.size()) || (_lines[line].font >= fontCount)) + return false; + + const Line &l = _lines[line]; + + left = l.x; + top = l.y; + right = l.x + l.text.size() * fonts[l.font]->getCharWidth() - 1; + bottom = l.y + fonts[l.font]->getCharHeight() - 1; + + return true; +} + +Common::String TXTFile::getStr(Common::SeekableReadStream &txt) { + // Skip all ' ', '\n' and '\r' + while (!txt.eos()) { + char c = txt.readByte(); + if (txt.eos()) + break; + + if ((c != ' ') && (c != '\n') && (c != '\r')) { + txt.seek(-1, SEEK_CUR); + break; + } + } + + if (txt.eos()) + return ""; + + // Read string until ' ', '\n' or '\r' + Common::String string; + while (!txt.eos()) { + char c = txt.readByte(); + if ((c == ' ') || (c == '\n') || (c == '\r')) + break; + + string += c; + } + + // Replace all '#' with ' ' and throw out non-printables + Common::String cleanString; + + for (uint i = 0; i < string.size(); i++) { + if (string[i] == '#') + cleanString += ' '; + else if ((unsigned char)string[i] >= ' ') + cleanString += string[i]; + } + + return cleanString; +} + +int TXTFile::getInt(Common::SeekableReadStream &txt) { + // Skip all [^-0-9] + while (!txt.eos()) { + char c = txt.readByte(); + if (txt.eos()) + break; + + if ((c == '-') || ((c >= '0') && (c <= '9'))) { + txt.seek(-1, SEEK_CUR); + break; + } + } + + if (txt.eos()) + return 0; + + // Read until [^-0-9] + Common::String string; + while (!txt.eos()) { + char c = txt.readByte(); + if ((c != '-') && ((c < '0') || (c > '9'))) + break; + + string += c; + } + + // Convert to integer + return atoi(string.c_str()); +} + +} // End of namespace Gob diff --git a/engines/gob/pregob/txtfile.h b/engines/gob/pregob/txtfile.h new file mode 100644 index 0000000000..c623b58859 --- /dev/null +++ b/engines/gob/pregob/txtfile.h @@ -0,0 +1,91 @@ +/* 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 GOB_PREGOB_TXTFILE_H +#define GOB_PREGOB_TXTFILE_H + +#include "common/system.h" +#include "common/str.h" +#include "common/array.h" + +#include "gob/backbuffer.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Gob { + +class Surface; +class Font; + +class TXTFile : public BackBuffer { +public: + enum Format { + kFormatString, + kFormatStringPosition, + kFormatStringPositionColor, + kFormatStringPositionColorFont + }; + + struct Line { + Common::String text; + int x, y; + int color; + uint font; + }; + + typedef Common::Array<Line> LineArray; + + TXTFile(Common::SeekableReadStream &txt, Format format); + ~TXTFile(); + + LineArray &getLines(); + + bool draw( Surface &surface, const Font * const *fonts, uint fontCount, int color = -1); + bool draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color = -1); + + bool draw( Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount, int color = -1); + bool draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount, int color = -1); + + bool clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom); + +private: + LineArray _lines; + + void load(Common::SeekableReadStream &txt, Format format); + + Common::String getStr(Common::SeekableReadStream &txt); + int getInt(Common::SeekableReadStream &txt); + + + bool getArea( int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount) const; + bool getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom, + const Font * const *fonts, uint fontCount) const; +}; + +} // End of namespace Gob + +#endif // GOB_PREGOB_TXTFILE_H diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp index d5497c25be..a84f4ac4b8 100644 --- a/engines/gob/resources.cpp +++ b/engines/gob/resources.cpp @@ -716,7 +716,7 @@ byte *Resources::getIMData(TOTResourceItem &totItem) const { return _imData + offset; } -byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const { +byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 &size) const { Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_extFile); if (!stream) return 0; @@ -726,6 +726,10 @@ byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const { return 0; } + // If that workaround is active, limit the resource size instead of throwing an error + if (_vm->hasResourceSizeWorkaround()) + size = MIN<int>(size, stream->size() - extItem.offset); + byte *data = new byte[extItem.packed ? (size + 2) : size]; if (stream->read(data, size) != size) { delete[] data; @@ -737,7 +741,7 @@ byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const { return data; } -byte *Resources::getEXData(EXTResourceItem &extItem, uint32 size) const { +byte *Resources::getEXData(EXTResourceItem &extItem, uint32 &size) const { Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_exFile); if (!stream) return 0; @@ -747,6 +751,10 @@ byte *Resources::getEXData(EXTResourceItem &extItem, uint32 size) const { return 0; } + // If that workaround is active, limit the resource size instead of throwing an error + if (_vm->hasResourceSizeWorkaround()) + size = MIN<int>(size, stream->size() - extItem.offset); + byte *data = new byte[extItem.packed ? (size + 2) : size]; if (stream->read(data, size) != size) { delete[] data; diff --git a/engines/gob/resources.h b/engines/gob/resources.h index 39155c5176..04b3b9d31e 100644 --- a/engines/gob/resources.h +++ b/engines/gob/resources.h @@ -103,7 +103,7 @@ private: static const int kTOTTextItemSize = 2 + 2; enum ResourceType { - kResourceTOT, + kResourceTOT = 0, kResourceIM, kResourceEXT, kResourceEX @@ -201,8 +201,8 @@ private: byte *getTOTData(TOTResourceItem &totItem) const; byte *getIMData(TOTResourceItem &totItem) const; - byte *getEXTData(EXTResourceItem &extItem, uint32 size) const; - byte *getEXData(EXTResourceItem &extItem, uint32 size) const; + byte *getEXTData(EXTResourceItem &extItem, uint32 &size) const; + byte *getEXData(EXTResourceItem &extItem, uint32 &size) const; }; } // End of namespace Gob diff --git a/engines/gob/rxyfile.cpp b/engines/gob/rxyfile.cpp index 9702dc8c7f..2ff8c121cd 100644 --- a/engines/gob/rxyfile.cpp +++ b/engines/gob/rxyfile.cpp @@ -21,12 +21,19 @@ */ #include "common/stream.h" +#include "common/substream.h" #include "gob/rxyfile.h" namespace Gob { RXYFile::RXYFile(Common::SeekableReadStream &rxy) : _width(0), _height(0) { + Common::SeekableSubReadStreamEndian sub(&rxy, 0, rxy.size(), false, DisposeAfterUse::NO); + + load(sub); +} + +RXYFile::RXYFile(Common::SeekableSubReadStreamEndian &rxy) : _width(0), _height(0) { load(rxy); } @@ -64,22 +71,22 @@ const RXYFile::Coordinates &RXYFile::operator[](uint i) const { return _coords[i]; } -void RXYFile::load(Common::SeekableReadStream &rxy) { +void RXYFile::load(Common::SeekableSubReadStreamEndian &rxy) { if (rxy.size() < 2) return; rxy.seek(0); - _realCount = rxy.readUint16LE(); + _realCount = rxy.readUint16(); uint16 count = (rxy.size() - 2) / 8; _coords.resize(count); for (CoordArray::iterator c = _coords.begin(); c != _coords.end(); ++c) { - c->left = rxy.readUint16LE(); - c->right = rxy.readUint16LE(); - c->top = rxy.readUint16LE(); - c->bottom = rxy.readUint16LE(); + c->left = rxy.readUint16(); + c->right = rxy.readUint16(); + c->top = rxy.readUint16(); + c->bottom = rxy.readUint16(); if (c->left != 0xFFFF) { _width = MAX<uint16>(_width , c->right + 1); diff --git a/engines/gob/rxyfile.h b/engines/gob/rxyfile.h index bc9600b5b0..4fd46c5e40 100644 --- a/engines/gob/rxyfile.h +++ b/engines/gob/rxyfile.h @@ -28,6 +28,7 @@ namespace Common { class SeekableReadStream; + class SeekableSubReadStreamEndian; } namespace Gob { @@ -46,6 +47,7 @@ public: }; RXYFile(Common::SeekableReadStream &rxy); + RXYFile(Common::SeekableSubReadStreamEndian &rxy); RXYFile(uint16 width, uint16 height); ~RXYFile(); @@ -71,7 +73,7 @@ private: uint16 _height; - void load(Common::SeekableReadStream &rxy); + void load(Common::SeekableSubReadStreamEndian &rxy); }; } // End of namespace Gob diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h index 66b3482bac..834484757b 100644 --- a/engines/gob/save/saveload.h +++ b/engines/gob/save/saveload.h @@ -257,6 +257,33 @@ protected: SaveFile *getSaveFile(const char *fileName); }; +/** Save/Load class for A.J.'s World of Discovery. */ +class SaveLoad_AJWorld : public SaveLoad { +public: + SaveLoad_AJWorld(GobEngine *vm, const char *targetName); + virtual ~SaveLoad_AJWorld(); + + SaveMode getSaveMode(const char *fileName) const; + +protected: + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + static SaveFile _saveFiles[]; + + TempSpriteHandler *_tempSpriteHandler; + + SaveHandler *getHandler(const char *fileName) const; + const char *getDescription(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + SaveFile *getSaveFile(const char *fileName); +}; + /** Save/Load class for Goblins 3 and Lost in Time. */ class SaveLoad_v3 : public SaveLoad { public: diff --git a/engines/gob/save/saveload_ajworld.cpp b/engines/gob/save/saveload_ajworld.cpp new file mode 100644 index 0000000000..727d071b3e --- /dev/null +++ b/engines/gob/save/saveload_ajworld.cpp @@ -0,0 +1,94 @@ +/* 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 "gob/save/saveload.h" +#include "gob/save/saveconverter.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_AJWorld::SaveFile SaveLoad_AJWorld::_saveFiles[] = { + { "menu.inf", kSaveModeSave, 0, "temporary sprite"} +}; + + +SaveLoad_AJWorld::SaveLoad_AJWorld(GobEngine *vm, const char *targetName) : + SaveLoad(vm) { + + _tempSpriteHandler = new TempSpriteHandler(vm); + + _saveFiles[0].handler = _tempSpriteHandler; +} + +SaveLoad_AJWorld::~SaveLoad_AJWorld() { + delete _tempSpriteHandler; +} + +const SaveLoad_AJWorld::SaveFile *SaveLoad_AJWorld::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_AJWorld::SaveFile *SaveLoad_AJWorld::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveHandler *SaveLoad_AJWorld::getHandler(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->handler; + + return 0; +} + +const char *SaveLoad_AJWorld::getDescription(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->description; + + return 0; +} + +SaveLoad::SaveMode SaveLoad_AJWorld::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +} // End of namespace Gob diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index f1ab2a2d79..d9fc362547 100644 --- a/engines/gob/sound/adlib.cpp +++ b/engines/gob/sound/adlib.cpp @@ -20,771 +20,621 @@ * */ -#include "common/debug.h" -#include "common/file.h" -#include "common/endian.h" +#include "common/util.h" #include "common/textconsole.h" +#include "common/debug.h" +#include "common/config-manager.h" + +#include "audio/fmopl.h" #include "gob/gob.h" #include "gob/sound/adlib.h" namespace Gob { -const unsigned char AdLib::_operators[] = {0, 1, 2, 8, 9, 10, 16, 17, 18}; -const unsigned char AdLib::_volRegNums[] = { - 3, 4, 5, - 11, 12, 13, - 19, 20, 21 +static const int kPitchTom = 24; +static const int kPitchTomToSnare = 7; +static const int kPitchSnareDrum = kPitchTom + kPitchTomToSnare; + + +// Is the operator a modulator (0) or a carrier (1)? +const uint8 AdLib::kOperatorType[kOperatorCount] = { + 0, 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 1 +}; + +// Operator number to register offset on the OPL +const uint8 AdLib::kOperatorOffset[kOperatorCount] = { + 0, 1, 2, 3, 4, 5, + 8, 9, 10, 11, 12, 13, + 16, 17, 18, 19, 20, 21 +}; + +// For each operator, the voice it belongs to +const uint8 AdLib::kOperatorVoice[kOperatorCount] = { + 0, 1, 2, + 0, 1, 2, + 3, 4, 5, + 3, 4, 5, + 6, 7, 8, + 6, 7, 8, +}; + +// Voice to operator set, for the 9 melodyvoices (only 6 useable in percussion mode) +const uint8 AdLib::kVoiceMelodyOperator[kOperatorsPerVoice][kMelodyVoiceCount] = { + {0, 1, 2, 6, 7, 8, 12, 13, 14}, + {3, 4, 5, 9, 10, 11, 15, 16, 17} }; -AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { - init(); +// Voice to operator set, for the 5 percussion voices (only useable in percussion mode) +const uint8 AdLib::kVoicePercussionOperator[kOperatorsPerVoice][kPercussionVoiceCount] = { + {12, 16, 14, 17, 13}, + {15, 0, 0, 0, 0} +}; + +// Mask bits to set each percussion instrument on/off +const byte AdLib::kPercussionMasks[kPercussionVoiceCount] = {0x10, 0x08, 0x04, 0x02, 0x01}; + +// Default instrument presets +const uint16 AdLib::kPianoParams [kOperatorsPerVoice][kParamCount] = { + { 1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0}, + { 0, 1, 1, 15, 7, 0, 2, 4, 0, 0, 0, 1, 0, 0} }; +const uint16 AdLib::kBaseDrumParams[kOperatorsPerVoice][kParamCount] = { + { 0, 0, 0, 10, 4, 0, 8, 12, 11, 0, 0, 0, 1, 0 }, + { 0, 0, 0, 13, 4, 0, 6, 15, 0, 0, 0, 0, 1, 0 } }; +const uint16 AdLib::kSnareDrumParams[kParamCount] = { + 0, 12, 0, 15, 11, 0, 8, 5, 0, 0, 0, 0, 0, 0 }; +const uint16 AdLib::kTomParams [kParamCount] = { + 0, 4, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 }; +const uint16 AdLib::kCymbalParams [kParamCount] = { + 0, 1, 0, 15, 11, 0, 5, 5, 0, 0, 0, 0, 0, 0 }; +const uint16 AdLib::kHihatParams [kParamCount] = { + 0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 }; + + +AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer), _opl(0), + _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true) { + + _rate = _mixer->getOutputRate(); + + initFreqs(); + + createOPL(); + initOPL(); + + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle, + this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); } AdLib::~AdLib() { - Common::StackLock slock(_mutex); - _mixer->stopHandle(_handle); - OPLDestroy(_opl); - if (_data && _freeData) - delete[] _data; -} -void AdLib::init() { - _index = -1; - _data = 0; - _playPos = 0; - _dataSize = 0; + delete _opl; +} - _rate = _mixer->getOutputRate(); +// Creates the OPL. Try to use the DOSBox emulator, unless that one is not compiled in, +// or the user explicitly wants the MAME emulator. The MAME one is slightly buggy, leading +// to some wrong sounds, especially noticeable in the title music of Gobliins 2, so we +// really don't want to use it, if we can help it. +void AdLib::createOPL() { + Common::String oplDriver = ConfMan.get("opl_driver"); - _opl = makeAdLibOPL(_rate); + if (oplDriver.empty() || (oplDriver == "auto") || (OPL::Config::parse(oplDriver) == -1)) { + // User has selected OPL driver auto detection or an invalid OPL driver. + // Set it to our preferred driver (DOSBox), if we can. - _first = true; - _ended = false; - _playing = false; + if (OPL::Config::parse("db") <= 0) { + warning("The DOSBox AdLib emulator is not compiled in. Please keep in mind that the MAME one is buggy"); + } else + oplDriver = "db"; - _freeData = false; + } else if (oplDriver == "mame") { + // User has selected the MAME OPL driver. It is buggy, so warn the user about that. - _repCount = -1; - _samplesTillPoll = 0; + warning("You have selected the MAME AdLib emulator. It is buggy; AdLib music might be slightly glitchy now"); + } - for (int i = 0; i < 16; i ++) - _pollNotes[i] = 0; - setFreqs(); + _opl = OPL::Config::create(OPL::Config::parse(oplDriver), OPL::Config::kOpl2); + if (!_opl || !_opl->init(_rate)) { + delete _opl; - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle, - this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + error("Could not create an AdLib emulator"); + } } int AdLib::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); - int samples; - int render; - if (!_playing || (numSamples < 0)) { + // Nothing to do, fill with silence + if (!_playing) { memset(buffer, 0, numSamples * sizeof(int16)); return numSamples; } - if (_first) { - memset(buffer, 0, numSamples * sizeof(int16)); - pollMusic(); - return numSamples; - } - samples = numSamples; + // Read samples from the OPL, polling in more music when necessary + uint32 samples = numSamples; while (samples && _playing) { - if (_samplesTillPoll) { - render = (samples > _samplesTillPoll) ? (_samplesTillPoll) : (samples); + if (_toPoll) { + const uint32 render = MIN(samples, _toPoll); + + _opl->readBuffer(buffer, render); + + buffer += render; samples -= render; - _samplesTillPoll -= render; - YM3812UpdateOne(_opl, buffer, render); - buffer += render; + _toPoll -= render; + } else { - pollMusic(); + // Song ended, fill the rest with silence if (_ended) { memset(buffer, 0, samples * sizeof(int16)); samples = 0; + break; } + + // Poll more music + _toPoll = pollMusic(_first); + _first = false; } } + // Song ended, loop if requested if (_ended) { - _first = true; - _ended = false; + _toPoll = 0; - rewind(); + // _repCount == 0: No looping (anymore); _repCount < 0: Infinite looping + if (_repCount != 0) { + if (_repCount > 0) + _repCount--; + + _first = true; + _ended = false; - _samplesTillPoll = 0; - if (_repCount == -1) { - reset(); - setVoices(); - } else if (_repCount > 0) { - _repCount--; reset(); - setVoices(); - } - else + rewind(); + } else _playing = false; } - return numSamples; -} -void AdLib::writeOPL(byte reg, byte val) { - debugC(6, kDebugSound, "AdLib::writeOPL (%02X, %02X)", reg, val); - OPLWriteReg(_opl, reg, val); + return numSamples; } -void AdLib::setFreqs() { - byte lin; - byte col; - long val = 0; - - // Run through the 11 channels - for (lin = 0; lin < 11; lin ++) { - _notes[lin] = 0; - _notCol[lin] = 0; - _notLin[lin] = 0; - _notOn[lin] = false; - } - - // Run through the 25 lines - for (lin = 0; lin < 25; lin ++) { - // Run through the 12 columns - for (col = 0; col < 12; col ++) { - if (!col) - val = (((0x2710L + lin * 0x18) * 0xCB78 / 0x3D090) << 0xE) * - 9 / 0x1B503; - _freqs[lin][col] = (short)((val + 4) >> 3); - val = val * 0x6A / 0x64; - } - } +bool AdLib::isStereo() const { + return _opl->isStereo(); } -void AdLib::reset() { - _first = true; - OPLResetChip(_opl); - _samplesTillPoll = 0; - - setFreqs(); - // Set frequencies and octave to 0; notes off - for (int i = 0; i < 9; i++) { - writeOPL(0xA0 | i, 0); - writeOPL(0xB0 | i, 0); - writeOPL(0xE0 | _operators[i] , 0); - writeOPL(0xE0 |(_operators[i] + 3), 0); - } - - // Authorize the control of the waveformes - writeOPL(0x01, 0x20); -} - -void AdLib::setKey(byte voice, byte note, bool on, bool spec) { - short freq = 0; - short octa = 0; - - // Instruction AX - if (spec) { - // 0x7F donne 0x16B; - // 7F - // << 7 = 3F80 - // + E000 = 11F80 - // & FFFF = 1F80 - // * 19 = 31380 - // / 2000 = 18 => Ligne 18h, colonne 0 => freq 16B - - // 0x3A donne 0x2AF; - // 3A - // << 7 = 1D00 - // + E000 = FD00 negatif - // * 19 = xB500 - // / 2000 = -2 => Ligne 17h, colonne -1 - - // 2E - // << 7 = 1700 - // + E000 = F700 negatif - // * 19 = x1F00 - // / 2000 = - short a; - short lin; - short col; - - a = (note << 7) + 0xE000; // Volontairement tronque - a = (short)((long)a * 25 / 0x2000); - if (a < 0) { - col = - ((24 - a) / 25); - lin = (-a % 25); - if (lin) - lin = 25 - lin; - } - else { - col = a / 25; - lin = a % 25; - } - - _notCol[voice] = col; - _notLin[voice] = lin; - note = _notes[voice]; - } - // Instructions 0X 9X 8X - else { - note -= 12; - _notOn[voice] = on; - } - - _notes[voice] = note; - note += _notCol[voice]; - note = MIN((byte) 0x5F, note); - octa = note / 12; - freq = _freqs[_notLin[voice]][note - octa * 12]; - - writeOPL(0xA0 + voice, freq & 0xFF); - writeOPL(0xB0 + voice, (freq >> 8) | (octa << 2) | (0x20 * (on ? 1 : 0))); - - if (!freq) - warning("AdLib::setKey Voice %d, note %02X unknown", voice, note); +bool AdLib::endOfData() const { + return !_playing; } -void AdLib::setVolume(byte voice, byte volume) { - debugC(6, kDebugSound, "AdLib::setVolume(%d, %d)", voice, volume); - //assert(voice >= 0 && voice <= 9); - volume = 0x3F - ((volume * 0x7E) + 0x7F) / 0xFE; - writeOPL(0x40 + _volRegNums[voice], volume); +bool AdLib::endOfStream() const { + return false; } -void AdLib::pollMusic() { - if ((_playPos > (_data + _dataSize)) && (_dataSize != 0xFFFFFFFF)) { - _ended = true; - return; - } - - interpret(); -} - -void AdLib::unload() { - _playing = false; - _index = -1; - - if (_data && _freeData) - delete[] _data; - - _freeData = false; +int AdLib::getRate() const { + return _rate; } bool AdLib::isPlaying() const { return _playing; } -bool AdLib::getRepeating() const { - return _repCount != 0; +int32 AdLib::getRepeating() const { + Common::StackLock slock(_mutex); + + return _repCount; } void AdLib::setRepeating(int32 repCount) { + Common::StackLock slock(_mutex); + _repCount = repCount; } -int AdLib::getIndex() const { - return _index; +uint32 AdLib::getSamplesPerSecond() const { + return _rate * (isStereo() ? 2 : 1); } void AdLib::startPlay() { - if (_data) _playing = true; + Common::StackLock slock(_mutex); + + _playing = true; + _ended = false; + _first = true; + + reset(); + rewind(); } void AdLib::stopPlay() { Common::StackLock slock(_mutex); + + end(true); + _playing = false; } -ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer) { -} +void AdLib::writeOPL(byte reg, byte val) { + debugC(6, kDebugSound, "AdLib::writeOPL (%02X, %02X)", reg, val); -ADLPlayer::~ADLPlayer() { + _opl->writeReg(reg, val); } -bool ADLPlayer::load(const char *fileName) { - Common::File song; +void AdLib::reset() { + allOff(); + initOPL(); +} - unload(); - song.open(fileName); - if (!song.isOpen()) - return false; +void AdLib::allOff() { + // NOTE: Explicit casts are necessary, because of 5.16 paragraph 4 of the C++ standard + int numVoices = isPercussionMode() ? (int)kMaxVoiceCount : (int)kMelodyVoiceCount; - _freeData = true; - _dataSize = song.size(); - _data = new byte[_dataSize]; - song.read(_data, _dataSize); - song.close(); + for (int i = 0; i < numVoices; i++) + noteOff(i); +} +void AdLib::end(bool killRepeat) { reset(); - setVoices(); - _playPos = _data + 3 + (_data[1] + 1) * 0x38; - return true; + _ended = true; + + if (killRepeat) + _repCount = 0; } -bool ADLPlayer::load(byte *data, uint32 size, int index) { - unload(); - _repCount = 0; +void AdLib::initOPL() { + _tremoloDepth = false; + _vibratoDepth = false; + _keySplit = false; - _dataSize = size; - _data = data; - _index = index; + _enableWaveSelect = true; - reset(); - setVoices(); - _playPos = _data + 3 + (_data[1] + 1) * 0x38; + for (int i = 0; i < kMaxVoiceCount; i++) { + _voiceNote[i] = 0; + _voiceOn [i] = 0; + } + + _opl->reset(); + + initOperatorVolumes(); + resetFreqs(); + + setPercussionMode(false); + + setTremoloDepth(false); + setVibratoDepth(false); + setKeySplit(false); + + for(int i = 0; i < kMelodyVoiceCount; i++) + voiceOff(i); - return true; + setPitchRange(1); + + enableWaveSelect(true); } -void ADLPlayer::unload() { - AdLib::unload(); +bool AdLib::isPercussionMode() const { + return _percussionMode; } -void ADLPlayer::interpret() { - unsigned char instr; - byte channel; - byte note; - byte volume; - uint16 tempo; +void AdLib::setPercussionMode(bool percussion) { + if (percussion) { + voiceOff(kVoiceBaseDrum); + voiceOff(kVoiceSnareDrum); + voiceOff(kVoiceTom); - // First tempo, we'll ignore it... - if (_first) { - tempo = *(_playPos++); - // Tempo on 2 bytes - if (tempo & 0x80) - tempo = ((tempo & 3) << 8) | *(_playPos++); - } - _first = false; - - // Instruction - instr = *(_playPos++); - channel = instr & 0x0F; - - switch (instr & 0xF0) { - // Note on + Volume - case 0x00: - note = *(_playPos++); - _pollNotes[channel] = note; - setVolume(channel, *(_playPos++)); - setKey(channel, note, true, false); - break; - // Note on - case 0x90: - note = *(_playPos++); - _pollNotes[channel] = note; - setKey(channel, note, true, false); - break; - // Last note off - case 0x80: - note = _pollNotes[channel]; - setKey(channel, note, false, false); - break; - // Frequency on/off - case 0xA0: - note = *(_playPos++); - setKey(channel, note, _notOn[channel], true); - break; - // Volume - case 0xB0: - volume = *(_playPos++); - setVolume(channel, volume); - break; - // Program change - case 0xC0: - setVoice(channel, *(_playPos++), false); - break; - // Special - case 0xF0: - switch (instr & 0x0F) { - case 0xF: // End instruction - _ended = true; - _samplesTillPoll = 0; - return; - default: - warning("ADLPlayer: Unknown special command %X, stopping playback", - instr & 0x0F); - _repCount = 0; - _ended = true; - break; - } - break; - default: - warning("ADLPlayer: Unknown command %X, stopping playback", - instr & 0xF0); - _repCount = 0; - _ended = true; - break; + /* set the frequency for the last 4 percussion voices: */ + setFreq(kVoiceTom, kPitchTom, 0); + setFreq(kVoiceSnareDrum, kPitchSnareDrum, 0); } - // Temporization - tempo = *(_playPos++); - // End tempo - if (tempo == 0xFF) { - _ended = true; - return; - } - // Tempo on 2 bytes - if (tempo & 0x80) - tempo = ((tempo & 3) << 8) | *(_playPos++); - if (!tempo) - tempo ++; + _percussionMode = percussion; + _percussionBits = 0; - _samplesTillPoll = tempo * (_rate / 1000); + initOperatorParams(); + writeTremoloVibratoDepthPercMode(); } -void ADLPlayer::reset() { - AdLib::reset(); +void AdLib::enableWaveSelect(bool enable) { + _enableWaveSelect = enable; + + for (int i = 0; i < kOperatorCount; i++) + writeOPL(0xE0 + kOperatorOffset[i], 0); + + writeOPL(0x011, _enableWaveSelect ? 0x20 : 0); } -void ADLPlayer::rewind() { - _playPos = _data + 3 + (_data[1] + 1) * 0x38; +void AdLib::setPitchRange(uint8 range) { + _pitchRange = CLIP<uint8>(range, 0, 12); + _pitchRangeStep = _pitchRange * kPitchStepCount; } -void ADLPlayer::setVoices() { - // Definitions of the 9 instruments - for (int i = 0; i < 9; i++) - setVoice(i, i, true); +void AdLib::setTremoloDepth(bool tremoloDepth) { + _tremoloDepth = tremoloDepth; + + writeTremoloVibratoDepthPercMode(); } -void ADLPlayer::setVoice(byte voice, byte instr, bool set) { - uint16 strct[27]; - byte channel; - byte *dataPtr; +void AdLib::setVibratoDepth(bool vibratoDepth) { + _vibratoDepth = vibratoDepth; - // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 - // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 - for (int i = 0; i < 2; i++) { - dataPtr = _data + 3 + instr * 0x38 + i * 0x1A; - for (int j = 0; j < 27; j++) { - strct[j] = READ_LE_UINT16(dataPtr); - dataPtr += 2; - } - channel = _operators[voice] + i * 3; - writeOPL(0xBD, 0x00); - writeOPL(0x08, 0x00); - writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); - if (!i) - writeOPL(0xC0 | voice, - ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); - writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); - writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); - writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | - ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | - ((strct[11] & 1) << 4) | (strct[1] & 0xF)); - if (!i) - writeOPL(0xE0 | channel, (strct[26] & 3)); - else - writeOPL(0xE0 | channel, (strct[14] & 3)); - if (i && set) - writeOPL(0x40 | channel, 0); + writeTremoloVibratoDepthPercMode(); +} + +void AdLib::setKeySplit(bool keySplit) { + _keySplit = keySplit; + + writeKeySplit(); +} + +void AdLib::setVoiceTimbre(uint8 voice, const uint16 *params) { + const uint16 *params0 = params; + const uint16 *params1 = params + kParamCount - 1; + const uint16 *waves = params + 2 * (kParamCount - 1); + + const int voicePerc = voice - kVoiceBaseDrum; + + if (!isPercussionMode() || (voice < kVoiceBaseDrum)) { + setOperatorParams(kVoiceMelodyOperator[0][voice], params0, waves[0]); + setOperatorParams(kVoiceMelodyOperator[1][voice], params1, waves[1]); + } else if (voice == kVoiceBaseDrum) { + setOperatorParams(kVoicePercussionOperator[0][voicePerc], params0, waves[0]); + setOperatorParams(kVoicePercussionOperator[1][voicePerc], params1, waves[1]); + } else { + setOperatorParams(kVoicePercussionOperator[0][voicePerc], params0, waves[0]); } } +void AdLib::setVoiceVolume(uint8 voice, uint8 volume) { + int oper; + + const int voicePerc = voice - kVoiceBaseDrum; -MDYPlayer::MDYPlayer(Audio::Mixer &mixer) : AdLib(mixer) { - init(); + if (!isPercussionMode() || (voice < kVoiceBaseDrum)) + oper = kVoiceMelodyOperator[1][ voice]; + else + oper = kVoicePercussionOperator[voice == kVoiceBaseDrum ? 1 : 0][voicePerc]; + + _operatorVolume[oper] = MIN<uint8>(volume, kMaxVolume); + writeKeyScaleLevelVolume(oper); } -MDYPlayer::~MDYPlayer() { +void AdLib::bendVoicePitch(uint8 voice, uint16 pitchBend) { + if (isPercussionMode() && (voice > kVoiceBaseDrum)) + return; + + changePitch(voice, MIN<uint16>(pitchBend, kMaxPitch)); + setFreq(voice, _voiceNote[voice], _voiceOn[voice]); } -void MDYPlayer::init() { - _soundMode = 0; +void AdLib::noteOn(uint8 voice, uint8 note) { + note = MAX<int>(0, note - (kStandardMidC - kOPLMidC)); + + if (isPercussionMode() && (voice >= kVoiceBaseDrum)) { + + if (voice == kVoiceBaseDrum) { + setFreq(kVoiceBaseDrum , note , false); + } else if (voice == kVoiceTom) { + setFreq(kVoiceTom , note , false); + setFreq(kVoiceSnareDrum, note + kPitchTomToSnare, false); + } + + _percussionBits |= kPercussionMasks[voice - kVoiceBaseDrum]; + writeTremoloVibratoDepthPercMode(); - _timbres = 0; - _tbrCount = 0; - _tbrStart = 0; - _timbresSize = 0; + } else + setFreq(voice, note, true); } -bool MDYPlayer::loadMDY(Common::SeekableReadStream &stream) { - unloadMDY(); +void AdLib::noteOff(uint8 voice) { + if (isPercussionMode() && (voice >= kVoiceBaseDrum)) { + _percussionBits &= ~kPercussionMasks[voice - kVoiceBaseDrum]; + writeTremoloVibratoDepthPercMode(); + } else + setFreq(voice, _voiceNote[voice], false); +} - _freeData = true; +void AdLib::writeKeyScaleLevelVolume(uint8 oper) { + uint16 volume = 0; - byte mdyHeader[70]; - stream.read(mdyHeader, 70); + volume = (63 - (_operatorParams[oper][kParamLevel] & 0x3F)) * _operatorVolume[oper]; + volume = 63 - ((2 * volume + kMaxVolume) / (2 * kMaxVolume)); - _tickBeat = mdyHeader[36]; - _beatMeasure = mdyHeader[37]; - _totalTick = mdyHeader[38] + (mdyHeader[39] << 8) + (mdyHeader[40] << 16) + (mdyHeader[41] << 24); - _dataSize = mdyHeader[42] + (mdyHeader[43] << 8) + (mdyHeader[44] << 16) + (mdyHeader[45] << 24); - _nrCommand = mdyHeader[46] + (mdyHeader[47] << 8) + (mdyHeader[48] << 16) + (mdyHeader[49] << 24); -// _soundMode is either 0 (melodic) or 1 (percussive) - _soundMode = mdyHeader[58]; - assert((_soundMode == 0) || (_soundMode == 1)); + uint8 keyScale = _operatorParams[oper][kParamKeyScaleLevel] << 6; - _pitchBendRangeStep = 25*mdyHeader[59]; - _basicTempo = mdyHeader[60] + (mdyHeader[61] << 8); + writeOPL(0x40 + kOperatorOffset[oper], volume | keyScale); +} - if (_pitchBendRangeStep < 25) - _pitchBendRangeStep = 25; - else if (_pitchBendRangeStep > 300) - _pitchBendRangeStep = 300; +void AdLib::writeKeySplit() { + writeOPL(0x08, _keySplit ? 0x40 : 0); +} - _data = new byte[_dataSize]; - stream.read(_data, _dataSize); +void AdLib::writeFeedbackFM(uint8 oper) { + if (kOperatorType[oper] == 1) + return; - reset(); - _playPos = _data; + uint8 value = 0; - return true; + value |= _operatorParams[oper][kParamFeedback] << 1; + value |= _operatorParams[oper][kParamFM] ? 0 : 1; + + writeOPL(0xC0 + kOperatorVoice[oper], value); } -bool MDYPlayer::loadMDY(const char *fileName) { - Common::File song; +void AdLib::writeAttackDecay(uint8 oper) { + uint8 value = 0; + + value |= _operatorParams[oper][kParamAttack] << 4; + value |= _operatorParams[oper][kParamDecay] & 0x0F; - song.open(fileName); - if (!song.isOpen()) - return false; + writeOPL(0x60 + kOperatorOffset[oper], value); +} - bool loaded = loadMDY(song); +void AdLib::writeSustainRelease(uint8 oper) { + uint8 value = 0; - song.close(); + value |= _operatorParams[oper][kParamSustain] << 4; + value |= _operatorParams[oper][kParamRelease] & 0x0F; - return loaded; + writeOPL(0x80 + kOperatorOffset[oper], value); } -bool MDYPlayer::loadTBR(Common::SeekableReadStream &stream) { - unloadTBR(); +void AdLib::writeTremoloVibratoSustainingKeyScaleRateFreqMulti(uint8 oper) { + uint8 value = 0; - _timbresSize = stream.size(); + value |= _operatorParams[oper][kParamAM] ? 0x80 : 0; + value |= _operatorParams[oper][kParamVib] ? 0x40 : 0; + value |= _operatorParams[oper][kParamSustaining] ? 0x20 : 0; + value |= _operatorParams[oper][kParamKeyScaleRate] ? 0x10 : 0; + value |= _operatorParams[oper][kParamFreqMulti] & 0x0F; - _timbres = new byte[_timbresSize]; - stream.read(_timbres, _timbresSize); + writeOPL(0x20 + kOperatorOffset[oper], value); +} - reset(); - setVoices(); +void AdLib::writeTremoloVibratoDepthPercMode() { + uint8 value = 0; + + value |= _tremoloDepth ? 0x80 : 0; + value |= _vibratoDepth ? 0x40 : 0; + value |= isPercussionMode() ? 0x20 : 0; + value |= _percussionBits; - return true; + writeOPL(0xBD, value); } -bool MDYPlayer::loadTBR(const char *fileName) { - Common::File timbres; +void AdLib::writeWaveSelect(uint8 oper) { + uint8 wave = 0; + if (_enableWaveSelect) + wave = _operatorParams[oper][kParamWaveSelect] & 0x03; - timbres.open(fileName); - if (!timbres.isOpen()) - return false; + writeOPL(0xE0 + kOperatorOffset[ oper], wave); +} - bool loaded = loadTBR(timbres); +void AdLib::writeAllParams(uint8 oper) { + writeTremoloVibratoDepthPercMode(); + writeKeySplit(); + writeKeyScaleLevelVolume(oper); + writeFeedbackFM(oper); + writeAttackDecay(oper); + writeSustainRelease(oper); + writeTremoloVibratoSustainingKeyScaleRateFreqMulti(oper); + writeWaveSelect(oper); +} - timbres.close(); +void AdLib::initOperatorParams() { + for (int i = 0; i < kOperatorCount; i++) + setOperatorParams(i, kPianoParams[kOperatorType[i]], kPianoParams[kOperatorType[i]][kParamCount - 1]); - return loaded; + if (isPercussionMode()) { + setOperatorParams(12, kBaseDrumParams [0], kBaseDrumParams [0][kParamCount - 1]); + setOperatorParams(15, kBaseDrumParams [1], kBaseDrumParams [1][kParamCount - 1]); + setOperatorParams(16, kSnareDrumParams , kSnareDrumParams [kParamCount - 1]); + setOperatorParams(14, kTomParams , kTomParams [kParamCount - 1]); + setOperatorParams(17, kCymbalParams , kCymbalParams [kParamCount - 1]); + setOperatorParams(13, kHihatParams , kHihatParams [kParamCount - 1]); + } } -void MDYPlayer::unload() { - unloadTBR(); - unloadMDY(); +void AdLib::initOperatorVolumes() { + for(int i = 0; i < kOperatorCount; i++) + _operatorVolume[i] = kMaxVolume; } -void MDYPlayer::unloadMDY() { - AdLib::unload(); +void AdLib::setOperatorParams(uint8 oper, const uint16 *params, uint8 wave) { + byte *operParams = _operatorParams[oper]; + + for (int i = 0; i < (kParamCount - 1); i++) + operParams[i] = params[i]; + + operParams[kParamCount - 1] = wave & 0x03; + + writeAllParams(oper); +} + +void AdLib::voiceOff(uint8 voice) { + writeOPL(0xA0 + voice, 0); + writeOPL(0xB0 + voice, 0); } -void MDYPlayer::unloadTBR() { - delete[] _timbres; +int32 AdLib::calcFreq(int32 deltaDemiToneNum, int32 deltaDemiToneDenom) { + int32 freq = 0; - _timbres = 0; - _timbresSize = 0; + freq = ((deltaDemiToneDenom * 100) + 6 * deltaDemiToneNum) * 52088; + freq /= deltaDemiToneDenom * 2500; + + return (freq * 147456) / 111875; } -void MDYPlayer::interpret() { - unsigned char instr; - byte channel; - byte note; - byte volume; - uint8 tempoMult, tempoFrac; - uint8 ctrlByte1, ctrlByte2; - uint8 timbre; +void AdLib::setFreqs(uint16 *freqs, int32 num, int32 denom) { + int32 val = calcFreq(num, denom); -// TODO : Verify the loop for percussive mode (11 ?) - if (_first) { - for (int i = 0; i < 9; i ++) - setVolume(i, 0); + *freqs++ = (4 + val) >> 3; -// TODO : Set pitch range + for (int i = 1; i < kHalfToneCount; i++) { + val = (val * 106) / 100; - _tempo = _basicTempo; - _wait = *(_playPos++); - _first = false; + *freqs++ = (4 + val) >> 3; } - do { - instr = *_playPos; - debugC(6, kDebugSound, "MDYPlayer::interpret instr 0x%X", instr); - switch (instr) { - case 0xF8: - _wait = *(_playPos++); - break; - case 0xFC: - _ended = true; - _samplesTillPoll = 0; - return; - case 0xF0: - _playPos++; - ctrlByte1 = *(_playPos++); - ctrlByte2 = *(_playPos++); - debugC(6, kDebugSound, "MDYPlayer::interpret ctrlBytes 0x%X 0x%X", ctrlByte1, ctrlByte2); - if (ctrlByte1 != 0x7F || ctrlByte2 != 0) { - _playPos -= 2; - while (*(_playPos++) != 0xF7) - ; - } else { - tempoMult = *(_playPos++); - tempoFrac = *(_playPos++); - _tempo = _basicTempo * tempoMult + (unsigned)(((long)_basicTempo * tempoFrac) >> 7); - _playPos++; - } - _wait = *(_playPos++); - break; - default: - if (instr >= 0x80) { - _playPos++; - } - channel = (int)(instr & 0x0f); - - switch (instr & 0xf0) { - case 0x90: - note = *(_playPos++); - volume = *(_playPos++); - _pollNotes[channel] = note; - setVolume(channel, volume); - setKey(channel, note, true, false); - break; - case 0x80: - _playPos += 2; - note = _pollNotes[channel]; - setKey(channel, note, false, false); - break; - case 0xA0: - setVolume(channel, *(_playPos++)); - break; - case 0xC0: - timbre = *(_playPos++); - setVoice(channel, timbre, false); - break; - case 0xE0: - warning("MDYPlayer: Pitch bend not yet implemented"); +} - note = *(_playPos)++; - note += (unsigned)(*(_playPos++)) << 7; +void AdLib::initFreqs() { + const int numStep = 100 / kPitchStepCount; - setKey(channel, note, _notOn[channel], true); + for (int i = 0; i < kPitchStepCount; i++) + setFreqs(_freqs[i], i * numStep, 100); - break; - case 0xB0: - _playPos += 2; - break; - case 0xD0: - _playPos++; - break; - default: - warning("MDYPlayer: Bad MIDI instr byte: 0%X", instr); - while ((*_playPos) < 0x80) - _playPos++; - if (*_playPos != 0xF8) - _playPos--; - break; - } //switch instr & 0xF0 - _wait = *(_playPos++); - break; - } //switch instr - } while (_wait == 0); - - if (_wait == 0xF8) { - _wait = 0xF0; - if (*_playPos != 0xF8) - _wait += *(_playPos++) & 0x0F; + resetFreqs(); +} + +void AdLib::resetFreqs() { + for (int i = 0; i < kMaxVoiceCount; i++) { + _freqPtr [i] = _freqs[0]; + _halfToneOffset[i] = 0; } -// _playPos++; - _samplesTillPoll = _wait * (_rate / 1000); } -void MDYPlayer::reset() { - AdLib::reset(); +void AdLib::changePitch(uint8 voice, uint16 pitchBend) { + + int full = 0; + int frac = 0; + int amount = ((pitchBend - kMidPitch) * _pitchRangeStep) / kMidPitch; + + if (amount >= 0) { + // Bend up + + full = amount / kPitchStepCount; + frac = amount % kPitchStepCount; -// _soundMode 1 : Percussive mode. - if (_soundMode == 1) { - writeOPL(0xA6, 0); - writeOPL(0xB6, 0); - writeOPL(0xA7, 0); - writeOPL(0xB7, 0); - writeOPL(0xA8, 0); - writeOPL(0xB8, 0); + } else { + // Bend down + + amount = kPitchStepCount - 1 - amount; + + full = -(amount / kPitchStepCount); + frac = (amount - kPitchStepCount + 1) % kPitchStepCount; + if (frac) + frac = kPitchStepCount - frac; -// TODO set the correct frequency for the last 4 percussive voices } + + _halfToneOffset[voice] = full; + _freqPtr [voice] = _freqs[frac]; } -void MDYPlayer::rewind() { - _playPos = _data; -} - -void MDYPlayer::setVoices() { - byte *timbrePtr; - - timbrePtr = _timbres; - debugC(6, kDebugSound, "MDYPlayer::setVoices TBR version: %X.%X", timbrePtr[0], timbrePtr[1]); - timbrePtr += 2; - - _tbrCount = READ_LE_UINT16(timbrePtr); - debugC(6, kDebugSound, "MDYPlayer::setVoices Timbres counter: %d", _tbrCount); - timbrePtr += 2; - _tbrStart = READ_LE_UINT16(timbrePtr); - - timbrePtr += 2; - for (int i = 0; i < _tbrCount; i++) - setVoice(i, i, true); -} - -void MDYPlayer::setVoice(byte voice, byte instr, bool set) { -// uint16 strct[27]; - uint8 strct[27]; - byte channel; - byte *timbrePtr; - char timbreName[10]; - - timbreName[9] = '\0'; - for (int j = 0; j < 9; j++) - timbreName[j] = _timbres[6 + j + (instr * 9)]; - debugC(6, kDebugSound, "MDYPlayer::setVoice Loading timbre %s", timbreName); - - // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 - // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 - for (int i = 0; i < 2; i++) { - timbrePtr = _timbres + _tbrStart + instr * 0x38 + i * 0x1A; - for (int j = 0; j < 27; j++) { - if (timbrePtr >= (_timbres + _timbresSize)) { - warning("MDYPlayer: Instrument %d out of range (%d, %d)", instr, - (uint32) (timbrePtr - _timbres), _timbresSize); - strct[j] = 0; - } else - //strct[j] = READ_LE_UINT16(timbrePtr); - strct[j] = timbrePtr[0]; - //timbrePtr += 2; - timbrePtr++; - } - channel = _operators[voice] + i * 3; - writeOPL(0xBD, 0x00); - writeOPL(0x08, 0x00); - writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); - if (!i) - writeOPL(0xC0 | voice, - ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); - writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); - writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); - writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | - ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | - ((strct[11] & 1) << 4) | (strct[1] & 0xF)); - if (!i) - writeOPL(0xE0 | channel, (strct[26] & 3)); - else { - writeOPL(0xE0 | channel, (strct[14] & 3)); - writeOPL(0x40 | channel, 0); - } - } +void AdLib::setFreq(uint8 voice, uint16 note, bool on) { + _voiceOn [voice] = on; + _voiceNote[voice] = note; + + note = CLIP<int>(note + _halfToneOffset[voice], 0, kNoteCount - 1); + + uint16 freq = _freqPtr[voice][note % kHalfToneCount]; + + uint8 value = 0; + value |= on ? 0x20 : 0; + value |= ((note / kHalfToneCount) << 2) | ((freq >> 8) & 0x03); + + writeOPL(0xA0 + voice, freq); + writeOPL(0xB0 + voice, value); } } // End of namespace Gob diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h index 934e9966eb..bd1778d2ed 100644 --- a/engines/gob/sound/adlib.h +++ b/engines/gob/sound/adlib.h @@ -24,148 +24,282 @@ #define GOB_SOUND_ADLIB_H #include "common/mutex.h" + #include "audio/audiostream.h" #include "audio/mixer.h" -#include "audio/fmopl.h" -namespace Gob { +namespace OPL { + class OPL; +} -class GobEngine; +namespace Gob { +/** Base class for a player of an AdLib music format. */ class AdLib : public Audio::AudioStream { public: AdLib(Audio::Mixer &mixer); virtual ~AdLib(); - bool isPlaying() const; - int getIndex() const; - bool getRepeating() const; + bool isPlaying() const; ///< Are we currently playing? + int32 getRepeating() const; ///< Return number of times left to loop. + /** Set the loop counter. + * + * @param repCount Number of times to loop (i.e. number of additional + * paythroughs to the first one, not overall). + * A negative value means infinite looping. + */ void setRepeating(int32 repCount); void startPlay(); void stopPlay(); - virtual void unload(); - // AudioStream API int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return !_playing; } - bool endOfStream() const { return false; } - int getRate() const { return _rate; } + bool isStereo() const; + bool endOfData() const; + bool endOfStream() const; + int getRate() const; protected: - static const unsigned char _operators[]; - static const unsigned char _volRegNums []; + enum kVoice { + kVoiceMelody0 = 0, + kVoiceMelody1 = 1, + kVoiceMelody2 = 2, + kVoiceMelody3 = 3, + kVoiceMelody4 = 4, + kVoiceMelody5 = 5, + kVoiceMelody6 = 6, // Only available in melody mode. + kVoiceMelody7 = 7, // Only available in melody mode. + kVoiceMelody8 = 8, // Only available in melody mode. + kVoiceBaseDrum = 6, // Only available in percussion mode. + kVoiceSnareDrum = 7, // Only available in percussion mode. + kVoiceTom = 8, // Only available in percussion mode. + kVoiceCymbal = 9, // Only available in percussion mode. + kVoiceHihat = 10 // Only available in percussion mode. + }; + + /** Operator parameters. */ + enum kParam { + kParamKeyScaleLevel = 0, + kParamFreqMulti = 1, + kParamFeedback = 2, + kParamAttack = 3, + kParamSustain = 4, + kParamSustaining = 5, + kParamDecay = 6, + kParamRelease = 7, + kParamLevel = 8, + kParamAM = 9, + kParamVib = 10, + kParamKeyScaleRate = 11, + kParamFM = 12, + kParamWaveSelect = 13 + }; + + static const int kOperatorCount = 18; ///< Number of operators. + static const int kParamCount = 14; ///< Number of operator parameters. + static const int kPitchStepCount = 25; ///< Number of pitch bend steps in a half tone. + static const int kOctaveCount = 8; ///< Number of octaves we can play. + static const int kHalfToneCount = 12; ///< Number of half tones in an octave. + + static const int kOperatorsPerVoice = 2; ///< Number of operators per voice. + + static const int kMelodyVoiceCount = 9; ///< Number of melody voices. + static const int kPercussionVoiceCount = 5; ///< Number of percussion voices. + static const int kMaxVoiceCount = 11; ///< Max number of voices. + + /** Number of notes we can play. */ + static const int kNoteCount = kHalfToneCount * kOctaveCount; + + static const int kMaxVolume = 0x007F; + static const int kMaxPitch = 0x3FFF; + static const int kMidPitch = 0x2000; + + static const int kStandardMidC = 60; ///< A mid C in standard MIDI. + static const int kOPLMidC = 48; ///< A mid C for the OPL. + + + /** Return the number of samples per second. */ + uint32 getSamplesPerSecond() const; + + /** Write a value into an OPL register. */ + void writeOPL(byte reg, byte val); + + /** Signal that the playback ended. + * + * @param killRepeat Explicitly request that the song is not to be looped. + */ + void end(bool killRepeat = false); + + /** The callback function that's called for polling more AdLib commands. + * + * @param first Is this the first poll since the start of the song? + * @return The number of samples until the next poll. + */ + virtual uint32 pollMusic(bool first) = 0; + + /** Rewind the song. */ + virtual void rewind() = 0; + + /** Return whether we're in percussion mode. */ + bool isPercussionMode() const; + + /** Set percussion or melody mode. */ + void setPercussionMode(bool percussion); + + /** Enable/Disable the wave select operator parameters. + * + * When disabled, all operators use the sine wave, regardless of the parameter. + */ + void enableWaveSelect(bool enable); + + /** Change the pitch bend range. + * + * @param range The range in half tones from 1 to 12 inclusive. + * See bendVoicePitch() for how this works in practice. + */ + void setPitchRange(uint8 range); + + /** Set the tremolo (amplitude vibrato) depth. + * + * @param tremoloDepth false: 1.0dB, true: 4.8dB. + */ + void setTremoloDepth(bool tremoloDepth); + + /** Set the frequency vibrato depth. + * + * @param vibratoDepth false: 7 cent, true: 14 cent. 1 cent = 1/100 half tone. + */ + void setVibratoDepth(bool vibratoDepth); + + /** Set the keyboard split point. */ + void setKeySplit(bool keySplit); + + /** Set the timbre of a voice. + * + * Layout of the operator parameters is as follows: + * - First 13 parameter for the first operator + * - First 13 parameter for the second operator + * - 14th parameter (wave select) for the first operator + * - 14th parameter (wave select) for the second operator + */ + void setVoiceTimbre(uint8 voice, const uint16 *params); + + /** Set a voice's volume. */ + void setVoiceVolume(uint8 voice, uint8 volume); + + /** Bend a voice's pitch. + * + * The pitchBend parameter is a value between 0 (full down) and kMaxPitch (full up). + * The actual frequency depends on the pitch range set previously by setPitchRange(), + * with full down being -range half tones and full up range half tones. + */ + void bendVoicePitch(uint8 voice, uint16 pitchBend); + + /** Switch a voice on. + * + * Plays one of the kNoteCount notes. However, the valid range of a note is between + * 0 and 127, of which only 12 to 107 are audible. + */ + void noteOn(uint8 voice, uint8 note); + + /** Switch a voice off. */ + void noteOff(uint8 voice); + +private: + static const uint8 kOperatorType [kOperatorCount]; + static const uint8 kOperatorOffset[kOperatorCount]; + static const uint8 kOperatorVoice [kOperatorCount]; + + static const uint8 kVoiceMelodyOperator [kOperatorsPerVoice][kMelodyVoiceCount]; + static const uint8 kVoicePercussionOperator[kOperatorsPerVoice][kPercussionVoiceCount]; + + static const byte kPercussionMasks[kPercussionVoiceCount]; + + static const uint16 kPianoParams [kOperatorsPerVoice][kParamCount]; + static const uint16 kBaseDrumParams [kOperatorsPerVoice][kParamCount]; + + static const uint16 kSnareDrumParams[kParamCount]; + static const uint16 kTomParams [kParamCount]; + static const uint16 kCymbalParams [kParamCount]; + static const uint16 kHihatParams [kParamCount]; + Audio::Mixer *_mixer; Audio::SoundHandle _handle; - FM_OPL *_opl; + OPL::OPL *_opl; Common::Mutex _mutex; uint32 _rate; - byte *_data; - byte *_playPos; - uint32 _dataSize; - - short _freqs[25][12]; - byte _notes[11]; - byte _notCol[11]; - byte _notLin[11]; - bool _notOn[11]; - byte _pollNotes[16]; + uint32 _toPoll; - int _samplesTillPoll; int32 _repCount; - bool _playing; bool _first; + bool _playing; bool _ended; - bool _freeData; + bool _tremoloDepth; + bool _vibratoDepth; + bool _keySplit; - int _index; + bool _enableWaveSelect; - unsigned char _wait; - uint8 _tickBeat; - uint8 _beatMeasure; - uint32 _totalTick; - uint32 _nrCommand; - uint16 _pitchBendRangeStep; - uint16 _basicTempo, _tempo; + bool _percussionMode; + byte _percussionBits; - void writeOPL(byte reg, byte val); - void setFreqs(); - void setKey(byte voice, byte note, bool on, bool spec); - void setVolume(byte voice, byte volume); - void pollMusic(); + uint8 _pitchRange; + uint16 _pitchRangeStep; - virtual void interpret() = 0; + uint8 _voiceNote[kMaxVoiceCount]; // Last note of each voice + uint8 _voiceOn [kMaxVoiceCount]; // Whether each voice is currently on - virtual void reset(); - virtual void rewind() = 0; - virtual void setVoices() = 0; + uint8 _operatorVolume[kOperatorCount]; // Volume of each operator -private: - void init(); -}; + byte _operatorParams[kOperatorCount][kParamCount]; // All operator parameters -class ADLPlayer : public AdLib { -public: - ADLPlayer(Audio::Mixer &mixer); - ~ADLPlayer(); + uint16 _freqs[kPitchStepCount][kHalfToneCount]; + uint16 *_freqPtr[kMaxVoiceCount]; - bool load(const char *fileName); - bool load(byte *data, uint32 size, int index = -1); + int _halfToneOffset[kMaxVoiceCount]; - void unload(); -protected: - void interpret(); + void createOPL(); + void initOPL(); void reset(); - void rewind(); + void allOff(); - void setVoices(); - void setVoice(byte voice, byte instr, bool set); -}; + // Write global parameters into the OPL + void writeTremoloVibratoDepthPercMode(); + void writeKeySplit(); -class MDYPlayer : public AdLib { -public: - MDYPlayer(Audio::Mixer &mixer); - ~MDYPlayer(); - - bool loadMDY(const char *fileName); - bool loadMDY(Common::SeekableReadStream &stream); - bool loadTBR(const char *fileName); - bool loadTBR(Common::SeekableReadStream &stream); - - void unload(); - -protected: - byte _soundMode; - - byte *_timbres; - uint16 _tbrCount; - uint16 _tbrStart; - uint32 _timbresSize; + // Write operator parameters into the OPL + void writeWaveSelect(uint8 oper); + void writeTremoloVibratoSustainingKeyScaleRateFreqMulti(uint8 oper); + void writeSustainRelease(uint8 oper); + void writeAttackDecay(uint8 oper); + void writeFeedbackFM(uint8 oper); + void writeKeyScaleLevelVolume(uint8 oper); + void writeAllParams(uint8 oper); - void interpret(); + void initOperatorParams(); + void initOperatorVolumes(); + void setOperatorParams(uint8 oper, const uint16 *params, uint8 wave); - void reset(); - void rewind(); + void voiceOff(uint8 voice); - void setVoices(); - void setVoice(byte voice, byte instr, bool set); + void initFreqs(); + void setFreqs(uint16 *freqs, int32 num, int32 denom); + int32 calcFreq(int32 deltaDemiToneNum, int32 deltaDemiToneDenom); + void resetFreqs(); - void unloadTBR(); - void unloadMDY(); + void changePitch(uint8 voice, uint16 pitchBend); -private: - void init(); + void setFreq(uint8 voice, uint16 note, bool on); }; } // End of namespace Gob diff --git a/engines/gob/sound/adlplayer.cpp b/engines/gob/sound/adlplayer.cpp new file mode 100644 index 0000000000..ee23191c0d --- /dev/null +++ b/engines/gob/sound/adlplayer.cpp @@ -0,0 +1,257 @@ +/* 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 "common/stream.h" +#include "common/memstream.h" +#include "common/textconsole.h" + +#include "gob/sound/adlplayer.h" + +namespace Gob { + +ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer), + _songData(0), _songDataSize(0), _playPos(0) { + +} + +ADLPlayer::~ADLPlayer() { + unload(); +} + +void ADLPlayer::unload() { + stopPlay(); + + _timbres.clear(); + + delete[] _songData; + + _songData = 0; + _songDataSize = 0; + + _playPos = 0; +} + +uint32 ADLPlayer::pollMusic(bool first) { + if (_timbres.empty() || !_songData || !_playPos || (_playPos >= (_songData + _songDataSize))) { + end(); + return 0; + } + + // We'll ignore the first delay + if (first) + _playPos += (*_playPos & 0x80) ? 2 : 1; + + byte cmd = *_playPos++; + + // Song end marker + if (cmd == 0xFF) { + end(); + return 0; + } + + // Set the instrument that should be modified + if (cmd == 0xFE) + _modifyInstrument = *_playPos++; + + if (cmd >= 0xD0) { + // Modify an instrument + + if (_modifyInstrument == 0xFF) + warning("ADLPlayer: No instrument to modify"); + else if (_modifyInstrument >= _timbres.size()) + warning("ADLPlayer: Can't modify invalid instrument %d (%d)", _modifyInstrument, _timbres.size()); + else + _timbres[_modifyInstrument].params[_playPos[0]] = _playPos[1]; + + _playPos += 2; + + // If we currently have that instrument loaded, reload it + for (int i = 0; i < kMaxVoiceCount; i++) + if (_currentInstruments[i] == _modifyInstrument) + setInstrument(i, _modifyInstrument); + } else { + // Voice command + + uint8 voice = cmd & 0x0F; + uint8 note, volume; + + switch (cmd & 0xF0) { + case 0x00: // Note on with volume + note = *_playPos++; + volume = *_playPos++; + + setVoiceVolume(voice, volume); + noteOn(voice, note); + break; + + case 0xA0: // Pitch bend + bendVoicePitch(voice, ((uint16)*_playPos++) << 7); + break; + + case 0xB0: // Set volume + setVoiceVolume(voice, *_playPos++); + break; + + case 0xC0: // Set instrument + setInstrument(voice, *_playPos++); + break; + + case 0x90: // Note on + noteOn(voice, *_playPos++); + break; + + case 0x80: // Note off + noteOff(voice); + break; + + default: + warning("ADLPlayer: Unsupported command: 0x%02X. Stopping playback.", cmd); + end(true); + return 0; + } + } + + uint16 delay = *_playPos++; + + if (delay & 0x80) + delay = ((delay & 3) << 8) | *_playPos++; + + return getSampleDelay(delay); +} + +uint32 ADLPlayer::getSampleDelay(uint16 delay) const { + if (delay == 0) + return 0; + + return ((uint32)delay * getSamplesPerSecond()) / 1000; +} + +void ADLPlayer::rewind() { + // Reset song data + _playPos = _songData; + + // Set melody/percussion mode + setPercussionMode(_soundMode != 0); + + // Reset instruments + for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) + memcpy(t->params, t->startParams, kOperatorsPerVoice * kParamCount * sizeof(uint16)); + + for (int i = 0; i < kMaxVoiceCount; i++) + _currentInstruments[i] = 0; + + // Reset voices + int numVoice = MIN<int>(_timbres.size(), _soundMode ? (int)kMaxVoiceCount : (int)kMelodyVoiceCount); + for (int i = 0; i < numVoice; i++) { + setInstrument(i, _currentInstruments[i]); + setVoiceVolume(i, kMaxVolume); + } + + _modifyInstrument = 0xFF; +} + +bool ADLPlayer::load(Common::SeekableReadStream &adl) { + unload(); + + int timbreCount; + if (!readHeader(adl, timbreCount)) { + unload(); + return false; + } + + if (!readTimbres(adl, timbreCount) || !readSongData(adl) || adl.err()) { + unload(); + return false; + } + + rewind(); + + return true; +} + +bool ADLPlayer::readHeader(Common::SeekableReadStream &adl, int &timbreCount) { + // Sanity check + if (adl.size() < 60) { + warning("ADLPlayer::readHeader(): File too small (%d)", adl.size()); + return false; + } + + _soundMode = adl.readByte(); + timbreCount = adl.readByte() + 1; + + adl.skip(1); + + return true; +} + +bool ADLPlayer::readTimbres(Common::SeekableReadStream &adl, int timbreCount) { + _timbres.resize(timbreCount); + for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) { + for (int i = 0; i < (kOperatorsPerVoice * kParamCount); i++) + t->startParams[i] = adl.readUint16LE(); + } + + if (adl.err()) { + warning("ADLPlayer::readTimbres(): Read failed"); + return false; + } + + return true; +} + +bool ADLPlayer::readSongData(Common::SeekableReadStream &adl) { + _songDataSize = adl.size() - adl.pos(); + _songData = new byte[_songDataSize]; + + if (adl.read(_songData, _songDataSize) != _songDataSize) { + warning("ADLPlayer::readSongData(): Read failed"); + return false; + } + + return true; +} + +bool ADLPlayer::load(const byte *data, uint32 dataSize, int index) { + unload(); + + Common::MemoryReadStream stream(data, dataSize); + if (!load(stream)) + return false; + + _index = index; + return true; +} + +void ADLPlayer::setInstrument(int voice, int instrument) { + if ((voice >= kMaxVoiceCount) || ((uint)instrument >= _timbres.size())) + return; + + _currentInstruments[voice] = instrument; + + setVoiceTimbre(voice, _timbres[instrument].params); +} + +int ADLPlayer::getIndex() const { + return _index; +} + +} // End of namespace Gob diff --git a/engines/gob/sound/adlplayer.h b/engines/gob/sound/adlplayer.h new file mode 100644 index 0000000000..9596447bbc --- /dev/null +++ b/engines/gob/sound/adlplayer.h @@ -0,0 +1,85 @@ +/* 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 GOB_SOUND_ADLPLAYER_H +#define GOB_SOUND_ADLPLAYER_H + +#include "common/array.h" + +#include "gob/sound/adlib.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Gob { + +/** A player for Coktel Vision's ADL music format. */ +class ADLPlayer : public AdLib { +public: + ADLPlayer(Audio::Mixer &mixer); + ~ADLPlayer(); + + bool load(Common::SeekableReadStream &adl); + bool load(const byte *data, uint32 dataSize, int index = -1); + void unload(); + + int getIndex() const; + +protected: + // AdLib interface + uint32 pollMusic(bool first); + void rewind(); + +private: + struct Timbre { + uint16 startParams[kOperatorsPerVoice * kParamCount]; + uint16 params[kOperatorsPerVoice * kParamCount]; + }; + + uint8 _soundMode; + + Common::Array<Timbre> _timbres; + + byte *_songData; + uint32 _songDataSize; + + const byte *_playPos; + + int _index; + + uint8 _modifyInstrument; + uint16 _currentInstruments[kMaxVoiceCount]; + + + void setInstrument(int voice, int instrument); + + bool readHeader (Common::SeekableReadStream &adl, int &timbreCount); + bool readTimbres (Common::SeekableReadStream &adl, int timbreCount); + bool readSongData(Common::SeekableReadStream &adl); + + uint32 getSampleDelay(uint16 delay) const; +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_ADLPLAYER_H diff --git a/engines/gob/sound/musplayer.cpp b/engines/gob/sound/musplayer.cpp new file mode 100644 index 0000000000..3e41dc6ed1 --- /dev/null +++ b/engines/gob/sound/musplayer.cpp @@ -0,0 +1,391 @@ +/* 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 "common/stream.h" +#include "common/textconsole.h" + +#include "gob/sound/musplayer.h" + +namespace Gob { + +MUSPlayer::MUSPlayer(Audio::Mixer &mixer) : AdLib(mixer), + _songData(0), _songDataSize(0), _playPos(0), _songID(0) { + +} + +MUSPlayer::~MUSPlayer() { + unload(); +} + +void MUSPlayer::unload() { + stopPlay(); + + unloadSND(); + unloadMUS(); +} + +uint32 MUSPlayer::getSampleDelay(uint16 delay) const { + if (delay == 0) + return 0; + + uint32 freq = (_ticksPerBeat * _tempo) / 60; + + return ((uint32)delay * getSamplesPerSecond()) / freq; +} + +void MUSPlayer::skipToTiming() { + while (*_playPos < 0x80) + _playPos++; + + if (*_playPos != 0xF8) + _playPos--; +} + +uint32 MUSPlayer::pollMusic(bool first) { + if (_timbres.empty() || !_songData || !_playPos || (_playPos >= (_songData + _songDataSize))) { + end(); + return 0; + } + + if (first) + return getSampleDelay(*_playPos++); + + uint16 delay = 0; + while (delay == 0) { + byte cmd = *_playPos; + + // Delay overflow + if (cmd == 0xF8) { + _playPos++; + delay = 0xF8; + break; + } + + // Song end marker + if (cmd == 0xFC) { + end(); + return 0; + } + + // Global command + if (cmd == 0xF0) { + _playPos++; + + byte type1 = *_playPos++; + byte type2 = *_playPos++; + + if ((type1 == 0x7F) && (type2 == 0)) { + // Tempo change, as a fraction of the base tempo + + uint32 num = *_playPos++; + uint32 denom = *_playPos++; + + _tempo = _baseTempo * num + ((_baseTempo * denom) >> 7); + + _playPos++; + } else { + + // Unsupported global command, skip it + _playPos -= 2; + while(*_playPos++ != 0xF7) + ; + } + + delay = *_playPos++; + break; + } + + // Voice command + + if (cmd >= 0x80) { + _playPos++; + + _lastCommand = cmd; + } else + cmd = _lastCommand; + + uint8 voice = cmd & 0x0F; + uint8 note, volume; + uint16 pitch; + + switch (cmd & 0xF0) { + case 0x80: // Note off + _playPos += 2; + noteOff(voice); + break; + + case 0x90: // Note on + note = *_playPos++; + volume = *_playPos++; + + if (volume) { + setVoiceVolume(voice, volume); + noteOn(voice, note); + } else + noteOff(voice); + break; + + case 0xA0: // Set volume + setVoiceVolume(voice, *_playPos++); + break; + + case 0xB0: + _playPos += 2; + break; + + case 0xC0: // Set instrument + setInstrument(voice, *_playPos++); + break; + + case 0xD0: + _playPos++; + break; + + case 0xE0: // Pitch bend + pitch = *_playPos++; + pitch += *_playPos++ << 7; + bendVoicePitch(voice, pitch); + break; + + default: + warning("MUSPlayer: Unsupported command: 0x%02X", cmd); + skipToTiming(); + break; + } + + delay = *_playPos++; + } + + if (delay == 0xF8) { + delay = 240; + + if (*_playPos != 0xF8) + delay += *_playPos++; + } + + return getSampleDelay(delay); +} + +void MUSPlayer::rewind() { + _playPos = _songData; + _tempo = _baseTempo; + + _lastCommand = 0; + + setPercussionMode(_soundMode != 0); + setPitchRange(_pitchBendRange); +} + +bool MUSPlayer::loadSND(Common::SeekableReadStream &snd) { + unloadSND(); + + int timbreCount, timbrePos; + if (!readSNDHeader(snd, timbreCount, timbrePos)) + return false; + + if (!readSNDTimbres(snd, timbreCount, timbrePos) || snd.err()) { + unloadSND(); + return false; + } + + return true; +} + +bool MUSPlayer::readString(Common::SeekableReadStream &stream, Common::String &string, byte *buffer, uint size) { + if (stream.read(buffer, size) != size) + return false; + + buffer[size] = '\0'; + + string = (char *) buffer; + + return true; +} + +bool MUSPlayer::readSNDHeader(Common::SeekableReadStream &snd, int &timbreCount, int &timbrePos) { + // Sanity check + if (snd.size() <= 6) { + warning("MUSPlayer::readSNDHeader(): File too small (%d)", snd.size()); + return false; + } + + // Version + const uint8 versionMajor = snd.readByte(); + const uint8 versionMinor = snd.readByte(); + + if ((versionMajor != 1) && (versionMinor != 0)) { + warning("MUSPlayer::readSNDHeader(): Unsupported version %d.%d", versionMajor, versionMinor); + return false; + } + + // Number of timbres and where they start + timbreCount = snd.readUint16LE(); + timbrePos = snd.readUint16LE(); + + const uint16 minTimbrePos = 6 + timbreCount * 9; + + // Sanity check + if (timbrePos < minTimbrePos) { + warning("MUSPlayer::readSNDHeader(): Timbre offset too small: %d < %d", timbrePos, minTimbrePos); + return false; + } + + const uint32 timbreParametersSize = snd.size() - timbrePos; + const uint32 paramSize = kOperatorsPerVoice * kParamCount * sizeof(uint16); + + // Sanity check + if (timbreParametersSize != (timbreCount * paramSize)) { + warning("MUSPlayer::loadSND(): Timbre parameters size mismatch: %d != %d", + timbreParametersSize, timbreCount * paramSize); + return false; + } + + return true; +} + +bool MUSPlayer::readSNDTimbres(Common::SeekableReadStream &snd, int timbreCount, int timbrePos) { + _timbres.resize(timbreCount); + + // Read names + byte nameBuffer[10]; + for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) { + if (!readString(snd, t->name, nameBuffer, 9)) { + warning("MUSPlayer::readMUSTimbres(): Failed to read timbre name"); + return false; + } + } + + if (!snd.seek(timbrePos)) { + warning("MUSPlayer::readMUSTimbres(): Failed to seek to timbres"); + return false; + } + + // Read parameters + for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) { + for (int i = 0; i < (kOperatorsPerVoice * kParamCount); i++) + t->params[i] = snd.readUint16LE(); + } + + return true; +} + +bool MUSPlayer::loadMUS(Common::SeekableReadStream &mus) { + unloadMUS(); + + if (!readMUSHeader(mus) || !readMUSSong(mus) || mus.err()) { + unloadMUS(); + return false; + } + + rewind(); + + return true; +} + +bool MUSPlayer::readMUSHeader(Common::SeekableReadStream &mus) { + // Sanity check + if (mus.size() <= 6) + return false; + + // Version + const uint8 versionMajor = mus.readByte(); + const uint8 versionMinor = mus.readByte(); + + if ((versionMajor != 1) && (versionMinor != 0)) { + warning("MUSPlayer::readMUSHeader(): Unsupported version %d.%d", versionMajor, versionMinor); + return false; + } + + _songID = mus.readUint32LE(); + + byte nameBuffer[31]; + if (!readString(mus, _songName, nameBuffer, 30)) { + warning("MUSPlayer::readMUSHeader(): Failed to read the song name"); + return false; + } + + _ticksPerBeat = mus.readByte(); + _beatsPerMeasure = mus.readByte(); + + mus.skip(4); // Length of song in ticks + + _songDataSize = mus.readUint32LE(); + + mus.skip(4); // Number of commands + mus.skip(8); // Unused + + _soundMode = mus.readByte(); + _pitchBendRange = mus.readByte(); + _baseTempo = mus.readUint16LE(); + + mus.skip(8); // Unused + + return true; +} + +bool MUSPlayer::readMUSSong(Common::SeekableReadStream &mus) { + const uint32 realSongDataSize = mus.size() - mus.pos(); + + if (realSongDataSize < _songDataSize) { + warning("MUSPlayer::readMUSSong(): File too small for the song data: %d < %d", realSongDataSize, _songDataSize); + return false; + } + + _songData = new byte[_songDataSize]; + + if (mus.read(_songData, _songDataSize) != _songDataSize) { + warning("MUSPlayer::readMUSSong(): Read failed"); + return false; + } + + return true; +} + +void MUSPlayer::unloadSND() { + _timbres.clear(); +} + +void MUSPlayer::unloadMUS() { + delete[] _songData; + + _songData = 0; + _songDataSize = 0; + + _playPos = 0; +} + +uint32 MUSPlayer::getSongID() const { + return _songID; +} + +const Common::String &MUSPlayer::getSongName() const { + return _songName; +} + +void MUSPlayer::setInstrument(uint8 voice, uint8 instrument) { + if (instrument >= _timbres.size()) + return; + + setVoiceTimbre(voice, _timbres[instrument].params); +} + +} // End of namespace Gob diff --git a/engines/gob/sound/musplayer.h b/engines/gob/sound/musplayer.h new file mode 100644 index 0000000000..6cc2a2d2ca --- /dev/null +++ b/engines/gob/sound/musplayer.h @@ -0,0 +1,109 @@ +/* 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 GOB_SOUND_MUSPLAYER_H +#define GOB_SOUND_MUSPLAYER_H + +#include "common/str.h" +#include "common/array.h" + +#include "gob/sound/adlib.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Gob { + +/** A player for the AdLib MUS format, with the instrument information in SND files. + * + * In the Gob engine, those files are usually named .MDY and .TBR instead. + */ +class MUSPlayer : public AdLib { +public: + MUSPlayer(Audio::Mixer &mixer); + ~MUSPlayer(); + + /** Load the instruments (.SND or .TBR) */ + bool loadSND(Common::SeekableReadStream &snd); + /** Load the melody (.MUS or .MDY) */ + bool loadMUS(Common::SeekableReadStream &mus); + + void unload(); + + uint32 getSongID() const; + const Common::String &getSongName() const; + +protected: + // AdLib interface + uint32 pollMusic(bool first); + void rewind(); + +private: + struct Timbre { + Common::String name; + + uint16 params[kOperatorsPerVoice * kParamCount]; + }; + + Common::Array<Timbre> _timbres; + + byte *_songData; + uint32 _songDataSize; + + const byte *_playPos; + + uint32 _songID; + Common::String _songName; + + uint8 _ticksPerBeat; + uint8 _beatsPerMeasure; + + uint8 _soundMode; + uint8 _pitchBendRange; + + uint16 _baseTempo; + + uint16 _tempo; + + byte _lastCommand; + + + void unloadSND(); + void unloadMUS(); + + bool readSNDHeader (Common::SeekableReadStream &snd, int &timbreCount, int &timbrePos); + bool readSNDTimbres(Common::SeekableReadStream &snd, int timbreCount, int timbrePos); + + bool readMUSHeader(Common::SeekableReadStream &mus); + bool readMUSSong (Common::SeekableReadStream &mus); + + uint32 getSampleDelay(uint16 delay) const; + void setInstrument(uint8 voice, uint8 instrument); + void skipToTiming(); + + static bool readString(Common::SeekableReadStream &stream, Common::String &string, byte *buffer, uint size); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_MUSPLAYER_H diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp index bfe0394390..63af6aeef4 100644 --- a/engines/gob/sound/sound.cpp +++ b/engines/gob/sound/sound.cpp @@ -30,7 +30,8 @@ #include "gob/sound/pcspeaker.h" #include "gob/sound/soundblaster.h" -#include "gob/sound/adlib.h" +#include "gob/sound/adlplayer.h" +#include "gob/sound/musplayer.h" #include "gob/sound/infogrames.h" #include "gob/sound/protracker.h" #include "gob/sound/cdrom.h" @@ -50,6 +51,8 @@ Sound::Sound(GobEngine *vm) : _vm(vm) { _hasAdLib = (!_vm->_noMusic && _vm->hasAdLib()); + _hasAdLibBg = _hasAdLib; + if (!_vm->_noMusic && (_vm->getPlatform() == Common::kPlatformAmiga)) { _infogrames = new Infogrames(*_vm->_mixer); _protracker = new Protracker(*_vm->_mixer); @@ -106,7 +109,7 @@ int Sound::sampleGetNextFreeSlot() const { return -1; } -bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist) { +bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName) { if (!sndDesc) return false; @@ -114,12 +117,15 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, int32 size; byte *data = _vm->_dataIO->getFile(fileName, size); - if (!data) { - warning("Can't open sample file \"%s\"", fileName); + + if (!data || !sndDesc->load(type, data, size)) { + delete data; + + warning("Sound::sampleLoad(): Failed to load sound \"%s\"", fileName); return false; } - return sndDesc->load(type, data, size); + return true; } void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdLib, int index) { @@ -131,10 +137,7 @@ void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdLib, int index) { if (noteAdLib) { if (_adlPlayer) if ((index == -1) || (_adlPlayer->getIndex() == index)) - _adlPlayer->stopPlay(); - if (_mdyPlayer) - if ((index == -1) || (_mdyPlayer->getIndex() == index)) - _mdyPlayer->stopPlay(); + _adlPlayer->unload(); } } else { @@ -235,7 +238,17 @@ bool Sound::adlibLoadADL(const char *fileName) { debugC(1, kDebugSound, "AdLib: Loading ADL data (\"%s\")", fileName); - return _adlPlayer->load(fileName); + Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName); + if (!stream) { + warning("Can't open ADL file \"%s\"", fileName); + return false; + } + + bool loaded = _adlPlayer->load(*stream); + + delete stream; + + return loaded; } bool Sound::adlibLoadADL(byte *data, uint32 size, int index) { @@ -266,8 +279,7 @@ bool Sound::adlibLoadMDY(const char *fileName) { if (!_hasAdLib) return false; - if (!_mdyPlayer) - _mdyPlayer = new MDYPlayer(*_vm->_mixer); + createMDYPlayer(); debugC(1, kDebugSound, "AdLib: Loading MDY data (\"%s\")", fileName); @@ -277,7 +289,7 @@ bool Sound::adlibLoadMDY(const char *fileName) { return false; } - bool loaded = _mdyPlayer->loadMDY(*stream); + bool loaded = _mdyPlayer->loadMUS(*stream); delete stream; @@ -288,8 +300,7 @@ bool Sound::adlibLoadTBR(const char *fileName) { if (!_hasAdLib) return false; - if (!_mdyPlayer) - _mdyPlayer = new MDYPlayer(*_vm->_mixer); + createMDYPlayer(); Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName); if (!stream) { @@ -299,7 +310,7 @@ bool Sound::adlibLoadTBR(const char *fileName) { debugC(1, kDebugSound, "AdLib: Loading MDY instruments (\"%s\")", fileName); - bool loaded = _mdyPlayer->loadTBR(*stream); + bool loaded = _mdyPlayer->loadSND(*stream); delete stream; @@ -310,28 +321,23 @@ void Sound::adlibPlayTrack(const char *trackname) { if (!_hasAdLib) return; - if (!_adlPlayer) - _adlPlayer = new ADLPlayer(*_vm->_mixer); + createADLPlayer(); if (_adlPlayer->isPlaying()) return; - debugC(1, kDebugSound, "AdLib: Playing ADL track \"%s\"", trackname); - - _adlPlayer->unload(); - _adlPlayer->load(trackname); - _adlPlayer->startPlay(); + if (adlibLoadADL(trackname)) + adlibPlay(); } void Sound::adlibPlayBgMusic() { - if (!_hasAdLib) + if (!_hasAdLib || _hasAdLibBg) return; - if (!_adlPlayer) - _adlPlayer = new ADLPlayer(*_vm->_mixer); + createADLPlayer(); static const char *const tracksMac[] = { -// "musmac1.adl", // TODO: This track isn't played correctly at all yet +// "musmac1.adl", // This track seems to be missing instruments... "musmac2.adl", "musmac3.adl", "musmac4.adl", @@ -347,13 +353,18 @@ void Sound::adlibPlayBgMusic() { "musmac5.mid" }; - if (_vm->getPlatform() == Common::kPlatformWindows) { - int track = _vm->_util->getRandom(ARRAYSIZE(tracksWin)); - adlibPlayTrack(tracksWin[track]); - } else { - int track = _vm->_util->getRandom(ARRAYSIZE(tracksMac)); - adlibPlayTrack(tracksMac[track]); + const char *track = 0; + if (_vm->getPlatform() == Common::kPlatformWindows) + track = tracksWin[_vm->_util->getRandom(ARRAYSIZE(tracksWin))]; + else + track = tracksMac[_vm->_util->getRandom(ARRAYSIZE(tracksMac))]; + + if (!track || !_vm->_dataIO->hasFile(track)) { + _hasAdLibBg = false; + return; } + + adlibPlayTrack(track); } void Sound::adlibPlay() { @@ -398,13 +409,11 @@ int Sound::adlibGetIndex() const { if (_adlPlayer) return _adlPlayer->getIndex(); - if (_mdyPlayer) - return _mdyPlayer->getIndex(); return -1; } -bool Sound::adlibGetRepeating() const { +int32 Sound::adlibGetRepeating() const { if (!_hasAdLib) return false; @@ -439,6 +448,10 @@ void Sound::blasterPlay(SoundDesc *sndDesc, int16 repCount, _blaster->playSample(*sndDesc, repCount, frequency, fadeLength); } +void Sound::blasterRepeatComposition(int32 repCount) { + _blaster->repeatComposition(repCount); +} + void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) { if (!_blaster) return; @@ -448,7 +461,7 @@ void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) { _blaster->stopSound(fadeLength, sndDesc); } -void Sound::blasterPlayComposition(int16 *composition, int16 freqVal, +void Sound::blasterPlayComposition(const int16 *composition, int16 freqVal, SoundDesc *sndDescs, int8 sndCount) { if (!_blaster) return; @@ -719,4 +732,24 @@ void Sound::bgUnshade() { _bgatmos->unshade(); } +void Sound::createMDYPlayer() { + if (_mdyPlayer) + return; + + delete _adlPlayer; + _adlPlayer = 0; + + _mdyPlayer = new MUSPlayer(*_vm->_mixer); +} + +void Sound::createADLPlayer() { + if (_adlPlayer) + return; + + delete _mdyPlayer; + _mdyPlayer= 0; + + _adlPlayer = new ADLPlayer(*_vm->_mixer); +} + } // End of namespace Gob diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index 585cf36703..bbc182d172 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -32,7 +32,7 @@ class GobEngine; class PCSpeaker; class SoundBlaster; class ADLPlayer; -class MDYPlayer; +class MUSPlayer; class Infogrames; class Protracker; class CDROM; @@ -51,7 +51,7 @@ public: const SoundDesc *sampleGetBySlot(int slot) const; int sampleGetNextFreeSlot() const; - bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist = true); + bool sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName); void sampleFree(SoundDesc *sndDesc, bool noteAdLib = false, int index = -1); @@ -60,9 +60,10 @@ public: int16 frequency, int16 fadeLength = 0); void blasterStop(int16 fadeLength, SoundDesc *sndDesc = 0); - void blasterPlayComposition(int16 *composition, int16 freqVal, + void blasterPlayComposition(const int16 *composition, int16 freqVal, SoundDesc *sndDescs = 0, int8 sndCount = kSoundsCount); void blasterStopComposition(); + void blasterRepeatComposition(int32 repCount); char blasterPlayingSound() const; @@ -92,7 +93,7 @@ public: bool adlibIsPlaying() const; int adlibGetIndex() const; - bool adlibGetRepeating() const; + int32 adlibGetRepeating() const; void adlibSetRepeating(int32 repCount); @@ -142,17 +143,30 @@ private: GobEngine *_vm; bool _hasAdLib; + bool _hasAdLibBg; SoundDesc _sounds[kSoundsCount]; + // Speaker PCSpeaker *_pcspeaker; + + // PCM based SoundBlaster *_blaster; + BackgroundAtmosphere *_bgatmos; + + // AdLib + MUSPlayer *_mdyPlayer; ADLPlayer *_adlPlayer; - MDYPlayer *_mdyPlayer; + + // Amiga Paula Infogrames *_infogrames; Protracker *_protracker; + + // Audio CD CDROM *_cdrom; - BackgroundAtmosphere *_bgatmos; + + void createMDYPlayer(); + void createADLPlayer(); }; } // End of namespace Gob diff --git a/engines/gob/sound/soundblaster.cpp b/engines/gob/sound/soundblaster.cpp index 4ff555b0e3..f267eee32d 100644 --- a/engines/gob/sound/soundblaster.cpp +++ b/engines/gob/sound/soundblaster.cpp @@ -31,6 +31,8 @@ SoundBlaster::SoundBlaster(Audio::Mixer &mixer) : SoundMixer(mixer, Audio::Mixer _compositionSamples = 0; _compositionSampleCount = 0; _compositionPos = -1; + + _compositionRepCount = 0; } SoundBlaster::~SoundBlaster() { @@ -47,6 +49,8 @@ void SoundBlaster::stopSound(int16 fadeLength, SoundDesc *sndDesc) { if (sndDesc && (sndDesc != _curSoundDesc)) return; + _compositionRepCount = 0; + if (fadeLength <= 0) _curSoundDesc = 0; @@ -62,6 +66,7 @@ void SoundBlaster::stopComposition() { void SoundBlaster::endComposition() { _compositionPos = -1; + _compositionRepCount = 0; } void SoundBlaster::nextCompositionPos() { @@ -79,10 +84,11 @@ void SoundBlaster::nextCompositionPos() { if (_compositionPos == 49) _compositionPos = -1; } + _compositionPos = -1; } -void SoundBlaster::playComposition(int16 *composition, int16 freqVal, +void SoundBlaster::playComposition(const int16 *composition, int16 freqVal, SoundDesc *sndDescs, int8 sndCount) { _compositionSamples = sndDescs; @@ -98,6 +104,10 @@ void SoundBlaster::playComposition(int16 *composition, int16 freqVal, nextCompositionPos(); } +void SoundBlaster::repeatComposition(int32 repCount) { + _compositionRepCount = repCount; +} + void SoundBlaster::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, int16 fadeLength) { @@ -106,10 +116,21 @@ void SoundBlaster::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency } void SoundBlaster::checkEndSample() { - if (_compositionPos != -1) + if (_compositionPos != -1) { nextCompositionPos(); - else - SoundMixer::checkEndSample(); + return; + } + + if (_compositionRepCount != 0) { + if (_compositionRepCount > 0) + _compositionRepCount--; + + nextCompositionPos(); + if (_compositionPos != -1) + return; + } + + SoundMixer::checkEndSample(); } void SoundBlaster::endFade() { diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h index c2704c5482..3c4968d611 100644 --- a/engines/gob/sound/soundblaster.h +++ b/engines/gob/sound/soundblaster.h @@ -41,11 +41,13 @@ public: int16 frequency, int16 fadeLength = 0); void stopSound(int16 fadeLength, SoundDesc *sndDesc = 0); - void playComposition(int16 *composition, int16 freqVal, + void playComposition(const int16 *composition, int16 freqVal, SoundDesc *sndDescs = 0, int8 sndCount = 60); void stopComposition(); void endComposition(); + void repeatComposition(int32 repCount); + protected: Common::Mutex _mutex; @@ -54,6 +56,8 @@ protected: int16 _composition[50]; int8 _compositionPos; + int32 _compositionRepCount; + SoundDesc *_curSoundDesc; void setSample(SoundDesc &sndDesc, int16 repCount, diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp index e294209ed7..afbb7c3bae 100644 --- a/engines/gob/surface.cpp +++ b/engines/gob/surface.cpp @@ -280,6 +280,18 @@ Surface::Surface(uint16 width, uint16 height, uint8 bpp, byte *vidMem) : _ownVidMem = false; } +Surface::Surface(uint16 width, uint16 height, uint8 bpp, const byte *vidMem) : + _width(width), _height(height), _bpp(bpp), _vidMem(0) { + + assert((_width > 0) && (_height > 0)); + assert((_bpp == 1) || (_bpp == 2)); + + _vidMem = new byte[_bpp * _width * _height]; + _ownVidMem = true; + + memcpy(_vidMem, vidMem, _bpp * _width * _height); +} + Surface::~Surface() { if (_ownVidMem) delete[] _vidMem; @@ -672,6 +684,12 @@ void Surface::shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom, } +void Surface::recolor(uint8 from, uint8 to) { + for (Pixel p = get(); p.isValid(); ++p) + if (p.get() == from) + p.set(to); +} + void Surface::putPixel(uint16 x, uint16 y, uint32 color) { if ((x >= _width) || (y >= _height)) return; @@ -683,6 +701,34 @@ void Surface::drawLine(uint16 x0, uint16 y0, uint16 x1, uint16 y1, uint32 color) Graphics::drawLine(x0, y0, x1, y1, color, &plotPixel, this); } +void Surface::drawRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color) { + // Just in case those are swapped + if (left > right) + SWAP(left, right); + if (top > bottom) + SWAP(top, bottom); + + if ((left >= _width) || (top >= _height)) + // Nothing to do + return; + + // Area to actually draw + const uint16 width = CLIP<int32>(right - left + 1, 0, _width - left); + const uint16 height = CLIP<int32>(bottom - top + 1, 0, _height - top); + + if ((width == 0) || (height == 0)) + // Nothing to do + return; + + right = left + width - 1; + bottom = top + height - 1; + + drawLine(left , top , left , bottom, color); + drawLine(right, top , right, bottom, color); + drawLine(left , top , right, top , color); + drawLine(left , bottom, right, bottom, color); +} + /* * The original's version of the Bresenham Algorithm was a bit "unclean" * and produced strange edges at 45, 135, 225 and 315 degrees, so using the diff --git a/engines/gob/surface.h b/engines/gob/surface.h index 866e63490f..8f895a7910 100644 --- a/engines/gob/surface.h +++ b/engines/gob/surface.h @@ -122,6 +122,7 @@ private: class Surface { public: Surface(uint16 width, uint16 height, uint8 bpp, byte *vidMem = 0); + Surface(uint16 width, uint16 height, uint8 bpp, const byte *vidMem); ~Surface(); uint16 getWidth () const; @@ -155,8 +156,11 @@ public: void shadeRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color, uint8 strength); + void recolor(uint8 from, uint8 to); + void putPixel(uint16 x, uint16 y, uint32 color); void drawLine(uint16 x0, uint16 y0, uint16 x1, uint16 y1, uint32 color); + void drawRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color); void drawCircle(uint16 x0, uint16 y0, uint16 radius, uint32 color, int16 pattern = 0); void blitToScreen(uint16 left, uint16 top, uint16 right, uint16 bottom, uint16 x, uint16 y) const; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 7f9c6131fd..5ac4ef024e 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -21,7 +21,6 @@ */ #include "common/stream.h" -#include "common/events.h" #include "graphics/palette.h" @@ -45,6 +44,8 @@ Util::Util(GobEngine *vm) : _vm(vm) { _frameRate = 12; _frameWaitTime = 0; _startFrameTime = 0; + + _keyState = 0; } uint32 Util::getTimeKey() { @@ -116,6 +117,8 @@ void Util::processInput(bool scroll) { _mouseButtons = (MouseButtons) (((uint32) _mouseButtons) & ~((uint32) kMouseButtonsRight)); break; case Common::EVENT_KEYDOWN: + keyDown(event); + if (event.kbd.hasFlags(Common::KBD_CTRL)) { if (event.kbd.keycode == Common::KEYCODE_f) _fastMode ^= 1; @@ -132,6 +135,7 @@ void Util::processInput(bool scroll) { addKeyToBuffer(event.kbd); break; case Common::EVENT_KEYUP: + keyUp(event); break; default: break; @@ -185,12 +189,27 @@ bool Util::getKeyFromBuffer(Common::KeyState &key) { return true; } +static const uint16 kLatin1ToCP850[] = { + 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, + 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, + 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, + 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, + 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, + 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 +}; + +int16 Util::toCP850(uint16 latin1) { + if ((latin1 < 0xA0) || ((latin1 - 0xA0) >= ARRAYSIZE(kLatin1ToCP850))) + return 0; + + return kLatin1ToCP850[latin1 - 0xA0]; +} + int16 Util::translateKey(const Common::KeyState &key) { static struct keyS { int16 from; int16 to; } keys[] = { - {Common::KEYCODE_INVALID, kKeyNone }, {Common::KEYCODE_BACKSPACE, kKeyBackspace}, {Common::KEYCODE_SPACE, kKeySpace }, {Common::KEYCODE_RETURN, kKeyReturn }, @@ -212,20 +231,88 @@ int16 Util::translateKey(const Common::KeyState &key) { {Common::KEYCODE_F10, kKeyF10 } }; + // Translate special keys for (int i = 0; i < ARRAYSIZE(keys); i++) if (key.keycode == keys[i].from) return keys[i].to; - if ((key.keycode >= Common::KEYCODE_SPACE) && - (key.keycode <= Common::KEYCODE_DELETE)) { - - // Used as a user input in Gobliins 2 notepad, in the save dialog, ... + // Return the ascii value, for text input + if ((key.ascii >= 32) && (key.ascii <= 127)) return key.ascii; - } + + // Translate international characters into CP850 characters + if ((key.ascii >= 160) && (key.ascii <= 255)) + return toCP850(key.ascii); return 0; } +static const uint8 kLowerToUpper[][2] = { + {0x81, 0x9A}, + {0x82, 0x90}, + {0x83, 0xB6}, + {0x84, 0x8E}, + {0x85, 0xB7}, + {0x86, 0x8F}, + {0x87, 0x80}, + {0x88, 0xD2}, + {0x89, 0xD3}, + {0x8A, 0xD4}, + {0x8B, 0xD8}, + {0x8C, 0xD7}, + {0x8D, 0xDE}, + {0x91, 0x92}, + {0x93, 0xE2}, + {0x94, 0x99}, + {0x95, 0xE3}, + {0x96, 0xEA}, + {0x97, 0xEB}, + {0x95, 0xE3}, + {0x96, 0xEA}, + {0x97, 0xEB}, + {0x9B, 0x9D}, + {0xA0, 0xB5}, + {0xA1, 0xD6}, + {0xA2, 0xE0}, + {0xA3, 0xE9}, + {0xA4, 0xA5}, + {0xC6, 0xC7}, + {0xD0, 0xD1}, + {0xE4, 0xE5}, + {0xE7, 0xE8}, + {0xEC, 0xED} +}; + +char Util::toCP850Lower(char cp850) { + const uint8 cp = (unsigned char)cp850; + if (cp <= 32) + return cp850; + + if (cp <= 127) + return tolower(cp850); + + for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++) + if (cp == kLowerToUpper[i][1]) + return (char)kLowerToUpper[i][0]; + + return cp850; +} + +char Util::toCP850Upper(char cp850) { + const uint8 cp = (unsigned char)cp850; + if (cp <= 32) + return cp850; + + if (cp <= 127) + return toupper(cp850); + + for (uint i = 0; i < ARRAYSIZE(kLowerToUpper); i++) + if (cp == kLowerToUpper[i][0]) + return (char)kLowerToUpper[i][1]; + + return cp850; +} + int16 Util::getKey() { Common::KeyState key; @@ -363,21 +450,29 @@ void Util::notifyNewAnim() { _startFrameTime = getTimeKey(); } -void Util::waitEndFrame() { +void Util::waitEndFrame(bool handleInput) { int32 time; - _vm->_video->waitRetrace(); - time = getTimeKey() - _startFrameTime; if ((time > 1000) || (time < 0)) { + _vm->_video->retrace(); _startFrameTime = getTimeKey(); return; } - int32 toWait = _frameWaitTime - time; + int32 toWait = 0; + do { + if (toWait > 0) + delay(MIN<int>(toWait, 10)); - if (toWait > 0) - delay(toWait); + if (handleInput) + processInput(); + + _vm->_video->retrace(); + + time = getTimeKey() - _startFrameTime; + toWait = _frameWaitTime - time; + } while (toWait > 0); _startFrameTime = getTimeKey(); } @@ -576,4 +671,38 @@ void Util::checkJoystick() { _vm->_global->_useJoystick = 0; } +uint32 Util::getKeyState() const { + return _keyState; +} + +void Util::keyDown(const Common::Event &event) { + if (event.kbd.keycode == Common::KEYCODE_UP) + _keyState |= 0x0001; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keyState |= 0x0002; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keyState |= 0x0004; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keyState |= 0x0008; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keyState |= 0x0020; + else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) + _keyState |= 0x0040; +} + +void Util::keyUp(const Common::Event &event) { + if (event.kbd.keycode == Common::KEYCODE_UP) + _keyState &= ~0x0001; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keyState &= ~0x0002; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keyState &= ~0x0004; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keyState &= ~0x0008; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keyState &= ~0x0020; + else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) + _keyState &= ~0x0040; +} + } // End of namespace Gob diff --git a/engines/gob/util.h b/engines/gob/util.h index 4228dac768..a4984c6207 100644 --- a/engines/gob/util.h +++ b/engines/gob/util.h @@ -25,6 +25,7 @@ #include "common/str.h" #include "common/keyboard.h" +#include "common/events.h" namespace Common { class SeekableReadStream; @@ -110,6 +111,8 @@ public: bool checkKey(int16 &key); bool keyPressed(); + uint32 getKeyState() const; + void getMouseState(int16 *pX, int16 *pY, MouseButtons *pButtons); void setMousePos(int16 x, int16 y); void waitMouseUp(); @@ -121,7 +124,7 @@ public: int16 getFrameRate(); void setFrameRate(int16 rate); void notifyNewAnim(); - void waitEndFrame(); + void waitEndFrame(bool handleInput = true); void setScrollOffset(int16 x = -1, int16 y = -1); static void insertStr(const char *str1, char *str2, int16 pos); @@ -140,6 +143,11 @@ public: /** Read a constant-length string out of a stream. */ static Common::String readString(Common::SeekableReadStream &stream, int n); + /** Convert a character in CP850 encoding to the equivalent lower case character. */ + static char toCP850Lower(char cp850); + /** Convert a character in CP850 encoding to the equivalent upper case character. */ + static char toCP850Upper(char cp850); + Util(GobEngine *vm); protected: @@ -155,13 +163,19 @@ protected: int16 _frameWaitTime; uint32 _startFrameTime; + uint32 _keyState; + GobEngine *_vm; bool keyBufferEmpty(); void addKeyToBuffer(const Common::KeyState &key); bool getKeyFromBuffer(Common::KeyState &key); int16 translateKey(const Common::KeyState &key); + int16 toCP850(uint16 latin1); void checkJoystick(); + + void keyDown(const Common::Event &event); + void keyUp(const Common::Event &event); }; } // End of namespace Gob diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp index ee5ff4abff..64af34cf62 100644 --- a/engines/gob/video.cpp +++ b/engines/gob/video.cpp @@ -25,7 +25,6 @@ #include "engines/util.h" #include "graphics/cursorman.h" -#include "graphics/fontman.h" #include "graphics/palette.h" #include "graphics/surface.h" @@ -85,6 +84,10 @@ uint16 Font::getCharCount() const { return _endItem - _startItem + 1; } +bool Font::hasChar(uint8 c) const { + return (c >= _startItem) && (c <= _endItem); +} + bool Font::isMonospaced() const { return _charWidths == 0; } @@ -135,6 +138,23 @@ void Font::drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y, } } +void Font::drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2, + bool transp, Surface &dest) const { + + const char *s = str.c_str(); + + while (*s != '\0') { + const int16 charRight = x + getCharWidth(*s); + const int16 charBottom = y + getCharHeight(); + + if ((x >= 0) && (y >= 0) && (charRight <= dest.getWidth()) && (charBottom <= dest.getHeight())) + drawLetter(dest, *s, x, y, color1, color2, transp); + + x += getCharWidth(*s); + s++; + } +} + const byte *Font::getCharData(uint8 c) const { if (_endItem == 0) { warning("Font::getCharData(): _endItem == 0"); @@ -226,10 +246,7 @@ void Video::setSize(bool defaultTo1XScaler) { void Video::retrace(bool mouse) { if (mouse) - if ((_vm->getGameType() != kGameTypeAdibou2) && - (_vm->getGameType() != kGameTypeAdi2) && - (_vm->getGameType() != kGameTypeAdi4)) - CursorMan.showMouse((_vm->_draw->_showCursor & 2) != 0); + CursorMan.showMouse((_vm->_draw->_showCursor & 6) != 0); if (_vm->_global->_primarySurfDesc) { int screenX = _screenDeltaX; @@ -336,6 +353,10 @@ void Video::drawPackedSprite(byte *sprBuf, int16 width, int16 height, void Video::drawPackedSprite(const char *path, Surface &dest, int width) { int32 size; byte *data = _vm->_dataIO->getFile(path, size); + if (!data) { + warning("Video::drawPackedSprite(): Failed to open sprite \"%s\"", path); + return; + } drawPackedSprite(data, width, dest.getHeight(), 0, 0, 0, dest); delete[] data; diff --git a/engines/gob/video.h b/engines/gob/video.h index ecbb579c5f..122c1e47d5 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -41,11 +41,16 @@ public: uint8 getCharWidth () const; uint8 getCharHeight() const; + bool hasChar(uint8 c) const; + bool isMonospaced() const; void drawLetter(Surface &surf, uint8 c, uint16 x, uint16 y, uint32 color1, uint32 color2, bool transp) const; + void drawString(const Common::String &str, int16 x, int16 y, int16 color1, int16 color2, + bool transp, Surface &dest) const; + private: const byte *_dataPtr; const byte *_data; diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index 221f5ab3c9..a478492ccc 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -234,6 +234,23 @@ void VideoPlayer::closeAll() { closeVideo(i); } +bool VideoPlayer::reopenVideo(int slot) { + Video *video = getVideoBySlot(slot); + if (!video) + return true; + + return reopenVideo(*video); +} + +bool VideoPlayer::reopenAll() { + bool all = true; + for (int i = 0; i < kVideoSlotCount; i++) + if (!reopenVideo(i)) + all = false; + + return all; +} + void VideoPlayer::pauseVideo(int slot, bool pause) { Video *video = getVideoBySlot(slot); if (!video || !video->decoder) @@ -850,6 +867,39 @@ Common::String VideoPlayer::findFile(const Common::String &file, Properties &pro return video; } +bool VideoPlayer::reopenVideo(Video &video) { + if (video.isEmpty()) + return true; + + if (video.fileName.empty()) { + video.close(); + return false; + } + + Properties properties; + + properties.type = video.properties.type; + + Common::String fileName = findFile(video.fileName, properties); + if (fileName.empty()) { + video.close(); + return false; + } + + Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName); + if (!stream) { + video.close(); + return false; + } + + if (!video.decoder->reloadStream(stream)) { + delete stream; + return false; + } + + return true; +} + void VideoPlayer::copyPalette(const Video &video, int16 palStart, int16 palEnd) { if (!video.decoder->hasPalette() || !video.decoder->isPaletted()) return; diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index bc7cb48768..129ccef67a 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -110,6 +110,9 @@ public: void closeLiveSound(); void closeAll(); + bool reopenVideo(int slot = 0); + bool reopenAll(); + void pauseVideo(int slot, bool pause); void pauseAll(bool pause); @@ -163,6 +166,8 @@ private: bool isEmpty() const; void close(); + + void reopen(); }; static const int kVideoSlotCount = 32; @@ -188,6 +193,8 @@ private: ::Video::CoktelDecoder *openVideo(const Common::String &file, Properties &properties); + bool reopenVideo(Video &video); + bool playFrame(int slot, Properties &properties); void checkAbort(Video &video, Properties &properties); diff --git a/engines/groovie/cursor.cpp b/engines/groovie/cursor.cpp index abefac54bd..6422570220 100644 --- a/engines/groovie/cursor.cpp +++ b/engines/groovie/cursor.cpp @@ -387,7 +387,7 @@ void Cursor_v2::enable() { void Cursor_v2::showFrame(uint16 frame) { int offset = _width * _height * frame * 2; - CursorMan.replaceCursor((const byte *)(_img + offset), _width, _height, _width >> 1, _height >> 1, 0, 1, &_format); + CursorMan.replaceCursor((const byte *)(_img + offset), _width, _height, _width >> 1, _height >> 1, 0, false, &_format); } diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp index c3ca03750a..73eb574dec 100644 --- a/engines/groovie/graphics.cpp +++ b/engines/groovie/graphics.cpp @@ -94,7 +94,7 @@ void GraphicsMan::mergeFgAndBg() { } void GraphicsMan::updateScreen(Graphics::Surface *source) { - _vm->_system->copyRectToScreen((byte *)source->getBasePtr(0, 0), 640, 0, 80, 640, 320); + _vm->_system->copyRectToScreen(source->getBasePtr(0, 0), 640, 0, 80, 640, 320); change(); } diff --git a/engines/groovie/resource.cpp b/engines/groovie/resource.cpp index c26f04d6ee..42d76cabfa 100644 --- a/engines/groovie/resource.cpp +++ b/engines/groovie/resource.cpp @@ -242,6 +242,7 @@ uint32 ResMan_v2::getRef(Common::String name, Common::String scriptname) { if (resname.hasPrefix(name.c_str())) { debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource %18s matches %s", readname, name.c_str()); found = true; + break; } } diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index baf42a7679..35d7ecf886 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -160,7 +160,7 @@ bool ROQPlayer::playFrameInternal() { if (_dirty) { // Update the screen - _syst->copyRectToScreen((byte *)_bg->getBasePtr(0, 0), _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h); + _syst->copyRectToScreen(_bg->getBasePtr(0, 0), _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h); _syst->updateScreen(); // Clear the dirty flag diff --git a/engines/groovie/saveload.cpp b/engines/groovie/saveload.cpp index 14e7a09cb2..1a92c02e0e 100644 --- a/engines/groovie/saveload.cpp +++ b/engines/groovie/saveload.cpp @@ -103,8 +103,6 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s if (descriptor) { // Initialize the SaveStateDescriptor descriptor->setSaveSlot(slot); - descriptor->setDeletableFlag(true); - descriptor->setWriteProtectedFlag(false); // TODO: Add extra information //setSaveDate(int year, int month, int day) diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index 68415233f4..cbbdecc3e7 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -373,7 +373,7 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { DebugMan.isDebugChannelEnabled(kGroovieDebugAll)) { rect.translate(0, -80); _vm->_graphicsMan->_foreground.frameRect(rect, 250); - _vm->_system->copyRectToScreen((byte *)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); + _vm->_system->copyRectToScreen(_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320); _vm->_system->updateScreen(); } @@ -1231,7 +1231,7 @@ void Script::o_copyrecttobg() { // 0x37 memcpy(bg + offset, fg + offset, width); offset += 640; } - _vm->_system->copyRectToScreen((byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80), 640, left, top, width, height); + _vm->_system->copyRectToScreen(_vm->_graphicsMan->_background.getBasePtr(left, top - 80), 640, left, top, width, height); _vm->_graphicsMan->change(); } diff --git a/engines/hugo/console.cpp b/engines/hugo/console.cpp index 19fd91e3fa..414c86e1d4 100644 --- a/engines/hugo/console.cpp +++ b/engines/hugo/console.cpp @@ -96,8 +96,8 @@ bool HugoConsole::Cmd_listObjects(int argc, const char **argv) { DebugPrintf("Available objects for this game are:\n"); for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) - DebugPrintf("%2d - %s\n", i, _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 2)); + if (_vm->_object->_objects[i]._genericCmd & TAKE) + DebugPrintf("%2d - %s\n", i, _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)); } return true; } @@ -111,7 +111,7 @@ bool HugoConsole::Cmd_getObject(int argc, const char **argv) { return true; } - if (_vm->_object->_objects[strToInt(argv[1])].genericCmd & TAKE) + if (_vm->_object->_objects[strToInt(argv[1])]._genericCmd & TAKE) _vm->_parser->takeObject(&_vm->_object->_objects[strToInt(argv[1])]); else DebugPrintf("Object not available\n"); @@ -129,7 +129,7 @@ bool HugoConsole::Cmd_getAllObjects(int argc, const char **argv) { } for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) + if (_vm->_object->_objects[i]._genericCmd & TAKE) _vm->_parser->takeObject(&_vm->_object->_objects[i]); } @@ -145,7 +145,7 @@ bool HugoConsole::Cmd_boundaries(int argc, const char **argv) { return true; } - _vm->getGameStatus().showBoundariesFl = !_vm->getGameStatus().showBoundariesFl; + _vm->getGameStatus()._showBoundariesFl = !_vm->getGameStatus()._showBoundariesFl; return false; } diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index 90708163f5..bb5944acc8 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -244,9 +244,6 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); desc.setThumbnail(thumbnail); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - uint32 saveDate = file->readUint32BE(); uint16 saveTime = file->readUint16BE(); diff --git a/engines/hugo/dialogs.cpp b/engines/hugo/dialogs.cpp index e0b0198470..0f07d52aee 100644 --- a/engines/hugo/dialogs.cpp +++ b/engines/hugo/dialogs.cpp @@ -34,19 +34,19 @@ namespace Hugo { -TopMenu::TopMenu(HugoEngine *vm) : Dialog(0, 0, kMenuWidth, kMenuHeight), arrayBmp(0), arraySize(0), +TopMenu::TopMenu(HugoEngine *vm) : Dialog(0, 0, kMenuWidth, kMenuHeight), _arrayBmp(0), _arraySize(0), _vm(vm) { init(); } TopMenu::~TopMenu() { - for (int i = 0; i < arraySize; i++) { - arrayBmp[i * 2]->free(); - delete arrayBmp[i * 2]; - arrayBmp[i * 2 + 1]->free(); - delete arrayBmp[i * 2 + 1]; + for (int i = 0; i < _arraySize; i++) { + _arrayBmp[i * 2]->free(); + delete _arrayBmp[i * 2]; + _arrayBmp[i * 2 + 1]->free(); + delete _arrayBmp[i * 2 + 1]; } - delete[] arrayBmp; + delete[] _arrayBmp; } void TopMenu::init() { @@ -108,23 +108,23 @@ void TopMenu::reflowLayout() { x += kButtonWidth + kButtonPad; // Set the graphics to the 'on' buttons, except for the variable ones - _whatButton->setGfx(arrayBmp[4 * kMenuWhat + scale - 1]); - _musicButton->setGfx(arrayBmp[4 * kMenuMusic + scale - 1 + ((_vm->_config.musicFl) ? 0 : 2)]); - _soundFXButton->setGfx(arrayBmp[4 * kMenuSoundFX + scale - 1 + ((_vm->_config.soundFl) ? 0 : 2)]); - _saveButton->setGfx(arrayBmp[4 * kMenuSave + scale - 1]); - _loadButton->setGfx(arrayBmp[4 * kMenuLoad + scale - 1]); - _recallButton->setGfx(arrayBmp[4 * kMenuRecall + scale - 1]); - _turboButton->setGfx(arrayBmp[4 * kMenuTurbo + scale - 1 + ((_vm->_config.turboFl) ? 0 : 2)]); - _lookButton->setGfx(arrayBmp[4 * kMenuLook + scale - 1]); - _inventButton->setGfx(arrayBmp[4 * kMenuInventory + scale - 1]); + _whatButton->setGfx(_arrayBmp[4 * kMenuWhat + scale - 1]); + _musicButton->setGfx(_arrayBmp[4 * kMenuMusic + scale - 1 + ((_vm->_config._musicFl) ? 0 : 2)]); + _soundFXButton->setGfx(_arrayBmp[4 * kMenuSoundFX + scale - 1 + ((_vm->_config._soundFl) ? 0 : 2)]); + _saveButton->setGfx(_arrayBmp[4 * kMenuSave + scale - 1]); + _loadButton->setGfx(_arrayBmp[4 * kMenuLoad + scale - 1]); + _recallButton->setGfx(_arrayBmp[4 * kMenuRecall + scale - 1]); + _turboButton->setGfx(_arrayBmp[4 * kMenuTurbo + scale - 1 + ((_vm->_config._turboFl) ? 0 : 2)]); + _lookButton->setGfx(_arrayBmp[4 * kMenuLook + scale - 1]); + _inventButton->setGfx(_arrayBmp[4 * kMenuInventory + scale - 1]); } void TopMenu::loadBmpArr(Common::SeekableReadStream &in) { - arraySize = in.readUint16BE(); + _arraySize = in.readUint16BE(); - delete arrayBmp; - arrayBmp = new Graphics::Surface *[arraySize * 2]; - for (int i = 0; i < arraySize; i++) { + delete _arrayBmp; + _arrayBmp = new Graphics::Surface *[_arraySize * 2]; + for (int i = 0; i < _arraySize; i++) { uint16 bmpSize = in.readUint16BE(); uint32 filPos = in.pos(); Common::SeekableSubReadStream stream(&in, filPos, filPos + bmpSize); @@ -137,28 +137,28 @@ void TopMenu::loadBmpArr(Common::SeekableReadStream &in) { if (bitmapSrc->format.bytesPerPixel == 1) error("TopMenu::loadBmpArr(): Unhandled paletted image"); - arrayBmp[i * 2] = bitmapSrc->convertTo(g_system->getOverlayFormat()); - arrayBmp[i * 2 + 1] = new Graphics::Surface(); - arrayBmp[i * 2 + 1]->create(arrayBmp[i * 2]->w * 2, arrayBmp[i * 2]->h * 2, g_system->getOverlayFormat()); - byte *src = (byte *)arrayBmp[i * 2]->pixels; - byte *dst = (byte *)arrayBmp[i * 2 + 1]->pixels; - - for (int j = 0; j < arrayBmp[i * 2]->h; j++) { - src = (byte *)arrayBmp[i * 2]->getBasePtr(0, j); - dst = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); - for (int k = arrayBmp[i * 2]->w; k > 0; k--) { - for (int m = arrayBmp[i * 2]->format.bytesPerPixel; m > 0; m--) { + _arrayBmp[i * 2] = bitmapSrc->convertTo(g_system->getOverlayFormat()); + _arrayBmp[i * 2 + 1] = new Graphics::Surface(); + _arrayBmp[i * 2 + 1]->create(_arrayBmp[i * 2]->w * 2, _arrayBmp[i * 2]->h * 2, g_system->getOverlayFormat()); + byte *src = (byte *)_arrayBmp[i * 2]->pixels; + byte *dst = (byte *)_arrayBmp[i * 2 + 1]->pixels; + + for (int j = 0; j < _arrayBmp[i * 2]->h; j++) { + src = (byte *)_arrayBmp[i * 2]->getBasePtr(0, j); + dst = (byte *)_arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); + for (int k = _arrayBmp[i * 2]->w; k > 0; k--) { + for (int m = _arrayBmp[i * 2]->format.bytesPerPixel; m > 0; m--) { *dst++ = *src++; } - src -= arrayBmp[i * 2]->format.bytesPerPixel; + src -= _arrayBmp[i * 2]->format.bytesPerPixel; - for (int m = arrayBmp[i * 2]->format.bytesPerPixel; m > 0; m--) { + for (int m = _arrayBmp[i * 2]->format.bytesPerPixel; m > 0; m--) { *dst++ = *src++; } } - src = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); - dst = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2 + 1); - for (int k = arrayBmp[i * 2 + 1]->pitch; k > 0; k--) { + src = (byte *)_arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); + dst = (byte *)_arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2 + 1); + for (int k = _arrayBmp[i * 2 + 1]->pitch; k > 0; k--) { *dst++ = *src++; } } @@ -171,12 +171,12 @@ void TopMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 d switch (command) { case kCmdWhat: close(); - _vm->getGameStatus().helpFl = true; + _vm->getGameStatus()._helpFl = true; break; case kCmdMusic: _vm->_sound->toggleMusic(); - _musicButton->setGfx(arrayBmp[4 * kMenuMusic + (g_system->getOverlayWidth() > 320 ? 2 : 1) - 1 + ((_vm->_config.musicFl) ? 0 : 2)]); + _musicButton->setGfx(_arrayBmp[4 * kMenuMusic + (g_system->getOverlayWidth() > 320 ? 2 : 1) - 1 + ((_vm->_config._musicFl) ? 0 : 2)]); _musicButton->draw(); g_gui.theme()->updateScreen(); g_system->updateScreen(); @@ -194,8 +194,8 @@ void TopMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 d break; case kCmdSave: close(); - if (_vm->getGameStatus().viewState == kViewPlay) { - if (_vm->getGameStatus().gameOverFl) + if (_vm->getGameStatus()._viewState == kViewPlay) { + if (_vm->getGameStatus()._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -207,7 +207,7 @@ void TopMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 d break; case kCmdRecall: close(); - _vm->getGameStatus().recallFl = true; + _vm->getGameStatus()._recallFl = true; break; case kCmdTurbo: _vm->_parser->switchTurbo(); diff --git a/engines/hugo/dialogs.h b/engines/hugo/dialogs.h index 4e710ff2f8..114bcf56a9 100644 --- a/engines/hugo/dialogs.h +++ b/engines/hugo/dialogs.h @@ -94,8 +94,8 @@ protected: GUI::PicButtonWidget *_lookButton; GUI::PicButtonWidget *_inventButton; - Graphics::Surface **arrayBmp; - uint16 arraySize; + Graphics::Surface **_arrayBmp; + uint16 _arraySize; }; class EntryDialog : public GUI::Dialog { diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp index fa18d6b791..fbe39b3a0c 100644 --- a/engines/hugo/display.cpp +++ b/engines/hugo/display.cpp @@ -85,43 +85,43 @@ Screen::Screen(HugoEngine *vm) : _vm(vm) { fontLoadedFl[i] = false; } for (int i = 0; i < kBlitListSize; i++) { - _dlBlistList[i].x = 0; - _dlBlistList[i].y = 0; - _dlBlistList[i].dx = 0; - _dlBlistList[i].dy = 0; + _dlBlistList[i]._x = 0; + _dlBlistList[i]._y = 0; + _dlBlistList[i]._dx = 0; + _dlBlistList[i]._dy = 0; } for (int i = 0; i < kRectListSize; i++) { - _dlAddList[i].x = 0; - _dlAddList[i].y = 0; - _dlAddList[i].dx = 0; - _dlAddList[i].dy = 0; - _dlRestoreList[i].x = 0; - _dlRestoreList[i].y = 0; - _dlRestoreList[i].dx = 0; - _dlRestoreList[i].dy = 0; + _dlAddList[i]._x = 0; + _dlAddList[i]._y = 0; + _dlAddList[i]._dx = 0; + _dlAddList[i]._dy = 0; + _dlRestoreList[i]._x = 0; + _dlRestoreList[i]._y = 0; + _dlRestoreList[i]._dx = 0; + _dlRestoreList[i]._dy = 0; } } Screen::~Screen() { } -icondib_t &Screen::getIconBuffer() { +Icondib &Screen::getIconBuffer() { return _iconBuffer; } -viewdib_t &Screen::getBackBuffer() { +Viewdib &Screen::getBackBuffer() { return _backBuffer; } -viewdib_t &Screen::getBackBufferBackup() { +Viewdib &Screen::getBackBufferBackup() { return _backBufferBackup; } -viewdib_t &Screen::getFrontBuffer() { +Viewdib &Screen::getFrontBuffer() { return _frontBuffer; } -viewdib_t &Screen::getGUIBuffer() { +Viewdib &Screen::getGUIBuffer() { return _GUIBuffer; } @@ -149,7 +149,7 @@ void Screen::initDisplay() { /** * Move an image from source to destination */ -void Screen::moveImage(image_pt srcImage, const int16 x1, const int16 y1, const int16 dx, int16 dy, const int16 width1, image_pt dstImage, const int16 x2, const int16 y2, const int16 width2) { +void Screen::moveImage(ImagePtr srcImage, const int16 x1, const int16 y1, const int16 dx, int16 dy, const int16 width1, ImagePtr dstImage, const int16 x2, const int16 y2, const int16 width2) { debugC(3, kDebugDisplay, "moveImage(srcImage, %d, %d, %d, %d, %d, dstImage, %d, %d, %d)", x1, y1, dx, dy, width1, x2, y2, width2); int16 wrap_src = width1 - dx; // Wrap to next src row @@ -236,16 +236,16 @@ void Screen::setBackgroundColor(const uint16 color) { * Merge an object frame into _frontBuffer at sx, sy and update rectangle list. * If fore TRUE, force object above any overlay */ -void Screen::displayFrame(const int sx, const int sy, seq_t *seq, const bool foreFl) { +void Screen::displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) { debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0); - image_pt image = seq->imagePtr; // Ptr to object image data - image_pt subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer - int16 frontBufferwrap = kXPix - seq->x2 - 1; // Wraps dest_p after each line - int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1; - overlayState_t overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object - for (uint16 y = 0; y < seq->lines; y++) { // Each line in object - for (uint16 x = 0; x <= seq->x2; x++) { + ImagePtr image = seq->_imagePtr; // Ptr to object image data + ImagePtr subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer + int16 frontBufferwrap = kXPix - seq->_x2 - 1; // Wraps dest_p after each line + int16 imageWrap = seq->_bytesPerLine8 - seq->_x2 - 1; + OverlayState overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object + for (uint16 y = 0; y < seq->_lines; y++) { // Each line in object + for (uint16 x = 0; x <= seq->_x2; x++) { if (*image) { // Non-transparent byte ovlBound = _vm->_object->getFirstOverlay((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set @@ -265,24 +265,24 @@ void Screen::displayFrame(const int sx, const int sy, seq_t *seq, const bool for } // Add this rectangle to the display list - displayList(kDisplayAdd, sx, sy, seq->x2 + 1, seq->lines); + displayList(kDisplayAdd, sx, sy, seq->_x2 + 1, seq->_lines); } /** * Merge rectangles A,B leaving result in B */ -void Screen::merge(const rect_t *rectA, rect_t *rectB) { +void Screen::merge(const Rect *rectA, Rect *rectB) { debugC(6, kDebugDisplay, "merge()"); - int16 xa = rectA->x + rectA->dx; // Find x2,y2 for each rectangle - int16 xb = rectB->x + rectB->dx; - int16 ya = rectA->y + rectA->dy; - int16 yb = rectB->y + rectB->dy; + int16 xa = rectA->_x + rectA->_dx; // Find x2,y2 for each rectangle + int16 xb = rectB->_x + rectB->_dx; + int16 ya = rectA->_y + rectA->_dy; + int16 yb = rectB->_y + rectB->_dy; - rectB->x = MIN(rectA->x, rectB->x); // Minimum x,y - rectB->y = MIN(rectA->y, rectB->y); - rectB->dx = MAX(xa, xb) - rectB->x; // Maximum dx,dy - rectB->dy = MAX(ya, yb) - rectB->y; + rectB->_x = MIN(rectA->_x, rectB->_x); // Minimum x,y + rectB->_y = MIN(rectA->_y, rectB->_y); + rectB->_dx = MAX(xa, xb) - rectB->_x; // Maximum dx,dy + rectB->_dy = MAX(ya, yb) - rectB->_y; } /** @@ -291,7 +291,7 @@ void Screen::merge(const rect_t *rectA, rect_t *rectB) { * of blist. bmax is the max size of the blist. Note that blist can * have holes, in which case dx = 0. Returns used length of blist. */ -int16 Screen::mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 blen) { +int16 Screen::mergeLists(Rect *list, Rect *blist, const int16 len, int16 blen) { debugC(4, kDebugDisplay, "mergeLists()"); int16 coalesce[kBlitListSize]; // List of overlapping rects @@ -299,9 +299,9 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 ble for (int16 a = 0; a < len; a++, list++) { // Compile list of overlapping rectangles in blit list int16 c = 0; - rect_t *bp = blist; + Rect *bp = blist; for (int16 b = 0; b < blen; b++, bp++) { - if (bp->dx) // blist entry used + if (bp->_dx) // blist entry used if (isOverlapping(list, bp)) coalesce[c++] = b; } @@ -316,9 +316,9 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 ble // Merge any more blist entries while (--c) { - rect_t *cp = &blist[coalesce[c]]; + Rect *cp = &blist[coalesce[c]]; merge(cp, bp); - cp->dx = 0; // Delete entry + cp->_dx = 0; // Delete entry } } } @@ -329,12 +329,12 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 ble * Process the display list * Trailing args are int16 x,y,dx,dy for the D_ADD operation */ -void Screen::displayList(dupdate_t update, ...) { +void Screen::displayList(Dupdate update, ...) { debugC(6, kDebugDisplay, "displayList()"); int16 blitLength = 0; // Length of blit list va_list marker; // Args used for D_ADD operation - rect_t *p; // Ptr to dlist entry + Rect *p; // Ptr to dlist entry switch (update) { case kDisplayInit: // Init lists, restore whole screen @@ -348,10 +348,10 @@ void Screen::displayList(dupdate_t update, ...) { } va_start(marker, update); // Initialize variable arguments p = &_dlAddList[_dlAddIndex]; - p->x = va_arg(marker, int); // x - p->y = va_arg(marker, int); // y - p->dx = va_arg(marker, int); // dx - p->dy = va_arg(marker, int); // dy + p->_x = va_arg(marker, int); // x + p->_y = va_arg(marker, int); // y + p->_dx = va_arg(marker, int); // dx + p->_dy = va_arg(marker, int); // dy va_end(marker); // Reset variable arguments _dlAddIndex++; break; @@ -359,8 +359,8 @@ void Screen::displayList(dupdate_t update, ...) { // Don't blit if newscreen just loaded because _frontBuffer will // get blitted via InvalidateRect() at end of this cycle // and blitting here causes objects to appear too soon. - if (_vm->getGameStatus().newScreenFl) { - _vm->getGameStatus().newScreenFl = false; + if (_vm->getGameStatus()._newScreenFl) { + _vm->getGameStatus()._newScreenFl = false; break; } @@ -370,15 +370,15 @@ void Screen::displayList(dupdate_t update, ...) { // Blit the combined blit-list for (_dlRestoreIndex = 0, p = _dlBlistList; _dlRestoreIndex < blitLength; _dlRestoreIndex++, p++) { - if (p->dx) // Marks a used entry - displayRect(p->x, p->y, p->dx, p->dy); + if (p->_dx) // Marks a used entry + displayRect(p->_x, p->_y, p->_dx, p->_dy); } break; case kDisplayRestore: // Restore each rectangle for (_dlRestoreIndex = 0, p = _dlAddList; _dlRestoreIndex < _dlAddIndex; _dlRestoreIndex++, p++) { // Restoring from _backBuffer to _frontBuffer _dlRestoreList[_dlRestoreIndex] = *p; // Copy add-list to restore-list - moveImage(_backBuffer, p->x, p->y, p->dx, p->dy, kXPix, _frontBuffer, p->x, p->y, kXPix); + moveImage(_backBuffer, p->_x, p->_y, p->_dx, p->_dy, kXPix, _frontBuffer, p->_x, p->_y, kXPix); } _dlAddIndex = 0; // Reset add-list break; @@ -488,7 +488,7 @@ void Screen::userHelp() const { "F5 - Restore game\n" "F6 - Inventory\n" "F8 - Turbo button\n" - "F9 - Boss button\n\n" + "\n" "ESC - Return to game"); } @@ -563,7 +563,7 @@ void Screen::initNewScreenDisplay() { displayBackground(); // Stop premature object display in Display_list(D_DISPLAY) - _vm->getGameStatus().newScreenFl = true; + _vm->getGameStatus()._newScreenFl = true; } /** @@ -627,20 +627,20 @@ void Screen::hideCursor() { CursorMan.showMouse(false); } -bool Screen::isInX(const int16 x, const rect_t *rect) const { - return (x >= rect->x) && (x <= rect->x + rect->dx); +bool Screen::isInX(const int16 x, const Rect *rect) const { + return (x >= rect->_x) && (x <= rect->_x + rect->_dx); } -bool Screen::isInY(const int16 y, const rect_t *rect) const { - return (y >= rect->y) && (y <= rect->y + rect->dy); +bool Screen::isInY(const int16 y, const Rect *rect) const { + return (y >= rect->_y) && (y <= rect->_y + rect->_dy); } /** * Check if two rectangles are overlapping */ -bool Screen::isOverlapping(const rect_t *rectA, const rect_t *rectB) const { - return (isInX(rectA->x, rectB) || isInX(rectA->x + rectA->dx, rectB) || isInX(rectB->x, rectA) || isInX(rectB->x + rectB->dx, rectA)) && - (isInY(rectA->y, rectB) || isInY(rectA->y + rectA->dy, rectB) || isInY(rectB->y, rectA) || isInY(rectB->y + rectB->dy, rectA)); +bool Screen::isOverlapping(const Rect *rectA, const Rect *rectB) const { + return (isInX(rectA->_x, rectB) || isInX(rectA->_x + rectA->_dx, rectB) || isInX(rectB->_x, rectA) || isInX(rectB->_x + rectB->_dx, rectA)) && + (isInY(rectA->_y, rectB) || isInY(rectA->_y + rectA->_dy, rectB) || isInY(rectB->_y, rectA) || isInY(rectB->_y + rectB->_dy, rectA)); } /** @@ -650,19 +650,19 @@ bool Screen::isOverlapping(const rect_t *rectA, const rect_t *rectB) const { * White = Fix objects, parts of background */ void Screen::drawBoundaries() { - if (!_vm->getGameStatus().showBoundariesFl) + if (!_vm->getGameStatus()._showBoundariesFl) return; _vm->_mouse->drawHotspots(); for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; // Get pointer to object - if (obj->screenIndex == *_vm->_screen_p) { - if ((obj->currImagePtr != 0) && (obj->cycling != kCycleInvisible)) - drawRectangle(false, obj->x + obj->currImagePtr->x1, obj->y + obj->currImagePtr->y1, - obj->x + obj->currImagePtr->x2, obj->y + obj->currImagePtr->y2, _TLIGHTGREEN); - else if ((obj->currImagePtr == 0) && (obj->vxPath != 0) && !obj->carriedFl) - drawRectangle(false, obj->oldx, obj->oldy, obj->oldx + obj->vxPath, obj->oldy + obj->vyPath, _TBRIGHTWHITE); + Object *obj = &_vm->_object->_objects[i]; // Get pointer to object + if (obj->_screenIndex == *_vm->_screenPtr) { + if ((obj->_currImagePtr != 0) && (obj->_cycling != kCycleInvisible)) + drawRectangle(false, obj->_x + obj->_currImagePtr->_x1, obj->_y + obj->_currImagePtr->_y1, + obj->_x + obj->_currImagePtr->_x2, obj->_y + obj->_currImagePtr->_y2, _TLIGHTGREEN); + else if ((obj->_currImagePtr == 0) && (obj->_vxPath != 0) && !obj->_carriedFl) + drawRectangle(false, obj->_oldx, obj->_oldy, obj->_oldx + obj->_vxPath, obj->_oldy + obj->_vyPath, _TBRIGHTWHITE); } } g_system->copyRectToScreen(_frontBuffer, 320, 0, 0, 320, 200); @@ -730,12 +730,12 @@ void Screen_v1d::loadFontArr(Common::ReadStream &in) { * processed object by looking down the current column for an overlay * base byte set (in which case the object is foreground). */ -overlayState_t Screen_v1d::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) { +OverlayState Screen_v1d::findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) { debugC(4, kDebugDisplay, "findOvl()"); - uint16 index = (uint16)(dst_p - _frontBuffer) >> 3; + uint16 index = (uint16)(dstPtr - _frontBuffer) >> 3; - for (int i = 0; i < seq_p->lines-y; i++) { // Each line in object + for (int i = 0; i < seqPtr->_lines-y; i++) { // Each line in object if (_vm->_object->getBaseBoundary(index)) // If any overlay base byte is non-zero then the object is foreground, else back. return kOvlForeground; index += kCompLineSize; @@ -799,14 +799,14 @@ void Screen_v1w::loadFontArr(Common::ReadStream &in) { * processed object by looking down the current column for an overlay * base bit set (in which case the object is foreground). */ -overlayState_t Screen_v1w::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) { +OverlayState Screen_v1w::findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) { debugC(4, kDebugDisplay, "findOvl()"); - for (; y < seq_p->lines; y++) { // Each line in object - byte ovb = _vm->_object->getBaseBoundary((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits - if (ovb & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set + for (; y < seqPtr->_lines; y++) { // Each line in object + byte ovb = _vm->_object->getBaseBoundary((uint16)(dstPtr - _frontBuffer) >> 3); // Ptr into overlay bits + if (ovb & (0x80 >> ((uint16)(dstPtr - _frontBuffer) & 7))) // Overlay bit is set return kOvlForeground; // Found a bit - must be foreground - dst_p += kXPix; + dstPtr += kXPix; } return kOvlBackground; // No bits set, must be background diff --git a/engines/hugo/display.h b/engines/hugo/display.h index 38c63e9fe5..00dc1b743c 100644 --- a/engines/hugo/display.h +++ b/engines/hugo/display.h @@ -31,18 +31,18 @@ #define HUGO_DISPLAY_H namespace Hugo { -enum overlayState_t {kOvlUndef, kOvlForeground, kOvlBackground}; // Overlay state +enum OverlayState {kOvlUndef, kOvlForeground, kOvlBackground}; // Overlay state static const int kCenter = -1; // Used to center text in x class Screen { public: - struct rect_t { // Rectangle used in Display list - int16 x; // Position in dib - int16 y; // Position in dib - int16 dx; // width - int16 dy; // height + struct Rect { // Rectangle used in Display list + int16 _x; // Position in dib + int16 _y; // Position in dib + int16 _dx; // width + int16 _dy; // height }; Screen(HugoEngine *vm); @@ -55,8 +55,8 @@ public: int16 stringLength(const char *s) const; void displayBackground(); - void displayFrame(const int sx, const int sy, seq_t *seq, const bool foreFl); - void displayList(dupdate_t update, ...); + void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl); + void displayList(Dupdate update, ...); void displayRect(const int16 x, const int16 y, const int16 dx, const int16 dy); void drawBoundaries(); void drawRectangle(const bool filledFl, const int16 x1, const int16 y1, const int16 x2, const int16 y2, const int color); @@ -67,7 +67,7 @@ public: void initDisplay(); void initNewScreenDisplay(); void loadPalette(Common::ReadStream &in); - void moveImage(image_pt srcImage, const int16 x1, const int16 y1, const int16 dx, int16 dy, const int16 width1, image_pt dstImage, const int16 x2, const int16 y2, const int16 width2); + void moveImage(ImagePtr srcImage, const int16 x1, const int16 y1, const int16 dx, int16 dy, const int16 width1, ImagePtr dstImage, const int16 x2, const int16 y2, const int16 width2); void remapPal(uint16 oldIndex, uint16 newIndex); void resetInventoryObjId(); void restorePal(Common::ReadStream *f); @@ -80,11 +80,11 @@ public: void userHelp() const; void writeStr(int16 sx, const int16 sy, const char *s, const byte color); - icondib_t &getIconBuffer(); - viewdib_t &getBackBuffer(); - viewdib_t &getBackBufferBackup(); - viewdib_t &getFrontBuffer(); - viewdib_t &getGUIBuffer(); + Icondib &getIconBuffer(); + Viewdib &getBackBuffer(); + Viewdib &getBackBufferBackup(); + Viewdib &getFrontBuffer(); + Viewdib &getGUIBuffer(); protected: HugoEngine *_vm; @@ -108,37 +108,37 @@ protected: byte *_mainPalette; int16 _arrayFontSize[kNumFonts]; - viewdib_t _frontBuffer; + Viewdib _frontBuffer; - inline bool isInX(const int16 x, const rect_t *rect) const; - inline bool isInY(const int16 y, const rect_t *rect) const; - inline bool isOverlapping(const rect_t *rectA, const rect_t *rectB) const; + inline bool isInX(const int16 x, const Rect *rect) const; + inline bool isInY(const int16 y, const Rect *rect) const; + inline bool isOverlapping(const Rect *rectA, const Rect *rectB) const; - virtual overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) = 0; + virtual OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) = 0; private: byte *_curPalette; byte _iconImage[kInvDx * kInvDy]; byte _paletteSize; - icondib_t _iconBuffer; // Inventory icon DIB + Icondib _iconBuffer; // Inventory icon DIB - int16 mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 blen); + int16 mergeLists(Rect *list, Rect *blist, const int16 len, int16 blen); int16 center(const char *s) const; - viewdib_t _backBuffer; - viewdib_t _GUIBuffer; // User interface images - viewdib_t _backBufferBackup; // Backup _backBuffer during inventory + Viewdib _backBuffer; + Viewdib _GUIBuffer; // User interface images + Viewdib _backBufferBackup; // Backup _backBuffer during inventory // Formerly static variables used by displayList() int16 _dlAddIndex, _dlRestoreIndex; // Index into add/restore lists - rect_t _dlRestoreList[kRectListSize]; // The restore list - rect_t _dlAddList[kRectListSize]; // The add list - rect_t _dlBlistList[kBlitListSize]; // The blit list + Rect _dlRestoreList[kRectListSize]; // The restore list + Rect _dlAddList[kRectListSize]; // The add list + Rect _dlBlistList[kBlitListSize]; // The blit list // void createPal(); - void merge(const rect_t *rectA, rect_t *rectB); + void merge(const Rect *rectA, Rect *rectB); void writeChr(const int sx, const int sy, const byte color, const char *local_fontdata); }; @@ -150,7 +150,7 @@ public: void loadFont(int16 fontId); void loadFontArr(Common::ReadStream &in); protected: - overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y); + OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y); }; class Screen_v1w : public Screen { @@ -161,7 +161,7 @@ public: void loadFont(int16 fontId); void loadFontArr(Common::ReadStream &in); protected: - overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y); + OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y); }; } // End of namespace Hugo diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index 2217cef92a..15ee06c82a 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -53,8 +53,8 @@ static const int s_bootCypherLen = sizeof(s_bootCypher) - 1; FileManager::FileManager(HugoEngine *vm) : _vm(vm) { - has_read_header = false; - firstUIFFl = true; + _hasReadHeader = false; + _firstUIFFl = true; } FileManager::~FileManager() { @@ -91,8 +91,8 @@ const char *FileManager::getUifFilename() const { * Convert 4 planes (RGBI) data to 8-bit DIB format * Return original plane data ptr */ -byte *FileManager::convertPCC(byte *p, const uint16 y, const uint16 bpl, image_pt dataPtr) const { - debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, image_pt data_p)", y, bpl); +byte *FileManager::convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const { + debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, ImagePtr dataPtr)", y, bpl); dataPtr += y * bpl * 8; // Point to correct DIB line for (int16 r = 0, g = bpl, b = g + bpl, i = b + bpl; r < bpl; r++, g++, b++, i++) { // Each byte in all planes @@ -107,47 +107,47 @@ byte *FileManager::convertPCC(byte *p, const uint16 y, const uint16 bpl, image_p } /** - * Read a pcx file of length len. Use supplied seq_p and image_p or - * allocate space if NULL. Name used for errors. Returns address of seq_p + * Read a pcx file of length len. Use supplied seqPtr and image_p or + * allocate space if NULL. Name used for errors. Returns address of seqPtr * Set first TRUE to initialize b_index (i.e. not reading a sequential image in file). */ -seq_t *FileManager::readPCX(Common::ReadStream &f, seq_t *seqPtr, byte *imagePtr, const bool firstFl, const char *name) { +Seq *FileManager::readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) { debugC(1, kDebugFile, "readPCX(..., %s)", name); // Read in the PCC header and check consistency - PCC_header.mfctr = f.readByte(); - PCC_header.vers = f.readByte(); - PCC_header.enc = f.readByte(); - PCC_header.bpx = f.readByte(); - PCC_header.x1 = f.readUint16LE(); - PCC_header.y1 = f.readUint16LE(); - PCC_header.x2 = f.readUint16LE(); - PCC_header.y2 = f.readUint16LE(); - PCC_header.xres = f.readUint16LE(); - PCC_header.yres = f.readUint16LE(); - f.read(PCC_header.palette, sizeof(PCC_header.palette)); - PCC_header.vmode = f.readByte(); - PCC_header.planes = f.readByte(); - PCC_header.bytesPerLine = f.readUint16LE(); - f.read(PCC_header.fill2, sizeof(PCC_header.fill2)); - - if (PCC_header.mfctr != 10) + _PCCHeader._mfctr = f.readByte(); + _PCCHeader._vers = f.readByte(); + _PCCHeader._enc = f.readByte(); + _PCCHeader._bpx = f.readByte(); + _PCCHeader._x1 = f.readUint16LE(); + _PCCHeader._y1 = f.readUint16LE(); + _PCCHeader._x2 = f.readUint16LE(); + _PCCHeader._y2 = f.readUint16LE(); + _PCCHeader._xres = f.readUint16LE(); + _PCCHeader._yres = f.readUint16LE(); + f.read(_PCCHeader._palette, sizeof(_PCCHeader._palette)); + _PCCHeader._vmode = f.readByte(); + _PCCHeader._planes = f.readByte(); + _PCCHeader._bytesPerLine = f.readUint16LE(); + f.read(_PCCHeader._fill2, sizeof(_PCCHeader._fill2)); + + if (_PCCHeader._mfctr != 10) error("Bad data file format: %s", name); - // Allocate memory for seq_t if 0 + // Allocate memory for Seq if 0 if (seqPtr == 0) { - if ((seqPtr = (seq_t *)malloc(sizeof(seq_t))) == 0) + if ((seqPtr = (Seq *)malloc(sizeof(Seq))) == 0) error("Insufficient memory to run game."); } // Find size of image data in 8-bit DIB format // Note save of x2 - marks end of valid data before garbage - uint16 bytesPerLine4 = PCC_header.bytesPerLine * 4; // 4-bit bpl - seqPtr->bytesPerLine8 = bytesPerLine4 * 2; // 8-bit bpl - seqPtr->lines = PCC_header.y2 - PCC_header.y1 + 1; - seqPtr->x2 = PCC_header.x2 - PCC_header.x1 + 1; + uint16 bytesPerLine4 = _PCCHeader._bytesPerLine * 4; // 4-bit bpl + seqPtr->_bytesPerLine8 = bytesPerLine4 * 2; // 8-bit bpl + seqPtr->_lines = _PCCHeader._y2 - _PCCHeader._y1 + 1; + seqPtr->_x2 = _PCCHeader._x2 - _PCCHeader._x1 + 1; // Size of the image - uint16 size = seqPtr->lines * seqPtr->bytesPerLine8; + uint16 size = seqPtr->_lines * seqPtr->_bytesPerLine8; // Allocate memory for image data if NULL if (imagePtr == 0) @@ -155,25 +155,25 @@ seq_t *FileManager::readPCX(Common::ReadStream &f, seq_t *seqPtr, byte *imagePtr assert(imagePtr); - seqPtr->imagePtr = imagePtr; + seqPtr->_imagePtr = imagePtr; // Process the image data, converting to 8-bit DIB format uint16 y = 0; // Current line index byte pline[kXPix]; // Hold 4 planes of data byte *p = pline; // Ptr to above - while (y < seqPtr->lines) { + while (y < seqPtr->_lines) { byte c = f.readByte(); if ((c & kRepeatMask) == kRepeatMask) { byte d = f.readByte(); // Read data byte for (int i = 0; i < (c & kLengthMask); i++) { *p++ = d; if ((uint16)(p - pline) == bytesPerLine4) - p = convertPCC(pline, y++, PCC_header.bytesPerLine, imagePtr); + p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr); } } else { *p++ = c; if ((uint16)(p - pline) == bytesPerLine4) - p = convertPCC(pline, y++, PCC_header.bytesPerLine, imagePtr); + p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr); } } return seqPtr; @@ -182,8 +182,8 @@ seq_t *FileManager::readPCX(Common::ReadStream &f, seq_t *seqPtr, byte *imagePtr /** * Read object file of PCC images into object supplied */ -void FileManager::readImage(const int objNum, object_t *objPtr) { - debugC(1, kDebugFile, "readImage(%d, object_t *objPtr)", objNum); +void FileManager::readImage(const int objNum, Object *objPtr) { + debugC(1, kDebugFile, "readImage(%d, Object *objPtr)", objNum); /** * Structure of object file lookup entry @@ -193,7 +193,7 @@ void FileManager::readImage(const int objNum, object_t *objPtr) { uint32 objLength; }; - if (!objPtr->seqNumb) // This object has no images + if (!objPtr->_seqNumb) // This object has no images return; if (_vm->isPacked()) { @@ -206,72 +206,72 @@ void FileManager::readImage(const int objNum, object_t *objPtr) { _objectsArchive.seek(objBlock.objOffset, SEEK_SET); } else { Common::String buf; - buf = _vm->_picDir + Common::String(_vm->_text->getNoun(objPtr->nounIndex, 0)) + ".PIX"; + buf = _vm->_picDir + Common::String(_vm->_text->getNoun(objPtr->_nounIndex, 0)) + ".PIX"; if (!_objectsArchive.open(buf)) { - buf = Common::String(_vm->_text->getNoun(objPtr->nounIndex, 0)) + ".PIX"; + buf = Common::String(_vm->_text->getNoun(objPtr->_nounIndex, 0)) + ".PIX"; if (!_objectsArchive.open(buf)) error("File not found: %s", buf.c_str()); } } bool firstImgFl = true; // Initializes pcx read function - seq_t *seqPtr = 0; // Ptr to sequence structure + Seq *seqPtr = 0; // Ptr to sequence structure // Now read the images into an images list - for (int j = 0; j < objPtr->seqNumb; j++) { // for each sequence - for (int k = 0; k < objPtr->seqList[j].imageNbr; k++) { // each image + for (int j = 0; j < objPtr->_seqNumb; j++) { // for each sequence + for (int k = 0; k < objPtr->_seqList[j]._imageNbr; k++) { // each image if (k == 0) { // First image // Read this image - allocate both seq and image memory - seqPtr = readPCX(_objectsArchive, 0, 0, firstImgFl, _vm->_text->getNoun(objPtr->nounIndex, 0)); - objPtr->seqList[j].seqPtr = seqPtr; + seqPtr = readPCX(_objectsArchive, 0, 0, firstImgFl, _vm->_text->getNoun(objPtr->_nounIndex, 0)); + objPtr->_seqList[j]._seqPtr = seqPtr; firstImgFl = false; } else { // Subsequent image // Read this image - allocate both seq and image memory - seqPtr->nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstImgFl, _vm->_text->getNoun(objPtr->nounIndex, 0)); - seqPtr = seqPtr->nextSeqPtr; + seqPtr->_nextSeqPtr = readPCX(_objectsArchive, 0, 0, firstImgFl, _vm->_text->getNoun(objPtr->_nounIndex, 0)); + seqPtr = seqPtr->_nextSeqPtr; } // Compute the bounding box - x1, x2, y1, y2 // Note use of x2 - marks end of valid data in row - uint16 x2 = seqPtr->x2; - seqPtr->x1 = seqPtr->x2; - seqPtr->x2 = 0; - seqPtr->y1 = seqPtr->lines; - seqPtr->y2 = 0; - - image_pt dibPtr = seqPtr->imagePtr; - for (int y = 0; y < seqPtr->lines; y++, dibPtr += seqPtr->bytesPerLine8 - x2) { + uint16 x2 = seqPtr->_x2; + seqPtr->_x1 = seqPtr->_x2; + seqPtr->_x2 = 0; + seqPtr->_y1 = seqPtr->_lines; + seqPtr->_y2 = 0; + + ImagePtr dibPtr = seqPtr->_imagePtr; + for (int y = 0; y < seqPtr->_lines; y++, dibPtr += seqPtr->_bytesPerLine8 - x2) { for (int x = 0; x < x2; x++) { if (*dibPtr++) { // Some data found - if (x < seqPtr->x1) - seqPtr->x1 = x; - if (x > seqPtr->x2) - seqPtr->x2 = x; - if (y < seqPtr->y1) - seqPtr->y1 = y; - if (y > seqPtr->y2) - seqPtr->y2 = y; + if (x < seqPtr->_x1) + seqPtr->_x1 = x; + if (x > seqPtr->_x2) + seqPtr->_x2 = x; + if (y < seqPtr->_y1) + seqPtr->_y1 = y; + if (y > seqPtr->_y2) + seqPtr->_y2 = y; } } } } assert(seqPtr); - seqPtr->nextSeqPtr = objPtr->seqList[j].seqPtr; // loop linked list to head + seqPtr->_nextSeqPtr = objPtr->_seqList[j]._seqPtr; // loop linked list to head } // Set the current image sequence to first or last - switch (objPtr->cycling) { + switch (objPtr->_cycling) { case kCycleInvisible: // (May become visible later) case kCycleAlmostInvisible: case kCycleNotCycling: case kCycleForward: - objPtr->currImagePtr = objPtr->seqList[0].seqPtr; + objPtr->_currImagePtr = objPtr->_seqList[0]._seqPtr; break; case kCycleBackward: - objPtr->currImagePtr = seqPtr; + objPtr->_currImagePtr = seqPtr; break; default: - warning("Unexpected cycling: %d", objPtr->cycling); + warning("Unexpected cycling: %d", objPtr->_cycling); } if (!_vm->isPacked()) @@ -282,7 +282,7 @@ void FileManager::readImage(const int objNum, object_t *objPtr) { * Read sound (or music) file data. Call with SILENCE to free-up * any allocated memory. Also returns size of data */ -sound_pt FileManager::getSound(const int16 sound, uint16 *size) { +SoundPtr FileManager::getSound(const int16 sound, uint16 *size) { debugC(1, kDebugFile, "getSound(%d)", sound); // No more to do if SILENCE (called for cleanup purposes) @@ -296,27 +296,27 @@ sound_pt FileManager::getSound(const int16 sound, uint16 *size) { return 0; } - if (!has_read_header) { + if (!_hasReadHeader) { for (int i = 0; i < kMaxSounds; i++) { - s_hdr[i].size = fp.readUint16LE(); - s_hdr[i].offset = fp.readUint32LE(); + _soundHdr[i]._size = fp.readUint16LE(); + _soundHdr[i]._offset = fp.readUint32LE(); } if (fp.err()) error("Wrong sound file format"); - has_read_header = true; + _hasReadHeader = true; } - *size = s_hdr[sound].size; + *size = _soundHdr[sound]._size; if (*size == 0) error("Wrong sound file format or missing sound %d", sound); // Allocate memory for sound or music, if possible - sound_pt soundPtr = (byte *)malloc(s_hdr[sound].size); // Ptr to sound data + SoundPtr soundPtr = (byte *)malloc(_soundHdr[sound]._size); // Ptr to sound data assert(soundPtr); // Seek to data and read it - fp.seek(s_hdr[sound].offset, SEEK_SET); - if (fp.read(soundPtr, s_hdr[sound].size) != s_hdr[sound].size) + fp.seek(_soundHdr[sound]._offset, SEEK_SET); + if (fp.read(soundPtr, _soundHdr[sound]._size) != _soundHdr[sound]._size) error("Wrong sound file format"); fp.close(); @@ -330,15 +330,12 @@ sound_pt FileManager::getSound(const int16 sound, uint16 *size) { bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip.c_str()); - const EnginePlugin *plugin = NULL; int16 savegameId; Common::String savegameDescription; - EngineMan.findGame(_vm->getGameId(), &plugin); if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); - dialog->setSaveMode(true); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + savegameId = dialog->runModalWithCurrentTarget(); savegameDescription = dialog->getResultString(); delete dialog; } else { @@ -385,7 +382,7 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { _vm->_object->saveObjects(out); - const status_t &gameStatus = _vm->getGameStatus(); + const Status &gameStatus = _vm->getGameStatus(); // Save whether hero image is swapped out->writeByte(_vm->_heroImage); @@ -394,13 +391,13 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { out->writeSint16BE(_vm->getScore()); // Save story mode - out->writeByte((gameStatus.storyModeFl) ? 1 : 0); + out->writeByte((gameStatus._storyModeFl) ? 1 : 0); // Save jumpexit mode out->writeByte((_vm->_mouse->getJumpExitFl()) ? 1 : 0); // Save gameover status - out->writeByte((gameStatus.gameOverFl) ? 1 : 0); + out->writeByte((gameStatus._gameOverFl) ? 1 : 0); // Save screen states for (int i = 0; i < _vm->_numStates; i++) @@ -411,17 +408,17 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { _vm->_screen->savePal(out); // Save maze status - out->writeByte((_vm->_maze.enabledFl) ? 1 : 0); - out->writeByte(_vm->_maze.size); - out->writeSint16BE(_vm->_maze.x1); - out->writeSint16BE(_vm->_maze.y1); - out->writeSint16BE(_vm->_maze.x2); - out->writeSint16BE(_vm->_maze.y2); - out->writeSint16BE(_vm->_maze.x3); - out->writeSint16BE(_vm->_maze.x4); - out->writeByte(_vm->_maze.firstScreenIndex); - - out->writeByte((byte)_vm->getGameStatus().viewState); + out->writeByte((_vm->_maze._enabledFl) ? 1 : 0); + out->writeByte(_vm->_maze._size); + out->writeSint16BE(_vm->_maze._x1); + out->writeSint16BE(_vm->_maze._y1); + out->writeSint16BE(_vm->_maze._x2); + out->writeSint16BE(_vm->_maze._y2); + out->writeSint16BE(_vm->_maze._x3); + out->writeSint16BE(_vm->_maze._x4); + out->writeByte(_vm->_maze._firstScreenIndex); + + out->writeByte((byte)_vm->getGameStatus()._viewState); out->finalize(); @@ -436,14 +433,11 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) { bool FileManager::restoreGame(const int16 slot) { debugC(1, kDebugFile, "restoreGame(%d)", slot); - const EnginePlugin *plugin = NULL; int16 savegameId; - EngineMan.findGame(_vm->getGameId(), &plugin); if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); - dialog->setSaveMode(false); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } else { savegameId = slot; @@ -492,14 +486,14 @@ bool FileManager::restoreGame(const int16 slot) { _vm->_object->swapImages(kHeroIndex, _vm->_heroImage); _vm->_heroImage = heroImg; - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); int score = in->readSint16BE(); _vm->setScore(score); - gameStatus.storyModeFl = (in->readByte() == 1); + gameStatus._storyModeFl = (in->readByte() == 1); _vm->_mouse->setJumpExitFl(in->readByte() == 1); - gameStatus.gameOverFl = (in->readByte() == 1); + gameStatus._gameOverFl = (in->readByte() == 1); for (int i = 0; i < _vm->_numStates; i++) _vm->_screenStates[i] = in->readByte(); @@ -509,18 +503,18 @@ bool FileManager::restoreGame(const int16 slot) { _vm->_screen->restorePal(in); // Restore maze status - _vm->_maze.enabledFl = (in->readByte() == 1); - _vm->_maze.size = in->readByte(); - _vm->_maze.x1 = in->readSint16BE(); - _vm->_maze.y1 = in->readSint16BE(); - _vm->_maze.x2 = in->readSint16BE(); - _vm->_maze.y2 = in->readSint16BE(); - _vm->_maze.x3 = in->readSint16BE(); - _vm->_maze.x4 = in->readSint16BE(); - _vm->_maze.firstScreenIndex = in->readByte(); - - _vm->_scheduler->restoreScreen(*_vm->_screen_p); - if ((_vm->getGameStatus().viewState = (vstate_t) in->readByte()) != kViewPlay) + _vm->_maze._enabledFl = (in->readByte() == 1); + _vm->_maze._size = in->readByte(); + _vm->_maze._x1 = in->readSint16BE(); + _vm->_maze._y1 = in->readSint16BE(); + _vm->_maze._x2 = in->readSint16BE(); + _vm->_maze._y2 = in->readSint16BE(); + _vm->_maze._x3 = in->readSint16BE(); + _vm->_maze._x4 = in->readSint16BE(); + _vm->_maze._firstScreenIndex = in->readByte(); + + _vm->_scheduler->restoreScreen(*_vm->_screenPtr); + if ((_vm->getGameStatus()._viewState = (Vstate) in->readByte()) != kViewPlay) _vm->_screen->hideCursor(); @@ -529,49 +523,6 @@ bool FileManager::restoreGame(const int16 slot) { } /** - * Read the encrypted text from the boot file and print it - */ -void FileManager::printBootText() { - debugC(1, kDebugFile, "printBootText()"); - - Common::File ofp; - if (!ofp.open(getBootFilename())) { - if (_vm->getPlatform() == Common::kPlatformPC) { - //TODO initialize properly _boot structure - warning("printBootText - Skipping as Dos versions may be a freeware or shareware"); - return; - } else { - Utils::notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename())); - _vm->getGameStatus().doQuitFl = true; - return; - } - } - - // Allocate space for the text and print it - char *buf = (char *)malloc(_vm->_boot.exit_len + 1); - if (buf) { - // Skip over the boot structure (already read) and read exit text - ofp.seek((long)sizeof(_vm->_boot), SEEK_SET); - if (ofp.read(buf, _vm->_boot.exit_len) != (size_t)_vm->_boot.exit_len) { - Utils::notifyBox(Common::String::format("Error while reading startup file '%s'", getBootFilename())); - _vm->getGameStatus().doQuitFl = true; - return; - } - - // Decrypt the exit text, using CRYPT substring - int i; - for (i = 0; i < _vm->_boot.exit_len; i++) - buf[i] ^= s_bootCypher[i % s_bootCypherLen]; - - buf[i] = '\0'; - Utils::notifyBox(buf); - } - - free(buf); - ofp.close(); -} - -/** * Reads boot file for program environment. Fatal error if not there or * file checksum is bad. De-crypts structure while checking checksum */ @@ -583,32 +534,32 @@ void FileManager::readBootFile() { if (_vm->_gameVariant == kGameVariantH1Dos) { //TODO initialize properly _boot structure warning("readBootFile - Skipping as H1 Dos may be a freeware"); - memset(_vm->_boot.distrib, '\0', sizeof(_vm->_boot.distrib)); - _vm->_boot.registered = kRegFreeware; + memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib)); + _vm->_boot._registered = kRegFreeware; return; } else if (_vm->getPlatform() == Common::kPlatformPC) { warning("readBootFile - Skipping as H2 and H3 Dos may be shareware"); - memset(_vm->_boot.distrib, '\0', sizeof(_vm->_boot.distrib)); - _vm->_boot.registered = kRegShareware; + memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib)); + _vm->_boot._registered = kRegShareware; return; } else { Utils::notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename())); - _vm->getGameStatus().doQuitFl = true; + _vm->getGameStatus()._doQuitFl = true; return; } } if (ofp.size() < (int32)sizeof(_vm->_boot)) { Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename())); - _vm->getGameStatus().doQuitFl = true; + _vm->getGameStatus()._doQuitFl = true; return; } - _vm->_boot.checksum = ofp.readByte(); - _vm->_boot.registered = ofp.readByte(); - ofp.read(_vm->_boot.pbswitch, sizeof(_vm->_boot.pbswitch)); - ofp.read(_vm->_boot.distrib, sizeof(_vm->_boot.distrib)); - _vm->_boot.exit_len = ofp.readUint16LE(); + _vm->_boot._checksum = ofp.readByte(); + _vm->_boot._registered = ofp.readByte(); + ofp.read(_vm->_boot._pbswitch, sizeof(_vm->_boot._pbswitch)); + ofp.read(_vm->_boot._distrib, sizeof(_vm->_boot._distrib)); + _vm->_boot._exitLen = ofp.readUint16LE(); byte *p = (byte *)&_vm->_boot; @@ -621,7 +572,7 @@ void FileManager::readBootFile() { if (checksum) { Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename())); - _vm->getGameStatus().doQuitFl = true; + _vm->getGameStatus()._doQuitFl = true; } } @@ -630,28 +581,28 @@ void FileManager::readBootFile() { * This file contains, between others, the bitmaps of the fonts used in the application * UIF means User interface database (Windows Only) */ -uif_hdr_t *FileManager::getUIFHeader(const uif_t id) { +UifHdr *FileManager::getUIFHeader(const Uif id) { debugC(1, kDebugFile, "getUIFHeader(%d)", id); // Initialize offset lookup if not read yet - if (firstUIFFl) { - firstUIFFl = false; + if (_firstUIFFl) { + _firstUIFFl = false; // Open unbuffered to do far read Common::File ip; // Image data file if (!ip.open(getUifFilename())) error("File not found: %s", getUifFilename()); - if (ip.size() < (int32)sizeof(UIFHeader)) + if (ip.size() < (int32)sizeof(_UIFHeader)) error("Wrong UIF file format"); for (int i = 0; i < kMaxUifs; ++i) { - UIFHeader[i].size = ip.readUint16LE(); - UIFHeader[i].offset = ip.readUint32LE(); + _UIFHeader[i]._size = ip.readUint16LE(); + _UIFHeader[i]._offset = ip.readUint32LE(); } ip.close(); } - return &UIFHeader[id]; + return &_UIFHeader[id]; } /** @@ -666,18 +617,18 @@ void FileManager::readUIFItem(const int16 id, byte *buf) { error("File not found: %s", getUifFilename()); // Seek to data - uif_hdr_t *UIFHeaderPtr = getUIFHeader((uif_t)id); - ip.seek(UIFHeaderPtr->offset, SEEK_SET); + UifHdr *_UIFHeaderPtr = getUIFHeader((Uif)id); + ip.seek(_UIFHeaderPtr->_offset, SEEK_SET); // We support pcx images and straight data - seq_t *dummySeq; // Dummy seq_t for image data + Seq *dummySeq; // Dummy Seq for image data switch (id) { case UIF_IMAGES: // Read uif images file dummySeq = readPCX(ip, 0, buf, true, getUifFilename()); free(dummySeq); break; default: // Read file data into supplied array - if (ip.read(buf, UIFHeaderPtr->size) != UIFHeaderPtr->size) + if (ip.read(buf, _UIFHeaderPtr->_size) != _UIFHeaderPtr->_size) error("Wrong UIF file format"); break; } diff --git a/engines/hugo/file.h b/engines/hugo/file.h index 3792c01ab4..1438bd2054 100644 --- a/engines/hugo/file.h +++ b/engines/hugo/file.h @@ -34,11 +34,11 @@ namespace Hugo { /** * Enumerate overlay file types */ -enum ovl_t {kOvlBoundary, kOvlOverlay, kOvlBase}; +enum OvlType {kOvlBoundary, kOvlOverlay, kOvlBase}; -struct uif_hdr_t { // UIF font/image look up - uint16 size; // Size of uif item - uint32 offset; // Offset of item in file +struct UifHdr { // UIF font/image look up + uint16 _size; // Size of uif item + uint32 _offset; // Offset of item in file }; @@ -47,10 +47,10 @@ public: FileManager(HugoEngine *vm); virtual ~FileManager(); - sound_pt getSound(const int16 sound, uint16 *size); + SoundPtr getSound(const int16 sound, uint16 *size); void readBootFile(); - void readImage(const int objNum, object_t *objPtr); + void readImage(const int objNum, Object *objPtr); void readUIFImages(); void readUIFItem(const int16 id, byte *buf); bool restoreGame(const int16 slot); @@ -69,7 +69,7 @@ public: virtual void instructions() const = 0; virtual void readBackground(const int screenIndex) = 0; - virtual void readOverlay(const int screenNum, image_pt image, ovl_t overlayType) = 0; + virtual void readOverlay(const int screenNum, ImagePtr image, OvlType overlayType) = 0; virtual const char *fetchString(const int index) = 0; @@ -84,48 +84,45 @@ protected: /** * Structure of scenery file lookup entry */ - struct sceneBlock_t { - uint32 scene_off; - uint32 scene_len; - uint32 b_off; - uint32 b_len; - uint32 o_off; - uint32 o_len; - uint32 ob_off; - uint32 ob_len; + struct SceneBlock { + uint32 _sceneOffset; + uint32 _sceneLength; + uint32 _boundaryOffset; + uint32 _boundaryLength; + uint32 _overlayOffset; + uint32 _overlayLength; + uint32 _baseOffset; + uint32 _baseLength; }; - struct PCC_header_t { // Structure of PCX file header - byte mfctr, vers, enc, bpx; - uint16 x1, y1, x2, y2; // bounding box - uint16 xres, yres; - byte palette[3 * kNumColors]; // EGA color palette - byte vmode, planes; - uint16 bytesPerLine; // Bytes per line - byte fill2[60]; + struct PCCHeader { // Structure of PCX file header + byte _mfctr, _vers, _enc, _bpx; + uint16 _x1, _y1, _x2, _y2; // bounding box + uint16 _xres, _yres; + byte _palette[3 * kNumColors]; // EGA color palette + byte _vmode, _planes; + uint16 _bytesPerLine; // Bytes per line + byte _fill2[60]; }; // Header of a PCC file - bool firstUIFFl; - uif_hdr_t UIFHeader[kMaxUifs]; // Lookup for uif fonts/images + bool _firstUIFFl; + UifHdr _UIFHeader[kMaxUifs]; // Lookup for uif fonts/images Common::File _stringArchive; // Handle for string file Common::File _sceneryArchive1; // Handle for scenery file Common::File _objectsArchive; // Handle for objects file - PCC_header_t PCC_header; + PCCHeader _PCCHeader; - seq_t *readPCX(Common::ReadStream &f, seq_t *seqPtr, byte *imagePtr, const bool firstFl, const char *name); + Seq *readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name); // If this is the first call, read the lookup table - bool has_read_header; - sound_hdr_t s_hdr[kMaxSounds]; // Sound lookup table + bool _hasReadHeader; + SoundHdr _soundHdr[kMaxSounds]; // Sound lookup table private: - byte *convertPCC(byte *p, const uint16 y, const uint16 bpl, image_pt dataPtr) const; - uif_hdr_t *getUIFHeader(const uif_t id); - -//Strangerke : Not used? - void printBootText(); + byte *convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const; + UifHdr *getUIFHeader(const Uif id); }; class FileManager_v1d : public FileManager { @@ -137,7 +134,7 @@ public: virtual void instructions() const; virtual void openDatabaseFiles(); virtual void readBackground(const int screenIndex); - virtual void readOverlay(const int screenNum, image_pt image, ovl_t overlayType); + virtual void readOverlay(const int screenNum, ImagePtr image, OvlType overlayType); virtual const char *fetchString(const int index); }; @@ -149,7 +146,7 @@ public: virtual void closeDatabaseFiles(); virtual void openDatabaseFiles(); virtual void readBackground(const int screenIndex); - virtual void readOverlay(const int screenNum, image_pt image, ovl_t overlayType); + virtual void readOverlay(const int screenNum, ImagePtr image, OvlType overlayType); const char *fetchString(const int index); private: char *_fetchStringBuf; @@ -163,7 +160,7 @@ public: void closeDatabaseFiles(); void openDatabaseFiles(); void readBackground(const int screenIndex); - void readOverlay(const int screenNum, image_pt image, ovl_t overlayType); + void readOverlay(const int screenNum, ImagePtr image, OvlType overlayType); private: Common::File _sceneryArchive2; // Handle for scenery file }; @@ -181,7 +178,7 @@ public: FileManager_v1w(HugoEngine *vm); ~FileManager_v1w(); - void readOverlay(const int screenNum, image_pt image, ovl_t overlayType); + void readOverlay(const int screenNum, ImagePtr image, OvlType overlayType); }; } // End of namespace Hugo diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp index c3bb0e275f..e42223fb13 100644 --- a/engines/hugo/file_v1d.cpp +++ b/engines/hugo/file_v1d.cpp @@ -55,11 +55,11 @@ void FileManager_v1d::closeDatabaseFiles() { /** * Open and read in an overlay file, close file */ -void FileManager_v1d::readOverlay(const int screenNum, image_pt image, const ovl_t overlayType) { +void FileManager_v1d::readOverlay(const int screenNum, ImagePtr image, const OvlType overlayType) { debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum); - const char *ovl_ext[] = {".b", ".o", ".ob"}; - Common::String buf = Common::String(_vm->_text->getScreenNames(screenNum)) + Common::String(ovl_ext[overlayType]); + const char *ovlExt[] = {".b", ".o", ".ob"}; + Common::String buf = Common::String(_vm->_text->getScreenNames(screenNum)) + Common::String(ovlExt[overlayType]); if (!Common::File::exists(buf)) { memset(image, 0, kOvlSize); @@ -70,7 +70,7 @@ void FileManager_v1d::readOverlay(const int screenNum, image_pt image, const ovl if (!_sceneryArchive1.open(buf)) error("File not found: %s", buf.c_str()); - image_pt tmpImage = image; // temp ptr to overlay file + ImagePtr tmpImage = image; // temp ptr to overlay file _sceneryArchive1.read(tmpImage, kOvlSize); _sceneryArchive1.close(); @@ -87,7 +87,7 @@ void FileManager_v1d::readBackground(const int screenIndex) { if (!_sceneryArchive1.open(buf)) error("File not found: %s", buf.c_str()); // Read the image into dummy seq and static dib_a - seq_t *dummySeq; // Image sequence structure for Read_pcx + Seq *dummySeq; // Image sequence structure for Read_pcx dummySeq = readPCX(_sceneryArchive1, 0, _vm->_screen->getFrontBuffer(), true, _vm->_text->getScreenNames(screenIndex)); free(dummySeq); _sceneryArchive1.close(); diff --git a/engines/hugo/file_v1w.cpp b/engines/hugo/file_v1w.cpp index 8a06cef939..002a1dc103 100644 --- a/engines/hugo/file_v1w.cpp +++ b/engines/hugo/file_v1w.cpp @@ -45,35 +45,35 @@ FileManager_v1w::~FileManager_v1w() { /** * Open and read in an overlay file, close file */ -void FileManager_v1w::readOverlay(const int screenNum, image_pt image, ovl_t overlayType) { +void FileManager_v1w::readOverlay(const int screenNum, ImagePtr image, OvlType overlayType) { debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum); - image_pt tmpImage = image; // temp ptr to overlay file - _sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET); + ImagePtr tmpImage = image; // temp ptr to overlay file + _sceneryArchive1.seek((uint32)screenNum * sizeof(SceneBlock), SEEK_SET); - sceneBlock_t sceneBlock; // Database header entry - sceneBlock.scene_off = _sceneryArchive1.readUint32LE(); - sceneBlock.scene_len = _sceneryArchive1.readUint32LE(); - sceneBlock.b_off = _sceneryArchive1.readUint32LE(); - sceneBlock.b_len = _sceneryArchive1.readUint32LE(); - sceneBlock.o_off = _sceneryArchive1.readUint32LE(); - sceneBlock.o_len = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_off = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_len = _sceneryArchive1.readUint32LE(); + SceneBlock sceneBlock; // Database header entry + sceneBlock._sceneOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._sceneLength = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryLength = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayLength = _sceneryArchive1.readUint32LE(); + sceneBlock._baseOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._baseLength = _sceneryArchive1.readUint32LE(); uint32 i = 0; switch (overlayType) { case kOvlBoundary: - _sceneryArchive1.seek(sceneBlock.b_off, SEEK_SET); - i = sceneBlock.b_len; + _sceneryArchive1.seek(sceneBlock._boundaryOffset, SEEK_SET); + i = sceneBlock._boundaryLength; break; case kOvlOverlay: - _sceneryArchive1.seek(sceneBlock.o_off, SEEK_SET); - i = sceneBlock.o_len; + _sceneryArchive1.seek(sceneBlock._overlayOffset, SEEK_SET); + i = sceneBlock._overlayLength; break; case kOvlBase: - _sceneryArchive1.seek(sceneBlock.ob_off, SEEK_SET); - i = sceneBlock.ob_len; + _sceneryArchive1.seek(sceneBlock._baseOffset, SEEK_SET); + i = sceneBlock._baseLength; break; default: error("Bad overlayType: %d", overlayType); diff --git a/engines/hugo/file_v2d.cpp b/engines/hugo/file_v2d.cpp index 520e1b77b6..19c90980b0 100644 --- a/engines/hugo/file_v2d.cpp +++ b/engines/hugo/file_v2d.cpp @@ -78,22 +78,22 @@ void FileManager_v2d::closeDatabaseFiles() { void FileManager_v2d::readBackground(const int screenIndex) { debugC(1, kDebugFile, "readBackground(%d)", screenIndex); - _sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET); + _sceneryArchive1.seek((uint32) screenIndex * sizeof(SceneBlock), SEEK_SET); - sceneBlock_t sceneBlock; // Read a database header entry - sceneBlock.scene_off = _sceneryArchive1.readUint32LE(); - sceneBlock.scene_len = _sceneryArchive1.readUint32LE(); - sceneBlock.b_off = _sceneryArchive1.readUint32LE(); - sceneBlock.b_len = _sceneryArchive1.readUint32LE(); - sceneBlock.o_off = _sceneryArchive1.readUint32LE(); - sceneBlock.o_len = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_off = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_len = _sceneryArchive1.readUint32LE(); + SceneBlock sceneBlock; // Read a database header entry + sceneBlock._sceneOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._sceneLength = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryLength = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayLength = _sceneryArchive1.readUint32LE(); + sceneBlock._baseOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._baseLength = _sceneryArchive1.readUint32LE(); - _sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET); + _sceneryArchive1.seek(sceneBlock._sceneOffset, SEEK_SET); // Read the image into dummy seq and static dib_a - seq_t *dummySeq; // Image sequence structure for Read_pcx + Seq *dummySeq; // Image sequence structure for Read_pcx dummySeq = readPCX(_sceneryArchive1, 0, _vm->_screen->getFrontBuffer(), true, _vm->_text->getScreenNames(screenIndex)); free(dummySeq); } @@ -101,35 +101,35 @@ void FileManager_v2d::readBackground(const int screenIndex) { /** * Open and read in an overlay file, close file */ -void FileManager_v2d::readOverlay(const int screenNum, image_pt image, ovl_t overlayType) { +void FileManager_v2d::readOverlay(const int screenNum, ImagePtr image, OvlType overlayType) { debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum); - image_pt tmpImage = image; // temp ptr to overlay file - _sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET); + ImagePtr tmpImage = image; // temp ptr to overlay file + _sceneryArchive1.seek((uint32)screenNum * sizeof(SceneBlock), SEEK_SET); - sceneBlock_t sceneBlock; // Database header entry - sceneBlock.scene_off = _sceneryArchive1.readUint32LE(); - sceneBlock.scene_len = _sceneryArchive1.readUint32LE(); - sceneBlock.b_off = _sceneryArchive1.readUint32LE(); - sceneBlock.b_len = _sceneryArchive1.readUint32LE(); - sceneBlock.o_off = _sceneryArchive1.readUint32LE(); - sceneBlock.o_len = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_off = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_len = _sceneryArchive1.readUint32LE(); + SceneBlock sceneBlock; // Database header entry + sceneBlock._sceneOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._sceneLength = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryLength = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayLength = _sceneryArchive1.readUint32LE(); + sceneBlock._baseOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._baseLength = _sceneryArchive1.readUint32LE(); uint32 i = 0; switch (overlayType) { case kOvlBoundary: - _sceneryArchive1.seek(sceneBlock.b_off, SEEK_SET); - i = sceneBlock.b_len; + _sceneryArchive1.seek(sceneBlock._boundaryOffset, SEEK_SET); + i = sceneBlock._boundaryLength; break; case kOvlOverlay: - _sceneryArchive1.seek(sceneBlock.o_off, SEEK_SET); - i = sceneBlock.o_len; + _sceneryArchive1.seek(sceneBlock._overlayOffset, SEEK_SET); + i = sceneBlock._overlayLength; break; case kOvlBase: - _sceneryArchive1.seek(sceneBlock.ob_off, SEEK_SET); - i = sceneBlock.ob_len; + _sceneryArchive1.seek(sceneBlock._baseOffset, SEEK_SET); + i = sceneBlock._baseLength; break; default: error("Bad overlayType: %d", overlayType); diff --git a/engines/hugo/file_v3d.cpp b/engines/hugo/file_v3d.cpp index d86003a040..5eb0cfc2c8 100644 --- a/engines/hugo/file_v3d.cpp +++ b/engines/hugo/file_v3d.cpp @@ -50,25 +50,25 @@ FileManager_v3d::~FileManager_v3d() { void FileManager_v3d::readBackground(const int screenIndex) { debugC(1, kDebugFile, "readBackground(%d)", screenIndex); - _sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET); - - sceneBlock_t sceneBlock; // Read a database header entry - sceneBlock.scene_off = _sceneryArchive1.readUint32LE(); - sceneBlock.scene_len = _sceneryArchive1.readUint32LE(); - sceneBlock.b_off = _sceneryArchive1.readUint32LE(); - sceneBlock.b_len = _sceneryArchive1.readUint32LE(); - sceneBlock.o_off = _sceneryArchive1.readUint32LE(); - sceneBlock.o_len = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_off = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_len = _sceneryArchive1.readUint32LE(); - - seq_t *dummySeq; // Image sequence structure for Read_pcx + _sceneryArchive1.seek((uint32) screenIndex * sizeof(SceneBlock), SEEK_SET); + + SceneBlock sceneBlock; // Read a database header entry + sceneBlock._sceneOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._sceneLength = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryLength = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayLength = _sceneryArchive1.readUint32LE(); + sceneBlock._baseOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._baseLength = _sceneryArchive1.readUint32LE(); + + Seq *dummySeq; // Image sequence structure for Read_pcx if (screenIndex < 20) { - _sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET); + _sceneryArchive1.seek(sceneBlock._sceneOffset, SEEK_SET); // Read the image into dummy seq and static dib_a dummySeq = readPCX(_sceneryArchive1, 0, _vm->_screen->getFrontBuffer(), true, _vm->_text->getScreenNames(screenIndex)); } else { - _sceneryArchive2.seek(sceneBlock.scene_off, SEEK_SET); + _sceneryArchive2.seek(sceneBlock._sceneOffset, SEEK_SET); // Read the image into dummy seq and static dib_a dummySeq = readPCX(_sceneryArchive2, 0, _vm->_screen->getFrontBuffer(), true, _vm->_text->getScreenNames(screenIndex)); } @@ -106,37 +106,37 @@ void FileManager_v3d::closeDatabaseFiles() { /** * Open and read in an overlay file, close file */ -void FileManager_v3d::readOverlay(const int screenNum, image_pt image, ovl_t overlayType) { +void FileManager_v3d::readOverlay(const int screenNum, ImagePtr image, OvlType overlayType) { debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum); - image_pt tmpImage = image; // temp ptr to overlay file - _sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET); + ImagePtr tmpImage = image; // temp ptr to overlay file + _sceneryArchive1.seek((uint32)screenNum * sizeof(SceneBlock), SEEK_SET); - sceneBlock_t sceneBlock; // Database header entry - sceneBlock.scene_off = _sceneryArchive1.readUint32LE(); - sceneBlock.scene_len = _sceneryArchive1.readUint32LE(); - sceneBlock.b_off = _sceneryArchive1.readUint32LE(); - sceneBlock.b_len = _sceneryArchive1.readUint32LE(); - sceneBlock.o_off = _sceneryArchive1.readUint32LE(); - sceneBlock.o_len = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_off = _sceneryArchive1.readUint32LE(); - sceneBlock.ob_len = _sceneryArchive1.readUint32LE(); + SceneBlock sceneBlock; // Database header entry + sceneBlock._sceneOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._sceneLength = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._boundaryLength = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._overlayLength = _sceneryArchive1.readUint32LE(); + sceneBlock._baseOffset = _sceneryArchive1.readUint32LE(); + sceneBlock._baseLength = _sceneryArchive1.readUint32LE(); uint32 i = 0; if (screenNum < 20) { switch (overlayType) { case kOvlBoundary: - _sceneryArchive1.seek(sceneBlock.b_off, SEEK_SET); - i = sceneBlock.b_len; + _sceneryArchive1.seek(sceneBlock._boundaryOffset, SEEK_SET); + i = sceneBlock._boundaryLength; break; case kOvlOverlay: - _sceneryArchive1.seek(sceneBlock.o_off, SEEK_SET); - i = sceneBlock.o_len; + _sceneryArchive1.seek(sceneBlock._overlayOffset, SEEK_SET); + i = sceneBlock._overlayLength; break; case kOvlBase: - _sceneryArchive1.seek(sceneBlock.ob_off, SEEK_SET); - i = sceneBlock.ob_len; + _sceneryArchive1.seek(sceneBlock._baseOffset, SEEK_SET); + i = sceneBlock._baseLength; break; default: error("Bad overlayType: %d", overlayType); @@ -166,16 +166,16 @@ void FileManager_v3d::readOverlay(const int screenNum, image_pt image, ovl_t ove } else { switch (overlayType) { case kOvlBoundary: - _sceneryArchive2.seek(sceneBlock.b_off, SEEK_SET); - i = sceneBlock.b_len; + _sceneryArchive2.seek(sceneBlock._boundaryOffset, SEEK_SET); + i = sceneBlock._boundaryLength; break; case kOvlOverlay: - _sceneryArchive2.seek(sceneBlock.o_off, SEEK_SET); - i = sceneBlock.o_len; + _sceneryArchive2.seek(sceneBlock._overlayOffset, SEEK_SET); + i = sceneBlock._overlayLength; break; case kOvlBase: - _sceneryArchive2.seek(sceneBlock.ob_off, SEEK_SET); - i = sceneBlock.ob_len; + _sceneryArchive2.seek(sceneBlock._baseOffset, SEEK_SET); + i = sceneBlock._baseLength; break; default: error("Bad overlayType: %d", overlayType); diff --git a/engines/hugo/game.h b/engines/hugo/game.h index b1c5f407b3..ed49ee8cbe 100644 --- a/engines/hugo/game.h +++ b/engines/hugo/game.h @@ -45,7 +45,7 @@ namespace Hugo { enum {LOOK_NAME = 1, TAKE_NAME}; // Index of name used in showing takeables and in confirming take // Definitions of 'generic' commands: Max # depends on size of gencmd in -// the object_t record since each requires 1 bit. Currently up to 16 +// the Object record since each requires 1 bit. Currently up to 16 enum {LOOK = 1, TAKE = 2, DROP = 4, LOOK_S = 8}; enum TEXTCOLORS { @@ -55,25 +55,25 @@ enum TEXTCOLORS { _TLIGHTRED, _TLIGHTMAGENTA, _TLIGHTYELLOW, _TBRIGHTWHITE }; -enum uif_t {U_FONT5, U_FONT6, U_FONT8, UIF_IMAGES, NUM_UIF_ITEMS}; +enum Uif {U_FONT5, U_FONT6, U_FONT8, UIF_IMAGES, NUM_UIF_ITEMS}; static const int kFirstFont = U_FONT5; /** * Enumerate ways of cycling a sequence of frames */ -enum cycle_t {kCycleInvisible, kCycleAlmostInvisible, kCycleNotCycling, kCycleForward, kCycleBackward}; +enum Cycle {kCycleInvisible, kCycleAlmostInvisible, kCycleNotCycling, kCycleForward, kCycleBackward}; /** * Enumerate sequence index matching direction of travel */ enum {SEQ_RIGHT, SEQ_LEFT, SEQ_DOWN, SEQ_UP}; -enum font_t {LARGE_ROMAN, MED_ROMAN, NUM_GDI_FONTS, INIT_FONTS, DEL_FONTS}; +enum Font {LARGE_ROMAN, MED_ROMAN, NUM_GDI_FONTS, INIT_FONTS, DEL_FONTS}; /** * Enumerate the different path types for an object */ -enum path_t { +enum Path { kPathUser, // User has control of object via cursor keys kPathAuto, // Computer has control, controlled by action lists kPathQuiet, // Computer has control and no commands allowed @@ -83,55 +83,55 @@ enum path_t { kPathWander2 // Same as WANDER, except keeps cycling when stationary }; -struct hugo_boot_t { // Common HUGO boot file - char checksum; // Checksum for boot structure (not exit text) - char registered; // TRUE if registered version, else FALSE - char pbswitch[8]; // Playback switch string - char distrib[32]; // Distributor branding string - uint16 exit_len; // Length of exit text (next in file) +struct hugoBoot { // Common HUGO boot file + char _checksum; // Checksum for boot structure (not exit text) + char _registered; // TRUE if registered version, else FALSE + char _pbswitch[8]; // Playback switch string + char _distrib[32]; // Distributor branding string + uint16 _exitLen; // Length of exit text (next in file) } PACKED_STRUCT; /** * Game specific type definitions */ -typedef byte *image_pt; // ptr to an object image (sprite) -typedef byte *sound_pt; // ptr to sound (or music) data +typedef byte *ImagePtr; // ptr to an object image (sprite) +typedef byte *SoundPtr; // ptr to sound (or music) data /** * Structure for initializing maze processing */ -struct maze_t { - bool enabledFl; // TRUE when maze processing enabled - byte size; // Size of (square) maze matrix - int x1, y1, x2, y2; // maze hotspot bounding box - int x3, x4; // north, south x entry coordinates - byte firstScreenIndex; // index of first screen in maze +struct Maze { + bool _enabledFl; // TRUE when maze processing enabled + byte _size; // Size of (square) maze matrix + int _x1, _y1, _x2, _y2; // maze hotspot bounding box + int _x3, _x4; // north, south x entry coordinates + byte _firstScreenIndex; // index of first screen in maze }; /** * The following is a linked list of images in an animation sequence * The image data is in 8-bit DIB format, i.e. 1 byte = 1 pixel */ -struct seq_t { // Linked list of images - byte *imagePtr; // ptr to image - uint16 bytesPerLine8; // bytes per line (8bits) - uint16 lines; // lines - uint16 x1, x2, y1, y2; // Offsets from x,y: data bounding box - seq_t *nextSeqPtr; // ptr to next record +struct Seq { // Linked list of images + byte *_imagePtr; // ptr to image + uint16 _bytesPerLine8; // bytes per line (8bits) + uint16 _lines; // lines + uint16 _x1, _x2, _y1, _y2; // Offsets from x,y: data bounding box + Seq *_nextSeqPtr; // ptr to next record }; /** * The following is an array of structures of above sequences */ -struct seqList_t { - uint16 imageNbr; // Number of images in sequence - seq_t *seqPtr; // Ptr to sequence structure +struct SeqList { + uint16 _imageNbr; // Number of images in sequence + Seq *_seqPtr; // Ptr to sequence structure }; #include "common/pack-start.h" // START STRUCT PACKING -struct sound_hdr_t { // Sound file lookup entry - uint16 size; // Size of sound data in bytes - uint32 offset; // Offset of sound data in file +struct SoundHdr { // Sound file lookup entry + uint16 _size; // Size of sound data in bytes + uint32 _offset; // Offset of sound data in file } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING @@ -140,38 +140,38 @@ static const int kMaxSeqNumb = 4; // Number of sequences of im /** * Following is definition of object attributes */ -struct object_t { - uint16 nounIndex; // String identifying object - uint16 dataIndex; // String describing the object - uint16 *stateDataIndex; // Added by Strangerke to handle the LOOK_S state-dependant descriptions - path_t pathType; // Describe path object follows - int vxPath, vyPath; // Delta velocities (e.g. for CHASE) - uint16 actIndex; // Action list to do on collision with hero - byte seqNumb; // Number of sequences in list - seq_t *currImagePtr; // Sequence image currently in use - seqList_t seqList[kMaxSeqNumb]; // Array of sequence structure ptrs and lengths - cycle_t cycling; // Whether cycling, forward or backward - byte cycleNumb; // No. of times to cycle - byte frameInterval; // Interval (in ticks) between frames - byte frameTimer; // Decrementing timer for above - int8 radius; // Defines sphere of influence by hero - byte screenIndex; // Screen in which object resides - int x, y; // Current coordinates of object - int oldx, oldy; // Previous coordinates of object - int8 vx, vy; // Velocity - byte objValue; // Value of object - int genericCmd; // Bit mask of 'generic' commands for object - uint16 cmdIndex; // ptr to list of cmd structures for verbs - bool carriedFl; // TRUE if object being carried - byte state; // state referenced in cmd list - bool verbOnlyFl; // TRUE if verb-only cmds allowed e.g. sit,look - byte priority; // Whether object fore, background or floating - int16 viewx, viewy; // Position to view object from (or 0 or -1) - int16 direction; // Direction to view object from - byte curSeqNum; // Save which seq number currently in use - byte curImageNum; // Save which image of sequence currently in use - int8 oldvx; // Previous vx (used in wandering) - int8 oldvy; // Previous vy +struct Object { + uint16 _nounIndex; // String identifying object + uint16 _dataIndex; // String describing the object + uint16 *_stateDataIndex; // Added by Strangerke to handle the LOOK_S state-dependant descriptions + Path _pathType; // Describe path object follows + int _vxPath, _vyPath; // Delta velocities (e.g. for CHASE) + uint16 _actIndex; // Action list to do on collision with hero + byte _seqNumb; // Number of sequences in list + Seq *_currImagePtr; // Sequence image currently in use + SeqList _seqList[kMaxSeqNumb]; // Array of sequence structure ptrs and lengths + Cycle _cycling; // Whether cycling, forward or backward + byte _cycleNumb; // No. of times to cycle + byte _frameInterval; // Interval (in ticks) between frames + byte _frameTimer; // Decrementing timer for above + int8 _radius; // Defines sphere of influence by hero + byte _screenIndex; // Screen in which object resides + int _x, _y; // Current coordinates of object + int _oldx, _oldy; // Previous coordinates of object + int8 _vx, _vy; // Velocity + byte _objValue; // Value of object + int _genericCmd; // Bit mask of 'generic' commands for object + uint16 _cmdIndex; // ptr to list of cmd structures for verbs + bool _carriedFl; // TRUE if object being carried + byte _state; // state referenced in cmd list + bool _verbOnlyFl; // TRUE if verb-only cmds allowed e.g. sit,look + byte _priority; // Whether object fore, background or floating + int16 _viewx, _viewy; // Position to view object from (or 0 or -1) + int16 _direction; // Direction to view object from + byte _curSeqNum; // Save which seq number currently in use + byte _curImageNum; // Save which image of sequence currently in use + int8 _oldvx; // Previous vx (used in wandering) + int8 _oldvy; // Previous vy }; } // End of namespace Hugo diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index df8abf32eb..9d28e0ac69 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -106,7 +106,7 @@ GUI::Debugger *HugoEngine::getDebugger() { return _console; } -status_t &HugoEngine::getGameStatus() { +Status &HugoEngine::getGameStatus() { return _status; } @@ -249,24 +249,24 @@ Common::Error HugoEngine::run() { initStatus(); // Initialize game status initConfig(); // Initialize user's config - if (!_status.doQuitFl) { + if (!_status._doQuitFl) { initialize(); resetConfig(); // Reset user's config initMachine(); // Start the state machine - _status.viewState = kViewIntroInit; + _status._viewState = kViewIntroInit; int16 loadSlot = Common::ConfigManager::instance().getInt("save_slot"); if (loadSlot >= 0) { - _status.skipIntroFl = true; + _status._skipIntroFl = true; _file->restoreGame(loadSlot); } else { _file->saveGame(0, "New Game"); } } - while (!_status.doQuitFl) { + while (!_status._doQuitFl) { _screen->drawBoundaries(); g_system->updateScreen(); runMachine(); @@ -289,20 +289,20 @@ Common::Error HugoEngine::run() { _mouse->setRightButton(); break; case Common::EVENT_QUIT: - _status.doQuitFl = true; + _status._doQuitFl = true; break; default: break; } } - if (_status.helpFl) { - _status.helpFl = false; + if (_status._helpFl) { + _status._helpFl = false; _file->instructions(); } _mouse->mouseHandler(); // Mouse activity - adds to display list _screen->displayList(kDisplayDisplay); // Blit the display list to screen - _status.doQuitFl |= shouldQuit(); // update game quit flag + _status._doQuitFl |= shouldQuit(); // update game quit flag } return Common::kNoError; } @@ -323,10 +323,10 @@ void HugoEngine::initMachine() { * Hugo game state machine - called during onIdle */ void HugoEngine::runMachine() { - status_t &gameStatus = getGameStatus(); + Status &gameStatus = getGameStatus(); // Don't process if gameover - if (gameStatus.gameOverFl) + if (gameStatus._gameOverFl) return; _curTime = g_system->getMillis(); @@ -338,19 +338,19 @@ void HugoEngine::runMachine() { _lastTime = _curTime; - switch (gameStatus.viewState) { + switch (gameStatus._viewState) { case kViewIdle: // Not processing state machine _screen->hideCursor(); _intro->preNewGame(); // Any processing before New Game selected break; case kViewIntroInit: // Initialization before intro begins _intro->introInit(); - gameStatus.viewState = kViewIntro; + gameStatus._viewState = kViewIntro; break; case kViewIntro: // Do any game-dependant preamble if (_intro->introPlay()) { // Process intro screen _scheduler->newScreen(0); // Initialize first screen - gameStatus.viewState = kViewPlay; + gameStatus._viewState = kViewPlay; } break; case kViewPlay: // Playing game @@ -368,8 +368,8 @@ void HugoEngine::runMachine() { _inventory->runInventory(); // Process Inventory state machine break; case kViewExit: // Game over or user exited - gameStatus.viewState = kViewIdle; - _status.doQuitFl = true; + gameStatus._viewState = kViewIdle; + _status._doQuitFl = true; break; } } @@ -427,7 +427,7 @@ bool HugoEngine::loadHugoDat() { _scheduler->loadActListArr(in); _scheduler->loadAlNewscrIndex(in); _hero = &_object->_objects[kHeroIndex]; // This always points to hero - _screen_p = &(_object->_objects[kHeroIndex].screenIndex); // Current screen is hero's + _screenPtr = &(_object->_objects[kHeroIndex]._screenIndex); // Current screen is hero's _heroImage = kHeroIndex; // Current in use hero image for (int varnt = 0; varnt < _numVariant; varnt++) { @@ -527,33 +527,20 @@ void HugoEngine::initPlaylist(bool playlist[kMaxTunes]) { */ void HugoEngine::initStatus() { debugC(1, kDebugEngine, "initStatus"); - _status.storyModeFl = false; // Not in story mode - _status.gameOverFl = false; // Hero not knobbled yet - _status.lookFl = false; // Toolbar "look" button - _status.recallFl = false; // Toolbar "recall" button - _status.newScreenFl = false; // Screen not just loaded - _status.godModeFl = false; // No special cheats allowed - _status.showBoundariesFl = false; // Boundaries hidden by default - _status.doQuitFl = false; - _status.skipIntroFl = false; - _status.helpFl = false; + _status._storyModeFl = false; // Not in story mode + _status._gameOverFl = false; // Hero not knobbled yet + _status._lookFl = false; // Toolbar "look" button + _status._recallFl = false; // Toolbar "recall" button + _status._newScreenFl = false; // Screen not just loaded + _status._godModeFl = false; // No special cheats allowed + _status._showBoundariesFl = false; // Boundaries hidden by default + _status._doQuitFl = false; + _status._skipIntroFl = false; + _status._helpFl = false; // Initialize every start of new game - _status.tick = 0; // Tick count - _status.viewState = kViewIdle; // View state - -// Strangerke - Suppress as related to playback -// _status.recordFl = false; // Not record mode -// _status.playbackFl = false; // Not playback mode -// Strangerke - Not used ? -// _status.mmtime = false; // Multimedia timer support -// _status.helpFl = false; // Not calling WinHelp() -// _status.demoFl = false; // Not demo mode -// _status.path[0] = 0; // Path to write files -// _status.screenWidth = 0; // Desktop screen width -// _status.saveTick = 0; // Time of last save -// _status.saveSlot = 0; // Slot to save/restore game -// _status.textBoxFl = false; // Not processing a text box + _status._tick = 0; // Tick count + _status._viewState = kViewIdle; // View state } /** @@ -562,11 +549,11 @@ void HugoEngine::initStatus() { void HugoEngine::initConfig() { debugC(1, kDebugEngine, "initConfig()"); - _config.musicFl = true; // Music state initially on - _config.soundFl = true; // Sound state initially on - _config.turboFl = false; // Turbo state initially off - initPlaylist(_config.playlist); // Initialize default tune playlist - _file->readBootFile(); // Read startup structure + _config._musicFl = true; // Music state initially on + _config._soundFl = true; // Sound state initially on + _config._turboFl = false; // Turbo state initially off + initPlaylist(_config._playlist); // Initialize default tune playlist + _file->readBootFile(); // Read startup structure } /** @@ -577,7 +564,7 @@ void HugoEngine::resetConfig() { // Find first tune and play it for (int16 i = 0; i < kMaxTunes; i++) { - if (_config.playlist[i]) { + if (_config._playlist[i]) { _sound->playMusic(i); break; } @@ -587,7 +574,7 @@ void HugoEngine::resetConfig() { void HugoEngine::initialize() { debugC(1, kDebugEngine, "initialize"); - _maze.enabledFl = false; + _maze._enabledFl = false; _line[0] = '\0'; _sound->initSound(); @@ -639,10 +626,10 @@ void HugoEngine::readScreenFiles(const int screenNum) { memcpy(_screen->getBackBuffer(), _screen->getFrontBuffer(), sizeof(_screen->getFrontBuffer())); // Make a copy // Workaround for graphic glitches in DOS versions. Cleaning the overlays fix the problem - memset(_object->_objBound, '\0', sizeof(overlay_t)); - memset(_object->_boundary, '\0', sizeof(overlay_t)); - memset(_object->_overlay, '\0', sizeof(overlay_t)); - memset(_object->_ovlBase, '\0', sizeof(overlay_t)); + memset(_object->_objBound, '\0', sizeof(Overlay)); + memset(_object->_boundary, '\0', sizeof(Overlay)); + memset(_object->_overlay, '\0', sizeof(Overlay)); + memset(_object->_ovlBase, '\0', sizeof(Overlay)); _file->readOverlay(screenNum, _object->_boundary, kOvlBoundary); // Boundary file _file->readOverlay(screenNum, _object->_overlay, kOvlOverlay); // Overlay file @@ -660,7 +647,7 @@ void HugoEngine::readScreenFiles(const int screenNum) { void HugoEngine::setNewScreen(const int screenNum) { debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum); - *_screen_p = screenNum; // HERO object + *_screenPtr = screenNum; // HERO object _object->setCarriedScreen(screenNum); // Carried objects } @@ -679,10 +666,10 @@ void HugoEngine::calcMaxScore() { void HugoEngine::endGame() { debugC(1, kDebugEngine, "endGame"); - if (_boot.registered != kRegRegistered) + if (_boot._registered != kRegRegistered) Utils::notifyBox(_text->getTextEngine(kEsAdvertise)); Utils::notifyBox(Common::String::format("%s\n%s", _episode, getCopyrightString())); - _status.viewState = kViewExit; + _status._viewState = kViewExit; } bool HugoEngine::canLoadGameStateCurrently() { @@ -690,11 +677,11 @@ bool HugoEngine::canLoadGameStateCurrently() { } bool HugoEngine::canSaveGameStateCurrently() { - return (_status.viewState == kViewPlay); + return (_status._viewState == kViewPlay); } int8 HugoEngine::getTPS() const { - return ((_config.turboFl) ? kTurboTps : _normalTPS); + return ((_config._turboFl) ? kTurboTps : _normalTPS); } void HugoEngine::syncSoundSettings() { diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h index 125819a39b..9f495a9037 100644 --- a/engines/hugo/hugo.h +++ b/engines/hugo/hugo.h @@ -80,18 +80,18 @@ static const int kMaxPath = 256; // Max length of a full path static const int kHeroMaxWidth = 24; // Maximum width of hero static const int kHeroMinWidth = 16; // Minimum width of hero -typedef char command_t[kMaxLineSize + 8]; // Command line (+spare for prompt,cursor) +typedef char Command[kMaxLineSize + 8]; // Command line (+spare for prompt,cursor) -struct config_t { // User's config (saved) - bool musicFl; // State of Music button/menu item - bool soundFl; // State of Sound button/menu item - bool turboFl; // State of Turbo button/menu item - bool playlist[kMaxTunes]; // Tune playlist +struct Config { // User's config (saved) + bool _musicFl; // State of Music button/menu item + bool _soundFl; // State of Sound button/menu item + bool _turboFl; // State of Turbo button/menu item + bool _playlist[kMaxTunes]; // Tune playlist }; -typedef byte icondib_t[kXPix * kInvDy]; // Icon bar dib -typedef byte viewdib_t[(long)kXPix * kYPix]; // Viewport dib -typedef byte overlay_t[kOvlSize]; // Overlay file +typedef byte Icondib[kXPix * kInvDy]; // Icon bar dib +typedef byte Viewdib[(long)kXPix * kYPix]; // Viewport dib +typedef byte Overlay[kOvlSize]; // Overlay file enum GameType { kGameTypeNone = 0, @@ -131,12 +131,12 @@ enum HugoRegistered { /** * Inventory icon bar states */ -enum istate_t {kInventoryOff, kInventoryUp, kInventoryDown, kInventoryActive}; +enum Istate {kInventoryOff, kInventoryUp, kInventoryDown, kInventoryActive}; /** * Game view state machine */ -enum vstate_t {kViewIdle, kViewIntroInit, kViewIntro, kViewPlay, kViewInvent, kViewExit}; +enum Vstate {kViewIdle, kViewIntroInit, kViewIntro, kViewPlay, kViewInvent, kViewExit}; /** * Enumerate whether object is foreground, background or 'floating' @@ -152,12 +152,12 @@ enum {kPriorityForeground, kPriorityBackground, kPriorityFloating, kPriorityOver /** * Display list functions */ -enum dupdate_t {kDisplayInit, kDisplayAdd, kDisplayDisplay, kDisplayRestore}; +enum Dupdate {kDisplayInit, kDisplayAdd, kDisplayDisplay, kDisplayRestore}; /** * Priority for sound effect */ -enum priority_t {kSoundPriorityLow, kSoundPriorityMedium, kSoundPriorityHigh}; +enum Priority {kSoundPriorityLow, kSoundPriorityMedium, kSoundPriorityHigh}; enum HugoGameFeatures { GF_PACKED = (1 << 0) // Database @@ -170,47 +170,31 @@ enum seqTextEngine { struct HugoGameDescription; -struct status_t { // Game status (not saved) - bool storyModeFl; // Game is telling story - no commands - bool gameOverFl; // Game is over - hero knobbled - bool lookFl; // Toolbar "look" button pressed - bool recallFl; // Toolbar "recall" button pressed - bool newScreenFl; // New screen just loaded in dib_a - bool godModeFl; // Allow DEBUG features in live version - bool showBoundariesFl; // Flag used to show and hide boundaries, +struct Status { // Game status (not saved) + bool _storyModeFl; // Game is telling story - no commands + bool _gameOverFl; // Game is over - hero knobbled + bool _lookFl; // Toolbar "look" button pressed + bool _recallFl; // Toolbar "recall" button pressed + bool _newScreenFl; // New screen just loaded in dib_a + bool _godModeFl; // Allow DEBUG features in live version + bool _showBoundariesFl; // Flag used to show and hide boundaries, // used by the console - bool doQuitFl; - bool skipIntroFl; - bool helpFl; - uint32 tick; // Current time in ticks - vstate_t viewState; // View state machine - int16 song; // Current song - -// Strangerke - Suppress as related to playback -// bool playbackFl; // Game is in playback mode -// bool recordFl; // Game is in record mode -// Strangerke - Not used ? -// bool helpFl; // Calling WinHelp (don't disable music) -// bool mmtimeFl; // Multimedia timer supported -// bool demoFl; // Game is in demo mode -// bool textBoxFl; // Game is (halted) in text box -// int16 screenWidth; // Desktop screen width -// int16 saveSlot; // Current slot to save/restore game -// int16 cx, cy; // Cursor position (dib coords) -// uint32 saveTick; // Time of last save in ticks -// -// typedef char fpath_t[kMaxPath]; // File path -// fpath_t path; // Alternate path for saved files + bool _doQuitFl; + bool _skipIntroFl; + bool _helpFl; + uint32 _tick; // Current time in ticks + Vstate _viewState; // View state machine + int16 _song; // Current song }; /** * Structure to define an EXIT or other collision-activated hotspot */ -struct hotspot_t { - int screenIndex; // Screen in which hotspot appears - int x1, y1, x2, y2; // Bounding box of hotspot - uint16 actIndex; // Actions to carry out if a 'hit' - int16 viewx, viewy, direction; // Used in auto-route mode +struct Hotspot { + int _screenIndex; // Screen in which hotspot appears + int _x1, _y1, _x2, _y2; // Bounding box of hotspot + uint16 _actIndex; // Actions to carry out if a 'hit' + int16 _viewx, _viewy, _direction; // Used in auto-route mode }; class FileManager; @@ -241,19 +225,19 @@ public: uint16 _numStates; int8 _normalTPS; // Number of ticks (frames) per second. // 8 for Win versions, 9 for DOS versions - object_t *_hero; - byte *_screen_p; + Object *_hero; + byte *_screenPtr; byte _heroImage; byte *_screenStates; - command_t _line; // Line of user text input - config_t _config; // User's config + Command _line; // Line of user text input + Config _config; // User's config int16 *_defltTunes; uint16 _look; uint16 _take; uint16 _drop; - maze_t _maze; // Maze control structure - hugo_boot_t _boot; // Boot info structure + Maze _maze; // Maze control structure + hugoBoot _boot; // Boot info structure GUI::Debugger *getDebugger(); @@ -262,8 +246,8 @@ public: const char *_episode; Common::String _picDir; - command_t _statusLine; - command_t _scoreLine; + Command _statusLine; + Command _scoreLine; const HugoGameDescription *_gameDescription; uint32 getFeatures() const; @@ -295,7 +279,7 @@ public: void shutdown(); void syncSoundSettings(); - status_t &getGameStatus(); + Status &getGameStatus(); int getScore() const; void setScore(const int newScore); void adjustScore(const int adjustment); @@ -330,7 +314,7 @@ protected: private: static const int kTurboTps = 16; // This many in turbo mode - status_t _status; // Game status structure + Status _status; // Game status structure uint32 _lastTime; uint32 _curTime; diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp index 72f718fe8e..f2ae06eb39 100644 --- a/engines/hugo/intro.cpp +++ b/engines/hugo/intro.cpp @@ -86,22 +86,22 @@ void intro_v1d::preNewGame() { void intro_v1d::introInit() { _introState = 0; - introTicks = 0; - surf.w = 320; - surf.h = 200; - surf.pixels = _vm->_screen->getFrontBuffer(); - surf.pitch = 320; - surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _introTicks = 0; + _surf.w = 320; + _surf.h = 200; + _surf.pixels = _vm->_screen->getFrontBuffer(); + _surf.pitch = 320; + _surf.format = Graphics::PixelFormat::createFormatCLUT8(); _vm->_screen->displayList(kDisplayInit); } bool intro_v1d::introPlay() { byte introSize = getIntroSize(); - if (_vm->getGameStatus().skipIntroFl) + if (_vm->getGameStatus()._skipIntroFl) return true; - if (introTicks < introSize) { + if (_introTicks < introSize) { switch (_introState++) { case 0: _vm->_screen->drawRectangle(true, 0, 0, 319, 199, _TMAGENTA); @@ -113,32 +113,32 @@ bool intro_v1d::introPlay() { _vm->_screen->drawShape(250,92,_TLIGHTMAGENTA,_TMAGENTA); // TROMAN, size 10-5 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 8"); char buffer[80]; - if (_vm->_boot.registered == kRegRegistered) + if (_vm->_boot._registered == kRegRegistered) strcpy(buffer, "Registered Version"); - else if (_vm->_boot.registered == kRegShareware) + else if (_vm->_boot._registered == kRegShareware) strcpy(buffer, "Shareware Version"); - else if (_vm->_boot.registered == kRegFreeware) + else if (_vm->_boot._registered == kRegFreeware) strcpy(buffer, "Freeware Version"); else - error("Unknown registration flag in hugo.bsf: %d", _vm->_boot.registered); + error("Unknown registration flag in hugo.bsf: %d", _vm->_boot._registered); - font.drawString(&surf, buffer, 0, 163, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); - font.drawString(&surf, _vm->getCopyrightString(), 0, 176, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 163, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, _vm->getCopyrightString(), 0, 176, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); - if ((*_vm->_boot.distrib != '\0') && (scumm_stricmp(_vm->_boot.distrib, "David P. Gray"))) { - sprintf(buffer, "Distributed by %s.", _vm->_boot.distrib); - font.drawString(&surf, buffer, 0, 75, 320, _TMAGENTA, Graphics::kTextAlignCenter); + if ((*_vm->_boot._distrib != '\0') && (scumm_stricmp(_vm->_boot._distrib, "David P. Gray"))) { + sprintf(buffer, "Distributed by %s.", _vm->_boot._distrib); + _font.drawString(&_surf, buffer, 0, 75, 320, _TMAGENTA, Graphics::kTextAlignCenter); } // SCRIPT, size 24-16 strcpy(buffer, "Hugo's"); - if (font.loadFromFON("SCRIPT.FON")) { - font.drawString(&surf, buffer, 0, 20, 320, _TMAGENTA, Graphics::kTextAlignCenter); + if (_font.loadFromFON("SCRIPT.FON")) { + _font.drawString(&_surf, buffer, 0, 20, 320, _TMAGENTA, Graphics::kTextAlignCenter); } else { // Workaround: SCRIPT.FON doesn't load properly at the moment _vm->_screen->loadFont(2); @@ -146,78 +146,78 @@ bool intro_v1d::introPlay() { } // TROMAN, size 30-24 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 24))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 24))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 24"); strcpy(buffer, "House of Horrors !"); - font.drawString(&surf, buffer, 0, 50, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 50, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; case 2: _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // TROMAN, size 16-9 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 14))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 14))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 14"); strcpy(buffer, "S t a r r i n g :"); - font.drawString(&surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); break; case 3: // TROMAN, size 20-9 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 18))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 18))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 18"); strcpy(buffer, "Hugo !"); - font.drawString(&surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; case 4: _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // TROMAN, size 16-9 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 14))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 14))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 14"); strcpy(buffer, "P r o d u c e d b y :"); - font.drawString(&surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); break; case 5: // TROMAN size 16-9 strcpy(buffer, "David P Gray !"); - font.drawString(&surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; case 6: _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // TROMAN, size 16-9 strcpy(buffer, "D i r e c t e d b y :"); - font.drawString(&surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); break; case 7: // TROMAN, size 16-9 strcpy(buffer, "David P Gray !"); - font.drawString(&surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; case 8: _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // TROMAN, size 16-9 strcpy(buffer, "M u s i c b y :"); - font.drawString(&surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 95, 320, _TMAGENTA, Graphics::kTextAlignCenter); break; case 9: // TROMAN, size 16-9 strcpy(buffer, "David P Gray !"); - font.drawString(&surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 115, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; case 10: _vm->_screen->drawRectangle(true, 82, 92, 237, 138, _TBLACK); // TROMAN, size 20-14 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 18))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 18))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 18"); strcpy(buffer, "E n j o y !"); - font.drawString(&surf, buffer, 0, 100, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 100, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter); break; } @@ -226,7 +226,7 @@ bool intro_v1d::introPlay() { g_system->delayMillis(1000); } - return (++introTicks >= introSize); + return (++_introTicks >= introSize); } intro_v2d::intro_v2d(HugoEngine *vm) : IntroHandler(vm) { @@ -241,29 +241,29 @@ void intro_v2d::preNewGame() { void intro_v2d::introInit() { _vm->_screen->displayList(kDisplayInit); _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen - surf.w = 320; - surf.h = 200; - surf.pixels = _vm->_screen->getFrontBuffer(); - surf.pitch = 320; - surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _surf.w = 320; + _surf.h = 200; + _surf.pixels = _vm->_screen->getFrontBuffer(); + _surf.pitch = 320; + _surf.format = Graphics::PixelFormat::createFormatCLUT8(); char buffer[128]; // TROMAN, size 10-5 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 8"); - if (_vm->_boot.registered) + if (_vm->_boot._registered) sprintf(buffer, "%s Registered Version", _vm->getCopyrightString()); else sprintf(buffer, "%s Shareware Version", _vm->getCopyrightString()); - font.drawString(&surf, buffer, 0, 186, 320, _TLIGHTRED, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 186, 320, _TLIGHTRED, Graphics::kTextAlignCenter); - if ((*_vm->_boot.distrib != '\0') && (scumm_stricmp(_vm->_boot.distrib, "David P. Gray"))) { + if ((*_vm->_boot._distrib != '\0') && (scumm_stricmp(_vm->_boot._distrib, "David P. Gray"))) { // TROMAN, size 10-5 - sprintf(buffer, "Distributed by %s.", _vm->_boot.distrib); - font.drawString(&surf, buffer, 0, 1, 320, _TLIGHTRED, Graphics::kTextAlignCenter); + sprintf(buffer, "Distributed by %s.", _vm->_boot._distrib); + _font.drawString(&_surf, buffer, 0, 1, 320, _TLIGHTRED, Graphics::kTextAlignCenter); } _vm->_screen->displayBackground(); @@ -287,27 +287,27 @@ void intro_v3d::preNewGame() { void intro_v3d::introInit() { _vm->_screen->displayList(kDisplayInit); _vm->_file->readBackground(_vm->_numScreens - 1); // display splash screen - surf.w = 320; - surf.h = 200; - surf.pixels = _vm->_screen->getFrontBuffer(); - surf.pitch = 320; - surf.format = Graphics::PixelFormat::createFormatCLUT8(); + _surf.w = 320; + _surf.h = 200; + _surf.pixels = _vm->_screen->getFrontBuffer(); + _surf.pitch = 320; + _surf.format = Graphics::PixelFormat::createFormatCLUT8(); char buffer[128]; - if (_vm->_boot.registered) + if (_vm->_boot._registered) sprintf(buffer, "%s Registered Version", _vm->getCopyrightString()); else sprintf(buffer,"%s Shareware Version", _vm->getCopyrightString()); // TROMAN, size 10-5 - if (!font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) + if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8))) error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 8"); - font.drawString(&surf, buffer, 0, 190, 320, _TBROWN, Graphics::kTextAlignCenter); + _font.drawString(&_surf, buffer, 0, 190, 320, _TBROWN, Graphics::kTextAlignCenter); - if ((*_vm->_boot.distrib != '\0') && (scumm_stricmp(_vm->_boot.distrib, "David P. Gray"))) { - sprintf(buffer, "Distributed by %s.", _vm->_boot.distrib); - font.drawString(&surf, buffer, 0, 0, 320, _TBROWN, Graphics::kTextAlignCenter); + if ((*_vm->_boot._distrib != '\0') && (scumm_stricmp(_vm->_boot._distrib, "David P. Gray"))) { + sprintf(buffer, "Distributed by %s.", _vm->_boot._distrib); + _font.drawString(&_surf, buffer, 0, 0, 320, _TBROWN, Graphics::kTextAlignCenter); } _vm->_screen->displayBackground(); @@ -316,7 +316,7 @@ void intro_v3d::introInit() { _vm->_file->readBackground(22); // display screen MAP_3d _vm->_screen->displayBackground(); - introTicks = 0; + _introTicks = 0; _vm->_sound->_DOSSongPtr = _vm->_sound->_DOSIntroSong; } @@ -325,15 +325,15 @@ void intro_v3d::introInit() { * Called every tick. Returns TRUE when complete */ bool intro_v3d::introPlay() { - if (_vm->getGameStatus().skipIntroFl) + if (_vm->getGameStatus()._skipIntroFl) return true; - if (introTicks < getIntroSize()) { - font.drawString(&surf, ".", _introX[introTicks], _introY[introTicks] - kDibOffY, 320, _TBRIGHTWHITE); + if (_introTicks < getIntroSize()) { + _font.drawString(&_surf, ".", _introX[_introTicks], _introY[_introTicks] - kDibOffY, 320, _TBRIGHTWHITE); _vm->_screen->displayBackground(); // Text boxes at various times - switch (introTicks) { + switch (_introTicks) { case 4: Utils::notifyBox(_vm->_text->getTextIntro(kIntro1)); break; @@ -346,7 +346,7 @@ bool intro_v3d::introPlay() { } } - return (++introTicks >= getIntroSize()); + return (++_introTicks >= getIntroSize()); } intro_v1w::intro_v1w(HugoEngine *vm) : IntroHandler(vm) { @@ -356,7 +356,7 @@ intro_v1w::~intro_v1w() { } void intro_v1w::preNewGame() { - _vm->getGameStatus().viewState = kViewIntroInit; + _vm->getGameStatus()._viewState = kViewIntroInit; } void intro_v1w::introInit() { @@ -407,7 +407,7 @@ void intro_v3w::introInit() { g_system->delayMillis(3000); _vm->_file->readBackground(22); // display screen MAP_3w _vm->_screen->displayBackground(); - introTicks = 0; + _introTicks = 0; _vm->_screen->loadFont(0); } @@ -416,16 +416,16 @@ void intro_v3w::introInit() { * Called every tick. Returns TRUE when complete */ bool intro_v3w::introPlay() { - if (_vm->getGameStatus().skipIntroFl) + if (_vm->getGameStatus()._skipIntroFl) return true; - if (introTicks < getIntroSize()) { + if (_introTicks < getIntroSize()) { // Scale viewport x_intro,y_intro to screen (offsetting y) - _vm->_screen->writeStr(_introX[introTicks], _introY[introTicks] - kDibOffY, "x", _TBRIGHTWHITE); + _vm->_screen->writeStr(_introX[_introTicks], _introY[_introTicks] - kDibOffY, "x", _TBRIGHTWHITE); _vm->_screen->displayBackground(); // Text boxes at various times - switch (introTicks) { + switch (_introTicks) { case 4: Utils::notifyBox(_vm->_text->getTextIntro(kIntro1)); break; @@ -438,6 +438,6 @@ bool intro_v3w::introPlay() { } } - return (++introTicks >= getIntroSize()); + return (++_introTicks >= getIntroSize()); } } // End of namespace Hugo diff --git a/engines/hugo/intro.h b/engines/hugo/intro.h index 1bb039216a..d5a5a4e4b4 100644 --- a/engines/hugo/intro.h +++ b/engines/hugo/intro.h @@ -42,8 +42,8 @@ enum seqTextIntro { class IntroHandler { public: IntroHandler(HugoEngine *vm); - Graphics::Surface surf; - Graphics::WinFont font; + Graphics::Surface _surf; + Graphics::WinFont _font; virtual ~IntroHandler(); @@ -62,7 +62,7 @@ protected: byte *_introX; byte *_introY; byte _introXSize; - int16 introTicks; // Count calls to introPlay() + int16 _introTicks; // Count calls to introPlay() }; class intro_v1w : public IntroHandler { diff --git a/engines/hugo/inventory.cpp b/engines/hugo/inventory.cpp index 410c4e715c..c2495beadb 100644 --- a/engines/hugo/inventory.cpp +++ b/engines/hugo/inventory.cpp @@ -56,7 +56,7 @@ void InventoryHandler::setInventoryObjId(int16 objId) { _inventoryObjId = objId; } -void InventoryHandler::setInventoryState(istate_t state) { +void InventoryHandler::setInventoryState(Istate state) { _inventoryState = state; } @@ -68,7 +68,7 @@ int16 InventoryHandler::getInventoryObjId() const { return _inventoryObjId; } -istate_t InventoryHandler::getInventoryState() const { +Istate InventoryHandler::getInventoryState() const { return _inventoryState; } @@ -137,8 +137,8 @@ void InventoryHandler::constructInventory(const int16 imageTotNumb, int displayN * Process required action for inventory * Returns objId under cursor (or -1) for INV_GET */ -int16 InventoryHandler::processInventory(const invact_t action, ...) { - debugC(1, kDebugInventory, "processInventory(invact_t action, ...)"); +int16 InventoryHandler::processInventory(const InvAct action, ...) { + debugC(1, kDebugInventory, "processInventory(InvAct action, ...)"); int16 imageNumb; // Total number of inventory items int displayNumb; // Total number displayed/carried @@ -208,7 +208,7 @@ int16 InventoryHandler::processInventory(const invact_t action, ...) { * Process inventory state machine */ void InventoryHandler::runInventory() { - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); debugC(1, kDebugInventory, "runInventory"); @@ -231,7 +231,7 @@ void InventoryHandler::runInventory() { _vm->_screen->moveImage(_vm->_screen->getBackBuffer(), 0, 0, kXPix, kYPix, kXPix, _vm->_screen->getFrontBuffer(), 0, 0, kXPix); _vm->_object->updateImages(); // Add objects back into display list for restore _inventoryState = kInventoryOff; - gameStatus.viewState = kViewPlay; + gameStatus._viewState = kViewPlay; } break; case kInventoryDown: // Icon bar moving down diff --git a/engines/hugo/inventory.h b/engines/hugo/inventory.h index 666cc37b51..5b55c3ec94 100644 --- a/engines/hugo/inventory.h +++ b/engines/hugo/inventory.h @@ -34,22 +34,22 @@ namespace Hugo { /** * Actions for Process_inventory() */ -enum invact_t {kInventoryActionInit, kInventoryActionLeft, kInventoryActionRight, kInventoryActionGet}; +enum InvAct {kInventoryActionInit, kInventoryActionLeft, kInventoryActionRight, kInventoryActionGet}; class InventoryHandler { public: InventoryHandler(HugoEngine *vm); void setInventoryObjId(int16 objId); - void setInventoryState(istate_t state); + void setInventoryState(Istate state); void freeInvent(); int16 getInventoryObjId() const; - istate_t getInventoryState() const; + Istate getInventoryState() const; int16 findIconId(int16 objId); void loadInvent(Common::SeekableReadStream &in); - int16 processInventory(const invact_t action, ...); + int16 processInventory(const InvAct action, ...); void runInventory(); private: @@ -59,7 +59,7 @@ private: int16 _firstIconId; // Index of first icon to display int16 *_invent; - istate_t _inventoryState; // Inventory icon bar state + Istate _inventoryState; // Inventory icon bar state int16 _inventoryHeight; // Inventory icon bar height int16 _inventoryObjId; // Inventory object selected, or -1 byte _maxInvent; diff --git a/engines/hugo/mouse.cpp b/engines/hugo/mouse.cpp index d2d5b59dae..a95170696c 100644 --- a/engines/hugo/mouse.cpp +++ b/engines/hugo/mouse.cpp @@ -98,17 +98,17 @@ int MouseHandler::getMouseY() const { } int16 MouseHandler::getDirection(const int16 hotspotId) const { - return _hotspots[hotspotId].direction; + return _hotspots[hotspotId]._direction; } int16 MouseHandler::getHotspotActIndex(const int16 hotspotId) const { - return _hotspots[hotspotId].actIndex; + return _hotspots[hotspotId]._actIndex; } /** * Shadow-blit supplied string into dib_a at cx,cy and add to display list */ -void MouseHandler::cursorText(const char *buffer, const int16 cx, const int16 cy, const uif_t fontId, const int16 color) { +void MouseHandler::cursorText(const char *buffer, const int16 cx, const int16 cy, const Uif fontId, const int16 color) { debugC(1, kDebugMouse, "cursorText(%s, %d, %d, %d, %d)", buffer, cx, cy, fontId, color); _vm->_screen->loadFont(fontId); @@ -137,9 +137,9 @@ void MouseHandler::cursorText(const char *buffer, const int16 cx, const int16 cy int16 MouseHandler::findExit(const int16 cx, const int16 cy, byte screenId) { debugC(2, kDebugMouse, "findExit(%d, %d, %d)", cx, cy, screenId); - for (int i = 0; _hotspots[i].screenIndex >= 0; i++) { - if (_hotspots[i].screenIndex == screenId) { - if (cx >= _hotspots[i].x1 && cx <= _hotspots[i].x2 && cy >= _hotspots[i].y1 && cy <= _hotspots[i].y2) + for (int i = 0; _hotspots[i]._screenIndex >= 0; i++) { + if (_hotspots[i]._screenIndex == screenId) { + if (cx >= _hotspots[i]._x1 && cx <= _hotspots[i]._x2 && cy >= _hotspots[i]._y1 && cy <= _hotspots[i]._y2) return i; } } @@ -152,9 +152,9 @@ int16 MouseHandler::findExit(const int16 cx, const int16 cy, byte screenId) { void MouseHandler::processRightClick(const int16 objId, const int16 cx, const int16 cy) { debugC(1, kDebugMouse, "ProcessRightClick(%d, %d, %d)", objId, cx, cy); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); - if (gameStatus.storyModeFl || _vm->_hero->pathType == kPathQuiet) // Make sure user has control + if (gameStatus._storyModeFl || _vm->_hero->_pathType == kPathQuiet) // Make sure user has control return; int16 inventObjId = _vm->_inventory->getInventoryObjId(); @@ -168,9 +168,9 @@ void MouseHandler::processRightClick(const int16 objId, const int16 cx, const in else _vm->_object->useObject(objId); // Use status.objid on object } else { // Clicked over viewport object - object_t *obj = &_vm->_object->_objects[objId]; + Object *obj = &_vm->_object->_objects[objId]; int16 x, y; - switch (obj->viewx) { // Where to walk to + switch (obj->_viewx) { // Where to walk to case -1: // Walk to object position if (_vm->_object->findObjectSpace(obj, &x, &y)) foundFl = _vm->_route->startRoute(kRouteGet, objId, x, y); @@ -181,8 +181,8 @@ void MouseHandler::processRightClick(const int16 objId, const int16 cx, const in _vm->_object->useObject(objId); // Pick up or use object break; default: // Walk to view point if possible - if (!_vm->_route->startRoute(kRouteGet, objId, obj->viewx, obj->viewy)) { - if (_vm->_hero->cycling == kCycleInvisible) // If invisible do + if (!_vm->_route->startRoute(kRouteGet, objId, obj->_viewx, obj->_viewy)) { + if (_vm->_hero->_cycling == kCycleInvisible) // If invisible do _vm->_object->useObject(objId); // immediate use else Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there @@ -203,11 +203,11 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int debugC(1, kDebugMouse, "ProcessLeftClick(%d, %d, %d)", objId, cx, cy); int16 i, x, y; - object_t *obj; + Object *obj; - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); - if (gameStatus.storyModeFl || _vm->_hero->pathType == kPathQuiet) // Make sure user has control + if (gameStatus._storyModeFl || _vm->_hero->_pathType == kPathQuiet) // Make sure user has control return; switch (objId) { @@ -223,20 +223,20 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int _vm->_screen->displayList(kDisplayAdd, 0, kDibOffY, kXPix, kInvDy); break; case kExitHotspot: // Walk to exit hotspot - i = findExit(cx, cy, *_vm->_screen_p); - x = _hotspots[i].viewx; - y = _hotspots[i].viewy; + i = findExit(cx, cy, *_vm->_screenPtr); + x = _hotspots[i]._viewx; + y = _hotspots[i]._viewy; if (x >= 0) { // Hotspot refers to an exit // Special case of immediate exit if (_jumpExitFl) { // Get rid of iconbar if necessary if (_vm->_inventory->getInventoryState() != kInventoryOff) _vm->_inventory->setInventoryState(kInventoryUp); - _vm->_scheduler->insertActionList(_hotspots[i].actIndex); + _vm->_scheduler->insertActionList(_hotspots[i]._actIndex); } else { // Set up route to exit spot - if (_hotspots[i].direction == Common::KEYCODE_RIGHT) + if (_hotspots[i]._direction == Common::KEYCODE_RIGHT) x -= kHeroMaxWidth; - else if (_hotspots[i].direction == Common::KEYCODE_LEFT) + else if (_hotspots[i]._direction == Common::KEYCODE_LEFT) x += kHeroMaxWidth; if (!_vm->_route->startRoute(kRouteExit, i, x, y)) Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there @@ -254,7 +254,7 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int _vm->_object->lookObject(obj); } else { bool foundFl = false; // TRUE if route found to object - switch (obj->viewx) { // Clicked over viewport object + switch (obj->_viewx) { // Clicked over viewport object case -1: // Walk to object position if (_vm->_object->findObjectSpace(obj, &x, &y)) foundFl = _vm->_route->startRoute(kRouteLook, objId, x, y); @@ -265,8 +265,8 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int _vm->_object->lookObject(obj); break; default: // Walk to view point if possible - if (!_vm->_route->startRoute(kRouteLook, objId, obj->viewx, obj->viewy)) { - if (_vm->_hero->cycling == kCycleInvisible) // If invisible do + if (!_vm->_route->startRoute(kRouteLook, objId, obj->_viewx, obj->_viewy)) { + if (_vm->_hero->_cycling == kCycleInvisible) // If invisible do _vm->_object->lookObject(obj); // immediate decription else Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there @@ -284,16 +284,16 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int void MouseHandler::mouseHandler() { debugC(2, kDebugMouse, "mouseHandler"); - status_t &gameStatus = _vm->getGameStatus(); - istate_t inventState = _vm->_inventory->getInventoryState(); - if ((gameStatus.viewState != kViewPlay) && (inventState != kInventoryActive)) + Status &gameStatus = _vm->getGameStatus(); + Istate inventState = _vm->_inventory->getInventoryState(); + if ((gameStatus._viewState != kViewPlay) && (inventState != kInventoryActive)) return; int16 cx = getMouseX(); int16 cy = getMouseY(); -// gameStatus.cx = cx; // Save cursor coords -// gameStatus.cy = cy; +// gameStatus._cx = cx; // Save cursor coords +// gameStatus._cy = cy; // Don't process if outside client area if ((cx < 0) || (cx > kXPix) || (cy < kDibOffY) || (cy > kViewSizeY + kDibOffY)) @@ -309,14 +309,14 @@ void MouseHandler::mouseHandler() { } } - if (!gameStatus.gameOverFl) { + if (!gameStatus._gameOverFl) { if (objId == -1) // No match, check rest of view objId = _vm->_object->findObject(cx, cy); if (objId >= 0) { // Got a match // Display object name next to cursor (unless CURSOR_NOCHAR) // Note test for swapped hero name - const char *name = _vm->_text->getNoun(_vm->_object->_objects[(objId == kHeroIndex) ? _vm->_heroImage : objId].nounIndex, kCursorNameIndex); + const char *name = _vm->_text->getNoun(_vm->_object->_objects[(objId == kHeroIndex) ? _vm->_heroImage : objId]._nounIndex, kCursorNameIndex); if (name[0] != kCursorNochar) cursorText(name, cx, cy, U_FONT8, _TBRIGHTWHITE); @@ -327,8 +327,8 @@ void MouseHandler::mouseHandler() { // Process cursor over an exit hotspot if (objId == -1) { - int i = findExit(cx, cy, *_vm->_screen_p); - if (i != -1 && _hotspots[i].viewx >= 0) { + int i = findExit(cx, cy, *_vm->_screenPtr); + if (i != -1 && _hotspots[i]._viewx >= 0) { objId = kExitHotspot; cursorText(_vm->_text->getTextMouse(kMsExit), cx, cy, U_FONT8, _TBRIGHTWHITE); } @@ -343,29 +343,29 @@ void MouseHandler::mouseHandler() { resetRightButton(); } -void MouseHandler::readHotspot(Common::ReadStream &in, hotspot_t &hotspot) { - hotspot.screenIndex = in.readSint16BE(); - hotspot.x1 = in.readSint16BE(); - hotspot.y1 = in.readSint16BE(); - hotspot.x2 = in.readSint16BE(); - hotspot.y2 = in.readSint16BE(); - hotspot.actIndex = in.readUint16BE(); - hotspot.viewx = in.readSint16BE(); - hotspot.viewy = in.readSint16BE(); - hotspot.direction = in.readSint16BE(); +void MouseHandler::readHotspot(Common::ReadStream &in, Hotspot &hotspot) { + hotspot._screenIndex = in.readSint16BE(); + hotspot._x1 = in.readSint16BE(); + hotspot._y1 = in.readSint16BE(); + hotspot._x2 = in.readSint16BE(); + hotspot._y2 = in.readSint16BE(); + hotspot._actIndex = in.readUint16BE(); + hotspot._viewx = in.readSint16BE(); + hotspot._viewy = in.readSint16BE(); + hotspot._direction = in.readSint16BE(); } /** * Load hotspots data from hugo.dat */ void MouseHandler::loadHotspots(Common::ReadStream &in) { - hotspot_t *wrkHotspots = 0; - hotspot_t tmp; + Hotspot *wrkHotspots = 0; + Hotspot tmp; memset(&tmp, 0, sizeof(tmp)); for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { int numRows = in.readUint16BE(); if (varnt == _vm->_gameVariant) - _hotspots = wrkHotspots = (hotspot_t *)malloc(sizeof(hotspot_t) * numRows); + _hotspots = wrkHotspots = (Hotspot *)malloc(sizeof(Hotspot) * numRows); for (int i = 0; i < numRows; i++) readHotspot(in, (varnt == _vm->_gameVariant) ? wrkHotspots[i] : tmp); @@ -376,10 +376,10 @@ void MouseHandler::loadHotspots(Common::ReadStream &in) { * Display hotspot boundaries for the current screen */ void MouseHandler::drawHotspots() const { - for (int i = 0; _hotspots[i].screenIndex >= 0; i++) { - hotspot_t *hotspot = &_hotspots[i]; - if (hotspot->screenIndex == _vm->_hero->screenIndex) - _vm->_screen->drawRectangle(false, hotspot->x1, hotspot->y1, hotspot->x2, hotspot->y2, _TLIGHTRED); + for (int i = 0; _hotspots[i]._screenIndex >= 0; i++) { + Hotspot *hotspot = &_hotspots[i]; + if (hotspot->_screenIndex == _vm->_hero->_screenIndex) + _vm->_screen->drawRectangle(false, hotspot->_x1, hotspot->_y1, hotspot->_x2, hotspot->_y2, _TLIGHTRED); } } } // End of namespace Hugo diff --git a/engines/hugo/mouse.h b/engines/hugo/mouse.h index 35f9e4e87e..e20716f72c 100644 --- a/engines/hugo/mouse.h +++ b/engines/hugo/mouse.h @@ -70,17 +70,17 @@ private: kMsExit = 1 }; - hotspot_t *_hotspots; + Hotspot *_hotspots; bool _leftButtonFl; // Left mouse button pressed bool _rightButtonFl; // Right button pressed int _mouseX; int _mouseY; bool _jumpExitFl; // Allowed to jump to a screen exit - void cursorText(const char *buffer, const int16 cx, const int16 cy, const uif_t fontId, const int16 color); + void cursorText(const char *buffer, const int16 cx, const int16 cy, const Uif fontId, const int16 color); void processRightClick(const int16 objId, const int16 cx, const int16 cy); void processLeftClick(const int16 objId, const int16 cx, const int16 cy); - void readHotspot(Common::ReadStream &in, hotspot_t &hotspot); + void readHotspot(Common::ReadStream &in, Hotspot &hotspot); }; } // End of namespace Hugo diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp index bc99abf410..7b4783e4d8 100644 --- a/engines/hugo/object.cpp +++ b/engines/hugo/object.cpp @@ -48,10 +48,10 @@ ObjectHandler::ObjectHandler(HugoEngine *vm) : _vm(vm), _objects(0), _uses(0) { _numObj = 0; _objCount = 0; _usesSize = 0; - memset(_objBound, '\0', sizeof(overlay_t)); - memset(_boundary, '\0', sizeof(overlay_t)); - memset(_overlay, '\0', sizeof(overlay_t)); - memset(_ovlBase, '\0', sizeof(overlay_t)); + memset(_objBound, '\0', sizeof(Overlay)); + memset(_boundary, '\0', sizeof(Overlay)); + memset(_overlay, '\0', sizeof(Overlay)); + memset(_ovlBase, '\0', sizeof(Overlay)); } ObjectHandler::~ObjectHandler() { @@ -74,55 +74,55 @@ byte ObjectHandler::getFirstOverlay(uint16 index) const { } bool ObjectHandler::isCarried(int objIndex) const { - return _objects[objIndex].carriedFl; + return _objects[objIndex]._carriedFl; } void ObjectHandler::setCarry(int objIndex, bool val) { - _objects[objIndex].carriedFl = val; + _objects[objIndex]._carriedFl = val; } void ObjectHandler::setVelocity(int objIndex, int8 vx, int8 vy) { - _objects[objIndex].vx = vx; - _objects[objIndex].vy = vy; + _objects[objIndex]._vx = vx; + _objects[objIndex]._vy = vy; } -void ObjectHandler::setPath(int objIndex, path_t pathType, int16 vxPath, int16 vyPath) { - _objects[objIndex].pathType = pathType; - _objects[objIndex].vxPath = vxPath; - _objects[objIndex].vyPath = vyPath; +void ObjectHandler::setPath(int objIndex, Path pathType, int16 vxPath, int16 vyPath) { + _objects[objIndex]._pathType = pathType; + _objects[objIndex]._vxPath = vxPath; + _objects[objIndex]._vyPath = vyPath; } /** * Save sequence number and image number in given object */ -void ObjectHandler::saveSeq(object_t *obj) { +void ObjectHandler::saveSeq(Object *obj) { debugC(1, kDebugObject, "saveSeq"); bool found = false; - for (int i = 0; !found && (i < obj->seqNumb); i++) { - seq_t *q = obj->seqList[i].seqPtr; - for (int j = 0; !found && (j < obj->seqList[i].imageNbr); j++) { - if (obj->currImagePtr == q) { + for (int i = 0; !found && (i < obj->_seqNumb); i++) { + Seq *q = obj->_seqList[i]._seqPtr; + for (int j = 0; !found && (j < obj->_seqList[i]._imageNbr); j++) { + if (obj->_currImagePtr == q) { found = true; - obj->curSeqNum = i; - obj->curImageNum = j; + obj->_curSeqNum = i; + obj->_curImageNum = j; } else { - q = q->nextSeqPtr; + q = q->_nextSeqPtr; } } } } /** - * Set up cur_seq_p from stored sequence and image number in object + * Set up cur_seqPtr from stored sequence and image number in object */ -void ObjectHandler::restoreSeq(object_t *obj) { +void ObjectHandler::restoreSeq(Object *obj) { debugC(1, kDebugObject, "restoreSeq"); - seq_t *q = obj->seqList[obj->curSeqNum].seqPtr; - for (int j = 0; j < obj->curImageNum; j++) - q = q->nextSeqPtr; - obj->currImagePtr = q; + Seq *q = obj->_seqList[obj->_curSeqNum]._seqPtr; + for (int j = 0; j < obj->_curImageNum; j++) + q = q->_nextSeqPtr; + obj->_currImagePtr = q; } /** @@ -134,36 +134,36 @@ void ObjectHandler::useObject(int16 objId) { const char *verb; // Background verb to use directly int16 inventObjId = _vm->_inventory->getInventoryObjId(); - object_t *obj = &_objects[objId]; // Ptr to object + Object *obj = &_objects[objId]; // Ptr to object if (inventObjId == -1) { // Get or use objid directly - if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item - sprintf(_vm->_line, "%s %s", _vm->_text->getVerb(_vm->_take, 0), _vm->_text->getNoun(obj->nounIndex, 0)); - else if (obj->cmdIndex != 0) // Use non-collectible item if able - sprintf(_vm->_line, "%s %s", _vm->_text->getVerb(_vm->_parser->getCmdDefaultVerbIdx(obj->cmdIndex), 0), _vm->_text->getNoun(obj->nounIndex, 0)); - else if ((verb = _vm->_parser->useBG(_vm->_text->getNoun(obj->nounIndex, 0))) != 0) - sprintf(_vm->_line, "%s %s", verb, _vm->_text->getNoun(obj->nounIndex, 0)); + if ((obj->_genericCmd & TAKE) || obj->_objValue) // Get collectible item + sprintf(_vm->_line, "%s %s", _vm->_text->getVerb(_vm->_take, 0), _vm->_text->getNoun(obj->_nounIndex, 0)); + else if (obj->_cmdIndex != 0) // Use non-collectible item if able + sprintf(_vm->_line, "%s %s", _vm->_text->getVerb(_vm->_parser->getCmdDefaultVerbIdx(obj->_cmdIndex), 0), _vm->_text->getNoun(obj->_nounIndex, 0)); + else if ((verb = _vm->_parser->useBG(_vm->_text->getNoun(obj->_nounIndex, 0))) != 0) + sprintf(_vm->_line, "%s %s", verb, _vm->_text->getNoun(obj->_nounIndex, 0)); else return; // Can't use object directly } else { // Use status.objid on objid // Default to first cmd verb - sprintf(_vm->_line, "%s %s %s", _vm->_text->getVerb(_vm->_parser->getCmdDefaultVerbIdx(_objects[inventObjId].cmdIndex), 0), - _vm->_text->getNoun(_objects[inventObjId].nounIndex, 0), - _vm->_text->getNoun(obj->nounIndex, 0)); + sprintf(_vm->_line, "%s %s %s", _vm->_text->getVerb(_vm->_parser->getCmdDefaultVerbIdx(_objects[inventObjId]._cmdIndex), 0), + _vm->_text->getNoun(_objects[inventObjId]._nounIndex, 0), + _vm->_text->getNoun(obj->_nounIndex, 0)); // Check valid use of objects and override verb if necessary - for (uses_t *use = _uses; use->objId != _numObj; use++) { - if (inventObjId == use->objId) { + for (Uses *use = _uses; use->_objId != _numObj; use++) { + if (inventObjId == use->_objId) { // Look for secondary object, if found use matching verb bool foundFl = false; - for (target_t *target = use->targets; target->nounIndex != 0; target++) - if (target->nounIndex == obj->nounIndex) { + for (Target *target = use->_targets; target->_nounIndex != 0; target++) + if (target->_nounIndex == obj->_nounIndex) { foundFl = true; - sprintf(_vm->_line, "%s %s %s", _vm->_text->getVerb(target->verbIndex, 0), - _vm->_text->getNoun(_objects[inventObjId].nounIndex, 0), - _vm->_text->getNoun(obj->nounIndex, 0)); + sprintf(_vm->_line, "%s %s %s", _vm->_text->getVerb(target->_verbIndex, 0), + _vm->_text->getNoun(_objects[inventObjId]._nounIndex, 0), + _vm->_text->getNoun(obj->_nounIndex, 0)); } // No valid use of objects found, print failure string @@ -171,7 +171,7 @@ void ObjectHandler::useObject(int16 objId) { // Deselect dragged icon if inventory not active if (_vm->_inventory->getInventoryState() != kInventoryActive) _vm->_screen->resetInventoryObjId(); - Utils::notifyBox(_vm->_text->getTextData(use->dataIndex)); + Utils::notifyBox(_vm->_text->getTextData(use->_dataIndex)); return; } } @@ -195,30 +195,30 @@ int16 ObjectHandler::findObject(uint16 x, uint16 y) { int16 objIndex = -1; // Index of found object uint16 y2Max = 0; // Greatest y2 - object_t *obj = _objects; + Object *obj = _objects; // Check objects on screen for (int i = 0; i < _numObj; i++, obj++) { // Object must be in current screen and "useful" - if (obj->screenIndex == *_vm->_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) { - seq_t *curImage = obj->currImagePtr; + if (obj->_screenIndex == *_vm->_screenPtr && (obj->_genericCmd || obj->_objValue || obj->_cmdIndex)) { + Seq *curImage = obj->_currImagePtr; // Object must have a visible image... - if (curImage != 0 && obj->cycling != kCycleInvisible) { + if (curImage != 0 && obj->_cycling != kCycleInvisible) { // If cursor inside object - if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2) { + if (x >= (uint16)obj->_x && x <= obj->_x + curImage->_x2 && y >= (uint16)obj->_y && y <= obj->_y + curImage->_y2) { // If object is closest so far - if (obj->y + curImage->y2 > y2Max) { - y2Max = obj->y + curImage->y2; + if (obj->_y + curImage->_y2 > y2Max) { + y2Max = obj->_y + curImage->_y2; objIndex = i; // Found an object! } } } else { // ...or a dummy object that has a hotspot rectangle - if (curImage == 0 && obj->vxPath != 0 && !obj->carriedFl) { + if (curImage == 0 && obj->_vxPath != 0 && !obj->_carriedFl) { // If cursor inside special rectangle - if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath) { + if ((int16)x >= obj->_oldx && (int16)x < obj->_oldx + obj->_vxPath && (int16)y >= obj->_oldy && (int16)y < obj->_oldy + obj->_vyPath) { // If object is closest so far - if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) { - y2Max = obj->oldy + obj->vyPath - 1; + if (obj->_oldy + obj->_vyPath - 1 > (int16)y2Max) { + y2Max = obj->_oldy + obj->_vyPath - 1; objIndex = i; // Found an object! } } @@ -233,14 +233,14 @@ int16 ObjectHandler::findObject(uint16 x, uint16 y) { * Issue "Look at <object>" command * Note special case of swapped hero image */ -void ObjectHandler::lookObject(object_t *obj) { +void ObjectHandler::lookObject(Object *obj) { debugC(1, kDebugObject, "lookObject"); if (obj == _vm->_hero) // Hero swapped - look at other obj = &_objects[_vm->_heroImage]; - _vm->_parser->command("%s %s", _vm->_text->getVerb(_vm->_look, 0), _vm->_text->getNoun(obj->nounIndex, 0)); + _vm->_parser->command("%s %s", _vm->_text->getVerb(_vm->_look, 0), _vm->_text->getNoun(obj->_nounIndex, 0)); } /** @@ -249,26 +249,26 @@ void ObjectHandler::lookObject(object_t *obj) { void ObjectHandler::freeObjects() { debugC(1, kDebugObject, "freeObjects"); - if (_vm->_hero != 0 && _vm->_hero->seqList[0].seqPtr != 0) { + if (_vm->_hero != 0 && _vm->_hero->_seqList[0]._seqPtr != 0) { // Free all sequence lists and image data for (int16 i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - for (int16 j = 0; j < obj->seqNumb; j++) { - seq_t *seq = obj->seqList[j].seqPtr; - seq_t *next; + Object *obj = &_objects[i]; + for (int16 j = 0; j < obj->_seqNumb; j++) { + Seq *seq = obj->_seqList[j]._seqPtr; + Seq *next; if (seq == 0) // Failure during database load break; - if (seq->imagePtr != 0) { - free(seq->imagePtr); - seq->imagePtr = 0; + if (seq->_imagePtr != 0) { + free(seq->_imagePtr); + seq->_imagePtr = 0; } - seq = seq->nextSeqPtr; - while (seq != obj->seqList[j].seqPtr) { - if (seq->imagePtr != 0) { - free(seq->imagePtr); - seq->imagePtr = 0; + seq = seq->_nextSeqPtr; + while (seq != obj->_seqList[j]._seqPtr) { + if (seq->_imagePtr != 0) { + free(seq->_imagePtr); + seq->_imagePtr = 0; } - next = seq->nextSeqPtr; + next = seq->_nextSeqPtr; free(seq); seq = next; } @@ -279,13 +279,13 @@ void ObjectHandler::freeObjects() { if (_uses) { for (int16 i = 0; i < _usesSize; i++) - free(_uses[i].targets); + free(_uses[i]._targets); free(_uses); } for (int16 i = 0; i < _objCount; i++) { - free(_objects[i].stateDataIndex); - _objects[i].stateDataIndex = 0; + free(_objects[i]._stateDataIndex); + _objects[i]._stateDataIndex = 0; } free(_objects); @@ -300,27 +300,27 @@ void ObjectHandler::freeObjects() { int ObjectHandler::y2comp(const void *a, const void *b) { debugC(6, kDebugObject, "y2comp"); - const object_t *p1 = &HugoEngine::get()._object->_objects[*(const byte *)a]; - const object_t *p2 = &HugoEngine::get()._object->_objects[*(const byte *)b]; + const Object *p1 = &HugoEngine::get()._object->_objects[*(const byte *)a]; + const Object *p2 = &HugoEngine::get()._object->_objects[*(const byte *)b]; if (p1 == p2) // Why does qsort try the same indexes? return 0; - if (p1->priority == kPriorityBackground) + if (p1->_priority == kPriorityBackground) return -1; - if (p2->priority == kPriorityBackground) + if (p2->_priority == kPriorityBackground) return 1; - if (p1->priority == kPriorityForeground) + if (p1->_priority == kPriorityForeground) return 1; - if (p2->priority == kPriorityForeground) + if (p2->_priority == kPriorityForeground) return -1; - int ay2 = p1->y + p1->currImagePtr->y2; - int by2 = p2->y + p2->currImagePtr->y2; + int ay2 = p1->_y + p1->_currImagePtr->_y2; + int by2 = p2->_y + p2->_currImagePtr->_y2; return ay2 - by2; } @@ -332,7 +332,7 @@ bool ObjectHandler::isCarrying(uint16 wordIndex) { debugC(1, kDebugObject, "isCarrying(%d)", wordIndex); for (int i = 0; i < _numObj; i++) { - if ((wordIndex == _objects[i].nounIndex) && _objects[i].carriedFl) + if ((wordIndex == _objects[i]._nounIndex) && _objects[i]._carriedFl) return true; } return false; @@ -345,11 +345,11 @@ void ObjectHandler::showTakeables() { debugC(1, kDebugObject, "showTakeables"); for (int j = 0; j < _numObj; j++) { - object_t *obj = &_objects[j]; - if ((obj->cycling != kCycleInvisible) && - (obj->screenIndex == *_vm->_screen_p) && - (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) { - Utils::notifyBox(Common::String::format("You can also see:\n%s.", _vm->_text->getNoun(obj->nounIndex, LOOK_NAME))); + Object *obj = &_objects[j]; + if ((obj->_cycling != kCycleInvisible) && + (obj->_screenIndex == *_vm->_screenPtr) && + (((TAKE & obj->_genericCmd) == TAKE) || obj->_objValue)) { + Utils::notifyBox(Common::String::format("You can also see:\n%s.", _vm->_text->getNoun(obj->_nounIndex, LOOK_NAME))); } } } @@ -357,22 +357,22 @@ void ObjectHandler::showTakeables() { /** * Find a clear space around supplied object that hero can walk to */ -bool ObjectHandler::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) { +bool ObjectHandler::findObjectSpace(Object *obj, int16 *destx, int16 *desty) { debugC(1, kDebugObject, "findObjectSpace(obj, %d, %d)", *destx, *desty); - seq_t *curImage = obj->currImagePtr; - int16 y = obj->y + curImage->y2 - 1; + Seq *curImage = obj->_currImagePtr; + int16 y = obj->_y + curImage->_y2 - 1; bool foundFl = true; // Try left rear corner - for (int16 x = *destx = obj->x + curImage->x1; x < *destx + kHeroMaxWidth; x++) { + for (int16 x = *destx = obj->_x + curImage->_x1; x < *destx + kHeroMaxWidth; x++) { if (checkBoundary(x, y)) foundFl = false; } if (!foundFl) { // Try right rear corner foundFl = true; - for (int16 x = *destx = obj->x + curImage->x2 - kHeroMaxWidth + 1; x <= obj->x + (int16)curImage->x2; x++) { + for (int16 x = *destx = obj->_x + curImage->_x2 - kHeroMaxWidth + 1; x <= obj->_x + (int16)curImage->_x2; x++) { if (checkBoundary(x, y)) foundFl = false; } @@ -381,7 +381,7 @@ bool ObjectHandler::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) { if (!foundFl) { // Try left front corner foundFl = true; y += 2; - for (int16 x = *destx = obj->x + curImage->x1; x < *destx + kHeroMaxWidth; x++) { + for (int16 x = *destx = obj->_x + curImage->_x1; x < *destx + kHeroMaxWidth; x++) { if (checkBoundary(x, y)) foundFl = false; } @@ -389,7 +389,7 @@ bool ObjectHandler::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) { if (!foundFl) { // Try right rear corner foundFl = true; - for (int16 x = *destx = obj->x + curImage->x2 - kHeroMaxWidth + 1; x <= obj->x + (int16)curImage->x2; x++) { + for (int16 x = *destx = obj->_x + curImage->_x2 - kHeroMaxWidth + 1; x <= obj->_x + (int16)curImage->_x2; x++) { if (checkBoundary(x, y)) foundFl = false; } @@ -399,29 +399,29 @@ bool ObjectHandler::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) { return foundFl; } -void ObjectHandler::readUse(Common::ReadStream &in, uses_t &curUse) { - curUse.objId = in.readSint16BE(); - curUse.dataIndex = in.readUint16BE(); +void ObjectHandler::readUse(Common::ReadStream &in, Uses &curUse) { + curUse._objId = in.readSint16BE(); + curUse._dataIndex = in.readUint16BE(); uint16 numSubElem = in.readUint16BE(); - curUse.targets = (target_t *)malloc(sizeof(target_t) * numSubElem); + curUse._targets = (Target *)malloc(sizeof(Target) * numSubElem); for (int j = 0; j < numSubElem; j++) { - curUse.targets[j].nounIndex = in.readUint16BE(); - curUse.targets[j].verbIndex = in.readUint16BE(); + curUse._targets[j]._nounIndex = in.readUint16BE(); + curUse._targets[j]._verbIndex = in.readUint16BE(); } } /** * Load _uses from Hugo.dat */ void ObjectHandler::loadObjectUses(Common::ReadStream &in) { - uses_t tmpUse; - tmpUse.targets = 0; + Uses tmpUse; + tmpUse._targets = 0; //Read _uses for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { uint16 numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) { _usesSize = numElem; - _uses = (uses_t *)malloc(sizeof(uses_t) * numElem); + _uses = (Uses *)malloc(sizeof(Uses) * numElem); } for (int i = 0; i < numElem; i++) { @@ -429,83 +429,83 @@ void ObjectHandler::loadObjectUses(Common::ReadStream &in) { readUse(in, _uses[i]); else { readUse(in, tmpUse); - free(tmpUse.targets); - tmpUse.targets = 0; + free(tmpUse._targets); + tmpUse._targets = 0; } } } } -void ObjectHandler::readObject(Common::ReadStream &in, object_t &curObject) { - curObject.nounIndex = in.readUint16BE(); - curObject.dataIndex = in.readUint16BE(); +void ObjectHandler::readObject(Common::ReadStream &in, Object &curObject) { + curObject._nounIndex = in.readUint16BE(); + curObject._dataIndex = in.readUint16BE(); uint16 numSubElem = in.readUint16BE(); if (numSubElem == 0) - curObject.stateDataIndex = 0; + curObject._stateDataIndex = 0; else - curObject.stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem); + curObject._stateDataIndex = (uint16 *)malloc(sizeof(uint16) * numSubElem); for (int j = 0; j < numSubElem; j++) - curObject.stateDataIndex[j] = in.readUint16BE(); - - curObject.pathType = (path_t) in.readSint16BE(); - curObject.vxPath = in.readSint16BE(); - curObject.vyPath = in.readSint16BE(); - curObject.actIndex = in.readUint16BE(); - curObject.seqNumb = in.readByte(); - curObject.currImagePtr = 0; - - if (curObject.seqNumb == 0) { - curObject.seqList[0].imageNbr = 0; - curObject.seqList[0].seqPtr = 0; + curObject._stateDataIndex[j] = in.readUint16BE(); + + curObject._pathType = (Path) in.readSint16BE(); + curObject._vxPath = in.readSint16BE(); + curObject._vyPath = in.readSint16BE(); + curObject._actIndex = in.readUint16BE(); + curObject._seqNumb = in.readByte(); + curObject._currImagePtr = 0; + + if (curObject._seqNumb == 0) { + curObject._seqList[0]._imageNbr = 0; + curObject._seqList[0]._seqPtr = 0; } - for (int j = 0; j < curObject.seqNumb; j++) { - curObject.seqList[j].imageNbr = in.readUint16BE(); - curObject.seqList[j].seqPtr = 0; + for (int j = 0; j < curObject._seqNumb; j++) { + curObject._seqList[j]._imageNbr = in.readUint16BE(); + curObject._seqList[j]._seqPtr = 0; } - curObject.cycling = (cycle_t)in.readByte(); - curObject.cycleNumb = in.readByte(); - curObject.frameInterval = in.readByte(); - curObject.frameTimer = in.readByte(); - curObject.radius = in.readByte(); - curObject.screenIndex = in.readByte(); - curObject.x = in.readSint16BE(); - curObject.y = in.readSint16BE(); - curObject.oldx = in.readSint16BE(); - curObject.oldy = in.readSint16BE(); - curObject.vx = in.readByte(); - curObject.vy = in.readByte(); - curObject.objValue = in.readByte(); - curObject.genericCmd = in.readSint16BE(); - curObject.cmdIndex = in.readUint16BE(); - curObject.carriedFl = (in.readByte() != 0); - curObject.state = in.readByte(); - curObject.verbOnlyFl = (in.readByte() != 0); - curObject.priority = in.readByte(); - curObject.viewx = in.readSint16BE(); - curObject.viewy = in.readSint16BE(); - curObject.direction = in.readSint16BE(); - curObject.curSeqNum = in.readByte(); - curObject.curImageNum = in.readByte(); - curObject.oldvx = in.readByte(); - curObject.oldvy = in.readByte(); + curObject._cycling = (Cycle)in.readByte(); + curObject._cycleNumb = in.readByte(); + curObject._frameInterval = in.readByte(); + curObject._frameTimer = in.readByte(); + curObject._radius = in.readByte(); + curObject._screenIndex = in.readByte(); + curObject._x = in.readSint16BE(); + curObject._y = in.readSint16BE(); + curObject._oldx = in.readSint16BE(); + curObject._oldy = in.readSint16BE(); + curObject._vx = in.readByte(); + curObject._vy = in.readByte(); + curObject._objValue = in.readByte(); + curObject._genericCmd = in.readSint16BE(); + curObject._cmdIndex = in.readUint16BE(); + curObject._carriedFl = (in.readByte() != 0); + curObject._state = in.readByte(); + curObject._verbOnlyFl = (in.readByte() != 0); + curObject._priority = in.readByte(); + curObject._viewx = in.readSint16BE(); + curObject._viewy = in.readSint16BE(); + curObject._direction = in.readSint16BE(); + curObject._curSeqNum = in.readByte(); + curObject._curImageNum = in.readByte(); + curObject._oldvx = in.readByte(); + curObject._oldvy = in.readByte(); } /** * Load ObjectArr from Hugo.dat */ void ObjectHandler::loadObjectArr(Common::ReadStream &in) { debugC(6, kDebugObject, "loadObject(&in)"); - object_t tmpObject; - tmpObject.stateDataIndex = 0; + Object tmpObject; + tmpObject._stateDataIndex = 0; for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { uint16 numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) { _objCount = numElem; - _objects = (object_t *)malloc(sizeof(object_t) * numElem); + _objects = (Object *)malloc(sizeof(Object) * numElem); } for (int i = 0; i < numElem; i++) { @@ -514,8 +514,8 @@ void ObjectHandler::loadObjectArr(Common::ReadStream &in) { else { // Skip over uneeded objects. readObject(in, tmpObject); - free(tmpObject.stateDataIndex); - tmpObject.stateDataIndex = 0; + free(tmpObject._stateDataIndex); + tmpObject._stateDataIndex = 0; } } } @@ -528,7 +528,7 @@ void ObjectHandler::loadObjectArr(Common::ReadStream &in) { void ObjectHandler::setCarriedScreen(int screenNum) { for (int i = kHeroIndex + 1; i < _numObj; i++) {// Any others if (isCarried(i)) // being carried - _objects[i].screenIndex = screenNum; + _objects[i]._screenIndex = screenNum; } } @@ -559,33 +559,33 @@ void ObjectHandler::restoreAllSeq() { */ void ObjectHandler::saveObjects(Common::WriteStream *out) { for (int i = 0; i < _numObj; i++) { - // Save where curr_seq_p is pointing to + // Save where curr_seqPtr is pointing to saveSeq(&_objects[i]); - out->writeByte(_objects[i].pathType); - out->writeSint16BE(_objects[i].vxPath); - out->writeSint16BE(_objects[i].vyPath); - out->writeByte(_objects[i].cycling); - out->writeByte(_objects[i].cycleNumb); - out->writeByte(_objects[i].frameTimer); - out->writeByte(_objects[i].screenIndex); - out->writeSint16BE(_objects[i].x); - out->writeSint16BE(_objects[i].y); - out->writeSint16BE(_objects[i].oldx); - out->writeSint16BE(_objects[i].oldy); - out->writeSByte(_objects[i].vx); - out->writeSByte(_objects[i].vy); - out->writeByte(_objects[i].objValue); - out->writeByte((_objects[i].carriedFl) ? 1 : 0); - out->writeByte(_objects[i].state); - out->writeByte(_objects[i].priority); - out->writeSint16BE(_objects[i].viewx); - out->writeSint16BE(_objects[i].viewy); - out->writeSint16BE(_objects[i].direction); - out->writeByte(_objects[i].curSeqNum); - out->writeByte(_objects[i].curImageNum); - out->writeSByte(_objects[i].oldvx); - out->writeSByte(_objects[i].oldvy); + out->writeByte(_objects[i]._pathType); + out->writeSint16BE(_objects[i]._vxPath); + out->writeSint16BE(_objects[i]._vyPath); + out->writeByte(_objects[i]._cycling); + out->writeByte(_objects[i]._cycleNumb); + out->writeByte(_objects[i]._frameTimer); + out->writeByte(_objects[i]._screenIndex); + out->writeSint16BE(_objects[i]._x); + out->writeSint16BE(_objects[i]._y); + out->writeSint16BE(_objects[i]._oldx); + out->writeSint16BE(_objects[i]._oldy); + out->writeSByte(_objects[i]._vx); + out->writeSByte(_objects[i]._vy); + out->writeByte(_objects[i]._objValue); + out->writeByte((_objects[i]._carriedFl) ? 1 : 0); + out->writeByte(_objects[i]._state); + out->writeByte(_objects[i]._priority); + out->writeSint16BE(_objects[i]._viewx); + out->writeSint16BE(_objects[i]._viewy); + out->writeSint16BE(_objects[i]._direction); + out->writeByte(_objects[i]._curSeqNum); + out->writeByte(_objects[i]._curImageNum); + out->writeSByte(_objects[i]._oldvx); + out->writeSByte(_objects[i]._oldvy); } } @@ -594,30 +594,30 @@ void ObjectHandler::saveObjects(Common::WriteStream *out) { */ void ObjectHandler::restoreObjects(Common::SeekableReadStream *in) { for (int i = 0; i < _numObj; i++) { - _objects[i].pathType = (path_t) in->readByte(); - _objects[i].vxPath = in->readSint16BE(); - _objects[i].vyPath = in->readSint16BE(); - _objects[i].cycling = (cycle_t) in->readByte(); - _objects[i].cycleNumb = in->readByte(); - _objects[i].frameTimer = in->readByte(); - _objects[i].screenIndex = in->readByte(); - _objects[i].x = in->readSint16BE(); - _objects[i].y = in->readSint16BE(); - _objects[i].oldx = in->readSint16BE(); - _objects[i].oldy = in->readSint16BE(); - _objects[i].vx = in->readSByte(); - _objects[i].vy = in->readSByte(); - _objects[i].objValue = in->readByte(); - _objects[i].carriedFl = (in->readByte() == 1); - _objects[i].state = in->readByte(); - _objects[i].priority = in->readByte(); - _objects[i].viewx = in->readSint16BE(); - _objects[i].viewy = in->readSint16BE(); - _objects[i].direction = in->readSint16BE(); - _objects[i].curSeqNum = in->readByte(); - _objects[i].curImageNum = in->readByte(); - _objects[i].oldvx = in->readSByte(); - _objects[i].oldvy = in->readSByte(); + _objects[i]._pathType = (Path) in->readByte(); + _objects[i]._vxPath = in->readSint16BE(); + _objects[i]._vyPath = in->readSint16BE(); + _objects[i]._cycling = (Cycle) in->readByte(); + _objects[i]._cycleNumb = in->readByte(); + _objects[i]._frameTimer = in->readByte(); + _objects[i]._screenIndex = in->readByte(); + _objects[i]._x = in->readSint16BE(); + _objects[i]._y = in->readSint16BE(); + _objects[i]._oldx = in->readSint16BE(); + _objects[i]._oldy = in->readSint16BE(); + _objects[i]._vx = in->readSByte(); + _objects[i]._vy = in->readSByte(); + _objects[i]._objValue = in->readByte(); + _objects[i]._carriedFl = (in->readByte() == 1); + _objects[i]._state = in->readByte(); + _objects[i]._priority = in->readByte(); + _objects[i]._viewx = in->readSint16BE(); + _objects[i]._viewy = in->readSint16BE(); + _objects[i]._direction = in->readSint16BE(); + _objects[i]._curSeqNum = in->readByte(); + _objects[i]._curImageNum = in->readByte(); + _objects[i]._oldvx = in->readSByte(); + _objects[i]._oldvy = in->readSByte(); } } @@ -627,7 +627,7 @@ void ObjectHandler::restoreObjects(Common::SeekableReadStream *in) { int ObjectHandler::calcMaxScore() { int score = 0; for (int i = 0; i < _numObj; i++) - score += _objects[i].objValue; + score += _objects[i]._objValue; return score; } @@ -782,32 +782,32 @@ void ObjectHandler::clearScreenBoundary(const int x1, const int x2, const int y) /** * An object has collided with a boundary. See if any actions are required */ -void ObjectHandler::boundaryCollision(object_t *obj) { +void ObjectHandler::boundaryCollision(Object *obj) { debugC(1, kDebugEngine, "boundaryCollision"); if (obj == _vm->_hero) { // Hotspots only relevant to HERO int x; - if (obj->vx > 0) - x = obj->x + obj->currImagePtr->x2; + if (obj->_vx > 0) + x = obj->_x + obj->_currImagePtr->_x2; else - x = obj->x + obj->currImagePtr->x1; - int y = obj->y + obj->currImagePtr->y2; + x = obj->_x + obj->_currImagePtr->_x1; + int y = obj->_y + obj->_currImagePtr->_y2; - int16 index = _vm->_mouse->findExit(x, y, obj->screenIndex); + int16 index = _vm->_mouse->findExit(x, y, obj->_screenIndex); if (index >= 0) _vm->_scheduler->insertActionList(_vm->_mouse->getHotspotActIndex(index)); } else { // Check whether an object collided with HERO - int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1; - int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2; + int dx = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1 - obj->_x - obj->_currImagePtr->_x1; + int dy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - obj->_y - obj->_currImagePtr->_y2; // If object's radius is infinity, use a closer value - int8 radius = obj->radius; + int8 radius = obj->_radius; if (radius < 0) radius = kStepDx * 2; if ((abs(dx) <= radius) && (abs(dy) <= radius)) - _vm->_scheduler->insertActionList(obj->actIndex); + _vm->_scheduler->insertActionList(obj->_actIndex); } } diff --git a/engines/hugo/object.h b/engines/hugo/object.h index 84c20db041..fd0d731a98 100644 --- a/engines/hugo/object.h +++ b/engines/hugo/object.h @@ -34,15 +34,15 @@ namespace Hugo { -struct target_t { // Secondary target for action - uint16 nounIndex; // Secondary object - uint16 verbIndex; // Action on secondary object +struct Target { // Secondary target for action + uint16 _nounIndex; // Secondary object + uint16 _verbIndex; // Action on secondary object }; -struct uses_t { // Define uses of certain objects - int16 objId; // Primary object - uint16 dataIndex; // String if no secondary object matches - target_t *targets; // List of secondary targets +struct Uses { // Define uses of certain objects + int16 _objId; // Primary object + uint16 _dataIndex; // String if no secondary object matches + Target *_targets; // List of secondary targets }; class ObjectHandler { @@ -50,12 +50,12 @@ public: ObjectHandler(HugoEngine *vm); virtual ~ObjectHandler(); - overlay_t _objBound; - overlay_t _boundary; // Boundary overlay file - overlay_t _overlay; // First overlay file - overlay_t _ovlBase; // First overlay base file + Overlay _objBound; + Overlay _boundary; // Boundary overlay file + Overlay _overlay; // First overlay file + Overlay _ovlBase; // First overlay base file - object_t *_objects; + Object *_objects; uint16 _numObj; byte getBoundaryOverlay(uint16 index) const; @@ -65,7 +65,7 @@ public: int deltaX(const int x1, const int x2, const int vx, int y) const; int deltaY(const int x1, const int x2, const int vy, const int y) const; - void boundaryCollision(object_t *obj); + void boundaryCollision(Object *obj); void clearBoundary(const int x1, const int x2, const int y); void clearScreenBoundary(const int x1, const int x2, const int y); void storeBoundary(const int x1, const int x2, const int y); @@ -76,7 +76,7 @@ public: virtual void swapImages(int objIndex1, int objIndex2) = 0; bool isCarrying(uint16 wordIndex); - bool findObjectSpace(object_t *obj, int16 *destx, int16 *desty); + bool findObjectSpace(Object *obj, int16 *destx, int16 *desty); int calcMaxScore(); int16 findObject(uint16 x, uint16 y); @@ -84,14 +84,14 @@ public: void loadObjectArr(Common::ReadStream &in); void loadObjectUses(Common::ReadStream &in); void loadNumObj(Common::ReadStream &in); - void lookObject(object_t *obj); + void lookObject(Object *obj); void readObjectImages(); - void readObject(Common::ReadStream &in, object_t &curObject); - void readUse(Common::ReadStream &in, uses_t &curUse); + void readObject(Common::ReadStream &in, Object &curObject); + void readUse(Common::ReadStream &in, Uses &curUse); void restoreAllSeq(); void restoreObjects(Common::SeekableReadStream *in); void saveObjects(Common::WriteStream *out); - void saveSeq(object_t *obj); + void saveSeq(Object *obj); void setCarriedScreen(int screenNum); void showTakeables(); void useObject(int16 objId); @@ -101,7 +101,7 @@ public: bool isCarried(int objIndex) const; void setCarry(int objIndex, bool val); void setVelocity(int objIndex, int8 vx, int8 vy); - void setPath(int objIndex, path_t pathType, int16 vxPath, int16 vyPath); + void setPath(int objIndex, Path pathType, int16 vxPath, int16 vyPath); protected: HugoEngine *_vm; @@ -110,11 +110,11 @@ protected: static const int kEdge2 = kEdge * 2; // Push object further back on edge collision static const int kMaxObjNumb = 128; // Used in Update_images() - uint16 _objCount; - uses_t *_uses; - uint16 _usesSize; + uint16 _objCount; + Uses *_uses; + uint16 _usesSize; - void restoreSeq(object_t *obj); + void restoreSeq(Object *obj); inline bool checkBoundary(int16 x, int16 y); template<typename T> diff --git a/engines/hugo/object_v1d.cpp b/engines/hugo/object_v1d.cpp index 831dc88dea..7f88e9e5b8 100644 --- a/engines/hugo/object_v1d.cpp +++ b/engines/hugo/object_v1d.cpp @@ -59,43 +59,43 @@ void ObjectHandler_v1d::updateImages() { debugC(5, kDebugObject, "updateImages"); // Initialize the index array to visible objects in current screen - int num_objs = 0; + int objNumb = 0; byte objindex[kMaxObjNumb]; // Array of indeces to objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= kCycleAlmostInvisible)) - objindex[num_objs++] = i; + Object *obj = &_objects[i]; + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling >= kCycleAlmostInvisible)) + objindex[objNumb++] = i; } // Sort the objects into increasing y+y2 (painter's algorithm) - qsort(objindex, num_objs, sizeof(objindex[0]), y2comp); + qsort(objindex, objNumb, sizeof(objindex[0]), y2comp); // Add each visible object to display list - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; // Count down inter-frame timer - if (obj->frameTimer) - obj->frameTimer--; + if (obj->_frameTimer) + obj->_frameTimer--; - if (obj->cycling > kCycleAlmostInvisible) { // Only if visible - switch (obj->cycling) { + if (obj->_cycling > kCycleAlmostInvisible) { // Only if visible + switch (obj->_cycling) { case kCycleNotCycling: - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, false); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, false); break; case kCycleForward: - if (obj->frameTimer) // Not time to see next frame yet - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, false); + if (obj->_frameTimer) // Not time to see next frame yet + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, false); else - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, false); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr->_nextSeqPtr, false); break; case kCycleBackward: { - seq_t *seqPtr = obj->currImagePtr; - if (!obj->frameTimer) { // Show next frame - while (seqPtr->nextSeqPtr != obj->currImagePtr) - seqPtr = seqPtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + if (!obj->_frameTimer) { // Show next frame + while (seqPtr->_nextSeqPtr != obj->_currImagePtr) + seqPtr = seqPtr->_nextSeqPtr; } - _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, false); + _vm->_screen->displayFrame(obj->_x, obj->_y, seqPtr, false); break; } default: @@ -107,30 +107,30 @@ void ObjectHandler_v1d::updateImages() { _vm->_scheduler->waitForRefresh(); // Cycle any animating objects - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; - if (obj->cycling != kCycleInvisible) { + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; + if (obj->_cycling != kCycleInvisible) { // Only if it's visible - if (obj->cycling == kCycleAlmostInvisible) - obj->cycling = kCycleInvisible; + if (obj->_cycling == kCycleAlmostInvisible) + obj->_cycling = kCycleInvisible; // Now Rotate to next picture in sequence - switch (obj->cycling) { + switch (obj->_cycling) { case kCycleNotCycling: break; case kCycleForward: - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to next frame - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is last frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb) { // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr->_nextSeqPtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb) { // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -138,20 +138,20 @@ void ObjectHandler_v1d::updateImages() { } break; case kCycleBackward: { - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to prev frame - seq_t *seqPtr = obj->currImagePtr; - while (obj->currImagePtr->nextSeqPtr != seqPtr) - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + while (obj->_currImagePtr->_nextSeqPtr != seqPtr) + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is first frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb){ // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb){ // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -162,8 +162,8 @@ void ObjectHandler_v1d::updateImages() { default: break; } - obj->oldx = obj->x; - obj->oldy = obj->y; + obj->_oldx = obj->_x; + obj->_oldy = obj->_y; } } } @@ -183,162 +183,162 @@ void ObjectHandler_v1d::moveObjects() { // and store all (visible) object baselines into the boundary file. // Don't store foreground or background objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if (obj->screenIndex == *_vm->_screen_p) { - switch (obj->pathType) { + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if (obj->_screenIndex == *_vm->_screenPtr) { + switch (obj->_pathType) { case kPathChase: { // Allowable motion wrt boundary - int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; - int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; + int dx = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1 - obj->_x - currImage->_x1; + int dy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - obj->_y - currImage->_y2 - 1; if (abs(dx) <= 1) - obj->vx = 0; + obj->_vx = 0; else - obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); + obj->_vx = (dx > 0) ? MIN(dx, obj->_vxPath) : MAX(dx, -obj->_vxPath); if (abs(dy) <= 1) - obj->vy = 0; + obj->_vy = 0; else - obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); + obj->_vy = (dy > 0) ? MIN(dy, obj->_vyPath) : MAX(dy, -obj->_vyPath); // Set first image in sequence (if multi-seq object) - if (obj->seqNumb == 4) { - if (!obj->vx) { // Got 4 directions - if (obj->vx != obj->oldvx) {// vx just stopped + if (obj->_seqNumb == 4) { + if (!obj->_vx) { // Got 4 directions + if (obj->_vx != obj->_oldvx) {// vx just stopped if (dy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { + } else if (obj->_vx != obj->_oldvx) { if (dx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } } - if (obj->vx || obj->vy) { - if (obj->seqNumb > 1) - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) { + if (obj->_seqNumb > 1) + obj->_cycling = kCycleForward; } else { - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; boundaryCollision(obj); // Must have got hero! } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image break; } case kPathWander: if (!_vm->_rnd->getRandomNumber(3 * _vm->_normalTPS)) { // Kick on random interval - obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; - obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; + obj->_vx = _vm->_rnd->getRandomNumber(obj->_vxPath << 1) - obj->_vxPath; + obj->_vy = _vm->_rnd->getRandomNumber(obj->_vyPath << 1) - obj->_vyPath; // Set first image in sequence (if multi-seq object) - if (obj->seqNumb > 1) { - if (!obj->vx && (obj->seqNumb > 2)) { - if (obj->vx != obj->oldvx) { // vx just stopped - if (obj->vy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + if (obj->_seqNumb > 1) { + if (!obj->_vx && (obj->_seqNumb > 2)) { + if (obj->_vx != obj->_oldvx) { // vx just stopped + if (obj->_vy > 0) + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { - if (obj->vx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + } else if (obj->_vx != obj->_oldvx) { + if (obj->_vx > 0) + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } - if (obj->vx || obj->vy) - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) + obj->_cycling = kCycleForward; else - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image } break; default: ; // Really, nothing } // Store boundaries - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + storeBoundary(obj->_x + currImage->_x1, obj->_x + currImage->_x2, obj->_y + currImage->_y2); } } // Move objects, allowing for boundaries for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { + Object *obj = &_objects[i]; // Get pointer to object + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_vx || obj->_vy)) { // Only process if it's moving // Do object movement. Delta_x,y return allowed movement in x,y // to move as close to a boundary as possible without crossing it. - seq_t *currImage = obj->currImagePtr; // Get ptr to current image + Seq *currImage = obj->_currImagePtr; // Get ptr to current image // object coordinates - int x1 = obj->x + currImage->x1; // Left edge of object - int x2 = obj->x + currImage->x2; // Right edge - int y1 = obj->y + currImage->y1; // Top edge - int y2 = obj->y + currImage->y2; // Bottom edge + int x1 = obj->_x + currImage->_x1; // Left edge of object + int x2 = obj->_x + currImage->_x2; // Right edge + int y1 = obj->_y + currImage->_y1; // Top edge + int y2 = obj->_y + currImage->_y2; // Bottom edge - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = deltaX(x1, x2, obj->vx, y2); - if (dx != obj->vx) { + int dx = deltaX(x1, x2, obj->_vx, y2); + if (dx != obj->_vx) { // An object boundary collision! boundaryCollision(obj); - obj->vx = 0; + obj->_vx = 0; } - int dy = deltaY(x1, x2, obj->vy, y2); - if (dy != obj->vy) { + int dy = deltaY(x1, x2, obj->_vy, y2); + if (dy != obj->_vy) { // An object boundary collision! boundaryCollision(obj); - obj->vy = 0; + obj->_vy = 0; } - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) storeBoundary(x1, x2, y2); // Re-store our own boundary - obj->x += dx; // Update object position - obj->y += dy; + obj->_x += dx; // Update object position + obj->_y += dy; // Don't let object go outside screen if (x1 < kEdge) - obj->x = kEdge2; + obj->_x = kEdge2; if (x2 > (kXPix - kEdge)) - obj->x = kXPix - kEdge2 - (x2 - x1); + obj->_x = kXPix - kEdge2 - (x2 - x1); if (y1 < kEdge) - obj->y = kEdge2; + obj->_y = kEdge2; if (y2 > (kYPix - kEdge)) - obj->y = kYPix - kEdge2 - (y2 - y1); + obj->_y = kYPix - kEdge2 - (y2 - y1); - if ((obj->vx == 0) && (obj->vy == 0)) - obj->cycling = kCycleNotCycling; + if ((obj->_vx == 0) && (obj->_vy == 0)) + obj->_cycling = kCycleNotCycling; } } // Clear all object baselines from the boundary file. for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + clearBoundary(obj->_oldx + currImage->_x1, obj->_oldx + currImage->_x2, obj->_oldy + currImage->_y2); } // If maze mode is enabled, do special maze processing - if (_vm->_maze.enabledFl) { - seq_t *currImage = _vm->_hero->currImagePtr;// Get ptr to current image + if (_vm->_maze._enabledFl) { + Seq *currImage = _vm->_hero->_currImagePtr;// Get ptr to current image // hero coordinates - int x1 = _vm->_hero->x + currImage->x1; // Left edge of object - int x2 = _vm->_hero->x + currImage->x2; // Right edge - int y1 = _vm->_hero->y + currImage->y1; // Top edge - int y2 = _vm->_hero->y + currImage->y2; // Bottom edge + int x1 = _vm->_hero->_x + currImage->_x1; // Left edge of object + int x2 = _vm->_hero->_x + currImage->_x2; // Right edge + int y1 = _vm->_hero->_y + currImage->_y1; // Top edge + int y2 = _vm->_hero->_y + currImage->_y2; // Bottom edge _vm->_scheduler->processMaze(x1, x2, y1, y2); } @@ -352,24 +352,24 @@ void ObjectHandler_v1d::moveObjects() { void ObjectHandler_v1d::swapImages(int objIndex1, int objIndex2) { debugC(1, kDebugObject, "swapImages(%d, %d)", objIndex1, objIndex2); - seqList_t tmpSeqList[kMaxSeqNumb]; - int seqListSize = sizeof(seqList_t) * kMaxSeqNumb; + SeqList tmpSeqList[kMaxSeqNumb]; + int seqListSize = sizeof(SeqList) * kMaxSeqNumb; - memmove(tmpSeqList, _objects[objIndex1].seqList, seqListSize); - memmove(_objects[objIndex1].seqList, _objects[objIndex2].seqList, seqListSize); - memmove(_objects[objIndex2].seqList, tmpSeqList, seqListSize); - _objects[objIndex1].currImagePtr = _objects[objIndex1].seqList[0].seqPtr; - _objects[objIndex2].currImagePtr = _objects[objIndex2].seqList[0].seqPtr; + memmove(tmpSeqList, _objects[objIndex1]._seqList, seqListSize); + memmove(_objects[objIndex1]._seqList, _objects[objIndex2]._seqList, seqListSize); + memmove(_objects[objIndex2]._seqList, tmpSeqList, seqListSize); + _objects[objIndex1]._currImagePtr = _objects[objIndex1]._seqList[0]._seqPtr; + _objects[objIndex2]._currImagePtr = _objects[objIndex2]._seqList[0]._seqPtr; _vm->_heroImage = (_vm->_heroImage == kHeroIndex) ? objIndex2 : kHeroIndex; } void ObjectHandler_v1d::homeIn(int objIndex1, const int objIndex2, const int8 objDx, const int8 objDy) { // object obj1 will home in on object obj2 - object_t *obj1 = &_objects[objIndex1]; - object_t *obj2 = &_objects[objIndex2]; - obj1->pathType = kPathAuto; - int dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1; - int dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1; + Object *obj1 = &_objects[objIndex1]; + Object *obj2 = &_objects[objIndex2]; + obj1->_pathType = kPathAuto; + int dx = obj1->_x + obj1->_currImagePtr->_x1 - obj2->_x - obj2->_currImagePtr->_x1; + int dy = obj1->_y + obj1->_currImagePtr->_y1 - obj2->_y - obj2->_currImagePtr->_y1; if (dx == 0) // Don't EVER divide by zero! dx = 1; @@ -377,11 +377,11 @@ void ObjectHandler_v1d::homeIn(int objIndex1, const int objIndex2, const int8 ob dy = 1; if (abs(dx) > abs(dy)) { - obj1->vx = objDx * -sign<int8>(dx); - obj1->vy = abs((objDy * dy) / dx) * -sign<int8>(dy); + obj1->_vx = objDx * -sign<int8>(dx); + obj1->_vy = abs((objDy * dy) / dx) * -sign<int8>(dy); } else { - obj1->vy = objDy * sign<int8>(dy); - obj1->vx = abs((objDx * dx) / dy) * sign<int8>(dx); + obj1->_vy = objDy * sign<int8>(dy); + obj1->_vx = abs((objDx * dx) / dy) * sign<int8>(dx); } } } // End of namespace Hugo diff --git a/engines/hugo/object_v1w.cpp b/engines/hugo/object_v1w.cpp index 4388ef5520..61b0f2e48a 100644 --- a/engines/hugo/object_v1w.cpp +++ b/engines/hugo/object_v1w.cpp @@ -59,43 +59,43 @@ void ObjectHandler_v1w::updateImages() { debugC(5, kDebugObject, "updateImages"); // Initialize the index array to visible objects in current screen - int num_objs = 0; + int objNumb = 0; byte objindex[kMaxObjNumb]; // Array of indeces to objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= kCycleAlmostInvisible)) - objindex[num_objs++] = i; + Object *obj = &_objects[i]; + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling >= kCycleAlmostInvisible)) + objindex[objNumb++] = i; } // Sort the objects into increasing y+y2 (painter's algorithm) - qsort(objindex, num_objs, sizeof(objindex[0]), y2comp); + qsort(objindex, objNumb, sizeof(objindex[0]), y2comp); // Add each visible object to display list - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; // Count down inter-frame timer - if (obj->frameTimer) - obj->frameTimer--; + if (obj->_frameTimer) + obj->_frameTimer--; - if (obj->cycling > kCycleAlmostInvisible) { // Only if visible - switch (obj->cycling) { + if (obj->_cycling > kCycleAlmostInvisible) { // Only if visible + switch (obj->_cycling) { case kCycleNotCycling: - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, obj->_priority == kPriorityOverOverlay); break; case kCycleForward: - if (obj->frameTimer) // Not time to see next frame yet - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == kPriorityOverOverlay); + if (obj->_frameTimer) // Not time to see next frame yet + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, obj->_priority == kPriorityOverOverlay); else - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr->_nextSeqPtr, obj->_priority == kPriorityOverOverlay); break; case kCycleBackward: { - seq_t *seqPtr = obj->currImagePtr; - if (!obj->frameTimer) { // Show next frame - while (seqPtr->nextSeqPtr != obj->currImagePtr) - seqPtr = seqPtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + if (!obj->_frameTimer) { // Show next frame + while (seqPtr->_nextSeqPtr != obj->_currImagePtr) + seqPtr = seqPtr->_nextSeqPtr; } - _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, seqPtr, obj->_priority == kPriorityOverOverlay); break; } default: @@ -105,30 +105,30 @@ void ObjectHandler_v1w::updateImages() { } // Cycle any animating objects - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; - if (obj->cycling != kCycleInvisible) { + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; + if (obj->_cycling != kCycleInvisible) { // Only if it's visible - if (obj->cycling == kCycleAlmostInvisible) - obj->cycling = kCycleInvisible; + if (obj->_cycling == kCycleAlmostInvisible) + obj->_cycling = kCycleInvisible; // Now Rotate to next picture in sequence - switch (obj->cycling) { + switch (obj->_cycling) { case kCycleNotCycling: break; case kCycleForward: - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to next frame - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is last frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb) { // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr->_nextSeqPtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb) { // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -136,20 +136,20 @@ void ObjectHandler_v1w::updateImages() { } break; case kCycleBackward: { - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to prev frame - seq_t *seqPtr = obj->currImagePtr; - while (obj->currImagePtr->nextSeqPtr != seqPtr) - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + while (obj->_currImagePtr->_nextSeqPtr != seqPtr) + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is first frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb){ // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb){ // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -160,8 +160,8 @@ void ObjectHandler_v1w::updateImages() { default: break; } - obj->oldx = obj->x; - obj->oldy = obj->y; + obj->_oldx = obj->_x; + obj->_oldy = obj->_y; } } } @@ -180,175 +180,175 @@ void ObjectHandler_v1w::moveObjects() { // and store all (visible) object baselines into the boundary file. // Don't store foreground or background objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if (obj->screenIndex == *_vm->_screen_p) { - switch (obj->pathType) { + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if (obj->_screenIndex == *_vm->_screenPtr) { + switch (obj->_pathType) { case kPathChase: case kPathChase2: { - int8 radius = obj->radius; // Default to object's radius + int8 radius = obj->_radius; // Default to object's radius if (radius < 0) // If radius infinity, use closer value radius = kStepDx; // Allowable motion wrt boundary - int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; - int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; + int dx = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1 - obj->_x - currImage->_x1; + int dy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - obj->_y - currImage->_y2 - 1; if (abs(dx) <= radius) - obj->vx = 0; + obj->_vx = 0; else - obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); + obj->_vx = (dx > 0) ? MIN(dx, obj->_vxPath) : MAX(dx, -obj->_vxPath); if (abs(dy) <= radius) - obj->vy = 0; + obj->_vy = 0; else - obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); + obj->_vy = (dy > 0) ? MIN(dy, obj->_vyPath) : MAX(dy, -obj->_vyPath); // Set first image in sequence (if multi-seq object) - switch (obj->seqNumb) { + switch (obj->_seqNumb) { case 4: - if (!obj->vx) { // Got 4 directions - if (obj->vx != obj->oldvx) { // vx just stopped + if (!obj->_vx) { // Got 4 directions + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dy >= 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { + } else if (obj->_vx != obj->_oldvx) { if (dx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; case 3: case 2: - if (obj->vx != obj->oldvx) { // vx just stopped + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dx > 0) // Left & right only - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; } - if (obj->vx || obj->vy) { - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) { + obj->_cycling = kCycleForward; } else { - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; boundaryCollision(obj); // Must have got hero! } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image break; } case kPathWander2: case kPathWander: if (!_vm->_rnd->getRandomNumber(3 * _vm->_normalTPS)) { // Kick on random interval - obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; - obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; + obj->_vx = _vm->_rnd->getRandomNumber(obj->_vxPath << 1) - obj->_vxPath; + obj->_vy = _vm->_rnd->getRandomNumber(obj->_vyPath << 1) - obj->_vyPath; // Set first image in sequence (if multi-seq object) - if (obj->seqNumb > 1) { - if (!obj->vx && (obj->seqNumb >= 4)) { - if (obj->vx != obj->oldvx) { // vx just stopped - if (obj->vy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + if (obj->_seqNumb > 1) { + if (!obj->_vx && (obj->_seqNumb >= 4)) { + if (obj->_vx != obj->_oldvx) { // vx just stopped + if (obj->_vy > 0) + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { - if (obj->vx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + } else if (obj->_vx != obj->_oldvx) { + if (obj->_vx > 0) + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image } - if (obj->vx || obj->vy) - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) + obj->_cycling = kCycleForward; break; default: ; // Really, nothing } // Store boundaries - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + storeBoundary(obj->_x + currImage->_x1, obj->_x + currImage->_x2, obj->_y + currImage->_y2); } } // Move objects, allowing for boundaries for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { + Object *obj = &_objects[i]; // Get pointer to object + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_vx || obj->_vy)) { // Only process if it's moving // Do object movement. Delta_x,y return allowed movement in x,y // to move as close to a boundary as possible without crossing it. - seq_t *currImage = obj->currImagePtr; // Get ptr to current image + Seq *currImage = obj->_currImagePtr; // Get ptr to current image // object coordinates - int x1 = obj->x + currImage->x1; // Left edge of object - int x2 = obj->x + currImage->x2; // Right edge - int y1 = obj->y + currImage->y1; // Top edge - int y2 = obj->y + currImage->y2; // Bottom edge + int x1 = obj->_x + currImage->_x1; // Left edge of object + int x2 = obj->_x + currImage->_x2; // Right edge + int y1 = obj->_y + currImage->_y1; // Top edge + int y2 = obj->_y + currImage->_y2; // Bottom edge - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = deltaX(x1, x2, obj->vx, y2); - if (dx != obj->vx) { + int dx = deltaX(x1, x2, obj->_vx, y2); + if (dx != obj->_vx) { // An object boundary collision! boundaryCollision(obj); - obj->vx = 0; + obj->_vx = 0; } - int dy = deltaY(x1, x2, obj->vy, y2); - if (dy != obj->vy) { + int dy = deltaY(x1, x2, obj->_vy, y2); + if (dy != obj->_vy) { // An object boundary collision! boundaryCollision(obj); - obj->vy = 0; + obj->_vy = 0; } - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) storeBoundary(x1, x2, y2); // Re-store our own boundary - obj->x += dx; // Update object position - obj->y += dy; + obj->_x += dx; // Update object position + obj->_y += dy; // Don't let object go outside screen if (x1 < kEdge) - obj->x = kEdge2; + obj->_x = kEdge2; if (x2 > (kXPix - kEdge)) - obj->x = kXPix - kEdge2 - (x2 - x1); + obj->_x = kXPix - kEdge2 - (x2 - x1); if (y1 < kEdge) - obj->y = kEdge2; + obj->_y = kEdge2; if (y2 > (kYPix - kEdge)) - obj->y = kYPix - kEdge2 - (y2 - y1); + obj->_y = kYPix - kEdge2 - (y2 - y1); - if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != kPathWander2) && (obj->pathType != kPathChase2)) - obj->cycling = kCycleNotCycling; + if ((obj->_vx == 0) && (obj->_vy == 0) && (obj->_pathType != kPathWander2) && (obj->_pathType != kPathChase2)) + obj->_cycling = kCycleNotCycling; } } // Clear all object baselines from the boundary file. for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + clearBoundary(obj->_oldx + currImage->_x1, obj->_oldx + currImage->_x2, obj->_oldy + currImage->_y2); } // If maze mode is enabled, do special maze processing - if (_vm->_maze.enabledFl) { - seq_t *currImage = _vm->_hero->currImagePtr; // Get ptr to current image + if (_vm->_maze._enabledFl) { + Seq *currImage = _vm->_hero->_currImagePtr; // Get ptr to current image // hero coordinates - int x1 = _vm->_hero->x + currImage->x1; // Left edge of object - int x2 = _vm->_hero->x + currImage->x2; // Right edge - int y1 = _vm->_hero->y + currImage->y1; // Top edge - int y2 = _vm->_hero->y + currImage->y2; // Bottom edge + int x1 = _vm->_hero->_x + currImage->_x1; // Left edge of object + int x2 = _vm->_hero->_x + currImage->_x2; // Right edge + int y1 = _vm->_hero->_y + currImage->_y1; // Top edge + int y2 = _vm->_hero->_y + currImage->_y2; // Bottom edge _vm->_scheduler->processMaze(x1, x2, y1, y2); } @@ -364,18 +364,18 @@ void ObjectHandler_v1w::swapImages(int objIndex1, int objIndex2) { saveSeq(&_objects[objIndex1]); - seqList_t tmpSeqList[kMaxSeqNumb]; - int seqListSize = sizeof(seqList_t) * kMaxSeqNumb; + SeqList tmpSeqList[kMaxSeqNumb]; + int seqListSize = sizeof(SeqList) * kMaxSeqNumb; - memmove(tmpSeqList, _objects[objIndex1].seqList, seqListSize); - memmove(_objects[objIndex1].seqList, _objects[objIndex2].seqList, seqListSize); - memmove(_objects[objIndex2].seqList, tmpSeqList, seqListSize); + memmove(tmpSeqList, _objects[objIndex1]._seqList, seqListSize); + memmove(_objects[objIndex1]._seqList, _objects[objIndex2]._seqList, seqListSize); + memmove(_objects[objIndex2]._seqList, tmpSeqList, seqListSize); restoreSeq(&_objects[objIndex1]); - _objects[objIndex2].currImagePtr = _objects[objIndex2].seqList[0].seqPtr; + _objects[objIndex2]._currImagePtr = _objects[objIndex2]._seqList[0]._seqPtr; _vm->_heroImage = (_vm->_heroImage == kHeroIndex) ? objIndex2 : kHeroIndex; // Make sure baseline stays constant - _objects[objIndex1].y += _objects[objIndex2].currImagePtr->y2 - _objects[objIndex1].currImagePtr->y2; + _objects[objIndex1]._y += _objects[objIndex2]._currImagePtr->_y2 - _objects[objIndex1]._currImagePtr->_y2; } } // End of namespace Hugo diff --git a/engines/hugo/object_v2d.cpp b/engines/hugo/object_v2d.cpp index 4a22fab2c0..7cb6c20dd0 100644 --- a/engines/hugo/object_v2d.cpp +++ b/engines/hugo/object_v2d.cpp @@ -59,43 +59,43 @@ void ObjectHandler_v2d::updateImages() { debugC(5, kDebugObject, "updateImages"); // Initialize the index array to visible objects in current screen - int num_objs = 0; + int objNumb = 0; byte objindex[kMaxObjNumb]; // Array of indeces to objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling >= kCycleAlmostInvisible)) - objindex[num_objs++] = i; + Object *obj = &_objects[i]; + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling >= kCycleAlmostInvisible)) + objindex[objNumb++] = i; } // Sort the objects into increasing y+y2 (painter's algorithm) - qsort(objindex, num_objs, sizeof(objindex[0]), y2comp); + qsort(objindex, objNumb, sizeof(objindex[0]), y2comp); // Add each visible object to display list - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; // Count down inter-frame timer - if (obj->frameTimer) - obj->frameTimer--; + if (obj->_frameTimer) + obj->_frameTimer--; - if (obj->cycling > kCycleAlmostInvisible) { // Only if visible - switch (obj->cycling) { + if (obj->_cycling > kCycleAlmostInvisible) { // Only if visible + switch (obj->_cycling) { case kCycleNotCycling: - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, obj->_priority == kPriorityOverOverlay); break; case kCycleForward: - if (obj->frameTimer) // Not time to see next frame yet - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == kPriorityOverOverlay); + if (obj->_frameTimer) // Not time to see next frame yet + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr, obj->_priority == kPriorityOverOverlay); else - _vm->_screen->displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, obj->_currImagePtr->_nextSeqPtr, obj->_priority == kPriorityOverOverlay); break; case kCycleBackward: { - seq_t *seqPtr = obj->currImagePtr; - if (!obj->frameTimer) { // Show next frame - while (seqPtr->nextSeqPtr != obj->currImagePtr) - seqPtr = seqPtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + if (!obj->_frameTimer) { // Show next frame + while (seqPtr->_nextSeqPtr != obj->_currImagePtr) + seqPtr = seqPtr->_nextSeqPtr; } - _vm->_screen->displayFrame(obj->x, obj->y, seqPtr, obj->priority == kPriorityOverOverlay); + _vm->_screen->displayFrame(obj->_x, obj->_y, seqPtr, obj->_priority == kPriorityOverOverlay); break; } default: @@ -107,30 +107,30 @@ void ObjectHandler_v2d::updateImages() { _vm->_scheduler->waitForRefresh(); // Cycle any animating objects - for (int i = 0; i < num_objs; i++) { - object_t *obj = &_objects[objindex[i]]; - if (obj->cycling != kCycleInvisible) { + for (int i = 0; i < objNumb; i++) { + Object *obj = &_objects[objindex[i]]; + if (obj->_cycling != kCycleInvisible) { // Only if it's visible - if (obj->cycling == kCycleAlmostInvisible) - obj->cycling = kCycleInvisible; + if (obj->_cycling == kCycleAlmostInvisible) + obj->_cycling = kCycleInvisible; // Now Rotate to next picture in sequence - switch (obj->cycling) { + switch (obj->_cycling) { case kCycleNotCycling: break; case kCycleForward: - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to next frame - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is last frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb) { // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr->_nextSeqPtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb) { // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -138,20 +138,20 @@ void ObjectHandler_v2d::updateImages() { } break; case kCycleBackward: { - if (!obj->frameTimer) { + if (!obj->_frameTimer) { // Time to step to prev frame - seq_t *seqPtr = obj->currImagePtr; - while (obj->currImagePtr->nextSeqPtr != seqPtr) - obj->currImagePtr = obj->currImagePtr->nextSeqPtr; + Seq *seqPtr = obj->_currImagePtr; + while (obj->_currImagePtr->_nextSeqPtr != seqPtr) + obj->_currImagePtr = obj->_currImagePtr->_nextSeqPtr; // Find out if this is first frame of sequence // If so, reset frame_timer and decrement n_cycle - if (obj->frameInterval || obj->cycleNumb) { - obj->frameTimer = obj->frameInterval; - for (int j = 0; j < obj->seqNumb; j++) { - if (obj->currImagePtr == obj->seqList[j].seqPtr) { - if (obj->cycleNumb){ // Decr cycleNumb if Non-continous - if (!--obj->cycleNumb) - obj->cycling = kCycleNotCycling; + if (obj->_frameInterval || obj->_cycleNumb) { + obj->_frameTimer = obj->_frameInterval; + for (int j = 0; j < obj->_seqNumb; j++) { + if (obj->_currImagePtr == obj->_seqList[j]._seqPtr) { + if (obj->_cycleNumb){ // Decr cycleNumb if Non-continous + if (!--obj->_cycleNumb) + obj->_cycling = kCycleNotCycling; } } } @@ -162,8 +162,8 @@ void ObjectHandler_v2d::updateImages() { default: break; } - obj->oldx = obj->x; - obj->oldy = obj->y; + obj->_oldx = obj->_x; + obj->_oldy = obj->_y; } } } @@ -183,175 +183,175 @@ void ObjectHandler_v2d::moveObjects() { // and store all (visible) object baselines into the boundary file. // Don't store foreground or background objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if (obj->screenIndex == *_vm->_screen_p) { - switch (obj->pathType) { + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if (obj->_screenIndex == *_vm->_screenPtr) { + switch (obj->_pathType) { case kPathChase: case kPathChase2: { - int8 radius = obj->radius; // Default to object's radius + int8 radius = obj->_radius; // Default to object's radius if (radius < 0) // If radius infinity, use closer value radius = kStepDx; // Allowable motion wrt boundary - int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; - int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; + int dx = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1 - obj->_x - currImage->_x1; + int dy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - obj->_y - currImage->_y2 - 1; if (abs(dx) <= radius) - obj->vx = 0; + obj->_vx = 0; else - obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); + obj->_vx = (dx > 0) ? MIN(dx, obj->_vxPath) : MAX(dx, -obj->_vxPath); if (abs(dy) <= radius) - obj->vy = 0; + obj->_vy = 0; else - obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); + obj->_vy = (dy > 0) ? MIN(dy, obj->_vyPath) : MAX(dy, -obj->_vyPath); // Set first image in sequence (if multi-seq object) - switch (obj->seqNumb) { + switch (obj->_seqNumb) { case 4: - if (!obj->vx) { // Got 4 directions - if (obj->vx != obj->oldvx) { // vx just stopped + if (!obj->_vx) { // Got 4 directions + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { + } else if (obj->_vx != obj->_oldvx) { if (dx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; case 3: case 2: - if (obj->vx != obj->oldvx) { // vx just stopped + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dx > 0) // Left & right only - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; } - if (obj->vx || obj->vy) { - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) { + obj->_cycling = kCycleForward; } else { - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; boundaryCollision(obj); // Must have got hero! } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image break; } case kPathWander2: case kPathWander: if (!_vm->_rnd->getRandomNumber(3 * _vm->_normalTPS)) { // Kick on random interval - obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; - obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; + obj->_vx = _vm->_rnd->getRandomNumber(obj->_vxPath << 1) - obj->_vxPath; + obj->_vy = _vm->_rnd->getRandomNumber(obj->_vyPath << 1) - obj->_vyPath; // Set first image in sequence (if multi-seq object) - if (obj->seqNumb > 1) { - if (!obj->vx && (obj->seqNumb >= 4)) { - if (obj->vx != obj->oldvx) { // vx just stopped - if (obj->vy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + if (obj->_seqNumb > 1) { + if (!obj->_vx && (obj->_seqNumb >= 4)) { + if (obj->_vx != obj->_oldvx) { // vx just stopped + if (obj->_vy > 0) + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { - if (obj->vx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + } else if (obj->_vx != obj->_oldvx) { + if (obj->_vx > 0) + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image } - if (obj->vx || obj->vy) - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) + obj->_cycling = kCycleForward; break; default: ; // Really, nothing } // Store boundaries - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + storeBoundary(obj->_x + currImage->_x1, obj->_x + currImage->_x2, obj->_y + currImage->_y2); } } // Move objects, allowing for boundaries for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { + Object *obj = &_objects[i]; // Get pointer to object + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_vx || obj->_vy)) { // Only process if it's moving // Do object movement. Delta_x,y return allowed movement in x,y // to move as close to a boundary as possible without crossing it. - seq_t *currImage = obj->currImagePtr; // Get ptr to current image + Seq *currImage = obj->_currImagePtr; // Get ptr to current image // object coordinates - int x1 = obj->x + currImage->x1; // Left edge of object - int x2 = obj->x + currImage->x2; // Right edge - int y1 = obj->y + currImage->y1; // Top edge - int y2 = obj->y + currImage->y2; // Bottom edge + int x1 = obj->_x + currImage->_x1; // Left edge of object + int x2 = obj->_x + currImage->_x2; // Right edge + int y1 = obj->_y + currImage->_y1; // Top edge + int y2 = obj->_y + currImage->_y2; // Bottom edge - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = deltaX(x1, x2, obj->vx, y2); - if (dx != obj->vx) { + int dx = deltaX(x1, x2, obj->_vx, y2); + if (dx != obj->_vx) { // An object boundary collision! boundaryCollision(obj); - obj->vx = 0; + obj->_vx = 0; } - int dy = deltaY(x1, x2, obj->vy, y2); - if (dy != obj->vy) { + int dy = deltaY(x1, x2, obj->_vy, y2); + if (dy != obj->_vy) { // An object boundary collision! boundaryCollision(obj); - obj->vy = 0; + obj->_vy = 0; } - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) storeBoundary(x1, x2, y2); // Re-store our own boundary - obj->x += dx; // Update object position - obj->y += dy; + obj->_x += dx; // Update object position + obj->_y += dy; // Don't let object go outside screen if (x1 < kEdge) - obj->x = kEdge2; + obj->_x = kEdge2; if (x2 > (kXPix - kEdge)) - obj->x = kXPix - kEdge2 - (x2 - x1); + obj->_x = kXPix - kEdge2 - (x2 - x1); if (y1 < kEdge) - obj->y = kEdge2; + obj->_y = kEdge2; if (y2 > (kYPix - kEdge)) - obj->y = kYPix - kEdge2 - (y2 - y1); + obj->_y = kYPix - kEdge2 - (y2 - y1); - if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != kPathWander2) && (obj->pathType != kPathChase2)) - obj->cycling = kCycleNotCycling; + if ((obj->_vx == 0) && (obj->_vy == 0) && (obj->_pathType != kPathWander2) && (obj->_pathType != kPathChase2)) + obj->_cycling = kCycleNotCycling; } } // Clear all object baselines from the boundary file. for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + clearBoundary(obj->_oldx + currImage->_x1, obj->_oldx + currImage->_x2, obj->_oldy + currImage->_y2); } // If maze mode is enabled, do special maze processing - if (_vm->_maze.enabledFl) { - seq_t *currImage = _vm->_hero->currImagePtr; // Get ptr to current image + if (_vm->_maze._enabledFl) { + Seq *currImage = _vm->_hero->_currImagePtr; // Get ptr to current image // hero coordinates - int x1 = _vm->_hero->x + currImage->x1; // Left edge of object - int x2 = _vm->_hero->x + currImage->x2; // Right edge - int y1 = _vm->_hero->y + currImage->y1; // Top edge - int y2 = _vm->_hero->y + currImage->y2; // Bottom edge + int x1 = _vm->_hero->_x + currImage->_x1; // Left edge of object + int x2 = _vm->_hero->_x + currImage->_x2; // Right edge + int y1 = _vm->_hero->_y + currImage->_y1; // Top edge + int y2 = _vm->_hero->_y + currImage->_y2; // Bottom edge _vm->_scheduler->processMaze(x1, x2, y1, y2); } @@ -359,11 +359,11 @@ void ObjectHandler_v2d::moveObjects() { void ObjectHandler_v2d::homeIn(const int objIndex1, const int objIndex2, const int8 objDx, const int8 objDy) { // object obj1 will home in on object obj2 - object_t *obj1 = &_objects[objIndex1]; - object_t *obj2 = &_objects[objIndex2]; - obj1->pathType = kPathAuto; - int dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1; - int dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1; + Object *obj1 = &_objects[objIndex1]; + Object *obj2 = &_objects[objIndex2]; + obj1->_pathType = kPathAuto; + int dx = obj1->_x + obj1->_currImagePtr->_x1 - obj2->_x - obj2->_currImagePtr->_x1; + int dy = obj1->_y + obj1->_currImagePtr->_y1 - obj2->_y - obj2->_currImagePtr->_y1; if (dx == 0) // Don't EVER divide by zero! dx = 1; @@ -371,11 +371,11 @@ void ObjectHandler_v2d::homeIn(const int objIndex1, const int objIndex2, const i dy = 1; if (abs(dx) > abs(dy)) { - obj1->vx = objDx * -sign<int8>(dx); - obj1->vy = abs((objDy * dy) / dx) * -sign<int8>(dy); + obj1->_vx = objDx * -sign<int8>(dx); + obj1->_vy = abs((objDy * dy) / dx) * -sign<int8>(dy); } else { - obj1->vy = objDy * -sign<int8>(dy); - obj1->vx = abs((objDx * dx) / dy) * -sign<int8>(dx); + obj1->_vy = objDy * -sign<int8>(dy); + obj1->_vx = abs((objDx * dx) / dy) * -sign<int8>(dx); } } } // End of namespace Hugo diff --git a/engines/hugo/object_v3d.cpp b/engines/hugo/object_v3d.cpp index cde7f5fd62..7bb4b95b4a 100644 --- a/engines/hugo/object_v3d.cpp +++ b/engines/hugo/object_v3d.cpp @@ -64,176 +64,176 @@ void ObjectHandler_v3d::moveObjects() { // and store all (visible) object baselines into the boundary file. // Don't store foreground or background objects for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if (obj->screenIndex == *_vm->_screen_p) { - switch (obj->pathType) { + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if (obj->_screenIndex == *_vm->_screenPtr) { + switch (obj->_pathType) { case kPathChase: case kPathChase2: { - int8 radius = obj->radius; // Default to object's radius + int8 radius = obj->_radius; // Default to object's radius if (radius < 0) // If radius infinity, use closer value radius = kStepDx; // Allowable motion wrt boundary - int dx = _vm->_hero->x + _vm->_hero->currImagePtr->x1 - obj->x - currImage->x1; - int dy = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - obj->y - currImage->y2 - 1; + int dx = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1 - obj->_x - currImage->_x1; + int dy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - obj->_y - currImage->_y2 - 1; if (abs(dx) <= radius) - obj->vx = 0; + obj->_vx = 0; else - obj->vx = (dx > 0) ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath); + obj->_vx = (dx > 0) ? MIN(dx, obj->_vxPath) : MAX(dx, -obj->_vxPath); if (abs(dy) <= radius) - obj->vy = 0; + obj->_vy = 0; else - obj->vy = (dy > 0) ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath); + obj->_vy = (dy > 0) ? MIN(dy, obj->_vyPath) : MAX(dy, -obj->_vyPath); // Set first image in sequence (if multi-seq object) - switch (obj->seqNumb) { + switch (obj->_seqNumb) { case 4: - if (!obj->vx) { // Got 4 directions - if (obj->vx != obj->oldvx) { // vx just stopped + if (!obj->_vx) { // Got 4 directions + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dy >= 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { + } else if (obj->_vx != obj->_oldvx) { if (dx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; case 3: case 2: - if (obj->vx != obj->oldvx) { // vx just stopped + if (obj->_vx != obj->_oldvx) { // vx just stopped if (dx > 0) // Left & right only - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } break; } - if (obj->vx || obj->vy) { - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) { + obj->_cycling = kCycleForward; } else { - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; boundaryCollision(obj); // Must have got hero! } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image break; } case kPathWander2: case kPathWander: if (!_vm->_rnd->getRandomNumber(3 * _vm->_normalTPS)) { // Kick on random interval - obj->vx = _vm->_rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath; - obj->vy = _vm->_rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath; + obj->_vx = _vm->_rnd->getRandomNumber(obj->_vxPath << 1) - obj->_vxPath; + obj->_vy = _vm->_rnd->getRandomNumber(obj->_vyPath << 1) - obj->_vyPath; // Set first image in sequence (if multi-seq object) - if (obj->seqNumb > 1) { - if (!obj->vx && (obj->seqNumb >= 4)) { - if (obj->vx != obj->oldvx) { // vx just stopped - if (obj->vy > 0) - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + if (obj->_seqNumb > 1) { + if (!obj->_vx && (obj->_seqNumb >= 4)) { + if (obj->_vx != obj->_oldvx) { // vx just stopped + if (obj->_vy > 0) + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; } - } else if (obj->vx != obj->oldvx) { - if (obj->vx > 0) - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + } else if (obj->_vx != obj->_oldvx) { + if (obj->_vx > 0) + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; else - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; } } - obj->oldvx = obj->vx; - obj->oldvy = obj->vy; - currImage = obj->currImagePtr; // Get (new) ptr to current image + obj->_oldvx = obj->_vx; + obj->_oldvy = obj->_vy; + currImage = obj->_currImagePtr; // Get (new) ptr to current image } - if (obj->vx || obj->vy) - obj->cycling = kCycleForward; + if (obj->_vx || obj->_vy) + obj->_cycling = kCycleForward; break; default: ; // Really, nothing } // Store boundaries - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2); + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + storeBoundary(obj->_x + currImage->_x1, obj->_x + currImage->_x2, obj->_y + currImage->_y2); } } // Move objects, allowing for boundaries for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - if ((obj->screenIndex == *_vm->_screen_p) && (obj->vx || obj->vy)) { + Object *obj = &_objects[i]; // Get pointer to object + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_vx || obj->_vy)) { // Only process if it's moving // Do object movement. Delta_x,y return allowed movement in x,y // to move as close to a boundary as possible without crossing it. - seq_t *currImage = obj->currImagePtr; // Get ptr to current image + Seq *currImage = obj->_currImagePtr; // Get ptr to current image // object coordinates - int x1 = obj->x + currImage->x1; // Left edge of object - int x2 = obj->x + currImage->x2; // Right edge - int y1 = obj->y + currImage->y1; // Top edge - int y2 = obj->y + currImage->y2; // Bottom edge + int x1 = obj->_x + currImage->_x1; // Left edge of object + int x2 = obj->_x + currImage->_x2; // Right edge + int y1 = obj->_y + currImage->_y1; // Top edge + int y2 = obj->_y + currImage->_y2; // Bottom edge - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) clearBoundary(x1, x2, y2); // Clear our own boundary // Allowable motion wrt boundary - int dx = deltaX(x1, x2, obj->vx, y2); - if (dx != obj->vx) { + int dx = deltaX(x1, x2, obj->_vx, y2); + if (dx != obj->_vx) { // An object boundary collision! boundaryCollision(obj); - obj->vx = 0; + obj->_vx = 0; } - int dy = deltaY(x1, x2, obj->vy, y2); - if (dy != obj->vy) { + int dy = deltaY(x1, x2, obj->_vy, y2); + if (dy != obj->_vy) { // An object boundary collision! boundaryCollision(obj); - obj->vy = 0; + obj->_vy = 0; } - if ((obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) + if ((obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) storeBoundary(x1, x2, y2); // Re-store our own boundary - obj->x += dx; // Update object position - obj->y += dy; + obj->_x += dx; // Update object position + obj->_y += dy; // Don't let object go outside screen if (x1 < kEdge) - obj->x = kEdge2; + obj->_x = kEdge2; if (x2 > (kXPix - kEdge)) - obj->x = kXPix - kEdge2 - (x2 - x1); + obj->_x = kXPix - kEdge2 - (x2 - x1); if (y1 < kEdge) - obj->y = kEdge2; + obj->_y = kEdge2; if (y2 > (kYPix - kEdge)) - obj->y = kYPix - kEdge2 - (y2 - y1); + obj->_y = kYPix - kEdge2 - (y2 - y1); - if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != kPathWander2) && (obj->pathType != kPathChase2)) - obj->cycling = kCycleNotCycling; + if ((obj->_vx == 0) && (obj->_vy == 0) && (obj->_pathType != kPathWander2) && (obj->_pathType != kPathChase2)) + obj->_cycling = kCycleNotCycling; } } // Clear all object baselines from the boundary file. for (int i = 0; i < _numObj; i++) { - object_t *obj = &_objects[i]; // Get pointer to object - seq_t *currImage = obj->currImagePtr; // Get ptr to current image - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling > kCycleAlmostInvisible) && (obj->priority == kPriorityFloating)) - clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2); + Object *obj = &_objects[i]; // Get pointer to object + Seq *currImage = obj->_currImagePtr; // Get ptr to current image + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling > kCycleAlmostInvisible) && (obj->_priority == kPriorityFloating)) + clearBoundary(obj->_oldx + currImage->_x1, obj->_oldx + currImage->_x2, obj->_oldy + currImage->_y2); } // If maze mode is enabled, do special maze processing - if (_vm->_maze.enabledFl) { - seq_t *currImage = _vm->_hero->currImagePtr;// Get ptr to current image + if (_vm->_maze._enabledFl) { + Seq *currImage = _vm->_hero->_currImagePtr;// Get ptr to current image // hero coordinates - int x1 = _vm->_hero->x + currImage->x1; // Left edge of object - int x2 = _vm->_hero->x + currImage->x2; // Right edge - int y1 = _vm->_hero->y + currImage->y1; // Top edge - int y2 = _vm->_hero->y + currImage->y2; // Bottom edge + int x1 = _vm->_hero->_x + currImage->_x1; // Left edge of object + int x2 = _vm->_hero->_x + currImage->_x2; // Right edge + int y1 = _vm->_hero->_y + currImage->_y1; // Top edge + int y2 = _vm->_hero->_y + currImage->_y2; // Bottom edge _vm->_scheduler->processMaze(x1, x2, y1, y2); } @@ -249,18 +249,18 @@ void ObjectHandler_v3d::swapImages(int objIndex1, int objIndex2) { saveSeq(&_objects[objIndex1]); - seqList_t tmpSeqList[kMaxSeqNumb]; - int seqListSize = sizeof(seqList_t) * kMaxSeqNumb; + SeqList tmpSeqList[kMaxSeqNumb]; + int seqListSize = sizeof(SeqList) * kMaxSeqNumb; - memmove(tmpSeqList, _objects[objIndex1].seqList, seqListSize); - memmove(_objects[objIndex1].seqList, _objects[objIndex2].seqList, seqListSize); - memmove(_objects[objIndex2].seqList, tmpSeqList, seqListSize); + memmove(tmpSeqList, _objects[objIndex1]._seqList, seqListSize); + memmove(_objects[objIndex1]._seqList, _objects[objIndex2]._seqList, seqListSize); + memmove(_objects[objIndex2]._seqList, tmpSeqList, seqListSize); restoreSeq(&_objects[objIndex1]); - _objects[objIndex2].currImagePtr = _objects[objIndex2].seqList[0].seqPtr; + _objects[objIndex2]._currImagePtr = _objects[objIndex2]._seqList[0]._seqPtr; _vm->_heroImage = (_vm->_heroImage == kHeroIndex) ? objIndex2 : kHeroIndex; // Make sure baseline stays constant - _objects[objIndex1].y += _objects[objIndex2].currImagePtr->y2 - _objects[objIndex1].currImagePtr->y2; + _objects[objIndex1]._y += _objects[objIndex2]._currImagePtr->_y2 - _objects[objIndex1]._currImagePtr->_y2; } } // End of namespace Hugo diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp index 4eaed6fecf..5fdb2026a7 100644 --- a/engines/hugo/parser.cpp +++ b/engines/hugo/parser.cpp @@ -58,21 +58,21 @@ Parser::~Parser() { } uint16 Parser::getCmdDefaultVerbIdx(const uint16 index) const { - return _cmdList[index][0].verbIndex; + return _cmdList[index][0]._verbIndex; } /** * Read a cmd structure from Hugo.dat */ void Parser::readCmd(Common::ReadStream &in, cmd &curCmd) { - curCmd.verbIndex = in.readUint16BE(); - curCmd.reqIndex = in.readUint16BE(); - curCmd.textDataNoCarryIndex = in.readUint16BE(); - curCmd.reqState = in.readByte(); - curCmd.newState = in.readByte(); - curCmd.textDataWrongIndex = in.readUint16BE(); - curCmd.textDataDoneIndex = in.readUint16BE(); - curCmd.actIndex = in.readUint16BE(); + curCmd._verbIndex = in.readUint16BE(); + curCmd._reqIndex = in.readUint16BE(); + curCmd._textDataNoCarryIndex = in.readUint16BE(); + curCmd._reqState = in.readByte(); + curCmd._newState = in.readByte(); + curCmd._textDataWrongIndex = in.readUint16BE(); + curCmd._textDataDoneIndex = in.readUint16BE(); + curCmd._actIndex = in.readUint16BE(); } /** @@ -99,20 +99,20 @@ void Parser::loadCmdList(Common::ReadStream &in) { } -void Parser::readBG(Common::ReadStream &in, background_t &curBG) { - curBG.verbIndex = in.readUint16BE(); - curBG.nounIndex = in.readUint16BE(); - curBG.commentIndex = in.readSint16BE(); - curBG.matchFl = (in.readByte() != 0); - curBG.roomState = in.readByte(); - curBG.bonusIndex = in.readByte(); +void Parser::readBG(Common::ReadStream &in, Background &curBG) { + curBG._verbIndex = in.readUint16BE(); + curBG._nounIndex = in.readUint16BE(); + curBG._commentIndex = in.readSint16BE(); + curBG._matchFl = (in.readByte() != 0); + curBG._roomState = in.readByte(); + curBG._bonusIndex = in.readByte(); } /** * Read _backgrounObjects from Hugo.dat */ void Parser::loadBackgroundObjects(Common::ReadStream &in) { - background_t tmpBG; + Background tmpBG; memset(&tmpBG, 0, sizeof(tmpBG)); for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { @@ -120,13 +120,13 @@ void Parser::loadBackgroundObjects(Common::ReadStream &in) { if (varnt == _vm->_gameVariant) { _backgroundObjectsSize = numElem; - _backgroundObjects = (background_t **)malloc(sizeof(background_t *) * numElem); + _backgroundObjects = (Background **)malloc(sizeof(Background *) * numElem); } for (int i = 0; i < numElem; i++) { uint16 numSubElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) - _backgroundObjects[i] = (background_t *)malloc(sizeof(background_t) * numSubElem); + _backgroundObjects[i] = (Background *)malloc(sizeof(Background) * numSubElem); for (int j = 0; j < numSubElem; j++) readBG(in, (varnt == _vm->_gameVariant) ? _backgroundObjects[i][j] : tmpBG); @@ -138,15 +138,15 @@ void Parser::loadBackgroundObjects(Common::ReadStream &in) { * Read _catchallList from Hugo.dat */ void Parser::loadCatchallList(Common::ReadStream &in) { - background_t *wrkCatchallList = 0; - background_t tmpBG; + Background *wrkCatchallList = 0; + Background tmpBG; memset(&tmpBG, 0, sizeof(tmpBG)); for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { uint16 numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) - _catchallList = wrkCatchallList = (background_t *)malloc(sizeof(background_t) * numElem); + _catchallList = wrkCatchallList = (Background *)malloc(sizeof(Background) * numElem); for (int i = 0; i < numElem; i++) readBG(in, (varnt == _vm->_gameVariant) ? wrkCatchallList[i] : tmpBG); @@ -164,12 +164,12 @@ void Parser::loadArrayReqs(Common::SeekableReadStream &in) { const char *Parser::useBG(const char *name) { debugC(1, kDebugEngine, "useBG(%s)", name); - objectList_t p = _backgroundObjects[*_vm->_screen_p]; - for (int i = 0; p[i].verbIndex != 0; i++) { - if ((name == _vm->_text->getNoun(p[i].nounIndex, 0) && - p[i].verbIndex != _vm->_look) && - ((p[i].roomState == kStateDontCare) || (p[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) - return _vm->_text->getVerb(p[i].verbIndex, 0); + ObjectList p = _backgroundObjects[*_vm->_screenPtr]; + for (int i = 0; p[i]._verbIndex != 0; i++) { + if ((name == _vm->_text->getNoun(p[i]._nounIndex, 0) && + p[i]._verbIndex != _vm->_look) && + ((p[i]._roomState == kStateDontCare) || (p[i]._roomState == _vm->_screenStates[*_vm->_screenPtr]))) + return _vm->_text->getVerb(p[i]._verbIndex, 0); } return 0; @@ -198,7 +198,7 @@ void Parser::freeParser() { } void Parser::switchTurbo() { - _vm->_config.turboFl = !_vm->_config.turboFl; + _vm->_config._turboFl = !_vm->_config._turboFl; } /** @@ -208,7 +208,7 @@ void Parser::switchTurbo() { void Parser::charHandler() { debugC(4, kDebugParser, "charHandler"); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); // Check for one or more characters in ring buffer while (_getIndex != _putIndex) { @@ -222,7 +222,7 @@ void Parser::charHandler() { _cmdLine[--_cmdLineIndex] = '\0'; break; case Common::KEYCODE_RETURN: // EOL, pass line to line handler - if (_cmdLineIndex && (_vm->_hero->pathType != kPathQuiet)) { + if (_cmdLineIndex && (_vm->_hero->_pathType != kPathQuiet)) { // Remove inventory bar if active if (_vm->_inventory->getInventoryState() == kInventoryActive) _vm->_inventory->setInventoryState(kInventoryUp); @@ -248,27 +248,27 @@ void Parser::charHandler() { _cmdLineCursor = (_cmdLineCursor == '_') ? ' ' : '_'; // See if recall button pressed - if (gameStatus.recallFl) { + if (gameStatus._recallFl) { // Copy previous line to current cmdline - gameStatus.recallFl = false; + gameStatus._recallFl = false; strcpy(_cmdLine, _vm->_line); _cmdLineIndex = strlen(_cmdLine); } sprintf(_vm->_statusLine, ">%s%c", _cmdLine, _cmdLineCursor); - sprintf(_vm->_scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_vm->_config.turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(), (_vm->_config.soundFl) ? "On" : "Off"); + sprintf(_vm->_scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(), (_vm->_config._soundFl) ? "On" : "Off"); // See if "look" button pressed - if (gameStatus.lookFl) { + if (gameStatus._lookFl) { command("look around"); - gameStatus.lookFl = false; + gameStatus._lookFl = false; } } void Parser::keyHandler(Common::Event event) { debugC(1, kDebugParser, "keyHandler(%d)", event.kbd.keycode); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); uint16 nChar = event.kbd.keycode; if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_SCRL)) @@ -288,8 +288,8 @@ void Parser::keyHandler(Common::Event event) { _vm->_file->restoreGame(0); break; case Common::KEYCODE_s: - if (gameStatus.viewState == kViewPlay) { - if (gameStatus.gameOverFl) + if (gameStatus._viewState == kViewPlay) { + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -304,8 +304,8 @@ void Parser::keyHandler(Common::Event event) { // Process key down event - called from OnKeyDown() switch (nChar) { // Set various toggle states case Common::KEYCODE_ESCAPE: // Escape key, may want to QUIT - if (gameStatus.viewState == kViewIntro) - gameStatus.skipIntroFl = true; + if (gameStatus._viewState == kViewIntro) + gameStatus._skipIntroFl = true; else { if (_vm->_inventory->getInventoryState() == kInventoryActive) // Remove inventory, if displayed _vm->_inventory->setInventoryState(kInventoryUp); @@ -333,7 +333,7 @@ void Parser::keyHandler(Common::Event event) { break; case Common::KEYCODE_F1: // User Help (DOS) if (_checkDoubleF1Fl) - gameStatus.helpFl = true; + gameStatus._helpFl = true; else _vm->_screen->userHelp(); _checkDoubleF1Fl = !_checkDoubleF1Fl; @@ -343,11 +343,11 @@ void Parser::keyHandler(Common::Event event) { _vm->_sound->toggleMusic(); break; case Common::KEYCODE_F3: // Repeat last line - gameStatus.recallFl = true; + gameStatus._recallFl = true; break; case Common::KEYCODE_F4: // Save game - if (gameStatus.viewState == kViewPlay) { - if (gameStatus.gameOverFl) + if (gameStatus._viewState == kViewPlay) { + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -362,11 +362,8 @@ void Parser::keyHandler(Common::Event event) { case Common::KEYCODE_F8: // Turbo mode switchTurbo(); break; - case Common::KEYCODE_F9: // Boss button - warning("STUB: F9 (DOS) - BossKey"); - break; default: // Any other key - if (!gameStatus.storyModeFl) { // Keyboard disabled + if (!gameStatus._storyModeFl) { // Keyboard disabled // Add printable keys to ring buffer uint16 bnext = _putIndex + 1; if (bnext >= sizeof(_ringBuffer)) @@ -452,7 +449,7 @@ void Parser::showDosInventory() const { for (int i = 0; i < _vm->_object->_numObj; i++) { // Find widths of 2 columns if (_vm->_object->isCarried(i)) { - uint16 len = strlen(_vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 2)); + uint16 len = strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)); if (index++ & 1) // Right hand column len2 = (len > len2) ? len : len2; else @@ -473,9 +470,9 @@ void Parser::showDosInventory() const { for (int i = 0; i < _vm->_object->_numObj; i++) { // Assign strings if (_vm->_object->isCarried(i)) { if (index++ & 1) - buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 2)) + "\n"; + buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + "\n"; else - buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 2)) + Common::String(blanks, len1 - strlen(_vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 2))); + buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + Common::String(blanks, len1 - strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2))); } } if (index & 1) diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h index f8b9d9f13b..e72c46f591 100644 --- a/engines/hugo/parser.h +++ b/engines/hugo/parser.h @@ -48,14 +48,14 @@ enum seqTextParser { * The following determines how a verb is acted on, for an object */ struct cmd { - uint16 verbIndex; // the verb - uint16 reqIndex; // ptr to list of required objects - uint16 textDataNoCarryIndex; // ptr to string if any of above not carried - byte reqState; // required state for verb to be done - byte newState; // new states if verb done - uint16 textDataWrongIndex; // ptr to string if wrong state - uint16 textDataDoneIndex; // ptr to string if verb done - uint16 actIndex; // Ptr to action list if verb done + uint16 _verbIndex; // the verb + uint16 _reqIndex; // ptr to list of required objects + uint16 _textDataNoCarryIndex; // ptr to string if any of above not carried + byte _reqState; // required state for verb to be done + byte _newState; // new states if verb done + uint16 _textDataWrongIndex; // ptr to string if wrong state + uint16 _textDataDoneIndex; // ptr to string if verb done + uint16 _actIndex; // Ptr to action list if verb done }; /** @@ -64,16 +64,16 @@ struct cmd { * interesting ever happens with them. Rather than just be dumb and say * "don't understand" we produce an interesting msg to keep user sane. */ -struct background_t { - uint16 verbIndex; - uint16 nounIndex; - int commentIndex; // Index of comment produced on match - bool matchFl; // TRUE if noun must match when present - byte roomState; // "State" of room. Comments might differ. - byte bonusIndex; // Index of bonus score (0 = no bonus) +struct Background { + uint16 _verbIndex; + uint16 _nounIndex; + int _commentIndex; // Index of comment produced on match + bool _matchFl; // TRUE if noun must match when present + byte _roomState; // "State" of room. Comments might differ. + byte _bonusIndex; // Index of bonus score (0 = no bonus) }; -typedef background_t *objectList_t; +typedef Background *ObjectList; class Parser { public: @@ -97,7 +97,7 @@ public: virtual void lineHandler() = 0; virtual void showInventory() const = 0; - virtual void takeObject(object_t *obj) = 0; + virtual void takeObject(Object *obj) = 0; protected: HugoEngine *_vm; @@ -105,18 +105,18 @@ protected: int16 _cmdLineIndex; // Index into line uint32 _cmdLineTick; // For flashing cursor char _cmdLineCursor; - command_t _cmdLine; // Build command line + Command _cmdLine; // Build command line uint16 _backgroundObjectsSize; uint16 _cmdListSize; uint16 **_arrayReqs; - background_t **_backgroundObjects; - background_t *_catchallList; + Background **_backgroundObjects; + Background *_catchallList; cmd **_cmdList; const char *findNoun() const; const char *findVerb() const; - void readBG(Common::ReadStream &in, background_t &curBG); + void readBG(Common::ReadStream &in, Background &curBG); void readCmd(Common::ReadStream &in, cmd &curCmd); void showDosInventory() const; @@ -136,17 +136,17 @@ public: virtual void lineHandler(); virtual void showInventory() const; - virtual void takeObject(object_t *obj); + virtual void takeObject(Object *obj); protected: - virtual void dropObject(object_t *obj); + virtual void dropObject(Object *obj); const char *findNextNoun(const char *noun) const; - bool isBackgroundWord_v1(const char *noun, const char *verb, objectList_t obj) const; - bool isCatchallVerb_v1(bool testNounFl, const char *noun, const char *verb, objectList_t obj) const; - bool isGenericVerb_v1(const char *word, object_t *obj); - bool isNear_v1(const char *verb, const char *noun, object_t *obj, char *comment) const; - bool isObjectVerb_v1(const char *word, object_t *obj); + bool isBackgroundWord_v1(const char *noun, const char *verb, ObjectList obj) const; + bool isCatchallVerb_v1(bool testNounFl, const char *noun, const char *verb, ObjectList obj) const; + bool isGenericVerb_v1(const char *word, Object *obj); + bool isNear_v1(const char *verb, const char *noun, Object *obj, char *comment) const; + bool isObjectVerb_v1(const char *word, Object *obj); }; class Parser_v2d : public Parser_v1d { @@ -164,13 +164,13 @@ public: virtual void lineHandler(); protected: - void dropObject(object_t *obj); - bool isBackgroundWord_v3(objectList_t obj) const; - bool isCatchallVerb_v3(objectList_t obj) const; - bool isGenericVerb_v3(object_t *obj, char *comment); - bool isNear_v3(object_t *obj, const char *verb, char *comment) const; - bool isObjectVerb_v3(object_t *obj, char *comment); - void takeObject(object_t *obj); + void dropObject(Object *obj); + bool isBackgroundWord_v3(ObjectList obj) const; + bool isCatchallVerb_v3(ObjectList obj) const; + bool isGenericVerb_v3(Object *obj, char *comment); + bool isNear_v3(Object *obj, const char *verb, char *comment) const; + bool isObjectVerb_v3(Object *obj, char *comment); + void takeObject(Object *obj); }; class Parser_v1w : public Parser_v3d { diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp index ccd428311b..f29b0161f5 100644 --- a/engines/hugo/parser_v1d.cpp +++ b/engines/hugo/parser_v1d.cpp @@ -78,35 +78,35 @@ const char *Parser_v1d::findNextNoun(const char *noun) const { * If object not near, return suitable string; may be similar object closer * If radius is -1, treat radius as infinity */ -bool Parser_v1d::isNear_v1(const char *verb, const char *noun, object_t *obj, char *comment) const { +bool Parser_v1d::isNear_v1(const char *verb, const char *noun, Object *obj, char *comment) const { debugC(1, kDebugParser, "isNear(%s, %s, obj, %s)", verb, noun, comment); - if (!noun && !obj->verbOnlyFl) { // No noun specified & object not context senesitive + if (!noun && !obj->_verbOnlyFl) { // No noun specified & object not context senesitive return false; - } else if (noun && (noun != _vm->_text->getNoun(obj->nounIndex, 0))) { // Noun specified & not same as object + } else if (noun && (noun != _vm->_text->getNoun(obj->_nounIndex, 0))) { // Noun specified & not same as object return false; - } else if (obj->carriedFl) { // Object is being carried + } else if (obj->_carriedFl) { // Object is being carried return true; - } else if (obj->screenIndex != *_vm->_screen_p) { // Not in same screen - if (obj->objValue) + } else if (obj->_screenIndex != *_vm->_screenPtr) { // Not in same screen + if (obj->_objValue) strcpy (comment, _vm->_text->getTextParser(kCmtAny4)); return false; } - if (obj->cycling == kCycleInvisible) { - if (obj->seqNumb) { // There is an image + if (obj->_cycling == kCycleInvisible) { + if (obj->_seqNumb) { // There is an image strcpy(comment, _vm->_text->getTextParser(kCmtAny5)); return false; } else { // No image, assume visible - if ((obj->radius < 0) || - ((abs(obj->x - _vm->_hero->x) <= obj->radius) && - (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { + if ((obj->_radius < 0) || + ((abs(obj->_x - _vm->_hero->_x) <= obj->_radius) && + (abs(obj->_y - _vm->_hero->_y - _vm->_hero->_currImagePtr->_y2) <= obj->_radius))) { return true; } else { // User is either not close enough (stationary, valueless objects) // or is not carrying it (small, portable objects of value) if (noun) { // Don't say unless object specified - if (obj->objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) + if (obj->_objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) strcpy(comment, _vm->_text->getTextParser(kCmtAny4)); else strcpy(comment, _vm->_text->getTextParser(kCmtClose)); @@ -116,15 +116,15 @@ bool Parser_v1d::isNear_v1(const char *verb, const char *noun, object_t *obj, ch } } - if ((obj->radius < 0) || - ((abs(obj->x - _vm->_hero->x) <= obj->radius) && - (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { + if ((obj->_radius < 0) || + ((abs(obj->_x - _vm->_hero->_x) <= obj->_radius) && + (abs(obj->_y + obj->_currImagePtr->_y2 - _vm->_hero->_y - _vm->_hero->_currImagePtr->_y2) <= obj->_radius))) { return true; } else { // User is either not close enough (stationary, valueless objects) // or is not carrying it (small, portable objects of value) if (noun) { // Don't say unless object specified - if (obj->objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) + if (obj->_objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) strcpy(comment, _vm->_text->getTextParser(kCmtAny4)); else strcpy(comment, _vm->_text->getTextParser(kCmtClose)); @@ -140,31 +140,31 @@ bool Parser_v1d::isNear_v1(const char *verb, const char *noun, object_t *obj, ch * say_ok needed for special case of take/drop which may be handled not only * here but also in a cmd_list with a donestr string simultaneously */ -bool Parser_v1d::isGenericVerb_v1(const char *word, object_t *obj) { - debugC(1, kDebugParser, "isGenericVerb(%s, object_t *obj)", word); +bool Parser_v1d::isGenericVerb_v1(const char *word, Object *obj) { + debugC(1, kDebugParser, "isGenericVerb(%s, Object *obj)", word); - if (!obj->genericCmd) + if (!obj->_genericCmd) return false; // Following is equivalent to switch, but couldn't do one if (word == _vm->_text->getVerb(_vm->_look, 0)) { - if ((LOOK & obj->genericCmd) == LOOK) - Utils::notifyBox(_vm->_text->getTextData(obj->dataIndex)); + if ((LOOK & obj->_genericCmd) == LOOK) + Utils::notifyBox(_vm->_text->getTextData(obj->_dataIndex)); else Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual_1d)); } else if (word == _vm->_text->getVerb(_vm->_take, 0)) { - if (obj->carriedFl) + if (obj->_carriedFl) Utils::notifyBox(_vm->_text->getTextParser(kTBHave)); - else if ((TAKE & obj->genericCmd) == TAKE) + else if ((TAKE & obj->_genericCmd) == TAKE) takeObject(obj); - else if (!obj->verbOnlyFl) // Make sure not taking object in context! + else if (!obj->_verbOnlyFl) // Make sure not taking object in context! Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse)); else return false; } else if (word == _vm->_text->getVerb(_vm->_drop, 0)) { - if (!obj->carriedFl) + if (!obj->_carriedFl) Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave)); - else if ((DROP & obj->genericCmd) == DROP) + else if ((DROP & obj->_genericCmd) == DROP) dropObject(obj); else Utils::notifyBox(_vm->_text->getTextParser(kTBNeed)); @@ -181,46 +181,46 @@ bool Parser_v1d::isGenericVerb_v1(const char *word, object_t *obj) { * and if it passes, perform the actions in the action list. If the verb * is catered for, return TRUE */ -bool Parser_v1d::isObjectVerb_v1(const char *word, object_t *obj) { - debugC(1, kDebugParser, "isObjectVerb(%s, object_t *obj)", word); +bool Parser_v1d::isObjectVerb_v1(const char *word, Object *obj) { + debugC(1, kDebugParser, "isObjectVerb(%s, Object *obj)", word); // First, find matching verb in cmd list - uint16 cmdIndex = obj->cmdIndex; // ptr to list of commands + uint16 cmdIndex = obj->_cmdIndex; // ptr to list of commands if (!cmdIndex) // No commands for this obj return false; int i; - for (i = 0; _cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd - if (!strcmp(word, _vm->_text->getVerb(_cmdList[cmdIndex][i].verbIndex, 0))) // Is this verb catered for? + for (i = 0; _cmdList[cmdIndex][i]._verbIndex != 0; i++) { // For each cmd + if (!strcmp(word, _vm->_text->getVerb(_cmdList[cmdIndex][i]._verbIndex, 0))) // Is this verb catered for? break; } - if (_cmdList[cmdIndex][i].verbIndex == 0) // No + if (_cmdList[cmdIndex][i]._verbIndex == 0) // No return false; // Verb match found, check all required objects are being carried cmd *cmnd = &_cmdList[cmdIndex][i]; // ptr to struct cmd - if (cmnd->reqIndex) { // At least 1 thing in list - uint16 *reqs = _arrayReqs[cmnd->reqIndex]; // ptr to list of required objects + if (cmnd->_reqIndex) { // At least 1 thing in list + uint16 *reqs = _arrayReqs[cmnd->_reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj if (!_vm->_object->isCarrying(reqs[i])) { - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataNoCarryIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex)); return true; } } } // Required objects are present, now check state is correct - if ((obj->state != cmnd->reqState) && (cmnd->reqState != kStateDontCare)){ - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataWrongIndex)); + if ((obj->_state != cmnd->_reqState) && (cmnd->_reqState != kStateDontCare)){ + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex)); return true; } // Everything checked. Change the state and carry out any actions - if (cmnd->reqState != kStateDontCare) // Don't change new state if required state didn't care - obj->state = cmnd->newState; - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataDoneIndex)); - _vm->_scheduler->insertActionList(cmnd->actIndex); + if (cmnd->_reqState != kStateDontCare) // Don't change new state if required state didn't care + obj->_state = cmnd->_newState; + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex)); + _vm->_scheduler->insertActionList(cmnd->_actIndex); // Special case if verb is Take or Drop. Assume additional generic actions if ((word == _vm->_text->getVerb(_vm->_take, 0)) || (word == _vm->_text->getVerb(_vm->_drop, 0))) isGenericVerb_v1(word, obj); @@ -231,15 +231,15 @@ bool Parser_v1d::isObjectVerb_v1(const char *word, object_t *obj) { * Print text for possible background object. Return TRUE if match found * Only match if both verb and noun found. Test_ca will match verb-only */ -bool Parser_v1d::isBackgroundWord_v1(const char *noun, const char *verb, objectList_t obj) const { +bool Parser_v1d::isBackgroundWord_v1(const char *noun, const char *verb, ObjectList obj) const { debugC(1, kDebugParser, "isBackgroundWord(%s, %s, object_list_t obj)", noun, verb); if (!noun) return false; - for (int i = 0; obj[i].verbIndex; i++) { - if ((verb == _vm->_text->getVerb(obj[i].verbIndex, 0)) && (noun == _vm->_text->getNoun(obj[i].nounIndex, 0))) { - Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); + for (int i = 0; obj[i]._verbIndex; i++) { + if ((verb == _vm->_text->getVerb(obj[i]._verbIndex, 0)) && (noun == _vm->_text->getNoun(obj[i]._nounIndex, 0))) { + Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex)); return true; } } @@ -249,31 +249,31 @@ bool Parser_v1d::isBackgroundWord_v1(const char *noun, const char *verb, objectL /** * Do all things necessary to carry an object */ -void Parser_v1d::takeObject(object_t *obj) { - debugC(1, kDebugParser, "takeObject(object_t *obj)"); +void Parser_v1d::takeObject(Object *obj) { + debugC(1, kDebugParser, "takeObject(Object *obj)"); - obj->carriedFl = true; - if (obj->seqNumb) // Don't change if no image to display - obj->cycling = kCycleAlmostInvisible; + obj->_carriedFl = true; + if (obj->_seqNumb) // Don't change if no image to display + obj->_cycling = kCycleAlmostInvisible; - _vm->adjustScore(obj->objValue); + _vm->adjustScore(obj->_objValue); - Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME))); + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->_nounIndex, TAKE_NAME))); } /** * Do all necessary things to drop an object */ -void Parser_v1d::dropObject(object_t *obj) { - debugC(1, kDebugParser, "dropObject(object_t *obj)"); - - obj->carriedFl = false; - obj->screenIndex = *_vm->_screen_p; - if (obj->seqNumb) // Don't change if no image to display - obj->cycling = kCycleNotCycling; - obj->x = _vm->_hero->x - 1; - obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; - _vm->adjustScore(-obj->objValue); +void Parser_v1d::dropObject(Object *obj) { + debugC(1, kDebugParser, "dropObject(Object *obj)"); + + obj->_carriedFl = false; + obj->_screenIndex = *_vm->_screenPtr; + if (obj->_seqNumb) // Don't change if no image to display + obj->_cycling = kCycleNotCycling; + obj->_x = _vm->_hero->_x - 1; + obj->_y = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - 1; + _vm->adjustScore(-obj->_objValue); Utils::notifyBox(_vm->_text->getTextParser(kTBOk)); } @@ -281,18 +281,18 @@ void Parser_v1d::dropObject(object_t *obj) { * Print text for possible background object. Return TRUE if match found * If test_noun TRUE, must have a noun given */ -bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char *verb, objectList_t obj) const { +bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char *verb, ObjectList obj) const { debugC(1, kDebugParser, "isCatchallVerb(%d, %s, %s, object_list_t obj)", (testNounFl) ? 1 : 0, noun, verb); - if (_vm->_maze.enabledFl) + if (_vm->_maze._enabledFl) return false; if (testNounFl && !noun) return false; - for (int i = 0; obj[i].verbIndex; i++) { - if ((verb == _vm->_text->getVerb(obj[i].verbIndex, 0)) && ((noun == _vm->_text->getNoun(obj[i].nounIndex, 0)) || (obj[i].nounIndex == 0))) { - Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); + for (int i = 0; obj[i]._verbIndex; i++) { + if ((verb == _vm->_text->getVerb(obj[i]._verbIndex, 0)) && ((noun == _vm->_text->getNoun(obj[i]._nounIndex, 0)) || (obj[i]._nounIndex == 0))) { + Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex)); return true; } } @@ -305,12 +305,12 @@ bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char void Parser_v1d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_vm->_line, "PPG", 3)) { _vm->_sound->playSound(!_vm->_soundTest, kSoundPriorityHigh); - gameStatus.godModeFl = !gameStatus.godModeFl; + gameStatus._godModeFl = !gameStatus._godModeFl; return; } @@ -321,7 +321,7 @@ void Parser_v1d::lineHandler() { // fetch <object name> Hero carries named object // fetch all Hero carries all possible objects // find <object name> Takes hero to screen containing named object - if (gameStatus.godModeFl) { + if (gameStatus._godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_vm->_line, "goto")) { for (int i = 0; i < _vm->_numScreens; i++) { @@ -335,7 +335,7 @@ void Parser_v1d::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_vm->_line, "fetch all")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) + if (_vm->_object->_objects[i]._genericCmd & TAKE) takeObject(&_vm->_object->_objects[i]); } return; @@ -343,7 +343,7 @@ void Parser_v1d::lineHandler() { if (strstr(_vm->_line, "fetch")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { + if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { takeObject(&_vm->_object->_objects[i]); return; } @@ -353,8 +353,8 @@ void Parser_v1d::lineHandler() { // Special code to allow me to goto objects if (strstr(_vm->_line, "find")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { - _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); + if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i]._screenIndex); return; } } @@ -369,7 +369,7 @@ void Parser_v1d::lineHandler() { // SAVE/RESTORE if (!strcmp("save", _vm->_line)) { - if (gameStatus.gameOverFl) + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -387,7 +387,7 @@ void Parser_v1d::lineHandler() { if (strspn(_vm->_line, " ") == strlen(_vm->_line)) // Nothing but spaces! return; - if (gameStatus.gameOverFl) { + if (gameStatus._gameOverFl) { // No commands allowed! _vm->gameOverMsg(); return; @@ -403,14 +403,14 @@ void Parser_v1d::lineHandler() { noun = findNextNoun(noun); // Find a noun in the line // Must try at least once for objects allowing verb-context for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; + Object *obj = &_vm->_object->_objects[i]; if (isNear_v1(verb, noun, obj, farComment)) { if (isObjectVerb_v1(verb, obj) // Foreground object || isGenericVerb_v1(verb, obj))// Common action type return; } } - if ((*farComment == '\0') && isBackgroundWord_v1(noun, verb, _backgroundObjects[*_vm->_screen_p])) + if ((*farComment == '\0') && isBackgroundWord_v1(noun, verb, _backgroundObjects[*_vm->_screenPtr])) return; } while (noun); } @@ -418,15 +418,15 @@ void Parser_v1d::lineHandler() { if (*farComment != '\0') // An object matched but not near enough Utils::notifyBox(farComment); else if (!isCatchallVerb_v1(true, noun, verb, _catchallList) && - !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screen_p]) && + !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screenPtr]) && !isCatchallVerb_v1(false, noun, verb, _catchallList)) Utils::notifyBox(_vm->_text->getTextParser(kTBEh_1d)); } void Parser_v1d::showInventory() const { - status_t &gameStatus = _vm->getGameStatus(); - if (gameStatus.viewState == kViewPlay) { - if (gameStatus.gameOverFl) + Status &gameStatus = _vm->getGameStatus(); + if (gameStatus._viewState == kViewPlay) { + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else showDosInventory(); diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp index b1657c3bf4..3722ccc0e1 100644 --- a/engines/hugo/parser_v1w.cpp +++ b/engines/hugo/parser_v1w.cpp @@ -56,12 +56,12 @@ Parser_v1w::~Parser_v1w() { void Parser_v1w::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_vm->_line, "PPG", 3)) { _vm->_sound->playSound(!_vm->_soundTest, kSoundPriorityHigh); - gameStatus.godModeFl = !gameStatus.godModeFl; + gameStatus._godModeFl = !gameStatus._godModeFl; return; } @@ -72,7 +72,7 @@ void Parser_v1w::lineHandler() { // fetch <object name> Hero carries named object // fetch all Hero carries all possible objects // find <object name> Takes hero to screen containing named object - if (gameStatus.godModeFl) { + if (gameStatus._godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_vm->_line, "goto")) { for (int i = 0; i < _vm->_numScreens; i++) { @@ -86,7 +86,7 @@ void Parser_v1w::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_vm->_line, "fetch all")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) + if (_vm->_object->_objects[i]._genericCmd & TAKE) takeObject(&_vm->_object->_objects[i]); } return; @@ -94,7 +94,7 @@ void Parser_v1w::lineHandler() { if (strstr(_vm->_line, "fetch")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { + if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { takeObject(&_vm->_object->_objects[i]); return; } @@ -104,8 +104,8 @@ void Parser_v1w::lineHandler() { // Special code to allow me to goto objects if (strstr(_vm->_line, "find")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { - _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); + if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i]._screenIndex); return; } } @@ -121,12 +121,12 @@ void Parser_v1w::lineHandler() { } // SAVE/RESTORE - if (!strcmp("save", _vm->_line) && gameStatus.viewState == kViewPlay) { + if (!strcmp("save", _vm->_line) && gameStatus._viewState == kViewPlay) { _vm->_file->saveGame(-1, Common::String()); return; } - if (!strcmp("restore", _vm->_line) && (gameStatus.viewState == kViewPlay || gameStatus.viewState == kViewIdle)) { + if (!strcmp("restore", _vm->_line) && (gameStatus._viewState == kViewPlay || gameStatus._viewState == kViewIdle)) { _vm->_file->restoreGame(-1); return; } @@ -137,7 +137,7 @@ void Parser_v1w::lineHandler() { if (strspn(_vm->_line, " ") == strlen(_vm->_line)) // Nothing but spaces! return; - if (gameStatus.gameOverFl) { + if (gameStatus._gameOverFl) { // No commands allowed! _vm->gameOverMsg(); return; @@ -147,8 +147,8 @@ void Parser_v1w::lineHandler() { // Test for nearby objects referenced explicitly for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; - if (isWordPresent(_vm->_text->getNounArray(obj->nounIndex))) { + Object *obj = &_vm->_object->_objects[i]; + if (isWordPresent(_vm->_text->getNounArray(obj->_nounIndex))) { if (isObjectVerb_v3(obj, farComment) || isGenericVerb_v3(obj, farComment)) return; } @@ -157,8 +157,8 @@ void Parser_v1w::lineHandler() { // Test for nearby objects that only require a verb // Note comment is unused if not near. for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; - if (obj->verbOnlyFl) { + Object *obj = &_vm->_object->_objects[i]; + if (obj->_verbOnlyFl) { char contextComment[kCompLineSize * 5] = ""; // Unused comment for context objects if (isObjectVerb_v3(obj, contextComment) || isGenericVerb_v3(obj, contextComment)) return; @@ -166,9 +166,9 @@ void Parser_v1w::lineHandler() { } // No objects match command line, try background and catchall commands - if (isBackgroundWord_v3(_backgroundObjects[*_vm->_screen_p])) + if (isBackgroundWord_v3(_backgroundObjects[*_vm->_screenPtr])) return; - if (isCatchallVerb_v3(_backgroundObjects[*_vm->_screen_p])) + if (isCatchallVerb_v3(_backgroundObjects[*_vm->_screenPtr])) return; if (isBackgroundWord_v3(_catchallList)) @@ -185,7 +185,7 @@ void Parser_v1w::lineHandler() { // Nothing matches. Report recognition success to user. const char *verb = findVerb(); const char *noun = findNoun(); - if (verb == _vm->_text->getVerb(_vm->_look, 0) && _vm->_maze.enabledFl) { + if (verb == _vm->_text->getVerb(_vm->_look, 0) && _vm->_maze._enabledFl) { Utils::notifyBox(_vm->_text->getTextParser(kTBMaze)); _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of @@ -200,16 +200,16 @@ void Parser_v1w::lineHandler() { } void Parser_v1w::showInventory() const { - status_t &gameStatus = _vm->getGameStatus(); - istate_t inventState = _vm->_inventory->getInventoryState(); - if (gameStatus.gameOverFl) { + Status &gameStatus = _vm->getGameStatus(); + Istate inventState = _vm->_inventory->getInventoryState(); + if (gameStatus._gameOverFl) { _vm->gameOverMsg(); - } else if ((inventState == kInventoryOff) && (gameStatus.viewState == kViewPlay)) { + } else if ((inventState == kInventoryOff) && (gameStatus._viewState == kViewPlay)) { _vm->_inventory->setInventoryState(kInventoryDown); - gameStatus.viewState = kViewInvent; + gameStatus._viewState = kViewInvent; } else if (inventState == kInventoryActive) { _vm->_inventory->setInventoryState(kInventoryUp); - gameStatus.viewState = kViewInvent; + gameStatus._viewState = kViewInvent; } } diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp index 0095c4d726..6d71186f49 100644 --- a/engines/hugo/parser_v2d.cpp +++ b/engines/hugo/parser_v2d.cpp @@ -55,12 +55,12 @@ Parser_v2d::~Parser_v2d() { void Parser_v2d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_vm->_line, "PPG", 3)) { _vm->_sound->playSound(!_vm->_soundTest, kSoundPriorityHigh); - gameStatus.godModeFl = !gameStatus.godModeFl; + gameStatus._godModeFl = !gameStatus._godModeFl; return; } @@ -71,7 +71,7 @@ void Parser_v2d::lineHandler() { // fetch <object name> Hero carries named object // fetch all Hero carries all possible objects // find <object name> Takes hero to screen containing named object - if (gameStatus.godModeFl) { + if (gameStatus._godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_vm->_line, "goto")) { for (int i = 0; i < _vm->_numScreens; i++) { @@ -85,7 +85,7 @@ void Parser_v2d::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_vm->_line, "fetch all")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) + if (_vm->_object->_objects[i]._genericCmd & TAKE) takeObject(&_vm->_object->_objects[i]); } return; @@ -93,7 +93,7 @@ void Parser_v2d::lineHandler() { if (strstr(_vm->_line, "fetch")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { + if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { takeObject(&_vm->_object->_objects[i]); return; } @@ -103,8 +103,8 @@ void Parser_v2d::lineHandler() { // Special code to allow me to goto objects if (strstr(_vm->_line, "find")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { - _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); + if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i]._screenIndex); return; } } @@ -119,7 +119,7 @@ void Parser_v2d::lineHandler() { // SAVE/RESTORE if (!strcmp("save", _vm->_line)) { - if (gameStatus.gameOverFl) + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -137,7 +137,7 @@ void Parser_v2d::lineHandler() { if (strspn(_vm->_line, " ") == strlen(_vm->_line)) // Nothing but spaces! return; - if (gameStatus.gameOverFl) { + if (gameStatus._gameOverFl) { // No commands allowed! _vm->gameOverMsg(); return; @@ -153,26 +153,26 @@ void Parser_v2d::lineHandler() { noun = findNextNoun(noun); // Find a noun in the line // Must try at least once for objects allowing verb-context for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; + Object *obj = &_vm->_object->_objects[i]; if (isNear_v1(verb, noun, obj, farComment)) { if (isObjectVerb_v1(verb, obj) // Foreground object || isGenericVerb_v1(verb, obj))// Common action type return; } } - if ((*farComment != '\0') && isBackgroundWord_v1(noun, verb, _backgroundObjects[*_vm->_screen_p])) + if ((*farComment != '\0') && isBackgroundWord_v1(noun, verb, _backgroundObjects[*_vm->_screenPtr])) return; } while (noun); } noun = findNextNoun(noun); - if ( !isCatchallVerb_v1(true, noun, verb, _backgroundObjects[*_vm->_screen_p]) + if ( !isCatchallVerb_v1(true, noun, verb, _backgroundObjects[*_vm->_screenPtr]) && !isCatchallVerb_v1(true, noun, verb, _catchallList) - && !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screen_p]) + && !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screenPtr]) && !isCatchallVerb_v1(false, noun, verb, _catchallList)) { if (*farComment != '\0') { // An object matched but not near enough Utils::notifyBox(farComment); - } else if (_vm->_maze.enabledFl && (verb == _vm->_text->getVerb(_vm->_look, 0))) { + } else if (_vm->_maze._enabledFl && (verb == _vm->_text->getVerb(_vm->_look, 0))) { Utils::notifyBox(_vm->_text->getTextParser(kTBMaze)); _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp index b45e9186b3..a7e5896833 100644 --- a/engines/hugo/parser_v3d.cpp +++ b/engines/hugo/parser_v3d.cpp @@ -55,12 +55,12 @@ Parser_v3d::~Parser_v3d() { void Parser_v3d::lineHandler() { debugC(1, kDebugParser, "lineHandler()"); - status_t &gameStatus = _vm->getGameStatus(); + Status &gameStatus = _vm->getGameStatus(); // Toggle God Mode if (!strncmp(_vm->_line, "PPG", 3)) { _vm->_sound->playSound(!_vm->_soundTest, kSoundPriorityHigh); - gameStatus.godModeFl = !gameStatus.godModeFl; + gameStatus._godModeFl = !gameStatus._godModeFl; return; } @@ -71,7 +71,7 @@ void Parser_v3d::lineHandler() { // fetch <object name> Hero carries named object // fetch all Hero carries all possible objects // find <object name> Takes hero to screen containing named object - if (gameStatus.godModeFl) { + if (gameStatus._godModeFl) { // Special code to allow me to go straight to any screen if (strstr(_vm->_line, "goto")) { for (int i = 0; i < _vm->_numScreens; i++) { @@ -85,7 +85,7 @@ void Parser_v3d::lineHandler() { // Special code to allow me to get objects from anywhere if (strstr(_vm->_line, "fetch all")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (_vm->_object->_objects[i].genericCmd & TAKE) + if (_vm->_object->_objects[i]._genericCmd & TAKE) takeObject(&_vm->_object->_objects[i]); } return; @@ -93,7 +93,7 @@ void Parser_v3d::lineHandler() { if (strstr(_vm->_line, "fetch")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { + if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { takeObject(&_vm->_object->_objects[i]); return; } @@ -103,8 +103,8 @@ void Parser_v3d::lineHandler() { // Special code to allow me to goto objects if (strstr(_vm->_line, "find")) { for (int i = 0; i < _vm->_object->_numObj; i++) { - if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i].nounIndex, 0))) { - _vm->_scheduler->newScreen(_vm->_object->_objects[i].screenIndex); + if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) { + _vm->_scheduler->newScreen(_vm->_object->_objects[i]._screenIndex); return; } } @@ -121,7 +121,7 @@ void Parser_v3d::lineHandler() { // SAVE/RESTORE if (!strcmp("save", _vm->_line)) { - if (gameStatus.gameOverFl) + if (gameStatus._gameOverFl) _vm->gameOverMsg(); else _vm->_file->saveGame(-1, Common::String()); @@ -139,7 +139,7 @@ void Parser_v3d::lineHandler() { if (strspn(_vm->_line, " ") == strlen(_vm->_line)) // Nothing but spaces! return; - if (gameStatus.gameOverFl) { + if (gameStatus._gameOverFl) { // No commands allowed! _vm->gameOverMsg(); return; @@ -149,8 +149,8 @@ void Parser_v3d::lineHandler() { // Test for nearby objects referenced explicitly for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; - if (isWordPresent(_vm->_text->getNounArray(obj->nounIndex))) { + Object *obj = &_vm->_object->_objects[i]; + if (isWordPresent(_vm->_text->getNounArray(obj->_nounIndex))) { if (isObjectVerb_v3(obj, farComment) || isGenericVerb_v3(obj, farComment)) return; } @@ -159,8 +159,8 @@ void Parser_v3d::lineHandler() { // Test for nearby objects that only require a verb // Note comment is unused if not near. for (int i = 0; i < _vm->_object->_numObj; i++) { - object_t *obj = &_vm->_object->_objects[i]; - if (obj->verbOnlyFl) { + Object *obj = &_vm->_object->_objects[i]; + if (obj->_verbOnlyFl) { char contextComment[kCompLineSize * 5] = ""; // Unused comment for context objects if (isObjectVerb_v3(obj, contextComment) || isGenericVerb_v3(obj, contextComment)) return; @@ -168,9 +168,9 @@ void Parser_v3d::lineHandler() { } // No objects match command line, try background and catchall commands - if (isBackgroundWord_v3(_backgroundObjects[*_vm->_screen_p])) + if (isBackgroundWord_v3(_backgroundObjects[*_vm->_screenPtr])) return; - if (isCatchallVerb_v3(_backgroundObjects[*_vm->_screen_p])) + if (isCatchallVerb_v3(_backgroundObjects[*_vm->_screenPtr])) return; if (isBackgroundWord_v3(_catchallList)) @@ -204,51 +204,51 @@ void Parser_v3d::lineHandler() { * If it does, and the object is near and passes the tests in the command * list then carry out the actions in the action list and return TRUE */ -bool Parser_v3d::isObjectVerb_v3(object_t *obj, char *comment) { - debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s)", comment); +bool Parser_v3d::isObjectVerb_v3(Object *obj, char *comment) { + debugC(1, kDebugParser, "isObjectVerb(Object *obj, %s)", comment); // First, find matching verb in cmd list - uint16 cmdIndex = obj->cmdIndex; // ptr to list of commands + uint16 cmdIndex = obj->_cmdIndex; // ptr to list of commands if (cmdIndex == 0) // No commands for this obj return false; int i; - for (i = 0; _cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd - if (isWordPresent(_vm->_text->getVerbArray(_cmdList[cmdIndex][i].verbIndex))) // Was this verb used? + for (i = 0; _cmdList[cmdIndex][i]._verbIndex != 0; i++) { // For each cmd + if (isWordPresent(_vm->_text->getVerbArray(_cmdList[cmdIndex][i]._verbIndex))) // Was this verb used? break; } - if (_cmdList[cmdIndex][i].verbIndex == 0) // No verbs used. + if (_cmdList[cmdIndex][i]._verbIndex == 0) // No verbs used. return false; // Verb match found. Check if object is Near - char *verb = *_vm->_text->getVerbArray(_cmdList[cmdIndex][i].verbIndex); + char *verb = *_vm->_text->getVerbArray(_cmdList[cmdIndex][i]._verbIndex); if (!isNear_v3(obj, verb, comment)) return false; // Check all required objects are being carried cmd *cmnd = &_cmdList[cmdIndex][i]; // ptr to struct cmd - if (cmnd->reqIndex) { // At least 1 thing in list - uint16 *reqs = _arrayReqs[cmnd->reqIndex]; // ptr to list of required objects + if (cmnd->_reqIndex) { // At least 1 thing in list + uint16 *reqs = _arrayReqs[cmnd->_reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj if (!_vm->_object->isCarrying(reqs[i])) { - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataNoCarryIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex)); return true; } } } // Required objects are present, now check state is correct - if ((obj->state != cmnd->reqState) && (cmnd->reqState != kStateDontCare)) { - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataWrongIndex)); + if ((obj->_state != cmnd->_reqState) && (cmnd->_reqState != kStateDontCare)) { + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex)); return true; } // Everything checked. Change the state and carry out any actions - if (cmnd->reqState != kStateDontCare) // Don't change new state if required state didn't care - obj->state = cmnd->newState; - Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataDoneIndex)); - _vm->_scheduler->insertActionList(cmnd->actIndex); + if (cmnd->_reqState != kStateDontCare) // Don't change new state if required state didn't care + obj->_state = cmnd->_newState; + Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex)); + _vm->_scheduler->insertActionList(cmnd->_actIndex); // See if any additional generic actions if ((verb == _vm->_text->getVerb(_vm->_look, 0)) || (verb == _vm->_text->getVerb(_vm->_take, 0)) || (verb == _vm->_text->getVerb(_vm->_drop, 0))) @@ -259,21 +259,21 @@ bool Parser_v3d::isObjectVerb_v3(object_t *obj, char *comment) { /** * Test whether command line contains one of the generic actions */ -bool Parser_v3d::isGenericVerb_v3(object_t *obj, char *comment) { - debugC(1, kDebugParser, "isGenericVerb(object_t *obj, %s)", comment); +bool Parser_v3d::isGenericVerb_v3(Object *obj, char *comment) { + debugC(1, kDebugParser, "isGenericVerb(Object *obj, %s)", comment); - if (!obj->genericCmd) + if (!obj->_genericCmd) return false; // Following is equivalent to switch, but couldn't do one if (isWordPresent(_vm->_text->getVerbArray(_vm->_look)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_look, 0), comment)) { // Test state-dependent look before general look - if ((obj->genericCmd & LOOK_S) == LOOK_S) { - Utils::notifyBox(_vm->_text->getTextData(obj->stateDataIndex[obj->state])); + if ((obj->_genericCmd & LOOK_S) == LOOK_S) { + Utils::notifyBox(_vm->_text->getTextData(obj->_stateDataIndex[obj->_state])); } else { - if ((LOOK & obj->genericCmd) == LOOK) { - if (obj->dataIndex != 0) - Utils::notifyBox(_vm->_text->getTextData(obj->dataIndex)); + if ((LOOK & obj->_genericCmd) == LOOK) { + if (obj->_dataIndex != 0) + Utils::notifyBox(_vm->_text->getTextData(obj->_dataIndex)); else return false; } else { @@ -281,22 +281,22 @@ bool Parser_v3d::isGenericVerb_v3(object_t *obj, char *comment) { } } } else if (isWordPresent(_vm->_text->getVerbArray(_vm->_take)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_take, 0), comment)) { - if (obj->carriedFl) + if (obj->_carriedFl) Utils::notifyBox(_vm->_text->getTextParser(kTBHave)); - else if ((TAKE & obj->genericCmd) == TAKE) + else if ((TAKE & obj->_genericCmd) == TAKE) takeObject(obj); - else if (obj->cmdIndex) // No comment if possible commands + else if (obj->_cmdIndex) // No comment if possible commands return false; - else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context! + else if (!obj->_verbOnlyFl && (TAKE & obj->_genericCmd) == TAKE) // Make sure not taking object in context! Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse)); else return false; } else if (isWordPresent(_vm->_text->getVerbArray(_vm->_drop))) { - if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) + if (!obj->_carriedFl && ((DROP & obj->_genericCmd) == DROP)) Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave)); - else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) + else if (obj->_carriedFl && ((DROP & obj->_genericCmd) == DROP)) dropObject(obj); - else if (obj->cmdIndex == 0) + else if (obj->_cmdIndex == 0) Utils::notifyBox(_vm->_text->getTextParser(kTBNeed)); else return false; @@ -313,35 +313,35 @@ bool Parser_v3d::isGenericVerb_v3(object_t *obj, char *comment) { * If radius is -1, treat radius as infinity * Verb is included to determine correct comment if not near */ -bool Parser_v3d::isNear_v3(object_t *obj, const char *verb, char *comment) const { - debugC(1, kDebugParser, "isNear(object_t *obj, %s, %s)", verb, comment); +bool Parser_v3d::isNear_v3(Object *obj, const char *verb, char *comment) const { + debugC(1, kDebugParser, "isNear(Object *obj, %s, %s)", verb, comment); - if (obj->carriedFl) // Object is being carried + if (obj->_carriedFl) // Object is being carried return true; - if (obj->screenIndex != *_vm->_screen_p) { + if (obj->_screenIndex != *_vm->_screenPtr) { // Not in same screen - if (obj->objValue) + if (obj->_objValue) strcpy(comment, _vm->_text->getTextParser(kCmtAny1)); else strcpy(comment, _vm->_text->getTextParser(kCmtAny2)); return false; } - if (obj->cycling == kCycleInvisible) { - if (obj->seqNumb) { + if (obj->_cycling == kCycleInvisible) { + if (obj->_seqNumb) { // There is an image strcpy(comment, _vm->_text->getTextParser(kCmtAny3)); return false; } else { // No image, assume visible - if ((obj->radius < 0) || - ((abs(obj->x - _vm->_hero->x) <= obj->radius) && - (abs(obj->y - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { + if ((obj->_radius < 0) || + ((abs(obj->_x - _vm->_hero->_x) <= obj->_radius) && + (abs(obj->_y - _vm->_hero->_y - _vm->_hero->_currImagePtr->_y2) <= obj->_radius))) { return true; } else { // User is not close enough - if (obj->objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) + if (obj->_objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) strcpy(comment, _vm->_text->getTextParser(kCmtAny1)); else strcpy(comment, _vm->_text->getTextParser(kCmtClose)); @@ -350,13 +350,13 @@ bool Parser_v3d::isNear_v3(object_t *obj, const char *verb, char *comment) const } } - if ((obj->radius < 0) || - ((abs(obj->x - _vm->_hero->x) <= obj->radius) && - (abs(obj->y + obj->currImagePtr->y2 - _vm->_hero->y - _vm->_hero->currImagePtr->y2) <= obj->radius))) { + if ((obj->_radius < 0) || + ((abs(obj->_x - _vm->_hero->_x) <= obj->_radius) && + (abs(obj->_y + obj->_currImagePtr->_y2 - _vm->_hero->_y - _vm->_hero->_currImagePtr->_y2) <= obj->_radius))) { return true; } else { // User is not close enough - if (obj->objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) + if (obj->_objValue && (verb != _vm->_text->getVerb(_vm->_take, 0))) strcpy(comment, _vm->_text->getTextParser(kCmtAny1)); else strcpy(comment, _vm->_text->getTextParser(kCmtClose)); @@ -368,36 +368,36 @@ bool Parser_v3d::isNear_v3(object_t *obj, const char *verb, char *comment) const /** * Do all things necessary to carry an object */ -void Parser_v3d::takeObject(object_t *obj) { - debugC(1, kDebugParser, "takeObject(object_t *obj)"); +void Parser_v3d::takeObject(Object *obj) { + debugC(1, kDebugParser, "takeObject(Object *obj)"); - obj->carriedFl = true; - if (obj->seqNumb) { // Don't change if no image to display - obj->cycling = kCycleInvisible; + obj->_carriedFl = true; + if (obj->_seqNumb) { // Don't change if no image to display + obj->_cycling = kCycleInvisible; } - _vm->adjustScore(obj->objValue); + _vm->adjustScore(obj->_objValue); - if (obj->seqNumb > 0) // If object has an image, force walk to dropped - obj->viewx = -1; // (possibly moved) object next time taken! - Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME))); + if (obj->_seqNumb > 0) // If object has an image, force walk to dropped + obj->_viewx = -1; // (possibly moved) object next time taken! + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->_nounIndex, TAKE_NAME))); } /** * Do all necessary things to drop an object */ -void Parser_v3d::dropObject(object_t *obj) { - debugC(1, kDebugParser, "dropObject(object_t *obj)"); +void Parser_v3d::dropObject(Object *obj) { + debugC(1, kDebugParser, "dropObject(Object *obj)"); - obj->carriedFl = false; - obj->screenIndex = *_vm->_screen_p; - if ((obj->seqNumb > 1) || (obj->seqList[0].imageNbr > 1)) - obj->cycling = kCycleForward; + obj->_carriedFl = false; + obj->_screenIndex = *_vm->_screenPtr; + if ((obj->_seqNumb > 1) || (obj->_seqList[0]._imageNbr > 1)) + obj->_cycling = kCycleForward; else - obj->cycling = kCycleNotCycling; - obj->x = _vm->_hero->x - 1; - obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; - obj->y = (obj->y + obj->currImagePtr->y2 < kYPix) ? obj->y : kYPix - obj->currImagePtr->y2 - 10; - _vm->adjustScore(-obj->objValue); + obj->_cycling = kCycleNotCycling; + obj->_x = _vm->_hero->_x - 1; + obj->_y = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - 1; + obj->_y = (obj->_y + obj->_currImagePtr->_y2 < kYPix) ? obj->_y : kYPix - obj->_currImagePtr->_y2 - 10; + _vm->adjustScore(-obj->_objValue); Utils::notifyBox(_vm->_text->getTextParser(kTBOk)); } @@ -407,22 +407,22 @@ void Parser_v3d::dropObject(object_t *obj) { * Note that if the background command list has match set TRUE then do not * print text if there are any recognizable nouns in the command line */ -bool Parser_v3d::isCatchallVerb_v3(objectList_t obj) const { +bool Parser_v3d::isCatchallVerb_v3(ObjectList obj) const { debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)"); - if (_vm->_maze.enabledFl) + if (_vm->_maze._enabledFl) return false; - for (int i = 0; obj[i].verbIndex != 0; i++) { - if (isWordPresent(_vm->_text->getVerbArray(obj[i].verbIndex)) && obj[i].nounIndex == 0 && - (!obj[i].matchFl || !findNoun()) && - ((obj[i].roomState == kStateDontCare) || - (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { - Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); - _vm->_scheduler->processBonus(obj[i].bonusIndex); + for (int i = 0; obj[i]._verbIndex != 0; i++) { + if (isWordPresent(_vm->_text->getVerbArray(obj[i]._verbIndex)) && obj[i]._nounIndex == 0 && + (!obj[i]._matchFl || !findNoun()) && + ((obj[i]._roomState == kStateDontCare) || + (obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr]))) { + Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex)); + _vm->_scheduler->processBonus(obj[i]._bonusIndex); // If this is LOOK (without a noun), show any takeable objects - if (*(_vm->_text->getVerbArray(obj[i].verbIndex)) == _vm->_text->getVerb(_vm->_look, 0)) + if (*(_vm->_text->getVerbArray(obj[i]._verbIndex)) == _vm->_text->getVerb(_vm->_look, 0)) _vm->_object->showTakeables(); return true; @@ -435,19 +435,19 @@ bool Parser_v3d::isCatchallVerb_v3(objectList_t obj) const { * Search for matching verb/noun pairs in background command list * Print text for possible background object. Return TRUE if match found */ -bool Parser_v3d::isBackgroundWord_v3(objectList_t obj) const { +bool Parser_v3d::isBackgroundWord_v3(ObjectList obj) const { debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)"); - if (_vm->_maze.enabledFl) + if (_vm->_maze._enabledFl) return false; - for (int i = 0; obj[i].verbIndex != 0; i++) { - if (isWordPresent(_vm->_text->getVerbArray(obj[i].verbIndex)) && - isWordPresent(_vm->_text->getNounArray(obj[i].nounIndex)) && - ((obj[i].roomState == kStateDontCare) || - (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { - Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); - _vm->_scheduler->processBonus(obj[i].bonusIndex); + for (int i = 0; obj[i]._verbIndex != 0; i++) { + if (isWordPresent(_vm->_text->getVerbArray(obj[i]._verbIndex)) && + isWordPresent(_vm->_text->getNounArray(obj[i]._nounIndex)) && + ((obj[i]._roomState == kStateDontCare) || + (obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr]))) { + Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex)); + _vm->_scheduler->processBonus(obj[i]._bonusIndex); return true; } } diff --git a/engines/hugo/route.cpp b/engines/hugo/route.cpp index 281aacf031..54dae88c28 100644 --- a/engines/hugo/route.cpp +++ b/engines/hugo/route.cpp @@ -61,41 +61,41 @@ int16 Route::getRouteIndex() const { void Route::setDirection(const uint16 keyCode) { debugC(1, kDebugRoute, "setDirection(%d)", keyCode); - object_t *obj = _vm->_hero; // Pointer to hero object + Object *obj = _vm->_hero; // Pointer to hero object // Set first image in sequence switch (keyCode) { case Common::KEYCODE_UP: case Common::KEYCODE_KP8: - obj->currImagePtr = obj->seqList[SEQ_UP].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_UP]._seqPtr; break; case Common::KEYCODE_DOWN: case Common::KEYCODE_KP2: - obj->currImagePtr = obj->seqList[SEQ_DOWN].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_DOWN]._seqPtr; break; case Common::KEYCODE_LEFT: case Common::KEYCODE_KP4: - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; break; case Common::KEYCODE_RIGHT: case Common::KEYCODE_KP6: - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; break; case Common::KEYCODE_HOME: case Common::KEYCODE_KP7: - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; break; case Common::KEYCODE_END: case Common::KEYCODE_KP1: - obj->currImagePtr = obj->seqList[SEQ_LEFT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_LEFT]._seqPtr; break; case Common::KEYCODE_PAGEUP: case Common::KEYCODE_KP9: - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; break; case Common::KEYCODE_PAGEDOWN: case Common::KEYCODE_KP3: - obj->currImagePtr = obj->seqList[SEQ_RIGHT].seqPtr; + obj->_currImagePtr = obj->_seqList[SEQ_RIGHT]._seqPtr; break; } } @@ -107,68 +107,68 @@ void Route::setDirection(const uint16 keyCode) { void Route::setWalk(const uint16 direction) { debugC(1, kDebugRoute, "setWalk(%d)", direction); - object_t *obj = _vm->_hero; // Pointer to hero object + Object *obj = _vm->_hero; // Pointer to hero object - if (_vm->getGameStatus().storyModeFl || obj->pathType != kPathUser) // Make sure user has control + if (_vm->getGameStatus()._storyModeFl || obj->_pathType != kPathUser) // Make sure user has control return; - if (!obj->vx && !obj->vy) + if (!obj->_vx && !obj->_vy) _oldWalkDirection = 0; // Fix for consistant restarts if (direction != _oldWalkDirection) { // Direction has changed setDirection(direction); // Face new direction - obj->vx = obj->vy = 0; + obj->_vx = obj->_vy = 0; switch (direction) { // And set correct velocity case Common::KEYCODE_UP: case Common::KEYCODE_KP8: - obj->vy = -kStepDy; + obj->_vy = -kStepDy; break; case Common::KEYCODE_DOWN: case Common::KEYCODE_KP2: - obj->vy = kStepDy; + obj->_vy = kStepDy; break; case Common::KEYCODE_LEFT: case Common::KEYCODE_KP4: - obj->vx = -kStepDx; + obj->_vx = -kStepDx; break; case Common::KEYCODE_RIGHT: case Common::KEYCODE_KP6: - obj->vx = kStepDx; + obj->_vx = kStepDx; break; case Common::KEYCODE_HOME: case Common::KEYCODE_KP7: - obj->vx = -kStepDx; + obj->_vx = -kStepDx; // Note: in v1 Dos and v2 Dos, obj->vy is set to DY - obj->vy = -kStepDy / 2; + obj->_vy = -kStepDy / 2; break; case Common::KEYCODE_END: case Common::KEYCODE_KP1: - obj->vx = -kStepDx; + obj->_vx = -kStepDx; // Note: in v1 Dos and v2 Dos, obj->vy is set to -DY - obj->vy = kStepDy / 2; + obj->_vy = kStepDy / 2; break; case Common::KEYCODE_PAGEUP: case Common::KEYCODE_KP9: - obj->vx = kStepDx; + obj->_vx = kStepDx; // Note: in v1 Dos and v2 Dos, obj->vy is set to -DY - obj->vy = -kStepDy / 2; + obj->_vy = -kStepDy / 2; break; case Common::KEYCODE_PAGEDOWN: case Common::KEYCODE_KP3: - obj->vx = kStepDx; + obj->_vx = kStepDx; // Note: in v1 Dos and v2 Dos, obj->vy is set to DY - obj->vy = kStepDy / 2; + obj->_vy = kStepDy / 2; break; } _oldWalkDirection = direction; - obj->cycling = kCycleForward; + obj->_cycling = kCycleForward; } else { // Same key twice - halt hero - obj->vy = 0; - obj->vx = 0; + obj->_vy = 0; + obj->_vx = 0; _oldWalkDirection = 0; - obj->cycling = kCycleNotCycling; + obj->_cycling = kCycleNotCycling; } } @@ -188,8 +188,8 @@ void Route::segment(int16 x, int16 y) { debugC(1, kDebugRoute, "segment(%d, %d)", x, y); // Note: use of static - can't waste stack - static image_pt p; // Ptr to _boundaryMap[y] - static segment_t *seg_p; // Ptr to segment + static ImagePtr p; // Ptr to _boundaryMap[y] + static Segment *segPtr; // Ptr to segment // Bomb out if stack exhausted // Vinterstum: Is this just a safeguard, or actually used? @@ -228,7 +228,7 @@ void Route::segment(int16 x, int16 y) { if (y <= 0 || y >= kYPix - 1) return; - if (_vm->_hero->x < x1) { + if (_vm->_hero->_x < x1) { // Hero x not in segment, search x1..x2 // Find all segments above current for (x = x1; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x <= x2; x++) { @@ -241,7 +241,7 @@ void Route::segment(int16 x, int16 y) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } - } else if (_vm->_hero->x + kHeroMaxWidth > x2) { + } else if (_vm->_hero->_x + kHeroMaxWidth > x2) { // Hero x not in segment, search x1..x2 // Find all segments above current for (x = x2; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x >= x1; x--) { @@ -257,22 +257,22 @@ void Route::segment(int16 x, int16 y) { } else { // Organize search around hero x position - this gives // better chance for more direct route. - for (x = _vm->_hero->x; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x <= x2; x++) { + for (x = _vm->_hero->_x; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x <= x2; x++) { if (_boundaryMap[y - 1][x] == 0) segment(x, y - 1); } - for (x = x1; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x < _vm->_hero->x; x++) { + for (x = x1; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x < _vm->_hero->_x; x++) { if (_boundaryMap[y - 1][x] == 0) segment(x, y - 1); } - for (x = _vm->_hero->x; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x <= x2; x++) { + for (x = _vm->_hero->_x; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x <= x2; x++) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } - for (x = x1; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x < _vm->_hero->x; x++) { + for (x = x1; !(_routeFoundFl || _fullStackFl || _fullSegmentFl) && x < _vm->_hero->_x; x++) { if (_boundaryMap[y + 1][x] == 0) segment(x, y + 1); } @@ -285,10 +285,10 @@ void Route::segment(int16 x, int16 y) { _fullSegmentFl = true; } else { // Create segment - seg_p = &_segment[_segmentNumb]; - seg_p->y = y; - seg_p->x1 = x1; - seg_p->x2 = x2; + segPtr = &_segment[_segmentNumb]; + segPtr->_y = y; + segPtr->_x1 = x1; + segPtr->_x2 = x2; _segmentNumb++; } } @@ -298,7 +298,7 @@ void Route::segment(int16 x, int16 y) { * Create and return ptr to new node. Initialize with previous node. * Returns 0 if MAX_NODES exceeded */ -Point *Route::newNode() { +Common::Point *Route::newNode() { debugC(1, kDebugRoute, "newNode"); _routeListIndex++; @@ -327,16 +327,16 @@ bool Route::findRoute(const int16 cx, const int16 cy) { _destY = cy; // Destination coords _destX = cx; // Destination coords - int16 herox1 = _vm->_hero->x + _vm->_hero->currImagePtr->x1; // Hero baseline - int16 herox2 = _vm->_hero->x + _vm->_hero->currImagePtr->x2; // Hero baseline - int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2; // Hero baseline + int16 herox1 = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1; // Hero baseline + int16 herox2 = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x2; // Hero baseline + int16 heroy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2; // Hero baseline // Store all object baselines into objbound (except hero's = [0]) - object_t *obj; // Ptr to object + Object *obj; // Ptr to object int i; for (i = 1, obj = &_vm->_object->_objects[i]; i < _vm->_object->_numObj; i++, obj++) { - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating)) - _vm->_object->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling != kCycleInvisible) && (obj->_priority == kPriorityFloating)) + _vm->_object->storeBoundary(obj->_oldx + obj->_currImagePtr->_x1, obj->_oldx + obj->_currImagePtr->_x2, obj->_oldy + obj->_currImagePtr->_y2); } // Combine objbound and boundary bitmaps to local byte map @@ -350,8 +350,8 @@ bool Route::findRoute(const int16 cx, const int16 cy) { // Clear all object baselines from objbound for (i = 0, obj = _vm->_object->_objects; i < _vm->_object->_numObj; i++, obj++) { - if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating)) - _vm->_object->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2); + if ((obj->_screenIndex == *_vm->_screenPtr) && (obj->_cycling != kCycleInvisible) && (obj->_priority == kPriorityFloating)) + _vm->_object->clearBoundary(obj->_oldx + obj->_currImagePtr->_x1, obj->_oldx + obj->_currImagePtr->_x2, obj->_oldy + obj->_currImagePtr->_y2); } // Search from hero to destination @@ -368,32 +368,32 @@ bool Route::findRoute(const int16 cx, const int16 cy) { _route[0].y = _destY; // Make a final segment for hero's base (we left a spare) - _segment[_segmentNumb].y = heroy; - _segment[_segmentNumb].x1 = herox1; - _segment[_segmentNumb].x2 = herox2; + _segment[_segmentNumb]._y = heroy; + _segment[_segmentNumb]._x1 = herox1; + _segment[_segmentNumb]._x2 = herox2; _segmentNumb++; - Point *routeNode; // Ptr to route node + Common::Point *routeNode; // Ptr to route node // Look in segments[] for straight lines from destination to hero for (i = 0, _routeListIndex = 0; i < _segmentNumb - 1; i++) { if ((routeNode = newNode()) == 0) // New node for new segment return false; // Too many nodes - routeNode->y = _segment[i].y; + routeNode->y = _segment[i]._y; // Look ahead for furthest straight line for (int16 j = i + 1; j < _segmentNumb; j++) { - segment_t *seg_p = &_segment[j]; + Segment *segPtr = &_segment[j]; // Can we get to this segment from previous node? - if (seg_p->x1 <= routeNode->x && seg_p->x2 >= routeNode->x + _heroWidth - 1) { - routeNode->y = seg_p->y; // Yes, keep updating node + if (segPtr->_x1 <= routeNode->x && segPtr->_x2 >= routeNode->x + _heroWidth - 1) { + routeNode->y = segPtr->_y; // Yes, keep updating node } else { // No, create another node on previous segment to reach it if ((routeNode = newNode()) == 0) // Add new route node return false; // Too many nodes // Find overlap between old and new segments - int16 x1 = MAX(_segment[j - 1].x1, seg_p->x1); - int16 x2 = MIN(_segment[j - 1].x2, seg_p->x2); + int16 x1 = MAX(_segment[j - 1]._x1, segPtr->_x1); + int16 x2 = MIN(_segment[j - 1]._x2, segPtr->_x2); // If room, add a little offset to reduce staircase effect int16 dx = kHeroMaxWidth >> 1; @@ -433,18 +433,18 @@ void Route::processRoute() { return; // Current hero position - int16 herox = _vm->_hero->x + _vm->_hero->currImagePtr->x1; - int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2; - Point *routeNode = &_route[_routeIndex]; + int16 herox = _vm->_hero->_x + _vm->_hero->_currImagePtr->_x1; + int16 heroy = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2; + Common::Point *routeNode = &_route[_routeIndex]; // Arrived at node? if (abs(herox - routeNode->x) < kStepDx + 1 && abs(heroy - routeNode->y) < kStepDy) { // kStepDx too low // Close enough - position hero exactly - _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; - _vm->_hero->y = _vm->_hero->oldy = routeNode->y - _vm->_hero->currImagePtr->y2; - _vm->_hero->vx = _vm->_hero->vy = 0; - _vm->_hero->cycling = kCycleNotCycling; + _vm->_hero->_x = _vm->_hero->_oldx = routeNode->x - _vm->_hero->_currImagePtr->_x1; + _vm->_hero->_y = _vm->_hero->_oldy = routeNode->y - _vm->_hero->_currImagePtr->_y2; + _vm->_hero->_vx = _vm->_hero->_vy = 0; + _vm->_hero->_cycling = kCycleNotCycling; // Arrived at final node? if (--_routeIndex < 0) { @@ -458,7 +458,7 @@ void Route::processRoute() { _vm->_object->lookObject(&_vm->_object->_objects[_routeObjId]); turnedFl = false; } else { - setDirection(_vm->_object->_objects[_routeObjId].direction); + setDirection(_vm->_object->_objects[_routeObjId]._direction); _routeIndex++; // Come round again turnedFl = true; } @@ -468,7 +468,7 @@ void Route::processRoute() { _vm->_object->useObject(_routeObjId); turnedFl = false; } else { - setDirection(_vm->_object->_objects[_routeObjId].direction); + setDirection(_vm->_object->_objects[_routeObjId]._direction); _routeIndex++; // Come round again turnedFl = true; } @@ -477,7 +477,7 @@ void Route::processRoute() { break; } } - } else if (_vm->_hero->vx == 0 && _vm->_hero->vy == 0) { + } else if (_vm->_hero->_vx == 0 && _vm->_hero->_vy == 0) { // Set direction of travel if at a node // Note realignment when changing to (thinner) up/down sprite, // otherwise hero could bump into boundaries along route. @@ -487,10 +487,10 @@ void Route::processRoute() { setWalk(Common::KEYCODE_LEFT); } else if (heroy < routeNode->y) { setWalk(Common::KEYCODE_DOWN); - _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; + _vm->_hero->_x = _vm->_hero->_oldx = routeNode->x - _vm->_hero->_currImagePtr->_x1; } else if (heroy > routeNode->y) { setWalk(Common::KEYCODE_UP); - _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1; + _vm->_hero->_x = _vm->_hero->_oldx = routeNode->x - _vm->_hero->_currImagePtr->_x1; } } } @@ -500,11 +500,11 @@ void Route::processRoute() { * go_for is the purpose, id indexes the exit or object to walk to * Returns FALSE if route not found */ -bool Route::startRoute(const go_t routeType, const int16 objId, int16 cx, int16 cy) { +bool Route::startRoute(const RouteType routeType, const int16 objId, int16 cx, int16 cy) { debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", routeType, objId, cx, cy); // Don't attempt to walk if user does not have control - if (_vm->_hero->pathType != kPathUser) + if (_vm->_hero->_pathType != kPathUser) return false; // if inventory showing, make it go away @@ -521,7 +521,7 @@ bool Route::startRoute(const go_t routeType, const int16 objId, int16 cx, int16 bool foundFl = false; // TRUE if route found ok if ((foundFl = findRoute(cx, cy))) { // Found a route? _routeIndex = _routeListIndex; // Node index - _vm->_hero->vx = _vm->_hero->vy = 0; // Stop manual motion + _vm->_hero->_vx = _vm->_hero->_vy = 0; // Stop manual motion } return foundFl; diff --git a/engines/hugo/route.h b/engines/hugo/route.h index a95dd2151b..716829a201 100644 --- a/engines/hugo/route.h +++ b/engines/hugo/route.h @@ -30,21 +30,18 @@ #ifndef HUGO_ROUTE_H #define HUGO_ROUTE_H +#include "common/rect.h" + namespace Hugo { /** * Purpose of an automatic route */ -enum go_t {kRouteSpace, kRouteExit, kRouteLook, kRouteGet}; - -struct Point { - int x; - int y; -}; +enum RouteType {kRouteSpace, kRouteExit, kRouteLook, kRouteGet}; -struct segment_t { // Search segment - int16 y; // y position - int16 x1, x2; // Range of segment +struct Segment { // Search segment + int16 _y; // y position + int16 _x1, _x2; // Range of segment }; class Route { @@ -55,7 +52,7 @@ public: int16 getRouteIndex() const; void processRoute(); - bool startRoute(const go_t routeType, const int16 objId, int16 cx, int16 cy); + bool startRoute(const RouteType routeType, const int16 objId, int16 cx, int16 cy); void setDirection(const uint16 keyCode); void setWalk(const uint16 direction); @@ -69,13 +66,13 @@ private: uint16 _oldWalkDirection; // Last direction char - int16 _routeIndex; // Index into route list, or -1 - go_t _routeType; // Purpose of an automatic route - int16 _routeObjId; // Index of exit of object walking to + int16 _routeIndex; // Index into route list, or -1 + RouteType _routeType; // Purpose of an automatic route + int16 _routeObjId; // Index of exit of object walking to byte _boundaryMap[kYPix][kXPix]; // Boundary byte map - segment_t _segment[kMaxSeg]; // List of points in fill-path - Point _route[kMaxNodes]; // List of nodes in route (global) + Segment _segment[kMaxSeg]; // List of points in fill-path + Common::Point _route[kMaxNodes]; // List of nodes in route (global) int16 _segmentNumb; // Count number of segments int16 _routeListIndex; // Index into route list int16 _destX; @@ -87,7 +84,7 @@ private: void segment(int16 x, int16 y); bool findRoute(const int16 cx, const int16 cy); - Point *newNode(); + Common::Point *newNode(); }; } // End of namespace Hugo diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp index 896e8fa2ce..32b8a47df7 100644 --- a/engines/hugo/schedule.cpp +++ b/engines/hugo/schedule.cpp @@ -66,15 +66,15 @@ void Scheduler::initCypher() { void Scheduler::initEventQueue() { debugC(1, kDebugSchedule, "initEventQueue"); - // Chain next_p from first to last + // Chain nextEvent from first to last for (int i = kMaxEvents; --i;) - _events[i - 1].nextEvent = &_events[i]; - _events[kMaxEvents - 1].nextEvent = 0; + _events[i - 1]._nextEvent = &_events[i]; + _events[kMaxEvents - 1]._nextEvent = 0; - // Chain prev_p from last to first + // Chain prevEvent from last to first for (int i = 1; i < kMaxEvents; i++) - _events[i].prevEvent = &_events[i - 1]; - _events[0].prevEvent = 0; + _events[i]._prevEvent = &_events[i - 1]; + _events[0]._prevEvent = 0; _headEvent = _tailEvent = 0; // Event list is empty _freeEvent = _events; // Free list is full @@ -83,14 +83,14 @@ void Scheduler::initEventQueue() { /** * Return a ptr to an event structure from the free list */ -event_t *Scheduler::getQueue() { +Event *Scheduler::getQueue() { debugC(4, kDebugSchedule, "getQueue"); if (!_freeEvent) // Error: no more events available error("An error has occurred: %s", "getQueue"); - event_t *resEvent = _freeEvent; - _freeEvent = _freeEvent->nextEvent; - resEvent->nextEvent = 0; + Event *resEvent = _freeEvent; + _freeEvent = _freeEvent->_nextEvent; + resEvent->_nextEvent = 0; return resEvent; } @@ -101,7 +101,7 @@ void Scheduler::insertActionList(const uint16 actIndex) { debugC(1, kDebugSchedule, "insertActionList(%d)", actIndex); if (_actListArr[actIndex]) { - for (int i = 0; _actListArr[actIndex][i].a0.actType != ANULL; i++) + for (int i = 0; _actListArr[actIndex][i]._a0._actType != ANULL; i++) insertAction(&_actListArr[actIndex][i]); } } @@ -112,7 +112,7 @@ void Scheduler::insertActionList(const uint16 actIndex) { uint32 Scheduler::getWinTicks() const { debugC(5, kDebugSchedule, "getWinTicks()"); - return _vm->getGameStatus().tick; + return _vm->getGameStatus()._tick; } /** @@ -147,9 +147,9 @@ uint32 Scheduler::getDosTicks(const bool updateFl) { void Scheduler::processBonus(const int bonusIndex) { debugC(1, kDebugSchedule, "processBonus(%d)", bonusIndex); - if (!_points[bonusIndex].scoredFl) { - _vm->adjustScore(_points[bonusIndex].score); - _points[bonusIndex].scoredFl = true; + if (!_points[bonusIndex]._scoredFl) { + _vm->adjustScore(_points[bonusIndex]._score); + _points[bonusIndex]._scoredFl = true; } } @@ -175,11 +175,11 @@ void Scheduler::newScreen(const int screenIndex) { } // 1. Clear out all local events - event_t *curEvent = _headEvent; // The earliest event - event_t *wrkEvent; // Event ptr + Event *curEvent = _headEvent; // The earliest event + Event *wrkEvent; // Event ptr while (curEvent) { // While mature events found - wrkEvent = curEvent->nextEvent; // Save p (becomes undefined after Del) - if (curEvent->localActionFl) + wrkEvent = curEvent->_nextEvent; // Save p (becomes undefined after Del) + if (curEvent->_localActionFl) delQueue(curEvent); // Return event to free list curEvent = wrkEvent; } @@ -259,10 +259,10 @@ void Scheduler::loadPoints(Common::SeekableReadStream &in) { uint16 numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) { _numBonuses = numElem; - _points = (point_t *)malloc(sizeof(point_t) * _numBonuses); + _points = (Point *)malloc(sizeof(Point) * _numBonuses); for (int i = 0; i < _numBonuses; i++) { - _points[i].score = in.readByte(); - _points[i].scoredFl = false; + _points[i]._score = in.readByte(); + _points[i]._scoredFl = false; } } else { in.skip(numElem); @@ -270,280 +270,280 @@ void Scheduler::loadPoints(Common::SeekableReadStream &in) { } } -void Scheduler::readAct(Common::ReadStream &in, act &curAct) { +void Scheduler::readAct(Common::ReadStream &in, Act &curAct) { uint16 numSubAct; - curAct.a0.actType = (action_t) in.readByte(); - switch (curAct.a0.actType) { + curAct._a0._actType = (Action) in.readByte(); + switch (curAct._a0._actType) { case ANULL: // -1 break; case ASCHEDULE: // 0 - curAct.a0.timer = in.readSint16BE(); - curAct.a0.actIndex = in.readUint16BE(); + curAct._a0._timer = in.readSint16BE(); + curAct._a0._actIndex = in.readUint16BE(); break; case START_OBJ: // 1 - curAct.a1.timer = in.readSint16BE(); - curAct.a1.objIndex = in.readSint16BE(); - curAct.a1.cycleNumb = in.readSint16BE(); - curAct.a1.cycle = (cycle_t) in.readByte(); + curAct._a1._timer = in.readSint16BE(); + curAct._a1._objIndex = in.readSint16BE(); + curAct._a1._cycleNumb = in.readSint16BE(); + curAct._a1._cycle = (Cycle) in.readByte(); break; case INIT_OBJXY: // 2 - curAct.a2.timer = in.readSint16BE(); - curAct.a2.objIndex = in.readSint16BE(); - curAct.a2.x = in.readSint16BE(); - curAct.a2.y = in.readSint16BE(); + curAct._a2._timer = in.readSint16BE(); + curAct._a2._objIndex = in.readSint16BE(); + curAct._a2._x = in.readSint16BE(); + curAct._a2._y = in.readSint16BE(); break; case PROMPT: // 3 - curAct.a3.timer = in.readSint16BE(); - curAct.a3.promptIndex = in.readSint16BE(); + curAct._a3._timer = in.readSint16BE(); + curAct._a3._promptIndex = in.readSint16BE(); numSubAct = in.readUint16BE(); - curAct.a3.responsePtr = (int *)malloc(sizeof(int) * numSubAct); + curAct._a3._responsePtr = (int *)malloc(sizeof(int) * numSubAct); for (int k = 0; k < numSubAct; k++) - curAct.a3.responsePtr[k] = in.readSint16BE(); - curAct.a3.actPassIndex = in.readUint16BE(); - curAct.a3.actFailIndex = in.readUint16BE(); - curAct.a3.encodedFl = (in.readByte() == 1) ? true : false; + curAct._a3._responsePtr[k] = in.readSint16BE(); + curAct._a3._actPassIndex = in.readUint16BE(); + curAct._a3._actFailIndex = in.readUint16BE(); + curAct._a3._encodedFl = (in.readByte() == 1) ? true : false; break; case BKGD_COLOR: // 4 - curAct.a4.timer = in.readSint16BE(); - curAct.a4.newBackgroundColor = in.readUint32BE(); + curAct._a4._timer = in.readSint16BE(); + curAct._a4._newBackgroundColor = in.readUint32BE(); break; case INIT_OBJVXY: // 5 - curAct.a5.timer = in.readSint16BE(); - curAct.a5.objIndex = in.readSint16BE(); - curAct.a5.vx = in.readSint16BE(); - curAct.a5.vy = in.readSint16BE(); + curAct._a5._timer = in.readSint16BE(); + curAct._a5._objIndex = in.readSint16BE(); + curAct._a5._vx = in.readSint16BE(); + curAct._a5._vy = in.readSint16BE(); break; case INIT_CARRY: // 6 - curAct.a6.timer = in.readSint16BE(); - curAct.a6.objIndex = in.readSint16BE(); - curAct.a6.carriedFl = (in.readByte() == 1) ? true : false; + curAct._a6._timer = in.readSint16BE(); + curAct._a6._objIndex = in.readSint16BE(); + curAct._a6._carriedFl = (in.readByte() == 1) ? true : false; break; case INIT_HF_COORD: // 7 - curAct.a7.timer = in.readSint16BE(); - curAct.a7.objIndex = in.readSint16BE(); + curAct._a7._timer = in.readSint16BE(); + curAct._a7._objIndex = in.readSint16BE(); break; case NEW_SCREEN: // 8 - curAct.a8.timer = in.readSint16BE(); - curAct.a8.screenIndex = in.readSint16BE(); + curAct._a8._timer = in.readSint16BE(); + curAct._a8._screenIndex = in.readSint16BE(); break; case INIT_OBJSTATE: // 9 - curAct.a9.timer = in.readSint16BE(); - curAct.a9.objIndex = in.readSint16BE(); - curAct.a9.newState = in.readByte(); + curAct._a9._timer = in.readSint16BE(); + curAct._a9._objIndex = in.readSint16BE(); + curAct._a9._newState = in.readByte(); break; case INIT_PATH: // 10 - curAct.a10.timer = in.readSint16BE(); - curAct.a10.objIndex = in.readSint16BE(); - curAct.a10.newPathType = in.readSint16BE(); - curAct.a10.vxPath = in.readByte(); - curAct.a10.vyPath = in.readByte(); + curAct._a10._timer = in.readSint16BE(); + curAct._a10._objIndex = in.readSint16BE(); + curAct._a10._newPathType = in.readSint16BE(); + curAct._a10._vxPath = in.readByte(); + curAct._a10._vyPath = in.readByte(); break; case COND_R: // 11 - curAct.a11.timer = in.readSint16BE(); - curAct.a11.objIndex = in.readSint16BE(); - curAct.a11.stateReq = in.readByte(); - curAct.a11.actPassIndex = in.readUint16BE(); - curAct.a11.actFailIndex = in.readUint16BE(); + curAct._a11._timer = in.readSint16BE(); + curAct._a11._objIndex = in.readSint16BE(); + curAct._a11._stateReq = in.readByte(); + curAct._a11._actPassIndex = in.readUint16BE(); + curAct._a11._actFailIndex = in.readUint16BE(); break; case TEXT: // 12 - curAct.a12.timer = in.readSint16BE(); - curAct.a12.stringIndex = in.readSint16BE(); + curAct._a12._timer = in.readSint16BE(); + curAct._a12._stringIndex = in.readSint16BE(); break; case SWAP_IMAGES: // 13 - curAct.a13.timer = in.readSint16BE(); - curAct.a13.objIndex1 = in.readSint16BE(); - curAct.a13.objIndex2 = in.readSint16BE(); + curAct._a13._timer = in.readSint16BE(); + curAct._a13._objIndex1 = in.readSint16BE(); + curAct._a13._objIndex2 = in.readSint16BE(); break; case COND_SCR: // 14 - curAct.a14.timer = in.readSint16BE(); - curAct.a14.objIndex = in.readSint16BE(); - curAct.a14.screenReq = in.readSint16BE(); - curAct.a14.actPassIndex = in.readUint16BE(); - curAct.a14.actFailIndex = in.readUint16BE(); + curAct._a14._timer = in.readSint16BE(); + curAct._a14._objIndex = in.readSint16BE(); + curAct._a14._screenReq = in.readSint16BE(); + curAct._a14._actPassIndex = in.readUint16BE(); + curAct._a14._actFailIndex = in.readUint16BE(); break; case AUTOPILOT: // 15 - curAct.a15.timer = in.readSint16BE(); - curAct.a15.objIndex1 = in.readSint16BE(); - curAct.a15.objIndex2 = in.readSint16BE(); - curAct.a15.dx = in.readByte(); - curAct.a15.dy = in.readByte(); + curAct._a15._timer = in.readSint16BE(); + curAct._a15._objIndex1 = in.readSint16BE(); + curAct._a15._objIndex2 = in.readSint16BE(); + curAct._a15._dx = in.readByte(); + curAct._a15._dy = in.readByte(); break; case INIT_OBJ_SEQ: // 16 - curAct.a16.timer = in.readSint16BE(); - curAct.a16.objIndex = in.readSint16BE(); - curAct.a16.seqIndex = in.readSint16BE(); + curAct._a16._timer = in.readSint16BE(); + curAct._a16._objIndex = in.readSint16BE(); + curAct._a16._seqIndex = in.readSint16BE(); break; case SET_STATE_BITS: // 17 - curAct.a17.timer = in.readSint16BE(); - curAct.a17.objIndex = in.readSint16BE(); - curAct.a17.stateMask = in.readSint16BE(); + curAct._a17._timer = in.readSint16BE(); + curAct._a17._objIndex = in.readSint16BE(); + curAct._a17._stateMask = in.readSint16BE(); break; case CLEAR_STATE_BITS: // 18 - curAct.a18.timer = in.readSint16BE(); - curAct.a18.objIndex = in.readSint16BE(); - curAct.a18.stateMask = in.readSint16BE(); + curAct._a18._timer = in.readSint16BE(); + curAct._a18._objIndex = in.readSint16BE(); + curAct._a18._stateMask = in.readSint16BE(); break; case TEST_STATE_BITS: // 19 - curAct.a19.timer = in.readSint16BE(); - curAct.a19.objIndex = in.readSint16BE(); - curAct.a19.stateMask = in.readSint16BE(); - curAct.a19.actPassIndex = in.readUint16BE(); - curAct.a19.actFailIndex = in.readUint16BE(); + curAct._a19._timer = in.readSint16BE(); + curAct._a19._objIndex = in.readSint16BE(); + curAct._a19._stateMask = in.readSint16BE(); + curAct._a19._actPassIndex = in.readUint16BE(); + curAct._a19._actFailIndex = in.readUint16BE(); break; case DEL_EVENTS: // 20 - curAct.a20.timer = in.readSint16BE(); - curAct.a20.actTypeDel = (action_t) in.readByte(); + curAct._a20._timer = in.readSint16BE(); + curAct._a20._actTypeDel = (Action) in.readByte(); break; case GAMEOVER: // 21 - curAct.a21.timer = in.readSint16BE(); + curAct._a21._timer = in.readSint16BE(); break; case INIT_HH_COORD: // 22 - curAct.a22.timer = in.readSint16BE(); - curAct.a22.objIndex = in.readSint16BE(); + curAct._a22._timer = in.readSint16BE(); + curAct._a22._objIndex = in.readSint16BE(); break; case EXIT: // 23 - curAct.a23.timer = in.readSint16BE(); + curAct._a23._timer = in.readSint16BE(); break; case BONUS: // 24 - curAct.a24.timer = in.readSint16BE(); - curAct.a24.pointIndex = in.readSint16BE(); + curAct._a24._timer = in.readSint16BE(); + curAct._a24._pointIndex = in.readSint16BE(); break; case COND_BOX: // 25 - curAct.a25.timer = in.readSint16BE(); - curAct.a25.objIndex = in.readSint16BE(); - curAct.a25.x1 = in.readSint16BE(); - curAct.a25.y1 = in.readSint16BE(); - curAct.a25.x2 = in.readSint16BE(); - curAct.a25.y2 = in.readSint16BE(); - curAct.a25.actPassIndex = in.readUint16BE(); - curAct.a25.actFailIndex = in.readUint16BE(); + curAct._a25._timer = in.readSint16BE(); + curAct._a25._objIndex = in.readSint16BE(); + curAct._a25._x1 = in.readSint16BE(); + curAct._a25._y1 = in.readSint16BE(); + curAct._a25._x2 = in.readSint16BE(); + curAct._a25._y2 = in.readSint16BE(); + curAct._a25._actPassIndex = in.readUint16BE(); + curAct._a25._actFailIndex = in.readUint16BE(); break; case SOUND: // 26 - curAct.a26.timer = in.readSint16BE(); - curAct.a26.soundIndex = in.readSint16BE(); + curAct._a26._timer = in.readSint16BE(); + curAct._a26._soundIndex = in.readSint16BE(); break; case ADD_SCORE: // 27 - curAct.a27.timer = in.readSint16BE(); - curAct.a27.objIndex = in.readSint16BE(); + curAct._a27._timer = in.readSint16BE(); + curAct._a27._objIndex = in.readSint16BE(); break; case SUB_SCORE: // 28 - curAct.a28.timer = in.readSint16BE(); - curAct.a28.objIndex = in.readSint16BE(); + curAct._a28._timer = in.readSint16BE(); + curAct._a28._objIndex = in.readSint16BE(); break; case COND_CARRY: // 29 - curAct.a29.timer = in.readSint16BE(); - curAct.a29.objIndex = in.readSint16BE(); - curAct.a29.actPassIndex = in.readUint16BE(); - curAct.a29.actFailIndex = in.readUint16BE(); + curAct._a29._timer = in.readSint16BE(); + curAct._a29._objIndex = in.readSint16BE(); + curAct._a29._actPassIndex = in.readUint16BE(); + curAct._a29._actFailIndex = in.readUint16BE(); break; case INIT_MAZE: // 30 - curAct.a30.timer = in.readSint16BE(); - curAct.a30.mazeSize = in.readByte(); - curAct.a30.x1 = in.readSint16BE(); - curAct.a30.y1 = in.readSint16BE(); - curAct.a30.x2 = in.readSint16BE(); - curAct.a30.y2 = in.readSint16BE(); - curAct.a30.x3 = in.readSint16BE(); - curAct.a30.x4 = in.readSint16BE(); - curAct.a30.firstScreenIndex = in.readByte(); + curAct._a30._timer = in.readSint16BE(); + curAct._a30._mazeSize = in.readByte(); + curAct._a30._x1 = in.readSint16BE(); + curAct._a30._y1 = in.readSint16BE(); + curAct._a30._x2 = in.readSint16BE(); + curAct._a30._y2 = in.readSint16BE(); + curAct._a30._x3 = in.readSint16BE(); + curAct._a30._x4 = in.readSint16BE(); + curAct._a30._firstScreenIndex = in.readByte(); break; case EXIT_MAZE: // 31 - curAct.a31.timer = in.readSint16BE(); + curAct._a31._timer = in.readSint16BE(); break; case INIT_PRIORITY: // 32 - curAct.a32.timer = in.readSint16BE(); - curAct.a32.objIndex = in.readSint16BE(); - curAct.a32.priority = in.readByte(); + curAct._a32._timer = in.readSint16BE(); + curAct._a32._objIndex = in.readSint16BE(); + curAct._a32._priority = in.readByte(); break; case INIT_SCREEN: // 33 - curAct.a33.timer = in.readSint16BE(); - curAct.a33.objIndex = in.readSint16BE(); - curAct.a33.screenIndex = in.readSint16BE(); + curAct._a33._timer = in.readSint16BE(); + curAct._a33._objIndex = in.readSint16BE(); + curAct._a33._screenIndex = in.readSint16BE(); break; case AGSCHEDULE: // 34 - curAct.a34.timer = in.readSint16BE(); - curAct.a34.actIndex = in.readUint16BE(); + curAct._a34._timer = in.readSint16BE(); + curAct._a34._actIndex = in.readUint16BE(); break; case REMAPPAL: // 35 - curAct.a35.timer = in.readSint16BE(); - curAct.a35.oldColorIndex = in.readSint16BE(); - curAct.a35.newColorIndex = in.readSint16BE(); + curAct._a35._timer = in.readSint16BE(); + curAct._a35._oldColorIndex = in.readSint16BE(); + curAct._a35._newColorIndex = in.readSint16BE(); break; case COND_NOUN: // 36 - curAct.a36.timer = in.readSint16BE(); - curAct.a36.nounIndex = in.readUint16BE(); - curAct.a36.actPassIndex = in.readUint16BE(); - curAct.a36.actFailIndex = in.readUint16BE(); + curAct._a36._timer = in.readSint16BE(); + curAct._a36._nounIndex = in.readUint16BE(); + curAct._a36._actPassIndex = in.readUint16BE(); + curAct._a36._actFailIndex = in.readUint16BE(); break; case SCREEN_STATE: // 37 - curAct.a37.timer = in.readSint16BE(); - curAct.a37.screenIndex = in.readSint16BE(); - curAct.a37.newState = in.readByte(); + curAct._a37._timer = in.readSint16BE(); + curAct._a37._screenIndex = in.readSint16BE(); + curAct._a37._newState = in.readByte(); break; case INIT_LIPS: // 38 - curAct.a38.timer = in.readSint16BE(); - curAct.a38.lipsObjIndex = in.readSint16BE(); - curAct.a38.objIndex = in.readSint16BE(); - curAct.a38.dxLips = in.readByte(); - curAct.a38.dyLips = in.readByte(); + curAct._a38._timer = in.readSint16BE(); + curAct._a38._lipsObjIndex = in.readSint16BE(); + curAct._a38._objIndex = in.readSint16BE(); + curAct._a38._dxLips = in.readByte(); + curAct._a38._dyLips = in.readByte(); break; case INIT_STORY_MODE: // 39 - curAct.a39.timer = in.readSint16BE(); - curAct.a39.storyModeFl = (in.readByte() == 1); + curAct._a39._timer = in.readSint16BE(); + curAct._a39._storyModeFl = (in.readByte() == 1); break; case WARN: // 40 - curAct.a40.timer = in.readSint16BE(); - curAct.a40.stringIndex = in.readSint16BE(); + curAct._a40._timer = in.readSint16BE(); + curAct._a40._stringIndex = in.readSint16BE(); break; case COND_BONUS: // 41 - curAct.a41.timer = in.readSint16BE(); - curAct.a41.BonusIndex = in.readSint16BE(); - curAct.a41.actPassIndex = in.readUint16BE(); - curAct.a41.actFailIndex = in.readUint16BE(); + curAct._a41._timer = in.readSint16BE(); + curAct._a41._bonusIndex = in.readSint16BE(); + curAct._a41._actPassIndex = in.readUint16BE(); + curAct._a41._actFailIndex = in.readUint16BE(); break; case TEXT_TAKE: // 42 - curAct.a42.timer = in.readSint16BE(); - curAct.a42.objIndex = in.readSint16BE(); + curAct._a42._timer = in.readSint16BE(); + curAct._a42._objIndex = in.readSint16BE(); break; case YESNO: // 43 - curAct.a43.timer = in.readSint16BE(); - curAct.a43.promptIndex = in.readSint16BE(); - curAct.a43.actYesIndex = in.readUint16BE(); - curAct.a43.actNoIndex = in.readUint16BE(); + curAct._a43._timer = in.readSint16BE(); + curAct._a43._promptIndex = in.readSint16BE(); + curAct._a43._actYesIndex = in.readUint16BE(); + curAct._a43._actNoIndex = in.readUint16BE(); break; case STOP_ROUTE: // 44 - curAct.a44.timer = in.readSint16BE(); + curAct._a44._timer = in.readSint16BE(); break; case COND_ROUTE: // 45 - curAct.a45.timer = in.readSint16BE(); - curAct.a45.routeIndex = in.readSint16BE(); - curAct.a45.actPassIndex = in.readUint16BE(); - curAct.a45.actFailIndex = in.readUint16BE(); + curAct._a45._timer = in.readSint16BE(); + curAct._a45._routeIndex = in.readSint16BE(); + curAct._a45._actPassIndex = in.readUint16BE(); + curAct._a45._actFailIndex = in.readUint16BE(); break; case INIT_JUMPEXIT: // 46 - curAct.a46.timer = in.readSint16BE(); - curAct.a46.jumpExitFl = (in.readByte() == 1); + curAct._a46._timer = in.readSint16BE(); + curAct._a46._jumpExitFl = (in.readByte() == 1); break; case INIT_VIEW: // 47 - curAct.a47.timer = in.readSint16BE(); - curAct.a47.objIndex = in.readSint16BE(); - curAct.a47.viewx = in.readSint16BE(); - curAct.a47.viewy = in.readSint16BE(); - curAct.a47.direction = in.readSint16BE(); + curAct._a47._timer = in.readSint16BE(); + curAct._a47._objIndex = in.readSint16BE(); + curAct._a47._viewx = in.readSint16BE(); + curAct._a47._viewy = in.readSint16BE(); + curAct._a47._direction = in.readSint16BE(); break; case INIT_OBJ_FRAME: // 48 - curAct.a48.timer = in.readSint16BE(); - curAct.a48.objIndex = in.readSint16BE(); - curAct.a48.seqIndex = in.readSint16BE(); - curAct.a48.frameIndex = in.readSint16BE(); + curAct._a48._timer = in.readSint16BE(); + curAct._a48._objIndex = in.readSint16BE(); + curAct._a48._seqIndex = in.readSint16BE(); + curAct._a48._frameIndex = in.readSint16BE(); break; case OLD_SONG: //49 - curAct.a49.timer = in.readSint16BE(); - curAct.a49.songIndex = in.readUint16BE(); + curAct._a49._timer = in.readSint16BE(); + curAct._a49._songIndex = in.readUint16BE(); break; default: - error("Engine - Unknown action type encountered: %d", curAct.a0.actType); + error("Engine - Unknown action type encountered: %d", curAct._a0._actType); } } @@ -553,32 +553,32 @@ void Scheduler::readAct(Common::ReadStream &in, act &curAct) { void Scheduler::loadActListArr(Common::ReadStream &in) { debugC(6, kDebugSchedule, "loadActListArr(&in)"); - act tmpAct; + Act tmpAct; int numElem, numSubElem; for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) { _actListArrSize = numElem; - _actListArr = (act **)malloc(sizeof(act *) * _actListArrSize); + _actListArr = (Act **)malloc(sizeof(Act *) * _actListArrSize); } for (int i = 0; i < numElem; i++) { numSubElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) - _actListArr[i] = (act *)malloc(sizeof(act) * (numSubElem + 1)); + _actListArr[i] = (Act *)malloc(sizeof(Act) * (numSubElem + 1)); for (int j = 0; j < numSubElem; j++) { if (varnt == _vm->_gameVariant) { readAct(in, _actListArr[i][j]); } else { readAct(in, tmpAct); - if (tmpAct.a0.actType == PROMPT) - free(tmpAct.a3.responsePtr); + if (tmpAct._a0._actType == PROMPT) + free(tmpAct._a3._responsePtr); } } if (varnt == _vm->_gameVariant) - _actListArr[i][numSubElem].a0.actType = ANULL; + _actListArr[i][numSubElem]._a0._actType = ANULL; } } } @@ -626,9 +626,9 @@ void Scheduler::freeScheduler() { if (_actListArr) { for (int i = 0; i < _actListArrSize; i++) { - for (int j = 0; _actListArr[i][j].a0.actType != ANULL; j++) { - if (_actListArr[i][j].a0.actType == PROMPT) - free(_actListArr[i][j].a3.responsePtr); + for (int j = 0; _actListArr[i][j]._a0._actType != ANULL; j++) { + if (_actListArr[i][j]._a0._actType == PROMPT) + free(_actListArr[i][j]._a3._responsePtr); } free(_actListArr[i]); } @@ -656,32 +656,32 @@ void Scheduler::screenActions(const int screenNum) { void Scheduler::processMaze(const int x1, const int x2, const int y1, const int y2) { debugC(1, kDebugSchedule, "processMaze"); - if (x1 < _vm->_maze.x1) { + if (x1 < _vm->_maze._x1) { // Exit west - _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p - 1; - _actListArr[_alNewscrIndex][0].a2.x = _vm->_maze.x2 - kShiftSize - (x2 - x1); - _actListArr[_alNewscrIndex][0].a2.y = _vm->_hero->y; + _actListArr[_alNewscrIndex][3]._a8._screenIndex = *_vm->_screenPtr - 1; + _actListArr[_alNewscrIndex][0]._a2._x = _vm->_maze._x2 - kShiftSize - (x2 - x1); + _actListArr[_alNewscrIndex][0]._a2._y = _vm->_hero->_y; _vm->_route->resetRoute(); insertActionList(_alNewscrIndex); - } else if (x2 > _vm->_maze.x2) { + } else if (x2 > _vm->_maze._x2) { // Exit east - _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p + 1; - _actListArr[_alNewscrIndex][0].a2.x = _vm->_maze.x1 + kShiftSize; - _actListArr[_alNewscrIndex][0].a2.y = _vm->_hero->y; + _actListArr[_alNewscrIndex][3]._a8._screenIndex = *_vm->_screenPtr + 1; + _actListArr[_alNewscrIndex][0]._a2._x = _vm->_maze._x1 + kShiftSize; + _actListArr[_alNewscrIndex][0]._a2._y = _vm->_hero->_y; _vm->_route->resetRoute(); insertActionList(_alNewscrIndex); - } else if (y1 < _vm->_maze.y1 - kShiftSize) { + } else if (y1 < _vm->_maze._y1 - kShiftSize) { // Exit north - _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p - _vm->_maze.size; - _actListArr[_alNewscrIndex][0].a2.x = _vm->_maze.x3; - _actListArr[_alNewscrIndex][0].a2.y = _vm->_maze.y2 - kShiftSize - (y2 - y1); + _actListArr[_alNewscrIndex][3]._a8._screenIndex = *_vm->_screenPtr - _vm->_maze._size; + _actListArr[_alNewscrIndex][0]._a2._x = _vm->_maze._x3; + _actListArr[_alNewscrIndex][0]._a2._y = _vm->_maze._y2 - kShiftSize - (y2 - y1); _vm->_route->resetRoute(); insertActionList(_alNewscrIndex); - } else if (y2 > _vm->_maze.y2 - kShiftSize / 2) { + } else if (y2 > _vm->_maze._y2 - kShiftSize / 2) { // Exit south - _actListArr[_alNewscrIndex][3].a8.screenIndex = *_vm->_screen_p + _vm->_maze.size; - _actListArr[_alNewscrIndex][0].a2.x = _vm->_maze.x4; - _actListArr[_alNewscrIndex][0].a2.y = _vm->_maze.y1 + kShiftSize; + _actListArr[_alNewscrIndex][3]._a8._screenIndex = *_vm->_screenPtr + _vm->_maze._size; + _actListArr[_alNewscrIndex][0]._a2._x = _vm->_maze._x4; + _actListArr[_alNewscrIndex][0]._a2._y = _vm->_maze._y1 + kShiftSize; _vm->_route->resetRoute(); insertActionList(_alNewscrIndex); } @@ -708,17 +708,17 @@ void Scheduler::saveEvents(Common::WriteStream *f) { // Convert event ptrs to indexes for (int16 i = 0; i < kMaxEvents; i++) { - event_t *wrkEvent = &_events[i]; + Event *wrkEvent = &_events[i]; // fix up action pointer (to do better) int16 index, subElem; - findAction(wrkEvent->action, &index, &subElem); + findAction(wrkEvent->_action, &index, &subElem); f->writeSint16BE(index); f->writeSint16BE(subElem); - f->writeByte((wrkEvent->localActionFl) ? 1 : 0); - f->writeUint32BE(wrkEvent->time); - f->writeSint16BE((wrkEvent->prevEvent == 0) ? -1 : (wrkEvent->prevEvent - _events)); - f->writeSint16BE((wrkEvent->nextEvent == 0) ? -1 : (wrkEvent->nextEvent - _events)); + f->writeByte((wrkEvent->_localActionFl) ? 1 : 0); + f->writeUint32BE(wrkEvent->_time); + f->writeSint16BE((wrkEvent->_prevEvent == 0) ? -1 : (wrkEvent->_prevEvent - _events)); + f->writeSint16BE((wrkEvent->_nextEvent == 0) ? -1 : (wrkEvent->_nextEvent - _events)); } } @@ -738,7 +738,7 @@ void Scheduler::restoreActions(Common::ReadStream *f) { int16 Scheduler::calcMaxPoints() const { int16 tmpScore = 0; for (int i = 0; i < _numBonuses; i++) - tmpScore += _points[i].score; + tmpScore += _points[i]._score; return tmpScore; } @@ -752,282 +752,282 @@ void Scheduler::saveActions(Common::WriteStream *f) const { for (int i = 0; i < _actListArrSize; i++) { // write all the sub elems data - for (nbrSubElem = 1; _actListArr[i][nbrSubElem - 1].a0.actType != ANULL; nbrSubElem++) + for (nbrSubElem = 1; _actListArr[i][nbrSubElem - 1]._a0._actType != ANULL; nbrSubElem++) ; f->writeUint16BE(nbrSubElem); for (int j = 0; j < nbrSubElem; j++) { - subElemType = _actListArr[i][j].a0.actType; + subElemType = _actListArr[i][j]._a0._actType; f->writeByte(subElemType); switch (subElemType) { case ANULL: // -1 break; case ASCHEDULE: // 0 - f->writeSint16BE(_actListArr[i][j].a0.timer); - f->writeUint16BE(_actListArr[i][j].a0.actIndex); + f->writeSint16BE(_actListArr[i][j]._a0._timer); + f->writeUint16BE(_actListArr[i][j]._a0._actIndex); break; case START_OBJ: // 1 - f->writeSint16BE(_actListArr[i][j].a1.timer); - f->writeSint16BE(_actListArr[i][j].a1.objIndex); - f->writeSint16BE(_actListArr[i][j].a1.cycleNumb); - f->writeByte(_actListArr[i][j].a1.cycle); + f->writeSint16BE(_actListArr[i][j]._a1._timer); + f->writeSint16BE(_actListArr[i][j]._a1._objIndex); + f->writeSint16BE(_actListArr[i][j]._a1._cycleNumb); + f->writeByte(_actListArr[i][j]._a1._cycle); break; case INIT_OBJXY: // 2 - f->writeSint16BE(_actListArr[i][j].a2.timer); - f->writeSint16BE(_actListArr[i][j].a2.objIndex); - f->writeSint16BE(_actListArr[i][j].a2.x); - f->writeSint16BE(_actListArr[i][j].a2.y); + f->writeSint16BE(_actListArr[i][j]._a2._timer); + f->writeSint16BE(_actListArr[i][j]._a2._objIndex); + f->writeSint16BE(_actListArr[i][j]._a2._x); + f->writeSint16BE(_actListArr[i][j]._a2._y); break; case PROMPT: // 3 - f->writeSint16BE(_actListArr[i][j].a3.timer); - f->writeSint16BE(_actListArr[i][j].a3.promptIndex); - for (nbrCpt = 0; _actListArr[i][j].a3.responsePtr[nbrCpt] != -1; nbrCpt++) + f->writeSint16BE(_actListArr[i][j]._a3._timer); + f->writeSint16BE(_actListArr[i][j]._a3._promptIndex); + for (nbrCpt = 0; _actListArr[i][j]._a3._responsePtr[nbrCpt] != -1; nbrCpt++) ; nbrCpt++; f->writeUint16BE(nbrCpt); for (int k = 0; k < nbrCpt; k++) - f->writeSint16BE(_actListArr[i][j].a3.responsePtr[k]); - f->writeUint16BE(_actListArr[i][j].a3.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a3.actFailIndex); - f->writeByte((_actListArr[i][j].a3.encodedFl) ? 1 : 0); + f->writeSint16BE(_actListArr[i][j]._a3._responsePtr[k]); + f->writeUint16BE(_actListArr[i][j]._a3._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a3._actFailIndex); + f->writeByte((_actListArr[i][j]._a3._encodedFl) ? 1 : 0); break; case BKGD_COLOR: // 4 - f->writeSint16BE(_actListArr[i][j].a4.timer); - f->writeUint32BE(_actListArr[i][j].a4.newBackgroundColor); + f->writeSint16BE(_actListArr[i][j]._a4._timer); + f->writeUint32BE(_actListArr[i][j]._a4._newBackgroundColor); break; case INIT_OBJVXY: // 5 - f->writeSint16BE(_actListArr[i][j].a5.timer); - f->writeSint16BE(_actListArr[i][j].a5.objIndex); - f->writeSint16BE(_actListArr[i][j].a5.vx); - f->writeSint16BE(_actListArr[i][j].a5.vy); + f->writeSint16BE(_actListArr[i][j]._a5._timer); + f->writeSint16BE(_actListArr[i][j]._a5._objIndex); + f->writeSint16BE(_actListArr[i][j]._a5._vx); + f->writeSint16BE(_actListArr[i][j]._a5._vy); break; case INIT_CARRY: // 6 - f->writeSint16BE(_actListArr[i][j].a6.timer); - f->writeSint16BE(_actListArr[i][j].a6.objIndex); - f->writeByte((_actListArr[i][j].a6.carriedFl) ? 1 : 0); + f->writeSint16BE(_actListArr[i][j]._a6._timer); + f->writeSint16BE(_actListArr[i][j]._a6._objIndex); + f->writeByte((_actListArr[i][j]._a6._carriedFl) ? 1 : 0); break; case INIT_HF_COORD: // 7 - f->writeSint16BE(_actListArr[i][j].a7.timer); - f->writeSint16BE(_actListArr[i][j].a7.objIndex); + f->writeSint16BE(_actListArr[i][j]._a7._timer); + f->writeSint16BE(_actListArr[i][j]._a7._objIndex); break; case NEW_SCREEN: // 8 - f->writeSint16BE(_actListArr[i][j].a8.timer); - f->writeSint16BE(_actListArr[i][j].a8.screenIndex); + f->writeSint16BE(_actListArr[i][j]._a8._timer); + f->writeSint16BE(_actListArr[i][j]._a8._screenIndex); break; case INIT_OBJSTATE: // 9 - f->writeSint16BE(_actListArr[i][j].a9.timer); - f->writeSint16BE(_actListArr[i][j].a9.objIndex); - f->writeByte(_actListArr[i][j].a9.newState); + f->writeSint16BE(_actListArr[i][j]._a9._timer); + f->writeSint16BE(_actListArr[i][j]._a9._objIndex); + f->writeByte(_actListArr[i][j]._a9._newState); break; case INIT_PATH: // 10 - f->writeSint16BE(_actListArr[i][j].a10.timer); - f->writeSint16BE(_actListArr[i][j].a10.objIndex); - f->writeSint16BE(_actListArr[i][j].a10.newPathType); - f->writeByte(_actListArr[i][j].a10.vxPath); - f->writeByte(_actListArr[i][j].a10.vyPath); + f->writeSint16BE(_actListArr[i][j]._a10._timer); + f->writeSint16BE(_actListArr[i][j]._a10._objIndex); + f->writeSint16BE(_actListArr[i][j]._a10._newPathType); + f->writeByte(_actListArr[i][j]._a10._vxPath); + f->writeByte(_actListArr[i][j]._a10._vyPath); break; case COND_R: // 11 - f->writeSint16BE(_actListArr[i][j].a11.timer); - f->writeSint16BE(_actListArr[i][j].a11.objIndex); - f->writeByte(_actListArr[i][j].a11.stateReq); - f->writeUint16BE(_actListArr[i][j].a11.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a11.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a11._timer); + f->writeSint16BE(_actListArr[i][j]._a11._objIndex); + f->writeByte(_actListArr[i][j]._a11._stateReq); + f->writeUint16BE(_actListArr[i][j]._a11._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a11._actFailIndex); break; case TEXT: // 12 - f->writeSint16BE(_actListArr[i][j].a12.timer); - f->writeSint16BE(_actListArr[i][j].a12.stringIndex); + f->writeSint16BE(_actListArr[i][j]._a12._timer); + f->writeSint16BE(_actListArr[i][j]._a12._stringIndex); break; case SWAP_IMAGES: // 13 - f->writeSint16BE(_actListArr[i][j].a13.timer); - f->writeSint16BE(_actListArr[i][j].a13.objIndex1); - f->writeSint16BE(_actListArr[i][j].a13.objIndex2); + f->writeSint16BE(_actListArr[i][j]._a13._timer); + f->writeSint16BE(_actListArr[i][j]._a13._objIndex1); + f->writeSint16BE(_actListArr[i][j]._a13._objIndex2); break; case COND_SCR: // 14 - f->writeSint16BE(_actListArr[i][j].a14.timer); - f->writeSint16BE(_actListArr[i][j].a14.objIndex); - f->writeSint16BE(_actListArr[i][j].a14.screenReq); - f->writeUint16BE(_actListArr[i][j].a14.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a14.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a14._timer); + f->writeSint16BE(_actListArr[i][j]._a14._objIndex); + f->writeSint16BE(_actListArr[i][j]._a14._screenReq); + f->writeUint16BE(_actListArr[i][j]._a14._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a14._actFailIndex); break; case AUTOPILOT: // 15 - f->writeSint16BE(_actListArr[i][j].a15.timer); - f->writeSint16BE(_actListArr[i][j].a15.objIndex1); - f->writeSint16BE(_actListArr[i][j].a15.objIndex2); - f->writeByte(_actListArr[i][j].a15.dx); - f->writeByte(_actListArr[i][j].a15.dy); + f->writeSint16BE(_actListArr[i][j]._a15._timer); + f->writeSint16BE(_actListArr[i][j]._a15._objIndex1); + f->writeSint16BE(_actListArr[i][j]._a15._objIndex2); + f->writeByte(_actListArr[i][j]._a15._dx); + f->writeByte(_actListArr[i][j]._a15._dy); break; case INIT_OBJ_SEQ: // 16 - f->writeSint16BE(_actListArr[i][j].a16.timer); - f->writeSint16BE(_actListArr[i][j].a16.objIndex); - f->writeSint16BE(_actListArr[i][j].a16.seqIndex); + f->writeSint16BE(_actListArr[i][j]._a16._timer); + f->writeSint16BE(_actListArr[i][j]._a16._objIndex); + f->writeSint16BE(_actListArr[i][j]._a16._seqIndex); break; case SET_STATE_BITS: // 17 - f->writeSint16BE(_actListArr[i][j].a17.timer); - f->writeSint16BE(_actListArr[i][j].a17.objIndex); - f->writeSint16BE(_actListArr[i][j].a17.stateMask); + f->writeSint16BE(_actListArr[i][j]._a17._timer); + f->writeSint16BE(_actListArr[i][j]._a17._objIndex); + f->writeSint16BE(_actListArr[i][j]._a17._stateMask); break; case CLEAR_STATE_BITS: // 18 - f->writeSint16BE(_actListArr[i][j].a18.timer); - f->writeSint16BE(_actListArr[i][j].a18.objIndex); - f->writeSint16BE(_actListArr[i][j].a18.stateMask); + f->writeSint16BE(_actListArr[i][j]._a18._timer); + f->writeSint16BE(_actListArr[i][j]._a18._objIndex); + f->writeSint16BE(_actListArr[i][j]._a18._stateMask); break; case TEST_STATE_BITS: // 19 - f->writeSint16BE(_actListArr[i][j].a19.timer); - f->writeSint16BE(_actListArr[i][j].a19.objIndex); - f->writeSint16BE(_actListArr[i][j].a19.stateMask); - f->writeUint16BE(_actListArr[i][j].a19.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a19.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a19._timer); + f->writeSint16BE(_actListArr[i][j]._a19._objIndex); + f->writeSint16BE(_actListArr[i][j]._a19._stateMask); + f->writeUint16BE(_actListArr[i][j]._a19._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a19._actFailIndex); break; case DEL_EVENTS: // 20 - f->writeSint16BE(_actListArr[i][j].a20.timer); - f->writeByte(_actListArr[i][j].a20.actTypeDel); + f->writeSint16BE(_actListArr[i][j]._a20._timer); + f->writeByte(_actListArr[i][j]._a20._actTypeDel); break; case GAMEOVER: // 21 - f->writeSint16BE(_actListArr[i][j].a21.timer); + f->writeSint16BE(_actListArr[i][j]._a21._timer); break; case INIT_HH_COORD: // 22 - f->writeSint16BE(_actListArr[i][j].a22.timer); - f->writeSint16BE(_actListArr[i][j].a22.objIndex); + f->writeSint16BE(_actListArr[i][j]._a22._timer); + f->writeSint16BE(_actListArr[i][j]._a22._objIndex); break; case EXIT: // 23 - f->writeSint16BE(_actListArr[i][j].a23.timer); + f->writeSint16BE(_actListArr[i][j]._a23._timer); break; case BONUS: // 24 - f->writeSint16BE(_actListArr[i][j].a24.timer); - f->writeSint16BE(_actListArr[i][j].a24.pointIndex); + f->writeSint16BE(_actListArr[i][j]._a24._timer); + f->writeSint16BE(_actListArr[i][j]._a24._pointIndex); break; case COND_BOX: // 25 - f->writeSint16BE(_actListArr[i][j].a25.timer); - f->writeSint16BE(_actListArr[i][j].a25.objIndex); - f->writeSint16BE(_actListArr[i][j].a25.x1); - f->writeSint16BE(_actListArr[i][j].a25.y1); - f->writeSint16BE(_actListArr[i][j].a25.x2); - f->writeSint16BE(_actListArr[i][j].a25.y2); - f->writeUint16BE(_actListArr[i][j].a25.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a25.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a25._timer); + f->writeSint16BE(_actListArr[i][j]._a25._objIndex); + f->writeSint16BE(_actListArr[i][j]._a25._x1); + f->writeSint16BE(_actListArr[i][j]._a25._y1); + f->writeSint16BE(_actListArr[i][j]._a25._x2); + f->writeSint16BE(_actListArr[i][j]._a25._y2); + f->writeUint16BE(_actListArr[i][j]._a25._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a25._actFailIndex); break; case SOUND: // 26 - f->writeSint16BE(_actListArr[i][j].a26.timer); - f->writeSint16BE(_actListArr[i][j].a26.soundIndex); + f->writeSint16BE(_actListArr[i][j]._a26._timer); + f->writeSint16BE(_actListArr[i][j]._a26._soundIndex); break; case ADD_SCORE: // 27 - f->writeSint16BE(_actListArr[i][j].a27.timer); - f->writeSint16BE(_actListArr[i][j].a27.objIndex); + f->writeSint16BE(_actListArr[i][j]._a27._timer); + f->writeSint16BE(_actListArr[i][j]._a27._objIndex); break; case SUB_SCORE: // 28 - f->writeSint16BE(_actListArr[i][j].a28.timer); - f->writeSint16BE(_actListArr[i][j].a28.objIndex); + f->writeSint16BE(_actListArr[i][j]._a28._timer); + f->writeSint16BE(_actListArr[i][j]._a28._objIndex); break; case COND_CARRY: // 29 - f->writeSint16BE(_actListArr[i][j].a29.timer); - f->writeSint16BE(_actListArr[i][j].a29.objIndex); - f->writeUint16BE(_actListArr[i][j].a29.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a29.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a29._timer); + f->writeSint16BE(_actListArr[i][j]._a29._objIndex); + f->writeUint16BE(_actListArr[i][j]._a29._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a29._actFailIndex); break; case INIT_MAZE: // 30 - f->writeSint16BE(_actListArr[i][j].a30.timer); - f->writeByte(_actListArr[i][j].a30.mazeSize); - f->writeSint16BE(_actListArr[i][j].a30.x1); - f->writeSint16BE(_actListArr[i][j].a30.y1); - f->writeSint16BE(_actListArr[i][j].a30.x2); - f->writeSint16BE(_actListArr[i][j].a30.y2); - f->writeSint16BE(_actListArr[i][j].a30.x3); - f->writeSint16BE(_actListArr[i][j].a30.x4); - f->writeByte(_actListArr[i][j].a30.firstScreenIndex); + f->writeSint16BE(_actListArr[i][j]._a30._timer); + f->writeByte(_actListArr[i][j]._a30._mazeSize); + f->writeSint16BE(_actListArr[i][j]._a30._x1); + f->writeSint16BE(_actListArr[i][j]._a30._y1); + f->writeSint16BE(_actListArr[i][j]._a30._x2); + f->writeSint16BE(_actListArr[i][j]._a30._y2); + f->writeSint16BE(_actListArr[i][j]._a30._x3); + f->writeSint16BE(_actListArr[i][j]._a30._x4); + f->writeByte(_actListArr[i][j]._a30._firstScreenIndex); break; case EXIT_MAZE: // 31 - f->writeSint16BE(_actListArr[i][j].a31.timer); + f->writeSint16BE(_actListArr[i][j]._a31._timer); break; case INIT_PRIORITY: // 32 - f->writeSint16BE(_actListArr[i][j].a32.timer); - f->writeSint16BE(_actListArr[i][j].a32.objIndex); - f->writeByte(_actListArr[i][j].a32.priority); + f->writeSint16BE(_actListArr[i][j]._a32._timer); + f->writeSint16BE(_actListArr[i][j]._a32._objIndex); + f->writeByte(_actListArr[i][j]._a32._priority); break; case INIT_SCREEN: // 33 - f->writeSint16BE(_actListArr[i][j].a33.timer); - f->writeSint16BE(_actListArr[i][j].a33.objIndex); - f->writeSint16BE(_actListArr[i][j].a33.screenIndex); + f->writeSint16BE(_actListArr[i][j]._a33._timer); + f->writeSint16BE(_actListArr[i][j]._a33._objIndex); + f->writeSint16BE(_actListArr[i][j]._a33._screenIndex); break; case AGSCHEDULE: // 34 - f->writeSint16BE(_actListArr[i][j].a34.timer); - f->writeUint16BE(_actListArr[i][j].a34.actIndex); + f->writeSint16BE(_actListArr[i][j]._a34._timer); + f->writeUint16BE(_actListArr[i][j]._a34._actIndex); break; case REMAPPAL: // 35 - f->writeSint16BE(_actListArr[i][j].a35.timer); - f->writeSint16BE(_actListArr[i][j].a35.oldColorIndex); - f->writeSint16BE(_actListArr[i][j].a35.newColorIndex); + f->writeSint16BE(_actListArr[i][j]._a35._timer); + f->writeSint16BE(_actListArr[i][j]._a35._oldColorIndex); + f->writeSint16BE(_actListArr[i][j]._a35._newColorIndex); break; case COND_NOUN: // 36 - f->writeSint16BE(_actListArr[i][j].a36.timer); - f->writeUint16BE(_actListArr[i][j].a36.nounIndex); - f->writeUint16BE(_actListArr[i][j].a36.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a36.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a36._timer); + f->writeUint16BE(_actListArr[i][j]._a36._nounIndex); + f->writeUint16BE(_actListArr[i][j]._a36._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a36._actFailIndex); break; case SCREEN_STATE: // 37 - f->writeSint16BE(_actListArr[i][j].a37.timer); - f->writeSint16BE(_actListArr[i][j].a37.screenIndex); - f->writeByte(_actListArr[i][j].a37.newState); + f->writeSint16BE(_actListArr[i][j]._a37._timer); + f->writeSint16BE(_actListArr[i][j]._a37._screenIndex); + f->writeByte(_actListArr[i][j]._a37._newState); break; case INIT_LIPS: // 38 - f->writeSint16BE(_actListArr[i][j].a38.timer); - f->writeSint16BE(_actListArr[i][j].a38.lipsObjIndex); - f->writeSint16BE(_actListArr[i][j].a38.objIndex); - f->writeByte(_actListArr[i][j].a38.dxLips); - f->writeByte(_actListArr[i][j].a38.dyLips); + f->writeSint16BE(_actListArr[i][j]._a38._timer); + f->writeSint16BE(_actListArr[i][j]._a38._lipsObjIndex); + f->writeSint16BE(_actListArr[i][j]._a38._objIndex); + f->writeByte(_actListArr[i][j]._a38._dxLips); + f->writeByte(_actListArr[i][j]._a38._dyLips); break; case INIT_STORY_MODE: // 39 - f->writeSint16BE(_actListArr[i][j].a39.timer); - f->writeByte((_actListArr[i][j].a39.storyModeFl) ? 1 : 0); + f->writeSint16BE(_actListArr[i][j]._a39._timer); + f->writeByte((_actListArr[i][j]._a39._storyModeFl) ? 1 : 0); break; case WARN: // 40 - f->writeSint16BE(_actListArr[i][j].a40.timer); - f->writeSint16BE(_actListArr[i][j].a40.stringIndex); + f->writeSint16BE(_actListArr[i][j]._a40._timer); + f->writeSint16BE(_actListArr[i][j]._a40._stringIndex); break; case COND_BONUS: // 41 - f->writeSint16BE(_actListArr[i][j].a41.timer); - f->writeSint16BE(_actListArr[i][j].a41.BonusIndex); - f->writeUint16BE(_actListArr[i][j].a41.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a41.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a41._timer); + f->writeSint16BE(_actListArr[i][j]._a41._bonusIndex); + f->writeUint16BE(_actListArr[i][j]._a41._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a41._actFailIndex); break; case TEXT_TAKE: // 42 - f->writeSint16BE(_actListArr[i][j].a42.timer); - f->writeSint16BE(_actListArr[i][j].a42.objIndex); + f->writeSint16BE(_actListArr[i][j]._a42._timer); + f->writeSint16BE(_actListArr[i][j]._a42._objIndex); break; case YESNO: // 43 - f->writeSint16BE(_actListArr[i][j].a43.timer); - f->writeSint16BE(_actListArr[i][j].a43.promptIndex); - f->writeUint16BE(_actListArr[i][j].a43.actYesIndex); - f->writeUint16BE(_actListArr[i][j].a43.actNoIndex); + f->writeSint16BE(_actListArr[i][j]._a43._timer); + f->writeSint16BE(_actListArr[i][j]._a43._promptIndex); + f->writeUint16BE(_actListArr[i][j]._a43._actYesIndex); + f->writeUint16BE(_actListArr[i][j]._a43._actNoIndex); break; case STOP_ROUTE: // 44 - f->writeSint16BE(_actListArr[i][j].a44.timer); + f->writeSint16BE(_actListArr[i][j]._a44._timer); break; case COND_ROUTE: // 45 - f->writeSint16BE(_actListArr[i][j].a45.timer); - f->writeSint16BE(_actListArr[i][j].a45.routeIndex); - f->writeUint16BE(_actListArr[i][j].a45.actPassIndex); - f->writeUint16BE(_actListArr[i][j].a45.actFailIndex); + f->writeSint16BE(_actListArr[i][j]._a45._timer); + f->writeSint16BE(_actListArr[i][j]._a45._routeIndex); + f->writeUint16BE(_actListArr[i][j]._a45._actPassIndex); + f->writeUint16BE(_actListArr[i][j]._a45._actFailIndex); break; case INIT_JUMPEXIT: // 46 - f->writeSint16BE(_actListArr[i][j].a46.timer); - f->writeByte((_actListArr[i][j].a46.jumpExitFl) ? 1 : 0); + f->writeSint16BE(_actListArr[i][j]._a46._timer); + f->writeByte((_actListArr[i][j]._a46._jumpExitFl) ? 1 : 0); break; case INIT_VIEW: // 47 - f->writeSint16BE(_actListArr[i][j].a47.timer); - f->writeSint16BE(_actListArr[i][j].a47.objIndex); - f->writeSint16BE(_actListArr[i][j].a47.viewx); - f->writeSint16BE(_actListArr[i][j].a47.viewy); - f->writeSint16BE(_actListArr[i][j].a47.direction); + f->writeSint16BE(_actListArr[i][j]._a47._timer); + f->writeSint16BE(_actListArr[i][j]._a47._objIndex); + f->writeSint16BE(_actListArr[i][j]._a47._viewx); + f->writeSint16BE(_actListArr[i][j]._a47._viewy); + f->writeSint16BE(_actListArr[i][j]._a47._direction); break; case INIT_OBJ_FRAME: // 48 - f->writeSint16BE(_actListArr[i][j].a48.timer); - f->writeSint16BE(_actListArr[i][j].a48.objIndex); - f->writeSint16BE(_actListArr[i][j].a48.seqIndex); - f->writeSint16BE(_actListArr[i][j].a48.frameIndex); + f->writeSint16BE(_actListArr[i][j]._a48._timer); + f->writeSint16BE(_actListArr[i][j]._a48._objIndex); + f->writeSint16BE(_actListArr[i][j]._a48._seqIndex); + f->writeSint16BE(_actListArr[i][j]._a48._frameIndex); break; case OLD_SONG: // 49, Added by Strangerke for DOS versions - f->writeSint16BE(_actListArr[i][j].a49.timer); - f->writeUint16BE(_actListArr[i][j].a49.songIndex); + f->writeSint16BE(_actListArr[i][j]._a49._timer); + f->writeUint16BE(_actListArr[i][j]._a49._songIndex); break; default: error("Unknown action %d", subElemType); @@ -1039,7 +1039,7 @@ void Scheduler::saveActions(Common::WriteStream *f) const { /* * Find the index in the action list to be able to serialize the action to save game */ -void Scheduler::findAction(const act* action, int16* index, int16* subElem) { +void Scheduler::findAction(const Act *action, int16 *index, int16 *subElem) { assert(index && subElem); if (!action) { @@ -1057,7 +1057,7 @@ void Scheduler::findAction(const act* action, int16* index, int16* subElem) { return; } j++; - } while (_actListArr[i][j-1].a0.actType != ANULL); + } while (_actListArr[i][j-1]._a0._actType != ANULL); } // action not found ?? assert(0); @@ -1090,10 +1090,10 @@ void Scheduler::restoreSchedulerData(Common::ReadStream *in) { void Scheduler::restoreEvents(Common::ReadStream *f) { debugC(1, kDebugSchedule, "restoreEvents"); - uint32 saveTime = f->readUint32BE(); // time of save - int16 freeIndex = f->readSint16BE(); // Free list index - int16 headIndex = f->readSint16BE(); // Head of list index - int16 tailIndex = f->readSint16BE(); // Tail of list index + uint32 saveTime = f->readUint32BE(); // time of save + int16 freeIndex = f->readSint16BE(); // Free list index + int16 headIndex = f->readSint16BE(); // Head of list index + int16 tailIndex = f->readSint16BE(); // Tail of list index // Restore events indexes to pointers for (int i = 0; i < kMaxEvents; i++) { @@ -1102,18 +1102,18 @@ void Scheduler::restoreEvents(Common::ReadStream *f) { // fix up action pointer (to do better) if ((index == -1) && (subElem == -1)) - _events[i].action = 0; + _events[i]._action = 0; else - _events[i].action = (act *)&_actListArr[index][subElem]; + _events[i]._action = (Act *)&_actListArr[index][subElem]; - _events[i].localActionFl = (f->readByte() == 1) ? true : false; - _events[i].time = f->readUint32BE(); + _events[i]._localActionFl = (f->readByte() == 1) ? true : false; + _events[i]._time = f->readUint32BE(); int16 prevIndex = f->readSint16BE(); int16 nextIndex = f->readSint16BE(); - _events[i].prevEvent = (prevIndex == -1) ? (event_t *)0 : &_events[prevIndex]; - _events[i].nextEvent = (nextIndex == -1) ? (event_t *)0 : &_events[nextIndex]; + _events[i]._prevEvent = (prevIndex == -1) ? (Event *)0 : &_events[prevIndex]; + _events[i]._nextEvent = (nextIndex == -1) ? (Event *)0 : &_events[nextIndex]; } _freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex]; _headEvent = (headIndex == -1) ? 0 : &_events[headIndex]; @@ -1121,10 +1121,10 @@ void Scheduler::restoreEvents(Common::ReadStream *f) { // Adjust times to fit our time uint32 curTime = getTicks(); - event_t *wrkEvent = _headEvent; // The earliest event - while (wrkEvent) { // While mature events found - wrkEvent->time = wrkEvent->time - saveTime + curTime; - wrkEvent = wrkEvent->nextEvent; + Event *wrkEvent = _headEvent; // The earliest event + while (wrkEvent) { // While mature events found + wrkEvent->_time = wrkEvent->_time - saveTime + curTime; + wrkEvent = wrkEvent->_nextEvent; } } @@ -1132,53 +1132,53 @@ void Scheduler::restoreEvents(Common::ReadStream *f) { * Insert the action pointed to by p into the timer event queue * The queue goes from head (earliest) to tail (latest) timewise */ -void Scheduler::insertAction(act *action) { - debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType); +void Scheduler::insertAction(Act *action) { + debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->_a0._actType); // First, get and initialize the event structure - event_t *curEvent = getQueue(); - curEvent->action = action; - switch (action->a0.actType) { // Assign whether local or global + Event *curEvent = getQueue(); + curEvent->_action = action; + switch (action->_a0._actType) { // Assign whether local or global case AGSCHEDULE: - curEvent->localActionFl = false; // Lasts over a new screen + curEvent->_localActionFl = false; // Lasts over a new screen break; // Workaround: When dying, switch to storyMode in order to block the keyboard. case GAMEOVER: - _vm->getGameStatus().storyModeFl = true; + _vm->getGameStatus()._storyModeFl = true; // No break on purpose default: - curEvent->localActionFl = true; // Rest are for current screen only + curEvent->_localActionFl = true; // Rest are for current screen only break; } - curEvent->time = action->a0.timer + getTicks(); // Convert rel to abs time + curEvent->_time = action->_a0._timer + getTicks(); // Convert rel to abs time // Now find the place to insert the event - if (!_tailEvent) { // Empty queue + if (!_tailEvent) { // Empty queue _tailEvent = _headEvent = curEvent; - curEvent->nextEvent = curEvent->prevEvent = 0; + curEvent->_nextEvent = curEvent->_prevEvent = 0; } else { - event_t *wrkEvent = _tailEvent; // Search from latest time back + Event *wrkEvent = _tailEvent; // Search from latest time back bool found = false; while (wrkEvent && !found) { - if (wrkEvent->time <= curEvent->time) { // Found if new event later + if (wrkEvent->_time <= curEvent->_time) { // Found if new event later found = true; - if (wrkEvent == _tailEvent) // New latest in list + if (wrkEvent == _tailEvent) // New latest in list _tailEvent = curEvent; else - wrkEvent->nextEvent->prevEvent = curEvent; - curEvent->nextEvent = wrkEvent->nextEvent; - wrkEvent->nextEvent = curEvent; - curEvent->prevEvent = wrkEvent; + wrkEvent->_nextEvent->_prevEvent = curEvent; + curEvent->_nextEvent = wrkEvent->_nextEvent; + wrkEvent->_nextEvent = curEvent; + curEvent->_prevEvent = wrkEvent; } - wrkEvent = wrkEvent->prevEvent; + wrkEvent = wrkEvent->_prevEvent; } - if (!found) { // Must be earliest in list - _headEvent->prevEvent = curEvent; // So insert as new head - curEvent->nextEvent = _headEvent; - curEvent->prevEvent = 0; + if (!found) { // Must be earliest in list + _headEvent->_prevEvent = curEvent; // So insert as new head + curEvent->_nextEvent = _headEvent; + curEvent->_prevEvent = 0; _headEvent = curEvent; } } @@ -1189,246 +1189,246 @@ void Scheduler::insertAction(act *action) { * It dequeues the event and returns it to the free list. It returns a ptr * to the next action in the list, except special case of NEW_SCREEN */ -event_t *Scheduler::doAction(event_t *curEvent) { - debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType); +Event *Scheduler::doAction(Event *curEvent) { + debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->_action->_a0._actType); - status_t &gameStatus = _vm->getGameStatus(); - act *action = curEvent->action; - object_t *obj1; - int dx, dy; - event_t *wrkEvent; // Save ev_p->next_p for return + Status &gameStatus = _vm->getGameStatus(); + Act *action = curEvent->_action; + Object *obj1; + int dx, dy; + Event *wrkEvent; // Save ev_p->nextEvent for return - switch (action->a0.actType) { - case ANULL: // Big NOP from DEL_EVENTS + switch (action->_a0._actType) { + case ANULL: // Big NOP from DEL_EVENTS break; - case ASCHEDULE: // act0: Schedule an action list - insertActionList(action->a0.actIndex); + case ASCHEDULE: // act0: Schedule an action list + insertActionList(action->_a0._actIndex); break; - case START_OBJ: // act1: Start an object cycling - _vm->_object->_objects[action->a1.objIndex].cycleNumb = action->a1.cycleNumb; - _vm->_object->_objects[action->a1.objIndex].cycling = action->a1.cycle; + case START_OBJ: // act1: Start an object cycling + _vm->_object->_objects[action->_a1._objIndex]._cycleNumb = action->_a1._cycleNumb; + _vm->_object->_objects[action->_a1._objIndex]._cycling = action->_a1._cycle; break; - case INIT_OBJXY: // act2: Initialize an object - _vm->_object->_objects[action->a2.objIndex].x = action->a2.x; // Coordinates - _vm->_object->_objects[action->a2.objIndex].y = action->a2.y; + case INIT_OBJXY: // act2: Initialize an object + _vm->_object->_objects[action->_a2._objIndex]._x = action->_a2._x; // Coordinates + _vm->_object->_objects[action->_a2._objIndex]._y = action->_a2._y; break; - case PROMPT: // act3: Prompt user for key phrase + case PROMPT: // act3: Prompt user for key phrase promptAction(action); break; - case BKGD_COLOR: // act4: Set new background color - _vm->_screen->setBackgroundColor(action->a4.newBackgroundColor); + case BKGD_COLOR: // act4: Set new background color + _vm->_screen->setBackgroundColor(action->_a4._newBackgroundColor); break; - case INIT_OBJVXY: // act5: Initialize an object velocity - _vm->_object->setVelocity(action->a5.objIndex, action->a5.vx, action->a5.vy); + case INIT_OBJVXY: // act5: Initialize an object velocity + _vm->_object->setVelocity(action->_a5._objIndex, action->_a5._vx, action->_a5._vy); break; - case INIT_CARRY: // act6: Initialize an object - _vm->_object->setCarry(action->a6.objIndex, action->a6.carriedFl); // carried status + case INIT_CARRY: // act6: Initialize an object + _vm->_object->setCarry(action->_a6._objIndex, action->_a6._carriedFl); // carried status break; - case INIT_HF_COORD: // act7: Initialize an object to hero's "feet" coords - _vm->_object->_objects[action->a7.objIndex].x = _vm->_hero->x - 1; - _vm->_object->_objects[action->a7.objIndex].y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; - _vm->_object->_objects[action->a7.objIndex].screenIndex = *_vm->_screen_p; // Don't forget screen! + case INIT_HF_COORD: // act7: Initialize an object to hero's "feet" coords + _vm->_object->_objects[action->_a7._objIndex]._x = _vm->_hero->_x - 1; + _vm->_object->_objects[action->_a7._objIndex]._y = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - 1; + _vm->_object->_objects[action->_a7._objIndex]._screenIndex = *_vm->_screenPtr; // Don't forget screen! break; - case NEW_SCREEN: // act8: Start new screen - newScreen(action->a8.screenIndex); + case NEW_SCREEN: // act8: Start new screen + newScreen(action->_a8._screenIndex); break; - case INIT_OBJSTATE: // act9: Initialize an object state - _vm->_object->_objects[action->a9.objIndex].state = action->a9.newState; + case INIT_OBJSTATE: // act9: Initialize an object state + _vm->_object->_objects[action->_a9._objIndex]._state = action->_a9._newState; break; - case INIT_PATH: // act10: Initialize an object path and velocity - _vm->_object->setPath(action->a10.objIndex, (path_t) action->a10.newPathType, action->a10.vxPath, action->a10.vyPath); + case INIT_PATH: // act10: Initialize an object path and velocity + _vm->_object->setPath(action->_a10._objIndex, (Path) action->_a10._newPathType, action->_a10._vxPath, action->_a10._vyPath); break; - case COND_R: // act11: action lists conditional on object state - if (_vm->_object->_objects[action->a11.objIndex].state == action->a11.stateReq) - insertActionList(action->a11.actPassIndex); + case COND_R: // act11: action lists conditional on object state + if (_vm->_object->_objects[action->_a11._objIndex]._state == action->_a11._stateReq) + insertActionList(action->_a11._actPassIndex); else - insertActionList(action->a11.actFailIndex); + insertActionList(action->_a11._actFailIndex); break; - case TEXT: // act12: Text box (CF WARN) - Utils::notifyBox(_vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file + case TEXT: // act12: Text box (CF WARN) + Utils::notifyBox(_vm->_file->fetchString(action->_a12._stringIndex)); // Fetch string from file break; - case SWAP_IMAGES: // act13: Swap 2 object images - _vm->_object->swapImages(action->a13.objIndex1, action->a13.objIndex2); + case SWAP_IMAGES: // act13: Swap 2 object images + _vm->_object->swapImages(action->_a13._objIndex1, action->_a13._objIndex2); break; - case COND_SCR: // act14: Conditional on current screen - if (_vm->_object->_objects[action->a14.objIndex].screenIndex == action->a14.screenReq) - insertActionList(action->a14.actPassIndex); + case COND_SCR: // act14: Conditional on current screen + if (_vm->_object->_objects[action->_a14._objIndex]._screenIndex == action->_a14._screenReq) + insertActionList(action->_a14._actPassIndex); else - insertActionList(action->a14.actFailIndex); + insertActionList(action->_a14._actFailIndex); break; - case AUTOPILOT: // act15: Home in on a (stationary) object - _vm->_object->homeIn(action->a15.objIndex1, action->a15.objIndex2, action->a15.dx, action->a15.dy); + case AUTOPILOT: // act15: Home in on a (stationary) object + _vm->_object->homeIn(action->_a15._objIndex1, action->_a15._objIndex2, action->_a15._dx, action->_a15._dy); break; - case INIT_OBJ_SEQ: // act16: Set sequence number to use + case INIT_OBJ_SEQ: // act16: Set sequence number to use // Note: Don't set a sequence at time 0 of a new screen, it causes // problems clearing the boundary bits of the object! t>0 is safe - _vm->_object->_objects[action->a16.objIndex].currImagePtr = _vm->_object->_objects[action->a16.objIndex].seqList[action->a16.seqIndex].seqPtr; + _vm->_object->_objects[action->_a16._objIndex]._currImagePtr = _vm->_object->_objects[action->_a16._objIndex]._seqList[action->_a16._seqIndex]._seqPtr; break; - case SET_STATE_BITS: // act17: OR mask with curr obj state - _vm->_object->_objects[action->a17.objIndex].state |= action->a17.stateMask; + case SET_STATE_BITS: // act17: OR mask with curr obj state + _vm->_object->_objects[action->_a17._objIndex]._state |= action->_a17._stateMask; break; - case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state - _vm->_object->_objects[action->a18.objIndex].state &= ~action->a18.stateMask; + case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state + _vm->_object->_objects[action->_a18._objIndex]._state &= ~action->_a18._stateMask; break; - case TEST_STATE_BITS: // act19: If all bits set, do apass else afail - if ((_vm->_object->_objects[action->a19.objIndex].state & action->a19.stateMask) == action->a19.stateMask) - insertActionList(action->a19.actPassIndex); + case TEST_STATE_BITS: // act19: If all bits set, do apass else afail + if ((_vm->_object->_objects[action->_a19._objIndex]._state & action->_a19._stateMask) == action->_a19._stateMask) + insertActionList(action->_a19._actPassIndex); else - insertActionList(action->a19.actFailIndex); + insertActionList(action->_a19._actFailIndex); break; - case DEL_EVENTS: // act20: Remove all events of this action type - delEventType(action->a20.actTypeDel); + case DEL_EVENTS: // act20: Remove all events of this action type + delEventType(action->_a20._actTypeDel); break; - case GAMEOVER: // act21: Game over! + case GAMEOVER: // act21: Game over! // NOTE: Must wait at least 1 tick before issuing this action if // any objects are to be made invisible! - gameStatus.gameOverFl = true; + gameStatus._gameOverFl = true; break; - case INIT_HH_COORD: // act22: Initialize an object to hero's actual coords - _vm->_object->_objects[action->a22.objIndex].x = _vm->_hero->x; - _vm->_object->_objects[action->a22.objIndex].y = _vm->_hero->y; - _vm->_object->_objects[action->a22.objIndex].screenIndex = *_vm->_screen_p;// Don't forget screen! + case INIT_HH_COORD: // act22: Initialize an object to hero's actual coords + _vm->_object->_objects[action->_a22._objIndex]._x = _vm->_hero->_x; + _vm->_object->_objects[action->_a22._objIndex]._y = _vm->_hero->_y; + _vm->_object->_objects[action->_a22._objIndex]._screenIndex = *_vm->_screenPtr;// Don't forget screen! break; - case EXIT: // act23: Exit game back to DOS + case EXIT: // act23: Exit game back to DOS _vm->endGame(); break; - case BONUS: // act24: Get bonus score for action - processBonus(action->a24.pointIndex); + case BONUS: // act24: Get bonus score for action + processBonus(action->_a24._pointIndex); break; - case COND_BOX: // act25: Conditional on bounding box - obj1 = &_vm->_object->_objects[action->a25.objIndex]; - dx = obj1->x + obj1->currImagePtr->x1; - dy = obj1->y + obj1->currImagePtr->y2; - if ((dx >= action->a25.x1) && (dx <= action->a25.x2) && - (dy >= action->a25.y1) && (dy <= action->a25.y2)) - insertActionList(action->a25.actPassIndex); + case COND_BOX: // act25: Conditional on bounding box + obj1 = &_vm->_object->_objects[action->_a25._objIndex]; + dx = obj1->_x + obj1->_currImagePtr->_x1; + dy = obj1->_y + obj1->_currImagePtr->_y2; + if ((dx >= action->_a25._x1) && (dx <= action->_a25._x2) && + (dy >= action->_a25._y1) && (dy <= action->_a25._y2)) + insertActionList(action->_a25._actPassIndex); else - insertActionList(action->a25.actFailIndex); + insertActionList(action->_a25._actFailIndex); break; - case SOUND: // act26: Play a sound (or tune) - if (action->a26.soundIndex < _vm->_tunesNbr) - _vm->_sound->playMusic(action->a26.soundIndex); + case SOUND: // act26: Play a sound (or tune) + if (action->_a26._soundIndex < _vm->_tunesNbr) + _vm->_sound->playMusic(action->_a26._soundIndex); else - _vm->_sound->playSound(action->a26.soundIndex, kSoundPriorityMedium); + _vm->_sound->playSound(action->_a26._soundIndex, kSoundPriorityMedium); break; - case ADD_SCORE: // act27: Add object's value to score - _vm->adjustScore(_vm->_object->_objects[action->a27.objIndex].objValue); + case ADD_SCORE: // act27: Add object's value to score + _vm->adjustScore(_vm->_object->_objects[action->_a27._objIndex]._objValue); break; - case SUB_SCORE: // act28: Subtract object's value from score - _vm->adjustScore(-_vm->_object->_objects[action->a28.objIndex].objValue); + case SUB_SCORE: // act28: Subtract object's value from score + _vm->adjustScore(-_vm->_object->_objects[action->_a28._objIndex]._objValue); break; - case COND_CARRY: // act29: Conditional on object being carried - if (_vm->_object->isCarried(action->a29.objIndex)) - insertActionList(action->a29.actPassIndex); + case COND_CARRY: // act29: Conditional on object being carried + if (_vm->_object->isCarried(action->_a29._objIndex)) + insertActionList(action->_a29._actPassIndex); else - insertActionList(action->a29.actFailIndex); - break; - case INIT_MAZE: // act30: Enable and init maze structure - _vm->_maze.enabledFl = true; - _vm->_maze.size = action->a30.mazeSize; - _vm->_maze.x1 = action->a30.x1; - _vm->_maze.y1 = action->a30.y1; - _vm->_maze.x2 = action->a30.x2; - _vm->_maze.y2 = action->a30.y2; - _vm->_maze.x3 = action->a30.x3; - _vm->_maze.x4 = action->a30.x4; - _vm->_maze.firstScreenIndex = action->a30.firstScreenIndex; - break; - case EXIT_MAZE: // act31: Disable maze mode - _vm->_maze.enabledFl = false; + insertActionList(action->_a29._actFailIndex); + break; + case INIT_MAZE: // act30: Enable and init maze structure + _vm->_maze._enabledFl = true; + _vm->_maze._size = action->_a30._mazeSize; + _vm->_maze._x1 = action->_a30._x1; + _vm->_maze._y1 = action->_a30._y1; + _vm->_maze._x2 = action->_a30._x2; + _vm->_maze._y2 = action->_a30._y2; + _vm->_maze._x3 = action->_a30._x3; + _vm->_maze._x4 = action->_a30._x4; + _vm->_maze._firstScreenIndex = action->_a30._firstScreenIndex; + break; + case EXIT_MAZE: // act31: Disable maze mode + _vm->_maze._enabledFl = false; break; case INIT_PRIORITY: - _vm->_object->_objects[action->a32.objIndex].priority = action->a32.priority; + _vm->_object->_objects[action->_a32._objIndex]._priority = action->_a32._priority; break; case INIT_SCREEN: - _vm->_object->_objects[action->a33.objIndex].screenIndex = action->a33.screenIndex; + _vm->_object->_objects[action->_a33._objIndex]._screenIndex = action->_a33._screenIndex; break; - case AGSCHEDULE: // act34: Schedule a (global) action list - insertActionList(action->a34.actIndex); + case AGSCHEDULE: // act34: Schedule a (global) action list + insertActionList(action->_a34._actIndex); break; - case REMAPPAL: // act35: Remap a palette color - _vm->_screen->remapPal(action->a35.oldColorIndex, action->a35.newColorIndex); + case REMAPPAL: // act35: Remap a palette color + _vm->_screen->remapPal(action->_a35._oldColorIndex, action->_a35._newColorIndex); break; - case COND_NOUN: // act36: Conditional on noun mentioned - if (_vm->_parser->isWordPresent(_vm->_text->getNounArray(action->a36.nounIndex))) - insertActionList(action->a36.actPassIndex); + case COND_NOUN: // act36: Conditional on noun mentioned + if (_vm->_parser->isWordPresent(_vm->_text->getNounArray(action->_a36._nounIndex))) + insertActionList(action->_a36._actPassIndex); else - insertActionList(action->a36.actFailIndex); + insertActionList(action->_a36._actFailIndex); break; - case SCREEN_STATE: // act37: Set new screen state - _vm->_screenStates[action->a37.screenIndex] = action->a37.newState; + case SCREEN_STATE: // act37: Set new screen state + _vm->_screenStates[action->_a37._screenIndex] = action->_a37._newState; break; - case INIT_LIPS: // act38: Position lips on object - _vm->_object->_objects[action->a38.lipsObjIndex].x = _vm->_object->_objects[action->a38.objIndex].x + action->a38.dxLips; - _vm->_object->_objects[action->a38.lipsObjIndex].y = _vm->_object->_objects[action->a38.objIndex].y + action->a38.dyLips; - _vm->_object->_objects[action->a38.lipsObjIndex].screenIndex = *_vm->_screen_p; // Don't forget screen! - _vm->_object->_objects[action->a38.lipsObjIndex].cycling = kCycleForward; + case INIT_LIPS: // act38: Position lips on object + _vm->_object->_objects[action->_a38._lipsObjIndex]._x = _vm->_object->_objects[action->_a38._objIndex]._x + action->_a38._dxLips; + _vm->_object->_objects[action->_a38._lipsObjIndex]._y = _vm->_object->_objects[action->_a38._objIndex]._y + action->_a38._dyLips; + _vm->_object->_objects[action->_a38._lipsObjIndex]._screenIndex = *_vm->_screenPtr; // Don't forget screen! + _vm->_object->_objects[action->_a38._lipsObjIndex]._cycling = kCycleForward; break; - case INIT_STORY_MODE: // act39: Init story_mode flag + case INIT_STORY_MODE: // act39: Init story_mode flag // This is similar to the QUIET path mode, except that it is // independant of it and it additionally disables the ">" prompt - gameStatus.storyModeFl = action->a39.storyModeFl; + gameStatus._storyModeFl = action->_a39._storyModeFl; break; - case WARN: // act40: Text box (CF TEXT) - Utils::notifyBox(_vm->_file->fetchString(action->a40.stringIndex)); + case WARN: // act40: Text box (CF TEXT) + Utils::notifyBox(_vm->_file->fetchString(action->_a40._stringIndex)); break; - case COND_BONUS: // act41: Perform action if got bonus - if (_points[action->a41.BonusIndex].scoredFl) - insertActionList(action->a41.actPassIndex); + case COND_BONUS: // act41: Perform action if got bonus + if (_points[action->_a41._bonusIndex]._scoredFl) + insertActionList(action->_a41._actPassIndex); else - insertActionList(action->a41.actFailIndex); + insertActionList(action->_a41._actFailIndex); break; - case TEXT_TAKE: // act42: Text box with "take" message - Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(_vm->_object->_objects[action->a42.objIndex].nounIndex, TAKE_NAME))); + case TEXT_TAKE: // act42: Text box with "take" message + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(_vm->_object->_objects[action->_a42._objIndex]._nounIndex, TAKE_NAME))); break; - case YESNO: // act43: Prompt user for Yes or No - if (Utils::yesNoBox(_vm->_file->fetchString(action->a43.promptIndex))) - insertActionList(action->a43.actYesIndex); + case YESNO: // act43: Prompt user for Yes or No + if (Utils::yesNoBox(_vm->_file->fetchString(action->_a43._promptIndex))) + insertActionList(action->_a43._actYesIndex); else - insertActionList(action->a43.actNoIndex); + insertActionList(action->_a43._actNoIndex); break; - case STOP_ROUTE: // act44: Stop any route in progress + case STOP_ROUTE: // act44: Stop any route in progress _vm->_route->resetRoute(); break; - case COND_ROUTE: // act45: Conditional on route in progress - if (_vm->_route->getRouteIndex() >= action->a45.routeIndex) - insertActionList(action->a45.actPassIndex); + case COND_ROUTE: // act45: Conditional on route in progress + if (_vm->_route->getRouteIndex() >= action->_a45._routeIndex) + insertActionList(action->_a45._actPassIndex); else - insertActionList(action->a45.actFailIndex); + insertActionList(action->_a45._actFailIndex); break; - case INIT_JUMPEXIT: // act46: Init status.jumpexit flag + case INIT_JUMPEXIT: // act46: Init status.jumpexit flag // This is to allow left click on exit to get there immediately // For example the plane crash in Hugo2 where hero is invisible // Couldn't use INVISIBLE flag since conflicts with boat in Hugo1 - _vm->_mouse->setJumpExitFl(action->a46.jumpExitFl); + _vm->_mouse->setJumpExitFl(action->_a46._jumpExitFl); break; - case INIT_VIEW: // act47: Init object.viewx, viewy, dir - _vm->_object->_objects[action->a47.objIndex].viewx = action->a47.viewx; - _vm->_object->_objects[action->a47.objIndex].viewy = action->a47.viewy; - _vm->_object->_objects[action->a47.objIndex].direction = action->a47.direction; + case INIT_VIEW: // act47: Init object._viewx, viewy, dir + _vm->_object->_objects[action->_a47._objIndex]._viewx = action->_a47._viewx; + _vm->_object->_objects[action->_a47._objIndex]._viewy = action->_a47._viewy; + _vm->_object->_objects[action->_a47._objIndex]._direction = action->_a47._direction; break; - case INIT_OBJ_FRAME: // act48: Set seq,frame number to use + case INIT_OBJ_FRAME: // act48: Set seq,frame number to use // Note: Don't set a sequence at time 0 of a new screen, it causes // problems clearing the boundary bits of the object! t>0 is safe - _vm->_object->_objects[action->a48.objIndex].currImagePtr = _vm->_object->_objects[action->a48.objIndex].seqList[action->a48.seqIndex].seqPtr; - for (dx = 0; dx < action->a48.frameIndex; dx++) - _vm->_object->_objects[action->a48.objIndex].currImagePtr = _vm->_object->_objects[action->a48.objIndex].currImagePtr->nextSeqPtr; + _vm->_object->_objects[action->_a48._objIndex]._currImagePtr = _vm->_object->_objects[action->_a48._objIndex]._seqList[action->_a48._seqIndex]._seqPtr; + for (dx = 0; dx < action->_a48._frameIndex; dx++) + _vm->_object->_objects[action->_a48._objIndex]._currImagePtr = _vm->_object->_objects[action->_a48._objIndex]._currImagePtr->_nextSeqPtr; break; case OLD_SONG: // Replaces ACT26 for DOS games. - _vm->_sound->_DOSSongPtr = _vm->_text->getTextData(action->a49.songIndex); + _vm->_sound->_DOSSongPtr = _vm->_text->getTextData(action->_a49._songIndex); break; default: error("An error has occurred: %s", "doAction"); break; } - if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list - return 0; // next_p = 0 since list now empty + if (action->_a0._actType == NEW_SCREEN) { // New_screen() deletes entire list + return 0; // nextEvent = 0 since list now empty } else { - wrkEvent = curEvent->nextEvent; - delQueue(curEvent); // Return event to free list - return wrkEvent; // Return next event ptr + wrkEvent = curEvent->_nextEvent; + delQueue(curEvent); // Return event to free list + return wrkEvent; // Return next event ptr } } @@ -1441,41 +1441,41 @@ event_t *Scheduler::doAction(event_t *curEvent) { * was modified to allow deletes anywhere in the list, and the DEL_EVENT * action was modified to perform the actual delete. */ -void Scheduler::delQueue(event_t *curEvent) { +void Scheduler::delQueue(Event *curEvent) { debugC(4, kDebugSchedule, "delQueue()"); - if (curEvent == _headEvent) { // If p was the head ptr - _headEvent = curEvent->nextEvent; // then make new head_p - } else { // Unlink p - curEvent->prevEvent->nextEvent = curEvent->nextEvent; - if (curEvent->nextEvent) - curEvent->nextEvent->prevEvent = curEvent->prevEvent; + if (curEvent == _headEvent) { // If p was the head ptr + _headEvent = curEvent->_nextEvent; // then make new head_p + } else { // Unlink p + curEvent->_prevEvent->_nextEvent = curEvent->_nextEvent; + if (curEvent->_nextEvent) + curEvent->_nextEvent->_prevEvent = curEvent->_prevEvent; else - _tailEvent = curEvent->prevEvent; + _tailEvent = curEvent->_prevEvent; } if (_headEvent) - _headEvent->prevEvent = 0; // Mark end of list + _headEvent->_prevEvent = 0; // Mark end of list else - _tailEvent = 0; // Empty queue + _tailEvent = 0; // Empty queue - curEvent->nextEvent = _freeEvent; // Return p to free list - if (_freeEvent) // Special case, if free list was empty - _freeEvent->prevEvent = curEvent; + curEvent->_nextEvent = _freeEvent; // Return p to free list + if (_freeEvent) // Special case, if free list was empty + _freeEvent->_prevEvent = curEvent; _freeEvent = curEvent; } /** * Delete all the active events of a given type */ -void Scheduler::delEventType(const action_t actTypeDel) { +void Scheduler::delEventType(const Action _actTypeDel) { // Note: actions are not deleted here, simply turned into NOPs! - event_t *wrkEvent = _headEvent; // The earliest event - event_t *saveEvent; + Event *wrkEvent = _headEvent; // The earliest event + Event *saveEvent; - while (wrkEvent) { // While events found in list - saveEvent = wrkEvent->nextEvent; - if (wrkEvent->action->a20.actType == actTypeDel) + while (wrkEvent) { // While events found in list + saveEvent = wrkEvent->_nextEvent; + if (wrkEvent->_action->_a20._actType == _actTypeDel) delQueue(wrkEvent); wrkEvent = saveEvent; } @@ -1486,8 +1486,8 @@ void Scheduler::delEventType(const action_t actTypeDel) { */ void Scheduler::savePoints(Common::WriteStream *out) const { for (int i = 0; i < _numBonuses; i++) { - out->writeByte(_points[i].score); - out->writeByte((_points[i].scoredFl) ? 1 : 0); + out->writeByte(_points[i]._score); + out->writeByte((_points[i]._scoredFl) ? 1 : 0); } } @@ -1497,8 +1497,8 @@ void Scheduler::savePoints(Common::WriteStream *out) const { void Scheduler::restorePoints(Common::ReadStream *in) { // Restore points table for (int i = 0; i < _numBonuses; i++) { - _points[i].score = in->readByte(); - _points[i].scoredFl = (in->readByte() == 1); + _points[i]._score = in->readByte(); + _points[i]._scoredFl = (in->readByte() == 1); } } @@ -1524,30 +1524,30 @@ uint32 Scheduler_v1d::getTicks() { void Scheduler_v1d::runScheduler() { debugC(6, kDebugSchedule, "runScheduler"); - uint32 ticker = getTicks(); // The time now, in ticks - event_t *curEvent = _headEvent; // The earliest event + uint32 ticker = getTicks(); // The time now, in ticks + Event *curEvent = _headEvent; // The earliest event - while (curEvent && (curEvent->time <= ticker)) // While mature events found - curEvent = doAction(curEvent); // Perform the action (returns next_p) + while (curEvent && (curEvent->_time <= ticker)) // While mature events found + curEvent = doAction(curEvent); // Perform the action (returns nextEvent) } -void Scheduler_v1d::promptAction(act *action) { +void Scheduler_v1d::promptAction(Act *action) { Common::String response; - response = Utils::promptBox(_vm->_file->fetchString(action->a3.promptIndex)); + response = Utils::promptBox(_vm->_file->fetchString(action->_a3._promptIndex)); response.toLowercase(); char resp[256]; Common::strlcpy(resp, response.c_str(), 256); - if (action->a3.encodedFl) + if (action->_a3._encodedFl) decodeString(resp); - if (strstr(resp, _vm->_file->fetchString(action->a3.responsePtr[0]))) - insertActionList(action->a3.actPassIndex); + if (strstr(resp, _vm->_file->fetchString(action->_a3._responsePtr[0]))) + insertActionList(action->_a3._actPassIndex); else - insertActionList(action->a3.actFailIndex); + insertActionList(action->_a3._actFailIndex); } /** @@ -1574,27 +1574,27 @@ const char *Scheduler_v2d::getCypher() const { return "Copyright 1991, Gray Design Associates"; } -void Scheduler_v2d::promptAction(act *action) { +void Scheduler_v2d::promptAction(Act *action) { Common::String response; - response = Utils::promptBox(_vm->_file->fetchString(action->a3.promptIndex)); + response = Utils::promptBox(_vm->_file->fetchString(action->_a3._promptIndex)); response.toLowercase(); - debug(1, "doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0])); + debug(1, "doAction(act3), expecting answer %s", _vm->_file->fetchString(action->_a3._responsePtr[0])); bool found = false; - const char *tmpStr; // General purpose string ptr + const char *tmpStr; // General purpose string ptr - for (int dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) { - tmpStr = _vm->_file->fetchString(action->a3.responsePtr[dx]); + for (int dx = 0; !found && (action->_a3._responsePtr[dx] != -1); dx++) { + tmpStr = _vm->_file->fetchString(action->_a3._responsePtr[dx]); if (response.contains(tmpStr)) found = true; } if (found) - insertActionList(action->a3.actPassIndex); + insertActionList(action->_a3._actPassIndex); else - insertActionList(action->a3.actFailIndex); + insertActionList(action->_a3._actFailIndex); } /** @@ -1638,12 +1638,12 @@ uint32 Scheduler_v1w::getTicks() { void Scheduler_v1w::runScheduler() { debugC(6, kDebugSchedule, "runScheduler"); - uint32 ticker = getTicks(); // The time now, in ticks - event_t *curEvent = _headEvent; // The earliest event + uint32 ticker = getTicks(); // The time now, in ticks + Event *curEvent = _headEvent; // The earliest event - while (curEvent && (curEvent->time <= ticker)) // While mature events found - curEvent = doAction(curEvent); // Perform the action (returns next_p) + while (curEvent && (curEvent->_time <= ticker)) // While mature events found + curEvent = doAction(curEvent); // Perform the action (returns nextEvent) - _vm->getGameStatus().tick++; // Accessed elsewhere via getTicks() + _vm->getGameStatus()._tick++; // Accessed elsewhere via getTicks() } } // End of namespace Hugo diff --git a/engines/hugo/schedule.h b/engines/hugo/schedule.h index 60d51f0673..37851f1ebc 100644 --- a/engines/hugo/schedule.h +++ b/engines/hugo/schedule.h @@ -37,7 +37,7 @@ namespace Hugo { /** * Following defines the action types and action list */ -enum action_t { // Parameters: +enum Action { // Parameters: ANULL = 0xff, // Special NOP used to 'delete' events in DEL_EVENTS ASCHEDULE = 0, // 0 - Ptr to action list to be rescheduled START_OBJ, // 1 - Object number @@ -56,7 +56,7 @@ enum action_t { // Parameters: SWAP_IMAGES, // 13 - Swap 2 object images COND_SCR, // 14 - Conditional on current screen AUTOPILOT, // 15 - Set object to home in on another (stationary) object - INIT_OBJ_SEQ, // 16 - Object number, sequence index to set curr_seq_p to + INIT_OBJ_SEQ, // 16 - Object number, sequence index to set curr_seqPtr to SET_STATE_BITS, // 17 - Objnum, mask to OR with obj states word CLEAR_STATE_BITS, // 18 - Objnum, mask to ~AND with obj states word TEST_STATE_BITS, // 19 - Objnum, mask to test obj states word @@ -88,429 +88,430 @@ enum action_t { // Parameters: COND_ROUTE, // 45 - Conditional on route in progress INIT_JUMPEXIT, // 46 - Initialize status.jumpexit INIT_VIEW, // 47 - Initialize viewx, viewy, dir - INIT_OBJ_FRAME, // 48 - Object number, seq,frame to set curr_seq_p to + INIT_OBJ_FRAME, // 48 - Object number, seq,frame to set curr_seqPtr to OLD_SONG = 49 // Added by Strangerke - Set currently playing sound, old way: that is, using a string index instead of a reference in a file }; struct act0 { // Type 0 - Schedule - action_t actType; // The type of action - int timer; // Time to set off the action - uint16 actIndex; // Ptr to an action list + Action _actType; // The type of action + int _timer; // Time to set off the action + uint16 _actIndex; // Ptr to an action list }; struct act1 { // Type 1 - Start an object - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int cycleNumb; // Number of times to cycle - cycle_t cycle; // Direction to start cycling + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _cycleNumb; // Number of times to cycle + Cycle _cycle; // Direction to start cycling }; struct act2 { // Type 2 - Initialize an object coords - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int x, y; // Coordinates + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _x, _y; // Coordinates }; struct act3 { // Type 3 - Prompt user for text - action_t actType; // The type of action - int timer; // Time to set off the action - uint16 promptIndex; // Index of prompt string - int *responsePtr; // Array of indexes to valid response string(s) (terminate list with -1) - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure - bool encodedFl; // (HUGO 1 DOS ONLY) Whether response is encoded or not + Action _actType; // The type of action + int _timer; // Time to set off the action + uint16 _promptIndex; // Index of prompt string + int *_responsePtr; // Array of indexes to valid response string(s) (terminate list with -1) + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure + bool _encodedFl; // (HUGO 1 DOS ONLY) Whether response is encoded or not }; struct act4 { // Type 4 - Set new background color - action_t actType; // The type of action - int timer; // Time to set off the action - long newBackgroundColor; // New color + Action _actType; // The type of action + int _timer; // Time to set off the action + long _newBackgroundColor; // New color }; struct act5 { // Type 5 - Initialize an object velocity - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int vx, vy; // velocity + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _vx, _vy; // velocity }; struct act6 { // Type 6 - Initialize an object carrying - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - bool carriedFl; // carrying + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + bool _carriedFl; // carrying }; struct act7 { // Type 7 - Initialize an object to hero's coords - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number }; struct act8 { // Type 8 - switch to new screen - action_t actType; // The type of action - int timer; // Time to set off the action - int screenIndex; // The new screen number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _screenIndex; // The new screen number }; struct act9 { // Type 9 - Initialize an object state - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - byte newState; // New state + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + byte _newState; // New state }; struct act10 { // Type 10 - Initialize an object path type - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int newPathType; // New path type - int8 vxPath, vyPath; // Max delta velocities e.g. for CHASE + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _newPathType; // New path type + int8 _vxPath, _vyPath; // Max delta velocities e.g. for CHASE }; struct act11 { // Type 11 - Conditional on object's state - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - byte stateReq; // Required state - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + byte _stateReq; // Required state + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure }; struct act12 { // Type 12 - Simple text box - action_t actType; // The type of action - int timer; // Time to set off the action - int stringIndex; // Index (enum) of string in strings.dat + Action _actType; // The type of action + int _timer; // Time to set off the action + int _stringIndex; // Index (enum) of string in strings.dat }; struct act13 { // Type 13 - Swap first object image with second - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex1; // Index of first object - int objIndex2; // 2nd + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex1; // Index of first object + int _objIndex2; // 2nd }; struct act14 { // Type 14 - Conditional on current screen - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The required object - int screenReq; // The required screen number - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The required object + int _screenReq; // The required screen number + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure }; struct act15 { // Type 15 - Home in on an object - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex1; // The object number homing in - int objIndex2; // The object number to home in on - int8 dx, dy; // Max delta velocities + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex1; // The object number homing in + int _objIndex2; // The object number to home in on + int8 _dx, _dy; // Max delta velocities }; + // Note: Don't set a sequence at time 0 of a new screen, it causes // problems clearing the boundary bits of the object! timer > 0 is safe -struct act16 { // Type 16 - Set curr_seq_p to seq - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int seqIndex; // The index of seq array to set to +struct act16 { // Type 16 - Set curr_seqPtr to seq + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _seqIndex; // The index of seq array to set to }; struct act17 { // Type 17 - SET obj individual state bits - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int stateMask; // The mask to OR with current obj state + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _stateMask; // The mask to OR with current obj state }; struct act18 { // Type 18 - CLEAR obj individual state bits - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int stateMask; // The mask to ~AND with current obj state + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _stateMask; // The mask to ~AND with current obj state }; struct act19 { // Type 19 - TEST obj individual state bits - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int stateMask; // The mask to AND with current obj state - uint16 actPassIndex; // Ptr to action list (all bits set) - uint16 actFailIndex; // Ptr to action list (not all set) + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _stateMask; // The mask to AND with current obj state + uint16 _actPassIndex; // Ptr to action list (all bits set) + uint16 _actFailIndex; // Ptr to action list (not all set) }; struct act20 { // Type 20 - Remove all events with this type of action - action_t actType; // The type of action - int timer; // Time to set off the action - action_t actTypeDel; // The action type to remove + Action _actType; // The type of action + int _timer; // Time to set off the action + Action _actTypeDel; // The action type to remove }; struct act21 { // Type 21 - Gameover. Disable hero & commands - action_t actType; // The type of action - int timer; // Time to set off the action + Action _actType; // The type of action + int _timer; // Time to set off the action }; struct act22 { // Type 22 - Initialize an object to hero's coords - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number }; struct act23 { // Type 23 - Exit game back to DOS - action_t actType; // The type of action - int timer; // Time to set off the action + Action _actType; // The type of action + int _timer; // Time to set off the action }; struct act24 { // Type 24 - Get bonus score - action_t actType; // The type of action - int timer; // Time to set off the action - int pointIndex; // Index into points array + Action _actType; // The type of action + int _timer; // Time to set off the action + int _pointIndex; // Index into points array }; struct act25 { // Type 25 - Conditional on bounding box - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The required object number - int x1, y1, x2, y2; // The bounding box - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The required object number + int _x1, _y1, _x2, _y2; // The bounding box + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure }; struct act26 { // Type 26 - Play a sound - action_t actType; // The type of action - int timer; // Time to set off the action - int16 soundIndex; // Sound index in data file + Action _actType; // The type of action + int _timer; // Time to set off the action + int16 _soundIndex; // Sound index in data file }; struct act27 { // Type 27 - Add object's value to score - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // object number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // object number }; struct act28 { // Type 28 - Subtract object's value from score - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // object number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // object number }; struct act29 { // Type 29 - Conditional on object carried - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The required object number - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The required object number + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure }; struct act30 { // Type 30 - Start special maze processing - action_t actType; // The type of action - int timer; // Time to set off the action - byte mazeSize; // Size of (square) maze - int x1, y1, x2, y2; // Bounding box of maze - int x3, x4; // Extra x points for perspective correction - byte firstScreenIndex; // First (top left) screen of maze + Action _actType; // The type of action + int _timer; // Time to set off the action + byte _mazeSize; // Size of (square) maze + int _x1, _y1, _x2, _y2; // Bounding box of maze + int _x3, _x4; // Extra x points for perspective correction + byte _firstScreenIndex; // First (top left) screen of maze }; struct act31 { // Type 31 - Exit special maze processing - action_t actType; // The type of action - int timer; // Time to set off the action + Action _actType; // The type of action + int _timer; // Time to set off the action }; struct act32 { // Type 32 - Init fbg field of object - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - byte priority; // Value of foreground/background field + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + byte _priority; // Value of foreground/background field }; struct act33 { // Type 33 - Init screen field of object - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int screenIndex; // Screen number + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _screenIndex; // Screen number }; struct act34 { // Type 34 - Global Schedule - action_t actType; // The type of action - int timer; // Time to set off the action - uint16 actIndex; // Ptr to an action list + Action _actType; // The type of action + int _timer; // Time to set off the action + uint16 _actIndex; // Ptr to an action list }; struct act35 { // Type 35 - Remappe palette - action_t actType; // The type of action - int timer; // Time to set off the action - int16 oldColorIndex; // Old color index, 0..15 - int16 newColorIndex; // New color index, 0..15 + Action _actType; // The type of action + int _timer; // Time to set off the action + int16 _oldColorIndex; // Old color index, 0..15 + int16 _newColorIndex; // New color index, 0..15 }; struct act36 { // Type 36 - Conditional on noun mentioned - action_t actType; // The type of action - int timer; // Time to set off the action - uint16 nounIndex; // The required noun (list) - uint16 actPassIndex; // Ptr to action list if success - uint16 actFailIndex; // Ptr to action list if failure + Action _actType; // The type of action + int _timer; // Time to set off the action + uint16 _nounIndex; // The required noun (list) + uint16 _actPassIndex; // Ptr to action list if success + uint16 _actFailIndex; // Ptr to action list if failure }; struct act37 { // Type 37 - Set new screen state - action_t actType; // The type of action - int timer; // Time to set off the action - int screenIndex; // The screen number - byte newState; // The new state + Action _actType; // The type of action + int _timer; // Time to set off the action + int _screenIndex; // The screen number + byte _newState; // The new state }; struct act38 { // Type 38 - Position lips - action_t actType; // The type of action - int timer; // Time to set off the action - int lipsObjIndex; // The LIPS object - int objIndex; // The object to speak - byte dxLips; // Relative offset of x - byte dyLips; // Relative offset of y + Action _actType; // The type of action + int _timer; // Time to set off the action + int _lipsObjIndex; // The LIPS object + int _objIndex; // The object to speak + byte _dxLips; // Relative offset of x + byte _dyLips; // Relative offset of y }; struct act39 { // Type 39 - Init story mode - action_t actType; // The type of action - int timer; // Time to set off the action - bool storyModeFl; // New state of story_mode flag + Action _actType; // The type of action + int _timer; // Time to set off the action + bool _storyModeFl; // New state of story_mode flag }; struct act40 { // Type 40 - Unsolicited text box - action_t actType; // The type of action - int timer; // Time to set off the action - int stringIndex; // Index (enum) of string in strings.dat + Action _actType; // The type of action + int _timer; // Time to set off the action + int _stringIndex; // Index (enum) of string in strings.dat }; struct act41 { // Type 41 - Conditional on bonus scored - action_t actType; // The type of action - int timer; // Time to set off the action - int BonusIndex; // Index into bonus list - uint16 actPassIndex; // Index of the action list if scored for the first time - uint16 actFailIndex; // Index of the action list if already scored + Action _actType; // The type of action + int _timer; // Time to set off the action + int _bonusIndex; // Index into bonus list + uint16 _actPassIndex; // Index of the action list if scored for the first time + uint16 _actFailIndex; // Index of the action list if already scored }; struct act42 { // Type 42 - Text box with "take" string - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object taken + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object taken }; struct act43 { // Type 43 - Prompt user for Yes or No - action_t actType; // The type of action - int timer; // Time to set off the action - int promptIndex; // index of prompt string - uint16 actYesIndex; // Ptr to action list if YES - uint16 actNoIndex; // Ptr to action list if NO + Action _actType; // The type of action + int _timer; // Time to set off the action + int _promptIndex; // index of prompt string + uint16 _actYesIndex; // Ptr to action list if YES + uint16 _actNoIndex; // Ptr to action list if NO }; struct act44 { // Type 44 - Stop any route in progress - action_t actType; // The type of action - int timer; // Time to set off the action + Action _actType; // The type of action + int _timer; // Time to set off the action }; struct act45 { // Type 45 - Conditional on route in progress - action_t actType; // The type of action - int timer; // Time to set off the action - int routeIndex; // Must be >= current status.rindex - uint16 actPassIndex; // Ptr to action list if en-route - uint16 actFailIndex; // Ptr to action list if not + Action _actType; // The type of action + int _timer; // Time to set off the action + int _routeIndex; // Must be >= current status.rindex + uint16 _actPassIndex; // Ptr to action list if en-route + uint16 _actFailIndex; // Ptr to action list if not }; struct act46 { // Type 46 - Init status.jumpexit - action_t actType; // The type of action - int timer; // Time to set off the action - bool jumpExitFl; // New state of jumpexit flag + Action _actType; // The type of action + int _timer; // Time to set off the action + bool _jumpExitFl; // New state of jumpexit flag }; struct act47 { // Type 47 - Init viewx,viewy,dir - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object - int16 viewx; // object.viewx - int16 viewy; // object.viewy - int16 direction; // object.dir -}; - -struct act48 { // Type 48 - Set curr_seq_p to frame n - action_t actType; // The type of action - int timer; // Time to set off the action - int objIndex; // The object number - int seqIndex; // The index of seq array to set to - int frameIndex; // The index of frame to set to -}; - -struct act49 { // Added by Strangerke - Type 79 - Play a song (DOS way) - action_t actType; // The type of action - int timer; // Time to set off the action - uint16 songIndex; // Song index in string array -}; - -union act { - act0 a0; - act1 a1; - act2 a2; - act3 a3; - act4 a4; - act5 a5; - act6 a6; - act7 a7; - act8 a8; - act9 a9; - act10 a10; - act11 a11; - act12 a12; - act13 a13; - act14 a14; - act15 a15; - act16 a16; - act17 a17; - act18 a18; - act19 a19; - act20 a20; - act21 a21; - act22 a22; - act23 a23; - act24 a24; - act25 a25; - act26 a26; - act27 a27; - act28 a28; - act29 a29; - act30 a30; - act31 a31; - act32 a32; - act33 a33; - act34 a34; - act35 a35; - act36 a36; - act37 a37; - act38 a38; - act39 a39; - act40 a40; - act41 a41; - act42 a42; - act43 a43; - act44 a44; - act45 a45; - act46 a46; - act47 a47; - act48 a48; - act49 a49; -}; - -struct event_t { - act *action; // Ptr to action to perform - bool localActionFl; // true if action is only for this screen - uint32 time; // (absolute) time to perform action - struct event_t *prevEvent; // Chain to previous event - struct event_t *nextEvent; // Chain to next event + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object + int16 _viewx; // object.viewx + int16 _viewy; // object.viewy + int16 _direction; // object.dir +}; + +struct act48 { // Type 48 - Set curr_seqPtr to frame n + Action _actType; // The type of action + int _timer; // Time to set off the action + int _objIndex; // The object number + int _seqIndex; // The index of seq array to set to + int _frameIndex; // The index of frame to set to +}; + +struct act49 { // Added by Strangerke - Type 49 - Play a song (DOS way) + Action _actType; // The type of action + int _timer; // Time to set off the action + uint16 _songIndex; // Song index in string array +}; + +union Act { + act0 _a0; + act1 _a1; + act2 _a2; + act3 _a3; + act4 _a4; + act5 _a5; + act6 _a6; + act7 _a7; + act8 _a8; + act9 _a9; + act10 _a10; + act11 _a11; + act12 _a12; + act13 _a13; + act14 _a14; + act15 _a15; + act16 _a16; + act17 _a17; + act18 _a18; + act19 _a19; + act20 _a20; + act21 _a21; + act22 _a22; + act23 _a23; + act24 _a24; + act25 _a25; + act26 _a26; + act27 _a27; + act28 _a28; + act29 _a29; + act30 _a30; + act31 _a31; + act32 _a32; + act33 _a33; + act34 _a34; + act35 _a35; + act36 _a36; + act37 _a37; + act38 _a38; + act39 _a39; + act40 _a40; + act41 _a41; + act42 _a42; + act43 _a43; + act44 _a44; + act45 _a45; + act46 _a46; + act47 _a47; + act48 _a48; + act49 _a49; +}; + +struct Event { + Act *_action; // Ptr to action to perform + bool _localActionFl; // true if action is only for this screen + uint32 _time; // (absolute) time to perform action + struct Event *_prevEvent; // Chain to previous event + struct Event *_nextEvent; // Chain to next event }; /** * Following are points for achieving certain actions. */ -struct point_t { - byte score; // The value of the point - bool scoredFl; // Whether scored yet +struct Point { + byte _score; // The value of the point + bool _scoredFl; // Whether scored yet }; class Scheduler { @@ -553,36 +554,36 @@ protected: uint16 **_screenActs; byte _numBonuses; - point_t *_points; + Point *_points; uint32 _curTick; // Current system time in ticks uint32 _oldTime; // The previous wall time in ticks uint32 _refreshTimeout; - event_t *_freeEvent; // Free list of event structures - event_t *_headEvent; // Head of list (earliest time) - event_t *_tailEvent; // Tail of list (latest time) - event_t _events[kMaxEvents]; // Statically declare event structures + Event *_freeEvent; // Free list of event structures + Event *_headEvent; // Head of list (earliest time) + Event *_tailEvent; // Tail of list (latest time) + Event _events[kMaxEvents]; // Statically declare event structures - act **_actListArr; + Act **_actListArr; virtual const char *getCypher() const = 0; virtual uint32 getTicks() = 0; - virtual void promptAction(act *action) = 0; + virtual void promptAction(Act *action) = 0; - event_t *doAction(event_t *curEvent); - event_t *getQueue(); + Event *doAction(Event *curEvent); + Event *getQueue(); uint32 getDosTicks(const bool updateFl); uint32 getWinTicks() const; - void delEventType(const action_t actTypeDel); - void delQueue(event_t *curEvent); - void findAction(const act* action, int16* index, int16* subElem); - void insertAction(act *action); - void readAct(Common::ReadStream &in, act &curAct); + void delEventType(const Action actTypeDel); + void delQueue(Event *curEvent); + void findAction(const Act* action, int16* index, int16* subElem); + void insertAction(Act *action); + void readAct(Common::ReadStream &in, Act &curAct); void restoreActions(Common::ReadStream *f); void restoreEvents(Common::ReadStream *f); void restorePoints(Common::ReadStream *in); @@ -604,7 +605,7 @@ public: protected: virtual const char *getCypher() const; virtual uint32 getTicks(); - virtual void promptAction(act *action); + virtual void promptAction(Act *action); }; class Scheduler_v2d : public Scheduler_v1d { @@ -617,7 +618,7 @@ public: protected: virtual const char *getCypher() const; - void promptAction(act *action); + void promptAction(Act *action); }; class Scheduler_v3d : public Scheduler_v2d { diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp index d0b4e3dfe8..aefa03cd5e 100644 --- a/engines/hugo/sound.cpp +++ b/engines/hugo/sound.cpp @@ -162,31 +162,31 @@ void SoundHandler::stopMusic() { * Turn music on and off */ void SoundHandler::toggleMusic() { - _vm->_config.musicFl = !_vm->_config.musicFl; + _vm->_config._musicFl = !_vm->_config._musicFl; - _midiPlayer->pause(!_vm->_config.musicFl); + _midiPlayer->pause(!_vm->_config._musicFl); } /** * Turn digitized sound on and off */ void SoundHandler::toggleSound() { - _vm->_config.soundFl = !_vm->_config.soundFl; + _vm->_config._soundFl = !_vm->_config._soundFl; } -void SoundHandler::playMIDI(sound_pt seq_p, uint16 size) { - _midiPlayer->play(seq_p, size); +void SoundHandler::playMIDI(SoundPtr seqPtr, uint16 size) { + _midiPlayer->play(seqPtr, size); } /** * Read a tune sequence from the sound database and start playing it */ void SoundHandler::playMusic(int16 tune) { - sound_pt seqPtr; // Sequence data from file + SoundPtr seqPtr; // Sequence data from file uint16 size; // Size of sequence data - if (_vm->_config.musicFl) { - _vm->getGameStatus().song = tune; + if (_vm->_config._musicFl) { + _vm->getGameStatus()._song = tune; seqPtr = _vm->_file->getSound(tune, &size); playMIDI(seqPtr, size); free(seqPtr); @@ -198,22 +198,22 @@ void SoundHandler::playMusic(int16 tune) { * Override currently playing sound only if lower or same priority */ void SoundHandler::playSound(int16 sound, const byte priority) { - // uint32 dwVolume; // Left, right volume of sound - sound_pt sound_p; // Sound data - uint16 size; // Size of data + // uint32 dwVolume; // Left, right volume of sound + SoundPtr soundPtr; // Sound data + uint16 size; // Size of data // Sound disabled - if (!_vm->_config.soundFl || !_vm->_mixer->isReady()) + if (!_vm->_config._soundFl || !_vm->_mixer->isReady()) return; syncVolume(); _curPriority = priority; // Get sound data - if ((sound_p = _vm->_file->getSound(sound, &size)) == 0) + if ((soundPtr = _vm->_file->getSound(sound, &size)) == 0) return; - Audio::AudioStream *stream = Audio::makeRawStream(sound_p, size, 11025, Audio::FLAG_UNSIGNED); + Audio::AudioStream *stream = Audio::makeRawStream(soundPtr, size, 11025, Audio::FLAG_UNSIGNED); _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream); } @@ -245,7 +245,7 @@ void SoundHandler::checkMusic() { return; for (int i = 0; _vm->_defltTunes[i] != -1; i++) { - if (_vm->_defltTunes[i] == _vm->getGameStatus().song) { + if (_vm->_defltTunes[i] == _vm->getGameStatus()._song) { if (_vm->_defltTunes[i + 1] != -1) playMusic(_vm->_defltTunes[i + 1]); else @@ -270,7 +270,7 @@ void SoundHandler::pcspkr_player() { static const uint16 pcspkrFlats[8] = {1435, 1279, 2342, 2150, 1916, 1755, 1611}; // The flats, Ab to Bb // Does the user not want any sound? - if (!_vm->_config.soundFl || !_vm->_mixer->isReady()) + if (!_vm->_config._soundFl || !_vm->_mixer->isReady()) return; // Is there no song? diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h index cb6d4e3168..b00d93eeb1 100644 --- a/engines/hugo/sound.h +++ b/engines/hugo/sound.h @@ -97,7 +97,7 @@ private: void stopSound(); void stopMusic(); - void playMIDI(sound_pt seq_p, uint16 size); + void playMIDI(SoundPtr seqPtr, uint16 size); }; } // End of namespace Hugo diff --git a/engines/kyra/animator_hof.cpp b/engines/kyra/animator_hof.cpp index 5a2378f4d0..59112504d6 100644 --- a/engines/kyra/animator_hof.cpp +++ b/engines/kyra/animator_hof.cpp @@ -104,9 +104,7 @@ void KyraEngine_HoF::refreshAnimObjects(int force) { if (height + y > 143) height -= height + y - 144; - _screen->hideMouse(); _screen->copyRegion(x, y, x, y, width, height, 2, 0, Screen::CR_NO_P_CHECK); - _screen->showMouse(); curObject->needRefresh = false; } diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp index 29fa3aba80..83e774e2fc 100644 --- a/engines/kyra/animator_mr.cpp +++ b/engines/kyra/animator_mr.cpp @@ -175,9 +175,7 @@ void KyraEngine_MR::refreshAnimObjects(int force) { height -= height + y - (maxY + 1); if (height > 0) { - _screen->hideMouse(); _screen->copyRegion(x, y, x, y, width, height, 2, 0, Screen::CR_NO_P_CHECK); - _screen->showMouse(); } curObject->needRefresh = false; @@ -209,9 +207,7 @@ void KyraEngine_MR::updateItemAnimations() { nextFrame = true; _screen->drawShape(2, getShapePtr(422 + i), 9, 0, 0, 0); _screen->drawShape(2, getShapePtr(shpIdx), 9, 0, 0, 0); - _screen->hideMouse(); _screen->copyRegion(9, 0, _inventoryX[i], _inventoryY[i], 24, 20, 2, 0, Screen::CR_NO_P_CHECK); - _screen->showMouse(); } } } diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index 884fca659b..e2162f20e2 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -159,7 +159,7 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA1_FLOPPY_FLAGS }, - { + { // russian fan translation { "kyra1", "Extracted", @@ -1329,6 +1329,22 @@ const KYRAGameDescription adGameDescs[] = { LOL_FLOPPY_CMP_FLAGS }, + { // French floppy version 1.20, bug #3552534 "KYRA: LOL Floppy FR version unknown" + { + "lol", + 0, + { + { "WESTWOOD.1", 0, "43857e24d1fc6731f3b13d9ed6db8c3a", -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GAMEOPTION_LOL_SCROLLING, GAMEOPTION_LOL_CURSORS) + }, + LOL_FLOPPY_CMP_FLAGS + }, + { { "lol", @@ -1397,6 +1413,23 @@ const KYRAGameDescription adGameDescs[] = { LOL_FLOPPY_FLAGS }, + { // French floppy version 1.23, bug #3552534 "KYRA: LOL Floppy FR version unknown" + { + "lol", + "Extracted", + { + { "GENERAL.PAK", 0, "f4fd14f244bd7c7fa08d026fafe44cc5", -1 }, + { "CHAPTER7.PAK", 0, "733e33c8444c93843dac3b683c283eaa", -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GAMEOPTION_LOL_SCROLLING, GAMEOPTION_LOL_CURSORS) + }, + LOL_FLOPPY_FLAGS + }, + // Russian fan translation { { diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp index a63f123258..fadb1066e0 100644 --- a/engines/kyra/eobcommon.cpp +++ b/engines/kyra/eobcommon.cpp @@ -770,7 +770,7 @@ void EoBCoreEngine::releaseItemsAndDecorationsShapes() { if (_spellShapes) { for (int i = 0; i < 4; i++) { if (_spellShapes[i]) - delete [] _spellShapes[i]; + delete[] _spellShapes[i]; } delete[] _spellShapes; } @@ -820,7 +820,7 @@ void EoBCoreEngine::releaseItemsAndDecorationsShapes() { if (_firebeamShapes[i]) delete[] _firebeamShapes[i]; } - delete []_firebeamShapes; + delete[] _firebeamShapes; } delete[] _redSplatShape; diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h index 050fe2b794..f60e755dd7 100644 --- a/engines/kyra/eobcommon.h +++ b/engines/kyra/eobcommon.h @@ -263,7 +263,7 @@ protected: // Main Menu, Intro, Finale virtual int mainMenu() = 0; - virtual void seq_xdeath() {}; + virtual void seq_xdeath() {} virtual void seq_playFinale() = 0; bool _playFinale; @@ -921,8 +921,8 @@ protected: void usePotion(int charIndex, int weaponSlot); void useWand(int charIndex, int weaponSlot); - virtual void turnUndeadAuto() {}; - virtual void turnUndeadAutoHit() {}; + virtual void turnUndeadAuto() {} + virtual void turnUndeadAutoHit() {} void castSpell(int spell, int weaponSlot); void removeCharacterEffect(int spell, int charIndex, int showWarning); diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index c1bfee066f..36fbb0b40a 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -121,14 +121,12 @@ int KyraEngine_HoF::buttonInventory(Button *button) { if (_itemInHand == kItemNone) { if (item == kItemNone) return 0; - _screen->hideMouse(); clearInventorySlot(inventorySlot, 0); snd_playSoundEffect(0x0B); setMouseCursor(item); int string = (_lang == 1) ? getItemCommandStringPickUp(item) : 7; updateCommandLineEx(item+54, string, 0xD6); _itemInHand = (int16)item; - _screen->showMouse(); _mainCharacter.inventory[inventorySlot] = kItemNone; } else { if (_mainCharacter.inventory[inventorySlot] != kItemNone) { @@ -137,23 +135,19 @@ int KyraEngine_HoF::buttonInventory(Button *button) { item = _mainCharacter.inventory[inventorySlot]; snd_playSoundEffect(0x0B); - _screen->hideMouse(); clearInventorySlot(inventorySlot, 0); drawInventoryShape(0, _itemInHand, inventorySlot); setMouseCursor(item); int string = (_lang == 1) ? getItemCommandStringPickUp(item) : 7; updateCommandLineEx(item+54, string, 0xD6); - _screen->showMouse(); _mainCharacter.inventory[inventorySlot] = _itemInHand; setHandItem(item); } else { snd_playSoundEffect(0x0C); - _screen->hideMouse(); drawInventoryShape(0, _itemInHand, inventorySlot); _screen->setMouseCursor(0, 0, getShapePtr(0)); int string = (_lang == 1) ? getItemCommandStringInv(_itemInHand) : 8; updateCommandLineEx(_itemInHand+54, string, 0xD6); - _screen->showMouse(); _mainCharacter.inventory[inventorySlot] = _itemInHand; _itemInHand = kItemNone; } @@ -172,9 +166,7 @@ int KyraEngine_HoF::scrollInventory(Button *button) { memcpy(src+5, dst, sizeof(Item)*5); memcpy(dst, dst+5, sizeof(Item)*5); memcpy(dst+5, temp, sizeof(Item)*5); - _screen->hideMouse(); _screen->copyRegion(0x46, 0x90, 0x46, 0x90, 0x71, 0x2E, 0, 2); - _screen->showMouse(); redrawInventory(2); scrollInventoryWheel(); return 0; @@ -199,9 +191,7 @@ int KyraEngine_HoF::findFreeVisibleInventorySlot() { void KyraEngine_HoF::removeSlotFromInventory(int slot) { _mainCharacter.inventory[slot] = kItemNone; if (slot < 10) { - _screen->hideMouse(); clearInventorySlot(slot, 0); - _screen->showMouse(); } } @@ -223,15 +213,12 @@ bool KyraEngine_HoF::checkInventoryItemExchange(Item handItem, int slot) { snd_playSoundEffect(0x68); _mainCharacter.inventory[slot] = newItem; - _screen->hideMouse(); clearInventorySlot(slot, 0); drawInventoryShape(0, newItem, slot); if (removeItem) removeHandItem(); - _screen->showMouse(); - if (_lang != 1) updateCommandLineEx(newItem+54, 0x2E, 0xD6); @@ -243,12 +230,10 @@ bool KyraEngine_HoF::checkInventoryItemExchange(Item handItem, int slot) { void KyraEngine_HoF::drawInventoryShape(int page, Item item, int slot) { _screen->drawShape(page, getShapePtr(item+64), _inventoryX[slot], _inventoryY[slot], 0, 0); - _screen->updateScreen(); } void KyraEngine_HoF::clearInventorySlot(int slot, int page) { _screen->drawShape(page, getShapePtr(240+slot), _inventoryX[slot], _inventoryY[slot], 0, 0); - _screen->updateScreen(); } void KyraEngine_HoF::redrawInventory(int page) { @@ -256,7 +241,6 @@ void KyraEngine_HoF::redrawInventory(int page) { _screen->_curPage = page; const Item *inventory = _mainCharacter.inventory; - _screen->hideMouse(); for (int i = 0; i < 10; ++i) { clearInventorySlot(i, page); if (inventory[i] != kItemNone) { @@ -264,7 +248,6 @@ void KyraEngine_HoF::redrawInventory(int page) { drawInventoryShape(page, inventory[i], i); } } - _screen->showMouse(); _screen->updateScreen(); _screen->_curPage = pageBackUp; @@ -277,17 +260,13 @@ void KyraEngine_HoF::scrollInventoryWheel() { memcpy(_screenBuffer, _screen->getCPagePtr(2), 64000); uint8 overlay[0x100]; _screen->generateOverlay(_screen->getPalette(0), overlay, 0, 50); - _screen->hideMouse(); _screen->copyRegion(0x46, 0x90, 0x46, 0x79, 0x71, 0x17, 0, 2, Screen::CR_NO_P_CHECK); - _screen->showMouse(); snd_playSoundEffect(0x25); bool breakFlag = false; for (int i = 0; i <= 6 && !breakFlag; ++i) { if (movie.opened()) { - _screen->hideMouse(); movie.displayFrame(i % frames, 0, 0, 0, 0, 0, 0); - _screen->showMouse(); _screen->updateScreen(); } @@ -355,9 +334,7 @@ int KyraEngine_HoF::bookButton(Button *button) { _bookNewPage = _bookCurPage; if (_screenBuffer) { - _screen->hideMouse(); memcpy(_screenBuffer, _screen->getCPagePtr(0), 64000); - _screen->showMouse(); } _screen->copyPalette(2, 0); @@ -382,9 +359,7 @@ int KyraEngine_HoF::bookButton(Button *button) { restorePage3(); if (_screenBuffer) { - _screen->hideMouse(); _screen->copyBlockToPage(0, 0, 0, 320, 200, _screenBuffer); - _screen->showMouse(); } setHandItem(_itemInHand); @@ -471,7 +446,6 @@ void KyraEngine_HoF::showBookPage() { int rightPageY = _bookPageYOffset[_bookCurPage+1]; - _screen->hideMouse(); if (leftPage) { bookDecodeText(leftPage); bookPrintText(2, leftPage, 20, leftPageY+20, 0x31); @@ -483,7 +457,6 @@ void KyraEngine_HoF::showBookPage() { bookPrintText(2, rightPage, 176, rightPageY+20, 0x31); delete[] rightPage; } - _screen->showMouse(); } void KyraEngine_HoF::bookLoop() { @@ -517,10 +490,8 @@ void KyraEngine_HoF::bookLoop() { loadBookBkgd(); showBookPage(); snd_playSoundEffect(0x64); - _screen->hideMouse(); _screen->copyRegion(0, 0, 0, 0, 0x140, 0xC8, 2, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); - _screen->showMouse(); } _system->delayMillis(10); } @@ -550,9 +521,7 @@ void KyraEngine_HoF::bookPrintText(int dstPage, const uint8 *str, int x, int y, Screen::FontId oldFont = _screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_BOOKFONT_FNT); _screen->_charWidth = -2; - _screen->hideMouse(); _screen->printText((const char *)str, x, y, color, (_flags.lang == Common::JA_JPN) ? 0xf6 : 0); - _screen->showMouse(); _screen->_charWidth = 0; _screen->setFont(oldFont); @@ -679,9 +648,7 @@ int GUI_HoF::optionsButton(Button *button) { _restartGame = false; _reloadTemporarySave = false; - _screen->hideMouse(); updateButton(&_vm->_inventoryButtons[0]); - _screen->showMouse(); if (!_screen->isMouseVisible() && button) return 0; @@ -690,9 +657,7 @@ int GUI_HoF::optionsButton(Button *button) { if (_vm->_mouseState < -1) { _vm->_mouseState = -1; - _screen->hideMouse(); _screen->setMouseCursor(1, 1, _vm->getShapePtr(0)); - _screen->showMouse(); return 0; } diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index b4e5148b64..8e18ff910d 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -48,19 +48,16 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) { snd_playSoundEffect(0x36); return 0; } else { - _screen->hideMouse(); _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12); snd_playSoundEffect(0x35); setMouseItem(inventoryItem); updateSentenceCommand(_itemList[getItemListIndex(inventoryItem)], _takenList[0], 179); _itemInHand = inventoryItem; - _screen->showMouse(); _currentCharacter->inventoryItems[itemOffset] = kItemNone; } } else { if (inventoryItem != kItemNone) { snd_playSoundEffect(0x35); - _screen->hideMouse(); _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12); _screen->drawShape(0, _shapes[216 + _itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); setMouseItem(inventoryItem); @@ -69,16 +66,13 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) { updateSentenceCommand(_itemList[getItemListIndex(inventoryItem)], _takenList[0], 179); else updateSentenceCommand(_itemList[getItemListIndex(inventoryItem)], _takenList[1], 179); - _screen->showMouse(); _currentCharacter->inventoryItems[itemOffset] = _itemInHand; _itemInHand = inventoryItem; } else { snd_playSoundEffect(0x32); - _screen->hideMouse(); _screen->drawShape(0, _shapes[216 + _itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); _screen->setMouseCursor(1, 1, _shapes[0]); updateSentenceCommand(_itemList[getItemListIndex(_itemInHand)], _placedList[0], 179); - _screen->showMouse(); _currentCharacter->inventoryItems[itemOffset] = _itemInHand; _itemInHand = kItemNone; } diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index e88b7fdffb..37526f9a5f 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -104,7 +104,6 @@ int KyraEngine_MR::callbackButton3(Button *button) { void KyraEngine_MR::showMessage(const char *string, uint8 c0, uint8 c1) { _shownMessage = string; - _screen->hideMouse(); restoreCommandLine(); _restoreCommandLine = false; @@ -118,8 +117,6 @@ void KyraEngine_MR::showMessage(const char *string, uint8 c0, uint8 c1) { _screen->updateScreen(); setCommandLineRestoreTimer(7); } - - _screen->showMouse(); } void KyraEngine_MR::showMessageFromCCode(int string, uint8 c0, int) { @@ -330,10 +327,8 @@ void KyraEngine_MR::drawMalcolmsMoodText() { _screen->_curPage = 2; } - _screen->hideMouse(); _screen->drawShape(_screen->_curPage, getShapePtr(432), 244, 189, 0, 0); _text->printText(string, x, y+1, 0xFF, 0xF0, 0x00); - _screen->showMouse(); _screen->_curPage = pageBackUp; } @@ -441,7 +436,6 @@ void KyraEngine_MR::redrawInventory(int page) { int pageBackUp = _screen->_curPage; _screen->_curPage = page; - _screen->hideMouse(); for (int i = 0; i < 10; ++i) { clearInventorySlot(i, page); @@ -451,7 +445,6 @@ void KyraEngine_MR::redrawInventory(int page) { } } - _screen->showMouse(); _screen->_curPage = pageBackUp; if (page == 0 || page == 1) @@ -489,14 +482,12 @@ int KyraEngine_MR::buttonInventory(Button *button) { if (slotItem == kItemNone) return 0; - _screen->hideMouse(); clearInventorySlot(slot, 0); snd_playSoundEffect(0x0B, 0xC8); setMouseCursor(slotItem); updateItemCommand(slotItem, (_lang == 1) ? getItemCommandStringPickUp(slotItem) : 0, 0xFF); _itemInHand = slotItem; _mainCharacter.inventory[slot] = kItemNone; - _screen->showMouse(); } else if (_itemInHand == 27) { if (_chatText) return 0; @@ -508,21 +499,17 @@ int KyraEngine_MR::buttonInventory(Button *button) { snd_playSoundEffect(0x0B, 0xC8); - _screen->hideMouse(); clearInventorySlot(slot, 0); drawInventorySlot(0, _itemInHand, slot); setMouseCursor(slotItem); updateItemCommand(slotItem, (_lang == 1) ? getItemCommandStringPickUp(slotItem) : 0, 0xFF); _mainCharacter.inventory[slot] = _itemInHand; _itemInHand = slotItem; - _screen->showMouse(); } else { snd_playSoundEffect(0x0C, 0xC8); - _screen->hideMouse(); drawInventorySlot(0, _itemInHand, slot); _screen->setMouseCursor(0, 0, getShapePtr(0)); updateItemCommand(_itemInHand, (_lang == 1) ? getItemCommandStringInv(_itemInHand) : 2, 0xFF); - _screen->showMouse(); _mainCharacter.inventory[slot] = _itemInHand; _itemInHand = kItemNone; } @@ -624,22 +611,18 @@ int KyraEngine_MR::buttonShowScore(Button *button) { int KyraEngine_MR::buttonJesterStaff(Button *button) { makeCharFacingMouse(); if (_itemInHand == 27) { - _screen->hideMouse(); removeHandItem(); snd_playSoundEffect(0x0C, 0xC8); drawJestersStaff(1, 0); updateItemCommand(27, 2, 0xFF); setGameFlag(0x97); - _screen->showMouse(); } else if (_itemInHand == kItemNone) { if (queryGameFlag(0x97)) { - _screen->hideMouse(); snd_playSoundEffect(0x0B, 0xC8); setHandItem(27); drawJestersStaff(0, 0); updateItemCommand(27, 0, 0xFF); resetGameFlag(0x97); - _screen->showMouse(); } else { if (queryGameFlag(0x2F)) objectChat((const char *)getTableEntry(_cCodeFile, 20), 0, 204, 20); @@ -1108,9 +1091,7 @@ int GUI_MR::redrawButtonCallback(Button *button) { if (!_displayMenu) return 0; - _screen->hideMouse(); _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xD0); - _screen->showMouse(); return 0; } @@ -1119,9 +1100,7 @@ int GUI_MR::redrawShadedButtonCallback(Button *button) { if (!_displayMenu) return 0; - _screen->hideMouse(); _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xD1, 0xCF); - _screen->showMouse(); return 0; } @@ -1162,9 +1141,7 @@ int GUI_MR::quitGame(Button *caller) { int GUI_MR::optionsButton(Button *button) { PauseTimer pause(*_vm->_timer); - _screen->hideMouse(); updateButton(&_vm->_mainButtonData[0]); - _screen->showMouse(); if (!_vm->_inventoryState && button && !_vm->_menuDirectlyToLoad) return 0; @@ -1179,9 +1156,7 @@ int GUI_MR::optionsButton(Button *button) { if (_vm->_mouseState < -1) { _vm->_mouseState = -1; - _screen->hideMouse(); _screen->setMouseCursor(1, 1, _vm->getShapePtr(0)); - _screen->showMouse(); return 0; } diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp index f3459ddfe3..cec6562dd9 100644 --- a/engines/kyra/gui_v1.cpp +++ b/engines/kyra/gui_v1.cpp @@ -70,8 +70,6 @@ void GUI_v1::initMenuLayout(Menu &menu) { void GUI_v1::initMenu(Menu &menu) { _menuButtonList = 0; - _screen->hideMouse(); - int textX; int textY; @@ -192,7 +190,6 @@ void GUI_v1::initMenu(Menu &menu) { updateMenuButton(scrollDownButton); } - _screen->showMouse(); _screen->updateScreen(); } @@ -309,10 +306,8 @@ void GUI_v1::updateMenuButton(Button *button) { if (!_displayMenu) return; - _screen->hideMouse(); updateButton(button); _screen->updateScreen(); - _screen->showMouse(); } void GUI_v1::updateButton(Button *button) { @@ -340,12 +335,10 @@ int GUI_v1::redrawButtonCallback(Button *button) { if (!_displayMenu) return 0; - _screen->hideMouse(); if (_vm->gameFlags().platform == Common::kPlatformAmiga) _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 17); else _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xF8); - _screen->showMouse(); return 0; } @@ -354,12 +347,10 @@ int GUI_v1::redrawShadedButtonCallback(Button *button) { if (!_displayMenu) return 0; - _screen->hideMouse(); if (_vm->gameFlags().platform == Common::kPlatformAmiga) _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 31, 18); else _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xF9, 0xFA); - _screen->showMouse(); return 0; } diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index 65f8bd45e5..1df4149d2e 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -105,15 +105,11 @@ void GUI_v2::processButton(Button *button) { switch (val1 - 1) { case 0: - _screen->hideMouse(); _screen->drawShape(_screen->_curPage, dataPtr, x, y, button->dimTableIndex, 0x10); - _screen->showMouse(); break; case 1: - _screen->hideMouse(); _screen->printText((const char *)dataPtr, x, y, val2, val3); - _screen->showMouse(); break; case 3: @@ -122,22 +118,16 @@ void GUI_v2::processButton(Button *button) { break; case 4: - _screen->hideMouse(); _screen->drawBox(x, y, x2, y2, val2); - _screen->showMouse(); break; case 5: - _screen->hideMouse(); _screen->fillRect(x, y, x2, y2, val2, -1, true); - _screen->showMouse(); break; default: break; } - - _screen->updateScreen(); } int GUI_v2::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseWheel) { diff --git a/engines/kyra/items_hof.cpp b/engines/kyra/items_hof.cpp index 711e1b8f7c..ef2c50c0c5 100644 --- a/engines/kyra/items_hof.cpp +++ b/engines/kyra/items_hof.cpp @@ -300,8 +300,6 @@ void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, in } void KyraEngine_HoF::exchangeMouseItem(int itemPos) { - _screen->hideMouse(); - deleteItemAnimEntry(itemPos); int itemId = _itemList[itemPos].id; @@ -317,7 +315,6 @@ void KyraEngine_HoF::exchangeMouseItem(int itemPos) { str2 = getItemCommandStringPickUp(itemId); updateCommandLineEx(itemId + 54, str2, 0xD6); - _screen->showMouse(); runSceneScript6(); } @@ -331,7 +328,6 @@ bool KyraEngine_HoF::pickUpItem(int x, int y) { if (_itemInHand >= 0) { exchangeMouseItem(itemPos); } else { - _screen->hideMouse(); deleteItemAnimEntry(itemPos); int itemId = _itemList[itemPos].id; _itemList[itemPos].id = kItemNone; @@ -344,7 +340,6 @@ bool KyraEngine_HoF::pickUpItem(int x, int y) { updateCommandLineEx(itemId + 54, str2, 0xD6); _itemInHand = itemId; - _screen->showMouse(); runSceneScript6(); } diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp index 2937038463..b92cd616c1 100644 --- a/engines/kyra/items_lok.cpp +++ b/engines/kyra/items_lok.cpp @@ -163,17 +163,13 @@ void KyraEngine_LoK::placeItemInGenericMapScene(int item, int index) { } void KyraEngine_LoK::setHandItem(Item item) { - _screen->hideMouse(); setMouseItem(item); _itemInHand = item; - _screen->showMouse(); } void KyraEngine_LoK::removeHandItem() { - _screen->hideMouse(); _screen->setMouseCursor(1, 1, _shapes[0]); _itemInHand = kItemNone; - _screen->showMouse(); } void KyraEngine_LoK::setMouseItem(Item item) { @@ -415,7 +411,6 @@ int KyraEngine_LoK::processItemDrop(uint16 sceneId, uint8 item, int x, int y, in } void KyraEngine_LoK::exchangeItemWithMouseItem(uint16 sceneId, int itemIndex) { - _screen->hideMouse(); _animator->animRemoveGameItem(itemIndex); assert(sceneId < _roomTableSize); Room *currentRoom = &_roomTable[sceneId]; @@ -432,7 +427,6 @@ void KyraEngine_LoK::exchangeItemWithMouseItem(uint16 sceneId, int itemIndex) { updateSentenceCommand(_itemList[getItemListIndex(_itemInHand)], _takenList[0], 179); else updateSentenceCommand(_itemList[getItemListIndex(_itemInHand)], _takenList[1], 179); - _screen->showMouse(); clickEventHandler2(); } @@ -720,9 +714,7 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) { _itemInHand = kItemNone; } else { _characterList[0].inventoryItems[itemPos] = kItemNone; - _screen->hideMouse(); _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12, 0); - _screen->showMouse(); } _screen->showMouse(); @@ -793,9 +785,7 @@ void KyraEngine_LoK::magicInMouseItem(int animIndex, int item, int itemPos) { _itemInHand = item; } else { _characterList[0].inventoryItems[itemPos] = item; - _screen->hideMouse(); _screen->drawShape(0, _shapes[216 + item], _itemPosX[itemPos], _itemPosY[itemPos], 0, 0); - _screen->showMouse(); } _screen->showMouse(); _screen->_curPage = videoPageBackUp; @@ -846,9 +836,7 @@ void KyraEngine_LoK::updatePlayerItemsForScene() { ++_itemInHand; if (_itemInHand > 33) _itemInHand = 33; - _screen->hideMouse(); _screen->setMouseCursor(8, 15, _shapes[216 + _itemInHand]); - _screen->showMouse(); } bool redraw = false; @@ -864,9 +852,7 @@ void KyraEngine_LoK::updatePlayerItemsForScene() { } if (redraw) { - _screen->hideMouse(); redrawInventory(0); - _screen->showMouse(); } if (_itemInHand == 33) @@ -884,7 +870,6 @@ void KyraEngine_LoK::updatePlayerItemsForScene() { void KyraEngine_LoK::redrawInventory(int page) { int videoPageBackUp = _screen->_curPage; _screen->_curPage = page; - _screen->hideMouse(); for (int i = 0; i < 10; ++i) { _screen->fillRect(_itemPosX[i], _itemPosY[i], _itemPosX[i] + 15, _itemPosY[i] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12, page); @@ -893,7 +878,6 @@ void KyraEngine_LoK::redrawInventory(int page) { _screen->drawShape(page, _shapes[216 + item], _itemPosX[i], _itemPosY[i], 0, 0); } } - _screen->showMouse(); _screen->_curPage = videoPageBackUp; _screen->updateScreen(); } diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index ea2acaf64d..409b53f6f0 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -441,20 +441,20 @@ bool LoLEngine::launchObject(int objectType, Item item, int startX, int startY, return true; } -void LoLEngine::endObjectFlight(FlyingObject *t, int x, int y, int collisionObject) { +void LoLEngine::endObjectFlight(FlyingObject *t, int x, int y, int collisionType) { int cx = x; int cy = y; uint16 block = calcBlockIndex(t->x, t->y); removeAssignedObjectFromBlock(&_levelBlockProperties[block], t->item); removeDrawObjectFromBlock(&_levelBlockProperties[block], t->item); - if (collisionObject == 1) { + if (collisionType == 1) { cx = t->x; cy = t->y; } if (t->objectType == 0 || t->objectType == 1) { - objectFlightProcessHits(t, cx, cy, collisionObject); + objectFlightProcessHits(t, cx, cy, collisionType); t->x = (cx & 0xffc0) | 0x40; t->y = (cy & 0xffc0) | 0x40; t->flyingHeight = 0; @@ -488,27 +488,23 @@ void LoLEngine::updateObjectFlightPosition(FlyingObject *t) { } } -void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objectOnNextBlock) { - uint16 r = 0; - - if (objectOnNextBlock == 1) { +void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int collisionType) { + if (collisionType == 1) { runLevelScriptCustom(calcNewBlockPosition(_itemsInPlay[t->item].block, t->direction >> 1), 0x8000, -1, t->item, 0, 0); - } else if (objectOnNextBlock == 2) { + } else if (collisionType == 2) { if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { - int o = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects; - while (o & 0x8000) { - LoLObject *i = findObject(o); - o = i->nextAssignedObject; - runItemScript(t->attackerId, t->item, 0x8000, o, 0); + uint16 obj = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects; + while (obj & 0x8000) { + runItemScript(t->attackerId, t->item, 0x8000, obj, 0); + obj = findObject(obj)->nextAssignedObject; } } else { - r = getNearestMonsterFromPos(x, y); - runItemScript(t->attackerId, t->item, 0x8000, r, 0); + runItemScript(t->attackerId, t->item, 0x8000, getNearestMonsterFromPos(x, y), 0); } - } else if (objectOnNextBlock == 4) { + } else if (collisionType == 4) { _partyAwake = true; if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { for (int i = 0; i < 4; i++) { @@ -516,8 +512,7 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec runItemScript(t->attackerId, t->item, 0x8000, i, 0); } } else { - r = getNearestPartyMemberFromPos(x, y); - runItemScript(t->attackerId, t->item, 0x8000, r, 0); + runItemScript(t->attackerId, t->item, 0x8000, getNearestPartyMemberFromPos(x, y), 0); } } } @@ -543,9 +538,9 @@ void LoLEngine::updateFlyingObject(FlyingObject *t) { middle of a block (or making the monsters align to the middle before casting them) wouldn't help here (and wouldn't be faithful to the original either). */ - int objectOnNextBlock = checkBlockBeforeObjectPlacement(x, y, /*_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000 ? 256 :*/ 63, t->flags, t->wallFlags); - if (objectOnNextBlock) { - endObjectFlight(t, x, y, objectOnNextBlock); + int collisionType = checkBlockBeforeObjectPlacement(x, y, /*_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000 ? 256 :*/ 63, t->flags, t->wallFlags); + if (collisionType) { + endObjectFlight(t, x, y, collisionType); } else { if (--t->distance) { processObjectFlight(t, x, y); @@ -567,16 +562,16 @@ void LoLEngine::assignItemToBlock(uint16 *assignedBlockObjects, int id) { *assignedBlockObjects = id; } -int LoLEngine::checkDrawObjectSpace(int itemX, int itemY, int partyX, int partyY) { - int a = itemX - partyX; - if (a < 0) - a = -a; +int LoLEngine::checkDrawObjectSpace(int x1, int y1, int x2, int y2) { + int dx = x1 - x2; + if (dx < 0) + dx = -dx; - int b = itemY - partyY; - if (b < 0) - b = -b; + int dy = y1 - y2; + if (dy < 0) + dy = -dy; - return a + b; + return dx + dy; } int LoLEngine::checkSceneForItems(uint16 *blockDrawObjects, int color) { diff --git a/engines/kyra/items_mr.cpp b/engines/kyra/items_mr.cpp index c731627026..029f676538 100644 --- a/engines/kyra/items_mr.cpp +++ b/engines/kyra/items_mr.cpp @@ -319,7 +319,6 @@ void KyraEngine_MR::exchangeMouseItem(int itemPos, int runScript) { return; } - _screen->hideMouse(); deleteItemAnimEntry(itemPos); Item itemId = _itemList[itemPos].id; @@ -335,7 +334,6 @@ void KyraEngine_MR::exchangeMouseItem(int itemPos, int runScript) { str2 = getItemCommandStringPickUp(itemId); updateItemCommand(itemId, str2, 0xFF); - _screen->showMouse(); if (runScript) runSceneScript6(); @@ -350,7 +348,6 @@ bool KyraEngine_MR::pickUpItem(int x, int y, int runScript) { if (_itemInHand >= 0) { exchangeMouseItem(itemPos, runScript); } else { - _screen->hideMouse(); deleteItemAnimEntry(itemPos); Item itemId = _itemList[itemPos].id; _itemList[itemPos].id = kItemNone; @@ -363,7 +360,6 @@ bool KyraEngine_MR::pickUpItem(int x, int y, int runScript) { updateItemCommand(itemId, itemString, 0xFF); _itemInHand = itemId; - _screen->showMouse(); if (runScript) runSceneScript6(); @@ -401,7 +397,6 @@ bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) { assert(animObjIndex != -1); - _screen->hideMouse(); snd_playSoundEffect(0x93, 0xC8); for (int i = 109; i <= 141; ++i) { _animObjects[animObjIndex].shapeIndex1 = i+248; @@ -411,7 +406,6 @@ bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) { deleteItemAnimEntry(itemSlot); _itemList[itemSlot].id = kItemNone; - _screen->showMouse(); return true; } @@ -440,7 +434,6 @@ bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) { _itemList[itemSlot].id = (int8)resItem; - _screen->hideMouse(); deleteItemAnimEntry(itemSlot); addItemToAnimList(itemSlot); @@ -448,7 +441,6 @@ bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) { removeHandItem(); else if (newItem != 0xFF) setHandItem(newItem); - _screen->showMouse(); if (_lang != 1) updateItemCommand(resItem, 3, 0xFF); @@ -500,7 +492,6 @@ bool KyraEngine_MR::itemInventoryMagic(Item handItem, int invSlot) { _mainCharacter.inventory[invSlot] = (int8)resItem; - _screen->hideMouse(); clearInventorySlot(invSlot, 0); drawInventorySlot(0, resItem, invSlot); @@ -508,7 +499,6 @@ bool KyraEngine_MR::itemInventoryMagic(Item handItem, int invSlot) { removeHandItem(); else if (newItem != 0xFF) setHandItem(newItem); - _screen->showMouse(); if (_lang != 1) updateItemCommand(resItem, 3, 0xFF); diff --git a/engines/kyra/items_v2.cpp b/engines/kyra/items_v2.cpp index c191c2e62b..2145a2c2f0 100644 --- a/engines/kyra/items_v2.cpp +++ b/engines/kyra/items_v2.cpp @@ -82,26 +82,19 @@ void KyraEngine_v2::resetItem(int index) { } void KyraEngine_v2::setHandItem(Item item) { - Screen *scr = screen(); - scr->hideMouse(); - if (item == kItemNone) { removeHandItem(); } else { setMouseCursor(item); _itemInHand = item; } - - scr->showMouse(); } void KyraEngine_v2::removeHandItem() { Screen *scr = screen(); - scr->hideMouse(); scr->setMouseCursor(0, 0, getShapePtr(0)); _itemInHand = kItemNone; _mouseState = kItemNone; - scr->showMouse(); } } // end of namesapce Kyra diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0ba173d9d0..7fbecb7f53 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -419,8 +419,6 @@ void KyraEngine_HoF::startup() { _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); _screen->loadBitmap("_PLAYFLD.CPS", 3, 3, 0); _screen->copyPage(3, 0); - _screen->showMouse(); - _screen->hideMouse(); clearAnimObjects(); @@ -784,20 +782,16 @@ void KyraEngine_HoF::updateMouse() { if (type != 0 && _mouseState != type && _screen->isMouseVisible()) { _mouseState = type; - _screen->hideMouse(); _screen->setMouseCursor(xOffset, yOffset, getShapePtr(shapeIndex)); - _screen->showMouse(); } if (type == 0 && _mouseState != _itemInHand && _screen->isMouseVisible()) { if ((mouse.y > 145) || (mouse.x > 6 && mouse.x < 312 && mouse.y > 6 && mouse.y < 135)) { _mouseState = _itemInHand; - _screen->hideMouse(); if (_itemInHand == kItemNone) _screen->setMouseCursor(0, 0, getShapePtr(0)); else _screen->setMouseCursor(8, 15, getShapePtr(_itemInHand+64)); - _screen->showMouse(); } } } @@ -914,7 +908,6 @@ void KyraEngine_HoF::showMessageFromCCode(int id, int16 palIndex, int) { void KyraEngine_HoF::showMessage(const char *string, int16 palIndex) { _shownMessage = string; - _screen->hideMouse(); _screen->fillRect(0, 190, 319, 199, 0xCF); if (string) { @@ -932,7 +925,6 @@ void KyraEngine_HoF::showMessage(const char *string, int16 palIndex) { } _fadeMessagePalette = false; - _screen->showMouse(); } void KyraEngine_HoF::showChapterMessage(int id, int16 palIndex) { @@ -1116,9 +1108,7 @@ int KyraEngine_HoF::getDrawLayer(int x, int y) { void KyraEngine_HoF::backUpPage0() { if (_screenBuffer) { - _screen->hideMouse(); memcpy(_screenBuffer, _screen->getCPagePtr(0), 64000); - _screen->showMouse(); } } diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index ece4a0daba..27bc2ad22a 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -454,10 +454,8 @@ void KyraEngine_LoK::mainLoop() { if (_deathHandler != -1) { snd_playWanderScoreViaMap(0, 1); snd_playSoundEffect(49); - _screen->hideMouse(); _screen->setMouseCursor(1, 1, _shapes[0]); removeHandItem(); - _screen->showMouse(); _gui->buttonMenuCallback(0); _deathHandler = -1; } @@ -706,7 +704,6 @@ int KyraEngine_LoK::processInputHelper(int xpos, int ypos) { uint8 item = findItemAtPos(xpos, ypos); if (item != 0xFF) { if (_itemInHand == kItemNone) { - _screen->hideMouse(); _animator->animRemoveGameItem(item); snd_playSoundEffect(53); assert(_currentCharacter->sceneId < _roomTableSize); @@ -717,7 +714,6 @@ int KyraEngine_LoK::processInputHelper(int xpos, int ypos) { assert(_itemList && _takenList); updateSentenceCommand(_itemList[getItemListIndex(item2)], _takenList[0], 179); _itemInHand = item2; - _screen->showMouse(); clickEventHandler2(); return 1; } else { @@ -834,21 +830,17 @@ void KyraEngine_LoK::updateMousePointer(bool forceUpdate) { if ((newMouseState && _mouseState != newMouseState) || (newMouseState && forceUpdate)) { _mouseState = newMouseState; - _screen->hideMouse(); _screen->setMouseCursor(newX, newY, _shapes[shape]); - _screen->showMouse(); } if (!newMouseState) { if (_mouseState != _itemInHand || forceUpdate) { if (mouse.y > 158 || (mouse.x >= 12 && mouse.x < 308 && mouse.y < 136 && mouse.y >= 12) || forceUpdate) { _mouseState = _itemInHand; - _screen->hideMouse(); if (_itemInHand == kItemNone) _screen->setMouseCursor(1, 1, _shapes[0]); else _screen->setMouseCursor(8, 15, _shapes[216 + _itemInHand]); - _screen->showMouse(); } } } diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 39ed0d038a..448e4ef70d 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -1298,7 +1298,6 @@ bool KyraEngine_MR::updateScore(int scoreId, int strId) { setNextIdleAnimTimer(); _scoreFlagTable[scoreIndex] |= (1 << scoreBit); - _screen->hideMouse(); strcpy(_stringBuffer, (const char *)getTableEntry(_scoreFile, strId)); strcat(_stringBuffer, ": "); @@ -1308,7 +1307,6 @@ bool KyraEngine_MR::updateScore(int scoreId, int strId) { if (count > 0) scoreIncrease(count, _stringBuffer); - _screen->showMouse(); setNextIdleAnimTimer(); return true; } diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 75b568a00a..848fb18b6a 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -198,8 +198,6 @@ void KyraEngine_v2::moveCharacter(int facing, int x, int y) { y &= ~1; _mainCharacter.facing = facing; - Screen *scr = screen(); - scr->hideMouse(); switch (facing) { case 0: while (_mainCharacter.y1 > y) @@ -224,7 +222,6 @@ void KyraEngine_v2::moveCharacter(int facing, int x, int y) { default: break; } - scr->showMouse(); } void KyraEngine_v2::updateCharPosWithUpdate() { diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 38e9d33259..d3028c5e2d 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -1436,7 +1436,7 @@ void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) { bool loop = true; while (loop) { - if (_characters[charNum].experiencePts[skill] <= _expRequirements[_characters[charNum].skillLevels[skill]]) + if (_characters[charNum].experiencePts[skill] < _expRequirements[_characters[charNum].skillLevels[skill]]) break; _characters[charNum].skillLevels[skill]++; @@ -2894,11 +2894,11 @@ int LoLEngine::processMagicVaelansCube() { uint8 s = _levelBlockProperties[bl].walls[_currentDirection ^ 2]; uint8 flg = _wllWallFlags[s]; - int v = (s == 47 && (_currentLevel == 17 || _currentLevel == 24)) ? 1 : 0; - if ((_wllVmpMap[s] == 1 || _wllVmpMap[s] == 2) && (flg & 1) && (_currentLevel == 22)) { + int res = (s == 47 && (_currentLevel == 17 || _currentLevel == 24)) ? 1 : 0; + if ((_wllVmpMap[s] == 1 || _wllVmpMap[s] == 2) && (!(flg & 1)) && (_currentLevel != 22)) { memset(_levelBlockProperties[bl].walls, 0, 4); gui_drawScene(0); - v = 1; + res = 1; } uint16 o = _levelBlockProperties[bl].assignedObjects; @@ -2906,7 +2906,7 @@ int LoLEngine::processMagicVaelansCube() { LoLMonster *m = &_monsters[o & 0x7fff]; if (m->properties->flags & 0x1000) { inflictDamage(o, 100, 0xffff, 0, 0x80); - v = 1; + res = 1; } o = m->nextAssignedObject; } @@ -2922,7 +2922,7 @@ int LoLEngine::processMagicVaelansCube() { delete[] tmpPal1; delete[] tmpPal2; - return v; + return res; } int LoLEngine::processMagicGuardian(int charNum) { diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index dbd461267f..dcd13804b3 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -1047,14 +1047,14 @@ private: void setItemPosition(Item item, uint16 x, uint16 y, int flyingHeight, int moveable); void removeLevelItem(Item item, int block); bool launchObject(int objectType, Item item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c); - void endObjectFlight(FlyingObject *t, int x, int y, int collisionObject); + void endObjectFlight(FlyingObject *t, int x, int y, int collisionType); void processObjectFlight(FlyingObject *t, int x, int y); void updateObjectFlightPosition(FlyingObject *t); - void objectFlightProcessHits(FlyingObject *t, int x, int y, int objectOnNextBlock); + void objectFlightProcessHits(FlyingObject *t, int x, int y, int collisionType); void updateFlyingObject(FlyingObject *t); void assignItemToBlock(uint16 *assignedBlockObjects, int id); - int checkDrawObjectSpace(int itemX, int itemY, int partyX, int partyY); + int checkDrawObjectSpace(int x1, int y1, int x2, int y2); int checkSceneForItems(uint16 *blockDrawObjects, int color); uint8 _moneyColumnHeight[5]; @@ -1095,7 +1095,7 @@ private: void monsterDropItems(LoLMonster *monster); void giveItemToMonster(LoLMonster *monster, Item item); int checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 objectWidth, uint16 testFlag, uint16 wallFlag); - int checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag); + int testBlockPassability(int block, int x, int y, int objectWidth, int testFlag, int wallFlag); int calcMonsterSkillLevel(int id, int a); int checkBlockOccupiedByParty(int x, int y, int testFlag); const uint16 *getCharacterOrMonsterStats(int id); @@ -1122,7 +1122,7 @@ private: int checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock); int walkMonsterCheckDest(int x, int y, LoLMonster *monster, int unk); void getNextStepCoords(int16 monsterX, int16 monsterY, int &newX, int &newY, uint16 direction); - void rearrangeAttackingMonster(LoLMonster *monster); + void alignMonsterToParty(LoLMonster *monster); void moveStrayingMonster(LoLMonster *monster); void killMonster(LoLMonster *monster); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 711fe15348..04d805737f 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -141,7 +141,7 @@ bool Screen::init() { if (!font) error("Could not load any SJIS font, neither the original nor ScummVM's 'SJIS.FNT'"); - _fonts[FID_SJIS_FNT] = new SJISFont(this, font, _sjisInvisibleColor, _use16ColorMode, !_use16ColorMode); + _fonts[FID_SJIS_FNT] = new SJISFont(font, _sjisInvisibleColor, _use16ColorMode, !_use16ColorMode); } } @@ -1128,8 +1128,6 @@ void Screen::drawBox(int x1, int y1, int x2, int y2, int color) { void Screen::drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2) { assert(x1 >= 0 && y1 >= 0); - hideMouse(); - fillRect(x1, y1, x2, y1 + 1, color1); fillRect(x2 - 1, y1, x2, y2, color1); @@ -1137,8 +1135,6 @@ void Screen::drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color drawClippedLine(x1 + 1, y1 + 1, x1 + 1, y2 - 1, color2); drawClippedLine(x1, y2 - 1, x2 - 1, y2 - 1, color2); drawClippedLine(x1, y2, x2, y2, color2); - - showMouse(); } void Screen::drawClippedLine(int x1, int y1, int x2, int y2, int color) { @@ -3599,8 +3595,8 @@ void AMIGAFont::unload() { memset(_chars, 0, sizeof(_chars)); } -SJISFont::SJISFont(Screen *s, Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize) - : _colorMap(0), _font(font), _invisColor(invisColor), _is16Color(is16Color), _screen(s) { +SJISFont::SJISFont(Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize) + : _colorMap(0), _font(font), _invisColor(invisColor), _is16Color(is16Color) { assert(_font); _font->setDrawingMode(outlineSize ? Graphics::FontSJIS::kOutlineMode : Graphics::FontSJIS::kDefaultMode); diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index b064c72bb0..60bfeb3241 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -213,7 +213,7 @@ private: */ class SJISFont : public Font { public: - SJISFont(Screen *s, Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize); + SJISFont(Graphics::FontSJIS *font, const uint8 invisColor, bool is16Color, bool outlineSize); ~SJISFont() { unload(); } bool usesOverlay() const { return true; } @@ -233,7 +233,6 @@ private: const uint8 _invisColor; const bool _is16Color; - const Screen *_screen; int _sjisWidth, _asciiWidth; int _fontHeight; }; diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp index e06ca42c40..ae75c111b4 100644 --- a/engines/kyra/screen_eob.cpp +++ b/engines/kyra/screen_eob.cpp @@ -607,7 +607,7 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco srcLineStart += SCREEN_W; src = srcLineStart; } - delete [] colorMap; + delete[] colorMap; } return shp; diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp index f32a898dd9..f028f93294 100644 --- a/engines/kyra/screen_lok.cpp +++ b/engines/kyra/screen_lok.cpp @@ -190,7 +190,6 @@ void Screen_LoK::copyBackgroundBlock(int x, int page, int flag) { _curPage = page; int curX = x; - hideMouse(); copyRegionToBuffer(_curPage, 8, 8, 8, height, ptr2); for (int i = 0; i < 19; ++i) { int tempX = curX + 1; @@ -208,7 +207,6 @@ void Screen_LoK::copyBackgroundBlock(int x, int page, int flag) { curX = curX % 38; } } - showMouse(); _curPage = oldVideoPage; } diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index 08b232f400..3726b1f4b9 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -31,7 +31,7 @@ namespace Kyra { -Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : _screenDimTable256C, _screenDimTableCount), _vm(vm) { +Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : _screenDimTable256C, _screenDimTableCount) { _paletteOverlay1 = new uint8[0x100]; _paletteOverlay2 = new uint8[0x100]; _grayOverlay = new uint8[0x100]; diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index 3bba9f8b70..09496705bb 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -89,8 +89,6 @@ public: static void convertPC98Gfx(uint8 *data, int w, int h, int pitch); private: - LoLEngine *_vm; - static const ScreenDim _screenDimTable256C[]; static const ScreenDim _screenDimTable16C[]; static const int _screenDimTableCount; diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index b80b8105a1..fca83ae632 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -325,7 +325,6 @@ int KyraEngine_HoF::o2_drawShape(EMCState *script) { if (modeFlag) { _screen->drawShape(2, shp, x, y, 2, dsFlag ? 1 : 0); } else { - _screen->hideMouse(); restorePage3(); _screen->drawShape(2, shp, x, y, 2, dsFlag ? 1 : 0); memcpy(_gamePlayBuffer, _screen->getCPagePtr(3), 46080); @@ -334,7 +333,6 @@ int KyraEngine_HoF::o2_drawShape(EMCState *script) { flagAnimObjsForRefresh(); flagAnimObjsSpecialRefresh(); refreshAnimObjectsIfNeed(); - _screen->showMouse(); } return 0; @@ -492,7 +490,6 @@ int KyraEngine_HoF::o2_drawSceneShape(EMCState *script) { int y = stackPos(2); int flag = (stackPos(3) != 0) ? 1 : 0; - _screen->hideMouse(); restorePage3(); _screen->drawShape(2, _sceneShapeTable[shape], x, y, 2, flag); @@ -504,7 +501,6 @@ int KyraEngine_HoF::o2_drawSceneShape(EMCState *script) { flagAnimObjsSpecialRefresh(); flagAnimObjsForRefresh(); refreshAnimObjectsIfNeed(); - _screen->showMouse(); return 0; } diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp index 8342bccab6..db9e01cabb 100644 --- a/engines/kyra/script_lok.cpp +++ b/engines/kyra/script_lok.cpp @@ -157,7 +157,6 @@ int KyraEngine_LoK::o1_dropItemInScene(EMCState *script) { int KyraEngine_LoK::o1_drawAnimShapeIntoScene(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_drawAnimShapeIntoScene(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); - _screen->hideMouse(); _animator->restoreAllObjectBackgrounds(); int shape = stackPos(0); int xpos = stackPos(1); @@ -169,7 +168,6 @@ int KyraEngine_LoK::o1_drawAnimShapeIntoScene(EMCState *script) { _animator->preserveAnyChangedBackgrounds(); _animator->flagAllObjectsForRefresh(); _animator->updateAllObjectShapes(); - _screen->showMouse(); return 0; } @@ -1298,7 +1296,6 @@ int KyraEngine_LoK::o1_drawItemShapeIntoScene(EMCState *script) { if (onlyHidPage) { _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags); } else { - _screen->hideMouse(); _animator->restoreAllObjectBackgrounds(); _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags); _screen->drawShape(0, _shapes[216 + item], x, y, 0, flags); @@ -1306,7 +1303,6 @@ int KyraEngine_LoK::o1_drawItemShapeIntoScene(EMCState *script) { _animator->preserveAnyChangedBackgrounds(); _animator->flagAllObjectsForRefresh(); _animator->updateAllObjectShapes(); - _screen->showMouse(); } return 0; } diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index c5d1d49030..9c0fe21ad4 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -958,10 +958,9 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) { l->hitPoints = stackPos(26); l->speedTotalWaitTicks = 1; l->flags = stackPos(27); - l->unk5 = stackPos(28); - // FIXME??? + // This is what the original does here (setting the value first to stackPos(28) and then to stackPos(29): + //l->unk5 = stackPos(28); l->unk5 = stackPos(29); - // l->numDistAttacks = stackPos(30); l->numDistWeapons = stackPos(31); diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index afe11aba02..22d0bc4e95 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -150,9 +150,7 @@ int KyraEngine_MR::o3_addItemToInventory(EMCState *script) { if (slot >= 0) { _mainCharacter.inventory[slot] = stackPos(0); if (_inventoryState) { - _screen->hideMouse(); redrawInventory(0); - _screen->showMouse(); } } return slot; @@ -330,7 +328,6 @@ int KyraEngine_MR::o3_drawSceneShape(EMCState *script) { int shape = stackPos(0); int flag = (stackPos(1) != 0) ? 1 : 0; - _screen->hideMouse(); restorePage3(); const int x = _sceneShapeDescs[shape].drawX; @@ -344,7 +341,6 @@ int KyraEngine_MR::o3_drawSceneShape(EMCState *script) { flagAnimObjsForRefresh(); refreshAnimObjectsIfNeed(); - _screen->showMouse(); return 0; } diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index dd49d6faaa..e63d0a7d8f 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -838,9 +838,7 @@ void KyraEngine_LoK::seq_fillFlaskWithWater(int item, int type) { if (newItem == -1) return; - _screen->hideMouse(); setMouseItem(newItem); - _screen->showMouse(); _itemInHand = newItem; assert(_fullFlask); diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h index 427bef66e2..827a487685 100644 --- a/engines/kyra/sound_intern.h +++ b/engines/kyra/sound_intern.h @@ -130,7 +130,6 @@ private: void fadeOutSoundEffects(); int _lastTrack; - Audio::AudioStream *_currentSFX; Audio::SoundHandle _sfxHandle; uint8 *_musicTrackData; diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp index 0004395f6f..70cc304192 100644 --- a/engines/kyra/sound_midi.cpp +++ b/engines/kyra/sound_midi.cpp @@ -475,8 +475,8 @@ SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *dri ::GUI::MessageDialog dialog(_("You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" "We try to map the Roland MT32 instruments to\n" - "General MIDI ones. After all it might happen\n" - "that a few tracks will not be correctly played.")); + "General MIDI ones. It is still possible that\n" + "some tracks sound incorrect.")); dialog.runModal(); } } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 2f996de1ac..4b25db33f2 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -34,7 +34,7 @@ namespace Kyra { SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) - : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0), + : Sound(vm, mixer), _lastTrack(-1), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0), _sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46) { _driver = new TownsEuphonyDriver(_mixer); diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index a07abd4580..f4bae113c5 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -355,7 +355,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object int yOffs = 0; int flag = 0; - int r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y), x, y, objectWidth, testFlag, wallFlag); + int r = testBlockPassability(calcBlockIndex(x, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -369,7 +369,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 2; x2 = x + objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -385,7 +385,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 6; x2 = x - objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -403,7 +403,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 4; y2 = y + objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -420,7 +420,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 0; y2 = y - objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -436,7 +436,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object if (!flag) return 0; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -447,7 +447,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object return 0; } -int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag) { +int LoLEngine::testBlockPassability(int block, int x, int y, int objectWidth, int testFlag, int wallFlag) { if (block == _currentBlock) testFlag &= 0xfffe; @@ -461,9 +461,9 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int if (!(testFlag & 2)) return 0; - uint16 b = _levelBlockProperties[block].assignedObjects; - while (b & 0x8000) { - LoLMonster *monster = &_monsters[b & 0x7fff]; + uint16 obj = _levelBlockProperties[block].assignedObjects; + while (obj & 0x8000) { + LoLMonster *monster = &_monsters[obj & 0x7fff]; if (monster->mode < 13) { int r = checkDrawObjectSpace(x, y, monster->x, monster->y); @@ -471,7 +471,7 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int return 2; } - b = findObject(b)->nextAssignedObject; + obj = findObject(obj)->nextAssignedObject; } return 0; @@ -1105,7 +1105,7 @@ void LoLEngine::updateMonster(LoLMonster *monster) { if ((monster->fightCurTick <= 0) || (checkDrawObjectSpace(_partyPosX, _partyPosY, monster->x, monster->y) > 256) || (monster->flags & 8)) setMonsterMode(monster, 7); else - rearrangeAttackingMonster(monster); + alignMonsterToParty(monster); break; case 6: @@ -1428,26 +1428,26 @@ int LoLEngine::walkMonsterCheckDest(int x, int y, LoLMonster *monster, int unk) uint8 m = monster->mode; monster->mode = 15; - int res = checkBlockBeforeObjectPlacement(x, y, monster->properties->maxWidth, 7, monster->properties->flags & 0x1000 ? 32 : unk); + int objType = checkBlockBeforeObjectPlacement(x, y, monster->properties->maxWidth, 7, monster->properties->flags & 0x1000 ? 32 : unk); monster->mode = m; - return res; + return objType; } void LoLEngine::getNextStepCoords(int16 srcX, int16 srcY, int &newX, int &newY, uint16 direction) { - static const int8 shiftTableX[] = { 0, 32, 32, 32, 0, -32, -32, -32 }; - static const int8 shiftTableY[] = { -32, -32, 0, 32, 32, 32, 0, -32 }; + static const int8 stepAdjustX[] = { 0, 32, 32, 32, 0, -32, -32, -32 }; + static const int8 stepAdjustY[] = { -32, -32, 0, 32, 32, 32, 0, -32 }; - newX = (srcX + shiftTableX[direction]) & 0x1fff; - newY = (srcY + shiftTableY[direction]) & 0x1fff; + newX = (srcX + stepAdjustX[direction]) & 0x1fff; + newY = (srcY + stepAdjustY[direction]) & 0x1fff; } -void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { - int t = (monster->direction >> 1); +void LoLEngine::alignMonsterToParty(LoLMonster *monster) { + uint8 mdir = monster->direction >> 1; uint16 mx = monster->x; uint16 my = monster->y; - uint16 *c = (t & 1) ? &my : &mx; - bool centered = (*c & 0x7f) == 0; + uint16 *pos = (mdir & 1) ? &my : &mx; + bool centered = (*pos & 0x7f) == 0; bool posFlag = true; if (monster->properties->maxWidth <= 63) { @@ -1464,11 +1464,13 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { r = true; } else { for (int i = 0; i < 3; i++) { - t = (t + 1) & 3; - id = _levelBlockProperties[calcNewBlockPosition(monster->block, t)].assignedObjects; + mdir = (mdir + 1) & 3; + id = _levelBlockProperties[calcNewBlockPosition(monster->block, mdir)].assignedObjects; id = (id & 0x8000) ? (id & 0x7fff) : 0xffff; - if (id != 0xffff) + if (id != 0xffff) { r = true; + break; + } } } } @@ -1484,15 +1486,15 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { return; if (posFlag) { - if (*c & 0x80) - *c -= 32; + if (*pos & 0x80) + *pos -= 32; else - *c += 32; + *pos += 32; } else { - if (*c & 0x80) - *c += 32; + if (*pos & 0x80) + *pos += 32; else - *c -= 32; + *pos -= 32; } if (walkMonsterCheckDest(mx, my, monster, 4)) @@ -1502,8 +1504,10 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { int fy = _partyPosY; calcSpriteRelPosition(mx, my, fx, fy, monster->direction >> 1); - t = (fx < 0) ? -fx : fx; - if (fy > 160 || t > 80) + if (fx < 0) + fx = -fx; + + if (fy > 160 || fx > 80) return; placeMonster(monster, mx, my); diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 423b827092..00dc4f9e13 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -38,7 +38,7 @@ namespace Kyra { -#define RESFILE_VERSION 82 +#define RESFILE_VERSION 83 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp index 4a52d7d740..06067d6693 100644 --- a/engines/kyra/text_hof.cpp +++ b/engines/kyra/text_hof.cpp @@ -42,9 +42,7 @@ void TextDisplayer_HoF::restoreTalkTextMessageBkgd(int srcPage, int dstPage) { void TextDisplayer_HoF::restoreScreen() { _vm->restorePage3(); _vm->drawAnimObjects(); - _screen->hideMouse(); _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK); - _screen->showMouse(); _vm->flagAnimObjsForRefresh(); _vm->refreshAnimObjects(0); } @@ -58,8 +56,6 @@ void TextDisplayer_HoF::printCustomCharacterText(const char *text, int x, int y, int x1 = 0, x2 = 0; calcWidestLineBounds(x1, x2, w, x); - _screen->hideMouse(); - _talkCoords.x = x1; _talkCoords.w = w+2; _talkCoords.y = y; @@ -78,7 +74,6 @@ void TextDisplayer_HoF::printCustomCharacterText(const char *text, int x, int y, } _screen->_curPage = curPageBackUp; - _screen->showMouse(); } char *TextDisplayer_HoF::preprocessString(const char *str) { @@ -248,8 +243,6 @@ void KyraEngine_HoF::objectChatInit(const char *str, int object, int vocHigh, in restorePage3(); _text->backupTalkTextMessageBkgd(2, 2); - _screen->hideMouse(); - _chatTextEnabled = textEnabled(); if (_chatTextEnabled) { objectChatPrintText(str, object); @@ -264,8 +257,6 @@ void KyraEngine_HoF::objectChatInit(const char *str, int object, int vocHigh, in } else { _chatVocHigh = _chatVocLow = -1; } - - _screen->showMouse(); } void KyraEngine_HoF::objectChatPrintText(const char *str, int object) { diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp index 62bdf18816..a557940868 100644 --- a/engines/kyra/text_lok.cpp +++ b/engines/kyra/text_lok.cpp @@ -296,10 +296,8 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu _animator->restoreAllObjectBackgrounds(); _screen->copyRegion(12, _text->_talkMessageY, 12, 136, 296, _text->_talkMessageH, 2, 2); - _screen->hideMouse(); _text->printCharacterText(processedString, charNum, _characterList[charNum].x1); - _screen->showMouse(); } if (chatDuration == -2) @@ -317,10 +315,8 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu _screen->copyRegion(12, 136, 12, _text->_talkMessageY, 296, _text->_talkMessageH, 2, 2); _animator->preserveAllBackgrounds(); _animator->prepDrawAllObjects(); - _screen->hideMouse(); _screen->copyRegion(12, _text->_talkMessageY, 12, _text->_talkMessageY, 296, _text->_talkMessageH, 2, 0); - _screen->showMouse(); _animator->flagAllObjectsForRefresh(); _animator->copyChangedObjectsForward(0); } @@ -332,7 +328,6 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu } void KyraEngine_LoK::drawSentenceCommand(const char *sentence, int color) { - _screen->hideMouse(); _screen->fillRect(8, 143, 311, 152, _flags.platform == Common::kPlatformAmiga ? 19 : 12); if (_flags.platform == Common::kPlatformAmiga) { @@ -354,7 +349,6 @@ void KyraEngine_LoK::drawSentenceCommand(const char *sentence, int color) { } _text->printText(sentence, 8, 143, 0xFF, _flags.platform == Common::kPlatformAmiga ? 19 : 12, 0); - _screen->showMouse(); setTextFadeTimerCountdown(15); _fadeText = false; } diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp index b680e9c6f9..10b0880f29 100644 --- a/engines/kyra/text_mr.cpp +++ b/engines/kyra/text_mr.cpp @@ -145,9 +145,7 @@ void TextDisplayer_MR::printText(const char *str, int x, int y, uint8 c0, uint8 void TextDisplayer_MR::restoreScreen() { _vm->restorePage3(); _vm->drawAnimObjects(); - _screen->hideMouse(); _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK); - _screen->showMouse(); _vm->flagAnimObjsForRefresh(); _vm->refreshAnimObjects(0); } @@ -261,8 +259,6 @@ void KyraEngine_MR::objectChatInit(const char *str, int object, int vocHigh, int restorePage3(); - _screen->hideMouse(); - _chatTextEnabled = textEnabled(); if (_chatTextEnabled) { objectChatPrintText(str, object); @@ -277,8 +273,6 @@ void KyraEngine_MR::objectChatInit(const char *str, int object, int vocHigh, int } else { _chatVocHigh = _chatVocLow = -1; } - - _screen->showMouse(); } void KyraEngine_MR::objectChatPrintText(const char *str, int object) { diff --git a/engines/lastexpress/data/animation.cpp b/engines/lastexpress/data/animation.cpp index 28d30ec7d1..7618259e69 100644 --- a/engines/lastexpress/data/animation.cpp +++ b/engines/lastexpress/data/animation.cpp @@ -32,10 +32,8 @@ #include "common/events.h" #include "common/rational.h" -#include "common/rect.h" #include "common/stream.h" #include "common/system.h" -#include "common/textconsole.h" #include "engines/engine.h" @@ -232,7 +230,7 @@ AnimFrame *Animation::processChunkFrame(Common::SeekableReadStream *in, const Ch i.read(str, false); // Decode the frame - AnimFrame *f = new AnimFrame(str, i); + AnimFrame *f = new AnimFrame(str, i, true); // Delete the temporary chunk buffer delete str; @@ -250,7 +248,7 @@ void Animation::processChunkAudio(Common::SeekableReadStream *in, const Chunk &c // Read Snd header uint32 header1 = in->readUint32LE(); uint16 header2 = in->readUint16LE(); - warning("Start ADPCM: %d, %d", header1, header2); + debugC(4, kLastExpressDebugSound, "Start ADPCM: %d, %d", header1, header2); size -= 6; } @@ -272,7 +270,7 @@ void Animation::play() { draw(s); // XXX: Update the screen - g_system->copyRectToScreen((byte *)s->pixels, s->pitch, 0, 0, s->w, s->h); + g_system->copyRectToScreen(s->pixels, s->pitch, 0, 0, s->w, s->h); // Free the temporary surface s->free(); diff --git a/engines/lastexpress/data/background.cpp b/engines/lastexpress/data/background.cpp index 3d866c26f9..60379251a3 100644 --- a/engines/lastexpress/data/background.cpp +++ b/engines/lastexpress/data/background.cpp @@ -107,6 +107,7 @@ byte *Background::decodeComponent(Common::SeekableReadStream *in, uint32 inSize, return NULL; // Initialize the decoding + memset(out, 0, outSize * sizeof(byte)); uint32 inPos = 0; uint32 outPos = 0; diff --git a/engines/lastexpress/data/cursor.cpp b/engines/lastexpress/data/cursor.cpp index 86a66b49d9..d176d963d1 100644 --- a/engines/lastexpress/data/cursor.cpp +++ b/engines/lastexpress/data/cursor.cpp @@ -91,9 +91,9 @@ void Cursor::setStyle(CursorStyle style) { // Reuse the screen pixel format Graphics::PixelFormat pf = g_system->getScreenFormat(); - CursorMan.replaceCursor((const byte *)getCursorImage(style), + CursorMan.replaceCursor(getCursorImage(style), 32, 32, _cursors[style].hotspotX, _cursors[style].hotspotY, - 0, 1, &pf); + 0, false, &pf); } const uint16 *Cursor::getCursorImage(CursorStyle style) const { @@ -128,7 +128,7 @@ Common::Rect Icon::draw(Graphics::Surface *surface) { for (int i = 0; i < 32; i++) { // Adjust brightness - if (_brightnessIndex == -1) + if (_brightnessIndex == -1 || _brightnessIndex >= ARRAYSIZE(brigthnessData)) *s = *image; else *s = (*image & brigthnessData[_brightnessIndex]) >> _brightnessIndex; diff --git a/engines/lastexpress/data/font.cpp b/engines/lastexpress/data/font.cpp index 79cf64e617..8ac1afce9a 100644 --- a/engines/lastexpress/data/font.cpp +++ b/engines/lastexpress/data/font.cpp @@ -149,7 +149,7 @@ uint8 Font::getCharWidth(uint16 c) const{ uint16 Font::getStringWidth(Common::String str) const { uint16 width = 0; for (uint i = 0; i < str.size(); i++) - width += getCharWidth((unsigned) (int)str[i]); + width += getCharWidth((unsigned char)str[i]); return width; } @@ -185,8 +185,8 @@ void Font::drawChar(Graphics::Surface *surface, int16 x, int16 y, uint16 c) { Common::Rect Font::drawString(Graphics::Surface *surface, int16 x, int16 y, Common::String str) { int16 currentX = x; for (uint i = 0; i < str.size(); i++) { - drawChar(surface, currentX, y, (unsigned) (int)str[i]); - currentX += getCharWidth((unsigned) (int)str[i]); + drawChar(surface, currentX, y, (unsigned char)str[i]); + currentX += getCharWidth((unsigned char)str[i]); } return Common::Rect(x, y, x + currentX, y + (int16)_charHeight); diff --git a/engines/lastexpress/data/scene.cpp b/engines/lastexpress/data/scene.cpp index 8f279ffbb3..fdb1ac6d46 100644 --- a/engines/lastexpress/data/scene.cpp +++ b/engines/lastexpress/data/scene.cpp @@ -28,7 +28,6 @@ #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" -#include "common/textconsole.h" #include "common/stream.h" namespace LastExpress { @@ -122,7 +121,7 @@ bool SceneHotspot::isInside(const Common::Point &point) { // Scene Scene::~Scene() { // Free the hotspots - for (int i = 0; i < (int)_hotspots.size(); i++) + for (uint i = 0; i < _hotspots.size(); i++) delete _hotspots[i]; } @@ -172,7 +171,7 @@ bool Scene::checkHotSpot(const Common::Point &coord, SceneHotspot **hotspot) { bool found = false; int _location = 0; - for (int i = 0; i < (int)_hotspots.size(); i++) { + for (uint i = 0; i < _hotspots.size(); i++) { if (_hotspots[i]->isInside(coord)) { if (_location <= _hotspots[i]->location) { _location = _hotspots[i]->location; @@ -224,7 +223,7 @@ Common::String Scene::toString() { // Hotspots if (_hotspots.size() != 0) { output += "\nHotspots:\n"; - for (int i = 0; i < (int)_hotspots.size(); i++) + for (uint i = 0; i < _hotspots.size(); i++) output += _hotspots[i]->toString() + "\n"; } @@ -241,7 +240,7 @@ SceneLoader::~SceneLoader() { void SceneLoader::clear() { // Remove all scenes - for (int i = 0; i < (int)_scenes.size(); i++) + for (uint i = 0; i < _scenes.size(); i++) delete _scenes[i]; _scenes.clear(); @@ -292,9 +291,9 @@ Scene *SceneLoader::get(SceneIndex index) { return NULL; // Load the hotspots if needed - _scenes[(int)index]->loadHotspots(_stream); + _scenes[(uint)index]->loadHotspots(_stream); - return _scenes[(int)index]; + return _scenes[(uint)index]; } } // End of namespace LastExpress diff --git a/engines/lastexpress/data/sequence.cpp b/engines/lastexpress/data/sequence.cpp index a62348f6c0..a5bcba84cd 100644 --- a/engines/lastexpress/data/sequence.cpp +++ b/engines/lastexpress/data/sequence.cpp @@ -27,7 +27,6 @@ #include "lastexpress/debug.h" #include "common/stream.h" -#include "common/textconsole.h" namespace LastExpress { @@ -77,7 +76,7 @@ void FrameInfo::read(Common::SeekableReadStream *in, bool isSequence) { // AnimFrame -AnimFrame::AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f) : _palette(NULL) { +AnimFrame::AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f, bool ignoreSubtype) : _palette(NULL), _ignoreSubtype(ignoreSubtype) { _palSize = 1; // TODO: use just the needed rectangle _image.create(640, 480, Graphics::PixelFormat::createFormatCLUT8()); diff --git a/engines/lastexpress/data/sequence.h b/engines/lastexpress/data/sequence.h index 9987eae48e..610a55cebf 100644 --- a/engines/lastexpress/data/sequence.h +++ b/engines/lastexpress/data/sequence.h @@ -49,8 +49,9 @@ byte {1} - Compression type byte {1} - Subtype (determines which set of decompression functions will be called) => 0, 1, 2, 3 byte {1} - Unknown + byte {1} - Keep previous frame while drawing + byte {1} - Unknown byte {1} - Unknown - uint16 {2} - Unknown byte {1} - Sound action byte {1} - Unknown uint32 {4} - positionId @@ -129,7 +130,7 @@ struct FrameInfo { class AnimFrame : public Drawable { public: - AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f); + AnimFrame(Common::SeekableReadStream *in, const FrameInfo &f, bool ignoreSubtype = false); ~AnimFrame(); Common::Rect draw(Graphics::Surface *s); @@ -146,6 +147,7 @@ private: uint16 _palSize; uint16 *_palette; Common::Rect _rect; + bool _ignoreSubtype; }; class Sequence { diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp index a9bee6155d..a77e4a06c6 100644 --- a/engines/lastexpress/data/snd.cpp +++ b/engines/lastexpress/data/snd.cpp @@ -28,11 +28,9 @@ #include "lastexpress/debug.h" #include "audio/decoders/adpcm_intern.h" -#include "audio/audiostream.h" #include "common/debug.h" #include "common/memstream.h" #include "common/system.h" -#include "common/textconsole.h" namespace LastExpress { @@ -358,6 +356,8 @@ public: Audio::ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) { _currentFilterId = -1; _nextFilterId = filterId; + _stepAdjust1 = 0; + _stepAdjust2 = 0; } int readBuffer(int16 *buffer, const int numSamples) { @@ -378,7 +378,7 @@ public: // Get current filter _currentFilterId = _nextFilterId; - _nextFilterId = -1; + //_nextFilterId = -1; // FIXME: the filter id should be recomputed based on the sound entry status for each block // No filter: skip decoding if (_currentFilterId == -1) @@ -455,7 +455,9 @@ void SimpleSound::play(Audio::AudioStream *as) { ////////////////////////////////////////////////////////////////////////// StreamedSound::StreamedSound() : _as(NULL), _loaded(false) {} -StreamedSound::~StreamedSound() {} +StreamedSound::~StreamedSound() { + _as = NULL; +} bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) { if (!stream) @@ -484,6 +486,9 @@ bool StreamedSound::isFinished() { } void StreamedSound::setFilterId(int32 filterId) { + if (!_as) + return; + ((LastExpress_ADPCMStream *)_as)->setFilterId(filterId); } @@ -521,6 +526,7 @@ void AppendableSound::queueBuffer(Common::SeekableReadStream *bufferIn) { // Setup the ADPCM decoder uint32 sizeIn = (uint32)bufferIn->size(); Audio::AudioStream *adpcm = makeDecoder(bufferIn, sizeIn); + ((LastExpress_ADPCMStream *)adpcm)->setFilterId(16); // Queue the stream _as->queueAudioStream(adpcm); diff --git a/engines/lastexpress/data/subtitle.cpp b/engines/lastexpress/data/subtitle.cpp index 0be832cbdd..4d19c02aa7 100644 --- a/engines/lastexpress/data/subtitle.cpp +++ b/engines/lastexpress/data/subtitle.cpp @@ -32,7 +32,6 @@ #include "common/debug.h" #include "common/rect.h" #include "common/stream.h" -#include "common/textconsole.h" namespace LastExpress { @@ -151,7 +150,7 @@ SubtitleManager::~SubtitleManager() { } void SubtitleManager::reset() { - for (int i = 0; i < (int)_subtitles.size(); i++) + for (uint i = 0; i < _subtitles.size(); i++) delete _subtitles[i]; _subtitles.clear(); @@ -211,10 +210,10 @@ void SubtitleManager::setTime(uint16 time) { _currentIndex = -1; // Find the appropriate line to show - for (int16 i = 0; i < (int16)_subtitles.size(); i++) { + for (uint i = 0; i < _subtitles.size(); i++) { if ((time >= _subtitles[i]->getTimeStart()) && (time <= _subtitles[i]->getTimeStop())) { // Keep the index of the line to show - _currentIndex = i; + _currentIndex = (int16)i; return; } } @@ -238,7 +237,7 @@ Common::Rect SubtitleManager::draw(Graphics::Surface *surface) { // Draw the current line assert(_currentIndex >= 0 && _currentIndex < (int16)_subtitles.size()); - return _subtitles[_currentIndex]->draw(surface, _font); + return _subtitles[(uint16)_currentIndex]->draw(surface, _font); } } // End of namespace LastExpress diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index dc2807db63..db3a3e3962 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -28,13 +28,13 @@ #include "lastexpress/data/cursor.h" #include "lastexpress/data/scene.h" #include "lastexpress/data/sequence.h" -#include "lastexpress/data/snd.h" #include "lastexpress/data/subtitle.h" #include "lastexpress/fight/fight.h" #include "lastexpress/game/action.h" #include "lastexpress/game/beetle.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" @@ -44,15 +44,12 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" #include "common/debug-channels.h" -#include "common/events.h" #include "common/md5.h" namespace LastExpress { @@ -88,7 +85,6 @@ Debugger::Debugger(LastExpressEngine *engine) : _engine(engine), _command(NULL), DCmd_Register("entity", WRAP_METHOD(Debugger, cmdEntity)); // Misc - DCmd_Register("loadgame", WRAP_METHOD(Debugger, cmdLoadGame)); DCmd_Register("chapter", WRAP_METHOD(Debugger, cmdSwitchChapter)); DCmd_Register("clear", WRAP_METHOD(Debugger, cmdClear)); @@ -142,6 +138,9 @@ void Debugger::copyCommand(int argc, const char **argv) { for (int i = 0; i < _numParams; i++) { _commandParams[i] = (char *)malloc(strlen(argv[i]) + 1); + if (_commandParams[i] == NULL) + error("[Debugger::copyCommand] Cannot allocate memory for command parameters"); + memset(_commandParams[i], 0, strlen(argv[i]) + 1); strcpy(_commandParams[i], argv[i]); } @@ -155,9 +154,18 @@ void Debugger::callCommand() { (*_command)(_numParams, const_cast<const char **>(_commandParams)); } -void Debugger::loadArchive(ArchiveIndex index) const { - _engine->getResourceManager()->loadArchive(index); - getScenes()->loadSceneDataFile(index); +bool Debugger::loadArchive(int index) { + if (index < 1 || index > 3) { + DebugPrintf("Invalid cd number (was: %d, valid: [1-3])\n", index); + return false; + } + + if (!_engine->getResourceManager()->loadArchive((ArchiveIndex)index)) + return false; + + getScenes()->loadSceneDataFile((ArchiveIndex)index); + + return true; } // Restore loaded archive @@ -236,8 +244,10 @@ bool Debugger::cmdListFiles(int argc, const char **argv) { Common::String filter(const_cast<char *>(argv[1])); // Load the proper archive - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } Common::ArchiveMemberList list; int count = _engine->getResourceManager()->listMatchingMembers(list, filter); @@ -320,8 +330,10 @@ bool Debugger::cmdShowFrame(int argc, const char **argv) { Common::String filename(const_cast<char *>(argv[1])); filename += ".seq"; - if (argc == 4) - loadArchive((ArchiveIndex)getNumber(argv[3])); + if (argc == 4) { + if (!loadArchive(getNumber(argv[3]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -380,8 +392,10 @@ bool Debugger::cmdShowBg(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename + ".BG")) { DebugPrintf("Cannot find file: %s\n", (filename + ".BG").c_str()); @@ -433,8 +447,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { Common::String filename(const_cast<char *>(argv[1])); filename += ".seq"; - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -508,8 +524,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { bool Debugger::cmdPlaySnd(int argc, const char **argv) { if (argc == 2 || argc == 3) { - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } // Add .SND at the end of the filename if needed Common::String name(const_cast<char *>(argv[1])); @@ -523,7 +541,7 @@ bool Debugger::cmdPlaySnd(int argc, const char **argv) { _engine->_system->getMixer()->stopAll(); - _soundStream->load(getArchive(name)); + _soundStream->load(getArchive(name), 16); if (argc == 3) restoreArchive(); @@ -545,8 +563,10 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } filename += ".sbe"; @@ -608,11 +628,13 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String name(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } // If we got a nis filename, check that the file exists - if (name.contains('.') && _engine->getResourceManager()->hasFile(name)) { + if (name.contains('.') && !_engine->getResourceManager()->hasFile(name)) { DebugPrintf("Cannot find file: %s\n", name.c_str()); return true; } @@ -665,8 +687,10 @@ bool Debugger::cmdLoadScene(int argc, const char **argv) { SceneIndex index = (SceneIndex)getNumber(argv[1]); // Check args - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (index > 2500) { DebugPrintf("Error: invalid index value (0-2500)"); @@ -1094,30 +1118,6 @@ label_error: } /** - * Command: loads a game - * - * @param argc The argument count. - * @param argv The values. - * - * @return true if it was handled, false otherwise - */ -bool Debugger::cmdLoadGame(int argc, const char **argv) { - if (argc == 2) { - int id = getNumber(argv[1]); - - if (id == 0 || id > 6) - goto error; - - getSaveLoad()->loadGame((GameId)(id - 1)); - } else { -error: - DebugPrintf("Syntax: loadgame <id> (id=1-6)\n"); - } - - return true; -} - -/** * Command: switch to a specific chapter * * @param argc The argument count. diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h index d9ba6f47a1..532cb83717 100644 --- a/engines/lastexpress/debug.h +++ b/engines/lastexpress/debug.h @@ -79,7 +79,6 @@ private: bool cmdShow(int argc, const char **argv); bool cmdEntity(int argc, const char **argv); - bool cmdLoadGame(int argc, const char **argv); bool cmdSwitchChapter(int argc, const char **argv); bool cmdClear(int argc, const char **argv); @@ -87,7 +86,7 @@ private: void copyCommand(int argc, const char **argv); int getNumber(const char *arg) const; - void loadArchive(ArchiveIndex index) const; + bool loadArchive(int index); void restoreArchive() const; Debuglet *_command; diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp index 82a6520522..2fdeef910a 100644 --- a/engines/lastexpress/detection.cpp +++ b/engines/lastexpress/detection.cpp @@ -173,7 +173,7 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, - + // The Last Express (Russian) // expressw.exe 1999-04-05 15:33:56 // express.exe ??? @@ -211,6 +211,7 @@ public: return "LastExpress Engine (C) 1997 Smoking Car Productions"; } +protected: bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; }; diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp index 301c52e142..406b017d3a 100644 --- a/engines/lastexpress/entities/abbot.cpp +++ b/engines/lastexpress/entities/abbot.cpp @@ -34,9 +34,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -60,10 +58,10 @@ Abbot::Abbot(LastExpressEngine *engine) : Entity(engine, kEntityAbbot) { ADD_CALLBACK_FUNCTION(Abbot, chapter2); ADD_CALLBACK_FUNCTION(Abbot, chapter3); ADD_CALLBACK_FUNCTION(Abbot, chapter3Handler); - ADD_CALLBACK_FUNCTION(Abbot, function19); - ADD_CALLBACK_FUNCTION(Abbot, function20); - ADD_CALLBACK_FUNCTION(Abbot, function21); - ADD_CALLBACK_FUNCTION(Abbot, function22); + ADD_CALLBACK_FUNCTION(Abbot, conversationWithBoutarel); + ADD_CALLBACK_FUNCTION(Abbot, readPaper); + ADD_CALLBACK_FUNCTION(Abbot, goToLunch); + ADD_CALLBACK_FUNCTION(Abbot, haveLunch); ADD_CALLBACK_FUNCTION(Abbot, function23); ADD_CALLBACK_FUNCTION(Abbot, function24); ADD_CALLBACK_FUNCTION(Abbot, function25); @@ -261,7 +259,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) getData()->entityPosition = kPosition_6470; getData()->location = kLocationInsideCompartment; - setup_function19(); + setup_conversationWithBoutarel(); break; } break; @@ -274,7 +272,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Abbot, function19) +IMPLEMENT_FUNCTION(19, Abbot, conversationWithBoutarel) switch (savepoint.action) { default: break; @@ -313,21 +311,21 @@ IMPLEMENT_FUNCTION(19, Abbot, function19) case 3: getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808); - setup_function20(); + setup_readPaper(); break; } } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Abbot, function20) +IMPLEMENT_FUNCTION(20, Abbot, readPaper) switch (savepoint.action) { default: break; case kActionNone: if (getState()->time > kTime1966500 && getEntities()->isInRestaurant(kEntityBoutarel)) - setup_function21(); + setup_goToLunch(); break; case kActionDefault: @@ -337,7 +335,7 @@ IMPLEMENT_FUNCTION(20, Abbot, function20) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Abbot, function21) +IMPLEMENT_FUNCTION(21, Abbot, goToLunch) switch (savepoint.action) { default: break; @@ -395,7 +393,7 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) break; case 7: - setup_function22(); + setup_haveLunch(); break; } break; @@ -411,13 +409,13 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Abbot, function22) +IMPLEMENT_FUNCTION(22, Abbot, haveLunch) switch (savepoint.action) { default: break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752); + Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752); if (getState()->time > kTime1989000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->inventoryItem = kItemNone; @@ -516,7 +514,8 @@ IMPLEMENT_FUNCTION(24, Abbot, function24) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 900); + if (!Entity::updateParameter(params->param1, getState()->time, 900)) + break; setup_function25(); break; @@ -617,7 +616,8 @@ IMPLEMENT_FUNCTION(26, Abbot, function26) break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, 4500); + if (!Entity::updateParameter(params->param2, getState()->time, 4500)) + break; if (getEntities()->isSomebodyInsideRestaurantOrSalon()) setup_function27(); @@ -691,7 +691,7 @@ IMPLEMENT_FUNCTION(28, Abbot, function28) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime2052000, params->param1, 1, setup_function29); + Entity::timeCheckCallback(kTime2052000, params->param1, 1, WRAP_SETUP_FUNCTION(Abbot, setup_function29)); break; case kActionDefault: @@ -770,7 +770,7 @@ IMPLEMENT_FUNCTION(29, Abbot, function29) getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122358304); getEntities()->drawSequenceLeft(kEntityAbbot, "508B"); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -864,7 +864,8 @@ IMPLEMENT_FUNCTION(31, Abbot, function31) if (!params->param1) break; - UPDATE_PARAM(params->param5, getState()->time, 450); + if (!Entity::updateParameter(params->param5, getState()->time, 450)) + break; setCallback(6); setup_callbackActionRestaurantOrSalon(); @@ -920,7 +921,8 @@ IMPLEMENT_FUNCTION(31, Abbot, function31) getSavePoints()->push(kEntityAbbot, kEntityAlexei, kAction122288808); params->param1 = 1; - UPDATE_PARAM(params->param5, getState()->time, 450); + if (!Entity::updateParameter(params->param5, getState()->time, 450)) + break; setCallback(6); setup_callbackActionRestaurantOrSalon(); @@ -1163,7 +1165,8 @@ IMPLEMENT_FUNCTION(36, Abbot, function36) break; case 2: - UPDATE_PARAM(params->param4, getState()->time, 900); + if (!Entity::updateParameter(params->param4, getState()->time, 900)) + break; getSound()->playSound(kEntityAbbot, "Abb3042"); break; @@ -1287,7 +1290,7 @@ IMPLEMENT_FUNCTION_II(40, Abbot, function40, CarIndex, EntityPosition) case kActionNone: if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); } else if (!getEvent(kEventAbbotInvitationDrink) && getEntities()->isDistanceBetweenEntities(kEntityAbbot, kEntityPlayer, 1000) && !getEntities()->isInsideCompartments(kEntityPlayer) @@ -1302,7 +1305,7 @@ IMPLEMENT_FUNCTION_II(40, Abbot, function40, CarIndex, EntityPosition) case kActionDefault: if (getEntities()->updateEntity(kEntityAbbot, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -1321,7 +1324,7 @@ IMPLEMENT_FUNCTION(41, Abbot, chapter4Handler) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129); + Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129); if (getState()->time > kTime2389500 && getEntities()->isSomebodyInsideRestaurantOrSalon()) setup_function42(); @@ -1425,10 +1428,12 @@ IMPLEMENT_FUNCTION(43, Abbot, function43) } label_callback_1: - TIME_CHECK(kTime2466000, params->param5, setup_function44); + if (Entity::timeCheck(kTime2466000, params->param5, WRAP_SETUP_FUNCTION(Abbot, setup_function44))) + break; if (params->param3) { - UPDATE_PARAM(params->param6, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param6, getState()->timeTicks, 75)) + break; params->param2 = 1; params->param3 = 0; @@ -1542,7 +1547,7 @@ IMPLEMENT_FUNCTION(45, Abbot, function45) getData()->car = kCarRedSleeping; getData()->location = kLocationOutsideCompartment; - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function38); + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_resetState); getEntities()->drawSequenceLeft(kEntityAbbot, "617Ec"); getEntities()->enterCompartment(kEntityAbbot, kObjectCompartmentC, true); @@ -1646,14 +1651,14 @@ IMPLEMENT_FUNCTION(48, Abbot, function48) if (ENTITY_PARAM(0, 1)) getData()->inventoryItem = kItemInvalid; - UPDATE_PARAM_PROC(params->param1, getState()->time, 1800) + if (Entity::updateParameter(params->param1, getState()->time, 1800)) { getData()->inventoryItem = kItemNone; setCallback(4); setup_updatePosition("126C", kCarRedSleeping, 52); - UPDATE_PARAM_PROC_END + } - TIME_CHECK_CALLBACK_INVENTORY(kTime2533500, params->param2, 5, setup_callbackActionRestaurantOrSalon); + Entity::timeCheckCallbackInventory(kTime2533500, params->param2, 5, WRAP_SETUP_FUNCTION(Abbot, setup_callbackActionRestaurantOrSalon)); break; case kAction1: @@ -1705,7 +1710,7 @@ IMPLEMENT_FUNCTION(48, Abbot, function48) getEntities()->drawSequenceLeft(kEntityAbbot, "126B"); params->param1 = 0; - TIME_CHECK_CALLBACK_INVENTORY(kTime2533500, params->param2, 5, setup_callbackActionRestaurantOrSalon); + Entity::timeCheckCallbackInventory(kTime2533500, params->param2, 5, WRAP_SETUP_FUNCTION(Abbot, setup_callbackActionRestaurantOrSalon)); break; case 5: @@ -1750,7 +1755,8 @@ IMPLEMENT_FUNCTION(49, Abbot, pickBomb) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->timeTicks, 150); + if (!Entity::updateParameter(params->param1, getState()->timeTicks, 150)) + break; getSavePoints()->push(kEntityAbbot, kEntityAbbot, kAction157489665); break; diff --git a/engines/lastexpress/entities/abbot.h b/engines/lastexpress/entities/abbot.h index 462f5a491e..dc3e86db54 100644 --- a/engines/lastexpress/entities/abbot.h +++ b/engines/lastexpress/entities/abbot.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_ABBOT_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -157,10 +156,10 @@ public: * Handle Chapter 3 events */ DECLARE_FUNCTION(chapter3Handler) - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) - DECLARE_FUNCTION(function21) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(conversationWithBoutarel) + DECLARE_FUNCTION(readPaper) + DECLARE_FUNCTION(goToLunch) + DECLARE_FUNCTION(haveLunch) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(function24) DECLARE_FUNCTION(function25) diff --git a/engines/lastexpress/entities/alexei.cpp b/engines/lastexpress/entities/alexei.cpp index 54c2d87b89..115c890f6f 100644 --- a/engines/lastexpress/entities/alexei.cpp +++ b/engines/lastexpress/entities/alexei.cpp @@ -31,9 +31,6 @@ #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -207,7 +204,7 @@ IMPLEMENT_FUNCTION(13, Alexei, function13) getData()->entityPosition = kPosition_7500; getEntities()->clearSequences(kEntityAlexei); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -242,7 +239,7 @@ IMPLEMENT_FUNCTION(14, Alexei, function14) getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); getEntities()->exitCompartment(kEntityAlexei, kObjectCompartment2, true); - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -254,7 +251,7 @@ IMPLEMENT_FUNCTION(15, Alexei, function15) break; case kActionNone: - UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1) + if (Entity::updateParameterCheck(params->param2, getState()->time, params->param1)) { if (getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->location = kLocationOutsideCompartment; @@ -292,7 +289,7 @@ IMPLEMENT_FUNCTION(15, Alexei, function15) getData()->location = kLocationInsideCompartment; getEntities()->drawSequenceLeft(kEntityAlexei, "103B"); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -312,12 +309,13 @@ IMPLEMENT_FUNCTION_IS(16, Alexei, function16, TimeValue) getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param5) { - UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75); + if (!Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, 75)) + break; params->param5 = 0; params->param6 = 1; @@ -448,7 +446,7 @@ IMPLEMENT_FUNCTION(17, Alexei, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler) + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Alexei, setup_chapter1Handler)); break; case kActionDefault: @@ -485,7 +483,9 @@ IMPLEMENT_FUNCTION(18, Alexei, chapter1Handler) } if (params->param1) { - UPDATE_PARAM(params->param3, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 90)) + break; + getScenes()->loadSceneFromPosition(kCarRestaurant, 61); } else { params->param3 = 0; @@ -689,7 +689,7 @@ IMPLEMENT_FUNCTION(21, Alexei, function21) break; case kActionNone: - UPDATE_PARAM_CHECK(params->param2, getState()->time, params->param1) + if (Entity::updateParameterCheck(params->param2, getState()->time, params->param1)) { getData()->location = kLocationOutsideCompartment; getData()->inventoryItem = kItemNone; @@ -751,7 +751,7 @@ IMPLEMENT_FUNCTION(22, Alexei, function22) break; case kActionNone: - UPDATE_PARAM_PROC(params->param2, getState()->time, params->param2) + if (Entity::updateParameter(params->param2, getState()->time, params->param2)) { if (getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->location = kLocationOutsideCompartment; getData()->inventoryItem = kItemNone; @@ -760,7 +760,7 @@ IMPLEMENT_FUNCTION(22, Alexei, function22) setup_updatePosition("103D", kCarRestaurant, 52); break; } - UPDATE_PARAM_PROC_END + } if (params->param3 == kTimeInvalid || getState()->time <= kTime1111500) break; @@ -978,7 +978,7 @@ IMPLEMENT_FUNCTION(26, Alexei, function26) break; case kActionNone: - TIME_CHECK(kTime1512000, params->param1, setup_function27) + Entity::timeCheck(kTime1512000, params->param1, WRAP_SETUP_FUNCTION(Alexei, setup_function27)); break; case kActionDefault: @@ -1333,25 +1333,26 @@ IMPLEMENT_FUNCTION(35, Alexei, function35) case kActionNone: if (getEntities()->isInSalon(kEntityPlayer)) { - UPDATE_PARAM_PROC(params->param2, getState()->time, 2700) + if (Entity::updateParameter(params->param2, getState()->time, 2700)) { setCallback(1); setup_callbackActionRestaurantOrSalon(); break; - UPDATE_PARAM_PROC_END + } } else { params->param2 = 0; } - UPDATE_PARAM_PROC(params->param3, getState()->time, params->param1) + if (Entity::updateParameter(params->param3, getState()->time, params->param1)) { if (getEntities()->isSomebodyInsideRestaurantOrSalon()) { setCallback(3); setup_function15(); break; } - UPDATE_PARAM_PROC_END + } label_callback_3: - UPDATE_PARAM(params->param4, getState()->time, 9000); + if (!Entity::updateParameter(params->param4, getState()->time, 9000)) + break; setCallback(4); setup_callbackActionRestaurantOrSalon(); @@ -1378,7 +1379,7 @@ label_callback_3: case 2: case 5: - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -1400,7 +1401,8 @@ IMPLEMENT_FUNCTION(36, Alexei, function36) if (params->param3 || params->param2) break; - UPDATE_PARAM(params->param4, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, params->param1)) + break; getEntities()->drawSequenceRight(kEntityAlexei, "124B"); @@ -1448,7 +1450,7 @@ IMPLEMENT_FUNCTION(36, Alexei, function36) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/alexei.h b/engines/lastexpress/entities/alexei.h index 262826ae42..9792385863 100644 --- a/engines/lastexpress/entities/alexei.h +++ b/engines/lastexpress/entities/alexei.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_ALEXEI_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/alouan.cpp b/engines/lastexpress/entities/alouan.cpp index cd79870559..e834e1f7cb 100644 --- a/engines/lastexpress/entities/alouan.cpp +++ b/engines/lastexpress/entities/alouan.cpp @@ -28,9 +28,6 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -89,22 +86,22 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(6, Alouan, compartment6) - COMPARTMENT_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Cf", "621Df"); + Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "621Cf", "621Df"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(7, Alouan, compartment8) - COMPARTMENT_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Ch", "621Dh"); + Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "621Ch", "621Dh"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(8, Alouan, compartment6to8) - COMPARTMENT_FROM_TO(Alouan, kObjectCompartment6, kPosition_4070, "621Bf", kObjectCompartment8, kPosition_2740, "621Ah"); + Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "621Bf", kObjectCompartment8, kPosition_2740, "621Ah"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(9, Alouan, compartment8to6) - COMPARTMENT_FROM_TO(Alouan, kObjectCompartment8, kPosition_2740, "621Bh", kObjectCompartment6, kPosition_4070, "621Af"); + Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "621Bh", kObjectCompartment6, kPosition_4070, "621Af"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -114,7 +111,7 @@ IMPLEMENT_FUNCTION(10, Alouan, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Alouan, setup_chapter1Handler)); break; case kActionDefault: @@ -134,7 +131,8 @@ IMPLEMENT_FUNCTION(11, Alouan, chapter1Handler) case kActionNone: - TIME_CHECK_CALLBACK(kTime1096200, params->param1, 1, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime1096200, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6))) + break; label_callback1: if (getState()->time > kTime1162800 && !params->param2) { @@ -284,21 +282,28 @@ IMPLEMENT_FUNCTION(16, Alouan, chapter3Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTimeCitySalzbourg, params->param1, 1, setup_compartment8to6); + if (Entity::timeCheckCallback(kTimeCitySalzbourg, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6))) + break; label_callback1: - if (params->param2 != kTimeInvalid && getState()->time > kTime1989000) - TIME_CHECK_CAR(kTime2119500, params->param5, 5, setup_compartment8); + if (params->param2 != kTimeInvalid && getState()->time > kTime1989000) { + if (Entity::timeCheckCar(kTime2119500, params->param5, 5, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8))) + break; + } label_callback2: - TIME_CHECK_CALLBACK_1(kTime2052000, params->param3, 3, setup_playSound, "Har1005"); + if (Entity::timeCheckCallback(kTime2052000, params->param3, 3, "Har1005", WRAP_SETUP_FUNCTION_S(Alouan, setup_playSound))) + break; label_callback3: - TIME_CHECK_CALLBACK(kTime2133000, params->param4, 4, setup_compartment6to8); + if (Entity::timeCheckCallback(kTime2133000, params->param4, 4, WRAP_SETUP_FUNCTION(Alouan, setup_compartment6to8))) + break; label_callback4: - if (params->param5 != kTimeInvalid && getState()->time > kTime2151000) - TIME_CHECK_CAR(kTime2241000, params->param5, 5, setup_compartment8); + if (params->param5 != kTimeInvalid && getState()->time > kTime2151000) { + if (Entity::timeCheckCar(kTime2241000, params->param5, 5, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8))) + break; + } break; case kActionDefault: @@ -355,11 +360,14 @@ IMPLEMENT_FUNCTION(18, Alouan, chapter4Handler) break; case kActionNone: - if (params->param1 != kTimeInvalid) - TIME_CHECK_CAR(kTime2443500, params->param1, 1, setup_compartment8); + if (params->param1 != kTimeInvalid) { + if (Entity::timeCheckCar(kTime2443500, params->param1, 1, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8))) + break; + } label_callback1: - TIME_CHECK_CALLBACK(kTime2455200, params->param2, 2, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime2455200, params->param2, 2, WRAP_SETUP_FUNCTION(Alouan, setup_compartment8to6))) + break; label_callback2: if (getState()->time > kTime2475000 && !params->param3) { @@ -441,7 +449,9 @@ IMPLEMENT_FUNCTION(22, Alouan, function22) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 2700); + if (!Entity::updateParameter(params->param1, getState()->time, 2700)) + break; + setup_function23(); break; diff --git a/engines/lastexpress/entities/alouan.h b/engines/lastexpress/entities/alouan.h index c6a6beddd9..91254a449a 100644 --- a/engines/lastexpress/entities/alouan.h +++ b/engines/lastexpress/entities/alouan.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_ALOUAN_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp index b13aa21f6d..f8768032b5 100644 --- a/engines/lastexpress/entities/anna.cpp +++ b/engines/lastexpress/entities/anna.cpp @@ -34,9 +34,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -200,16 +198,17 @@ IMPLEMENT_FUNCTION(12, Anna, function12) params->param2 = 1; if (params->param6) { - UPDATE_PARAM_PROC(params->param7, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param7, getState()->timeTicks, 75)) { getSavePoints()->push(kEntityAnna, kEntityAnna, kActionEndSound); params->param6 = 0; params->param7 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param4) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75)) + break; params->param4 = 0; params->param5 = 1; @@ -227,7 +226,7 @@ IMPLEMENT_FUNCTION(12, Anna, function12) case kActionEndSound: if (params->param2) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -289,7 +288,7 @@ IMPLEMENT_FUNCTION(12, Anna, function12) getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand); getObjects()->update(kObject53, kEntityAnna, kObjectLocation1, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -424,12 +423,13 @@ IMPLEMENT_FUNCTION_IS(15, Anna, function15, TimeValue) getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); getObjects()->update(kObject53, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param5) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75)) + break; params->param5 = 0; params->param6 = 1; @@ -547,7 +547,7 @@ IMPLEMENT_FUNCTION(16, Anna, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Anna, setup_chapter1Handler)); break; case kActionDefault: @@ -577,7 +577,7 @@ IMPLEMENT_FUNCTION_II(17, Anna, function17, uint32, uint32) if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -615,7 +615,7 @@ IMPLEMENT_FUNCTION_II(17, Anna, function17, uint32, uint32) } if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -664,20 +664,21 @@ IMPLEMENT_FUNCTION_I(18, Anna, function18, TimeValue) case kActionNone: if (params->param1 && params->param1 < getState()->time && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param5 && !params->param4) { - UPDATE_PARAM_PROC(params->param6, getState()->time, 900) + if (Entity::updateParameter(params->param6, getState()->time, 900)) { params->param2 |= kItemScarf; params->param5 = 0; params->param6 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param3) { - UPDATE_PARAM(params->param7, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param7, getState()->timeTicks, 90)) + break; getScenes()->loadSceneFromPosition(kCarRestaurant, 61); } else { @@ -757,7 +758,7 @@ IMPLEMENT_FUNCTION_I(18, Anna, function18, TimeValue) case kAction259136835: case kAction268773672: getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -1151,15 +1152,16 @@ IMPLEMENT_FUNCTION(29, Anna, function29) case kActionNone: if (params->param2) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 900) + if (Entity::updateParameter(params->param3, getState()->time, 900)) { getData()->inventoryItem = (InventoryItem)(getData()->inventoryItem | kItemScarf); params->param2 = 0; params->param3 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param1) { - UPDATE_PARAM(params->param4, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 90)) + break; getScenes()->loadSceneFromPosition(kCarRestaurant, 55); } else { @@ -1281,7 +1283,9 @@ IMPLEMENT_FUNCTION(30, Anna, function30) } if (params->param1) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 90)) + break; + getScenes()->loadSceneFromPosition(kCarRestaurant, 55); } else { params->param5 = 0; @@ -1411,15 +1415,15 @@ IMPLEMENT_FUNCTION(34, Anna, function34) case kActionNone: if (!params->param1 && getEntities()->isPlayerPosition(kCarRedSleeping, 60)) { - UPDATE_PARAM_PROC(params->param2, getState()->time, 150) + if (Entity::updateParameter(params->param2, getState()->time, 150)) { setCallback(1); setup_draw("419B"); break; - UPDATE_PARAM_PROC_END + } } label_callback_1: - TIME_CHECK(kTime1489500, params->param3, setup_function35); + Entity::timeCheck(kTime1489500, params->param3, WRAP_SETUP_FUNCTION(Anna, setup_function35)); break; case kActionKnock: @@ -1485,7 +1489,8 @@ IMPLEMENT_FUNCTION(35, Anna, function35) if (!params->param1) break; - UPDATE_PARAM(params->param3, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75)) + break; switch (params->param2) { default: @@ -1666,7 +1671,7 @@ IMPLEMENT_FUNCTION_II(39, Anna, function39, CarIndex, EntityPosition) if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -1687,7 +1692,7 @@ IMPLEMENT_FUNCTION_II(39, Anna, function39, CarIndex, EntityPosition) if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -1799,7 +1804,8 @@ IMPLEMENT_FUNCTION(41, Anna, function41) break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, 2700); + if (!Entity::updateParameter(params->param2, getState()->time, 2700)) + break; params->param5++; switch (params->param5) { @@ -1985,7 +1991,7 @@ IMPLEMENT_FUNCTION_I(45, Anna, function45, bool) case 2: getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF, true); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2092,11 +2098,11 @@ IMPLEMENT_FUNCTION(48, Anna, function48) break; if (params->param3 != kTimeInvalid && getState()->time > kTime1969200) { - UPDATE_PARAM_PROC_TIME(kTime1983600, (!getEntities()->isInRestaurant(kEntityPlayer) || getSoundQueue()->isBuffered(kEntityBoutarel)), params->param3, 150) + if (Entity::updateParameterTime(kTime1983600, (!getEntities()->isInRestaurant(kEntityPlayer) || getSoundQueue()->isBuffered(kEntityBoutarel)), params->param3, 150)) { setCallback(3); setup_playSound("Aug3007A"); break; - UPDATE_PARAM_PROC_END + } } label_callback_4: @@ -2195,7 +2201,7 @@ IMPLEMENT_FUNCTION(49, Anna, leaveTableWithAugust) getSavePoints()->push(kEntityAnna, kEntityTables3, kActionDrawTablesWithChairs, "010M"); getEntities()->clearSequences(kEntityAugust); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -2386,22 +2392,23 @@ IMPLEMENT_FUNCTION(53, Anna, function53) case kActionNone: if (getProgress().field_48 && params->param5 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(kTime2065500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param5, 150) + if (Entity::updateParameterTime(kTime2065500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param5, 150)) { setup_function54(); break; - UPDATE_PARAM_PROC_END + } } if (params->param3) { - UPDATE_PARAM_PROC(params->param6, getState()->time, 9000) + if (Entity::updateParameter(params->param6, getState()->time, 9000)) { params->param4 = !params->param4; getEntities()->drawSequenceLeft(kEntityAnna, params->param4 ? "417B" : "417A"); params->param6 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param1) { - UPDATE_PARAM(params->param7, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param7, getState()->timeTicks, 75)) + break; CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal; @@ -2537,17 +2544,19 @@ IMPLEMENT_FUNCTION(54, Anna, function54) case kActionNone: if (params->param3) { - TIME_CHECK(kTime2079000, params->param5, setup_function55); + if (Entity::timeCheck(kTime2079000, params->param5, WRAP_SETUP_FUNCTION(Anna, setup_function55))) + break; - UPDATE_PARAM_PROC(params->param6, getState()->time, 9000) + if (Entity::updateParameter(params->param6, getState()->time, 9000)) { params->param4 = !params->param4; getEntities()->drawSequenceLeft(kEntityAnna, params->param4 ? "417B" : "417A"); params->param6 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param1) { - UPDATE_PARAM(params->param7, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param7, getState()->timeTicks, 75)) + break; CursorStyle cursor = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal; @@ -2894,7 +2903,8 @@ IMPLEMENT_FUNCTION(59, Anna, function59) } if (params->param1) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; CursorStyle style = getEntities()->isInsideCompartment(kEntityMax, kCarRedSleeping, kPosition_4070) ? kCursorHand : kCursorNormal; getObjects()->update(kObjectCompartmentF, kEntityAnna, kObjectLocation1, kCursorNormal, style); @@ -3040,7 +3050,7 @@ IMPLEMENT_FUNCTION(60, Anna, function60) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityAnna); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3268,7 +3278,8 @@ IMPLEMENT_FUNCTION(67, Anna, chapter4Handler) case kActionNone: if (getEntities()->isPlayerPosition(kCarRedSleeping, 46)) { - UPDATE_PARAM_GOTO(params->param4, getState()->timeTicks, 30, label_next); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 30)) + goto label_next; getScenes()->loadSceneFromPosition(kCarRedSleeping, 8); } @@ -3277,7 +3288,8 @@ IMPLEMENT_FUNCTION(67, Anna, chapter4Handler) label_next: if (params->param1) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; @@ -3407,7 +3419,8 @@ IMPLEMENT_FUNCTION(69, Anna, function69) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param2, getState()->time, 4500); + if (!Entity::updateParameter(params->param2, getState()->time, 4500)) + break; getData()->car = kCarRedSleeping; getData()->entityPosition = kPosition_9270; @@ -3417,7 +3430,7 @@ IMPLEMENT_FUNCTION(69, Anna, function69) break; } - TIME_CHECK_CALLBACK(kTime2535300, params->param3, 4, setup_callbackActionRestaurantOrSalon); + Entity::timeCheckCallback(kTime2535300, params->param3, 4, WRAP_SETUP_FUNCTION(Anna, setup_callbackActionRestaurantOrSalon)); break; case kActionDefault: @@ -3533,7 +3546,7 @@ IMPLEMENT_FUNCTION(71, Anna, function71) getEntities()->exitCompartment(kEntityAnna, kObjectCompartmentF); getData()->entityPosition = kPosition_4070; - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -3589,7 +3602,7 @@ IMPLEMENT_FUNCTION_II(72, Anna, function72, CarIndex, EntityPosition) if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -3602,7 +3615,7 @@ IMPLEMENT_FUNCTION_II(72, Anna, function72, CarIndex, EntityPosition) case kActionDefault: if (getEntities()->updateEntity(kEntityAnna, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); } else if (!getEvent(kEventAnnaTired)) getData()->inventoryItem = kItemInvalid; break; @@ -3911,7 +3924,8 @@ IMPLEMENT_FUNCTION(80, Anna, function80) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->timeTicks, 450); + if (!Entity::updateParameter(params->param1, getState()->timeTicks, 450)) + break; getSound()->playSound(kEntityPlayer, "Kro5001", kFlagDefault); break; @@ -3980,7 +3994,8 @@ IMPLEMENT_FUNCTION(81, Anna, finalSequence) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->timeTicks, 180); + if (!Entity::updateParameter(params->param1, getState()->timeTicks, 180)) + break; getSound()->playSound(kEntityTrain, "LIB069"); getLogic()->gameOver(kSavegameTypeIndex, 2, kSceneNone, true); diff --git a/engines/lastexpress/entities/anna.h b/engines/lastexpress/entities/anna.h index 72c6db4bd9..205ff9d42c 100644 --- a/engines/lastexpress/entities/anna.h +++ b/engines/lastexpress/entities/anna.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_ANNA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp index cfde8a2d6f..dbae7bad20 100644 --- a/engines/lastexpress/entities/august.cpp +++ b/engines/lastexpress/entities/august.cpp @@ -36,9 +36,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -150,7 +148,7 @@ IMPLEMENT_FUNCTION_END IMPLEMENT_FUNCTION_SI(7, August, enterExitCompartment3, ObjectIndex) if (savepoint.action == kAction4) { getEntities()->exitCompartment(kEntityAugust, (ObjectIndex)params->param4); - CALLBACK_ACTION(); + callbackAction(); return; } @@ -177,7 +175,7 @@ IMPLEMENT_FUNCTION_IIS(10, August, callSavepointNoDrawing, EntityIndex, ActionIn if (!params->param6) getSavePoints()->call(kEntityAugust, (EntityIndex)params->param1, (ActionIndex)params->param2, (char *)¶ms->seq); - CALLBACK_ACTION(); + callbackAction(); break; case kAction10: @@ -233,7 +231,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue) case kActionNone: if (params->param1 < getState()->time && !params->param2) { params->param2 = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -262,7 +260,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue) case 1: if (ENTITY_PARAM(0, 1)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -272,7 +270,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue) case 2: case 3: if (ENTITY_PARAM(0, 1)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -289,7 +287,7 @@ IMPLEMENT_FUNCTION_I(17, August, function17, TimeValue) case 5: if (ENTITY_PARAM(0, 1)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -308,7 +306,7 @@ IMPLEMENT_FUNCTION_II(18, August, updateEntity2, CarIndex, EntityPosition) case kActionNone: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); } else if (getEntities()->isDistanceBetweenEntities(kEntityAugust, kEntityPlayer, 1000) && !getEntities()->isInGreenCarEntrance(kEntityPlayer) && !getEntities()->isInsideCompartments(kEntityPlayer) @@ -316,14 +314,14 @@ IMPLEMENT_FUNCTION_II(18, August, updateEntity2, CarIndex, EntityPosition) if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) { ENTITY_PARAM(0, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); } } break; case kActionDefault: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -407,7 +405,7 @@ IMPLEMENT_FUNCTION_II(19, August, function19, bool, bool) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityAugust); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -503,7 +501,7 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool) getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); getEntities()->exitCompartment(kEntityAugust, kObjectCompartment3, true); - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -520,12 +518,13 @@ IMPLEMENT_FUNCTION_I(21, August, function21, TimeValue) getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param2) { - UPDATE_PARAM_GOTO(params->param8, getState()->timeTicks, 75, label_continue); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75)) + goto label_continue; params->param2 = 0; params->param3 = 1; @@ -540,10 +539,10 @@ label_continue: break; if (params->param6) { - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 6300) + if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->time, 6300)) { params->param6 = 0; CURRENT_PARAM(1, 1) = 0; - UPDATE_PARAM_PROC_END + } } if (!params->param4 @@ -753,7 +752,7 @@ IMPLEMENT_FUNCTION(22, August, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(August, setup_chapter1Handler)); break; case kActionDefault: @@ -786,7 +785,7 @@ IMPLEMENT_FUNCTION_I(23, August, function23, TimeValue) } else { getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true); getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -806,7 +805,7 @@ IMPLEMENT_FUNCTION_I(23, August, function23, TimeValue) } label_callback_8: - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->timeTicks, 75) + if (Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->timeTicks, 75)) { getEntities()->exitCompartment(kEntityAugust, kObjectCompartment1, true); if (getProgress().eventCorpseMovedFromFloor) { @@ -822,7 +821,7 @@ label_callback_8: setup_savegame(kSavegameTypeEvent, kEventAugustFindCorpse); } break; - UPDATE_PARAM_PROC_END + } label_callback_9: if (params->param3 && params->param1 < getState()->time && !CURRENT_PARAM(1, 5)) { @@ -842,7 +841,8 @@ label_callback_9: break; if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) { - UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75); + if (!Entity::updateParameter(CURRENT_PARAM(1, 2), getState()->timeTicks, 75)) + break; getObjects()->update(kObjectCompartment1, kEntityAugust, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal); @@ -867,7 +867,7 @@ label_callback_9: if (params->param8 >= 3) { getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -959,7 +959,7 @@ label_callback_9: case 2: getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -986,7 +986,7 @@ label_callback_9: getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; case 5: @@ -1028,7 +1028,7 @@ label_callback_9: case 12: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 13: @@ -1056,7 +1056,7 @@ label_callback_9: getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; case 15: @@ -1096,7 +1096,7 @@ IMPLEMENT_FUNCTION(24, August, dinner) getScenes()->loadSceneFromPosition(kCarRestaurant, 61); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -1485,7 +1485,8 @@ IMPLEMENT_FUNCTION(30, August, restaurant) break; case kActionNone: - UPDATE_PARAM(params->param3, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75)) + break; getData()->inventoryItem = kItemInvalid; break; @@ -1634,9 +1635,9 @@ IMPLEMENT_FUNCTION(32, August, function32) break; case kActionNone: - UPDATE_PARAM_PROC_TIME(kTime1179000, (!getEntities()->isInSalon(kEntityAnna) || getEntities()->isInSalon(kEntityPlayer)), params->param6, 0); + if (Entity::updateParameterTime(kTime1179000, (!getEntities()->isInSalon(kEntityAnna) || getEntities()->isInSalon(kEntityPlayer)), params->param6, 0)) { getSavePoints()->push(kEntityAugust, kEntityAnna, kAction123712592); - UPDATE_PARAM_PROC_END + } if (params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { if (!params->param4) { @@ -1645,18 +1646,19 @@ IMPLEMENT_FUNCTION(32, August, function32) } if (params->param7 != kTimeInvalid && params->param4 < getState()->time) { - UPDATE_PARAM_PROC_TIME(params->param5, getEntities()->isInSalon(kEntityPlayer), params->param7, 0); + if (Entity::updateParameterTime((TimeValue)params->param5, getEntities()->isInSalon(kEntityPlayer), params->param7, 0)) { getData()->location = kLocationOutsideCompartment; setCallback(5); setup_updatePosition("109D", kCarRestaurant, 56); break; - UPDATE_PARAM_PROC_END + } } } if (params->param3) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 90)) + break; getScenes()->loadSceneFromPosition(kCarRestaurant, 55); } else { @@ -1813,7 +1815,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704); + Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704); if (getState()->time > kTime1773000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->inventoryItem = kItemNone; @@ -1904,7 +1906,7 @@ IMPLEMENT_FUNCTION(37, August, function37) break; case kActionNone: - TIME_CHECK_CALLBACK_1(kTime1791000, params->param2, 5, setup_function20, true); + Entity::timeCheckCallback(kTime1791000, params->param2, 5, true, WRAP_SETUP_FUNCTION_B(August, setup_function20)); break; case kActionDefault: @@ -1962,9 +1964,9 @@ IMPLEMENT_FUNCTION(38, August, function38) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1801800, params->param1, kEntityAugust, kEntityRebecca, kAction155980128); + Entity::timeCheckSavepoint(kTime1801800, params->param1, kEntityAugust, kEntityRebecca, kAction155980128); - TIME_CHECK_CALLBACK(kTime1820700, params->param2, 3, setup_callbackActionRestaurantOrSalon); + Entity::timeCheckCallback(kTime1820700, params->param2, 3, WRAP_SETUP_FUNCTION(August, setup_callbackActionRestaurantOrSalon)); break; case kActionDefault: @@ -2110,7 +2112,7 @@ IMPLEMENT_FUNCTION_II(41, August, function41, CarIndex, EntityPosition) getData()->inventoryItem = kItemNone; if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -2147,7 +2149,7 @@ IMPLEMENT_FUNCTION_II(41, August, function41, CarIndex, EntityPosition) case kActionDefault: if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -2172,7 +2174,7 @@ IMPLEMENT_FUNCTION_III(42, August, function42, CarIndex, EntityPosition, bool) if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -2191,7 +2193,7 @@ IMPLEMENT_FUNCTION_III(42, August, function42, CarIndex, EntityPosition, bool) case kActionDefault: if (getEntities()->updateEntity(kEntityAugust, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -2212,7 +2214,7 @@ IMPLEMENT_FUNCTION(43, August, chapter3Handler) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1953000, params->param2, kEntityAugust, kEntityAnna, kAction291662081); + Entity::timeCheckSavepoint(kTime1953000, params->param2, kEntityAugust, kEntityAnna, kAction291662081); // Set as same position as Anna if (params->param1) { @@ -2402,7 +2404,7 @@ IMPLEMENT_FUNCTION_END IMPLEMENT_FUNCTION(46, August, function46) switch (savepoint.action) { default: - TIME_CHECK_CALLBACK(kTime2088000, params->param1, 1, setup_function47); + Entity::timeCheckCallback(kTime2088000, params->param1, 1, WRAP_SETUP_FUNCTION(August, setup_function47)); break; case kActionNone: @@ -2473,7 +2475,7 @@ IMPLEMENT_FUNCTION(47, August, function47) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2487,7 +2489,7 @@ IMPLEMENT_FUNCTION(48, August, function48) break; case kActionNone: - TIME_CHECK(kTimeCityLinz, params->param1, setup_function49); + Entity::timeCheck(kTimeCityLinz, params->param1, WRAP_SETUP_FUNCTION(August, setup_function49)); break; case kActionKnock: @@ -2770,7 +2772,8 @@ IMPLEMENT_FUNCTION(54, August, function54) getData()->inventoryItem = kItemInvalid; if (!params->param2 && params->param1) { - UPDATE_PARAM(params->param5, getState()->time, params->param1); + if (!Entity::updateParameter(params->param5, getState()->time, params->param1)) + break; getData()->inventoryItem = kItemNone; setup_function55(); @@ -3046,7 +3049,8 @@ IMPLEMENT_FUNCTION(60, August, function60) if (!params->param1) break; - UPDATE_PARAM(params->param3, getState()->time, 9000); + if (!Entity::updateParameter(params->param3, getState()->time, 9000)) + break; setCallback(1); setup_callbackActionRestaurantOrSalon(); @@ -3142,7 +3146,8 @@ IMPLEMENT_FUNCTION(62, August, function62) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 900); + if (!Entity::updateParameter(params->param1, getState()->time, 900)) + break; getSound()->playSound(kEntityAugust, "Aug4003A"); @@ -3220,9 +3225,9 @@ IMPLEMENT_FUNCTION(63, August, function63) break; case kActionNone: - UPDATE_PARAM_PROC(params->param3, getState()->time, 1800) + if (Entity::updateParameter(params->param3, getState()->time, 1800)) { getData()->inventoryItem = kItemInvalid; - UPDATE_PARAM_PROC_END + } if (getState()->time > kTime2488500 && !params->param4) { params->param4 = 1; @@ -3231,7 +3236,8 @@ IMPLEMENT_FUNCTION(63, August, function63) break; } - UPDATE_PARAM(params->param5, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, params->param1)) + break; params->param2 = (params->param6 < 1 ? 1 : 0); @@ -3388,7 +3394,8 @@ IMPLEMENT_FUNCTION(68, August, function68) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param4, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; @@ -3523,7 +3530,7 @@ IMPLEMENT_FUNCTION(69, August, unhookCars) getScenes()->loadSceneFromPosition(kCarRestaurant, 85, 1); getSavePoints()->pushAll(kEntityAugust, kActionProceedChapter5); - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function42) + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_end) } break; } diff --git a/engines/lastexpress/entities/august.h b/engines/lastexpress/entities/august.h index 2cbb31b968..606321955b 100644 --- a/engines/lastexpress/entities/august.h +++ b/engines/lastexpress/entities/august.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_AUGUST_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/boutarel.cpp b/engines/lastexpress/entities/boutarel.cpp index 315b12a69e..219ddf901b 100644 --- a/engines/lastexpress/entities/boutarel.cpp +++ b/engines/lastexpress/entities/boutarel.cpp @@ -32,9 +32,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -231,7 +229,7 @@ IMPLEMENT_FUNCTION_I(11, Boutarel, function11, bool) case 7: getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -249,7 +247,7 @@ IMPLEMENT_FUNCTION(12, Boutarel, enterTableWithMmeBoutarel) getSavePoints()->push(kEntityBoutarel, kEntityTables2, kAction136455232); getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -276,7 +274,7 @@ IMPLEMENT_FUNCTION(13, Boutarel, leaveTableWithMmeBoutarel) getSavePoints()->push(kEntityBoutarel, kEntityTables2, kActionDrawTablesWithChairs, "008F"); getEntities()->clearSequences(kEntityMmeBoutarel); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -358,7 +356,7 @@ IMPLEMENT_FUNCTION_I(14, Boutarel, function14, bool) getEntities()->clearSequences(kEntityBoutarel); getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -416,7 +414,7 @@ IMPLEMENT_FUNCTION_IS(15, Boutarel, function15, bool) case 5: getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -464,7 +462,7 @@ IMPLEMENT_FUNCTION_IS(16, Boutarel, function16, bool) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityBoutarel); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -478,10 +476,13 @@ IMPLEMENT_FUNCTION_IS(17, Boutarel, function17, TimeValue) break; case kActionNone: - TIME_CHECK_CALLBACK_ACTION(params->param1, params->param6); + if (Entity::timeCheckCallbackAction((TimeValue)params->param1, params->param6)) + break; if (params->param5) { - UPDATE_PARAM(params->param7, getState()->timeTicks, 90) + if (!Entity::updateParameter(params->param7, getState()->timeTicks, 90)) + break; + getScenes()->loadSceneFromPosition(kCarRestaurant, 51); } else { params->param7 = 0; @@ -511,12 +512,13 @@ IMPLEMENT_FUNCTION_I(18, Boutarel, function18, TimeValue) getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param2) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param2 = 0; params->param3 = 1; @@ -615,7 +617,7 @@ IMPLEMENT_FUNCTION(19, Boutarel, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_chapter1Handler)); break; case kActionDefault: @@ -644,14 +646,14 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20) break; if (!params->param2) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 4500) + if (Entity::updateParameter(params->param3, getState()->time, 4500)) { setCallback(3); setup_playSound("MRB1078A"); break; - UPDATE_PARAM_PROC_END + } } - TIME_CHECK_CALLBACK_1(kTime1138500, params->param4, 4, setup_function14, false); + Entity::timeCheckCallback(kTime1138500, params->param4, 4, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case kActionDefault: @@ -676,13 +678,13 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20) break; case 3: - TIME_CHECK_CALLBACK_1(kTime1138500, params->param4, 4, setup_function14, false); + Entity::timeCheckCallback(kTime1138500, params->param4, 4, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case 4: getSavePoints()->push(kEntityBoutarel, kEntityCooks, kAction224849280); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -834,7 +836,7 @@ IMPLEMENT_FUNCTION(24, Boutarel, chapter2Handler) break; case kActionNone: - TIME_CHECK_CALLBACK_1(kTime1759500, params->param2, 1, setup_function14, false); + Entity::timeCheckCallback(kTime1759500, params->param2, 1, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case kActionDefault: @@ -934,9 +936,9 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29) break; case kActionNone: - UPDATE_PARAM_PROC(params->param2, getState()->time, 450) + if (Entity::updateParameter(params->param2, getState()->time, 450)) { getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848); - UPDATE_PARAM_PROC_END + } if (!params->param1) break; @@ -959,7 +961,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29) } } - TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true); + Entity::timeCheckCallback(kTime2002500, params->param4, 1, true, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case kActionDefault: @@ -972,7 +974,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29) break; case 1: - TIME_CHECK_CALLBACK_1(kTime2002500, params->param4, 1, setup_function14, true); + Entity::timeCheckCallback(kTime2002500, params->param4, 1, true, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case 2: @@ -1045,7 +1047,7 @@ IMPLEMENT_FUNCTION(32, Boutarel, chapter4Handler) break; case kActionNone: - TIME_CHECK(kTime2367000, params->param1, setup_function33); + Entity::timeCheck(kTime2367000, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_function33)); break; case kActionDefault: @@ -1063,7 +1065,7 @@ IMPLEMENT_FUNCTION(33, Boutarel, function33) case kActionNone: if (params->param1) - TIME_CHECK_CALLBACK_1(kTime2389500, params->param2, 3, setup_function14, false); + Entity::timeCheckCallback(kTime2389500, params->param2, 3, false, WRAP_SETUP_FUNCTION_B(Boutarel, setup_function14)); break; case kActionDefault: @@ -1111,7 +1113,8 @@ IMPLEMENT_FUNCTION(34, Boutarel, function34) break; case kActionNone: - TIME_CHECK(kTime2470500, params->param1, setup_function35); + if (Entity::timeCheck(kTime2470500, params->param1, WRAP_SETUP_FUNCTION(Boutarel, setup_function35))) + break; if (getState()->time > kTime2457000 && getEvent(kEventAugustDrink)) { getSavePoints()->push(kEntityBoutarel, kEntityAbbot, kAction159003408); diff --git a/engines/lastexpress/entities/boutarel.h b/engines/lastexpress/entities/boutarel.h index 5eb264631c..04838f6527 100644 --- a/engines/lastexpress/entities/boutarel.h +++ b/engines/lastexpress/entities/boutarel.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_BOUTAREL_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp index 4ef2dc50e8..d373432710 100644 --- a/engines/lastexpress/entities/chapters.cpp +++ b/engines/lastexpress/entities/chapters.cpp @@ -63,11 +63,9 @@ #include "lastexpress/game/state.h" #include "lastexpress/menu/menu.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -152,7 +150,7 @@ IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities) RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_reset); RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_reset); - CALLBACK_ACTION(); + callbackAction(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -191,7 +189,7 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End) getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); } else { getSound()->playSound(kEntityPlayer, "LIB014"); getSound()->playSound(kEntityPlayer, "LIB015", kFlagDefault, 15); @@ -386,12 +384,6 @@ IMPLEMENT_FUNCTION(7, Chapters, chapter1Init) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -#define PLAY_STEAM() { \ - getSoundQueue()->resetState(); \ - getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); \ - ENTITY_PARAM(0, 2) = 0; \ - } - IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler) switch (savepoint.action) { default: @@ -401,21 +393,28 @@ IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler) if (!getProgress().isTrainRunning || getState()->time >= kTime1458000) goto label_processStations; - UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param2) + if (Entity::updateParameter(params->param6, getState()->timeTicks, params->param2)) { // Play sound FX getSound()->playLocomotiveSound(); params->param2 = 225 * (4 * rnd(5) + 20); params->param6 = 0; - UPDATE_PARAM_PROC_END + } label_processStations: // Process stations - TIME_CHECK_CALLBACK_2(kTime1039500, params->param7, 1, setup_savegame, kSavegameTypeTime, kTimeNone); + if (getState()->time > kTime1039500 && !params->param7) { + params->param7 = 1; + setCallback(1); + setup_savegame(kSavegameTypeTime, kTimeNone); + + break; + } label_enter_epernay: // Entering Epernay station - TIME_CHECK_CALLBACK_2(kTimeEnterEpernay, params->param8, 1, setup_enterStation, "Epernay", kCityEpernay); + if (timeCheckEnterStation(kTimeEnterEpernay, params->param8, 1, "Epernay", kCityEpernay)) + break; label_exit_epernay: // Exiting Epernay station @@ -445,19 +444,23 @@ label_enter_chalons: goto label_exit_strasbourg; // Entering Chalons station - TIME_CHECK_CALLBACK_2(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, setup_enterStation, "Chalons", kCityChalons); + if (timeCheckEnterStation(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, "Chalons", kCityChalons)) + break; label_exit_chalons: // Exiting Chalons station - TIME_CHECK_CALLBACK_1(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, setup_exitStation, "Chalons"); + if (timeCheckExitStation(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, "Chalons")) + break; label_enter_barleduc: // Entering Bar-Le-Duc station - TIME_CHECK_CALLBACK_2(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, setup_enterStation, "BarLeDuc", kCityBarleduc); + if (timeCheckEnterStation(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, "BarLeDuc", kCityBarleduc)) + break; label_exit_barleduc: // Exiting Bar-Le-Duc station - TIME_CHECK_CALLBACK_1(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, setup_exitStation, "BarLeDuc"); + if (timeCheckExitStation(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, "BarLeDuc")) + break; label_enter_nancy: if (getState()->time > kTime1260000 && !CURRENT_PARAM(1, 7)) { @@ -466,50 +469,67 @@ label_enter_nancy: } // Entering Nancy station - TIME_CHECK_CALLBACK_2(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, setup_enterStation, "Nancy", kCityNancy); + if (timeCheckEnterStation(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, "Nancy", kCityNancy)) + break; label_exit_nancy: // Exiting Nancy station - TIME_CHECK_CALLBACK_1(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, setup_exitStation, "Nancy"); + if (timeCheckExitStation(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, "Nancy")) + break; label_enter_luneville: // Entering Luneville station - TIME_CHECK_CALLBACK_2(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, setup_enterStation, "Luneville", kCityLuneville); + if (timeCheckEnterStation(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, "Luneville", kCityLuneville)) + break; label_exit_luneville: // Exiting Luneville station - TIME_CHECK_CALLBACK_1(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, setup_exitStation, "Luneville"); + if (timeCheckExitStation(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, "Luneville")) + break; label_enter_avricourt: // Entering Avricourt station - TIME_CHECK_CALLBACK_2(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, setup_enterStation, "Avricourt", kCityAvricourt); + if (timeCheckEnterStation(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, "Avricourt", kCityAvricourt)) + break; label_exit_avricourt: // Exiting Avricourt station - TIME_CHECK_CALLBACK_1(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, setup_exitStation, "Avricourt"); + if (timeCheckExitStation(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, "Avricourt")) + break; label_enter_deutschavricourt: // Entering Deutsch-Avricourt station - TIME_CHECK_CALLBACK_2(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, setup_enterStation, "DeutschA", kCityDeutschAvricourt); + if (timeCheckEnterStation(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, "DeutschA", kCityDeutschAvricourt)) + break; label_exit_deutschavricourt: // Exiting Avricourt station - TIME_CHECK_CALLBACK_1(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, setup_exitStation, "DeutschA"); + if (timeCheckExitStation(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, "DeutschA")) + break; label_enter_strasbourg: - TIME_CHECK_CALLBACK_2(kTimeCityStrasbourg, CURRENT_PARAM(2, 8), 17, setup_savegame, kSavegameTypeTime, kTimeNone); + if (getState()->time > kTimeCityStrasbourg && !CURRENT_PARAM(2, 8)) { + CURRENT_PARAM(2, 8) = 1; + setCallback(17); + setup_savegame(kSavegameTypeTime, kTimeNone); + + break; + } label_exit_strasbourg: // Exiting Strasbourg station - TIME_CHECK_CALLBACK_1(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, setup_exitStation, "Strasbou"); + if (timeCheckExitStation(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, "Strasbou")) + break; label_enter_badenoos: // Entering Baden Oos station - TIME_CHECK_CALLBACK_2(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, setup_enterStation, "BadenOos", kCityBadenOos); + if (timeCheckEnterStation(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, "BadenOos", kCityBadenOos)) + break; label_exit_badenoos: // Exiting Baden Oos station - TIME_CHECK_CALLBACK_1(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, setup_exitStation, "BadenOos"); + if (timeCheckExitStation(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, "BadenOos")) + break; label_chapter1_next: if (getState()->time > kTimeChapter1End3 && ! CURRENT_PARAM(3, 4)) { @@ -524,43 +544,43 @@ label_chapter1_next: getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning); if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) { - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isOutsideAlexeiWindow()) { getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49); - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isOutsideAnnaWindow()) { getScenes()->loadSceneFromPosition(kCarRedSleeping, 49); - PLAY_STEAM(); + playSteam(); break; } CarIndex car = getEntityData(kEntityPlayer)->car; if (car < kCarRedSleeping || car > kCarCoalTender) { if (car < kCarBaggageRear || car > kCarGreenSleeping) { - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) { getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71); - PLAY_STEAM(); + playSteam(); break; } getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82); - PLAY_STEAM(); + playSteam(); break; } getScenes()->loadSceneFromPosition(kCarRestaurant, 82); - PLAY_STEAM(); + playSteam(); break; } @@ -817,7 +837,8 @@ IMPLEMENT_FUNCTION(12, Chapters, chapter2Handler) if (!getProgress().isTrainRunning) break; - UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1)) + break; getSound()->playLocomotiveSound(); @@ -903,15 +924,15 @@ IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler) case kActionNone: if (getProgress().isTrainRunning) { - UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, params->param1) + if (Entity::updateParameter(params->param4, getState()->timeTicks, params->param1)) { getSound()->playLocomotiveSound(); params->param1 = 225 * (4 * rnd(5) + 20); params->param4 = 0; - UPDATE_PARAM_PROC_END + } } - UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, params->param2) + if (Entity::updateParameter(params->param5, getState()->timeTicks, params->param2)) { switch (rnd(2)) { default: break; @@ -927,30 +948,38 @@ IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler) params->param2 = 225 * (4 * rnd(6) + 8); params->param5 = 0; - UPDATE_PARAM_PROC_END + } - TIME_CHECK_CALLBACK_2(kTimeEnterSalzbourg, params->param6, 1, setup_enterStation, "Salzburg", kCitySalzbourg); + if (timeCheckEnterStation(kTimeEnterSalzbourg, params->param6, 1, "Salzburg", kCitySalzbourg)) + break; label_callback_1: - TIME_CHECK_CALLBACK_1(kTimeExitSalzbourg, params->param7, 2, setup_exitStation, "Salzburg"); + if (timeCheckExitStation(kTimeExitSalzbourg, params->param7, 2, "Salzburg")) + break; label_callback_2: - TIME_CHECK_CALLBACK_2(kTimeEnterAttnangPuchheim, params->param8, 3, setup_enterStation, "Attnang", kCityAttnangPuchheim); + if (timeCheckEnterStation(kTimeEnterAttnangPuchheim, params->param8, 3, "Attnang", kCityAttnangPuchheim)) + break; label_callback_3: - TIME_CHECK_CALLBACK_1(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, setup_exitStation, "Attnang"); + if (timeCheckExitStation(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, "Attnang")) + break; label_callback_4: - TIME_CHECK_CALLBACK_2(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, setup_enterStation, "Wels", kCityWels); + if (timeCheckEnterStation(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, "Wels", kCityWels)) + break; label_callback_5: - TIME_CHECK_CALLBACK_1(kTimeEnterWels, CURRENT_PARAM(1, 3), 6, setup_exitStation, "Wels"); + if (timeCheckExitStation(kTimeEnterWels, CURRENT_PARAM(1, 3), 6, "Wels")) + break; label_callback_6: - TIME_CHECK_CALLBACK_2(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, setup_enterStation, "Linz", kCityLinz); + if (timeCheckEnterStation(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, "Linz", kCityLinz)) + break; label_callback_7: - TIME_CHECK_CALLBACK_1(kTimeCityLinz, CURRENT_PARAM(1, 5), 8, setup_exitStation, "Linz"); + if (timeCheckExitStation(kTimeCityLinz, CURRENT_PARAM(1, 5), 8, "Linz")) + break; label_callback_8: if (getState()->time > kTime2187000 && !CURRENT_PARAM(1, 6)) { @@ -958,7 +987,7 @@ label_callback_8: getState()->timeDelta = 5; } - TIME_CHECK_CALLBACK_2(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, setup_enterStation, "Vienna", kCityVienna); + timeCheckEnterStation(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, "Vienna", kCityVienna); break; case kActionEndSound: @@ -1202,15 +1231,15 @@ IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler) case kActionNone: if (getProgress().isTrainRunning) { - UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, params->param4); + if (Entity::updateParameter(params->param6, getState()->timeTicks, params->param4)) { getSound()->playLocomotiveSound(); params->param4 = 225 * (4 * rnd(5) + 20); params->param6 = 0; - UPDATE_PARAM_PROC_END + } } - UPDATE_PARAM_PROC(params->param7, getState()->timeTicks, params->param5) + if (Entity::updateParameter(params->param7, getState()->timeTicks, params->param5)) { switch (rnd(2)) { default: break; @@ -1226,12 +1255,14 @@ IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler) params->param5 = 225 * (4 * rnd(6) + 8); params->param7 = 0; - UPDATE_PARAM_PROC_END + } - TIME_CHECK_CALLBACK_2(kTimeEnterPoszony, params->param8, 1, setup_enterStation, "Pozsony", kCityPoszony); + if (timeCheckEnterStation(kTimeEnterPoszony, params->param8, 1, "Pozsony", kCityPoszony)) + break; label_exitPozsony: - TIME_CHECK_CALLBACK_1(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, setup_exitStation, "Pozsony"); + if (timeCheckExitStation(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, "Pozsony")) + break; label_enterGalanta: if (getObjects()->get(kObjectCompartment1).location2 == kObjectLocation1) { @@ -1244,10 +1275,12 @@ label_enterGalanta: if (params->param1) goto label_callback_4; - TIME_CHECK_CALLBACK_2(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, setup_enterStation, "Galanta", kCityGalanta); + if (timeCheckEnterStation(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, "Galanta", kCityGalanta)) + break; label_exitGalanta: - TIME_CHECK_CALLBACK_1(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, setup_exitStation, "Galanta"); + if (timeCheckExitStation(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, "Galanta")) + break; label_callback_4: if (getState()->time > kTime2470500 && !CURRENT_PARAM(1, 5)) { @@ -1280,43 +1313,43 @@ label_callback_4: getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning); if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) { - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isOutsideAlexeiWindow()) { getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49); - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isOutsideAnnaWindow()) { getScenes()->loadSceneFromPosition(kCarRedSleeping, 49); - PLAY_STEAM(); + playSteam(); break; } CarIndex car = getEntityData(kEntityPlayer)->car; if (car < kCarRedSleeping || car > kCarCoalTender) { if (car < kCarBaggageRear || car > kCarGreenSleeping) { - PLAY_STEAM(); + playSteam(); break; } if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) { getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71); - PLAY_STEAM(); + playSteam(); break; } getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82); - PLAY_STEAM(); + playSteam(); break; } getScenes()->loadSceneFromPosition(kCarRestaurant, 82); - PLAY_STEAM(); + playSteam(); break; } @@ -1815,7 +1848,37 @@ void Chapters::enterExitHelper(bool isEnteringStation) { ENTITY_PARAM(0, 3) = 1; } - CALLBACK_ACTION(); + callbackAction(); +} + +void Chapters::playSteam() const { + getSoundQueue()->resetState(); + getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); + ENTITY_PARAM(0, 2) = 0; +} + +bool Chapters::timeCheckEnterStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence, CityIndex cityIndex) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + setup_enterStation(sequence, cityIndex); + + return true; + } + + return false; +} + +bool Chapters::timeCheckExitStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + setup_exitStation(sequence); + + return true; + } + + return false; } } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h index 353d3a6b5b..fb52ea3ee4 100644 --- a/engines/lastexpress/entities/chapters.h +++ b/engines/lastexpress/entities/chapters.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_CHAPTERS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -154,8 +153,11 @@ public: DECLARE_FUNCTION(chapter5Handler) private: + bool timeCheckEnterStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence, CityIndex cityIndex); + bool timeCheckExitStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence); void enterExitStation(const SavePoint &savepoint, bool isEnteringStation); void enterExitHelper(bool isEnteringStation); + void playSteam() const; }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/cooks.cpp b/engines/lastexpress/entities/cooks.cpp index 42e888cc7c..5e8a2df8cb 100644 --- a/engines/lastexpress/entities/cooks.cpp +++ b/engines/lastexpress/entities/cooks.cpp @@ -29,9 +29,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -96,7 +94,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3) case kActionDrawScene: if (!getEntities()->isInKitchen(kEntityPlayer)) { getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -108,7 +106,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3) if (!getEntities()->hasValidFrame(kEntityCooks)) { getSound()->playSound(kEntityCooks, "LIB015"); getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -122,7 +120,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3) if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) { getSound()->playSound(kEntityCooks, "LIB015"); getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); } break; @@ -182,7 +180,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4) case kActionDrawScene: if (!getEntities()->isInKitchen(kEntityPlayer)) { getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -194,7 +192,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4) if (!getEntities()->hasValidFrame(kEntityCooks)) { getSound()->playSound(kEntityCooks, "LIB015"); getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -208,7 +206,7 @@ IMPLEMENT_FUNCTION(4, Cooks, function4) if (params->param1 && !getEntities()->hasValidFrame(kEntityCooks)) { getSound()->playSound(kEntityCooks, "LIB015"); getEntities()->clearSequences(kEntityCooks); - CALLBACK_ACTION(); + callbackAction(); } break; @@ -241,7 +239,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_chapter1Handler)); break; case kActionDefault: @@ -262,7 +260,8 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler) break; case kActionNone: - UPDATE_PARAM(params->param4, getState()->time, params->param2); + if (!Entity::updateParameter(params->param4, getState()->time, params->param2)) + break; // Broken plate sound getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks)); @@ -375,7 +374,8 @@ IMPLEMENT_FUNCTION(9, Cooks, chapter2Handler) break; case kActionNone: - UPDATE_PARAM(params->param3, getState()->time, params->param1); + if (!Entity::updateParameter(params->param3, getState()->time, params->param1)) + break; // Broken plate sound getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks)); @@ -434,12 +434,12 @@ IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler) break; case kActionNone: - UPDATE_PARAM_PROC(params->param4, getState()->time, params->param2) + if (Entity::updateParameter(params->param4, getState()->time, params->param2)) { // Broken plate sound getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks)); params->param2 = 225 * (4 * rnd(30) + 120); params->param4 = 0; - UPDATE_PARAM_PROC_END + } if (getState()->time > kTime2079000 && !params->param5) { params->param1 = 0; @@ -526,7 +526,8 @@ IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler) break; case kActionNone: - UPDATE_PARAM(params->param3, getState()->time, params->param1) + if (!Entity::updateParameter(params->param3, getState()->time, params->param1)) + break; // Broken plate sound getSound()->playSound(kEntityPlayer, "LIB122", getSound()->getSoundFlag(kEntityCooks)); diff --git a/engines/lastexpress/entities/cooks.h b/engines/lastexpress/entities/cooks.h index 3ab7d35161..f01d0b2ca0 100644 --- a/engines/lastexpress/entities/cooks.h +++ b/engines/lastexpress/entities/cooks.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_COOKS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/coudert.cpp b/engines/lastexpress/entities/coudert.cpp index c3e7e37b88..b604277903 100644 --- a/engines/lastexpress/entities/coudert.cpp +++ b/engines/lastexpress/entities/coudert.cpp @@ -32,22 +32,11 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { -#define SAVEGAME_BLOOD_JACKET() \ - if (getProgress().jacket == kJacketBlood \ - && getEntities()->isDistanceBetweenEntities(kEntityCoudert, kEntityPlayer, 1000) \ - && !getEntities()->isInsideCompartments(kEntityPlayer) \ - && !getEntities()->checkFields10(kEntityPlayer)) { \ - setCallback(1); \ - setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket); \ - } - Coudert::Coudert(LastExpressEngine *engine) : Entity(engine, kEntityCoudert) { ADD_CALLBACK_FUNCTION(Coudert, reset); ADD_CALLBACK_FUNCTION(Coudert, bloodJacket); @@ -126,11 +115,11 @@ IMPLEMENT_FUNCTION_S(2, Coudert, bloodJacket) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -153,7 +142,7 @@ IMPLEMENT_FUNCTION_SI(3, Coudert, enterExitCompartment, ObjectIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); return; case kActionCallback: @@ -175,15 +164,15 @@ IMPLEMENT_FUNCTION(4, Coudert, callbackActionOnDirection) case kActionNone: if (getData()->direction != kDirectionRight) { - CALLBACK_ACTION(); + callbackAction(); break; } - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -202,7 +191,7 @@ IMPLEMENT_FUNCTION_SIII(5, Coudert, enterExitCompartment2, ObjectIndex, EntityPo break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); return; case kActionCallback: @@ -223,11 +212,11 @@ IMPLEMENT_FUNCTION_S(6, Coudert, playSound) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -252,11 +241,11 @@ IMPLEMENT_FUNCTION_NOSETUP(7, Coudert, playSound16) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -296,7 +285,7 @@ IMPLEMENT_FUNCTION_II(9, Coudert, updateEntity, CarIndex, EntityPosition) if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -332,7 +321,7 @@ IMPLEMENT_FUNCTION_II(9, Coudert, updateEntity, CarIndex, EntityPosition) params->param3 = kItemInvalid; if (getEntities()->updateEntity(kEntityCoudert, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -365,11 +354,12 @@ IMPLEMENT_FUNCTION_I(10, Coudert, updateFromTime, uint32) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); - UPDATE_PARAM(params->param2, getState()->time, params->param1); + if (!Entity::updateParameter(params->param2, getState()->time, params->param1)) + break; - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -388,11 +378,12 @@ IMPLEMENT_FUNCTION_I(11, Coudert, updateFromTicks, uint32) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); - UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1)) + break; - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -412,7 +403,7 @@ IMPLEMENT_FUNCTION_I(12, Coudert, excuseMe, EntityIndex) return; if (getSoundQueue()->isBuffered(kEntityCoudert)) { - CALLBACK_ACTION(); + callbackAction(); return; } @@ -452,7 +443,7 @@ IMPLEMENT_FUNCTION_I(12, Coudert, excuseMe, EntityIndex) getSound()->playSound(kEntityCoudert, "JAC1112E"); } - CALLBACK_ACTION(); + callbackAction(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -462,7 +453,7 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); if (!params->param2 && !params->param3) { @@ -487,7 +478,8 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex) } } - UPDATE_PARAM(params->param5, getState()->timeTicks, 225); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 225)) + break; getData()->inventoryItem = kItemNone; setCallback(5); @@ -561,7 +553,7 @@ IMPLEMENT_FUNCTION_II(13, Coudert, function13, bool, EntityIndex) case 5: case 6: case 7: - CALLBACK_ACTION(); + callbackAction(); break; case 9: @@ -584,7 +576,7 @@ IMPLEMENT_FUNCTION_I(14, Coudert, function14, EntityIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionDefault: @@ -629,7 +621,7 @@ IMPLEMENT_FUNCTION_I(14, Coudert, function14, EntityIndex) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -706,7 +698,7 @@ IMPLEMENT_FUNCTION_I(15, Coudert, function15, bool) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -724,7 +716,7 @@ IMPLEMENT_FUNCTION(16, Coudert, function16) ENTITY_PARAM(2, 1) = 0; getInventory()->setLocationAndProcess(kItem5, kObjectLocation1); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -743,7 +735,7 @@ IMPLEMENT_FUNCTION(16, Coudert, function16) if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2)) getData()->entityPosition = kPosition_2088; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -761,7 +753,7 @@ IMPLEMENT_FUNCTION_I(17, Coudert, function17, bool) if (ENTITY_PARAM(2, 1)) { ENTITY_PARAM(2, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -789,7 +781,7 @@ IMPLEMENT_FUNCTION_I(17, Coudert, function17, bool) case 1: case 2: case 3: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -817,7 +809,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18) getEntities()->drawSequenceLeft(kEntityCoudert, "627K"); getScenes()->loadSceneFromItemPosition(kItem5); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -849,7 +841,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18) break; case 2: - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -857,7 +849,7 @@ IMPLEMENT_FUNCTION(18, Coudert, function18) ENTITY_PARAM(0, 1) = 0; getSavePoints()->push(kEntityCoudert, kEntityCoudert, kActionDrawScene); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -876,14 +868,14 @@ IMPLEMENT_FUNCTION_I(19, Coudert, function19, bool) || ENTITY_PARAM(2, 4) || ENTITY_PARAM(2, 6)) { getInventory()->setLocationAndProcess(kItem5, kObjectLocation1); ENTITY_PARAM(2, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } if (ENTITY_PARAM(0, 3) || ENTITY_PARAM(0, 5) || ENTITY_PARAM(0, 4)) { getScenes()->loadSceneFromItemPosition(kItem5); ENTITY_PARAM(2, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -903,7 +895,7 @@ IMPLEMENT_FUNCTION_I(19, Coudert, function19, bool) getEntities()->drawSequenceLeft(kEntityCoudert, ENTITY_PARAM(0, 2) ? "627B" : "627E"); ENTITY_PARAM(0, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -916,11 +908,12 @@ IMPLEMENT_FUNCTION_II(20, Coudert, function20, ObjectIndex, ObjectIndex) break; case kActionNone: - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 3), getState()->time, 300) + if (Entity::updateParameter(CURRENT_PARAM(1, 3), getState()->time, 300)) { getSound()->playSound(kEntityPlayer, "ZFX1004", getSound()->getSoundFlag(kEntityCoudert)); - UPDATE_PARAM_PROC_END + } - UPDATE_PARAM(CURRENT_PARAM(1, 4), getState()->time, 900); + if (!Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->time, 900)) + break; getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1); @@ -930,7 +923,7 @@ IMPLEMENT_FUNCTION_II(20, Coudert, function20, ObjectIndex, ObjectIndex) if (params->param2) getObjects()->update((ObjectIndex)params->param2, (EntityIndex)params->param7, (ObjectLocation)params->param8, (CursorStyle)CURRENT_PARAM(1, 1), (CursorStyle)CURRENT_PARAM(1, 2)); - CALLBACK_ACTION(); + callbackAction(); break; case kActionKnock: @@ -999,7 +992,8 @@ IMPLEMENT_FUNCTION(21, Coudert, function21) case kActionNone: if (!params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment("627Zh", kObjectCompartmentH); @@ -1044,7 +1038,7 @@ IMPLEMENT_FUNCTION(21, Coudert, function21) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1073,7 +1067,7 @@ IMPLEMENT_FUNCTION(21, Coudert, function21) getData()->location = kLocationOutsideCompartment; getSavePoints()->push(kEntityCoudert, kEntityIvo, kAction123852928); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1100,7 +1094,8 @@ IMPLEMENT_FUNCTION(22, Coudert, function22) case kActionNone: if (!params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment("627Rg", kObjectCompartmentG); @@ -1145,7 +1140,7 @@ IMPLEMENT_FUNCTION(22, Coudert, function22) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1174,7 +1169,7 @@ IMPLEMENT_FUNCTION(22, Coudert, function22) getData()->location = kLocationOutsideCompartment; getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction123852928); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1225,7 +1220,7 @@ IMPLEMENT_FUNCTION(23, Coudert, function23) case 3: getEntities()->exitCompartment(kEntityCoudert, kObjectCompartmentF, true); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1296,7 +1291,7 @@ IMPLEMENT_FUNCTION(25, Coudert, function25) getData()->location = kLocationOutsideCompartment; getSavePoints()->push(kEntityCoudert, kEntityRebecca, kAction123852928); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1311,7 +1306,8 @@ IMPLEMENT_FUNCTION(26, Coudert, function26) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment2("627Zd", kObjectCompartmentD, kPosition_5790, kPosition_6130); @@ -1357,7 +1353,7 @@ IMPLEMENT_FUNCTION(26, Coudert, function26) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1375,7 +1371,7 @@ IMPLEMENT_FUNCTION(26, Coudert, function26) getData()->location = kLocationOutsideCompartment; getSavePoints()->push(kEntityCoudert, kEntityMmeBoutarel, kAction123852928); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1402,7 +1398,8 @@ IMPLEMENT_FUNCTION(27, Coudert, function27) case kActionNone: if (!params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment2("627Rc", kObjectCompartmentC, kPosition_6470, kPosition_6130); @@ -1446,7 +1443,7 @@ IMPLEMENT_FUNCTION(27, Coudert, function27) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1473,7 +1470,7 @@ IMPLEMENT_FUNCTION(27, Coudert, function27) getData()->location = kLocationOutsideCompartment; getSavePoints()->push(kEntityCoudert, kEntityBoutarel, kAction123852928); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1515,7 +1512,7 @@ IMPLEMENT_FUNCTION_I(30, Coudert, function30, ObjectIndex) case kActionDefault: switch (parameters->param1) { default: - CALLBACK_ACTION(); + callbackAction(); // Stop processing here return; @@ -1615,7 +1612,7 @@ IMPLEMENT_FUNCTION_I(30, Coudert, function30, ObjectIndex) break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1654,7 +1651,7 @@ IMPLEMENT_FUNCTION_I(31, Coudert, function31, uint32) case 2: case 3: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1699,7 +1696,7 @@ IMPLEMENT_FUNCTION(32, Coudert, function32) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1726,7 +1723,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33) setup_updateEntity(kCarRedSleeping, kPosition_540); } } else { - CALLBACK_ACTION(); + callbackAction(); } break; @@ -1763,7 +1760,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33) case 4: ENTITY_PARAM(2, 6) = 0; - CALLBACK_ACTION(); + callbackAction(); break; case 5: @@ -1808,7 +1805,7 @@ IMPLEMENT_FUNCTION(33, Coudert, function33) case 10: ENTITY_PARAM(2, 6) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1882,7 +1879,7 @@ IMPLEMENT_FUNCTION_I(34, Coudert, function34, bool) break; case 7: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1902,7 +1899,8 @@ IMPLEMENT_FUNCTION_I(35, Coudert, function35, bool) getScenes()->loadSceneFromPosition(kCarRestaurant, 65); } - UPDATE_PARAM(params->param2, getState()->time, 2700); + if (!Entity::updateParameter(params->param2, getState()->time, 2700)) + break; getSavePoints()->push(kEntityCoudert, kEntityMax, kActionMaxFreeFromCage); @@ -1951,7 +1949,7 @@ IMPLEMENT_FUNCTION_I(35, Coudert, function35, bool) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1965,7 +1963,7 @@ IMPLEMENT_FUNCTION(36, Coudert, chapter1) break; case kActionNone: - TIME_CHECK_CALLBACK(kTimeChapter1, params->param1, 1, setup_chapter1Handler) + Entity::timeCheckCallback(kTimeChapter1, params->param1, 1, WRAP_SETUP_FUNCTION(Coudert, setup_chapter1Handler)); break; case kActionDefault: @@ -2174,7 +2172,7 @@ IMPLEMENT_FUNCTION(39, Coudert, function39) getSavePoints()->push(kEntityCoudert, kEntityVerges, kAction167854368); ENTITY_PARAM(2, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2283,22 +2281,22 @@ label_callback_9: label_callback_10: if (getState()->time > kTime1189800 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 2700); + if (Entity::updateParameter(params->param3, getState()->time, 2700)) { ENTITY_PARAM(0, 2) = 1; ENTITY_PARAM(0, 1) = 1; getEntities()->drawSequenceLeft(kEntityCoudert, "697F"); params->param3 = 0; - UPDATE_PARAM_PROC_END + } } if (!ENTITY_PARAM(0, 2)) break; - TIME_CHECK_OBJECT(kTime1107000, params->param4, kObject111, kObjectLocation2); - TIME_CHECK_OBJECT(kTime1161000, params->param5, kObject111, kObjectLocation3); - TIME_CHECK_OBJECT(kTime1206000, params->param6, kObject111, kObjectLocation4); + timeCheckObject(kTime1107000, params->param4, kObject111, kObjectLocation2); + timeCheckObject(kTime1161000, params->param5, kObject111, kObjectLocation3); + timeCheckObject(kTime1206000, params->param6, kObject111, kObjectLocation4); break; case kAction1: @@ -2536,7 +2534,7 @@ IMPLEMENT_FUNCTION(41, Coudert, function41) case 18: getSavePoints()->push(kEntityCoudert, kEntityMilos, kAction208228224); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2827,28 +2825,34 @@ label_callback_12: } label_callback_13: - TIME_CHECK_CALLBACK(kTime2088900, params->param1, 14, setup_function32); + if (Entity::timeCheckCallback(kTime2088900, params->param1, 14, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_14: - TIME_CHECK_CALLBACK(kTime2119500, params->param2, 15, setup_function32); + if (Entity::timeCheckCallback(kTime2119500, params->param2, 15, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_15: - TIME_CHECK_CALLBACK(kTime2138400, params->param3, 16, setup_function32); + if (Entity::timeCheckCallback(kTime2138400, params->param3, 16, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_16: - TIME_CHECK_CALLBACK(kTime2147400, params->param4, 17, setup_function32); + if (Entity::timeCheckCallback(kTime2147400, params->param4, 17, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_17: - TIME_CHECK_CALLBACK(kTime2160000, params->param5, 18, setup_function32); + if (Entity::timeCheckCallback(kTime2160000, params->param5, 18, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_18: - TIME_CHECK_CALLBACK(kTime2205000, params->param6, 19, setup_function32); + if (Entity::timeCheckCallback(kTime2205000, params->param6, 19, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_19: if (ENTITY_PARAM(0, 2)) { - TIME_CHECK_OBJECT(kTime2025000, params->param7, kObject111, kObjectLocation7); - TIME_CHECK_OBJECT(kTime2133000, params->param8, kObject111, kObjectLocation8); - TIME_CHECK_OBJECT(kTime2173500, CURRENT_PARAM(1, 1), kObject111, kObjectLocation9); + timeCheckObject(kTime2025000, params->param7, kObject111, kObjectLocation7); + timeCheckObject(kTime2133000, params->param8, kObject111, kObjectLocation8); + timeCheckObject(kTime2173500, CURRENT_PARAM(1, 1), kObject111, kObjectLocation9); } break; @@ -3051,7 +3055,7 @@ IMPLEMENT_FUNCTION(46, Coudert, function46) break; case 11: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3116,7 +3120,7 @@ IMPLEMENT_FUNCTION_I(47, Coudert, function47, bool) break; case 7: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3164,7 +3168,7 @@ IMPLEMENT_FUNCTION(48, Coudert, function48) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3261,7 +3265,7 @@ IMPLEMENT_FUNCTION(49, Coudert, function49) break; case 11: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3347,7 +3351,7 @@ IMPLEMENT_FUNCTION(50, Coudert, function50) break; case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3541,11 +3545,11 @@ label_callback_1: params->param2 = (uint)(getState()->time + 4500); if (params->param3 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(params->param2, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param3, 0) + if (Entity::updateParameterTime((TimeValue)params->param2, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param3, 0)) { setCallback(2); setup_function55(); break; - UPDATE_PARAM_PROC_END + } } } @@ -3558,18 +3562,22 @@ label_callback_2: label_callback_3: if (!params->param1) { - TIME_CHECK_CALLBACK(kTime2394000, params->param4, 4, setup_function56); + if (Entity::timeCheckCallback(kTime2394000, params->param4, 4, WRAP_SETUP_FUNCTION(Coudert, setup_function56))) + break; label_callback_4: - TIME_CHECK_CALLBACK(kTime2434500, params->param5, 5, setup_function32); + if (Entity::timeCheckCallback(kTime2434500, params->param5, 5, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; label_callback_5: - TIME_CHECK_CALLBACK(kTime2448000, params->param6, 6, setup_function32); + if (Entity::timeCheckCallback(kTime2448000, params->param6, 6, WRAP_SETUP_FUNCTION(Coudert, setup_function32))) + break; } label_callback_6: if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) { - UPDATE_PARAM(params->param7, getState()->time, 2700); + if (!Entity::updateParameter(params->param7, getState()->time, 2700)) + break; ENTITY_PARAM(0, 2) = 0; ENTITY_PARAM(0, 1) = 1; @@ -3696,7 +3704,7 @@ IMPLEMENT_FUNCTION(54, Coudert, function54) break; case 3: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3764,7 +3772,7 @@ IMPLEMENT_FUNCTION(55, Coudert, function55) break; case 7: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3868,7 +3876,7 @@ IMPLEMENT_FUNCTION(56, Coudert, function56) break; case 16: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -4034,7 +4042,8 @@ IMPLEMENT_FUNCTION(62, Coudert, function62) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param4, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; @@ -4168,7 +4177,7 @@ void Coudert::visitCompartment(const SavePoint &savepoint, EntityPosition positi case 6: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/coudert.h b/engines/lastexpress/entities/coudert.h index 45d13ce9bb..8303c80a32 100644 --- a/engines/lastexpress/entities/coudert.h +++ b/engines/lastexpress/entities/coudert.h @@ -24,8 +24,6 @@ #define LASTEXPRESS_COUDERT_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" - namespace LastExpress { class LastExpressEngine; diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index e136ca4776..dad5e67392 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -22,22 +22,17 @@ #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" - #include "lastexpress/data/sequence.h" #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" #include "lastexpress/game/logic.h" -#include "lastexpress/game/scenes.h" -#include "lastexpress/game/state.h" +#include "lastexpress/game/object.h" #include "lastexpress/game/savegame.h" #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" +#include "lastexpress/game/scenes.h" -#include "lastexpress/sound/sound.h" - -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -55,6 +50,19 @@ EntityData::EntityCallData::~EntityCallData() { SAFE_DELETE(sequence3); } +void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const { + char seqName[13]; + memset(&seqName, 0, length); + + if (s.isSaving()) + strcpy((char *)&seqName, string.c_str()); + + s.syncBytes((byte *)&seqName, length); + + if (s.isLoading()) + string = seqName; +} + void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) { for (uint i = 0; i < ARRAYSIZE(callbacks); i++) s.syncAsByte(callbacks[i]); @@ -81,23 +89,19 @@ void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsByte(directionSwitch); // Sync strings -#define SYNC_STRING(varName, count) { \ - char seqName[13]; \ - memset(&seqName, 0, count); \ - if (s.isSaving()) strcpy((char *)&seqName, varName.c_str()); \ - s.syncBytes((byte *)&seqName, count); \ - if (s.isLoading()) varName = seqName; \ -} - - SYNC_STRING(sequenceName, 13); - SYNC_STRING(sequenceName2, 13); - SYNC_STRING(sequenceNamePrefix, 7); - SYNC_STRING(sequenceNameCopy, 13); - -#undef SYNC_STRING + syncString(s, sequenceName, 13); + syncString(s, sequenceName2, 13); + syncString(s, sequenceNamePrefix, 7); + syncString(s, sequenceNameCopy, 13); // Skip pointers to frame & sequences - s.skip(5 * 4); + // (we are using a compressed stream, so we cannot seek on load) + if (s.isLoading()) { + byte empty[5 * 4]; + s.syncBytes(empty, 5 * 4); + } else { + s.skip(5 * 4); + } } ////////////////////////////////////////////////////////////////////////// @@ -113,7 +117,7 @@ EntityData::EntityParameters *EntityData::getParameters(uint callback, byte inde return _parameters[callback].parameters[index]; } -int EntityData::getCallback(uint callback) const { +byte EntityData::getCallback(uint callback) const { if (callback >= 16) error("[EntityData::getCallback] Invalid callback value (was: %d, max: 16)", callback); @@ -246,16 +250,38 @@ void Entity::savegame(const SavePoint &savepoint) { break; case kActionNone: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: getSaveLoad()->saveGame((SavegameType)params->param1, _entityIndex, (EventIndex)params->param2); - CALLBACK_ACTION(); + callbackAction(); break; } } +void Entity::savegameBloodJacket() { + if (getProgress().jacket == kJacketBlood + && getEntities()->isDistanceBetweenEntities(_entityIndex, kEntityPlayer, 1000) + && !getEntities()->isInsideCompartments(kEntityPlayer) + && !getEntities()->checkFields10(kEntityPlayer)) { + setCallback(1); + + switch (_entityIndex) { + default: + break; + + case kEntityCoudert: + setup_savegame(kSavegameTypeEvent, kEventCoudertBloodJacket); + break; + + case kEntityMertens: + setup_savegame(kSavegameTypeEvent, kEventCoudertBloodJacket); + break; + } + } +} + void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundFlag flag) { EXPOSE_PARAMS(EntityData::EntityParametersSIIS) @@ -264,7 +290,7 @@ void Entity::playSound(const SavePoint &savepoint, bool resetItem, SoundFlag fla break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -284,7 +310,7 @@ void Entity::draw(const SavePoint &savepoint, bool handleExcuseMe) { break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -308,7 +334,7 @@ void Entity::draw2(const SavePoint &savepoint) { break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -326,8 +352,10 @@ void Entity::updateFromTicks(const SavePoint &savepoint) { break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->timeTicks, params->param1) - CALLBACK_ACTION(); + if (Entity::updateParameter(params->param2, getState()->timeTicks, params->param1)) + break; + + callbackAction(); break; } } @@ -340,8 +368,10 @@ void Entity::updateFromTime(const SavePoint &savepoint) { break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, params->param1) - CALLBACK_ACTION(); + if (Entity::updateParameter(params->param2, getState()->time, params->param1)) + break; + + callbackAction(); break; } } @@ -352,12 +382,12 @@ void Entity::callbackActionOnDirection(const SavePoint &savepoint) { break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: if (getData()->direction != kDirectionRight) - CALLBACK_ACTION(); + callbackAction(); break; } } @@ -370,7 +400,7 @@ void Entity::callbackActionRestaurantOrSalon(const SavePoint &savepoint) { case kActionNone: case kActionDefault: if (getEntities()->isSomebodyInsideRestaurantOrSalon()) - CALLBACK_ACTION(); + callbackAction(); break; } } @@ -395,7 +425,7 @@ void Entity::updateEntity(const SavePoint &savepoint, bool handleExcuseMe) { case kActionNone: case kActionDefault: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; } } @@ -410,7 +440,7 @@ void Entity::callSavepoint(const SavePoint &savepoint, bool handleExcuseMe) { case kActionExitCompartment: if (!CURRENT_PARAM(1, 1)) getSavePoints()->call(_entityIndex, (EntityIndex)params->param4, (ActionIndex)params->param5, (char *)¶ms->seq2); - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -448,7 +478,7 @@ void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition pos if (updateLocation) getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -468,6 +498,74 @@ void Entity::enterExitCompartment(const SavePoint &savepoint, EntityPosition pos } } +void Entity::goToCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, Common::String sequenceTo) { + switch (savepoint.action) { + default: + break; + + case kActionDefault: + getData()->entityPosition = positionFrom; + setCallback(1); + setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom); + break; + + case kActionCallback: + switch (getCallback()) { + default: + break; + + case 1: + setCallback(2); + setup_enterExitCompartment(sequenceTo.c_str(), compartmentFrom); + break; + + case 2: + getData()->entityPosition = positionFrom; + getEntities()->clearSequences(_entityIndex); + callbackAction(); + break; + } + break; + } +} + +void Entity::goToCompartmentFromCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, ObjectIndex compartmentTo, EntityPosition positionTo, Common::String sequenceTo) { + switch (savepoint.action) { + default: + break; + + case kActionDefault: + getData()->entityPosition = positionFrom; + getData()->location = kLocationOutsideCompartment; + setCallback(1); + setup_enterExitCompartment(sequenceFrom.c_str(), compartmentFrom); + break; + + case kActionCallback: + switch (getCallback()) { + default: + break; + + case 1: + setCallback(2); + setup_updateEntity(kCarGreenSleeping, positionTo); + break; + + case 2: + setCallback(3); + setup_enterExitCompartment(sequenceTo.c_str(), compartmentTo); + break; + + case 3: + getData()->location = kLocationInsideCompartment; + getEntities()->clearSequences(_entityIndex); + callbackAction(); + break; + } + break; + } +} + void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) { EXPOSE_PARAMS(EntityData::EntityParametersSIII) @@ -477,7 +575,7 @@ void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) { case kActionExitCompartment: getEntities()->updatePositionExit(_entityIndex, (CarIndex)params->param4, (Position)params->param5); - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -494,4 +592,385 @@ void Entity::updatePosition(const SavePoint &savepoint, bool handleExcuseMe) { } } +void Entity::callbackAction() { + if (getData()->currentCall == 0) + error("[Entity::callbackAction] currentCall is already 0, cannot proceed"); + + getData()->currentCall--; + + getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]); + + getSavePoints()->call(_entityIndex, _entityIndex, kActionCallback); +} + +////////////////////////////////////////////////////////////////////////// +// Setup functions +////////////////////////////////////////////////////////////////////////// +void Entity::setup(const char *name, uint index) { + debugC(6, kLastExpressDebugLogic, "Entity: %s()", name); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIIII>(); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupI(const char *name, uint index, uint param1) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u)", name, param1); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIIII>(); + + EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters(); + params->param1 = (unsigned int)param1; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupII(const char *name, uint index, uint param1, uint param2) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u)", name, param1, param2); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIIII>(); + + EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters(); + params->param1 = param1; + params->param2 = param2; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupIII(const char *name, uint index, uint param1, uint param2, uint param3) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %u)", name, param1, param2, param3); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIIII>(); + + EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII *)_data->getCurrentParameters(); + params->param1 = param1; + params->param2 = param2; + params->param3 = param3; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupS(const char *name, uint index, const char *seq1) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s)", name, seq1); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSIIS>(); + + EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSS(const char *name, uint index, const char *seq1, const char *seq2) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s)", name, seq1, seq2); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSSII>(); + + EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + strncpy(params->seq2, seq2, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSI(const char *name, uint index, const char *seq1, uint param4) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u)", name, seq1, param4); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSIIS>(); + + EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + params->param4 = param4; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSII(const char *name, uint index, const char *seq1, uint param4, uint param5) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u)", name, seq1, param4, param5); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSIIS>(); + + EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + params->param4 = param4; + params->param5 = param5; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSIII(const char *name, uint index, const char *seq, uint param4, uint param5, uint param6) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %u)", name, seq, param4, param5, param6); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSIII>(); + + EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII *)_data->getCurrentParameters(); + strncpy(params->seq, seq, 12); + params->param4 = param4; + params->param5 = param5; + params->param6 = param6; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSIIS(const char *name, uint index, const char *seq1, uint param4, uint param5, const char *seq2) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %u, %u, %s)", name, seq1, param4, param5, seq2); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSIIS>(); + + EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS *)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + params->param4 = param4; + params->param5 = param5; + strncpy(params->seq2, seq2, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupSSI(const char *name, uint index, const char *seq1, const char *seq2, uint param7) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%s, %s, %u)", name, seq1, seq2, param7); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersSSII>(); + + EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII *)_data->getCurrentParameters(); + strncpy(params->seq1, seq1, 12); + strncpy(params->seq2, seq2, 12); + params->param7 = param7; + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupIS(const char *name, uint index, uint param1, const char *seq) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s)", name, param1, seq); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersISII>(); + + EntityData::EntityParametersISII *params = (EntityData::EntityParametersISII *)_data->getCurrentParameters(); + params->param1 = (unsigned int)param1; + strncpy(params->seq, seq, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupISS(const char *name, uint index, uint param1, const char *seq1, const char *seq2) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %s, %s)", name, param1, seq1, seq2); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersISSI>(); + + EntityData::EntityParametersISSI *params = (EntityData::EntityParametersISSI *)_data->getCurrentParameters(); + params->param1 = param1; + strncpy(params->seq1, seq1, 12); + strncpy(params->seq2, seq2, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupIIS(const char *name, uint index, uint param1, uint param2, const char *seq) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s)", name, param1, param2, seq); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIISI>(); + + EntityData::EntityParametersIISI *params = (EntityData::EntityParametersIISI *)_data->getCurrentParameters(); + params->param1 = param1; + params->param2 = param2; + strncpy(params->seq, seq, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +void Entity::setupIISS(const char *name, uint index, uint param1, uint param2, const char *seq1, const char *seq2) { + debugC(6, kLastExpressDebugLogic, "Entity: %s(%u, %u, %s, %s)", name, param1, param2, seq1, seq2); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); + _data->setCurrentCallback(index); + _data->resetCurrentParameters<EntityData::EntityParametersIISS>(); + + EntityData::EntityParametersIISS *params = (EntityData::EntityParametersIISS *)_data->getCurrentParameters(); + params->param1 = param1; + params->param2 = param2; + strncpy(params->seq1, seq1, 12); + strncpy(params->seq2, seq2, 12); + + _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); +} + +////////////////////////////////////////////////////////////////////////// +// Helper functions +////////////////////////////////////////////////////////////////////////// + +bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) const { + if (!parameter) + parameter = (uint)(timeType + delta); + + if (parameter >= timeType) + return false; + + parameter = kTimeInvalid; + + return true; +} + +bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const { + if (getState()->time <= timeValue) { + if (check || !parameter) + parameter = (uint)(getState()->time + delta); + } + + if (parameter >= getState()->time && getState()->time <= timeValue) + return false; + + parameter = kTimeInvalid; + + return true; +} + +bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) const { + if (parameter && parameter >= timeType) + return false; + + if (!parameter) + parameter = (uint)(timeType + delta); + + return true; +} + +bool Entity::timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function) const { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + (*function)(); + + return true; + } + + return false; +} + +bool Entity::timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + (*function)(); + + return true; + } + + return false; +} + +bool Entity::timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, const char *str, Common::Functor1<const char *, void> *function) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + (*function)(str); + + return true; + } + + return false; +} + +bool Entity::timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, bool check, Common::Functor1<bool, void> *function) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + (*function)(check); + + return true; + } + + return false; +} + +bool Entity::timeCheckCallbackInventory(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + getData()->inventoryItem = kItemNone; + setCallback(callback); + (*function)(); + + return true; + } + + return false; +} + +bool Entity::timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function) { + if ((getState()->time <= timeValue && !getEntities()->isPlayerInCar(kCarGreenSleeping)) || !parameter) + parameter = (uint)getState()->time + 75; + + if (getState()->time > timeValue || parameter < getState()->time) { + parameter = kTimeInvalid; + setCallback(callback); + (*function)(); + + return true; + } + + return false; +} + +void Entity::timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + getSavePoints()->push(entity1, entity2, action); + } +} + +void Entity::timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex object, ObjectLocation location) const { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + getObjects()->updateLocation2(object, location); + } +} + +bool Entity::timeCheckCallbackAction(TimeValue timeValue, uint ¶meter) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + callbackAction(); + return true; + } + + return false; +} + +bool Entity::timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint ¶meter, byte callback, const char* sound, EntityPosition position) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + getData()->entityPosition = position; + setCallback(callback); + setup_playSound(sound); + return true; + } + + return false; +} + + } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index 039f461c7b..c67d13db9e 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -41,10 +41,229 @@ class Sequence; class SequenceFrame; struct SavePoint; +////////////////////////////////////////////////////////////////////////// +// Declaration +////////////////////////////////////////////////////////////////////////// +#define DECLARE_FUNCTION(name) \ + void setup_##name(); \ + void name(const SavePoint &savepoint); + +#define DECLARE_FUNCTION_1(name, param1) \ + void setup_##name(param1); \ + void name(const SavePoint &savepoint); + +#define DECLARE_FUNCTION_2(name, param1, param2) \ + void setup_##name(param1, param2); \ + void name(const SavePoint &savepoint); + +#define DECLARE_FUNCTION_3(name, param1, param2, param3) \ + void setup_##name(param1, param2, param3); \ + void name(const SavePoint &savepoint); + +#define DECLARE_FUNCTION_4(name, param1, param2, param3, param4) \ + void setup_##name(param1, param2, param3, param4); \ + void name(const SavePoint &savepoint); + +#define DECLARE_FUNCTION_NOSETUP(name) \ + void name(const SavePoint &savepoint); + +#define DECLARE_NULL_FUNCTION() \ + void setup_nullfunction(); + +////////////////////////////////////////////////////////////////////////// +// Callbacks +////////////////////////////////////////////////////////////////////////// +#define ENTITY_CALLBACK(class, name, pointer) \ + Common::Functor1Mem<const SavePoint&, void, class>(pointer, &class::name) + +#define ADD_CALLBACK_FUNCTION(class, name) \ + _callbacks.push_back(new ENTITY_CALLBACK(class, name, this)); + +#define ADD_NULL_FUNCTION() \ + _callbacks.push_back(new ENTITY_CALLBACK(Entity, nullfunction, this)); + +#define WRAP_SETUP_FUNCTION(className, method) \ + new Common::Functor0Mem<void, className>(this, &className::method) + +#define WRAP_SETUP_FUNCTION_S(className, method) \ + new Common::Functor1Mem<const char *, void, className>(this, &className::method) + +#define WRAP_SETUP_FUNCTION_B(className, method) \ + new Common::Functor1Mem<bool, void, className>(this, &className::method) + +////////////////////////////////////////////////////////////////////////// +// Parameters macros +////////////////////////////////////////////////////////////////////////// +#define CURRENT_PARAM(index, id) \ + ((EntityData::EntityParametersIIII*)_data->getCurrentParameters(index))->param##id + +#define ENTITY_PARAM(index, id) \ + ((EntityData::EntityParametersIIII*)_data->getParameters(8, index))->param##id + +////////////////////////////////////////////////////////////////////////// +// Misc +////////////////////////////////////////////////////////////////////////// +#define RESET_ENTITY_STATE(entity, class, function) \ + getEntities()->resetState(entity); \ + ((class *)getEntities()->get(entity))->function(); + +////////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////////// + +// Expose parameters and check validity +#define EXPOSE_PARAMS(type) \ + type *params = (type *)_data->getCurrentParameters(); \ + if (!params) \ + error("[EXPOSE_PARAMS] Trying to call an entity function with invalid parameters"); \ + +// function signature without setup (we keep the index for consistency but never use it) +#define IMPLEMENT_FUNCTION_NOSETUP(index, class, name) \ + void class::name(const SavePoint &savepoint) { \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(index=" #index ")"); + +// simple setup with no parameters +#define IMPLEMENT_FUNCTION(index, class, name) \ + void class::setup_##name() { \ + Entity::setup(#class "::setup_" #name, index); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "() - action: %s", ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_END } + +// nullfunction call +#define IMPLEMENT_NULL_FUNCTION(index, class) \ + void class::setup_nullfunction() { \ + Entity::setup(#class "::setup_nullfunction", index); \ + } + +// setup with one uint parameter +#define IMPLEMENT_FUNCTION_I(index, class, name, paramType) \ + void class::setup_##name(paramType param1) { \ + Entity::setupI(#class "::setup_" #name, index, param1); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d) - action: %s", params->param1, ACTION_NAME(savepoint.action)); + +// setup with two uint parameters +#define IMPLEMENT_FUNCTION_II(index, class, name, paramType1, paramType2) \ + void class::setup_##name(paramType1 param1, paramType2 param2) { \ + Entity::setupII(#class "::setup_" #name, index, param1, param2); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d) - action: %s", params->param1, params->param2, ACTION_NAME(savepoint.action)); + +// setup with three uint parameters +#define IMPLEMENT_FUNCTION_III(index, class, name, paramType1, paramType2, paramType3) \ + void class::setup_##name(paramType1 param1, paramType2 param2, paramType3 param3) { \ + Entity::setupIII(#class "::setup_" #name, index, param1, param2, param3); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %d) - action: %s", params->param1, params->param2, params->param3, ACTION_NAME(savepoint.action)); + +// setup with one char *parameter +#define IMPLEMENT_FUNCTION_S(index, class, name) \ + void class::setup_##name(const char *seq1) { \ + Entity::setupS(#class "::setup_" #name, index, seq1); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s) - action: %s", (char *)¶ms->seq1, ACTION_NAME(savepoint.action)); + +// setup with one char *parameter and one uint +#define IMPLEMENT_FUNCTION_SI(index, class, name, paramType2) \ + void class::setup_##name(const char *seq1, paramType2 param4) { \ + Entity::setupSI(#class "::setup_" #name, index, seq1, param4); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d) - action: %s", (char *)¶ms->seq1, params->param4, ACTION_NAME(savepoint.action)); + +// setup with one char *parameter and two uints +#define IMPLEMENT_FUNCTION_SII(index, class, name, paramType2, paramType3) \ + void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5) { \ + Entity::setupSII(#class "::setup_" #name, index, seq1, param4, param5); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d) - action: %s", (char *)¶ms->seq1, params->param4, params->param5, ACTION_NAME(savepoint.action)); + +// setup with one char *parameter and three uints +#define IMPLEMENT_FUNCTION_SIII(index, class, name, paramType2, paramType3, paramType4) \ + void class::setup_##name(const char *seq, paramType2 param4, paramType3 param5, paramType4 param6) { \ + Entity::setupSIII(#class "::setup_" #name, index, seq, param4, param5, param6); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSIII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %d) - action: %s", (char *)¶ms->seq, params->param4, params->param5, params->param6, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_SIIS(index, class, name, paramType2, paramType3) \ + void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5, const char *seq2) { \ + Entity::setupSIIS(#class "::setup_" #name, index, seq1, param4, param5, seq2); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %s) - action: %s", (char *)¶ms->seq1, params->param4, params->param5, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_SS(index, class, name) \ + void class::setup_##name(const char *seq1, const char *seq2) { \ + Entity::setupSS(#class "::setup_" #name, index, seq1, seq2); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSSII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s) - action: %s", (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_SSI(index, class, name, paramType3) \ + void class::setup_##name(const char *seq1, const char *seq2, paramType3 param7) { \ + Entity::setupSSI(#class "::setup_" #name, index, seq1, seq2, param7); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersSSII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s, %d) - action: %s", (char *)¶ms->seq1, (char *)¶ms->seq2, params->param7, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_IS(index, class, name, paramType) \ + void class::setup_##name(paramType param1, const char *seq) { \ + Entity::setupIS(#class "::setup_" #name, index, param1, seq); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersISII) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s) - action: %s", params->param1, (char *)¶ms->seq, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_ISS(index, class, name, paramType) \ + void class::setup_##name(paramType param1, const char *seq1, const char *seq2) { \ + Entity::setupISS(#class "::setup_" #name, index, param1, seq1, seq2); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersISSI) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s, %s) - action: %s", params->param1, (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_IIS(index, class, name, paramType1, paramType2) \ + void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq) { \ + Entity::setupIIS(#class "::setup_" #name, index, param1, param2, seq); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIISI) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s) - action: %s", params->param1, params->param2, (char *)¶ms->seq, ACTION_NAME(savepoint.action)); + +#define IMPLEMENT_FUNCTION_IISS(index, class, name, paramType1, paramType2) \ + void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq1, const char *seq2) { \ + Entity::setupIISS(#class "::setup_" #name, index, param1, param2, seq1, seq2); \ + } \ + void class::name(const SavePoint &savepoint) { \ + EXPOSE_PARAMS(EntityData::EntityParametersIISS) \ + debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s, %s) - action: %s", params->param1, params->param2, (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); + + +////////////////////////////////////////////////////////////////////////// class EntityData : Common::Serializable { public: - struct EntityParameters : Common::Serializable{ + struct EntityParameters : Common::Serializable { virtual ~EntityParameters() {} virtual Common::String toString() = 0; @@ -596,6 +815,15 @@ public: return str; } + /** + * Synchronizes a string. + * + * @param s The Common::Serializer to use. + * @param string The string. + * @param length Length of the string. + */ + void syncString(Common::Serializer &s, Common::String &string, uint length) const; + // Serializable void saveLoadWithSerializer(Common::Serializer &s); }; @@ -611,32 +839,30 @@ public: params->parameters[i] = new T(); } - EntityCallData *getCallData() { return &_data; } + EntityCallData *getCallData() { return &_data; } - EntityParameters *getParameters(uint callback, byte index) const; - EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); } + EntityParameters *getParameters(uint callback, byte index) const; + EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); } + EntityCallParameters *getCurrentCallParameters() { return &_parameters[_data.currentCall]; } - int getCallback(uint callback) const; - int getCurrentCallback() { return getCallback(_data.currentCall); } - void setCallback(uint callback, byte index); - void setCurrentCallback(uint index) { setCallback(_data.currentCall, index); } + byte getCallback(uint callback) const; + byte getCurrentCallback() { return getCallback(_data.currentCall); } + void setCallback(uint callback, byte index); + void setCurrentCallback(uint index) { setCallback(_data.currentCall, index); } - void updateParameters(uint32 index) const; + void updateParameters(uint32 index) const; // Serializable - void saveLoadWithSerializer(Common::Serializer &ser); + void saveLoadWithSerializer(Common::Serializer &ser); private: - EntityCallData _data; + EntityCallData _data; EntityCallParameters _parameters[9]; }; class Entity : Common::Serializable { public: - - typedef Common::Functor1<const SavePoint&, void> Callback; - Entity(LastExpressEngine *engine, EntityIndex index); virtual ~Entity(); @@ -657,6 +883,12 @@ public: virtual void setup_chapter4() = 0; virtual void setup_chapter5() = 0; + // Shared functions + virtual void setup_savegame(SavegameType, uint32) { error("[Entity::setup_savegame] Trying to call the parent setup function. Use the specific entity function directly"); } + virtual void setup_enterExitCompartment(const char *, ObjectIndex) { error("[Entity::setup_enterExitCompartment] Trying to call the parent setup function. Use the specific entity function directly"); } + virtual void setup_updateEntity(CarIndex, EntityPosition) { error("[Entity::setup_updateEntity] Trying to call the parent setup function. Use the specific entity function directly"); } + virtual void setup_playSound(const char*) { error("[Entity::setup_playSound] Trying to call the parent setup function. Use the specific entity function directly"); } + // Serializable void saveLoadWithSerializer(Common::Serializer &ser) { _data->saveLoadWithSerializer(ser); } @@ -664,10 +896,11 @@ public: protected: LastExpressEngine *_engine; + typedef Common::Functor1<const SavePoint&, void> Callback; - EntityIndex _entityIndex; - EntityData *_data; - Common::Array<Callback *> _callbacks; + EntityIndex _entityIndex; + EntityData *_data; + Common::Array<Callback *> _callbacks; /** * Saves the game @@ -679,6 +912,13 @@ protected: void savegame(const SavePoint &savepoint); /** + * Saves the game before being found out with a blood covered jacket. + * + * @param saveFunction The setup function to call to save the game + */ + void savegameBloodJacket(); + + /** * Play sound * * @param savepoint The savepoint @@ -782,15 +1022,83 @@ protected: void enterExitCompartment(const SavePoint &savepoint, EntityPosition position1 = kPositionNone, EntityPosition position2 = kPositionNone, CarIndex car = kCarNone, ObjectIndex compartment = kObjectNone, bool alternate = false, bool updateLocation = false); /** + * Go to compartment. + * + * @param savepoint The savepoint. + * @param compartmentFrom The compartment from. + * @param positionFrom The position from. + * @param sequenceFrom The sequence from. + * @param sequenceTo The sequence to. + */ + void goToCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, Common::String sequenceTo); + + /** + * Go to compartment from compartment. + * + * @param savepoint The savepoint. + * @param compartmentFrom The compartment from. + * @param positionFrom The position from. + * @param sequenceFrom The sequence from. + * @param compartmentTo The compartment to. + * @param positionTo The position to. + * @param sequenceTo The sequence to. + */ + void goToCompartmentFromCompartment(const SavePoint &savepoint, ObjectIndex compartmentFrom, EntityPosition positionFrom, Common::String sequenceFrom, ObjectIndex compartmentTo, EntityPosition positionTo, Common::String sequenceTo); + + /** * Updates the position * - * @param savepoint The savepoint + * @param savepoint The savepoint * - Sequence name * - CarIndex * - Position * @param handleExcuseMe true to handle excuseMe actions */ void updatePosition(const SavePoint &savepoint, bool handleExcuseMe = false); + + /** + * Store the current callback information and perform the callback action + */ + void callbackAction(); + + ////////////////////////////////////////////////////////////////////////// + // Setup functions + ////////////////////////////////////////////////////////////////////////// + void setup(const char *name, uint index); + void setupI(const char *name, uint index, uint param1); + void setupII(const char *name, uint index, uint param1, uint param2); + void setupIII(const char *name, uint index, uint param1, uint param2, uint param3); + void setupS(const char *name, uint index, const char *seq1); + void setupSS(const char *name, uint index, const char *seq1, const char *seq2); + void setupSI(const char *name, uint index, const char *seq1, uint param4); + void setupSII(const char *name, uint index, const char *seq1, uint param4, uint param5); + void setupSIII(const char *name, uint index, const char *seq, uint param4, uint param5, uint param6); + void setupSIIS(const char *name, uint index, const char *seq1, uint param4, uint param5, const char *seq2); + void setupSSI(const char *name, uint index, const char *seq1, const char *seq2, uint param7); + void setupIS(const char *name, uint index, uint param1, const char *seq); + void setupISS(const char *name, uint index, uint param1, const char *seq1, const char *seq2); + void setupIIS(const char *name, uint index, uint param1, uint param2, const char *seq); + void setupIISS(const char *name, uint index, uint param1, uint param2, const char *seq1, const char *seq2); + + ////////////////////////////////////////////////////////////////////////// + // Helper functions + ////////////////////////////////////////////////////////////////////////// + + bool updateParameter(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterCheck(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const; + + bool timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function) const; + bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); + bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, const char *str, Common::Functor1<const char *, void> *function); + bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, bool check, Common::Functor1<bool, void> *function); + bool timeCheckCallbackInventory(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); + bool timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); + void timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const; + void timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex index, ObjectLocation location) const; + bool timeCheckCallbackAction(TimeValue timeValue, uint ¶meter); + bool timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint ¶meter, byte callback, const char* sound, EntityPosition position); + }; diff --git a/engines/lastexpress/entities/entity39.cpp b/engines/lastexpress/entities/entity39.cpp index e786d153a0..1786cd2201 100644 --- a/engines/lastexpress/entities/entity39.cpp +++ b/engines/lastexpress/entities/entity39.cpp @@ -28,7 +28,6 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/entity39.h b/engines/lastexpress/entities/entity39.h index 4335a9566e..54b65408c7 100644 --- a/engines/lastexpress/entities/entity39.h +++ b/engines/lastexpress/entities/entity39.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_ENTITY39_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -72,4 +71,4 @@ private: } // End of namespace LastExpress -#endif // LASTEXPRESS_##define##_H +#endif // LASTEXPRESS_ENTITY39_H diff --git a/engines/lastexpress/entities/entity_intern.h b/engines/lastexpress/entities/entity_intern.h index 2da0da15b3..fd803676a9 100644 --- a/engines/lastexpress/entities/entity_intern.h +++ b/engines/lastexpress/entities/entity_intern.h @@ -25,502 +25,6 @@ namespace LastExpress { -#define LOW_BYTE(w) ((unsigned char)(((unsigned long)(w)) & 0xff)) - -////////////////////////////////////////////////////////////////////////// -// Callbacks -#define ENTITY_CALLBACK(class, name, pointer) \ - Common::Functor1Mem<const SavePoint&, void, class>(pointer, &class::name) - -#define ADD_CALLBACK_FUNCTION(class, name) \ - _callbacks.push_back(new ENTITY_CALLBACK(class, name, this)); - -#define ADD_NULL_FUNCTION() \ - _callbacks.push_back(new ENTITY_CALLBACK(Entity, nullfunction, this)); - -////////////////////////////////////////////////////////////////////////// -// Declaration -////////////////////////////////////////////////////////////////////////// - -#define DECLARE_FUNCTION(name) \ - void setup_##name(); \ - void name(const SavePoint &savepoint); - -#define DECLARE_FUNCTION_1(name, param1) \ - void setup_##name(param1); \ - void name(const SavePoint &savepoint); - -#define DECLARE_FUNCTION_2(name, param1, param2) \ - void setup_##name(param1, param2); \ - void name(const SavePoint &savepoint); - -#define DECLARE_FUNCTION_3(name, param1, param2, param3) \ - void setup_##name(param1, param2, param3); \ - void name(const SavePoint &savepoint); - -#define DECLARE_FUNCTION_4(name, param1, param2, param3, param4) \ - void setup_##name(param1, param2, param3, param4); \ - void name(const SavePoint &savepoint); - -#define DECLARE_FUNCTION_NOSETUP(name) \ - void name(const SavePoint &savepoint); - -#define DECLARE_NULL_FUNCTION() \ - void setup_nullfunction(); - -////////////////////////////////////////////////////////////////////////// -// Setup -////////////////////////////////////////////////////////////////////////// - -#define IMPLEMENT_SETUP(class, callback_class, name, index) \ -void class::setup_##name() { \ - BEGIN_SETUP(callback_class, name, index, EntityData::EntityParametersIIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::setup_" #name "()"); \ - END_SETUP() \ -} - -#define BEGIN_SETUP(class, name, index, type) \ - _engine->getGameLogic()->getGameState()->getGameSavePoints()->setCallback(_entityIndex, _callbacks[index]); \ - _data->setCurrentCallback(index); \ - _data->resetCurrentParameters<type>(); - -#define END_SETUP() \ - _engine->getGameLogic()->getGameState()->getGameSavePoints()->call(_entityIndex, _entityIndex, kActionDefault); - - -////////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////////// - -// Expose parameters and check validity -#define EXPOSE_PARAMS(type) \ - type *params = (type *)_data->getCurrentParameters(); \ - if (!params) \ - error("[EXPOSE_PARAMS] Trying to call an entity function with invalid parameters"); \ - - -// function signature without setup (we keep the index for consistency but never use it) -#define IMPLEMENT_FUNCTION_NOSETUP(index, class, name) \ - void class::name(const SavePoint &savepoint) { \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(index=" #index ")"); - -// simple setup with no parameters -#define IMPLEMENT_FUNCTION(index, class, name) \ - IMPLEMENT_SETUP(class, class, name, index) \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "() - action: %s", ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_END } - -// nullfunction call -#define IMPLEMENT_NULL_FUNCTION(index, class) \ - IMPLEMENT_SETUP(class, Entity, nullfunction, index) - -// setup with one uint parameter -#define IMPLEMENT_FUNCTION_I(index, class, name, paramType) \ - void class::setup_##name(paramType param1) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \ - EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \ - params->param1 = (unsigned int)param1; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d) - action: %s", params->param1, ACTION_NAME(savepoint.action)); - -// setup with two uint parameters -#define IMPLEMENT_FUNCTION_II(index, class, name, paramType1, paramType2) \ - void class::setup_##name(paramType1 param1, paramType2 param2) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \ - EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \ - params->param1 = param1; \ - params->param2 = param2; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d) - action: %s", params->param1, params->param2, ACTION_NAME(savepoint.action)); - -// setup with three uint parameters -#define IMPLEMENT_FUNCTION_III(index, class, name, paramType1, paramType2, paramType3) \ - void class::setup_##name(paramType1 param1, paramType2 param2, paramType3 param3) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersIIII) \ - EntityData::EntityParametersIIII *params = (EntityData::EntityParametersIIII*)_data->getCurrentParameters(); \ - params->param1 = param1; \ - params->param2 = param2; \ - params->param3 = param3; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %d) - action: %s", params->param1, params->param2, params->param3, ACTION_NAME(savepoint.action)); - -// setup with one char *parameter -#define IMPLEMENT_FUNCTION_S(index, class, name) \ - void class::setup_##name(const char *seq1) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \ - EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s) - action: %s", (char *)¶ms->seq1, ACTION_NAME(savepoint.action)); - -// setup with one char *parameter and one uint -#define IMPLEMENT_FUNCTION_SI(index, class, name, paramType2) \ - void class::setup_##name(const char *seq1, paramType2 param4) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \ - EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - params->param4 = param4; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d) - action: %s", (char *)¶ms->seq1, params->param4, ACTION_NAME(savepoint.action)); - -// setup with one char *parameter and two uints -#define IMPLEMENT_FUNCTION_SII(index, class, name, paramType2, paramType3) \ - void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \ - EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - params->param4 = param4; \ - params->param5 = param5; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d) - action: %s", (char *)¶ms->seq1, params->param4, params->param5, ACTION_NAME(savepoint.action)); - -// setup with one char *parameter and three uints -#define IMPLEMENT_FUNCTION_SIII(index, class, name, paramType2, paramType3, paramType4) \ - void class::setup_##name(const char *seq, paramType2 param4, paramType3 param5, paramType4 param6) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIII) \ - EntityData::EntityParametersSIII *params = (EntityData::EntityParametersSIII*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq, seq, 12); \ - params->param4 = param4; \ - params->param5 = param5; \ - params->param6 = param6; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSIII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %d) - action: %s", (char *)¶ms->seq, params->param4, params->param5, params->param6, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_SIIS(index, class, name, paramType2, paramType3) \ - void class::setup_##name(const char *seq1, paramType2 param4, paramType3 param5, const char *seq2) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSIIS) \ - EntityData::EntityParametersSIIS *params = (EntityData::EntityParametersSIIS*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - params->param4 = param4; \ - params->param5 = param5; \ - strncpy((char *)¶ms->seq2, seq2, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSIIS) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %d, %d, %s) - action: %s", (char *)¶ms->seq1, params->param4, params->param5, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_SS(index, class, name) \ - void class::setup_##name(const char *seq1, const char *seq2) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSSII) \ - EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - strncpy((char *)¶ms->seq2, seq2, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSSII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s) - action: %s", (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_SSI(index, class, name, paramType3) \ - void class::setup_##name(const char *seq1, const char *seq2, paramType3 param7) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersSSII) \ - EntityData::EntityParametersSSII *params = (EntityData::EntityParametersSSII*)_data->getCurrentParameters(); \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - strncpy((char *)¶ms->seq2, seq2, 12); \ - params->param7 = param7; \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersSSII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%s, %s, %d) - action: %s", (char *)¶ms->seq1, (char *)¶ms->seq2, params->param7, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_IS(index, class, name, paramType) \ - void class::setup_##name(paramType param1, const char *seq) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersISII) \ - EntityData::EntityParametersISII *params = (EntityData::EntityParametersISII*)_data->getCurrentParameters(); \ - params->param1 = (unsigned int)param1; \ - strncpy((char *)¶ms->seq, seq, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersISII) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s) - action: %s", params->param1, (char *)¶ms->seq, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_ISS(index, class, name, paramType) \ - void class::setup_##name(paramType param1, const char *seq1, const char *seq2) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersISSI) \ - EntityData::EntityParametersISSI *params = (EntityData::EntityParametersISSI*)_data->getCurrentParameters(); \ - params->param1 = param1; \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - strncpy((char *)¶ms->seq2, seq2, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersISSI) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %s, %s) - action: %s", params->param1, (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_IIS(index, class, name, paramType1, paramType2) \ - void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersIISI) \ - EntityData::EntityParametersIISI *params = (EntityData::EntityParametersIISI*)_data->getCurrentParameters(); \ - params->param1 = param1; \ - params->param2 = param2; \ - strncpy((char *)¶ms->seq, seq, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIISI) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s) - action: %s", params->param1, params->param2, (char *)¶ms->seq, ACTION_NAME(savepoint.action)); - -#define IMPLEMENT_FUNCTION_IISS(index, class, name, paramType1, paramType2) \ - void class::setup_##name(paramType1 param1, paramType2 param2, const char *seq1, const char *seq2) { \ - BEGIN_SETUP(class, name, index, EntityData::EntityParametersIISS) \ - EntityData::EntityParametersIISS *params = (EntityData::EntityParametersIISS*)_data->getCurrentParameters(); \ - params->param1 = param1; \ - params->param2 = param2; \ - strncpy((char *)¶ms->seq1, seq1, 12); \ - strncpy((char *)¶ms->seq2, seq2, 12); \ - END_SETUP() \ - } \ - void class::name(const SavePoint &savepoint) { \ - EXPOSE_PARAMS(EntityData::EntityParametersIISS) \ - debugC(6, kLastExpressDebugLogic, "Entity: " #class "::" #name "(%d, %d, %s, %s) - action: %s", params->param1, params->param2, (char *)¶ms->seq1, (char *)¶ms->seq2, ACTION_NAME(savepoint.action)); - - -////////////////////////////////////////////////////////////////////////// -// Misc -////////////////////////////////////////////////////////////////////////// -#define RESET_ENTITY_STATE(entity, class, function) \ - getEntities()->resetState(entity); \ - ((class *)getEntities()->get(entity))->function(); - -////////////////////////////////////////////////////////////////////////// -// Parameters macros (for default IIII parameters) -////////////////////////////////////////////////////////////////////////// -#define CURRENT_PARAM(index, id) \ - ((EntityData::EntityParametersIIII*)_data->getCurrentParameters(index))->param##id - -#define ENTITY_PARAM(index, id) \ - ((EntityData::EntityParametersIIII*)_data->getParameters(8, index))->param##id - -////////////////////////////////////////////////////////////////////////// -// Time check macros -////////////////////////////////////////////////////////////////////////// -#define TIME_CHECK(timeValue, parameter, function) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - function(); \ - break; \ - } - -#define TIME_CHECK_SAVEPOINT(timeValue, parameter, entity1, entity2, action) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - getSavePoints()->push(entity1, entity2, action); \ - } - -#define TIME_CHECK_CALLBACK(timeValue, parameter, callback, function) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - setCallback(callback); \ - function(); \ - break; \ - } - -#define TIME_CHECK_CALLBACK_1(timeValue, parameter, callback, function, param1) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - setCallback(callback); \ - function(param1); \ - break; \ - } - -#define TIME_CHECK_CALLBACK_2(timeValue, parameter, callback, function, param1, param2) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - setCallback(callback); \ - function(param1, param2); \ - break; \ - } - -#define TIME_CHECK_CALLBACK_3(timeValue, parameter, callback, function, param1, param2, param3) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - setCallback(callback); \ - function(param1, param2, param3); \ - break; \ - } - -#define TIME_CHECK_CALLBACK_INVENTORY(timeValue, parameter, callback, function) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - getData()->inventoryItem = kItemNone; \ - setCallback(callback); \ - function(); \ - break; \ - } - -#define TIME_CHECK_CALLBACK_ACTION(timeValue, parameter) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - CALLBACK_ACTION(); \ - break; \ - } - -#define TIME_CHECK_PLAYSOUND_UPDATEPOSITION(timeValue, parameter, callback, sound, position) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - getData()->entityPosition = position; \ - setCallback(callback); \ - setup_playSound(sound); \ - break; \ - } - -#define TIME_CHECK_OBJECT(timeValue, parameter, object, location) \ - if (getState()->time > timeValue && !parameter) { \ - parameter = 1; \ - getObjects()->updateLocation2(object, location); \ - } - -#define TIME_CHECK_CAR(timeValue, parameter, callback, function) {\ - if ((getState()->time <= timeValue && !getEntities()->isPlayerInCar(kCarGreenSleeping)) || !parameter) \ - parameter = (uint)getState()->time + 75; \ - if (getState()->time > timeValue || parameter < getState()->time) { \ - parameter = kTimeInvalid; \ - setCallback(callback); \ - function(); \ - break; \ - } \ -} - -////////////////////////////////////////////////////////////////////////// -// Callback action -////////////////////////////////////////////////////////////////////////// -#define CALLBACK_ACTION() { \ - if (getData()->currentCall == 0) \ - error("[CALLBACK_ACTION] currentCall is already 0, cannot proceed"); \ - getData()->currentCall--; \ - getSavePoints()->setCallback(_entityIndex, _callbacks[_data->getCurrentCallback()]); \ - getSavePoints()->call(_entityIndex, _entityIndex, kActionCallback); \ - } - -////////////////////////////////////////////////////////////////////////// -// Param update -////////////////////////////////////////////////////////////////////////// -#define UPDATE_PARAM(parameter, type, value) { \ - if (!parameter) \ - parameter = (uint)(type + value); \ - if (parameter >= type) \ - break; \ - parameter = kTimeInvalid; \ -} - -// Todo: replace with UPDATE_PARAM_PROC as appropriate -#define UPDATE_PARAM_GOTO(parameter, type, value, label) { \ - if (!parameter) \ - parameter = (uint)(type + value); \ - if (parameter >= type) \ - goto label; \ - parameter = kTimeInvalid; \ -} - -// Updating parameter with code inside the check -#define UPDATE_PARAM_PROC(parameter, type, value) \ - if (!parameter) \ - parameter = (uint)(type + value); \ - if (parameter < type) { \ - parameter = kTimeInvalid; - -#define UPDATE_PARAM_PROC_TIME(timeValue, test, parameter, value) \ - if (getState()->time <= timeValue) { \ - if (test || !parameter) \ - parameter = (uint)(getState()->time + value); \ - } \ - if (parameter < getState()->time || getState()->time > timeValue) { \ - parameter = kTimeInvalid; - -#define UPDATE_PARAM_PROC_END } - -// Updating parameter with an added check (and code inside the check) -#define UPDATE_PARAM_CHECK(parameter, type, value) \ - if (!parameter || parameter < type) { \ - if (!parameter) \ - parameter = (uint)(type + value); - -////////////////////////////////////////////////////////////////////////// -// Compartments -////////////////////////////////////////////////////////////////////////// -// Go from one compartment to another (or the same one if no optional args are passed -#define COMPARTMENT_TO(class, compartmentFrom, positionFrom, sequenceFrom, sequenceTo) \ - switch (savepoint.action) { \ - default: \ - break; \ - case kActionDefault: \ - getData()->entityPosition = positionFrom; \ - setCallback(1); \ - setup_enterExitCompartment(sequenceFrom, compartmentFrom); \ - break; \ - case kActionCallback: \ - switch (getCallback()) { \ - default: \ - break; \ - case 1: \ - setCallback(2); \ - setup_enterExitCompartment(sequenceTo, compartmentFrom); \ - break; \ - case 2: \ - getData()->entityPosition = positionFrom; \ - getEntities()->clearSequences(_entityIndex); \ - CALLBACK_ACTION(); \ - } \ - break; \ - } - -#define COMPARTMENT_FROM_TO(class, compartmentFrom, positionFrom, sequenceFrom, compartmentTo, positionTo, sequenceTo) \ - switch (savepoint.action) { \ - default: \ - break; \ - case kActionDefault: \ - getData()->entityPosition = positionFrom; \ - getData()->location = kLocationOutsideCompartment; \ - setCallback(1); \ - setup_enterExitCompartment(sequenceFrom, compartmentFrom); \ - break; \ - case kActionCallback: \ - switch (getCallback()) { \ - default: \ - break; \ - case 1: \ - setCallback(2); \ - setup_updateEntity(kCarGreenSleeping, positionTo); \ - break; \ - case 2: \ - setCallback(3); \ - setup_enterExitCompartment(sequenceTo, compartmentTo); \ - break; \ - case 3: \ - getData()->location = kLocationInsideCompartment; \ - getEntities()->clearSequences(_entityIndex); \ - CALLBACK_ACTION(); \ - break; \ - } \ - break; \ - } } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/francois.cpp b/engines/lastexpress/entities/francois.cpp index 46cd790ffb..d2bbc9854c 100644 --- a/engines/lastexpress/entities/francois.cpp +++ b/engines/lastexpress/entities/francois.cpp @@ -32,7 +32,6 @@ #include "lastexpress/sound/queue.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { @@ -114,7 +113,7 @@ IMPLEMENT_FUNCTION_II(8, Francois, updateEntity, CarIndex, EntityPosition) case kActionNone: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); } else { if (!getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000) || !getInventory()->hasItem(kItemFirebird) @@ -169,7 +168,7 @@ IMPLEMENT_FUNCTION_II(8, Francois, updateEntity, CarIndex, EntityPosition) case kActionDefault: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -225,7 +224,7 @@ IMPLEMENT_FUNCTION(9, Francois, function9) case 2: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -263,7 +262,7 @@ IMPLEMENT_FUNCTION(10, Francois, function10) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityFrancois); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -279,7 +278,7 @@ IMPLEMENT_FUNCTION_I(11, Francois, function11, TimeValue) case kActionNone: if (!getSoundQueue()->isBuffered(kEntityFrancois)) { - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->timeTicks, params->param6) + if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, params->param6)) { switch (rnd(7)) { default: break; @@ -312,7 +311,7 @@ IMPLEMENT_FUNCTION_I(11, Francois, function11, TimeValue) params->param6 = 15 * rnd(7); CURRENT_PARAM(1, 1) = 0; - UPDATE_PARAM_PROC_END + } } if (!getEntities()->hasValidFrame(kEntityFrancois) || !getEntities()->isWalkingOppositeToPlayer(kEntityFrancois)) @@ -442,7 +441,7 @@ label_callback: break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -465,7 +464,7 @@ label_callback: getData()->field_4A3 = 30; getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); break; case kAction205346192: @@ -524,7 +523,7 @@ IMPLEMENT_FUNCTION(12, Francois, function12) break; case 7: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -609,7 +608,7 @@ IMPLEMENT_FUNCTION(13, Francois, function13) break; case 11: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -708,7 +707,7 @@ IMPLEMENT_FUNCTION_IIS(14, Francois, function14, ObjectIndex, EntityPosition) break; case 13: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -764,7 +763,7 @@ IMPLEMENT_FUNCTION(15, Francois, function15) case 7: if (!getEntities()->isInsideCompartment(kEntityMmeBoutarel, kCarRedSleeping, kPosition_5790)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -773,7 +772,7 @@ IMPLEMENT_FUNCTION(15, Francois, function15) break; case 8: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -830,7 +829,7 @@ IMPLEMENT_FUNCTION(16, Francois, function16) getData()->entityPosition = kPosition_5790; getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -849,7 +848,7 @@ IMPLEMENT_FUNCTION(17, Francois, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Francois, setup_chapter1Handler)); break; case kActionDefault: @@ -867,7 +866,7 @@ IMPLEMENT_FUNCTION(18, Francois, chapter1Handler) break; case kActionNone: - TIME_CHECK_CALLBACK_1(kTimeParisEpernay, params->param1, 1, setup_function11, kTime1093500); + timeCheckCallback(kTimeParisEpernay, params->param1, 1, kTime1093500); break; case kActionCallback: @@ -884,7 +883,7 @@ IMPLEMENT_FUNCTION(19, Francois, function19) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime1161000, params->param1, 2, setup_function12); + Entity::timeCheckCallback(kTime1161000, params->param1, 2, WRAP_SETUP_FUNCTION(Francois, setup_function12)); break; case kAction101107728: @@ -979,17 +978,21 @@ IMPLEMENT_FUNCTION(23, Francois, function23) } label_callback_1: - TIME_CHECK_CALLBACK_1(kTime1764000, params->param1, 2, setup_playSound, "Fra2011"); + if (Entity::timeCheckCallback(kTime1764000, params->param1, 2, "Fra2011", WRAP_SETUP_FUNCTION_S(Francois, setup_playSound))) + break; label_callback_2: - TIME_CHECK_CALLBACK(kTime1800000, params->param2, 3, setup_function13); + if (Entity::timeCheckCallback(kTime1800000, params->param2, 3, WRAP_SETUP_FUNCTION(Francois, setup_function13))) + break; label_callback_3: if (!getInventory()->hasItem(kItemWhistle) && getInventory()->get(kItemWhistle)->location != kObjectLocation3) { - TIME_CHECK_CALLBACK_1(kTime1768500, params->param3, 4, setup_function11, kTime1773000); + if (timeCheckCallback(kTime1768500, params->param3, 4, kTime1773000)) + break; label_callback_4: - TIME_CHECK_CALLBACK_1(kTime1827000, params->param4, 5, setup_function11, kTime1831500); + if (timeCheckCallback(kTime1827000, params->param4, 5, kTime1831500)) + break; } label_callback_5: @@ -999,18 +1002,19 @@ label_callback_5: } if (params->param5 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(kTimeEnd, !getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000), params->param5, 75); + if (Entity::updateParameterTime(kTimeEnd, !getEntities()->isDistanceBetweenEntities(kEntityFrancois, kEntityPlayer, 2000), params->param5, 75)) { setCallback(6); setup_playSound("Fra2010"); break; - UPDATE_PARAM_PROC_END + } } label_callback_6: - TIME_CHECK_CALLBACK_3(kTime1782000, params->param6, 7, setup_function14, kObjectCompartmentC, kPosition_6470, "c"); + if (timeCheckCallbackCompartment(kTime1782000, params->param6, 7, kObjectCompartmentC, kPosition_6470, "c")) + break; label_callback_7: - TIME_CHECK_CALLBACK_3(kTime1813500, params->param7, 8, setup_function14, kObjectCompartmentF, kPosition_4070, "f"); + timeCheckCallbackCompartment(kTime1813500, params->param7, 8, kObjectCompartmentF, kPosition_4070, "f"); break; case kActionCallback: @@ -1086,32 +1090,41 @@ IMPLEMENT_FUNCTION(25, Francois, chapter3Handler) } label_callback_2: - TIME_CHECK_CALLBACK(kTime2025000, params->param3, 3, setup_function12); + if (Entity::timeCheckCallback(kTime2025000, params->param3, 3, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_3: - TIME_CHECK_CALLBACK(kTime2052000, params->param4, 4, setup_function12); + if (Entity::timeCheckCallback(kTime2052000, params->param4, 4, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_4: - TIME_CHECK_CALLBACK(kTime2079000, params->param5, 5, setup_function12); + if (Entity::timeCheckCallback(kTime2079000, params->param5, 5, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_5: - TIME_CHECK_CALLBACK(kTime2092500, params->param6, 6, setup_function12); + if (Entity::timeCheckCallback(kTime2092500, params->param6, 6, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_6: - TIME_CHECK_CALLBACK(kTime2173500, params->param7, 7, setup_function12); + if (Entity::timeCheckCallback(kTime2173500, params->param7, 7, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_7: - TIME_CHECK_CALLBACK(kTime2182500, params->param8, 8, setup_function12); + if (Entity::timeCheckCallback(kTime2182500, params->param8, 8, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_8: - TIME_CHECK_CALLBACK(kTime2241000, CURRENT_PARAM(1, 1), 9, setup_function12); + if (Entity::timeCheckCallback(kTime2241000, CURRENT_PARAM(1, 1), 9, WRAP_SETUP_FUNCTION(Francois, setup_function12))) + break; label_callback_9: if (!getInventory()->hasItem(kItemWhistle) && getInventory()->get(kItemWhistle)->location != kObjectLocation3) { - TIME_CHECK_CALLBACK_1(kTime2011500, CURRENT_PARAM(1, 2), 10, setup_function11, kTime2016000); + if (timeCheckCallback(kTime2011500, CURRENT_PARAM(1, 2), 10, kTime2016000)) + break; label_callback_10: - TIME_CHECK_CALLBACK_1(kTime2115000, CURRENT_PARAM(1, 3), 11, setup_function11, kTime2119500); + if (timeCheckCallback(kTime2115000, CURRENT_PARAM(1, 3), 11, kTime2119500)) + break; } label_callback_11: @@ -1129,13 +1142,15 @@ label_callback_11: } label_callback_12: - TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 5), 13, setup_function14, kObjectCompartmentE, kPosition_4840, "e"); + if (timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 5), 13, kObjectCompartmentE, kPosition_4840, "e")) + break; label_callback_13: - TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 6), 14, setup_function14, kObjectCompartmentF, kPosition_4070, "f"); + if (timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 6), 14, kObjectCompartmentF, kPosition_4070, "f")) + break; label_callback_14: - TIME_CHECK_CALLBACK_3(kTime2040300, CURRENT_PARAM(1, 7), 15, setup_function14, kObjectCompartmentB, kPosition_7500, "b"); + timeCheckCallbackCompartment(kTime2040300, CURRENT_PARAM(1, 7), 15, kObjectCompartmentB, kPosition_7500, "b"); } } break; @@ -1291,4 +1306,33 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_NULL_FUNCTION(31, Francois) + +////////////////////////////////////////////////////////////////////////// +// Helper functions +////////////////////////////////////////////////////////////////////////// +bool Francois::timeCheckCallbackCompartment(TimeValue timeValue, uint ¶meter, byte callback, ObjectIndex compartment, EntityPosition position, const char* sequenceSuffix) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + setup_function14(compartment, position, sequenceSuffix); + + return true; + } + + return false; +} + +bool Francois::timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, TimeValue timeValue2) { + if (getState()->time > timeValue && !parameter) { + parameter = 1; + setCallback(callback); + setup_function11(timeValue2); + + return true; + } + + return false; +} + + } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/francois.h b/engines/lastexpress/entities/francois.h index 19eca6fb50..51270fa4b6 100644 --- a/engines/lastexpress/entities/francois.h +++ b/engines/lastexpress/entities/francois.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_FRANCOIS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -160,6 +159,10 @@ public: DECLARE_FUNCTION(function30) DECLARE_NULL_FUNCTION() + +private: + bool timeCheckCallbackCompartment(TimeValue timeValue, uint ¶meter, byte callback, ObjectIndex compartment, EntityPosition position, const char* sequenceSuffix); + bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, TimeValue timeValue2); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp index daa50956d3..a912fa4ecb 100644 --- a/engines/lastexpress/entities/gendarmes.cpp +++ b/engines/lastexpress/entities/gendarmes.cpp @@ -31,7 +31,6 @@ #include "lastexpress/game/state.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -67,7 +66,7 @@ IMPLEMENT_FUNCTION(2, Gendarmes, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Gendarmes, setup_chapter1Handler)); break; case kActionDefault: @@ -195,7 +194,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) break; case 1: - CALLBACK_ACTION(); + callbackAction(); break; case 2: @@ -233,7 +232,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) case 6: getData()->location = kLocationOutsideCompartment; getEntities()->exitCompartment(kEntityGendarmes, (ObjectIndex)parameters2->param5); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -267,11 +266,12 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje getSound()->playSound(kEntityGendarmes, "POL1046A", kFlagDefault); } - UPDATE_PARAM(params->param7, getState()->timeTicks, 300); + if (!Entity::updateParameter(params->param7, getState()->timeTicks, 300)) + break; if (!params->param4 && getEntities()->isOutsideAlexeiWindow()) { getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); } else { if (getEntities()->isOutsideAlexeiWindow()) getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49); @@ -322,7 +322,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverBloodJacket, true); getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 4: @@ -330,7 +330,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneGameOverPolice1, true); getObjects()->update((ObjectIndex)params->param3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 5: @@ -552,13 +552,14 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl case kActionNone: if (checkCallback) { EXPOSE_PARAMS(EntityData::EntityParametersIIII); - TIME_CHECK_CALLBACK_ACTION(params->param1, params->param2); + if (Entity::timeCheckCallbackAction((TimeValue)params->param1, params->param2)) + break; } if (shouldUpdateEntity) { EXPOSE_PARAMS(EntityData::EntityParametersIIII); if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } } @@ -582,7 +583,7 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -599,7 +600,7 @@ void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFl if (shouldUpdateEntity) { EXPOSE_PARAMS(EntityData::EntityParametersIIII); if (getEntities()->updateEntity(kEntityGendarmes, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } } diff --git a/engines/lastexpress/entities/gendarmes.h b/engines/lastexpress/entities/gendarmes.h index d999cfc1fd..a761643531 100644 --- a/engines/lastexpress/entities/gendarmes.h +++ b/engines/lastexpress/entities/gendarmes.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_GENDARMES_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" #include "lastexpress/sound/sound.h" diff --git a/engines/lastexpress/entities/hadija.cpp b/engines/lastexpress/entities/hadija.cpp index 8ec972b939..e9abcd888a 100644 --- a/engines/lastexpress/entities/hadija.cpp +++ b/engines/lastexpress/entities/hadija.cpp @@ -28,10 +28,7 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -89,22 +86,22 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(6, Hadija, compartment6) - COMPARTMENT_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Cf", "619Df"); + Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Cf", "619Df"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(7, Hadija, compartment8) - COMPARTMENT_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh"); + Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(8, Hadija, compartment6to8) - COMPARTMENT_FROM_TO(Hadija, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah"); + Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(9, Hadija, compartment8to6) - COMPARTMENT_FROM_TO(Hadija, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af"); + Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -114,7 +111,7 @@ IMPLEMENT_FUNCTION(10, Hadija, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Hadija, setup_chapter1Handler)); break; case kActionDefault: @@ -133,10 +130,12 @@ IMPLEMENT_FUNCTION(11, Hadija, chapter1Handler) break; case kActionNone: - TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTimeParisEpernay, params->param1, 1, "Har1100", kPosition_4840); + if (Entity::timeCheckPlaySoundUpdatePosition(kTimeParisEpernay, params->param1, 1, "Har1100", kPosition_4840)) + break; label_callback1: - TIME_CHECK_CALLBACK(kTime1084500, params->param2, 2, setup_compartment6to8); + if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + break; label_callback2: if (params->param3 != kTimeInvalid && getState()->time > kTime1093500) { @@ -164,7 +163,8 @@ label_callback2: } label_callback3: - TIME_CHECK_CALLBACK(kTime1156500, params->param4, 4, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + break; label_callback4: if (params->param5 != kTimeInvalid && getState()->time > kTime1165500) { @@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) } if (params->param2 == kTimeInvalid || getState()->time <= kTime1786500) { - TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); break; } @@ -264,7 +264,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) params->param2 = (uint)getState()->time + 75; if (params->param2 >= getState()->time) { - TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); break; } } @@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) break; case 1: - TIME_CHECK_CALLBACK(kTime1822500, params->param3, 2, setup_compartment8to6); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); break; case 2: @@ -321,20 +321,26 @@ IMPLEMENT_FUNCTION(16, Hadija, chapter3Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime1998000, params->param1, 1, setup_compartment6to8); + if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + break; label_callback1: - TIME_CHECK_CALLBACK(kTime2020500, params->param2, 2, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + break; label_callback2: - TIME_CHECK_CALLBACK(kTime2079000, params->param3, 3, setup_compartment6to8); + if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + break; label_callback3: - TIME_CHECK_CALLBACK(kTime2187000, params->param4, 4, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + break; label_callback4: - if (params->param5 != kTimeInvalid && getState()->time > kTime2196000) - TIME_CHECK_CAR(kTime2254500, params->param5, 5, setup_compartment6); + if (params->param5 != kTimeInvalid && getState()->time > kTime2196000) { + if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + break; + } break; case kActionDefault: @@ -387,18 +393,24 @@ IMPLEMENT_FUNCTION(18, Hadija, chapter4Handler) break; case kActionNone: - if (params->param1 != kTimeInvalid) - TIME_CHECK_CAR(kTime1714500, params->param1, 1, setup_compartment6); + if (params->param1 != kTimeInvalid) { + if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + break; + } label_callback1: - TIME_CHECK_CALLBACK(kTime2367000, params->param2, 2, setup_compartment6to8); + if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + break; label_callback2: - TIME_CHECK_CALLBACK(kTime2421000, params->param3, 3, setup_compartment8to6); + if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + break; label_callback3: - if (params->param4 != kTimeInvalid && getState()->time > kTime2425500) - TIME_CHECK_CAR(kTime2484000, params->param4, 4, setup_compartment6); + if (params->param4 != kTimeInvalid && getState()->time > kTime2425500) { + if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + break; + } break; case kActionCallback: @@ -468,7 +480,9 @@ IMPLEMENT_FUNCTION(22, Hadija, function22) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 2700); + if (!Entity::updateParameter(params->param1, getState()->time, 2700)) + break; + setup_function23(); break; diff --git a/engines/lastexpress/entities/hadija.h b/engines/lastexpress/entities/hadija.h index d2495955e0..545f21ee03 100644 --- a/engines/lastexpress/entities/hadija.h +++ b/engines/lastexpress/entities/hadija.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_HADIJA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp index f2261b438c..c53f4689fb 100644 --- a/engines/lastexpress/entities/ivo.cpp +++ b/engines/lastexpress/entities/ivo.cpp @@ -32,10 +32,7 @@ #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -184,7 +181,7 @@ IMPLEMENT_FUNCTION(11, Ivo, function11) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityIvo); - CALLBACK_ACTION(); + callbackAction(); break; case 4: @@ -193,7 +190,7 @@ IMPLEMENT_FUNCTION(11, Ivo, function11) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityIvo); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -210,7 +207,7 @@ IMPLEMENT_FUNCTION(12, Ivo, sitAtTableWithSalko) getEntities()->clearSequences(kEntitySalko); getSavePoints()->push(kEntityIvo, kEntityTables2, kAction136455232); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -231,7 +228,7 @@ IMPLEMENT_FUNCTION(13, Ivo, leaveTableWithSalko) getSavePoints()->push(kEntityIvo, kEntityTables2, kActionDrawTablesWithChairs, "009E"); getEntities()->clearSequences(kEntitySalko); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -249,7 +246,7 @@ IMPLEMENT_FUNCTION(14, Ivo, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_chapter1Handler)); break; case kActionDefault: @@ -374,7 +371,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2) break; case kActionNone: - TIME_CHECK(kTime1777500, params->param1, setup_function19); + Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_function19)); break; case kActionDefault: diff --git a/engines/lastexpress/entities/ivo.h b/engines/lastexpress/entities/ivo.h index cd5cb7b6be..75814336e0 100644 --- a/engines/lastexpress/entities/ivo.h +++ b/engines/lastexpress/entities/ivo.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_IVO_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/kahina.cpp b/engines/lastexpress/entities/kahina.cpp index 2918b1e8bd..7860836a26 100644 --- a/engines/lastexpress/entities/kahina.cpp +++ b/engines/lastexpress/entities/kahina.cpp @@ -32,10 +32,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -90,7 +88,7 @@ IMPLEMENT_FUNCTION_END IMPLEMENT_FUNCTION_I(4, Kahina, updateFromTime, uint32) if (savepoint.action == kAction137503360) { ENTITY_PARAM(0, 2) = 1; - CALLBACK_ACTION(); + callbackAction(); } Entity::updateFromTime(savepoint); @@ -111,7 +109,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) if (params->param1 < getState()->time && !params->param2) { params->param2 = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -141,7 +139,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) case 1: if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -151,7 +149,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) case 2: case 3: if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -163,7 +161,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) case 4: if (ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -173,7 +171,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) case 5: if (ENTITY_PARAM(0, 1) || ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -185,7 +183,7 @@ IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) case kAction137503360: ENTITY_PARAM(0, 2) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -198,12 +196,12 @@ IMPLEMENT_FUNCTION_II(7, Kahina, updateEntity2, CarIndex, EntityPosition) case kActionNone: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: if (getEntities()->updateEntity(_entityIndex, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); } else if (getEntities()->isDistanceBetweenEntities(kEntityKahina, kEntityPlayer, 1000) && !getEntities()->isInGreenCarEntrance(kEntityPlayer) && !getEntities()->isInsideCompartments(kEntityPlayer) @@ -211,14 +209,14 @@ IMPLEMENT_FUNCTION_II(7, Kahina, updateEntity2, CarIndex, EntityPosition) if (getData()->car == kCarGreenSleeping || getData()->car == kCarRedSleeping) { ENTITY_PARAM(0, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); } } break; case kAction137503360: ENTITY_PARAM(0, 2) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -249,7 +247,7 @@ IMPLEMENT_FUNCTION(10, Kahina, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Kahina, setup_chapter1Handler)); break; case kActionDefault: @@ -269,7 +267,7 @@ IMPLEMENT_FUNCTION(11, Kahina, chapter1Handler) return; if (getProgress().jacket != kJacketOriginal) - TIME_CHECK_SAVEPOINT(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837); + Entity::timeCheckSavepoint(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837); if (getProgress().eventMertensKronosInvitation) setup_function12(); @@ -282,7 +280,7 @@ IMPLEMENT_FUNCTION(12, Kahina, function12) break; case kActionNone: - TIME_CHECK(kTime1485000, params->param2, setup_function13); + Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_function13)); break; case kActionKnock: @@ -372,12 +370,12 @@ IMPLEMENT_FUNCTION(14, Kahina, function14) case kActionExitCompartment: getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF); - CALLBACK_ACTION(); + callbackAction(); break; case kAction4: getEntities()->exitCompartment(kEntityKahina, kObjectCompartmentF); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -396,10 +394,10 @@ IMPLEMENT_FUNCTION(15, Kahina, function15) case kActionNone: if (params->param2 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param2, 0) + if (Entity::updateParameterTime((TimeValue)params->param1, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param2, 0)) { setCallback(9); setup_updateEntity(kCarRedSleeping, kPosition_4070); - UPDATE_PARAM_PROC_END + } } break; @@ -542,7 +540,7 @@ IMPLEMENT_FUNCTION(15, Kahina, function15) case 17: getEntities()->clearSequences(kEntityKahina); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -582,18 +580,18 @@ IMPLEMENT_FUNCTION(17, Kahina, chapter2Handler) case kActionNone: if (params->param1) { - UPDATE_PARAM_PROC(params->param2, getState()->time, 9000) + if (Entity::updateParameter(params->param2, getState()->time, 9000)) { params->param1 = 1; params->param2 = 0; - UPDATE_PARAM_PROC_END + } } if (getEvent(kEventKahinaAskSpeakFirebird) && getEvent(kEventKronosConversationFirebird) && getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 900) + if (Entity::updateParameter(params->param3, getState()->time, 900)) { setCallback(1); setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird); break; - UPDATE_PARAM_PROC_END + } } label_callback_3: @@ -729,7 +727,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition) RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function22); if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -745,7 +743,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition) case kActionDefault: if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -787,16 +785,17 @@ label_callback_2: } if (!params->param1) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 9000) + if (Entity::updateParameter(params->param3, getState()->time, 9000)) { params->param1 = 1; params->param3 = 0; - UPDATE_PARAM_PROC_END + } } if (getEvent(kEventKahinaAskSpeakFirebird) && !getEvent(kEventKronosConversationFirebird) && getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) { - UPDATE_PARAM(params->param4, getState()->time, 900); + if (!Entity::updateParameter(params->param4, getState()->time, 900)) + break; setCallback(3); setup_savegame(kSavegameTypeEvent, kEventKronosConversationFirebird); @@ -928,11 +927,11 @@ IMPLEMENT_FUNCTION(21, Kahina, function21) params->param3 = (uint)getState()->time + 4500; if (params->param6 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0) + if (Entity::updateParameterTime((TimeValue)params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0)) { setCallback(2); setup_function23(); break; - UPDATE_PARAM_PROC_END + } } } @@ -943,14 +942,14 @@ label_callback_2: params->param4 = (uint)getState()->time + 4500; if (params->param6 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param6, 0) + if (Entity::updateParameterTime((TimeValue)params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param6, 0)) { getSound()->playSound(kEntityPlayer, "LIB014", getSound()->getSoundFlag(kEntityKahina)); getSound()->playSound(kEntityPlayer, "LIB015", getSound()->getSoundFlag(kEntityKahina)); getEntities()->drawSequenceLeft(kEntityKahina, "202a"); params->param2 = 0; - UPDATE_PARAM_PROC_END + } } } @@ -1125,7 +1124,7 @@ IMPLEMENT_FUNCTION(23, Kahina, function23) case 7: getEntities()->clearSequences(kEntityKahina); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1262,7 +1261,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25) getProgress().field_78 = 1; ENTITY_PARAM(0, 3) = 0; - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -1303,7 +1302,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25) case 13: getEntities()->clearSequences(kEntityKahina); - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1387,7 +1386,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26) getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation2); getProgress().field_78 = 1; - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -1429,7 +1428,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26) case 9: getEntities()->clearSequences(kEntityKahina); - CALLBACK_ACTION(); + callbackAction(); break; case 6: diff --git a/engines/lastexpress/entities/kahina.h b/engines/lastexpress/entities/kahina.h index b25053e339..7479cf76f9 100644 --- a/engines/lastexpress/entities/kahina.h +++ b/engines/lastexpress/entities/kahina.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_KAHINA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/kronos.cpp b/engines/lastexpress/entities/kronos.cpp index 134dce9c81..26ce3ca424 100644 --- a/engines/lastexpress/entities/kronos.cpp +++ b/engines/lastexpress/entities/kronos.cpp @@ -39,10 +39,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -128,7 +126,7 @@ IMPLEMENT_FUNCTION(7, Kronos, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Kronos, setup_chapter1Handler)); break; case kActionDefault: @@ -149,7 +147,7 @@ IMPLEMENT_FUNCTION(8, Kronos, chapter1Handler) break; case kActionNone: - TIME_CHECK(kTime1489500, params->param2, setup_function11); + Entity::timeCheck(kTime1489500, params->param2, WRAP_SETUP_FUNCTION(Kronos, setup_function11)); break; case kAction171849314: @@ -191,7 +189,7 @@ IMPLEMENT_FUNCTION(10, Kronos, function10) break; case kActionNone: - TIME_CHECK(kTime1489500, params->param1, setup_function11); + Entity::timeCheck(kTime1489500, params->param1, WRAP_SETUP_FUNCTION(Kronos, setup_function11)); break; case kActionDefault: @@ -295,10 +293,10 @@ IMPLEMENT_FUNCTION(15, Kronos, function15) case kActionNone: if (params->param1 && !getEntities()->isInSalon(kEntityBoutarel)) { - UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param2, getState()->timeTicks, 75)) { setup_function16(); break; - UPDATE_PARAM_PROC_END + } } if (params->param3 != kTimeInvalid && getState()->time > kTime2002500) { @@ -407,8 +405,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18) params->param2 = 1; } - TIME_CHECK(kTime2106000, params->param3, setup_function19) - else { + if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_function19))) { if (params->param1 && getEntities()->isInKronosSanctum(kEntityPlayer)) { setCallback(1); setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4); @@ -528,9 +525,9 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) } if (CURRENT_PARAM(1, 2) != kTimeInvalid && params->param7 < getState()->time) { - UPDATE_PARAM_PROC_TIME(params->param8, !params->param1, CURRENT_PARAM(1, 2), 450) + if (Entity::updateParameterTime((TimeValue)params->param8, !params->param1, CURRENT_PARAM(1, 2), 450)) { getSavePoints()->push(kEntityKronos, kEntityKahina, kAction237555748); - UPDATE_PARAM_PROC_END + } } if (!params->param1) diff --git a/engines/lastexpress/entities/kronos.h b/engines/lastexpress/entities/kronos.h index 4c61b98620..a7693fcd46 100644 --- a/engines/lastexpress/entities/kronos.h +++ b/engines/lastexpress/entities/kronos.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_KRONOS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/mahmud.cpp b/engines/lastexpress/entities/mahmud.cpp index 0e67b45cd2..af86ef8cdd 100644 --- a/engines/lastexpress/entities/mahmud.cpp +++ b/engines/lastexpress/entities/mahmud.cpp @@ -34,10 +34,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -86,7 +84,8 @@ IMPLEMENT_FUNCTION_SIII(4, Mahmud, enterExitCompartment2, ObjectIndex, uint32, O break; case kActionNone: - UPDATE_PARAM(params->param7, getState()->timeTicks, params->param5); + if (!Entity::updateParameter(params->param7, getState()->timeTicks, params->param5)) + break; if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) getScenes()->loadSceneFromObject((ObjectIndex)params->param6, true); @@ -95,7 +94,7 @@ IMPLEMENT_FUNCTION_SIII(4, Mahmud, enterExitCompartment2, ObjectIndex, uint32, O case kActionExitCompartment: getEntities()->exitCompartment(kEntityMahmud, (ObjectIndex)params->param4); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -146,7 +145,8 @@ IMPLEMENT_FUNCTION_II(10, Mahmud, function10, ObjectIndex, bool) break; case kActionNone: - UPDATE_PARAM(params->param6, getState()->time, 13500); + if (!Entity::updateParameter(params->param6, getState()->time, 13500)) + break; getObjects()->update(kObjectCompartment5, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand); getObjects()->update(kObjectCompartment6, kEntityTrain, kObjectLocation3, kCursorHandKnock, kCursorHand); @@ -267,7 +267,7 @@ IMPLEMENT_FUNCTION_II(10, Mahmud, function10, ObjectIndex, bool) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityMahmud); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -392,7 +392,7 @@ IMPLEMENT_FUNCTION(11, Mahmud, function11) getEntities()->clearSequences(kEntityMahmud); getObjects()->update(kObjectCompartment4, kEntityMahmud, kObjectLocation3, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -471,7 +471,7 @@ IMPLEMENT_FUNCTION(12, Mahmud, function12) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityMahmud); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -537,7 +537,7 @@ IMPLEMENT_FUNCTION(13, Mahmud, function13) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityMahmud); - CALLBACK_ACTION(); + callbackAction(); break; } @@ -560,7 +560,8 @@ IMPLEMENT_FUNCTION(14, Mahmud, chaptersHandler) if (!params->param2 && getProgress().chapter == kChapter1) { - TIME_CHECK_CALLBACK(kTime1098000, params->param6, 1, setup_function13); + if (Entity::timeCheckCallback(kTime1098000, params->param6, 1, WRAP_SETUP_FUNCTION(Mahmud, setup_function13))) + break; if (!getSoundQueue()->isBuffered("HAR1104") && getState()->time > kTime1167300 && !params->param7) { params->param7 = 1; @@ -572,7 +573,8 @@ IMPLEMENT_FUNCTION(14, Mahmud, chaptersHandler) } if (params->param5) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75)) + break; params->param4 = 1; params->param5 = 0; @@ -732,7 +734,7 @@ IMPLEMENT_FUNCTION(15, Mahmud, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Mahmud, setup_chaptersHandler)); break; case kActionDefault: diff --git a/engines/lastexpress/entities/mahmud.h b/engines/lastexpress/entities/mahmud.h index 5feb95cba5..685100f078 100644 --- a/engines/lastexpress/entities/mahmud.h +++ b/engines/lastexpress/entities/mahmud.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_MAHMUD_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/max.cpp b/engines/lastexpress/entities/max.cpp index eacc38bf60..abd2aae9e4 100644 --- a/engines/lastexpress/entities/max.cpp +++ b/engines/lastexpress/entities/max.cpp @@ -31,10 +31,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -91,7 +89,8 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler) break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, params->param1); + if (!Entity::updateParameter(params->param2, getState()->time, params->param1)) + break; if (!getSoundQueue()->isBuffered(kEntityMax)) getSound()->playSound(kEntityMax, "Max1122"); @@ -125,7 +124,8 @@ IMPLEMENT_FUNCTION(7, Max, function7) break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, params->param1) + if (!Entity::updateParameter(params->param2, getState()->time, params->param1)) + break; if (!getSoundQueue()->isBuffered(kEntityMax)) getSound()->playSound(kEntityMax, "Max1122"); @@ -186,7 +186,7 @@ IMPLEMENT_FUNCTION(7, Max, function7) case kAction101687594: getEntities()->clearSequences(kEntityMax); - CALLBACK_ACTION(); + callbackAction(); break; case kAction122358304: @@ -195,7 +195,7 @@ IMPLEMENT_FUNCTION(7, Max, function7) getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); getObjects()->update(kObject53, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case kAction158007856: @@ -214,7 +214,8 @@ IMPLEMENT_FUNCTION(8, Max, chapter4Handler) break; case kActionNone: - UPDATE_PARAM(params->param3, getState()->time, params->param2); + if (!Entity::updateParameter(params->param3, getState()->time, params->param2)) + break; if (!getSoundQueue()->isBuffered(kEntityMax)) getSound()->playSound(kEntityMax, "Max3101"); @@ -323,7 +324,7 @@ IMPLEMENT_FUNCTION(10, Max, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter12_handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_chapter12_handler)); break; case kActionDefault: @@ -392,7 +393,8 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler) break; } - UPDATE_PARAM(params->param3, getState()->time, params->param1); + if (!Entity::updateParameter(params->param3, getState()->time, params->param1)) + break; if (!getSoundQueue()->isBuffered(kEntityMax)) getSound()->playSound(kEntityMax, "Max1122"); @@ -514,7 +516,8 @@ IMPLEMENT_FUNCTION(15, Max, function15) } if (!params->param1) { - UPDATE_PARAM(params->param3, getState()->time, 900); + if (!Entity::updateParameter(params->param3, getState()->time, 900)) + break; getSavePoints()->push(kEntityMax, kEntityCoudert, kAction157026693); } diff --git a/engines/lastexpress/entities/max.h b/engines/lastexpress/entities/max.h index 17b58475aa..acd8235e89 100644 --- a/engines/lastexpress/entities/max.h +++ b/engines/lastexpress/entities/max.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_MAX_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/mertens.cpp b/engines/lastexpress/entities/mertens.cpp index d88962fce2..97dd293793 100644 --- a/engines/lastexpress/entities/mertens.cpp +++ b/engines/lastexpress/entities/mertens.cpp @@ -32,21 +32,11 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { -#define SAVEGAME_BLOOD_JACKET() \ - if (getProgress().jacket == kJacketBlood \ - && getEntities()->isDistanceBetweenEntities(kEntityMertens, kEntityPlayer, 1000) \ - && !getEntities()->isInsideCompartments(kEntityPlayer) \ - && !getEntities()->checkFields10(kEntityPlayer)) { \ - setCallback(1); \ - setup_savegame(kSavegameTypeEvent, kEventMertensBloodJacket); \ - } Mertens::Mertens(LastExpressEngine *engine) : Entity(engine, kEntityMertens) { ADD_CALLBACK_FUNCTION(Mertens, reset); @@ -117,11 +107,11 @@ IMPLEMENT_FUNCTION_S(2, Mertens, bloodJacket) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -144,7 +134,7 @@ IMPLEMENT_FUNCTION_SI(3, Mertens, enterExitCompartment, ObjectIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); return; case kActionCallback: @@ -165,12 +155,12 @@ IMPLEMENT_FUNCTION_SI(4, Mertens, enterExitCompartment2, ObjectIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); return; case kAction4: getEntities()->exitCompartment(kEntityMertens, (ObjectIndex)params->param4); - CALLBACK_ACTION(); + callbackAction(); return; case kActionCallback: @@ -191,13 +181,13 @@ IMPLEMENT_FUNCTION_SIII(5, Mertens, enterExitCompartment3, ObjectIndex, EntityPo break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionExitCompartment: getEntities()->exitCompartment(_entityIndex, (ObjectIndex)params->param4); getData()->entityPosition = (EntityPosition)params->param5; - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -229,15 +219,15 @@ IMPLEMENT_FUNCTION(6, Mertens, callbackActionOnDirection) case kActionNone: if (getData()->direction != kDirectionRight) { - CALLBACK_ACTION(); + callbackAction(); break; } - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -256,11 +246,11 @@ IMPLEMENT_FUNCTION_S(7, Mertens, playSound) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -283,11 +273,11 @@ IMPLEMENT_FUNCTION_S(8, Mertens, playSound16) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -310,14 +300,6 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) - -#define LOADSCENE_FROM_POSITION() \ - if (getData()->direction != kDirectionUp) { \ - getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750)); \ - } else { \ - getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition - 750), true); \ - } - switch (savepoint.action) { default: break; @@ -333,7 +315,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) || getEntities()->checkFields10(kEntityPlayer)) { if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -364,7 +346,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) { getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -395,7 +377,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) params->param3 = 1; if (getEntities()->updateEntity(kEntityMertens, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -416,7 +398,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) ENTITY_PARAM(0, 7) = 0; if (params->param1 != 3 || (params->param2 != kPosition_8200 && params->param2 != kPosition_9510)) { - LOADSCENE_FROM_POSITION(); + loadSceneFromPosition(); break; } @@ -428,7 +410,7 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000); getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750)); - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -444,35 +426,33 @@ IMPLEMENT_FUNCTION_II(10, Mertens, updateEntity, CarIndex, EntityPosition) getEntities()->updateEntity(kEntityMertens, kCarGreenSleeping, kPosition_2000); getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750)); - CALLBACK_ACTION(); + callbackAction(); break; } - LOADSCENE_FROM_POSITION(); + loadSceneFromPosition(); break; case 4: getAction()->playAnimation(kEventMertensKronosConcertInvitation); ENTITY_PARAM(2, 4) = 0; - LOADSCENE_FROM_POSITION(); + loadSceneFromPosition(); break; case 5: getAction()->playAnimation(getData()->entityPosition < getEntityData(kEntityPlayer)->entityPosition ? kEventMertensAskTylerCompartmentD : kEventMertensAskTylerCompartment); - LOADSCENE_FROM_POSITION(); + loadSceneFromPosition(); break; case 6: getAction()->playAnimation(kEventMertensDontMakeBed); - LOADSCENE_FROM_POSITION(); + loadSceneFromPosition(); ENTITY_PARAM(0, 4) = 0; break; } break; } - -#undef LOADSCENE_FROM_POSITION IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -482,11 +462,12 @@ IMPLEMENT_FUNCTION_I(11, Mertens, function11, uint32) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); - UPDATE_PARAM(params->param2, getState()->time, params->param1) + if (!Entity::updateParameter(params->param2, getState()->time, params->param1)) + break; - CALLBACK_ACTION(); + callbackAction(); break; case kActionCallback: @@ -506,7 +487,7 @@ IMPLEMENT_FUNCTION_I(12, Mertens, bonsoir, EntityIndex) return; if (getSoundQueue()->isBuffered(kEntityMertens)) { - CALLBACK_ACTION(); + callbackAction(); return; } @@ -540,7 +521,7 @@ IMPLEMENT_FUNCTION_I(12, Mertens, bonsoir, EntityIndex) getSound()->playSound(kEntityMertens, "CON1112G"); } - CALLBACK_ACTION(); + callbackAction(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -550,23 +531,23 @@ IMPLEMENT_FUNCTION_II(13, Mertens, function13, bool, bool) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); if (!params->param2 && !params->param3) { - UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param4, getState()->timeTicks, 75)) { getData()->inventoryItem = kItemNone; setCallback(5); setup_function18(); break; - UPDATE_PARAM_PROC_END + } } - UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, 225) + if (Entity::updateParameter(params->param5, getState()->timeTicks, 225)) { getData()->inventoryItem = kItemNone; setCallback(6); setup_function18(); break; - UPDATE_PARAM_PROC_END + } getData()->inventoryItem = (getProgress().chapter == kChapter1 && !ENTITY_PARAM(2, 1) @@ -640,7 +621,7 @@ IMPLEMENT_FUNCTION_II(13, Mertens, function13, bool, bool) case 6: case 9: case 10: - CALLBACK_ACTION(); + callbackAction(); break; case 7: @@ -672,7 +653,7 @@ IMPLEMENT_FUNCTION_I(14, Mertens, function14, EntityIndex) break; case kActionNone: - SAVEGAME_BLOOD_JACKET(); + Entity::savegameBloodJacket(); break; case kActionDefault: @@ -719,7 +700,7 @@ IMPLEMENT_FUNCTION_I(14, Mertens, function14, EntityIndex) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -783,7 +764,7 @@ IMPLEMENT_FUNCTION_I(15, Mertens, function15, bool) break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -860,7 +841,7 @@ IMPLEMENT_FUNCTION_I(16, Mertens, function16, bool) break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -888,7 +869,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17) getScenes()->loadSceneFromItemPosition(kItem7); ENTITY_PARAM(2, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -926,7 +907,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17) break; case 2: - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -944,7 +925,7 @@ IMPLEMENT_FUNCTION(17, Mertens, function17) getSavePoints()->push(kEntityMertens, kEntityMertens, kActionDrawScene); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -970,7 +951,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18) getInventory()->setLocationAndProcess(kItem7, kObjectLocation1); ENTITY_PARAM(2, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -978,7 +959,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18) getScenes()->loadSceneFromItemPosition(kItem7); ENTITY_PARAM(2, 1) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1009,7 +990,7 @@ IMPLEMENT_FUNCTION(18, Mertens, function18) ENTITY_PARAM(0, 1) = 0; getData()->inventoryItem = kItemNone; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -1025,7 +1006,7 @@ IMPLEMENT_FUNCTION(19, Mertens, function19) if (ENTITY_PARAM(2, 1)) { getInventory()->setLocationAndProcess(kItem7, kObjectLocation1); ENTITY_PARAM(2, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); } else { setCallback(1); setup_bloodJacket("601C"); @@ -1039,7 +1020,7 @@ IMPLEMENT_FUNCTION(19, Mertens, function19) if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2)) getData()->entityPosition = kPosition_2088; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -1057,7 +1038,7 @@ IMPLEMENT_FUNCTION(20, Mertens, function20) if (ENTITY_PARAM(2, 1)) { ENTITY_PARAM(2, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); } else { setCallback(1); setup_bloodJacket("601C"); @@ -1066,7 +1047,7 @@ IMPLEMENT_FUNCTION(20, Mertens, function20) case kActionCallback: if (getCallback() == 1) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -1078,11 +1059,12 @@ IMPLEMENT_FUNCTION_II(21, Mertens, function21, ObjectIndex, ObjectIndex) break; case kActionNone: - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 4), getState()->time, 300) + if (Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->time, 300)) { getSound()->playSound(kEntityPlayer, "ZFX1004", getSound()->getSoundFlag(kEntityMertens)); - UPDATE_PARAM_PROC_END + } - UPDATE_PARAM(CURRENT_PARAM(1, 5), getState()->time, 900); + if (!Entity::updateParameter(CURRENT_PARAM(1, 5), getState()->time, 900)) + break; // Update objects getObjects()->updateLocation2((ObjectIndex)params->param1, kObjectLocation1); @@ -1092,7 +1074,7 @@ IMPLEMENT_FUNCTION_II(21, Mertens, function21, ObjectIndex, ObjectIndex) if (params->param2) getObjects()->update((ObjectIndex)params->param2, (EntityIndex)params->param8, (ObjectLocation)CURRENT_PARAM(1, 1), (CursorStyle)CURRENT_PARAM(1, 2), (CursorStyle)CURRENT_PARAM(1, 3)); - CALLBACK_ACTION(); + callbackAction(); break; case kActionKnock: @@ -1222,7 +1204,7 @@ IMPLEMENT_FUNCTION(22, Mertens, function22) break; case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1291,7 +1273,7 @@ IMPLEMENT_FUNCTION(23, Mertens, function23) case 6: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1306,7 +1288,8 @@ IMPLEMENT_FUNCTION(24, Mertens, function24) case kActionNone: if (!params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment3("601Rc", kObjectCompartment3, kPosition_6470, kPosition_6130); @@ -1351,7 +1334,7 @@ IMPLEMENT_FUNCTION(24, Mertens, function24) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1380,7 +1363,7 @@ IMPLEMENT_FUNCTION(24, Mertens, function24) break; case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1409,7 +1392,8 @@ IMPLEMENT_FUNCTION(25, Mertens, function25) case kActionNone: if (!params->param1) { - UPDATE_PARAM(params->param2, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 75)) + break; setCallback(3); setup_enterExitCompartment3("601Zb", kObjectCompartment2, kPosition_7500, kPositionNone); @@ -1458,7 +1442,7 @@ IMPLEMENT_FUNCTION(25, Mertens, function25) case 5: getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -1492,7 +1476,7 @@ IMPLEMENT_FUNCTION(25, Mertens, function25) break; case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1547,7 +1531,7 @@ IMPLEMENT_FUNCTION_I(26, Mertens, function26, bool) case 2: getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -1613,7 +1597,7 @@ IMPLEMENT_FUNCTION_I(26, Mertens, function26, bool) getData()->location = kLocationOutsideCompartment; getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1628,17 +1612,17 @@ IMPLEMENT_FUNCTION_I(27, Mertens, tylerCompartment, MertensActionType) case kActionNone: if (getProgress().field_14 == 29) { - CALLBACK_ACTION(); + callbackAction(); break; } - UPDATE_PARAM_PROC(params->param2, getState()->timeTicks, 150) + if (Entity::updateParameter(params->param2, getState()->timeTicks, 150)) { getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal); setCallback(10); setup_playSound16("CON1018A"); break; - UPDATE_PARAM_PROC_END + } label_callback10: if (!params->param3) @@ -1646,7 +1630,8 @@ label_callback10: if (params->param3 >= getState()->timeTicks) { label_callback11: - UPDATE_PARAM(params->param4, getState()->timeTicks, 375); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 375)) + break; getSound()->playSound(kEntityPlayer, "LIB033"); @@ -1680,7 +1665,7 @@ label_callback11: getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; } } else { @@ -1738,7 +1723,7 @@ label_callback11: getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; } } else { @@ -1763,7 +1748,7 @@ label_callback11: default: getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 1: @@ -1821,7 +1806,7 @@ label_callback11: getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; } } else { @@ -1930,7 +1915,7 @@ label_callback11: getData()->location = kLocationOutsideCompartment; getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 8: @@ -1957,7 +1942,7 @@ label_callback11: case 19: case 22: case 28: - CALLBACK_ACTION(); + callbackAction(); break; case 15: @@ -1969,7 +1954,7 @@ label_callback11: getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; case 16: @@ -1981,27 +1966,27 @@ label_callback11: getSound()->playSound(kEntityPlayer, "LIB015"); getScenes()->loadScene(kScene41); - CALLBACK_ACTION(); + callbackAction(); break; case 23: getProgress().eventMertensAugustWaiting = true; getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 24: getProgress().eventMertensKronosInvitation = true; getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 25: getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2053,7 +2038,7 @@ IMPLEMENT_FUNCTION_S(28, Mertens, function28) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2115,7 +2100,7 @@ IMPLEMENT_FUNCTION_SS(29, Mertens, function29) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2140,14 +2125,14 @@ IMPLEMENT_FUNCTION_I(30, Mertens, function30, MertensActionType) case kActionDefault: switch (params->param1) { default: - CALLBACK_ACTION(); + callbackAction(); return; case 1: params->param2 = kPosition_8200; if (getProgress().field_14) { - CALLBACK_ACTION(); + callbackAction(); return; } @@ -2273,7 +2258,7 @@ IMPLEMENT_FUNCTION_I(30, Mertens, function30, MertensActionType) break; case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2312,7 +2297,7 @@ IMPLEMENT_FUNCTION_I(31, Mertens, function31, MertensActionType) case 2: case 3: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2360,7 +2345,7 @@ IMPLEMENT_FUNCTION(32, Mertens, function32) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2382,7 +2367,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33) setCallback(ENTITY_PARAM(0, 8) ? 1 : 3); setup_updateEntity(kCarGreenSleeping, ENTITY_PARAM(0, 8) ? kPosition_1500 : kPosition_540); } else { - CALLBACK_ACTION(); + callbackAction(); } break; @@ -2401,7 +2386,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33) case 2: ENTITY_PARAM(1, 8) = 0; - CALLBACK_ACTION(); + callbackAction(); break; case 3: @@ -2480,7 +2465,7 @@ IMPLEMENT_FUNCTION(33, Mertens, function33) break; } - CALLBACK_ACTION(); + callbackAction(); break; case 12: @@ -2493,13 +2478,13 @@ IMPLEMENT_FUNCTION(33, Mertens, function33) break; } - CALLBACK_ACTION(); + callbackAction(); break; case 13: ENTITY_PARAM(2, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2513,7 +2498,7 @@ IMPLEMENT_FUNCTION(34, Mertens, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Mertens, setup_chapter1Handler)); break; case kActionDefault: @@ -2548,7 +2533,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35) case kActionDefault: if (getProgress().field_14 == 29) { - CALLBACK_ACTION(); + callbackAction(); break; } else { getProgress().field_14 = 3; @@ -2589,7 +2574,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; case 5: @@ -2611,7 +2596,7 @@ IMPLEMENT_FUNCTION(35, Mertens, function35) break; case 7: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2626,7 +2611,7 @@ IMPLEMENT_FUNCTION(36, Mertens, function36) case kActionDefault: if (getProgress().field_14 == 29) { - CALLBACK_ACTION(); + callbackAction(); } else { getProgress().field_14 = 3; @@ -2712,7 +2697,7 @@ IMPLEMENT_FUNCTION(36, Mertens, function36) case 6: case 9: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2767,7 +2752,7 @@ IMPLEMENT_FUNCTION(37, Mertens, function37) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2791,12 +2776,12 @@ IMPLEMENT_FUNCTION(38, Mertens, function38) case kActionDefault: if (!ENTITY_PARAM(0, 4)) { - CALLBACK_ACTION(); + callbackAction(); break; } if (getProgress().field_14 == 29) { - CALLBACK_ACTION(); + callbackAction(); } else { setCallback(1); setup_updateEntity(kCarGreenSleeping, kPosition_8200); @@ -2810,7 +2795,7 @@ IMPLEMENT_FUNCTION(38, Mertens, function38) case 1: if (!ENTITY_PARAM(0, 4)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -2820,7 +2805,7 @@ IMPLEMENT_FUNCTION(38, Mertens, function38) case 2: ENTITY_PARAM(0, 4) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2894,7 +2879,7 @@ IMPLEMENT_FUNCTION(39, Mertens, function39) break; case 10: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -2940,7 +2925,7 @@ IMPLEMENT_FUNCTION(40, Mertens, function40) case 5: ENTITY_PARAM(0, 6) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -3013,7 +2998,7 @@ IMPLEMENT_FUNCTION(42, Mertens, function42) getData()->inventoryItem = kItemInvalid; if (!params->param2) { - TIME_CHECK_SAVEPOINT(kTime1125000, params->param3, kEntityMertens, kEntityMahmud, kAction170483072); + Entity::timeCheckSavepoint(kTime1125000, params->param3, kEntityMertens, kEntityMahmud, kAction170483072); if (params->param4 != kTimeInvalid && getState()->time > kTimeCityChalons) { @@ -3040,11 +3025,11 @@ IMPLEMENT_FUNCTION(42, Mertens, function42) label_callback_8: if (getState()->time > kTime1215000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) { - UPDATE_PARAM_PROC(params->param5, getState()->time, 2700) + if (Entity::updateParameter(params->param5, getState()->time, 2700)) { getEntities()->drawSequenceLeft(kEntityMertens, "601E"); ENTITY_PARAM(0, 1) = 1; params->param5 = 0; - UPDATE_PARAM_PROC_END + } } if (ENTITY_PARAM(0, 8)) { @@ -3547,19 +3532,23 @@ label_callback_5: } label_callback_6: - TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 7, setup_function28, "CON3012"); + if (Entity::timeCheckCallback(kTime1971000, params->param1, 7, "CON3012", WRAP_SETUP_FUNCTION_S(Mertens, setup_function28))) + break; label_callback_7: - TIME_CHECK_CALLBACK(kTime2117700, params->param2, 8, setup_function32); + if (Entity::timeCheckCallback(kTime2117700, params->param2, 8, WRAP_SETUP_FUNCTION(Mertens, setup_function32))) + break; label_callback_8: - TIME_CHECK_CALLBACK_1(kTime2124000, params->param3, 9, setup_function28, "CON2010"); + if (Entity::timeCheckCallback(kTime2124000, params->param3, 9, "CON2010", WRAP_SETUP_FUNCTION_S(Mertens, setup_function28))) + break; label_callback_9: - TIME_CHECK_CALLBACK(kTime2146500, params->param4, 10, setup_function32); + if (Entity::timeCheckCallback(kTime2146500, params->param4, 10, WRAP_SETUP_FUNCTION(Mertens, setup_function32))) + break; label_callback_10: - TIME_CHECK_CALLBACK(kTime2169000, params->param5, 11, setup_function32); + Entity::timeCheckCallback(kTime2169000, params->param5, 11, WRAP_SETUP_FUNCTION(Mertens, setup_function32)); break; case kAction11: @@ -3742,21 +3731,26 @@ label_callback_3: label_callback_4: if (!params->param1) { - TIME_CHECK_CALLBACK(kTime2403000, params->param2, 5, setup_function49); + if (Entity::timeCheckCallback(kTime2403000, params->param2, 5, WRAP_SETUP_FUNCTION(Mertens, setup_function49))) + break; label_callback_5: - TIME_CHECK_CALLBACK(kTime2430000, params->param3, 6, setup_function32); + if (Entity::timeCheckCallback(kTime2430000, params->param3, 6, WRAP_SETUP_FUNCTION(Mertens, setup_function32))) + break; label_callback_6: - TIME_CHECK_CALLBACK(kTime2439000, params->param4, 7, setup_function32); + if (Entity::timeCheckCallback(kTime2439000, params->param4, 7, WRAP_SETUP_FUNCTION(Mertens, setup_function32))) + break; label_callback_7: - TIME_CHECK_CALLBACK(kTime2448000, params->param5, 8, setup_function32); + if (Entity::timeCheckCallback(kTime2448000, params->param5, 8, WRAP_SETUP_FUNCTION(Mertens, setup_function32))) + break; } label_callback_8: if (getState()->time > kTime2538000 && !ENTITY_PARAM(0, 1) && !ENTITY_PARAM(2, 1)) { - UPDATE_PARAM(params->param6, getState()->time, 2700); + if (!Entity::updateParameter(params->param6, getState()->time, 2700)) + break; getEntities()->drawSequenceLeft(kEntityMertens, "601E"); @@ -3913,7 +3907,7 @@ IMPLEMENT_FUNCTION(49, Mertens, function49) break; case 11: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -4010,7 +4004,8 @@ IMPLEMENT_FUNCTION(53, Mertens, function53) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param4, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 0; @@ -4108,4 +4103,15 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_NULL_FUNCTION(54, Mertens) +////////////////////////////////////////////////////////////////////////// +// Helper functions +////////////////////////////////////////////////////////////////////////// + +void Mertens::loadSceneFromPosition() { + if (getData()->direction != kDirectionUp) + getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition + 750)); + else + getEntities()->loadSceneFromEntityPosition(getData()->car, (EntityPosition)(getData()->entityPosition - 750), true); +} + } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/mertens.h b/engines/lastexpress/entities/mertens.h index 31b7a97dcd..4cc58fd4ba 100644 --- a/engines/lastexpress/entities/mertens.h +++ b/engines/lastexpress/entities/mertens.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_MERTENS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -210,6 +209,9 @@ public: DECLARE_FUNCTION(function53) DECLARE_NULL_FUNCTION() + +private: + void loadSceneFromPosition(); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp index ff3d2b6744..519a613497 100644 --- a/engines/lastexpress/entities/milos.cpp +++ b/engines/lastexpress/entities/milos.cpp @@ -36,10 +36,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -135,7 +133,7 @@ IMPLEMENT_FUNCTION_II(10, Milos, enterCompartmentDialog, CarIndex, EntityPositio case kActionNone: case kActionDefault: if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -173,16 +171,16 @@ IMPLEMENT_FUNCTION_I(11, Milos, function11, TimeValue) if (!params->param5 && params->param1 < getState()->time && !params->param7) { params->param7 = 1; - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param2) { - UPDATE_PARAM_PROC(params->param8, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param8, getState()->timeTicks, 75)) { params->param2 = 0; params->param3 = 1; getObjects()->update(kObjectCompartmentG, kEntityMilos, kObjectLocation1, kCursorNormal, kCursorNormal); - UPDATE_PARAM_PROC_END + } } params->param8 = 0; @@ -191,10 +189,10 @@ IMPLEMENT_FUNCTION_I(11, Milos, function11, TimeValue) break; if (params->param6) { - UPDATE_PARAM_PROC(CURRENT_PARAM(1, 1), getState()->time, 4500) + if (Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->time, 4500)) { params->param6 = 0; CURRENT_PARAM(1, 1) = 0; - UPDATE_PARAM_PROC_END + } } if (!getProgress().field_CC) { @@ -364,7 +362,7 @@ IMPLEMENT_FUNCTION(12, Milos, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Milos, setup_chapter1Handler)); break; case kActionDefault: @@ -394,7 +392,7 @@ IMPLEMENT_FUNCTION(13, Milos, function13) getEntities()->clearSequences(kEntityIvo); getEntities()->clearSequences(kEntitySalko); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -422,7 +420,7 @@ IMPLEMENT_FUNCTION(14, Milos, function14) getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true); getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -436,7 +434,8 @@ IMPLEMENT_FUNCTION(14, Milos, function14) if (CURRENT_PARAM(1, 1) < getState()->timeTicks) { if (getObjects()->get(kObjectCompartment1).location == kObjectLocation1) { - UPDATE_PARAM(CURRENT_PARAM(1, 2), getState()->timeTicks, 75); + if (!Entity::updateParameter(CURRENT_PARAM(1, 2), getState()->timeTicks, 75)) + break; getObjects()->update(kObjectCompartment1, kEntityMilos, getObjects()->get(kObjectCompartment1).location, kCursorNormal, kCursorNormal); @@ -474,7 +473,7 @@ IMPLEMENT_FUNCTION(14, Milos, function14) getObjects()->update(kObjectCompartment1, kEntityPlayer, getObjects()->get(kObjectCompartment1).location, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } } else { @@ -507,7 +506,8 @@ IMPLEMENT_FUNCTION(14, Milos, function14) } label_callback_12: - UPDATE_PARAM(CURRENT_PARAM(1, 4), getState()->timeTicks, 75); + if (!Entity::updateParameter(CURRENT_PARAM(1, 4), getState()->timeTicks, 75)) + break; getEntities()->exitCompartment(kEntityMilos, kObjectCompartment1, true); @@ -593,7 +593,7 @@ label_callback_12: getData()->location = kLocationOutsideCompartment; getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; case 2: @@ -633,7 +633,7 @@ label_callback_12: getScenes()->loadScene(kScene41); getData()->location = kLocationOutsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -722,7 +722,7 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560); + Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560); if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { setup_function16(); @@ -730,15 +730,16 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler) } if (getEntities()->isPlayerPosition(kCarRestaurant, 61) && !params->param1) { - UPDATE_PARAM_PROC(params->param4, getState()->timeTicks, 45) + if (Entity::updateParameter(params->param4, getState()->timeTicks, 45)) { setCallback(1); setup_draw("009C"); break; - UPDATE_PARAM_PROC_END + } } if (getEntities()->isPlayerPosition(kCarRestaurant, 70) && !params->param2) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 45); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 45)) + break; setCallback(2); setup_draw("009C"); @@ -953,7 +954,8 @@ IMPLEMENT_FUNCTION(21, Milos, function21) break; case kActionNone: - UPDATE_PARAM(params->param2, getState()->time, 4500); + if (!Entity::updateParameter(params->param2, getState()->time, 4500)) + break; params->param1 = 1; break; @@ -1118,7 +1120,8 @@ IMPLEMENT_FUNCTION(24, Milos, function24) } if (params->param1) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; @@ -1284,14 +1287,15 @@ IMPLEMENT_FUNCTION(25, Milos, function25) case kActionNone: if (!getEvent(kEventMilosCompartmentVisitTyler) && !getProgress().field_54 && !ENTITY_PARAM(0, 4)) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 13500) + if (Entity::updateParameter(params->param3, getState()->time, 13500)) { getSavePoints()->push(kEntityMilos, kEntityVesna, kAction155913424); params->param3 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param1) { - UPDATE_PARAM(params->param4, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; @@ -1386,7 +1390,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue) case kActionNone: if (params->param1 < getState()->time && !params->param2) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1415,7 +1419,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue) case 1: if (ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1425,7 +1429,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue) case 2: case 3: if (ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1442,7 +1446,7 @@ IMPLEMENT_FUNCTION_I(26, Milos, function26, TimeValue) case 5: if (ENTITY_PARAM(0, 2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1461,7 +1465,7 @@ IMPLEMENT_FUNCTION_II(27, Milos, function27, CarIndex, EntityPosition) case kActionNone: if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } @@ -1472,14 +1476,14 @@ IMPLEMENT_FUNCTION_II(27, Milos, function27, CarIndex, EntityPosition) if (getData()->car == kCarRedSleeping || getData()->car == kCarGreenSleeping) { ENTITY_PARAM(0, 2) = 1; - CALLBACK_ACTION(); + callbackAction(); } } break; case kActionDefault: if (getEntities()->updateEntity(kEntityMilos, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -1536,7 +1540,7 @@ IMPLEMENT_FUNCTION(29, Milos, chapter4Handler) TIME_CHECK_PLAYSOUND_MILOS(kTime2370600, params->param5, "Mil4015"); - TIME_CHECK_SAVEPOINT(kTime2407500, params->param6, kEntityMilos, kEntityVesna, kAction55996766); + Entity::timeCheckSavepoint(kTime2407500, params->param6, kEntityMilos, kEntityVesna, kAction55996766); break; case kActionCallback: diff --git a/engines/lastexpress/entities/milos.h b/engines/lastexpress/entities/milos.h index d58d717f8a..e8f95dc5ff 100644 --- a/engines/lastexpress/entities/milos.h +++ b/engines/lastexpress/entities/milos.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_MILOS_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/mmeboutarel.cpp b/engines/lastexpress/entities/mmeboutarel.cpp index 9ca10ca374..950644cb8f 100644 --- a/engines/lastexpress/entities/mmeboutarel.cpp +++ b/engines/lastexpress/entities/mmeboutarel.cpp @@ -31,10 +31,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -124,7 +122,7 @@ IMPLEMENT_FUNCTION_S(8, MmeBoutarel, function8) if (!getEntities()->isPlayerPosition(kCarRedSleeping, 2)) getData()->entityPosition = kPosition_2088; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -211,7 +209,7 @@ IMPLEMENT_FUNCTION(9, MmeBoutarel, function9) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityMmeBoutarel); - CALLBACK_ACTION(); + callbackAction(); break; case 5: @@ -220,7 +218,7 @@ IMPLEMENT_FUNCTION(9, MmeBoutarel, function9) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityMmeBoutarel); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -246,7 +244,7 @@ IMPLEMENT_FUNCTION(10, MmeBoutarel, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_chapter1Handler)); break; case kActionDefault: @@ -312,7 +310,7 @@ IMPLEMENT_FUNCTION(11, MmeBoutarel, function11) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -402,7 +400,7 @@ IMPLEMENT_FUNCTION(13, MmeBoutarel, function13) case kActionNone: if (!getSoundQueue()->isBuffered(kEntityMmeBoutarel) && params->param6 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(params->param1, !getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000), params->param6, 0) + if (Entity::updateParameterTime((TimeValue)params->param1, !getEntities()->isDistanceBetweenEntities(kEntityMmeBoutarel, kEntityPlayer, 2000), params->param6, 0)) { getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal); getObjects()->update(kObject51, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorNormal); @@ -414,22 +412,24 @@ IMPLEMENT_FUNCTION(13, MmeBoutarel, function13) setCallback(1); setup_playSound("MME1037"); break; - UPDATE_PARAM_PROC_END + } } label_callback_1: if (getProgress().field_24 && params->param7 != kTimeInvalid) { - UPDATE_PARAM_PROC_TIME(kTime1093500, (!params->param5 || !getEntities()->isPlayerInCar(kCarRedSleeping)), params->param7, 0) + if (Entity::updateParameterTime(kTime1093500, (!params->param5 || !getEntities()->isPlayerInCar(kCarRedSleeping)), params->param7, 0)) { setCallback(2); setup_function11(); break; - UPDATE_PARAM_PROC_END + } } - TIME_CHECK(kTime1094400, params->param8, setup_function14); + if (Entity::timeCheck(kTime1094400, params->param8, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_function14))) + break; if (params->param4) { - UPDATE_PARAM(CURRENT_PARAM(1, 1), getState()->timeTicks, 75); + if (!Entity::updateParameter(CURRENT_PARAM(1, 1), getState()->timeTicks, 75)) + break; params->param3 = 1; params->param4 = 0; @@ -589,7 +589,8 @@ IMPLEMENT_FUNCTION(15, MmeBoutarel, function15) label_callback_5: if (params->param2) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param1 = 1; params->param2 = 0; @@ -1018,7 +1019,8 @@ IMPLEMENT_FUNCTION(23, MmeBoutarel, chapter4Handler) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param2, getState()->time, 900); + if (!Entity::updateParameter(params->param2, getState()->time, 900)) + break; getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue); @@ -1064,10 +1066,12 @@ IMPLEMENT_FUNCTION(24, MmeBoutarel, function24) break; case kActionNone: - TIME_CHECK(kTime2470500, params->param4, setup_function25); + if (Entity::timeCheck(kTime2470500, params->param4, WRAP_SETUP_FUNCTION(MmeBoutarel, setup_function25))) + break; if (params->param2) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param1 = 1; params->param2 = 0; @@ -1210,7 +1214,8 @@ IMPLEMENT_FUNCTION(28, MmeBoutarel, function28) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param3, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; diff --git a/engines/lastexpress/entities/mmeboutarel.h b/engines/lastexpress/entities/mmeboutarel.h index 772451ba15..0f6e6349fe 100644 --- a/engines/lastexpress/entities/mmeboutarel.h +++ b/engines/lastexpress/entities/mmeboutarel.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_MMEBOUTAREL_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/pascale.cpp b/engines/lastexpress/entities/pascale.cpp index a191273702..6e9f992390 100644 --- a/engines/lastexpress/entities/pascale.cpp +++ b/engines/lastexpress/entities/pascale.cpp @@ -30,10 +30,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -171,7 +169,7 @@ IMPLEMENT_FUNCTION(8, Pascale, welcomeSophieAndRebecca) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 4) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -185,8 +183,8 @@ IMPLEMENT_FUNCTION(9, Pascale, sitSophieAndRebecca) break; case kActionExitCompartment: - CALLBACK_ACTION(); - break; + callbackAction(); + break; case kActionDefault: getEntities()->drawSequenceLeft(kEntityPascale, "012C1"); @@ -217,7 +215,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath) getScenes()->loadSceneFromPosition(kCarRestaurant, 69); } - CALLBACK_ACTION(); + callbackAction(); break; case kAction4: @@ -239,7 +237,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath) getScenes()->loadSceneFromPosition(kCarRestaurant, 69); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -283,7 +281,7 @@ IMPLEMENT_FUNCTION(11, Pascale, function11) getEntities()->clearSequences(kEntityPascale); getData()->entityPosition = kPosition_5900; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -298,7 +296,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1) case kActionNone: setup_chapter1Handler(); - break; + break; case kActionDefault: getSavePoints()->addData(kEntityPascale, kAction239072064, 0); @@ -366,7 +364,7 @@ IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler) getSavePoints()->push(kEntityPascale, kEntityVerges, kActionDeliverMessageToTyler); ENTITY_PARAM(0, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -382,7 +380,7 @@ IMPLEMENT_FUNCTION(14, Pascale, sitAnna) case kActionExitCompartment: getEntities()->updatePositionExit(kEntityPascale, kCarRestaurant, 62); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -433,7 +431,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -486,7 +484,7 @@ IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 3) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -648,7 +646,7 @@ IMPLEMENT_FUNCTION(21, Pascale, chapter3) case kActionNone: setup_chapter3Handler(); - break; + break; case kActionDefault: getEntities()->clearSequences(kEntityPascale); @@ -685,7 +683,7 @@ label_callback: setCallback(2); setup_welcomeSophieAndRebecca(); } - break; + break; case kActionCallback: if (getCallback() == 1) @@ -727,7 +725,7 @@ IMPLEMENT_FUNCTION(23, Pascale, function23) ENTITY_PARAM(0, 7) = 0; getEntities()->clearSequences(kEntityPascale); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -748,7 +746,7 @@ IMPLEMENT_FUNCTION(24, Pascale, welcomeAbbot) break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kAction10: @@ -771,7 +769,7 @@ IMPLEMENT_FUNCTION(25, Pascale, chapter4) case kActionNone: setup_chapter4Handler(); - break; + break; case kActionDefault: getEntities()->clearSequences(kEntityPascale); @@ -953,7 +951,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27) ENTITY_PARAM(1, 1) = 0; ENTITY_PARAM(1, 2) = 1; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -999,7 +997,7 @@ IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(1, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1037,7 +1035,7 @@ IMPLEMENT_FUNCTION(29, Pascale, function29) case 2: getData()->entityPosition = kPosition_850; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1075,7 +1073,7 @@ IMPLEMENT_FUNCTION(30, Pascale, function30) case 2: getData()->entityPosition = kPosition_5900; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1090,7 +1088,7 @@ IMPLEMENT_FUNCTION(31, Pascale, chapter5) case kActionNone: setup_chapter5Handler(); - break; + break; case kActionDefault: getEntities()->clearSequences(kEntityPascale); @@ -1117,18 +1115,19 @@ IMPLEMENT_FUNCTION(33, Pascale, function33) case kActionNone: if (params->param4) { - UPDATE_PARAM_PROC(params->param5, getState()->time, 4500) + if (Entity::updateParameter(params->param5, getState()->time, 4500)) { getObjects()->update(kObjectCompartmentG, kEntityPascale, kObjectLocation1, kCursorNormal, kCursorNormal); setCallback(1); setup_playSound("Wat5010"); break; - UPDATE_PARAM_PROC_END + } } label_callback1: if (params->param1) { - UPDATE_PARAM(params->param6, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param6, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 2; diff --git a/engines/lastexpress/entities/pascale.h b/engines/lastexpress/entities/pascale.h index 333ebcae3e..eaf0f3ba0c 100644 --- a/engines/lastexpress/entities/pascale.h +++ b/engines/lastexpress/entities/pascale.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_PASCALE_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/rebecca.cpp b/engines/lastexpress/entities/rebecca.cpp index b1a176b47e..5bcb6aef85 100644 --- a/engines/lastexpress/entities/rebecca.cpp +++ b/engines/lastexpress/entities/rebecca.cpp @@ -30,10 +30,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -179,7 +177,7 @@ IMPLEMENT_FUNCTION(15, Rebecca, function15) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityRebecca); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -261,7 +259,7 @@ IMPLEMENT_FUNCTION_I(16, Rebecca, function16, bool) getSavePoints()->push(kEntityRebecca, kEntityTables3, kAction136455232); getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -334,7 +332,7 @@ IMPLEMENT_FUNCTION_I(17, Rebecca, function17, bool) case 5: getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -343,7 +341,7 @@ IMPLEMENT_FUNCTION_I(17, Rebecca, function17, bool) getData()->location = kLocationInsideCompartment; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -397,7 +395,7 @@ IMPLEMENT_FUNCTION(18, Rebecca, function18) case 2: case 3: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -473,7 +471,7 @@ IMPLEMENT_FUNCTION(19, Rebecca, function19) case 5: case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -493,21 +491,21 @@ IMPLEMENT_FUNCTION_I(20, Rebecca, function20, TimeValue) getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (!params->param2) { params->param6 = 0; } else { - UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param6, getState()->timeTicks, 75)) { params->param2 = 0; params->param3 = 1; getObjects()->update(kObjectCompartmentE, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal); getObjects()->update(kObject52, kEntityRebecca, kObjectLocation1, kCursorNormal, kCursorNormal); params->param6 = 0; - UPDATE_PARAM_PROC_END + } } if (getProgress().chapter == kChapter1 && !ENTITY_PARAM(0, 3)) { @@ -657,7 +655,7 @@ IMPLEMENT_FUNCTION(21, Rebecca, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Rebecca, setup_chapter1Handler)); break; case kActionDefault: @@ -685,7 +683,8 @@ IMPLEMENT_FUNCTION(22, Rebecca, chapter1Handler) break; case kActionNone: - TIME_CHECK_CALLBACK_1(kTime1084500, params->param3, 1, setup_playSound, "REB1015"); + if (Entity::timeCheckCallback(kTime1084500, params->param3, 1, "REB1015", WRAP_SETUP_FUNCTION_S(Rebecca, setup_playSound))) + break; if (params->param4 == kTimeInvalid) goto label_callback_4; @@ -699,7 +698,7 @@ IMPLEMENT_FUNCTION(22, Rebecca, chapter1Handler) if (params->param4 >= getState()->time) { label_callback_4: if (params->param1) { - UPDATE_PARAM_CHECK(params->param5, getState()->time, 900) + if (Entity::updateParameterCheck(params->param5, getState()->time, 900)) { if (getEntities()->isInSalon(kEntityPlayer)) { setCallback(5); setup_playSound("REB1013"); @@ -710,7 +709,9 @@ label_callback_4: label_callback_5: if (params->param2) { - UPDATE_PARAM(params->param6, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param6, getState()->timeTicks, 90)) + break; + getScenes()->loadSceneFromPosition(kCarRestaurant, 55); } else { params->param6 = 0; @@ -774,7 +775,13 @@ IMPLEMENT_FUNCTION(23, Rebecca, function23) break; case kActionNone: - TIME_CHECK_CALLBACK_2(kTime1111500, params->param2, 3, setup_enterExitCompartment, "623De", kObjectCompartmentE); + if (getState()->time > kTime1111500 && !params->param2) { + params->param2 = 1; + setCallback(3); + setup_enterExitCompartment("623De", kObjectCompartmentE); + + break; + } break; case kActionDefault: @@ -843,12 +850,13 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24) break; case kActionNone: - TIME_CHECK_SAVEPOINT(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416); + Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416); if (!params->param1) break; - TIME_CHECK_CALLBACK(kTime1165500, params->param3, 6, setup_function19); + if (Entity::timeCheckCallback(kTime1165500, params->param3, 6, WRAP_SETUP_FUNCTION(Rebecca, setup_function19))) + break; if (params->param4 != kTimeInvalid) { if (getState()->time <= kTime1161000) { @@ -965,10 +973,16 @@ IMPLEMENT_FUNCTION(26, Rebecca, function26) break; case kActionNone: - TIME_CHECK_CALLBACK_3(kTime1224000, params->param2, 1, setup_updatePosition, "118H", kCarRestaurant, 52); + if (getState()->time > kTime1224000 && !params->param2) { + params->param2 = 1; + setCallback(1); + setup_updatePosition("118H", kCarRestaurant, 52); + break; + } if (params->param1) { - UPDATE_PARAM(params->param3, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 90)) + break; getScenes()->loadSceneFromPosition(kCarRestaurant, 51); } @@ -1223,7 +1237,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34) params->param2 = (uint)getState()->time; if (params->param2 >= getState()->time) { - TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19); + Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19)); break; } } @@ -1233,7 +1247,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34) getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416); } - TIME_CHECK_CALLBACK(kTime2052000, params->param3, 1, setup_function19); + Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19)); break; case kActionEndSound: @@ -1632,7 +1646,7 @@ label_next: label_callback_2: if (params->param2) - TIME_CHECK_CALLBACK(kTime2443500, params->param5, 3, setup_function19); + Entity::timeCheckCallback(kTime2443500, params->param5, 3, WRAP_SETUP_FUNCTION(Rebecca, setup_function19)); break; case kActionEndSound: @@ -1755,7 +1769,8 @@ IMPLEMENT_FUNCTION(48, Rebecca, function48) case kActionNone: if (params->param1) { - UPDATE_PARAM(params->param3, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 75)) + break; params->param1 = 0; params->param2 = 1; diff --git a/engines/lastexpress/entities/rebecca.h b/engines/lastexpress/entities/rebecca.h index e91ee30d4d..885632f884 100644 --- a/engines/lastexpress/entities/rebecca.h +++ b/engines/lastexpress/entities/rebecca.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_REBECCA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/salko.cpp b/engines/lastexpress/entities/salko.cpp index 63d995dc42..e8b4b4247b 100644 --- a/engines/lastexpress/entities/salko.cpp +++ b/engines/lastexpress/entities/salko.cpp @@ -33,10 +33,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -137,7 +135,7 @@ IMPLEMENT_FUNCTION_II(7, Salko, function7, CarIndex, EntityPosition) break; case kAction123668192: - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -158,7 +156,7 @@ IMPLEMENT_FUNCTION(9, Salko, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Salko, setup_chapter1Handler)); break; case kActionDefault: @@ -301,7 +299,8 @@ IMPLEMENT_FUNCTION(15, Salko, chapter3Handler) case kActionNone: if (getState()->time < kTime2200500) { - UPDATE_PARAM(params->param1, getState()->time, 81000); + if (!Entity::updateParameter(params->param1, getState()->time, 81000)) + break; setCallback(1); setup_function16(); @@ -331,7 +330,8 @@ IMPLEMENT_FUNCTION(16, Salko, function16) } label_callback3: - UPDATE_PARAM(params->param1, getState()->time, 4500); + if (!Entity::updateParameter(params->param1, getState()->time, 4500)) + break; getSavePoints()->push(kEntitySalko, kEntitySalko, kAction101169464); break; @@ -390,7 +390,7 @@ label_callback3: getData()->entityPosition = kPosition_2740; getEntities()->clearSequences(kEntitySalko); - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/salko.h b/engines/lastexpress/entities/salko.h index 6308211053..6ca73e39f6 100644 --- a/engines/lastexpress/entities/salko.h +++ b/engines/lastexpress/entities/salko.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_SALKO_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/servers0.cpp b/engines/lastexpress/entities/servers0.cpp index 989bddd662..73e0d34722 100644 --- a/engines/lastexpress/entities/servers0.cpp +++ b/engines/lastexpress/entities/servers0.cpp @@ -28,10 +28,7 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -113,11 +110,11 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection) case kActionNone: if (getData()->direction != kDirectionRight) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -163,7 +160,7 @@ IMPLEMENT_FUNCTION(7, Servers0, function7) case 2: getEntities()->clearSequences(kEntityServers0); getData()->entityPosition = kPosition_5900; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -220,7 +217,7 @@ IMPLEMENT_FUNCTION(9, Servers0, function9) ENTITY_PARAM(2, 2) = 0; ENTITY_PARAM(1, 6) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -315,17 +312,17 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) case kActionNone: if (params->param2) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 2700); + if (Entity::updateParameter(params->param3, getState()->time, 2700)) { ENTITY_PARAM(0, 4) = 1; params->param2 = 0; - UPDATE_PARAM_PROC_END + } } if (params->param1) { - UPDATE_PARAM_PROC(params->param4, getState()->time, 4500) + if (Entity::updateParameter(params->param4, getState()->time, 4500)) { ENTITY_PARAM(0, 5) = 1; params->param1 = 0; - UPDATE_PARAM_PROC_END + } } if (!getEntities()->isInKitchen(kEntityServers0) && !getEntities()->isSomebodyInsideRestaurantOrSalon()) @@ -486,7 +483,7 @@ IMPLEMENT_FUNCTION(25, Servers0, function25) getEntities()->clearSequences(kEntityServers0); ENTITY_PARAM(1, 3) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -647,7 +644,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder) getEntities()->clearSequences(kEntityServers0); ENTITY_PARAM(1, 5) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -693,7 +690,7 @@ IMPLEMENT_FUNCTION(30, Servers0, function30) getEntities()->clearSequences(kEntityServers0); ENTITY_PARAM(2, 4) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -736,10 +733,10 @@ IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler) break; case kActionNone: - UPDATE_PARAM_PROC(params->param2, getState()->time, 3600) + if (Entity::updateParameter(params->param2, getState()->time, 3600)) { ENTITY_PARAM(1, 8) = 1; params->param1 = 0; - UPDATE_PARAM_PROC_END + } if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; @@ -859,7 +856,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) getEntities()->clearSequences(kEntityServers0); ENTITY_PARAM(1, 7) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -902,7 +899,7 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck) getEntities()->clearSequences(kEntityServers0); ENTITY_PARAM(1, 8) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -972,7 +969,7 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity getSavePoints()->push(kEntityServers0, entity, action); *parameter = 0; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -1027,7 +1024,7 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn getEntities()->clearSequences(kEntityServers0); *parameter = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/servers0.h b/engines/lastexpress/entities/servers0.h index 2e9165a410..4c35637d65 100644 --- a/engines/lastexpress/entities/servers0.h +++ b/engines/lastexpress/entities/servers0.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_SERVERS0_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/servers1.cpp b/engines/lastexpress/entities/servers1.cpp index 995fbbc01b..a8f4c0233c 100644 --- a/engines/lastexpress/entities/servers1.cpp +++ b/engines/lastexpress/entities/servers1.cpp @@ -28,10 +28,7 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -143,7 +140,7 @@ IMPLEMENT_FUNCTION(7, Servers1, function7) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(1, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -219,7 +216,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 1) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -265,7 +262,7 @@ IMPLEMENT_FUNCTION(10, Servers1, function10) getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 2) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -469,7 +466,7 @@ IMPLEMENT_FUNCTION(20, Servers1, function20) getEntities()->drawSequenceLeft(kEntityServers1, "BLANK"); ENTITY_PARAM(0, 7) = 0; - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -566,10 +563,10 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler) case kActionNone: if (params->param2) { - UPDATE_PARAM_PROC(params->param2, getState()->time, 900) + if (Entity::updateParameter(params->param2, getState()->time, 900)) { ENTITY_PARAM(1, 5) = 1; params->param1 = 0; - UPDATE_PARAM_PROC_END + } } if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) @@ -705,7 +702,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn if (parameter2 != NULL) *parameter2 = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -775,7 +772,7 @@ void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const ch getData()->entityPosition = kPosition_5900; *parameter = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/servers1.h b/engines/lastexpress/entities/servers1.h index 13b30696f0..c8f667ec5c 100644 --- a/engines/lastexpress/entities/servers1.h +++ b/engines/lastexpress/entities/servers1.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_SERVERS1_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/sophie.cpp b/engines/lastexpress/entities/sophie.cpp index 57bd491949..170090005f 100644 --- a/engines/lastexpress/entities/sophie.cpp +++ b/engines/lastexpress/entities/sophie.cpp @@ -27,38 +27,10 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { -#define CHAPTER_IMPLEMENTATION() \ - switch (savepoint.action) { \ - default: \ - break; \ - case kActionNone: \ - setup_chaptersHandler(); \ - break; \ - case kActionDefault: \ - getEntities()->clearSequences(kEntitySophie); \ - getData()->entityPosition = kPosition_4840; \ - getData()->location = kLocationInsideCompartment; \ - getData()->car = kCarRedSleeping; \ - getData()->clothes = kClothesDefault; \ - getData()->inventoryItem = kItemNone; \ - break; \ - } - -#define DEFAULT_ACTION_IMPLEMENTATION() \ - if (savepoint.action == kActionDefault) { \ - getData()->entityPosition = kPosition_4840; \ - getData()->location = kLocationInsideCompartment; \ - getData()->car = kCarRedSleeping; \ - getEntities()->clearSequences(kEntitySophie); \ - } - Sophie::Sophie(LastExpressEngine *engine) : Entity(engine, kEntitySophie) { ADD_CALLBACK_FUNCTION(Sophie, reset); ADD_CALLBACK_FUNCTION(Sophie, updateEntity); @@ -123,7 +95,7 @@ IMPLEMENT_FUNCTION_II(2, Sophie, updateEntity, CarIndex, EntityPosition) break; case kAction123668192: - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -207,7 +179,7 @@ IMPLEMENT_FUNCTION(4, Sophie, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chaptersHandler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Sophie, setup_chaptersHandler)); break; case kActionDefault: @@ -220,27 +192,27 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(5, Sophie, function5) - DEFAULT_ACTION_IMPLEMENTATION() + handleAction(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(6, Sophie, chapter2) - CHAPTER_IMPLEMENTATION() + handleChapter(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(7, Sophie, chapter3) - CHAPTER_IMPLEMENTATION() + handleChapter(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(8, Sophie, chapter4) - CHAPTER_IMPLEMENTATION() + handleChapter(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(9, Sophie, function9) - DEFAULT_ACTION_IMPLEMENTATION() + handleAction(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -274,4 +246,37 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_NULL_FUNCTION(12, Sophie) +////////////////////////////////////////////////////////////////////////// +// Helpers functions +////////////////////////////////////////////////////////////////////////// + +void Sophie::handleAction(const SavePoint &savepoint) { + if (savepoint.action == kActionDefault) { + getData()->entityPosition = kPosition_4840; + getData()->location = kLocationInsideCompartment; + getData()->car = kCarRedSleeping; + getEntities()->clearSequences(kEntitySophie); + } +} + +void Sophie::handleChapter(const SavePoint &savepoint) { + switch (savepoint.action) { + default: + break; + + case kActionNone: + setup_chaptersHandler(); + break; + + case kActionDefault: + getEntities()->clearSequences(kEntitySophie); + getData()->entityPosition = kPosition_4840; + getData()->location = kLocationInsideCompartment; + getData()->car = kCarRedSleeping; + getData()->clothes = kClothesDefault; + getData()->inventoryItem = kItemNone; + break; + } +} + } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/sophie.h b/engines/lastexpress/entities/sophie.h index c2ca348027..188788bb9b 100644 --- a/engines/lastexpress/entities/sophie.h +++ b/engines/lastexpress/entities/sophie.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_SOPHIE_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -88,6 +87,10 @@ public: DECLARE_FUNCTION(chapter5Handler) DECLARE_NULL_FUNCTION() + +private: + void handleAction(const SavePoint &savepoint); + void handleChapter(const SavePoint &savepoint); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/tables.cpp b/engines/lastexpress/entities/tables.cpp index 06ea4c597c..4f8d2b954d 100644 --- a/engines/lastexpress/entities/tables.cpp +++ b/engines/lastexpress/entities/tables.cpp @@ -29,10 +29,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/tables.h b/engines/lastexpress/entities/tables.h index 7fcfc0499e..c213aac978 100644 --- a/engines/lastexpress/entities/tables.h +++ b/engines/lastexpress/entities/tables.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_TABLES_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/tatiana.cpp b/engines/lastexpress/entities/tatiana.cpp index c8901b3e30..432def6253 100644 --- a/engines/lastexpress/entities/tatiana.cpp +++ b/engines/lastexpress/entities/tatiana.cpp @@ -35,10 +35,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -192,7 +190,7 @@ IMPLEMENT_FUNCTION(14, Tatiana, function14) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityTatiana); - CALLBACK_ACTION(); + callbackAction(); } break; @@ -228,7 +226,7 @@ IMPLEMENT_FUNCTION(15, Tatiana, function15) getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentB, true); getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -246,12 +244,13 @@ IMPLEMENT_FUNCTION_I(16, Tatiana, function16, uint32) getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param2) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; params->param2 = 0; params->param3 = 1; @@ -342,7 +341,7 @@ IMPLEMENT_FUNCTION(17, Tatiana, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Tatiana, setup_chapter1Handler)); break; case kActionDefault: @@ -375,10 +374,10 @@ IMPLEMENT_FUNCTION(18, Tatiana, function18) } if (!params->param1) { - UPDATE_PARAM_PROC(params->param3, getState()->time, 4500) + if (Entity::updateParameter(params->param3, getState()->time, 4500)) { getEntities()->drawSequenceRight(kEntityTatiana, "806DS"); params->param1 = 1; - UPDATE_PARAM_PROC_END + } } } @@ -386,14 +385,14 @@ IMPLEMENT_FUNCTION(18, Tatiana, function18) getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction157159392); getEntities()->clearSequences(kEntityTatiana); - CALLBACK_ACTION(); + callbackAction(); } break; case kActionExitCompartment: getSavePoints()->push(kEntityTatiana, kEntityAlexei, kAction188784532); - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -425,27 +424,29 @@ IMPLEMENT_FUNCTION(19, Tatiana, chapter1Handler) if (getSoundQueue()->isBuffered(kEntityTatiana) || !params->param4 || params->param3 == 2 || getSoundQueue()->isBuffered("TAT1066")) goto label_tatiana_chapter1_2; - UPDATE_PARAM_PROC(params->param5, getState()->timeTicks, 450) + if (Entity::updateParameter(params->param5, getState()->timeTicks, 450)) { getSound()->playSound(kEntityTatiana, params->param3 ? "TAT1069B" : "TAT1069A"); getProgress().field_64 = 1; params->param3++; params->param5 = 0; - UPDATE_PARAM_PROC_END + } if (getEntities()->isPlayerPosition(kCarRestaurant, 71)) { - UPDATE_PARAM_PROC(params->param6, getState()->timeTicks, 75) + if (Entity::updateParameter(params->param6, getState()->timeTicks, 75)) { getSound()->playSound(kEntityTatiana, params->param3 ? "TAT1069B" : "TAT1069A"); getProgress().field_64 = 1; params->param3++; params->param6 = 0; - UPDATE_PARAM_PROC_END + } } label_tatiana_chapter1_2: - TIME_CHECK_SAVEPOINT(kTime1084500, params->param7, kEntityTatiana, kEntityPascale, kAction257489762); + Entity::timeCheckSavepoint(kTime1084500, params->param7, kEntityTatiana, kEntityPascale, kAction257489762); if (params->param1) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 90); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 90)) + break; + getScenes()->loadSceneFromPosition(kCarRestaurant, 65); } else { params->param8 = 0; @@ -614,7 +615,7 @@ IMPLEMENT_FUNCTION(22, Tatiana, function22) if (params->param1 == kTimeInvalid || getState()->time <= kTime1179000) goto label_update; - UPDATE_PARAM_PROC_TIME(kTime1233000, ((!getEvent(kEventTatianaAskMatchSpeakRussian) && !getEvent(kEventTatianaAskMatch)) || getEntities()->isInGreenCarEntrance(kEntityPlayer)), params->param1, 0) + if (Entity::updateParameterTime(kTime1233000, ((!getEvent(kEventTatianaAskMatchSpeakRussian) && !getEvent(kEventTatianaAskMatch)) || getEntities()->isInGreenCarEntrance(kEntityPlayer)), params->param1, 0)) { label_update: if (!getEvent(kEventTatianaAskMatchSpeakRussian) && !getEvent(kEventTatianaAskMatch) @@ -623,7 +624,7 @@ label_update: getObjects()->update(kObject25, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward); getObjects()->update(kObjectTrainTimeTable, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorForward); } - UPDATE_PARAM_PROC_END + } params->param1 = kTimeInvalid; @@ -1022,7 +1023,7 @@ IMPLEMENT_FUNCTION(32, Tatiana, chapter3Handler) } if (parameters->param4 && parameters->param5) { - UPDATE_PARAM_CHECK(parameters->param4, getState()->time, 6300) + if (Entity::updateParameterCheck(parameters->param4, getState()->time, 6300)) { if (getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->location = kLocationOutsideCompartment; @@ -1283,18 +1284,19 @@ IMPLEMENT_FUNCTION(37, Tatiana, function37) params->param3 = (uint)getState()->time + 900; if (params->param4 != kTimeInvalid && params->param3 < getState()->time) { - UPDATE_PARAM_PROC_TIME(kTime2227500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param4, 450) + if (Entity::updateParameterTime(kTime2227500, !getEntities()->isPlayerInCar(kCarRedSleeping), params->param4, 450)) { getProgress().field_5C = 1; if (getEntities()->isInsideCompartment(kEntityAnna, kCarRedSleeping, kPosition_4070)) { setup_function38(); break; } - UPDATE_PARAM_PROC_END + } } } if (params->param1) { - UPDATE_PARAM(params->param5, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param5, getState()->timeTicks, 75)) + break; getObjects()->update(kObjectCompartmentB, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal); getObjects()->update(kObject49, kEntityTatiana, kObjectLocation1, kCursorNormal, kCursorNormal); @@ -1403,7 +1405,8 @@ IMPLEMENT_FUNCTION(38, Tatiana, function38) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 450); + if (!Entity::updateParameter(params->param1, getState()->time, 450)) + break; getEntities()->exitCompartment(kEntityTatiana, kObjectCompartmentF, true); @@ -1535,7 +1538,7 @@ IMPLEMENT_FUNCTION(40, Tatiana, function40) if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos) || getData()->car != getEntityData(kEntityPlayer)->car || getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMe: @@ -1547,7 +1550,7 @@ IMPLEMENT_FUNCTION(40, Tatiana, function40) case kActionDefault: if (getEntities()->updateEntity(kEntityTatiana, kCarKronos, kPosition_9270)) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -1595,7 +1598,7 @@ IMPLEMENT_FUNCTION(41, Tatiana, function41) } getEntities()->clearSequences(kEntityTatiana); - CALLBACK_ACTION(); + callbackAction(); } break; @@ -1629,7 +1632,7 @@ IMPLEMENT_FUNCTION(41, Tatiana, function41) case 6: getEntities()->clearSequences(kEntityTatiana); - CALLBACK_ACTION(); + callbackAction(); break; case 4: @@ -1952,7 +1955,8 @@ IMPLEMENT_FUNCTION(48, Tatiana, function48) if (!params->param1 || getSoundQueue()->isBuffered(kEntityTatiana)) goto label_end; - UPDATE_PARAM_GOTO(params->param2, getState()->timeTicks, 5 * (3 * rnd(5) + 30), label_end); + if (!Entity::updateParameter(params->param2, getState()->timeTicks, 5 * (3 * rnd(5) + 30))) + goto label_end; getSound()->playSound(kEntityTatiana, "LIB012", kFlagDefault); params->param2 = 0; @@ -2199,7 +2203,8 @@ IMPLEMENT_FUNCTION(54, Tatiana, function54) } if (params->param1 > 3) { - UPDATE_PARAM(params->param3, getState()->timeTicks, 225); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, 225)) + break; params->param1 = 0; params->param3 = 0; diff --git a/engines/lastexpress/entities/tatiana.h b/engines/lastexpress/entities/tatiana.h index c457d49b1e..8ec69db5e9 100644 --- a/engines/lastexpress/entities/tatiana.h +++ b/engines/lastexpress/entities/tatiana.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_TATIANA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/train.cpp b/engines/lastexpress/entities/train.cpp index bced1da62b..e3f530ef25 100644 --- a/engines/lastexpress/entities/train.cpp +++ b/engines/lastexpress/entities/train.cpp @@ -32,10 +32,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -269,18 +267,20 @@ IMPLEMENT_FUNCTION(8, Train, process) if ((getEntities()->isPlayerInCar(kCarGreenSleeping) || getEntities()->isPlayerInCar(kCarRedSleeping)) && params->param4 && !params->param5) { - params->param4 -= 1; + params->param4 -= 1; - if (!params->param4 && getProgress().jacket == kJacketGreen) { + if (!params->param4 && getProgress().jacket == kJacketGreen) { - getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay); - params->param5 = 1; - getScenes()->processScene(); - } + getAction()->playAnimation(isNight() ? kEventCathSmokeNight : kEventCathSmokeDay); + params->param5 = 1; + getScenes()->processScene(); + } } if (params->param6) { - UPDATE_PARAM_GOTO(params1->param7, getState()->time, 900, label_process); + if (!Entity::updateParameter(params1->param7, getState()->time, 900)) + goto label_process; + getScenes()->loadSceneFromPosition(kCarRestaurant, 58); } @@ -552,7 +552,7 @@ void Train::handleCompartmentAction() { ENTITY_PARAM(0, 8) = params->param1; - CALLBACK_ACTION(); + callbackAction(); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/entities/train.h b/engines/lastexpress/entities/train.h index ea9e1d7a07..4b8bc10c1a 100644 --- a/engines/lastexpress/entities/train.h +++ b/engines/lastexpress/entities/train.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_TRAIN_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/vassili.cpp b/engines/lastexpress/entities/vassili.cpp index 22f41afa92..4695f8831f 100644 --- a/engines/lastexpress/entities/vassili.cpp +++ b/engines/lastexpress/entities/vassili.cpp @@ -35,10 +35,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -85,7 +83,7 @@ IMPLEMENT_FUNCTION(4, Vassili, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Vassili, setup_chapter1Handler)); break; case kActionDefault: @@ -146,7 +144,8 @@ IMPLEMENT_FUNCTION(6, Vassili, function6) case kActionNone: if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) { - UPDATE_PARAM_GOTO(params->param3, getState()->timeTicks, params->param1, label_function7); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1)) + goto label_function7; setCallback(1); setup_draw("303B"); @@ -402,7 +401,8 @@ IMPLEMENT_FUNCTION(13, Vassili, sleeping) case kActionNone: if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) { - UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1)) + break; setCallback(1); setup_draw("303B"); @@ -461,7 +461,8 @@ IMPLEMENT_FUNCTION(15, Vassili, stealEgg) case kActionNone: if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) { - UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1)) + break; setCallback(1); setup_draw("303B"); @@ -545,7 +546,8 @@ IMPLEMENT_FUNCTION(17, Vassili, chapter4Handler) case kActionNone: if (getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_8200)) { - UPDATE_PARAM(params->param3, getState()->timeTicks, params->param1); + if (!Entity::updateParameter(params->param3, getState()->timeTicks, params->param1)) + break; setCallback(1); setup_draw("303B"); diff --git a/engines/lastexpress/entities/vassili.h b/engines/lastexpress/entities/vassili.h index 843a065174..d006770f7b 100644 --- a/engines/lastexpress/entities/vassili.h +++ b/engines/lastexpress/entities/vassili.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_VASSILI_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp index 8246f85145..d9ddb0a4d1 100644 --- a/engines/lastexpress/entities/verges.cpp +++ b/engines/lastexpress/entities/verges.cpp @@ -32,10 +32,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -48,40 +46,40 @@ Verges::Verges(LastExpressEngine *engine) : Entity(engine, kEntityVerges) { ADD_CALLBACK_FUNCTION(Verges, callbackActionRestaurantOrSalon); ADD_CALLBACK_FUNCTION(Verges, savegame); ADD_CALLBACK_FUNCTION(Verges, updateEntity); - ADD_CALLBACK_FUNCTION(Verges, function9); - ADD_CALLBACK_FUNCTION(Verges, function10); + ADD_CALLBACK_FUNCTION(Verges, walkBetweenCars); + ADD_CALLBACK_FUNCTION(Verges, makeAnnouncement); ADD_CALLBACK_FUNCTION(Verges, function11); ADD_CALLBACK_FUNCTION(Verges, function12); - ADD_CALLBACK_FUNCTION(Verges, function13); + ADD_CALLBACK_FUNCTION(Verges, baggageCar); ADD_CALLBACK_FUNCTION(Verges, updateFromTime); - ADD_CALLBACK_FUNCTION(Verges, function15); - ADD_CALLBACK_FUNCTION(Verges, function16); - ADD_CALLBACK_FUNCTION(Verges, function17); + ADD_CALLBACK_FUNCTION(Verges, dialog); + ADD_CALLBACK_FUNCTION(Verges, dialog2); + ADD_CALLBACK_FUNCTION(Verges, talkAboutPassengerList); ADD_CALLBACK_FUNCTION(Verges, chapter1); ADD_CALLBACK_FUNCTION(Verges, talkHarem); ADD_CALLBACK_FUNCTION(Verges, talkPassengerList); ADD_CALLBACK_FUNCTION(Verges, talkGendarmes); - ADD_CALLBACK_FUNCTION(Verges, function22); + ADD_CALLBACK_FUNCTION(Verges, askMertensToRelayAugustInvitation); ADD_CALLBACK_FUNCTION(Verges, function23); ADD_CALLBACK_FUNCTION(Verges, policeGettingOffTrain); - ADD_CALLBACK_FUNCTION(Verges, function25); + ADD_CALLBACK_FUNCTION(Verges, policeSearch); ADD_CALLBACK_FUNCTION(Verges, chapter1Handler); ADD_CALLBACK_FUNCTION(Verges, chapter2); ADD_CALLBACK_FUNCTION(Verges, chapter2Handler); ADD_CALLBACK_FUNCTION(Verges, chapter3); ADD_CALLBACK_FUNCTION(Verges, function30); - ADD_CALLBACK_FUNCTION(Verges, function31); + ADD_CALLBACK_FUNCTION(Verges, talkAboutMax); ADD_CALLBACK_FUNCTION(Verges, function32); ADD_CALLBACK_FUNCTION(Verges, function33); ADD_CALLBACK_FUNCTION(Verges, function34); - ADD_CALLBACK_FUNCTION(Verges, function35); + ADD_CALLBACK_FUNCTION(Verges, organizeConcertInvitations); ADD_CALLBACK_FUNCTION(Verges, chapter4); ADD_CALLBACK_FUNCTION(Verges, chapter4Handler); - ADD_CALLBACK_FUNCTION(Verges, function38); + ADD_CALLBACK_FUNCTION(Verges, resetState); ADD_CALLBACK_FUNCTION(Verges, chapter5); ADD_CALLBACK_FUNCTION(Verges, chapter5Handler); - ADD_CALLBACK_FUNCTION(Verges, function41); - ADD_CALLBACK_FUNCTION(Verges, function42); + ADD_CALLBACK_FUNCTION(Verges, askPassengersToStayInCompartments); + ADD_CALLBACK_FUNCTION(Verges, end); } ////////////////////////////////////////////////////////////////////////// @@ -102,11 +100,11 @@ IMPLEMENT_FUNCTION(3, Verges, callbackActionOnDirection) case kActionNone: if (getData()->direction != kDirectionRight) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExitCompartment: - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: @@ -151,7 +149,7 @@ IMPLEMENT_FUNCTION_II(8, Verges, updateEntity, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(9, Verges, function9) +IMPLEMENT_FUNCTION_S(9, Verges, walkBetweenCars) switch (savepoint.action) { default: break; @@ -203,7 +201,7 @@ switch (savepoint.action) { case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); break; case 4: @@ -219,7 +217,7 @@ switch (savepoint.action) { break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -227,7 +225,7 @@ switch (savepoint.action) { IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition) +IMPLEMENT_FUNCTION_IIS(10, Verges, makeAnnouncement, CarIndex, EntityPosition) switch (savepoint.action) { default: break; @@ -241,12 +239,13 @@ IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition) } if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2)) { - CALLBACK_ACTION(); + callbackAction(); break; } if (params->param6) { - UPDATE_PARAM(params->param8, getState()->timeTicks, 75); + if (!Entity::updateParameter(params->param8, getState()->timeTicks, 75)) + break; getSound()->playSound(kEntityVerges, (char *)¶ms->seq); @@ -266,7 +265,7 @@ IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition) } if (getEntities()->updateEntity(kEntityVerges, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -337,7 +336,7 @@ IMPLEMENT_FUNCTION(11, Verges, function11) getObjects()->update(kObject104, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand); getObjects()->update(kObject105, kEntityVerges, kObjectLocationNone, kCursorNormal, kCursorHand); - CALLBACK_ACTION(); + callbackAction(); break; } } @@ -397,7 +396,7 @@ IMPLEMENT_FUNCTION(12, Verges, function12) getData()->entityPosition = kPosition_850; getEntities()->clearSequences(kEntityVerges); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -405,7 +404,7 @@ IMPLEMENT_FUNCTION(12, Verges, function12) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_I(13, Verges, function13, bool) +IMPLEMENT_FUNCTION_I(13, Verges, baggageCar, bool) switch (savepoint.action) { default: break; @@ -438,7 +437,7 @@ IMPLEMENT_FUNCTION_I(13, Verges, function13, bool) getEntities()->clearSequences(kEntityVerges); getScenes()->loadSceneFromPosition(kCarBaggage, 91); - CALLBACK_ACTION(); + callbackAction(); } break; } @@ -450,7 +449,7 @@ IMPLEMENT_FUNCTION_I(14, Verges, updateFromTime, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) +IMPLEMENT_FUNCTION_IS(15, Verges, dialog, EntityIndex) switch (savepoint.action) { default: break; @@ -462,7 +461,7 @@ IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2)) getData()->entityPosition = kPosition_2088; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -487,7 +486,7 @@ IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) +IMPLEMENT_FUNCTION_ISS(16, Verges, dialog2, EntityIndex) switch (savepoint.action) { default: break; @@ -499,7 +498,7 @@ IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) if (!getEntities()->isPlayerPosition(kCarGreenSleeping, 2) && !getEntities()->isPlayerPosition(kCarRedSleeping, 2)) getData()->entityPosition = kPosition_2088; - CALLBACK_ACTION(); + callbackAction(); } break; @@ -527,7 +526,7 @@ IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Verges, function17) +IMPLEMENT_FUNCTION(17, Verges, talkAboutPassengerList) switch (savepoint.action) { default: break; @@ -549,7 +548,7 @@ IMPLEMENT_FUNCTION(17, Verges, function17) case 2: setCallback(3); - setup_function15(kEntityMertens, "TRA1291"); + setup_dialog(kEntityMertens, "TRA1291"); break; case 3: @@ -559,7 +558,7 @@ IMPLEMENT_FUNCTION(17, Verges, function17) case 4: ENTITY_PARAM(0, 3) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -573,7 +572,7 @@ IMPLEMENT_FUNCTION(18, Verges, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Verges, setup_chapter1Handler)); break; case kActionDefault: @@ -612,7 +611,7 @@ IMPLEMENT_FUNCTION(21, Verges, talkGendarmes) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Verges, function22) +IMPLEMENT_FUNCTION(22, Verges, askMertensToRelayAugustInvitation) switch (savepoint.action) { default: break; @@ -635,10 +634,10 @@ IMPLEMENT_FUNCTION(22, Verges, function22) case 2: if (getEvent(kEventMertensAskTylerCompartment) || getEvent(kEventMertensAskTylerCompartmentD) || getEvent(kEventMertensAugustWaiting)) { setCallback(3); - setup_function16(kEntityMertens, "TRA1200", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200", "TRA1201"); } else { setCallback(4); - setup_function16(kEntityMertens, "TRA1200A", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200A", "TRA1201"); } break; @@ -651,7 +650,7 @@ IMPLEMENT_FUNCTION(22, Verges, function22) break; case 5: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -697,7 +696,7 @@ IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain) break; case kActionEndSound: - CALLBACK_ACTION(); + callbackAction(); break; case kActionDefault: @@ -715,7 +714,7 @@ IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Verges, function25) +IMPLEMENT_FUNCTION(25, Verges, policeSearch) switch (savepoint.action) { default: break; @@ -775,10 +774,10 @@ IMPLEMENT_FUNCTION(25, Verges, function25) if (getData()->car == kCarRedSleeping) { setCallback(6); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1005"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1005"); } else { setCallback(7); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); } break; } @@ -806,7 +805,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(4); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); break; case 4: @@ -818,7 +817,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) case 11: ENTITY_PARAM(0, 7) = 0; - CALLBACK_ACTION(); + callbackAction(); break; case 6: @@ -839,7 +838,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(10); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1006"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1006"); break; case 10: @@ -893,14 +892,14 @@ IMPLEMENT_FUNCTION(26, Verges, chapter1Handler) label_callback1: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(2); - setup_function13(false); + setup_baggageCar(false); break; } label_callback2: if (ENTITY_PARAM(0, 7)) { setCallback(3); - setup_function25(); + setup_policeSearch(); break; } @@ -908,10 +907,12 @@ label_callback3: if (params->param6) goto label_callback12; - TIME_CHECK_CALLBACK_1(kTimeChapter1, params->param7, 4, setup_function9, "TRA1001"); + if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback4: - TIME_CHECK_CALLBACK(kTime1089000, params->param8, 5, setup_function12); + if (Entity::timeCheckCallback(kTime1089000, params->param8, 5, WRAP_SETUP_FUNCTION(Verges, setup_function12))) + break; params->param8 = 1; @@ -922,16 +923,20 @@ label_callback4: } label_callback8: - TIME_CHECK_CALLBACK_1(kTime1107000, CURRENT_PARAM(1, 1), 9, setup_function9, "TRA1001A"); + if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback9: - TIME_CHECK_CALLBACK_1(kTime1134000, CURRENT_PARAM(1, 2), 10, setup_function9, "TRA1002"); + if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback10: - TIME_CHECK_CALLBACK_1(kTime1165500, CURRENT_PARAM(1, 3), 11, setup_function9, "TRA1003"); + if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback11: - TIME_CHECK_CALLBACK_1(kTime1225800, CURRENT_PARAM(1, 4), 12, setup_function9, "TRA1004"); + if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback12: if (ENTITY_PARAM(0, 5) && !params->param2) { @@ -950,7 +955,7 @@ label_callback13: label_callback14: if (ENTITY_PARAM(0, 3) && !params->param4 && (getState()->time < kTime1134000 || getState()->time > kTime1156500)) { setCallback(15); - setup_function17(); + setup_talkAboutPassengerList(); break; } @@ -958,14 +963,14 @@ label_callback15: if (ENTITY_PARAM(0, 1) && !params->param5) { if (getState()->time < kTime1134000 || getState()->time > kTime1156500) { setCallback(16); - setup_function22(); + setup_askMertensToRelayAugustInvitation(); } } break; case kActionOpenDoor: setCallback(17); - setup_function13(savepoint.param.intValue < 106 ? true : false); + setup_baggageCar(savepoint.param.intValue < 106 ? true : false); break; case kActionDefault: @@ -1001,7 +1006,7 @@ label_callback15: case 6: setCallback(7); - setup_function15(kEntityMertens, "TRA1202"); + setup_dialog(kEntityMertens, "TRA1202"); break; case 7: @@ -1079,11 +1084,12 @@ IMPLEMENT_FUNCTION(28, Verges, chapter2Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); } label_callback_1: - TIME_CHECK_CALLBACK_1(kTime1818900, params->param1, 2, setup_function9, "Tra2177"); + if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_2: if (params->param2 == kTimeInvalid || !getState()->time) @@ -1111,7 +1117,7 @@ label_callback_6: if (ENTITY_PARAM(0, 3)) { setCallback(7); - setup_function17(); + setup_talkAboutPassengerList(); } break; @@ -1124,7 +1130,7 @@ label_callback_6: case kActionOpenDoor: setCallback(8); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1149,7 +1155,7 @@ label_callback_6: case 4: setCallback(5); - setup_function15(kEntityCoudert, "TRA2100"); + setup_dialog(kEntityCoudert, "TRA2100"); break; case 5: @@ -1171,7 +1177,7 @@ IMPLEMENT_FUNCTION(29, Verges, chapter3) break; case kActionNone: - setup_function23(); + setup_function33(); break; case kActionDefault: @@ -1215,7 +1221,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) case 2: setCallback(3); - setup_function15(kEntityCoudert, (char *)¶ms->seq1); + setup_dialog(kEntityCoudert, (char *)¶ms->seq1); break; case 3: @@ -1224,7 +1230,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) break; case 4: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1232,7 +1238,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(31, Verges, function31) +IMPLEMENT_FUNCTION(31, Verges, talkAboutMax) switch (savepoint.action) { default: break; @@ -1254,7 +1260,7 @@ IMPLEMENT_FUNCTION(31, Verges, function31) case 2: setCallback(3); - setup_function15(kEntityCoudert, "TRA3015"); + setup_dialog(kEntityCoudert, "TRA3015"); break; case 3: @@ -1266,7 +1272,7 @@ IMPLEMENT_FUNCTION(31, Verges, function31) getProgress().field_48 = 1; ENTITY_PARAM(0, 4) = 0; - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1280,7 +1286,12 @@ IMPLEMENT_FUNCTION(32, Verges, function32) break; case kActionNone: - TIME_CHECK_CALLBACK_3(kTime2263500, params->param1, 5, setup_function10, kCarRedSleeping, kPosition_9460, "TRA3006"); + if (getState()->time > kTime2263500 && !params->param1) { + params->param1 = 1; + setCallback(5); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA3006"); + break; + } break; case kActionDefault: @@ -1330,7 +1341,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA3004"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA3004"); break; case 4: @@ -1343,7 +1354,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1401,7 +1412,7 @@ IMPLEMENT_FUNCTION(33, Verges, function33) getSavePoints()->push(kEntityVerges, kEntityAbbot, kAction192054567); setCallback(6); - setup_function9("Tra3010"); + setup_walkBetweenCars("Tra3010"); break; case 6: @@ -1421,49 +1432,55 @@ IMPLEMENT_FUNCTION(34, Verges, function34) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } label_callback_1: if (ENTITY_PARAM(0, 4)) { setCallback(2); - setup_function31(); + setup_talkAboutMax(); break; } label_callback_2: if (ENTITY_PARAM(0, 3)) { setCallback(3); - setup_function17(); + setup_talkAboutPassengerList(); break; } label_callback_3: - TIME_CHECK_CALLBACK_1(kTime1971000, params->param1, 4, setup_function9, "Tra3001"); + if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_4: - TIME_CHECK_CALLBACK_1(kTime1998000, params->param2, 5, setup_function9, "Tra3010a"); + if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_5: - TIME_CHECK_CALLBACK(kTime2016000, params->param3, 6, setup_function35); + if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_organizeConcertInvitations))) + break; label_callback_6: - TIME_CHECK_CALLBACK_1(kTime2070000, params->param4, 7, setup_function9, "Tra3002"); + if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_7: - TIME_CHECK_CALLBACK_1(kTime2142000, params->param5, 8, setup_function9, "Tra3003"); + if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_8: - TIME_CHECK_CALLBACK_1(kTime2173500, params->param6, 9, setup_function30, "Tra3012"); + if (Entity::timeCheckCallback(kTime2173500, params->param6, 9, "Tra3012", WRAP_SETUP_FUNCTION_S(Verges, setup_function30))) + break; label_callback_9: - TIME_CHECK_CALLBACK(kTime2218500, params->param7, 10, setup_function32); + Entity::timeCheckCallback(kTime2218500, params->param7, 10, WRAP_SETUP_FUNCTION(Verges, setup_function32)); break; case kActionOpenDoor: setCallback(11); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionCallback: @@ -1503,7 +1520,7 @@ label_callback_9: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(35, Verges, function35) +IMPLEMENT_FUNCTION(35, Verges, organizeConcertInvitations) switch (savepoint.action) { default: break; @@ -1525,7 +1542,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 2: setCallback(3); - setup_function15(kEntityMertens, "Tra3011A"); + setup_dialog(kEntityMertens, "Tra3011A"); break; case 3: @@ -1537,7 +1554,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 4: setCallback(5); - setup_function15(kEntityMertens, "Tra3011"); + setup_dialog(kEntityMertens, "Tra3011"); break; case 5: @@ -1548,7 +1565,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1592,7 +1609,7 @@ IMPLEMENT_FUNCTION(37, Verges, chapter4Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } @@ -1600,37 +1617,42 @@ label_callback_1: if (ENTITY_PARAM(0, 6)) { if (ENTITY_PARAM(0, 3)) { setCallback(2); - setup_function17(); + setup_talkAboutPassengerList(); break; } label_callback_2: - TIME_CHECK_CALLBACK_1(kTime2349000, params->param1, 3, setup_function9, "Tra1001"); + if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_3: - TIME_CHECK_CALLBACK_1(kTime2378700, params->param2, 4, setup_function9, "Tra4001"); + if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_4: - TIME_CHECK_CALLBACK_1(kTime2403000, params->param3, 5, setup_function9, "Tra1001A"); + if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_5: - TIME_CHECK_CALLBACK_1(kTime2414700, params->param4, 6, setup_function9, "Tra4002"); + if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_6: - TIME_CHECK_CALLBACK_1(kTime2484000, params->param5, 7, setup_function9, "Tra4003"); + if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; label_callback_7: - TIME_CHECK_CALLBACK_1(kTime2511000, params->param6, 8, setup_function9, "Tra4004"); + if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) + break; } label_callback_8: - TIME_CHECK_CALLBACK_1(kTime2538000, params->param7, 9, setup_function9, "Tra4005"); - + Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars)); break; case kActionOpenDoor: setCallback(10); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1675,7 +1697,7 @@ label_callback_8: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(38, Verges, function38) +IMPLEMENT_FUNCTION(38, Verges, resetState) switch (savepoint.action) { default: break; @@ -1781,14 +1803,14 @@ IMPLEMENT_FUNCTION(40, Verges, chapter5Handler) getAction()->playAnimation(kEventCathFreePassengers); getSavePoints()->pushAll(kEntityVerges, kActionProceedChapter5); getScenes()->loadSceneFromPosition(kCarRedSleeping, 40); - setup_function41(); + setup_askPassengersToStayInCompartments(); } break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(41, Verges, function41) +IMPLEMENT_FUNCTION(41, Verges, askPassengersToStayInCompartments) switch (savepoint.action) { default: break; @@ -1800,7 +1822,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) getData()->location = kLocationInsideCompartment; setCallback(1); - setup_function10(kCarRedSleeping, kPosition_2000, "Tra5001"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_2000, "Tra5001"); break; case kActionCallback: @@ -1830,7 +1852,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) break; case 4: - setup_function42(); + setup_end(); break; } break; @@ -1838,7 +1860,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(42, Verges, function42) +IMPLEMENT_FUNCTION(42, Verges, end) if (savepoint.action == kActionDefault) getEntities()->clearSequences(kEntityVerges); IMPLEMENT_FUNCTION_END @@ -1869,7 +1891,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 2: setCallback(3); - setup_function15(kEntityCoudert, sound1); + setup_dialog(kEntityCoudert, sound1); break; case 3: @@ -1879,7 +1901,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 4: setCallback(5); - setup_function15(kEntityMertens, sound2); + setup_dialog(kEntityMertens, sound2); break; case 5: @@ -1887,7 +1909,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so break; case 6: - CALLBACK_ACTION(); + callbackAction(); break; } break; diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h index 17a3c8ac40..93cc190d1e 100644 --- a/engines/lastexpress/entities/verges.h +++ b/engines/lastexpress/entities/verges.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_VERGES_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { @@ -88,11 +87,11 @@ public: */ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition) - DECLARE_FUNCTION_1(function9, const char *soundName) - DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, const char *soundName) + DECLARE_FUNCTION_1(walkBetweenCars, const char *soundName) + DECLARE_FUNCTION_3(makeAnnouncement, CarIndex car, EntityPosition entityPosition, const char *soundName) DECLARE_FUNCTION(function11) DECLARE_FUNCTION(function12) - DECLARE_FUNCTION_1(function13, bool) + DECLARE_FUNCTION_1(baggageCar, bool) /** * Updates parameter 2 using time value @@ -101,9 +100,9 @@ public: */ DECLARE_FUNCTION_1(updateFromTime, uint32 time) - DECLARE_FUNCTION_2(function15, EntityIndex entity, const char *soundName) - DECLARE_FUNCTION_3(function16, EntityIndex entityIndex, const char *soundName1, const char *soundName2) - DECLARE_FUNCTION(function17) + DECLARE_FUNCTION_2(dialog, EntityIndex entity, const char *soundName) + DECLARE_FUNCTION_3(dialog2, EntityIndex entityIndex, const char *soundName1, const char *soundName2) + DECLARE_FUNCTION(talkAboutPassengerList) /** * Setup Chapter 1 @@ -113,10 +112,10 @@ public: DECLARE_FUNCTION_NOSETUP(talkHarem) DECLARE_FUNCTION(talkPassengerList) DECLARE_FUNCTION(talkGendarmes) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(askMertensToRelayAugustInvitation) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(policeGettingOffTrain) - DECLARE_FUNCTION(function25) + DECLARE_FUNCTION(policeSearch) /** * Handle Chapter 1 events @@ -139,11 +138,11 @@ public: DECLARE_FUNCTION(chapter3) DECLARE_FUNCTION_1(function30, const char *soundName) - DECLARE_FUNCTION(function31) + DECLARE_FUNCTION(talkAboutMax) DECLARE_FUNCTION(function32) DECLARE_FUNCTION(function33) DECLARE_FUNCTION(function34) - DECLARE_FUNCTION(function35) + DECLARE_FUNCTION(organizeConcertInvitations) /** * Setup Chapter 4 @@ -155,7 +154,7 @@ public: */ DECLARE_FUNCTION(chapter4Handler) - DECLARE_FUNCTION(function38) + DECLARE_FUNCTION(resetState) /** * Setup Chapter 5 @@ -167,8 +166,8 @@ public: */ DECLARE_FUNCTION(chapter5Handler) - DECLARE_FUNCTION(function41) - DECLARE_FUNCTION(function42) + DECLARE_FUNCTION(askPassengersToStayInCompartments) + DECLARE_FUNCTION(end) private: void talk(const SavePoint &savepoint, const char *sound1, const char *sound2); diff --git a/engines/lastexpress/entities/vesna.cpp b/engines/lastexpress/entities/vesna.cpp index 7a1f1d3195..f29bce8b2b 100644 --- a/engines/lastexpress/entities/vesna.cpp +++ b/engines/lastexpress/entities/vesna.cpp @@ -32,10 +32,7 @@ #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" - #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -134,7 +131,7 @@ IMPLEMENT_FUNCTION_II(7, Vesna, updateEntity2, CarIndex, EntityPosition) break; case kAction123668192: - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -165,7 +162,8 @@ IMPLEMENT_FUNCTION(11, Vesna, function11) case kActionNone: if (parameters->param3) { - UPDATE_PARAM(parameters->param7, getState()->timeTicks, 75); + if (!Entity::updateParameter(parameters->param7, getState()->timeTicks, 75)) + break; parameters->param2 = 1; parameters->param3 = 0; @@ -245,7 +243,7 @@ IMPLEMENT_FUNCTION(11, Vesna, function11) case kAction55996766: case kAction101687594: - CALLBACK_ACTION(); + callbackAction(); break; } IMPLEMENT_FUNCTION_END @@ -257,7 +255,7 @@ IMPLEMENT_FUNCTION(12, Vesna, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Vesna, setup_chapter1Handler)); break; case kActionDefault: @@ -458,7 +456,7 @@ IMPLEMENT_FUNCTION(18, Vesna, function18) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityVesna); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -514,7 +512,8 @@ IMPLEMENT_FUNCTION(20, Vesna, chapter3Handler) } if (parameters->param2) { - UPDATE_PARAM(parameters->param8, getState()->timeTicks, 75); + if (!Entity::updateParameter(parameters->param8, getState()->timeTicks, 75)) + break; parameters->param1 = 1; parameters->param2 = 0; @@ -711,7 +710,7 @@ IMPLEMENT_FUNCTION(21, Vesna, function21) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityVesna); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -1083,13 +1082,14 @@ IMPLEMENT_FUNCTION(30, Vesna, function30) case kActionNone: if (!params->param1) { - UPDATE_PARAM_PROC(params->param3, getState()->timeTicks, 120) + if (Entity::updateParameter(params->param3, getState()->timeTicks, 120)) { getSound()->playSound(kEntityVesna, "Ves50001", kFlagDefault); params->param1 = 1; - UPDATE_PARAM_PROC_END + } } - UPDATE_PARAM(params->param4, getState()->timeTicks, 180); + if (!Entity::updateParameter(params->param4, getState()->timeTicks, 180)) + break; setCallback(1); setup_savegame(kSavegameTypeEvent, kEventCathVesnaTrainTopKilled); diff --git a/engines/lastexpress/entities/vesna.h b/engines/lastexpress/entities/vesna.h index a09664096d..025d45882e 100644 --- a/engines/lastexpress/entities/vesna.h +++ b/engines/lastexpress/entities/vesna.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_VESNA_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/entities/yasmin.cpp b/engines/lastexpress/entities/yasmin.cpp index 45e5e11568..1d280f51e0 100644 --- a/engines/lastexpress/entities/yasmin.cpp +++ b/engines/lastexpress/entities/yasmin.cpp @@ -28,10 +28,8 @@ #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" namespace LastExpress { @@ -132,7 +130,7 @@ IMPLEMENT_FUNCTION(6, Yasmin, function6) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityYasmin); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -172,7 +170,7 @@ IMPLEMENT_FUNCTION(7, Yasmin, function7) getData()->location = kLocationInsideCompartment; getEntities()->clearSequences(kEntityYasmin); - CALLBACK_ACTION(); + callbackAction(); break; } break; @@ -186,7 +184,7 @@ IMPLEMENT_FUNCTION(8, Yasmin, chapter1) break; case kActionNone: - TIME_CHECK(kTimeChapter1, params->param1, setup_chapter1Handler); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Yasmin, setup_chapter1Handler)); break; case kActionDefault: @@ -204,12 +202,22 @@ IMPLEMENT_FUNCTION(9, Yasmin, chapter1Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime1093500, params->param1, 1, setup_function6); - TIME_CHECK_CALLBACK(kTime1161000, params->param2, 3, setup_function7); - TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTime1162800, params->param3, 4, "Har1102", kPosition_4070); - TIME_CHECK_CALLBACK_1(kTime1165500, params->param4, 5, setup_playSound, "Har1104"); - TIME_CHECK_CALLBACK_1(kTime1174500, params->param5, 6, setup_playSound, "Har1106"); - TIME_CHECK_CALLBACK(kTime1183500, params->param6, 7, setup_function6); + if (Entity::timeCheckCallback(kTime1093500, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function6))) + break; + + if (Entity::timeCheckCallback(kTime1161000, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; + + if (Entity::timeCheckPlaySoundUpdatePosition(kTime1162800, params->param3, 4, "Har1102", kPosition_4070)) + break; + + if (Entity::timeCheckCallback(kTime1165500, params->param4, 5, "Har1104", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound))) + break; + + if (Entity::timeCheckCallback(kTime1174500, params->param5, 6, "Har1106", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound))) + break; + + Entity::timeCheckCallback(kTime1183500, params->param6, 7, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; case kActionCallback: @@ -224,23 +232,27 @@ IMPLEMENT_FUNCTION(9, Yasmin, chapter1Handler) break; case 2: - TIME_CHECK_CALLBACK(kTime1161000, params->param2, 3, setup_function7); + if (Entity::timeCheckCallback(kTime1161000, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; // Fallback to case 3 case 3: - TIME_CHECK_PLAYSOUND_UPDATEPOSITION(kTime1162800, params->param3, 4, "Har1102", kPosition_4070); + if (Entity::timeCheckPlaySoundUpdatePosition(kTime1162800, params->param3, 4, "Har1102", kPosition_4070)) + break; // Fallback to case 4 case 4: - TIME_CHECK_CALLBACK_1(kTime1165500, params->param4, 5, setup_playSound, "Har1104"); + if (Entity::timeCheckCallback(kTime1165500, params->param4, 5, "Har1104", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound))) + break; // Fallback to case 5 case 5: - TIME_CHECK_CALLBACK_1(kTime1174500, params->param5, 6, setup_playSound, "Har1106"); + if (Entity::timeCheckCallback(kTime1174500, params->param5, 6, "Har1106", WRAP_SETUP_FUNCTION_S(Yasmin, setup_playSound))) + break; // Fallback to case 6 case 6: - TIME_CHECK_CALLBACK(kTime1183500, params->param6, 7, setup_function6); + Entity::timeCheckCallback(kTime1183500, params->param6, 7, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; } break; @@ -281,7 +293,8 @@ IMPLEMENT_FUNCTION(12, Yasmin, chapter2Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime1759500, params->param1, 1, setup_function7); + if (Entity::timeCheckCallback(kTime1759500, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; if (getState()->time > kTime1800000 && !params->param2) { params->param2 = 1; @@ -334,9 +347,13 @@ IMPLEMENT_FUNCTION(14, Yasmin, chapter3Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime2062800, params->param1, 1, setup_function6); - TIME_CHECK_CALLBACK(kTime2106000, params->param2, 2, setup_function7); - TIME_CHECK_CALLBACK(kTime2160000, params->param3, 3, setup_function6); + if (Entity::timeCheckCallback(kTime2062800, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function6))) + break; + + if (Entity::timeCheckCallback(kTime2106000, params->param2, 2, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; + + Entity::timeCheckCallback(kTime2160000, params->param3, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; case kActionCallback: @@ -345,11 +362,12 @@ IMPLEMENT_FUNCTION(14, Yasmin, chapter3Handler) break; case 1: - TIME_CHECK_CALLBACK(kTime2106000, params->param2, 2, setup_function7); + if (Entity::timeCheckCallback(kTime2106000, params->param2, 2, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; // Fallback to case 2 case 2: - TIME_CHECK_CALLBACK(kTime2160000, params->param3, 3, setup_function6); + Entity::timeCheckCallback(kTime2160000, params->param3, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; } break; @@ -381,8 +399,10 @@ IMPLEMENT_FUNCTION(16, Yasmin, chapter4Handler) break; case kActionNone: - TIME_CHECK_CALLBACK(kTime2457000, params->param1, 1, setup_function7); - TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6); + if (Entity::timeCheckCallback(kTime2457000, params->param1, 1, WRAP_SETUP_FUNCTION(Yasmin, setup_function7))) + break; + + Entity::timeCheckCallback(kTime2479500, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; case kActionCallback: @@ -397,7 +417,7 @@ IMPLEMENT_FUNCTION(16, Yasmin, chapter4Handler) break; case 2: - TIME_CHECK_CALLBACK(kTime2479500, params->param2, 3, setup_function6); + Entity::timeCheckCallback(kTime2479500, params->param2, 3, WRAP_SETUP_FUNCTION(Yasmin, setup_function6)); break; } break; @@ -445,7 +465,9 @@ IMPLEMENT_FUNCTION(20, Yasmin, function20) break; case kActionNone: - UPDATE_PARAM(params->param1, getState()->time, 2700); + if (!Entity::updateParameter(params->param1, getState()->time, 2700)) + break; + setup_function21(); break; @@ -472,7 +494,7 @@ IMPLEMENT_FUNCTION(21, Yasmin, function21) case kActionNone: case kActionDefault: if (getEntities()->updateEntity(kEntityYasmin, (CarIndex)params->param1, (EntityPosition)params->param2)) - CALLBACK_ACTION(); + callbackAction(); break; case kActionExcuseMeCath: diff --git a/engines/lastexpress/entities/yasmin.h b/engines/lastexpress/entities/yasmin.h index e943a8b158..b1413f5c2f 100644 --- a/engines/lastexpress/entities/yasmin.h +++ b/engines/lastexpress/entities/yasmin.h @@ -24,7 +24,6 @@ #define LASTEXPRESS_YASMIN_H #include "lastexpress/entities/entity.h" -#include "lastexpress/entities/entity_intern.h" namespace LastExpress { diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp index b832d46a60..49a9b85657 100644 --- a/engines/lastexpress/fight/fight.cpp +++ b/engines/lastexpress/fight/fight.cpp @@ -31,6 +31,7 @@ #include "lastexpress/data/cursor.h" #include "lastexpress/data/sequence.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" @@ -40,7 +41,6 @@ #include "lastexpress/sound/queue.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -53,6 +53,8 @@ Fight::FightData::FightData() { index = 0; isFightRunning = false; + + memset(&sequences, 0, sizeof(sequences)); } Fight::FightData::~FightData() { @@ -399,6 +401,9 @@ end_load: } void Fight::setOpponents() { + if (!_data) + error("[Fight::setOpponents] Data not initialized"); + _data->player->setOpponent(_data->opponent); _data->opponent->setOpponent(_data->player); diff --git a/engines/lastexpress/fight/fighter.cpp b/engines/lastexpress/fight/fighter.cpp index bae7728a2b..4b1cddabd4 100644 --- a/engines/lastexpress/fight/fighter.cpp +++ b/engines/lastexpress/fight/fighter.cpp @@ -53,20 +53,20 @@ Fighter::Fighter(LastExpressEngine *engine) : _engine(engine) { } Fighter::~Fighter() { - clearSequences(); -} - -////////////////////////////////////////////////////////////////////////// -// Cleanup -////////////////////////////////////////////////////////////////////////// -void Fighter::clearSequences() { // The original game resets the function pointers to default values, just before deleting the struct getScenes()->removeAndRedraw(&_frame, false); // Free sequences - for (int i = 0; i < (int)_sequences.size(); i++) + for (uint i = 0; i < _sequences.size(); i++) SAFE_DELETE(_sequences[i]); + + // Zero-out passed pointers + _sequence = NULL; + _opponent = NULL; + _fight = NULL; + + _engine = NULL; } ////////////////////////////////////////////////////////////////////////// @@ -113,6 +113,9 @@ void Fighter::draw() { // Processing ////////////////////////////////////////////////////////////////////////// void Fighter::process() { + if (!_fight) + error("[Fighter::handleAction] Fighter not initialized properly"); + if (!_sequence) { if (_frame) { getScenes()->removeFromQueue(_frame); @@ -188,6 +191,9 @@ void Fighter::process() { // Default actions ////////////////////////////////////////////////////////////////////////// void Fighter::handleAction(FightAction action) { + if (!_opponent || !_fight) + error("[Fighter::handleAction] Fighter not initialized properly"); + switch (action) { default: return; @@ -243,7 +249,10 @@ void Opponent::update() { // Helpers ////////////////////////////////////////////////////////////////////////// bool Fighter::checkFrame(uint32 val) { - return (_frame->getInfo()->field_33 & val); + if (!_frame) + error("[Fighter::checkFrame] Invalid current frame"); + + return (bool)(_frame->getInfo()->field_33 & val); } } // End of namespace LastExpress diff --git a/engines/lastexpress/fight/fighter.h b/engines/lastexpress/fight/fighter.h index e37fe49d86..dad95af186 100644 --- a/engines/lastexpress/fight/fighter.h +++ b/engines/lastexpress/fight/fighter.h @@ -99,9 +99,6 @@ protected: void draw(); void process(); - // Cleanup - void clearSequences(); - // Helpers bool checkFrame(uint32 val); }; diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 98d74dd1a7..796abf2ce7 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -29,7 +29,6 @@ #include "lastexpress/entities/abbot.h" #include "lastexpress/entities/anna.h" -#include "lastexpress/entities/entity.h" #include "lastexpress/game/beetle.h" #include "lastexpress/game/entities.h" @@ -42,9 +41,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -332,6 +329,22 @@ static const struct { {"8042A", 600} }; +template<class Arg, class Res, class T> +class Functor1MemConst : public Common::Functor1<Arg, Res> { +public: + typedef Res (T::*FuncType)(Arg) const; + + Functor1MemConst(T *t, const FuncType &func) : _t(t), _func(func) {} + + bool isValid() const { return _func != 0 && _t != 0; } + Res operator()(Arg v1) const { + return (_t->*_func)(v1); + } +private: + mutable T *_t; + const FuncType _func; +}; + Action::Action(LastExpressEngine *engine) : _engine(engine) { ADD_ACTION(dummy); ADD_ACTION(inventory); @@ -381,7 +394,7 @@ Action::Action(LastExpressEngine *engine) : _engine(engine) { } Action::~Action() { - for (int i = 0; i < (int)_actions.size(); i++) + for (uint i = 0; i < _actions.size(); i++) SAFE_DELETE(_actions[i]); _actions.clear(); @@ -407,9 +420,7 @@ SceneIndex Action::processHotspot(const SceneHotspot &hotspot) { ////////////////////////////////////////////////////////////////////////// // Action 0 IMPLEMENT_ACTION(dummy) - warning("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action); - - return kSceneInvalid; + error("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action); } ////////////////////////////////////////////////////////////////////////// @@ -1742,14 +1753,14 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const { return kCursorBackward; case SceneHotspot::kActionKnockOnDoor: - warning("================================= DOOR %03d =================================", object); + debugC(2, kLastExpressDebugScenes, "================================= DOOR %03d =================================", object); if (object >= kObjectMax) return kCursorNormal; else return (CursorStyle)getObjects()->get(object).cursor; case SceneHotspot::kAction12: - warning("================================= OBJECT %03d =================================", object); + debugC(2, kLastExpressDebugScenes, "================================= OBJECT %03d =================================", object); if (object >= kObjectMax) return kCursorNormal; @@ -1759,7 +1770,7 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const { return kCursorNormal; case SceneHotspot::kActionPickItem: - warning("================================= ITEM %03d =================================", object); + debugC(2, kLastExpressDebugScenes, "================================= ITEM %03d =================================", object); if (object >= kObjectCompartmentA) return kCursorNormal; @@ -1770,7 +1781,7 @@ CursorStyle Action::getCursor(const SceneHotspot &hotspot) const { return kCursorNormal; case SceneHotspot::kActionDropItem: - warning("================================= ITEM %03d =================================", object); + debugC(2, kLastExpressDebugScenes, "================================= ITEM %03d =================================", object); if (object >= kObjectCompartmentA) return kCursorNormal; @@ -1887,7 +1898,7 @@ LABEL_KEY: // Handle compartment action case SceneHotspot::kActionCompartment: case SceneHotspot::kActionExitCompartment: - warning("================================= DOOR %03d =================================", object); + debugC(2, kLastExpressDebugScenes, "================================= DOOR %03d =================================", object); if (object >= kObjectMax) return kCursorNormal; diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp index ab707ddae9..d7a369ba40 100644 --- a/engines/lastexpress/game/beetle.cpp +++ b/engines/lastexpress/game/beetle.cpp @@ -27,7 +27,6 @@ #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -95,7 +94,7 @@ void Beetle::load() { // Check that all sequences are loaded properly _data->isLoaded = true; - for (int i = 0; i < (int)_data->sequences.size(); i++) { + for (uint i = 0; i < _data->sequences.size(); i++) { if (!_data->sequences[i]->isLoaded()) { _data->isLoaded = false; break; @@ -337,26 +336,13 @@ void Beetle::drawUpdate() { } } -#define INVERT_Y() \ - switch (_data->indexes[_data->offset]) { \ - default: \ - break; \ - case 24: \ - case 25: \ - case 26: \ - case 27: \ - case 28: \ - _data->coordY = -_data->coordY; \ - break; \ - } - // Invert direction - INVERT_Y(); + invertDirection(); SequenceFrame *frame = new SequenceFrame(_data->currentSequence, (uint16)_data->currentFrame); updateFrame(frame); - INVERT_Y(); + invertDirection(); getScenes()->addToQueue(frame); @@ -364,6 +350,24 @@ void Beetle::drawUpdate() { _data->frame = frame; } +void Beetle::invertDirection() { + if (!_data) + error("[Beetle::invertDirection] Sequences have not been loaded"); + + switch (_data->indexes[_data->offset]) { + default: + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + _data->coordY = -_data->coordY; + break; + } +} + void Beetle::move() { if (!_data) error("[Beetle::move] Sequences have not been loaded"); diff --git a/engines/lastexpress/game/beetle.h b/engines/lastexpress/game/beetle.h index d3c47f39e5..034ebbd557 100644 --- a/engines/lastexpress/game/beetle.h +++ b/engines/lastexpress/game/beetle.h @@ -111,6 +111,7 @@ private: void updateFrame(SequenceFrame *frame) const; void updateData(uint32 index); void drawUpdate(); + void invertDirection(); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index f27087a609..fafbd7cb64 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -27,8 +27,6 @@ #include "lastexpress/data/sequence.h" // Entities -#include "lastexpress/entities/entity.h" - #include "lastexpress/entities/abbot.h" #include "lastexpress/entities/alexei.h" #include "lastexpress/entities/alouan.h" @@ -71,10 +69,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -185,7 +181,7 @@ Entities::Entities(LastExpressEngine *engine) : _engine(engine) { Entities::~Entities() { SAFE_DELETE(_header); - for (int i = 0; i < (int)_entities.size(); i++) + for (uint i = 0; i < _entities.size(); i++) SAFE_DELETE(_entities[i]); _entities.clear(); @@ -673,11 +669,12 @@ void Entities::executeCallbacks() { ////////////////////////////////////////////////////////////////////////// // Processing ////////////////////////////////////////////////////////////////////////// -#define INCREMENT_DIRECTION_COUNTER() { \ - data->doProcessEntity = false; \ - if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) \ - ++data->field_4A1; \ - } +void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) const { + data->doProcessEntity = false; + + if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) + ++data->field_4A1; +} void Entities::processEntity(EntityIndex entityIndex) { EntityData::EntityCallData *data = getData(entityIndex); @@ -696,7 +693,7 @@ void Entities::processEntity(EntityIndex entityIndex) { getScenes()->removeAndRedraw(&data->frame, false); getScenes()->removeAndRedraw(&data->frame1, false); - INCREMENT_DIRECTION_COUNTER(); + incrementDirectionCounter(data); return; } @@ -726,7 +723,7 @@ label_nosequence: processFrame(entityIndex, false, true); if (!getFlags()->flag_entities_0 && !data->doProcessEntity) { - INCREMENT_DIRECTION_COUNTER(); + incrementDirectionCounter(data); return; } } else { @@ -744,7 +741,7 @@ label_nosequence: data->position = 0; } - INCREMENT_DIRECTION_COUNTER(); + incrementDirectionCounter(data); } return; } @@ -754,46 +751,44 @@ label_nosequence: if (data->frame->getInfo()->field_30 > (data->field_49B + 1) || (data->direction == kDirectionLeft && data->sequence->count() == 1)) { ++data->field_49B; - } else { - if (data->frame->getInfo()->field_30 > data->field_49B && !data->frame->getInfo()->keepPreviousFrame) { - ++data->field_49B; - } else { - if (data->frame->getInfo()->keepPreviousFrame == 1) - keepPreviousFrame = true; - - // Increment current frame - ++data->currentFrame; + } else if (data->frame->getInfo()->field_30 <= data->field_49B || data->frame->getInfo()->keepPreviousFrame) { + if (data->frame->getInfo()->keepPreviousFrame == 1) + keepPreviousFrame = true; - if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) { + // Increment current frame + ++data->currentFrame; - if (data->direction == kDirectionLeft) { - data->currentFrame = 0; - } else { - keepPreviousFrame = true; - drawNextSequence(entityIndex); + if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) { - if (getFlags()->flag_entities_0 || data->doProcessEntity) - return; + if (data->direction == kDirectionLeft) { + data->currentFrame = 0; + } else { + keepPreviousFrame = true; + drawNextSequence(entityIndex); - if (!data->sequence2) { - updateEntityPosition(entityIndex); - data->doProcessEntity = false; - return; - } + if (getFlags()->flag_entities_0 || data->doProcessEntity) + return; - copySequenceData(entityIndex); + if (!data->sequence2) { + updateEntityPosition(entityIndex); + data->doProcessEntity = false; + return; } + copySequenceData(entityIndex); } - processFrame(entityIndex, keepPreviousFrame, false); - - if (getFlags()->flag_entities_0 || data->doProcessEntity) - return; } + + processFrame(entityIndex, keepPreviousFrame, false); + + if (getFlags()->flag_entities_0 || data->doProcessEntity) + return; + } else { + ++data->field_49B; } - INCREMENT_DIRECTION_COUNTER(); + incrementDirectionCounter(data); } void Entities::computeCurrentFrame(EntityIndex entityIndex) const { @@ -2283,7 +2278,7 @@ label_process_entity: if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) { getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath); - } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)){ + } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)) { getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe); if (getScenes()->checkCurrentPosition(false)) diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h index eb5eae461f..81aed627aa 100644 --- a/engines/lastexpress/game/entities.h +++ b/engines/lastexpress/game/entities.h @@ -344,6 +344,7 @@ private: uint _positions[_positionsCount]; void executeCallbacks(); + void incrementDirectionCounter(EntityData::EntityCallData *data) const; void processEntity(EntityIndex entity); void drawSequence(EntityIndex entity, const char *sequence, EntityDirection direction) const; diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index e417b1ec0d..11e7369ee1 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -26,17 +26,17 @@ #include "lastexpress/data/scene.h" #include "lastexpress/data/snd.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/logic.h" +#include "lastexpress/game/savegame.h" #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" #include "lastexpress/menu/menu.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -44,7 +44,7 @@ namespace LastExpress { Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItemIndex(0), _itemsShown(0), - _showingHourGlass(false), _blinkingEgg(false), _blinkingTime(0), _blinkingInterval(_defaultBlinkingInterval), _blinkingBrightness(1), + _showingHourGlass(false), _blinkingDirection(1), _blinkingBrightness(0), _useMagnifier(false), _portraitHighlighted(false), _isOpened(false), _eggHightlighted(false), _itemScene(NULL) { //_inventoryRect = Common::Rect(0, 0, 32, 32); @@ -162,13 +162,11 @@ void Inventory::handleMouseEvent(const Common::Event &ev) { getMenu()->show(true, kSavegameTypeIndex, 0); - } else if (ev.type == Common::EVENT_RBUTTONDOWN) { - if (getGlobalTimer()) { - if (getSoundQueue()->isBuffered("TIMER")) - getSoundQueue()->removeFromQueue("TIMER"); + } else if (ev.type == Common::EVENT_RBUTTONDOWN && getGlobalTimer()) { + if (getSoundQueue()->isBuffered("TIMER")) + getSoundQueue()->removeFromQueue("TIMER"); - setGlobalTimer(900); - } + setGlobalTimer(900); } } @@ -180,7 +178,7 @@ void Inventory::handleMouseEvent(const Common::Event &ev) { if (_highlightedItemIndex) drawHighlight(_highlightedItemIndex, true); } else { - // The user released the mouse button, we need to update the inventory state (clear hightlight and items) + // The user released the mouse button, we need to update the inventory state (clear highlight and items) drawItem((CursorStyle)getProgress().portrait, 0, 0, 1); _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(0, 44, 32, (int16)(40 * _itemsShown + 40))); _isOpened = false; @@ -226,12 +224,11 @@ void Inventory::handleMouseEvent(const Common::Event &ev) { if (getFlags()->mouseLeftPressed) { if (getState()->sceneUseBackup) { - if (getState()->sceneBackup2 - && getFirstExaminableItem() == _selectedItem) { - SceneIndex sceneIndex = getState()->sceneBackup2; - getState()->sceneBackup2 = kSceneNone; + if (getState()->sceneBackup2 && getFirstExaminableItem() == _selectedItem) { + SceneIndex sceneIndex = getState()->sceneBackup2; + getState()->sceneBackup2 = kSceneNone; - getScenes()->loadScene(sceneIndex); + getScenes()->loadScene(sceneIndex); } } else { getState()->sceneBackup = getState()->scene; @@ -261,7 +258,7 @@ void Inventory::handleMouseEvent(const Common::Event &ev) { // Change item highlight on list if (getFlags()->mouseLeftPressed) { - uint32 index = ev.mouse.y / 40; + uint32 index = (uint16)ev.mouse.y / 40; if (_highlightedItemIndex && _highlightedItemIndex != index) drawHighlight(_highlightedItemIndex, true); @@ -418,12 +415,12 @@ void Inventory::show() { drawEgg(); } -void Inventory::setPortrait(InventoryItem item) { +void Inventory::setPortrait(InventoryItem item) const { getProgress().portrait = item; drawItem((CursorStyle)getProgress().portrait, 0, 0); } -void Inventory::showHourGlass(){ +void Inventory::showHourGlass() const { if (!getMenu()->isShown()) drawItem(kCursorHourGlass, 608, 448); @@ -613,7 +610,7 @@ void Inventory::examine(InventoryItem item) { } } -void Inventory::drawEgg() { +void Inventory::drawEgg() const { if (!getMenu()->isShown()) drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, _eggHightlighted ? 0 : 1); @@ -621,40 +618,51 @@ void Inventory::drawEgg() { } // Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit. -void Inventory::drawBlinkingEgg() { +void Inventory::drawBlinkingEgg(uint ticks) { + uint globalTimer = (uint)getGlobalTimer(); + uint timerValue = (getProgress().jacket == kJacketGreen) ? 450 : 225; - warning("[Inventory::drawBlinkingEgg] Blinking not implemented"); + if (globalTimer == timerValue || globalTimer == 900) { + _blinkingBrightness = 0; + _blinkingDirection = 1; + } - //// TODO show egg (with or without mouseover) + globalTimer = globalTimer <= ticks ? 0 : globalTimer - ticks; + setGlobalTimer(globalTimer); - //// Play timer sound - //if (getGlobalTimer() < 90) { - // if (getGlobalTimer() + ticks >= 90) - // getSound()->playSoundWithSubtitles("TIMER.SND", 50331664, kEntityPlayer); + if (getFlags()->flag_0 + || (globalTimer % 5) == 0 + || (globalTimer <= 500 && (globalTimer % ((globalTimer + 100) / 100)) == 0)) + blinkEgg(); - // if (getSoundQueue()->isBuffered("TIMER")) - // setGlobalTimer(0); - //} + if (globalTimer < 90) { + if ((globalTimer + ticks) >= 90) + getSound()->playSoundWithSubtitles("TIMER", (SoundFlag)(kFlagType13|kFlagDefault), kEntityPlayer); - //// Restore egg to standard brightness - //if (!getGlobalTimer()) { - // - //} + if (!getSoundQueue()->isBuffered("TIMER")) + setGlobalTimer(0); + } + if (globalTimer == 0) { + drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, _menuEggRect.contains(getCoords()) ? 1 : -1); - //drawItem(608, 448, getMenu()->getGameId() + 39, _blinkingBrightness) + askForRedraw(); - //// TODO if delta time > _blinkingInterval, update egg & ask for redraw then adjust blinking time and remaining time - // + getSaveLoad()->saveGame(kSavegameTypeAuto, kEntityChapters, 0); + } +} - //// Reset values and stop blinking - //if (_blinkingTime == 0) - // blinkEgg(false); +void Inventory::blinkEgg() { + drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : (int16)_blinkingBrightness); askForRedraw(); + + _blinkingBrightness += _blinkingDirection; + if (_blinkingBrightness == 0 || _blinkingBrightness == 3) + _blinkingDirection = -_blinkingDirection; } -void Inventory::drawItem(CursorStyle id, uint16 x, uint16 y, int16 brightnessIndex) { +void Inventory::drawItem(CursorStyle id, uint16 x, uint16 y, int16 brightnessIndex) const { Icon icon(id); icon.setPosition(x, y); @@ -678,7 +686,7 @@ void Inventory::drawSelectedItem() { } } -void Inventory::clearSelectedItem() { +void Inventory::clearSelectedItem() const { _engine->getGraphicsManager()->clear(GraphicsManager::kBackgroundInventory, Common::Rect(44, 0, 44 + 32, 32)); } @@ -733,7 +741,7 @@ void Inventory::drawHighlight(uint32 currentIndex, bool reset) { } } -uint32 Inventory::getItemIndex(uint32 currentIndex) { +uint32 Inventory::getItemIndex(uint32 currentIndex) const { uint32 count = 0; for (uint32 i = 1; i < ARRAYSIZE(_entries); i++) { diff --git a/engines/lastexpress/game/inventory.h b/engines/lastexpress/game/inventory.h index b1995adce3..b1019a43c6 100644 --- a/engines/lastexpress/game/inventory.h +++ b/engines/lastexpress/game/inventory.h @@ -106,11 +106,10 @@ public: // UI Control void show(); - void blinkEgg(bool enabled); - void showHourGlass(); - void setPortrait(InventoryItem item); - void drawEgg(); - void drawBlinkingEgg(); + void showHourGlass() const; + void setPortrait(InventoryItem item) const; + void drawEgg() const; + void drawBlinkingEgg(uint ticks = 1); // Handle inventory UI events. void handleMouseEvent(const Common::Event &ev); @@ -133,8 +132,6 @@ public: Common::String toString(); private: - static const uint32 _defaultBlinkingInterval = 250; ///< Default blinking interval in ms - LastExpressEngine *_engine; InventoryEntry _entries[32]; @@ -144,9 +141,7 @@ private: uint32 _itemsShown; bool _showingHourGlass; - bool _blinkingEgg; - uint32 _blinkingTime; - uint32 _blinkingInterval; + int16 _blinkingDirection; uint16 _blinkingBrightness; // Flags @@ -157,8 +152,6 @@ private: Scene *_itemScene; - // Important rects - //Common::Rect _inventoryRect; Common::Rect _menuEggRect; Common::Rect _selectedItemRect; @@ -168,14 +161,15 @@ private: void close(); void examine(InventoryItem item); void drawHighlight(uint32 currentIndex, bool reset); - uint32 getItemIndex(uint32 currentIndex); + uint32 getItemIndex(uint32 currentIndex) const; bool isItemSceneParameter(InventoryItem item) const; - void drawItem(CursorStyle id, uint16 x, uint16 y, int16 brighnessIndex = -1); + void drawItem(CursorStyle id, uint16 x, uint16 y, int16 brighnessIndex = -1) const; + void blinkEgg(); void drawSelectedItem(); - void clearSelectedItem(); + void clearSelectedItem() const; }; } // End of namespace LastExpress diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp index aeac8cff98..09104d1bf9 100644 --- a/engines/lastexpress/game/logic.cpp +++ b/engines/lastexpress/game/logic.cpp @@ -47,10 +47,7 @@ #include "lastexpress/menu/menu.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" -#include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -88,16 +85,6 @@ Logic::~Logic() { ////////////////////////////////////////////////////////////////////////// // Event Handling ////////////////////////////////////////////////////////////////////////// -#define REDRAW_CURSOR() { \ - if (getInventory()->isMagnifierInUse()) \ - _engine->getCursor()->setStyle(kCursorMagnifier); \ - if (getInventory()->isPortraitHighlighted() \ - || getInventory()->isOpened() \ - || getInventory()->isEggHighlighted()) \ - _engine->getCursor()->setStyle(kCursorNormal); \ - return; \ -} - void Logic::eventMouse(const Common::Event &ev) { bool hotspotHandled = false; @@ -168,7 +155,9 @@ void Logic::eventMouse(const Common::Event &ev) { getInventory()->unselectItem(); } - REDRAW_CURSOR() + redrawCursor(); + + return; } // Handle match case @@ -194,7 +183,9 @@ void Logic::eventMouse(const Common::Event &ev) { getScenes()->processScene(); } - REDRAW_CURSOR() + redrawCursor(); + + return; } // Handle entity item case @@ -315,7 +306,7 @@ void Logic::eventTick(const Common::Event &) { ////////////////////////////////////////////////////////////////////////// // Draw the blinking egg if needed if (getGlobalTimer() && !getFlags()->shouldDrawEggOrHourGlass) - getInventory()->drawBlinkingEgg(); + getInventory()->drawBlinkingEgg(ticks); ////////////////////////////////////////////////////////////////////////// // Adjust time and save game if needed @@ -411,9 +402,12 @@ void Logic::eventTick(const Common::Event &) { * Resets the game state. */ void Logic::resetState() { - getState()->scene = kSceneDefault; + getScenes()->setCoordinates(Common::Rect(80, 0, 559, 479)); + + SAFE_DELETE(_entities); + _entities = new Entities(_engine); - warning("[Logic::resetState] Not implemented! You need to restart the engine until this is implemented."); + _state->reset(); } /** @@ -595,4 +589,14 @@ void Logic::updateCursor(bool) const { /* the cursor is always updated, even whe _engine->getCursor()->setStyle(style); } +void Logic::redrawCursor() const { + if (getInventory()->isMagnifierInUse()) + _engine->getCursor()->setStyle(kCursorMagnifier); + + if (getInventory()->isPortraitHighlighted() + || getInventory()->isOpened() + || getInventory()->isEggHighlighted()) + _engine->getCursor()->setStyle(kCursorNormal); +} + } // End of namespace LastExpress diff --git a/engines/lastexpress/game/logic.h b/engines/lastexpress/game/logic.h index 8b7dcef942..efb8f1e1a3 100644 --- a/engines/lastexpress/game/logic.h +++ b/engines/lastexpress/game/logic.h @@ -25,8 +25,6 @@ #include "lastexpress/shared.h" -#include "lastexpress/game/entities.h" - #include "lastexpress/eventhandler.h" #include "common/events.h" @@ -75,6 +73,7 @@ private: void switchChapter() const; void showCredits() const; + void redrawCursor() const; // Flags & Members bool _flagActionPerformed; diff --git a/engines/lastexpress/game/object.cpp b/engines/lastexpress/game/object.cpp index d9e9e4279a..48df91ea6d 100644 --- a/engines/lastexpress/game/object.cpp +++ b/engines/lastexpress/game/object.cpp @@ -22,11 +22,11 @@ #include "lastexpress/game/object.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/scenes.h" #include "lastexpress/game/state.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" namespace LastExpress { diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 9c464feb6e..021dc40bb9 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -22,6 +22,7 @@ #include "lastexpress/game/savegame.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" @@ -34,13 +35,13 @@ #include "lastexpress/debug.h" #include "lastexpress/lastexpress.h" -#include "lastexpress/helpers.h" #include "common/file.h" -#include "common/system.h" namespace LastExpress { +#define DISABLE_COMPRESSION 1 + // Names of savegames static const struct { const char *saveFile; @@ -54,14 +55,305 @@ static const struct { }; ////////////////////////////////////////////////////////////////////////// +// SavegameStream +////////////////////////////////////////////////////////////////////////// + +uint32 SavegameStream::write(const void *dataPtr, uint32 dataSize) { +#if !DISABLE_COMPRESSION + if (_enableCompression) + return writeCompressed(dataPtr, dataSize); +#endif + + return Common::MemoryWriteStreamDynamic::write(dataPtr, dataSize); +} + +uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) { +#if !DISABLE_COMPRESSION + if (_enableCompression) + return readCompressed(dataPtr, dataSize); +#endif + + return readUncompressed(dataPtr, dataSize); +} + +uint32 SavegameStream::readUncompressed(void *dataPtr, uint32 dataSize) { + if ((int32)dataSize > size() - pos()) { + dataSize = (uint32)(size() - pos()); + _eos = true; + } + memcpy(dataPtr, getData() + pos(), dataSize); + + seek(dataSize, SEEK_CUR); + + return dataSize; +} + +void SavegameStream::writeBuffer(uint8 value, bool onlyValue) { + if (_bufferOffset == -1) + _bufferOffset = 0; + + if (_bufferOffset == 256) { + _bufferOffset = 0; + Common::MemoryWriteStreamDynamic::write(_buffer, 256); + } + + if (onlyValue || value < 0xFB) + _buffer[_bufferOffset] = value; + else + _buffer[_bufferOffset] = 0xFE; + + _offset++; + _bufferOffset++; + + if (!onlyValue && value >= 0xFB) + { + if (_bufferOffset == 256) { + _bufferOffset = 0; + Common::MemoryWriteStreamDynamic::write(_buffer, 256); + } + + _buffer[_bufferOffset] = value; + + _bufferOffset++; + _offset++; + } +} + +uint8 SavegameStream::readBuffer() { + if (_bufferOffset == -1 || _bufferOffset >= 256) { + readUncompressed(_buffer, 256); + _bufferOffset = 0; + } + + byte val = _buffer[_bufferOffset]; + _bufferOffset++; + + return val; +} + +uint32 SavegameStream::process() { + _enableCompression = !_enableCompression; + +#if DISABLE_COMPRESSION + return 0; +#else + switch (_status) { + default: + break; + + case kStatusReading: + _status = kStatusReady; + if (_bufferOffset != -1 && _bufferOffset != 256) { + seek(_bufferOffset - 256, SEEK_CUR); + _bufferOffset = -1; + } + break; + + case kStatusWriting: + switch (_valueCount) { + default: + break; + + case 1: + writeBuffer(_previousValue, false); + break; + + case 2: + if (_previousValue) { + writeBuffer(0xFF); + writeBuffer(_repeatCount); + writeBuffer(_previousValue); + break; + } + + if (_repeatCount == 3) { + writeBuffer(0xFB); + break; + } + + if (_repeatCount == 255) { + writeBuffer(0xFC); + break; + } + + writeBuffer(0xFD); + writeBuffer(_repeatCount); + break; + } + + if (_bufferOffset != -1 && _bufferOffset != 0) { + Common::MemoryWriteStreamDynamic::write(_buffer, _bufferOffset); + _bufferOffset = -1; + } + break; + } + + _status = kStatusReady; + _valueCount = 0; + uint32 offset = _offset; + _offset = 0; + + return offset; +#endif +} + +uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { + if (_status == kStatusReading) + error("[SavegameStream::writeCompressed] Error: Compression buffer is in read mode."); + + _status = kStatusWriting; + const byte *data = (const byte *)dataPtr; + + while (dataSize) { + switch (_valueCount) { + default: + error("[SavegameStream::writeCompressed] Invalid value count (%d)", _valueCount); + + case 0: + _previousValue = *data++; + _valueCount = 1; + break; + + case 1: + if (*data != _previousValue) { + writeBuffer(_previousValue, false); + _previousValue = *data; + } else { + _valueCount = 2; + _repeatCount = 2; + } + + ++data; + break; + + case 2: + if (*data != _previousValue || _repeatCount >= 255) { + if (_previousValue) { + writeBuffer(0xFF, true); + writeBuffer((uint8)_repeatCount, true); + writeBuffer(_previousValue, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + if (_repeatCount == 3) { + writeBuffer(0xFB, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + if (_repeatCount == -1) { + writeBuffer(0xFC, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + writeBuffer(0xFD, true); + writeBuffer((uint8)_repeatCount, true); + + _previousValue = *data++; + _valueCount = 1; + } + + ++data; + ++_repeatCount; + break; + } + + --dataSize; + } + + return _offset; +} + +uint32 SavegameStream::readCompressed(void *dataPtr, uint32 dataSize) { + if (_status == kStatusWriting) + error("[SavegameStream::writeCompressed] Error: Compression buffer is in write mode."); + + _status = kStatusReady; + byte *data = (byte *)dataPtr; + + while (dataSize) { + switch (_valueCount) { + default: + error("[SavegameStream::readCompressed] Invalid value count (%d)", _valueCount); + + case 0: + case 1: { + // Read control code + byte control = readBuffer(); + + switch (control) { + default: + // Data value + *data++ = control; + break; + + case 0xFB: + _repeatCount = 2; + _previousValue = 0; + *data++ = 0; + _valueCount = 2; + break; + + case 0xFC: + _repeatCount = 254; + _previousValue = 0; + *data++ = 0; + _valueCount = 2; + break; + + case 0xFD: + _repeatCount = readBuffer() - 1; + _previousValue = 0; + *data++ = 0; + _valueCount = 2; + break; + + case 0xFE: + *data++ = readBuffer(); + break; + + case 0xFF: + _repeatCount = readBuffer() - 1; + _previousValue = readBuffer(); + *data++ = _previousValue; + _valueCount = 2; + break; + } + } + break; + + case 2: + *data++ = _previousValue; + _repeatCount--; + if (!_repeatCount) + _valueCount = 1; + break; + } + + --dataSize; + } + + return _offset; +} + +////////////////////////////////////////////////////////////////////////// // Constructors ////////////////////////////////////////////////////////////////////////// -SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0) { +SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0), _entity(kEntityPlayer) { } SaveLoad::~SaveLoad() { clear(true); + _savegame = NULL; // Zero passed pointers _engine = NULL; @@ -81,6 +373,7 @@ void SaveLoad::flushStream(GameId id) { error("[SaveLoad::flushStream] Savegame stream is invalid"); save->write(_savegame->getData(), (uint32)_savegame->size()); + save->finalize(); delete save; } @@ -189,10 +482,10 @@ void SaveLoad::clear(bool clearStream) { // Save & Load ////////////////////////////////////////////////////////////////////////// -// Load game -void SaveLoad::loadGame(GameId id) { +// Load last saved game +void SaveLoad::loadLastGame() { if (!_savegame) - error("[SaveLoad::loadGame] No savegame stream present"); + error("[SaveLoad::loadLastGame] No savegame stream present"); // Rewind current savegame _savegame->seek(0); @@ -229,7 +522,29 @@ void SaveLoad::loadGame(GameId id) { } // Load a specific game entry -void SaveLoad::loadGame(GameId id, uint32 index) { +void SaveLoad::loadGame(uint32 index) { + if (!_savegame) + error("[SaveLoad::loadLastGame] No savegame stream present"); + + // Rewind current savegame + _savegame->seek(0); + + // Write main header (with selected index) + SavegameMainHeader header; + header.count = index; + header.brightness = getState()->brightness; + header.volume = getState()->volume; + + Common::Serializer ser(NULL, _savegame); + header.saveLoadWithSerializer(ser); + + // TODO + // Go to the entry + // Load the entry + // Get offset (main and entry) + // Write main header again with correct entry offset + // Setup game and start + error("[SaveLoad::loadGame] Not implemented! (only loading the last entry is working for now)"); } @@ -341,16 +656,52 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he ////////////////////////////////////////////////////////////////////////// // Entries ////////////////////////////////////////////////////////////////////////// -void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { -#define WRITE_ENTRY(name, func, val) { \ - uint32 _prevPosition = (uint32)_savegame->pos(); \ - func; \ - uint32 _count = (uint32)_savegame->pos() - _prevPosition; \ - debugC(kLastExpressDebugSavegame, "Savegame: Writing " #name ": %d bytes", _count); \ - if (_count != val)\ - error("[SaveLoad::writeEntry] Number of bytes written (%d) differ from expected count (%d)", _count, val); \ +uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) { + if (!_savegame) + error("[SaveLoad::writeValue] Stream not initialized properly"); + + debugC(kLastExpressDebugSavegame, "Savegame: Writing %s: %u bytes", name, size); + + uint32 prevPosition = (uint32)_savegame->pos(); + + // Serialize data into our buffer + (*function)(ser); + + uint32 count = (uint32)_savegame->pos() - prevPosition; + +#if DISABLE_COMPRESSION + if (count != size) + error("[SaveLoad::writeValue] %s - Number of bytes written (%d) differ from expected count (%d)", name, count, size); +#endif + + return count; } +uint32 SaveLoad::readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) { + if (!_savegame) + error("[SaveLoad::readValue] Stream not initialized properly"); + + debugC(kLastExpressDebugSavegame, "Savegame: Reading %s: %u bytes", name, size); + + uint32 prevPosition = (uint32)_savegame->pos(); + + (*function)(ser); + + uint32 count = (uint32)_savegame->pos() - prevPosition; + +#if DISABLE_COMPRESSION + if (size != 0 && count != size) + error("[SaveLoad::readValue] %s - Number of bytes read (%d) differ from expected count (%d)", name, count, size); +#endif + + return count; +} + +void SaveLoad::syncEntity(Common::Serializer &ser) { + ser.syncAsUint32LE(_entity); +} + +void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { if (!_savegame) error("[SaveLoad::writeEntry] Savegame stream is invalid"); @@ -369,18 +720,22 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { header.saveLoadWithSerializer(ser); // Write game data - WRITE_ENTRY("entity index", ser.syncAsUint32LE(entity), 4); - WRITE_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4); - WRITE_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4); - WRITE_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000); - WRITE_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2); - WRITE_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128); - WRITE_ENTRY("events", getState()->syncEvents(ser), 512); - WRITE_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32); - WRITE_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128); - WRITE_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40); - WRITE_ENTRY("sound", getSoundQueue()->saveLoadWithSerializer(ser), 3 * 4 + getSoundQueue()->count() * 64); - WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16); + _entity = entity; + + _savegame->process(); + writeValue(ser, "entity index", WRAP_SYNC_FUNCTION(this, SaveLoad, syncEntity), 4); + writeValue(ser, "state", WRAP_SYNC_FUNCTION(getState(), State::GameState, saveLoadWithSerializer), 4 + 4 + 4 + 4 + 1 + 4 + 4); + writeValue(ser, "selected item", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveSelectedItem), 4); + writeValue(ser, "positions", WRAP_SYNC_FUNCTION(getEntities(), Entities, savePositions), 4 * 1000); + writeValue(ser, "compartments", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveCompartments), 4 * 16 * 2); + writeValue(ser, "progress", WRAP_SYNC_FUNCTION(&getProgress(), State::GameProgress, saveLoadWithSerializer), 4 * 128); + writeValue(ser, "events", WRAP_SYNC_FUNCTION(getState(), State::GameState, syncEvents), 512); + writeValue(ser, "inventory", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveLoadWithSerializer), 7 * 32); + writeValue(ser, "objects", WRAP_SYNC_FUNCTION(getObjects(), Objects, saveLoadWithSerializer), 5 * 128); + writeValue(ser, "entities", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveLoadWithSerializer), 1262 * 40); + writeValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer), 3 * 4 + getSoundQueue()->count() * 64); + writeValue(ser, "savepoints", WRAP_SYNC_FUNCTION(getSavePoints(), SavePoints, saveLoadWithSerializer), 128 * 16 + 4 + getSavePoints()->count() * 16); + _savegame->process(); header.offset = (uint32)_savegame->pos() - (originalPosition + 32); @@ -406,22 +761,6 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { } void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex) { -#define LOAD_ENTRY(name, func, val) { \ - uint32 _prevPosition = (uint32)_savegame->pos(); \ - func; \ - uint32 _count = (uint32)_savegame->pos() - _prevPosition; \ - debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \ - if (_count != val) \ - error("[SaveLoad::readEntry] Number of bytes read (%d) differ from expected count (%d)", _count, val); \ -} - -#define LOAD_ENTRY_ONLY(name, func) { \ - uint32 _prevPosition = (uint32)_savegame->pos(); \ - func; \ - uint32 _count = (uint32)_savegame->pos() - _prevPosition; \ - debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \ -} - if (!type || !entity || !val) error("[SaveLoad::readEntry] Invalid parameters passed"); @@ -444,20 +783,23 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b uint32 originalPosition = (uint32)_savegame->pos(); // Load game data - LOAD_ENTRY("entity index", ser.syncAsUint32LE(*entity), 4); - LOAD_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4); - LOAD_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4); - LOAD_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000); - LOAD_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2); - LOAD_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128); - LOAD_ENTRY("events", getState()->syncEvents(ser), 512); - LOAD_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32); - LOAD_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128); - LOAD_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40); - LOAD_ENTRY_ONLY("sound", getSoundQueue()->saveLoadWithSerializer(ser)); - LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser)); + _savegame->process(); + readValue(ser, "entity index", WRAP_SYNC_FUNCTION(this, SaveLoad, syncEntity), 4); + readValue(ser, "state", WRAP_SYNC_FUNCTION(getState(), State::GameState, saveLoadWithSerializer), 4 + 4 + 4 + 4 + 1 + 4 + 4); + readValue(ser, "selected item", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveSelectedItem), 4); + readValue(ser, "positions", WRAP_SYNC_FUNCTION(getEntities(), Entities, savePositions), 4 * 1000); + readValue(ser, "compartments", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveCompartments), 4 * 16 * 2); + readValue(ser, "progress", WRAP_SYNC_FUNCTION(&getProgress(), State::GameProgress, saveLoadWithSerializer), 4 * 128); + readValue(ser, "events", WRAP_SYNC_FUNCTION(getState(), State::GameState, syncEvents), 512); + readValue(ser, "inventory", WRAP_SYNC_FUNCTION(getInventory(), Inventory, saveLoadWithSerializer), 7 * 32); + readValue(ser, "objects", WRAP_SYNC_FUNCTION(getObjects(), Objects, saveLoadWithSerializer), 5 * 128); + readValue(ser, "entities", WRAP_SYNC_FUNCTION(getEntities(), Entities, saveLoadWithSerializer), 1262 * 40); + readValue(ser, "sound", WRAP_SYNC_FUNCTION(getSoundQueue(), SoundQueue, saveLoadWithSerializer)); + readValue(ser, "savepoints", WRAP_SYNC_FUNCTION(getSavePoints(), SavePoints, saveLoadWithSerializer)); + _savegame->process(); // Update chapter + *entity = _entity; getProgress().chapter = entry.chapter; // Skip padding @@ -567,7 +909,7 @@ Common::InSaveFile *SaveLoad::openForLoading(GameId id) { } Common::OutSaveFile *SaveLoad::openForSaving(GameId id) { - Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id)); + Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id), false); // TODO Enable compression again if (!save) debugC(2, kLastExpressDebugSavegame, "Cannot open savegame for writing: %s", getFilename(id).c_str()); diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index 6f0408487f..361957227e 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -80,11 +80,68 @@ namespace LastExpress { // Savegame signatures -#define SAVEGAME_SIGNATURE 0x12001200 -#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 +#define SAVEGAME_SIGNATURE 0x12001200 // 301994496 +#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 // 3865110112 + +#define WRAP_SYNC_FUNCTION(instance, className, method) \ + new Common::Functor1Mem<Common::Serializer &, void, className>(instance, &className::method) class LastExpressEngine; +class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream { +public: + SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES), _eos(false) { + _enableCompression = false; + _bufferOffset = -1; + _valueCount = 0; + _previousValue = 0; + _repeatCount = 0; + _offset = 0; + _status = kStatusReady; + + memset(_buffer, 0, 256); + } + + int32 pos() const { return MemoryWriteStreamDynamic::pos(); } + int32 size() const { return MemoryWriteStreamDynamic::size(); } + bool seek(int32 offset, int whence = SEEK_SET) { return MemoryWriteStreamDynamic::seek(offset, whence); } + bool eos() const { return _eos; } + uint32 read(void *dataPtr, uint32 dataSize); + uint32 write(const void *dataPtr, uint32 dataSize); + + uint32 process(); + +private: + enum CompressedStreamStatus { + kStatusReady, + kStatusReading, + kStatusWriting + }; + + uint32 readUncompressed(void *dataPtr, uint32 dataSize); + + // Compressed data + uint32 writeCompressed(const void *dataPtr, uint32 dataSize); + uint32 readCompressed(void *dataPtr, uint32 dataSize); + + void writeBuffer(uint8 value, bool onlyValue = true); + uint8 readBuffer(); + +private: + bool _eos; + + // Compression handling + bool _enableCompression; + int16 _bufferOffset; + byte _valueCount; + byte _previousValue; + int16 _repeatCount; + uint32 _offset; + CompressedStreamStatus _status; + + byte _buffer[256]; +}; + class SaveLoad { public: SaveLoad(LastExpressEngine *engine); @@ -96,8 +153,8 @@ public: uint32 init(GameId id, bool resetHeaders); // Save & Load - void loadGame(GameId id); - void loadGame(GameId id, uint32 index); + void loadLastGame(); + void loadGame(uint32 index); void saveGame(SavegameType type, EntityIndex entity, uint32 value); void loadVolumeBrightness(); @@ -116,30 +173,6 @@ public: uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; } private: - class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream { - public: - SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES), - _eos(false) {} - - int32 pos() const { return MemoryWriteStreamDynamic::pos(); } - int32 size() const { return MemoryWriteStreamDynamic::size(); } - bool seek(int32 offset, int whence = SEEK_SET) { return MemoryWriteStreamDynamic::seek(offset, whence); } - bool eos() const { return _eos; } - uint32 read(void *dataPtr, uint32 dataSize) { - if ((int32)dataSize > size() - pos()) { - dataSize = size() - pos(); - _eos = true; - } - memcpy(dataPtr, getData() + pos(), dataSize); - - seek(dataSize, SEEK_CUR); - - return dataSize; - } - private: - bool _eos; - }; - LastExpressEngine *_engine; struct SavegameMainHeader : Common::Serializable { @@ -268,6 +301,9 @@ private: void writeEntry(SavegameType type, EntityIndex entity, uint32 val); void readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex); + uint32 writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size); + uint32 readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size = 0); + SavegameEntryHeader *getEntry(uint32 index); // Opening save files @@ -279,6 +315,10 @@ private: void initStream(); void loadStream(GameId id); void flushStream(GameId id); + + // Misc + EntityIndex _entity; + void syncEntity(Common::Serializer &ser); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp index 64ae26c2be..8d14ec386b 100644 --- a/engines/lastexpress/game/savepoint.cpp +++ b/engines/lastexpress/game/savepoint.cpp @@ -26,7 +26,6 @@ #include "lastexpress/game/logic.h" #include "lastexpress/game/state.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -95,7 +94,7 @@ void SavePoints::process() { if (!updateEntityFromData(savepoint)) { // Call requested callback - Entity::Callback *callback = getCallback(savepoint.entity1); + Callback *callback = getCallback(savepoint.entity1); if (callback && callback->isValid()) { debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s", ENTITY_NAME(savepoint.entity1), ACTION_NAME(savepoint.action), ENTITY_NAME(savepoint.entity2)); (*callback)(savepoint); @@ -126,7 +125,7 @@ void SavePoints::addData(EntityIndex entity, ActionIndex action, uint32 param) { ////////////////////////////////////////////////////////////////////////// // Callbacks ////////////////////////////////////////////////////////////////////////// -void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) { +void SavePoints::setCallback(EntityIndex index, Callback *callback) { if (index >= 40) error("[SavePoints::setCallback] Attempting to use an invalid entity index. Valid values 0-39, was %d", index); @@ -136,7 +135,7 @@ void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) { _callbacks[index] = callback; } -Entity::Callback *SavePoints::getCallback(EntityIndex index) const { +Callback *SavePoints::getCallback(EntityIndex index) const { if (index >= 40) error("[SavePoints::getCallback] Attempting to use an invalid entity index. Valid values 0-39, was %d", index); @@ -150,7 +149,7 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti point.entity2 = entity2; point.param.intValue = param; - Entity::Callback *callback = getCallback(entity1); + Callback *callback = getCallback(entity1); if (callback != NULL && callback->isValid()) { debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%d", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param); (*callback)(point); @@ -164,7 +163,7 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti point.entity2 = entity2; strcpy((char *)&point.param.charValue, param); - Entity::Callback *callback = getCallback(entity1); + Callback *callback = getCallback(entity1); if (callback != NULL && callback->isValid()) { debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param); (*callback)(point); @@ -181,7 +180,7 @@ void SavePoints::callAndProcess() { bool isRunning = getFlags()->isGameRunning; while (isRunning) { - Entity::Callback *callback = getCallback(index); + Callback *callback = getCallback(index); if (callback != NULL && callback->isValid()) { (*callback)(savepoint); isRunning = getFlags()->isGameRunning; @@ -203,7 +202,7 @@ void SavePoints::callAndProcess() { // Misc ////////////////////////////////////////////////////////////////////////// bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { - for (int i = 0; i < (int)_data.size(); i++) { + for (uint i = 0; i < _data.size(); i++) { // Not a data savepoint! if (!_data[i].entity1) @@ -211,7 +210,7 @@ bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { // Found our data! if (_data[i].entity1 == savepoint.entity1 && _data[i].action == savepoint.action) { - debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%d", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); + debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%u", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); // the SavePoint param value is the index of the entity call parameter to update getEntities()->get(_data[i].entity1)->getParamData()->updateParameters(_data[i].param); @@ -243,7 +242,15 @@ void SavePoints::saveLoadWithSerializer(Common::Serializer &s) { } // Skip uninitialized data if any - s.skip((_savePointsMaxSize - dataSize) * 16); + // (we are using a compressed stream, so we cannot seek on load) + uint32 unusedDataSize = (_savePointsMaxSize - dataSize) * 16; + if (s.isLoading()) { + byte *empty = (byte *)malloc(unusedDataSize); + s.syncBytes(empty, unusedDataSize); + free(empty); + } else { + s.skip(unusedDataSize); + } // Number of savepoints uint32 numSavepoints = _savepoints.size(); diff --git a/engines/lastexpress/game/savepoint.h b/engines/lastexpress/game/savepoint.h index a3303b4b8a..005133891a 100644 --- a/engines/lastexpress/game/savepoint.h +++ b/engines/lastexpress/game/savepoint.h @@ -23,9 +23,8 @@ #ifndef LASTEXPRESS_SAVEPOINT_H #define LASTEXPRESS_SAVEPOINT_H -#include "lastexpress/entities/entity.h" - #include "lastexpress/helpers.h" +#include "lastexpress/shared.h" #include "common/array.h" #include "common/list.h" @@ -74,10 +73,9 @@ struct SavePoint { } }; -class SavePoints : Common::Serializable { -private: - typedef Common::Functor1<const SavePoint&, void> Callback; +typedef Common::Functor1<const SavePoint&, void> Callback; +class SavePoints : Common::Serializable { public: struct SavePointData { @@ -112,7 +110,7 @@ public: void addData(EntityIndex entity, ActionIndex action, uint32 param); // Callbacks - void setCallback(EntityIndex index, Entity::Callback *callback); + void setCallback(EntityIndex index, Callback *callback); Callback *getCallback(EntityIndex entity) const; void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0) const; void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const; diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index b886951e0b..a2c7226b93 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -22,8 +22,6 @@ #include "lastexpress/game/scenes.h" -#include "lastexpress/data/scene.h" - #include "lastexpress/game/action.h" #include "lastexpress/game/beetle.h" #include "lastexpress/game/entities.h" @@ -34,10 +32,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -493,7 +489,7 @@ bool SceneManager::checkCurrentPosition(bool doCheckOtherCars) const { if (position == 99) return true; - switch (car){ + switch (car) { default: break; @@ -743,24 +739,31 @@ void SceneManager::resetQueue() { _queue.clear(); } -void SceneManager::setCoordinates(SequenceFrame *frame) { +void SceneManager::setCoordinates(const Common::Rect &rect) { + _flagCoordinates = true; - if (!frame || frame->getInfo()->subType == 3) - return; + if (_coords.right > rect.right) + _coords.right = rect.right; - _flagCoordinates = true; + if (_coords.bottom > rect.bottom) + _coords.bottom = rect.bottom; + + if (_coords.left < rect.left) + _coords.left = rect.left; - if (_coords.right > (int)frame->getInfo()->xPos1) - _coords.right = (int16)frame->getInfo()->xPos1; + if (_coords.top < rect.top) + _coords.top = rect.top; +} - if (_coords.bottom > (int)frame->getInfo()->yPos1) - _coords.bottom = (int16)frame->getInfo()->yPos1; +void SceneManager::setCoordinates(SequenceFrame *frame) { - if (_coords.left < (int)frame->getInfo()->xPos2) - _coords.left = (int16)frame->getInfo()->xPos2; + if (!frame || frame->getInfo()->subType == 3) + return; - if (_coords.top < (int)frame->getInfo()->yPos2) - _coords.top = (int16)frame->getInfo()->yPos2; + setCoordinates(Common::Rect((int16)frame->getInfo()->xPos1, + (int16)frame->getInfo()->yPos1, + (int16)frame->getInfo()->xPos2, + (int16)frame->getInfo()->yPos2)); } void SceneManager::resetCoordinates() { diff --git a/engines/lastexpress/game/scenes.h b/engines/lastexpress/game/scenes.h index 172dde2683..1c7ae85f98 100644 --- a/engines/lastexpress/game/scenes.h +++ b/engines/lastexpress/game/scenes.h @@ -79,6 +79,7 @@ public: void removeAndRedraw(SequenceFrame **frame, bool doRedraw); void resetQueue(); void setCoordinates(SequenceFrame *frame); + void setCoordinates(const Common::Rect &rect); // Helpers SceneIndex getSceneIndexFromPosition(CarIndex car, Position position, int param3 = -1); diff --git a/engines/lastexpress/game/state.cpp b/engines/lastexpress/game/state.cpp index f3fd9720b1..02ede25595 100644 --- a/engines/lastexpress/game/state.cpp +++ b/engines/lastexpress/game/state.cpp @@ -49,6 +49,18 @@ State::~State() { _engine = NULL; } +void State::reset() { + SAFE_DELETE(_inventory); + SAFE_DELETE(_objects); + SAFE_DELETE(_savepoints); + SAFE_DELETE(_state); + + _inventory = new Inventory(_engine); + _objects = new Objects(_engine); + _savepoints = new SavePoints(_engine); + _state = new GameState(); +} + bool State::isNightTime() const { return (_state->progress.chapter == kChapter1 || _state->progress.chapter == kChapter4 diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h index c937fdce9f..2c484f6976 100644 --- a/engines/lastexpress/game/state.h +++ b/engines/lastexpress/game/state.h @@ -621,6 +621,8 @@ public: State(LastExpressEngine *engine); ~State(); + void reset(); + // Accessors Inventory *getGameInventory() { return _inventory; } Objects *getGameObjects() { return _objects; } diff --git a/engines/lastexpress/graphics.cpp b/engines/lastexpress/graphics.cpp index e129457256..753c3a39e4 100644 --- a/engines/lastexpress/graphics.cpp +++ b/engines/lastexpress/graphics.cpp @@ -160,7 +160,7 @@ void GraphicsManager::mergePlanes() { void GraphicsManager::updateScreen() { g_system->fillScreen(0); - g_system->copyRectToScreen((byte *)_screen.getBasePtr(0, 0), 640 * 2, 0, 0, 640, 480); + g_system->copyRectToScreen(_screen.getBasePtr(0, 0), 640 * 2, 0, 0, 640, 480); } } // End of namespace LastExpress diff --git a/engines/lastexpress/helpers.h b/engines/lastexpress/helpers.h index 7f3f1e246c..02454be13d 100644 --- a/engines/lastexpress/helpers.h +++ b/engines/lastexpress/helpers.h @@ -27,6 +27,8 @@ // Misc helpers ////////////////////////////////////////////////////////////////////////// +#define LOW_BYTE(w) ((unsigned char)(((unsigned long)(w)) & 0xff)) + // Misc #define getArchive(name) _engine->getResourceManager()->getFileStream(name) #define rnd(value) _engine->getRandom().getRandomNumber(value - 1) diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index 250fa0f2d0..01d2634dec 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -54,18 +54,17 @@ const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert" namespace LastExpress { LastExpressEngine::LastExpressEngine(OSystem *syst, const ADGameDescription *gd) : - Engine(syst), _gameDescription(gd), - _debugger(NULL), _cursor(NULL), - _font(NULL), _logic(NULL), _menu(NULL), - _frameCounter(0), _lastFrameCount(0), + Engine(syst), _gameDescription(gd), + _debugger(NULL), _random("lastexpress"), _cursor(NULL), + _font(NULL), _logic(NULL), _menu(NULL), + _frameCounter(0), _lastFrameCount(0), _graphicsMan(NULL), _resMan(NULL), _sceneMan(NULL), _soundMan(NULL), _eventMouse(NULL), _eventTick(NULL), - _eventMouseBackup(NULL), _eventTickBackup(NULL), - _random("lastexpress") + _eventMouseBackup(NULL), _eventTickBackup(NULL) { // Setup mixer - syncSoundSettings(); + Engine::syncSoundSettings(); // Adding the default directories const Common::FSNode gameDataDir(ConfMan.get("path")); diff --git a/engines/lastexpress/menu/menu.cpp b/engines/lastexpress/menu/menu.cpp index f1a8bebe94..c48e55bb55 100644 --- a/engines/lastexpress/menu/menu.cpp +++ b/engines/lastexpress/menu/menu.cpp @@ -30,6 +30,7 @@ #include "lastexpress/fight/fight.h" +#include "lastexpress/game/entities.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/savegame.h" @@ -41,10 +42,8 @@ #include "lastexpress/menu/trainline.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -865,7 +864,7 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) { doSavegame = false; } else { - // TODO rename saves? + warning("[Menu::initGame] Renaming saves not implemented"); } // Create a new savegame if needed @@ -876,7 +875,7 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) { getSaveLoad()->saveGame(kSavegameTypeEvent2, kEntityPlayer, kEventNone); if (!getGlobalTimer()) { - // TODO: remove existing savegame temp file + warning("[Menu::initGame] Removing temporary saves not implemented"); } // Init savegame & menu values @@ -917,13 +916,13 @@ void Menu::startGame() { if (_lastIndex == _index) { setGlobalTimer(0); if (_index) { - getSaveLoad()->loadGame(_gameId); + getSaveLoad()->loadLastGame(); } else { getLogic()->resetState(); getEntities()->setup(true, kEntityPlayer); } } else { - getSaveLoad()->loadGame(_gameId, _index); + getSaveLoad()->loadGame(_index); } } diff --git a/engines/lastexpress/resource.cpp b/engines/lastexpress/resource.cpp index ee4885e34e..1d010355ac 100644 --- a/engines/lastexpress/resource.cpp +++ b/engines/lastexpress/resource.cpp @@ -31,7 +31,6 @@ #include "common/debug.h" #include "common/file.h" -#include "common/textconsole.h" namespace LastExpress { @@ -129,13 +128,10 @@ bool ResourceManager::loadArchive(const Common::String &name) { // Get a stream to file in the archive // - same as createReadStreamForMember except it checks if the file exists and will assert / output a debug message if not -Common::SeekableReadStream *ResourceManager::getFileStream(const Common::String &name) { +Common::SeekableReadStream *ResourceManager::getFileStream(const Common::String &name) const { // Check if the file exits in the archive if (!hasFile(name)) { -//#ifdef _DEBUG -// error("[ResourceManager::getFileStream] Cannot open file: %s", name.c_str()); -//#endif debugC(2, kLastExpressDebugResource, "Error opening file: %s", name.c_str()); return NULL; } diff --git a/engines/lastexpress/resource.h b/engines/lastexpress/resource.h index f2f5d63bce..90ac9b87ad 100644 --- a/engines/lastexpress/resource.h +++ b/engines/lastexpress/resource.h @@ -42,7 +42,7 @@ public: // Loading bool loadArchive(ArchiveIndex type); static bool isArchivePresent(ArchiveIndex type); - Common::SeekableReadStream *getFileStream(const Common::String &name); + Common::SeekableReadStream *getFileStream(const Common::String &name) const; // Archive functions bool hasFile(const Common::String &name) const; diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h index d60a498447..56cf730e24 100644 --- a/engines/lastexpress/shared.h +++ b/engines/lastexpress/shared.h @@ -80,7 +80,8 @@ enum SoundFlag { kFlagMusic = 0x5000010, kFlagType3 = 0x6000000, kFlagLoop = 0x6001008, - kFlagType9 = 0x7000000 + kFlagType9 = 0x7000000, + kFlagNIS = 0x7002010 }; enum SoundState { @@ -1732,62 +1733,6 @@ enum ActionIndex { kActionEnd }; -////////////////////////////////////////////////////////////////////////// -// Functors classes used by the engine -////////////////////////////////////////////////////////////////////////// - -// FIXME is this achievable with the existing Functor1Mem function -template<class Arg, class Res, class T> -class Functor1MemConst : public Common::Functor1<Arg, Res> { -public: - typedef Res (T::*FuncType)(Arg) const; - - Functor1MemConst(T *t, const FuncType &func) : _t(t), _func(func) {} - - bool isValid() const { return _func != 0 && _t != 0; } - Res operator()(Arg v1) const { - return (_t->*_func)(v1); - } -private: - mutable T *_t; - const FuncType _func; -}; - -// FIXME move this to existing func.h file -template<class Arg1, class Arg2, class Arg3, class Arg4, class Result> -struct QuaternaryFunction { - typedef Arg1 FirstArgumentType; - typedef Arg2 SecondArgumentType; - typedef Arg3 ThirdArgumentType; - typedef Arg4 FourthArgumentType; - typedef Result ResultType; -}; - -template<class Arg1, class Arg2, class Arg3, class Arg4, class Res> -struct Functor4 : public QuaternaryFunction<Arg1, Arg2, Arg3, Arg4, Res> { - virtual ~Functor4() {} - - virtual bool isValid() const = 0; - virtual Res operator()(Arg1, Arg2, Arg3, Arg4) const = 0; -}; - -template<class Arg1, class Arg2, class Arg3, class Arg4, class Res, class T> -class Functor4Mem : public Functor4<Arg1, Arg2, Arg3, Arg4, Res> { -public: - typedef Res (T::*FuncType)(Arg1, Arg2, Arg3, Arg4); - - Functor4Mem(T *t, const FuncType &func) : _t(t), _func(func) {} - - bool isValid() const { return _func != 0 && _t != 0; } - Res operator()(Arg1 v1, Arg2 v2, Arg3 v3, Arg4 v4) const { - return (_t->*_func)(v1, v2, v3, v4); - } -private: - mutable T *_t; - const FuncType _func; -}; - - } // End of namespace LastExpress #endif // LASTEXPRESS_SHARED_H diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index 44cc68a57b..3d22657124 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -30,11 +30,9 @@ #include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" -#include "common/stream.h" namespace LastExpress { @@ -47,6 +45,8 @@ namespace LastExpress { SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) { _type = kSoundTypeNone; + _currentDataPtr = NULL; + _blockCount = 0; _time = 0; @@ -71,7 +71,13 @@ SoundEntry::~SoundEntry() { // Entries that have been queued will have their streamed disposed automatically if (!_soundStream) SAFE_DELETE(_stream); - delete _soundStream; + + SAFE_DELETE(_soundStream); + + free(_currentDataPtr); + + _subtitle = NULL; + _stream = NULL; // Zero passed pointers _engine = NULL; @@ -110,10 +116,8 @@ void SoundEntry::close() { } void SoundEntry::play() { - if (!_stream) { - warning("[SoundEntry::play] stream has been disposed"); - return; - } + if (!_stream) + error("[SoundEntry::play] stream has been disposed"); // Prepare sound stream if (!_soundStream) @@ -277,7 +281,7 @@ bool SoundEntry::updateSound() { int l = strlen(sub) + 1; if (l - 1 > 4) - sub[l - 1 - 4] = 0; + sub[l - (1 + 4)] = 0; showSubtitle(sub); } } else { @@ -393,6 +397,10 @@ SubtitleEntry::SubtitleEntry(LastExpressEngine *engine) : _engine(engine) { SubtitleEntry::~SubtitleEntry() { SAFE_DELETE(_data); + + // Zero-out passed pointers + _sound = NULL; + _engine = NULL; } void SubtitleEntry::load(Common::String filename, SoundEntry *soundEntry) { @@ -423,6 +431,9 @@ void SubtitleEntry::loadData() { } void SubtitleEntry::setupAndDraw() { + if (!_sound) + error("[SubtitleEntry::setupAndDraw] Sound entry not initialized"); + if (!_data) { _data = new SubtitleManager(_engine->getFont()); _data->load(getArchive(_filename)); diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index 33b4c06793..8904b48930 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -26,6 +26,7 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/entry.h" +#include "lastexpress/sound/sound.h" #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -39,6 +40,7 @@ SoundQueue::SoundQueue(LastExpressEngine *engine) : _engine(engine) { _subtitlesFlag = 0; _currentSubtitle = NULL; + //_soundCacheData = NULL; } SoundQueue::~SoundQueue() { @@ -51,6 +53,7 @@ SoundQueue::~SoundQueue() { _subtitles.clear(); _currentSubtitle = NULL; + //SAFE_DELETE(_soundCacheData); // Zero passed pointers _engine = NULL; @@ -64,6 +67,8 @@ void SoundQueue::handleTimer() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::handleTimer] Invalid entry found in sound queue"); // When the entry has stopped playing, we remove his buffer if (entry->isFinished()) { @@ -120,6 +125,8 @@ void SoundQueue::updateQueue() { for (Common::List<SoundEntry *>::iterator it = _soundList.begin(); it != _soundList.end(); ++it) { SoundEntry *entry = *it; + if (entry == NULL) + error("[SoundQueue::updateQueue] Invalid entry found in sound queue"); // Original removes the entry data from the cache and sets the archive as not loaded // and if the sound data buffer is not full, loads a new entry to be played based on @@ -134,7 +141,7 @@ void SoundQueue::updateQueue() { // Original update the current entry, loading another set of samples to be decoded - getFlags()->flag_3 = 0; + getFlags()->flag_3 = false; --_flag; } @@ -176,6 +183,8 @@ void SoundQueue::clearQueue() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::clearQueue] Invalid entry found in sound queue"); // Delete entry entry->close(); @@ -340,13 +349,14 @@ void SoundQueue::updateSubtitles() { return; } + if (!subtitle) + return; + if (_subtitlesFlag & 1) subtitle->drawOnScreen(); - if (subtitle) { - subtitle->loadData(); - subtitle->setupAndDraw(); - } + subtitle->loadData(); + subtitle->setupAndDraw(); } ////////////////////////////////////////////////////////////////////////// @@ -368,7 +378,15 @@ void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) { (*i)->saveLoadWithSerializer(s); } else { warning("[Sound::saveLoadWithSerializer] Loading not implemented"); - s.skip(numEntries * 64); + + uint32 unusedDataSize = numEntries * 64; + if (s.isLoading()) { + byte *empty = (byte *)malloc(unusedDataSize); + s.syncBytes(empty, unusedDataSize); + free(empty); + } else { + s.skip(unusedDataSize); + } } } diff --git a/engines/lastexpress/sound/queue.h b/engines/lastexpress/sound/queue.h index 75fe06883a..e1f9be1cf7 100644 --- a/engines/lastexpress/sound/queue.h +++ b/engines/lastexpress/sound/queue.h @@ -106,7 +106,7 @@ private: // Entries Common::List<SoundEntry *> _soundList; ///< List of all sound entries - void *_soundCacheData; + //void *_soundCacheData; // Subtitles int _subtitlesFlag; diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp index 2f7bb4a601..319f7cd4f4 100644 --- a/engines/lastexpress/sound/sound.cpp +++ b/engines/lastexpress/sound/sound.cpp @@ -33,7 +33,6 @@ #include "lastexpress/sound/entry.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/helpers.h" #include "lastexpress/graphics.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -675,7 +674,7 @@ const char *SoundManager::getDialogName(EntityIndex entity) const { ////////////////////////////////////////////////////////////////////////// // Letters & Messages ////////////////////////////////////////////////////////////////////////// -void SoundManager::readText(int id){ +void SoundManager::readText(int id) { if (!_queue->isBuffered(kEntityTables4)) return; @@ -1330,23 +1329,23 @@ void SoundManager::playLoopingSound(int param) { } } else { switch (getEntityData(kEntityPlayer)->car) { - case 1: - case 6: + case kCarBaggageRear: + case kCarBaggage: partNumber = 4; break; - case 2: - case 3: - case 4: - case 5: + case kCarKronos: + case kCarGreenSleeping: + case kCarRedSleeping: + case kCarRestaurant: partNumber = 1; break; - case 7: + case kCarCoalTender: partNumber = 5; break; - case 8: + case kCarLocomotive: partNumber = 99; break; - case 9: + case kCar9: partNumber = 3; break; default: @@ -1357,13 +1356,13 @@ void SoundManager::playLoopingSound(int param) { } if (partNumber != 99) - sprintf(tmp, "LOOP%d%c.SND", partNumber, _engine->getRandom().getRandomNumber(numLoops[partNumber] - 1) + 'A'); + sprintf(tmp, "LOOP%d%c.SND", partNumber, (char)(_engine->getRandom().getRandomNumber(numLoops[partNumber] - 1) + 'A')); } if (getFlags()->flag_3) fnameLen = 5; - if (!entry || scumm_strnicmp(entry->getName2().c_str(), tmp, fnameLen)) { + if (!entry || scumm_strnicmp(entry->getName2().c_str(), tmp, (uint)fnameLen)) { _loopingSoundDuration = _engine->getRandom().getRandomNumber(319) + 260; if (partNumber != 99) { diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp index 4d63647af5..0f13d87fbc 100644 --- a/engines/lure/surface.cpp +++ b/engines/lure/surface.cpp @@ -1360,8 +1360,8 @@ bool CopyProtectionDialog::show() { (*tmpHotspot)->copyTo(&screen.screen()); screen.update(); - } else if ((events.event().kbd.keycode >= Common::KEYCODE_0) && - (events.event().kbd.keycode <= Common::KEYCODE_9)) { + } else if ((events.event().kbd.ascii >= '0') && + (events.event().kbd.ascii <= '9')) { HotspotsList::iterator tmpHotspot = _hotspots.begin(); for (int i = 0; i < _charIndex + 3; i++) ++tmpHotspot; diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp index 6c4749f44d..cf450f7e25 100644 --- a/engines/made/pmvplayer.cpp +++ b/engines/made/pmvplayer.cpp @@ -248,7 +248,7 @@ void PmvPlayer::handleEvents() { } void PmvPlayer::updateScreen() { - _vm->_system->copyRectToScreen((const byte*)_surface->pixels, _surface->pitch, + _vm->_system->copyRectToScreen(_surface->pixels, _surface->pitch, (320 - _surface->w) / 2, (200 - _surface->h) / 2, _surface->w, _surface->h); _vm->_system->updateScreen(); } diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index b49bfff840..ea7d57f82d 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -349,7 +349,7 @@ void Screen::updateSprites() { drawSpriteChannels(_backgroundScreenDrawCtx, 3, 0); drawSpriteChannels(_workScreenDrawCtx, 1, 2); - _vm->_system->copyRectToScreen((const byte*)_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); + _vm->_system->copyRectToScreen(_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); _vm->_screen->updateScreenAndWait(10); } @@ -775,10 +775,10 @@ void Screen::unlockScreen() { } void Screen::showWorkScreen() { - _vm->_system->copyRectToScreen((const byte*)_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); + _vm->_system->copyRectToScreen(_workScreen->pixels, _workScreen->pitch, 0, 0, _workScreen->w, _workScreen->h); } -void Screen::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { +void Screen::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { _vm->_system->copyRectToScreen(buf, pitch, x, y, w, h); } diff --git a/engines/made/screen.h b/engines/made/screen.h index a61ecabdce..266ac3811d 100644 --- a/engines/made/screen.h +++ b/engines/made/screen.h @@ -176,7 +176,7 @@ public: Graphics::Surface *lockScreen(); void unlockScreen(); void showWorkScreen(); - void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); void updateScreenAndWait(int delay); int16 addToSpriteList(int16 index, int16 xofs, int16 yofs); diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp index 4e0d463b53..de9231a158 100644 --- a/engines/made/screenfx.cpp +++ b/engines/made/screenfx.cpp @@ -293,7 +293,7 @@ void ScreenEffects::vfx00(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx01(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 312); for (int x = 0; x < 320; x += 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(x, 0), surface->pitch, x, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(x, 0), surface->pitch, x, 0, 8, 200); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -303,7 +303,7 @@ void ScreenEffects::vfx01(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx02(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 312); for (int x = 312; x >= 0; x -= 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(x, 0), surface->pitch, x, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(x, 0), surface->pitch, x, 0, 8, 200); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -313,7 +313,7 @@ void ScreenEffects::vfx02(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx03(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 190); for (int y = 0; y < 200; y += 10) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, y), surface->pitch, 0, y, 320, 10); + _screen->copyRectToScreen(surface->getBasePtr(0, y), surface->pitch, 0, y, 320, 10); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -323,7 +323,7 @@ void ScreenEffects::vfx03(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx04(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 190); for (int y = 190; y >= 0; y -= 10) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, y), surface->pitch, 0, y, 320, 10); + _screen->copyRectToScreen(surface->getBasePtr(0, y), surface->pitch, 0, y, 320, 10); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -333,8 +333,8 @@ void ScreenEffects::vfx04(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx05(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 90); for (int y = 0; y < 100; y += 10) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, y + 100), surface->pitch, 0, y + 100, 320, 10); - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, 90 - y), surface->pitch, 0, 90 - y, 320, 10); + _screen->copyRectToScreen(surface->getBasePtr(0, y + 100), surface->pitch, 0, y + 100, 320, 10); + _screen->copyRectToScreen(surface->getBasePtr(0, 90 - y), surface->pitch, 0, 90 - y, 320, 10); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -345,8 +345,8 @@ void ScreenEffects::vfx05(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx06(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 152); for (int x = 0; x < 160; x += 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(x + 160, 0), surface->pitch, x + 160, 0, 8, 200); - _screen->copyRectToScreen((const byte*)surface->getBasePtr(152 - x, 0), surface->pitch, 152 - x, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(x + 160, 0), surface->pitch, x + 160, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(152 - x, 0), surface->pitch, 152 - x, 0, 8, 200); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -357,8 +357,8 @@ void ScreenEffects::vfx06(Graphics::Surface *surface, byte *palette, byte *newPa void ScreenEffects::vfx07(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { startBlendedPalette(palette, newPalette, colorCount, 152); for (int x = 152; x >= 0; x -= 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(x + 160, 0), surface->pitch, x + 160, 0, 8, 200); - _screen->copyRectToScreen((const byte*)surface->getBasePtr(152 - x, 0), surface->pitch, 152 - x, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(x + 160, 0), surface->pitch, x + 160, 0, 8, 200); + _screen->copyRectToScreen(surface->getBasePtr(152 - x, 0), surface->pitch, 152 - x, 0, 8, 200); stepBlendedPalette(); _screen->updateScreenAndWait(25); } @@ -368,7 +368,7 @@ void ScreenEffects::vfx07(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" right to left void ScreenEffects::vfx08(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int x = 8; x <= 320; x += 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, 0), surface->pitch, 320 - x, 0, x, 200); + _screen->copyRectToScreen(surface->getBasePtr(0, 0), surface->pitch, 320 - x, 0, x, 200); _screen->updateScreenAndWait(25); } setPalette(palette); @@ -509,7 +509,7 @@ void ScreenEffects::vfx17(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" left to right void ScreenEffects::vfx18(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int x = 8; x <= 320; x += 8) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(320 - x, 0), surface->pitch, 0, 0, x, 200); + _screen->copyRectToScreen(surface->getBasePtr(320 - x, 0), surface->pitch, 0, 0, x, 200); _screen->updateScreenAndWait(25); } @@ -519,7 +519,7 @@ void ScreenEffects::vfx18(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" top to bottom void ScreenEffects::vfx19(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int y = 4; y <= 200; y += 4) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, 200 - y), surface->pitch, 0, 0, 320, y); + _screen->copyRectToScreen(surface->getBasePtr(0, 200 - y), surface->pitch, 0, 0, 320, y); _screen->updateScreenAndWait(25); } @@ -529,7 +529,7 @@ void ScreenEffects::vfx19(Graphics::Surface *surface, byte *palette, byte *newPa // "Screen slide in" bottom to top void ScreenEffects::vfx20(Graphics::Surface *surface, byte *palette, byte *newPalette, int colorCount) { for (int y = 4; y <= 200; y += 4) { - _screen->copyRectToScreen((const byte*)surface->getBasePtr(0, 0), surface->pitch, 0, 200 - y, 320, y); + _screen->copyRectToScreen(surface->getBasePtr(0, 0), surface->pitch, 0, 200 - y, 320, y); _screen->updateScreenAndWait(25); } diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp index de7b5b70f9..c57778fb71 100644 --- a/engines/made/scriptfuncs.cpp +++ b/engines/made/scriptfuncs.cpp @@ -574,7 +574,7 @@ int16 ScriptFunctions::sfLoadMouseCursor(int16 argc, int16 *argv) { PictureResource *flex = _vm->_res->getPicture(argv[2]); if (flex) { Graphics::Surface *surf = flex->getPicture(); - CursorMan.replaceCursor((const byte *)surf->pixels, surf->w, surf->h, argv[1], argv[0], 0); + CursorMan.replaceCursor(surf->pixels, surf->w, surf->h, argv[1], argv[0], 0); _vm->_res->freeResource(flex); } return 0; diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 8c72c9875e..e73d4ed6a3 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -121,11 +121,11 @@ void MystCursorManager::setCursor(uint16 id) { // Myst ME stores some cursors as 24bpp images instead of 8bpp if (surface->format.bytesPerPixel == 1) { - CursorMan.replaceCursor((byte *)surface->pixels, surface->w, surface->h, hotspotX, hotspotY, 0); + CursorMan.replaceCursor(surface->pixels, surface->w, surface->h, hotspotX, hotspotY, 0); CursorMan.replaceCursorPalette(mhkSurface->getPalette(), 0, 256); } else { Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - CursorMan.replaceCursor((byte *)surface->pixels, surface->w, surface->h, hotspotX, hotspotY, pixelFormat.RGBToColor(255, 255, 255), 1, &pixelFormat); + CursorMan.replaceCursor(surface->pixels, surface->w, surface->h, hotspotX, hotspotY, pixelFormat.RGBToColor(255, 255, 255), false, &pixelFormat); } _vm->_needsUpdate = true; @@ -157,7 +157,7 @@ void NECursorManager::setCursor(uint16 id) { Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id); if (cursorGroup) { - Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor; + Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor; CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor()); CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256); return; @@ -257,7 +257,7 @@ void PECursorManager::setCursor(uint16 id) { Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id); if (cursorGroup) { - Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor; + Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor; CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor()); CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256); delete cursorGroup; diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index f0c657897d..5664929948 100644 --- a/engines/mohawk/detection.cpp +++ b/engines/mohawk/detection.cpp @@ -167,7 +167,7 @@ public: } virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { - return detectGameFilebased(allFiles, Mohawk::fileBased); + return detectGameFilebased(allFiles, fslist, Mohawk::fileBased); } virtual const char *getName() const { diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 5acc1bb179..55814af1c3 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -204,24 +204,6 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Myst Masterpiece Edition - // English Windows - // From clone2727 - { - { - "myst", - "Masterpiece Edition", - AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) - }, - GType_MYST, - GF_ME, - 0, - }, - - // Myst Masterpiece Edition // German Windows // From DrMcCoy (Included in "Myst: Die Trilogie") { diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index 708478a6d8..a0671d18d5 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -3378,11 +3378,10 @@ void LBLiveTextItem::readData(uint16 type, uint16 size, Common::MemoryReadStream LiveTextWord word; word.bounds = _vm->readRect(stream); word.soundId = stream->readUint16(); - // TODO: unknowns - uint16 unknown1 = stream->readUint16(); - uint16 unknown2 = stream->readUint16(); - debug(4, "Word: (%d, %d) to (%d, %d), sound %d, unknowns %04x, %04x", - word.bounds.left, word.bounds.top, word.bounds.right, word.bounds.bottom, word.soundId, unknown1, unknown2); + word.itemType = stream->readUint16(); + word.itemId = stream->readUint16(); + debug(4, "Word: (%d, %d) to (%d, %d), sound %d, item %d (type %d)", + word.bounds.left, word.bounds.top, word.bounds.right, word.bounds.bottom, word.soundId, word.itemId, word.itemType); _words.push_back(word); } @@ -3461,6 +3460,12 @@ void LBLiveTextItem::update() { uint16 soundId = _words[_currentWord].soundId; if (soundId && !_vm->_sound->isPlaying(soundId)) { paletteUpdate(_currentWord, false); + + // TODO: check this in RE + LBItem *item = _vm->getItemById(_words[_currentWord].itemId); + if (item) + item->togglePlaying(false, true); + _currentWord = 0xFFFF; } } diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index 91d6a8cd30..76da7d8219 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -537,6 +537,9 @@ protected: struct LiveTextWord { Common::Rect bounds; uint16 soundId; + + uint16 itemType; + uint16 itemId; }; struct LiveTextPhrase { diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index c22b30ad4d..9c0e642203 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -98,11 +98,6 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription _view.soundListVolume = NULL; _view.scriptResCount = 0; _view.scriptResources = NULL; - - if ((getFeatures() & GF_ME) && getPlatform() == Common::kPlatformMacintosh) { - const Common::FSNode gameDataDir(ConfMan.get("path")); - SearchMan.addSubDirectoryMatching(gameDataDir, "CD Data"); - } } MohawkEngine_Myst::~MohawkEngine_Myst() { @@ -205,11 +200,6 @@ static const char *mystFiles[] = { // qtw/myst/libelev.mov: libup.mov is basically the same with sound Common::String MohawkEngine_Myst::wrapMovieFilename(const Common::String &movieName, uint16 stack) { - // The Macintosh release of Myst ME stores its videos in a different folder - // WORKAROUND: The gear rotation videos are not in the CD Data folder. See above comments. - if ((getFeatures() & GF_ME) && getPlatform() == Common::kPlatformMacintosh && !movieName.matchString("cl1wg?")) - return Common::String("CD Data/m/") + movieName + ".mov"; - Common::String prefix; switch (stack) { @@ -252,8 +242,7 @@ Common::Error MohawkEngine_Myst::run() { _gfx = new MystGraphics(this); _console = new MystConsole(this); _gameState = new MystGameState(this, _saveFileMan); - _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); - _loadDialog->setSaveMode(false); + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); _optionsDialog = new MystOptionsDialog(this); _cursor = new MystCursorManager(this); _rnd = new Common::RandomSource("myst"); @@ -499,52 +488,32 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS if (!_mhk[0]->openFile(mystFiles[_curStack])) error("Could not open %s", mystFiles[_curStack]); - if (getPlatform() == Common::kPlatformMacintosh) - _gfx->loadExternalPictureFile(_curStack); - _runExitScript = false; // Clear the resource cache and the image cache _cache.clear(); _gfx->clearCache(); - // Play Flyby Entry Movie on Masterpiece Edition. The Macintosh version is currently hooked - // up to the Cinepak versions of the video (the 'c' suffix) until the SVQ1 decoder is completed. + // Play Flyby Entry Movie on Masterpiece Edition. const char *flyby = 0; if (getFeatures() & GF_ME) { switch (_curStack) { case kSeleniticStack: - if (getPlatform() == Common::kPlatformMacintosh) - flyby = "FLY_SEc"; - else - flyby = "selenitic flyby"; + flyby = "selenitic flyby"; break; case kStoneshipStack: - if (getPlatform() == Common::kPlatformMacintosh) - flyby = "FLY_STc"; - else - flyby = "stoneship flyby"; + flyby = "stoneship flyby"; break; // Myst Flyby Movie not used in Original Masterpiece Edition Engine case kMystStack: - if (_tweaksEnabled) { - if (getPlatform() == Common::kPlatformMacintosh) - flyby = "FLY_MYc"; - else - flyby = "myst flyby"; - } + if (_tweaksEnabled) + flyby = "myst flyby"; break; case kMechanicalStack: - if (getPlatform() == Common::kPlatformMacintosh) - flyby = "FLY_MEc"; - else - flyby = "mech age flyby"; + flyby = "mech age flyby"; break; case kChannelwoodStack: - if (getPlatform() == Common::kPlatformMacintosh) - flyby = "FLY_CHc"; - else - flyby = "channelwood flyby"; + flyby = "channelwood flyby"; break; default: break; diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp index 484e49d529..2df0f7e6ba 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -49,8 +49,6 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { if (_pixelFormat.bytesPerPixel == 1) error("Myst requires greater than 256 colors to run"); - _pictureFile.entries = NULL; - // Initialize our buffer _backBuffer = new Graphics::Surface(); _backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat); @@ -61,122 +59,50 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { MystGraphics::~MystGraphics() { delete _bmpDecoder; - delete[] _pictureFile.entries; _backBuffer->free(); delete _backBuffer; } -static const char *s_picFileNames[] = { - "CHpics", - "", - "", - "DUpics", - "INpics", - "", - "MEpics", - "MYpics", - "SEpics", - "", - "", - "STpics" -}; - -void MystGraphics::loadExternalPictureFile(uint16 stack) { - if (_vm->getPlatform() != Common::kPlatformMacintosh) - return; - - if (_pictureFile.picFile.isOpen()) - _pictureFile.picFile.close(); - delete[] _pictureFile.entries; - - if (!scumm_stricmp(s_picFileNames[stack], "")) - return; - - if (!_pictureFile.picFile.open(s_picFileNames[stack])) - error ("Could not open external picture file \'%s\'", s_picFileNames[stack]); - - _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount]; - - for (uint32 i = 0; i < _pictureFile.pictureCount; i++) { - _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE(); +MohawkSurface *MystGraphics::decodeImage(uint16 id) { + // We need to grab the image from the current stack archive, however, we don't know + // if it's a PICT or WDIB resource. If it's Myst ME it's most likely a PICT, and if it's + // original it's definitely a WDIB. However, Myst ME throws us another curve ball in + // that PICT resources can contain WDIB's instead of PICT's. + Common::SeekableReadStream *dataStream = NULL; + + if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { + // The PICT resource exists. However, it could still contain a MystBitmap + // instead of a PICT image... + dataStream = _vm->getResource(ID_PICT, id); + } else { + // No PICT, so the WDIB must exist. Let's go grab it. + dataStream = _vm->getResource(ID_WDIB, id); } -} -MohawkSurface *MystGraphics::decodeImage(uint16 id) { - MohawkSurface *mhkSurface = 0; + bool isPict = false; - // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images, - // though there are a few weird ones that use that format. For further nonsense with images, - // the Macintosh version stores images in external "picture files." We check them before - // going to check for a PICT resource. - if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) { - for (uint32 i = 0; i < _pictureFile.pictureCount; i++) - if (_pictureFile.entries[i].id == id) { - if (_pictureFile.entries[i].type == 0) { - Graphics::JPEGDecoder jpeg; - Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); - - if (!jpeg.loadStream(subStream)) - error("Could not decode Myst ME Mac JPEG"); - - mhkSurface = new MohawkSurface(jpeg.getSurface()->convertTo(_pixelFormat)); - } else if (_pictureFile.entries[i].type == 1) { - Graphics::PICTDecoder pict; - Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); - - if (!pict.loadStream(subStream)) - error("Could not decode Myst ME Mac PICT"); - - mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); - } else - error ("Unknown Picture File type %d", _pictureFile.entries[i].type); - break; - } + if (_vm->getFeatures() & GF_ME) { + // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap + // would be compressed, there's no way to detect for the BM without a hack. + // So, we search for the PICT version opcode for detection. + dataStream->seek(512 + 10); // 512 byte pict header + isPict = (dataStream->readUint32BE() == 0x001102FF); + dataStream->seek(0); } - // We're not using the external Mac files, so it's time to delve into the main Mohawk - // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst - // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However, - // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead - // of PICT's. - if (!mhkSurface) { - bool isPict = false; - Common::SeekableReadStream *dataStream = NULL; - - if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { - // The PICT resource exists. However, it could still contain a MystBitmap - // instead of a PICT image... - dataStream = _vm->getResource(ID_PICT, id); - } else // No PICT, so the WDIB must exist. Let's go grab it. - dataStream = _vm->getResource(ID_WDIB, id); - - if (_vm->getFeatures() & GF_ME) { - // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap - // would be compressed, there's no way to detect for the BM without a hack. - // So, we search for the PICT version opcode for detection. - dataStream->seek(512 + 10); // 512 byte pict header - isPict = (dataStream->readUint32BE() == 0x001102FF); - dataStream->seek(0); - } + MohawkSurface *mhkSurface = 0; - if (isPict) { - Graphics::PICTDecoder pict; + if (isPict) { + Graphics::PICTDecoder pict; - if (!pict.loadStream(*dataStream)) - error("Could not decode Myst ME PICT"); + if (!pict.loadStream(*dataStream)) + error("Could not decode Myst ME PICT"); - mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); - } else { - mhkSurface = _bmpDecoder->decodeImage(dataStream); - mhkSurface->convertToTrueColor(); - } + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); + } else { + mhkSurface = _bmpDecoder->decodeImage(dataStream); + mhkSurface->convertToTrueColor(); } assert(mhkSurface); @@ -222,7 +148,7 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm simulatePreviousDrawDelay(dest); - _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height); + _vm->_system->copyRectToScreen(surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height); } void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) { @@ -280,7 +206,7 @@ void MystGraphics::copyBackBufferToScreen(Common::Rect r) { simulatePreviousDrawDelay(r); - _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height()); + _vm->_system->copyRectToScreen(_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height()); } void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) { diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index 20fd46c5b9..de8fe521e6 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -43,7 +43,6 @@ public: MystGraphics(MohawkEngine_Myst*); ~MystGraphics(); - void loadExternalPictureFile(uint16 stack); void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest); void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest); void copyImageToScreen(uint16 image, Common::Rect dest); @@ -66,20 +65,6 @@ private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; - struct PictureFile { - uint32 pictureCount; - struct PictureEntry { - uint32 offset; - uint32 size; - uint16 id; - uint16 type; - uint16 width; - uint16 height; - } *entries; - - Common::File picFile; - } _pictureFile; - Graphics::Surface *_backBuffer; Graphics::PixelFormat _pixelFormat; Common::Rect _viewport; diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp index 2ced265f02..d103105c2d 100644 --- a/engines/mohawk/myst_stacks/dni.cpp +++ b/engines/mohawk/myst_stacks/dni.cpp @@ -103,13 +103,13 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) { VideoHandle atrus = _vm->_video->findVideoHandle(_video); // Good ending and Atrus asked to give page - if (_globals.ending == 1 && _vm->_video->getElapsedTime(atrus) > (uint)Audio::Timestamp(0, 6801, 600).msecs()) { + if (_globals.ending == 1 && _vm->_video->getTime(atrus) > (uint)Audio::Timestamp(0, 6801, 600).msecs()) { _globals.ending = 2; _globals.heldPage = 0; _vm->setMainCursor(kDefaultMystCursor); // Play movie end (atrus leaving) - _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), Audio::Timestamp(0xFFFFFFFF)); + _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), _vm->_video->getDuration(atrus)); _vm->_video->setVideoLooping(atrus, false); _atrusLeft = true; diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index a5f608dbbf..545b97d956 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -100,12 +100,8 @@ void Intro::introMovies_run() { switch (_introStep) { case 0: - // Play the Mattel (or UbiSoft) logo in the Myst ME Mac version - if ((_vm->getFeatures() & GF_ME) && _vm->getPlatform() == Common::kPlatformMacintosh) { - _vm->_video->playMovie(_vm->wrapMovieFilename("mattel", kIntroStack)); - _introStep = 1; - } else - _introStep = 2; + _introStep = 1; + _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack)); break; case 1: if (!_vm->_video->isVideoPlaying()) @@ -113,10 +109,7 @@ void Intro::introMovies_run() { break; case 2: _introStep = 3; - if ((_vm->getFeatures() & GF_ME) && _vm->getPlatform() == Common::kPlatformMacintosh) - _vm->_video->playMovie(_vm->wrapMovieFilename("presto", kIntroStack)); - else - _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack)); + _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack)); break; case 3: if (!_vm->_video->isVideoPlaying()) @@ -124,21 +117,13 @@ void Intro::introMovies_run() { break; case 4: _introStep = 5; - _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack)); - break; - case 5: - if (!_vm->_video->isVideoPlaying()) - _introStep = 6; - break; - case 6: - _introStep = 7; if (!(_vm->getFeatures() & GF_DEMO)) // The demo doesn't have the intro video _vm->_video->playMovie(_vm->wrapMovieFilename("intro", kIntroStack)); break; - case 7: + case 5: if (!_vm->_video->isVideoPlaying()) - _introStep = 8; + _introStep = 6; break; default: if (_vm->getFeatures() & GF_DEMO) diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 95a8313536..32613c6185 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -646,7 +646,7 @@ Common::String MohawkEngine_Riven::getName(uint16 nameResource, uint16 nameID) { } delete nameStream; - delete [] stringOffsets; + delete[] stringOffsets; return name; } @@ -713,19 +713,11 @@ void MohawkEngine_Riven::delayAndUpdate(uint32 ms) { } void MohawkEngine_Riven::runLoadDialog() { - GUI::SaveLoadChooser slc(_("Load game:"), _("Load")); - slc.setSaveMode(false); + GUI::SaveLoadChooser slc(_("Load game:"), _("Load"), false); - Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int slot = slc.runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = slc.runModalWithCurrentTarget(); if (slot >= 0) loadGameState(slot); - - slc.close(); } Common::Error MohawkEngine_Riven::loadGameState(int slot) { @@ -979,7 +971,7 @@ void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) { return; // Run the opcode if we can at this point - if (force || _video->getElapsedTime(handle) >= _scriptMan->getStoredMovieOpcodeTime()) + if (force || _video->getTime(handle) >= _scriptMan->getStoredMovieOpcodeTime()) _scriptMan->runStoredMovieOpcode(); } diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 8dfc74ebf0..337a57e3e1 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -2059,7 +2059,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) { debug(0, "\tHotspot = %d -> %d", argv[3], hotspotMap[argv[3] - 1]); // Just let the video play while we wait until Gehn opens the trap book for us - while (_vm->_video->getElapsedTime(video) < startTime && !_vm->shouldQuit()) { + while (_vm->_video->getTime(video) < startTime && !_vm->shouldQuit()) { if (_vm->_video->updateMovies()) _vm->_system->updateScreen(); @@ -2084,7 +2084,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) { // OK, Gehn has opened the trap book and has asked us to go in. Let's watch // and see what the player will do... - while (_vm->_video->getElapsedTime(video) < endTime && !_vm->shouldQuit()) { + while (_vm->_video->getTime(video) < endTime && !_vm->shouldQuit()) { bool updateScreen = _vm->_video->updateMovies(); Common::Event event; diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp index 9415e51412..05e66a3924 100644 --- a/engines/mohawk/riven_graphics.cpp +++ b/engines/mohawk/riven_graphics.cpp @@ -115,7 +115,7 @@ void RivenGraphics::updateScreen(Common::Rect updateRect) { // Copy to screen if there's no transition. Otherwise transition. ;) if (_scheduledTransition < 0) - _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); + _vm->_system->copyRectToScreen(_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); else runScheduledTransition(); @@ -255,7 +255,7 @@ void RivenGraphics::runScheduledTransition() { } // For now, just copy the image to screen without doing any transition. - _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->copyRectToScreen(_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); _vm->_system->updateScreen(); _scheduledTransition = -1; // Clear scheduled transition @@ -345,7 +345,7 @@ void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { mhkSurface->convertToTrueColor(); Graphics::Surface *surface = mhkSurface->getSurface(); - _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); + _vm->_system->copyRectToScreen(surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); delete mhkSurface; } @@ -437,7 +437,7 @@ void RivenGraphics::updateCredits() { } // Now flush the new screen - _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->copyRectToScreen(_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); _vm->_system->updateScreen(); } } diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 80fa4bf9a0..0ed4f38b53 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -29,6 +29,7 @@ #include "common/textconsole.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/qt_decoder.h" @@ -43,13 +44,12 @@ void VideoEntry::clear() { loop = false; enabled = false; start = Audio::Timestamp(0, 1); - end = Audio::Timestamp(0xFFFFFFFF, 1); // Largest possible, there is an endOfVideo() check anyway filename.clear(); id = -1; } bool VideoEntry::endOfVideo() { - return !video || video->endOfVideo() || video->getElapsedTime() >= (uint)end.msecs(); + return !video || video->endOfVideo(); } VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { @@ -207,7 +207,7 @@ bool VideoManager::updateMovies() { // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { - _videoStreams[i]->seekToTime(_videoStreams[i].start); + _videoStreams[i]->seek(_videoStreams[i].start); } else { // Check the video time one last time before deleting it _vm->doVideoTimer(i, true); @@ -227,23 +227,25 @@ bool VideoManager::updateMovies() { Graphics::Surface *convertedFrame = 0; if (frame && _videoStreams[i].enabled) { - // Convert from 8bpp to the current screen format if necessary Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); - if (frame->format.bytesPerPixel == 1) { - if (pixelFormat.bytesPerPixel == 1) { - if (_videoStreams[i]->hasDirtyPalette()) - _videoStreams[i]->setSystemPalette(); - } else { - convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette()); - frame = convertedFrame; - } + if (frame->format != pixelFormat) { + // We don't support downconverting to 8bpp + if (pixelFormat.bytesPerPixel == 1) + error("Cannot convert high color video frame to 8bpp"); + + // Convert to the current screen format + convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette()); + frame = convertedFrame; + } else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) { + // Set the palette when running in 8bpp mode only + _vm->_system->getPaletteManager()->setPalette(_videoStreams[i]->getPalette(), 0, 256); } // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); - _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); + _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; @@ -315,7 +317,7 @@ VideoHandle VideoManager::playMovieRiven(uint16 id) { for (uint16 i = 0; i < _mlstRecords.size(); i++) if (_mlstRecords[i].code == id) { debug(1, "Play tMOV %d (non-blocking) at (%d, %d) %s", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0 ? "looping" : "non-looping"); - return createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0); + return createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0, _mlstRecords[i].volume); } return NULL_VID_HANDLE; @@ -371,7 +373,7 @@ void VideoManager::disableAllMovies() { _videoStreams[i].enabled = false; } -VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop) { +VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop, byte volume) { // First, check to see if that video is already playing for (uint32 i = 0; i < _videoStreams.size(); i++) if (_videoStreams[i].id == id) @@ -381,6 +383,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool Video::QuickTimeDecoder *decoder = new Video::QuickTimeDecoder(); decoder->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id)); decoder->loadStream(_vm->getResource(ID_TMOV, id)); + decoder->setVolume(volume); VideoEntry entry; entry.clear(); @@ -391,6 +394,8 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool entry.loop = loop; entry.enabled = true; + entry->start(); + // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) if (!_videoStreams[i].video) { @@ -403,7 +408,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool return _videoStreams.size() - 1; } -VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop) { +VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop, byte volume) { // First, check to see if that video is already playing for (uint32 i = 0; i < _videoStreams.size(); i++) if (_videoStreams[i].filename == filename) @@ -426,6 +431,8 @@ VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint } entry->loadStream(file); + entry->setVolume(volume); + entry->start(); // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) @@ -481,14 +488,14 @@ uint32 VideoManager::getFrameCount(VideoHandle handle) { return _videoStreams[handle]->getFrameCount(); } -uint32 VideoManager::getElapsedTime(VideoHandle handle) { +uint32 VideoManager::getTime(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); - return _videoStreams[handle]->getElapsedTime(); + return _videoStreams[handle]->getTime(); } uint32 VideoManager::getDuration(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); - return _videoStreams[handle]->getDuration(); + return _videoStreams[handle]->getDuration().msecs(); } bool VideoManager::endOfVideo(VideoHandle handle) { @@ -507,14 +514,13 @@ bool VideoManager::isVideoPlaying() { void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle].start = start; - _videoStreams[handle].end = end; - _videoStreams[handle]->seekToTime(start); + _videoStreams[handle]->setEndTime(end); + _videoStreams[handle]->seek(start); } void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); updateMovies(); delete _videoStreams[handle].video; _videoStreams[handle].clear(); @@ -522,7 +528,7 @@ void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); } void VideoManager::setVideoLooping(VideoHandle handle, bool loop) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 34c287497f..9dddcde09b 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -45,19 +45,19 @@ struct MLSTRecord { struct VideoEntry { // Playback variables - Video::SeekableVideoDecoder *video; + Video::VideoDecoder *video; uint16 x; uint16 y; bool loop; bool enabled; - Audio::Timestamp start, end; + Audio::Timestamp start; // Identification Common::String filename; // External video files int id; // Internal Mohawk files // Helper functions - Video::SeekableVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually + Video::VideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually void clear(); bool endOfVideo(); }; @@ -100,7 +100,7 @@ public: VideoHandle findVideoHandle(const Common::String &filename); int32 getCurFrame(VideoHandle handle); uint32 getFrameCount(VideoHandle handle); - uint32 getElapsedTime(VideoHandle handle); + uint32 getTime(VideoHandle handle); uint32 getDuration(VideoHandle videoHandle); bool endOfVideo(VideoHandle handle); void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end); @@ -120,8 +120,8 @@ private: // Keep tabs on any videos playing Common::Array<VideoEntry> _videoStreams; - VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop); - VideoHandle createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop); + VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop, byte volume = 0xff); + VideoHandle createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop, byte volume = 0xff); }; } // End of namespace Mohawk diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 5e39c893db..ee981a2c7d 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -617,7 +617,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) { } } - delete []shadow; + delete[] shadow; delete stream; } diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 839b2c6834..8d4afd6847 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -832,7 +832,7 @@ void AmigaDisk_ns::decodeCnv(byte *data, uint16 numFrames, uint16 width, uint16 assert(buf); stream->read(buf, rawsize); unpackBitmap(data, buf, numFrames, bytesPerPlane, height); - delete []buf; + delete[] buf; } #undef NUM_PLANES diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 6868505c52..9855830478 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -766,7 +766,7 @@ Gfx::~Gfx() { freeLabels(); - delete []_unpackedBitmap; + delete[] _unpackedBitmap; return; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index b43dd193b5..f8cb4b3647 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -144,7 +144,7 @@ public: ~Cnv() { if (_freeData) - delete []_data; + delete[] _data; } byte* getFramePtr(uint16 index) { diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 3ab25f203f..8de2d89b18 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -180,20 +180,13 @@ void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) { } int SaveLoad::selectSaveFile(Common::String &selectedName, bool saveMode, const Common::String &caption, const Common::String &button) { - GUI::SaveLoadChooser slc(caption, button); - slc.setSaveMode(saveMode); + GUI::SaveLoadChooser slc(caption, button, saveMode); selectedName.clear(); - Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int idx = slc.runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int idx = slc.runModalWithCurrentTarget(); if (idx >= 0) { selectedName = slc.getResultString(); - slc.close(); } return idx; diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp index 3cc25b36b0..dcc71e4f2f 100644 --- a/engines/parallaction/sound_ns.cpp +++ b/engines/parallaction/sound_ns.cpp @@ -237,7 +237,7 @@ AmigaSoundMan_ns::~AmigaSoundMan_ns() { stopSfx(2); stopSfx(3); - delete []beepSoundBuffer; + delete[] beepSoundBuffer; } Audio::AudioStream *AmigaSoundMan_ns::loadChannelData(const char *filename, Channel *ch, bool looping) { diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index 3acc87b856..f3b183c84f 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -56,8 +56,8 @@ static const PlainGameDescriptor queenGameDescriptor = { }; static const ExtraGuiOption queenExtraGuiOption = { - _s("Floppy intro"), - _s("Use the floppy version's intro (CD version only)"), + _s("Alternative intro"), + _s("Use an alternative game intro (CD version only)"), "alt_intro", false }; diff --git a/engines/saga/actor_path.cpp b/engines/saga/actor_path.cpp index 0fb072b201..d0f1cf2b5b 100644 --- a/engines/saga/actor_path.cpp +++ b/engines/saga/actor_path.cpp @@ -23,6 +23,7 @@ #include "saga/saga.h" #include "saga/actor.h" +#include "saga/objectmap.h" #include "saga/scene.h" namespace Saga { @@ -99,6 +100,47 @@ void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point _debugPointsCount = 0; #endif + // WORKAROUND for bug #3360396. Path finding in IHNM is a bit buggy + // compared to the original, which occasionally leads to the player + // leaving the room instead of interacting with an object. So far, no + // one has figured out how to fix this properly. As a temporary [*] + // solution, we try to fix this on a case-by-case basis. + // + // The workaround is to assume that the player wants to stay in the + // room, unless he or she explicitly clicked on an exit zone. + // + // [*] And there is nothing more permanent than a temporary solution... + + bool pathFindingWorkaround = false; + + if (_vm->getGameId() == GID_IHNM) { + int chapter = _vm->_scene->currentChapterNumber(); + int scene = _vm->_scene->currentSceneNumber(); + + // Ellen, in the room with the monitors. + if (chapter == 3 && scene == 54) + pathFindingWorkaround = true; + + // Nimdok in the recovery room + if (chapter == 4 && scene == 71) + pathFindingWorkaround = true; + } + + int hitZoneIndex; + const HitZone *hitZone; + bool restrictToRoom = false; + + if (pathFindingWorkaround) { + restrictToRoom = true; + hitZoneIndex = _vm->_scene->_actionMap->hitTest(toPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + if (hitZone->getFlags() & kHitZoneExit) { + restrictToRoom = false; + } + } + } + actor->_walkStepsCount = 0; if (fromPoint == toPoint) { actor->addWalkStepPoint(toPoint); @@ -110,6 +152,15 @@ void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point if (_vm->_scene->validBGMaskPoint(iteratorPoint)) { maskType = _vm->_scene->getBGMaskType(iteratorPoint); setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty); + if (restrictToRoom) { + hitZoneIndex = _vm->_scene->_actionMap->hitTest(iteratorPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + if (hitZone->getFlags() & kHitZoneExit) { + setPathCell(iteratorPoint, kPathCellBarrier); + } + } + } } else { setPathCell(iteratorPoint, kPathCellBarrier); } diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index d39ec34cc8..9c178559f2 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -252,9 +252,6 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s debug(0, "Save is for: %s", title); } - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - if (version >= 6) { Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp index 364c4cf306..6015e6757a 100644 --- a/engines/saga/introproc_ihnm.cpp +++ b/engines/saga/introproc_ihnm.cpp @@ -212,7 +212,7 @@ bool Scene::playTitle(int title, int time, int mode) { break; case 2: // display background - _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); phase++; startTime = curTime; @@ -247,7 +247,7 @@ bool Scene::playTitle(int title, int time, int mode) { frameTime = curTime; - _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); } @@ -274,7 +274,7 @@ bool Scene::playTitle(int title, int time, int mode) { _vm->_anim->endVideo(); memset((byte *)backBufferSurface->pixels, 0, backBufferSurface->w * backBufferSurface->h); - _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + _vm->_system->copyRectToScreen(backBufferSurface->pixels, backBufferSurface->w, 0, 0, backBufferSurface->w, backBufferSurface->h); return interrupted; diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 9248f2b530..484ebe1779 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -126,21 +126,25 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue textEntry.text = dialogue[i].i_str; entry = _vm->_scene->_textList.addEntry(textEntry); - // Display text - event.type = kEvTOneshot; - event.code = kTextEvent; - event.op = kEventDisplay; - event.data = entry; - event.time = (i == 0) ? 0 : VOICE_PAD; - eventColumns = _vm->_events->chain(eventColumns, event); + if (_vm->_subtitlesEnabled) { + // Display text + event.type = kEvTOneshot; + event.code = kTextEvent; + event.op = kEventDisplay; + event.data = entry; + event.time = (i == 0) ? 0 : VOICE_PAD; + eventColumns = _vm->_events->chain(eventColumns, event); + } - // Play voice - event.type = kEvTOneshot; - event.code = kVoiceEvent; - event.op = kEventPlay; - event.param = dialogue[i].i_voice_rn; - event.time = 0; - _vm->_events->chain(eventColumns, event); + if (_vm->_voicesEnabled) { + // Play voice + event.type = kEvTOneshot; + event.code = kVoiceEvent; + event.op = kEventPlay; + event.param = dialogue[i].i_voice_rn; + event.time = 0; + _vm->_events->chain(eventColumns, event); + } voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn); if (voice_len < 0) { diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index bdf8936a55..260eca98e6 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -32,6 +32,7 @@ #include "common/keyboard.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/smk_decoder.h" @@ -92,7 +93,7 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) { } void Scene::playMovie(const char *filename) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(_vm->_mixer); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); if (!smkDecoder->loadFile(filename)) return; @@ -101,14 +102,16 @@ void Scene::playMovie(const char *filename) { uint16 y = (g_system->getHeight() - smkDecoder->getHeight()) / 2; bool skipVideo = false; + smkDecoder->start(); + while (!_vm->shouldQuit() && !smkDecoder->endOfVideo() && !skipVideo) { if (smkDecoder->needsUpdate()) { const Graphics::Surface *frame = smkDecoder->decodeNextFrame(); if (frame) { - _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (smkDecoder->hasDirtyPalette()) - smkDecoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(smkDecoder->getPalette(), 0, 256); _vm->_system->updateScreen(); } diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 5efc8d1f67..69c27b6a6b 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -519,9 +519,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by if (maxLPC > 0) free(lpc); - if (size > 0) - free(unpackedBuffer); - delete gReader; return unpackedBuffer; } diff --git a/engines/savestate.h b/engines/savestate.h index 6cbdb22edf..c233554657 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -40,6 +40,8 @@ struct Surface; * * Further possibilites are a thumbnail, play time, creation date, * creation time, delete protected, write protection. + * + * Saves are writable and deletable by default. */ class SaveStateDescriptor { public: diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 9607a8e66d..1889d53480 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -53,6 +53,7 @@ #include "video/avi_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/frameout.h" #include "video/coktel_decoder.h" #include "sci/video/robot_decoder.h" #endif @@ -131,6 +132,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), DCmd_Register("al", WRAP_METHOD(Console, cmdAnimateList)); // alias DCmd_Register("window_list", WRAP_METHOD(Console, cmdWindowList)); DCmd_Register("wl", WRAP_METHOD(Console, cmdWindowList)); // alias + DCmd_Register("plane_list", WRAP_METHOD(Console, cmdPlaneList)); + DCmd_Register("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias + DCmd_Register("plane_items", WRAP_METHOD(Console, cmdPlaneItemList)); + DCmd_Register("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias DCmd_Register("saved_bits", WRAP_METHOD(Console, cmdSavedBits)); DCmd_Register("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits)); // Segments @@ -245,20 +250,18 @@ void Console::postEnter() { #endif if (_videoFile.hasSuffix(".seq")) { - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(_videoFrameDelay); - videoDecoder = seqDecoder; + videoDecoder = new SEQDecoder(_videoFrameDelay); #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); } else if (_videoFile.hasSuffix(".rbt")) { - videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); + videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { duckMode = true; - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); #endif } else if (_videoFile.hasSuffix(".avi")) { - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); } else { warning("Unrecognized video type"); } @@ -365,7 +368,10 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" pic_visualize - Enables visualization of the drawing process of EGA pictures\n"); DebugPrintf(" undither - Enable/disable undithering\n"); DebugPrintf(" play_video - Plays a SEQ, AVI, VMD, RBT or DUK video\n"); - DebugPrintf(" animate_object_list / al - Shows the current list of objects in kAnimate's draw list\n"); + DebugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n"); + DebugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n"); DebugPrintf(" saved_bits - List saved bits on the hunk\n"); DebugPrintf(" show_saved_bits - Display saved bits\n"); DebugPrintf("\n"); @@ -1209,12 +1215,33 @@ bool Console::cmdRestartGame(int argc, const char **argv) { return Cmd_Exit(0, 0); } +// The scripts get IDs ranging from 100->199, because the scripts require us to assign unique ids THAT EVEN STAY BETWEEN +// SAVES and the scripts also use "saves-count + 1" to create a new savedgame slot. +// SCI1.1 actually recycles ids, in that case we will currently get "0". +// This behavior is required especially for LSL6. In this game, it's possible to quick save. The scripts will use +// the last-used id for that feature. If we don't assign sticky ids, the feature will overwrite different saves all the +// time. And sadly we can't just use the actual filename ids directly, because of the creation method for new slots. + +extern void listSavegames(Common::Array<SavegameDesc> &saves); + +bool Console::cmdListSaves(int argc, const char **argv) { + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + for (uint i = 0; i < saves.size(); i++) { + Common::String filename = g_sci->getSavegameName(saves[i].id); + DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name); + } + + return true; +} + bool Console::cmdClassTable(int argc, const char **argv) { DebugPrintf("Available classes (parse a parameter to filter the table by a specific class):\n"); for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) { Class temp = _engine->_gamestate->_segMan->_classTable[i]; - if (temp.reg.segment) { + if (temp.reg.getSegment()) { const char *className = _engine->_gamestate->_segMan->getObjectName(temp.reg); if (argc == 1 || (argc == 2 && !strcmp(className, argv[1]))) { DebugPrintf(" Class 0x%x (%s) at %04x:%04x (script %d)\n", i, @@ -1589,6 +1616,8 @@ bool Console::cmdAnimateList(int argc, const char **argv) { if (_engine->_gfxAnimate) { DebugPrintf("Animate list:\n"); _engine->_gfxAnimate->printAnimateList(this); + } else { + DebugPrintf("This SCI version does not have an animate list\n"); } return true; } @@ -1597,9 +1626,52 @@ bool Console::cmdWindowList(int argc, const char **argv) { if (_engine->_gfxPorts) { DebugPrintf("Window list:\n"); _engine->_gfxPorts->printWindowList(this); + } else { + DebugPrintf("This SCI version does not have a list of ports\n"); } return true; +} + +bool Console::cmdPlaneList(int argc, const char **argv) { +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane list:\n"); + _engine->_gfxFrameout->printPlaneList(this); + } else { + DebugPrintf("This SCI version does not have a list of planes\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} +bool Console::cmdPlaneItemList(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Shows the list of items for a plane\n"); + DebugPrintf("Usage: %s <plane address>\n", argv[0]); + return true; + } + + reg_t planeObject = NULL_REG; + + if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) { + DebugPrintf("Invalid address passed.\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane item list:\n"); + _engine->_gfxFrameout->printPlaneItemList(this, planeObject); + } else { + DebugPrintf("This SCI version does not have a list of plane items\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; } bool Console::cmdSavedBits(int argc, const char **argv) { @@ -1614,7 +1686,7 @@ bool Console::cmdSavedBits(int argc, const char **argv) { Common::Array<reg_t> entries = hunks->listAllDeallocatable(id); for (uint i = 0; i < entries.size(); ++i) { - uint16 offset = entries[i].offset; + uint16 offset = entries[i].getOffset(); const Hunk& h = hunks->_table[offset]; if (strcmp(h.type, "SaveBits()") == 0) { byte* memoryPtr = (byte *)h.mem; @@ -1677,12 +1749,12 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) { return true; } - if (memoryHandle.segment != id || !hunks->isValidOffset(memoryHandle.offset)) { + if (memoryHandle.getSegment() != id || !hunks->isValidOffset(memoryHandle.getOffset())) { DebugPrintf("Invalid address.\n"); return true; } - const Hunk& h = hunks->_table[memoryHandle.offset]; + const Hunk& h = hunks->_table[memoryHandle.getOffset()]; if (strcmp(h.type, "SaveBits()") != 0) { DebugPrintf("Invalid address.\n"); @@ -2192,16 +2264,16 @@ bool Console::cmdGCShowReachable(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return 1; } DebugPrintf("Reachable from %04x:%04x:\n", PRINT_REG(addr)); const Common::Array<reg_t> tmp = mobj->listAllOutgoingReferences(addr); for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - if (it->segment) + if (it->getSegment()) g_sci->getSciDebugger()->DebugPrintf(" %04x:%04x\n", PRINT_REG(*it)); return true; @@ -2224,16 +2296,16 @@ bool Console::cmdGCShowFreeable(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return true; } - DebugPrintf("Freeable in segment %04x:\n", addr.segment); - const Common::Array<reg_t> tmp = mobj->listAllDeallocatable(addr.segment); + DebugPrintf("Freeable in segment %04x:\n", addr.getSegment()); + const Common::Array<reg_t> tmp = mobj->listAllDeallocatable(addr.getSegment()); for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - if (it->segment) + if (it->getSegment()) g_sci->getSciDebugger()->DebugPrintf(" %04x:%04x\n", PRINT_REG(*it)); return true; @@ -2257,9 +2329,9 @@ bool Console::cmdGCNormalize(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return true; } @@ -2498,12 +2570,12 @@ bool Console::cmdViewReference(int argc, const char **argv) { DebugPrintf("%04x:%04x is of type 0x%x: ", PRINT_REG(reg), type_mask); - if (reg.segment == 0 && reg.offset == 0) { + if (reg.getSegment() == 0 && reg.getOffset() == 0) { DebugPrintf("Null.\n"); return true; } - if (reg_end.segment != reg.segment && reg_end != NULL_REG) { + if (reg_end.getSegment() != reg.getSegment() && reg_end != NULL_REG) { DebugPrintf("Ending segment different from starting segment. Assuming no bound on dump.\n"); reg_end = NULL_REG; } @@ -2539,7 +2611,7 @@ bool Console::cmdViewReference(int argc, const char **argv) { printObject(reg); break; case SIG_TYPE_REFERENCE: { - switch (_engine->_gamestate->_segMan->getSegmentType(reg.segment)) { + switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) { #ifdef ENABLE_SCI32 case SEG_TYPE_STRING: { DebugPrintf("SCI32 string\n"); @@ -2555,21 +2627,20 @@ bool Console::cmdViewReference(int argc, const char **argv) { } #endif default: { - int size; const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg); - size = block.maxSize; + uint16 size = block.maxSize; DebugPrintf("raw data\n"); - if (reg_end.segment != 0 && size < reg_end.offset - reg.offset) { + if (reg_end.getSegment() != 0 && (size < reg_end.getOffset() - reg.getOffset())) { DebugPrintf("Block end out of bounds (size %d). Resetting.\n", size); reg_end = NULL_REG; } - if (reg_end.segment != 0 && (size >= reg_end.offset - reg.offset)) - size = reg_end.offset - reg.offset; + if (reg_end.getSegment() != 0 && (size >= reg_end.getOffset() - reg.getOffset())) + size = reg_end.getOffset() - reg.getOffset(); - if (reg_end.segment != 0) + if (reg_end.getSegment() != 0) DebugPrintf("Block size less than or equal to %d\n", size); if (block.isRaw) @@ -2581,7 +2652,7 @@ bool Console::cmdViewReference(int argc, const char **argv) { break; } case SIG_TYPE_INTEGER: - DebugPrintf("arithmetic value\n %d (%04x)\n", (int16) reg.offset, reg.offset); + DebugPrintf("arithmetic value\n %d (%04x)\n", (int16) reg.getOffset(), reg.getOffset()); break; default: DebugPrintf("unknown type %d.\n", type); @@ -2651,7 +2722,7 @@ bool Console::cmdBacktrace(int argc, const char **argv) { switch (call.type) { case EXEC_STACK_TYPE_CALL: // Normal function if (call.type == EXEC_STACK_TYPE_CALL) - DebugPrintf(" %x: script %d - ", i, (*(Script *)_engine->_gamestate->_segMan->_heap[call.addr.pc.segment]).getScriptNumber()); + DebugPrintf(" %x: script %d - ", i, (*(Script *)_engine->_gamestate->_segMan->_heap[call.addr.pc.getSegment()]).getScriptNumber()); if (call.debugSelector != -1) { DebugPrintf("%s::%s(", objname, _engine->getKernel()->getSelectorName(call.debugSelector).c_str()); } else if (call.debugExportId != -1) { @@ -2840,10 +2911,11 @@ bool Console::cmdDisassemble(int argc, const char **argv) { if (jumpTarget > farthestTarget) farthestTarget = jumpTarget; } - addr = disassemble(_engine->_gamestate, addr, printBWTag, printBytecode); + // TODO: Use a true 32-bit reg_t for the position (addr) + addr = disassemble(_engine->_gamestate, make_reg32(addr.getSegment(), addr.getOffset()), printBWTag, printBytecode); if (addr.isNull() && prevAddr < farthestTarget) addr = prevAddr + 1; // skip past the ret - } while (addr.offset > 0); + } while (addr.getOffset() > 0); return true; } @@ -2860,10 +2932,10 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } reg_t vpc = NULL_REG; - int opCount = 1; + uint opCount = 1; bool printBWTag = false; bool printBytes = false; - int size; + uint16 size; if (parse_reg_t(_engine->_gamestate, argv[1], &vpc, false)) { DebugPrintf("Invalid address passed.\n"); @@ -2872,7 +2944,7 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } SegmentRef ref = _engine->_gamestate->_segMan->dereference(vpc); - size = ref.maxSize + vpc.offset; // total segment size + size = ref.maxSize + vpc.getOffset(); // total segment size for (int i = 2; i < argc; i++) { if (!scumm_stricmp(argv[i], "bwt")) @@ -2887,14 +2959,10 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } } - if (opCount < 0) { - DebugPrintf("Invalid op_count\n"); - return true; - } - do { - vpc = disassemble(_engine->_gamestate, vpc, printBWTag, printBytes); - } while ((vpc.offset > 0) && (vpc.offset + 6 < size) && (--opCount)); + // TODO: Use a true 32-bit reg_t for the position (vpc) + vpc = disassemble(_engine->_gamestate, make_reg32(vpc.getSegment(), vpc.getOffset()), printBWTag, printBytes); + } while ((vpc.getOffset() > 0) && (vpc.getOffset() + 6 < size) && (--opCount)); return true; } @@ -2917,8 +2985,9 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // Ignore specific leftover scripts, which require other non-existing scripts if ((_engine->getGameId() == GID_HOYLE3 && itr->getNumber() == 995) || (_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) || - (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947) || - (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980)) { + (_engine->getGameId() == GID_KQ7 && itr->getNumber() == 111) || + (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980) || + (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947)) { continue; } @@ -2937,7 +3006,7 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // Now dissassemble each method of the script object for (uint16 i = 0; i < obj->getMethodCount(); i++) { reg_t fptr = obj->getFunction(i); - uint16 offset = fptr.offset; + uint16 offset = fptr.getOffset(); int16 opparams[4]; byte extOpcode; byte opcode; @@ -3584,10 +3653,14 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV relativeOffset = true; if (!scumm_strnicmp(str + 1, "PC", 2)) { - *dest = s->_executionStack.back().addr.pc; + // TODO: Handle 32-bit PC addresses + reg32_t pc = s->_executionStack.back().addr.pc; + *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset()); offsetStr = str + 3; } else if (!scumm_strnicmp(str + 1, "P", 1)) { - *dest = s->_executionStack.back().addr.pc; + // TODO: Handle 32-bit PC addresses + reg32_t pc = s->_executionStack.back().addr.pc; + *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset()); offsetStr = str + 2; } else if (!scumm_strnicmp(str + 1, "PREV", 4)) { *dest = s->r_prev; @@ -3625,8 +3698,8 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV return 1; // Now lookup the script's segment - dest->segment = s->_segMan->getScriptSegment(script_nr); - if (!dest->segment) { + dest->setSegment(s->_segMan->getScriptSegment(script_nr)); + if (!dest->getSegment()) { return 1; } @@ -3708,19 +3781,19 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV offsetStr = colon + 1; Common::String segmentStr(str, colon); - dest->segment = strtol(segmentStr.c_str(), &endptr, 16); + dest->setSegment(strtol(segmentStr.c_str(), &endptr, 16)); if (*endptr) return 1; } else { int val = 0; - dest->segment = 0; + dest->setSegment(0); if (charsCountNumber == charsCount) { // Only numbers in input, assume decimal value val = strtol(str, &endptr, 10); if (*endptr) return 1; // strtol failed? - dest->offset = val; + dest->setOffset(val); return 0; } else { // We also got letters, check if there were only hexadecimal letters and '0x' at the start or 'h' at the end @@ -3728,7 +3801,7 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV val = strtol(str, &endptr, 16); if ((*endptr != 'h') && (*endptr != 0)) return 1; - dest->offset = val; + dest->setOffset(val); return 0; } else { // Something else was in input, assume object name @@ -3777,9 +3850,9 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV int val = strtol(offsetStr, &endptr, 16); if (relativeOffset) - dest->offset += val; + dest->incOffset(val); else - dest->offset = val; + dest->setOffset(val); if (*endptr) return 1; @@ -3859,15 +3932,15 @@ void Console::printList(List *list) { while (!pos.isNull()) { Node *node; - NodeTable *nt = (NodeTable *)_engine->_gamestate->_segMan->getSegment(pos.segment, SEG_TYPE_NODES); + NodeTable *nt = (NodeTable *)_engine->_gamestate->_segMan->getSegment(pos.getSegment(), SEG_TYPE_NODES); - if (!nt || !nt->isValidEntry(pos.offset)) { + if (!nt || !nt->isValidEntry(pos.getOffset())) { DebugPrintf(" WARNING: %04x:%04x: Doesn't contain list node!\n", PRINT_REG(pos)); return; } - node = &(nt->_table[pos.offset]); + node = &(nt->_table[pos.getOffset()]); DebugPrintf("\t%04x:%04x : %04x:%04x -> %04x:%04x\n", PRINT_REG(pos), PRINT_REG(node->key), PRINT_REG(node->value)); @@ -3886,37 +3959,37 @@ void Console::printList(List *list) { } int Console::printNode(reg_t addr) { - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegment(addr.segment, SEG_TYPE_LISTS); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegment(addr.getSegment(), SEG_TYPE_LISTS); if (mobj) { ListTable *lt = (ListTable *)mobj; List *list; - if (!lt->isValidEntry(addr.offset)) { + if (!lt->isValidEntry(addr.getOffset())) { DebugPrintf("Address does not contain a list\n"); return 1; } - list = &(lt->_table[addr.offset]); + list = &(lt->_table[addr.getOffset()]); DebugPrintf("%04x:%04x : first x last = (%04x:%04x, %04x:%04x)\n", PRINT_REG(addr), PRINT_REG(list->first), PRINT_REG(list->last)); } else { NodeTable *nt; Node *node; - mobj = _engine->_gamestate->_segMan->getSegment(addr.segment, SEG_TYPE_NODES); + mobj = _engine->_gamestate->_segMan->getSegment(addr.getSegment(), SEG_TYPE_NODES); if (!mobj) { - DebugPrintf("Segment #%04x is not a list or node segment\n", addr.segment); + DebugPrintf("Segment #%04x is not a list or node segment\n", addr.getSegment()); return 1; } nt = (NodeTable *)mobj; - if (!nt->isValidEntry(addr.offset)) { + if (!nt->isValidEntry(addr.getOffset())) { DebugPrintf("Address does not contain a node\n"); return 1; } - node = &(nt->_table[addr.offset]); + node = &(nt->_table[addr.getOffset()]); DebugPrintf("%04x:%04x : prev x next = (%04x:%04x, %04x:%04x); maps %04x:%04x -> %04x:%04x\n", PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(node->succ), PRINT_REG(node->key), PRINT_REG(node->value)); @@ -3954,8 +4027,8 @@ int Console::printObject(reg_t pos) { reg_t val = obj->getVariable(i); DebugPrintf("%04x:%04x", PRINT_REG(val)); - if (!val.segment) - DebugPrintf(" (%d)", val.offset); + if (!val.getSegment()) + DebugPrintf(" (%d)", val.getOffset()); const Object *ref = s->_segMan->getObject(val); if (ref) @@ -3968,8 +4041,8 @@ int Console::printObject(reg_t pos) { reg_t fptr = obj->getFunction(i); DebugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), _engine->getKernel()->getSelectorName(obj->getFuncSelector(i)).c_str(), PRINT_REG(fptr)); } - if (s->_segMan->_heap[pos.segment]->getType() == SEG_TYPE_SCRIPT) - DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.segment)->getScriptNumber()); + if (s->_segMan->_heap[pos.getSegment()]->getType() == SEG_TYPE_SCRIPT) + DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.getSegment())->getScriptNumber()); return 0; } diff --git a/engines/sci/console.h b/engines/sci/console.h index d943923ba1..1c54748842 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -33,7 +33,7 @@ namespace Sci { class SciEngine; struct List; -reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode); +reg_t disassemble(EngineState *s, reg32_t pos, bool printBWTag, bool printBytecode); bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpOffset); class Console : public GUI::Debugger { @@ -94,6 +94,8 @@ private: bool cmdPlayVideo(int argc, const char **argv); bool cmdAnimateList(int argc, const char **argv); bool cmdWindowList(int argc, const char **argv); + bool cmdPlaneList(int argc, const char **argv); + bool cmdPlaneItemList(int argc, const char **argv); bool cmdSavedBits(int argc, const char **argv); bool cmdShowSavedBits(int argc, const char **argv); // Segments diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 78df3065b2..58ac5f1fa6 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -397,8 +397,8 @@ static const ADExtraGuiOptionsMap optionsList[] = { { GAMEOPTION_FB01_MIDI, { - _s("Use IMF/Yahama FB-01 for MIDI output"), - _s("Use an IBM Music Feature card or a Yahama FB-01 FM synth module for MIDI output"), + _s("Use IMF/Yamaha FB-01 for MIDI output"), + _s("Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI output"), "native_fb01", false } @@ -762,9 +762,6 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - int day = (meta.saveDate >> 24) & 0xFF; int month = (meta.saveDate >> 16) & 0xFF; int year = meta.saveDate & 0xFFFF; diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index d741bb801f..b978f40aba 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -445,7 +445,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a4b73d5d2b55bdb6e44345e99c8fbdd0", 4804}, {"resource.000", 0, "d908dbef56816ac6c60dd145fdeafb2b", 3536046}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO1(GUIO_MIDIGM) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO4(GUIO_MIDIGM, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Eco Quest - English DOS Floppy // SCI interpreter version 1.000.510 @@ -1007,7 +1007,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "459f5b04467bc2107aec02f5c4b71b37", 4878}, {"resource.001", 0, "3876da2ce16fb7dea2f5d943d946fa84", 1652150}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO2(GUIO_MIDIGM, GAMEOPTION_JONES_CDAUDIO) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO4(GUIO_MIDIGM, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI, GAMEOPTION_JONES_CDAUDIO) }, // King's Quest 1 SCI Remake - English Amiga (from www.back2roots.org) // Executable scanning reports "1.003.007" @@ -1221,7 +1221,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "449471bfd77be52f18a3773c7f7d843d", 571368}, {"resource.001", 0, "b45a581ff8751e052c7e364f58d3617f", 16800210}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO1(GUIO_MIDIGM) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO4(GUIO_MIDIGM, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // King's Quest 5 - English DOS Floppy // SCI interpreter version 1.000.060 @@ -1238,6 +1238,24 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 5 - English DOS Floppy + // VERSION file reports "0.000.051" + // Supplied by misterhands in bug report #3536863. + // This is the original English version, which has been externally patched to + // Polish in the Polish release below. + {"kq5", "", { + {"resource.map", 0, "70010c20138541f89013bb5e1b30f16a", 7998}, + {"resource.000", 0, "a591bd4b879fc832b8095c0b3befe9e2", 276398}, + {"resource.001", 0, "c0f48d4a7ebeaa6aa074fc98d77423e9", 1018560}, + {"resource.002", 0, "7f188a95acdb60bbe32a8379ba299393", 1307048}, + {"resource.003", 0, "0860785af59518b94d54718dddcd6907", 1348500}, + {"resource.004", 0, "c4745dd1e261c22daa6477961d08bf6c", 1239887}, + {"resource.005", 0, "6556ff8e7c4d1acf6a78aea154daa76c", 1287869}, + {"resource.006", 0, "da82e4beb744731d0a151f1d4922fafa", 1170456}, + {"resource.007", 0, "431def14ca29cdb5e6a5e84d3f38f679", 1240176}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 5 - English DOS Floppy (supplied by omer_mor in bug report #3036996) // VERSION file reports "0.000.051" {"kq5", "", { @@ -1308,6 +1326,21 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 5 DOS Spanish Floppy 0.000.062 VGA (5 x 3.5" disks) + // Supplied by dianiu in bug report #3555646 + {"kq5", "", { + {"resource.map", 0, "c09896a2a30c9b002c5cbbc62f5a5c3a", 8169}, + {"resource.000", 0, "1f1d03aead44da46362ff40c0074a3ec", 335871}, + {"resource.001", 0, "d1803ad904127ae091edb274ee8c047f", 1180637}, + {"resource.002", 0, "d9cd5972016f650cc31fb7c2a2b0953a", 1102207}, + {"resource.003", 0, "829c8caeff793f3cfcea2cb01aaa4150", 965586}, + {"resource.004", 0, "0bd9e570ee04b025e43d3075998fae5b", 1117965}, + {"resource.005", 0, "4aaa2e9a69089b9afbaaccbbf2c4e647", 1202936}, + {"resource.006", 0, "65b520e60c4217e6a6572d9edf77193b", 1141985}, + {"resource.007", 0, "f42b0100f0a1c30806814f8648b6bc28", 1145583}, + AD_LISTEND}, + Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 5 - German DOS Floppy (supplied by markcoolio in bug report #2727101, also includes english language) // SCI interpreter version 1.000.060 {"kq5", "", { @@ -1354,8 +1387,10 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::IT_ITA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722, includes english language?!) + // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722) // SCI interpreter version 1.000.060 + // VERSION file reports "0.000.051". + // This is actually an English version with external text resource patches (bug #3536863). {"kq5", "", { {"resource.map", 0, "70010c20138541f89013bb5e1b30f16a", 7998}, {"resource.000", 0, "a591bd4b879fc832b8095c0b3befe9e2", 276398}, @@ -1366,6 +1401,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "6556ff8e7c4d1acf6a78aea154daa76c", 1287869}, {"resource.006", 0, "da82e4beb744731d0a151f1d4922fafa", 1170456}, {"resource.007", 0, "431def14ca29cdb5e6a5e84d3f38f679", 1240176}, + {"text.000", 0, "601aa35a3ddeb558e1280e0963e955a2", 1517}, AD_LISTEND}, Common::PL_POL, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, @@ -1447,6 +1483,16 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::DE_DEU, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 6 - Spanish DOS Floppy (from jvprat) + // Executable scanning reports "1.cfs.158", VERSION file reports "1.000.000, July 5, 1994" + // SCI interpreter version 1.001.055 + {"kq6", "", { + {"resource.map", 0, "a73a5ab04b8f60c4b75b946a4dccea5a", 8953}, + {"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260}, + {"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102}, + AD_LISTEND}, + Common::ES_ESP, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Quest 6 - English DOS CD (from the King's Quest Collection) // Executable scanning reports "1.cfs.158", VERSION file reports "1.034 9/11/94 - KQ6 version 1.000.00G" // SCI interpreter version 1.001.054 @@ -1465,16 +1511,6 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO5(GUIO_NOASPECT, GAMEOPTION_KQ6_WINDOWS_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // King's Quest 6 - Spanish DOS CD (from jvprat) - // Executable scanning reports "1.cfs.158", VERSION file reports "1.000.000, July 5, 1994" - // SCI interpreter version 1.001.055 - {"kq6", "CD", { - {"resource.map", 0, "a73a5ab04b8f60c4b75b946a4dccea5a", 8953}, - {"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260}, - {"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102}, - AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // King's Quest 6 - English Macintosh Floppy // VERSION file reports "1.0" {"kq6", "", { @@ -2660,6 +2696,13 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Police Quest 3 - Spanish DOS v1.000 - Supplied by dianiu in bug report #3555647 + {"pq3", "", { + {"resource.map", 0, "ffa0b4631c4e36d69631256d19ba29e7", 5421}, + {"resource.000", 0, "5ee460af3d70c06a745cc482b6c783ba", 5410263}, + AD_LISTEND}, + Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Police Quest 3 EGA // Reported by musiclyinspired in bug report #3046573 {"pq3", "", { @@ -2777,6 +2820,31 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy v1.102 Int#0.000.629 (suppled by digitoxin1 in bug report #3554611) + {"qfg1", "", { + {"resource.map", 0, "b162dbd4632250d4d83bed46d0783c10", 6396}, + {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800}, + {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 459835}, + {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635561}, + {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502}, + {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + + // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy v1.102 Int#0.000.629 (suppled by digitoxin1 in bug report #3554611) + {"qfg1", "", { + {"resource.map", 0, "5772a2c1bfae46f26582582c9901121e", 6858}, + {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800}, + {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 75090}, + {"resource.002", 0, "d22695c53835dfdece056d86f26c251e", 271354}, + {"resource.003", 0, "3cd085e27078f269b3ece5838812ff41", 258084}, + {"resource.004", 0, "8927c7a04a78f1e76f342db3ccc9d879", 267835}, + {"resource.005", 0, "13d16cc9b90b51e2c8643cdf52a62957", 268807}, + {"resource.006", 0, "48b2b3c964dcbeccb68e984e6d4e97db", 278473}, + {"resource.007", 0, "f0af87c60ec869946da442833aa5afa8", 269237}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by markcoolio in bug report #2723843) // Executable scanning reports "0.000.566" {"qfg1", "", { @@ -2864,17 +2932,6 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Quest for Glory 1 (from abevi, bug report #2612718) - {"qfg1", "", { - {"resource.map", 0, "b162dbd4632250d4d83bed46d0783c10", 6396}, - {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 78800}, - {"resource.001", 0, "a270012fa74445d74c044d1b65a9ff8c", 459835}, - {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635561}, - {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502}, - {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575}, - AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Quest for Glory 1 - English DOS // SCI interpreter version 0.000.629 {"qfg1", "", { @@ -2925,7 +2982,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "ccf5dba33e5cab6d5872838c0f8db44c", 500039}, {"resource.007", 0, "4c9fc1587545879295cb9627f56a2cb8", 575056}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 2 - English (supplied by ssburnout in bug report #3049193) // 1.000 5x5.25" (label: INT#10.31.90) @@ -2937,7 +2994,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "0790f67d87642132be515cab05026baa", 972144}, {"resource.004", 0, "2ac1e6fea9aa1f5b91a06693a67b9766", 982830}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 2 - English (supplied by ssburnout in bug report #3049193) // 1.000 9x3.5" (label: INT#10.31.90) @@ -2952,7 +3009,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "5e9deacbdb17198ad844988e04833520", 498593}, {"resource.007", 0, "2ac1e6fea9aa1f5b91a06693a67b9766", 490151}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 2 - English (from FRG) // Executable scanning reports "1.000.072" @@ -2964,7 +3021,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "b192607c42f6960ecdf2ad2e4f90e9bc", 972804}, {"resource.004", 0, "cd2de58e27665d5853530de93fae7cd6", 983617}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 2 - English DOS // Executable scanning reports "1.000.072" @@ -2979,7 +3036,22 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "b1944bd664ddbd2859cdaa0c4a0d6281", 507489}, {"resource.007", 0, "cd2de58e27665d5853530de93fae7cd6", 490794}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + + // Quest for Glory 2 - English DOS (supplied by digitoxin1 in bug report #3554614) + // v1.102 9x3.5" (label: Int#11.20.90) + {"qfg2", "", { + {"resource.map", 0, "367023314ea33e3156297402f6c1da49", 8166}, + {"resource.000", 0, "a17e374c4d33b81208c862bc0ffc1a38", 212119}, + {"resource.001", 0, "e08d7887e30b12008c40f9570447711a", 331995}, + {"resource.002", 0, "df137dc7869cab07e1149ba2333c815c", 467461}, + {"resource.003", 0, "df137dc7869cab07e1149ba2333c815c", 502560}, + {"resource.004", 0, "df137dc7869cab07e1149ba2333c815c", 488532}, + {"resource.005", 0, "df137dc7869cab07e1149ba2333c815c", 478574}, + {"resource.006", 0, "b1944bd664ddbd2859cdaa0c4a0d6281", 507489}, + {"resource.007", 0, "cd2de58e27665d5853530de93fae7cd6", 490794}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 2 - English DOS Non-Interactive Demo // Executable scanning reports "1.000.046" @@ -2987,7 +3059,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "e75eb86bdd517b3ef709058249986a87", 906}, {"resource.001", 0, "9b098f9e1008abe30e56c93b896494e6", 362123}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Quest for Glory 3 - English DOS Non-Interactive Demo (from FRG) // Executable scanning reports "1.001.021", VERSION file reports "1.000, 0.001.059, 6.12.92" @@ -3445,6 +3517,19 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Space Quest 4 1.000 - French DOS Floppy (supplied by misterhands in bug report #3515247) + {"sq4", "", { + + {"resource.map", 0, "1fd6f356f6a59ad2057686ce6573caeb", 6159}, + {"resource.000", 0, "8000a55aebc50a68b7cce07a8c33758c", 205287}, + {"resource.001", 0, "99a6df6d366b3f061271ff3450ac0d32", 1269850}, + {"resource.002", 0, "a6a8d7a24dbb7a266a26b084e7275e89", 1242668}, + {"resource.003", 0, "482a99c8103b4bcb5706e5969d1c1193", 1323083}, + {"resource.004", 0, "b2cca3afcf2e013b8ce86b64155af766", 1254353}, + {"resource.005", 0, "9e520577e035547c4b5149a6d12ef85b", 1098814}, + AD_LISTEND}, + Common::FR_FRA, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Space Quest 4 1.000 - English DOS Floppy (from abevi, bug report #2612718) {"sq4", "", { {"resource.map", 0, "8f08b97ca093f370c56d99715b015554", 6153}, @@ -3523,7 +3608,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "ed90a8e3ccc53af6633ff6ab58392bae", 7054}, {"resource.000", 0, "63247e3901ab8963d4eece73747832e0", 5157378}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GAMEOPTION_SQ4_SILVER_CURSORS) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO5(GUIO_MIDIGM, GAMEOPTION_SQ4_SILVER_CURSORS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, // Space Quest 4 - English Windows CD (from the Space Quest Collection) // Executable scanning reports "1.001.064", VERSION file reports "1.0" @@ -3731,53 +3816,61 @@ static const struct ADGameDescription SciGameDescriptions[] = { #ifdef ENABLE_SCI32 // Torin's Passage - English Windows Interactive Demo - // SCI interpreter version 2.100.002 (just a guess) + // SCI interpreter version 2.100.002 {"torin", "Demo", { {"resmap.000", 0, "9a3e172cde9963d0a969f26469318cec", 3403}, {"ressci.000", 0, "db3e290481c35c3224e9602e71e4a1f1", 5073868}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Torin's Passage - English Windows - // SCI interpreter version 2.100.002 (just a guess) + // Torin's Passage (Multilingual) - English Windows CD + // SCI interpreter version 2.100.002 {"torin", "", { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Torin's Passage - Spanish Windows (from jvprat) + // Torin's Passage (Multilingual) - Spanish Windows CD (from jvprat) // Executable scanning reports "2.100.002", VERSION file reports "1.0" {"torin", "", { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, // TODO: depend on one of the patches? AD_LISTEND}, - Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Torin's Passage - French Windows - // SCI interpreter version 2.100.002 (just a guess) + // Torin's Passage (Multilingual) - French Windows CD + // SCI interpreter version 2.100.002 {"torin", "", { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Torin's Passage - German Windows - // SCI interpreter version 2.100.002 (just a guess) + // Torin's Passage (Multilingual) - German Windows CD + // SCI interpreter version 2.100.002 {"torin", "", { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Torin's Passage - Italian Windows CD (from glorifindel) - // SCI interpreter version 2.100.002 (just a guess) + // Torin's Passage (Multilingual) - Italian Windows CD (from glorifindel) + // SCI interpreter version 2.100.002 {"torin", "", { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + + // Torin's Passage - French Windows (from LePhilousophe) + // SCI interpreter version 2.100.002 + {"torin", "", { + {"resmap.000", 0, "66ed46e3e56f487e688d52f05b33d0ba", 9787}, + {"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56126981}, + AD_LISTEND}, + Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #endif // ENABLE_SCI32 // SCI Fanmade Games diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index cad95b1c18..22c0a1479d 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -45,6 +45,7 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan) _usesCdTrack = Common::File::exists("cdaudio.map"); if (!ConfMan.getBool("use_cdaudio")) _usesCdTrack = false; + _forceDOSTracks = false; } reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc, int methodNum) { @@ -73,11 +74,11 @@ bool GameFeatures::autoDetectSoundType() { // Look up the script address reg_t addr = getDetectionAddr("Sound", SELECTOR(play)); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); uint16 intParam = 0xFFFF; bool foundTarget = false; @@ -220,11 +221,11 @@ bool GameFeatures::autoDetectLofsType(Common::String gameSuperClassName, int met // Look up the script address reg_t addr = getDetectionAddr(gameSuperClassName.c_str(), -1, methodNum); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); while (true) { int16 opparams[4]; @@ -319,11 +320,11 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) { // Look up the script address reg_t addr = getDetectionAddr("Rm", SELECTOR(overlay), methodNum); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); while (true) { int16 opparams[4]; @@ -473,11 +474,11 @@ bool GameFeatures::autoDetectSci21KernelType() { // Look up the script address reg_t addr = getDetectionAddr("Sound", SELECTOR(play)); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); while (true) { int16 opparams[4]; @@ -549,11 +550,11 @@ bool GameFeatures::autoDetectSci21StringFunctionType() { // Look up the script address reg_t addr = getDetectionAddr("Str", SELECTOR(size)); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); while (true) { int16 opparams[4]; @@ -586,11 +587,11 @@ bool GameFeatures::autoDetectMoveCountType() { // Look up the script address reg_t addr = getDetectionAddr("Motion", SELECTOR(doit)); - if (!addr.segment) + if (!addr.getSegment()) return false; - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); + uint16 offset = addr.getOffset(); + Script *script = _segMan->getScript(addr.getSegment()); bool foundTarget = false; while (true) { @@ -642,7 +643,7 @@ MoveCountType GameFeatures::detectMoveCountType() { } bool GameFeatures::useAltWinGMSound() { - if (g_sci && g_sci->getPlatform() == Common::kPlatformWindows && g_sci->isCD()) { + if (g_sci && g_sci->getPlatform() == Common::kPlatformWindows && g_sci->isCD() && !_forceDOSTracks) { SciGameId id = g_sci->getGameId(); return (id == GID_ECOQUEST || id == GID_JONES || diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h index 4592c5be9c..f6bb0b5759 100644 --- a/engines/sci/engine/features.h +++ b/engines/sci/engine/features.h @@ -117,6 +117,12 @@ public: */ bool useAltWinGMSound(); + /** + * Forces DOS soundtracks in Windows CD versions when the user hasn't + * selected a MIDI output device + */ + void forceDOSTracks() { _forceDOSTracks = true; } + private: reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1); @@ -137,6 +143,7 @@ private: MoveCountType _moveCountType; bool _usesCdTrack; + bool _forceDOSTracks; SegManager *_segMan; Kernel *_kernel; diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp new file mode 100644 index 0000000000..a0f7ebf4a2 --- /dev/null +++ b/engines/sci/engine/file.cpp @@ -0,0 +1,464 @@ +/* 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 "common/savefile.h" +#include "common/stream.h" + +#include "sci/sci.h" +#include "sci/engine/file.h" +#include "sci/engine/kernel.h" +#include "sci/engine/savegame.h" +#include "sci/engine/selector.h" +#include "sci/engine/state.h" + +namespace Sci { + +/* + * Note on how file I/O is implemented: In ScummVM, one can not create/write + * arbitrary data files, simply because many of our target platforms do not + * support this. The only files one can create are savestates. But SCI has an + * opcode to create and write to seemingly 'arbitrary' files. This is mainly + * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver, used + * for persisting the results of the "age quiz" across restarts) and in LSL5 + * for MEMORY.DRV (which is again a game data file and contains the game's + * password, XOR encrypted). + * To implement that opcode, we combine the SaveFileManager with regular file + * code, similarly to how the SCUMM HE engine does it. + * + * To handle opening a file called "foobar", what we do is this: First, we + * create an 'augmented file name', by prepending the game target and a dash, + * so if we running game target sq1sci, the name becomes "sq1sci-foobar". + * Next, we check if such a file is known to the SaveFileManager. If so, we + * we use that for reading/writing, delete it, whatever. + * + * If no such file is present but we were only asked to *read* the file, + * we fallback to looking for a regular file called "foobar", and open that + * for reading only. + */ + +reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) { + Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH); + englishName.toLowercase(); + + Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName; + Common::SeekableReadStream *inFile = 0; + Common::WriteStream *outFile = 0; + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + + bool isCompressed = true; + const SciGameId gameId = g_sci->getGameId(); + if ((gameId == GID_QFG1 || gameId == GID_QFG1VGA || gameId == GID_QFG2 || gameId == GID_QFG3) + && englishName.hasSuffix(".sav")) { + // QFG Characters are saved via the CharSave object. + // We leave them uncompressed so that they can be imported in later QFG + // games. + // Rooms/Scripts: QFG1: 601, QFG2: 840, QFG3/4: 52 + isCompressed = false; + } + + if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { + // Try to open file, abort if not possible + inFile = saveFileMan->openForLoading(wrappedName); + // If no matching savestate exists: fall back to reading from a regular + // file + if (!inFile) + inFile = SearchMan.createReadStreamForMember(englishName); + + if (!inFile) + debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str()); + } else if (mode == _K_FILE_MODE_CREATE) { + // Create the file, destroying any content it might have had + outFile = saveFileMan->openForSaving(wrappedName, isCompressed); + if (!outFile) + debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str()); + } else if (mode == _K_FILE_MODE_OPEN_OR_CREATE) { + // Try to open file, create it if it doesn't exist + outFile = saveFileMan->openForSaving(wrappedName, isCompressed); + if (!outFile) + debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str()); + + // QfG1 opens the character export file with _K_FILE_MODE_CREATE first, + // closes it immediately and opens it again with this here. Perhaps + // other games use this for read access as well. I guess changing this + // whole code into using virtual files and writing them after close + // would be more appropriate. + } else { + error("file_open: unsupported mode %d (filename '%s')", mode, englishName.c_str()); + } + + if (!inFile && !outFile) { // Failed + debugC(kDebugLevelFile, " -> file_open() failed"); + return SIGNAL_REG; + } + + // Find a free file handle + uint handle = 1; // Ignore _fileHandles[0] + while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) + handle++; + + if (handle == s->_fileHandles.size()) { + // Hit size limit => Allocate more space + s->_fileHandles.resize(s->_fileHandles.size() + 1); + } + + s->_fileHandles[handle]._in = inFile; + s->_fileHandles[handle]._out = outFile; + s->_fileHandles[handle]._name = englishName; + + debugC(kDebugLevelFile, " -> opened file '%s' with handle %d", englishName.c_str(), handle); + return make_reg(0, handle); +} + +FileHandle *getFileFromHandle(EngineState *s, uint handle) { + if (handle == 0 || handle == VIRTUALFILE_HANDLE) { + error("Attempt to use invalid file handle (%d)", handle); + return 0; + } + + if ((handle >= s->_fileHandles.size()) || !s->_fileHandles[handle].isOpen()) { + warning("Attempt to use invalid/unused file handle %d", handle); + return 0; + } + + return &s->_fileHandles[handle]; +} + +int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) { + FileHandle *f = getFileFromHandle(s, handle); + if (!f) + return 0; + + if (!f->_in) { + error("fgets_wrapper: Trying to read from file '%s' opened for writing", f->_name.c_str()); + return 0; + } + int readBytes = 0; + if (maxsize > 1) { + memset(dest, 0, maxsize); + f->_in->readLine(dest, maxsize); + readBytes = strlen(dest); // FIXME: sierra sci returned byte count and didn't react on NUL characters + // The returned string must not have an ending LF + if (readBytes > 0) { + if (dest[readBytes - 1] == 0x0A) + dest[readBytes - 1] = 0; + } + } else { + *dest = 0; + } + + debugC(kDebugLevelFile, " -> FGets'ed \"%s\"", dest); + return readBytes; +} + +static bool _savegame_sort_byDate(const SavegameDesc &l, const SavegameDesc &r) { + if (l.date != r.date) + return (l.date > r.date); + return (l.time > r.time); +} + +// Create a sorted array containing all found savedgames +void listSavegames(Common::Array<SavegameDesc> &saves) { + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + + // Load all saves + Common::StringArray saveNames = saveFileMan->listSavefiles(g_sci->getSavegamePattern()); + + for (Common::StringArray::const_iterator iter = saveNames.begin(); iter != saveNames.end(); ++iter) { + Common::String filename = *iter; + Common::SeekableReadStream *in; + if ((in = saveFileMan->openForLoading(filename))) { + SavegameMetadata meta; + if (!get_savegame_metadata(in, &meta) || meta.name.empty()) { + // invalid + delete in; + continue; + } + delete in; + + SavegameDesc desc; + desc.id = strtol(filename.end() - 3, NULL, 10); + desc.date = meta.saveDate; + // We need to fix date in here, because we save DDMMYYYY instead of + // YYYYMMDD, so sorting wouldn't work + desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24); + desc.time = meta.saveTime; + desc.version = meta.version; + + if (meta.name.lastChar() == '\n') + meta.name.deleteLastChar(); + + Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH); + + debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id); + + saves.push_back(desc); + } + } + + // Sort the list by creation date of the saves + Common::sort(saves.begin(), saves.end(), _savegame_sort_byDate); +} + +// Find a savedgame according to virtualId and return the position within our array +int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId) { + for (uint saveNr = 0; saveNr < saves.size(); saveNr++) { + if (saves[saveNr].id == savegameId) + return saveNr; + } + return -1; +} + + +FileHandle::FileHandle() : _in(0), _out(0) { +} + +FileHandle::~FileHandle() { + close(); +} + +void FileHandle::close() { + delete _in; + delete _out; + _in = 0; + _out = 0; + _name.clear(); +} + +bool FileHandle::isOpen() const { + return _in || _out; +} + + +void DirSeeker::addAsVirtualFiles(Common::String title, Common::String fileMask) { + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + Common::StringArray foundFiles = saveFileMan->listSavefiles(fileMask); + if (!foundFiles.empty()) { + _files.push_back(title); + _virtualFiles.push_back(""); + Common::StringArray::iterator it; + Common::StringArray::iterator it_end = foundFiles.end(); + + for (it = foundFiles.begin(); it != it_end; it++) { + Common::String regularFilename = *it; + Common::String wrappedFilename = Common::String(regularFilename.c_str() + fileMask.size() - 1); + + Common::SeekableReadStream *testfile = saveFileMan->openForLoading(regularFilename); + int32 testfileSize = testfile->size(); + delete testfile; + if (testfileSize > 1024) // check, if larger than 1k. in that case its a saved game. + continue; // and we dont want to have those in the list + // We need to remove the prefix for display purposes + _files.push_back(wrappedFilename); + // but remember the actual name as well + _virtualFiles.push_back(regularFilename); + } + } +} + +Common::String DirSeeker::getVirtualFilename(uint fileNumber) { + if (fileNumber >= _virtualFiles.size()) + error("invalid virtual filename access"); + return _virtualFiles[fileNumber]; +} + +reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) { + // Verify that we are given a valid buffer + if (!buffer.getSegment()) { + error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str()); + return NULL_REG; + } + _outbuffer = buffer; + _files.clear(); + _virtualFiles.clear(); + + int QfGImport = g_sci->inQfGImportRoom(); + if (QfGImport) { + _files.clear(); + addAsVirtualFiles("-QfG1-", "qfg1-*"); + addAsVirtualFiles("-QfG1VGA-", "qfg1vga-*"); + if (QfGImport > 2) + addAsVirtualFiles("-QfG2-", "qfg2-*"); + if (QfGImport > 3) + addAsVirtualFiles("-QfG3-", "qfg3-*"); + + if (QfGImport == 3) { + // QfG3 sorts the filelisting itself, we can't let that happen otherwise our + // virtual list would go out-of-sync + reg_t savedHeros = segMan->findObjectByName("savedHeros"); + if (!savedHeros.isNull()) + writeSelectorValue(segMan, savedHeros, SELECTOR(sort), 0); + } + + } else { + // Prefix the mask + const Common::String wrappedMask = g_sci->wrapFilename(mask); + + // Obtain a list of all files matching the given mask + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + _files = saveFileMan->listSavefiles(wrappedMask); + } + + // Reset the list iterator and write the first match to the output buffer, + // if any. + _iter = _files.begin(); + return nextFile(segMan); +} + +reg_t DirSeeker::nextFile(SegManager *segMan) { + if (_iter == _files.end()) { + return NULL_REG; + } + + Common::String string; + + if (_virtualFiles.empty()) { + // Strip the prefix, if we don't got a virtual filelisting + const Common::String wrappedString = *_iter; + string = g_sci->unwrapFilename(wrappedString); + } else { + string = *_iter; + } + if (string.size() > 12) + string = Common::String(string.c_str(), 12); + segMan->strcpy(_outbuffer, string.c_str()); + + // Return the result and advance the list iterator :) + ++_iter; + return _outbuffer; +} + + +#ifdef ENABLE_SCI32 + +VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) { + Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName); + + _bufferSize = inFile->size(); + _buffer = new char[_bufferSize]; + inFile->read(_buffer, _bufferSize); + _ptr = _buffer; + delete inFile; +} + +VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) { + _bufferSize = initialSize; + _buffer = new char[_bufferSize]; + _ptr = _buffer; +} + +VirtualIndexFile::~VirtualIndexFile() { + close(); + + _bufferSize = 0; + delete[] _buffer; + _buffer = 0; +} + +uint32 VirtualIndexFile::read(char *buffer, uint32 size) { + uint32 curPos = _ptr - _buffer; + uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos); + char *localPtr = buffer; + + for (uint32 i = 0; i < finalSize; i++) + *localPtr++ = *_ptr++; + + return finalSize; +} + +uint32 VirtualIndexFile::write(const char *buffer, uint32 size) { + _changed = true; + uint32 curPos = _ptr - _buffer; + + // Check if the buffer needs to be resized + if (curPos + size >= _bufferSize) { + _bufferSize = curPos + size + 1; + char *tmp = _buffer; + _buffer = new char[_bufferSize]; + _ptr = _buffer + curPos; + memcpy(_buffer, tmp, _bufferSize); + delete[] tmp; + } + + for (uint32 i = 0; i < size; i++) + *_ptr++ = *buffer++; + + return size; +} + +uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) { + uint32 startPos = _ptr - _buffer; + uint32 bytesRead = 0; + char *localPtr = buffer; + + // This is not a full-blown implementation of readLine, but it + // suffices for Phantasmagoria + while (startPos + bytesRead < size) { + bytesRead++; + + if (*_ptr == 0 || *_ptr == 0x0A) { + _ptr++; + *localPtr = 0; + return bytesRead; + } else { + *localPtr++ = *_ptr++; + } + } + + return bytesRead; +} + +bool VirtualIndexFile::seek(int32 offset, int whence) { + uint32 startPos = _ptr - _buffer; + assert(offset >= 0); + + switch (whence) { + case SEEK_CUR: + assert(startPos + offset < _bufferSize); + _ptr += offset; + break; + case SEEK_SET: + assert(offset < (int32)_bufferSize); + _ptr = _buffer + offset; + break; + case SEEK_END: + assert((int32)_bufferSize - offset >= 0); + _ptr = _buffer + (_bufferSize - offset); + break; + } + + return true; +} + +void VirtualIndexFile::close() { + if (_changed && !_fileName.empty()) { + Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName); + outFile->write(_buffer, _bufferSize); + delete outFile; + } + + // Maintain the buffer, and seek to the beginning of it + _ptr = _buffer; +} + +#endif + +} // End of namespace Sci diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h new file mode 100644 index 0000000000..1c8e302d15 --- /dev/null +++ b/engines/sci/engine/file.h @@ -0,0 +1,140 @@ +/* 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 SCI_ENGINE_FILE_H +#define SCI_ENGINE_FILE_H + +#include "common/str-array.h" +#include "common/stream.h" + +namespace Sci { + +enum { + _K_FILE_MODE_OPEN_OR_CREATE = 0, + _K_FILE_MODE_OPEN_OR_FAIL = 1, + _K_FILE_MODE_CREATE = 2 +}; + +/* Maximum length of a savegame name (including terminator character). */ +#define SCI_MAX_SAVENAME_LENGTH 0x24 + +enum { + MAX_SAVEGAME_NR = 20 /**< Maximum number of savegames */ +}; + +#define VIRTUALFILE_HANDLE 200 +#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir" + +struct SavegameDesc { + int16 id; + int virtualId; // straight numbered, according to id but w/o gaps + int date; + int time; + int version; + char name[SCI_MAX_SAVENAME_LENGTH]; +}; + +class FileHandle { +public: + Common::String _name; + Common::SeekableReadStream *_in; + Common::WriteStream *_out; + +public: + FileHandle(); + ~FileHandle(); + + void close(); + bool isOpen() const; +}; + + +class DirSeeker { +protected: + reg_t _outbuffer; + Common::StringArray _files; + Common::StringArray _virtualFiles; + Common::StringArray::const_iterator _iter; + +public: + DirSeeker() { + _outbuffer = NULL_REG; + _iter = _files.begin(); + } + + reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan); + reg_t nextFile(SegManager *segMan); + + Common::String getVirtualFilename(uint fileNumber); + +private: + void addAsVirtualFiles(Common::String title, Common::String fileMask); +}; + + +#ifdef ENABLE_SCI32 + +/** + * An implementation of a virtual file that supports basic read and write + * operations simultaneously. + * + * This class has been initially implemented for Phantasmagoria, which has its + * own custom save/load code. The load code keeps checking for the existence + * of the save index file and keeps closing and reopening it for each save + * slot. This is notoriously slow and clumsy, and introduces noticeable delays, + * especially for non-desktop systems. Also, its game scripts request to open + * the index file for reading and writing with the same parameters + * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover, + * the game scripts reopen the index file for writing in order to update it + * and seek within it. We do not support seeking in writeable streams, and the + * fact that our saved games are ZIP files makes this operation even more + * expensive. Finally, the savegame index file is supposed to be expanded when + * a new save slot is added. + * For the aforementioned reasons, this class has been implemented, which offers + * the basic functionality needed by the game scripts in Phantasmagoria. + */ +class VirtualIndexFile { +public: + VirtualIndexFile(Common::String fileName); + VirtualIndexFile(uint32 initialSize); + ~VirtualIndexFile(); + + uint32 read(char *buffer, uint32 size); + uint32 readLine(char *buffer, uint32 size); + uint32 write(const char *buffer, uint32 size); + bool seek(int32 offset, int whence); + void close(); + +private: + char *_buffer; + uint32 _bufferSize; + char *_ptr; + + Common::String _fileName; + bool _changed; +}; + +#endif + +} // End of namespace Sci + +#endif // SCI_ENGINE_FILE_H diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp index 2d71878bda..9a30ff3e17 100644 --- a/engines/sci/engine/gc.cpp +++ b/engines/sci/engine/gc.cpp @@ -47,7 +47,7 @@ const char *segmentTypeNames[] = { #endif void WorklistManager::push(reg_t reg) { - if (!reg.segment) // No numbers + if (!reg.getSegment()) // No numbers return; debugC(kDebugLevelGC, "[GC] Adding %04x:%04x", PRINT_REG(reg)); @@ -69,7 +69,7 @@ static AddrSet *normalizeAddresses(SegManager *segMan, const AddrSet &nonnormal_ for (AddrSet::const_iterator i = nonnormal_map.begin(); i != nonnormal_map.end(); ++i) { reg_t reg = i->_key; - SegmentObj *mobj = segMan->getSegmentObj(reg.segment); + SegmentObj *mobj = segMan->getSegmentObj(reg.getSegment()); if (mobj) { reg = mobj->findCanonicAddress(segMan, reg); @@ -85,11 +85,11 @@ static void processWorkList(SegManager *segMan, WorklistManager &wm, const Commo while (!wm._worklist.empty()) { reg_t reg = wm._worklist.back(); wm._worklist.pop_back(); - if (reg.segment != stackSegment) { // No need to repeat this one + if (reg.getSegment() != stackSegment) { // No need to repeat this one debugC(kDebugLevelGC, "[GC] Checking %04x:%04x", PRINT_REG(reg)); - if (reg.segment < heap.size() && heap[reg.segment]) { + if (reg.getSegment() < heap.size() && heap[reg.getSegment()]) { // Valid heap object? Find its outgoing references! - wm.pushArray(heap[reg.segment]->listAllOutgoingReferences(reg)); + wm.pushArray(heap[reg.getSegment()]->listAllOutgoingReferences(reg)); } } } diff --git a/engines/sci/engine/gc.h b/engines/sci/engine/gc.h index 97aa6513b6..9e02bbd0bd 100644 --- a/engines/sci/engine/gc.h +++ b/engines/sci/engine/gc.h @@ -32,7 +32,7 @@ namespace Sci { struct reg_t_Hash { uint operator()(const reg_t& x) const { - return (x.segment << 3) ^ x.offset ^ (x.offset << 16); + return (x.getSegment() << 3) ^ x.getOffset() ^ (x.getOffset() << 16); } }; diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index c99bc4fe47..46051ef145 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -357,27 +357,27 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS uint16 Kernel::findRegType(reg_t reg) { // No segment? Must be integer - if (!reg.segment) - return SIG_TYPE_INTEGER | (reg.offset ? 0 : SIG_TYPE_NULL); + if (!reg.getSegment()) + return SIG_TYPE_INTEGER | (reg.getOffset() ? 0 : SIG_TYPE_NULL); - if (reg.segment == 0xFFFF) + if (reg.getSegment() == 0xFFFF) return SIG_TYPE_UNINITIALIZED; // Otherwise it's an object - SegmentObj *mobj = _segMan->getSegmentObj(reg.segment); + SegmentObj *mobj = _segMan->getSegmentObj(reg.getSegment()); if (!mobj) return SIG_TYPE_ERROR; uint16 result = 0; - if (!mobj->isValidOffset(reg.offset)) + if (!mobj->isValidOffset(reg.getOffset())) result |= SIG_IS_INVALID; switch (mobj->getType()) { case SEG_TYPE_SCRIPT: - if (reg.offset <= (*(Script *)mobj).getBufSize() && - reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && - RAW_IS_OBJECT((*(Script *)mobj).getBuf(reg.offset)) ) { - result |= ((Script *)mobj)->getObject(reg.offset) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE; + if (reg.getOffset() <= (*(Script *)mobj).getBufSize() && + reg.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && + (*(Script *)mobj).offsetIsObject(reg.getOffset())) { + result |= ((Script *)mobj)->getObject(reg.getOffset()) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE; } else result |= SIG_TYPE_REFERENCE; break; @@ -608,7 +608,7 @@ void Kernel::mapFunctions() { _kernelFuncs[id].workarounds = kernelMap->workarounds; if (kernelMap->subFunctions) { // Get version for subfunction identification - SciVersion mySubVersion = (SciVersion)kernelMap->function(NULL, 0, NULL).offset; + SciVersion mySubVersion = (SciVersion)kernelMap->function(NULL, 0, NULL).getOffset(); // Now check whats the highest subfunction-id for this version const SciKernelMapSubEntry *kernelSubMap = kernelMap->subFunctions; uint16 subFunctionCount = 0; @@ -757,13 +757,26 @@ bool Kernel::debugSetFunction(const char *kernelName, int logging, int breakpoin return true; } -void Kernel::setDefaultKernelNames(GameFeatures *features) { - _kernelNames = Common::StringArray(s_defaultKernelNames, ARRAYSIZE(s_defaultKernelNames)); +#ifdef ENABLE_SCI32 +enum { + kKernelEntriesSci2 = 0x8b, + kKernelEntriesGk2Demo = 0xa0, + kKernelEntriesSci21 = 0x9d, + kKernelEntriesSci3 = 0xa1 +}; +#endif + +void Kernel::loadKernelNames(GameFeatures *features) { + _kernelNames.clear(); - // Some (later) SCI versions replaced CanBeHere by CantBeHere - // If vocab.999 exists, the kernel function is still named CanBeHere - if (_selectorCache.cantBeHere != -1) - _kernelNames[0x4d] = "CantBeHere"; + if (getSciVersion() <= SCI_VERSION_1_1) { + _kernelNames = Common::StringArray(s_defaultKernelNames, ARRAYSIZE(s_defaultKernelNames)); + + // Some (later) SCI versions replaced CanBeHere by CantBeHere + // If vocab.999 exists, the kernel function is still named CanBeHere + if (_selectorCache.cantBeHere != -1) + _kernelNames[0x4d] = "CantBeHere"; + } switch (getSciVersion()) { case SCI_VERSION_0_EARLY: @@ -817,66 +830,60 @@ void Kernel::setDefaultKernelNames(GameFeatures *features) { _kernelNames[0x7c] = "Message"; break; - default: - // Use default table for the other versions - break; - } -} - #ifdef ENABLE_SCI32 + case SCI_VERSION_2: + _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2); + break; -enum { - kKernelEntriesSci2 = 0x8b, - kKernelEntriesGk2Demo = 0xa0, - kKernelEntriesSci21 = 0x9d, - kKernelEntriesSci3 = 0xa1 -}; - -void Kernel::setKernelNamesSci2() { - _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2); -} + case SCI_VERSION_2_1: + if (features->detectSci21KernelType() == SCI_VERSION_2) { + // Some early SCI2.1 games use a modified SCI2 kernel table instead of + // the SCI2.1 kernel table. We detect which version to use based on + // how kDoSound is called from Sound::play(). + // Known games that use this: + // GK2 demo + // KQ7 1.4 + // PQ4 SWAT demo + // LSL6 + // PQ4CD + // QFG4CD + + // This is interesting because they all have the same interpreter + // version (2.100.002), yet they would not be compatible with other + // games of the same interpreter. + + _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo); + // OnMe is IsOnMe here, but they should be compatible + _kernelNames[0x23] = "Robot"; // Graph in SCI2 + _kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2 + } else { + // Normal SCI2.1 kernel table + _kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci21); + } + break; -void Kernel::setKernelNamesSci21(GameFeatures *features) { - // Some SCI games use a modified SCI2 kernel table instead of the - // SCI2.1 kernel table. We detect which version to use based on - // how kDoSound is called from Sound::play(). - // Known games that use this: - // GK2 demo - // KQ7 1.4 - // PQ4 SWAT demo - // LSL6 - // PQ4CD - // QFG4CD - - // This is interesting because they all have the same interpreter - // version (2.100.002), yet they would not be compatible with other - // games of the same interpreter. - - if (getSciVersion() != SCI_VERSION_3 && features->detectSci21KernelType() == SCI_VERSION_2) { - _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo); - // OnMe is IsOnMe here, but they should be compatible - _kernelNames[0x23] = "Robot"; // Graph in SCI2 - _kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2 - } else if (getSciVersion() != SCI_VERSION_3) { - _kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci21); - } else if (getSciVersion() == SCI_VERSION_3) { + case SCI_VERSION_3: _kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci3); - } -} -#endif - -void Kernel::loadKernelNames(GameFeatures *features) { - _kernelNames.clear(); + // In SCI3, some kernel functions have been removed, and others have been added + _kernelNames[0x18] = "Dummy"; // AddMagnify in SCI2.1 + _kernelNames[0x19] = "Dummy"; // DeleteMagnify in SCI2.1 + _kernelNames[0x30] = "Dummy"; // SetScroll in SCI2.1 + _kernelNames[0x39] = "Dummy"; // ShowMovie in SCI2.1 + _kernelNames[0x4c] = "Dummy"; // ScrollWindow in SCI2.1 + _kernelNames[0x56] = "Dummy"; // VibrateMouse in SCI2.1 (only used in QFG4 floppy) + _kernelNames[0x64] = "Dummy"; // AvoidPath in SCI2.1 + _kernelNames[0x66] = "Dummy"; // MergePoly in SCI2.1 + _kernelNames[0x8d] = "MessageBox"; // Dummy in SCI2.1 + _kernelNames[0x9b] = "Minimize"; // Dummy in SCI2.1 -#ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1) - setKernelNamesSci21(features); - else if (getSciVersion() == SCI_VERSION_2) - setKernelNamesSci2(); - else + break; #endif - setDefaultKernelNames(features); + + default: + // Use default table for the other versions + break; + } mapFunctions(); } @@ -885,15 +892,15 @@ Common::String Kernel::lookupText(reg_t address, int index) { char *seeker; Resource *textres; - if (address.segment) + if (address.getSegment()) return _segMan->getString(address); int textlen; int _index = index; - textres = _resMan->findResource(ResourceId(kResourceTypeText, address.offset), 0); + textres = _resMan->findResource(ResourceId(kResourceTypeText, address.getOffset()), 0); if (!textres) { - error("text.%03d not found", address.offset); + error("text.%03d not found", address.getOffset()); return NULL; /* Will probably segfault */ } @@ -907,7 +914,7 @@ Common::String Kernel::lookupText(reg_t address, int index) { if (textlen) return seeker; - error("Index %d out of bounds in text.%03d", _index, address.offset); + error("Index %d out of bounds in text.%03d", _index, address.getOffset()); return NULL; } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index e549c1f8ae..f985a69ebc 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -224,23 +224,6 @@ public: private: /** - * Sets the default kernel function names, based on the SCI version used. - */ - void setDefaultKernelNames(GameFeatures *features); - -#ifdef ENABLE_SCI32 - /** - * Sets the default kernel function names to the SCI2 kernel functions. - */ - void setKernelNamesSci2(); - - /** - * Sets the default kernel function names to the SCI2.1 kernel functions. - */ - void setKernelNamesSci21(GameFeatures *features); -#endif - - /** * Loads the kernel selector names. */ void loadSelectorNames(); @@ -276,9 +259,6 @@ private: const Common::String _invalid; }; -/* Maximum length of a savegame name (including terminator character). */ -#define SCI_MAX_SAVENAME_LENGTH 0x24 - /******************** Kernel functions ********************/ reg_t kStrLen(EngineState *s, int argc, reg_t *argv); @@ -326,10 +306,6 @@ reg_t kTimesCot(EngineState *s, int argc, reg_t *argv); reg_t kCosDiv(EngineState *s, int argc, reg_t *argv); reg_t kSinDiv(EngineState *s, int argc, reg_t *argv); reg_t kValidPath(EngineState *s, int argc, reg_t *argv); -reg_t kFOpen(EngineState *s, int argc, reg_t *argv); -reg_t kFPuts(EngineState *s, int argc, reg_t *argv); -reg_t kFGets(EngineState *s, int argc, reg_t *argv); -reg_t kFClose(EngineState *s, int argc, reg_t *argv); reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv); reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv); reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv); @@ -436,6 +412,7 @@ reg_t kListAt(EngineState *s, int argc, reg_t *argv); reg_t kString(EngineState *s, int argc, reg_t *argv); reg_t kMulDiv(EngineState *s, int argc, reg_t *argv); reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv); +reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv); // "Screen items" in SCI32 are views reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv); reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv); @@ -458,10 +435,15 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv); reg_t kInPolygon(EngineState *s, int argc, reg_t *argv); reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv); reg_t kEditText(EngineState *s, int argc, reg_t *argv); +reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv); +reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv); +reg_t kSetScroll(EngineState *s, int argc, reg_t *argv); +reg_t kPalCycle(EngineState *s, int argc, reg_t *argv); // SCI2.1 Kernel Functions reg_t kText(EngineState *s, int argc, reg_t *argv); reg_t kSave(EngineState *s, int argc, reg_t *argv); +reg_t kAutoSave(EngineState *s, int argc, reg_t *argv); reg_t kList(EngineState *s, int argc, reg_t *argv); reg_t kRobot(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv); @@ -473,12 +455,16 @@ reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv); reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv); reg_t kWinHelp(EngineState *s, int argc, reg_t *argv); reg_t kGetConfig(EngineState *s, int argc, reg_t *argv); +reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv); reg_t kCelInfo(EngineState *s, int argc, reg_t *argv); reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv); reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv); reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv); reg_t kFont(EngineState *s, int argc, reg_t *argv); reg_t kBitmap(EngineState *s, int argc, reg_t *argv); +reg_t kAddLine(EngineState *s, int argc, reg_t *argv); +reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv); +reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv); // SCI3 Kernel functions reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv); @@ -556,6 +542,7 @@ reg_t kFileIOWriteByte(EngineState *s, int argc, reg_t *argv); reg_t kFileIOReadWord(EngineState *s, int argc, reg_t *argv); reg_t kFileIOWriteWord(EngineState *s, int argc, reg_t *argv); reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv); +reg_t kFileIOIsValidDirectory(EngineState *s, int argc, reg_t *argv); #endif //@} diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 622511c906..f5f46285be 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -239,12 +239,27 @@ static const SciKernelMapSubEntry kFileIO_subops[] = { { SIG_SCI32, 15, MAP_CALL(FileIOReadWord), "i", NULL }, { SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL }, { SIG_SCI32, 17, MAP_CALL(FileIOCreateSaveSlot), "ir", NULL }, - { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo + { SIG_SCI32, 18, MAP_EMPTY(FileIOChangeDirectory), "r", NULL }, // for SQ6, when changing the savegame directory in the save/load dialog + { SIG_SCI32, 19, MAP_CALL(FileIOIsValidDirectory), "r", NULL }, // for Torin / Torin demo #endif SCI_SUBOPENTRY_TERMINATOR }; #ifdef ENABLE_SCI32 + +static const SciKernelMapSubEntry kSave_subops[] = { + { SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL }, + { SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL }, + { SIG_SCI32, 2, MAP_CALL(GetSaveDir), "(r*)", NULL }, + { SIG_SCI32, 3, MAP_CALL(CheckSaveGame), ".*", NULL }, + // Subop 4 hasn't been encountered yet + { SIG_SCI32, 5, MAP_CALL(GetSaveFiles), "rrr", NULL }, + { SIG_SCI32, 6, MAP_CALL(MakeSaveCatName), "rr", NULL }, + { SIG_SCI32, 7, MAP_CALL(MakeSaveFileName), "rri", NULL }, + { SIG_SCI32, 8, MAP_CALL(AutoSave), "[o0]", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kList_subops[] = { { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL }, @@ -337,10 +352,10 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(EditControl), SIG_EVERYWHERE, "[o0][o0]", NULL, NULL }, { MAP_CALL(Empty), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(EmptyList), SIG_EVERYWHERE, "l", NULL, NULL }, - { MAP_CALL(FClose), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(FGets), SIG_EVERYWHERE, "rii", NULL, NULL }, - { MAP_CALL(FOpen), SIG_EVERYWHERE, "ri", NULL, NULL }, - { MAP_CALL(FPuts), SIG_EVERYWHERE, "ir", NULL, NULL }, + { "FClose", kFileIOClose, SIG_EVERYWHERE, "i", NULL, NULL }, + { "FGets", kFileIOReadString, SIG_EVERYWHERE, "rii", NULL, NULL }, + { "FOpen", kFileIOOpen, SIG_EVERYWHERE, "ri", NULL, NULL }, + { "FPuts", kFileIOWriteString, SIG_EVERYWHERE, "ir", NULL, NULL }, { MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", kFileIO_subops, NULL }, { MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds }, { MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL }, @@ -404,7 +419,10 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL }, { MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(RemapColors), SIG_EVERYWHERE, "i(i)(i)(i)(i)(i)", NULL, NULL }, + { MAP_CALL(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL }, +#ifdef ENABLE_SCI32 + { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", NULL, NULL }, +#endif { MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL }, { MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL }, { MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL }, @@ -500,29 +518,23 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL }, { MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL }, - - // SCI2 unmapped functions - TODO! - - // SetScroll - called by script 64909, Styler::doit() - // PalCycle - called by Game::newRoom. Related to RemapColors. - // VibrateMouse - used in QFG4 + { MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL }, + { MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL }, + { MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL }, + { MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // SCI2 Empty functions // Debug function used to track resources { MAP_EMPTY(ResourceTrack), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - - // SCI2 functions that are used in the original save/load menus. Marked as dummy, so - // that the engine errors out on purpose. TODO: Implement once the original save/load - // menus are implemented. - - // Creates the name of the save catalogue/directory to save into. - // TODO: Implement once the original save/load menus are implemented. - { MAP_DUMMY(MakeSaveCatName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - - // Creates the name of the save file to save into - // TODO: Implement once the original save/load menus are implemented. - { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // Future TODO: This call is used in the floppy version of QFG4 to add + // vibration to exotic mice with force feedback, such as the Logitech + // Cyberman and Wingman mice. Since this is only used for very exotic + // hardware and we have no direct and cross-platform way of communicating + // with them via SDL, plus we would probably need to make changes to common + // code, this call is mapped to an empty function for now as it's a rare + // feature not worth the effort. + { MAP_EMPTY(VibrateMouse), SIG_EVERYWHERE, "(.*)", NULL, NULL }, // Unused / debug SCI2 unused functions, always mapped to kDummy @@ -549,6 +561,11 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // SetScroll is called by script 64909, Styler::doit(), but it doesn't seem to + // be used at all (plus, it was then changed to a dummy function in SCI3). + // Since this is most likely unused, and we got no test case, error out when + // it is called in order to find an actual call to it. + { MAP_DUMMY(SetScroll), SIG_EVERYWHERE, "(.*)", NULL, NULL }, // SCI2.1 Kernel Functions { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -557,18 +574,22 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(Save), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL }, { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL }, { MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(GetConfig), SIG_EVERYWHERE, "ro", NULL, NULL }, + { MAP_CALL(GetSierraProfileInt), SIG_EVERYWHERE, "rri", NULL, NULL }, { MAP_CALL(CelInfo), SIG_EVERYWHERE, "iiiiii", NULL, NULL }, { MAP_CALL(SetLanguage), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "io(.*)", NULL, NULL }, { MAP_CALL(SetFontRes), SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL }, + { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "[r0]oiiiiiiiii", NULL, NULL }, + { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "[r0]o", NULL, NULL }, // SCI2.1 Empty Functions @@ -582,11 +603,6 @@ static SciKernelMapEntry s_kernelMap[] = { // the game window in Phantasmagoria 2. We ignore these settings completely. { MAP_EMPTY(SetWindowsOption), SIG_EVERYWHERE, "ii", NULL, NULL }, - // Used by the Windows version of Phantasmagoria 1 to get the video speed setting. This is called after - // kGetConfig and overrides the setting obtained by it. It is a dummy function in the DOS Version. We can - // just use GetConfig and mark this one as empty, like the DOS version does. - { MAP_EMPTY(GetSierraProfileInt), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - // Debug function called whenever the current room changes { MAP_EMPTY(NewRoom), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -618,14 +634,14 @@ static SciKernelMapEntry s_kernelMap[] = { // SCI2.1 unmapped functions - TODO! + // SetHotRectangles - used by Phantasmagoria 1, script 64981 (used in the chase scene) + // <lskovlun> The idea, if I understand correctly, is that the engine generates events + // of a special HotRect type continuously when the mouse is on that rectangle + // MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons - // AddLine - used by Torin's Passage to highlight the chapter buttons - // DeleteLine - used by Torin's Passage to delete the highlight from the chapter buttons - // UpdateLine - used by LSL6 // SetPalStyleRange - 2 integer parameters, start and end. All styles from start-end // (inclusive) are set to 0 // MorphOn - used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270) - // SetHotRectangles - used by Phantasmagoria 1 // SCI3 Kernel Functions { MAP_CALL(PlayDuck), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -820,7 +836,7 @@ static const char *const sci2_default_knames[] = { /*0x20*/ "AddMagnify", /*0x21*/ "DeleteMagnify", /*0x22*/ "IsHiRes", - /*0x23*/ "Graph", + /*0x23*/ "Graph", // Robot in early SCI2.1 games with a SCI2 kernel table /*0x24*/ "InvertRect", // only in SCI2, not used in any SCI2 game /*0x25*/ "TextSize", /*0x26*/ "Message", @@ -831,7 +847,7 @@ static const char *const sci2_default_knames[] = { /*0x2b*/ "EditText", /*0x2c*/ "InputText", // unused function /*0x2d*/ "CreateTextBitmap", - /*0x2e*/ "DisposeTextBitmap", + /*0x2e*/ "DisposeTextBitmap", // Priority in early SCI2.1 games with a SCI2 kernel table /*0x2f*/ "GetEvent", /*0x30*/ "GlobalToLocal", /*0x31*/ "LocalToGlobal", @@ -1091,7 +1107,7 @@ static const char *const sci21_default_knames[] = { /*0x8a*/ "LoadChunk", /*0x8b*/ "SetPalStyleRange", /*0x8c*/ "AddPicAt", - /*0x8d*/ "MessageBox", // SCI3, was Dummy in SCI2.1 + /*0x8d*/ "Dummy", // MessageBox in SCI3 /*0x8e*/ "NewRoom", // debug function /*0x8f*/ "Dummy", /*0x90*/ "Priority", @@ -1105,7 +1121,7 @@ static const char *const sci21_default_knames[] = { /*0x98*/ "GetWindowsOption", // Windows only /*0x99*/ "WinDLL", // Windows only /*0x9a*/ "Dummy", - /*0x9b*/ "Minimize", // SCI3, was Dummy in SCI2.1 + /*0x9b*/ "Dummy", // Minimize in SCI3 /*0x9c*/ "DeletePic", // == SCI3 only =============== /*0x9d*/ "Dummy", @@ -1119,57 +1135,73 @@ static const char *const sci21_default_knames[] = { // Base set of opcode formats. They're copied and adjusted slightly in // script_adjust_opcode_format depending on SCI version. static const opcode_format g_base_opcode_formats[128][4] = { - /*00*/ + // 00 - 03 / bnot, add, sub, mul {Script_None}, {Script_None}, {Script_None}, {Script_None}, - /*04*/ + // 04 - 07 / div, mod, shr, shl {Script_None}, {Script_None}, {Script_None}, {Script_None}, - /*08*/ + // 08 - 0B / xor, and, or, neg {Script_None}, {Script_None}, {Script_None}, {Script_None}, - /*0C*/ + // 0C - 0F / not, eq, ne, gt {Script_None}, {Script_None}, {Script_None}, {Script_None}, - /*10*/ + // 10 - 13 / ge, lt, le, ugt {Script_None}, {Script_None}, {Script_None}, {Script_None}, - /*14*/ + // 14 - 17 / uge, ult, ule, bt {Script_None}, {Script_None}, {Script_None}, {Script_SRelative}, - /*18*/ + // 18 - 1B / bnt, jmp, ldi, push {Script_SRelative}, {Script_SRelative}, {Script_SVariable}, {Script_None}, - /*1C*/ + // 1C - 1F / pushi, toss, dup, link {Script_SVariable}, {Script_None}, {Script_None}, {Script_Variable}, - /*20*/ + // 20 - 23 / call, callk, callb, calle {Script_SRelative, Script_Byte}, {Script_Variable, Script_Byte}, {Script_Variable, Script_Byte}, {Script_Variable, Script_SVariable, Script_Byte}, - /*24 (24=ret)*/ + // 24 - 27 / ret, send, dummy, dummy {Script_End}, {Script_Byte}, {Script_Invalid}, {Script_Invalid}, - /*28*/ + // 28 - 2B / class, dummy, self, super {Script_Variable}, {Script_Invalid}, {Script_Byte}, {Script_Variable, Script_Byte}, - /*2C*/ + // 2C - 2F / rest, lea, selfID, dummy {Script_SVariable}, {Script_SVariable, Script_Variable}, {Script_None}, {Script_Invalid}, - /*30*/ + // 30 - 33 / pprev, pToa, aTop, pTos {Script_None}, {Script_Property}, {Script_Property}, {Script_Property}, - /*34*/ + // 34 - 37 / sTop, ipToa, dpToa, ipTos {Script_Property}, {Script_Property}, {Script_Property}, {Script_Property}, - /*38*/ + // 38 - 3B / dpTos, lofsa, lofss, push0 {Script_Property}, {Script_SRelative}, {Script_SRelative}, {Script_None}, - /*3C*/ + // 3C - 3F / push1, push2, pushSelf, line {Script_None}, {Script_None}, {Script_None}, {Script_Word}, - /*40-4F*/ + // ------------------------------------------------------------------------ + // 40 - 43 / lag, lal, lat, lap {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 44 - 47 / lsg, lsl, lst, lsp {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 48 - 4B / lagi, lali, lati, lapi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 4C - 4F / lsgi, lsli, lsti, lspi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, - /*50-5F*/ + // ------------------------------------------------------------------------ + // 50 - 53 / sag, sal, sat, sap {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 54 - 57 / ssg, ssl, sst, ssp {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 58 - 5B / sagi, sali, sati, sapi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 5C - 5F / ssgi, ssli, ssti, sspi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, - /*60-6F*/ + // ------------------------------------------------------------------------ + // 60 - 63 / plusag, plusal, plusat, plusap {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 64 - 67 / plussg, plussl, plusst, plussp {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 68 - 6B / plusagi, plusali, plusati, plusapi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 6C - 6F / plussgi, plussli, plussti, plusspi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, - /*70-7F*/ + // ------------------------------------------------------------------------ + // 70 - 73 / minusag, minusal, minusat, minusap {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 74 - 77 / minussg, minussl, minusst, minussp {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 78 - 7B / minusagi, minusali, minusati, minusapi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param}, + // 7C - 7F / minussgi, minussli, minussti, minusspi {Script_Global}, {Script_Local}, {Script_Temp}, {Script_Param} }; #undef END diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index df3b3efd57..34477cc23b 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -157,7 +157,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { s->r_acc = NULL_REG; } - if ((s->r_acc.offset) && (g_sci->_debugState.stopOnEvent)) { + if ((s->r_acc.getOffset()) && (g_sci->_debugState.stopOnEvent)) { g_sci->_debugState.stopOnEvent = false; // A SCI event occurred, and we have been asked to stop, so open the debug console @@ -248,7 +248,7 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) { reg_t planeObject = argc > 1 ? argv[1] : NULL_REG; // SCI32 SegManager *segMan = s->_segMan; - if (obj.segment) { + if (obj.getSegment()) { int16 x = readSelectorValue(segMan, obj, SELECTOR(x)); int16 y = readSelectorValue(segMan, obj, SELECTOR(y)); @@ -267,7 +267,7 @@ reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) { reg_t planeObject = argc > 1 ? argv[1] : NULL_REG; // SCI32 SegManager *segMan = s->_segMan; - if (obj.segment) { + if (obj.getSegment()) { int16 x = readSelectorValue(segMan, obj, SELECTOR(x)); int16 y = readSelectorValue(segMan, obj, SELECTOR(y)); diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 312497720a..f7cc4f44b5 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -33,6 +33,7 @@ #include "gui/saveload.h" #include "sci/sci.h" +#include "sci/engine/file.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/engine/savegame.h" @@ -40,209 +41,11 @@ namespace Sci { -struct SavegameDesc { - int16 id; - int virtualId; // straight numbered, according to id but w/o gaps - int date; - int time; - int version; - char name[SCI_MAX_SAVENAME_LENGTH]; -}; - -/* - * Note on how file I/O is implemented: In ScummVM, one can not create/write - * arbitrary data files, simply because many of our target platforms do not - * support this. The only files one can create are savestates. But SCI has an - * opcode to create and write to seemingly 'arbitrary' files. This is mainly - * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver, used - * for persisting the results of the "age quiz" across restarts) and in LSL5 - * for MEMORY.DRV (which is again a game data file and contains the game's - * password, XOR encrypted). - * To implement that opcode, we combine the SaveFileManager with regular file - * code, similarly to how the SCUMM HE engine does it. - * - * To handle opening a file called "foobar", what we do is this: First, we - * create an 'augmented file name', by prepending the game target and a dash, - * so if we running game target sq1sci, the name becomes "sq1sci-foobar". - * Next, we check if such a file is known to the SaveFileManager. If so, we - * we use that for reading/writing, delete it, whatever. - * - * If no such file is present but we were only asked to *read* the file, - * we fallback to looking for a regular file called "foobar", and open that - * for reading only. - */ - - - -FileHandle::FileHandle() : _in(0), _out(0) { -} - -FileHandle::~FileHandle() { - close(); -} - -void FileHandle::close() { - delete _in; - delete _out; - _in = 0; - _out = 0; - _name.clear(); -} - -bool FileHandle::isOpen() const { - return _in || _out; -} - - - -enum { - _K_FILE_MODE_OPEN_OR_CREATE = 0, - _K_FILE_MODE_OPEN_OR_FAIL = 1, - _K_FILE_MODE_CREATE = 2 -}; - - - -reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename) { - Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH); - Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName; - Common::SeekableReadStream *inFile = 0; - Common::WriteStream *outFile = 0; - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - - if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { - // Try to open file, abort if not possible - inFile = saveFileMan->openForLoading(wrappedName); - // If no matching savestate exists: fall back to reading from a regular - // file - if (!inFile) - inFile = SearchMan.createReadStreamForMember(englishName); - - if (!inFile) - debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str()); - } else if (mode == _K_FILE_MODE_CREATE) { - // Create the file, destroying any content it might have had - outFile = saveFileMan->openForSaving(wrappedName); - if (!outFile) - debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str()); - } else if (mode == _K_FILE_MODE_OPEN_OR_CREATE) { - // Try to open file, create it if it doesn't exist - outFile = saveFileMan->openForSaving(wrappedName); - if (!outFile) - debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str()); - // QfG1 opens the character export file with _K_FILE_MODE_CREATE first, - // closes it immediately and opens it again with this here. Perhaps - // other games use this for read access as well. I guess changing this - // whole code into using virtual files and writing them after close - // would be more appropriate. - } else { - error("file_open: unsupported mode %d (filename '%s')", mode, englishName.c_str()); - } - - if (!inFile && !outFile) { // Failed - debugC(kDebugLevelFile, " -> file_open() failed"); - return SIGNAL_REG; - } - - // Find a free file handle - uint handle = 1; // Ignore _fileHandles[0] - while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) - handle++; - - if (handle == s->_fileHandles.size()) { - // Hit size limit => Allocate more space - s->_fileHandles.resize(s->_fileHandles.size() + 1); - } - - s->_fileHandles[handle]._in = inFile; - s->_fileHandles[handle]._out = outFile; - s->_fileHandles[handle]._name = englishName; - - debugC(kDebugLevelFile, " -> opened file '%s' with handle %d", englishName.c_str(), handle); - return make_reg(0, handle); -} - -reg_t kFOpen(EngineState *s, int argc, reg_t *argv) { - Common::String name = s->_segMan->getString(argv[0]); - int mode = argv[1].toUint16(); - - debugC(kDebugLevelFile, "kFOpen(%s,0x%x)", name.c_str(), mode); - return file_open(s, name, mode, true); -} - -static FileHandle *getFileFromHandle(EngineState *s, uint handle) { - if (handle == 0) { - error("Attempt to use file handle 0"); - return 0; - } - - if ((handle >= s->_fileHandles.size()) || !s->_fileHandles[handle].isOpen()) { - warning("Attempt to use invalid/unused file handle %d", handle); - return 0; - } - - return &s->_fileHandles[handle]; -} - -reg_t kFClose(EngineState *s, int argc, reg_t *argv) { - debugC(kDebugLevelFile, "kFClose(%d)", argv[0].toUint16()); - if (argv[0] != SIGNAL_REG) { - FileHandle *f = getFileFromHandle(s, argv[0].toUint16()); - if (f) - f->close(); - } - return s->r_acc; -} - -reg_t kFPuts(EngineState *s, int argc, reg_t *argv) { - int handle = argv[0].toUint16(); - Common::String data = s->_segMan->getString(argv[1]); - - FileHandle *f = getFileFromHandle(s, handle); - if (f) - f->_out->write(data.c_str(), data.size()); - - return s->r_acc; -} - -static int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) { - FileHandle *f = getFileFromHandle(s, handle); - if (!f) - return 0; - - if (!f->_in) { - error("fgets_wrapper: Trying to read from file '%s' opened for writing", f->_name.c_str()); - return 0; - } - int readBytes = 0; - if (maxsize > 1) { - memset(dest, 0, maxsize); - f->_in->readLine(dest, maxsize); - readBytes = strlen(dest); // FIXME: sierra sci returned byte count and didn't react on NUL characters - // The returned string must not have an ending LF - if (readBytes > 0) { - if (dest[readBytes - 1] == 0x0A) - dest[readBytes - 1] = 0; - } - } else { - *dest = 0; - } - - debugC(kDebugLevelFile, " -> FGets'ed \"%s\"", dest); - return readBytes; -} - -reg_t kFGets(EngineState *s, int argc, reg_t *argv) { - int maxsize = argv[1].toUint16(); - char *buf = new char[maxsize]; - int handle = argv[2].toUint16(); - - debugC(kDebugLevelFile, "kFGets(%d, %d)", handle, maxsize); - int readBytes = fgets_wrapper(s, buf, maxsize, handle); - s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize); - delete[] buf; - return readBytes ? argv[0] : NULL_REG; -} +extern reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool unwrapFilename); +extern FileHandle *getFileFromHandle(EngineState *s, uint handle); +extern int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle); +extern void listSavegames(Common::Array<SavegameDesc> &saves); +extern int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId); /** * Writes the cwd to the supplied address and returns the address in acc. @@ -258,9 +61,6 @@ reg_t kGetCWD(EngineState *s, int argc, reg_t *argv) { return argv[0]; } -static void listSavegames(Common::Array<SavegameDesc> &saves); -static int findSavegame(Common::Array<SavegameDesc> &saves, int16 saveId); - enum { K_DEVICE_INFO_GET_DEVICE = 0, K_DEVICE_INFO_GET_CURRENT_DEVICE = 1, @@ -331,7 +131,7 @@ reg_t kDeviceInfo(EngineState *s, int argc, reg_t *argv) { s->_segMan->strcpy(argv[1], "__throwaway"); debug(3, "K_DEVICE_INFO_GET_SAVEFILE_NAME(%s,%d) -> %s", game_prefix.c_str(), virtualId, "__throwaway"); if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) - error("kDeviceInfo(deleteSave): invalid savegame-id specified"); + error("kDeviceInfo(deleteSave): invalid savegame ID specified"); uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; Common::Array<SavegameDesc> saves; listSavegames(saves); @@ -352,18 +152,6 @@ reg_t kDeviceInfo(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) { -#ifdef ENABLE_SCI32 - // SCI32 uses a parameter here. It is used to modify a string, stored in a - // global variable, so that game scripts store the save directory. We - // don't really set a save game directory, thus not setting the string to - // anything is the correct thing to do here. - //if (argc > 0) - // warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0])); -#endif - return s->_segMan->getSaveDirPtr(); -} - reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) { if (argc > 1) { // SCI1.1/SCI32 @@ -394,354 +182,43 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) { return make_reg(0, 1); } -static bool _savegame_sort_byDate(const SavegameDesc &l, const SavegameDesc &r) { - if (l.date != r.date) - return (l.date > r.date); - return (l.time > r.time); -} - -// Create a sorted array containing all found savedgames -static void listSavegames(Common::Array<SavegameDesc> &saves) { - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - - // Load all saves - Common::StringArray saveNames = saveFileMan->listSavefiles(g_sci->getSavegamePattern()); - - for (Common::StringArray::const_iterator iter = saveNames.begin(); iter != saveNames.end(); ++iter) { - Common::String filename = *iter; - Common::SeekableReadStream *in; - if ((in = saveFileMan->openForLoading(filename))) { - SavegameMetadata meta; - if (!get_savegame_metadata(in, &meta) || meta.name.empty()) { - // invalid - delete in; - continue; - } - delete in; - - SavegameDesc desc; - desc.id = strtol(filename.end() - 3, NULL, 10); - desc.date = meta.saveDate; - // We need to fix date in here, because we save DDMMYYYY instead of - // YYYYMMDD, so sorting wouldn't work - desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24); - desc.time = meta.saveTime; - desc.version = meta.version; - - if (meta.name.lastChar() == '\n') - meta.name.deleteLastChar(); - - Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH); - - debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id); - - saves.push_back(desc); - } - } - - // Sort the list by creation date of the saves - Common::sort(saves.begin(), saves.end(), _savegame_sort_byDate); -} - -// Find a savedgame according to virtualId and return the position within our array -static int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId) { - for (uint saveNr = 0; saveNr < saves.size(); saveNr++) { - if (saves[saveNr].id == savegameId) - return saveNr; - } - return -1; -} - -// The scripts get IDs ranging from 100->199, because the scripts require us to assign unique ids THAT EVEN STAY BETWEEN -// SAVES and the scripts also use "saves-count + 1" to create a new savedgame slot. -// SCI1.1 actually recycles ids, in that case we will currently get "0". -// This behavior is required especially for LSL6. In this game, it's possible to quick save. The scripts will use -// the last-used id for that feature. If we don't assign sticky ids, the feature will overwrite different saves all the -// time. And sadly we can't just use the actual filename ids directly, because of the creation method for new slots. - -bool Console::cmdListSaves(int argc, const char **argv) { - Common::Array<SavegameDesc> saves; - listSavegames(saves); - - for (uint i = 0; i < saves.size(); i++) { - Common::String filename = g_sci->getSavegameName(saves[i].id); - DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name); - } - - return true; -} - -reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) { - Common::String game_id = s->_segMan->getString(argv[0]); - uint16 virtualId = argv[1].toUint16(); - - debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), virtualId); - - Common::Array<SavegameDesc> saves; - listSavegames(saves); - - // we allow 0 (happens in QfG2 when trying to restore from an empty saved game list) and return false in that case - if (virtualId == 0) - return NULL_REG; - - // Find saved-game - if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) - error("kCheckSaveGame: called with invalid savegameId"); - uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; - int savegameNr = findSavegame(saves, savegameId); - if (savegameNr == -1) - return NULL_REG; - - // Check for compatible savegame version - int ver = saves[savegameNr].version; - if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION) - return NULL_REG; - - // Otherwise we assume the savegame is OK - return TRUE_REG; -} - -reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) { - Common::String game_id = s->_segMan->getString(argv[0]); - - debug(3, "kGetSaveFiles(%s)", game_id.c_str()); - - // Scripts ask for current save files, we can assume that if afterwards they ask us to create a new slot they really - // mean new slot instead of overwriting the old one - s->_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START; - - Common::Array<SavegameDesc> saves; - listSavegames(saves); - uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR); - - reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves); - - if (!slot) { - warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2])); - totalSaves = 0; - } - - const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1; - char *saveNames = new char[bufSize]; - char *saveNamePtr = saveNames; - - for (uint i = 0; i < totalSaves; i++) { - *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame-id ffs. see above - strcpy(saveNamePtr, saves[i].name); - saveNamePtr += SCI_MAX_SAVENAME_LENGTH; - } - - *saveNamePtr = 0; // Terminate list - - s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize); - delete[] saveNames; - - return make_reg(0, totalSaves); -} - -reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { - Common::String game_id; - int16 virtualId = argv[1].toSint16(); - int16 savegameId = -1; - Common::String game_description; - Common::String version; - - if (argc > 3) - version = s->_segMan->getString(argv[3]); - - // We check here, we don't want to delete a users save in case we are within a kernel function - if (s->executionStackBase) { - warning("kSaveGame - won't save from within kernel function"); - return NULL_REG; - } - - if (argv[0].isNull()) { - // Direct call, from a patched Game::save - if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull())) - error("kSaveGame: assumed patched call isn't accurate"); - - // we are supposed to show a dialog for the user and let him choose where to save - g_sci->_soundCmd->pauseAll(true); // pause music - const EnginePlugin *plugin = NULL; - EngineMan.findGame(g_sci->getGameIdStr(), &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); - dialog->setSaveMode(true); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); - game_description = dialog->getResultString(); - if (game_description.empty()) { - // create our own description for the saved game, the user didnt enter it - #if defined(USE_SAVEGAME_TIMESTAMP) - TimeDate curTime; - g_system->getTimeAndDate(curTime); - curTime.tm_year += 1900; // fixup year - curTime.tm_mon++; // fixup month - game_description = Common::String::format("%04d.%02d.%02d / %02d:%02d:%02d", curTime.tm_year, curTime.tm_mon, curTime.tm_mday, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); - #else - game_description = Common::String::format("Save %d", savegameId + 1); - #endif - } - delete dialog; - g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save) - if (savegameId < 0) - return NULL_REG; - - } else { - // Real call from script - game_id = s->_segMan->getString(argv[0]); - if (argv[2].isNull()) - error("kSaveGame: called with description being NULL"); - game_description = s->_segMan->getString(argv[2]); - - debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), virtualId, game_description.c_str(), version.c_str()); - - Common::Array<SavegameDesc> saves; - listSavegames(saves); - - if ((virtualId >= SAVEGAMEID_OFFICIALRANGE_START) && (virtualId <= SAVEGAMEID_OFFICIALRANGE_END)) { - // savegameId is an actual Id, so search for it just to make sure - savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; - if (findSavegame(saves, savegameId) == -1) - return NULL_REG; - } else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) { - // virtualId is low, we assume that scripts expect us to create new slot - if (virtualId == s->_lastSaveVirtualId) { - // if last virtual id is the same as this one, we assume that caller wants to overwrite last save - savegameId = s->_lastSaveNewId; - } else { - uint savegameNr; - // savegameId is in lower range, scripts expect us to create a new slot - for (savegameId = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; savegameId++) { - for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) { - if (savegameId == saves[savegameNr].id) - break; - } - if (savegameNr == saves.size()) - break; - } - if (savegameId == SAVEGAMEID_OFFICIALRANGE_START) - error("kSavegame: no more savegame slots available"); - } - } else { - error("kSaveGame: invalid savegameId used"); - } - - // Save in case caller wants to overwrite last newly created save - s->_lastSaveVirtualId = virtualId; - s->_lastSaveNewId = savegameId; - } - - s->r_acc = NULL_REG; - - Common::String filename = g_sci->getSavegameName(savegameId); - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - Common::OutSaveFile *out; - - out = saveFileMan->openForSaving(filename); - if (!out) { - warning("Error opening savegame \"%s\" for writing", filename.c_str()); - } else { - if (!gamestate_save(s, out, game_description, version)) { - warning("Saving the game failed"); - } else { - s->r_acc = TRUE_REG; // save successful - } +reg_t kValidPath(EngineState *s, int argc, reg_t *argv) { + Common::String path = s->_segMan->getString(argv[0]); - out->finalize(); - if (out->err()) { - warning("Writing the savegame failed"); - s->r_acc = NULL_REG; // write failure - } - delete out; - } + debug(3, "kValidPath(%s) -> %d", path.c_str(), s->r_acc.getOffset()); - return s->r_acc; + // Always return true + return make_reg(0, 1); } -reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { - Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : ""; - int16 savegameId = argv[1].toSint16(); - bool pausedMusic = false; - - debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId); +#ifdef ENABLE_SCI32 - if (argv[0].isNull()) { - // Direct call, either from launcher or from a patched Game::restore - if (savegameId == -1) { - // we are supposed to show a dialog for the user and let him choose a saved game - g_sci->_soundCmd->pauseAll(true); // pause music - const EnginePlugin *plugin = NULL; - EngineMan.findGame(g_sci->getGameIdStr(), &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore")); - dialog->setSaveMode(false); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); - delete dialog; - if (savegameId < 0) { - g_sci->_soundCmd->pauseAll(false); // unpause music - return s->r_acc; - } - pausedMusic = true; - } - // don't adjust ID of the saved game, it's already correct - } else { - if (argv[2].isNull()) - error("kRestoreGame: called with parameter 2 being NULL"); - // Real call from script, we need to adjust ID - if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) { - warning("Savegame ID %d is not allowed", savegameId); +reg_t kCD(EngineState *s, int argc, reg_t *argv) { + // TODO: Stub + switch (argv[0].toUint16()) { + case 0: + if (argc == 1) { + // Check if a disc is in the drive return TRUE_REG; - } - savegameId -= SAVEGAMEID_OFFICIALRANGE_START; - } - - s->r_acc = NULL_REG; // signals success - - Common::Array<SavegameDesc> saves; - listSavegames(saves); - if (findSavegame(saves, savegameId) == -1) { - s->r_acc = TRUE_REG; - warning("Savegame ID %d not found", savegameId); - } else { - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - Common::String filename = g_sci->getSavegameName(savegameId); - Common::SeekableReadStream *in; - - in = saveFileMan->openForLoading(filename); - if (in) { - // found a savegame file - - gamestate_restore(s, in); - delete in; - - if (g_sci->getGameId() == GID_MOTHERGOOSE256) { - // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for - // saving a previously restored game. - // We set the current savedgame-id directly and remove the script - // code concerning this via script patch. - s->variables[VAR_GLOBAL][0xB3].offset = SAVEGAMEID_OFFICIALRANGE_START + savegameId; - } } else { - s->r_acc = TRUE_REG; - warning("Savegame #%d not found", savegameId); + // Check if the specified disc is in the drive + // and return the current disc number. We just + // return the requested disc number. + return argv[1]; } + case 1: + // Return the current CD number + return make_reg(0, 1); + default: + warning("CD(%d)", argv[0].toUint16()); } - if (!s->r_acc.isNull()) { - // no success? - if (pausedMusic) - g_sci->_soundCmd->pauseAll(false); // unpause music - } - - return s->r_acc; + return NULL_REG; } -reg_t kValidPath(EngineState *s, int argc, reg_t *argv) { - Common::String path = s->_segMan->getString(argv[0]); - - debug(3, "kValidPath(%s) -> %d", path.c_str(), s->r_acc.offset); +#endif - // Always return true - return make_reg(0, 1); -} +// ---- FileIO operations ----------------------------------------------------- reg_t kFileIO(EngineState *s, int argc, reg_t *argv) { if (!s) @@ -779,6 +256,73 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { } debugC(kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode); +#ifdef ENABLE_SCI32 + if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { + if (s->_virtualIndexFile) { + return make_reg(0, VIRTUALFILE_HANDLE); + } else { + Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH); + Common::String wrappedName = g_sci->wrapFilename(englishName); + if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) { + s->_virtualIndexFile = new VirtualIndexFile(wrappedName); + return make_reg(0, VIRTUALFILE_HANDLE); + } + } + } + + // Shivers is trying to store savegame descriptions and current spots in + // separate .SG files, which are hardcoded in the scripts. + // Essentially, there is a normal save file, created by the executable + // and an extra hardcoded save file, created by the game scripts, probably + // because they didn't want to modify the save/load code to add the extra + // information. + // Each slot in the book then has two strings, the save description and a + // description of the current spot that the player is at. Currently, the + // spot strings are always empty (probably related to the unimplemented + // kString subop 14, which gets called right before this call). + // For now, we don't allow the creation of these files, which means that + // all the spot descriptions next to each slot description will be empty + // (they are empty anyway). Until a viable solution is found to handle these + // extra files and until the spot description strings are initialized + // correctly, we resort to virtual files in order to make the load screen + // useable. Without this code it is unusable, as the extra information is + // always saved to 0.SG for some reason, but on restore the correct file is + // used. Perhaps the virtual ID is not taken into account when saving. + // + // Future TODO: maintain spot descriptions and show them too, ideally without + // having to return to this logic of extra hardcoded files. + if (g_sci->getGameId() == GID_SHIVERS && name.hasSuffix(".SG")) { + if (mode == _K_FILE_MODE_OPEN_OR_CREATE || mode == _K_FILE_MODE_CREATE) { + // Game scripts are trying to create a file with the save + // description, stop them here + debugC(kDebugLevelFile, "Not creating unused file %s", name.c_str()); + return SIGNAL_REG; + } else if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { + // Create a virtual file containing the save game description + // and slot number, as the game scripts expect. + int slotNumber; + sscanf(name.c_str(), "%d.SG", &slotNumber); + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START); + + if (!s->_virtualIndexFile) { + // Make the virtual file buffer big enough to avoid having it grow dynamically. + // 50 bytes should be more than enough. + s->_virtualIndexFile = new VirtualIndexFile(50); + } + + s->_virtualIndexFile->seek(0, SEEK_SET); + s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name)); + s->_virtualIndexFile->write("\0", 1); + s->_virtualIndexFile->write("\0", 1); // Spot description (empty) + s->_virtualIndexFile->seek(0, SEEK_SET); + return make_reg(0, VIRTUALFILE_HANDLE); + } + } +#endif + // QFG import rooms get a virtual filelisting instead of an actual one if (g_sci->inQfGImportRoom()) { // We need to find out what the user actually selected, "savedHeroes" is @@ -794,44 +338,82 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) { debugC(kDebugLevelFile, "kFileIO(close): %d", argv[0].toUint16()); - FileHandle *f = getFileFromHandle(s, argv[0].toUint16()); + if (argv[0] == SIGNAL_REG) + return s->r_acc; + + uint16 handle = argv[0].toUint16(); + +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) { + s->_virtualIndexFile->close(); + return SIGNAL_REG; + } +#endif + + FileHandle *f = getFileFromHandle(s, handle); if (f) { f->close(); + if (getSciVersion() <= SCI_VERSION_0_LATE) + return s->r_acc; // SCI0 semantics: no value returned return SIGNAL_REG; } + + if (getSciVersion() <= SCI_VERSION_0_LATE) + return s->r_acc; // SCI0 semantics: no value returned return NULL_REG; } reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) { - int handle = argv[0].toUint16(); - int size = argv[2].toUint16(); + uint16 handle = argv[0].toUint16(); + uint16 size = argv[2].toUint16(); int bytesRead = 0; char *buf = new char[size]; debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size); - FileHandle *f = getFileFromHandle(s, handle); - if (f) { - bytesRead = f->_in->read(buf, size); - s->_segMan->memcpy(argv[1], (const byte*)buf, size); +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) { + bytesRead = s->_virtualIndexFile->read(buf, size); + } else { +#endif + FileHandle *f = getFileFromHandle(s, handle); + if (f) + bytesRead = f->_in->read(buf, size); +#ifdef ENABLE_SCI32 } +#endif + + // TODO: What happens if less bytes are read than what has + // been requested? (i.e. if bytesRead is non-zero, but still + // less than size) + if (bytesRead > 0) + s->_segMan->memcpy(argv[1], (const byte*)buf, size); delete[] buf; return make_reg(0, bytesRead); } reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) { - int handle = argv[0].toUint16(); - int size = argv[2].toUint16(); + uint16 handle = argv[0].toUint16(); + uint16 size = argv[2].toUint16(); char *buf = new char[size]; bool success = false; s->_segMan->memcpy((byte *)buf, argv[1], size); debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size); - FileHandle *f = getFileFromHandle(s, handle); - if (f) { - f->_out->write(buf, size); +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) { + s->_virtualIndexFile->write(buf, size); success = true; + } else { +#endif + FileHandle *f = getFileFromHandle(s, handle); + if (f) { + f->_out->write(buf, size); + success = true; + } +#ifdef ENABLE_SCI32 } +#endif delete[] buf; if (success) @@ -863,6 +445,20 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) { int savedir_nr = saves[slotNum].id; name = g_sci->getSavegameName(savedir_nr); result = saveFileMan->removeSavefile(name); + } else if (getSciVersion() >= SCI_VERSION_2) { + // The file name may be already wrapped, so check both cases + result = saveFileMan->removeSavefile(name); + if (!result) { + const Common::String wrappedName = g_sci->wrapFilename(name); + result = saveFileMan->removeSavefile(wrappedName); + } + +#ifdef ENABLE_SCI32 + if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { + delete s->_virtualIndexFile; + s->_virtualIndexFile = 0; + } +#endif } else { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); @@ -875,15 +471,22 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) { } reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) { - int size = argv[1].toUint16(); - char *buf = new char[size]; - int handle = argv[2].toUint16(); - debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, size); + uint16 maxsize = argv[1].toUint16(); + char *buf = new char[maxsize]; + uint16 handle = argv[2].toUint16(); + debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize); + uint32 bytesRead; + +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) + bytesRead = s->_virtualIndexFile->readLine(buf, maxsize); + else +#endif + bytesRead = fgets_wrapper(s, buf, maxsize, handle); - int readBytes = fgets_wrapper(s, buf, size, handle); - s->_segMan->memcpy(argv[0], (const byte*)buf, size); + s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize); delete[] buf; - return readBytes ? argv[0] : NULL_REG; + return bytesRead ? argv[0] : NULL_REG; } reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) { @@ -891,126 +494,55 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) { Common::String str = s->_segMan->getString(argv[1]); debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle); +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) { + s->_virtualIndexFile->write(str.c_str(), str.size()); + return NULL_REG; + } +#endif + FileHandle *f = getFileFromHandle(s, handle); if (f) { f->_out->write(str.c_str(), str.size()); + if (getSciVersion() <= SCI_VERSION_0_LATE) + return s->r_acc; // SCI0 semantics: no value returned return NULL_REG; } + if (getSciVersion() <= SCI_VERSION_0_LATE) + return s->r_acc; // SCI0 semantics: no value returned return make_reg(0, 6); // DOS - invalid handle } reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) { - int handle = argv[0].toUint16(); - int offset = argv[1].toUint16(); - int whence = argv[2].toUint16(); + uint16 handle = argv[0].toUint16(); + uint16 offset = ABS<int16>(argv[1].toSint16()); // can be negative + uint16 whence = argv[2].toUint16(); debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence); - FileHandle *f = getFileFromHandle(s, handle); - - if (f) - s->r_acc = make_reg(0, f->_in->seek(offset, whence)); - - return SIGNAL_REG; -} - -void DirSeeker::addAsVirtualFiles(Common::String title, Common::String fileMask) { - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - Common::StringArray foundFiles = saveFileMan->listSavefiles(fileMask); - if (!foundFiles.empty()) { - _files.push_back(title); - _virtualFiles.push_back(""); - Common::StringArray::iterator it; - Common::StringArray::iterator it_end = foundFiles.end(); - - for (it = foundFiles.begin(); it != it_end; it++) { - Common::String regularFilename = *it; - Common::String wrappedFilename = Common::String(regularFilename.c_str() + fileMask.size() - 1); - - Common::SeekableReadStream *testfile = saveFileMan->openForLoading(regularFilename); - int32 testfileSize = testfile->size(); - delete testfile; - if (testfileSize > 1024) // check, if larger than 1k. in that case its a saved game. - continue; // and we dont want to have those in the list - // We need to remove the prefix for display purposes - _files.push_back(wrappedFilename); - // but remember the actual name as well - _virtualFiles.push_back(regularFilename); - } - } -} +#ifdef ENABLE_SCI32 + if (handle == VIRTUALFILE_HANDLE) + return make_reg(0, s->_virtualIndexFile->seek(offset, whence)); +#endif -Common::String DirSeeker::getVirtualFilename(uint fileNumber) { - if (fileNumber >= _virtualFiles.size()) - error("invalid virtual filename access"); - return _virtualFiles[fileNumber]; -} + FileHandle *f = getFileFromHandle(s, handle); -reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) { - // Verify that we are given a valid buffer - if (!buffer.segment) { - error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str()); - return NULL_REG; - } - _outbuffer = buffer; - _files.clear(); - _virtualFiles.clear(); - - int QfGImport = g_sci->inQfGImportRoom(); - if (QfGImport) { - _files.clear(); - addAsVirtualFiles("-QfG1-", "qfg1-*"); - addAsVirtualFiles("-QfG1VGA-", "qfg1vga-*"); - if (QfGImport > 2) - addAsVirtualFiles("-QfG2-", "qfg2-*"); - if (QfGImport > 3) - addAsVirtualFiles("-QfG3-", "qfg3-*"); - - if (QfGImport == 3) { - // QfG3 sorts the filelisting itself, we can't let that happen otherwise our - // virtual list would go out-of-sync - reg_t savedHeros = segMan->findObjectByName("savedHeros"); - if (!savedHeros.isNull()) - writeSelectorValue(segMan, savedHeros, SELECTOR(sort), 0); + if (f && f->_in) { + // Backward seeking isn't supported in zip file streams, thus adapt the + // parameters accordingly if games ask for such a seek mode. A known + // case where this is requested is the save file manager in Phantasmagoria + if (whence == SEEK_END) { + whence = SEEK_SET; + offset = f->_in->size() - offset; } - } else { - // Prefix the mask - const Common::String wrappedMask = g_sci->wrapFilename(mask); - - // Obtain a list of all files matching the given mask - Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); - _files = saveFileMan->listSavefiles(wrappedMask); + return make_reg(0, f->_in->seek(offset, whence)); + } else if (f && f->_out) { + error("kFileIOSeek: Unsupported seek operation on a writeable stream (offset: %d, whence: %d)", offset, whence); } - // Reset the list iterator and write the first match to the output buffer, - // if any. - _iter = _files.begin(); - return nextFile(segMan); -} - -reg_t DirSeeker::nextFile(SegManager *segMan) { - if (_iter == _files.end()) { - return NULL_REG; - } - - Common::String string; - - if (_virtualFiles.empty()) { - // Strip the prefix, if we don't got a virtual filelisting - const Common::String wrappedString = *_iter; - string = g_sci->unwrapFilename(wrappedString); - } else { - string = *_iter; - } - if (string.size() > 12) - string = Common::String(string.c_str(), 12); - segMan->strcpy(_outbuffer, string.c_str()); - - // Return the result and advance the list iterator :) - ++_iter; - return _outbuffer; + return SIGNAL_REG; } reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) { @@ -1033,6 +565,14 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) { reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { Common::String name = s->_segMan->getString(argv[0]); +#ifdef ENABLE_SCI32 + // Cache the file existence result for the Phantasmagoria + // save index file, as the game scripts keep checking for + // its existence. + if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile) + return TRUE_REG; +#endif + bool exists = false; // Check for regular file @@ -1155,51 +695,328 @@ reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv) { return TRUE_REG; // slot creation was successful } -reg_t kCD(EngineState *s, int argc, reg_t *argv) { - // TODO: Stub - switch (argv[0].toUint16()) { - case 0: - // Return whether the contents of disc argv[1] is available. - return TRUE_REG; - default: - warning("CD(%d)", argv[0].toUint16()); +reg_t kFileIOIsValidDirectory(EngineState *s, int argc, reg_t *argv) { + // Used in Torin's Passage and LSL7 to determine if the directory passed as + // a parameter (usually the save directory) is valid. We always return true + // here. + return TRUE_REG; +} + +#endif + +// ---- Save operations ------------------------------------------------------- + +#ifdef ENABLE_SCI32 + +reg_t kSave(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +#endif + +reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { + Common::String game_id; + int16 virtualId = argv[1].toSint16(); + int16 savegameId = -1; + Common::String game_description; + Common::String version; + + if (argc > 3) + version = s->_segMan->getString(argv[3]); + + // We check here, we don't want to delete a users save in case we are within a kernel function + if (s->executionStackBase) { + warning("kSaveGame - won't save from within kernel function"); + return NULL_REG; } - return NULL_REG; + if (argv[0].isNull()) { + // Direct call, from a patched Game::save + if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull())) + error("kSaveGame: assumed patched call isn't accurate"); + + // we are supposed to show a dialog for the user and let him choose where to save + g_sci->_soundCmd->pauseAll(true); // pause music + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + savegameId = dialog->runModalWithCurrentTarget(); + game_description = dialog->getResultString(); + if (game_description.empty()) { + // create our own description for the saved game, the user didnt enter it + game_description = dialog->createDefaultSaveDescription(savegameId); + } + delete dialog; + g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save) + if (savegameId < 0) + return NULL_REG; + + } else { + // Real call from script + game_id = s->_segMan->getString(argv[0]); + if (argv[2].isNull()) + error("kSaveGame: called with description being NULL"); + game_description = s->_segMan->getString(argv[2]); + + debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), virtualId, game_description.c_str(), version.c_str()); + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + if ((virtualId >= SAVEGAMEID_OFFICIALRANGE_START) && (virtualId <= SAVEGAMEID_OFFICIALRANGE_END)) { + // savegameId is an actual Id, so search for it just to make sure + savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; + if (findSavegame(saves, savegameId) == -1) + return NULL_REG; + } else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) { + // virtualId is low, we assume that scripts expect us to create new slot + if (virtualId == s->_lastSaveVirtualId) { + // if last virtual id is the same as this one, we assume that caller wants to overwrite last save + savegameId = s->_lastSaveNewId; + } else { + uint savegameNr; + // savegameId is in lower range, scripts expect us to create a new slot + for (savegameId = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; savegameId++) { + for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) { + if (savegameId == saves[savegameNr].id) + break; + } + if (savegameNr == saves.size()) + break; + } + if (savegameId == SAVEGAMEID_OFFICIALRANGE_START) + error("kSavegame: no more savegame slots available"); + } + } else { + error("kSaveGame: invalid savegameId used"); + } + + // Save in case caller wants to overwrite last newly created save + s->_lastSaveVirtualId = virtualId; + s->_lastSaveNewId = savegameId; + } + + s->r_acc = NULL_REG; + + Common::String filename = g_sci->getSavegameName(savegameId); + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + Common::OutSaveFile *out; + + out = saveFileMan->openForSaving(filename); + if (!out) { + warning("Error opening savegame \"%s\" for writing", filename.c_str()); + } else { + if (!gamestate_save(s, out, game_description, version)) { + warning("Saving the game failed"); + } else { + s->r_acc = TRUE_REG; // save successful + } + + out->finalize(); + if (out->err()) { + warning("Writing the savegame failed"); + s->r_acc = NULL_REG; // write failure + } + delete out; + } + + return s->r_acc; } -reg_t kSave(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: - return kSaveGame(s, argc - 1,argv + 1); - case 1: - return kRestoreGame(s, argc - 1,argv + 1); - case 2: - return kGetSaveDir(s, argc - 1, argv + 1); - case 3: - return kCheckSaveGame(s, argc - 1, argv + 1); - case 5: - return kGetSaveFiles(s, argc - 1, argv + 1); - case 6: - // This is used in Shivers to delete saved games, however it - // always passes the same file name (SHIVER), so it doesn't - // actually delete anything... - // TODO: Check why this happens - // argv[1] is a string (most likely the save game directory) - return kFileIOUnlink(s, argc - 2, argv + 2); - case 8: - // TODO - // This is a timer callback, with 1 parameter: the timer object - // (e.g. "timers"). - // It's used for auto-saving (i.e. save every X minutes, by checking - // the elapsed time from the timer object) - - // This function has to return something other than 0 to proceed - return s->r_acc; - default: - kStub(s, argc, argv); +reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { + Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : ""; + int16 savegameId = argv[1].toSint16(); + bool pausedMusic = false; + + debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId); + + if (argv[0].isNull()) { + // Direct call, either from launcher or from a patched Game::restore + if (savegameId == -1) { + // we are supposed to show a dialog for the user and let him choose a saved game + g_sci->_soundCmd->pauseAll(true); // pause music + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + savegameId = dialog->runModalWithCurrentTarget(); + delete dialog; + if (savegameId < 0) { + g_sci->_soundCmd->pauseAll(false); // unpause music + return s->r_acc; + } + pausedMusic = true; + } + // don't adjust ID of the saved game, it's already correct + } else { + if (argv[2].isNull()) + error("kRestoreGame: called with parameter 2 being NULL"); + // Real call from script, we need to adjust ID + if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) { + warning("Savegame ID %d is not allowed", savegameId); + return TRUE_REG; + } + savegameId -= SAVEGAMEID_OFFICIALRANGE_START; + } + + s->r_acc = NULL_REG; // signals success + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + if (findSavegame(saves, savegameId) == -1) { + s->r_acc = TRUE_REG; + warning("Savegame ID %d not found", savegameId); + } else { + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + Common::String filename = g_sci->getSavegameName(savegameId); + Common::SeekableReadStream *in; + + in = saveFileMan->openForLoading(filename); + if (in) { + // found a savegame file + + gamestate_restore(s, in); + delete in; + + if (g_sci->getGameId() == GID_MOTHERGOOSE256) { + // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for + // saving a previously restored game. + // We set the current savedgame-id directly and remove the script + // code concerning this via script patch. + s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); + } + } else { + s->r_acc = TRUE_REG; + warning("Savegame #%d not found", savegameId); + } + } + + if (!s->r_acc.isNull()) { + // no success? + if (pausedMusic) + g_sci->_soundCmd->pauseAll(false); // unpause music + } + + return s->r_acc; +} + +reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) { +#ifdef ENABLE_SCI32 + // SCI32 uses a parameter here. It is used to modify a string, stored in a + // global variable, so that game scripts store the save directory. We + // don't really set a save game directory, thus not setting the string to + // anything is the correct thing to do here. + //if (argc > 0) + // warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0])); +#endif + return s->_segMan->getSaveDirPtr(); +} + +reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) { + Common::String game_id = s->_segMan->getString(argv[0]); + uint16 virtualId = argv[1].toUint16(); + + debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), virtualId); + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + // we allow 0 (happens in QfG2 when trying to restore from an empty saved game list) and return false in that case + if (virtualId == 0) return NULL_REG; + + // Find saved-game + if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) + error("kCheckSaveGame: called with invalid savegameId"); + uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; + int savegameNr = findSavegame(saves, savegameId); + if (savegameNr == -1) + return NULL_REG; + + // Check for compatible savegame version + int ver = saves[savegameNr].version; + if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION) + return NULL_REG; + + // Otherwise we assume the savegame is OK + return TRUE_REG; +} + +reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) { + Common::String game_id = s->_segMan->getString(argv[0]); + + debug(3, "kGetSaveFiles(%s)", game_id.c_str()); + + // Scripts ask for current save files, we can assume that if afterwards they ask us to create a new slot they really + // mean new slot instead of overwriting the old one + s->_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START; + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR); + + reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves); + + if (!slot) { + warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2])); + totalSaves = 0; + } + + const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1; + char *saveNames = new char[bufSize]; + char *saveNamePtr = saveNames; + + for (uint i = 0; i < totalSaves; i++) { + *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame ID ffs. see above + strcpy(saveNamePtr, saves[i].name); + saveNamePtr += SCI_MAX_SAVENAME_LENGTH; } + + *saveNamePtr = 0; // Terminate list + + s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize); + delete[] saveNames; + + return make_reg(0, totalSaves); +} + +#ifdef ENABLE_SCI32 + +reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv) { + // Normally, this creates the name of the save catalogue/directory to save into. + // First parameter is the string to save the result into. Second is a string + // with game parameters. We don't have a use for this at all, as we have our own + // savegame directory management, thus we always return an empty string. + return argv[0]; +} + +reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) { + // Creates a savegame name from a slot number. Used when deleting saved games. + // Param 0: the output buffer (same as in kMakeSaveCatName) + // Param 1: a string with game parameters, ignored + // Param 2: the selected slot + + SciString *resultString = s->_segMan->lookupString(argv[0]); + uint16 virtualId = argv[2].toUint16(); + if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) + error("kMakeSaveFileName: invalid savegame ID specified"); + uint saveSlot = virtualId - SAVEGAMEID_OFFICIALRANGE_START; + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + Common::String filename = g_sci->getSavegameName(saveSlot); + resultString->fromString(filename); + + return argv[0]; +} + +reg_t kAutoSave(EngineState *s, int argc, reg_t *argv) { + // TODO + // This is a timer callback, with 1 parameter: the timer object + // (e.g. "timers"). + // It's used for auto-saving (i.e. save every X minutes, by checking + // the elapsed time from the timer object) + + // This function has to return something other than 0 to proceed + return TRUE_REG; } #endif diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index caae562d67..da377319c0 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -25,12 +25,10 @@ #include "engines/util.h" #include "graphics/cursorman.h" #include "graphics/surface.h" -#include "graphics/palette.h" // temporary, for the fadeIn()/fadeOut() functions below #include "gui/message.h" #include "sci/sci.h" -#include "sci/debug.h" // for g_debug_sleeptime_factor #include "sci/event.h" #include "sci/resource.h" #include "sci/engine/features.h" @@ -50,10 +48,7 @@ #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 -#include "sci/graphics/controls32.h" -#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class #include "sci/graphics/text32.h" -#include "sci/graphics/frameout.h" #endif namespace Sci { @@ -342,7 +337,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { Common::String sep_str; const char *sep = NULL; - if ((argc > 4) && (argv[4].segment)) { + if ((argc > 4) && (argv[4].getSegment())) { sep_str = s->_segMan->getString(argv[4]); sep = sep_str.c_str(); } @@ -650,6 +645,20 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) { if (paletteChanged) g_sci->_gfxPalette->kernelAnimateSet(); + // WORKAROUND: The game scripts in SQ4 floppy count the number of elapsed + // cycles in the intro from the number of successive kAnimate calls during + // the palette cycling effect, while showing the SQ4 logo. This worked in + // older computers because each animate call took awhile to complete. + // Normally, such scripts are handled automatically by our speed throttler, + // however in this case there are no calls to kGameIsRestarting (where the + // speed throttler gets called) between the different palette animation calls. + // Thus, we add a small delay between each animate call to make the whole + // palette animation effect slower and visible, and not have the logo screen + // get skipped because the scripts don't wait between animation steps. Fixes + // bug #3537232. + if (g_sci->getGameId() == GID_SQ4 && !g_sci->isCD() && s->currentRoomNumber() == 1) + g_sci->sleep(10); + return s->r_acc; } @@ -794,7 +803,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { Common::Rect rect; TextAlignment alignment; int16 mode, maxChars, cursorPos, upperPos, listCount, i; - int16 upperOffset, cursorOffset; + uint16 upperOffset, cursorOffset; GuiResourceId viewId; int16 loopNo; int16 celNo; @@ -876,7 +885,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { listCount = 0; listSeeker = textReference; while (s->_segMan->strlen(listSeeker) > 0) { listCount++; - listSeeker.offset += maxChars; + listSeeker.incOffset(maxChars); } // TODO: This is rather convoluted... It would be a lot cleaner @@ -890,11 +899,11 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { for (i = 0; i < listCount; i++) { listStrings[i] = s->_segMan->getString(listSeeker); listEntries[i] = listStrings[i].c_str(); - if (listSeeker.offset == upperOffset) + if (listSeeker.getOffset() == upperOffset) upperPos = i; - if (listSeeker.offset == cursorOffset) + if (listSeeker.getOffset() == cursorOffset) cursorPos = i; - listSeeker.offset += maxChars; + listSeeker.incOffset(maxChars); } } @@ -941,8 +950,9 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) { } } if (objName == "savedHeros") { - // Import of QfG character files dialog is shown - // display additional popup information before letting user use it + // Import of QfG character files dialog is shown. + // Display additional popup information before letting user use it. + // For the SCI32 version of this, check kernelAddPlane(). reg_t changeDirButton = s->_segMan->findObjectByName("changeDirItem"); if (!changeDirButton.isNull()) { // check if checkDirButton is still enabled, in that case we are called the first time during that room @@ -955,6 +965,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) { "for Quest for Glory 2. Example: 'qfg2-thief.sav'."); } } + + // For the SCI32 version of this, check kListAt(). s->_chosenQfGImportItem = readSelectorValue(s->_segMan, controlObject, SELECTOR(mark)); } @@ -1109,7 +1121,7 @@ reg_t kNewWindow(EngineState *s, int argc, reg_t *argv) { rect2 = Common::Rect (argv[5].toSint16(), argv[4].toSint16(), argv[7].toSint16(), argv[6].toSint16()); Common::String title; - if (argv[4 + argextra].segment) { + if (argv[4 + argextra].getSegment()) { title = s->_segMan->getString(argv[4 + argextra]); title = g_sci->strSplit(title.c_str(), NULL); } @@ -1148,7 +1160,7 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) { Common::String text; - if (textp.segment) { + if (textp.getSegment()) { argc--; argv++; text = s->_segMan->getString(textp); } else { @@ -1209,688 +1221,33 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +// Early variant of the SCI32 kRemapColors kernel function, used in the demo of QFG4 reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { uint16 operation = argv[0].toUint16(); switch (operation) { - case 0: { // Set remapping to base. 0 turns remapping off. - int16 base = (argc >= 2) ? argv[1].toSint16() : 0; - if (base != 0) // 0 is the default behavior when changing rooms in GK1, thus silencing the warning - warning("kRemapColors: Set remapping to base %d", base); - } - break; - case 1: { // unknown - // The demo of QFG4 calls this with 1+3 parameters, thus there are differences here - //int16 unk1 = argv[1].toSint16(); - //int16 unk2 = argv[2].toSint16(); - //int16 unk3 = argv[3].toSint16(); - //uint16 unk4 = argv[4].toUint16(); - //uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; - kStub(s, argc, argv); - } - break; - case 2: { // remap by percent - // This adjusts the alpha value of a specific color, and it operates on - // an RGBA palette. Since we're operating on an RGB palette, we just - // modify the color intensity instead - // TODO: From what I understand, palette remapping should be placed - // separately, so that it can be reset by case 0 above. Thus, we - // should adjust the functionality of the Palette class accordingly. - int16 color = argv[1].toSint16(); - if (color >= 10) - color -= 10; - uint16 percent = argv[2].toUint16(); // 0 - 100 - if (argc >= 4) - warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - g_sci->_gfxPalette->kernelSetIntensity(color, 255, percent, false); - } - break; - case 3: { // remap to gray - // NOTE: This adjusts the alpha value of a specific color, and it operates on - // an RGBA palette - int16 color = argv[1].toSint16(); // this is subtracted from a maximum color value, and can be offset by 10 - int16 percent = argv[2].toSint16(); // 0 - 100 - uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0; - warning("kRemapColors: RemapToGray color %d by %d percent (unk3 = %d)", color, percent, unk3); - } - break; - case 4: { // unknown - //int16 unk1 = argv[1].toSint16(); - //uint16 unk2 = argv[2].toUint16(); - //uint16 unk3 = argv[3].toUint16(); - //uint16 unk4 = (argc >= 5) ? argv[4].toUint16() : 0; - kStub(s, argc, argv); - } - break; - case 5: { // increment color - //int16 unk1 = argv[1].toSint16(); - //uint16 unk2 = argv[2].toUint16(); - kStub(s, argc, argv); - } - break; - default: - break; - } - - return s->r_acc; -} - -#ifdef ENABLE_SCI32 - -reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { - // Returns 0 if the screen width or height is less than 640 or 400, - // respectively. - if (g_system->getWidth() < 640 || g_system->getHeight() < 400) - return make_reg(0, 0); - - return make_reg(0, 1); -} - -// SCI32 variant, can't work like sci16 variants -reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { - // TODO -// reg_t curObject = argv[0]; -// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; - - return NULL_REG; -} - -reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { - if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) - g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); - else - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelAddPlane(argv[0]); - return s->r_acc; -} - -reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); - return s->r_acc; -} - -reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); - return s->r_acc; -} - -reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { - reg_t planeObj = argv[0]; - GuiResourceId pictureId = argv[1].toUint16(); - int16 pictureX = argv[2].toSint16(); - int16 pictureY = argv[3].toSint16(); - - g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); - return s->r_acc; -} - -reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, g_sci->_gfxFrameout->kernelGetHighPlanePri()); -} - -reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelFrameout(); - return NULL_REG; -} - -reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { - Common::Rect objRect1 = g_sci->_gfxCompare->getNSRect(argv[0]); - Common::Rect objRect2 = g_sci->_gfxCompare->getNSRect(argv[1]); - return make_reg(0, objRect1.intersects(objRect2)); -} - -// Tests if the coordinate is on the passed object -reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - uint16 illegalBits = argv[3].offset; - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject, true); - - // we assume that x, y are local coordinates - - bool contained = nsRect.contains(x, y); - if (contained && illegalBits) { - // If illegalbits are set, we check the color of the pixel that got clicked on - // for now, we return false if the pixel is transparent - // although illegalBits may get differently set, don't know yet how this really works out - uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); - int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); - int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); - if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) - contained = false; - } - return make_reg(0, contained); -} - -reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: { - if (argc != 4) { - warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[3]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", - PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - uint16 maxWidth = argv[1].toUint16(); // nsRight - nsLeft + 1 - uint16 maxHeight = argv[2].toUint16(); // nsBottom - nsTop + 1 - return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); - } - case 1: { - if (argc != 2) { - warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[1]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - return g_sci->_gfxText32->createTextBitmap(object); - } - default: - warning("CreateTextBitmap(%d)", argv[0].toUint16()); - return NULL_REG; - } -} - -reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxText32->disposeTextBitmap(argv[0]); - return s->r_acc; -} - -reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) { - uint16 windowsOption = argv[0].toUint16(); - switch (windowsOption) { - case 0: - // Title bar on/off in Phantasmagoria, we return 0 (off) - return NULL_REG; - default: - warning("GetWindowsOption: Unknown option %d", windowsOption); - return NULL_REG; - } -} - -reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 1: - // Load a help file - // Maybe in the future we can implement this, but for now this message should suffice - showScummVMDialog("Please use an external viewer to open the game's help file: " + s->_segMan->getString(argv[1])); - break; - case 2: - // Looks like some init function - break; - default: - warning("Unknown kWinHelp subop %d", argv[0].toUint16()); - } - - return s->r_acc; -} - -// Taken from the SCI16 GfxTransitions class -static void fadeOut() { - byte oldPalette[3 * 256], workPalette[3 * 256]; - int16 stepNr, colorNr; - // Sierra did not fade in/out color 255 for sci1.1, but they used it in - // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; - - g_system->getPaletteManager()->grabPalette(oldPalette, 0, 256); - - for (stepNr = 100; stepNr >= 0; stepNr -= 10) { - for (colorNr = 1; colorNr <= tillColorNr; colorNr++) { - if (g_sci->_gfxPalette->colorIsFromMacClut(colorNr)) { - workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3]; - workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1]; - workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2]; - } else { - workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3] * stepNr / 100; - workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1] * stepNr / 100; - workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2] * stepNr / 100; - } - } - g_system->getPaletteManager()->setPalette(workPalette + 3, 1, tillColorNr); - g_sci->getEngineState()->wait(2); - } -} - -// Taken from the SCI16 GfxTransitions class -static void fadeIn() { - int16 stepNr; - // Sierra did not fade in/out color 255 for sci1.1, but they used it in - // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; - - for (stepNr = 0; stepNr <= 100; stepNr += 10) { - g_sci->_gfxPalette->kernelSetIntensity(1, tillColorNr + 1, stepNr, true); - g_sci->getEngineState()->wait(2); - } -} - -/** - * Used for scene transitions, replacing (but reusing parts of) the old - * transition code. - */ -reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { - // Can be called with 7 or 8 parameters - // The style defines which transition to perform. Related to the transition - // tables inside graphics/transitions.cpp - uint16 showStyle = argv[0].toUint16(); // 0 - 15 - reg_t planeObj = argv[1]; // the affected plane - uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts - uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff - int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out - uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts - uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out - int16 divisions; - - // If the game has the pFadeArray selector, another parameter is used here, - // before the optional last parameter - bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; - if (hasFadeArray) { - // argv[7] - divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) - } else { - divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) - } - - if (showStyle > 15) { - warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); - return s->r_acc; - } - - // TODO: Proper implementation. This is a very basic version. I'm not even - // sure if the rest of the styles will work with this mechanism. - - // Check if the passed parameters are the ones we expect - if (showStyle == 13 || showStyle == 14) { // fade out / fade in - if (seconds != 1) - warning("kSetShowStyle(fade): seconds isn't 1, it's %d", seconds); - if (backColor != 0 && backColor != 0xFFFF) - warning("kSetShowStyle(fade): backColor isn't 0 or 0xFFFF, it's %d", backColor); - if (priority != 200) - warning("kSetShowStyle(fade): priority isn't 200, it's %d", priority); - if (animate != 0) - warning("kSetShowStyle(fade): animate isn't 0, it's %d", animate); - if (refFrame != 0) - warning("kSetShowStyle(fade): refFrame isn't 0, it's %d", refFrame); - if (divisions >= 0 && divisions != 20) - warning("kSetShowStyle(fade): divisions isn't 20, it's %d", divisions); - } - - // TODO: Check if the plane is in the list of planes to draw - - switch (showStyle) { - //case 0: // no transition, perhaps? (like in the previous SCI versions) - case 13: // fade out - // TODO: Temporary implementation, which ignores all additional parameters - fadeOut(); - break; - case 14: // fade in - // TODO: Temporary implementation, which ignores all additional parameters - g_sci->_gfxFrameout->kernelFrameout(); // draw new scene before fading in - fadeIn(); - break; - default: - // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now - kStub(s, argc, argv); - break; - } - - return s->r_acc; -} - -reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) { - // Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board - // are occupied by pieces already - - switch (argv[0].toUint16()) { // subops 0 - 4 - // 0 - return the view - // 1 - return the loop - // 2, 3 - nop - case 4: { - GuiResourceId viewId = argv[1].toSint16(); - int16 loopNo = argv[2].toSint16(); - int16 celNo = argv[3].toSint16(); - int16 x = argv[4].toUint16(); - int16 y = argv[5].toUint16(); - byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y); - return make_reg(0, color); + case 0: { // remap by percent + uint16 percent = argv[1].toUint16(); + g_sci->_gfxPalette->resetRemapping(); + g_sci->_gfxPalette->setRemappingPercent(254, percent); } - default: { - kStub(s, argc, argv); - return s->r_acc; - } - } -} - -reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { - // Used by Phantasmagoria 1 and SQ6. In SQ6, it is used for the messages - // shown in the scroll window at the bottom of the screen. - - // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now - kStub(s, argc, argv); - - switch (argv[0].toUint16()) { - case 0: // Init - // 2 parameters - // argv[1] points to the scroll object (e.g. textScroller in SQ6) - // argv[2] is an integer (e.g. 0x32) - break; - case 1: // Show message - // 5 or 6 parameters - // Seems to be called with 5 parameters when the narrator speaks, and - // with 6 when Roger speaks - // argv[1] unknown (usually 0) - // argv[2] the text to show - // argv[3] a small integer (e.g. 0x32) - // argv[4] a small integer (e.g. 0x54) - // argv[5] optional, unknown (usually 0) - warning("kScrollWindow: '%s'", s->_segMan->getString(argv[2]).c_str()); - break; - case 2: // Clear - // 2 parameters - // TODO - break; - case 3: // Page up - // 2 parameters - // TODO - break; - case 4: // Page down - // 2 parameters - // TODO - break; - case 5: // Up arrow - // 2 parameters - // TODO - break; - case 6: // Down arrow - // 2 parameters - // TODO - break; - case 7: // Home - // 2 parameters - // TODO - break; - case 8: // End - // 2 parameters - // TODO - break; - case 9: // Resize - // 3 parameters - // TODO - break; - case 10: // Where - // 3 parameters - // TODO - break; - case 11: // Go - // 4 parameters - // TODO - break; - case 12: // Insert - // 7 parameters - // TODO break; - case 13: // Delete - // 3 parameters - // TODO - break; - case 14: // Modify - // 7 or 8 parameters - // TODO - break; - case 15: // Hide - // 2 parameters - // TODO - break; - case 16: // Show - // 2 parameters - // TODO - break; - case 17: // Destroy - // 2 parameters - // TODO - break; - case 18: // Text - // 2 parameters - // TODO - break; - case 19: // Reconstruct - // 3 parameters - // TODO - break; - default: - error("kScrollWindow: unknown subop %d", argv[0].toUint16()); - break; - } - - return s->r_acc; -} - -reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { - // TODO: This defines the resolution that the fonts are supposed to be displayed - // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but - // should be extended to handle other font resolutions such as those - - int xResolution = argv[0].toUint16(); - //int yResolution = argv[1].toUint16(); - - g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && - g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); - - return s->r_acc; -} - -reg_t kFont(EngineState *s, int argc, reg_t *argv) { - // Handle font settings for SCI2.1 - - switch (argv[0].toUint16()) { - case 1: - // Set font resolution - return kSetFontRes(s, argc - 1, argv + 1); - default: - warning("kFont: unknown subop %d", argv[0].toUint16()); - } - - return s->r_acc; -} - -// TODO: Eventually, all of the kBitmap operations should be put -// in a separate class - -#define BITMAP_HEADER_SIZE 46 - -reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { - // Used for bitmap operations in SCI2.1 and SCI3. - // This is the SCI2.1 version, the functionality seems to have changed in SCI3. - - switch (argv[0].toUint16()) { - case 0: // init bitmap surface - { - // 6 params, called e.g. from TextView::init() in Torin's Passage, - // script 64890 and TransView::init() in script 64884 - uint16 width = argv[1].toUint16(); - uint16 height = argv[2].toUint16(); - //uint16 skip = argv[3].toUint16(); - uint16 back = argv[4].toUint16(); // usually equals skip - //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; - //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; - //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; - - // TODO: skip, width2, height2, transparentFlag - // (used for transparent bitmaps) - int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); - byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); - memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header - memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); - // Save totalWidth, totalHeight - // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); - return memoryId; + case 1: { // remap by range + uint16 from = argv[1].toUint16(); + uint16 to = argv[2].toUint16(); + uint16 base = argv[3].toUint16(); + g_sci->_gfxPalette->resetRemapping(); + g_sci->_gfxPalette->setRemappingRange(254, from, to, base); } break; - case 1: // dispose text bitmap surface - return kDisposeTextBitmap(s, argc - 1, argv + 1); - case 2: // dispose bitmap surface, with extra param - // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, - // script 64893 - warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); - break; - case 3: // tiled surface - { - // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, - // script 64869 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - // The tiled view seems to always have 2 loops. - // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. - uint16 viewNum = argv[2].toUint16(); // vTiles selector - uint16 loop = argv[3].toUint16(); - uint16 cel = argv[4].toUint16(); - uint16 x = argv[5].toUint16(); - uint16 y = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxView *view = g_sci->_gfxCache->getView(viewNum); - uint16 tileWidth = view->getWidth(loop, cel); - uint16 tileHeight = view->getHeight(loop, cel); - const byte *tileBitmap = view->getBitmap(loop, cel); - uint16 width = MIN<uint16>(totalWidth - x, tileWidth); - uint16 height = MIN<uint16>(totalHeight - y, tileHeight); - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; - } - } - - } - break; - case 4: // add text to bitmap - { - // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, - // script 64894 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - Common::String text = s->_segMan->getString(argv[2]); - uint16 textX = argv[3].toUint16(); - uint16 textY = argv[4].toUint16(); - //reg_t unk5 = argv[5]; - //reg_t unk6 = argv[6]; - //reg_t unk7 = argv[7]; // skip? - //reg_t unk8 = argv[8]; // back? - //reg_t unk9 = argv[9]; - uint16 fontId = argv[10].toUint16(); - //uint16 mode = argv[11].toUint16(); - uint16 dimmed = argv[12].toUint16(); - //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", - // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); - uint16 foreColor = 255; // TODO - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxFont *font = g_sci->_gfxCache->getFont(fontId); - - int16 charCount = 0; - uint16 curX = textX, curY = textY; - const char *txt = text.c_str(); - - while (*txt) { - charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); - if (charCount == 0) - break; - - for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); - curX += font->getCharWidth(curChar); - } - - curX = textX; - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces - } - - } - break; - case 5: // fill with color - { - // 6 params, called e.g. from TextView::init() and TextView::draw() - // in Torin's Passage, script 64890 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - uint16 x = argv[2].toUint16(); - uint16 y = argv[3].toUint16(); - uint16 fillWidth = argv[4].toUint16(); // width - 1 - uint16 fillHeight = argv[5].toUint16(); // height - 1 - uint16 back = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - uint16 width = MIN<uint16>(totalWidth - x, fillWidth); - uint16 height = MIN<uint16>(totalHeight - y, fillHeight); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = back; - } - } - - } + case 2: // turn remapping off (unused) + error("Unused subop kRemapColors(2) has been called"); break; default: - kStub(s, argc, argv); break; } return s->r_acc; } -// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, -// but it handles events on its own, using an internal loop, instead of using SCI -// scripts for event management like kEditControl does. Called by script 64914, -// DEdit::hilite(). -reg_t kEditText(EngineState *s, int argc, reg_t *argv) { - reg_t controlObject = argv[0]; - - if (!controlObject.isNull()) { - g_sci->_gfxControls32->kernelTexteditChange(controlObject); - } - - return s->r_acc; -} - -#endif - } // End of namespace Sci diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp new file mode 100644 index 0000000000..8b3afeef99 --- /dev/null +++ b/engines/sci/engine/kgraphics32.cpp @@ -0,0 +1,812 @@ +/* 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 "common/system.h" + +#include "engines/util.h" +#include "graphics/cursorman.h" +#include "graphics/surface.h" + +#include "gui/message.h" + +#include "sci/sci.h" +#include "sci/event.h" +#include "sci/resource.h" +#include "sci/engine/features.h" +#include "sci/engine/state.h" +#include "sci/engine/selector.h" +#include "sci/engine/kernel.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/cache.h" +#include "sci/graphics/compare.h" +#include "sci/graphics/controls16.h" +#include "sci/graphics/coordadjuster.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/paint16.h" +#include "sci/graphics/picture.h" +#include "sci/graphics/ports.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/text16.h" +#include "sci/graphics/view.h" +#ifdef ENABLE_SCI32 +#include "sci/graphics/controls32.h" +#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class +#include "sci/graphics/text32.h" +#include "sci/graphics/frameout.h" +#endif + +namespace Sci { +#ifdef ENABLE_SCI32 + +extern void showScummVMDialog(const Common::String &message); + +reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { + // Returns 0 if the screen width or height is less than 640 or 400, + // respectively. + if (g_system->getWidth() < 640 || g_system->getHeight() < 400) + return make_reg(0, 0); + + return make_reg(0, 1); +} + +// SCI32 variant, can't work like sci16 variants +reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { + // TODO +// reg_t curObject = argv[0]; +// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; + + return NULL_REG; +} + +reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { + if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) + g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); + else + g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelAddPlane(argv[0]); + return s->r_acc; +} + +reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); + return s->r_acc; +} + +reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); + return s->r_acc; +} + +reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { + reg_t planeObj = argv[0]; + GuiResourceId pictureId = argv[1].toUint16(); + int16 pictureX = argv[2].toSint16(); + int16 pictureY = argv[3].toSint16(); + + g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); + return s->r_acc; +} + +reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_gfxFrameout->kernelGetHighPlanePri()); +} + +reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelFrameout(); + return NULL_REG; +} + +reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { + Common::Rect objRect1 = g_sci->_gfxCompare->getNSRect(argv[0]); + Common::Rect objRect2 = g_sci->_gfxCompare->getNSRect(argv[1]); + return make_reg(0, objRect1.intersects(objRect2)); +} + +// Tests if the coordinate is on the passed object +reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { + uint16 x = argv[0].toUint16(); + uint16 y = argv[1].toUint16(); + reg_t targetObject = argv[2]; + uint16 illegalBits = argv[3].getOffset(); + Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject, true); + + // we assume that x, y are local coordinates + + bool contained = nsRect.contains(x, y); + if (contained && illegalBits) { + // If illegalbits are set, we check the color of the pixel that got clicked on + // for now, we return false if the pixel is transparent + // although illegalBits may get differently set, don't know yet how this really works out + uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); + int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); + int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); + if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) + contained = false; + } + return make_reg(0, contained); +} + +reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { + switch (argv[0].toUint16()) { + case 0: { + if (argc != 4) { + warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); + return NULL_REG; + } + reg_t object = argv[3]; + Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); + debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", + PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); + debugC(kDebugLevelStrings, "%s", text.c_str()); + int16 maxWidth = argv[1].toUint16(); + int16 maxHeight = argv[2].toUint16(); + g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth); + // These values can be larger than the screen in the SQ6 demo, room 100 + // TODO: Find out why. For now, don't show any text in that room. + if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100) + return NULL_REG; + return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); + } + case 1: { + if (argc != 2) { + warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); + return NULL_REG; + } + reg_t object = argv[1]; + Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); + debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); + debugC(kDebugLevelStrings, "%s", text.c_str()); + return g_sci->_gfxText32->createTextBitmap(object); + } + default: + warning("CreateTextBitmap(%d)", argv[0].toUint16()); + return NULL_REG; + } +} + +reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->disposeTextBitmap(argv[0]); + return s->r_acc; +} + +reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { + switch (argv[0].toUint16()) { + case 1: + // Load a help file + // Maybe in the future we can implement this, but for now this message should suffice + showScummVMDialog("Please use an external viewer to open the game's help file: " + s->_segMan->getString(argv[1])); + break; + case 2: + // Looks like some init function + break; + default: + warning("Unknown kWinHelp subop %d", argv[0].toUint16()); + } + + return s->r_acc; +} + +/** + * Used for scene transitions, replacing (but reusing parts of) the old + * transition code. + */ +reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { + // Can be called with 7 or 8 parameters + // The style defines which transition to perform. Related to the transition + // tables inside graphics/transitions.cpp + uint16 showStyle = argv[0].toUint16(); // 0 - 15 + reg_t planeObj = argv[1]; // the affected plane + Common::String planeObjName = s->_segMan->getObjectName(planeObj); + uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts + uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff + int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out + uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts + uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out + int16 divisions; + + // If the game has the pFadeArray selector, another parameter is used here, + // before the optional last parameter + bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; + if (hasFadeArray) { + // argv[7] + divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) + } else { + divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) + } + + if (showStyle > 15) { + warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); + return s->r_acc; + } + + // GK1 calls fadeout (13) / fadein (14) with the following parameters: + // seconds: 1 + // backColor: 0 / -1 + // fade: 200 + // animate: 0 + // refFrame: 0 + // divisions: 0 / 20 + + // TODO: Check if the plane is in the list of planes to draw + + Common::String effectName = "unknown"; + + switch (showStyle) { + case 0: // no transition / show + effectName = "show"; + break; + case 13: // fade out + effectName = "fade out"; + // TODO + break; + case 14: // fade in + effectName = "fade in"; + // TODO + break; + default: + // TODO + break; + } + + warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, " + "back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d", + showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(), + seconds, backColor, priority, animate, refFrame, divisions); + return s->r_acc; +} + +reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) { + // Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board + // are occupied by pieces already + + switch (argv[0].toUint16()) { // subops 0 - 4 + // 0 - return the view + // 1 - return the loop + // 2, 3 - nop + case 4: { + GuiResourceId viewId = argv[1].toSint16(); + int16 loopNo = argv[2].toSint16(); + int16 celNo = argv[3].toSint16(); + int16 x = argv[4].toUint16(); + int16 y = argv[5].toUint16(); + byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y); + return make_reg(0, color); + } + default: { + kStub(s, argc, argv); + return s->r_acc; + } + } +} + +reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { + // Used by SQ6 and LSL6 hires for the text area in the bottom of the + // screen. The relevant scripts also exist in Phantasmagoria 1, but they're + // unused. This is always called by scripts 64906 (ScrollerWindow) and + // 64907 (ScrollableWindow). + + reg_t kWindow = argv[1]; + uint16 op = argv[0].toUint16(); + switch (op) { + case 0: // Init + g_sci->_gfxFrameout->initScrollText(argv[2].toUint16()); // maxItems + g_sci->_gfxFrameout->clearScrollTexts(); + return argv[1]; // kWindow + case 1: // Show message, called by ScrollableWindow::addString + case 14: // Modify message, called by ScrollableWindow::modifyString + // 5 or 6 parameters + // Seems to be called with 5 parameters when the narrator speaks, and + // with 6 when Roger speaks + { + Common::String text = s->_segMan->getString(argv[2]); + uint16 x = 0;//argv[3].toUint16(); // TODO: can't be x (values are all wrong) + uint16 y = 0;//argv[4].toUint16(); // TODO: can't be y (values are all wrong) + // TODO: argv[5] is an optional unknown parameter (an integer set to 0) + g_sci->_gfxFrameout->addScrollTextEntry(text, kWindow, x, y, (op == 14)); + } + break; + case 2: // Clear, called by ScrollableWindow::erase + g_sci->_gfxFrameout->clearScrollTexts(); + break; + case 3: // Page up, called by ScrollableWindow::scrollTo + // TODO + kStub(s, argc, argv); + break; + case 4: // Page down, called by ScrollableWindow::scrollTo + // TODO + kStub(s, argc, argv); + break; + case 5: // Up arrow, called by ScrollableWindow::scrollTo + g_sci->_gfxFrameout->prevScrollText(); + break; + case 6: // Down arrow, called by ScrollableWindow::scrollTo + g_sci->_gfxFrameout->nextScrollText(); + break; + case 7: // Home, called by ScrollableWindow::scrollTo + g_sci->_gfxFrameout->firstScrollText(); + break; + case 8: // End, called by ScrollableWindow::scrollTo + g_sci->_gfxFrameout->lastScrollText(); + break; + case 9: // Resize, called by ScrollableWindow::resize and ScrollerWindow::resize + // TODO + kStub(s, argc, argv); + break; + case 10: // Where, called by ScrollableWindow::where + // TODO + // argv[2] is an unknown integer + // Silenced the warnings because of the high amount of console spam + //kStub(s, argc, argv); + break; + case 11: // Go, called by ScrollableWindow::scrollTo + // 2 extra parameters here + // TODO + kStub(s, argc, argv); + break; + case 12: // Insert, called by ScrollableWindow::insertString + // 3 extra parameters here + // TODO + kStub(s, argc, argv); + break; + // case 13 (Delete) is handled below + // case 14 (Modify) is handled above + case 15: // Hide, called by ScrollableWindow::hide + g_sci->_gfxFrameout->toggleScrollText(false); + break; + case 16: // Show, called by ScrollableWindow::show + g_sci->_gfxFrameout->toggleScrollText(true); + break; + case 17: // Destroy, called by ScrollableWindow::dispose + g_sci->_gfxFrameout->clearScrollTexts(); + break; + case 13: // Delete, unused + case 18: // Text, unused + case 19: // Reconstruct, unused + error("kScrollWindow: Unused subop %d invoked", op); + break; + default: + error("kScrollWindow: unknown subop %d", op); + break; + } + + return s->r_acc; +} + +reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { + // TODO: This defines the resolution that the fonts are supposed to be displayed + // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but + // should be extended to handle other font resolutions such as those + + int xResolution = argv[0].toUint16(); + //int yResolution = argv[1].toUint16(); + + g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && + g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); + + return s->r_acc; +} + +reg_t kFont(EngineState *s, int argc, reg_t *argv) { + // Handle font settings for SCI2.1 + + switch (argv[0].toUint16()) { + case 1: + // Set font resolution + return kSetFontRes(s, argc - 1, argv + 1); + default: + warning("kFont: unknown subop %d", argv[0].toUint16()); + } + + return s->r_acc; +} + +// TODO: Eventually, all of the kBitmap operations should be put +// in a separate class + +#define BITMAP_HEADER_SIZE 46 + +reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { + // Used for bitmap operations in SCI2.1 and SCI3. + // This is the SCI2.1 version, the functionality seems to have changed in SCI3. + + switch (argv[0].toUint16()) { + case 0: // init bitmap surface + { + // 6 params, called e.g. from TextView::init() in Torin's Passage, + // script 64890 and TransView::init() in script 64884 + uint16 width = argv[1].toUint16(); + uint16 height = argv[2].toUint16(); + //uint16 skip = argv[3].toUint16(); + uint16 back = argv[4].toUint16(); // usually equals skip + //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; + //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; + //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; + + // TODO: skip, width2, height2, transparentFlag + // (used for transparent bitmaps) + int entrySize = width * height + BITMAP_HEADER_SIZE; + reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); + byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); + memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header + memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); + // Save totalWidth, totalHeight + // TODO: Save the whole bitmap header, like SSCI does + WRITE_LE_UINT16(memoryPtr, width); + WRITE_LE_UINT16(memoryPtr + 2, height); + return memoryId; + } + break; + case 1: // dispose text bitmap surface + return kDisposeTextBitmap(s, argc - 1, argv + 1); + case 2: // dispose bitmap surface, with extra param + // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, + // script 64893 + warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); + break; + case 3: // tiled surface + { + // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, + // script 64869 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + // The tiled view seems to always have 2 loops. + // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. + uint16 viewNum = argv[2].toUint16(); // vTiles selector + uint16 loop = argv[3].toUint16(); + uint16 cel = argv[4].toUint16(); + uint16 x = argv[5].toUint16(); + uint16 y = argv[6].toUint16(); + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + GfxView *view = g_sci->_gfxCache->getView(viewNum); + uint16 tileWidth = view->getWidth(loop, cel); + uint16 tileHeight = view->getHeight(loop, cel); + const byte *tileBitmap = view->getBitmap(loop, cel); + uint16 width = MIN<uint16>(totalWidth - x, tileWidth); + uint16 height = MIN<uint16>(totalHeight - y, tileHeight); + + for (uint16 curY = 0; curY < height; curY++) { + for (uint16 curX = 0; curX < width; curX++) { + bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; + } + } + + } + break; + case 4: // add text to bitmap + { + // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, + // script 64894 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + Common::String text = s->_segMan->getString(argv[2]); + uint16 textX = argv[3].toUint16(); + uint16 textY = argv[4].toUint16(); + //reg_t unk5 = argv[5]; + //reg_t unk6 = argv[6]; + //reg_t unk7 = argv[7]; // skip? + //reg_t unk8 = argv[8]; // back? + //reg_t unk9 = argv[9]; + uint16 fontId = argv[10].toUint16(); + //uint16 mode = argv[11].toUint16(); + uint16 dimmed = argv[12].toUint16(); + //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", + // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); + uint16 foreColor = 255; // TODO + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + GfxFont *font = g_sci->_gfxCache->getFont(fontId); + + int16 charCount = 0; + uint16 curX = textX, curY = textY; + const char *txt = text.c_str(); + + while (*txt) { + charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); + if (charCount == 0) + break; + + for (int i = 0; i < charCount; i++) { + unsigned char curChar = txt[i]; + font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); + curX += font->getCharWidth(curChar); + } + + curX = textX; + curY += font->getHeight(); + txt += charCount; + while (*txt == ' ') + txt++; // skip over breaking spaces + } + + } + break; + case 5: // fill with color + { + // 6 params, called e.g. from TextView::init() and TextView::draw() + // in Torin's Passage, script 64890 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + uint16 x = argv[2].toUint16(); + uint16 y = argv[3].toUint16(); + uint16 fillWidth = argv[4].toUint16(); // width - 1 + uint16 fillHeight = argv[5].toUint16(); // height - 1 + uint16 back = argv[6].toUint16(); + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + uint16 width = MIN<uint16>(totalWidth - x, fillWidth); + uint16 height = MIN<uint16>(totalHeight - y, fillHeight); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + for (uint16 curY = 0; curY < height; curY++) { + for (uint16 curX = 0; curX < width; curX++) { + bitmap[(curY + y) * totalWidth + (curX + x)] = back; + } + } + + } + break; + default: + kStub(s, argc, argv); + break; + } + + return s->r_acc; +} + +// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, +// but it handles events on its own, using an internal loop, instead of using SCI +// scripts for event management like kEditControl does. Called by script 64914, +// DEdit::hilite(). +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + reg_t controlObject = argv[0]; + + if (!controlObject.isNull()) { + g_sci->_gfxControls32->kernelTexteditChange(controlObject); + } + + return s->r_acc; +} + +reg_t kAddLine(EngineState *s, int argc, reg_t *argv) { + reg_t plane = argv[0]; + Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16()); + Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16()); + // argv[5] is unknown (a number, usually 200) + byte color = (byte)argv[6].toUint16(); + byte priority = (byte)argv[7].toUint16(); + byte control = (byte)argv[8].toUint16(); + // argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps? + return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control); +} + +reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) { + reg_t hunkId = argv[0]; + reg_t plane = argv[1]; + Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16()); + Common::Point endPoint(argv[4].toUint16(), argv[5].toUint16()); + // argv[6] is unknown (a number, usually 200) + byte color = (byte)argv[7].toUint16(); + byte priority = (byte)argv[8].toUint16(); + byte control = (byte)argv[9].toUint16(); + // argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps? + g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control); + return s->r_acc; +} +reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) { + reg_t hunkId = argv[0]; + reg_t plane = argv[1]; + g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId); + return s->r_acc; +} + +reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) { + // Called in the intro of LSL6 hires (room 110) + // The end effect of this is the same as the old screen scroll transition + + // 7 parameters + reg_t planeObject = argv[0]; + //int16 x = argv[1].toSint16(); + //int16 y = argv[2].toSint16(); + uint16 pictureId = argv[3].toUint16(); + // param 4: int (0 in LSL6, probably scroll direction? The picture in LSL6 scrolls down) + // param 5: int (first call is 1, then the subsequent one is 0 in LSL6) + // param 6: optional int (0 in LSL6) + + // Set the new picture directly for now + //writeSelectorValue(s->_segMan, planeObject, SELECTOR(left), x); + //writeSelectorValue(s->_segMan, planeObject, SELECTOR(top), y); + writeSelectorValue(s->_segMan, planeObject, SELECTOR(picture), pictureId); + // and update our draw list + g_sci->_gfxFrameout->kernelUpdatePlane(planeObject); + + // TODO + return kStub(s, argc, argv); +} + +reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) { + // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen) + + switch (argv[0].toUint16()) { + case 0: { // Palette animation initialization + // 3 or 4 extra params + // Case 1 sends fromColor and speed again, so we don't need them here. + // Only toColor is stored + //uint16 fromColor = argv[1].toUint16(); + s->_palCycleToColor = argv[2].toUint16(); + //uint16 speed = argv[3].toUint16(); + + // Invalidate the picture, so that the palette steps calls (case 1 + // below) can update its palette without it being overwritten by the + // view/picture palettes. + g_sci->_gfxScreen->_picNotValid = 1; + + // TODO: The fourth optional parameter is an unknown integer, and is 0 by default + if (argc == 5) { + // When this variant is used, picNotValid doesn't seem to be set + // (e.g. GK1 room 480). In this case, the animation step calls are + // not made, so perhaps this signifies the palette cycling steps + // to make. + // GK1 sets this to 6 (6 palette steps?) + g_sci->_gfxScreen->_picNotValid = 0; + } + kStub(s, argc, argv); + } + break; + case 1: { // Palette animation step + // This is the same as the old kPaletteAnimate call, with 1 set of colors. + // The end color is set up during initialization in case 0 above. + + // 1 or 2 extra params + uint16 fromColor = argv[1].toUint16(); + uint16 speed = (argc == 2) ? 1 : argv[2].toUint16(); + // TODO: For some reason, this doesn't set the color correctly + // (e.g. LSL6 intro, room 100, Sierra logo) + if (g_sci->_gfxPalette->kernelAnimate(fromColor, s->_palCycleToColor, speed)) + g_sci->_gfxPalette->kernelAnimateSet(); + } + // No kStub() call here, as this gets called loads of times, like kPaletteAnimate + break; + // case 2 hasn't been encountered + // case 3 hasn't been encountered + case 4: // reset any palette cycling and make the picture valid again + // Gets called when changing rooms and after palette cycling animations finish + // 0 or 1 extra params + if (argc == 1) { + g_sci->_gfxScreen->_picNotValid = 0; + // TODO: This also seems to perform more steps + } else { + // The variant with the 1 extra param resets remapping to base + // TODO + } + kStub(s, argc, argv); + break; + default: + // TODO + kStub(s, argc, argv); + break; + } + + return s->r_acc; +} + +reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { + uint16 operation = argv[0].toUint16(); + + switch (operation) { + case 0: { // turn remapping off + // WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room + // 140 (the character point allocation screen) and never turn it back on, + // even if it's clearly used in that screen. + if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140) + return s->r_acc; + + int16 base = (argc >= 2) ? argv[1].toSint16() : 0; + if (base > 0) + warning("kRemapColors(0) called with base %d", base); + g_sci->_gfxPalette->resetRemapping(); + } + break; + case 1: { // remap by range + uint16 color = argv[1].toUint16(); + uint16 from = argv[2].toUint16(); + uint16 to = argv[3].toUint16(); + uint16 base = argv[4].toUint16(); + uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; + if (unk5 > 0) + warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5); + g_sci->_gfxPalette->setRemappingRange(color, from, to, base); + } + break; + case 2: { // remap by percent + uint16 color = argv[1].toUint16(); + uint16 percent = argv[2].toUint16(); // 0 - 100 + if (argc >= 4) + warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); + g_sci->_gfxPalette->setRemappingPercent(color, percent); + } + break; + case 3: { // remap to gray + // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0. + // In this room, it's used for the cloud before Baba Yaga appears. + int16 color = argv[1].toSint16(); + int16 percent = argv[2].toSint16(); // 0 - 100 + if (argc >= 4) + warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); + } + break; + case 4: { // remap to percent gray + // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200 + int16 color = argv[1].toSint16(); + int16 percent = argv[2].toSint16(); // 0 - 100 + // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? + if (argc >= 5) + warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); + } + break; + case 5: { // don't map to range + //int16 mapping = argv[1].toSint16(); + uint16 intensity = argv[2].toUint16(); + // HACK for PQ4 + if (g_sci->getGameId() == GID_PQ4) + g_sci->_gfxPalette->kernelSetIntensity(0, 255, intensity, true); + + kStub(s, argc, argv); + } + break; + default: + break; + } + + return s->r_acc; +} + +#endif + +} // End of namespace Sci diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 2a33df26bc..342fa95eda 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -409,10 +409,14 @@ int sort_temp_cmp(const void *p1, const void *p2) { const sort_temp_t *st1 = (const sort_temp_t *)p1; const sort_temp_t *st2 = (const sort_temp_t *)p2; - if (st1->order.segment < st2->order.segment || (st1->order.segment == st2->order.segment && st1->order.offset < st2->order.offset)) + if (st1->order.getSegment() < st2->order.getSegment() || + (st1->order.getSegment() == st2->order.getSegment() && + st1->order.getOffset() < st2->order.getOffset())) return -1; - if (st1->order.segment > st2->order.segment || (st1->order.segment == st2->order.segment && st1->order.offset > st2->order.offset)) + if (st1->order.getSegment() > st2->order.getSegment() || + (st1->order.getSegment() == st2->order.getSegment() && + st1->order.getOffset() > st2->order.getOffset())) return 1; return 0; @@ -502,6 +506,11 @@ reg_t kListAt(EngineState *s, int argc, reg_t *argv) { curIndex++; } + // Update the virtual file selected in the character import screen of QFG4. + // For the SCI0-SCI1.1 version of this, check kDrawControl(). + if (g_sci->inQfGImportRoom() && !strcmp(s->_segMan->getObjectName(curObject), "SelectorDText")) + s->_chosenQfGImportItem = listIndex; + return curObject; } @@ -575,8 +584,11 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) { // First, check if the target selector is a variable if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) { - // Can this happen with variable selectors? - error("kListFirstTrue: Attempted to access a variable selector"); + // If it's a variable selector, check its value. + // Example: script 64893 in Torin, MenuHandler::isHilited checks + // all children for variable selector 0x03ba (bHilited). + if (!readSelector(s->_segMan, curObject, slc).isNull()) + return curObject; } else { invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2); @@ -609,16 +621,16 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) { // First, check if the target selector is a variable if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) { - // Can this happen with variable selectors? - error("kListAllTrue: Attempted to access a variable selector"); + // If it's a variable selector, check its value + s->r_acc = readSelector(s->_segMan, curObject, slc); } else { invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2); - - // Check if the result isn't true - if (s->r_acc.isNull()) - break; } + // Check if the result isn't true + if (s->r_acc.isNull()) + break; + curNode = s->_segMan->lookupNode(nextNode); } @@ -662,15 +674,15 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) { if (argv[2].toUint16() == 3) return kString(s, argc, argv); } else { - if (s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_STRING || - s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_SCRIPT) { + if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING || + s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) { return kString(s, argc, argv); } #if 0 if (op == 6) { - if (s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_STRING || - s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_SCRIPT) { + if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING || + s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) { return kString(s, argc, argv); } } @@ -789,7 +801,7 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) { #endif return NULL_REG; } - if (s->_segMan->getSegmentObj(argv[1].segment)->getType() != SEG_TYPE_ARRAY) + if (s->_segMan->getSegmentObj(argv[1].getSegment())->getType() != SEG_TYPE_ARRAY) error("kArray(Dup): Request to duplicate a segment which isn't an array"); reg_t arrayHandle; diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp index 7570856dff..4b8fadbb84 100644 --- a/engines/sci/engine/kmath.cpp +++ b/engines/sci/engine/kmath.cpp @@ -77,7 +77,18 @@ reg_t kSqrt(EngineState *s, int argc, reg_t *argv) { return make_reg(0, (int16) sqrt((float) ABS(argv[0].toSint16()))); } +/** + * Returns the angle (in degrees) between the two points determined by (x1, y1) + * and (x2, y2). The angle ranges from 0 to 359 degrees. + * What this function does is pretty simple but apparently the original is not + * accurate. + */ uint16 kGetAngleWorker(int16 x1, int16 y1, int16 x2, int16 y2) { + // SCI1 games (QFG2 and newer) use a simple atan implementation. SCI0 games + // use a somewhat less accurate calculation (below). + if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) + return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360; + int16 xRel = x2 - x1; int16 yRel = y1 - y2; // y-axis is mirrored. int16 angle; diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index a32480c168..8b7fc4ffec 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -128,7 +128,7 @@ reg_t kMemoryInfo(EngineState *s, int argc, reg_t *argv) { // fragmented const uint16 size = 0x7fea; - switch (argv[0].offset) { + switch (argv[0].getOffset()) { case K_MEMORYINFO_LARGEST_HEAP_BLOCK: // In order to prevent "Memory fragmented" dialogs from // popping up in some games, we must return FREE_HEAP - 2 here. @@ -140,7 +140,7 @@ reg_t kMemoryInfo(EngineState *s, int argc, reg_t *argv) { return make_reg(0, size); default: - error("Unknown MemoryInfo operation: %04x", argv[0].offset); + error("Unknown MemoryInfo operation: %04x", argv[0].getOffset()); } return NULL_REG; @@ -304,7 +304,7 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) { break; } case K_MEMORY_PEEK : { - if (!argv[1].segment) { + if (!argv[1].getSegment()) { // This occurs in KQ5CD when interacting with certain objects warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1])); return s->r_acc; @@ -334,11 +334,11 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) { } if (ref.isRaw) { - if (argv[2].segment) { + if (argv[2].getSegment()) { error("Attempt to poke memory reference %04x:%04x to %04x:%04x", PRINT_REG(argv[2]), PRINT_REG(argv[1])); return s->r_acc; } - WRITE_SCIENDIAN_UINT16(ref.raw, argv[2].offset); // Amiga versions are BE + WRITE_SCIENDIAN_UINT16(ref.raw, argv[2].getOffset()); // Amiga versions are BE } else { if (ref.skipByte) error("Attempt to poke memory at odd offset %04X:%04X", PRINT_REG(argv[1])); @@ -356,10 +356,81 @@ reg_t kGetConfig(EngineState *s, int argc, reg_t *argv) { Common::String setting = s->_segMan->getString(argv[0]); reg_t data = readSelector(s->_segMan, argv[1], SELECTOR(data)); - warning("Get config setting %s", setting.c_str()); - s->_segMan->strcpy(data, ""); + // This function is used to get the benchmarked results stored in the + // resource.cfg configuration file in Phantasmagoria 1. Normally, + // the configuration file contains values stored by the installer + // regarding audio and video settings, which are then used by the + // executable. In Phantasmagoria, two extra executable files are used + // to perform system benchmarks: + // - CPUID for the CPU benchmarks, sets the cpu and cpuspeed settings + // - HDDTEC for the graphics and CD-ROM benchmarks, sets the videospeed setting + // + // These settings are then used by the game scripts directly to modify + // the game speed and graphics output. The result of this call is stored + // in global 178. The scripts check these values against the value 425. + // Anything below that makes Phantasmagoria awfully sluggish, so we're + // setting everything to 500, which makes the game playable. + + setting.toLowercase(); + + if (setting == "videospeed") { + s->_segMan->strcpy(data, "500"); + } else if (setting == "cpu") { + // We always return the fastest CPU setting that CPUID can detect + // (i.e. 586). + s->_segMan->strcpy(data, "586"); + } else if (setting == "cpuspeed") { + s->_segMan->strcpy(data, "500"); + } else if (setting == "language") { + Common::String languageId = Common::String::format("%d", g_sci->getSciLanguage()); + s->_segMan->strcpy(data, languageId.c_str()); + } else if (setting == "torindebug") { + // Used to enable the debug mode in Torin's Passage (French). + // If true, the debug mode is enabled. + s->_segMan->strcpy(data, ""); + } else if (setting == "leakdump") { + // An unknown setting in LSL7. Likely used for debugging. + s->_segMan->strcpy(data, ""); + } else if (setting == "startroom") { + // Debug setting in LSL7, specifies the room to start from. + s->_segMan->strcpy(data, ""); + } else { + error("GetConfig: Unknown configuration setting %s", setting.c_str()); + } + return argv[1]; } + +// Likely modelled after the Windows 3.1 function GetPrivateProfileInt: +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724345%28v=vs.85%29.aspx +reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv) { + Common::String category = s->_segMan->getString(argv[0]); // always "config" + category.toLowercase(); + Common::String setting = s->_segMan->getString(argv[1]); + setting.toLowercase(); + // The third parameter is the default value returned if the configuration key is missing + + if (category == "config" && setting == "videospeed") { + // We return the same fake value for videospeed as with kGetConfig + return make_reg(0, 500); + } + + warning("kGetSierraProfileInt: Returning default value %d for unknown setting %s.%s", argv[2].toSint16(), category.c_str(), setting.c_str()); + return argv[2]; +} + +reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) { + uint16 windowsOption = argv[0].toUint16(); + switch (windowsOption) { + case 0: + // Title bar on/off in Phantasmagoria, we return 0 (off) + return NULL_REG; + default: + warning("GetWindowsOption: Unknown option %d", windowsOption); + return NULL_REG; + } +} + #endif // kIconBar is really a subop of kMacPlatform for SCI1.1 Mac diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp index 59694cb6ee..5e861daaa4 100644 --- a/engines/sci/engine/kparse.cpp +++ b/engines/sci/engine/kparse.cpp @@ -48,7 +48,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) { const int debug_parser = 0; #endif - if (!heap_said_block.segment) + if (!heap_said_block.getSegment()) return NULL_REG; said_block = (byte *)s->_segMan->derefBulkPtr(heap_said_block, 0); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 089b325a7f..002ef1ff07 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -367,7 +367,7 @@ static void draw_input(EngineState *s, reg_t poly_list, Common::Point start, Com draw_point(s, start, 1, width, height); draw_point(s, end, 0, width, height); - if (!poly_list.segment) + if (!poly_list.getSegment()) return; list = s->_segMan->lookupList(poly_list); @@ -423,7 +423,7 @@ static void print_input(EngineState *s, reg_t poly_list, Common::Point start, Co debug("End point: (%i, %i)", end.x, end.y); debug("Optimization level: %i", opt); - if (!poly_list.segment) + if (!poly_list.getSegment()) return; list = s->_segMan->lookupList(poly_list); @@ -1180,7 +1180,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co PathfindingState *pf_s = new PathfindingState(width, height); // Convert all polygons - if (poly_list.segment) { + if (poly_list.getSegment()) { List *list = s->_segMan->lookupList(poly_list); Node *node = s->_segMan->lookupNode(list->first); @@ -1503,7 +1503,7 @@ reg_t kAvoidPath(EngineState *s, int argc, reg_t *argv) { draw_point(s, start, 1, width, height); draw_point(s, end, 0, width, height); - if (poly_list.segment) { + if (poly_list.getSegment()) { print_input(s, poly_list, start, end, opt); draw_input(s, poly_list, start, end, opt, width, height); } diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 9b0e490d7e..2c115be500 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -140,7 +140,7 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) { debugC(kDebugLevelMemory, "Attempting to clone from %04x:%04x", PRINT_REG(parentAddr)); - uint16 infoSelector = parentObj->getInfoSelector().offset; + uint16 infoSelector = parentObj->getInfoSelector().getOffset(); cloneObj = s->_segMan->allocateClone(&cloneAddr); if (!cloneObj) { @@ -169,8 +169,8 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) { cloneObj->setSpeciesSelector(cloneObj->getPos()); if (parentObj->isClass()) cloneObj->setSuperClassSelector(parentObj->getPos()); - s->_segMan->getScript(parentObj->getPos().segment)->incrementLockers(); - s->_segMan->getScript(cloneObj->getPos().segment)->incrementLockers(); + s->_segMan->getScript(parentObj->getPos().getSegment())->incrementLockers(); + s->_segMan->getScript(cloneObj->getPos().getSegment())->incrementLockers(); return cloneAddr; } @@ -191,7 +191,7 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) { // At least kq4early relies on this behavior. The scripts clone "Sound", then set bit 1 manually // and call kDisposeClone later. In that case we may not free it, otherwise we will run into issues // later, because kIsObject would then return false and Sound object wouldn't get checked. - uint16 infoSelector = object->getInfoSelector().offset; + uint16 infoSelector = object->getInfoSelector().getOffset(); if ((infoSelector & 3) == kInfoFlagClone) object->markAsFreed(); @@ -203,7 +203,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { int script = argv[0].toUint16(); uint16 index = (argc > 1) ? argv[1].toUint16() : 0; - if (argv[0].segment) + if (argv[0].getSegment()) return argv[0]; SegmentId scriptSeg = s->_segMan->getScriptSegment(script, SCRIPT_GET_LOAD); @@ -226,11 +226,6 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } - if (index > scr->getExportsNr()) { - error("Dispatch index too big: %d > %d", index, scr->getExportsNr()); - return NULL_REG; - } - uint16 address = scr->validateExportFunc(index, true); // Point to the heap for SCI1.1 - SCI2.1 games @@ -251,12 +246,12 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { } reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) { - int script = argv[0].offset; + int script = argv[0].getOffset(); SegmentId id = s->_segMan->getScriptSegment(script); Script *scr = s->_segMan->getScriptIfLoaded(id); if (scr && !scr->isMarkedAsDeleted()) { - if (s->_executionStack.back().addr.pc.segment != id) + if (s->_executionStack.back().addr.pc.getSegment() != id) scr->setLockers(1); } @@ -273,7 +268,7 @@ reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) { } reg_t kIsObject(EngineState *s, int argc, reg_t *argv) { - if (argv[0].offset == SIGNAL_OFFSET) // Treated specially + if (argv[0].getOffset() == SIGNAL_OFFSET) // Treated specially return NULL_REG; else return make_reg(0, s->_segMan->isHeapObject(argv[0])); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index c469f775f9..0633267db4 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -140,8 +140,14 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { ((argv[3].toUint16() & 0xff) << 16) | ((argv[4].toUint16() & 0xff) << 8) | (argv[5].toUint16() & 0xff); - if (argc == 8) - warning("kDoAudio: Play called with SQ6 extra parameters"); + // Removed warning because of the high amount of console spam + /*if (argc == 8) { + // TODO: Handle the extra 2 SCI21 params + // argv[6] is always 1 + // argv[7] is the contents of global 229 (0xE5) + warning("kDoAudio: Play called with SCI2.1 extra parameters: %04x:%04x and %04x:%04x", + PRINT_REG(argv[6]), PRINT_REG(argv[7])); + }*/ } else { warning("kDoAudio: Play called with an unknown number of parameters (%d)", argc); return NULL_REG; @@ -240,6 +246,11 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { // Used in Pharkas whenever a speech sample starts (takes no params) //warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1); break; + case 17: + // Seems to be some sort of audio sync, used in SQ6. Silenced the + // warning due to the high level of spam it produces. (takes no params) + //warning("kDoAudio: Unhandled case 17, %d extra arguments passed", argc - 1); + break; default: warning("kDoAudio: Unhandled case %d, %d extra arguments passed", argv[0].toUint16(), argc - 1); } diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index fe8d631497..c22d7c7b1e 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -33,7 +33,7 @@ namespace Sci { reg_t kStrEnd(EngineState *s, int argc, reg_t *argv) { reg_t address = argv[0]; - address.offset += s->_segMan->strlen(address); + address.incOffset(s->_segMan->strlen(address)); return address; } @@ -96,7 +96,7 @@ reg_t kStrAt(EngineState *s, int argc, reg_t *argv) { byte value; byte newvalue = 0; - unsigned int offset = argv[1].toUint16(); + uint16 offset = argv[1].toUint16(); if (argc > 2) newvalue = argv[2].toSint16(); @@ -123,18 +123,22 @@ reg_t kStrAt(EngineState *s, int argc, reg_t *argv) { oddOffset = !oddOffset; if (!oddOffset) { - value = tmp.offset & 0x00ff; + value = tmp.getOffset() & 0x00ff; if (argc > 2) { /* Request to modify this char */ - tmp.offset &= 0xff00; - tmp.offset |= newvalue; - tmp.segment = 0; + uint16 tmpOffset = tmp.toUint16(); + tmpOffset &= 0xff00; + tmpOffset |= newvalue; + tmp.setOffset(tmpOffset); + tmp.setSegment(0); } } else { - value = tmp.offset >> 8; + value = tmp.getOffset() >> 8; if (argc > 2) { /* Request to modify this char */ - tmp.offset &= 0x00ff; - tmp.offset |= newvalue << 8; - tmp.segment = 0; + uint16 tmpOffset = tmp.toUint16(); + tmpOffset &= 0x00ff; + tmpOffset |= newvalue << 8; + tmp.setOffset(tmpOffset); + tmp.setSegment(0); } } } @@ -204,7 +208,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) { int strLength = 0; /* Used for stuff like "%13s" */ bool unsignedVar = false; - if (position.segment) + if (position.getSegment()) startarg = 2; else { // WORKAROUND: QFG1 VGA Mac calls this without the first parameter (dest). It then @@ -291,7 +295,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) { if (extralen < 0) extralen = 0; - if (reg.segment) /* Heap address? */ + if (reg.getSegment()) /* Heap address? */ paramindex++; else paramindex += 2; /* No, text resource address */ @@ -653,10 +657,16 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { case 1: // Size return make_reg(0, s->_segMan->getString(argv[1]).size()); case 2: { // At (return value at an index) - if (argv[1].segment == s->_segMan->getStringSegmentId()) - return make_reg(0, s->_segMan->lookupString(argv[1])->getRawData()[argv[2].toUint16()]); - - return make_reg(0, s->_segMan->getString(argv[1])[argv[2].toUint16()]); + // Note that values are put in bytes to avoid sign extension + if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) { + SciString *string = s->_segMan->lookupString(argv[1]); + byte val = string->getRawData()[argv[2].toUint16()]; + return make_reg(0, val); + } else { + Common::String string = s->_segMan->getString(argv[1]); + byte val = string[argv[2].toUint16()]; + return make_reg(0, val); + } } case 3: { // Atput (put value at an index) SciString *string = s->_segMan->lookupString(argv[1]); @@ -699,7 +709,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { uint32 string2Size = 0; Common::String string; - if (argv[3].segment == s->_segMan->getStringSegmentId()) { + if (argv[3].getSegment() == s->_segMan->getStringSegmentId()) { SciString *sstr; sstr = s->_segMan->lookupString(argv[3]); string2 = sstr->getRawData(); @@ -749,7 +759,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { SciString *dupString = s->_segMan->allocateString(&stringHandle); - if (argv[1].segment == s->_segMan->getStringSegmentId()) { + if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) { *dupString = *s->_segMan->lookupString(argv[1]); } else { dupString->fromString(s->_segMan->getString(argv[1])); diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index c9cf652013..6bf9aff2fe 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -32,6 +32,7 @@ #include "common/str.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/palette.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" #include "video/video_decoder.h" @@ -49,6 +50,8 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { if (!videoDecoder) return; + videoDecoder->start(); + byte *scaleBuffer = 0; byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel; uint16 width = videoDecoder->getWidth(); @@ -86,9 +89,12 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { } bool skipVideo = false; + EngineState *s = g_sci->getEngineState(); - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + if (videoDecoder->hasDirtyPalette()) { + const byte *palette = videoDecoder->getPalette() + s->_vmdPalStart * 3; + g_system->getPaletteManager()->setPalette(palette, s->_vmdPalStart, s->_vmdPalEnd - s->_vmdPalStart); + } while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { @@ -100,11 +106,13 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { g_sci->_gfxScreen->scale2x((byte *)frame->pixels, scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel); g_system->copyRectToScreen(scaleBuffer, pitch, x, y, width, height); } else { - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, width, height); + g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, width, height); } - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + if (videoDecoder->hasDirtyPalette()) { + const byte *palette = videoDecoder->getPalette() + s->_vmdPalStart * 3; + g_system->getPaletteManager()->setPalette(palette, s->_vmdPalStart, s->_vmdPalEnd - s->_vmdPalStart); + } g_system->updateScreen(); } @@ -135,7 +143,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { Video::VideoDecoder *videoDecoder = 0; - if (argv[0].segment != 0) { + if (argv[0].getSegment() != 0) { Common::String filename = s->_segMan->getString(argv[0]); if (g_sci->getPlatform() == Common::kPlatformMacintosh) { @@ -156,9 +164,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } else { // DOS SEQ // SEQ's are called with no subops, just the string and delay - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks - videoDecoder = seqDecoder; + // Time is specified as ticks + videoDecoder = new SEQDecoder(argv[1].toUint16()); if (!videoDecoder->loadFile(filename)) { warning("Failed to open movie file %s", filename.c_str()); @@ -184,7 +191,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 0: { Common::String filename = s->_segMan->getString(argv[1]); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (filename.equalsIgnoreCase("gk2a.avi")) { // HACK: Switch to 16bpp graphics for Indeo3. @@ -203,6 +210,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { warning("Failed to open movie file %s", filename.c_str()); delete videoDecoder; videoDecoder = 0; + } else { + s->_videoState.fileName = filename; } break; } @@ -244,6 +253,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); g_sci->_robotDecoder->load(id); + g_sci->_robotDecoder->start(); g_sci->_robotDecoder->setPos(x, y); } break; @@ -259,12 +269,13 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { warning("kRobot(%d)", subop); break; case 8: // sync - if ((uint32)g_sci->_robotDecoder->getCurFrame() != g_sci->_robotDecoder->getFrameCount() - 1) { - writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); - } else { + //if (true) { // debug: automatically skip all robot videos + if (g_sci->_robotDecoder->endOfVideo()) { g_sci->_robotDecoder->close(); // Signal the engine scripts that the video is done writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); + } else { + writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); } break; default: @@ -302,7 +313,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { // with subfx 21. The subtleness has to do with creation of temporary // planes and positioning relative to such planes. - uint16 flags = argv[3].offset; + uint16 flags = argv[3].getOffset(); Common::String flagspec; if (argc > 3) { @@ -330,16 +341,22 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { s->_videoState.flags = flags; } - warning("x, y: %d, %d", argv[1].offset, argv[2].offset); - s->_videoState.x = argv[1].offset; - s->_videoState.y = argv[2].offset; + warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset()); + s->_videoState.x = argv[1].getOffset(); + s->_videoState.y = argv[2].getOffset(); if (argc > 4 && flags & 16) - warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].offset, argv[5].offset, argv[6].offset); + warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset()); break; } case 6: // Play - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); + + if (s->_videoState.fileName.empty()) { + // Happens in Lighthouse + warning("kPlayVMD: Empty filename passed"); + return s->r_acc; + } if (!videoDecoder->loadFile(s->_videoState.fileName)) { warning("Could not open VMD %s", s->_videoState.fileName.c_str()); @@ -354,6 +371,10 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { if (reshowCursor) g_sci->_gfxCursor->kernelShow(); break; + case 23: // set video palette range + s->_vmdPalStart = argv[1].toUint16(); + s->_vmdPalEnd = argv[2].toUint16(); + break; case 14: // Takes an additional integer parameter (e.g. 3) case 16: @@ -387,7 +408,7 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) { s->_videoState.reset(); s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16()); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (!videoDecoder->loadFile(s->_videoState.fileName)) { warning("Could not open Duck %s", s->_videoState.fileName.c_str()); diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp index cddd01e10c..a92d572d35 100644 --- a/engines/sci/engine/message.cpp +++ b/engines/sci/engine/message.cpp @@ -400,11 +400,21 @@ Common::String MessageState::processString(const char *s) { void MessageState::outputString(reg_t buf, const Common::String &str) { #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { - SciString *sciString = _segMan->lookupString(buf); - sciString->setSize(str.size() + 1); - for (uint32 i = 0; i < str.size(); i++) - sciString->setValue(i, str.c_str()[i]); - sciString->setValue(str.size(), 0); + if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_STRING) { + SciString *sciString = _segMan->lookupString(buf); + sciString->setSize(str.size() + 1); + for (uint32 i = 0; i < str.size(); i++) + sciString->setValue(i, str.c_str()[i]); + sciString->setValue(str.size(), 0); + } else if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_ARRAY) { + // Happens in the intro of LSL6, we are asked to write the string + // into an array + SciArray<reg_t> *sciString = _segMan->lookupArray(buf); + sciString->setSize(str.size() + 1); + for (uint32 i = 0; i < str.size(); i++) + sciString->setValue(i, make_reg(0, str.c_str()[i])); + sciString->setValue(str.size(), NULL_REG); + } } else { #endif SegmentRef buffer_r = _segMan->dereference(buf); diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp index 78e216cdb5..b28026b71f 100644 --- a/engines/sci/engine/object.cpp +++ b/engines/sci/engine/object.cpp @@ -44,15 +44,15 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme error("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location); return false; } - block[idx].segment = segment; // Perform relocation + block[idx].setSegment(segment); // Perform relocation if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) - block[idx].offset += scriptSize; + block[idx].incOffset(scriptSize); return true; } void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { - byte *data = buf + obj_pos.offset; + byte *data = buf + obj_pos.getOffset(); _baseObj = data; _pos = obj_pos; @@ -109,16 +109,16 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { } bool Object::relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize) { - return relocateBlock(_variables, getPos().offset, segment, location, scriptSize); + return relocateBlock(_variables, getPos().getOffset(), segment, location, scriptSize); } -bool Object::relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize) { +bool Object::relocateSci3(SegmentId segment, uint32 location, int offset, size_t scriptSize) { assert(_propertyOffsetsSci3); for (uint i = 0; i < _variables.size(); ++i) { if (location == _propertyOffsetsSci3[i]) { - _variables[i].segment = segment; - _variables[i].offset += offset; + _variables[i].setSegment(segment); + _variables[i].incOffset(offset); return true; } } @@ -148,21 +148,21 @@ int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { } void Object::initSpecies(SegManager *segMan, reg_t addr) { - uint16 speciesOffset = getSpeciesSelector().offset; + uint16 speciesOffset = getSpeciesSelector().getOffset(); if (speciesOffset == 0xffff) // -1 setSpeciesSelector(NULL_REG); // no species else - setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr)); + setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr.getSegment())); } void Object::initSuperClass(SegManager *segMan, reg_t addr) { - uint16 superClassOffset = getSuperClassSelector().offset; + uint16 superClassOffset = getSuperClassSelector().getOffset(); if (superClassOffset == 0xffff) // -1 setSuperClassSelector(NULL_REG); // no superclass else - setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr)); + setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr.getSegment())); } bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) { @@ -187,7 +187,7 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClas // The effect is that a number of its method selectors may be // treated as variable selectors, causing unpredictable effects. - int objScript = segMan->getScript(_pos.segment)->getScriptNumber(); + int objScript = segMan->getScript(_pos.getSegment())->getScriptNumber(); // We have to do a little bit of work to get the name of the object // before any relocations are done. @@ -196,7 +196,7 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClas if (nameReg.isNull()) { name = "<no name>"; } else { - nameReg.segment = _pos.segment; + nameReg.setSegment(_pos.getSegment()); name = segMan->derefString(nameReg); if (!name) name = "<invalid name>"; @@ -286,7 +286,7 @@ void Object::initSelectorsSci3(const byte *buf) { _variables.resize(properties); uint16 *propertyIds = (uint16 *)malloc(sizeof(uint16) * properties); // uint16 *methodOffsets = (uint16 *)malloc(sizeof(uint16) * 2 * methods); - uint16 *propertyOffsets = (uint16 *)malloc(sizeof(uint16) * properties); + uint32 *propertyOffsets = (uint32 *)malloc(sizeof(uint32) * properties); int propertyCounter = 0; int methodCounter = 0; @@ -314,7 +314,8 @@ void Object::initSelectorsSci3(const byte *buf) { WRITE_SCI11ENDIAN_UINT16(&propertyIds[propertyCounter], groupBaseId + bit); _variables[propertyCounter] = make_reg(0, value); - propertyOffsets[propertyCounter] = (seeker + bit * 2) - buf; + uint32 propertyOffset = (seeker + bit * 2) - buf; + propertyOffsets[propertyCounter] = propertyOffset; ++propertyCounter; } else if (value != 0xffff) { // Method _baseMethod.push_back(groupBaseId + bit); diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h index 0ca16b48a2..1ea9ae449a 100644 --- a/engines/sci/engine/object.h +++ b/engines/sci/engine/object.h @@ -168,7 +168,7 @@ public: uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2; if (getSciVersion() == SCI_VERSION_3) offset--; - return make_reg(_pos.segment, _baseMethod[offset]); + return make_reg(_pos.getSegment(), _baseMethod[offset]); } Selector getFuncSelector(uint16 i) const { @@ -198,7 +198,7 @@ public: */ int locateVarSelector(SegManager *segMan, Selector slc) const; - bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); } + bool isClass() const { return (getInfoSelector().getOffset() & kInfoFlagClass); } const Object *getClass(SegManager *segMan) const; void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } @@ -223,7 +223,7 @@ public: } bool relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize); - bool relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize); + bool relocateSci3(SegmentId segment, uint32 location, int offset, size_t scriptSize); int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; @@ -238,7 +238,7 @@ private: const byte *_baseObj; /**< base + object offset within base */ const uint16 *_baseVars; /**< Pointer to the varselector area for this object */ Common::Array<uint16> _baseMethod; /**< Pointer to the method selector area for this object */ - uint16 *_propertyOffsetsSci3; /**< This is used to enable relocation of property valuesa in SCI3 */ + uint32 *_propertyOffsetsSci3; /**< This is used to enable relocation of property valuesa in SCI3 */ Common::Array<reg_t> _variables; uint16 _methodCount; diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 404bea799d..ff3f19b53d 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -115,8 +115,9 @@ void syncArray(Common::Serializer &s, Common::Array<T> &arr) { template<> void syncWithSerializer(Common::Serializer &s, reg_t &obj) { - s.syncAsUint16LE(obj.segment); - s.syncAsUint16LE(obj.offset); + // Segment and offset are accessed directly here + s.syncAsUint16LE(obj._segment); + s.syncAsUint16LE(obj._offset); } template<> @@ -189,7 +190,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { assert(mobj); - // Let the object sync custom data + // Let the object sync custom data. Scripts are loaded at this point. mobj->saveLoadWithSerializer(s); if (type == SEG_TYPE_SCRIPT) { @@ -200,12 +201,9 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { // Hook the script up in the script->segment map _scriptSegMap[scr->getScriptNumber()] = i; - // Now, load the script itself - scr->load(g_sci->getResMan()); - ObjMap objects = scr->getObjectMap(); for (ObjMap::iterator it = objects.begin(); it != objects.end(); ++it) - it->_value.syncBaseObject(scr->getBuf(it->_value.getPos().offset)); + it->_value.syncBaseObject(scr->getBuf(it->_value.getPos().getOffset())); } @@ -467,7 +465,7 @@ void Script::syncStringHeap(Common::Serializer &s) { break; } while (1); - } else { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1){ // Strings in SCI1.1 come after the object instances byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2; @@ -477,6 +475,8 @@ void Script::syncStringHeap(Common::Serializer &s) { // Now, sync everything till the end of the buffer s.syncBytes(buf, _heapSize - (buf - _heapStart)); + } else if (getSciVersion() == SCI_VERSION_3) { + warning("TODO: syncStringHeap(): Implement SCI3 variant"); } } @@ -484,7 +484,7 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsSint32LE(_nr); if (s.isLoading()) - init(_nr, g_sci->getResMan()); + load(_nr, g_sci->getResMan()); s.skip(4, VER(14), VER(22)); // OBSOLETE: Used to be _bufSize s.skip(4, VER(14), VER(22)); // OBSOLETE: Used to be _scriptSize s.skip(4, VER(14), VER(22)); // OBSOLETE: Used to be _heapSize @@ -508,7 +508,7 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) { Object tmp; for (uint i = 0; i < numObjs; ++i) { syncWithSerializer(s, tmp); - _objects[tmp.getPos().offset] = tmp; + _objects[tmp.getPos().getOffset()] = tmp; } } else { ObjMap::iterator it; @@ -817,7 +817,7 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::Strin Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false); meta.script0Size = script0->size; - meta.gameObjectOffset = g_sci->getGameObject().offset; + meta.gameObjectOffset = g_sci->getGameObject().getOffset(); // Checking here again if (s->executionStackBase) { @@ -868,7 +868,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { if (meta.gameObjectOffset > 0 && meta.script0Size > 0) { Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false); - if (script0->size != meta.script0Size || g_sci->getGameObject().offset != meta.gameObjectOffset) { + if (script0->size != meta.script0Size || g_sci->getGameObject().getOffset() != meta.gameObjectOffset) { //warning("This saved game was created with a different version of the game, unable to load it"); showScummVMDialog("This saved game was created with a different version of the game, unable to load it"); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 8b26969f4a..037f4ab700 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -32,58 +32,48 @@ namespace Sci { -Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) { +Script::Script() : SegmentObj(SEG_TYPE_SCRIPT), _buf(NULL) { + freeScript(); +} + +Script::~Script() { + freeScript(); +} + +void Script::freeScript() { _nr = 0; + + free(_buf); _buf = NULL; _bufSize = 0; _scriptSize = 0; + _heapStart = NULL; _heapSize = 0; - _synonyms = NULL; - _heapStart = NULL; _exportTable = NULL; + _numExports = 0; + _synonyms = NULL; + _numSynonyms = 0; _localsOffset = 0; _localsSegment = 0; _localsBlock = NULL; _localsCount = 0; + _lockers = 1; _markedAsDeleted = false; + _objects.clear(); } -Script::~Script() { +void Script::load(int script_nr, ResourceManager *resMan) { freeScript(); -} - -void Script::freeScript() { - free(_buf); - _buf = NULL; - _bufSize = 0; - - _objects.clear(); -} -void Script::init(int script_nr, ResourceManager *resMan) { Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0); - if (!script) error("Script %d not found", script_nr); - _localsOffset = 0; - _localsBlock = NULL; - _localsCount = 0; - - _markedAsDeleted = false; - _nr = script_nr; - _buf = 0; - _heapStart = 0; - - _scriptSize = script->size; - _bufSize = script->size; - _heapSize = 0; - - _lockers = 1; + _bufSize = _scriptSize = script->size; if (getSciVersion() == SCI_VERSION_0_EARLY) { _bufSize += READ_LE_UINT16(script->data) * 2; @@ -115,16 +105,18 @@ void Script::init(int script_nr, ResourceManager *resMan) { // scheme. We need an overlaying mechanism, or a mechanism to split script parts // in different segments to handle these. For now, simply stop when such a script // is found. + // + // Known large SCI 3 scripts are: + // Lighthouse: 9, 220, 270, 351, 360, 490, 760, 765, 800 + // LSL7: 240, 511, 550 + // Phantasmagoria 2: none (hooray!) + // RAMA: 70 + // // TODO: Remove this once such a mechanism is in place if (script->size > 65535) error("TODO: SCI script %d is over 64KB - it's %d bytes long. This can't " "be handled at the moment, thus stopping", script_nr, script->size); } -} - -void Script::load(ResourceManager *resMan) { - Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0); - assert(script != 0); uint extraLocalsWorkaround = 0; if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size == 11140) { @@ -156,11 +148,6 @@ void Script::load(ResourceManager *resMan) { memcpy(_heapStart, heap->data, heap->size); } - _exportTable = 0; - _numExports = 0; - _synonyms = 0; - _numSynonyms = 0; - if (getSciVersion() <= SCI_VERSION_1_LATE) { _exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS); if (_exportTable) { @@ -212,7 +199,7 @@ void Script::load(ResourceManager *resMan) { _localsOffset = 0; if (_localsOffset + _localsCount * 2 + 1 >= (int)_bufSize) { - error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, _bufSize); + error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, (int)_bufSize); //_localsCount = (_bufSize - _localsOffset) >> 1; } } @@ -252,14 +239,14 @@ const Object *Script::getObject(uint16 offset) const { Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) { if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit) - obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) + obj_pos.incOffset(8); // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) - if (obj_pos.offset >= _bufSize) + if (obj_pos.getOffset() >= _bufSize) error("Attempt to initialize object beyond end of script"); // Get the object at the specified position and init it. This will // automatically "allocate" space for it in the _objects map if necessary. - Object *obj = &_objects[obj_pos.offset]; + Object *obj = &_objects[obj_pos.getOffset()]; obj->init(_buf, obj_pos, fullObjectInit); return obj; @@ -282,9 +269,9 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme error("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location); return false; } - block[idx].segment = segment; // Perform relocation + block[idx].setSegment(segment); // Perform relocation if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) - block[idx].offset += scriptSize; + block[idx].incOffset(scriptSize); return true; } @@ -323,23 +310,23 @@ void Script::relocateSci0Sci21(reg_t block) { heapOffset = _scriptSize; } - if (block.offset >= (uint16)heapSize || - READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset >= (uint16)heapSize) + if (block.getOffset() >= (uint16)heapSize || + READ_SCI11ENDIAN_UINT16(heap + block.getOffset()) * 2 + block.getOffset() >= (uint16)heapSize) error("Relocation block outside of script"); - int count = READ_SCI11ENDIAN_UINT16(heap + block.offset); + int count = READ_SCI11ENDIAN_UINT16(heap + block.getOffset()); int exportIndex = 0; int pos = 0; for (int i = 0; i < count; i++) { - pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset; + pos = READ_SCI11ENDIAN_UINT16(heap + block.getOffset() + 2 + (exportIndex * 2)) + heapOffset; // This occurs in SCI01/SCI1 games where usually one export value is // zero. It seems that in this situation, we should skip the export and // move to the next one, though the total count of valid exports remains // the same if (!pos) { exportIndex++; - pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset; + pos = READ_SCI11ENDIAN_UINT16(heap + block.getOffset() + 2 + (exportIndex * 2)) + heapOffset; if (!pos) error("Script::relocate(): Consecutive zero exports found"); } @@ -348,12 +335,12 @@ void Script::relocateSci0Sci21(reg_t block) { // We only relocate locals and objects here, and ignore relocation of // code blocks. In SCI1.1 and newer versions, only locals and objects // are relocated. - if (!relocateLocal(block.segment, pos)) { + if (!relocateLocal(block.getSegment(), pos)) { // Not a local? It's probably an object or code block. If it's an // object, relocate it. const ObjMap::iterator end = _objects.end(); for (ObjMap::iterator it = _objects.begin(); it != end; ++it) - if (it->_value.relocateSci0Sci21(block.segment, pos, _scriptSize)) + if (it->_value.relocateSci0Sci21(block.getSegment(), pos, _scriptSize)) break; } @@ -370,7 +357,7 @@ void Script::relocateSci3(reg_t block) { const byte *seeker = relocStart; while (seeker < _buf + _bufSize) { // TODO: Find out what UINT16 at (seeker + 8) means - it->_value.relocateSci3(block.segment, + it->_value.relocateSci3(block.getSegment(), READ_SCI11ENDIAN_UINT32(seeker), READ_SCI11ENDIAN_UINT32(seeker + 4), _scriptSize); @@ -398,7 +385,7 @@ void Script::setLockers(int lockers) { _lockers = lockers; } -uint16 Script::validateExportFunc(int pubfunct, bool relocate) { +uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) { bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE); if (_numExports <= pubfunct) { @@ -409,17 +396,17 @@ uint16 Script::validateExportFunc(int pubfunct, bool relocate) { if (exportsAreWide) pubfunct *= 2; - uint16 offset; + uint32 offset; - if (getSciVersion() != SCI_VERSION_3 || !relocate) { + if (getSciVersion() != SCI_VERSION_3) { offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct); } else { - offset = relocateOffsetSci3(pubfunct * 2 + 22); + if (!relocSci3) + offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct) + getCodeBlockOffsetSci3(); + else + offset = relocateOffsetSci3(pubfunct * 2 + 22); } - if (offset >= _bufSize) - error("Invalid export function pointer"); - // Check if the offset found points to a second export table (e.g. script 912 // in Camelot and script 306 in KQ4). Such offsets are usually small (i.e. < 10), // thus easily distinguished from actual code offsets. @@ -432,11 +419,16 @@ uint16 Script::validateExportFunc(int pubfunct, bool relocate) { if (secondExportTable) { secondExportTable += 3; // skip header plus 2 bytes (secondExportTable is a uint16 pointer) offset = READ_SCI11ENDIAN_UINT16(secondExportTable + pubfunct); - if (offset >= _bufSize) - error("Invalid export function pointer"); } } + // Note that it's perfectly normal to return a zero offset, especially in + // SCI1.1 and newer games. Examples include script 64036 in Torin's Passage, + // script 64908 in the demo of RAMA and script 1013 in KQ6 floppy. + + if (offset >= _bufSize) + error("Invalid export function pointer"); + return offset; } @@ -479,7 +471,7 @@ bool Script::isValidOffset(uint16 offset) const { } SegmentRef Script::dereference(reg_t pointer) { - if (pointer.offset > _bufSize) { + if (pointer.getOffset() > _bufSize) { error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)", PRINT_REG(pointer), (uint)_bufSize); return SegmentRef(); @@ -487,8 +479,8 @@ SegmentRef Script::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = true; - ret.maxSize = _bufSize - pointer.offset; - ret.raw = _buf + pointer.offset; + ret.maxSize = _bufSize - pointer.getOffset(); + ret.raw = _buf + pointer.getOffset(); return ret; } @@ -553,7 +545,7 @@ void Script::initializeClasses(SegManager *segMan) { uint16 marker; bool isClass = false; - uint16 classpos; + uint32 classpos; int16 species = 0; while (true) { @@ -564,7 +556,7 @@ void Script::initializeClasses(SegManager *segMan) { if (getSciVersion() <= SCI_VERSION_1_LATE && !marker) break; - if (getSciVersion() >= SCI_VERSION_1_1 && marker != 0x1234) + if (getSciVersion() >= SCI_VERSION_1_1 && marker != SCRIPT_OBJECT_MAGIC_NUMBER) break; if (getSciVersion() <= SCI_VERSION_1_LATE) { @@ -666,7 +658,7 @@ void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) { // Copy base from species class, as we need its selector IDs obj->setSuperClassSelector( - segMan->getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG)); + segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0)); // If object is instance, get -propDict- from class and set it for this // object. This is needed for ::isMemberOf() to work. @@ -699,7 +691,7 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) { reg_t reg = make_reg(segmentId, seeker - _buf); Object *obj = scriptObjInit(reg); - obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG)); + obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0)); seeker += READ_SCI11ENDIAN_UINT16(seeker + 2); } @@ -716,7 +708,7 @@ void Script::initializeObjects(SegManager *segMan, SegmentId segmentId) { } reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const { - addr.offset = 0; + addr.setOffset(0); return addr; } @@ -738,8 +730,8 @@ Common::Array<reg_t> Script::listAllDeallocatable(SegmentId segId) const { Common::Array<reg_t> Script::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; - if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) { - const Object *obj = getObject(addr.offset); + if (addr.getOffset() <= _bufSize && addr.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && offsetIsObject(addr.getOffset())) { + const Object *obj = getObject(addr.getOffset()); if (obj) { // Note all local variables, if we have a local variable environment if (_localsSegment) @@ -774,4 +766,8 @@ Common::Array<reg_t> Script::listObjectReferences() const { return tmp; } +bool Script::offsetIsObject(uint16 offset) const { + return (READ_SCI11ENDIAN_UINT16((const byte *)_buf + offset + SCRIPT_OBJECT_MAGIC_OFFSET) == SCRIPT_OBJECT_MAGIC_NUMBER); +} + } // End of namespace Sci diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 1ebae3b7a8..0b499203c2 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -57,7 +57,7 @@ private: int _lockers; /**< Number of classes and objects that require this script */ size_t _scriptSize; size_t _heapSize; - uint16 _bufSize; + size_t _bufSize; const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ uint16 _numExports; /**< Number of entries in the exports table */ @@ -89,14 +89,14 @@ public: void syncLocalsBlock(SegManager *segMan); ObjMap &getObjectMap() { return _objects; } const ObjMap &getObjectMap() const { return _objects; } + bool offsetIsObject(uint16 offset) const; public: Script(); ~Script(); void freeScript(); - void init(int script_nr, ResourceManager *resMan); - void load(ResourceManager *resMan); + void load(int script_nr, ResourceManager *resMan); void matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize); int32 findSignature(const SciScriptSignature *signature, const byte *scriptData, const uint32 scriptSize); @@ -197,11 +197,11 @@ public: * Validate whether the specified public function is exported by * the script in the specified segment. * @param pubfunct Index of the function to validate - * @param relocate Decide whether to relocate this public function or not + * @param relocSci3 Decide whether to relocate this SCI3 public function or not * @return NULL if the public function is invalid, its * offset into the script's segment otherwise */ - uint16 validateExportFunc(int pubfunct, bool relocate); + uint32 validateExportFunc(int pubfunct, bool relocSci3); /** * Marks the script as deleted. @@ -249,7 +249,7 @@ public: /** * Gets an offset to the beginning of the code block in a SCI3 script */ - int getCodeBlockOffset() { return READ_SCI11ENDIAN_UINT32(_buf); } + int getCodeBlockOffsetSci3() { return READ_SCI11ENDIAN_UINT32(_buf); } private: /** diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 187f1ce021..659c13b13e 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -775,7 +775,7 @@ const uint16 mothergoose256PatchReplay[] = { PATCH_END }; -// when saving, it also checks if the savegame-id is below 13. +// when saving, it also checks if the savegame ID is below 13. // we change this to check if below 113 instead const byte mothergoose256SignatureSaveLimit[] = { 5, @@ -978,7 +978,27 @@ const uint16 sq4CdPatchTextOptionsButton[] = { PATCH_END }; -// Patch 2: Add the ability to toggle among the three available options, +// Patch 2: Adjust a check in babbleIcon::init, which handles the babble icon +// (e.g. the two guys from Andromeda) shown when dying/quitting. +// Fixes bug #3538418. +const byte sq4CdSignatureBabbleIcon[] = { + 7, + 0x89, 0x5a, // lsg 5a + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x26, // bnt 26 [02a7] + 0 +}; + +const uint16 sq4CdPatchBabbleIcon[] = { + 0x89, 0x5a, // lsg 5a + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + 0x2f, 0x26, // bt 26 [02a7] + PATCH_END +}; + +// Patch 3: Add the ability to toggle among the three available options, // when the text options button is clicked: "Speech", "Text" and "Both". // Refer to the patch above for additional details. // iconTextSwitch::doit (called when the text options button is clicked) @@ -1030,6 +1050,7 @@ const SciScriptSignature sq4Signatures[] = { { 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, { 298, "Floppy (German): endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x4c), -3, sq4FloppySignatureEndlessFlightGerman, sq4FloppyPatchEndlessFlight }, { 818, "CD: Speech and subtitles option", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x3c, 0x35), 0, sq4CdSignatureTextOptions, sq4CdPatchTextOptions }, + { 0, "CD: Babble icon speech and subtitles fix", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x35, 0x02), 0, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon }, { 818, "CD: Speech and subtitles option button", 1, PATCH_MAGICDWORD(0x35, 0x01, 0xa1, 0x53), 0, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index ef61b2e28a..d3abb9ff41 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -50,7 +50,7 @@ const char *opcodeNames[] = { "lea", "selfID", "dummy", "pprev", "pToa", "aTop", "pTos", "sTop", "ipToa", "dpToa", "ipTos", "dpTos", "lofsa", "lofss", "push0", - "push1", "push2", "pushSelf", "dummy", "lag", + "push1", "push2", "pushSelf", "line", "lag", "lal", "lat", "lap", "lsg", "lsl", "lst", "lsp", "lagi", "lali", "lati", "lapi", "lsgi", "lsli", "lsti", "lspi", @@ -68,18 +68,18 @@ const char *opcodeNames[] = { #endif // REDUCE_MEMORY_USAGE // Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered. -reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode) { - SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT); +reg_t disassemble(EngineState *s, reg32_t pos, bool printBWTag, bool printBytecode) { + SegmentObj *mobj = s->_segMan->getSegment(pos.getSegment(), SEG_TYPE_SCRIPT); Script *script_entity = NULL; const byte *scr; - int scr_size; - reg_t retval = make_reg(pos.segment, pos.offset + 1); + uint32 scr_size; + reg_t retval = make_reg(pos.getSegment(), pos.getOffset() + 1); uint16 param_value = 0xffff; // Suppress GCC warning by setting default value, chose value as invalid to getKernelName etc. - int i = 0; + uint i = 0; Kernel *kernel = g_sci->getKernel(); if (!mobj) { - warning("Disassembly failed: Segment %04x non-existant or not a script", pos.segment); + warning("Disassembly failed: Segment %04x non-existant or not a script", pos.getSegment()); return retval; } else script_entity = (Script *)mobj; @@ -87,28 +87,37 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode scr = script_entity->getBuf(); scr_size = script_entity->getBufSize(); - if (pos.offset >= scr_size) { + if (pos.getOffset() >= scr_size) { warning("Trying to disassemble beyond end of script"); return NULL_REG; } int16 opparams[4]; byte opsize; - int bytecount = readPMachineInstruction(scr + pos.offset, opsize, opparams); + uint bytecount = readPMachineInstruction(scr + pos.getOffset(), opsize, opparams); const byte opcode = opsize >> 1; - opsize &= 1; // byte if true, word if false - debugN("%04x:%04x: ", PRINT_REG(pos)); + if (opcode == op_pushSelf) { // 0x3e (62) + if ((opsize & 1) && g_sci->getGameId() != GID_FANMADE) { + // Debug opcode op_file + debugN("file \"%s\"\n", scr + pos.getOffset() + 1); // +1: op_pushSelf size + retval.incOffset(bytecount - 1); + return retval; + } + } + + opsize &= 1; // byte if true, word if false + if (printBytecode) { - if (pos.offset + bytecount > scr_size) { + if (pos.getOffset() + bytecount > scr_size) { warning("Operation arguments extend beyond end of script"); return retval; } for (i = 0; i < bytecount; i++) - debugN("%02x ", scr[pos.offset + i]); + debugN("%02x ", scr[pos.getOffset() + i]); for (i = bytecount; i < 5; i++) debugN(" "); @@ -130,16 +139,16 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode case Script_SByte: case Script_Byte: - param_value = scr[retval.offset]; - debugN(" %02x", scr[retval.offset]); - retval.offset++; + param_value = scr[retval.getOffset()]; + debugN(" %02x", scr[retval.getOffset()]); + retval.incOffset(1); break; case Script_Word: case Script_SWord: - param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.offset]); - debugN(" %04x", READ_SCI11ENDIAN_UINT16(&scr[retval.offset])); - retval.offset += 2; + param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]); + debugN(" %04x", READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()])); + retval.incOffset(2); break; case Script_SVariable: @@ -149,11 +158,12 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode case Script_Local: case Script_Temp: case Script_Param: - if (opsize) - param_value = scr[retval.offset++]; - else { - param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.offset]); - retval.offset += 2; + if (opsize) { + param_value = scr[retval.getOffset()]; + retval.incOffset(1); + } else { + param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]); + retval.incOffset(2); } if (opcode == op_callk) @@ -166,24 +176,26 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode break; case Script_Offset: - if (opsize) - param_value = scr[retval.offset++]; - else { - param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.offset]); - retval.offset += 2; + if (opsize) { + param_value = scr[retval.getOffset()]; + retval.incOffset(1); + } else { + param_value = READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]); + retval.incOffset(2); } debugN(opsize ? " %02x" : " %04x", param_value); break; case Script_SRelative: if (opsize) { - int8 offset = (int8)scr[retval.offset++]; - debugN(" %02x [%04x]", 0xff & offset, 0xffff & (retval.offset + offset)); + int8 offset = (int8)scr[retval.getOffset()]; + retval.incOffset(1); + debugN(" %02x [%04x]", 0xff & offset, 0xffff & (retval.getOffset() + offset)); } else { - int16 offset = (int16)READ_SCI11ENDIAN_UINT16(&scr[retval.offset]); - retval.offset += 2; - debugN(" %04x [%04x]", 0xffff & offset, 0xffff & (retval.offset + offset)); + int16 offset = (int16)READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]); + retval.incOffset(2); + debugN(" %04x [%04x]", 0xffff & offset, 0xffff & (retval.getOffset() + offset)); } break; @@ -216,8 +228,8 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode if (opcode == op_callk) { - int stackframe = (scr[pos.offset + 2] >> 1) + (s->r_rest); - int argc = ((s->xs->sp)[- stackframe - 1]).offset; + int stackframe = (scr[pos.getOffset() + 2] >> 1) + (s->r_rest); + int argc = ((s->xs->sp)[- stackframe - 1]).getOffset(); bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); if (!oldScriptHeader) @@ -233,13 +245,13 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode debugN(")\n"); } else if ((opcode == op_send) || (opcode == op_self)) { int restmod = s->r_rest; - int stackframe = (scr[pos.offset + 1] >> 1) + restmod; + int stackframe = (scr[pos.getOffset() + 1] >> 1) + restmod; reg_t *sb = s->xs->sp; uint16 selector; reg_t fun_ref; while (stackframe > 0) { - int argc = sb[- stackframe + 1].offset; + int argc = sb[- stackframe + 1].getOffset(); const char *name = NULL; reg_t called_obj_addr = s->xs->objp; @@ -248,7 +260,7 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode else if (opcode == op_self) called_obj_addr = s->xs->objp; - selector = sb[- stackframe].offset; + selector = sb[- stackframe].getOffset(); name = s->_segMan->getObjectName(called_obj_addr); @@ -290,20 +302,20 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode } bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) { - SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT); + SegmentObj *mobj = s->_segMan->getSegment(pos.getSegment(), SEG_TYPE_SCRIPT); if (!mobj) return false; Script *script_entity = (Script *)mobj; const byte *scr = script_entity->getBuf(); - int scr_size = script_entity->getScriptSize(); + uint scr_size = script_entity->getScriptSize(); - if (pos.offset >= scr_size) + if (pos.getOffset() >= scr_size) return false; int16 opparams[4]; byte opsize; - int bytecount = readPMachineInstruction(scr + pos.offset, opsize, opparams); + int bytecount = readPMachineInstruction(scr + pos.getOffset(), opsize, opparams); const byte opcode = opsize >> 1; switch (opcode) { @@ -313,7 +325,7 @@ bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) { { reg_t jmpTarget = pos + bytecount + opparams[0]; // QFG2 has invalid jumps outside the script buffer in script 260 - if (jmpTarget.offset >= scr_size) + if (jmpTarget.getOffset() >= scr_size) return false; jumpTarget = jmpTarget; } @@ -335,17 +347,17 @@ void SciEngine::scriptDebug() { } if (_debugState.seeking != kDebugSeekNothing) { - const reg_t pc = s->xs->addr.pc; - SegmentObj *mobj = s->_segMan->getSegment(pc.segment, SEG_TYPE_SCRIPT); + const reg32_t pc = s->xs->addr.pc; + SegmentObj *mobj = s->_segMan->getSegment(pc.getSegment(), SEG_TYPE_SCRIPT); if (mobj) { Script *scr = (Script *)mobj; const byte *code_buf = scr->getBuf(); - int code_buf_size = scr->getBufSize(); - int opcode = pc.offset >= code_buf_size ? 0 : code_buf[pc.offset]; + uint16 code_buf_size = scr->getBufSize(); // TODO: change to a 32-bit integer for large SCI3 scripts + int opcode = pc.getOffset() >= code_buf_size ? 0 : code_buf[pc.getOffset()]; int op = opcode >> 1; - int paramb1 = pc.offset + 1 >= code_buf_size ? 0 : code_buf[pc.offset + 1]; - int paramf1 = (opcode & 1) ? paramb1 : (pc.offset + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + pc.offset + 1)); + uint16 paramb1 = pc.getOffset() + 1 >= code_buf_size ? 0 : code_buf[pc.getOffset() + 1]; + uint16 paramf1 = (opcode & 1) ? paramb1 : (pc.getOffset() + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + pc.getOffset() + 1)); switch (_debugState.seeking) { case kDebugSeekSpecialCallk: @@ -714,7 +726,7 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke else if (regType & SIG_IS_INVALID) debugN("INVALID"); else if (regType & SIG_TYPE_INTEGER) - debugN("%d", argv[parmNr].offset); + debugN("%d", argv[parmNr].getOffset()); else { debugN("%04x:%04x", PRINT_REG(argv[parmNr])); switch (regType) { @@ -723,12 +735,12 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke break; case SIG_TYPE_REFERENCE: { - SegmentObj *mobj = s->_segMan->getSegmentObj(argv[parmNr].segment); + SegmentObj *mobj = s->_segMan->getSegmentObj(argv[parmNr].getSegment()); switch (mobj->getType()) { case SEG_TYPE_HUNK: { HunkTable *ht = (HunkTable *)mobj; - int index = argv[parmNr].offset; + int index = argv[parmNr].getOffset(); if (ht->isValidEntry(index)) { // NOTE: This ", deleted" isn't as useful as it could // be because it prints the status _after_ the kernel @@ -765,7 +777,7 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke if (result.isPointer()) debugN(" = %04x:%04x\n", PRINT_REG(result)); else - debugN(" = %d\n", result.offset); + debugN(" = %d\n", result.getOffset()); } } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index cc127c8dbc..951fc7c363 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -81,7 +81,7 @@ void SegManager::initSysStrings() { if (getSciVersion() <= SCI_VERSION_1_1) { // We need to allocate system strings in one segment, for compatibility reasons allocDynmem(512, "system strings", &_saveDirPtr); - _parserPtr = make_reg(_saveDirPtr.segment, _saveDirPtr.offset + 256); + _parserPtr = make_reg(_saveDirPtr.getSegment(), _saveDirPtr.getOffset() + 256); #ifdef ENABLE_SCI32 } else { SciString *saveDirString = allocateString(&_saveDirPtr); @@ -143,16 +143,27 @@ Script *SegManager::allocateScript(int script_nr, SegmentId *segid) { } void SegManager::deallocate(SegmentId seg) { - if (!check(seg)) - error("SegManager::deallocate(): invalid segment ID"); + if (seg < 1 || (uint)seg >= _heap.size()) + error("Attempt to deallocate an invalid segment ID"); SegmentObj *mobj = _heap[seg]; + if (!mobj) + error("Attempt to deallocate an already freed segment"); if (mobj->getType() == SEG_TYPE_SCRIPT) { Script *scr = (Script *)mobj; _scriptSegMap.erase(scr->getScriptNumber()); - if (scr->getLocalsSegment()) - deallocate(scr->getLocalsSegment()); + if (scr->getLocalsSegment()) { + // Check if the locals segment has already been deallocated. + // If the locals block has been stored in a segment with an ID + // smaller than the segment ID of the script itself, it will be + // already freed at this point. This can happen when scripts are + // uninstantiated and instantiated again: they retain their own + // segment ID, but are allocated a new locals segment, which can + // have an ID smaller than the segment of the script itself. + if (_heap[scr->getLocalsSegment()]) + deallocate(scr->getLocalsSegment()); + } } delete mobj; @@ -163,7 +174,7 @@ bool SegManager::isHeapObject(reg_t pos) const { const Object *obj = getObject(pos); if (obj == NULL || (obj && obj->isFreed())) return false; - Script *scr = getScriptIfLoaded(pos.segment); + Script *scr = getScriptIfLoaded(pos.getSegment()); return !(scr && scr->isMarkedAsDeleted()); } @@ -214,21 +225,21 @@ SegmentObj *SegManager::getSegment(SegmentId seg, SegmentType type) const { } Object *SegManager::getObject(reg_t pos) const { - SegmentObj *mobj = getSegmentObj(pos.segment); + SegmentObj *mobj = getSegmentObj(pos.getSegment()); Object *obj = NULL; if (mobj != NULL) { if (mobj->getType() == SEG_TYPE_CLONES) { CloneTable *ct = (CloneTable *)mobj; - if (ct->isValidEntry(pos.offset)) - obj = &(ct->_table[pos.offset]); + if (ct->isValidEntry(pos.getOffset())) + obj = &(ct->_table[pos.getOffset()]); else warning("getObject(): Trying to get an invalid object"); } else if (mobj->getType() == SEG_TYPE_SCRIPT) { Script *scr = (Script *)mobj; - if (pos.offset <= scr->getBufSize() && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET - && RAW_IS_OBJECT(scr->getBuf(pos.offset))) { - obj = scr->getObject(pos.offset); + if (pos.getOffset() <= scr->getBufSize() && pos.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET + && scr->offsetIsObject(pos.getOffset())) { + obj = scr->getObject(pos.getOffset()); } } } @@ -246,7 +257,7 @@ const char *SegManager::getObjectName(reg_t pos) { return "<no name>"; const char *name = 0; - if (nameReg.segment) + if (nameReg.getSegment()) name = derefString(nameReg); if (!name) return "<invalid name>"; @@ -272,7 +283,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) { const Script *scr = (const Script *)mobj; const ObjMap &objects = scr->getObjectMap(); for (ObjMap::const_iterator it = objects.begin(); it != objects.end(); ++it) { - objpos.offset = it->_value.getPos().offset; + objpos.setOffset(it->_value.getPos().getOffset()); if (name == getObjectName(objpos)) result.push_back(objpos); } @@ -283,7 +294,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) { if (!ct->isValidEntry(idx)) continue; - objpos.offset = idx; + objpos.setOffset(idx); if (name == getObjectName(objpos)) result.push_back(objpos); } @@ -307,21 +318,6 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) { return result[index]; } -// validate the seg -// return: -// false - invalid seg -// true - valid seg -bool SegManager::check(SegmentId seg) { - if (seg < 1 || (uint)seg >= _heap.size()) { - return false; - } - if (!_heap[seg]) { - warning("SegManager: seg %x is removed from memory, but not removed from hash_map", seg); - return false; - } - return true; -} - // return the seg if script_id is valid and in the map, else 0 SegmentId SegManager::getScriptSegment(int script_id) const { return _scriptSegMap.getVal(script_id, 0); @@ -364,14 +360,14 @@ void SegManager::freeHunkEntry(reg_t addr) { return; } - HunkTable *ht = (HunkTable *)getSegment(addr.segment, SEG_TYPE_HUNK); + HunkTable *ht = (HunkTable *)getSegment(addr.getSegment(), SEG_TYPE_HUNK); if (!ht) { warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type", PRINT_REG(addr)); return; } - ht->freeEntryContents(addr.offset); + ht->freeEntryContents(addr.getOffset()); } reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) { @@ -398,14 +394,14 @@ reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) { } byte *SegManager::getHunkPointer(reg_t addr) { - HunkTable *ht = (HunkTable *)getSegment(addr.segment, SEG_TYPE_HUNK); + HunkTable *ht = (HunkTable *)getSegment(addr.getSegment(), SEG_TYPE_HUNK); - if (!ht || !ht->isValidEntry(addr.offset)) { + if (!ht || !ht->isValidEntry(addr.getOffset())) { // Valid SCI behavior, e.g. when loading/quitting return NULL; } - return (byte *)ht->_table[addr.offset].mem; + return (byte *)ht->_table[addr.getOffset()].mem; } Clone *SegManager::allocateClone(reg_t *addr) { @@ -462,35 +458,35 @@ reg_t SegManager::newNode(reg_t value, reg_t key) { } List *SegManager::lookupList(reg_t addr) { - if (getSegmentType(addr.segment) != SEG_TYPE_LISTS) { + if (getSegmentType(addr.getSegment()) != SEG_TYPE_LISTS) { error("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr)); return NULL; } - ListTable *lt = (ListTable *)_heap[addr.segment]; + ListTable *lt = (ListTable *)_heap[addr.getSegment()]; - if (!lt->isValidEntry(addr.offset)) { + if (!lt->isValidEntry(addr.getOffset())) { error("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr)); return NULL; } - return &(lt->_table[addr.offset]); + return &(lt->_table[addr.getOffset()]); } Node *SegManager::lookupNode(reg_t addr, bool stopOnDiscarded) { if (addr.isNull()) return NULL; // Non-error null - SegmentType type = getSegmentType(addr.segment); + SegmentType type = getSegmentType(addr.getSegment()); if (type != SEG_TYPE_NODES) { error("Attempt to use non-node %04x:%04x (type %d) as list node", PRINT_REG(addr), type); return NULL; } - NodeTable *nt = (NodeTable *)_heap[addr.segment]; + NodeTable *nt = (NodeTable *)_heap[addr.getSegment()]; - if (!nt->isValidEntry(addr.offset)) { + if (!nt->isValidEntry(addr.getOffset())) { if (!stopOnDiscarded) return NULL; @@ -498,19 +494,19 @@ Node *SegManager::lookupNode(reg_t addr, bool stopOnDiscarded) { return NULL; } - return &(nt->_table[addr.offset]); + return &(nt->_table[addr.getOffset()]); } SegmentRef SegManager::dereference(reg_t pointer) { SegmentRef ret; - if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) { + if (!pointer.getSegment() || (pointer.getSegment() >= _heap.size()) || !_heap[pointer.getSegment()]) { // This occurs in KQ5CD when interacting with certain objects warning("SegManager::dereference(): Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); return ret; /* Invalid */ } - SegmentObj *mobj = _heap[pointer.segment]; + SegmentObj *mobj = _heap[pointer.getSegment()]; return mobj->dereference(pointer); } @@ -522,7 +518,7 @@ static void *derefPtr(SegManager *segMan, reg_t pointer, int entries, bool wantR if (ret.isRaw != wantRaw) { warning("Dereferencing pointer %04x:%04x (type %d) which is %s, but expected %s", PRINT_REG(pointer), - segMan->getSegmentType(pointer.segment), + segMan->getSegmentType(pointer.getSegment()), ret.isRaw ? "raw" : "not raw", wantRaw ? "raw" : "not raw"); } @@ -565,15 +561,15 @@ static inline char getChar(const SegmentRef &ref, uint offset) { // segment 0xFFFF means that the scripts are using uninitialized temp-variable space // we can safely ignore this, if it isn't one of the first 2 chars. // foreign lsl3 uses kFileIO(readraw) and then immediately uses kReadNumber right at the start - if (val.segment != 0) - if (!((val.segment == 0xFFFF) && (offset > 1))) + if (val.getSegment() != 0) + if (!((val.getSegment() == 0xFFFF) && (offset > 1))) warning("Attempt to read character from non-raw data"); bool oddOffset = offset & 1; if (g_sci->isBE()) oddOffset = !oddOffset; - return (oddOffset ? val.offset >> 8 : val.offset & 0xff); + return (oddOffset ? val.getOffset() >> 8 : val.getOffset() & 0xff); } static inline void setChar(const SegmentRef &ref, uint offset, byte value) { @@ -582,16 +578,16 @@ static inline void setChar(const SegmentRef &ref, uint offset, byte value) { reg_t *val = ref.reg + offset / 2; - val->segment = 0; + val->setSegment(0); bool oddOffset = offset & 1; if (g_sci->isBE()) oddOffset = !oddOffset; if (oddOffset) - val->offset = (val->offset & 0x00ff) | (value << 8); + val->setOffset((val->getOffset() & 0x00ff) | (value << 8)); else - val->offset = (val->offset & 0xff00) | value; + val->setOffset((val->getOffset() & 0xff00) | value); } // TODO: memcpy, strcpy and strncpy could maybe be folded into a single function @@ -829,10 +825,11 @@ byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) { } bool SegManager::freeDynmem(reg_t addr) { - if (addr.segment < 1 || addr.segment >= _heap.size() || !_heap[addr.segment] || _heap[addr.segment]->getType() != SEG_TYPE_DYNMEM) + if (addr.getSegment() < 1 || addr.getSegment() >= _heap.size() || + !_heap[addr.getSegment()] || _heap[addr.getSegment()]->getType() != SEG_TYPE_DYNMEM) return false; // error - deallocate(addr.segment); + deallocate(addr.getSegment()); return true; // OK } @@ -854,28 +851,28 @@ SciArray<reg_t> *SegManager::allocateArray(reg_t *addr) { } SciArray<reg_t> *SegManager::lookupArray(reg_t addr) { - if (_heap[addr.segment]->getType() != SEG_TYPE_ARRAY) + if (_heap[addr.getSegment()]->getType() != SEG_TYPE_ARRAY) error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr)); - ArrayTable *arrayTable = (ArrayTable *)_heap[addr.segment]; + ArrayTable *arrayTable = (ArrayTable *)_heap[addr.getSegment()]; - if (!arrayTable->isValidEntry(addr.offset)) + if (!arrayTable->isValidEntry(addr.getOffset())) error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr)); - return &(arrayTable->_table[addr.offset]); + return &(arrayTable->_table[addr.getOffset()]); } void SegManager::freeArray(reg_t addr) { - if (_heap[addr.segment]->getType() != SEG_TYPE_ARRAY) + if (_heap[addr.getSegment()]->getType() != SEG_TYPE_ARRAY) error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr)); - ArrayTable *arrayTable = (ArrayTable *)_heap[addr.segment]; + ArrayTable *arrayTable = (ArrayTable *)_heap[addr.getSegment()]; - if (!arrayTable->isValidEntry(addr.offset)) + if (!arrayTable->isValidEntry(addr.getOffset())) error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr)); - arrayTable->_table[addr.offset].destroy(); - arrayTable->freeEntry(addr.offset); + arrayTable->_table[addr.getOffset()].destroy(); + arrayTable->freeEntry(addr.getOffset()); } SciString *SegManager::allocateString(reg_t *addr) { @@ -894,28 +891,28 @@ SciString *SegManager::allocateString(reg_t *addr) { } SciString *SegManager::lookupString(reg_t addr) { - if (_heap[addr.segment]->getType() != SEG_TYPE_STRING) + if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING) error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr)); - StringTable *stringTable = (StringTable *)_heap[addr.segment]; + StringTable *stringTable = (StringTable *)_heap[addr.getSegment()]; - if (!stringTable->isValidEntry(addr.offset)) + if (!stringTable->isValidEntry(addr.getOffset())) error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr)); - return &(stringTable->_table[addr.offset]); + return &(stringTable->_table[addr.getOffset()]); } void SegManager::freeString(reg_t addr) { - if (_heap[addr.segment]->getType() != SEG_TYPE_STRING) + if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING) error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr)); - StringTable *stringTable = (StringTable *)_heap[addr.segment]; + StringTable *stringTable = (StringTable *)_heap[addr.getSegment()]; - if (!stringTable->isValidEntry(addr.offset)) + if (!stringTable->isValidEntry(addr.getOffset())) error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr)); - stringTable->_table[addr.offset].destroy(); - stringTable->freeEntry(addr.offset); + stringTable->_table[addr.getOffset()].destroy(); + stringTable->freeEntry(addr.getOffset()); } #endif @@ -939,7 +936,7 @@ void SegManager::createClassTable() { _resMan->unlockResource(vocab996); } -reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller) { +reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment) { if (classnr == 0xffff) return NULL_REG; @@ -948,16 +945,16 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller return NULL_REG; } else { Class *the_class = &_classTable[classnr]; - if (!the_class->reg.segment) { + if (!the_class->reg.getSegment()) { getScriptSegment(the_class->script, lock); - if (!the_class->reg.segment) { + if (!the_class->reg.getSegment()) { error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;", classnr, the_class->script, the_class->script); return NULL_REG; } } else - if (caller.segment != the_class->reg.segment) - getScript(the_class->reg.segment)->incrementLockers(); + if (callerSegment != the_class->reg.getSegment()) + getScript(the_class->reg.getSegment())->incrementLockers(); return the_class->reg; } @@ -977,8 +974,7 @@ int SegManager::instantiateScript(int scriptNum) { scr = allocateScript(scriptNum, &segmentId); } - scr->init(scriptNum, _resMan); - scr->load(_resMan); + scr->load(scriptNum, _resMan); scr->initializeLocals(this); scr->initializeClasses(this); scr->initializeObjects(this, segmentId); @@ -1003,7 +999,7 @@ void SegManager::uninstantiateScript(int script_nr) { // Free all classtable references to this script for (uint i = 0; i < classTableSize(); i++) - if (getClass(i).reg.segment == segmentId) + if (getClass(i).reg.getSegment() == segmentId) setClassOffset(i, NULL_REG); if (getSciVersion() < SCI_VERSION_1_1) @@ -1027,18 +1023,18 @@ void SegManager::uninstantiateScriptSci0(int script_nr) { // Make a pass over the object in order to uninstantiate all superclasses do { - reg.offset += objLength; // Step over the last checked object + reg.incOffset(objLength); // Step over the last checked object - objType = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.offset)); + objType = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.getOffset())); if (!objType) break; - objLength = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.offset + 2)); + objLength = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.getOffset() + 2)); - reg.offset += 4; // Step over header + reg.incOffset(4); // Step over header if ((objType == SCI_OBJ_OBJECT) || (objType == SCI_OBJ_CLASS)) { // object or class? - reg.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) - int16 superclass = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.offset + 2)); + reg.incOffset(8); // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) + int16 superclass = READ_SCI11ENDIAN_UINT16(scr->getBuf(reg.getOffset() + 2)); if (superclass >= 0) { int superclass_script = getClass(superclass).script; @@ -1052,10 +1048,10 @@ void SegManager::uninstantiateScriptSci0(int script_nr) { // Recurse to assure that the superclass lockers number gets decreased } - reg.offset += SCRIPT_OBJECT_MAGIC_OFFSET; + reg.incOffset(SCRIPT_OBJECT_MAGIC_OFFSET); } // if object or class - reg.offset -= 4; // Step back on header + reg.incOffset(-4); // Step back on header } while (objType != 0); } diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 62e711e686..074d3f6b0a 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -125,7 +125,7 @@ private: public: // TODO: document this - reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller); + reg_t getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment); /** * Return a pointer to the specified script. @@ -471,14 +471,6 @@ private: void createClassTable(); SegmentId findFreeSegment() const; - - /** - * Check segment validity - * @param[in] seg The segment to validate - * @return false if 'seg' is an invalid segment, true if - * 'seg' is a valid segment - */ - bool check(SegmentId seg); }; } // End of namespace Sci diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 36b7d92c07..a7f147a15a 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -93,11 +93,11 @@ Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; // assert(addr.segment == _segId); - if (!isValidEntry(addr.offset)) { + if (!isValidEntry(addr.getOffset())) { error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr)); } - const Clone *clone = &(_table[addr.offset]); + const Clone *clone = &(_table[addr.getOffset()]); // Emit all member variables (including references to the 'super' delegate) for (uint i = 0; i < clone->getVarCount(); i++) @@ -112,7 +112,7 @@ Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const { void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) { #ifdef GC_DEBUG - Object *victim_obj = &(_table[addr.offset]); + Object *victim_obj = &(_table[addr.getOffset()]); if (!(victim_obj->_flags & OBJECT_FLAG_FREED)) warning("[GC] Clone %04x:%04x not reachable and not freed (freeing now)", PRINT_REG(addr)); @@ -124,7 +124,7 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) { #endif #endif - freeEntry(addr.offset); + freeEntry(addr.getOffset()); } @@ -133,15 +133,15 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) { SegmentRef LocalVariables::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = false; // reg_t based data! - ret.maxSize = (_locals.size() - pointer.offset / 2) * 2; + ret.maxSize = (_locals.size() - pointer.getOffset() / 2) * 2; - if (pointer.offset & 1) { + if (pointer.getOffset() & 1) { ret.maxSize -= 1; ret.skipByte = true; } if (ret.maxSize > 0) { - ret.reg = &_locals[pointer.offset / 2]; + ret.reg = &_locals[pointer.getOffset() / 2]; } else { if ((g_sci->getEngineState()->currentRoomNumber() == 160 || g_sci->getEngineState()->currentRoomNumber() == 220) @@ -181,14 +181,14 @@ Common::Array<reg_t> LocalVariables::listAllOutgoingReferences(reg_t addr) const SegmentRef DataStack::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = false; // reg_t based data! - ret.maxSize = (_capacity - pointer.offset / 2) * 2; + ret.maxSize = (_capacity - pointer.getOffset() / 2) * 2; - if (pointer.offset & 1) { + if (pointer.getOffset() & 1) { ret.maxSize -= 1; ret.skipByte = true; } - ret.reg = &_entries[pointer.offset / 2]; + ret.reg = &_entries[pointer.getOffset() / 2]; return ret; } @@ -204,11 +204,11 @@ Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const { Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; - if (!isValidEntry(addr.offset)) { + if (!isValidEntry(addr.getOffset())) { error("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); } - const List *list = &(_table[addr.offset]); + const List *list = &(_table[addr.getOffset()]); tmp.push_back(list->first); tmp.push_back(list->last); @@ -222,10 +222,10 @@ Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; - if (!isValidEntry(addr.offset)) { + if (!isValidEntry(addr.getOffset())) { error("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); } - const Node *node = &(_table[addr.offset]); + const Node *node = &(_table[addr.getOffset()]); // We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us // to walk around from any given node @@ -242,8 +242,8 @@ Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const { SegmentRef DynMem::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = true; - ret.maxSize = _size - pointer.offset; - ret.raw = _buf + pointer.offset; + ret.maxSize = _size - pointer.getOffset(); + ret.raw = _buf + pointer.getOffset(); return ret; } @@ -252,27 +252,27 @@ SegmentRef DynMem::dereference(reg_t pointer) { SegmentRef ArrayTable::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = false; - ret.maxSize = _table[pointer.offset].getSize() * 2; - ret.reg = _table[pointer.offset].getRawData(); + ret.maxSize = _table[pointer.getOffset()].getSize() * 2; + ret.reg = _table[pointer.getOffset()].getRawData(); return ret; } void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) { - _table[sub_addr.offset].destroy(); - freeEntry(sub_addr.offset); + _table[sub_addr.getOffset()].destroy(); + freeEntry(sub_addr.getOffset()); } Common::Array<reg_t> ArrayTable::listAllOutgoingReferences(reg_t addr) const { Common::Array<reg_t> tmp; - if (!isValidEntry(addr.offset)) { + if (!isValidEntry(addr.getOffset())) { error("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); } - const SciArray<reg_t> *array = &(_table[addr.offset]); + const SciArray<reg_t> *array = &(_table[addr.getOffset()]); for (uint32 i = 0; i < array->getSize(); i++) { reg_t value = array->getValue(i); - if (value.segment != 0) + if (value.getSegment() != 0) tmp.push_back(value); } @@ -305,8 +305,8 @@ void SciString::fromString(const Common::String &string) { SegmentRef StringTable::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = true; - ret.maxSize = _table[pointer.offset].getSize(); - ret.raw = (byte *)_table[pointer.offset].getRawData(); + ret.maxSize = _table[pointer.getOffset()].getSize(); + ret.raw = (byte *)_table[pointer.getOffset()].getRawData(); return ret; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 54cf7b98af..0d54b651e1 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -175,7 +175,7 @@ public: } virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const { - return make_reg(addr.segment, 0); + return make_reg(addr.getSegment(), 0); } virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const; @@ -291,7 +291,7 @@ struct NodeTable : public SegmentObjTable<Node> { NodeTable() : SegmentObjTable<Node>(SEG_TYPE_NODES) {} virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) { - freeEntry(sub_addr.offset); + freeEntry(sub_addr.getOffset()); } virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const; @@ -304,7 +304,7 @@ struct ListTable : public SegmentObjTable<List> { ListTable() : SegmentObjTable<List>(SEG_TYPE_LISTS) {} virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) { - freeEntry(sub_addr.offset); + freeEntry(sub_addr.getOffset()); } virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const; @@ -333,7 +333,7 @@ struct HunkTable : public SegmentObjTable<Hunk> { } virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) { - freeEntry(sub_addr.offset); + freeEntry(sub_addr.getOffset()); } virtual void saveLoadWithSerializer(Common::Serializer &ser); @@ -358,7 +358,7 @@ public: } virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const { - return make_reg(addr.segment, 0); + return make_reg(addr.getSegment(), 0); } virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const { const reg_t r = make_reg(segId, 0); @@ -502,8 +502,8 @@ struct StringTable : public SegmentObjTable<SciString> { StringTable() : SegmentObjTable<SciString>(SEG_TYPE_STRING) {} virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) { - _table[sub_addr.offset].destroy(); - freeEntry(sub_addr.offset); + _table[sub_addr.getOffset()].destroy(); + freeEntry(sub_addr.getOffset()); } void saveLoadWithSerializer(Common::Serializer &ser); diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index a8b1cf7ec2..2f6b4d58dd 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -181,6 +181,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(skip); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); + FIND_SELECTOR(visible); FIND_SELECTOR(useInsetRect); FIND_SELECTOR(inTop); FIND_SELECTOR(inLeft); diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index 4b913a866a..5d3d0752ac 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -149,6 +149,7 @@ struct SelectorCache { Selector fixPriority; Selector mirrored; + Selector visible; Selector useInsetRect; Selector inTop, inLeft, inBottom, inRight; @@ -170,7 +171,7 @@ struct SelectorCache { * SelectorCache and mapped in script.cpp. */ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId); -#define readSelectorValue(segMan, _obj_, _slc_) (readSelector(segMan, _obj_, _slc_).offset) +#define readSelectorValue(segMan, _obj_, _slc_) (readSelector(segMan, _obj_, _slc_).getOffset()) /** * Writes a selector value to an object. diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 28818cddef..0f0c8dcd66 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -26,6 +26,7 @@ #include "sci/debug.h" // for g_debug_sleeptime_factor #include "sci/event.h" +#include "sci/engine/file.h" #include "sci/engine/kernel.h" #include "sci/engine/state.h" #include "sci/engine/selector.h" @@ -68,21 +69,26 @@ static const uint16 s_halfWidthSJISMap[256] = { }; EngineState::EngineState(SegManager *segMan) -: _segMan(segMan), _dirseeker() { +: _segMan(segMan), +#ifdef ENABLE_SCI32 + _virtualIndexFile(0), +#endif + _dirseeker() { reset(false); } EngineState::~EngineState() { delete _msgState; +#ifdef ENABLE_SCI32 + delete _virtualIndexFile; +#endif } void EngineState::reset(bool isRestoring) { if (!isRestoring) { _memorySegmentSize = 0; - _fileHandles.resize(5); - abortScriptProcessing = kAbortNone; } @@ -116,6 +122,11 @@ void EngineState::reset(bool isRestoring) { _videoState.reset(); _syncedAudioOptions = false; + + _vmdPalStart = 0; + _vmdPalEnd = 256; + + _palCycleToColor = 255; } void EngineState::speedThrottler(uint32 neededSleep) { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index dcffe6dbb3..81090876c7 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -34,6 +34,7 @@ class WriteStream; } #include "sci/sci.h" +#include "sci/engine/file.h" #include "sci/engine/seg_manager.h" #include "sci/parser/vocabulary.h" @@ -42,9 +43,12 @@ class WriteStream; namespace Sci { +class FileHandle; +class DirSeeker; class EventManager; class MessageState; class SoundCommandParser; +class VirtualIndexFile; enum AbortGameState { kAbortNone = 0, @@ -53,32 +57,6 @@ enum AbortGameState { kAbortQuitGame = 3 }; -class DirSeeker { -protected: - reg_t _outbuffer; - Common::StringArray _files; - Common::StringArray _virtualFiles; - Common::StringArray::const_iterator _iter; - -public: - DirSeeker() { - _outbuffer = NULL_REG; - _iter = _files.begin(); - } - - reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan); - reg_t nextFile(SegManager *segMan); - - Common::String getVirtualFilename(uint fileNumber); - -private: - void addAsVirtualFiles(Common::String title, Common::String fileMask); -}; - -enum { - MAX_SAVEGAME_NR = 20 /**< Maximum number of savegames */ -}; - // We assume that scripts give us savegameId 0->99 for creating a new save slot // and savegameId 100->199 for existing save slots ffs. kfile.cpp enum { @@ -92,20 +70,6 @@ enum { GAMEISRESTARTING_RESTORE = 2 }; -class FileHandle { -public: - Common::String _name; - Common::SeekableReadStream *_in; - Common::WriteStream *_out; - -public: - FileHandle(); - ~FileHandle(); - - void close(); - bool isOpen() const; -}; - enum VideoFlags { kNone = 0, kDoubled = 1 << 0, @@ -163,6 +127,10 @@ public: int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween int16 _lastSaveNewId; // last newly created filename-id by kSaveGame +#ifdef ENABLE_SCI32 + VirtualIndexFile *_virtualIndexFile; +#endif + uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms bool _cursorWorkaroundActive; // ffs. GfxCursor::setPosition() @@ -228,8 +196,11 @@ public: byte _memorySegment[kMemorySegmentMax]; VideoState _videoState; + uint16 _vmdPalStart, _vmdPalEnd; bool _syncedAudioOptions; + uint16 _palCycleToColor; + /** * Resets the engine state. */ diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 162dce9fcc..3f43966976 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -119,7 +119,7 @@ extern const char *opcodeNames[]; // from scriptdebug.cpp static reg_t read_var(EngineState *s, int type, int index) { if (validate_variable(s->variables[type], s->stack_base, type, s->variablesMax[type], index)) { - if (s->variables[type][index].segment == 0xffff) { + if (s->variables[type][index].getSegment() == 0xffff) { switch (type) { case VAR_TEMP: { // Uninitialized read on a temp @@ -195,8 +195,8 @@ static void write_var(EngineState *s, int type, int index, reg_t value) { // this happens at least in sq1/room 44 (slot-machine), because a send is missing parameters, then // those parameters are taken from uninitialized stack and afterwards they are copied back into temps // if we don't remove the segment, we would get false-positive uninitialized reads later - if (type == VAR_TEMP && value.segment == 0xffff) - value.segment = 0; + if (type == VAR_TEMP && value.getSegment() == 0xffff) + value.setSegment(0); s->variables[type][index] = value; @@ -225,30 +225,15 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP scr = s->_segMan->getScript(seg); } - int temp = scr->validateExportFunc(pubfunct, false); - - if (getSciVersion() == SCI_VERSION_3) - temp += scr->getCodeBlockOffset(); - - if (!temp) { -#ifdef ENABLE_SCI32 - if (g_sci->getGameId() == GID_TORIN && script == 64036) { - // Script 64036 in Torin's Passage is empty and contains an invalid - // (empty) export - } else if (g_sci->getGameId() == GID_RAMA && script == 64908) { - // Script 64908 in the demo of RAMA contains an invalid (empty) - // export - } else -#endif - error("Request for invalid exported function 0x%x of script %d", pubfunct, script); + uint32 exportAddr = scr->validateExportFunc(pubfunct, false); + if (!exportAddr) return NULL; - } - + // Check if a breakpoint is set on this method g_sci->checkExportBreakpoint(script, pubfunct); ExecStack xstack(calling_obj, calling_obj, sp, argc, argp, - seg, make_reg(seg, temp), -1, pubfunct, -1, + seg, make_reg32(seg, exportAddr), -1, pubfunct, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); s->_executionStack.push_back(xstack); return &(s->_executionStack.back()); @@ -304,11 +289,12 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt ExecStackType stackType = EXEC_STACK_TYPE_VARSELECTOR; StackPtr curSP = NULL; - reg_t curFP = NULL_REG; + reg32_t curFP = make_reg32(0, 0); if (selectorType == kSelectorMethod) { stackType = EXEC_STACK_TYPE_CALL; curSP = sp; - curFP = funcp; + // TODO: Will this offset suffice for large SCI3 scripts? + curFP = make_reg32(funcp.getSegment(), funcp.getOffset()); sp = CALL_SP_CARRY; // Destroy sp, as it will be carried over } @@ -342,7 +328,7 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc, // Add stack frame to indicate we're executing a callk. // This is useful in debugger backtraces if this // kernel function calls a script itself. - ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, NULL_REG, + ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, make_reg32(0, 0), kernelCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL); s->_executionStack.push_back(xstack); } @@ -578,16 +564,16 @@ void run_vm(EngineState *s) { int var_type; // See description below int var_number; - g_sci->_debugState.old_pc_offset = s->xs->addr.pc.offset; + g_sci->_debugState.old_pc_offset = s->xs->addr.pc.getOffset(); g_sci->_debugState.old_sp = s->xs->sp; if (s->abortScriptProcessing != kAbortNone) return; // Stop processing if (s->_executionStackPosChanged) { - scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.segment); + scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.getSegment()); if (!scr) - error("No script in segment %d", s->xs->addr.pc.segment); + error("No script in segment %d", s->xs->addr.pc.getSegment()); s->xs = &(s->_executionStack.back()); s->_executionStackPosChanged = false; @@ -624,13 +610,13 @@ void run_vm(EngineState *s) { s->variablesMax[VAR_TEMP] = s->xs->sp - s->xs->fp; - if (s->xs->addr.pc.offset >= scr->getBufSize()) + if (s->xs->addr.pc.getOffset() >= scr->getBufSize()) error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d", - s->xs->addr.pc.offset, scr->getBufSize()); + s->xs->addr.pc.getOffset(), scr->getBufSize()); // Get opcode byte extOpcode; - s->xs->addr.pc.offset += readPMachineInstruction(scr->getBuf() + s->xs->addr.pc.offset, extOpcode, opparams); + s->xs->addr.pc.incOffset(readPMachineInstruction(scr->getBuf(s->xs->addr.pc.getOffset()), extOpcode, opparams)); const byte opcode = extOpcode >> 1; //debug("%s: %d, %d, %d, %d, acc = %04x:%04x, script %d, local script %d", opcodeNames[opcode], opparams[0], opparams[1], opparams[2], opparams[3], PRINT_REG(s->r_acc), scr->getScriptNumber(), local_script->getScriptNumber()); @@ -705,7 +691,7 @@ void run_vm(EngineState *s) { break; case op_not: // 0x0c (12) - s->r_acc = make_reg(0, !(s->r_acc.offset || s->r_acc.segment)); + s->r_acc = make_reg(0, !(s->r_acc.getOffset() || s->r_acc.getSegment())); // Must allow pointers to be negated, as this is used for checking whether objects exist break; @@ -765,30 +751,30 @@ void run_vm(EngineState *s) { case op_bt: // 0x17 (23) // Branch relative if true - if (s->r_acc.offset || s->r_acc.segment) - s->xs->addr.pc.offset += opparams[0]; + if (s->r_acc.getOffset() || s->r_acc.getSegment()) + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_bt: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_bnt: // 0x18 (24) // Branch relative if not true - if (!(s->r_acc.offset || s->r_acc.segment)) - s->xs->addr.pc.offset += opparams[0]; + if (!(s->r_acc.getOffset() || s->r_acc.getSegment())) + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_bnt: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_jmp: // 0x19 (25) - s->xs->addr.pc.offset += opparams[0]; + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_jmp: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_ldi: // 0x1a (26) @@ -831,13 +817,13 @@ void run_vm(EngineState *s) { int argc = (opparams[1] >> 1) // Given as offset, but we need count + 1 + s->r_rest; StackPtr call_base = s->xs->sp - argc; - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); - uint16 localCallOffset = s->xs->addr.pc.offset + opparams[0]; + uint32 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0]; ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp, (call_base->requireUint16()) + s->r_rest, call_base, - s->xs->local_segment, make_reg(s->xs->addr.pc.segment, localCallOffset), + s->xs->local_segment, make_reg32(s->xs->addr.pc.getSegment(), localCallOffset), NULL_SELECTOR, -1, localCallOffset, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); @@ -894,9 +880,9 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= temp; - s->xs->sp[0].offset += s->r_rest; + s->xs->sp[0].incOffset(s->r_rest); xs_new = execute_method(s, 0, opparams[0], s_temp, s->xs->objp, - s->xs->sp[0].offset, s->xs->sp); + s->xs->sp[0].getOffset(), s->xs->sp); s->r_rest = 0; // Used up the &rest adjustment if (xs_new) // in case of error, keep old stack s->_executionStackPosChanged = true; @@ -908,11 +894,10 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= temp; - s->xs->sp[0].offset += s->r_rest; + s->xs->sp[0].incOffset(s->r_rest); xs_new = execute_method(s, opparams[0], opparams[1], s_temp, s->xs->objp, - s->xs->sp[0].offset, s->xs->sp); + s->xs->sp[0].getOffset(), s->xs->sp); s->r_rest = 0; // Used up the &rest adjustment - if (xs_new) // in case of error, keep old stack s->_executionStackPosChanged = true; break; @@ -965,7 +950,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, s->r_acc, s->r_acc, s_temp, (int)(opparams[0] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -996,7 +981,7 @@ void run_vm(EngineState *s) { case op_class: // 0x28 (40) // Get class address s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK, - s->xs->addr.pc); + s->xs->addr.pc.getSegment()); break; case 0x29: // (41) @@ -1008,7 +993,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, s->xs->objp, s->xs->objp, s_temp, (int)(opparams[0] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -1021,7 +1006,7 @@ void run_vm(EngineState *s) { case op_super: // 0x2b (43) // Send to any class - r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc); + r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc.getSegment()); if (!r_temp.isPointer()) error("[VM]: Invalid superclass in object"); @@ -1029,7 +1014,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[1] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, r_temp, s->xs->objp, s_temp, (int)(opparams[1] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -1058,14 +1043,14 @@ void run_vm(EngineState *s) { var_number = temp & 0x03; // Get variable type // Get variable block offset - r_temp.segment = s->variablesSegment[var_number]; - r_temp.offset = s->variables[var_number] - s->variablesBase[var_number]; + r_temp.setSegment(s->variablesSegment[var_number]); + r_temp.setOffset(s->variables[var_number] - s->variablesBase[var_number]); if (temp & 0x08) // Add accumulator offset if requested - r_temp.offset += s->r_acc.requireSint16(); + r_temp.incOffset(s->r_acc.requireSint16()); - r_temp.offset += opparams[1]; // Add index - r_temp.offset *= 2; // variables are 16 bit + r_temp.incOffset(opparams[1]); // Add index + r_temp.setOffset(r_temp.getOffset() * 2); // variables are 16 bit // That's the immediate address now s->r_acc = r_temp; break; @@ -1129,28 +1114,28 @@ void run_vm(EngineState *s) { case op_lofsa: // 0x39 (57) case op_lofss: // 0x3a (58) // Load offset to accumulator or push to stack - r_temp.segment = s->xs->addr.pc.segment; + r_temp.setSegment(s->xs->addr.pc.getSegment()); switch (g_sci->_features->detectLofsType()) { case SCI_VERSION_0_EARLY: - r_temp.offset = s->xs->addr.pc.offset + opparams[0]; + r_temp.setOffset((uint16)s->xs->addr.pc.getOffset() + opparams[0]); break; case SCI_VERSION_1_MIDDLE: - r_temp.offset = opparams[0]; + r_temp.setOffset(opparams[0]); break; case SCI_VERSION_1_1: - r_temp.offset = opparams[0] + local_script->getScriptSize(); + r_temp.setOffset(opparams[0] + local_script->getScriptSize()); break; case SCI_VERSION_3: // In theory this can break if the variant with a one-byte argument is // used. For now, assume it doesn't happen. - r_temp.offset = local_script->relocateOffsetSci3(s->xs->addr.pc.offset-2); + r_temp.setOffset(local_script->relocateOffsetSci3(s->xs->addr.pc.getOffset() - 2)); break; default: error("Unknown lofs type"); } - if (r_temp.offset >= scr->getBufSize()) + if (r_temp.getOffset() >= scr->getBufSize()) error("VM: lofsa/lofss operation overflowed: %04x:%04x beyond end" " of script (at %04x)", PRINT_REG(r_temp), scr->getBufSize()); @@ -1188,6 +1173,7 @@ void run_vm(EngineState *s) { case op_line: // 0x3f (63) // Debug opcode (line number) + //debug("Script %d, line %d", scr->getScriptNumber(), opparams[0]); break; case op_lag: // 0x40 (64) diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 334d224baf..8b38faa013 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -61,8 +61,6 @@ struct Class { reg_t reg; ///< offset; script-relative offset, segment: 0 if not instantiated }; -#define RAW_IS_OBJECT(datablock) (READ_SCI11ENDIAN_UINT16(((const byte *) datablock) + SCRIPT_OBJECT_MAGIC_OFFSET) == SCRIPT_OBJECT_MAGIC_NUMBER) - // A reference to an object's variable. // The object is stored as a reg_t, the variable as an index into _variables struct ObjVarRef { @@ -84,7 +82,7 @@ struct ExecStack { union { ObjVarRef varp; // Variable pointer for r/w access - reg_t pc; // Pointer to the initial program counter. Not accurate for the TOS element + reg32_t pc; // Pointer to the initial program counter. Not accurate for the TOS element } addr; StackPtr fp; // Frame pointer @@ -104,7 +102,7 @@ struct ExecStack { reg_t* getVarPointer(SegManager *segMan) const; ExecStack(reg_t objp_, reg_t sendp_, StackPtr sp_, int argc_, StackPtr argp_, - SegmentId localsSegment_, reg_t pc_, Selector debugSelector_, + SegmentId localsSegment_, reg32_t pc_, Selector debugSelector_, int debugExportId_, int debugLocalCallOffset_, int debugOrigin_, ExecStackType type_) { objp = objp_; @@ -118,7 +116,7 @@ struct ExecStack { if (localsSegment_ != 0xFFFF) local_segment = localsSegment_; else - local_segment = pc_.segment; + local_segment = pc_.getSegment(); debugSelector = debugSelector_; debugExportId = debugExportId_; debugLocalCallOffset = debugLocalCallOffset_; @@ -139,7 +137,7 @@ enum { GC_INTERVAL = 0x8000 }; -enum sci_opcodes { +enum SciOpcodes { op_bnot = 0x00, // 000 op_add = 0x01, // 001 op_sub = 0x02, // 002 @@ -204,6 +202,7 @@ enum sci_opcodes { op_push2 = 0x3d, // 061 op_pushSelf = 0x3e, // 062 op_line = 0x3f, // 063 + // op_lag = 0x40, // 064 op_lal = 0x41, // 065 op_lat = 0x42, // 066 @@ -220,6 +219,7 @@ enum sci_opcodes { op_lsli = 0x4d, // 077 op_lsti = 0x4e, // 078 op_lspi = 0x4f, // 079 + // op_sag = 0x50, // 080 op_sal = 0x51, // 081 op_sat = 0x52, // 082 @@ -236,6 +236,7 @@ enum sci_opcodes { op_ssli = 0x5d, // 093 op_ssti = 0x5e, // 094 op_sspi = 0x5f, // 095 + // op_plusag = 0x60, // 096 op_plusal = 0x61, // 097 op_plusat = 0x62, // 098 @@ -252,6 +253,7 @@ enum sci_opcodes { op_plussli = 0x6d, // 109 op_plussti = 0x6e, // 110 op_plusspi = 0x6f, // 111 + // op_minusag = 0x70, // 112 op_minusal = 0x71, // 113 op_minusat = 0x72, // 114 diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index b95fd58129..27015d9be4 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -43,17 +43,17 @@ reg_t reg_t::lookForWorkaround(const reg_t right) const { reg_t reg_t::operator+(const reg_t right) const { if (isPointer() && right.isNumber()) { // Pointer arithmetics. Only some pointer types make sense here - SegmentObj *mobj = g_sci->getEngineState()->_segMan->getSegmentObj(segment); + SegmentObj *mobj = g_sci->getEngineState()->_segMan->getSegmentObj(getSegment()); if (!mobj) - error("[VM]: Attempt to add %d to invalid pointer %04x:%04x", right.offset, PRINT_REG(*this)); + error("[VM]: Attempt to add %d to invalid pointer %04x:%04x", right.getOffset(), PRINT_REG(*this)); switch (mobj->getType()) { case SEG_TYPE_LOCALS: case SEG_TYPE_SCRIPT: case SEG_TYPE_STACK: case SEG_TYPE_DYNMEM: - return make_reg(segment, offset + right.toSint16()); + return make_reg(getSegment(), getOffset() + right.toSint16()); default: return lookForWorkaround(right); } @@ -69,12 +69,12 @@ reg_t reg_t::operator+(const reg_t right) const { } reg_t reg_t::operator-(const reg_t right) const { - if (segment == right.segment) { + if (getSegment() == right.getSegment()) { // We can subtract numbers, or pointers with the same segment, // an operation which will yield a number like in C return make_reg(0, toSint16() - right.toSint16()); } else { - return *this + make_reg(right.segment, -right.offset); + return *this + make_reg(right.getSegment(), -right.toSint16()); } } @@ -174,7 +174,7 @@ reg_t reg_t::operator^(const reg_t right) const { } int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { - if (segment == right.segment) { // can compare things in the same segment + if (getSegment() == right.getSegment()) { // can compare things in the same segment if (treatAsUnsigned || !isNumber()) return toUint16() - right.toUint16(); else @@ -218,7 +218,7 @@ bool reg_t::pointerComparisonWithInteger(const reg_t right) const { // SQ1, room 28, when throwing water at the Orat // SQ1, room 58, when giving the ID card to the robot // SQ4 CD, at the first game screen, when the narrator is about to speak - return (isPointer() && right.isNumber() && right.offset <= 2000 && getSciVersion() <= SCI_VERSION_1_1); + return (isPointer() && right.isNumber() && right.getOffset() <= 2000 && getSciVersion() <= SCI_VERSION_1_1); } } // End of namespace Sci diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index 7b155a4532..9a7589e9a7 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -31,43 +31,64 @@ namespace Sci { typedef uint16 SegmentId; struct reg_t { - SegmentId segment; - uint16 offset; + // Segment and offset. These should never be accessed directly + SegmentId _segment; + uint16 _offset; + + inline SegmentId getSegment() const { + return _segment; + } + + inline void setSegment(SegmentId segment) { + _segment = segment; + } + + inline uint16 getOffset() const { + return _offset; + } + + inline void setOffset(uint16 offset) { + _offset = offset; + } + + inline void incOffset(int16 offset) { + setOffset(getOffset() + offset); + } inline bool isNull() const { - return (offset | segment) == 0; + return (_offset | getSegment()) == 0; } inline uint16 toUint16() const { - return offset; + return _offset; } inline int16 toSint16() const { - return (int16)offset; + return (int16)_offset; } bool isNumber() const { - return segment == 0; + return getSegment() == 0; } bool isPointer() const { - return segment != 0 && segment != 0xFFFF; + return getSegment() != 0 && getSegment() != 0xFFFF; } uint16 requireUint16() const; int16 requireSint16() const; inline bool isInitialized() const { - return segment != 0xFFFF; + return getSegment() != 0xFFFF; } // Comparison operators bool operator==(const reg_t &x) const { - return (offset == x.offset) && (segment == x.segment); + return (getOffset() == x.getOffset()) && (getSegment() == x.getSegment()); } bool operator!=(const reg_t &x) const { - return (offset != x.offset) || (segment != x.segment); + return (getOffset() != x.getOffset()) || (getSegment() != x.getSegment()); } bool operator>(const reg_t right) const { @@ -141,12 +162,55 @@ private: static inline reg_t make_reg(SegmentId segment, uint16 offset) { reg_t r; - r.offset = offset; - r.segment = segment; + r.setSegment(segment); + r.setOffset(offset); return r; } -#define PRINT_REG(r) (0xffff) & (unsigned) (r).segment, (unsigned) (r).offset +#define PRINT_REG(r) (0xffff) & (unsigned) (r).getSegment(), (unsigned) (r).getOffset() + +// A true 32-bit reg_t +struct reg32_t { + // Segment and offset. These should never be accessed directly + SegmentId _segment; + uint32 _offset; + + inline SegmentId getSegment() const { + return _segment; + } + + inline void setSegment(SegmentId segment) { + _segment = segment; + } + + inline uint32 getOffset() const { + return _offset; + } + + inline void setOffset(uint32 offset) { + _offset = offset; + } + + inline void incOffset(int32 offset) { + setOffset(getOffset() + offset); + } + + // Comparison operators + bool operator==(const reg32_t &x) const { + return (getOffset() == x.getOffset()) && (getSegment() == x.getSegment()); + } + + bool operator!=(const reg32_t &x) const { + return (getOffset() != x.getOffset()) || (getSegment() != x.getSegment()); + } +}; + +static inline reg32_t make_reg32(SegmentId segment, uint32 offset) { + reg32_t r; + r.setSegment(segment); + r.setOffset(offset); + return r; +} // Stack pointer type typedef reg_t *StackPtr; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 4a0aea81ff..9fa0368784 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -36,13 +36,15 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = { { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // op_or: when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464 { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xce0, 0, { WORKAROUND_FAKE, 0 } }, // Same as above, for the Spanish version - bug #3313962 { GID_FANMADE, 516, 983, 0, "Wander", "setTarget", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_mul: The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913 + { GID_GK1, 800,64992, 0, "Fwd", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7 { GID_ICEMAN, 199, 977, 0, "Grooper", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_add: While dancing with the girl { GID_MOTHERGOOSE256, -1, 999, 0, "Event", "new", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_and: constantly during the game (SCI1 version) { GID_MOTHERGOOSE256, -1, 4, 0, "rm004", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_or: when going north and reaching the castle (rooms 4 and 37) - bug #3038228 { GID_MOTHERGOOSEHIRES,90, 90, 0, "newGameButton", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue. + { GID_PHANTASMAGORIA, 902, 0, 0, "", "export 7", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_shr: when starting a chapter in Phantasmagoria { GID_QFG1VGA, 301, 928, 0, "Blink", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_div: when entering the inn, gets called with 1 parameter, but 2nd parameter is used for div which happens to be an object { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer bug #3039879 - { GID_GK1, 800,64992, 0, "Fwd", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7 + { GID_QFG4, 710,64941, 0, "RandCycle", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when the tentacle appears in the third room of the caves SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -162,11 +164,12 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_SQ1, -1, 703, 0, "", "export 1", -1, 0, { WORKAROUND_FAKE, 0 } }, // sub that's called from several objects while on sarien battle cruiser { GID_SQ1, -1, 703, 0, "firePulsar", "changeState", 0x18a, 0, { WORKAROUND_FAKE, 0 } }, // export 1, but called locally (when shooting at aliens) { GID_SQ4, -1, 398, 0, "showBox", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // CD: called when rummaging in Software Excess bargain bin - { GID_SQ4, -1, 928, 0, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // CD: method returns this to the caller + { GID_SQ4, -1, 928, -1, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // CD: happens in the options dialog and in-game when speech and subtitles are used simultaneously { GID_SQ5, 201, 201, 0, "buttonPanel", "doVerb", -1, 0, { WORKAROUND_FAKE, 1 } }, // when looking at the orange or red button - bug #3038563 { GID_SQ6, -1, 0, 0, "SQ6", "init", -1, 2, { WORKAROUND_FAKE, 0 } }, // Demo and full version: called when the game starts (demo: room 0, full: room 100) - { GID_SQ6, 100, 64950, 0, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu + { GID_SQ6, -1, 64950, -1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu, when entering the Orion's Belt bar (room 300), and perhaps other places { GID_SQ6, -1, 64964, 0, "DPath", "init", -1, 1, { WORKAROUND_FAKE, 0 } }, // during the game + { GID_TORIN, -1, 64017, 0, "oFlags", "clear", -1, 0, { WORKAROUND_FAKE, 0 } }, // entering Torin's home in the French version SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -176,6 +179,7 @@ const SciWorkaroundEntry kAbs_workarounds[] = { { GID_HOYLE1, 2, 2, 0, "room2", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // old maid - called with objects instead of integers { GID_HOYLE1, 3, 3, 0, "room3", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // hearts - called with objects instead of integers { GID_QFG1VGA, -1, -1, 0, NULL, "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // when the game is patched with the NRS patch + { GID_QFG3 , -1, -1, 0, NULL, "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // when the game is patched with the NRS patch (bugs #3528416, #3528542) SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -321,8 +325,9 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = { { GID_ECOQUEST2, 100, 333, 0, "showEcorder", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // necessary workaround for our ecorder script patch, because there isn't enough space to patch the function - { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 { GID_PQ3, 202, 202, 0, "MapEdit", "addPt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 + { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 + { GID_PQ3, 202, 202, 0, "MapEdit", "dispose", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -394,6 +399,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { { GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident { GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident { GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error + { GID_QFG4, -1, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index 378e88b7df..14443db1e2 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -102,8 +102,8 @@ const MouseEventConversion mouseEventMappings[] = { { Common::EVENT_RBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 2 }, { Common::EVENT_MBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 3 }, { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 1 }, - { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 2 }, - { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 3 } + { Common::EVENT_RBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 2 }, + { Common::EVENT_MBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 3 } }; EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended) { diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 983e697481..ee28c5ca31 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -723,7 +723,7 @@ void GfxAnimate::printAnimateList(Console *con) { const AnimateList::iterator end = _list.end(); for (it = _list.begin(); it != end; ++it) { - Script *scr = _s->_segMan->getScriptIfLoaded(it->object.segment); + Script *scr = _s->_segMan->getScriptIfLoaded(it->object.getSegment()); int16 scriptNo = scr ? scr->getScriptNumber() : -1; con->DebugPrintf("%04x:%04x (%s), script %d, view %d (%d, %d), pal %d, " diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 71f4598afc..ce77cf6ed3 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -148,11 +148,13 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { colorMapping[1] = _screen->getColorWhite(); // White is also hardcoded colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; colorMapping[3] = _palette->matchColor(170, 170, 170); // Grey - // Special case for the magnifier cursor in LB1 (bug #3487092). - // No other SCI0 game has a cursor resource of 1, so this is handled - // specifically for LB1. + // TODO: Figure out if the grey color is hardcoded + // HACK for the magnifier cursor in LB1, fixes its color (bug #3487092) if (g_sci->getGameId() == GID_LAURABOW && resourceId == 1) colorMapping[3] = _screen->getColorWhite(); + // HACK for Longbow cursors, fixes the shade of grey they're using (bug #3489101) + if (g_sci->getGameId() == GID_LONGBOW) + colorMapping[3] = _palette->matchColor(223, 223, 223); // Light Grey // Seek to actual data resourceData += 4; @@ -409,7 +411,7 @@ void GfxCursor::refreshPosition() { } } - CursorMan.replaceCursor((const byte *)_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey); + CursorMan.replaceCursor(_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey); } } diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp index fcdd057509..30184cc091 100644 --- a/engines/sci/graphics/font.cpp +++ b/engines/sci/graphics/font.cpp @@ -54,7 +54,7 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr } GfxFontFromResource::~GfxFontFromResource() { - delete []_chars; + delete[] _chars; _resMan->unlockResource(_resource); } diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index b12413ab69..968014c032 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -28,9 +28,11 @@ #include "common/system.h" #include "common/textconsole.h" #include "engines/engine.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "sci/sci.h" +#include "sci/console.h" #include "sci/engine/kernel.h" #include "sci/engine/state.h" #include "sci/engine/selector.h" @@ -52,12 +54,18 @@ namespace Sci { // TODO/FIXME: This is all guesswork +enum SciSpeciaPlanelPictureCodes { + kPlaneTranslucent = 0xfffe, // -2 + kPlanePlainColored = 0xffff // -1 +}; + GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32) : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) { _coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; - _scriptsRunningWidth = 320; - _scriptsRunningHeight = 200; + _curScrollText = -1; + _showScrollText = false; + _maxScrollTexts = 0; } GfxFrameout::~GfxFrameout() { @@ -68,32 +76,88 @@ void GfxFrameout::clear() { deletePlaneItems(NULL_REG); _planes.clear(); deletePlanePictures(NULL_REG); + clearScrollTexts(); +} + +void GfxFrameout::clearScrollTexts() { + _scrollTexts.clear(); + _curScrollText = -1; +} + +void GfxFrameout::addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace) { + //reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow); + // HACK: We set the container dimensions manually + reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow, 480, 70); + ScrollTextEntry textEntry; + textEntry.bitmapHandle = bitmapHandle; + textEntry.kWindow = kWindow; + textEntry.x = x; + textEntry.y = y; + if (!replace || _scrollTexts.size() == 0) { + if (_scrollTexts.size() > _maxScrollTexts) { + _scrollTexts.remove_at(0); + _curScrollText--; + } + _scrollTexts.push_back(textEntry); + _curScrollText++; + } else { + _scrollTexts.pop_back(); + _scrollTexts.push_back(textEntry); + } +} + +void GfxFrameout::showCurrentScrollText() { + if (!_showScrollText || _curScrollText < 0) + return; + + uint16 size = (uint16)_scrollTexts.size(); + if (size > 0) { + assert(_curScrollText < size); + ScrollTextEntry textEntry = _scrollTexts[_curScrollText]; + g_sci->_gfxText32->drawScrollTextBitmap(textEntry.kWindow, textEntry.bitmapHandle, textEntry.x, textEntry.y); + } } +extern void showScummVMDialog(const Common::String &message); + void GfxFrameout::kernelAddPlane(reg_t object) { PlaneEntry newPlane; if (_planes.empty()) { // There has to be another way for sierra sci to do this or maybe script resolution is compiled into // interpreter (TODO) - uint16 tmpRunningWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); - uint16 tmpRunningHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); + uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); + uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); - // The above can be 0 in SCI3 (e.g. Phantasmagoria 2) - if (tmpRunningWidth > 0 && tmpRunningHeight > 0) { - _scriptsRunningWidth = tmpRunningWidth; - _scriptsRunningHeight = tmpRunningHeight; + // Phantasmagoria 2 doesn't specify a script width/height + if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { + scriptWidth = 640; + scriptHeight = 480; } - _coordAdjuster->setScriptsResolution(_scriptsRunningWidth, _scriptsRunningHeight); + assert(scriptWidth > 0 && scriptHeight > 0); + _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight); + } + + // Import of QfG character files dialog is shown in QFG4. + // Display additional popup information before letting user use it. + // For the SCI0-SCI1.1 version of this, check kDrawControl(). + if (g_sci->inQfGImportRoom() && !strcmp(_segMan->getObjectName(object), "DSPlane")) { + showScummVMDialog("Characters saved inside ScummVM are shown " + "automatically. Character files saved in the original " + "interpreter need to be put inside ScummVM's saved games " + "directory and a prefix needs to be added depending on which " + "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' " + "for Quest for Glory 2, 'qfg3-' for Quest for Glory 3. " + "Example: 'qfg2-thief.sav'."); } newPlane.object = object; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - newPlane.lastPriority = 0xFFFF; // hidden + newPlane.lastPriority = -1; // hidden newPlane.planeOffsetX = 0; newPlane.planeOffsetY = 0; - newPlane.pictureId = 0xFFFF; + newPlane.pictureId = kPlanePlainColored; newPlane.planePictureMirrored = false; newPlane.planeBack = 0; _planes.push_back(newPlane); @@ -111,7 +175,8 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { if (lastPictureId != it->pictureId) { // picture got changed, load new picture deletePlanePictures(object); - if ((it->pictureId != 0xFFFF) && (it->pictureId != 0xFFFE)) { + // Draw the plane's picture if it's not a translucent/plane colored frame + if ((it->pictureId != kPlanePlainColored) && (it->pictureId != kPlaneTranslucent)) { // SQ6 gives us a bad picture number for the control menu if (_resMan->testResource(ResourceId(kResourceTypePic, it->pictureId))) addPlanePicture(object, it->pictureId, 0); @@ -122,11 +187,8 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); - Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - it->planeRect.top = (it->planeRect.top * screenRect.height()) / _scriptsRunningHeight; - it->planeRect.left = (it->planeRect.left * screenRect.width()) / _scriptsRunningWidth; - it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; - it->planeRect.right = (it->planeRect.right * screenRect.width()) / _scriptsRunningWidth; + _coordAdjuster->fromScriptToDisplay(it->planeRect.top, it->planeRect.left); + _coordAdjuster->fromScriptToDisplay(it->planeRect.bottom, it->planeRect.right); // We get negative left in kq7 in scrolling rooms if (it->planeRect.left < 0) { @@ -191,11 +253,9 @@ void GfxFrameout::kernelDeletePlane(reg_t object) { planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); - Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - planeRect.top = (planeRect.top * screenRect.height()) / _scriptsRunningHeight; - planeRect.left = (planeRect.left * screenRect.width()) / _scriptsRunningWidth; - planeRect.bottom = (planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; - planeRect.right = (planeRect.right * screenRect.width()) / _scriptsRunningWidth; + _coordAdjuster->fromScriptToDisplay(planeRect.top, planeRect.left); + _coordAdjuster->fromScriptToDisplay(planeRect.bottom, planeRect.right); + // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; @@ -204,6 +264,9 @@ void GfxFrameout::kernelDeletePlane(reg_t object) { } void GfxFrameout::addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY) { + if (pictureId == kPlanePlainColored || pictureId == kPlaneTranslucent) // sanity check + return; + PlanePictureEntry newPicture; newPicture.object = object; newPicture.pictureId = pictureId; @@ -228,15 +291,76 @@ void GfxFrameout::deletePlanePictures(reg_t object) { } } +// Provides the same functionality as kGraph(DrawLine) +reg_t GfxFrameout::addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { + for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { + if (it->object == object) { + PlaneLineEntry line; + line.hunkId = _segMan->allocateHunkEntry("PlaneLine()", 1); // we basically use this for a unique ID + line.startPoint = startPoint; + line.endPoint = endPoint; + line.color = color; + line.priority = priority; + line.control = control; + it->lines.push_back(line); + return line.hunkId; + } + } + + return NULL_REG; +} + +void GfxFrameout::updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { + // Check if we're asked to update a line that was never added + if (hunkId.isNull()) + return; + + for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { + if (it->object == object) { + for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { + if (it2->hunkId == hunkId) { + it2->startPoint = startPoint; + it2->endPoint = endPoint; + it2->color = color; + it2->priority = priority; + it2->control = control; + return; + } + } + } + } +} + +void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) { + // Check if we're asked to delete a line that was never added (happens during the intro of LSL6) + if (hunkId.isNull()) + return; + + for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { + if (it->object == object) { + for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { + if (it2->hunkId == hunkId) { + _segMan->freeHunkEntry(hunkId); + it2 = it->lines.erase(it2); + return; + } + } + } + } +} + void GfxFrameout::kernelAddScreenItem(reg_t object) { // Ignore invalid items - if (!_segMan->isObject(object)) + if (!_segMan->isObject(object)) { + warning("kernelAddScreenItem: Attempt to add an invalid object (%04x:%04x)", PRINT_REG(object)); return; + } FrameoutEntry *itemEntry = new FrameoutEntry(); memset(itemEntry, 0, sizeof(FrameoutEntry)); itemEntry->object = object; itemEntry->givenOrderNr = _screenItems.size(); + itemEntry->visible = true; _screenItems.push_back(itemEntry); kernelUpdateScreenItem(object); @@ -244,8 +368,10 @@ void GfxFrameout::kernelAddScreenItem(reg_t object) { void GfxFrameout::kernelUpdateScreenItem(reg_t object) { // Ignore invalid items - if (!_segMan->isObject(object)) + if (!_segMan->isObject(object)) { + warning("kernelUpdateScreenItem: Attempt to update an invalid object (%04x:%04x)", PRINT_REG(object)); return; + } FrameoutEntry *itemEntry = findScreenItem(object); if (!itemEntry) { @@ -266,14 +392,18 @@ void GfxFrameout::kernelUpdateScreenItem(reg_t object) { itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal)); itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); + itemEntry->visible = true; + + // Check if the entry can be hidden + if (lookupSelector(_segMan, object, SELECTOR(visible), NULL, NULL) != kSelectorNone) + itemEntry->visible = readSelectorValue(_segMan, object, SELECTOR(visible)); } void GfxFrameout::kernelDeleteScreenItem(reg_t object) { FrameoutEntry *itemEntry = findScreenItem(object); - if (!itemEntry) { - warning("kernelDeleteScreenItem: invalid object %04x:%04x", PRINT_REG(object)); + // If the item could not be found, it may already have been deleted + if (!itemEntry) return; - } _screenItems.remove(itemEntry); delete itemEntry; @@ -330,15 +460,10 @@ bool sortHelper(const FrameoutEntry* entry1, const FrameoutEntry* entry2) { } bool planeSortHelper(const PlaneEntry &entry1, const PlaneEntry &entry2) { -// SegManager *segMan = g_sci->getEngineState()->_segMan; - -// uint16 plane1Priority = readSelectorValue(segMan, entry1, SELECTOR(priority)); -// uint16 plane2Priority = readSelectorValue(segMan, entry2, SELECTOR(priority)); - - if (entry1.priority == 0xffff) + if (entry1.priority < 0) return true; - if (entry2.priority == 0xffff) + if (entry2.priority < 0) return false; return entry1.priority < entry2.priority; @@ -357,23 +482,6 @@ void GfxFrameout::sortPlanes() { Common::sort(_planes.begin(), _planes.end(), planeSortHelper); } -int16 GfxFrameout::upscaleHorizontalCoordinate(int16 coordinate) { - return ((coordinate * _screen->getWidth()) / _scriptsRunningWidth); -} - -int16 GfxFrameout::upscaleVerticalCoordinate(int16 coordinate) { - return ((coordinate * _screen->getHeight()) / _scriptsRunningHeight); -} - -Common::Rect GfxFrameout::upscaleRect(Common::Rect &rect) { - rect.top = (rect.top * _scriptsRunningHeight) / _screen->getHeight(); - rect.left = (rect.left * _scriptsRunningWidth) / _screen->getWidth(); - rect.bottom = (rect.bottom * _scriptsRunningHeight) / _screen->getHeight(); - rect.right = (rect.right * _scriptsRunningWidth) / _screen->getWidth(); - - return rect; -} - void GfxFrameout::showVideo() { bool skipVideo = false; RobotDecoder *videoDecoder = g_sci->_robotDecoder; @@ -381,16 +489,16 @@ void GfxFrameout::showVideo() { uint16 y = videoDecoder->getPos().y; if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); if (frame) { - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); g_system->updateScreen(); } @@ -433,6 +541,7 @@ void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) picEntry->x = planePicture->getSci32celX(pictureCelNr); picEntry->picStartX = pictureIt->startX; picEntry->picStartY = pictureIt->startY; + picEntry->visible = true; picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); @@ -507,13 +616,26 @@ void GfxFrameout::kernelFrameout() { for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { reg_t planeObject = it->object; - uint16 planeLastPriority = it->lastPriority; + + // Draw any plane lines, if they exist + // These are drawn on invisible planes as well. (e.g. "invisiblePlane" in LSL6 hires) + // FIXME: Lines aren't always drawn (e.g. when the narrator speaks in LSL6 hires). + // Perhaps something is painted over them? + for (PlaneLineList::iterator it2 = it->lines.begin(); it2 != it->lines.end(); ++it2) { + Common::Point startPoint = it2->startPoint; + Common::Point endPoint = it2->endPoint; + _coordAdjuster->kernelLocalToGlobal(startPoint.x, startPoint.y, it->object); + _coordAdjuster->kernelLocalToGlobal(endPoint.x, endPoint.y, it->object); + _screen->drawLine(startPoint, endPoint, it2->color, it2->priority, it2->control); + } + + int16 planeLastPriority = it->lastPriority; // Update priority here, sq6 sets it w/o UpdatePlane - uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); + int16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); it->lastPriority = planePriority; - if (planePriority == 0xffff) { // Plane currently not meant to be shown + if (planePriority < 0) { // Plane currently not meant to be shown // If plane was shown before, delete plane rect if (planePriority != planeLastPriority) _paint32->fillRect(it->planeRect, 0); @@ -523,44 +645,40 @@ void GfxFrameout::kernelFrameout() { // There is a race condition lurking in SQ6, which causes the game to hang in the intro, when teleporting to Polysorbate LX. // Since I first wrote the patch, the race has stopped occurring for me though. // I'll leave this for investigation later, when someone can reproduce. - //if (it->pictureId == 0xffff) // FIXME: This is what SSCI does, and fixes the intro of LSL7, but breaks the dialogs in GK1 (adds black boxes) - if (it->planeBack) + //if (it->pictureId == kPlanePlainColored) // FIXME: This is what SSCI does, and fixes the intro of LSL7, but breaks the dialogs in GK1 (adds black boxes) + if (it->pictureId == kPlanePlainColored && (it->planeBack || g_sci->getGameId() != GID_GK1)) _paint32->fillRect(it->planeRect, it->planeBack); - GuiResourceId planeMainPictureId = it->pictureId; - _coordAdjuster->pictureSetDisplayArea(it->planeRect); - _palette->drewPicture(planeMainPictureId); + _palette->drewPicture(it->pictureId); FrameoutList itemList; createPlaneItemList(planeObject, itemList); -// warning("Plane %s", _segMan->getObjectName(planeObject)); - for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) { FrameoutEntry *itemEntry = *listIterator; + if (!itemEntry->visible) + continue; + if (itemEntry->object.isNull()) { // Picture cel data - itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); - itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); - itemEntry->picStartX = upscaleHorizontalCoordinate(itemEntry->picStartX); - itemEntry->picStartY = upscaleVerticalCoordinate(itemEntry->picStartY); + _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); + _coordAdjuster->fromScriptToDisplay(itemEntry->picStartY, itemEntry->picStartX); if (!isPictureOutOfView(itemEntry, it->planeRect, it->planeOffsetX, it->planeOffsetY)) drawPicture(itemEntry, it->planeOffsetX, it->planeOffsetY, it->planePictureMirrored); } else { GfxView *view = (itemEntry->viewId != 0xFFFF) ? _cache->getView(itemEntry->viewId) : NULL; - + int16 dummyX = 0; + if (view && view->isSci2Hires()) { - int16 dummyX = 0; view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); view->adjustToUpscaledCoordinates(itemEntry->z, dummyX); - } else if (getSciVersion() == SCI_VERSION_2_1) { - itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); - itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); - itemEntry->z = upscaleVerticalCoordinate(itemEntry->z); + } else if (getSciVersion() >= SCI_VERSION_2_1) { + _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); + _coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX); } // Adjust according to current scroll position @@ -581,13 +699,13 @@ void GfxFrameout::kernelFrameout() { // TODO: maybe we should clip the cels rect with this, i'm not sure // the only currently known usage is game menu of gk1 } else if (view) { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->getCelRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); - else - view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, - itemEntry->scaleY, itemEntry->celRect); + if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) + view->getCelRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); + else + view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, + itemEntry->scaleY, itemEntry->celRect); Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane @@ -596,8 +714,9 @@ void GfxFrameout::kernelFrameout() { if (view && view->isSci2Hires()) { view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); - } else if (getSciVersion() == SCI_VERSION_2_1) { - nsRect = upscaleRect(nsRect); + } else if (getSciVersion() >= SCI_VERSION_2_1) { + _coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left); + _coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right); } if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { @@ -610,17 +729,11 @@ void GfxFrameout::kernelFrameout() { g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } - int16 screenHeight = _screen->getHeight(); - int16 screenWidth = _screen->getWidth(); - if (view && view->isSci2Hires()) { - screenHeight = _screen->getDisplayHeight(); - screenWidth = _screen->getDisplayWidth(); - } - - if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= screenHeight) - continue; - - if (itemEntry->celRect.right < 0 || itemEntry->celRect.left >= screenWidth) + // Don't attempt to draw sprites that are outside the visible + // screen area. An example is the random people walking in + // Jackson Square in GK1. + if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() || + itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth()) continue; Common::Rect clipRect, translatedClipRect; @@ -631,6 +744,9 @@ void GfxFrameout::kernelFrameout() { translatedClipRect = clipRect; translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); } else { + // QFG4 passes invalid rectangles when a battle is starting + if (!clipRect.isValidRect()) + continue; clipRect.clip(it->planeClipRect); translatedClipRect = clipRect; translatedClipRect.translate(it->planeRect.left, it->planeRect.top); @@ -662,9 +778,61 @@ void GfxFrameout::kernelFrameout() { } } + showCurrentScrollText(); + _screen->copyToScreen(); g_sci->getEngineState()->_throttleTrigger = true; } +void GfxFrameout::printPlaneList(Console *con) { + for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) { + PlaneEntry p = *it; + Common::String curPlaneName = _segMan->getObjectName(p.object); + Common::Rect r = p.upscaledPlaneRect; + Common::Rect cr = p.upscaledPlaneClipRect; + + con->DebugPrintf("%04x:%04x (%s): prio %d, lastprio %d, offsetX %d, offsetY %d, pic %d, mirror %d, back %d\n", + PRINT_REG(p.object), curPlaneName.c_str(), + (int16)p.priority, (int16)p.lastPriority, + p.planeOffsetX, p.planeOffsetY, p.pictureId, + p.planePictureMirrored, p.planeBack); + con->DebugPrintf(" rect: (%d, %d, %d, %d), clip rect: (%d, %d, %d, %d)\n", + r.left, r.top, r.right, r.bottom, + cr.left, cr.top, cr.right, cr.bottom); + + if (p.pictureId != 0xffff && p.pictureId != 0xfffe) { + con->DebugPrintf("Pictures:\n"); + + for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { + if (pictureIt->object == p.object) { + con->DebugPrintf(" Picture %d: x %d, y %d\n", pictureIt->pictureId, pictureIt->startX, pictureIt->startY); + } + } + } + } +} + +void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) { + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + FrameoutEntry *e = *listIterator; + reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane)); + + if (planeObject == itemPlane) { + Common::String curItemName = _segMan->getObjectName(e->object); + Common::Rect icr = e->celRect; + GuiResourceId picId = e->picture ? e->picture->getResourceId() : 0; + + con->DebugPrintf("%d: %04x:%04x (%s), view %d, loop %d, cel %d, x %d, y %d, z %d, " + "signal %d, scale signal %d, scaleX %d, scaleY %d, rect (%d, %d, %d, %d), " + "pic %d, picX %d, picY %d, visible %d\n", + e->givenOrderNr, PRINT_REG(e->object), curItemName.c_str(), + e->viewId, e->loopNo, e->celNo, e->x, e->y, e->z, + e->signal, e->scaleSignal, e->scaleX, e->scaleY, + icr.left, icr.top, icr.right, icr.bottom, + picId, e->picStartX, e->picStartY, e->visible); + } + } +} + } // End of namespace Sci diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 8c3cc261d5..5fd2824224 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -27,10 +27,21 @@ namespace Sci { class GfxPicture; +struct PlaneLineEntry { + reg_t hunkId; + Common::Point startPoint; + Common::Point endPoint; + byte color; + byte priority; + byte control; +}; + +typedef Common::List<PlaneLineEntry> PlaneLineList; + struct PlaneEntry { reg_t object; - uint16 priority; - uint16 lastPriority; + int16 priority; + int16 lastPriority; int16 planeOffsetX; int16 planeOffsetY; GuiResourceId pictureId; @@ -40,6 +51,7 @@ struct PlaneEntry { Common::Rect upscaledPlaneClipRect; bool planePictureMirrored; byte planeBack; + PlaneLineList lines; }; typedef Common::List<PlaneEntry> PlaneList; @@ -60,6 +72,7 @@ struct FrameoutEntry { GfxPicture *picture; int16 picStartX; int16 picStartY; + bool visible; }; typedef Common::List<FrameoutEntry *> FrameoutList; @@ -75,6 +88,15 @@ struct PlanePictureEntry { typedef Common::List<PlanePictureEntry> PlanePictureList; +struct ScrollTextEntry { + reg_t bitmapHandle; + reg_t kWindow; + uint16 x; + uint16 y; +}; + +typedef Common::Array<ScrollTextEntry> ScrollTextList; + class GfxCache; class GfxCoordAdjuster32; class GfxPaint32; @@ -102,16 +124,30 @@ public: void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0); void deletePlanePictures(reg_t object); + reg_t addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control); + void updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control); + void deletePlaneLine(reg_t object, reg_t hunkId); void clear(); + // Scroll text functions + void addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace); + void showCurrentScrollText(); + void initScrollText(uint16 maxItems) { _maxScrollTexts = maxItems; } + void clearScrollTexts(); + void firstScrollText() { if (_scrollTexts.size() > 0) _curScrollText = 0; } + void lastScrollText() { if (_scrollTexts.size() > 0) _curScrollText = _scrollTexts.size() - 1; } + void prevScrollText() { if (_curScrollText > 0) _curScrollText--; } + void nextScrollText() { if (_curScrollText + 1 < (uint16)_scrollTexts.size()) _curScrollText++; } + void toggleScrollText(bool show) { _showScrollText = show; } + + void printPlaneList(Console *con); + void printPlaneItemList(Console *con, reg_t planeObject); + private: void showVideo(); void createPlaneItemList(reg_t planeObject, FrameoutList &itemList); bool isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY); void drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored); - int16 upscaleHorizontalCoordinate(int16 coordinate); - int16 upscaleVerticalCoordinate(int16 coordinate); - Common::Rect upscaleRect(Common::Rect &rect); SegManager *_segMan; ResourceManager *_resMan; @@ -124,11 +160,12 @@ private: FrameoutList _screenItems; PlaneList _planes; PlanePictureList _planePictures; + ScrollTextList _scrollTexts; + int16 _curScrollText; + bool _showScrollText; + uint16 _maxScrollTexts; void sortPlanes(); - - uint16 _scriptsRunningWidth; - uint16 _scriptsRunningHeight; }; } // End of namespace Sci diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index 7ecba5a24d..dfb50b0edb 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -129,7 +129,7 @@ void GfxMacIconBar::drawIcon(uint16 iconIndex, bool selected) { void GfxMacIconBar::drawEnabledImage(Graphics::Surface *surface, const Common::Rect &rect) { if (surface) - g_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect.left, rect.top, rect.width(), rect.height()); + g_system->copyRectToScreen(surface->pixels, surface->pitch, rect.left, rect.top, rect.width(), rect.height()); } void GfxMacIconBar::drawDisabledImage(Graphics::Surface *surface, const Common::Rect &rect) { @@ -153,7 +153,7 @@ void GfxMacIconBar::drawDisabledImage(Graphics::Surface *surface, const Common:: *((byte *)newSurf.getBasePtr(j, i)) = 0; } - g_system->copyRectToScreen((byte *)newSurf.pixels, newSurf.pitch, rect.left, rect.top, rect.width(), rect.height()); + g_system->copyRectToScreen(newSurf.pixels, newSurf.pitch, rect.left, rect.top, rect.width(), rect.height()); newSurf.free(); } diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp index 47f34cf99d..bfecc296a2 100644 --- a/engines/sci/graphics/menu.cpp +++ b/engines/sci/graphics/menu.cpp @@ -219,7 +219,7 @@ void GfxMenu::kernelAddEntry(Common::String title, Common::String content, reg_t } } itemEntry->textVmPtr = contentVmPtr; - itemEntry->textVmPtr.offset += beginPos; + itemEntry->textVmPtr.incOffset(beginPos); if (rightAlignedPos) { rightAlignedPos++; @@ -297,13 +297,13 @@ void GfxMenu::kernelSetAttribute(uint16 menuId, uint16 itemId, uint16 attributeI // We assume here that no script ever creates a separatorLine dynamically break; case SCI_MENU_ATTRIBUTE_KEYPRESS: - itemEntry->keyPress = tolower(value.offset); + itemEntry->keyPress = tolower(value.getOffset()); itemEntry->keyModifier = 0; // TODO: Find out how modifier is handled - debug("setAttr keypress %X %X", value.segment, value.offset); + debug("setAttr keypress %X %X", value.getSegment(), value.getOffset()); break; case SCI_MENU_ATTRIBUTE_TAG: - itemEntry->tag = value.offset; + itemEntry->tag = value.getOffset(); break; default: // Happens when loading a game in LSL3 - attribute 1A diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp index c951f3349d..89f3625e2c 100644 --- a/engines/sci/graphics/paint16.cpp +++ b/engines/sci/graphics/paint16.cpp @@ -491,10 +491,10 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { // processing codes in argv while (argc > 0) { displayArg = argv[0]; - if (displayArg.segment) - displayArg.offset = 0xFFFF; + if (displayArg.getSegment()) + displayArg.setOffset(0xFFFF); argc--; argv++; - switch (displayArg.offset) { + switch (displayArg.getOffset()) { case SCI_DISPLAY_MOVEPEN: _ports->moveTo(argv[0].toUint16(), argv[1].toUint16()); argc -= 2; argv += 2; @@ -547,9 +547,9 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { if (!(g_sci->getGameId() == GID_LONGBOW && g_sci->isDemo()) && !(g_sci->getGameId() == GID_QFG1 && g_sci->isDemo()) && !(g_sci->getGameId() == GID_PQ2)) - error("Unknown kDisplay argument %d", displayArg.offset); + error("Unknown kDisplay argument %d", displayArg.getOffset()); - if (displayArg.offset == SCI_DISPLAY_DUMMY2) { + if (displayArg.getOffset() == SCI_DISPLAY_DUMMY2) { if (!argc) error("No parameter left for kDisplay(115)"); argc--; argv++; diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 47d1647c6c..53d69cdcca 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -100,6 +100,9 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen) default: error("GfxPalette: Unknown view type"); } + + _remapOn = false; + resetRemapping(); } GfxPalette::~GfxPalette() { @@ -140,8 +143,9 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) memset(paletteOut, 0, sizeof(Palette)); // Setup 1:1 mapping - for (colorNo = 0; colorNo < 256; colorNo++) + for (colorNo = 0; colorNo < 256; colorNo++) { paletteOut->mapping[colorNo] = colorNo; + } if (bytesLeft < 37) { // This happens when loading palette of picture 0 in sq5 - the resource is broken and doesn't contain a full @@ -329,6 +333,79 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) { } } +byte GfxPalette::remapColor(byte remappedColor, byte screenColor) { + assert(_remapOn); + if (_remappingType[remappedColor] == kRemappingByRange) + return _remappingByRange[screenColor]; + else if (_remappingType[remappedColor] == kRemappingByPercent) + return _remappingByPercent[screenColor]; + else + error("remapColor(): Color %d isn't remapped", remappedColor); + + return 0; // should never reach here +} + +void GfxPalette::resetRemapping() { + _remapOn = false; + _remappingPercentToSet = 0; + + for (int i = 0; i < 256; i++) { + _remappingType[i] = kRemappingNone; + _remappingByPercent[i] = i; + _remappingByRange[i] = i; + } +} + +void GfxPalette::setRemappingPercent(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + for (int i = 0; i < 256; i++) { + byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = kernelFindColor(r, g, b); + } + + _remappingType[color] = kRemappingByPercent; +} + +void GfxPalette::setRemappingPercentGray(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + // Note: This is not what the original does, but the results are the same visually + for (int i = 0; i < 256; i++) { + byte rComponent = _sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100; + byte gComponent = _sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100; + byte bComponent = _sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100; + byte luminosity = rComponent + gComponent + bComponent; + _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity); + } + + _remappingType[color] = kRemappingByPercent; +} + +void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) { + _remapOn = true; + + for (int i = from; i <= to; i++) { + _remappingByRange[i] = i + base; + } + + _remappingType[color] = kRemappingByRange; +} + bool GfxPalette::insert(Palette *newPalette, Palette *destPalette) { bool paletteChanged = false; @@ -491,6 +568,16 @@ void GfxPalette::copySysPaletteToScreen() { } } + // Check if we need to reset remapping by percent with the new colors. + if (_remappingPercentToSet) { + for (int i = 0; i < 256; i++) { + byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = kernelFindColor(r, g, b); + } + } + g_system->getPaletteManager()->setPalette(bpal, 0, 256); } @@ -698,7 +785,7 @@ void GfxPalette::palVaryInit() { } bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) { - _palVaryResourceId = resourceId; + _palVaryResourceId = (resourceId != 65535) ? resourceId : -1; Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); if (palResource) { // Load and initialize destination palette @@ -999,8 +1086,9 @@ bool GfxPalette::loadClut(uint16 clutId) { memset(&pal, 0, sizeof(Palette)); // Setup 1:1 mapping - for (int i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) { pal.mapping[i] = i; + } // Now load in the palette for (int i = 1; i <= 236; i++) { diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index a9ea1c32de..e974781d49 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -31,6 +31,12 @@ namespace Sci { class ResourceManager; class GfxScreen; +enum ColorRemappingType { + kRemappingNone = 0, + kRemappingByRange = 1, + kRemappingByPercent = 2 +}; + /** * Palette class, handles palette operations like changing intensity, setting up the palette, merging different palettes */ @@ -53,6 +59,15 @@ public: void getSys(Palette *pal); uint16 getTotalColorCount() const { return _totalScreenColors; } + void resetRemapping(); + void setRemappingPercent(byte color, byte percent); + void setRemappingPercentGray(byte color, byte percent); + void setRemappingRange(byte color, byte from, byte to, byte base); + bool isRemapped(byte color) const { + return _remapOn && (_remappingType[color] != kRemappingNone); + } + byte remapColor(byte remappedColor, byte screenColor); + void setOnScreen(); void copySysPaletteToScreen(); @@ -123,6 +138,12 @@ private: int _palVarySignal; uint16 _totalScreenColors; + bool _remapOn; + ColorRemappingType _remappingType[256]; + byte _remappingByPercent[256]; + byte _remappingByRange[256]; + uint16 _remappingPercentToSet; + void loadMacIconBarPalette(); byte *_macClut; diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 4020518b72..246b6bfff9 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -53,23 +53,35 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { #ifdef ENABLE_SCI32 // GK1 Mac uses a 640x480 resolution too - if (g_sci->getGameId() == GID_GK1 && g_sci->getPlatform() == Common::kPlatformMacintosh) - _upscaledHires = GFX_SCREEN_UPSCALED_640x480; + if (g_sci->getPlatform() == Common::kPlatformMacintosh) { + if (g_sci->getGameId() == GID_GK1) + _upscaledHires = GFX_SCREEN_UPSCALED_640x480; + } #endif if (_resMan->detectHires()) { _width = 640; + _pitch = 640; _height = 480; } else { _width = 320; + _pitch = 320; _height = getLowResScreenHeight(); } +#ifdef ENABLE_SCI32 + // Phantasmagoria 1 sets a window area of 630x450 + if (g_sci->getGameId() == GID_PHANTASMAGORIA) { + _width = 630; + _height = 450; + } +#endif + // Japanese versions of games use hi-res font on upscaled version of the game. if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1)) _upscaledHires = GFX_SCREEN_UPSCALED_640x400; - _pixels = _width * _height; + _pixels = _pitch * _height; switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_640x400: @@ -91,7 +103,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { _upscaledMapping[i] = (i * 12) / 5; break; default: - _displayWidth = _width; + _displayWidth = _pitch; _displayHeight = _height; memset(&_upscaledMapping, 0, sizeof(_upscaledMapping) ); break; @@ -207,7 +219,7 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) { } void GfxScreen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; + int offset = y * _pitch + x; if (drawMask & GFX_SCREEN_MASK_VISUAL) { _visualScreen[offset] = color; @@ -240,7 +252,7 @@ void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) { // Do not scale ourselves, but put it on the display directly putPixelOnDisplay(x, y + startingY, color); } else { - int offset = (startingY + y) * _width + x; + int offset = (startingY + y) * _pitch + x; _visualScreen[offset] = color; if (!_upscaledHires) { @@ -342,19 +354,19 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u } byte GfxScreen::getVisual(int x, int y) { - return _visualScreen[y * _width + x]; + return _visualScreen[y * _pitch + x]; } byte GfxScreen::getPriority(int x, int y) { - return _priorityScreen[y * _width + x]; + return _priorityScreen[y * _pitch + x]; } byte GfxScreen::getControl(int x, int y) { - return _controlScreen[y * _width + x]; + return _controlScreen[y * _pitch + x]; } byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) { - int offset = y * _width + x; + int offset = y * _pitch + x; byte match = 0; if (screenMask & GFX_SCREEN_MASK_VISUAL) { @@ -415,14 +427,14 @@ void GfxScreen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) { memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask); if (mask & GFX_SCREEN_MASK_VISUAL) { - bitsSaveScreen(rect, _visualScreen, _width, memoryPtr); + bitsSaveScreen(rect, _visualScreen, _pitch, memoryPtr); bitsSaveDisplayScreen(rect, memoryPtr); } if (mask & GFX_SCREEN_MASK_PRIORITY) { - bitsSaveScreen(rect, _priorityScreen, _width, memoryPtr); + bitsSaveScreen(rect, _priorityScreen, _pitch, memoryPtr); } if (mask & GFX_SCREEN_MASK_CONTROL) { - bitsSaveScreen(rect, _controlScreen, _width, memoryPtr); + bitsSaveScreen(rect, _controlScreen, _pitch, memoryPtr); } if (mask & GFX_SCREEN_MASK_DISPLAY) { if (!_upscaledHires) @@ -475,14 +487,14 @@ void GfxScreen::bitsRestore(byte *memoryPtr) { memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask); if (mask & GFX_SCREEN_MASK_VISUAL) { - bitsRestoreScreen(rect, memoryPtr, _visualScreen, _width); + bitsRestoreScreen(rect, memoryPtr, _visualScreen, _pitch); bitsRestoreDisplayScreen(rect, memoryPtr); } if (mask & GFX_SCREEN_MASK_PRIORITY) { - bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _width); + bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _pitch); } if (mask & GFX_SCREEN_MASK_CONTROL) { - bitsRestoreScreen(rect, memoryPtr, _controlScreen, _width); + bitsRestoreScreen(rect, memoryPtr, _controlScreen, _pitch); } if (mask & GFX_SCREEN_MASK_DISPLAY) { if (!_upscaledHires) @@ -560,7 +572,7 @@ void GfxScreen::dither(bool addToFlag) { if (!_unditheringEnabled) { // Do dithering on visual and display-screen for (y = 0; y < _height; y++) { - for (x = 0; x < _width; x++) { + for (x = 0; x < _pitch; x++) { color = *visualPtr; if (color & 0xF0) { color ^= color << 4; @@ -585,7 +597,7 @@ void GfxScreen::dither(bool addToFlag) { memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors)); // Do dithering on visual screen and put decoded but undithered byte onto display-screen for (y = 0; y < _height; y++) { - for (x = 0; x < _width; x++) { + for (x = 0; x < _pitch; x++) { color = *visualPtr; if (color & 0xF0) { color ^= color << 4; diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h index 73ea596ba1..01fb899edb 100644 --- a/engines/sci/graphics/screen.h +++ b/engines/sci/graphics/screen.h @@ -132,6 +132,7 @@ public: private: uint16 _width; + uint16 _pitch; uint16 _height; uint _pixels; uint16 _displayWidth; diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 7894c7109c..f14ae2ef0b 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -49,9 +49,12 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) GfxText32::~GfxText32() { } +reg_t GfxText32::createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { + return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk); + +} reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); - // The object in the text selector of the item can be either a raw string // or a Str object. In the latter case, we need to access the object's data // selector to get the raw string. @@ -59,6 +62,11 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); Common::String text = _segMan->getString(stringObject); + + return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk); +} + +reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { // HACK: The character offsets of the up and down arrow buttons are off by one // in GK1, for some unknown reason. Fix them here. if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) { @@ -91,7 +99,11 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH reg_t memoryId = NULL_REG; if (prevHunk.isNull()) { memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); - writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); + + // Scroll text objects have no bitmap selector! + ObjVarRef varp; + if (lookupSelector(_segMan, textObject, SELECTOR(bitmap), &varp, NULL) == kSelectorVariable) + writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); } else { memoryId = prevHunk; } @@ -153,10 +165,24 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH warning("Invalid alignment %d used in TextBox()", alignment); } + byte curChar; + for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); - curX += font->getCharWidth(curChar); + curChar = txt[i]; + + switch (curChar) { + case 0x0A: + case 0x0D: + case 0: + break; + case 0x7C: + warning("Code processing isn't implemented in SCI32"); + break; + default: + font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); + curX += font->getCharWidth(curChar); + break; + } } curX = 0; @@ -175,7 +201,25 @@ void GfxText32::disposeTextBitmap(reg_t hunkId) { void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) { reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap)); - uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); + drawTextBitmapInternal(x, y, planeRect, textObject, hunkId); +} + +void GfxText32::drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y) { + /*reg_t plane = readSelector(_segMan, textObject, SELECTOR(plane)); + Common::Rect planeRect; + planeRect.top = readSelectorValue(_segMan, plane, SELECTOR(top)); + planeRect.left = readSelectorValue(_segMan, plane, SELECTOR(left)); + planeRect.bottom = readSelectorValue(_segMan, plane, SELECTOR(bottom)); + planeRect.right = readSelectorValue(_segMan, plane, SELECTOR(right)); + + drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);*/ + + // HACK: we pretty much ignore the plane rect and x, y... + drawTextBitmapInternal(0, 0, Common::Rect(20, 390, 600, 460), textObject, hunkId); +} + +void GfxText32::drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId) { + int16 backColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(back)); // Sanity check: Check if the hunk is set. If not, either the game scripts // didn't set it, or an old saved game has been loaded, where it wasn't set. if (hunkId.isNull()) @@ -187,13 +231,17 @@ void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t t byte *memoryPtr = _segMan->getHunkPointer(hunkId); - if (!memoryPtr) - error("Attempt to draw an invalid text bitmap"); + if (!memoryPtr) { + // Happens when restoring in some SCI32 games (e.g. SQ6). + // Commented out to reduce console spam + //warning("Attempt to draw an invalid text bitmap"); + return; + } byte *surface = memoryPtr + BITMAP_HEADER_SIZE; int curByte = 0; - uint16 skipColor = readSelectorValue(_segMan, textObject, SELECTOR(skip)); + int16 skipColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(skip)); uint16 textX = planeRect.left + x; uint16 textY = planeRect.top + y; // Get totalWidth, totalHeight @@ -206,10 +254,13 @@ void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t t textY = textY * _screen->getDisplayHeight() / _screen->getHeight(); } + bool translucent = (skipColor == -1 && backColor == -1); + for (int curY = 0; curY < height; curY++) { for (int curX = 0; curX < width; curX++) { byte pixel = surface[curByte++]; - if (pixel != skipColor && pixel != backColor) + if ((!translucent && pixel != skipColor && pixel != backColor) || + (translucent && pixel != 0xFF)) _screen->putFontPixel(textY, curX + textX, curY, pixel); } } @@ -265,7 +316,7 @@ void GfxText32::StringWidth(const char *str, GuiResourceId fontId, int16 &textWi } void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fontId, int16 &textWidth, int16 &textHeight, bool restoreFont) { - uint16 curChar; + byte curChar; textWidth = 0; textHeight = 0; GfxFont *font = _cache->getFont(fontId); @@ -277,7 +328,6 @@ void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fon switch (curChar) { case 0x0A: case 0x0D: - case 0x9781: // this one is used by SQ4/japanese as line break as well textHeight = MAX<int16> (textHeight, font->getHeight()); break; case 0x7C: diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h index 3505de85eb..ce78003fdf 100644 --- a/engines/sci/graphics/text32.h +++ b/engines/sci/graphics/text32.h @@ -33,13 +33,17 @@ public: GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); ~GfxText32(); reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); - void disposeTextBitmap(reg_t hunkId); + reg_t createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); void drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject); + void drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y); + void disposeTextBitmap(reg_t hunkId); int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font); void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); private: + reg_t createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t hunkId); + void drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId); int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth); void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont); void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index a77bcccc52..36aaae9232 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -720,6 +720,19 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); + // WORKAROUND: EcoQuest French and German draw the fish and anemone sprites + // with priority 15 in scene 440. Afterwards, a dialog is shown on top of + // these sprites with priority 15 as well. This is undefined behavior + // actually, as the sprites and dialog share the same priority, so in our + // implementation the sprites get drawn incorrectly on top of the dialog. + // Perhaps this worked by mistake in SSCI because of subtle differences in + // how sprites are drawn. We compensate for this by resetting the priority + // of all sprites that have a priority of 15 in scene 440 to priority 14, + // so that the speech bubble can be drawn correctly on top of them. Fixes + // bug #3040625. + if (g_sci->getGameId() == GID_ECOQUEST && g_sci->getEngineState()->currentRoomNumber() == 440 && priority == 15) + priority = 14; + if (!_EGAmapping) { for (y = 0; y < height; y++, bitmap += celWidth) { for (x = 0; x < width; x++) { @@ -728,8 +741,14 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; if (!upscaledHires) { - if (priority >= _screen->getPriority(x2, y2)) - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); + if (priority >= _screen->getPriority(x2, y2)) { + if (!_palette->isRemapped(palette->mapping[color])) { + _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); + } else { + byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); + } + } } else { // UpscaledHires means view is hires and is supposed to // get drawn onto lowres screen. @@ -838,7 +857,12 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; if (color != clearKey && priority >= _screen->getPriority(x2, y2)) { - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); + if (!_palette->isRemapped(palette->mapping[color])) { + _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); + } else { + byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); + } } } } diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 90a0f33f06..6b6058c819 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -10,6 +10,7 @@ MODULE_OBJS := \ sci.o \ util.o \ engine/features.o \ + engine/file.o \ engine/gc.o \ engine/kernel.o \ engine/kevent.o \ @@ -79,6 +80,7 @@ MODULE_OBJS := \ ifdef ENABLE_SCI32 MODULE_OBJS += \ + engine/kgraphics32.o \ graphics/controls32.o \ graphics/frameout.o \ graphics/paint32.o \ diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 77a6a40a92..c9c0d25bc6 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -93,7 +93,7 @@ const char *getSciVersionDesc(SciVersion version) { //#define SCI_VERBOSE_RESMAN 1 -static const char *const sci_error_types[] = { +static const char *const s_errorDescriptions[] = { "No error", "I/O error", "Resource is empty (size 0)", @@ -101,10 +101,8 @@ static const char *const sci_error_types[] = { "resource.map file not found", "No resource files found", "Unknown compression method", - "Decompression failed: Decompression buffer overflow", "Decompression failed: Sanity check failed", - "Decompression failed: Resource too big", - "SCI version is unsupported" + "Decompression failed: Resource too big" }; static const char *const s_resourceTypeNames[] = { @@ -576,7 +574,7 @@ void ResourceSource::loadResource(ResourceManager *resMan, Resource *res) { if (error) { warning("Error %d occurred while reading %s from resource file %s: %s", error, res->_id.toString().c_str(), res->getResourceLocation().c_str(), - sci_error_types[error]); + s_errorDescriptions[error]); res->unalloc(); } @@ -1876,6 +1874,9 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream uint32 wCompression, szUnpacked; ResourceType type; + if (file->size() == 0) + return SCI_ERROR_EMPTY_RESOURCE; + switch (volVersion) { case kResVersionSci0Sci1Early: case kResVersionSci1Middle: @@ -1920,7 +1921,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream break; #endif default: - return SCI_ERROR_INVALID_RESMAP_ENTRY; + return SCI_ERROR_RESMAP_INVALID_ENTRY; } // check if there were errors while reading @@ -1961,7 +1962,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream compression = kCompUnknown; } - return compression == kCompUnknown ? SCI_ERROR_UNKNOWN_COMPRESSION : 0; + return (compression == kCompUnknown) ? SCI_ERROR_UNKNOWN_COMPRESSION : SCI_ERROR_NONE; } int Resource::decompress(ResVersion volVersion, Common::SeekableReadStream *file) { @@ -2589,7 +2590,7 @@ Common::String ResourceManager::findSierraGameId() { if (!heap) return ""; - int16 gameObjectOffset = findGameObject(false).offset; + int16 gameObjectOffset = findGameObject(false).getOffset(); if (!gameObjectOffset) return ""; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 294a4672e2..4baf39c67f 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -54,17 +54,17 @@ enum ResourceStatus { kResStatusLocked /**< Allocated and in use */ }; -/** Initialization result types */ -enum { +/** Resource error codes. Should be in sync with s_errorDescriptions */ +enum ResourceErrorCodes { + SCI_ERROR_NONE = 0, SCI_ERROR_IO_ERROR = 1, - SCI_ERROR_INVALID_RESMAP_ENTRY = 2, /**< Invalid resource.map entry */ - SCI_ERROR_RESMAP_NOT_FOUND = 3, - SCI_ERROR_NO_RESOURCE_FILES_FOUND = 4, /**< No resource at all was found */ - SCI_ERROR_UNKNOWN_COMPRESSION = 5, - SCI_ERROR_DECOMPRESSION_ERROR = 6, /**< sanity checks failed during decompression */ + SCI_ERROR_EMPTY_RESOURCE = 2, + SCI_ERROR_RESMAP_INVALID_ENTRY = 3, /**< Invalid resource.map entry */ + SCI_ERROR_RESMAP_NOT_FOUND = 4, + SCI_ERROR_NO_RESOURCE_FILES_FOUND = 5, /**< No resource at all was found */ + SCI_ERROR_UNKNOWN_COMPRESSION = 6, + SCI_ERROR_DECOMPRESSION_ERROR = 7, /**< sanity checks failed during decompression */ SCI_ERROR_RESOURCE_TOO_BIG = 8 /**< Resource size exceeds SCI_MAX_RESOURCE_SIZE */ - - /* the first critical error number */ }; enum { diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 9b0ee6924b..42ae00b525 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -385,7 +385,7 @@ bool SciEngine::gameHasFanMadePatch() { { GID_PQ3, 994, 4686, 1291, 0x78 }, // English { GID_PQ3, 994, 4734, 1283, 0x78 }, // German { GID_QFG1VGA, 994, 4388, 0, 0x00 }, - { GID_QFG3, 994, 4714, 0, 0x00 }, + { GID_QFG3, 33, 260, 0, 0x00 }, // TODO: Disabled, as it fixes a whole lot of bugs which can't be tested till SCI2.1 support is finished //{ GID_QFG4, 710, 11477, 0, 0x00 }, { GID_SQ1, 994, 4740, 0, 0x00 }, @@ -453,8 +453,8 @@ static byte patchGameRestoreSaveSci21[] = { }; static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) { - Script *script = segMan->getScript(methodAddress.segment); - byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset)); + Script *script = segMan->getScript(methodAddress.getSegment()); + byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); if (getSciVersion() <= SCI_VERSION_1_1) memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave)); else // SCI2+ @@ -463,8 +463,8 @@ static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, by } static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) { - Script *script = segMan->getScript(methodAddress.segment); - byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset)); + Script *script = segMan->getScript(methodAddress.getSegment()); + byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset())); memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21)); if (doRestore) patchPtr[2] = 0x78; // push1 @@ -632,7 +632,7 @@ void SciEngine::initGraphics() { _gfxPaint = _gfxPaint32; _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxText32); - _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); + _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { #endif @@ -740,7 +740,7 @@ GUI::Debugger *SciEngine::getDebugger() { if (_gamestate) { ExecStack *xs = &(_gamestate->_executionStack.back()); if (xs) { - xs->addr.pc.offset = _debugState.old_pc_offset; + xs->addr.pc.setOffset(_debugState.old_pc_offset); xs->sp = _debugState.old_sp; } } diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp index 123dd21894..528bb51393 100644 --- a/engines/sci/sound/audio.cpp +++ b/engines/sci/sound/audio.cpp @@ -67,7 +67,8 @@ int AudioPlayer::startAudio(uint16 module, uint32 number) { if (audioStream) { _wPlayFlag = false; - _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); + Audio::Mixer::SoundType soundType = (module == 65535) ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType; + _mixer->playStream(soundType, &_audioHandle, audioStream); return sampleLen; } else { // Don't throw a warning in this case. getAudioStream() already has. Some games diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 09cab75c39..918b045cb9 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -88,6 +88,12 @@ void SciMusic::init() { uint32 dev = MidiDriver::detectDevice(deviceFlags); _musicType = MidiDriver::getMusicType(dev); + if (g_sci->_features->useAltWinGMSound() && _musicType != MT_GM) { + warning("A Windows CD version with an alternate MIDI soundtrack has been chosen, " + "but no MIDI music device has been selected. Reverting to the DOS soundtrack"); + g_sci->_features->forceDOSTracks(); + } + switch (_musicType) { case MT_ADLIB: // FIXME: There's no Amiga sound option, so we hook it up to AdLib diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 05bb90332a..5d32f40f18 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -61,7 +61,7 @@ reg_t SoundCommandParser::kDoSoundInit(int argc, reg_t *argv, reg_t acc) { } int SoundCommandParser::getSoundResourceId(reg_t obj) { - int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1; + int resourceId = obj.getSegment() ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1; // Modify the resourceId for the Windows versions that have an alternate MIDI soundtrack, like SSCI did. if (g_sci && g_sci->_features->useAltWinGMSound()) { // Check if the alternate MIDI song actually exists... @@ -96,7 +96,7 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) { if (_useDigitalSFX || !newSound->soundRes) { int sampleLen; newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); - newSound->soundType = Audio::Mixer::kSpeechSoundType; + newSound->soundType = Audio::Mixer::kSFXSoundType; } } @@ -291,7 +291,7 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) { reg_t obj = argv[0]; uint16 value = argc > 1 ? argv[1].toUint16() : 0; - if (!obj.segment) { // pause the whole playlist + if (!obj.getSegment()) { // pause the whole playlist _music->pauseAll(value); } else { // pause a playlist slot MusicEntry *musicSlot = _music->getSlot(obj); @@ -367,24 +367,36 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) { case 4: // SCI01+ case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue - musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); - // sometimes we get objects in that position, fix it up (ffs. workarounds) - if (!argv[1].segment) - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); - else - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; - musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); - musicSlot->fadeTicker = 0; - if (argc == 5) { // TODO: We currently treat this argument as a boolean, but may // have to handle different non-zero values differently. (e.g., - // some KQ6 scripts pass 3 here) - musicSlot->stopAfterFading = (argv[4].toUint16() != 0); + // some KQ6 scripts pass 3 here). + // There is a script bug in KQ6, room 460 (the room with the flying + // books). An object is passed here, which should not be treated as + // a true flag. Fixes bugs #3555404 and #3291115. + musicSlot->stopAfterFading = (argv[4].isNumber() && argv[4].toUint16() != 0); } else { musicSlot->stopAfterFading = false; } + musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); + // Check if the song is already at the requested volume. If it is, don't + // perform any fading. Happens for example during the intro of Longbow. + if (musicSlot->fadeTo != musicSlot->volume) { + // sometimes we get objects in that position, fix it up (ffs. workarounds) + if (!argv[1].getSegment()) + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); + else + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; + musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); + } else { + // Stop the music, if requested. Fixes bug #3555404. + if (musicSlot->stopAfterFading) + processStopSound(obj, false); + } + + musicSlot->fadeTicker = 0; + // WORKAROUND/HACK: In the labyrinth in KQ6, when falling in the pit and // lighting the lantern, the game scripts perform a fade in of the game // music, but set it to stop after fading. Remove that flag here. This is @@ -497,12 +509,7 @@ void SoundCommandParser::processUpdateCues(reg_t obj) { // fireworks). // It is also needed in other games, e.g. LSL6 when talking to the // receptionist (bug #3192166). - if (g_sci->getGameId() == GID_LONGBOW && g_sci->getEngineState()->currentRoomNumber() == 95) { - // HACK: Don't set a signal here in the intro of Longbow, as that makes some dialog - // boxes disappear too soon (bug #3044844). - } else { - writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET); - } + writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET); if (_soundVersion <= SCI_VERSION_0_LATE) { processStopSound(obj, false); } else { diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index 77f45e0788..608c77136f 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -22,11 +22,13 @@ #include "common/archive.h" #include "common/stream.h" +#include "common/substream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" #include "graphics/surface.h" +#include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "sci/resource.h" @@ -63,46 +65,26 @@ namespace Sci { // our graphics engine, it looks just like a part of the room. A RBT can move // around the screen and go behind other objects. (...) -#ifdef ENABLE_SCI32 - -enum robotPalTypes { +enum RobotPalTypes { kRobotPalVariable = 0, kRobotPalConstant = 1 }; -RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) { - _surface = 0; - _width = 0; - _height = 0; +RobotDecoder::RobotDecoder(bool isBigEndian) { _fileStream = 0; - _audioStream = 0; - _dirtyPalette = false; _pos = Common::Point(0, 0); - _mixer = mixer; _isBigEndian = isBigEndian; + _frameTotalSize = 0; } RobotDecoder::~RobotDecoder() { close(); } -bool RobotDecoder::load(GuiResourceId id) { - Common::String fileName = Common::String::format("%d.rbt", id); - Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - - if (!stream) { - warning("Unable to open robot file %s", fileName.c_str()); - return false; - } - - return loadStream(stream); -} - bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), _isBigEndian, DisposeAfterUse::YES); - _surface = new Graphics::Surface(); readHeaderChunk(); @@ -114,131 +96,60 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { if (_header.version < 4 || _header.version > 6) error("Unknown robot version: %d", _header.version); - if (_header.hasSound) { - _audioStream = Audio::makeQueuingAudioStream(11025, false); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream); - } + RobotVideoTrack *videoTrack = new RobotVideoTrack(_header.frameCount); + addTrack(videoTrack); - readPaletteChunk(_header.paletteDataSize); - readFrameSizesChunk(); - calculateVideoDimensions(); - _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8()); + if (_header.hasSound) + addTrack(new RobotAudioTrack()); + videoTrack->readPaletteChunk(_fileStream, _header.paletteDataSize); + readFrameSizesChunk(); + videoTrack->calculateVideoDimensions(_fileStream, _frameTotalSize); return true; } -void RobotDecoder::readHeaderChunk() { - // Header (60 bytes) - _fileStream->skip(6); - _header.version = _fileStream->readUint16(); - _header.audioChunkSize = _fileStream->readUint16(); - _header.audioSilenceSize = _fileStream->readUint16(); - _fileStream->skip(2); - _header.frameCount = _fileStream->readUint16(); - _header.paletteDataSize = _fileStream->readUint16(); - _header.unkChunkDataSize = _fileStream->readUint16(); - _fileStream->skip(5); - _header.hasSound = _fileStream->readByte(); - _fileStream->skip(34); - - // Some videos (e.g. robot 1305 in Phantasmagoria and - // robot 184 in Lighthouse) have an unknown chunk before - // the palette chunk (probably used for sound preloading). - // Skip it here. - if (_header.unkChunkDataSize) - _fileStream->skip(_header.unkChunkDataSize); -} - -void RobotDecoder::readPaletteChunk(uint16 chunkSize) { - byte *paletteData = new byte[chunkSize]; - _fileStream->read(paletteData, chunkSize); - - // SCI1.1 palette - byte palFormat = paletteData[32]; - uint16 palColorStart = paletteData[25]; - uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); +bool RobotDecoder::load(GuiResourceId id) { + // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) - + // its drawn at odd coordinates. SV can't play it either (along with some + // others), so it must be some new functionality added in RAMA's robot + // videos. Skip it for now. + if (g_sci->getGameId() == GID_RAMA && id == 1003) + return false; + + // TODO: The robot video in the Lighthouse demo gets stuck + if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16) + return false; - int palOffset = 37; - memset(_palette, 0, 256 * 3); + Common::String fileName = Common::String::format("%d.rbt", id); + Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { - if (palFormat == kRobotPalVariable) - palOffset++; - _palette[colorNo * 3 + 0] = paletteData[palOffset++]; - _palette[colorNo * 3 + 1] = paletteData[palOffset++]; - _palette[colorNo * 3 + 2] = paletteData[palOffset++]; + if (!stream) { + warning("Unable to open robot file %s", fileName.c_str()); + return false; } - _dirtyPalette = true; - delete[] paletteData; + return loadStream(stream); } +void RobotDecoder::close() { + VideoDecoder::close(); -void RobotDecoder::readFrameSizesChunk() { - // The robot video file contains 2 tables, with one entry for each frame: - // - A table containing the size of the image in each video frame - // - A table containing the total size of each video frame. - // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, - // they contain 32-bit integers. - - _frameTotalSize = new uint32[_header.frameCount]; - - // TODO: The table reading code can probably be removed once the - // audio chunk size is figured out (check the TODO inside processNextFrame()) -#if 0 - // We don't need any of the two tables to play the video, so we ignore - // both of them. - uint16 wordSize = _header.version == 6 ? 4 : 2; - _fileStream->skip(_header.frameCount * wordSize * 2); -#else - switch (_header.version) { - case 4: - case 5: // sizes are 16-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 2); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint16(); - break; - case 6: // sizes are 32-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 4); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint32(); - break; - default: - error("Can't yet handle index table for robot version %d", _header.version); - } -#endif - - // 2 more unknown tables - _fileStream->skip(1024 + 512); + delete _fileStream; + _fileStream = 0; - // Pad to nearest 2 kilobytes - uint32 curPos = _fileStream->pos(); - if (curPos & 0x7ff) - _fileStream->seek((curPos & ~0x7ff) + 2048); + delete[] _frameTotalSize; + _frameTotalSize = 0; } -void RobotDecoder::calculateVideoDimensions() { - // This is an O(n) operation, as each frame has a different size. - // We need to know the actual frame size to have a constant video size. - uint32 pos = _fileStream->pos(); - - for (uint32 curFrame = 0; curFrame < _header.frameCount; curFrame++) { - _fileStream->skip(4); - uint16 frameWidth = _fileStream->readUint16(); - uint16 frameHeight = _fileStream->readUint16(); - if (frameWidth > _width) - _width = frameWidth; - if (frameHeight > _height) - _height = frameHeight; - _fileStream->skip(_frameTotalSize[curFrame] - 8); - } +void RobotDecoder::readNextPacket() { + // Get our track + RobotVideoTrack *videoTrack = (RobotVideoTrack *)getTrack(0); + videoTrack->increaseCurFrame(); + Graphics::Surface *surface = videoTrack->getSurface(); - _fileStream->seek(pos); -} + if (videoTrack->endOfTrack()) + return; -const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Read frame image header (24 bytes) _fileStream->skip(3); byte frameScale = _fileStream->readByte(); @@ -247,23 +158,28 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { _fileStream->skip(4); // unknown, almost always 0 uint16 frameX = _fileStream->readUint16(); uint16 frameY = _fileStream->readUint16(); + // TODO: In v4 robot files, frameX and frameY have a different meaning. // Set them both to 0 for v4 for now, so that robots in PQ:SWAT show up // correctly. if (_header.version == 4) frameX = frameY = 0; + uint16 compressedSize = _fileStream->readUint16(); uint16 frameFragments = _fileStream->readUint16(); _fileStream->skip(4); // unknown uint32 decompressedSize = frameWidth * frameHeight * frameScale / 100; + // FIXME: A frame's height + position can go off limits... why? With the // following, we cut the contents to fit the frame - uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, _height - frameY); + uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, surface->h - frameY); + // FIXME: Same goes for the frame's width + position. In this case, we // modify the position to fit the contents on screen. - if (frameWidth + frameX > _width) - frameX = _width - frameWidth; - assert (frameWidth + frameX <= _width && scaledHeight + frameY <= _height); + if (frameWidth + frameX > surface->w) + frameX = surface->w - frameWidth; + + assert(frameWidth + frameX <= surface->w && scaledHeight + frameY <= surface->h); DecompressorLZS lzs; byte *decompressedFrame = new byte[decompressedSize]; @@ -294,24 +210,23 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Copy over the decompressed frame byte *inFrame = decompressedFrame; - byte *outFrame = (byte *)_surface->pixels; + byte *outFrame = (byte *)surface->pixels; // Black out the surface - memset(outFrame, 0, _width * _height); + memset(outFrame, 0, surface->w * surface->h); // Move to the correct y coordinate - outFrame += _width * frameY; + outFrame += surface->w * frameY; for (uint16 y = 0; y < scaledHeight; y++) { memcpy(outFrame + frameX, inFrame, frameWidth); inFrame += frameWidth; - outFrame += _width; + outFrame += surface->w; } delete[] decompressedFrame; - // +1 because we start with frame number -1 - uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize); + uint32 audioChunkSize = _frameTotalSize[videoTrack->getCurFrame()] - (24 + compressedSize); // TODO: The audio chunk size below is usually correct, but there are some // exceptions (e.g. robot 4902 in Phantasmagoria, towards its end) @@ -326,41 +241,166 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Queue the next audio frame // FIXME: For some reason, there are audio hiccups/gaps if (_header.hasSound) { - _fileStream->skip(8); // header - _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize - 8), - (audioChunkSize - 8) * 2, DisposeAfterUse::NO, - Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); + RobotAudioTrack *audioTrack = (RobotAudioTrack *)getTrack(1); + _fileStream->skip(8); // header + audioChunkSize -= 8; + audioTrack->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize), audioChunkSize * 2); } else { _fileStream->skip(audioChunkSize); - } - - if (_curFrame == -1) - _startTime = g_system->getMillis(); + } +} - _curFrame++; +void RobotDecoder::readHeaderChunk() { + // Header (60 bytes) + _fileStream->skip(6); + _header.version = _fileStream->readUint16(); + _header.audioChunkSize = _fileStream->readUint16(); + _header.audioSilenceSize = _fileStream->readUint16(); + _fileStream->skip(2); + _header.frameCount = _fileStream->readUint16(); + _header.paletteDataSize = _fileStream->readUint16(); + _header.unkChunkDataSize = _fileStream->readUint16(); + _fileStream->skip(5); + _header.hasSound = _fileStream->readByte(); + _fileStream->skip(34); - return _surface; + // Some videos (e.g. robot 1305 in Phantasmagoria and + // robot 184 in Lighthouse) have an unknown chunk before + // the palette chunk (probably used for sound preloading). + // Skip it here. + if (_header.unkChunkDataSize) + _fileStream->skip(_header.unkChunkDataSize); } -void RobotDecoder::close() { - if (!_fileStream) - return; +void RobotDecoder::readFrameSizesChunk() { + // The robot video file contains 2 tables, with one entry for each frame: + // - A table containing the size of the image in each video frame + // - A table containing the total size of each video frame. + // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, + // they contain 32-bit integers. - delete _fileStream; - _fileStream = 0; + _frameTotalSize = new uint32[_header.frameCount]; + // TODO: The table reading code can probably be removed once the + // audio chunk size is figured out (check the TODO inside processNextFrame()) +#if 0 + // We don't need any of the two tables to play the video, so we ignore + // both of them. + uint16 wordSize = _header.version == 6 ? 4 : 2; + _fileStream->skip(_header.frameCount * wordSize * 2); +#else + switch (_header.version) { + case 4: + case 5: // sizes are 16-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 2); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint16(); + break; + case 6: // sizes are 32-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 4); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint32(); + break; + default: + error("Can't yet handle index table for robot version %d", _header.version); + } +#endif + + // 2 more unknown tables + _fileStream->skip(1024 + 512); + + // Pad to nearest 2 kilobytes + uint32 curPos = _fileStream->pos(); + if (curPos & 0x7ff) + _fileStream->seek((curPos & ~0x7ff) + 2048); +} + +RobotDecoder::RobotVideoTrack::RobotVideoTrack(int frameCount) : _frameCount(frameCount) { + _surface = new Graphics::Surface(); + _curFrame = -1; + _dirtyPalette = false; +} + +RobotDecoder::RobotVideoTrack::~RobotVideoTrack() { _surface->free(); delete _surface; - _surface = 0; +} - if (_header.hasSound) { - _mixer->stopHandle(_audioHandle); - //delete _audioStream; _audioStream = 0; +uint16 RobotDecoder::RobotVideoTrack::getWidth() const { + return _surface->w; +} + +uint16 RobotDecoder::RobotVideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat RobotDecoder::RobotVideoTrack::getPixelFormat() const { + return _surface->format; +} + +void RobotDecoder::RobotVideoTrack::readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize) { + byte *paletteData = new byte[chunkSize]; + stream->read(paletteData, chunkSize); + + // SCI1.1 palette + byte palFormat = paletteData[32]; + uint16 palColorStart = paletteData[25]; + uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); + + int palOffset = 37; + memset(_palette, 0, 256 * 3); + + for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + if (palFormat == kRobotPalVariable) + palOffset++; + _palette[colorNo * 3 + 0] = paletteData[palOffset++]; + _palette[colorNo * 3 + 1] = paletteData[palOffset++]; + _palette[colorNo * 3 + 2] = paletteData[palOffset++]; } - reset(); + _dirtyPalette = true; + delete[] paletteData; } -#endif +void RobotDecoder::RobotVideoTrack::calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes) { + // This is an O(n) operation, as each frame has a different size. + // We need to know the actual frame size to have a constant video size. + uint32 pos = stream->pos(); + + uint16 width = 0, height = 0; + + for (int curFrame = 0; curFrame < _frameCount; curFrame++) { + stream->skip(4); + uint16 frameWidth = stream->readUint16(); + uint16 frameHeight = stream->readUint16(); + if (frameWidth > width) + width = frameWidth; + if (frameHeight > height) + height = frameHeight; + stream->skip(frameSizes[curFrame] - 8); + } + + stream->seek(pos); + + _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); +} + +RobotDecoder::RobotAudioTrack::RobotAudioTrack() { + _audioStream = Audio::makeQueuingAudioStream(11025, false); +} + +RobotDecoder::RobotAudioTrack::~RobotAudioTrack() { + delete _audioStream; +} + +void RobotDecoder::RobotAudioTrack::queueBuffer(byte *buffer, int size) { + _audioStream->queueBuffer(buffer, size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); +} + +Audio::AudioStream *RobotDecoder::RobotAudioTrack::getAudioStream() const { + return _audioStream; +} } // End of namespace Sci diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h index 3f93582418..ebc3262939 100644 --- a/engines/sci/video/robot_decoder.h +++ b/engines/sci/video/robot_decoder.h @@ -25,79 +25,103 @@ #include "common/rational.h" #include "common/rect.h" -#include "common/stream.h" -#include "common/substream.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" #include "video/video_decoder.h" -namespace Sci { +namespace Audio { +class QueuingAudioStream; +} -#ifdef ENABLE_SCI32 - -struct RobotHeader { - // 6 bytes, identifier bytes - uint16 version; - uint16 audioChunkSize; - uint16 audioSilenceSize; - // 2 bytes, unknown - uint16 frameCount; - uint16 paletteDataSize; - uint16 unkChunkDataSize; - // 5 bytes, unknown - byte hasSound; - // 34 bytes, unknown -}; +namespace Common { +class SeekableSubReadStreamEndian; +} + +namespace Sci { -class RobotDecoder : public Video::FixedRateVideoDecoder { +class RobotDecoder : public Video::VideoDecoder { public: - RobotDecoder(Audio::Mixer *mixer, bool isBigEndian); + RobotDecoder(bool isBigEndian); virtual ~RobotDecoder(); bool loadStream(Common::SeekableReadStream *stream); bool load(GuiResourceId id); void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint32 getFrameCount() const { return _header.frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } + void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); } Common::Point getPos() const { return _pos; } protected: - Common::Rational getFrameRate() const { return Common::Rational(60, 10); } - + void readNextPacket(); + private: + class RobotVideoTrack : public FixedRateVideoTrack { + public: + RobotVideoTrack(int frameCount); + ~RobotVideoTrack(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _surface; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize); + void calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes); + Graphics::Surface *getSurface() { return _surface; } + void increaseCurFrame() { _curFrame++; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, 10); } + + private: + int _frameCount; + int _curFrame; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + }; + + class RobotAudioTrack : public AudioTrack { + public: + RobotAudioTrack(); + ~RobotAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kMusicSoundType; } + + void queueBuffer(byte *buffer, int size); + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::QueuingAudioStream *_audioStream; + }; + + struct RobotHeader { + // 6 bytes, identifier bytes + uint16 version; + uint16 audioChunkSize; + uint16 audioSilenceSize; + // 2 bytes, unknown + uint16 frameCount; + uint16 paletteDataSize; + uint16 unkChunkDataSize; + // 5 bytes, unknown + byte hasSound; + // 34 bytes, unknown + } _header; + void readHeaderChunk(); - void readPaletteChunk(uint16 chunkSize); void readFrameSizesChunk(); - void calculateVideoDimensions(); - - void freeData(); - RobotHeader _header; Common::Point _pos; bool _isBigEndian; + uint32 *_frameTotalSize; Common::SeekableSubReadStreamEndian *_fileStream; - - uint16 _width; - uint16 _height; - uint32 *_frameTotalSize; - byte _palette[256 * 3]; - bool _dirtyPalette; - Graphics::Surface *_surface; - Audio::QueuingAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - Audio::Mixer *_mixer; }; -#endif } // End of namespace Sci diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp index abd64911a7..a7b6346eca 100644 --- a/engines/sci/video/seq_decoder.cpp +++ b/engines/sci/video/seq_decoder.cpp @@ -41,33 +41,44 @@ enum seqFrameTypes { kSeqFrameDiff = 1 }; -SeqDecoder::SeqDecoder() { - _fileStream = 0; - _surface = 0; - _dirtyPalette = false; +SEQDecoder::SEQDecoder(uint frameDelay) : _frameDelay(frameDelay) { } -SeqDecoder::~SeqDecoder() { +SEQDecoder::~SEQDecoder() { close(); } -bool SeqDecoder::loadStream(Common::SeekableReadStream *stream) { +bool SEQDecoder::loadStream(Common::SeekableReadStream *stream) { close(); + addTrack(new SEQVideoTrack(stream, _frameDelay)); + + return true; +} + +SEQDecoder::SEQVideoTrack::SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay) { + assert(stream); + assert(frameDelay != 0); _fileStream = stream; + _frameDelay = frameDelay; + _curFrame = -1; + _surface = new Graphics::Surface(); _surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); _frameCount = _fileStream->readUint16LE(); - // Set palette - int paletteChunkSize = _fileStream->readUint32LE(); - readPaletteChunk(paletteChunkSize); + // Set initial palette + readPaletteChunk(_fileStream->readUint32LE()); +} - return true; +SEQDecoder::SEQVideoTrack::~SEQVideoTrack() { + delete _fileStream; + _surface->free(); + delete _surface; } -void SeqDecoder::readPaletteChunk(uint16 chunkSize) { +void SEQDecoder::SEQVideoTrack::readPaletteChunk(uint16 chunkSize) { byte *paletteData = new byte[chunkSize]; _fileStream->read(paletteData, chunkSize); @@ -91,23 +102,7 @@ void SeqDecoder::readPaletteChunk(uint16 chunkSize) { delete[] paletteData; } -void SeqDecoder::close() { - if (!_fileStream) - return; - - _frameDelay = 0; - - delete _fileStream; - _fileStream = 0; - - _surface->free(); - delete _surface; - _surface = 0; - - reset(); -} - -const Graphics::Surface *SeqDecoder::decodeNextFrame() { +const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() { int16 frameWidth = _fileStream->readUint16LE(); int16 frameHeight = _fileStream->readUint16LE(); int16 frameLeft = _fileStream->readUint16LE(); @@ -142,9 +137,6 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { delete[] buf; } - if (_curFrame == -1) - _startTime = g_system->getMillis(); - _curFrame++; return _surface; } @@ -159,7 +151,7 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { } \ memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n); -bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { +bool SEQDecoder::SEQVideoTrack::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { int writeRow = 0; int writeCol = left; int litPos = 0; @@ -237,4 +229,9 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS return true; } +const byte *SEQDecoder::SEQVideoTrack::getPalette() const { + _dirtyPalette = false; + return _palette; +} + } // End of namespace Sci diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index 800a3c9024..890f349feb 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -40,44 +40,49 @@ namespace Sci { /** * Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS */ -class SeqDecoder : public Video::FixedRateVideoDecoder { +class SEQDecoder : public Video::VideoDecoder { public: - SeqDecoder(); - virtual ~SeqDecoder(); + SEQDecoder(uint frameDelay); + virtual ~SEQDecoder(); bool loadStream(Common::SeekableReadStream *stream); - void close(); - - void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; } - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } - uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } - uint32 getFrameCount() const { return _frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - -protected: - Common::Rational getFrameRate() const { assert(_frameDelay); return Common::Rational(60, _frameDelay); } private: - enum { - SEQ_SCREEN_WIDTH = 320, - SEQ_SCREEN_HEIGHT = 200 + class SEQVideoTrack : public FixedRateVideoTrack { + public: + SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); + ~SEQVideoTrack(); + + uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } + uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } + Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const { return _dirtyPalette; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, _frameDelay); } + + private: + enum { + SEQ_SCREEN_WIDTH = 320, + SEQ_SCREEN_HEIGHT = 200 + }; + + void readPaletteChunk(uint16 chunkSize); + bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); + + Common::SeekableReadStream *_fileStream; + int _curFrame, _frameCount; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + uint _frameDelay; }; - void readPaletteChunk(uint16 chunkSize); - bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); - - uint16 _width, _height; - uint16 _frameDelay; - Common::SeekableReadStream *_fileStream; - byte _palette[256 * 3]; - bool _dirtyPalette; - uint32 _frameCount; - Graphics::Surface *_surface; + uint _frameDelay; }; } // End of namespace Sci diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 42f11498d9..88681898f5 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -121,13 +121,13 @@ void ScummEngine::updateCursor() { CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, _cursor.hotspotX, _cursor.hotspotY, (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), - (_game.heversion == 70 ? 2 : 1), + (_game.heversion == 70 ? true : false), &format); #else CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height, _cursor.hotspotX, _cursor.hotspotY, (_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor), - (_game.heversion == 70 ? 2 : 1)); + (_game.heversion == 70 ? true : false)); #endif } diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index b47982af00..5404c7f8b1 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "common/archive.h" @@ -156,6 +153,7 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { case kGenHEMac: case kGenHEMacNoParens: case kGenHEPC: + case kGenHEIOS: if (_game.heversion >= 98 && room >= 0) { int disk = 0; if (_heV7DiskOffsets) @@ -168,7 +166,11 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { break; case 1: id = 'a'; - result = Common::String::format("%s.(a)", _filenamePattern.pattern); + // Some of the newer HE games for iOS use the ".hea" suffix instead + if (_filenamePattern.genMethod == kGenHEIOS) + result = Common::String::format("%s.hea", _filenamePattern.pattern); + else + result = Common::String::format("%s.(a)", _filenamePattern.pattern); break; default: id = '0'; @@ -180,7 +182,7 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { id = (room == 0) ? '0' : '1'; } - if (_filenamePattern.genMethod == kGenHEPC) { + if (_filenamePattern.genMethod == kGenHEPC || _filenamePattern.genMethod == kGenHEIOS) { // For HE >= 98, we already called snprintf above. if (_game.heversion < 98 || room < 0) result = Common::String::format("%s.he%c", _filenamePattern.pattern, id); @@ -217,6 +219,7 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename break; case kGenHEPC: + case kGenHEIOS: result = Common::String::format("%s.he0", pattern); break; @@ -589,11 +592,11 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul file.c_str(), md5str.c_str(), filesize); // Sanity check: We *should* have found a matching gameid / variant at this point. - // If not, then there's a bug in our data tables... - assert(dr.game.gameid != 0); - - // Add it to the list of detected games - results.push_back(dr); + // If not, we may have #ifdef'ed the entry out in our detection_tables.h because we + // don't have the required stuff compiled in, or there's a bug in our data tables... + if (dr.game.gameid != 0) + // Add it to the list of detected games + results.push_back(dr); } } @@ -1060,19 +1063,31 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co // unknown MD5, or with a medium debug level in case of a known MD5 (for // debugging purposes). if (!findInMD5Table(res.md5.c_str())) { - printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n"); - printf("version (in particular, not a fan-made translation), please, report the\n"); - printf("following data to the ScummVM team along with name of the game you tried\n"); - printf("to add and its version/language/etc.:\n"); + Common::String md5Warning; - printf(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", + md5Warning = "Your game version appears to be unknown. If this is *NOT* a fan-modified\n"; + md5Warning += "version (in particular, not a fan-made translation), please, report the\n"; + md5Warning += "following data to the ScummVM team along with name of the game you tried\n"; + md5Warning += "to add and its version/language/etc.:\n"; + + md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", res.game.gameid, generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(), res.md5.c_str()); + + g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str()); } else { debug(1, "Using MD5 '%s'", res.md5.c_str()); } + // We don't support the "Lite" version off puttzoo iOS because it contains + // the full game. + if (!strcmp(res.game.gameid, "puttzoo") && !strcmp(res.extra, "Lite")) { + GUIErrorMessage("The Lite version of Putt-Putt Saves the Zoo iOS is not supported to avoid piracy.\n" + "The full version is available for purchase from the iTunes Store."); + return Common::kUnsupportedGameidError; + } + // If the GUI options were updated, we catch this here and update them in the users config // file transparently. Common::updateGameGUIOptions(res.game.guioptions, getGameGUIOptionsDescriptionLanguage(res.language)); @@ -1121,6 +1136,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co case 200: *engine = new ScummEngine_vCUPhe(syst, res); break; + case 101: case 100: *engine = new ScummEngine_v100he(syst, res); break; @@ -1251,7 +1267,6 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int Graphics::Surface *thumbnail = ScummEngine::loadThumbnailFromSlot(target, slot); SaveStateDescriptor desc(slot, saveDesc); - desc.setDeletableFlag(true); desc.setThumbnail(thumbnail); SaveStateMetaInfos infos; diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h index b6dfa757bb..5ed6b5aab0 100644 --- a/engines/scumm/detection.h +++ b/engines/scumm/detection.h @@ -99,6 +99,7 @@ enum FilenameGenMethod { kGenHEMac, kGenHEMacNoParens, kGenHEPC, + kGenHEIOS, kGenUnchanged }; diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index e1989d5274..be1b90e356 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -382,14 +382,16 @@ static const GameSettings gameVariantsTable[] = { {"pjgames", 0, 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Added the use of bink videos - {"Baseball2003", 0, 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, - {"basketball", 0, 0, GID_BASKETBALL, 6, 100, MDT_NONE, GF_USE_KEY| GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, - {"football2002", 0, 0, GID_FOOTBALL, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, {"Soccer2004", 0, 0, GID_SOCCER2004, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // U32 code required, for testing only {"moonbase", 0, 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, {"moonbase", "Demo", 0, GID_MOONBASE, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR | GF_DEMO, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + + // HE100 games, which use older o72_debugInput code + {"Baseball2003", 0, 0, GID_BASEBALL2003, 6, 101, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"basketball", 0, 0, GID_BASKETBALL, 6, 101, MDT_NONE, GF_USE_KEY| GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"football2002", 0, 0, GID_FOOTBALL2002, 6, 101, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, #endif // The following are meant to be generic HE game variants and as such do @@ -407,6 +409,7 @@ static const GameSettings gameVariantsTable[] = { {"", "HE 98.5", 0, GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, {"", "HE 99", 0, GID_HEGAME, 6, 99, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, {"", "HE 100", 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"", "HE 101", 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, #endif {NULL, NULL, 0, 0, 0, MDT_NONE, 0, 0, UNK, 0} }; @@ -704,7 +707,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "freddi4", "Freddi 4 Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "freddi4", "FreddiGS", kGenHEPC, Common::DE_DEU, UNK, 0 }, { "freddi4", "FreddiGS", kGenHEMac, Common::DE_DEU, Common::kPlatformMacintosh, 0 }, - { "freddi4", "FreddiHRBG", kGenHEPC, UNK_LANG, UNK, 0 }, + { "freddi4", "FreddiHRBG", kGenHEPC, Common::EN_GRB, UNK, 0 }, + { "freddi4", "FreddiHRBG", kGenHEMac, Common::EN_GRB, Common::kPlatformMacintosh, 0 }, { "freddi4", "FreddiMini", kGenHEPC, UNK_LANG, UNK, 0 }, { "freddi4", "Malice4", kGenHEMac, Common::FR_FRA, Common::kPlatformMacintosh, 0 }, { "freddi4", "MaliceMRC", kGenHEPC, Common::FR_FRA, UNK, 0 }, @@ -885,6 +889,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "spyfox", "Spy Fox", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 }, { "spyfox", "Spy Fox Demo", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 }, { "spyfox", "JR-Demo", kGenHEMac, Common::FR_FRA, Common::kPlatformMacintosh, 0 }, + { "spyfox", "game", kGenHEIOS, Common::EN_ANY, Common::kPlatformIOS, 0 }, { "spyfox2", "spyfox2", kGenHEPC, UNK_LANG, UNK, 0 }, { "spyfox2", "sf2-demo", kGenHEPC, UNK_LANG, UNK, 0 }, diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 2cf4a429db..ffff329036 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -755,7 +755,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i memset(blackbuf, 0, 16 * 240); // Prepare a buffer 16px wide and 240px high, to fit on a lateral strip width = 240; // Fix right strip - _system->copyRectToScreen((const byte *)blackbuf, 16, 0, 0, 16, 240); // Fix left strip + _system->copyRectToScreen(blackbuf, 16, 0, 0, 16, 240); // Fix left strip } } @@ -763,7 +763,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i } // Finally blit the whole thing to the screen - _system->copyRectToScreen((const byte *)src, pitch, x, y, width, height); + _system->copyRectToScreen(src, pitch, x, y, width, height); } // CGA diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 40e99c26a8..be17a3b305 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -40,7 +40,7 @@ MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) { _video = new Video::BinkDecoder(); else #endif - _video = new Video::SmackerDecoder(mixer); + _video = new Video::SmackerDecoder(); _flags = 0; _wizResNum = 0; @@ -61,11 +61,16 @@ int MoviePlayer::load(const char *filename, int flags, int image) { if (_video->isVideoLoaded()) _video->close(); + // Ensure that Bink will use our PixelFormat + _video->setDefaultHighColorFormat(g_system->getScreenFormat()); + if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename); return -1; } + _video->start(); + debug(1, "Playing video %s", filename); if (flags & 2) diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index cdc5faa084..fc5e4bcdf0 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -187,6 +187,8 @@ public: Wiz *_wiz; + virtual int setupStringArray(int size); + protected: virtual void setupOpcodes(); @@ -201,7 +203,6 @@ protected: virtual void clearDrawQueues(); int getStringCharWidth(byte chr); - virtual int setupStringArray(int size); void appendSubstring(int dst, int src, int len2, int len); void adjustRect(Common::Rect &rect); @@ -258,6 +259,9 @@ public: virtual void resetScumm(); + virtual byte *getStringAddress(ResId idx); + virtual int setupStringArray(int size); + protected: virtual void setupOpcodes(); @@ -265,7 +269,6 @@ protected: virtual void resetScummVars(); virtual void readArrayFromIndexFile(); - virtual byte *getStringAddress(ResId idx); virtual void readMAXS(int blockSize); virtual void redrawBGAreas(); @@ -280,7 +283,6 @@ protected: void copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end, int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end); void copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num); - virtual int setupStringArray(int size); int readFileToArray(int slot, int32 size); void writeFileFromArray(int slot, int32 resID); diff --git a/engines/scumm/he/logic/football.cpp b/engines/scumm/he/logic/football.cpp index f86f97eaf7..b405d634a4 100644 --- a/engines/scumm/he/logic/football.cpp +++ b/engines/scumm/he/logic/football.cpp @@ -20,6 +20,8 @@ * */ +#include "common/savefile.h" + #include "scumm/he/intern_he.h" #include "scumm/he/logic_he.h" @@ -35,16 +37,16 @@ public: LogicHEfootball(ScummEngine_v90he *vm) : LogicHE(vm) {} int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int op_1004(int32 *args); - int op_1006(int32 *args); - int op_1007(int32 *args); - int op_1010(int32 *args); - int op_1022(int32 *args); - int op_1023(int32 *args); - int op_1024(int32 *args); + virtual int32 dispatch(int op, int numArgs, int32 *args); + +protected: + int lineEquation3D(int32 *args); + virtual int translateWorldToScreen(int32 *args); + int fieldGoalScreenTranslation(int32 *args); + virtual int translateScreenToWorld(int32 *args); + int nextPoint(int32 *args); + int computePlayerBallIntercepts(int32 *args); + int computeTwoCircleIntercepts(int32 *args); }; int LogicHEfootball::versionID() { @@ -56,31 +58,31 @@ int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { switch (op) { case 1004: - res = op_1004(args); + res = lineEquation3D(args); break; case 1006: - res = op_1006(args); + res = translateWorldToScreen(args); break; case 1007: - res = op_1007(args); + res = fieldGoalScreenTranslation(args); break; case 1010: - res = op_1010(args); + res = translateScreenToWorld(args); break; case 1022: - res = op_1022(args); + res = nextPoint(args); break; case 1023: - res = op_1023(args); + res = computePlayerBallIntercepts(args); break; case 1024: - res = op_1024(args); + res = computeTwoCircleIntercepts(args); break; case 8221968: @@ -123,8 +125,8 @@ int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { return res; } -int LogicHEfootball::op_1004(int32 *args) { - // Identical to LogicHEsoccer::op_1004 +int LogicHEfootball::lineEquation3D(int32 *args) { + // Identical to soccer's 1004 opcode double res, a2, a4, a5; a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); @@ -141,8 +143,8 @@ int LogicHEfootball::op_1004(int32 *args) { return 1; } -int LogicHEfootball::op_1006(int32 *args) { - // This seems to be more or less the inverse of op_1010 +int LogicHEfootball::translateWorldToScreen(int32 *args) { + // This is more or less the inverse of translateScreenToWorld const double a1 = args[1]; double res; @@ -167,7 +169,7 @@ int LogicHEfootball::op_1006(int32 *args) { return 1; } -int LogicHEfootball::op_1007(int32 *args) { +int LogicHEfootball::fieldGoalScreenTranslation(int32 *args) { double res, temp; temp = (double)args[1] * 0.32; @@ -188,8 +190,8 @@ int LogicHEfootball::op_1007(int32 *args) { return 1; } -int LogicHEfootball::op_1010(int32 *args) { - // This seems to be more or less the inverse of op_1006 +int LogicHEfootball::translateScreenToWorld(int32 *args) { + // This is more or less the inverse of translateWorldToScreen double a1 = (640.0 - (double)args[1] - 26.0) / 1.1588235e-1; // 2.9411764e-4 = 1/3400 @@ -205,7 +207,7 @@ int LogicHEfootball::op_1010(int32 *args) { return 1; } -int LogicHEfootball::op_1022(int32 *args) { +int LogicHEfootball::nextPoint(int32 *args) { double res; double var10 = args[4] - args[1]; double var8 = args[5] - args[2]; @@ -226,7 +228,7 @@ int LogicHEfootball::op_1022(int32 *args) { return 1; } -int LogicHEfootball::op_1023(int32 *args) { +int LogicHEfootball::computePlayerBallIntercepts(int32 *args) { double var10, var18, var20, var28, var30, var30_; double argf[7]; @@ -272,7 +274,8 @@ int LogicHEfootball::op_1023(int32 *args) { return 1; } -int LogicHEfootball::op_1024(int32 *args) { +int LogicHEfootball::computeTwoCircleIntercepts(int32 *args) { + // Looks like this was just dummied out writeScummVar(108, 0); writeScummVar(109, 0); writeScummVar(110, 0); @@ -281,8 +284,125 @@ int LogicHEfootball::op_1024(int32 *args) { return 1; } +class LogicHEfootball2002 : public LogicHEfootball { +public: + LogicHEfootball2002(ScummEngine_v90he *vm) : LogicHEfootball(vm) {} + + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int translateWorldToScreen(int32 *args); + int translateScreenToWorld(int32 *args); + int getDayOfWeek(); + int initScreenTranslations(); + int getPlaybookFiles(int32 *args); + int largestFreeBlock(); +}; + +int32 LogicHEfootball2002::dispatch(int op, int numArgs, int32 *args) { + int32 res = 0; + + switch (op) { + case 1025: + res = getDayOfWeek(); + break; + + case 1026: + res = initScreenTranslations(); + break; + + case 1027: + res = getPlaybookFiles(args); + break; + + case 1028: + res = largestFreeBlock(); + break; + + case 1029: + // Clean-up off heap + // Dummied in the Windows U32 + res = 1; + break; + + case 1516: + // Start auto LAN game + break; + + default: + res = LogicHEfootball::dispatch(op, numArgs, args); + break; + } + + return res; +} + +int LogicHEfootball2002::translateWorldToScreen(int32 *args) { + // TODO: Implement modified 2002 version + return LogicHEfootball::translateWorldToScreen(args); +} + +int LogicHEfootball2002::translateScreenToWorld(int32 *args) { + // TODO: Implement modified 2002 version + return LogicHEfootball::translateScreenToWorld(args); +} + +int LogicHEfootball2002::getDayOfWeek() { + // Get day of week, store in var 108 + + TimeDate time; + _vm->_system->getTimeAndDate(time); + writeScummVar(108, time.tm_wday); + + return 1; +} + +int LogicHEfootball2002::initScreenTranslations() { + // TODO: Set values used by translateWorldToScreen/translateScreenToWorld + return 1; +} + +int LogicHEfootball2002::getPlaybookFiles(int32 *args) { + // Get the pattern and then skip over the directory prefix ("*\" or "*:") + Common::String pattern = (const char *)_vm->getStringAddress(args[0] & ~0x33539000) + 2; + + // Prepare a buffer to hold the file names + char buffer[1000]; + buffer[0] = 0; + + // Get the list of file names that match the pattern and iterate over it + Common::StringArray fileList = _vm->getSaveFileManager()->listSavefiles(pattern); + + for (uint32 i = 0; i < fileList.size() && strlen(buffer) < 970; i++) { + // Isolate the base part of the filename and concatenate it to our buffer + Common::String fileName = Common::String(fileList[i].c_str(), fileList[i].size() - (pattern.size() - 1)); + strcat(buffer, fileName.c_str()); + strcat(buffer, ">"); // names separated by '>' + } + + // Now store the result in an array + int array = _vm->setupStringArray(strlen(buffer)); + strcpy((char *)_vm->getStringAddress(array), buffer); + + // And store the array index in variable 108 + writeScummVar(108, array); + + return 1; +} + +int LogicHEfootball2002::largestFreeBlock() { + // The Windows version always sets the variable to this + // The Mac version actually checks for the largest free block + writeScummVar(108, 100000000); + return 1; +} + LogicHE *makeLogicHEfootball(ScummEngine_v90he *vm) { return new LogicHEfootball(vm); } +LogicHE *makeLogicHEfootball2002(ScummEngine_v90he *vm) { + return new LogicHEfootball2002(vm); +} + } // End of namespace Scumm diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp index a76c393e13..0f9454ba28 100644 --- a/engines/scumm/he/logic_he.cpp +++ b/engines/scumm/he/logic_he.cpp @@ -87,6 +87,9 @@ LogicHE *LogicHE::makeLogicHE(ScummEngine_v90he *vm) { case GID_FOOTBALL: return makeLogicHEfootball(vm); + case GID_FOOTBALL2002: + return makeLogicHEfootball2002(vm); + case GID_SOCCER: case GID_SOCCERMLS: case GID_SOCCER2004: diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h index 893dc81b87..93c0569a4f 100644 --- a/engines/scumm/he/logic_he.h +++ b/engines/scumm/he/logic_he.h @@ -61,6 +61,7 @@ protected: LogicHE *makeLogicHErace(ScummEngine_v90he *vm); LogicHE *makeLogicHEfunshop(ScummEngine_v90he *vm); LogicHE *makeLogicHEfootball(ScummEngine_v90he *vm); +LogicHE *makeLogicHEfootball2002(ScummEngine_v90he *vm); LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm); LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm); LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm); diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 42748d08ed..ce4b2239d2 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -129,7 +129,7 @@ bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) { if (!group) return false; - Graphics::WinCursor *cursor = group->cursors[0].cursor; + Graphics::Cursor *cursor = group->cursors[0].cursor; cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()]; cc->width = cursor->getWidth(); diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index 56ea10f507..a2eb42214b 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -876,6 +876,7 @@ void ScummEngine_v100he::o100_floodFill() { _floodFillParams.box.top = 0; _floodFillParams.box.right = 639; _floodFillParams.box.bottom = 479; + adjustRect(_floodFillParams.box); break; case 6: _floodFillParams.y = pop(); @@ -886,6 +887,7 @@ void ScummEngine_v100he::o100_floodFill() { _floodFillParams.box.right = pop(); _floodFillParams.box.top = pop(); _floodFillParams.box.left = pop(); + adjustRect(_floodFillParams.box); break; case 20: _floodFillParams.flags = pop(); @@ -1345,6 +1347,7 @@ void ScummEngine_v100he::o100_wizImageOps() { _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); + adjustRect(_wizParams.box2); break; case 135: _wizParams.processFlags |= kWPFDstResNum; @@ -1358,6 +1361,7 @@ void ScummEngine_v100he::o100_wizImageOps() { _wizParams.box2.right = pop(); _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); + adjustRect(_wizParams.box2); break; case 137: _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; @@ -1365,6 +1369,7 @@ void ScummEngine_v100he::o100_wizImageOps() { _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); + adjustRect(_wizParams.box2); break; case 138: _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; @@ -1374,6 +1379,7 @@ void ScummEngine_v100he::o100_wizImageOps() { _wizParams.box2.right = pop(); _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); + adjustRect(_wizParams.box2); break; default: error("o100_wizImageOps: Unknown case %d", subOp); @@ -2339,6 +2345,13 @@ void ScummEngine_v100he::o100_writeFile() { } void ScummEngine_v100he::o100_debugInput() { + // Backyard Baseball 2003 / Basketball / Football 2002 + // use older o72_debugInput code + if (_game.heversion == 101) { + ScummEngine_v72he::o72_debugInput(); + return; + } + byte subOp = fetchScriptByte(); switch (subOp) { diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index dbeee567bf..5e359385b6 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -124,8 +124,6 @@ int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { } else if (dst[0] == '.' && dst[1] == '/') { // Game Data Path // The default game data path is set to './' by ScummVM r = 2; - } else if (dst[2] == 'b' && dst[5] == 'k') { // Backyard Basketball INI - r = 13; } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (Windows HE72 - HE100) // The default save game path is set to '*/' by ScummVM r = 2; diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index 0beebdb7a1..1ea9960a18 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -244,6 +244,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.box2.right = pop(); _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); + adjustRect(_wizParams.box2); break; case 134: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; @@ -253,6 +254,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.box2.right = pop(); _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); + adjustRect(_wizParams.box2); break; case 135: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; @@ -260,6 +262,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); + adjustRect(_wizParams.box2); break; case 136: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; @@ -267,6 +270,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); + adjustRect(_wizParams.box2); break; case 137: // HE99+ _wizParams.processFlags |= kWPFDstResNum; @@ -1488,6 +1492,7 @@ void ScummEngine_v90he::o90_floodFill() { _floodFillParams.box.top = 0; _floodFillParams.box.right = 639; _floodFillParams.box.bottom = 479; + adjustRect(_floodFillParams.box); break; case 65: _floodFillParams.y = pop(); @@ -1501,6 +1506,7 @@ void ScummEngine_v90he::o90_floodFill() { _floodFillParams.box.right = pop(); _floodFillParams.box.top = pop(); _floodFillParams.box.left = pop(); + adjustRect(_floodFillParams.box); break; case 255: floodFill(&_floodFillParams, this); @@ -1666,7 +1672,7 @@ void ScummEngine_v90he::o90_getPolygonOverlap() { { Common::Rect r2; _sprite->getSpriteBounds(args2[0], false, r2); - Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); + Common::Rect r1(args1[0], args1[1], args1[2] + 1, args1[3] + 1); if (r2.isValidRect() == false) { push(0); break; @@ -1711,7 +1717,7 @@ void ScummEngine_v90he::o90_getPolygonOverlap() { { Common::Rect r2; _sprite->getSpriteBounds(args2[0], true, r2); - Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); + Common::Rect r1(args1[0], args1[1], args1[2] + 1, args1[3] + 1); if (r2.isValidRect() == false) { push(0); break; @@ -2373,8 +2379,8 @@ void ScummEngine_v90he::o90_kernelSetFunctions() { case 2001: _logicHE->dispatch(args[1], num - 2, (int32 *)&args[2]); break; - case 201102: - // Used in puttzoo iOS + case 201102: // Used in puttzoo iOS + case 20111014: // Used in spyfox iOS break; default: error("o90_kernelSetFunctions: default case %d (param count %d)", args[0], num); diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp index 1007d2a7b0..f94b74ac45 100644 --- a/engines/scumm/he/sound_he.cpp +++ b/engines/scumm/he/sound_he.cpp @@ -65,7 +65,7 @@ void SoundHE::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlag if (_vm->VAR_LAST_SOUND != 0xFF) _vm->VAR(_vm->VAR_LAST_SOUND) = sound; - if ((_vm->_game.heversion <= 99 && (heFlags & 16)) || (_vm->_game.heversion == 100 && (heFlags & 8))) { + if ((_vm->_game.heversion <= 99 && (heFlags & 16)) || (_vm->_game.heversion >= 100 && (heFlags & 8))) { playHESound(sound, heOffset, heChannel, heFlags); return; } else { diff --git a/engines/scumm/insane/insane_scenes.cpp b/engines/scumm/insane/insane_scenes.cpp index 6db1cb5059..db0b0171bc 100644 --- a/engines/scumm/insane/insane_scenes.cpp +++ b/engines/scumm/insane/insane_scenes.cpp @@ -1386,7 +1386,7 @@ void Insane::postCase12(byte *renderBitmap, int32 codecparam, int32 setupsan12, break; case EN_TORQUE: turnBen(false); - if (_actor[1].y != 300) + if (_actor[1].y == 300) prepareScenePropScene(57, 1, 0); break; default: diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 39420ee974..d8c4948ea8 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -250,7 +250,7 @@ void ScummEngine::stopScript(int script) { if (vm.nest[i].number == script && (vm.nest[i].where == WIO_GLOBAL || vm.nest[i].where == WIO_LOCAL)) { nukeArrays(vm.nest[i].slot); - vm.nest[i].number = 0xFF; + vm.nest[i].number = 0; vm.nest[i].slot = 0xFF; vm.nest[i].where = 0xFF; } @@ -284,7 +284,7 @@ void ScummEngine::stopObjectScript(int script) { if (vm.nest[i].number == script && (vm.nest[i].where == WIO_ROOM || vm.nest[i].where == WIO_INVENTORY || vm.nest[i].where == WIO_FLOBJECT)) { nukeArrays(vm.nest[i].slot); - vm.nest[i].number = 0xFF; + vm.nest[i].number = 0; vm.nest[i].slot = 0xFF; vm.nest[i].where = 0xFF; } @@ -318,7 +318,7 @@ void ScummEngine::runScriptNested(int script) { nest = &vm.nest[vm.numNestedScripts]; if (_currentScript == 0xFF) { - nest->number = 0xFF; + nest->number = 0; nest->where = 0xFF; } else { // Store information about the currently running script @@ -338,7 +338,7 @@ void ScummEngine::runScriptNested(int script) { if (vm.numNestedScripts != 0) vm.numNestedScripts--; - if (nest->number != 0xFF) { + if (nest->number) { // Try to resume the script which called us, if its status has not changed // since it invoked us. In particular, we only resume it if it hasn't been // stopped in the meantime, and if it did not already move on. diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 3957c7c42d..d4eefe8c28 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Tue Apr 24 03:50:58 2012 + This file was generated by the md5table tool on Sat Jul 07 23:39:27 2012 DO NOT EDIT MANUALLY! */ @@ -73,6 +73,7 @@ static const MD5Table md5table[] = { { "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "15240c59d3681ed53f714f8d925cb2d6", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformAtariST }, { "157367c3c21e0d03a0cba44361b4cf65", "indy3", "No AdLib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, + { "15878e3bee2e1e759184abee98589eaa", "spyfox", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformIOS }, { "15e03ffbfeddb9c2aebc13dcb2a4a8f4", "monkey", "VGA", "VGA", 8357, Common::EN_ANY, Common::kPlatformPC }, { "15f588e887e857e8c56fe6ade4956168", "atlantis", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "16542a7342a918bfe4ba512007d36c47", "FreddisFunShop", "HE 99L", "", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -173,7 +174,7 @@ static const MD5Table md5table[] = { { "3ae7f002d9256b8bdf76aaf8a3a069f8", "freddi", "HE 100", "", 34837, Common::EN_GRB, Common::kPlatformWii }, { "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HE_ISR, Common::kPlatformWindows }, { "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, - { "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, + { "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformUnknown }, { "3c4c471342bd95505a42334367d8f127", "puttmoon", "HE 70", "", 12161, Common::RU_RUS, Common::kPlatformWindows }, { "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformPC }, { "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, @@ -190,6 +191,7 @@ static const MD5Table md5table[] = { { "45082a5c9f42ba14dacfe1fdeeba819d", "freddicove", "HE 100", "Demo", 18422, Common::EN_ANY, Common::kPlatformUnknown }, { "45152f7cf2ba8f43cf8a8ea2e740ae09", "monkey", "VGA", "VGA", 8357, Common::ES_ESP, Common::kPlatformPC }, { "4521138d15d1fd7649c31fb981746231", "pajama2", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, + { "4522564b3c31aaf218b6a96826a549fd", "maze", "HE 99", "", -1, Common::EN_USA, Common::kPlatformWindows }, { "46b53fd430adcfbed791b48a0d4b079f", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, { "470c45b636139bb40716daa1c7edaad0", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC }, { "477dbafbd66a53c98416dc01aef019ad", "monkey", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC }, @@ -214,6 +216,7 @@ static const MD5Table md5table[] = { { "4dbff3787aedcd96b0b325f2d92d7ad9", "maze", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4dc780f1bc587a193ce8a97652791438", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "4e5867848ee61bc30d157e2c94eee9b4", "PuttTime", "HE 90", "Demo", 18394, Common::EN_USA, Common::kPlatformUnknown }, + { "4e859d3ef1e146b41e7d93c35cd6cc62", "puttzoo", "HE 100", "Lite", -1, Common::EN_ANY, Common::kPlatformIOS }, { "4edbf9d03550f7ba01e7f34d69b678dd", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, @@ -225,7 +228,7 @@ static const MD5Table md5table[] = { { "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, { "5057fb0e99e5aa29df1836329232f101", "freddi2", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows }, - { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, + { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii }, { "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "513f91a9dbe8d5490b39e56a3ac5bbdf", "pajama2", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -332,7 +335,7 @@ static const MD5Table md5table[] = { { "7766c9487f9d53a8cb0edabda5119c3d", "puttputt", "HE 60", "", 8022, Common::EN_ANY, Common::kPlatformPC }, { "77f5c9cc0986eb729c1a6b4c8823bbae", "zakloom", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "780e4a0ae2ff17dc296f4a79543b44f8", "puttmoon", "", "", -1, Common::UNK_LANG, Common::kPlatformPC }, - { "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 101", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "784b499c98d07260a30952685758636b", "pajama3", "", "Demo", 13911, Common::DE_DEU, Common::kPlatformWindows }, { "78bd5f036ea35a878b74e4f47941f784", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, @@ -492,7 +495,7 @@ static const MD5Table md5table[] = { { "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD }, { "c20848f53c2d48bfacdc840993843765", "freddi2", "HE 80", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, - { "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, + { "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii }, { "c24c490373aeb48fbd54caa8e7ae376d", "loom", "No AdLib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "c25755b08a8d0d47695e05f1e2111bfc", "freddi4", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "c30ef068add4277104243c31ce46c12b", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformAmiga }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index fc46f88df4..d0f46f3e56 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -1917,6 +1917,13 @@ void ScummEngine::syncSoundSettings() { if (VAR_CHARINC != 0xFF) VAR(VAR_CHARINC) = _defaultTalkDelay; } + + // Backyard Baseball 2003 uses a unique subtitle variable, + // rather than VAR_SUBTITLES + if (_game.id == GID_BASEBALL2003) { + _scummVars[632] = ConfMan.getBool("subtitles"); + } + } void ScummEngine::setTalkSpeed(int talkspeed) { diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index cacf8c214e..c8cf096a19 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -241,10 +241,12 @@ enum ScummGameId { GID_PUTTRACE, GID_FUNSHOP, // Used for all three funshops GID_FOOTBALL, + GID_FOOTBALL2002, GID_SOCCER, GID_SOCCERMLS, GID_SOCCER2004, GID_BASEBALL2001, + GID_BASEBALL2003, GID_BASKETBALL, GID_MOONBASE, GID_HECUP // CUP demos diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 1e2964054a..f7add4eed2 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -37,6 +37,7 @@ #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/psx_decoder.h" #include "video/smk_decoder.h" @@ -96,9 +97,8 @@ static const char *const sequenceListPSX[20] = { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _textMan(textMan), _resMan(resMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _textMan(textMan), _resMan(resMan), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -107,7 +107,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio:: } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -116,16 +115,12 @@ MoviePlayer::~MoviePlayer() { * @param id the id of the file */ bool MoviePlayer::load(uint32 id) { - Common::File f; Common::String filename; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]); - else - _bgSoundStream = NULL; - if (SwordEngine::_systemVars.showText) { + Common::File f; filename = Common::String::format("%s.txt", sequenceList[id]); + if (f.open(filename)) { Common::String line; int lineNo = 0; @@ -169,7 +164,6 @@ bool MoviePlayer::load(uint32 id) { _movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color)); lastEnd = endFrame; } - f.close(); } } @@ -189,6 +183,7 @@ bool MoviePlayer::load(uint32 id) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + _decoder->start(); return true; } else { initGraphics(g_system->getWidth(), g_system->getHeight(), true); @@ -197,30 +192,27 @@ bool MoviePlayer::load(uint32 id) { break; } - return _decoder->loadFile(filename.c_str()); -} + if (!_decoder->loadFile(filename)) + return false; -void MoviePlayer::play() { - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + _decoder->addStreamFileTrack(sequenceList[id]); - bool terminated = false; + _decoder->start(); + return true; +} +void MoviePlayer::play() { _textX = 0; _textY = 0; - terminated = !playVideo(); - - if (terminated) - _snd->stopHandle(*_bgSoundHandle); + playVideo(); _textMan->releaseText(2, false); _movieTexts.clear(); - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - // It's tempting to call _screen->fullRefresh() here to restore the old // palette. However, that causes glitches with DXA movies, where the // previous location would be momentarily drawn, before switching to @@ -316,11 +308,11 @@ bool MoviePlayer::playVideo() { if (_decoderType == kVideoDecoderPSX) drawFramePSX(frame); else - _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); if (!_movieTexts.empty()) { // Look for the best color indexes to use to display the subtitles @@ -501,29 +493,17 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { uint16 x = (g_system->getWidth() - scaledFrame.w) / 2; uint16 y = (g_system->getHeight() - scaledFrame.h) / 2; - _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); + _vm->_system->copyRectToScreen(scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getElapsedTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getElapsedTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system) { +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; // For the PSX version, we'll try the PlayStation stream files if (vm->isPsx()) { @@ -534,7 +514,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * #ifdef USE_RGB_COLOR // All BS1 PSX videos run the videos at 2x speed Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, textMan, resMan, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK")); dialog.runModal(); @@ -546,20 +526,20 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * filename = Common::String::format("%s.smk", sequenceList[id]); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); + return new MoviePlayer(vm, textMan, resMan, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", sequenceList[id]); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::VideoDecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); - return NULL; + return 0; #endif } @@ -569,7 +549,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * if (Common::File::exists(filename)) { GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK")); dialog.runModal(); - return NULL; + return 0; } if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) { @@ -578,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * dialog.runModal(); } - return NULL; + return 0; } } // End of namespace Sword1 diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index f64b03dd1b..d0c61f5eb3 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -23,16 +23,19 @@ #ifndef SWORD1_ANIMATION_H #define SWORD1_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" - #include "common/list.h" -#include "audio/audiostream.h" - #include "sword1/screen.h" #include "sword1/sound.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword1 { enum DecoderType { @@ -55,21 +58,9 @@ public: } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getElapsedTime() const; - -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(uint32 id); void play(); @@ -78,7 +69,6 @@ protected: SwordEngine *_vm; Text *_textMan; ResMan *_resMan; - Audio::Mixer *_snd; OSystem *_system; Common::List<MovieText> _movieTexts; int _textX, _textY, _textWidth, _textHeight; @@ -88,8 +78,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; bool playVideo(); void performPostProcessing(byte *screen); @@ -100,7 +88,7 @@ protected: void convertColor(byte r, byte g, byte b, float &h, float &s, float &v); }; -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system); +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system); } // End of namespace Sword1 diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp index 087dcd09d8..5662e4672b 100644 --- a/engines/sword1/detection.cpp +++ b/engines/sword1/detection.cpp @@ -268,9 +268,6 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int SaveStateDescriptor desc(slot, name); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - if (versionSave < 2) // These older version of the savegames used a flag to signal presence of thumbnail in->skip(1); diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 8e04861edf..757d768780 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -959,7 +959,7 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3 // meantime, we don't want any looping sound effects still playing. _sound->quitScreen(); - MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _mixer, _system); + MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _system); if (player) { _screen->clearScreen(); if (player->load(sequenceId)) diff --git a/engines/sword1/objectman.cpp b/engines/sword1/objectman.cpp index ed994a97fa..5d1864d58d 100644 --- a/engines/sword1/objectman.cpp +++ b/engines/sword1/objectman.cpp @@ -99,13 +99,64 @@ uint8 ObjectMan::fnCheckForTextLine(uint32 textId) { char *ObjectMan::lockText(uint32 textId) { uint8 lang = SwordEngine::_systemVars.language; + char *text = lockText(textId, lang); + if (text == 0) { + if (lang != BS1_ENGLISH) { + text = lockText(textId, BS1_ENGLISH); + if (text != 0) + warning("Missing translation for textId %u (\"%s\")", textId, text); + unlockText(textId, BS1_ENGLISH); + } + + return _missingSubTitleStr; + } + return text; +} + +char *ObjectMan::lockText(uint32 textId, uint8 lang) { char *addr = (char *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]); if (addr == 0) - return _missingSubTitleStr; + return NULL; addr += sizeof(Header); if ((textId & ITM_ID) >= _resMan->readUint32(addr)) { + // Workaround for missing sentences in some langages in the demo. + switch(textId) { + case 8455194: + return const_cast<char *>(_translationId8455194[lang]); + case 8455195: + return const_cast<char *>(_translationId8455195[lang]); + case 8455196: + return const_cast<char *>(_translationId8455196[lang]); + case 8455197: + return const_cast<char *>(_translationId8455197[lang]); + case 8455198: + return const_cast<char *>(_translationId8455198[lang]); + case 8455199: + return const_cast<char *>(_translationId8455199[lang]); + case 8455200: + return const_cast<char *>(_translationId8455200[lang]); + case 8455201: + return const_cast<char *>(_translationId8455201[lang]); + case 8455202: + return const_cast<char *>(_translationId8455202[lang]); + case 8455203: + return const_cast<char *>(_translationId8455203[lang]); + case 8455204: + return const_cast<char *>(_translationId8455204[lang]); + case 8455205: + return const_cast<char *>(_translationId8455205[lang]); + case 6488080: + return const_cast<char *>(_translationId6488080[lang]); + case 6488081: + return const_cast<char *>(_translationId6488081[lang]); + case 6488082: + return const_cast<char *>(_translationId6488082[lang]); + case 6488083: + return const_cast<char *>(_translationId6488083[lang]); + } + warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, _resMan->readUint32(addr)); - textId = 0; // get first line instead + return NULL; } uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4); if (offset == 0) { @@ -113,15 +164,19 @@ char *ObjectMan::lockText(uint32 textId) { // We use the hardcoded text in this case. if (textId == 2950145) return const_cast<char *>(_translationId2950145[lang]); - + warning("ObjectMan::lockText(%d): text number has no text lines", textId); - return _missingSubTitleStr; + return NULL; } return addr + offset; } void ObjectMan::unlockText(uint32 textId) { - _resMan->resClose(_textList[textId / ITM_PER_SEC][SwordEngine::_systemVars.language]); + unlockText(textId, SwordEngine::_systemVars.language); +} + +void ObjectMan::unlockText(uint32 textId, uint8 lang) { + _resMan->resClose(_textList[textId / ITM_PER_SEC][lang]); } uint32 ObjectMan::lastTextNumber(int section) { @@ -186,7 +241,193 @@ const char *const ObjectMan::_translationId2950145[7] = { "Eh?", // Italian "\277Eh?", // Spanish "Ano?", // Czech - " " // Portuguese + NULL // Portuguese +}; + +// The translations for the next texts are missing in the demo but are present +// in the full game. The translations were therefore extracted from the full game. + +// Missing translation for textId 8455194 (in the demo). +const char *const ObjectMan::_translationId8455194[7] = { + NULL, // "Who was the guy you were supposed to meet?", // English (not needed) + "Qui \351tait l'homme que vous deviez rencontrer?", // French + "Wer war der Typ, den Du treffen wolltest?", // German + "Chi dovevi incontrare?", // Italian + "\277Qui\351n era el hombre con el que ten\355as que encontrarte?", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455195 (in the demo). +const char *const ObjectMan::_translationId8455195[7] = { + NULL, // "His name was Plantard. I didn't know him, but he called me last night.", // English (not needed) + "Son nom \351tait Plantard. Je ne le connaissais pas, mais il m'avait t\351l\351phon\351 la veille.", // French + "Sein Name war Plantard. Ich kannte ihn nicht, aber er hat mich letzte Nacht angerufen.", // German + "Si chiamava Plantard. Mi ha chiamato ieri sera, ma non lo conoscevo.", // Italian + "Su nombre era Plantard. Yo no lo conoc\355a pero \351l me llam\363 ayer por la noche.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455196 (in the demo). +const char *const ObjectMan::_translationId8455196[7] = { + NULL, // "He said he had a story which would interest me.", // English (not needed) + "Il a dit qu'il avait une histoire qui devrait m'int\351resser.", // French + "Er sagte, er h\344tte eine Story, die mich interessieren w\374rde.", // German + "Mi disse che aveva una storia che mi poteva interessare.", // Italian + "Dijo que ten\355a una historia que me interesar\355a.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455197 (in the demo). +const char *const ObjectMan::_translationId8455197[7] = { + NULL, // "He asked me to meet him at the caf\351.", // English (not needed) + "Il m'a demand\351 de le rencontrer au caf\351.", // French + "Er fragte mich, ob wir uns im Caf\351 treffen k\366nnten.", // German + "Mi chiese di incontrarci al bar.", // Italian + "Me pidi\363 que nos encontr\341ramos en el caf\351.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455198 (in the demo). +const char *const ObjectMan::_translationId8455198[7] = { + NULL, // "I guess I'll never know what he wanted to tell me...", // English (not needed) + "Je suppose que je ne saurai jamais ce qu'il voulait me dire...", // French + "Ich werde wohl nie erfahren, was er mir sagen wollte...", // German + "Penso che non sapr\362 mai che cosa voleva dirmi...", // Italian + "Supongo que nunca sabr\351 qu\351 me quer\355a contar...", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455199 (in the demo). +const char *const ObjectMan::_translationId8455199[7] = { + NULL, // "Not unless you have Rosso's gift for psychic interrogation.", // English (not needed) + "Non, \340 moins d'avoir les dons de Rosso pour les interrogatoires psychiques.", // French + "Es sei denn, Du h\344ttest Rosso's Gabe der parapsychologischen Befragung.", // German + "A meno che tu non riesca a fare interrogatori telepatici come Rosso.", // Italian + "A no ser que tengas el don de Rosso para la interrogaci\363n ps\355quica.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455200 (in the demo). +const char *const ObjectMan::_translationId8455200[7] = { + NULL, // "How did Plantard get your name?", // English (not needed) + "Comment Plantard a-t-il obtenu votre nom?", // French + "Woher hat Plantard Deinen Namen?", // German + "Come ha fatto Plantard a sapere il tuo nome?", // Italian + "\277C\363mo consigui\363 Plantard tu nombre?", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455201 (in the demo). +const char *const ObjectMan::_translationId8455201[7] = { + NULL, // "Through the newspaper - La Libert\351.", // English (not needed) + "Par mon journal... La Libert\351.", // French + "\334ber die Zeitung - La Libert\351.", // German + "Tramite il giornale La Libert\351.", // Italian + "Por el peri\363dico - La Libert\351.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455202 (in the demo). +const char *const ObjectMan::_translationId8455202[7] = { + NULL, // "I'd written an article linking two unsolved murders, one in Italy, the other in Japan.", // English (not needed) + "J'ai \351crit un article o\371 je faisais le lien entre deux meurtres inexpliqu\351s, en Italie et au japon.", // French + "Ich habe einen Artikel geschrieben, in dem ich zwei ungel\366ste Morde miteinander in Verbindung bringe, einen in Italien, einen anderen in Japan.", // German + "Ho scritto un articolo che metteva in collegamento due omicidi insoluti in Italia e Giappone.", // Italian + "Yo hab\355a escrito un art\355culo conectando dos asesinatos sin resolver, uno en Italia, el otro en Jap\363n.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455203 (in the demo). +const char *const ObjectMan::_translationId8455203[7] = { + NULL, // "The cases were remarkably similar...", // English (not needed) + "Les affaires \351taient quasiment identiques...", // French + "Die F\344lle sind sich bemerkenswert \344hnlich...", // German + "I casi erano sorprendentemente uguali...", // Italian + "Los casos eran incre\355blemente parecidos...", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455204 (in the demo). +const char *const ObjectMan::_translationId8455204[7] = { + NULL, // "...a wealthy victim, no apparent motive, and a costumed killer.", // English (not needed) + "...une victime riche, pas de motif apparent, et un tueur d\351guis\351.", // French + "...ein wohlhabendes Opfer, kein offensichtliches Motiv, und ein verkleideter Killer.", // German + "...una vittima ricca, nessun motivo apparente e un assassino in costume.", // Italian + "...una v\355ctima rica, sin motivo aparente, y un asesino disfrazado.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 8455205 (in the demo). +const char *const ObjectMan::_translationId8455205[7] = { + NULL, // "Plantard said he could supply me with more information.", // English (not needed) + "Plantard m'a dit qu'il pourrait me fournir des renseignements.", // French + "Plantard sagte, er k\366nne mir weitere Informationen beschaffen.", // German + "Plantard mi disse che mi avrebbe fornito ulteriori informazioni.", // Italian + "Plantard dijo que \351l me pod\355a proporcionar m\341s informaci\363n.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 6488080 (in the demo). +const char *const ObjectMan::_translationId6488080[7] = { + NULL, // "I wasn't going to head off all over Paris until I'd investigated some more.", // English (not needed) + "Je ferais mieux d'enqu\351ter un peu par ici avant d'aller me promener ailleurs.", // French + "Ich durchquere nicht ganz Paris, bevor ich etwas mehr herausgefunden habe.", // German + "Non mi sarei incamminato per tutta Parigi prima di ulteriori indagini.", // Italian + "No iba a ponerme a recorrer Par\355s sin haber investigado un poco m\341s.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// The next three sentences are specific to the demo and only the english text is present. +// The translations were provided by: +// French: Thierry Crozat +// German: Simon Sawatzki +// Italian: Matteo Angelino +// Spanish: Tomás Maidagan + +// Missing translation for textId 6488081 (in the demo). +const char *const ObjectMan::_translationId6488081[7] = { + NULL, // "I wasn't sure what I was going to do when I caught up with that clown...", // English (not needed) + "Je ne savais pas ce que je ferais quand je rattraperais le clown...", // French + "Ich wu\337te nicht, worauf ich mich einlie\337, als ich dem Clown nachjagte...", // German + "Non sapevo cosa avrei fatto una volta raggiunto quel clown...", // Italian + "No sab\355a muy bien qu\351 es lo que har\355a cuando alcanzara al payaso...", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 6488082 (in the demo). +const char *const ObjectMan::_translationId6488082[7] = { + NULL, // "...but before I knew it, I was drawn into a desperate race between two ruthless enemies.", // English (not needed) + "...mais avant de m'en rendre compte je me retrouvais happ\351 dans une course effr\351n\351e entre deux ennemis impitoyables.", // French + "... doch bevor ich mich versah, war ich inmitten eines Wettlaufs von zwei r\374cksichtslosen Feinden.", // German + "... ma prima che me ne rendessi conto, fui trascinato in una corsa disperata con due spietati nemici.", // Italian + "...pero sin darme cuenta, acab\351 en medio de una desesperada carrera entre dos despiadados enemigos.", // Spanish + NULL, // Czech + NULL // Portuguese +}; + +// Missing translation for textId 6488083 (in the demo). +const char *const ObjectMan::_translationId6488083[7] = { + NULL, // "The goal: the mysterious power of the Broken Sword.", // English (not needed) + "Le but: les pouvoirs myst\351rieux de l'\351p\351e bris\351e.", // French + "Das Ziel: die geheimnisvolle Macht des zerbrochenen Schwertes.", // German + "Obiettivo: il misterioso potere della Spada spezzata.", // Italian + "El objetivo: el misterioso poder de la Espada Rota.", // Spanish + NULL, // Czech + NULL // Portuguese }; } // End of namespace Sword1 diff --git a/engines/sword1/objectman.h b/engines/sword1/objectman.h index ca3c7c1526..197b437c15 100644 --- a/engines/sword1/objectman.h +++ b/engines/sword1/objectman.h @@ -53,6 +53,9 @@ public: void saveLiveList(uint16 *dest); // for loading/saving void loadLiveList(uint16 *src); private: + char *lockText(uint32 textId, uint8 language); + void unlockText(uint32 textId, uint8 language); + ResMan *_resMan; static const uint32 _objectList[TOTAL_SECTIONS]; //a table of pointers to object files static const uint32 _textList[TOTAL_SECTIONS][7]; //a table of pointers to text files @@ -60,6 +63,22 @@ private: uint8 *_cptData[TOTAL_SECTIONS]; static char _missingSubTitleStr[]; static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some langages) + static const char *const _translationId8455194[7]; //translation for textId 8455194 (missing in the demo) + static const char *const _translationId8455195[7]; //translation for textId 8455195 (missing in the demo) + static const char *const _translationId8455196[7]; //translation for textId 8455196 (missing in the demo) + static const char *const _translationId8455197[7]; //translation for textId 8455197 (missing in the demo) + static const char *const _translationId8455198[7]; //translation for textId 8455198 (missing in the demo) + static const char *const _translationId8455199[7]; //translation for textId 8455199 (missing in the demo) + static const char *const _translationId8455200[7]; //translation for textId 8455200 (missing in the demo) + static const char *const _translationId8455201[7]; //translation for textId 8455201 (missing in the demo) + static const char *const _translationId8455202[7]; //translation for textId 8455202 (missing in the demo) + static const char *const _translationId8455203[7]; //translation for textId 8455203 (missing in the demo) + static const char *const _translationId8455204[7]; //translation for textId 8455204 (missing in the demo) + static const char *const _translationId8455205[7]; //translation for textId 8455205 (missing in the demo) + static const char *const _translationId6488080[7]; //translation for textId 6488081 (missing in the demo) + static const char *const _translationId6488081[7]; //translation for textId 6488081 (missing in the demo) + static const char *const _translationId6488082[7]; //translation for textId 6488082 (missing in the demo) + static const char *const _translationId6488083[7]; //translation for textId 6488083 (missing in the demo) }; } // End of namespace Sword1 diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index 3574074b00..61bf5257ab 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -142,7 +142,7 @@ void Sound::checkSpeechFileEndianness() { be_diff_sum += fabs((double)(be_value - prev_be_value)); prev_be_value = be_value; } - delete [] data; + delete[] data; } // Set the big endian flag _bigEndianSpeech = (be_diff_sum < le_diff_sum); diff --git a/engines/sword1/text.cpp b/engines/sword1/text.cpp index 3bd2fdb2e6..f23ac5f182 100644 --- a/engines/sword1/text.cpp +++ b/engines/sword1/text.cpp @@ -156,6 +156,8 @@ uint16 Text::analyzeSentence(const uint8 *text, uint16 maxWidth, LineInfo *line) } uint16 Text::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) { + if (ch < SPACE) + ch = 64; FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE); uint8 *chData = ((uint8 *)chFrame) + sizeof(FrameHeader); uint8 *dest = sprPtr; diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index e77ae98163..00260f789a 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -38,8 +38,11 @@ #include "sword2/screen.h" #include "sword2/animation.h" +#include "graphics/palette.h" + #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/smk_decoder.h" #include "video/psx_decoder.h" @@ -51,9 +54,8 @@ namespace Sword2 { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -62,7 +64,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -75,11 +76,6 @@ bool MoviePlayer::load(const char *name) { if (_vm->shouldQuit()) return false; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name); - else - _bgSoundStream = NULL; - _textSurface = NULL; Common::String filename; @@ -99,6 +95,7 @@ bool MoviePlayer::load(const char *name) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + _decoder->start(); return true; } else { initGraphics(640, 480, true); @@ -106,7 +103,15 @@ bool MoviePlayer::load(const char *name) { } } - return _decoder->loadFile(filename.c_str()); + if (!_decoder->loadFile(filename)) + return false; + + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + _decoder->addStreamFileTrack(name); + + _decoder->start(); + return true; } void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) { @@ -122,24 +127,15 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI if (leadIn) _vm->_sound->playMovieSound(leadIn, kLeadInSound); - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); - - bool terminated = false; - - terminated = !playVideo(); + bool terminated = !playVideo(); closeTextObject(_currentMovieText, NULL, 0); if (terminated) { - _snd->stopHandle(*_bgSoundHandle); _vm->_sound->stopMovieSounds(); _vm->_sound->stopSpeech(); } - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - if (_decoderType == kVideoDecoderPSX) { // Need to jump back to paletted color initGraphics(640, 480, true); @@ -332,11 +328,11 @@ bool MoviePlayer::playVideo() { if (_decoderType == kVideoDecoderPSX) drawFramePSX(frame); else - _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); uint32 maxWeight = 0; uint32 minWeight = 0xFFFFFFFF; @@ -401,36 +397,24 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { uint16 x = (g_system->getWidth() - scaledFrame.w) / 2; uint16 y = (g_system->getHeight() - scaledFrame.h) / 2; - _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); + _vm->_system->copyRectToScreen(scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h); scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getElapsedTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getElapsedTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) { +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; filename = Common::String::format("%s.str", name); if (Common::File::exists(filename)) { #ifdef USE_RGB_COLOR Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount); - return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK")); dialog.runModal(); @@ -441,16 +425,16 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s filename = Common::String::format("%s.smk", name); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); - return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); + return new MoviePlayer(vm, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", name); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::DXADecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 3ef8dac754..b2a243b2ca 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -25,12 +25,16 @@ #ifndef SWORD2_ANIMATION_H #define SWORD2_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" -#include "audio/mixer.h" - #include "sword2/screen.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword2 { enum DecoderType { @@ -55,20 +59,9 @@ struct MovieText { } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getElapsedTime() const; -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(const char *name); @@ -76,7 +69,6 @@ public: protected: Sword2Engine *_vm; - Audio::Mixer *_snd; OSystem *_system; MovieText *_movieTexts; uint32 _numMovieTexts; @@ -87,8 +79,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; uint32 _leadOut; int _leadOutFrame; @@ -105,7 +95,7 @@ protected: uint32 getWhiteColor(); }; -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount); +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount); } // End of namespace Sword2 diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp index 836b252d6c..07fcaa094b 100644 --- a/engines/sword2/function.cpp +++ b/engines/sword2/function.cpp @@ -2139,7 +2139,7 @@ int32 Logic::fnPlaySequence(int32 *params) { uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0; - _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount); + _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_system, frameCount); if (_moviePlayer && _moviePlayer->load(filename)) { _moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut); diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index 1acb366b3a..a95532ec65 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -61,6 +61,7 @@ bool MoviePlayer::loadMovie(const Common::String &filename, uint z) { // Get the file and load it into the decoder Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename); _decoder.loadStream(in); + _decoder.start(); GraphicEngine *pGfx = Kernel::getInstance()->getGfx(); @@ -132,7 +133,7 @@ void MoviePlayer::update() { const byte *frameData = (const byte *)s->getBasePtr(0, 0); _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch); #else - g_system->copyRectToScreen((byte *)s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h)); + g_system->copyRectToScreen(s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h)); g_system->updateScreen(); #endif } @@ -167,7 +168,7 @@ void MoviePlayer::setScaleFactor(float scaleFactor) { } double MoviePlayer::getTime() { - return _decoder.getElapsedTime() / 1000.0; + return _decoder.getTime() / 1000.0; } #else // USE_THEORADEC diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h index 1d256e56ba..2f5614b505 100644 --- a/engines/sword25/fmv/movieplayer.h +++ b/engines/sword25/fmv/movieplayer.h @@ -39,7 +39,7 @@ #include "sword25/gfx/bitmap.h" #ifdef USE_THEORADEC -#include "sword25/fmv/theora_decoder.h" +#include "video/theora_decoder.h" #endif #define THEORA_INDIRECT_RENDERING @@ -141,7 +141,7 @@ private: #ifdef USE_THEORADEC - TheoraDecoder _decoder; + Video::TheoraDecoder _decoder; Graphics::Surface *_backSurface; int _outX, _outY; diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp deleted file mode 100644 index a7ebb5df8c..0000000000 --- a/engines/sword25/fmv/theora_decoder.cpp +++ /dev/null @@ -1,555 +0,0 @@ -/* 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. - * - */ - -/* - * Source is based on the player example from libvorbis package, - * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c - * - * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. - * - * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 - * by the Xiph.Org Foundation and contributors http://www.xiph.org/ - * - */ - -#include "sword25/fmv/theora_decoder.h" - -#ifdef USE_THEORADEC -#include "common/system.h" -#include "common/textconsole.h" -#include "common/util.h" -#include "graphics/yuv_to_rgb.h" -#include "audio/decoders/raw.h" -#include "sword25/kernel/common.h" - -namespace Sword25 { - -#define AUDIOFD_FRAGSIZE 10240 - -static double rint(double v) { - return floor(v + 0.5); -} - -TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { - _fileStream = 0; - - _theoraPacket = 0; - _vorbisPacket = 0; - _theoraDecode = 0; - _theoraSetup = 0; - _nextFrameStartTime = 0.0; - - _soundType = soundType; - _audStream = 0; - _audHandle = new Audio::SoundHandle(); - - ogg_sync_init(&_oggSync); - - _curFrame = -1; - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - - reset(); -} - -TheoraDecoder::~TheoraDecoder() { - close(); - delete _fileStream; - delete _audHandle; - free(_audiobuf); -} - -void TheoraDecoder::queuePage(ogg_page *page) { - if (_theoraPacket) - ogg_stream_pagein(&_theoraOut, page); - - if (_vorbisPacket) - ogg_stream_pagein(&_vorbisOut, page); -} - -int TheoraDecoder::bufferData() { - char *buffer = ogg_sync_buffer(&_oggSync, 4096); - int bytes = _fileStream->read(buffer, 4096); - - ogg_sync_wrote(&_oggSync, bytes); - - return bytes; -} - -bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { - close(); - - _endOfAudio = false; - _endOfVideo = false; - _fileStream = stream; - - // start up Ogg stream synchronization layer - ogg_sync_init(&_oggSync); - - // init supporting Vorbis structures needed in header parsing - vorbis_info_init(&_vorbisInfo); - vorbis_comment_init(&_vorbisComment); - - // init supporting Theora structures needed in header parsing - th_comment_init(&_theoraComment); - th_info_init(&_theoraInfo); - - // Ogg file open; parse the headers - // Only interested in Vorbis/Theora streams - bool foundHeader = false; - while (!foundHeader) { - int ret = bufferData(); - - if (ret == 0) - break; - - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - ogg_stream_state test; - - // is this a mandated initial header? If not, stop parsing - if (!ogg_page_bos(&_oggPage)) { - // don't leak the page; get it into the appropriate stream - queuePage(&_oggPage); - foundHeader = true; - break; - } - - ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); - ogg_stream_pagein(&test, &_oggPage); - ogg_stream_packetout(&test, &_oggPacket); - - // identify the codec: try theora - if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { - // it is theora - memcpy(&_theoraOut, &test, sizeof(test)); - _theoraPacket = 1; - } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { - // it is vorbis - memcpy(&_vorbisOut, &test, sizeof(test)); - _vorbisPacket = 1; - } else { - // whatever it is, we don't care about it - ogg_stream_clear(&test); - } - } - // fall through to non-bos page parsing - } - - // we're expecting more header packets. - while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { - int ret; - - // look for further theora headers - while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Theora stream headers; corrupt stream?"); - - if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) - error("Error parsing Theora stream headers; corrupt stream?"); - - _theoraPacket++; - } - - // look for more vorbis header packets - while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - _vorbisPacket++; - - if (_vorbisPacket == 3) - break; - } - - // The header pages/packets will arrive before anything else we - // care about, or the stream is not obeying spec - - if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - queuePage(&_oggPage); // demux into the appropriate stream - } else { - ret = bufferData(); // someone needs more data - - if (ret == 0) - error("End of file while searching for codec headers."); - } - } - - // and now we have it all. initialize decoders - if (_theoraPacket) { - _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); - debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", - _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, - (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); - - switch (_theoraInfo.pixel_fmt) { - case TH_PF_420: - debug(1, " 4:2:0 video"); - break; - case TH_PF_422: - debug(1, " 4:2:2 video"); - break; - case TH_PF_444: - debug(1, " 4:4:4 video"); - break; - case TH_PF_RSVD: - default: - debug(1, " video\n (UNKNOWN Chroma sampling!)"); - break; - } - - if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) - debug(1, " Frame content is %dx%d with offset (%d,%d).", - _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); - - switch (_theoraInfo.colorspace){ - case TH_CS_UNSPECIFIED: - /* nothing to report */ - break; - case TH_CS_ITU_REC_470M: - debug(1, " encoder specified ITU Rec 470M (NTSC) color."); - break; - case TH_CS_ITU_REC_470BG: - debug(1, " encoder specified ITU Rec 470BG (PAL) color."); - break; - default: - debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); - break; - } - - debug(1, "Encoded by %s", _theoraComment.vendor); - if (_theoraComment.comments) { - debug(1, "theora comment header:"); - for (int i = 0; i < _theoraComment.comments; i++) { - if (_theoraComment.user_comments[i]) { - int len = _theoraComment.comment_lengths[i]; - char *value = (char *)malloc(len + 1); - if (value) { - memcpy(value, _theoraComment.user_comments[i], len); - value[len] = '\0'; - debug(1, "\t%s", value); - free(value); - } - } - } - } - - th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); - _ppLevel = _ppLevelMax; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } else { - // tear down the partial theora setup - th_info_clear(&_theoraInfo); - th_comment_clear(&_theoraComment); - } - - th_setup_free(_theoraSetup); - _theoraSetup = 0; - - if (_vorbisPacket) { - vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); - vorbis_block_init(&_vorbisDSP, &_vorbisBlock); - debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", - _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); - - _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); - - // Get enough audio data to start us off - while (_audStream->numQueuedStreams() == 0) { - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - queueAudio(); - } - - if (_audStream) - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream); - } else { - // tear down the partial vorbis setup - vorbis_info_clear(&_vorbisInfo); - vorbis_comment_clear(&_vorbisComment); - _endOfAudio = true; - } - - _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); - - // Set up a display surface - _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); - _displaySurface.w = _theoraInfo.pic_width; - _displaySurface.h = _theoraInfo.pic_height; - _displaySurface.format = _surface.format; - _displaySurface.pitch = _surface.pitch; - - // Set the frame rate - _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); - - return true; -} - -void TheoraDecoder::close() { - if (_vorbisPacket) { - ogg_stream_clear(&_vorbisOut); - vorbis_block_clear(&_vorbisBlock); - vorbis_dsp_clear(&_vorbisDSP); - vorbis_comment_clear(&_vorbisComment); - vorbis_info_clear(&_vorbisInfo); - - g_system->getMixer()->stopHandle(*_audHandle); - - _audStream = 0; - _vorbisPacket = false; - } - if (_theoraPacket) { - ogg_stream_clear(&_theoraOut); - th_decode_free(_theoraDecode); - th_comment_clear(&_theoraComment); - th_info_clear(&_theoraInfo); - _theoraDecode = 0; - _theoraPacket = false; - } - - if (!_fileStream) - return; - - ogg_sync_clear(&_oggSync); - - delete _fileStream; - _fileStream = 0; - - _surface.free(); - _displaySurface.pixels = 0; - _displaySurface.free(); - - reset(); -} - -const Graphics::Surface *TheoraDecoder::decodeNextFrame() { - // First, let's get our frame - while (_theoraPacket) { - // theora is one in, one out... - if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { - - if (_ppInc) { - _ppLevel += _ppInc; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } - - if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { - _curFrame++; - - // Convert YUV data to RGB data - th_ycbcr_buffer yuv; - th_decode_ycbcr_out(_theoraDecode, yuv); - translateYUVtoRGBA(yuv); - - if (_curFrame == 0) - _startTime = g_system->getMillis(); - - double time = th_granule_time(_theoraDecode, _oggPacket.granulepos); - - // We need to calculate when the next frame should be shown - // This is all in floating point because that's what the Ogg code gives us - // Ogg is a lossy container format, so it doesn't always list the time to the - // next frame. In such cases, we need to calculate it ourselves. - if (time == -1.0) - _nextFrameStartTime += _frameRate.getInverse().toDouble(); - else - _nextFrameStartTime = time; - - // break out - break; - } - } else { - // If we can't get any more frames, we're done. - if (_theoraOut.e_o_s || _fileStream->eos()) { - _endOfVideo = true; - break; - } - - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - } - - // Update audio if we can - queueAudio(); - } - - // Force at least some audio to be buffered - // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. - while (!_endOfAudio && _audStream->numQueuedStreams() < 5) { - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - bool queuedAudio = queueAudio(); - if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { - _endOfAudio = true; - break; - } - } - - return &_displaySurface; -} - -bool TheoraDecoder::queueAudio() { - if (!_audStream) - return false; - - // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer) - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Invalid audio buffer"); - return false; - } - - bool queuedAudio = false; - - for (;;) { - float **pcm; - - // if there's pending, decoded audio, grab it - int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); - if (ret > 0) { - int count = _audiobufFill / 2; - int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1; - int i; - for (i = 0; i < ret && i < maxsamples; i++) - for (int j = 0; j < _vorbisInfo.channels; j++) { - int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); - _audiobuf[count++] = val; - } - - vorbis_synthesis_read(&_vorbisDSP, i); - _audiobufFill += (i * _vorbisInfo.channels) << 1; - - if (_audiobufFill == AUDIOFD_FRAGSIZE) { - byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif - _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags); - - // The audio mixer is now responsible for the old audio buffer. - // We need to create a new one. - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer"); - return false; - } - - _audiobufFill = 0; - queuedAudio = true; - } - } else { - // no pending audio; is there a pending packet to decode? - if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { - if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success! - vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); - } else // we've buffered all we have, break out for now - return queuedAudio; - } - } - - // Unreachable - return false; -} - -void TheoraDecoder::reset() { - VideoDecoder::reset(); - - // FIXME: This does a rewind() instead of a reset()! - - if (_fileStream) - _fileStream->seek(0); - - _audiobufFill = 0; - _audiobufReady = false; - - _curFrame = -1; - - _theoraPacket = 0; - _vorbisPacket = 0; -} - -bool TheoraDecoder::endOfVideo() const { - return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio))); -} - -uint32 TheoraDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) - return 0; - - uint32 elapsedTime = getElapsedTime(); - uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); - - if (nextFrameStartTime <= elapsedTime) - return 0; - - return nextFrameStartTime - elapsedTime; -} - -uint32 TheoraDecoder::getElapsedTime() const { - if (_audStream) - return g_system->getMixer()->getSoundElapsedTime(*_audHandle); - - return VideoDecoder::getElapsedTime(); -} - -void TheoraDecoder::pauseVideoIntern(bool pause) { - if (_audStream) - g_system->getMixer()->pauseHandle(*_audHandle, pause); -} - -enum TheoraYUVBuffers { - kBufferY = 0, - kBufferU = 1, - kBufferV = 2 -}; - -void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { - // Width and height of all buffers have to be divisible by 2. - assert((YUVBuffer[kBufferY].width & 1) == 0); - assert((YUVBuffer[kBufferY].height & 1) == 0); - assert((YUVBuffer[kBufferU].width & 1) == 0); - assert((YUVBuffer[kBufferV].width & 1) == 0); - - // UV images have to have a quarter of the Y image resolution - assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); - assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); - - Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); -} - -} // End of namespace Sword25 - -#endif diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h deleted file mode 100644 index e8cc5ab8b9..0000000000 --- a/engines/sword25/fmv/theora_decoder.h +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 SWORD25_THEORADECODER_H -#define SWORD25_THEORADECODER_H - -#include "common/scummsys.h" // for USE_THEORADEC - -#ifdef USE_THEORADEC - -#include "common/rational.h" -#include "video/video_decoder.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" - -#include <theora/theoradec.h> -#include <vorbis/codec.h> - -namespace Common { -class SeekableReadStream; -} - -namespace Sword25 { - -/** - * - * Decoder for Theora videos. - * Video decoder used in engines: - * - sword25 - */ -class TheoraDecoder : public Video::VideoDecoder { -public: - TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); - virtual ~TheoraDecoder(); - - /** - * Load a video file - * @param stream the stream to load - */ - bool loadStream(Common::SeekableReadStream *stream); - void close(); - void reset(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _displaySurface.w; } - uint16 getHeight() const { return _displaySurface.h; } - - uint32 getFrameCount() const { - // It is not possible to get frame count easily - // I.e. seeking is required - assert(0); - return 0; - } - - Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } - uint32 getElapsedTime() const; - uint32 getTimeToNextFrame() const; - - bool endOfVideo() const; - -protected: - void pauseVideoIntern(bool pause); - -private: - void queuePage(ogg_page *page); - bool queueAudio(); - int bufferData(); - void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface _surface; - Graphics::Surface _displaySurface; - Common::Rational _frameRate; - double _nextFrameStartTime; - bool _endOfVideo; - bool _endOfAudio; - - Audio::Mixer::SoundType _soundType; - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; - - ogg_sync_state _oggSync; - ogg_page _oggPage; - ogg_packet _oggPacket; - ogg_stream_state _vorbisOut; - ogg_stream_state _theoraOut; - th_info _theoraInfo; - th_comment _theoraComment; - th_dec_ctx *_theoraDecode; - th_setup_info *_theoraSetup; - vorbis_info _vorbisInfo; - vorbis_dsp_state _vorbisDSP; - vorbis_block _vorbisBlock; - vorbis_comment _vorbisComment; - - int _theoraPacket; - int _vorbisPacket; - - int _ppLevelMax; - int _ppLevel; - int _ppInc; - - // single audio fragment audio buffering - int _audiobufFill; - bool _audiobufReady; - ogg_int16_t *_audiobuf; -}; - -} // End of namespace Sword25 - -#endif - -#endif diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp index 14ba032107..6f5da32bc4 100644 --- a/engines/sword25/gfx/graphicengine.cpp +++ b/engines/sword25/gfx/graphicengine.cpp @@ -216,7 +216,7 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) { } } - g_system->copyRectToScreen((byte *)_backSurface.getBasePtr(rect.left, rect.top), _backSurface.pitch, rect.left, rect.top, rect.width(), rect.height()); + g_system->copyRectToScreen(_backSurface.getBasePtr(rect.left, rect.top), _backSurface.pitch, rect.left, rect.top, rect.width(), rect.height()); } return true; diff --git a/engines/sword25/gfx/image/art.cpp b/engines/sword25/gfx/image/art.cpp index 3944a207c8..9c4b9fe8bd 100644 --- a/engines/sword25/gfx/image/art.cpp +++ b/engines/sword25/gfx/image/art.cpp @@ -2367,38 +2367,30 @@ ArtSVPRenderAAIter *art_svp_render_aa_iter(const ArtSVP *svp, return iter; } -#define ADD_STEP(xpos, xdelta) \ +#define ADD_STEP(xpos, xdelta) \ /* stereotype code fragment for adding a step */ \ - if (n_steps == 0 || steps[n_steps - 1].x < xpos) \ - { \ + if (n_steps == 0 || steps[n_steps - 1].x < xpos) { \ sx = n_steps; \ steps[sx].x = xpos; \ steps[sx].delta = xdelta; \ n_steps++; \ - } \ - else \ - { \ - for (sx = n_steps; sx > 0; sx--) \ - { \ - if (steps[sx - 1].x == xpos) \ - { \ + } else { \ + for (sx = n_steps; sx > 0; sx--) { \ + if (steps[sx - 1].x == xpos) { \ steps[sx - 1].delta += xdelta; \ sx = n_steps; \ break; \ - } \ - else if (steps[sx - 1].x < xpos) \ - { \ + } else if (steps[sx - 1].x < xpos) { \ break; \ - } \ - } \ - if (sx < n_steps) \ - { \ + } \ + } \ + if (sx < n_steps) { \ memmove (&steps[sx + 1], &steps[sx], \ (n_steps - sx) * sizeof(steps[0])); \ steps[sx].x = xpos; \ steps[sx].delta = xdelta; \ n_steps++; \ - } \ + } \ } void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start, diff --git a/engines/sword25/gfx/image/art.h b/engines/sword25/gfx/image/art.h index 8c9c97bc57..40bcb55aa7 100644 --- a/engines/sword25/gfx/image/art.h +++ b/engines/sword25/gfx/image/art.h @@ -50,7 +50,7 @@ namespace Sword25 { be variables. They can also be pstruct->el lvalues. */ #define art_expand(p, type, max) \ do { \ - if(max) {\ + if (max) {\ type *tmp = art_renew(p, type, max <<= 1); \ if (!tmp) error("Cannot reallocate memory for art data"); \ p = tmp; \ diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp index b0d4853e5e..27ee4ef182 100644 --- a/engines/sword25/gfx/image/renderedimage.cpp +++ b/engines/sword25/gfx/image/renderedimage.cpp @@ -430,7 +430,7 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe ino += inoStep; } - g_system->copyRectToScreen((byte *)_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY, + g_system->copyRectToScreen(_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY, img->w, img->h); } diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk index 302120c500..e24a221244 100644 --- a/engines/sword25/module.mk +++ b/engines/sword25/module.mk @@ -85,11 +85,6 @@ MODULE_OBJS := \ util/pluto/pluto.o \ util/pluto/plzio.o -ifdef USE_THEORADEC -MODULE_OBJS += \ - fmv/theora_decoder.o -endif - # This module can be built as a plugin ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN) PLUGIN := 1 diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index 78b2db19eb..69fae3dc4e 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -239,16 +239,20 @@ void SoundEngine::setSoundVolume(uint handle, float volume) { debugC(1, kDebugSound, "SoundEngine::setSoundVolume(%d, %f)", handle, volume); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->volume = volume; _mixer->setChannelVolume(sndHandle->handle, (byte)(volume * 255)); + } } void SoundEngine::setSoundPanning(uint handle, float pan) { debugC(1, kDebugSound, "SoundEngine::setSoundPanning(%d, %f)", handle, pan); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->pan = pan; _mixer->setChannelBalance(sndHandle->handle, (int8)(pan * 127)); + } } void SoundEngine::pauseSound(uint handle) { @@ -324,13 +328,16 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) { return fname.hasSuffix(".ogg"); } - - bool SoundEngine::persist(OutputPersistenceBlock &writer) { +bool SoundEngine::persist(OutputPersistenceBlock &writer) { writer.write(_maxHandleId); for (uint i = 0; i < SOUND_HANDLES; i++) { writer.write(_handles[i].id); + // Don't restart sounds which already finished playing. + if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle)) + _handles[i].type = kFreeHandle; + writer.writeString(_handles[i].fileName); writer.write((int)_handles[i].sndType); writer.write(_handles[i].volume); @@ -374,7 +381,8 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) { reader.read(layer); if (reader.isGood()) { - playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); + if (sndType != kFreeHandle) + playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); } else return false; } diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp index d645e5ed2a..b7f5e30340 100644 --- a/engines/sword25/util/pluto/pluto.cpp +++ b/engines/sword25/util/pluto/pluto.cpp @@ -895,10 +895,10 @@ static void unpersistnumber(UnpersistInfo *upi) static void unpersiststring(UnpersistInfo *upi) { /* perms reftbl sptbl ref */ - int length; + size_t length; char* string; lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); string = pdep_newvector(upi->L, length, char); verify(LIF(Z,read)(&upi->zio, string, length) == 0); lua_pushlstring(upi->L, string, length); diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp index 8882531d27..934727a478 100644 --- a/engines/teenagent/callbacks.cpp +++ b/engines/teenagent/callbacks.cpp @@ -2252,7 +2252,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) { return true; case 0x78e0: - processCallback(0x50c5); + processCallback(0x505c); return false; case 0x78e7: @@ -2265,7 +2265,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) { case 0x78f5: if (CHECK_FLAG(0xDB95, 1)) { - displayMessage(0x3575); + displayMessage(0x3E75); return true; } else return false; @@ -3925,7 +3925,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) { displayMessage(0x39ae); break; default: - displayMessage(0x39b7); + displayMessage(0x3ab7); } return true; diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp index dad876dd97..2de6f49c44 100644 --- a/engines/teenagent/detection.cpp +++ b/engines/teenagent/detection.cpp @@ -80,7 +80,7 @@ static const ADGameDescription teenAgentGameDescriptions[] = { }; enum { - MAX_SAVES = 20 + MAX_SAVES = 20 }; class TeenAgentMetaEngine : public AdvancedMetaEngine { @@ -123,16 +123,15 @@ public: virtual SaveStateList listSaves(const char *target) const { Common::String pattern = target; - pattern += ".*"; + pattern += ".??"; Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern); Common::sort(filenames.begin(), filenames.end()); SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - int slot; - const char *ext = strrchr(file->c_str(), '.'); - if (ext && (slot = atoi(ext + 1)) >= 0 && slot < MAX_SAVES) { + int slot = atoi(file->c_str() + file->size() - 2); + if (slot >= 0 && slot < MAX_SAVES) { Common::ScopedPtr<Common::InSaveFile> in(g_system->getSavefileManager()->openForLoading(*file)); if (!in) continue; @@ -174,7 +173,6 @@ public: return SaveStateDescriptor(slot, desc); SaveStateDescriptor ssd(slot, desc); - ssd.setDeletableFlag(true); //checking for the thumbnail if (Graphics::Surface *const thumb = Graphics::loadThumbnail(*in)) diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp index 597ca670c0..dff58f98e2 100644 --- a/engines/teenagent/resources.cpp +++ b/engines/teenagent/resources.cpp @@ -22,6 +22,7 @@ #include "teenagent/resources.h" #include "teenagent/teenagent.h" #include "common/textconsole.h" +#include "common/translation.h" #include "common/zlib.h" namespace TeenAgent { @@ -64,28 +65,47 @@ bool Resources::loadArchives(const ADGameDescription *gd) { Common::File *dat_file = new Common::File(); if (!dat_file->open("teenagent.dat")) { delete dat_file; - Common::String errorMessage = "You're missing the 'teenagent.dat' file. Get it from the ScummVM website"; - GUIErrorMessage(errorMessage); + Common::String errorMessage = _("You're missing the 'teenagent.dat' file. Get it from the ScummVM website"); warning("%s", errorMessage.c_str()); + GUIErrorMessage(errorMessage); return false; } + + // teenagent.dat used to be compressed with zlib compression. The usage of + // zlib here is no longer needed, and it's maintained only for backwards + // compatibility. Common::SeekableReadStream *dat = Common::wrapCompressedReadStream(dat_file); + +#if !defined(USE_ZLIB) + uint16 header = dat->readUint16BE(); + bool isCompressed = (header == 0x1F8B || + ((header & 0x0F00) == 0x0800 && + header % 31 == 0)); + dat->seek(-2, SEEK_CUR); + + if (isCompressed) { + // teenagent.dat is compressed, but zlib hasn't been compiled in + delete dat; + Common::String errorMessage = _("The teenagent.dat file is compressed and zlib hasn't been included in this executable. Please decompress it"); + warning("%s", errorMessage.c_str()); + GUIErrorMessage(errorMessage); + return false; + } +#endif + cseg.read(dat, 0xb3b0); dseg.read(dat, 0xe790); eseg.read(dat, 0x8be2); - delete dat; - { - FilePack varia; - varia.open("varia.res"); - font7.load(varia, 7); - font7.width_pack = 1; - font7.height = 11; - font8.load(varia, 8); - font8.height = 31; - varia.close(); - } + FilePack varia; + varia.open("varia.res"); + font7.load(varia, 7); + font7.width_pack = 1; + font7.height = 11; + font8.load(varia, 8); + font8.height = 31; + varia.close(); off.open("off.res"); on.open("on.res"); diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp index e8c2dec4fa..038c8ea05e 100644 --- a/engines/teenagent/scene.cpp +++ b/engines/teenagent/scene.cpp @@ -423,7 +423,7 @@ void Scene::init(int id, const Common::Point &pos) { if (now_playing != res->dseg.get_byte(0xDB90)) _engine->music->load(res->dseg.get_byte(0xDB90)); - _system->copyRectToScreen((const byte *)background.pixels, background.pitch, 0, 0, background.w, background.h); + _system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h); setPalette(0); } @@ -654,7 +654,7 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) { } if (background.pixels && debug_features.feature[DebugFeatures::kShowBack]) { - _system->copyRectToScreen((const byte *)background.pixels, background.pitch, 0, 0, background.w, background.h); + _system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h); } else _system->fillScreen(0); diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp index fb228ef2fc..57c069fe59 100644 --- a/engines/teenagent/teenagent.cpp +++ b/engines/teenagent/teenagent.cpp @@ -389,7 +389,7 @@ bool TeenAgentEngine::showLogo() { return true; } - _system->copyRectToScreen((const byte *)s.pixels, s.w, s.x, s.y, s.w, s.h); + _system->copyRectToScreen(s.pixels, s.w, s.x, s.y, s.w, s.h); _system->updateScreen(); _system->delayMillis(100); @@ -535,9 +535,8 @@ Common::Error TeenAgentEngine::run() { syncSoundSettings(); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false); setMusic(1); - music->start(); + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false); int load_slot = Common::ConfigManager::instance().getInt("save_slot"); if (load_slot >= 0) { diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp index 36ec726fc7..590e6c6d81 100644 --- a/engines/testbed/graphics.cpp +++ b/engines/testbed/graphics.cpp @@ -935,7 +935,7 @@ TestExitStatus GFXtests::overlayGraphics() { } g_system->showOverlay(); - g_system->copyRectToOverlay(buffer, 100, 270, 175, 100, 50); + g_system->copyRectToOverlay(buffer, 200, 270, 175, 100, 50); g_system->updateScreen(); g_system->delayMillis(1000); @@ -1028,7 +1028,7 @@ TestExitStatus GFXtests::paletteRotation() { GFXTestSuite::setCustomColor(255, 0, 0); Testsuite::clearScreen(); - if(Testsuite::handleInteractiveInput("Did you see a rotation in colors of rectangles displayed on screen?", "Yes", "No", kOptionRight)) { + if (Testsuite::handleInteractiveInput("Did you see a rotation in colors of rectangles displayed on screen?", "Yes", "No", kOptionRight)) { return kTestFailed; } @@ -1121,7 +1121,7 @@ TestExitStatus GFXtests::pixelFormats() { g_system->updateScreen(); g_system->delayMillis(500); - if(Testsuite::handleInteractiveInput("Were you able to notice the colored rectangles on the screen for this format?", "Yes", "No", kOptionLeft)) { + if (Testsuite::handleInteractiveInput("Were you able to notice the colored rectangles on the screen for this format?", "Yes", "No", kOptionLeft)) { numPassed++; } else { numFailed++; diff --git a/engines/testbed/testsuite.cpp b/engines/testbed/testsuite.cpp index 655179aa74..39eeca31bd 100644 --- a/engines/testbed/testsuite.cpp +++ b/engines/testbed/testsuite.cpp @@ -289,7 +289,7 @@ void Testsuite::execute() { continue; } - if((*i)->isInteractive && !ConfParams.isSessionInteractive()) { + if ((*i)->isInteractive && !ConfParams.isSessionInteractive()) { logPrintf("Info! Skipping Test: %s, non-interactive environment is selected\n", ((*i)->featureName).c_str()); _numTestsSkipped++; continue; diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 0f662e22bd..2e4be33e53 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -63,6 +63,14 @@ uint16 TinselEngine::getVersion() const { return _gameDescription->version; } +bool TinselEngine::getIsADGFDemo() const { + return (bool)(_gameDescription->desc.flags & ADGF_DEMO); +} + +bool TinselEngine::isCD() const { + return (bool)(_gameDescription->desc.flags & ADGF_CD); +} + } // End of namespace Tinsel static const PlainGameDescriptor tinselGames[] = { diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h index be44b1c462..631c2dce14 100644 --- a/engines/tinsel/detection_tables.h +++ b/engines/tinsel/detection_tables.h @@ -47,7 +47,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_DEMO, + 0, TINSEL_V0, }, @@ -61,12 +61,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_DEMO, + ADGF_DEMO | ADGF_CD, GUIO0() }, GID_DW1, 0, - GF_CD, + 0, TINSEL_V1, }, #if 0 @@ -81,12 +81,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_DEMO, + ADGF_DEMO | ADGF_CD, GUIO0() }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_BIG_ENDIAN, + GF_SCNFILES, TINSEL_V1, }, #endif @@ -110,7 +110,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -133,7 +133,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -156,7 +156,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -179,7 +179,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_FLOPPY | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -195,7 +195,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_FLOPPY | GF_ENHANCED_AUDIO_SUPPORT, + GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -214,7 +214,42 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_ENHANCED_AUDIO_SUPPORT, + GF_ENHANCED_AUDIO_SUPPORT, + TINSEL_V1, + }, + + { // Polish fan translation CD V1 version, with *.gra files (same as the floppy one, with english.smp) + { + "dw", + "CD", + { + {"dw.gra", 0, "ef05bbd2a754bd11a2e87bcd84ab5ccf", 781864}, + {"english.smp", 0, NULL, -1}, + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_CD, + GUIO_NONE + }, + GID_DW1, + 0, + GF_ENHANCED_AUDIO_SUPPORT, + TINSEL_V1, + }, + + { // Polish fan translaction floppy V1 version, with *.gra files + { + "dw", + "Floppy", + AD_ENTRY1s("dw.gra", "ef05bbd2a754bd11a2e87bcd84ab5ccf", 781864), + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSPEECH + }, + GID_DW1, + 0, + GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -236,7 +271,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -261,7 +296,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -280,12 +315,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_DROPLANGUAGE | ADGF_CD, + ADGF_DROPLANGUAGE, GUIO0() }, GID_DW1, 0, - GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, { @@ -308,7 +343,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, { @@ -331,7 +366,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -351,7 +386,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -371,7 +406,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -390,14 +425,14 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, { // multilanguage PSX demo { "dw", - "CD demo", + "CD Demo", { {"french.txt", 0, "e7020d35f58d0d187052ac406d86cc87", 273914}, {"german.txt", 0, "52f0a01e0ff0d340b02a36fd5109d705", 263942}, @@ -408,12 +443,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPSX, - ADGF_DEMO, + ADGF_CD | ADGF_DEMO, GUIO0() }, GID_DW1, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V1, }, @@ -434,7 +469,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, #endif @@ -456,7 +491,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_BIG_ENDIAN, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, @@ -475,7 +510,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_ALT_MIDI, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT | GF_ALT_MIDI, TINSEL_V1, }, @@ -496,11 +531,32 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_CD | GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + TINSEL_V1, + }, + + { // Polish fan translaction Discworld 1 + { + "dw", + "CD", + { + {"dw.scn", 0, "fa169d2c98660215ebd84b49c1899eef", 776396}, + {"english.txt", 0, "c1a53eb7ec812689dab70e2bb22cf2ab", 224151}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::PL_POL, + Common::kPlatformPC, + ADGF_CD, + GUIO_NONE + }, + GID_DW1, + 0, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, - { // English DW2 demo + { // English Discworld 2 demo { "dw2", "Demo", @@ -511,12 +567,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_DEMO, + ADGF_DEMO | ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES | GF_DEMO, + GF_SCNFILES, TINSEL_V2, }, @@ -531,12 +587,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_GRB, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, @@ -551,12 +607,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_USA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, @@ -571,12 +627,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, @@ -591,12 +647,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, @@ -612,12 +668,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, { @@ -632,12 +688,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, @@ -653,12 +709,12 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::RU_RUS, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO1(GUIO_NOASPECT) }, GID_DW2, 0, - GF_CD | GF_SCNFILES, + GF_SCNFILES, TINSEL_V2, }, diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp index fbe9e8d1f6..56ee2ea752 100644 --- a/engines/tinsel/dialogs.cpp +++ b/engines/tinsel/dialogs.cpp @@ -753,6 +753,11 @@ static CONFBOX t1RestartBox[] = { #endif }; +static CONFBOX t1RestartBoxPSX[] = { + { AAGBUT, INITGAME, TM_NONE, NULL, USE_POINTER, 122, 48, 23, 19, NULL, IX1_TICK1 }, + { AAGBUT, CLOSEWIN, TM_NONE, NULL, USE_POINTER, 82, 48, 23, 19, NULL, IX1_CROSS1 } +}; + static CONFBOX t2RestartBox[] = { { AAGBUT, INITGAME, TM_NONE, NULL, 0, 140, 78, BW, BH, NULL, IX2_TICK1 }, { AAGBUT, CLOSEWIN, TM_NONE, NULL, 0, 60, 78, BW, BH, NULL, IX2_CROSS1 } @@ -763,10 +768,10 @@ static CONFINIT t1ciRestart = { 6, 2, 72, 53, false, t1RestartBox, ARRAYSIZE(t1R #else static CONFINIT t1ciRestart = { 4, 2, 98, 53, false, t1RestartBox, ARRAYSIZE(t1RestartBox), SIX_RESTART_HEADING }; #endif +static CONFINIT t1ciRestartPSX = { 8, 2, 46, 53, false, t1RestartBoxPSX, ARRAYSIZE(t1RestartBoxPSX), SIX_RESTART_HEADING }; static CONFINIT t2ciRestart = { 4, 2, 196, 53, false, t2RestartBox, sizeof(t2RestartBox)/sizeof(CONFBOX), SS_RESTART_HEADING }; -#define ciRestart (TinselV2 ? t2ciRestart : t1ciRestart) -#define restartBox (TinselV2 ? t2RestartBox : t1RestartBox) +#define ciRestart (TinselV2 ? t2ciRestart : (TinselV1PSX ? t1ciRestartPSX : t1ciRestart)) /*-------------------------------------------------------------*\ | This is the sound control 'menu'. In Discworld 2, it also | @@ -1038,18 +1043,20 @@ static bool RePosition(); static bool LanguageChange() { LANGUAGE nLang = _vm->_config->_language; - if (_vm->getFeatures() & GF_USE_3FLAGS) { - // VERY quick dodgy bodge - if (cd.selBox == 0) - nLang = TXT_FRENCH; // = 1 - else if (cd.selBox == 1) - nLang = TXT_GERMAN; // = 2 - else - nLang = TXT_SPANISH; // = 4 - } else if (_vm->getFeatures() & GF_USE_4FLAGS) { - nLang = (LANGUAGE)(cd.selBox + 1); - } else if (_vm->getFeatures() & GF_USE_5FLAGS) { - nLang = (LANGUAGE)cd.selBox; + if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) { + // Languages: TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, TXT_ITALIAN, TXT_SPANISH + // 5 flag versions include English + int selected = (_vm->getFeatures() & GF_USE_5FLAGS) ? cd.selBox : cd.selBox + 1; + // Make sure that a language flag has been selected. If the user has + // changed the language speed slider and hasn't clicked on a flag, it + // won't be selected. + if (selected >= 0 && selected <= 4) { + nLang = (LANGUAGE)selected; + + // 3 flag versions don't include Italian + if (selected >= 3 && (_vm->getFeatures() & GF_USE_3FLAGS)) + nLang = TXT_SPANISH; + } } if (nLang != _vm->_config->_language) { @@ -1256,6 +1263,20 @@ static INV_OBJECT *GetInvObject(int id) { } /** + * Returns true if the given id represents a valid inventory object + */ +bool GetIsInvObject(int id) { + INV_OBJECT *pObject = g_invObjects; + + for (int i = 0; i < g_numObjects; i++, pObject++) { + if (pObject->id == id) + return true; + } + + return false; +} + +/** * Convert item ID number to index. */ static int GetObjectIndex(int id) { diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h index 8c48eb8b76..ab53ba771c 100644 --- a/engines/tinsel/dialogs.h +++ b/engines/tinsel/dialogs.h @@ -152,6 +152,8 @@ void InvSetLimit(int invno, int n); void InvSetSize(int invno, int MinWidth, int MinHeight, int StartWidth, int StartHeight, int MaxWidth, int MaxHeight); +bool GetIsInvObject(int id); + int WhichInventoryOpen(); bool IsTopWindow(); diff --git a/engines/tinsel/drives.cpp b/engines/tinsel/drives.cpp index 5c4b939e4e..3ecef83753 100644 --- a/engines/tinsel/drives.cpp +++ b/engines/tinsel/drives.cpp @@ -149,7 +149,7 @@ bool GotoCD() { bool TinselFile::_warningShown = false; -TinselFile::TinselFile() : ReadStreamEndian((_vm->getFeatures() & GF_BIG_ENDIAN) != 0) { +TinselFile::TinselFile() : ReadStreamEndian(TinselV1Mac) { _stream = NULL; } diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index c3089db990..14d588dcec 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -99,14 +99,16 @@ void SetupHandleTable() { MEMHANDLE *pH; TinselFile f; - if (f.open(TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME)) { + const char *indexFileName = TinselV1PSX ? PSX_INDEX_FILENAME : INDEX_FILENAME; + + if (f.open(indexFileName)) { // get size of index file len = f.size(); if (len > 0) { if ((len % RECORD_SIZE) != 0) { // index file is corrupt - error(FILE_IS_CORRUPT, TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME); + error(FILE_IS_CORRUPT, indexFileName); } // calc number of handles @@ -132,16 +134,16 @@ void SetupHandleTable() { if (f.eos() || f.err()) { // index file is corrupt - error(FILE_IS_CORRUPT, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME)); + error(FILE_IS_CORRUPT, indexFileName); } // close the file f.close(); } else { // index file is corrupt - error(FILE_IS_CORRUPT, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME)); + error(FILE_IS_CORRUPT, indexFileName); } } else { // cannot find the index file - error(CANNOT_FIND_FILE, (TinselV1PSX? PSX_INDEX_FILENAME : INDEX_FILENAME)); + error(CANNOT_FIND_FILE, indexFileName); } // allocate memory nodes and load all permanent graphics diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 781a378f13..b3bfbcc5dc 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -131,21 +131,13 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { g_currentMidi = dwFileOffset; g_currentLoop = bLoop; - // Tinsel V1 PSX uses a different music format, so i - // disable it here. - // TODO: Maybe this should be moved to a better place... - if (TinselV1PSX) return false; + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); - if (_vm->_config->_musicVolume != 0) { - bool mute = false; - if (ConfMan.hasKey("mute")) - mute = ConfMan.getBool("mute"); - - SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume); - } + SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume); // the index and length of the last tune loaded - static uint32 dwLastMidiIndex = 0; // FIXME: Avoid non-const global vars uint32 dwSeqLen = 0; // length of the sequence // Support for external music from the music enhancement project @@ -186,61 +178,53 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { if (dwFileOffset == 0) return true; - if (dwFileOffset != dwLastMidiIndex) { - Common::File midiStream; - - // open MIDI sequence file in binary mode - if (!midiStream.open(MIDI_FILE)) - error(CANNOT_FIND_FILE, MIDI_FILE); - - // update index of last tune loaded - dwLastMidiIndex = dwFileOffset; - - // move to correct position in the file - midiStream.seek(dwFileOffset, SEEK_SET); - - // read the length of the sequence - dwSeqLen = midiStream.readUint32LE(); - - // make sure buffer is large enough for this sequence - assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size); - - // stop any currently playing tune - _vm->_midiMusic->stop(); - - // read the sequence - if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen) - error(FILE_IS_CORRUPT, MIDI_FILE); - - midiStream.close(); - - // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii", - // which actually affects all ports, since it's specific to the GRA version. - // - // The GRA version does not seem to set the channel volume at all for the first - // intro track, thus we need to do that here. We only initialize the channels - // used in that sequence. And we are using 127 as default channel volume. - // - // Only in the GRA version dwFileOffset can be "38888", just to be sure, we - // check for the SCN files feature flag not being set though. - if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) { - _vm->_midiMusic->send(0x7F07B0 | 3); - _vm->_midiMusic->send(0x7F07B0 | 5); - _vm->_midiMusic->send(0x7F07B0 | 8); - _vm->_midiMusic->send(0x7F07B0 | 10); - _vm->_midiMusic->send(0x7F07B0 | 13); - } + Common::File midiStream; - _vm->_midiMusic->playXMIDI(g_midiBuffer.pDat, dwSeqLen, bLoop); + // open MIDI sequence file in binary mode + if (!midiStream.open(MIDI_FILE)) + error(CANNOT_FIND_FILE, MIDI_FILE); - // Store the length - //dwLastSeqLen = dwSeqLen; - } else { - // dwFileOffset == dwLastMidiIndex - _vm->_midiMusic->stop(); - _vm->_midiMusic->playXMIDI(g_midiBuffer.pDat, dwSeqLen, bLoop); + // move to correct position in the file + midiStream.seek(dwFileOffset, SEEK_SET); + + // read the length of the sequence + dwSeqLen = midiStream.readUint32LE(); + + // make sure buffer is large enough for this sequence + assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size); + + // stop any currently playing tune + _vm->_midiMusic->stop(); + + // read the sequence. This needs to be read again before playSEQ() is + // called even if the music is restarting, as playSEQ() reads the file + // name off the buffer itself. However, that function adds SMF headers + // to the buffer, thus if it's read again, the SMF headers will be read + // and the filename will always be 'MThd'. + if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen) + error(FILE_IS_CORRUPT, MIDI_FILE); + + midiStream.close(); + + // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii", + // which actually affects all ports, since it's specific to the GRA version. + // + // The GRA version does not seem to set the channel volume at all for the first + // intro track, thus we need to do that here. We only initialize the channels + // used in that sequence. And we are using 127 as default channel volume. + // + // Only in the GRA version dwFileOffset can be "38888", just to be sure, we + // check for the SCN files feature flag not being set though. + if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) { + _vm->_midiMusic->send(0x7F07B0 | 3); + _vm->_midiMusic->send(0x7F07B0 | 5); + _vm->_midiMusic->send(0x7F07B0 | 8); + _vm->_midiMusic->send(0x7F07B0 | 10); + _vm->_midiMusic->send(0x7F07B0 | 13); } + _vm->_midiMusic->playMIDI(dwSeqLen, bLoop); + return true; } @@ -284,27 +268,7 @@ int GetMidiVolume() { */ void SetMidiVolume(int vol) { assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume); - - static int priorVolMusic = 0; // FIXME: Avoid non-const global vars - - if (vol == 0 && priorVolMusic == 0) { - // Nothing to do - } else if (vol == 0 && priorVolMusic != 0) { - // Stop current midi sequence - StopMidi(); - _vm->_midiMusic->setVolume(vol); - } else if (vol != 0 && priorVolMusic == 0) { - // Perhaps restart last midi sequence - if (g_currentLoop) - PlayMidiSequence(g_currentMidi, true); - - _vm->_midiMusic->setVolume(vol); - } else if (vol != 0 && priorVolMusic != 0) { - // Alter current volume - _vm->_midiMusic->setVolume(vol); - } - - priorVolMusic = vol; + _vm->_midiMusic->setVolume(vol); } /** @@ -314,8 +278,7 @@ void OpenMidiFiles() { Common::File midiStream; // Demo version has no midi file - // Also, Discworld PSX uses still unsupported psx SEQ format for music... - if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2) || TinselV1PSX) + if (TinselV0 || TinselV2) return; if (g_midiBuffer.pDat) @@ -412,7 +375,7 @@ void MidiMusicPlayer::send(uint32 b) { } } -void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) { +void MidiMusicPlayer::playMIDI(uint32 size, bool loop) { Common::StackLock lock(_mutex); if (_isPlaying) @@ -420,6 +383,13 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) { stop(); + if (TinselV1PSX) + playSEQ(size, loop); + else + playXMIDI(size, loop); +} + +void MidiMusicPlayer::playXMIDI(uint32 size, bool loop) { // It seems like not all music (the main menu music, for instance) set // all the instruments explicitly. That means the music will sound // different, depending on which music played before it. This appears @@ -433,7 +403,78 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) { // Load XMID resource data MidiParser *parser = MidiParser::createParser_XMIDI(); - if (parser->loadMusic(midiData, size)) { + if (parser->loadMusic(g_midiBuffer.pDat, size)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1); + + _parser = parser; + + _isLooping = loop; + _isPlaying = true; + } else { + delete parser; + } +} + +void MidiMusicPlayer::playSEQ(uint32 size, bool loop) { + // MIDI.DAT holds the file names in DW1 PSX + Common::String baseName((char *)g_midiBuffer.pDat, size); + Common::String seqName = baseName + ".SEQ"; + + // TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH) + + Common::File seqFile; + if (!seqFile.open(seqName)) + error("Failed to open SEQ file '%s'", seqName.c_str()); + + if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p')) + error("Failed to find SEQp tag"); + + // Make sure we don't have a SEP file (with multiple SEQ's inside) + if (seqFile.readUint32BE() != 1) + error("Can only play SEQ files, not SEP"); + + uint16 ppqn = seqFile.readUint16BE(); + uint32 tempo = seqFile.readUint16BE() << 8; + tempo |= seqFile.readByte(); + /* uint16 beat = */ seqFile.readUint16BE(); + + // SEQ is directly based on SMF and we'll use that to our advantage here + // and convert to SMF and then use the SMF MidiParser. + + // Calculate the SMF size we'll need + uint32 dataSize = seqFile.size() - 15; + uint32 actualSize = dataSize + 7 + 22; + + // Resize the buffer if necessary + if (g_midiBuffer.size < actualSize) { + g_midiBuffer.pDat = (byte *)realloc(g_midiBuffer.pDat, actualSize); + assert(g_midiBuffer.pDat); + } + + // Now construct the header + WRITE_BE_UINT32(g_midiBuffer.pDat, MKTAG('M', 'T', 'h', 'd')); + WRITE_BE_UINT32(g_midiBuffer.pDat + 4, 6); // header size + WRITE_BE_UINT16(g_midiBuffer.pDat + 8, 0); // type 0 + WRITE_BE_UINT16(g_midiBuffer.pDat + 10, 1); // one track + WRITE_BE_UINT16(g_midiBuffer.pDat + 12, ppqn); + WRITE_BE_UINT32(g_midiBuffer.pDat + 14, MKTAG('M', 'T', 'r', 'k')); + WRITE_BE_UINT32(g_midiBuffer.pDat + 18, dataSize + 7); // SEQ data size + tempo change event size + + // Add in a fake tempo change event + WRITE_BE_UINT32(g_midiBuffer.pDat + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3 + WRITE_BE_UINT16(g_midiBuffer.pDat + 26, tempo >> 8); + g_midiBuffer.pDat[28] = tempo & 0xFF; + + // Now copy in the rest of the events + seqFile.read(g_midiBuffer.pDat + 29, dataSize); + seqFile.close(); + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(g_midiBuffer.pDat, actualSize)) { parser->setTrack(0); parser->setMidiDriver(this); parser->setTimerRate(getBaseTempo()); @@ -870,14 +911,12 @@ void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) { g_currentMidi = Midi; g_currentLoop = Loop; - if (_vm->_config->_musicVolume != 0 && Loop) { - bool mute = false; - if (ConfMan.hasKey("mute")) - mute = ConfMan.getBool("mute"); + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); - PlayMidiSequence(g_currentMidi, true); - SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume); - } + PlayMidiSequence(g_currentMidi, true); + SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume); } #if 0 diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h index d43fed268d..121bf3d79b 100644 --- a/engines/tinsel/music.h +++ b/engines/tinsel/music.h @@ -64,7 +64,7 @@ public: virtual void setVolume(int volume); - void playXMIDI(byte *midiData, uint32 size, bool loop); + void playMIDI(uint32 size, bool loop); // void stop(); void pause(); @@ -76,6 +76,10 @@ public: // The original sets the "sequence timing" to 109 Hz, whatever that // means. The default is 120. uint32 getBaseTempo() { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; } + +private: + void playXMIDI(uint32 size, bool loop); + void playSEQ(uint32 size, bool loop); }; class PCMMusicPlayer : public Audio::AudioStream { diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 60f04b47fd..6ea18c8268 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -122,6 +122,8 @@ static uint32 g_hMasterScript; struct WorkaroundEntry { TinselEngineVersion version; ///< Engine version this workaround applies to bool scnFlag; ///< Only applicable for Tinsel 1 (DW 1) + bool isDemo; ///< Flags whether it's for a demo + Common::Platform platform; ///< Platform filter SCNHANDLE hCode; ///< Script to apply fragment to int ip; ///< Script offset to run this fragment before int numBytes; ///< Number of bytes in the script @@ -129,6 +131,7 @@ struct WorkaroundEntry { }; #define FRAGMENT_WORD(x) (byte)(x & 0xFF), (byte)(x >> 8) +#define FRAGMENT_DWORD(x) (byte)(x & 0xFF), (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24) static const byte fragment1[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 206, 0}; static const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110}; @@ -149,6 +152,10 @@ static const byte fragment12[] = {OP_JMPTRUE | OPSIZE16, FRAGMENT_WORD(1491), OP_IMM | OPSIZE16, FRAGMENT_WORD(322), OP_LIBCALL | OPSIZE8, 46, // Give back the whistle OP_JUMP | OPSIZE16, FRAGMENT_WORD(1568)}; static const byte fragment13[] = {OP_ZERO, OP_GSTORE | OPSIZE16, FRAGMENT_WORD(306)}; +static const byte fragment14[] = {OP_LIBCALL | OPSIZE8, 58, + OP_IMM, FRAGMENT_DWORD((42 << 23)), OP_ONE, OP_ZERO, OP_LIBCALL | OPSIZE8, 44, + OP_LIBCALL | OPSIZE8, 97, OP_JUMP | OPSIZE16, FRAGMENT_WORD(2220) +}; #undef FRAGMENT_WORD @@ -157,7 +164,7 @@ const WorkaroundEntry workaroundList[] = { // book back to the present. In the GRA version, it was global 373, // and was reset when he is returned to the past, but was forgotten // in the SCN version, so this ensures the flag is properly reset. - {TINSEL_V1, true, 427942095, 1, sizeof(fragment1), fragment1}, + {TINSEL_V1, true, false, Common::kPlatformUnknown, 427942095, 1, sizeof(fragment1), fragment1}, // DW1-GRA: Rincewind exiting the Inn is blocked by the luggage. // Whilst you can then move into walkable areas, saving and @@ -165,26 +172,26 @@ const WorkaroundEntry workaroundList[] = { // fragment turns off NPC blocking for the Outside Inn rooms so that // the luggage won't block Past Outside Inn. // See bug report #2525010. - {TINSEL_V1, false, 444622076, 0, sizeof(fragment2), fragment2}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 444622076, 0, sizeof(fragment2), fragment2}, // Present Outside Inn - {TINSEL_V1, false, 352600876, 0, sizeof(fragment2), fragment2}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 352600876, 0, sizeof(fragment2), fragment2}, // DW1-GRA: Talking to palace guards in Act 2 gives !!!HIGH // STRING||| - this happens if you initiate dialog with one of the // guards, but not the other. So these fragments provide the correct // talk parameters where needed. // See bug report #2831159. - {TINSEL_V1, false, 310506872, 463, sizeof(fragment4), fragment4}, - {TINSEL_V1, false, 310506872, 485, sizeof(fragment5), fragment5}, - {TINSEL_V1, false, 310506872, 513, sizeof(fragment6), fragment6}, - {TINSEL_V1, false, 310506872, 613, sizeof(fragment7), fragment7}, - {TINSEL_V1, false, 310506872, 641, sizeof(fragment8), fragment8}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 463, sizeof(fragment4), fragment4}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 485, sizeof(fragment5), fragment5}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 513, sizeof(fragment6), fragment6}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 613, sizeof(fragment7), fragment7}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 310506872, 641, sizeof(fragment8), fragment8}, // DW1-SCN: The script for the lovable street-Starfish does a // 'StopSample' after flicking the coin to ensure it's sound is // stopped, but which also accidentally can stop any active // conversation with the Amazon. - {TINSEL_V1, true, 394640351, 121, sizeof(fragment9), fragment9}, + {TINSEL_V1, true, false, Common::kPlatformUnknown, 394640351, 121, sizeof(fragment9), fragment9}, // DW2: In the garden, global #490 is set when the bees begin their // 'out of hive' animation, and reset when done. But if the game is @@ -197,25 +204,29 @@ const WorkaroundEntry workaroundList[] = { // * Stealing the mallets from the wizards (bug #2820788). // This fix ensures that the global is reset when the Garden scene // is loaded (both entering and restoring a game). - {TINSEL_V2, true, 2888147476U, 0, sizeof(fragment3), fragment3}, + {TINSEL_V2, true, false, Common::kPlatformUnknown, 2888147476U, 0, sizeof(fragment3), fragment3}, // DW1-GRA: Corrects text being drawn partially off-screen during // the blackboard description of the Librarian. - {TINSEL_V1, false, 293831402, 133, sizeof(fragment10), fragment10}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 293831402, 133, sizeof(fragment10), fragment10}, // DW1-GRA/SCN: Corrects the dead-end of being able to give the // whistle back to the pirate before giving him the parrot. // See bug report #2934211. - {TINSEL_V1, true, 352601285, 1569, sizeof(fragment11), fragment11}, - {TINSEL_V1, false, 352602304, 1488, sizeof(fragment12), fragment12}, + {TINSEL_V1, true, false, Common::kPlatformUnknown, 352601285, 1569, sizeof(fragment11), fragment11}, + {TINSEL_V1, false, false, Common::kPlatformUnknown, 352602304, 1488, sizeof(fragment12), fragment12}, // DW2: Corrects a bug with global 306 not being cleared if you leave // the marketplace scene whilst D'Blah is talking (even if it's not // actually audible); returning to the scene and clicking on him multiple // times would cause the game to crash - {TINSEL_V2, true, 1109294728, 0, sizeof(fragment13), fragment13}, + {TINSEL_V2, true, false, Common::kPlatformUnknown, 1109294728, 0, sizeof(fragment13), fragment13}, + + // DW1 PSX DEMO: Alters a script in the PSX DW1 demo to show the Idle animation scene rather than + // quitting the game when no user input happens for a while + {TINSEL_V1, true, true, Common::kPlatformPSX, 0, 2186, sizeof(fragment14), fragment14}, - {TINSEL_V0, false, 0, 0, 0, NULL} + {TINSEL_V0, false, false, Common::kPlatformUnknown, 0, 0, 0, NULL} }; //----------------- LOCAL GLOBAL DATA -------------------- @@ -582,6 +593,8 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { if ((wkEntry->version == TinselVersion) && (wkEntry->hCode == ic->hCode) && (wkEntry->ip == ip) && + (wkEntry->isDemo == _vm->getIsADGFDemo()) && + ((wkEntry->platform == Common::kPlatformUnknown) || (wkEntry->platform == _vm->getPlatform())) && (!TinselV1 || (wkEntry->scnFlag == ((_vm->getFeatures() & GF_SCNFILES) != 0)))) { // Point to start of workaround fragment ip = 0; diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 0a552c8c2b..518e27f02b 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -55,8 +55,7 @@ namespace Tinsel { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 1 -// TODO: Not yet used +#define CURRENT_VER 2 /** * An auxillary macro, used to specify savegame versions. We use this instead @@ -97,12 +96,13 @@ struct SaveGameHeader { TimeDate dateTime; bool scnFlag; byte language; + uint16 numInterpreters; // Savegame version 2 or later only }; enum { DW1_SAVEGAME_ID = 0x44575399, // = 'DWSc' = "DiscWorld 1 ScummVM" DW2_SAVEGAME_ID = 0x44573253, // = 'DW2S' = "DiscWorld 2 ScummVM" - SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7 + 1 + 1 + SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7 + 1 + 1 + 2 }; #define SAVEGAME_ID (TinselV2 ? (uint32)DW2_SAVEGAME_ID : (uint32)DW1_SAVEGAME_ID) @@ -186,6 +186,15 @@ static bool syncSaveGameHeader(Common::Serializer &s, SaveGameHeader &hdr) { } } + // Handle the number of interpreter contexts that will be saved in the savegame + if (tmp >= 2) { + tmp -= 2; + hdr.numInterpreters = NUM_INTERPRET; + s.syncAsUint16LE(hdr.numInterpreters); + } else { + hdr.numInterpreters = (TinselV2 ? 70 : 64) - 20; + } + // Skip over any extra bytes s.skip(tmp); return true; @@ -262,7 +271,7 @@ static void syncSoundReel(Common::Serializer &s, SOUNDREELS &sr) { s.syncAsSint32LE(sr.actorCol); } -static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd) { +static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd, int numInterp) { s.syncAsUint32LE(sd.SavedSceneHandle); s.syncAsUint32LE(sd.SavedBgroundHandle); for (int i = 0; i < MAX_MOVERS; ++i) @@ -273,7 +282,7 @@ static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd) { s.syncAsSint32LE(sd.NumSavedActors); s.syncAsSint32LE(sd.SavedLoffset); s.syncAsSint32LE(sd.SavedToffset); - for (int i = 0; i < NUM_INTERPRET; ++i) + for (int i = 0; i < numInterp; ++i) sd.SavedICInfo[i].syncWithSerializer(s); for (int i = 0; i < MAX_POLY; ++i) s.syncAsUint32LE(sd.SavedDeadPolys[i]); @@ -422,7 +431,7 @@ char *ListEntry(int i, letype which) { return NULL; } -static void DoSync(Common::Serializer &s) { +static bool DoSync(Common::Serializer &s, int numInterp) { int sg = 0; if (TinselV2) { @@ -434,7 +443,7 @@ static void DoSync(Common::Serializer &s) { if (TinselV2 && s.isLoading()) HoldItem(INV_NOICON); - syncSavedData(s, *g_srsd); + syncSavedData(s, *g_srsd, numInterp); syncGlobInfo(s); // Glitter globals syncInvInfo(s); // Inventory data @@ -443,6 +452,10 @@ static void DoSync(Common::Serializer &s) { sg = WhichItemHeld(); s.syncAsSint32LE(sg); if (s.isLoading()) { + if (sg != -1 && !GetIsInvObject(sg)) + // Not a valid inventory object, so return false + return false; + if (TinselV2) g_thingHeld = sg; else @@ -459,7 +472,7 @@ static void DoSync(Common::Serializer &s) { if (*g_SaveSceneSsCount != 0) { SAVED_DATA *sdPtr = g_SaveSceneSsData; for (int i = 0; i < *g_SaveSceneSsCount; ++i, ++sdPtr) - syncSavedData(s, *sdPtr); + syncSavedData(s, *sdPtr, numInterp); // Flag that there is a saved scene to return to. Note that in this context 'saved scene' // is a stored scene to return to from another scene, such as from the Summoning Book close-up @@ -469,6 +482,8 @@ static void DoSync(Common::Serializer &s) { if (!TinselV2) syncAllActorsAlive(s); + + return true; } /** @@ -487,8 +502,23 @@ static bool DoRestore() { delete f; // Invalid header, or savegame too new -> skip it return false; } + + // Load in the data. For older savegame versions, we potentially need to load the data twice, once + // for pre 1.5 savegames, and if that fails, a second time for 1.5 savegames + int numInterpreters = hdr.numInterpreters; + int32 currentPos = f->pos(); + for (int tryNumber = 0; tryNumber < ((hdr.ver >= 2) ? 1 : 2); ++tryNumber) { + // If it's the second loop iteration, try with the 1.5 savegame number of interpreter contexts + if (tryNumber == 1) { + f->seek(currentPos); + numInterpreters = 80; + } - DoSync(s); + // Load the savegame data + if (DoSync(s, numInterpreters)) + // Data load was successful (or likely), so break out of loop + break; + } uint32 id = f->readSint32LE(); if (id != (uint32)0xFEEDFACE) @@ -575,7 +605,7 @@ static void DoSave() { return; } - DoSync(s); + DoSync(s, hdr.numInterpreters); // Write out the special Id for Discworld savegames f->writeUint32LE(0xFEEDFACE); diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h index baaff27a3e..06e5c096d9 100644 --- a/engines/tinsel/scene.h +++ b/engines/tinsel/scene.h @@ -75,9 +75,9 @@ enum REEL { typedef enum { TRANS_DEF, TRANS_CUT, TRANS_FADE } TRANSITS; // amount to shift scene handles by -#define SCNHANDLE_SHIFT ((TinselV2 && !IsDemo) ? 25 : 23) -#define OFFSETMASK ((TinselV2 && !IsDemo) ? 0x01ffffffL : 0x007fffffL) -#define HANDLEMASK ((TinselV2 && !IsDemo) ? 0xFE000000L : 0xFF800000L) +#define SCNHANDLE_SHIFT ((TinselV2 && !TinselV2Demo) ? 25 : 23) +#define OFFSETMASK ((TinselV2 && !TinselV2Demo) ? 0x01ffffffL : 0x007fffffL) +#define HANDLEMASK ((TinselV2 && !TinselV2Demo) ? 0xFE000000L : 0xFF800000L) void DoHailScene(SCNHANDLE scene); diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index f575b03270..e052302cfd 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -75,7 +75,7 @@ SoundManager::~SoundManager() { // playSample for DiscWorld 1 bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { // Floppy version has no sample file - if (_vm->getFeatures() & GF_FLOPPY) + if (!_vm->isCD()) return false; // no sample driver? @@ -182,7 +182,7 @@ bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int p Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { // Floppy version has no sample file - if (_vm->getFeatures() & GF_FLOPPY) + if (!_vm->isCD()) return false; // no sample driver? @@ -471,7 +471,7 @@ void SoundManager::setSFXVolumes(uint8 volume) { */ void SoundManager::openSampleFiles() { // Floppy and demo versions have no sample files, except for the Discworld 2 demo - if (_vm->getFeatures() & GF_FLOPPY || (IsDemo && !TinselV2)) + if (!_vm->isCD() || TinselV0) return; TinselFile f; diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index dfa44c505a..058f8eb6fd 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -1625,10 +1625,6 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int * Play a midi file. */ static void PlayMidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) { - // FIXME: This is a workaround for the FIXME below - if (GetMidiVolume() == 0 || TinselV1PSX) - return; - CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -1637,18 +1633,13 @@ static void PlayMidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) { PlayMidiSequence(hMidi, loop == MIDI_LOOP); - // FIXME: The following check messes up the script arguments when - // entering the secret door in the bookshelf in the library, - // leading to a crash, when the music volume is set to 0 (MidiPlaying() - // always false then). - // - // Why exactly this happens is unclear. An analysis of the involved - // script(s) might reveal more. - // - // Note: This check&sleep was added in DW v2. It was most likely added - // to ensure that the MIDI song started playing before the next opcode + // This check&sleep was added in DW v2. It was most likely added to + // ensure that the MIDI song started playing before the next opcode // is executed. - if (!MidiPlaying()) + // In DW1, it messes up the script arguments when entering the secret + // door in the bookshelf in the library, leading to a crash, when the + // music volume is set to 0. + if (!MidiPlaying() && TinselV2) CORO_SLEEP(1); if (complete) { @@ -3412,7 +3403,7 @@ static void TalkOrSay(CORO_PARAM, SPEECH_TYPE speechType, SCNHANDLE hText, int x // Kick off the sample now (perhaps with a delay) if (g_bNoPause) g_bNoPause = false; - else if (!IsDemo) + else if (!TinselV2Demo) CORO_SLEEP(SysVar(SV_SPEECHDELAY)); //SamplePlay(VOICE, hText, _ctx->sub, false, -1, -1, PRIORITY_TALK); @@ -4244,7 +4235,7 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi int libCode; if (TinselV0) libCode = DW1DEMO_CODES[operand]; else if (!TinselV2) libCode = DW1_CODES[operand]; - else if (_vm->getFeatures() & GF_DEMO) libCode = DW2DEMO_CODES[operand]; + else if (TinselV2Demo) libCode = DW2DEMO_CODES[operand]; else libCode = DW2_CODES[operand]; debug(7, "CallLibraryRoutine op %d (escOn %d, myEscape %d)", operand, pic->escOn, pic->myEscape); diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 59344c44f4..123249125e 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -53,7 +53,6 @@ class Config; class MidiDriver; class MidiMusicPlayer; class PCMMusicPlayer; -class Scheduler; class SoundManager; typedef Common::List<Common::Rect> RectList; @@ -64,21 +63,16 @@ enum TinselGameID { }; enum TinselGameFeatures { - GF_DEMO = 1 << 0, - GF_CD = 1 << 1, - GF_FLOPPY = 1 << 2, - GF_SCNFILES = 1 << 3, - GF_ENHANCED_AUDIO_SUPPORT = 1 << 4, - GF_ALT_MIDI = 1 << 5, // Alternate sequence in midi.dat file + GF_SCNFILES = 1 << 0, + GF_ENHANCED_AUDIO_SUPPORT = 1 << 1, + GF_ALT_MIDI = 1 << 2, // Alternate sequence in midi.dat file // The GF_USE_?FLAGS values specify how many country flags are displayed // in the subtitles options dialog. // None of these defined -> 1 language, in ENGLISH.TXT - GF_USE_3FLAGS = 1 << 6, // French, German, Spanish - GF_USE_4FLAGS = 1 << 7, // French, German, Spanish, Italian - GF_USE_5FLAGS = 1 << 8, // All 5 flags - - GF_BIG_ENDIAN = 1 << 9 + GF_USE_3FLAGS = 1 << 3, // French, German, Spanish + GF_USE_4FLAGS = 1 << 4, // French, German, Spanish, Italian + GF_USE_5FLAGS = 1 << 5 // All 5 flags }; /** @@ -135,13 +129,12 @@ typedef bool (*KEYFPTR)(const Common::KeyState &); #define TinselV0 (TinselVersion == TINSEL_V0) #define TinselV1 (TinselVersion == TINSEL_V1) #define TinselV2 (TinselVersion == TINSEL_V2) +#define TinselV2Demo (TinselVersion == TINSEL_V2 && _vm->getIsADGFDemo()) #define TinselV1PSX (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformPSX) #define TinselV1Mac (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformMacintosh) -#define IsDemo (_vm->getFeatures() & GF_DEMO) - -#define READ_16(v) ((_vm->getFeatures() & GF_BIG_ENDIAN) ? READ_BE_UINT16(v) : READ_LE_UINT16(v)) -#define READ_32(v) ((_vm->getFeatures() & GF_BIG_ENDIAN) ? READ_BE_UINT32(v) : READ_LE_UINT32(v)) +#define READ_16(v) (TinselV1Mac ? READ_BE_UINT16(v) : READ_LE_UINT16(v)) +#define READ_32(v) (TinselV1Mac ? READ_BE_UINT32(v) : READ_LE_UINT32(v)) // Global reference to the TinselEngine object extern TinselEngine *_vm; @@ -154,7 +147,6 @@ class TinselEngine : public Engine { Common::Point _mousePos; uint8 _dosPlayerDir; Console *_console; - Scheduler *_scheduler; static const char *const _sampleIndices[][3]; static const char *const _sampleFiles[][3]; @@ -188,6 +180,8 @@ public: uint16 getVersion() const; uint32 getFlags() const; Common::Platform getPlatform() const; + bool getIsADGFDemo() const; + bool isCD() const; const char *getSampleIndex(LANGUAGE lang); const char *getSampleFile(LANGUAGE lang); diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index c532bbbf09..c1a57638c2 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -273,8 +273,6 @@ SaveStateDescriptor ToltecsMetaEngine::querySaveMetaInfos(const char *target, in if (error == Toltecs::ToltecsEngine::kRSHENoError) { SaveStateDescriptor desc(slot, header.description); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); desc.setThumbnail(header.thumbnail); if (header.version > 0) { diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp index 172ec0a565..415f19ca31 100644 --- a/engines/toltecs/menu.cpp +++ b/engines/toltecs/menu.cpp @@ -81,7 +81,7 @@ int MenuSystem::run() { // Restore original background memcpy(_vm->_screen->_frontScreen, backgroundOrig.getBasePtr(0,0), 640 * 400); - _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); + _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); _vm->_system->updateScreen(); // Cleanup @@ -103,8 +103,8 @@ void MenuSystem::update() { handleEvents(); if (_needRedraw) { - //_vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen + 39 * 640 + 60, 640, 60, 39, 520, 247); - _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); + //_vm->_system->copyRectToScreen(_vm->_screen->_frontScreen + 39 * 640 + 60, 640, 60, 39, 520, 247); + _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); //debug("redraw"); _needRedraw = false; } diff --git a/engines/toltecs/render.cpp b/engines/toltecs/render.cpp index de5e77fb50..3f5356493e 100644 --- a/engines/toltecs/render.cpp +++ b/engines/toltecs/render.cpp @@ -193,7 +193,7 @@ void RenderQueue::update() { if (doFullRefresh) { clear(); - _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, _vm->_cameraHeight); + _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, 0, 640, _vm->_cameraHeight); } else { updateDirtyRects(); } @@ -301,7 +301,7 @@ void RenderQueue::updateDirtyRects() { int n_rects = 0; Common::Rect *rects = _updateUta->getRectangles(&n_rects, 0, 0, 639, _vm->_cameraHeight - 1); for (int i = 0; i < n_rects; i++) { - _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen + rects[i].left + rects[i].top * 640, + _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen + rects[i].left + rects[i].top * 640, 640, rects[i].left, rects[i].top, rects[i].width(), rects[i].height()); } delete[] rects; diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp index b781490b69..634917a7b1 100644 --- a/engines/toltecs/screen.cpp +++ b/engines/toltecs/screen.cpp @@ -114,7 +114,7 @@ void Screen::loadMouseCursor(uint resIndex) { } } // FIXME: Where's the cursor hotspot? Using 8, 8 seems good enough for now. - CursorMan.replaceCursor((const byte*)mouseCursor, 16, 16, 8, 8, 0); + CursorMan.replaceCursor(mouseCursor, 16, 16, 8, 8, 0); } void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) { diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp index d403e0499b..6d6c37dffd 100644 --- a/engines/toltecs/toltecs.cpp +++ b/engines/toltecs/toltecs.cpp @@ -300,7 +300,7 @@ void ToltecsEngine::drawScreen() { if (_screen->_guiRefresh && _guiHeight > 0 && _cameraHeight > 0) { // Update the GUI when needed and it's visible - _system->copyRectToScreen((const byte *)_screen->_frontScreen + _cameraHeight * 640, + _system->copyRectToScreen(_screen->_frontScreen + _cameraHeight * 640, 640, 0, _cameraHeight, 640, _guiHeight); _screen->_guiRefresh = false; } diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp index 98c667c303..1c85a8d798 100644 --- a/engines/toon/anim.cpp +++ b/engines/toon/anim.cpp @@ -132,7 +132,7 @@ Common::Rect Animation::getRect() { return Common::Rect(_x1, _y1, _x2, _y2); } -void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy) { +void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy) { debugC(3, kDebugAnim, "drawFrame(surface, %d, %d, %d)", frame, xx, yy); if (frame < 0) frame = 0; @@ -146,10 +146,13 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int if (_frames[frame]._ref != -1) frame = _frames[frame]._ref; - int32 rectX = _frames[frame]._x2 - _frames[frame]._x1; - int32 rectY = _frames[frame]._y2 - _frames[frame]._y1; - int32 offsX = 0; - int32 offsY = 0; + if (!_frames[frame]._data) + return; + + int16 rectX = _frames[frame]._x2 - _frames[frame]._x1; + int16 rectY = _frames[frame]._y2 - _frames[frame]._y1; + int16 offsX = 0; + int16 offsY = 0; _vm->addDirtyRect(xx + _x1 + _frames[frame]._x1, yy + _y1 + _frames[frame]._y1, xx + rectX + _x1 + _frames[frame]._x1 , yy + rectY + _y1 + _frames[frame]._y1); @@ -186,10 +189,10 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int int32 destPitch = surface.pitch; uint8 *srcRow = _frames[frame]._data + offsX + (_frames[frame]._x2 - _frames[frame]._x1) * offsY; uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1 + offsY) * destPitch + (xx + _x1 + _frames[frame]._x1 + offsX); - for (int32 y = 0; y < rectY; y++) { + for (int16 y = 0; y < rectY; y++) { uint8 *cur = curRow; uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1); - for (int32 x = 0; x < rectX; x++) { + for (int16 x = 0; x < rectX; x++) { if (*c) *cur = *c; c++; @@ -199,27 +202,27 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int } } -void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask) { +void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask) { debugC(1, kDebugAnim, "drawFrameWithMask(surface, %d, %d, %d, %d, mask)", frame, xx, yy, zz); warning("STUB: drawFrameWithMask()"); } -void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale) { +void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask, int32 scale) { debugC(5, kDebugAnim, "drawFrameWithMaskAndScale(surface, %d, %d, %d, %d, mask, %d)", frame, xx, yy, zz, scale); if (_frames[frame]._ref != -1) frame = _frames[frame]._ref; - int32 rectX = _frames[frame]._x2 - _frames[frame]._x1; - int32 rectY = _frames[frame]._y2 - _frames[frame]._y1; + int16 rectX = _frames[frame]._x2 - _frames[frame]._x1; + int16 rectY = _frames[frame]._y2 - _frames[frame]._y1; - int32 finalWidth = rectX * scale / 1024; - int32 finalHeight = rectY * scale / 1024; + int16 finalWidth = rectX * scale / 1024; + int16 finalHeight = rectY * scale / 1024; // compute final x1, y1, x2, y2 - int32 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024; - int32 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024; - int32 xx2 = xx1 + finalWidth; - int32 yy2 = yy1 + finalHeight; - int32 w = _frames[frame]._x2 - _frames[frame]._x1; + int16 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024; + int16 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024; + int16 xx2 = xx1 + finalWidth; + int16 yy2 = yy1 + finalHeight; + int16 w = _frames[frame]._x2 - _frames[frame]._x1; _vm->addDirtyRect(xx1, yy1, xx2, yy2); @@ -229,37 +232,26 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram uint8 *curRow = (uint8 *)surface.pixels; uint8 *curRowMask = mask->getDataPtr(); - if (strstr(_name, "SHADOW")) { - for (int y = yy1; y < yy2; y++) { - for (int x = xx1; x < xx2; x++) { - if (x < 0 || x >= 1280 || y < 0 || y >= 400) - continue; + bool shadowFlag = false; + if (strstr(_name, "SHADOW")) + shadowFlag = true; + + for (int16 y = yy1; y < yy2; y++) { + for (int16 x = xx1; x < xx2; x++) { + if (x < 0 || x >= 1280 || y < 0 || y >= 400) + continue; - uint8 *cur = curRow + x + y * destPitch; - uint8 *curMask = curRowMask + x + y * destPitchMask; + uint8 *cur = curRow + x + y * destPitch; + uint8 *curMask = curRowMask + x + y * destPitchMask; - // find the good c - int32 xs = (x - xx1) * 1024 / scale; - int32 ys = (y - yy1) * 1024 / scale; - uint8 *cc = &c[ys * w + xs]; - if (*cc && ((*curMask) >= zz)) + // find the good c + int16 xs = (x - xx1) * 1024 / scale; + int16 ys = (y - yy1) * 1024 / scale; + uint8 *cc = &c[ys * w + xs]; + if (*cc && ((*curMask) >= zz)) { + if (shadowFlag) *cur = _vm->getShadowLUT()[*cur]; - } - } - } else { - for (int y = yy1; y < yy2; y++) { - for (int x = xx1; x < xx2; x++) { - if (x < 0 || x >= 1280 || y < 0 || y >= 400) - continue; - - uint8 *cur = curRow + x + y * destPitch; - uint8 *curMask = curRowMask + x + y * destPitchMask; - - // find the good c - int32 xs = (x - xx1) * 1024 / scale; - int32 ys = (y - yy1) * 1024 / scale; - uint8 *cc = &c[ys * w + xs]; - if (*cc && ((*curMask) >= zz)) + else *cur = *cc; } } @@ -283,7 +275,7 @@ Common::Rect Animation::getFrameRect(int32 frame) { return Common::Rect(_frames[frame]._x1, _frames[frame]._y1, _frames[frame]._x2, _frames[frame]._y2); } -int32 Animation::getFrameWidth(int32 frame) { +int16 Animation::getFrameWidth(int32 frame) { debugC(4, kDebugAnim, "getFrameWidth(%d)", frame); if ((frame < 0) || (frame >= _numFrames)) return 0; @@ -294,7 +286,7 @@ int32 Animation::getFrameWidth(int32 frame) { return _frames[frame]._x2 - _frames[frame]._x1; } -int32 Animation::getFrameHeight(int32 frame) { +int16 Animation::getFrameHeight(int32 frame) { debugC(4, kDebugAnim, "getFrameHeight(%d)", frame); if (frame < 0 || frame >= _numFrames) return 0; @@ -305,15 +297,15 @@ int32 Animation::getFrameHeight(int32 frame) { return _frames[frame]._y2 - _frames[frame]._y1; } -int32 Animation::getWidth() const { +int16 Animation::getWidth() const { return _x2 - _x1; } -int32 Animation::getHeight() const { +int16 Animation::getHeight() const { return _y2 - _y1; } -void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, byte *colorMap) { +void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, byte *colorMap) { debugC(4, kDebugAnim, "drawFontFrame(surface, %d, %d, %d, colorMap)", frame, xx, yy); if (frame < 0) frame = 0; @@ -327,8 +319,8 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, if (_frames[frame]._ref != -1) frame = _frames[frame]._ref; - int32 rectX = _frames[frame]._x2 - _frames[frame]._x1; - int32 rectY = _frames[frame]._y2 - _frames[frame]._y1; + int16 rectX = _frames[frame]._x2 - _frames[frame]._x1; + int16 rectY = _frames[frame]._y2 - _frames[frame]._y1; if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0)) return; @@ -348,9 +340,9 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 destPitch = surface.pitch; uint8 *c = _frames[frame]._data; uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1); - for (int32 y = 0; y < rectY; y++) { + for (int16 y = 0; y < rectY; y++) { unsigned char *cur = curRow; - for (int32 x = 0; x < rectX; x++) { + for (int16 x = 0; x < rectX; x++) { if (*c && *c < 4) *cur = colorMap[*c]; c++; @@ -360,7 +352,7 @@ void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, } } -void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) { +void Animation::drawFrameOnPicture(int32 frame, int16 xx, int16 yy) { debugC(1, kDebugAnim, "drawFrameOnPicture(%d, %d, %d)", frame, xx, yy); if (frame < 0) frame = 0; @@ -374,8 +366,8 @@ void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) { if (_frames[frame]._ref != -1) frame = _frames[frame]._ref; - int32 rectX = _frames[frame]._x2 - _frames[frame]._x1; - int32 rectY = _frames[frame]._y2 - _frames[frame]._y1; + int16 rectX = _frames[frame]._x2 - _frames[frame]._x1; + int16 rectY = _frames[frame]._y2 - _frames[frame]._y1; Picture *pic = _vm->getPicture(); @@ -397,9 +389,9 @@ void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) { int32 destPitch = pic->getWidth(); uint8 *c = _frames[frame]._data; uint8 *curRow = (uint8 *)pic->getDataPtr() + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1); - for (int32 y = 0; y < rectY; y++) { + for (int16 y = 0; y < rectY; y++) { unsigned char *cur = curRow; - for (int32 x = 0; x < rectX; x++) { + for (int16 x = 0; x < rectX; x++) { if (*c) *cur = *c; c++; @@ -466,8 +458,8 @@ void AnimationInstance::render() { if (frame >= _animation->_numFrames) frame = _animation->_numFrames - 1; - int32 x = _x; - int32 y = _y; + int16 x = _x; + int16 y = _y; if (_alignBottom) { int32 offsetX = (_animation->_x2 - _animation->_x1) / 2 * (_scale - 1024); @@ -509,7 +501,7 @@ void AnimationInstance::setAnimation(Animation *animation, bool setRange) { } } -void AnimationInstance::setAnimationRange(int32 rangeStart, int rangeEnd) { +void AnimationInstance::setAnimationRange(int32 rangeStart, int32 rangeEnd) { debugC(5, kDebugAnim, "setAnimationRange(%d, %d)", rangeStart, rangeEnd); _rangeStart = rangeStart; _rangeEnd = rangeEnd; @@ -521,7 +513,7 @@ void AnimationInstance::setAnimationRange(int32 rangeStart, int rangeEnd) { _currentFrame = _rangeEnd; } -void AnimationInstance::setPosition(int32 x, int32 y, int32 z, bool relative) { +void AnimationInstance::setPosition(int16 x, int16 y, int32 z, bool relative) { debugC(5, kDebugAnim, "setPosition(%d, %d, %d, %d)", x, y, z, (relative) ? 1 : 0); if (relative || !_animation) { _x = x; @@ -534,7 +526,7 @@ void AnimationInstance::setPosition(int32 x, int32 y, int32 z, bool relative) { } } -void AnimationInstance::moveRelative(int32 dx, int32 dy, int32 dz) { +void AnimationInstance::moveRelative(int16 dx, int16 dy, int32 dz) { debugC(1, kDebugAnim, "moveRelative(%d, %d, %d)", dx, dy, dz); _x += dx; _y += dy; @@ -579,13 +571,13 @@ void AnimationInstance::setUseMask(bool useMask) { _useMask = useMask; } -void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const { +void AnimationInstance::getRect(int16 *x1, int16 *y1, int16 *x2, int16 *y2) const { debugC(5, kDebugAnim, "getRect(%d, %d, %d, %d)", *x1, *y1, *x2, *y2); - int32 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1; - int32 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1; + int16 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1; + int16 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1; - int32 finalWidth = rectX * _scale / 1024; - int32 finalHeight = rectY * _scale / 1024; + int16 finalWidth = rectX * _scale / 1024; + int16 finalHeight = rectY * _scale / 1024; // compute final x1, y1, x2, y2 *x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024; @@ -594,7 +586,7 @@ void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) cons *y2 = *y1 + finalHeight; } -void AnimationInstance::setX(int32 x, bool relative) { +void AnimationInstance::setX(int16 x, bool relative) { debugC(1, kDebugAnim, "setX(%d, %d)", x, (relative) ? 1 : 0); if (relative || !_animation) _x = x; @@ -602,7 +594,7 @@ void AnimationInstance::setX(int32 x, bool relative) { _x = x - _animation->_x1; } -void AnimationInstance::setY(int32 y, bool relative) { +void AnimationInstance::setY(int16 y, bool relative) { debugC(1, kDebugAnim, "setY(%d, %d)", y, (relative) ? 1 : 0); if (relative || !_animation) _y = y; @@ -625,11 +617,11 @@ int32 AnimationInstance::getLayerZ() const { return _layerZ; } -int32 AnimationInstance::getX2() const { +int16 AnimationInstance::getX2() const { return _x + _animation->_x1; } -int32 AnimationInstance::getY2() const { +int16 AnimationInstance::getY2() const { return _y + _animation->_y1; } @@ -658,6 +650,7 @@ void AnimationInstance::save(Common::WriteStream *stream) { stream->writeSint32LE(_visible); stream->writeSint32LE(_useMask); } + void AnimationInstance::load(Common::ReadStream *stream) { _currentFrame = stream->readSint32LE(); _currentTime = stream->readSint32LE(); @@ -706,14 +699,13 @@ void AnimationManager::updateInstance(AnimationInstance* instance) { } void AnimationManager::addInstance(AnimationInstance *instance) { - // if the instance already exists, we skip the add for (uint32 i = 0; i < _instances.size(); i++) { if (_instances[i] == instance) return; } - int found = -1; + int32 found = -1; // here we now do an ordered insert (closer to the original game) for (uint32 i = 0; i < _instances.size(); i++) { @@ -723,11 +715,10 @@ void AnimationManager::addInstance(AnimationInstance *instance) { } } - if ( found == -1 ) { + if (found == -1) _instances.push_back(instance); - } else { + else _instances.insert_at(found, instance); - } } void AnimationManager::removeInstance(AnimationInstance *instance) { diff --git a/engines/toon/anim.h b/engines/toon/anim.h index eb8dcbd600..cd550b2621 100644 --- a/engines/toon/anim.h +++ b/engines/toon/anim.h @@ -36,10 +36,10 @@ class Picture; class ToonEngine; struct AnimationFrame { - int32 _x1; - int32 _y1; - int32 _x2; - int32 _y2; + int16 _x1; + int16 _y1; + int16 _x2; + int16 _y2; int32 _ref; uint8 *_data; }; @@ -49,10 +49,10 @@ public: Animation(ToonEngine *vm); ~Animation(); - int32 _x1; - int32 _y1; - int32 _x2; - int32 _y2; + int16 _x1; + int16 _y1; + int16 _x2; + int16 _y2; int32 _numFrames; int32 _fps; AnimationFrame *_frames; @@ -61,18 +61,18 @@ public: char _name[32]; bool loadAnimation(const Common::String &file); - void drawFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y); - void drawFontFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y, byte *colorMap); - void drawFrameOnPicture(int32 frame, int32 x, int32 y); - void drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask); - void drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale); + void drawFrame(Graphics::Surface &surface, int32 frame, int16 x, int16 y); + void drawFontFrame(Graphics::Surface &surface, int32 frame, int16 x, int16 y, byte *colorMap); + void drawFrameOnPicture(int32 frame, int16 x, int16 y); + void drawFrameWithMask(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask); + void drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask, int32 scale); void drawStrip(int32 offset = 0); void applyPalette(int32 offset, int32 srcOffset, int32 numEntries); Common::Rect getFrameRect(int32 frame); - int32 getFrameWidth(int32 frame); - int32 getFrameHeight(int32 frame); - int32 getWidth() const; - int32 getHeight() const; + int16 getFrameWidth(int32 frame); + int16 getFrameHeight(int32 frame); + int16 getWidth() const; + int16 getHeight() const; Common::Rect getRect(); protected: ToonEngine *_vm; @@ -92,25 +92,25 @@ public: void renderOnPicture(); void setAnimation(Animation *animation, bool setRange = true); void playAnimation(); - void setAnimationRange(int32 rangeStart, int rangeEnd); + void setAnimationRange(int32 rangeStart, int32 rangeEnd); void setFps(int32 fps); void setLooping(bool enable); void stopAnimation(); void setFrame(int32 position); void forceFrame(int32 position); - void setPosition(int32 x, int32 y, int32 z, bool relative = false); + void setPosition(int16 x, int16 y, int32 z, bool relative = false); Animation *getAnimation() const { return _animation; } void setScale(int32 scale, bool align = false); void setVisible(bool visible); bool getVisible() const { return _visible; } void setUseMask(bool useMask); - void moveRelative(int32 dx, int32 dy, int32 dz); - void getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const; - int32 getX() const { return _x; } - int32 getY() const { return _y; } + void moveRelative(int16 dx, int16 dy, int32 dz); + void getRect(int16 *x1, int16 *y1, int16 *x2, int16 *y2) const; + int16 getX() const { return _x; } + int16 getY() const { return _y; } int32 getZ() const { return _z; } - int32 getX2() const; - int32 getY2() const; + int16 getX2() const; + int16 getY2() const; int32 getZ2() const; int32 getFrame() const { return _currentFrame; } void reset(); @@ -120,8 +120,8 @@ public: void setId(int32 id) { _id = id; } int32 getId() const { return _id; } - void setX(int32 x, bool relative = false); - void setY(int32 y, bool relative = false); + void setX(int16 x, bool relative = false); + void setY(int16 y, bool relative = false); void setZ(int32 z, bool relative = false); void setLayerZ(int32 layer); int32 getLayerZ() const; @@ -133,8 +133,8 @@ protected: int32 _currentTime; int32 _fps; Animation *_animation; - int32 _x; - int32 _y; + int16 _x; + int16 _y; int32 _z; int32 _layerZ; int32 _rangeStart; diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp index 77822ab078..bc0e051057 100644 --- a/engines/toon/audio.cpp +++ b/engines/toon/audio.cpp @@ -326,7 +326,7 @@ bool AudioStreamInstance::readPacket() { } if (numDecompressedBytes > _bufferMaxSize) { - delete [] _buffer; + delete[] _buffer; _bufferMaxSize = numDecompressedBytes; _buffer = new int16[numDecompressedBytes]; } diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp index 0e5189957b..479f4965f3 100644 --- a/engines/toon/character.cpp +++ b/engines/toon/character.cpp @@ -56,14 +56,13 @@ Character::Character(ToonEngine *vm) : _vm(vm) { _animScriptId = -1; _animSpecialId = -1; _animSpecialDefaultId = 0; - _currentPathNodeCount = 0; _currentPathNode = 0; _currentWalkStamp = 0; _visible = true; _speed = 150; // 150 = nominal drew speed _lastWalkTime = 0; _numPixelToWalk = 0; - _nextIdleTime = _vm->getSystem()->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength(); + _nextIdleTime = _vm->_system->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength(); _lineToSayId = 0; } @@ -81,7 +80,7 @@ Character::~Character(void) { void Character::init() { } -void Character::forceFacing( int32 facing ) { +void Character::forceFacing(int32 facing) { debugC(4, kDebugCharacter, "forceFacing(%d)", facing); _facing = facing; } @@ -102,7 +101,7 @@ void Character::setFacing(int32 facing) { int32 dir = 0; - _lastWalkTime = _vm->getSystem()->getMillis(); + _lastWalkTime = _vm->_system->getMillis(); if ((_facing - facing + 8) % 8 > (facing - _facing + 8) % 8) dir = 1; else @@ -123,7 +122,7 @@ void Character::setFacing(int32 facing) { _lastWalkTime = _vm->getOldMilli(); } - if (_currentPathNode == 0) + if (_currentPathNode == 0) playStandingAnim(); else playWalkAnim(0, 0); @@ -136,8 +135,7 @@ void Character::setFacing(int32 facing) { _facing = facing; } -void Character::forcePosition(int32 x, int32 y) { - +void Character::forcePosition(int16 x, int16 y) { debugC(5, kDebugCharacter, "forcePosition(%d, %d)", x, y); setPosition(x, y); @@ -145,7 +143,7 @@ void Character::forcePosition(int32 x, int32 y) { _finalY = y; } -void Character::setPosition(int32 x, int32 y) { +void Character::setPosition(int16 x, int16 y) { debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y); _x = x; @@ -155,7 +153,7 @@ void Character::setPosition(int32 x, int32 y) { return; } -bool Character::walkTo(int32 newPosX, int32 newPosY) { +bool Character::walkTo(int16 newPosX, int16 newPosY) { debugC(1, kDebugCharacter, "walkTo(%d, %d)", newPosX, newPosY); if (!_visible) @@ -167,9 +165,9 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { _vm->getPathFinding()->resetBlockingRects(); // don't allow flux to go at the same position as drew - if (_id == 1 ) { - int32 sizeX = MAX<int32>(5, 30 * _vm->getDrew()->getScale() / 1024); - int32 sizeY = MAX<int32>(2, 20 * _vm->getDrew()->getScale() / 1024); + if (_id == 1) { + int16 sizeX = MAX<int16>(5, 30 * _vm->getDrew()->getScale() / 1024); + int16 sizeY = MAX<int16>(2, 20 * _vm->getDrew()->getScale() / 1024); _vm->getPathFinding()->addBlockingEllipse(_vm->getDrew()->getFinalX(), _vm->getDrew()->getFinalY(), sizeX, sizeY); } @@ -179,20 +177,18 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { if (_vm->getPathFinding()->findPath(_x, _y, _finalX, _finalY)) { - int32 localFinalX = _finalX; - int32 localFinalY = _finalY; + int16 localFinalX = _finalX; + int16 localFinalY = _finalY; int32 smoothDx = 0; int32 smoothDy = 0; - for (int32 a = 0; a < _vm->getPathFinding()->getPathNodeCount(); a++) { - _currentPathX[a] = _vm->getPathFinding()->getPathNodeX(a); - _currentPathY[a] = _vm->getPathFinding()->getPathNodeY(a); - } - _currentPathNodeCount = _vm->getPathFinding()->getPathNodeCount(); + _currentPath.clear(); + for (uint32 a = 0; a < _vm->getPathFinding()->getPathNodeCount(); a++) + _currentPath.push_back(Common::Point(_vm->getPathFinding()->getPathNodeX(a), _vm->getPathFinding()->getPathNodeY(a))); _currentPathNode = 0; stopSpecialAnim(); - _lastWalkTime = _vm->getSystem()->getMillis(); + _lastWalkTime = _vm->_system->getMillis(); _numPixelToWalk = 0; @@ -203,12 +199,12 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { int32 localWalkStamp = _currentWalkStamp; if (_blockingWalk) { - while ((_x != newPosX || _y != newPosY) && _currentPathNode < _currentPathNodeCount && !_vm->shouldQuitGame()) { - if (_currentPathNode < _currentPathNodeCount - 4) { - int32 delta = MIN<int32>(4, _currentPathNodeCount - _currentPathNode); + while ((_x != newPosX || _y != newPosY) && _currentPathNode < _currentPath.size() && !_vm->shouldQuitGame()) { + if (_currentPathNode < _currentPath.size() - 4) { + int32 delta = MIN<int32>(4, _currentPath.size() - 1 - _currentPathNode); - int32 dx = _currentPathX[_currentPathNode+delta] - _x; - int32 dy = _currentPathY[_currentPathNode+delta] - _y; + int16 dx = _currentPath[_currentPathNode+delta].x - _x; + int16 dy = _currentPath[_currentPathNode+delta].y - _y; // smooth the facing computation. It prevents some ugly flickering from happening if (!smoothDx && !smoothDy) { @@ -224,12 +220,12 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { } // in 1/1000 pixels - _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024; - _lastWalkTime = _vm->getSystem()->getMillis(); + _numPixelToWalk += _speed * (_vm->_system->getMillis() - _lastWalkTime) * _scale / 1024; + _lastWalkTime = _vm->_system->getMillis(); - while (_numPixelToWalk >= 1000 && _currentPathNode < _currentPathNodeCount) { - _x = _currentPathX[_currentPathNode]; - _y = _currentPathY[_currentPathNode]; + while (_numPixelToWalk >= 1000 && _currentPathNode < _currentPath.size()) { + _x = _currentPath[_currentPathNode].x; + _y = _currentPath[_currentPathNode].y; _currentPathNode += 1; _numPixelToWalk -= 1000; } @@ -245,7 +241,7 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { playStandingAnim(); _flags &= ~0x1; _currentPathNode = 0; - _currentPathNodeCount = 0; + _currentPath.clear(); if (_x != localFinalX || _y != localFinalY) { return false; @@ -264,10 +260,11 @@ int32 Character::getFlag() { return _flags; } -int32 Character::getX() { +int16 Character::getX() { return _x; } -int32 Character::getY() { + +int16 Character::getY() { return _y; } @@ -348,23 +345,23 @@ void Character::stopSpecialAnim() { void Character::update(int32 timeIncrement) { debugC(5, kDebugCharacter, "update(%d)", timeIncrement); - if ((_flags & 0x1) && _currentPathNodeCount > 0) { - if (_currentPathNode < _currentPathNodeCount) { - if (_currentPathNode < _currentPathNodeCount - 10) { - int32 delta = MIN<int32>(10, _currentPathNodeCount - _currentPathNode); - int32 dx = _currentPathX[_currentPathNode+delta] - _x; - int32 dy = _currentPathY[_currentPathNode+delta] - _y; + if ((_flags & 0x1) && _currentPath.size() > 0) { + if (_currentPathNode < _currentPath.size()) { + if (_currentPathNode < _currentPath.size() - 10) { + int32 delta = MIN<int32>(10, _currentPath.size() - 1 - _currentPathNode); + int16 dx = _currentPath[_currentPathNode+delta].x - _x; + int16 dy = _currentPath[_currentPathNode+delta].y - _y; setFacing(getFacingFromDirection(dx, dy)); playWalkAnim(0, 0); } // in 1/1000 pixels - _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024; - _lastWalkTime = _vm->getSystem()->getMillis(); + _numPixelToWalk += _speed * (_vm->_system->getMillis() - _lastWalkTime) * _scale / 1024; + _lastWalkTime = _vm->_system->getMillis(); - while (_numPixelToWalk > 1000 && _currentPathNode < _currentPathNodeCount) { - _x = _currentPathX[_currentPathNode]; - _y = _currentPathY[_currentPathNode]; + while (_numPixelToWalk > 1000 && _currentPathNode < _currentPath.size()) { + _x = _currentPath[_currentPathNode].x; + _y = _currentPath[_currentPathNode].y; _currentPathNode += 1; _numPixelToWalk -= 1000; } @@ -372,7 +369,7 @@ void Character::update(int32 timeIncrement) { } else { playStandingAnim(); _flags &= ~0x1; - _currentPathNodeCount = 0; + _currentPath.clear(); } } @@ -527,7 +524,7 @@ void Character::update(int32 timeIncrement) { } // adapted from Kyra -int32 Character::getFacingFromDirection(int32 dx, int32 dy) { +int32 Character::getFacingFromDirection(int16 dx, int16 dy) { debugC(4, kDebugCharacter, "getFacingFromDirection(%d, %d)", dx, dy); static const int facingTable[] = { @@ -537,35 +534,33 @@ int32 Character::getFacingFromDirection(int32 dx, int32 dy) { dx = -dx; int32 facingEntry = 0; - int32 ydiff = dy; + int16 ydiff = dy; if (ydiff < 0) { ++facingEntry; ydiff = -ydiff; } - facingEntry <<= 1; + facingEntry *= 2; - int32 xdiff = dx; + int16 xdiff = dx; if (xdiff < 0) { ++facingEntry; xdiff = -xdiff; } - facingEntry <<= 1; + facingEntry *= 2; if (xdiff >= ydiff) { - int32 temp = ydiff; + // Swap xdiff and ydiff + int16 temp = ydiff; ydiff = xdiff; xdiff = temp; - } else { - facingEntry += 1; - } - - facingEntry <<= 1; + } else + facingEntry++; - int32 temp = (ydiff + 1) >> 1; + facingEntry *= 2; - if (xdiff < temp) - facingEntry += 1; + if (xdiff < ((ydiff + 1) / 2)) + facingEntry++; return facingTable[facingEntry]; } @@ -638,7 +633,7 @@ void Character::load(Common::ReadStream *stream) { // "not visible" flag. if (_flags & 0x100) { _flags &= ~0x100; - setVisible(false); + setVisible(false); } } @@ -664,7 +659,7 @@ void Character::stopWalk() { _finalY = _y; _flags &= ~0x1; _currentPathNode = 0; - _currentPathNodeCount = 0; + _currentPath.clear(); } const SpecialCharacterAnimation *Character::getSpecialAnimation(int32 characterId, int32 animationId) { @@ -996,8 +991,8 @@ bool Character::loadShadowAnimation(const Common::String &animName) { } void Character::plotPath(Graphics::Surface& surface) { - for (int i = 0; i < _currentPathNodeCount; i++) { - *(byte *)surface.getBasePtr(_currentPathX[i], _currentPathY[i]) = ( i < _currentPathNode); + for (uint32 i = 0; i < _currentPath.size(); i++) { + *(byte *)surface.getBasePtr(_currentPath[i].x, _currentPath[i].y) = (i < _currentPathNode); } } @@ -1078,11 +1073,11 @@ void Character::setDefaultSpecialAnimationId(int32 defaultAnimationId) { _animSpecialDefaultId = defaultAnimationId; } -int32 Character::getFinalX() { +int16 Character::getFinalX() { return _finalX; } -int32 Character::getFinalY() { +int16 Character::getFinalY() { return _finalY; } diff --git a/engines/toon/character.h b/engines/toon/character.h index d06a6c060c..d33c314bf7 100644 --- a/engines/toon/character.h +++ b/engines/toon/character.h @@ -23,6 +23,9 @@ #ifndef TOON_CHARACTER_H #define TOON_CHARACTER_H +#include "common/array.h" +#include "common/rect.h" + #include "toon/toon.h" namespace Toon { @@ -65,13 +68,13 @@ public: virtual int32 getFlag(); virtual int32 getAnimFlag(); virtual void setAnimFlag(int32 flag); - virtual void setPosition(int32 x, int32 y); - virtual void forcePosition(int32 x, int32 y); - virtual int32 getX(); - virtual int32 getY(); - virtual int32 getFinalX(); - virtual int32 getFinalY(); - virtual bool walkTo(int32 newPosX, int32 newPosY); + virtual void setPosition(int16 x, int16 y); + virtual void forcePosition(int16 x, int16 y); + virtual int16 getX(); + virtual int16 getY(); + virtual int16 getFinalX(); + virtual int16 getFinalY(); + virtual bool walkTo(int16 newPosX, int16 newPosY); virtual bool getVisible(); virtual void setVisible(bool visible); virtual bool loadWalkAnimation(const Common::String &animName); @@ -99,7 +102,7 @@ public: virtual void resetScale() {} virtual void plotPath(Graphics::Surface& surface); - int32 getFacingFromDirection(int32 dx, int32 dy); + int32 getFacingFromDirection(int16 dx, int16 dy); static const SpecialCharacterAnimation *getSpecialAnimation(int32 characterId, int32 animationId); protected: @@ -112,11 +115,11 @@ protected: int32 _sceneAnimationId; int32 _lineToSayId; int32 _time; - int32 _x; - int32 _y; + int16 _x; + int16 _y; int32 _z; - int32 _finalX; - int32 _finalY; + int16 _finalX; + int16 _finalY; int32 _facing; int32 _flags; int32 _animFlags; @@ -137,10 +140,8 @@ protected: Animation *_shadowAnim; Animation *_specialAnim; - int32 _currentPathX[4096]; - int32 _currentPathY[4096]; - int32 _currentPathNodeCount; - int32 _currentPathNode; + Common::Array<Common::Point> _currentPath; + uint32 _currentPathNode; int32 _currentWalkStamp; }; diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index 8234934972..3877fa2a6c 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -133,7 +133,7 @@ public: } virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { - return detectGameFilebased(allFiles, Toon::fileBasedFallback); + return detectGameFilebased(allFiles, fslist, Toon::fileBasedFallback); } virtual const char *getName() const { @@ -234,9 +234,6 @@ SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int s Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); desc.setThumbnail(thumbnail); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - uint32 saveDate = file->readUint32BE(); uint16 saveTime = file->readUint16BE(); diff --git a/engines/toon/drew.cpp b/engines/toon/drew.cpp index df5cfcfa03..dfd3f515fa 100644 --- a/engines/toon/drew.cpp +++ b/engines/toon/drew.cpp @@ -48,7 +48,7 @@ bool CharacterDrew::setupPalette() { return false; } -void CharacterDrew::setPosition(int32 x, int32 y) { +void CharacterDrew::setPosition(int16 x, int16 y) { debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y); _z = _vm->getLayerAtPoint(x, y); diff --git a/engines/toon/drew.h b/engines/toon/drew.h index 3357b99846..ff1b619125 100644 --- a/engines/toon/drew.h +++ b/engines/toon/drew.h @@ -35,7 +35,7 @@ public: virtual ~CharacterDrew(); bool setupPalette(); void playStandingAnim(); - void setPosition(int32 x, int32 y); + void setPosition(int16 x, int16 y); void resetScale(); void update(int32 timeIncrement); void playWalkAnim(int32 start, int32 end); diff --git a/engines/toon/flux.cpp b/engines/toon/flux.cpp index b752e65c82..70aa40fb36 100644 --- a/engines/toon/flux.cpp +++ b/engines/toon/flux.cpp @@ -45,7 +45,7 @@ void CharacterFlux::playStandingAnim() { _animationInstance->stopAnimation(); _animationInstance->setLooping(true); - //s/etVisible(true); + //setVisible(true); } void CharacterFlux::setVisible(bool visible) { @@ -99,7 +99,7 @@ int32 CharacterFlux::fixFacingForAnimation(int32 originalFacing, int32 animation return finalFacing; } -void CharacterFlux::setPosition(int32 x, int32 y) { +void CharacterFlux::setPosition(int16 x, int16 y) { debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y); _z = _vm->getLayerAtPoint(x, y); diff --git a/engines/toon/flux.h b/engines/toon/flux.h index c208bc5bda..1dc0d9c55f 100644 --- a/engines/toon/flux.h +++ b/engines/toon/flux.h @@ -34,7 +34,7 @@ public: CharacterFlux(ToonEngine *vm); virtual ~CharacterFlux(); - void setPosition(int32 x, int32 y); + void setPosition(int16 x, int16 y); void playStandingAnim(); void playWalkAnim(int32 start, int32 end); void update(int32 timeIncrement); diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp index d58663a00c..1e851ff4ae 100644 --- a/engines/toon/font.cpp +++ b/engines/toon/font.cpp @@ -65,10 +65,10 @@ byte FontRenderer::textToFont(byte c) { return map_textToFont[c - 0x80]; } -void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText, int32 mode) { +void FontRenderer::renderText(int16 x, int16 y, const Common::String &origText, int32 mode) { debugC(5, kDebugFont, "renderText(%d, %d, %s, %d)", x, y, origText.c_str(), mode); - int32 xx, yy; + int16 xx, yy; computeSize(origText, &xx, &yy); if (mode & 2) { @@ -83,8 +83,8 @@ void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText, _vm->addDirtyRect(x, y, x + xx, y + yy); - int32 curX = x; - int32 curY = y; + int16 curX = x; + int16 curY = y; int32 height = 0; const byte *text = (const byte *)origText.c_str(); @@ -98,20 +98,20 @@ void FontRenderer::renderText(int32 x, int32 y, const Common::String &origText, curChar = textToFont(curChar); _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX, curY, _currentFontColor); curX = curX + _currentFont->getFrameWidth(curChar) - 1; - height = MAX(height, _currentFont->getFrameHeight(curChar)); + height = MAX<int32>(height, _currentFont->getFrameHeight(curChar)); } text++; } } -void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int32 *retY) { +void FontRenderer::computeSize(const Common::String &origText, int16 *retX, int16 *retY) { debugC(4, kDebugFont, "computeSize(%s, retX, retY)", origText.c_str()); - int32 lineWidth = 0; - int32 lineHeight = 0; - int32 totalHeight = 0; - int32 totalWidth = 0; - int32 lastLineHeight = 0; + int16 lineWidth = 0; + int16 lineHeight = 0; + int16 totalHeight = 0; + int16 totalWidth = 0; + int16 lastLineHeight = 0; const byte *text = (const byte *)origText.c_str(); while (*text) { @@ -127,8 +127,8 @@ void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int3 lastLineHeight = 0; } else { curChar = textToFont(curChar); - int32 charWidth = _currentFont->getFrameWidth(curChar) - 1; - int32 charHeight = _currentFont->getFrameHeight(curChar); + int16 charWidth = _currentFont->getFrameWidth(curChar) - 1; + int16 charHeight = _currentFont->getFrameHeight(curChar); lineWidth += charWidth; lineHeight = MAX(lineHeight, charHeight); @@ -137,7 +137,7 @@ void FontRenderer::computeSize(const Common::String &origText, int32 *retX, int3 // assume we only need to take the lower bound into // consideration. Common::Rect charRect = _currentFont->getFrameRect(curChar); - lastLineHeight = MAX<int32>(lastLineHeight, charRect.bottom); + lastLineHeight = MAX(lastLineHeight, charRect.bottom); } text++; } @@ -189,7 +189,7 @@ void FontRenderer::setFontColor(int32 fontColor1, int32 fontColor2, int32 fontCo _currentFontColor[3] = fontColor3; } -void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &origText, int32 mode) { +void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode) { debugC(5, kDebugFont, "renderMultiLineText(%d, %d, %s, %d)", x, y, origText.c_str(), mode); // divide the text in several lines @@ -204,10 +204,10 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o byte *it = text; - int32 maxWidth = 0; - int32 curWidth = 0; + int16 maxWidth = 0; + int16 curWidth = 0; - while (1) { + while (true) { byte *lastLine = it; byte *lastSpace = it; int32 lastSpaceX = 0; @@ -223,7 +223,7 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o curChar = textToFont(curChar); int width = _currentFont->getFrameWidth(curChar); - curWidth += MAX<int32>(width - 2, 0); + curWidth += MAX(width - 2, 0); it++; curLetterNr++; } @@ -260,8 +260,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o //numLines++; // get font height (assumed to be constant) - int32 height = _currentFont->getHeight(); - int textSize = (height - 2) * numLines; + int16 height = _currentFont->getHeight(); + int32 textSize = (height - 2) * numLines; y = y - textSize; if (y < 30) y = 30; @@ -278,8 +278,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, const Common::String &o x = TOON_SCREEN_WIDTH - (maxWidth / 2) - 30; // we have good coordinates now, we can render the multi line - int32 curX = x; - int32 curY = y; + int16 curX = x; + int16 curY = y; for (int32 i = 0; i < numLines; i++) { const byte *line = lines[i]; diff --git a/engines/toon/font.h b/engines/toon/font.h index 349d9d1ee7..2a46ad3559 100644 --- a/engines/toon/font.h +++ b/engines/toon/font.h @@ -33,9 +33,9 @@ public: ~FontRenderer(); void setFont(Animation *font); - void computeSize(const Common::String &origText, int32 *retX, int32 *retY); - void renderText(int32 x, int32 y, const Common::String &origText, int32 mode); - void renderMultiLineText(int32 x, int32 y, const Common::String &origText, int32 mode); + void computeSize(const Common::String &origText, int16 *retX, int16 *retY); + void renderText(int16 x, int16 y, const Common::String &origText, int32 mode); + void renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode); void setFontColorByCharacter(int32 characterId); void setFontColor(int32 fontColor1, int32 fontColor2, int32 fontColor3); protected: diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp index ce2cdf1bb9..8b8f0ab577 100644 --- a/engines/toon/hotspot.cpp +++ b/engines/toon/hotspot.cpp @@ -57,7 +57,7 @@ void Hotspots::save(Common::WriteStream *Stream) { } } -int32 Hotspots::FindBasedOnCorner(int32 x, int32 y) { +int32 Hotspots::FindBasedOnCorner(int16 x, int16 y) { debugC(1, kDebugHotspot, "FindBasedOnCorner(%d, %d)", x, y); for (int32 i = 0; i < _numItems; i++) { @@ -73,7 +73,7 @@ int32 Hotspots::FindBasedOnCorner(int32 x, int32 y) { return -1; } -int32 Hotspots::Find(int32 x, int32 y) { +int32 Hotspots::Find(int16 x, int16 y) { debugC(6, kDebugHotspot, "Find(%d, %d)", x, y); int32 priority = -1; diff --git a/engines/toon/hotspot.h b/engines/toon/hotspot.h index 70e80046e1..3852e2e42e 100644 --- a/engines/toon/hotspot.h +++ b/engines/toon/hotspot.h @@ -51,8 +51,8 @@ public: ~Hotspots(); bool LoadRif(const Common::String &rifName, const Common::String &additionalRifName); - int32 Find(int32 x, int32 y); - int32 FindBasedOnCorner(int32 x, int32 y); + int32 Find(int16 x, int16 y); + int32 FindBasedOnCorner(int16 x, int16 y); HotspotData *Get(int32 id); int32 getCount() const { return _numItems; } diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 59ad8484d5..8c85e20f7c 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -25,6 +25,7 @@ #include "common/keyboard.h" #include "common/stream.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "toon/audio.h" @@ -33,6 +34,10 @@ namespace Toon { +ToonstruckSmackerDecoder::ToonstruckSmackerDecoder() : Video::SmackerDecoder() { + _lowRes = false; +} + void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { debugC(6, kDebugMovie, "handleAudioTrack(%d, %d, %d)", track, chunkSize, unpackedSize); @@ -40,33 +45,21 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui /* uint16 width = */ _fileStream->readUint16LE(); uint16 height = _fileStream->readUint16LE(); _lowRes = (height == getHeight() / 2); - } else + } else { Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize); + } } -bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) { - debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str()); +bool ToonstruckSmackerDecoder::loadStream(Common::SeekableReadStream *stream) { + if (!Video::SmackerDecoder::loadStream(stream)) + return false; _lowRes = false; - - if (Video::SmackerDecoder::loadFile(filename)) { - if (_surface->h == 200) { - if (_surface) { - _surface->free(); - delete _surface; - } - _surface = new Graphics::Surface(); - _surface->create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); - _header.flags = 4; - } - - return true; - } - return false; + return true; } -ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : Video::SmackerDecoder(mixer, soundType) { - _lowRes = false; +Video::SmackerDecoder::SmackerVideoTrack *ToonstruckSmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const { + return Video::SmackerDecoder::createVideoTrack(width, height, frameCount, frameRate, (height == 200) ? 4 : flags, signature); } // decoder is deallocated with Movie destruction i.e. new ToonstruckSmackerDecoder is needed @@ -103,46 +96,49 @@ void Movie::play(const Common::String &video, int32 flags) { bool Movie::playVideo(bool isFirstIntroVideo) { debugC(1, kDebugMovie, "playVideo(isFirstIntroVideo: %d)", isFirstIntroVideo); + + _decoder->start(); + while (!_vm->shouldQuit() && !_decoder->endOfVideo()) { if (_decoder->needsUpdate()) { const Graphics::Surface *frame = _decoder->decodeNextFrame(); if (frame) { if (_decoder->isLowRes()) { // handle manually 2x scaling here - Graphics::Surface* surf = _vm->getSystem()->lockScreen(); + Graphics::Surface* surf = _vm->_system->lockScreen(); for (int y = 0; y < frame->h / 2; y++) { memcpy(surf->getBasePtr(0, y * 2 + 0), frame->getBasePtr(0, y), frame->pitch); memcpy(surf->getBasePtr(0, y * 2 + 1), frame->getBasePtr(0, y), frame->pitch); } - _vm->getSystem()->unlockScreen(); + _vm->_system->unlockScreen(); } else { - _vm->getSystem()->copyRectToScreen((byte *)frame->pixels, frame->pitch, 0, 0, frame->w, frame->h); + _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, 0, 0, frame->w, frame->h); // WORKAROUND: There is an encoding glitch in the first intro video. This hides this using the adjacent pixels. if (isFirstIntroVideo) { int32 currentFrame = _decoder->getCurFrame(); if (currentFrame >= 956 && currentFrame <= 1038) { debugC(1, kDebugMovie, "Triggered workaround for glitch in first intro video..."); - _vm->getSystem()->copyRectToScreen((const byte *)frame->getBasePtr(frame->w-188, 123), frame->pitch, frame->w-188, 124, 188, 1); - _vm->getSystem()->copyRectToScreen((const byte *)frame->getBasePtr(frame->w-188, 126), frame->pitch, frame->w-188, 125, 188, 1); - _vm->getSystem()->copyRectToScreen((const byte *)frame->getBasePtr(0, 125), frame->pitch, 0, 126, 64, 1); - _vm->getSystem()->copyRectToScreen((const byte *)frame->getBasePtr(0, 128), frame->pitch, 0, 127, 64, 1); + _vm->_system->copyRectToScreen(frame->getBasePtr(frame->w-188, 123), frame->pitch, frame->w-188, 124, 188, 1); + _vm->_system->copyRectToScreen(frame->getBasePtr(frame->w-188, 126), frame->pitch, frame->w-188, 125, 188, 1); + _vm->_system->copyRectToScreen(frame->getBasePtr(0, 125), frame->pitch, 0, 126, 64, 1); + _vm->_system->copyRectToScreen(frame->getBasePtr(0, 128), frame->pitch, 0, 127, 64, 1); } } } } - _decoder->setSystemPalette(); - _vm->getSystem()->updateScreen(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); + _vm->_system->updateScreen(); } Common::Event event; - while (_vm->getSystem()->getEventManager()->pollEvent(event)) + while (_vm->_system->getEventManager()->pollEvent(event)) if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE)) { _vm->dirtyAllScreen(); return false; } - _vm->getSystem()->delayMillis(10); + _vm->_system->delayMillis(10); } _vm->dirtyAllScreen(); return !_vm->shouldQuit(); diff --git a/engines/toon/movie.h b/engines/toon/movie.h index 2cd33302f2..e795182cba 100644 --- a/engines/toon/movie.h +++ b/engines/toon/movie.h @@ -30,13 +30,17 @@ namespace Toon { class ToonstruckSmackerDecoder : public Video::SmackerDecoder { public: - ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); - virtual ~ToonstruckSmackerDecoder() {} - void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - bool loadFile(const Common::String &filename); + ToonstruckSmackerDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); bool isLowRes() { return _lowRes; } + protected: - bool _lowRes; + void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); + SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const; + +private: + bool _lowRes; }; class Movie { diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp index 2dd5fc45e2..7914aed595 100644 --- a/engines/toon/path.cpp +++ b/engines/toon/path.cpp @@ -60,12 +60,12 @@ void PathFindingHeap::clear() { memset(_data, 0, sizeof(HeapDataGrid) * _size); } -void PathFindingHeap::push(int32 x, int32 y, int32 weight) { +void PathFindingHeap::push(int16 x, int16 y, uint16 weight) { debugC(2, kDebugPath, "push(%d, %d, %d)", x, y, weight); if (_count == _size) { // Increase size by 50% - int newSize = _size + (_size >> 1) + 1; + uint32 newSize = _size + (_size / 2) + 1; HeapDataGrid *newData; newData = (HeapDataGrid *)realloc(_data, sizeof(HeapDataGrid) * newSize); @@ -84,13 +84,13 @@ void PathFindingHeap::push(int32 x, int32 y, int32 weight) { _data[_count]._weight = weight; _count++; - int32 lMax = _count-1; - int32 lT = 0; + uint32 lMax = _count - 1; + uint32 lT = 0; - while (1) { + while (true) { if (lMax <= 0) break; - lT = (lMax-1) / 2; + lT = (lMax - 1) / 2; if (_data[lT]._weight > _data[lMax]._weight) { HeapDataGrid temp; @@ -104,7 +104,7 @@ void PathFindingHeap::push(int32 x, int32 y, int32 weight) { } } -void PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { +void PathFindingHeap::pop(int16 *x, int16 *y, uint16 *weight) { debugC(2, kDebugPath, "pop(x, y, weight)"); if (!_count) { @@ -120,13 +120,13 @@ void PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { if (!_count) return; - int32 lMin = 0; - int32 lT = 0; + uint32 lMin = 0; + uint32 lT = 0; - while (1) { - lT = (lMin << 1) + 1; + while (true) { + lT = (lMin * 2) + 1; if (lT < _count) { - if (lT < _count-1) { + if (lT < _count - 1) { if (_data[lT + 1]._weight < _data[lT]._weight) lT++; } @@ -146,11 +146,11 @@ void PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { } } -PathFinding::PathFinding(ToonEngine *vm) : _vm(vm) { +PathFinding::PathFinding() { _width = 0; _height = 0; _heap = new PathFindingHeap(); - _gridTemp = NULL; + _sq = NULL; _numBlockingRects = 0; } @@ -158,17 +158,29 @@ PathFinding::~PathFinding(void) { if (_heap) _heap->unload(); delete _heap; - delete[] _gridTemp; + delete[] _sq; } -bool PathFinding::isLikelyWalkable(int32 x, int32 y) { - for (int32 i = 0; i < _numBlockingRects; i++) { +void PathFinding::init(Picture *mask) { + debugC(1, kDebugPath, "init(mask)"); + + _width = mask->getWidth(); + _height = mask->getHeight(); + _currentMask = mask; + _heap->unload(); + _heap->init(500); + delete[] _sq; + _sq = new uint16[_width * _height]; +} + +bool PathFinding::isLikelyWalkable(int16 x, int16 y) { + for (uint8 i = 0; i < _numBlockingRects; i++) { if (_blockingRects[i][4] == 0) { if (x >= _blockingRects[i][0] && x <= _blockingRects[i][2] && y >= _blockingRects[i][1] && y < _blockingRects[i][3]) return false; } else { - int32 dx = abs(_blockingRects[i][0] - x); - int32 dy = abs(_blockingRects[i][1] - y); + int16 dx = abs(_blockingRects[i][0] - x); + int16 dy = abs(_blockingRects[i][1] - y); if ((dx << 8) / _blockingRects[i][2] < (1 << 8) && (dy << 8) / _blockingRects[i][3] < (1 << 8)) { return false; } @@ -177,15 +189,13 @@ bool PathFinding::isLikelyWalkable(int32 x, int32 y) { return true; } -bool PathFinding::isWalkable(int32 x, int32 y) { +bool PathFinding::isWalkable(int16 x, int16 y) { debugC(2, kDebugPath, "isWalkable(%d, %d)", x, y); - bool maskWalk = (_currentMask->getData(x, y) & 0x1f) > 0; - - return maskWalk; + return (_currentMask->getData(x, y) & 0x1f) > 0; } -int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 *fyy, int origX, int origY) { +bool PathFinding::findClosestWalkingPoint(int16 xx, int16 yy, int16 *fxx, int16 *fyy, int16 origX, int16 origY) { debugC(1, kDebugPath, "findClosestWalkingPoint(%d, %d, fxx, fyy, %d, %d)", xx, yy, origX, origY); int32 currentFound = -1; @@ -197,8 +207,8 @@ int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 if (origY == -1) origY = yy; - for (int y = 0; y < _height; y++) { - for (int x = 0; x < _width; x++) { + for (int16 y = 0; y < _height; y++) { + for (int16 x = 0; x < _width; x++) { if (isWalkable(x, y) && isLikelyWalkable(x, y)) { int32 ndist = (x - xx) * (x - xx) + (y - yy) * (y - yy); int32 ndist2 = (x - origX) * (x - origX) + (y - origY) * (y - origY); @@ -214,15 +224,15 @@ int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 if (currentFound != -1) { *fxx = currentFound % _width; *fyy = currentFound / _width; - return 1; + return true; } else { *fxx = 0; *fyy = 0; - return 0; + return false; } } -bool PathFinding::walkLine(int32 x, int32 y, int32 x2, int32 y2) { +void PathFinding::walkLine(int16 x, int16 y, int16 x2, int16 y2) { uint32 bx = x << 16; int32 dx = x2 - x; uint32 by = y << 16; @@ -238,24 +248,17 @@ bool PathFinding::walkLine(int32 x, int32 y, int32 x2, int32 y2) { int32 cdx = (dx << 16) / t; int32 cdy = (dy << 16) / t; - int32 i = t; - _gridPathCount = 0; - while (i) { - _tempPathX[i] = bx >> 16; - _tempPathY[i] = by >> 16; - _gridPathCount++; + _tempPath.clear(); + for (int32 i = t; i > 0; i--) { + _tempPath.insert_at(0, Common::Point(bx >> 16, by >> 16)); bx += cdx; by += cdy; - i--; } - _tempPathX[0] = x2; - _tempPathY[0] = y2; - - return true; + _tempPath.insert_at(0, Common::Point(x2, y2)); } -bool PathFinding::lineIsWalkable(int32 x, int32 y, int32 x2, int32 y2) { +bool PathFinding::lineIsWalkable(int16 x, int16 y, int16 x2, int16 y2) { uint32 bx = x << 16; int32 dx = x2 - x; uint32 by = y << 16; @@ -271,27 +274,26 @@ bool PathFinding::lineIsWalkable(int32 x, int32 y, int32 x2, int32 y2) { int32 cdx = (dx << 16) / t; int32 cdy = (dy << 16) / t; - int32 i = t; - while (i) { + for (int32 i = t; i > 0; i--) { if (!isWalkable(bx >> 16, by >> 16)) return false; bx += cdx; by += cdy; - i--; } return true; } -int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { + +bool PathFinding::findPath(int16 x, int16 y, int16 destx, int16 desty) { debugC(1, kDebugPath, "findPath(%d, %d, %d, %d)", x, y, destx, desty); if (x == destx && y == desty) { - _gridPathCount = 0; + _tempPath.clear(); return true; } // ignore path finding if the character is outside the screen if (x < 0 || x > 1280 || y < 0 || y > 400 || destx < 0 || destx > 1280 || desty < 0 || desty > 400) { - _gridPathCount = 0; + _tempPath.clear(); return true; } @@ -302,40 +304,45 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { } // no direct line, we use the standard A* algorithm - memset(_gridTemp , 0, _width * _height * sizeof(int32)); + memset(_sq , 0, _width * _height * sizeof(uint16)); _heap->clear(); - int32 curX = x; - int32 curY = y; - int32 curWeight = 0; - int32 *sq = _gridTemp; + int16 curX = x; + int16 curY = y; + uint16 curWeight = 0; - sq[curX + curY *_width] = 1; + _sq[curX + curY *_width] = 1; _heap->push(curX, curY, abs(destx - x) + abs(desty - y)); - int wei = 0; while (_heap->getCount()) { - wei = 0; _heap->pop(&curX, &curY, &curWeight); - int curNode = curX + curY * _width; + int32 curNode = curX + curY * _width; - int32 endX = MIN<int32>(curX + 1, _width - 1); - int32 endY = MIN<int32>(curY + 1, _height - 1); - int32 startX = MAX<int32>(curX - 1, 0); - int32 startY = MAX<int32>(curY - 1, 0); + int16 endX = MIN<int16>(curX + 1, _width - 1); + int16 endY = MIN<int16>(curY + 1, _height - 1); + int16 startX = MAX<int16>(curX - 1, 0); + int16 startY = MAX<int16>(curY - 1, 0); bool next = false; - for (int32 px = startX; px <= endX && !next; px++) { - for (int py = startY; py <= endY && !next; py++) { + for (int16 px = startX; px <= endX && !next; px++) { + for (int16 py = startY; py <= endY && !next; py++) { if (px != curX || py != curY) { - wei = ((abs(px - curX) + abs(py - curY))); + uint16 wei = abs(px - curX) + abs(py - curY); - int32 curPNode = px + py * _width; if (isWalkable(px, py)) { // walkable ? - int sum = sq[curNode] + wei * (1 + (isLikelyWalkable(px, py) ? 5 : 0)); - if (sq[curPNode] > sum || !sq[curPNode]) { - int newWeight = abs(destx - px) + abs(desty - py); - sq[curPNode] = sum; - _heap->push(px, py, sq[curPNode] + newWeight); + int32 curPNode = px + py * _width; + uint32 sum = _sq[curNode] + wei * (1 + (isLikelyWalkable(px, py) ? 5 : 0)); + if (sum > (uint32)0xFFFF) { + warning("PathFinding::findPath sum exceeds maximum representable!"); + sum = (uint32)0xFFFF; + } + if (_sq[curPNode] > sum || !_sq[curPNode]) { + _sq[curPNode] = sum; + uint32 newWeight = _sq[curPNode] + abs(destx - px) + abs(desty - py); + if (newWeight > (uint32)0xFFFF) { + warning("PathFinding::findPath newWeight exceeds maximum representable!"); + newWeight = (uint16)0xFFFF; + } + _heap->push(px, py, newWeight); if (!newWeight) next = true; // we found it ! } @@ -346,49 +353,37 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { } // let's see if we found a result ! - if (!_gridTemp[destx + desty * _width]) { + if (!_sq[destx + desty * _width]) { // didn't find anything - _gridPathCount = 0; + _tempPath.clear(); return false; } curX = destx; curY = desty; - int32 *retPathX = (int32 *)malloc(4096 * sizeof(int32)); - int32 *retPathY = (int32 *)malloc(4096 * sizeof(int32)); - if (!retPathX || !retPathY) { - free(retPathX); - free(retPathY); - - error("[PathFinding::findPath] Cannot allocate pathfinding buffers"); - } - - int32 numpath = 0; + Common::Array<Common::Point> retPath; + retPath.push_back(Common::Point(curX, curY)); - retPathX[numpath] = curX; - retPathY[numpath] = curY; - numpath++; - int32 bestscore = sq[destx + desty * _width]; + uint16 bestscore = _sq[destx + desty * _width]; - while (1) { - int32 bestX = -1; - int32 bestY = -1; + bool retVal = false; + while (true) { + int16 bestX = -1; + int16 bestY = -1; - int32 endX = MIN<int32>(curX + 1, _width - 1); - int32 endY = MIN<int32>(curY + 1, _height - 1); - int32 startX = MAX<int32>(curX - 1, 0); - int32 startY = MAX<int32>(curY - 1, 0); + int16 endX = MIN<int16>(curX + 1, _width - 1); + int16 endY = MIN<int16>(curY + 1, _height - 1); + int16 startX = MAX<int16>(curX - 1, 0); + int16 startY = MAX<int16>(curY - 1, 0); - for (int32 px = startX; px <= endX; px++) { - for (int32 py = startY; py <= endY; py++) { + for (int16 px = startX; px <= endX; px++) { + for (int16 py = startY; py <= endY; py++) { if (px != curX || py != curY) { - wei = abs(px - curX) + abs(py - curY); - - int PNode = px + py * _width; - if (sq[PNode] && (isWalkable(px, py))) { - if (sq[PNode] < bestscore) { - bestscore = sq[PNode]; + int32 PNode = px + py * _width; + if (_sq[PNode] && (isWalkable(px, py))) { + if (_sq[PNode] < bestscore) { + bestscore = _sq[PNode]; bestX = px; bestY = py; } @@ -397,57 +392,33 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { } } - if (bestX < 0 || bestY < 0) { - free(retPathX); - free(retPathY); - - return 0; - } + if (bestX < 0 || bestY < 0) + break; - retPathX[numpath] = bestX; - retPathY[numpath] = bestY; - numpath++; + retPath.push_back(Common::Point(bestX, bestY)); if ((bestX == x && bestY == y)) { - _gridPathCount = numpath; - - memcpy(_tempPathX, retPathX, sizeof(int32) * numpath); - memcpy(_tempPathY, retPathY, sizeof(int32) * numpath); - - free(retPathX); - free(retPathY); + _tempPath.clear(); + for (uint32 i = 0; i < retPath.size(); i++) + _tempPath.push_back(retPath[i]); - return true; + retVal = true; + break; } curX = bestX; curY = bestY; } - free(retPathX); - free(retPathY); - - return false; + return retVal; } -void PathFinding::init(Picture *mask) { - debugC(1, kDebugPath, "init(mask)"); - - _width = mask->getWidth(); - _height = mask->getHeight(); - _currentMask = mask; - _heap->unload(); - _heap->init(500); - delete[] _gridTemp; - _gridTemp = new int32[_width*_height]; -} - -void PathFinding::resetBlockingRects() { - _numBlockingRects = 0; -} - -void PathFinding::addBlockingRect(int32 x1, int32 y1, int32 x2, int32 y2) { +void PathFinding::addBlockingRect(int16 x1, int16 y1, int16 x2, int16 y2) { debugC(1, kDebugPath, "addBlockingRect(%d, %d, %d, %d)", x1, y1, x2, y2); + if (_numBlockingRects >= kMaxBlockingRects) { + warning("Maximum number of %d Blocking Rects reached!", kMaxBlockingRects); + return; + } _blockingRects[_numBlockingRects][0] = x1; _blockingRects[_numBlockingRects][1] = y1; @@ -457,8 +428,12 @@ void PathFinding::addBlockingRect(int32 x1, int32 y1, int32 x2, int32 y2) { _numBlockingRects++; } -void PathFinding::addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h) { - debugC(1, kDebugPath, "addBlockingRect(%d, %d, %d, %d)", x1, y1, w, h); +void PathFinding::addBlockingEllipse(int16 x1, int16 y1, int16 w, int16 h) { + debugC(1, kDebugPath, "addBlockingEllipse(%d, %d, %d, %d)", x1, y1, w, h); + if (_numBlockingRects >= kMaxBlockingRects) { + warning("Maximum number of %d Blocking Rects reached!", kMaxBlockingRects); + return; + } _blockingRects[_numBlockingRects][0] = x1; _blockingRects[_numBlockingRects][1] = y1; @@ -468,16 +443,4 @@ void PathFinding::addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h) { _numBlockingRects++; } -int32 PathFinding::getPathNodeCount() const { - return _gridPathCount; -} - -int32 PathFinding::getPathNodeX(int32 nodeId) const { - return _tempPathX[ _gridPathCount - nodeId - 1]; -} - -int32 PathFinding::getPathNodeY(int32 nodeId) const { - return _tempPathY[ _gridPathCount - nodeId - 1]; -} - } // End of namespace Toon diff --git a/engines/toon/path.h b/engines/toon/path.h index 2de58064f0..59f74ef286 100644 --- a/engines/toon/path.h +++ b/engines/toon/path.h @@ -23,72 +23,75 @@ #ifndef TOON_PATH_H #define TOON_PATH_H +#include "common/array.h" +#include "common/rect.h" + #include "toon/toon.h" namespace Toon { // binary heap system for fast A* -struct HeapDataGrid { - int16 _x, _y; - int16 _weight; -}; - class PathFindingHeap { public: PathFindingHeap(); ~PathFindingHeap(); - void push(int32 x, int32 y, int32 weight); - void pop(int32 *x, int32 *y, int32 *weight); + void push(int16 x, int16 y, uint16 weight); + void pop(int16 *x, int16 *y, uint16 *weight); void init(int32 size); void clear(); void unload(); - int32 getCount() { return _count; } + uint32 getCount() { return _count; } private: + struct HeapDataGrid { + int16 _x, _y; + uint16 _weight; + }; + HeapDataGrid *_data; - int32 _size; - int32 _count; + uint32 _size; + uint32 _count; }; class PathFinding { public: - PathFinding(ToonEngine *vm); + PathFinding(); ~PathFinding(); - int32 findPath(int32 x, int32 y, int32 destX, int32 destY); - int32 findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 *fyy, int origX = -1, int origY = -1); - bool isWalkable(int32 x, int32 y); - bool isLikelyWalkable(int32 x, int32 y); - bool lineIsWalkable(int32 x, int32 y, int32 x2, int32 y2); - bool walkLine(int32 x, int32 y, int32 x2, int32 y2); void init(Picture *mask); - void resetBlockingRects(); - void addBlockingRect(int32 x1, int32 y1, int32 x2, int32 y2); - void addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h); + bool findPath(int16 x, int16 y, int16 destX, int16 destY); + bool findClosestWalkingPoint(int16 xx, int16 yy, int16 *fxx, int16 *fyy, int16 origX = -1, int16 origY = -1); + bool isWalkable(int16 x, int16 y); + bool isLikelyWalkable(int16 x, int16 y); + bool lineIsWalkable(int16 x, int16 y, int16 x2, int16 y2); + void walkLine(int16 x, int16 y, int16 x2, int16 y2); + + void resetBlockingRects() { _numBlockingRects = 0; } + void addBlockingRect(int16 x1, int16 y1, int16 x2, int16 y2); + void addBlockingEllipse(int16 x1, int16 y1, int16 w, int16 h); + + uint32 getPathNodeCount() const { return _tempPath.size(); } + int16 getPathNodeX(uint32 nodeId) const { return _tempPath[(_tempPath.size() - 1) - nodeId].x; } + int16 getPathNodeY(uint32 nodeId) const { return _tempPath[(_tempPath.size() - 1) - nodeId].y; } + +private: + static const uint8 kMaxBlockingRects = 16; - int32 getPathNodeCount() const; - int32 getPathNodeX(int32 nodeId) const; - int32 getPathNodeY(int32 nodeId) const; -protected: Picture *_currentMask; PathFindingHeap *_heap; - int32 *_gridTemp; - int32 _width; - int32 _height; + uint16 *_sq; + int16 _width; + int16 _height; - int32 _tempPathX[4096]; - int32 _tempPathY[4096]; - int32 _blockingRects[16][5]; - int32 _numBlockingRects; - int32 _allocatedGridPathCount; - int32 _gridPathCount; + Common::Array<Common::Point> _tempPath; - ToonEngine *_vm; + int16 _blockingRects[kMaxBlockingRects][5]; + uint8 _numBlockingRects; }; } // End of namespace Toon diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp index ff136e5acb..204b0fe576 100644 --- a/engines/toon/picture.cpp +++ b/engines/toon/picture.cpp @@ -150,7 +150,7 @@ void Picture::setupPalette() { _vm->setPaletteEntries(_palette, 1, 128); } -void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) { +void Picture::drawMask(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy) { debugC(1, kDebugPicture, "drawMask(surface, %d, %d, %d, %d)", x, y, dx, dy); for (int32 i = 0; i < 128; i++) { @@ -161,8 +161,8 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i _vm->setPaletteEntries(color, i, 1); } - int32 rx = MIN(_width, surface.w - x); - int32 ry = MIN(_height, surface.h - y); + int16 rx = MIN<int16>(_width, surface.w - x); + int16 ry = MIN<int16>(_height, surface.h - y); if (rx < 0 || ry < 0) return; @@ -172,10 +172,10 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i uint8 *c = _data + _width * dy + dx; uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x; - for (int32 yy = 0; yy < ry; yy++) { + for (int16 yy = 0; yy < ry; yy++) { uint8 *curSrc = c; uint8 *cur = curRow; - for (int32 xx = 0; xx < rx; xx++) { + for (int16 xx = 0; xx < rx; xx++) { //*cur = (*curSrc >> 5) * 8; // & 0x1f; *cur = (*curSrc & 0x1f) ? 127 : 0; @@ -187,10 +187,9 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i } } -void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray) { - - int32 rx = MIN(_width, surface.w - x); - int32 ry = MIN(_height, surface.h - y); +void Picture::drawWithRectList(Graphics::Surface& surface, int16 x, int16 y, int16 dx, int16 dy, Common::Array<Common::Rect>& rectArray) { + int16 rx = MIN<int16>(_width, surface.w - x); + int16 ry = MIN<int16>(_height, surface.h - y); if (rx < 0 || ry < 0) return; @@ -202,16 +201,16 @@ void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int Common::Rect rect = rectArray[i]; - int32 fillRx = MIN<int32>(rx, rect.right - rect.left); - int32 fillRy = MIN<int32>(ry, rect.bottom - rect.top); + int16 fillRx = MIN<int32>(rx, rect.right - rect.left); + int16 fillRy = MIN<int32>(ry, rect.bottom - rect.top); uint8 *c = _data + _width * (dy + rect.top) + (dx + rect.left); uint8 *curRow = (uint8 *)surface.pixels + (y + rect.top) * destPitch + (x + rect.left); - for (int32 yy = 0; yy < fillRy; yy++) { + for (int16 yy = 0; yy < fillRy; yy++) { uint8 *curSrc = c; uint8 *cur = curRow; - for (int32 xx = 0; xx < fillRx; xx++) { + for (int16 xx = 0; xx < fillRx; xx++) { *cur = *curSrc; curSrc++; cur++; @@ -222,11 +221,11 @@ void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int } } -void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) { +void Picture::draw(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy) { debugC(6, kDebugPicture, "draw(surface, %d, %d, %d, %d)", x, y, dx, dy); - int32 rx = MIN(_width, surface.w - x); - int32 ry = MIN(_height, surface.h - y); + int16 rx = MIN<int16>(_width, surface.w - x); + int16 ry = MIN<int16>(_height, surface.h - y); if (rx < 0 || ry < 0) return; @@ -236,10 +235,10 @@ void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 uint8 *c = _data + _width * dy + dx; uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x; - for (int32 yy = 0; yy < ry; yy++) { + for (int16 yy = 0; yy < ry; yy++) { uint8 *curSrc = c; uint8 *cur = curRow; - for (int32 xx = 0; xx < rx; xx++) { + for (int16 xx = 0; xx < rx; xx++) { *cur = *curSrc; curSrc++; cur++; @@ -249,7 +248,7 @@ void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 } } -uint8 Picture::getData(int32 x, int32 y) { +uint8 Picture::getData(int16 x, int16 y) { debugC(6, kDebugPicture, "getData(%d, %d)", x, y); if (!_data) @@ -259,7 +258,7 @@ uint8 Picture::getData(int32 x, int32 y) { } // use original work from johndoe -void Picture::floodFillNotWalkableOnMask(int32 x, int32 y) { +void Picture::floodFillNotWalkableOnMask(int16 x, int16 y) { debugC(1, kDebugPicture, "floodFillNotWalkableOnMask(%d, %d)", x, y); // Stack-based floodFill algorithm based on // http://student.kuleuven.be/~m0216922/CG/files/floodfill.cpp @@ -292,10 +291,10 @@ void Picture::floodFillNotWalkableOnMask(int32 x, int32 y) { } } -void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable) { +void Picture::drawLineOnMask(int16 x, int16 y, int16 x2, int16 y2, bool walkable) { debugC(1, kDebugPicture, "drawLineOnMask(%d, %d, %d, %d, %d)", x, y, x2, y2, (walkable) ? 1 : 0); - static int32 lastX = 0; - static int32 lastY = 0; + static int16 lastX = 0; + static int16 lastY = 0; if (x == -1) { x = lastX; @@ -303,12 +302,12 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable } uint32 bx = x << 16; - int32 dx = x2 - x; + int16 dx = x2 - x; uint32 by = y << 16; - int32 dy = y2 - y; - uint32 adx = abs(dx); - uint32 ady = abs(dy); - int32 t = 0; + int16 dy = y2 - y; + uint16 adx = abs(dx); + uint16 ady = abs(dy); + int16 t = 0; if (adx <= ady) t = ady; else @@ -317,9 +316,7 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable int32 cdx = (dx << 16) / t; int32 cdy = (dy << 16) / t; - int32 i = t; - while (i) { - + for (int16 i = t; i > 0; i--) { int32 rx = bx >> 16; int32 ry = by >> 16; @@ -337,7 +334,6 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable bx += cdx; by += cdy; - i--; } } } // End of namespace Toon diff --git a/engines/toon/picture.h b/engines/toon/picture.h index 460c5b58a2..5e79612a39 100644 --- a/engines/toon/picture.h +++ b/engines/toon/picture.h @@ -33,25 +33,27 @@ namespace Toon { class ToonEngine; -class Picture { +class Picture { public: Picture(ToonEngine *vm); ~Picture(); + bool loadPicture(const Common::String &file); void setupPalette(); - void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy); - void drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray); - void drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy); - void drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable); - void floodFillNotWalkableOnMask(int32 x, int32 y); - uint8 getData(int32 x, int32 y); + void draw(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy); + void drawWithRectList(Graphics::Surface& surface, int16 x, int16 y, int16 dx, int16 dy, Common::Array<Common::Rect>& rectArray); + void drawMask(Graphics::Surface &surface, int16 x, int16 y, int16 dx, int16 dy); + void drawLineOnMask(int16 x, int16 y, int16 x2, int16 y2, bool walkable); + void floodFillNotWalkableOnMask(int16 x, int16 y); + uint8 getData(int16 x, int16 y); uint8 *getDataPtr() { return _data; } - int32 getWidth() const { return _width; } - int32 getHeight() const { return _height; } + int16 getWidth() const { return _width; } + int16 getHeight() const { return _height; } + protected: - int32 _width; - int32 _height; + int16 _width; + int16 _height; uint8 *_data; uint8 *_palette; // need to be copied at 3-387 int32 _paletteEntries; diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp index e9b7534198..1fa4058114 100644 --- a/engines/toon/script_func.cpp +++ b/engines/toon/script_func.cpp @@ -564,9 +564,9 @@ int32 ScriptFunc::sys_Cmd_Exit_Conversation(EMCState *state) { int32 ScriptFunc::sys_Cmd_Set_Mouse_Pos(EMCState *state) { if (_vm->state()->_inCloseUp) { - _vm->getSystem()->warpMouse(stackPos(0), stackPos(1)); + _vm->_system->warpMouse(stackPos(0), stackPos(1)); } else { - _vm->getSystem()->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1)); + _vm->_system->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1)); } return 0; } diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 657e18635f..9fd8415676 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -51,7 +51,7 @@ void ToonEngine::init() { _currentScriptRegion = 0; _resources = new Resources(this); _animationManager = new AnimationManager(this); - _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer)); + _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder()); _hotspots = new Hotspots(this); _mainSurface = new Graphics::Surface(); @@ -100,7 +100,7 @@ void ToonEngine::init() { syncSoundSettings(); - _pathFinding = new PathFinding(this); + _pathFinding = new PathFinding(); resources()->openPackage("LOCAL.PAK"); resources()->openPackage("ONETIME.PAK"); @@ -168,7 +168,7 @@ void ToonEngine::waitForScriptStep() { // Wait after a specified number of script steps when executing a script // to lower CPU usage if (++_scriptStep >= 40) { - g_system->delayMillis(1); + _system->delayMillis(1); _scriptStep = 0; } } @@ -820,7 +820,6 @@ Common::Error ToonEngine::run() { ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription) : Engine(syst), _gameDescription(gameDescription), _language(gameDescription->language), _rnd("toon") { - _system = syst; _tickLength = 16; _currentPicture = NULL; _inventoryPicture = NULL; @@ -1224,7 +1223,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { _script->init(&_sceneAnimationScripts[i]._state, _sceneAnimationScripts[i]._data); if (!forGameLoad) { _script->start(&_sceneAnimationScripts[i]._state, 9 + i); - _sceneAnimationScripts[i]._lastTimer = getSystem()->getMillis(); + _sceneAnimationScripts[i]._lastTimer = _system->getMillis(); _sceneAnimationScripts[i]._frozen = false; _sceneAnimationScripts[i]._frozenForConversation = false; } @@ -1488,7 +1487,7 @@ void ToonEngine::clickEvent() { } if (!currentHot) { - int32 xx, yy; + int16 xx, yy; if (_gameState->_inCutaway || _gameState->_inInventory || _gameState->_inCloseUp) return; @@ -1588,12 +1587,12 @@ void ToonEngine::clickEvent() { } void ToonEngine::selectHotspot() { - int32 x1 = 0; - int32 x2 = 0; - int32 y1 = 0; - int32 y2 = 0; + int16 x1 = 0; + int16 x2 = 0; + int16 y1 = 0; + int16 y2 = 0; - int32 mouseX = _mouseX; + int16 mouseX = _mouseX; if (_gameState->_inCutaway) mouseX += TOON_BACKBUFFER_WIDTH; @@ -1693,7 +1692,6 @@ void ToonEngine::selectHotspot() { } void ToonEngine::exitScene() { - fadeOut(5); // disable all scene animation @@ -2831,7 +2829,6 @@ void ToonEngine::playSoundWrong() { } void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { - if (characterId < 0) characterId = 0; @@ -2852,8 +2849,8 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { } } else if (characterId == 1) { // flux - int32 x = _flux->getX(); - int32 y = _flux->getY(); + int16 x = _flux->getX(); + int16 y = _flux->getY(); if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) { if (!_gameState->_inCutaway) { *retX = x; @@ -2885,7 +2882,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { if (character && !_gameState->_inCutaway) { if (character->getAnimationInstance()) { if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) { - int32 x1, y1, x2, y2; + int16 x1, y1, x2, y2; character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2); *retX = (x1 + x2) / 2; *retY = y1; @@ -2896,7 +2893,6 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { } Character *ToonEngine::getCharacterById(int32 charId) { - for (int32 i = 0; i < 8; i++) { if (_characters[i] && _characters[i]->getId() == charId) return _characters[i]; @@ -2955,15 +2951,12 @@ Common::String ToonEngine::getSavegameName(int nr) { } bool ToonEngine::saveGame(int32 slot, const Common::String &saveGameDesc) { - const EnginePlugin *plugin = NULL; int16 savegameId; Common::String savegameDescription; - EngineMan.findGame(_gameDescription->gameid, &plugin); if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); - dialog->setSaveMode(true); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + savegameId = dialog->runModalWithCurrentTarget(); savegameDescription = dialog->getResultString(); delete dialog; } else { @@ -2979,8 +2972,7 @@ bool ToonEngine::saveGame(int32 slot, const Common::String &saveGameDesc) { return false; // dialog aborted Common::String savegameFile = getSavegameName(savegameId); - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::OutSaveFile *saveFile = saveMan->openForSaving(savegameFile); + Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(savegameFile); if (!saveFile) return false; @@ -3052,14 +3044,11 @@ bool ToonEngine::saveGame(int32 slot, const Common::String &saveGameDesc) { } bool ToonEngine::loadGame(int32 slot) { - const EnginePlugin *plugin = NULL; int16 savegameId; - EngineMan.findGame(_gameDescription->gameid, &plugin); if (slot == -1) { - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); - dialog->setSaveMode(false); - savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } else { savegameId = slot; @@ -3068,8 +3057,7 @@ bool ToonEngine::loadGame(int32 slot) { return false; // dialog aborted Common::String savegameFile = getSavegameName(savegameId); - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *loadFile = saveMan->openForLoading(savegameFile); + Common::InSaveFile *loadFile = _saveFileMan->openForLoading(savegameFile); if (!loadFile) return false; diff --git a/engines/toon/toon.h b/engines/toon/toon.h index 540f3e403b..d40c489011 100644 --- a/engines/toon/toon.h +++ b/engines/toon/toon.h @@ -289,10 +289,6 @@ public: return _oldTimer2; } - OSystem *getSystem() { - return _system; - } - AudioManager *getAudioManager() { return _audioManager; } @@ -340,7 +336,6 @@ public: void clearDirtyRects(); protected: - OSystem *_system; int32 _tickLength; Resources *_resources; TextResource *_genericTexts; diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index 35dd54776f..e4bbe0c4c1 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -135,19 +135,13 @@ public: } virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { - const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, Touche::fileBasedFallback); - - if (matchedDesc) { // We got a match - Common::String report = Common::String::format(_("Your game version has been detected using " - "filename matching as a variant of %s."), matchedDesc->gameid); - report += "\n"; - report += _("If this is an original and unmodified version, please report any"); - report += "\n"; - report += _("information previously printed by ScummVM to the team."); - report += "\n"; - g_system->logMessage(LogMessageType::kInfo, report.c_str()); - } + ADFilePropertiesMap filesProps; + + const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback, &filesProps); + if (!matchedDesc) + return 0; + reportUnknown(fslist.begin()->getParent(), filesProps); return matchedDesc; } diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp index a76d5839a9..23701c9e5b 100644 --- a/engines/tsage/blue_force/blueforce_dialogs.cpp +++ b/engines/tsage/blue_force/blueforce_dialogs.cpp @@ -88,7 +88,7 @@ RightClickDialog::~RightClickDialog() { void RightClickDialog::draw() { // Save the covered background area - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); // Draw the dialog image g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top); @@ -323,7 +323,7 @@ void AmmoBeltDialog::draw() { if (!_savedArea) { // Save the covered background area - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); } else { bounds.moveTo(0, 0); } diff --git a/engines/tsage/blue_force/blueforce_scenes9.cpp b/engines/tsage/blue_force/blueforce_scenes9.cpp index 2178f31b30..1cb8191640 100644 --- a/engines/tsage/blue_force/blueforce_scenes9.cpp +++ b/engines/tsage/blue_force/blueforce_scenes9.cpp @@ -794,12 +794,12 @@ bool Scene910::Lyle::startAction(CursorType action, Event &event) { Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene; if (action == CURSOR_USE) { - if (BF_GLOBALS._v4CEE2 == 0) + if (BF_GLOBALS._nico910State == 0) return NamedObject::startAction(action, event); else return false; } else if (action == CURSOR_TALK) { - if ((BF_GLOBALS._hiddenDoorStatus != 0) || (BF_GLOBALS._v4CEE2 != 0)) { + if ((BF_GLOBALS._hiddenDoorStatus != 0) || (BF_GLOBALS._nico910State != 0)) { scene->_stripManager.start(9100 + _field90, &BF_GLOBALS._stripProxy); if (_field90 < 1) _field90++; @@ -833,7 +833,7 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) { return true; break; case CURSOR_TALK: - if (BF_GLOBALS._v4CEE2 >= 4) + if (BF_GLOBALS._nico910State >= 4) return NamedObject::startAction(action, event); if (BF_GLOBALS._v4CEE6 < 4) @@ -847,8 +847,8 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) { return true; break; case INV_COLT45: - if (BF_GLOBALS._v4CEE2 > 1) { - if (BF_GLOBALS._v4CEE2 != 4) { + if (BF_GLOBALS._nico910State > 1) { + if (BF_GLOBALS._nico910State != 4) { if ((BF_GLOBALS.getFlag(gunDrawn)) && (BF_GLOBALS.getFlag(fGunLoaded)) && (BF_GLOBALS.getHasBullets())) { if (scene->_field2DE0 == 0) { BF_GLOBALS._player.disableControl(); @@ -880,7 +880,7 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) { break; case INV_BADGE: case INV_ID: - if (BF_GLOBALS._v4CEE2 >= 4) + if (BF_GLOBALS._nico910State >= 4) return NamedObject::startAction(action, event); if (BF_GLOBALS._v4CEE6 < 4) @@ -895,11 +895,12 @@ bool Scene910::Nico::startAction(CursorType action, Event &event) { return true; break; case INV_YELLOW_CORD: - if (BF_GLOBALS._v4CEE2 < 4) { + if (BF_GLOBALS._nico910State < 4) { BF_GLOBALS._player.disableControl(); scene->_yellowCord.fixPriority(121); scene->_sceneSubMode = 10; scene->_sceneMode = 9123; + BF_GLOBALS._nico910State = 3; if (BF_GLOBALS._player._visage == 1911) scene->setAction(&scene->_sequenceManager1, scene, 9123, &BF_GLOBALS._player, NULL); else @@ -995,7 +996,7 @@ bool Scene910::Stuart::startAction(CursorType action, Event &event) { return true; } else { BF_GLOBALS._player.disableControl(); - if (BF_GLOBALS._v4CEE2 == 4) { + if (BF_GLOBALS._nico910State == 4) { scene->_sceneSubMode = 11; scene->_sceneMode = 9123; if (BF_GLOBALS._player._visage == 1911) @@ -1136,7 +1137,7 @@ bool Scene910::BreakerBox::startAction(CursorType action, Event &event) { SceneItem::display2(910, 62); return true; } else if (scene->_sceneMode != 9120) { - if (BF_GLOBALS._v4CEE2 == 1) { + if (BF_GLOBALS._nico910State == 1) { BF_GLOBALS._player.disableControl(); scene->_sceneMode = 9118; scene->setAction(&scene->_sequenceManager1, scene, 9118, &BF_GLOBALS._player, &scene->_nico, NULL); @@ -1291,7 +1292,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) { switch (_state) { case 1: - if (BF_GLOBALS._v4CEE2 < 1) { + if (BF_GLOBALS._nico910State < 1) { if (_frame == 2) { if (!BF_GLOBALS.getFlag(fGotPointsForClosingDoor)) { T2_GLOBALS._uiElements.addScore(30); @@ -1299,7 +1300,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) { } scene->_sceneMode = 0; if (BF_GLOBALS._dayNumber == 5) { - if (BF_GLOBALS._v4CEE2 == 0) { + if (BF_GLOBALS._nico910State == 0) { scene->_breakerBoxInset.remove(); // _objectList.draw(); BF_GLOBALS._player.disableControl(); @@ -1309,7 +1310,7 @@ bool Scene910::Object13::startAction(CursorType action, Event &event) { scene->_nico.postInit(); scene->_sceneMode = 9129; scene->setAction(&scene->_sequenceManager1, scene, 9129, &BF_GLOBALS._player, &scene->_nico, NULL); - } else if (BF_GLOBALS._v4CEE2 == 2) { + } else if (BF_GLOBALS._nico910State == 2) { scene->_breakerBoxInset.remove(); // _objectList.draw(); BF_GLOBALS._player.disableControl(); @@ -1612,7 +1613,7 @@ bool Scene910::BlackPlug::startAction(CursorType action, Event &event) { SET_EXT_FGCOLOR, 13, LIST_END); return true; } - if (BF_GLOBALS._v4CEE2 == 3) { + if (BF_GLOBALS._nico910State == 3) { SceneItem::display(910, 84, SET_WIDTH, 312, SET_X, GLOBALS._sceneManager._scene->_sceneBounds.left + 4, SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2, @@ -1830,7 +1831,7 @@ bool Scene910::Generator::startAction(CursorType action, Event &event) { SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2, SET_FONT, 4, SET_BG_COLOR, 1, SET_FG_COLOR, 19, SET_EXT_BGCOLOR, 9, SET_EXT_FGCOLOR, 13, LIST_END); - else if (BF_GLOBALS._v4CEE2 == 1) { + else if (BF_GLOBALS._nico910State == 1) { BF_GLOBALS._player.disableControl(); scene->_sceneMode = 9118; scene->setAction(&scene->_sequenceManager1, scene, 9118, &BF_GLOBALS._player, &scene->_nico, NULL); @@ -1869,7 +1870,7 @@ bool Scene910::Item2::startAction(CursorType action, Event &event) { bool Scene910::Item3::startAction(CursorType action, Event &event) { Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene; - if ((action == CURSOR_TALK) && (BF_GLOBALS._v4CEE2 == 4) && (BF_GLOBALS._v4CEE4 == 0)) { + if ((action == CURSOR_TALK) && (BF_GLOBALS._nico910State == 4) && (BF_GLOBALS._v4CEE4 == 0)) { BF_GLOBALS._player.disableControl(); scene->_sceneMode = 15; scene->_stripManager.start(9102, scene); @@ -1907,7 +1908,7 @@ bool Scene910::Item15::startAction(CursorType action, Event &event) { bool Scene910::Item16::startAction(CursorType action, Event &event) { Scene910 *scene = (Scene910 *)BF_GLOBALS._sceneManager._scene; - if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._v4CEE2 != 0)) + if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._nico910State != 0)) return false; if (BF_GLOBALS._player._visage == 1911) { @@ -2016,7 +2017,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) { if (BF_GLOBALS._dayNumber < 5) _item17.setDetails(Rect(0, 149, 29, 167), 910, -1, -1, -1, 1, NULL); - if (BF_GLOBALS._v4CEE2 == 0) + if (BF_GLOBALS._nico910State == 0) _item16.setDetails(Rect(265, 18, 319, 102), 910, -1, -1, -1, 1, NULL); _breakerBox.setDetails(910, 6, -1, -1, 1, (SceneItem *)NULL); @@ -2048,7 +2049,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) { || (BF_GLOBALS._sceneManager._previousScene == 190) || (BF_GLOBALS._sceneManager._previousScene == 300)) { BF_GLOBALS._sceneManager._previousScene = 900; - BF_GLOBALS._v4CEE2 = 0; + BF_GLOBALS._nico910State = 0; BF_GLOBALS._v4CEE4 = 0; } @@ -2142,7 +2143,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) { _nico.setPosition(Common::Point(262, 124)); _nico.setStrip(6); BF_GLOBALS._v4CEE6 = 0; - BF_GLOBALS._v4CEE2 = 1; + BF_GLOBALS._nico910State = 1; _nico.setDetails(910, 63, 64, 67, 5, &_item4); BF_GLOBALS._v4CECA = 2; if (BF_GLOBALS._v4CECC == 0) @@ -2157,7 +2158,7 @@ void Scene910::postInit(SceneObjectList *OwnerList) { BF_GLOBALS._player.disableControl(); } - if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)){ + if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)){ _shadow.postInit(); _shadow.setAction(&_action2); } @@ -2297,7 +2298,7 @@ void Scene910::signal() { case 13: BF_GLOBALS._player.disableControl(); BF_GLOBALS._player.setAction(&_sequenceManager2, NULL, 9117, &_nico, NULL); - BF_GLOBALS._v4CEE2 = 2; + BF_GLOBALS._nico910State = 2; // No break on purpose case 15: _stuart.postInit(); @@ -2314,7 +2315,7 @@ void Scene910::signal() { _lyle._field90 = 1; _sceneMode = 10; addFader((const byte *)&black, 2, this); - BF_GLOBALS._v4CEE2 = 1; + BF_GLOBALS._nico910State = 1; BF_GLOBALS._walkRegions.disableRegion(16); BF_GLOBALS._walkRegions.disableRegion(14); BF_GLOBALS._sceneItems.remove(&_item16); @@ -2324,7 +2325,7 @@ void Scene910::signal() { BF_GLOBALS._player._frame = 1; if (_field2DE2 == 0) { _field2DE2 = 1; - if (BF_GLOBALS._v4CEE2 == 4) { + if (BF_GLOBALS._nico910State == 4) { _sceneMode = 9149; setAction(&_sequenceManager1, this, 9149, &BF_GLOBALS._player, NULL); } else { @@ -2452,7 +2453,7 @@ void Scene910::signal() { break; case 9114: _fakeWall.hide(); - if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)) { + if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)) { BF_GLOBALS._player.disableControl(); _nico.postInit(); _nico.setDetails(910, 63, 64, 65, 5, &_item4); @@ -2496,7 +2497,7 @@ void Scene910::signal() { case 9121: _item3.setDetails(7, 910, 96, 60, 61, 3); BF_GLOBALS._v4CEE4 = 2; - if (BF_GLOBALS._v4CEE2 == 4) { + if (BF_GLOBALS._nico910State == 4) { _sceneMode = 20; _stripManager.start(9115, this); } else { @@ -2527,7 +2528,7 @@ void Scene910::signal() { setAction(&_sequenceManager1, this, 9111, &BF_GLOBALS._player, &_blackCord, NULL); break; case 5: - switch (BF_GLOBALS._v4CEE2 - 1) { + switch (BF_GLOBALS._nico910State - 1) { case 0: _sceneMode = 9118; setAction(&_sequenceManager1, this, 9118, &BF_GLOBALS._player, &_nico, NULL); @@ -2598,7 +2599,7 @@ void Scene910::signal() { break; case 9125: BF_GLOBALS.setFlag(fBackupAt340); - BF_GLOBALS._v4CEE2 = 4; + BF_GLOBALS._nico910State = 4; _stuart.postInit(); _nico.setDetails(910, 72, 73, 74, 3, (SceneItem *)NULL); _stuart.setDetails(910, 66, 67, 68, 5, &_nico); @@ -2645,7 +2646,7 @@ void Scene910::signal() { } _lyle.setAction(&_sequenceManager2, NULL, 9131, &_lyle, NULL); BF_GLOBALS._walkRegions.enableRegion(16); - if (BF_GLOBALS._v4CEE2 == 4) + if (BF_GLOBALS._nico910State == 4) BF_INVENTORY.setObjectScene(INV_YELLOW_CORD, 0); else BF_INVENTORY.setObjectScene(INV_HALF_YELLOW_CORD, 910); @@ -2679,7 +2680,7 @@ void Scene910::signal() { } break; case 9143: - if (BF_GLOBALS._v4CEE2 == 0) { + if (BF_GLOBALS._nico910State == 0) { BF_GLOBALS._v51C44 = 1; BF_GLOBALS._sceneManager.changeScene(920); } else { @@ -2730,7 +2731,7 @@ void Scene910::process(Event &event) { if (_item17._bounds.contains(event.mousePos)) { GfxSurface surface = _cursorVisage.getFrame(EXITFRAME_SW); BF_GLOBALS._events.setCursor(surface); - } else if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._v4CEE2 != 0)) { + } else if ((BF_GLOBALS._hiddenDoorStatus == 0) || (BF_GLOBALS._nico910State != 0)) { CursorType cursorId = BF_GLOBALS._events.getCursor(); BF_GLOBALS._events.setCursor(cursorId); } else if (!_item16._bounds.contains(event.mousePos)) { @@ -2755,7 +2756,7 @@ void Scene910::process(Event &event) { _sceneMode = 9123; setAction(&_sequenceManager1, this, 9123, &BF_GLOBALS._player, NULL); event.handled = true; - } else if (BF_GLOBALS._v4CEE2 <= 1) { + } else if (BF_GLOBALS._nico910State <= 1) { if (BF_GLOBALS.getFlag(fCanDrawGun)) { BF_GLOBALS._player.addMover(NULL); BF_GLOBALS._player.disableControl(); @@ -2776,7 +2777,7 @@ void Scene910::process(Event &event) { event.handled = true; break; case CURSOR_WALK: - if (BF_GLOBALS._v4CEE2 == 1) { + if (BF_GLOBALS._nico910State == 1) { BF_GLOBALS._player.disableControl(); if (BF_GLOBALS._player._visage == 1911) { BF_GLOBALS._player.disableControl(); @@ -2826,7 +2827,7 @@ void Scene910::dispatch() { _sceneSubMode = 3; _sceneMode = 9123; setAction(&_sequenceManager1, this, 9123, &BF_GLOBALS._player, NULL); - } else if (BF_GLOBALS._v4CEE2 == 0) { + } else if (BF_GLOBALS._nico910State == 0) { _sceneMode = 9143; setAction(&_sequenceManager1, this, 9143, &BF_GLOBALS._player, NULL); } else { @@ -2840,7 +2841,7 @@ void Scene910::dispatch() { } } - if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._player._position.x > 250) && (_sceneMode != 9135) && (_sceneMode != 11) && (BF_GLOBALS._hiddenDoorStatus != 0) && (BF_GLOBALS._v4CEE2 == 0)) { + if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._player._position.x > 250) && (_sceneMode != 9135) && (_sceneMode != 11) && (BF_GLOBALS._hiddenDoorStatus != 0) && (BF_GLOBALS._nico910State == 0)) { BF_GLOBALS._player.disableControl(); _shadow.remove(); _nico.remove(); @@ -2853,7 +2854,7 @@ void Scene910::dispatch() { } void Scene910::checkGun() { - if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0) && (BF_GLOBALS._hiddenDoorStatus != 0)) + if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0) && (BF_GLOBALS._hiddenDoorStatus != 0)) SceneItem::display(910, 70, SET_WIDTH, 312, SET_X, GLOBALS._sceneManager._scene->_sceneBounds.left + 4, SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2, @@ -2900,7 +2901,7 @@ void Scene910::closeHiddenDoor() { setAction(&_sequenceManager1, this, 9115, &_fakeWall, &_object5, NULL); } - if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._v4CEE2 == 0)) { + if ((BF_GLOBALS._dayNumber == 5) && (BF_GLOBALS._nico910State == 0)) { // _objectList.draw(); if (BF_GLOBALS._sceneObjects->contains(&_breakerBoxInset)) _breakerBoxInset.remove(); diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index 06fbffb751..ba27db9104 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -505,7 +505,7 @@ void ConversationChoiceDialog::draw() { // Make a backup copy of the area the dialog will occupy Rect tempRect = _bounds; tempRect.collapse(-10, -10); - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), tempRect); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), tempRect); // Fill in the contents of the entire dialog _gfxManager._bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index 0c458f5c35..bcadfdc201 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -164,8 +164,6 @@ public: // Create the return descriptor SaveStateDescriptor desc(slot, header.saveName); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); desc.setThumbnail(header.thumbnail); desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay); desc.setSaveTime(header.saveHour, header.saveMinutes); diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h index d538cbacbf..a84ee5662f 100644 --- a/engines/tsage/detection_tables.h +++ b/engines/tsage/detection_tables.h @@ -105,7 +105,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "17c3993415e8a2cf93040eef7e88ec93", 1156508), Common::EN_ANY, Common::kPlatformPC, - ADGF_TESTING, + ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOSFX) }, GType_BlueForce, @@ -120,7 +120,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "17eabb456cb1546c66baf1aff387ba6a", 10032614), Common::EN_ANY, Common::kPlatformPC, - ADGF_TESTING, + ADGF_NO_FLAGS, GUIO2(GUIO_NOSPEECH, GUIO_NOSFX) }, GType_BlueForce, @@ -134,7 +134,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "99983f48cb218f1f3760cf2f9a7ef11d", 63863322), Common::EN_ANY, Common::kPlatformPC, - ADGF_CD | ADGF_TESTING, + ADGF_CD, GUIO2(GUIO_NOSPEECH, GUIO_NOSFX) }, GType_BlueForce, @@ -150,7 +150,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "5b2b35c51b62e82d82b0791540bfae2d", 10082565), Common::ES_ESP, Common::kPlatformPC, - ADGF_CD | ADGF_TESTING, + ADGF_CD | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOSFX) }, GType_BlueForce, diff --git a/engines/tsage/dialogs.cpp b/engines/tsage/dialogs.cpp index 972d591c34..77ac0a25d7 100644 --- a/engines/tsage/dialogs.cpp +++ b/engines/tsage/dialogs.cpp @@ -116,7 +116,7 @@ void ModalDialog::draw() { // Make a backup copy of the area the dialog will occupy Rect tempRect = _bounds; tempRect.collapse(-10, -10); - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), tempRect); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), tempRect); _gfxManager.activate(); diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 59eb59b194..de9463268b 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -247,7 +247,7 @@ void BlueForceGlobals::synchronize(Serializer &s) { for (int i = 0; i < 18; i++) s.syncAsByte(_breakerBoxStatusArr[i]); s.syncAsSint16LE(_hiddenDoorStatus); - s.syncAsSint16LE(_v4CEE2); + s.syncAsSint16LE(_nico910State); s.syncAsSint16LE(_v4CEE4); s.syncAsSint16LE(_v4CEE6); s.syncAsSint16LE(_v4CEE8); @@ -320,7 +320,7 @@ void BlueForceGlobals::reset() { _breakerBoxStatusArr[16] = 3; _breakerBoxStatusArr[17] = 0; _hiddenDoorStatus = 0; - _v4CEE2 = 0; + _nico910State = 0; _v4CEE4 = 0; _v4CEE6 = 0; _v4CEE8 = 0; diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index 45226c921b..d190b6a2a4 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -200,7 +200,7 @@ public: int _v4CECC; int8 _breakerBoxStatusArr[18]; int _hiddenDoorStatus; - int _v4CEE2; + int _nico910State; int _v4CEE4; int _v4CEE6; int _v4CEE8; diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index 0781ae4544..fb0b0b0cbb 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -38,7 +38,7 @@ namespace TsAGE { * @src Source surface * @bounds Area to backup */ -GfxSurface *Surface_getArea(GfxSurface &src, const Rect &bounds) { +GfxSurface *surfaceGetArea(GfxSurface &src, const Rect &bounds) { assert(bounds.isValidRect()); GfxSurface *dest = new GfxSurface(); dest->create(bounds.width(), bounds.height()); @@ -437,7 +437,7 @@ bool GfxSurface::displayText(const Common::String &msg, const Common::Point &pt) // Make a backup copy of the area the text will occupy Rect saveRect = textRect; saveRect.collapse(-20, -8); - GfxSurface *savedArea = Surface_getArea(gfxManager.getSurface(), saveRect); + GfxSurface *savedArea = surfaceGetArea(gfxManager.getSurface(), saveRect); // Display the text gfxManager._font.writeLines(msg.c_str(), textRect, ALIGN_LEFT); @@ -1073,7 +1073,7 @@ void GfxDialog::draw() { Rect tempRect(_bounds); // Make a backup copy of the area the dialog will occupy - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); // Set the palette for use in the dialog setPalette(); diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h index 9c6f13e407..9175b1050a 100644 --- a/engines/tsage/graphics.h +++ b/engines/tsage/graphics.h @@ -339,7 +339,7 @@ public: static void setPalette(); }; -GfxSurface *Surface_getArea(GfxSurface &src, const Rect &bounds); +GfxSurface *surfaceGetArea(GfxSurface &src, const Rect &bounds); GfxSurface surfaceFromRes(const byte *imgData); GfxSurface surfaceFromRes(int resNum, int rlbNum, int subNum); diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp index 0e451b8429..4728e66cd9 100644 --- a/engines/tsage/ringworld/ringworld_dialogs.cpp +++ b/engines/tsage/ringworld/ringworld_dialogs.cpp @@ -59,7 +59,7 @@ void RightClickButton::highlight() { _savedButton = NULL; } else { // Highlight button by getting the needed highlighted image resource - _savedButton = Surface_getArea(g_globals->gfxManager().getSurface(), _bounds); + _savedButton = surfaceGetArea(g_globals->gfxManager().getSurface(), _bounds); uint size; byte *imgData = g_resourceManager->getSubResource(7, 2, _buttonIndex, &size); @@ -122,7 +122,7 @@ RightClickButton *RightClickDialog::findButton(const Common::Point &pt) { void RightClickDialog::draw() { // Save the covered background area - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); // Draw the dialog image g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top); diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp index 00c219f2ee..7d571b40d7 100644 --- a/engines/tsage/ringworld/ringworld_logic.cpp +++ b/engines/tsage/ringworld/ringworld_logic.cpp @@ -295,7 +295,7 @@ void SceneArea::display() { _bounds.setWidth(_surface.getBounds().width()); _bounds.setHeight(_surface.getBounds().height()); - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); draw2(); } diff --git a/engines/tsage/ringworld/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp index 3b415bdb6a..004ccbbb6d 100644 --- a/engines/tsage/ringworld/ringworld_scenes5.cpp +++ b/engines/tsage/ringworld/ringworld_scenes5.cpp @@ -1893,7 +1893,7 @@ void Scene4045::postInit(SceneObjectList *OwnerList) { _olloFace.setStrip(4); _olloFace.fixPriority(152); - if(g_globals->_sceneManager._previousScene == 4050) { + if (g_globals->_sceneManager._previousScene == 4050) { g_globals->_soundHandler.play(155); g_globals->_player.setPosition(Common::Point(72, 128)); g_globals->_player.enableControl(); diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index 30ae6be7b1..478fdcf5a5 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -85,7 +85,7 @@ RightClickDialog::~RightClickDialog() { void RightClickDialog::draw() { // Save the covered background area - _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); + _savedArea = surfaceGetArea(g_globals->_gfxManagerInstance.getSurface(), _bounds); // Draw the dialog image g_globals->gfxManager().copyFrom(_surface, _bounds.left, _bounds.top); diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 304d3a4298..216444e722 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -5571,7 +5571,7 @@ void Scene1337::subCF979() { tmpVal = subC26CB(0, i); if (tmpVal != -1) { - bool flag = false;; + bool flag = false; for (int j = 0; j <= 7; j++) { if (_arrunkObj1337[0]._arr2[j]._field34 == _arrunkObj1337[0]._arr1[tmpVal]._field34) { flag = true; @@ -11068,7 +11068,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { case R2_REBREATHER_TANK: if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { if (R2_GLOBALS.getFlag(30)) - return SceneActor::startAction(action, event);; + return SceneActor::startAction(action, event); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1878; diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 3dd566c900..61711d0a4f 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -3294,7 +3294,7 @@ void Scene3500::Action1::signal() { NpcMover *mover = new NpcMover(); scene->_actor8.addMover(mover, &pt, this); - scene->_actor9.setPosition(Common::Point(160 + ((_field1E * 2) * 160), 73));; + scene->_actor9.setPosition(Common::Point(160 + ((_field1E * 2) * 160), 73)); scene->_actor9._moveDiff.x = 160 - scene->_field126E; scene->_fieldB9E = 160; Common::Point pt2(scene->_fieldB9E, 73); diff --git a/engines/tsage/ringworld2/ringworld2_speakers.h b/engines/tsage/ringworld2/ringworld2_speakers.h index e336564c5f..fa2946d56c 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.h +++ b/engines/tsage/ringworld2/ringworld2_speakers.h @@ -504,14 +504,14 @@ public: class SpeakerSoldier300 : public SpeakerSoldier { public: - SpeakerSoldier300() : SpeakerSoldier(60) {}; + SpeakerSoldier300() : SpeakerSoldier(60) {} virtual Common::String getClassName() { return "SpeakerSoldier300"; } virtual void proc15(); }; class SpeakerSoldier1625 : public SpeakerSoldier { public: - SpeakerSoldier1625() : SpeakerSoldier(5) {}; + SpeakerSoldier1625() : SpeakerSoldier(5) {} virtual Common::String getClassName() { return "SpeakerSoldier1625"; } }; @@ -585,7 +585,7 @@ public: class SpeakerWebbster3240 : public SpeakerWebbster { public: - SpeakerWebbster3240() : SpeakerWebbster(10) {}; + SpeakerWebbster3240() : SpeakerWebbster(10) {} virtual Common::String getClassName() { return "SpeakerWebbster3240"; } virtual void proc15(); @@ -593,7 +593,7 @@ public: class SpeakerWebbster3375 : public SpeakerWebbster { public: - SpeakerWebbster3375() : SpeakerWebbster(60) {}; + SpeakerWebbster3375() : SpeakerWebbster(60) {} virtual Common::String getClassName() { return "SpeakerWebbster3375"; } virtual void proc15(); @@ -601,7 +601,7 @@ public: class SpeakerWebbster3385 : public SpeakerWebbster { public: - SpeakerWebbster3385() : SpeakerWebbster(60) {}; + SpeakerWebbster3385() : SpeakerWebbster(60) {} virtual Common::String getClassName() { return "SpeakerWebbster3385"; } virtual void proc15(); @@ -609,7 +609,7 @@ public: class SpeakerWebbster3395 : public SpeakerWebbster { public: - SpeakerWebbster3395() : SpeakerWebbster(60) {}; + SpeakerWebbster3395() : SpeakerWebbster(60) {} virtual Common::String getClassName() { return "SpeakerWebbster3395"; } virtual void proc15(); @@ -617,7 +617,7 @@ public: class SpeakerWebbster3400 : public SpeakerWebbster { public: - SpeakerWebbster3400() : SpeakerWebbster(27) {}; + SpeakerWebbster3400() : SpeakerWebbster(27) {} virtual Common::String getClassName() { return "SpeakerWebbster3400"; } virtual void proc15(); diff --git a/engines/tsage/scenes.cpp b/engines/tsage/scenes.cpp index 0756d71d4c..774a5277dc 100644 --- a/engines/tsage/scenes.cpp +++ b/engines/tsage/scenes.cpp @@ -569,17 +569,13 @@ void Game::quitGame() { } void Game::handleSaveLoad(bool saveFlag, int &saveSlot, Common::String &saveName) { - const EnginePlugin *plugin = 0; - EngineMan.findGame(g_vm->getGameId(), &plugin); GUI::SaveLoadChooser *dialog; if (saveFlag) - dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); + dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), saveFlag); else - dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); + dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), saveFlag); - dialog->setSaveMode(saveFlag); - - saveSlot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + saveSlot = dialog->runModalWithCurrentTarget(); saveName = dialog->getResultString(); delete dialog; diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp index 10cb6961dc..4bd9e49875 100644 --- a/engines/tsage/user_interface.cpp +++ b/engines/tsage/user_interface.cpp @@ -112,7 +112,7 @@ void UIQuestion::showItem(int resNum, int rlbNum, int frameNum) { imgRect.center(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2); // Save the area behind where the image will be displayed - GfxSurface *savedArea = Surface_getArea(GLOBALS.gfxManager().getSurface(), imgRect); + GfxSurface *savedArea = surfaceGetArea(GLOBALS.gfxManager().getSurface(), imgRect); // Draw the image GLOBALS.gfxManager().copyFrom(objImage, imgRect); diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 775fd6f1a0..16c4f4f6f0 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -28,6 +28,7 @@ #include "audio/decoders/wave.h" #include "graphics/palette.h" +#include "graphics/surface.h" #include "tucker/tucker.h" #include "tucker/graphics.h" @@ -749,6 +750,7 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) { _seqNum = 1; return; } + _flicPlayer[index].start(); _flicPlayer[index].decodeNextFrame(); if (index == 0) { getRGBPalette(index); @@ -801,7 +803,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { if (_flicPlayer[0].getCurFrame() >= 115) { surface = _flicPlayer[1].decodeNextFrame(); if (_flicPlayer[1].endOfVideo()) - _flicPlayer[1].reset(); + _flicPlayer[1].rewind(); } bool framesLeft = decodeNextAnimationFrame(0, false); |