aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/livingbooks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk/livingbooks.cpp')
-rw-r--r--engines/mohawk/livingbooks.cpp192
1 files changed, 131 insertions, 61 deletions
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 375806cda4..06500bc725 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -32,6 +32,7 @@
#include "common/archive.h"
#include "common/textconsole.h"
#include "common/system.h"
+#include "common/memstream.h"
#include "graphics/palette.h"
@@ -42,7 +43,7 @@
namespace Mohawk {
// read a null-terminated string from a stream
-Common::String MohawkEngine_LivingBooks::readString(Common::SeekableSubReadStreamEndian *stream) {
+Common::String MohawkEngine_LivingBooks::readString(Common::ReadStream *stream) {
Common::String ret;
while (!stream->eos()) {
byte in = stream->readByte();
@@ -54,7 +55,7 @@ Common::String MohawkEngine_LivingBooks::readString(Common::SeekableSubReadStrea
}
// read a rect from a stream
-Common::Rect MohawkEngine_LivingBooks::readRect(Common::SeekableSubReadStreamEndian *stream) {
+Common::Rect MohawkEngine_LivingBooks::readRect(Common::ReadStreamEndian *stream) {
Common::Rect rect;
// the V1 mac games have their rects in QuickDraw order
@@ -81,7 +82,7 @@ LBPage::LBPage(MohawkEngine_LivingBooks *vm) : _vm(vm) {
_cascade = false;
}
-void LBPage::open(MohawkArchive *mhk, uint16 baseId) {
+void LBPage::open(Archive *mhk, uint16 baseId) {
_mhk = mhk;
_baseId = baseId;
@@ -384,8 +385,8 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) {
warning("ignoring 'killgag' for filename '%s'", filename.c_str());
}
- MohawkArchive *pageArchive = createMohawkArchive();
- if (!filename.empty() && pageArchive->open(filename)) {
+ Archive *pageArchive = createArchive();
+ if (!filename.empty() && pageArchive->openFile(filename)) {
_page = new LBPage(this);
_page->open(pageArchive, 1000);
} else {
@@ -589,11 +590,11 @@ void MohawkEngine_LivingBooks::updatePage() {
}
}
-void MohawkEngine_LivingBooks::addArchive(MohawkArchive *archive) {
+void MohawkEngine_LivingBooks::addArchive(Archive *archive) {
_mhk.push_back(archive);
}
-void MohawkEngine_LivingBooks::removeArchive(MohawkArchive *archive) {
+void MohawkEngine_LivingBooks::removeArchive(Archive *archive) {
for (uint i = 0; i < _mhk.size(); i++) {
if (archive != _mhk[i])
continue;
@@ -767,6 +768,8 @@ void LBPage::loadBITL(uint16 resourceId) {
if (bitlStream->size() == bitlStream->pos())
break;
}
+
+ delete bitlStream;
}
Common::SeekableSubReadStreamEndian *MohawkEngine_LivingBooks::wrapStreamEndian(uint32 tag, uint16 id) {
@@ -862,8 +865,11 @@ Common::String MohawkEngine_LivingBooks::convertWinFileName(const Common::String
return filename;
}
-MohawkArchive *MohawkEngine_LivingBooks::createMohawkArchive() const {
- return isPreMohawk() ? new LivingBooksArchive_v1() : new MohawkArchive();
+Archive *MohawkEngine_LivingBooks::createArchive() const {
+ if (isPreMohawk())
+ return new LivingBooksArchive_v1();
+
+ return new MohawkArchive();
}
bool MohawkEngine_LivingBooks::isPreMohawk() const {
@@ -1873,6 +1879,7 @@ uint16 LBAnimation::getParentId() {
LBScriptEntry::LBScriptEntry() {
state = 0;
+ data = NULL;
argvParam = NULL;
argvTarget = NULL;
}
@@ -1880,6 +1887,7 @@ LBScriptEntry::LBScriptEntry() {
LBScriptEntry::~LBScriptEntry() {
delete[] argvParam;
delete[] argvTarget;
+ delete[] data;
for (uint i = 0; i < subentries.size(); i++)
delete subentries[i];
@@ -1943,7 +1951,10 @@ void LBItem::readFrom(Common::SeekableSubReadStreamEndian *stream) {
uint16 dataSize = stream->readUint16();
debug(4, "Data type %04x, size %d", dataType, dataSize);
- readData(dataType, dataSize, stream);
+ byte *buf = new byte[dataSize];
+ stream->read(buf, dataSize);
+ readData(dataType, dataSize, buf);
+ delete[] buf;
if ((uint)stream->pos() != oldPos + 4 + (uint)dataSize)
error("Failed to read correct number of bytes (off by %d) for data type %04x (size %d)",
@@ -1956,7 +1967,7 @@ void LBItem::readFrom(Common::SeekableSubReadStreamEndian *stream) {
}
}
-LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::SeekableSubReadStreamEndian *stream, bool isSubentry) {
+LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::MemoryReadStreamEndian *stream, bool isSubentry) {
if (size < 6)
error("Script entry of type 0x%04x was too small (%d)", type, size);
@@ -1999,30 +2010,40 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
entry->argc = stream->readUint16();
size -= 2;
+ entry->targetingType = 0;
+
uint16 targetingType = entry->argc;
- if (targetingType == 0x3f3f || targetingType == 0xffff) {
- entry->argc = 0;
+ if (targetingType == kTargetTypeExpression || targetingType == kTargetTypeCode
+ || targetingType == kTargetTypeName) {
+ entry->targetingType = targetingType;
+
+ // FIXME
+ if (targetingType == kTargetTypeCode)
+ error("encountered kTargetTypeCode");
+ if (size < 2)
+ error("not enough bytes (%d) reading special targeting", size);
uint16 count = stream->readUint16();
size -= 2;
debug(4, "%d targets with targeting type %04x", count, targetingType);
- // FIXME: targeting by name
uint oldAlign = size % 2;
for (uint i = 0; i < count; i++) {
Common::String target = _vm->readString(stream);
- warning("ignoring target '%s' in script entry", target.c_str());
+ debug(4, "target '%s'", target.c_str());
+ entry->targets.push_back(target);
+ if (target.size() + 1 > size)
+ error("failed to read target (ran out of stream)");
size -= target.size() + 1;
}
+ entry->argc = entry->targets.size();
if ((uint)(size % 2) != oldAlign) {
stream->skip(1);
size--;
}
- }
-
- if (entry->argc) {
+ } else if (entry->argc) {
entry->argvParam = new uint16[entry->argc];
entry->argvTarget = new uint16[entry->argc];
debug(4, "With %d targets:", entry->argc);
@@ -2075,37 +2096,33 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
debug(4, "kLBOpSendExpression: offset %08x", entry->offset);
size -= 4;
}
- if (entry->opcode == 0xffff) {
+ if (entry->opcode == kLBOpRunData) {
if (size < 4)
- error("didn't get enough bytes (%d) to read message in script entry", size);
- uint16 msgId = stream->readUint16();
- uint16 msgLen = stream->readUint16();
+ error("didn't get enough bytes (%d) to read data header in script entry", size);
+ entry->dataType = stream->readUint16();
+ entry->dataLen = stream->readUint16();
size -= 4;
- if (msgId == kLBSetPlayInfo) {
- if (size != 20)
- error("wah, more than just the kLBSetPlayInfo in here");
- // FIXME
- warning("ignoring kLBSetPlayInfo");
- size -= 20;
- stream->skip(20);
- return entry;
- }
- if (msgId != kLBCommand)
- error("expected a command in script entry, got 0x%04x", msgId);
+ if (size < entry->dataLen)
+ error("didn't get enough bytes (%d) to read data in script entry", size);
- if (msgLen != size - (entry->event == kLBEventNotified ? 4 : 0) && !conditionTag)
- error("script entry msgLen %d is not equal to size %d", msgLen, size);
-
- Common::String command = _vm->readString(stream);
- if (command.size() + 1 > size) {
- error("failed to read command in script entry: msgLen %d, command '%s' (%d chars)",
- msgLen, command.c_str(), command.size());
+ if (entry->dataType == kLBCommand) {
+ Common::String command = _vm->readString(stream);
+ uint commandSize = command.size() + 1;
+ if (commandSize > entry->dataLen)
+ error("failed to read command in script entry: dataLen %d, command '%s' (%d chars)",
+ entry->dataLen, command.c_str(), commandSize);
+ entry->dataLen = commandSize;
+ entry->data = new byte[commandSize];
+ memcpy(entry->data, command.c_str(), commandSize);
+ size -= commandSize;
+ } else {
+ if (conditionTag)
+ error("kLBOpRunData had unexpected conditionTag");
+ entry->data = new byte[entry->dataLen];
+ stream->read(entry->data, entry->dataLen);
+ size -= entry->dataLen;
}
- size -= command.size() + 1;
-
- entry->command = command;
- debug(4, "script entry command '%s'", command.c_str());
}
if (entry->event == kLBEventNotified) {
if (size < 4)
@@ -2126,6 +2143,8 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
}
if (conditionTag == 1) {
+ if (!size)
+ error("failed to read condition (empty stream)");
Common::String condition = _vm->readString(stream);
if (condition.size() == 0) {
size--;
@@ -2140,6 +2159,8 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
entry->conditions.push_back(condition);
debug(4, "script entry condition '%s'", condition.c_str());
} else if (conditionTag == 2) {
+ if (size < 4)
+ error("expected more than %d bytes for conditionTag 2", size);
// FIXME
stream->skip(4);
size -= 4;
@@ -2156,7 +2177,12 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Seeka
return entry;
}
-void LBItem::readData(uint16 type, uint16 size, Common::SeekableSubReadStreamEndian *stream) {
+void LBItem::readData(uint16 type, uint16 size, byte *data) {
+ Common::MemoryReadStreamEndian stream(data, size, _vm->isBigEndian());
+ readData(type, size, &stream);
+}
+
+void LBItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *stream) {
switch (type) {
case kLBMsgListScript:
case kLBNotifyScript:
@@ -2612,15 +2638,59 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) {
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;
+ switch (entry->targetingType) {
+ case kTargetTypeExpression:
+ {
+ // FIXME: this should be EVALUATED
+ LBValue &tgt = _vm->_variables[entry->targets[n]];
+ switch (tgt.type) {
+ case kLBValueItemPtr:
+ target = tgt.item;
+ break;
+ case kLBValueString:
+ // FIXME: handle 'self', at least
+ // TODO: correct otherwise? or only self?
+ target = _vm->getItemByName(tgt.string);
+ break;
+ case kLBValueInteger:
+ target = _vm->getItemById(tgt.integer);
+ break;
+ default:
+ // FIXME: handle list
+ warning("Target '%s' (by expression) resulted in unknown type, skipping", entry->targets[n].c_str());
+ continue;
+ }
+ }
+ if (!target) {
+ debug(2, "Target '%s' (by expression) doesn't exist, skipping", entry->targets[n].c_str());
+ continue;
+ }
+ debug(2, "Target: '%s' (expression '%s')", target->_desc.c_str(), entry->targets[n].c_str());
+ break;
+ case kTargetTypeCode:
+ // FIXME
+ error("encountered kTargetTypeCode");
+ break;
+ case kTargetTypeName:
+ // FIXME: handle 'self'
+ target = _vm->getItemByName(entry->targets[n]);
+ if (!target) {
+ debug(2, "Target '%s' (by name) doesn't exist, skipping", entry->targets[n].c_str());
+ continue;
+ }
+ debug(2, "Target: '%s' (by name)", target->_desc.c_str());
+ break;
+ default:
+ 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, target->_desc.c_str());
}
- debug(2, "Target: %04x (%04x) '%s'", targetId, param, target->_desc.c_str());
} else {
target = this;
debug(2, "Self-target on '%s'", _desc.c_str());
@@ -2781,8 +2851,8 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) {
}
break;
- case kLBOpRunCommand:
- runCommand(entry->command);
+ case kLBOpRunData:
+ readData(entry->dataType, entry->dataLen, entry->data);
break;
case kLBOpJumpUnlessExpression:
@@ -3118,7 +3188,7 @@ LBGroupItem::LBGroupItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rec
_starting = false;
}
-void LBGroupItem::readData(uint16 type, uint16 size, Common::SeekableSubReadStreamEndian *stream) {
+void LBGroupItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *stream) {
switch (type) {
case kLBGroupData:
{
@@ -3239,7 +3309,7 @@ LBPaletteItem::~LBPaletteItem() {
delete[] _palette;
}
-void LBPaletteItem::readData(uint16 type, uint16 size, Common::SeekableSubReadStreamEndian *stream) {
+void LBPaletteItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *stream) {
switch (type) {
case kLBPaletteXData:
{
@@ -3319,7 +3389,7 @@ LBLiveTextItem::LBLiveTextItem(MohawkEngine_LivingBooks *vm, LBPage *page, Commo
debug(3, "new LBLiveTextItem");
}
-void LBLiveTextItem::readData(uint16 type, uint16 size, Common::SeekableSubReadStreamEndian *stream) {
+void LBLiveTextItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *stream) {
switch (type) {
case kLBLiveTextData:
{
@@ -3564,7 +3634,7 @@ LBPictureItem::LBPictureItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common:
debug(3, "new LBPictureItem");
}
-void LBPictureItem::readData(uint16 type, uint16 size, Common::SeekableSubReadStreamEndian *stream) {
+void LBPictureItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *stream) {
switch (type) {
case kLBSetDrawMode:
{
@@ -3790,8 +3860,8 @@ void LBProxyItem::init() {
}
debug(1, "LBProxyItem loading archive '%s' with id %d", filename.c_str(), baseId);
- MohawkArchive *pageArchive = _vm->createMohawkArchive();
- if (!pageArchive->open(filename))
+ Archive *pageArchive = _vm->createArchive();
+ if (!pageArchive->openFile(filename))
error("failed to open archive '%s' (for proxy '%s')", filename.c_str(), _desc.c_str());
_page = new LBPage(_vm);
_page->open(pageArchive, baseId);