diff options
Diffstat (limited to 'engines/mohawk')
-rw-r--r-- | engines/mohawk/console.cpp | 41 | ||||
-rw-r--r-- | engines/mohawk/console.h | 1 | ||||
-rw-r--r-- | engines/mohawk/dialogs.cpp | 8 | ||||
-rw-r--r-- | engines/mohawk/graphics.cpp | 153 | ||||
-rw-r--r-- | engines/mohawk/graphics.h | 7 | ||||
-rw-r--r-- | engines/mohawk/myst.cpp | 5 | ||||
-rw-r--r-- | engines/mohawk/myst_scripts.cpp | 9 | ||||
-rw-r--r-- | engines/mohawk/riven.cpp | 306 | ||||
-rw-r--r-- | engines/mohawk/riven.h | 32 | ||||
-rw-r--r-- | engines/mohawk/riven_cursors.h | 296 | ||||
-rw-r--r-- | engines/mohawk/riven_external.cpp | 941 | ||||
-rw-r--r-- | engines/mohawk/riven_external.h | 14 | ||||
-rw-r--r-- | engines/mohawk/riven_saveload.cpp | 8 | ||||
-rw-r--r-- | engines/mohawk/riven_scripts.cpp | 25 | ||||
-rw-r--r-- | engines/mohawk/riven_scripts.h | 6 | ||||
-rw-r--r-- | engines/mohawk/riven_vars.cpp | 55 | ||||
-rw-r--r-- | engines/mohawk/sound.cpp | 54 | ||||
-rw-r--r-- | engines/mohawk/sound.h | 13 | ||||
-rw-r--r-- | engines/mohawk/video.cpp | 18 | ||||
-rw-r--r-- | engines/mohawk/video.h | 2 |
20 files changed, 1458 insertions, 536 deletions
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 5dcfff4f90..3eed08e3c1 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -309,6 +309,7 @@ RivenConsole::RivenConsole(MohawkEngine_Riven *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("listZipCards", WRAP_METHOD(RivenConsole, Cmd_ListZipCards)); DCmd_Register("getRMAP", WRAP_METHOD(RivenConsole, Cmd_GetRMAP)); DCmd_Register("combos", WRAP_METHOD(RivenConsole, Cmd_Combos)); + DCmd_Register("sliderState", WRAP_METHOD(RivenConsole, Cmd_SliderState)); } RivenConsole::~RivenConsole() { @@ -349,7 +350,7 @@ bool RivenConsole::Cmd_Var(int argc, const char **argv) { return true; } - uint32 *globalVar = _vm->matchVarToString(argv[1]); + uint32 *globalVar = _vm->getVar(argv[1]); if (!globalVar) { DebugPrintf("Unknown variable \'%s\'\n", argv[1]); @@ -366,19 +367,13 @@ bool RivenConsole::Cmd_Var(int argc, const char **argv) { bool RivenConsole::Cmd_PlaySound(int argc, const char **argv) { if (argc < 2) { - DebugPrintf("Usage: playSound <value> (<use main sound file, default = true>)\n"); - DebugPrintf("The main sound file is default, but you can use the word \'false\' to make it use the current stack file.\n"); - + DebugPrintf("Usage: playSound <value>\n"); return true; } _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); - - bool mainSoundFile = (argc < 3) || (scumm_stricmp(argv[2], "false") != 0); - - _vm->_sound->playSound((uint16)atoi(argv[1]), mainSoundFile); - + _vm->_sound->playSound((uint16)atoi(argv[1])); return false; } @@ -392,13 +387,9 @@ bool RivenConsole::Cmd_PlaySLST(int argc, const char **argv) { _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); - uint16 card = _vm->getCurCard(); - - if (argc == 3) - card = (uint16)atoi(argv[2]); + uint16 card = (argc == 3) ? (uint16)atoi(argv[2]) : _vm->getCurCard(); _vm->_sound->playSLST((uint16)atoi(argv[1]), card); - return false; } @@ -407,7 +398,6 @@ bool RivenConsole::Cmd_StopSound(int argc, const char **argv) { _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); - return true; } @@ -466,10 +456,11 @@ bool RivenConsole::Cmd_Hotspots(int argc, const char **argv) { DebugPrintf("Hotspot %d, index %d, BLST ID %d (", i, _vm->_hotspots[i].index, _vm->_hotspots[i].blstID); if (_vm->_hotspots[i].enabled) - DebugPrintf("enabled)\n"); + DebugPrintf("enabled"); else - DebugPrintf("disabled)\n"); + DebugPrintf("disabled"); + DebugPrintf(") - (%d, %d, %d, %d)\n", _vm->_hotspots[i].rect.left, _vm->_hotspots[i].rect.top, _vm->_hotspots[i].rect.right, _vm->_hotspots[i].rect.bottom); DebugPrintf(" Name = %s\n", _vm->getHotspotName(i).c_str()); } @@ -477,7 +468,7 @@ bool RivenConsole::Cmd_Hotspots(int argc, const char **argv) { } bool RivenConsole::Cmd_ZipMode(int argc, const char **argv) { - uint32 *zipModeActive = _vm->matchVarToString("azip"); + uint32 *zipModeActive = _vm->getVar("azip"); *zipModeActive = !(*zipModeActive); DebugPrintf("Zip Mode is "); @@ -620,9 +611,9 @@ bool RivenConsole::Cmd_Combos(int argc, const char **argv) { // You'll need to look up the Rebel Tunnel puzzle on your own; the // solution is constant. - uint32 teleCombo = *_vm->matchVarToString("tcorrectorder"); - uint32 prisonCombo = *_vm->matchVarToString("pcorrectorder"); - uint32 domeCombo = *_vm->matchVarToString("adomecombo"); + uint32 teleCombo = *_vm->getVar("tcorrectorder"); + uint32 prisonCombo = *_vm->getVar("pcorrectorder"); + uint32 domeCombo = *_vm->getVar("adomecombo"); DebugPrintf("Telescope Combo:\n "); for (int i = 0; i < 5; i++) @@ -641,6 +632,14 @@ bool RivenConsole::Cmd_Combos(int argc, const char **argv) { return true; } +bool RivenConsole::Cmd_SliderState(int argc, const char **argv) { + if (argc > 1) + _vm->_externalScriptHandler->setDomeSliderState((uint32)atoi(argv[1])); + + DebugPrintf("Dome Slider State = %08x\n", _vm->_externalScriptHandler->getDomeSliderState()); + return true; +} + LivingBooksConsole::LivingBooksConsole(MohawkEngine_LivingBooks *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("playSound", WRAP_METHOD(LivingBooksConsole, Cmd_PlaySound)); DCmd_Register("stopSound", WRAP_METHOD(LivingBooksConsole, Cmd_StopSound)); diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h index 1806c61027..beba3f8852 100644 --- a/engines/mohawk/console.h +++ b/engines/mohawk/console.h @@ -89,6 +89,7 @@ private: bool Cmd_ListZipCards(int argc, const char **argv); bool Cmd_GetRMAP(int argc, const char **argv); bool Cmd_Combos(int argc, const char **argv); + bool Cmd_SliderState(int argc, const char **argv); }; class LivingBooksConsole : public GUI::Debugger { diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index c09763cbb3..a7369b4825 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -125,17 +125,17 @@ RivenOptionsDialog::~RivenOptionsDialog() { void RivenOptionsDialog::open() { Dialog::open(); - _zipModeCheckbox->setState(*_vm->matchVarToString("azip") != 0); - _waterEffectCheckbox->setState(*_vm->matchVarToString("waterenabled") != 0); + _zipModeCheckbox->setState(*_vm->getVar("azip") != 0); + _waterEffectCheckbox->setState(*_vm->getVar("waterenabled") != 0); } void RivenOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { case kZipCmd: - *_vm->matchVarToString("azip") = _zipModeCheckbox->getState() ? 1 : 0; + *_vm->getVar("azip") = _zipModeCheckbox->getState() ? 1 : 0; break; case kWaterCmd: - *_vm->matchVarToString("waterenabled") = _waterEffectCheckbox->getState() ? 1 : 0; + *_vm->getVar("waterenabled") = _waterEffectCheckbox->getState() ? 1 : 0; break; case GUI::kCloseCmd: close(); diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index 1974aec9c2..f472a9d721 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -326,7 +326,7 @@ void RivenGraphics::drawPLST(uint16 x) { // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw // twice. There should never be a problem with doing it this way. if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) { - debug (0, "Drawing image %d", id); + debug(0, "Drawing image %d", id); copyImageToScreen(id, left, top, right, bottom); _activatedPLSTs.push_back(x); break; @@ -399,7 +399,7 @@ void RivenGraphics::clearWaterEffects() { bool RivenGraphics::runScheduledWaterEffects() { // Don't run the effect if it's disabled - if (*_vm->matchVarToString("waterenabled") == 0) + if (*_vm->getVar("waterenabled") == 0) return false; Graphics::Surface *screen = NULL; @@ -491,95 +491,106 @@ void RivenGraphics::runScheduledTransition() { _scheduledTransition = -1; // Clear scheduled transition } -// TODO: Marble Cursors/Palettes void RivenGraphics::changeCursor(uint16 num) { // All of Riven's cursors are hardcoded. See riven_cursors.h for these definitions. switch (num) { case 1002: // Zip Mode - CursorMan.replaceCursor(zipModeCursor, 16, 16, 8, 8, 0); - CursorMan.replaceCursorPalette(zipModeCursorPalette, 1, ARRAYSIZE(zipModeCursorPalette) / 4); + CursorMan.replaceCursor(s_zipModeCursor, 16, 16, 8, 8, 0); + CursorMan.replaceCursorPalette(s_zipModeCursorPalette, 1, ARRAYSIZE(s_zipModeCursorPalette) / 4); break; case 2003: // Hand Over Object - CursorMan.replaceCursor(objectHandCursor, 16, 16, 8, 8, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_objectHandCursor, 16, 16, 8, 8, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 2004: // Grabbing/Using Object - CursorMan.replaceCursor(grabbingHandCursor, 13, 13, 6, 6, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_grabbingHandCursor, 13, 13, 6, 6, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3000: // Standard Hand - CursorMan.replaceCursor(standardHandCursor, 15, 16, 6, 0, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_standardHandCursor, 15, 16, 6, 0, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3001: // Pointing Left - CursorMan.replaceCursor(pointingLeftCursor, 15, 13, 0, 3, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingLeftCursor, 15, 13, 0, 3, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3002: // Pointing Right - CursorMan.replaceCursor(pointingRightCursor, 15, 13, 14, 3, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingRightCursor, 15, 13, 14, 3, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3003: // Pointing Down (Palm Up) - CursorMan.replaceCursor(pointingDownCursorPalmUp, 13, 16, 3, 15, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingDownCursorPalmUp, 13, 16, 3, 15, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3004: // Pointing Up (Palm Up) - CursorMan.replaceCursor(pointingUpCursorPalmUp, 13, 16, 3, 0, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingUpCursorPalmUp, 13, 16, 3, 0, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3005: // Pointing Left (Curved) - CursorMan.replaceCursor(pointingLeftCursorBent, 15, 13, 0, 5, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingLeftCursorBent, 15, 13, 0, 5, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3006: // Pointing Right (Curved) - CursorMan.replaceCursor(pointingRightCursorBent, 15, 13, 14, 5, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingRightCursorBent, 15, 13, 14, 5, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 3007: // Pointing Down (Palm Down) - CursorMan.replaceCursor(pointingDownCursorPalmDown, 15, 16, 7, 15, 0); - CursorMan.replaceCursorPalette(handCursorPalette, 1, ARRAYSIZE(handCursorPalette) / 4); + CursorMan.replaceCursor(s_pointingDownCursorPalmDown, 15, 16, 7, 15, 0); + CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); break; case 4001: // Red Marble + CursorMan.replaceCursor(s_redMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_redMarbleCursorPalette, 1, ARRAYSIZE(s_redMarbleCursorPalette) / 4); break; case 4002: // Orange Marble + CursorMan.replaceCursor(s_orangeMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_orangeMarbleCursorPalette, 1, ARRAYSIZE(s_orangeMarbleCursorPalette) / 4); break; case 4003: // Yellow Marble + CursorMan.replaceCursor(s_yellowMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_yellowMarbleCursorPalette, 1, ARRAYSIZE(s_yellowMarbleCursorPalette) / 4); break; case 4004: // Green Marble + CursorMan.replaceCursor(s_greenMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_greenMarbleCursorPalette, 1, ARRAYSIZE(s_greenMarbleCursorPalette) / 4); break; case 4005: // Blue Marble + CursorMan.replaceCursor(s_blueMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_blueMarbleCursorPalette, 1, ARRAYSIZE(s_blueMarbleCursorPalette) / 4); break; case 4006: - // Purple Marble + // Violet Marble + CursorMan.replaceCursor(s_violetMarbleCursor, 12, 12, 5, 5, 0); + CursorMan.replaceCursorPalette(s_violetMarbleCursorPalette, 1, ARRAYSIZE(s_violetMarbleCursorPalette) / 4); break; case 5000: // Pellet - CursorMan.replaceCursor(pelletCursor, 8, 8, 4, 4, 0); - CursorMan.replaceCursorPalette(pelletCursorPalette, 1, ARRAYSIZE(pelletCursorPalette) / 4); + CursorMan.replaceCursor(s_pelletCursor, 8, 8, 4, 4, 0); + CursorMan.replaceCursorPalette(s_pelletCursorPalette, 1, ARRAYSIZE(s_pelletCursorPalette) / 4); break; case 9000: // Hide Cursor CursorMan.showMouse(false); break; default: - error ("Cursor %d does not exist!", num); + error("Cursor %d does not exist!", num); } if (num != 9000) // Show Cursor @@ -597,28 +608,35 @@ void RivenGraphics::showInventory() { // Clear the inventory area clearInventoryArea(); - // The demo doesn't have the inventory system and we don't want - // to show the inventory on setup screens or in other journals. - if (_vm->getFeatures() & GF_DEMO || _vm->getCurStack() == aspit) - return; - - // There are three books and three vars. We have three different - // combinations. At the start you have just Atrus' journal. Later, - // you get Catherine's journal and the trap book. Near the end, - // you lose the trap book and have just the two journals. - - bool hasCathBook = *_vm->matchVarToString("acathbook") != 0; - bool hasTrapBook = *_vm->matchVarToString("atrapbook") != 0; - - if (!hasCathBook) { - drawInventoryImage(101, g_atrusJournalRect1); - } else if (!hasTrapBook) { - drawInventoryImage(101, g_atrusJournalRect2); - drawInventoryImage(102, g_cathJournalRect2); + // Draw the demo's exit button + if (_vm->getFeatures() & GF_DEMO) { + // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo! + // The demo's extras.mhk contains all the other inventory/marble/credits image + // but has hacked tBMP 101 with "EXIT". *sigh* + drawInventoryImage(101, g_demoExitRect); } else { - drawInventoryImage(101, g_atrusJournalRect3); - drawInventoryImage(102, g_cathJournalRect3); - drawInventoryImage(100, g_trapBookRect3); + // We don't want to show the inventory on setup screens or in other journals. + if (_vm->getCurStack() == aspit) + return; + + // There are three books and three vars. We have three different + // combinations. At the start you have just Atrus' journal. Later, + // you get Catherine's journal and the trap book. Near the end, + // you lose the trap book and have just the two journals. + + bool hasCathBook = *_vm->getVar("acathbook") != 0; + bool hasTrapBook = *_vm->getVar("atrapbook") != 0; + + if (!hasCathBook) { + drawInventoryImage(101, g_atrusJournalRect1); + } else if (!hasTrapBook) { + drawInventoryImage(101, g_atrusJournalRect2); + drawInventoryImage(102, g_cathJournalRect2); + } else { + drawInventoryImage(101, g_atrusJournalRect3); + drawInventoryImage(102, g_cathJournalRect3); + drawInventoryImage(100, g_trapBookRect3); + } } _vm->_system->updateScreen(); @@ -672,6 +690,39 @@ void RivenGraphics::drawRect(Common::Rect rect, bool active) { _vm->_system->unlockScreen(); } +void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) { + // Draw tBMP id from srcRect to dstRect + ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getRawData(ID_TBMP, id)); + Graphics::Surface *surface = imageData->getSurface(); + delete imageData; + + assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()); + + for (uint16 i = 0; i < srcRect.height(); i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->bytesPerPixel); + + surface->free(); + delete surface; + + _dirtyScreen = true; +} + +void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { + ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); + Graphics::Surface *surface = imageData->getSurface(); + delete imageData; + + assert(dstRect.width() == surface->w); + + for (uint16 i = 0; i < surface->h; i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch); + + surface->free(); + delete surface; + + _dirtyScreen = true; +} + LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm) : _vm(vm) { _bmpDecoder = (_vm->getGameType() == GType_LIVINGBOOKSV1) ? new OldMohawkBitmap() : new MohawkBitmap(); _palette = new byte[256 * 4]; @@ -707,7 +758,7 @@ void LBGraphics::copyImageToScreen(uint16 image, uint16 left, uint16 right) { } void LBGraphics::setPalette(uint16 id) { - // Old Living Books gamnes use the old CTBL-style palette format while newer + // Old Living Books games use the old CTBL-style palette format while newer // games use the better tPAL format which can store partial palettes. if (_vm->getGameType() == GType_LIVINGBOOKSV1) { diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index dd1764e6d6..9419aad277 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -41,6 +41,8 @@ class MohawkBitmap; class MystBitmap; enum { + kRivenOpenHandCursor = 2003, + kRivenClosedHandCursor = 2004, kRivenMainCursor = 3000, kRivenPelletCursor = 5000, kRivenHideCursor = 9000 @@ -117,7 +119,7 @@ private: uint16 type; uint16 width; uint16 height; - } *entries; + } *entries; Common::File picFile; } _pictureFile; @@ -147,6 +149,8 @@ public: Common::Array<uint16> _activatedPLSTs; void drawPLST(uint16 x); void drawRect(Common::Rect rect, bool active); + void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect); + void drawExtrasImage(uint16 id, Common::Rect dstRect); // Water Effect void scheduleWaterEffect(uint16); @@ -181,7 +185,6 @@ private: Graphics::Surface *_mainScreen; bool _dirtyScreen; Graphics::PixelFormat _pixelFormat; - byte findBlackIndex(); }; class LBGraphics { diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 9ff301c129..6ed7a313a0 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/debug-channels.h" +#include "common/translation.h" #include "mohawk/graphics.h" #include "mohawk/myst.h" @@ -218,7 +219,7 @@ Common::Error MohawkEngine_Myst::run() { _varStore = new MystVar(this); _saveLoad = new MystSaveLoad(this, _saveFileMan); _scriptParser = new MystScriptParser(this); - _loadDialog = new GUI::SaveLoadChooser("Load Game:", "Load"); + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); _loadDialog->setSaveMode(false); _optionsDialog = new MystOptionsDialog(this); @@ -427,7 +428,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card) { // NOTE: All sounds are looped when played via the sound section of the // VIEW resources. - _sound->playSound(soundAction, true, soundActionVolume, true); + _sound->playSound(soundAction, soundActionVolume, true); } else { error("Unknown sound action %d", soundAction); } diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 2f6d178da8..a8cd643e2c 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -709,10 +709,7 @@ void MystScriptParser::playSoundBlocking(uint16 op, uint16 var, uint16 argc, uin debugC(kDebugScript, "Opcode %d: playSoundBlocking", op); debugC(kDebugScript, "\tsoundId: %d", soundId); - Audio::SoundHandle *handle = _vm->_sound->playSound(soundId); - - while (_vm->_mixer->isSoundHandleActive(*handle)) - _vm->_system->delayMillis(10); + _vm->_sound->playSoundBlocking(soundId); } else unknown(op, var, argc, argv); } @@ -870,7 +867,7 @@ void MystScriptParser::opcode_30(uint16 op, uint16 var, uint16 argc, uint16 *arg _vm->_sound->stopSound(); // TODO: Need to keep sound handle and add function to change volume of // looped running sound for kMystSoundActionChangeVolume type - _vm->_sound->playSound(soundAction, true, soundVolume); + _vm->_sound->playSound(soundAction, soundVolume); } else { debugC(kDebugScript, "Unknown"); warning("Unknown sound control value in opcode %d", op); @@ -2458,7 +2455,7 @@ void MystScriptParser::opcode_120(uint16 op, uint16 var, uint16 argc, uint16 *ar if (var8 != 0xFFFF) _vm->_varStore->setVar(var8, !_vm->_varStore->getVar(var8)); else - warning("Opcode 120: No invoking Resource Var 8 found!"); + warning("Opcode 120: No invoking Resource Var 8 found"); } else unknown(op, var, argc, argv); break; diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 07b08dc220..f2f4a42f0e 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -27,6 +27,7 @@ #include "common/events.h" #include "common/EventRecorder.h" #include "common/keyboard.h" +#include "common/translation.h" #include "mohawk/graphics.h" #include "mohawk/resource.h" @@ -44,6 +45,7 @@ Common::Rect *g_cathJournalRect2; Common::Rect *g_atrusJournalRect3; Common::Rect *g_cathJournalRect3; Common::Rect *g_trapBookRect3; +Common::Rect *g_demoExitRect; MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) { _showHotspots = false; @@ -73,6 +75,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio g_atrusJournalRect3 = new Common::Rect(222, 402, 240, 426); g_cathJournalRect3 = new Common::Rect(291, 408, 311, 419); g_trapBookRect3 = new Common::Rect(363, 396, 386, 432); + g_demoExitRect = new Common::Rect(291, 408, 317, 419); } MohawkEngine_Riven::~MohawkEngine_Riven() { @@ -92,13 +95,13 @@ MohawkEngine_Riven::~MohawkEngine_Riven() { delete g_atrusJournalRect3; delete g_cathJournalRect3; delete g_trapBookRect3; + delete g_demoExitRect; } GUI::Debugger *MohawkEngine_Riven::getDebugger() { return _console; } - Common::Error MohawkEngine_Riven::run() { MohawkEngine::run(); @@ -114,124 +117,133 @@ Common::Error MohawkEngine_Riven::run() { initVars(); - // Open extras.mhk for common images (non-existant in the demo) - if (!(getFeatures() & GF_DEMO)) { - _extrasFile = new MohawkArchive(); - _extrasFile->open("extras.mhk"); - } + // Open extras.mhk for common images + _extrasFile = new MohawkArchive(); + _extrasFile->open("extras.mhk"); // Start at main cursor _gfx->changeCursor(kRivenMainCursor); - // Load game from launcher/command line if requested - if (ConfMan.hasKey("save_slot") && !(getFeatures() & GF_DEMO)) { + // Let's begin, shall we? + if (getFeatures() & GF_DEMO) { + // Start the demo off with the videos + changeToStack(aspit); + changeToCard(6); + } else if (ConfMan.hasKey("save_slot")) { + // Load game from launcher/command line if requested uint32 gameToLoad = ConfMan.getInt("save_slot"); Common::StringArray savedGamesList = _saveLoad->generateSaveGameList(); if (gameToLoad > savedGamesList.size()) error ("Could not find saved game"); _saveLoad->loadGame(savedGamesList[gameToLoad]); - } else { // Otherwise, start us off at aspit's card 1 + } else { + // Otherwise, start us off at aspit's card 1 (the main menu) changeToStack(aspit); changeToCard(1); } + + while (!_gameOver && !shouldQuit()) + handleEvents(); + + return Common::kNoError; +} + +void MohawkEngine_Riven::handleEvents() { Common::Event event; - while (!_gameOver) { - bool needsUpdate = _gfx->runScheduledWaterEffects(); - needsUpdate |= _video->updateBackgroundMovies(); - while (_eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_MOUSEMOVE: - _mousePos = event.mouse; - checkHotspotChange(); + // Update background videos and the water effect + bool needsUpdate = _gfx->runScheduledWaterEffects(); + needsUpdate |= _video->updateBackgroundMovies(); + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + checkHotspotChange(); - // Check to show the inventory - if (_mousePos.y >= 392) + if (!(getFeatures() & GF_DEMO)) { + // Check to show the inventory, but it is always "showing" in the demo + if (_eventMan->getMousePos().y >= 392) _gfx->showInventory(); else _gfx->hideInventory(); + } - needsUpdate = true; - break; - case Common::EVENT_LBUTTONDOWN: + needsUpdate = true; + break; + case Common::EVENT_LBUTTONDOWN: + if (_curHotspot >= 0) + runHotspotScript(_curHotspot, kMouseDownScript); + break; + case Common::EVENT_LBUTTONUP: + // See RivenScript::switchCard() for more information on why we sometimes + // disable the next up event. + if (!_ignoreNextMouseUp) { if (_curHotspot >= 0) - runHotspotScript(_curHotspot, kMouseDownScript); + runHotspotScript(_curHotspot, kMouseUpScript); + else + checkInventoryClick(); + } + _ignoreNextMouseUp = false; + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_d: + if (event.kbd.flags & Common::KBD_CTRL) { + _console->attach(); + _console->onFrame(); + } break; - case Common::EVENT_LBUTTONUP: - // See RivenScript::switchCard() for more information on why we sometimes - // disable the next up event. - if (!_ignoreNextMouseUp) { - if (_curHotspot >= 0) - runHotspotScript(_curHotspot, kMouseUpScript); - else - checkInventoryClick(); + case Common::KEYCODE_SPACE: + pauseGame(); + break; + case Common::KEYCODE_F4: + _showHotspots = !_showHotspots; + if (_showHotspots) { + for (uint16 i = 0; i < _hotspotCount; i++) + _gfx->drawRect(_hotspots[i].rect, _hotspots[i].enabled); + needsUpdate = true; + } else + refreshCard(); + break; + case Common::KEYCODE_F5: + runDialog(*_optionsDialog); + updateZipMode(); + break; + case Common::KEYCODE_r: + // Return to the main menu in the demo on ctrl+r + if (event.kbd.flags & Common::KBD_CTRL && getFeatures() & GF_DEMO) { + if (_curStack != aspit) + changeToStack(aspit); + changeToCard(1); } - _ignoreNextMouseUp = false; break; - case Common::EVENT_KEYDOWN: - switch (event.kbd.keycode) { - case Common::KEYCODE_d: - if (event.kbd.flags & Common::KBD_CTRL) { - _console->attach(); - _console->onFrame(); - } - break; - case Common::KEYCODE_SPACE: - pauseGame(); - break; - case Common::KEYCODE_F4: - _showHotspots = !_showHotspots; - if (_showHotspots) { - for (uint16 i = 0; i < _hotspotCount; i++) - _gfx->drawRect(_hotspots[i].rect, _hotspots[i].enabled); - needsUpdate = true; - } else - refreshCard(); - break; - case Common::KEYCODE_F5: - runDialog(*_optionsDialog); - updateZipMode(); - break; - case Common::KEYCODE_ESCAPE: - if (getFeatures() & GF_DEMO) { - if (_curStack != aspit) - changeToStack(aspit); - changeToCard(1); - } - break; - default: - break; + case Common::KEYCODE_p: + // Play the intro videos in the demo on ctrl+p + if (event.kbd.flags & Common::KBD_CTRL && getFeatures() & GF_DEMO) { + if (_curStack != aspit) + changeToStack(aspit); + changeToCard(6); } break; default: break; } + break; + default: + break; } + } - if (_curHotspot >= 0) - runHotspotScript(_curHotspot, kMouseInsideScript); - - if (shouldQuit()) { - if (_eventMan->shouldRTL() && (getFeatures() & GF_DEMO) && !(_curStack == aspit && _curCard == 12)) { - if (_curStack != aspit) - changeToStack(aspit); - changeToCard(12); - _eventMan->resetRTL(); - continue; - } - return Common::kNoError; - } - - // Update the screen if we need to - if (needsUpdate) - _system->updateScreen(); + if (_curHotspot >= 0) + runHotspotScript(_curHotspot, kMouseInsideScript); - // Cut down on CPU usage - _system->delayMillis(10); - } + // Update the screen if we need to + if (needsUpdate) + _system->updateScreen(); - return Common::kNoError; + // Cut down on CPU usage + _system->delayMillis(10); } // Stack/Card-Related Functions @@ -240,7 +252,7 @@ void MohawkEngine_Riven::changeToStack(uint16 n) { // The endings are in reverse order because of the way the 1.02 patch works. // The only "Data3" file is j_Data3.mhk from that patch. Patch files have higher // priorities over the regular files and are therefore loaded and checked first. - static const char *endings[] = { "_Data3.mhk", "_Data2.mhk", "_Data1.mhk", "_Data.mhk" }; + static const char *endings[] = { "_Data3.mhk", "_Data2.mhk", "_Data1.mhk", "_Data.mhk", "_Sounds.mhk" }; // Don't change stack to the current stack (if the files are loaded) if (_curStack == n && !_mhk.empty()) @@ -274,9 +286,8 @@ void MohawkEngine_Riven::changeToStack(uint16 n) { if (_mhk.empty()) error("Could not load stack %s", getStackName(_curStack).c_str()); - // Stop any currently playing sounds and load the new sound file too + // Stop any currently playing sounds _sound->stopAllSLST(); - _sound->loadRivenSounds(_curStack); } // Riven uses some hacks to change stacks for linking books @@ -379,12 +390,11 @@ void MohawkEngine_Riven::loadHotspots(uint16 id) { // NOTE: The hotspot scripts are cleared by the RivenScriptManager automatically. - Common::SeekableReadStream* inStream = getRawData(ID_HSPT, id); + Common::SeekableReadStream *inStream = getRawData(ID_HSPT, id); _hotspotCount = inStream->readUint16BE(); _hotspots = new RivenHotspot[_hotspotCount]; - for (uint16 i = 0; i < _hotspotCount; i++) { _hotspots[i].enabled = true; @@ -396,26 +406,21 @@ void MohawkEngine_Riven::loadHotspots(uint16 id) { int16 right = inStream->readSint16BE(); int16 bottom = inStream->readSint16BE(); - // Riven has some weird hotspots, disable them here + // Riven has some invalid rects, disable them here + // Known weird hotspots: + // - tspit 371 (DVD: 377), hotspot 4 if (left >= right || top >= bottom) { - left = top = right = bottom = 0; - _hotspots[i].enabled = 0; + warning("%s %d hotspot %d is invalid: (%d, %d, %d, %d)", getStackName(_curStack).c_str(), _curCard, i, left, top, right, bottom); + left = top = right = bottom = 0; + _hotspots[i].enabled = 0; } _hotspots[i].rect = Common::Rect(left, top, right, bottom); _hotspots[i].u0 = inStream->readUint16BE(); - - if (_hotspots[i].u0 != 0) - warning("Hotspot %d u0 non-zero", i); - _hotspots[i].mouse_cursor = inStream->readUint16BE(); _hotspots[i].index = inStream->readUint16BE(); _hotspots[i].u1 = inStream->readSint16BE(); - - if (_hotspots[i].u1 != -1) - warning("Hotspot %d u1 not -1", i); - _hotspots[i].zipModeHotspot = inStream->readUint16BE(); // Read in the scripts now @@ -431,7 +436,7 @@ void MohawkEngine_Riven::updateZipMode() { for (uint32 i = 0; i < _hotspotCount; i++) { if (_hotspots[i].zipModeHotspot) { - if (*matchVarToString("azip") != 0) { + if (*getVar("azip") != 0) { // Check if a zip mode hotspot is enabled by checking the name/id against the ZIPS records. Common::String hotspotName = getName(HotspotNames, _hotspots[i].name_resource); @@ -455,7 +460,7 @@ void MohawkEngine_Riven::checkHotspotChange() { uint16 hotspotIndex = 0; bool foundHotspot = false; for (uint16 i = 0; i < _hotspotCount; i++) - if (_hotspots[i].enabled && _hotspots[i].rect.contains(_mousePos)) { + if (_hotspots[i].enabled && _hotspots[i].rect.contains(_eventMan->getMousePos())) { foundHotspot = true; hotspotIndex = i; } @@ -481,50 +486,71 @@ Common::String MohawkEngine_Riven::getHotspotName(uint16 hotspot) { } void MohawkEngine_Riven::checkInventoryClick() { + Common::Point mousePos = _eventMan->getMousePos(); + // Don't even bother. We're not in the inventory portion of the screen. - if (_mousePos.y < 392) + if (mousePos.y < 392) + return; + + // In the demo, check if we've clicked the exit button + if (getFeatures() & GF_DEMO) { + if (g_demoExitRect->contains(mousePos)) { + if (_curStack == aspit && _curCard == 1) { + // From the main menu, go to the "quit" screen + changeToCard(12); + } else if (_curStack == aspit && _curCard == 12) { + // From the "quit" screen, just quit + _gameOver = true; + } else { + // Otherwise, return to the main menu + if (_curStack != aspit) + changeToStack(aspit); + changeToCard(1); + } + } return; + } - // No inventory in the demo or opening screens. - if (getFeatures() & GF_DEMO || _curStack == aspit) + // No inventory shown on aspit + if (_curStack == aspit) return; // Set the return stack/card id's. - *matchVarToString("returnstackid") = _curStack; - *matchVarToString("returncardid") = _curCard; + *getVar("returnstackid") = _curStack; + *getVar("returncardid") = _curCard; // See RivenGraphics::showInventory() for an explanation // of the variables' meanings. - bool hasCathBook = *matchVarToString("acathbook") != 0; - bool hasTrapBook = *matchVarToString("atrapbook") != 0; + bool hasCathBook = *getVar("acathbook") != 0; + bool hasTrapBook = *getVar("atrapbook") != 0; // Go to the book if a hotspot contains the mouse if (!hasCathBook) { - if (g_atrusJournalRect1->contains(_mousePos)) { + if (g_atrusJournalRect1->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(5); } } else if (!hasTrapBook) { - if (g_atrusJournalRect2->contains(_mousePos)) { + if (g_atrusJournalRect2->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(5); - } else if (g_cathJournalRect2->contains(_mousePos)) { + } else if (g_cathJournalRect2->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(6); } } else { - if (g_atrusJournalRect3->contains(_mousePos)) { + if (g_atrusJournalRect3->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(5); - } else if (g_cathJournalRect3->contains(_mousePos)) { + } else if (g_cathJournalRect3->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(6); - } else if (g_trapBookRect3->contains(_mousePos)) { + } else if (g_trapBookRect3->contains(mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(7); @@ -607,8 +633,26 @@ void MohawkEngine_Riven::runHotspotScript(uint16 hotspot, uint16 scriptType) { } } +void MohawkEngine_Riven::delayAndUpdate(uint32 ms) { + uint32 startTime = _system->getMillis(); + + while (_system->getMillis() < startTime + ms && !shouldQuit()) { + bool needsUpdate = _gfx->runScheduledWaterEffects(); + needsUpdate |= _video->updateBackgroundMovies(); + + Common::Event event; + while (_system->getEventManager()->pollEvent(event)) + ; + + if (needsUpdate) + _system->updateScreen(); + + _system->delayMillis(10); // Ease off the CPU + } +} + void MohawkEngine_Riven::runLoadDialog() { - GUI::SaveLoadChooser slc("Load Game:", "Load"); + GUI::SaveLoadChooser slc(_("Load game:"), _("Load")); slc.setSaveMode(false); Common::String gameId = ConfMan.get("gameid"); @@ -636,19 +680,19 @@ Common::Error MohawkEngine_Riven::saveGameState(int slot, const char *desc) { return _saveLoad->saveGame(Common::String(desc)) ? Common::kNoError : Common::kUnknownError; } -static const char *rivenStackNames[] = { - "aspit", - "bspit", - "gspit", - "jspit", - "ospit", - "pspit", - "rspit", - "tspit" -}; - -Common::String MohawkEngine_Riven::getStackName(uint16 stack) { - return Common::String(rivenStackNames[stack]); +Common::String MohawkEngine_Riven::getStackName(uint16 stack) const { + static const char *rivenStackNames[] = { + "aspit", + "bspit", + "gspit", + "jspit", + "ospit", + "pspit", + "rspit", + "tspit" + }; + + return rivenStackNames[stack]; } bool ZipMode::operator== (const ZipMode &z) const { diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 631285455e..251a0fc753 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -74,6 +74,7 @@ extern Common::Rect *g_cathJournalRect2; extern Common::Rect *g_atrusJournalRect3; extern Common::Rect *g_cathJournalRect3; extern Common::Rect *g_trapBookRect3; +extern Common::Rect *g_demoExitRect; struct RivenHotspot { uint16 blstID; @@ -135,11 +136,11 @@ private: uint16 _curCard; uint16 _curStack; void loadCard(uint16); + void handleEvents(); // Hotspot related functions and variables uint16 _hotspotCount; void loadHotspots(uint16); - void checkHotspotChange(); void checkInventoryClick(); bool _showHotspots; void updateZipMode(); @@ -153,41 +154,44 @@ private: bool _ignoreNextMouseUp; public: - Common::SeekableReadStream *getExtrasResource(uint32 tag, uint16 id); - bool _activatedSLST; - void runLoadDialog(); - + // Stack/card/script funtions void changeToCard(uint16 dest); void changeToStack(uint16); void refreshCard(); Common::String getName(uint16 nameResource, uint16 nameID); - Common::String getStackName(uint16 stack); + Common::String getStackName(uint16 stack) const; void runCardScript(uint16 scriptType); void runUpdateScreenScript() { runCardScript(kCardUpdateScript); } - uint16 getCurCard() { return _curCard; } - uint16 getCurStack() { return _curStack; } + uint16 getCurCard() const { return _curCard; } + uint16 getCurStack() const { return _curStack; } uint16 matchRMAPToCard(uint32); uint32 getCurCardRMAP(); - Common::Point _mousePos; + // Hotspot functions/variables RivenHotspot *_hotspots; int32 _curHotspot; Common::Array<ZipMode> _zipModeData; - uint16 getHotspotCount() { return _hotspotCount; } + uint16 getHotspotCount() const { return _hotspotCount; } void runHotspotScript(uint16 hotspot, uint16 scriptType); - int32 getCurHotspot() { return _curHotspot; } + int32 getCurHotspot() const { return _curHotspot; } Common::String getHotspotName(uint16 hotspot); + void checkHotspotChange(); + // Variable functions void initVars(); - uint32 getVarCount() { return _varCount; } + uint32 getVarCount() const { return _varCount; } uint32 getGlobalVar(uint32 index); Common::String getGlobalVarName(uint32 index); uint32 *getLocalVar(uint32 index); - uint32 *matchVarToString(Common::String varName); - uint32 *matchVarToString(const char *varName); + uint32 *getVar(const Common::String &varName); + // Miscellaneous void setGameOver() { _gameOver = true; } void ignoreNextMouseUp() { _ignoreNextMouseUp = true; } + Common::SeekableReadStream *getExtrasResource(uint32 tag, uint16 id); + bool _activatedSLST; + void runLoadDialog(); + void delayAndUpdate(uint32 ms); }; } // End of namespace Mohawk diff --git a/engines/mohawk/riven_cursors.h b/engines/mohawk/riven_cursors.h index 7deaf9c33c..71cb8fd804 100644 --- a/engines/mohawk/riven_cursors.h +++ b/engines/mohawk/riven_cursors.h @@ -37,7 +37,7 @@ namespace Mohawk { // 1 = Black (0x000000) // 2 = Yellow (0xDCFF00) //////////////////////////////////////// -static const byte zipModeCursor[] = { +static const byte s_zipModeCursor[] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, @@ -61,7 +61,7 @@ static const byte zipModeCursor[] = { // Zip Mode Cursor Palette: // Palette For The Zip Mode Cursor //////////////////////////////////////// -static const byte zipModeCursorPalette[] = { +static const byte s_zipModeCursorPalette[] = { 0x00, 0x00, 0x00, 0x00, // Black 0xDC, 0xFF, 0x00, 0x00, // Yellow }; @@ -77,7 +77,7 @@ static const byte zipModeCursorPalette[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte objectHandCursor[] = { +static const byte s_objectHandCursor[] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 0, 0, 0, @@ -107,7 +107,7 @@ static const byte objectHandCursor[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte grabbingHandCursor[] = { +static const byte s_grabbingHandCursor[] = { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 1, 1, 1, 0, 0, 0, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 0, @@ -134,7 +134,7 @@ static const byte grabbingHandCursor[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte standardHandCursor[] = { +static const byte s_standardHandCursor[] = { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 1, 0, 0, 0, 0, 0, 0, @@ -164,7 +164,7 @@ static const byte standardHandCursor[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingLeftCursor[] = { +static const byte s_pointingLeftCursor[] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1, @@ -191,7 +191,7 @@ static const byte pointingLeftCursor[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingRightCursor[] = { +static const byte s_pointingRightCursor[] = { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, @@ -218,7 +218,7 @@ static const byte pointingRightCursor[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingDownCursorPalmUp[] = { +static const byte s_pointingDownCursorPalmUp[] = { 0, 0, 1, 4, 2, 2, 2, 2, 2, 4, 1, 0, 0, 0, 0, 1, 4, 2, 2, 4, 2, 2, 2, 4, 1, 0, 0, 1, 3, 4, 2, 2, 4, 4, 4, 4, 4, 1, 0, @@ -248,7 +248,7 @@ static const byte pointingDownCursorPalmUp[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingUpCursorPalmUp[] = { +static const byte s_pointingUpCursorPalmUp[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, @@ -278,7 +278,7 @@ static const byte pointingUpCursorPalmUp[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingLeftCursorBent[] = { +static const byte s_pointingLeftCursorBent[] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1, @@ -305,7 +305,7 @@ static const byte pointingLeftCursorBent[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingRightCursorBent[] = { +static const byte s_pointingRightCursorBent[] = { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, @@ -332,7 +332,7 @@ static const byte pointingRightCursorBent[] = { // 3 = Brown (0x8A672F) // 4 = Dark Peach (0xE89A62) //////////////////////////////////////// -static const byte pointingDownCursorPalmDown[] = { +static const byte s_pointingDownCursorPalmDown[] = { 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, @@ -355,7 +355,7 @@ static const byte pointingDownCursorPalmDown[] = { // Hand Cursor Palette: // Palette For All Hand Cursors //////////////////////////////////////// -static const byte handCursorPalette[] = { +static const byte s_handCursorPalette[] = { 0x00, 0x00, 0x00, 0x00, // Black 0xED, 0xCD, 0x96, 0x00, // Light Peach 0x8A, 0x67, 0x2F, 0x00, // Brown @@ -376,7 +376,7 @@ static const byte handCursorPalette[] = { // 6 = Dark Green (0x2D3300) // 7 = Darkest Gray (0x222222) //////////////////////////////////////// -static const byte pelletCursor[] = { +static const byte s_pelletCursor[] = { 0, 0, 1, 1, 2, 3, 0, 0, 0, 2, 1, 4, 1, 2, 5, 0, 4, 1, 4, 1, 2, 1, 5, 4, @@ -391,7 +391,7 @@ static const byte pelletCursor[] = { // Pellet Cursor Palette: // Palette For The Pellet Cursor //////////////////////////////////////// -static const byte pelletCursorPalette[] = { +static const byte s_pelletCursorPalette[] = { 0x5D, 0x67, 0x30, 0x00, 0x5E, 0x33, 0x33, 0x00, 0x55, 0x55, 0x55, 0x00, @@ -401,4 +401,270 @@ static const byte pelletCursorPalette[] = { 0x22, 0x22, 0x22, 0x00 }; +//////////////////////////////////////// +// Red Marble Cursor (12x12): +// Cursor When Holding The Red Marble +//////////////////////////////////////// +static const byte s_redMarbleCursor[] = { + 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 3, 4, 2, 5, 2, 2, 2, 2, 0, 0, + 0, 6, 1, 1, 2, 2, 5, 2, 2, 2, 2, 0, + 0, 6, 3, 4, 5, 2, 2, 7, 8, 5, 2, 0, + 9, 6, 10,11,2, 2, 2, 12,13,2, 2, 2, + 14,10,6, 4, 1, 2, 8, 2, 2, 5, 2, 2, + 15,16,6, 3, 1, 2, 2, 2, 2, 2, 2, 5, + 17,9,18, 3, 4, 4, 4, 5, 2, 5, 1, 2, + 0, 16,9, 6, 6, 19,1, 20,1, 4, 11,0, + 0, 17,15,18,9, 10,6, 10,3, 21,4, 0, + 0, 0, 18,15,9, 18,6, 22,10,23,0, 0, + 0, 0, 0, 0, 15,15,16,9, 0, 0, 0, 0 +}; + + +//////////////////////////////////////// +// Red Marble Cursor Palette: +// Palette For The Red Marble Cursor +//////////////////////////////////////// +static const byte s_redMarbleCursorPalette[] = { + 0xb8, 0x33, 0x32, 0x00, + 0xe5, 0x33, 0x31, 0x00, + 0x98, 0x06, 0x00, 0x00, + 0xb8, 0x00, 0x34, 0x00, + 0xe6, 0x00, 0x34, 0x00, + 0x7a, 0x04, 0x00, 0x00, + 0xe8, 0x9a, 0x62, 0x00, + 0xea, 0x31, 0x67, 0x00, + 0x6a, 0x03, 0x00, 0x00, + 0x8c, 0x00, 0x35, 0x00, + 0xb6, 0x36, 0x00, 0x00, + 0xed, 0xcd, 0x96, 0x00, + 0xe9, 0x66, 0x65, 0x00, + 0x5b, 0x35, 0x00, 0x00, + 0x5b, 0x02, 0x00, 0x00, + 0x5f, 0x00, 0x35, 0x00, + 0x4c, 0x01, 0x00, 0x00, + 0x5e, 0x33, 0x33, 0x00, + 0x89, 0x05, 0x00, 0x00, + 0xb6, 0x08, 0x00, 0x00, + 0xa7, 0x07, 0x00, 0x00, + 0x88, 0x36, 0x00, 0x00, + 0x8b, 0x33, 0x33, 0x00 +}; + +//////////////////////////////////////// +// Orange Marble Cursor (12x12): +// Cursor When Holding The Orange Marble +//////////////////////////////////////// +static const byte s_orangeMarbleCursor[] = { + 0, 0, 0, 0, 1, 2, 2, 3, 0, 0, 0, 0, + 0, 0, 4, 5, 2, 2, 3, 3, 3, 3, 0, 0, + 0, 6, 7, 4, 2, 1, 2, 2, 3, 3, 3, 0, + 0, 6, 6, 7, 1, 2, 3, 8, 9, 2, 10,0, + 11,12,7, 4, 2, 3, 3, 13,9, 2, 2, 1, + 14,15,6, 4, 2, 16,3, 3, 2, 1, 1, 1, + 14,14,12,17,4, 2, 2, 1, 2, 1, 2, 1, + 14,18,12,6, 4, 4, 4, 19,2, 19,20,4, + 0, 14,14,15,6, 15,6, 4, 4, 4, 4, 0, + 0, 14,11,14,14,12,12,12,17,6, 17,0, + 0, 0, 14,14,17,14,17,6, 6, 17,0, 0, + 0, 0, 0, 0, 14,11,14,11,0, 0, 0, 0 +}; + +//////////////////////////////////////// +// Orange Marble Cursor Palette: +// Palette For The Orange Marble Cursor +//////////////////////////////////////// +static const byte s_orangeMarbleCursorPalette[] = { + 0xe1, 0x9e, 0x00, 0x00, + 0xe3, 0x9b, 0x28, 0x00, + 0xe2, 0xcf, 0x20, 0x00, + 0xb5, 0x6a, 0x00, 0x00, + 0xb6, 0x9b, 0x29, 0x00, + 0x87, 0x69, 0x00, 0x00, + 0xb7, 0x67, 0x2f, 0x00, + 0xe9, 0xff, 0x93, 0x00, + 0xe1, 0xff, 0x5a, 0x00, + 0xe0, 0xd0, 0x00, 0x00, + 0x5e, 0x33, 0x33, 0x00, + 0x88, 0x36, 0x00, 0x00, + 0xf3, 0xff, 0xc9, 0x00, + 0x5b, 0x35, 0x00, 0x00, + 0x8b, 0x33, 0x33, 0x00, + 0xe6, 0xce, 0x5f, 0x00, + 0x8a, 0x67, 0x2f, 0x00, + 0x5d, 0x67, 0x30, 0x00, + 0xe2, 0x6a, 0x00, 0x00, + 0xb3, 0x9d, 0x00, 0x00 +}; + +//////////////////////////////////////// +// Yellow Marble Cursor (12x12): +// Cursor When Holding The Yellow Marble +//////////////////////////////////////// +static const byte s_yellowMarbleCursor[] = { + 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0, + 0, 0, 3, 4, 1, 1, 1, 5, 6, 6, 0, 0, + 0, 3, 3, 7, 1, 1, 1, 1, 2, 1, 6, 0, + 0, 3, 3, 3, 3, 1, 1, 8, 6, 1, 6, 0, + 9, 9, 3, 3, 1, 1, 2, 10,8, 1, 1, 2, + 11,9, 3, 3, 1, 1, 1, 1, 1, 1, 5, 1, + 9, 9, 12,3, 3, 1, 1, 1, 1, 1, 1, 1, + 9, 9, 9, 3, 3, 3, 3, 3, 1, 1, 1, 1, + 0, 11,9, 9, 12,3, 3, 3, 3, 3, 3, 0, + 0, 9, 9, 13,9, 14,12,3, 3, 3, 3, 0, + 0, 0, 9, 9, 9, 12,14,3, 13,3, 0, 0, + 0, 0, 0, 0, 11,9, 11,9, 0, 0, 0, 0 +}; + +//////////////////////////////////////// +// Yellow Marble Cursor Palette: +// Palette For The Yellow Marble Cursor +//////////////////////////////////////// +static const byte s_yellowMarbleCursorPalette[] = { + 0xb3, 0xd0, 0x00, 0x00, + 0xb0, 0xff, 0x00, 0x00, + 0x86, 0x9c, 0x00, 0x00, + 0x87, 0xd0, 0x00, 0x00, + 0xe0, 0xd0, 0x00, 0x00, + 0xdc, 0xff, 0x00, 0x00, + 0xb3, 0x9d, 0x00, 0x00, + 0xdc, 0xff, 0x11, 0x00, + 0x5a, 0x68, 0x00, 0x00, + 0xe1, 0xff, 0x5a, 0x00, + 0x5d, 0x67, 0x30, 0x00, + 0x87, 0x69, 0x00, 0x00, + 0x88, 0x9b, 0x2a, 0x00, + 0x5a, 0x9c, 0x00, 0x00 +}; + +//////////////////////////////////////// +// Green Marble Cursor (12x12): +// Cursor When Holding The Green Marble +//////////////////////////////////////// +static const byte s_greenMarbleCursor[] = { + 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0, + 0, 0, 4, 5, 2, 1, 2, 3, 6, 6, 0, 0, + 0, 7, 5, 8, 8, 1, 1, 2, 3, 6, 6, 0, + 0, 7, 7, 4, 8, 1, 2, 9, 6, 2, 6, 0, + 10,7, 7, 4, 1, 2, 3, 11,12,2, 2, 3, + 13,13,7, 4, 1, 2, 3, 2, 1, 2, 2, 3, + 14,13,7, 7, 5, 1, 1, 8, 2, 1, 1, 2, + 15,16,13,7, 4, 4, 5, 5, 1, 8, 1, 1, + 0, 15,13,7, 7, 7, 4, 4, 4, 5, 8, 0, + 0, 14,16,15,13, 7, 7, 7, 4,17,5, 0, + 0, 0, 10,16,13,13,13,17,18,17,0, 0, + 0, 0, 0, 0, 15,10,19,10,0, 0, 0, 0 +}; + +//////////////////////////////////////// +// Green Marble Cursor Palette: +// Palette For The Green Marble Cursor +//////////////////////////////////////// +static const byte s_greenMarbleCursorPalette[] = { + 0x0e, 0xd0, 0x00, 0x00, + 0x0f, 0xe1, 0x00, 0x00, + 0x10, 0xf2, 0x00, 0x00, + 0x0b, 0x9c, 0x00, 0x00, + 0x0c, 0xad, 0x00, 0x00, + 0x11, 0xff, 0x00, 0x00, + 0x09, 0x8a, 0x00, 0x00, + 0x0d, 0xbe, 0x00, 0x00, + 0x30, 0xff, 0x5a, 0x00, + 0x0d, 0x67, 0x30, 0x00, + 0x6b, 0xff, 0x92, 0x00, + 0x00, 0xff, 0x28, 0x00, + 0x08, 0x79, 0x00, 0x00, + 0x05, 0x57, 0x00, 0x00, + 0x30, 0x67, 0x30, 0x00, + 0x06, 0x68, 0x00, 0x00, + 0x00, 0x9b, 0x2c, 0x00, + 0x2e, 0x9c, 0x00, 0x00, + 0x2e, 0x68, 0x00, 0x00 +}; + +//////////////////////////////////////// +// Blue Marble Cursor (12x12): +// Cursor When Holding The Blue Marble +//////////////////////////////////////// +static const byte s_blueMarbleCursor[] = { + 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0, + 0, 0, 4, 5, 2, 2, 6, 3, 7, 3, 0, 0, + 0, 8, 9, 5, 10,11,2, 6, 3, 3, 7, 0, + 0, 12,13,9, 10,11,6, 14,7, 6, 3, 0, + 15,8, 4, 13,2, 6, 3, 16,17,6, 6, 3, + 18,15,19,13,10,7, 3, 6, 2, 2, 6, 7, + 20,8, 18,4, 21,11,2, 10,6, 2, 2, 2, + 15,15,18,8, 13,9, 21,5, 11,10,2, 1, + 0, 8, 15,19,15,13,13,21,21,5, 9, 0, + 0, 22,20,15, 8,19,15,19,4, 9, 4, 0, + 0, 0, 15,20,15,15,19,15,9, 15,0, 0, + 0, 0, 0, 0, 20,15, 8,15,0, 0, 0, 0 +}; + +//////////////////////////////////////// +// Blue Marble Cursor Palette: +// Palette For The Blue Marble Cursor +//////////////////////////////////////// +static const byte s_blueMarbleCursorPalette[] = { + 0x6b, 0x00, 0xd2, 0x00, + 0x66, 0x00, 0xe3, 0x00, + 0x72, 0x00, 0xff, 0x00, + 0x53, 0x2d, 0x9d, 0x00, + 0x4e, 0x00, 0xaf, 0x00, + 0x6d, 0x00, 0xf5, 0x00, + 0x7d, 0x00, 0xff, 0x00, + 0x44, 0x00, 0x69, 0x00, + 0x56, 0x00, 0x9d, 0x00, + 0x56, 0x00, 0xc0, 0x00, + 0x5e, 0x00, 0xd2, 0x00, + 0x2b, 0x31, 0x68, 0x00, + 0x3f, 0x00, 0x8c, 0x00, + 0x91, 0x22, 0xff, 0x00, + 0x41, 0x31, 0x68, 0x00, + 0xd7, 0x95, 0xff, 0x00, + 0x77, 0x22, 0xff, 0x00, + 0x2f, 0x00, 0x69, 0x00, + 0x37, 0x00, 0x7a, 0x00, + 0x27, 0x00, 0x58, 0x00, + 0x46, 0x00, 0x9d, 0x00, + 0x33, 0x33, 0x33, 0x00 +}; + +//////////////////////////////////////// +// Violet Marble Cursor (12x12): +// Cursor When Holding The Violet Marble +//////////////////////////////////////// +static const byte s_violetMarbleCursor[] = { + 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0, + 0, 0, 3, 3, 1, 1, 1, 4, 2, 4, 0, 0, + 0, 3, 3, 3, 1, 5, 1, 1, 4, 2, 4, 0, + 0, 3, 3, 3, 3, 1, 1, 6, 4, 1, 2, 0, + 3, 7, 8, 3, 1, 1, 4, 9, 4, 1, 1, 4, + 8, 7, 8, 3, 10,4, 1, 1, 1, 1, 4, 1, + 8, 3, 8, 7, 3, 1, 1, 5, 1, 1, 1, 1, + 7, 7, 11,3, 3, 3, 3, 3, 1, 3, 1, 1, + 0, 8, 7, 7, 8, 8, 7, 3, 3, 3, 1, 0, + 0, 7, 8, 3, 11,7, 3, 11,3, 10,3, 0, + 0, 0, 8, 7, 3, 3, 7, 3, 3, 3, 0, 0, + 0, 0, 0, 0, 8, 7, 11,3, 0, 0, 0, 0 +}; + +//////////////////////////////////////// +// Violet Marble Cursor Palette: +// Palette For The Violet Marble Cursor +//////////////////////////////////////// +static const byte s_violetMarbleCursorPalette[] = { + 0xaa, 0x00, 0xd1, 0x00, + 0xd8, 0x00, 0xff, 0x00, + 0x76, 0x00, 0x9d, 0x00, + 0xb5, 0x00, 0xff, 0x00, + 0x87, 0x00, 0xd2, 0x00, + 0xd7, 0x22, 0xff, 0x00, + 0x68, 0x00, 0x69, 0x00, + 0x44, 0x00, 0x69, 0x00, + 0xd7, 0x5e, 0xff, 0x00, + 0x9c, 0x00, 0x9d, 0x00, + 0x56, 0x00, 0x9d, 0x00 +}; + } // End of namespace Mohawk diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 67d621a54c..21464a6a48 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -34,8 +34,12 @@ namespace Mohawk { +static const uint32 kDomeSliderDefaultState = 0x01F00000; +static const uint32 kDomeSliderSlotCount = 25; + RivenExternal::RivenExternal(MohawkEngine_Riven *vm) : _vm(vm) { setupCommands(); + _sliderState = kDomeSliderDefaultState; } RivenExternal::~RivenExternal() { @@ -64,6 +68,8 @@ void RivenExternal::setupCommands() { COMMAND(xadisablemenureturn); COMMAND(xaenablemenureturn); COMMAND(xalaunchbrowser); + COMMAND(xadisablemenuintro); + COMMAND(xaenablemenuintro); // bspit (Bookmaking Island) external commands COMMAND(xblabopenbook); @@ -200,16 +206,33 @@ void RivenExternal::runCommand(uint16 argc, uint16 *argv) { } void RivenExternal::runDemoBoundaryDialog() { - GUI::MessageDialog dialog("This demo does not allow you\n" - "to visit that part of Riven."); + GUI::MessageDialog dialog("Exploration beyond this point available only within the full version of\n" + "the game."); dialog.runModal(); } void RivenExternal::runEndGame(uint16 video) { _vm->_sound->stopAllSLST(); - _vm->_video->playMovieBlocking(video); + _vm->_video->playMovie(video); + runCredits(video); +} +void RivenExternal::runCredits(uint16 video) { // TODO: Play until the last frame and then run the credits + + VideoHandle videoHandle = _vm->_video->findVideoHandle(video); + + while (!_vm->_video->endOfVideo(videoHandle) && !_vm->shouldQuit()) { + if (_vm->_video->updateBackgroundMovies()) + _vm->_system->updateScreen(); + + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) + ; + + _vm->_system->delayMillis(10); + } + _vm->setGameOver(); } @@ -231,7 +254,151 @@ void RivenExternal::runDomeCheck() { // frame that is the magic one is the one with the golden symbol) but we // give a 3 frame leeway in either direction. if (frameCount - curFrame < 3 || curFrame < 3) - *_vm->matchVarToString("domecheck") = 1; + *_vm->getVar("domecheck") = 1; +} + +void RivenExternal::resetDomeSliders(uint16 bitmapId, uint16 soundId, uint16 startHotspot) { + // The rightmost slider should move left until it finds the next slider, + // then those two continue until they find the third slider. This continues + // until all five sliders have returned their starting slots. + byte slidersFound = 0; + for (uint32 i = 0; i < kDomeSliderSlotCount; i++) { + if (_sliderState & (1 << i)) { + // A slider occupies this spot. Increase the number of sliders we + // have found, but we're not doing any moving this iteration. + slidersFound++; + } else { + // Move all the sliders we have found over one slot + for (byte j = 0; j < slidersFound; j++) { + _sliderState &= ~(1 << (i - j - 1)); + _sliderState |= 1 << (i - j); + } + + // If we have at least one found slider, it has now moved + // so we should redraw and play a tick sound + if (slidersFound) { + _vm->_sound->playSound(soundId); + drawDomeSliders(bitmapId, startHotspot); + _vm->_system->delayMillis(10); + } + } + } + + // Sanity checks - the slider count should always be 5 and we should end up at + // the default state after moving them all over. + assert(slidersFound == 5); + assert(_sliderState == kDomeSliderDefaultState); +} + +void RivenExternal::checkDomeSliders(uint16 resetSlidersHotspot, uint16 openDomeHotspot) { + // Let's see if we're all matched up... + if (*_vm->getVar("adomecombo") == _sliderState) { + // Set the button hotspot to the open dome hotspot + _vm->_hotspots[resetSlidersHotspot].enabled = false; + _vm->_hotspots[openDomeHotspot].enabled = true; + } else { + // Set the button hotspot to the reset sliders hotspot + _vm->_hotspots[resetSlidersHotspot].enabled = true; + _vm->_hotspots[openDomeHotspot].enabled = false; + } +} + +void RivenExternal::checkSliderCursorChange(uint16 startHotspot) { + // Set the cursor based on _sliderState and what hotspot we're over + for (uint16 i = 0; i < kDomeSliderSlotCount; i++) { + if (_vm->_hotspots[i + startHotspot].rect.contains(_vm->_system->getEventManager()->getMousePos())) { + if (_sliderState & (1 << (24 - i))) + _vm->_gfx->changeCursor(kRivenOpenHandCursor); + else + _vm->_gfx->changeCursor(kRivenMainCursor); + break; + } + } +} + +void RivenExternal::dragDomeSlider(uint16 bitmapId, uint16 soundId, uint16 resetSlidersHotspot, uint16 openDomeHotspot, uint16 startHotspot) { + int16 foundSlider = -1; + + for (uint16 i = 0; i < kDomeSliderSlotCount; i++) { + if (_vm->_hotspots[i + startHotspot].rect.contains(_vm->_system->getEventManager()->getMousePos())) { + // If the slider is not at this hotspot, we can't do anything else + if (!(_sliderState & (1 << (24 - i)))) + return; + + foundSlider = i; + break; + } + } + + // We're not over any slider + if (foundSlider < 0) + return; + + // We've clicked down, so show the closed hand cursor + _vm->_gfx->changeCursor(kRivenClosedHandCursor); + + bool done = false; + while (!done) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + if (foundSlider < 24 && !(_sliderState & (1 << (23 - foundSlider))) && _vm->_hotspots[foundSlider + startHotspot + 1].rect.contains(event.mouse)) { + // We've moved the slider right one space + _sliderState &= ~(_sliderState & (1 << (24 - foundSlider))); + foundSlider++; + _sliderState |= 1 << (24 - foundSlider); + + // Now play a click sound and redraw + _vm->_sound->playSound(soundId); + drawDomeSliders(bitmapId, startHotspot); + } else if (foundSlider > 0 && !(_sliderState & (1 << (25 - foundSlider))) && _vm->_hotspots[foundSlider + startHotspot - 1].rect.contains(event.mouse)) { + // We've moved the slider left one space + _sliderState &= ~(_sliderState & (1 << (24 - foundSlider))); + foundSlider--; + _sliderState |= 1 << (24 - foundSlider); + + // Now play a click sound and redraw + _vm->_sound->playSound(soundId); + drawDomeSliders(bitmapId, startHotspot); + } else + _vm->_system->updateScreen(); // A normal update for the cursor + break; + case Common::EVENT_LBUTTONUP: + done = true; + break; + default: + break; + } + } + _vm->_system->delayMillis(10); + } + + // Check to see if we have the right combination + checkDomeSliders(resetSlidersHotspot, openDomeHotspot); +} + +void RivenExternal::drawDomeSliders(uint16 bitmapId, uint16 startHotspot) { + Common::Rect dstAreaRect = Common::Rect(200, 250, 420, 319); + + // On pspit, the rect is different by two pixels + // (alternatively, we could just use hotspot 3 here, but only on pspit is there a hotspot for this) + if (_vm->getCurStack() == pspit) + dstAreaRect.translate(-2, 0); + + for (uint16 i = 0; i < kDomeSliderSlotCount; i++) { + Common::Rect srcRect = _vm->_hotspots[startHotspot + i].rect; + srcRect.translate(-dstAreaRect.left, -dstAreaRect.top); // Adjust the rect so it's in the destination area + + Common::Rect dstRect = _vm->_hotspots[startHotspot + i].rect; + + if (_sliderState & (1 << (24 - i))) + _vm->_gfx->drawImageRect(bitmapId, srcRect, dstRect); + else + _vm->_gfx->drawImageRect(bitmapId + 1, srcRect, dstRect); + } + + _vm->_gfx->updateScreen(); } // ------------------------------------------------------------------------------------ @@ -252,7 +419,7 @@ void RivenExternal::xasetupcomplete(uint16 argc, uint16 *argv) { void RivenExternal::xaatrusopenbook(uint16 argc, uint16 *argv) { // Get the variable - uint32 page = *_vm->matchVarToString("aatruspage"); + uint32 page = *_vm->getVar("aatruspage"); // Set hotspots depending on the page if (page == 1) { @@ -271,13 +438,13 @@ void RivenExternal::xaatrusopenbook(uint16 argc, uint16 *argv) { void RivenExternal::xaatrusbookback(uint16 argc, uint16 *argv) { // Return to where we were before entering the book - _vm->changeToStack(*_vm->matchVarToString("returnstackid")); - _vm->changeToCard(*_vm->matchVarToString("returncardid")); + _vm->changeToStack(*_vm->getVar("returnstackid")); + _vm->changeToCard(*_vm->getVar("returncardid")); } void RivenExternal::xaatrusbookprevpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("aatruspage"); + uint32 *page = _vm->getVar("aatruspage"); // Decrement the page if it's not the first page if (*page == 1) @@ -286,9 +453,9 @@ void RivenExternal::xaatrusbookprevpage(uint16 argc, uint16 *argv) { // Play the page turning sound if (_vm->getFeatures() & GF_DEMO) - _vm->_sound->playSound(4, false); + _vm->_sound->playSound(4); else - _vm->_sound->playSound(3, false); + _vm->_sound->playSound(3); // Now update the screen :) _vm->_gfx->scheduleTransition(1); @@ -297,7 +464,7 @@ void RivenExternal::xaatrusbookprevpage(uint16 argc, uint16 *argv) { void RivenExternal::xaatrusbooknextpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("aatruspage"); + uint32 *page = _vm->getVar("aatruspage"); // Increment the page if it's not the last page if (((_vm->getFeatures() & GF_DEMO) && *page == 6) || *page == 10) @@ -306,9 +473,9 @@ void RivenExternal::xaatrusbooknextpage(uint16 argc, uint16 *argv) { // Play the page turning sound if (_vm->getFeatures() & GF_DEMO) - _vm->_sound->playSound(5, false); + _vm->_sound->playSound(5); else - _vm->_sound->playSound(4, false); + _vm->_sound->playSound(4); // Now update the screen :) _vm->_gfx->scheduleTransition(0); @@ -317,7 +484,7 @@ void RivenExternal::xaatrusbooknextpage(uint16 argc, uint16 *argv) { void RivenExternal::xacathopenbook(uint16 argc, uint16 *argv) { // Get the variable - uint32 page = *_vm->matchVarToString("acathpage"); + uint32 page = *_vm->getVar("acathpage"); // Set hotspots depending on the page if (page == 1) { @@ -340,19 +507,33 @@ void RivenExternal::xacathopenbook(uint16 argc, uint16 *argv) { _vm->_gfx->drawPLST(51); if (page == 28) { - // TODO: Draw telescope combination + // Draw the telescope combination + // The images for the numbers are tBMP's 13 through 17. + // The start point is at (156, 247) + uint32 teleCombo = *_vm->getVar("tcorrectorder"); + static const uint16 kNumberWidth = 32; + static const uint16 kNumberHeight = 25; + static const uint16 kDstX = 156; + static const uint16 kDstY = 247; + + for (byte i = 0; i < 5; i++) { + uint16 offset = (getComboDigit(teleCombo, i) - 1) * kNumberWidth; + Common::Rect srcRect = Common::Rect(offset, 0, offset + kNumberWidth, kNumberHeight); + Common::Rect dstRect = Common::Rect(i * kNumberWidth + kDstX, kDstY, (i + 1) * kNumberWidth + kDstX, kDstY + kNumberHeight); + _vm->_gfx->drawImageRect(i + 13, srcRect, dstRect); + } } } void RivenExternal::xacathbookback(uint16 argc, uint16 *argv) { // Return to where we were before entering the book - _vm->changeToStack(*_vm->matchVarToString("returnstackid")); - _vm->changeToCard(*_vm->matchVarToString("returncardid")); + _vm->changeToStack(*_vm->getVar("returnstackid")); + _vm->changeToCard(*_vm->getVar("returncardid")); } void RivenExternal::xacathbookprevpage(uint16 argc, uint16 *argv) { // Get the variable - uint32 *page = _vm->matchVarToString("acathpage"); + uint32 *page = _vm->getVar("acathpage"); // Increment the page if it's not the first page if (*page == 1) @@ -360,7 +541,7 @@ void RivenExternal::xacathbookprevpage(uint16 argc, uint16 *argv) { (*page)--; // Play the page turning sound - _vm->_sound->playSound(5, false); + _vm->_sound->playSound(5); // Now update the screen :) _vm->_gfx->scheduleTransition(3); @@ -369,7 +550,7 @@ void RivenExternal::xacathbookprevpage(uint16 argc, uint16 *argv) { void RivenExternal::xacathbooknextpage(uint16 argc, uint16 *argv) { // Get the variable - uint32 *page = _vm->matchVarToString("acathpage"); + uint32 *page = _vm->getVar("acathpage"); // Increment the page if it's not the last page if (*page == 49) @@ -377,7 +558,7 @@ void RivenExternal::xacathbooknextpage(uint16 argc, uint16 *argv) { (*page)++; // Play the page turning sound - _vm->_sound->playSound(6, false); + _vm->_sound->playSound(6); // Now update the screen :) _vm->_gfx->scheduleTransition(2); @@ -386,27 +567,27 @@ void RivenExternal::xacathbooknextpage(uint16 argc, uint16 *argv) { void RivenExternal::xtrapbookback(uint16 argc, uint16 *argv) { // Return to where we were before entering the book - *_vm->matchVarToString("atrap") = 0; - _vm->changeToStack(*_vm->matchVarToString("returnstackid")); - _vm->changeToCard(*_vm->matchVarToString("returncardid")); + *_vm->getVar("atrap") = 0; + _vm->changeToStack(*_vm->getVar("returnstackid")); + _vm->changeToCard(*_vm->getVar("returncardid")); } void RivenExternal::xatrapbookclose(uint16 argc, uint16 *argv) { // Close the trap book - *_vm->matchVarToString("atrap") = 0; + *_vm->getVar("atrap") = 0; // Play the page turning sound - _vm->_sound->playSound(8, false); + _vm->_sound->playSound(8); _vm->refreshCard(); } void RivenExternal::xatrapbookopen(uint16 argc, uint16 *argv) { // Open the trap book - *_vm->matchVarToString("atrap") = 1; + *_vm->getVar("atrap") = 1; // Play the page turning sound - _vm->_sound->playSound(9, false); + _vm->_sound->playSound(9); _vm->refreshCard(); } @@ -417,42 +598,99 @@ void RivenExternal::xarestoregame(uint16 argc, uint16 *argv) { } void RivenExternal::xadisablemenureturn(uint16 argc, uint16 *argv) { - // Dummy function -- implemented in Mohawk::go + // This function would normally enable the Windows menu item for + // returning to the main menu. Ctrl+r will do this instead. + // The original also had this shortcut. } void RivenExternal::xaenablemenureturn(uint16 argc, uint16 *argv) { - // Dummy function -- implemented in Mohawk::go + // This function would normally enable the Windows menu item for + // returning to the main menu. Ctrl+r will do this instead. + // The original also had this shortcut. } void RivenExternal::xalaunchbrowser(uint16 argc, uint16 *argv) { // Well, we can't launch a browser for obvious reasons ;) + // The original text is as follows (for reference): + + // If you have an auto-dial configured connection to the Internet, + // please select YES below. + // + // America Online and CompuServe users may experience difficulty. If + // you find that you are unable to connect, please quit the Riven + // Demo, launch your browser and type in the following URL: + // + // www.redorb.com/buyriven + // + // Would you like to attempt to make the connection? + // + // [YES] [NO] + GUI::MessageDialog dialog("At this point, the Riven Demo would\n" - "open up a web browser to bring you to\n" - "the Riven website. ScummVM cannot do\n" - "that. Visit the site on your own."); + "ask if you would like to open a web browser\n" + "to bring you to the Red Orb store to buy\n" + "the game. ScummVM cannot do that and\n" + "the site no longer exists."); dialog.runModal(); } +void RivenExternal::xadisablemenuintro(uint16 argc, uint16 *argv) { + // This function would normally enable the Windows menu item for + // playing the intro. Ctrl+p will play the intro movies instead. + // The original also had this shortcut. + + // Hide the "exit" button here + _vm->_gfx->hideInventory(); +} + +void RivenExternal::xaenablemenuintro(uint16 argc, uint16 *argv) { + // This function would normally enable the Windows menu item for + // playing the intro. Ctrl+p will play the intro movies instead. + // The original also had this shortcut. + + // Show the "exit" button here + _vm->_gfx->showInventory(); +} + // ------------------------------------------------------------------------------------ // bspit (Bookmaking Island) external commands // ------------------------------------------------------------------------------------ void RivenExternal::xblabopenbook(uint16 argc, uint16 *argv) { // Get the variable - uint32 page = *_vm->matchVarToString("blabbook"); + uint32 page = *_vm->getVar("blabbook"); // Draw the image of the page based on the blabbook variable _vm->_gfx->drawPLST(page); - // TODO: Draw the dome combo if (page == 14) { - warning ("Need to draw dome combo"); + // Draw the dome combination + // The images for the numbers are tBMP's 364 through 368 + // The start point is at (240, 82) + uint32 domeCombo = *_vm->getVar("adomecombo"); + static const uint16 kNumberWidth = 32; + static const uint16 kNumberHeight = 24; + static const uint16 kDstX = 240; + static const uint16 kDstY = 82; + byte numCount = 0; + + for (int bitPos = 24; bitPos >= 0; bitPos--) { + if (domeCombo & (1 << bitPos)) { + uint16 offset = (24 - bitPos) * kNumberWidth; + Common::Rect srcRect = Common::Rect(offset, 0, offset + kNumberWidth, kNumberHeight); + Common::Rect dstRect = Common::Rect(numCount * kNumberWidth + kDstX, kDstY, (numCount + 1) * kNumberWidth + kDstX, kDstY + kNumberHeight); + _vm->_gfx->drawImageRect(numCount + 364, srcRect, dstRect); + numCount++; + } + } + + assert(numCount == 5); // Sanity check } } void RivenExternal::xblabbookprevpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("blabbook"); + uint32 *page = _vm->getVar("blabbook"); // Decrement the page if it's not the first page if (*page == 1) @@ -460,7 +698,7 @@ void RivenExternal::xblabbookprevpage(uint16 argc, uint16 *argv) { (*page)--; // Play the page turning sound - _vm->_sound->playSound(22, false); + _vm->_sound->playSound(22); // Now update the screen :) _vm->_gfx->scheduleTransition(1); @@ -469,7 +707,7 @@ void RivenExternal::xblabbookprevpage(uint16 argc, uint16 *argv) { void RivenExternal::xblabbooknextpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("blabbook"); + uint32 *page = _vm->getVar("blabbook"); // Increment the page if it's not the last page if (*page == 22) @@ -477,7 +715,7 @@ void RivenExternal::xblabbooknextpage(uint16 argc, uint16 *argv) { (*page)++; // Play the page turning sound - _vm->_sound->playSound(23, false); + _vm->_sound->playSound(23); // Now update the screen :) _vm->_gfx->scheduleTransition(0); @@ -485,8 +723,8 @@ void RivenExternal::xblabbooknextpage(uint16 argc, uint16 *argv) { } void RivenExternal::xsoundplug(uint16 argc, uint16 *argv) { - uint32 heat = *_vm->matchVarToString("bheat"); - uint32 boilerInactive = *_vm->matchVarToString("bcratergg"); + uint32 heat = *_vm->getVar("bheat"); + uint32 boilerInactive = *_vm->getVar("bcratergg"); if (heat != 0) _vm->_sound->playSLST(1, _vm->getCurCard()); @@ -497,58 +735,64 @@ void RivenExternal::xsoundplug(uint16 argc, uint16 *argv) { } void RivenExternal::xbchangeboiler(uint16 argc, uint16 *argv) { - uint32 heat = *_vm->matchVarToString("bheat"); - uint32 water = *_vm->matchVarToString("bblrwtr"); - uint32 platform = *_vm->matchVarToString("bblrgrt"); + uint32 heat = *_vm->getVar("bheat"); + uint32 water = *_vm->getVar("bblrwtr"); + uint32 platform = *_vm->getVar("bblrgrt"); + + // Stop any background videos + _vm->_video->stopVideos(); if (argv[0] == 1) { + // Water is filling/draining from the boiler if (water == 0) { - if (platform == 0) - _vm->_video->activateMLST(10, _vm->getCurCard()); - else + if (platform == 1) _vm->_video->activateMLST(12, _vm->getCurCard()); - } else if (heat == 0) { - if (platform == 0) - _vm->_video->activateMLST(19, _vm->getCurCard()); else + _vm->_video->activateMLST(10, _vm->getCurCard()); + } else if (heat == 1) { + if (platform == 1) _vm->_video->activateMLST(22, _vm->getCurCard()); - } else { - if (platform == 0) - _vm->_video->activateMLST(13, _vm->getCurCard()); else + _vm->_video->activateMLST(19, _vm->getCurCard()); + } else { + if (platform == 1) _vm->_video->activateMLST(16, _vm->getCurCard()); + else + _vm->_video->activateMLST(13, _vm->getCurCard()); } } else if (argv[0] == 2 && water != 0) { - if (heat == 0) { - if (platform == 0) - _vm->_video->activateMLST(20, _vm->getCurCard()); - else + if (heat == 1) { + // Turning on the heat + if (platform == 1) _vm->_video->activateMLST(23, _vm->getCurCard()); + else + _vm->_video->activateMLST(20, _vm->getCurCard()); } else { - if (platform == 0) + // Turning off the heat + if (platform == 1) _vm->_video->activateMLST(18, _vm->getCurCard()); else _vm->_video->activateMLST(15, _vm->getCurCard()); } } else if (argv[0] == 3) { - if (platform == 0) { - if (water == 0) { - _vm->_video->activateMLST(11, _vm->getCurCard()); - } else { - if (heat == 0) - _vm->_video->activateMLST(17, _vm->getCurCard()); - else + if (platform == 1) { + // Lowering the platform + if (water == 1) { + if (heat == 1) _vm->_video->activateMLST(24, _vm->getCurCard()); - } - } else { - if (water == 0) { - _vm->_video->activateMLST(9, _vm->getCurCard()); - } else { - if (heat == 0) - _vm->_video->activateMLST(14, _vm->getCurCard()); else + _vm->_video->activateMLST(17, _vm->getCurCard()); + } else + _vm->_video->activateMLST(11, _vm->getCurCard()); + } else { + // Raising the platform + if (water == 1) { + if (heat == 1) _vm->_video->activateMLST(21, _vm->getCurCard()); - } + else + _vm->_video->activateMLST(14, _vm->getCurCard()); + } else + _vm->_video->activateMLST(9, _vm->getCurCard()); } } @@ -557,27 +801,26 @@ void RivenExternal::xbchangeboiler(uint16 argc, uint16 *argv) { else if (argv[0] == 2) _vm->_sound->playSLST(1, _vm->getCurCard()); - _vm->_video->playMovie(11); + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(11); } void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) { - uint32 heat = *_vm->matchVarToString("bheat"); - uint32 platform = *_vm->matchVarToString("bblrgrt"); + uint32 heat = *_vm->getVar("bheat"); + uint32 platform = *_vm->getVar("bblrgrt"); if (heat) { if (platform == 0) { - _vm->_video->activateMLST(7, _vm->getCurCard()); - _vm->_video->playMovie(7); - } else { _vm->_video->activateMLST(8, _vm->getCurCard()); _vm->_video->playMovie(8); + } else { + _vm->_video->activateMLST(7, _vm->getCurCard()); + _vm->_video->playMovie(7); } } else { - _vm->_video->stopMovie(7); - _vm->_video->stopMovie(8); + _vm->_video->disableMovie(7); + _vm->_video->disableMovie(8); } - - _vm->refreshCard(); } void RivenExternal::xbsettrap(uint16 argc, uint16 *argv) { @@ -613,7 +856,7 @@ void RivenExternal::xbait(uint16 argc, uint16 *argv) { // Set the bait if we put it on the plate if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) { - *_vm->matchVarToString("bbait") = 1; + *_vm->getVar("bbait") = 1; _vm->_gfx->drawPLST(4); _vm->_gfx->updateScreen(); _vm->_hotspots[3].enabled = false; // Disable bait hotspot @@ -652,32 +895,32 @@ void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) { // Set the bait if we put it on the plate, remove otherwise if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) { - *_vm->matchVarToString("bbait") = 1; + *_vm->getVar("bbait") = 1; _vm->_gfx->drawPLST(4); _vm->_gfx->updateScreen(); _vm->_hotspots[3].enabled = false; // Disable bait hotspot _vm->_hotspots[9].enabled = true; // Enable baitplate hotspot } else { - *_vm->matchVarToString("bbait") = 0; + *_vm->getVar("bbait") = 0; _vm->_hotspots[3].enabled = true; // Enable bait hotspot _vm->_hotspots[9].enabled = false; // Disable baitplate hotspot } } void RivenExternal::xbisland190_opencard(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkDomeSliders(27, 28); } void RivenExternal::xbisland190_resetsliders(uint16 argc, uint16 *argv) { - // TODO: Dome related + resetDomeSliders(701, 41, 2); } void RivenExternal::xbisland190_slidermd(uint16 argc, uint16 *argv) { - // TODO: Dome related + dragDomeSlider(701, 41, 27, 28, 2); } void RivenExternal::xbisland190_slidermw(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkSliderCursorChange(2); } void RivenExternal::xbscpbtn(uint16 argc, uint16 *argv) { @@ -689,15 +932,17 @@ void RivenExternal::xbisland_domecheck(uint16 argc, uint16 *argv) { } void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) { + Common::Point startPos = _vm->_system->getEventManager()->getMousePos(); + // Get the variable for the valve - uint32 *valve = _vm->matchVarToString("bvalve"); + uint32 *valve = _vm->getVar("bvalve"); int changeX = 0; int changeY = 0; bool done = false; // Set the cursor to the closed position - _vm->_gfx->changeCursor(2004); + _vm->_gfx->changeCursor(kRivenClosedHandCursor); _vm->_system->updateScreen(); while (!done) { @@ -706,8 +951,8 @@ void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: - changeX = event.mouse.x - _vm->_mousePos.x; - changeY = _vm->_mousePos.y - event.mouse.y; + changeX = event.mouse.x - startPos.x; + changeY = startPos.y - event.mouse.y; _vm->_system->updateScreen(); break; case Common::EVENT_LBUTTONUP: @@ -746,26 +991,26 @@ void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) { // If we changed state and the new state is that the valve is flowing to // the boiler, we need to update the boiler state. if (*valve == 1) { - if (*_vm->matchVarToString("bidvlv") == 1) { // Check which way the water is going at the boiler - if (*_vm->matchVarToString("bblrarm") == 1) { + if (*_vm->getVar("bidvlv") == 1) { // Check which way the water is going at the boiler + if (*_vm->getVar("bblrarm") == 1) { // If the pipe is open, make sure the water is drained out - *_vm->matchVarToString("bheat") = 0; - *_vm->matchVarToString("bblrwtr") = 0; + *_vm->getVar("bheat") = 0; + *_vm->getVar("bblrwtr") = 0; } else { // If the pipe is closed, fill the boiler again - *_vm->matchVarToString("bheat") = *_vm->matchVarToString("bblrvalve"); - *_vm->matchVarToString("bblrwtr") = 1; + *_vm->getVar("bheat") = *_vm->getVar("bblrvalve"); + *_vm->getVar("bblrwtr") = 1; } } else { // Have the grating inside the boiler match the switch outside - *_vm->matchVarToString("bblrgrt") = (*_vm->matchVarToString("bblrsw") == 1) ? 0 : 1; + *_vm->getVar("bblrgrt") = (*_vm->getVar("bblrsw") == 1) ? 0 : 1; } } } void RivenExternal::xbchipper(uint16 argc, uint16 *argv) { // Why is this an external command....? - if (*_vm->matchVarToString("bvalve") == 2) + if (*_vm->getVar("bvalve") == 2) _vm->_video->playMovieBlocking(2); } @@ -786,19 +1031,19 @@ void RivenExternal::xgpincontrols(uint16 argc, uint16 *argv) { } void RivenExternal::xgisland25_opencard(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkDomeSliders(29, 30); } void RivenExternal::xgisland25_resetsliders(uint16 argc, uint16 *argv) { - // TODO: Dome related + resetDomeSliders(161, 16, 2); } void RivenExternal::xgisland25_slidermd(uint16 argc, uint16 *argv) { - // TODO: Dome related + dragDomeSlider(161, 16, 29, 30, 2); } void RivenExternal::xgisland25_slidermw(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkSliderCursorChange(2); } void RivenExternal::xgscpbtn(uint16 argc, uint16 *argv) { @@ -810,18 +1055,20 @@ void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) { } void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) { - // TODO: "Bubble" map related + // Play the deactivation of a pool if one is active and a different one is activated + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(*_vm->getVar("glkbtns") * 2); } void RivenExternal::xgwt200_scribetime(uint16 argc, uint16 *argv) { // Get the current time - *_vm->matchVarToString("gscribetime") = _vm->_system->getMillis(); + *_vm->getVar("gscribetime") = _vm->_system->getMillis(); } void RivenExternal::xgwt900_scribe(uint16 argc, uint16 *argv) { - uint32 *scribeVar = _vm->matchVarToString("gscribe"); + uint32 *scribeVar = _vm->getVar("gscribe"); - if (*scribeVar == 1 && _vm->_system->getMillis() > *_vm->matchVarToString("gscribetime") + 40000) + if (*scribeVar == 1 && _vm->_system->getMillis() > *_vm->getVar("gscribetime") + 40000) *scribeVar = 2; } @@ -863,9 +1110,9 @@ void RivenExternal::xglview_villageon(uint16 argc, uint16 *argv) { void RivenExternal::xreseticons(uint16 argc, uint16 *argv) { // Reset the icons when going to Tay (rspit) - *_vm->matchVarToString("jicons") = 0; - *_vm->matchVarToString("jiconorder") = 0; - *_vm->matchVarToString("jrbook") = 0; + *_vm->getVar("jicons") = 0; + *_vm->getVar("jiconorder") = 0; + *_vm->getVar("jrbook") = 0; } // Count up how many icons are pressed @@ -886,30 +1133,30 @@ static byte countDepressedIcons(uint32 iconOrderVar) { void RivenExternal::xicon(uint16 argc, uint16 *argv) { // Set atemp as the status of whether or not the icon can be depressed. - if (*_vm->matchVarToString("jicons") & (1 << (argv[0] - 1))) { + if (*_vm->getVar("jicons") & (1 << (argv[0] - 1))) { // This icon is depressed. Allow depression only if the last depressed icon was this one. - if ((*_vm->matchVarToString("jiconorder") & 0x1f) == argv[0]) - *_vm->matchVarToString("atemp") = 1; + if ((*_vm->getVar("jiconorder") & 0x1f) == argv[0]) + *_vm->getVar("atemp") = 1; else - *_vm->matchVarToString("atemp") = 2; + *_vm->getVar("atemp") = 2; } else - *_vm->matchVarToString("atemp") = 0; + *_vm->getVar("atemp") = 0; } void RivenExternal::xcheckicons(uint16 argc, uint16 *argv) { // Reset the icons if this is the sixth icon - uint32 *iconOrderVar = _vm->matchVarToString("jiconorder"); + uint32 *iconOrderVar = _vm->getVar("jiconorder"); if (countDepressedIcons(*iconOrderVar) == 5) { *iconOrderVar = 0; - *_vm->matchVarToString("jicons") = 0; - _vm->_sound->playSound(46, false); + *_vm->getVar("jicons") = 0; + _vm->_sound->playSound(46); } } void RivenExternal::xtoggleicon(uint16 argc, uint16 *argv) { // Get the variables - uint32 *iconsDepressed = _vm->matchVarToString("jicons"); - uint32 *iconOrderVar = _vm->matchVarToString("jiconorder"); + uint32 *iconsDepressed = _vm->getVar("jicons"); + uint32 *iconOrderVar = _vm->getVar("jiconorder"); if (*iconsDepressed & (1 << (argv[0] - 1))) { // The icon is depressed, now unpress it @@ -922,13 +1169,13 @@ void RivenExternal::xtoggleicon(uint16 argc, uint16 *argv) { } // Check if the puzzle is complete now and assign 1 to jrbook if the puzzle is complete. - if (*iconOrderVar == *_vm->matchVarToString("jiconcorrectorder")) - *_vm->matchVarToString("jrbook") = 1; + if (*iconOrderVar == *_vm->getVar("jiconcorrectorder")) + *_vm->getVar("jrbook") = 1; } void RivenExternal::xjtunnel103_pictfix(uint16 argc, uint16 *argv) { // Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle - uint32 iconsDepressed = *_vm->matchVarToString("jicons"); + uint32 iconsDepressed = *_vm->getVar("jicons"); // Now, draw which icons are depressed based on the bits of the variable if (iconsDepressed & (1 << 0)) @@ -949,7 +1196,7 @@ void RivenExternal::xjtunnel103_pictfix(uint16 argc, uint16 *argv) { void RivenExternal::xjtunnel104_pictfix(uint16 argc, uint16 *argv) { // Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle - uint32 iconsDepressed = *_vm->matchVarToString("jicons"); + uint32 iconsDepressed = *_vm->getVar("jicons"); // Now, draw which icons are depressed based on the bits of the variable if (iconsDepressed & (1 << 9)) @@ -972,7 +1219,7 @@ void RivenExternal::xjtunnel104_pictfix(uint16 argc, uint16 *argv) { void RivenExternal::xjtunnel105_pictfix(uint16 argc, uint16 *argv) { // Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle - uint32 iconsDepressed = *_vm->matchVarToString("jicons"); + uint32 iconsDepressed = *_vm->getVar("jicons"); // Now, draw which icons are depressed based on the bits of the variable if (iconsDepressed & (1 << 3)) @@ -993,7 +1240,7 @@ void RivenExternal::xjtunnel105_pictfix(uint16 argc, uint16 *argv) { void RivenExternal::xjtunnel106_pictfix(uint16 argc, uint16 *argv) { // Get the jicons variable which contains which of the stones are depressed in the rebel tunnel puzzle - uint32 iconsDepressed = *_vm->matchVarToString("jicons"); + uint32 iconsDepressed = *_vm->getVar("jicons"); // Now, draw which icons are depressed based on the bits of the variable if (iconsDepressed & (1 << 16)) @@ -1027,7 +1274,7 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) { _vm->changeToCard(_vm->matchRMAPToCard(0x183a9)); // Change to card looking straight again _vm->_video->playMovieBlocking(2); - uint32 *gallows = _vm->matchVarToString("jgallows"); + uint32 *gallows = _vm->getVar("jgallows"); if (*gallows == 1) { // If the gallows is open, play the up movie and return _vm->_video->playMovieBlocking(3); @@ -1072,15 +1319,15 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) { } void RivenExternal::xjdome25_resetsliders(uint16 argc, uint16 *argv) { - // TODO: Dome related + resetDomeSliders(_vm->getFeatures() & GF_DVD ? 547 : 548, 81, 2); } void RivenExternal::xjdome25_slidermd(uint16 argc, uint16 *argv) { - // TODO: Dome related + dragDomeSlider(_vm->getFeatures() & GF_DVD ? 547: 548, 81, 29, 28, 2); } void RivenExternal::xjdome25_slidermw(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkSliderCursorChange(2); } void RivenExternal::xjscpbtn(uint16 argc, uint16 *argv) { @@ -1092,18 +1339,20 @@ void RivenExternal::xjisland3500_domecheck(uint16 argc, uint16 *argv) { } int RivenExternal::jspitElevatorLoop() { + Common::Point startPos = _vm->_system->getEventManager()->getMousePos(); + Common::Event event; int changeLevel = 0; - _vm->_gfx->changeCursor(2004); + _vm->_gfx->changeCursor(kRivenClosedHandCursor); _vm->_system->updateScreen(); for (;;) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: - if (event.mouse.y > (_vm->_mousePos.y + 10)) { + if (event.mouse.y > (startPos.y + 10)) { changeLevel = -1; - } else if (event.mouse.y < (_vm->_mousePos.y - 10)) { + } else if (event.mouse.y < (startPos.y - 10)) { changeLevel = 1; } else { changeLevel = 0; @@ -1157,7 +1406,7 @@ void RivenExternal::xhandlecontrolmid(uint16 argc, uint16 *argv) { _vm->_video->playMovieBlocking(6); // If the whark's mouth is open, close it - uint32 *mouthVar = _vm->matchVarToString("jwmouth"); + uint32 *mouthVar = _vm->getVar("jwmouth"); if (*mouthVar == 1) { _vm->_video->playMovieBlocking(3); _vm->_video->playMovieBlocking(8); @@ -1176,27 +1425,27 @@ void RivenExternal::xhandlecontrolmid(uint16 argc, uint16 *argv) { void RivenExternal::xjplaybeetle_550(uint16 argc, uint16 *argv) { // Play a beetle animation 25% of the time - *_vm->matchVarToString("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; + *_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; } void RivenExternal::xjplaybeetle_600(uint16 argc, uint16 *argv) { // Play a beetle animation 25% of the time - *_vm->matchVarToString("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; + *_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; } void RivenExternal::xjplaybeetle_950(uint16 argc, uint16 *argv) { // Play a beetle animation 25% of the time - *_vm->matchVarToString("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; + *_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; } void RivenExternal::xjplaybeetle_1050(uint16 argc, uint16 *argv) { // Play a beetle animation 25% of the time - *_vm->matchVarToString("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; + *_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0) ? 1 : 0; } void RivenExternal::xjplaybeetle_1450(uint16 argc, uint16 *argv) { // Play a beetle animation 25% of the time as long as the girl is not present - *_vm->matchVarToString("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0 && *_vm->matchVarToString("jgirl") != 1) ? 1 : 0; + *_vm->getVar("jplaybeetle") = (_vm->_rnd->getRandomNumberRng(0, 3) == 0 && *_vm->getVar("jgirl") != 1) ? 1 : 0; } void RivenExternal::xjlagoon700_alert(uint16 argc, uint16 *argv) { @@ -1209,7 +1458,7 @@ void RivenExternal::xjlagoon800_alert(uint16 argc, uint16 *argv) { void RivenExternal::xjlagoon1500_alert(uint16 argc, uint16 *argv) { // Have the sunners move a bit as you get closer ;) - uint32 *sunners = _vm->matchVarToString("jsunners"); + uint32 *sunners = _vm->getVar("jsunners"); if (*sunners == 0) { _vm->_video->playMovieBlocking(3); } else if (*sunners == 1) { @@ -1234,14 +1483,14 @@ void RivenExternal::xorollcredittime(uint16 argc, uint16 *argv) { // WORKAROUND: The special change stuff only handles one destination and it would // be messy to modify the way that currently works. If we use the trap book on Tay, // we should be using the Tay end game sequences. - if (*_vm->matchVarToString("returnstackid") == rspit) { + if (*_vm->getVar("returnstackid") == rspit) { _vm->changeToStack(rspit); _vm->changeToCard(2); return; } // You used the trap book... why? What were you thinking? - uint32 *gehnState = _vm->matchVarToString("agehn"); + uint32 *gehnState = _vm->getVar("agehn"); if (*gehnState == 0) // Gehn who? runEndGame(1); @@ -1252,16 +1501,127 @@ void RivenExternal::xorollcredittime(uint16 argc, uint16 *argv) { } void RivenExternal::xbookclick(uint16 argc, uint16 *argv) { - // TODO: This fun external command is probably one of the most complex, - // up there with the marble puzzle ones. It involves so much... Basically, - // it's playing when Gehn holds the trap book up to you and you have to - // click on the book (hence the name of the function). Yeah, not fun. - // Lots of timing stuff needs to be done for a couple videos. + // Hide the cursor + _vm->_gfx->changeCursor(kRivenHideCursor); + + // Let's hook onto our video + VideoHandle video = _vm->_video->findVideoHandle(argv[0]); + + // Convert from the standard QuickTime base time to milliseconds + // The values are in terms of 1/600 of a second. + // Have I said how much I just *love* QuickTime? </sarcasm> + uint32 startTime = argv[1] * 1000 / 600; + uint32 endTime = argv[2] * 1000 / 600; + + // Track down our hotspot + // Of course, they're not in any sane order... + static const uint16 hotspotMap[] = { 1, 3, 2, 0 }; + Common::Rect hotspotRect = _vm->_hotspots[hotspotMap[argv[3] - 1]].rect; + + debug(0, "xbookclick:"); + debug(0, "\tVideo Code = %d", argv[0]); + debug(0, "\tStart Time = %dms", startTime); + debug(0, "\tEnd Time = %dms", endTime); + debug(0, "\tHotspot = %d -> %d", argv[3], hotspotMap[argv[3] - 1]); + + // Just let the video play while we wait until Gehn opens the trap book for us + while (_vm->_video->getElapsedTime(video) < startTime && !_vm->shouldQuit()) { + if (_vm->_video->updateBackgroundMovies()) + _vm->_system->updateScreen(); + + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) + ; + + _vm->_system->delayMillis(10); + } + + // Break out if we're quitting + if (_vm->shouldQuit()) + return; + + // Update our hotspot stuff + if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) + _vm->_gfx->changeCursor(kRivenOpenHandCursor); + else + _vm->_gfx->changeCursor(kRivenMainCursor); + + // OK, Gehn has opened the trap book and has asked us to go in. Let's watch + // and see what the player will do... + while (_vm->_video->getElapsedTime(video) < endTime && !_vm->shouldQuit()) { + bool updateScreen = _vm->_video->updateBackgroundMovies(); + + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) + _vm->_gfx->changeCursor(kRivenOpenHandCursor); + else + _vm->_gfx->changeCursor(kRivenMainCursor); + updateScreen = false; // Don't update twice, changing the cursor already updates the screen + break; + case Common::EVENT_LBUTTONUP: + if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) { + // OK, we've used the trap book! We go for ride lady! + _vm->_scriptMan->stopAllScripts(); // Stop all running scripts (so we don't remain in the cage) + _vm->_video->stopVideos(); // Stop all videos + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor + _vm->_gfx->drawPLST(3); // Black out the screen + _vm->_gfx->updateScreen(); // Update the screen + _vm->_sound->playSound(0); // Play the link sound + _vm->_video->activateMLST(7, _vm->getCurCard()); // Activate Gehn Link Video + _vm->_video->playMovieBlocking(1); // Play Gehn Link Video + *_vm->getVar("agehn") = 4; // Set Gehn to the trapped state + *_vm->getVar("atrapbook") = 1; // We've got the trap book again + _vm->_sound->playSound(0); // Play the link sound again + _vm->changeToCard(_vm->matchRMAPToCard(0x2885)); // Link out! (TODO: Shouldn't this card change?) + return; + } + break; + default: + break; + } + } + + if (updateScreen && !_vm->shouldQuit()) + _vm->_system->updateScreen(); + + _vm->_system->delayMillis(10); + } + + // Break out if we're quitting + if (_vm->shouldQuit()) + return; + + // Hide the cursor again + _vm->_gfx->changeCursor(kRivenHideCursor); + + // If there was no click and this is the third time Gehn asks us to + // use the trap book, he will shoot the player. Dead on arrival. + // Run the credits from here. + if (*_vm->getVar("agehn") == 3) { + _vm->_scriptMan->stopAllScripts(); + runCredits(argv[0]); + return; + } + + // There was no click, so just play the rest of the video. + while (!_vm->_video->endOfVideo(video) && !_vm->shouldQuit()) { + if (_vm->_video->updateBackgroundMovies()) + _vm->_system->updateScreen(); + + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) + ; + + _vm->_system->delayMillis(10); + } } void RivenExternal::xooffice30_closebook(uint16 argc, uint16 *argv) { // Close the blank linking book if it's open - uint32 *book = _vm->matchVarToString("odeskbook"); + uint32 *book = _vm->getVar("odeskbook"); if (*book != 1) return; @@ -1284,16 +1644,16 @@ void RivenExternal::xooffice30_closebook(uint16 argc, uint16 *argv) { void RivenExternal::xobedroom5_closedrawer(uint16 argc, uint16 *argv) { // Close the drawer if open when clicking on the journal. _vm->_video->playMovieBlocking(2); - *_vm->matchVarToString("ostanddrawer") = 0; + *_vm->getVar("ostanddrawer") = 0; } void RivenExternal::xogehnopenbook(uint16 argc, uint16 *argv) { - _vm->_gfx->drawPLST(*_vm->matchVarToString("ogehnpage")); + _vm->_gfx->drawPLST(*_vm->getVar("ogehnpage")); } void RivenExternal::xogehnbookprevpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("ogehnpage"); + uint32 *page = _vm->getVar("ogehnpage"); // Decrement the page if it's not the first page if (*page == 1) @@ -1301,7 +1661,7 @@ void RivenExternal::xogehnbookprevpage(uint16 argc, uint16 *argv) { (*page)--; // Play the page turning sound - _vm->_sound->playSound(12, false); + _vm->_sound->playSound(12); // Now update the screen :) _vm->_gfx->scheduleTransition(1); @@ -1310,7 +1670,7 @@ void RivenExternal::xogehnbookprevpage(uint16 argc, uint16 *argv) { void RivenExternal::xogehnbooknextpage(uint16 argc, uint16 *argv) { // Get the page variable - uint32 *page = _vm->matchVarToString("ogehnpage"); + uint32 *page = _vm->getVar("ogehnpage"); // Increment the page if it's not the last page if (*page == 13) @@ -1318,7 +1678,7 @@ void RivenExternal::xogehnbooknextpage(uint16 argc, uint16 *argv) { (*page)++; // Play the page turning sound - _vm->_sound->playSound(13, false); + _vm->_sound->playSound(13); // Now update the screen :) _vm->_gfx->scheduleTransition(0); @@ -1334,7 +1694,7 @@ void RivenExternal::xgwatch(uint16 argc, uint16 *argv) { // Hide the cursor _vm->_gfx->changeCursor(kRivenHideCursor); - uint32 *prisonCombo = _vm->matchVarToString("pcorrectorder"); + uint32 *prisonCombo = _vm->getVar("pcorrectorder"); uint32 soundTime = _vm->_system->getMillis() - 500; // Start the first sound instantly byte curSound = 0; @@ -1371,19 +1731,19 @@ void RivenExternal::xgwatch(uint16 argc, uint16 *argv) { void RivenExternal::xpisland990_elevcombo(uint16 argc, uint16 *argv) { // Play button sound based on argv[0] - _vm->_sound->playSound(argv[0] + 5, false); + _vm->_sound->playSound(argv[0] + 5); // It is impossible to get here if Gehn is not trapped. However, // the original also disallows brute forcing the ending if you have // not yet trapped Gehn. - if (*_vm->matchVarToString("agehn") != 4) + if (*_vm->getVar("agehn") != 4) return; - uint32 *correctDigits = _vm->matchVarToString("pelevcombo"); + uint32 *correctDigits = _vm->getVar("pelevcombo"); // pelevcombo keeps count of how many buttons we have pressed in the correct order. // When pelevcombo is 5, clicking the handle will show the video freeing Catherine. - if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->matchVarToString("pcorrectorder"), *correctDigits)) + if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->getVar("pcorrectorder"), *correctDigits)) *correctDigits += 1; else *correctDigits = 0; @@ -1398,19 +1758,19 @@ void RivenExternal::xpisland290_domecheck(uint16 argc, uint16 *argv) { } void RivenExternal::xpisland25_opencard(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkDomeSliders(31, 5); } void RivenExternal::xpisland25_resetsliders(uint16 argc, uint16 *argv) { - // TODO: Dome related + resetDomeSliders(58, 10, 6); } void RivenExternal::xpisland25_slidermd(uint16 argc, uint16 *argv) { - // TODO: Dome related + dragDomeSlider(58, 10, 31, 5, 6); } void RivenExternal::xpisland25_slidermw(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkSliderCursorChange(6); } // ------------------------------------------------------------------------------------ @@ -1430,8 +1790,8 @@ void RivenExternal::xrcredittime(uint16 argc, uint16 *argv) { void RivenExternal::xrshowinventory(uint16 argc, uint16 *argv) { // Give the trap book and Catherine's journal to the player - *_vm->matchVarToString("atrapbook") = 1; - *_vm->matchVarToString("acathbook") = 1; + *_vm->getVar("atrapbook") = 1; + *_vm->getVar("acathbook") = 1; _vm->_gfx->showInventory(); } @@ -1452,29 +1812,29 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) { _vm->_video->playMovieBlocking(3); // Don't do anything else if the telescope power is off - if (*_vm->matchVarToString("ttelevalve") == 0) + if (*_vm->getVar("ttelevalve") == 0) return; - uint32 *telescopePos = _vm->matchVarToString("ttelescope"); - uint32 *telescopeCover = _vm->matchVarToString("ttelecover"); + uint32 *telescopePos = _vm->getVar("ttelescope"); + uint32 *telescopeCover = _vm->getVar("ttelecover"); if (*telescopePos == 1) { // We're at the bottom, which means one of two things can happen... - if (*telescopeCover == 1 && *_vm->matchVarToString("ttelepin") == 1) { + if (*telescopeCover == 1 && *_vm->getVar("ttelepin") == 1) { // ...if the cover is open and the pin is up, the game is now over. - if (*_vm->matchVarToString("pcage") == 2) { + if (*_vm->getVar("pcage") == 2) { // The best ending: Catherine is free, Gehn is trapped, Atrus comes to rescue you. // And now we fall back to Earth... all the way... warning("xtexterior300_telescopedown: Good ending"); _vm->_video->activateMLST(8, _vm->getCurCard()); runEndGame(8); - } else if (*_vm->matchVarToString("agehn") == 4) { + } else if (*_vm->getVar("agehn") == 4) { // The ok ending: Catherine is still trapped, Gehn is trapped, Atrus comes to rescue you. // Nice going! Catherine and the islanders are all dead now! Just go back to your home... warning("xtexterior300_telescopedown: OK ending"); _vm->_video->activateMLST(9, _vm->getCurCard()); runEndGame(9); - } else if (*_vm->matchVarToString("atrapbook") == 1) { + } else if (*_vm->getVar("atrapbook") == 1) { // The bad ending: Catherine is trapped, Gehn is free, Atrus gets shot by Gehn, // And then you get shot by Cho. Nice going! Catherine and the islanders are dead // and you have just set Gehn free from Riven, not to mention you're dead. @@ -1492,7 +1852,9 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) { } } else { // ...the telescope can't move down anymore. - // TODO: Play sound + // Play the sound of not being able to move + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_sound->playSoundBlocking(13); } } else { // We're not at the bottom, and we can move down again @@ -1510,14 +1872,16 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) { _vm->_video->playMovieBlocking(3); // Don't do anything else if the telescope power is off - if (*_vm->matchVarToString("ttelevalve") == 0) + if (*_vm->getVar("ttelevalve") == 0) return; - uint32 *telescopePos = _vm->matchVarToString("ttelescope"); + uint32 *telescopePos = _vm->getVar("ttelescope"); // Check if we can't move up anymore if (*telescopePos == 5) { - // TODO: Play sound + // Play the sound of not being able to move + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_sound->playSoundBlocking(13); return; } @@ -1530,9 +1894,9 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) { void RivenExternal::xtisland390_covercombo(uint16 argc, uint16 *argv) { // Called when clicking the telescope cover buttons. argv[0] is the button number (1...5). - uint32 *correctDigits = _vm->matchVarToString("tcovercombo"); + uint32 *correctDigits = _vm->getVar("tcovercombo"); - if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->matchVarToString("tcorrectorder"), *correctDigits)) + if (*correctDigits < 5 && argv[0] == getComboDigit(*_vm->getVar("tcorrectorder"), *correctDigits)) *correctDigits += 1; else *correctDigits = 0; @@ -1548,8 +1912,8 @@ void RivenExternal::xtisland390_covercombo(uint16 argc, uint16 *argv) { // Atrus' Journal and Trap Book are added to inventory void RivenExternal::xtatrusgivesbooks(uint16 argc, uint16 *argv) { // Give the player Atrus' Journal and the Trap book - *_vm->matchVarToString("aatrusbook") = 1; - *_vm->matchVarToString("atrapbook") = 1; + *_vm->getVar("aatrusbook") = 1; + *_vm->getVar("atrapbook") = 1; } // Trap Book is removed from inventory @@ -1557,35 +1921,216 @@ void RivenExternal::xtchotakesbook(uint16 argc, uint16 *argv) { // And now Cho takes the trap book. Sure, this isn't strictly // necessary to add and them remove the trap book... but it // seems better to do this ;) - *_vm->matchVarToString("atrapbook") = 0; + *_vm->getVar("atrapbook") = 0; } void RivenExternal::xthideinventory(uint16 argc, uint16 *argv) { _vm->_gfx->hideInventory(); } +// Marble Puzzle related constants +static const uint32 kMarbleCount = 6; +static const int kSmallMarbleWidth = 4; +static const int kSmallMarbleHeight = 2; +static const int kLargeMarbleSize = 8; +static const int kMarbleHotspotSize = 13; +static const char *s_marbleNames[] = { "tred", "torange", "tyellow", "tgreen", "tblue", "tviolet" }; + +// Marble Puzzle helper functions +// The y portion takes the upper 16 bits, while the x portion takes the lower 16 bits +static void setMarbleX(uint32 *var, byte x) { + *var = (*var & 0xff00) | (x + 1); +} + +static void setMarbleY(uint32 *var, byte y) { + *var = ((y + 1) << 16) | (*var & 0xff); +} + +static byte getMarbleX(uint32 *var) { + return (*var & 0xff) - 1; +} + +static byte getMarbleY(uint32 *var) { // Give that that Y you old hag! </bad Seinfeld reference> + return ((*var >> 16) & 0xff) - 1; +} + +static Common::Rect generateMarbleGridRect(uint16 x, uint16 y) { + // x/y in terms of 0! + static const int marbleGridOffsetX[] = { 134, 202, 270, 338, 406 }; + static const int marbleGridOffsetY[] = { 24, 92, 159, 227, 295 }; + + uint16 offsetX = marbleGridOffsetX[x / 5] + (x % 5) * kMarbleHotspotSize; + uint16 offsetY = marbleGridOffsetY[y / 5] + (y % 5) * kMarbleHotspotSize; + return Common::Rect(offsetX, offsetY, offsetX + kMarbleHotspotSize, offsetY + kMarbleHotspotSize); +} + void RivenExternal::xt7500_checkmarbles(uint16 argc, uint16 *argv) { - // TODO: Lots of stuff to do here, eventually we have to check each individual - // marble position and set apower based on that. The game handles the video playing - // so we don't have to. For the purposes of making the game progress further, we'll - // just turn the power on for now. - *_vm->matchVarToString("apower") = 1; + // Set apower if the marbles are in their correct spot. + + bool valid = true; + static const uint32 marbleFinalValues[] = { 1114121, 1441798, 0, 65552, 65558, 262146 }; + + for (uint16 i = 0; i < kMarbleCount; i++) + if (*_vm->getVar(s_marbleNames[i]) != marbleFinalValues[i]) { + valid = false; + break; + } + + // If we have the correct combo, activate the power and reset the marble positions + // Otherwise, make sure the power is off + if (valid) { + *_vm->getVar("apower") = 1; + for (uint16 i = 0; i < kMarbleCount; i++) + *_vm->getVar(s_marbleNames[i]) = 0; + } else + *_vm->getVar("apower") = 0; } void RivenExternal::xt7600_setupmarbles(uint16 argc, uint16 *argv) { - // TODO: Marble puzzle related + // Draw the small marbles when we're a step away from the waffle + uint16 baseBitmapId = (_vm->getFeatures() & GF_DVD) ? 539 : 526; + bool waffleDown = *_vm->getVar("twaffle") != 0; + + // Note that each of the small marble images is exactly 4x2 + + for (uint16 i = 0; i < kMarbleCount; i++) { + uint32 *var = _vm->getVar(s_marbleNames[i]); + + if (*var == 0) { + // The marble is still in its initial place + // (Note that this is still drawn even if the waffle is down) + int marbleX = 376 + i * 2; + int marbleY = 253 + i * 4; + _vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight); + } else if (waffleDown) { + // The marble is on the grid and the waffle is down + // (Nothing to draw here) + } else { + // The marble is on the grid and the waffle is up + // TODO: Draw them onto the grid + } + } +} + +void RivenExternal::setMarbleHotspots() { + // Set the hotspots + for (uint16 i = 0; i < kMarbleCount; i++) { + uint32 *marblePos = _vm->getVar(s_marbleNames[i]); + + if (*marblePos == 0) // In the receptacle + _vm->_hotspots[i + 3].rect = _marbleBaseHotspots[i]; + else // On the grid + _vm->_hotspots[i + 3].rect = generateMarbleGridRect(getMarbleX(marblePos), getMarbleY(marblePos)); + } } void RivenExternal::xt7800_setup(uint16 argc, uint16 *argv) { - // TODO: Marble puzzle related + // First, let's store the base receptacle hotspots for the marbles + if (_marbleBaseHotspots.empty()) + for (uint16 i = 0; i < kMarbleCount; i++) + _marbleBaseHotspots.push_back(_vm->_hotspots[i + 3].rect); + + // Move the marble hotspots based on their position variables + setMarbleHotspots(); + *_vm->getVar("themarble") = 0; +} + +void RivenExternal::drawMarbles() { + for (uint32 i = 0; i < kMarbleCount; i++) { + // Don't draw the marble if we're holding it + if (*_vm->getVar("themarble") - 1 == i) + continue; + + Common::Rect rect = _vm->_hotspots[i + 3].rect; + // Trim the rect down a bit + rect.left += 3; + rect.top += 3; + rect.right -= 2; + rect.bottom -= 2; + _vm->_gfx->drawExtrasImage(i + 200, rect); + } } void RivenExternal::xdrawmarbles(uint16 argc, uint16 *argv) { - // TODO: Marble puzzle related + // Draw marbles in the closeup + drawMarbles(); + + // We have to re-enable the updates here + // Would be really nice if the scripts did this for us, but alas... + _vm->_gfx->_updatesEnabled = true; } void RivenExternal::xtakeit(uint16 argc, uint16 *argv) { - // TODO: Marble puzzle related + // Pick up and move a marble + + // First, let's figure out what marble we're now holding + uint32 *marble = _vm->getVar("themarble"); + *marble = 0; + + for (uint32 i = 0; i < kMarbleCount; i++) + if (_vm->_hotspots[i + 3].rect.contains(_vm->_system->getEventManager()->getMousePos())) { + *marble = i + 1; + break; + } + + // xtakeit() shouldn't be called if we're not on a marble hotspot + assert(*marble); + + // Redraw the background + _vm->_gfx->drawPLST(1); + _vm->_gfx->updateScreen(); + + // Loop until the player lets go (or quits) + Common::Event event; + bool mouseDown = true; + while (mouseDown) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + if (event.type == Common::EVENT_LBUTTONUP) + mouseDown = false; + else if (event.type == Common::EVENT_MOUSEMOVE) + _vm->_system->updateScreen(); + else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL) + return; + } + + _vm->_system->delayMillis(10); // Take it easy on the CPU + } + + // Check if we landed in a valid location and no other marble has that location + uint32 *marblePos = _vm->getVar(s_marbleNames[*marble - 1]); + + bool foundMatch = false; + for (int y = 0; y < 25 && !foundMatch; y++) { + for (int x = 0; x < 25 && !foundMatch; x++) { + Common::Rect testHotspot = generateMarbleGridRect(x, y); + + // Let's try to place the marble! + if (testHotspot.contains(_vm->_system->getEventManager()->getMousePos())) { + // Set this as the position + setMarbleX(marblePos, x); + setMarbleY(marblePos, y); + + // Let's make sure no other marble is in this spot... + for (uint16 i = 0; i < kMarbleCount; i++) + if (i != *marble - 1 && *_vm->getVar(s_marbleNames[i]) == *marblePos) + *marblePos = 0; + + // We have a match + foundMatch = true; + } + } + } + + // If we still don't have a match, reset it to the original location + if (!foundMatch) + *marblePos = 0; + + // Check the new hotspots and refresh everything + *marble = 0; + setMarbleHotspots(); + _vm->_curHotspot = -1; + _vm->checkHotspotChange(); + _vm->_gfx->updateScreen(); } void RivenExternal::xtscpbtn(uint16 argc, uint16 *argv) { @@ -1597,19 +2142,19 @@ void RivenExternal::xtisland4990_domecheck(uint16 argc, uint16 *argv) { } void RivenExternal::xtisland5056_opencard(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkDomeSliders(29, 30); } void RivenExternal::xtisland5056_resetsliders(uint16 argc, uint16 *argv) { - // TODO: Dome related + resetDomeSliders(_vm->getFeatures() & GF_DVD ? 813 : 798, 37, 3); } void RivenExternal::xtisland5056_slidermd(uint16 argc, uint16 *argv) { - // TODO: Dome related + dragDomeSlider(_vm->getFeatures() & GF_DVD ? 813 : 798, 37, 29, 30, 3); } void RivenExternal::xtisland5056_slidermw(uint16 argc, uint16 *argv) { - // TODO: Dome related + checkSliderCursorChange(3); } void RivenExternal::xtatboundary(uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h index bdf3fa01bc..1f012c82d9 100644 --- a/engines/mohawk/riven_external.h +++ b/engines/mohawk/riven_external.h @@ -39,9 +39,13 @@ public: void runCommand(uint16 argc, uint16 *argv); uint16 getComboDigit(uint32 correctCombo, uint32 digit); + uint32 getDomeSliderState() { return _sliderState; } + void setDomeSliderState(uint32 state) { _sliderState = state; } private: MohawkEngine_Riven *_vm; + uint32 _sliderState; + Common::Array<Common::Rect> _marbleBaseHotspots; typedef void (RivenExternal::*ExternalCmd)(uint16 argc, uint16 *argv); @@ -58,8 +62,16 @@ private: int jspitElevatorLoop(); void runDemoBoundaryDialog(); void runEndGame(uint16 video); + void runCredits(uint16 video); void runDomeCheck(); void runDomeButtonMovie(); + void resetDomeSliders(uint16 bitmapId, uint16 soundId, uint16 startHotspot); + void checkDomeSliders(uint16 resetSlidersHotspot, uint16 openDomeHotspot); + void checkSliderCursorChange(uint16 startHotspot); + void dragDomeSlider(uint16 bitmapId, uint16 soundId, uint16 resetSlidersHotspot, uint16 openDomeHotspot, uint16 startHotspot); + void drawDomeSliders(uint16 bitmapId, uint16 startHotspot); + void drawMarbles(); + void setMarbleHotspots(); // ----------------------------------------------------- // aspit (Main Menu, Books, Setup) external commands @@ -86,6 +98,8 @@ private: void xadisablemenureturn(uint16 argc, uint16 *argv); void xaenablemenureturn(uint16 argc, uint16 *argv); void xalaunchbrowser(uint16 argc, uint16 *argv); + void xadisablemenuintro(uint16 argc, uint16 *argv); + void xaenablemenuintro(uint16 argc, uint16 *argv); // ----------------------------------------------------- // bspit (Boiler Island) external commands diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index d73b4ec0dc..c63a3f98fb 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -110,7 +110,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { delete vers; if ((saveGameVersion == kCDSaveGameVersion && (_vm->getFeatures() & GF_DVD)) || (saveGameVersion == kDVDSaveGameVersion && !(_vm->getFeatures() & GF_DVD))) { - warning("Incompatible saved game versions. No support for this yet."); + warning("Incompatible saved game versions. No support for this yet"); delete mhk; return false; } @@ -161,7 +161,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { if (name == "dropLeftStart" || name == "dropRightStart") continue; - uint32 *var = _vm->matchVarToString(name); + uint32 *var = _vm->getVar(name); *var = rawVariables[i]; @@ -272,8 +272,8 @@ bool RivenSaveLoad::saveGame(Common::String filename) { filename += ".rvn"; // Convert class variables to variable numbers - *_vm->matchVarToString("currentstackid") = mapNewStackIDToOld(_vm->getCurStack()); - *_vm->matchVarToString("currentcardid") = _vm->getCurCard(); + *_vm->getVar("currentstackid") = mapNewStackIDToOld(_vm->getCurStack()); + *_vm->getVar("currentcardid") = _vm->getCurCard(); Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); if (!saveFile) diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index 1fcaba8ac0..30d1d727eb 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -38,7 +38,7 @@ namespace Mohawk { RivenScript::RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType, uint16 parentStack, uint16 parentCard) : _vm(vm), _stream(stream), _scriptType(scriptType), _parentStack(parentStack), _parentCard(parentCard) { setupOpcodes(); - _isRunning = false; + _isRunning = _continueRunning = false; } RivenScript::~RivenScript() { @@ -227,7 +227,7 @@ void RivenScript::dumpCommands(Common::StringArray varNames, Common::StringArray } void RivenScript::runScript() { - _isRunning = true; + _isRunning = _continueRunning = true; if (_stream->pos() != 0) _stream->seek(0); @@ -242,7 +242,7 @@ void RivenScript::processCommands(bool runCommands) { uint16 commandCount = _stream->readUint16BE(); - for (uint16 j = 0; j < commandCount && !_vm->shouldQuit() && _stream->pos() < _stream->size(); j++) { + for (uint16 j = 0; j < commandCount && !_vm->shouldQuit() && _stream->pos() < _stream->size() && _continueRunning; j++) { uint16 command = _stream->readUint16BE(); if (command == 8) { @@ -346,9 +346,14 @@ void RivenScript::playScriptSLST(uint16 op, uint16 argc, uint16 *argv) { _vm->_activatedSLST = true; } -// Command 4: play local tWAV resource (twav_id, volume, u1) +// Command 4: play local tWAV resource (twav_id, volume, block) void RivenScript::playSound(uint16 op, uint16 argc, uint16 *argv) { - _vm->_sound->playSound(argv[0], false); + byte volume = Sound::convertRivenVolume(argv[1]); + + if (argv[2] == 1) + _vm->_sound->playSoundBlocking(argv[0], volume); + else + _vm->_sound->playSound(argv[0], volume); } // Command 7: set variable value (variable, value) @@ -398,7 +403,7 @@ void RivenScript::changeCursor(uint16 op, uint16 argc, uint16 *argv) { void RivenScript::delay(uint16 op, uint16 argc, uint16 *argv) { debug(2, "Delay %dms", argv[0]); if (argv[0] > 0) - _vm->_system->delayMillis(argv[0]); + _vm->delayAndUpdate(argv[0]); } // Command 17: call external command @@ -572,7 +577,8 @@ void RivenScript::activateFLST(uint16 op, uint16 argc, uint16 *argv) { for (uint16 i = 0; i < recordCount; i++) { uint16 index = flst->readUint16BE(); uint16 sfxeID = flst->readUint16BE(); - if(flst->readUint16BE() != 0) + + if (flst->readUint16BE() != 0) warning("FLST u0 non-zero"); if (index == argv[0]) { @@ -632,6 +638,11 @@ RivenScriptList RivenScriptManager::readScripts(Common::SeekableReadStream *stre return scriptList; } +void RivenScriptManager::stopAllScripts() { + for (uint32 i = 0; i < _currentScripts.size(); i++) + _currentScripts[i]->stopRunning(); +} + void RivenScriptManager::unloadUnusedScripts() { // Free any scripts that aren't part of the current card and aren't running for (uint32 i = 0; i < _currentScripts.size(); i++) { diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index 5187bbde08..a85cde1702 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -62,6 +62,7 @@ public: uint16 getParentStack() { return _parentStack; } uint16 getParentCard() { return _parentCard; } bool isRunning() { return _isRunning; } + void stopRunning() { _continueRunning = false; } static uint32 calculateScriptSize(Common::SeekableReadStream *script); @@ -76,8 +77,8 @@ private: MohawkEngine_Riven *_vm; Common::SeekableReadStream *_stream; - uint16 _scriptType, _parentStack, _parentCard, _parentHotspot; - bool _isRunning; + uint16 _scriptType, _parentStack, _parentCard; + bool _isRunning, _continueRunning; void dumpCommands(Common::StringArray varNames, Common::StringArray xNames, byte tabs); void processCommands(bool runCommands); @@ -131,6 +132,7 @@ public: ~RivenScriptManager(); RivenScriptList readScripts(Common::SeekableReadStream *stream, bool garbageCollect = true); + void stopAllScripts(); private: void unloadUnusedScripts(); diff --git a/engines/mohawk/riven_vars.cpp b/engines/mohawk/riven_vars.cpp index b6d2dff315..ae06afef01 100644 --- a/engines/mohawk/riven_vars.cpp +++ b/engines/mohawk/riven_vars.cpp @@ -271,7 +271,7 @@ static const char *variableNames[] = { }; uint32 *MohawkEngine_Riven::getLocalVar(uint32 index) { - return matchVarToString(getName(VariableNames, index)); + return getVar(getName(VariableNames, index)); } uint32 MohawkEngine_Riven::getGlobalVar(uint32 index) { @@ -279,18 +279,15 @@ uint32 MohawkEngine_Riven::getGlobalVar(uint32 index) { } Common::String MohawkEngine_Riven::getGlobalVarName(uint32 index) { - return Common::String(variableNames[index]); + return variableNames[index]; } -uint32 *MohawkEngine_Riven::matchVarToString(Common::String varName) { - return matchVarToString(varName.c_str()); -} - -uint32 *MohawkEngine_Riven::matchVarToString(const char *varName) { +uint32 *MohawkEngine_Riven::getVar(const Common::String &varName) { for (uint32 i = 0; i < _varCount; i++) - if (!scumm_stricmp(varName, variableNames[i])) + if (varName.equalsIgnoreCase(variableNames[i])) return &_vars[i]; - error ("Unknown variable: \'%s\'", varName); + + error ("Unknown variable: '%s'", varName.c_str()); return NULL; } @@ -304,33 +301,33 @@ void MohawkEngine_Riven::initVars() { _vars[i] = 0; // Init Variables to their correct starting state. - *matchVarToString("ttelescope") = 5; - *matchVarToString("tgatestate") = 1; - *matchVarToString("jbridge1") = 1; - *matchVarToString("jbridge4") = 1; - *matchVarToString("jgallows") = 1; - *matchVarToString("jiconcorrectorder") = 12068577; - *matchVarToString("bblrvalve") = 1; - *matchVarToString("bblrwtr") = 1; - *matchVarToString("bfans") = 1; - *matchVarToString("bytrap") = 2; - *matchVarToString("aatruspage") = 1; - *matchVarToString("acathpage") = 1; - *matchVarToString("bheat") = 1; - *matchVarToString("waterenabled") = 1; - *matchVarToString("ogehnpage") = 1; - *matchVarToString("bblrsw") = 1; - *matchVarToString("ocage") = 1; + *getVar("ttelescope") = 5; + *getVar("tgatestate") = 1; + *getVar("jbridge1") = 1; + *getVar("jbridge4") = 1; + *getVar("jgallows") = 1; + *getVar("jiconcorrectorder") = 12068577; + *getVar("bblrvalve") = 1; + *getVar("bblrwtr") = 1; + *getVar("bfans") = 1; + *getVar("bytrap") = 2; + *getVar("aatruspage") = 1; + *getVar("acathpage") = 1; + *getVar("bheat") = 1; + *getVar("waterenabled") = 1; + *getVar("ogehnpage") = 1; + *getVar("bblrsw") = 1; + *getVar("ocage") = 1; // Randomize the telescope combination - uint32 *teleCombo = matchVarToString("tcorrectorder"); + uint32 *teleCombo = getVar("tcorrectorder"); for (byte i = 0; i < 5; i++) { *teleCombo *= 10; *teleCombo += _rnd->getRandomNumberRng(1, 5); // 5 buttons } // Randomize the prison combination - uint32 *prisonCombo = matchVarToString("pcorrectorder"); + uint32 *prisonCombo = getVar("pcorrectorder"); for (byte i = 0; i < 5; i++) { *prisonCombo *= 10; *prisonCombo += _rnd->getRandomNumberRng(1, 3); // 3 buttons/sounds @@ -338,7 +335,7 @@ void MohawkEngine_Riven::initVars() { // Randomize the dome combination -- each bit represents a slider position, // the highest bit (1 << 24) represents 1, (1 << 23) represents 2, etc. - uint32 *domeCombo = matchVarToString("adomecombo"); + uint32 *domeCombo = getVar("adomecombo"); for (byte bitsSet = 0; bitsSet < 5;) { uint32 randomBit = 1 << (24 - _rnd->getRandomNumber(24)); diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 091bd68021..4a8c923c01 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -36,7 +36,6 @@ namespace Mohawk { Sound::Sound(MohawkEngine* vm) : _vm(vm) { - _rivenSoundFile = NULL; _midiDriver = NULL; _midiParser = NULL; @@ -51,7 +50,6 @@ Sound::Sound(MohawkEngine* vm) : _vm(vm) { Sound::~Sound() { stopSound(); stopAllSLST(); - delete _rivenSoundFile; if (_midiDriver) { _midiDriver->close(); @@ -64,15 +62,6 @@ Sound::~Sound() { } } -void Sound::loadRivenSounds(uint16 stack) { - static const char prefixes[] = { 'a', 'b', 'g', 'j', 'o', 'p', 'r', 't' }; - - if (!_rivenSoundFile) - _rivenSoundFile = new MohawkArchive(); - - _rivenSoundFile->open(Common::String(prefixes[stack]) + "_Sounds.mhk"); -} - void Sound::initMidi() { if (!(_vm->getFeatures() & GF_HASMIDI)) return; @@ -87,7 +76,7 @@ void Sound::initMidi() { _midiParser->setTimerRate(_midiDriver->getBaseTempo()); } -Audio::SoundHandle *Sound::playSound(uint16 id, bool mainSoundFile, byte volume, bool loop) { +Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop) { debug (0, "Playing sound %d", id); SndHandle *handle = getHandle(); @@ -113,21 +102,9 @@ Audio::SoundHandle *Sound::playSound(uint16 id, bool mainSoundFile, byte volume, } else audStream = makeMohawkWaveStream(_vm->getRawData(ID_MSND, id)); break; - case GType_RIVEN: - if (mainSoundFile) - audStream = makeMohawkWaveStream(_rivenSoundFile->getRawData(ID_TWAV, id)); - else - audStream = makeMohawkWaveStream(_vm->getRawData(ID_TWAV, id)); - break; case GType_ZOOMBINI: audStream = makeMohawkWaveStream(_vm->getRawData(ID_SND, id)); break; - case GType_CSAMTRAK: - if (mainSoundFile) - audStream = makeMohawkWaveStream(_vm->getRawData(ID_TWAV, id)); - else - audStream = getCSAmtrakMusic(id); - break; case GType_LIVINGBOOKSV1: audStream = makeOldMohawkWaveStream(_vm->getRawData(ID_WAV, id)); break; @@ -147,6 +124,13 @@ Audio::SoundHandle *Sound::playSound(uint16 id, bool mainSoundFile, byte volume, return NULL; } +void Sound::playSoundBlocking(uint16 id, byte volume) { + Audio::SoundHandle *handle = playSound(id, volume); + + while (_vm->_mixer->isSoundHandleActive(*handle)) + _vm->_system->delayMillis(10); +} + void Sound::playMidi(uint16 id) { uint32 idTag; if (!(_vm->getFeatures() & GF_HASMIDI)) { @@ -188,6 +172,10 @@ void Sound::playMidi(uint16 id) { _midiDriver->setTimerCallback(_midiParser, MidiParser::timerCallback); } +byte Sound::convertRivenVolume(uint16 volume) { + return (volume == 256) ? 255 : volume; +} + void Sound::playSLST(uint16 index, uint16 card) { Common::SeekableReadStream *slstStream = _vm->getRawData(ID_SLST, card); SLSTRecord slstRecord; @@ -304,19 +292,15 @@ void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16 sndHandle.id = id; _currentSLSTSounds.push_back(sndHandle); - Audio::AudioStream *audStream = makeMohawkWaveStream(_rivenSoundFile->getRawData(ID_TWAV, id)); + Audio::AudioStream *audStream = makeMohawkWaveStream(_vm->getRawData(ID_TWAV, id)); // Loop here if necessary if (loop) audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0); - // The max mixer volume is 255 and the max Riven volume is 256. Just change it to 255. - if (volume == 256) - volume = 255; - // TODO: Handle fading, possibly just raise the volume of the channel in increments? - _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, sndHandle.handle, audStream, -1, volume, convertBalance(balance)); + _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, sndHandle.handle, audStream, -1, convertRivenVolume(volume), convertBalance(balance)); } void Sound::stopSLSTSound(uint16 index, bool fade) { @@ -336,16 +320,6 @@ void Sound::resumeSLST() { _vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false); } -Audio::AudioStream *Sound::getCSAmtrakMusic(uint16 id) { - char filename[18]; - sprintf(filename, "MUSIC/MUSIC%02d.MHK", id); - MohawkArchive *file = new MohawkArchive(); - file->open(filename); - Audio::AudioStream *audStream = makeMohawkWaveStream(file->getRawData(ID_TWAV, 2000 + id)); - delete file; - return audStream; -} - Audio::AudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream) { uint32 tag = 0; ADPC_Chunk adpc; diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h index 0e3ecd3c51..f493130d35 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -115,28 +115,29 @@ class MohawkEngine; class Sound { public: - Sound(MohawkEngine*); + Sound(MohawkEngine *vm); ~Sound(); - void loadRivenSounds(uint16 stack); - Audio::SoundHandle *playSound(uint16 id, bool mainSoundFile = true, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false); + Audio::SoundHandle *playSound(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false); + void playSoundBlocking(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume); void playMidi(uint16 id); void stopSound(); void pauseSound(); void resumeSound(); + + // Riven-specific void playSLST(uint16 index, uint16 card); void playSLST(SLSTRecord slstRecord); void pauseSLST(); void resumeSLST(); void stopAllSLST(); + static byte convertRivenVolume(uint16 volume); private: MohawkEngine *_vm; - MohawkArchive *_rivenSoundFile; MidiDriver *_midiDriver; MidiParser *_midiParser; - static Audio::AudioStream *getCSAmtrakMusic(uint16 id); static Audio::AudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream); static Audio::AudioStream *makeOldMohawkWaveStream(Common::SeekableReadStream *stream); void initMidi(); @@ -144,7 +145,7 @@ private: Common::Array<SndHandle> _handles; SndHandle *getHandle(); - // Riven specific + // Riven-specific void playSLSTSound(uint16 index, bool fade, bool loop, uint16 volume, int16 balance); void stopSLSTSound(uint16 id, bool fade); Common::Array<SLSTSndHandle> _currentSLSTSounds; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 17456b8ec3..b7ee4c8a2c 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -123,7 +123,7 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { delete _videoStreams[videoHandle].video; _videoStreams[videoHandle].video = 0; - _videoStreams[videoHandle].id = 0; + _videoStreams[videoHandle].id = 0xffff; _videoStreams[videoHandle].filename.clear(); } @@ -156,7 +156,7 @@ bool VideoManager::updateBackgroundMovies() { } else { delete _videoStreams[i].video; _videoStreams[i].video = 0; - _videoStreams[i].id = 0; + _videoStreams[i].id = 0xffff; _videoStreams[i].filename.clear(); continue; } @@ -292,7 +292,7 @@ void VideoManager::stopMovie(uint16 id) { if (_mlstRecords[i].movieID == _videoStreams[j].id) { delete _videoStreams[j].video; _videoStreams[j].video = 0; - _videoStreams[j].id = 0; + _videoStreams[j].id = 0xffff; _videoStreams[j].filename.clear(); return; } @@ -368,7 +368,7 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u entry.x = x; entry.y = y; entry.filename = filename; - entry.id = 0; + entry.id = 0xffff; entry.loop = loop; entry.enabled = true; @@ -412,4 +412,14 @@ uint32 VideoManager::getFrameCount(const VideoHandle &handle) { return _videoStreams[handle]->getFrameCount(); } +uint32 VideoManager::getElapsedTime(const VideoHandle &handle) { + assert(handle != NULL_VID_HANDLE); + return _videoStreams[handle]->getElapsedTime(); +} + +bool VideoManager::endOfVideo(const VideoHandle &handle) { + assert(handle != NULL_VID_HANDLE); + return _videoStreams[handle]->endOfVideo(); +} + } // End of namespace Mohawk diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 6aa553e26b..4c6ed05cef 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -94,6 +94,8 @@ public: VideoHandle findVideoHandle(uint16 id); int32 getCurFrame(const VideoHandle &handle); uint32 getFrameCount(const VideoHandle &handle); + uint32 getElapsedTime(const VideoHandle &handle); + bool endOfVideo(const VideoHandle &handle); private: MohawkEngine *_vm; |