aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/myst.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk/myst.cpp')
-rw-r--r--engines/mohawk/myst.cpp287
1 files changed, 147 insertions, 140 deletions
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 5baa89cea8..a01cfdd343 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -54,7 +54,8 @@
namespace Mohawk {
-MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) {
+MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc) :
+ MohawkEngine(syst, gamedesc) {
DebugMan.addDebugChannel(kDebugVariable, "Variable", "Track Variable Accesses");
DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function");
DebugMan.addDebugChannel(kDebugView, "View", "Track Card File (VIEW) Parsing");
@@ -69,7 +70,9 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_currentCursor = 0;
_mainCursor = kDefaultMystCursor;
_showResourceRects = false;
+ _curStack = 0;
_curCard = 0;
+ _lastSaveTime = 0;
_hoverResource = nullptr;
_activeResource = nullptr;
@@ -82,13 +85,20 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_scriptParser = nullptr;
_gameState = nullptr;
_optionsDialog = nullptr;
+ _rnd = nullptr;
_prevStack = nullptr;
_mouseClicked = false;
_mouseMoved = false;
_escapePressed = false;
- _interactive = true;
+ _waitingOnBlockingOperation = false;
+ _runExitScript = true;
+
+ _needsPageDrop = false;
+ _needsShowCredits = false;
+ _needsShowDemoMenu = false;
+ _needsShowMap = false;
}
MohawkEngine_Myst::~MohawkEngine_Myst() {
@@ -253,8 +263,40 @@ void MohawkEngine_Myst::playMovieBlocking(const Common::String &name, MystStack
waitUntilMovieEnds(video);
}
-void MohawkEngine_Myst::playFlybyMovie(const Common::String &name) {
- Common::String filename = wrapMovieFilename(name, kMasterpieceOnly);
+void MohawkEngine_Myst::playFlybyMovie(uint16 stack, uint16 card) {
+ static const uint16 kMasterpieceOnly = 0xFFFF;
+
+ // Play Flyby Entry Movie on Masterpiece Edition.
+ const char *flyby = nullptr;
+
+ switch (stack) {
+ case kSeleniticStack:
+ flyby = "selenitic flyby";
+ break;
+ case kStoneshipStack:
+ flyby = "stoneship flyby";
+ break;
+ // Myst Flyby Movie not used in Original Masterpiece Edition Engine
+ // We play it when first arriving on Myst, and if the user has chosen so.
+ case kMystStack:
+ if (ConfMan.getBool("playmystflyby"))
+ flyby = "myst flyby";
+ break;
+ case kMechanicalStack:
+ flyby = "mech age flyby";
+ break;
+ case kChannelwoodStack:
+ flyby = "channelwood flyby";
+ break;
+ default:
+ break;
+ }
+
+ if (!flyby) {
+ return;
+ }
+
+ Common::String filename = wrapMovieFilename(flyby, kMasterpieceOnly);
VideoEntryPtr video = _video->playMovie(filename, Audio::Mixer::kSFXSoundType);
if (!video) {
error("Failed to open the '%s' movie", filename.c_str());
@@ -271,7 +313,7 @@ void MohawkEngine_Myst::waitUntilMovieEnds(const VideoEntryPtr &video) {
if (!video)
return;
- _interactive = false;
+ _waitingOnBlockingOperation = true;
// Sanity check
if (video->isLooping())
@@ -289,17 +331,17 @@ void MohawkEngine_Myst::waitUntilMovieEnds(const VideoEntryPtr &video) {
// Ensure it's removed
_video->removeEntry(video);
- _interactive = true;
+ _waitingOnBlockingOperation = false;
}
void MohawkEngine_Myst::playSoundBlocking(uint16 id) {
- _interactive = false;
+ _waitingOnBlockingOperation = true;
_sound->playEffect(id);
while (_sound->isEffectPlaying() && !shouldQuit()) {
doFrame();
}
- _interactive = true;
+ _waitingOnBlockingOperation = false;
}
Common::Error MohawkEngine_Myst::run() {
@@ -340,9 +382,6 @@ Common::Error MohawkEngine_Myst::run() {
_mhk.push_back(mhk);
}
- // Test Load Function...
- loadHelp(10000);
-
while (!shouldQuit()) {
doFrame();
}
@@ -353,10 +392,14 @@ Common::Error MohawkEngine_Myst::run() {
void MohawkEngine_Myst::doFrame() {
// Update any background videos
_video->updateMovies();
- if (!_scriptParser->isScriptRunning() && _interactive) {
- _interactive = false;
+ if (isInteractive()) {
+ _waitingOnBlockingOperation = true;
_scriptParser->runPersistentScripts();
- _interactive = true;
+ _waitingOnBlockingOperation = false;
+ }
+
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ tryAutoSaving();
}
Common::Event event;
@@ -410,9 +453,19 @@ void MohawkEngine_Myst::doFrame() {
}
if (_needsShowCredits) {
- _cursor->hideCursor();
- changeToStack(kCreditsStack, 10000, 0, 0);
- _needsShowCredits = false;
+ if (isInteractive()) {
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+
+ _cursor->hideCursor();
+ changeToStack(kCreditsStack, 10000, 0, 0);
+ _needsShowCredits = false;
+ } else {
+ // Showing the credits in the middle of a script is not possible
+ // because it unloads the previous age, removing data needed by the
+ // rest of the script. Instead we just quit without showing the credits.
+ quitGame();
+ }
}
break;
case Common::KEYCODE_ESCAPE:
@@ -431,12 +484,17 @@ void MohawkEngine_Myst::doFrame() {
break;
}
break;
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+ break;
default:
break;
}
}
- if (!_scriptParser->isScriptRunning() && _interactive) {
+ if (isInteractive()) {
updateActiveResource();
checkCurrentResource();
}
@@ -448,7 +506,7 @@ void MohawkEngine_Myst::doFrame() {
}
bool MohawkEngine_Myst::wait(uint32 duration, bool skippable) {
- _interactive = false;
+ _waitingOnBlockingOperation = true;
uint32 end = getTotalPlayTime() + duration;
do {
@@ -460,7 +518,7 @@ bool MohawkEngine_Myst::wait(uint32 duration, bool skippable) {
}
} while (getTotalPlayTime() < end && !shouldQuit());
- _interactive = true;
+ _waitingOnBlockingOperation = false;
return false;
}
@@ -480,20 +538,27 @@ void MohawkEngine_Myst::pauseEngineIntern(bool pause) {
void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound) {
debug(2, "changeToStack(%d)", stack);
- _curStack = stack;
-
// Fill screen with black and empty cursor
_cursor->setCursor(0);
_currentCursor = 0;
+ _sound->stopEffect();
+ _video->stopVideos();
+
+ // In Myst ME, play a fullscreen flyby movie, except when loading saves.
+ // Also play a flyby when first linking to Myst.
+ if (getFeatures() & GF_ME
+ && (_curStack != kIntroStack || (stack == kMystStack && card == 4134))) {
+ playFlybyMovie(stack, card);
+ }
+
+ _sound->stopBackground();
+
if (getFeatures() & GF_ME)
_system->fillScreen(_system->getScreenFormat().RGBToColor(0, 0, 0));
else
_gfx->clearScreenPalette();
- _sound->stopEffect();
- _sound->stopBackground();
- _video->stopVideos();
if (linkSrcSound)
playSoundBlocking(linkSrcSound);
@@ -503,20 +568,22 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
delete _prevStack;
_prevStack = _scriptParser;
+ _curStack = stack;
+
switch (_curStack) {
case kChannelwoodStack:
- _gameState->_globals.currentAge = 4;
+ _gameState->_globals.currentAge = kChannelwood;
_scriptParser = new MystStacks::Channelwood(this);
break;
case kCreditsStack:
_scriptParser = new MystStacks::Credits(this);
break;
case kDemoStack:
- _gameState->_globals.currentAge = 0;
+ _gameState->_globals.currentAge = kSelenitic;
_scriptParser = new MystStacks::Demo(this);
break;
case kDniStack:
- _gameState->_globals.currentAge = 6;
+ _gameState->_globals.currentAge = kDni;
_scriptParser = new MystStacks::Dni(this);
break;
case kIntroStack:
@@ -526,26 +593,26 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_scriptParser = new MystStacks::MakingOf(this);
break;
case kMechanicalStack:
- _gameState->_globals.currentAge = 3;
+ _gameState->_globals.currentAge = kMechanical;
_scriptParser = new MystStacks::Mechanical(this);
break;
case kMystStack:
- _gameState->_globals.currentAge = 2;
+ _gameState->_globals.currentAge = kMystLibrary;
_scriptParser = new MystStacks::Myst(this);
break;
case kDemoPreviewStack:
_scriptParser = new MystStacks::Preview(this);
break;
case kSeleniticStack:
- _gameState->_globals.currentAge = 0;
+ _gameState->_globals.currentAge = kSelenitic;
_scriptParser = new MystStacks::Selenitic(this);
break;
case kDemoSlidesStack:
- _gameState->_globals.currentAge = 1;
+ _gameState->_globals.currentAge = kStoneship;
_scriptParser = new MystStacks::Slides(this);
break;
case kStoneshipStack:
- _gameState->_globals.currentAge = 1;
+ _gameState->_globals.currentAge = kStoneship;
_scriptParser = new MystStacks::Stoneship(this);
break;
default:
@@ -570,38 +637,6 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_cache.clear();
_gfx->clearCache();
- if (getFeatures() & GF_ME) {
- // Play Flyby Entry Movie on Masterpiece Edition.
- const char *flyby = nullptr;
-
- switch (_curStack) {
- case kSeleniticStack:
- flyby = "selenitic flyby";
- break;
- case kStoneshipStack:
- flyby = "stoneship flyby";
- break;
- // Myst Flyby Movie not used in Original Masterpiece Edition Engine
- // We play it when first arriving on Myst, and if the user has chosen so.
- case kMystStack:
- if (ConfMan.getBool("playmystflyby") && card == 4134)
- flyby = "myst flyby";
- break;
- case kMechanicalStack:
- flyby = "mech age flyby";
- break;
- case kChannelwoodStack:
- flyby = "channelwood flyby";
- break;
- default:
- break;
- }
-
- if (flyby) {
- playFlybyMovie(flyby);
- }
- }
-
changeToCard(card, kTransitionCopy);
if (linkDstSound)
@@ -677,7 +712,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
// The demo resets the cursor at each card change except when in the library
if (getFeatures() & GF_DEMO
- && _gameState->_globals.currentAge != 2) {
+ && _gameState->_globals.currentAge != kMystLibrary) {
_cursor->setDefaultCursor();
}
@@ -724,7 +759,7 @@ void MohawkEngine_Myst::checkCurrentResource() {
}
for (uint16 i = 0; i < _resources.size(); i++) {
- if (_resources[i]->contains(mouse) && _resources[i]->type == kMystAreaHover
+ if (_resources[i]->contains(mouse) && _resources[i]->hasType(kMystAreaHover)
&& _hoverResource != _resources[i]) {
_hoverResource = static_cast<MystAreaHover *>(_resources[i]);
_hoverResource->handleMouseEnter();
@@ -955,50 +990,6 @@ void MohawkEngine_Myst::runExitScript() {
_scriptParser->runScript(script);
}
-void MohawkEngine_Myst::loadHelp(uint16 id) {
- // The original version did not have the help system
- if (!(getFeatures() & GF_ME))
- return;
-
- // TODO: Help File contains 5 cards i.e. VIEW, RLST, etc.
- // in addition to HELP resources.
- // These are Ids 9930 to 9934
- // Need to deal with loading and displaying these..
- // Current engine structure only supports display of
- // card from primary stack MHK
-
- debugC(kDebugHelp, "Loading Help System Data");
-
- Common::SeekableReadStream *helpStream = getResource(ID_HELP, id);
-
- uint16 count = helpStream->readUint16LE();
- uint16 *u0 = new uint16[count];
- Common::String helpText;
-
- debugC(kDebugHelp, "\tcount: %d", count);
-
- for (uint16 i = 0; i < count; i++) {
- u0[i] = helpStream->readUint16LE();
- debugC(kDebugHelp, "\tu0[%d]: %d", i, u0[i]);
- }
-
- // TODO: Previous values i.e. u0[0] to u0[count - 2]
- // appear to be resource ids in the help.dat file..
- if (u0[count - 1] != count)
- warning("loadHelp(): last u0 value is not equal to count");
-
- do {
- helpText += helpStream->readByte();
- } while (helpText.lastChar() != 0);
- helpText.deleteLastChar();
-
- debugC(kDebugHelp, "\thelpText: \"%s\"", helpText.c_str());
-
- delete[] u0;
-
- delete helpStream;
-}
-
void MohawkEngine_Myst::loadCursorHints() {
_cursorHints.clear();
@@ -1059,7 +1050,7 @@ void MohawkEngine_Myst::checkCursorHints() {
// Check all the cursor hints to see if we're in a hotspot that contains a hint.
for (uint16 i = 0; i < _cursorHints.size(); i++)
- if (_resources[_cursorHints[i].id] == _activeResource && _activeResource->isEnabled()) {
+ if (_activeResource && _resources[_cursorHints[i].id] == _activeResource && _activeResource->isEnabled()) {
if (_cursorHints[i].cursor == -1) {
uint16 var_value = _scriptParser->getVar(_cursorHints[i].variableHint.var);
@@ -1107,7 +1098,7 @@ void MohawkEngine_Myst::redrawResource(MystAreaImageSwitch *resource, bool updat
void MohawkEngine_Myst::redrawArea(uint16 var, bool update) {
for (uint16 i = 0; i < _resources.size(); i++)
- if (_resources[i]->type == kMystAreaImageSwitch && _resources[i]->getImageSwitchVar() == var)
+ if (_resources[i]->hasType(kMystAreaImageSwitch) && _resources[i]->getImageSwitchVar() == var)
redrawResource(static_cast<MystAreaImageSwitch *>(_resources[i]), update);
}
@@ -1120,36 +1111,34 @@ MystArea *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream
switch (type) {
case kMystAreaAction:
- resource = new MystAreaAction(this, rlstStream, parent);
+ resource = new MystAreaAction(this, type, rlstStream, parent);
break;
case kMystAreaVideo:
- resource = new MystAreaVideo(this, rlstStream, parent);
+ resource = new MystAreaVideo(this, type, rlstStream, parent);
break;
case kMystAreaActionSwitch:
- resource = new MystAreaActionSwitch(this, rlstStream, parent);
+ resource = new MystAreaActionSwitch(this, type, rlstStream, parent);
break;
case kMystAreaImageSwitch:
- resource = new MystAreaImageSwitch(this, rlstStream, parent);
+ resource = new MystAreaImageSwitch(this, type, rlstStream, parent);
break;
case kMystAreaSlider:
- resource = new MystAreaSlider(this, rlstStream, parent);
+ resource = new MystAreaSlider(this, type, rlstStream, parent);
break;
case kMystAreaDrag:
- resource = new MystAreaDrag(this, rlstStream, parent);
+ resource = new MystAreaDrag(this, type, rlstStream, parent);
break;
case kMystVideoInfo:
- resource = new MystVideoInfo(this, rlstStream, parent);
+ resource = new MystVideoInfo(this, type, rlstStream, parent);
break;
case kMystAreaHover:
- resource = new MystAreaHover(this, rlstStream, parent);
+ resource = new MystAreaHover(this, type, rlstStream, parent);
break;
default:
- resource = new MystArea(this, rlstStream, parent);
+ resource = new MystArea(this, type, rlstStream, parent);
break;
}
- resource->type = type;
-
return resource;
}
@@ -1184,15 +1173,34 @@ Common::Error MohawkEngine_Myst::loadGameState(int slot) {
}
Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) {
- return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError;
+ return _gameState->save(slot, desc, false) ? Common::kNoError : Common::kUnknownError;
+}
+
+void MohawkEngine_Myst::tryAutoSaving() {
+ if (!canSaveGameStateCurrently()) {
+ return; // Can't save right now, try again on the next frame
+ }
+
+ _lastSaveTime = _system->getMillis();
+
+ if (!_gameState->isAutoSaveAllowed()) {
+ return; // Can't autosave ever, try again after the next autosave delay
+ }
+
+ if (!_gameState->save(MystGameState::kAutoSaveSlot, "Autosave", true))
+ warning("Attempt to autosave has failed.");
}
bool MohawkEngine_Myst::hasGameSaveSupport() const {
return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF;
}
+bool MohawkEngine_Myst::isInteractive() {
+ return !_scriptParser->isScriptRunning() && !_waitingOnBlockingOperation;
+}
+
bool MohawkEngine_Myst::canLoadGameStateCurrently() {
- if (_scriptParser->isScriptRunning() || !_interactive) {
+ if (!isInteractive()) {
return false;
}
@@ -1229,8 +1237,8 @@ bool MohawkEngine_Myst::canSaveGameStateCurrently() {
}
void MohawkEngine_Myst::dropPage() {
- uint16 page = _gameState->_globals.heldPage;
- bool whitePage = page == 13;
+ HeldPage page = _gameState->_globals.heldPage;
+ bool whitePage = page == kWhitePage;
bool bluePage = page - 1 < 6;
bool redPage = page - 7 < 6;
@@ -1238,25 +1246,25 @@ void MohawkEngine_Myst::dropPage() {
_sound->playEffect(800);
// Drop page
- _gameState->_globals.heldPage = 0;
+ _gameState->_globals.heldPage = kNoPage;
// Redraw page area
- if (whitePage && _gameState->_globals.currentAge == 2) {
+ if (whitePage && _gameState->_globals.currentAge == kMystLibrary) {
_scriptParser->toggleVar(41);
redrawArea(41);
} else if (bluePage) {
- if (page == 6) {
- if (_gameState->_globals.currentAge == 2)
+ if (page == kBlueFirePlacePage) {
+ if (_gameState->_globals.currentAge == kMystLibrary)
redrawArea(24);
} else {
redrawArea(103);
}
} else if (redPage) {
- if (page == 12) {
- if (_gameState->_globals.currentAge == 2)
+ if (page == kRedFirePlacePage) {
+ if (_gameState->_globals.currentAge == kMystLibrary)
redrawArea(25);
- } else if (page == 10) {
- if (_gameState->_globals.currentAge == 1)
+ } else if (page == kRedStoneshipPage) {
+ if (_gameState->_globals.currentAge == kStoneship)
redrawArea(35);
} else {
redrawArea(102);
@@ -1277,9 +1285,9 @@ MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) con
debugC(kDebugView, "\tSound: %d", soundBlock.sound);
soundBlock.soundVolume = stream->readUint16LE();
debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
- } else if (soundBlock.sound == kMystSoundActionContinue)
+ } else if (soundBlock.sound == kMystSoundActionContinue) {
debugC(kDebugView, "Continue current sound");
- else if (soundBlock.sound == kMystSoundActionChangeVolume) {
+ } else if (soundBlock.sound == kMystSoundActionChangeVolume) {
debugC(kDebugView, "Continue current sound, change volume");
soundBlock.soundVolume = stream->readUint16LE();
debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
@@ -1305,8 +1313,7 @@ MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) con
soundBlock.soundList.push_back(sound);
}
} else {
- debugC(kDebugView, "Unknown");
- warning("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard);
+ error("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard);
}
return soundBlock;