From 87a75ad02bd1a521b51abb90e95c5f26886da245 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Tue, 27 Jul 2021 21:36:38 +0200 Subject: [PATCH] ADL: Add support for more hires2 variants --- engines/adl/adl.cpp | 18 +++++++++++++ engines/adl/adl.h | 1 + engines/adl/adl_v2.cpp | 3 +++ engines/adl/detection.cpp | 42 +++++++++++++++++++++++++++--- engines/adl/hires1.cpp | 21 +-------------- engines/adl/hires2.cpp | 55 ++++++++++++++++++++++----------------- 6 files changed, 93 insertions(+), 47 deletions(-) diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index c1c40415c76..dfea3eac523 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -147,6 +147,24 @@ Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint return readString(stream, until); } +void AdlEngine::extractExeStrings(Common::ReadStream &stream, uint16 printAddr, Common::StringArray &strings) const { + uint32 window = 0; + + for (;;) { + window <<= 8; + window |= stream.readByte(); + + if (stream.eos()) + return; + + if (stream.err()) + error("Failed to extract strings from game executable"); + + if ((window & 0xffffff) == (0x200000U | printAddr)) + strings.push_back(readString(stream)); + } +} + void AdlEngine::printMessage(uint idx) { printString(loadMessage(idx)); } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index f84189b3a69..af6871ce72f 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -269,6 +269,7 @@ protected: virtual void saveState(Common::WriteStream &stream); Common::String readString(Common::ReadStream &stream, byte until = 0) const; Common::String readStringAt(Common::SeekableReadStream &stream, uint offset, byte until = 0) const; + void extractExeStrings(Common::ReadStream &stream, uint16 printAddr, Common::StringArray &strings) const; virtual void printString(const Common::String &str) = 0; virtual Common::String loadMessage(uint idx) const = 0; diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp index e30502eac9e..c4030e2070d 100644 --- a/engines/adl/adl_v2.cpp +++ b/engines/adl/adl_v2.cpp @@ -568,6 +568,9 @@ int AdlEngine_v2::o_tellTime(ScriptEnv &e) { Common::String time = _strings_v2.time; + if (time.size() <= 16) + error("Invalid time string"); + const char zeroChar = _display->asciiToNative('0'); time.setChar(zeroChar + _state.time.hours / 10, 12); diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index 83bae4f8d68..1ac5217d53c 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -277,9 +277,45 @@ static const AdlGameDescription gameDiskDescriptions[] = { GAME_TYPE_HIRES1, GAME_VER_HR1_PD }, + { // Hi-Res Adventure #2: Wizard and the Princess - Apple II - DOS 3.2 only + { + "hires2", "On-Line Systems [A]", + AD_ENTRY1s("wizard", "5201c87db24ba7e3fa447471f4f2ec99", 116480), + Common::EN_ANY, + Common::kPlatformApple2, + ADGF_NO_FLAGS, + DEFAULT_OPTIONS + }, + GAME_TYPE_HIRES2, + GAME_VER_NONE + }, + { // Hi-Res Adventure #2: Wizard and the Princess - Apple II + { + "hires2", "On-Line Systems [B]", + AD_ENTRY1s("wizard", "1de984859212ff11cf61b29cb9b55f8c", 116480), + Common::EN_ANY, + Common::kPlatformApple2, + ADGF_NO_FLAGS, + DEFAULT_OPTIONS + }, + GAME_TYPE_HIRES2, + GAME_VER_NONE + }, + { // Hi-Res Adventure #2: Wizard and the Princess - Apple II - Green Valley Publishing + { + "hires2", "Green Valley [A]", + AD_ENTRY1s("wizard", "73cd373e9a2946c3181b72fdf7a32c77", 143360), + Common::EN_ANY, + Common::kPlatformApple2, + ADGF_NO_FLAGS, + DEFAULT_OPTIONS + }, + GAME_TYPE_HIRES2, + GAME_VER_NONE + }, { // Hi-Res Adventure #2: Wizard and the Princess - Apple II - Roberta Williams Anthology { - "hires2", "", + "hires2", "Green Valley [B]", AD_ENTRY1s("wizard", "72b114bf8f94fafe5672daac2a70c765", 143360), Common::EN_ANY, Common::kPlatformApple2, @@ -375,7 +411,7 @@ static const AdlGameDescription gameDiskDescriptions[] = { }, { // Hi-Res Adventure #6: The Dark Crystal - Apple II - Roberta Williams Anthology / SierraVenture { - "hires6", "SierraVenture [version A]", + "hires6", "SierraVenture [A]", { { "dark1a", 0, "9a5968a8f378c84454d88f4cd4e143a9", 143360 }, { "dark1b", 3, "1271ff9c3e1bdb4942301dd37dd0ef87", 143360 }, @@ -393,7 +429,7 @@ static const AdlGameDescription gameDiskDescriptions[] = { }, { // Hi-Res Adventure #6: The Dark Crystal - Apple II - SierraVenture { - "hires6", "SierraVenture [version B]", + "hires6", "SierraVenture [B]", { { "dark1a", 0, "d0b8e808b02564b6ce58b5ea5cc61ead", 143360 }, { "dark1b", 3, "1271ff9c3e1bdb4942301dd37dd0ef87", 143360 }, diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 3ebb905c2ee..58ea0346a08 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -90,7 +90,6 @@ protected: void loadRoom(byte roomNr) override; void showRoom() override; - void extractExeStrings(Common::ReadStream &stream, Common::StringArray &strings); void showInstructions(Common::SeekableReadStream &stream); void wordWrap(Common::String &str) const; @@ -108,24 +107,6 @@ protected: } _gameStrings; }; -void HiRes1Engine::extractExeStrings(Common::ReadStream &stream, Common::StringArray &strings) { - uint32 window = 0; - - for (;;) { - window <<= 8; - window |= stream.readByte(); - - if (stream.eos()) - return; - - if (stream.err()) - error("Failed to extract strings from game executable"); - - if ((window & 0xffffff) == 0x201576) - strings.push_back(readString(stream)); - } -} - void HiRes1Engine::showInstructions(Common::SeekableReadStream &stream) { _display->setMode(Display::kModeText); @@ -301,7 +282,7 @@ void HiRes1Engine::init() { StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1)); Common::StringArray exeStrings; - extractExeStrings(*stream, exeStrings); + extractExeStrings(*stream, 0x1576, exeStrings); if (exeStrings.size() != 18) error("Failed to load strings from executable"); diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp index 6db3c9e0b24..34e9aecca43 100644 --- a/engines/adl/hires2.cpp +++ b/engines/adl/hires2.cpp @@ -70,28 +70,37 @@ void HiResBaseEngine::init() { StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 4)); loadMessages(*stream, _numMsgs); - // Read parser messages - stream.reset(_disk->createReadStream(0x1a, 0x1)); - _strings.verbError = readStringAt(*stream, 0x4f); - _strings.nounError = readStringAt(*stream, 0x8e); - _strings.enterCommand = readStringAt(*stream, 0xbc); + stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 25, 13)); + Common::StringArray exeStrings; + extractExeStrings(*stream, 0x1566, exeStrings); - // Read time string - stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7)); - _strings_v2.time = readString(*stream, 0xff); + if (exeStrings.size() < 11) + error("Failed to load strings from executable"); + + // Heuristic to test for early versions that differ slightly + // Later versions have two additional strings for "INIT DISK" + const bool oldEngine = exeStrings.size() < 13; + + // Read parser messages + _strings.verbError = exeStrings[2]; + _strings.nounError = exeStrings[3]; + _strings.enterCommand = exeStrings[4]; + + if (!oldEngine) { + stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7)); + _strings_v2.time = readString(*stream, 0xff); + } // Read line feeds - stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1)); - _strings.lineFeeds = readString(*stream); + _strings.lineFeeds = exeStrings[0]; // Read opcode strings - stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2)); - _strings_v2.saveInsert = readStringAt(*stream, 0x5f); - _strings_v2.saveReplace = readStringAt(*stream, 0xe5); - _strings_v2.restoreInsert = readStringAt(*stream, 0x132); - _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2); - _strings.playAgain = readStringAt(*stream, 0x225); - _strings.pressReturn = readStringAt(*stream, 0x25f); + _strings_v2.saveInsert = exeStrings[5]; + _strings_v2.saveReplace = exeStrings[6]; + _strings_v2.restoreInsert = exeStrings[7]; + _strings_v2.restoreReplace = exeStrings[8]; + _strings.playAgain = exeStrings[9]; + _strings.pressReturn = exeStrings[10]; // Load global picture data stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0)); @@ -105,7 +114,7 @@ void HiResBaseEngine::init() { stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 4)); readCommands(*stream, _roomCommands); - stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 3)); + stream.reset(_disk->createReadStream((oldEngine ? 0x19 : 0x1f), 0x7, 0x00, 3)); readCommands(*stream, _globalCommands); // Load dropped item offsets @@ -151,10 +160,10 @@ HiRes2Engine::HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : } void HiRes2Engine::runIntro() { - // This only works for the 16-sector re-release. The original - // release is not supported at this time, because we don't have - // access to it. - _disk->setSectorLimit(0); + // Only the Green Valley version has a title screen + if (_disk->getSectorsPerTrack() != 16) + return; + StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1)); _display->setMode(Display::kModeText); @@ -166,8 +175,6 @@ void HiRes2Engine::runIntro() { _display->printString(str); delay(2000); - - _disk->setSectorLimit(13); } class HiRes3Engine : public HiResBaseEngine {