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:
parent
582eb13fa2
commit
00f4794c0a
22 changed files with 592 additions and 853 deletions
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue