aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorAlyssa Milburn2010-12-13 20:19:34 +0000
committerAlyssa Milburn2010-12-13 20:19:34 +0000
commit0082f8ec8b690682f6fb0ae8339b6002fe8ea5e6 (patch)
tree6e00594c25d6072393973959ef4c4e2f12dba586 /engines
parent51685f26dc5777e3bb1893705f85ca18cb41632d (diff)
downloadscummvm-rg350-0082f8ec8b690682f6fb0ae8339b6002fe8ea5e6.tar.gz
scummvm-rg350-0082f8ec8b690682f6fb0ae8339b6002fe8ea5e6.tar.bz2
scummvm-rg350-0082f8ec8b690682f6fb0ae8339b6002fe8ea5e6.zip
MOHAWK: parse LB subentries correctly
svn-id: r54901
Diffstat (limited to 'engines')
-rw-r--r--engines/mohawk/livingbooks.cpp327
-rw-r--r--engines/mohawk/livingbooks.h5
2 files changed, 180 insertions, 152 deletions
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 18fa00d987..b8551235dc 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -1583,6 +1583,9 @@ LBScriptEntry::LBScriptEntry() {
LBScriptEntry::~LBScriptEntry() {
delete[] argvParam;
delete[] argvTarget;
+
+ for (uint i = 0; i < subentries.size(); i++)
+ delete subentries[i];
}
LBItem::LBItem(MohawkEngine_LivingBooks *vm, Common::Rect rect) : _vm(vm), _rect(rect) {
@@ -1659,9 +1662,15 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
if (size < 6)
error("Script entry of type 0x%04x was too small (%d)", type, size);
+ uint16 expectedEndSize = 0;
+
LBScriptEntry *entry = new LBScriptEntry;
entry->type = type;
- entry->event = stream->readUint16();
+ if (isSubentry) {
+ expectedEndSize = size - (stream->readUint16() + 2);
+ entry->event = 0xffff;
+ } else
+ entry->event = stream->readUint16();
entry->opcode = stream->readUint16();
entry->param = stream->readUint16();
debug(4, "Script entry: type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x",
@@ -1672,13 +1681,11 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
byte conditionTag = (entry->event & 0xff00) >> 8;
entry->event = entry->event & 0xff;
- if (type == kLBMsgListScript && entry->opcode == 0xfffe) {
+ if (type == kLBMsgListScript && entry->opcode == kLBOpRunSubentries) {
debug(4, "%d script subentries:", entry->param);
for (uint i = 0; i < entry->param; i++) {
LBScriptEntry *subentry = parseScriptEntry(type, size, stream, true);
- // FIXME: deal with subentry
- delete subentry;
- //entry->_scriptEntries.push_back(entry);
+ entry->subentries.push_back(subentry);
// subentries are aligned
if (i + 1 < entry->param && size % 2 == 1) {
@@ -1803,9 +1810,13 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
debug(4, "script entry command '%s'", command.c_str());
}
- // FIXME
- if (isSubentry)
+ if (isSubentry) {
+ // TODO: subentries may be aligned, so this check is a bit too relaxed
+ if (size != expectedEndSize && size != expectedEndSize + 1)
+ error("expected %d bytes left at end of subentry, but had %d",
+ expectedEndSize, size);
return entry;
+ }
if (conditionTag == 1) {
Common::String condition = readString(stream);
@@ -2173,13 +2184,14 @@ void LBItem::notify(uint16 data, uint16 from) {
runScript(kLBEventNotified, data, from);
}
-void LBItem::runScript(uint id, uint16 data, uint16 from) {
+void LBItem::runScript(uint event, uint16 data, uint16 from) {
for (uint i = 0; i < _scriptEntries.size(); i++) {
LBScriptEntry *entry = _scriptEntries[i];
- if (entry->event != id)
+
+ if (entry->event != event)
continue;
- if (id == kLBEventNotified) {
+ if (event == kLBEventNotified) {
if (entry->matchFrom != from || entry->matchNotify != data)
continue;
}
@@ -2201,177 +2213,190 @@ void LBItem::runScript(uint id, uint16 data, uint16 from) {
if (entry->opcode == kLBNotifyGUIAction)
_vm->addNotifyEvent(NotifyEvent(entry->opcode, _itemId));
else if (entry->opcode == kLBNotifyChangeMode && _vm->getGameType() != GType_LIVINGBOOKSV1) {
- NotifyEvent event(entry->opcode, entry->param);
- event.newUnknown = entry->newUnknown;
- event.newMode = entry->newMode;
- event.newPage = entry->newPage;
- event.newSubpage = entry->newSubpage;
- _vm->addNotifyEvent(event);
+ NotifyEvent notifyEvent(entry->opcode, entry->param);
+ notifyEvent.newUnknown = entry->newUnknown;
+ notifyEvent.newMode = entry->newMode;
+ notifyEvent.newPage = entry->newPage;
+ notifyEvent.newSubpage = entry->newSubpage;
+ _vm->addNotifyEvent(notifyEvent);
} else
_vm->addNotifyEvent(NotifyEvent(entry->opcode, entry->param));
- } else {
- if (entry->param != 0xffff) {
- // TODO: if param is 1/2/3..
- warning("Ignoring script entry (type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x)",
- entry->type, entry->event, entry->opcode, entry->param);
+ } else
+ runScriptEntry(entry);
+ }
+}
+
+void LBItem::runScriptEntry(LBScriptEntry *entry) {
+ if (entry->param != 0xffff) {
+ // TODO: if param is 1/2/3..
+ warning("Ignoring script entry (type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x)",
+ entry->type, entry->event, entry->opcode, entry->param);
+ return;
+ }
+
+ uint count = entry->argc;
+ // zero targets = apply to self
+ if (!count)
+ count = 1;
+
+ for (uint n = 0; n < count; n++) {
+ LBItem *target;
+
+ debug(2, "Script run: type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x",
+ entry->type, entry->event, entry->opcode, entry->param);
+
+ if (entry->argc) {
+ uint16 targetId = entry->argvTarget[n];
+ // TODO: is this type, perhaps?
+ uint16 param = entry->argvParam[n];
+ target = _vm->getItemById(targetId);
+ if (!target) {
+ debug(2, "Target %04x (%04x) doesn't exist, skipping", targetId, param);
continue;
}
+ debug(2, "Target: %04x (%04x) '%s'", targetId, param, _desc.c_str());
+ } else {
+ target = this;
+ debug(2, "Self-target on '%s'", _desc.c_str());
+ }
- uint count = entry->argc;
- // zero targets = apply to self
- if (!count)
- count = 1;
-
- for (uint n = 0; n < count; n++) {
- LBItem *target;
-
- debug(2, "Script run: type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x",
- entry->type, entry->event, entry->opcode, entry->param);
-
- if (entry->argc) {
- uint16 targetId = entry->argvTarget[n];
- // TODO: is this type, perhaps?
- uint16 param = entry->argvParam[n];
- target = _vm->getItemById(targetId);
- if (!target) {
- debug(2, "Target %04x (%04x) doesn't exist, skipping", targetId, param);
- continue;
- }
- debug(2, "Target: %04x (%04x) '%s'", targetId, param, _desc.c_str());
- } else {
- target = this;
- debug(2, "Self-target on '%s'", _desc.c_str());
- }
-
- // an opcode in the form 0x1xx means to run the script for event 0xx
- if ((entry->opcode & 0xff00) == 0x0100) {
- // FIXME: pass on param
- target->runScript(entry->opcode & 0xff);
- break;
- }
+ // an opcode in the form 0x1xx means to run the script for event 0xx
+ if ((entry->opcode & 0xff00) == 0x0100) {
+ // FIXME: pass on param
+ target->runScript(entry->opcode & 0xff);
+ break;
+ }
- switch (entry->opcode) {
- case kLBOpNone:
- warning("ignoring kLBOpNone (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ switch (entry->opcode) {
+ case kLBOpNone:
+ warning("ignoring kLBOpNone (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpXShow:
- // TODO: should be setVisible(true) - not a delayed event -
- // when we're doing the param 1/2/3 stuff above?
- // and in modern LB this is perhaps just a direct target->setVisible(true)..
- _vm->queueDelayedEvent(DelayedEvent(this, kLBDelayedEventSetNotVisible));
- break;
+ case kLBOpXShow:
+ // TODO: should be setVisible(true) - not a delayed event -
+ // when we're doing the param 1/2/3 stuff above?
+ // and in modern LB this is perhaps just a direct target->setVisible(true)..
+ if (_vm->getGameType() != GType_LIVINGBOOKSV1)
+ warning("kLBOpXShow on '%s' is probably broken", target->_desc.c_str());
+ _vm->queueDelayedEvent(DelayedEvent(this, kLBDelayedEventSetNotVisible));
+ break;
- case kLBOpTogglePlay:
- target->togglePlaying(false);
- break;
+ case kLBOpTogglePlay:
+ target->togglePlaying(false);
+ break;
- case kLBOpSetNotVisible:
- target->setVisible(false);
- break;
+ case kLBOpSetNotVisible:
+ target->setVisible(false);
+ break;
- case kLBOpSetVisible:
- target->setVisible(true);
- break;
+ case kLBOpSetVisible:
+ target->setVisible(true);
+ break;
- case kLBOpDestroy:
- target->destroySelf();
- break;
+ case kLBOpDestroy:
+ target->destroySelf();
+ break;
- case kLBOpRewind:
- target->seek(0);
- break;
+ case kLBOpRewind:
+ target->seek(0);
+ break;
- case kLBOpStop:
- target->stop();
- break;
+ case kLBOpStop:
+ target->stop();
+ break;
- case kLBOpDisable:
- target->setEnabled(false);
- break;
+ case kLBOpDisable:
+ target->setEnabled(false);
+ break;
- case kLBOpEnable:
- target->setEnabled(true);
- break;
+ case kLBOpEnable:
+ target->setEnabled(true);
+ break;
- case kLBOpGlobalSetNotVisible:
- target->setGlobalVisible(false);
- break;
+ case kLBOpGlobalSetNotVisible:
+ target->setGlobalVisible(false);
+ break;
- case kLBOpGlobalSetVisible:
- target->setGlobalVisible(true);
- break;
+ case kLBOpGlobalSetVisible:
+ target->setGlobalVisible(true);
+ break;
- case kLBOpGlobalDisable:
- target->setGlobalEnabled(false);
- break;
+ case kLBOpGlobalDisable:
+ target->setGlobalEnabled(false);
+ break;
- case kLBOpGlobalEnable:
- target->setGlobalEnabled(true);
- break;
+ case kLBOpGlobalEnable:
+ target->setGlobalEnabled(true);
+ break;
- case kLBOpSeekToEnd:
- target->seek(0xFFFF);
- break;
+ case kLBOpSeekToEnd:
+ target->seek(0xFFFF);
+ break;
- case kLBOpMute:
- case kLBOpUnmute:
- // FIXME
- warning("ignoring kLBOpMute/Unmute (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpMute:
+ case kLBOpUnmute:
+ // FIXME
+ warning("ignoring kLBOpMute/Unmute (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpLoad:
- case kLBOpPreload:
- case kLBOpUnload:
- // FIXME
- warning("ignoring kLBOpLoad/Preload/Unload (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpLoad:
+ case kLBOpPreload:
+ case kLBOpUnload:
+ // FIXME
+ warning("ignoring kLBOpLoad/Preload/Unload (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpSeekToPrev:
- case kLBOpSeekToNext:
- // FIXME
- warning("ignoring kLBOpSeekToPrev/Next (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpSeekToPrev:
+ case kLBOpSeekToNext:
+ // FIXME
+ warning("ignoring kLBOpSeekToPrev/Next (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpDragBegin:
- case kLBOpDragEnd:
- // FIXME
- warning("ignoring kLBOpDragBegin/End (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpDragBegin:
+ case kLBOpDragEnd:
+ // FIXME
+ warning("ignoring kLBOpDragBegin/End (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpScriptDisable:
- case kLBOpScriptEnable:
- // FIXME
- warning("ignoring kLBOpScriptDisable/Enable (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpScriptDisable:
+ case kLBOpScriptEnable:
+ // FIXME
+ warning("ignoring kLBOpScriptDisable/Enable (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpUnknown1C:
- // FIXME
- warning("ignoring kLBOpUnknown1C (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpUnknown1C:
+ // FIXME
+ warning("ignoring kLBOpUnknown1C (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpSendExpression:
- // FIXME
- warning("ignoring kLBOpSendExpression (event 0x%04x, param 0x%04x, target '%s')",
- entry->event, entry->param, target->_desc.c_str());
- break;
+ case kLBOpSendExpression:
+ // FIXME
+ warning("ignoring kLBOpSendExpression (event 0x%04x, param 0x%04x, target '%s')",
+ entry->event, entry->param, target->_desc.c_str());
+ break;
- case kLBOpRunCommand:
- runCommand(entry->command);
- break;
+ case kLBOpRunSubentries:
+ for (uint i = 0; i < entry->subentries.size(); i++) {
+ LBScriptEntry *subentry = entry->subentries[i];
- default:
- error("Unknown script opcode (type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x, target '%s')",
- entry->type, entry->event, entry->opcode, entry->param, target->_desc.c_str());
- }
+ runScriptEntry(subentry);
}
+ break;
+
+ case kLBOpRunCommand:
+ runCommand(entry->command);
+ break;
+
+ default:
+ error("Unknown script opcode (type 0x%04x, event 0x%04x, opcode 0x%04x, param 0x%04x, target '%s')",
+ entry->type, entry->event, entry->opcode, entry->param, target->_desc.c_str());
}
}
}
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index b192c9fe05..4d99dd2dee 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -199,6 +199,7 @@ enum {
kLBOpScriptEnable = 0x1b,
kLBOpUnknown1C = 0x1c,
kLBOpSendExpression = 0x1d,
+ kLBOpRunSubentries = 0xfffe,
kLBOpRunCommand = 0xffff
};
@@ -246,6 +247,7 @@ struct LBScriptEntry {
Common::String command;
Common::Array<Common::String> conditions;
+ Common::Array<LBScriptEntry *> subentries;
};
struct LBAnimScriptEntry {
@@ -390,7 +392,8 @@ protected:
bool _isAmbient;
Common::Array<LBScriptEntry *> _scriptEntries;
- void runScript(uint id, uint16 data = 0, uint16 from = 0);
+ void runScript(uint event, uint16 data = 0, uint16 from = 0);
+ void runScriptEntry(LBScriptEntry *entry);
LBValue parseValue(const Common::String &command, uint &pos);
void runCommand(const Common::String &command);