diff options
Diffstat (limited to 'engines/sci/engine/kmovement.cpp')
-rw-r--r-- | engines/sci/engine/kmovement.cpp | 197 |
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; |