diff options
author | Norbert Lange | 2009-08-08 19:09:30 +0000 |
---|---|---|
committer | Norbert Lange | 2009-08-08 19:09:30 +0000 |
commit | 0350a1598deea8d1af252ddd96a490699d10e2e2 (patch) | |
tree | 11557d7a87ee5da2ee20e6c13e8be7d2607f393c /engines | |
parent | df06592be1b4c9904acde5a843d3ab3d076c65ac (diff) | |
parent | 65a39cc2b0ebb989444330c561743ba0466c1a9c (diff) | |
download | scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.tar.gz scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.tar.bz2 scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.zip |
merge with trunk
svn-id: r43134
Diffstat (limited to 'engines')
204 files changed, 3864 insertions, 2014 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index e373dd3e6d..69b27e10f9 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -25,6 +25,7 @@ #include "common/md5.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -271,19 +272,6 @@ void AgiEngine::processEvents() { } } -void AgiEngine::checkQuickLoad() { - if (ConfMan.hasKey("save_slot")) { - char saveNameBuffer[256]; - - snprintf (saveNameBuffer, 256, "%s.%03d", _targetName.c_str(), ConfMan.getInt("save_slot")); - - if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id - _game.exitAllLogics = 1; - _menu->enableAll(); - } - } -} - void AgiEngine::pollTimer(void) { static uint32 m = 0; uint32 dm; @@ -301,40 +289,10 @@ void AgiEngine::pollTimer(void) { m = g_tickTimer; } -bool AgiEngine::isKeypress(void) { - processEvents(); - return _keyQueueStart != _keyQueueEnd; -} - -int AgiEngine::getKeypress(void) { - int k; - - while (_keyQueueStart == _keyQueueEnd) // block - pollTimer(); - - keyDequeue(k); - - return k; -} - -void AgiEngine::clearKeyQueue(void) { - while (isKeypress()) { - getKeypress(); - } -} - void AgiEngine::agiTimerFunctionLow(void *refCon) { g_tickTimer++; } -void AgiEngine::clearImageStack(void) { - _imageStack.clear(); -} - -void AgiEngine::releaseImageStack(void) { - _imageStack.clear(); -} - void AgiEngine::pause(uint32 msec) { uint32 endTime = _system->getMillis() + msec; @@ -348,38 +306,6 @@ void AgiEngine::pause(uint32 msec) { _gfx->setCursor(_renderMode == Common::kRenderAmiga); } -void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, - int16 p4, int16 p5, int16 p6, int16 p7) { - ImageStackElement pnew; - - pnew.type = type; - pnew.pad = 0; - pnew.parm1 = p1; - pnew.parm2 = p2; - pnew.parm3 = p3; - pnew.parm4 = p4; - pnew.parm5 = p5; - pnew.parm6 = p6; - pnew.parm7 = p7; - - _imageStack.push(pnew); -} - -void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, - int16 p4, int16 p5, int16 p6, int16 p7) { - switch (type) { - case ADD_PIC: - debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1); - agiLoadResource(rPICTURE, p1); - _picture->decodePicture(p1, p2, p3 != 0); - break; - case ADD_VIEW: - agiLoadResource(rVIEW, p1); - _sprites->addToPic(p1, p2, p3, p4, p5, p6, p7); - break; - } -} - void AgiEngine::initPriTable() { int i, p, y = 0; @@ -489,11 +415,6 @@ int AgiEngine::agiInit() { _game.mouseFence.setWidth(0); // Reset - _game.lastController = 0; - for (i = 0; i < MAX_DIRS; i++) - _game.controllerOccured[i] = false; - - return ec; } @@ -530,21 +451,6 @@ int AgiEngine::agiDeinit() { return ec; } -int AgiEngine::agiDetectGame() { - int ec = errOK; - - assert(_gameDescription != NULL); - - if (getVersion() <= 0x2999) { - _loader = new AgiLoader_v2(this); - } else { - _loader = new AgiLoader_v3(this); - } - ec = _loader->detectGame(); - - return ec; -} - int AgiEngine::agiLoadResource(int r, int n) { int i; @@ -587,67 +493,6 @@ static const GameSettings agiSettings[] = { {NULL, NULL, 0, 0, NULL} }; -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const { - if (_amigaStyle) { - if (positive) { - if (pressed) { // Positive pressed Amiga-style button - if (_olderAgi) { - return AgiTextColor(amigaBlack, amigaOrange); - } else { - return AgiTextColor(amigaBlack, amigaPurple); - } - } else { // Positive unpressed Amiga-style button - return AgiTextColor(amigaWhite, amigaGreen); - } - } else { // _amigaStyle && !positive - if (pressed) { // Negative pressed Amiga-style button - return AgiTextColor(amigaBlack, amigaCyan); - } else { // Negative unpressed Amiga-style button - return AgiTextColor(amigaWhite, amigaRed); - } - } - } else { // PC-style button - if (hasFocus || pressed) { // A pressed or in focus PC-style button - return AgiTextColor(pcWhite, pcBlack); - } else { // An unpressed PC-style button without focus - return AgiTextColor(pcBlack, pcWhite); - } - } -} - -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const { - return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor)); -} - -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const { - if (hasFocus || pressed) - return baseColor.swap(); - else - return baseColor; -} - -int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const { - return (pressed && !_amigaStyle) ? 1 : 0; -} - -bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const { - return _amigaStyle && !_authenticAmiga && (hasFocus || pressed); -} - -void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) { - _amigaStyle = amigaStyle; - _olderAgi = olderAgi; - _authenticAmiga = authenticAmiga; -} - -void AgiButtonStyle::setPcStyle(bool pcStyle) { - setAmigaStyle(!pcStyle); -} - -AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) { - setAmigaStyle(renderMode == Common::kRenderAmiga); -} - AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { _noSaveLoadAllowed = false; @@ -671,7 +516,7 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas parseFeatures(); _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "agi"); + g_eventRec.registerRandomSource(*_rnd, "agi"); Common::addDebugChannel(kDebugLevelMain, "Main", "Generic debug level"); Common::addDebugChannel(kDebugLevelResources, "Resources", "Resources debugging"); @@ -718,6 +563,12 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas _predictiveDictLine = NULL; _predictiveDictLineCount = 0; _firstSlot = 0; + + // NOTE: On game reload the keys do not get set again, + // thus it is incorrect to reset it in agiInit(). Fixes bug #2823762 + _game.lastController = 0; + for (int i = 0; i < MAX_DIRS; i++) + _game.controllerOccured[i] = false; } void AgiEngine::initialize() { diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 14e1fd448b..ab572b0dd0 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -760,8 +760,6 @@ public: void initVersion(void); void setVersion(uint16 version); - Common::Error loadGameState(int slot); - Common::Error saveGameState(int slot, const char *desc); bool canLoadGameStateCurrently(); bool canSaveGameStateCurrently(); }; @@ -785,6 +783,8 @@ public: return _gameId; } + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const char *desc); private: diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index bf4622bc08..d212f8c2e0 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -328,7 +328,7 @@ int AgiEngine::playGame() { _game.vars[vKey] = 0; debugC(2, kDebugLevelMain, "Entering main loop"); - bool firstLoop = true; + bool firstLoop = !getflag(fRestartGame); // Do not restore on game restart do { diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 910f6e0e55..553e42f88e 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -1290,20 +1290,6 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSList &fsl namespace Agi { -Common::Error AgiBase::loadGameState(int slot) { - static char saveLoadSlot[12]; - sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); - loadGame(saveLoadSlot); - return Common::kNoError; // TODO: return success/failure -} - -Common::Error AgiBase::saveGameState(int slot, const char *desc) { - static char saveLoadSlot[12]; - sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); - saveGame(saveLoadSlot, desc); - return Common::kNoError; // TODO: return success/failure -} - bool AgiBase::canLoadGameStateCurrently() { return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed); } @@ -1312,4 +1298,19 @@ bool AgiBase::canSaveGameStateCurrently() { return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed && _game.inputEnabled); } +int AgiEngine::agiDetectGame() { + int ec = errOK; + + assert(_gameDescription != NULL); + + if (getVersion() <= 0x2999) { + _loader = new AgiLoader_v2(this); + } else { + _loader = new AgiLoader_v3(this); + } + ec = _loader->detectGame(); + + return ec; +} + } // End of namespace Agi diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 6604587051..b47a39e592 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -393,6 +393,11 @@ int AgiEngine::waitKey() { _gfx->doUpdate(); } + + // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() + // Fixes bug #2823759 + _game.keypress = 0; + return key; } @@ -409,7 +414,33 @@ int AgiEngine::waitAnyKey() { break; _gfx->doUpdate(); } + + // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() + _game.keypress = 0; + return key; } +bool AgiEngine::isKeypress(void) { + processEvents(); + return _keyQueueStart != _keyQueueEnd; +} + +int AgiEngine::getKeypress(void) { + int k; + + while (_keyQueueStart == _keyQueueEnd) // block + pollTimer(); + + keyDequeue(k); + + return k; +} + +void AgiEngine::clearKeyQueue(void) { + while (isKeypress()) { + getKeypress(); + } +} + } // End of namespace Agi diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp index 27e234ebc9..5d30eda81d 100644 --- a/engines/agi/menu.cpp +++ b/engines/agi/menu.cpp @@ -493,4 +493,66 @@ void Menu::enableAll() { } } + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const { + if (_amigaStyle) { + if (positive) { + if (pressed) { // Positive pressed Amiga-style button + if (_olderAgi) { + return AgiTextColor(amigaBlack, amigaOrange); + } else { + return AgiTextColor(amigaBlack, amigaPurple); + } + } else { // Positive unpressed Amiga-style button + return AgiTextColor(amigaWhite, amigaGreen); + } + } else { // _amigaStyle && !positive + if (pressed) { // Negative pressed Amiga-style button + return AgiTextColor(amigaBlack, amigaCyan); + } else { // Negative unpressed Amiga-style button + return AgiTextColor(amigaWhite, amigaRed); + } + } + } else { // PC-style button + if (hasFocus || pressed) { // A pressed or in focus PC-style button + return AgiTextColor(pcWhite, pcBlack); + } else { // An unpressed PC-style button without focus + return AgiTextColor(pcBlack, pcWhite); + } + } +} + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const { + return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor)); +} + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const { + if (hasFocus || pressed) + return baseColor.swap(); + else + return baseColor; +} + +int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const { + return (pressed && !_amigaStyle) ? 1 : 0; +} + +bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const { + return _amigaStyle && !_authenticAmiga && (hasFocus || pressed); +} + +void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) { + _amigaStyle = amigaStyle; + _olderAgi = olderAgi; + _authenticAmiga = authenticAmiga; +} + +void AgiButtonStyle::setPcStyle(bool pcStyle) { + setAmigaStyle(!pcStyle); +} + +AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) { + setAmigaStyle(renderMode == Common::kRenderAmiga); +} + } // End of namespace Agi diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index e728f2f695..7a6608d0d0 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -1267,7 +1267,7 @@ void Mickey::pressOB(int iButton) { } // print pressed buttons - printLine("MICKEY HAS PRESSED: "); + printLine("MICKEY HAS PRESSED: "); _vm->drawStr(20, 22, IDA_DEFAULT, szButtons); waitAnyKey(); } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 7c84f1dd72..50b329c0b6 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -32,6 +32,7 @@ #include "common/file.h" #include "graphics/thumbnail.h" +#include "common/config-manager.h" #include "agi/agi.h" #include "agi/graphics.h" @@ -925,4 +926,85 @@ int AgiEngine::loadGameSimple() { return rc; } +void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) { + ImageStackElement pnew; + + pnew.type = type; + pnew.pad = 0; + pnew.parm1 = p1; + pnew.parm2 = p2; + pnew.parm3 = p3; + pnew.parm4 = p4; + pnew.parm5 = p5; + pnew.parm6 = p6; + pnew.parm7 = p7; + + _imageStack.push(pnew); +} + +void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) { + switch (type) { + case ADD_PIC: + debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1); + agiLoadResource(rPICTURE, p1); + _picture->decodePicture(p1, p2, p3 != 0); + break; + case ADD_VIEW: + agiLoadResource(rVIEW, p1); + _sprites->addToPic(p1, p2, p3, p4, p5, p6, p7); + break; + } +} + +void AgiEngine::clearImageStack(void) { + _imageStack.clear(); +} + +void AgiEngine::releaseImageStack(void) { + _imageStack.clear(); +} + +void AgiEngine::checkQuickLoad() { + if (ConfMan.hasKey("save_slot")) { + char saveNameBuffer[256]; + + snprintf (saveNameBuffer, 256, "%s.%03d", _targetName.c_str(), ConfMan.getInt("save_slot")); + + _sprites->eraseBoth(); + _sound->stopSound(); + + if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id + _game.exitAllLogics = 1; + _menu->enableAll(); + } + } +} + +Common::Error AgiEngine::loadGameState(int slot) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + + _sprites->eraseBoth(); + _sound->stopSound(); + + if (loadGame(saveLoadSlot) == errOK) { + _game.exitAllLogics = 1; + _menu->enableAll(); + return Common::kNoError; + } else { + return Common::kUnknownError; + } +} + +Common::Error AgiEngine::saveGameState(int slot, const char *desc) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + if (saveGame(saveLoadSlot, desc) == errOK) + return Common::kNoError; + else + return Common::kUnknownError; +} + } // End of namespace Agi diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp index f3c0b7365c..63ac880267 100644 --- a/engines/agi/sprite.cpp +++ b/engines/agi/sprite.cpp @@ -56,9 +56,10 @@ struct Sprite { void *SpritesMgr::poolAlloc(int size) { uint8 *x; - // Adjust size to 32-bit boundary to prevent data misalignment + // Adjust size to sizeof(void *) boundary to prevent data misalignment // errors. - size = (size + 3) & ~3; + const int alignPadding = sizeof(void*) - 1; + size = (size + alignPadding) & ~alignPadding; x = _poolTop; _poolTop += size; diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 9903952577..0e53698b59 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -27,6 +27,7 @@ #include "common/file.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "agos/debugger.h" #include "agos/intern.h" @@ -528,7 +529,7 @@ AGOSEngine::AGOSEngine(OSystem *syst) File::addDefaultDirectory(_gameDataDir.getChild("speech")); File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); - syst->getEventManager()->registerRandomSource(_rnd, "agos"); + g_eventRec.registerRandomSource(_rnd, "agos"); } Common::Error AGOSEngine::init() { diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 263811b78a..ac1f33428b 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1248,6 +1248,7 @@ protected: void hitarea_stuff_helper_2(); void fastFadeIn(); void slowFadeIn(); + void fullFade(); virtual void vcStopAnimation(uint16 zone, uint16 sprite); @@ -1265,20 +1266,6 @@ protected: #ifdef ENABLE_PN class AGOSEngine_PN : public AGOSEngine { - struct StackFrame { - StackFrame *nextframe; - int16 flag[6]; - int16 param[8]; - int16 classnum; - uint8 *linpos; - uint8 *lbase; - int16 ll; - int16 linenum; - int16 process; - jmp_buf *savearea; - StackFrame() { memset(this, 0, sizeof(*this)); } - }; - virtual Common::Error go(); void demoSeq(); @@ -1358,8 +1345,30 @@ public: void opn_opcode62(); void opn_opcode63(); +protected: + struct StackFrame { + StackFrame *nextframe; + int16 flag[6]; + int16 param[8]; + int16 classnum; + uint8 *linpos; + uint8 *lbase; + int16 ll; + int16 linenum; + int16 process; + int tagOfParentDoline; ///< tag of the doline "instance" to which this StackFrame belongs + StackFrame() { memset(this, 0, sizeof(*this)); } + }; + + StackFrame *_stackbase; + int _tagOfActiveDoline; ///< tag of the active doline "instance" + int _dolineReturnVal; + + jmp_buf _loadfail; + + byte *_dataBase, *_textBase; uint32 _dataBaseSize, _textBaseSize; @@ -1404,8 +1413,6 @@ public: int _linembr; uint8 *_linebase; uint8 *_workptr; - jmp_buf *_cjmpbuff; - jmp_buf _loadfail; uint16 getptr(uint32 pos); uint32 getlong(uint32 pos); @@ -1429,7 +1436,6 @@ public: void addstack(int type); void dumpstack(); - void junkstack(); void popstack(int type); void funccpy(int *store); void funcentry(int *storestore, int procn); @@ -1465,8 +1471,8 @@ public: virtual void windowPutChar(WindowBlock *window, byte c, byte b = 0); bool badload(int8 errorNum); - int loadfl(char *name); - int savfl(char *name); + int loadFile(char *name); + int saveFile(char *name); void getFilename(); void sysftodb(); void dbtosysf(); diff --git a/engines/agos/debug.h b/engines/agos/debug.h index 375878a4bc..38674de765 100644 --- a/engines/agos/debug.h +++ b/engines/agos/debug.h @@ -2549,7 +2549,7 @@ const char *const ww_videoOpcodeNameTable[] = { "j|IF_EGA", /* 60 */ "d|STOP_ANIMATE", - "d|VC_61", + "d|INTRO", "|FASTFADEOUT", "|FASTFADEIN", }; diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h index ec21acc0a1..0c672aef52 100644 --- a/engines/agos/detection_tables.h +++ b/engines/agos/detection_tables.h @@ -26,6 +26,8 @@ namespace AGOS { using Common::GUIO_NONE; +using Common::GUIO_NOMIDI; +using Common::GUIO_NOMUSIC; using Common::GUIO_NOSPEECH; using Common::GUIO_NOSUBTITLES; @@ -45,7 +47,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -68,7 +70,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -91,7 +93,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -137,7 +139,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -158,7 +160,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -179,7 +181,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -200,7 +202,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -223,7 +225,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -246,7 +248,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -269,7 +271,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -410,7 +412,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -436,7 +438,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -462,7 +464,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -488,7 +490,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -514,7 +516,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -540,7 +542,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -566,7 +568,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -802,7 +804,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_WW, @@ -829,7 +831,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_WW, @@ -992,7 +994,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1017,7 +1019,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_DEMO, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1042,7 +1044,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1066,7 +1068,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1090,7 +1092,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1114,7 +1116,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1138,7 +1140,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1162,7 +1164,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1186,7 +1188,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1210,7 +1212,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMIDI }, GType_SIMON1, @@ -1234,7 +1236,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMIDI }, GType_SIMON1, @@ -1523,7 +1525,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1548,7 +1550,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1573,7 +1575,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1598,7 +1600,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1623,7 +1625,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1648,7 +1650,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1673,7 +1675,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::HB_ISR, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1698,7 +1700,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1724,7 +1726,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1749,7 +1751,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1774,7 +1776,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1799,7 +1801,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1824,7 +1826,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSPEECH }, GType_SIMON2, @@ -1949,7 +1951,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -1974,7 +1976,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -1999,7 +2001,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2024,7 +2026,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2049,7 +2051,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2074,7 +2076,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2099,7 +2101,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2124,7 +2126,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2175,7 +2177,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2200,7 +2202,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2225,7 +2227,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::CZ_CZE, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2250,7 +2252,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2275,7 +2277,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2300,7 +2302,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2325,7 +2327,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2346,7 +2348,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2367,7 +2369,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2391,7 +2393,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2415,7 +2417,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2439,7 +2441,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2463,7 +2465,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2487,7 +2489,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2511,7 +2513,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2534,7 +2536,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2557,7 +2559,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2580,7 +2582,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2603,7 +2605,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2626,7 +2628,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2649,7 +2651,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2672,7 +2674,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2693,7 +2695,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_PP, @@ -2714,7 +2716,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2735,7 +2737,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2756,7 +2758,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2777,7 +2779,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2798,7 +2800,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index 45443aa335..368da5db83 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -871,13 +871,11 @@ void AGOSEngine::slowFadeIn() { _fastFadeInFlag &= ~0x8000; _paletteFlag = false; - memset(_videoBuf1, 0, 1024); - memcpy(_currentPalette, _displayPalette, 1024); - memcpy(_videoBuf1 + 1024, _displayPalette, 1024); + memset(_currentPalette, 0, sizeof(_currentPalette)); for (c = 255; c >= 0; c -= 4) { - src = _videoBuf1 + 1024; - dst = _videoBuf1; + src = _displayPalette; + dst = _currentPalette; for (p = _fastFadeInFlag; p !=0 ; p -= 3) { if (src[0] >= c) @@ -889,7 +887,7 @@ void AGOSEngine::slowFadeIn() { src += 4; dst += 4; } - _system->setPalette(_videoBuf1, 0, _fastFadeCount); + _system->setPalette(_currentPalette, 0, _fastFadeCount); delay(5); } _fastFadeInFlag = 0; diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index cf6e808384..5c37fe620a 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -664,10 +664,11 @@ void AGOSEngine_PN::handleKeyboard() { } } if (chr == -1) { - chr = _keyPressed.ascii; - if (chr == 8 || chr == 13) { + if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE || _keyPressed.keycode == Common::KEYCODE_RETURN) { + chr = _keyPressed.keycode; addChar(chr); } else if (!(_videoLockOut & 0x10)) { + chr = _keyPressed.ascii; if (chr >= 32) addChar(chr); } diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp index d77621cc7b..568135ef8c 100644 --- a/engines/agos/midiparser_s1d.cpp +++ b/engines/agos/midiparser_s1d.cpp @@ -126,6 +126,10 @@ void MidiParser_S1D::parseNextEvent(EventInfo &info) { switch (info.event & 0x0F) { case 0x0: // Trigged by MOD2/MOD6/MOD15 in Waxworks + // Pure guesswork + info.ext.type = *(_position._play_pos++); + info.length = readVLQ(_position._play_pos); + info.ext.data = _position._play_pos; break; case 0x3: // Not sure, Song Select? diff --git a/engines/agos/pn.cpp b/engines/agos/pn.cpp index d92efa9077..e8135f56cd 100644 --- a/engines/agos/pn.cpp +++ b/engines/agos/pn.cpp @@ -35,6 +35,10 @@ namespace AGOS { AGOSEngine_PN::AGOSEngine_PN(OSystem *system) : AGOSEngine(system) { + _stackbase = 0; + _tagOfActiveDoline = 0; + _dolineReturnVal = 0; + _dataBase = 0; _dataBaseSize = 0; _textBase = 0; @@ -70,7 +74,7 @@ AGOSEngine_PN::AGOSEngine_PN(OSystem *system) _objects = 0; _objectCountS = 0; - _bp = 0; + _bp = 0; _xofs = 0; _havinit = 0; _seed = 0; @@ -84,16 +88,12 @@ AGOSEngine_PN::AGOSEngine_PN(OSystem *system) _linebase = 0; _workptr = 0; - - _cjmpbuff = NULL; } AGOSEngine_PN::~AGOSEngine_PN() { free(_dataBase); free(_textBase); - free(_cjmpbuff); - free(_stackbase); } const byte egaPalette[48] = { @@ -251,29 +251,33 @@ void AGOSEngine_PN::setupBoxes() { } void AGOSEngine_PN::processor() { - int q; - setqptrs(); - q = setjmp(_loadfail); - _variableArray[6] = 0; + _tagOfActiveDoline = 0; + int q = 0; + do { + assert(_tagOfActiveDoline == 0); + _dolineReturnVal = 0; - if (getPlatform() == Common::kPlatformAtariST) { - _variableArray[21] = 2; - } else if (getPlatform() == Common::kPlatformAmiga) { - _variableArray[21] = 0; - } else { - _variableArray[21] = 1; - } + _variableArray[6] = 0; + + if (getPlatform() == Common::kPlatformAtariST) { + _variableArray[21] = 2; + } else if (getPlatform() == Common::kPlatformAmiga) { + _variableArray[21] = 0; + } else { + _variableArray[21] = 1; + } - _variableArray[16] = _quickshort[6]; - _variableArray[17] = _quickshort[7]; - _variableArray[19] = getptr(55L); + _variableArray[16] = _quickshort[6]; + _variableArray[17] = _quickshort[7]; + _variableArray[19] = getptr(55L); - // q indicates the process to run and is 0 the first time, - // but 1 later on (i.e., when we are "called" from badload()). - setposition(q, 0); - doline(0); + // q indicates the process to run and is 0 the first time, + // but 1 later on (i.e., when we are "called" from badload()). + setposition(0, 0); + q = doline(0); + } while (q); } void AGOSEngine_PN::setqptrs() { diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp index e85440d8e1..4f3582b55d 100644 --- a/engines/agos/res_snd.cpp +++ b/engines/agos/res_snd.cpp @@ -285,10 +285,6 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) { void AGOSEngine::playMusic(uint16 music, uint16 track) { stopMusic(); - // FIXME: Music too unstable, when switching locations. - if (getPlatform() == Common::kPlatformPC && getGameType() == GType_WW) - return; - if (getPlatform() == Common::kPlatformAmiga) { playModule(music); } else if (getPlatform() == Common::kPlatformAtariST) { diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 16bde0097b..3787617be7 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -23,8 +23,6 @@ * */ - - #include "common/savefile.h" #include "common/system.h" @@ -231,7 +229,7 @@ bool AGOSEngine::confirmOverWrite(WindowBlock *window) { break; case Common::DE_DEU: message1 = "\rDatei existiert bereits.\r\r"; - message2 = " berschreiben ?\r\r"; + message2 = " Ueberschreiben ?\r\r"; message3 = " Ja Nein"; break; default: @@ -1555,13 +1553,16 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { bool AGOSEngine_PN::badload(int8 errorNum) { if (errorNum == -2) return 0; - /* Load error recovery routine */ + // Load error recovery routine + + // Clear any stack while (_stackbase != NULL) { - /* Clear any stack */ dumpstack(); } - /* Restart from process 1 */ - longjmp(_loadfail, 1); + + // Restart from process 1 + _tagOfActiveDoline = 1; + _dolineReturnVal = 3; return 1; } @@ -1572,7 +1573,7 @@ void AGOSEngine_PN::getFilename() { memset(_saveFile, 0, sizeof(_saveFile)); while (!shouldQuit() && !strlen(_saveFile)) { const char *msg = "File name : "; - pcf((unsigned char)'\n'); + pcf((unsigned char)'\n'); while (*msg) pcf((unsigned char)*msg++); @@ -1582,7 +1583,7 @@ void AGOSEngine_PN::getFilename() { } } -int AGOSEngine_PN::loadfl(char *name) { +int AGOSEngine_PN::loadFile(char *name) { Common::InSaveFile *f; haltAnimation(); @@ -1609,13 +1610,13 @@ int AGOSEngine_PN::loadfl(char *name) { delete f; return -1; } - delete f; + delete f; restartAnimation(); dbtosysf(); return 0; } -int AGOSEngine_PN::savfl(char *name) { +int AGOSEngine_PN::saveFile(char *name) { Common::OutSaveFile *f; sysftodb(); haltAnimation(); @@ -1625,7 +1626,7 @@ int AGOSEngine_PN::savfl(char *name) { restartAnimation(); const char *msg = "Couldn't save. "; - pcf((unsigned char)'\n'); + pcf((unsigned char)'\n'); while (*msg) pcf((unsigned char)*msg++); diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp index 4f9aab2965..2885781a9f 100644 --- a/engines/agos/script_pn.cpp +++ b/engines/agos/script_pn.cpp @@ -324,8 +324,8 @@ void AGOSEngine_PN::opn_opcode24() { // That value then is returned to actCallD, which once again // returns it. In the end, this amounts to a setScriptReturn(true) // (but possibly in a different level than the current one). - longjmp(*(_stackbase->savearea), 2); - setScriptReturn(false); + _dolineReturnVal = 2; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode25() { @@ -334,13 +334,13 @@ void AGOSEngine_PN::opn_opcode25() { // That value then is returned to actCallD, which once again // returns it. In the end, this amounts to a setScriptReturn(false) // (but possibly in a different level than the current one). - longjmp(*(_stackbase->savearea), 1); - setScriptReturn(false); + _dolineReturnVal = 1; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode26() { while ((_stackbase != NULL) && (_stackbase->classnum != kJmpClassNum)) - junkstack(); + dumpstack(); dumpstack(); setScriptReturn(true); } @@ -353,16 +353,16 @@ void AGOSEngine_PN::opn_opcode27() { void AGOSEngine_PN::opn_opcode28() { addstack(varval()); - _stackbase->savearea = _cjmpbuff; + _stackbase->tagOfParentDoline = _tagOfActiveDoline; setScriptReturn(false); } void AGOSEngine_PN::opn_opcode29() { popstack(varval()); - // Jump back to the last doline indicated by the top stackfram. + // Jump back to the last doline indicated by the top stackframe. // The -1 tells it to simply go on with its business. - longjmp(*(_stackbase->savearea), -1); - setScriptReturn(false); + _dolineReturnVal = -1; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode30() { @@ -386,7 +386,7 @@ void AGOSEngine_PN::opn_opcode31() { strcpy(bf, genSaveName(slot)); break; case 1: - strcpy(bf, "test.sav"); + strcpy(bf, "pn.sav"); break; case 2: // NOTE: Is this case ever used? @@ -397,7 +397,7 @@ void AGOSEngine_PN::opn_opcode31() { if (slot == -1) { setScriptReturn(false); } else { - a = loadfl(bf); + a = loadFile(bf); if (a) setScriptReturn(badload(a)); else @@ -426,7 +426,7 @@ void AGOSEngine_PN::opn_opcode32() { strcpy(bf, genSaveName(curSlot)); break; case 1: - strcpy(bf, "test.sav"); + strcpy(bf, "pn.sav"); break; case 2: // NOTE: Is this case ever used? @@ -434,7 +434,7 @@ void AGOSEngine_PN::opn_opcode32() { break; } - a = savfl(bf); + a = saveFile(bf); setScriptReturn(a); } @@ -520,19 +520,32 @@ void AGOSEngine_PN::opn_opcode39() { } void AGOSEngine_PN::opn_opcode40() { - setScriptReturn(doaction() | doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a | b); } void AGOSEngine_PN::opn_opcode41() { - setScriptReturn(doaction() & doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a & b); } void AGOSEngine_PN::opn_opcode42() { - setScriptReturn(doaction() ^ doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a ^ b); } void AGOSEngine_PN::opn_opcode43() { - setScriptReturn(!(doaction())); + int a = doaction(); + setScriptReturn(!a); } void AGOSEngine_PN::opn_opcode44() { @@ -874,41 +887,14 @@ int AGOSEngine_PN::doaction() { } int AGOSEngine_PN::doline(int needsave) { - int x; - jmp_buf *old_jmpbuf = NULL; - jmp_buf *mybuf; + assert(!_stackbase == !needsave); - mybuf = (jmp_buf *)malloc(sizeof(jmp_buf)); - if (mybuf == NULL) - error("doline: Out of memory - stack overflow"); - - x = setjmp(*mybuf); - // Looking at the longjmp calls below, x can be -1, 1 or 2 - // (and of course 0 when it returns directly, as always). - if (x > 0) { - dumpstack(); - // Restore the active jmpbuf to its previous value, - // then return the longjmp value (will be 2-1=1 or 1-1=0). - _cjmpbuff = old_jmpbuf; - free((char *)mybuf); - return (x - 1); - } + int x; + int myTag = ++_tagOfActiveDoline; // Obtain a unique tag for this doline invocation + _dolineReturnVal = 0; - if (x == -1) { - // Make this doline instance the active one (again). - // This is used to "return" over possibly multiple - // layers of nested script invocations. - // Kind of like throwing an exception. - _cjmpbuff = mybuf; - goto carryon; - } - - // Remember the previous active jmpbuf (gets restored - // above when a longjmp with a positive param occurs). - old_jmpbuf = _cjmpbuff; - _cjmpbuff = mybuf; if (needsave) - _stackbase->savearea = mybuf; + _stackbase->tagOfParentDoline = myTag; do { _linct = ((*_linebase) & 127) - 1; @@ -919,9 +905,26 @@ int AGOSEngine_PN::doline(int needsave) { goto skipln; } -carryon: do { x = doaction(); + + if (_dolineReturnVal != 0) { + if (_tagOfActiveDoline != myTag) + return 0; + + x = _dolineReturnVal; + _dolineReturnVal = 0; + + if (x > 0) { + if (x != 3) + dumpstack(); + // Restore the active jmpbuf to its previous value, + // then return _dolineReturnVal-1 (will be 2-1=1 or 1-1=0). + _tagOfActiveDoline = myTag - 1; + return (x - 1); + } + } + } while (x && !shouldQuit()); skipln: @@ -1063,7 +1066,7 @@ void AGOSEngine_PN::addstack(int type) { StackFrame *a; int i; - a = (StackFrame *)malloc(sizeof(StackFrame)); + a = (StackFrame *)calloc(1, sizeof(StackFrame)); if (a == NULL) error("addstack: Out of memory - stack overflow"); @@ -1093,24 +1096,13 @@ void AGOSEngine_PN::dumpstack() { _stackbase = a; } -void AGOSEngine_PN::junkstack() { - StackFrame *a; - - if (_stackbase == NULL) - error("junkstack: Stack underflow or unknown longjmp"); - - a = _stackbase->nextframe; - if (_stackbase->classnum == kJmpClassNum) - free((char *)_stackbase->savearea); - free((char *)_stackbase); - _stackbase = a; -} - void AGOSEngine_PN::popstack(int type) { - int i; + int i = 0; - while ((_stackbase != NULL) && (_stackbase->classnum != type)) - junkstack(); + while ((_stackbase != NULL) && (_stackbase->classnum != type)) { + dumpstack(); + ++i; + } if (_stackbase == NULL) error("popstack: Stack underflow or unknown longjmp"); diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index 2e3d936037..81efb5cd81 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -576,18 +576,15 @@ void AGOSEngine_Simon1::os1_specialFade() { // 187: fade to black uint i; - memcpy(_videoBuf1, _currentPalette, 4 * 256); - for (i = 32; i != 0; --i) { - paletteFadeOut(_videoBuf1, 32, 8); - paletteFadeOut(_videoBuf1 + 4 * 48, 144, 8); - paletteFadeOut(_videoBuf1 + 4 * 208, 48, 8); - _system->setPalette(_videoBuf1, 0, 256); + paletteFadeOut(_currentPalette, 32, 8); + paletteFadeOut(_currentPalette + 4 * 48, 144, 8); + paletteFadeOut(_currentPalette + 4 * 208, 48, 8); + _system->setPalette(_currentPalette, 0, 256); delay(5); } - memcpy(_currentPalette, _videoBuf1, 1024); - memcpy(_displayPalette, _videoBuf1, 1024); + memcpy(_displayPalette, _currentPalette, 1024); } void AGOSEngine::scriptMouseOff() { diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp index f6e6630d43..de3cb55963 100644 --- a/engines/agos/vga_e2.cpp +++ b/engines/agos/vga_e2.cpp @@ -353,9 +353,32 @@ void AGOSEngine::vc55_moveBox() { _needHitAreaRecalc++; } -void AGOSEngine::vc56_fullScreen() { - uint8 palette[1024]; +void AGOSEngine::fullFade() { + uint8 *srcPal, *dstPal; + int c, p; + + for (c = 64; c != 0; c --) { + srcPal = _curVgaFile2 + 32; + dstPal = _currentPalette; + for (p = 768; p !=0 ; p -= 3) { + uint8 r = srcPal[0] * 4; + if (dstPal[0] != r) + dstPal[0] += 4; + uint8 g = srcPal[1] * 4; + if (dstPal[1] != g) + dstPal[1] += 4; + uint8 b = srcPal[2] * 4; + if (dstPal[2] != b) + dstPal[2] += 4; + srcPal += 3; + dstPal += 4; + } + _system->setPalette(_currentPalette, 0, 256); + delay(5); + } +} +void AGOSEngine::vc56_fullScreen() { Graphics::Surface *screen = _system->lockScreen(); byte *dst = (byte *)screen->pixels; byte *src = _curVgaFile2 + 800; @@ -367,23 +390,12 @@ void AGOSEngine::vc56_fullScreen() { } _system->unlockScreen(); - //fullFade(); - - src = _curVgaFile2 + 32; - for (int i = 0; i < 256; i++) { - palette[i * 4 + 0] = *src++ * 4; - palette[i * 4 + 1] = *src++ * 4; - palette[i * 4 + 2] = *src++ * 4; - palette[i * 4 + 3] = 0; - } - - _system->setPalette(palette, 0, 256); + fullFade(); } void AGOSEngine::vc57_blackPalette() { - uint8 palette[1024]; - memset(palette, 0, sizeof(palette)); - _system->setPalette(palette, 0, 256); + memset(_currentPalette, 0, sizeof(_currentPalette)); + _system->setPalette(_currentPalette, 0, 256); } void AGOSEngine::vc58_checkCodeWheel() { diff --git a/engines/agos/vga_ww.cpp b/engines/agos/vga_ww.cpp index e7f2ad7807..afc05f7869 100644 --- a/engines/agos/vga_ww.cpp +++ b/engines/agos/vga_ww.cpp @@ -193,20 +193,8 @@ void AGOSEngine::vc61() { _system->unlockScreen(); - if (a == 6) { - //fullFade(); - src = _curVgaFile2 + 32; - - uint8 palette[1024]; - for (int i = 0; i < 256; i++) { - palette[i * 4 + 0] = *src++ * 4; - palette[i * 4 + 1] = *src++ * 4; - palette[i * 4 + 2] = *src++ * 4; - palette[i * 4 + 3] = 0; - } - - _system->setPalette(palette, 0, 256); - } + if (a == 6) + fullFade(); } void AGOSEngine::vc62_fastFadeOut() { @@ -221,8 +209,6 @@ void AGOSEngine::vc62_fastFadeOut() { _fastFadeCount = 208; } - memcpy(_videoBuf1, _currentPalette, _fastFadeCount * 4); - if (getGameType() == GType_FF || getGameType() == GType_PP) { if (getGameType() == GType_FF && getBitFlag(75)) { fadeCount = 4; @@ -237,8 +223,8 @@ void AGOSEngine::vc62_fastFadeOut() { } for (i = fadeCount; i != 0; --i) { - paletteFadeOut(_videoBuf1, _fastFadeCount, fadeSize); - _system->setPalette(_videoBuf1, 0, _fastFadeCount); + paletteFadeOut(_currentPalette, _fastFadeCount, fadeSize); + _system->setPalette(_currentPalette, 0, _fastFadeCount); delay(5); } diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 64a9a9dfb8..8756a2fc3c 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -64,7 +65,7 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng g_cine = this; - syst->getEventManager()->registerRandomSource(_rnd, "cine"); + g_eventRec.registerRandomSource(_rnd, "cine"); } CineEngine::~CineEngine() { @@ -113,6 +114,9 @@ int CineEngine::modifyGameSpeed(int speedChange) { } void CineEngine::initialize() { + // Initialize all savegames' descriptions to empty strings + memset(currentSaveName, 0, sizeof(currentSaveName)); + // Resize object table to its correct size and reset all its elements objectTable.resize(NUM_MAX_OBJECT); resetObjectTable(); diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index 4786005647..3bc26ab417 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -607,35 +607,37 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const { pattern += ".?"; Common::StringList filenames = saveFileMan->listSavefiles(pattern); sort(filenames.begin(), filenames.end()); - Common::StringList::const_iterator file = filenames.begin(); + Common::StringList::const_iterator file; Common::String filename = target; filename += ".dir"; Common::InSaveFile *in = saveFileMan->openForLoading(filename); if (in) { - int8 ch; - char saveDesc[20]; - do { + typedef char CommandeType[20]; + CommandeType saveNames[10]; + + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(saveNames, 0, sizeof(saveNames)); + + in->read(saveNames, 10 * 20); + CommandeType saveDesc; + + for (file = filenames.begin(); file != filenames.end(); ++file) { + // Jump over savegame files that don't end with a digit (e.g. "fw.3" is ok, "fw.a" is not). + if (!isdigit(file->lastChar())) + continue; + // Obtain the last digit of the filename, since they correspond to the save slot int slotNum = atoi(file->c_str() + file->size() - 1); - uint pos = 0; - do { - ch = in->readByte(); - if (pos < (sizeof(saveDesc) - 1)) { - if (ch < 32 || in->eos()) { - saveDesc[pos++] = '\0'; - } - else if (ch >= 32) { - saveDesc[pos++] = ch; - } - } - } while (ch >= 32 && !in->eos()); - if (saveDesc[0] != 0) { - saveList.push_back(SaveStateDescriptor(slotNum, saveDesc)); - file++; - } - } while (!in->eos()); + // Copy the savegame description making sure it ends with a trailing zero + strncpy(saveDesc, saveNames[slotNum], 20); + saveDesc[sizeof(CommandeType) - 1] = 0; + + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc)); + } } delete in; @@ -650,6 +652,11 @@ void CineMetaEngine::removeSaveState(const char *target, int slot) const { typedef char CommandeType[20]; CommandeType saveNames[10]; + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(saveNames, 0, sizeof(saveNames)); + Common::InSaveFile *in; char tmp[80]; @@ -707,8 +714,9 @@ Common::Error CineEngine::saveGameState(int slot, const char *desc) { // Load savegame descriptions from index file loadSaveDirectory(); - // Set description for selected slot + // Set description for selected slot making sure it ends with a trailing zero strncpy(currentSaveName[slot], desc, 20); + currentSaveName[slot][sizeof(CommandeType) - 1] = 0; // Update savegame descriptions char indexFile[80]; diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp index b3e3629239..757419ef87 100644 --- a/engines/cine/pal.cpp +++ b/engines/cine/pal.cpp @@ -239,9 +239,6 @@ Palette &Palette::saturatedAddNormalizedGray(Palette& output, byte firstIndex, b } // a.k.a. transformColor -// Parameter color components (i.e. r, g and b) are in range [-7, 7] -// e.g. r = 7 sets the resulting color's red component to maximum -// e.g. r = -7 sets the resulting color's red component to minimum (i.e. zero) Cine::Palette::Color Palette::saturatedAddColor(Cine::Palette::Color baseColor, signed r, signed g, signed b) const { Cine::Palette::Color result; result.r = CLIP<int>(baseColor.r + r, 0, _format.rMax()); diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index be1e19b229..158d209289 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -468,9 +468,18 @@ bool CineEngine::loadSaveDirectory(void) { return false; } + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(currentSaveName, 0, sizeof(currentSaveName)); + fHandle->read(currentSaveName, 10 * 20); delete fHandle; + // Make sure all savegames' descriptions end with a trailing zero. + for (int i = 0; i < ARRAYSIZE(currentSaveName); i++) + currentSaveName[i][sizeof(CommandeType) - 1] = 0; + return true; } diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index 3d3a44a36c..7abf83f054 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -65,7 +66,7 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc _debugger = new Debugger(); _sound = new PCSound(_mixer, this); - syst->getEventManager()->registerRandomSource(_rnd, "cruise"); + g_eventRec.registerRandomSource(_rnd, "cruise"); } CruiseEngine::~CruiseEngine() { diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index e5864ebb31..94dfc95cb5 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -1390,7 +1390,7 @@ int CruiseEngine::processInput(void) { } // Player Menu - test for both buttons or the F10 key - if (((button & MB_BOTH) == MB_BOTH) || (keyboardCode == Common::KEYCODE_F10)) { + if (((button & CRS_MB_BOTH) == CRS_MB_BOTH) || (keyboardCode == Common::KEYCODE_F10)) { changeCursor(CURSOR_NORMAL); keyboardCode = Common::KEYCODE_INVALID; return (playerMenu(mouseX, mouseY)); @@ -1398,7 +1398,7 @@ int CruiseEngine::processInput(void) { if (userWait) { // Check for left mouse button click or Space to end user waiting - if ((keyboardCode == Common::KEYCODE_SPACE) || (button == MB_LEFT)) + if ((keyboardCode == Common::KEYCODE_SPACE) || (button == CRS_MB_LEFT)) userWait = 0; keyboardCode = Common::KEYCODE_INVALID; @@ -1450,7 +1450,7 @@ int CruiseEngine::processInput(void) { menuDown = 0; } } else { - if ((button & MB_LEFT) && (buttonDown == 0)) { + if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { if (menuTable[0]) { callRelation(getSelectedEntryInMenu(menuTable[0]), dialogueObj); @@ -1472,7 +1472,7 @@ int CruiseEngine::processInput(void) { } } - } else if ((button & MB_LEFT) && (buttonDown == 0)) { + } else if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { // left click buttonDown = 1; @@ -1538,20 +1538,17 @@ int CruiseEngine::processInput(void) { aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { // No object found, we move the character to the cursor aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { // handle click in menu @@ -1590,7 +1587,7 @@ int CruiseEngine::processInput(void) { } } } - } else if ((button & MB_RIGHT) || (keyboardCode == Common::KEYCODE_F9)) { + } else if ((button & CRS_MB_RIGHT) || (keyboardCode == Common::KEYCODE_F9)) { if (buttonDown == 0) { keyboardCode = Common::KEYCODE_INVALID; @@ -1628,29 +1625,28 @@ bool bFastMode = false; bool manageEvents() { Common::Event event; - bool result = false; Common::EventManager * eventMan = g_system->getEventManager(); - while (eventMan->pollEvent(event) && !result) { - result = true; + while (eventMan->pollEvent(event)) { + bool abortFlag = true; switch (event.type) { case Common::EVENT_LBUTTONDOWN: - currentMouseButton |= MB_LEFT; + currentMouseButton |= CRS_MB_LEFT; break; case Common::EVENT_LBUTTONUP: - currentMouseButton &= ~MB_LEFT; + currentMouseButton &= ~CRS_MB_LEFT; break; case Common::EVENT_RBUTTONDOWN: - currentMouseButton |= MB_RIGHT; + currentMouseButton |= CRS_MB_RIGHT; break; case Common::EVENT_RBUTTONUP: - currentMouseButton &= ~MB_RIGHT; + currentMouseButton &= ~CRS_MB_RIGHT; break; case Common::EVENT_MOUSEMOVE: currentMouseX = event.mouse.x; currentMouseY = event.mouse.y; - result = false; + abortFlag = false; break; case Common::EVENT_QUIT: case Common::EVENT_RTL: @@ -1659,7 +1655,7 @@ bool manageEvents() { case Common::EVENT_KEYUP: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: - currentMouseButton &= ~MB_MIDDLE; + currentMouseButton &= ~CRS_MB_MIDDLE; break; default: break; @@ -1668,7 +1664,7 @@ bool manageEvents() { case Common::EVENT_KEYDOWN: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: - currentMouseButton |= MB_MIDDLE; + currentMouseButton |= CRS_MB_MIDDLE; break; default: keyboardCode = event.kbd.keycode; @@ -1689,9 +1685,12 @@ bool manageEvents() { default: break; } + + if (abortFlag) + return true; } - return result; + return false; } void getMouseStatus(int16 *pMouseVar, int16 *pMouseX, int16 *pMouseButton, int16 *pMouseY) { @@ -1798,6 +1797,9 @@ void CruiseEngine::mainLoop(void) { // User waiting has ended changeScriptParamInList(-1, -1, &procHead, 9999, 0); changeScriptParamInList(-1, -1, &relHead, 9999, 0); + + // Disable any mouse click used to end the user wait + currentMouseButton = 0; } manageScripts(&relHead); @@ -1899,8 +1901,6 @@ void CruiseEngine::mainLoop(void) { g_system->updateScreen(); } - manageEvents(); - } while (!playerDontAskQuit && quitValue2 && quitValue != 7); } diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h index d2e9350d70..5f4d5c5c13 100644 --- a/engines/cruise/cruise_main.h +++ b/engines/cruise/cruise_main.h @@ -56,10 +56,10 @@ namespace Cruise { enum MouseButton { - MB_LEFT = 1, - MB_RIGHT = 2, - MB_MIDDLE = 4, - MB_BOTH = MB_LEFT | MB_RIGHT + CRS_MB_LEFT = 1, + CRS_MB_RIGHT = 2, + CRS_MB_MIDDLE = 4, + CRS_MB_BOTH = CRS_MB_LEFT | CRS_MB_RIGHT }; /*#define DUMP_SCRIPT diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp index 3cf3957703..1202d06fbc 100644 --- a/engines/cruise/dataLoader.cpp +++ b/engines/cruise/dataLoader.cpp @@ -382,7 +382,7 @@ int loadFNTSub(uint8 *ptr, int destIdx) { currentPtr = destPtr + 14; - for (i = 0; i < *(int16 *)(destPtr + 8); i++) { + for (i = 0; i < (int16)READ_UINT16(destPtr + 8); i++) { bigEndianLongToNative((int32 *) currentPtr); currentPtr += 4; diff --git a/engines/cruise/linker.cpp b/engines/cruise/linker.cpp index bb6f682e1e..2d14d46ce3 100644 --- a/engines/cruise/linker.cpp +++ b/engines/cruise/linker.cpp @@ -23,6 +23,7 @@ * */ +#include "common/endian.h" #include "cruise/cruise_main.h" namespace Cruise { @@ -182,9 +183,7 @@ int updateScriptImport(int ovlIdx) { uint8 *ptr = ptrData + temp; *(ptr + 1) = out2; - *(int16 *)(ptr + 2) = ptrDest2->idx; - - bigEndianShortToNative((int16 *)(ptr + 2)); + WRITE_BE_UINT16(ptr + 2, ptrDest2->idx); } else { if (param2 == 20 || param2 == 30 || param2 == 40 || param2 == 50) { // this patch a double push uint8 *ptr = ptrData + temp; @@ -192,9 +191,7 @@ int updateScriptImport(int ovlIdx) { *(ptr + 1) = 0; *(ptr + 2) = out2; // update the overlay number - *(int16 *)(ptr + 4) = ptrDest2->idx; - - bigEndianShortToNative((int16 *)(ptr + 4)); + WRITE_BE_UINT16(ptr + 4, ptrDest2->idx); } else { int var_4 = ptrDest2->var4; @@ -213,17 +210,7 @@ int updateScriptImport(int ovlIdx) { *(ptrData + temp) = param2; *(ptrData + temp + 1) = out2; - *(int16 *)(ptrData + temp + 2) = ptrDest2->idx; - - bigEndianShortToNative - ( - (int16 - *) - (ptrData - + - temp - + - 2)); + WRITE_BE_UINT16(ptrData + temp + 2, ptrDest2->idx); } } } diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 2932e6dc7d..047f00ee90 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -206,10 +206,34 @@ int m_first_Y; int m_scaleValue; int m_color; -int16 DIST_3D[512]; -int16 polyBuffer2[512]; -int16 XMIN_XMAX[404]; -int16 polyBuffer4[512]; +/* + FIXME: Whether intentional or not, the game often seems to use negative indexing + of one or more of the arrays below and expects(?) to end up in the preceding one. + This "worked" on many platforms so far, but on OSX apparently the buffers don't + occupy contiguous memory, and this causes severe corruption and subsequent crashes. + Since I'm not really familiar with how the strange drawing code is supposed to work, + or whether this behaviour is intentional or not, the short-term fix is to allocate a big + buffer and setup pointers within it. This fixes the crashes I'm seeing without causing any + (visual) side-effects. + If anyone wants to look, this is easily reproduced by starting the game and examining the rug. + drawPolyMode1() will then (indirectly) negatively index polyBuffer4. Good luck! +*/ + +//int16 DIST_3D[512]; +//int16 polyBuffer2[512]; +//int16 XMIN_XMAX[404]; +//int16 polyBuffer4[512]; + +int16 bigPolyBuf[512 + 512 + 404 + 512]; /* consolidates the 4 separate buffers above */ + +//set up the replacement index pointers. +int16 *DIST_3D = &bigPolyBuf[0]; +int16 *polyBuffer2 = &bigPolyBuf[512]; +int16 *XMIN_XMAX = &bigPolyBuf[512 + 512]; +int16 *polyBuffer4 = &bigPolyBuf[512 + 512 + 404]; + + + // this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2) void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], unsigned char *dataPtr) { diff --git a/engines/cruise/mainDraw.h b/engines/cruise/mainDraw.h index dc988b551d..620ac6e4d7 100644 --- a/engines/cruise/mainDraw.h +++ b/engines/cruise/mainDraw.h @@ -29,8 +29,8 @@ namespace Cruise { extern int currentTransparent; -extern int16 polyBuffer2[512]; -extern int16 XMIN_XMAX[404]; +extern int16 *polyBuffer2; +extern int16 *XMIN_XMAX; extern int m_color; int upscaleValue(int value, int scale); diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index 54f686f32a..7e454e78f8 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -179,6 +179,7 @@ int processMenu(menuStruct *pMenu) { flipScreen(); manageEvents(); + g_system->delayMillis(10); // readKeyboard(); } while (!si); diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp index 9f89f04069..761bba3673 100644 --- a/engines/cruise/script.cpp +++ b/engines/cruise/script.cpp @@ -23,6 +23,7 @@ * */ +#include "cruise/cruise.h" #include "cruise/cruise_main.h" #include "common/endian.h" @@ -632,7 +633,11 @@ int executeScripts(scriptInstanceStruct *ptr) { #endif opcodeType = getByteFromScript(); - // printf("opType: %d\n",(opcodeType&0xFB)>>3); + debugC(5, kCruiseDebugScript, "Script %s/%d ip=%d opcode=%d", + overlayTable[currentScriptPtr->overlayNumber].overlayName, + currentScriptPtr->scriptNumber, + currentScriptPtr->scriptOffset, + (opcodeType & 0xFB) >> 3); currentScriptOpcodeType = opcodeType & 7; diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index 92c2ac6256..7ca4246785 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -766,6 +766,10 @@ void PCSoundFxPlayer::doSync(Common::Serializer &s) { for (int i = 0; i < NUM_CHANNELS; ++i) { _instrumentsChannelTable[i] = -1; } + + _numOrders = _sfxData[470]; + _eventsDelay = (244 - _sfxData[471]) * 100 / 1060; + _updateTicksCounter = 0; } s.syncAsSint16LE(_songPlayed); diff --git a/engines/cruise/staticres.cpp b/engines/cruise/staticres.cpp index d49d12c05b..595ac5a38b 100644 --- a/engines/cruise/staticres.cpp +++ b/engines/cruise/staticres.cpp @@ -168,6 +168,59 @@ int16 german_fontCharacterTable[256] = { -1, -1, -1, -1 }; +int16 spanish_fontCharacterTable[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, + -1, -1, -1, + 0x72, 0x80 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0x7f, 0x79, 0x7b, 0x81, 0x82, 0x83, + -1, -1, + 0x7d, + -1, -1, -1, -1, + 0x7E, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, + 0x6A, 0x69, + -1, -1, -1, -1, + 0x6B, 0x6C, + -1, -1, + 0x6D, 0x6E, + -1, -1, -1, -1, -1, -1, + 0x6F, + -1, + 0x70, + -1, -1, + 0x71, 0x72, + -1, -1, + 0x74, 0x5D, + -1, + 0x76, + -1, + 0x5E, + -1, + 0x75, 0x73, 0x60, 0x5F, 0x61, 0x62, 0x79, 0x78, 0x63, 0x64, + -1, -1, + 0x7B, 0x7A, + 0x65, + -1, + 0x66, + -1, -1, + 0x67, + -1, + 0x68, + -1, -1, -1, -1 +}; + // // Mouse data // diff --git a/engines/cruise/staticres.h b/engines/cruise/staticres.h index ef9a1b47e9..964bf294dc 100644 --- a/engines/cruise/staticres.h +++ b/engines/cruise/staticres.h @@ -41,9 +41,11 @@ extern int actor_invstat[][13]; extern short int english_fontCharacterTable[256]; extern short int german_fontCharacterTable[256]; +extern short int spanish_fontCharacterTable[256]; #define fontCharacterTable (_vm->getLanguage() == Common::DE_DEU ? \ - german_fontCharacterTable : english_fontCharacterTable) + german_fontCharacterTable : (_vm->getLanguage() == Common::ES_ESP ? \ + spanish_fontCharacterTable : english_fontCharacterTable)) // Mouse cursor data extern const byte mouseCursorNormal[]; diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp index 4aa8ee0d9e..006f16ab45 100644 --- a/engines/drascula/converse.cpp +++ b/engines/drascula/converse.cpp @@ -141,8 +141,9 @@ void DrasculaEngine::converse(int index) { int game1 = kDialogOptionUnselected, game2 = kDialogOptionUnselected, game3 = kDialogOptionUnselected; - char phrase1[78], phrase2[78], phrase3[78], phrase4[78]; + char phrase1[128], phrase2[128], phrase3[128], phrase4[128]; char sound1[13], sound2[13], sound3[13], sound4[13]; + int phrase1_bottom, phrase2_bottom, phrase3_bottom, phrase4_bottom; int answer1, answer2, answer3; char buffer[256]; @@ -207,12 +208,12 @@ void DrasculaEngine::converse(int index) { updateEvents(); - print_abc_opc(phrase1, 2, game1); - print_abc_opc(phrase2, 10, game2); - print_abc_opc(phrase3, 18, game3); - print_abc_opc(phrase4, 26, kDialogOptionUnselected); + phrase1_bottom = 8 * print_abc_opc(phrase1, 2, game1); + phrase2_bottom = phrase1_bottom + 8 * print_abc_opc(phrase2, phrase1_bottom + 2, game2); + phrase3_bottom = phrase2_bottom + 8 * print_abc_opc(phrase3, phrase2_bottom + 2, game3); + phrase4_bottom = phrase3_bottom + 8 * print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionUnselected); - if (mouseY > 0 && mouseY < 9) { + if (mouseY > 0 && mouseY < phrase1_bottom) { if (game1 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game1 != kDialogOptionClicked && _color != kColorLightGreen) @@ -226,13 +227,13 @@ void DrasculaEngine::converse(int index) { talk(phrase1, sound1); response(answer1); } - } else if (mouseY > 8 && mouseY < 17) { + } else if (mouseY > phrase1_bottom && mouseY < phrase2_bottom) { if (game2 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game2 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); - print_abc_opc(phrase2, 10, kDialogOptionSelected); + print_abc_opc(phrase2, phrase1_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -240,13 +241,13 @@ void DrasculaEngine::converse(int index) { talk(phrase2, sound2); response(answer2); } - } else if (mouseY > 16 && mouseY < 25) { + } else if (mouseY > phrase2_bottom && mouseY < phrase3_bottom) { if (game3 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game3 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); - print_abc_opc(phrase3, 18, kDialogOptionSelected); + print_abc_opc(phrase3, phrase2_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -254,8 +255,8 @@ void DrasculaEngine::converse(int index) { talk(phrase3, sound3); response(answer3); } - } else if (mouseY > 24 && mouseY < 33) { - print_abc_opc(phrase4, 26, kDialogOptionSelected); + } else if (mouseY > phrase3_bottom && mouseY < phrase4_bottom) { + print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -265,6 +266,7 @@ void DrasculaEngine::converse(int index) { } else if (_color != kColorLightGreen) color_abc(kColorLightGreen); + _system->delayMillis(10); updateScreen(); } // while (breakOut == 0) diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index a3c56be1f4..2e3db3478e 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -92,7 +93,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam *textName = 0; _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "drascula"); + g_eventRec.registerRandomSource(*_rnd, "drascula"); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) @@ -181,10 +182,6 @@ Common::Error DrasculaEngine::run() { for (;;) { int i; - - VGA = (byte *)malloc(320 * 200); - memset(VGA, 0, 64000); - takeObject = 0; _menuBar = false; _menuScreen = false; @@ -295,7 +292,6 @@ void DrasculaEngine::endChapter() { MusicFadeout(); stopMusic(); freeMemory(); - free(VGA); } bool DrasculaEngine::runCurrentChapter() { @@ -716,7 +712,8 @@ bool DrasculaEngine::verify2() { Common::KeyCode DrasculaEngine::getScan() { updateEvents(); - if (_keyBufferHead == _keyBufferTail) return Common::KEYCODE_INVALID; + if (_keyBufferHead == _keyBufferTail) + return Common::KEYCODE_INVALID; Common::KeyCode key = _keyBuffer[_keyBufferTail].keycode; _keyBufferTail = (_keyBufferTail + 1) % KEYBUFSIZE; diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index b06a2c9d4b..85f31ea2d1 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -344,7 +344,6 @@ public: byte *mouseCursor; // Graphics buffers/pointers - byte *VGA; byte *bgSurface; byte *backSurface; byte *drawSurface3; @@ -353,7 +352,6 @@ public: byte *extraSurface; // not sure about this one, was "dir_hare_dch" byte *screenSurface; byte *frontSurface; - byte *textSurface; byte *memPtr; byte *mSession; @@ -564,7 +562,7 @@ public: void playTalkSequence(int sequence); void doTalkSequenceCommand(TalkSequenceCommand cmd); void converse(int); - void print_abc_opc(const char *, int, int); + int print_abc_opc(const char *, int, int); void response(int); void activatePendulum(); diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 76a551c980..74b9e131e3 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -24,6 +24,7 @@ */ #include "drascula/drascula.h" +#include "graphics/surface.h" namespace Drascula { @@ -47,7 +48,7 @@ void DrasculaEngine::allocMemory() { assert(tableSurface); extraSurface = (byte *)malloc(64000); assert(extraSurface); - crosshairCursor = (byte *)malloc(40 * 25); + crosshairCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT); assert(crosshairCursor); mouseCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT); assert(mouseCursor); @@ -126,16 +127,18 @@ void DrasculaEngine::showFrame(bool firstFrame) { } byte *prevFrame = (byte *)malloc(64000); - memcpy(prevFrame, VGA, 64000); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; + memcpy(prevFrame, screenBuffer, 64000); - decodeRLE(pcxData, VGA); + decodeRLE(pcxData, screenBuffer); free(pcxData); if (!firstFrame) - mixVideo(VGA, prevFrame); + mixVideo(screenBuffer, prevFrame); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + _system->unlockScreen(); _system->updateScreen(); + if (firstFrame) setPalette(cPal); @@ -192,8 +195,9 @@ void DrasculaEngine::copyRect(int xorg, int yorg, int xdes, int ydes, int width, } void DrasculaEngine::updateScreen(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *buffer) { - copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, VGA); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; + copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, screenBuffer); + _system->unlockScreen(); _system->updateScreen(); } @@ -235,13 +239,30 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) { } // for } -void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { +int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { int signY, letterY, letterX = 0; uint len = strlen(said); int screenX = 1; + int lines = 1; for (uint h = 0; h < len; h++) { + int wordLength; + + // Look ahead to the end of the word. + wordLength = 0; + int pos = h; + while (said[pos] && said[pos] != ' ') { + wordLength++; + pos++; + } + + if (screenX + wordLength * CHAR_WIDTH_OPC > 317) { + screenX = 0; + screenY += (CHAR_HEIGHT + 2); + lines++; + } + if (game == 1) { letterY = 6; signY = 15; @@ -281,6 +302,8 @@ void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { screenX = screenX + CHAR_WIDTH_OPC; } + + return lines; } bool DrasculaEngine::textFitsCentered(char *text, int x) { @@ -402,6 +425,7 @@ void DrasculaEngine::screenSaver() { int x1_, y1_, off1, off2; + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; for (int i = 0; i < 200; i++) { for (int j = 0; j < 320; j++) { x1_ = j + tempRow[i]; @@ -419,10 +443,11 @@ void DrasculaEngine::screenSaver() { y1_ = checkWrapY(y1_); off2 = 320 * y1_ + x1_; - VGA[320 * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)]; + screenBuffer[320 * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)]; } } - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + + _system->unlockScreen(); _system->updateScreen(); _system->delayMillis(20); @@ -515,11 +540,14 @@ int DrasculaEngine::playFrameSSN() { decodeRLE(BufferSSN, screenSurface); free(BufferSSN); waitFrameSSN(); + + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; if (FrameSSN) - mixVideo(VGA, screenSurface); + mixVideo(screenBuffer, screenSurface); else - memcpy(VGA, screenSurface, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + memcpy(screenBuffer, screenSurface, 64000); + + _system->unlockScreen(); _system->updateScreen(); FrameSSN++; } else { @@ -534,11 +562,13 @@ int DrasculaEngine::playFrameSSN() { decodeOffset(BufferSSN, screenSurface, length); free(BufferSSN); waitFrameSSN(); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; if (FrameSSN) - mixVideo(VGA, screenSurface); + mixVideo(screenBuffer, screenSurface); else - memcpy(VGA, screenSurface, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + memcpy(screenBuffer, screenSurface, 64000); + + _system->unlockScreen(); _system->updateScreen(); FrameSSN++; } diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 8284112c1e..c9912f25d2 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -1866,69 +1866,68 @@ void DrasculaEngine::enterRoom(int roomIndex) { } void DrasculaEngine::clearRoom() { - memset(VGA, 0, 64000); _system->fillScreen(0); _system->updateScreen(); } -bool DrasculaEngine::exitRoom(int l) { - debug(2, "Exiting room from door %d", l); +bool DrasculaEngine::exitRoom(int doorNumber) { + debug(2, "Exiting room from door %d", doorNumber); int roomNum = 0; // Player can't exit the inn in chapter 1 - if (currentChapter == 1 && objectNum[l] == 104) { + if (currentChapter == 1 && objectNum[doorNumber] == 104) { return false; } - if (currentChapter == 1 && objectNum[l] == 105 && flags[0] == 0) { + if (currentChapter == 1 && objectNum[doorNumber] == 105 && flags[0] == 0) { talk(442); return false; } - updateDoor(l); - if (isDoor[l] != 0 && - ((currentChapter != 3 && currentChapter != 5) || visible[l] == 1)) { + updateDoor(doorNumber); + if (isDoor[doorNumber] != 0 && + ((currentChapter != 3 && currentChapter != 5) || visible[doorNumber] == 1)) { hideCursor(); - gotoObject(roomObjX[l], roomObjY[l]); + gotoObject(roomObjX[doorNumber], roomObjY[doorNumber]); if (currentChapter != 2) { - trackProtagonist = trackObj[l]; + trackProtagonist = trackObj[doorNumber]; updateRoom(); updateScreen(); } characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = roomExits[l]; + trackProtagonist = trackCharacter_alkeva[doorNumber]; + objExit = roomExits[doorNumber]; doBreak = 1; previousMusic = roomMusic; // Object specific actions - if (currentChapter == 1 && objectNum[l] == 105) { + if (currentChapter == 1 && objectNum[doorNumber] == 105) { animation_2_1(); return true; } else if (currentChapter == 2) { - if (objectNum[l] == 136) + if (objectNum[doorNumber] == 136) animation_2_2(); - if (objectNum[l] == 124) { + if (objectNum[doorNumber] == 124) { gotoObject(163, 106); gotoObject(287, 101); trackProtagonist = 0; } - if (objectNum[l] == 173) { + if (objectNum[doorNumber] == 173) { animation_35_2(); return true; } - if (objectNum[l] == 146 && flags[39] == 1) { + if (objectNum[doorNumber] == 146 && flags[39] == 1) { flags[5] = 1; flags[11] = 1; } - if (objectNum[l] == 176 && flags[29] == 1) { + if (objectNum[doorNumber] == 176 && flags[29] == 1) { flags[29] = 0; removeObject(kItemEarWithEarPlug); addObject(kItemEarplugs); } - } else if (currentChapter == 4 && objectNum[l] == 108) { + } else if (currentChapter == 4 && objectNum[doorNumber] == 108) { gotoObject(171, 78); } @@ -1936,7 +1935,7 @@ bool DrasculaEngine::exitRoom(int l) { hare_se_ve = 1; clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); + sscanf(_targetSurface[doorNumber], "%d", &roomNum); curX = -1; enterRoom(roomNum); diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index 7c94938c9b..4b649ce8db 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -803,6 +803,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha p = 0; + memset(buf, 0, sizeof(buf)); talkInit(filename); do { diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 99cf7c1193..3b7a61d485 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -35,21 +35,22 @@ namespace Gob { DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) { _io = &io; - _handle = handle; - _size = dSize; + + _handle = handle; + _size = dSize; _dispose = dispose; - _data = 0; + _data = 0; _stream = 0; } DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) { - _data = buf; - _size = dSize; - _stream = new Common::MemoryReadStream(_data, _size); + _data = buf; + _size = dSize; + _stream = new Common::MemoryReadStream(_data, _size); _dispose = dispose; - _io = 0; + _io = 0; _handle = -1; } @@ -84,7 +85,7 @@ int32 DataStream::size() const { bool DataStream::seek(int32 offset, int whence) { if (_stream) return _stream->seek(offset, whence); - else if ((_handle < 50) || (_handle >= 128)) + else if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->seek(offset, whence); else { _io->seekChunk(_handle, offset, whence); @@ -103,7 +104,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { if (_stream) return _stream->read(dataPtr, dataSize); - if ((_handle < 50) || (_handle >= 128)) + if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); byte *data = (byte *) dataPtr; @@ -111,7 +112,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { while (dataSize > 0x3FFF) { _io->readChunk(_handle, (byte *) data, 0x3FFF); dataSize -= 0x3FFF; - data += 0x3FFF; + data += 0x3FFF; haveRead += 0x3FFF; } _io->readChunk(_handle, (byte *) data, dataSize); @@ -121,11 +122,10 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { DataIO::DataIO(GobEngine *vm) : _vm(vm) { for (int i = 0; i < MAX_DATA_FILES; i++) { - _dataFiles[i] = 0; - _numDataChunks[i] = 0; + _dataFiles[i] = 0; + _numDataChunks[i] = 0; _dataFileHandles[i] = -1; } - _packedSize = 0; } DataIO::~DataIO() { @@ -136,6 +136,46 @@ DataIO::~DataIO() { } } +bool DataIO::isDataFileChunk(int16 handle) const { + return (handle >= 50) && (handle < 128); +} + +bool DataIO::isPacked(int16 handle) const { + if (!isDataFileChunk(handle)) + return false; + + return _chunk[getIndex(handle)]->packed != 0; +} + +int DataIO::getFile(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) / 10; +} + +int DataIO::getSlot(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) % 10; +} + +int DataIO::getIndex(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return getIndex(getFile(handle), getSlot(handle)); +} + +int DataIO::getIndex(int file, int slot) const { + return file * MAX_SLOT_COUNT + slot; +} + +int16 DataIO::getHandle(int file, int slot) const { + return file * 10 + slot + 50; +} + int32 DataIO::unpackData(byte *src, byte *dest) { uint32 realSize; uint32 counter; @@ -222,13 +262,11 @@ int16 DataIO::file_open(const char *path) { } int16 DataIO::getChunk(const char *chunkName) { - int16 slot; - struct ChunkDesc *dataDesc; - for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; + int16 slot; for (slot = 0; slot < MAX_SLOT_COUNT; slot++) if (_chunkPos[file * MAX_SLOT_COUNT + slot] == -1) break; @@ -238,59 +276,55 @@ int16 DataIO::getChunk(const char *chunkName) { return -1; } - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; - _isCurrentSlot[file * MAX_SLOT_COUNT + slot] = false; - _chunkSize[file * MAX_SLOT_COUNT + slot] = dataDesc->size; - _chunkOffset[file * MAX_SLOT_COUNT + slot] = dataDesc->offset; - _chunkPos[file * MAX_SLOT_COUNT + slot] = 0; - return file * 10 + slot + 50; + int index = getIndex(file, slot); + + _isCurrentSlot[index] = false; + _chunk [index] = dataDesc; + _chunkPos [index] = 0; + + return getHandle(file, slot); } } return -1; } char DataIO::freeChunk(int16 handle) { - if ((handle >= 50) && (handle < 128)) { - handle -= 50; - _chunkPos[(handle / 10) * MAX_SLOT_COUNT + (handle % 10)] = -1; + if (isDataFileChunk(handle)) { + _chunkPos[getIndex(handle)] = -1; return 0; } return 1; } int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { - int16 file; - int16 slot; - int16 i; - int32 offset; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -2; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); - _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunkSize[index]); + _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunk[index]->size); if (!_isCurrentSlot[index]) { - for (i = 0; i < MAX_SLOT_COUNT; i++) + for (int16 i = 0; i < MAX_SLOT_COUNT; i++) _isCurrentSlot[file * MAX_SLOT_COUNT + i] = false; - offset = _chunkOffset[index] + _chunkPos[index]; + int32 offset = _chunk[index]->offset + _chunkPos[index]; - debugC(7, kDebugFileIO, "seek: %d, %d", _chunkOffset[index], _chunkPos[index]); + debugC(7, kDebugFileIO, "seek: %d, %d", _chunk[index]->offset, _chunkPos[index]); file_getHandle(_dataFileHandles[file])->seek(offset, SEEK_SET); } _isCurrentSlot[index] = true; - if ((_chunkPos[index] + size) > (_chunkSize[index])) - size = _chunkSize[index] - _chunkPos[index]; + if ((_chunkPos[index] + size) > (int32) (_chunk[index]->size)) + size = _chunk[index]->size - _chunkPos[index]; file_getHandle(_dataFileHandles[file])->read(buf, size); _chunkPos[index] += size; @@ -298,15 +332,12 @@ int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { } int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -1; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); _isCurrentSlot[index] = false; if (from == SEEK_SET) @@ -314,50 +345,45 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { else if (from == SEEK_CUR) _chunkPos[index] += pos; else if (from == SEEK_END) - _chunkPos[index] = _chunkSize[index] - pos; + _chunkPos[index] = _chunk[index]->size - pos; return _chunkPos[index]; } uint32 DataIO::getChunkPos(int16 handle) const { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return 0xFFFFFFFF; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; + int file = getFile(handle); + int slot = getSlot(handle); return _chunkPos[file * MAX_SLOT_COUNT + slot]; } -int32 DataIO::getChunkSize(const char *chunkName) { - int16 file; - struct ChunkDesc *dataDesc; - int16 slot; - int32 realSize; - - for (file = 0; file < MAX_DATA_FILES; file++) { +int32 DataIO::getChunkSize(const char *chunkName, int32 &packSize) { + for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; if (dataDesc->packed == 0) { - _packedSize = -1; + packSize = -1; return dataDesc->size; } - for (slot = 0; slot < MAX_SLOT_COUNT; slot++) + for (int16 slot = 0; slot < MAX_SLOT_COUNT; slot++) _isCurrentSlot[slot] = false; + int32 realSize; + file_getHandle(_dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET); realSize = file_getHandle(_dataFileHandles[file])->readUint32LE(); - _packedSize = dataDesc->size; + packSize = dataDesc->size; + return realSize; } } @@ -365,10 +391,7 @@ int32 DataIO::getChunkSize(const char *chunkName) { } void DataIO::openDataFile(const char *src, bool itk) { - ChunkDesc *dataDesc; char path[128]; - int16 file; - char *fakeTotPtr; strncpy0(path, src, 127); if (!strchr(path, '.')) { @@ -376,6 +399,7 @@ void DataIO::openDataFile(const char *src, bool itk) { strcat(path, ".stk"); } + int16 file; for (file = 0; file < MAX_DATA_FILES; file++) if (_dataFiles[file] == 0) break; @@ -388,17 +412,17 @@ void DataIO::openDataFile(const char *src, bool itk) { if (_dataFileHandles[file] == -1) error("DataIO::openDataFile(): Can't open data file \"%s\"", path); - _dataFileItk[file] = itk; + _dataFileItk [file] = itk; _numDataChunks[file] = file_getHandle(_dataFileHandles[file])->readUint16LE(); debugC(7, kDebugFileIO, "DataChunks: %d [for %s]", _numDataChunks[file], path); - dataDesc = new ChunkDesc[_numDataChunks[file]]; + ChunkDesc *dataDesc = new ChunkDesc[_numDataChunks[file]]; _dataFiles[file] = dataDesc; for (int i = 0; i < _numDataChunks[file]; i++) { file_getHandle(_dataFileHandles[file])->read(dataDesc[i].chunkName, 13); - dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); + dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].offset = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].packed = file_getHandle(_dataFileHandles[file])->readByte(); @@ -410,7 +434,7 @@ void DataIO::openDataFile(const char *src, bool itk) { Util::replaceChar(dataDesc[i].chunkName, (char) 0x92, 'T'); // Geisha use 0ot files, which are compressed TOT files without the packed byte set. - fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); + char *fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); if (fakeTotPtr != 0) { strncpy(fakeTotPtr, "TOT", 3); dataDesc[i].packed = 1; @@ -436,33 +460,29 @@ void DataIO::closeDataFile(bool itk) { } byte *DataIO::getUnpackedData(const char *name) { - int32 realSize; - int16 chunk; - byte *unpackBuf; - byte *packBuf; - byte *ptr; - int32 sizeLeft; - - realSize = getChunkSize(name); - if ((_packedSize == -1) || (realSize == -1)) + int32 realSize, packSize; + + realSize = getChunkSize(name, packSize); + + if ((packSize == -1) || (realSize == -1)) return 0; - chunk = getChunk(name); + int16 chunk = getChunk(name); if (chunk == -1) return 0; - unpackBuf = new byte[realSize]; + byte *unpackBuf = new byte[realSize]; assert(unpackBuf); - packBuf = new byte[_packedSize]; + byte *packBuf = new byte[packSize]; assert(packBuf); - sizeLeft = _packedSize; - ptr = packBuf; + int32 sizeLeft = packSize; + byte *ptr = packBuf; while (sizeLeft > 0x4000) { readChunk(chunk, ptr, 0x4000); sizeLeft -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readChunk(chunk, ptr, sizeLeft); freeChunk(chunk); @@ -478,9 +498,7 @@ void DataIO::closeData(int16 handle) { } int16 DataIO::openData(const char *path) { - int16 handle; - - handle = getChunk(path); + int16 handle = getChunk(path); if (handle >= 0) return handle; @@ -492,7 +510,6 @@ bool DataIO::existData(const char *path) { return false; int16 handle = openData(path); - if (handle < 0) return false; @@ -510,9 +527,7 @@ DataStream *DataIO::openAsStream(int16 handle, bool dispose) { } uint32 DataIO::getPos(int16 handle) { - uint32 resPos; - - resPos = getChunkPos(handle); + uint32 resPos = getChunkPos(handle); if (resPos != 0xFFFFFFFF) return resPos; @@ -520,9 +535,7 @@ uint32 DataIO::getPos(int16 handle) { } void DataIO::seekData(int16 handle, int32 pos, int16 from) { - int32 resPos; - - resPos = seekChunk(handle, pos, from); + int32 resPos = seekChunk(handle, pos, from); if (resPos != -1) return; @@ -530,9 +543,7 @@ void DataIO::seekData(int16 handle, int32 pos, int16 from) { } int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { - int32 res; - - res = readChunk(handle, buf, size); + int16 res = readChunk(handle, buf, size); if (res >= 0) return res; @@ -541,45 +552,42 @@ int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { int32 DataIO::getDataSize(const char *name) { char buf[128]; - int32 chunkSz; - Common::File file; strncpy0(buf, name, 127); - chunkSz = getChunkSize(buf); - if (chunkSz >= 0) - return chunkSz; + int32 chunkSize, packSize; + + chunkSize = getChunkSize(buf, packSize); + if (chunkSize >= 0) + return chunkSize; + Common::File file; if (!file.open(buf)) error("DataIO::getDataSize(): Can't find data \"%s\"", name); - chunkSz = file.size(); + chunkSize = file.size(); file.close(); - return chunkSz; + return chunkSize; } byte *DataIO::getData(const char *path) { - byte *data; - byte *ptr; - int32 size; - int16 handle; - - data = getUnpackedData(path); + byte *data = getUnpackedData(path); if (data) return data; - size = getDataSize(path); + int32 size = getDataSize(path); + data = new byte[size]; assert(data); - handle = openData(path); + int16 handle = openData(path); - ptr = data; + byte *ptr = data; while (size > 0x4000) { readData(handle, ptr, 0x4000); size -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readData(handle, ptr, size); closeData(handle); @@ -588,12 +596,26 @@ byte *DataIO::getData(const char *path) { DataStream *DataIO::getDataStream(const char *path) { if (!existData(path)) + return 0; + + int16 handle = openData(path); + if (handle < 0) return 0; - uint32 size = getDataSize(path); - byte *data = getData(path); + if (isDataFileChunk(handle) && isPacked(handle)) { + // It's a packed chunk in the data files, packed, + // so we have to read it in completely and unpack it + + closeData(handle); + + uint32 size = getDataSize(path); + byte *data = getData(path); + + return new DataStream(data, size); - return new DataStream(data, size); + } else + // Otherwise, we can just return a stream + return openAsStream(handle, true); } } // End of namespace Gob diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 1f55cac90d..6a86667e1b 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -26,16 +26,14 @@ #ifndef GOB_DATAIO_H #define GOB_DATAIO_H - #include "common/endian.h" - #include "common/file.h" namespace Gob { -#define MAX_FILES 30 -#define MAX_DATA_FILES 8 -#define MAX_SLOT_COUNT 8 +#define MAX_FILES 30 +#define MAX_DATA_FILES 8 +#define MAX_SLOT_COUNT 8 class DataIO; @@ -56,20 +54,20 @@ public: private: DataIO *_io; - int16 _handle; - uint32 _size; - byte *_data; + int16 _handle; + uint32 _size; + byte *_data; + bool _dispose; Common::MemoryReadStream *_stream; - bool _dispose; }; class DataIO { public: struct ChunkDesc { - char chunkName[13]; + char chunkName[13]; uint32 size; uint32 offset; - byte packed; + byte packed; ChunkDesc() : size(0), offset(0), packed(0) { chunkName[0] = 0; } }; @@ -77,10 +75,13 @@ public: void openDataFile(const char *src, bool itk = 0); void closeDataFile(bool itk = 0); + byte *getUnpackedData(const char *name); - void closeData(int16 handle); + + void closeData(int16 handle); int16 openData(const char *path); - bool existData(const char *path); + bool existData(const char *path); + DataStream *openAsStream(int16 handle, bool dispose = false); int32 getDataSize(const char *name); @@ -92,34 +93,47 @@ public: protected: Common::File _filesHandles[MAX_FILES]; - struct ChunkDesc *_dataFiles[MAX_DATA_FILES]; - uint16 _numDataChunks[MAX_DATA_FILES]; - int16 _dataFileHandles[MAX_DATA_FILES]; - bool _dataFileItk[MAX_DATA_FILES]; - int32 _chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkOffset[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkSize[MAX_SLOT_COUNT * MAX_DATA_FILES]; - bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _packedSize; + + ChunkDesc *_dataFiles [MAX_DATA_FILES]; + uint16 _numDataChunks [MAX_DATA_FILES]; + int16 _dataFileHandles[MAX_DATA_FILES]; + bool _dataFileItk [MAX_DATA_FILES]; + + ChunkDesc *_chunk [MAX_SLOT_COUNT * MAX_DATA_FILES]; + int32 _chunkPos [MAX_SLOT_COUNT * MAX_DATA_FILES]; + bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; class GobEngine *_vm; + bool isDataFileChunk(int16 handle) const; + bool isPacked (int16 handle) const; + + int getFile (int16 handle) const; + int getSlot (int16 handle) const; + int getIndex(int16 handle) const; + + int getIndex (int file, int slot) const; + int16 getHandle(int file, int slot) const; + int16 file_open(const char *path); Common::File *file_getHandle(int16 handle); const Common::File *file_getHandle(int16 handle) const; int16 getChunk(const char *chunkName); - char freeChunk(int16 handle); + char freeChunk(int16 handle); int32 readChunk(int16 handle, byte *buf, uint16 size); int16 seekChunk(int16 handle, int32 pos, int16 from); + uint32 getChunkPos(int16 handle) const; - int32 getChunkSize(const char *chunkName); + + int32 getChunkSize(const char *chunkName, int32 &packSize); uint32 getPos(int16 handle); - void seekData(int16 handle, int32 pos, int16 from); + void seekData(int16 handle, int32 pos, int16 from); + int32 readData(int16 handle, byte *buf, uint16 size); -friend class DataStream; + friend class DataStream; }; } // End of namespace Gob diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp index 7f65721ce5..13b7aa5327 100644 --- a/engines/gob/demos/demoplayer.cpp +++ b/engines/gob/demos/demoplayer.cpp @@ -34,6 +34,7 @@ #include "gob/draw.h" #include "gob/inter.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -186,6 +187,30 @@ void DemoPlayer::playVideo(const char *fileName) { free(filePtr); } +void DemoPlayer::playADL(const char *params) { + const char *end; + + end = strchr(params, ' '); + if (!end) + end = params + strlen(params); + + Common::String fileName(params, end); + bool waitEsc = true; + int32 repeat = -1; + + if (*end != '\0') { + const char *start = end + 1; + + waitEsc = (*start != '0'); + + end = strchr(start, ' '); + if (end) + repeat = atoi(end + 1); + } + + playADL(fileName, waitEsc, repeat); +} + void DemoPlayer::playVideoNormal() { _vm->_vidPlayer->primaryPlay(); } @@ -233,6 +258,26 @@ void DemoPlayer::playVideoDoubled() { } } +void DemoPlayer::playADL(const Common::String &fileName, bool waitEsc, int32 repeat) { + debugC(1, kDebugDemo, "Playing ADL \"%s\" (%d, %d)", fileName.c_str(), waitEsc, repeat); + + _vm->_sound->adlibUnload(); + _vm->_sound->adlibLoadADL(fileName.c_str()); + _vm->_sound->adlibSetRepeating(repeat); + _vm->_sound->adlibPlay(); + + if (!waitEsc) + return; + + int16 key = 0; + while (!_vm->shouldQuit() && (key != kKeyEscape) && _vm->_sound->adlibIsPlaying()) { + _vm->_util->longDelay(1); + while (_vm->_util->checkKey(key)) + if (key == kKeyEscape) + break; + } +} + void DemoPlayer::evaluateVideoMode(const char *mode) { debugC(2, kDebugDemo, "Video mode \"%s\"", mode); diff --git a/engines/gob/demos/demoplayer.h b/engines/gob/demos/demoplayer.h index 64c98b58c5..f0672b9645 100644 --- a/engines/gob/demos/demoplayer.h +++ b/engines/gob/demos/demoplayer.h @@ -57,9 +57,11 @@ protected: void evaluateVideoMode(const char *mode); void clearScreen(); void playVideo(const char *fileName); + void playADL(const char *params); void playVideoNormal(); void playVideoDoubled(); + void playADL(const Common::String &fileName, bool waitEsc = true, int32 repeat = -1); private: enum ScriptSource { diff --git a/engines/gob/demos/scnplayer.cpp b/engines/gob/demos/scnplayer.cpp index 616da3272a..bf81773a15 100644 --- a/engines/gob/demos/scnplayer.cpp +++ b/engines/gob/demos/scnplayer.cpp @@ -66,6 +66,8 @@ bool SCNPlayer::playStream(Common::SeekableReadStream &scn) { _rebase0 = true; } else if (lineStartsWith(line, "REBASE0:OFF")) { _rebase0 = false; + } else if (lineStartsWith(line, "ADL ")) { + playADL(line.c_str() + 4); } // Mind user input diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 61c17b16f8..6088d622f8 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -2750,7 +2750,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2764,7 +2764,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2778,7 +2778,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2792,7 +2792,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2806,7 +2806,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2820,7 +2820,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2834,7 +2834,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2848,7 +2848,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2862,7 +2862,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2876,7 +2876,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2890,7 +2890,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2904,7 +2904,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2918,7 +2918,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2932,7 +2932,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2946,7 +2946,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2960,7 +2960,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2974,7 +2974,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2988,7 +2988,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3002,7 +3002,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3016,7 +3016,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3030,7 +3030,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3044,7 +3044,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3058,7 +3058,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3072,7 +3072,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3086,7 +3086,7 @@ static const GOBGameDescription gameDescriptions[] = { PL_POL, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -4299,7 +4299,7 @@ static const GOBGameDescription fallbackDescs[] = { GUIO_NONE }, kGameTypeUrban, - kFeatures640 | kFeaturesSCNDemo, + kFeaturesAdlib | kFeatures640 | kFeaturesSCNDemo, "", "", 8 } }; diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index fb3cb9bbcd..46f75f67aa 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -303,6 +303,8 @@ void Draw::dirtiedRect(SurfaceDescPtr surface, invalidateRect(left, top, right, bottom); else if (surface == _frontSurface) _vm->_video->dirtyRectsAdd(left, top, right, bottom); + else if (_vm->_video->_splitSurf && (surface == _vm->_video->_splitSurf)) + _vm->_video->retrace(); } void Draw::initSpriteSurf(int16 index, int16 width, int16 height, diff --git a/engines/gob/draw.h b/engines/gob/draw.h index ba32df0c3e..1da6ba4b74 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -39,7 +39,7 @@ namespace Gob { #define RENDERFLAG_USEDELTAS 0x0010 #define RENDERFLAG_UNKNOWN 0x0080 #define RENDERFLAG_NOBLITINVALIDATED 0x0200 -#define RENDERFLAG_SKIPOPTIONALTEXT 0x0400 +#define RENDERFLAG_NOSUBTITLES 0x0400 #define RENDERFLAG_FROMSPLIT 0x0800 #define RENDERFLAG_DOUBLECOORDS 0x1000 @@ -77,6 +77,9 @@ public: int16 _backDeltaX; int16 _backDeltaY; + int16 _subtitleFont; + int16 _subtitleColor; + FontToSprite _fontToSprite[4]; Font *_fonts[kFontCount]; diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index e2cfcb613d..719945fd6f 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -318,6 +318,8 @@ void Draw_v1::spriteOperation(int16 operation) { int16 perLine; Resource *resource; + operation &= 0x0F; + if (_sourceSurface >= 100) _sourceSurface -= 80; if (_destSurface >= 100) diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 8fe70589a7..a1074d7ecb 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -216,7 +216,9 @@ void Draw_v2::printTotText(int16 id) { dataPtr = textItem->getData(); ptr = dataPtr; - if ((_renderFlags & RENDERFLAG_SKIPOPTIONALTEXT) && (ptr[1] & 0x80)) { + bool isSubtitle = (ptr[1] & 0x80) != 0; + + if (isSubtitle && !_vm->_global->_doSubtitles) { delete textItem; return; } @@ -398,10 +400,15 @@ void Draw_v2::printTotText(int16 id) { } else { _destSpriteX = offX; _destSpriteY = offY; - _fontIndex = fontIndex; - _frontColor = frontColor; + _fontIndex = fontIndex; + _frontColor = frontColor; _textToPrint = str; + if (isSubtitle) { + _fontIndex = _subtitleFont; + _frontColor = _subtitleColor; + } + if (_needAdjust != 2) { if ((_destSpriteX >= destX) && (_destSpriteY >= destY) && (((_fonts[_fontIndex]->getCharHeight() / 2) + _destSpriteY - 1) <= spriteBottom)) { @@ -449,6 +456,10 @@ void Draw_v2::printTotText(int16 id) { ptr++; offX = destX + (int16)READ_LE_UINT16(ptr); offY = destY + (int16)READ_LE_UINT16(ptr + 2); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { + offX += (int16)READ_LE_UINT16(ptr); + offY += (int16)READ_LE_UINT16(ptr + 2); + } ptr += 4; break; @@ -457,11 +468,19 @@ void Draw_v2::printTotText(int16 id) { fontIndex = ((*ptr & 0xF0) >> 4) & 7; frontColor = *ptr & 0x0F; ptr++; + + if (isSubtitle) { + _subtitleFont = fontIndex; + _subtitleColor = frontColor; + } break; case 4: ptr++; frontColor = *ptr++; + + if (isSubtitle) + _subtitleColor = frontColor; break; case 6: @@ -502,8 +521,7 @@ void Draw_v2::printTotText(int16 id) { case 10: str[0] = (char) 255; - WRITE_LE_UINT16((uint16 *) (str + 1), - ptr - _vm->_game->_resources->getTexts()); + WRITE_LE_UINT16(str + 1, ptr - _vm->_game->_resources->getTexts()); str[3] = 0; ptr++; for (int i = *ptr++; i > 0; i--) { diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index d201019d08..4e2bd223b7 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -275,6 +275,12 @@ void Game::playTot(int16 skipPlay) { _vm->_draw->_fontToSprite[i].height = -1; } + // Gobliiins music stopping + if (_vm->getGameType() == kGameTypeGob1) { + _vm->_sound->adlibStop(); + _vm->_sound->cdStop(); + } + _vm->_mult->initAll(); _vm->_mult->zeroMultData(); diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index 2969ed0870..f4f1303386 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -124,6 +124,8 @@ Global::Global(GobEngine *vm) : _vm(vm) { _speedFactor = 1; + _doSubtitles = false; + _noCd = false; } diff --git a/engines/gob/global.h b/engines/gob/global.h index 7849490107..5830e3e58c 100644 --- a/engines/gob/global.h +++ b/engines/gob/global.h @@ -141,6 +141,8 @@ public: // Can be 1, 2 or 3 for normal, double and triple speed, respectively uint8 _speedFactor; + bool _doSubtitles; + bool _noCd; Global(GobEngine *vm); diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index fa4f04eab8..082345e675 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -25,6 +25,7 @@ #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "base/plugins.h" #include "common/config-manager.h" @@ -129,7 +130,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { Common::addDebugChannel(kDebugHotspots, "Hotspots", "Hotspots debug level"); Common::addDebugChannel(kDebugDemo, "Demo", "Demo script debug level"); - syst->getEventManager()->registerRandomSource(_rnd, "gob"); + g_eventRec.registerRandomSource(_rnd, "gob"); } GobEngine::~GobEngine() { @@ -302,7 +303,6 @@ void GobEngine::pauseEngineIntern(bool pause) { } else { uint32 duration = _system->getMillis() - _pauseStart; - _vidPlayer->notifyPaused(duration); _util->notifyPaused(duration); _game->_startTimeKey += duration; @@ -314,6 +314,12 @@ void GobEngine::pauseEngineIntern(bool pause) { _mixer->pauseAll(pause); } +void GobEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + _init->updateConfig(); +} + void GobEngine::pauseGame() { pauseEngineIntern(true); @@ -329,139 +335,138 @@ bool GobEngine::initGameParts() { _saveLoad = 0; - _global = new Global(this); - _util = new Util(this); - _dataIO = new DataIO(this); - _palAnim = new PalAnim(this); + _global = new Global(this); + _util = new Util(this); + _dataIO = new DataIO(this); + _palAnim = new PalAnim(this); _vidPlayer = new VideoPlayer(this); - _sound = new Sound(this); - _game = new Game(this); + _sound = new Sound(this); + _game = new Game(this); switch (_gameType) { case kGameTypeGeisha: case kGameTypeAdibouUnknown: case kGameTypeGob1: - _init = new Init_v1(this); - _video = new Video_v1(this); - _inter = new Inter_v1(this); - _mult = new Mult_v1(this); - _draw = new Draw_v1(this); - _map = new Map_v1(this); - _goblin = new Goblin_v1(this); - _scenery = new Scenery_v1(this); + _init = new Init_v1(this); + _video = new Video_v1(this); + _inter = new Inter_v1(this); + _mult = new Mult_v1(this); + _draw = new Draw_v1(this); + _map = new Map_v1(this); + _goblin = new Goblin_v1(this); + _scenery = new Scenery_v1(this); break; case kGameTypeFascination: - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_Fascination(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); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_Fascination(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_v2(this, _targetName.c_str()); break; case kGameTypeWeen: case kGameTypeGob2: - _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); + _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_v2(this, _targetName.c_str()); break; case kGameTypeBargon: - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_Bargon(this); - _mult = new Mult_v2(this); - _draw = new Draw_Bargon(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_Bargon(this); + _mult = new Mult_v2(this); + _draw = new Draw_Bargon(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; case kGameTypeGob3: case kGameTypeInca2: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v3(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v3(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeGob3); break; case kGameTypeLostInTime: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v3(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v3(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeLost); break; case kGameTypeWoodruff: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v4(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v4(this); + _video = new Video_v2(this); + _inter = new Inter_v4(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); break; case kGameTypeDynasty: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v5(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v5(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad(this); break; case kGameTypeAdibou4: case kGameTypeUrban: - _init = new Init_v6(this); - _video = new Video_v6(this); - _inter = new Inter_v6(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v6(this); + _video = new Video_v6(this); + _inter = new Inter_v6(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v6(this, _targetName.c_str()); break; case kGameTypePlaytoon: case kGameTypePlaytnCk: case kGameTypeBambou: - _init = new Init_v2(this); - _video = new Video_v2(this); -// _inter = new Inter_Playtoons(this); - _inter = new Inter_v6(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); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v6(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_Playtoons(this); break; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 02f6af51bf..84ff707877 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -75,8 +75,6 @@ class SaveLoad; #define GET_VAR_FSTR(var) _vm->_inter->_variables->getAddressVarString(var) #define GET_VARO_FSTR(off) _vm->_inter->_variables->getAddressOffString(off) -#define VAR_ADDRESS(var) _vm->_inter->_variables->getAddressVar32(var) - #define WRITE_VAR_OFFSET(off, val) WRITE_VARO_UINT32((off), (val)) #define WRITE_VAR(var, val) WRITE_VAR_UINT32((var), (val)) #define VAR_OFFSET(off) READ_VARO_UINT32(off) @@ -165,6 +163,7 @@ private: virtual Common::Error run(); virtual bool hasFeature(EngineFeature f) const; virtual void pauseEngineIntern(bool pause); + virtual void syncSoundSettings(); bool initGameParts(); void deinitGameParts(); diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index faf85a5b41..834e9b8553 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -49,6 +49,9 @@ Init::Init(GobEngine *vm) : _vm(vm) { _palDesc = 0; } +Init::~Init() { +} + void Init::cleanup() { _vm->_video->freeDriver(); _vm->_global->_primarySurfDesc.reset(); @@ -87,6 +90,7 @@ void Init::initGame() { char buffer[128]; initVideo(); + updateConfig(); if (!_vm->isDemo()) { if (_vm->_dataIO->existData(_vm->_startStk.c_str())) @@ -206,4 +210,7 @@ void Init::initGame() { cleanup(); } +void Init::updateConfig() { +} + } // End of namespace Gob diff --git a/engines/gob/init.h b/engines/gob/init.h index 60642d0189..c2784a59ac 100644 --- a/engines/gob/init.h +++ b/engines/gob/init.h @@ -32,12 +32,14 @@ namespace Gob { class Init { public: + Init(GobEngine *vm); + virtual ~Init(); + virtual void initGame(); virtual void initVideo() = 0; - Init(GobEngine *vm); - virtual ~Init() {} + virtual void updateConfig(); protected: Video::PalDesc *_palDesc; @@ -50,34 +52,42 @@ protected: class Init_v1 : public Init { public: - virtual void initVideo(); - Init_v1(GobEngine *vm); - virtual ~Init_v1() {} + ~Init_v1(); + + void initVideo(); }; class Init_v2 : public Init_v1 { public: - virtual void initVideo(); - Init_v2(GobEngine *vm); - virtual ~Init_v2() {} + ~Init_v2(); + + void initVideo(); }; class Init_v3 : public Init_v2 { public: - virtual void initVideo(); - Init_v3(GobEngine *vm); - virtual ~Init_v3() {} + ~Init_v3(); + + void initVideo(); }; -class Init_v6 : public Init_v3 { +class Init_v4 : public Init_v3 { public: - virtual void initGame(); + Init_v4(GobEngine *vm); + ~Init_v4(); + + void updateConfig(); +}; +class Init_v6 : public Init_v3 { +public: Init_v6(GobEngine *vm); - virtual ~Init_v6() {} + ~Init_v6(); + + void initGame(); }; } // End of namespace Gob diff --git a/engines/gob/init_v1.cpp b/engines/gob/init_v1.cpp index e482104ff9..50db774734 100644 --- a/engines/gob/init_v1.cpp +++ b/engines/gob/init_v1.cpp @@ -35,6 +35,9 @@ namespace Gob { Init_v1::Init_v1(GobEngine *vm) : Init(vm) { } +Init_v1::~Init_v1() { +} + void Init_v1::initVideo() { if (_vm->_global->_videoMode) _vm->validateVideoMode(_vm->_global->_videoMode); diff --git a/engines/gob/init_v2.cpp b/engines/gob/init_v2.cpp index 4c65b8102c..f89d5a8cfb 100644 --- a/engines/gob/init_v2.cpp +++ b/engines/gob/init_v2.cpp @@ -36,6 +36,9 @@ namespace Gob { Init_v2::Init_v2(GobEngine *vm) : Init_v1(vm) { } +Init_v2::~Init_v2() { +} + void Init_v2::initVideo() { if (_vm->_global->_videoMode) _vm->validateVideoMode(_vm->_global->_videoMode); diff --git a/engines/gob/init_v3.cpp b/engines/gob/init_v3.cpp index 67304b389a..c96005ed5a 100644 --- a/engines/gob/init_v3.cpp +++ b/engines/gob/init_v3.cpp @@ -34,6 +34,9 @@ namespace Gob { Init_v3::Init_v3(GobEngine *vm) : Init_v2(vm) { } +Init_v3::~Init_v3() { +} + void Init_v3::initVideo() { Init_v2::initVideo(); diff --git a/engines/gob/init_v4.cpp b/engines/gob/init_v4.cpp new file mode 100644 index 0000000000..3bd50a494d --- /dev/null +++ b/engines/gob/init_v4.cpp @@ -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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/config-manager.h" + +#include "gob/gob.h" +#include "gob/init.h" +#include "gob/global.h" + +namespace Gob { + +Init_v4::Init_v4(GobEngine *vm) : Init_v3(vm) { +} + +Init_v4::~Init_v4() { +} + +void Init_v4::updateConfig() { + _vm->_global->_doSubtitles = ConfMan.getBool("subtitles"); +} + +} // End of namespace Gob diff --git a/engines/gob/init_v6.cpp b/engines/gob/init_v6.cpp index 4b14c8a29c..40b4769e78 100644 --- a/engines/gob/init_v6.cpp +++ b/engines/gob/init_v6.cpp @@ -34,6 +34,9 @@ namespace Gob { Init_v6::Init_v6(GobEngine *vm) : Init_v3(vm) { } +Init_v6::~Init_v6() { +} + void Init_v6::initGame() { _vm->_global->_noCd = false; diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 69c392b198..446d86643d 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -972,6 +972,7 @@ bool Inter_v1::o1_loadTot(OpFuncParams ¶ms) { bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { int index1, index2; + int16 id; byte cmd; Resource *resource; @@ -1116,7 +1117,8 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { case 61: index1 = _vm->_game->_script->readByte(); index2 = (_vm->_game->_script->readByte() - index1 + 1) * 3; - resource = _vm->_game->_resources->getResource(_vm->_game->_script->readInt16()); + id = _vm->_game->_script->readInt16(); + resource = _vm->_game->_resources->getResource(id); if (!resource) break; @@ -1124,6 +1126,13 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { resource->getData() + index1 * 3, index2); delete resource; + // WORKAROUND: The Last Dynasty overwrites the 0. palette entry but depends on it staying black. + if ((_vm->getGameType() == kGameTypeDynasty) && (index1 == 0)) { + _vm->_draw->_vgaPalette[0].red = 0; + _vm->_draw->_vgaPalette[0].green = 0; + _vm->_draw->_vgaPalette[0].blue = 0; + } + if (_vm->_draw->_applyPal) { _vm->_draw->_applyPal = false; _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); @@ -2303,7 +2312,7 @@ void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { void Inter_v1::o1_loadObjects(OpGobParams ¶ms) { params.extraData = _vm->_game->_script->readInt16(); - _vm->_goblin->loadObjects((char *) VAR_ADDRESS(params.extraData)); + _vm->_goblin->loadObjects(_variables->getAddressVarString(params.extraData)); } void Inter_v1::o1_freeObjects(OpGobParams ¶ms) { diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 20f812bb88..19cac86465 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -25,6 +25,8 @@ #include "common/endian.h" +#include "gui/message.h" + #include "sound/mixer.h" #include "sound/mods/infogrames.h" @@ -587,6 +589,11 @@ void Inter_v2::o2_totSub() { if (!scumm_stricmp(totFile, "edit")) _vm->_util->forceMouseUp(); + // WORKAROUND: For some reason, the variable indicating which TOT to load next + // is overwritten in the guard house card game in Woodruff + if ((_vm->getGameType() == kGameTypeWoodruff) && !scumm_stricmp(totFile, "6")) + strcpy(totFile, "EMAP2011"); + flags = _vm->_game->_script->readByte(); _vm->_game->totSub(flags, totFile); } @@ -1297,16 +1304,23 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { size = -1; handle = 1; - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + char *file = _vm->_game->_script->getResultStr(); + + // WORKAROUND: For some reason, the variable indicating which TOT to load next + // is overwritten in the guard house card game in Woodruff + if ((_vm->getGameType() == kGameTypeWoodruff) && !scumm_stricmp(file, "6.TOT")) + strcpy(file, "EMAP2011.TOT"); + + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeNone) { - if (_vm->_dataIO->existData(_vm->_game->_script->getResultStr())) - size = _vm->_dataIO->getDataSize(_vm->_game->_script->getResultStr()); + if (_vm->_dataIO->existData(file)) + size = _vm->_dataIO->getDataSize(file); else - warning("File \"%s\" not found", _vm->_game->_script->getResultStr()); + warning("File \"%s\" not found", file); } else if (mode == SaveLoad::kSaveModeSave) - size = _vm->_saveLoad->getSize(_vm->_game->_script->getResultStr()); + size = _vm->_saveLoad->getSize(file); else if (mode == SaveLoad::kSaveModeExists) size = 23; @@ -1314,7 +1328,7 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { handle = -1; debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d", - _vm->_game->_script->getResultStr(), size); + file, size); WRITE_VAR_OFFSET(varOff, handle); WRITE_VAR(16, (uint32) size); @@ -1338,21 +1352,32 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { offset = _vm->_game->_script->getResultInt(); retSize = 0; + char *file = _vm->_game->_script->getResultStr(); + debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)", - _vm->_game->_script->getResultStr(), dataVar, size, offset); + file, dataVar, size, offset); - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeSave) { + WRITE_VAR(1, 1); - if (_vm->_saveLoad->load(_vm->_game->_script->getResultStr(), dataVar, size, offset)) + + if (!_vm->_saveLoad->load(file, dataVar, size, offset)) { + + GUI::MessageDialog dialog("Failed to load game state from file."); + dialog.runModal(); + + } else WRITE_VAR(1, 0); + return false; + } else if (mode == SaveLoad::kSaveModeIgnore) return false; if (size < 0) { warning("Attempted to read a raw sprite from file \"%s\"", - _vm->_game->_script->getResultStr()); + file); return false ; } else if (size == 0) { dataVar = 0; @@ -1361,13 +1386,13 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { buf = _variables->getAddressOff8(dataVar); - if (_vm->_game->_script->getResultStr()[0] == 0) { + if (file[0] == 0) { WRITE_VAR(1, size); return false; } WRITE_VAR(1, 1); - handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr()); + handle = _vm->_dataIO->openData(file); if (handle < 0) return false; @@ -1408,17 +1433,26 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { _vm->_game->_script->evalExpr(0); offset = _vm->_game->_script->getResultInt(); + char *file = _vm->_game->_script->getResultStr(); + debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)", - _vm->_game->_script->getResultStr(), dataVar, size, offset); + file, dataVar, size, offset); WRITE_VAR(1, 1); - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeSave) { - if (_vm->_saveLoad->save(_vm->_game->_script->getResultStr(), dataVar, size, offset)) + + if (!_vm->_saveLoad->save(file, dataVar, size, offset)) { + + GUI::MessageDialog dialog("Failed to save game state to file."); + dialog.runModal(); + + } else WRITE_VAR(1, 0); + } else if (mode == SaveLoad::kSaveModeNone) - warning("Attempted to write to file \"%s\"", _vm->_game->_script->getResultStr()); + warning("Attempted to write to file \"%s\"", file); return false; } diff --git a/engines/gob/map.h b/engines/gob/map.h index 4a211f205d..ba976ff7ac 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -204,14 +204,6 @@ protected: void loadGoblinStates(Common::SeekableReadStream &data, int index); }; -class Map_v4 : public Map_v2 { -public: - virtual void loadMapObjects(const char *avjFile); - - Map_v4(GobEngine *vm); - virtual ~Map_v4(); -}; - } // End of namespace Gob #endif // GOB_MAP_H diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index 6ceda7ab44..51caad74b8 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -60,7 +60,10 @@ void Map_v2::loadMapObjects(const char *avjFile) { id = _vm->_game->_script->readInt16(); - if (id == -1) { + if (((uint16) id) >= 65520) { + warning("Map_v2::loadMapObjects(): ID >= 65520"); + return; + } else if (id == -1) { _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); return; } @@ -71,13 +74,20 @@ void Map_v2::loadMapObjects(const char *avjFile) { Common::SeekableReadStream &mapData = *resource->stream(); - if (mapData.readByte() == 3) { + _widthByte = mapData.readByte(); + if (_widthByte == 4) { _screenWidth = 640; + _screenHeight = 400; + } else if (_widthByte == 3) { _passWidth = 65; + _screenWidth = 640; + _screenHeight = 200; } else { - _screenWidth = 320; _passWidth = 40; + _screenWidth = 320; + _screenHeight = 200; } + _wayPointsCount = mapData.readByte(); _tilesWidth = mapData.readSint16LE(); _tilesHeight = mapData.readSint16LE(); @@ -85,6 +95,11 @@ void Map_v2::loadMapObjects(const char *avjFile) { _bigTiles = !(_tilesHeight & 0xFF00); _tilesHeight &= 0xFF; + if (_widthByte == 4) { + _screenWidth = mapData.readSint16LE(); + _screenHeight = mapData.readSint16LE(); + } + _mapWidth = _screenWidth / _tilesWidth; _mapHeight = _screenHeight / _tilesHeight; @@ -104,6 +119,11 @@ void Map_v2::loadMapObjects(const char *avjFile) { _wayPoints[i].notWalkable = mapData.readSByte(); } + if (_widthByte == 4) { + _mapWidth = VAR(17); + _passWidth = _mapWidth; + } + // In the original asm, this writes byte-wise into the variables-array tmpPos = mapData.pos(); mapData.seek(passPos); diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp deleted file mode 100644 index 1db3d6a3f8..0000000000 --- a/engines/gob/map_v4.cpp +++ /dev/null @@ -1,159 +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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stream.h" - -#include "gob/gob.h" -#include "gob/map.h" -#include "gob/global.h" -#include "gob/goblin.h" -#include "gob/inter.h" -#include "gob/game.h" -#include "gob/script.h" -#include "gob/resources.h" -#include "gob/mult.h" - -namespace Gob { - -Map_v4::Map_v4(GobEngine *vm) : Map_v2(vm) { -} - -Map_v4::~Map_v4() { -} - -void Map_v4::loadMapObjects(const char *avjFile) { - uint8 wayPointsCount; - int16 var; - int16 id; - int16 mapWidth, mapHeight; - int16 tmp; - byte *variables; - uint32 tmpPos; - uint32 passPos; - - var = _vm->_game->_script->readVarIndex(); - variables = _vm->_inter->_variables->getAddressOff8(var); - - id = _vm->_game->_script->readInt16(); - - if (((uint16) id) >= 65520) { - warning("Woodruff Stub: loadMapObjects ID >= 65520"); - return; - } else if (id == -1) { - _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); - return; - } - - Resource *resource = _vm->_game->_resources->getResource(id); - if (!resource) - return; - - Common::SeekableReadStream &mapData = *resource->stream(); - - _widthByte = mapData.readByte(); - if (_widthByte == 4) { - _screenWidth = 640; - _screenHeight = 400; - } else if (_widthByte == 3) { - _screenWidth = 640; - _screenHeight = 200; - } else { - _screenWidth = 320; - _screenHeight = 200; - } - - _wayPointsCount = mapData.readByte(); - _tilesWidth = mapData.readSint16LE(); - _tilesHeight = mapData.readSint16LE(); - - _bigTiles = !(_tilesHeight & 0xFF00); - _tilesHeight &= 0xFF; - - if (_widthByte == 4) { - _screenWidth = mapData.readSint16LE(); - _screenHeight = mapData.readSint16LE(); - } - - _mapWidth = _screenWidth / _tilesWidth; - _mapHeight = _screenHeight / _tilesHeight; - - passPos = mapData.pos(); - mapData.skip(_mapWidth * _mapHeight); - - if (resource->getData()[0] == 1) - wayPointsCount = _wayPointsCount = 40; - else - wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; - - delete[] _wayPoints; - _wayPoints = new Point[wayPointsCount]; - for (int i = 0; i < _wayPointsCount; i++) { - _wayPoints[i].x = mapData.readSByte(); - _wayPoints[i].y = mapData.readSByte(); - _wayPoints[i].notWalkable = mapData.readSByte(); - } - - if (_widthByte == 4) - _mapWidth = VAR(17); - - _passWidth = _mapWidth; - - // In the original asm, this writes byte-wise into the variables-array - tmpPos = mapData.pos(); - mapData.seek(passPos); - if ((variables != 0) && - (variables != _vm->_inter->_variables->getAddressOff8(0))) { - - _passMap = (int8 *) variables; - mapHeight = _screenHeight / _tilesHeight; - mapWidth = _screenWidth / _tilesWidth; - - for (int i = 0; i < mapHeight; i++) { - for (int j = 0; j < mapWidth; j++) - setPass(j, i, mapData.readSByte()); - _vm->_inter->_variables->getAddressOff8(var + i * _passWidth); - } - } - mapData.seek(tmpPos); - - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14); - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14 + 28); - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14); - - _vm->_goblin->_gobsCount = tmp; - for (int i = 0; i < _vm->_goblin->_gobsCount; i++) - loadGoblinStates(mapData, i); - - _vm->_goblin->_soundSlotsCount = _vm->_game->_script->readInt16(); - for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) - _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); - - delete resource; -} - -} // End of namespace Gob diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 611abb6038..26cc4e5d27 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -23,6 +23,7 @@ MODULE_OBJS := \ init_v1.o \ init_v2.o \ init_v3.o \ + init_v4.o \ init_v6.o \ inter.o \ inter_v1.o \ @@ -36,7 +37,6 @@ MODULE_OBJS := \ map.o \ map_v1.o \ map_v2.o \ - map_v4.o \ mult.o \ mult_v1.o \ mult_v2.o \ diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp index c52b65f0d7..2f3b1b23e7 100644 --- a/engines/gob/resources.cpp +++ b/engines/gob/resources.cpp @@ -144,8 +144,6 @@ Resources::~Resources() { bool Resources::load(const Common::String &fileName) { unload(); - Common::String fileBase; - _totFile = TOTFile::createFileName(fileName, _hasLOM); if (_hasLOM) { @@ -154,9 +152,9 @@ bool Resources::load(const Common::String &fileName) { return false; } - fileBase = TOTFile::getFileBase(fileName); + _fileBase = TOTFile::getFileBase(fileName); - _extFile = fileBase + ".ext"; + _extFile = _fileBase + ".ext"; bool hasTOTRes = loadTOTResourceTable(); bool hasEXTRes = loadEXTResourceTable(); @@ -165,7 +163,7 @@ bool Resources::load(const Common::String &fileName) { return false; if (hasTOTRes) { - if (!loadTOTTextTable(fileBase)) { + if (!loadTOTTextTable(_fileBase)) { unload(); return false; } @@ -195,6 +193,7 @@ void Resources::unload(bool del) { delete[] _totData; delete[] _imData; + _fileBase.clear(); _totFile.clear(); _extFile.clear(); _exFile.clear(); @@ -573,6 +572,41 @@ byte *Resources::getTexts() const { return _totTextTable->data; } +bool Resources::dumpResource(const Resource &resource, + const Common::String &fileName) const { + + Common::DumpFile dump; + + if (!dump.open(fileName)) + return false; + + if (dump.write(resource.getData(), resource.getSize()) != ((uint32) resource.getSize())) + return false; + + if (!dump.flush()) + return false; + if (dump.err()) + return false; + + dump.close(); + return true; +} + +bool Resources::dumpResource(const Resource &resource, uint16 id, + const Common::String &ext) const { + + Common::String fileName = _fileBase; + + char idStr[7]; + + snprintf(idStr, 7, "_%05d", id); + fileName += idStr; + fileName += "."; + fileName += ext; + + return dumpResource(resource, fileName); +} + Resource *Resources::getTOTResource(uint16 id) const { if (id >= _totResourceTable->itemsCount) { warning("Trying to load non-existent TOT resource (%s, %d/%d)", diff --git a/engines/gob/resources.h b/engines/gob/resources.h index d316be83e5..7511185954 100644 --- a/engines/gob/resources.h +++ b/engines/gob/resources.h @@ -91,6 +91,11 @@ public: byte *getTexts() const; + bool dumpResource(const Resource &resource, + const Common::String &fileName) const; + bool dumpResource(const Resource &resource, uint16 id, + const Common::String &ext = "dmp") const; + private: // Structure sizes in the files static const int kTOTResItemSize = 4 + 2 + 2 + 2; @@ -166,6 +171,7 @@ private: GobEngine *_vm; + Common::String _fileBase; Common::String _totFile; Common::String _extFile; Common::String _exFile; diff --git a/engines/gob/save/saveconverter.cpp b/engines/gob/save/saveconverter.cpp index 38fec06859..7bfb2a2da2 100644 --- a/engines/gob/save/saveconverter.cpp +++ b/engines/gob/save/saveconverter.cpp @@ -122,14 +122,14 @@ bool SaveConverter::swapDataEndian(byte *data, const byte *sizes, uint32 count) while (count-- > 0) { if (*sizes == 3) // 32bit value (3 additional bytes) - *((uint32 *) data) = SWAP_BYTES_32(*((uint32 *) data)); + WRITE_UINT32(data, SWAP_BYTES_32(READ_UINT32(data))); else if (*sizes == 1) // 16bit value (1 additional byte) - *((uint16 *) data) = SWAP_BYTES_16(*((uint16 *) data)); + WRITE_UINT16(data, SWAP_BYTES_16(READ_UINT16(data))); else if (*sizes != 0) // else, it has to be an 8bit value return false; count -= *sizes; - data += *sizes + 1; + data += *sizes + 1; sizes += *sizes + 1; } diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h index 8d785c7233..1a1a47178b 100644 --- a/engines/gob/save/saveload.h +++ b/engines/gob/save/saveload.h @@ -74,15 +74,15 @@ protected: /** Save/Load class for Gobliins 2, Ween: The Prophecy and Bargon Attack. */ class SaveLoad_v2 : public SaveLoad { public: + static const uint32 kSlotCount = 15; + static const uint32 kSlotNameLength = 40; + SaveLoad_v2(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v2(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 15; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -136,6 +136,9 @@ protected: /** Save/Load class for Goblins 3 and Lost in Time. */ class SaveLoad_v3 : public SaveLoad { public: + static const uint32 kSlotCount = 30; + static const uint32 kSlotNameLength = 40; + enum ScreenshotType { kScreenshotTypeGob3, //!< Goblins 3 type screenshot kScreenshotTypeLost //!< Lost in Time type screenshot @@ -147,9 +150,6 @@ public: SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 30; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -264,15 +264,15 @@ protected: /** Save/Load class for Woodruff. */ class SaveLoad_v4 : public SaveLoad { public: + static const uint32 kSlotCount = 10; + static const uint32 kSlotNameLength = 40; + SaveLoad_v4(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v4(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 10; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -289,6 +289,8 @@ protected: GameHandler(GobEngine *vm, const char *target); ~GameHandler(); + int getLastSlot() const; + int32 getSize(); bool load(int16 dataVar, int32 size, int32 offset); bool save(int16 dataVar, int32 size, int32 offset); @@ -317,6 +319,8 @@ protected: File *_slotFile; + int _lastSlot; + SaveReader *_reader; SaveWriter *_writer; @@ -386,15 +390,15 @@ protected: /** Save/Load class for Urban Runner. */ class SaveLoad_v6 : public SaveLoad { public: + static const uint32 kSlotCount = 60; + static const uint32 kSlotNameLength = 40; + SaveLoad_v6(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v6(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 60; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; diff --git a/engines/gob/save/saveload_v4.cpp b/engines/gob/save/saveload_v4.cpp index 06280af2a6..16c87b9a64 100644 --- a/engines/gob/save/saveload_v4.cpp +++ b/engines/gob/save/saveload_v4.cpp @@ -84,6 +84,8 @@ SaveLoad_v4::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveH _slotFile = new File(vm, target); + _lastSlot = -1; + _writer = 0; _reader = 0; } @@ -94,6 +96,10 @@ SaveLoad_v4::GameHandler::~GameHandler() { delete _writer; } +int SaveLoad_v4::GameHandler::getLastSlot() const { + return _lastSlot; +} + int32 SaveLoad_v4::GameHandler::getSize() { // Fake an empty save file for the very first query, to get clear properties if (_firstSize) { @@ -178,6 +184,7 @@ bool SaveLoad_v4::GameHandler::load(int16 dataVar, int32 size, int32 offset) { if (!vars.writeInto(0, 0, varSize)) return false; + _lastSlot = slot; } return true; @@ -261,6 +268,7 @@ bool SaveLoad_v4::GameHandler::save(int16 dataVar, int32 size, int32 offset) { if (!_writer->writePart(1, &vars)) return false; + _lastSlot = slot; } return true; @@ -465,7 +473,11 @@ bool SaveLoad_v4::ScreenPropsHandler::load(int16 dataVar, int32 size, int32 offs return false; } - return _gameHandler->loadScreenProps(_file->getSlot(offset), _curProps->_props); + int slot = _gameHandler->getLastSlot(); + if (slot == -1) + slot = _file->getSlot(offset); + + return _gameHandler->loadScreenProps(slot, _curProps->_props); } bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offset) { @@ -474,7 +486,11 @@ bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offs return false; } - return _gameHandler->saveScreenProps(_file->getSlot(offset), _curProps->_props); + int slot = _gameHandler->getLastSlot(); + if (slot == -1) + slot = _file->getSlot(offset); + + return _gameHandler->saveScreenProps(slot, _curProps->_props); } diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 7a4b8ad868..a6d6c06544 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -95,7 +95,7 @@ void Scenery::init() { int16 Scenery::loadStatic(char search) { int16 size; - int16 *backsPtr; + byte *backsPtr; int16 picsCount; int16 resId; int16 sceneryIndex; @@ -108,7 +108,7 @@ int16 Scenery::loadStatic(char search) { _vm->_game->_script->evalExpr(&sceneryIndex); size = _vm->_game->_script->readInt16(); - backsPtr = (int16 *) (_vm->_game->_script->getData() + _vm->_game->_script->pos()); + backsPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); _vm->_game->_script->skip(size * 2); picsCount = _vm->_game->_script->readInt16(); resId = _vm->_game->_script->readInt16(); @@ -162,7 +162,7 @@ int16 Scenery::loadStatic(char search) { ptr->layers[i].planes = 0; ptr->layers[i].backResId = (int16) READ_LE_UINT16(backsPtr); - backsPtr++; + backsPtr += 2; } ptr->pieces = new PieceDesc*[picsCount]; @@ -185,7 +185,7 @@ int16 Scenery::loadStatic(char search) { _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex]++; } else { - for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--); + for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--) { } _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex] = 1; @@ -632,6 +632,11 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); } + // Subtitle + Graphics::CoktelVideo::State state = _vm->_vidPlayer->getState(obj.videoSlot - 1); + if (state.flags & Graphics::CoktelVideo::kStateSpeech) + _vm->_draw->printTotText(state.speechId); + destX = 0; destY = 0; left = *(obj.pPosX); diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp index 38b1f8fa40..0475bb06f7 100644 --- a/engines/gob/script.cpp +++ b/engines/gob/script.cpp @@ -201,7 +201,7 @@ int32 Script::readInt32() { char *Script::readString(int32 length) { if (length < 0) { length = 0; - while (_totPtr[length++] != '\0'); + while (_totPtr[length++] != '\0') { } } char *string = (char *) _totPtr; diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp index 6ce184155e..f0977aa45b 100644 --- a/engines/gob/sound/bgatmosphere.cpp +++ b/engines/gob/sound/bgatmosphere.cpp @@ -25,6 +25,7 @@ #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "gob/sound/bgatmosphere.h" #include "gob/sound/sounddesc.h" @@ -39,7 +40,7 @@ BackgroundAtmosphere::BackgroundAtmosphere(Audio::Mixer &mixer) : _shaded = false; _shadable = true; - g_system->getEventManager()->registerRandomSource(_rnd, "gobBA"); + g_eventRec.registerRandomSource(_rnd, "gobBA"); } BackgroundAtmosphere::~BackgroundAtmosphere() { diff --git a/engines/gob/sound/sounddesc.cpp b/engines/gob/sound/sounddesc.cpp index b9b327d105..e8045d21f7 100644 --- a/engines/gob/sound/sounddesc.cpp +++ b/engines/gob/sound/sounddesc.cpp @@ -121,9 +121,9 @@ void SoundDesc::convToSigned() { return; if (_mixerFlags & Audio::Mixer::FLAG_16BITS) { - uint16 *data = (uint16 *) _dataPtr; - for (uint32 i = 0; i < _size; i++) - data[i] ^= 0x8000; + byte *data = _dataPtr; + for (uint32 i = 0; i < _size; i++, data += 2) + WRITE_LE_UINT16(data, READ_LE_UINT16(data) ^ 0x8000); } else for (uint32 i = 0; i < _size; i++) _dataPtr[i] ^= 0x80; diff --git a/engines/gob/sound/soundmixer.cpp b/engines/gob/sound/soundmixer.cpp index 68a96d3b01..eb6d7882f0 100644 --- a/engines/gob/sound/soundmixer.cpp +++ b/engines/gob/sound/soundmixer.cpp @@ -33,8 +33,7 @@ SoundMixer::SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type) : _mix _rate = _mixer->getOutputRate(); _end = true; - _data8 = 0; - _data16 = 0; + _data = 0; _length = 0; _freq = 0; _repCount = 0; @@ -61,9 +60,9 @@ SoundMixer::~SoundMixer() { inline int16 SoundMixer::getData(int offset) { if (!_16bit) - return (int16) _data8[offset]; + return (int16) ((int8) _data[offset]); else - return (int16) FROM_LE_16(_data16[offset]); + return (int16) READ_LE_UINT16(_data + (offset * 2)); } bool SoundMixer::isPlaying() const { @@ -78,8 +77,7 @@ void SoundMixer::stop(int16 fadeLength) { Common::StackLock slock(_mutex); if (fadeLength <= 0) { - _data8 = 0; - _data16 = 0; + _data = 0; _end = true; _playingSound = 0; return; @@ -109,13 +107,7 @@ void SoundMixer::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, _16bit = (sndDesc._mixerFlags & Audio::Mixer::FLAG_16BITS) != 0; - if (_16bit) { - _data16 = (int16 *) sndDesc.getData(); - _shift = 0; - } else { - _data8 = (int8 *) sndDesc.getData(); - _shift = 8; - } + _data = sndDesc.getData(); _length = sndDesc.size(); _freq = frequency; @@ -171,7 +163,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); for (int i = 0; i < numSamples; i++) { - if (!_data8 && !_data16) + if (!_data) return i; if (_end || (_offset >= _length)) checkEndSample(); @@ -181,7 +173,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { // Linear interpolation. See sound/rate.cpp int16 val = (_last + (((_cur - _last) * _offsetFrac + - FRAC_HALF) >> FRAC_BITS)) << _shift; + FRAC_HALF) >> FRAC_BITS)) << (_16bit ? 0 : 8); *buffer++ = (val * _fadeVol) >> 16; _offsetFrac += _offsetInc; @@ -211,8 +203,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { void SoundMixer::endFade() { if (_fadeVolStep > 0) { - _data8 = 0; - _data16 = 0; + _data = 0; _end = true; _playingSound = 0; } else { diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h index 20376b5152..9e66c474e9 100644 --- a/engines/gob/sound/soundmixer.h +++ b/engines/gob/sound/soundmixer.h @@ -62,11 +62,9 @@ protected: Common::Mutex _mutex; bool _16bit; - int _shift; bool _end; - int8 *_data8; - int16 *_data16; + byte *_data; uint32 _length; uint32 _rate; int32 _freq; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 356eb3c643..1a8668b1c2 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -45,7 +45,6 @@ Util::Util(GobEngine *vm) : _vm(vm) { _frameRate = 12; _frameWaitTime = 0; _startFrameTime = 0; - _frameWaitLag = 0; } uint32 Util::getTimeKey(void) { @@ -331,12 +330,10 @@ void Util::setFrameRate(int16 rate) { _frameRate = rate; _frameWaitTime = 1000 / rate; _startFrameTime = getTimeKey(); - _frameWaitLag = 0; } void Util::notifyNewAnim() { _startFrameTime = getTimeKey(); - _frameWaitLag = 0; } void Util::waitEndFrame() { @@ -350,17 +347,12 @@ void Util::waitEndFrame() { return; } - int32 waitTime = _frameWaitTime - _frameWaitLag; - int32 toWait = waitTime - time; + int32 toWait = _frameWaitTime - time; if (toWait > 0) delay(toWait); - int32 now = getTimeKey(); - - _frameWaitLag = (now - _startFrameTime) - waitTime; - - _startFrameTime = now; + _startFrameTime = getTimeKey(); } void Util::setScrollOffset(int16 x, int16 y) { diff --git a/engines/gob/util.h b/engines/gob/util.h index 82e2df94de..ef972eb68c 100644 --- a/engines/gob/util.h +++ b/engines/gob/util.h @@ -145,7 +145,6 @@ protected: int16 _frameRate; int16 _frameWaitTime; uint32 _startFrameTime; - int32 _frameWaitLag; GobEngine *_vm; diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 1183ec21ae..572cba0796 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -123,22 +123,6 @@ uint8 *Variables::getAddressVar8(uint32 var) { return getAddressOff8(var * 4); } -const uint16 *Variables::getAddressVar16(uint32 var) const { - return getAddressOff16(var * 4); -} - -uint16 *Variables::getAddressVar16(uint32 var) { - return getAddressOff16(var * 4); -} - -const uint32 *Variables::getAddressVar32(uint32 var) const { - return getAddressOff32(var * 4); -} - -uint32 *Variables::getAddressVar32(uint32 var) { - return getAddressOff32(var * 4); -} - const char *Variables::getAddressVarString(uint32 var) const { return getAddressOffString(var * 4); } @@ -155,22 +139,6 @@ uint8 *Variables::getAddressOff8(uint32 offset) { return ((uint8 *) (_vars + offset)); } -const uint16 *Variables::getAddressOff16(uint32 offset) const { - return ((const uint16 *) (_vars + offset)); -} - -uint16 *Variables::getAddressOff16(uint32 offset) { - return ((uint16 *) (_vars + offset)); -} - -const uint32 *Variables::getAddressOff32(uint32 offset) const { - return ((const uint32 *) (_vars + offset)); -} - -uint32 *Variables::getAddressOff32(uint32 offset) { - return ((uint32 *) (_vars + offset)); -} - const char *Variables::getAddressOffString(uint32 offset) const { return ((const char *) (_vars + offset)); } diff --git a/engines/gob/variables.h b/engines/gob/variables.h index 84a4772baa..d11b91ea16 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -69,24 +69,12 @@ public: const uint8 *getAddressVar8(uint32 var) const; uint8 *getAddressVar8(uint32 var); - const uint16 *getAddressVar16(uint32 var) const; - uint16 *getAddressVar16(uint32 var); - - const uint32 *getAddressVar32(uint32 var) const; - uint32 *getAddressVar32(uint32 var); - const char *getAddressVarString(uint32 var) const; char *getAddressVarString(uint32 var); const uint8 *getAddressOff8(uint32 offset) const; uint8 *getAddressOff8(uint32 offset); - const uint16 *getAddressOff16(uint32 offset) const; - uint16 *getAddressOff16(uint32 offset); - - const uint32 *getAddressOff32(uint32 offset) const; - uint32 *getAddressOff32(uint32 offset); - const char *getAddressOffString(uint32 offset) const; char *getAddressOffString(uint32 offset); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index da552d7202..a7399caa54 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -156,6 +156,7 @@ VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { _backSurf = false; _needBlit = false; _noCursorSwitch = false; + _woodruffCohCottWorkaround = false; } VideoPlayer::~VideoPlayer() { @@ -248,6 +249,14 @@ bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y, _noCursorSwitch = true; } + // WORKAROUND: In Woodruff, Coh Cott vanished in one video on her party. + // This is a bug in video, so we work around it. + _woodruffCohCottWorkaround = false; + if (_vm->getGameType() == kGameTypeWoodruff) { + if (!scumm_stricmp(fileName, "SQ32-03.VMD")) + _woodruffCohCottWorkaround = true; + } + _ownSurf = false; if (!(flags & kFlagNoVideo)) { @@ -316,6 +325,7 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, endFrame = lastFrame; palCmd &= 0x3F; + int16 realStartFrame = startFrame; if (video.getCurrentFrame() != startFrame) { if (!forceSeek && (video.getFeatures() & Graphics::CoktelVideo::kFeaturesSound)) startFrame = video.getCurrentFrame(); @@ -331,7 +341,9 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, bool canceled = false; while (startFrame <= lastFrame) { - if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) { + if (doPlay(startFrame, breakKey, + palCmd, palStart, palEnd, palFrame, endFrame, startFrame < realStartFrame)) { + canceled = true; break; } @@ -621,7 +633,7 @@ Common::MemoryReadStream *VideoPlayer::getExtraData(const char *fileName, int sl void VideoPlayer::playFrame(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame) { + int16 palFrame, int16 endFrame, bool noRetrace) { if (!_primaryVideo) return; @@ -657,6 +669,12 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, Graphics::CoktelVideo::State state = video.nextFrame(); WRITE_VAR(11, frame); + if (_woodruffCohCottWorkaround && (frame == 32)) { + // WORKAROUND: This frame mistakenly masks Coh Cott, making her vanish + // To prevent that, we'll never draw that part + state.left += 50; + } + if (_needBlit) _vm->_draw->forceBlit(true); @@ -688,9 +706,14 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, _vm->_draw->blitInvalidated(); } else _vm->_video->dirtyRectsAdd(state.left, state.top, state.right, state.bottom); - _vm->_video->retrace(); + + if (!noRetrace) + _vm->_video->retrace(); } + // Subtitle + if (state.flags & Graphics::CoktelVideo::kStateSpeech) + _vm->_draw->printTotText(state.speechId); if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); @@ -698,9 +721,9 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, bool VideoPlayer::doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame) { + int16 palFrame, int16 endFrame, bool noRetrace) { - playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame); + playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame, noRetrace); _vm->_util->processInput(); @@ -716,6 +739,8 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_inter->storeKey(_vm->_util->checkKey()); if (VAR(0) == (unsigned) breakKey) { _primaryVideo->getVideo()->disableSound(); + // Seek to the last frame. Some scripts depend on that. + _primaryVideo->getVideo()->seekFrame(endFrame, SEEK_SET, true); return true; } } @@ -749,7 +774,7 @@ void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, height = _primaryVideo->getVideo()->getHeight(); if (VAR_OFFSET(varX) == 0xFFFFFFFF) - _primaryVideo->getVideo()->getAnchor(1, 2, x, y, width, height); + _primaryVideo->getVideo()->getFrameCoords(1, x, y, width, height); WRITE_VAR_OFFSET(varX, x); WRITE_VAR_OFFSET(varY, y); @@ -774,13 +799,4 @@ void VideoPlayer::evalBgShading(Graphics::CoktelVideo &video) { _vm->_sound->bgUnshade(); } -void VideoPlayer::notifyPaused(uint32 duration) { - if (_primaryVideo->isOpen()) - _primaryVideo->getVideo()->notifyPaused(duration); - - for (uint i = 0; i < _videoSlots.size(); i++) - if (_videoSlots[i] && _videoSlots[i]->isOpen()) - _videoSlots[i]->getVideo()->notifyPaused(duration); -} - } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index ead752d446..28e72ab43a 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -70,7 +70,7 @@ public: void playFrame(int16 frame, int16 breakKey = kShortKeyEscape, uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, - int16 palFrame = -1 , int16 endFrame = -1); + int16 palFrame = -1 , int16 endFrame = -1, bool noRetrace = false); int slotOpen(const char *videoFile, Type which = kVideoTypeTry); void slotPlay(int slot, int16 frame = -1); @@ -103,8 +103,6 @@ public: void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, int16 varFrames, int16 varWidth, int16 varHeight); - void notifyPaused(uint32 duration); - private: class Video { public: @@ -152,6 +150,8 @@ private: bool _needBlit; bool _noCursorSwitch; + bool _woodruffCohCottWorkaround; + bool findFile(char *fileName, Type &which); const Video *getVideoBySlot(int slot = -1) const; @@ -162,7 +162,7 @@ private: void copyPalette(Graphics::CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1); bool doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame); + int16 palFrame, int16 endFrame, bool noRetrace = false); void evalBgShading(Graphics::CoktelVideo &video); }; diff --git a/engines/groovie/cell.cpp b/engines/groovie/cell.cpp index 3bc8650aa6..c257ac108e 100644 --- a/engines/groovie/cell.cpp +++ b/engines/groovie/cell.cpp @@ -27,156 +27,773 @@ namespace Groovie { -CellGame::CellGame(byte *board) : - _board(board) { +CellGame::CellGame() { _startX = _startY = _endX = _endY = 255; -} -int8 CellGame::calcMove(byte *origboard, uint8 color, uint8 depth) { - uint8 i, j; - int8 di, dj; - uint8 bestStartX, bestStartY, bestEndX, bestEndY; - int8 bestDiff = -100; - int8 origBoardCount = countBoard(origboard, color); - int8 currDiff = -100; - byte *newboard; - uint8 boardmemsize = sizeof(byte) * BOARDSIZE * BOARDSIZE; - uint8 oppColor = 3 - color; + _stack_index = _boardStackPtr = 0; + _flag4 = false; + _flag2 = false; + _coeff3 = 0; - bestStartX = bestStartY = bestEndX = bestEndY = 255; - newboard = (byte*) malloc(boardmemsize); - memcpy(newboard, origboard, boardmemsize); + _moveCount = 0; +} - if (0 == depth) { +byte CellGame::getStartX() { + if (_startX > BOARDSIZE) { + warning ("CellGame::getStartX: not calculated yet (%d)!", _startX); return 0; + } else { + return _startX; + } +} + +byte CellGame::getStartY() { + if (_startY > BOARDSIZE) { + warning ("CellGame::getStartY: not calculated yet (%d)!", _startY); + return 6; + } else { + return _startY; + } +} + +byte CellGame::getEndX() { + if (_endX > BOARDSIZE) { + warning ("CellGame::getEndX: not calculated yet (%d)!", _endX); + return 1; + } else { + return _endX; + } +} + +byte CellGame::getEndY() { + if (_endY > BOARDSIZE) { + warning ("CellGame::getEndY: not calculated yet (%d)!", _endY); + return 6; + } else { + return _endY; + } +} + +CellGame::~CellGame() { +} + +const int8 possibleMoves[][9] = { + { 1, 7, 8, -1 }, + { 0, 2, 7, 8, 9, -1 }, + { 1, 3, 8, 9, 10, -1 }, + { 2, 4, 9, 10, 11, -1 }, + { 3, 5, 10, 11, 12, -1 }, + { 4, 6, 11, 12, 13, -1 }, // 5 + { 5, 12, 13, -1 }, + { 0, 1, 8, 14, 15, -1 }, + { 0, 1, 2, 7, 9, 14, 15, 16, -1 }, + { 1, 2, 3, 8, 10, 15, 16, 17, -1 }, + { 2, 3, 4, 9, 11, 16, 17, 18, -1 }, // 10 + { 3, 4, 5, 10, 12, 17, 18, 19, -1 }, + { 4, 5, 6, 11, 13, 18, 19, 20, -1 }, + { 5, 6, 12, 19, 20, -1 }, + { 7, 8, 15, 21, 22, -1 }, + { 7, 8, 9, 14, 16, 21, 22, 23, -1 }, // 15 + { 8, 9, 10, 15, 17, 22, 23, 24, -1 }, + { 9, 10, 11, 16, 18, 23, 24, 25, -1 }, + { 10, 11, 12, 17, 19, 24, 25, 26, -1 }, + { 11, 12, 13, 18, 20, 25, 26, 27, -1 }, + { 12, 13, 19, 26, 27, -1 }, // 20 + { 14, 15, 22, 28, 29, -1 }, + { 14, 15, 16, 21, 23, 28, 29, 30, -1 }, + { 15, 16, 17, 22, 24, 29, 30, 31, -1 }, + { 16, 17, 18, 23, 25, 30, 31, 32, -1 }, + { 17, 18, 19, 24, 26, 31, 32, 33, -1 }, // 25 + { 18, 19, 20, 25, 27, 32, 33, 34, -1 }, + { 19, 20, 26, 33, 34, -1 }, + { 21, 22, 29, 35, 36, -1 }, + { 21, 22, 23, 28, 30, 35, 36, 37, -1 }, + { 22, 23, 24, 29, 31, 36, 37, 38, -1 }, // 30 + { 23, 24, 25, 30, 32, 37, 38, 39, -1 }, + { 24, 25, 26, 31, 33, 38, 39, 40, -1 }, + { 25, 26, 27, 32, 34, 39, 40, 41, -1 }, + { 26, 27, 33, 40, 41, -1 }, + { 28, 29, 36, 42, 43, -1 }, // 35 + { 28, 29, 30, 35, 37, 42, 43, 44, -1 }, + { 29, 30, 31, 36, 38, 43, 44, 45, -1 }, + { 30, 31, 32, 37, 39, 44, 45, 46, -1 }, + { 31, 32, 33, 38, 40, 45, 46, 47, -1 }, + { 32, 33, 34, 39, 41, 46, 47, 48, -1 }, // 40 + { 33, 34, 40, 47, 48, -1 }, + { 35, 36, 43, -1 }, + { 35, 36, 37, 42, 44, -1 }, + { 36, 37, 38, 43, 45, -1 }, + { 37, 38, 39, 44, 46, -1 }, // 45 + { 38, 39, 40, 45, 47, -1 }, + { 39, 40, 41, 46, 48, -1 }, + { 40, 41, 47, -1 } +}; + + +const int8 strategy2[][17] = { + { 2, 9, 14, 15, 16, -1 }, + { 3, 10, 14, 15, 16, 17, -1 }, + { 0, 4, 7, 11, 14, 15, 16, 17, 18, -1 }, + { 1, 5, 8, 12, 15, 16, 17, 18, 19, -1 }, + { 2, 6, 9, 13, 16, 17, 18, 19, 20, -1 }, + { 3, 10, 17, 18, 19, 20, -1 }, // 5 + { 4, 11, 18, 19, 20, -1 }, + { 2, 9, 16, 21, 22, 23, -1 }, + { 3, 10, 17, 21, 22, 23, 24, -1 }, + { 0, 4, 7, 11, 14, 18, 21, 22, 23, 24, 25, -1 }, + { 1, 5, 8, 12, 15, 19, 22, 23, 24, 25, 26, -1 }, // 10 + { 2, 6, 9, 13, 16, 20, 23, 24, 25, 26, 27, -1 }, + { 3, 10, 17, 24, 25, 26, 27, -1 }, + { 4, 11, 18, 25, 26, 27, -1 }, + { 0, 1, 2, 9, 16, 23, 28, 29, 30, -1 }, + { 0, 1, 2, 3, 10, 17, 24, 28, 29, 30, 31, -1 }, // 15 + { 0, 1, 2, 3, 4, 7, 11, 14, 18, 21, 25, 28, 29, 30, 31, 32, -1 }, + { 1, 2, 3, 4, 5, 8, 12, 15, 19, 22, 26, 29, 30, 31, 32, 33, -1 }, + { 2, 3, 4, 5, 6, 9, 13, 16, 20, 23, 27, 30, 31, 32, 33, 34, -1 }, + { 3, 4, 5, 6, 10, 17, 24, 31, 32, 33, 34, -1 }, + { 4, 5, 6, 11, 18, 25, 32, 33, 34, -1 }, // 20 + { 7, 8, 9, 16, 23, 30, 35, 36, 37, -1 }, + { 7, 8, 9, 10, 17, 24, 31, 35, 36, 37, 38, -1 }, + { 7, 8, 9, 10, 11, 14, 18, 21, 25, 28, 32, 35, 36, 37, 38, 39, -1 }, + { 8, 9, 10, 11, 12, 15, 19, 22, 26, 29, 33, 36, 37, 38, 39, 40, -1 }, + { 9, 10, 11, 12, 13, 16, 20, 23, 27, 30, 34, 37, 38, 39, 40, 41, -1 }, // 25 + { 10, 11, 12, 13, 17, 24, 31, 38, 39, 40, 41, -1 }, + { 11, 12, 13, 18, 25, 32, 39, 40, 41, -1 }, + { 14, 15, 16, 23, 30, 37, 42, 43, 44, -1 }, + { 14, 15, 16, 17, 24, 31, 38, 42, 43, 44, 45, -1 }, + { 14, 15, 16, 17, 18, 21, 25, 28, 32, 35, 39, 42, 43, 44, 45, 46, -1 }, // 30 + { 15, 16, 17, 18, 19, 22, 26, 29, 33, 36, 40, 43, 44, 45, 46, 47, -1 }, + { 16, 17, 18, 19, 20, 23, 27, 30, 34, 37, 41, 44, 45, 46, 47, 48, -1 }, + { 17, 18, 19, 20, 24, 31, 38, 45, 46, 47, 48, -1 }, + { 18, 19, 20, 25, 32, 39, 46, 47, 48, -1 }, + { 21, 22, 23, 30, 37, 44, -1 }, // 35 + { 21, 22, 23, 24, 31, 38, 45, -1 }, + { 21, 22, 23, 24, 25, 28, 32, 35, 39, 42, 46, -1 }, + { 22, 23, 24, 25, 26, 29, 33, 36, 40, 43, 47, -1 }, + { 23, 24, 25, 26, 27, 30, 34, 37, 41, 44, 48, -1 }, + { 24, 25, 26, 27, 31, 38, 45, -1 }, // 40 + { 25, 26, 27, 32, 39, 46, -1 }, + { 28, 29, 30, 37, 44, -1 }, + { 28, 29, 30, 31, 38, 45, -1 }, + { 28, 29, 30, 31, 32, 35, 39, 42, 46, -1 }, + { 29, 30, 31, 32, 33, 36, 40, 43, 47, -1 }, // 45 + { 30, 31, 32, 33, 34, 37, 41, 44, 48, -1 }, + { 31, 32, 33, 34, 38, 45, -1 }, + { 32, 33, 34, 39, 46, -1 } +}; + +void CellGame::copyToTempBoard() { + for (int i = 0; i < 53; ++i) { + _tempBoard[i] = _board[i]; + } +} + +void CellGame::copyFromTempBoard() { + for (int i = 0; i < 53; ++i) { + _board[i] = _tempBoard[i]; } +} + +void CellGame::copyToShadowBoard() { + _board[53] = 0; + _board[55] = 1; + _board[56] = 0; + + for (int i = 0; i < 49; ++i) { + _shadowBoard[i] = _board[i]; + } +} + +void CellGame::pushBoard() { + assert(_boardStackPtr < 57 * 9); - for (i = 0; BOARDSIZE > i; i++) { // For every square on the board - for (j = 0; BOARDSIZE > j; j++) { // - if (color == *(origboard + i + (BOARDSIZE * j))) { // If the square is the desired colour - for (di = -2; 2 >= di; di++) { // Check every square two or less in every direction - for (dj = -2; 2 >= dj; dj++) { // - if (di != 0 || dj != 0) { // Don't allow a move onto itself - debugC(7, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Testing move %d, %d-> %d, %d", depth, i, j, i+di, j+dj); - if (validMove(origboard, color, i+di, j+dj)) { - int8 nextlevel; - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Valid move %d, %d-> %d, %d", depth, i, j, i+di, j+dj); - execMove (newboard, color, i, j, i+di, j+dj); - - nextlevel = calcMove (newboard, oppColor, depth - 1); - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Next level down returned %d", depth, nextlevel); - currDiff = countBoard(newboard, color) - origBoardCount - nextlevel; - if (currDiff > bestDiff) { - debugC(4, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Found new best move (diff of %d): %d, %d-> %d, %d", depth, currDiff, i, j, i+di, j+dj); - bestDiff = currDiff; - bestStartX = i; - bestStartY = j; - bestEndX = i+di; - bestEndY = j+dj; - - } - // TODO: ideal would be to revert the move, rather than copy the board again. I think. - memcpy(newboard, origboard, boardmemsize); - } - } + for (int i = 0; i < 57; ++i) + _boardStack[_boardStackPtr + i] = _board[i]; + _boardStackPtr += 57; +} + +void CellGame::popBoard() { + assert(_boardStackPtr > 0); + + _boardStackPtr -= 57; + for (int i = 0; i < 57; ++i) { + _board[i] = _boardStack[_boardStackPtr + i]; + } +} + +void CellGame::pushShadowBoard() { + assert(_boardStackPtr < 57 * 9); + + for (int i = 0; i < 57; ++i) + _boardStack[_boardStackPtr + i] = _shadowBoard[i]; + + _boardStackPtr += 57; +} + +void CellGame::popShadowBoard() { + assert(_boardStackPtr > 0); + + _boardStackPtr -= 57; + + for (int i = 0; i < 57; ++i) { + _shadowBoard[i] = _boardStack[_boardStackPtr + i]; + } +} + +void CellGame::clearMoves() { + _stack_startXY[0] = _board[53]; + _stack_endXY[0] = _board[54]; + _stack_pass[0] = _board[55]; + + _stack_index = 1; +} + +void CellGame::pushMove() { + _stack_startXY[_stack_index] = _board[53]; + _stack_endXY[_stack_index] = _board[54]; + _stack_pass[_stack_index] = _board[55]; + + _stack_index++; +} + +void CellGame::resetMove() { + _board[53] = 0; + _board[54] = 0; + _board[55] = 0; +} + +void CellGame::takeCells(uint16 whereTo, int8 color) { + int cellN; + const int8 *str; + + str = possibleMoves[whereTo]; + while (1) { + cellN = *str++; + if (cellN < 0) + break; + if (_tempBoard[cellN] > 0) { + --_tempBoard[_tempBoard[cellN] + 48]; + _tempBoard[cellN] = color; + ++_tempBoard[color + 48]; + } + } +} + +void CellGame::countAllCells() { + _board[49] = 0; + _board[50] = 0; + _board[51] = 0; + _board[52] = 0; + + for (int i = 0; i < 49; i++) { + switch (_board[i]) { + case 1: // CELL_BLUE + _board[49]++; + break; + case 2: // CELL_GREEN + _board[50]++; + break; + case 3: + _board[51]++; + break; + case 4: + _board[52]++; + break; + } + } +} + +int CellGame::countCellsOnTempBoard(int8 color) { + const int8 *str; + int res = 0; + int i; + + for (i = 0; i < 49; i++) + _boardSum[i] = 0; + + for (i = 0; i < 49; i++) { + if (_tempBoard[i] == color) { + for (str = possibleMoves[i]; *str > 0; str++) { + if (!_tempBoard[*str]) + ++_boardSum[*str]; + } + } + } + + for (i = 0; i < 49; i++) + res += _boardSum[i]; + + return res; +} + +bool CellGame::canMoveFunc1(int8 color) { + const int8 *str; + + if (_board[55] == 1) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &possibleMoves[_board[53]][_board[56]]; + for (;_board[56] < 8; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; } } + _board[56] = 0; + } + } + _board[53] = 0; + _board[55] = 2; + _board[56] = 0; + } + if (_board[55] == 2) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &strategy2[_board[53]][_board[56]]; + for (;_board[56] < 16; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_board[_board[54]]) { + ++_board[56]; + return true; + } + } + _board[56] = 0; } } } - _startX = bestStartX; - _startY = bestStartY; - _endX = bestEndX; - _endY = bestEndY; - - debugC(2, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Best move is (diff of %d): %d, %d-> %d, %d", depth, bestDiff, _startX, _startY, _endX, _endY); - free(newboard); - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Freed newboard"); - return bestDiff; + return false; } -void CellGame::execMove(byte *board, uint8 color, int8 startX, int8 startY, int8 endX, int8 endY) { - int8 i, j; - uint8 colorToEat = 3 - color; // The opposite of the colour passed: 2 -> 1, 1 -> 2 +bool CellGame::canMoveFunc3(int8 color) { + const int8 *str; + + if (_board[55] == 1) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &possibleMoves[_board[53]][_board[56]]; + for (;_board[56] < 8; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; + } + } + _board[56] = 0; + } + } - if (abs(endX - startX) == 2 || abs(endY - startY) == 2) { - *(board + startX + BOARDSIZE * startY) = 0; + _board[53] = 0; + _board[55] = 2; + _board[56] = 0; + for (int i = 0; i < 49; ++i) + _shadowBoard[i] = _board[i]; + } + if (_board[55] == 2) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &strategy2[_board[53]][_board[56]]; + for (;_board[56] < 16; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; + } + } + _board[56] = 0; + } + } } - *(board + endX + BOARDSIZE * endY) = color; + return false; +} + +bool CellGame::canMoveFunc2(int8 color) { + const int8 *str; - for (i = (endX - 1); endX + 1 >= i; i++) { - for (j = (endY - 1); endY + 1 >= j; j++) { - if (BOARDSIZE > i && BOARDSIZE > j && 0 <= i && 0 <= j) { // Don't wrap around the board edges! - uint8 offset = i + BOARDSIZE * j; - if (colorToEat == *(board + offset)) { - *(board + offset) = color; + while (1) { + while (_board[_board[54]]) { + ++_board[54]; + if (_board[54] >= 49) + return false; + } + if (!_board[55]) { + str = possibleMoves[_board[54]]; + while (1) { + _board[53] = *str++; + if (_board[53] < 0) + break; + if (_board[_board[53]] == color) { + _board[55] = 1; + return true; + } + } + _board[55] = 1; + } + if (_board[55] == 1) { + _board[55] = 2; + _board[56] = 0; + } + if (_board[55] == 2) { + str = &strategy2[_board[54]][_board[56]]; + for (; _board[56] < 16; _board[56]++) { + _board[53] = *str++; + if (_board[53] < 0) + break; + if (_board[_board[53]] == color) { + ++_board[56]; + return true; } } + ++_board[54]; + _board[55] = 0; + if (_board[54] >= 49) + break; } } + return false; +} + +void CellGame::makeMove(int8 color) { + copyToTempBoard(); + _tempBoard[_board[54]] = color; + ++_tempBoard[color + 48]; + if (_board[55] == 2) { + _tempBoard[_board[53]] = 0; + --_tempBoard[color + 48]; + } + takeCells(_board[54], color); } -bool CellGame::validMove(byte *board, uint8 color, int8 endX, int8 endY) { - if (0 > endX || 0 > endY || BOARDSIZE <= endX || BOARDSIZE <= endY) { // Move is out of bounds - return false; +int CellGame::getBoardWeight(int8 color1, int8 color2) { + int8 celln; + const int8 *str; + byte cellCnt[8]; + + str = possibleMoves[_board[54]]; + cellCnt[1] = _board[49]; + cellCnt[2] = _board[50]; + cellCnt[3] = _board[51]; + cellCnt[4] = _board[52]; + if (_board[55] != 2) + ++cellCnt[color2]; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; } - if (0 == *(board + endX + (BOARDSIZE * endY))) { - return true; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; } - return false; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; + } + while (1) { + celln = *str++; + if (celln < 0) + break; + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; + } + } + return _coeff3 + 2 * (2 * cellCnt[color1] - cellCnt[1] - cellCnt[2] - cellCnt[3] - cellCnt[4]); } -uint8 CellGame::countBoard(byte *board, uint8 color) { - uint8 total = 0; - for (uint8 i = 0; BOARDSIZE > i; i++) { - for (uint8 j = 0; BOARDSIZE > j; j++) { - if (color == *(board + i + (BOARDSIZE * j))) { - total++; +void CellGame::chooseBestMove(int8 color) { + int moveIndex = 0; + int curWeight; + int bestWeight; + + if (_flag2) { + bestWeight = 32767; + for (int i = 0; i < _stack_index; ++i) { + _board[53] = _stack_startXY[i]; + _board[54] = _stack_endXY[i]; + _board[55] = _stack_pass[i]; + makeMove(color); + curWeight = countCellsOnTempBoard(color); + if (curWeight <= bestWeight) { + if (curWeight < bestWeight) + moveIndex = 0; + bestWeight = curWeight; + _stack_startXY[moveIndex] = _board[53]; + _stack_endXY[moveIndex] = _board[54]; + _stack_pass[moveIndex++] = _board[55]; } } + _stack_index = moveIndex; } - return total; + + _startX = _stack_startXY[0] % 7; + _startY = _stack_startXY[0] / 7; + _endX = _stack_endXY[0] % 7; + _endY = _stack_endXY[0] / 7; } -byte CellGame::getStartX() { - if (_startX > BOARDSIZE) { - warning ("CellGame::getStartX: not calculated yet!"); - return 0; +int8 CellGame::calcBestWeight(int8 color1, int8 color2, uint16 depth, int bestWeight) { + int8 res; + int8 curColor; + bool canMove; + int type; + uint16 i; + int8 currBoardWeight; + int8 weight; + + pushBoard(); + copyFromTempBoard(); + curColor = color2; + for (i = 0;; ++i) { + if (i >= 4) { + res = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + popBoard(); + return res; + } + ++curColor; + if (curColor > 4) + curColor = 1; + + if (_board[curColor + 48]) { + if (_board[curColor + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) { + resetMove(); + canMove = canMoveFunc2(curColor); + type = 1; + } else { + copyToShadowBoard(); + if (depth == 1) { + canMove = canMoveFunc3(curColor); + type = 3; + } else { + canMove = canMoveFunc1(curColor); + type = 2; + } + } + if (canMove) + break; + } + } + if (_flag1) { + popBoard(); + return bestWeight + 1; + } + + depth -= 1; + if (depth) { + makeMove(curColor); + if (type == 1) { + res = calcBestWeight(color1, curColor, depth, bestWeight); + } else { + pushShadowBoard(); + res = calcBestWeight(color1, curColor, depth, bestWeight); + popShadowBoard(); + } } else { - return _startX; + res = getBoardWeight(color1, curColor); + } + + if ((res < bestWeight && color1 != curColor) || _flag4) { + popBoard(); + return res; + } + + currBoardWeight = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + while (1) { + if (type == 1) { + canMove = canMoveFunc2(curColor); + } else if (type == 2) { + canMove = canMoveFunc1(curColor); + } else { + canMove = canMoveFunc3(curColor); + } + + if (!canMove) + break; + if (_flag1) { + popBoard(); + return bestWeight + 1; + } + if (_board[55] == 2) { + if (getBoardWeight(color1, curColor) == currBoardWeight) + continue; + } + if (!depth) { + weight = getBoardWeight(color1, curColor); + if (type == 1) { + if (_board[55] == 2) + _board[56] = 16; + } + } else { + makeMove(curColor); + if (type != 1) { + pushShadowBoard(); + weight = calcBestWeight(color1, curColor, depth, bestWeight); + popShadowBoard(); + } else { + weight = calcBestWeight(color1, curColor, depth, bestWeight); + } + } + if ((weight < res && color1 != curColor) || (weight > res && color1 == curColor)) + res = weight; + + if ((res < bestWeight && color1 != curColor) || _flag4) + break; } + popBoard(); + + return res; } -byte CellGame::getStartY() { - if (_startY > BOARDSIZE) { - warning ("CellGame::getStartY: not calculated yet!"); - return 6; +int16 CellGame::doGame(int8 color, int depth) { + bool canMove; + int type; + int8 currBoardWeight; + int8 w1; + int8 w2; + + countAllCells(); + if (_board[color + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) { + resetMove(); + canMove = canMoveFunc2(color); + type = true; } else { - return _startY; + copyToShadowBoard(); + canMove = canMoveFunc1(color); + type = false; } -} -byte CellGame::getEndX() { - if (_endX > BOARDSIZE) { - warning ("CellGame::getEndX: not calculated yet!"); + if (canMove) { + if (_board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52] == 0) + depth = 0; + _coeff3 = 0; + if (_board[55] == 1) + _coeff3 = 1; + clearMoves(); + if (depth) { + makeMove(color); + _flag4 = false; + if (type) { + w2 = calcBestWeight(color, color, depth, -127); + } else { + pushShadowBoard(); + w2 = calcBestWeight(color, color, depth, -127); + popShadowBoard(); + } + } else { + w2 = getBoardWeight(color, color); + } + currBoardWeight = 2 * (2 * _board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + while (1) { + if (type) + canMove = canMoveFunc2(color); + else + canMove = canMoveFunc1(color); + + if (!canMove) + break; + if (_flag1) + break; + _coeff3 = 0; + if (_board[55] == 2) { + if (getBoardWeight(color, color) == currBoardWeight) + continue; + } + if (_board[55] == 1) + _coeff3 = 1; + if (depth) { + makeMove(color); + _flag4 = false; + if (type) { + w1 = calcBestWeight(color, color, depth, w2); + } else { + pushShadowBoard(); + w1 = calcBestWeight(color, color, depth, w2); + popShadowBoard(); + } + } else { + w1 = getBoardWeight(color, color); + } + if (w1 == w2) + pushMove(); + + if (w1 > w2) { + clearMoves(); + w2 = w1; + } + } + chooseBestMove(color); return 1; - } else { - return _endX; } + + return 0; } -byte CellGame::getEndY() { - if (_endY > BOARDSIZE) { - warning ("CellGame::getEndY: not calculated yet!"); - return 6; +const int8 depths[] = { 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3 }; + +int16 CellGame::calcMove(int8 color, uint16 depth) { + int result; + + _flag1 = false; + ++_moveCount; + if (depth) { + if (depth == 1) { + _flag2 = true; + result = doGame(color, 0); + } else { + int newDepth; + + newDepth = depths[3 * (depth - 2) + _moveCount % 3]; + _flag2 = true; + if (newDepth >= 20) { + assert(0); // This branch is not implemented + } else { + result = doGame(color, newDepth); + } + } } else { - return _endY; + _flag2 = false; + result = doGame(color, depth); } + return result; } -CellGame::~CellGame() { +int CellGame::playStauf(byte color, uint16 depth, byte *scriptBoard) { + int i; + + for (i = 0; i < 49; i++, scriptBoard++) { + _board[i] = 0; + if (*scriptBoard == 50) + _board[i] = 1; + if (*scriptBoard == 66) + _board[i] = 2; + } + for (i = 49; i < 57; i++) + _board[i] = 0; + + return calcMove(color, depth); } + } // End of Groovie namespace diff --git a/engines/groovie/cell.h b/engines/groovie/cell.h index 70e135b62d..39ee529beb 100644 --- a/engines/groovie/cell.h +++ b/engines/groovie/cell.h @@ -29,6 +29,7 @@ #include "common/file.h" #include "common/util.h" +#include "groovie/cell.h" #include "groovie/groovie.h" #define BOARDSIZE 7 @@ -43,24 +44,59 @@ class Script; class CellGame { public: - CellGame(byte *board); + CellGame(); ~CellGame(); - int8 calcMove(byte *origboard, uint8 color, uint8 depth); byte getStartX(); byte getStartY(); byte getEndX(); byte getEndY(); + int playStauf(byte color, uint16 depth, byte *scriptBoard); private: - bool validMove(byte *board, uint8 color, int8 endX, int8 endY); - void execMove(byte *board, uint8 color, int8 startX, int8 startY, int8 endX, int8 endY); - uint8 countBoard(byte* board, uint8 color); - byte *_board; + void copyToTempBoard(); + void copyFromTempBoard(); + void copyToShadowBoard(); + void pushBoard(); + void popBoard(); + void pushShadowBoard(); + void popShadowBoard(); + void clearMoves(); + void pushMove(); + void resetMove(); + bool canMoveFunc1(int8 color); + bool canMoveFunc2(int8 color); + bool canMoveFunc3(int8 color); + void takeCells(uint16 whereTo, int8 color); + void countAllCells(); + int countCellsOnTempBoard(int8 color); + void makeMove(int8 color); + int getBoardWeight(int8 color1, int8 color2); + void chooseBestMove(int8 color); + int8 calcBestWeight(int8 color1, int8 color2, uint16 depth, int bestWeight); + int16 doGame(int8 color, int depth); + int16 calcMove(int8 color, uint16 depth); byte _startX; byte _startY; byte _endX; byte _endY; + + int8 _board[57]; + int8 _tempBoard[58]; + int8 _shadowBoard[64]; + int8 _boardStack[570]; + int _boardStackPtr; + + int8 _boardSum[58]; + + int8 _stack_startXY[128]; + int8 _stack_endXY[128]; + int8 _stack_pass[128]; + int _stack_index; + + int _coeff3; + bool _flag1, _flag2, _flag4; + int _moveCount; }; } // End of Groovie namespace diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index 1a1de92156..797290a6f3 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -35,7 +35,7 @@ namespace Groovie { MusicPlayer::MusicPlayer(GroovieEngine *vm) : _vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100), - _prevCDtrack(0) { + _prevCDtrack(0), _backgroundDelay(0) { } void MusicPlayer::playSong(uint32 fileref) { @@ -56,6 +56,18 @@ void MusicPlayer::setBackgroundSong(uint32 fileref) { _backgroundFileRef = fileref; } +void MusicPlayer::frameTick() { + if (_backgroundDelay > 0) { + _backgroundDelay--; + if (_backgroundDelay == 0) + playSong(_backgroundFileRef); + } +} + +void MusicPlayer::setBackgroundDelay(uint16 delay) { + _backgroundDelay = delay; +} + void MusicPlayer::playCD(uint8 track) { int startms = 0; diff --git a/engines/groovie/music.h b/engines/groovie/music.h index db50930c37..9909c8a185 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -44,6 +44,9 @@ public: void playCD(uint8 track); void startBackground(); + void frameTick(); + void setBackgroundDelay(uint16 delay); + // Volume void setUserVolume(uint16 volume); void setGameVolume(uint16 volume, uint16 time); @@ -55,6 +58,8 @@ private: uint32 _backgroundFileRef; uint8 _prevCDtrack; + uint16 _backgroundDelay; + // Volume fading uint32 _fadingStartTime; uint16 _fadingStartVolume; diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index eb53842b91..7fdfa6c780 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -33,6 +33,7 @@ #include "common/config-manager.h" #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" #define NUM_OPCODES 90 @@ -61,7 +62,7 @@ static void debugScript(int level, bool nl, const char *s, ...) { Script::Script(GroovieEngine *vm, EngineVersion version) : _code(NULL), _savedCode(NULL), _stacktop(0), _debugger(NULL), _vm(vm), - _videoFile(NULL), _videoRef(0), _font(NULL) { + _videoFile(NULL), _videoRef(0), _font(NULL), _staufsMove(NULL) { // Initialize the opcode set depending on the engine version switch (version) { case kGroovieT7G: @@ -73,7 +74,7 @@ Script::Script(GroovieEngine *vm, EngineVersion version) : } // Initialize the random source - _vm->_system->getEventManager()->registerRandomSource(_random, "GroovieScripts"); + g_eventRec.registerRandomSource(_random, "GroovieScripts"); // Prepare the variables _bitflags = 0; @@ -195,6 +196,10 @@ void Script::directGameLoad(int slot) { // TODO: We'll probably need to start by running the beginning of the // script to let it do the soundcard initialization and then do the // actual loading. + + // Due to HACK above, the call to check valid save slots is not run. + // As this is where we load save names, manually call it here. + o_checkvalidsaves(); } void Script::step() { @@ -559,6 +564,7 @@ bool Script::playvideofromref(uint32 fileref) { // Video available, play one frame if (_videoFile) { bool endVideo = _vm->_videoPlayer->playFrame(); + _vm->_musicPlayer->frameTick(); if (endVideo) { // Close the file @@ -1376,33 +1382,21 @@ void Script::o_sub() { } void Script::o_cellmove() { - uint16 arg = readScript8bits(); + uint16 depth = readScript8bits(); byte *scriptBoard = &_variables[0x19]; - byte *board = (byte*) malloc (BOARDSIZE * BOARDSIZE * sizeof(byte)); byte startX, startY, endX, endY; - debugScript(1, true, "CELL MOVE var[0x%02X]", arg); - - // Arguments used by the original implementation: (2, arg, scriptBoard) - for (int y = 0; y < 7; y++) { - for (int x = 0; x < 7; x++) { - uint8 offset = x + BOARDSIZE * y; - *(board + offset) = 0; - if (*scriptBoard == 0x32) *(board + offset) = CELL_BLUE; - if (*scriptBoard == 0x42) *(board + offset) = CELL_GREEN; - scriptBoard++; - debugScript(1, false, "%d", *(board + offset)); - } - debugScript(1, false, "\n"); - } + debugScript(1, true, "CELL MOVE var[0x%02X]", depth); + + if (!_staufsMove) + _staufsMove = new CellGame; - CellGame staufsMove((byte*) board); - staufsMove.calcMove((byte*) board, CELL_GREEN, 2); - startX = staufsMove.getStartX(); - startY = staufsMove.getStartY(); - endX = staufsMove.getEndX(); - endY = staufsMove.getEndY(); + _staufsMove->playStauf(2, depth, scriptBoard); + startX = _staufsMove->getStartX(); + startY = _staufsMove->getStartY(); + endX = _staufsMove->getEndX(); + endY = _staufsMove->getEndY(); // Set the movement origin setVariable(0, startY); // y @@ -1410,8 +1404,6 @@ void Script::o_cellmove() { // Set the movement destination setVariable(2, endY); setVariable(3, endX); - - free (board); } void Script::o_returnscript() { @@ -1500,6 +1492,14 @@ void Script::o_playcd() { _vm->_musicPlayer->playCD(val); } +void Script::o_musicdelay() { + uint16 delay = readScript16bits(); + + debugScript(1, true, "MUSICDELAY %d", delay); + + _vm->_musicPlayer->setBackgroundDelay(delay); +} + void Script::o_hotspot_outrect() { uint16 left = readScript16bits(); uint16 top = readScript16bits(); @@ -1671,7 +1671,7 @@ Script::OpcodeFunc Script::_opcodesT7G[NUM_OPCODES] = { &Script::o_nop8, &Script::o_getcd, // 0x4C &Script::o_playcd, - &Script::o_nop16, + &Script::o_musicdelay, &Script::o_nop16, &Script::o_nop16, // 0x50 &Script::o_nop16, diff --git a/engines/groovie/script.h b/engines/groovie/script.h index 664cac82d8..e9e0be69ec 100644 --- a/engines/groovie/script.h +++ b/engines/groovie/script.h @@ -40,6 +40,7 @@ enum EngineVersion { }; class GroovieEngine; +class CellGame; class Script { friend class Debugger; @@ -120,6 +121,8 @@ private: Common::String _debugString; uint16 _oldInstruction; + CellGame *_staufsMove; + // Helper functions uint8 getCodeByte(uint16 address); uint8 readScript8bits(); @@ -216,6 +219,7 @@ private: void o_sethotspotleft(); void o_getcd(); void o_playcd(); + void o_musicdelay(); void o_hotspot_outrect(); void o_stub56(); void o_stub59(); diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index 85d974f675..d9924d233b 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -538,18 +538,18 @@ int MainMenu::handle(int dim) { int item = (mouse.y - menuRect.top) / fh; if (item != selected) { - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5); - printString(_static.strings[item], textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]); + printString("%s", textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5, _static.strings[item]); selected = item; } if (mousePressed) { for (int i = 0; i < 3; i++) { - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]); _screen->updateScreen(); _system->delayMillis(50); - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5, _static.strings[selected]); _screen->updateScreen(); _system->delayMillis(50); } @@ -577,7 +577,7 @@ void MainMenu::draw(int select) { for (int i = 0; i < _static.menuTable[3]; ++i) { int curY = top + i * _screen->getFontHeight(); int color = (i == select) ? _static.menuTable[6] : _static.menuTable[5]; - printString(_static.strings[i], ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5); + printString("%s", ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5, _static.strings[i]); } } diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 69e7419757..cb2476ff99 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -757,7 +757,6 @@ int GUI_HoF::optionsButton(Button *button) { initMenu(*_currentMenu); _madeSave = false; _loadedSave = false; - _vm->_itemInHand = -1; updateAllMenuButtons(); if (_isDeathMenu) { @@ -821,6 +820,7 @@ void GUI_HoF::resetState(int item) { _vm->setNextIdleAnimTimer(); _isDeathMenu = false; if (!_loadedSave) { + _vm->_itemInHand = -1; _vm->setHandItem(item); } else { _vm->setHandItem(_vm->_itemInHand); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 9f42697ec7..4624aced90 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -681,6 +681,7 @@ void GUI_LoK::updateSavegameString() { } int GUI_LoK::saveGame(Button *button) { + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); updateMenuButton(button); _vm->_gameToLoad = _menu[2].item[button->index-0xC].saveSlot; @@ -729,6 +730,7 @@ int GUI_LoK::saveGame(Button *button) { } } + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); return 0; } diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index e7001ed31f..858e3fde94 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -1141,6 +1141,7 @@ void GUI_MR::resetState(int item) { _vm->setNextIdleAnimTimer(); _isDeathMenu = false; if (!_loadedSave) { + _vm->_itemInHand = -1; _vm->setHandItem(item); } else { _vm->setHandItem(_vm->_itemInHand); @@ -1260,7 +1261,6 @@ int GUI_MR::optionsButton(Button *button) { initMenu(*_currentMenu); _madeSave = false; _loadedSave = false; - _vm->_itemInHand = -1; updateAllMenuButtons(); if (_isDeathMenu) { diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index e5c8637fb5..3633a546e7 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -661,7 +661,9 @@ int GUI_v2::clickSaveSlot(Button *caller) { initMenu(_savenameMenu); _screen->fillRect(0x26, 0x5B, 0x11F, 0x66, textFieldColor2()); + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); const char *desc = nameInputProcess(_saveDescription, 0x27, 0x5C, textFieldColor1(), textFieldColor2(), textFieldColor3(), 0x50); + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); restorePage1(_vm->_screenBuffer); backUpPage1(_vm->_screenBuffer); if (desc) { diff --git a/engines/kyra/items_mr.cpp b/engines/kyra/items_mr.cpp index 5397651e97..d08d58e65d 100644 --- a/engines/kyra/items_mr.cpp +++ b/engines/kyra/items_mr.cpp @@ -87,7 +87,8 @@ void KyraEngine_MR::setMouseCursor(uint16 item) { shape = item+248; } - if ((int16)item != _itemInHand) + _mouseState = item; + if ((int16)item >= 0) _screen->setMouseCursor(hotX, hotY, getShapePtr(shape)); } diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 5c41989713..bf515498dc 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -1658,7 +1658,7 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { if (!file) error("Couldn't load cauldron palette"); file->seek(state*18, SEEK_SET); - _screen->getPalette(0).loadVGAPalette(*file, 241, 6); + _screen->getPalette(2).loadVGAPalette(*file, 241, 6); delete file; file = 0; @@ -1673,8 +1673,8 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { _screen->getPalette(0).copy(_screen->getPalette(2), 241, 6); _cauldronState = state; _cauldronUseCount = 0; - //if (state == 5) - // sub_27149(); + if (state == 5) + setDlgIndex(5); } void KyraEngine_HoF::clearCauldronTable() { diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 88bfb8c89b..2204f78b82 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -495,6 +495,7 @@ private: bool _useFrameTable; int o3a_setCharacterFrame(EMCState *script); + int o3a_playSoundEffect(EMCState *script); // special shape code int initAnimationShapes(uint8 *filedata); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 5f5dc10e75..9ee6935384 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -24,6 +24,7 @@ */ #include "common/config-manager.h" +#include "common/EventRecorder.h" #include "sound/mididrv.h" #include "sound/mixer.h" @@ -84,7 +85,7 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) Common::addDebugChannel(kDebugLevelMovie, "Movie", "Movie debug level"); Common::addDebugChannel(kDebugLevelTimer, "Timer", "Timer debug level"); - _eventMan->registerRandomSource(_rnd, "kyra"); + g_eventRec.registerRandomSource(_rnd, "kyra"); } ::GUI::Debugger *KyraEngine_v1::getDebugger() { diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 83230d6e3b..9e0ddcea4f 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -222,11 +222,7 @@ const char *KyraEngine_v1::getSavegameFilename(int num) { Common::String KyraEngine_v1::getSavegameFilename(const Common::String &target, int num) { assert(num >= 0 && num <= 999); - - char extension[5]; - sprintf(extension, "%03d", num); - - return target + "." + extension; + return target + Common::String::printf(".%03d", num); } bool KyraEngine_v1::saveFileLoadable(int slot) { diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 6c2c48cb02..7a7544a589 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -95,25 +95,10 @@ bool Screen::init() { } if (_useSJIS) { - if (!_sjisFont) { - // we use the FM-TOWNS font rom for PC-98, too, until we feel - // like adding support for the PC-98 font - //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { - // FM-TOWNS - Common::SeekableReadStream *rom = _vm->resource()->createReadStream("FMT_FNT.ROM"); - Graphics::FontTowns *townsFont = new Graphics::FontTowns(); - if (!rom || !townsFont || !townsFont->loadFromStream(*rom)) - error("Could not load font rom ('FMT_FNT.ROM') required for this version"); - _sjisFont = townsFont; - delete rom; - /*} else { - // PC-98 - _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0); - if (!_sjisFontData) - error("missing font rom ('FONT.ROM') required for this version"); - }*/ - } - + _sjisFont = Graphics::FontSJIS::createFont(_vm->gameFlags().platform); + + if (!_sjisFont) + error("Could not load any SJIS font, neither the original nor ScummVM's 'SJIS.FNT'"); _sjisFont->enableOutline(!_use16ColorMode); } } diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 1800bd1939..819bf838ca 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -1114,6 +1114,12 @@ int KyraEngine_MR::o3a_setCharacterFrame(EMCState *script) { return 0; } +int KyraEngine_MR::o3a_playSoundEffect(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0)); + snd_playSoundEffect(stackPos(0), 200); + return 0; +} + #pragma mark - int KyraEngine_MR::o3d_updateAnim(EMCState *script) { @@ -1374,7 +1380,7 @@ void KyraEngine_MR::setupOpcodeTable() { // 0x00 Opcode(o2a_setAnimationShapes); Opcode(o3a_setCharacterFrame); - Opcode(o3_playSoundEffect); + Opcode(o3a_playSoundEffect); Opcode(o3_dummy); // 0x04 Opcode(o2a_setResetFrame); diff --git a/engines/kyra/sequences_mr.cpp b/engines/kyra/sequences_mr.cpp index 4d1117f3c9..a1830aec5c 100644 --- a/engines/kyra/sequences_mr.cpp +++ b/engines/kyra/sequences_mr.cpp @@ -42,7 +42,8 @@ void KyraEngine_MR::showBadConscience() { _badConscienceAnim = 6; else if (_currentChapter == 5 && _rnd.getRandomNumberRng(1, 100) <= 25) _badConscienceAnim = 7; - else if (_characterShapeFile == 9) + + if (_characterShapeFile == 9) _badConscienceAnim = 4; _badConsciencePosition = (_mainCharacter.x1 <= 160); diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp index 6b81b1c022..1d8bc5b03c 100644 --- a/engines/kyra/sound_digital.cpp +++ b/engines/kyra/sound_digital.cpp @@ -346,7 +346,7 @@ int AUDStream::readChunk(int16 *buffer, const int maxSamples) { #pragma mark - -SoundDigital::SoundDigital(KyraEngine_MR *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _sounds() { +SoundDigital::SoundDigital(KyraEngine_MR *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { for (uint i = 0; i < ARRAYSIZE(_sounds); ++i) _sounds[i].stream = 0; } diff --git a/engines/kyra/sprites.cpp b/engines/kyra/sprites.cpp index 3cc632a391..456dcc06f3 100644 --- a/engines/kyra/sprites.cpp +++ b/engines/kyra/sprites.cpp @@ -28,6 +28,8 @@ #include "common/stream.h" #include "common/util.h" #include "common/system.h" +#include "common/EventRecorder.h" + #include "kyra/screen.h" #include "kyra/kyra_lok.h" #include "kyra/sprites.h" @@ -47,7 +49,7 @@ Sprites::Sprites(KyraEngine_LoK *vm, OSystem *system) { _spriteDefStart = 0; memset(_drawLayerTable, 0, sizeof(_drawLayerTable)); _sceneAnimatorBeaconFlag = 0; - _vm->getEventManager()->registerRandomSource(_rnd, "kyraSprites"); + g_eventRec.registerRandomSource(_rnd, "kyraSprites"); } Sprites::~Sprites() { diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 969d8215fb..b5ec00fdf9 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -38,6 +38,7 @@ #include "lure/sound.h" #include "lure/lure.h" #include "common/endian.h" +#include "common/EventRecorder.h" namespace Lure { @@ -600,7 +601,7 @@ void Hotspot::setRandomDest() { Common::RandomSource rnd; int16 xp, yp; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); if (currentActions().isEmpty()) currentActions().addFront(START_WALKING, roomNumber()); @@ -2691,7 +2692,19 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { return; } h.currentActions().top().setAction(WALKING); - h.setPosition(h.x(), h.y() & 0xfff8); + + // WORKAROUND: A character that had enteredg an exit area might have been blocked from entering the new room. + // The Y position adjust below could thus place a character further into the exit area. So don't do the + // position adjustment if the user is already in an exit area + int16 x = h.x() + (h.widthCopy() >> 1); + int16 y = h.y() + h.heightCopy() - (h.yCorrection() >> 1); + + RoomData *roomData = Resources::getReference().getRoom(h.roomNumber()); + RoomExitData *exitRec = roomData->exits.checkExits(x, y); + + if (!exitRec) + h.setPosition(h.x(), h.y() & 0xfff8); + } else if (h.blockedState() == BS_FINAL) { // If this point is reached, the character twice hasn't found a walking path debugC(ERROR_DETAILED, kLureDebugAnimations, "Character is hopelessly blocked"); @@ -3135,7 +3148,7 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { Common::RandomSource rnd; RandomActionType actionType; uint16 scheduleId; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); int actionIndex = rnd.getRandomNumber(set->numActions() - 1); set->getEntry(actionIndex, actionType, scheduleId); @@ -3325,7 +3338,7 @@ void HotspotTickHandlers::prisonerAnimHandler(Hotspot &h) { ValueTableData &fields = Resources::getReference().fieldList(); Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.handleTalkDialog(); if (h.frameCtr() > 0) { @@ -3368,7 +3381,7 @@ void HotspotTickHandlers::morkusAnimHandler(Hotspot &h) { if (h.executeScript()) { // Script is done - set new script to one of two alternates randomly Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.setHotspotScript(rnd.getRandomNumber(100) >= 50 ? 0x54 : 0); h.setFrameCtr(20 + rnd.getRandomNumber(63)); @@ -3668,7 +3681,7 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { Common::RandomSource rnd; static bool ewanXOffset = false; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.handleTalkDialog(); if (h.delayCtr() > 0) { diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp index 95cb0a2f1b..7eb76cad32 100644 --- a/engines/lure/res.cpp +++ b/engines/lure/res.cpp @@ -30,6 +30,7 @@ #include "lure/lure.h" #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" namespace Lure { @@ -42,7 +43,7 @@ Resources &Resources::getReference() { } Resources::Resources() { - g_system->getEventManager()->registerRandomSource(_rnd, "lureResources"); + g_eventRec.registerRandomSource(_rnd, "lureResources"); int_resources = this; reloadData(); diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp index 391147ebd5..f9d854a73b 100644 --- a/engines/lure/scripts.cpp +++ b/engines/lure/scripts.cpp @@ -34,6 +34,7 @@ #include "lure/sound.h" #include "common/stack.h" #include "common/endian.h" +#include "common/EventRecorder.h" namespace Lure { @@ -739,7 +740,7 @@ void Script::addActions(uint16 hotspotId, uint16 actions, uint16 v3) { void Script::randomToGeneral(uint16 maxVal, uint16 minVal, uint16 v3) { Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureScripts"); + g_eventRec.registerRandomSource(rnd, "lureScripts"); uint16 v = minVal + rnd.getRandomNumber(maxVal - minVal); Resources::getReference().fieldList().setField(GENERAL, v); } diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index c27f151fdf..b4973002a6 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -53,6 +53,7 @@ #include "common/file.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/endian.h" #include "common/system.h" #include "common/config-manager.h" @@ -192,7 +193,7 @@ Common::Error M4Engine::run() { _animation = new Animation(this); //_callbacks = new Callbacks(this); _random = new Common::RandomSource(); - g_system->getEventManager()->registerRandomSource(*_random, "m4"); + g_eventRec.registerRandomSource(*_random, "m4"); if (isM4()) return goM4(); diff --git a/engines/made/made.cpp b/engines/made/made.cpp index 50a14c3e34..c83f7aaf02 100644 --- a/engines/made/made.cpp +++ b/engines/made/made.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -74,7 +75,7 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng _gameId = g->id; _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "made"); + g_eventRec.registerRandomSource(*_rnd, "made"); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 7aee966aa6..8fadd4e462 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/util.h" #include "common/system.h" @@ -70,7 +71,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Common::addDebugChannel(kDebugMenu, "menu", "Menu debug level"); Common::addDebugChannel(kDebugInventory, "inventory", "Inventory debug level"); - syst->getEventManager()->registerRandomSource(_rnd, "parallaction"); + g_eventRec.registerRandomSource(_rnd, "parallaction"); } diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index b7c8a9e029..3672fd3b09 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -172,14 +172,14 @@ protected: DECLARE_UNQUALIFIED_COMMAND_PARSER(simple); DECLARE_UNQUALIFIED_COMMAND_PARSER(move); DECLARE_UNQUALIFIED_COMMAND_PARSER(endcommands); - +public: virtual void parseGetData(ZonePtr z); virtual void parseExamineData(ZonePtr z); virtual void parseDoorData(ZonePtr z); virtual void parseMergeData(ZonePtr z); virtual void parseHearData(ZonePtr z); virtual void parseSpeakData(ZonePtr z); - +protected: Common::String parseComment(); Common::String parseDialogueString(); Dialogue *parseDialogue(); @@ -289,10 +289,12 @@ protected: DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); virtual void parseZoneTypeBlock(ZonePtr z); - void parsePathData(ZonePtr z); - void parseGetData(ZonePtr z); - void parseDoorData(ZonePtr z); - void parseAnswerCounter(Answer *answer); +public: + virtual void parsePathData(ZonePtr z); + virtual void parseGetData(ZonePtr z); + virtual void parseDoorData(ZonePtr z); +protected: + void parseAnswerCounter(Answer *answer); virtual Answer *parseAnswer(); public: diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index b1dd86a693..563faa16e6 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -808,26 +808,27 @@ void LocationParser_br::parseDoorData(ZonePtr z) { } } +typedef void (LocationParser_br::*ZoneTypeParser)(ZonePtr); +static ZoneTypeParser parsers[] = { + 0, // no type + &LocationParser_br::parseExamineData, + &LocationParser_br::parseDoorData, + &LocationParser_br::parseGetData, + &LocationParser_br::parseMergeData, + 0, // taste + &LocationParser_br::parseHearData, + 0, // feel + &LocationParser_br::parseSpeakData, + 0, // none + 0, // trap + 0, // you + 0, // command + &LocationParser_br::parsePathData, + 0, // box +}; + void LocationParser_br::parseZoneTypeBlock(ZonePtr z) { debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type); - typedef void (LocationParser_br::*ZoneTypeParser)(ZonePtr); - ZoneTypeParser parsers[] = { - 0, // no type - &LocationParser_br::parseExamineData, - &LocationParser_br::parseDoorData, - &LocationParser_br::parseGetData, - &LocationParser_br::parseMergeData, - 0, // taste - &LocationParser_br::parseHearData, - 0, // feel - &LocationParser_br::parseSpeakData, - 0, // none - 0, // trap - 0, // you - 0, // command - &LocationParser_br::parsePathData, - 0, // box - }; ZoneTypeParser p = parsers[ACTIONTYPE(z)]; do { diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 9971828c31..1c06f86bfa 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1411,24 +1411,25 @@ void LocationParser_ns::parseSpeakData(ZonePtr z) { } } +typedef void (LocationParser_ns::*ZoneTypeParser)(ZonePtr); +static ZoneTypeParser parsers[] = { + 0, // no type + &LocationParser_ns::parseExamineData, + &LocationParser_ns::parseDoorData, + &LocationParser_ns::parseGetData, + &LocationParser_ns::parseMergeData, + 0, // taste + &LocationParser_ns::parseHearData, + 0, // feel + &LocationParser_ns::parseSpeakData, + 0, // none + 0, // trap + 0, // you + 0 // command +}; + void LocationParser_ns::parseZoneTypeBlock(ZonePtr z) { debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type); - typedef void (LocationParser_ns::*ZoneTypeParser)(ZonePtr); - ZoneTypeParser parsers[] = { - 0, // no type - &LocationParser_ns::parseExamineData, - &LocationParser_ns::parseDoorData, - &LocationParser_ns::parseGetData, - &LocationParser_ns::parseMergeData, - 0, // taste - &LocationParser_ns::parseHearData, - 0, // feel - &LocationParser_ns::parseSpeakData, - 0, // none - 0, // trap - 0, // you - 0 // command - }; ZoneTypeParser p = parsers[ACTIONTYPE(z)]; do { diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 5db0e732ee..d95decfd4f 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -67,16 +67,6 @@ public: virtual void reflowLayout(); }; -Common::String SaveLoad_ns::genOldSaveFileName(uint slot) { - assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); - - char s[20]; - sprintf(s, "game.%i", slot); - - return Common::String(s); -} - - Common::String SaveLoad::genSaveFileName(uint slot) { assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); @@ -430,55 +420,55 @@ void SaveLoad_ns::getGamePartProgress(bool *complete, int size) { complete[2] = s.contains("dough"); } -void SaveLoad_ns::renameOldSavefiles() { +static bool askRenameOldSavefiles() { + GUI::MessageDialog dialog0( + "ScummVM found that you have old savefiles for Nippon Safes that should be renamed.\n" + "The old names are no longer supported, so you will not be able to load your games if you don't convert them.\n\n" + "Press OK to convert them now, otherwise you will be asked next time.\n", "OK", "Cancel"); - bool exists[NUM_SAVESLOTS]; - uint num = 0; - uint i; + return (dialog0.runModal() != 0); +} - for (i = 0; i < NUM_SAVESLOTS; i++) { - exists[i] = false; - Common::String name = genOldSaveFileName(i); - Common::InSaveFile *f = _saveFileMan->openForLoading(name); - if (f) { - exists[i] = true; - num++; +void SaveLoad_ns::renameOldSavefiles() { + Common::StringList oldFilenames = _saveFileMan->listSavefiles("game.*"); + uint numOldSaves = oldFilenames.size(); + + bool rename = false; + uint success = 0, id; + Common::String oldName, newName; + for (uint i = 0; i < oldFilenames.size(); ++i) { + oldName = oldFilenames[i]; + int e = sscanf(oldName.c_str(), "game.%u", &id); + if (e != 1) { + // this wasn't a savefile, so adjust numOldSaves accordingly + --numOldSaves; + continue; } - delete f; - } - - if (num == 0) { - // there are no old savefiles: nothing to do - return; - } - GUI::MessageDialog dialog0( - "ScummVM found that you have old savefiles for Nippon Safes that should be renamed.\n" - "The old names are no longer supported, so you will not be able to load your games if you don't convert them.\n\n" - "Press OK to convert them now, otherwise you will be asked you next time.\n", "OK", "Cancel"); + if (!rename) { + rename = askRenameOldSavefiles(); + } + if (!rename) { + // return immediately if the user doesn't want to rename the files + return; + } - int choice = dialog0.runModal(); - if (choice == 0) { - // user pressed cancel - return; + newName = genSaveFileName(id); + if (_saveFileMan->renameSavefile(oldName, newName)) { + success++; + } else { + warning("Error %i (%s) occurred while renaming %s to %s", _saveFileMan->getError(), + _saveFileMan->getErrorDesc().c_str(), oldName.c_str(), newName.c_str()); + } } - uint success = 0; - for (i = 0; i < NUM_SAVESLOTS; i++) { - if (exists[i]) { - Common::String oldName = genOldSaveFileName(i); - Common::String newName = genSaveFileName(i); - if (_saveFileMan->renameSavefile(oldName, newName)) { - success++; - } else { - warning("Error %i (%s) occurred while renaming %s to %s", _saveFileMan->getError(), - _saveFileMan->getErrorDesc().c_str(), oldName.c_str(), newName.c_str()); - } - } + if (numOldSaves == 0) { + // there were no old savefiles: nothing to notify + return; } char msg[200]; - if (success == num) { + if (success == numOldSaves) { sprintf(msg, "ScummVM successfully converted all your savefiles."); } else { sprintf(msg, diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h index 2b2a7ab6a5..0bcc930c8a 100644 --- a/engines/parallaction/saveload.h +++ b/engines/parallaction/saveload.h @@ -62,7 +62,6 @@ public: class SaveLoad_ns : public SaveLoad { Parallaction_ns *_vm; - Common::String genOldSaveFileName(uint slot); protected: void renameOldSavefiles(); diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp index bac7c5f419..ae223ff6cf 100644 --- a/engines/queen/display.cpp +++ b/engines/queen/display.cpp @@ -25,6 +25,7 @@ #include "common/system.h" +#include "common/EventRecorder.h" #include "common/events.h" #include "graphics/cursorman.h" @@ -74,7 +75,7 @@ Display::Display(QueenEngine *vm, OSystem *system) memset(&_dynalum, 0, sizeof(_dynalum)); setupInkColors(); - system->getEventManager()->registerRandomSource(_rnd, "queenDisplay"); + g_eventRec.registerRandomSource(_rnd, "queenDisplay"); } Display::~Display() { diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp index 8a50ae6b40..3d5bfbdf73 100644 --- a/engines/queen/music.cpp +++ b/engines/queen/music.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "queen/music.h" #include "queen/queen.h" @@ -84,7 +85,7 @@ MidiMusic::MidiMusic(QueenEngine *vm) _parser->setMidiDriver(this); _parser->setTimerRate(_driver->getBaseTempo()); - vm->getEventManager()->registerRandomSource(_rnd, "queenMusic"); + g_eventRec.registerRandomSource(_rnd, "queenMusic"); } MidiMusic::~MidiMusic() { diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index ec074190d3..7c351842c4 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -31,6 +31,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "queen/queen.h" #include "queen/bankman.h" @@ -193,7 +194,7 @@ namespace Queen { QueenEngine::QueenEngine(OSystem *syst) : Engine(syst), _debugger(0) { - syst->getEventManager()->registerRandomSource(randomizer, "queen"); + g_eventRec.registerRandomSource(randomizer, "queen"); } QueenEngine::~QueenEngine() { diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index faf9cbed80..265008992a 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -204,7 +204,7 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { // Obtain the last 2 digits of the filename, since they correspond to the save slot slotNum = atoi(file->c_str() + file->size() - 2); - if (slotNum >= 0 && slotNum <= 99) { + if (slotNum >= 0 && slotNum < MAX_SAVES) { Common::InSaveFile *in = saveFileMan->openForLoading(*file); if (in) { for (int i = 0; i < 3; i++) @@ -219,7 +219,7 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { return saveList; } -int SagaMetaEngine::getMaximumSaveSlot() const { return 99; } +int SagaMetaEngine::getMaximumSaveSlot() const { return MAX_SAVES - 1; } void SagaMetaEngine::removeSaveState(const char *target, int slot) const { char extension[6]; diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index d58d1a8900..8b9b45d3ff 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -143,10 +143,7 @@ void Font::createOutline(FontData *font) { int i; int row; int newByteWidth; - int oldByteWidth; int newRowLength = 0; - size_t indexOffset = 0; - int index; int currentByte; unsigned char *basePointer; unsigned char *srcPointer; @@ -154,57 +151,22 @@ void Font::createOutline(FontData *font) { unsigned char *destPointer2; unsigned char *destPointer3; unsigned char charRep; - int nextIndex = 0; - // Populate new font style character data for (i = 0; i < FONT_CHARCOUNT; i++) { newByteWidth = 0; - oldByteWidth = 0; - index = font->normal.fontCharEntry[i].index; - if ((index > 0) || (i == FONT_FIRSTCHAR)) { - index += indexOffset; - } - - bool skip = false; - - if (font->normal.fontCharEntry[i].width != 0 && font->normal.fontCharEntry[i].index < nextIndex) { - // Some characters are copies of earlier characters. - // Look up the original, and make sure not to grow the size of - // the outline font twice. - skip = true; - bool found = false; - for (int j = 0; j < i; j++) { - if (font->normal.fontCharEntry[i].index == font->normal.fontCharEntry[j].index) { - index = font->outline.fontCharEntry[j].index; - found = true; - break; - } - } - if (!found) - error("Invalid index backreference in font char %d", i); - } - font->outline.fontCharEntry[i].index = index; + font->outline.fontCharEntry[i].index = newRowLength; font->outline.fontCharEntry[i].tracking = font->normal.fontCharEntry[i].tracking; font->outline.fontCharEntry[i].flag = font->normal.fontCharEntry[i].flag; - if (font->normal.fontCharEntry[i].width != 0) { + if (font->normal.fontCharEntry[i].width != 0) newByteWidth = getByteLen(font->normal.fontCharEntry[i].width + 2); - oldByteWidth = getByteLen(font->normal.fontCharEntry[i].width); - - if (!skip && newByteWidth > oldByteWidth) { - indexOffset++; - } - } font->outline.fontCharEntry[i].width = font->normal.fontCharEntry[i].width + 2; font->outline.fontCharEntry[i].byteWidth = newByteWidth; - if (!skip) { - newRowLength += newByteWidth; - nextIndex = font->normal.fontCharEntry[i].index + oldByteWidth; - } + newRowLength += newByteWidth; } debug(2, "New row length: %d", newRowLength); @@ -220,10 +182,6 @@ void Font::createOutline(FontData *font) { // Generate outline font representation for (i = 0; i < FONT_CHARCOUNT; i++) { - if (i > 0 && font->normal.fontCharEntry[i].index < font->normal.fontCharEntry[i-1].index) { - // Skip copies - continue; - } for (row = 0; row < font->normal.header.charHeight; row++) { for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) { basePointer = font->outline.font + font->outline.fontCharEntry[i].index + currentByte; diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 4acf93d030..2a2a4b993c 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -29,6 +29,7 @@ #include "common/config-manager.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "sound/mixer.h" @@ -114,7 +115,7 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); _displayClip.left = _displayClip.top = 0; - syst->getEventManager()->registerRandomSource(_rnd, "saga"); + g_eventRec.registerRandomSource(_rnd, "saga"); } SagaEngine::~SagaEngine() { diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 7c1a165ec1..2ddc6979c9 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -194,6 +194,7 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { scriptState.seekLevel = 0; scriptState.runningStep = 0; scriptState.stopOnEvent = false; + scriptState.debugging = false; } Console::~Console() { @@ -2091,28 +2092,30 @@ bool Console::cmdBacktrace(int argc, const char **argv) { printf("\n"); } - return 0; return true; } bool Console::cmdStep(int argc, const char **argv) { if (argc == 2 && atoi(argv[1]) > 0) scriptState.runningStep = atoi(argv[1]) - 1; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepEvent(int argc, const char **argv) { scriptState.stopOnEvent = true; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepRet(int argc, const char **argv) { scriptState.seeking = kDebugSeekLevelRet; scriptState.seekLevel = _vm->_gamestate->_executionStack.size() - 1; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepGlobal(int argc, const char **argv) { @@ -2124,8 +2127,9 @@ bool Console::cmdStepGlobal(int argc, const char **argv) { scriptState.seeking = kDebugSeekGlobal; scriptState.seekSpecial = atoi(argv[1]); + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepCallk(int argc, const char **argv) { @@ -2156,8 +2160,9 @@ bool Console::cmdStepCallk(int argc, const char **argv) { } else { scriptState.seeking = kDebugSeekCallk; } + scriptState.debugging = true; - return true; + return false; } bool Console::cmdDissassemble(int argc, const char **argv) { @@ -2227,7 +2232,7 @@ bool Console::cmdDissassembleAddress(int argc, const char **argv) { _vm->_gamestate->seg_manager->dereference(vpc, &size); size += vpc.offset; // total segment size - for (int i = 1; i < argc; i++) { + for (int i = 2; i < argc; i++) { if (!scumm_stricmp(argv[i], "bwt")) do_bwc = 1; else if (!scumm_stricmp(argv[i], "bc")) @@ -2322,14 +2327,16 @@ bool Console::cmdSend(int argc, const char **argv) { xstack->fp += argc; _vm->_gamestate->_executionStackPosChanged = true; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdGo(int argc, const char **argv) { + // CHECKME: is this necessary? scriptState.seeking = kDebugSeekNothing; - return true; + return Cmd_Exit(argc, argv); } bool Console::cmdBreakpointList(int argc, const char **argv) { diff --git a/engines/sci/debug.h b/engines/sci/debug.h index cd2de2b3a9..a3c4fab372 100644 --- a/engines/sci/debug.h +++ b/engines/sci/debug.h @@ -38,6 +38,7 @@ enum DebugSeeking { }; struct ScriptState { + bool debugging; bool stopOnEvent; DebugSeeking seeking; // Stepping forward until some special condition is met int runningStep; // Set to > 0 to allow multiple stepping diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 92cfe9daf3..11dd56f2aa 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -311,11 +311,18 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod void script_debug(EngineState *s, bool bp) { // Do we support a separate console? - printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc)); - disassemble(s, scriptState.xs->addr.pc, 0, 1); - if (scriptState.seeking == kDebugSeekGlobal) - printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial, - scriptState.seekSpecial, PRINT_REG(s->script_000->locals_block->_locals[scriptState.seekSpecial])); + /* if (sci_debug_flags & _DEBUG_FLAG_LOGGING) { */ + printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc)); + disassemble(s, scriptState.xs->addr.pc, 0, 1); + if (scriptState.seeking == kDebugSeekGlobal) + printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial, + scriptState.seekSpecial, PRINT_REG(s->script_000->locals_block->_locals[scriptState.seekSpecial])); + /* } */ + +#if 0 + if (!scriptState.debugging) + return; +#endif if (scriptState.seeking && !bp) { // Are we looking for something special? MemObject *mobj = GET_SEGMENT(*s->seg_manager, scriptState.xs->addr.pc.segment, MEM_OBJ_SCRIPT); @@ -370,9 +377,19 @@ void script_debug(EngineState *s, bool bp) { // OK, found whatever we were looking for } } - + printf("Step #%d\n", script_step_counter); disassemble(s, scriptState.xs->addr.pc, 0, 1); + + if (scriptState.runningStep) { + scriptState.runningStep--; + return; + } + + scriptState.debugging = false; + + Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); + con->attach(); } } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 6752ba3e56..905cba9d94 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -169,7 +169,9 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) { setScriptSize(scr, s, script_nr); scr.buf = (byte *)malloc(scr.buf_size); - dbgPrint("scr.buf ", scr.buf); +#ifdef DEBUG_SEG_MANAGER + printf("scr.buf = %p ", scr.buf); +#endif if (!scr.buf) { scr.freeScript(); warning("SegManager: Not enough memory space for script size"); @@ -864,14 +866,5 @@ int SegManager::freeDynmem(reg_t addr) { return 0; // OK } -void SegManager::dbgPrint(const char* msg, void *i) { -#ifdef DEBUG_SEG_MANAGER - char buf[1000]; - sprintf(buf, "%s = [0x%x], dec:[%d]", msg, i, i); - perror(buf); -#endif -} - - } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index a41d820014..9d406f559f 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -362,13 +362,6 @@ private: * 'seg' is a valid segment */ bool check(SegmentId seg); - - void dbgPrint(const char* msg, void *i); // for debug only - - // Perform garbage collection - // Parameters: (EngineState *) s: The state to operate on - // Effects : Unreachable objects in 's' are deallocated - //void sm_gc(EngineState *s); }; } // End of namespace Sci diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 99b5a86e53..0f8fee0876 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -258,6 +258,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP if (bp->type == BREAK_EXPORT && bp->data.address == bpaddress) { Console *con = ((SciEngine *)g_engine)->getSciDebugger(); con->DebugPrintf("Break on script %d, export %d\n", script, pubfunct); + scriptState.debugging = true; breakpointFlag = true; break; } @@ -325,6 +326,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt con->DebugPrintf("Break on %s (in [%04x:%04x])\n", method_name, PRINT_REG(send_obj)); print_send_action = 1; breakpointFlag = true; + scriptState.debugging = true; break; } bp = bp->next; @@ -652,17 +654,19 @@ void run_vm(EngineState *s, int restoring) { } - if (script_abort_flag) + if (script_abort_flag || g_engine->shouldQuit()) return; // Emergency -// TODO: re-enable this -#if 0 // Debug if this has been requested: - if (script_debug_flag || sci_debug_flags) { + // TODO: re-implement sci_debug_flags + if (scriptState.debugging /* sci_debug_flags*/) { script_debug(s, breakpointFlag); breakpointFlag = false; } -#endif + Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); + if (con->isAttached()) { + con->onFrame(); + } #ifndef DISABLE_VALIDATIONS if (scriptState.xs->sp < scriptState.xs->fp) diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index f711570d11..ba225a9c00 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -266,18 +266,19 @@ struct ExecStack { }; +// These types are used both as identifiers and as elements of bitfields enum BreakpointType { /** * Break when selector is executed. data contains (char *) selector name * (in the format Object::Method) */ - BREAK_SELECTOR, + BREAK_SELECTOR = 1, /** * Break when an exported function is called. data contains * script_no << 16 | export_no. */ - BREAK_EXPORT + BREAK_EXPORT = 2 }; struct Breakpoint { diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 6b15cdc516..94bb6e0443 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -1380,7 +1380,6 @@ static sci_event_t scummvm_get_event(GfxDriver *drv) { // Open debug console Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); con->attach(); - con->onFrame(); // Clear keyboard event input.type = SCI_EVT_NONE; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index d99f9f0771..943361332f 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -882,7 +882,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, if (resnumber == -1) return; if (!file.open(source->location_name)) { - perror("""__FILE__"": (""__LINE__""): failed to open"); + warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str()); return; } fsize = file.size(); @@ -1007,8 +1007,7 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) { offset = file.readUint32LE(); if (file.ioFailed()) { - warning("Error while reading %s: ", map->location_name.c_str()); - perror(""); + warning("Error while reading %s", map->location_name.c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } if (offset == 0xFFFFFFFF) @@ -1079,8 +1078,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { } } if (file.ioFailed()) { - warning("Error while reading %s: ", map->location_name.c_str()); - perror(""); + warning("Error while reading %s", map->location_name.c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } resId = ResourceId((ResourceType)type, number); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 504e38c7c1..65d0a4753a 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -283,9 +283,7 @@ uint32 SciEngine::getFlags() const { } Common::String SciEngine::getSavegameName(int nr) const { - char extension[6]; - snprintf(extension, sizeof(extension), ".%03d", nr); - return _targetName + extension; + return _targetName + Common::String::printf(".%03d", nr); } Common::String SciEngine::getSavegamePattern() const { diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 88c258a2e6..3033904357 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -527,9 +527,15 @@ void Actor_v2::walkActor() { if (_moving & MF_TURN) { new_dir = updateActorDirection(false); // FIXME: is this correct? - if (_facing != new_dir) + if (_facing != new_dir) { + + // Actor never stops walking when an object has been selected without this + if (_vm->_game.version ==0) + _moving = 0; + setDirection(new_dir); - else + + } else _moving = 0; return; } @@ -817,6 +823,16 @@ void Actor::setDirection(int direction) { if (_costume == 0) return; + // V0 MM + if (_vm->_game.version == 0) { + if (_moving) + _vm->_costumeLoader->costumeDecodeData(this, _walkFrame, 0); + else + _vm->_costumeLoader->costumeDecodeData(this, _standFrame, 0); + _needRedraw = true; + return; + } + // Update the costume for the new direction (and mark the actor for redraw) aMask = 0x8000; for (i = 0; i < 16; i++, aMask >>= 1) { @@ -1224,7 +1240,10 @@ void Actor::showActor() { _vm->ensureResourceLoaded(rtCostume, _costume); - if (_vm->_game.version <= 2) { + if (_vm->_game.version == 0) { + _cost.reset(); + startAnimActor(_standFrame); + } else if (_vm->_game.version <= 2) { _cost.reset(); startAnimActor(_standFrame); startAnimActor(_initFrame); @@ -1380,6 +1399,13 @@ void ScummEngine::processActors() { Actor** end = _sortedActors + numactors; for (Actor** ac = _sortedActors; ac != end; ++ac) { Actor* a = *ac; + + // V0 MM: 0x057B + if (_game.version == 0) { + ActorC64 *A = (ActorC64*) a; + if ((A->_speaking & 1)) + A->_speaking ^= 0xFE; + } // Draw and animate the actors, except those w/o a costume. // Note: We could 'optimize' this a little bit by only putting // actors with a costume into the _sortedActors array in the @@ -1572,6 +1598,8 @@ void Actor_v2::prepareDrawActorCostume(BaseCostumeRenderer *bcr) { // we need to shift it 8 pixels to the left if (_facing == 90) bcr->_actorX -= 8; + } else if (_vm->_game.version == 0) { + bcr->_actorX += 12; } else if (_vm->_game.version <= 2) { // HACK: We have to adjust the x position by one strip (8 pixels) in // V2 games. However, it is not quite clear to me why. And to fully @@ -1703,6 +1731,12 @@ void Actor::animateActor(int anim) { case 4: // turn to new direction turnToDirection(dir); break; + case 64: + if (_vm->_game.version == 0) { + _moving &= ~MF_TURN; + setDirection(dir); + break; + } default: if (_vm->_game.version <= 2) startAnimActor(anim / 4); @@ -2167,21 +2201,38 @@ void Actor::setActorCostume(int c) { } } -static const char* v0ActorNames[7] = { +static const char* v0ActorNames[0x19] = { "Syd", "Razor", "Dave", "Michael", "Bernard", "Wendy", - "Jeff" + "Jeff", + "", + "Dr Fred", + "Nurse Edna", + "Weird Ed", + "Dead Cousin Ted", + "Purple Tentacle", + "Green Tentacle", + "Meteor", + "Plant", + "", + "", + "", + "", + "", + "", + "Sandy" }; const byte *Actor::getActorName() { - const byte *ptr; + const byte *ptr = NULL; if (_vm->_game.version == 0) { - ptr = (const byte *)v0ActorNames[_number - 1]; + if (_number) + ptr = (const byte *)v0ActorNames[_number - 1]; } else { ptr = _vm->getResourceAddress(rtActorName, _number); } diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3e8fe6626b..3f67d42a50 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -380,11 +380,15 @@ protected: class ActorC64 : public Actor_v2 { public: - // FIXME: This flag is never saved, which might lead to broken save states. + // FIXME: These vars are never saved, which might lead to broken save states. byte _miscflags; + byte _speaking, _speakingPrev; + byte _costCommand, _costFrame; public: - ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {} + ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) { + _speaking = _speakingPrev = _costCommand = _costFrame = 0; + } virtual void initActor(int mode) { Actor_v2::initActor(mode); if (mode == -1) { diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp index 472e04b5f3..d480209501 100644 --- a/engines/scumm/boxes.cpp +++ b/engines/scumm/boxes.cpp @@ -445,7 +445,7 @@ byte ScummEngine::getNumBoxes() { return 0; if (_game.version == 8) return (byte)READ_LE_UINT32(ptr); - else if (_game.features >= 5) + else if (_game.version >= 5) return (byte)READ_LE_UINT16(ptr); else return ptr[0]; diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 82497de87a..57b793d579 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -1040,26 +1040,25 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (limb >= 8) return 0; + if (a->_cost.start[limb] == 0xFFFF) + return 0; + if (limb == 0) { _draw_top = 200; _draw_bottom = 0; } + + bool flipped = (a->_cost.start[limb] & 0x80) != 0; + byte frameStart = _loaded._frameOffsets[a->_cost.frame[limb]]; + byte frame = _loaded._frameOffsets[frameStart + a->_cost.curpos[limb]]; + if (frame == 0xFF) + return 0; - // TODO: - // get out how animations are handled - byte state = a->_moving != 0 ? 0 : 1; - byte unk1 = (_loaded._animCmds + (state*32) + newDirToOldDir(a->getFacing()) * 8)[limb]; - byte unk2 = _loaded._frameOffsets[_loaded._frameOffsets[limb] + (unk1 & 0x7f)]; - bool flipped = (unk1 & 0x80) != 0; - - byte p1 = _loaded._frameOffsets[unk2]; - byte temp1 = _loaded._baseptr[p1]; - byte temp2 = temp1 + _loaded._dataOffsets[4]; - int offL = _loaded._baseptr[temp1 + 2]; - int offH = _loaded._baseptr[temp2]; - int off = (offH << 8) + offL; + byte ptrLow = _loaded._baseptr[frame]; + byte ptrHigh = ptrLow + _loaded._dataOffsets[4]; + int frameOffset = (_loaded._baseptr[ptrHigh] << 8) + _loaded._baseptr[ptrLow + 2]; // 0x23EF / 0x2400 - const byte *data = _loaded._baseptr + off; + const byte *data = _loaded._baseptr + frameOffset; // Set up the palette data byte palette[4] = { 0, 0, 0, 0 }; @@ -1077,8 +1076,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int offsetY = *data++; // these two fields seems to be most times zero // byte6 was one time 255 in one costume I tried -// int byte5 = *data++; -// int byte6 = *data++; +// int byte5 = *data++; // 0x1F80 // This value is never used +// int byte6 = *data++; // 0x1F86 // This value is subtracted from ?actor drawy? at 0x2383 // debug(3, "byte5: %d", byte5); // debug(3, "byte6: %d", byte6); data += 2; @@ -1091,17 +1090,13 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (flipped) { if (offsetX) - xpos += (offsetX-1) * 8; + xpos += (offsetX - 1) * 8; } else { xpos += offsetX * 8; } - // + 4 could be commented, because maybe the _actorX position is - // wrong, I looked at the scumm-c64 interpreter by lloyd - // and there Bernhard is directly on the right in the intro - // but here in ScummVM he is 4 pixel left of the other position. - xpos += _actorX - (a->_width / 2) + 4; - ypos += _actorY - _loaded._maxHeight; + xpos += _actorX - (a->_width / 2); + ypos += (_actorY - _loaded._maxHeight) + 1; // +1 as we appear to be 1 pixel away from the original interpreter // This code is very similar to procC64() for (int y = 0; y < height; ++y) { @@ -1111,9 +1106,9 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int realX = 0; if (flipped) { if (offsetX == 0||offsetX == 1) { - realX = width-(x+1); + realX = width-(x + 1); } else if (offsetX == 2) { - realX = width-(x+2); + realX = width-(x + 2); } } else { realX = x; @@ -1134,10 +1129,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { } _draw_top = MIN(_draw_top, ypos); - _draw_bottom = MAX(_draw_bottom, ypos+height); - // if +4 above is NOT commented, here "+(flipped ? 4 : 0)" can be commented out - // and other way round - _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos+(width*8)/*+(flipped ? 4 : 0)*/, ypos, ypos+height, _actorID); + _draw_bottom = MAX(_draw_bottom, ypos + height); + _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos + (width * 8), ypos, ypos + height, _actorID); return 0; } @@ -1151,6 +1144,7 @@ void C64CostumeRenderer::setCostume(int costume, int shadow) { void C64CostumeLoader::loadCostume(int id) { const byte *ptr = _vm->getResourceAddress(rtCostume, id); + _id = id; _baseptr = ptr + 9; @@ -1165,33 +1159,152 @@ void C64CostumeLoader::loadCostume(int id) { _animCmds = _baseptr + READ_LE_UINT16(ptr + 7); _maxHeight = 0; - for (int i = 0; i < 8; ++i) { - int pid = _frameOffsets[_frameOffsets[i]]; - byte p1 = _frameOffsets[pid]; - byte b = _baseptr[p1]; - byte c = b + _dataOffsets[4]; - int offL = _baseptr[b + 2]; - int offH = _baseptr[c]; - int off = (offH << 8) + offL; - const byte *data = _baseptr + off; - - if (data[3] > _maxHeight) { - _maxHeight = data[3]; // data[3] is libs's Y offset +} + +void C64CostumeLoader::frameUpdate(ActorC64 *a, int cmd ) { + byte limbFrames = 0; + + // Each costume-command has 8 limbs (0x2622) + cmd <<= 3; + + for (int limb = 0, pos = 0; limb < 8; ++limb, pos = 0) { + // get a limb frames ptr from the costume command + limbFrames = ((_animCmds + cmd)[limb]); + + // Dont change limb if entry is invalid + if (limbFrames == 0xFF) + continue; + + // Has limb frames ptr changed since last update? + if (a->_cost.start[limb] == limbFrames) + continue; + + // Set new limb command addresses + a->_cost.start[limb] = limbFrames; + a->_cost.frame[limb] = _frameOffsets[limb] + (limbFrames & 0x7f); // limb animation-frames ptr + + // Get first entry of a limbs' frames + byte frameStart = _frameOffsets[ a->_cost.frame[limb]]; + + // Loop each frame in this limb until we reach the end marker + while (pos != 0xFF) { // This is just so we dont overflow + byte frame = _frameOffsets[frameStart + pos]; + + // Each animation-frame until we find end + if (frame == 0xFF) + break; + + byte ptrLow = _baseptr[frame]; + byte ptrHigh = ptrLow + _dataOffsets[4]; + int frameOffset = (_baseptr[ptrHigh] << 8) + _baseptr[ptrLow + 2]; // 0x23EF / 0x2400 + + const byte *data = _baseptr + frameOffset; + + if (data[3] > _maxHeight) + _maxHeight = data[3] + 1; + + ++pos; } + + // Set ending position of limb frames + a->_cost.end[limb] = pos - 1; + a->_cost.curpos[limb] = 0; } - ++_maxHeight; } -void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { +// based on 0x2BCA, doesn't match disassembly because 'oldDir' variable +// is not the same value as stored in the original interpreter +int C64CostumeLoader::dirToDirStop(int oldDir) { + switch (oldDir) { + case 0: + return 4; // Left + case 1: + return 5; // Right + case 2: + return 6; // Face Camera + case 3: + return 7; // Face Away + } + // shouldnt' be reached + return 4; } -byte C64CostumeLoader::increaseAnims(Actor *a) { - return 0; +void C64CostumeLoader::actorSpeak(ActorC64 *a, int &cmd) { + if ((a->_speaking & 0x80)) + cmd += 0x0C; + else + cmd += 0x10; } -byte C64CostumeLoader::increaseAnim(Actor *a, int slot) { - return 0; +void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { + ActorC64 *A = (ActorC64 *)a; + int dir = newDirToOldDir(a->getFacing()); + int command = dir; + + loadCostume(a->_costume); + + // Enable/Disable speaking flag + if (frame == a->_talkStartFrame) { + A->_speaking = 1; + return; + } + if (frame == a->_talkStopFrame) { + A->_speaking = 0; + return; + } + + // Different command for stand frame + if (frame == a->_standFrame) + command = dirToDirStop(dir); + + // Update the limb frames + frameUpdate(A, command); + + // Keep current command/frame mode + A->_costCommand = dir; + A->_costFrame = frame; + + // Update 'speaking' frames? + if (A->_speaking) { + command = dir; // Incase standing frame was set as cmd + actorSpeak(A, command); + + // Update the limb speak frames + frameUpdate(A, command); + } } +byte C64CostumeLoader::increaseAnims(Actor *a) { + ActorC64 *A = (ActorC64 *)a; + + // check if the actor speak flag has changed since last frame increase + if (A->_speaking != A->_speakingPrev) { + int cmd = A->_costCommand; + A->_speakingPrev = A->_speaking; + + // Update to use speak frame + if (A->_speaking & 0x80) { + actorSpeak(A, cmd); + + } else { + // Update to use stand frame + if (A->_costFrame == A->_standFrame) + cmd = dirToDirStop(cmd); + } + + // Update the limb frames + frameUpdate(A, cmd); + } + + // increase each frame pos + for (int limb = 0; limb < 8; ++limb) { + if (a->_cost.curpos[limb] < a->_cost.end[limb]) + a->_cost.curpos[limb]++; + else + a->_cost.curpos[limb] = 0; + } + + return 1; +} } // End of namespace Scumm diff --git a/engines/scumm/costume.h b/engines/scumm/costume.h index 003bd6ce2b..8e1910abcf 100644 --- a/engines/scumm/costume.h +++ b/engines/scumm/costume.h @@ -79,8 +79,12 @@ public: byte increaseAnims(Actor *a); int _maxHeight; + protected: - byte increaseAnim(Actor *a, int slot); + void actorSpeak(ActorC64 *a, int &cmd); + int dirToDirStop(int oldDir); + void frameUpdate(ActorC64 *A, int cmd); + }; class ClassicCostumeRenderer : public BaseCostumeRenderer { diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 5fa74d22c3..8beb2ef720 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -723,6 +723,32 @@ GameDescriptor ScummMetaEngine::findGame(const char *gameid) const { return AdvancedDetector::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable); } +static Common::String generatePreferredTarget(const DetectorResult &x) { + Common::String res(x.game.gameid); + + if (x.game.preferredTag) { + res = res + "-" + x.game.preferredTag; + } + + if (x.game.features & GF_DEMO) { + res = res + "-demo"; + } + + // Append the platform, if a non-standard one has been specified. + if (x.game.platform != Common::kPlatformPC && x.game.platform != Common::kPlatformUnknown) { + // HACK: For CoMI, it's pointless to encode the fact that it's for Windows + if (x.game.id != GID_CMI) + res = res + "-" + Common::getPlatformAbbrev(x.game.platform); + } + + // Append the language, if a non-standard one has been specified + if (x.language != Common::EN_ANY && x.language != Common::UNK_LANG) { + res = res + "-" + Common::getLanguageCode(x.language); + } + + return res; +} + GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; Common::List<DetectorResult> results; @@ -737,34 +763,34 @@ GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const { const PlainGameDescriptor *g = findPlainGameDescriptor(x->game.gameid, gameDescriptions); assert(g); GameDescriptor dg(x->game.gameid, g->description, x->language, x->game.platform); - dg.updateDesc(x->extra); // Append additional information, if set, to the description. + + // Append additional information, if set, to the description. + dg.updateDesc(x->extra); // Compute and set the preferred target name for this game. // Based on generateComplexID() in advancedDetector.cpp. - Common::String res(x->game.gameid); - - if (x->game.preferredTag) { - res = res + "-" + x->game.preferredTag; - } - - if (x->game.features & GF_DEMO) { - res = res + "-demo"; - } - - // Append the platform, if a non-standard one has been specified. - if (x->game.platform != Common::kPlatformPC && x->game.platform != Common::kPlatformUnknown) { - // HACK: For CoMI, it's pointless to encode the fact that it's for Windows - if (x->game.id != GID_CMI) - res = res + "-" + Common::getPlatformAbbrev(x->game.platform); - } - - // Append the language, if a non-standard one has been specified - if (x->language != Common::EN_ANY && x->language != Common::UNK_LANG) { - res = res + "-" + Common::getLanguageCode(x->language); + dg["preferredtarget"] = generatePreferredTarget(*x); + + // HACK: Detect and distinguish the FM-TOWNS demos + if (x->game.platform == Common::kPlatformFMTowns && (x->game.features & GF_DEMO)) { + if (x->md5 == "2d388339d6050d8ccaa757b64633954e") { + // Indy + Loom demo + dg.description() = "Indiana Jones and the Last Crusade & Loom"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "indyloom"; + } else if (x->md5 == "77f5c9cc0986eb729c1a6b4c8823bbae") { + // Zak + Loom demo + dg.description() = "Zak McKracken & Loom"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "zakloom"; + } else if (x->md5 == "3938ee1aa4433fca9d9308c9891172b1") { + // Indy + Zak demo + dg.description() = "Indiana Jones and the Last Crusade & Zak McKracken"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "indyzak"; + } } - dg["preferredtarget"] = res; - dg.setGUIOptions(x->game.guioptions); detectedGames.push_back(dg); diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 92024a21cc..5054bffd30 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -230,14 +230,14 @@ static const GameSettings gameVariantsTable[] = { {"monkey2", 0, 0, GID_MONKEY2, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"atlantis", "CD" , 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NONE}, + {"atlantis", "" , 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NONE}, + {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"tentacle", "CD", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"samnmax", "", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"samnmax", "CD", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"samnmax", "", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"samnmax", "Floppy", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, #ifdef ENABLE_SCUMM_7_8 {"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO_NOMIDI}, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 880fab04a5..42e49afcc1 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -439,7 +439,7 @@ ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm) new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P'); new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L'); - new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S'); + _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S'); new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O'); #ifndef DISABLE_HELP @@ -471,6 +471,13 @@ ScummMenuDialog::~ScummMenuDialog() { delete _loadDialog; } +void ScummMenuDialog::reflowLayout() { + if (!_vm->canSaveGameStateCurrently()) + _saveButton->setEnabled(false); + + Dialog::reflowLayout(); +} + void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { case kSaveCmd: diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index af844272fa..d4ecbde534 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -88,6 +88,8 @@ public: ~ScummMenuDialog(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + virtual void reflowLayout(); + protected: ScummEngine *_vm; @@ -99,6 +101,8 @@ protected: SaveLoadChooser *_saveDialog; SaveLoadChooser *_loadDialog; + GUI::ButtonWidget *_saveButton; + void save(); void load(); }; diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 3f101691c7..6dc31b09ef 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -126,7 +126,7 @@ bool ScummFile::openSubFile(const Common::String &filename) { bool ScummFile::eos() const { - return _subFileLen ? (pos() >= _subFileLen) : File::eos(); // FIXME + return _subFileLen ? _myEos : File::eos(); } int32 ScummFile::pos() const { @@ -154,7 +154,10 @@ bool ScummFile::seek(int32 offs, int whence) { assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen)); whence = SEEK_SET; } - return File::seek(offs, whence); + bool ret = File::seek(offs, whence); + if (ret) + _myEos = false; + return ret; } uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { @@ -167,7 +170,7 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { int32 newPos = curPos + dataSize; if (newPos > _subFileLen) { dataSize = _subFileLen - curPos; - _myIoFailed = true; + _myEos = true; } } diff --git a/engines/scumm/file.h b/engines/scumm/file.h index aa52dd069f..c37c2f036e 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -55,7 +55,7 @@ private: byte _encbyte; int32 _subFileStart; int32 _subFileLen; - bool _myIoFailed; + bool _myEos; // Have we read past the end of the subfile? void setSubfileRange(int32 start, int32 len); void resetSubfile(); @@ -67,8 +67,7 @@ public: bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); - bool ioFailed() const { return _myIoFailed || BaseScummFile::ioFailed(); } - void clearIOFailed() { _myIoFailed = false; BaseScummFile::clearIOFailed(); } + void clearErr() { _myEos = false; BaseScummFile::clearErr(); } bool eos() const; int32 pos() const; diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 5961ec4013..18cba0ab4a 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -758,18 +758,18 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid } void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { - byte *dstL1 = dst; - byte *dstL2 = dst + dstPitch; + uint16 *dstL1 = (uint16 *)dst; + uint16 *dstL2 = (uint16 *)(dst + dstPitch); - int dstAdd = dstPitch * 2 - w * 2; - int srcAdd = srcPitch - w; + const int dstAdd = dstPitch - w; + const int srcAdd = srcPitch - w; while (h--) { - for (int x = 0; x < w; ++x, dstL1 += 2, dstL2 += 2) { + for (int x = 0; x < w; ++x) { uint16 col = *src++; col |= col << 8; - *(uint16*)(dstL1) = col; - *(uint16*)(dstL2) = col; + *dstL1++ = col; + *dstL2++ = col; } dstL1 += dstAdd; dstL2 += dstAdd; src += srcAdd; diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp index 51176c5df9..39615edb6a 100644 --- a/engines/scumm/he/cup_player_he.cpp +++ b/engines/scumm/he/cup_player_he.cpp @@ -91,20 +91,19 @@ void CUP_Player::close() { } void CUP_Player::play() { - while (parseNextHeaderTag(_fileStream)) { - if (_fileStream.ioFailed()) { - return; - } - } + while (parseNextHeaderTag(_fileStream)) { } + + if (_fileStream.eos() || _fileStream.err()) + return; + debug(1, "rate %d width %d height %d", _playbackRate, _width, _height); int ticks = _system->getMillis(); while (_dataSize != 0 && !_vm->shouldQuit()) { - while (parseNextBlockTag(_fileStream)) { - if (_fileStream.ioFailed()) { - return; - } - } + while (parseNextBlockTag(_fileStream)) { } + if (_fileStream.eos() || _fileStream.err()) + return; + int diff = _system->getMillis() - ticks; if (diff >= 0 && diff <= _playbackRate) { _system->delayMillis(_playbackRate - diff); @@ -200,6 +199,10 @@ void CUP_Player::waitForSfxChannel(int channel) { bool CUP_Player::parseNextHeaderTag(Common::SeekableReadStream &dataStream) { uint32 tag = dataStream.readUint32BE(); uint32 size = dataStream.readUint32BE() - 8; + + if (dataStream.eos()) + return false; + uint32 next = dataStream.pos() + size; debug(1, "New header tag %s %d dataSize %d", tag2str(tag), size, _dataSize); switch (tag) { diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index 4c2da19cc5..9e905b0e79 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -78,7 +78,7 @@ protected: int virtScreenSave(byte *dst, int x1, int y1, int x2, int y2); void virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2); - int convertFilePath(byte *dst); + int convertFilePath(byte *dst, int dstSize); virtual void decodeParseString(int a, int b); void swapObjects(int object1, int object2); diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index fe0904d632..84fec085cc 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -1621,7 +1621,7 @@ void ScummEngine_v100he::o100_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o100_roomOps: case 137: filename %s", _saveLoadFileName); @@ -2239,7 +2239,7 @@ void ScummEngine_v100he::o100_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename); + const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags == 2) { VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); } else { diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index 5ad447b1c7..f186495f81 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -93,7 +93,7 @@ void ScummEngine_v60he::setupOpcodes() { _opcodes[0xed].setProc(0, 0); } -int ScummEngine_v60he::convertFilePath(byte *dst) { +int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { debug(1, "convertFilePath: original filePath is %s", dst); int len = resStrLen(dst); @@ -113,16 +113,25 @@ int ScummEngine_v60he::convertFilePath(byte *dst) { // Strip path int r = 0; - if (dst[0] == '.' && dst[1] == '/') { // Game Data Path + if (dst[len - 3] == 's' && dst[len - 2] == 'g') { // Save Game File + // Change filename prefix to target name, for save game files. + char saveName[20]; + sprintf(saveName, "%s.sg%c", _targetName.c_str(), dst[len - 1]); + memcpy(dst, saveName, 20); + } else if (dst[0] == '.' && dst[1] == '/') { // Game Data Path + // The default game data path is set to './' by ScummVM r = 2; } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (HE72 - HE100) + // The default save game path is set to '*/' by ScummVM r = 2; } else if (dst[0] == 'c' && dst[1] == ':') { // Save Game Path (HE60 - HE71) + // The default save path is game path (DOS) or 'c:/hegames/' (Windows) for (r = len; r != 0; r--) { if (dst[r - 1] == '/') break; } } else if (dst[0] == 'u' && dst[1] == 's') { // Save Game Path (Moonbase Commander) + // The default save path is 'user/' r = 5; } @@ -269,7 +278,7 @@ void ScummEngine_v60he::o60_roomOps() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName); @@ -684,7 +693,7 @@ void ScummEngine_v60he::o60_openFile() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer); + filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "Final filename to %s", filename); mode = pop(); @@ -738,7 +747,7 @@ void ScummEngine_v60he::o60_deleteFile() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer); + filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "o60_deleteFile (\"%s\")", filename); @@ -760,8 +769,8 @@ void ScummEngine_v60he::o60_rename() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - oldFilename = (char *)buffer1 + convertFilePath(buffer1); - newFilename = (char *)buffer2 + convertFilePath(buffer2); + oldFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); + newFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); debug(1, "o60_rename (\"%s\" to \"%s\")", oldFilename, newFilename); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 64c63baa9d..6224ef5b47 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -713,7 +713,7 @@ void ScummEngine_v72he::o72_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName); @@ -1401,7 +1401,7 @@ void ScummEngine_v72he::o72_openFile() { strcpy((char *)buffer, "moonbase.ini"); } - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "Final filename to %s", filename); slot = -1; @@ -1547,7 +1547,7 @@ void ScummEngine_v72he::o72_deleteFile() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "o72_deleteFile(%s)", filename); @@ -1562,8 +1562,8 @@ void ScummEngine_v72he::o72_rename() { copyScriptString(buffer1, sizeof(buffer1)); copyScriptString(buffer2, sizeof(buffer2)); - const char *newFilename = (char *)buffer1 + convertFilePath(buffer1); - const char *oldFilename = (char *)buffer2 + convertFilePath(buffer2); + const char *newFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); + const char *oldFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); _saveFileMan->renameSavefile(oldFilename, newFilename); diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index b71a0f9e10..d7e36106ea 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -89,7 +89,7 @@ void ScummEngine_v80he::o80_getFileSize() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); Common::SeekableReadStream *f = 0; if (!_saveFileMan->listSavefiles(filename).empty()) { @@ -154,7 +154,7 @@ void ScummEngine_v80he::o80_readConfigFile() { copyScriptString(section, sizeof(section)); copyScriptString(filename, sizeof(filename)); - r = convertFilePath(filename); + r = convertFilePath(filename, sizeof(filename)); if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters @@ -222,7 +222,7 @@ void ScummEngine_v80he::o80_writeConfigFile() { error("o80_writeConfigFile: default type %d", subOp); } - r = convertFilePath(filename); + r = convertFilePath(filename, sizeof(filename)); if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index f97771a4f8..2da58b4480 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1426,7 +1426,7 @@ void ScummEngine_v90he::o90_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename); + const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags & 2) { VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); } else { diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index 4c20ed7835..6b1db38b23 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -2083,7 +2083,7 @@ void Wiz::processWizImage(const WizParameters *params) { Common::File f; memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + _vm->convertFilePath(filename, sizeof(filename)); if (f.open((const char *)filename)) { uint32 id = f.readUint32BE(); @@ -2126,7 +2126,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 0: memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + _vm->convertFilePath(filename, sizeof(filename)); if (!f.open((const char *)filename)) { debug(0, "Unable to open for write '%s'", filename); diff --git a/engines/scumm/imuse_digi/dimuse_bndmgr.cpp b/engines/scumm/imuse_digi/dimuse_bndmgr.cpp index 4577a11fe1..be5f7623ca 100644 --- a/engines/scumm/imuse_digi/dimuse_bndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_bndmgr.cpp @@ -225,7 +225,7 @@ bool BundleMgr::loadCompTable(int32 index) { _file->seek(8, SEEK_CUR); if (tag != MKID_BE('COMP')) { - error("BundleMgr::loadCompTable() Compressed sound %d invalid (%s)", index, tag2str(tag)); + error("BundleMgr::loadCompTable() Compressed sound %d (%s:%d) invalid (%s)", index, _file->getName(), _bundleTable[index].offset, tag2str(tag)); return false; } diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 61b714a3e2..ab32992b03 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -110,9 +110,9 @@ void ScummEngine_v80he::parseEvent(Common::Event event) { void ScummEngine::parseEvent(Common::Event event) { switch (event.type) { case Common::EVENT_KEYDOWN: - if (event.kbd.keycode >= '0' && event.kbd.keycode <= '9' - && (event.kbd.flags == Common::KBD_ALT || - event.kbd.flags == Common::KBD_CTRL)) { + if (event.kbd.keycode >= '0' && event.kbd.keycode <= '9' && + ((event.kbd.flags == Common::KBD_ALT && canSaveGameStateCurrently()) || + (event.kbd.flags == Common::KBD_CTRL && canLoadGameStateCurrently()))) { _saveLoadSlot = event.kbd.keycode - '0'; // don't overwrite autosave (slot 0) @@ -302,17 +302,6 @@ void ScummEngine::processInput() { // _mouseAndKeyboardStat = 0; - // Interpret 'return' as left click and 'tab' as right click - if (lastKeyHit.keycode && _cursor.state > 0) { - if (lastKeyHit.keycode == Common::KEYCODE_TAB) { - _mouseAndKeyboardStat = MBS_RIGHT_CLICK; - lastKeyHit.reset(); - } else if (lastKeyHit.keycode == Common::KEYCODE_RETURN) { - _mouseAndKeyboardStat = MBS_LEFT_CLICK; - lastKeyHit.reset(); - } - } - if ((_leftBtnPressed & msClicked) && (_rightBtnPressed & msClicked) && _game.version >= 4) { // Pressing both mouse buttons is treated as if you pressed // the cutscene exit key (ESC) in V4+ games. That mimicks diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index f29be071e0..2eab2cfa3a 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -181,7 +181,11 @@ void ScummEngine::clearOwnerOf(int obj) { // Alternatively, scan the inventory to see if the object is in there... for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) { - assert(WIO_INVENTORY == whereIsObject(obj)); + if (_game.version == 0) + assert(WIO_INVENTORY == whereIsObjectInventory(obj)); + else + assert(WIO_INVENTORY == whereIsObject(obj)); + // Found the object! Nuke it from the inventory. _res->nukeResource(rtInventory, i); _inventory[i] = 0; @@ -286,7 +290,7 @@ int ScummEngine::getState(int obj) { // it. Fortunately this does not prevent frustrated players from // blowing up the mansion, should they feel the urge to. - if (_game.id == GID_MANIAC && (obj == 182 || obj == 193)) + if (_game.id == GID_MANIAC && _game.version != 0 && (obj == 182 || obj == 193)) _objectStateTable[obj] |= kObjectState_08; } @@ -317,6 +321,15 @@ int ScummEngine::getObjectIndex(int object) const { return -1; } +int ScummEngine::whereIsObjectInventory(int object) { + int res = 0; + _v0ObjectInInventory = true; + res = whereIsObject(object); + _v0ObjectInInventory = false; + + return res; +} + int ScummEngine::whereIsObject(int object) const { int i; @@ -326,7 +339,7 @@ int ScummEngine::whereIsObject(int object) const { if (object < 1) return WIO_NOT_FOUND; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) { + if ((_objectOwnerTable[object] != OF_OWNER_ROOM && _game.version != 0) || _v0ObjectInInventory) { for (i = 0; i < _numInventory; i++) if (_inventory[i] == object) return WIO_INVENTORY; @@ -334,7 +347,7 @@ int ScummEngine::whereIsObject(int object) const { } for (i = (_numLocalObjects-1); i > 0; i--) - if (_objs[i].obj_nr == object) { + if ((_objs[i].obj_nr == object && !_v0ObjectIndex) || (_v0ObjectIndex && i == object)) { if (_objs[i].fl_object_index) return WIO_FLOBJECT; return WIO_ROOM; @@ -379,7 +392,7 @@ int ScummEngine::getObjectOrActorXY(int object, int &x, int &y) { * Returns X, Y and direction in angles */ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { - int idx = getObjectIndex(object); + int idx = (_v0ObjectIndex) ? object : getObjectIndex(object); assert(idx >= 0); ObjectData &od = _objs[idx]; int state; @@ -434,7 +447,7 @@ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { dir = oldDirToNewDir(od.actordir & 3); } -static int getDist(int x, int y, int x2, int y2) { +int ScummEngine::getDist(int x, int y, int x2, int y2) { int a = ABS(y - y2); int b = ABS(x - x2); return MAX(a, b); @@ -475,6 +488,14 @@ int ScummEngine::getObjActToObjActDist(int a, int b) { return getDist(x, y, x2, y2); } +int ScummEngine_v0::findObjectIndex(int x, int y) { + int objIdx; + _v0ObjectIndex = true; + objIdx = findObject(x, y); + _v0ObjectIndex = false; + return objIdx; +} + int ScummEngine::findObject(int x, int y) { int i, b; byte a; @@ -504,8 +525,12 @@ int ScummEngine::findObject(int x, int y) { } #endif if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x && - _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) - return _objs[i].obj_nr; + _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) { + if (_game.version == 0 && _v0ObjectIndex) + return i; + else + return _objs[i].obj_nr; + } break; } } while ((_objs[b].state & mask) == a); @@ -811,6 +836,9 @@ void ScummEngine_v3old::resetRoomObjects() { if (_dumpScripts) { char buf[32]; sprintf(buf, "roomobj-%d-", _roomResource); + if (_game.version == 0) + sprintf(buf + 11, "%d-", od->flags); + dumpResource(buf, od->obj_nr, room + od->OBCDoffset); } } @@ -1033,6 +1061,10 @@ void ScummEngine::updateObjectStates() { int i; ObjectData *od = &_objs[1]; for (i = 1; i < _numLocalObjects; i++, od++) { + // V0 MM, Room objects with Flag == 1 are objects with 'no-state' (room specific objects, non-pickup) + if (_game.version == 0 && od->flags == 1) + continue; + if (od->obj_nr > 0) od->state = getState(od->obj_nr); } @@ -1155,7 +1187,7 @@ const byte *ScummEngine::getObjOrActorName(int obj) { void ScummEngine::setObjectName(int obj) { int i; - if (obj < _numActors) + if (obj < _numActors && _game.version != 0) error("Can't set actor %d name with new-name-of", obj); for (i = 0; i < _numNewNames; i++) { @@ -1181,8 +1213,13 @@ void ScummEngine::setObjectName(int obj) { uint32 ScummEngine::getOBCDOffs(int object) const { int i; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) + if ((_objectOwnerTable[object] != OF_OWNER_ROOM && (_game.version != 0)) || _v0ObjectInInventory) return 0; + + // V0 MM Return by Index + if (_v0ObjectIndex) + return _objs[object].OBCDoffset; + for (i = (_numLocalObjects-1); i > 0; i--) { if (_objs[i].obj_nr == object) { if (_objs[i].fl_object_index != 0) @@ -1194,17 +1231,20 @@ uint32 ScummEngine::getOBCDOffs(int object) const { } byte *ScummEngine::getOBCDFromObject(int obj) { + bool useInventory = _v0ObjectInInventory; int i; byte *ptr; - if (_objectOwnerTable[obj] != OF_OWNER_ROOM) { + _v0ObjectInInventory = false; + + if ((_objectOwnerTable[obj] != OF_OWNER_ROOM && (_game.version != 0)) || useInventory) { for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) return getResourceAddress(rtInventory, i); } } else { for (i = (_numLocalObjects-1); i > 0; --i) { - if (_objs[i].obj_nr == obj) { + if ((_objs[i].obj_nr == obj && !_v0ObjectIndex) || (_v0ObjectIndex && i == obj)) { if (_objs[i].fl_object_index) { assert(_objs[i].OBCDoffset == 8); ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index); diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 88802a205f..67baff97b3 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -229,7 +229,7 @@ void ScummEngine::askForDisk(const char *filename, int disknum) { sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataDir.getPath().c_str()); #endif - result = displayMessage("Quit", buf); + result = displayMessage("Quit", "%s", buf); if (!result) { error("Cannot find file: '%s'", filename); } @@ -253,10 +253,10 @@ void ScummEngine::readIndexFile() { if (_game.version <= 5) { // Figure out the sizes of various resources - while (!_fileHandle->eos()) { + while (true) { blocktype = _fileHandle->readUint32BE(); itemsize = _fileHandle->readUint32BE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; switch (blocktype) { case MKID_BE('DOBJ'): @@ -285,7 +285,6 @@ void ScummEngine::readIndexFile() { } _fileHandle->seek(itemsize - 8, SEEK_CUR); } - _fileHandle->clearIOFailed(); _fileHandle->seek(0, SEEK_SET); } @@ -300,7 +299,7 @@ void ScummEngine::readIndexFile() { blocktype = _fileHandle->readUint32BE(); itemsize = _fileHandle->readUint32BE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; numblock++; @@ -689,7 +688,7 @@ int ScummEngine::loadResource(int type, int idx) { dumpResource("script-", idx, getResourceAddress(rtScript, idx)); } - if (!_fileHandle->ioFailed()) { + if (!_fileHandle->err() && !_fileHandle->eos()) { return 1; } diff --git a/engines/scumm/resource_v2.cpp b/engines/scumm/resource_v2.cpp index 184f3d94df..e469c721b1 100644 --- a/engines/scumm/resource_v2.cpp +++ b/engines/scumm/resource_v2.cpp @@ -138,7 +138,7 @@ void ScummEngine_v2::readEnhancedIndexFile() { _fileHandle->seek(_numScripts * 3, SEEK_CUR); _numSounds = _fileHandle->readByte(); - _fileHandle->clearIOFailed(); + _fileHandle->clearErr(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); diff --git a/engines/scumm/resource_v3.cpp b/engines/scumm/resource_v3.cpp index 420f71cf03..0728395055 100644 --- a/engines/scumm/resource_v3.cpp +++ b/engines/scumm/resource_v3.cpp @@ -80,7 +80,7 @@ void ScummEngine_v3old::readIndexFile() { _fileHandle->seek(_numScripts * 3, SEEK_CUR); _numSounds = _fileHandle->readByte(); - _fileHandle->clearIOFailed(); + _fileHandle->clearErr(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); diff --git a/engines/scumm/resource_v4.cpp b/engines/scumm/resource_v4.cpp index 28e0fb05b5..75858f7b42 100644 --- a/engines/scumm/resource_v4.cpp +++ b/engines/scumm/resource_v4.cpp @@ -61,11 +61,11 @@ void ScummEngine_v4::readIndexFile() { closeRoom(); openRoom(0); - while (!_fileHandle->eos()) { + while (true) { // Figure out the sizes of various resources itemsize = _fileHandle->readUint32LE(); blocktype = _fileHandle->readUint16LE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; switch (blocktype) { @@ -95,16 +95,15 @@ void ScummEngine_v4::readIndexFile() { _fileHandle->seek(itemsize - 8, SEEK_CUR); } - _fileHandle->clearIOFailed(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); allocateArrays(); - while (1) { + while (true) { itemsize = _fileHandle->readUint32LE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; blocktype = _fileHandle->readUint16LE(); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index d474a43b05..aa4dce470e 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -86,6 +86,19 @@ bool ScummEngine::canLoadGameStateCurrently() { // FIXME: Actually, we might wish to support loading in more places. // As long as we are sure it won't cause any problems... Are we // aware of *any* spots where loading is not supported? + + // HE games are limited to original load and save interface only, + // due to numerous glitches (see bug #1726909) that can occur. + if (_game.heversion >= 60) + return false; + + // COMI always disables saving/loading (to tell the truth: + // the main menu) via its scripts, thus we need to make an + // exception here. This the same forced overwriting of the + // script decisions as in ScummEngine::processKeyboard. + if (_game.id == GID_CMI) + return true; + return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0); } @@ -99,7 +112,22 @@ bool ScummEngine::canSaveGameStateCurrently() { // TODO: Should we disallow saving in some more places, // e.g. when a SAN movie is playing? Not sure whether the // original EXE allowed this. - return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0); + + // HE games are limited to original load and save interface only, + // due to numerous glitches (see bug #1726909) that can occur. + if (_game.heversion >= 60) + return false; + + // COMI always disables saving/loading (to tell the truth: + // the main menu) via its scripts, thus we need to make an + // exception here. This the same forced overwriting of the + // script decisions as in ScummEngine::processKeyboard. + if (_game.id == GID_CMI) + return true; + + // SCUMM v4+ doesn't allow saving in room 0 or if + // VAR(VAR_MAINMENU_KEY) to set to zero. + return (VAR_MAINMENU_KEY == 0xFF || (VAR(VAR_MAINMENU_KEY) != 0 && _currentRoom != 0)); } @@ -1368,11 +1396,31 @@ void ScummEngine::saveOrLoad(Serializer *s) { } void ScummEngine_v0::saveOrLoad(Serializer *s) { + ScummEngine_v2::saveOrLoad(s); + + const SaveLoadEntry v0Entrys[] = { + MKLINE(ScummEngine_v0, _currentMode, sleByte, VER(78)), + MKLINE(ScummEngine_v0, _currentLights, sleByte, VER(78)), + MKEND() + }; + s->saveLoadEntries(this, v0Entrys); +} + + +void ScummEngine_v2::saveOrLoad(Serializer *s) { ScummEngine::saveOrLoad(s); - // TODO: Save additional variables - // _currentMode - // _currentLights + const SaveLoadEntry v2Entrys[] = { + MKLINE(ScummEngine_v2, _inventoryOffset, sleUint16, VER(79)), + MKEND() + }; + s->saveLoadEntries(this, v2Entrys); + + // In old saves we didn't store _inventoryOffset -> reset it to + // a sane default when loading one of those. + if (s->getVersion() < 79 && s->isLoading()) { + _inventoryOffset = 0; + } } void ScummEngine_v5::saveOrLoad(Serializer *s) { diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 29184ad023..4f6adc5570 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 77 +#define CURRENT_VER 79 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 4d9447bee5..2c3fe09db2 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -23,10 +23,9 @@ * */ - - #include "common/config-manager.h" #include "common/util.h" +#include "common/system.h" #include "scumm/actor.h" #include "scumm/object.h" @@ -133,6 +132,8 @@ void ScummEngine::runObjectScript(int object, int entry, bool freezeResistant, b initializeLocals(slot, vars); + // V0 Ensure we don't try and access objects via index inside the script + _v0ObjectIndex = false; runScriptNested(slot); } @@ -786,92 +787,65 @@ void ScummEngine::runInventoryScript(int i) { } void ScummEngine::inventoryScriptIndy3Mac() { - VerbSlot *vs; - int args[24]; - int j, slot; + int slot; - memset(args, 0, sizeof(args)); + // VAR(67) controls the scroll offset of the inventory in Indy3 for Macintosh. + // The inventory consists of two columns with three items visible in each, + // so a maximum of six items are visible at once. - if (VAR(67) < 0) { - VAR(67) = 0; - } - args[5] = getInventoryCount(VAR(VAR_EGO)); - if (args[5] <= 6) { + // The scroll offset must be non-negative and if there are six or less items + // in the inventory, the inventory is fixed in the top position. + const int invCount = getInventoryCount(VAR(VAR_EGO)); + if (VAR(67) < 0 || invCount <= 6) { VAR(67) = 0; } - if (args[5] >= 6) { - args[5] -= 6; - } - args[6] = 0; - if (VAR(67) >= args[5]) { - VAR(67) = args[5]; - args[4] = args[5]; - args[5] /= 2; - args[5] *= 2; - args[4] -= args[5]; - if (args[4]) { + + // If there are more than six items in the inventory, clamp the scroll position + // to be at most invCount-6, rounded up to the next even integer. + bool scrolledToBottom = false; + if (invCount > 6 && VAR(67) >= invCount - 6) { + VAR(67) = invCount - 6; + // Odd number of inventory items? -> increment VAR(67) to make it even + if (invCount & 1) { VAR(67)++; } - args[6]++; - } - args[2] = 1; - for (j = 1; j < 7; j++) { - args[1] = (VAR(67) + args[2]); - args[3] = findInventory(VAR(VAR_EGO),args[1]); - VAR(82 + args[2]) = args[3]; - args[2]++; + scrolledToBottom = true; } - byte tmp[6]; - - tmp[0] = 0xFF; - tmp[1] = 0x06; - tmp[3] = 0x00; - tmp[4] = 0x00; - - for (j = 0; j < 6; j++) { - tmp[2] = 0x53 + j; - - slot = getVerbSlot(101 + j, 0); - vs = &_verbs[slot]; + // Now update var 83 till 89 to contain the inventory IDs of the + // corresponding inventory slots. + // Also setup fake verbs for the inventory + byte tmp[6] = { 0xFF, 0x06, 0x52, 0x00, 0x00, 0x00 }; + for (int j = 1; j < 7; j++) { + int tmpA = (VAR(67) + j); + int tmpB = findInventory(VAR(VAR_EGO), tmpA); + VAR(82 + j) = tmpB; + + // Setup fake verb + tmp[2] = 0x52 + j; + slot = getVerbSlot(100 + j, 0); loadPtrToResource(rtVerb, slot, tmp); + + VerbSlot *vs = &_verbs[slot]; vs->type = kTextVerbType; vs->imgindex = 0; vs->curmode = 1; drawVerb(slot, 0); } - args[5] = getInventoryCount(VAR(VAR_EGO)); - if (args[5] > 6) { - slot = getVerbSlot(107, 0); - if (VAR(67)) { - vs = &_verbs[slot]; - vs->curmode = 1; - } else { - vs = &_verbs[slot]; - vs->curmode = 0; - } - drawVerb(slot, 0); - slot = getVerbSlot(108, 0); - if (!args[6]) { - vs = &_verbs[slot]; - vs->curmode = 1; - } else { - vs = &_verbs[slot]; - vs->curmode = 0; - } - drawVerb(slot, 0); - } else { - slot = getVerbSlot(107, 0); - vs = &_verbs[slot]; - vs->curmode = 0; - drawVerb(slot, 0); - slot = getVerbSlot(108, 0); - vs = &_verbs[slot]; - vs->curmode = 0; - drawVerb(slot, 0); - } + // Enable up arrow if there are more than six items and we are not already + // scrolled all the way up. + slot = getVerbSlot(107, 0); + _verbs[slot].curmode = (invCount > 6 && VAR(67)) ? 1 : 0; + drawVerb(slot, 0); + + // Enable down arrow if there are more than six items and we are not already + // scrolled all the way down. + slot = getVerbSlot(108, 0); + _verbs[slot].curmode = (invCount > 6 && !scrolledToBottom) ? 1 : 0; + drawVerb(slot, 0); + // Redraw! verbMouseOver(0); } @@ -1204,7 +1178,7 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) { args[4] = VAR(VAR_VIRT_MOUSE_Y); } - // Macintosh verison of indy3ega used different interface, so adjust values. + // Macintosh version of indy3ega used different interface, so adjust values. if (_game.id == GID_INDY3 && _game.platform == Common::kPlatformMacintosh) { if (clickArea == kVerbClickArea && (val >= 101 && val <= 108)) { if (val == 107) { @@ -1216,10 +1190,16 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) { inventoryScriptIndy3Mac(); return; } else { - args[0] = 3; - args[1] = VAR(83 + (val - 101)); + args[0] = kInventoryClickArea; + args[1] = VAR(82 + (val - 100)); } } + + // Clicks are handled differently in Indy3 mac: param 2 of the + // input script is set to 0 for normal clicks, and to 1 for double clicks. + uint32 time = _system->getMillis(); + args[2] = (time < _lastInputScriptTime + 500); // 500 ms double click delay + _lastInputScriptTime = time; } if (verbScript) diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp index 1b8368d636..873f2fa281 100644 --- a/engines/scumm/script_v0.cpp +++ b/engines/scumm/script_v0.cpp @@ -410,41 +410,43 @@ void ScummEngine_v0::decodeParseString() { actorTalk(buffer); } -void ScummEngine_v0::drawSentence() { - Common::Rect sentenceline; +void ScummEngine_v0::drawSentenceWord(int object, bool usePrep, bool objInInventory) { const byte *temp; int sentencePrep = 0; + + // If object not in inventory, we except an index + if (!objInInventory) + _v0ObjectIndex = true; + else + _v0ObjectInInventory = true; - if (!(_userState & 32)) - return; + temp = getObjOrActorName(object); - if (getResourceAddress(rtVerb, _activeVerb)) { - strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); - } else { - return; + _v0ObjectInInventory = false; + _v0ObjectIndex = false; + + // Append the 'object-name' + if (temp) { + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)temp); } - if (_activeObject > 0) { - temp = getObjOrActorName(_activeObject); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); - } + // Append the modifier? (With / On / To / In) + if (!usePrep) + return; - if (_verbs[_activeVerb].prep == 0xFF) { - byte *ptr = getOBCDFromObject(_activeObject); - assert(ptr); - sentencePrep = (*(ptr + 11) >> 5); - } else { - sentencePrep = _verbs[_activeVerb].prep; - } + if (_verbs[_activeVerb].prep == 0xFF) { + _v0ObjectInInventory = objInInventory; + sentencePrep = verbPrep(object); + } else { + sentencePrep = _verbs[_activeVerb].prep; } if (sentencePrep > 0 && sentencePrep <= 4) { // The prepositions, like the fonts, were hard code in the engine. Thus // we have to do that, too, and provde localized versions for all the // languages MM/Zak are available in. - const char *prepositions[][5] = { + static const char *prepositions[][5] = { { " ", " in", " with", " on", " to" }, // English { " ", " mit", " mit", " mit", " zu" }, // German { " ", " dans", " avec", " sur", " <" }, // French @@ -471,13 +473,65 @@ void ScummEngine_v0::drawSentence() { strcat(_sentenceBuf, prepositions[lang][sentencePrep]); } +} + +void ScummEngine_v0::drawSentence() { + Common::Rect sentenceline; + bool inventoryFirst = false; + + if (!(_userState & 32)) + return; + + // Current Verb, Walk/Use + if (getResourceAddress(rtVerb, _activeVerb)) { + strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); + } else { + return; + } - if (_activeInventory > 0) { - temp = getObjOrActorName(_activeInventory); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); + // If using inventory first, draw it first + if (_activeInvExecute && _activeInventory) { + drawSentenceWord(_activeInventory, true, true); + } else { + // Not using inventory, use selected object + if (_activeObject) + drawSentenceWord(_activeObjectIndex, true, false); + else + inventoryFirst = true; + } + + + // Draw the inventory? + if (_activeInventory > 0 && _activeObject2 == 0) { + // Only if inventory isnt first (it will already be drawn by now) + if (!_activeInvExecute) { + drawSentenceWord(_activeInventory, inventoryFirst, true); + } else { + // Draw the active object, which could be inventory based, or room based + if (_activeObject && !_activeObjectIndex) { + drawSentenceWord(_activeObject, inventoryFirst, true); + } else // Room based + drawSentenceWord(_activeObjectIndex, inventoryFirst, false); } + + // Draw the 2nd active object + } else if (_activeObject2) { + + // 2nd Object is in inventory + if (_activeObject2Inv) { + _v0ObjectInInventory = true; + drawSentenceWord(_activeObject2, inventoryFirst, true); + } else { + drawSentenceWord(_activeObject2Index, inventoryFirst, false); + } + } + + // Draw the active actor + if (_activeActor) { + Actor *a = derefActor(_activeActor, ""); + + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)a->getActorName()); } _string[2].charset = 1; @@ -664,9 +718,22 @@ void ScummEngine_v0::o_animateActor() { int act = getVarOrDirectByte(PARAM_1); int anim = getVarOrDirectByte(PARAM_2); int unk = fetchScriptByte(); + debug(0,"o_animateActor: unk %d", unk); - Actor *a = derefActor(act, "o_animateActor"); + ActorC64 *a = (ActorC64*) derefActor(act, "o_animateActor"); + + // 0x6993 + if (anim == 0xFE) { + a->_speaking = 0x80; // Enabled, but not switching + return; + } + // 0x69A3 + if (anim == 0xFD) { + a->_speaking = 0x00; + return; + } + a->animateActor(anim); } @@ -713,9 +780,9 @@ void ScummEngine_v0::o_pickupObject() { if (getObjectIndex(obj) == -1) return; - if (whereIsObject(obj) == WIO_INVENTORY) /* Don't take an */ + if (whereIsObjectInventory(_activeObject2) == WIO_INVENTORY) /* Don't take an */ return; /* object twice */ - + addObjectToInventory(obj, _roomResource); markObjectRectAsDirty(obj); putOwner(obj, VAR(VAR_EGO)); @@ -738,8 +805,13 @@ void ScummEngine_v0::o_setActorBitVar() { byte act = getVarOrDirectByte(PARAM_1); byte mask = getVarOrDirectByte(PARAM_2); byte mod = getVarOrDirectByte(PARAM_3); + + // 0x63ED + if (act >= _numActors) + return; ActorC64 *a = (ActorC64 *)derefActor(act, "o_setActorBitVar"); + if (mod) a->_miscflags |= mask; else @@ -900,10 +972,25 @@ void ScummEngine_v0::o_setOwnerOf() { setOwnerOf(obj, owner); } -void ScummEngine_v0::resetSentence() { - _activeInventory = 0; - _activeObject = 0; +void ScummEngine_v0::resetSentence(bool walking) { _activeVerb = 13; + + if (!walking) { + _activeInventory = 0; + _activeObject = 0; + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + } + + _verbExecuting = false; + _verbPickup = false; + + _activeActor = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } } // End of namespace Scumm diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index 1ce38fd800..f83e7f2879 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -1138,9 +1138,19 @@ void ScummEngine_v5::o5_ifClassOfIs() { while ((_opcode = fetchScriptByte()) != 0xFF) { cls = getVarOrDirectWord(PARAM_1); - b = getClass(obj, cls); - if (((cls & 0x80) && !b) || (!(cls & 0x80) && b)) - cond = false; + + // WORKAROUND bug #1668393: Due to a script bug, the wrong opcode is used + // to check the state of the inside door (object 465) of the Hostel on Mars, + // when opening the Hostel door from the outside. + if (_game.id == GID_ZAK && _game.platform == Common::kPlatformFMTowns && + vm.slot[_currentScript].number == 205 && _currentRoom == 185 && + obj == 465 && cls == 0) { + cond = (getState(obj) == 0); + } else { + b = getClass(obj, cls); + if (((cls & 0x80) && !b) || (!(cls & 0x80) && b)) + cond = false; + } } jumpRelative(cond); } @@ -1775,7 +1785,7 @@ void ScummEngine_v5::o5_roomOps() { while ((chr = fetchScriptByte())) filename += chr; - if (filename.hasPrefix("iq-") || filename.hasPrefix("IQ-") || filename.hasSuffix("-iq")) { + if (filename.hasPrefix("iq-") || filename.hasPrefix("IQ-") || filename.hasSuffix("-iq") || filename.hasSuffix("-IQ")) { filename = _targetName + ".iq"; } else { error("SO_LOAD_STRING: Unsupported filename %s", filename.c_str()); diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index dcd60352c7..6df3c0c494 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -701,6 +701,14 @@ void ScummEngine_v6::o6_ifNot() { void ScummEngine_v6::o6_jump() { int offset = fetchScriptWordSigned(); + + // WORKAROUND bug #2826144: Talking to the guard at the bigfoot party, after + // he's let you inside, will cause the game to hang, if you end the conversation. + // This is a script bug, due to a missing jump in one segment of the script. + if (_game.id == GID_SAMNMAX && vm.slot[_currentScript].number == 101 && readVar(0x8000 + 97) == 1 && offset == 1) { + offset = -18; + } + _scriptPointer += offset; } diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 5bb0e097dc..cb7f906f13 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 Sat Jul 11 01:37:44 2009 + This file was generated by the md5table tool on Thu Jul 30 10:23:41 2009 DO NOT EDIT MANUALLY! */ @@ -17,20 +17,20 @@ static const MD5Table md5table[] = { { "008e76ec3ae58d0add637ea7aa299a2c", "freddi3", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "02cae0e7ff8504f73618391873d5781a", "freddi3", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "0305e850382b812fec6e5998ef88a966", "pajama", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, - { "0425954a9db5c340861672892c3e678d", "samnmax", "CD", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "0425954a9db5c340861672892c3e678d", "samnmax", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "04401d747f1a2c1c4b388daff71ed378", "ft", "", "", 535405461, Common::DE_DEU, Common::kPlatformMacintosh }, { "04687cdf7f975a89d2474929f7b80946", "indy3", "FM-TOWNS", "", 7552, Common::EN_ANY, Common::kPlatformFMTowns }, { "0557df19f046a84c2fdc63507c6616cb", "farm", "HE 72", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "055ffe4f47753e47594ac67823220c54", "puttrace", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "057c9b456dedcc4d71b991a3072a20b3", "monkey", "SEGA", "", 9465, Common::JA_JPN, Common::kPlatformSegaCD }, { "0650e8ab1432564607cd651c0fa3f344", "loom", "PC-Engine", "", -1, Common::EN_ANY, Common::kPlatformPCEngine }, - { "06b187468113f9ae5a400b148a847fac", "atlantis", "", "Floppy", 12075, Common::EN_ANY, Common::kPlatformMacintosh }, + { "06b187468113f9ae5a400b148a847fac", "atlantis", "Floppy", "Floppy", 12075, Common::EN_ANY, Common::kPlatformMacintosh }, { "06c3cf4f31daad8b1cd93153491db9e6", "pajama3", "", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "07433205acdca3bc553d0e731588b35f", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "07a1eefd8ca95d77310311446c0f53d0", "brstorm", "", "Demo", 5433, Common::EN_ANY, Common::kPlatformUnknown }, + { "07a1eefd8ca95d77310311446c0f53d0", "brstorm", "", "", 5433, Common::EN_ANY, Common::kPlatformUnknown }, { "07b810e37be7489263f7bc7627d4765d", "freddi4", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows }, { "084ed0fa98a6d1e9368d67fe9cfbd417", "freddi", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "0855496dde35356b1a9691e22ba84cdc", "freddi", "HE 73", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -49,14 +49,14 @@ static const MD5Table md5table[] = { { "0c45eb4baff0c12c3d9dfa889c8070ab", "pajama3", "", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "0cccfa5223099a60e76cfcca57a1a141", "freddi3", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "0d1b69471605201ef2fa9cec1f5f02d2", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformPC }, - { "0e4c5d54a0ad4b26132e78b5ea76642a", "samnmax", "", "Demo", 6485, Common::EN_ANY, Common::kPlatformPC }, + { "0e4c5d54a0ad4b26132e78b5ea76642a", "samnmax", "Floppy", "Demo", 6485, Common::EN_ANY, Common::kPlatformPC }, { "0e96ab45a4eb72acc1b46813976589fd", "activity", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "0e9b01430e31d9fcd94071d433bbc6bf", "loom", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, { "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows }, - { "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "CD", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, + { "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, { "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, { "0f9d3317910ac7a9f449243118884ada", "puttzoo", "", "", 42070, Common::DE_DEU, Common::kPlatformWindows }, - { "0fb73eddfcf584c02ba097984df131ba", "samnmax", "CD", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown }, + { "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown }, { "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "10d8e66cd11049ce64815ebb9fd76eb3", "spyozon", "", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, @@ -72,22 +72,22 @@ static const MD5Table md5table[] = { { "15240c59d3681ed53f714f8d925cb2d6", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformAtariST }, { "157367c3c21e0d03a0cba44361b4cf65", "indy3", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, { "15e03ffbfeddb9c2aebc13dcb2a4a8f4", "monkey", "VGA", "VGA", 8357, Common::EN_ANY, Common::kPlatformPC }, - { "15f588e887e857e8c56fe6ade4956168", "atlantis", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformAmiga }, + { "15f588e887e857e8c56fe6ade4956168", "atlantis", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "16542a7342a918bfe4ba512007d36c47", "FreddisFunShop", "HE 99L", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "166553538ff320c69edafeee29525419", "samnmax", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "166553538ff320c69edafeee29525419", "samnmax", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "16effd200aa6b8abe9c569c3e578814d", "freddi4", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "179879b6e35c1ead0d93aab26db0951b", "fbear", "HE 70", "", 13381, Common::EN_ANY, Common::kPlatformWindows }, { "17b5d5e6af4ae89d62631641d66d5a05", "indy3", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "17f7296f63c78642724f057fd8e736a7", "maniac", "NES", "extracted", -1, Common::EN_GRB, Common::kPlatformNES }, - { "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "CD", "Demo", -1, Common::FR_FRA, Common::kPlatformPC }, - { "182344899c2e2998fca0bebcd82aa81a", "atlantis", "CD", "CD", 12035, Common::EN_ANY, Common::kPlatformPC }, + { "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "", "Demo", -1, Common::FR_FRA, Common::kPlatformPC }, + { "182344899c2e2998fca0bebcd82aa81a", "atlantis", "", "CD", 12035, Common::EN_ANY, Common::kPlatformPC }, { "183d7464902d40d00800e8ee1f04117c", "maniac", "V2", "V2", 1988, Common::DE_DEU, Common::kPlatformPC }, { "1875b90fade138c9253a8e967007031a", "indy3", "VGA", "VGA", 6295, Common::EN_ANY, Common::kPlatformPC }, { "187d315f6b5168f68680dfe8c3d76a3e", "loom", "EGA", "EGA", -1, Common::HB_ISR, Common::kPlatformPC }, { "1900e501a52fbf55bde6e4196f6d2aa6", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "19263586f749a560c1adf8b3393a9593", "socks", "HE 85", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "19bf6938a94698296bcb0c99c31c91a7", "spyfox2", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, - { "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "1c792d28376d45e145cb916bca0400a2", "spyfox2", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "1c7e7db2cfab1ad62746ab680a634204", "maniac", "NES", "extracted", -1, Common::FR_FRA, Common::kPlatformNES }, { "1ca86e2cf9aaa2068738a1e5ba477e60", "zak", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, @@ -97,12 +97,12 @@ static const MD5Table md5table[] = { { "1dd7aa088e09f96d06818aa9a9deabe0", "indy3", "No Adlib", "EGA", 5361, Common::EN_ANY, Common::kPlatformMacintosh }, { "1ed22f601f8b3695804a6583cc3083f1", "puttrace", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "1f2e62b5a9c50589fc342285a6bb3a27", "freddi", "HE 73", "", -1, Common::HB_ISR, Common::kPlatformWindows }, - { "1fbebd7b2b692df5297870447a80cfed", "atlantis", "", "Floppy", 12030, Common::DE_DEU, Common::kPlatformPC }, + { "1fbebd7b2b692df5297870447a80cfed", "atlantis", "Floppy", "Floppy", 12030, Common::DE_DEU, Common::kPlatformPC }, { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "Red", -1, Common::EN_ANY, Common::kPlatformWindows }, { "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows }, - { "20da6fce37805423966aaa8f3c2426aa", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga }, + { "20da6fce37805423966aaa8f3c2426aa", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "21abe302e1b1e2b66d6f5c12e241ebfd", "freddicove", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows }, @@ -114,14 +114,14 @@ static const MD5Table md5table[] = { { "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES }, - { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "", "Floppy", 7932, Common::EN_ANY, Common::kPlatformPC }, + { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "Floppy", "Floppy", 7932, Common::EN_ANY, Common::kPlatformPC }, { "27b2ef1653089fe5b897d9cc89ce784f", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformAmiga }, - { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "CD", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, + { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, { "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC }, { "28f07458f1b6c24e118a1ea056827701", "lost", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "2a208ffbcd0e83e86f4356e6f64aa6e1", "loom", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformPC }, - { "2a41b53cf1a90b6e6f26c10cc6041084", "tentacle", "CD", "Demo", 2439158, Common::EN_ANY, Common::kPlatformMacintosh }, + { "2a41b53cf1a90b6e6f26c10cc6041084", "tentacle", "", "Demo", 2439158, Common::EN_ANY, Common::kPlatformMacintosh }, { "2a446817ffcabfef8716e0c456ecaf81", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformWindows }, { "2a8658dbd13d84d1bce64a71a35995eb", "pajama2", "HE 99", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, { "2c04aacffb8428f30ccf4f734fbe3adc", "activity", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, @@ -130,7 +130,7 @@ static const MD5Table md5table[] = { { "2d388339d6050d8ccaa757b64633954e", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "2d4536a56e01da4b02eb021e7770afa2", "zak", "FM-TOWNS", "", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "2d4acbdcfd8e374c9da8c2e7303a5cd0", "BluesBirthday", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "2d9d46f23cb07bbc90b8ad464d3e4ff8", "atlantis", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "2d9d46f23cb07bbc90b8ad464d3e4ff8", "atlantis", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "2e85f7aa054930c692a5b1bed1dfc295", "football2002", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "2e8a1f76ea33bc5e04347646feee173d", "pajama3", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "2fe369ad70f52a8cf7ad6077ee64f81a", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformAmiga }, @@ -157,18 +157,18 @@ static const MD5Table md5table[] = { { "3824e60cdf639d22f6df92a03dc4b131", "fbear", "HE 61", "", 7732, Common::EN_ANY, Common::kPlatformPC }, { "387a544b8b10b26912d8413bab63a853", "monkey2", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "3905799e081b80a61d4460b7b733c206", "maniac", "NES", "", 262144, Common::EN_USA, Common::kPlatformNES }, - { "3938ee1aa4433fca9d9308c9891172b1", "zak", "FM-TOWNS", "Demo", -1, Common::EN_ANY, Common::kPlatformFMTowns }, + { "3938ee1aa4433fca9d9308c9891172b1", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "399b217b0c8d65d0398076da486363a9", "indy3", "VGA", "VGA", 6295, Common::DE_DEU, Common::kPlatformPC }, { "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "39fd6db10d0222d817025c4d3346e3b4", "farm", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "3a03dab514e4038df192d8a8de469788", "atlantis", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga }, + { "3a03dab514e4038df192d8a8de469788", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "3a0c35f3c147b98a2bdf8d400cfc4ab5", "indy3", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, { "3a3e592b074f595489f7f11e150c398d", "puttzoo", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformWindows }, - { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "3a5ec90d556d4920976c5578bfbfaf79", "maniac", "NES", "extracted", -1, Common::DE_DEU, Common::kPlatformNES }, { "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, - { "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformPC }, { "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, @@ -176,7 +176,7 @@ static const MD5Table md5table[] = { { "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, { "40564ec47da48a67787d1f9bd043902a", "maniac", "V2 Demo", "V2 Demo", 1988, Common::EN_ANY, Common::kPlatformPC }, - { "4167a92a1d46baa4f4127d918d561f88", "tentacle", "CD", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown }, + { "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown }, { "41958e24d03181ff9a381a66d048a581", "ft", "", "", -1, Common::PT_BRA, Common::kPlatformUnknown }, { "425205754fa749f4f0b0dd9d09fa45fd", "football", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "430bc518017b6fac046f58bab6baad5d", "monkey2", "", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, @@ -195,13 +195,13 @@ static const MD5Table md5table[] = { { "4aa93cb30e485b728504ba3a693f12bf", "pajama", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "4af4a6b248103c1fe9edef619677f540", "puttmoon", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "4ba37f835be11a59d969f90f272f575b", "water", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "4ba7fb331296c283e73d8f5b2096e551", "samnmax", "CD", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, + { "4ba7fb331296c283e73d8f5b2096e551", "samnmax", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, { "4bedb49943df95a9c900a5a82ccbe9de", "ft", "", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "4bfa4a43684bcb437f7fb47f457a0aa5", "socks", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "4c4820518e16e1a0e3616a3b021a04f3", "catalog", "HE CUP", "Preview", 10927456, Common::DE_DEU, Common::kPlatformUnknown }, { "4cb9c3618f71668f8e4346c8f323fa82", "monkey2", "", "", 10700, Common::EN_ANY, Common::kPlatformMacintosh }, { "4ce2d5b355964bbcb5e5ce73236ef868", "freddicove", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, - { "4d34042713958b971cb139fba4658586", "atlantis", "CD", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, + { "4d34042713958b971cb139fba4658586", "atlantis", "", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, { "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 }, @@ -209,15 +209,15 @@ static const MD5Table md5table[] = { { "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 61", "", 7717, Common::EN_ANY, Common::kPlatformPC }, - { "4f267a901719623de7dde83e47d5b474", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, + { "4f267a901719623de7dde83e47d5b474", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, { "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "CD", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, + { "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, { "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 }, - { "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "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::kPlatformMacintosh }, { "5262a27afcaee04e5c4900220bd463e7", "PuttsFunShop", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -229,10 +229,10 @@ static const MD5Table md5table[] = { { "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", 9800, Common::EN_ANY, Common::kPlatformWindows }, { "5719fc8a13b4638b78d9d8d12f091f94", "puttrace", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, - { "5798972220cd458be2626d54c80f71d7", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga }, + { "5798972220cd458be2626d54c80f71d7", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "57a17febe2183f521250e55d55b83e60", "PuttTime", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "57a5cfec9ef231a007043cc1917e8988", "freddi", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, - { "57b0d89af79befe1cabce3bece869e7f", "tentacle", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, + { "57b0d89af79befe1cabce3bece869e7f", "tentacle", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, { "58436e634f4fae1d9973591c2ffa1fcb", "spyfox", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "589601b676c98b1c0c987bc031ab68b3", "chase", "HE 95", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "58fdf4c7ad13540a734e18f8584cad89", "puttzoo", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, @@ -289,9 +289,9 @@ static const MD5Table md5table[] = { { "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows }, { "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, - { "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "CD", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh }, + { "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh }, { "6df20c50c1ab19799de9be7ae7716881", "fbear", "HE 61", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "6e959d65358eedf9b68b81e304b97fa4", "tentacle", "CD", "CD", 7932, Common::DE_DEU, Common::kPlatformUnknown }, + { "6e959d65358eedf9b68b81e304b97fa4", "tentacle", "", "CD", 7932, Common::DE_DEU, Common::kPlatformUnknown }, { "6ea966b4d660c870b9ee790d1fbfc535", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "6f0be328c64d689bb606d22a389e1b0f", "loom", "No Adlib", "EGA", 5748, Common::EN_ANY, Common::kPlatformMacintosh }, { "6f6ef668c608c7f534fea6e6d3878dde", "indy3", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC }, @@ -332,7 +332,7 @@ static const MD5Table md5table[] = { { "7ddeaf52c8b9a50551ce0aa2ac811d07", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "7e151c17adf624f1966c8fc5827c95e9", "puttputt", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "7ea2da67ebabea4ac20cee9f4f9d2934", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformPC }, { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -354,12 +354,12 @@ static const MD5Table md5table[] = { { "87df3e0074624040407764b7c5e710b9", "pajama", "", "Demo", 18354, Common::NL_NLD, Common::kPlatformWindows }, { "87f6e8037b7cc996e13474b491a7a98e", "maniac", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "8801fb4a1200b347f7a38523339526dd", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "CD", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, + { "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, { "898ce8eb1234a955ef75e87141902bb3", "freddi3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "898eaa21f79cf8d4f08db856244689ff", "pajama", "HE 99", "Updated", 66505, Common::EN_ANY, Common::kPlatformWindows }, { "89cfc425566003ff74b7dc7b3e6fd469", "indy3", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC }, { "8a484262363a8e18be87112454f1456b", "pjgames", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "8aa05d3cdb0e795436043f0546af2da2", "tentacle", "CD", "CD?", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "8aa05d3cdb0e795436043f0546af2da2", "tentacle", "", "CD?", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "8aed489aba45d2b9fb8a04079c9c6e6a", "baseball", "HE CUP", "Preview", 12876596, Common::UNK_LANG, Common::kPlatformUnknown }, { "8afb3cf9f95abf208358e984f0c9e738", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "8bdb0bf87b5e303dd35693afb9351215", "ft", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, @@ -367,11 +367,11 @@ static const MD5Table md5table[] = { { "8de13897f0121c79d29a2377159f9ad0", "socks", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "8e3241ddd6c8dadf64305e8740d45e13", "balloon", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "8e4ee4db46954bfe2912e259a16fad82", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformPC }, - { "8e9417564f33790815445b2136efa667", "atlantis", "CD", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh }, + { "8e9417564f33790815445b2136efa667", "atlantis", "", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh }, { "8e9830a6f2702be5b22c8fa0a6aaf977", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "8eb84cee9b429314c7f0bdcf560723eb", "monkey", "FM-TOWNS", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, { "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", 18041, Common::UNK_LANG, Common::kPlatformWindows }, { "8ffd618a776a4c0d8922bb28b09f8ce8", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "90a329d8ad5b7ce0690429e98cfbb32f", "funpack", "", "", -1, Common::HB_ISR, Common::kPlatformPC }, @@ -381,10 +381,10 @@ static const MD5Table md5table[] = { { "91469353f7be1b122fa88d23480a1320", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "91d5db93187fab54d823f73bd6441cb6", "maniac", "NES", "extracted", -1, Common::EN_USA, Common::kPlatformNES }, { "927a764615c7fcdd72f591355e089d8c", "monkey", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, - { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "92e7727e67f5cd979d8a1070e4eb8cb3", "puttzoo", "HE 98.5", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "92fc0073a4cf259ff36070ecb8628ba8", "thinkerk", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "94aaedbb8f26d71ed3ad6dd34490e29e", "tentacle", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "94aaedbb8f26d71ed3ad6dd34490e29e", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "94db6519da85b8d08c976d8e9a858ea7", "baseball", "HE CUP", "Preview", 10044774, Common::UNK_LANG, Common::kPlatformUnknown }, { "95818b178d473c989ac753574e8892aa", "readtime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "95b3806e043be08668c54c3ffe98650f", "BluesABCTime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -392,13 +392,13 @@ static const MD5Table md5table[] = { { "9708cf716ed8bcc9ff3fcfc69413b746", "puttputt", "HE 61", "", -1, Common::EN_ANY, Common::kPlatformPC }, { "9781422e4288dbc090720e4563168ba7", "puttzoo", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "981e1e1891f2be7e25a01f50ae55a5af", "puttrace", "HE 98", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "99128b6a5bdd9831d9682fb8b5cbf8d4", "BluesBirthday", "", "Yellow", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "99a3699f80b8f776efae592b44b9b991", "maniac", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformPC }, - { "99b6f822b0b2612415407865438697d6", "atlantis", "CD", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "99b6f822b0b2612415407865438697d6", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "9b7452b5cd6d3ffb2b2f5118010af84f", "ft", "Demo", "Demo", 116463537, Common::EN_ANY, Common::kPlatformMacintosh }, { "9bc548e179cdb0767009401c094d0895", "maniac", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAmiga }, - { "9bd2a8f72613e715c199246dd511e10f", "atlantis", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "9bd2a8f72613e715c199246dd511e10f", "atlantis", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "9bda5fee51d2fda5253d02c642016bf4", "spyfox", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "9c0ee9c252785e9fca0143e42ac4b256", "freddi2", "HE 99", "Updated", -1, Common::DE_DEU, Common::kPlatformWindows }, { "9c0fee288ad564a7d25ec3e841810d79", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, @@ -420,7 +420,7 @@ static const MD5Table md5table[] = { { "a2386da005672cbd5136f4f27a626c5f", "farm", "", "", 87061, Common::NL_NLD, Common::kPlatformWindows }, { "a28135a7ade38cc0208b04507c46efd1", "spyfox", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "a2bb6aa0537402c1b3c2ea899ccef64b", "lost", "HE 99", "Demo", 15540, Common::EN_ANY, Common::kPlatformWindows }, - { "a3036878840720fbefa41e6965fa4a0a", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "a3036878840720fbefa41e6965fa4a0a", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "a336134914eaab4892d35625aa15ad1d", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -441,16 +441,16 @@ static const MD5Table md5table[] = { { "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "CD", "Demo", -1, Common::DE_DEU, Common::kPlatformPC }, + { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformPC }, { "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "aefa244ea034b7cd2041f0a44be7d9ba", "pajama3", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "af2bd1a43b50b55915d87994e093203d", "freddi", "HE 99", "Updated", 34829, Common::DE_DEU, Common::kPlatformWindows }, { "b100abf7ff83146df50db78dbd5e9cfa", "freddicove", "HE 100", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "b23f7cd7c304d7dff08e92a96120d5b4", "zak", "V1", "V1", -1, Common::EN_ANY, Common::kPlatformPC }, { "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformPC }, - { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "b47be81e39a9710f6f595f7b527b60f8", "puttrace", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformPC }, @@ -479,7 +479,7 @@ static const MD5Table md5table[] = { { "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 }, - { "c3196c5349e53e387aaff1533d95e53a", "samnmax", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "c3196c5349e53e387aaff1533d95e53a", "samnmax", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "c3b22fa4654bb580b20325ebf4174841", "puttzoo", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "c3df37df9d3b481b45f75283a9907c47", "loom", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "c4787c3e8b5e2dfda90850ee800af00f", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformPC }, @@ -487,22 +487,22 @@ static const MD5Table md5table[] = { { "c4ffae9fac495475d6bc3343ccc8faf9", "Soccer2004", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "c5cc7cba02a2fbd539c4439e775b0536", "puttzoo", "HE 99", "Updated", 43470, Common::DE_DEU, Common::kPlatformWindows }, { "c5d10e190d4b4d59114b824f2fdbd00e", "loom", "FM-TOWNS", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, - { "c63ee46143ba65f9ce14cf539ca51bd7", "atlantis", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "c63ee46143ba65f9ce14cf539ca51bd7", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "c666a998af90d81db447eccba9f72c8d", "monkey", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, { "c6907d44f1166941d982864cd42cdc89", "pajama2", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "c782fbbe74a987c3df8ac73cd3e289ed", "freddi", "HE 73", "", -1, Common::SE_SWE, Common::kPlatformMacintosh }, { "c7890e038806df2bb5c0c8c6f1986ea2", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformPC }, - { "c7be10f775404fd9785a8b92a06d240c", "atlantis", "CD", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, + { "c7be10f775404fd9785a8b92a06d240c", "atlantis", "", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, { "c7c492a107ec520d7a7943037d0ca54a", "freddi", "HE 71", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "c83079157ec765a28de445aec9768d60", "tentacle", "CD", "Demo", 7477, Common::EN_ANY, Common::kPlatformUnknown }, + { "c83079157ec765a28de445aec9768d60", "tentacle", "", "Demo", 7477, Common::EN_ANY, Common::kPlatformUnknown }, { "c8575e0b973ff1723aba6cd92c642db2", "puttrace", "HE 99", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, { "c8aac5e3e701874e2fa4117896f9e1b1", "freddi", "HE 73", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "c8c5baadcbfc8d0372ed4335abace8a7", "pajama3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, { "c9717ee6059f1e43b768b464493d2fba", "fbpack", "", "", -1, Common::JA_JPN, Common::kPlatform3DO }, { "cb1559e8405d17a5a278a6b5ad9338d1", "freddi3", "", "Demo", 22718, Common::EN_ANY, Common::kPlatformUnknown }, - { "cc04a076779379524ed4d9c5ee3c6fb1", "tentacle", "CD", "CD", 282467632, Common::EN_ANY, Common::kPlatformMacintosh }, + { "cc04a076779379524ed4d9c5ee3c6fb1", "tentacle", "", "CD", 282467632, Common::EN_ANY, Common::kPlatformMacintosh }, { "cc0c4111449054f1692bb3c0c5e04629", "BluesBirthday", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "cc8ba2b0df2f9c450bcf055fe2711979", "samnmax", "", "Demo", 7485, Common::DE_DEU, Common::kPlatformPC }, + { "cc8ba2b0df2f9c450bcf055fe2711979", "samnmax", "Floppy", "Demo", 7485, Common::DE_DEU, Common::kPlatformPC }, { "cd424f143a141bc59226ad83a6e40f51", "maze", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "cd46c9f122272d02bbf79332ff521898", "loom", "EGA", "EGA", 5748, Common::RU_RUS, Common::kPlatformPC }, { "cd9c05e755d7bf8e9b9590ad1ebe273e", "dig", "Demo", "Demo", 45156007, Common::EN_ANY, Common::kPlatformMacintosh }, @@ -525,7 +525,7 @@ static const MD5Table md5table[] = { { "d220d154aafbfa12bd6f3ab1b2dae420", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformMacintosh }, { "d2cc8e31bce61e6cf2951249e10638fe", "basketball", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "d37c55388294b66e53e7ced3af88fa68", "freddi2", "HE 100", "Updated Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "d43352a805d78b5f4936c6d7779bf575", "samnmax", "CD", "CD", -1, Common::RU_RUS, Common::kPlatformPC }, + { "d43352a805d78b5f4936c6d7779bf575", "samnmax", "", "CD", -1, Common::RU_RUS, Common::kPlatformPC }, { "d4aac997e2f4e15341f0bfbf905419bd", "PuttTime", "HE 99", "", 62698, Common::EN_GRB, Common::kPlatformWindows }, { "d4b8ee426b1afd3e53bc0cf020418cf6", "dog", "HE 99", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "d4cccb5af88f3e77f370896e9ba8c5f9", "freddi", "HE 71", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, @@ -535,7 +535,7 @@ static const MD5Table md5table[] = { { "d62047a6729349ab36f7ee065bf26509", "dig", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "d62d248c3df6ec177405e2cb23d923b2", "indy3", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "d6334a5a9b61afe18c368540fdf522ca", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "d6dd0646404768a63e963891a96daadd", "atlantis", "", "Floppy", 12035, Common::EN_ANY, Common::kPlatformMacintosh }, + { "d6dd0646404768a63e963891a96daadd", "atlantis", "Floppy", "Floppy", 12035, Common::EN_ANY, Common::kPlatformMacintosh }, { "d73c851b942af44deb9b6d5f416a0972", "freddi3", "HE 99", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, { "d74122362a77ec24525fdd50297dfd82", "freddi4", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "d7ab7cd6105546016e6a0d46fb36b964", "pajama", "HE 100", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -543,8 +543,8 @@ static const MD5Table md5table[] = { { "d831f7c048574dd9d5d85db2a1468099", "maniac", "C64", "", -1, Common::EN_ANY, Common::kPlatformC64 }, { "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown }, { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", 262144, Common::EN_GRB, Common::kPlatformNES }, - { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "CD", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, - { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "CD", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, + { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, + { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, { "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformPC }, { "da669b20271b85182e9c17a2a37ea02e", "monkey2", "", "", -1, Common::DE_DEU, Common::kPlatformAmiga }, @@ -566,7 +566,7 @@ static const MD5Table md5table[] = { { "e361a7058ed8e8ebb462663c0a3ae8d6", "puttputt", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, { "e41de1c2a15abbcdbf9977e2d7e8a340", "freddi2", "HE 100", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, { "e44ea295a3f8fe4f41983080dab1e9ce", "freddi", "HE 90", "Updated", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, + { "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "e5563c8358443c4352fcddf7402a5e0a", "pajama2", "HE 98.5", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "e5c112140ad6574997de033a8e2a2964", "readtime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -584,11 +584,11 @@ static const MD5Table md5table[] = { { "ecc4340c2b801f5af8da4e00c0e432d9", "puttcircus", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "ed2b074bc3166087a747acb2a3c6abb0", "freddi3", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO }, { "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "ef71a322b6530ac45b1a070f7c0795f7", "moonbase", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, { "efe0a04a703e765ebebe92b6c8aa6b86", "baseball2003", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -598,11 +598,11 @@ static const MD5Table md5table[] = { { "f163cf53f7850e43fb482471e5c52e1a", "maniac", "NES", "", 262144, Common::ES_ESP, Common::kPlatformNES }, { "f1b0e0d587b85052de5534a3847e68fe", "water", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown }, - { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, + { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, { "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows }, { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, - { "f73883f13b5a302749a5bad31d909780", "tentacle", "CD", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh }, + { "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh }, { "f7711f9264d4d43c2a1518ec7c10a607", "pajama3", "", "", 79382, Common::EN_USA, Common::kPlatformUnknown }, { "f79e60c17cca601e411f1f75e8ee9b5a", "spyfox2", "", "", 51286, Common::UNK_LANG, Common::kPlatformUnknown }, { "f8be685007a8b425ba2a455da732f59f", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, @@ -613,7 +613,7 @@ static const MD5Table md5table[] = { { "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "fbdd947d21e8f5bac6d6f7a316af1c5a", "spyfox", "", "Demo", 15693, Common::EN_ANY, Common::kPlatformUnknown }, - { "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "fc6b6148e80d67939d9a18697c0f626a", "monkey", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC }, { "fc8d197a22146e74766e9cb0cfcaf1da", "freddi2", "HE 80", "Demo", 27298, Common::EN_ANY, Common::kPlatformUnknown }, { "fcb78ebecab2757264c590890c319cc5", "PuttTime", "HE 85", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index abf9848451..9d6673d308 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -26,6 +26,7 @@ #include "common/config-manager.h" #include "common/md5.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "gui/message.h" @@ -135,6 +136,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) // Init all vars + _v0ObjectIndex = false; + _v0ObjectInInventory = false; _imuse = NULL; _imuseDigital = NULL; _musicEngine = NULL; @@ -182,6 +185,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _mouseAndKeyboardStat = 0; _leftBtnPressed = 0; _rightBtnPressed = 0; + _lastInputScriptTime = 0; _bootParam = 0; _dumpScripts = false; _debugMode = 0; @@ -215,7 +219,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _roomResource = 0; OF_OWNER_ROOM = 0; _verbMouseOver = 0; - _inventoryOffset = 0; _classData = NULL; _actorToPrintStrFor = 0; _sentenceNum = 0; @@ -539,7 +542,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) for (int i = 0; i < ARRAYSIZE(debugChannels); ++i) Common::addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc); - syst->getEventManager()->registerRandomSource(_rnd, "scumm"); + g_eventRec.registerRandomSource(_rnd, "scumm"); } @@ -645,6 +648,8 @@ ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const DetectorResult &dr) ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) : ScummEngine_v3old(syst, dr) { + _inventoryOffset = 0; + _activeInventory = 0; _activeObject = 0; _activeVerb = 0; @@ -663,7 +668,17 @@ ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr) : ScummEngine_v2(syst, dr) { + _verbExecuting = false; + _verbPickup = false; _currentMode = 0; + + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr) @@ -1883,7 +1898,7 @@ void ScummEngine::scummLoop(int delta) { } // Trigger autosave if necessary. - if (!_saveLoadFlag && shouldPerformAutoSave(_lastSaveTime)) { + if (!_saveLoadFlag && shouldPerformAutoSave(_lastSaveTime) && canSaveGameStateCurrently()) { _saveLoadSlot = 0; sprintf(_saveLoadName, "Autosave %d", _saveLoadSlot); _saveLoadFlag = 1; diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 4ed8cf57eb..f0f2521225 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -565,6 +565,9 @@ protected: int32 *_scummVars; byte *_bitVars; + bool _v0ObjectIndex; // V0 Use object index, instead of object number + bool _v0ObjectInInventory; // V0 Use object number from inventory + /* Global resource tables */ int _numVariables, _numBitVariables, _numLocalObjects; int _numGlobalObjects, _numArray, _numVerbs, _numFlObject; @@ -612,6 +615,12 @@ protected: uint16 _mouseAndKeyboardStat; byte _leftBtnPressed, _rightBtnPressed; + /** + * Last time runInputScript was run (measured in terms of OSystem::getMillis()). + * This is currently only used for Indy3 mac to detect "double clicks". + */ + uint32 _lastInputScriptTime; + /** The bootparam, to be passed to the script 1, the bootscript. */ int _bootParam; @@ -858,12 +867,14 @@ protected: int getObjNewDir(int obj); int getObjectIndex(int object) const; int getObjectImageCount(int object); + int whereIsObjectInventory(int object); int whereIsObject(int object) const; int findObject(int x, int y); void findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint object, uint room); public: int getObjectOrActorXY(int object, int &x, int &y); // Used in actor.cpp, hence public protected: + int getDist(int x, int y, int x2, int y2); int getObjActToObjActDist(int a, int b); // Not sure how to handle const byte *getObjOrActorName(int obj); // these three.. void setObjectName(int obj); @@ -884,7 +895,6 @@ protected: protected: /* Should be in Verb class */ uint16 _verbMouseOver; - int _inventoryOffset; int8 _userPut; uint16 _userState; diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h index ccca5df0d3..19260b6429 100644 --- a/engines/scumm/scumm_v0.h +++ b/engines/scumm/scumm_v0.h @@ -35,7 +35,20 @@ namespace Scumm { */ class ScummEngine_v0 : public ScummEngine_v2 { protected: - int _currentMode; + byte _currentMode; + bool _verbExecuting; // is a verb executing + bool _verbPickup; // are we picking up an object during a verb execute + + int _activeActor; // Actor Number + int _activeObject2; // 2nd Object Number + + bool _activeInvExecute; // is activeInventory first to be executed + bool _activeObject2Inv; // is activeobject2 in the inventory + bool _activeObjectObtained; // collected _activeobject? + bool _activeObject2Obtained; // collected _activeObject2? + + int _activeObjectIndex; + int _activeObject2Index; public: ScummEngine_v0(OSystem *syst, const DetectorResult &dr); @@ -53,12 +66,25 @@ protected: virtual void processInput(); + virtual void runObject(int obj, int entry); virtual void saveOrLoad(Serializer *s); + // V0 MM Verb commands + int verbPrep(int object); + bool verbMove(int object, int objectIndex, bool invObject); + bool verbMoveToActor(int actor); + bool verbObtain(int object, int objIndex); + bool verbExecutes(int object, bool inventory = false); + bool verbExec(); + + int findObjectIndex(int x, int y); + virtual void checkExecVerbs(); virtual void handleMouseOver(bool updateInventory); void resetVerbs(); void setNewKidVerbs(); + + void drawSentenceWord(int object, bool usePrep, bool objInInventory); void drawSentence(); void switchActor(int slot); @@ -68,7 +94,7 @@ protected: virtual int getActiveObject(); - virtual void resetSentence(); + virtual void resetSentence(bool walking = false); /* Version C64 script opcodes */ void o_stopCurrentScript(); diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h index 338b5f6167..ee9591bc45 100644 --- a/engines/scumm/scumm_v2.h +++ b/engines/scumm/scumm_v2.h @@ -45,6 +45,7 @@ protected: int8 _mouseOverBoxV2; char _sentenceBuf[256]; + uint16 _inventoryOffset; int _activeInventory; int _activeObject; @@ -66,6 +67,8 @@ protected: virtual void resetScummVars(); virtual void decodeParseString(); + virtual void saveOrLoad(Serializer *s); + virtual void processKeyboard(Common::KeyState lastKeyHit); virtual void readIndexFile(); @@ -100,7 +103,7 @@ protected: virtual void setBuiltinCursor(int index); - void runObject(int obj, int entry); + virtual void runObject(int obj, int entry); /* Version 2 script opcodes */ void o2_actorFromPos(); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 2a681ffd62..d1676772a8 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -23,6 +23,9 @@ * */ +#include "common/config-manager.h" +#include "common/timer.h" +#include "common/util.h" #include "scumm/actor.h" #include "scumm/file.h" @@ -32,10 +35,6 @@ #include "scumm/sound.h" #include "scumm/util.h" -#include "common/config-manager.h" -#include "common/timer.h" -#include "common/util.h" - #include "sound/adpcm.h" #include "sound/audiocd.h" #include "sound/flac.h" @@ -46,8 +45,6 @@ #include "sound/vorbis.h" #include "sound/wave.h" - - namespace Scumm { struct MP3OffsetTable { /* Compressed Sound (.SO3) */ @@ -420,17 +417,16 @@ void Sound::playSound(int soundID) { sound = (char *)malloc(size); int vol = ptr[24] * 4; int loopStart = 0, loopEnd = 0; -#if 0 // Disabling this until after 0.11.0 int loopcount = ptr[27]; if (loopcount > 1) { // TODO: We can only loop once, or infinitely many times, but // have no support for a finite number of repetitions. - // This is + // So far, I have seen only 1 and 255 (for infinite repetitions), + // so maybe this is not really a problem. loopStart = READ_BE_UINT16(ptr + 10) - READ_BE_UINT16(ptr + 8); loopEnd = READ_BE_UINT16(ptr + 14); flags |= Audio::Mixer::FLAG_LOOP; } -#endif memcpy(sound, ptr + READ_BE_UINT16(ptr + 8), size); _mixer->playRaw(Audio::Mixer::kSFXSoundType, NULL, sound, size, rate, diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index f00f4ff33b..e99bea87de 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -995,6 +995,11 @@ void ScummEngine::drawString(int a, const byte *msg) { } _string[a].xpos = _charset->_str.right; + + if (_game.heversion >= 60) { + _string[a]._default.xpos = _string[a].xpos; + _string[a]._default.ypos = _string[a].ypos; + } } int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize) { diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 22487b43a3..98e088365e 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -538,9 +538,7 @@ void ScummEngine_v8::setupScummVars() { #endif void ScummEngine_v0::resetScummVars() { - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + resetSentence(); VAR(VAR_EGO) = 3; diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index 81b28ce563..1ab9d72a58 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -155,6 +155,7 @@ void ScummEngine_v0::switchActor(int slot) { VAR(VAR_EGO) = VAR(97 + slot); actorFollowCamera(VAR(VAR_EGO)); resetVerbs(); + resetSentence(false); setUserState(247); } @@ -376,14 +377,8 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { if (object > 0) { if (_game.version == 0) { - if (_activeInventory != object) { - _activeInventory = object; - } else if (_activeVerb != 3 && _activeVerb != 13) { - if (_activeObject) - runObject(_activeObject, _activeVerb); - else - runObject(_activeInventory, _activeVerb); - } + _activeInventory = object; + } else { runInputScript(kInventoryClickArea, object, 0); } @@ -425,7 +420,9 @@ void ScummEngine_v2::redrawV2Inventory() { _string[1].right = _mouseOverBoxesV2[i].rect.right - 1; _string[1].color = _mouseOverBoxesV2[i].color; + _v0ObjectInInventory = true; const byte *tmp = getObjOrActorName(obj); + _v0ObjectInInventory = false; assert(tmp); // Prevent inventory entries from overflowing by truncating the text @@ -629,14 +626,14 @@ void ScummEngine_v2::checkExecVerbs() { if (vs->verbid && vs->saveid == 0 && vs->curmode == 1) { if (_mouseAndKeyboardStat == vs->key) { // Trigger verb as if the user clicked it - runInputScript(1, vs->verbid, 1); + runInputScript(kVerbClickArea, vs->verbid, 1); return; } } } // Generic keyboard input - runInputScript(4, _mouseAndKeyboardStat, 1); + runInputScript(kKeyClickArea, _mouseAndKeyboardStat, 1); } else if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { VirtScreen *zone = findVirtScreen(_mouse.y); const byte code = _mouseAndKeyboardStat & MBS_LEFT_CLICK ? 1 : 2; @@ -649,7 +646,7 @@ void ScummEngine_v2::checkExecVerbs() { if (zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // Click into V2 sentence line - runInputScript(5, 0, 0); + runInputScript(kSentenceClickArea, 0, 0); } else if (zone->number == kVerbVirtScreen && _mouse.y > zone->topline + inventoryArea) { // Click into V2 inventory checkV2Inventory(_mouse.x, _mouse.y); @@ -657,7 +654,7 @@ void ScummEngine_v2::checkExecVerbs() { over = findVerbAtPos(_mouse.x, _mouse.y); if (over != 0) { // Verb was clicked - runInputScript(1, _verbs[over].verbid, code); + runInputScript(kVerbClickArea, _verbs[over].verbid, code); } else { // Scene was clicked runInputScript((zone->number == kMainVirtScreen) ? kSceneClickArea : kVerbClickArea, 0, code); @@ -666,6 +663,25 @@ void ScummEngine_v2::checkExecVerbs() { } } +void ScummEngine_v0::runObject(int obj, int entry) { + int prev = _v0ObjectInInventory; + + if (getVerbEntrypoint(obj, entry) != 0) { + _v0ObjectInInventory = prev; + runObjectScript(obj, entry, false, false, NULL); + } else if (entry != 13 && entry != 15) { + if (_activeVerb != 3) { + VAR(9) = entry; + runScript(3, 0, 0, 0); + + // For some reasons, certain objects don't have a "give" script + } else if (VAR(5) > 0 && VAR(5) < 8) { + if (_activeInventory) + setOwnerOf(_activeInventory, VAR(5)); + } + } +} + void ScummEngine_v2::runObject(int obj, int entry) { if (getVerbEntrypoint(obj, entry) != 0) { runObjectScript(obj, entry, false, false, NULL); @@ -679,10 +695,293 @@ void ScummEngine_v2::runObject(int obj, int entry) { _activeVerb = 13; } +bool ScummEngine_v0::verbMoveToActor(int actor) { + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + Actor *a2 =derefActor(actor, "checkExecVerbs"); + + if (!a->_moving) { + int dist = getDist(a->getRealPos().x, a->getRealPos().y, a2->getRealPos().x, a2->getRealPos().y); + if (dist > 5) + a->startWalkActor(a2->getRealPos().x, a2->getRealPos().y, 1); + else + return false; + + return true; + } + + return true; +} + +bool ScummEngine_v0::verbMove(int object, int objectIndex, bool invObject) { + int x, y, dir; + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + + if (_currentMode != 3 && _currentMode != 2) + return false; + + if (a->_moving) + return true; + + _v0ObjectIndex = true; + getObjectXYPos(objectIndex, x, y, dir); + _v0ObjectIndex = false; + // Detect distance from target object + int dist = getDist(a->getRealPos().x, a->getRealPos().y, x, y); + + // FIXME: This should be changed once the walkbox problem is fixed + if (dist > 0x5) { + a->startWalkActor(x, y, dir); + VAR(6) = x; + VAR(7) = y; + return true; + } else { + // Finished walk, are we picking up the item? + if (_verbPickup) { + int oldActive = _activeObject, oldIndex = _activeObjectIndex; + _activeObject = object; + _activeObjectIndex = objectIndex; + + _v0ObjectIndex = true; + // Execute pickup + runObject(objectIndex, 14); + _v0ObjectIndex = false; + + _activeObject = oldActive; + _activeObjectIndex = oldIndex; + + // Finished picking up + _verbPickup = false; + } + } + + return false; +} + +bool ScummEngine_v0::verbObtain(int obj, int objIndex) { + bool didPickup = false; + + int prep, where = whereIsObjectInventory(obj); + + if (objIndex == 0) + return false; + + if (where != WIO_INVENTORY) { + _v0ObjectIndex = true; + prep = verbPrep(objIndex); + + if (prep == 1 || prep == 4) { + if (_activeVerb != 13 && _activeVerb != 14) { + _verbPickup = true; + didPickup = true; + } + } else { + _verbPickup = false; + } + + if (verbMove(obj, objIndex, false)) + return true; + + if (didPickup && (prep == 1 || prep == 4)) + if (_activeVerb != 13 && _activeVerb != 14) + _activeInventory = obj; + } + + return false; +} + +int ScummEngine_v0::verbPrep(int object) { + if (!_v0ObjectInInventory) + _v0ObjectIndex = true; + else + _v0ObjectIndex = false; + byte *ptr = getOBCDFromObject(object); + _v0ObjectIndex = false; + assert(ptr); + return (*(ptr + 11) >> 5); +} + +bool ScummEngine_v0::verbExecutes(int object, bool inventory) { + _v0ObjectInInventory = inventory; + int prep = verbPrep(object); + + if (prep == 2 || prep == 0) { + return true; + } + + return false; +} + +bool ScummEngine_v0::verbExec() { + int prep = 0; + int entry = (_currentMode != 0 && _currentMode != 1) ? _activeVerb : 15; + + if ((!_activeInvExecute && _activeObject && getObjectIndex(_activeObject) == -1)) { + resetSentence(); + return false; + } + + // Lets try walk to the object + if (_activeObject && _activeObjectIndex && !_activeObjectObtained && _currentMode != 0) { + prep = verbPrep(_activeObjectIndex); + + if (verbObtain(_activeObject, _activeObjectIndex)) + return true; + + _activeObjectObtained = true; + } + + if (_activeObject2 && _activeObject2Index && !_activeObject2Obtained && _currentMode != 0) { + prep = verbPrep(_activeObject2Index); + + _v0ObjectInInventory = false; + if (verbObtain(_activeObject2, _activeObject2Index)) + return true; + + if (prep != 1 && prep != 4) { + _activeInventory = _activeObject; + _activeObject = _activeObject2; + _activeObjectIndex = _activeObject2Index; + _activeObject2 = 0; + _activeObject2Index = 0; + } + + _activeObject2Obtained = true; + } + + // Give-To + if (_activeVerb == 3 && _activeInventory && _activeActor) { + // FIXME: Actors need to turn and face each other + // And walk to each other + if (verbMoveToActor(_activeActor)) + return true; + + _v0ObjectInInventory = true; + VAR(5) = _activeActor; + runObject(_activeInventory , 3); + _v0ObjectInInventory = false; + + resetSentence(); + return false; + } + + if (_activeActor) { + _v0ObjectIndex = true; + runObject(_activeActor, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + resetSentence(); + return false; + } + + // If we've finished walking (now near target), execute the action + if (_activeObject && _activeObjectIndex && verbPrep(_activeObjectIndex) == 2) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + if ((_currentMode == 3 || _currentMode == 2) && _activeVerb == 13) + return false; + + resetSentence(); + return false; + } + + // We acted on an inventory item + if (_activeInventory && verbExecutes(_activeInventory, true) && _activeVerb != 3) { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + + _verbExecuting = false; + + if (_currentMode == 3 && _activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + return false; + } + + if (_activeObject) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + } else if (_activeInventory) { + if (verbExecutes(_activeInventory, true) == false) { + if (_activeObject2 && verbExecutes(_activeObject2, true)) { + _v0ObjectInInventory = true; + + _activeObject = _activeInventory; + _activeInventory = _activeObject2; + + runObject(_activeObject, _activeVerb); + } else { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + } + } else { + runObject(_activeInventory, _activeVerb); + _v0ObjectInInventory = true; + } + } + + _verbExecuting = false; + + if (_activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + + return false; +} + void ScummEngine_v0::checkExecVerbs() { Actor *a; VirtScreen *zone = findVirtScreen(_mouse.y); + // Is a verb currently executing + if (_verbExecuting) { + // Check if mouse click + if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { + int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + + if (over && over != _activeVerb) { + _activeVerb = over; + _verbExecuting = false; + return; + } + + if (!obj && !act && !over) { + resetSentence(false); + } else { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + } + } else { + if (_verbExecuting && !verbExec()) + return; + } + } + + // What-Is selected, any object we hover over is selected, on mouse press we set to WalkTo + if (_activeVerb == 15) { + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + _activeObject = obj; + _activeObjectIndex = objIdx; + + if ((_mouseAndKeyboardStat & MBS_MOUSE_MASK)) + _activeVerb = 13; // Walk-To + + return; + } + if (_userPut <= 0 || _mouseAndKeyboardStat == 0) return; @@ -693,61 +992,147 @@ void ScummEngine_v0::checkExecVerbs() { if (zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // TODO } else if (zone->number == kVerbVirtScreen && _mouse.y > zone->topline + 32) { + int prevInventory = _activeInventory; + // Click into V2 inventory checkV2Inventory(_mouse.x, _mouse.y); + if (!_activeInventory) + return; + + // Did we just change the selected inventory item? + if (prevInventory && prevInventory != _activeInventory && _activeInventory != _activeObject2) { + _activeObject = 0; + _activeInvExecute = true; + _activeObject2Inv = true; + _activeObject2 = _activeInventory; + _activeInventory = prevInventory; + return; + } + + // is the new selected inventory the same as the last selected?, reset to previous if it is + if (_activeInventory == _activeObject2) + _activeInventory = prevInventory; + + // Inventory Selected changed + if (prevInventory != _activeInventory) + if (!_activeObject2 || prevInventory != _activeObject2) + return; + + if (_activeVerb == 11 && !((!(_activeObject || _activeInventory)) || !_activeObject2)) + return; } else { int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + + if ((_activeObject || _activeInventory) && act) { + obj = 0; + objIdx = 0; + } // Handle New Kid verb options - if (_activeVerb == 7) { + if (_activeVerb == 7 || over == 7) { + // Disable New-Kid (in the secret lab) + if (_currentMode == 2 || _currentMode == 0) + return; + + if (_activeVerb != 7) { + _activeVerb = over; + over = 0; + } + if (over) { _activeVerb = 13; switchActor(_verbs[over].verbid - 1); + return; } + + setNewKidVerbs(); + return; } + + // Clicked on nothing, walk here? + if (!over && !act && _activeVerb == 13 && !obj && _currentMode != 0) { + // Clear all selected + resetSentence(); - if (over) { - _activeVerb = _verbs[over].verbid; - // Selected New Kid verb - if (_activeVerb == 7) - setNewKidVerbs(); + // 0xB31 + VAR(6) = _virtualMouse.x / V12_X_MULTIPLIER; + VAR(7) = _virtualMouse.y / V12_Y_MULTIPLIER; + if (zone->number == kMainVirtScreen) { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + } return; } - int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); - int obj = findObject(_virtualMouse.x, _virtualMouse.y); - if (act != 0 && _activeVerb == 3 && _activeInventory != 0) { - // Give inventory item to actor - VAR(5) = act; - runObject(_activeInventory, _activeVerb); - } else if (obj) { - if (_currentMode == 3 && _activeVerb != 13 && obj != _activeObject) { - _activeObject = obj; - return; - } + // No new verb, use previous + if (over == 0) + over = _activeVerb; - _activeObject = obj; - if (_currentMode == 3) { - int x, y, dir; - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - getObjectXYPos(obj, x, y, dir); - a->startWalkActor(x, y, dir); + // No verb selected, use walk-to + if (!_activeVerb) + _activeVerb = over = 13; // Walk-To + + // New verb selected + if (_activeVerb != over) { + _activeVerb = over; + if (_activeVerb == 13) { + resetSentence(); } + return; + } - int entry = (_currentMode == 3) ? _activeVerb : 15; - runObject(_activeObject, entry); - } else if (zone->number == kMainVirtScreen) { - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + // Only allowing targetting actors if its the GIVE/USE verb + if (_activeVerb == 3 || _activeVerb == 11) { + // Different actor selected? + if (act) { + if (_activeActor != act) { + _activeActor = act; + return; + } + } } - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + if (obj && obj != _activeObject) { + if (!_activeObject) + if (_activeInventory) + _activeInvExecute = true; + + // USE + if (_activeVerb == 11 || _activeVerb == 8) { + if (obj != _activeObject || obj != _activeObject2) { + if (!_activeObject || _activeInventory) { + _activeObject = obj; + _activeObjectIndex = objIdx; + return; + } else { + if (_activeObject2 != obj) { + _activeObject2 = obj; + _activeObject2Index = objIdx; + return; + } + } + } + } else { + _activeObject = obj; + _activeObjectIndex = objIdx; + + if (_activeVerb != 13) + return; + + //return; + } + } } - } + + _verbExecuting = true; + + } // mouse k/b action } void ScummEngine::verbMouseOver(int verb) { diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp index 991fbe19d0..5924197d96 100644 --- a/engines/sky/logic.cpp +++ b/engines/sky/logic.cpp @@ -27,6 +27,7 @@ #include "common/endian.h" #include "common/rect.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "sky/autoroute.h" @@ -73,7 +74,7 @@ void Logic::setupLogicTable() { } Logic::Logic(SkyCompact *skyCompact, Screen *skyScreen, Disk *skyDisk, Text *skyText, MusicBase *skyMusic, Mouse *skyMouse, Sound *skySound) { - g_system->getEventManager()->registerRandomSource(_rnd, "sky"); + g_eventRec.registerRandomSource(_rnd, "sky"); _skyCompact = skyCompact; _skyScreen = skyScreen; diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 2d0d081ef6..7ed50461af 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -160,6 +160,9 @@ void MoviePlayer::play(void) { stopEvent.kbd = Common::KEYCODE_ESCAPE; stopEvents.push_back(stopEvent); + _textX = 0; + _textY = 0; + terminated = !playVideo(stopEvents); if (terminated) @@ -200,12 +203,15 @@ void MoviePlayer::performPostProcessing(byte *screen) { } } + byte *src, *dst; + int x, y; + if (_textMan->giveSpriteData(2)) { - byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); - byte *dst = screen + _textY * _decoder->getWidth() + _textX * 1; + src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); + dst = screen + _textY * SCREEN_WIDTH + _textX * 1; - for (int y = 0; y < _textHeight; y++) { - for (int x = 0; x < _textWidth; x++) { + for (y = 0; y < _textHeight; y++) { + for (x = 0; x < _textWidth; x++) { switch (src[x]) { case BORDER_COL: dst[x] = _decoder->getBlack(); @@ -216,8 +222,34 @@ void MoviePlayer::performPostProcessing(byte *screen) { } } src += _textWidth; - dst += _decoder->getWidth(); + dst += SCREEN_WIDTH; + } + } else if (_textX && _textY) { + // If the frame doesn't cover the entire screen, we have to + // erase the subtitles manually. + + int frameWidth = _decoder->getWidth(); + int frameHeight = _decoder->getHeight(); + int frameX = (_system->getWidth() - frameWidth) / 2; + int frameY = (_system->getHeight() - frameHeight) / 2; + + dst = screen + _textY * _system->getWidth(); + + for (y = 0; y < _textHeight; y++) { + if (_textY + y < frameY || _textY + y >= frameY + frameHeight) { + memset(dst + _textX, _decoder->getBlack(), _textWidth); + } else { + if (frameX > _textX) + memset(dst + _textX, _decoder->getBlack(), frameX - _textX); + if (frameX + frameWidth < _textX + _textWidth) + memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + _textWidth - (frameX + frameWidth)); + } + + dst += _system->getWidth(); } + + _textX = 0; + _textY = 0; } } diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp index 756ce3a5cc..09d2197f2a 100644 --- a/engines/sword1/control.cpp +++ b/engines/sword1/control.cpp @@ -1207,7 +1207,7 @@ bool Control::restoreGameFromFile(uint8 slot) { for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) playerBuf[cnt2] = inf->readUint32LE(); - if (inf->ioFailed()) { + if (inf->err() || inf->eos()) { displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan->popErrorDesc().c_str()); delete inf; free(_restoreBuf); diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 7e911bd197..be3797b0bd 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -28,6 +28,7 @@ #include "common/util.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "sword1/logic.h" #include "sword1/text.h" @@ -55,7 +56,7 @@ namespace Sword1 { uint32 Logic::_scriptVars[NUM_SCRIPT_VARS]; Logic::Logic(SwordEngine *vm, ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, Audio::Mixer *mixer) { - g_system->getEventManager()->registerRandomSource(_rnd, "sword1"); + g_eventRec.registerRandomSource(_rnd, "sword1"); _vm = vm; _objMan = pObjMan; diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp index 979bd3210a..90ea5fe677 100644 --- a/engines/sword1/resman.cpp +++ b/engines/sword1/resman.cpp @@ -263,9 +263,9 @@ void ResMan::resOpen(uint32 id) { // load resource ID into memory _memMan->alloc(memHandle, size); Common::File *clusFile = resFile(id); assert(clusFile); - clusFile->seek( resOffset(id) ); - clusFile->read( memHandle->data, size); - if (clusFile->ioFailed()) { + clusFile->seek(resOffset(id)); + clusFile->read(memHandle->data, size); + if (clusFile->err() || clusFile->eos()) { error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id); } } else diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index b23bf71445..6ad946b28d 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -28,6 +28,7 @@ #include "common/util.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "sword1/sound.h" @@ -47,7 +48,7 @@ namespace Sword1 { #define SPEECH_FLAGS (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_LITTLE_ENDIAN) Sound::Sound(const char *searchPath, Audio::Mixer *mixer, ResMan *pResMan) { - g_system->getEventManager()->registerRandomSource(_rnd, "sword1sound"); + g_eventRec.registerRandomSource(_rnd, "sword1sound"); strcpy(_filePath, searchPath); _mixer = mixer; _resMan = pResMan; diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 21ab645bfe..4a235315b6 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -116,7 +116,7 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI terminated = !playVideo(stopEvents); - closeTextObject(_currentMovieText); + closeTextObject(_currentMovieText, NULL); if (terminated) { _snd->stopHandle(*_bgSoundHandle); @@ -171,7 +171,7 @@ void MoviePlayer::openTextObject(uint32 index) { } } -void MoviePlayer::closeTextObject(uint32 index) { +void MoviePlayer::closeTextObject(uint32 index, byte *screen) { if (index < _numMovieTexts) { MovieText *text = &_movieTexts[index]; @@ -179,6 +179,32 @@ void MoviePlayer::closeTextObject(uint32 index) { text->_textMem = NULL; if (_textSurface) { + if (screen) { + // If the frame doesn't cover the entire + // screen, we have to erase the subtitles + // manually. + + int frameWidth = _decoder->getWidth(); + int frameHeight = _decoder->getHeight(); + int frameX = (_system->getWidth() - frameWidth) / 2; + int frameY = (_system->getHeight() - frameHeight) / 2; + + byte *dst = screen + _textY * _system->getWidth(); + + for (int y = 0; y < text->_textSprite.h; y++) { + if (_textY + y < frameY || _textY + y >= frameY + frameHeight) { + memset(dst + _textX, _decoder->getBlack(), text->_textSprite.w); + } else { + if (frameX > _textX) + memset(dst + _textX, _decoder->getBlack(), frameX - _textX); + if (frameX + frameWidth < _textX + text->_textSprite.w) + memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + text->_textSprite.w - (frameX + frameWidth)); + } + + dst += _system->getWidth(); + } + } + _vm->_screen->deleteSurface(_textSurface); _textSurface = NULL; } @@ -204,7 +230,7 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) { src = buffer; } - byte *dst = screen + _textY * _decoder->getWidth() + _textX; + byte *dst = screen + _textY * RENDERWIDE + _textX; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -214,15 +240,11 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) { dst[x] = white; } src += width; - dst += _decoder->getWidth(); + dst += RENDERWIDE; } } } -// FIXME: This assumes that the subtitles always fit within the frame of the -// movie. In Broken Sword 2, that's a fairly safe assumption, but not -// necessarily in all other games. - void MoviePlayer::performPostProcessing(byte *screen) { MovieText *text; int frame = _decoder->getCurFrame(); @@ -247,6 +269,7 @@ void MoviePlayer::performPostProcessing(byte *screen) { if (frame <= text->_endFrame) { drawTextObject(_currentMovieText, screen); } else { + closeTextObject(_currentMovieText, screen); _currentMovieText++; } } diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 032350d2d6..f2b44baaa0 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -98,7 +98,7 @@ protected: void performPostProcessing(byte *screen); void openTextObject(uint32 index); - void closeTextObject(uint32 index); + void closeTextObject(uint32 index, byte *screen); void drawTextObject(uint32 index, byte *screen); }; diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp index 6741be33f1..c49fb8e786 100644 --- a/engines/sword2/resman.cpp +++ b/engines/sword2/resman.cpp @@ -151,7 +151,7 @@ bool ResourceManager::init() { for (i = 0; i < size / 2; i++) _resConvTable[i] = file.readUint16LE(); - if (file.ioFailed()) { + if (file.eos() || file.err()) { file.close(); GUIErrorMessage("Broken Sword 2: Cannot read resource.tab"); return false; @@ -178,7 +178,7 @@ bool ResourceManager::init() { cdInf[i].cd = file.readByte(); - if (file.ioFailed()) { + if (file.eos() || file.err()) { delete cdInf; file.close(); GUIErrorMessage("Broken Sword 2: Cannot read cd.inf"); @@ -477,7 +477,7 @@ void ResourceManager::readCluIndex(uint16 fileNum, Common::File *file) { _resFiles[fileNum].entryTab = (uint32*)malloc(tableSize); _resFiles[fileNum].numEntries = tableSize / 8; file->read(_resFiles[fileNum].entryTab, tableSize); - if (file->ioFailed()) + if (file->eos() || file->err()) error("unable to read index table from file %s", _resFiles[fileNum].fileName); #ifdef SCUMM_BIG_ENDIAN diff --git a/engines/sword2/startup.cpp b/engines/sword2/startup.cpp index 09bf65bf75..e4572d3c1a 100644 --- a/engines/sword2/startup.cpp +++ b/engines/sword2/startup.cpp @@ -66,7 +66,7 @@ bool Sword2Engine::initStartMenu() { int start_ids[MAX_starts]; int lineno = 0; - while (!fp.eos() && !fp.ioFailed()) { + while (!fp.eos() && !fp.err()) { Common::String line = fp.readLine(); // Skip empty lines or, more likely, the end of the stream. @@ -103,7 +103,7 @@ bool Sword2Engine::initStartMenu() { } // An I/O error before EOS? That's bad, but this is not a vital file. - if (fp.ioFailed() && !fp.eos()) + if (fp.err() && !fp.eos()) warning("I/O error while reading startup.inf"); fp.close(); diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index cf44b4c99c..e368f257a2 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -33,6 +33,7 @@ #include "common/file.h" #include "common/fs.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/savefile.h" #include "common/system.h" @@ -305,7 +306,7 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) { _gmmLoadSlot = -1; // Used to manage GMM Loading - syst->getEventManager()->registerRandomSource(_rnd, "sword2"); + g_eventRec.registerRandomSource(_rnd, "sword2"); } Sword2Engine::~Sword2Engine() { diff --git a/engines/tinsel/background.cpp b/engines/tinsel/background.cpp index 94525e33dd..583b9817a9 100644 --- a/engines/tinsel/background.cpp +++ b/engines/tinsel/background.cpp @@ -249,6 +249,8 @@ void DrawBackgnd(void) { UpdateScreenRect(*r); } + g_system->updateScreen(); + // delete all the clipping rectangles ResetClipRect(); } diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp index 1df932f1af..1e9693542e 100644 --- a/engines/tinsel/bmv.cpp +++ b/engines/tinsel/bmv.cpp @@ -1118,6 +1118,7 @@ void CopyMovieToScreen(void) { BmvDrawText(true); PalettesToVideoDAC(); // Keep palette up-to-date UpdateScreenRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)); + g_system->updateScreen(); BmvDrawText(false); } diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index a3f921505a..df3f95ca13 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -79,6 +79,8 @@ namespace Tinsel { using Common::GUIO_NONE; using Common::GUIO_NOSPEECH; +using Common::GUIO_NOSFX; +using Common::GUIO_NOMUSIC; static const TinselGameDescription gameDescriptions[] = { @@ -101,7 +103,7 @@ static const TinselGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOSFX | GUIO_NOMUSIC }, GID_DW1, 0, diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h index 826c0e38ba..943d728354 100644 --- a/engines/tinsel/dw.h +++ b/engines/tinsel/dw.h @@ -100,7 +100,7 @@ typedef int HPOLYGON; #define NO_ENTRY_NUM (-3458) // Magic unlikely number -#define SAMPLETIMEOUT (15*ONE_SECOND) +#define SAMPLETIMEOUT (20*ONE_SECOND) // Language for the resource strings enum LANGUAGE { diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp index cb334d96b0..0b3f2e6e24 100644 --- a/engines/tinsel/graphics.cpp +++ b/engines/tinsel/graphics.cpp @@ -713,7 +713,6 @@ void UpdateScreenRect(const Common::Rect &pClip) { byte *pSrc = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top); g_system->copyRectToScreen(pSrc, _vm->screen().pitch, pClip.left, pClip.top + yOffset, pClip.width(), pClip.height()); - g_system->updateScreen(); } /** diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp index e77f505edb..5db2918d2f 100644 --- a/engines/tinsel/heapmem.cpp +++ b/engines/tinsel/heapmem.cpp @@ -285,7 +285,8 @@ MEM_NODE *MemoryAlloc(int flags, long size) { } #ifdef SCUMM_NEED_ALIGNMENT - size = (size + 3) & ~3; //round up to nearest multiple of 4, this ensures the addresses that are returned are 4-byte aligned as well. + const int alignPadding = sizeof(void*) - 1; + size = (size + alignPadding) & ~alignPadding; //round up to nearest multiple of sizeof(void*), this ensures the addresses that are returned are alignment-safe. #endif while ((flags & DWM_NOALLOC) == 0 && bCompacted) { @@ -521,7 +522,7 @@ MEM_NODE *MemoryReAlloc(MEM_NODE *pMemNode, long size, int flags) { assert(flags & (DWM_FIXED | DWM_MOVEABLE)); // align the size to machine boundary requirements - size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1); + size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1); // validate the size assert(size); diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 12d9f0393a..6ce1ea7288 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -189,7 +189,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { } // the index and length of the last tune loaded - static uint32 dwLastMidiIndex; + static uint32 dwLastMidiIndex = 0; //static uint32 dwLastSeqLen; uint32 dwSeqLen = 0; // length of the sequence @@ -256,6 +256,23 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { 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->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop); // Store the length @@ -303,6 +320,8 @@ int GetMidiVolume() { return volMusic; } +static int priorVolMusic = 0; + /** * Sets the volume of the MIDI music. * @param vol New volume - 0..MAXMIDIVOL @@ -310,23 +329,24 @@ int GetMidiVolume() { void SetMidiVolume(int vol) { assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume); - if (vol == 0 && volMusic == 0) { + if (vol == 0 && priorVolMusic == 0) { // Nothing to do - } else if (vol == 0 && volMusic != 0) { + } else if (vol == 0 && priorVolMusic != 0) { // Stop current midi sequence StopMidi(); - } else if (vol != 0 && volMusic == 0) { + _vm->_midiMusic->setVolume(vol); + } else if (vol != 0 && priorVolMusic == 0) { // Perhaps restart last midi sequence - if (currentLoop) { + if (currentLoop) PlayMidiSequence(currentMidi, true); - _vm->_midiMusic->setVolume(vol); - } - } else if (vol != 0 && volMusic != 0) { + + _vm->_midiMusic->setVolume(vol); + } else if (vol != 0 && priorVolMusic != 0) { // Alter current volume _vm->_midiMusic->setVolume(vol); } - volMusic = vol; + priorVolMusic = vol; } /** @@ -374,6 +394,7 @@ void DeleteMidiBuffer() { MidiMusicPlayer::MidiMusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) { memset(_channel, 0, sizeof(_channel)); + memset(_channelVolume, 0, sizeof(_channelVolume)); _masterVolume = 0; this->open(); _xmidiParser = MidiParser::createParser_XMIDI(); diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp index 8df9e9a375..84e88fe06b 100644 --- a/engines/tinsel/palette.cpp +++ b/engines/tinsel/palette.cpp @@ -133,7 +133,6 @@ void psxPaletteMapper(PALQ *originalPal, uint8 *psxClut, byte *mapperTable) { void PalettesToVideoDAC(void) { PALQ *pPalQ; // palette Q iterator VIDEO_DAC_Q *pDACtail = vidDACdata; // set tail pointer - bool needUpdate = false; // while Q is not empty while (pDAChead != pDACtail) { @@ -162,9 +161,6 @@ void PalettesToVideoDAC(void) { pColours = pDACtail->pal.pRGBarray; } - if (pDACtail->numColours > 0) - needUpdate = true; - // update the system palette g_system->setPalette((byte *)pColours, pDACtail->destDACindex, pDACtail->numColours); @@ -179,9 +175,6 @@ void PalettesToVideoDAC(void) { // clear all palette moved bits for (pPalQ = palAllocData; pPalQ < palAllocData + NUM_PALETTES; pPalQ++) pPalQ->posInDAC &= ~PALETTE_MOVED; - - if (needUpdate) - g_system->updateScreen(); } /** diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 1d73411e13..e6ed9df5c9 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -120,6 +120,12 @@ const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110}; const int fragment2_size = 2; const byte fragment3[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 490 % 256, 490 / 256}; const int fragment3_size = 4; +const byte fragment4[] = {OP_IMM | OPSIZE16, 900 % 256, 900 / 256, OP_JUMP, 466 % 256, 466 / 256}; +const int fragment4_size = 6; +const byte fragment5[] = {OP_IMM | OPSIZE16, 901 % 256, 901 / 256, OP_JUMP, 488 % 256, 488 / 256}; +const int fragment5_size = 6; +const byte fragment6[] = {OP_IMM | OPSIZE16, 903 % 256, 903 / 256, OP_JUMP, 516 % 256, 516 / 256}; +const int fragment6_size = 6; const WorkaroundEntry workaroundList[] = { // DW1-SCN: Global 206 is whether Rincewind is trying to take the book back to the present. @@ -135,6 +141,12 @@ const WorkaroundEntry workaroundList[] = { // Present Outside Inn {TINSEL_V1, false, 352600876, 0, fragment2_size, 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 this fix routes the talk parameters of the broken one + {TINSEL_V1, false, 310506872, 463, fragment4_size, fragment4}, + {TINSEL_V1, false, 310506872, 485, fragment5_size, fragment5}, + {TINSEL_V1, false, 310506872, 513, fragment6_size, fragment6}, + // 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 saved/restored during it, the animation sequence is reset without the global being cleared. // This causes bugs in several actions which try to disable the bees animation, since they wait indefinitely for @@ -636,6 +648,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_JUMP: // unconditional jump ip = Fetch(opcode, ic->code, wkEntry, ip); + wkEntry = NULL; // In case a jump occurs from a workaround break; case OP_JMPFALSE: // conditional jump @@ -644,6 +657,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { if (ic->stack[ic->sp--] == 0) { // condition satisfied - do the jump ip = tmp; + wkEntry = NULL; // In case a jump occurs from a workaround } break; @@ -653,6 +667,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { if (ic->stack[ic->sp--] != 0) { // condition satisfied - do the jump ip = tmp; + wkEntry = NULL; // In case a jump occurs from a workaround } break; diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 62bcc732a8..0069778531 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -37,6 +37,8 @@ #include "common/serializer.h" #include "common/savefile.h" +#include "gui/message.h" + namespace Tinsel { @@ -84,6 +86,8 @@ extern void syncGlobInfo(Common::Serializer &s); // in POLYGONS.C extern void syncPolyInfo(Common::Serializer &s); +extern int sceneCtr; + //----------------- LOCAL DEFINES -------------------- struct SaveGameHeader { @@ -450,6 +454,11 @@ static bool DoRestore() { delete f; + if (failed) { + GUI::MessageDialog dialog("Failed to load game state from file."); + dialog.runModal(); + } + return !failed; } @@ -471,11 +480,11 @@ static void DoSave(void) { fname = SaveSceneName; f = _vm->getSaveFileMan()->openForSaving(fname); - if (f == NULL) - return; - Common::Serializer s(0, f); + if (f == NULL) + goto save_failure; + // Write out a savegame header SaveGameHeader hdr; hdr.id = SAVEGAME_ID; @@ -500,8 +509,12 @@ static void DoSave(void) { return; save_failure: - delete f; - _vm->getSaveFileMan()->removeSavefile(fname); + if (f) { + delete f; + _vm->getSaveFileMan()->removeSavefile(fname); + } + GUI::MessageDialog dialog("Failed to save game state to file."); + dialog.runModal(); } /** @@ -510,6 +523,10 @@ save_failure: void ProcessSRQueue(void) { switch (SRstate) { case SR_DORESTORE: + // If a load has been done directly from title screens, set a larger value for scene ctr so the + // code used to skip the title screens in Discworld 1 gets properly disabled + if (sceneCtr < 10) sceneCtr = 10; + if (DoRestore()) { DoRestoreScene(srsd, false); } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 95541e3287..5f056351b6 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -26,6 +26,7 @@ #include "common/endian.h" #include "common/error.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -934,7 +935,7 @@ Common::Error TinselEngine::run() { _screenSurface.create(320, 200, 1); } - g_system->getEventManager()->registerRandomSource(_random, "tinsel"); + g_eventRec.registerRandomSource(_random, "tinsel"); _console = new Console(); diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 5d79e0fb9a..1a6546cb4c 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -26,6 +26,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "graphics/cursorman.h" @@ -73,7 +74,7 @@ ToucheEngine::ToucheEngine(OSystem *system, Common::Language language) Common::addDebugChannel(kDebugOpcodes, "Opcodes", "Opcodes debug level"); Common::addDebugChannel(kDebugMenu, "Menu", "Menu debug level"); - _eventMan->registerRandomSource(_rnd, "touche"); + g_eventRec.registerRandomSource(_rnd, "touche"); } ToucheEngine::~ToucheEngine() { diff --git a/engines/tucker/locations.cpp b/engines/tucker/locations.cpp index 4117391cdf..011410fe07 100644 --- a/engines/tucker/locations.cpp +++ b/engines/tucker/locations.cpp @@ -1671,7 +1671,7 @@ void TuckerEngine::execData3PreUpdate_locationNum26() { void TuckerEngine::updateSprite_locationNum27(int i) { int state; - if (_flagsTable[155] < 3 || _flagsTable[125] == 5) { + if (_flagsTable[155] < 3 || _flagsTable[155] == 5) { state = -1; } else if (_flagsTable[155] == 3) { state = 1; |