[Scummvm-cvs-logs] SF.net SVN: scummvm: [23533] tools/trunk
lordhoto at users.sourceforge.net
lordhoto at users.sourceforge.net
Thu Jul 20 22:52:23 CEST 2006
Revision: 23533
http://svn.sourceforge.net/scummvm/?rev=23533&view=rev
Author: lordhoto
Date: 2006-07-17 18:44:49 -0700 (Mon, 17 Jul 2006)
Log Message:
-----------
Rewrite of dekyra (still WIP):
- supports EMC files without TEXT chunks
- basic function chunk detection
- should be compatible with (most) Kyra1 and Kyra2 files (needs some more testing though, e.g. checks for special Kyra2 commands)
- script parser/execution taken from the ScummVM Kyrandia engine
Modified Paths:
--------------
tools/trunk/Makefile
tools/trunk/dekyra.cpp
tools/trunk/dekyra.h
Added Paths:
-----------
tools/trunk/dekyra_v1.cpp
Modified: tools/trunk/Makefile
===================================================================
--- tools/trunk/Makefile 2006-07-17 12:22:29 UTC (rev 23532)
+++ tools/trunk/Makefile 2006-07-18 01:44:49 UTC (rev 23533)
@@ -56,7 +56,7 @@
desword2$(EXEEXT): desword2.o util.o
$(CXX) $(LDFLAGS) -o $@ $+
-dekyra$(EXEEXT): dekyra.o util.o
+dekyra$(EXEEXT): dekyra.o dekyra_v1.o util.o
$(CXX) $(LDFLAGS) -o $@ $+
extract_kyra$(EXEEXT): extract_kyra.o util.o
@@ -123,6 +123,7 @@
compress_kyra.o \
descumm.o descumm6.o descumm-common.o descumm-tool.o \
dekyra.o \
+dekyra_v1.o \
desword2.o \
encode_dxa.o \
extract_kyra.o \
Modified: tools/trunk/dekyra.cpp
===================================================================
--- tools/trunk/dekyra.cpp 2006-07-17 12:22:29 UTC (rev 23532)
+++ tools/trunk/dekyra.cpp 2006-07-18 01:44:49 UTC (rev 23533)
@@ -23,211 +23,515 @@
#include "dekyra.h"
-int main(int argc, char** argv) {
+#include <stdio.h>
+void printCommandsV1Ref();
+void setupCommandsV1(Script *myScript);
+void setupTraceCommandsV1(Script *myScript);
+
+void getOpcodesV1(OpcodeEntry *&opcodes, int &opcodesSize);
+void getOpcodesV2(OpcodeEntry *&opcodes, int &opcodesSize);
+
+FILE *outputFile = NULL;
+
+int main(int argc, char** argv) {
if (argc < 2) {
printf("Use:\n"
"%s filename\n"
- "-t displays text segment\n"
- "-n display only function 'n'. n should be a integer\n"
- "-e set engine version (1 for kyra1 (default), 2 for kyra2)\n",
+ "-t displays only the text segment\n"
+ "-e set engine version (1 for kyra1 (default), 2 for kyra2)\n"
+ "-o set optional outputfilename (default: stdout)\n",
argv[0]);
- return false;
+ return -1;
}
- uint32 file = 0xFFFFFFFE;
+ int file = -1;
+ int outputfile = -1;
bool displayText = false;
- bool displayOnlyOneScript = false;
- int32 scriptnum = 0, engine = 1;
+ int32 engine = 1;
// search for some parameters
for (int param = 1; param < argc; ++param) {
- if (*argv[param] != '-' && file == 0xFFFFFFFE)
+ if (*argv[param] != '-' && file == -1)
file = param;
else {
- if(argv[param][1] == 't')
+ if(argv[param][1] == 't') {
displayText = true;
- else if (argv[param][1] == 'n') {
- scriptnum = atoi(argv[param+1]);
- if (scriptnum >= 0 && scriptnum < 256)
- displayOnlyOneScript = true;
- param++;
} else if (argv[param][1] == 'e') {
engine = atoi(argv[param+1]);
- param++;
-
+ ++param;
+ } else if (argv[param][1] == 'o' && outputfile == -1) {
+ outputfile = ++param;
}
}
}
- if (file == 0xFFFFFFFE) {
+ if (file == -1) {
printf("Use:\n"
"%s filename\n"
- "-t displays text segment\n"
- "-n display only function 'n'\n"
- "-e set engine version (1 for kyra1 (default), 2 for kyra2)\n",
+ "-t displays only the text segment\n"
+ "-e set engine version (1 for kyra1 (default), 2 for kyra2)\n"
+ "-o set optional outputfilename (default: stdout)\n",
argv[0]);
- return false;
+ return -1;
+ } else if (engine != 1 && engine != 2) {
+ printf("-e (engine version) must be set to 1 or 2!\n");
+ return -1;
}
- Script myscript(argv[file]);
+ // currently output goes to stdout
+ if (outputfile == -1 || outputfile >= argc) {
+ outputFile = stdout;
+ } else {
+ outputFile = fopen(argv[outputfile], "w");
+ }
+
+ Script myScript;
+ ScriptData scriptData;
+ memset(&scriptData, 0, sizeof(ScriptData));
+
+ OpcodeEntry *opcodes;
+ int opcodesSize;
+
+ if (engine == 1) {
+ getOpcodesV1(opcodes, opcodesSize);
+ } else if (engine == 2) {
+ getOpcodesV2(opcodes, opcodesSize);
+ }
+ if (!myScript.loadScript(argv[file], &scriptData, opcodes, opcodesSize)) {
+ printf("ERROR: script loading failed!\n");
+ return -1;
+ }
- if (myscript.isOpen()) {
- if (displayText) {
- myscript.decodeTextArea();
- printf("\n\n");
- return true;
+ myScript.setEngineVersion(engine);
+ if (!displayText) {
+ if (engine == 1) {
+ setupTraceCommandsV1(&myScript);
+ } else if (engine == 2) {
+ // TODO: maybe kyra2 has other commands?
+ setupTraceCommandsV1(&myScript);
}
- if (!displayOnlyOneScript) {
- myscript.decodeScript(engine);
- } else {
- if (!myscript.decodeSpecialScript(scriptnum, engine)) {
- error("No script with number %d", scriptnum);
- }
+ myScript.processScriptTrace(&scriptData);
+ }
+
+ fprintf(outputFile, "/-----------------------------------\\\n");
+ fprintf(outputFile, "| |\n");
+ fprintf(outputFile, "| Dekyra output for file: |\n");
+ fprintf(outputFile, "| %-31s |\n", argv[file]);
+ fprintf(outputFile, "|-----------------------------------|\n");
+ fprintf(outputFile, "| General information: |\n");
+ fprintf(outputFile, "| Engine version: %1d |\n", engine);
+ fprintf(outputFile, "| Filesize: %15d bytes |\n", scriptData.fileSize);
+ if (scriptData.text) {
+ fprintf(outputFile, "|-----------------------------------|\n");
+ fprintf(outputFile, "| TEXT chunk information: |\n");
+ fprintf(outputFile, "| Strings: %-22d |\n", scriptData.numStrings);
+ fprintf(outputFile, "| Text chunk size: %8d bytes |\n", scriptData.textChunkSize);
+ }
+ if (!displayText) {
+ fprintf(outputFile, "|-----------------------------------|\n");
+ fprintf(outputFile, "| ORDR chunk information: |\n");
+ fprintf(outputFile, "| Ordr chunk size: %8d bytes |\n", scriptData.ordrChunkSize);
+ fprintf(outputFile, "| Max scriptfunctions: %-10d |\n", scriptData.ordrChunkSize / 2);
+ fprintf(outputFile, "| Valid scriptfunctions: %-8d |\n", scriptData.validORDRFunctions);
+ fprintf(outputFile, "|-----------------------------------|\n");
+ fprintf(outputFile, "| DATA chunk information: |\n");
+ fprintf(outputFile, "| Code chunk size: %8d bytes |\n", scriptData.dataChunkSize);
+ fprintf(outputFile, "| Detected functionchunks: %-6d |\n", scriptData.numFunctions);
+ }
+ fprintf(outputFile, "| |\n");
+ fprintf(outputFile, "\\-----------------------------------/\n\n");
+
+ myScript.setEngineVersion(engine);
+ myScript.printTextArea(&scriptData, argv[file]);
+ if (!displayText) {
+ if (engine == 1) {
+ printCommandsV1Ref();
+ setupCommandsV1(&myScript);
+ } else if (engine == 2) {
+ // TODO: maybe kyra2 has other commands?
+ printCommandsV1Ref();
+ setupCommandsV1(&myScript);
}
-
- } else {
- error("Couldn't find file '%s'", argv[1]);
- }
+
+ myScript.decodeScript(&scriptData);
+ }
+ myScript.unloadScript(&scriptData);
+
+ if (outputFile != stdout)
+ fclose(outputFile);
+
+ return 0;
+}
+
+Script::Script() : _commands(0), _commandsSize(0) {
+}
+
+Script::~Script() {
+}
+
+bool Script::setCommands(CommandProc *commands, int commandsSize) {
+ _commands = commands;
+ _commandsSize = commandsSize;
return true;
}
-Script::Script(const char* filename) {
- _scriptFile = 0;
- _stackPos = 0;
- FILE* script = fopen(filename, "rb");
+bool Script::loadScript(const char *filename, ScriptData *scriptData, OpcodeEntry *opcodes, int opcodeSize) {
+ FILE *scriptFile = fopen(filename, "rb");
+
+ if (scriptFile == NULL) {
+ error("couldn't load file '%s'", filename);
+ return false;
+ }
+
+ uint32 size = fileSize(scriptFile);
+ scriptData->fileSize = size;
+ uint8 *data = new uint8[size];
+ assert(data);
+ if (size != fread(data, sizeof(uint8), size, scriptFile)) {
+ delete [] data;
+ error("couldn't read all bytes from file '%s'", filename);
+ return false;
+ }
+ fclose(scriptFile);
+ scriptFile = NULL;
+
+ byte *curData = data;
- if (!script)
- return;
+ uint32 formBlockSize = Script::getFORMBlockSize(curData);
+ if (formBlockSize == (uint32)-1) {
+ delete [] data;
+ error("No FORM chunk found in file: '%s'", filename);
+ return false;
+ }
+
+ uint32 chunkSize = Script::getIFFBlockSize(data, curData, size, TEXT_CHUNK);
+ if (chunkSize != (uint32)-1) {
+ scriptData->text = new byte[chunkSize];
+ scriptData->textChunkSize = chunkSize;
+ assert(scriptData->text);
+
+ if (!Script::loadIFFBlock(data, curData, size, TEXT_CHUNK, scriptData->text, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load TEXT chunk from file: '%s'", filename);
+ return false;
+ }
- _scriptSize = fileSize(script);
- _scriptFile = new uint8[_scriptSize];
- assert(_scriptFile);
- fread(_scriptFile, sizeof(uint8) * _scriptSize, 1, script);
- fseek(script, 0, SEEK_SET);
-
- uint8 chunkName[sizeof("EMC2ORDR") + 1];
+ uint16 minTextOffset = 0xFFFF;
+ for (int i = 0; i < scriptData->textChunkSize / 2; ++i, ++scriptData->numStrings) {
+ if (minTextOffset > READ_BE_UINT16(&((uint16 *)scriptData->text)[i])) {
+ minTextOffset = READ_BE_UINT16(&((uint16 *)scriptData->text)[i]);
+ }
+ if (minTextOffset <= i*2)
+ break;
+ }
+ }
- // so lets look for our chunks :)
- while(true) {
- if ((uint32)ftell(script) >= _scriptSize) {
- break;
- }
- // lets read only the first 4 chars
- fread(chunkName, sizeof(uint8) * 4, 1, script);
- chunkName[4] = '\0';
- // check name of chunk
- if (!strcmp((char*)chunkName, "FORM")) {
- // FreeKyra swaps the size I only read it in BigEndian :)
- _chunks[kForm]._size = readUint32BE(script);
- } else if (!strcmp((char*)chunkName, "TEXT")) {
- uint32 text_size = readUint32BE(script);
- text_size += text_size % 2 != 0 ? 1 : 0;
-
- _chunks[kText]._data = _scriptFile + ftell(script);
- _chunks[kText]._size = READ_BE_UINT16(_chunks[kText]._data) >> 1;
- _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1);
- fseek(script, text_size, SEEK_CUR);
- } else if (!strcmp((char*)chunkName, "DATA")) {
- _chunks[kData]._size = readUint32BE(script);
- _chunks[kData]._data = _scriptFile + ftell(script);
- // mostly it will be the end of the file because all files should end with a 'DATA' chunk
- fseek(script, _chunks[kData]._size, SEEK_CUR);
- } else {
- // read next 4 chars
- fread(&chunkName[4], sizeof(uint8) * 4, 1, script);
- chunkName[8] = '\0';
- if (!strcmp((char*)chunkName, "EMC2ORDR")) {
- _chunks[kEmc2Ordr]._size = readUint32BE(script) >> 1;
- _chunks[kEmc2Ordr]._data = _scriptFile + ftell(script);
- fseek(script, _chunks[kEmc2Ordr]._size * 2, SEEK_CUR);
- } else {
- // any unkown chunk or problems with seeking through the file
- error("unknown chunk '%s'", chunkName);
+ chunkSize = Script::getIFFBlockSize(data, curData, size, ORDR_CHUNK);
+ if (chunkSize == (uint32)-1) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("No ORDR chunk found in file: '%s'", filename);
+ return false;
+ }
+
+ scriptData->ordr = new byte[chunkSize];
+ scriptData->ordrChunkSize = chunkSize;
+ assert(scriptData->ordr);
+
+ if (!Script::loadIFFBlock(data, curData, size, ORDR_CHUNK, scriptData->ordr, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load ORDR chunk from file: '%s'", filename);
+ return false;
+ }
+ chunkSize = chunkSize / 2;
+ while (chunkSize--) {
+ ((uint16*)scriptData->ordr)[chunkSize] = READ_BE_UINT16(&((uint16*)scriptData->ordr)[chunkSize]);
+ }
+
+ chunkSize = Script::getIFFBlockSize(data, curData, size, DATA_CHUNK);
+ if (chunkSize == (uint32)-1) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("No DATA chunk found in file: '%s'", filename);
+ return false;
+ }
+
+ scriptData->data = new byte[chunkSize];
+ assert(scriptData->data);
+
+ if (!Script::loadIFFBlock(data, curData, size, DATA_CHUNK, scriptData->data, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load DATA chunk from file: '%s'", filename);
+ return false;
+ }
+
+ scriptData->dataChunkSize = chunkSize;
+ scriptData->opcodes = opcodes;
+ scriptData->opcodeSize = opcodeSize;
+
+ delete [] data;
+ return true;
+}
+
+void Script::unloadScript(ScriptData *data) {
+ if (!data)
+ return;
+
+ delete [] data->text;
+ delete [] data->ordr;
+ delete [] data->data;
+ data->text = data->ordr = data->data = 0;
+}
+
+// decoding
+void Script::printTextArea(ScriptData *dataPtr, const char *filename) {
+ if (!dataPtr->textChunkSize)
+ return;
+
+#define posString(x) (char*)&dataPtr->text[READ_BE_UINT16(&((uint16 *)dataPtr->text)[(x)])]
+ fprintf(outputFile, "------------ Text Segment of '%s' --------------\n\n", filename);
+ for (int i = 0; i < dataPtr->numStrings; ++i) {
+ fprintf(outputFile, "0x%.04X '%s'\n", i, posString(i));
+ }
+ fprintf(outputFile, "\n");
+#undef posString
+}
+
+void Script::processScriptTrace(ScriptData *dataPtr) {
+ uint8 *ip = dataPtr->data;
+
+ for (int i = 0; i < dataPtr->ordrChunkSize / 2; ++i) {
+ if (dataPtr->numFunctions < MAX_FUNCTIONS) {
+ dataPtr->functions[dataPtr->numFunctions].id = i;
+ dataPtr->functions[dataPtr->numFunctions].startOffset = (((uint16*)dataPtr->ordr)[i]);
+ if (dataPtr->functions[dataPtr->numFunctions].startOffset != (uint16)-1) {
+ ++dataPtr->validORDRFunctions;
+ dataPtr->functions[dataPtr->numFunctions].startOffset <<= 1;
+ ++dataPtr->numFunctions;
}
+ } else {
+ warning("losing function");
}
}
+
+ for (; ip && ip < (dataPtr->data + dataPtr->dataChunkSize);) {
+ dataPtr->curOffset = (uint16)(ip - dataPtr->data);
+ int16 parameter = 0;
+ int16 code = READ_BE_UINT16(ip); ip += 2;
+ int16 opcode = (code >> 8) & 0x1F;
+
+ if (code & 0x8000) {
+ opcode = 0;
+ parameter = code & 0x7FFF;
+ } else if (code & 0x4000) {
+ parameter = (int8)(code);
+ } else if (code & 0x2000) {
+ parameter = READ_BE_UINT16(ip); ip += 2;
+ } else {
+ parameter = 0;
+ }
+
+ if (opcode < _commandsSize) {
+ if (_commands[(uint)opcode])
+ _commands[(uint)opcode](dataPtr, parameter);
+ }
+ }
- fclose(script);
+ // TODO: sort the 'function' list (except for the functions with id != -1) after start address
}
-void Script::decodeTextArea(void) {
- printf("TEXT chunk:\n");
- // first is size
- for (uint32 pos = 1; pos < (_chunks[kText]._size << 1); ++pos) {
- if (READ_BE_UINT16(_chunks[kText]._data + 2*pos) >= _scriptSize) {
+int Script::findFunction(ScriptData *dataPtr, uint16 offset) {
+ int bestStartOffset = -1;
+ int functionFittingBest = -1;
+
+ for (int i = 0; i < dataPtr->numFunctions; ++i) {
+ if (dataPtr->functions[i].startOffset == offset)
+ return i;
+
+ int temp = (dataPtr->functions[i].startOffset < offset) ? dataPtr->functions[i].startOffset : offset;
+ if (temp == offset)
+ continue;
+
+ int temp2 = (bestStartOffset > temp) ? bestStartOffset : temp;
+ if (temp2 == bestStartOffset)
+ continue;
+
+ bestStartOffset = temp2;
+ functionFittingBest = i;
+ }
+
+ return functionFittingBest;
+}
+
+void Script::outputFunctionInfo(ScriptData *dataPtr, uint16 curOffset, bool list) {
+ for (int i = 0; i < dataPtr->numFunctions; ++i) {
+ if (dataPtr->functions[i].startOffset != curOffset && !list)
+ continue;
+
+ if (!list) {
+ fprintf(outputFile, "\n------------------------------------------------\n");
+ fprintf(outputFile, "Function(chunk) start: ");
+ }
+
+ fprintf(outputFile, "num: %d, ID: %d startOffset: 0x%.04X\n", i, dataPtr->functions[i].id, dataPtr->functions[i].startOffset);
+ if (dataPtr->functions[i].refs) {
+ fprintf(outputFile, "refs:\n");
+ for (int i2 = 0; i2 < dataPtr->functions[i].refs; ++i2) {
+ uint16 tmpOffset = dataPtr->functions[i].refOffs[i2];
+ fprintf(outputFile, "0x%.04X (funcnum: %d) ", dataPtr->functions[i].refOffs[i2], findFunction(dataPtr, tmpOffset));
+ if ((i2 % 3) == 2)
+ fprintf(outputFile, "\n");
+ }
+ if (((dataPtr->functions[i].refs - 1)% 3) != 2)
+ fprintf(outputFile, "\n");
+ }
+
+ if (!list) {
+ fprintf(outputFile, "------------------------------------------------\n\n");
break;
+ } else if (i + 1 != dataPtr->numFunctions) {
+ fprintf(outputFile, "------------------------------------------------\n");
}
- uint32 startoffset = READ_BE_UINT16(_chunks[kText]._data + 2*pos);
- printf("%d(at %d) : %s\n", pos, startoffset, (char*)(_chunks[kText]._data + startoffset));
}
-}
-void Script::decodeScript(int8 engine) {
- decodeSpecialScript(-1, engine);
+ if (list)
+ fprintf(outputFile, "\n");
}
-struct CommandDesc {
- uint16 command; // normally uint8
- const char* description;
- bool usesArgument;
-};
+void Script::decodeScript(ScriptData *dataPtr) {
+ uint8 *ip = dataPtr->data;
+
+ fprintf(outputFile, "\n");
+ fprintf(outputFile, "---------- scriptfunction list ----------------\n\n");
+ for (int i = 0; i < dataPtr->ordrChunkSize / 2; ++i) {
+ uint16 offset = ((uint16*)dataPtr->ordr)[i];
+ if (offset != (uint16)-1)
+ fprintf(outputFile, "Scriptfunction %d starts at 0x%.04X\n", i, offset << 1);
+ }
+ fprintf(outputFile, "\n");
+
+ fprintf(outputFile, "--------- detected functionchunk list ----------\n\n");
+ outputFunctionInfo(dataPtr, 0, true);
-struct ScriptDesc {
- int32 script; // normally uint8
- const char* description;
-};
+ fprintf(outputFile, "---------- 'disassembled' output ---------------\n");
+ for (; ip < (dataPtr->data + dataPtr->dataChunkSize);) {
+ uint16 curOffset = (uint16)(ip - dataPtr->data);
-struct OpcodeDesc {
- uint16 opcode; // normally uint8
- const char* description;
-};
+ outputFunctionInfo(dataPtr, curOffset);
+
+ fprintf(outputFile, "0x%.04X: ", curOffset);
-// function which calls opcode procs
-const uint16 OPCODE_CALLER = 0x0E;
+ int16 parameter = 0;
+ int16 code = READ_BE_UINT16(ip); ip += 2;
+ int16 opcode = (code >> 8) & 0x1F;
-bool Script::decodeSpecialScript(int32 script, int8 engineVersion) {
- static CommandDesc commandDesc[] = {
- { 0x00, "goToLine", true },
- { 0x01, "setReturn", true },
- { 0x02, "pushRetRec", true },
- { 0x03, "push", true },
- { 0x04, "push", true },
- { 0x05, "pushVar", true },
- { 0x06, "pushFrameNeg", true },
- { 0x07, "pushFramePos", true },
- { 0x08, "popRetRec", true },
- { 0x09, "popVar", true },
- { 0x0A, "popFrameNeg", true },
- { 0x0B, "popFramePos", true },
- { 0x0C, "addToSP", true },
- { 0x0D, "subFromSP", true },
- { 0x0E, "execOpcode", true },
- { 0x0F, "ifNotGoTo", true },
- { 0x10, "negate", true },
- { 0x11, "evaluate", true },
- // normally only until 0xFF
- { 0xFFFF, 0, 0 }
- };
+ if (code & 0x8000) {
+ opcode = 0;
+ parameter = code & 0x7FFF;
+ } else if (code & 0x4000) {
+ parameter = (int8)(code);
+ } else if (code & 0x2000) {
+ parameter = READ_BE_UINT16(ip); ip += 2;
+ } else {
+ parameter = 0;
+ }
+
+ fprintf(outputFile, "0x%.02X ", opcode);
+ if (opcode >= _commandsSize) {
+ fprintf(outputFile, "unknown command\n");
+ } else {
+ if (_commands[(uint)opcode]) {
+ _commands[(uint)opcode](dataPtr, parameter);
+ } else {
+ fprintf(outputFile, "no valid command\n");
+ }
+ }
+ }
+}
+
+// block loading
+uint32 Script::getFORMBlockSize(byte *&data) {
+ static const uint32 chunkName = FORM_CHUNK;
+ if (READ_LE_UINT32(data) != chunkName) {
+ return (uint32)-1;
+ }
+ data += 4;
+ uint32 retValue = READ_BE_UINT32(data); data += 4;
+ return retValue;
+}
+
+uint32 Script::getIFFBlockSize(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName) {
+ uint32 size = (uint32)-1;
+ bool special = false;
- static ScriptDesc scriptDesc[] = {
- { 0, "kSetupScene" },
- { 1, "kClickEvent" },
- { 2, "kInitScreenEvent" },
- { 3, "kInitDataEvent" },
- { 4, "kEnterEvent" },
- { 5, "kExitEvent" },
- { 6, "kClick2Event" },
- { 7, "kLoadResources" },
- { 0xFFFF, "unknown script" }
- };
+ if (data == (start + maxSize)) {
+ data = start + 0x0C;
+ }
+ while (data < (start + maxSize)) {
+ uint32 chunk = READ_LE_UINT32(data); data += 4;
+ uint32 size_temp = READ_BE_UINT32(data); data += 4;
+ if (chunk != chunkName) {
+ if (special) {
+ data += (size_temp + 1) & 0xFFFFFFFE;
+ } else {
+ data = start + 0x0C;
+ special = true;
+ }
+ } else {
+ // kill our data
+ data = start;
+ size = size_temp;
+ break;
+ }
+ }
+ return size;
+}
+
+bool Script::loadIFFBlock(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName, byte *loadTo, uint32 ptrSize) {
+ bool special = false;
- static OpcodeDesc kyra2OpcodeDesc[] = {
+ if (data == (start + maxSize)) {
+ data = start + 0x0C;
+ }
+ while (data < (start + maxSize)) {
+ uint32 chunk = READ_LE_UINT32(data); data += 4;
+ uint32 chunkSize = READ_BE_UINT32(data); data += 4;
+ if (chunk != chunkName) {
+ if (special) {
+ data += (chunkSize + 1) & 0xFFFFFFFE;
+ } else {
+ data = start + 0x0C;
+ special = true;
+ }
+ } else {
+ uint32 loadSize = 0;
+ if (chunkSize < ptrSize)
+ loadSize = chunkSize;
+ else
+ loadSize = ptrSize;
+ memcpy(loadTo, data, loadSize);
+ chunkSize = (chunkSize + 1) & 0xFFFFFFFE;
+ if (chunkSize > loadSize) {
+ data += (chunkSize - loadSize);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+// TODO: move to own file dekyra_v2.cpp if there are special kyra2 commands!
+void getOpcodesV2(OpcodeEntry *&opcodes, int &opcodesSize) {
+ static OpcodeEntry kyra2OpcodeDesc[] = {
{ 0x0, "o2_setCharacterShape" },
{ 0x1, "o2_drawShapeFrame" },
{ 0x2, "o2_defineObject" },
@@ -397,478 +701,7 @@
{ 0xa6, "o2_unk0xA6" },
{ 0xa7, "o2_dummy" }
};
-
- static OpcodeDesc kyra1OpcodeDesc[] = {
- { 0x00 ,"o1_Magic_In_Mouse_Item" },
- { 0x01 ,"o1_Character_Says" },
- { 0x02 ,"o1_Pause_Ticks" },
- { 0x03 ,"o1_Draw_Scene_Anim_Shape" },
- { 0x04 ,"o1_Query_Game_Flag" },
- { 0x05 ,"o1_Set_Game_Flag" },
- { 0x06 ,"o1_Reset_Game_Flag" },
- { 0x07 ,"o1_Run_NPC_Script" },
- { 0x08 ,"o1_Set_Special_Exit_List" },
- { 0x09 ,"o1_Block_In_Walkable_Region" },
- { 0x0A ,"o1_Block_Out_Walkable_Region" },
- { 0x0B ,"o1_Walk_Player_To_Point" },
- { 0x0C ,"o1_Drop_Item_In_Scene" },
- { 0x0D ,"o1_Draw_Anim_Shape_Into_Scene" },
- { 0x0E ,"o1_Create_Mouse_Item" },
- { 0x0F ,"o1_Save_Page_To_Disk" },
- { 0x10 ,"o1_Scene_Anim_On" },
- { 0x11 ,"o1_Scene_Anim_Off" },
- { 0x12 ,"o1_Elapsed_Seconds" },
- { 0x13 ,"o1_Mouse_Is_Pointer" },
- { 0x14 ,"o1_Destroy_Mouse_Item" },
- { 0x15 ,"o1_Run_Scene_Anim_Until_Done" },
- { 0x16 ,"o1_Fade_Special_Palette" },
- { 0x17 ,"o1_Play_AdLib_Sound" },
- { 0x18 ,"o1_Play_AdLib_Score" },
- { 0x19 ,"o1_Phase_In_Same_Scene" },
- { 0x1a ,"o1_Set_Scene_Phasing_Flag" },
- { 0x1b ,"o1_Reset_Scene_Phasing_Flag" },
- { 0x1c ,"o1_Query_Scene_Phasing_Flag" },
- { 0x1d ,"o1_Scene_To_Direction" },
- { 0x1e ,"o1_Set_Birthstone_Gem" },
- { 0x1f ,"o1_Place_Item_In_Generic_Map_Scene" },
- { 0x20 ,"o1_Set_Brandon_Status_Bit" },
- { 0x21 ,"o1_Pause_Seconds" },
- { 0x22 ,"o1_Get_Characters_Location" },
- { 0x23 ,"o1_Run_NPC_Subscript" },
- { 0x24 ,"o1_Magic_Out_Mouse_Item" },
- { 0x25 ,"o1_Internal_Anim_On" },
- { 0x26 ,"o1_Force_Brandon_To_Normal" },
- { 0x27 ,"o1_Poison_Death_Now" },
- { 0x28 ,"o1_Set_Scale_Mode" },
- { 0x29 ,"o1_Open_WSA_File" },
- { 0x2a ,"o1_Close_WSA_File" },
- { 0x2b ,"o1_Run_WSA_From_Beginning_To_End" },
- { 0x2c ,"o1_Display_WSA_Frame" },
- { 0x2d ,"o1_Enter_New_Scene" },
- { 0x2e ,"o1_Set_Special_Enter_X_And_Y" },
- { 0x2f ,"o1_Run_WSA_Frames" },
- { 0x30 ,"o1_Pop_Brandon_Into_Scene" },
- { 0x31 ,"o1_Restore_All_Object_Backgrounds" },
- { 0x32 ,"o1_Set_Custom_Palette_Range" },
- { 0x33 ,"o1_Load_Page_From_Disk" },
- { 0x34 ,"o1_Custom_Print_Talk_String" },
- { 0x35 ,"o1_Restore_Custom_Print_Background" },
- { 0x36 ,"o1_Hide_Mouse" },
- { 0x37 ,"o1_Show_Mouse" },
- { 0x38 ,"o1_Get_Character_X" },
- { 0x39 ,"o1_Get_Character_Y" },
- { 0x3A ,"o1_Change_Characters_Facing" },
- { 0x3B ,"o1_Copy_WSA_Region" },
- { 0x3C ,"o1_Text_Print" },
- { 0x3D ,"o1_Random" },
- { 0x3E ,"o1_Load_Sound_File" },
- { 0x3F ,"o1_Display_WSA_Frame_On_HidPage" },
- { 0x40 ,"o1_Display_WSA_Sequential_Frames" },
- { 0x41 ,"o1_Draw_Character_Standing" },
- { 0x42 ,"o1_Internal_Anim_Off" },
- { 0x43 ,"o1_Change_Characters_X_And_Y" },
- { 0x44 ,"o1_Clear_Scene_Animator_Beacon" },
- { 0x45 ,"o1_Query_Scene_Animator_Beacon" },
- { 0x46 ,"o1_Refresh_Scene_Animator" },
- { 0x47 ,"o1_Place_Item_In_Off_Scene" },
- { 0x48 ,"o1_Wipe_Down_Mouse_Item" },
- { 0x49 ,"o1_Place_Character_In_Other_Scene" },
- { 0x4A ,"o1_Get_Key" },
- { 0x4B ,"o1_Specific_Item_In_Inventory" },
- { 0x4C ,"o1_Pop_Mobile_NPC_Into_Scene" },
- { 0x4D ,"o1_Mobile_Character_In_Scene" },
- { 0x4E ,"o1_Hide_Mobile_Character" },
- { 0x4F ,"o1_Unhide_Mobile_Character" },
- { 0x50 ,"o1_Set_Characters_Location" },
- { 0x51 ,"o1_Walk_Character_To_Point" },
- { 0x52 ,"o1_Special_Event_Display_Brynns_Note" },
- { 0x53 ,"o1_Special_Event_Remove_Brynns_Note" },
- { 0x54 ,"o1_Set_Logic_Page" },
- { 0x55 ,"o1_Fat_Print" },
- { 0x56 ,"o1_Preserve_All_Object_Backgrounds" },
- { 0x57 ,"o1_Update_Scene_Animations" },
- { 0x58 ,"o1_Scene_Animation_Active" },
- { 0x59 ,"o1_Set_Characters_Movement_Delay" },
- { 0x5A ,"o1_Get_Characters_Facing" },
- { 0x5B ,"o1_Bkgd_Scroll_Scene_And_Masks_Right" },
- { 0x5C ,"o1_Dispel_Magic_Animation" },
- { 0x5d ,"o1_Find_Brightest_Fireberry" },
- { 0x5e ,"o1_Set_Fireberry_Glow_Palette" },
- { 0x5f ,"o1_Set_Death_Handler_Flag" },
- { 0x60 ,"o1_Drink_Potion_Animation" },
- { 0x61 ,"o1_Make_Amulet_Appear" },
- { 0x62 ,"o1_Draw_Item_Shape_Into_Scene" },
- { 0x63 ,"o1_Set_Characters_Current_Frame" },
- { 0x64 ,"o1_Wait_For_Confirmation_Mouse_Click" },
- { 0x65 ,"o1_Page_Flip" },
- { 0x66 ,"o1_Set_Scene_File" },
- { 0x67 ,"o1_What_Item_In_Marble_Vase" },
- { 0x68 ,"o1_Set_Item_In_Marble_Vase" },
- { 0x69 ,"o1_Add_Item_To_Inventory" },
- { 0x6a ,"o1_Int_Print" },
- { 0x6b ,"o1_Shake_Screen" },
- { 0x6c ,"o1_Create_Amulet_Jewel" },
- { 0x6d ,"o1_Set_Scene_Anim_Curr_XY" },
- { 0x6e ,"o1_Poison_Brandon_And_Remaps" },
- { 0x6f ,"o1_Fill_Flask_With_Water" },
- { 0x70 ,"o1_Get_Characters_Movement_Delay" },
- { 0x71 ,"o1_Get_Birthstone_Gem" },
- { 0x72 ,"o1_Query_Brandon_Status_Bit" },
- { 0x73 ,"o1_Play_Flute_Animation" },
- { 0x74 ,"o1_Play_Winter_Scroll_Sequence" },
- { 0x75 ,"o1_Get_Idol_Gem" },
- { 0x76 ,"o1_Set_Idol_Gem" },
- { 0x77 ,"o1_Total_Items_In_Scene" },
- { 0x78 ,"o1_Restore_Brandons_Movement_Delay" },
- { 0x79 ,"o1_Set_Mouse_Pos" },
- { 0x7a ,"o1_Get_Mouse_State" },
- { 0x7b ,"o1_Set_Entrance_Mouse_Cursor_Track" },
- { 0x7c ,"o1_Item_Appears_On_Ground" },
- { 0x7d ,"o1_Set_No_Draw_Shapes_Flag" },
- { 0x7e ,"o1_Fade_Entire_Palette" },
- { 0x7f ,"o1_Item_On_Ground_Here" },
- { 0x80 ,"o1_Query_Cauldron_State" },
- { 0x81 ,"o1_Set_Cauldron_State" },
- { 0x82 ,"o1_Query_Crystal_State" },
- { 0x83 ,"o1_Set_Crystal_State" },
- { 0x84 ,"o1_Set_Palette_Range" },
- { 0x85 ,"o1_Shrink_Brandon_Down" },
- { 0x86 ,"o1_Grow_Brandon_Up" },
- { 0x87 ,"o1_Set_Brandon_Scale_X_And_Y" },
- { 0x88 ,"o1_Reset_Scale_Mode" },
- { 0x89 ,"o1_Get_Scale_Depth_Table_Value" },
- { 0x8a ,"o1_Set_Scale_Depth_Table_Value" },
- { 0x8b ,"o1_Message" },
- { 0x8c ,"o1_Check_Click_On_NPC" },
- { 0x8d ,"o1_Get_Foyer_Item" },
- { 0x8e ,"o1_Set_Foyer_Item" },
- { 0x8F ,"o1_Set_No_Item_Drop_Region" },
- { 0x90 ,"o1_Walk_Malcolm_On" },
- { 0x91 ,"o1_Passive_Protection" },
- { 0x92 ,"o1_Set_Playing_Loop" },
- { 0x93 ,"o1_Brandon_To_Stone_Sequence" },
- { 0x94 ,"o1_Brandon_Healing_Sequence" },
- { 0x95 ,"o1_Protect_Command_Line" },
- { 0x96 ,"o1_Pause_Music_Seconds" },
- { 0x97 ,"o1_Reset_Mask_Region" },
- { 0x98 ,"o1_Set_Palette_Change_Flag" },
- { 0x99 ,"o1_Fill_Rect" },
- { 0x9a ,"o1_Voc_Unload" },
- { 0x9b ,"o1_Voc_Load" },
- { 0x9c ,"o1_Dummy" }
- };
-
- if (script > -1) {
- _instructionPos = (READ_BE_UINT16(_chunks[kEmc2Ordr]._data + 2 * script) << 1);
- } else
- _instructionPos = 0;
-
- memset(_stack, 0, sizeof(_stack));
- memset(_registers, 0, sizeof(_registers));
-
- _stackPos = 0;
- uint8* script_start = _chunks[kData]._data;
- bool gotArgument = true;
-
- // uint32 nextScriptStartsAt = getNextScriptPos(_instructionPos);
-
- while(true) {
- if ((uint32)_instructionPos > _chunks[kData]._size /*|| (uint32)_instructionPos >= nextScriptStartsAt*/) {
- break;
- }
-
- for (uint32 pos = 0; pos < ARRAYSIZE(scriptDesc) - 1; ++pos) {
- if ((READ_BE_UINT16(_chunks[kEmc2Ordr]._data + 2*pos) << 1) == _instructionPos) {
- printf("\nScript %i: %s:\n", pos, scriptDesc[pos].description);
- break;
- }
- }
-
- // prints the offset
- printf("0x%04x:\t\t" , _instructionPos);
-
- gotArgument = true;
- _currentCommand = *(script_start + _instructionPos++);
-
- // gets out
- if (_currentCommand & 0x80) {
- _argument = ((_currentCommand & 0x0F) << 8) | *(script_start + _instructionPos++);
- _currentCommand &= 0xF0;
- } else if (_currentCommand & 0x40) {
- _argument = *(script_start + _instructionPos++);
- } else if (_currentCommand & 0x20) {
- _instructionPos++;
-
- // FIXME: I am not 100% sure if this code is correct (after my
- // 'endian macro' changes), somebody please double check.
- uint16 tmp = READ_BE_UINT16(script_start + _instructionPos);
- tmp &= 0xFF7F;
-
- _argument = tmp;
- _instructionPos += 2;
- } else {
- gotArgument = false;
- }
-
- _currentCommand &= 0x1f;
-
-
- bool gotCommand = false;
-
- // lets get out what the command means
- for (uint32 pos = 0; pos < ARRAYSIZE(commandDesc) - 1; ++pos) {
- if (commandDesc[pos].command == _currentCommand) {
- gotCommand = true;
- if (commandDesc[pos].command != OPCODE_CALLER)
- printf("\t%s" , commandDesc[pos].description);
-
- if (commandDesc[pos].usesArgument && commandDesc[pos].command != OPCODE_CALLER) {
- if (commandDesc[pos].command == 0x3 || commandDesc[pos].command == 0x4)
- printf("(0x%x | %s)" , _argument, stringAtIndex(_argument));
- else
- printf("(0x%x)\t" , _argument);
-
- } else if(commandDesc[pos].usesArgument && commandDesc[pos].command == OPCODE_CALLER) {
- bool gotOpcode = false;
- // lets look for our opcodes
- if (engineVersion == 1)
- for (uint32 pos2 = 0; pos2 < ARRAYSIZE(kyra1OpcodeDesc); ++pos2) {
- if (kyra1OpcodeDesc[pos2].opcode == _argument) {
- printf("%s()", kyra1OpcodeDesc[pos2].description);
- gotOpcode = true;
- break;
- }
- }
- else if (engineVersion == 2)
- for (uint32 pos2 = 0; pos2 < ARRAYSIZE(kyra2OpcodeDesc); ++pos2) {
- if (kyra2OpcodeDesc[pos2].opcode == _argument) {
- printf("%s()", kyra2OpcodeDesc[pos2].description);
- gotOpcode = true;
- break;
- }
- }
- if (!gotOpcode)
- printf("UNKNOWN OPCODE: 0x%x", _argument);
- }
-
- break;
- }
- }
- execCommand(_currentCommand);
-
- // prints our command number + arg
- if (!gotCommand) {
- printf("0x%x(0x%x)", _currentCommand, _argument);
- }
-
- if (!gotArgument) {
- printf("\t; couldn't get argument! maybe command is wrong.");
- }
-
- printf("\n");
- }
-
- printf("\n-------------\n");
-
- return true;
+ opcodes = kyra2OpcodeDesc;
+ opcodesSize = ARRAYSIZE(kyra2OpcodeDesc);
}
-
-uint32 Script::getNextScriptPos(uint32 current_start) {
- uint32 pos = 0xFFFFFFFE;
-
- for (uint32 tmp = 0; tmp < _chunks[kEmc2Ordr]._size; ++tmp) {
- uint32 tmp2 = READ_BE_UINT16(_chunks[kEmc2Ordr]._data + tmp);
- tmp2 = (tmp2 << 1) + 2;
- if (tmp2 > current_start && tmp2 < pos) {
- pos = tmp2;
- }
- }
-
- if (pos > _scriptSize) {
- pos = _scriptSize;
- }
-
- return pos;
-}
-
-const char* Script::stringAtIndex(int32 index) {
- if (index < 0 || (uint32)index >= _chunks[kText]._size)
- return 0;
-
- uint16 offset = READ_BE_UINT16(_chunks[kText]._data + 2*index);
- return (const char *)(_chunks[kText]._data + offset);
-}
-
-void Script::execCommand(uint32 command) {
-#define COMMAND(x) { &Script::x }
- typedef void (Script::*CommandProc)();
- struct CommandEntry {
- CommandProc proc;
- };
-
- // now we create a list of all Command/Opcode procs and so
- static CommandEntry commandProcs[] = {
- // 0x00
- COMMAND(goToLine),
- COMMAND(setReturn),
- COMMAND(pushRetRec),
- COMMAND(push),
- // 0x04
- COMMAND(push),
- COMMAND(pushVar),
- COMMAND(pushFrameNeg),
- COMMAND(pushFramePos),
- // 0x08
- COMMAND(popRetRec),
- COMMAND(popVar),
- COMMAND(popFrameNeg),
- COMMAND(popFramePos),
- // 0x0C
- COMMAND(addToSP),
- COMMAND(subFromSP),
- COMMAND(execOpcode),
- COMMAND(ifNotGoTo),
- // 0x10
- COMMAND(negate),
- COMMAND(evaluate)
- };
-
- static uint16 _numCommands = ARRAYSIZE(commandProcs);
- static CommandEntry* _commands = commandProcs;
-
- if (command < _numCommands) {
- CommandProc currentProc = _commands[command].proc;
- (this->*currentProc)();
- }
-}
-
-void Script::goToLine(void) {
-}
-
-void Script::setReturn(void) {
-}
-
-void Script::pushRetRec(void) {
-}
-
-void Script::push(void) {
-}
-
-void Script::pushVar(void) {
-}
-
-void Script::pushFrameNeg(void) {
-}
-
-void Script::pushFramePos(void) {
-}
-
-void Script::popRetRec(void) {
-}
-
-void Script::popVar(void) {
-}
-
-void Script::popFrameNeg(void) {
-}
-
-void Script::popFramePos(void) {
-}
-
-void Script::addToSP(void) {
-}
-
-void Script::subFromSP(void) {
-}
-
-void Script::execOpcode(void) {
-}
-
-void Script::ifNotGoTo(void) {
-}
-
-void Script::negate(void) {
-}
-
-void Script::evaluate(void) {
- switch(_argument) {
- case 0:
- printf("x && y");
- break;
-
- case 1:
- printf("x || y");
- break;
-
- case 2:
- printf("x == y");
- break;
-
- case 3:
- printf("x != y");
- break;
-
- case 4:
- printf("x < y");
- break;
-
- case 5:
- printf("x <= y");
- break;
-
- case 6:
- printf("x > y");
- break;
-
- case 7:
- printf("x >= y");
- break;
-
- case 8:
- printf("x + y");
- break;
-
- case 9:
- printf("x - y");
- break;
-
- case 10:
- printf("x * y");
- break;
-
- case 11:
- printf("x / y");
- break;
-
- case 12:
- printf("x >> y");
- break;
-
- case 13:
- printf("x << y");
- break;
-
- case 14:
- printf("x & y");
- break;
-
- case 15:
- printf("x | y");
- break;
-
- case 16:
- printf("x %% y");
- break;
-
- case 17:
- printf("x ^ y");
- break;
-
- default:
- printf("ERROR: unknown evaluate command %d\n", _argument);
- break;
- };
-
-}
-
Modified: tools/trunk/dekyra.h
===================================================================
--- tools/trunk/dekyra.h 2006-07-17 12:22:29 UTC (rev 23532)
+++ tools/trunk/dekyra.h 2006-07-18 01:44:49 UTC (rev 23533)
@@ -26,83 +26,88 @@
#include "util.h"
-class Script {
- public:
- Script(const char* filename);
- ~Script() { delete _scriptFile; }
-
- void decodeTextArea(void);
- void decodeScript(int8 engine);
- bool decodeSpecialScript(int32 script, int8 engine);
- bool isOpen(void) { return (_scriptFile != 0); }
-
- uint32 getNextScriptPos(uint32 current_start);
+typedef unsigned int uint;
- protected:
- const char* getParamsOnStack(void);
- const char* stringAtIndex(int32 index);
+struct OpcodeEntry {
+ uint16 opcode;
+ const char *name;
+};
- void pushStack(int32 value) { _stack[_stackPos++] = value; }
- void registerValue(int16 reg, int16 value) { _registers[reg] = value; }
- int32 checkReg(int16 reg) { return _registers[reg]; }
+#define MAX_REFS 30
+struct Function {
+ int id;
+ uint16 startOffset;
- int32 popStack(void) { return _stack[--_stackPos]; }
- int32& topStack(void) { return _stack[_stackPos]; }
+ int refs;
+ uint16 refOffs[MAX_REFS];
+};
- int32 param(int32 index);
- const char* paramString(int32 index) { return stringAtIndex(param(index)); }
-
- enum ScriptChunkTypes {
- kForm = 0,
- kEmc2Ordr = 1,
- kText = 2,
- kData = 3,
- kCountChunkTypes
- };
-
- struct ScriptChunk {
- uint32 _size;
- uint8* _data; // by TEXT used for count of texts, by EMC2ODRD it is used for a count of somewhat
- uint8* _additional; // currently only used for TEXT
- };
-
- ScriptChunk _chunks[kCountChunkTypes];
-
- uint32 _scriptSize;
- uint8* _scriptFile;
+#define MAX_FUNCTIONS 400
- int32 _nextScriptPos;
- int32 _instructionPos;
- int32 _stackPos;
- int32 _tempPos;
+struct ScriptData {
+ int fileSize;
- uint32 _returnValue;
- uint16 _argument;
- uint8 _currentCommand;
- uint32 _currentOpcode;
-
- int32 _stack[128]; // the stack
- int32 _registers[32]; // registers of the interpreter
+ byte *text;
+ int numStrings;
+ int textChunkSize;
+
+ byte *data;
+ int dataChunkSize;
+
+ byte *ordr;
+ int validORDRFunctions;
+ int ordrChunkSize;
+
+ OpcodeEntry *opcodes;
+ int opcodeSize;
+
+ // trace information
+ uint16 curOffset;
- void execCommand(uint32 command);
+ int numFunctions;
+ Function functions[MAX_FUNCTIONS];
+
+ Function *getFunction(uint16 startOff) {
+ for (int i = 0; i < numFunctions; ++i) {
+ if (functions[i].startOffset == startOff)
+ return &functions[i];
+ }
+ return 0;
+ }
+};
- void goToLine(void); // 0x00
- void setReturn(void); // 0x01
- void pushRetRec(void); // 0x02
- void push(void); // 0x03 & 0x04
- void pushVar(void); // 0x05
- void pushFrameNeg(void); // 0x06
- void pushFramePos(void); // 0x07
- void popRetRec(void); // 0x08
- void popVar(void); // 0x09
- void popFrameNeg(void); // 0x0A
- void popFramePos(void); // 0x0B
- void addToSP(void); // 0x0C
- void subFromSP(void); // 0x0D
- void execOpcode(void); // 0x0E
- void ifNotGoTo(void); // 0x0F
- void negate(void); // 0x10
- void evaluate(void); // 0x11
+#define FORM_CHUNK 0x4D524F46
+#define TEXT_CHUNK 0x54584554
+#define DATA_CHUNK 0x41544144
+#define ORDR_CHUNK 0x5244524F
+
+typedef void (*CommandProc)(ScriptData *script, int argument);
+
+class Script {
+public:
+ Script();
+ ~Script();
+
+ bool setCommands(CommandProc *commands, int commandsSize);
+ void setEngineVersion(int ver) { _engine = ver; }
+
+ bool loadScript(const char *filename, ScriptData *data, OpcodeEntry *opcodes, int opcodeSize);
+ void unloadScript(ScriptData *data);
+
+ void printTextArea(ScriptData *dataPtr, const char *filename);
+ void processScriptTrace(ScriptData *dataPtr);
+ void decodeScript(ScriptData *dataPtr);
+private:
+ int findFunction(ScriptData *dataPtr, uint16 offset);
+ void outputFunctionInfo(ScriptData *dataPtr, uint16 curOffset, bool list = false);
+
+ static uint32 getFORMBlockSize(byte *&data);
+ static uint32 getIFFBlockSize(byte *start, byte *&data, uint32 maxSize, const uint32 chunk);
+ static bool loadIFFBlock(byte *start, byte *&data, uint32 maxSize, const uint32 chunk, byte *loadTo, uint32 ptrSize);
+
+ int _engine;
+ CommandProc *_commands;
+ int _commandsSize;
};
#endif
Added: tools/trunk/dekyra_v1.cpp
===================================================================
--- tools/trunk/dekyra_v1.cpp 2006-07-17 12:22:29 UTC (rev 23532)
+++ tools/trunk/dekyra_v1.cpp 2006-07-18 01:44:49 UTC (rev 23533)
@@ -0,0 +1,547 @@
+/* DeKyra - Basic Kyrandia script disassembler
+ * Copyright (C) 2006 The ScummVM Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "dekyra.h"
+
+extern FILE *outputFile;
+
+// command help
+void printCommandsV1Ref() {
+ fprintf(outputFile, "------------- Command Reference ----------------\n\n");
+ fprintf(outputFile, "c1_jumpTo - jumps to the given param\n\n");
+ fprintf(outputFile, "c1_setRetValue - sets the return value\n\n");
+ fprintf(outputFile, "c1_pushRetOrPos - dependent on param:\n");
+ fprintf(outputFile, " - 0: pushes return value\n");
+ fprintf(outputFile, " - 1: pushes the next instruction address and the bp and updates the bp to sp+2\n");
+ fprintf(outputFile, " - else: breaks execution\n\n");
+ fprintf(outputFile, "c1_push - push an integer to the stack (is also be used for string indexes)\n\n");
+ fprintf(outputFile, "c1_pushVar - pushes var[param] to the stack\n\n");
+ fprintf(outputFile, "c1_pushBPNeg - pushes the value at stack[(-(param + 2))+ bp] to the stack\n\n");
+ fprintf(outputFile, "c1_pushBPAdd - pushes the value at stack[(param - 1) + bp] to the stack\n\n");
+ fprintf(outputFile, "c1_popRetOrPos - dependent on param:\n");
+ fprintf(outputFile, " - 0: pops return value\n");
+ fprintf(outputFile, " - 1: pops the bp and after it the ip from the stack\n");
+ fprintf(outputFile, " - else: breaks execution\n\n");
+ fprintf(outputFile, "c1_popVar - pops the stack top to var[param]\n\n");
+ fprintf(outputFile, "c1_popBPNeg - pops the stack top to stack[-(param + 2) + bp]\n\n");
+ fprintf(outputFile, "c1_popBPAdd - pops the stack top to stack[(param - 1) + bp]\n\n");
+ fprintf(outputFile, "c1_execOpcode - executes a function and sets the return value to the return value of the called function\n\n");
+ fprintf(outputFile, "c1_ifNotJmp - jumps to address param if the stack top is zero\n\n");
+ fprintf(outputFile, "c1_negate - dependent on param:\n");
+ fprintf(outputFile, " - 0: sets the stack top to 1 if the stack top is non-zero, if the stack top is zero it doesn't do anything\n");
+ fprintf(outputFile, " - 1: sets the stack top to -(stack top)\n");
+ fprintf(outputFile, " - 2: sets the stack top to ~(stack top)\n");
+ fprintf(outputFile, " - else: breaks execution\n\n");
+ fprintf(outputFile, "c1_eval - pops val1 and val2 from the stack and does the given evaulation and pushes the result of it to the stack\n\n");
+ fprintf(outputFile, "c1_setRetAndJmp - pops the return value from the stack, after that pops the new ip from the stack and jumps to that position\n\n");
+}
+
+// commands
+void c1_jumpTo(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_jumpTo 0x%.04X\n", (((uint)argument) << 1) & 0xFFFF);
+}
+
+void c1_setRetValue(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_setRetValue %d\n", argument);
+}
+
+void c1_pushRetOrPos(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_pushRetOrPos %d ", argument);
+ switch (argument) {
+ case 0:
+ case 1:
+ break;
+
+ default:
+ fprintf(outputFile, "; called with illegal param! breaks execution!");
+ break;
+ }
+ fprintf(outputFile, "\n");
+}
+
+void c1_push(ScriptData *dataPtr, int argument) {
+#define posString(x) (char*)&dataPtr->text[READ_BE_UINT16(&((uint16 *)dataPtr->text)[(x)])]
+ if (argument < dataPtr->numStrings && argument > 0) {
+ fprintf(outputFile, "c1_push %d ; could be string '%s'\n", argument, posString(argument));
+ } else {
+ fprintf(outputFile, "c1_push %d\n", argument);
+ }
+#undef posString
+}
+
+void c1_pushVar(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_pushVar %d\n", argument);
+}
+
+void c1_pushBPNeg(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_pushBPNeg %d\n", argument);
+}
+
+void c1_pushBPAdd(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_pushBPAdd %d\n", argument);
+}
+
+void c1_popRetOrPos(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_popRetOrPos %d ", argument);
+ switch (argument) {
+ case 0:
+ case 1:
+ break;
+
+ default:
+ fprintf(outputFile, "; called with illegal param! breaks execution!");
+ break;
+ }
+ fprintf(outputFile, "\n");
+}
+
+void c1_popVar(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_popVar %d\n", argument);
+}
+
+void c1_popBPNeg(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_popBPNeg %d\n", argument);
+}
+
+void c1_popBPAdd(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_popBPAdd %d\n", argument);
+}
+
+void c1_addSP(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_addSP %d\n", argument);
+}
+
+void c1_subSP(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_subSP %d\n", argument);
+}
+
+void c1_execOpcode(ScriptData *script, int argument) {
+ if ((uint8)argument >= (uint8)script->opcodeSize) {
+ fprintf(outputFile, "c1_execOpcode %d ; tries to call illegal opcode param and breaks exectuion\n", (uint8)argument);
+ } else {
+ fprintf(outputFile, "c1_execOpcode %d ; functionname: '%s'\n", (uint8)argument, script->opcodes[(uint8)argument].name);
+ }
+}
+
+void c1_ifNotJmp(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_ifNotJmp 0x%.04X\n", (((uint)argument) << 1) & 0xFFFF);
+}
+
+void c1_negate(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_negate %d ", argument);
+ switch (argument) {
+ case 0:
+ case 1:
+ case 2:
+ break;
+
+ default:
+ fprintf(outputFile, "; called with illegal param! breaks execution");
+ break;
+ }
+ fprintf(outputFile, "\n");
+}
+
+void c1_eval(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_eval %d ; (C syntax): '", argument);
+
+ switch (argument) {
+ case 0:
+ fprintf(outputFile, "(val2 && val1)");
+ break;
+
+ case 1:
+ fprintf(outputFile, "(val2 || val1)");
+ break;
+
+ case 2:
+ fprintf(outputFile, "(val1 == val2)");
+ break;
+
+ case 3:
+ fprintf(outputFile, "(val1 != val2)");
+ break;
+
+ case 4:
+ fprintf(outputFile, "(val1 > val2)");
+ break;
+
+ case 5:
+ fprintf(outputFile, "(val1 >= val2)");
+ break;
+
+ case 6:
+ fprintf(outputFile, "(val1 < val2)");
+ break;
+
+ case 7:
+ fprintf(outputFile, "(val1 <= val2)");
+ break;
+
+ case 8:
+ fprintf(outputFile, "val1 + val2");
+ break;
+
+ case 9:
+ fprintf(outputFile, "val2 - val1");
+ break;
+
+ case 10:
+ fprintf(outputFile, "val1 * val2");
+ break;
+
+ case 11:
+ fprintf(outputFile, "val2 / val1");
+ break;
+
+ case 12:
+ fprintf(outputFile, "val2 >> val1");
+ break;
+
+ case 13:
+ fprintf(outputFile, "val2 << val1");
+ break;
+
+ case 14:
+ fprintf(outputFile, "val1 & val2");
+ break;
+
+ case 15:
+ fprintf(outputFile, "val1 | val2");
+ break;
+
+ case 16:
+ fprintf(outputFile, "val2 %% val1");
+ break;
+
+ case 17:
+ fprintf(outputFile, "val1 ^ val2");
+ break;
+
+ default:
+ fprintf(outputFile, "!error breaking exectution!");
+ break;
+ }
+
+ fprintf(outputFile, "'\n");
+}
+
+void c1_setRetAndJmp(ScriptData *script, int argument) {
+ fprintf(outputFile, "c1_setRetAndJmp %d\n", argument);
+}
+
+void setupCommandsV1(Script *myScript) {
+ static CommandProc commands[] = {
+ &c1_jumpTo,
+ &c1_setRetValue,
+ &c1_pushRetOrPos,
+ &c1_push,
+ &c1_push,
+ &c1_pushVar,
+ &c1_pushBPNeg,
+ &c1_pushBPAdd,
+ &c1_popRetOrPos,
+ &c1_popVar,
+ &c1_popBPNeg,
+ &c1_popBPAdd,
+ &c1_addSP,
+ &c1_subSP,
+ &c1_execOpcode,
+ &c1_ifNotJmp,
+ &c1_negate,
+ &c1_eval,
+ &c1_setRetAndJmp
+ };
+
+ myScript->setCommands(commands, ARRAYSIZE(commands));
+}
+
+// trace commands
+void c1_traceJumpTo(ScriptData *script, int argument) {
+ Function *call = script->getFunction(((uint)argument) << 1);
+ if (call) {
+ for (int i = 0; i < call->refs; ++i) {
+ if (call->refOffs[i] == script->curOffset)
+ return;
+ }
+
+ if (call->refs < MAX_REFS) {
+ call->refOffs[call->refs++] = script->curOffset;
+ } else {
+ warning("losing ref");
+ }
+ } else {
+ if (script->numFunctions < MAX_FUNCTIONS) {
+ call = &script->functions[script->numFunctions];
+ call->id = -1;
+ call->startOffset = ((uint)argument) << 1;
+ call->refOffs[call->refs++] = script->curOffset;
+ ++script->numFunctions;
+ } else {
+ warning("losing function");
+ }
+ }
+}
+
+void c1_traceIfNotJmp(ScriptData *script, int argument) {
+ Function *call = script->getFunction(((uint)argument) << 1);
+ if (call) {
+ for (int i = 0; i < call->refs; ++i) {
+ if (call->refOffs[i] == script->curOffset)
+ return;
+ }
+
+ if (call->refs < MAX_REFS) {
+ call->refOffs[call->refs++] = script->curOffset;
+ } else {
+ warning("losing ref");
+ }
+ } else {
+ if (script->numFunctions < MAX_FUNCTIONS) {
+ call = &script->functions[script->numFunctions];
+ call->id = -1;
+ call->startOffset = ((uint)argument) << 1;
+ call->refOffs[call->refs++] = script->curOffset;
+ ++script->numFunctions;
+ } else {
+ warning("losing function");
+ }
+ }
+}
+
+void c1_traceSetRetAndJmp(ScriptData *script, int argument) {
+ Function *call = script->getFunction(((uint)argument) << 1);
+ if (call) {
+ for (int i = 0; i < call->refs; ++i) {
+ if (call->refOffs[i] == script->curOffset)
+ return;
+ }
+
+ if (call->refs < MAX_REFS) {
+ call->refOffs[call->refs++] = script->curOffset;
+ } else {
+ warning("losing ref");
+ }
+ } else {
+ if (script->numFunctions < MAX_FUNCTIONS) {
+ call = &script->functions[script->numFunctions];
+ call->id = -1;
+ call->startOffset = ((uint)argument) << 1;
+ call->refOffs[call->refs++] = script->curOffset;
+ ++script->numFunctions;
+ } else {
+ warning("losing function");
+ }
+ }
+}
+
+void setupTraceCommandsV1(Script *myScript) {
+ static CommandProc commands[] = {
+ &c1_traceJumpTo,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &c1_traceIfNotJmp,
+ 0,
+ 0,
+ &c1_traceSetRetAndJmp
+ };
+
+ myScript->setCommands(commands, ARRAYSIZE(commands));
+}
+
+// opcode tables
+void getOpcodesV1(OpcodeEntry *&opcodes, int &opcodesSize) {
+ static OpcodeEntry kyra1OpcodeDesc[] = {
+ { 0x00 ,"o1_magicInMouseItem" },
+ { 0x01 ,"o1_characterSays" },
+ { 0x02 ,"o1_pauseTicks" },
+ { 0x03 ,"o1_drawSceneAnimShape" },
+ { 0x04 ,"o1_queryGameFlag" },
+ { 0x05 ,"o1_setGameFlag" },
+ { 0x06 ,"o1_resetGameFlag" },
+ { 0x07 ,"o1_runNPCScript" },
+ { 0x08 ,"o1_setSpecialExitList" },
+ { 0x09 ,"o1_blockInWalkableRegion" },
+ { 0x0A ,"o1_blockOutWalkableRegion" },
+ { 0x0B ,"o1_walkPlayerToPoint" },
+ { 0x0C ,"o1_dropItemInScene" },
+ { 0x0D ,"o1_drawAnimShapeIntoScene" },
+ { 0x0E ,"o1_createMouseItem" },
+ { 0x0F ,"o1_savePageToDisk" },
+ { 0x10 ,"o1_sceneAnimOn" },
+ { 0x11 ,"o1_sceneAnimOff" },
+ { 0x12 ,"o1_elapsedSeconds" },
+ { 0x13 ,"o1_mouseIsPointer" },
+ { 0x14 ,"o1_destroyMouseItem" },
+ { 0x15 ,"o1_runSceneAnimUntilDone" },
+ { 0x16 ,"o1_fadeSpecialPalette" },
+ { 0x17 ,"o1_playAdLibSound" },
+ { 0x18 ,"o1_playAdLibScore" },
+ { 0x19 ,"o1_phaseInSameScene" },
+ { 0x1a ,"o1_setScenePhasingFlag" },
+ { 0x1b ,"o1_resetScenePhasingFlag" },
+ { 0x1c ,"o1_queryScenePhasingFlag" },
+ { 0x1d ,"o1_sceneToDirection" },
+ { 0x1e ,"o1_setBirthstoneGem" },
+ { 0x1f ,"o1_rlaceItemInGenericMapScene" },
+ { 0x20 ,"o1_setBrandonStatusBit" },
+ { 0x21 ,"o1_pauseSeconds" },
+ { 0x22 ,"o1_getCharactersLocation" },
+ { 0x23 ,"o1_runNPCSubscript" },
+ { 0x24 ,"o1_magicOutMouseItem" },
+ { 0x25 ,"o1_internalAnimOn" },
+ { 0x26 ,"o1_forceBrandonToNormal" },
+ { 0x27 ,"o1_poisonDeathNow" },
+ { 0x28 ,"o1_setScaleMode" },
+ { 0x29 ,"o1_openWSAFile" },
+ { 0x2a ,"o1_closeWSAFile" },
+ { 0x2b ,"o1_runWSAFromBeginningToEnd" },
+ { 0x2c ,"o1_displayWSAFrame" },
+ { 0x2d ,"o1_enterNewScene" },
+ { 0x2e ,"o1_setSpecialEnterXAndY" },
+ { 0x2f ,"o1_runWSAFrames" },
+ { 0x30 ,"o1_popBrandonIntoScene" },
+ { 0x31 ,"o1_restoreAllObjectBackgrounds" },
+ { 0x32 ,"o1_setCustomPaletteRange" },
+ { 0x33 ,"o1_loadPageFromDisk" },
+ { 0x34 ,"o1_customPrintTalkString" },
+ { 0x35 ,"o1_restoreCustomPrintBackground" },
+ { 0x36 ,"o1_hideMouse" },
+ { 0x37 ,"o1_showMouse" },
+ { 0x38 ,"o1_getCharacterX" },
+ { 0x39 ,"o1_getCharacterY" },
+ { 0x3A ,"o1_changeCharactersFacing" },
+ { 0x3B ,"o1_copyWSARegion" },
+ { 0x3C ,"o1_textPrint" },
+ { 0x3D ,"o1_random" },
+ { 0x3E ,"o1_loadSoundFile" },
+ { 0x3F ,"o1_displayWSAFrameOnHidPage" },
+ { 0x40 ,"o1_displayWSASequentialFrames" },
+ { 0x41 ,"o1_drawCharacterStanding" },
+ { 0x42 ,"o1_internalAnimOff" },
+ { 0x43 ,"o1_changeCharactersXAndY" },
+ { 0x44 ,"o1_clearSceneAnimatorBeacon" },
+ { 0x45 ,"o1_querySceneAnimatorBeacon" },
+ { 0x46 ,"o1_refreshSceneAnimator" },
+ { 0x47 ,"o1_placeItemInOffScene" },
+ { 0x48 ,"o1_wipeDownMouseItem" },
+ { 0x49 ,"o1_placeCharacterInOtherScene" },
+ { 0x4A ,"o1_getKey" },
+ { 0x4B ,"o1_specificItemInInventory" },
+ { 0x4C ,"o1_popMobileNPCIntoScene" },
+ { 0x4D ,"o1_mobileCharacterInScene" },
+ { 0x4E ,"o1_hideMobileCharacter" },
+ { 0x4F ,"o1_unhideMobileCharacter" },
+ { 0x50 ,"o1_setCharactersLocation" },
+ { 0x51 ,"o1_walkCharacterToPoint" },
+ { 0x52 ,"o1_specialEventDisplayBrynnsNote" },
+ { 0x53 ,"o1_specialEventRemoveBrynnsNote" },
+ { 0x54 ,"o1_setLogicPage" },
+ { 0x55 ,"o1_fatPrint" },
+ { 0x56 ,"o1_preserveAllObjectBackgrounds" },
+ { 0x57 ,"o1_updateSceneAnimations" },
+ { 0x58 ,"o1_sceneAnimationActive" },
+ { 0x59 ,"o1_setCharactersMovementDelay" },
+ { 0x5A ,"o1_getCharactersFacing" },
+ { 0x5B ,"o1_bkgdScrollSceneAndMasksRight" },
+ { 0x5C ,"o1_dispelMagicAnimation" },
+ { 0x5d ,"o1_findBrightestFireberry" },
+ { 0x5e ,"o1_setFireberryGlowPalette" },
+ { 0x5f ,"o1_setDeathHandlerFlag" },
+ { 0x60 ,"o1_drinkPotionAnimation" },
+ { 0x61 ,"o1_makeAmuletAppear" },
+ { 0x62 ,"o1_drawItemShapeIntoScene" },
+ { 0x63 ,"o1_setCharactersCurrentFrame" },
+ { 0x64 ,"o1_waitForConfirmationMouseClick" },
+ { 0x65 ,"o1_pageFlip" },
+ { 0x66 ,"o1_setSceneFile" },
+ { 0x67 ,"o1_whatItemInMarbleVase" },
+ { 0x68 ,"o1_setItemInMarbleVase" },
+ { 0x69 ,"o1_addItemToInventory" },
+ { 0x6a ,"o1_intPrint" },
+ { 0x6b ,"o1_shakeScreen" },
+ { 0x6c ,"o1_createAmuletJewel" },
+ { 0x6d ,"o1_setSceneAnimCurrXY" },
+ { 0x6e ,"o1_poisonBrandonAndRemaps" },
+ { 0x6f ,"o1_fillFlaskWithWater" },
+ { 0x70 ,"o1_getCharactersMovementDelay" },
+ { 0x71 ,"o1_getBirthstoneGem" },
+ { 0x72 ,"o1_queryBrandonStatusBit" },
+ { 0x73 ,"o1_playFluteAnimation" },
+ { 0x74 ,"o1_playWinterScrollSequence" },
+ { 0x75 ,"o1_getIdolGem" },
+ { 0x76 ,"o1_setIdolGem" },
+ { 0x77 ,"o1_totalItemsInScene" },
+ { 0x78 ,"o1_restoreBrandonsMovementDelay" },
+ { 0x79 ,"o1_setMousePos" },
+ { 0x7a ,"o1_getMouseState" },
+ { 0x7b ,"o1_setEntranceMouseCursorTrack" },
+ { 0x7c ,"o1_itemAppearsOnGround" },
+ { 0x7d ,"o1_setNoDrawShapesFlag" },
+ { 0x7e ,"o1_fadeEntirePalette" },
+ { 0x7f ,"o1_itemOnGroundHere" },
+ { 0x80 ,"o1_queryCauldronState" },
+ { 0x81 ,"o1_setCauldronState" },
+ { 0x82 ,"o1_queryCrystalState" },
+ { 0x83 ,"o1_setCrystalState" },
+ { 0x84 ,"o1_setPaletteRange" },
+ { 0x85 ,"o1_shrinkBrandonDown" },
+ { 0x86 ,"o1_growBrandonUp" },
+ { 0x87 ,"o1_setBrandonScaleXAndY" },
+ { 0x88 ,"o1_resetScaleMode" },
+ { 0x89 ,"o1_getScaleDepthTableValue" },
+ { 0x8a ,"o1_setScaleDepthTableValue" },
+ { 0x8b ,"o1_message" },
+ { 0x8c ,"o1_checkClickOnNPC" },
+ { 0x8d ,"o1_getFoyerItem" },
+ { 0x8e ,"o1_setFoyerItem" },
+ { 0x8F ,"o1_setNoItemDropRegion" },
+ { 0x90 ,"o1_walkMalcolmOn" },
+ { 0x91 ,"o1_passiveProtection" },
+ { 0x92 ,"o1_setPlayingLoop" },
+ { 0x93 ,"o1_brandonToStoneSequence" },
+ { 0x94 ,"o1_brandonHealingSequence" },
+ { 0x95 ,"o1_protectCommandLine" },
+ { 0x96 ,"o1_pauseMusicSeconds" },
+ { 0x97 ,"o1_resetMaskRegion" },
+ { 0x98 ,"o1_setPaletteChangeFlag" },
+ { 0x99 ,"o1_fillRect" },
+ { 0x9a ,"o1_vocUnload" },
+ { 0x9b ,"o1_vocLoad" },
+ { 0x9c ,"o1_dummy" }
+ };
+
+ opcodes = kyra1OpcodeDesc;
+ opcodesSize = ARRAYSIZE(kyra1OpcodeDesc);
+}
Property changes on: tools/trunk/dekyra_v1.cpp
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Id,URL
Name: svn:eol-style
+ native
More information about the Scummvm-git-logs
mailing list