diff options
Diffstat (limited to 'engines/sci/engine')
| -rw-r--r-- | engines/sci/engine/file.cpp | 261 | ||||
| -rw-r--r-- | engines/sci/engine/file.h | 46 | ||||
| -rw-r--r-- | engines/sci/engine/kernel.cpp | 6 | ||||
| -rw-r--r-- | engines/sci/engine/kernel.h | 20 | ||||
| -rw-r--r-- | engines/sci/engine/kernel_tables.h | 35 | ||||
| -rw-r--r-- | engines/sci/engine/kfile.cpp | 109 | ||||
| -rw-r--r-- | engines/sci/engine/kgraphics32.cpp | 117 | ||||
| -rw-r--r-- | engines/sci/engine/kmisc.cpp | 3 | ||||
| -rw-r--r-- | engines/sci/engine/kvideo.cpp | 153 | ||||
| -rw-r--r-- | engines/sci/engine/savegame.cpp | 11 | ||||
| -rw-r--r-- | engines/sci/engine/script_patches.cpp | 168 | ||||
| -rw-r--r-- | engines/sci/engine/state.cpp | 6 | ||||
| -rw-r--r-- | engines/sci/engine/state.h | 5 |
13 files changed, 506 insertions, 434 deletions
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp index 0b1001bfda..156f6f51f7 100644 --- a/engines/sci/engine/file.cpp +++ b/engines/sci/engine/file.cpp @@ -22,6 +22,7 @@ #include "common/savefile.h" #include "common/stream.h" +#include "common/memstream.h" #include "sci/sci.h" #include "sci/engine/file.h" @@ -32,6 +33,112 @@ namespace Sci { +#ifdef ENABLE_SCI32 +/** + * A MemoryWriteStreamDynamic with additional read functionality. + * The read and write functions share a single stream position. + */ +class MemoryDynamicRWStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream { +protected: + bool _eos; +public: + MemoryDynamicRWStream(DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) : MemoryWriteStreamDynamic(disposeMemory), _eos(false) { } + + uint32 read(void *dataPtr, uint32 dataSize); + + bool eos() const { return _eos; } + int32 pos() const { return _pos; } + int32 size() const { return _size; } + void clearErr() { _eos = false; Common::MemoryWriteStreamDynamic::clearErr(); } + bool seek(int32 offs, int whence = SEEK_SET) { return Common::MemoryWriteStreamDynamic::seek(offs, whence); } + +}; + +uint32 MemoryDynamicRWStream::read(void *dataPtr, uint32 dataSize) +{ + // Read at most as many bytes as are still available... + if (dataSize > _size - _pos) { + dataSize = _size - _pos; + _eos = true; + } + memcpy(dataPtr, _ptr, dataSize); + + _ptr += dataSize; + _pos += dataSize; + + return dataSize; +} + +/** + * A MemoryDynamicRWStream intended to re-write a file. + * It reads the contents of `inFile` in the constructor, and writes back + * the changes to `fileName` in the destructor (and when calling commit() ). + */ +class SaveFileRewriteStream : public MemoryDynamicRWStream { +public: + SaveFileRewriteStream(Common::String fileName, + Common::SeekableReadStream *inFile, + bool truncate, bool compress); + virtual ~SaveFileRewriteStream(); + + virtual uint32 write(const void *dataPtr, uint32 dataSize) { _changed = true; return MemoryDynamicRWStream::write(dataPtr, dataSize); } + + void commit(); //< Save back to disk + +protected: + Common::String _fileName; + bool _compress; + bool _changed; +}; + +SaveFileRewriteStream::SaveFileRewriteStream(Common::String fileName, + Common::SeekableReadStream *inFile, + bool truncate, + bool compress) +: MemoryDynamicRWStream(DisposeAfterUse::YES), + _fileName(fileName), _compress(compress) +{ + if (!truncate && inFile) { + unsigned int s = inFile->size(); + ensureCapacity(s); + inFile->read(_data, s); + _changed = false; + } else { + _changed = true; + } +} + +SaveFileRewriteStream::~SaveFileRewriteStream() { + commit(); +} + +void SaveFileRewriteStream::commit() { + // Write contents of buffer back to file + + if (_changed) { + Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName, _compress); + outFile->write(_data, _size); + delete outFile; + _changed = false; + } +} + +#endif + +uint findFreeFileHandle(EngineState *s) { + // Find a free file handle + uint handle = 1; // Ignore _fileHandles[0] + while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) + handle++; + + if (handle == s->_fileHandles.size()) { + // Hit size limit => Allocate more space + s->_fileHandles.resize(s->_fileHandles.size() + 1); + } + + return handle; +} + /* * Note on how file I/O is implemented: In ScummVM, one can not create/write * arbitrary data files, simply because many of our target platforms do not @@ -91,6 +198,27 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u break; } +#ifdef ENABLE_SCI32 + if (mode != _K_FILE_MODE_OPEN_OR_FAIL && ( + (g_sci->getGameId() == GID_PHANTASMAGORIA && filename == "phantsg.dir") || + (g_sci->getGameId() == GID_PQSWAT && filename == "swat.dat"))) { + debugC(kDebugLevelFile, " -> file_open opening %s for rewriting", wrappedName.c_str()); + + inFile = saveFileMan->openForLoading(wrappedName); + // If no matching savestate exists: fall back to reading from a regular + // file + if (!inFile) + inFile = SearchMan.createReadStreamForMember(englishName); + + SaveFileRewriteStream *stream; + stream = new SaveFileRewriteStream(wrappedName, inFile, mode == _K_FILE_MODE_CREATE, isCompressed); + + delete inFile; + + inFile = stream; + outFile = stream; + } else +#endif if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { // Try to open file, abort if not possible inFile = saveFileMan->openForLoading(wrappedName); @@ -126,15 +254,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u return SIGNAL_REG; } - // Find a free file handle - uint handle = 1; // Ignore _fileHandles[0] - while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen()) - handle++; - - if (handle == s->_fileHandles.size()) { - // Hit size limit => Allocate more space - s->_fileHandles.resize(s->_fileHandles.size() + 1); - } + uint handle = findFreeFileHandle(s); s->_fileHandles[handle]._in = inFile; s->_fileHandles[handle]._out = outFile; @@ -252,8 +372,12 @@ FileHandle::~FileHandle() { } void FileHandle::close() { - delete _in; - delete _out; + // NB: It is possible _in and _out are both non-null, but + // then they point to the same object. + if (_in) + delete _in; + else + delete _out; _in = 0; _out = 0; _name.clear(); @@ -365,119 +489,4 @@ reg_t DirSeeker::nextFile(SegManager *segMan) { return _outbuffer; } - -#ifdef ENABLE_SCI32 - -VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) { - Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName); - - _bufferSize = inFile->size(); - _buffer = new char[_bufferSize]; - inFile->read(_buffer, _bufferSize); - _ptr = _buffer; - delete inFile; -} - -VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) { - _bufferSize = initialSize; - _buffer = new char[_bufferSize]; - _ptr = _buffer; -} - -VirtualIndexFile::~VirtualIndexFile() { - close(); - - _bufferSize = 0; - delete[] _buffer; - _buffer = 0; -} - -uint32 VirtualIndexFile::read(char *buffer, uint32 size) { - uint32 curPos = _ptr - _buffer; - uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos); - char *localPtr = buffer; - - for (uint32 i = 0; i < finalSize; i++) - *localPtr++ = *_ptr++; - - return finalSize; -} - -uint32 VirtualIndexFile::write(const char *buffer, uint32 size) { - _changed = true; - uint32 curPos = _ptr - _buffer; - - // Check if the buffer needs to be resized - if (curPos + size >= _bufferSize) { - _bufferSize = curPos + size + 1; - char *tmp = _buffer; - _buffer = new char[_bufferSize]; - _ptr = _buffer + curPos; - memcpy(_buffer, tmp, _bufferSize); - delete[] tmp; - } - - for (uint32 i = 0; i < size; i++) - *_ptr++ = *buffer++; - - return size; -} - -uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) { - uint32 startPos = _ptr - _buffer; - uint32 bytesRead = 0; - char *localPtr = buffer; - - // This is not a full-blown implementation of readLine, but it - // suffices for Phantasmagoria - while (startPos + bytesRead < size) { - bytesRead++; - - if (*_ptr == 0 || *_ptr == 0x0A) { - _ptr++; - *localPtr = 0; - return bytesRead; - } else { - *localPtr++ = *_ptr++; - } - } - - return bytesRead; -} - -bool VirtualIndexFile::seek(int32 offset, int whence) { - uint32 startPos = _ptr - _buffer; - assert(offset >= 0); - - switch (whence) { - case SEEK_CUR: - assert(startPos + offset < _bufferSize); - _ptr += offset; - break; - case SEEK_SET: - assert(offset < (int32)_bufferSize); - _ptr = _buffer + offset; - break; - case SEEK_END: - assert((int32)_bufferSize - offset >= 0); - _ptr = _buffer + (_bufferSize - offset); - break; - } - - return true; -} - -void VirtualIndexFile::close() { - if (_changed && !_fileName.empty()) { - Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName); - outFile->write(_buffer, _bufferSize); - delete outFile; - } - - // Maintain the buffer, and seek to the beginning of it - _ptr = _buffer; -} - -#endif - } // End of namespace Sci diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h index 54627d5228..982d7b7823 100644 --- a/engines/sci/engine/file.h +++ b/engines/sci/engine/file.h @@ -43,7 +43,6 @@ enum { #define VIRTUALFILE_HANDLE_START 32000 #define VIRTUALFILE_HANDLE_SCI32SAVE 32100 -#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir" #define VIRTUALFILE_HANDLE_SCIAUDIO 32300 #define VIRTUALFILE_HANDLE_END 32300 @@ -93,50 +92,7 @@ private: void addAsVirtualFiles(Common::String title, Common::String fileMask); }; - -#ifdef ENABLE_SCI32 - -/** - * An implementation of a virtual file that supports basic read and write - * operations simultaneously. - * - * This class has been initially implemented for Phantasmagoria, which has its - * own custom save/load code. The load code keeps checking for the existence - * of the save index file and keeps closing and reopening it for each save - * slot. This is notoriously slow and clumsy, and introduces noticeable delays, - * especially for non-desktop systems. Also, its game scripts request to open - * the index file for reading and writing with the same parameters - * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover, - * the game scripts reopen the index file for writing in order to update it - * and seek within it. We do not support seeking in writeable streams, and the - * fact that our saved games are ZIP files makes this operation even more - * expensive. Finally, the savegame index file is supposed to be expanded when - * a new save slot is added. - * For the aforementioned reasons, this class has been implemented, which offers - * the basic functionality needed by the game scripts in Phantasmagoria. - */ -class VirtualIndexFile { -public: - VirtualIndexFile(Common::String fileName); - VirtualIndexFile(uint32 initialSize); - ~VirtualIndexFile(); - - uint32 read(char *buffer, uint32 size); - uint32 readLine(char *buffer, uint32 size); - uint32 write(const char *buffer, uint32 size); - bool seek(int32 offset, int whence); - void close(); - -private: - char *_buffer; - uint32 _bufferSize; - char *_ptr; - - Common::String _fileName; - bool _changed; -}; - -#endif +uint findFreeFileHandle(EngineState *s); } // End of namespace Sci diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 2fc338b618..2afb8b73d1 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -885,8 +885,8 @@ void Kernel::loadKernelNames(GameFeatures *features) { // how kDoSound is called from Sound::play(). // Known games that use this: // GK2 demo - // KQ7 1.4 - // PQ4 SWAT demo + // KQ7 1.4/1.51 + // PQ:SWAT demo // LSL6 // PQ4CD // QFG4CD @@ -897,7 +897,7 @@ void Kernel::loadKernelNames(GameFeatures *features) { _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo); // OnMe is IsOnMe here, but they should be compatible - _kernelNames[0x23] = "Robot"; // Graph in SCI2 + _kernelNames[0x23] = g_sci->getGameId() == GID_LSL6HIRES ? "Empty" : "Robot"; // Graph in SCI2 _kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2 } else { // Normal SCI2.1 kernel table diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index d95e228045..5ff4f932be 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -441,6 +441,15 @@ reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv); reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv); reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv); +reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv); + reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv); reg_t kArray(EngineState *s, int argc, reg_t *argv); reg_t kListAt(EngineState *s, int argc, reg_t *argv); @@ -538,8 +547,17 @@ reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv); reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv); reg_t kSetScroll(EngineState *s, int argc, reg_t *argv); -reg_t kPalCycle(EngineState *s, int argc, reg_t *argv); +reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv); +reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv); reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv); + +reg_t kPalCycle(EngineState *s, int argc, reg_t *argv); +reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv); +reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv); +reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv); +reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv); +reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv); + reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv); reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv); reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index dacaafe757..8a1176eed8 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -291,12 +291,13 @@ static const SciKernelMapSubEntry kPalVary_subops[] = { // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kPalette_subops[] = { - { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL }, + { SIG_SCI16, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL }, { SIG_SCI16, 2, MAP_CALL(PaletteSetFlag), "iii", NULL }, { SIG_SCI16, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds }, #ifdef ENABLE_SCI32 + { SIG_SCI32, 1, MAP_CALL(PaletteSetFromResource32), "i(i)", NULL }, { SIG_SCI32, 2, MAP_CALL(PaletteSetFade), "iii", NULL }, - { SIG_SCI32, 3, MAP_CALL(PaletteFindColor), "iii", NULL }, + { SIG_SCI32, 3, MAP_CALL(PaletteFindColor32), "iii", NULL }, #endif { SIG_SCI16, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL }, { SIG_SCI16, 5, MAP_CALL(PaletteFindColor), "iii", NULL }, @@ -335,6 +336,16 @@ static const SciKernelMapSubEntry kFileIO_subops[] = { #ifdef ENABLE_SCI32 // version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kPalCycle_subops[] = { + { SIG_SCI32, 0, MAP_CALL(PalCycleSetCycle), "iii(i)", NULL }, + { SIG_SCI32, 1, MAP_CALL(PalCycleDoCycle), "i(i)", NULL }, + { SIG_SCI32, 2, MAP_CALL(PalCyclePause), "(i)", NULL }, + { SIG_SCI32, 3, MAP_CALL(PalCycleOn), "(i)", NULL }, + { SIG_SCI32, 4, MAP_CALL(PalCycleOff), "(i)", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + +// version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kSave_subops[] = { { SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL }, { SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL }, @@ -412,6 +423,22 @@ static const SciKernelMapSubEntry kList_subops[] = { SCI_SUBOPENTRY_TERMINATOR }; +// There are a lot of subops to PlayVMD, but only a few of them are ever +// actually used by games +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kPlayVMD_subops[] = { + { SIG_SINCE_SCI21, 0, MAP_CALL(PlayVMDOpen), "r(i)(i)", NULL }, + { SIG_SINCE_SCI21, 1, MAP_CALL(PlayVMDInit), "ii(i)(i)(ii)", NULL }, + { SIG_SINCE_SCI21, 6, MAP_CALL(PlayVMDClose), "", NULL }, + { SIG_SINCE_SCI21, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL }, + { SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL }, + { SIG_SINCE_SCI21, 17, MAP_DUMMY(PlayVMDStartBlob), "", NULL }, + { SIG_SINCE_SCI21, 18, MAP_DUMMY(PlayVMDStopBlobs), "", NULL }, + { SIG_SINCE_SCI21, 21, MAP_CALL(PlayVMDSetBlackoutArea), "iiii", NULL }, + { SIG_SINCE_SCI21, 23, MAP_CALL(PlayVMDRestrictPalette), "ii", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kRemapColors_subops[] = { { SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL }, @@ -746,7 +773,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL }, { MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL }, { MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL }, - { MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, + { MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL }, // SCI2 Empty functions @@ -792,7 +819,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL }, { MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, - { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL }, { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL }, { MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL }, diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index d604bb85d0..4508a481a0 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -29,6 +29,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/translation.h" +#include "common/memstream.h" #include "gui/saveload.h" @@ -263,19 +264,6 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { } #ifdef ENABLE_SCI32 - if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { - if (s->_virtualIndexFile) { - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); - } else { - Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH); - Common::String wrappedName = g_sci->wrapFilename(englishName); - if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) { - s->_virtualIndexFile = new VirtualIndexFile(wrappedName); - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); - } - } - } - // Shivers is trying to store savegame descriptions and current spots in // separate .SG files, which are hardcoded in the scripts. // Essentially, there is a normal save file, created by the executable @@ -313,18 +301,18 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { listSavegames(saves); int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START); - if (!s->_virtualIndexFile) { - // Make the virtual file buffer big enough to avoid having it grow dynamically. - // 50 bytes should be more than enough. - s->_virtualIndexFile = new VirtualIndexFile(50); - } + int size = strlen(saves[savegameNr].name) + 2; + char *buf = (char *)malloc(size); + strcpy(buf, saves[savegameNr].name); + buf[size - 1] = 0; // Spot description (empty) - s->_virtualIndexFile->seek(0, SEEK_SET); - s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name)); - s->_virtualIndexFile->write("\0", 1); - s->_virtualIndexFile->write("\0", 1); // Spot description (empty) - s->_virtualIndexFile->seek(0, SEEK_SET); - return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); + uint handle = findFreeFileHandle(s); + + s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buf, size, DisposeAfterUse::YES); + s->_fileHandles[handle]._out = nullptr; + s->_fileHandles[handle]._name = ""; + + return make_reg(0, handle); } } #endif @@ -349,13 +337,6 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) { uint16 handle = argv[0].toUint16(); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->close(); - return SIGNAL_REG; - } -#endif - if (handle >= VIRTUALFILE_HANDLE_START) { // it's a virtual handle? ignore it return SIGNAL_REG; @@ -381,17 +362,9 @@ reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) { char *buf = new char[size]; debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - bytesRead = s->_virtualIndexFile->read(buf, size); - } else { -#endif - FileHandle *f = getFileFromHandle(s, handle); - if (f) - bytesRead = f->_in->read(buf, size); -#ifdef ENABLE_SCI32 - } -#endif + FileHandle *f = getFileFromHandle(s, handle); + if (f) + bytesRead = f->_in->read(buf, size); // TODO: What happens if less bytes are read than what has // been requested? (i.e. if bytesRead is non-zero, but still @@ -411,20 +384,11 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) { s->_segMan->memcpy((byte *)buf, argv[1], size); debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->write(buf, size); + FileHandle *f = getFileFromHandle(s, handle); + if (f) { + f->_out->write(buf, size); success = true; - } else { -#endif - FileHandle *f = getFileFromHandle(s, handle); - if (f) { - f->_out->write(buf, size); - success = true; - } -#ifdef ENABLE_SCI32 } -#endif delete[] buf; if (success) @@ -463,13 +427,6 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); } - -#ifdef ENABLE_SCI32 - if (name == PHANTASMAGORIA_SAVEGAME_INDEX) { - delete s->_virtualIndexFile; - s->_virtualIndexFile = 0; - } -#endif } else { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); @@ -488,12 +445,7 @@ reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) { debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize); uint32 bytesRead; -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) - bytesRead = s->_virtualIndexFile->readLine(buf, maxsize); - else -#endif - bytesRead = fgets_wrapper(s, buf, maxsize, handle); + bytesRead = fgets_wrapper(s, buf, maxsize, handle); s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize); delete[] buf; @@ -520,13 +472,6 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) { - s->_virtualIndexFile->write(str.c_str(), str.size()); - return NULL_REG; - } -#endif - FileHandle *f = getFileFromHandle(s, handle); if (f) { @@ -547,11 +492,6 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) { uint16 whence = argv[2].toUint16(); debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence); -#ifdef ENABLE_SCI32 - if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) - return make_reg(0, s->_virtualIndexFile->seek(offset, whence)); -#endif - FileHandle *f = getFileFromHandle(s, handle); if (f && f->_in) { @@ -591,14 +531,6 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) { reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { Common::String name = s->_segMan->getString(argv[0]); -#ifdef ENABLE_SCI32 - // Cache the file existence result for the Phantasmagoria - // save index file, as the game scripts keep checking for - // its existence. - if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile) - return TRUE_REG; -#endif - bool exists = false; if (g_sci->getGameId() == GID_PEPPER) { @@ -611,6 +543,9 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } + // TODO: It may apparently be worth caching the existence of + // phantsg.dir, and possibly even keeping it open persistently + // Check for regular file exists = Common::File::exists(name); diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 019a06930c..9cfe53255b 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -790,6 +790,19 @@ reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv) { + const GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->loadPalette(paletteId); + return s->r_acc; +} + +reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) { + const uint8 r = argv[0].toUint16(); + const uint8 g = argv[1].toUint16(); + const uint8 b = argv[2].toUint16(); + return make_reg(0, g_sci->_gfxPalette32->matchColor(r, g, b)); +} + reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) { uint16 fromColor = argv[0].toUint16(); uint16 toColor = argv[1].toUint16(); @@ -862,67 +875,57 @@ reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) { return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } -enum { - kSetCycle = 0, - kDoCycle = 1, - kCyclePause = 2, - kCycleOn = 3, - kCycleOff = 4 -}; - reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) { - // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen) + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - switch (argv[0].toUint16()) { - case kSetCycle: { - uint16 fromColor = argv[1].toUint16(); - uint16 toColor = argv[2].toUint16(); - int16 direction = argv[3].toSint16(); - uint16 delay = (argc == 4 ? 0 : argv[4].toUint16()); - - g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay); - } - break; - case kDoCycle: { - uint16 fromColor = argv[1].toUint16(); - int16 speed = (argc == 2) ? 1 : argv[2].toSint16(); - g_sci->_gfxPalette32->doCycle(fromColor, speed); - } - break; - case kCyclePause: { - if (argc == 1) { - g_sci->_gfxPalette32->cycleAllPause(); - } else { - uint16 fromColor = argv[1].toUint16(); - g_sci->_gfxPalette32->cyclePause(fromColor); - } - } - break; - case kCycleOn: { - if (argc == 1) { - g_sci->_gfxPalette32->cycleAllOn(); - } else { - uint16 fromColor = argv[1].toUint16(); - g_sci->_gfxPalette32->cycleOn(fromColor); - } - } - break; - case kCycleOff: { - if (argc == 1) { - g_sci->_gfxPalette32->cycleAllOff(); - } else { - uint16 fromColor = argv[1].toUint16(); - g_sci->_gfxPalette32->cycleOff(fromColor); - } - break; - } - default: - // In SCI2.1 there are no values above 4, so should never get here; - // SCI just returns early if this ever happens. - assert(false); - break; +reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) { + const uint16 fromColor = argv[0].toUint16(); + const uint16 toColor = argv[1].toUint16(); + const int16 direction = argv[2].toSint16(); + const uint16 delay = argc > 3 ? argv[3].toUint16() : 0; + + g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay); + return s->r_acc; +} + +reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv) { + const uint16 fromColor = argv[0].toUint16(); + const int16 speed = argc > 1 ? argv[1].toSint16() : 1; + + g_sci->_gfxPalette32->doCycle(fromColor, speed); + return s->r_acc; +} + +reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllPause(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cyclePause(fromColor); } + return s->r_acc; +} +reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllOn(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cycleOn(fromColor); + } + return s->r_acc; +} + +reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllOff(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cycleOff(fromColor); + } return s->r_acc; } diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 065625f85f..0d6831139a 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -409,6 +409,9 @@ reg_t kGetConfig(EngineState *s, int argc, reg_t *argv) { } else if (setting == "startroom") { // Debug setting in LSL7, specifies the room to start from. s->_segMan->strcpy(data, ""); + } else if (setting == "game") { + // Hoyle 5 Demo startup. + s->_segMan->strcpy(data, ""); } else { error("GetConfig: Unknown configuration setting %s", setting.c_str()); } diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 8db0c542eb..1096e78cca 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -40,7 +40,8 @@ #include "video/qt_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 -#include "video/coktel_decoder.h" +#include "sci/graphics/frameout.h" +#include "sci/graphics/video32.h" #include "sci/video/robot_decoder.h" #endif @@ -289,113 +290,73 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { } reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { - uint16 operation = argv[0].toUint16(); - Video::VideoDecoder *videoDecoder = 0; - bool reshowCursor = g_sci->_gfxCursor->isVisible(); - Common::String warningMsg; - - switch (operation) { - case 0: // init - s->_videoState.reset(); - s->_videoState.fileName = s->_segMan->derefString(argv[1]); + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - if (argc > 2 && argv[2] != NULL_REG) - warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2])); - break; - case 1: - { - // Set VMD parameters. Called with a maximum of 6 parameters: - // - // x, y, flags, gammaBoost, gammaFirst, gammaLast - // - // gammaBoost boosts palette colors in the range gammaFirst to - // gammaLast, but only if bit 4 in flags is set. Percent value such that - // 0% = no amplification These three parameters are optional if bit 4 is - // clear. Also note that the x, y parameters play subtle games if used - // with subfx 21. The subtleness has to do with creation of temporary - // planes and positioning relative to such planes. - - uint16 flags = argv[3].getOffset(); - Common::String flagspec; - - if (argc > 3) { - if (flags & kDoubled) - flagspec += "doubled "; - if (flags & kDropFrames) - flagspec += "dropframes "; - if (flags & kBlackLines) - flagspec += "blacklines "; - if (flags & kUnkBit3) - flagspec += "bit3 "; - if (flags & kGammaBoost) - flagspec += "gammaboost "; - if (flags & kHoldBlackFrame) - flagspec += "holdblack "; - if (flags & kHoldLastFrame) - flagspec += "holdlast "; - if (flags & kUnkBit7) - flagspec += "bit7 "; - if (flags & kStretch) - flagspec += "stretch"; - - warning("VMDFlags: %s", flagspec.c_str()); - - s->_videoState.flags = flags; - } +reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv) { + const Common::String fileName = s->_segMan->getString(argv[0]); + // argv[1] is an optional cache size argument which we do not use + // const uint16 cacheSize = argc > 1 ? CLIP<int16>(argv[1].toSint16(), 16, 1024) : 0; + const VMDPlayer::OpenFlags flags = argc > 2 ? (VMDPlayer::OpenFlags)argv[2].toUint16() : VMDPlayer::kOpenFlagNone; - warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset()); - s->_videoState.x = argv[1].getOffset(); - s->_videoState.y = argv[2].getOffset(); + return make_reg(0, g_sci->_video32->getVMDPlayer().open(fileName, flags)); +} - if (argc > 4 && flags & 16) - warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset()); - break; +reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv) { + const int16 x = argv[0].toSint16(); + const int16 y = argv[1].toSint16(); + const VMDPlayer::PlayFlags flags = argc > 2 ? (VMDPlayer::PlayFlags)argv[2].toUint16() : VMDPlayer::kPlayFlagNone; + int16 boostPercent; + int16 boostStartColor; + int16 boostEndColor; + if (argc > 5 && (flags & VMDPlayer::kPlayFlagBoost)) { + boostPercent = argv[3].toSint16(); + boostStartColor = argv[4].toSint16(); + boostEndColor = argv[5].toSint16(); + } else { + boostPercent = 0; + boostStartColor = -1; + boostEndColor = -1; } - case 6: // Play - videoDecoder = new Video::AdvancedVMDDecoder(); - if (s->_videoState.fileName.empty()) { - // Happens in Lighthouse - warning("kPlayVMD: Empty filename passed"); - return s->r_acc; - } + g_sci->_video32->getVMDPlayer().init(x, y, flags, boostPercent, boostStartColor, boostEndColor); - if (!videoDecoder->loadFile(s->_videoState.fileName)) { - warning("Could not open VMD %s", s->_videoState.fileName.c_str()); - break; - } + return make_reg(0, 0); +} - if (reshowCursor) - g_sci->_gfxCursor->kernelHide(); +reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_video32->getVMDPlayer().close()); +} - playVideo(videoDecoder, s->_videoState); +reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv) { + const VMDPlayer::EventFlags flags = (VMDPlayer::EventFlags)argv[0].toUint16(); + const int16 lastFrameNo = argc > 1 ? argv[1].toSint16() : -1; + const int16 yieldInterval = argc > 2 ? argv[2].toSint16() : -1; + return make_reg(0, g_sci->_video32->getVMDPlayer().kernelPlayUntilEvent(flags, lastFrameNo, yieldInterval)); +} - if (reshowCursor) - g_sci->_gfxCursor->kernelShow(); - break; - case 23: // set video palette range - s->_vmdPalStart = argv[1].toUint16(); - s->_vmdPalEnd = argv[2].toUint16(); - break; - case 14: - // Takes an additional integer parameter (e.g. 3) - case 16: - // Takes an additional parameter, usually 0 - case 21: - // Looks to be setting the video size and position. Called with 4 extra integer - // parameters (e.g. 86, 41, 235, 106) - default: - warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc); +reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) { + g_sci->_video32->getVMDPlayer().setShowCursor((bool)argv[0].toUint16()); + return s->r_acc; +} - for (int i = 0; i < argc; i++) { - warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i])); - warningMsg += (i == argc - 1 ? ")" : ", "); - } +reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv) { + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; - warning("%s", warningMsg.c_str()); - break; - } + Common::Rect blackoutArea; + blackoutArea.left = MAX((int16)0, argv[0].toSint16()); + blackoutArea.top = MAX((int16)0, argv[1].toSint16()); + blackoutArea.right = MIN(scriptWidth, (int16)(argv[2].toSint16() + 1)); + blackoutArea.bottom = MIN(scriptHeight, (int16)(argv[3].toSint16() + 1)); + g_sci->_video32->getVMDPlayer().setBlackoutArea(blackoutArea); + return s->r_acc; +} +reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) { + g_sci->_video32->getVMDPlayer().restrictPalette(argv[0].toUint16(), argv[1].toUint16()); return s->r_acc; } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 0972aec4a4..31fb848a2c 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -398,8 +398,13 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) { _segMan->saveLoadWithSerializer(s); g_sci->_soundCmd->syncPlayList(s); - // NOTE: This will be GfxPalette32 for SCI32 engine games - g_sci->_gfxPalette16->saveLoadWithSerializer(s); + +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + g_sci->_gfxPalette32->saveLoadWithSerializer(s); + } else +#endif + g_sci->_gfxPalette16->saveLoadWithSerializer(s); } void Vocabulary::saveLoadWithSerializer(Common::Serializer &s) { @@ -767,7 +772,7 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsSint16LE(_varyFromColor); s.syncAsSint16LE(_varyToColor); s.syncAsUint16LE(_varyNumTimesPaused); - s.syncAsByte(_versionUpdated); + s.syncAsByte(_needsUpdate); s.syncAsSint32LE(_varyTime); s.syncAsUint32LE(_varyLastTick); diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 70436e1269..e6eed0b4b7 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -1453,6 +1453,167 @@ static const SciScriptPatcherEntry kq6Signatures[] = { }; // =========================================================================== + +// King's Quest 7 has really weird subtitles. It seems as if the subtitles were +// not fully finished. +// +// Method kqMessager::findTalker in script 0 tries to figure out, which class to use for +// displaying subtitles. It uses the "talker" data of the given message to do that. +// Strangely this "talker" data seems to be quite broken. +// For example chapter 2 starts with a cutscene. +// Troll king: "Welcome, most beautiful of princesses!" - talker 6 +// Which is followed by the princess going +// "Hmm?" - which is set to talker 99, normally the princess is talker 7. +// +// Talker 99 is seen as unknown and thus treated as "narrator", which makes +// the scripts put the text at the top of the game screen and even use a +// different font. +// +// In other cases, when the player character thinks to himself talker 99 +// is also used. In such situations it may make somewhat sense to do so, +// but putting the text at the top of the screen is also irritating to the player. +// It's really weird. +// +// The scripts also put the regular text in the middle of the screen, blocking +// animations. +// +// And for certain rooms, the subtitle box may use another color +// like for example pink/purple at the start of chapter 5. +// +// We fix all of that (hopefully - lots of testing is required). +// We put the text at the bottom of the play screen. +// We also make the scripts use the regular KQTalker instead of KQNarrator. +// And we also make the subtitle box use color 255, which is fixed white. +// +// Applies to at least: PC CD 1.4 English, 1.51 English, 1.51 German, 2.00 English +// Patched method: KQNarrator::init (script 31) +static const uint16 kq7SignatureSubtitleFix1[] = { + SIG_MAGICDWORD, + 0x39, 0x25, // pushi 25h (fore) + 0x78, // push1 + 0x39, 0x06, // pushi 06 - sets back to 6 + 0x39, 0x26, // pushi 26 (back) + 0x78, // push1 + 0x78, // push1 - sets back to 1 + 0x39, 0x2a, // pushi 2Ah (font) + 0x78, // push1 + 0x89, 0x16, // lsg global[16h] - sets font to global[16h] + 0x7a, // push2 (y) + 0x78, // push1 + 0x76, // push0 - sets y to 0 + 0x54, SIG_UINT16(0x0018), // self 18h + SIG_END +}; + +static const uint16 kq7PatchSubtitleFix1[] = { + 0x33, 0x12, // jmp [skip special init code] + PATCH_END +}; + +// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English +// Patched method: Narrator::init (script 64928) +static const uint16 kq7SignatureSubtitleFix2[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x12, // and + 0x31, 0x1e, // bnt [skip audio volume code] + 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51) + 0x76, // push0 + 0x81, 0x01, // lag global[1] + 0x4a, 0x04, 0x00, // send 04 + 0x65, 0x32, // aTop curVolume + 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51) + 0x78, // push1 + 0x67, 0x32, // pTos curVolume + 0x35, 0x02, // ldi 02 + 0x06, // mul + 0x36, // push + 0x35, 0x03, // ldi 03 + 0x08, // div + 0x36, // push + 0x81, 0x01, // lag global[1] + 0x4a, 0x06, 0x00, // send 06 + // end of volume code + 0x35, 0x01, // ldi 01 + 0x65, 0x28, // aTop initialized + SIG_END +}; + +static const uint16 kq7PatchSubtitleFix2[] = { + PATCH_ADDTOOFFSET(+5), // skip to bnt + 0x31, 0x1b, // bnt [skip audio volume code] + PATCH_ADDTOOFFSET(+15), // right after "aTop curVolume / pushi masterVolume / push1" + 0x7a, // push2 + 0x06, // mul (saves 3 bytes in total) + 0x36, // push + 0x35, 0x03, // ldi 03 + 0x08, // div + 0x36, // push + 0x81, 0x01, // lag global[1] + 0x4a, 0x06, 0x00, // send 06 + // end of volume code + 0x35, 118, // ldi 118d + 0x65, 0x16, // aTop y + 0x78, // push1 (saves 1 byte) + 0x69, 0x28, // sTop initialized + PATCH_END +}; + +// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English +// Patched method: Narrator::say (script 64928) +static const uint16 kq7SignatureSubtitleFix3[] = { + SIG_MAGICDWORD, + 0x63, 0x28, // pToa initialized + 0x18, // not + 0x31, 0x07, // bnt [skip init code] + 0x38, SIG_ADDTOOFFSET(+2), // pushi init (008Eh for 2.00, 0093h for 1.51) + 0x76, // push0 + 0x54, SIG_UINT16(0x0004), // self 04 + // end of init code + 0x8f, 0x00, // lsp param[0] + 0x35, 0x01, // ldi 01 + 0x1e, // gt? + 0x31, 0x08, // bnt [set acc to 0] + 0x87, 0x02, // lap param[2] + 0x31, 0x04, // bnt [set acc to 0] + 0x87, 0x02, // lap param[2] + 0x33, 0x02, // jmp [over set acc to 0 code] + 0x35, 0x00, // ldi 00 + 0x65, 0x18, // aTop caller + SIG_END +}; + +static const uint16 kq7PatchSubtitleFix3[] = { + PATCH_ADDTOOFFSET(+2), // skip over "pToa initialized code" + 0x2f, 0x0c, // bt [skip init code] - saved 1 byte + 0x38, + PATCH_GETORIGINALBYTE(+6), + PATCH_GETORIGINALBYTE(+7), // pushi (init) + 0x76, // push0 + 0x54, PATCH_UINT16(0x0004), // self 04 + // additionally set background color here (5 bytes) + 0x34, PATCH_UINT16(255), // pushi 255d + 0x65, 0x2e, // aTop back + // end of init code + 0x8f, 0x00, // lsp param[0] + 0x35, 0x01, // ldi 01 - this may get optimized to get another byte + 0x1e, // gt? + 0x31, 0x04, // bnt [set acc to 0] + 0x87, 0x02, // lap param[2] + 0x2f, 0x02, // bt [over set acc to 0 code] + PATCH_END +}; + +// script, description, signature patch +static const SciScriptPatcherEntry kq7Signatures[] = { + { true, 31, "subtitle fix 1/3", 1, kq7SignatureSubtitleFix1, kq7PatchSubtitleFix1 }, + { true, 64928, "subtitle fix 2/3", 1, kq7SignatureSubtitleFix2, kq7PatchSubtitleFix2 }, + { true, 64928, "subtitle fix 3/3", 1, kq7SignatureSubtitleFix3, kq7PatchSubtitleFix3 }, + SCI_SIGNATUREENTRY_TERMINATOR +}; + +// =========================================================================== // Script 210 in the German version of Longbow handles the case where Robin // hands out the scroll to Marion and then types his name using the hand code. // The German version script contains a typo (probably a copy/paste error), @@ -1506,9 +1667,9 @@ static const uint16 longbowPatchShowHandCode[] = { // that's why I rather patched the code, that uses the locals for a lookup. // Which means it doesn't matter anymore when those locals are overwritten. // -// Applies to at least: English PC floppy, German PC floppy (not tested), English Amiga floppy +// Applies to at least: English PC floppy, German PC floppy, English Amiga floppy // Responsible method: export 2 of script 225 -// Fixes bug: #6571 +// Fixes bug: #6751 static const uint16 longbowSignatureBerryBushFix[] = { 0x89, 0x70, // lsg global[70h] 0x35, 0x03, // ldi 03h @@ -4453,6 +4614,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3 case GID_KQ6: signatureTable = kq6Signatures; break; + case GID_KQ7: + signatureTable = kq7Signatures; + break; case GID_LAURABOW: signatureTable = laurabow1Signatures; break; diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index fda78317b5..2c85907628 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -70,9 +70,6 @@ static const uint16 s_halfWidthSJISMap[256] = { EngineState::EngineState(SegManager *segMan) : _segMan(segMan), -#ifdef ENABLE_SCI32 - _virtualIndexFile(0), -#endif _dirseeker() { reset(false); @@ -80,9 +77,6 @@ EngineState::EngineState(SegManager *segMan) EngineState::~EngineState() { delete _msgState; -#ifdef ENABLE_SCI32 - delete _virtualIndexFile; -#endif } void EngineState::reset(bool isRestoring) { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index cf9a753f5c..dd8d76f002 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -131,10 +131,6 @@ public: int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween int16 _lastSaveNewId; // last newly created filename-id by kSaveGame -#ifdef ENABLE_SCI32 - VirtualIndexFile *_virtualIndexFile; -#endif - // see detection.cpp / SciEngine::loadGameState() bool _delayedRestoreGame; // boolean, that triggers delayed restore (triggered by ScummVM menu) int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu) @@ -205,6 +201,7 @@ public: uint16 _memorySegmentSize; byte _memorySegment[kMemorySegmentMax]; + // TODO: Excise video code from the state manager VideoState _videoState; uint16 _vmdPalStart, _vmdPalEnd; bool _syncedAudioOptions; |
