SCI32: split up SCI2.1 into EARLY/MIDDLE/LATE
- Detection works via signatures (couldn't find a better way) - new kString subcalls were introduced SCI2.1 LATE - kString now has signatures and is split via subcall table - kString fix, so that KQ7 doesn't crash, when starting a chapter - Sci2StringFunctionType removed, because no longer needed
This commit is contained in:
parent
00e0d68a9f
commit
0dd760724e
32 changed files with 510 additions and 366 deletions
|
@ -483,9 +483,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
|
|||
debugPrintf("Move count type: %s\n", (_engine->_features->handleMoveCount()) ? "increment" : "ignore");
|
||||
debugPrintf("SetCursor type: %s\n", getSciVersionDesc(_engine->_features->detectSetCursorType()));
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2)
|
||||
debugPrintf("kString type: %s\n", (_engine->_features->detectSci2StringFunctionType() == kSci2StringFunctionOld) ? "SCI2 (old)" : "SCI2.1 (new)");
|
||||
if (getSciVersion() == SCI_VERSION_2_1)
|
||||
if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE))
|
||||
debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)");
|
||||
#endif
|
||||
debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]);
|
||||
|
@ -1046,7 +1044,7 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) {
|
|||
if (!script)
|
||||
debugPrintf("Error: script %d couldn't be loaded\n", itr->getNumber());
|
||||
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
heap = _engine->getResMan()->findResource(ResourceId(kResourceTypeHeap, itr->getNumber()), false);
|
||||
if (!heap)
|
||||
debugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->getNumber());
|
||||
|
|
|
@ -40,7 +40,6 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan)
|
|||
_moveCountType = kMoveCountUninitialized;
|
||||
#ifdef ENABLE_SCI32
|
||||
_sci21KernelType = SCI_VERSION_NONE;
|
||||
_sci2StringFunctionType = kSci2StringFunctionUninitialized;
|
||||
#endif
|
||||
_usesCdTrack = Common::File::exists("cdaudio.map");
|
||||
if (!ConfMan.getBool("use_cdaudio"))
|
||||
|
@ -143,8 +142,8 @@ SciVersion GameFeatures::detectDoSoundType() {
|
|||
// SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources
|
||||
_doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
|
||||
#ifdef ENABLE_SCI32
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1) {
|
||||
_doSoundType = SCI_VERSION_2_1;
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
||||
_doSoundType = SCI_VERSION_2_1_EARLY;
|
||||
#endif
|
||||
} else if (SELECTOR(nodePtr) == -1) {
|
||||
// No nodePtr selector, so this game is definitely using newer
|
||||
|
@ -271,7 +270,7 @@ SciVersion GameFeatures::detectLofsType() {
|
|||
return _lofsType;
|
||||
}
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
// SCI1.1 type, i.e. we compensate for the fact that the heap is attached
|
||||
// to the end of the script
|
||||
_lofsType = SCI_VERSION_1_1;
|
||||
|
@ -475,7 +474,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
|
|||
}
|
||||
|
||||
warning("autoDetectSci21KernelType(): Sound object not loaded, assuming a SCI2.1 table");
|
||||
_sci21KernelType = SCI_VERSION_2_1;
|
||||
_sci21KernelType = SCI_VERSION_2_1_EARLY;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -514,7 +513,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
|
|||
_sci21KernelType = SCI_VERSION_2;
|
||||
return true;
|
||||
} else if (kFuncNum == 0x75) {
|
||||
_sci21KernelType = SCI_VERSION_2_1;
|
||||
_sci21KernelType = SCI_VERSION_2_1_EARLY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -532,65 +531,6 @@ SciVersion GameFeatures::detectSci21KernelType() {
|
|||
}
|
||||
return _sci21KernelType;
|
||||
}
|
||||
|
||||
Sci2StringFunctionType GameFeatures::detectSci2StringFunctionType() {
|
||||
if (_sci2StringFunctionType == kSci2StringFunctionUninitialized) {
|
||||
if (getSciVersion() <= SCI_VERSION_1_1) {
|
||||
error("detectSci21StringFunctionType() called from SCI1.1 or earlier");
|
||||
} else if (getSciVersion() == SCI_VERSION_2) {
|
||||
// SCI2 games are always using the old type
|
||||
_sci2StringFunctionType = kSci2StringFunctionOld;
|
||||
} else if (getSciVersion() == SCI_VERSION_3) {
|
||||
// SCI3 games are always using the new type
|
||||
_sci2StringFunctionType = kSci2StringFunctionNew;
|
||||
} else { // SCI2.1
|
||||
if (!autoDetectSci21StringFunctionType())
|
||||
_sci2StringFunctionType = kSci2StringFunctionOld;
|
||||
else
|
||||
_sci2StringFunctionType = kSci2StringFunctionNew;
|
||||
}
|
||||
}
|
||||
|
||||
debugC(1, kDebugLevelVM, "Detected SCI2 kString type: %s", (_sci2StringFunctionType == kSci2StringFunctionOld) ? "old" : "new");
|
||||
|
||||
return _sci2StringFunctionType;
|
||||
}
|
||||
|
||||
bool GameFeatures::autoDetectSci21StringFunctionType() {
|
||||
// Look up the script address
|
||||
reg_t addr = getDetectionAddr("Str", SELECTOR(size));
|
||||
|
||||
if (!addr.getSegment())
|
||||
return false;
|
||||
|
||||
uint16 offset = addr.getOffset();
|
||||
Script *script = _segMan->getScript(addr.getSegment());
|
||||
|
||||
while (true) {
|
||||
int16 opparams[4];
|
||||
byte extOpcode;
|
||||
byte opcode;
|
||||
offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams);
|
||||
opcode = extOpcode >> 1;
|
||||
|
||||
// Check for end of script
|
||||
if (opcode == op_ret || offset >= script->getBufSize())
|
||||
break;
|
||||
|
||||
if (opcode == op_callk) {
|
||||
uint16 kFuncNum = opparams[0];
|
||||
|
||||
// SCI2.1 games which use the new kString functions call kString(8).
|
||||
// Earlier ones call the callKernel script function, but not kString
|
||||
// directly
|
||||
if (_kernel->getKernelName(kFuncNum) == "String")
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // not found a call to kString
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool GameFeatures::autoDetectMoveCountType() {
|
||||
|
|
|
@ -34,12 +34,6 @@ enum MoveCountType {
|
|||
kIncrementMoveCount
|
||||
};
|
||||
|
||||
enum Sci2StringFunctionType {
|
||||
kSci2StringFunctionUninitialized,
|
||||
kSci2StringFunctionOld,
|
||||
kSci2StringFunctionNew
|
||||
};
|
||||
|
||||
class GameFeatures {
|
||||
public:
|
||||
GameFeatures(SegManager *segMan, Kernel *kernel);
|
||||
|
@ -82,13 +76,6 @@ public:
|
|||
* @return Graphics functions type, SCI_VERSION_2 / SCI_VERSION_2_1
|
||||
*/
|
||||
SciVersion detectSci21KernelType();
|
||||
|
||||
/**
|
||||
* Autodetects the string subfunctions used in SCI2 - SCI3
|
||||
* @return string subfunctions type, kSci2StringFunctionOld / kSci2StringFunctionNew
|
||||
*/
|
||||
Sci2StringFunctionType detectSci2StringFunctionType();
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -132,13 +119,11 @@ private:
|
|||
bool autoDetectMoveCountType();
|
||||
#ifdef ENABLE_SCI32
|
||||
bool autoDetectSci21KernelType();
|
||||
bool autoDetectSci21StringFunctionType();
|
||||
#endif
|
||||
|
||||
SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType, _messageFunctionType;
|
||||
#ifdef ENABLE_SCI32
|
||||
SciVersion _sci21KernelType;
|
||||
Sci2StringFunctionType _sci2StringFunctionType;
|
||||
#endif
|
||||
|
||||
MoveCountType _moveCountType;
|
||||
|
|
|
@ -118,7 +118,7 @@ void Kernel::loadSelectorNames() {
|
|||
|
||||
// Starting with KQ7, Mac versions have a BE name table. GK1 Mac and earlier (and all
|
||||
// other platforms) always use LE.
|
||||
bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1
|
||||
bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY
|
||||
&& g_sci->getGameId() != GID_GK1);
|
||||
|
||||
if (!r) { // No such resource?
|
||||
|
@ -863,7 +863,9 @@ void Kernel::loadKernelNames(GameFeatures *features) {
|
|||
_kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2);
|
||||
break;
|
||||
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
case SCI_VERSION_2_1_MIDDLE:
|
||||
case SCI_VERSION_2_1_LATE:
|
||||
if (features->detectSci21KernelType() == SCI_VERSION_2) {
|
||||
// Some early SCI2.1 games use a modified SCI2 kernel table instead of
|
||||
// the SCI2.1 kernel table. We detect which version to use based on
|
||||
|
|
|
@ -414,6 +414,27 @@ 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 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 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 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 kMulDiv(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv);
|
||||
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
|
||||
|
|
|
@ -34,6 +34,15 @@ namespace Sci {
|
|||
// . -> any type
|
||||
// i* -> optional multiple integers
|
||||
// .* -> any parameters afterwards (or none)
|
||||
//
|
||||
// data types:
|
||||
// i - regular integer
|
||||
// o - object
|
||||
// r - reference
|
||||
// n - node
|
||||
// 0 - NULL
|
||||
// . - any
|
||||
// ! - invalid reference/offset
|
||||
|
||||
struct SciKernelMapSubEntry {
|
||||
SciVersion fromVersion;
|
||||
|
@ -56,7 +65,8 @@ struct SciKernelMapSubEntry {
|
|||
#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE
|
||||
#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1
|
||||
#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE
|
||||
#define SIG_SCI21 SCI_VERSION_2_1, SCI_VERSION_3
|
||||
#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3
|
||||
#define SIG_UNTIL_SCI21MID SCI_VERSION_2_1_EARLY, SCI_VERSION_2_1_MIDDLE
|
||||
|
||||
#define SIG_SCI16 SCI_VERSION_NONE, SCI_VERSION_1_1
|
||||
#define SIG_SCI32 SCI_VERSION_2, SCI_VERSION_NONE
|
||||
|
@ -65,7 +75,7 @@ struct SciKernelMapSubEntry {
|
|||
#define SIG_SOUNDSCI0 SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE
|
||||
#define SIG_SOUNDSCI1EARLY SCI_VERSION_1_EARLY, SCI_VERSION_1_EARLY
|
||||
#define SIG_SOUNDSCI1LATE SCI_VERSION_1_LATE, SCI_VERSION_1_LATE
|
||||
#define SIG_SOUNDSCI21 SCI_VERSION_2_1, SCI_VERSION_3
|
||||
#define SIG_SOUNDSCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3
|
||||
|
||||
#define SIGFOR_ALL 0x3f
|
||||
#define SIGFOR_DOS 1 << 0
|
||||
|
@ -190,7 +200,7 @@ static const SciKernelMapSubEntry kGraph_subops[] = {
|
|||
|
||||
// version, subId, function-mapping, signature, workarounds
|
||||
static const SciKernelMapSubEntry kPalVary_subops[] = {
|
||||
{ SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL },
|
||||
{ SIG_SINCE_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL },
|
||||
{ SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL },
|
||||
{ SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL },
|
||||
{ SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL },
|
||||
|
@ -246,6 +256,7 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
|
|||
|
||||
#ifdef ENABLE_SCI32
|
||||
|
||||
// version, subId, function-mapping, signature, workarounds
|
||||
static const SciKernelMapSubEntry kSave_subops[] = {
|
||||
{ SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL },
|
||||
{ SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL },
|
||||
|
@ -261,31 +272,73 @@ static const SciKernelMapSubEntry kSave_subops[] = {
|
|||
|
||||
// version, subId, function-mapping, signature, workarounds
|
||||
static const SciKernelMapSubEntry kList_subops[] = {
|
||||
{ SIG_SCI21, 0, MAP_CALL(NewList), "", NULL },
|
||||
{ SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
|
||||
{ SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
|
||||
{ SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
|
||||
{ SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
|
||||
{ SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
|
||||
{ SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
|
||||
{ SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
|
||||
{ SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
|
||||
{ SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
|
||||
{ SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
|
||||
{ SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
|
||||
{ SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
|
||||
{ SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
|
||||
{ SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
|
||||
{ SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
|
||||
{ SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
|
||||
{ SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
|
||||
{ SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
|
||||
{ SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
|
||||
{ SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
|
||||
{ SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
|
||||
{ SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL },
|
||||
{ SIG_SINCE_SCI21, 0, MAP_CALL(NewList), "", NULL },
|
||||
{ SIG_SINCE_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
|
||||
{ SIG_SINCE_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL },
|
||||
{ SIG_SINCE_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL },
|
||||
{ SIG_SINCE_SCI21, 4, MAP_CALL(LastNode), "l", NULL },
|
||||
{ SIG_SINCE_SCI21, 5, MAP_CALL(EmptyList), "l", NULL },
|
||||
{ SIG_SINCE_SCI21, 6, MAP_CALL(NextNode), "n", NULL },
|
||||
{ SIG_SINCE_SCI21, 7, MAP_CALL(PrevNode), "n", NULL },
|
||||
{ SIG_SINCE_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL },
|
||||
{ SIG_SINCE_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL },
|
||||
{ SIG_SINCE_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL },
|
||||
{ SIG_SINCE_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL },
|
||||
{ SIG_SINCE_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL },
|
||||
{ SIG_SINCE_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL },
|
||||
{ SIG_SINCE_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL },
|
||||
{ SIG_SINCE_SCI21, 15, MAP_CALL(FindKey), "l.", NULL },
|
||||
{ SIG_SINCE_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL },
|
||||
{ SIG_SINCE_SCI21, 17, MAP_CALL(ListAt), "li", NULL },
|
||||
{ SIG_SINCE_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL },
|
||||
{ SIG_SINCE_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL },
|
||||
{ SIG_SINCE_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL },
|
||||
{ SIG_SINCE_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL },
|
||||
{ SIG_SINCE_SCI21, 22, MAP_CALL(Sort), "ooo", 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*)", NULL },
|
||||
// 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 },
|
||||
|
||||
// =SCI2.1 Early and SCI2.1 Middle=
|
||||
{ SIG_UNTIL_SCI21MID, 8, MAP_CALL(StringDup), "[or]", NULL },
|
||||
{ SIG_UNTIL_SCI21MID, 9, MAP_CALL(StringGetData), "[or]", 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 },
|
||||
// exact functionality of Trim is unknown atm
|
||||
{ SIG_UNTIL_SCI21MID, 14, MAP_CALL(StringTrim), "[or]", 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 },
|
||||
|
||||
// SCI2.1 Late + SCI3 - kStringDup + kStringGetData were removed
|
||||
{ SIG_SCI32, 8, MAP_CALL(StringLen), "[or]", NULL },
|
||||
{ SIG_SCI32, 9, MAP_CALL(StringPrintf), "[or](.*)", NULL },
|
||||
{ SIG_SCI32, 10, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL },
|
||||
{ SIG_SCI32, 11, MAP_CALL(StringAtoi), "[or]", NULL },
|
||||
{ SIG_SCI32, 12, MAP_CALL(StringTrim), "[or]", NULL },
|
||||
{ SIG_SCI32, 13, MAP_CALL(StringUpper), "[or]", NULL },
|
||||
{ SIG_SCI32, 14, MAP_CALL(StringLower), "[or]", NULL },
|
||||
{ SIG_SCI32, 15, MAP_CALL(StringTrn), "[or]", NULL },
|
||||
{ SIG_SCI32, 16, MAP_CALL(StringTrnExclude), "[or]", NULL },
|
||||
SCI_SUBOPENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct SciKernelMapEntry {
|
||||
|
@ -429,7 +482,7 @@ static SciKernelMapEntry s_kernelMap[] = {
|
|||
{ MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
|
||||
{ MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r0)", NULL, NULL },
|
||||
{ MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
|
||||
{ MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
|
||||
{ MAP_CALL(SetCursor), SIG_SINCE_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
|
||||
// TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
|
||||
{ MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
|
||||
{ MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
|
||||
|
@ -513,7 +566,7 @@ static SciKernelMapEntry s_kernelMap[] = {
|
|||
// our garbage collector (i.e. the SCI0-SCI1.1 semantics).
|
||||
{ "Purge", kFlushResources, SIG_EVERYWHERE, "i", NULL, NULL },
|
||||
{ MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL },
|
||||
{ MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||
{ MAP_CALL(String), SIG_EVERYWHERE, "(.*)", kString_subops, NULL },
|
||||
{ MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
{ MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
|
||||
{ MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL },
|
||||
|
@ -570,7 +623,7 @@ static SciKernelMapEntry s_kernelMap[] = {
|
|||
// SCI2.1 Kernel Functions
|
||||
{ MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
|
||||
{ MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
|
||||
{ MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
|
||||
{ MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
|
||||
{ MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||
|
|
|
@ -58,7 +58,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
|
|||
// In case we use a simulated event we query the current mouse position
|
||||
mousePos = g_sci->_gfxCursor->getPosition();
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
|
||||
g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
|
||||
#endif
|
||||
// Limit the mouse cursor position, if necessary
|
||||
|
@ -84,7 +84,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
|
|||
// For a real event we use its associated mouse position
|
||||
mousePos = curEvent.mousePos;
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
|
||||
g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
|
||||
#endif
|
||||
// Limit the mouse cursor position, if necessary
|
||||
|
|
|
@ -487,7 +487,7 @@ reg_t kMacPlatform(EngineState *s, int argc, reg_t *argv) {
|
|||
// In SCI1, its usage is still unknown
|
||||
// In SCI1.1, it's NOP
|
||||
// In SCI32, it's used for remapping cursor ID's
|
||||
if (getSciVersion() >= SCI_VERSION_2_1) // Set Mac cursor remap
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) // Set Mac cursor remap
|
||||
g_sci->_gfxCursor->setMacCursorRemapList(argc - 1, argv + 1);
|
||||
else if (getSciVersion() != SCI_VERSION_1_1)
|
||||
warning("Unknown SCI1 kMacPlatform(0) call");
|
||||
|
|
|
@ -229,7 +229,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
|
|||
uint16 address = scr->validateExportFunc(index, true);
|
||||
|
||||
// Point to the heap for SCI1.1 - SCI2.1 games
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
|
||||
address += scr->getScriptSize();
|
||||
|
||||
// Bugfix for the intro speed in PQ2 version 1.002.011.
|
||||
|
|
|
@ -185,7 +185,7 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
|
|||
volume = CLIP<int16>(volume, 0, AUDIO_VOLUME_MAX);
|
||||
debugC(kDebugLevelSound, "kDoAudio: set volume to %d", volume);
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
||||
int16 volumePrev = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2;
|
||||
volumePrev = CLIP<int16>(volumePrev, 0, AUDIO_VOLUME_MAX);
|
||||
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
|
||||
|
|
|
@ -674,189 +674,230 @@ reg_t kText(EngineState *s, int argc, reg_t *argv) {
|
|||
return s->r_acc;
|
||||
}
|
||||
|
||||
reg_t kString(EngineState *s, int argc, reg_t *argv) {
|
||||
uint16 op = argv[0].toUint16();
|
||||
// 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());
|
||||
|
||||
if (g_sci->_features->detectSci2StringFunctionType() == kSci2StringFunctionNew) {
|
||||
if (op >= 8) // Dup, GetData have been removed
|
||||
op += 2;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case 0: { // New
|
||||
reg_t stringHandle;
|
||||
SciString *string = s->_segMan->allocateString(&stringHandle);
|
||||
string->setSize(argv[1].toUint16());
|
||||
// Atput (put value at an index)
|
||||
reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv) {
|
||||
SciString *string = s->_segMan->lookupString(argv[0]);
|
||||
|
||||
// Make sure the first character is a null character
|
||||
if (string->getSize() > 0)
|
||||
string->setValue(0, 0);
|
||||
uint32 index = argv[1].toUint16();
|
||||
uint32 count = argc - 2;
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
case 1: // Size
|
||||
return make_reg(0, s->_segMan->getString(argv[1]).size());
|
||||
case 2: { // At (return value at an index)
|
||||
// Note that values are put in bytes to avoid sign extension
|
||||
if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
SciString *string = s->_segMan->lookupString(argv[1]);
|
||||
byte val = string->getRawData()[argv[2].toUint16()];
|
||||
return make_reg(0, val);
|
||||
} else {
|
||||
Common::String string = s->_segMan->getString(argv[1]);
|
||||
byte val = string[argv[2].toUint16()];
|
||||
return make_reg(0, val);
|
||||
}
|
||||
}
|
||||
case 3: { // Atput (put value at an index)
|
||||
SciString *string = s->_segMan->lookupString(argv[1]);
|
||||
|
||||
uint32 index = argv[2].toUint16();
|
||||
uint32 count = argc - 3;
|
||||
|
||||
if (index + count > 65535)
|
||||
break;
|
||||
|
||||
if (string->getSize() < index + count)
|
||||
string->setSize(index + count);
|
||||
|
||||
for (uint16 i = 0; i < count; i++)
|
||||
string->setValue(i + index, argv[i + 3].toUint16());
|
||||
|
||||
return argv[1]; // We also have to return the handle
|
||||
}
|
||||
case 4: // Free
|
||||
// Freeing of strings is handled by the garbage collector
|
||||
return s->r_acc;
|
||||
case 5: { // Fill
|
||||
SciString *string = s->_segMan->lookupString(argv[1]);
|
||||
uint16 index = argv[2].toUint16();
|
||||
|
||||
// A count of -1 means fill the rest of the array
|
||||
uint16 count = argv[3].toSint16() == -1 ? string->getSize() - index : argv[3].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[4].toUint16());
|
||||
|
||||
return argv[1];
|
||||
}
|
||||
case 6: { // Cpy
|
||||
const char *string2 = 0;
|
||||
uint32 string2Size = 0;
|
||||
Common::String string;
|
||||
|
||||
if (argv[3].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
SciString *sstr;
|
||||
sstr = s->_segMan->lookupString(argv[3]);
|
||||
string2 = sstr->getRawData();
|
||||
string2Size = sstr->getSize();
|
||||
} else {
|
||||
string = s->_segMan->getString(argv[3]);
|
||||
string2 = string.c_str();
|
||||
string2Size = string.size() + 1;
|
||||
}
|
||||
|
||||
uint32 index1 = argv[2].toUint16();
|
||||
uint32 index2 = argv[4].toUint16();
|
||||
|
||||
// The original engine ignores bad copies too
|
||||
if (index2 > string2Size)
|
||||
break;
|
||||
|
||||
// A count of -1 means fill the rest of the array
|
||||
uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16();
|
||||
reg_t strAddress = argv[1];
|
||||
|
||||
SciString *string1 = s->_segMan->lookupString(argv[1]);
|
||||
//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 strAddress;
|
||||
}
|
||||
case 7: { // Cmp
|
||||
Common::String string1 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]);
|
||||
Common::String string2 = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]);
|
||||
|
||||
if (argc == 4) // Strncmp
|
||||
return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[3].toUint16()));
|
||||
else // Strcmp
|
||||
return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
|
||||
}
|
||||
case 8: { // Dup
|
||||
reg_t stringHandle;
|
||||
|
||||
SciString *dupString = s->_segMan->allocateString(&stringHandle);
|
||||
|
||||
if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) {
|
||||
*dupString = *s->_segMan->lookupString(argv[1]);
|
||||
} else {
|
||||
dupString->fromString(s->_segMan->getString(argv[1]));
|
||||
}
|
||||
|
||||
return stringHandle;
|
||||
}
|
||||
case 9: // Getdata
|
||||
if (!s->_segMan->isHeapObject(argv[1]))
|
||||
return argv[1];
|
||||
|
||||
return readSelector(s->_segMan, argv[1], SELECTOR(data));
|
||||
case 10: // Stringlen
|
||||
return make_reg(0, s->_segMan->strlen(argv[1]));
|
||||
case 11: { // Printf
|
||||
reg_t stringHandle;
|
||||
s->_segMan->allocateString(&stringHandle);
|
||||
|
||||
reg_t *adjustedArgs = new reg_t[argc];
|
||||
adjustedArgs[0] = stringHandle;
|
||||
memcpy(&adjustedArgs[1], argv + 1, (argc - 1) * sizeof(reg_t));
|
||||
|
||||
kFormat(s, argc, adjustedArgs);
|
||||
delete[] adjustedArgs;
|
||||
return stringHandle;
|
||||
}
|
||||
case 12: // Printf Buf
|
||||
return kFormat(s, argc - 1, argv + 1);
|
||||
case 13: { // atoi
|
||||
Common::String string = s->_segMan->getString(argv[1]);
|
||||
return make_reg(0, (uint16)atoi(string.c_str()));
|
||||
}
|
||||
// New subops in SCI2.1 late / SCI3
|
||||
case 14: // unknown
|
||||
warning("kString, subop %d", op);
|
||||
if (index + count > 65535)
|
||||
return NULL_REG;
|
||||
case 15: { // upper
|
||||
Common::String string = s->_segMan->getString(argv[1]);
|
||||
|
||||
string.toUppercase();
|
||||
s->_segMan->strcpy(argv[1], string.c_str());
|
||||
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;
|
||||
}
|
||||
case 16: { // lower
|
||||
Common::String string = s->_segMan->getString(argv[1]);
|
||||
|
||||
string.toLowercase();
|
||||
s->_segMan->strcpy(argv[1], string.c_str());
|
||||
return NULL_REG;
|
||||
}
|
||||
default:
|
||||
error("Unknown kString subop %d", argv[0].toUint16());
|
||||
// A count of -1 means fill the rest of the array
|
||||
uint32 count = argv[4].toSint16() == -1 ? string2Size - index2 + 1 : 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) {
|
||||
warning("kStringTrim (argc = %d)", argc);
|
||||
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");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // End of namespace Sci
|
||||
|
|
|
@ -181,7 +181,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
|
|||
// for the video, so we'll just play it from there for now.
|
||||
|
||||
#ifdef ENABLE_SCI32
|
||||
if (getSciVersion() >= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
||||
// SCI2.1 always has argv[0] as 1, the rest of the arguments seem to
|
||||
// follow SCI1.1/2.
|
||||
if (argv[0].toUint16() != 1)
|
||||
|
|
|
@ -182,7 +182,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
|
|||
#ifdef ENABLE_SCI32
|
||||
case 5: // v5 seems to be compatible with v4
|
||||
// SCI32 Mac is different than SCI32 DOS/Win here
|
||||
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1)
|
||||
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY)
|
||||
reader = new MessageReaderV4_MacSCI32(res->data, res->size);
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -45,7 +45,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
|
|||
return false;
|
||||
}
|
||||
block[idx].setSegment(segment); // Perform relocation
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
|
||||
block[idx].incOffset(scriptSize);
|
||||
|
||||
return true;
|
||||
|
@ -63,7 +63,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
|
|||
for (int i = 0; i < _methodCount * 2 + 2; ++i) {
|
||||
_baseMethod.push_back(READ_SCI11ENDIAN_UINT16(data + READ_LE_UINT16(data + kOffsetFunctionArea) + i * 2));
|
||||
}
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
_variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
|
||||
_baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
|
||||
_methodCount = READ_SCI11ENDIAN_UINT16(buf + READ_SCI11ENDIAN_UINT16(data + 6));
|
||||
|
@ -75,7 +75,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
|
|||
}
|
||||
|
||||
if (initVariables) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
for (uint i = 0; i < _variables.size(); i++)
|
||||
_variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
|
||||
} else {
|
||||
|
@ -92,7 +92,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
|
|||
const byte *buf = 0;
|
||||
uint varnum = 0;
|
||||
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
const Object *obj = getClass(segMan);
|
||||
varnum = getSciVersion() <= SCI_VERSION_1_LATE ? getVarCount() : obj->getVariable(1).toUint16();
|
||||
buf = (const byte *)obj->_baseVars;
|
||||
|
|
|
@ -79,42 +79,42 @@ public:
|
|||
}
|
||||
|
||||
reg_t getSpeciesSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _variables[_offset];
|
||||
else // SCI3
|
||||
return _speciesSelectorSci3;
|
||||
}
|
||||
|
||||
void setSpeciesSelector(reg_t value) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
_variables[_offset] = value;
|
||||
else // SCI3
|
||||
_speciesSelectorSci3 = value;
|
||||
}
|
||||
|
||||
reg_t getSuperClassSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _variables[_offset + 1];
|
||||
else // SCI3
|
||||
return _superClassPosSci3;
|
||||
}
|
||||
|
||||
void setSuperClassSelector(reg_t value) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
_variables[_offset + 1] = value;
|
||||
else // SCI3
|
||||
_superClassPosSci3 = value;
|
||||
}
|
||||
|
||||
reg_t getInfoSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _variables[_offset + 2];
|
||||
else // SCI3
|
||||
return _infoSelectorSci3;
|
||||
}
|
||||
|
||||
void setInfoSelector(reg_t info) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
_variables[_offset + 2] = info;
|
||||
else // SCI3
|
||||
_infoSelectorSci3 = info;
|
||||
|
@ -123,7 +123,7 @@ public:
|
|||
// No setter for the -info- selector
|
||||
|
||||
reg_t getNameSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG;
|
||||
else // SCI3
|
||||
return _variables.size() ? _variables[0] : NULL_REG;
|
||||
|
@ -132,7 +132,7 @@ public:
|
|||
// No setter for the name selector
|
||||
|
||||
reg_t getPropDictSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _variables[2];
|
||||
else
|
||||
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
|
||||
|
@ -140,7 +140,7 @@ public:
|
|||
}
|
||||
|
||||
void setPropDictSelector(reg_t value) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
_variables[2] = value;
|
||||
else
|
||||
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
|
||||
|
@ -148,14 +148,14 @@ public:
|
|||
}
|
||||
|
||||
reg_t getClassScriptSelector() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
return _variables[4];
|
||||
else // SCI3
|
||||
return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6));
|
||||
}
|
||||
|
||||
void setClassScriptSelector(reg_t value) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() < SCI_VERSION_3)
|
||||
_variables[4] = value;
|
||||
else // SCI3
|
||||
// This should never occur, this is called from a SCI1.1 - SCI2.1 only function
|
||||
|
|
|
@ -465,7 +465,7 @@ void Script::syncStringHeap(Common::Serializer &s) {
|
|||
break;
|
||||
} while (1);
|
||||
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1){
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE){
|
||||
// Strings in SCI1.1 come after the object instances
|
||||
byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
|
|||
|
||||
if (getSciVersion() == SCI_VERSION_0_EARLY) {
|
||||
_bufSize += READ_LE_UINT16(script->data) * 2;
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
// In SCI1.1 - SCI2.1, the heap was in a separate space from the script. We append
|
||||
// it to the end of the script, and adjust addressing accordingly.
|
||||
// However, since we address the heap with a 16-bit pointer, the
|
||||
|
@ -142,7 +142,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
|
|||
assert(_bufSize >= script->size);
|
||||
memcpy(_buf, script->data, script->size);
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
|
||||
assert(heap != 0);
|
||||
|
||||
|
@ -171,7 +171,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
|
|||
_localsOffset = localsBlock - _buf + 4;
|
||||
_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size
|
||||
}
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
if (READ_LE_UINT16(_buf + 1 + 5) > 0) { // does the script have an export table?
|
||||
_exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
|
||||
_numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
|
||||
|
@ -387,7 +387,7 @@ void Script::identifyOffsets() {
|
|||
scriptDataLeft -= blockSize;
|
||||
} while (1);
|
||||
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
// Strings in SCI1.1 up to SCI2 come after the object instances
|
||||
scriptDataPtr = _heapStart;
|
||||
scriptDataLeft = _heapSize;
|
||||
|
@ -668,7 +668,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
|
|||
return false;
|
||||
}
|
||||
block[idx].setSegment(segment); // Perform relocation
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
|
||||
block[idx].incOffset(scriptSize);
|
||||
|
||||
return true;
|
||||
|
@ -702,7 +702,7 @@ void Script::relocateSci0Sci21(reg_t block) {
|
|||
uint16 heapSize = (uint16)_bufSize;
|
||||
uint16 heapOffset = 0;
|
||||
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
heap = _heapStart;
|
||||
heapSize = (uint16)_heapSize;
|
||||
heapOffset = _scriptSize;
|
||||
|
@ -930,7 +930,7 @@ void Script::initializeClasses(SegManager *segMan) {
|
|||
if (getSciVersion() <= SCI_VERSION_1_LATE) {
|
||||
seeker = findBlockSCI0(SCI_OBJ_CLASS);
|
||||
mult = 1;
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
|
||||
mult = 2;
|
||||
} else if (getSciVersion() == SCI_VERSION_3) {
|
||||
|
@ -962,7 +962,7 @@ void Script::initializeClasses(SegManager *segMan) {
|
|||
if (isClass)
|
||||
species = READ_SCI11ENDIAN_UINT16(seeker + 12);
|
||||
classpos += 12;
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
isClass = (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass); // -info- selector
|
||||
species = READ_SCI11ENDIAN_UINT16(seeker + 10);
|
||||
} else if (getSciVersion() == SCI_VERSION_3) {
|
||||
|
@ -1104,7 +1104,7 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) {
|
|||
void Script::initializeObjects(SegManager *segMan, SegmentId segmentId) {
|
||||
if (getSciVersion() <= SCI_VERSION_1_LATE)
|
||||
initializeObjectsSci0(segMan, segmentId);
|
||||
else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1)
|
||||
else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE)
|
||||
initializeObjectsSci11(segMan, segmentId);
|
||||
else if (getSciVersion() == SCI_VERSION_3)
|
||||
initializeObjectsSci3(segMan, segmentId);
|
||||
|
|
|
@ -114,16 +114,16 @@ static const SelectorRemap sciSelectorRemap[] = {
|
|||
{ SCI_VERSION_1_1, SCI_VERSION_1_1, "cantBeHere", 54 },
|
||||
// The following are not really needed. They've only been defined to
|
||||
// ease game debugging.
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-objID-", 4096 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-size-", 4097 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-propDict-", 4098 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-methDict-", 4099 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-classScript-", 4100 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-script-", 4101 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-super-", 4102 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-objID-", 4096 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-size-", 4097 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-propDict-", 4098 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-methDict-", 4099 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-classScript-", 4100 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-script-", 4101 },
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-super-", 4102 },
|
||||
//
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1, "-info-", 4103 },
|
||||
{ SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
|
||||
{ SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-info-", 4103 },
|
||||
{ SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
|
||||
};
|
||||
|
||||
struct ClassReference {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
namespace Sci {
|
||||
|
||||
SegmentId reg_t::getSegment() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() < SCI_VERSION_3) {
|
||||
return _segment;
|
||||
} else {
|
||||
// Return the lower 14 bits of the segment
|
||||
|
@ -38,7 +38,7 @@ SegmentId reg_t::getSegment() const {
|
|||
}
|
||||
|
||||
void reg_t::setSegment(SegmentId segment) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() < SCI_VERSION_3) {
|
||||
_segment = segment;
|
||||
} else {
|
||||
// Set the lower 14 bits of the segment, and preserve the upper 2 ones for the offset
|
||||
|
@ -47,7 +47,7 @@ void reg_t::setSegment(SegmentId segment) {
|
|||
}
|
||||
|
||||
uint32 reg_t::getOffset() const {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() < SCI_VERSION_3) {
|
||||
return _offset;
|
||||
} else {
|
||||
// Return the lower 16 bits from the offset, and the 17th and 18th bits from the segment
|
||||
|
@ -56,7 +56,7 @@ uint32 reg_t::getOffset() const {
|
|||
}
|
||||
|
||||
void reg_t::setOffset(uint32 offset) {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() < SCI_VERSION_3) {
|
||||
_offset = offset;
|
||||
} else {
|
||||
// Store the lower 16 bits in the offset, and the 17th and 18th bits in the segment
|
||||
|
|
|
@ -130,7 +130,7 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
|
|||
#ifdef ENABLE_SCI32
|
||||
if (view->isSci2Hires())
|
||||
view->adjustToUpscaledCoordinates(y, x);
|
||||
else if (getSciVersion() == SCI_VERSION_2_1)
|
||||
else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE))
|
||||
_coordAdjuster->fromScriptToDisplay(y, x);
|
||||
#endif
|
||||
|
||||
|
@ -140,7 +140,7 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
|
|||
if (view->isSci2Hires()) {
|
||||
view->adjustBackUpscaledCoordinates(celRect.top, celRect.left);
|
||||
view->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right);
|
||||
} else if (getSciVersion() == SCI_VERSION_2_1) {
|
||||
} else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) {
|
||||
_coordAdjuster->fromDisplayToScript(celRect.top, celRect.left);
|
||||
_coordAdjuster->fromDisplayToScript(celRect.bottom, celRect.right);
|
||||
}
|
||||
|
|
|
@ -727,7 +727,7 @@ void GfxFrameout::kernelFrameout() {
|
|||
if (view && view->isSci2Hires()) {
|
||||
view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x);
|
||||
view->adjustToUpscaledCoordinates(itemEntry->z, dummyX);
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
||||
_coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x);
|
||||
_coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX);
|
||||
}
|
||||
|
@ -782,7 +782,7 @@ void GfxFrameout::kernelFrameout() {
|
|||
view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left);
|
||||
view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right);
|
||||
g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1 && _resMan->detectHires()) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) {
|
||||
_coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left);
|
||||
_coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right);
|
||||
g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
|
||||
|
|
|
@ -356,7 +356,7 @@ void GfxView::initData(GuiResourceId resourceId) {
|
|||
for (loopNo = 0; loopNo < _loopCount; loopNo++)
|
||||
for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++)
|
||||
_screen->adjustBackUpscaledCoordinates(_loop[loopNo].cel[celNo].scriptWidth, _loop[loopNo].cel[celNo].scriptHeight, _sci2ScaleRes);
|
||||
} else if (getSciVersion() == SCI_VERSION_2_1) {
|
||||
} else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) {
|
||||
for (loopNo = 0; loopNo < _loopCount; loopNo++)
|
||||
for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++)
|
||||
_coordAdjuster->fromDisplayToScript(_loop[loopNo].cel[celNo].scriptHeight, _loop[loopNo].cel[celNo].scriptWidth);
|
||||
|
|
|
@ -82,8 +82,12 @@ const char *getSciVersionDesc(SciVersion version) {
|
|||
return "SCI1.1";
|
||||
case SCI_VERSION_2:
|
||||
return "SCI2";
|
||||
case SCI_VERSION_2_1:
|
||||
return "SCI2.1";
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
return "Early SCI2.1";
|
||||
case SCI_VERSION_2_1_MIDDLE:
|
||||
return "Middle SCI2.1";
|
||||
case SCI_VERSION_2_1_LATE:
|
||||
return "Late SCI2.1";
|
||||
case SCI_VERSION_3:
|
||||
return "SCI3";
|
||||
default:
|
||||
|
@ -2121,6 +2125,79 @@ ViewType ResourceManager::detectViewType() {
|
|||
return kViewUnknown;
|
||||
}
|
||||
|
||||
// to detect selector "wordFail" in LE vocab resource
|
||||
static const byte detectSci21EarlySignature[] = {
|
||||
10, // size of signature
|
||||
0x08, 0x00, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
|
||||
};
|
||||
|
||||
// to detect selector "wordFail" in BE vocab resource (SCI2.1 Early)
|
||||
static const byte detectSci21EarlyBESignature[] = {
|
||||
10, // size of signature
|
||||
0x00, 0x08, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l'
|
||||
};
|
||||
|
||||
// to detect new kString calling to detect SCI2.1 Late
|
||||
static const byte detectSci21NewStringSignature[] = {
|
||||
8, // size of signature
|
||||
0x78, // push1
|
||||
0x78, // push1
|
||||
0x39, 0x09, // pushi 09
|
||||
0x59, 0x01, // rest 01
|
||||
0x43, 0x5c, // callk String
|
||||
};
|
||||
|
||||
bool ResourceManager::checkResourceDataForSignature(Resource *resource, const byte *signature) {
|
||||
byte signatureSize = *signature;
|
||||
const byte *resourceData = resource->data;
|
||||
|
||||
signature++; // skip over size byte
|
||||
if (signatureSize < 4)
|
||||
error("resource signature is too small, internal error");
|
||||
if (signatureSize > resource->size)
|
||||
return false;
|
||||
|
||||
const uint32 signatureDWord = *((uint32 *)signature);
|
||||
signature += 4; signatureSize -= 4;
|
||||
|
||||
const uint32 searchLimit = resource->size - signatureSize + 1;
|
||||
uint32 DWordOffset = 0;
|
||||
while (DWordOffset < searchLimit) {
|
||||
if (signatureDWord == READ_UINT32(resourceData + DWordOffset)) {
|
||||
// magic DWORD found, check if the rest matches as well
|
||||
uint32 offset = DWordOffset + 4;
|
||||
uint32 signaturePos = 0;
|
||||
while (signaturePos < signatureSize) {
|
||||
if (resourceData[offset] != signature[signaturePos])
|
||||
break;
|
||||
offset++;
|
||||
signaturePos++;
|
||||
}
|
||||
if (signaturePos >= signatureSize)
|
||||
return true; // signature found
|
||||
}
|
||||
DWordOffset++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResourceManager::checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2) {
|
||||
Resource *resource = findResource(ResourceId(resourceType, resourceNr), false);
|
||||
|
||||
if (resource) {
|
||||
// resource found and loaded, check for signatures
|
||||
if (signature1) {
|
||||
if (checkResourceDataForSignature(resource, signature1))
|
||||
return true;
|
||||
}
|
||||
if (signature2) {
|
||||
if (checkResourceDataForSignature(resource, signature2))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResourceManager::detectSciVersion() {
|
||||
// We use the view compression to set a preliminary s_sciVersion for the sake of getResourceInfo
|
||||
// Pretend we have a SCI0 game
|
||||
|
@ -2180,31 +2257,52 @@ void ResourceManager::detectSciVersion() {
|
|||
// no Mac SCI2 games. Yes, that means that GK1 Mac is SCI2.1 and not SCI2.
|
||||
|
||||
// TODO: Decide between SCI2.1 and SCI3
|
||||
if (res)
|
||||
s_sciVersion = SCI_VERSION_2_1;
|
||||
else
|
||||
if (res) {
|
||||
s_sciVersion = SCI_VERSION_2_1_EARLY; // we check for SCI2.1 specifics a bit later
|
||||
} else {
|
||||
s_sciVersion = SCI_VERSION_1_1;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle SCI32 versions here
|
||||
if (_volVersion >= kResVersionSci2) {
|
||||
Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
|
||||
bool hasHeapResources = !heaps.empty();
|
||||
if (s_sciVersion != SCI_VERSION_2_1_EARLY) {
|
||||
if (_volVersion >= kResVersionSci2) {
|
||||
Common::List<ResourceId> heaps = listResources(kResourceTypeHeap);
|
||||
bool hasHeapResources = !heaps.empty();
|
||||
|
||||
// SCI2.1/3 and SCI1 Late resource maps are the same, except that
|
||||
// SCI1 Late resource maps have the resource types or'd with
|
||||
// 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
|
||||
if (_mapVersion == kResVersionSci1Late) {
|
||||
s_sciVersion = SCI_VERSION_2;
|
||||
return;
|
||||
} else if (hasHeapResources) {
|
||||
s_sciVersion = SCI_VERSION_2_1;
|
||||
return;
|
||||
} else {
|
||||
s_sciVersion = SCI_VERSION_3;
|
||||
// SCI2.1/3 and SCI1 Late resource maps are the same, except that
|
||||
// SCI1 Late resource maps have the resource types or'd with
|
||||
// 0x80. We differentiate between SCI2 and SCI2.1/3 based on that.
|
||||
if (_mapVersion == kResVersionSci1Late) {
|
||||
s_sciVersion = SCI_VERSION_2;
|
||||
return;
|
||||
} else if (hasHeapResources) {
|
||||
s_sciVersion = SCI_VERSION_2_1_EARLY; // exact SCI2.1 version is checked a bit later
|
||||
} else {
|
||||
s_sciVersion = SCI_VERSION_3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s_sciVersion == SCI_VERSION_2_1_EARLY) {
|
||||
// we only know that it's SCI2.1, not which exact version it is
|
||||
|
||||
// check, if selector "wordFail" inside vocab 997 exists, if it does it's SCI2.1 Early
|
||||
if ((checkResourceForSignatures(kResourceTypeVocab, 997, detectSci21EarlySignature, detectSci21EarlyBESignature))) {
|
||||
// found -> it is SCI2.1 early
|
||||
return;
|
||||
}
|
||||
|
||||
s_sciVersion = SCI_VERSION_2_1_MIDDLE;
|
||||
if (checkResourceForSignatures(kResourceTypeScript, 64918, detectSci21NewStringSignature, nullptr)) {
|
||||
// new kString call detected, it's SCI2.1 late
|
||||
// TODO: this call seems to be different on Mac
|
||||
s_sciVersion = SCI_VERSION_2_1_LATE;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for transitive SCI1/SCI1.1 games, like PQ1 here
|
||||
|
@ -2537,7 +2635,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
|
|||
|
||||
int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
|
||||
return make_reg(1, offset);
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
offsetPtr = script->data + 4 + 2 + 2;
|
||||
|
||||
// In SCI1.1 - SCI2.1, the heap is appended at the end of the script,
|
||||
|
@ -2565,7 +2663,7 @@ Common::String ResourceManager::findSierraGameId() {
|
|||
|
||||
if (getSciVersion() < SCI_VERSION_1_1) {
|
||||
heap = findResource(ResourceId(kResourceTypeScript, 0), false);
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
|
||||
heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
|
||||
nameSelector += 5;
|
||||
} else if (getSciVersion() == SCI_VERSION_3) {
|
||||
|
|
|
@ -559,6 +559,8 @@ protected:
|
|||
ViewType detectViewType();
|
||||
bool hasSci0Voc999();
|
||||
bool hasSci1Voc900();
|
||||
bool checkResourceDataForSignature(Resource *resource, const byte *signature);
|
||||
bool checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2);
|
||||
void detectSciVersion();
|
||||
};
|
||||
|
||||
|
|
|
@ -637,7 +637,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
|
|||
|
||||
case SCI_VERSION_1_EARLY:
|
||||
case SCI_VERSION_1_LATE:
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
data = resource->data;
|
||||
// Count # of tracks
|
||||
_trackCount = 0;
|
||||
|
|
|
@ -897,7 +897,9 @@ void SciEngine::syncIngameAudioOptions() {
|
|||
break;
|
||||
#ifdef ENABLE_SCI32
|
||||
case SCI_VERSION_2:
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
case SCI_VERSION_2_1_MIDDLE:
|
||||
case SCI_VERSION_2_1_LATE:
|
||||
// Only use global 90 for some specific games, not all SCI32 games used this method
|
||||
switch (_gameId) {
|
||||
case GID_KQ7: // SCI2.1
|
||||
|
|
|
@ -200,7 +200,9 @@ enum SciVersion {
|
|||
SCI_VERSION_1_LATE, // Dr. Brain 1, EcoQuest 1, Longbow, PQ3, SQ1, LSL5, KQ5 CD
|
||||
SCI_VERSION_1_1, // Dr. Brain 2, EcoQuest 1 CD, EcoQuest 2, KQ6, QFG3, SQ4CD, XMAS 1992 and many more
|
||||
SCI_VERSION_2, // GK1, PQ4 floppy, QFG4 floppy
|
||||
SCI_VERSION_2_1, // GK2, KQ7, LSL6 hires, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
|
||||
SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7, LSL6 hires, PQ4, QFG4 floppy
|
||||
SCI_VERSION_2_1_MIDDLE, // GK2, KQ7, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
|
||||
SCI_VERSION_2_1_LATE, // demos of LSL7, Lighthouse, RAMA
|
||||
SCI_VERSION_3 // LSL7, Lighthouse, RAMA, Phantasmagoria 2
|
||||
};
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) {
|
|||
if (b & 8) {
|
||||
#ifdef ENABLE_SCI32
|
||||
// SCI2.1 reverses the order of the table values here
|
||||
if (getSciVersion() >= SCI_VERSION_2_1)
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
|
||||
s -= tableDPCM8[b & 7];
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -1019,7 +1019,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
|
|||
if (!isMt32GmPatch(res->data, res->size)) {
|
||||
mapMt32ToGm(res->data, res->size);
|
||||
} else {
|
||||
if (getSciVersion() <= SCI_VERSION_2_1) {
|
||||
if (getSciVersion() < SCI_VERSION_3) {
|
||||
error("MT-32 patch has wrong type");
|
||||
} else {
|
||||
// Happens in the SCI3 interactive demo of Lighthouse
|
||||
|
|
|
@ -717,7 +717,7 @@ bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) {
|
|||
break;
|
||||
case SCI_VERSION_1_EARLY:
|
||||
case SCI_VERSION_1_LATE:
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
inc = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -862,7 +862,7 @@ void MidiParser_SCI::setMasterVolume(byte masterVolume) {
|
|||
|
||||
case SCI_VERSION_1_EARLY:
|
||||
case SCI_VERSION_1_LATE:
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
// directly set master volume (global volume is merged with channel volumes)
|
||||
((MidiPlayer *)_driver)->setVolume(masterVolume);
|
||||
break;
|
||||
|
@ -887,7 +887,7 @@ void MidiParser_SCI::setVolume(byte volume) {
|
|||
|
||||
case SCI_VERSION_1_EARLY:
|
||||
case SCI_VERSION_1_LATE:
|
||||
case SCI_VERSION_2_1:
|
||||
case SCI_VERSION_2_1_EARLY:
|
||||
// Send previous channel volumes again to actually update the volume
|
||||
for (int i = 0; i < 15; i++)
|
||||
if (_channelRemap[i] != -1)
|
||||
|
|
|
@ -73,7 +73,7 @@ void SciMusic::init() {
|
|||
// Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
|
||||
// Also, default to MIDI for Windows versions of SCI1.1 games, as their
|
||||
// soundtrack is written for GM.
|
||||
if (getSciVersion() >= SCI_VERSION_2_1 || g_sci->_features->useAltWinGMSound())
|
||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY || g_sci->_features->useAltWinGMSound())
|
||||
deviceFlags |= MDT_PREFER_GM;
|
||||
|
||||
// Currently our CMS implementation only supports SCI1(.1)
|
||||
|
|
|
@ -49,7 +49,7 @@ uint16 READ_SCI11ENDIAN_UINT16(const void *ptr) {
|
|||
}
|
||||
|
||||
uint16 READ_SCI32ENDIAN_UINT16(const void *ptr) {
|
||||
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1)
|
||||
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY)
|
||||
return READ_BE_UINT16(ptr);
|
||||
else
|
||||
return READ_LE_UINT16(ptr);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue