scummvm/engines/sci/engine/script.cpp
Filippos Karapetis e940bcff23 - Simplified SCI version detection a bit and clarified the different version feature flags (not used yet)
- Removed the version verification functions (they were only used for two specific cases, but the SCI executable reader is able to detect the exact SCI game version anyway, so there is no point in having these)
- Removed the empty GameFlags structure and replaced it with a 32-bit integer instead

svn-id: r40524
2009-05-13 16:52:41 +00:00

458 lines
14 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 "sci/sci.h"
#include "sci/scicore/resource.h"
#include "sci/engine/state.h"
#include "common/util.h"
namespace Sci {
// #define SCRIPT_DEBUG
#define END Script_None
opcode_format g_opcode_formats[128][4] = {
/*00*/
{Script_None}, {Script_None}, {Script_None}, {Script_None},
/*04*/
{Script_None}, {Script_None}, {Script_None}, {Script_None},
/*08*/
{Script_None}, {Script_None}, {Script_None}, {Script_None},
/*0C*/
{Script_None}, {Script_None}, {Script_None}, {Script_None},
/*10*/
{Script_None}, {Script_None}, {Script_None}, {Script_None},
/*14*/
{Script_None}, {Script_None}, {Script_None}, {Script_SRelative, END},
/*18*/
{Script_SRelative, END}, {Script_SRelative, END}, {Script_SVariable, END}, {Script_None},
/*1C*/
{Script_SVariable, END}, {Script_None}, {Script_None}, {Script_Variable, END},
/*20*/
{Script_SRelative, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_SVariable, Script_Byte, END},
/*24 (24=ret)*/
{Script_End}, {Script_Byte, END}, {Script_Invalid}, {Script_Invalid},
/*28*/
{Script_Variable, END}, {Script_Invalid}, {Script_Byte, END}, {Script_Variable, Script_Byte, END},
/*2C*/
{Script_SVariable, END}, {Script_SVariable, Script_Variable, END}, {Script_None}, {Script_Invalid},
/*30*/
{Script_None}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
/*34*/
{Script_Property, END}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
/*38*/
{Script_Property, END}, {Script_SRelative, END}, {Script_SRelative, END}, {Script_None},
/*3C*/
{Script_None}, {Script_None}, {Script_None}, {Script_Invalid},
/*40-4F*/
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
/*50-5F*/
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
/*60-6F*/
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
/*70-7F*/
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END}
};
#undef END
void script_adjust_opcode_formats(int res_version) {
switch (res_version) {
case SCI_VERSION_0:
case SCI_VERSION_01:
break;
case SCI_VERSION_01_VGA:
case SCI_VERSION_01_VGA_ODD:
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_1_1:
g_opcode_formats[op_lofsa][0] = Script_Offset;
g_opcode_formats[op_lofss][0] = Script_Offset;
break;
default:
sciprintf("script_adjust_opcode_formats(): Unknown script version %d\n", res_version);
}
}
int script_find_selector(EngineState *s, const char *selectorname) {
for (uint pos = 0; pos < s->_selectorNames.size(); ++pos) {
if (s->_selectorNames[pos] == selectorname)
return pos;
}
warning("Could not map '%s' to any selector", selectorname);
return -1;
}
#define FIND_SELECTOR(_slc_) map->_slc_ = script_find_selector(s, #_slc_)
#define FIND_SELECTOR2(_slc_, _slcstr_) map->_slc_ = script_find_selector(s, _slcstr_)
void script_map_selectors(EngineState *s, selector_map_t *map) {
FIND_SELECTOR(init);
FIND_SELECTOR(play);
FIND_SELECTOR(replay);
FIND_SELECTOR(x);
FIND_SELECTOR(y);
FIND_SELECTOR(z);
FIND_SELECTOR(priority);
FIND_SELECTOR(view);
FIND_SELECTOR(loop);
FIND_SELECTOR(cel);
FIND_SELECTOR(brLeft);
FIND_SELECTOR(brRight);
FIND_SELECTOR(brTop);
FIND_SELECTOR(brBottom);
FIND_SELECTOR(xStep);
FIND_SELECTOR(yStep);
FIND_SELECTOR(nsBottom);
FIND_SELECTOR(nsTop);
FIND_SELECTOR(nsLeft);
FIND_SELECTOR(nsRight);
FIND_SELECTOR(font);
FIND_SELECTOR(text);
FIND_SELECTOR(type);
FIND_SELECTOR(state);
FIND_SELECTOR(doit);
FIND_SELECTOR2(delete_, "delete");
FIND_SELECTOR(signal);
FIND_SELECTOR(underBits);
FIND_SELECTOR(canBeHere);
FIND_SELECTOR(client);
FIND_SELECTOR(dx);
FIND_SELECTOR(dy);
FIND_SELECTOR(xStep);
FIND_SELECTOR(yStep);
FIND_SELECTOR2(b_movCnt, "b-moveCnt");
FIND_SELECTOR2(b_i1, "b-i1");
FIND_SELECTOR2(b_i2, "b-i2");
FIND_SELECTOR2(b_di, "b-di");
FIND_SELECTOR2(b_xAxis, "b-xAxis");
FIND_SELECTOR2(b_incr, "b-incr");
FIND_SELECTOR(completed);
FIND_SELECTOR(illegalBits);
FIND_SELECTOR(dispose);
FIND_SELECTOR(prevSignal);
FIND_SELECTOR(message);
FIND_SELECTOR(modifiers);
FIND_SELECTOR(cue);
FIND_SELECTOR(owner);
FIND_SELECTOR(handle);
FIND_SELECTOR(number);
FIND_SELECTOR(max);
FIND_SELECTOR(cursor);
FIND_SELECTOR(claimed);
FIND_SELECTOR(edgeHit);
FIND_SELECTOR(wordFail);
FIND_SELECTOR(syntaxFail);
FIND_SELECTOR(semanticFail);
FIND_SELECTOR(cycler);
FIND_SELECTOR(elements);
FIND_SELECTOR(lsTop);
FIND_SELECTOR(lsBottom);
FIND_SELECTOR(lsLeft);
FIND_SELECTOR(lsRight);
FIND_SELECTOR(baseSetter);
FIND_SELECTOR(who);
FIND_SELECTOR(distance);
FIND_SELECTOR(mover);
FIND_SELECTOR(looper);
FIND_SELECTOR(isBlocked);
FIND_SELECTOR(heading);
FIND_SELECTOR(mode);
FIND_SELECTOR(caller);
FIND_SELECTOR(moveDone);
FIND_SELECTOR(vol);
FIND_SELECTOR(pri);
FIND_SELECTOR(min);
FIND_SELECTOR(sec);
FIND_SELECTOR(frame);
FIND_SELECTOR(dataInc);
FIND_SELECTOR(size);
FIND_SELECTOR(palette);
FIND_SELECTOR(moveSpeed);
FIND_SELECTOR(cantBeHere);
FIND_SELECTOR(nodePtr);
FIND_SELECTOR(flags);
FIND_SELECTOR(points);
FIND_SELECTOR(syncCue);
FIND_SELECTOR(syncTime);
}
static void script_dump_object(char *data, int seeker, int objsize, const Common::StringList &selectorNames) {
int selectors, overloads, selectorsize;
int species = (int16)READ_LE_UINT16((unsigned char *) data + 8 + seeker);
int superclass = (int16)READ_LE_UINT16((unsigned char *) data + 10 + seeker);
int namepos = (int16)READ_LE_UINT16((unsigned char *) data + 14 + seeker);
int i = 0;
sciprintf("Object\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
//-4 because the size includes the two-word header
sciprintf("Name: %s\n", namepos ? ((char *)(data + namepos)) : "<unknown>");
sciprintf("Superclass: %x\n", superclass);
sciprintf("Species: %x\n", species);
sciprintf("-info-:%x\n", (int16)READ_LE_UINT16((unsigned char *) data + 12 + seeker) & 0xffff);
sciprintf("Function area offset: %x\n", (int16)READ_LE_UINT16((unsigned char *) data + seeker + 4));
sciprintf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_LE_UINT16((unsigned char *) data + seeker + 6)));
seeker += 8;
while (selectors--) {
sciprintf(" [#%03x] = 0x%x\n", i++, (int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
}
sciprintf("Overridden functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
if (overloads < 100)
while (overloads--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker));
sciprintf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)selectorNames.size()) ? selectorNames[selector].c_str() : "<?>");
sciprintf("%04x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + selectors*2 + 2) & 0xffff);
seeker += 2;
}
}
static void script_dump_class(char *data, int seeker, int objsize, const Common::StringList &selectorNames) {
int selectors, overloads, selectorsize;
int species = (int16)READ_LE_UINT16((unsigned char *) data + 8 + seeker);
int superclass = (int16)READ_LE_UINT16((unsigned char *) data + 10 + seeker);
int namepos = (int16)READ_LE_UINT16((unsigned char *) data + 14 + seeker);
sciprintf("Class\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
sciprintf("Name: %s\n", namepos ? ((char *)data + namepos) : "<unknown>");
sciprintf("Superclass: %x\n", superclass);
sciprintf("Species: %x\n", species);
sciprintf("-info-:%x\n", (int16)READ_LE_UINT16((unsigned char *)data + 12 + seeker) & 0xffff);
sciprintf("Function area offset: %x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + 4));
sciprintf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_LE_UINT16((unsigned char *)data + seeker + 6)));
seeker += 8;
selectorsize <<= 1;
while (selectors--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker) + selectorsize);
sciprintf(" [%03x] %s = 0x%x\n", 0xffff & selector, (selector >= 0 && selector < (int)selectorNames.size()) ? selectorNames[selector].c_str() : "<?>",
(int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
}
seeker += selectorsize;
sciprintf("Overloaded functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
while (overloads--) {
int selector = (int16)READ_LE_UINT16((unsigned char *)data + (seeker));
fprintf(stderr, "selector=%d; selectorNames.size() =%d\n", selector, selectorNames.size());
sciprintf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)selectorNames.size()) ?
selectorNames[selector].c_str() : "<?>");
sciprintf("%04x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + selectors * 2 + 2) & 0xffff);
seeker += 2;
}
}
void script_dissect(ResourceManager *resmgr, int res_no, const Common::StringList &selectorNames) {
int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned int _seeker = 0;
Resource *script = resmgr->findResource(kResourceTypeScript, res_no, 0);
WordMap words;
if (!script) {
sciprintf("Script not found!\n");
return;
}
vocab_get_words(resmgr, words);
while (_seeker < script->size) {
int objtype = (int16)READ_LE_UINT16(script->data + _seeker);
int objsize;
unsigned int seeker = _seeker + 4;
if (!objtype) {
sciprintf("End of script object (#0) encountered.\n");
sciprintf("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)",
objectctr[6], objectctr[1], objectctr[7], objectctr[10]);
return;
}
sciprintf("\n");
objsize = (int16)READ_LE_UINT16(script->data + _seeker + 2);
sciprintf("Obj type #%x, size 0x%x: ", objtype, objsize);
_seeker += objsize;
objectctr[objtype]++;
switch (objtype) {
case sci_obj_object:
script_dump_object((char *)script->data, seeker, objsize, selectorNames);
break;
case sci_obj_code: {
sciprintf("Code\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case 3: {
sciprintf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case sci_obj_said: {
sciprintf("Said\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
sciprintf("%04x: ", seeker);
while (seeker < _seeker) {
unsigned char nextitem = script->data [seeker++];
if (nextitem == 0xFF)
sciprintf("\n%04x: ", seeker);
else if (nextitem >= 0xF0) {
switch (nextitem) {
case 0xf0:
sciprintf(", ");
break;
case 0xf1:
sciprintf("& ");
break;
case 0xf2:
sciprintf("/ ");
break;
case 0xf3:
sciprintf("( ");
break;
case 0xf4:
sciprintf(") ");
break;
case 0xf5:
sciprintf("[ ");
break;
case 0xf6:
sciprintf("] ");
break;
case 0xf7:
sciprintf("# ");
break;
case 0xf8:
sciprintf("< ");
break;
case 0xf9:
sciprintf("> ");
break;
}
} else {
nextitem = nextitem << 8 | script->data [seeker++];
sciprintf("%s[%03x] ", vocab_get_any_group_word(nextitem, words), nextitem);
}
}
sciprintf("\n");
}
break;
case sci_obj_strings: {
sciprintf("Strings\n");
while (script->data [seeker]) {
sciprintf("%04x: %s\n", seeker, script->data + seeker);
seeker += strlen((char *)script->data + seeker) + 1;
}
seeker++; // the ending zero byte
};
break;
case sci_obj_class:
script_dump_class((char *)script->data, seeker, objsize, selectorNames);
break;
case sci_obj_exports: {
sciprintf("Exports\n");
Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker);
};
break;
case sci_obj_pointers: {
sciprintf("Pointers\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case 9: {
sciprintf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case sci_obj_localvars: {
sciprintf("Local vars\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
default:
sciprintf("Unsupported!\n");
return;
}
}
sciprintf("Script ends without terminator\n");
}
} // End of namespace Sci