aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/console.cpp14
-rw-r--r--engines/sci/engine/game.cpp4
-rw-r--r--engines/sci/engine/kernel.cpp87
-rw-r--r--engines/sci/engine/kernel.h86
-rw-r--r--engines/sci/engine/kgraphics.cpp20
-rw-r--r--engines/sci/engine/kmisc.cpp2
-rw-r--r--engines/sci/engine/kmovement.cpp4
-rw-r--r--engines/sci/engine/kscripts.cpp6
-rw-r--r--engines/sci/engine/savegame.cpp9
-rw-r--r--engines/sci/engine/script.cpp10
-rw-r--r--engines/sci/engine/scriptdebug.cpp34
-rw-r--r--engines/sci/engine/state.cpp1
-rw-r--r--engines/sci/engine/state.h3
-rw-r--r--engines/sci/engine/vm.cpp8
-rw-r--r--engines/sci/vocabulary.cpp73
-rw-r--r--engines/sci/vocabulary.h73
16 files changed, 226 insertions, 208 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index a8883b549c..56605e1d17 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -134,8 +134,8 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
bool Console::cmdOpcodes(int argc, const char **argv) {
DebugPrintf("Opcode names in numeric order [index: type name]:\n");
- for (uint seeker = 0; seeker < g_EngineState->_vocabulary->getOpcodesSize(); seeker++) {
- opcode op = g_EngineState->_vocabulary->getOpcode(seeker);
+ for (uint seeker = 0; seeker < g_EngineState->_kernel->getOpcodesSize(); seeker++) {
+ opcode op = g_EngineState->_kernel->getOpcode(seeker);
DebugPrintf("%03x: %03x %20s | ", seeker, op.type, op.name.c_str());
if ((seeker % 3) == 2)
DebugPrintf("\n");
@@ -148,8 +148,8 @@ bool Console::cmdOpcodes(int argc, const char **argv) {
bool Console::cmdSelectors(int argc, const char **argv) {
DebugPrintf("Selector names in numeric order:\n");
- for (uint seeker = 0; seeker < g_EngineState->_vocabulary->getSelectorNamesSize(); seeker++) {
- DebugPrintf("%03x: %20s | ", seeker, g_EngineState->_vocabulary->getSelectorName(seeker).c_str());
+ for (uint seeker = 0; seeker < g_EngineState->_kernel->getSelectorNamesSize(); seeker++) {
+ DebugPrintf("%03x: %20s | ", seeker, g_EngineState->_kernel->getSelectorName(seeker).c_str());
if ((seeker % 3) == 2)
DebugPrintf("\n");
}
@@ -161,8 +161,8 @@ bool Console::cmdSelectors(int argc, const char **argv) {
bool Console::cmdKernelNames(int argc, const char **argv) {
DebugPrintf("Selector names in numeric order:\n");
- for (uint seeker = 0; seeker < g_EngineState->_vocabulary->getKernelNamesSize(); seeker++) {
- DebugPrintf("%03x: %20s | ", seeker, g_EngineState->_vocabulary->getKernelName(seeker).c_str());
+ for (uint seeker = 0; seeker < g_EngineState->_kernel->getKernelNamesSize(); seeker++) {
+ DebugPrintf("%03x: %20s | ", seeker, g_EngineState->_kernel->getKernelName(seeker).c_str());
if ((seeker % 3) == 2)
DebugPrintf("\n");
}
@@ -221,7 +221,7 @@ bool Console::cmdDissectScript(int argc, const char **argv) {
return true;
}
- g_EngineState->_vocabulary->dissectScript(atoi(argv[1]));
+ g_EngineState->_kernel->dissectScript(atoi(argv[1]), g_EngineState->_vocabulary);
return true;
}
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index 0355bb3966..192aa66367 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -372,7 +372,8 @@ int script_init_engine(EngineState *s, sci_version_t version) {
s->parser_lastmatch_word = SAID_NO_MATCH;
- s->_vocabulary = new Vocabulary(s->resmgr, (s->flags & GF_SCI0_OLD));
+ s->_kernel = new Kernel(s->resmgr, (s->flags & GF_SCI0_OLD));
+ s->_vocabulary = new Vocabulary(s->resmgr);
script_map_kernel(s);
// Maps the kernel functions
@@ -423,6 +424,7 @@ void script_free_engine(EngineState *s) {
s->_kfuncTable.clear();
delete s->_vocabulary;
+ delete s->_kernel;
}
void script_free_breakpoints(EngineState *s) {
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 23f1fc911d..740673afab 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -469,7 +469,80 @@ SciKernelFunction kfunct_mappers[] = {
{KF_TERMINATOR, NULL, NULL, NULL} // Terminator
};
-static const char *argtype_description[] = { "Undetermined (WTF?)", "List", "Node", "Object", "Reference", "Arithmetic" };
+static const char *argtype_description[] = { "Undetermined", "List", "Node", "Object", "Reference", "Arithmetic" };
+
+Kernel::Kernel(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr) {
+ memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t
+
+ loadKernelNames();
+
+ loadOpcodes();
+
+ if (!loadSelectorNames(isOldSci0)) {
+ error("Kernel: Could not retrieve selector names");
+ }
+
+ // Map a few special selectors for later use
+ mapSelectors();
+}
+
+Kernel::~Kernel() {
+ _selectorNames.clear();
+ _opcodes.clear();
+ _kernelNames.clear();
+}
+
+bool Kernel::loadSelectorNames(bool isOldSci0) {
+ int count;
+
+ Resource *r = _resmgr->findResource(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES, 0);
+
+ if (!r) // No such resource?
+ return false;
+
+ count = READ_LE_UINT16(r->data) + 1; // Counter is slightly off
+
+ for (int i = 0; i < count; i++) {
+ int offset = READ_LE_UINT16(r->data + 2 + i * 2);
+ int len = READ_LE_UINT16(r->data + offset);
+
+ Common::String tmp((const char *)r->data + offset + 2, len);
+ _selectorNames.push_back(tmp);
+
+ // Early SCI versions used the LSB in the selector ID as a read/write
+ // toggle. To compensate for that, we add every selector name twice.
+ if (isOldSci0)
+ _selectorNames.push_back(tmp);
+ }
+
+ return true;
+}
+
+bool Kernel::loadOpcodes() {
+ int count, i = 0;
+ Resource* r = _resmgr->findResource(kResourceTypeVocab, VOCAB_RESOURCE_OPCODES, 0);
+
+ _opcodes.clear();
+
+ // if the resource couldn't be loaded, leave
+ if (r == NULL) {
+ warning("unable to load vocab.%03d", VOCAB_RESOURCE_OPCODES);
+ return false;
+ }
+
+ count = READ_LE_UINT16(r->data);
+
+ _opcodes.resize(count);
+ for (i = 0; i < count; i++) {
+ int offset = READ_LE_UINT16(r->data + 2 + i * 2);
+ int len = READ_LE_UINT16(r->data + offset) - 2;
+ _opcodes[i].type = READ_LE_UINT16(r->data + offset + 2);
+ // QFG3 has empty opcodes
+ _opcodes[i].name = len > 0 ? Common::String((char *)r->data + offset + 4, len) : "Dummy";
+ }
+
+ return true;
+}
// Allocates a set amount of memory for a specified use and returns a handle to it.
reg_t kalloc(EngineState *s, const char *type, int space) {
@@ -582,7 +655,7 @@ void kernel_compile_signature(const char **s) {
int script_map_kernel(EngineState *s) {
int mapped = 0;
int ignored = 0;
- uint functions_nr = s->_vocabulary->getKernelNamesSize();
+ uint functions_nr = s->_kernel->getKernelNamesSize();
uint max_functions_nr = (s->resmgr->_sciVersion == SCI_VERSION_0) ? 0x72 : 0x7b;
if (functions_nr < max_functions_nr) {
@@ -599,8 +672,8 @@ int script_map_kernel(EngineState *s) {
int seeker, found = -1;
Common::String sought_name;
- if (functnr < s->_vocabulary->getKernelNamesSize())
- sought_name = s->_vocabulary->getKernelName(functnr);
+ if (functnr < s->_kernel->getKernelNamesSize())
+ sought_name = s->_kernel->getKernelName(functnr);
if (!sought_name.empty())
for (seeker = 0; (found == -1) && kfunct_mappers[seeker].type != KF_TERMINATOR; seeker++)
@@ -609,7 +682,7 @@ int script_map_kernel(EngineState *s) {
if (found == -1) {
if (!sought_name.empty()) {
- warning("Kernel function %s[%x] unmapped", s->_vocabulary->getKernelName(functnr).c_str(), functnr);
+ warning("Kernel function %s[%x] unmapped", s->_kernel->getKernelName(functnr).c_str(), functnr);
s->_kfuncTable[functnr].fun = kNOP;
} else {
warning("Flagging kernel function %x as unknown", functnr);
@@ -639,7 +712,7 @@ int script_map_kernel(EngineState *s) {
} // for all functions requesting to be mapped
- sciprintf("Handled %d/%d kernel functions, mapping %d", mapped + ignored, s->_vocabulary->getKernelNamesSize(), mapped);
+ sciprintf("Handled %d/%d kernel functions, mapping %d", mapped + ignored, s->_kernel->getKernelNamesSize(), mapped);
if (ignored)
sciprintf(" and ignoring %d", ignored);
sciprintf(".\n");
@@ -885,7 +958,7 @@ static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &name
}
#endif
-bool Vocabulary::loadKernelNames() {
+bool Kernel::loadKernelNames() {
_kernelNames.clear();
switch (_resmgr->_sciVersion) {
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 557b308506..1ef1e918d9 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -31,6 +31,7 @@
#include "common/rect.h"
#include "sci/uinput.h"
+#include "sci/vocabulary.h"
namespace Sci {
@@ -45,7 +46,82 @@ extern int _debug_step_running;
#define AVOIDPATH_DYNMEM_STRING "AvoidPath polyline"
//#define DEBUG_PARSER // enable for parser debugging
-/* Formerly, the heap macros were here; they have been deprecated, however. */
+struct opcode {
+ int type;
+ Common::String name;
+};
+
+class Kernel {
+public:
+ Kernel(ResourceManager *resmgr, bool isOldSci0);
+ ~Kernel();
+
+ uint getOpcodesSize() const { return _opcodes.size(); }
+ const opcode &getOpcode(uint opcode) const { return _opcodes[opcode]; }
+
+ uint getSelectorNamesSize() const { return _selectorNames.size(); }
+ const Common::String &getSelectorName(uint selector) const { return _selectorNames[selector]; }
+
+ uint getKernelNamesSize() const { return _kernelNames.size(); }
+ const Common::String &getKernelName(uint number) const { return _kernelNames[number]; }
+
+ /* Determines the selector ID of a selector by its name
+ ** (const char *) selectorName: Name of the selector to look up
+ ** Returns : (int) The appropriate selector ID, or -1 on error
+ */
+ int findSelector(const char *selectorName) const;
+
+ /* Detects whether a particular kernel function is required in the game
+ ** (const char *) functionName: The name of the desired kernel function
+ ** Returns : (bool) true if the kernel function is listed in the kernel table,
+ ** false otherwise
+ */
+ bool hasKernelFunction(const char *functionName) const;
+
+ // Script dissection/dumping functions
+ void dissectScript(int scriptNumber, Vocabulary *vocab);
+ void dumpScriptObject(char *data, int seeker, int objsize);
+ void dumpScriptClass(char *data, int seeker, int objsize);
+
+ selector_map_t _selectorMap; /**< Shortcut list for important selectors */
+private:
+ /**
+ * Loads the kernel function names.
+ *
+ * This function reads the kernel function name table from resource_map,
+ * and fills the _kernelNames array with them.
+ * The resulting list has the same format regardless of the format of the
+ * name table of the resource (the format changed between version 0 and 1).
+ * @return true on success, false on failure
+ */
+ bool loadKernelNames();
+
+ /**
+ * Loads the kernel selector names.
+ * Returns true upon success, false otherwise.
+ */
+ bool loadSelectorNames(bool isOldSci0);
+
+ /* Maps special selectors
+ ** Returns : (void)
+ */
+ void mapSelectors();
+
+ /**
+ * Loads the opcode names (only used for debugging).
+ * @return true on success, false on failure
+ */
+ bool loadOpcodes();
+
+ ResourceManager *_resmgr;
+
+ // Kernel-related lists
+ // List of opcodes, loaded from vocab.998. This list is only used for debugging
+ // purposes, as we hardcode the list of opcodes in the sci_opcodes enum (script.h)
+ Common::Array<opcode> _opcodes;
+ Common::StringList _selectorNames;
+ Common::StringList _kernelNames;
+};
/******************** Selector functionality ********************/
@@ -54,7 +130,7 @@ enum SelectorInvocation {
kContinueOnInvalidSelector = 1
};
-#define GET_SEL32(_o_, _slc_) read_selector(s, _o_, s->_vocabulary->_selectorMap._slc_, __FILE__, __LINE__)
+#define GET_SEL32(_o_, _slc_) read_selector(s, _o_, s->_kernel->_selectorMap._slc_, __FILE__, __LINE__)
#define GET_SEL32V(_o_, _slc_) (GET_SEL32(_o_, _slc_).offset)
#define GET_SEL32SV(_o_, _slc_) ((int16)(GET_SEL32(_o_, _slc_).offset))
/* Retrieves a selector from an object
@@ -65,8 +141,8 @@ enum SelectorInvocation {
** selector_map_t and mapped in script.c.
*/
-#define PUT_SEL32(_o_, _slc_, _val_) write_selector(s, _o_, s->_vocabulary->_selectorMap._slc_, _val_, __FILE__, __LINE__)
-#define PUT_SEL32V(_o_, _slc_, _val_) write_selector(s, _o_, s->_vocabulary->_selectorMap._slc_, make_reg(0, _val_), __FILE__, __LINE__)
+#define PUT_SEL32(_o_, _slc_, _val_) write_selector(s, _o_, s->_kernel->_selectorMap._slc_, _val_, __FILE__, __LINE__)
+#define PUT_SEL32V(_o_, _slc_, _val_) write_selector(s, _o_, s->_kernel->_selectorMap._slc_, make_reg(0, _val_), __FILE__, __LINE__)
/* Writes a selector value to an object
** Parameters: (reg_t) object: The address of the object which the selector should be written to
** (selector_name) selector: The selector to read
@@ -78,7 +154,7 @@ enum SelectorInvocation {
#define INV_SEL(_object_, _selector_, _noinvalid_) \
- s, _object_, s->_vocabulary->_selectorMap._selector_, _noinvalid_, funct_nr, argv, argc, __FILE__, __LINE__
+ s, _object_, s->_kernel->_selectorMap._selector_, _noinvalid_, funct_nr, argv, argc, __FILE__, __LINE__
/* Kludge for use with invoke_selector(). Used for compatibility with compilers that can't
** handle vararg macros.
*/
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index b381d7dd51..2ce71c911d 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1076,7 +1076,7 @@ Common::Rect set_base(EngineState *s, reg_t object) {
x = GET_SEL32SV(object, x);
original_y = y = GET_SEL32SV(object, y);
- if (s->_vocabulary->_selectorMap.z > -1)
+ if (s->_kernel->_selectorMap.z > -1)
z = GET_SEL32SV(object, z);
else
z = 0;
@@ -1130,7 +1130,7 @@ Common::Rect set_base(EngineState *s, reg_t object) {
void _k_base_setter(EngineState *s, reg_t object) {
Common::Rect absrect = set_base(s, object);
- if (lookup_selector(s, object, s->_vocabulary->_selectorMap.brLeft, NULL, NULL) != kSelectorVariable)
+ if (lookup_selector(s, object, s->_kernel->_selectorMap.brLeft, NULL, NULL) != kSelectorVariable)
return; // non-fatal
// Note: there was a check here for a very old version of SCI, which supposedly needed
@@ -1211,7 +1211,7 @@ Common::Rect get_nsrect(EngineState *s, reg_t object, byte clip) {
x = GET_SEL32SV(object, x);
y = GET_SEL32SV(object, y);
- if (s->_vocabulary->_selectorMap.z > -1)
+ if (s->_kernel->_selectorMap.z > -1)
z = GET_SEL32SV(object, z);
else
z = 0;
@@ -1235,7 +1235,7 @@ Common::Rect get_nsrect(EngineState *s, reg_t object, byte clip) {
static void _k_set_now_seen(EngineState *s, reg_t object) {
Common::Rect absrect = get_nsrect(s, object, 0);
- if (lookup_selector(s, object, s->_vocabulary->_selectorMap.nsTop, NULL, NULL) != kSelectorVariable) {
+ if (lookup_selector(s, object, s->_kernel->_selectorMap.nsTop, NULL, NULL) != kSelectorVariable) {
return;
} // This isn't fatal
@@ -1720,7 +1720,7 @@ static void _k_view_list_do_postdraw(EngineState *s, GfxList *list) {
* if ((widget->signal & (_K_VIEW_SIG_FLAG_PRIVATE | _K_VIEW_SIG_FLAG_REMOVE | _K_VIEW_SIG_FLAG_NO_UPDATE)) == _K_VIEW_SIG_FLAG_PRIVATE) {
*/
if ((widget->signal & (_K_VIEW_SIG_FLAG_REMOVE | _K_VIEW_SIG_FLAG_NO_UPDATE)) == 0) {
- int has_nsrect = lookup_selector(s, obj, s->_vocabulary->_selectorMap.nsBottom, NULL, NULL) == kSelectorVariable;
+ int has_nsrect = lookup_selector(s, obj, s->_kernel->_selectorMap.nsBottom, NULL, NULL) == kSelectorVariable;
if (has_nsrect) {
int temp;
@@ -1742,7 +1742,7 @@ static void _k_view_list_do_postdraw(EngineState *s, GfxList *list) {
}
#ifdef DEBUG_LSRECT
else
- fprintf(stderr, "Not lsRecting %04x:%04x because %d\n", PRINT_REG(obj), lookup_selector(s, obj, s->_vocabulary->_selectorMap.nsBottom, NULL, NULL));
+ fprintf(stderr, "Not lsRecting %04x:%04x because %d\n", PRINT_REG(obj), lookup_selector(s, obj, s->_kernel->_selectorMap.nsBottom, NULL, NULL));
#endif
if (widget->signal & _K_VIEW_SIG_FLAG_HIDDEN)
@@ -1894,7 +1894,7 @@ static GfxDynView *_k_make_dynview_obj(EngineState *s, reg_t obj, int options, i
loop = oldloop = sign_extend_byte(GET_SEL32V(obj, loop));
cel = oldcel = sign_extend_byte(GET_SEL32V(obj, cel));
- if (s->_vocabulary->_selectorMap.palette)
+ if (s->_kernel->_selectorMap.palette)
palette = GET_SEL32V(obj, palette);
else
palette = 0;
@@ -1916,14 +1916,14 @@ static GfxDynView *_k_make_dynview_obj(EngineState *s, reg_t obj, int options, i
PUT_SEL32V(obj, cel, cel);
}
- if (lookup_selector(s, obj, s->_vocabulary->_selectorMap.underBits, &(under_bitsp), NULL) != kSelectorVariable) {
+ if (lookup_selector(s, obj, s->_kernel->_selectorMap.underBits, &(under_bitsp), NULL) != kSelectorVariable) {
under_bitsp = NULL;
under_bits = NULL_REG;
debugC(2, kDebugLevelGraphics, "Object at %04x:%04x has no underBits\n", PRINT_REG(obj));
} else
under_bits = *((reg_t *)under_bitsp);
- if (lookup_selector(s, obj, s->_vocabulary->_selectorMap.signal, &(signalp), NULL) != kSelectorVariable) {
+ if (lookup_selector(s, obj, s->_kernel->_selectorMap.signal, &(signalp), NULL) != kSelectorVariable) {
signalp = NULL;
signal = 0;
debugC(2, kDebugLevelGraphics, "Object at %04x:%04x has no signal selector\n", PRINT_REG(obj));
@@ -2015,7 +2015,7 @@ static void _k_prepare_view_list(EngineState *s, GfxList *list, int options) {
while (view) {
reg_t obj = make_reg(view->_ID, view->_subID);
int priority, _priority;
- int has_nsrect = (view->_ID <= 0) ? 0 : lookup_selector(s, obj, s->_vocabulary->_selectorMap.nsBottom, NULL, NULL) == kSelectorVariable;
+ int has_nsrect = (view->_ID <= 0) ? 0 : lookup_selector(s, obj, s->_kernel->_selectorMap.nsBottom, NULL, NULL) == kSelectorVariable;
int oldsignal = view->signal;
_k_set_now_seen(s, obj);
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 278c5c4b27..df5b3ffba9 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -236,7 +236,7 @@ reg_t kMemory(EngineState *s, int funct_nr, int argc, reg_t *argv) {
}
reg_t kstub(EngineState *s, int funct_nr, int argc, reg_t *argv) {
- sciprintf("Unimplemented syscall: %s[%x](", s->_vocabulary->getKernelName(funct_nr).c_str(), funct_nr);
+ sciprintf("Unimplemented syscall: %s[%x](", s->_kernel->getKernelName(funct_nr).c_str(), funct_nr);
for (int i = 0; i < argc; i++) {
sciprintf("%04x:%04x", PRINT_REG(argv[i]));
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 402f040304..4f7d770d0f 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -462,7 +462,7 @@ static void bresenham_autodetect(EngineState *s) {
return;
}
- if (lookup_selector(s, motion_class, s->_vocabulary->_selectorMap.doit, NULL, &fptr) != kSelectorMethod) {
+ if (lookup_selector(s, motion_class, s->_kernel->_selectorMap.doit, NULL, &fptr) != kSelectorMethod) {
warning("bresenham_autodetect failed");
handle_movecnt = INCREMENT_MOVECNT; // Most games do this, so best guess
return;
@@ -557,7 +557,7 @@ reg_t kDoBresen(EngineState *s, int funct_nr, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "New data: (x,y)=(%d,%d), di=%d\n", x, y, bdi);
- if (s->_vocabulary->_selectorMap.cantBeHere != -1)
+ if (s->_kernel->_selectorMap.cantBeHere != -1)
invoke_selector(INV_SEL(client, cantBeHere, kStopOnInvalidSelector), 0);
else
invoke_selector(INV_SEL(client, canBeHere, kStopOnInvalidSelector), 0);
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 6aa773a469..abdf2b0447 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -43,7 +43,7 @@ reg_t read_selector(EngineState *s, reg_t object, Selector selector_id, const ch
void write_selector(EngineState *s, reg_t object, Selector selector_id, reg_t value, const char *fname, int line) {
reg_t *address;
- if ((selector_id < 0) || (selector_id > (int)s->_vocabulary->getSelectorNamesSize())) {
+ if ((selector_id < 0) || (selector_id > (int)s->_kernel->getSelectorNamesSize())) {
warning("Attempt to write to invalid selector %d of"
" object at %04x:%04x (%s L%d).", selector_id, PRINT_REG(object), fname, line);
return;
@@ -51,7 +51,7 @@ void write_selector(EngineState *s, reg_t object, Selector selector_id, reg_t va
if (lookup_selector(s, object, selector_id, &address, NULL) != kSelectorVariable)
warning("Selector '%s' of object at %04x:%04x could not be"
- " written to (%s L%d)", s->_vocabulary->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line);
+ " written to (%s L%d)", s->_kernel->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line);
else
*address = value;
}
@@ -72,7 +72,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc
if (slc_type == kSelectorNone) {
warning("Selector '%s' of object at %04x:%04x could not be invoked (%s L%d)",
- s->_vocabulary->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line);
+ s->_kernel->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line);
if (noinvalid == kStopOnInvalidSelector)
error("[Kernel] Not recoverable: VM was halted\n");
return 1;
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index e817b798ec..704051d627 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -827,13 +827,16 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
retval->_vocabulary = s->_vocabulary;
// s->_vocabulary = 0; // FIXME: We should set s->_vocabulary to 0 here,
// else it could be freed when the old EngineState is freed. Luckily, this freeing currently
-// never happens, so we don't need to. This is lucky, because the fact that the kernel function
-// and selector tables are stored in the Vocabulary (????) makes it impossible for us to
-// free the vocabulary here.
+// never happens, so we don't need to.
retval->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
// static VM/Kernel information:
+ retval->_kernel = s->_kernel;
+ assert(0 == retval->_kernel);
+// s->_kernel = 0; // FIXME: We should set s->_kernel to 0 here,
+// else it could be freed when the old EngineState is freed. Luckily, this freeing currently
+// never happens, so we don't need to.
retval->_kfuncTable = s->_kfuncTable;
// Copy breakpoint information from current game instance
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index a111c7e84a..74bbaa8854 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -111,7 +111,7 @@ void script_adjust_opcode_formats(int res_version) {
#define FIND_SELECTOR(_slc_) _selectorMap._slc_ = findSelector(#_slc_)
#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorMap._slc_ = findSelector(_slcstr_)
-void Vocabulary::mapSelectors() {
+void Kernel::mapSelectors() {
FIND_SELECTOR(init);
FIND_SELECTOR(play);
FIND_SELECTOR(replay);
@@ -202,7 +202,7 @@ void Vocabulary::mapSelectors() {
FIND_SELECTOR(syncTime);
}
-void Vocabulary::dumpScriptObject(char *data, int seeker, int objsize) {
+void Kernel::dumpScriptObject(char *data, int seeker, int objsize) {
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);
@@ -245,7 +245,7 @@ void Vocabulary::dumpScriptObject(char *data, int seeker, int objsize) {
}
}
-void Vocabulary::dumpScriptClass(char *data, int seeker, int objsize) {
+void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
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);
@@ -292,7 +292,7 @@ void Vocabulary::dumpScriptClass(char *data, int seeker, int objsize) {
}
}
-void Vocabulary::dissectScript(int scriptNumber) {
+void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned int _seeker = 0;
Resource *script = _resmgr->findResource(kResourceTypeScript, scriptNumber, 0);
@@ -385,7 +385,7 @@ void Vocabulary::dissectScript(int scriptNumber) {
}
} else {
nextitem = nextitem << 8 | script->data [seeker++];
- sciprintf("%s[%03x] ", getAnyWordFromGroup(nextitem), nextitem);
+ sciprintf("%s[%03x] ", vocab->getAnyWordFromGroup(nextitem), nextitem);
}
}
sciprintf("\n");
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 80c876e9f1..1f7fe73e51 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -699,8 +699,8 @@ int c_stack(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
}
const char *selector_name(EngineState *s, int selector) {
- if (selector >= 0 && selector < (int)s->_vocabulary->getSelectorNamesSize())
- return s->_vocabulary->getSelectorName(selector).c_str();
+ if (selector >= 0 && selector < (int)s->_kernel->getSelectorNamesSize())
+ return s->_kernel->getSelectorName(selector).c_str();
else
return "--INVALID--";
}
@@ -822,7 +822,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (print_bw_tag)
sciprintf("[%c] ", opsize ? 'B' : 'W');
- sciprintf("%s", s->_vocabulary->getOpcode(opcode).name.c_str());
+ sciprintf("%s", s->_kernel->getOpcode(opcode).name.c_str());
i = 0;
while (g_opcode_formats[opcode][i]) {
@@ -858,7 +858,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (opcode == op_callk)
sciprintf(" %s[%x]", (param_value < s->_kfuncTable.size()) ?
- ((param_value < s->_vocabulary->getKernelNamesSize()) ? s->_vocabulary->getKernelName(param_value).c_str() : "[Unknown(postulated)]")
+ ((param_value < s->_kernel->getKernelNamesSize()) ? s->_kernel->getKernelName(param_value).c_str() : "[Unknown(postulated)]")
: "<invalid>", param_value);
else
sciprintf(opsize ? " %02x" : " %04x", param_value);
@@ -948,7 +948,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (!name)
name = "<invalid>";
- sciprintf(" %s::%s[", name, (selector > s->_vocabulary->getSelectorNamesSize()) ? "<invalid>" : selector_name(s, selector));
+ sciprintf(" %s::%s[", name, (selector > s->_kernel->getSelectorNamesSize()) ? "<invalid>" : selector_name(s, selector));
switch (lookup_selector(s, called_obj_addr, selector, &val_ref, &fun_ref)) {
case kSelectorMethod:
@@ -1058,12 +1058,12 @@ static int c_backtrace(EngineState *s, const Common::Array<cmd_param_t> &cmdPara
break;
case EXEC_STACK_TYPE_KERNEL: // Kernel function
- sciprintf(" %x:[%x] k%s(", i, call.origin, s->_vocabulary->getKernelName(-(call.selector) - 42).c_str());
+ sciprintf(" %x:[%x] k%s(", i, call.origin, s->_kernel->getKernelName(-(call.selector) - 42).c_str());
break;
case EXEC_STACK_TYPE_VARSELECTOR:
sciprintf(" %x:[%x] vs%s %s::%s (", i, call.origin, (call.argc) ? "write" : "read",
- objname,s->_vocabulary->getSelectorName(call.selector).c_str());
+ objname,s->_kernel->getSelectorName(call.selector).c_str());
break;
}
@@ -1232,10 +1232,10 @@ static int c_gfx_draw_viewobj(EngineState *s, const Common::Array<cmd_param_t> &
}
- is_view = (lookup_selector(s, pos, s->_vocabulary->_selectorMap.x, NULL) == kSelectorVariable) &&
- (lookup_selector(s, pos, s->_vocabulary->_selectorMap.brLeft, NULL) == kSelectorVariable) &&
- (lookup_selector(s, pos, s->_vocabulary->_selectorMap.signal, NULL) == kSelectorVariable) &&
- (lookup_selector(s, pos, s->_vocabulary->_selectorMap.nsTop, NULL) == kSelectorVariable);
+ is_view = (lookup_selector(s, pos, s->_kernel->_selectorMap.x, NULL) == kSelectorVariable) &&
+ (lookup_selector(s, pos, s->_kernel->_selectorMap.brLeft, NULL) == kSelectorVariable) &&
+ (lookup_selector(s, pos, s->_kernel->_selectorMap.signal, NULL) == kSelectorVariable) &&
+ (lookup_selector(s, pos, s->_kernel->_selectorMap.nsTop, NULL) == kSelectorVariable);
if (!is_view) {
sciprintf("Not a dynamic View object.\n");
@@ -1318,7 +1318,7 @@ static int c_disasm_addr(EngineState *s, const Common::Array<cmd_param_t> &cmdPa
static int c_disasm(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
Object *obj = obj_get(s, cmdParams[0].reg);
- int selector_id = s->_vocabulary->findSelector(cmdParams[1].str);
+ int selector_id = s->_kernel->findSelector(cmdParams[1].str);
reg_t addr;
if (!obj) {
@@ -1367,8 +1367,8 @@ static int c_snk(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
callk_index = strtoul(cmdParams [0].str, &endptr, 0);
if (*endptr != '\0') {
callk_index = -1;
- for (uint i = 0; i < s->_vocabulary->getKernelNamesSize(); i++)
- if (cmdParams [0].str == s->_vocabulary->getKernelName(i)) {
+ for (uint i = 0; i < s->_kernel->getKernelNamesSize(); i++)
+ if (cmdParams [0].str == s->_kernel->getKernelName(i)) {
callk_index = i;
break;
}
@@ -1419,7 +1419,7 @@ static int c_send(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t *vptr;
reg_t fptr;
- selector_id = s->_vocabulary->findSelector(selector_name);
+ selector_id = s->_kernel->findSelector(selector_name);
if (selector_id < 0) {
sciprintf("Unknown selector: \"%s\"\n", selector_name);
@@ -1566,7 +1566,7 @@ static void viewobjinfo(EngineState *s, HeapPtr pos) {
int have_rects = 0;
Common::Rect nsrect, nsrect_clipped, brrect;
- if (lookup_selector(s, pos, s->_vocabulary->_selectorMap.nsBottom, NULL) == kSelectorVariable) {
+ if (lookup_selector(s, pos, s->_kernel->_selectorMap.nsBottom, NULL) == kSelectorVariable) {
GETRECT(nsLeft, nsRight, nsBottom, nsTop);
GETRECT(lsLeft, lsRight, lsBottom, lsTop);
GETRECT(brLeft, brRight, brBottom, brTop);
@@ -1580,7 +1580,7 @@ static void viewobjinfo(EngineState *s, HeapPtr pos) {
x = GET_SELECTOR(pos, x);
y = GET_SELECTOR(pos, y);
priority = GET_SELECTOR(pos, priority);
- if (s->_vocabulary->_selectorMap.z > 0) {
+ if (s->_kernel->_selectorMap.z > 0) {
z = GET_SELECTOR(pos, z);
sciprintf("(%d,%d,%d)\n", x, y, z);
} else
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index b8853706ab..c6797edfff 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -121,6 +121,7 @@ EngineState::EngineState() : _dirseeker(this) {
gc_countdown = 0;
_vocabulary = 0;
+ _kernel = 0;
successor = 0;
}
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 79b753b1be..6f22527f28 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -244,6 +244,7 @@ public:
MessageState _msgState;
Vocabulary *_vocabulary;
+ Kernel *_kernel;
EngineState *successor; /**< Successor of this state: Used for restoring */
};
@@ -257,7 +258,7 @@ public:
PaletteEntry get_pic_color(EngineState *s, int color);
static inline reg_t not_register(EngineState *s, reg_t r) {
- if (s->_vocabulary->_selectorMap.cantBeHere != -1)
+ if (s->_kernel->_selectorMap.cantBeHere != -1)
return make_reg(0, !r.offset);
else
return r;
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 9e070a5e4f..e796d0ae30 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -315,7 +315,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
Breakpoint *bp;
char method_name [256];
- sprintf(method_name, "%s::%s", obj_get_name(s, send_obj), s->_vocabulary->getSelectorName(selector).c_str());
+ sprintf(method_name, "%s::%s", obj_get_name(s, send_obj), s->_kernel->getSelectorName(selector).c_str());
bp = s->bp_list;
while (bp) {
@@ -1959,7 +1959,7 @@ static EngineState *_game_run(EngineState *s, int restoring) {
script_init_engine(s, s->version);
game_init(s);
sfx_reset_player();
- _init_stack_base_with_selector(s, s->_vocabulary->_selectorMap.play);
+ _init_stack_base_with_selector(s, s->_kernel->_selectorMap.play);
send_selector(s, s->game_obj, s->game_obj, s->stack_base, 2, s->stack_base);
@@ -1979,7 +1979,7 @@ static EngineState *_game_run(EngineState *s, int restoring) {
sciprintf("Restarting with replay()\n");
s->_executionStack.clear(); // Restart with replay
- _init_stack_base_with_selector(s, s->_vocabulary->_selectorMap.replay);
+ _init_stack_base_with_selector(s, s->_kernel->_selectorMap.replay);
send_selector(s, s->game_obj, s->game_obj, s->stack_base, 2, s->stack_base);
}
@@ -2000,7 +2000,7 @@ int game_run(EngineState **_s) {
EngineState *s = *_s;
sciprintf(" Calling %s::play()\n", s->_gameName.c_str());
- _init_stack_base_with_selector(s, s->_vocabulary->_selectorMap.play); // Call the play selector
+ _init_stack_base_with_selector(s, s->_kernel->_selectorMap.play); // Call the play selector
// Now: Register the first element on the execution stack-
if (!send_selector(s, s->game_obj, s->game_obj, s->stack_base, 2, s->stack_base)) {
diff --git a/engines/sci/vocabulary.cpp b/engines/sci/vocabulary.cpp
index 20b319bbdf..537f24974c 100644
--- a/engines/sci/vocabulary.cpp
+++ b/engines/sci/vocabulary.cpp
@@ -85,10 +85,9 @@ int vocab_get_class_count(ResourceManager *resmgr) {
#endif
-Vocabulary::Vocabulary(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr), _isOldSci0(isOldSci0) {
+Vocabulary::Vocabulary(ResourceManager *resmgr) : _resmgr(resmgr) {
_parserRules = NULL;
_vocabVersion = kVocabularySCI0;
- memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t
debug(2, "Initializing vocabulary");
@@ -101,81 +100,15 @@ Vocabulary::Vocabulary(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr
debug(2, "Assuming that this game does not use a parser.");
_parserRules = NULL;
}
-
- loadOpcodes();
-
- if (!loadSelectorNames()) {
- error("Vocabulary: Could not retrieve selector names");
- }
-
- // Map a few special selectors for later use
- mapSelectors();
-
- loadKernelNames();
}
Vocabulary::~Vocabulary() {
freeRuleList(_parserRules);
_parserWords.clear();
- _selectorNames.clear();
- _opcodes.clear();
- _kernelNames.clear();
_parserBranches.clear();
freeSuffixes();
}
-bool Vocabulary::loadSelectorNames() {
- int count;
-
- Resource *r = _resmgr->findResource(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES, 0);
-
- if (!r) // No such resource?
- return false;
-
- count = READ_LE_UINT16(r->data) + 1; // Counter is slightly off
-
- for (int i = 0; i < count; i++) {
- int offset = READ_LE_UINT16(r->data + 2 + i * 2);
- int len = READ_LE_UINT16(r->data + offset);
-
- Common::String tmp((const char *)r->data + offset + 2, len);
- _selectorNames.push_back(tmp);
-
- // Early SCI versions used the LSB in the selector ID as a read/write
- // toggle. To compensate for that, we add every selector name twice.
- if (_isOldSci0)
- _selectorNames.push_back(tmp);
- }
-
- return true;
-}
-
-bool Vocabulary::loadOpcodes() {
- int count, i = 0;
- Resource* r = _resmgr->findResource(kResourceTypeVocab, VOCAB_RESOURCE_OPCODES, 0);
-
- _opcodes.clear();
-
- // if the resource couldn't be loaded, leave
- if (r == NULL) {
- warning("unable to load vocab.%03d", VOCAB_RESOURCE_OPCODES);
- return false;
- }
-
- count = READ_LE_UINT16(r->data);
-
- _opcodes.resize(count);
- for (i = 0; i < count; i++) {
- int offset = READ_LE_UINT16(r->data + 2 + i * 2);
- int len = READ_LE_UINT16(r->data + offset) - 2;
- _opcodes[i].type = READ_LE_UINT16(r->data + offset + 2);
- // QFG3 has empty opcodes
- _opcodes[i].name = len > 0 ? Common::String((char *)r->data + offset + 4, len) : "Dummy";
- }
-
- return true;
-}
-
bool Vocabulary::loadParserWords() {
char currentword[256] = ""; // They're not going to use words longer than 255 ;-)
@@ -533,7 +466,7 @@ void Vocabulary::printParserWords() const {
con->DebugPrintf("\n");
}
-int Vocabulary::findSelector(const char *selectorName) const {
+int Kernel::findSelector(const char *selectorName) const {
for (uint pos = 0; pos < _selectorNames.size(); ++pos) {
if (_selectorNames[pos] == selectorName)
return pos;
@@ -544,7 +477,7 @@ int Vocabulary::findSelector(const char *selectorName) const {
return -1;
}
-bool Vocabulary::hasKernelFunction(const char *functionName) const {
+bool Kernel::hasKernelFunction(const char *functionName) const {
Common::StringList::const_iterator it = Common::find(_kernelNames.begin(), _kernelNames.end(), functionName);
return (it != _kernelNames.end());
}
diff --git a/engines/sci/vocabulary.h b/engines/sci/vocabulary.h
index 9382b79809..c8ed146917 100644
--- a/engines/sci/vocabulary.h
+++ b/engines/sci/vocabulary.h
@@ -42,12 +42,6 @@ class ResourceManager;
/** Number of bytes allocated on the heap to store bad words if parsing fails */
#define PARSE_HEAP_SIZE 64
-
-struct opcode {
- int type;
- Common::String name;
-};
-
enum {
VOCAB_RESOURCE_CLASSES = 996,
VOCAB_RESOURCE_SNAMES = 997,
@@ -185,7 +179,7 @@ enum VocabularyVersions {
class Vocabulary {
public:
- Vocabulary(ResourceManager *resmgr, bool isOldSci0);
+ Vocabulary(ResourceManager *resmgr);
~Vocabulary();
/**
@@ -260,65 +254,8 @@ public:
uint getParserBranchesSize() const { return _parserBranches.size(); }
const parse_tree_branch_t &getParseTreeBranch(int number) const { return _parserBranches[number]; }
- uint getOpcodesSize() const { return _opcodes.size(); }
- const opcode &getOpcode(uint opcode) const { return _opcodes[opcode]; }
-
- uint getSelectorNamesSize() const { return _selectorNames.size(); }
- const Common::String &getSelectorName(uint selector) const { return _selectorNames[selector]; }
-
- /* Determines the selector ID of a selector by its name
- ** (const char *) selectorName: Name of the selector to look up
- ** Returns : (int) The appropriate selector ID, or -1 on error
- */
- int findSelector(const char *selectorName) const;
-
- /* Detects whether a particular kernel function is required in the game
- ** (const char *) functionName: The name of the desired kernel function
- ** Returns : (bool) true if the kernel function is listed in the kernel table,
- ** false otherwise
- */
- bool hasKernelFunction(const char *functionName) const;
-
- uint getKernelNamesSize() const { return _kernelNames.size(); }
- const Common::String &getKernelName(uint number) const { return _kernelNames[number]; }
-
- // Script dissection/dumping functions
- void dissectScript(int scriptNumber);
- void dumpScriptObject(char *data, int seeker, int objsize);
- void dumpScriptClass(char *data, int seeker, int objsize);
-
- selector_map_t _selectorMap; /**< Shortcut list for important selectors */
-
private:
/**
- * Loads the vocabulary selector names.
- * Returns true upon success, false otherwise.
- */
- bool loadSelectorNames();
-
- /* Maps special selectors
- ** Returns : (void)
- */
- void mapSelectors();
-
- /**
- * Loads the opcode names (only used for debugging).
- * @return true on success, false on failure
- */
- bool loadOpcodes();
-
- /**
- * Loads the kernel function names.
- *
- * This function reads the kernel function name table from resource_map,
- * and fills the _kernelNames array with them.
- * The resulting list has the same format regardless of the format of the
- * name table of the resource (the format changed between version 0 and 1).
- * @return true on success, false on failure
- */
- bool loadKernelNames();
-
- /**
* Loads all words from the main vocabulary.
* @return true on success, false on failure
*/
@@ -349,16 +286,8 @@ private:
void freeRuleList(parse_rule_list_t *rule_list);
ResourceManager *_resmgr;
- bool _isOldSci0;
VocabularyVersions _vocabVersion;
- // Kernel-related lists
- // List of opcodes, loaded from vocab.998. This list is only used for debugging
- // purposes, as we hardcode the list of opcodes in the sci_opcodes enum (script.h)
- Common::Array<opcode> _opcodes;
- Common::StringList _selectorNames;
- Common::StringList _kernelNames;
-
// Parser-related lists
SuffixList _parserSuffixes;
parse_rule_list_t *_parserRules; /**< GNF rules used in the parser algorithm */