SCI: Stage 1 of the game detection overhaul. The end goal is to autodetect

as much as possible. All SCI_VERSION_* information was removed from
detection.cpp (much of it was incorrect anyway).

svn-id: r43449
This commit is contained in:
Walter van Niftrik 2009-08-16 19:18:19 +00:00
parent 582eb13fa2
commit 00f4794c0a
22 changed files with 592 additions and 853 deletions

File diff suppressed because it is too large Load diff

View file

@ -179,7 +179,7 @@ static void _free_graphics_input(EngineState *s) {
}
int game_init_sound(EngineState *s, int sound_flags) {
if (s->resmgr->sciVersion() >= SCI_VERSION_01)
if (s->resmgr->sciVersion() > SCI_VERSION_0_LATE)
sound_flags |= SFX_STATE_FLAG_MULTIPLAY;
s->sfx_init_flags = sound_flags;

View file

@ -382,6 +382,8 @@ Kernel::~Kernel() {
}
void Kernel::detectSciFeatures() {
// FIXME Much of this is unreliable
Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0);
Common::StringList staticSelectorTable;
@ -396,9 +398,15 @@ void Kernel::detectSciFeatures() {
features = 0;
// Initialize features based on SCI version
if (_resmgr->sciVersion() == SCI_VERSION_0) {
switch (_resmgr->sciVersion()) {
case SCI_VERSION_0_EARLY:
features |= kFeatureOldScriptHeader;
/* Fallthrough */
case SCI_VERSION_0_LATE:
features |= kFeatureOldGfxFunctions;
break;
default:
break;
}
for (int i = 0; i < count; i++) {
@ -413,18 +421,12 @@ void Kernel::detectSciFeatures() {
tmp = staticSelectorTable[i];
}
if (tmp == "setTarget") // "motionInited" can also be used
features &= ~kFeatureOldScriptHeader;
if (tmp == "motionCue")
features &= ~kFeatureOldGfxFunctions;
if (tmp == "egoMoveSpeed" && _resmgr->sciVersion() < SCI_VERSION_1_1)
features |= kFeatureLofsAbsolute;
if (tmp == "sightAngle" && _resmgr->sciVersion() == SCI_VERSION_0)
features |= kFeatureSci0Sci1Table;
if (tmp == "setVol")
features |= kFeatureSci1Sound;
@ -437,12 +439,6 @@ void Kernel::detectSciFeatures() {
printf("Kernel auto-detected features:\n");
printf("Script block headers: ");
if (features & kFeatureOldScriptHeader)
printf("old\n");
else
printf("new\n");
printf("Graphics functions: ");
if (features & kFeatureOldGfxFunctions)
printf("old\n");
@ -462,9 +458,6 @@ void Kernel::detectSciFeatures() {
printf("SCI01\n");
else
printf("SCI0\n");
if (features & kFeatureSci0Sci1Table)
printf("Found SCI0 game using a SCI1 kernel table\n");
}
void Kernel::loadSelectorNames() {
@ -642,15 +635,6 @@ void Kernel::mapFunctions() {
int mapped = 0;
int ignored = 0;
uint functions_nr = getKernelNamesSize();
uint max_functions_nr = (_resmgr->sciVersion() == SCI_VERSION_0) ? 0x72 : 0x7b;
if (functions_nr < max_functions_nr) {
warning("SCI version believed to have %d kernel"
" functions, but only %d reported-- filling up remaining %d",
max_functions_nr, functions_nr, max_functions_nr - functions_nr);
functions_nr = max_functions_nr;
}
_kernelFuncs.resize(functions_nr);
@ -833,15 +817,9 @@ reg_t *kernel_dereference_reg_pointer(EngineState *s, reg_t pointer, int entries
}
void Kernel::setDefaultKernelNames() {
bool isSci0 = (_resmgr->sciVersion() == SCI_VERSION_0);
bool isSci0 = (_resmgr->sciVersion() <= SCI_VERSION_0_LATE);
int offset = 0;
// Check if we have a SCI01 game which uses a SCI1 kernel table (e.g. the KQ1 demo
// and full version). We do this by checking if the sightAngle selector exists, as no
// SCI0 game seems to have it
if (features & kFeatureSci0Sci1Table)
isSci0 = false;
_kernelNames.resize(SCI_KNAMES_DEFAULT_ENTRIES_NR + (isSci0 ? 4 : 0));
for (int i = 0; i < SCI_KNAMES_DEFAULT_ENTRIES_NR; i++) {
// In SCI0, Platform was DoAvoider
@ -897,23 +875,7 @@ static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &name
bool Kernel::loadKernelNames() {
_kernelNames.clear();
switch (_resmgr->sciVersion()) {
case SCI_VERSION_0:
case SCI_VERSION_01:
case SCI_VERSION_1:
case SCI_VERSION_1_1:
setDefaultKernelNames();
break;
#ifdef ENABLE_SCI32
case SCI_VERSION_32:
vocab_get_knames11(_resmgr, _kernelNames);
#endif
break;
default:
break;
}
setDefaultKernelNames();
return true;
}

View file

@ -60,8 +60,7 @@ enum AutoDetectedFeatures {
kFeatureOldGfxFunctions = 1 << 1,
kFeatureLofsAbsolute = 1 << 2,
kFeatureSci01Sound = 1 << 3,
kFeatureSci1Sound = 1 << 4,
kFeatureSci0Sci1Table = 1 << 5
kFeatureSci1Sound = 1 << 4
};
class Kernel {

View file

@ -40,7 +40,7 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t obj = argv[1];
sci_event_t e;
int oldx, oldy;
int modifier_mask = s->_version <= SCI_VERSION_0 ? SCI_EVM_ALL : SCI_EVM_NO_FOOLOCK;
int modifier_mask = s->_version <= SCI_VERSION_01 ? SCI_EVM_ALL : SCI_EVM_NO_FOOLOCK;
// If there's a simkey pending, and the game wants a keyboard event, use the
// simkey instead of a normal event

View file

@ -304,9 +304,9 @@ static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int
reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
switch (argc) {
case 1 :
if (s->_version < SCI_VERSION_1) {
if (s->_version < SCI_VERSION_1_LATE) {
GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, argv[0].toSint16()));
} else if (s->_version == SCI_VERSION_1) {
} else if (s->_version < SCI_VERSION_1_1) {
if (argv[0].toSint16() <= 1) {
// Newer (SCI1.1) semantics: show/hide cursor
CursorMan.showMouse(argv[0].toSint16() != 0);
@ -314,16 +314,16 @@ reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
// Pre-SCI1.1: set cursor according to the first parameter
GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, argv[0].toSint16()));
}
} else if (s->_version >= SCI_VERSION_1_1) {
} else {
// SCI1.1: Show/hide cursor
CursorMan.showMouse(argv[0].toSint16() != 0);
}
break;
case 2 :
if (s->_version < SCI_VERSION_1) {
if (s->_version < SCI_VERSION_1_LATE) {
GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state,
argv[1].toSint16() == 0 ? GFXOP_NO_POINTER : argv[0].toSint16()));
} else if (s->_version == SCI_VERSION_1) {
} else if (s->_version < SCI_VERSION_1_1) {
// Pre-SCI1.1: set cursor according to the first parameter, and toggle its
// visibility based on the second parameter
// Some late SCI1 games actually use the SCI1.1 version of this call (EcoQuest 1
@ -342,7 +342,7 @@ reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state,
Common::Point(argv[0].toUint16(), argv[1].toUint16())));
}
} else if (s->_version >= SCI_VERSION_1_1) {
} else {
// SCI1.1 and newer: set pointer position
GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state,
Common::Point(argv[0].toUint16(), argv[1].toUint16())));

View file

@ -274,7 +274,7 @@ static void bresenham_autodetect(EngineState *s) {
}
buf = s->seg_manager->getScript(fptr.segment)->buf + fptr.offset;
handle_movecnt = (s->_version <= SCI_VERSION_0 || checksum_bytes(buf, 8) == 0x216) ? INCREMENT_MOVECNT : IGNORE_MOVECNT;
handle_movecnt = (s->_version <= SCI_VERSION_01 || checksum_bytes(buf, 8) == 0x216) ? INCREMENT_MOVECNT : IGNORE_MOVECNT;
printf("b-moveCnt action based on checksum: %s\n", handle_movecnt == IGNORE_MOVECNT ? "ignore" : "increment");
} else {
warning("bresenham_autodetect failed");
@ -293,7 +293,7 @@ reg_t kDoBresen(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int completed = 0;
int max_movcnt = GET_SEL32V(client, moveSpeed);
if (s->_version > SCI_VERSION_0)
if (s->_version > SCI_VERSION_01)
signal &= ~_K_VIEW_SIG_FLAG_HIT_OBSTACLE;
if (handle_movecnt == UNINITIALIZED)
@ -380,7 +380,7 @@ reg_t kDoBresen(EngineState *s, int funct_nr, int argc, reg_t *argv) {
completed = 1;
}
if (s->_version > SCI_VERSION_0)
if (s->_version > SCI_VERSION_01)
if (completed)
invoke_selector(INV_SEL(mover, moveDone, kStopOnInvalidSelector), 0);

View file

@ -157,9 +157,9 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
SongHandle handle;
int cue;
if (s->_version >= SCI_VERSION_01)
if (s->_version > SCI_VERSION_01)
return;
/* SCI01 and later explicitly poll for everything */
/* SCI1 and later explicitly poll for everything */
while ((result = s->_sound.sfx_poll(&handle, &cue))) {
reg_t obj = DEFROBNICATE_HANDLE(handle);

View file

@ -693,7 +693,13 @@ int _reset_graphics_input(EngineState *s);
static void reconstruct_sounds(EngineState *s) {
Song *seeker;
SongIteratorType it_type = s->resmgr->sciVersion() >= SCI_VERSION_01 ? SCI_SONG_ITERATOR_TYPE_SCI1 : SCI_SONG_ITERATOR_TYPE_SCI0;
SongIteratorType it_type;
if (((SciEngine *)g_engine)->getKernel()->usesSci01SoundFunctions()
|| ((SciEngine *)g_engine)->getKernel()->usesSci1SoundFunctions())
it_type = SCI_SONG_ITERATOR_TYPE_SCI1;
else
it_type = SCI_SONG_ITERATOR_TYPE_SCI0;
seeker = s->_sound._songlib._lib;

View file

@ -88,18 +88,11 @@ opcode_format g_opcode_formats[128][4] = {
};
#undef END
void script_adjust_opcode_formats(int res_version) {
switch (res_version) {
case SCI_VERSION_0:
break;
case SCI_VERSION_01:
case SCI_VERSION_1:
case SCI_VERSION_1_1:
void script_adjust_opcode_formats(SciVersion version) {
// TODO: Check that this is correct
if ((version >= SCI_VERSION_1_1) || ((SciEngine*)g_engine)->getKernel()->hasLofsAbsolute()) {
g_opcode_formats[op_lofsa][0] = Script_Offset;
g_opcode_formats[op_lofss][0] = Script_Offset;
break;
default:
error("script_adjust_opcode_formats(): Unknown script version %d\n", res_version);
}
}

View file

@ -202,7 +202,7 @@ enum sci_opcodes { /* FIXME */
extern opcode_format g_opcode_formats[128][4];
void script_adjust_opcode_formats(int res_version);
void script_adjust_opcode_formats(SciVersion version);
void script_free_breakpoints(EngineState *s);

View file

@ -129,7 +129,7 @@ public:
SpeedThrottler(SciVersion version) {
if (version >= SCI_VERSION_1_1)
_maxInstructions = 3300;
else if (version >= SCI_VERSION_1)
else if (version >= SCI_VERSION_1_EARLY)
_maxInstructions = 2200;
else
_maxInstructions = 1100;

View file

@ -260,7 +260,6 @@ Common::String readSciVersionFromExe(Common::SeekableReadStream *exeStream, Comm
// String-encoded result, copied from buffer
char currentString[10];
Common::String resultString;
for (int i = 0; i < len; i++) {
unsigned char ch = *buf++;
@ -275,15 +274,8 @@ Common::String readSciVersionFromExe(Common::SeekableReadStream *exeStream, Comm
// Terminate string
currentString[9] = 0;
// Return the current string if it's parseable
SciVersion version;
if (getSciVersionFromString(currentString, &version, platform)) {
delete[] buffer;
return currentString;
}
// Save the found string and continue searching
resultString = currentString;
// Return the current string
return currentString;
}
if (accept)
@ -293,57 +285,7 @@ Common::String readSciVersionFromExe(Common::SeekableReadStream *exeStream, Comm
}
delete[] buffer;
return resultString;
}
bool getSciVersionFromString(Common::String versionString, SciVersion *version, Common::Platform platform) {
*version = SCI_VERSION_AUTODETECT;
if (platform == Common::kPlatformAmiga) {
if (versionString.hasPrefix("1.002.")) {
*version = SCI_VERSION_0;
} else if (versionString.hasPrefix("1.003.")) {
*version = SCI_VERSION_01;
} else if (versionString.hasPrefix("1.004.")) {
*version = SCI_VERSION_01;
} else if (versionString.hasPrefix("1.005.")) {
*version = SCI_VERSION_1;
} else if (versionString == "x.yyy.zzz") {
// How to map it?
} else {
return false;
}
} else if (versionString.hasPrefix("0.000.")) {
*version = SCI_VERSION_0;
} else if (versionString.hasPrefix("S.old.")) {
*version = SCI_VERSION_01;
} else if (versionString.hasPrefix("1.000.")) {
*version = SCI_VERSION_1;
} else if (versionString.hasPrefix("1.001.")) {
*version = SCI_VERSION_1_1;
} else if (versionString.hasPrefix("2.000.")
|| versionString.hasPrefix("2.100.")
|| versionString.hasPrefix("3.000.")) {
*version = SCI_VERSION_32;
} else if (versionString.hasPrefix("1.ECO.")
|| versionString.hasPrefix("1.SQ1.")
|| versionString.hasPrefix("1.SQ4.")
|| versionString.hasPrefix("1.LS5.")
|| versionString.hasPrefix("1.pq3.")
|| versionString.hasPrefix("FAIRY.")
|| versionString.hasPrefix("T.A00.")) {
*version = SCI_VERSION_1;
} else if (versionString.hasPrefix("L.rry.")
|| versionString.hasPrefix("l.cfs.")) {
*version = SCI_VERSION_1_1;
} else if (versionString == "x.yyy.zzz") {
// How to map it?
} else {
// Unknown or not a version number
return false;
}
return true;
return "unknown";
}
} // End of namespace Sci

View file

@ -33,7 +33,6 @@ namespace Sci {
Common::Platform getGameExePlatform(Common::SeekableReadStream *exeStream);
Common::String readSciVersionFromExe(Common::SeekableReadStream *exeStream, Common::Platform platform);
bool getSciVersionFromString(Common::String versionString, SciVersion *version, Common::Platform platform);
} // End of namespace Sci

View file

@ -57,11 +57,6 @@ GfxResManager::GfxResManager(gfx_options_t *options, GfxDriver *driver, Resource
_portBounds = Common::Rect(0, 10, 320, 200); // default value, with a titlebar of 10px
_version = resManager->sciVersion();
// Workaround for QFG1 VGA (has SCI 1.1 view data with SCI 1 compression)
if (_version == SCI_VERSION_1 && !strcmp(((SciEngine*)g_engine)->getGameID(), "qfg1")) {
_version = SCI_VERSION_1_1;
}
if (!_resManager->isVGA()) {
_staticPalette = gfx_sci0_pic_colors->getref();
} else if (_version == SCI_VERSION_1_1) {
@ -537,7 +532,8 @@ gfxr_view_t *GfxResManager::getView(int nr, int *loop, int *cel, int palette) {
int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr);
if (!_resManager->isVGA()) {
int pal = (_version == SCI_VERSION_0) ? -1 : palette;
// TODO: Check which versions this applies to
int pal = (_version < SCI_VERSION_1_EARLY) ? -1 : palette;
view = getEGAView(resid, viewRes->data, viewRes->size, pal);
} else {
if (_version < SCI_VERSION_1_1)
@ -679,7 +675,7 @@ gfx_pixmap_t *GfxResManager::getCursor(int num) {
}
gfx_pixmap_t *cursor = gfxr_draw_cursor(GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, num),
cursorRes->data, cursorRes->size, _version != SCI_VERSION_0);
cursorRes->data, cursorRes->size, _version > SCI_VERSION_01);
if (!cursor)
return NULL;

View file

@ -231,15 +231,6 @@ public:
int calculatePic(gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic,
int flags, int default_palette, int nr);
/**
* Determines whether support for pointers with more than two colors
* is required.
*
* @return false if no support for multi-colored pointers is required,
* true otherwise
*/
bool multicoloredPointers() { return _version > SCI_VERSION_1; }
/**
* Frees all resources currently allocated.

View file

@ -319,63 +319,6 @@ int sci0_get_compression_method(Common::ReadStream &stream) {
return compressionMethod;
}
SciVersion ResourceManager::guessSciVersion() {
Common::File file;
char filename[MAXPATHLEN];
int compression;
Resource *res;
int i;
for (i = 0; i < 1000; i++) {
res = testResource(ResourceId(kResourceTypeView, i));
if (!res)
continue;
if (res->source->source_type == kSourceDirectory)
continue;
strcpy(filename, res->source->location_name.c_str());
if (!file.open(filename))
continue;
file.seek(res->file_offset, SEEK_SET);
compression = sci0_get_compression_method(file);
file.close();
if (compression == 3) {
return SCI_VERSION_01;
}
}
// Try the same thing with pics
for (i = 0; i < 1000; i++) {
res = testResource(ResourceId(kResourceTypePic, i));
if (!res)
continue;
if (res->source->source_type == kSourceDirectory)
continue;
strcpy(filename, res->source->location_name.c_str());
if (!file.open(filename))
continue;
file.seek(res->file_offset, SEEK_SET);
compression = sci0_get_compression_method(file);
file.close();
if (compression == 3) {
return SCI_VERSION_01;
}
}
return SCI_VERSION_AUTODETECT;
}
int ResourceManager::addAppropriateSources() {
ResourceSource *map;
@ -484,91 +427,23 @@ ResourceManager::ResourceManager(int maxMemory) {
addInternalSources();
scanNewSources();
switch (_mapVersion) {
case kResVersionSci0Sci1Early:
if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB))) {
_sciVersion = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0;
} else if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB))) {
_sciVersion = guessSciVersion();
if (_sciVersion != SCI_VERSION_01) {
_sciVersion = testResource(ResourceId(kResourceTypeVocab, 912)) ? SCI_VERSION_0 : SCI_VERSION_01;
}
} else {
_sciVersion = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0;
}
break;
case kResVersionSci1Middle:
_sciVersion = SCI_VERSION_01;
break;
case kResVersionSci1Late:
_sciVersion = SCI_VERSION_1;
break;
case kResVersionSci11:
_sciVersion = SCI_VERSION_1_1;
break;
case kResVersionSci32:
_sciVersion = SCI_VERSION_32;
break;
default:
_sciVersion = SCI_VERSION_AUTODETECT;
}
_sciVersion = detectSciVersion();
_isVGA = false;
// Determine if the game is using EGA graphics or not
if (_sciVersion == SCI_VERSION_0) {
_isVGA = false; // There is no SCI0 VGA game
} else if (_sciVersion >= SCI_VERSION_1_1) {
_isVGA = true; // There is no SCI11 EGA game
} else {
// SCI01 or SCI1: EGA games have the second byte of their views set
// to 0, VGA ones to non-zero
int i = 0;
while (true) {
Resource *res = findResource(ResourceId(kResourceTypeView, i), 0);
if (res) {
_isVGA = (res->data[1] != 0);
break;
}
i++;
}
}
// Workaround for QFG1 VGA (has SCI 1.1 view data with SCI 1 compression)
if (_sciVersion == SCI_VERSION_1 && !strcmp(((SciEngine*)g_engine)->getGameID(), "qfg1")) {
debug("Resmgr: Detected QFG1 VGA");
_isVGA = true;
}
// temporary version printout - should be reworked later
switch (_sciVersion) {
case SCI_VERSION_0:
debug("Resmgr: Detected SCI0");
break;
case SCI_VERSION_01:
debug("Resmgr: Detected SCI01");
break;
case SCI_VERSION_1:
debug("Resmgr: Detected SCI1");
break;
case SCI_VERSION_1_1:
debug("Resmgr: Detected SCI1.1");
break;
#ifdef ENABLE_SCI32
case SCI_VERSION_32:
debug("Resmgr: Couldn't determine SCI version");
break;
#endif
default:
debug("Resmgr: Couldn't determine SCI version");
break;
}
if (_isVGA)
debug("Resmgr: Detected VGA graphic resources");
if (_sciVersion != SCI_VERSION_AUTODETECT)
debug("Resmgr: Detected %s", versionNames[_sciVersion]);
else
debug("Resmgr: Detected non-VGA/EGA graphic resources");
debug("Resmgr: Couldn't determine SCI version");
switch (_viewType) {
case kViewEga:
debug("Resmgr: Detected EGA graphic resources");
break;
case kViewVga:
debug("Resmgr: Detected VGA graphic resources");
break;
case kViewVga11:
debug("Resmgr: Detected SCI1.1 VGA graphic resources");
}
}
ResourceManager::~ResourceManager() {
@ -1408,10 +1283,10 @@ int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
compression = kCompNone;
break;
case 1:
compression = (_sciVersion == SCI_VERSION_0) ? kCompLZW : kCompHuffman;
compression = (_sciVersion <= SCI_VERSION_01) ? kCompLZW : kCompHuffman;
break;
case 2:
compression = (_sciVersion == SCI_VERSION_0) ? kCompHuffman : kCompLZW1;
compression = (_sciVersion <= SCI_VERSION_01) ? kCompHuffman : kCompLZW1;
break;
case 3:
compression = kCompLZW1View;
@ -1483,4 +1358,239 @@ int ResourceManager::decompress(Resource *res, Common::File *file) {
return error;
}
ResourceCompression ResourceManager::getViewCompression() {
int viewsTested = 0;
// Test 10 views to see if any are compressed
for (int i = 0; i < 1000; i++) {
Common::File *file;
Resource *res = testResource(ResourceId(kResourceTypeView, i));
if (!res)
continue;
if (res->source->source_type != kSourceVolume)
continue;
file = getVolumeFile(res->source->location_name.c_str());
if (!file)
continue;
file->seek(res->file_offset, SEEK_SET);
uint32 szPacked;
ResourceCompression compression;
if (readResourceInfo(res, file, szPacked, compression))
continue;
if (compression != kCompNone)
return compression;
if (++viewsTested == 10)
break;
}
return kCompNone;
}
ResourceManager::ViewType ResourceManager::detectViewType() {
for (int i = 0; i < 1000; i++) {
Resource *res = findResource(ResourceId(kResourceTypeView, i), 0);
if (res) {
//FIXME: Amiga
switch(res->data[1]) {
case 0:
return kViewEga;
default:
return kViewVga;
}
}
}
warning("Resmgr: Couldn't find any views");
return kViewVga;
}
SciVersion ResourceManager::detectSciVersion() {
// We use the view compression to set a preliminary _sciVersion for the sake of getResourceInfo
// Pretend we have a SCI0 game
_sciVersion = SCI_VERSION_0_EARLY;
bool oldDecompressors = true;
ResourceCompression viewCompression = getViewCompression();
if (viewCompression != kCompLZW) {
// If it's a different compression type from kCompLZW, the game is probably
// SCI_VERSION_1_EGA or later. If the views are uncompressed, it is
// likely not an early disk game.
_sciVersion = SCI_VERSION_1_EGA;
oldDecompressors = false;
}
// Set view type
if (viewCompression == kCompDCL) {
// SCI1.1 VGA views
_viewType = kViewVga11;
} else {
// Otherwise we detect it from a view
_viewType = detectViewType();
}
switch (_mapVersion) {
case kResVersionSci0Sci1Early:
if (_viewType == kViewVga) {
// VGA
return SCI_VERSION_1_EARLY;
}
// EGA
if (hasOldScriptHeader())
return SCI_VERSION_0_EARLY;
if (oldDecompressors) {
// It's either SCI_VERSION_0_LATE or SCI_VERSION_01
// We first check for SCI1 vocab.999
if (testResource(ResourceId(kResourceTypeVocab, 999))) {
if (hasSci0Voc999()) {
return SCI_VERSION_0_LATE;
} else {
return SCI_VERSION_01;
}
}
// If vocab.999 is missing, we try vocab.900
if (testResource(ResourceId(kResourceTypeVocab, 900))) {
if (hasSci1Voc900()) {
return SCI_VERSION_01;
} else {
return SCI_VERSION_0_LATE;
}
}
warning("Failed to accurately determine SCI version");
// No parser, we assume SCI_VERSION_01.
return SCI_VERSION_01;
}
// New decompressors. It's either SCI_VERSION_1_EGA or SCI_VERSION_1_EARLY.
if (hasSci1Voc900())
return SCI_VERSION_1_EGA;
// SCI_VERSION_1_EARLY EGA versions seem to be lacking a valid vocab.900.
// If this turns out to be unreliable, we could do some pic resource checks instead.
return SCI_VERSION_1_EARLY;
case kResVersionSci1Middle:
return SCI_VERSION_1_LATE;
case kResVersionSci1Late:
if (_viewType == kViewVga11) {
// SCI1.1 resources, assume SCI1.1
return SCI_VERSION_1_1;
}
return SCI_VERSION_1_LATE;
case kResVersionSci11:
return SCI_VERSION_1_1;
case kResVersionSci32:
return SCI_VERSION_32;
default:
return SCI_VERSION_AUTODETECT;
}
}
// Functions below are based on PD code by Brian Provinciano (SCI Studio)
bool ResourceManager::hasOldScriptHeader() {
Resource *res = findResource(ResourceId(kResourceTypeScript, 0), 0);
if (!res) {
warning("Resmgr: Failed to find script.000");
return false;
}
uint offset = 2;
const int objTypes = 17;
while (offset < res->size) {
uint16 objType = READ_LE_UINT16(res->data + offset);
if (!objType) {
offset += 2;
// We should be at the end of the resource now
return offset == res->size;
}
if (objType >= objTypes) {
// Invalid objType
return false;
}
int skip = READ_LE_UINT16(res->data + offset + 2);
if (skip < 2) {
// Invalid size
return false;
}
offset += skip;
}
return false; }
bool ResourceManager::hasSci0Voc999() {
Resource *res = findResource(ResourceId(kResourceTypeVocab, 999), 0);
if (!res) {
// No vocab present, possibly a demo version
return false;
}
if (res->size < 2)
return false;
uint16 count = READ_LE_UINT16(res->data);
// Make sure there's enough room for the pointers
if (res->size < (uint)count * 2)
return false;
// Iterate over all pointers
for (uint i = 0; i < count; i++) {
// Offset to string
uint16 offset = READ_LE_UINT16(res->data + 2 + count * 2);
// Look for end of string
do {
if (offset >= res->size) {
// Out of bounds
return false;
}
} while (res->data[offset++]);
}
return true;
}
bool ResourceManager::hasSci1Voc900() {
Resource *res = findResource(ResourceId(kResourceTypeVocab, 900), 0);
if (!res )
return false;
if (res->size < 0x1fe)
return false;
uint16 offset = 0x1fe;
while (offset < res->size) {
offset++;
do {
if (offset >= res->size) {
// Out of bounds;
return false;
}
} while (res->data[offset++]);
offset += 3;
}
return offset == res->size;
}
} // End of namespace Sci

View file

@ -47,12 +47,15 @@ namespace Sci {
/** SCI versions */
enum SciVersion {
SCI_VERSION_AUTODETECT = 0,
SCI_VERSION_0 = 1,
SCI_VERSION_01 = 2,
SCI_VERSION_1 = 3,
SCI_VERSION_1_1 = 4,
SCI_VERSION_32 = 5
SCI_VERSION_AUTODETECT,
SCI_VERSION_0_EARLY, // Early KQ4, 1988 xmas card
SCI_VERSION_0_LATE, // KQ4, LSL2, LSL3, SQ3 etc
SCI_VERSION_01, // KQ1 and multilingual games (S.old.*)
SCI_VERSION_1_EGA, // EGA with parser, QFG2
SCI_VERSION_1_EARLY, // KQ5, LSL1. (EGA/VGA)
SCI_VERSION_1_LATE, // ECO1, LSL5. (EGA/VGA)
SCI_VERSION_1_1, // KQ6, ECO2
SCI_VERSION_32 // GK
};
/** Resource status types */
@ -225,7 +228,14 @@ public:
kResVersionSci32
};
bool isVGA() const { return _isVGA; }
// TODO: Amiga
enum ViewType {
kViewEga,
kViewVga,
kViewVga11
};
bool isVGA() const { return (_viewType == kViewVga) || (_viewType == kViewVga11); }
/**
* Returns the SCI version as detected by the resource manager
@ -284,7 +294,7 @@ public:
void setAudioLanguage(int language);
protected:
bool _isVGA; // Used to determine if the game has EGA or VGA graphics
ViewType _viewType; // Used to determine if the game has EGA or VGA graphics
int _maxMemory; //!< Config option: Maximum total byte number allocated
Common::List<ResourceSource *> _sources;
int _memoryLocked; //!< Amount of resource bytes in locked memory
@ -403,7 +413,12 @@ protected:
void addToLRU(Resource *res);
void removeFromLRU(Resource *res);
SciVersion guessSciVersion();
ResourceCompression getViewCompression();
ViewType detectViewType();
bool hasOldScriptHeader();
bool hasSci0Voc999();
bool hasSci1Voc900();
SciVersion detectSciVersion();
};
} // End of namespace Sci

View file

@ -43,11 +43,15 @@ namespace Sci {
class GfxDriver;
const char *versionNames[6] = {
"Autodetected",
"SCI0",
// FIXME: error-prone
const char *versionNames[9] = {
"Autodetect",
"SCI0 Early",
"SCI0 Late",
"SCI01",
"SCI1",
"SCI1 EGA",
"SCI1 Early",
"SCI1 Late",
"SCI1.1",
"SCI32"
};
@ -128,51 +132,25 @@ Common::Error SciEngine::run() {
// FIXME/TODO: Move some of the stuff below to init()
SciVersion version = getVersion();
const uint32 flags = getFlags();
_resmgr = new ResourceManager(256 * 1024);
_version = _resmgr->sciVersion();
if (!_resmgr) {
printf("No resources found, aborting...\n");
return Common::kNoGameDataFoundError;
}
// When version is set to autodetect, use version as determined by resource manager
if (version == SCI_VERSION_AUTODETECT)
version = _resmgr->sciVersion();
_kernel = new Kernel(_resmgr);
_vocabulary = new Vocabulary(_resmgr);
script_adjust_opcode_formats(_resmgr->sciVersion());
script_adjust_opcode_formats(_version);
#if 0
printf("Mapping instruments to General Midi\n");
map_MIDI_instruments(_resmgr);
#endif
_gamestate = new EngineState(_resmgr, version, flags);
// Verify that we haven't got an invalid game detection entry
if (version < SCI_VERSION_1) {
// SCI0/SCI01
} else if (version == SCI_VERSION_1) {
if (flags & GF_SCI0_OLDGETTIME) {
error("This game entry is erroneous. It's marked as SCI1, but it has SCI0 flags set");
}
} else if (version == SCI_VERSION_1_1 || version == SCI_VERSION_32) {
if (flags & GF_SCI0_OLDGETTIME) {
error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI0 flags set");
}
} else {
error ("Unknown SCI version in game entry");
}
_gamestate = new EngineState(_resmgr, _version, flags);
if (script_init_engine(_gamestate))
return Common::kUnknownError;
if (game_init(_gamestate)) { /* Initialize */
warning("Game initialization failed: Aborting...");
// TODO: Add an "init failed" error?
@ -226,7 +204,7 @@ Common::Error SciEngine::run() {
return Common::kUnknownError;
}
printf("Emulating SCI version %s\n", versionNames[version]);
printf("Emulating SCI version %s\n", versionNames[_version]);
game_run(&_gamestate); // Run the game
@ -265,7 +243,7 @@ const char* SciEngine::getGameID() const {
}
SciVersion SciEngine::getVersion() const {
return _gameDescription->version;
return _version;
}
Common::Language SciEngine::getLanguage() const {

View file

@ -66,10 +66,9 @@ enum kDebugLevels {
struct SciGameDescription {
ADGameDescription desc;
uint32 flags;
SciVersion version;
};
extern const char *versionNames[6];
extern const char *versionNames[];
enum SciGameFlags {
// SCI0 flags
@ -113,6 +112,7 @@ public:
private:
const SciGameDescription *_gameDescription;
SciVersion _version;
ResourceManager *_resmgr;
EngineState *_gamestate;
Kernel *_kernel;

View file

@ -641,7 +641,7 @@ int MidiPlayer_Adlib::open(ResourceManager *resmgr) {
static_cast<MidiDriver_Adlib *>(_driver)->loadResource(res);
return static_cast<MidiDriver_Adlib *>(_driver)->open(resmgr->sciVersion() == SCI_VERSION_0);
return static_cast<MidiDriver_Adlib *>(_driver)->open(resmgr->sciVersion() <= SCI_VERSION_0_LATE);
}
} // End of namespace Sci

View file

@ -91,7 +91,7 @@ Vocabulary::Vocabulary(ResourceManager *resmgr) : _resmgr(resmgr) {
debug(2, "Initializing vocabulary");
if (_resmgr->sciVersion() <= SCI_VERSION_01 && loadParserWords()) {
if (_resmgr->sciVersion() <= SCI_VERSION_1_EGA && loadParserWords()) {
loadSuffixes();
if (loadBranches())
// Now build a GNF grammar out of this