diff options
Diffstat (limited to 'engines/sci/engine/klists.cpp')
-rw-r--r-- | engines/sci/engine/klists.cpp | 210 |
1 files changed, 146 insertions, 64 deletions
diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 0701883a9b..93e95099f5 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -34,10 +34,15 @@ static bool isSaneNodePointer(SegManager *segMan, reg_t addr) { reg_t prev = addr; do { - Node *node = segMan->lookupNode(addr); + Node *node = segMan->lookupNode(addr, false); if (!node) { - error("isSaneNodePointer: Node at %04x:%04x wasn't found", PRINT_REG(addr)); + if ((g_sci->getGameId() == GID_ICEMAN) && (g_sci->getEngineState()->currentRoomNumber() == 40)) { + // ICEMAN: when plotting course, unDrawLast is called by startPlot::changeState + // there is no previous entry so we get 0 in here + } else { + error("isSaneNodePointer: Node at %04x:%04x wasn't found", PRINT_REG(addr)); + } return false; } @@ -70,8 +75,8 @@ static void checkListPointer(SegManager *segMan, reg_t addr) { // Empty list is fine } else if (!list->first.isNull() && !list->last.isNull()) { // Normal list - Node *node_a = segMan->lookupNode(list->first); - Node *node_z = segMan->lookupNode(list->last); + Node *node_a = segMan->lookupNode(list->first, false); + Node *node_z = segMan->lookupNode(list->last, false); if (!node_a) { error("checkListPointer (list %04x:%04x): missing first node", PRINT_REG(addr)); @@ -251,6 +256,19 @@ reg_t kNodeValue(EngineState *s, int argc, reg_t *argv) { reg_t kAddToFront(EngineState *s, int argc, reg_t *argv) { addToFront(s, argv[0], argv[1]); + + if (argc == 3) + s->_segMan->lookupNode(argv[1])->key = argv[2]; + + return s->r_acc; +} + +reg_t kAddToEnd(EngineState *s, int argc, reg_t *argv) { + addToEnd(s, argv[0], argv[1]); + + if (argc == 3) + s->_segMan->lookupNode(argv[1])->key = argv[2]; + return s->r_acc; } @@ -294,11 +312,6 @@ reg_t kAddAfter(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -reg_t kAddToEnd(EngineState *s, int argc, reg_t *argv) { - addToEnd(s, argv[0], argv[1]); - return s->r_acc; -} - reg_t kFindKey(EngineState *s, int argc, reg_t *argv) { reg_t node_pos; reg_t key = argv[1]; @@ -580,65 +593,134 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -// In SCI2.1, all the list functions were merged in one reg_t kList(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kAddBefore(EngineState *s, int argc, reg_t *argv) { + error("Unimplemented function kAddBefore called"); + return s->r_acc; +} + +reg_t kMoveToFront(EngineState *s, int argc, reg_t *argv) { + error("Unimplemented function kMoveToFront called"); + return s->r_acc; +} + +reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv) { + error("Unimplemented function kMoveToEnd called"); + return s->r_acc; +} + +reg_t kArray(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { - case 0: - return kNewList(s, argc - 1, argv + 1); - case 1: - return kDisposeList(s, argc - 1, argv + 1); - case 2: - return kNewNode(s, argc - 1, argv + 1); - case 3: - return kFirstNode(s, argc - 1, argv + 1); - case 4: - return kLastNode(s, argc - 1, argv + 1); - case 5: - return kEmptyList(s, argc - 1, argv + 1); - case 6: - return kNextNode(s, argc - 1, argv + 1); - case 7: - return kPrevNode(s, argc - 1, argv + 1); - case 8: - return kNodeValue(s, argc - 1, argv + 1); - case 9: - return kAddAfter(s, argc - 1, argv + 1); - case 10: - return kAddToFront(s, argc - 1, argv + 1); - case 11: - return kAddToEnd(s, argc - 1, argv + 1); - case 12: - error("kList: unimplemented subfunction kAddBefore"); - //return kAddBefore(s, argc - 1, argv + 1); - return NULL_REG; - case 13: - error("kList: unimplemented subfunction kMoveToFront"); - //return kMoveToFront(s, argc - 1, argv + 1); - return NULL_REG; - case 14: - error("kList: unimplemented subfunction kMoveToEnd"); - //return kMoveToEnd(s, argc - 1, argv + 1); - return NULL_REG; - case 15: - return kFindKey(s, argc - 1, argv + 1); - case 16: - return kDeleteKey(s, argc - 1, argv + 1); - case 17: - return kListAt(s, argc - 1, argv + 1); - case 18: - return kListIndexOf(s, argc - 1, argv + 1); - case 19: - return kListEachElementDo(s, argc - 1, argv + 1); - case 20: - return kListFirstTrue(s, argc - 1, argv + 1); - case 21: - return kListAllTrue(s, argc - 1, argv + 1); - case 22: - return kSort(s, argc - 1, argv + 1); + case 0: { // New + reg_t arrayHandle; + SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle); + array->setType(argv[2].toUint16()); + array->setSize(argv[1].toUint16()); + return arrayHandle; + } + case 1: { // Size + SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); + return make_reg(0, array->getSize()); + } + case 2: { // At (return value at an index) + SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); + return array->getValue(argv[2].toUint16()); + } + case 3: { // Atput (put value at an index) + SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); + + uint32 index = argv[2].toUint16(); + uint32 count = argc - 3; + + if (index + count > 65535) + break; + + if (array->getSize() < index + count) + array->setSize(index + count); + + for (uint16 i = 0; i < count; i++) + array->setValue(i + index, argv[i + 3]); + + return argv[1]; // We also have to return the handle + } + case 4: // Free + // Freeing of arrays is handled by the garbage collector + return s->r_acc; + case 5: { // Fill + SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); + uint16 index = argv[2].toUint16(); + + // A count of -1 means fill the rest of the array + uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16(); + uint16 arraySize = array->getSize(); + + if (arraySize < index + count) + array->setSize(index + count); + + for (uint16 i = 0; i < count; i++) + array->setValue(i + index, argv[4]); + + return argv[1]; + } + case 6: { // Cpy + if (s->_segMan->getSegmentObj(argv[1].segment)->getType() != SEG_TYPE_ARRAY || + s->_segMan->getSegmentObj(argv[3].segment)->getType() != SEG_TYPE_ARRAY) { + // Happens in the RAMA demo + warning("kArray(Cpy): Request to copy a segment which isn't an array, ignoring"); + return NULL_REG; + } + + SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]); + SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]); + uint32 index1 = argv[2].toUint16(); + uint32 index2 = argv[4].toUint16(); + + // The original engine ignores bad copies too + if (index2 > array2->getSize()) + break; + + // A count of -1 means fill the rest of the array + uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16(); + + if (array1->getSize() < index1 + count) + array1->setSize(index1 + count); + + for (uint16 i = 0; i < count; i++) + array1->setValue(i + index1, array2->getValue(i + index2)); + + return argv[1]; + } + case 7: // Cmp + // Not implemented in SSCI + return s->r_acc; + case 8: { // Dup + SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]); + reg_t arrayHandle; + SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle); + + dupArray->setType(array->getType()); + dupArray->setSize(array->getSize()); + + for (uint32 i = 0; i < array->getSize(); i++) + dupArray->setValue(i, array->getValue(i)); + + return arrayHandle; + } + case 9: // Getdata + if (!s->_segMan->isHeapObject(argv[1])) + return argv[1]; + + return readSelector(s->_segMan, argv[1], SELECTOR(data)); default: - error("kList: Unhandled case %d", argv[0].toUint16()); - return NULL_REG; + error("Unknown kArray subop %d", argv[0].toUint16()); } + + return NULL_REG; } #endif |