MOHAWK: Cleanup Myst script handling

Scripts are now loaded from a central place and are properly freed at the correct time. This fixes a regression from r54152.

svn-id: r54309
This commit is contained in:
Matthew Hoops 2010-11-18 05:47:16 +00:00
parent 8ebee136b6
commit d971396572
4 changed files with 101 additions and 139 deletions

View File

@ -29,7 +29,6 @@
#include "mohawk/graphics.h"
#include "mohawk/myst.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/myst_saveload.h"
#include "mohawk/dialogs.h"
#include "mohawk/resource.h"
@ -703,44 +702,10 @@ void MohawkEngine_Myst::runInitScript() {
debugC(kDebugINIT, "Running INIT script");
Common::SeekableReadStream *initStream = getRawData(ID_INIT, _view.init);
uint16 scriptCount = initStream->readUint16LE();
debugC(kDebugINIT, "\tOpcode Count: %d", scriptCount);
MystScriptEntry *scripts = new MystScriptEntry[scriptCount];
for (uint16 i = 0; i < scriptCount; i++) {
// TODO: u0 is likely variable reference for boolean to
// determine whether or not to execute opcode
uint16 u0 = initStream->readUint16LE();
scripts[i].opcode = initStream->readUint16LE();
// If variable indicates not to execute opcode, rewrite to NOP
//if (!_varStore->getVar(u0))
// scripts[i].opcode = 0xFFFF;
scripts[i].var = initStream->readUint16LE();
scripts[i].numValues = initStream->readUint16LE();
scripts[i].values = new uint16[scripts[i].numValues];
debugC(kDebugINIT, "\tu0: %d", u0);
debugC(kDebugINIT, "\tOpcode %d: %s", i, _scriptParser->getOpcodeDesc(scripts[i].opcode));
debugC(kDebugINIT, "\t\tUses Variable %d", scripts[i].var);
debugC(kDebugINIT, "\t\tHas %d Arguments:", scripts[i].numValues);
for (uint16 j = 0; j < scripts[i].numValues; j++) {
scripts[i].values[j] = initStream->readUint16LE();
debugC(kDebugINIT, "\t\tArgument %d: %d", j, scripts[i].values[j]);
}
}
MystScript script = _scriptParser->readScript(initStream, kMystScriptInit);
delete initStream;
_scriptParser->runScript(scriptCount, scripts);
for (uint16 i = 0; i < scriptCount; i++)
delete[] scripts[i].values;
delete[] scripts;
_scriptParser->runScript(script);
_gfx->updateScreen();
}
@ -753,49 +718,10 @@ void MohawkEngine_Myst::runExitScript() {
debugC(kDebugEXIT, "Running EXIT script");
Common::SeekableReadStream *exitStream = getRawData(ID_EXIT, _view.exit);
uint16 scriptCount = exitStream->readUint16LE();
debugC(kDebugEXIT, "\tOpcode Count: %d", scriptCount);
MystScriptEntry *scripts = new MystScriptEntry[scriptCount];
for (uint16 i = 0; i < scriptCount; i++) {
// TODO: u0 is likely variable reference for boolean to
// to determine whether or not to execute opcode (i.e. door
// close noises only when door is open).
uint16 u0 = exitStream->readUint16LE();
scripts[i].opcode = exitStream->readUint16LE();
// If variable indicates not to execute opcode, rewrite to NOP
//if (!_varStore->getVar(u0))
// scripts[i].opcode = 0xFFFF;
scripts[i].var = exitStream->readUint16LE();
scripts[i].numValues = exitStream->readUint16LE();
scripts[i].values = new uint16[scripts[i].numValues];
debugC(kDebugEXIT, "\tu0: %d", u0);
debugC(kDebugEXIT, "\tOpcode %d: %s", i, _scriptParser->getOpcodeDesc(scripts[i].opcode));
debugC(kDebugEXIT, "\t\tUses Variable %d", scripts[i].var);
debugC(kDebugEXIT, "\t\tHas %d Arguments:", scripts[i].numValues);
for (uint16 j = 0; j < scripts[i].numValues; j++) {
scripts[i].values[j] = exitStream->readUint16LE();
debugC(kDebugEXIT, "\t\tArgument %d: %d", j, scripts[i].values[j]);
}
uint16 u1 = exitStream->readUint16LE();
if (u1 != 1)
warning("Myst EXIT u1 not 1");
}
MystScript script = _scriptParser->readScript(exitStream, kMystScriptExit);
delete exitStream;
_scriptParser->runScript(scriptCount, scripts);
for (uint16 i = 0; i < scriptCount; i++)
delete[] scripts[i].values;
delete[] scripts;
_scriptParser->runScript(script);
_gfx->updateScreen();
}
@ -1059,40 +985,11 @@ void MystResource::handleMouseUp() {
MystResourceType5::MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) {
debugC(kDebugResource, "\tResource Type 5 Script:");
_scripts = NULL;
_scriptCount = rlstStream->readUint16LE();
debugC(kDebugResource, "\tOpcode Count: %d", _scriptCount);
if (_scriptCount == 0)
return;
_scripts = new MystScriptEntry[_scriptCount];
for (uint16 i = 0; i < _scriptCount; i++) {
_scripts[i].opcode = rlstStream->readUint16LE();
_scripts[i].var = rlstStream->readUint16LE();
_scripts[i].numValues = rlstStream->readUint16LE();
_scripts[i].values = new uint16[_scripts[i].numValues];
debugC(kDebugResource, "\tOpcode %d: %s", i, _vm->_scriptParser->getOpcodeDesc(_scripts[i].opcode));
debugC(kDebugResource, "\t\tUses Variable %d", _scripts[i].var);
debugC(kDebugResource, "\t\tHas %d Arguments:", _scripts[i].numValues);
for (uint16 j = 0; j < _scripts[i].numValues; j++) {
_scripts[i].values[j] = rlstStream->readUint16LE();
debugC(kDebugResource, "\t\tArgument %d: %d", j, _scripts[i].values[j]);
}
}
}
MystResourceType5::~MystResourceType5() {
for (uint16 i = 0; i < _scriptCount; i++)
delete[] _scripts[i].values;
delete[] _scripts;
_script = vm->_scriptParser->readScript(rlstStream, kMystScriptNormal);
}
void MystResourceType5::handleMouseUp() {
_vm->_scriptParser->runScript(_scriptCount, _scripts, this);
_vm->_scriptParser->runScript(_script, this);
}
// In Myst/Making of Myst, the paths are hardcoded ala Windows style without extension. Convert them.

View File

@ -30,6 +30,7 @@
#include "mohawk/mohawk.h"
#include "mohawk/resource_cache.h"
#include "mohawk/myst_vars.h"
#include "mohawk/myst_scripts.h"
#include "gui/saveload.h"
@ -147,13 +148,6 @@ struct MystView {
uint16 exit;
};
struct MystScriptEntry {
uint16 opcode;
uint16 var;
uint16 numValues;
uint16 *values;
};
class MystResource {
public:
MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
@ -188,12 +182,10 @@ protected:
class MystResourceType5 : public MystResource {
public:
MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent);
virtual ~MystResourceType5();
void handleMouseUp();
protected:
uint16 _scriptCount;
MystScriptEntry *_scripts;
MystScript _script;
};
class MystResourceType6 : public MystResourceType5 {

View File

@ -33,6 +33,19 @@
namespace Mohawk {
MystScriptEntry::MystScriptEntry() {
type = kMystScriptNone;
var = 0;
argc = 0;
argv = 0;
u0 = 0;
u1 = 0;
}
MystScriptEntry::~MystScriptEntry() {
delete[] argv;
}
const uint8 stack_map[8] = {
kSeleniticStack,
kStoneshipStack,
@ -78,12 +91,12 @@ void MystScriptParser::setupOpcodes() {
OPCODE(2, altDest),
OPCODE(3, takePage),
OPCODE(4, opcode_4),
// TODO: Opcode 5 Not Present
// Opcode 5 Not Present
OPCODE(6, opcode_6),
OPCODE(7, opcode_7),
OPCODE(8, opcode_8),
OPCODE(9, opcode_9),
// TODO: Opcode 10 to 11 Not Present
// Opcode 10 to 11 Not Present
OPCODE(12, altDest),
OPCODE(13, altDest),
OPCODE(14, opcode_14),
@ -97,7 +110,7 @@ void MystScriptParser::setupOpcodes() {
OPCODE(22, opcode_22),
OPCODE(23, opcode_23),
OPCODE(24, playSound),
// TODO: Opcode 25 Not Present
// Opcode 25 Not Present
OPCODE(26, opcode_26),
OPCODE(27, playSoundBlocking),
OPCODE(28, opcode_28),
@ -117,9 +130,9 @@ void MystScriptParser::setupOpcodes() {
OPCODE(42, opcode_42),
OPCODE(43, opcode_43),
OPCODE(44, opcode_44),
// TODO: Opcode 45 Not Present
// Opcode 45 Not Present
OPCODE(46, opcode_46),
// TODO: Opcodes 47 to 99 Not Present
// Opcodes 47 to 99 Not Present
// "Stack-Specific" Opcodes
OPCODE(100, opcode_100),
@ -156,18 +169,18 @@ void MystScriptParser::setupOpcodes() {
OPCODE(131, opcode_131),
OPCODE(132, opcode_132),
OPCODE(133, opcode_133),
// TODO: Opcodes 134 to 146 Not Present
// Opcodes 134 to 146 Not Present
OPCODE(147, opcode_147),
// TODO: Opcodes 148 to 163 Not Present
// Opcodes 148 to 163 Not Present
OPCODE(164, opcode_164),
// TODO: Opcodes 165 to 168 Not Present
// Opcodes 165 to 168 Not Present
OPCODE(169, opcode_169),
// TODO: Opcodes 170 to 181 Not Present
// Opcodes 170 to 181 Not Present
OPCODE(182, opcode_182),
OPCODE(183, opcode_183),
OPCODE(184, opcode_184),
OPCODE(185, opcode_185),
// TODO: Opcodes 186 to 195 Not Present
// Opcodes 186 to 195 Not Present
OPCODE(196, opcode_196), // Demo only
OPCODE(197, opcode_197), // Demo only
OPCODE(198, opcode_198),
@ -197,7 +210,7 @@ void MystScriptParser::setupOpcodes() {
OPCODE(220, opcode_220),
OPCODE(221, opcode_221),
OPCODE(222, opcode_222),
// TODO: Opcodes 223 to 297 Not Present
// Opcodes 223 to 297 Not Present
OPCODE(298, opcode_298), // Demo only
OPCODE(299, opcode_299), // Demo only
@ -212,9 +225,9 @@ void MystScriptParser::setupOpcodes() {
OPCODE(307, opcode_307),
OPCODE(308, opcode_308),
OPCODE(309, opcode_309),
// TODO: Opcodes 310 to 311 Not Present
// Opcodes 310 to 311 Not Present
OPCODE(312, opcode_312),
// TODO: Opcodes 313 and greater Not Present
// Opcodes 313 and greater Not Present
OPCODE(0xFFFF, NOP)
};
@ -251,13 +264,14 @@ void MystScriptParser::runPersistentOpcodes() {
opcode_212_run();
}
void MystScriptParser::runScript(uint16 scriptCount, MystScriptEntry *scripts, MystResource *invokingResource) {
void MystScriptParser::runScript(MystScript script, MystResource *invokingResource) {
_invokingResource = invokingResource;
debugC(kDebugScript, "Script Count: %d", scriptCount);
for (uint16 i = 0; i < scriptCount; i++) {
debugC(kDebugScript, "\tOpcode %d: %d", i, scripts[i].opcode);
runOpcode(scripts[i].opcode, scripts[i].var, scripts[i].numValues, scripts[i].values);
debugC(kDebugScript, "Script Size: %d", script->size());
for (uint16 i = 0; i < script->size(); i++) {
MystScriptEntry &entry = script->operator[](i);
debugC(kDebugScript, "\tOpcode %d: %d", i, entry.opcode);
runOpcode(entry.opcode, entry.var, entry.argc, entry.argv);
}
}
@ -284,6 +298,41 @@ const char *MystScriptParser::getOpcodeDesc(uint16 op) {
return "";
}
MystScript MystScriptParser::readScript(Common::SeekableReadStream *stream, MystScriptType type) {
assert(stream);
assert(type != kMystScriptNone);
MystScript script = MystScript(new Common::Array<MystScriptEntry>());
uint16 opcodeCount = stream->readUint16LE();
script->resize(opcodeCount);
for (uint16 i = 0; i < opcodeCount; i++) {
MystScriptEntry &entry = script->operator[](i);
entry.type = type;
// u0 only exists in INIT and EXIT scripts
if (type != kMystScriptNormal)
entry.u0 = stream->readUint16LE();
entry.opcode = stream->readUint16LE();
entry.var = stream->readUint16LE();
entry.argc = stream->readUint16LE();
if (entry.argc > 0) {
entry.argv = new uint16[entry.argc];
for (uint16 j = 0; j < entry.argc; j++)
entry.argv[j] = stream->readUint16LE();
}
// u1 exists only in EXIT scripts
if (type == kMystScriptExit)
entry.u1 = stream->readUint16LE();
}
return script;
}
// NOTE: Check to be used on Opcodes where var is thought
// not to be used. This emits a warning if var is nonzero.
// It is possible that the opcode does use var 0 in this case,

View File

@ -26,6 +26,7 @@
#ifndef MYST_SCRIPTS_H
#define MYST_SCRIPTS_H
#include "common/ptr.h"
#include "common/scummsys.h"
#include "common/util.h"
@ -34,16 +35,39 @@ namespace Mohawk {
#define DECLARE_OPCODE(x) void x(uint16 op, uint16 var, uint16 argc, uint16 *argv)
class MohawkEngine_Myst;
struct MystScriptEntry;
class MystResource;
enum MystScriptType {
kMystScriptNone,
kMystScriptNormal,
kMystScriptInit,
kMystScriptExit
};
struct MystScriptEntry {
MystScriptEntry();
~MystScriptEntry();
MystScriptType type;
uint16 u0;
uint16 opcode;
uint16 var;
uint16 argc;
uint16 *argv;
uint16 u1;
};
typedef Common::SharedPtr<Common::Array<MystScriptEntry> > MystScript;
class MystScriptParser {
public:
MystScriptParser(MohawkEngine_Myst *vm);
~MystScriptParser();
void runScript(uint16 scriptCount, MystScriptEntry *scripts, MystResource* invokingResource = NULL);
void runScript(MystScript script, MystResource *invokingResource = NULL);
void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = NULL);
const char *getOpcodeDesc(uint16 op);
MystScript readScript(Common::SeekableReadStream *stream, MystScriptType type);
void disableInitOpcodes();
void runPersistentOpcodes();