aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kmovement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kmovement.cpp')
-rw-r--r--engines/sci/engine/kmovement.cpp197
1 files changed, 196 insertions, 1 deletions
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 5e3da6403b..9a80b3c99f 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -239,7 +239,202 @@ enum Movecnt {
static Movecnt handle_movecnt = UNINITIALIZED; // FIXME: Avoid static vars
-int parse_reg_t(EngineState *s, const char *str, reg_t *dest);
+/**
+ * Address parameters may be passed in one of three forms:
+ * - ssss:oooo -- where 'ssss' denotes a segment and 'oooo' an offset.
+ * Example: "a:c5" would address something in segment 0xa at offset 0xc5.
+ * - &scr:oooo -- where 'scr' is a script number and oooo an offset within that script; will
+ * fail if the script is not currently loaded
+ * - $REG -- where 'REG' is one of 'PC', 'ACC', 'PREV' or 'OBJ': References the address
+ * indicated by the register of this name.
+ * - $REG+n (or -n) -- Like $REG, but modifies the offset part by a specific amount (which
+ * is specified in hexadecimal).
+ * - ?obj -- Looks up an object with the specified name, uses its address. This will abort if
+ * the object name is ambiguous; in that case, a list of addresses and indices is provided.
+ * ?obj.idx may be used to disambiguate 'obj' by the index 'idx'.
+**/
+int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on success
+ int rel_offsetting = 0;
+ const char *offsetting = NULL;
+ // Non-NULL: Parse end of string for relative offsets
+ char *endptr;
+
+ if (*str == '$') { // Register
+ rel_offsetting = 1;
+
+ if (!scumm_strnicmp(str + 1, "PC", 2)) {
+ *dest = s->_executionStack.back().addr.pc;
+ offsetting = str + 3;
+ } else if (!scumm_strnicmp(str + 1, "P", 1)) {
+ *dest = s->_executionStack.back().addr.pc;
+ offsetting = str + 2;
+ } else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
+ *dest = s->r_prev;
+ offsetting = str + 5;
+ } else if (!scumm_strnicmp(str + 1, "ACC", 3)) {
+ *dest = s->r_acc;
+ offsetting = str + 4;
+ } else if (!scumm_strnicmp(str + 1, "A", 1)) {
+ *dest = s->r_acc;
+ offsetting = str + 2;
+ } else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
+ *dest = s->_executionStack.back().objp;
+ offsetting = str + 4;
+ } else if (!scumm_strnicmp(str + 1, "O", 1)) {
+ *dest = s->_executionStack.back().objp;
+ offsetting = str + 2;
+ } else
+ return 1; // No matching register
+
+ if (!*offsetting)
+ offsetting = NULL;
+ else if (*offsetting != '+' && *offsetting != '-')
+ return 1;
+ } else if (*str == '&') {
+ int script_nr;
+ // Look up by script ID
+ char *colon = (char *)strchr(str, ':');
+
+ if (!colon)
+ return 1;
+ *colon = 0;
+ offsetting = colon + 1;
+
+ script_nr = strtol(str + 1, &endptr, 10);
+
+ if (*endptr)
+ return 1;
+
+ dest->segment = s->seg_manager->segGet(script_nr);
+
+ if (!dest->segment) {
+ return 1;
+ }
+ } else if (*str == '?') {
+ int index = -1;
+ int times_found = 0;
+ char *tmp;
+ const char *str_objname;
+ char *str_suffix;
+ char suffchar = 0;
+ uint i;
+ // Parse obj by name
+
+ tmp = (char *)strchr(str, '+');
+ str_suffix = (char *)strchr(str, '-');
+ if (tmp < str_suffix)
+ str_suffix = tmp;
+ if (str_suffix) {
+ suffchar = (*str_suffix);
+ *str_suffix = 0;
+ }
+
+ tmp = (char *)strchr(str, '.');
+
+ if (tmp) {
+ *tmp = 0;
+ index = strtol(tmp + 1, &endptr, 16);
+ if (*endptr)
+ return -1;
+ }
+
+ str_objname = str + 1;
+
+ // Now all values are available; iterate over all objects.
+ for (i = 0; i < s->seg_manager->_heap.size(); i++) {
+ MemObject *mobj = s->seg_manager->_heap[i];
+ int idx = 0;
+ int max_index = 0;
+
+ if (mobj) {
+ if (mobj->getType() == MEM_OBJ_SCRIPT)
+ max_index = (*(Script *)mobj)._objects.size();
+ else if (mobj->getType() == MEM_OBJ_CLONES)
+ max_index = (*(CloneTable *)mobj)._table.size();
+ }
+
+ while (idx < max_index) {
+ int valid = 1;
+ Object *obj = NULL;
+ reg_t objpos;
+ objpos.offset = 0;
+ objpos.segment = i;
+
+ if (mobj->getType() == MEM_OBJ_SCRIPT) {
+ obj = &(*(Script *)mobj)._objects[idx];
+ objpos.offset = obj->pos.offset;
+ } else if (mobj->getType() == MEM_OBJ_CLONES) {
+ obj = &((*(CloneTable *)mobj)._table[idx]);
+ objpos.offset = idx;
+ valid = ((CloneTable *)mobj)->isValidEntry(idx);
+ }
+
+ if (valid) {
+ const char *objname = obj_get_name(s, objpos);
+ if (!strcmp(objname, str_objname)) {
+ // Found a match!
+ if ((index < 0) && (times_found > 0)) {
+ if (times_found == 1) {
+ // First time we realized the ambiguity
+ sciprintf("Ambiguous:\n");
+ sciprintf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname);
+ }
+ sciprintf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname);
+ }
+ if (index < 0 || times_found == index)
+ *dest = objpos;
+ ++times_found;
+ }
+ }
+ ++idx;
+ }
+
+ }
+
+ if (!times_found)
+ return 1;
+
+ if (times_found > 1 && index < 0) {
+ sciprintf("Ambiguous: Aborting.\n");
+ return 1; // Ambiguous
+ }
+
+ if (times_found <= index)
+ return 1; // Not found
+
+ offsetting = str_suffix;
+ if (offsetting)
+ *str_suffix = suffchar;
+ rel_offsetting = 1;
+ } else {
+ char *colon = (char *)strchr(str, ':');
+
+ if (!colon) {
+ offsetting = str;
+ dest->segment = 0;
+ } else {
+ *colon = 0;
+ offsetting = colon + 1;
+
+ dest->segment = strtol(str, &endptr, 16);
+ if (*endptr)
+ return 1;
+ }
+ }
+ if (offsetting) {
+ int val = strtol(offsetting, &endptr, 16);
+
+ if (rel_offsetting)
+ dest->offset += val;
+ else
+ dest->offset = val;
+
+ if (*endptr)
+ return 1;
+ }
+
+ return 0;
+}
static int checksum_bytes(byte *data, int size) {
int result = 0;