aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk')
-rw-r--r--engines/mohawk/POTFILES3
-rw-r--r--engines/mohawk/bitmap.cpp10
-rw-r--r--engines/mohawk/configure.engine4
-rw-r--r--engines/mohawk/console.cpp1
-rw-r--r--engines/mohawk/cstime.cpp3
-rw-r--r--engines/mohawk/cstime.h3
-rw-r--r--engines/mohawk/cstime_game.cpp5
-rw-r--r--engines/mohawk/cstime_ui.cpp4
-rw-r--r--engines/mohawk/cstime_view.cpp8
-rw-r--r--engines/mohawk/cursors.cpp23
-rw-r--r--engines/mohawk/cursors.h2
-rw-r--r--engines/mohawk/detection.cpp98
-rw-r--r--engines/mohawk/detection_tables.h180
-rw-r--r--engines/mohawk/dialogs.cpp183
-rw-r--r--engines/mohawk/dialogs.h66
-rw-r--r--engines/mohawk/graphics.h8
-rw-r--r--engines/mohawk/livingbooks.cpp5
-rw-r--r--engines/mohawk/livingbooks.h1
-rw-r--r--engines/mohawk/module.mk1
-rw-r--r--engines/mohawk/mohawk.cpp12
-rw-r--r--engines/mohawk/mohawk.h5
-rw-r--r--engines/mohawk/myst.cpp61
-rw-r--r--engines/mohawk/myst.h4
-rw-r--r--engines/mohawk/myst_areas.cpp17
-rw-r--r--engines/mohawk/myst_areas.h2
-rw-r--r--engines/mohawk/myst_graphics.cpp92
-rw-r--r--engines/mohawk/myst_graphics.h4
-rw-r--r--engines/mohawk/myst_scripts.cpp10
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp16
-rw-r--r--engines/mohawk/myst_stacks/credits.cpp5
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp2
-rw-r--r--engines/mohawk/myst_stacks/makingof.cpp2
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp6
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp17
-rw-r--r--engines/mohawk/myst_stacks/myst.h2
-rw-r--r--engines/mohawk/myst_stacks/selenitic.cpp21
-rw-r--r--engines/mohawk/myst_stacks/selenitic.h1
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp1
-rw-r--r--engines/mohawk/myst_state.cpp100
-rw-r--r--engines/mohawk/myst_state.h22
-rw-r--r--engines/mohawk/resource.h2
-rw-r--r--engines/mohawk/riven.cpp47
-rw-r--r--engines/mohawk/riven.h4
-rw-r--r--engines/mohawk/riven_external.cpp15
-rw-r--r--engines/mohawk/riven_graphics.cpp4
-rw-r--r--engines/mohawk/riven_saveload.cpp341
-rw-r--r--engines/mohawk/riven_saveload.h35
-rw-r--r--engines/mohawk/riven_scripts.cpp46
-rw-r--r--engines/mohawk/riven_sound.cpp459
-rw-r--r--engines/mohawk/riven_sound.h197
-rw-r--r--engines/mohawk/sound.cpp466
-rw-r--r--engines/mohawk/sound.h43
-rw-r--r--engines/mohawk/video.cpp137
-rw-r--r--engines/mohawk/video.h4
-rw-r--r--engines/mohawk/view.cpp52
-rw-r--r--engines/mohawk/view.h17
56 files changed, 1984 insertions, 895 deletions
diff --git a/engines/mohawk/POTFILES b/engines/mohawk/POTFILES
index 54d9dcaa3a..42d1d084c2 100644
--- a/engines/mohawk/POTFILES
+++ b/engines/mohawk/POTFILES
@@ -1,3 +1,6 @@
+engines/mohawk/detection.cpp
engines/mohawk/dialogs.cpp
engines/mohawk/myst.cpp
engines/mohawk/riven.cpp
+engines/mohawk/riven_external.cpp
+engines/mohawk/mohawk.cpp
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index 6435daf46f..d8c6d6aacd 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -53,6 +53,16 @@ MohawkBitmap::MohawkBitmap() {
_drawTable = drawTable;
_drawTableSize = ARRAYSIZE(drawTable);
+
+ _header.width = 0;
+ _header.height = 0;
+ _header.bytesPerRow = 0;
+ _header.format = 0;
+ _header.colorTable.colorCount = 0;
+ _header.colorTable.palette = nullptr;
+ _header.colorTable.rgbBits = 0;
+ _header.colorTable.tableSize = 0;
+ _data = nullptr;
}
MohawkBitmap::~MohawkBitmap() {
diff --git a/engines/mohawk/configure.engine b/engines/mohawk/configure.engine
index 47402c4560..ccb9499ef0 100644
--- a/engines/mohawk/configure.engine
+++ b/engines/mohawk/configure.engine
@@ -1,6 +1,6 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books"
+add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" "highres"
add_engine cstime "Where in Time is Carmen Sandiego?" no
add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit"
-add_engine myst "Myst" no
+add_engine myst "Myst" yes
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index fd79e53b07..f08eee9677 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -42,6 +42,7 @@
#ifdef ENABLE_RIVEN
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
+#include "mohawk/riven_sound.h"
#endif
namespace Mohawk {
diff --git a/engines/mohawk/cstime.cpp b/engines/mohawk/cstime.cpp
index 3b26378819..b2889be714 100644
--- a/engines/mohawk/cstime.cpp
+++ b/engines/mohawk/cstime.cpp
@@ -54,6 +54,7 @@ MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescript
_console = 0;
_gfx = 0;
+ _sound = 0;
_cursor = 0;
_interface = 0;
_view = 0;
@@ -66,6 +67,7 @@ MohawkEngine_CSTime::~MohawkEngine_CSTime() {
delete _interface;
delete _view;
delete _console;
+ delete _sound;
delete _gfx;
delete _rnd;
}
@@ -75,6 +77,7 @@ Common::Error MohawkEngine_CSTime::run() {
_console = new CSTimeConsole(this);
_gfx = new CSTimeGraphics(this);
+ _sound = new Sound(this);
_cursor = new DefaultCursorManager(this, ID_CURS);
_interface = new CSTimeInterface(this);
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index f95222d3a1..393032aaa9 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -111,7 +111,7 @@ enum {
};
struct CSTimeEvent {
- CSTimeEvent() { }
+ CSTimeEvent() : type(0), param1(0), param2(0) { }
CSTimeEvent(uint16 t, uint16 p1, uint16 p2) : type(t), param1(p1), param2(p2) { }
uint16 type;
@@ -136,6 +136,7 @@ public:
Common::RandomSource *_rnd;
+ Sound *_sound;
CSTimeGraphics *_gfx;
bool _needsUpdate;
diff --git a/engines/mohawk/cstime_game.cpp b/engines/mohawk/cstime_game.cpp
index 8eced701c3..c939d8bc24 100644
--- a/engines/mohawk/cstime_game.cpp
+++ b/engines/mohawk/cstime_game.cpp
@@ -94,6 +94,11 @@ CSTimeChar::CSTimeChar(MohawkEngine_CSTime *vm, CSTimeScene *scene, uint id) : _
_lastTime2 = 0;
_lastTime3 = 0;
+ _unknown1 = _unknown2 = _unknown3 = 0;
+ _enabled = false;
+ _nextCue = 0;
+ _waveStatus = 0;
+
_playingWaveId = 0;
}
diff --git a/engines/mohawk/cstime_ui.cpp b/engines/mohawk/cstime_ui.cpp
index f3fe27a966..59be95adf6 100644
--- a/engines/mohawk/cstime_ui.cpp
+++ b/engines/mohawk/cstime_ui.cpp
@@ -79,6 +79,8 @@ CSTimeInterface::CSTimeInterface(MohawkEngine_CSTime *vm) : _vm(vm) {
_rolloverTextFeature = NULL;
_bubbleTextFeature = NULL;
+ _draggedItem = 0;
+
_mouseWasInScene = false;
_state = kCSTimeInterfaceStateNormal;
@@ -1034,6 +1036,8 @@ CSTimeInventoryDisplay::CSTimeInventoryDisplay(MohawkEngine_CSTime *vm, Common::
_cuffsState = false;
_cuffsShape = 10;
+ _draggedItem = 0;
+
_invRect = baseRect;
for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) {
diff --git a/engines/mohawk/cstime_view.cpp b/engines/mohawk/cstime_view.cpp
index 7879175bb0..8727560094 100644
--- a/engines/mohawk/cstime_view.cpp
+++ b/engines/mohawk/cstime_view.cpp
@@ -243,7 +243,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
if ((feature->_flags & kFeatureNewDisable) || (feature->_flags & kFeatureNewDisableOnReset)) {
feature->_data.enabled = 0;
}
- feature->_dirty = 1;
+ feature->_dirty = true;
if (feature->_flags & kFeatureInternalRegion) {
// TODO: create region [+140] (if not already done)
}
@@ -257,7 +257,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
// TODO: or clip with bounds
}
}
- feature->_dirty = 1;
+ feature->_dirty = true;
if (feature->_flags & kFeatureNewInternalTiming) {
feature->_nextTime += feature->_delayTime;
} else {
@@ -277,7 +277,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
}
feature->_data.currOffset = 26;
- feature->_done = 0;
+ feature->_done = false;
}
if (feature->_flags & kFeatureNewDisable)
feature->_data.enabled = 0;
@@ -307,7 +307,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
}
case 0:
// TODO: set ptr +176 to 1
- feature->_done = 1;
+ feature->_done = true;
if (feature->_doneProc) {
(this->*(feature->_doneProc))(feature); // TODO: with -1
}
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index 4b66829e6a..b78f71a71d 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -34,8 +34,8 @@
#include "graphics/wincursor.h"
#ifdef ENABLE_MYST
-#include "mohawk/bitmap.h"
#include "mohawk/myst.h"
+#include "mohawk/myst_graphics.h"
#endif
namespace Mohawk {
@@ -86,11 +86,9 @@ void DefaultCursorManager::setCursor(uint16 id) {
#ifdef ENABLE_MYST
MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) {
- _bmpDecoder = new MystBitmap();
}
MystCursorManager::~MystCursorManager() {
- delete _bmpDecoder;
}
void MystCursorManager::showCursor() {
@@ -111,17 +109,27 @@ void MystCursorManager::setCursor(uint16 id) {
return;
}
- // Both Myst and Myst ME use the "MystBitmap" format for cursor images.
- MohawkSurface *mhkSurface = _bmpDecoder->decodeImage(_vm->getResource(ID_WDIB, id));
- Graphics::Surface *surface = mhkSurface->getSurface();
Common::SeekableReadStream *clrcStream = _vm->getResource(ID_CLRC, id);
uint16 hotspotX = clrcStream->readUint16LE();
uint16 hotspotY = clrcStream->readUint16LE();
delete clrcStream;
+ // Both Myst and Myst ME use the "MystBitmap" format for cursor images.
+ MohawkSurface *mhkSurface = _vm->_gfx->findImage(id);
+ Graphics::Surface *surface = mhkSurface->getSurface();
+
// Myst ME stores some cursors as 24bpp images instead of 8bpp
if (surface->format.bytesPerPixel == 1) {
- CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 0);
+ // The transparent color is almost always 255, except for the main cursor (100)
+ // in the D'ni archive, where it is 0.
+ // Using the color of the first pixel as the transparent color for the main cursor always works.
+ byte transparentColor;
+ if (id == kDefaultMystCursor) {
+ transparentColor = ((byte *)surface->getPixels())[0];
+ } else {
+ transparentColor = 255;
+ }
+ CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, transparentColor);
// We're using the screen palette for the original game, but we need
// to use this for any 8bpp cursor in ME.
@@ -133,7 +141,6 @@ void MystCursorManager::setCursor(uint16 id) {
}
_vm->_needsUpdate = true;
- delete mhkSurface;
}
void MystCursorManager::setDefaultCursor() {
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index c41b5c273e..742ae30107 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -102,7 +102,6 @@ enum {
};
class MohawkEngine_Myst;
-class MystBitmap;
// The cursor manager for Myst
// Uses WDIB + CLRC resources
@@ -119,7 +118,6 @@ public:
private:
MohawkEngine_Myst *_vm;
- MystBitmap *_bmpDecoder;
};
#endif // ENABLE_MYST
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 986b35c85e..439ea152c4 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -26,6 +26,7 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "mohawk/livingbooks.h"
@@ -40,6 +41,7 @@
#ifdef ENABLE_RIVEN
#include "mohawk/riven.h"
+#include "mohawk/riven_saveload.h"
#endif
namespace Mohawk {
@@ -53,7 +55,7 @@ struct MohawkGameDescription {
};
const char* MohawkEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 MohawkEngine::getFeatures() const {
@@ -112,7 +114,7 @@ bool MohawkEngine_Riven::hasFeature(EngineFeature f) const {
static const PlainGameDescriptor mohawkGames[] = {
{"mohawk", "Mohawk Game"},
{"myst", "Myst"},
- {"MakingOfMyst", "The Making of Myst"},
+ {"makingofmyst", "The Making of Myst"},
{"riven", "Riven: The Sequel to Myst"},
{"zoombini", "Logical Journey of the Zoombinis"},
{"cstime", "Where in Time is Carmen Sandiego?"},
@@ -160,10 +162,24 @@ static const char *directoryGlobs[] = {
0
};
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_PLAY_MYST_FLYBY,
+ {
+ _s("Play the Myst fly by movie"),
+ _s("The Myst fly by movie was not played by the original engine."),
+ "playmystflyby",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
class MohawkMetaEngine : public AdvancedMetaEngine {
public:
- MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames) {
- _singleid = "mohawk";
+ MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames, optionsList) {
+ _singleId = "mohawk";
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
@@ -183,6 +199,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual SaveStateList listSaves(const char *target) const;
+ SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const;
virtual int getMaximumSaveSlot() const { return 999; }
virtual void removeSaveState(const char *target, int slot) const;
virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
@@ -199,53 +216,86 @@ bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const {
|| (f == kSavesSupportPlayTime);
}
+SaveStateList MohawkMetaEngine::listSavesForPrefix(const char *prefix, const char *extension) const {
+ Common::String pattern = Common::String::format("%s-###.%s", prefix, extension);
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
+ size_t prefixLen = strlen(prefix);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ // Extract the slot number from the filename
+ char slot[4];
+ slot[0] = (*filename)[prefixLen + 1];
+ slot[1] = (*filename)[prefixLen + 2];
+ slot[2] = (*filename)[prefixLen + 3];
+ slot[3] = '\0';
+
+ int slotNum = atoi(slot);
+
+ saveList.push_back(SaveStateDescriptor(slotNum, ""));
+ }
+
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+
+ return saveList;
+}
+
SaveStateList MohawkMetaEngine::listSaves(const char *target) const {
- Common::StringArray filenames;
SaveStateList saveList;
// Loading games is only supported in Myst/Riven currently.
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- filenames = Mohawk::MystGameState::generateSaveGameList();
+ saveList = listSavesForPrefix("myst", "mys");
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
- } else
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+ // Read the description from the save
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::MystGameState::querySaveDescription(slot);
+ save->setDescription(description);
+ }
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
+ saveList = listSavesForPrefix("riven", "rvn");
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+ // Read the description from the save
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(slot);
+ save->setDescription(description);
+ }
}
+#endif
return saveList;
}
void MohawkMetaEngine::removeSaveState(const char *target, int slot) const {
+
// Removing saved games is only supported in Myst/Riven currently.
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList();
- Mohawk::MystGameState::deleteSave(filenames[slot]);
- } else
+ Mohawk::MystGameState::deleteSave(slot);
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+ Mohawk::RivenSaveLoad::deleteSave(slot);
}
+#endif
}
SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList();
-
- if (slot >= (int) filenames.size()) {
- return SaveStateDescriptor();
- }
-
- return Mohawk::MystGameState::querySaveMetaInfos(filenames[slot]);
+ return Mohawk::MystGameState::querySaveMetaInfos(slot);
+ }
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ return Mohawk::RivenSaveLoad::querySaveMetaInfos(slot);
} else
#endif
{
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 97d2932d57..9cc52a78b3 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -22,6 +22,13 @@
namespace Mohawk {
+#define GAMEOPTION_PLAY_MYST_FLYBY GUIO_GAMEOPTIONS1
+
+#define GUI_OPTIONS_MYST GUIO3(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI)
+#define GUI_OPTIONS_MYST_ME GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GAMEOPTION_PLAY_MYST_FLYBY)
+#define GUI_OPTIONS_MYST_DEMO GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD)
+#define GUI_OPTIONS_MYST_MAKING_OF GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD)
+
static const MohawkGameDescription gameDescriptions[] = {
// Myst
// English Windows 3.11
@@ -33,8 +40,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "ae3258c9c90128d274aa6a790b3ad181"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -51,8 +58,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("DEMO.DAT", "c39303dd53fb5c4e7f3c23231c606cd0"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DEMO | ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_DEMO | ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_DEMO
},
GType_MYST,
GF_DEMO,
@@ -69,8 +76,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "4beb3366ed3f3b9bfb6e81a14a43bdcc"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -87,8 +94,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "e0937cca1ab125e48e30dc3cd5046ddf"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -105,8 +112,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "f7e7d7ca69934f1351b5acd4fe4d44c2"),
Common::ES_ESP,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -123,8 +130,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "a5795ce1751fc42525e4f9a1859181d5"),
Common::IT_ITA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -141,8 +148,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "032c88e3b7e8db4ca475e7b7db9a66bb"),
Common::JA_JPN,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -159,8 +166,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "d631d42567a941c67c78f2e491f4ea58"),
Common::FR_FRA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -172,13 +179,13 @@ static const MohawkGameDescription gameDescriptions[] = {
// From clone2727
{
{
- "MakingOfMyst",
+ "makingofmyst",
"",
AD_ENTRY1("MAKING.DAT", "f6387e8f0f7b8a3e42c95294315d6a0e"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -190,13 +197,13 @@ static const MohawkGameDescription gameDescriptions[] = {
// From clone2727
{
{
- "MakingOfMyst",
+ "makingofmyst",
"",
AD_ENTRY1("MAKING.DAT", "03ff62607e64419ab2b6ebf7b7bcdf63"),
Common::JA_JPN,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -213,8 +220,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -231,8 +238,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "f88e0ace66dbca78eebdaaa1d3314ceb"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -249,8 +256,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"),
Common::FR_FRA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -267,8 +274,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "4a05771b60f4a69869838d01e85c9e80"),
Common::PL_POL,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -330,6 +337,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0 (5CD), 1.02 (DVD, From "Myst: La Trilogie")
+ // From gamin
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.0 (5CD) - Italian
// From dodomorandi on bug #6629
{
@@ -348,6 +373,23 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0.0 (5CD) - Russian, Fargus
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1s("a_Data.MHK", "2a840ed74fe5dc3a388bced674d379d5", 12024358),
+ Common::RU_RUS,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.1 (5CD) - Russian, Fargus
{
{
@@ -364,33 +406,34 @@ static const MohawkGameDescription gameDescriptions[] = {
0,
},
+
// Riven: The Sequel to Myst
- // Version 1.? (DVD, From "Myst 10th Anniversary Edition")
- // From Clone2727
+ // Version 1.0J (5CD) - Japanese
+ // From sev
{
{
"riven",
- "DVD",
- AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"),
- Common::EN_ANY,
+ "",
+ AD_ENTRY1s("a_Data.MHK", "3a2b4764979dc007a0e6ded64e4b7889", 10014314),
+ Common::JA_JPN,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
},
GType_RIVEN,
- GF_DVD,
+ 0,
0,
},
// Riven: The Sequel to Myst
- // Version 1.0 (DVD, From "Myst: Die Trilogie")
- // From DrMcCoy
+ // Version 1.? (DVD, From "Myst 10th Anniversary Edition")
+ // From Clone2727
{
{
"riven",
- "",
- AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"),
- Common::DE_DEU,
+ "DVD",
+ AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"),
+ Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -401,14 +444,14 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version ? (DVD, From "Myst: La Trilogie")
- // From gamin
+ // Version 1.0 (DVD, From "Myst: Die Trilogie")
+ // From DrMcCoy
{
{
"riven",
"",
- AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
- Common::FR_FRA,
+ AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"),
+ Common::DE_DEU,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -1871,6 +1914,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"Living Books Player"
},
+ // From Matthew Winder in bug#6557
+ // v1.0E, English, Windows
+ {
+ {
+ "arthurbday",
+ "",
+ AD_ENTRY1s("AB16B.LB", "c169be346de7b0bbfcd18761fc0a3e49", 3093),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_LIVINGBOOKSV2,
+ 0,
+ 0,
+ },
+
// From Torsten in bug#3422652
{
{
@@ -2093,6 +2153,22 @@ static const MohawkGameDescription gameDescriptions[] = {
0
},
+ // From Matthew Winder in bug#6557
+ {
+ {
+ "lilmonster",
+ "",
+ AD_ENTRY1s("lmasf.lb", "fcb665df1713d0411a41515efb20bebc", 4136),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_LIVINGBOOKSV2,
+ 0,
+ 0
+ },
+
// From afholman in bug#3309308
{
{
@@ -2697,8 +2773,8 @@ static const MohawkGameDescription fallbackDescs[] = {
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -2707,13 +2783,13 @@ static const MohawkGameDescription fallbackDescs[] = {
{
{
- "MakingOfMyst",
+ "makingofmyst",
"unknown",
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -2727,8 +2803,8 @@ static const MohawkGameDescription fallbackDescs[] = {
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp
index f8aaf0f4af..38be98dfec 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -25,7 +25,6 @@
#include "gui/gui-manager.h"
#include "gui/saveload.h"
-#include "gui/ThemeEngine.h"
#include "gui/widget.h"
#include "common/system.h"
#include "common/translation.h"
@@ -89,27 +88,11 @@ enum {
kQuitCmd = 'QUIT'
};
-#ifdef ENABLE_MYST
-
-MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, 360, 200), _vm(vm) {
- // I18N: Option for fast scene switching
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
- // I18N: Drop book page
- _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd);
-
- // Myst ME only has maps
- if (_vm->getFeatures() & GF_ME)
- _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd);
- else
- _showMapButton = 0;
-
- // Myst demo only has a menu
- if (_vm->getFeatures() & GF_DEMO)
- _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
- else
- _returnToMenuButton = 0;
+#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN)
+MohawkOptionsDialog::MohawkOptionsDialog(MohawkEngine *vm) :
+ GUI::Dialog(0, 0, 360, 200),
+ _vm(vm), _loadSlot(-1) {
_loadButton = new GUI::ButtonWidget(this, 245, 25, 100, 25, _("~L~oad"), 0, kLoadCmd);
_saveButton = new GUI::ButtonWidget(this, 245, 60, 100, 25, _("~S~ave"), 0, kSaveCmd);
new GUI::ButtonWidget(this, 245, 95, 100, 25, _("~Q~uit"), 0, kQuitCmd);
@@ -121,37 +104,21 @@ MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0,
_saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
}
-MystOptionsDialog::~MystOptionsDialog() {
+MohawkOptionsDialog::~MohawkOptionsDialog() {
delete _loadDialog;
delete _saveDialog;
}
-void MystOptionsDialog::open() {
- Dialog::open();
-
- _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
-
- if (_showMapButton)
- _showMapButton->setEnabled(_vm->_scriptParser &&
- _vm->_scriptParser->getMap());
-
- // Return to menu button is not enabled on the menu
- if (_returnToMenuButton)
- _returnToMenuButton->setEnabled(_vm->_scriptParser &&
- _vm->getCurStack() != kDemoStack);
-
- // Zip mode is disabled in the demo
- if (_vm->getFeatures() & GF_DEMO)
- _zipModeCheckbox->setEnabled(false);
-
- _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode);
- _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions);
+void MohawkOptionsDialog::open() {
+ GUI::Dialog::open();
+ _loadSlot = -1;
_loadButton->setEnabled(_vm->canLoadGameStateCurrently());
_saveButton->setEnabled(_vm->canSaveGameStateCurrently());
}
-void MystOptionsDialog::save() {
+
+void MohawkOptionsDialog::save() {
int slot = _saveDialog->runModalWithCurrentTarget();
if (slot >= 0) {
@@ -166,16 +133,18 @@ void MystOptionsDialog::save() {
}
}
-void MystOptionsDialog::load() {
- int slot = _loadDialog->runModalWithCurrentTarget();
+void MohawkOptionsDialog::load() {
+ // Do not load the game state from insite the dialog loop to
+ // avoid mouse cursor glitches (see bug #7164). Instead store
+ // the slot to load and let the code exectuting the dialog do
+ // the load after the dialog finished running.
+ _loadSlot = _loadDialog->runModalWithCurrentTarget();
- if (slot >= 0) {
- _vm->loadGameState(slot);
+ if (_loadSlot >= 0)
close();
- }
}
-void MystOptionsDialog::reflowLayout() {
+void MohawkOptionsDialog::reflowLayout() {
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
@@ -183,7 +152,73 @@ void MystOptionsDialog::reflowLayout() {
_x = (screenW - getWidth()) / 2;
_y = (screenH - getHeight()) / 2;
- Dialog::reflowLayout();
+ GUI::Dialog::reflowLayout();
+}
+
+
+void MohawkOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kLoadCmd:
+ load();
+ break;
+ case kSaveCmd:
+ save();
+ break;
+ case GUI::kCloseCmd:
+ close();
+ break;
+ default:
+ GUI::Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+#endif
+
+#ifdef ENABLE_MYST
+
+MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) {
+ // I18N: Option for fast scene switching
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
+ _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
+ // I18N: Drop book page
+ _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd);
+
+ // Myst ME only has maps
+ if (_vm->getFeatures() & GF_ME)
+ _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd);
+ else
+ _showMapButton = 0;
+
+ // Myst demo only has a menu
+ if (_vm->getFeatures() & GF_DEMO)
+ _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
+ else
+ _returnToMenuButton = 0;
+}
+
+MystOptionsDialog::~MystOptionsDialog() {
+}
+
+void MystOptionsDialog::open() {
+ MohawkOptionsDialog::open();
+
+ _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
+
+ if (_showMapButton)
+ _showMapButton->setEnabled(_vm->_scriptParser &&
+ _vm->_scriptParser->getMap());
+
+ // Return to menu button is not enabled on the menu
+ if (_returnToMenuButton)
+ _returnToMenuButton->setEnabled(_vm->_scriptParser &&
+ _vm->getCurStack() != kDemoStack);
+
+ // Zip mode is disabled in the demo
+ if (_vm->getFeatures() & GF_DEMO)
+ _zipModeCheckbox->setEnabled(false);
+
+ _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode);
+ _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions);
}
void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
@@ -200,16 +235,14 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
_vm->_needsShowDemoMenu = true;
close();
break;
- case kLoadCmd:
- load();
- break;
- case kSaveCmd:
- save();
- break;
case kQuitCmd: {
- Common::Event eventQ;
- eventQ.type = Common::EVENT_QUIT;
- g_system->getEventManager()->pushEvent(eventQ);
+ if (_vm->getGameType() != GType_MAKINGOF) {
+ _vm->_needsShowCredits = true;
+ } else {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
+ }
close();
}
break;
@@ -219,11 +252,8 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
setResult(1);
close();
break;
- case GUI::kCloseCmd:
- close();
- break;
default:
- GUI::Dialog::handleCommand(sender, cmd, data);
+ MohawkOptionsDialog::handleCommand(sender, cmd, data);
}
}
@@ -231,19 +261,18 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
#ifdef ENABLE_RIVEN
-RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) {
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd);
-
- new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd);
- new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd);
+RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) :
+ MohawkOptionsDialog(vm),
+ _vm(vm) {
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
+ _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd);
}
RivenOptionsDialog::~RivenOptionsDialog() {
}
void RivenOptionsDialog::open() {
- Dialog::open();
+ MohawkOptionsDialog::open();
_zipModeCheckbox->setState(_vm->_vars["azip"] != 0);
_waterEffectCheckbox->setState(_vm->_vars["waterenabled"] != 0);
@@ -251,17 +280,21 @@ void RivenOptionsDialog::open() {
void RivenOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
- case kZipCmd:
+ case GUI::kOKCmd:
_vm->_vars["azip"] = _zipModeCheckbox->getState() ? 1 : 0;
- break;
- case kWaterCmd:
_vm->_vars["waterenabled"] = _waterEffectCheckbox->getState() ? 1 : 0;
+ setResult(1);
+ close();
break;
- case GUI::kCloseCmd:
+ case kQuitCmd: {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
close();
break;
+ }
default:
- GUI::OptionsDialog::handleCommand(sender, cmd, data);
+ MohawkOptionsDialog::handleCommand(sender, cmd, data);
}
}
diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h
index bc25c72a43..443f2fb67e 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -28,12 +28,13 @@
#include "common/events.h"
#include "common/str.h"
#include "gui/dialog.h"
-#include "gui/options.h"
-#include "gui/widget.h"
-#include "gui/widgets/list.h"
namespace GUI {
class SaveLoadChooser;
+class ButtonWidget;
+class CheckboxWidget;
+class CommandSender;
+class StaticTextWidget;
}
namespace Mohawk {
@@ -70,18 +71,48 @@ public:
virtual void handleKeyDown(Common::KeyState state);
};
+#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN)
+
+class MohawkOptionsDialog : public GUI::Dialog {
+public:
+ MohawkOptionsDialog(MohawkEngine *_vm);
+ virtual ~MohawkOptionsDialog();
+
+ virtual void open() override;
+ virtual void reflowLayout() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+
+ int getLoadSlot() const {return _loadSlot;}
+
+private:
+ MohawkEngine *_vm;
+
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+
+ GUI::SaveLoadChooser *_loadDialog;
+ GUI::SaveLoadChooser *_saveDialog;
+
+ int _loadSlot;
+
+ void save();
+ void load();
+};
+
+#endif
+
#ifdef ENABLE_MYST
class MohawkEngine_Myst;
-class MystOptionsDialog : public GUI::Dialog {
+class MystOptionsDialog : public MohawkOptionsDialog {
public:
MystOptionsDialog(MohawkEngine_Myst *vm);
- ~MystOptionsDialog();
- void open();
+ virtual ~MystOptionsDialog();
+
+ virtual void open() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
- virtual void reflowLayout() override;
- virtual void handleCommand(GUI::CommandSender*, uint32, uint32);
private:
MohawkEngine_Myst *_vm;
@@ -91,15 +122,6 @@ private:
GUI::ButtonWidget *_dropPageButton;
GUI::ButtonWidget *_showMapButton;
GUI::ButtonWidget *_returnToMenuButton;
-
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
-
- GUI::SaveLoadChooser *_loadDialog;
- GUI::SaveLoadChooser *_saveDialog;
-
- void save();
- void load();
};
#endif
@@ -108,15 +130,17 @@ private:
class MohawkEngine_Riven;
-class RivenOptionsDialog : public GUI::OptionsDialog {
+class RivenOptionsDialog : public MohawkOptionsDialog {
public:
RivenOptionsDialog(MohawkEngine_Riven *vm);
- ~RivenOptionsDialog();
- void open();
+ virtual ~RivenOptionsDialog();
+
+ virtual void open() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
- virtual void handleCommand(GUI::CommandSender*, uint32, uint32);
private:
MohawkEngine_Riven *_vm;
+
GUI::CheckboxWidget *_zipModeCheckbox;
GUI::CheckboxWidget *_waterEffectCheckbox;
};
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index 5f9b523e9a..f9fdeea15f 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -74,6 +74,10 @@ public:
// Free all surfaces in the cache
void clearCache();
+ // findImage will search the cache to find the image.
+ // If not found, it will call decodeImage to get a new one.
+ MohawkSurface *findImage(uint16 id);
+
void preloadImage(uint16 image);
virtual void setPalette(uint16 id);
void copyAnimImageToScreen(uint16 image, int left = 0, int top = 0);
@@ -85,10 +89,6 @@ public:
protected:
void copyAnimImageSectionToScreen(MohawkSurface *image, Common::Rect src, Common::Rect dest);
- // findImage will search the cache to find the image.
- // If not found, it will call decodeImage to get a new one.
- MohawkSurface *findImage(uint16 id);
-
// decodeImage will always return a new image.
virtual MohawkSurface *decodeImage(uint16 id) = 0;
virtual Common::Array<MohawkSurface *> decodeImages(uint16 id);
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 5af8fac901..6ee18d1576 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -144,6 +144,7 @@ MohawkEngine_LivingBooks::MohawkEngine_LivingBooks(OSystem *syst, const MohawkGa
_rnd = new Common::RandomSource("livingbooks");
+ _sound = NULL;
_page = NULL;
const Common::FSNode gameDataDir(ConfMan.get("path"));
@@ -158,6 +159,7 @@ MohawkEngine_LivingBooks::~MohawkEngine_LivingBooks() {
destroyPage();
delete _console;
+ delete _sound;
delete _gfx;
delete _rnd;
_bookInfoFile.clear();
@@ -182,6 +184,7 @@ Common::Error MohawkEngine_LivingBooks::run() {
error("Could not find xRes/yRes variables");
_gfx = new LBGraphics(this, _screenWidth, _screenHeight);
+ _sound = new Sound(this);
if (getGameType() != GType_LIVINGBOOKSV1)
_cursor = new LivingBooksCursorManager_v2();
@@ -3886,7 +3889,7 @@ bool LBMiniGameItem::togglePlaying(bool playing, bool restart) {
// Go back to the menu if requested, otherwise go to the requested page
if (returnToMenu)
_vm->addNotifyEvent(NotifyEvent(kLBNotifyGoToControls, 1));
- else
+ else
_vm->addNotifyEvent(NotifyEvent(kLBNotifyChangePage, destPage));
return false;
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 1a265a1a02..cf67c1ee8e 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -714,6 +714,7 @@ public:
Common::RandomSource *_rnd;
+ Sound *_sound;
LBGraphics *_gfx;
bool _needsRedraw, _needsUpdate;
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index 83e541e3e4..3fc118d2b6 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -57,6 +57,7 @@ MODULE_OBJS += \
riven_graphics.o \
riven_saveload.o \
riven_scripts.o \
+ riven_sound.o \
riven_vars.o
endif
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index d740d9479a..40290d4e4c 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -24,6 +24,7 @@
#include "common/error.h"
#include "common/system.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "mohawk/mohawk.h"
#include "mohawk/cursors.h"
@@ -40,14 +41,12 @@ MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc)
// Setup mixer
syncSoundSettings();
- _sound = 0;
_video = 0;
_pauseDialog = 0;
_cursor = 0;
}
MohawkEngine::~MohawkEngine() {
- delete _sound;
delete _video;
delete _pauseDialog;
delete _cursor;
@@ -58,22 +57,19 @@ MohawkEngine::~MohawkEngine() {
}
Common::Error MohawkEngine::run() {
- _sound = new Sound(this);
_video = new VideoManager(this);
- _pauseDialog = new PauseDialog(this, "The game is paused. Press any key to continue.");
+ _pauseDialog = new PauseDialog(this, _("The game is paused. Press any key to continue."));
return Common::kNoError;
}
void MohawkEngine::pauseEngineIntern(bool pause) {
+ Engine::pauseEngineIntern(pause);
+
if (pause) {
_video->pauseVideos();
- _sound->pauseSound();
- _sound->pauseSLST();
} else {
_video->resumeVideos();
- _sound->resumeSound();
- _sound->resumeSLST();
_system->updateScreen();
}
}
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index 6fa733e38e..bc0d642bce 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef MOHAWK_H
-#define MOHAWK_H
+#ifndef MOHAWK_MOHAWK_H
+#define MOHAWK_MOHAWK_H
#include "common/scummsys.h"
#include "common/array.h"
@@ -100,7 +100,6 @@ public:
bool hasFeature(EngineFeature f) const;
- Sound *_sound;
VideoManager *_video;
CursorManager *_cursor;
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 3bc2b2dccb..e887436e98 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -66,11 +66,6 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
DebugMan.addDebugChannel(kDebugHelp, "Help", "Track Help File (HELP) Parsing");
DebugMan.addDebugChannel(kDebugCache, "Cache", "Track Resource Cache Accesses");
- // Engine tweaks
- // Disabling this makes engine behavior as per
- // original, including bugs, missing bits etc. :)
- _tweaksEnabled = true;
-
_currentCursor = 0;
_mainCursor = kDefaultMystCursor;
_showResourceRects = false;
@@ -80,6 +75,7 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_curResource = -1;
_hoverResource = nullptr;
+ _sound = nullptr;
_gfx = nullptr;
_console = nullptr;
_scriptParser = nullptr;
@@ -93,6 +89,7 @@ MohawkEngine_Myst::~MohawkEngine_Myst() {
DebugMan.clearAllDebugChannels();
delete _gfx;
+ delete _sound;
delete _console;
delete _scriptParser;
delete _gameState;
@@ -152,7 +149,7 @@ void MohawkEngine_Myst::cachePreload(uint32 tag, uint16 id) {
}
}
- warning("cachePreload: Could not find a \'%s\' resource with ID %04x", tag2str(tag), id);
+ debugC(kDebugCache, "cachePreload: Could not find a \'%s\' resource with ID %04x", tag2str(tag), id);
}
static const char *mystFiles[] = {
@@ -225,6 +222,7 @@ Common::Error MohawkEngine_Myst::run() {
MohawkEngine::run();
_gfx = new MystGraphics(this);
+ _sound = new Sound(this);
_console = new MystConsole(this);
_gameState = new MystGameState(this, _saveFileMan);
_optionsDialog = new MystOptionsDialog(this);
@@ -236,11 +234,9 @@ Common::Error MohawkEngine_Myst::run() {
// Load game from launcher/command line if requested
if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) {
- uint32 gameToLoad = ConfMan.getInt("save_slot");
- Common::StringArray savedGamesList = MystGameState::generateSaveGameList();
- if (gameToLoad > savedGamesList.size())
- error ("Could not find saved game");
- _gameState->load(savedGamesList[gameToLoad]);
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (!_gameState->load(saveSlot))
+ error("Failed to load save game from slot %i", saveSlot);
} else {
// Start us on the first stack.
if (getGameType() == GType_MAKINGOF)
@@ -312,9 +308,12 @@ Common::Error MohawkEngine_Myst::run() {
_needsPageDrop = false;
_needsShowMap = false;
_needsShowDemoMenu = false;
+ _needsShowCredits = false;
_canSafelySaveLoad = true;
runDialog(*_optionsDialog);
+ if (_optionsDialog->getLoadSlot() >= 0)
+ loadGameState(_optionsDialog->getLoadSlot());
_canSafelySaveLoad = false;
if (_needsPageDrop) {
@@ -331,6 +330,12 @@ Common::Error MohawkEngine_Myst::run() {
changeToStack(kDemoStack, 2002, 0, 0);
_needsShowDemoMenu = false;
}
+
+ if (_needsShowCredits) {
+ _cursor->hideCursor();
+ changeToStack(kCreditsStack, 10000, 0, 0);
+ _needsShowCredits = false;
+ }
break;
default:
break;
@@ -396,6 +401,25 @@ bool MohawkEngine_Myst::skippableWait(uint32 duration) {
return skipped;
}
+void MohawkEngine_Myst::pollAndDiscardEvents() {
+ // Poll the events to update the mouse cursor position
+ Common::Event event;
+ while (_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_SPACE:
+ pauseGame();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound) {
debug(2, "changeToStack(%d)", stack);
@@ -503,8 +527,9 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
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 (_tweaksEnabled)
+ if (ConfMan.getBool("playmystflyby") && card == 4134)
flyby = "myst flyby";
break;
case kMechanicalStack:
@@ -603,7 +628,8 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
_gfx->runTransition(transition, Common::Rect(544, 333), 10, 0);
} else {
_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
- _needsUpdate = true;
+ _system->updateScreen();
+ _needsUpdate = false;
}
}
@@ -1080,19 +1106,14 @@ void MohawkEngine_Myst::loadResources() {
}
Common::Error MohawkEngine_Myst::loadGameState(int slot) {
- if (_gameState->load(MystGameState::generateSaveGameList()[slot]))
+ if (_gameState->load(slot))
return Common::kNoError;
return Common::kUnknownError;
}
Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) {
- Common::StringArray saveList = MystGameState::generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- MystGameState::deleteSave(saveList[slot]);
-
- return _gameState->save(desc) ? Common::kNoError : Common::kUnknownError;
+ return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError;
}
bool MohawkEngine_Myst::hasGameSaveSupport() const {
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 0803c69e55..2414b71cb1 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -187,19 +187,21 @@ public:
uint16 getMainCursor() { return _mainCursor; }
void checkCursorHints();
MystArea *updateCurrentResource();
+ void pollAndDiscardEvents();
bool skippableWait(uint32 duration);
MystSoundBlock readSoundBlock(Common::ReadStream *stream) const;
void applySoundBlock(const MystSoundBlock &block);
- bool _tweaksEnabled;
bool _needsUpdate;
bool _needsPageDrop;
bool _needsShowMap;
bool _needsShowDemoMenu;
+ bool _needsShowCredits;
bool _showResourceRects;
+ Sound *_sound;
MystGraphics *_gfx;
MystGameState *_gameState;
MystScriptParser *_scriptParser;
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 59871ed49f..8514cd5406 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -42,7 +42,7 @@ MystArea::MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream
_rect.top = rlstStream->readSint16LE();
if (_rect.top == -1) {
- warning("Invalid _rect.top of -1 found - clamping to 0");
+ debugC(kDebugResource, "Invalid _rect.top of -1 found - clamping to 0");
_rect.top = 0;
}
@@ -240,6 +240,7 @@ VideoHandle MystAreaVideo::playMovie() {
} else {
// Resume the video
handle->pause(false);
+ handle->start();
}
if (_playBlocking) {
@@ -250,6 +251,20 @@ VideoHandle MystAreaVideo::playMovie() {
return handle;
}
+VideoHandle MystAreaVideo::getMovieHandle() {
+ // If the video is already in the manager, just return the handle
+ VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
+ if (!handle) {
+ // If the video has not been loaded yet, do it but don't start playing it
+ handle = _vm->_video->playMovie(_videoFile);
+ if (!handle)
+ error("Failed to open '%s'", _videoFile.c_str());
+ handle->stop();
+ }
+
+ return handle;
+}
+
void MystAreaVideo::handleCardChange() {
if (_playOnCardChange)
playMovie();
diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h
index 09ec6a2742..b19a2df9e2 100644
--- a/engines/mohawk/myst_areas.h
+++ b/engines/mohawk/myst_areas.h
@@ -108,6 +108,8 @@ public:
MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
VideoHandle playMovie();
+ VideoHandle getMovieHandle();
+
void handleCardChange() override;
bool isPlaying();
void setDirection(int16 direction) { _direction = direction; }
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
index 5db9697a78..333da402fa 100644
--- a/engines/mohawk/myst_graphics.cpp
+++ b/engines/mohawk/myst_graphics.cpp
@@ -47,8 +47,7 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
} else {
// Paletted
initGraphics(_viewport.width(), _viewport.height(), true);
- setBasePalette();
- setPaletteToScreen();
+ clearScreenPalette();
}
_pixelFormat = _vm->_system->getScreenFormat();
@@ -86,7 +85,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
bool isPict = false;
- if (_vm->getFeatures() & GF_ME) {
+ if ((_vm->getFeatures() & GF_ME) && dataStream->size() > 512 + 10 + 4) {
// Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
// would be compressed, there's no way to detect for the BM without a hack.
// So, we search for the PICT version opcode for detection.
@@ -109,8 +108,11 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
} else {
mhkSurface = _bmpDecoder->decodeImage(dataStream);
- if (_vm->getFeatures() & GF_ME)
+ if (_vm->getFeatures() & GF_ME) {
mhkSurface->convertToTrueColor();
+ } else {
+ remapSurfaceToSystemPalette(mhkSurface);
+ }
}
assert(mhkSurface);
@@ -204,7 +206,7 @@ void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src,
if (!(_vm->getFeatures() & GF_ME)) {
// Make sure the palette is set
assert(mhkSurface->getPalette());
- memcpy(_palette + 10 * 3, mhkSurface->getPalette() + 10 * 3, (256 - 10 * 2) * 3);
+ memcpy(_palette, mhkSurface->getPalette(), 256 * 3);
setPaletteToScreen();
}
}
@@ -241,6 +243,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
area.right = area.left + step;
_vm->_system->delayMillis(delay);
+ _vm->pollAndDiscardEvents();
copyBackBufferToScreen(area);
_vm->_system->updateScreen();
@@ -264,6 +267,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
area.left = area.right - step;
_vm->_system->delayMillis(delay);
+ _vm->pollAndDiscardEvents();
copyBackBufferToScreen(area);
_vm->_system->updateScreen();
@@ -307,6 +311,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
area.bottom = area.top + step;
_vm->_system->delayMillis(delay);
+ _vm->pollAndDiscardEvents();
copyBackBufferToScreen(area);
_vm->_system->updateScreen();
@@ -330,6 +335,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16
area.top = area.bottom - step;
_vm->_system->delayMillis(delay);
+ _vm->pollAndDiscardEvents();
copyBackBufferToScreen(area);
_vm->_system->updateScreen();
@@ -454,6 +460,7 @@ void MystGraphics::transitionDissolve(Common::Rect rect, uint step) {
}
_vm->_system->unlockScreen();
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -473,6 +480,7 @@ void MystGraphics::transitionSlideToLeft(Common::Rect rect, uint16 steps, uint16
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -498,6 +506,7 @@ void MystGraphics::transitionSlideToRight(Common::Rect rect, uint16 steps, uint1
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -523,6 +532,7 @@ void MystGraphics::transitionSlideToTop(Common::Rect rect, uint16 steps, uint16
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -549,6 +559,7 @@ void MystGraphics::transitionSlideToBottom(Common::Rect rect, uint16 steps, uint
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -573,6 +584,7 @@ void MystGraphics::transitionPartialToRight(Common::Rect rect, uint32 width, uin
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -594,6 +606,7 @@ void MystGraphics::transitionPartialToLeft(Common::Rect rect, uint32 width, uint
simulatePreviousDrawDelay(dstRect);
_vm->_system->copyRectToScreen(_backBuffer->getBasePtr(dstRect.left, dstRect.top),
_backBuffer->pitch, srcRect.left, srcRect.top, srcRect.width(), srcRect.height());
+ _vm->pollAndDiscardEvents();
_vm->_system->updateScreen();
}
@@ -703,10 +716,10 @@ void MystGraphics::clearScreenPalette() {
_vm->_system->getPaletteManager()->setPalette(palette, 0, 256);
}
-void MystGraphics::setBasePalette() {
+void MystGraphics::remapSurfaceToSystemPalette(MohawkSurface *mhkSurface) {
// Entries [0, 9] of the palette
static const byte lowPalette[] = {
- 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00,
0x80, 0x00, 0x00,
0x00, 0x80, 0x00,
0x80, 0x80, 0x00,
@@ -729,15 +742,68 @@ void MystGraphics::setBasePalette() {
0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF,
0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x00
+ 0xFF, 0xFF, 0xFF
};
- // Note that 0 and 255 are different from normal Windows.
- // Myst seems to hack that to white, resp. black (probably for Mac compat).
+ byte *originalPalette = mhkSurface->getPalette();
+
+ // The target palette is made of the Windows reserved palette, and colors 10 to 245
+ // of the bitmap palette. Entries 0 to 9 and 246 to 255 of the bitmap palette are
+ // discarded.
+ byte targetPalette[256 * 3];
+ memcpy(targetPalette, lowPalette, sizeof(lowPalette));
+ memcpy(targetPalette + sizeof(lowPalette), originalPalette + sizeof(lowPalette), sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette));
+ memcpy(targetPalette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette));
+
+ // Remap the discarded entries from the bitmap palette using the target palette.
+ byte lowColorMap[ARRAYSIZE(lowPalette) / 3];
+ byte highColorMap[ARRAYSIZE(highPalette) / 3];
+
+ for (uint i = 0; i < ARRAYSIZE(lowColorMap); i++) {
+ uint colorIndex = 3 * i;
+ byte red = originalPalette[colorIndex + 0];
+ byte green = originalPalette[colorIndex + 1];
+ byte blue = originalPalette[colorIndex + 2];
+
+ lowColorMap[i] = getColorIndex(targetPalette, red, green, blue);
+ }
+
+ for (uint i = 0; i < ARRAYSIZE(highColorMap); i++) {
+ uint colorIndex = 3 * (i + 246);
+ byte red = originalPalette[colorIndex + 0];
+ byte green = originalPalette[colorIndex + 1];
+ byte blue = originalPalette[colorIndex + 2];
+
+ highColorMap[i] = getColorIndex(targetPalette, red, green, blue);
+ }
+
+ // Replace the original palette with the target palette
+ memcpy(originalPalette, targetPalette, sizeof(targetPalette));
+
+ // Remap the pixel data to the target palette
+ Graphics::Surface *surface = mhkSurface->getSurface();
+ byte *pixels = (byte *) surface->getPixels();
+
+ for (int i = 0; i < surface->w * surface->h; i++) {
+ if (pixels[i] < ARRAYSIZE(lowColorMap)) {
+ pixels[i] = lowColorMap[pixels[i]];
+ } else if (pixels[i] >= 246) {
+ pixels[i] = highColorMap[pixels[i] - 246];
+ }
+ }
+}
+
+byte MystGraphics::getColorIndex(const byte *palette, byte red, byte green, byte blue) {
+ for (uint i = 0; i < 256; i++) {
+ if (palette[(3 * i) + 0] == red && palette[(3 * i) + 1] == green && palette[(3 * i) + 2] == blue) {
+ return i;
+ }
+ }
- memcpy(_palette, lowPalette, sizeof(lowPalette));
- memset(_palette + sizeof(lowPalette), 0, sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette));
- memcpy(_palette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette));
+ // GDI actually chooses the nearest color if no exact match is found,
+ // but this should not happen in Myst
+ debug(1, "Color (%d, %d, %d) not in target palette", red, green, blue);
+ return 0;
}
void MystGraphics::setPaletteToScreen() {
diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h
index 93e388cb83..cd09a53a3a 100644
--- a/engines/mohawk/myst_graphics.h
+++ b/engines/mohawk/myst_graphics.h
@@ -56,7 +56,6 @@ public:
void fadeFromBlack();
void clearScreenPalette();
- void setBasePalette();
void setPaletteToScreen();
const byte *getPalette() const { return _palette; }
@@ -86,6 +85,9 @@ private:
void transitionSlideToBottom(Common::Rect rect, uint16 steps, uint16 delay);
void transitionPartialToRight(Common::Rect rect, uint32 width, uint32 steps);
void transitionPartialToLeft(Common::Rect rect, uint32 width, uint32 steps);
+
+ void remapSurfaceToSystemPalette(MohawkSurface *mhkSurface);
+ byte getColorIndex(const byte *palette, byte red, byte green, byte blue);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index 04e7c5a9b7..596180ddb2 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -31,7 +31,6 @@
#include "common/system.h"
#include "common/memstream.h"
#include "common/textconsole.h"
-#include "gui/message.h"
namespace Mohawk {
@@ -685,9 +684,14 @@ void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 arg
// Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List
debugC(kDebugScript, "Opcode %d: Process Sound Block", op);
- Common::MemoryReadStream stream = Common::MemoryReadStream((const byte *) argv, argc * sizeof(uint16));
+ Common::MemoryWriteStreamDynamic writeStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
+ for (uint i = 0; i < argc; i++) {
+ writeStream.writeUint16LE(argv[i]);
+ }
+
+ Common::MemoryReadStream readStream = Common::MemoryReadStream(writeStream.getData(), writeStream.size());
- MystSoundBlock soundBlock = _vm->readSoundBlock(&stream);
+ MystSoundBlock soundBlock = _vm->readSoundBlock(&readStream);
_vm->applySoundBlock(soundBlock);
}
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index 659c5dcdf2..21c3042359 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -621,24 +621,32 @@ void Channelwood::o_hologramMonitor(uint16 op, uint16 var, uint16 argc, uint16 *
switch (button) {
case 0:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monalgh movie");
+ handle->moveTo(227, 70);
break;
case 1:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monamth movie");
+ handle->moveTo(227, 70);
break;
case 2:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monasirs movie");
+ handle->moveTo(227, 70);
break;
case 3:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monsmsg movie");
+ handle->moveTo(226, 68);
break;
default:
warning("Opcode %d Control Variable Out of Range", op);
break;
}
-
- // Move the video to the right location
- if (handle)
- handle->moveTo(227, 70);
}
}
diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp
index 6548dd3171..c382263f7c 100644
--- a/engines/mohawk/myst_stacks/credits.cpp
+++ b/engines/mohawk/myst_stacks/credits.cpp
@@ -28,7 +28,6 @@
#include "mohawk/myst_stacks/credits.h"
#include "common/system.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
@@ -67,8 +66,10 @@ void Credits::runPersistentScripts() {
_curImage++;
// After the 6th image has shown, it's time to quit
- if (_curImage == 7)
+ if (_curImage == 7) {
_vm->quitGame();
+ return;
+ }
// Draw next image
_vm->drawCardBackground();
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index 1d733d8100..f448108199 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -28,8 +28,6 @@
#include "mohawk/video.h"
#include "mohawk/myst_stacks/intro.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_stacks/makingof.cpp b/engines/mohawk/myst_stacks/makingof.cpp
index 1059fd0c5e..a0a1f359ba 100644
--- a/engines/mohawk/myst_stacks/makingof.cpp
+++ b/engines/mohawk/myst_stacks/makingof.cpp
@@ -27,8 +27,6 @@
#include "mohawk/video.h"
#include "mohawk/myst_stacks/makingof.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index 3214c643a5..3324c9a22d 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -667,7 +667,7 @@ void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 *
void Mechanical::o_fortressRotationSetPosition(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Set fortress position", op);
- VideoHandle gears = _fortressRotationGears->playMovie();
+ VideoHandle gears = _fortressRotationGears->getMovieHandle();
uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
// Myst ME short movie workaround, explained in o_fortressRotation_init
@@ -801,7 +801,7 @@ void Mechanical::o_elevatorRotation_init(uint16 op, uint16 var, uint16 argc, uin
}
void Mechanical::fortressRotation_run() {
- VideoHandle gears = _fortressRotationGears->playMovie();
+ VideoHandle gears = _fortressRotationGears->getMovieHandle();
double oldRate = gears->getRate().toDouble();
uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
@@ -949,7 +949,7 @@ void Mechanical::fortressSimulation_run() {
_fortressSimulationInit = false;
} else {
- VideoHandle holo = _fortressSimulationHolo->playMovie();
+ VideoHandle holo = _fortressSimulationHolo->getMovieHandle();
double oldRate = holo->getRate().toDouble();
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index 5033f0fef8..f9ba6a42fa 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -33,8 +33,6 @@
#include "common/system.h"
#include "common/textconsole.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
@@ -52,6 +50,7 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_cabinDoorOpened = 0;
_cabinHandleDown = 0;
_cabinMatchState = 2;
+ _cabinGaugeMovieEnabled = false;
_matchBurning = false;
_tree = nullptr;
_treeAlcove = nullptr;
@@ -2142,7 +2141,7 @@ void Myst::tree_run() {
// Check if alcove is accessible
treeSetAlcoveAccessible();
- if (_cabinGaugeMovie) {
+ if (_cabinGaugeMovieEnabled) {
Common::Rational rate = boilerComputeGaugeRate(pressure, delay);
boilerResetGauge(rate);
}
@@ -2313,7 +2312,7 @@ void Myst::o_rocketPianoStart(uint16 op, uint16 var, uint16 argc, uint16 *argv)
dest.bottom = 332 - rect.top;
// Draw pressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
_vm->_system->updateScreen();
// Play note
@@ -3088,6 +3087,8 @@ void Myst::clockReset() {
}
void Myst::clockResetWeight() {
+ _vm->_sound->replaceSoundMyst(9113);
+
_clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack));
if (!_clockWeightVideo)
error("Failed to open cl1wlfch movie");
@@ -3270,7 +3271,7 @@ void Myst::towerRotationMapDrawLine(const Common::Point &center, const Common::P
color = pf.RGBToColor(0xFF, 0, 0); // Red
} else {
if (!_towerRotationOverSpot)
- color = 0x00; // White
+ color = 0xFF; // White
else
color = 0xF9; // Red
}
@@ -3608,7 +3609,7 @@ void Myst::gullsFly2_run() {
VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack));
if (!handle)
error("Failed to open gulls movie");
-
+
handle->moveTo(424, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
@@ -3703,6 +3704,8 @@ void Myst::boilerGaugeInit() {
frame = Audio::Timestamp(0, 0, 600);
_vm->_video->drawVideoFrame(_cabinGaugeMovie, frame);
+
+ _cabinGaugeMovieEnabled = true;
}
void Myst::o_rocketSliders_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -3842,6 +3845,8 @@ void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_cabinGaugeMovie = VideoHandle();
_cabinFireMovie = VideoHandle();
+
+ _cabinGaugeMovieEnabled = false;
}
void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h
index 9d66b798c5..6e2f7cc1c8 100644
--- a/engines/mohawk/myst_stacks/myst.h
+++ b/engines/mohawk/myst_stacks/myst.h
@@ -261,6 +261,8 @@ protected:
uint32 _matchGoOutTime; // 144
VideoHandle _cabinFireMovie; // 240
+
+ bool _cabinGaugeMovieEnabled;
VideoHandle _cabinGaugeMovie; // 244
bool _boilerPressureIncreasing;
diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp
index 2617bd04aa..454435cf92 100644
--- a/engines/mohawk/myst_stacks/selenitic.cpp
+++ b/engines/mohawk/myst_stacks/selenitic.cpp
@@ -31,7 +31,6 @@
#include "common/system.h"
#include "common/textconsole.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
@@ -672,6 +671,11 @@ void Selenitic::soundReceiverUpdate() {
}
void Selenitic::soundReceiverDrawView() {
+ soundReceiverSetSubimageRect();
+ soundReceiverDrawAngle();
+}
+
+void Selenitic::soundReceiverSetSubimageRect() const {
uint32 left = ((*_soundReceiverPosition) * 1800) / 3600;
Common::Rect rect = _soundReceiverViewer->getSubImage(0).rect;
@@ -681,8 +685,6 @@ void Selenitic::soundReceiverDrawView() {
_soundReceiverViewer->setSubImageRect(0, rect);
_soundReceiverViewer->drawConditionalDataToScreen(0);
-
- soundReceiverDrawAngle();
}
void Selenitic::soundReceiverDrawAngle() {
@@ -948,10 +950,13 @@ void Selenitic::soundReceiver_run() {
if (_soundReceiverDirection) {
uint32 currentTime = _vm->_system->getMillis();
- if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500)
- soundReceiverIncreaseSpeed();
- else if (currentTime > _soundReceiverStartTime + 1000)
- soundReceiverIncreaseSpeed();
+ if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) {
+ soundReceiverIncreaseSpeed();
+ _soundReceiverStartTime = currentTime;
+ } else if (currentTime > _soundReceiverStartTime + 1000) {
+ soundReceiverIncreaseSpeed();
+ _soundReceiverStartTime = currentTime;
+ }
if (currentTime > _soundReceiverStartTime + 100)
soundReceiverUpdate();
@@ -1080,6 +1085,8 @@ void Selenitic::o_soundReceiver_init(uint16 op, uint16 var, uint16 argc, uint16
_soundReceiverPosition = &_state.soundReceiverPositions[currentSource];
_soundReceiverCurrentSource = _soundReceiverSources[currentSource];
+ soundReceiverSetSubimageRect();
+
_soundReceiverSigmaPressed = false;
}
diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h
index ffd8941f2c..fc9649755d 100644
--- a/engines/mohawk/myst_stacks/selenitic.h
+++ b/engines/mohawk/myst_stacks/selenitic.h
@@ -117,6 +117,7 @@ private:
void soundReceiverLeftRight(uint direction);
void soundReceiverUpdate();
+ void soundReceiverSetSubimageRect() const;
void soundReceiverDrawView();
void soundReceiverDrawAngle();
void soundReceiverIncreaseSpeed();
diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp
index a1413f0d71..0560608b24 100644
--- a/engines/mohawk/myst_stacks/slides.cpp
+++ b/engines/mohawk/myst_stacks/slides.cpp
@@ -29,7 +29,6 @@
#include "mohawk/myst_stacks/slides.h"
#include "common/system.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index 06cd69b23c..213a976413 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -106,16 +106,12 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav
MystGameState::~MystGameState() {
}
-Common::StringArray MystGameState::generateSaveGameList() {
- return g_system->getSavefileManager()->listSavefiles("*.mys");
-}
-
-bool MystGameState::load(const Common::String &filename) {
- if (!loadState(filename)) {
+bool MystGameState::load(int slot) {
+ if (!loadState(slot)) {
return false;
}
- loadMetadata(filename);
+ loadMetadata(slot);
// Set Channelwood elevator state to down, because we start on the lower level
_channelwood.elevatorState = 0;
@@ -124,6 +120,7 @@ bool MystGameState::load(const Common::String &filename) {
_vm->changeToStack(kIntroStack, 5, 0, 0);
// Set our default cursor
+ _vm->_cursor->showCursor();
if (_globals.heldPage == 0 || _globals.heldPage > 13)
_vm->setMainCursor(kDefaultMystCursor);
else if (_globals.heldPage < 7)
@@ -136,7 +133,8 @@ bool MystGameState::load(const Common::String &filename) {
return true;
}
-bool MystGameState::loadState(const Common::String &filename) {
+bool MystGameState::loadState(int slot) {
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile) {
return false;
@@ -160,9 +158,10 @@ bool MystGameState::loadState(const Common::String &filename) {
return true;
}
-void MystGameState::loadMetadata(const Common::String &filename) {
+void MystGameState::loadMetadata(int slot) {
// Open the metadata file
- Common::InSaveFile *metadataFile = openMetadataFile(filename);
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = _vm->getSaveFileManager()->openForLoading(filename);
if (!metadataFile) {
return;
}
@@ -179,25 +178,19 @@ void MystGameState::loadMetadata(const Common::String &filename) {
delete metadataFile;
}
-bool MystGameState::save(const Common::String &filename) {
- // Make sure the description does not have an extension
- Common::String desc = filename;
- if (filename.hasSuffix(".mys") || filename.hasSuffix(".MYS")) {
- desc = removeExtension(filename);
- }
-
- if (!saveState(desc)) {
+bool MystGameState::save(int slot, const Common::String &desc) {
+ if (!saveState(slot)) {
return false;
}
updateMetadateForSaving(desc);
- return saveMetadata(desc);
+ return saveMetadata(slot);
}
-bool MystGameState::saveState(const Common::String &desc) {
+bool MystGameState::saveState(int slot) {
// Make sure we have the right extension
- Common::String filename = desc + ".mys";
+ Common::String filename = buildSaveFilename(slot);
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename);
if (!saveFile) {
return false;
@@ -213,6 +206,14 @@ bool MystGameState::saveState(const Common::String &desc) {
return true;
}
+Common::String MystGameState::buildSaveFilename(int slot) {
+ return Common::String::format("myst-%03d.mys", slot);
+}
+
+Common::String MystGameState::buildMetadataFilename(int slot) {
+ return Common::String::format("myst-%03d.mym", slot);
+}
+
void MystGameState::updateMetadateForSaving(const Common::String &desc) {
// Update save creation info
TimeDate t;
@@ -226,10 +227,10 @@ void MystGameState::updateMetadateForSaving(const Common::String &desc) {
_metadata.totalPlayTime = _vm->getTotalPlayTime();
}
-bool MystGameState::saveMetadata(const Common::String &desc) {
+bool MystGameState::saveMetadata(int slot) {
// Write the metadata to a separate file so that the save files
// are still compatible with the original engine
- Common::String metadataFilename = desc + ".mym";
+ Common::String metadataFilename = buildMetadataFilename(slot);
Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename);
if (!metadataFile) {
return false;
@@ -248,14 +249,12 @@ bool MystGameState::saveMetadata(const Common::String &desc) {
return true;
}
-SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filename) {
- SaveStateDescriptor desc;
- desc.setDescription(filename);
-
+SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
// Open the metadata file
- Common::InSaveFile *metadataFile = openMetadataFile(filename);
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
if (!metadataFile) {
- return desc;
+ return SaveStateDescriptor();
}
Common::Serializer m(metadataFile, nullptr);
@@ -264,10 +263,11 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filen
Mohawk::MystSaveMetadata metadata;
if (!metadata.sync(m)) {
delete metadataFile;
- return desc;
+ return SaveStateDescriptor();
}
// Set the save description
+ SaveStateDescriptor desc;
desc.setDescription(metadata.saveDescription);
desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
desc.setSaveTime(metadata.saveHour, metadata.saveMinute);
@@ -279,20 +279,26 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filen
return desc;
}
-Common::InSaveFile *MystGameState::openMetadataFile(const Common::String &filename) {
- // Remove the extension
- Common::String baseName = removeExtension(filename);
-
+Common::String MystGameState::querySaveDescription(int slot) {
// Open the metadata file
- return g_system->getSavefileManager()->openForLoading(baseName + ".mym");
-}
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!metadataFile) {
+ return "";
+ }
+
+ Common::Serializer m(metadataFile, nullptr);
-Common::String MystGameState::removeExtension(const Common::String &filename) {
- Common::String baseName = filename;
- for (uint i = 0; i < 4; i++) {
- baseName.deleteLastChar();
+ // Read the metadata file
+ Mohawk::MystSaveMetadata metadata;
+ if (!metadata.sync(m)) {
+ delete metadataFile;
+ return "";
}
- return baseName;
+
+ delete metadataFile;
+
+ return metadata.saveDescription;
}
void MystGameState::syncGameState(Common::Serializer &s, bool isME) {
@@ -471,12 +477,14 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) {
warning("Unexpected File Position 0x%03X At End of Save/Load", s.bytesSynced());
}
-void MystGameState::deleteSave(const Common::String &saveName) {
- debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str());
- Common::String basename = removeExtension(saveName);
+void MystGameState::deleteSave(int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::String metadataFilename = buildMetadataFilename(slot);
+
+ debugC(kDebugSaveLoad, "Deleting save file \'%s\'", filename.c_str());
- g_system->getSavefileManager()->removeSavefile(saveName);
- g_system->getSavefileManager()->removeSavefile(basename + ".mym");
+ g_system->getSavefileManager()->removeSavefile(filename);
+ g_system->getSavefileManager()->removeSavefile(metadataFilename);
}
void MystGameState::addZipDest(uint16 stack, uint16 view) {
diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h
index 50359a5b52..7d5f3f7102 100644
--- a/engines/mohawk/myst_state.h
+++ b/engines/mohawk/myst_state.h
@@ -58,12 +58,12 @@ public:
MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*);
~MystGameState();
- static Common::StringArray generateSaveGameList();
- static SaveStateDescriptor querySaveMetaInfos(const Common::String filename);
+ static SaveStateDescriptor querySaveMetaInfos(int slot);
+ static Common::String querySaveDescription(int slot);
- bool load(const Common::String &filename);
- bool save(const Common::String &filename);
- static void deleteSave(const Common::String &saveName);
+ bool load(int slot);
+ bool save(int slot, const Common::String &desc);
+ static void deleteSave(int slot);
void addZipDest(uint16 stack, uint16 view);
bool isReachableZipDest(uint16 stack, uint16 view);
@@ -292,13 +292,13 @@ public:
private:
void syncGameState(Common::Serializer &s, bool isME);
- static Common::InSaveFile *openMetadataFile(const Common::String &filename);
- bool loadState(const Common::String &filename);
- void loadMetadata(const Common::String &filename);
- bool saveState(const Common::String &desc);
+ static Common::String buildSaveFilename(int slot);
+ static Common::String buildMetadataFilename(int slot);
+ bool loadState(int slot);
+ void loadMetadata(int slot);
+ bool saveState(int slot);
void updateMetadateForSaving(const Common::String &desc);
- bool saveMetadata(const Common::String &desc);
- static Common::String removeExtension(const Common::String &filename);
+ bool saveMetadata(int slot);
// The values in these regions are lists of VIEW resources
// which correspond to visited zip destinations
diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h
index d9074a5b73..12c5a139e4 100644
--- a/engines/mohawk/resource.h
+++ b/engines/mohawk/resource.h
@@ -68,6 +68,8 @@ namespace Mohawk {
#define ID_VARS MKTAG('V','A','R','S') // Variable Values
#define ID_VERS MKTAG('V','E','R','S') // Version Info
#define ID_ZIPS MKTAG('Z','I','P','S') // Zip Mode Status
+#define ID_META MKTAG('M','E','T','A') // ScummVM save metadata
+#define ID_THMB MKTAG('T','H','M','B') // ScummVM save thumbnail
// Zoombini Resource FourCC's
#define ID_SND MKTAG( 0 ,'S','N','D') // Standard Mohawk Sound
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 898f68c581..12b4851a9c 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -25,6 +25,7 @@
#include "common/keyboard.h"
#include "common/translation.h"
#include "common/system.h"
+#include "gui/saveload.h"
#include "mohawk/cursors.h"
#include "mohawk/installer_archive.h"
@@ -33,8 +34,8 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_graphics.h"
#include "mohawk/riven_saveload.h"
+#include "mohawk/riven_sound.h"
#include "mohawk/dialogs.h"
-#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/console.h"
@@ -54,9 +55,20 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_gameOver = false;
_activatedSLST = false;
_ignoreNextMouseUp = false;
- _extrasFile = 0;
+ _extrasFile = nullptr;
_curStack = kStackUnknown;
- _hotspots = 0;
+ _hotspots = nullptr;
+ _gfx = nullptr;
+ _sound = nullptr;
+ _externalScriptHandler = nullptr;
+ _rnd = nullptr;
+ _scriptMan = nullptr;
+ _console = nullptr;
+ _saveLoad = nullptr;
+ _optionsDialog = nullptr;
+ _curCard = 0;
+ _hotspotCount = 0;
+ _curHotspot = -1;
removeTimer();
// NOTE: We can never really support CD swapping. All of the music files
@@ -70,6 +82,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
SearchMan.addSubDirectoryMatching(gameDataDir, "data");
SearchMan.addSubDirectoryMatching(gameDataDir, "exe");
SearchMan.addSubDirectoryMatching(gameDataDir, "assets1");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "program");
g_atrusJournalRect1 = new Common::Rect(295, 402, 313, 426);
g_atrusJournalRect2 = new Common::Rect(259, 402, 278, 426);
@@ -81,6 +94,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
}
MohawkEngine_Riven::~MohawkEngine_Riven() {
+ delete _sound;
delete _gfx;
delete _console;
delete _externalScriptHandler;
@@ -112,6 +126,7 @@ Common::Error MohawkEngine_Riven::run() {
SearchMan.add("arcriven.z", &_installerArchive, 0, false);
_gfx = new RivenGraphics(this);
+ _sound = new RivenSoundManager(this);
_console = new RivenConsole(this);
_saveLoad = new RivenSaveLoad(this, _saveFileMan);
_externalScriptHandler = new RivenExternal(this);
@@ -132,8 +147,8 @@ Common::Error MohawkEngine_Riven::run() {
// We need to have a cursor source, or the game won't work
if (!_cursor->hasSource()) {
- Common::String message = "You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendmo.exe'. ";
- message += "Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.";
+ Common::String message = _("You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendmo.exe'. ");
+ message += _("Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.");
GUIErrorMessage(message);
warning("%s", message.c_str());
return Common::kNoGameDataFoundError;
@@ -144,7 +159,7 @@ Common::Error MohawkEngine_Riven::run() {
// We need extras.mhk for inventory images, marble images, and credits images
if (!_extrasFile->openFile("extras.mhk")) {
- Common::String message = "You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.";
+ Common::String message = _("You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.");
GUIErrorMessage(message);
warning("%s", message.c_str());
return Common::kNoGameDataFoundError;
@@ -165,13 +180,10 @@ Common::Error MohawkEngine_Riven::run() {
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");
+ int gameToLoad = ConfMan.getInt("save_slot");
// Attempt to load the game. On failure, just send us to the main menu.
- if (_saveLoad->loadGame(savedGamesList[gameToLoad]).getCode() != Common::kNoError) {
+ if (_saveLoad->loadGame(gameToLoad).getCode() != Common::kNoError) {
changeToStack(kStackAspit);
changeToCard(1);
}
@@ -191,6 +203,7 @@ Common::Error MohawkEngine_Riven::run() {
void MohawkEngine_Riven::handleEvents() {
// Update background running things
checkTimer();
+ _sound->updateSLST();
bool needsUpdate = _gfx->runScheduledWaterEffects();
needsUpdate |= _video->updateMovies();
@@ -250,6 +263,8 @@ void MohawkEngine_Riven::handleEvents() {
break;
case Common::KEYCODE_F5:
runDialog(*_optionsDialog);
+ if (_optionsDialog->getLoadSlot() >= 0)
+ loadGameState(_optionsDialog->getLoadSlot());
updateZipMode();
break;
case Common::KEYCODE_r:
@@ -700,6 +715,7 @@ void MohawkEngine_Riven::delayAndUpdate(uint32 ms) {
uint32 startTime = _system->getMillis();
while (_system->getMillis() < startTime + ms && !shouldQuit()) {
+ _sound->updateSLST();
bool needsUpdate = _gfx->runScheduledWaterEffects();
needsUpdate |= _video->updateMovies();
@@ -723,16 +739,11 @@ void MohawkEngine_Riven::runLoadDialog() {
}
Common::Error MohawkEngine_Riven::loadGameState(int slot) {
- return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]);
+ return _saveLoad->loadGame(slot);
}
Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) {
- Common::StringArray saveList = _saveLoad->generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- _saveLoad->deleteSave(saveList[slot]);
-
- return _saveLoad->saveGame(desc);
+ return _saveLoad->saveGame(slot, desc);
}
Common::String MohawkEngine_Riven::getStackName(uint16 stack) const {
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 9c23d07c52..ce819ac970 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -27,8 +27,6 @@
#include "mohawk/mohawk.h"
#include "mohawk/riven_scripts.h"
-#include "gui/saveload.h"
-
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/random.h"
@@ -43,6 +41,7 @@ class RivenExternal;
class RivenConsole;
class RivenSaveLoad;
class RivenOptionsDialog;
+class RivenSoundManager;
// Riven Stack Types
enum {
@@ -123,6 +122,7 @@ public:
MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc);
virtual ~MohawkEngine_Riven();
+ RivenSoundManager *_sound;
RivenGraphics *_gfx;
RivenExternal *_externalScriptHandler;
Common::RandomSource *_rnd;
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 00075039fe..fb98145b44 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -24,12 +24,13 @@
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
#include "mohawk/riven_graphics.h"
-#include "mohawk/sound.h"
+#include "mohawk/riven_sound.h"
#include "mohawk/video.h"
#include "gui/message.h"
#include "common/events.h"
#include "common/system.h"
+#include "common/translation.h"
namespace Mohawk {
@@ -209,8 +210,8 @@ void RivenExternal::runCommand(uint16 argc, uint16 *argv) {
}
void RivenExternal::runDemoBoundaryDialog() {
- GUI::MessageDialog dialog("Exploration beyond this point available only within the full version of\n"
- "the game.");
+ GUI::MessageDialog dialog(_("Exploration beyond this point available only within the full version of\n"
+ "the game."));
dialog.runModal();
}
@@ -651,11 +652,11 @@ void RivenExternal::xalaunchbrowser(uint16 argc, uint16 *argv) {
//
// [YES] [NO]
- GUI::MessageDialog dialog("At this point, the Riven Demo would\n"
+ GUI::MessageDialog dialog(_("At this point, the Riven Demo would\n"
"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.");
+ "the site no longer exists."));
dialog.runModal();
}
@@ -2429,7 +2430,7 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
_vm->_system->updateScreen();
- _vm->_sound->playSoundBlocking(13);
+ _vm->_sound->playSound(13);
}
} else {
// We're not at the bottom, and we can move down again
@@ -2463,7 +2464,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
_vm->_system->updateScreen();
- _vm->_sound->playSoundBlocking(13);
+ _vm->_sound->playSound(13);
return;
}
diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp
index b44fbb828e..b583bc9710 100644
--- a/engines/mohawk/riven_graphics.cpp
+++ b/engines/mohawk/riven_graphics.cpp
@@ -23,6 +23,7 @@
#include "mohawk/resource.h"
#include "mohawk/riven.h"
#include "mohawk/riven_graphics.h"
+#include "mohawk/riven_sound.h"
#include "common/system.h"
#include "engines/util.h"
@@ -51,6 +52,8 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm
_creditsImage = 302;
_creditsPos = 0;
+
+ _transitionSpeed = 0;
}
RivenGraphics::~RivenGraphics() {
@@ -109,6 +112,7 @@ void RivenGraphics::drawPLST(uint16 x) {
void RivenGraphics::updateScreen(Common::Rect updateRect) {
if (_updatesEnabled) {
_vm->runUpdateScreenScript();
+ _vm->_sound->triggerDrawSound();
if (_dirtyScreen) {
_activatedPLSTs.clear();
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 6af66f7a2d..755f87767d 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -24,25 +24,141 @@
#include "mohawk/riven.h"
#include "mohawk/riven_saveload.h"
-#include "common/util.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
namespace Mohawk {
+RivenSaveMetadata::RivenSaveMetadata() {
+ saveDay = 0;
+ saveMonth = 0;
+ saveYear = 0;
+ saveHour = 0;
+ saveMinute = 0;
+ totalPlayTime = 0;
+}
+
+bool RivenSaveMetadata::sync(Common::Serializer &s) {
+ static const Common::Serializer::Version kCurrentVersion = 1;
+
+ if (!s.syncVersion(kCurrentVersion)) {
+ return false;
+ }
+
+ s.syncAsByte(saveDay);
+ s.syncAsByte(saveMonth);
+ s.syncAsUint16BE(saveYear);
+ s.syncAsByte(saveHour);
+ s.syncAsByte(saveMinute);
+ s.syncString(saveDescription);
+ s.syncAsUint32BE(totalPlayTime);
+
+ return true;
+}
+
RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
}
RivenSaveLoad::~RivenSaveLoad() {
}
-Common::StringArray RivenSaveLoad::generateSaveGameList() {
- return _saveFileMan->listSavefiles("*.rvn");
+Common::String RivenSaveLoad::buildSaveFilename(const int slot) {
+ return Common::String::format("riven-%03d.rvn", slot);
+}
+
+Common::String RivenSaveLoad::querySaveDescription(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return "";
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return "";
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return "";
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return "";
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return "";
+ }
+
+ delete metaStream;
+
+ return metadata.saveDescription;
}
-Common::Error RivenSaveLoad::loadGame(Common::String filename) {
+SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return SaveStateDescriptor();
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return SaveStateDescriptor();
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return SaveStateDescriptor();
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return SaveStateDescriptor();
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return SaveStateDescriptor();
+ }
+
+ SaveStateDescriptor descriptor;
+ descriptor.setDescription(metadata.saveDescription);
+ descriptor.setPlayTime(metadata.totalPlayTime);
+ descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
+ descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute);
+
+ delete metaStream;
+
+ if (!mhk.hasResource(ID_THMB, 1)) {
+ return descriptor;
+ }
+
+ Common::SeekableReadStream *thmbStream = mhk.getResource(ID_THMB, 1);
+ if (!thmbStream) {
+ return descriptor;
+ }
+
+ descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream));
+
+ delete thmbStream;
+
+ return descriptor;
+}
+
+Common::Error RivenSaveLoad::loadGame(const int slot) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
- Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile)
return Common::kReadingFailed;
@@ -72,8 +188,11 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
Common::Array<uint32> rawVariables;
while (!vars->eos()) {
- vars->readUint32BE(); // Unknown (Stack?)
- vars->readUint32BE(); // Unknown (0 or 1)
+ // The original engine stores the variables values in an array. All the slots in
+ // the array may not be in use, which is why it needs a reference counter and
+ // a flag to tell if the value has been set.
+ vars->readUint32BE(); // Reference counter
+ vars->readUint32BE(); // Variable initialized flag
rawVariables.push_back(vars->readUint32BE());
}
@@ -144,6 +263,20 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
}
delete zips;
+
+ // Load the ScummVM specific save metadata
+ if (mhk->hasResource(ID_META, 1)) {
+ Common::SeekableReadStream *metadataStream = mhk->getResource(ID_META, 1);
+ Common::Serializer serializer = Common::Serializer(metadataStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ metadata.sync(serializer);
+
+ // Set the saved total play time
+ _vm->setTotalPlayTime(metadata.totalPlayTime);
+
+ delete metadataStream;
+ }
delete mhk;
return Common::kNoError;
@@ -162,14 +295,18 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVARSSection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
- stream->writeUint32BE(0); // Unknown
- stream->writeUint32BE(0); // Unknown
+ stream->writeUint32BE(1); // Reference counter
+ stream->writeUint32BE(1); // Variable initialized flag
stream->writeUint32BE(it->_value);
}
return stream;
}
+static int stringCompareToIgnoreCase(const Common::String &s1, const Common::String &s2) {
+ return s1.compareToIgnoreCase(s2) < 0;
+}
+
Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
@@ -181,8 +318,28 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
curPos += it->_key.size() + 1;
}
- for (uint16 i = 0; i < _vm->_vars.size(); i++)
- stream->writeUint16BE(i);
+ // The original engine does not store the variables in a HashMap, but in a "NameList"
+ // for the keys and an array for the values. The NameList data structure maintains an array
+ // of indices in the string table sorted by case insensitive key alphabetical order.
+ // It is used to perform fast key -> index lookups.
+ // ScummVM does not need the sorted array, but has to write it anyway for the saved games
+ // to be compatible with original engine.
+ Common::Array<Common::String> sortedKeys;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ sortedKeys.push_back(it->_key);
+ }
+ Common::sort(sortedKeys.begin(), sortedKeys.end(), stringCompareToIgnoreCase);
+
+ for (uint i = 0; i < sortedKeys.size(); i++) {
+ uint16 varIndex = 0;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ if (it->_key == sortedKeys[i]) {
+ stream->writeUint16BE(varIndex);
+ break;
+ }
+ varIndex++;
+ }
+ }
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
stream->write(it->_key.c_str(), it->_key.size());
@@ -206,7 +363,35 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genZIPSSection() {
return stream;
}
-Common::Error RivenSaveLoad::saveGame(Common::String filename) {
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+
+ Graphics::saveThumbnail(*stream);
+
+ return stream;
+}
+
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+ Common::Serializer serializer = Common::Serializer(nullptr, stream);
+
+ TimeDate t;
+ _vm->_system->getTimeAndDate(t);
+
+ RivenSaveMetadata metadata;
+ metadata.saveDay = t.tm_mday;
+ metadata.saveMonth = t.tm_mon + 1;
+ metadata.saveYear = t.tm_year + 1900;
+ metadata.saveHour = t.tm_hour;
+ metadata.saveMinute = t.tm_min;
+ metadata.saveDescription = desc;
+ metadata.totalPlayTime = _vm->getTotalPlayTime();
+ metadata.sync(serializer);
+
+ return stream;
+}
+
+Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
// (as of right now) this is the only place in the engine
@@ -214,13 +399,7 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// games need this, we should think about coming up with some
// more common way of outputting resources to an archive.
- // TODO: Make these saves work with the original interpreter.
- // Not sure why they don't work yet (they still can be loaded
- // by ScummVM).
-
- // Make sure we have the right extension
- if (!filename.matchString("*.rvn", true))
- filename += ".rvn";
+ Common::String filename = buildSaveFilename(slot);
// Convert class variables to variable numbers
_vm->_vars["currentstackid"] = _vm->getCurStack();
@@ -232,16 +411,20 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
debug (0, "Saving game to \'%s\'", filename.c_str());
- Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
+ Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
+ Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();
+ Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
Common::MemoryWriteStreamDynamic *zipsSection = genZIPSSection();
// Let's calculate the file size!
- uint32 fileSize = 142;
- fileSize += versSection->size();
+ uint32 fileSize = 194;
+ fileSize += metaSection->size();
fileSize += nameSection->size();
+ fileSize += thmbSection->size();
fileSize += varsSection->size();
+ fileSize += versSection->size();
fileSize += zipsSection->size();
// MHWK Header (8 bytes - total: 8)
@@ -254,109 +437,151 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
saveFile->writeUint16BE(1); // Compaction -- original saves have this too
saveFile->writeUint32BE(fileSize); // Subtract off the MHWK header size
saveFile->writeUint32BE(28); // Absolute offset: right after both headers
- saveFile->writeUint16BE(70); // File Table Offset
- saveFile->writeUint16BE(44); // File Table Size (4 bytes count + 4 entries * 10 bytes per entry)
+ saveFile->writeUint16BE(102); // File Table Offset
+ saveFile->writeUint16BE(64); // File Table Size (4 bytes count + 6 entries * 10 bytes per entry)
// Type Table (4 bytes - total: 32)
- saveFile->writeUint16BE(36); // String table offset After the Type Table Entries
- saveFile->writeUint16BE(4); // 4 Type Table Entries
+ saveFile->writeUint16BE(52); // String table offset After the Type Table Entries
+ saveFile->writeUint16BE(6); // 6 Type Table Entries
- // Hardcode Entries (32 bytes - total: 64)
- saveFile->writeUint32BE(ID_VERS);
- saveFile->writeUint16BE(46); // Resource table offset
- saveFile->writeUint16BE(38); // String table offset
+ // Hardcode Entries (48 bytes - total: 80)
+ // The original engine relies on the entries being sorted by tag alphabetical order
+ // to optimize its lookup algorithm.
+ saveFile->writeUint32BE(ID_META);
+ saveFile->writeUint16BE(66); // Resource table offset
+ saveFile->writeUint16BE(54); // String table offset
saveFile->writeUint32BE(ID_NAME);
- saveFile->writeUint16BE(52);
- saveFile->writeUint16BE(40);
+ saveFile->writeUint16BE(72);
+ saveFile->writeUint16BE(56);
- saveFile->writeUint32BE(ID_VARS);
+ saveFile->writeUint32BE(ID_THMB);
+ saveFile->writeUint16BE(78);
saveFile->writeUint16BE(58);
- saveFile->writeUint16BE(42);
+
+ saveFile->writeUint32BE(ID_VARS);
+ saveFile->writeUint16BE(84);
+ saveFile->writeUint16BE(60);
+
+ saveFile->writeUint32BE(ID_VERS);
+ saveFile->writeUint16BE(90);
+ saveFile->writeUint16BE(62);
saveFile->writeUint32BE(ID_ZIPS);
+ saveFile->writeUint16BE(96);
saveFile->writeUint16BE(64);
- saveFile->writeUint16BE(44);
- // Pseudo-String Table (2 bytes - total: 66)
+ // Pseudo-String Table (2 bytes - total: 82)
saveFile->writeUint16BE(0); // We don't need a name list
- // Psuedo-Name Tables (8 bytes - total: 74)
+ // Pseudo-Name Tables (12 bytes - total: 94)
+ saveFile->writeUint16BE(0);
+ saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
- // VERS Section (Resource Table) (6 bytes - total: 80)
+ // META Section (Resource Table) (6 bytes - total: 100)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
- // NAME Section (Resource Table) (6 bytes - total: 86)
+ // NAME Section (Resource Table) (6 bytes - total: 106)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(2);
- // VARS Section (Resource Table) (6 bytes - total: 92)
+ // THMB Section (Resource Table) (6 bytes - total: 112)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(3);
- // ZIPS Section (Resource Table) (6 bytes - total: 98)
+ // VARS Section (Resource Table) (6 bytes - total: 118)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(4);
- // File Table (4 bytes - total: 102)
- saveFile->writeUint32BE(4);
+ // VERS Section (Resource Table) (6 bytes - total: 124)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(5);
- // VERS Section (File Table) (10 bytes - total: 112)
- saveFile->writeUint32BE(142);
- saveFile->writeUint16BE(versSection->size() & 0xFFFF);
- saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
+ // ZIPS Section (Resource Table) (6 bytes - total: 130)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(6);
+
+ // File Table (4 bytes - total: 134)
+ saveFile->writeUint32BE(6);
+
+ // META Section (File Table) (10 bytes - total: 144)
+ saveFile->writeUint32BE(194);
+ saveFile->writeUint16BE(metaSection->size() & 0xFFFF);
+ saveFile->writeByte((metaSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // NAME Section (File Table) (10 bytes - total: 122)
- saveFile->writeUint32BE(142 + versSection->size());
+ // NAME Section (File Table) (10 bytes - total: 154)
+ saveFile->writeUint32BE(194 + metaSection->size());
saveFile->writeUint16BE(nameSection->size() & 0xFFFF);
saveFile->writeByte((nameSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // VARS Section (File Table) (10 bytes - total: 132)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size());
+ // THMB Section (File Table) (10 bytes - total: 164)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size());
+ saveFile->writeUint16BE(thmbSection->size() & 0xFFFF);
+ saveFile->writeByte((thmbSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // VARS Section (File Table) (10 bytes - total: 174)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size());
saveFile->writeUint16BE(varsSection->size() & 0xFFFF);
saveFile->writeByte((varsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // ZIPS Section (File Table) (10 bytes - total: 142)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size() + varsSection->size());
+ // VERS Section (File Table) (10 bytes - total: 184)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size());
+ saveFile->writeUint16BE(versSection->size() & 0xFFFF);
+ saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // ZIPS Section (File Table) (10 bytes - total: 194)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size() + versSection->size());
saveFile->writeUint16BE(zipsSection->size() & 0xFFFF);
saveFile->writeByte((zipsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- saveFile->write(versSection->getData(), versSection->size());
+ saveFile->write(metaSection->getData(), metaSection->size());
saveFile->write(nameSection->getData(), nameSection->size());
+ saveFile->write(thmbSection->getData(), thmbSection->size());
saveFile->write(varsSection->getData(), varsSection->size());
+ saveFile->write(versSection->getData(), versSection->size());
saveFile->write(zipsSection->getData(), zipsSection->size());
saveFile->finalize();
delete saveFile;
- delete versSection;
+ delete metaSection;
delete nameSection;
+ delete thmbSection;
delete varsSection;
+ delete versSection;
delete zipsSection;
return Common::kNoError;
}
-void RivenSaveLoad::deleteSave(Common::String saveName) {
- debug (0, "Deleting save file \'%s\'", saveName.c_str());
- _saveFileMan->removeSavefile(saveName);
+void RivenSaveLoad::deleteSave(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+
+ debug (0, "Deleting save file \'%s\'", filename.c_str());
+ g_system->getSavefileManager()->removeSavefile(filename);
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h
index a6ddce5713..34bfbdc434 100644
--- a/engines/mohawk/riven_saveload.h
+++ b/engines/mohawk/riven_saveload.h
@@ -23,10 +23,13 @@
#ifndef MOHAWK_SAVELOAD_H
#define MOHAWK_SAVELOAD_H
+#include "common/serializer.h"
#include "common/savefile.h"
#include "common/str.h"
#include "common/memstream.h"
+#include "engines/savestate.h"
+
namespace Mohawk {
class MohawkEngine_Riven;
@@ -36,23 +39,45 @@ enum {
kDVDSaveGameVersion = 0x00010100
};
+struct RivenSaveMetadata {
+ uint8 saveDay;
+ uint8 saveMonth;
+ uint16 saveYear;
+
+ uint8 saveHour;
+ uint8 saveMinute;
+
+ uint32 totalPlayTime;
+
+ Common::String saveDescription;
+
+ RivenSaveMetadata();
+ bool sync(Common::Serializer &s);
+};
+
class RivenSaveLoad {
public:
RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*);
~RivenSaveLoad();
- Common::StringArray generateSaveGameList();
- Common::Error loadGame(Common::String);
- Common::Error saveGame(Common::String);
- void deleteSave(Common::String);
+ Common::Error loadGame(const int slot);
+ Common::Error saveGame(const int slot, const Common::String &description);
+ static void deleteSave(const int slot);
+
+ static SaveStateDescriptor querySaveMetaInfos(const int slot);
+ static Common::String querySaveDescription(const int slot);
private:
MohawkEngine_Riven *_vm;
Common::SaveFileManager *_saveFileMan;
- Common::MemoryWriteStreamDynamic *genVERSSection();
+ static Common::String buildSaveFilename(const int slot);
+
Common::MemoryWriteStreamDynamic *genNAMESection();
+ Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const;
+ Common::MemoryWriteStreamDynamic *genTHMBSection() const;
Common::MemoryWriteStreamDynamic *genVARSSection();
+ Common::MemoryWriteStreamDynamic *genVERSSection();
Common::MemoryWriteStreamDynamic *genZIPSSection();
};
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index caa235ec8b..3655452603 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -25,7 +25,7 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_graphics.h"
#include "mohawk/riven_scripts.h"
-#include "mohawk/sound.h"
+#include "mohawk/riven_sound.h"
#include "mohawk/video.h"
#include "common/memstream.h"
@@ -309,54 +309,44 @@ void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) {
// Command 3: play an SLST from the script
void RivenScript::playScriptSLST(uint16 op, uint16 argc, uint16 *argv) {
- SLSTRecord slstRecord;
int offset = 0, j = 0;
+ uint16 soundCount = argv[offset++];
+ SLSTRecord slstRecord;
slstRecord.index = 0; // not set by the scripts, so we set it to 0
- slstRecord.sound_count = argv[0];
- slstRecord.sound_ids = new uint16[slstRecord.sound_count];
-
- offset = slstRecord.sound_count;
+ slstRecord.soundIds.resize(soundCount);
- for (j = 0; j < slstRecord.sound_count; j++)
- slstRecord.sound_ids[j] = argv[offset++];
- slstRecord.fade_flags = argv[offset++];
+ for (j = 0; j < soundCount; j++)
+ slstRecord.soundIds[j] = argv[offset++];
+ slstRecord.fadeFlags = argv[offset++];
slstRecord.loop = argv[offset++];
- slstRecord.global_volume = argv[offset++];
+ slstRecord.globalVolume = argv[offset++];
slstRecord.u0 = argv[offset++];
- slstRecord.u1 = argv[offset++];
+ slstRecord.suspend = argv[offset++];
- slstRecord.volumes = new uint16[slstRecord.sound_count];
- slstRecord.balances = new int16[slstRecord.sound_count];
- slstRecord.u2 = new uint16[slstRecord.sound_count];
+ slstRecord.volumes.resize(soundCount);
+ slstRecord.balances.resize(soundCount);
+ slstRecord.u2.resize(soundCount);
- for (j = 0; j < slstRecord.sound_count; j++)
+ for (j = 0; j < soundCount; j++)
slstRecord.volumes[j] = argv[offset++];
- for (j = 0; j < slstRecord.sound_count; j++)
+ for (j = 0; j < soundCount; j++)
slstRecord.balances[j] = argv[offset++]; // negative = left, 0 = center, positive = right
- for (j = 0; j < slstRecord.sound_count; j++)
+ for (j = 0; j < soundCount; j++)
slstRecord.u2[j] = argv[offset++]; // Unknown
// Play the requested sound list
_vm->_sound->playSLST(slstRecord);
- _vm->_activatedSLST = true;
-
- delete[] slstRecord.sound_ids;
- delete[] slstRecord.volumes;
- delete[] slstRecord.balances;
- delete[] slstRecord.u2;
}
// Command 4: play local tWAV resource (twav_id, volume, block)
void RivenScript::playSound(uint16 op, uint16 argc, uint16 *argv) {
- byte volume = Sound::convertRivenVolume(argv[1]);
+ uint16 volume = argv[1];
+ bool playOnDraw = argv[2] == 1;
- if (argv[2] == 1)
- _vm->_sound->playSoundBlocking(argv[0], volume);
- else
- _vm->_sound->playSound(argv[0], volume);
+ _vm->_sound->playSound(argv[0], volume, playOnDraw);
}
// Command 7: set variable value (variable, value)
diff --git a/engines/mohawk/riven_sound.cpp b/engines/mohawk/riven_sound.cpp
new file mode 100644
index 0000000000..10a23a0719
--- /dev/null
+++ b/engines/mohawk/riven_sound.cpp
@@ -0,0 +1,459 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/system.h"
+
+#include "audio/audiostream.h"
+
+#include "mohawk/riven_sound.h"
+#include "mohawk/sound.h"
+
+namespace Mohawk {
+
+RivenSoundManager::RivenSoundManager(MohawkEngine *vm) :
+ _vm(vm),
+ _effect(nullptr),
+ _mainAmbientSoundId(-1),
+ _effectPlayOnDraw(false),
+ _nextFadeUpdate(0) {
+
+}
+
+RivenSoundManager::~RivenSoundManager() {
+ stopSound();
+ stopAllSLST(false);
+}
+
+Audio::RewindableAudioStream *RivenSoundManager::makeAudioStream(uint16 id) {
+ return makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
+}
+
+void RivenSoundManager::playSound(uint16 id, uint16 volume, bool playOnDraw) {
+ debug (0, "Playing sound %d", id);
+
+ stopSound();
+
+ Audio::RewindableAudioStream *rewindStream = makeAudioStream(id);
+ if (!rewindStream) {
+ warning("Unable to play sound with id %d", id);
+ return;
+ }
+
+ _effect = new RivenSound(_vm, rewindStream);
+ _effect->setVolume(volume);
+
+ _effectPlayOnDraw = playOnDraw;
+ if (!playOnDraw) {
+ _effect->play();
+ }
+}
+
+void RivenSoundManager::playSLST(uint16 index, uint16 card) {
+ Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card);
+
+ uint16 recordCount = slstStream->readUint16BE();
+
+ for (uint16 i = 0; i < recordCount; i++) {
+ SLSTRecord slstRecord;
+ slstRecord.index = slstStream->readUint16BE();
+
+ uint16 soundCount = slstStream->readUint16BE();
+ slstRecord.soundIds.resize(soundCount);
+
+ for (uint16 j = 0; j < soundCount; j++)
+ slstRecord.soundIds[j] = slstStream->readUint16BE();
+
+ slstRecord.fadeFlags = slstStream->readUint16BE();
+ slstRecord.loop = slstStream->readUint16BE();
+ slstRecord.globalVolume = slstStream->readUint16BE();
+ slstRecord.u0 = slstStream->readUint16BE(); // Unknown
+
+ if (slstRecord.u0 > 1)
+ warning("slstRecord.u0: %d non-boolean", slstRecord.u0);
+
+ slstRecord.suspend = slstStream->readUint16BE();
+
+ if (slstRecord.suspend != 0)
+ warning("slstRecord.u1: %d non-zero", slstRecord.suspend);
+
+ slstRecord.volumes.resize(soundCount);
+ slstRecord.balances.resize(soundCount);
+ slstRecord.u2.resize(soundCount);
+
+ for (uint16 j = 0; j < soundCount; j++)
+ slstRecord.volumes[j] = slstStream->readUint16BE();
+
+ for (uint16 j = 0; j < soundCount; j++)
+ slstRecord.balances[j] = slstStream->readSint16BE(); // negative = left, 0 = center, positive = right
+
+ for (uint16 j = 0; j < soundCount; j++) {
+ slstRecord.u2[j] = slstStream->readUint16BE(); // Unknown
+
+ if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256)
+ warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]);
+ }
+
+ if (slstRecord.index == index) {
+ playSLST(slstRecord);
+ delete slstStream;
+ return;
+ }
+ }
+
+ delete slstStream;
+
+ // If we have no matching entries, we do nothing and just let
+ // the previous ambient sounds continue.
+}
+
+void RivenSoundManager::playSLST(const SLSTRecord &slstRecord) {
+ if (slstRecord.soundIds.empty()) {
+ return;
+ }
+
+ if (slstRecord.soundIds[0] == _mainAmbientSoundId) {
+ if (slstRecord.soundIds.size() > _ambientSounds.sounds.size()) {
+ addAmbientSounds(slstRecord);
+ }
+ setAmbientLooping(slstRecord.loop);
+ setTargetVolumes(slstRecord);
+ _ambientSounds.suspend = slstRecord.suspend;
+ if (slstRecord.suspend) {
+ freePreviousAmbientSounds();
+ pauseAmbientSounds();
+ applyTargetVolumes();
+ } else {
+ playAmbientSounds();
+ }
+ } else {
+ _mainAmbientSoundId = slstRecord.soundIds[0];
+ freePreviousAmbientSounds();
+ moveAmbientSoundsToPreviousSounds();
+ addAmbientSounds(slstRecord);
+ setAmbientLooping(slstRecord.loop);
+ setTargetVolumes(slstRecord);
+ _ambientSounds.suspend = slstRecord.suspend;
+ if (slstRecord.suspend) {
+ freePreviousAmbientSounds();
+ applyTargetVolumes();
+ } else {
+ startFadingAmbientSounds(slstRecord.fadeFlags);
+ }
+ }
+}
+
+void RivenSoundManager::stopAllSLST(bool fade) {
+ _mainAmbientSoundId = -1;
+ freePreviousAmbientSounds();
+ moveAmbientSoundsToPreviousSounds();
+ startFadingAmbientSounds(fade ? kFadeOutPreviousSounds : 0);
+}
+
+void RivenSoundManager::stopSound() {
+ if (_effect) {
+ delete _effect;
+ }
+ _effect = nullptr;
+ _effectPlayOnDraw = false;
+}
+
+void RivenSoundManager::addAmbientSounds(const SLSTRecord &record) {
+ if (record.soundIds.size() > _ambientSounds.sounds.size()) {
+ uint oldSize = _ambientSounds.sounds.size();
+
+ // Resize the list to the new size
+ _ambientSounds.sounds.resize(record.soundIds.size());
+
+ // Add new elements to the list
+ for (uint i = oldSize; i < _ambientSounds.sounds.size(); i++) {
+ Audio::RewindableAudioStream *stream = makeAudioStream(record.soundIds[i]);
+
+ RivenSound *sound = new RivenSound(_vm, stream);
+ sound->setVolume(record.volumes[i]);
+ sound->setBalance(record.balances[i]);
+
+ _ambientSounds.sounds[i].sound = sound;
+ _ambientSounds.sounds[i].targetVolume = record.volumes[i];
+ _ambientSounds.sounds[i].targetBalance = record.balances[i];
+ }
+ }
+}
+
+void RivenSoundManager::setTargetVolumes(const SLSTRecord &record) {
+ for (uint i = 0; i < record.volumes.size(); i++) {
+ _ambientSounds.sounds[i].targetVolume = record.volumes[i] * record.globalVolume / 256;
+ _ambientSounds.sounds[i].targetBalance = record.balances[i];
+ }
+ _ambientSounds.fading = true;
+}
+
+void RivenSoundManager::freePreviousAmbientSounds() {
+ for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) {
+ delete _previousAmbientSounds.sounds[i].sound;
+ }
+ _previousAmbientSounds = AmbientSoundList();
+}
+
+void RivenSoundManager::moveAmbientSoundsToPreviousSounds() {
+ _previousAmbientSounds = _ambientSounds;
+ _ambientSounds = AmbientSoundList();
+}
+
+void RivenSoundManager::applyTargetVolumes() {
+ for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+ AmbientSound &ambientSound = _ambientSounds.sounds[i];
+ RivenSound *sound = ambientSound.sound;
+ sound->setVolume(ambientSound.targetVolume);
+ sound->setBalance(ambientSound.targetBalance);
+ }
+ _ambientSounds.fading = false;
+}
+
+void RivenSoundManager::startFadingAmbientSounds(uint16 flags) {
+ for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+ AmbientSound &ambientSound = _ambientSounds.sounds[i];
+ uint16 volume;
+ if (flags & kFadeInNewSounds) {
+ volume = 0;
+ } else {
+ volume = ambientSound.targetVolume;
+ }
+ ambientSound.sound->setVolume(volume);
+ }
+ _ambientSounds.fading = true;
+ playAmbientSounds();
+
+ if (!_previousAmbientSounds.sounds.empty()) {
+ if (flags) {
+ _previousAmbientSounds.fading = true;
+ } else {
+ freePreviousAmbientSounds();
+ }
+
+ for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) {
+ AmbientSound &ambientSound = _previousAmbientSounds.sounds[i];
+ if (flags & kFadeOutPreviousSounds) {
+ ambientSound.targetVolume = 0;
+ } else {
+ ambientSound.sound->setVolume(ambientSound.targetVolume);
+ }
+ }
+ }
+}
+
+void RivenSoundManager::playAmbientSounds() {
+ for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+ _ambientSounds.sounds[i].sound->play();
+ }
+}
+
+void RivenSoundManager::setAmbientLooping(bool loop) {
+ for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+ _ambientSounds.sounds[i].sound->setLooping(loop);
+ }
+}
+
+void RivenSoundManager::triggerDrawSound() {
+ if (_effectPlayOnDraw && _effect) {
+ _effect->play();
+ }
+ _effectPlayOnDraw = false;
+}
+
+void RivenSoundManager::pauseAmbientSounds() {
+ for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+ _ambientSounds.sounds[i].sound->pause();
+ }
+}
+
+void RivenSoundManager::updateSLST() {
+ uint32 time = _vm->_system->getMillis();
+ int32 delta = CLIP<int32>(time - _nextFadeUpdate, -50, 50);
+ if (_nextFadeUpdate == 0 || delta > 0) {
+ _nextFadeUpdate = time + 50 - delta;
+
+ if (_ambientSounds.fading) {
+ fadeAmbientSoundList(_ambientSounds);
+ }
+
+ if (_previousAmbientSounds.fading) {
+ fadeAmbientSoundList(_previousAmbientSounds);
+ }
+
+ if (!_previousAmbientSounds.sounds.empty() && !_ambientSounds.fading && !_previousAmbientSounds.fading) {
+ freePreviousAmbientSounds();
+ }
+ }
+}
+
+void RivenSoundManager::fadeAmbientSoundList(AmbientSoundList &list) {
+ list.fading = false;
+
+ for (uint i = 0; i < list.sounds.size(); i++) {
+ AmbientSound &ambientSound = list.sounds[i];
+ list.fading |= fadeVolume(ambientSound);
+ list.fading |= fadeBalance(ambientSound);
+ }
+}
+
+bool RivenSoundManager::fadeVolume(AmbientSound &ambientSound) {
+ uint16 volume = ambientSound.sound->getVolume();
+ float delta = (ambientSound.targetVolume - volume) / 30.0f;
+
+ if (ABS<float>(delta) < 0.01f) {
+ ambientSound.sound->setVolume(ambientSound.targetVolume);
+ return false;
+ } else {
+ // Make sure the increment is not zero once converted to an integer
+ if (delta > 0 && delta < 1) {
+ delta = 1;
+ } else if (delta < 0 && delta > -1) {
+ delta = -1;
+ }
+
+ ambientSound.sound->setVolume(volume + delta);
+ return true;
+ }
+}
+
+bool RivenSoundManager::fadeBalance(RivenSoundManager::AmbientSound &ambientSound) {
+ int16 balance = ambientSound.sound->getBalance();
+ float delta = (ambientSound.targetBalance - balance) / 10.0f;
+
+ if (ABS<float>(delta) < 0.01) {
+ ambientSound.sound->setBalance(ambientSound.targetBalance);
+ return false;
+ } else {
+ // Make sure the increment is not zero once converted to an integer
+ if (delta > 0 && delta < 1) {
+ delta = 1;
+ } else if (delta < 0 && delta > -1) {
+ delta = -1;
+ }
+
+ ambientSound.sound->setBalance(balance + delta);
+ return true;
+ }
+}
+
+RivenSound::RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream) :
+ _vm(vm),
+ _volume(Audio::Mixer::kMaxChannelVolume),
+ _balance(0),
+ _looping(false),
+ _stream(rewindStream) {
+
+}
+
+bool RivenSound::isPlaying() const {
+ return _vm->_mixer->isSoundHandleActive(_handle);
+}
+
+void RivenSound::pause() {
+ _vm->_mixer->pauseHandle(_handle, true);
+}
+
+void RivenSound::setVolume(uint16 volume) {
+ _volume = volume;
+ if (isPlaying()) {
+ byte mixerVolume = convertVolume(volume);
+ _vm->_mixer->setChannelVolume(_handle, mixerVolume);
+ }
+}
+
+void RivenSound::setBalance(int16 balance) {
+ _balance = balance;
+ if (isPlaying()) {
+ int8 mixerBalance = convertBalance(balance);
+ _vm->_mixer->setChannelBalance(_handle, mixerBalance);
+ }
+}
+
+void RivenSound::setLooping(bool loop) {
+ if (isPlaying() && _looping != loop) {
+ warning("Changing loop state while a sound is playing is not implemented.");
+ }
+ _looping = loop;
+}
+
+void RivenSound::play() {
+ if (isPlaying()) {
+ // If the sound is already playing, make sure it is not paused
+ _vm->_mixer->pauseHandle(_handle, false);
+ return;
+ }
+
+ if (!_stream) {
+ warning("Trying to play a sound without a stream");
+ return;
+ }
+
+ Audio::AudioStream *playStream;
+ if (_looping) {
+ playStream = new Audio::LoopingAudioStream(_stream, 0);
+ } else {
+ playStream = _stream;
+ }
+
+ int8 mixerBalance = convertBalance(_balance);
+ byte mixerVolume = convertVolume(_volume);
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, playStream, -1, mixerVolume, mixerBalance);
+ _stream = nullptr;
+}
+
+byte RivenSound::convertVolume(uint16 volume) {
+ // The volume is a fixed point value in the Mohawk part of the original engine.
+ // It's not clear what happens when it is higher than one.
+ return (volume > 255) ? 255 : volume;
+}
+
+int8 RivenSound::convertBalance(int16 balance) {
+ return (int8)(balance >> 8);
+}
+
+RivenSound::~RivenSound() {
+ _vm->_mixer->stopHandle(_handle);
+ delete _stream;
+}
+
+int16 RivenSound::getBalance() const {
+ return _balance;
+}
+
+uint16 RivenSound::getVolume() const {
+ return _volume;
+}
+
+RivenSoundManager::AmbientSound::AmbientSound() :
+ sound(nullptr),
+ targetVolume(0),
+ targetBalance(0) {
+
+}
+
+RivenSoundManager::AmbientSoundList::AmbientSoundList() :
+ fading(false),
+ suspend(false) {
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_sound.h b/engines/mohawk/riven_sound.h
new file mode 100644
index 0000000000..c79ccc3e3a
--- /dev/null
+++ b/engines/mohawk/riven_sound.h
@@ -0,0 +1,197 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_RIVEN_SOUND_H
+#define MOHAWK_RIVEN_SOUND_H
+
+#include "common/array.h"
+#include "common/str.h"
+
+#include "audio/mixer.h"
+
+namespace Audio {
+class RewindableAudioStream;
+}
+
+namespace Mohawk {
+
+class MohawkEngine;
+class RivenSound;
+
+/**
+ * Ambient sound list
+ */
+struct SLSTRecord {
+ uint16 index;
+ Common::Array<uint16> soundIds;
+ uint16 fadeFlags;
+ uint16 loop;
+ uint16 globalVolume;
+ uint16 u0;
+ uint16 suspend;
+ Common::Array<uint16> volumes;
+ Common::Array<int16> balances;
+ Common::Array<uint16> u2;
+};
+
+/**
+ * Sound manager for Riven
+ *
+ * The sound manager can play simulteaneously:
+ * - An effect sound
+ * - A list of ambient sounds
+ *
+ * The list of ambient sounds can be cross faded
+ * with the previously running ambient sounds.
+ */
+class RivenSoundManager {
+public:
+ RivenSoundManager(MohawkEngine *vm);
+ ~RivenSoundManager();
+
+ /**
+ * Play an effect sound
+ *
+ * @param id Sound ID in the stack
+ * @param volume Playback volume, between 0 and 255
+ * @param playOnDraw Start playing when the current card is drawn instead of immediatly
+ */
+ void playSound(uint16 id, uint16 volume = 255, bool playOnDraw = false);
+
+ /** Start playing the scheduled on-draw effect sound, if any. Called by the GraphicsManager. */
+ void triggerDrawSound();
+
+ /** Stop playing the current effect sound, if any */
+ void stopSound();
+
+ /** Start playing an ambient sound list */
+ void playSLST(const SLSTRecord &slstRecord);
+
+ /** Start playing an ambient sound list from a resource */
+ void playSLST(uint16 index, uint16 card);
+
+ /** Stop playing the current ambient sounds */
+ void stopAllSLST(bool fade = false);
+
+ /** Update the ambient sounds for fading. Called once per frame. */
+ void updateSLST();
+
+private:
+ struct AmbientSound {
+ RivenSound *sound;
+ uint16 targetVolume;
+ int16 targetBalance;
+
+ AmbientSound();
+ };
+
+ struct AmbientSoundList {
+ bool fading;
+ bool suspend;
+ Common::Array<AmbientSound> sounds;
+
+ AmbientSoundList();
+ };
+
+ enum FadeFlags {
+ kFadeOutPreviousSounds = 1,
+ kFadeInNewSounds = 2
+ };
+
+ MohawkEngine *_vm;
+
+ int16 _mainAmbientSoundId;
+ AmbientSoundList _ambientSounds;
+ AmbientSoundList _previousAmbientSounds;
+ uint32 _nextFadeUpdate;
+
+ RivenSound *_effect;
+ bool _effectPlayOnDraw;
+
+ Audio::RewindableAudioStream *makeAudioStream(uint16 id);
+
+ // Ambient sound management
+ void addAmbientSounds(const SLSTRecord &record);
+ void playAmbientSounds();
+ void pauseAmbientSounds();
+ void moveAmbientSoundsToPreviousSounds();
+ void freePreviousAmbientSounds();
+
+ // Ambient sound fading
+ void setTargetVolumes(const SLSTRecord &record);
+ void applyTargetVolumes();
+ void startFadingAmbientSounds(uint16 flags);
+ void fadeAmbientSoundList(AmbientSoundList &list);
+ bool fadeVolume(AmbientSound &ambientSound);
+ bool fadeBalance(AmbientSound &ambientSound);
+ void setAmbientLooping(bool loop);
+};
+
+/**
+ * A sound used internally by the SoundManager
+ */
+class RivenSound {
+public:
+ RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream);
+ ~RivenSound();
+
+ /** Start playing the sound stream passed to the constructor */
+ void play();
+
+ /** Is the sound currently playing ar paused? */
+ bool isPlaying() const;
+
+ /** Pause the playback, the play method resumes */
+ void pause();
+
+ /** Get the current volume */
+ uint16 getVolume() const;
+
+ /** Change the playback volume */
+ void setVolume(uint16 volume);
+
+ /** Get the current balance */
+ int16 getBalance() const;
+
+ /** Change the balance */
+ void setBalance(int16 balance);
+
+ /** Set the sound to indefinitely loop. Must be called before startting the playback */
+ void setLooping(bool loop);
+
+private:
+ static byte convertVolume(uint16 volume);
+ static int8 convertBalance(int16 balance);
+
+ MohawkEngine *_vm;
+
+ Audio::SoundHandle _handle;
+ Audio::RewindableAudioStream *_stream;
+
+ uint16 _volume;
+ int16 _balance;
+ bool _looping;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index a2c08d4a92..2a54696b68 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -23,12 +23,12 @@
#include "common/debug.h"
#include "common/events.h"
#include "common/system.h"
-#include "common/util.h"
#include "common/textconsole.h"
+#include "audio/mididrv.h"
#include "audio/midiparser.h"
-#include "audio/musicplugin.h"
#include "audio/audiostream.h"
+#include "audio/decoders/adpcm.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
@@ -37,6 +37,150 @@
namespace Mohawk {
+Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
+ uint32 tag = 0;
+ ADPCMStatus adpcmStatus;
+ DataChunk dataChunk;
+ uint32 dataSize = 0;
+
+ memset(&dataChunk, 0, sizeof(DataChunk));
+
+ if (stream->readUint32BE() != ID_MHWK) // MHWK tag again
+ error ("Could not find tag 'MHWK'");
+
+ stream->readUint32BE(); // Skip size
+
+ if (stream->readUint32BE() != ID_WAVE)
+ error ("Could not find tag 'WAVE'");
+
+ while (!dataChunk.audioData) {
+ tag = stream->readUint32BE();
+
+ switch (tag) {
+ case ID_ADPC:
+ debug(2, "Found Tag ADPC");
+ // ADPCM Sound Only
+ //
+ // This is useful for seeking in the stream, and is actually quite brilliant
+ // considering some of the other things Broderbund did with the engine.
+ // Only Riven and CSTime are known to use ADPCM audio and only CSTime
+ // actually requires this for seeking. On the other hand, it may be interesting
+ // to look at that one Riven sample that uses the cue points.
+ //
+ // Basically, the sample frame from the cue list is looked up here and then
+ // sets the starting sample and step index at the point specified. Quite
+ // an elegant/efficient system, really.
+
+ adpcmStatus.size = stream->readUint32BE();
+ adpcmStatus.itemCount = stream->readUint16BE();
+ adpcmStatus.channels = stream->readUint16BE();
+ adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount];
+
+ assert(adpcmStatus.channels <= 2);
+
+ for (uint16 i = 0; i < adpcmStatus.itemCount; i++) {
+ adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE();
+
+ for (uint16 j = 0; j < adpcmStatus.channels; j++) {
+ adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE();
+ adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE();
+ }
+ }
+
+ // TODO: Actually use this chunk. For now, just delete the status items...
+ delete[] adpcmStatus.statusItems;
+ break;
+ case ID_CUE:
+ debug(2, "Found Tag Cue#");
+ // Cues are used for animation sync. There are a couple in Myst and
+ // Riven but are not used there at all.
+
+ if (!cueList) {
+ uint32 size = stream->readUint32BE();
+ stream->skip(size);
+ break;
+ }
+
+ cueList->size = stream->readUint32BE();
+ cueList->pointCount = stream->readUint16BE();
+
+ if (cueList->pointCount == 0)
+ debug(2, "Cue# chunk found with no points!");
+ else
+ debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount);
+
+ cueList->points.resize(cueList->pointCount);
+ for (uint16 i = 0; i < cueList->pointCount; i++) {
+ cueList->points[i].sampleFrame = stream->readUint32BE();
+
+ byte nameLength = stream->readByte();
+ cueList->points[i].name.clear();
+ for (byte j = 0; j < nameLength; j++)
+ cueList->points[i].name += stream->readByte();
+
+ // Realign to an even boundary
+ if (!(nameLength & 1))
+ stream->readByte();
+
+ debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str());
+ }
+ break;
+ case ID_DATA:
+ debug(2, "Found Tag DATA");
+ // We subtract 20 from the actual chunk size, which is the total size
+ // of the chunk's header
+ dataSize = stream->readUint32BE() - 20;
+ dataChunk.sampleRate = stream->readUint16BE();
+ dataChunk.sampleCount = stream->readUint32BE();
+ dataChunk.bitsPerSample = stream->readByte();
+ dataChunk.channels = stream->readByte();
+ dataChunk.encoding = stream->readUint16BE();
+ dataChunk.loopCount = stream->readUint16BE();
+ dataChunk.loopStart = stream->readUint32BE();
+ dataChunk.loopEnd = stream->readUint32BE();
+
+ // NOTE: We currently ignore all of the loop parameters here. Myst uses the
+ // loopCount variable but the loopStart and loopEnd are always 0 and the size of
+ // the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE
+ // files and therefore does not contain any of this metadata and we have to specify
+ // whether or not to loop elsewhere.
+
+ dataChunk.audioData = stream->readStream(dataSize);
+ break;
+ default:
+ error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag));
+ }
+ }
+
+ // makeMohawkWaveStream always takes control of the original stream
+ delete stream;
+
+ // The sound in Myst uses raw unsigned 8-bit data
+ // The sound in the CD version of Riven is encoded in Intel DVI ADPCM
+ // The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM
+ if (dataChunk.encoding == kCodecRaw) {
+ byte flags = Audio::FLAG_UNSIGNED;
+
+ if (dataChunk.channels == 2)
+ flags |= Audio::FLAG_STEREO;
+
+ return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
+ } else if (dataChunk.encoding == kCodecADPCM) {
+ uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
+ return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign);
+ } else if (dataChunk.encoding == kCodecMPEG2) {
+#ifdef USE_MAD
+ return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES);
+#else
+ warning ("MAD library not included - unable to play MP2 audio");
+#endif
+ } else {
+ error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding);
+ }
+
+ return nullptr;
+}
+
Sound::Sound(MohawkEngine* vm) : _vm(vm) {
_midiDriver = NULL;
_midiParser = NULL;
@@ -47,7 +191,6 @@ Sound::Sound(MohawkEngine* vm) : _vm(vm) {
Sound::~Sound() {
stopSound();
- stopAllSLST();
stopBackgroundMyst();
if (_midiParser) {
@@ -133,17 +276,6 @@ Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop, CueList
Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) {
debug (0, "Replacing sound %d", id);
- // TODO: The original engine does fading
-
- Common::String name = _vm->getResourceName(ID_MSND, convertMystID(id));
-
- // Check if sound is already playing
- for (uint32 i = 0; i < _handles.size(); i++)
- if (_handles[i].type == kUsedHandle
- && _vm->_mixer->isSoundHandleActive(_handles[i].handle)
- && name.equals(_vm->getResourceName(ID_MSND, convertMystID(_handles[i].id))))
- return &_handles[i].handle;
-
// The original engine also forces looping for those sounds
switch (id) {
case 2205:
@@ -234,300 +366,6 @@ void Sound::stopMidi() {
_midiParser->unloadMusic();
}
-byte Sound::convertRivenVolume(uint16 volume) {
- return (volume == 256) ? 255 : volume;
-}
-
-void Sound::playSLST(uint16 index, uint16 card) {
- Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card);
- SLSTRecord slstRecord;
- uint16 recordCount = slstStream->readUint16BE();
-
- for (uint16 i = 0; i < recordCount; i++) {
- slstRecord.index = slstStream->readUint16BE();
- slstRecord.sound_count = slstStream->readUint16BE();
- slstRecord.sound_ids = new uint16[slstRecord.sound_count];
-
- for (uint16 j = 0; j < slstRecord.sound_count; j++)
- slstRecord.sound_ids[j] = slstStream->readUint16BE();
-
- slstRecord.fade_flags = slstStream->readUint16BE();
- slstRecord.loop = slstStream->readUint16BE();
- slstRecord.global_volume = slstStream->readUint16BE();
- slstRecord.u0 = slstStream->readUint16BE(); // Unknown
-
- if (slstRecord.u0 > 1)
- warning("slstRecord.u0: %d non-boolean", slstRecord.u0);
-
- slstRecord.u1 = slstStream->readUint16BE(); // Unknown
-
- if (slstRecord.u1 != 0)
- warning("slstRecord.u1: %d non-zero", slstRecord.u1);
-
- slstRecord.volumes = new uint16[slstRecord.sound_count];
- slstRecord.balances = new int16[slstRecord.sound_count];
- slstRecord.u2 = new uint16[slstRecord.sound_count];
-
- for (uint16 j = 0; j < slstRecord.sound_count; j++)
- slstRecord.volumes[j] = slstStream->readUint16BE();
-
- for (uint16 j = 0; j < slstRecord.sound_count; j++)
- slstRecord.balances[j] = slstStream->readSint16BE(); // negative = left, 0 = center, positive = right
-
- for (uint16 j = 0; j < slstRecord.sound_count; j++) {
- slstRecord.u2[j] = slstStream->readUint16BE(); // Unknown
-
- if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256)
- warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]);
- }
-
- if (slstRecord.index == index) {
- playSLST(slstRecord);
- delete[] slstRecord.sound_ids;
- delete[] slstRecord.volumes;
- delete[] slstRecord.balances;
- delete[] slstRecord.u2;
- delete slstStream;
- return;
- }
-
- delete[] slstRecord.sound_ids;
- delete[] slstRecord.volumes;
- delete[] slstRecord.balances;
- delete[] slstRecord.u2;
- }
-
- delete slstStream;
-
- // If we have no matching entries, we do nothing and just let
- // the previous ambient sounds continue.
-}
-
-void Sound::playSLST(SLSTRecord slstRecord) {
- // End old sounds
- for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) {
- bool noLongerPlay = true;
- for (uint16 j = 0; j < slstRecord.sound_count; j++)
- if (_currentSLSTSounds[i].id == slstRecord.sound_ids[j])
- noLongerPlay = false;
- if (noLongerPlay)
- stopSLSTSound(i, (slstRecord.fade_flags & 1) != 0);
- }
-
- // Start new sounds
- for (uint16 i = 0; i < slstRecord.sound_count; i++) {
- bool alreadyPlaying = false;
- for (uint16 j = 0; j < _currentSLSTSounds.size(); j++) {
- if (_currentSLSTSounds[j].id == slstRecord.sound_ids[i])
- alreadyPlaying = true;
- }
- if (!alreadyPlaying) {
- playSLSTSound(slstRecord.sound_ids[i],
- (slstRecord.fade_flags & (1 << 1)) != 0,
- slstRecord.loop != 0,
- slstRecord.volumes[i],
- slstRecord.balances[i]);
- }
- }
-}
-
-void Sound::stopAllSLST(bool fade) {
- for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) {
- // TODO: Fade out, if requested
- _vm->_mixer->stopHandle(*_currentSLSTSounds[i].handle);
- delete _currentSLSTSounds[i].handle;
- }
-
- _currentSLSTSounds.clear();
-}
-
-static int8 convertBalance(int16 balance) {
- return (int8)(balance >> 8);
-}
-
-void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16 balance) {
- // WORKAROUND: Some Riven SLST entries have a volume of 0, so we just ignore them.
- if (volume == 0)
- return;
-
- SLSTSndHandle sndHandle;
- sndHandle.handle = new Audio::SoundHandle();
- sndHandle.id = id;
- _currentSLSTSounds.push_back(sndHandle);
-
- Audio::RewindableAudioStream *rewindStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
-
- // Loop here if necessary
- Audio::AudioStream *audStream = rewindStream;
- if (loop)
- audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
-
- // TODO: Handle fading, possibly just raise the volume of the channel in increments?
-
- _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, sndHandle.handle, audStream, -1, convertRivenVolume(volume), convertBalance(balance));
-}
-
-void Sound::stopSLSTSound(uint16 index, bool fade) {
- // TODO: Fade out, if requested
- _vm->_mixer->stopHandle(*_currentSLSTSounds[index].handle);
- delete _currentSLSTSounds[index].handle;
- _currentSLSTSounds.remove_at(index);
-}
-
-void Sound::pauseSLST() {
- for (uint16 i = 0; i < _currentSLSTSounds.size(); i++)
- _vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, true);
-}
-
-void Sound::resumeSLST() {
- for (uint16 i = 0; i < _currentSLSTSounds.size(); i++)
- _vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false);
-}
-
-Audio::RewindableAudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
- uint32 tag = 0;
- ADPCMStatus adpcmStatus;
- DataChunk dataChunk;
- uint32 dataSize = 0;
-
- memset(&dataChunk, 0, sizeof(DataChunk));
-
- if (stream->readUint32BE() != ID_MHWK) // MHWK tag again
- error ("Could not find tag 'MHWK'");
-
- stream->readUint32BE(); // Skip size
-
- if (stream->readUint32BE() != ID_WAVE)
- error ("Could not find tag 'WAVE'");
-
- while (!dataChunk.audioData) {
- tag = stream->readUint32BE();
-
- switch (tag) {
- case ID_ADPC:
- debug(2, "Found Tag ADPC");
- // ADPCM Sound Only
- //
- // This is useful for seeking in the stream, and is actually quite brilliant
- // considering some of the other things Broderbund did with the engine.
- // Only Riven and CSTime are known to use ADPCM audio and only CSTime
- // actually requires this for seeking. On the other hand, it may be interesting
- // to look at that one Riven sample that uses the cue points.
- //
- // Basically, the sample frame from the cue list is looked up here and then
- // sets the starting sample and step index at the point specified. Quite
- // an elegant/efficient system, really.
-
- adpcmStatus.size = stream->readUint32BE();
- adpcmStatus.itemCount = stream->readUint16BE();
- adpcmStatus.channels = stream->readUint16BE();
- adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount];
-
- assert(adpcmStatus.channels <= 2);
-
- for (uint16 i = 0; i < adpcmStatus.itemCount; i++) {
- adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE();
-
- for (uint16 j = 0; j < adpcmStatus.channels; j++) {
- adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE();
- adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE();
- }
- }
-
- // TODO: Actually use this chunk. For now, just delete the status items...
- delete[] adpcmStatus.statusItems;
- break;
- case ID_CUE:
- debug(2, "Found Tag Cue#");
- // Cues are used for animation sync. There are a couple in Myst and
- // Riven but are not used there at all.
-
- if (!cueList) {
- uint32 size = stream->readUint32BE();
- stream->skip(size);
- break;
- }
-
- cueList->size = stream->readUint32BE();
- cueList->pointCount = stream->readUint16BE();
-
- if (cueList->pointCount == 0)
- debug(2, "Cue# chunk found with no points!");
- else
- debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount);
-
- cueList->points.resize(cueList->pointCount);
- for (uint16 i = 0; i < cueList->pointCount; i++) {
- cueList->points[i].sampleFrame = stream->readUint32BE();
-
- byte nameLength = stream->readByte();
- cueList->points[i].name.clear();
- for (byte j = 0; j < nameLength; j++)
- cueList->points[i].name += stream->readByte();
-
- // Realign to an even boundary
- if (!(nameLength & 1))
- stream->readByte();
-
- debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str());
- }
- break;
- case ID_DATA:
- debug(2, "Found Tag DATA");
- // We subtract 20 from the actual chunk size, which is the total size
- // of the chunk's header
- dataSize = stream->readUint32BE() - 20;
- dataChunk.sampleRate = stream->readUint16BE();
- dataChunk.sampleCount = stream->readUint32BE();
- dataChunk.bitsPerSample = stream->readByte();
- dataChunk.channels = stream->readByte();
- dataChunk.encoding = stream->readUint16BE();
- dataChunk.loopCount = stream->readUint16BE();
- dataChunk.loopStart = stream->readUint32BE();
- dataChunk.loopEnd = stream->readUint32BE();
-
- // NOTE: We currently ignore all of the loop parameters here. Myst uses the
- // loopCount variable but the loopStart and loopEnd are always 0 and the size of
- // the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE
- // files and therefore does not contain any of this metadata and we have to specify
- // whether or not to loop elsewhere.
-
- dataChunk.audioData = stream->readStream(dataSize);
- break;
- default:
- error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag));
- }
- }
-
- // makeMohawkWaveStream always takes control of the original stream
- delete stream;
-
- // The sound in Myst uses raw unsigned 8-bit data
- // The sound in the CD version of Riven is encoded in Intel DVI ADPCM
- // The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM
- if (dataChunk.encoding == kCodecRaw) {
- byte flags = Audio::FLAG_UNSIGNED;
-
- if (dataChunk.channels == 2)
- flags |= Audio::FLAG_STEREO;
-
- return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
- } else if (dataChunk.encoding == kCodecADPCM) {
- uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
- return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign);
- } else if (dataChunk.encoding == kCodecMPEG2) {
-#ifdef USE_MAD
- return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES);
-#else
- warning ("MAD library not included - unable to play MP2 audio");
-#endif
- } else {
- error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding);
- }
-
- return NULL;
-}
-
Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
uint16 header = stream->readUint16BE();
uint16 rate = 0;
@@ -591,18 +429,6 @@ void Sound::stopSound(uint16 id) {
}
}
-void Sound::pauseSound() {
- for (uint32 i = 0; i < _handles.size(); i++)
- if (_handles[i].type == kUsedHandle)
- _vm->_mixer->pauseHandle(_handles[i].handle, true);
-}
-
-void Sound::resumeSound() {
- for (uint32 i = 0; i < _handles.size(); i++)
- if (_handles[i].type == kUsedHandle)
- _vm->_mixer->pauseHandle(_handles[i].handle, false);
-}
-
bool Sound::isPlaying(uint16 id) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle && _handles[i].id == id)
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index c62e6e9874..2b4b1ce091 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -26,9 +26,7 @@
#include "common/scummsys.h"
#include "common/str.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/decoders/adpcm.h"
#include "mohawk/mohawk.h"
#include "mohawk/resource.h"
@@ -36,24 +34,14 @@
class MidiDriver;
class MidiParser;
+namespace Audio {
+class RewindableAudioStream;
+}
+
namespace Mohawk {
#define MAX_CHANNELS 2 // Can there be more than 2?
-struct SLSTRecord {
- uint16 index;
- uint16 sound_count;
- uint16 *sound_ids;
- uint16 fade_flags;
- uint16 loop;
- uint16 global_volume;
- uint16 u0;
- uint16 u1;
- uint16 *volumes;
- int16 *balances;
- uint16 *u2;
-};
-
enum SndHandleType {
kFreeHandle,
kUsedHandle
@@ -66,11 +54,6 @@ struct SndHandle {
uint16 id;
};
-struct SLSTSndHandle {
- Audio::SoundHandle *handle;
- uint16 id;
-};
-
struct ADPCMStatus { // Holds ADPCM status data, but is irrelevant for us.
uint32 size;
uint16 itemCount;
@@ -114,6 +97,8 @@ struct DataChunk {
Common::SeekableReadStream *audioData;
};
+Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = nullptr);
+
class MohawkEngine;
class Sound {
@@ -128,8 +113,6 @@ public:
void stopMidi();
void stopSound();
void stopSound(uint16 id);
- void pauseSound();
- void resumeSound();
bool isPlaying(uint16 id);
bool isPlaying();
uint getNumSamplesPlayed(uint16 id);
@@ -142,21 +125,12 @@ public:
void stopBackgroundMyst();
void changeBackgroundVolumeMyst(uint16 vol);
- // Riven-specific sound functions
- void playSLST(uint16 index, uint16 card);
- void playSLST(SLSTRecord slstRecord);
- void pauseSLST();
- void resumeSLST();
- void stopAllSLST(bool fade = false);
- static byte convertRivenVolume(uint16 volume);
-
private:
MohawkEngine *_vm;
MidiDriver *_midiDriver;
MidiParser *_midiParser;
byte *_midiData;
- static Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = NULL);
static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
void initMidi();
@@ -167,11 +141,6 @@ private:
// Myst-specific
SndHandle _mystBackgroundSound;
-
- // Riven-specific
- void playSLSTSound(uint16 index, bool fade, bool loop, uint16 volume, int16 balance);
- void stopSLSTSound(uint16 id, bool fade);
- Common::Array<SLSTSndHandle> _currentSLSTSounds;
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 522dd5ecdd..eec543235e 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -146,7 +146,7 @@ VideoHandle::VideoHandle(const VideoHandle &handle) : _ptr(handle._ptr) {
VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
// Set dithering enabled, if required
- _enableDither = _vm->getGameType() == GType_MYST && !(_vm->getFeatures() & GF_ME);
+ _enableDither = (_vm->getGameType() == GType_MYST || _vm->getGameType() == GType_MAKINGOF) && !(_vm->getFeatures() & GF_ME);
}
VideoManager::~VideoManager() {
@@ -317,69 +317,8 @@ bool VideoManager::updateMovies() {
// Check if we need to draw a frame
if (video->needsUpdate()) {
- const Graphics::Surface *frame = video->decodeNextFrame();
- Graphics::Surface *convertedFrame = 0;
-
- if (frame && (*it)->isEnabled()) {
- Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
-
- if (frame->format != pixelFormat) {
- // We don't support downconverting to 8bpp without having
- // support in the codec. Set _enableDither if shows up.
- if (pixelFormat.bytesPerPixel == 1) {
- warning("Cannot convert high color video frame to 8bpp");
- (*it)->close();
- it = _videos.erase(it);
- continue;
- }
-
- // Convert to the current screen format
- convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
- frame = convertedFrame;
- } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) {
- // Set the palette when running in 8bpp mode only
- // Don't do this for Myst, which has its own per-stack handling
- if (_vm->getGameType() != GType_MYST)
- _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256);
- }
-
- // Clip the video to make sure it stays on the screen (Myst does this a few times)
- Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight());
- targetRect.translate((*it)->getX(), (*it)->getY());
-
- Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight());
-
- if (targetRect.left < 0) {
- frameRect.left -= targetRect.left;
- targetRect.left = 0;
- }
-
- if (targetRect.top < 0) {
- frameRect.top -= targetRect.top;
- targetRect.top = 0;
- }
-
- if (targetRect.right > _vm->_system->getWidth()) {
- frameRect.right -= targetRect.right - _vm->_system->getWidth();
- targetRect.right = _vm->_system->getWidth();
- }
-
- if (targetRect.bottom > _vm->_system->getHeight()) {
- frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight();
- targetRect.bottom = _vm->_system->getHeight();
- }
-
- _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch,
- targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
-
- // We've drawn something to the screen, make sure we update it
+ if (drawNextFrame(*it)) {
updateScreen = true;
-
- // Delete 8bpp conversion surface
- if (convertedFrame) {
- convertedFrame->free();
- delete convertedFrame;
- }
}
}
@@ -394,6 +333,74 @@ bool VideoManager::updateMovies() {
return updateScreen;
}
+bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) {
+ Video::VideoDecoder *video = videoEntry->_video;
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (!frame || !videoEntry->isEnabled()) {
+ return false;
+ }
+
+ Graphics::Surface *convertedFrame = 0;
+ Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
+
+ if (frame->format != pixelFormat) {
+ // We don't support downconverting to 8bpp without having
+ // support in the codec. Set _enableDither if shows up.
+ if (pixelFormat.bytesPerPixel == 1) {
+ warning("Cannot convert high color video frame to 8bpp");
+ return false;
+ }
+
+ // Convert to the current screen format
+ convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
+ frame = convertedFrame;
+ } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) {
+ // Set the palette when running in 8bpp mode only
+ // Don't do this for Myst, which has its own per-stack handling
+ if (_vm->getGameType() != GType_MYST)
+ _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256);
+ }
+
+ // Clip the video to make sure it stays on the screen (Myst does this a few times)
+ Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight());
+ targetRect.translate(videoEntry->getX(), videoEntry->getY());
+
+ Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight());
+
+ if (targetRect.left < 0) {
+ frameRect.left -= targetRect.left;
+ targetRect.left = 0;
+ }
+
+ if (targetRect.top < 0) {
+ frameRect.top -= targetRect.top;
+ targetRect.top = 0;
+ }
+
+ if (targetRect.right > _vm->_system->getWidth()) {
+ frameRect.right -= targetRect.right - _vm->_system->getWidth();
+ targetRect.right = _vm->_system->getWidth();
+ }
+
+ if (targetRect.bottom > _vm->_system->getHeight()) {
+ frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight();
+ targetRect.bottom = _vm->_system->getHeight();
+ }
+
+ _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch,
+ targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
+
+ // Delete 8bpp conversion surface
+ if (convertedFrame) {
+ convertedFrame->free();
+ delete convertedFrame;
+ }
+
+ // We've drawn something to the screen, make sure we update it
+ return true;
+}
+
void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
Common::SeekableReadStream *mlstStream = _vm->getResource(ID_MLST, card);
uint16 recordCount = mlstStream->readUint16BE();
@@ -582,11 +589,9 @@ bool VideoManager::isVideoPlaying() {
}
void VideoManager::drawVideoFrame(VideoHandle handle, const Audio::Timestamp &time) {
- // FIXME: This should be done separately from the "playing"
- // videos eventually.
assert(handle);
handle->seek(time);
- updateMovies();
+ drawNextFrame(handle._ptr);
handle->stop();
}
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index c5a3dc7041..e2b09b6afd 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -346,10 +346,12 @@ private:
// Utility functions for managing entries
VideoEntryPtr open(uint16 id);
VideoEntryPtr open(const Common::String &fileName);
-
+
VideoList::iterator findEntry(VideoEntryPtr ptr);
void removeEntry(VideoEntryPtr ptr);
+ bool drawNextFrame(VideoEntryPtr videoEntry);
+
// Dithering control
bool _enableDither;
void checkEnableDither(VideoEntryPtr &entry);
diff --git a/engines/mohawk/view.cpp b/engines/mohawk/view.cpp
index 1aaf32ea78..70d20270a5 100644
--- a/engines/mohawk/view.cpp
+++ b/engines/mohawk/view.cpp
@@ -37,6 +37,23 @@ Module::~Module() {
}
Feature::Feature(View *view) : _view(view) {
+ _next = _prev = nullptr;
+ _drawProc = nullptr;
+ _moveProc = nullptr;
+ _doneProc = nullptr;
+ _frameProc = nullptr;
+ _timeProc = nullptr;
+ _region = 0;
+ _id = 0;
+ _scrbId = 0;
+ _storedScrbId = 0;
+ _flags = 0;
+ _nextTime = 0;
+ _delayTime = 0;
+ _dirty = false;
+ _needsReset = false;
+ _justReset = false;
+ _done = false;
}
Feature::~Feature() {
@@ -75,11 +92,10 @@ void Feature::setNodeDefaults(Feature *prev, Feature *next) {
_flags = 0;
- _dirty = 1;
- _needsReset = 1;
- _justReset = 0; // old
- _notifyDone = 0;
- _done = 0; // new
+ _dirty = true;
+ _needsReset = true;
+ _justReset = false; // old
+ _done = false; // new
_nextTime = 0;
_delayTime = 0;
@@ -107,11 +123,11 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
resetFrame();
_nextTime = 0; // New feature code uses _view->_lastIdleTime, but should be equivalent.
_data.enabled = enabled;
- _dirty = 1;
+ _dirty = true;
finishResetFeatureScript();
- _needsReset = 0;
+ _needsReset = false;
if (_region) {
// TODO: mark _region as dirty
@@ -123,7 +139,6 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
void Feature::resetFeature(bool notifyDone, Module::FeatureProc doneProc, uint16 scrbId) {
resetFeatureScript(1, scrbId);
_doneProc = doneProc;
- _notifyDone = notifyDone;
}
void Feature::hide(bool clip) {
@@ -159,7 +174,7 @@ void Feature::moveAndUpdate(Common::Point newPos) {
return;
_nextTime = 0;
- _dirty = 1;
+ _dirty = true;
// TODO: mark _data.bounds as dirty
if (_data.bitmapIds[0])
@@ -228,7 +243,7 @@ void OldFeature::resetScript() {
}
void OldFeature::finishResetFeatureScript() {
- _justReset = 1;
+ _justReset = true;
if (_flags & kFeatureOldAdjustByPos) {
Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
@@ -240,6 +255,13 @@ void OldFeature::finishResetFeatureScript() {
}
NewFeature::NewFeature(View *view) : Feature(view) {
+ _unknown168 = 0;
+ _pickupProc = nullptr;
+ _dropProc = nullptr;
+ _dragMoveProc = nullptr;
+ _oldMoveProc = nullptr;
+ _dragFlags = 0;
+ _oldFlags = 0;
}
NewFeature::~NewFeature() {
@@ -307,7 +329,7 @@ void NewFeature::resetScript() {
}
void NewFeature::finishResetFeatureScript() {
- _done = 0;
+ _done = false;
}
View::View(MohawkEngine *vm) : _vm(vm) {
@@ -319,6 +341,12 @@ View::View(MohawkEngine *vm) : _vm(vm) {
_compoundSHAPGroups[i] = 0;
}
_numSCRBGroups = 0;
+
+ _lastIdleTime = 0;
+ _needsUpdate = false;
+ _gfx = nullptr;
+ _rootNode = nullptr;
+ _cursorNode = nullptr;
}
View::~View() {
@@ -347,7 +375,7 @@ void View::idleView() {
}
if (node->_drawProc)
(_currentModule->*(node->_drawProc))(node);
- node->_dirty = 0;
+ node->_dirty = false;
}
if (_needsUpdate) {
diff --git a/engines/mohawk/view.h b/engines/mohawk/view.h
index 47853f056f..463715b765 100644
--- a/engines/mohawk/view.h
+++ b/engines/mohawk/view.h
@@ -138,11 +138,10 @@ public:
uint32 _flags;
uint32 _nextTime;
uint32 _delayTime;
- uint16 _dirty; // byte in old
- byte _needsReset;
- byte _justReset; // old
- byte _notifyDone; // old
- byte _done; // new
+ bool _dirty; // byte in old
+ bool _needsReset;
+ bool _justReset; // old
+ bool _done; // new
FeatureData _data;
@@ -192,13 +191,6 @@ protected:
void finishResetFeatureScript();
};
-#define NUM_SYNC_CHANNELS 17
-struct SyncChannel {
- uint16 masterId;
- byte state;
- bool alternate;
-};
-
class View {
public:
View(MohawkEngine *vm);
@@ -234,7 +226,6 @@ public:
void sortView();
uint32 _lastIdleTime;
- SyncChannel _syncChannels[NUM_SYNC_CHANNELS];
virtual uint32 getTime() = 0;