aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/made/database.h2
-rw-r--r--engines/made/made.cpp5
-rw-r--r--engines/made/script.cpp281
-rw-r--r--engines/made/script.h11
-rw-r--r--engines/made/scriptfuncs.cpp21
-rw-r--r--engines/made/scriptfuncs.h1
6 files changed, 237 insertions, 84 deletions
diff --git a/engines/made/database.h b/engines/made/database.h
index 50e37d6936..0924200374 100644
--- a/engines/made/database.h
+++ b/engines/made/database.h
@@ -95,6 +95,8 @@ public:
return NULL;
}
+ uint getObjectCount() const { return _objects.size(); }
+
int16 getMainCodeObjectIndex() const { return _mainCodeObjectIndex; }
int16 getVar(int16 index);
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index 4ec857547b..76482b03bb 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -206,7 +206,12 @@ int MadeEngine::go() {
}
_eventKey = _eventMouseX = _eventMouseY = 0;
+
+#ifdef DUMP_SCRIPTS
+ _script->dumpAllScripts();
+#else
_script->runScript(_dat->getMainCodeObjectIndex());
+#endif
return 0;
}
diff --git a/engines/made/script.cpp b/engines/made/script.cpp
index 7d7ebc83cd..6b736e321b 100644
--- a/engines/made/script.cpp
+++ b/engines/made/script.cpp
@@ -91,83 +91,87 @@ int16 *ScriptStack::getStackPtr() {
/* ScriptInterpreter */
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[] = {
/* 01 */
- COMMAND(cmd_branchTrue),
- COMMAND(cmd_branchFalse),
- COMMAND(cmd_branch),
- COMMAND(cmd_true),
+ COMMAND(cmd_branchTrue, "W"),
+ COMMAND(cmd_branchFalse, "W"),
+ COMMAND(cmd_branch, "W"),
+ COMMAND(cmd_true, ""),
/* 05 */
- COMMAND(cmd_false),
- COMMAND(cmd_push),
- COMMAND(cmd_not),
- COMMAND(cmd_add),
+ COMMAND(cmd_false, ""),
+ COMMAND(cmd_push, ""),
+ COMMAND(cmd_not, ""),
+ COMMAND(cmd_add, ""),
/* 09 */
- COMMAND(cmd_sub),
- COMMAND(cmd_mul),
- COMMAND(cmd_div),
- COMMAND(cmd_mod),
+ COMMAND(cmd_sub, ""),
+ COMMAND(cmd_mul, ""),
+ COMMAND(cmd_div, ""),
+ COMMAND(cmd_mod, ""),
/* 13 */
- COMMAND(cmd_band),
- COMMAND(cmd_bor),
- COMMAND(cmd_bnot),
- COMMAND(cmd_lt),
+ COMMAND(cmd_band, ""),
+ COMMAND(cmd_bor, ""),
+ COMMAND(cmd_bnot, ""),
+ COMMAND(cmd_lt, ""),
/* 17 */
- COMMAND(cmd_eq),
- COMMAND(cmd_gt),
- COMMAND(cmd_loadConstant),
- COMMAND(cmd_loadVariable),
+ COMMAND(cmd_eq, ""),
+ COMMAND(cmd_gt, ""),
+ COMMAND(cmd_loadConstant, "w"),
+ COMMAND(cmd_loadVariable, "w"),
/* 21 */
- COMMAND(cmd_getObjectProperty),
- COMMAND(cmd_setObjectProperty),
- COMMAND(cmd_set),
- COMMAND(cmd_print),
+ COMMAND(cmd_getObjectProperty, ""),
+ COMMAND(cmd_setObjectProperty, ""),
+ COMMAND(cmd_set, "w"),
+ COMMAND(cmd_print, ""),
/* 25 */
- COMMAND(cmd_terpri),
- COMMAND(cmd_printNumber),
- COMMAND(cmd_vref),
- COMMAND(cmd_vset),
+ COMMAND(cmd_terpri, ""),
+ COMMAND(cmd_printNumber, ""),
+ COMMAND(cmd_vref, ""),
+ COMMAND(cmd_vset, ""),
/* 29 */
- COMMAND(cmd_vsize),
- COMMAND(cmd_exit),
- COMMAND(cmd_return),
- COMMAND(cmd_call),
+ COMMAND(cmd_vsize, ""),
+ COMMAND(cmd_exit, ""),
+ COMMAND(cmd_return, ""),
+ COMMAND(cmd_call, "b"),
/* 33 */
- COMMAND(cmd_svar),
- COMMAND(cmd_sset),
- COMMAND(cmd_split),
- COMMAND(cmd_snlit),
+ COMMAND(cmd_svar, ""),
+ COMMAND(cmd_sset, ""),
+ COMMAND(cmd_split, ""),
+ COMMAND(cmd_snlit, ""),
/* 37 */
- COMMAND(cmd_yorn),
- COMMAND(cmd_save),
- COMMAND(cmd_restore),
- COMMAND(cmd_arg),
+ COMMAND(cmd_yorn, ""),
+ COMMAND(cmd_save, ""),
+ COMMAND(cmd_restore, ""),
+ COMMAND(cmd_arg, "b"),
/* 41 */
- COMMAND(cmd_aset),
- COMMAND(cmd_tmp),
- COMMAND(cmd_tset),
- COMMAND(cmd_tspace),
+ COMMAND(cmd_aset, "b"),
+ COMMAND(cmd_tmp, "b"),
+ COMMAND(cmd_tset, "b"),
+ COMMAND(cmd_tspace, "b"),
/* 45 */
- COMMAND(cmd_class),
- COMMAND(cmd_objectp),
- COMMAND(cmd_vectorp),
- COMMAND(cmd_restart),
+ COMMAND(cmd_class, ""),
+ COMMAND(cmd_objectp, ""),
+ COMMAND(cmd_vectorp, ""),
+ COMMAND(cmd_restart, ""),
/* 49 */
- COMMAND(cmd_rand),
- COMMAND(cmd_randomize),
- COMMAND(cmd_send),
- COMMAND(cmd_extend),
+ COMMAND(cmd_rand, ""),
+ COMMAND(cmd_randomize, ""),
+ COMMAND(cmd_send, "b"),
+ COMMAND(cmd_extend, "Eb"),
/* 53 */
- COMMAND(cmd_catch),
- COMMAND(cmd_cdone),
- COMMAND(cmd_throw),
- COMMAND(cmd_functionp),
+ COMMAND(cmd_catch, ""),
+ COMMAND(cmd_cdone, ""),
+ COMMAND(cmd_throw, ""),
+ COMMAND(cmd_functionp, ""),
/* 57 */
- COMMAND(cmd_le),
- COMMAND(cmd_ge),
- COMMAND(cmd_varx),
- COMMAND(cmd_setx)
+ COMMAND(cmd_le, ""),
+ COMMAND(cmd_ge, ""),
+ COMMAND(cmd_varx, ""),
+ COMMAND(cmd_setx, "")
};
_commands = commandProcs;
_commandsMax = ARRAYSIZE(commandProcs) + 1;
@@ -175,9 +179,6 @@ ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) {
_functions = new ScriptFunctions(_vm);
_functions->setupExternalsTable();
- // set to true to dump scripts instead of parsing them
- _dumpScripts = false;
-
#undef COMMAND
}
@@ -217,27 +218,18 @@ int16 ScriptInterpreter::readInt16() {
}
void ScriptInterpreter::cmd_branchTrue() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
if (_stack.top() != 0)
_codeIp = _codeBase + ofs;
}
void ScriptInterpreter::cmd_branchFalse() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
if (_stack.top() == 0)
_codeIp = _codeBase + ofs;
}
void ScriptInterpreter::cmd_branch() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
_codeIp = _codeBase + ofs;
}
@@ -459,29 +451,31 @@ void ScriptInterpreter::cmd_call() {
}
void ScriptInterpreter::cmd_svar() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_svar");
}
void ScriptInterpreter::cmd_sset() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_sset");
}
void ScriptInterpreter::cmd_split() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_split");
}
void ScriptInterpreter::cmd_snlit() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_snlit");
}
void ScriptInterpreter::cmd_yorn() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_yorn");
}
void ScriptInterpreter::cmd_save() {
- if (_dumpScripts)
- return;
-
int16 result = 0;
int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs);
@@ -490,9 +484,6 @@ void ScriptInterpreter::cmd_save() {
}
void ScriptInterpreter::cmd_restore() {
- if (_dumpScripts)
- return;
-
int16 result = 0;
int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs);
@@ -531,6 +522,7 @@ void ScriptInterpreter::cmd_tspace() {
}
void ScriptInterpreter::cmd_class() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_class");
}
@@ -543,10 +535,12 @@ void ScriptInterpreter::cmd_objectp() {
}
void ScriptInterpreter::cmd_vectorp() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_vectorp");
}
void ScriptInterpreter::cmd_restart() {
+ // TODO: Used in RTZ
warning("Unimplemented command: cmd_restart");
}
@@ -613,9 +607,6 @@ void ScriptInterpreter::cmd_extend() {
for (int i = 0; i < argc; i++)
debug(2, "argv[%02d] = %04X (%d)", i, argv[i], argv[i]);
- if (_dumpScripts)
- return;
-
int16 result = _functions->callFunction(func, argc, argv);
debug(2, "result = %04X (%d)", result, result);
@@ -626,18 +617,22 @@ void ScriptInterpreter::cmd_extend() {
}
void ScriptInterpreter::cmd_catch() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_catch");
}
void ScriptInterpreter::cmd_cdone() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_cdone");
}
void ScriptInterpreter::cmd_throw() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_throw");
}
void ScriptInterpreter::cmd_functionp() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_functionp");
}
@@ -658,11 +653,133 @@ void ScriptInterpreter::cmd_ge() {
}
void ScriptInterpreter::cmd_varx() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_varx");
}
void ScriptInterpreter::cmd_setx() {
+ // Never used in LGOP2, RTZ, Manhole:NE
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
diff --git a/engines/made/script.h b/engines/made/script.h
index 0ec43478ab..459a088cb8 100644
--- a/engines/made/script.h
+++ b/engines/made/script.h
@@ -32,6 +32,11 @@
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 ScriptFunctions;
@@ -63,6 +68,8 @@ public:
ScriptInterpreter(MadeEngine *vm);
~ScriptInterpreter();
void runScript(int16 scriptObjectIndex);
+ void dumpScript(int16 objectIndex, int *opcodeStats, int *externStats);
+ void dumpAllScripts();
protected:
MadeEngine *_vm;
@@ -71,7 +78,6 @@ protected:
int16 _runningScriptObjectIndex;
byte *_codeBase, *_codeIp;
bool _terminated;
- bool _dumpScripts;
ScriptFunctions *_functions;
@@ -82,6 +88,9 @@ protected:
struct CommandEntry {
CommandProc proc;
const char *desc;
+#ifdef DUMP_SCRIPTS
+ const char *sig;
+#endif
};
const CommandEntry *_commands;
diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp
index d5227ecbf5..d627be38d4 100644
--- a/engines/made/scriptfuncs.cpp
+++ b/engines/made/scriptfuncs.cpp
@@ -319,6 +319,7 @@ int16 ScriptFunctions::sfIsMusicPlaying(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfSetTextPos(int16 argc, int16 *argv) {
+ // TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfSetTextPos");
// This seems to be some kind of low-level opcode.
// 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) {
+ // TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfPlayNote");
return 0;
}
int16 ScriptFunctions::sfStopNote(int16 argc, int16 *argv) {
+ // TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfStopNote");
return 0;
}
int16 ScriptFunctions::sfPlayTele(int16 argc, int16 *argv) {
+ // TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfPlayTele");
return 0;
}
int16 ScriptFunctions::sfStopTele(int16 argc, int16 *argv) {
+ // TODO: Used in Manhole:NE
warning("Unimplemented opcode: sfStopTele");
return 0;
}
@@ -374,7 +379,7 @@ int16 ScriptFunctions::sfSetScreenLock(int16 argc, int16 *argv) {
int16 ScriptFunctions::sfAddSprite(int16 argc, int16 *argv) {
if (_vm->getGameID() == GID_RTZ) {
- warning("Unimplemented opcode: sfAddSprite");
+ // Unused in RTZ
return 0;
} if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) {
return argv[2];
@@ -483,6 +488,7 @@ int16 ScriptFunctions::sfDrawText(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfHomeText(int16 argc, int16 *argv) {
+ // TODO: Used in LGOP2
warning("Unimplemented opcode: sfHomeText");
return 0;
}
@@ -542,6 +548,7 @@ int16 ScriptFunctions::sfSetSpriteGround(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfLoadResText(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfLoadResText");
return 0;
}
@@ -611,6 +618,7 @@ int16 ScriptFunctions::sfGetCdTime(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfPlayCdSegment(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfPlayCdSegment");
return 0;
}
@@ -623,6 +631,7 @@ int16 ScriptFunctions::sfPrintf(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfClearMono(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfClearMono");
return 0;
}
@@ -637,11 +646,13 @@ int16 ScriptFunctions::sfGetSoundEnergy(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfClearText(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfClearText");
return 1;
}
int16 ScriptFunctions::sfAnimText(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfAnimText");
return 0;
}
@@ -692,11 +703,13 @@ int16 ScriptFunctions::sfLoadPicture(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfSetMusicVolume(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetMusicVolume");
return 0;
}
int16 ScriptFunctions::sfRestartEvents(int16 argc, int16 *argv) {
+ // TODO: Used in RTZ
warning("Unimplemented opcode: sfRestartEvents");
return 0;
}
@@ -724,11 +737,13 @@ int16 ScriptFunctions::sfSetChannelState(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfSetChannelLocation(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetChannelLocation");
return 0;
}
int16 ScriptFunctions::sfSetChannelContent(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfSetChannelContent");
return 0;
}
@@ -796,6 +811,7 @@ int16 ScriptFunctions::sfSetSoundRate(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfDrawAnimPic(int16 argc, int16 *argv) {
+ // TODO: Used in RTZ
warning("Unimplemented opcode: sfDrawAnimPic");
return 0;
}
@@ -810,6 +826,7 @@ int16 ScriptFunctions::sfLoadAnim(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfReadText(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfReadText");
return 0;
}
@@ -913,11 +930,13 @@ int16 ScriptFunctions::sfGetGameDescription(int16 argc, int16 *argv) {
}
int16 ScriptFunctions::sfShakeScreen(int16 argc, int16 *argv) {
+ // TODO: Used in RTZ
warning("Unimplemented opcode: sfShakeScreen");
return 0;
}
int16 ScriptFunctions::sfPlaceMenu(int16 argc, int16 *argv) {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented opcode: sfPlaceMenu");
return 0;
}
diff --git a/engines/made/scriptfuncs.h b/engines/made/scriptfuncs.h
index 2b0f15c7a2..9879556c3f 100644
--- a/engines/made/scriptfuncs.h
+++ b/engines/made/scriptfuncs.h
@@ -54,6 +54,7 @@ public:
}
void setupExternalsTable();
const char* getFuncName(int index) { return _externalFuncNames[index]; }
+ int getCount() const { return _externalFuncs.size(); }
protected:
MadeEngine *_vm;
Audio::SoundHandle _audioStreamHandle;