aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk')
-rw-r--r--engines/mohawk/console.cpp2
-rw-r--r--engines/mohawk/cstime.h2
-rw-r--r--engines/mohawk/cursors.cpp37
-rw-r--r--engines/mohawk/detection_tables.h84
-rw-r--r--engines/mohawk/dialogs.cpp24
-rw-r--r--engines/mohawk/dialogs.h1
-rw-r--r--engines/mohawk/graphics.cpp11
-rw-r--r--engines/mohawk/graphics.h4
-rw-r--r--engines/mohawk/livingbooks.cpp65
-rw-r--r--engines/mohawk/livingbooks.h11
-rw-r--r--engines/mohawk/livingbooks_code.cpp33
-rw-r--r--engines/mohawk/livingbooks_code.h2
-rw-r--r--engines/mohawk/mohawk.cpp2
-rw-r--r--engines/mohawk/myst.cpp14
-rw-r--r--engines/mohawk/myst.h1
-rw-r--r--engines/mohawk/myst_scripts.cpp2
-rw-r--r--engines/mohawk/myst_stacks/demo.cpp98
-rw-r--r--engines/mohawk/myst_stacks/demo.h14
-rw-r--r--engines/mohawk/myst_stacks/myst.h4
-rw-r--r--engines/mohawk/myst_stacks/preview.cpp213
-rw-r--r--engines/mohawk/myst_stacks/preview.h27
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp25
-rw-r--r--engines/mohawk/myst_stacks/slides.h2
-rw-r--r--engines/mohawk/myst_state.cpp8
-rw-r--r--engines/mohawk/riven.cpp175
-rw-r--r--engines/mohawk/riven.h8
-rw-r--r--engines/mohawk/riven_external.cpp32
-rw-r--r--engines/mohawk/riven_vars.cpp8
-rw-r--r--engines/mohawk/sound.cpp7
-rw-r--r--engines/mohawk/sound.h7
30 files changed, 722 insertions, 201 deletions
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index e7dc84606c..0234c86c7e 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -117,7 +117,7 @@ static const char *mystStackNames[12] = {
static const uint16 default_start_card[12] = {
3137,
10000,
- 2001, // TODO: Should be 2000?
+ 2000,
5038,
2, // TODO: Should be 1?
1,
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index 3a1de6a137..0bc236f930 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -30,8 +30,6 @@
#include "common/random.h"
#include "common/list.h"
-#include "audio/mixer.h"
-
namespace Mohawk {
class CSTimeCase;
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index 78e099ccfe..cbd17e0b86 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -49,36 +49,13 @@ void CursorManager::hideCursor() {
}
void CursorManager::setDefaultCursor() {
- static const byte defaultCursor[] = {
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
- 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
- 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0,
- 1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0,
- 1, 2, 1, 0, 1, 1, 2, 2, 1, 0, 0, 0,
- 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
- };
-
- static const byte bwPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xFF, 0xFF, 0xFF // White
- };
-
- CursorMan.replaceCursor(defaultCursor, 12, 20, 0, 0, 0);
- CursorMan.replaceCursorPalette(bwPalette, 1, 2);
+ Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
+
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
+ cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
+
+ delete cursor;
}
void CursorManager::setCursor(uint16 id) {
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 01eac0aaba..a587d06760 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -653,6 +653,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"HARRY.EXE"
},
+ // part of "Super Living Books" compilation
+ // from rgemini, bug #3309343
+ {
+ {
+ "harryhh",
+ "",
+ AD_ENTRY1("HARRY.512", "39d11399796dfa36d3f631d2d87e8b85"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV1,
+ 0,
+ "HARRY.EXE"
+ },
+
{
{
"carmentq",
@@ -929,6 +946,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"TORTOISE.EXE"
},
+ // part of "Super Living Books" compilation
+ // from rgemini, bug #3309343
+ {
+ {
+ "tortoise",
+ "",
+ AD_ENTRY1("TORTOISE.512", "e9ec7a6bc6b451c9e85e5b4f072d5143"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV1,
+ 0,
+ "TORTOISE.EXE"
+ },
+
// From afholman in bug#3309308
{
{
@@ -1053,6 +1087,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"ARTHUR.EXE"
},
+ // part of "Super Living Books" compilation
+ // from rgemini, bug #3309343
+ {
+ {
+ "arthur",
+ "",
+ AD_ENTRY1("PAGES.512", "cd995d20d0d7b4642476fd76044b4e5b"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV1,
+ GF_LB_10,
+ "ARTHUR.EXE"
+ },
+
// From afholman in bug#3309308
{
{
@@ -1195,6 +1246,22 @@ static const MohawkGameDescription gameDescriptions[] = {
"GRANDMA.EXE"
},
+ // from jjnryan in bug #3389857
+ {
+ {
+ "grandma",
+ "v1.0",
+ AD_ENTRY1("PAGES.512", "613ca946bc8d91087fb7c10e9b84e88b"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV1,
+ GF_LB_10,
+ "GRANDMA.EXE"
+ },
+
{
{
"grandma",
@@ -1366,6 +1433,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"NEWKID.EXE"
},
+ // part of "Super Living Books" compilation
+ // from rgemini, bug #3309343
+ {
+ {
+ "newkid",
+ "",
+ AD_ENTRY1("NEWKID.512", "28a5aef3e6ef7e2ed7742485c25bdff6"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV1,
+ 0,
+ "NEWKID.EXE"
+ },
+
// From aluff in bug#3309981
{
{
diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp
index 6cb455917e..4461a30ad4 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -81,14 +81,17 @@ enum {
kTransCmd = 'TRAN',
kWaterCmd = 'WATR',
kDropCmd = 'DROP',
- kMapCmd = 'SMAP'
+ kMapCmd = 'SMAP',
+ kMenuCmd = 'MENU'
};
#ifdef ENABLE_MYST
MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) {
+ // I18N: Option for fast scene switching
_zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
_transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 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
@@ -97,6 +100,12 @@ MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog
else
_showMapButton = 0;
+ // Myst demo only has a menu
+ if (_vm->getFeatures() & GF_DEMO)
+ _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~M~ain Menu"), 0, kMenuCmd);
+ else
+ _returnToMenuButton = 0;
+
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);
}
@@ -113,6 +122,15 @@ void MystOptionsDialog::open() {
_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);
}
@@ -133,6 +151,10 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
_vm->_needsShowMap = true;
close();
break;
+ case kMenuCmd:
+ _vm->_needsShowDemoMenu = true;
+ close();
+ break;
case GUI::kCloseCmd:
close();
break;
diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h
index 853ff30813..844c01ad26 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -83,6 +83,7 @@ private:
GUI::CheckboxWidget *_transitionsCheckbox;
GUI::ButtonWidget *_dropPageButton;
GUI::ButtonWidget *_showMapButton;
+ GUI::ButtonWidget *_returnToMenuButton;
};
#endif
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index b3653b1fdf..35c9d478d8 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -672,6 +672,14 @@ void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) {
_nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay;
}
+void MystGraphics::fadeToBlack() {
+ // TODO: Implement
+}
+
+void MystGraphics::fadeFromBlack() {
+ // TODO: Implement
+}
+
#endif // ENABLE_MYST
#ifdef ENABLE_RIVEN
@@ -913,7 +921,8 @@ void RivenGraphics::clearMainScreen() {
}
void RivenGraphics::fadeToBlack() {
- // Self-explanatory
+ // The transition speed is forced to best here
+ setTransitionSpeed(kRivenTransitionSpeedBest);
scheduleTransition(16);
clearMainScreen();
runScheduledTransition();
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index d7057f48cf..96357bbff1 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -129,6 +129,8 @@ public:
void drawRect(Common::Rect rect, RectState state);
void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color);
void enableDrawingTimeSimulation(bool enable);
+ void fadeToBlack();
+ void fadeFromBlack();
protected:
MohawkSurface *decodeImage(uint16 id);
@@ -194,6 +196,7 @@ public:
void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392));
void runScheduledTransition();
void fadeToBlack();
+ void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; }
// Inventory
void showInventory();
@@ -229,6 +232,7 @@ private:
// Transitions
int16 _scheduledTransition;
Common::Rect _transitionRect;
+ uint32 _transitionSpeed;
// Inventory
void clearInventoryArea();
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index f9d18ff7ff..65073bd970 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -204,9 +204,12 @@ Common::Error MohawkEngine_LivingBooks::run() {
break;
case Common::EVENT_LBUTTONDOWN:
- for (uint16 i = 0; i < _items.size(); i++)
- if (_items[i]->contains(event.mouse))
- found = _items[i];
+ for (Common::List<LBItem *>::const_iterator i = _orderedItems.begin(); i != _orderedItems.end(); ++i) {
+ if ((*i)->contains(event.mouse)) {
+ found = *i;
+ break;
+ }
+ }
if (found)
found->handleMouseDown(event.mouse);
@@ -341,6 +344,7 @@ void MohawkEngine_LivingBooks::destroyPage() {
delete _page;
assert(_items.empty());
+ assert(_orderedItems.empty());
_page = NULL;
_notifyEvents.clear();
@@ -567,6 +571,7 @@ void MohawkEngine_LivingBooks::updatePage() {
case kLBDelayedEventDestroy:
_items.remove_at(i);
i--;
+ _orderedItems.remove(delayedEvent.item);
delete delayedEvent.item;
_page->itemDestroyed(delayedEvent.item);
if (_focus == delayedEvent.item)
@@ -613,6 +618,8 @@ void MohawkEngine_LivingBooks::removeArchive(Archive *archive) {
void MohawkEngine_LivingBooks::addItem(LBItem *item) {
_items.push_back(item);
+ _orderedItems.push_front(item);
+ item->_iterator = _orderedItems.begin();
}
void MohawkEngine_LivingBooks::removeItems(const Common::Array<LBItem *> &items) {
@@ -626,6 +633,7 @@ void MohawkEngine_LivingBooks::removeItems(const Common::Array<LBItem *> &items)
break;
}
assert(found);
+ _orderedItems.erase(items[i]->_iterator);
}
}
@@ -1319,8 +1327,13 @@ void MohawkEngine_LivingBooks::handleNotify(NotifyEvent &event) {
if (getGameType() == GType_LIVINGBOOKSV1) {
debug(2, "kLBNotifyChangeMode: %d", event.param);
quitGame();
- } else {
- debug(2, "kLBNotifyChangeMode: mode %d, page %d.%d",
+ break;
+ }
+
+ debug(2, "kLBNotifyChangeMode: v2 type %d", event.param);
+ switch (event.param) {
+ case 1:
+ debug(2, "kLBNotifyChangeMode:, mode %d, page %d.%d",
event.newMode, event.newPage, event.newSubpage);
// TODO: what is entry.newUnknown?
if (!event.newMode)
@@ -1331,6 +1344,13 @@ void MohawkEngine_LivingBooks::handleNotify(NotifyEvent &event) {
error("kLBNotifyChangeMode failed to move to mode %d, page %d.%d",
event.newMode, event.newPage, event.newSubpage);
}
+ break;
+ case 3:
+ debug(2, "kLBNotifyChangeMode: new cursor '%s'", event.newCursor.c_str());
+ _cursor->setCursor(event.newCursor);
+ break;
+ default:
+ error("unknown v2 kLBNotifyChangeMode type %d", event.param);
}
break;
@@ -2084,16 +2104,32 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Memor
}
if (type == kLBNotifyScript && entry->opcode == kLBNotifyChangeMode && _vm->getGameType() != GType_LIVINGBOOKSV1) {
- if (size < 8) {
- error("%d unknown bytes in notify entry kLBNotifyChangeMode", size);
+ switch (entry->param) {
+ case 1:
+ if (size < 8)
+ error("%d unknown bytes in notify entry kLBNotifyChangeMode", size);
+ entry->newUnknown = stream->readUint16();
+ entry->newMode = stream->readUint16();
+ entry->newPage = stream->readUint16();
+ entry->newSubpage = stream->readUint16();
+ debug(4, "kLBNotifyChangeMode: unknown %04x, mode %d, page %d.%d",
+ entry->newUnknown, entry->newMode, entry->newPage, entry->newSubpage);
+ size -= 8;
+ break;
+ case 3:
+ {
+ Common::String newCursor = _vm->readString(stream);
+ entry->newCursor = newCursor;
+ if (size < newCursor.size() + 1)
+ error("failed to read newCursor in notify entry");
+ size -= newCursor.size() + 1;
+ debug(4, "kLBNotifyChangeMode: new cursor '%s'", newCursor.c_str());
+ }
+ break;
+ default:
+ // the original engine also does something when param==2 (but not a notify)
+ error("unknown v2 kLBNotifyChangeMode type %d", entry->param);
}
- entry->newUnknown = stream->readUint16();
- entry->newMode = stream->readUint16();
- entry->newPage = stream->readUint16();
- entry->newSubpage = stream->readUint16();
- debug(4, "kLBNotifyChangeMode: unknown %04x, mode %d, page %d.%d",
- entry->newUnknown, entry->newMode, entry->newPage, entry->newSubpage);
- size -= 8;
}
if (entry->opcode == kLBOpSendExpression) {
if (size < 4)
@@ -2577,6 +2613,7 @@ void LBItem::runScript(uint event, uint16 data, uint16 from) {
notifyEvent.newMode = entry->newMode;
notifyEvent.newPage = entry->newPage;
notifyEvent.newSubpage = entry->newSubpage;
+ notifyEvent.newCursor = entry->newCursor;
_vm->addNotifyEvent(notifyEvent);
} else
_vm->addNotifyEvent(NotifyEvent(entry->opcode, entry->param));
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index ad2fe56a52..008a7dbf23 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -33,8 +33,6 @@
#include "common/queue.h"
#include "common/random.h"
-#include "audio/mixer.h"
-
#include "livingbooks_code.h"
namespace Common {
@@ -133,7 +131,9 @@ enum {
kLBEventMouseUp = 5,
kLBEventPhaseMain = 6,
kLBEventNotified = 7,
+ kLBEventDragStart = 8,
kLBEventDragMove = 9,
+ kLBEventDragEnd = 0xa,
kLBEventRolloverBegin = 0xb,
kLBEventRolloverMove = 0xc,
kLBEventRolloverEnd = 0xd,
@@ -271,6 +271,7 @@ struct LBScriptEntry {
uint16 newMode;
uint16 newPage;
uint16 newSubpage;
+ Common::String newCursor;
// kLBEventNotified
uint16 matchFrom;
@@ -405,6 +406,8 @@ public:
uint16 getSoundPriority() { return _soundMode; }
bool isAmbient() { return _isAmbient; }
+ Common::List<LBItem *>::iterator _iterator;
+
protected:
MohawkEngine_LivingBooks *_vm;
LBPage *_page;
@@ -608,6 +611,7 @@ struct NotifyEvent {
uint16 newMode;
uint16 newPage;
uint16 newSubpage;
+ Common::String newCursor;
};
enum DelayedEventType {
@@ -667,7 +671,7 @@ public:
GUI::Debugger *getDebugger() { return _console; }
void addArchive(Archive *archive);
- void removeArchive(Archive *Archive);
+ void removeArchive(Archive *archive);
void addItem(LBItem *item);
void removeItems(const Common::Array<LBItem *> &items);
@@ -714,6 +718,7 @@ private:
uint16 _phase;
LBPage *_page;
Common::Array<LBItem *> _items;
+ Common::List<LBItem *> _orderedItems;
Common::Queue<DelayedEvent> _eventQueue;
LBItem *_focus;
void destroyPage();
diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp
index e9ef2516e2..80b5fe9660 100644
--- a/engines/mohawk/livingbooks_code.cpp
+++ b/engines/mohawk/livingbooks_code.cpp
@@ -686,8 +686,8 @@ struct CodeCommandInfo {
CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = {
{ "eval", &LBCode::cmdEval },
{ "random", &LBCode::cmdRandom },
- { "stringLen", 0 },
- { "substring", 0 },
+ { "stringLen", &LBCode::cmdStringLen },
+ { "substring", &LBCode::cmdSubstring },
{ "max", 0 },
{ "min", 0 },
{ "abs", 0 },
@@ -861,6 +861,31 @@ void LBCode::cmdRandom(const Common::Array<LBValue> &params) {
_stack.push(_vm->_rnd->getRandomNumberRng(min, max));
}
+void LBCode::cmdStringLen(const Common::Array<LBValue> &params) {
+ if (params.size() != 1)
+ error("incorrect number of parameters (%d) to stringLen", params.size());
+
+ const Common::String &string = params[0].toString();
+ _stack.push(string.size());
+}
+
+void LBCode::cmdSubstring(const Common::Array<LBValue> &params) {
+ if (params.size() != 3)
+ error("incorrect number of parameters (%d) to substring", params.size());
+
+ const Common::String &string = params[0].toString();
+ uint begin = params[1].toInt();
+ uint end = params[2].toInt();
+ if (begin == 0)
+ error("invalid substring call (%d to %d)", begin, end);
+ if (begin > end || end > string.size()) {
+ _stack.push(Common::String());
+ return;
+ }
+ Common::String substring(string.c_str() + (begin - 1), end - begin + 1);
+ _stack.push(substring);
+}
+
void LBCode::cmdGetRect(const Common::Array<LBValue> &params) {
if (params.size() < 2) {
_stack.push(getRectFromParams(params));
@@ -1156,8 +1181,8 @@ bool LBCode::parseCodeSymbol(const Common::String &name, uint &pos, Common::Arra
// first, check whether the name matches a known function
for (uint i = 0; i < 2; i++) {
byte cmdToken;
- CodeCommandInfo *cmdInfo;
- uint cmdCount;
+ CodeCommandInfo *cmdInfo = NULL;
+ uint cmdCount = 0;
switch (i) {
case 0:
diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h
index 9c58ed7a46..79c9af94f7 100644
--- a/engines/mohawk/livingbooks_code.h
+++ b/engines/mohawk/livingbooks_code.h
@@ -222,6 +222,8 @@ public:
void cmdUnimplemented(const Common::Array<LBValue> &params);
void cmdEval(const Common::Array<LBValue> &params);
void cmdRandom(const Common::Array<LBValue> &params);
+ void cmdStringLen(const Common::Array<LBValue> &params);
+ void cmdSubstring(const Common::Array<LBValue> &params);
void cmdGetRect(const Common::Array<LBValue> &params);
void cmdTopLeft(const Common::Array<LBValue> &params);
void cmdBottomRight(const Common::Array<LBValue> &params);
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index faf52595b7..cb419064c0 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -31,8 +31,6 @@
#include "mohawk/sound.h"
#include "mohawk/video.h"
-#include "audio/mixer.h"
-
namespace Mohawk {
MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc) {
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 6bdf163a91..eeb4594f3c 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -343,6 +343,7 @@ Common::Error MohawkEngine_Myst::run() {
case Common::KEYCODE_F5:
_needsPageDrop = false;
_needsShowMap = false;
+ _needsShowDemoMenu = false;
runDialog(*_optionsDialog);
@@ -355,6 +356,11 @@ Common::Error MohawkEngine_Myst::run() {
_scriptParser->showMap();
_needsShowMap = false;
}
+
+ if (_needsShowDemoMenu) {
+ changeToStack(kDemoStack, 2002, 0, 0);
+ _needsShowDemoMenu = false;
+ }
break;
default:
break;
@@ -441,6 +447,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_scriptParser = new MystStacks::Credits(this);
break;
case kDemoStack:
+ _gameState->_globals.currentAge = 0;
_scriptParser = new MystStacks::Demo(this);
break;
case kDniStack:
@@ -469,6 +476,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_scriptParser = new MystStacks::Selenitic(this);
break;
case kDemoSlidesStack:
+ _gameState->_globals.currentAge = 1;
_scriptParser = new MystStacks::Slides(this);
break;
case kStoneshipStack:
@@ -645,7 +653,11 @@ void MohawkEngine_Myst::changeToCard(uint16 card, bool updateScreen) {
for (uint16 i = 0; i < _resources.size(); i++)
_resources[i]->handleCardChange();
- // TODO: Handle Script Resources
+ // The demo resets the cursor at each card change except when in the library
+ if (getFeatures() & GF_DEMO
+ && _gameState->_globals.currentAge != 2) {
+ _cursor->setDefaultCursor();
+ }
// Make sure the screen is updated
if (updateScreen) {
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index ebcc3b445c..02f0a46e3f 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -167,6 +167,7 @@ public:
bool _needsUpdate;
bool _needsPageDrop;
bool _needsShowMap;
+ bool _needsShowDemoMenu;
MystView _view;
MystGraphics *_gfx;
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index 307be2dd05..ca8e985491 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -500,7 +500,7 @@ void MystScriptParser::o_disableAreas(uint16 op, uint16 var, uint16 argc, uint16
resource = _vm->_resources[argv[i + 1]];
if (resource)
- resource->setEnabled(true);
+ resource->setEnabled(false);
else
warning("Unknown Resource in disableAreas script Opcode");
}
diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp
index 5788f4b3a3..c9e806655e 100644
--- a/engines/mohawk/myst_stacks/demo.cpp
+++ b/engines/mohawk/myst_stacks/demo.cpp
@@ -20,16 +20,20 @@
*
*/
+#include "mohawk/cursors.h"
+#include "mohawk/graphics.h"
#include "mohawk/myst.h"
#include "mohawk/myst_stacks/demo.h"
-#include "gui/message.h"
+#include "common/system.h"
namespace Mohawk {
namespace MystStacks {
Demo::Demo(MohawkEngine_Myst *vm) : Intro(vm) {
setupOpcodes();
+
+ _returnToMenuStep = 0;
}
Demo::~Demo() {
@@ -47,15 +51,12 @@ Demo::~Demo() {
void Demo::setupOpcodes() {
// "Stack-Specific" Opcodes
- OVERRIDE_OPCODE(100, opcode_100);
- OPCODE(101, opcode_101);
- OPCODE(102, opcode_102);
+ OVERRIDE_OPCODE(100, o_stopIntro);
+ OPCODE(101, o_fadeFromBlack);
+ OPCODE(102, o_fadeToBlack);
// "Init" Opcodes
- OVERRIDE_OPCODE(201, opcode_201);
-
- // "Exit" Opcodes
- OVERRIDE_OPCODE(300, opcode_300);
+ OVERRIDE_OPCODE(201, o_returnToMenu_init);
}
#undef OPCODE
@@ -64,61 +65,66 @@ void Demo::setupOpcodes() {
void Demo::disablePersistentScripts() {
Intro::disablePersistentScripts();
- _enabled201 = false;
+ _returnToMenuRunning = false;
}
void Demo::runPersistentScripts() {
Intro::runPersistentScripts();
- if (_enabled201) {
- // Used on Card 2001, 2002 and 2003
-
- // TODO: Fill in Function...
+ if (_returnToMenuRunning) {
+ returnToMenu_run();
}
}
-void Demo::opcode_100(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- // TODO: Fill in Function...
+void Demo::o_stopIntro(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Unk", op);
+ // The original also seems to stop the movies. Not needed with this engine.
+ _vm->_gfx->fadeToBlack();
}
-void Demo::opcode_101(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
-
- // Used on Card 2000, 2002 and 2003
- // Triggered by Click
- if (argc == 0) {
- // TODO: Fill in Logic.. Fade in?
- } else
- unknown(op, var, argc, argv);
+void Demo::o_fadeFromBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Fade from black", op);
+ _vm->_gfx->fadeFromBlack();
}
-void Demo::opcode_102(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
-
- // Used on Card 2002 and 2003
- // Triggered by Click
- if (argc == 0) {
- // TODO: Fill in Logic.. Fade out?
- } else
- unknown(op, var, argc, argv);
+void Demo::o_fadeToBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Fade to black", op);
+ _vm->_gfx->fadeToBlack();
}
-void Demo::opcode_201(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
-
- // Used on Card 2001, 2002 and 2003
- if (argc == 0)
- _enabled201 = true;
- else
- unknown(op, var, argc, argv);
+void Demo::returnToMenu_run() {
+ uint32 time = _vm->_system->getMillis();
+
+ if (time < _returnToMenuNextTime)
+ return;
+
+ switch (_returnToMenuStep){
+ case 0:
+ _vm->_gfx->fadeToBlack();
+ _vm->changeToCard(2003, true);
+ _vm->_gfx->fadeFromBlack();
+
+ _returnToMenuStep++;
+ break;
+ case 1:
+ _vm->_gfx->fadeToBlack();
+ _vm->changeToCard(2001, true);
+ _vm->_gfx->fadeFromBlack();
+ _vm->_cursor->showCursor();
+
+ _returnToMenuStep++;
+ break;
+ default:
+ break;
+ }
}
+void Demo::o_returnToMenu_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Return to menu init", op);
-void Demo::opcode_300(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- // Used on Card 2000
- varUnusedCheck(op, var);
-
- // TODO: Fill in Function...
+ // Used on Card 2001, 2002 and 2003
+ _returnToMenuNextTime = _vm->_system->getMillis() + 5000;
+ _returnToMenuRunning = true;
}
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h
index 4f8d68759b..c3e57cf7ae 100644
--- a/engines/mohawk/myst_stacks/demo.h
+++ b/engines/mohawk/myst_stacks/demo.h
@@ -46,15 +46,19 @@ public:
private:
void setupOpcodes();
- DECLARE_OPCODE(opcode_100);
- DECLARE_OPCODE(opcode_101);
- DECLARE_OPCODE(opcode_102);
+ DECLARE_OPCODE(o_stopIntro);
+ DECLARE_OPCODE(o_fadeFromBlack);
+ DECLARE_OPCODE(o_fadeToBlack);
- DECLARE_OPCODE(opcode_201);
+ DECLARE_OPCODE(o_returnToMenu_init);
DECLARE_OPCODE(opcode_300);
- bool _enabled201;
+ bool _returnToMenuRunning;
+ uint16 _returnToMenuStep; // 42
+ uint32 _returnToMenuNextTime; // 6
+
+ void returnToMenu_run();
};
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h
index 9510d371d7..e9bff08cb4 100644
--- a/engines/mohawk/myst_stacks/myst.h
+++ b/engines/mohawk/myst_stacks/myst.h
@@ -40,8 +40,8 @@ public:
Myst(MohawkEngine_Myst *vm);
~Myst();
- void disablePersistentScripts();
- void runPersistentScripts();
+ virtual void disablePersistentScripts();
+ virtual void runPersistentScripts();
private:
void setupOpcodes();
diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp
index 37b749f100..1b72c85d96 100644
--- a/engines/mohawk/myst_stacks/preview.cpp
+++ b/engines/mohawk/myst_stacks/preview.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
@@ -35,6 +36,7 @@ namespace MystStacks {
Preview::Preview(MohawkEngine_Myst *vm) : Myst(vm) {
setupOpcodes();
+ _vm->_cursor->hideCursor();
}
Preview::~Preview() {
@@ -52,86 +54,187 @@ Preview::~Preview() {
void Preview::setupOpcodes() {
// "Stack-Specific" Opcodes
- OVERRIDE_OPCODE(196, opcode_196);
- OVERRIDE_OPCODE(197, opcode_197);
- OVERRIDE_OPCODE(198, opcode_198);
- OVERRIDE_OPCODE(199, opcode_199);
+ OVERRIDE_OPCODE(196, o_fadeToBlack);
+ OVERRIDE_OPCODE(197, o_fadeFromBlack);
+ OVERRIDE_OPCODE(198, o_stayHere);
+ OVERRIDE_OPCODE(199, o_speechStop);
// "Init" Opcodes
- OPCODE(298, opcode_298);
- OPCODE(299, opcode_299);
+ OPCODE(298, o_speech_init);
+ OPCODE(299, o_library_init);
}
#undef OPCODE
#undef OVERRIDE_OPCODE
-void Preview::opcode_196(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::disablePersistentScripts() {
+ Myst::disablePersistentScripts();
+}
+
+void Preview::runPersistentScripts() {
+ Myst::runPersistentScripts();
- // Used on Card ...
- // TODO: Finish Implementation...
- // Voice Over and Card Advance?
+ if (_speechRunning)
+ speech_run();
}
-void Preview::opcode_197(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::o_fadeToBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Fade to black", op);
+ _vm->_gfx->fadeToBlack();
+}
- // Used on Card ...
- // TODO: Finish Implementation...
- // Voice Over and Card Advance?
+void Preview::o_fadeFromBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Fade from black", op);
+ _vm->_gfx->fadeFromBlack();
}
-// TODO: Merge with Opcode 42?
-void Preview::opcode_198(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::o_stayHere(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Stay here dialog", op);
- if (argc == 0) {
- // Nuh-uh! No leaving the library in the demo!
- GUI::MessageDialog dialog("You can't leave the library in the demo.");
- dialog.runModal();
- } else
- unknown(op, var, argc, argv);
+ // Nuh-uh! No leaving the library in the demo!
+ GUI::MessageDialog dialog("You can't leave the library in the demo.");
+ dialog.runModal();
}
-void Preview::opcode_199(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::o_speechStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Speech stop", op);
- // Used on Card ...
- // TODO: Finish Implementation...
- // Voice Over and Card Advance?
+ _speechRunning = false;
+ _globals.currentAge = 2;
}
-void Preview::opcode_298(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::speechUpdateCue() {
+ // This is a callback in the original, handling audio events.
+ if (!_vm->_sound->isPlaying(3001)) {
+ return;
+ }
- // Used for Card 3000 (Closed Myst Book)
- // TODO: Fill in logic.
- // Start Voice Over... which controls book opening
- _vm->_sound->replaceSoundMyst(3001);
-
- // then link to Myst - Trigger of Hotspot? then opcode 199/196/197 for voice over continue?
- // TODO: Sync Voice and Actions to Original
- // TODO: Flash Library Red
- // TODO: Move to run process based delay to prevent
- // blocking...
- _vm->_system->updateScreen();
- _vm->_system->delayMillis(20 * 1000);
-
- for (uint16 imageId = 3001; imageId <= 3012; imageId++) {
- _vm->_gfx->copyImageToScreen(imageId, Common::Rect(0, 0, 544, 333));
- _vm->_system->updateScreen();
- _vm->_system->delayMillis(5 * 1000);
+ uint samples = _vm->_sound->getNumSamplesPlayed(3001);
+ for (int16 i = 0; i < _cueList.pointCount; i++) {
+ if (_cueList.points[i].sampleFrame > samples)
+ return;
+ if (i > _currentCue - 1) {
+ _currentCue++;
+ debugC(kDebugScript, "Sneak speech advanced to cue %d", _currentCue);
+ }
}
}
-void Preview::opcode_299(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- varUnusedCheck(op, var);
+void Preview::speech_run() {
+ uint32 time = _vm->_system->getMillis();
+
+ // Update current speech sound cue
+ speechUpdateCue();
+
+ switch (_speechStep) {
+ case 0: // Start Voice Over... which controls book opening
+ _currentCue = 0;
+ _vm->_sound->playSound(3001, Audio::Mixer::kMaxChannelVolume, false, &_cueList);
+
+ _speechStep++;
+ break;
+ case 1: // Open book
+ if (_currentCue >= 1) {
+ _vm->changeToCard(3001, true);
+
+ _speechStep++;
+ }
+ break;
+ case 2: // Go to Myst
+ if (_currentCue >= 2) {
+ _vm->_gfx->fadeToBlack();
+ _vm->changeToCard(3002, true);
+ _vm->_gfx->fadeFromBlack();
+
+ _speechStep++;
+ }
+ break;
+ case 3: // Start blinking the library
+ if (_currentCue >= 3) {
+ _libraryState = 1;
+ _speechNextTime = 0;
+ _speechStep++;
+ }
+ break;
+ case 4: // Library blinking, zoom in library
+ if (_currentCue >= 4) {
+ _library->drawConditionalDataToScreen(0);
+
+ _vm->changeToCard(3003, true);
+
+ _speechNextTime = time + 2000;
+ _speechStep++;
+ } else {
+ if (time < _speechNextTime)
+ break;
+
+ _library->drawConditionalDataToScreen(_libraryState);
+ _libraryState = (_libraryState + 1) % 2;
+ _speechNextTime = time + 500;
+ }
+ break;
+ case 5: // Go to library near view
+ if (time < _speechNextTime)
+ break;
+
+ _vm->changeToCard(3004, true);
+ _speechNextTime = time + 2000;
+ _speechStep++;
+ break;
+ case 6: // Fade to courtyard
+ if (time < _speechNextTime)
+ break;
+
+ _vm->_gfx->fadeToBlack();
+ _vm->changeToCard(3005, true);
+ _vm->_gfx->fadeFromBlack();
+ _speechNextTime = time + 1000;
+ _speechStep++;
+ break;
+ case 7: // Walk to library
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ if (time < _speechNextTime)
+ break;
+
+ _vm->changeToCard(3006 + _speechStep - 7, true);
+ _speechNextTime = time + 2000;
+ _speechStep++;
+ break;
+ case 14: // Go to playable library card
+ if (time < _speechNextTime)
+ break;
+
+ _vm->changeToCard(4329, true);
+
+ _speechRunning = false;
+ _globals.currentAge = 2;
+
+ _vm->_cursor->showCursor();
+ break;
+ default:
+ warning("Unknown speech step");
+ break;
+ }
+}
+
+void Preview::o_speech_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Speech init", op);
+
+ // Used for Card 3000 (Closed Myst Book)
+ _speechStep = 0;
+ _speechRunning = true;
+}
+
+void Preview::o_library_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Library init", op);
// Used for Card 3002 (Myst Island Overview)
- // TODO: Fill in logic.
- // Zoom into Island?
- // On this card is a Type 8 controlled by Var 0, which
- // can change the Myst Library to Red..
+ _library = static_cast<MystResourceType8 *>(_invokingResource);
}
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h
index 7e4e418eef..1e4ff3efb4 100644
--- a/engines/mohawk/myst_stacks/preview.h
+++ b/engines/mohawk/myst_stacks/preview.h
@@ -40,16 +40,31 @@ public:
Preview(MohawkEngine_Myst *vm);
~Preview();
+ void disablePersistentScripts();
+ void runPersistentScripts();
+
private:
void setupOpcodes();
- DECLARE_OPCODE(opcode_196);
- DECLARE_OPCODE(opcode_197);
- DECLARE_OPCODE(opcode_198);
- DECLARE_OPCODE(opcode_199);
+ DECLARE_OPCODE(o_fadeToBlack);
+ DECLARE_OPCODE(o_fadeFromBlack);
+ DECLARE_OPCODE(o_stayHere);
+ DECLARE_OPCODE(o_speechStop);
+
+ DECLARE_OPCODE(o_speech_init);
+ DECLARE_OPCODE(o_library_init);
+
+ uint16 _libraryState; // 4
+ MystResourceType8 *_library; // 32
+
+ bool _speechRunning;
+ uint _speechStep;
+ CueList _cueList;
+ int16 _currentCue;
+ uint32 _speechNextTime; // 6
- DECLARE_OPCODE(opcode_298);
- DECLARE_OPCODE(opcode_299);
+ void speech_run();
+ void speechUpdateCue();
};
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp
index 72b299ee6d..943cb90071 100644
--- a/engines/mohawk/myst_stacks/slides.cpp
+++ b/engines/mohawk/myst_stacks/slides.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
@@ -35,6 +36,7 @@ namespace MystStacks {
Slides::Slides(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
setupOpcodes();
+ _vm->_cursor->hideCursor();
}
Slides::~Slides() {
@@ -59,23 +61,28 @@ void Slides::disablePersistentScripts() {
void Slides::runPersistentScripts() {
if (_cardSwapEnabled) {
// Used on Cards...
- if (_vm->_system->getMillis() - _lastCardTime >= 2 * 1000)
+ if (_vm->_system->getMillis() > _nextCardTime) {
+ _vm->_gfx->fadeToBlack();
_vm->changeToCard(_nextCardID, true);
+ _vm->_gfx->fadeFromBlack();
+ }
}
}
void Slides::o_returnToMenu(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- _vm->changeToStack(kDemoStack, 2001, 0, 0);
+ debugC(kDebugScript, "Opcode %d: Return to menu", op);
+
+ // Go to the information screens of the menu
+ _vm->changeToStack(kDemoStack, 2002, 0, 0);
}
void Slides::o_setCardSwap(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- // Used on Cards...
- if (argc == 1) {
- _nextCardID = argv[0];
- _lastCardTime = _vm->_system->getMillis();
- _cardSwapEnabled = true;
- } else
- unknown(op, var, argc, argv);
+ _nextCardID = argv[0];
+
+ debugC(kDebugScript, "Opcode %d: Set next card %d", op, _nextCardID);
+
+ _nextCardTime = _vm->_system->getMillis() + 5000;
+ _cardSwapEnabled = true;
}
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h
index 8bc61d0e24..9fb76728b6 100644
--- a/engines/mohawk/myst_stacks/slides.h
+++ b/engines/mohawk/myst_stacks/slides.h
@@ -52,7 +52,7 @@ private:
bool _cardSwapEnabled;
uint16 _nextCardID;
- uint32 _lastCardTime;
+ uint32 _nextCardTime;
};
} // End of namespace MystStacks
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index bab4b8dd51..3a8d233a26 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -320,6 +320,10 @@ void MystGameState::deleteSave(const Common::String &saveName) {
void MystGameState::addZipDest(uint16 stack, uint16 view) {
ZipDests *zipDests = 0;
+ // The demo has no zip dest storage
+ if (_vm->getFeatures() & GF_DEMO)
+ return;
+
// Select stack
switch (stack) {
case kChannelwoodStack:
@@ -362,6 +366,10 @@ bool MystGameState::isReachableZipDest(uint16 stack, uint16 view) {
if (!_globals.zipMode)
return false;
+ // The demo has no zip dest storage
+ if (_vm->getFeatures() & GF_DEMO)
+ return false;
+
// Select stack
ZipDests *zipDests;
switch (stack) {
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 612b8b3685..3e2fa4f979 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -150,6 +150,9 @@ Common::Error MohawkEngine_Riven::run() {
return Common::kNoGameDataFoundError;
}
+ // Set the transition speed
+ _gfx->setTransitionSpeed(_vars["transitionmode"]);
+
// Start at main cursor
_cursor->setCursor(kRivenMainCursor);
_cursor->showCursor();
@@ -209,8 +212,10 @@ void MohawkEngine_Riven::handleEvents() {
needsUpdate = true;
break;
case Common::EVENT_LBUTTONDOWN:
- if (_curHotspot >= 0)
+ if (_curHotspot >= 0) {
+ checkSunnerAlertClick();
runHotspotScript(_curHotspot, kMouseDownScript);
+ }
break;
case Common::EVENT_LBUTTONUP:
// See RivenScript::switchCard() for more information on why we sometimes
@@ -812,6 +817,138 @@ static void catherineIdleTimer(MohawkEngine_Riven *vm) {
vm->installTimer(&catherineIdleTimer, timeUntilNextMovie);
}
+static void sunnersTopStairsTimer(MohawkEngine_Riven *vm) {
+ // If the sunners are gone, we have no video to play
+ if (vm->_vars["jsunners"] != 0) {
+ vm->removeTimer();
+ return;
+ }
+
+ // Play a random sunners video if the script one is not playing already
+ // and then set a new timer for when the new video should be played
+
+ VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
+ uint32 timerTime = 500;
+
+ if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ uint32 &sunnerTime = vm->_vars["jsunnertime"];
+
+ if (sunnerTime == 0) {
+ timerTime = vm->_rnd->getRandomNumberRng(2, 15) * 1000;
+ } else if (sunnerTime < vm->getTotalPlayTime()) {
+ VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(1, 3));
+
+ timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(2, 15) * 1000;
+ }
+
+ sunnerTime = timerTime + vm->getTotalPlayTime();
+ }
+
+ vm->installTimer(&sunnersTopStairsTimer, timerTime);
+}
+
+static void sunnersMidStairsTimer(MohawkEngine_Riven *vm) {
+ // If the sunners are gone, we have no video to play
+ if (vm->_vars["jsunners"] != 0) {
+ vm->removeTimer();
+ return;
+ }
+
+ // Play a random sunners video if the script one is not playing already
+ // and then set a new timer for when the new video should be played
+
+ VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
+ uint32 timerTime = 500;
+
+ if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ uint32 &sunnerTime = vm->_vars["jsunnertime"];
+
+ if (sunnerTime == 0) {
+ timerTime = vm->_rnd->getRandomNumberRng(1, 10) * 1000;
+ } else if (sunnerTime < vm->getTotalPlayTime()) {
+ // Randomize the video
+ int randValue = vm->_rnd->getRandomNumber(5);
+ uint16 movie = 4;
+ if (randValue == 4)
+ movie = 2;
+ else if (randValue == 5)
+ movie = 3;
+
+ VideoHandle handle = vm->_video->playMovieRiven(movie);
+
+ timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 10) * 1000;
+ }
+
+ sunnerTime = timerTime + vm->getTotalPlayTime();
+ }
+
+ vm->installTimer(&sunnersMidStairsTimer, timerTime);
+}
+
+static void sunnersLowerStairsTimer(MohawkEngine_Riven *vm) {
+ // If the sunners are gone, we have no video to play
+ if (vm->_vars["jsunners"] != 0) {
+ vm->removeTimer();
+ return;
+ }
+
+ // Play a random sunners video if the script one is not playing already
+ // and then set a new timer for when the new video should be played
+
+ VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
+ uint32 timerTime = 500;
+
+ if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ uint32 &sunnerTime = vm->_vars["jsunnertime"];
+
+ if (sunnerTime == 0) {
+ timerTime = vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ } else if (sunnerTime < vm->getTotalPlayTime()) {
+ VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(3, 5));
+
+ timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ }
+
+ sunnerTime = timerTime + vm->getTotalPlayTime();
+ }
+
+ vm->installTimer(&sunnersLowerStairsTimer, timerTime);
+}
+
+static void sunnersBeachTimer(MohawkEngine_Riven *vm) {
+ // If the sunners are gone, we have no video to play
+ if (vm->_vars["jsunners"] != 0) {
+ vm->removeTimer();
+ return;
+ }
+
+ // Play a random sunners video if the script one is not playing already
+ // and then set a new timer for when the new video should be played
+
+ VideoHandle oldHandle = vm->_video->findVideoHandleRiven(3);
+ uint32 timerTime = 500;
+
+ if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ uint32 &sunnerTime = vm->_vars["jsunnertime"];
+
+ if (sunnerTime == 0) {
+ timerTime = vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ } else if (sunnerTime < vm->getTotalPlayTime()) {
+ // Unlike the other cards' scripts which automatically
+ // activate the MLST, we have to set it manually here.
+ uint16 mlstID = vm->_rnd->getRandomNumberRng(3, 8);
+ vm->_video->activateMLST(mlstID, vm->getCurCard());
+ VideoHandle handle = vm->_video->playMovieRiven(mlstID);
+
+ timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ }
+
+ sunnerTime = timerTime + vm->getTotalPlayTime();
+ }
+
+ vm->installTimer(&sunnersBeachTimer, timerTime);
+}
+
void MohawkEngine_Riven::installCardTimer() {
switch (getCurCardRMAP()) {
case 0x3a85: // Top of elevator on prison island
@@ -819,16 +956,16 @@ void MohawkEngine_Riven::installCardTimer() {
installTimer(&catherineIdleTimer, _rnd->getRandomNumberRng(1, 33) * 1000);
break;
case 0x77d6: // Sunners, top of stairs
- // TODO: Background Sunner videos
+ installTimer(&sunnersTopStairsTimer, 500);
break;
case 0x79bd: // Sunners, middle of stairs
- // TODO: Background Sunner videos
+ installTimer(&sunnersMidStairsTimer, 500);
break;
case 0x7beb: // Sunners, bottom of stairs
- // TODO: Background Sunner videos
+ installTimer(&sunnersLowerStairsTimer, 500);
break;
case 0xb6ca: // Sunners, shoreline
- // TODO: Background Sunner videos
+ installTimer(&sunnersBeachTimer, 500);
break;
}
}
@@ -846,6 +983,34 @@ void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) {
_scriptMan->runStoredMovieOpcode();
}
+void MohawkEngine_Riven::checkSunnerAlertClick() {
+ // We need to do a manual hardcoded check for the sunners'
+ // alert movies.
+
+ uint32 &sunners = _vars["jsunners"];
+
+ // If the sunners are gone, there's nothing for us to do
+ if (sunners != 0)
+ return;
+
+ uint32 rmapCode = getCurCardRMAP();
+
+ // This is only for the mid/lower staircase sections
+ if (rmapCode != 0x79bd && rmapCode != 0x7beb)
+ return;
+
+ // Only set the sunners variable on the forward hotspot
+ if ((rmapCode == 0x79bd && _curHotspot != 1) || (rmapCode == 0x7beb && _curHotspot != 2))
+ return;
+
+ // If the alert video is no longer playing, we have nothing left to do
+ VideoHandle handle = _video->findVideoHandleRiven(1);
+ if (handle == NULL_VID_HANDLE || _video->endOfVideo(handle))
+ return;
+
+ sunners = 1;
+}
+
bool ZipMode::operator== (const ZipMode &z) const {
return z.name == name && z.id == id;
}
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index c7d36e585d..e99a9f78fc 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -67,6 +67,13 @@ enum {
StackNames = 5
};
+enum RivenTransitionSpeed {
+ kRivenTransitionSpeedNone = 5000,
+ kRivenTransitionSpeedFastest = 5001,
+ kRivenTransitionSpeedNormal = 5002,
+ kRivenTransitionSpeedBest = 5003
+};
+
// Rects for the inventory object positions (initialized in
// MohawkEngine_Riven's constructor).
extern Common::Rect *g_atrusJournalRect1;
@@ -164,6 +171,7 @@ private:
// Miscellaneous
bool _gameOver;
bool _ignoreNextMouseUp;
+ void checkSunnerAlertClick();
public:
// Stack/card/script funtions
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 60e94ea795..9e1365f8da 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -234,10 +234,10 @@ void RivenExternal::runCredits(uint16 video, uint32 delay) {
// Set us up to start after delay ms
nextCreditsFrameStart = _vm->_system->getMillis() + delay;
} else if (_vm->_system->getMillis() >= nextCreditsFrameStart) {
- // the first two frames stay on for 5 seconds
+ // the first two frames stay on for 4 seconds
// the rest of the scroll updates happen at 30Hz
if (_vm->_gfx->getCurCreditsImage() < 304)
- nextCreditsFrameStart = _vm->_system->getMillis() + 5000;
+ nextCreditsFrameStart = _vm->_system->getMillis() + 4000;
else
nextCreditsFrameStart = _vm->_system->getMillis() + 1000 / 30;
@@ -1889,21 +1889,42 @@ void RivenExternal::xjplaybeetle_1450(uint16 argc, uint16 *argv) {
}
void RivenExternal::xjlagoon700_alert(uint16 argc, uint16 *argv) {
- // TODO: Sunner related
+ // Handle sunner reactions (mid-staircase)
+
+ if (_vm->_vars["jsunners"] == 0)
+ _vm->_video->playMovieRiven(1);
}
void RivenExternal::xjlagoon800_alert(uint16 argc, uint16 *argv) {
- // TODO: Sunner related
+ // Handle sunner reactions (lower-staircase)
+
+ uint32 &sunners = _vm->_vars["jsunners"];
+
+ if (sunners == 0) {
+ // Show the sunners alert video
+ _vm->_video->playMovieRiven(1);
+ } else if (sunners == 1) {
+ // Show the sunners leaving if you moved forward in their "alert" status
+ _vm->_video->playMovieBlockingRiven(2);
+ _vm->_video->playMovieBlockingRiven(6);
+ sunners = 2;
+ _vm->refreshCard();
+ }
}
void RivenExternal::xjlagoon1500_alert(uint16 argc, uint16 *argv) {
- // Have the sunners move a bit as you get closer ;)
+ // Handle sunner reactions (beach)
+
uint32 &sunners = _vm->_vars["jsunners"];
+
if (sunners == 0) {
+ // Show the sunners alert video
_vm->_video->playMovieBlockingRiven(3);
} else if (sunners == 1) {
+ // Show the sunners leaving if you moved forward in their "alert" status
_vm->_video->playMovieBlockingRiven(2);
sunners = 2;
+ _vm->refreshCard();
}
}
@@ -2726,6 +2747,7 @@ void RivenExternal::xtatboundary(uint16 argc, uint16 *argv) {
void RivenExternal::xflies(uint16 argc, uint16 *argv) {
// TODO: Activate the "flies" effect
+ debug(1, "STUB: xflies(): create %d %s fl%s", argv[1], (argv[0] == 0) ? "black" : "glowing", (argv[1] == 1) ? "y" : "ies");
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_vars.cpp b/engines/mohawk/riven_vars.cpp
index 946e2e0496..ba5c343e07 100644
--- a/engines/mohawk/riven_vars.cpp
+++ b/engines/mohawk/riven_vars.cpp
@@ -268,7 +268,12 @@ static const char *variableNames[] = {
};
uint32 &MohawkEngine_Riven::getStackVar(uint32 index) {
- return _vars[getName(VariableNames, index)];
+ Common::String name = getName(VariableNames, index);
+
+ if (!_vars.contains(name))
+ error("Could not find variable '%s' (stack variable %d)", name.c_str(), index);
+
+ return _vars[name];
}
void MohawkEngine_Riven::initVars() {
@@ -299,6 +304,7 @@ void MohawkEngine_Riven::initVars() {
_vars["bmagcar"] = 1;
_vars["gnmagcar"] = 1;
_vars["omusicplayer"] = 1;
+ _vars["transitionmode"] = kRivenTransitionSpeedFastest;
// Randomize the telescope combination
uint32 &teleCombo = _vars["tcorrectorder"];
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 791b18db49..f92bebf10e 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -20,19 +20,20 @@
*
*/
-#include "mohawk/sound.h"
-
#include "common/debug.h"
#include "common/system.h"
#include "common/util.h"
#include "common/textconsole.h"
+#include "audio/midiparser.h"
#include "audio/musicplugin.h"
#include "audio/audiostream.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
+#include "mohawk/sound.h"
+
namespace Mohawk {
Sound::Sound(MohawkEngine* vm) : _vm(vm) {
@@ -84,7 +85,7 @@ Audio::AudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
if (_vm->getFeatures() & GF_ME)
audStream = Audio::makeWAVStream(_vm->getResource(ID_MSND, convertMystID(id)), DisposeAfterUse::YES);
else
- audStream = makeMohawkWaveStream(_vm->getResource(ID_MSND, id));
+ audStream = makeMohawkWaveStream(_vm->getResource(ID_MSND, id), cueList);
break;
case GType_ZOOMBINI:
audStream = makeMohawkWaveStream(_vm->getResource(ID_SND, id));
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 593f2fcd0b..12a59cdedf 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -27,14 +27,15 @@
#include "common/str.h"
#include "audio/audiostream.h"
-#include "audio/decoders/adpcm.h"
-#include "audio/mididrv.h"
-#include "audio/midiparser.h"
#include "audio/mixer.h"
+#include "audio/decoders/adpcm.h"
#include "mohawk/mohawk.h"
#include "mohawk/resource.h"
+class MidiDriver;
+class MidiParser;
+
namespace Mohawk {
#define MAX_CHANNELS 2 // Can there be more than 2?