- Implemented "stand-alone" script dumper/disassembler; it can be enabled by defining DUMP_SCRIPTS in script.h and starting with at least debug level 1.

- Commented which script opcodes and extended functions are actually used or not.

svn-id: r32202
This commit is contained in:
Benjamin Haisch 2008-05-20 20:00:10 +00:00
parent 11697c0eb2
commit 828a217a03
6 changed files with 237 additions and 84 deletions

View file

@ -95,6 +95,8 @@ public:
return NULL; return NULL;
} }
uint getObjectCount() const { return _objects.size(); }
int16 getMainCodeObjectIndex() const { return _mainCodeObjectIndex; } int16 getMainCodeObjectIndex() const { return _mainCodeObjectIndex; }
int16 getVar(int16 index); int16 getVar(int16 index);

View file

@ -206,7 +206,12 @@ int MadeEngine::go() {
} }
_eventKey = _eventMouseX = _eventMouseY = 0; _eventKey = _eventMouseX = _eventMouseY = 0;
#ifdef DUMP_SCRIPTS
_script->dumpAllScripts();
#else
_script->runScript(_dat->getMainCodeObjectIndex()); _script->runScript(_dat->getMainCodeObjectIndex());
#endif
return 0; return 0;
} }

View file

@ -91,83 +91,87 @@ int16 *ScriptStack::getStackPtr() {
/* ScriptInterpreter */ /* ScriptInterpreter */
ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) { ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) {
#define COMMAND(x) { &ScriptInterpreter::x, #x } #ifdef DUMP_SCRIPTS
#define COMMAND(x, sig) { &ScriptInterpreter::x, #x, sig }
#else
#define COMMAND(x, sig) { &ScriptInterpreter::x, #x}
#endif
static CommandEntry commandProcs[] = { static CommandEntry commandProcs[] = {
/* 01 */ /* 01 */
COMMAND(cmd_branchTrue), COMMAND(cmd_branchTrue, "W"),
COMMAND(cmd_branchFalse), COMMAND(cmd_branchFalse, "W"),
COMMAND(cmd_branch), COMMAND(cmd_branch, "W"),
COMMAND(cmd_true), COMMAND(cmd_true, ""),
/* 05 */ /* 05 */
COMMAND(cmd_false), COMMAND(cmd_false, ""),
COMMAND(cmd_push), COMMAND(cmd_push, ""),
COMMAND(cmd_not), COMMAND(cmd_not, ""),
COMMAND(cmd_add), COMMAND(cmd_add, ""),
/* 09 */ /* 09 */
COMMAND(cmd_sub), COMMAND(cmd_sub, ""),
COMMAND(cmd_mul), COMMAND(cmd_mul, ""),
COMMAND(cmd_div), COMMAND(cmd_div, ""),
COMMAND(cmd_mod), COMMAND(cmd_mod, ""),
/* 13 */ /* 13 */
COMMAND(cmd_band), COMMAND(cmd_band, ""),
COMMAND(cmd_bor), COMMAND(cmd_bor, ""),
COMMAND(cmd_bnot), COMMAND(cmd_bnot, ""),
COMMAND(cmd_lt), COMMAND(cmd_lt, ""),
/* 17 */ /* 17 */
COMMAND(cmd_eq), COMMAND(cmd_eq, ""),
COMMAND(cmd_gt), COMMAND(cmd_gt, ""),
COMMAND(cmd_loadConstant), COMMAND(cmd_loadConstant, "w"),
COMMAND(cmd_loadVariable), COMMAND(cmd_loadVariable, "w"),
/* 21 */ /* 21 */
COMMAND(cmd_getObjectProperty), COMMAND(cmd_getObjectProperty, ""),
COMMAND(cmd_setObjectProperty), COMMAND(cmd_setObjectProperty, ""),
COMMAND(cmd_set), COMMAND(cmd_set, "w"),
COMMAND(cmd_print), COMMAND(cmd_print, ""),
/* 25 */ /* 25 */
COMMAND(cmd_terpri), COMMAND(cmd_terpri, ""),
COMMAND(cmd_printNumber), COMMAND(cmd_printNumber, ""),
COMMAND(cmd_vref), COMMAND(cmd_vref, ""),
COMMAND(cmd_vset), COMMAND(cmd_vset, ""),
/* 29 */ /* 29 */
COMMAND(cmd_vsize), COMMAND(cmd_vsize, ""),
COMMAND(cmd_exit), COMMAND(cmd_exit, ""),
COMMAND(cmd_return), COMMAND(cmd_return, ""),
COMMAND(cmd_call), COMMAND(cmd_call, "b"),
/* 33 */ /* 33 */
COMMAND(cmd_svar), COMMAND(cmd_svar, ""),
COMMAND(cmd_sset), COMMAND(cmd_sset, ""),
COMMAND(cmd_split), COMMAND(cmd_split, ""),
COMMAND(cmd_snlit), COMMAND(cmd_snlit, ""),
/* 37 */ /* 37 */
COMMAND(cmd_yorn), COMMAND(cmd_yorn, ""),
COMMAND(cmd_save), COMMAND(cmd_save, ""),
COMMAND(cmd_restore), COMMAND(cmd_restore, ""),
COMMAND(cmd_arg), COMMAND(cmd_arg, "b"),
/* 41 */ /* 41 */
COMMAND(cmd_aset), COMMAND(cmd_aset, "b"),
COMMAND(cmd_tmp), COMMAND(cmd_tmp, "b"),
COMMAND(cmd_tset), COMMAND(cmd_tset, "b"),
COMMAND(cmd_tspace), COMMAND(cmd_tspace, "b"),
/* 45 */ /* 45 */
COMMAND(cmd_class), COMMAND(cmd_class, ""),
COMMAND(cmd_objectp), COMMAND(cmd_objectp, ""),
COMMAND(cmd_vectorp), COMMAND(cmd_vectorp, ""),
COMMAND(cmd_restart), COMMAND(cmd_restart, ""),
/* 49 */ /* 49 */
COMMAND(cmd_rand), COMMAND(cmd_rand, ""),
COMMAND(cmd_randomize), COMMAND(cmd_randomize, ""),
COMMAND(cmd_send), COMMAND(cmd_send, "b"),
COMMAND(cmd_extend), COMMAND(cmd_extend, "Eb"),
/* 53 */ /* 53 */
COMMAND(cmd_catch), COMMAND(cmd_catch, ""),
COMMAND(cmd_cdone), COMMAND(cmd_cdone, ""),
COMMAND(cmd_throw), COMMAND(cmd_throw, ""),
COMMAND(cmd_functionp), COMMAND(cmd_functionp, ""),
/* 57 */ /* 57 */
COMMAND(cmd_le), COMMAND(cmd_le, ""),
COMMAND(cmd_ge), COMMAND(cmd_ge, ""),
COMMAND(cmd_varx), COMMAND(cmd_varx, ""),
COMMAND(cmd_setx) COMMAND(cmd_setx, "")
}; };
_commands = commandProcs; _commands = commandProcs;
_commandsMax = ARRAYSIZE(commandProcs) + 1; _commandsMax = ARRAYSIZE(commandProcs) + 1;
@ -175,9 +179,6 @@ ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) {
_functions = new ScriptFunctions(_vm); _functions = new ScriptFunctions(_vm);
_functions->setupExternalsTable(); _functions->setupExternalsTable();
// set to true to dump scripts instead of parsing them
_dumpScripts = false;
#undef COMMAND #undef COMMAND
} }
@ -217,27 +218,18 @@ int16 ScriptInterpreter::readInt16() {
} }
void ScriptInterpreter::cmd_branchTrue() { void ScriptInterpreter::cmd_branchTrue() {
if (_dumpScripts)
return;
int16 ofs = readInt16(); int16 ofs = readInt16();
if (_stack.top() != 0) if (_stack.top() != 0)
_codeIp = _codeBase + ofs; _codeIp = _codeBase + ofs;
} }
void ScriptInterpreter::cmd_branchFalse() { void ScriptInterpreter::cmd_branchFalse() {
if (_dumpScripts)
return;
int16 ofs = readInt16(); int16 ofs = readInt16();
if (_stack.top() == 0) if (_stack.top() == 0)
_codeIp = _codeBase + ofs; _codeIp = _codeBase + ofs;
} }
void ScriptInterpreter::cmd_branch() { void ScriptInterpreter::cmd_branch() {
if (_dumpScripts)
return;
int16 ofs = readInt16(); int16 ofs = readInt16();
_codeIp = _codeBase + ofs; _codeIp = _codeBase + ofs;
} }
@ -459,29 +451,31 @@ void ScriptInterpreter::cmd_call() {
} }
void ScriptInterpreter::cmd_svar() { void ScriptInterpreter::cmd_svar() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_svar"); warning("Unimplemented command: cmd_svar");
} }
void ScriptInterpreter::cmd_sset() { void ScriptInterpreter::cmd_sset() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_sset"); warning("Unimplemented command: cmd_sset");
} }
void ScriptInterpreter::cmd_split() { void ScriptInterpreter::cmd_split() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_split"); warning("Unimplemented command: cmd_split");
} }
void ScriptInterpreter::cmd_snlit() { void ScriptInterpreter::cmd_snlit() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_snlit"); warning("Unimplemented command: cmd_snlit");
} }
void ScriptInterpreter::cmd_yorn() { void ScriptInterpreter::cmd_yorn() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_yorn"); warning("Unimplemented command: cmd_yorn");
} }
void ScriptInterpreter::cmd_save() { void ScriptInterpreter::cmd_save() {
if (_dumpScripts)
return;
int16 result = 0; int16 result = 0;
int16 stringOfs = _stack.top(); int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs); const char *filename = _vm->_dat->getString(stringOfs);
@ -490,9 +484,6 @@ void ScriptInterpreter::cmd_save() {
} }
void ScriptInterpreter::cmd_restore() { void ScriptInterpreter::cmd_restore() {
if (_dumpScripts)
return;
int16 result = 0; int16 result = 0;
int16 stringOfs = _stack.top(); int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs); const char *filename = _vm->_dat->getString(stringOfs);
@ -531,6 +522,7 @@ void ScriptInterpreter::cmd_tspace() {
} }
void ScriptInterpreter::cmd_class() { void ScriptInterpreter::cmd_class() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_class"); warning("Unimplemented command: cmd_class");
} }
@ -543,10 +535,12 @@ void ScriptInterpreter::cmd_objectp() {
} }
void ScriptInterpreter::cmd_vectorp() { void ScriptInterpreter::cmd_vectorp() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_vectorp"); warning("Unimplemented command: cmd_vectorp");
} }
void ScriptInterpreter::cmd_restart() { void ScriptInterpreter::cmd_restart() {
// TODO: Used in RTZ
warning("Unimplemented command: cmd_restart"); warning("Unimplemented command: cmd_restart");
} }
@ -613,9 +607,6 @@ void ScriptInterpreter::cmd_extend() {
for (int i = 0; i < argc; i++) for (int i = 0; i < argc; i++)
debug(2, "argv[%02d] = %04X (%d)", i, argv[i], argv[i]); debug(2, "argv[%02d] = %04X (%d)", i, argv[i], argv[i]);
if (_dumpScripts)
return;
int16 result = _functions->callFunction(func, argc, argv); int16 result = _functions->callFunction(func, argc, argv);
debug(2, "result = %04X (%d)", result, result); debug(2, "result = %04X (%d)", result, result);
@ -626,18 +617,22 @@ void ScriptInterpreter::cmd_extend() {
} }
void ScriptInterpreter::cmd_catch() { void ScriptInterpreter::cmd_catch() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_catch"); warning("Unimplemented command: cmd_catch");
} }
void ScriptInterpreter::cmd_cdone() { void ScriptInterpreter::cmd_cdone() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_cdone"); warning("Unimplemented command: cmd_cdone");
} }
void ScriptInterpreter::cmd_throw() { void ScriptInterpreter::cmd_throw() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_throw"); warning("Unimplemented command: cmd_throw");
} }
void ScriptInterpreter::cmd_functionp() { void ScriptInterpreter::cmd_functionp() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_functionp"); warning("Unimplemented command: cmd_functionp");
} }
@ -658,11 +653,133 @@ void ScriptInterpreter::cmd_ge() {
} }
void ScriptInterpreter::cmd_varx() { void ScriptInterpreter::cmd_varx() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_varx"); warning("Unimplemented command: cmd_varx");
} }
void ScriptInterpreter::cmd_setx() { void ScriptInterpreter::cmd_setx() {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_setx"); warning("Unimplemented command: cmd_setx");
} }
#ifdef DUMP_SCRIPTS
void ScriptInterpreter::dumpScript(int16 objectIndex, int *opcodeStats, int *externStats) {
debug(1, "Dumping code for object %04X", objectIndex);
Object *obj = _vm->_dat->getObject(objectIndex);
byte *code = obj->getData(), *codeEnd = code + obj->getSize();
while (code < codeEnd) {
byte opcode = *code++;
if (opcode >= 1 && opcode <= _commandsMax) {
Common::String codeLine;
const char *desc = _commands[opcode - 1].desc;
const char *sig = _commands[opcode - 1].sig;
int valueType; /* 0: dec; 1: hex; 2: extended function */
int16 value;
char tempStr[32];
if (opcodeStats)
opcodeStats[opcode - 1]++;
codeLine += desc;
for (; *sig != '\0'; sig++) {
codeLine += " ";
// Fallthroughs are intended
switch (*sig) {
case 'b':
valueType = 0;
value = *code++;
break;
case 'B':
valueType = 1;
value = *code++;
break;
case 'w':
valueType = 0;
value = READ_LE_UINT16(code);
code += 2;
break;
case 'W':
valueType = 1;
value = READ_LE_UINT16(code);
code += 2;
break;
case 'E':
valueType = 2;
value = *code++;
break;
}
switch (valueType) {
case 0:
snprintf(tempStr, 32, "%d", value);
break;
case 1:
snprintf(tempStr, 32, "0x%X", value);
break;
case 2:
if (value < _functions->getCount()) {
snprintf(tempStr, 32, "%s", _functions->getFuncName(value));
externStats[value]++;
} else {
snprintf(tempStr, 32, "invalid: %d", value);
}
break;
}
codeLine += tempStr;
}
debug(1, "%s", codeLine.c_str());
} else {
error("ScriptInterpreter::dumpScript(%d) Unknown opcode %02X", objectIndex, opcode);
}
}
debug(1, "-------------------------------------------");
}
void ScriptInterpreter::dumpAllScripts() {
int *opcodeStats = new int[_commandsMax - 1];
int *externStats = new int[_functions->getCount()];
for (int i = 0; i < _commandsMax; i++)
opcodeStats[i] = 0;
for (int i = 0; i < _functions->getCount(); i++)
externStats[i] = 0;
for (uint objectIndex = 1; objectIndex <= _vm->_dat->getObjectCount(); objectIndex++) {
Object *obj = _vm->_dat->getObject(objectIndex);
// Check if it's a byte array which might contain code
if (obj->getClass() != 0x7FFF)
continue;
// Code objects aren't excplicitly marked as such, we need to check if
// the last byte is a cmd_return opcode.
byte *retByte = obj->getData() + obj->getSize() - 1;
if (*retByte == 0x1F) {
dumpScript(objectIndex, opcodeStats, externStats);
}
}
debug(1, "OPCODE statistics:");
for (int i = 0; i < _commandsMax - 1; i++)
if (opcodeStats[i] > 0)
debug(1, "%-30s: %d", _commands[i].desc, opcodeStats[i]);
debug(1, "UNUSED OPCODE statistics:");
for (int i = 0; i < _commandsMax - 1; i++)
if (opcodeStats[i] == 0)
debug(1, "%-30s: %d", _commands[i].desc, opcodeStats[i]);
debug(1, ".");
debug(1, "EXTERN statistics (%d):", _functions->getCount());
for (int i = 0; i < _functions->getCount(); i++)
if (externStats[i] > 0)
debug(1, "%-30s: %d", _functions->getFuncName(i), externStats[i]);
debug(1, "UNUSED EXTERN statistics (%d):", _functions->getCount());
for (int i = 0; i < _functions->getCount(); i++)
if (externStats[i] == 0)
debug(1, "%-30s: %d", _functions->getFuncName(i), externStats[i]);
debug(1, ".");
delete[] opcodeStats;
delete[] externStats;
}
#endif
} // End of namespace Made } // End of namespace Made

View file

@ -32,6 +32,11 @@
namespace Made { namespace Made {
// Define this to dump all game scripts and a usage statistic of all
// opcodes/extended functions instead of running the actual game.
// Then run ScummVM with debuglevel 1.
//#define DUMP_SCRIPTS
class MadeEngine; class MadeEngine;
class ScriptFunctions; class ScriptFunctions;
@ -63,6 +68,8 @@ public:
ScriptInterpreter(MadeEngine *vm); ScriptInterpreter(MadeEngine *vm);
~ScriptInterpreter(); ~ScriptInterpreter();
void runScript(int16 scriptObjectIndex); void runScript(int16 scriptObjectIndex);
void dumpScript(int16 objectIndex, int *opcodeStats, int *externStats);
void dumpAllScripts();
protected: protected:
MadeEngine *_vm; MadeEngine *_vm;
@ -71,7 +78,6 @@ protected:
int16 _runningScriptObjectIndex; int16 _runningScriptObjectIndex;
byte *_codeBase, *_codeIp; byte *_codeBase, *_codeIp;
bool _terminated; bool _terminated;
bool _dumpScripts;
ScriptFunctions *_functions; ScriptFunctions *_functions;
@ -82,6 +88,9 @@ protected:
struct CommandEntry { struct CommandEntry {
CommandProc proc; CommandProc proc;
const char *desc; const char *desc;
#ifdef DUMP_SCRIPTS
const char *sig;
#endif
}; };
const CommandEntry *_commands; const CommandEntry *_commands;

View file

@ -319,6 +319,7 @@ int16 ScriptFunctions::sfIsMusicPlaying(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfSetTextPos(int16 argc, int16 *argv) { int16 ScriptFunctions::sfSetTextPos(int16 argc, int16 *argv) {
// TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfSetTextPos"); warning("Unimplemented opcode: sfSetTextPos");
// This seems to be some kind of low-level opcode. // This seems to be some kind of low-level opcode.
// The original engine calls int 10h to set the VGA cursor position. // The original engine calls int 10h to set the VGA cursor position.
@ -331,21 +332,25 @@ int16 ScriptFunctions::sfFlashScreen(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfPlayNote(int16 argc, int16 *argv) { int16 ScriptFunctions::sfPlayNote(int16 argc, int16 *argv) {
// TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfPlayNote"); warning("Unimplemented opcode: sfPlayNote");
return 0; return 0;
} }
int16 ScriptFunctions::sfStopNote(int16 argc, int16 *argv) { int16 ScriptFunctions::sfStopNote(int16 argc, int16 *argv) {
// TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfStopNote"); warning("Unimplemented opcode: sfStopNote");
return 0; return 0;
} }
int16 ScriptFunctions::sfPlayTele(int16 argc, int16 *argv) { int16 ScriptFunctions::sfPlayTele(int16 argc, int16 *argv) {
// TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfPlayTele"); warning("Unimplemented opcode: sfPlayTele");
return 0; return 0;
} }
int16 ScriptFunctions::sfStopTele(int16 argc, int16 *argv) { int16 ScriptFunctions::sfStopTele(int16 argc, int16 *argv) {
// TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfStopTele"); warning("Unimplemented opcode: sfStopTele");
return 0; return 0;
} }
@ -374,7 +379,7 @@ int16 ScriptFunctions::sfSetScreenLock(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfAddSprite(int16 argc, int16 *argv) { int16 ScriptFunctions::sfAddSprite(int16 argc, int16 *argv) {
if (_vm->getGameID() == GID_RTZ) { if (_vm->getGameID() == GID_RTZ) {
warning("Unimplemented opcode: sfAddSprite"); // Unused in RTZ
return 0; return 0;
} if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) { } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) {
return argv[2]; return argv[2];
@ -483,6 +488,7 @@ int16 ScriptFunctions::sfDrawText(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfHomeText(int16 argc, int16 *argv) { int16 ScriptFunctions::sfHomeText(int16 argc, int16 *argv) {
// TODO: Used in LGOP2
warning("Unimplemented opcode: sfHomeText"); warning("Unimplemented opcode: sfHomeText");
return 0; return 0;
} }
@ -542,6 +548,7 @@ int16 ScriptFunctions::sfSetSpriteGround(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfLoadResText(int16 argc, int16 *argv) { int16 ScriptFunctions::sfLoadResText(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfLoadResText"); warning("Unimplemented opcode: sfLoadResText");
return 0; return 0;
} }
@ -611,6 +618,7 @@ int16 ScriptFunctions::sfGetCdTime(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfPlayCdSegment(int16 argc, int16 *argv) { int16 ScriptFunctions::sfPlayCdSegment(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfPlayCdSegment"); warning("Unimplemented opcode: sfPlayCdSegment");
return 0; return 0;
} }
@ -623,6 +631,7 @@ int16 ScriptFunctions::sfPrintf(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfClearMono(int16 argc, int16 *argv) { int16 ScriptFunctions::sfClearMono(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfClearMono"); warning("Unimplemented opcode: sfClearMono");
return 0; return 0;
} }
@ -637,11 +646,13 @@ int16 ScriptFunctions::sfGetSoundEnergy(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfClearText(int16 argc, int16 *argv) { int16 ScriptFunctions::sfClearText(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfClearText"); warning("Unimplemented opcode: sfClearText");
return 1; return 1;
} }
int16 ScriptFunctions::sfAnimText(int16 argc, int16 *argv) { int16 ScriptFunctions::sfAnimText(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfAnimText"); warning("Unimplemented opcode: sfAnimText");
return 0; return 0;
} }
@ -692,11 +703,13 @@ int16 ScriptFunctions::sfLoadPicture(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfSetMusicVolume(int16 argc, int16 *argv) { int16 ScriptFunctions::sfSetMusicVolume(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetMusicVolume"); warning("Unimplemented opcode: sfSetMusicVolume");
return 0; return 0;
} }
int16 ScriptFunctions::sfRestartEvents(int16 argc, int16 *argv) { int16 ScriptFunctions::sfRestartEvents(int16 argc, int16 *argv) {
// TODO: Used in RTZ
warning("Unimplemented opcode: sfRestartEvents"); warning("Unimplemented opcode: sfRestartEvents");
return 0; return 0;
} }
@ -724,11 +737,13 @@ int16 ScriptFunctions::sfSetChannelState(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfSetChannelLocation(int16 argc, int16 *argv) { int16 ScriptFunctions::sfSetChannelLocation(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetChannelLocation"); warning("Unimplemented opcode: sfSetChannelLocation");
return 0; return 0;
} }
int16 ScriptFunctions::sfSetChannelContent(int16 argc, int16 *argv) { int16 ScriptFunctions::sfSetChannelContent(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetChannelContent"); warning("Unimplemented opcode: sfSetChannelContent");
return 0; return 0;
} }
@ -796,6 +811,7 @@ int16 ScriptFunctions::sfSetSoundRate(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfDrawAnimPic(int16 argc, int16 *argv) { int16 ScriptFunctions::sfDrawAnimPic(int16 argc, int16 *argv) {
// TODO: Used in RTZ
warning("Unimplemented opcode: sfDrawAnimPic"); warning("Unimplemented opcode: sfDrawAnimPic");
return 0; return 0;
} }
@ -810,6 +826,7 @@ int16 ScriptFunctions::sfLoadAnim(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfReadText(int16 argc, int16 *argv) { int16 ScriptFunctions::sfReadText(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfReadText"); warning("Unimplemented opcode: sfReadText");
return 0; return 0;
} }
@ -913,11 +930,13 @@ int16 ScriptFunctions::sfGetGameDescription(int16 argc, int16 *argv) {
} }
int16 ScriptFunctions::sfShakeScreen(int16 argc, int16 *argv) { int16 ScriptFunctions::sfShakeScreen(int16 argc, int16 *argv) {
// TODO: Used in RTZ
warning("Unimplemented opcode: sfShakeScreen"); warning("Unimplemented opcode: sfShakeScreen");
return 0; return 0;
} }
int16 ScriptFunctions::sfPlaceMenu(int16 argc, int16 *argv) { int16 ScriptFunctions::sfPlaceMenu(int16 argc, int16 *argv) {
// Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfPlaceMenu"); warning("Unimplemented opcode: sfPlaceMenu");
return 0; return 0;
} }

View file

@ -54,6 +54,7 @@ public:
} }
void setupExternalsTable(); void setupExternalsTable();
const char* getFuncName(int index) { return _externalFuncNames[index]; } const char* getFuncName(int index) { return _externalFuncNames[index]; }
int getCount() const { return _externalFuncs.size(); }
protected: protected:
MadeEngine *_vm; MadeEngine *_vm;
Audio::SoundHandle _audioStreamHandle; Audio::SoundHandle _audioStreamHandle;