Skip to content
Permalink
Browse files

SCI: Added automatic detection for several selectors

This ensures that these selectors will be detected regardless of the game
ID, when they're missing
  • Loading branch information...
bluegr committed Mar 12, 2011
1 parent 429b091 commit 0bc9db7872ca163a2a7ccfde74ab0afa4656345c
Showing with 117 additions and 102 deletions.
  1. +5 −0 engines/sci/engine/kernel.h
  2. +112 −102 engines/sci/engine/static_selectors.cpp
@@ -254,6 +254,11 @@ class Kernel {
*/
Common::StringArray checkStaticSelectorNames();

/**
* Automatically find specific selectors
*/
void findSpecificSelectors(Common::StringArray &selectorNames);

/**
* Maps special selectors.
*/
@@ -28,6 +28,7 @@

#include "sci/engine/kernel.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/vm.h"

namespace Sci {

@@ -118,6 +119,33 @@ static const SelectorRemap sciSelectorRemap[] = {
{ SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
};

struct ClassReference {
int script;
const char *className;
const char *selectorName;
SelectorType selectorType;
uint selectorOffset;
};

// For variable selectors, we ignore the global selectors and start off from
// the object's selectors (i.e. from the name selector onwards). Thus, the
// following are not taken into consideration when calculating the indices of
// variable selectors in this array:
// SCI0 - SCI1: species, superClass, -info-
// SCI1.1: -objID-, -size-, -propDict-, -methDict-, -classScript-, -script-,
// -super-, -info-
static const ClassReference classReferences[] = {
{ 0, "Character", "say", kSelectorMethod, 5 }, // Crazy Nick's Soft Picks
{ 928, "Narrator", "say", kSelectorMethod, 4 },
{ 928, "Narrator", "startText", kSelectorMethod, 5 },
{ 929, "Sync", "syncTime", kSelectorVariable, 1 },
{ 929, "Sync", "syncCue", kSelectorVariable, 2 },
{ 981, "SysWindow", "open", kSelectorMethod, 1 },
{ 999, "Script", "init", kSelectorMethod, 0 },
{ 999, "Script", "dispose", kSelectorMethod, 2 },
{ 999, "Script", "changeState", kSelectorMethod, 3 }
};

Common::StringArray Kernel::checkStaticSelectorNames() {
Common::StringArray names;
const int offset = (getSciVersion() < SCI_VERSION_1_1) ? 3 : 0;
@@ -158,133 +186,115 @@ Common::StringArray Kernel::checkStaticSelectorNames() {
names[i] = sci11Selectors[i - count - countSci1];
}

// Now, we need to find out selectors which keep changing place...
// We do that by dissecting game objects, and looking for selectors at
// specified locations.
findSpecificSelectors(names);

// We need to initialize script 0 here, to make sure that it's always
// located at segment 1.
_segMan->instantiateScript(0);

// The Actor class contains the init, xLast and yLast selectors, which
// we reference directly. It's always in script 998, so we need to
// explicitly load it here.
if (_resMan->testResource(ResourceId(kResourceTypeScript, 998))) {
_segMan->instantiateScript(998);

const Object *actorClass = _segMan->getObject(_segMan->findObjectByName("Actor"));

if (actorClass) {
// The init selector is always the first function
int initSelectorPos = actorClass->getFuncSelector(0);
#ifdef ENABLE_SCI32
} else {
// SCI2+
for (int i = 0; i < count; i++)
names[i] = sci2Selectors[i];
#endif
}

if (names.size() < (uint32)initSelectorPos + 2)
names.resize((uint32)initSelectorPos + 2);
for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) {
if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) {
const uint32 slot = selectorRemap->slot;
if (slot >= names.size())
names.resize(slot + 1);
names[slot] = selectorRemap->name;
}
}

names[initSelectorPos] = "init";
// dispose comes right after init
names[initSelectorPos + 1] = "dispose";
return names;
}

if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY)) {
// Find the xLast and yLast selectors, used in kDoBresen
void Kernel::findSpecificSelectors(Common::StringArray &selectorNames) {
// Now, we need to find out selectors which keep changing place...
// We do that by dissecting game objects, and looking for selectors at
// specified locations.

// xLast and yLast always come between illegalBits and xStep
int illegalBitsSelectorPos = actorClass->locateVarSelector(_segMan, 15 + offset); // illegalBits
int xStepSelectorPos = actorClass->locateVarSelector(_segMan, 51 + offset); // xStep
if (xStepSelectorPos - illegalBitsSelectorPos != 3) {
error("illegalBits and xStep selectors aren't found in "
"known locations. illegalBits = %d, xStep = %d",
illegalBitsSelectorPos, xStepSelectorPos);
}
// We need to initialize script 0 here, to make sure that it's always
// located at segment 1.
_segMan->instantiateScript(0);

int xLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 1);
int yLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 2);
// The Actor class contains the init, xLast and yLast selectors, which
// we reference directly. It's always in script 998, so we need to
// explicitly load it here.
if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY)) {
if (_resMan->testResource(ResourceId(kResourceTypeScript, 998))) {
_segMan->instantiateScript(998);

if (names.size() < (uint32)yLastSelectorPos + 1)
names.resize((uint32)yLastSelectorPos + 1);
const Object *actorClass = _segMan->getObject(_segMan->findObjectByName("Actor"));

names[xLastSelectorPos] = "xLast";
names[yLastSelectorPos] = "yLast";
} // if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY))
if (actorClass) {
// Find the xLast and yLast selectors, used in kDoBresen

const int offset = (getSciVersion() < SCI_VERSION_1_1) ? 3 : 0;
// xLast and yLast always come between illegalBits and xStep
int illegalBitsSelectorPos = actorClass->locateVarSelector(_segMan, 15 + offset); // illegalBits
int xStepSelectorPos = actorClass->locateVarSelector(_segMan, 51 + offset); // xStep
if (xStepSelectorPos - illegalBitsSelectorPos != 3) {
error("illegalBits and xStep selectors aren't found in "
"known locations. illegalBits = %d, xStep = %d",
illegalBitsSelectorPos, xStepSelectorPos);
}

int xLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 1);
int yLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 2);

if (selectorNames.size() < (uint32)yLastSelectorPos + 1)
selectorNames.resize((uint32)yLastSelectorPos + 1);

selectorNames[xLastSelectorPos] = "xLast";
selectorNames[yLastSelectorPos] = "yLast";
} // if (actorClass)

_segMan->uninstantiateScript(998);
} // if (_resMan->testResource(ResourceId(kResourceTypeScript, 998)))
} // if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY))

// Find selectors from specific classes

for (int i = 0; i < ARRAYSIZE(classReferences); i++) {
if (!_resMan->testResource(ResourceId(kResourceTypeScript, classReferences[i].script)))
continue;

if (_resMan->testResource(ResourceId(kResourceTypeScript, 981))) {
// The SysWindow class contains the open selectors, which we
// reference directly. It's always in script 981, so we need to
// explicitly load it here
_segMan->instantiateScript(981);
_segMan->instantiateScript(classReferences[i].script);

const Object *sysWindowClass = _segMan->getObject(_segMan->findObjectByName("SysWindow"));
const Object *targetClass = _segMan->getObject(_segMan->findObjectByName(classReferences[i].className));
int targetSelectorPos = 0;
uint selectorOffset = classReferences[i].selectorOffset;

if (sysWindowClass) {
if (sysWindowClass->getMethodCount() < 2)
error("The SysWindow class has less than 2 methods");
if (targetClass) {
if (classReferences[i].selectorType == kSelectorMethod) {
if (targetClass->getMethodCount() < selectorOffset + 1)
error("The %s class has less than %d methods (%d)",
classReferences[i].className, selectorOffset + 1,
targetClass->getMethodCount());

// The open selector is always the second function
int openSelectorPos = sysWindowClass->getFuncSelector(1);
targetSelectorPos = targetClass->getFuncSelector(selectorOffset);
} else {
// Add the global selectors to the selector ID
selectorOffset += (getSciVersion() <= SCI_VERSION_1_LATE) ? 3 : 8;

if (names.size() < (uint32)openSelectorPos + 1)
names.resize((uint32)openSelectorPos + 1);
if (targetClass->getVarCount() < selectorOffset + 1)
error("The %s class has less than %d variables (%d)",
classReferences[i].className, selectorOffset + 1,
targetClass->getVarCount());

names[openSelectorPos] = "open";
targetSelectorPos = targetClass->getVarSelector(selectorOffset);
}

_segMan->uninstantiateScript(981);
} // if (_resMan->testResource(ResourceId(kResourceTypeScript, 981)))

if (g_sci->getGameId() == GID_HOYLE4) {
// The demo of Hoyle 4 is one of the few demos with lip syncing and no selector vocabulary.
// This needs two selectors, "syncTime" and "syncCue", which keep changing positions in each
// game. Usually, games with speech and lip sync have a selector vocabulary, so we don't need
// to set these two selectors, but we need for Hoyle...
if (names.size() < 276)
names.resize(276);

names[274] = "syncTime";
names[275] = "syncCue";
} else if (g_sci->getGameId() == GID_PEPPER) {
// Same as above for the non-interactive demo of Pepper
if (names.size() < 539)
names.resize(539);

names[263] = "syncTime";
names[264] = "syncCue";
names[538] = "startText";
} else if (g_sci->getGameId() == GID_LAURABOW2) {
// The floppy of version needs the changeState selector set to match up with the
// CD version's workarounds.
if (names.size() < 251)
names.resize(251);

names[144] = "changeState";
} else if (g_sci->getGameId() == GID_CNICK_KQ) {
if (names.size() < 447)
names.resize(447);

names[446] = "say";
}
if (selectorNames.size() < (uint32)targetSelectorPos + 1)
selectorNames.resize((uint32)targetSelectorPos + 1);

#ifdef ENABLE_SCI32
} else {
// SCI2+
for (int i = 0; i < count; i++)
names[i] = sci2Selectors[i];
#endif
}

for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) {
if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) {
const uint32 slot = selectorRemap->slot;
if (slot >= names.size())
names.resize(slot + 1);
names[slot] = selectorRemap->name;
selectorNames[targetSelectorPos] = classReferences[i].selectorName;
}
}

return names;
// Reset the segment manager
_segMan->resetSegMan();
}

} // End of namespace Sci

0 comments on commit 0bc9db7

Please sign in to comment.
You can’t perform that action at this time.