diff options
| author | Norbert Lange | 2009-08-24 17:51:47 +0000 |
|---|---|---|
| committer | Norbert Lange | 2009-08-24 17:51:47 +0000 |
| commit | 917d4b78b36d6c5a5c25a03e7ee6a1c1b6a85fd5 (patch) | |
| tree | e652563203a00f8acecfaafbf93c64dbfbd13f25 /engines/sci/engine | |
| parent | 5f87d5090cfcb34cda3c1f5d430e0865344d7366 (diff) | |
| parent | dd7868acc2512c9761d892e67a4837f4dc38bdc0 (diff) | |
| download | scummvm-rg350-917d4b78b36d6c5a5c25a03e7ee6a1c1b6a85fd5.tar.gz scummvm-rg350-917d4b78b36d6c5a5c25a03e7ee6a1c1b6a85fd5.tar.bz2 scummvm-rg350-917d4b78b36d6c5a5c25a03e7ee6a1c1b6a85fd5.zip | |
Merge with trunk
svn-id: r43701
Diffstat (limited to 'engines/sci/engine')
| -rw-r--r-- | engines/sci/engine/game.cpp | 149 | ||||
| -rw-r--r-- | engines/sci/engine/kernel.cpp | 150 | ||||
| -rw-r--r-- | engines/sci/engine/kernel.h | 17 | ||||
| -rw-r--r-- | engines/sci/engine/klists.cpp | 8 | ||||
| -rw-r--r-- | engines/sci/engine/kmisc.cpp | 25 | ||||
| -rw-r--r-- | engines/sci/engine/kpathing.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/kscripts.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/ksound.cpp | 23 | ||||
| -rw-r--r-- | engines/sci/engine/savegame.cpp | 3 | ||||
| -rw-r--r-- | engines/sci/engine/seg_manager.cpp | 34 | ||||
| -rw-r--r-- | engines/sci/engine/seg_manager.h | 1 | ||||
| -rw-r--r-- | engines/sci/engine/state.cpp | 75 | ||||
| -rw-r--r-- | engines/sci/engine/state.h | 15 | ||||
| -rw-r--r-- | engines/sci/engine/static_selectors.cpp | 109 | ||||
| -rw-r--r-- | engines/sci/engine/vm.cpp | 36 |
15 files changed, 340 insertions, 309 deletions
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 6872039c89..994054f6a7 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -43,7 +43,7 @@ int _reset_graphics_input(EngineState *s) { gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 }; debug(2, "Initializing graphics"); - if (!s->resmgr->isVGA()) { + if (s->resmgr->getViewType() == kViewEga) { for (int i = 0; i < 16; i++) { if (gfxop_set_color(s->gfx_state, &(s->ega_colors[i]), gfx_sci0_image_colors[sci0_palette][i].r, gfx_sci0_image_colors[sci0_palette][i].g, gfx_sci0_image_colors[sci0_palette][i].b, 0, -1, -1)) { @@ -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->gc_countdown = GC_INTERVAL - 1; SegmentId script_000_segment = s->seg_manager->getSegment(0, SCRIPT_GET_LOCK); diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 6d027d5788..687e621405 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -33,11 +33,7 @@ namespace Sci { -/** The string used to identify the "unknown" SCI0 function for each game */ -#define SCRIPT_UNKNOWN_FUNCTION_STRING "[Unknown]" - // Default kernel name table -#define SCI0_KNAMES_WELL_DEFINED 0x6e #define SCI_KNAMES_DEFAULT_ENTRIES_NR 0x89 static const char *sci_default_knames[SCI_KNAMES_DEFAULT_ENTRIES_NR] = { @@ -370,8 +366,9 @@ static const char *argtype_description[] = { Kernel::Kernel(ResourceManager *resmgr) : _resmgr(resmgr) { memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t - detectSciFeatures(); // must be called before loadSelectorNames() loadSelectorNames(); + detectSciFeatures(); + mapSelectors(); // Map a few special selectors for later use loadOpcodes(); loadKernelNames(); @@ -382,61 +379,30 @@ Kernel::~Kernel() { } void Kernel::detectSciFeatures() { - // FIXME Much of this is unreliable - - Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0); - - Common::StringList staticSelectorTable; - - if (!r) { // No such resource? - staticSelectorTable = checkStaticSelectorNames(); - if (staticSelectorTable.empty()) - error("Kernel: Could not retrieve selector names"); - } + SciVersion version = _resmgr->sciVersion(); - int count = staticSelectorTable.empty() ? READ_LE_UINT16(r->data) + 1 : staticSelectorTable.size(); // Counter is slightly off features = 0; // Initialize features based on SCI version - 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++) { - Common::String tmp; - - if (staticSelectorTable.empty()) { - int offset = READ_LE_UINT16(r->data + 2 + i * 2); - int len = READ_LE_UINT16(r->data + offset); - - tmp = Common::String((const char *)r->data + offset + 2, len); - } else { - tmp = staticSelectorTable[i]; - } - - if (tmp == "motionCue") - features &= ~kFeatureOldGfxFunctions; + // Script header and graphics functions + if (version == SCI_VERSION_0_EARLY) { + features |= kFeatureOldScriptHeader | kFeatureOldGfxFunctions; + } else if (version == SCI_VERSION_0_LATE) { + if (findSelector("motionCue") == -1) + features |= kFeatureOldGfxFunctions; + } - if (tmp == "egoMoveSpeed" && _resmgr->sciVersion() < SCI_VERSION_1_1) + // Lofs absolute/relative + if (version >= SCI_VERSION_1_MIDDLE && version < SCI_VERSION_1_1) { + // Assume all games use absolute lofs + features |= kFeatureLofsAbsolute; + } else if (version == SCI_VERSION_1_EARLY) { + // Use heuristic + if (findSelector("egoMoveSpeed") != -1) features |= kFeatureLofsAbsolute; - - if (tmp == "setVol") - features |= kFeatureSci1Sound; - - if (tmp == "nodePtr") - features |= kFeatureSci01Sound; } - if (features & kFeatureSci1Sound) - features &= ~kFeatureSci01Sound; - printf("Kernel auto-detected features:\n"); printf("Graphics functions: "); @@ -445,19 +411,13 @@ void Kernel::detectSciFeatures() { else printf("new\n"); - printf("lofs parameters: "); - if (features & kFeatureLofsAbsolute) - printf("absolute\n"); - else - printf("relative\n"); - - printf("Sound functions: "); - if (features & kFeatureSci1Sound) - printf("SCI1\n"); - else if (features & kFeatureSci01Sound) - printf("SCI01\n"); - else - printf("SCI0\n"); + if (version < SCI_VERSION_1_1) { + printf("lofs parameters: "); + if (features & kFeatureLofsAbsolute) + printf("absolute\n"); + else + printf("relative\n"); + } } void Kernel::loadSelectorNames() { @@ -473,7 +433,7 @@ void Kernel::loadSelectorNames() { for (uint32 i = 0; i < staticSelectorTable.size(); i++) { _selectorNames.push_back(staticSelectorTable[i]); - if (features & kFeatureOldScriptHeader) + if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY) _selectorNames.push_back(staticSelectorTable[i]); } @@ -492,7 +452,7 @@ void Kernel::loadSelectorNames() { // Early SCI versions used the LSB in the selector ID as a read/write // toggle. To compensate for that, we add every selector name twice. - if (features & kFeatureOldScriptHeader) + if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY) _selectorNames.push_back(tmp); } } @@ -819,37 +779,45 @@ reg_t *kernel_dereference_reg_pointer(EngineState *s, reg_t pointer, int entries } void Kernel::setDefaultKernelNames() { - bool isSci0 = (_resmgr->sciVersion() <= SCI_VERSION_0_LATE); - int offset = 0; - - _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 - if (!strcmp(sci_default_knames[i], "Platform") && isSci0) { - _kernelNames[i + offset] = "DoAvoider"; - continue; - } + _kernelNames = Common::StringList(sci_default_knames, SCI_KNAMES_DEFAULT_ENTRIES_NR); - _kernelNames[i + offset] = sci_default_knames[i]; + switch (_resmgr->sciVersion()) { + case SCI_VERSION_0_EARLY: + case SCI_VERSION_0_LATE: + // Insert SCI0 file functions after SetCursor (0x28) + _kernelNames.insert_at(0x29, "FOpen"); + _kernelNames.insert_at(0x2A, "FPuts"); + _kernelNames.insert_at(0x2B, "FGets"); + _kernelNames.insert_at(0x2C, "FClose"); - // SCI0 has 4 extra functions between SetCursor (0x28) and Savegame - if (!strcmp(sci_default_knames[i], "SetCursor") && isSci0) { - _kernelNames[i + 1] = "FOpen"; - _kernelNames[i + 2] = "FPuts"; - _kernelNames[i + 3] = "FGets"; - _kernelNames[i + 4] = "FClose"; - offset = 4; - } - } + // Function 0x55 is DoAvoider + _kernelNames[0x55] = "DoAvoider"; + + // Cut off unused functions + _kernelNames.resize(0x72); + break; + + case SCI_VERSION_01: + // Multilingual SCI01 games have StrSplit as function 0x78 + _kernelNames[0x78] = "StrSplit"; + + // Cut off unused functions + _kernelNames.resize(0x79); + break; - if (_resmgr->sciVersion() == SCI_VERSION_1_1) { - // HACK: KQ6CD calls unimplemented function 0x26 + case SCI_VERSION_1_1: + // KQ6CD calls unimplemented function 0x26 _kernelNames[0x26] = "Dummy"; + break; + + default: + // Use default table for the other versions + break; } } #ifdef ENABLE_SCI32 -static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &names) { +//static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &names) { /* 999.voc format for SCI1.1 games: [b] # of kernel functions @@ -859,7 +827,7 @@ static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &name {[w name-len][function name]} ... */ - //unsigned int size = 64, pos = 3; +/* //unsigned int size = 64, pos = 3; int len; Resource *r = resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_KNAMES), 0); if(r == NULL) // failed to open vocab.999 (happens with SCI1 demos) @@ -872,7 +840,7 @@ static void vocab_get_knames11(ResourceManager *resmgr, Common::StringList &name len = READ_LE_UINT16(r->data + off); names[i] = Common::String((char *)r->data + off + 2, len); } -} +}*/ #endif bool Kernel::loadKernelNames() { diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index bb5563a876..a85025f514 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -60,13 +60,14 @@ struct KernelFuncWithSignature { enum AutoDetectedFeatures { kFeatureOldScriptHeader = 1 << 0, kFeatureOldGfxFunctions = 1 << 1, - kFeatureLofsAbsolute = 1 << 2, - kFeatureSci01Sound = 1 << 3, - kFeatureSci1Sound = 1 << 4 + kFeatureLofsAbsolute = 1 << 2 }; class Kernel { public: + /** + * Initializes the SCI kernel + */ Kernel(ResourceManager *resmgr); ~Kernel(); @@ -119,16 +120,6 @@ public: */ bool hasLofsAbsolute() const { return (features & kFeatureLofsAbsolute); } - /** - * Determines if the game is using SCI01 sound functions - */ - bool usesSci01SoundFunctions() const { return (features & kFeatureSci01Sound); } - - /** - * Determines if the game is using SCI1 sound functions - */ - bool usesSci1SoundFunctions() const { return (features & kFeatureSci1Sound); } - // Script dissection/dumping functions void dissectScript(int scriptNumber, Vocabulary *vocab); void dumpScriptObject(char *data, int seeker, int objsize); diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 43d1f25e01..a9ae77972f 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -36,7 +36,7 @@ Node *lookup_node(EngineState *s, reg_t addr) { if (!mobj) { // FIXME: This occurs right at the beginning of SQ4, when walking north from the first screen. It doesn't // seem to have any apparent ill-effects, though, so it's been changed to non-fatal, for now - //error("%s, L%d: Attempt to use non-node %04x:%04x as list node\n", __FILE__, __LINE__, PRINT_REG(addr)); + //error("%s, L%d: Attempt to use non-node %04x:%04x as list node", __FILE__, __LINE__, PRINT_REG(addr)); warning("Attempt to use non-node %04x:%04x as list node", PRINT_REG(addr)); return NULL; } @@ -44,7 +44,7 @@ Node *lookup_node(EngineState *s, reg_t addr) { NodeTable *nt = (NodeTable *)mobj; if (!nt->isValidEntry(addr.offset)) { - error("Attempt to use non-node %04x:%04x as list node\n", PRINT_REG(addr)); + error("Attempt to use non-node %04x:%04x as list node", PRINT_REG(addr)); return NULL; } @@ -55,14 +55,14 @@ List *lookup_list(EngineState *s, reg_t addr) { MemObject *mobj = GET_SEGMENT(*s->seg_manager, addr.segment, MEM_OBJ_LISTS); if (!mobj) { - error("Attempt to use non-list %04x:%04x as list\n", PRINT_REG(addr)); + error("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr)); return NULL; } ListTable *lt = (ListTable *)mobj; if (!lt->isValidEntry(addr.offset)) { - error("Attempt to use non-list %04x:%04x as list\n", PRINT_REG(addr)); + error("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr)); return NULL; } diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 2f0072ec67..90ae88b73f 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -63,14 +63,27 @@ reg_t kHaveMouse(EngineState *s, int funct_nr, int argc, reg_t *argv) { return make_reg(0, -1); } +enum kMemoryInfoFunc { + K_MEMORYINFO_LARGEST_HEAP_BLOCK = 0, // Largest heap block available + K_MEMORYINFO_FREE_HEAP = 1, // Total free heap memory + K_MEMORYINFO_LARGEST_HUNK_BLOCK = 2, // Largest available hunk memory block + K_MEMORYINFO_FREE_HUNK = 3, // Amount of free DOS paragraphs + K_MEMORYINFO_TOTAL_HUNK = 4 // Total amount of hunk memory (SCI01) +}; + reg_t kMemoryInfo(EngineState *s, int funct_nr, int argc, reg_t *argv) { + uint16 size = 0x7fff; // Must not be 0xffff, or some memory calculations will overflow + switch (argv[0].offset) { - case 0: // Total free heap memory - case 1: // Largest heap block available - case 2: // Largest available hunk memory block - case 3: // Total amount of hunk memory - case 4: // Amount of free DOS paragraphs- SCI01 - return make_reg(0, 0x7fff); // Must not be 0xffff, or some memory calculations will overflow + case K_MEMORYINFO_LARGEST_HEAP_BLOCK: + // In order to prevent "Memory fragmented" dialogs from + // popping up in some games, we must return FREE_HEAP - 2 here. + return make_reg(0, size - 2); + case K_MEMORYINFO_FREE_HEAP: + case K_MEMORYINFO_LARGEST_HUNK_BLOCK: + case K_MEMORYINFO_FREE_HUNK: + case K_MEMORYINFO_TOTAL_HUNK: + return make_reg(0, size); default: warning("Unknown MemoryInfo operation: %04x", argv[0].offset); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index da24a388fa..ad14202257 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1406,7 +1406,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co err = nearest_intersection(pf_s, start, end, &intersection); if (err == PF_FATAL) { - warning("AvoidPath: fatal error finding nearest intersecton"); + warning("AvoidPath: fatal error finding nearest intersection"); delete pf_s; return NULL; } diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 4d90dd68ac..41eb9f624d 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -74,7 +74,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc warning("Selector '%s' of object at %04x:%04x could not be invoked (%s L%d)", ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); if (noinvalid == kStopOnInvalidSelector) - error("[Kernel] Not recoverable: VM was halted\n"); + error("[Kernel] Not recoverable: VM was halted"); return 1; } if (slc_type == kSelectorVariable) // Swallow silently diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 38baeafad8..44b2404e41 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -204,7 +204,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their } -reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t obj = (argc > 1) ? argv[1] : NULL_REG; uint16 command = argv[0].toUint16(); SongHandle handle = FROBNICATE_HANDLE(obj); @@ -383,7 +383,7 @@ reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) { } -reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint16 command = argv[0].toUint16(); reg_t obj = (argc > 1) ? argv[1] : NULL_REG; SongHandle handle = FROBNICATE_HANDLE(obj); @@ -673,7 +673,7 @@ reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } -reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint16 command = argv[0].toUint16(); reg_t obj = (argc > 1) ? argv[1] : NULL_REG; SongHandle handle = FROBNICATE_HANDLE(obj); @@ -988,12 +988,17 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { * Used for synthesized music playback */ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { - if (((SciEngine*)g_engine)->getKernel()->usesSci1SoundFunctions()) - return kDoSound_SCI1(s, funct_nr, argc, argv); - else if (((SciEngine*)g_engine)->getKernel()->usesSci01SoundFunctions()) - return kDoSound_SCI01(s, funct_nr, argc, argv); - else - return kDoSound_SCI0(s, funct_nr, argc, argv); + switch(s->detectDoSoundType()) { + case EngineState::kDoSoundTypeSci0: + return kDoSoundSci0(s, funct_nr, argc, argv); + case EngineState::kDoSoundTypeSci1Early: + return kDoSoundSci1Early(s, funct_nr, argc, argv); + case EngineState::kDoSoundTypeSci1Late: + return kDoSoundSci1Late(s, funct_nr, argc, argv); + default: + warning("Unknown DoSound type"); + return NULL_REG; + } } /** diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 1768695244..b53e9d522c 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -701,8 +701,7 @@ static void reconstruct_sounds(EngineState *s) { Song *seeker; SongIteratorType it_type; - if (((SciEngine *)g_engine)->getKernel()->usesSci01SoundFunctions() - || ((SciEngine *)g_engine)->getKernel()->usesSci1SoundFunctions()) + if (s->_version > SCI_VERSION_01) it_type = SCI_SONG_ITERATOR_TYPE_SCI1; else it_type = SCI_SONG_ITERATOR_TYPE_SCI0; diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index f47a874528..0c88481125 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -68,6 +68,13 @@ SegManager::SegManager(ResourceManager *resMgr, SciVersion version) { exports_wide = 0; _version = version; _resMgr = resMgr; + + int result = 0; + + result = createClassTable(); + + if (result) + error("SegManager: Failed to initialize class table"); } // Destroy the object, free the memorys if allocated before @@ -139,7 +146,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 (_version == SCI_VERSION_0_EARLY) { // check if we got an old script header 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) { @@ -155,7 +162,7 @@ void SegManager::setScriptSize(Script &scr, int script_nr) { } if (scr.buf_size > 65535) { - error("Script and heap sizes combined exceed 64K.\n" + error("Script and heap sizes combined exceed 64K." "This means a fundamental design bug was made in SCI\n" "regarding SCI1.1 games.\nPlease report this so it can be" "fixed in the next major version"); @@ -677,12 +684,11 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { int species = READ_LE_UINT16(seeker + 10); if (species < 0 || species >= (int)_classtable.size()) { - error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d\n", + error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d", species, species, _classtable.size(), scr->nr); return; } - _classtable[species].script = scr->nr; _classtable[species].reg.segment = seg; _classtable[species].reg.offset = classpos; } @@ -906,5 +912,25 @@ int SegManager::freeDynmem(reg_t addr) { return 0; // OK } +int SegManager::createClassTable() { + Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1); + + if (!vocab996) + error("SegManager: failed to open vocab 996"); + + int totalClasses = vocab996->size >> 2; + _classtable.resize(totalClasses); + + for (uint16 classNr = 0; classNr < totalClasses; classNr++) { + uint16 scriptNr = READ_LE_UINT16(vocab996->data + classNr * 4 + 2); + + _classtable[classNr].reg = NULL_REG; + _classtable[classNr].script = scriptNr; + } + + _resMgr->unlockResource(vocab996); + + return 0; +} } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index f73c788b37..27c8ad446a 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -360,6 +360,7 @@ private: LocalVariables *allocLocalsSegment(Script *scr, int count); MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type); int deallocate(SegmentId seg, bool recursive); + int createClassTable(); Hunk *alloc_Hunk(reg_t *); diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index fd45ef5834..baa51bcb58 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -24,6 +24,8 @@ */ #include "sci/engine/state.h" +#include "sci/engine/vm.h" +#include "sci/console.h" // For parse_reg_t namespace Sci { @@ -116,6 +118,8 @@ EngineState::EngineState(ResourceManager *res, SciVersion version, uint32 flags) successor = 0; speedThrottler = new SpeedThrottler(version); + + _doSoundType = kDoSoundTypeUnknown; } EngineState::~EngineState() { @@ -242,4 +246,75 @@ Common::String EngineState::strSplit(const char *str, const char *sep) { return retval; } +EngineState::DoSoundType EngineState::detectDoSoundType() { + if (_doSoundType == kDoSoundTypeUnknown) { + reg_t soundClass; + const uint checkBytes = 6; // Number of bytes to check + + if (!parse_reg_t(this, "?Sound", &soundClass)) { + reg_t fptr; + + Object *obj = obj_get(seg_manager, _version, soundClass); + SelectorType sel = lookup_selector(this, soundClass, ((SciEngine*)g_engine)->getKernel()->_selectorMap.play, NULL, &fptr); + + if (obj && (sel == kSelectorMethod)) { + Script *script = seg_manager->getScript(fptr.segment); + + if (fptr.offset > checkBytes) { + // Go to the last portion of Sound::init, should be right before the play function + fptr.offset -= checkBytes; + byte *buf = script->buf + fptr.offset; + + // Check the call to DoSound's INIT_HANDLE function. + // It's either subfunction 0, 5 or 6, depending on the version of DoSound. + uint sum = 0; + for (uint i = 0; i < checkBytes; i++) + sum += buf[i]; + + switch(sum) { + case 0x1B2: // SCI0 + case 0x1AE: // SCI01 + _doSoundType = kDoSoundTypeSci0; + break; + case 0x13D: + _doSoundType = kDoSoundTypeSci1Early; + break; + case 0x13E: + _doSoundType = kDoSoundTypeSci1Late; + } + } + } + } + + if (_doSoundType == kDoSoundTypeUnknown) { + warning("DoSound detection failed, taking an educated guess"); + + if (_version >= SCI_VERSION_1_MIDDLE) + _doSoundType = kDoSoundTypeSci1Late; + else if (_version > SCI_VERSION_01) + _doSoundType = kDoSoundTypeSci1Early; + else + _doSoundType = kDoSoundTypeSci0; + } + + debugCN(1, kDebugLevelSound, "Detected DoSound type: "); + + switch(_doSoundType) { + case kDoSoundTypeSci0: + debugC(1, kDebugLevelSound, "SCI0"); + break; + case kDoSoundTypeSci1Early: + debugC(1, kDebugLevelSound, "SCI1 Early"); + break; + case kDoSoundTypeSci1Late: + debugC(1, kDebugLevelSound, "SCI1 Late"); + break; + default: + break; + } + } + + return _doSoundType; +} + } // End of namespace Sci diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index c8e9139f27..a3983f6ae4 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -163,6 +163,14 @@ struct EngineState : public Common::Serializable { public: EngineState(ResourceManager *res, SciVersion version, uint32 flags); virtual ~EngineState(); + + enum DoSoundType { + kDoSoundTypeUnknown, + kDoSoundTypeSci0, + kDoSoundTypeSci1Early, + kDoSoundTypeSci1Late + }; + virtual void saveLoadWithSerializer(Common::Serializer &ser); kLanguage getLanguage(); @@ -272,6 +280,12 @@ public: */ Common::String strSplit(const char *str, const char *sep = "\r----------\r"); + /** + * Autodetects the DoSound type + * @return DoSound type + */ + DoSoundType detectDoSoundType(); + /* Debugger data: */ Breakpoint *bp_list; /**< List of breakpoints */ int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */ @@ -301,6 +315,7 @@ public: EngineState *successor; /**< Successor of this state: Used for restoring */ private: + DoSoundType _doSoundType; kLanguage charToLanguage(const char c) const; Common::String getLanguageString(const char *str, kLanguage lang) const; }; diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp index c1d0ad9bac..1897748c6d 100644 --- a/engines/sci/engine/static_selectors.cpp +++ b/engines/sci/engine/static_selectors.cpp @@ -26,9 +26,6 @@ // We place selector vocab name tables here for any game that doesn't have // them. This includes the King's Quest IV Demo and LSL3 Demo. -#ifndef SCI_STATIC_SELECTORS_H -#define SCI_STATIC_SELECTORS_H - #include "sci/engine/kernel.h" namespace Sci { @@ -397,6 +394,100 @@ static const SelectorRemap iceman_demo_selectors[] = { { "setTarget", 171 } }; +// Taken from Space Quest 1 VGA (Demo) +static const SelectorRemap lsl5_demo_selectors[] = { + { "init", 103 }, + { "play", 42 }, + { "replay", 65 }, + { "x", 4 }, + { "y", 3 }, + { "z", 85 }, + { "priority", 63 }, + { "view", 5 }, + { "loop", 6 }, + { "cel", 7 }, + { "brLeft", 20 }, + { "brRight", 22 }, + { "brTop", 19 }, + { "brBottom", 21 }, + { "xStep", 54 }, + { "yStep", 55 }, + { "nsBottom", 11 }, + { "nsTop", 9 }, + { "nsLeft", 10 }, + { "nsRight", 12 }, + { "font", 33 }, + { "text", 26 }, + { "type", 34 }, + { "state", 32 }, + { "doit", 60 }, + { "delete", 84 }, + { "signal", 17 }, + { "underBits", 8 }, + { "canBeHere", 57 }, + { "client", 45 }, + { "dx", 46 }, + { "dy", 47 }, + { "xStep", 54 }, + { "yStep", 55 }, + { "b-moveCnt", 48 }, + { "b-i1", 49 }, + { "b-i2", 50 }, + { "b-di", 51 }, + { "b-xAxis", 52 }, + { "b-incr", 53 }, + { "completed", 207 }, + { "illegalBits", 18 }, + { "dispose", 104 }, + { "prevSignal", 148 }, + { "message", 40 }, + { "modifiers", 64 }, + { "cue", 135 }, + { "owner", 149 }, + { "handle", 93 }, + { "number", 43 }, + { "max", 37 }, + { "cursor", 36 }, + { "claimed", 76 }, + { "edgeHit", 308 }, + { "wordFail", 71 }, + { "syntaxFail", 72 }, + { "semanticFail", 73 }, + { "cycler", 212 }, + { "elements", 27 }, + { "lsTop", 13 }, + { "lsBottom", 15 }, + { "lsLeft", 14 }, + { "lsRight", 16 }, + { "baseSetter", 277 }, + { "who", 39 }, + { "distance", 221 }, + { "mover", 59 }, + { "looper", 62 }, + { "isBlocked", 61 }, + { "heading", 58 }, + { "mode", 30 }, + { "caller", 133 }, + { "moveDone", 100 }, + { "vol", 97 }, + { "pri", 98 }, + { "min", 94 }, + { "sec", 95 }, + { "frame", 96 }, + { "dataInc", 92 }, + { "size", 89 }, + { "palette", 91 }, + { "moveSpeed", 56 }, + { "nodePtr", 44 }, + { "flags", 150 }, + { "points", 90 }, + { "printLang", 87 }, + { "subtitleLang", 88 }, + { "parseLang", 86 }, + { "motionCue", 210 }, + { "egoMoveSpeed", 357 } +}; + // A macro for loading one of the above tables in the function below #define USE_SELECTOR_TABLE(x) \ do { \ @@ -408,10 +499,12 @@ static const SelectorRemap iceman_demo_selectors[] = { } while (0) Common::StringList Kernel::checkStaticSelectorNames() { - Common::String gameID = ((SciEngine*)g_engine)->getGameID(); - Common::StringList names; - + if (!g_engine) + return names; + + Common::String gameID = ((SciEngine*)g_engine)->getGameID(); + if (gameID == "kq4sci") USE_SELECTOR_TABLE(kq4_demo_selectors); else if (gameID == "lsl3" || gameID == "iceman") // identical, except iceman has "flags" @@ -420,10 +513,10 @@ Common::StringList Kernel::checkStaticSelectorNames() { USE_SELECTOR_TABLE(christmas1992_selectors); else if (gameID == "lsl1sci") USE_SELECTOR_TABLE(lsl1_demo_selectors); + else if (gameID == "lsl5") + USE_SELECTOR_TABLE(lsl5_demo_selectors); return names; } } // End of namespace Sci - -#endif // SCI_STATIC_SELECTORS_H diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index fbd3bc3baf..fbdb3d1c85 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -79,7 +79,7 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { if (sp >= s->stack_base && sp < s->stack_top) return sp; - error("[VM] Stack index %d out of valid range [%d..%d]\n", + error("[VM] Stack index %d out of valid range [%d..%d]", (int)(sp - s->stack_base), 0, (int)(s->stack_top - s->stack_base - 1)); return 0; } @@ -87,9 +87,9 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { static int validate_arithmetic(reg_t reg) { if (reg.segment) { if (g_debug_weak_validations) - warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); + warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]", reg.segment); else - error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); + error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]", reg.segment); return 0; } @@ -99,9 +99,9 @@ static int validate_arithmetic(reg_t reg) { static int signed_validate_arithmetic(reg_t reg) { if (reg.segment) { if (g_debug_weak_validations) - warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); + warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]", reg.segment); else - error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); + error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]", reg.segment); return 0; } @@ -214,7 +214,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP int temp = s->seg_manager->validateExportFunc(pubfunct, seg); if (!temp) { - error("Request for invalid exported function 0x%x of script 0x%x\n", pubfunct, script); + error("Request for invalid exported function 0x%x of script 0x%x", pubfunct, script); return NULL; } @@ -312,14 +312,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt ObjVarRef varp; switch (lookup_selector(s, send_obj, selector, &varp, &funcp)) { case kSelectorNone: - // WORKAROUND: LSL6 tries to access the invalid 'keep' selector of the game object. - // FIXME: Find out if this is a game bug. - if ((s->_gameName == "LSL6") && (selector == 0x18c)) { - debug("LSL6 detected, continuing..."); - break; - } - - error("Send to invalid selector 0x%x of object at %04x:%04x\n", 0xffff & selector, PRINT_REG(send_obj)); + error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj)); break; @@ -930,7 +923,7 @@ void run_vm(EngineState *s, int restoring) { } if (opparams[0] >= (int)((SciEngine*)g_engine)->getKernel()->_kernelFuncs.size()) { - error("Invalid kernel function 0x%x requested\n", opparams[0]); + error("Invalid kernel function 0x%x requested", opparams[0]); } else { int argc = ASSERT_ARITHMETIC(scriptState.xs->sp[0]); @@ -941,7 +934,7 @@ void run_vm(EngineState *s, int restoring) { && !kernel_matches_signature(s, ((SciEngine*)g_engine)->getKernel()->_kernelFuncs[opparams[0]].signature, argc, scriptState.xs->sp + 1)) { - error("[VM] Invalid arguments to kernel call %x\n", opparams[0]); + error("[VM] Invalid arguments to kernel call %x", opparams[0]); } else { s->r_acc = ((SciEngine*)g_engine)->getKernel()->_kernelFuncs[opparams[0]].fun(s, opparams[0], argc, scriptState.xs->sp + 1); @@ -1195,7 +1188,7 @@ void run_vm(EngineState *s, int restoring) { #ifndef DISABLE_VALIDATIONS if (r_temp.offset >= code_buf_size) { error("VM: lofss operation overflowed: %04x:%04x beyond end" - " of script (at %04x)\n", PRINT_REG(r_temp), code_buf_size); + " of script (at %04x)", PRINT_REG(r_temp), code_buf_size); } #endif PUSH32(r_temp); @@ -1492,7 +1485,7 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select if (!obj) { - error("lookup_selector(): Error while looking up Species class.\nOriginal address was %04x:%04x. Species address was %04x:%04x\n", + error("lookup_selector(): Error while looking up Species class.\nOriginal address was %04x:%04x. Species address was %04x:%04x", PRINT_REG(obj_location), PRINT_REG(obj->_variables[SCRIPT_SPECIES_SELECTOR])); return kSelectorNone; } @@ -1573,7 +1566,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 +1586,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); @@ -1660,7 +1653,6 @@ int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, Sci return 1; } - segManager->_classtable[species].script = script_nr; segManager->_classtable[species].reg = addr; segManager->_classtable[species].reg.offset = classpos; // Set technical class position-- into the block allocated for it @@ -1765,7 +1757,7 @@ int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersi 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, (version == SCI_VERSION_0_EARLY), script_nr); } void script_uninstantiate_sci0(SegManager *segManager, SciVersion version, int script_nr, SegmentId seg) { |
