[Scummvm-git-logs] scummvm master -> 9e0d874a67da96609e39005774d1bcd9d8ec9923

whoozle noreply at scummvm.org
Thu Jan 8 18:19:47 UTC 2026


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

Summary:
9e0d874a67 AGDS: add support for the demo version of Black Mirror


Commit: 9e0d874a67da96609e39005774d1bcd9d8ec9923
    https://github.com/scummvm/scummvm/commit/9e0d874a67da96609e39005774d1bcd9d8ec9923
Author: Vladimir Menshakov (vladimir.menshakov at gmail.com)
Date: 2026-01-08T18:19:19Z

Commit Message:
AGDS: add support for the demo version of Black Mirror

Changed paths:
    engines/agds/agds.cpp
    engines/agds/agds.h
    engines/agds/detection_tables.h
    engines/agds/object.cpp
    engines/agds/object.h
    engines/agds/process.cpp
    engines/agds/process.h
    engines/agds/process_opcodes.cpp
    engines/agds/resourceManager.cpp
    engines/agds/resourceManager.h


diff --git a/engines/agds/agds.cpp b/engines/agds/agds.cpp
index 04121063d2f..4634733efd5 100644
--- a/engines/agds/agds.cpp
+++ b/engines/agds/agds.cpp
@@ -49,20 +49,22 @@
 namespace AGDS {
 
 AGDSEngine::AGDSEngine(OSystem *system, const ADGameDescription *gameDesc) : Engine(system),
-																			 _gameDescription(gameDesc), _pictureCacheId(1), _sharedStorageIndex(-2),
-																			 _shadowIntensity(0),
+																			 _gameDescription(gameDesc),
+																			 _resourceManager(version()),
+																			 _soundManager(this, system->getMixer()), _pictureCacheId(1),
 																			 _processes(MaxProcesses),
-																			 _mjpgPlayer(), _filmStarted(0),
+																			 _sharedStorageIndex(-2),
+																			 _shadowIntensity(0), _mjpgPlayer(),
+																			 _filmStarted(0),
 																			 _currentScreen(),
 																			 _currentCharacter(),
-																			 _defaultMouseCursor(),
 																			 _nextScreenType(ScreenLoadingType::Normal),
-																			 _mouse(400, 300),
-																			 _userEnabled(true), _systemUserEnabled(true),
+																			 _defaultMouseCursor(),
+																			 _mouse(400, 300), _userEnabled(true),
+																			 _systemUserEnabled(true),
 																			 _random("agds"),
-																			 _inventoryRegion(),
-																			 _soundManager(this, system->getMixer()),
 																			 _inventory(this),
+																			 _inventoryRegion(),
 																			 _dialog(this),
 																			 _tellTextTimer(0),
 																			 _syncSoundId(-1),
@@ -144,9 +146,13 @@ bool AGDSEngine::load() {
 
 	Common::INIFile::SectionKeyList values = config.getKeys("core");
 	for (Common::INIFile::SectionKeyList::iterator i = values.begin(); i != values.end(); ++i) {
-		if (i->key == "path")
-			if (!_resourceManager.addPath(Common::Path{i->value}))
+		if (i->key == "path") {
+			auto path = i->value;
+			if (path.hasPrefix(".\\"))
+				path = path.substr(2);
+			if (!_resourceManager.addPath(Common::Path{path, '\\'}))
 				return false;
+		}
 	}
 
 	if (!_data.open("data.adb"))
@@ -190,7 +196,7 @@ Common::String AGDSEngine::loadText(const Common::String &entryName) {
 	if (entryName.empty())
 		return Common::String();
 	Common::ScopedPtr<Common::SeekableReadStream> stream(_data.getEntry(entryName));
-	return ResourceManager::loadText(*stream);
+	return _resourceManager.loadText(*stream);
 }
 
 ObjectPtr AGDSEngine::loadObject(const Common::String &name, const Common::String &prototype, bool allowInitialise) {
@@ -200,7 +206,7 @@ ObjectPtr AGDSEngine::loadObject(const Common::String &name, const Common::Strin
 	if (!stream)
 		error("no database entry for %s\n", clone.c_str());
 
-	ObjectPtr object(new Object(name, *stream, v2()));
+	ObjectPtr object(new Object(name, *stream, version()));
 	object->allowInitialise(allowInitialise);
 	if (!prototype.empty()) {
 		object->persistent(false);
@@ -244,7 +250,7 @@ void AGDSEngine::runProcess(const ObjectPtr &object, uint ip) {
 			return;
 		}
 		if (!process) {
-			process = ProcessPtr(new Process(this, object, ip, v2()));
+			process = ProcessPtr(new Process(this, object, ip, version()));
 			process->run();
 			return;
 		}
@@ -396,8 +402,10 @@ Console *AGDSEngine::getConsole() {
 void AGDSEngine::newGame() {
 	SystemVariable *doneVar = getSystemVariable("done_resources");
 	Common::String done = doneVar->getString();
-	debug("running engine resource dtor: %s", done.c_str());
-	runObject(done);
+	if (!done.empty()) {
+		debug("running engine resource dtor: %s", done.c_str());
+		runObject(done);
+	}
 
 	_patches.clear();
 	_objectPatches.clear();
@@ -409,8 +417,10 @@ void AGDSEngine::newGame() {
 
 	SystemVariable *initVar = getSystemVariable("init_resources");
 	Common::String init = initVar->getString();
-	debug("running engine resource ctor: %s", init.c_str());
-	runObject(init);
+	if (!init.empty()) {
+		debug("running engine resource ctor: %s", init.c_str());
+		runObject(init);
+	}
 }
 
 void AGDSEngine::curtain(const Common::String &process, int screen, int sound, int music, bool updateGlobals) {
@@ -1438,4 +1448,12 @@ bool AGDSEngine::v2() const {
 	return _gameDescription->flags & AGDS_V2;
 }
 
+int AGDSEngine::version() const {
+	if (_gameDescription->flags & ADGF_DEMO)
+		return 0;
+	if (v2())
+		return 2;
+	return 1;
+}
+
 } // End of namespace AGDS
diff --git a/engines/agds/agds.h b/engines/agds/agds.h
index 6ee5a2c4e6c..1730e27256d 100644
--- a/engines/agds/agds.h
+++ b/engines/agds/agds.h
@@ -53,7 +53,7 @@
 namespace Graphics {
 class Font;
 class ManagedSurface;
-}
+} // namespace Graphics
 
 namespace AGDS {
 
@@ -280,7 +280,9 @@ public:
 	bool activeCurtain() const {
 		return _curtainTimer >= 0;
 	}
+
 	bool v2() const;
+	int version() const;
 
 private:
 	void stopAmbientSound();
diff --git a/engines/agds/detection_tables.h b/engines/agds/detection_tables.h
index 128eb76c3f5..61e97506ecd 100644
--- a/engines/agds/detection_tables.h
+++ b/engines/agds/detection_tables.h
@@ -56,7 +56,7 @@ static const ADGameDescription gameDescriptions[] = {
 	 ADGF_DROPPLATFORM | ADGF_CD,
 	 GUIO1(GUIO_NONE)},
 	{"black-mirror",
-	 0,
+	 "Demo",
 	 AD_ENTRY2s(
 		 "gfx_en.grp", "7539f35f9242461114c8746b62f884a6", 67516239,
 		 "data.adb", "56680d118afddf9477c57e508d118dc8", 114764),
diff --git a/engines/agds/object.cpp b/engines/agds/object.cpp
index b6accc550e6..61c2d35380d 100644
--- a/engines/agds/object.cpp
+++ b/engines/agds/object.cpp
@@ -33,16 +33,16 @@
 
 namespace AGDS {
 
-Object::Object(const Common::String &name, Common::SeekableReadStream &stream, bool v2) : _name(name), _stringTableLoaded(false),
-																						  _picture(), _rotatedPicture(), _region(),
-																						  _animation(), _mouseCursor(),
-																						  _pos(), _z(10), _rotation(0),
-																						  _clickHandler(0), _examineHandler(0), _userUseHandler(0),
-																						  _throwHandler(0), _useOnHandler(0),
-																						  _handlerBD(0), _handlerC1(0),
-																						  _alpha(255), _scale(100), _locked(0), _alive(true),
-																						  _persistent(true), _allowInitialise(true),
-																						  _ignoreRegion(false), _v2(v2) {
+Object::Object(const Common::String &name, Common::SeekableReadStream &stream, int version) : _name(name), _stringTableLoaded(false),
+																							  _picture(), _rotatedPicture(), _region(),
+																							  _animation(), _mouseCursor(),
+																							  _pos(), _z(10), _rotation(0),
+																							  _clickHandler(0), _examineHandler(0), _userUseHandler(0),
+																							  _throwHandler(0), _useOnHandler(0),
+																							  _handlerBD(0), _handlerC1(0),
+																							  _alpha(255), _scale(100), _locked(0), _alive(true),
+																							  _persistent(true), _allowInitialise(true),
+																							  _ignoreRegion(false), _version(version) {
 	uint16 id = stream.readUint16LE();
 	debug("id: 0x%02x %u", id, id);
 
@@ -92,7 +92,7 @@ void Object::readStringTable(unsigned resOffset, uint16 resCount) {
 	if (_stringTableLoaded)
 		return;
 
-	resOffset += 5 /*instruction*/ + (_v2 ? 0x13 : 0x11) /*another header*/;
+	resOffset += 5 /*instruction*/ + (_version >= 2 ? 0x13 : 0x11) /*another header*/;
 	if (resOffset >= _code.size())
 		error("invalid resource table offset %u/%u", resOffset, _code.size());
 
diff --git a/engines/agds/object.h b/engines/agds/object.h
index 3d7feb3c079..fe4a00a7cc5 100644
--- a/engines/agds/object.h
+++ b/engines/agds/object.h
@@ -95,7 +95,7 @@ private:
 	bool _persistent;
 	bool _allowInitialise;
 	bool _ignoreRegion;
-	bool _v2;
+	int _version;
 
 private:
 	void freeRotated();
@@ -103,7 +103,7 @@ private:
 	void createRotated();
 
 public:
-	Object(const Common::String &name, Common::SeekableReadStream &stream, bool v2);
+	Object(const Common::String &name, Common::SeekableReadStream &stream, int version);
 	~Object();
 
 	bool allowInitialise() const {
diff --git a/engines/agds/process.cpp b/engines/agds/process.cpp
index 86179780612..c508dd925da 100644
--- a/engines/agds/process.cpp
+++ b/engines/agds/process.cpp
@@ -27,15 +27,15 @@
 
 namespace AGDS {
 
-Process::Process(AGDSEngine *engine, const ObjectPtr &object, unsigned ip, bool v2) : _engine(engine), _parentScreen(engine->getCurrentScreenName()), _object(object),
-																					  _entryPoint(ip), _ip(ip), _lastIp(ip),
-																					  _status(kStatusActive), _exited(false), _exitCode(kExitCodeDestroy),
-																					  _tileWidth(16), _tileHeight(16), _tileResource(-1), _tileIndex(0),
-																					  _timer(0),
-																					  _animationCycles(1), _animationLoop(false), _animationZ(0), _animationDelay(-1), _animationRandom(0),
-																					  _phaseVarControlled(false), _animationSpeed(100),
-																					  _samplePeriodic(false), _sampleAmbient(false), _sampleVolume(100),
-																					  _filmSubtitlesResource(-1), _v2(v2) {
+Process::Process(AGDSEngine *engine, const ObjectPtr &object, unsigned ip, int version) : _engine(engine), _parentScreen(engine->getCurrentScreenName()), _object(object),
+																						  _entryPoint(ip), _ip(ip), _lastIp(ip),
+																						  _status(kStatusActive), _exited(false), _exitCode(kExitCodeDestroy),
+																						  _tileWidth(16), _tileHeight(16), _tileResource(-1), _tileIndex(0),
+																						  _timer(0),
+																						  _animationCycles(1), _animationLoop(false), _animationZ(0), _animationDelay(-1), _animationRandom(0),
+																						  _phaseVarControlled(false), _animationSpeed(100),
+																						  _samplePeriodic(false), _sampleAmbient(false), _sampleVolume(100),
+																						  _filmSubtitlesResource(-1), _version(version) {
 	updateWithCurrentMousePosition();
 }
 
@@ -319,14 +319,14 @@ void Process::run() {
 
 #define UNARY_OP(NAME, OP)       \
 	void Process::NAME() {       \
-		int32 arg = pop();         \
+		int32 arg = pop();       \
 		debug(#NAME " %d", arg); \
 		push(OP arg);            \
 	}
 #define BINARY_OP(NAME, OP)                    \
 	void Process::NAME() {                     \
-		int32 arg2 = pop();                      \
-		int32 arg1 = pop();                      \
+		int32 arg2 = pop();                    \
+		int32 arg1 = pop();                    \
 		debug(" %d " #NAME " %d", arg1, arg2); \
 		push(arg1 OP arg2);                    \
 	}
@@ -400,6 +400,24 @@ BINARY_OP(bitXor, ^)
 		METHOD(static_cast<int32>(arg1 | (arg2 << 16))); \
 	} break;
 
+uint16 Process::nextOpcode() {
+	uint16 op = next();
+	switch (_version) {
+	case 0:
+		return op + 5;
+
+	case 2:
+		if (op & 1) {
+			op |= next() << 8;
+			op >>= 1;
+		}
+		return op - 7995;
+
+	default:
+		return op;
+	}
+}
+
 ProcessExitCode Process::resume() {
 	_exitCode = kExitCodeDestroy;
 	if (_timer) {
@@ -413,14 +431,7 @@ ProcessExitCode Process::resume() {
 			return kExitCodeSuspend;
 		}
 		_lastIp = _ip;
-		uint16 op = next();
-		if (_v2) {
-			if (op & 1) {
-				op |= next() << 8;
-				op >>= 1;
-			}
-			op -= 7995;
-		}
+		auto op = nextOpcode();
 		// debug("CODE %04x: %u", _lastIp, (uint)op);
 		switch (op) {
 			AGDS_OPCODE_LIST(
@@ -488,18 +499,20 @@ ProcessExitCode Process::resume() {
 		source += Common::String::format("%s %u\n", #NAME, (uint)(arg1 | (arg2 << 16))); \
 	} break;
 
-Common::String Process::disassemble(const ObjectPtr &object, bool v2) {
+Common::String Process::disassemble(const ObjectPtr &object, int version) {
 	Common::String source = Common::String::format("Object %s disassembly:\n", object->getName().c_str());
 
 	const auto &code = object->getCode();
 	uint ip = 0;
 	while (ip < code.size()) {
 		uint16 op = code[ip++];
-		if (v2) {
+		if (version == 2) {
 			if (op & 1) {
 				op |= code[ip++] << 8;
 				op >>= 1;
 			}
+		} else if (version == 0) {
+			op += 5;
 		}
 
 		source += Common::String::format("%04x: %02x: ", ip - 1, op);
diff --git a/engines/agds/process.h b/engines/agds/process.h
index 9d0a94c9744..a9a1a1b8042 100644
--- a/engines/agds/process.h
+++ b/engines/agds/process.h
@@ -76,7 +76,7 @@ private:
 	Common::Point _mousePosition;
 	int _filmSubtitlesResource;
 	AnimationPtr _processAnimation;
-	bool _v2;
+	int _version;
 
 private:
 	void debug(const char *str, ...);
@@ -90,6 +90,7 @@ private:
 		uint16 h = next();
 		return (h << 8) | l;
 	}
+	uint16 nextOpcode();
 
 	int32 pop();
 	int32 top();
@@ -138,12 +139,12 @@ private:
 	void removeScreenObject(const Common::String &name);
 
 public:
-	Process(AGDSEngine *engine, const ObjectPtr &object, unsigned ip, bool v2);
+	Process(AGDSEngine *engine, const ObjectPtr &object, unsigned ip, int version);
 	unsigned entryPoint() const {
 		return _entryPoint;
 	}
 
-	static Common::String disassemble(const ObjectPtr &object, bool v2);
+	static Common::String disassemble(const ObjectPtr &object, int version);
 
 	ObjectPtr getObject() const {
 		return _object;
diff --git a/engines/agds/process_opcodes.cpp b/engines/agds/process_opcodes.cpp
index ef6667a2b65..6bb5df3496b 100644
--- a/engines/agds/process_opcodes.cpp
+++ b/engines/agds/process_opcodes.cpp
@@ -724,7 +724,10 @@ void Process::setAnimationZ() {
 }
 
 void Process::setPanAndVolume() {
-	int pan = pop();
+	int pan = 0;
+	if (_version > 0) {
+		pan = pop();
+	}
 	int volume = pop();
 	debug("setPanAndVolume: pan %d volume %d", pan, volume);
 }
diff --git a/engines/agds/resourceManager.cpp b/engines/agds/resourceManager.cpp
index 172d70ce6a0..0b06b29df24 100644
--- a/engines/agds/resourceManager.cpp
+++ b/engines/agds/resourceManager.cpp
@@ -32,7 +32,7 @@
 #include "video/flic_decoder.h"
 
 namespace AGDS {
-ResourceManager::ResourceManager() {}
+ResourceManager::ResourceManager(int version) : _version(version) {}
 
 ResourceManager::~ResourceManager() {}
 
@@ -63,10 +63,17 @@ bool ResourceManager::GrpFile::load(const Common::Path &grpPath) {
 		return false;
 	}
 
-	decrypt(header, 0x10);
 	if (strncmp(reinterpret_cast<const char *>(header), kSignature, 0x10) != 0) {
-		warning("invalid signature");
-		return false;
+		decrypt(header, 0x10);
+		if (strncmp(reinterpret_cast<const char *>(header), kSignature, 0x10) != 0) {
+			warning("invalid signature");
+			return false;
+		}
+		debug("load grp file %s, encrypted", grpPath.toString().c_str());
+		_encrypted = true;
+	} else {
+		debug("load grp file %s, unencrypted", grpPath.toString().c_str());
+		_encrypted = false;
 	}
 
 	Common::MemoryReadStreamEndian reader(header + 0x10, sizeof(header) - 0x10, false);
@@ -109,7 +116,8 @@ bool ResourceManager::GrpFile::load(const Common::Path &grpPath) {
 		}
 
 		unsigned nameLength = nameEnd - dirData;
-		decrypt(dirData, nameLength);
+		if (_encrypted)
+			decrypt(dirData, nameLength);
 		Common::String name(reinterpret_cast<char *>(dirData), nameLength);
 
 		Common::MemoryReadStreamEndian dirReader(dirData + 0x21, 8, false);
@@ -206,7 +214,7 @@ Graphics::Surface *ResourceManager::loadPicture(const Common::String &name, cons
 	return NULL;
 }
 
-Common::String ResourceManager::loadText(Common::SeekableReadStream &stream) {
+Common::String ResourceManager::loadText(Common::SeekableReadStream &stream) const {
 	Common::Array<char> text(stream.size());
 	if (stream.read(text.data(), text.size()) != text.size())
 		error("short read from text resource");
@@ -219,7 +227,8 @@ Common::String ResourceManager::loadText(Common::SeekableReadStream &stream) {
 	while (begin != end && end[-1] == 0)
 		--end;
 
-	decrypt(reinterpret_cast<uint8 *>(text.data()), end - begin);
+	if (_version != 0 || (text[0] < ' ' || text[0] >= 0x7f))
+		decrypt(reinterpret_cast<uint8 *>(text.data()), end - begin);
 
 	while (begin != end && end[-1] == 0)
 		--end;
diff --git a/engines/agds/resourceManager.h b/engines/agds/resourceManager.h
index 8ff5864cce8..a4c9712adf9 100644
--- a/engines/agds/resourceManager.h
+++ b/engines/agds/resourceManager.h
@@ -67,6 +67,7 @@ private:
 
 	class GrpFile : public Common::Archive {
 		Common::File _file;
+		bool _encrypted;
 
 		using MembersType = Common::HashMap<Common::String, ArchiveMemberPtr, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>;
 		MembersType _members;
@@ -84,11 +85,14 @@ private:
 		Common::SeekableReadStream *createReadStreamForMember(const Common::Path &name) const override;
 	};
 
+	static void decrypt(uint8 *data, unsigned size);
+
+	int _version;
+
 public:
-	ResourceManager();
+	ResourceManager(int version);
 	~ResourceManager();
 
-	static void decrypt(uint8 *data, unsigned size);
 	static bool IsBMP(Common::SeekableReadStream &stream);
 
 	bool addPath(const Common::Path &grpFilename);
@@ -96,7 +100,7 @@ public:
 	Common::SeekableReadStream *getResource(const Common::String &name) const;
 	Graphics::Surface *loadPicture(const Common::String &name, const Graphics::PixelFormat &format);
 
-	static Common::String loadText(Common::SeekableReadStream &stream);
+	Common::String loadText(Common::SeekableReadStream &stream) const;
 	Common::String loadText(const Common::String &name) const;
 };
 




More information about the Scummvm-git-logs mailing list