mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-09 03:10:22 +00:00
SCI32: Rewrite kArray & kString
This change invalidates earlier SCI32 save games, which separated arrays and strings in an incompatible manner. Old save games contain invalid references to a string segment which no longer exists, and contain incompatible array structures that lack critical type information.
This commit is contained in:
parent
240b0ca348
commit
3f91726765
@ -2075,10 +2075,6 @@ bool Console::cmdPrintSegmentTable(int argc, const char **argv) {
|
||||
debugPrintf("A SCI32 arrays (%d)", (*(ArrayTable *)mobj).entries_used);
|
||||
break;
|
||||
|
||||
case SEG_TYPE_STRING:
|
||||
debugPrintf("T SCI32 strings (%d)", (*(StringTable *)mobj).entries_used);
|
||||
break;
|
||||
|
||||
case SEG_TYPE_BITMAP:
|
||||
debugPrintf("T SCI32 bitmaps (%d)", (*(BitmapTable *)mobj).entries_used);
|
||||
break;
|
||||
@ -2210,9 +2206,6 @@ bool Console::segmentInfo(int nr) {
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
case SEG_TYPE_STRING:
|
||||
debugPrintf("SCI32 strings\n");
|
||||
break;
|
||||
case SEG_TYPE_ARRAY:
|
||||
debugPrintf("SCI32 arrays\n");
|
||||
break;
|
||||
@ -2808,16 +2801,11 @@ bool Console::cmdViewReference(int argc, const char **argv) {
|
||||
case SIG_TYPE_REFERENCE: {
|
||||
switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) {
|
||||
#ifdef ENABLE_SCI32
|
||||
case SEG_TYPE_STRING: {
|
||||
debugPrintf("SCI32 string\n");
|
||||
const SciString *str = _engine->_gamestate->_segMan->lookupString(reg);
|
||||
Common::hexdump((const byte *) str->getRawData(), str->getSize(), 16, 0);
|
||||
break;
|
||||
}
|
||||
case SEG_TYPE_ARRAY: {
|
||||
debugPrintf("SCI32 array:\n");
|
||||
const SciArray<reg_t> *array = _engine->_gamestate->_segMan->lookupArray(reg);
|
||||
hexDumpReg(array->getRawData(), array->getSize(), 4, 0, true);
|
||||
// TODO: Different prints for different types
|
||||
const SciArray *array = _engine->_gamestate->_segMan->lookupArray(reg);
|
||||
hexDumpReg((reg_t *)array->getRawData(), array->size(), 4, 0, true);
|
||||
break;
|
||||
}
|
||||
case SEG_TYPE_BITMAP: {
|
||||
|
@ -46,7 +46,7 @@ const char *segmentTypeNames[] = {
|
||||
"dynmem", // 9
|
||||
"obsolete", // 10: obsolete string fragments
|
||||
"array", // 11: SCI32 arrays
|
||||
"string" // 12: SCI32 strings
|
||||
"obsolete" // 12: obsolete SCI32 strings
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -410,7 +410,6 @@ uint16 Kernel::findRegType(reg_t reg) {
|
||||
case SEG_TYPE_HUNK:
|
||||
#ifdef ENABLE_SCI32
|
||||
case SEG_TYPE_ARRAY:
|
||||
case SEG_TYPE_STRING:
|
||||
case SEG_TYPE_BITMAP:
|
||||
#endif
|
||||
result |= SIG_TYPE_REFERENCE;
|
||||
|
@ -484,29 +484,36 @@ reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv);
|
||||
|
||||
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArray(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kString(EngineState *s, int argc, reg_t *argv);
|
||||
|
||||
reg_t kArray(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayNew(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayGetSize(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayGetElement(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArraySetElements(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayFree(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayFill(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayCopy(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayCompare(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayDuplicate(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayGetData(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kArrayByteCopy(EngineState *s, int argc, reg_t *argv);
|
||||
|
||||
reg_t kString(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringNew(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringSize(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringAt(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringGetChar(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringFree(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringFill(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringCopy(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringCompare(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringDup(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringGetData(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringLen(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringLength(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringFormat(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringFormatAt(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringToInteger(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringTrim(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringUpper(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringLower(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringTrn(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringToUpperCase(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringToLowerCase(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringReplaceSubstring(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kStringReplaceSubstringEx(EngineState *s, int argc, reg_t *argv);
|
||||
|
||||
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv);
|
||||
|
@ -500,45 +500,57 @@ static const SciKernelMapSubEntry kRemapColors_subops[] = {
|
||||
SCI_SUBOPENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// version, subId, function-mapping, signature, workarounds
|
||||
static const SciKernelMapSubEntry kArray_subops[] = {
|
||||
{ SIG_SCI32, 0, MAP_CALL(ArrayNew), "ii", NULL },
|
||||
{ SIG_SCI32, 1, MAP_CALL(ArrayGetSize), "r", NULL },
|
||||
{ SIG_SCI32, 2, MAP_CALL(ArrayGetElement), "ri", NULL },
|
||||
{ SIG_SCI32, 3, MAP_CALL(ArraySetElements), "ri.*", kArraySetElements_workarounds },
|
||||
{ SIG_SCI32, 4, MAP_CALL(ArrayFree), "r", NULL },
|
||||
{ SIG_SCI32, 5, MAP_CALL(ArrayFill), "riii", NULL },
|
||||
{ SIG_SCI32, 6, MAP_CALL(ArrayCopy), "ririi", NULL },
|
||||
// there is no subop 7
|
||||
{ SIG_SCI32, 8, MAP_CALL(ArrayDuplicate), "r", NULL },
|
||||
{ SIG_SCI32, 9, MAP_CALL(ArrayGetData), "[or]", NULL },
|
||||
{ SIG_SCI3, 10, MAP_CALL(ArrayByteCopy), "ririi", NULL },
|
||||
SCI_SUBOPENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// version, subId, function-mapping, signature, workarounds
|
||||
static const SciKernelMapSubEntry kString_subops[] = {
|
||||
{ SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL },
|
||||
{ SIG_SCI32, 1, MAP_CALL(StringSize), "[or]", NULL },
|
||||
{ SIG_SCI32, 2, MAP_CALL(StringAt), "[or]i", NULL },
|
||||
{ SIG_SCI32, 3, MAP_CALL(StringPutAt), "[or]i(i*)", kStringPutAt_workarounds },
|
||||
// StringFree accepts invalid references
|
||||
{ SIG_SCI32, 4, MAP_CALL(StringFree), "[or0!]", NULL },
|
||||
{ SIG_SCI32, 5, MAP_CALL(StringFill), "[or]ii", NULL },
|
||||
{ SIG_SCI32, 6, MAP_CALL(StringCopy), "[or]i[or]ii", NULL },
|
||||
{ SIG_SCI32, 7, MAP_CALL(StringCompare), "[or][or](i)", NULL },
|
||||
// every single copy of script 64918 in SCI2 through 2.1mid calls StringNew
|
||||
// with a second type argument which is unused (new strings are always type
|
||||
// 3)
|
||||
{ SIG_UNTIL_SCI21MID, 0, MAP_CALL(StringNew), "i(i)", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 1, MAP_CALL(ArrayGetSize), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 2, MAP_CALL(StringGetChar), "ri", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 3, MAP_CALL(ArraySetElements), "rii*", kArraySetElements_workarounds },
|
||||
{ SIG_UNTIL_SCI21MID, 4, MAP_CALL(StringFree), "[0r]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 5, MAP_CALL(ArrayFill), "rii", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 6, MAP_CALL(ArrayCopy), "ririi", NULL },
|
||||
{ SIG_SCI32, 7, MAP_CALL(StringCompare), "rr(i)", NULL },
|
||||
|
||||
// =SCI2, SCI2.1 Early and SCI2.1 Middle=
|
||||
{ SIG_UNTIL_SCI21MID, 8, MAP_CALL(StringDup), "[or]", NULL },
|
||||
// TODO: This gets called with null references in Torin. Check if this is correct, or it's
|
||||
// caused by missing functionality
|
||||
{ SIG_UNTIL_SCI21MID, 9, MAP_CALL(StringGetData), "[or0]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 10, MAP_CALL(StringLen), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 11, MAP_CALL(StringPrintf), "[or](.*)", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 12, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 13, MAP_CALL(StringAtoi), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 14, MAP_CALL(StringTrim), "[or]i", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 15, MAP_CALL(StringUpper), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 16, MAP_CALL(StringLower), "[or]", NULL },
|
||||
// the following 2 are unknown atm (happen in Phantasmagoria)
|
||||
// possibly translate?
|
||||
{ SIG_UNTIL_SCI21MID, 17, MAP_CALL(StringTrn), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 18, MAP_CALL(StringTrnExclude), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 8, MAP_CALL(ArrayDuplicate), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 9, MAP_CALL(StringGetData), "[0or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 10, MAP_CALL(StringLength), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 11, MAP_CALL(StringFormat), "r.*", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 12, MAP_CALL(StringFormatAt), "r[ro].*", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 13, MAP_CALL(StringToInteger), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 14, MAP_CALL(StringTrim), "ri(i)", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 15, MAP_CALL(StringToUpperCase), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 16, MAP_CALL(StringToLowerCase), "r", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 17, MAP_CALL(StringReplaceSubstring), "rrrr", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 18, MAP_CALL(StringReplaceSubstringEx), "rrrr", NULL },
|
||||
|
||||
// SCI2.1 Late + SCI3 - kStringDup + kStringGetData were removed
|
||||
{ SIG_SINCE_SCI21LATE, 8, MAP_CALL(StringLen), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE, 9, MAP_CALL(StringPrintf), "[or](.*)", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,10, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,11, MAP_CALL(StringAtoi), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,12, MAP_CALL(StringTrim), "[or]i", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,13, MAP_CALL(StringUpper), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,14, MAP_CALL(StringLower), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,15, MAP_CALL(StringTrn), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,16, MAP_CALL(StringTrnExclude), "[or]", NULL },
|
||||
{ SIG_SINCE_SCI21LATE, 8, MAP_CALL(StringLength), "r", NULL },
|
||||
{ SIG_SINCE_SCI21LATE, 9, MAP_CALL(StringFormat), "r.*", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,10, MAP_CALL(StringFormatAt), "rr.*", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,11, MAP_CALL(StringToInteger), "r", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,12, MAP_CALL(StringTrim), "ri(i)", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,13, MAP_CALL(StringToUpperCase), "r", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,14, MAP_CALL(StringToLowerCase), "r", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,15, MAP_CALL(StringReplaceSubstring), "rrrr", NULL },
|
||||
{ SIG_SINCE_SCI21LATE,16, MAP_CALL(StringReplaceSubstringEx), "rrrr", NULL },
|
||||
SCI_SUBOPENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
@ -811,7 +823,7 @@ static SciKernelMapEntry s_kernelMap[] = {
|
||||
|
||||
{ MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
{ MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
{ MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||
{ MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", kArray_subops, NULL },
|
||||
{ MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
|
||||
{ MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
{ MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
|
@ -693,8 +693,8 @@ reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv) {
|
||||
// We don't really use or need any of this...
|
||||
|
||||
uint16 saveSlot = argv[0].toUint16();
|
||||
char* fileName = s->_segMan->lookupString(argv[1])->getRawData();
|
||||
warning("kFileIOCreateSaveSlot(%d, '%s')", saveSlot, fileName);
|
||||
const SciArray &fileName = *s->_segMan->lookupArray(argv[1]);
|
||||
warning("kFileIOCreateSaveSlot(%d, '%s')", saveSlot, fileName.toString().c_str());
|
||||
|
||||
return TRUE_REG; // slot creation was successful
|
||||
}
|
||||
@ -1051,7 +1051,7 @@ reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) {
|
||||
// Param 1: a string with game parameters, ignored
|
||||
// Param 2: the selected slot
|
||||
|
||||
SciString *resultString = s->_segMan->lookupString(argv[0]);
|
||||
SciArray *resultString = s->_segMan->lookupArray(argv[0]);
|
||||
uint16 virtualId = argv[2].toUint16();
|
||||
if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
|
||||
error("kMakeSaveFileName: invalid savegame ID specified");
|
||||
|
@ -317,7 +317,7 @@ reg_t kText(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
|
||||
g_sci->_gfxText32->setFont(argv[2].toUint16());
|
||||
|
||||
reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4);
|
||||
SciArray *rect = s->_segMan->lookupArray(argv[0]);
|
||||
if (rect == nullptr) {
|
||||
error("kTextSize: %04x:%04x cannot be dereferenced", PRINT_REG(argv[0]));
|
||||
}
|
||||
@ -327,10 +327,14 @@ reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
|
||||
bool doScaling = argc > 4 ? argv[4].toSint16() : true;
|
||||
|
||||
Common::Rect textRect = g_sci->_gfxText32->getTextSize(text, maxWidth, doScaling);
|
||||
rect[0] = make_reg(0, textRect.left);
|
||||
rect[1] = make_reg(0, textRect.top);
|
||||
rect[2] = make_reg(0, textRect.right - 1);
|
||||
rect[3] = make_reg(0, textRect.bottom - 1);
|
||||
|
||||
reg_t value[4] = {
|
||||
make_reg(0, textRect.left),
|
||||
make_reg(0, textRect.top),
|
||||
make_reg(0, textRect.right - 1),
|
||||
make_reg(0, textRect.bottom - 1) };
|
||||
|
||||
rect->setElements(0, 4, value);
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
|
@ -683,197 +683,105 @@ reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv) {
|
||||
}
|
||||
|
||||
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
|
||||
uint16 op = argv[0].toUint16();
|
||||
|
||||
// Use kString when accessing strings
|
||||
// This is possible, as strings inherit from arrays
|
||||
// and in this case (type 3) arrays are of type char *.
|
||||
// kString is almost exactly the same as kArray, so
|
||||
// this call is possible
|
||||
// TODO: we need to either merge SCI2 strings and
|
||||
// arrays together, and in the future merge them with
|
||||
// the SCI1 strings and arrays in the segment manager
|
||||
bool callStringFunc = false;
|
||||
if (op == 0) {
|
||||
// New, check if the target type is 3 (string)
|
||||
if (argv[2].toUint16() == 3)
|
||||
callStringFunc = true;
|
||||
} else {
|
||||
if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING ||
|
||||
s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) {
|
||||
callStringFunc = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (op == 6) {
|
||||
if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING ||
|
||||
s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) {
|
||||
callStringFunc = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (callStringFunc) {
|
||||
Kernel *kernel = g_sci->getKernel();
|
||||
uint16 kernelStringFuncId = kernel->_kernelFunc_StringId;
|
||||
if (kernelStringFuncId) {
|
||||
const KernelFunction *kernelStringFunc = &kernel->_kernelFuncs[kernelStringFuncId];
|
||||
|
||||
if (op < kernelStringFunc->subFunctionCount) {
|
||||
// subfunction-id is valid
|
||||
const KernelSubFunction *kernelStringSubCall = &kernelStringFunc->subFunctions[op];
|
||||
argc--;
|
||||
argv++; // remove subfunction-id from arguments
|
||||
// and call the kString subfunction
|
||||
return kernelStringSubCall->function(s, argc, argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
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]);
|
||||
if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
|
||||
// HACK: Phantasmagoria 2 keeps trying to access past the end of an
|
||||
// array when it starts. I'm assuming it's trying to see where the
|
||||
// array ends, or tries to resize it. Adjust the array size
|
||||
// accordingly, and return NULL for now.
|
||||
if (array->getSize() == argv[2].toUint16()) {
|
||||
array->setSize(argv[2].toUint16());
|
||||
return NULL_REG;
|
||||
}
|
||||
}
|
||||
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 (argv[1].isNull() || argv[3].isNull()) {
|
||||
if (getSciVersion() == SCI_VERSION_3) {
|
||||
// FIXME: Happens in SCI3, probably because of a missing kernel function.
|
||||
warning("kArray(Cpy): Request to copy from or to a null pointer");
|
||||
return NULL_REG;
|
||||
} else {
|
||||
// SCI2-2.1: error out
|
||||
error("kArray(Cpy): Request to copy from or to a null pointer");
|
||||
}
|
||||
}
|
||||
|
||||
reg_t arrayHandle = argv[1];
|
||||
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 arrayHandle;
|
||||
}
|
||||
case 7: // Cmp
|
||||
// Not implemented in SSCI
|
||||
warning("kArray(Cmp) called");
|
||||
return s->r_acc;
|
||||
case 8: { // Dup
|
||||
if (argv[1].isNull()) {
|
||||
warning("kArray(Dup): Request to duplicate a null pointer");
|
||||
#if 0
|
||||
// Allocate an array anyway
|
||||
reg_t arrayHandle;
|
||||
SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
|
||||
dupArray->setType(3);
|
||||
dupArray->setSize(0);
|
||||
return arrayHandle;
|
||||
#endif
|
||||
return NULL_REG;
|
||||
}
|
||||
SegmentObj *sobj = s->_segMan->getSegmentObj(argv[1].getSegment());
|
||||
if (!sobj || sobj->getType() != SEG_TYPE_ARRAY)
|
||||
error("kArray(Dup): Request to duplicate a segment which isn't an array");
|
||||
|
||||
reg_t arrayHandle;
|
||||
SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
|
||||
// This must occur after allocateArray, as inserting a new object
|
||||
// in the heap object list might invalidate this pointer. Also refer
|
||||
// to the same issue in kClone()
|
||||
SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
|
||||
|
||||
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("Unknown kArray subop %d", op);
|
||||
}
|
||||
|
||||
return NULL_REG;
|
||||
if (!s)
|
||||
return make_reg(0, getSciVersion());
|
||||
error("not supposed to call this");
|
||||
}
|
||||
|
||||
reg_t kArrayNew(EngineState *s, int argc, reg_t *argv) {
|
||||
uint16 size = argv[0].toUint16();
|
||||
const SciArrayType type = (SciArrayType)argv[1].toUint16();
|
||||
|
||||
if (type == kArrayTypeString) {
|
||||
++size;
|
||||
}
|
||||
|
||||
reg_t arrayHandle;
|
||||
s->_segMan->allocateArray(type, size, &arrayHandle);
|
||||
return arrayHandle;
|
||||
}
|
||||
|
||||
reg_t kArrayGetSize(EngineState *s, int argc, reg_t *argv) {
|
||||
const SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
||||
return make_reg(0, array.size());
|
||||
}
|
||||
|
||||
reg_t kArrayGetElement(EngineState *s, int argc, reg_t *argv) {
|
||||
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
||||
return array.getAsID(argv[1].toUint16());
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
reg_t kArrayFree(EngineState *s, int argc, reg_t *argv) {
|
||||
s->_segMan->freeArray(argv[0]);
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
reg_t kArrayCopy(EngineState *s, int argc, reg_t *argv) {
|
||||
SciArray &target = *s->_segMan->lookupArray(argv[0]);
|
||||
const uint16 targetIndex = argv[1].toUint16();
|
||||
|
||||
SciArray source;
|
||||
// String copies may be made from static script data
|
||||
if (!s->_segMan->isArray(argv[2])) {
|
||||
source.setType(kArrayTypeString);
|
||||
source.fromString(s->_segMan->getString(argv[2]));
|
||||
} else {
|
||||
source = *s->_segMan->lookupArray(argv[2]);
|
||||
}
|
||||
const uint16 sourceIndex = argv[3].toUint16();
|
||||
const uint16 count = argv[4].toUint16();
|
||||
|
||||
target.copy(source, sourceIndex, targetIndex, count);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kArrayDuplicate(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t targetHandle;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return targetHandle;
|
||||
}
|
||||
|
||||
reg_t kArrayGetData(EngineState *s, int argc, reg_t *argv) {
|
||||
if (s->_segMan->isObject(argv[0])) {
|
||||
return readSelector(s->_segMan, argv[0], SELECTOR(data));
|
||||
}
|
||||
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace Sci
|
||||
|
@ -285,6 +285,13 @@ struct PathfindingState {
|
||||
static Common::Point readPoint(SegmentRef list_r, int offset) {
|
||||
Common::Point point;
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2) {
|
||||
point.x = READ_UINT16(list_r.raw + offset * POLY_POINT_SIZE + 0);
|
||||
point.y = READ_UINT16(list_r.raw + offset * POLY_POINT_SIZE + 2);
|
||||
} else
|
||||
#endif
|
||||
|
||||
if (list_r.isRaw) { // dynmem blocks are raw
|
||||
point.x = (int16)READ_SCIENDIAN_UINT16(list_r.raw + offset * POLY_POINT_SIZE);
|
||||
point.y = (int16)READ_SCIENDIAN_UINT16(list_r.raw + offset * POLY_POINT_SIZE + 2);
|
||||
@ -296,6 +303,12 @@ static Common::Point readPoint(SegmentRef list_r, int offset) {
|
||||
}
|
||||
|
||||
static void writePoint(SegmentRef ref, int offset, const Common::Point &point) {
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2) {
|
||||
WRITE_UINT16(ref.raw + offset * POLY_POINT_SIZE + 0, point.x);
|
||||
WRITE_UINT16(ref.raw + offset * POLY_POINT_SIZE + 2, point.y);
|
||||
} else
|
||||
#endif
|
||||
if (ref.isRaw) { // dynmem blocks are raw
|
||||
WRITE_SCIENDIAN_UINT16(ref.raw + offset * POLY_POINT_SIZE, point.x);
|
||||
WRITE_SCIENDIAN_UINT16(ref.raw + offset * POLY_POINT_SIZE + 2, point.y);
|
||||
@ -1397,10 +1410,8 @@ static reg_t allocateOutputArray(SegManager *segMan, int size) {
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2) {
|
||||
SciArray<reg_t> *array = segMan->allocateArray(&addr);
|
||||
SciArray *array = segMan->allocateArray(kArrayTypeInt16, size * 2, &addr);
|
||||
assert(array);
|
||||
array->setType(0);
|
||||
array->setSize(size * 2);
|
||||
return addr;
|
||||
}
|
||||
#endif
|
||||
|
@ -202,11 +202,6 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
|
||||
}
|
||||
|
||||
|
||||
#define ALIGN_NONE 0
|
||||
#define ALIGN_RIGHT 1
|
||||
#define ALIGN_LEFT -1
|
||||
#define ALIGN_CENTER 2
|
||||
|
||||
/* Format(targ_address, textresnr, index_inside_res, ...)
|
||||
** or
|
||||
** Format(targ_address, heap_text_addr, ...)
|
||||
@ -214,6 +209,13 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
|
||||
** the supplied parameters and writes it to the targ_address.
|
||||
*/
|
||||
reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
|
||||
enum {
|
||||
ALIGN_NONE = 0,
|
||||
ALIGN_RIGHT = 1,
|
||||
ALIGN_LEFT = -1,
|
||||
ALIGN_CENTER = 2
|
||||
};
|
||||
|
||||
uint16 *arguments;
|
||||
reg_t dest = argv[0];
|
||||
int maxsize = 4096; /* Arbitrary... */
|
||||
@ -301,12 +303,6 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
|
||||
case 's': { /* Copy string */
|
||||
reg_t reg = argv[startarg + paramindex];
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
// If the string is a string object, get to the actual string in the data selector
|
||||
if (s->_segMan->isObject(reg))
|
||||
reg = readSelector(s->_segMan, reg, SELECTOR(data));
|
||||
#endif
|
||||
|
||||
Common::String tempsource = g_sci->getKernel()->lookupText(reg,
|
||||
arguments[paramindex + 1]);
|
||||
int slen = strlen(tempsource.c_str());
|
||||
@ -379,12 +375,6 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
|
||||
case 'u':
|
||||
unsignedVar = true;
|
||||
case 'd': { /* Copy decimal */
|
||||
// In the new SCI2 kString function, %d is used for unsigned
|
||||
// integers. An example is script 962 in Shivers - it uses %d
|
||||
// to create file names.
|
||||
if (getSciVersion() >= SCI_VERSION_2)
|
||||
unsignedVar = true;
|
||||
|
||||
/* int templen; -- unused atm */
|
||||
const char *format_string = "%d";
|
||||
|
||||
@ -437,14 +427,6 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
|
||||
|
||||
*target = 0; /* Terminate string */
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
// Resize SCI32 strings if necessary
|
||||
if (getSciVersion() >= SCI_VERSION_2) {
|
||||
SciString *string = s->_segMan->lookupString(dest);
|
||||
string->setSize(strlen(targetbuf) + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
s->_segMan->strcpy(dest, targetbuf);
|
||||
|
||||
return dest; /* Return target addr */
|
||||
@ -661,238 +643,236 @@ reg_t kStrSplit(EngineState *s, int argc, reg_t *argv) {
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
|
||||
// TODO: there is an unused second argument, happens at least in LSL6 right during the intro
|
||||
reg_t kStringNew(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t stringHandle;
|
||||
SciString *string = s->_segMan->allocateString(&stringHandle);
|
||||
string->setSize(argv[0].toUint16());
|
||||
|
||||
// Make sure the first character is a null character
|
||||
if (string->getSize() > 0)
|
||||
string->setValue(0, 0);
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
reg_t kStringSize(EngineState *s, int argc, reg_t *argv) {
|
||||
return make_reg(0, s->_segMan->getString(argv[0]).size());
|
||||
}
|
||||
|
||||
// At (return value at an index)
|
||||
reg_t kStringAt(EngineState *s, int argc, reg_t *argv) {
|
||||
// Note that values are put in bytes to avoid sign extension
|
||||
if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
SciString *string = s->_segMan->lookupString(argv[0]);
|
||||
byte val = string->getRawData()[argv[1].toUint16()];
|
||||
return make_reg(0, val);
|
||||
} else {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
byte val = string[argv[1].toUint16()];
|
||||
return make_reg(0, val);
|
||||
}
|
||||
}
|
||||
|
||||
// Atput (put value at an index)
|
||||
reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv) {
|
||||
SciString *string = s->_segMan->lookupString(argv[0]);
|
||||
|
||||
uint32 index = argv[1].toUint16();
|
||||
uint32 count = argc - 2;
|
||||
|
||||
if (index + count > 65535)
|
||||
return NULL_REG;
|
||||
|
||||
if (string->getSize() < index + count)
|
||||
string->setSize(index + count);
|
||||
|
||||
for (uint16 i = 0; i < count; i++)
|
||||
string->setValue(i + index, argv[i + 2].toUint16());
|
||||
|
||||
return argv[0]; // We also have to return the handle
|
||||
}
|
||||
|
||||
reg_t kStringFree(EngineState *s, int argc, reg_t *argv) {
|
||||
// Freeing of strings is handled by the garbage collector
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
reg_t kStringFill(EngineState *s, int argc, reg_t *argv) {
|
||||
SciString *string = s->_segMan->lookupString(argv[0]);
|
||||
uint16 index = argv[1].toUint16();
|
||||
|
||||
// A count of -1 means fill the rest of the array
|
||||
uint16 count = argv[2].toSint16() == -1 ? string->getSize() - index : argv[2].toUint16();
|
||||
uint16 stringSize = string->getSize();
|
||||
|
||||
if (stringSize < index + count)
|
||||
string->setSize(index + count);
|
||||
|
||||
for (uint16 i = 0; i < count; i++)
|
||||
string->setValue(i + index, argv[3].toUint16());
|
||||
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringCopy(EngineState *s, int argc, reg_t *argv) {
|
||||
const char *string2 = 0;
|
||||
uint32 string2Size = 0;
|
||||
Common::String string;
|
||||
|
||||
if (argv[2].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
SciString *sstr;
|
||||
sstr = s->_segMan->lookupString(argv[2]);
|
||||
string2 = sstr->getRawData();
|
||||
string2Size = sstr->getSize();
|
||||
} else {
|
||||
string = s->_segMan->getString(argv[2]);
|
||||
string2 = string.c_str();
|
||||
string2Size = string.size() + 1;
|
||||
}
|
||||
|
||||
uint32 index1 = argv[1].toUint16();
|
||||
uint32 index2 = argv[3].toUint16();
|
||||
|
||||
if (argv[0] == argv[2]) {
|
||||
// source and destination string are one and the same
|
||||
if (index1 == index2) {
|
||||
// even same index? ignore this call
|
||||
// Happens in KQ7, when starting a chapter
|
||||
return argv[0];
|
||||
}
|
||||
// TODO: this will crash, when setSize() is triggered later
|
||||
// we need to exactly replicate original interpreter behavior
|
||||
warning("kString(Copy): source is the same as destination string");
|
||||
}
|
||||
|
||||
// The original engine ignores bad copies too
|
||||
if (index2 >= string2Size)
|
||||
return NULL_REG;
|
||||
|
||||
// A count of -1 means fill the rest of the array
|
||||
uint32 count = string2Size - index2;
|
||||
if (argv[4].toSint16() != -1) {
|
||||
count = MIN(count, (uint32)argv[4].toUint16());
|
||||
}
|
||||
// reg_t strAddress = argv[0];
|
||||
|
||||
SciString *string1 = s->_segMan->lookupString(argv[0]);
|
||||
//SciString *string1 = !argv[1].isNull() ? s->_segMan->lookupString(argv[1]) : s->_segMan->allocateString(&strAddress);
|
||||
|
||||
if (string1->getSize() < index1 + count)
|
||||
string1->setSize(index1 + count);
|
||||
|
||||
// Note: We're accessing from c_str() here because the
|
||||
// string's size ignores the trailing 0 and therefore
|
||||
// triggers an assert when doing string2[i + index2].
|
||||
for (uint16 i = 0; i < count; i++)
|
||||
string1->setValue(i + index1, string2[i + index2]);
|
||||
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringCompare(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string1 = argv[0].isNull() ? "" : s->_segMan->getString(argv[0]);
|
||||
Common::String string2 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]);
|
||||
|
||||
if (argc == 3) // Strncmp
|
||||
return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[2].toUint16()));
|
||||
else // Strcmp
|
||||
return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
|
||||
}
|
||||
|
||||
// was removed for SCI2.1 Late+
|
||||
reg_t kStringDup(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t stringHandle;
|
||||
|
||||
SciString *dupString = s->_segMan->allocateString(&stringHandle);
|
||||
|
||||
if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
*dupString = *s->_segMan->lookupString(argv[0]);
|
||||
} else {
|
||||
dupString->fromString(s->_segMan->getString(argv[0]));
|
||||
}
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
// was removed for SCI2.1 Late+
|
||||
reg_t kStringGetData(EngineState *s, int argc, reg_t *argv) {
|
||||
if (!s->_segMan->isHeapObject(argv[0]))
|
||||
return argv[0];
|
||||
|
||||
return readSelector(s->_segMan, argv[0], SELECTOR(data));
|
||||
}
|
||||
|
||||
reg_t kStringLen(EngineState *s, int argc, reg_t *argv) {
|
||||
return make_reg(0, s->_segMan->strlen(argv[0]));
|
||||
}
|
||||
|
||||
reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t stringHandle;
|
||||
s->_segMan->allocateString(&stringHandle);
|
||||
|
||||
reg_t *adjustedArgs = new reg_t[argc + 1];
|
||||
adjustedArgs[0] = stringHandle;
|
||||
memcpy(&adjustedArgs[1], argv, argc * sizeof(reg_t));
|
||||
|
||||
kFormat(s, argc + 1, adjustedArgs);
|
||||
delete[] adjustedArgs;
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv) {
|
||||
return kFormat(s, argc, argv);
|
||||
}
|
||||
|
||||
reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
return make_reg(0, (uint16)atoi(string.c_str()));
|
||||
}
|
||||
|
||||
reg_t kStringTrim(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
|
||||
string.trim();
|
||||
// TODO: Second parameter (bitfield, trim from left, right, center)
|
||||
warning("kStringTrim (%d)", argv[1].getOffset());
|
||||
s->_segMan->strcpy(argv[0], string.c_str());
|
||||
return NULL_REG;
|
||||
}
|
||||
|
||||
reg_t kStringUpper(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
|
||||
string.toUppercase();
|
||||
s->_segMan->strcpy(argv[0], string.c_str());
|
||||
return NULL_REG;
|
||||
}
|
||||
|
||||
reg_t kStringLower(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
|
||||
string.toLowercase();
|
||||
s->_segMan->strcpy(argv[0], string.c_str());
|
||||
return NULL_REG;
|
||||
}
|
||||
|
||||
// Possibly kStringTranslate?
|
||||
reg_t kStringTrn(EngineState *s, int argc, reg_t *argv) {
|
||||
warning("kStringTrn (argc = %d)", argc);
|
||||
return NULL_REG;
|
||||
}
|
||||
|
||||
// Possibly kStringTranslateExclude?
|
||||
reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv) {
|
||||
warning("kStringTrnExclude (argc = %d)", argc);
|
||||
return NULL_REG;
|
||||
}
|
||||
|
||||
reg_t kString(EngineState *s, int argc, reg_t *argv) {
|
||||
if (!s)
|
||||
return make_reg(0, getSciVersion());
|
||||
error("not supposed to call this");
|
||||
}
|
||||
|
||||
reg_t kStringNew(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t stringHandle;
|
||||
const uint16 size = argv[0].toUint16();
|
||||
s->_segMan->allocateArray(kArrayTypeString, size, &stringHandle);
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
reg_t kStringGetChar(EngineState *s, int argc, reg_t *argv) {
|
||||
const uint16 index = argv[1].toUint16();
|
||||
|
||||
// Game scripts may contain static raw string data
|
||||
if (!s->_segMan->isArray(argv[0])) {
|
||||
const Common::String string = s->_segMan->getString(argv[0]);
|
||||
if (index >= string.size()) {
|
||||
return make_reg(0, 0);
|
||||
}
|
||||
|
||||
return make_reg(0, (byte)string[index]);
|
||||
}
|
||||
|
||||
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
||||
|
||||
if (index >= array.size()) {
|
||||
return make_reg(0, 0);
|
||||
}
|
||||
|
||||
return array.getAsID(index);
|
||||
}
|
||||
|
||||
reg_t kStringFree(EngineState *s, int argc, reg_t *argv) {
|
||||
if (!argv[0].isNull()) {
|
||||
s->_segMan->freeArray(argv[0]);
|
||||
}
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
reg_t kStringCompare(EngineState *s, int argc, reg_t *argv) {
|
||||
const Common::String string1 = s->_segMan->getString(argv[0]);
|
||||
const Common::String string2 = s->_segMan->getString(argv[1]);
|
||||
|
||||
int result;
|
||||
if (argc == 3) {
|
||||
result = strncmp(string1.c_str(), string2.c_str(), argv[2].toUint16());
|
||||
} else {
|
||||
result = strcmp(string1.c_str(), string2.c_str());
|
||||
}
|
||||
|
||||
return make_reg(0, (result > 0) - (result < 0));
|
||||
}
|
||||
|
||||
reg_t kStringGetData(EngineState *s, int argc, reg_t *argv) {
|
||||
if (s->_segMan->isObject(argv[0])) {
|
||||
return readSelector(s->_segMan, argv[0], SELECTOR(data));
|
||||
}
|
||||
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringLength(EngineState *s, int argc, reg_t *argv) {
|
||||
return make_reg(0, s->_segMan->getString(argv[0]).size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool isFlag(const char c) {
|
||||
return strchr("-+ 0#", c);
|
||||
}
|
||||
|
||||
bool isPrecision(const char c) {
|
||||
return strchr(".0123456789*", c);
|
||||
}
|
||||
|
||||
bool isWidth(const char c) {
|
||||
return strchr("0123456789*", c);
|
||||
}
|
||||
|
||||
bool isLength(const char c) {
|
||||
return strchr("hjlLtz", c);
|
||||
}
|
||||
|
||||
bool isType(const char c) {
|
||||
return strchr("dsuxXaAceEfFgGinop", c);
|
||||
}
|
||||
|
||||
bool isSignedType(const char type) {
|
||||
return type == 'd' || type == 'i';
|
||||
}
|
||||
|
||||
bool isUnsignedType(const char type) {
|
||||
return strchr("uxXoc", type);
|
||||
}
|
||||
|
||||
bool isStringType(const char type) {
|
||||
return type == 's';
|
||||
}
|
||||
|
||||
Common::String readPlaceholder(const char *&in, reg_t arg) {
|
||||
const char *const start = in;
|
||||
|
||||
assert(*in == '%');
|
||||
++in;
|
||||
|
||||
while (isFlag(*in)) {
|
||||
++in;
|
||||
}
|
||||
while (isWidth(*in)) {
|
||||
++in;
|
||||
}
|
||||
while (isPrecision(*in)) {
|
||||
++in;
|
||||
}
|
||||
while (isLength(*in)) {
|
||||
++in;
|
||||
}
|
||||
|
||||
char format[64];
|
||||
format[0] = '\0';
|
||||
const char type = *in++;
|
||||
Common::strlcpy(format, start, MIN<size_t>(64, in - start + 1));
|
||||
|
||||
if (isType(type)) {
|
||||
if (isSignedType(type)) {
|
||||
const int value = arg.toSint16();
|
||||
return Common::String::format(format, value);
|
||||
} else if (isUnsignedType(type)) {
|
||||
const uint value = arg.toUint16();
|
||||
return Common::String::format(format, value);
|
||||
} else if (isStringType(type)) {
|
||||
Common::String value;
|
||||
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||
if (segMan->isObject(arg)) {
|
||||
value = segMan->getString(readSelector(segMan, arg, SELECTOR(data)));
|
||||
} else {
|
||||
value = segMan->getString(arg);
|
||||
}
|
||||
return Common::String::format(format, value.c_str());
|
||||
} else {
|
||||
error("Unsupported format type %c", type);
|
||||
}
|
||||
} else {
|
||||
return Common::String::format("%s", format);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Common::String format(const Common::String &source, int argc, const reg_t *argv) {
|
||||
Common::String out;
|
||||
const char *in = source.c_str();
|
||||
int argIndex = 0;
|
||||
while (*in != '\0') {
|
||||
if (*in == '%') {
|
||||
if (in[1] == '%') {
|
||||
in += 2;
|
||||
out += "%";
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(argIndex < argc);
|
||||
out += readPlaceholder(in, argv[argIndex++]);
|
||||
} else {
|
||||
out += *in++;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
reg_t kStringFormat(EngineState *s, int argc, reg_t *argv) {
|
||||
reg_t stringHandle;
|
||||
SciArray &target = *s->_segMan->allocateArray(kArrayTypeString, 0, &stringHandle);
|
||||
reg_t source = argv[0];
|
||||
// Str objects may be passed in place of direct references to string data
|
||||
if (s->_segMan->isObject(argv[0])) {
|
||||
source = readSelector(s->_segMan, argv[0], SELECTOR(data));
|
||||
}
|
||||
target.fromString(format(s->_segMan->getString(source), argc - 1, argv + 1));
|
||||
return stringHandle;
|
||||
}
|
||||
|
||||
reg_t kStringFormatAt(EngineState *s, int argc, reg_t *argv) {
|
||||
SciArray &target = *s->_segMan->lookupArray(argv[0]);
|
||||
reg_t source = argv[1];
|
||||
// Str objects may be passed in place of direct references to string data
|
||||
if (s->_segMan->isObject(argv[1])) {
|
||||
source = readSelector(s->_segMan, argv[1], SELECTOR(data));
|
||||
}
|
||||
target.fromString(format(s->_segMan->getString(source), argc - 2, argv + 2));
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringToInteger(EngineState *s, int argc, reg_t *argv) {
|
||||
return make_reg(0, (uint16)s->_segMan->getString(argv[0]).asUint64());
|
||||
}
|
||||
|
||||
reg_t kStringTrim(EngineState *s, int argc, reg_t *argv) {
|
||||
SciArray &array = *s->_segMan->lookupArray(argv[0]);
|
||||
const int8 flags = argv[1].toSint16();
|
||||
const char showChar = argc > 2 ? argv[2].toSint16() : '\0';
|
||||
array.trim(flags, showChar);
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
reg_t kStringToUpperCase(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
string.toUppercase();
|
||||
s->_segMan->strcpy(argv[0], string.c_str());
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringToLowerCase(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String string = s->_segMan->getString(argv[0]);
|
||||
string.toLowercase();
|
||||
s->_segMan->strcpy(argv[0], string.c_str());
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
reg_t kStringReplaceSubstring(EngineState *s, int argc, reg_t *argv) {
|
||||
error("TODO: kStringReplaceSubstring not implemented");
|
||||
return argv[3];
|
||||
}
|
||||
|
||||
reg_t kStringReplaceSubstringEx(EngineState *s, int argc, reg_t *argv) {
|
||||
error("TODO: kStringReplaceSubstringEx not implemented");
|
||||
return argv[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace Sci
|
||||
|
@ -253,11 +253,13 @@ reg_t kRobotGetFrameSize(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::Rect frameRect;
|
||||
const uint16 numFramesTotal = g_sci->_video32->getRobotPlayer().getFrameSize(frameRect);
|
||||
|
||||
reg_t *outRect = s->_segMan->derefRegPtr(argv[0], 4);
|
||||
outRect[0] = make_reg(0, frameRect.left);
|
||||
outRect[1] = make_reg(0, frameRect.top);
|
||||
outRect[2] = make_reg(0, frameRect.right - 1);
|
||||
outRect[3] = make_reg(0, frameRect.bottom - 1);
|
||||
SciArray *outRect = s->_segMan->lookupArray(argv[0]);
|
||||
reg_t values[4] = {
|
||||
make_reg(0, frameRect.left),
|
||||
make_reg(0, frameRect.top),
|
||||
make_reg(0, frameRect.right - 1),
|
||||
make_reg(0, frameRect.bottom - 1) };
|
||||
outRect->setElements(0, 4, values);
|
||||
|
||||
return make_reg(0, numFramesTotal);
|
||||
}
|
||||
|
@ -439,21 +439,8 @@ Common::String MessageState::processString(const char *s) {
|
||||
void MessageState::outputString(reg_t buf, const Common::String &str) {
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2) {
|
||||
if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_STRING) {
|
||||
SciString *sciString = _segMan->lookupString(buf);
|
||||
sciString->setSize(str.size() + 1);
|
||||
for (uint32 i = 0; i < str.size(); i++)
|
||||
sciString->setValue(i, str.c_str()[i]);
|
||||
sciString->setValue(str.size(), 0);
|
||||
} else if (_segMan->getSegmentType(buf.getSegment()) == SEG_TYPE_ARRAY) {
|
||||
// Happens in the intro of LSL6, we are asked to write the string
|
||||
// into an array
|
||||
SciArray<reg_t> *sciString = _segMan->lookupArray(buf);
|
||||
sciString->setSize(str.size() + 1);
|
||||
for (uint32 i = 0; i < str.size(); i++)
|
||||
sciString->setValue(i, make_reg(0, str.c_str()[i]));
|
||||
sciString->setValue(str.size(), NULL_REG);
|
||||
}
|
||||
SciArray *sciString = _segMan->lookupArray(buf);
|
||||
sciString->fromString(str);
|
||||
} else {
|
||||
#endif
|
||||
SegmentRef buffer_r = _segMan->dereference(buf);
|
||||
|
@ -102,66 +102,6 @@ void syncWithSerializer(Common::Serializer &s, Node &obj) {
|
||||
syncWithSerializer(s, obj.value);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
void syncWithSerializer(Common::Serializer &s, SciArray<reg_t> &obj) {
|
||||
byte type = 0;
|
||||
uint32 size = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
type = (byte)obj.getType();
|
||||
size = obj.getSize();
|
||||
}
|
||||
s.syncAsByte(type);
|
||||
s.syncAsUint32LE(size);
|
||||
if (s.isLoading()) {
|
||||
obj.setType((int8)type);
|
||||
|
||||
// HACK: Skip arrays that have a negative type
|
||||
if ((int8)type < 0)
|
||||
return;
|
||||
|
||||
obj.setSize(size);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < size; i++) {
|
||||
reg_t value;
|
||||
|
||||
if (s.isSaving())
|
||||
value = obj.getValue(i);
|
||||
|
||||
syncWithSerializer(s, value);
|
||||
|
||||
if (s.isLoading())
|
||||
obj.setValue(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
void syncWithSerializer(Common::Serializer &s, SciString &obj) {
|
||||
uint32 size = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
size = obj.getSize();
|
||||
s.syncAsUint32LE(size);
|
||||
} else {
|
||||
s.syncAsUint32LE(size);
|
||||
obj.setSize(size);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < size; i++) {
|
||||
char value = 0;
|
||||
|
||||
if (s.isSaving())
|
||||
value = obj.getValue(i);
|
||||
|
||||
s.syncAsByte(value);
|
||||
|
||||
if (s.isLoading())
|
||||
obj.setValue(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// By default, sync using syncWithSerializer, which in turn can easily be overloaded.
|
||||
@ -292,9 +232,6 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
|
||||
} else if (type == SEG_TYPE_ARRAY) {
|
||||
// Set the correct segment for SCI32 arrays
|
||||
_arraysSegId = i;
|
||||
} else if (type == SEG_TYPE_STRING) {
|
||||
// Set the correct segment for SCI32 strings
|
||||
_stringSegId = i;
|
||||
} else if (s.getVersion() >= 36 && type == SEG_TYPE_BITMAP) {
|
||||
_bitmapSegId = i;
|
||||
#endif
|
||||
@ -707,11 +644,39 @@ void ArrayTable::saveLoadWithSerializer(Common::Serializer &ser) {
|
||||
sync_Table<ArrayTable>(ser, *this);
|
||||
}
|
||||
|
||||
void StringTable::saveLoadWithSerializer(Common::Serializer &ser) {
|
||||
if (ser.getVersion() < 18)
|
||||
return;
|
||||
void SciArray::saveLoadWithSerializer(Common::Serializer &s) {
|
||||
uint16 size;
|
||||
|
||||
sync_Table<StringTable>(ser, *this);
|
||||
if (s.isSaving()) {
|
||||
size = _size;
|
||||
}
|
||||
|
||||
s.syncAsByte(_type);
|
||||
s.syncAsByte(_elementSize);
|
||||
s.syncAsUint16LE(size);
|
||||
|
||||
if (s.isLoading()) {
|
||||
resize(size);
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case kArrayTypeByte:
|
||||
case kArrayTypeString:
|
||||
s.syncBytes((byte *)_data, size);
|
||||
break;
|
||||
case kArrayTypeInt16:
|
||||
for (int i = 0; i < size; ++i) {
|
||||
s.syncAsUint16LE(((int16 *)_data)[i]);
|
||||
}
|
||||
break;
|
||||
case kArrayTypeID:
|
||||
for (int i = 0; i < size; ++i) {
|
||||
syncWithSerializer(s, ((reg_t *)_data)[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("Attempt to sync invalid SciArray type %d", _type);
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapTable::saveLoadWithSerializer(Common::Serializer &ser) {
|
||||
|
@ -37,7 +37,7 @@ struct EngineState;
|
||||
*
|
||||
* Version - new/changed feature
|
||||
* =============================
|
||||
* 38 - SCI32 cursor
|
||||
* 38 - SCI32 cursor, accurate SCI32 arrays/strings
|
||||
* 37 - Segment entry data changed to pointers
|
||||
* 36 - SCI32 bitmap segment
|
||||
* 35 - SCI32 remap
|
||||
|
@ -42,7 +42,6 @@ SegManager::SegManager(ResourceManager *resMan, ScriptPatcher *scriptPatcher)
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
_arraysSegId = 0;
|
||||
_stringSegId = 0;
|
||||
_bitmapSegId = 0;
|
||||
#endif
|
||||
|
||||
@ -72,7 +71,6 @@ void SegManager::resetSegMan() {
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
_arraysSegId = 0;
|
||||
_stringSegId = 0;
|
||||
_bitmapSegId = 0;
|
||||
#endif
|
||||
|
||||
@ -88,9 +86,8 @@ void SegManager::initSysStrings() {
|
||||
_parserPtr = make_reg(_saveDirPtr.getSegment(), _saveDirPtr.getOffset() + 256);
|
||||
#ifdef ENABLE_SCI32
|
||||
} else {
|
||||
SciString *saveDirString = allocateString(&_saveDirPtr);
|
||||
saveDirString->setSize(256);
|
||||
saveDirString->setValue(0, 0);
|
||||
SciArray *saveDirString = allocateArray(kArrayTypeString, 256, &_saveDirPtr);
|
||||
saveDirString->byteAt(0) = '\0';
|
||||
|
||||
_parserPtr = NULL_REG; // no SCI2 game had a parser
|
||||
#endif
|
||||
@ -863,7 +860,10 @@ bool SegManager::freeDynmem(reg_t addr) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
SciArray<reg_t> *SegManager::allocateArray(reg_t *addr) {
|
||||
#pragma mark -
|
||||
#pragma mark Arrays
|
||||
|
||||
SciArray *SegManager::allocateArray(SciArrayType type, uint16 size, reg_t *addr) {
|
||||
ArrayTable *table;
|
||||
int offset;
|
||||
|
||||
@ -875,10 +875,14 @@ SciArray<reg_t> *SegManager::allocateArray(reg_t *addr) {
|
||||
offset = table->allocEntry();
|
||||
|
||||
*addr = make_reg(_arraysSegId, offset);
|
||||
return &table->at(offset);
|
||||
|
||||
SciArray *array = &table->at(offset);
|
||||
array->setType(type);
|
||||
array->resize(size);
|
||||
return array;
|
||||
}
|
||||
|
||||
SciArray<reg_t> *SegManager::lookupArray(reg_t addr) {
|
||||
SciArray *SegManager::lookupArray(reg_t addr) {
|
||||
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_ARRAY)
|
||||
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
|
||||
|
||||
@ -899,48 +903,11 @@ void SegManager::freeArray(reg_t addr) {
|
||||
if (!arrayTable.isValidEntry(addr.getOffset()))
|
||||
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
|
||||
|
||||
arrayTable[addr.getOffset()].destroy();
|
||||
arrayTable.freeEntry(addr.getOffset());
|
||||
}
|
||||
|
||||
SciString *SegManager::allocateString(reg_t *addr) {
|
||||
StringTable *table;
|
||||
int offset;
|
||||
|
||||
if (!_stringSegId) {
|
||||
table = (StringTable *)allocSegment(new StringTable(), &(_stringSegId));
|
||||
} else
|
||||
table = (StringTable *)_heap[_stringSegId];
|
||||
|
||||
offset = table->allocEntry();
|
||||
|
||||
*addr = make_reg(_stringSegId, offset);
|
||||
return &table->at(offset);
|
||||
}
|
||||
|
||||
SciString *SegManager::lookupString(reg_t addr) {
|
||||
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING)
|
||||
error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
|
||||
|
||||
StringTable &stringTable = *(StringTable *)_heap[addr.getSegment()];
|
||||
|
||||
if (!stringTable.isValidEntry(addr.getOffset()))
|
||||
error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
|
||||
|
||||
return &(stringTable[addr.getOffset()]);
|
||||
}
|
||||
|
||||
void SegManager::freeString(reg_t addr) {
|
||||
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING)
|
||||
error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
|
||||
|
||||
StringTable &stringTable = *(StringTable *)_heap[addr.getSegment()];
|
||||
|
||||
if (!stringTable.isValidEntry(addr.getOffset()))
|
||||
error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
|
||||
|
||||
stringTable[addr.getOffset()].destroy();
|
||||
stringTable.freeEntry(addr.getOffset());
|
||||
bool SegManager::isArray(reg_t addr) const {
|
||||
return addr.getSegment() == _arraysSegId;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -433,14 +433,10 @@ public:
|
||||
reg_t getParserPtr() const { return _parserPtr; }
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
SciArray<reg_t> *allocateArray(reg_t *addr);
|
||||
SciArray<reg_t> *lookupArray(reg_t addr);
|
||||
SciArray *allocateArray(SciArrayType type, uint16 size, reg_t *addr);
|
||||
SciArray *lookupArray(reg_t addr);
|
||||
void freeArray(reg_t addr);
|
||||
|
||||
SciString *allocateString(reg_t *addr);
|
||||
SciString *lookupString(reg_t addr);
|
||||
void freeString(reg_t addr);
|
||||
SegmentId getStringSegmentId() { return _stringSegId; }
|
||||
bool isArray(reg_t addr) const;
|
||||
|
||||
SciBitmap *allocateBitmap(reg_t *addr, const int16 width, const int16 height, const uint8 skipColor = kDefaultSkipColor, const int16 displaceX = 0, const int16 displaceY = 0, const int16 scaledWidth = kLowResX, const int16 scaledHeight = kLowResY, const uint32 paletteSize = 0, const bool remap = false, const bool gc = true);
|
||||
SciBitmap *lookupBitmap(reg_t addr);
|
||||
@ -469,7 +465,6 @@ private:
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
SegmentId _arraysSegId;
|
||||
SegmentId _stringSegId;
|
||||
SegmentId _bitmapSegId;
|
||||
#endif
|
||||
|
||||
|
@ -67,9 +67,6 @@ SegmentObj *SegmentObj::createSegmentObj(SegmentType type) {
|
||||
case SEG_TYPE_ARRAY:
|
||||
mem = new ArrayTable();
|
||||
break;
|
||||
case SEG_TYPE_STRING:
|
||||
mem = new StringTable();
|
||||
break;
|
||||
case SEG_TYPE_BITMAP:
|
||||
mem = new BitmapTable();
|
||||
break;
|
||||
@ -254,63 +251,39 @@ SegmentRef DynMem::dereference(reg_t pointer) {
|
||||
|
||||
SegmentRef ArrayTable::dereference(reg_t pointer) {
|
||||
SegmentRef ret;
|
||||
ret.isRaw = false;
|
||||
ret.maxSize = at(pointer.getOffset()).getSize() * 2;
|
||||
ret.reg = at(pointer.getOffset()).getRawData();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
|
||||
at(sub_addr.getOffset()).destroy();
|
||||
freeEntry(sub_addr.getOffset());
|
||||
SciArray &array = at(pointer.getOffset());
|
||||
const bool isRaw = array.getType() != kArrayTypeID;
|
||||
|
||||
ret.isRaw = isRaw;
|
||||
ret.maxSize = isRaw ? array.byteSize() : array.size();
|
||||
if (isRaw) {
|
||||
ret.raw = (byte *)array.getRawData();
|
||||
} else {
|
||||
ret.reg = (reg_t *)array.getRawData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Common::Array<reg_t> ArrayTable::listAllOutgoingReferences(reg_t addr) const {
|
||||
Common::Array<reg_t> tmp;
|
||||
Common::Array<reg_t> refs;
|
||||
if (!isValidEntry(addr.getOffset())) {
|
||||
error("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
|
||||
// Scripts may still hold references to array memory that has been
|
||||
// explicitly freed; ignore these references
|
||||
return refs;
|
||||
}
|
||||
|
||||
const SciArray<reg_t> *array = &at(addr.getOffset());
|
||||
|
||||
for (uint32 i = 0; i < array->getSize(); i++) {
|
||||
reg_t value = array->getValue(i);
|
||||
if (value.getSegment() != 0)
|
||||
tmp.push_back(value);
|
||||
SciArray &array = const_cast<SciArray &>(at(addr.getOffset()));
|
||||
if (array.getType() == kArrayTypeID) {
|
||||
for (uint16 i = 0; i < array.size(); ++i) {
|
||||
const reg_t value = array.getAsID(i);
|
||||
if (value.isPointer()) {
|
||||
refs.push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Common::String SciString::toString() const {
|
||||
if (_type != 3)
|
||||
error("SciString::toString(): Array is not a string");
|
||||
|
||||
Common::String string;
|
||||
for (uint32 i = 0; i < _size && _data[i] != 0; i++)
|
||||
string += _data[i];
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void SciString::fromString(const Common::String &string) {
|
||||
if (_type != 3)
|
||||
error("SciString::fromString(): Array is not a string");
|
||||
|
||||
setSize(string.size() + 1);
|
||||
|
||||
for (uint32 i = 0; i < string.size(); i++)
|
||||
_data[i] = string[i];
|
||||
|
||||
_data[string.size()] = 0;
|
||||
}
|
||||
|
||||
SegmentRef StringTable::dereference(reg_t pointer) {
|
||||
SegmentRef ret;
|
||||
ret.isRaw = true;
|
||||
ret.maxSize = at(pointer.getOffset()).getSize();
|
||||
ret.raw = (byte *)at(pointer.getOffset()).getRawData();
|
||||
return ret;
|
||||
return refs;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define SCI_ENGINE_SEGMENT_H
|
||||
|
||||
#include "common/serializer.h"
|
||||
|
||||
#include "common/str.h"
|
||||
#include "sci/engine/object.h"
|
||||
#include "sci/engine/vm.h"
|
||||
#include "sci/engine/vm_types.h" // for reg_t
|
||||
@ -70,7 +70,7 @@ enum SegmentType {
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
SEG_TYPE_ARRAY = 11,
|
||||
SEG_TYPE_STRING = 12,
|
||||
// 12 used to be string, now obsolete
|
||||
SEG_TYPE_BITMAP = 13,
|
||||
#endif
|
||||
|
||||
@ -408,146 +408,463 @@ public:
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
|
||||
template<typename T>
|
||||
class SciArray {
|
||||
public:
|
||||
SciArray() : _type(-1), _data(NULL), _size(0), _actualSize(0) { }
|
||||
#pragma mark -
|
||||
#pragma mark Arrays
|
||||
|
||||
SciArray(const SciArray<T> &array) {
|
||||
enum SciArrayType {
|
||||
kArrayTypeInt16 = 0,
|
||||
kArrayTypeID = 1,
|
||||
kArrayTypeByte = 2,
|
||||
kArrayTypeString = 3,
|
||||
// Type 4 was for 32-bit integers; never used
|
||||
kArrayTypeInvalid = 5
|
||||
};
|
||||
|
||||
enum SciArrayTrim {
|
||||
kArrayTrimRight = 1, ///< Trim whitespace after the last non-whitespace character
|
||||
kArrayTrimCenter = 2, ///< Trim whitespace between non-whitespace characters
|
||||
kArrayTrimLeft = 4 ///< Trim whitespace before the first non-whitespace character
|
||||
};
|
||||
|
||||
class SciArray : public Common::Serializable {
|
||||
public:
|
||||
SciArray() :
|
||||
_type(kArrayTypeInvalid),
|
||||
_size(0),
|
||||
_data(nullptr) {}
|
||||
|
||||
SciArray(const SciArray &array) {
|
||||
_type = array._type;
|
||||
_size = array._size;
|
||||
_actualSize = array._actualSize;
|
||||
_data = new T[_actualSize];
|
||||
_elementSize = array._elementSize;
|
||||
_data = malloc(_elementSize * _size);
|
||||
assert(_data);
|
||||
memcpy(_data, array._data, _size * sizeof(T));
|
||||
memcpy(_data, array._data, _elementSize * _size);
|
||||
}
|
||||
|
||||
SciArray<T>& operator=(const SciArray<T> &array) {
|
||||
SciArray &operator=(const SciArray &array) {
|
||||
if (this == &array)
|
||||
return *this;
|
||||
|
||||
delete[] _data;
|
||||
free(_data);
|
||||
_type = array._type;
|
||||
_size = array._size;
|
||||
_actualSize = array._actualSize;
|
||||
_data = new T[_actualSize];
|
||||
_elementSize = array._elementSize;
|
||||
_data = malloc(_elementSize * _size);
|
||||
assert(_data);
|
||||
memcpy(_data, array._data, _size * sizeof(T));
|
||||
memcpy(_data, array._data, _elementSize * _size);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~SciArray() {
|
||||
destroy();
|
||||
free(_data);
|
||||
_size = 0;
|
||||
_type = kArrayTypeInvalid;
|
||||
}
|
||||
|
||||
virtual void destroy() {
|
||||
delete[] _data;
|
||||
_data = NULL;
|
||||
_type = -1;
|
||||
_size = _actualSize = 0;
|
||||
void saveLoadWithSerializer(Common::Serializer &s);
|
||||
|
||||
/**
|
||||
* Returns the type of this array.
|
||||
*/
|
||||
SciArrayType getType() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
void setType(byte type) {
|
||||
if (_type >= 0)
|
||||
error("SciArray::setType(): Type already set");
|
||||
|
||||
/**
|
||||
* Sets the type of this array. The type of the array may only be set once.
|
||||
*/
|
||||
void setType(SciArrayType type) {
|
||||
assert(_type == kArrayTypeInvalid);
|
||||
switch(type) {
|
||||
case kArrayTypeID:
|
||||
_elementSize = sizeof(reg_t);
|
||||
break;
|
||||
case kArrayTypeInt16:
|
||||
_elementSize = sizeof(int16);
|
||||
break;
|
||||
case kArrayTypeString:
|
||||
_elementSize = sizeof(char);
|
||||
break;
|
||||
case kArrayTypeByte:
|
||||
_elementSize = sizeof(byte);
|
||||
break;
|
||||
default:
|
||||
error("Invalid array type %d", type);
|
||||
}
|
||||
_type = type;
|
||||
}
|
||||
|
||||
void setSize(uint32 size) {
|
||||
if (_type < 0)
|
||||
error("SciArray::setSize(): No type set");
|
||||
/**
|
||||
* Returns the size of the array, in elements.
|
||||
*/
|
||||
uint16 size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
// Check if we don't have to do anything
|
||||
if (_size == size)
|
||||
return;
|
||||
/**
|
||||
* Returns the size of the array, in bytes.
|
||||
*/
|
||||
uint16 byteSize() const {
|
||||
return _size * _elementSize;
|
||||
}
|
||||
|
||||
// Check if we don't have to expand the array
|
||||
if (size <= _actualSize) {
|
||||
_size = size;
|
||||
/**
|
||||
* Ensures the array is large enough to store at least the given number of
|
||||
* values given in `newSize`. If `force` is true, the array will be resized
|
||||
* to store exactly `newSize` values. New values are initialized to zero.
|
||||
*/
|
||||
void resize(uint16 newSize, const bool force = false) {
|
||||
if (force || newSize > _size) {
|
||||
_data = realloc(_data, _elementSize * newSize);
|
||||
if (newSize > _size) {
|
||||
memset((byte *)_data + _elementSize * _size, 0, (newSize - _size) * _elementSize);
|
||||
}
|
||||
_size = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrinks a string array to its optimal size.
|
||||
*/
|
||||
void snug() {
|
||||
assert(_type == kArrayTypeString || _type == kArrayTypeByte);
|
||||
resize(strlen((char *)_data) + 1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the array's raw data storage.
|
||||
*/
|
||||
void *getRawData() { return _data; }
|
||||
const void *getRawData() const { return _data; }
|
||||
|
||||
/**
|
||||
* Gets the value at the given index as a reg_t.
|
||||
*/
|
||||
reg_t getAsID(const uint16 index) {
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
switch(_type) {
|
||||
case kArrayTypeInt16:
|
||||
return make_reg(0, ((int16 *)_data)[index]);
|
||||
case kArrayTypeByte:
|
||||
case kArrayTypeString:
|
||||
return make_reg(0, ((byte *)_data)[index]);
|
||||
case kArrayTypeID:
|
||||
return ((reg_t *)_data)[index];
|
||||
default:
|
||||
error("Invalid array type %d", _type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value at the given index from a reg_t.
|
||||
*/
|
||||
void setFromID(const uint16 index, const reg_t value) {
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
switch(_type) {
|
||||
case kArrayTypeInt16:
|
||||
((int16 *)_data)[index] = value.toSint16();
|
||||
break;
|
||||
case kArrayTypeByte:
|
||||
case kArrayTypeString:
|
||||
((byte *)_data)[index] = value.toSint16();
|
||||
break;
|
||||
case kArrayTypeID:
|
||||
((reg_t *)_data)[index] = value;
|
||||
break;
|
||||
default:
|
||||
error("Invalid array type %d", _type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the byte at the given index. Only valid for
|
||||
* string and byte arrays.
|
||||
*/
|
||||
byte &byteAt(const uint16 index) {
|
||||
assert(_type == kArrayTypeString || _type == kArrayTypeByte);
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
return ((byte *)_data)[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the char at the given index. Only valid for
|
||||
* string and byte arrays.
|
||||
*/
|
||||
char &charAt(const uint16 index) {
|
||||
assert(_type == kArrayTypeString || _type == kArrayTypeByte);
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
return ((char *)_data)[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the int16 at the given index. Only valid for int16
|
||||
* arrays.
|
||||
*/
|
||||
int16 &int16At(const uint16 index) {
|
||||
assert(_type == kArrayTypeInt16);
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
return ((int16 *)_data)[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the reg_t at the given index. Only valid for ID
|
||||
* arrays.
|
||||
*/
|
||||
reg_t &IDAt(const uint16 index) {
|
||||
assert(_type == kArrayTypeID);
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_3) {
|
||||
resize(index);
|
||||
} else {
|
||||
assert(index < _size);
|
||||
}
|
||||
|
||||
return ((reg_t *)_data)[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads values from the given reg_t pointer and sets them in the array,
|
||||
* growing the array if needed to store all values.
|
||||
*/
|
||||
void setElements(const uint16 index, uint16 count, const reg_t *values) {
|
||||
resize(index + count);
|
||||
|
||||
switch (_type) {
|
||||
case kArrayTypeInt16: {
|
||||
const reg_t *source = values;
|
||||
int16 *target = (int16 *)_data + index;
|
||||
while (count--) {
|
||||
assert(source->isNumber());
|
||||
*target++ = source->toSint16();
|
||||
++source;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArrayTypeID: {
|
||||
const reg_t *source = values;
|
||||
reg_t *target = (reg_t *)_data + index;
|
||||
while (count--) {
|
||||
*target++ = *source++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArrayTypeByte:
|
||||
case kArrayTypeString: {
|
||||
const reg_t *source = values;
|
||||
byte *target = (byte *)_data + index;
|
||||
while (count--) {
|
||||
assert(source->isNumber());
|
||||
*target++ = source->getOffset();
|
||||
++source;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Attempted write to SciArray with invalid type %d", _type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the array with the given value. Existing values will be
|
||||
* overwritten. The array will be grown if needed to store all values.
|
||||
*/
|
||||
void fill(const uint16 index, uint16 count, const reg_t value) {
|
||||
if (count == 65535 /* -1 */) {
|
||||
count = size() - index;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
// So, we're going to have to create an array of some sort
|
||||
T *newArray = new T[size];
|
||||
memset(newArray, 0, size * sizeof(T));
|
||||
resize(index + count);
|
||||
|
||||
// Check if we never created an array before
|
||||
if (!_data) {
|
||||
_size = _actualSize = size;
|
||||
_data = newArray;
|
||||
switch (_type) {
|
||||
case kArrayTypeInt16: {
|
||||
const int16 fillValue = value.toSint16();
|
||||
int16 *target = (int16 *)_data + index;
|
||||
while (count--) {
|
||||
*target++ = fillValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArrayTypeID: {
|
||||
reg_t *target = (reg_t *)_data + index;
|
||||
while (count--) {
|
||||
*target = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArrayTypeByte:
|
||||
case kArrayTypeString: {
|
||||
byte *target = (byte *)_data + index;
|
||||
const byte fillValue = value.getOffset();
|
||||
while (count--) {
|
||||
*target = fillValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kArrayTypeInvalid:
|
||||
error("Attempted write to uninitialized SciArray");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies values from the source array. Both arrays will be grown if needed
|
||||
* to prevent out-of-bounds reads/writes.
|
||||
*/
|
||||
void copy(SciArray &source, const uint16 sourceIndex, const uint16 targetIndex, uint16 count) {
|
||||
if (count == 65535 /* -1 */) {
|
||||
count = source.size() - sourceIndex;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy data from the old array to the new
|
||||
memcpy(newArray, _data, _size * sizeof(T));
|
||||
resize(targetIndex + count);
|
||||
source.resize(sourceIndex + count);
|
||||
|
||||
// Now set the new array to the old and set the sizes
|
||||
delete[] _data;
|
||||
_data = newArray;
|
||||
_size = _actualSize = size;
|
||||
assert(source._elementSize == _elementSize);
|
||||
|
||||
const byte *sourceData = (byte *)source._data + sourceIndex * source._elementSize;
|
||||
byte *targetData = (byte *)_data + targetIndex * _elementSize;
|
||||
memmove(targetData, sourceData, count * _elementSize);
|
||||
}
|
||||
|
||||
T getValue(uint16 index) const {
|
||||
if (index >= _size)
|
||||
error("SciArray::getValue(): %d is out of bounds (%d)", index, _size);
|
||||
|
||||
return _data[index];
|
||||
void byteCopy(const SciArray &source, const uint16 sourceOffset, const uint16 targetOffset, const uint16 count) {
|
||||
error("SciArray::byteCopy not implemented");
|
||||
}
|
||||
|
||||
void setValue(uint16 index, T value) {
|
||||
if (index >= _size)
|
||||
error("SciArray::setValue(): %d is out of bounds (%d)", index, _size);
|
||||
/**
|
||||
* Removes whitespace from string data held in this array.
|
||||
*/
|
||||
void trim(const int8 flags, const char showChar) {
|
||||
enum {
|
||||
kWhitespaceBoundary = 32,
|
||||
kAsciiBoundary = 128
|
||||
};
|
||||
|
||||
_data[index] = value;
|
||||
byte *data = (byte *)_data;
|
||||
byte *source;
|
||||
byte *target;
|
||||
|
||||
if (flags & kArrayTrimLeft) {
|
||||
target = data;
|
||||
source = data;
|
||||
while (*source != '\0' && *source != showChar && *source <= kWhitespaceBoundary) {
|
||||
++source;
|
||||
}
|
||||
strcpy((char *)target, (char *)source);
|
||||
}
|
||||
|
||||
if (flags & kArrayTrimRight) {
|
||||
source = data + strlen((char *)data) - 1;
|
||||
while (source > data && *source != showChar && *source <= kWhitespaceBoundary) {
|
||||
--source;
|
||||
}
|
||||
*source = '\0';
|
||||
}
|
||||
|
||||
if (flags & kArrayTrimCenter) {
|
||||
target = data;
|
||||
while (*target && *target <= kWhitespaceBoundary && *target != showChar) {
|
||||
++target;
|
||||
}
|
||||
|
||||
if (*target) {
|
||||
while (*target && (*target > kWhitespaceBoundary || *target == showChar)) {
|
||||
++target;
|
||||
}
|
||||
|
||||
if (*target) {
|
||||
source = target;
|
||||
while (*source) {
|
||||
while (*source && *source <= kWhitespaceBoundary && *source != showChar) {
|
||||
++source;
|
||||
}
|
||||
|
||||
while (*source && (*source > kWhitespaceBoundary || *source == showChar)) {
|
||||
*target++ = *source++;
|
||||
}
|
||||
}
|
||||
|
||||
--source;
|
||||
while (source > target && (*source <= kWhitespaceBoundary || *source >= kAsciiBoundary) && *source != showChar) {
|
||||
--source;
|
||||
}
|
||||
++source;
|
||||
|
||||
memmove(target, source, strlen((char *)source) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the string data held by this array into a new Common::String.
|
||||
*/
|
||||
Common::String toString() const {
|
||||
assert(_type == kArrayTypeString);
|
||||
return Common::String((char *)_data);
|
||||
}
|
||||
|
||||
byte getType() const { return _type; }
|
||||
uint32 getSize() const { return _size; }
|
||||
T *getRawData() { return _data; }
|
||||
const T *getRawData() const { return _data; }
|
||||
/**
|
||||
* Copies the string from the given Common::String into this array.
|
||||
*/
|
||||
void fromString(const Common::String &string) {
|
||||
// At least LSL6hires uses a byte-type array to hold string data
|
||||
assert(_type == kArrayTypeString || _type == kArrayTypeByte);
|
||||
resize(string.size() + 1, true);
|
||||
Common::strlcpy((char *)_data, string.c_str(), string.size() + 1);
|
||||
}
|
||||
|
||||
protected:
|
||||
int8 _type;
|
||||
T *_data;
|
||||
uint32 _size; // _size holds the number of entries that the scripts have requested
|
||||
uint32 _actualSize; // _actualSize is the actual numbers of entries allocated
|
||||
void *_data;
|
||||
SciArrayType _type;
|
||||
uint16 _size;
|
||||
uint8 _elementSize;
|
||||
};
|
||||
|
||||
class SciString : public SciArray<char> {
|
||||
public:
|
||||
SciString() : SciArray<char>() { setType(3); }
|
||||
struct ArrayTable : public SegmentObjTable<SciArray> {
|
||||
ArrayTable() : SegmentObjTable<SciArray>(SEG_TYPE_ARRAY) {}
|
||||
|
||||
// We overload destroy to ensure the string type is 3 after destroying
|
||||
void destroy() { SciArray<char>::destroy(); _type = 3; }
|
||||
|
||||
Common::String toString() const;
|
||||
void fromString(const Common::String &string);
|
||||
};
|
||||
|
||||
struct ArrayTable : public SegmentObjTable<SciArray<reg_t> > {
|
||||
ArrayTable() : SegmentObjTable<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
|
||||
|
||||
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
|
||||
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
|
||||
|
||||
void saveLoadWithSerializer(Common::Serializer &ser);
|
||||
SegmentRef dereference(reg_t pointer);
|
||||
};
|
||||
|
||||
struct StringTable : public SegmentObjTable<SciString> {
|
||||
StringTable() : SegmentObjTable<SciString>(SEG_TYPE_STRING) {}
|
||||
|
||||
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
|
||||
at(sub_addr.getOffset()).destroy();
|
||||
freeEntry(sub_addr.getOffset());
|
||||
}
|
||||
|
||||
void saveLoadWithSerializer(Common::Serializer &ser);
|
||||
SegmentRef dereference(reg_t pointer);
|
||||
};
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Bitmaps
|
||||
|
||||
|
@ -395,6 +395,12 @@ const SciWorkaroundEntry kAbs_workarounds[] = {
|
||||
SCI_WORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
|
||||
const SciWorkaroundEntry kArraySetElements_workarounds[] = {
|
||||
{ GID_PHANTASMAGORIA,902, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_FAKE, 0 } }, // tries to set an element of a string array to the ego object when starting a new game and selecting a chapter above 1
|
||||
SCI_WORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
|
||||
const SciWorkaroundEntry kCelHigh_workarounds[] = {
|
||||
{ GID_KQ5, -1, 255, 0, "deathIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #5049
|
||||
@ -766,14 +772,10 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = {
|
||||
SCI_WORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
|
||||
const SciWorkaroundEntry kStringPutAt_workarounds[] = {
|
||||
{ GID_PHANTASMAGORIA,902, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // When starting a new game from after chapter 1, the game tries to save ego's object in a string
|
||||
};
|
||||
|
||||
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
|
||||
const SciWorkaroundEntry kScrollWindowAdd_workarounds[] = {
|
||||
{ GID_PHANTASMAGORIA, 45, 64907, 0, "ScrollableWindow", "addString", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // ScrollWindow interface passes the last two parameters twice
|
||||
SCI_WORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciCallOrigin *trackOrigin) {
|
||||
|
@ -89,12 +89,13 @@ extern const SciWorkaroundEntry kRandom_workarounds[];
|
||||
extern const SciWorkaroundEntry kReadNumber_workarounds[];
|
||||
extern const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[];
|
||||
extern const SciWorkaroundEntry kSetCursor_workarounds[];
|
||||
extern const SciWorkaroundEntry kArraySetElements_workarounds[];
|
||||
extern const SciWorkaroundEntry kSetPort_workarounds[];
|
||||
extern const SciWorkaroundEntry kStrAt_workarounds[];
|
||||
extern const SciWorkaroundEntry kStrCpy_workarounds[];
|
||||
extern const SciWorkaroundEntry kStrLen_workarounds[];
|
||||
extern const SciWorkaroundEntry kUnLoad_workarounds[];
|
||||
extern const SciWorkaroundEntry kStringPutAt_workarounds[];
|
||||
extern const SciWorkaroundEntry kStringNew_workarounds[];
|
||||
extern const SciWorkaroundEntry kScrollWindowAdd_workarounds[];
|
||||
|
||||
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciCallOrigin *trackOrigin);
|
||||
|
@ -313,8 +313,8 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
|
||||
|
||||
if (textChanged) {
|
||||
editor.text.trim();
|
||||
SciString *string = _segMan->lookupString(textObject);
|
||||
string->fromString(editor.text);
|
||||
SciArray &string = *_segMan->lookupArray(textObject);
|
||||
string.fromString(editor.text);
|
||||
}
|
||||
|
||||
return make_reg(0, textChanged);
|
||||
|
@ -267,9 +267,9 @@ void GfxTransitions32::kernelSetShowStyle(const uint16 argc, const reg_t planeOb
|
||||
// NOTE: SCI2.1mid engine does no check to verify that an array is
|
||||
// successfully retrieved, and SegMan will cause a fatal error
|
||||
// if we try to use a memory segment that is not an array
|
||||
SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
|
||||
SciArray &table = *_segMan->lookupArray(pFadeArray);
|
||||
|
||||
uint32 rangeCount = table->getSize();
|
||||
uint32 rangeCount = table.size();
|
||||
entry->fadeColorRangesCount = rangeCount;
|
||||
|
||||
// NOTE: SCI engine code always allocates memory even if the range
|
||||
@ -278,7 +278,7 @@ void GfxTransitions32::kernelSetShowStyle(const uint16 argc, const reg_t planeOb
|
||||
if (rangeCount > 0) {
|
||||
entry->fadeColorRanges = new uint16[rangeCount];
|
||||
for (size_t i = 0; i < rangeCount; ++i) {
|
||||
entry->fadeColorRanges[i] = table->getValue(i).toUint16();
|
||||
entry->fadeColorRanges[i] = table.int16At(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user