From 22c2f39c0026a1ba00d7f28a93a0b4f9baa5fbfc Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Sun, 6 Nov 2016 15:05:58 -0600 Subject: SCI32: Add recursion code to kListFirstTrue and kListAllTrue This change ensures that these kernel calls operate in the same manner that they did in SSCI. --- engines/sci/engine/klists.cpp | 57 +++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 5cd9c3623d..16ce2363d7 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -547,7 +547,6 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) { List *list = s->_segMan->lookupList(argv[0]); Node *curNode = s->_segMan->lookupNode(list->first); - reg_t curObject; Selector slc = argv[1].toUint16(); ObjVarRef address; @@ -564,7 +563,7 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) { // needs to be able to adjust the location of the next node, which is // why it is stored on the list instead of on the stack list->nextNodes[list->numRecursions] = curNode->succ; - curObject = curNode->value; + reg_t curObject = curNode->value; // First, check if the target selector is a variable if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) { @@ -595,37 +594,51 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) { List *list = s->_segMan->lookupList(argv[0]); Node *curNode = s->_segMan->lookupNode(list->first); - reg_t curObject; Selector slc = argv[1].toUint16(); ObjVarRef address; - s->r_acc = NULL_REG; // reset the accumulator + s->r_acc = NULL_REG; + + ++list->numRecursions; + + if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) { + error("Too much recursion in kListFirstTrue"); + } while (curNode) { - reg_t nextNode = curNode->succ; - curObject = curNode->value; + // We get the next node here as the current node might be deleted by the + // invoke. In the case that the next node is also deleted, kDeleteKey + // needs to be able to adjust the location of the next node, which is + // why it is stored on the list instead of on the stack + list->nextNodes[list->numRecursions] = curNode->succ; + reg_t curObject = curNode->value; // First, check if the target selector is a variable if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) { // If it's a variable selector, check its value. // Example: script 64893 in Torin, MenuHandler::isHilited checks // all children for variable selector 0x03ba (bHilited). - if (!readSelector(s->_segMan, curObject, slc).isNull()) - return curObject; + if (!readSelector(s->_segMan, curObject, slc).isNull()) { + s->r_acc = curObject; + break; + } } else { invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2); // Check if the result is true - if (!s->r_acc.isNull()) - return curObject; + if (!s->r_acc.isNull()) { + s->r_acc = curObject; + break; + } } - curNode = s->_segMan->lookupNode(nextNode); + curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]); } - // No selector returned true - return NULL_REG; + --list->numRecursions; + + return s->r_acc; } reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) { @@ -637,10 +650,20 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) { ObjVarRef address; - s->r_acc = make_reg(0, 1); // reset the accumulator + s->r_acc = TRUE_REG; + + ++list->numRecursions; + + if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) { + error("Too much recursion in kListAllTrue"); + } while (curNode) { - reg_t nextNode = curNode->succ; + // We get the next node here as the current node might be deleted by the + // invoke. In the case that the next node is also deleted, kDeleteKey + // needs to be able to adjust the location of the next node, which is + // why it is stored on the list instead of on the stack + list->nextNodes[list->numRecursions] = curNode->succ; curObject = curNode->value; // First, check if the target selector is a variable @@ -655,9 +678,11 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) { if (s->r_acc.isNull()) break; - curNode = s->_segMan->lookupNode(nextNode); + curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]); } + --list->numRecursions; + return s->r_acc; } -- cgit v1.2.3