From 8ef1b1b362e6d7bcc2fa378bc15bf09b6c86926b Mon Sep 17 00:00:00 2001 From: Marisa-Chan Date: Fri, 26 Dec 2025 15:08:10 +0700 Subject: [PATCH] GAMOS: Add support loading games with engine version 0x12 and 0x0b --- file.cpp | 25 +++++++++--- file.h | 6 +++ gamos.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++------------ gamos.h | 2 + proc.cpp | 60 ++++++++++++++-------------- 5 files changed, 149 insertions(+), 58 deletions(-) diff --git a/file.cpp b/file.cpp index 1210fbf..6638568 100644 --- a/file.cpp +++ b/file.cpp @@ -37,7 +37,9 @@ bool Archive::open(const Common::Path &name) { seek(-12, SEEK_END); - _dirOffset = 12 + readUint32LE(); + const uint32 dirInfSize = readUint32LE(); + + _dirOffset = 12 + dirInfSize; skip(4); uint32 magic = readUint32LE(); @@ -46,8 +48,16 @@ bool Archive::open(const Common::Path &name) { seek(-_dirOffset, SEEK_END); - _dirCount = readUint32LE(); - _dataOffset = readUint32LE(); + byte tmpbuf[8] = {0, 0 ,0, 0, 0, 0, 0, 0}; + + /* read it into buffer firs, because it's can be less than 8 bytes */ + if (dirInfSize > 8) + read(tmpbuf, 8); + else + read(tmpbuf, dirInfSize); + + _dirCount = READ_LE_UINT32(tmpbuf); + _dataOffset = READ_LE_UINT32(tmpbuf + 4); seek(-(_dirOffset + _dirCount * 5), SEEK_END); @@ -141,12 +151,17 @@ bool Archive::readCompressedData(RawData *out) { /* read size */ const byte szsize = (t & 3) + 1; + if (_version == 0xb) + skip(szsize); + /* big data size */ for (uint i = 0; i < szsize; ++i) _lastReadSize |= readByte() << (i << 3); /* is compressed */ - if (t & 0xC) { + if (_version == 0xb) { + skip(szsize + 1); + } else if (t & 0xC) { for (uint i = 0; i < szsize; ++i) _lastReadDecompressedSize |= readByte() << (i << 3); } @@ -159,7 +174,7 @@ bool Archive::readCompressedData(RawData *out) { out->resize(_lastReadSize); read(out->data(), _lastReadSize); - if (!_lastReadDecompressedSize) + if (!_lastReadDecompressedSize || _version != 0x18) return true; /* looks hacky but we just allocate array for decompressed and swap it with compressed */ diff --git a/file.h b/file.h index 1b2d2a9..f03fedf 100644 --- a/file.h +++ b/file.h @@ -61,6 +61,10 @@ public: static void decompress(RawData const *in, RawData *out); + void setVersion(int v) { + _version = v; + } + public: uint32 _lastReadSize = 0; @@ -76,6 +80,8 @@ private: Common::Array _directories; + int _version = 0x18; + //bool _error; }; diff --git a/gamos.cpp b/gamos.cpp index af0d8f3..76d4e7a 100644 --- a/gamos.cpp +++ b/gamos.cpp @@ -86,6 +86,10 @@ Common::Error GamosEngine::run() { else setCP1252(); + _engineVersion = getEngineVersion() & 0xFF; + + _arch.setVersion(_engineVersion); + init(getRunFile()); Common::Event e; @@ -564,30 +568,43 @@ bool GamosEngine::initMainDatas() { } /* skip count of pages 1kb size */ - dataStream.skip(4); - /* skip read buffer size */ - dataStream.skip(4); - _width = dataStream.readUint32LE(); - _height = dataStream.readUint32LE(); - _gridCellW = dataStream.readSint32LE(); - _gridCellH = dataStream.readSint32LE(); - _movieCount = dataStream.readUint32LE(); - dataStream.skip(3); // skip unknown unused - _fps = dataStream.readByte(); - dataStream.skip(1); // skip unknown unused - _drawCursor = dataStream.readByte(); - _fadeEffectID = dataStream.readByte(); - _playIntro = dataStream.readByte(); + dataStream.skip(4); // 4 + if (_engineVersion >= 0x12) { + /* skip read buffer size */ + dataStream.skip(4); // 8 + } + _width = dataStream.readUint32LE(); // c + _height = dataStream.readUint32LE(); // 10 + _gridCellW = dataStream.readSint32LE(); // 14 + _gridCellH = dataStream.readSint32LE(); // 18 + _movieCount = dataStream.readUint32LE(); // 1c + dataStream.skip(3); // skip unknown unused 20 + _fps = dataStream.readByte(); // 23 + dataStream.skip(1); // skip unknown unused 24 + _drawCursor = dataStream.readByte(); // 25 - _introPos.x = dataStream.readSint32LE(); - _introPos.y = dataStream.readSint32LE(); - _introSize.x = dataStream.readSint32LE(); - _introSize.y = dataStream.readSint32LE(); + if (_engineVersion >= 0x12) { + _fadeEffectID = dataStream.readByte(); // 26 + _playIntro = dataStream.readByte(); // 27 + } else { + _playIntro = dataStream.readByte(); + _fadeEffectID = dataStream.readByte(); + } - int64 pos = dataStream.pos(); - _string1 = dataStream.readString(0, 64); - dataStream.seek(pos + 64); - _winCaption = dataStream.readString(0, 9); + if (_engineVersion >= 0x12) { + _introPos.x = dataStream.readSint32LE(); // 28 + _introPos.y = dataStream.readSint32LE(); // 2c + _introSize.x = dataStream.readSint32LE(); // 30 + _introSize.y = dataStream.readSint32LE(); // 34 + + int64 pos = dataStream.pos(); + _string1 = dataStream.readString(0, 64); // 38 + dataStream.seek(pos + 64); + } else { + _string1 = ""; + } + + _winCaption = dataStream.readString(0, 32); // 78 if (!_screen) { initGraphics(_width, _height); @@ -1085,7 +1102,7 @@ void GamosEngine::readData2(const RawData &data) { //warning("Game data size %d", data.size()); - if (getEngineVersion() == 0x80000018) { + if (_engineVersion == 0x18) { _stateExt = dataStream.readString(0, 4); // FIX ME dataStream.seek(4); _messageProc._inputFlags = dataStream.readByte(); //4 @@ -1121,7 +1138,7 @@ void GamosEngine::readData2(const RawData &data) { for (int i = 0; i < 12; i++) { _messageProc._keyCodes[i] = dataStream.readByte(); } - } else if (getEngineVersion() == 0x80000016) { + } else if (_engineVersion >= 0x12 && _engineVersion <= 0x16) { _stateExt = dataStream.readString(0, 4); // FIX ME dataStream.seek(4); _messageProc._inputFlags = dataStream.readByte(); //4 @@ -1156,6 +1173,52 @@ void GamosEngine::readData2(const RawData &data) { for (int i = 0; i < 12; i++) { _messageProc._keyCodes[i] = dataStream.readByte(); } + } else if (_engineVersion == 0xb) { + _stateExt = dataStream.readString(0, 4); // FIX ME + dataStream.seek(4); + _messageProc._inputFlags = dataStream.readByte(); //4 + dataStream.seek(8); + _svModuleId = dataStream.readSint32LE(); // 8 + _svGameScreen = dataStream.readSint32LE(); // c + _d2_fld10 = dataStream.readUint32LE(); // 10 + _enableSounds = dataStream.readByte() != 0 ? true : false; // x14 + _enableMidi = dataStream.readByte() != 0 ? true : false; //x15 + _enableInput = dataStream.readByte() != 0 ? true : false; // x16 + _enableMovie = dataStream.readByte() != 0 ? true : false; // x17 + _enableCDAudio = false; + _cdAudioTrack = -1; + _scrollX = 0; + _scrollY = 0; + _scrollTrackObj = -1; + _scrollSpeed = 16; + _scrollCutoff = 80; + _scrollSpeedReduce = -1; + _scrollBorderL = 0; + _scrollBorderR = 0; + _scrollBorderU = 0; + _scrollBorderB = 0; + _sndChannels = dataStream.readByte(); // x18 + _sndVolume = dataStream.readByte(); // x19 + _midiVolume = dataStream.readByte(); // x1a + _svFps = dataStream.readByte(); // x1b + _svFrame = dataStream.readSint32LE(); // x1c + _midiTrack = dataStream.readUint32LE(); // x20 + _mouseCursorImgId = dataStream.readSint32LE(); // x24 + //0x28 + + _messageProc._keyCodes[0] = KeyCodes::WIN_UP; + _messageProc._keyCodes[1] = KeyCodes::WIN_PRIOR; + _messageProc._keyCodes[2] = KeyCodes::WIN_RIGHT; + _messageProc._keyCodes[3] = KeyCodes::WIN_NEXT; + _messageProc._keyCodes[4] = KeyCodes::WIN_DOWN; + _messageProc._keyCodes[5] = KeyCodes::WIN_END; + _messageProc._keyCodes[6] = KeyCodes::WIN_LEFT; + _messageProc._keyCodes[7] = KeyCodes::WIN_HOME; + _messageProc._keyCodes[8] = KeyCodes::WIN_SPACE; + _messageProc._keyCodes[9] = KeyCodes::WIN_RETURN; + _messageProc._keyCodes[10] = KeyCodes::WIN_TAB; + _messageProc._keyCodes[11] = KeyCodes::WIN_INVALID; + _messageProc._keyCodes[12] = KeyCodes::WIN_INVALID; } } @@ -2292,6 +2355,9 @@ uint32 GamosEngine::doScript(uint32 scriptAddress) { void GamosEngine::vmCallDispatcher(VM::Context *ctx, uint32 funcID) { uint32 arg1 = 0, arg2 = 0; + if (_engineVersion <= 0x12 && funcID >= 47) // skip 47 func for old versions + funcID++; + switch (funcID) { case 0: _restartUpdateObject = true; diff --git a/gamos.h b/gamos.h index caadf3d..4a459de 100644 --- a/gamos.h +++ b/gamos.h @@ -594,6 +594,8 @@ private: bool _needReload = false; + uint32 _engineVersion = 0x18; + protected: // Engine APIs Common::Error run() override; diff --git a/proc.cpp b/proc.cpp index ebc1585..e920a17 100644 --- a/proc.cpp +++ b/proc.cpp @@ -45,36 +45,38 @@ void SystemProc::processMessage(const Common::Event &ev) { if (_rawKeyCode == 0) _rawKeyCode = ACT_NONE; - if (winKey == _keyCodes[0]) - _act1 = 0; - else if (winKey == _keyCodes[1]) - _act1 = 1; - else if (winKey == _keyCodes[2]) - _act1 = 2; - else if (winKey == _keyCodes[3]) - _act1 = 3; - else if (winKey == _keyCodes[4]) - _act1 = 4; - else if (winKey == _keyCodes[5]) - _act1 = 5; - else if (winKey == _keyCodes[6]) - _act1 = 6; - else if (winKey == _keyCodes[7]) - _act1 = 7; - else { - if (winKey == _keyCodes[8]) - _act2 = ACT2_MOUSEUP_L; - else if (winKey == _keyCodes[9]) - _act2 = ACT2_MOUSEUP_R; - else if (winKey == _keyCodes[10]) - _act2 = ACT2_TAB; - else if (winKey == _keyCodes[11]) - _act2 = ACT2_HELP; - else - return; + if (winKey != KeyCodes::WIN_INVALID) { + if (winKey == _keyCodes[0]) + _act1 = 0; + else if (winKey == _keyCodes[1]) + _act1 = 1; + else if (winKey == _keyCodes[2]) + _act1 = 2; + else if (winKey == _keyCodes[3]) + _act1 = 3; + else if (winKey == _keyCodes[4]) + _act1 = 4; + else if (winKey == _keyCodes[5]) + _act1 = 5; + else if (winKey == _keyCodes[6]) + _act1 = 6; + else if (winKey == _keyCodes[7]) + _act1 = 7; + else { + if (winKey == _keyCodes[8]) + _act2 = ACT2_MOUSEUP_L; + else if (winKey == _keyCodes[9]) + _act2 = ACT2_MOUSEUP_R; + else if (winKey == _keyCodes[10]) + _act2 = ACT2_TAB; + else if (winKey == _keyCodes[11]) + _act2 = ACT2_HELP; + else + return; - _rawKeyCode = winKey; - return; + _rawKeyCode = winKey; + return; + } } if ((_act1 < 8) && (ev.kbd.flags & Common::KBD_SHIFT))