2009-02-17 15:02:16 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2014-02-18 02:34:24 +01:00
|
|
|
*
|
2009-02-17 15:02:16 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2014-02-18 02:34:24 +01:00
|
|
|
*
|
2009-02-17 15:02:16 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-11-21 00:47:56 +00:00
|
|
|
#include "sci/engine/features.h"
|
2009-02-27 02:23:40 +00:00
|
|
|
#include "sci/engine/state.h"
|
2010-01-29 11:03:54 +00:00
|
|
|
#include "sci/engine/selector.h"
|
2009-02-24 05:51:55 +00:00
|
|
|
#include "sci/engine/kernel.h"
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 10:23:36 +00:00
|
|
|
namespace Sci {
|
2011-01-01 12:43:09 +00:00
|
|
|
//#define CHECK_LISTS // adds sanity checking for lists and errors out when problems are found
|
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2009-02-21 10:23:36 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
static bool isSaneNodePointer(SegManager *segMan, reg_t addr) {
|
|
|
|
bool havePrev = false;
|
2009-02-15 14:52:51 +00:00
|
|
|
reg_t prev = addr;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
do {
|
2010-07-22 17:41:42 +00:00
|
|
|
Node *node = segMan->lookupNode(addr, false);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!node) {
|
2010-07-17 13:27:07 +00:00
|
|
|
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
|
2010-08-18 07:14:17 +00:00
|
|
|
} else if ((g_sci->getGameId() == GID_HOYLE1) && (g_sci->getEngineState()->currentRoomNumber() == 3)) {
|
|
|
|
// HOYLE1: after sorting cards in hearts, in the next round
|
|
|
|
// we get an invalid node - bug #3038433
|
2010-07-17 13:27:07 +00:00
|
|
|
} else {
|
|
|
|
error("isSaneNodePointer: Node at %04x:%04x wasn't found", PRINT_REG(addr));
|
|
|
|
}
|
2010-01-28 09:49:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (havePrev && node->pred != prev) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("isSaneNodePointer: Node at %04x:%04x points to invalid predecessor %04x:%04x (should be %04x:%04x)",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(prev));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 20:53:33 +00:00
|
|
|
//node->pred = prev; // fix the problem in the node
|
|
|
|
return false;
|
2010-01-28 09:49:54 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
prev = addr;
|
|
|
|
addr = node->succ;
|
2010-01-28 09:49:54 +00:00
|
|
|
havePrev = true;
|
2009-05-21 17:18:46 +00:00
|
|
|
} while (!addr.isNull());
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
return true;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
static void checkListPointer(SegManager *segMan, reg_t addr) {
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = segMan->lookupList(addr);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (!list) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): The requested list wasn't found",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr));
|
|
|
|
return;
|
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->first.isNull() && list->last.isNull()) {
|
2010-01-28 09:49:54 +00:00
|
|
|
// Empty list is fine
|
2010-06-25 19:09:19 +00:00
|
|
|
} else if (!list->first.isNull() && !list->last.isNull()) {
|
2010-01-28 09:49:54 +00:00
|
|
|
// Normal list
|
2010-07-22 18:13:05 +00:00
|
|
|
Node *node_a = segMan->lookupNode(list->first, false);
|
|
|
|
Node *node_z = segMan->lookupNode(list->last, false);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!node_a) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): missing first node", PRINT_REG(addr));
|
2010-01-28 09:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!node_z) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): missing last node", PRINT_REG(addr));
|
2010-01-28 09:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node_a->pred.isNull()) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): First node of the list points to a predecessor node",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 20:53:33 +00:00
|
|
|
//node_a->pred = NULL_REG; // fix the problem in the node
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!node_z->succ.isNull()) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): Last node of the list points to a successor node",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 20:53:33 +00:00
|
|
|
//node_z->succ = NULL_REG; // fix the problem in the node
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-01-28 09:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
isSaneNodePointer(segMan, list->first);
|
2010-01-28 09:49:54 +00:00
|
|
|
} else {
|
|
|
|
// Not sane list... it's missing pointers to the first or last element
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->first.isNull())
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): missing pointer to first element",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr));
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->last.isNull())
|
2010-06-28 12:29:06 +00:00
|
|
|
error("checkListPointer (list %04x:%04x): missing pointer to last element",
|
2010-01-28 09:49:54 +00:00
|
|
|
PRINT_REG(addr));
|
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kNewList(EngineState *s, int argc, reg_t *argv) {
|
2010-06-25 19:09:19 +00:00
|
|
|
reg_t listRef;
|
|
|
|
List *list = s->_segMan->allocateList(&listRef);
|
|
|
|
list->first = list->last = NULL_REG;
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "New listRef at %04x:%04x", PRINT_REG(listRef));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
return listRef; // Return list base address
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kDisposeList(EngineState *s, int argc, reg_t *argv) {
|
2010-01-28 21:05:42 +00:00
|
|
|
// This function is not needed in ScummVM. The garbage collector
|
|
|
|
// cleans up unused objects automatically
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kNewNode(EngineState *s, int argc, reg_t *argv) {
|
2010-05-26 22:05:51 +00:00
|
|
|
reg_t nodeValue = argv[0];
|
2010-06-13 21:43:13 +00:00
|
|
|
// Some SCI32 games call this with 1 parameter (e.g. the demo of Phantasmagoria).
|
|
|
|
// Set the key to be the same as the value in this case
|
|
|
|
reg_t nodeKey = (argc == 2) ? argv[1] : argv[0];
|
2010-05-26 22:05:51 +00:00
|
|
|
s->r_acc = s->_segMan->newNode(nodeValue, nodeKey);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "New nodeRef at %04x:%04x", PRINT_REG(s->r_acc));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kFirstNode(EngineState *s, int argc, reg_t *argv) {
|
2009-05-21 17:18:46 +00:00
|
|
|
if (argv[0].isNull())
|
2009-03-12 03:26:58 +00:00
|
|
|
return NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list) {
|
2011-01-01 12:43:09 +00:00
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2010-06-25 19:09:19 +00:00
|
|
|
return list->first;
|
2010-01-28 09:49:54 +00:00
|
|
|
} else {
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
2010-01-28 09:49:54 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kLastNode(EngineState *s, int argc, reg_t *argv) {
|
2010-01-28 09:49:54 +00:00
|
|
|
if (argv[0].isNull())
|
|
|
|
return NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list) {
|
2011-01-01 12:43:09 +00:00
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2010-06-25 19:09:19 +00:00
|
|
|
return list->last;
|
2010-01-28 09:49:54 +00:00
|
|
|
} else {
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
2010-01-28 09:49:54 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kEmptyList(EngineState *s, int argc, reg_t *argv) {
|
2010-01-28 09:49:54 +00:00
|
|
|
if (argv[0].isNull())
|
|
|
|
return NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2010-06-25 19:09:19 +00:00
|
|
|
return make_reg(0, ((list) ? list->first.isNull() : 0));
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-07-01 16:04:29 +00:00
|
|
|
static void addToFront(EngineState *s, reg_t listRef, reg_t nodeRef) {
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(listRef);
|
|
|
|
Node *newNode = s->_segMan->lookupNode(nodeRef);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "Adding node %04x:%04x to end of list %04x:%04x", PRINT_REG(nodeRef), PRINT_REG(listRef));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (!newNode)
|
|
|
|
error("Attempt to add non-node (%04x:%04x) to list at %04x:%04x", PRINT_REG(nodeRef), PRINT_REG(listRef));
|
2011-01-01 12:43:09 +00:00
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2010-06-25 19:09:19 +00:00
|
|
|
checkListPointer(s->_segMan, listRef);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2010-06-25 19:09:19 +00:00
|
|
|
|
|
|
|
newNode->pred = NULL_REG;
|
|
|
|
newNode->succ = list->first;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 16:18:08 +00:00
|
|
|
// Set node to be the first and last node if it's the only node of the list
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->first.isNull())
|
|
|
|
list->last = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
else {
|
2010-06-25 19:09:19 +00:00
|
|
|
Node *oldNode = s->_segMan->lookupNode(list->first);
|
|
|
|
oldNode->pred = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2010-06-25 19:09:19 +00:00
|
|
|
list->first = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-07-01 16:04:29 +00:00
|
|
|
static void addToEnd(EngineState *s, reg_t listRef, reg_t nodeRef) {
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(listRef);
|
|
|
|
Node *newNode = s->_segMan->lookupNode(nodeRef);
|
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "Adding node %04x:%04x to end of list %04x:%04x", PRINT_REG(nodeRef), PRINT_REG(listRef));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (!newNode)
|
|
|
|
error("Attempt to add non-node (%04x:%04x) to list at %04x:%04x", PRINT_REG(nodeRef), PRINT_REG(listRef));
|
2011-01-01 12:43:09 +00:00
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2010-06-25 19:09:19 +00:00
|
|
|
checkListPointer(s->_segMan, listRef);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
newNode->pred = list->last;
|
|
|
|
newNode->succ = NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 16:18:08 +00:00
|
|
|
// Set node to be the first and last node if it's the only node of the list
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->last.isNull())
|
|
|
|
list->first = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
else {
|
2010-06-25 19:09:19 +00:00
|
|
|
Node *old_n = s->_segMan->lookupNode(list->last);
|
|
|
|
old_n->succ = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2010-06-25 19:09:19 +00:00
|
|
|
list->last = nodeRef;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kNextNode(EngineState *s, int argc, reg_t *argv) {
|
2009-10-07 23:34:24 +00:00
|
|
|
Node *n = s->_segMan->lookupNode(argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!isSaneNodePointer(s->_segMan, argv[0]))
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return n->succ;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kPrevNode(EngineState *s, int argc, reg_t *argv) {
|
2009-10-07 23:34:24 +00:00
|
|
|
Node *n = s->_segMan->lookupNode(argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!isSaneNodePointer(s->_segMan, argv[0]))
|
2010-01-03 21:12:44 +00:00
|
|
|
return NULL_REG;
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return n->pred;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kNodeValue(EngineState *s, int argc, reg_t *argv) {
|
2009-10-07 23:34:24 +00:00
|
|
|
Node *n = s->_segMan->lookupNode(argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
if (!isSaneNodePointer(s->_segMan, argv[0]))
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:43:09 +00:00
|
|
|
// ICEMAN: when plotting a course in room 40, unDrawLast is called by
|
|
|
|
// startPlot::changeState, but there is no previous entry, so we get 0 here
|
|
|
|
return n ? n->value : NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kAddToFront(EngineState *s, int argc, reg_t *argv) {
|
2010-07-01 16:04:29 +00:00
|
|
|
addToFront(s, argv[0], argv[1]);
|
2010-07-14 00:57:48 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kAddAfter(EngineState *s, int argc, reg_t *argv) {
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
2016-12-11 20:04:34 -06:00
|
|
|
Node *firstNode = s->_segMan->lookupNode(argv[1]);
|
|
|
|
Node *newNode = s->_segMan->lookupNode(argv[2]);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:43:09 +00:00
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
if (!newNode) {
|
2010-06-18 02:03:28 +00:00
|
|
|
error("New 'node' %04x:%04x is not a node", PRINT_REG(argv[2]));
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
2010-06-18 00:05:41 +00:00
|
|
|
if (argc != 3 && argc != 4) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("kAddAfter: Haven't got 3 or 4 arguments, aborting");
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
2010-06-30 17:36:52 +00:00
|
|
|
if (argc == 4)
|
2016-12-11 20:04:34 -06:00
|
|
|
newNode->key = argv[3];
|
2010-06-18 00:05:41 +00:00
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
if (firstNode) { // We're really appending after
|
|
|
|
const reg_t oldNext = firstNode->succ;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
newNode->pred = argv[1];
|
|
|
|
firstNode->succ = argv[2];
|
|
|
|
newNode->succ = oldNext;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
if (oldNext.isNull()) // Appended after last node?
|
2009-02-20 16:18:08 +00:00
|
|
|
// Set new node as last list node
|
2010-06-25 19:09:19 +00:00
|
|
|
list->last = argv[2];
|
2009-02-15 06:10:59 +00:00
|
|
|
else
|
2016-12-11 20:04:34 -06:00
|
|
|
s->_segMan->lookupNode(oldNext)->pred = argv[2];
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
} else {
|
|
|
|
addToFront(s, argv[0], argv[2]); // Set as initial list node
|
|
|
|
}
|
|
|
|
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg_t kAddBefore(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
|
|
|
Node *firstNode = s->_segMan->lookupNode(argv[1]);
|
|
|
|
Node *newNode = s->_segMan->lookupNode(argv[2]);
|
|
|
|
|
|
|
|
#ifdef CHECK_LISTS
|
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!newNode) {
|
|
|
|
error("New 'node' %04x:%04x is not a node", PRINT_REG(argv[2]));
|
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc != 3 && argc != 4) {
|
|
|
|
error("kAddBefore: Haven't got 3 or 4 arguments, aborting");
|
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 4)
|
|
|
|
newNode->key = argv[3];
|
|
|
|
|
|
|
|
if (firstNode) { // We're really appending before
|
|
|
|
const reg_t oldPred = firstNode->pred;
|
|
|
|
|
|
|
|
newNode->succ = argv[1];
|
|
|
|
firstNode->pred = argv[2];
|
|
|
|
newNode->pred = oldPred;
|
|
|
|
|
|
|
|
if (oldPred.isNull()) // Appended before first node?
|
|
|
|
// Set new node as first list node
|
|
|
|
list->first = argv[2];
|
|
|
|
else
|
|
|
|
s->_segMan->lookupNode(oldPred)->succ = argv[2];
|
|
|
|
|
|
|
|
} else {
|
2010-07-01 16:04:29 +00:00
|
|
|
addToFront(s, argv[0], argv[2]); // Set as initial list node
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-06-04 20:51:24 +00:00
|
|
|
|
|
|
|
return s->r_acc;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kFindKey(EngineState *s, int argc, reg_t *argv) {
|
2009-02-15 06:10:59 +00:00
|
|
|
reg_t node_pos;
|
|
|
|
reg_t key = argv[1];
|
|
|
|
reg_t list_pos = argv[0];
|
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "Looking for key %04x:%04x in list %04x:%04x", PRINT_REG(key), PRINT_REG(list_pos));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:43:09 +00:00
|
|
|
#ifdef CHECK_LISTS
|
2010-01-28 09:49:54 +00:00
|
|
|
checkListPointer(s->_segMan, argv[0]);
|
2011-01-01 12:43:09 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-10-07 23:34:24 +00:00
|
|
|
node_pos = s->_segMan->lookupList(list_pos)->first;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "First node at %04x:%04x", PRINT_REG(node_pos));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-21 17:18:46 +00:00
|
|
|
while (!node_pos.isNull()) {
|
2009-10-07 23:34:24 +00:00
|
|
|
Node *n = s->_segMan->lookupNode(node_pos);
|
2009-05-21 17:18:46 +00:00
|
|
|
if (n->key == key) {
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, " Found key at %04x:%04x", PRINT_REG(node_pos));
|
2009-02-15 06:10:59 +00:00
|
|
|
return node_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
node_pos = n->succ;
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "NextNode at %04x:%04x", PRINT_REG(node_pos));
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2011-01-01 12:48:12 +00:00
|
|
|
debugC(kDebugLevelNodes, "Looking for key without success");
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kDeleteKey(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
reg_t node_pos = kFindKey(s, 2, argv);
|
2010-06-25 19:09:19 +00:00
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-21 17:18:46 +00:00
|
|
|
if (node_pos.isNull())
|
2010-01-28 09:49:54 +00:00
|
|
|
return NULL_REG; // Signal failure
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2016-08-10 18:47:21 -05:00
|
|
|
Node *n = s->_segMan->lookupNode(node_pos);
|
|
|
|
|
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
for (int i = 1; i <= list->numRecursions; ++i) {
|
|
|
|
if (list->nextNodes[i] == node_pos) {
|
|
|
|
list->nextNodes[i] = n->succ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
if (list->first == node_pos)
|
|
|
|
list->first = n->succ;
|
|
|
|
if (list->last == node_pos)
|
|
|
|
list->last = n->pred;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-21 17:18:46 +00:00
|
|
|
if (!n->pred.isNull())
|
2009-10-07 23:34:24 +00:00
|
|
|
s->_segMan->lookupNode(n->pred)->succ = n->succ;
|
2009-05-21 17:18:46 +00:00
|
|
|
if (!n->succ.isNull())
|
2009-10-07 23:34:24 +00:00
|
|
|
s->_segMan->lookupNode(n->succ)->pred = n->pred;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-30 09:51:21 +00:00
|
|
|
// Erase references to the predecessor and successor nodes, as the game
|
|
|
|
// scripts could reference the node itself again.
|
|
|
|
// Happens in the intro of QFG1 and in Longbow, when exiting the cave.
|
2010-06-30 07:18:43 +00:00
|
|
|
n->pred = NULL_REG;
|
|
|
|
n->succ = NULL_REG;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 16:18:08 +00:00
|
|
|
return make_reg(0, 1); // Signal success
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 22:06:42 +00:00
|
|
|
struct sort_temp_t {
|
2009-02-15 06:10:59 +00:00
|
|
|
reg_t key, value;
|
|
|
|
reg_t order;
|
2009-02-21 22:06:42 +00:00
|
|
|
};
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 16:18:08 +00:00
|
|
|
int sort_temp_cmp(const void *p1, const void *p2) {
|
2009-10-09 21:47:33 +00:00
|
|
|
const sort_temp_t *st1 = (const sort_temp_t *)p1;
|
|
|
|
const sort_temp_t *st2 = (const sort_temp_t *)p2;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2012-06-18 05:21:59 +03:00
|
|
|
if (st1->order.getSegment() < st2->order.getSegment() ||
|
|
|
|
(st1->order.getSegment() == st2->order.getSegment() &&
|
|
|
|
st1->order.getOffset() < st2->order.getOffset()))
|
2009-02-15 06:10:59 +00:00
|
|
|
return -1;
|
|
|
|
|
2012-06-18 05:21:59 +03:00
|
|
|
if (st1->order.getSegment() > st2->order.getSegment() ||
|
|
|
|
(st1->order.getSegment() == st2->order.getSegment() &&
|
|
|
|
st1->order.getOffset() > st2->order.getOffset()))
|
2009-02-15 06:10:59 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
|
|
|
reg_t kSort(EngineState *s, int argc, reg_t *argv) {
|
2009-10-04 18:38:18 +00:00
|
|
|
SegManager *segMan = s->_segMan;
|
2009-02-15 06:10:59 +00:00
|
|
|
reg_t source = argv[0];
|
|
|
|
reg_t dest = argv[1];
|
|
|
|
reg_t order_func = argv[2];
|
|
|
|
|
2010-05-29 23:37:15 +00:00
|
|
|
int input_size = (int16)readSelectorValue(segMan, source, SELECTOR(size));
|
|
|
|
reg_t input_data = readSelector(segMan, source, SELECTOR(elements));
|
|
|
|
reg_t output_data = readSelector(segMan, dest, SELECTOR(elements));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-28 11:12:59 +00:00
|
|
|
List *list;
|
|
|
|
Node *node;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!input_size)
|
|
|
|
return s->r_acc;
|
|
|
|
|
2009-05-21 17:18:46 +00:00
|
|
|
if (output_data.isNull()) {
|
2009-10-04 18:38:18 +00:00
|
|
|
list = s->_segMan->allocateList(&output_data);
|
2009-02-15 06:10:59 +00:00
|
|
|
list->first = list->last = NULL_REG;
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelector(segMan, dest, SELECTOR(elements), output_data);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelectorValue(segMan, dest, SELECTOR(size), input_size);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-10-07 23:34:24 +00:00
|
|
|
list = s->_segMan->lookupList(input_data);
|
|
|
|
node = s->_segMan->lookupNode(list->first);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-10-02 14:32:54 +00:00
|
|
|
sort_temp_t *temp_array = (sort_temp_t *)malloc(sizeof(sort_temp_t) * input_size);
|
|
|
|
|
2010-06-25 19:09:19 +00:00
|
|
|
int i = 0;
|
2009-02-15 22:28:12 +00:00
|
|
|
while (node) {
|
2010-06-10 09:22:30 +00:00
|
|
|
reg_t params[1] = { node->value };
|
|
|
|
invokeSelector(s, order_func, SELECTOR(doit), argc, argv, 1, params);
|
2009-02-15 06:10:59 +00:00
|
|
|
temp_array[i].key = node->key;
|
|
|
|
temp_array[i].value = node->value;
|
|
|
|
temp_array[i].order = s->r_acc;
|
|
|
|
i++;
|
2009-10-07 23:34:24 +00:00
|
|
|
node = s->_segMan->lookupNode(node->succ);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qsort(temp_array, input_size, sizeof(sort_temp_t), sort_temp_cmp);
|
|
|
|
|
2009-02-15 22:28:12 +00:00
|
|
|
for (i = 0;i < input_size;i++) {
|
2010-05-26 22:05:51 +00:00
|
|
|
reg_t lNode = s->_segMan->newNode(temp_array[i].value, temp_array[i].key);
|
2010-07-01 16:04:29 +00:00
|
|
|
addToEnd(s, output_data, lNode);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(temp_array);
|
|
|
|
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
2009-02-21 10:23:36 +00:00
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
// SCI32 list functions
|
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
|
|
|
|
reg_t kListAt(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
if (argc != 2) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("kListAt called with %d parameters", argc);
|
2009-12-30 14:00:30 +00:00
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
|
|
|
reg_t curAddress = list->first;
|
2010-02-06 16:12:19 +00:00
|
|
|
if (list->first.isNull()) {
|
2016-08-23 14:26:59 +03:00
|
|
|
// Happens in Torin when examining Di's locket in chapter 3
|
2010-02-06 16:12:19 +00:00
|
|
|
return NULL_REG;
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
Node *curNode = s->_segMan->lookupNode(curAddress);
|
|
|
|
reg_t curObject = curNode->value;
|
|
|
|
int16 listIndex = argv[1].toUint16();
|
|
|
|
int curIndex = 0;
|
|
|
|
|
|
|
|
while (curIndex != listIndex) {
|
|
|
|
if (curNode->succ.isNull()) { // end of the list?
|
|
|
|
return NULL_REG;
|
|
|
|
}
|
|
|
|
|
|
|
|
curAddress = curNode->succ;
|
|
|
|
curNode = s->_segMan->lookupNode(curAddress);
|
|
|
|
curObject = curNode->value;
|
|
|
|
|
|
|
|
curIndex++;
|
|
|
|
}
|
|
|
|
|
2012-07-08 15:58:50 +03:00
|
|
|
// Update the virtual file selected in the character import screen of QFG4.
|
|
|
|
// For the SCI0-SCI1.1 version of this, check kDrawControl().
|
|
|
|
if (g_sci->inQfGImportRoom() && !strcmp(s->_segMan->getObjectName(curObject), "SelectorDText"))
|
|
|
|
s->_chosenQfGImportItem = listIndex;
|
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
return curObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg_t kListIndexOf(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
|
|
|
|
|
|
|
reg_t curAddress = list->first;
|
|
|
|
Node *curNode = s->_segMan->lookupNode(curAddress);
|
|
|
|
reg_t curObject;
|
|
|
|
uint16 curIndex = 0;
|
|
|
|
|
|
|
|
while (curNode) {
|
|
|
|
curObject = curNode->value;
|
|
|
|
if (curObject == argv[1])
|
|
|
|
return make_reg(0, curIndex);
|
|
|
|
|
|
|
|
curAddress = curNode->succ;
|
|
|
|
curNode = s->_segMan->lookupNode(curAddress);
|
|
|
|
curIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGNAL_REG;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
|
2017-01-05 12:22:22 -06:00
|
|
|
const reg_t listReg = argv[0];
|
|
|
|
List *list = s->_segMan->lookupList(listReg);
|
2009-12-30 14:00:30 +00:00
|
|
|
|
2010-02-12 02:23:28 +00:00
|
|
|
Node *curNode = s->_segMan->lookupNode(list->first);
|
2009-12-30 14:00:30 +00:00
|
|
|
Selector slc = argv[1].toUint16();
|
|
|
|
|
|
|
|
ObjVarRef address;
|
|
|
|
|
2016-08-10 18:47:21 -05:00
|
|
|
++list->numRecursions;
|
|
|
|
|
2016-08-28 20:44:25 -05:00
|
|
|
if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) {
|
2016-08-10 18:47:21 -05:00
|
|
|
error("Too much recursion in kListEachElementDo");
|
|
|
|
}
|
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
while (curNode) {
|
2016-08-10 18:47:21 -05:00
|
|
|
// 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;
|
2016-11-06 15:05:58 -06:00
|
|
|
reg_t curObject = curNode->value;
|
2009-12-30 14:00:30 +00:00
|
|
|
|
|
|
|
// First, check if the target selector is a variable
|
2010-05-29 23:37:15 +00:00
|
|
|
if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
|
2009-12-30 14:00:30 +00:00
|
|
|
// This can only happen with 3 params (list, target selector, variable)
|
|
|
|
if (argc != 3) {
|
2010-06-28 12:29:06 +00:00
|
|
|
error("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
|
2009-12-30 14:00:30 +00:00
|
|
|
} else {
|
2010-05-29 23:37:15 +00:00
|
|
|
writeSelector(s->_segMan, curObject, slc, argv[2]);
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-06-10 09:22:30 +00:00
|
|
|
invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
|
2017-01-31 19:03:33 -06:00
|
|
|
|
2016-08-23 13:08:37 +03:00
|
|
|
// Check if the call above leads to a game restore, in which case
|
|
|
|
// the segment manager will be reset, and the original list will
|
|
|
|
// be invalidated
|
|
|
|
if (s->abortScriptProcessing == kAbortLoadGame)
|
2016-08-23 11:36:04 +03:00
|
|
|
return s->r_acc;
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 18:47:21 -05:00
|
|
|
curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]);
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 12:22:22 -06:00
|
|
|
if (s->_segMan->isValidAddr(listReg, SEG_TYPE_LISTS)) {
|
|
|
|
--list->numRecursions;
|
|
|
|
}
|
2016-08-10 18:47:21 -05:00
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
|
2017-01-05 12:22:22 -06:00
|
|
|
const reg_t listReg = argv[0];
|
|
|
|
List *list = s->_segMan->lookupList(listReg);
|
2009-12-30 14:00:30 +00:00
|
|
|
|
2010-02-12 02:23:28 +00:00
|
|
|
Node *curNode = s->_segMan->lookupNode(list->first);
|
2009-12-30 14:00:30 +00:00
|
|
|
Selector slc = argv[1].toUint16();
|
|
|
|
|
|
|
|
ObjVarRef address;
|
|
|
|
|
2016-11-06 15:05:58 -06:00
|
|
|
s->r_acc = NULL_REG;
|
|
|
|
|
|
|
|
++list->numRecursions;
|
|
|
|
|
|
|
|
if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) {
|
|
|
|
error("Too much recursion in kListFirstTrue");
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
|
|
|
|
while (curNode) {
|
2016-11-06 15:05:58 -06:00
|
|
|
// 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;
|
2009-12-30 14:00:30 +00:00
|
|
|
|
|
|
|
// First, check if the target selector is a variable
|
2010-05-29 23:37:15 +00:00
|
|
|
if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
|
2012-06-11 21:14:08 +03:00
|
|
|
// If it's a variable selector, check its value.
|
|
|
|
// Example: script 64893 in Torin, MenuHandler::isHilited checks
|
|
|
|
// all children for variable selector 0x03ba (bHilited).
|
2016-11-06 15:05:58 -06:00
|
|
|
if (!readSelector(s->_segMan, curObject, slc).isNull()) {
|
|
|
|
s->r_acc = curObject;
|
|
|
|
break;
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
} else {
|
2010-06-10 09:22:30 +00:00
|
|
|
invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
|
2009-12-30 14:00:30 +00:00
|
|
|
|
2017-01-31 19:03:33 -06:00
|
|
|
// Check if the call above leads to a game restore, in which case
|
|
|
|
// the segment manager will be reset, and the original list will
|
|
|
|
// be invalidated
|
|
|
|
if (s->abortScriptProcessing == kAbortLoadGame)
|
|
|
|
return s->r_acc;
|
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
// Check if the result is true
|
2016-11-06 15:05:58 -06:00
|
|
|
if (!s->r_acc.isNull()) {
|
|
|
|
s->r_acc = curObject;
|
|
|
|
break;
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-06 15:05:58 -06:00
|
|
|
curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]);
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 12:22:22 -06:00
|
|
|
if (s->_segMan->isValidAddr(listReg, SEG_TYPE_LISTS)) {
|
|
|
|
--list->numRecursions;
|
|
|
|
}
|
2016-11-06 15:05:58 -06:00
|
|
|
|
|
|
|
return s->r_acc;
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) {
|
2017-01-05 12:22:22 -06:00
|
|
|
const reg_t listReg = argv[0];
|
|
|
|
List *list = s->_segMan->lookupList(listReg);
|
2009-12-30 14:00:30 +00:00
|
|
|
|
2010-02-12 02:23:28 +00:00
|
|
|
Node *curNode = s->_segMan->lookupNode(list->first);
|
2009-12-30 14:00:30 +00:00
|
|
|
reg_t curObject;
|
|
|
|
Selector slc = argv[1].toUint16();
|
|
|
|
|
|
|
|
ObjVarRef address;
|
|
|
|
|
2016-11-06 15:05:58 -06:00
|
|
|
s->r_acc = TRUE_REG;
|
|
|
|
|
|
|
|
++list->numRecursions;
|
|
|
|
|
|
|
|
if (list->numRecursions >= ARRAYSIZE(list->nextNodes)) {
|
|
|
|
error("Too much recursion in kListAllTrue");
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
|
|
|
|
while (curNode) {
|
2016-11-06 15:05:58 -06:00
|
|
|
// 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;
|
2009-12-30 14:00:30 +00:00
|
|
|
curObject = curNode->value;
|
|
|
|
|
|
|
|
// First, check if the target selector is a variable
|
2010-05-29 23:37:15 +00:00
|
|
|
if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
|
2012-06-11 21:14:08 +03:00
|
|
|
// If it's a variable selector, check its value
|
|
|
|
s->r_acc = readSelector(s->_segMan, curObject, slc);
|
2009-12-30 14:00:30 +00:00
|
|
|
} else {
|
2010-06-10 09:22:30 +00:00
|
|
|
invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
|
2017-01-31 19:03:33 -06:00
|
|
|
|
|
|
|
// Check if the call above leads to a game restore, in which case
|
|
|
|
// the segment manager will be reset, and the original list will
|
|
|
|
// be invalidated
|
|
|
|
if (s->abortScriptProcessing == kAbortLoadGame)
|
|
|
|
return s->r_acc;
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2012-06-11 21:14:08 +03:00
|
|
|
// Check if the result isn't true
|
|
|
|
if (s->r_acc.isNull())
|
|
|
|
break;
|
|
|
|
|
2016-11-06 15:05:58 -06:00
|
|
|
curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]);
|
2009-12-30 14:00:30 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 12:22:22 -06:00
|
|
|
if (s->_segMan->isValidAddr(listReg, SEG_TYPE_LISTS)) {
|
|
|
|
--list->numRecursions;
|
|
|
|
}
|
2016-11-06 15:05:58 -06:00
|
|
|
|
2009-12-30 14:00:30 +00:00
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
2016-12-11 20:04:34 -06:00
|
|
|
reg_t kListSort(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
List *list = s->_segMan->lookupList(argv[0]);
|
|
|
|
const int16 selector = argv[1].toSint16();
|
|
|
|
const bool isDescending = argc > 2 ? (bool)argv[2].toUint16() : false;
|
|
|
|
|
|
|
|
reg_t firstNode = list->first;
|
|
|
|
for (reg_t node = firstNode; node != NULL_REG; node = s->_segMan->lookupNode(firstNode)->succ) {
|
|
|
|
|
|
|
|
reg_t a;
|
|
|
|
if (selector == -1) {
|
|
|
|
a = s->_segMan->lookupNode(node)->value;
|
|
|
|
} else {
|
|
|
|
a = readSelector(s->_segMan, s->_segMan->lookupNode(node)->value, selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
firstNode = node;
|
|
|
|
for (reg_t newNode = s->_segMan->lookupNode(node)->succ; newNode != NULL_REG; newNode = s->_segMan->lookupNode(newNode)->succ) {
|
|
|
|
reg_t b;
|
|
|
|
if (selector == -1) {
|
|
|
|
b = s->_segMan->lookupNode(newNode)->value;
|
|
|
|
} else {
|
|
|
|
b = readSelector(s->_segMan, s->_segMan->lookupNode(newNode)->value, selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!isDescending && b < a) || (isDescending && a < b)) {
|
|
|
|
firstNode = newNode;
|
|
|
|
a = b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (firstNode != node) {
|
|
|
|
reg_t buf[4] = { argv[0], s->_segMan->lookupNode(firstNode)->key };
|
|
|
|
kDeleteKey(s, 2, buf);
|
|
|
|
|
|
|
|
buf[1] = node;
|
|
|
|
buf[2] = firstNode;
|
|
|
|
buf[3] = s->_segMan->lookupNode(firstNode)->value;
|
|
|
|
kAddBefore(s, 4, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
2009-12-30 14:31:00 +00:00
|
|
|
reg_t kList(EngineState *s, int argc, reg_t *argv) {
|
2010-07-14 00:57:48 +00:00
|
|
|
if (!s)
|
|
|
|
return make_reg(0, getSciVersion());
|
|
|
|
error("not supposed to call this");
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2009-12-30 14:31:00 +00:00
|
|
|
}
|
|
|
|
|
2010-07-21 21:18:21 +00:00
|
|
|
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
|
2016-09-04 16:30:47 -05:00
|
|
|
if (!s)
|
|
|
|
return make_reg(0, getSciVersion());
|
|
|
|
error("not supposed to call this");
|
|
|
|
}
|
2010-11-21 00:47:56 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayNew(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
uint16 size = argv[0].toUint16();
|
|
|
|
const SciArrayType type = (SciArrayType)argv[1].toUint16();
|
2016-01-04 14:57:04 +01:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
if (type == kArrayTypeString) {
|
|
|
|
++size;
|
2010-07-21 21:18:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t arrayHandle;
|
|
|
|
s->_segMan->allocateArray(type, size, &arrayHandle);
|
|
|
|
return arrayHandle;
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayGetSize(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
const SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
return make_reg(0, array.size());
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayGetElement(EngineState *s, int argc, reg_t *argv) {
|
2017-09-30 00:03:05 -05:00
|
|
|
if (getSciVersion() == SCI_VERSION_2_1_LATE) {
|
|
|
|
return kStringGetChar(s, argc, argv);
|
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
return array.getAsID(argv[1].toUint16());
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArraySetElements(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
array.setElements(argv[1].toUint16(), argc - 2, argv + 2);
|
|
|
|
return argv[0];
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayFree(EngineState *s, int argc, reg_t *argv) {
|
2017-09-30 00:03:05 -05:00
|
|
|
if (getSciVersion() == SCI_VERSION_2_1_LATE && !s->_segMan->isValidAddr(argv[0], SEG_TYPE_ARRAY)) {
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
s->_segMan->freeArray(argv[0]);
|
|
|
|
return s->r_acc;
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayFill(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
array.fill(argv[1].toUint16(), argv[2].toUint16(), argv[3]);
|
|
|
|
return argv[0];
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayCopy(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
SciArray &target = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
const uint16 targetIndex = argv[1].toUint16();
|
2017-09-23 20:01:05 -05:00
|
|
|
const uint16 sourceIndex = argv[3].toUint16();
|
|
|
|
const int16 count = argv[4].toSint16();
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
if (!s->_segMan->isArray(argv[2])) {
|
2017-09-23 20:01:05 -05:00
|
|
|
// String copies may be made from static script data
|
|
|
|
SciArray source;
|
2016-09-04 16:30:47 -05:00
|
|
|
source.setType(kArrayTypeString);
|
|
|
|
source.fromString(s->_segMan->getString(argv[2]));
|
2017-09-23 20:01:05 -05:00
|
|
|
target.copy(source, sourceIndex, targetIndex, count);
|
2016-09-04 16:30:47 -05:00
|
|
|
} else {
|
2017-09-23 20:01:05 -05:00
|
|
|
target.copy(*s->_segMan->lookupArray(argv[2]), sourceIndex, targetIndex, count);
|
2010-07-21 21:18:21 +00:00
|
|
|
}
|
2010-12-07 00:47:05 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
return argv[0];
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayDuplicate(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
reg_t targetHandle;
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
// String duplicates may be made from static script data
|
|
|
|
if (!s->_segMan->isArray(argv[0])) {
|
|
|
|
const Common::String source = s->_segMan->getString(argv[0]);
|
|
|
|
SciArray &target = *s->_segMan->allocateArray(kArrayTypeString, source.size(), &targetHandle);
|
|
|
|
target.fromString(source);
|
|
|
|
} else {
|
|
|
|
SciArray &source = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
SciArray &target = *s->_segMan->allocateArray(source.getType(), source.size(), &targetHandle);
|
|
|
|
target = source;
|
2010-07-21 21:18:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
return targetHandle;
|
|
|
|
}
|
2010-07-21 21:18:21 +00:00
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayGetData(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
if (s->_segMan->isObject(argv[0])) {
|
|
|
|
return readSelector(s->_segMan, argv[0], SELECTOR(data));
|
2010-07-21 21:18:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
return argv[0];
|
2010-07-21 21:18:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 16:30:47 -05:00
|
|
|
reg_t kArrayByteCopy(EngineState *s, int argc, reg_t *argv) {
|
|
|
|
SciArray &target = *s->_segMan->lookupArray(argv[0]);
|
|
|
|
const uint16 targetOffset = argv[1].toUint16();
|
|
|
|
const SciArray &source = *s->_segMan->lookupArray(argv[2]);
|
|
|
|
const uint16 sourceOffset = argv[3].toUint16();
|
|
|
|
const uint16 count = argv[4].toUint16();
|
|
|
|
|
|
|
|
target.byteCopy(source, sourceOffset, targetOffset, count);
|
|
|
|
return argv[0];
|
|
|
|
}
|
2009-12-30 14:00:30 +00:00
|
|
|
#endif
|
|
|
|
|
2009-02-21 10:23:36 +00:00
|
|
|
} // End of namespace Sci
|