diff options
author | Filippos Karapetis | 2009-08-18 10:01:18 +0000 |
---|---|---|
committer | Filippos Karapetis | 2009-08-18 10:01:18 +0000 |
commit | ca9bbce9b3e8771f346eca037bd0c39a7e0360de (patch) | |
tree | b48e0126781ab5e042bd144d2be1d109b14ec39b | |
parent | 65ac355efa2cb792278e34de5c397ab11c8a46e3 (diff) | |
download | scummvm-rg350-ca9bbce9b3e8771f346eca037bd0c39a7e0360de.tar.gz scummvm-rg350-ca9bbce9b3e8771f346eca037bd0c39a7e0360de.tar.bz2 scummvm-rg350-ca9bbce9b3e8771f346eca037bd0c39a7e0360de.zip |
- Added game ID detection to the fallback detector. We still need to map some of Sierra's internal IDs to our own ones
- The class table is now created in the segment manager constructor
svn-id: r43504
-rw-r--r-- | engines/sci/detection.cpp | 23 | ||||
-rw-r--r-- | engines/sci/engine/game.cpp | 151 | ||||
-rw-r--r-- | engines/sci/engine/savegame.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.cpp | 150 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.h | 5 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 10 | ||||
-rw-r--r-- | engines/sci/engine/vm.h | 2 |
7 files changed, 177 insertions, 166 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index d46dd2cbd8..c025523ca0 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -27,6 +27,7 @@ #include "base/plugins.h" #include "sci/sci.h" +#include "sci/engine/kernel.h" #include "sci/exereader.h" #include "sci/engine/seg_manager.h" @@ -3047,8 +3048,12 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl Common::String filename = file->getName(); filename.toLowercase(); - if (filename.contains("resource.map") || filename.contains("resmap.000")) + if (filename.contains("resource.map") || filename.contains("resmap.000")) { + // resource.map is located in the same directory as the other resource files, + // therefore add the directory here, so that the game files can be opened later on + Common::File::addDefaultDirectory(file->getParent().getPath()); foundResMap = true; + } if (filename.contains("resource.000") || filename.contains("resource.001") || filename.contains("ressci.000") || filename.contains("ressci.001")) @@ -3081,24 +3086,30 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl return 0; // Set some defaults - s_fallbackDesc.desc.gameid = "sci"; s_fallbackDesc.desc.extra = ""; s_fallbackDesc.desc.language = Common::UNK_LANG; s_fallbackDesc.desc.platform = exePlatform; s_fallbackDesc.desc.flags = ADGF_NO_FLAGS; -#if 0 // Determine the game id - // TODO ResourceManager *resMgr = new ResourceManager(); SciVersion version = resMgr->sciVersion(); - SegManager *segManager = new SegManager(resMgr, version); + Kernel *kernel = new Kernel(resMgr); + SegManager *segManager = new SegManager(resMgr, version, kernel->hasOldScriptHeader()); + if (!script_instantiate(resMgr, segManager, version, kernel->hasOldScriptHeader(), 0)) { + warning("fallbackDetect(): Could not instantiate script 0"); + return 0; + } reg_t game_obj = script_lookup_export(segManager, 0, 0); Common::String gameName = obj_get_name(segManager,version, game_obj); debug(2, " \"%s\" at %04x:%04x", gameName.c_str(), PRINT_REG(game_obj)); + gameName.toLowercase(); + // TODO: Sierra's game IDs are not always the same as our own ones, we need to map them + // accordingly here + s_fallbackDesc.desc.gameid = strdup(gameName.c_str()); + delete kernel; delete segManager; delete resMgr; -#endif printf("If this is *NOT* a fan-modified version (in particular, not a fan-made\n"); printf("translation), please, report the data above, including the following\n"); diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 6872039c89..c34ac1cf00 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -188,157 +188,10 @@ int game_init_sound(EngineState *s, int sound_flags) { return 0; } -int create_class_table_sci11(EngineState *s) { - int scriptnr; - unsigned int seeker_offset; - char *seeker_ptr; - int classnr; - - Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); - - if (!vocab996) - s->seg_manager->_classtable.resize(20); - else - s->seg_manager->_classtable.resize(vocab996->size >> 2); - - for (scriptnr = 0; scriptnr < 1000; scriptnr++) { - Resource *heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0); - - if (heap) { - int global_vars = READ_LE_UINT16(heap->data + 2); - - seeker_ptr = (char*)heap->data + 4 + global_vars * 2; - seeker_offset = 4 + global_vars * 2; - - while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) { - if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) { - classnr = READ_LE_UINT16((byte*)seeker_ptr + 10); - if (classnr >= (int)s->seg_manager->_classtable.size()) { - if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { - warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", - classnr, scriptnr, scriptnr, seeker_offset); - return 1; - } - - s->seg_manager->_classtable.resize(classnr + 1); // Adjust maximum number of entries - } - - s->seg_manager->_classtable[classnr].reg.offset = seeker_offset; - s->seg_manager->_classtable[classnr].reg.segment = 0; - s->seg_manager->_classtable[classnr].script = scriptnr; - } - - seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; - seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; - } - } - } - - s->resmgr->unlockResource(vocab996); - vocab996 = NULL; - return 0; -} - -static int create_class_table_sci0(EngineState *s) { - int scriptnr; - unsigned int seeker; - int classnr; - int magic_offset; // For strange scripts in older SCI versions - - Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); - SciVersion version = s->_version; // for the offset defines - - if (!vocab996) - s->seg_manager->_classtable.resize(20); - else - s->seg_manager->_classtable.resize(vocab996->size >> 2); - - for (scriptnr = 0; scriptnr < 1000; scriptnr++) { - int objtype = 0; - Resource *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0); - - if (script) { - if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) - magic_offset = seeker = 2; - else - magic_offset = seeker = 0; - - do { - while (seeker < script->size) { - unsigned int lastseeker = seeker; - objtype = (int16)READ_LE_UINT16(script->data + seeker); - if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR) - break; - seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); - if (seeker <= lastseeker) { - s->seg_manager->_classtable.clear(); - error("Script version is invalid"); - } - } - - if (objtype == SCI_OBJ_CLASS) { - int sugg_script; - - seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes - - classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET); - if (classnr >= (int)s->seg_manager->_classtable.size()) { - - if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { - warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", - classnr, scriptnr, scriptnr, seeker); - return 1; - } - - s->seg_manager->_classtable.resize(classnr + 1); // Adjust maximum number of entries - } - - // Map the class ID to the script the corresponding class is contained in - // The script number is found in vocab.996, if it exists - if (!vocab996 || (uint32)classnr >= vocab996->size >> 2) - sugg_script = -1; - else - sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2)); - - // First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script - - if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/) { - // Now set the home script of the class - s->seg_manager->_classtable[classnr].reg.offset = seeker + 4 - magic_offset; - s->seg_manager->_classtable[classnr].reg.segment = 0; - s->seg_manager->_classtable[classnr].script = scriptnr; - } - - seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position - seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next - } - - } while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size); - - } - } - s->resmgr->unlockResource(vocab996); - vocab996 = NULL; - return 0; -} - // Architectural stuff: Init/Unintialize engine int script_init_engine(EngineState *s) { - int result; - s->kernel_opt_flags = 0; - s->seg_manager = new SegManager(s->resmgr, s->_version); - - if (s->_version >= SCI_VERSION_1_1) - result = create_class_table_sci11(s); - else - result = create_class_table_sci0(s); - - if (result) { - debug(2, "Failed to initialize class table"); - return 1; - } - + s->seg_manager = new SegManager(s->resmgr, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()); s->gc_countdown = GC_INTERVAL - 1; SegmentId script_000_segment = s->seg_manager->getSegment(0, SCRIPT_GET_LOCK); @@ -441,7 +294,7 @@ int game_init(EngineState *s) { s->stack_base = stack->entries; s->stack_top = s->stack_base + VM_STACK_SIZE; - if (!script_instantiate(s->resmgr, s->seg_manager, s->_version, 0)) { + if (!script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), 0)) { warning("game_init(): Could not instantiate script 0"); return 1; } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index b53e9d522c..0ddb5187ac 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -219,7 +219,7 @@ static void sync_SegManagerPtr(Common::Serializer &s, SegManager *&obj) { if (s.isLoading()) { // FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch. delete obj; - obj = new SegManager(resMgr, version); + obj = new SegManager(resMgr, version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()); } obj->saveLoadWithSerializer(s); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index f47a874528..a6f54c5bf7 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -52,7 +52,7 @@ namespace Sci { #define INVALID_SCRIPT_ID -1 -SegManager::SegManager(ResourceManager *resMgr, SciVersion version) { +SegManager::SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader) { id_seg_map = new IntMapper(); reserved_id = INVALID_SCRIPT_ID; id_seg_map->checkKey(reserved_id, true); // reserve entry 0 for INVALID_SCRIPT_ID @@ -68,6 +68,17 @@ SegManager::SegManager(ResourceManager *resMgr, SciVersion version) { exports_wide = 0; _version = version; _resMgr = resMgr; + _oldScriptHeader = oldScriptHeader; + + int result = 0; + + if (version >= SCI_VERSION_1_1) + result = createSci11ClassTable(); + else + result = createSci0ClassTable(); + + if (result) + error("SegManager: Failed to initialize class table"); } // Destroy the object, free the memorys if allocated before @@ -139,7 +150,7 @@ void SegManager::setScriptSize(Script &scr, int script_nr) { if (!script || (_version >= SCI_VERSION_1_1 && !heap)) { error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap"); } - if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) { + if (_oldScriptHeader) { scr.buf_size = script->size + READ_LE_UINT16(script->data) * 2; //locals_size = READ_LE_UINT16(script->data) * 2; } else if (_version < SCI_VERSION_1_1) { @@ -434,7 +445,7 @@ SegmentId SegManager::getSegment(int script_nr, SCRIPT_GET load) { SegmentId segment; if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD) - script_instantiate(_resMgr, this, _version, script_nr); + script_instantiate(_resMgr, this, _version, _oldScriptHeader, script_nr); segment = segGet(script_nr); @@ -906,5 +917,138 @@ int SegManager::freeDynmem(reg_t addr) { return 0; // OK } +int SegManager::createSci11ClassTable() { + int scriptnr; + unsigned int seeker_offset; + char *seeker_ptr; + int classnr; + + Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); + + if (!vocab996) + _classtable.resize(20); + else + _classtable.resize(vocab996->size >> 2); + + for (scriptnr = 0; scriptnr < 1000; scriptnr++) { + Resource *heap = _resMgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0); + + if (heap) { + int global_vars = READ_LE_UINT16(heap->data + 2); + + seeker_ptr = (char*)heap->data + 4 + global_vars * 2; + seeker_offset = 4 + global_vars * 2; + + while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) { + if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) { + classnr = READ_LE_UINT16((byte*)seeker_ptr + 10); + if (classnr >= (int)_classtable.size()) { + if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { + warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", + classnr, scriptnr, scriptnr, seeker_offset); + return 1; + } + + _classtable.resize(classnr + 1); // Adjust maximum number of entries + } + + _classtable[classnr].reg.offset = seeker_offset; + _classtable[classnr].reg.segment = 0; + _classtable[classnr].script = scriptnr; + } + + seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; + seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2; + } + } + } + + _resMgr->unlockResource(vocab996); + vocab996 = NULL; + return 0; +} + +int SegManager::createSci0ClassTable() { + int scriptnr; + unsigned int seeker; + int classnr; + int magic_offset; // For strange scripts in older SCI versions + + Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); + SciVersion version = _version; // for the offset defines + + if (!vocab996) + _classtable.resize(20); + else + _classtable.resize(vocab996->size >> 2); + + for (scriptnr = 0; scriptnr < 1000; scriptnr++) { + int objtype = 0; + Resource *script = _resMgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0); + + if (script) { + if (_oldScriptHeader) + magic_offset = seeker = 2; + else + magic_offset = seeker = 0; + + do { + while (seeker < script->size) { + unsigned int lastseeker = seeker; + objtype = (int16)READ_LE_UINT16(script->data + seeker); + if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR) + break; + seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); + if (seeker <= lastseeker) { + _classtable.clear(); + error("Script version is invalid"); + } + } + + if (objtype == SCI_OBJ_CLASS) { + int sugg_script; + + seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes + + classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET); + if (classnr >= (int)_classtable.size()) { + + if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) { + warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x", + classnr, scriptnr, scriptnr, seeker); + return 1; + } + + _classtable.resize(classnr + 1); // Adjust maximum number of entries + } + + // Map the class ID to the script the corresponding class is contained in + // The script number is found in vocab.996, if it exists + if (!vocab996 || (uint32)classnr >= vocab996->size >> 2) + sugg_script = -1; + else + sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2)); + + // First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script + + if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/) { + // Now set the home script of the class + _classtable[classnr].reg.offset = seeker + 4 - magic_offset; + _classtable[classnr].reg.segment = 0; + _classtable[classnr].script = scriptnr; + } + + seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position + seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next + } + + } while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size); + + } + } + _resMgr->unlockResource(vocab996); + vocab996 = NULL; + return 0; +} } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index f73c788b37..fcf2659df3 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -58,7 +58,7 @@ public: /** * Initialize the segment manager */ - SegManager(ResourceManager *resMgr, SciVersion version); + SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader); /** * Deallocate all memory associated with the segment manager @@ -342,6 +342,7 @@ public: private: IntMapper *id_seg_map; ///< id - script id; seg - index of heap + bool _oldScriptHeader; public: // TODO: make private Common::Array<MemObject *> _heap; int reserved_id; @@ -360,6 +361,8 @@ private: LocalVariables *allocLocalsSegment(Script *scr, int count); MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type); int deallocate(SegmentId seg, bool recursive); + int createSci0ClassTable(); + int createSci11ClassTable(); Hunk *alloc_Hunk(reg_t *); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index fbd3bc3baf..64ee7243fb 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -208,7 +208,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP Script *scr = s->seg_manager->getScriptIfLoaded(seg); if (!scr) // Script not present yet? - seg = script_instantiate(s->resmgr, s->seg_manager, s->_version, script); + seg = script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), script); else scr->unmarkDeleted(); @@ -1573,7 +1573,7 @@ int script_instantiate_common(ResourceManager *resMgr, SegManager *segManager, S return seg_id; } -int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr) { +int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) { int objtype; unsigned int objlength; reg_t reg; @@ -1593,7 +1593,7 @@ int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, Sci Script *scr = segManager->getScript(seg_id); - if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) { + if (oldScriptHeader) { // int locals_nr = READ_LE_UINT16(script->data); @@ -1761,11 +1761,11 @@ int script_instantiate_sci11(ResourceManager *resMgr, SegManager *segManager, Sc return seg_id; } -int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr) { +int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) { if (version >= SCI_VERSION_1_1) return script_instantiate_sci11(resMgr, segManager, version, script_nr); else - return script_instantiate_sci0(resMgr, segManager, version, script_nr); + return script_instantiate_sci0(resMgr, segManager, version, oldScriptHeader, script_nr); } void script_uninstantiate_sci0(SegManager *segManager, SciVersion version, int script_nr, SegmentId seg) { diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index c8f94d5446..867f732e2a 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -489,7 +489,7 @@ reg_t script_lookup_export(SegManager *segManager, int script_nr, int export_ind * @param[in] script_nr The script number to load * @return The script's segment ID or 0 if out of heap */ -int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr); +int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr); /** * Decreases the numer of lockers of a script and unloads it if that number |