[Scummvm-git-logs] scummvm master -> 5f6c88ef15ff3e82178dab8fffbfc08b677cb100

waltervn walter at vanniftrik-it.nl
Fri Jul 23 23:10:51 UTC 2021


This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
28e049e8d6 ADL: Require C++11
ce2742a828 ADL: Add detection entry for early hires1
eb6751a055 ADL: Try VTOC track 0x10 if 0x11 fails
960811fc55 ADL: Add support for another early hires1
f32dde20bd ADL: Scan for executable strings in hires1
56390d5f5f ADL: Add support for hires1 french (early version)
e8dd3b7085 ADL: Add delay after printing strings in hires1
01e6ec1649 ADL: Use slot 15 for autosave
5f6c88ef15 ADL: Add support for later French hires1


Commit: 28e049e8d6edb50152478b42713116215b95fb80
    https://github.com/scummvm/scummvm/commit/28e049e8d6edb50152478b42713116215b95fb80
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Require C++11

Changed paths:
    engines/adl/configure.engine


diff --git a/engines/adl/configure.engine b/engines/adl/configure.engine
index c138b64943..4868e8d996 100644
--- a/engines/adl/configure.engine
+++ b/engines/adl/configure.engine
@@ -1,3 +1,3 @@
 # This file is included from the main "configure" script
 # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine adl "ADL" yes "" "" "16bit highres"
+add_engine adl "ADL" yes "" "" "cxx11 16bit highres"


Commit: ce2742a828814900dabfd6ee7089d4694ecab8a4
    https://github.com/scummvm/scummvm/commit/ce2742a828814900dabfd6ee7089d4694ecab8a4
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Add detection entry for early hires1

Changed paths:
    engines/adl/detection.cpp
    engines/adl/hires1.cpp


diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 5fab9057c7..693efaef51 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -169,6 +169,18 @@ static const AdlGameDescription gameFileDescriptions[] = {
 };
 
 static const AdlGameDescription gameDiskDescriptions[] = {
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Simi Valley address
+		{
+			"hires1", "",
+			AD_ENTRY1s("mysthous", "629b9d034cbf8d8e3a612398f53a8dfc", 116480),
+			Common::EN_ANY,
+			Common::kPlatformApple2,
+			ADGF_NO_FLAGS,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_SIMI
+	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Coarsegold address
 		{
 			"hires1", "",
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 0eae793d48..8f6a9248fa 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -262,8 +262,8 @@ void HiRes1Engine::init() {
 		_files = new Files_Plain();
 	} else {
 		Files_AppleDOS *files = new Files_AppleDOS();
-		// The 2nd release obfuscates the VTOC (same may be true for the 1st release)
-		if (!files->open(getDiskImageName(0), (getGameVersion() == GAME_VER_HR1_COARSE ? 16 : 17)))
+		// Non-PD versions have an obfuscated VTOC
+		if (!files->open(getDiskImageName(0), (getGameVersion() == GAME_VER_HR1_PD ? 17 : 16)))
 			error("Failed to open '%s'", getDiskImageName(0).c_str());
 		_files = files;
 	}


Commit: eb6751a055abe4400c0fe06415b527389ffcf99b
    https://github.com/scummvm/scummvm/commit/eb6751a055abe4400c0fe06415b527389ffcf99b
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Try VTOC track 0x10 if 0x11 fails

Changed paths:
    engines/adl/disk.cpp
    engines/adl/disk.h
    engines/adl/hires1.cpp


diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
index 4c3c450ad5..dd241e587c 100644
--- a/engines/adl/disk.cpp
+++ b/engines/adl/disk.cpp
@@ -684,10 +684,21 @@ void Files_AppleDOS::readSectorList(TrackSector start, Common::Array<TrackSector
 	}
 }
 
-void Files_AppleDOS::readVTOC(uint trackVTOC) {
-	Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(trackVTOC, 0x00));
+void Files_AppleDOS::readVTOC() {
+	Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(0x11, 0x00));
 	stream->readByte();
 	byte track = stream->readByte();
+
+	if (!track) {
+		// VTOC probably obfuscated, try track 0x10
+		stream.reset(_disk->createReadStream(0x10, 0x00));
+		stream->readByte();
+		track = stream->readByte();
+	}
+
+	if (!track)
+		error("VTOC not found");
+
 	byte sector = stream->readByte();
 
 	while (track != 0) {
@@ -815,12 +826,12 @@ Common::SeekableReadStream *Files_AppleDOS::createReadStream(const Common::Strin
 	return new Common::SeekableSubReadStream(stream, offset, stream->size(), DisposeAfterUse::YES);
 }
 
-bool Files_AppleDOS::open(const Common::String &filename, uint trackVTOC) {
+bool Files_AppleDOS::open(const Common::String &filename) {
 	_disk = new DiskImage();
 	if (!_disk->open(filename))
 		return false;
 
-	readVTOC(trackVTOC);
+	readVTOC();
 	return true;
 }
 
diff --git a/engines/adl/disk.h b/engines/adl/disk.h
index 4de23e9aea..8759e7efe1 100644
--- a/engines/adl/disk.h
+++ b/engines/adl/disk.h
@@ -134,7 +134,7 @@ public:
 	Files_AppleDOS();
 	~Files_AppleDOS() override;
 
-	bool open(const Common::String &filename, uint trackVTOC = 17);
+	bool open(const Common::String &filename);
 	const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const override;
 	Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const override;
 
@@ -161,7 +161,7 @@ private:
 		Common::Array<TrackSector> sectors;
 	};
 
-	void readVTOC(uint trackVTOC);
+	void readVTOC();
 	void readSectorList(TrackSector start, Common::Array<TrackSector> &list);
 	Common::SeekableReadStream *createReadStreamText(const TOCEntry &entry) const;
 	Common::SeekableReadStream *createReadStreamBinary(const TOCEntry &entry) const;
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 8f6a9248fa..c29547043e 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -262,8 +262,7 @@ void HiRes1Engine::init() {
 		_files = new Files_Plain();
 	} else {
 		Files_AppleDOS *files = new Files_AppleDOS();
-		// Non-PD versions have an obfuscated VTOC
-		if (!files->open(getDiskImageName(0), (getGameVersion() == GAME_VER_HR1_PD ? 17 : 16)))
+		if (!files->open(getDiskImageName(0)))
 			error("Failed to open '%s'", getDiskImageName(0).c_str());
 		_files = files;
 	}


Commit: 960811fc554656acfbdf18ca90005102c2208a19
    https://github.com/scummvm/scummvm/commit/960811fc554656acfbdf18ca90005102c2208a19
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Add support for another early hires1

Changed paths:
    engines/adl/detection.cpp
    engines/adl/hires1.cpp


diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 693efaef51..c47f7c3fe6 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -116,9 +116,9 @@ static const PlainGameDescriptor adlGames[] = {
 };
 
 static const AdlGameDescription gameFileDescriptions[] = {
-	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Simi Valley address
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Simi Valley
 		{
-			"hires1", 0,
+			"hires1", "V1",
 			{
 				{ "ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952 },
 				{ "AUTO LOAD OBJ", 0, "a2ab7be25842e1fa9f1343b0894a8b6f", 4095 },
@@ -132,9 +132,25 @@ static const AdlGameDescription gameFileDescriptions[] = {
 		GAME_TYPE_HIRES1,
 		GAME_VER_HR1_SIMI
 	},
-	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Coarsegold address
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - Without MIXEDON
 		{
-			"hires1", 0,
+			"hires1", "V2",
+			{
+				{ "ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952 },
+				{ "AUTO LOAD OBJ", 0, "669b5f313ffdfb373ab8dce5961688d3", 12288 },
+				AD_LISTEND
+			},
+			Common::EN_ANY,
+			Common::kPlatformApple2,
+			ADGF_NO_FLAGS,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_COARSE
+	},
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - With MIXEDON
+		{
+			"hires1", "V3",
 			{
 				{ "ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952 },
 				{ "AUTO LOAD OBJ", 0, "f6a6ac60c04c6ba6dff68b92cc279ba2", 12291 },
@@ -169,9 +185,9 @@ static const AdlGameDescription gameFileDescriptions[] = {
 };
 
 static const AdlGameDescription gameDiskDescriptions[] = {
-	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Simi Valley address
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Simi Valley
 		{
-			"hires1", "",
+			"hires1", "V1",
 			AD_ENTRY1s("mysthous", "629b9d034cbf8d8e3a612398f53a8dfc", 116480),
 			Common::EN_ANY,
 			Common::kPlatformApple2,
@@ -181,9 +197,21 @@ static const AdlGameDescription gameDiskDescriptions[] = {
 		GAME_TYPE_HIRES1,
 		GAME_VER_HR1_SIMI
 	},
-	{ // Hi-Res Adventure #1: Mystery House - Apple II - Contains Coarsegold address
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - Without MIXEDON
+		{
+			"hires1", "V2",
+			AD_ENTRY1s("mysthous", "b22561b5327c7dcdb659e2d649749310", 116480),
+			Common::EN_ANY,
+			Common::kPlatformApple2,
+			ADGF_NO_FLAGS,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_COARSE
+	},
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - With MIXEDON
 		{
-			"hires1", "",
+			"hires1", "V3",
 			AD_ENTRY1s("mysthous", "8df0b3b3e609a2e40237e2419c1cb767", 116480),
 			Common::EN_ANY,
 			Common::kPlatformApple2,
@@ -195,7 +223,7 @@ static const AdlGameDescription gameDiskDescriptions[] = {
 	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Roberta Williams Anthology
 		{
-			"hires1", "",
+			"hires1", "PD",
 			AD_ENTRY1s("mysthous", "54d20eb1ef0084ac3c2d16c31c5b7eb7", 143360),
 			Common::EN_ANY,
 			Common::kPlatformApple2,
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index c29547043e..9a8f149739 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -68,11 +68,6 @@ namespace Adl {
 #define IDI_HR1_OFS_PD_TEXT_2    0x016d
 #define IDI_HR1_OFS_PD_TEXT_3    0x0259
 
-#define IDI_HR1_OFS_INTRO_TEXT   0x0066
-#define IDI_HR1_OFS_GAME_OR_HELP 0x000f
-
-#define IDI_HR1_OFS_LOGO_0       0x1003
-
 #define IDI_HR1_OFS_ITEMS        0x0100
 #define IDI_HR1_OFS_ROOMS        0x050a
 #define IDI_HR1_OFS_PICS         0x4b03
@@ -108,7 +103,7 @@ private:
 	void loadRoom(byte roomNr) override;
 	void showRoom() override;
 
-	void showInstructions(Common::SeekableReadStream &stream, const uint pages[], bool goHome);
+	void showInstructions(Common::SeekableReadStream &stream);
 	void wordWrap(Common::String &str) const;
 
 	Files *_files;
@@ -125,26 +120,43 @@ private:
 	} _gameStrings;
 };
 
-void HiRes1Engine::showInstructions(Common::SeekableReadStream &stream, const uint pages[], bool goHome) {
+void HiRes1Engine::showInstructions(Common::SeekableReadStream &stream) {
 	_display->setMode(Display::kModeText);
 
-	uint page = 0;
-	while (pages[page] != 0) {
-		if (goHome)
+	for (;;) {
+		byte opc = stream.readByte();
+
+		if (opc != 0x20)
+			error("Error reading instructions");
+
+		uint16 addr = stream.readUint16BE();
+
+		if (addr == 0x58fc) {
+			// HOME
 			_display->home();
+		} else if (addr == 0x6ffd) {
+			// GETLN1
+			inputString();
 
-		uint count = pages[page++];
-		for (uint i = 0; i < count; ++i) {
-			_display->printString(readString(stream));
-			stream.seek(3, SEEK_CUR);
-		}
+			if (shouldQuit())
+				return;
+		} else {
+			// We assume print string call (addr varies per game)
+			Common::String str = readString(stream);
 
-		inputString();
+			if (stream.err() || stream.eos())
+				error("Error reading instructions");
 
-		if (shouldQuit())
-			return;
+			// Ctrl-D signifies system command (main binary would be loaded here)
+			size_t posChr4 = str.findFirstOf(_display->asciiToNative(4));
+
+			if (posChr4 != str.npos) {
+				_display->printString(str.substr(0, posChr4));
+				return;
+			}
 
-		stream.seek((goHome ? 6 : 3), SEEK_CUR);
+			_display->printString(str);
+		}
 	}
 }
 
@@ -153,7 +165,12 @@ void HiRes1Engine::runIntro() {
 
 	// Early version have no bitmap in 'AUTO LOAD OBJ'
 	if (getGameVersion() >= GAME_VER_HR1_COARSE) {
-		stream->seek(IDI_HR1_OFS_LOGO_0);
+		// Later binaries have a MIXEDON prepended to it, by skipping it
+		// we can use the same offsets for both variants
+		if (stream->readUint16BE() == 0xad53)
+			stream.reset(_files->createReadStream(IDS_HR1_EXE_0, 3));
+
+		stream->seek(0x1000);
 		_display->setMode(Display::kModeGraphics);
 		static_cast<Display_A2 *>(_display)->loadFrameBuffer(*stream);
 		_display->renderGraphics();
@@ -199,7 +216,7 @@ void HiRes1Engine::runIntro() {
 
 	_display->setMode(Display::kModeMixed);
 
-	str = readStringAt(*stream, IDI_HR1_OFS_GAME_OR_HELP);
+	str = readStringAt(*stream, 0xc);
 
 	if (getGameVersion() >= GAME_VER_HR1_COARSE) {
 		bool instructions = false;
@@ -223,17 +240,16 @@ void HiRes1Engine::runIntro() {
 		}
 
 		if (instructions) {
-			// This version shows the last page during the loading of the game
-			// We wait for a key instead (even though there's no prompt for that).
-			const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 };
-			stream->seek(IDI_HR1_OFS_INTRO_TEXT);
-			showInstructions(*stream, pages, true);
+			stream->seek(0x5d);
+			showInstructions(*stream);
 			_display->printAsciiString("\r");
 		}
 	} else {
-		const uint pages[] = { 6, 6, 8, 6, 0 };
-		stream->seek(6);
-		showInstructions(*stream, pages, false);
+		// This version shows the last page during the loading of the game
+		// We wait for a key instead (even though there's no prompt for that).
+		stream->seek(3);
+		showInstructions(*stream);
+		inputString();
 	}
 
 	stream.reset(_files->createReadStream(IDS_HR1_EXE_1));


Commit: f32dde20bdba851dc54556ad4ce9fbf2ae9c52ab
    https://github.com/scummvm/scummvm/commit/f32dde20bdba851dc54556ad4ce9fbf2ae9c52ab
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Scan for executable strings in hires1

Changed paths:
    engines/adl/adl.cpp
    engines/adl/adl.h
    engines/adl/hires1.cpp


diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index 5ce0c20b6c..b1b7eeb8ec 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -145,11 +145,6 @@ Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint
 	return readString(stream, until);
 }
 
-void AdlEngine::openFile(Common::File &file, const Common::String &name) const {
-	if (!file.open(name))
-		error("Error opening '%s'", name.c_str());
-}
-
 void AdlEngine::printMessage(uint idx) {
 	printString(loadMessage(idx));
 }
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 5442c89e31..28c827c90a 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -266,7 +266,6 @@ 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 openFile(Common::File &file, const Common::String &name) const;
 
 	virtual void printString(const Common::String &str) = 0;
 	virtual Common::String loadMessage(uint idx) const = 0;
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 9a8f149739..0ee483d567 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -52,17 +52,6 @@ namespace Adl {
 #define IDI_HR1_MSG_DONT_HAVE_IT       127
 #define IDI_HR1_MSG_GETTING_DARK         7
 
-#define IDI_HR1_OFS_STR_ENTER_COMMAND   0x5bbc
-#define IDI_HR1_OFS_STR_VERB_ERROR      0x5b4f
-#define IDI_HR1_OFS_STR_NOUN_ERROR      0x5b8e
-#define IDI_HR1_OFS_STR_PLAY_AGAIN      0x5f1e
-#define IDI_HR1_OFS_STR_CANT_GO_THERE   0x6c0a
-#define IDI_HR1_OFS_STR_DONT_HAVE_IT    0x6c31
-#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51
-#define IDI_HR1_OFS_STR_GETTING_DARK    0x6c7c
-#define IDI_HR1_OFS_STR_PRESS_RETURN    0x5f68
-#define IDI_HR1_OFS_STR_LINE_FEEDS      0x59d4
-
 #define IDI_HR1_OFS_PD_TEXT_0    0x005d
 #define IDI_HR1_OFS_PD_TEXT_1    0x012b
 #define IDI_HR1_OFS_PD_TEXT_2    0x016d
@@ -103,6 +92,7 @@ private:
 	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;
 
@@ -120,6 +110,24 @@ private:
 	} _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);
 
@@ -288,19 +296,25 @@ void HiRes1Engine::init() {
 
 	StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1));
 
+	Common::StringArray exeStrings;
+	extractExeStrings(*stream, exeStrings);
+
+	if (exeStrings.size() != 18)
+		error("Failed to load strings from executable");
+
 	// Some messages have overrides inside the executable
-	_gameStrings.cantGoThere = readStringAt(*stream, IDI_HR1_OFS_STR_CANT_GO_THERE);
-	_gameStrings.dontHaveIt = readStringAt(*stream, IDI_HR1_OFS_STR_DONT_HAVE_IT);
-	_gameStrings.dontUnderstand = readStringAt(*stream, IDI_HR1_OFS_STR_DONT_UNDERSTAND);
-	_gameStrings.gettingDark = readStringAt(*stream, IDI_HR1_OFS_STR_GETTING_DARK);
+	_gameStrings.cantGoThere = exeStrings[12];
+	_gameStrings.dontHaveIt = exeStrings[13];
+	_gameStrings.dontUnderstand = exeStrings[14];
+	_gameStrings.gettingDark = exeStrings[15];
 
 	// Load other strings from executable
-	_strings.enterCommand = readStringAt(*stream, IDI_HR1_OFS_STR_ENTER_COMMAND);
-	_strings.verbError = readStringAt(*stream, IDI_HR1_OFS_STR_VERB_ERROR);
-	_strings.nounError = readStringAt(*stream, IDI_HR1_OFS_STR_NOUN_ERROR);
-	_strings.playAgain = readStringAt(*stream, IDI_HR1_OFS_STR_PLAY_AGAIN);
-	_strings.pressReturn = readStringAt(*stream, IDI_HR1_OFS_STR_PRESS_RETURN);
-	_strings.lineFeeds = readStringAt(*stream, IDI_HR1_OFS_STR_LINE_FEEDS);
+	_strings.enterCommand = exeStrings[5];
+	_strings.verbError = exeStrings[3];
+	_strings.nounError = exeStrings[4];
+	_strings.playAgain = exeStrings[8];
+	_strings.pressReturn = exeStrings[10];
+	_strings.lineFeeds = exeStrings[1];
 
 	// Set message IDs
 	_messageIds.cantGoThere = IDI_HR1_MSG_CANT_GO_THERE;


Commit: 56390d5f5fb05cbb9ea4448c58399c226715ccd9
    https://github.com/scummvm/scummvm/commit/56390d5f5fb05cbb9ea4448c58399c226715ccd9
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Add support for hires1 french (early version)

Changed paths:
    engines/adl/adl.cpp
    engines/adl/adl.h
    engines/adl/detection.cpp
    engines/adl/detection.h
    engines/adl/hires1.cpp
    engines/adl/metaengine.cpp


diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index b1b7eeb8ec..c1c40415c7 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -84,6 +84,8 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) :
 		_display(nullptr),
 		_graphics(nullptr),
 		_textMode(false),
+		_verbErrorPos(19),
+		_nounErrorPos(30),
 		_linesPrinted(0),
 		_isRestarting(false),
 		_isRestoring(false),
@@ -1063,17 +1065,24 @@ Common::String AdlEngine::getWord(const Common::String &line, uint &index) const
 
 Common::String AdlEngine::formatVerbError(const Common::String &verb) const {
 	Common::String err = _strings.verbError;
-	for (uint i = 0; i < verb.size(); ++i)
-		err.setChar(verb[i], i + 19);
+
+	if (_verbErrorPos + verb.size() > err.size())
+		error("Failed to format verb error string");
+
+	err.replace(_verbErrorPos, verb.size(), verb);
+
 	return err;
 }
 
 Common::String AdlEngine::formatNounError(const Common::String &verb, const Common::String &noun) const {
 	Common::String err = _strings.nounError;
-	for (uint i = 0; i < verb.size(); ++i)
-		err.setChar(verb[i], i + 19);
-	for (uint i = 0; i < noun.size(); ++i)
-		err.setChar(noun[i], i + 30);
+
+	if (_verbErrorPos + verb.size() > err.size() || _nounErrorPos + noun.size() > err.size())
+		error("Failed to format noun error string");
+
+	err.replace(_verbErrorPos, verb.size(), verb);
+	err.replace(_nounErrorPos, noun.size(), noun);
+
 	return err;
 }
 
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 28c827c90a..ef53c151b2 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -57,6 +57,7 @@ namespace Adl {
 Common::String getDiskImageName(const AdlGameDescription &adlDesc, byte volume);
 GameType getGameType(const AdlGameDescription &desc);
 GameVersion getGameVersion(const AdlGameDescription &desc);
+Common::Language getLanguage(const AdlGameDescription &desc);
 Common::Platform getPlatform(const AdlGameDescription &desc);
 
 class Console;
@@ -261,6 +262,7 @@ protected:
 	Common::String getDiskImageName(byte volume) const { return Adl::getDiskImageName(*_gameDescription, volume); }
 	GameType getGameType() const { return Adl::getGameType(*_gameDescription); }
 	GameVersion getGameVersion() const { return Adl::getGameVersion(*_gameDescription); }
+	Common::Language getLanguage() const { return Adl::getLanguage(*_gameDescription); }
 	virtual void gameLoop();
 	virtual void loadState(Common::ReadStream &stream);
 	virtual void saveState(Common::WriteStream &stream);
@@ -412,6 +414,8 @@ protected:
 		Common::String lineFeeds;
 	} _strings;
 
+	uint32 _verbErrorPos, _nounErrorPos;
+
 	struct {
 		uint cantGoThere;
 		uint dontUnderstand;
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index c47f7c3fe6..44ee787282 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -148,6 +148,22 @@ static const AdlGameDescription gameFileDescriptions[] = {
 		GAME_TYPE_HIRES1,
 		GAME_VER_HR1_COARSE
 	},
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - French - Without MIXEDON
+		{
+			"hires1", "VF1",
+			{
+				{ "ADVENTURE", 0, "6e2245979871b44a9fec46b4b2ba590a", 29952 },
+				{ "AUTO LOAD OBJ", 0, "3d417e923e70abe9a82e51155974027d", 12288 },
+				AD_LISTEND
+			},
+			Common::FR_FRA,
+			Common::kPlatformApple2,
+			ADGF_TESTING,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_VF1
+	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - With MIXEDON
 		{
 			"hires1", "V3",
@@ -166,7 +182,7 @@ static const AdlGameDescription gameFileDescriptions[] = {
 	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Roberta Williams Anthology
 		{
-			"hires1", 0,
+			"hires1", "PD",
 			{
 				{ "ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952 },
 				{ "AUTO LOAD OBJ", 0, "23bfccfe9fcff9b22cf6c41bde9078ac", 12291 },
diff --git a/engines/adl/detection.h b/engines/adl/detection.h
index c609530b1f..ecd9e22abf 100644
--- a/engines/adl/detection.h
+++ b/engines/adl/detection.h
@@ -61,6 +61,7 @@ enum GameVersion {
 	GAME_VER_NONE = 0,
 	GAME_VER_HR1_SIMI = 0,
 	GAME_VER_HR1_COARSE,
+	GAME_VER_HR1_VF1,
 	GAME_VER_HR1_PD
 };
 
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 0ee483d567..78bb842c97 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -67,9 +67,6 @@ namespace Adl {
 #define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff
 #define IDI_HR1_OFS_SHAPES       0x4f00
 
-#define IDI_HR1_OFS_VERBS        0x3800
-#define IDI_HR1_OFS_NOUNS        0x0f00
-
 class HiRes1Engine : public AdlEngine {
 public:
 	HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) :
@@ -229,6 +226,14 @@ void HiRes1Engine::runIntro() {
 	if (getGameVersion() >= GAME_VER_HR1_COARSE) {
 		bool instructions = false;
 
+		char keyInstr = 'I';
+		char keyGame = 'G';
+
+		if (getLanguage() == Common::FR_FRA) {
+			keyInstr = 'M';
+			keyGame = 'J';
+		}
+
 		while (1) {
 			_display->printString(str);
 			Common::String s = inputString();
@@ -239,10 +244,10 @@ void HiRes1Engine::runIntro() {
 			if (s.empty())
 				continue;
 
-			if (s[0] == _display->asciiToNative('I')) {
+			if (s[0] == _display->asciiToNative(keyInstr)) {
 				instructions = true;
 				break;
-			} else if (s[0] == _display->asciiToNative('G')) {
+			} else if (s[0] == _display->asciiToNative(keyGame)) {
 				break;
 			}
 		}
@@ -292,7 +297,7 @@ void HiRes1Engine::init() {
 	}
 
 	_graphics = new GraphicsMan_v1<Display_A2>(*static_cast<Display_A2 *>(_display));
-	_display->moveCursorTo(Common::Point(0, 3));
+	_display->moveCursorTo(Common::Point(0, 23)); // DOS 3.3
 
 	StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1));
 
@@ -323,11 +328,21 @@ void HiRes1Engine::init() {
 	_messageIds.itemNotHere = IDI_HR1_MSG_ITEM_NOT_HERE;
 	_messageIds.thanksForPlaying = IDI_HR1_MSG_THANKS_FOR_PLAYING;
 
+	if (getLanguage() == Common::FR_FRA) {
+		_verbErrorPos = 15;
+		_nounErrorPos = 31;
+	}
+
 	// Load message offsets
 	stream->seek(IDI_HR1_OFS_MSGS);
 	for (uint i = 0; i < IDI_HR1_NUM_MESSAGES; ++i)
 		_messages.push_back(_files->getDataBlock(IDS_HR1_MESSAGES, stream->readUint16LE()));
 
+	// The French version has 5 additional strings
+	if (getLanguage() == Common::FR_FRA)
+		for (uint i = 0; i < 5; ++i)
+			_messages.push_back(_files->getDataBlock(IDS_HR1_MESSAGES, stream->readUint16LE()));
+
 	// Load picture data from executable
 	stream->seek(IDI_HR1_OFS_PICS);
 	for (uint i = 1; i <= IDI_HR1_NUM_PICS; ++i) {
@@ -357,10 +372,10 @@ void HiRes1Engine::init() {
 	if (stream->eos() || stream->err())
 		error("Failed to read game data from '" IDS_HR1_EXE_1 "'");
 
-	stream->seek(IDI_HR1_OFS_VERBS);
+	stream->seek(getLanguage() == Common::FR_FRA ? 0x900 : 0x3800);
 	loadWords(*stream, _verbs, _priVerbs);
 
-	stream->seek(IDI_HR1_OFS_NOUNS);
+	stream->seek(0xf00);
 	loadWords(*stream, _nouns, _priNouns);
 }
 
@@ -422,7 +437,7 @@ void HiRes1Engine::printString(const Common::String &str) {
 	_display->printString(wrap);
 
 	if (_messageDelay)
-		delay(14 * 166018 / 1000);
+		delay(getLanguage() == Common::FR_FRA ? 2900 : 2250);
 }
 
 Common::String HiRes1Engine::loadMessage(uint idx) const {
diff --git a/engines/adl/metaengine.cpp b/engines/adl/metaengine.cpp
index e6f56b279a..795f65ef03 100644
--- a/engines/adl/metaengine.cpp
+++ b/engines/adl/metaengine.cpp
@@ -63,6 +63,10 @@ GameVersion getGameVersion(const AdlGameDescription &adlDesc) {
 	return adlDesc.version;
 }
 
+Common::Language getLanguage(const AdlGameDescription &adlDesc) {
+	return adlDesc.desc.language;
+}
+
 Common::Platform getPlatform(const AdlGameDescription &adlDesc) {
 	return adlDesc.desc.platform;
 }


Commit: e8dd3b7085365818f17fe6965f5209e1ab5daf3e
    https://github.com/scummvm/scummvm/commit/e8dd3b7085365818f17fe6965f5209e1ab5daf3e
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Add delay after printing strings in hires1

Changed paths:
    engines/adl/hires1.cpp


diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 78bb842c97..1bd6310a5a 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -281,8 +281,6 @@ void HiRes1Engine::runIntro() {
 		// This does mean we need to push out some extra line feeds to clear the screen
 		_display->printString(_strings.lineFeeds);
 		inputKey();
-		if (shouldQuit())
-			return;
 	}
 }
 
@@ -447,29 +445,39 @@ Common::String HiRes1Engine::loadMessage(uint idx) const {
 }
 
 void HiRes1Engine::printMessage(uint idx) {
-	// Messages with hardcoded overrides don't delay after printing.
-	// It's unclear if this is a bug or not. In some cases the result
-	// is that these strings will scroll past the four-line text window
-	// before the user gets a chance to read them.
-	// NOTE: later games seem to wait for a key when the text window
-	// overflows and don't use delays. It might be better to use
-	// that system for this game as well.
+	// In the English version, messages with hardcoded overrides don't delay
+	// after printing. It's unclear if this is a bug or not. In most cases
+	// the slow drawing of the room will give the player a chance to read
+	// it. This isn't the case in ScummVM however, so we add a delay after
+	// these messages.
+
+	// In the French version, messages with hardcoded overrides delay
+	// based on string length. This leads to overly long delays on longer
+	// strings. This might be a bug, since other messages have a fixed
+	// delay (that is slightly longer than the English version).
+	// We've chosen to stick with fixed delays here as well.
+
+	// NOTE: Later games wait for a key when the text window overflows and
+	// don't use delays. It might be better to use that system for this game
+	// as well.
 	switch (idx) {
 	case IDI_HR1_MSG_CANT_GO_THERE:
 		_display->printString(_gameStrings.cantGoThere);
-		return;
+		break;
 	case IDI_HR1_MSG_DONT_HAVE_IT:
 		_display->printString(_gameStrings.dontHaveIt);
-		return;
+		break;
 	case IDI_HR1_MSG_DONT_UNDERSTAND:
 		_display->printString(_gameStrings.dontUnderstand);
-		return;
+		break;
 	case IDI_HR1_MSG_GETTING_DARK:
 		_display->printString(_gameStrings.gettingDark);
-		return;
+		break;
 	default:
-		printString(loadMessage(idx));
+		return printString(loadMessage(idx));
 	}
+
+	delay(1500);
 }
 
 void HiRes1Engine::drawItems() {


Commit: 01e6ec1649e24c95605be7df0c7a0faf1373b189
    https://github.com/scummvm/scummvm/commit/01e6ec1649e24c95605be7df0c7a0faf1373b189
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Use slot 15 for autosave

Changed paths:
    engines/adl/adl.h
    engines/adl/metaengine.cpp


diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index ef53c151b2..68a4c3fdea 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -258,6 +258,7 @@ protected:
 	Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
 	bool canSaveGameStateCurrently() override;
 	virtual Common::String getSaveStateName(int slot) const override;
+	int getAutosaveSlot() const override { return 15; }
 
 	Common::String getDiskImageName(byte volume) const { return Adl::getDiskImageName(*_gameDescription, volume); }
 	GameType getGameType() const { return Adl::getGameType(*_gameDescription); }
diff --git a/engines/adl/metaengine.cpp b/engines/adl/metaengine.cpp
index 795f65ef03..73740de6da 100644
--- a/engines/adl/metaengine.cpp
+++ b/engines/adl/metaengine.cpp
@@ -79,7 +79,8 @@ public:
 
 	bool hasFeature(MetaEngineFeature f) const override;
 	SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
-	int getMaximumSaveSlot() const override { return 'O' - 'A'; }
+	int getAutosaveSlot() const override { return 15; }
+	int getMaximumSaveSlot() const override { return 15; }
 	SaveStateList listSaves(const char *target) const override;
 	void removeSaveState(const char *target, int slot) const override;
 


Commit: 5f6c88ef15ff3e82178dab8fffbfc08b677cb100
    https://github.com/scummvm/scummvm/commit/5f6c88ef15ff3e82178dab8fffbfc08b677cb100
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2021-07-24T00:56:51+02:00

Commit Message:
ADL: Add support for later French hires1

Changed paths:
    engines/adl/adl.h
    engines/adl/detection.cpp
    engines/adl/detection.h
    engines/adl/hires1.cpp


diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 68a4c3fdea..f84189b3a6 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -279,7 +279,8 @@ protected:
 	virtual Common::String getLine();
 	Common::String inputString(byte prompt = 0) const;
 	byte inputKey(bool showCursor = true) const;
-	void getInput(uint &verb, uint &noun);
+	virtual void getInput(uint &verb, uint &noun);
+	Common::String getWord(const Common::String &line, uint &index) const;
 
 	virtual Common::String formatVerbError(const Common::String &verb) const;
 	virtual Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
@@ -460,7 +461,6 @@ private:
 
 	// Text input
 	byte convertKey(uint16 ascii) const;
-	Common::String getWord(const Common::String &line, uint &index) const;
 
 	byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun;
 };
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 44ee787282..1373c06e6d 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -164,6 +164,22 @@ static const AdlGameDescription gameFileDescriptions[] = {
 		GAME_TYPE_HIRES1,
 		GAME_VER_HR1_VF1
 	},
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - French - Modified parser
+		{
+			"hires1", "VF2",
+			{
+				{ "ADVENTURE", 0, "f9a1add3609b4bc24b5dc4a9db1fec67", 29952 },
+				{ "AUTO LOAD OBJ", 0, "2a348058363da4c78a069ee5a2d81a31", 12287 },
+				AD_LISTEND
+			},
+			Common::FR_FRA,
+			Common::kPlatformApple2,
+			ADGF_TESTING,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_VF2
+	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - With MIXEDON
 		{
 			"hires1", "V3",
@@ -225,6 +241,18 @@ static const AdlGameDescription gameDiskDescriptions[] = {
 		GAME_TYPE_HIRES1,
 		GAME_VER_HR1_COARSE
 	},
+	{ // Hi-Res Adventure #1: Mystery House - Apple II - French - Modified parser
+		{
+			"hires1", "VF2",
+			AD_ENTRY1s("mysthous", "7bd1918ffc28e551e5b3baf610982bd3", 116480),
+			Common::FR_FRA,
+			Common::kPlatformApple2,
+			ADGF_TESTING,
+			MH_OPTIONS
+		},
+		GAME_TYPE_HIRES1,
+		GAME_VER_HR1_VF2
+	},
 	{ // Hi-Res Adventure #1: Mystery House - Apple II - Coarsegold - With MIXEDON
 		{
 			"hires1", "V3",
diff --git a/engines/adl/detection.h b/engines/adl/detection.h
index ecd9e22abf..adb251dcd3 100644
--- a/engines/adl/detection.h
+++ b/engines/adl/detection.h
@@ -62,6 +62,7 @@ enum GameVersion {
 	GAME_VER_HR1_SIMI = 0,
 	GAME_VER_HR1_COARSE,
 	GAME_VER_HR1_VF1,
+	GAME_VER_HR1_VF2,
 	GAME_VER_HR1_PD
 };
 
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 1bd6310a5a..3ebb905c2e 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -25,6 +25,7 @@
 #include "common/error.h"
 #include "common/file.h"
 #include "common/stream.h"
+#include "common/memstream.h"
 #include "common/ptr.h"
 
 #include "adl/adl.h"
@@ -75,7 +76,7 @@ public:
 			_messageDelay(true) { }
 	~HiRes1Engine() override { delete _files; }
 
-private:
+protected:
 	// AdlEngine
 	void runIntro() override;
 	void init() override;
@@ -555,7 +556,116 @@ void HiRes1Engine::wordWrap(Common::String &str) const {
 	}
 }
 
+class HiRes1Engine_VF : public HiRes1Engine {
+public:
+	HiRes1Engine_VF(OSystem *syst, const AdlGameDescription *gd) :
+			HiRes1Engine(syst, gd) { }
+
+private:
+	// AdlEngine
+	void runIntro() override;
+	void getInput(uint &verb, uint &noun) override;
+};
+
+void HiRes1Engine_VF::getInput(uint &verb, uint &noun) {
+	// This version has a modified "parser"
+	while (1) {
+		_display->printString(_strings.enterCommand);
+		const Common::String line = getLine();
+
+		if (shouldQuit() || _isRestoring)
+			return;
+
+		uint index = 0;
+		Common::String verbString = getWord(line, index);
+
+		if (!_verbs.contains(verbString)) {
+			// If the verb is not found and it looks like an imperative, try to build the infinitive
+			const size_t ezPos = verbString.find("\xc5\xda"); // "EZ"
+
+			bool found = false;
+
+			if (ezPos != verbString.npos) {
+				const char *suf[] = { "\xc5\xd2", "\xc9\xd2", "\xd2\xc5", nullptr }; // "ER", "IR", "RE"
+
+				for (uint i = 0; suf[i]; ++i) {
+					verbString.replace(ezPos, 2, suf[i]);
+					if (_verbs.contains(verbString)) {
+						found = true;
+						break;
+					}
+				}
+			}
+
+			if (!found) {
+				_display->printString(formatVerbError(verbString));
+				continue;
+			}
+		}
+
+		verb = _verbs[verbString];
+
+		while (1) {
+			// Go over all nouns to find one we know. At the end of the string,
+			// it will always match the empty word (which is in the noun list).
+
+			// The original has a code path to return a noun error here, but
+			// it appears to be non-functional.
+			const Common::String nounString = getWord(line, index);
+
+			if (_nouns.contains(nounString)) {
+				noun = _nouns[nounString];
+				return;
+			}
+		}
+	}
+}
+
+void HiRes1Engine_VF::runIntro() {
+	StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0));
+
+	stream->seek(0x1000);
+
+	// Title image is one padding byte short, so we first read it into a buffer
+	const uint frameBufferSize = 0x2000;
+	byte *const frameBuffer = (byte *)malloc(frameBufferSize);
+
+	if (stream->read(frameBuffer, frameBufferSize - 1) < frameBufferSize - 1)
+		error("Failed to read title image");
+
+	// Set missing byte
+	frameBuffer[frameBufferSize - 1] = 0;
+	Common::MemoryReadStream frameBufferStream(frameBuffer, frameBufferSize, DisposeAfterUse::YES);
+
+	_display->setMode(Display::kModeGraphics);
+	static_cast<Display_A2 *>(_display)->loadFrameBuffer(frameBufferStream);
+	_display->renderGraphics();
+
+	_display->setMode(Display::kModeMixed);
+
+	Common::String str = readStringAt(*stream, 0xf);
+
+	while (1) {
+		_display->printString(str);
+		const char key = inputKey();
+
+		if (shouldQuit())
+			return;
+
+		if (key == _display->asciiToNative('M')) {
+			stream->seek(0x75);
+			showInstructions(*stream);
+			return;
+		} else if (key == _display->asciiToNative('J')) {
+			return;
+		}
+	}
+}
+
 Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+	if (gd->version == GAME_VER_HR1_VF2)
+		return new HiRes1Engine_VF(syst, gd);
+
 	return new HiRes1Engine(syst, gd);
 }
 




More information about the Scummvm-git-logs mailing list