diff options
author | Alyssa Milburn | 2010-12-13 20:19:34 +0000 |
---|---|---|
committer | Alyssa Milburn | 2010-12-13 20:19:34 +0000 |
commit | 0082f8ec8b690682f6fb0ae8339b6002fe8ea5e6 (patch) | |
tree | 6e00594c25d6072393973959ef4c4e2f12dba586 /engines | |
parent | 51685f26dc5777e3bb1893705f85ca18cb41632d (diff) | |
download | scummvm-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.cpp | 327 | ||||
-rw-r--r-- | engines/mohawk/livingbooks.h | 5 |
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); |