[Scummvm-git-logs] scummvm master -> 354abe0cc72ff12b39b747276ac02ee07164b88e

sev- noreply at scummvm.org
Thu Jun 8 07:16:38 UTC 2023


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

Summary:
458e97933d DIRECTOR: Refactor archive loading code
dcd897e5c6 DIRECTOR: Add Object::incRefCount() and Object::decRefCount() helpers
d69dac6016 COMMON: Fix file handle leak in generateZipSet()
871c1d0907 DIRECTOR: Fix leak in Window::runTests()
14474ce129 DIRECTOR: Fix "the number of castMembers"
993c473bb6 DIRECTOR: b_objectp should return 1 for ARRAY and PARRAY
9b29fff76c DIRECTOR: Make b_sort behaviour more accurate
07608d13ec DIRECTOR: Add stub for Color XObj
507a4431a8 DIRECTOR: Fix b_getAt to support POINT
c94f2de321 DIRECTOR: Add font quirks for two Star Trek games
354abe0cc7 DIRECTOR: Fix ProjectorArchive path lookup


Commit: 458e97933dc6d0c3419bb3cd2f8c0c59130790d5
    https://github.com/scummvm/scummvm/commit/458e97933dc6d0c3419bb3cd2f8c0c59130790d5
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Refactor archive loading code

Make DirectorEngine::_allOpenResFiles the de-facto owner of Archive *
objects, move all of the various loadEXE/loadMac methods off Window and
onto DirectorEngine, and replace inline Archive loading with
openArchive().

Changed paths:
    engines/director/archive.cpp
    engines/director/cast.cpp
    engines/director/director.cpp
    engines/director/director.h
    engines/director/lingo/lingo-builtins.cpp
    engines/director/movie.cpp
    engines/director/resource.cpp
    engines/director/tests.cpp
    engines/director/window.cpp
    engines/director/window.h


diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index 240e2ab62f1..81f5262b8df 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -388,19 +388,19 @@ bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 	stream->seek(startOffset);
 
 	if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'I', 'F', 'F')) {
-		warning("RIFFArchive::openStream(): RIFF expected but not found");
+		debugC(5, kDebugLoading, "RIFFArchive::openStream(): RIFF expected but not found");
 		return false;
 	}
 
 	stream->readUint32LE(); // size
 
 	if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'M', 'M', 'P')) {
-		warning("RIFFArchive::openStream(): RMMP expected but not found");
+		debugC(5, kDebugLoading, "RIFFArchive::openStream(): RMMP expected but not found");
 		return false;
 	}
 
 	if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('C', 'F', 'T', 'C')) {
-		warning("RIFFArchive::openStream(): CFTC expected but not found");
+		debugC(5, kDebugLoading, "RIFFArchive::openStream(): CFTC expected but not found");
 		return false;
 	}
 
@@ -549,12 +549,12 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 			// We need to look at the resource fork to detect XCOD resources
 			Common::SeekableSubReadStream *macStream = new Common::SeekableSubReadStream(stream, 0, stream->size());
 			MacArchive *macArchive = new MacArchive();
-			if (!macArchive->openStream(macStream)) {
-				delete macArchive;
-				delete macStream;
+			if (macArchive->openStream(macStream)) {
+				g_director->getCurrentWindow()->probeResources(macArchive);
 			} else {
-				g_director->getCurrentWindow()->probeMacBinary(macArchive);
+				delete macStream;
 			}
+			delete macArchive;
 
 			// Then read the data fork
 			moreOffset = Common::MacResManager::getDataForkOffset();
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 2a27f4b2834..9cdcd38a72f 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -88,12 +88,6 @@ Cast::~Cast() {
 		for (Common::HashMap<int, const Stxt *>::iterator it = _loadedStxts->begin(); it != _loadedStxts->end(); ++it)
 			delete it->_value;
 
-	if (_castArchive) {
-		_castArchive->close();
-		delete _castArchive;
-		_castArchive = nullptr;
-	}
-
 	if (_loadedCast)
 		for (Common::HashMap<int, CastMember *>::iterator it = _loadedCast->begin(); it != _loadedCast->end(); ++it)
 			if (it->_value) {
@@ -828,15 +822,7 @@ void Cast::loadExternalSound(Common::SeekableReadStreamEndian &stream) {
 
 	Common::String resPath = g_director->getCurrentPath() + str;
 
-	if (!g_director->_allOpenResFiles.contains(resPath)) {
-		MacArchive *resFile = new MacArchive();
-
-		if (resFile->openFile(resPath)) {
-			g_director->_allOpenResFiles.setVal(resPath, resFile);
-		} else {
-			delete resFile;
-		}
-	}
+	g_director->openArchive(resPath);
 }
 
 static void readEditInfo(EditInfo *info, Common::ReadStreamEndian *stream) {
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 4dc2cd96287..a1efc761317 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -144,8 +144,8 @@ DirectorEngine::~DirectorEngine() {
 	delete _wm;
 	delete _surface;
 
-	for (Common::HashMap<Common::String, Archive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>::iterator it = _allOpenResFiles.begin(); it != _allOpenResFiles.end(); ++it) {
-		delete it->_value;
+	for (auto &it : _allOpenResFiles) {
+		delete it._value;
 	}
 
 	for (uint i = 0; i < _winCursor.size(); i++)
diff --git a/engines/director/director.h b/engines/director/director.h
index fcec6af0440..e6e970218a3 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -211,6 +211,14 @@ public:
 	Common::CodePage getPlatformEncoding();
 
 	Archive *createArchive();
+	Archive *openArchive(const Common::String movie);
+	Archive *loadEXE(const Common::String movie);
+	Archive *loadEXEv3(Common::SeekableReadStream *stream);
+	Archive *loadEXEv4(Common::SeekableReadStream *stream);
+	Archive *loadEXEv5(Common::SeekableReadStream *stream);
+	Archive *loadEXEv7(Common::SeekableReadStream *stream);
+	Archive *loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset);
+	Archive *loadMac(const Common::String movie);
 
 	bool desktopEnabled();
 
@@ -244,9 +252,10 @@ public:
 	Common::Rect _fixStageRect;
 	Common::List<Common::String> _extraSearchPath;
 
+	// Owner of all Archive objects.
 	Common::HashMap<Common::String, Archive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _allOpenResFiles;
-	// Opened Resource Files that were opened by OpenResFile
-	Common::HashMap<Common::String, MacArchive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _openResFiles;
+	// Handles to resource files that were opened by OpenResFile.
+	Common::HashMap<Common::String, Archive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _openResFiles;
 
 	Common::Array<Graphics::WinCursorGroup *> _winCursor;
 
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index a759cf5532b..0aa1aa042af 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1114,13 +1114,7 @@ void LB::b_closeDA(int nargs) {
 void LB::b_closeResFile(int nargs) {
 	// closeResFile closes only resource files that were opened with openResFile.
 
-	if (nargs == 0) { // Close all open resesource files
-		for (Common::HashMap<Common::String, MacArchive *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>::iterator
-				it = g_director->_openResFiles.begin(); it != g_director->_openResFiles.end(); ++it) {
-			// also clean up the global resource file hashmap
-			g_director->_allOpenResFiles.erase(it->_key);
-			delete it->_value;
-		}
+	if (nargs == 0) { // Close all open resource files
 		g_director->_openResFiles.clear();
 		return;
 	}
@@ -1129,11 +1123,7 @@ void LB::b_closeResFile(int nargs) {
 	Common::String resFileName = g_director->getCurrentWindow()->getCurrentPath() + d.asString();
 
 	if (g_director->_openResFiles.contains(resFileName)) {
-		auto archive = g_director->_openResFiles.getVal(resFileName);
-		delete archive;
 		g_director->_openResFiles.erase(resFileName);
-		// also clean up the global resource file hashmap
-		g_director->_allOpenResFiles.erase(resFileName);
 	}
 }
 
@@ -1218,21 +1208,13 @@ void LB::b_openDA(int nargs) {
 void LB::b_openResFile(int nargs) {
 	Datum d = g_lingo->pop();
 	Common::String resPath = g_director->getCurrentWindow()->getCurrentPath() + d.asString();
-
-	if (g_director->getPlatform() == Common::kPlatformWindows) {
-		warning("STUB: BUILDBOT: b_openResFile(%s) on Windows", d.asString().c_str());
-		return;
-	}
+	resPath = pathMakeRelative(resPath);
 
 	if (!g_director->_allOpenResFiles.contains(resPath)) {
-		MacArchive *resFile = new MacArchive();
-
-		if (resFile->openFile(pathMakeRelative(resPath))) {
+		Archive *arch = g_director->openArchive(resPath);
+		if (arch) {
 			// Track responsibility. closeResFile may only close resource files opened by openResFile.
-			g_director->_openResFiles.setVal(resPath, resFile);
-			g_director->_allOpenResFiles.setVal(resPath, resFile);
-		} else {
-			delete resFile;
+			g_director->_openResFiles.setVal(resPath, arch);
 		}
 	}
 }
@@ -1244,40 +1226,36 @@ void LB::b_openXlib(int nargs) {
 
 	Datum d = g_lingo->pop();
 	if (g_director->getPlatform() == Common::kPlatformMacintosh) {
-		// try opening the file as a resfile
+		// try opening the file as a Macintosh resource fork
 		Common::String resPath = g_director->getCurrentWindow()->getCurrentPath() + d.asString();
-		if (!g_director->_allOpenResFiles.contains(resPath)) {
-			MacArchive *resFile = new MacArchive();
-
-			if (resFile->openFile(pathMakeRelative(resPath))) {
-				g_director->_allOpenResFiles.setVal(resPath, resFile);
-				uint32 XCOD = MKTAG('X', 'C', 'O', 'D');
-				uint32 XCMD = MKTAG('X', 'C', 'M', 'D');
-				uint32 XFCN = MKTAG('X', 'F', 'C', 'N');
+		MacArchive *resFile = new MacArchive();
+		if (resFile->openFile(resPath)) {
+			uint32 XCOD = MKTAG('X', 'C', 'O', 'D');
+			uint32 XCMD = MKTAG('X', 'C', 'M', 'D');
+			uint32 XFCN = MKTAG('X', 'F', 'C', 'N');
 
-				Common::Array<uint16> rsrcList = resFile->getResourceIDList(XCOD);
+			Common::Array<uint16> rsrcList = resFile->getResourceIDList(XCOD);
 
-				for (uint i = 0; i < rsrcList.size(); i++) {
-					xlibName = resFile->getResourceDetail(XCOD, rsrcList[i]).name.c_str();
-					g_lingo->openXLib(xlibName, kXObj);
-				}
+			for (uint i = 0; i < rsrcList.size(); i++) {
+				xlibName = resFile->getResourceDetail(XCOD, rsrcList[i]).name.c_str();
+				g_lingo->openXLib(xlibName, kXObj);
+			}
 
-				rsrcList = resFile->getResourceIDList(XCMD);
-				for (uint i = 0; i < rsrcList.size(); i++) {
-					xlibName = resFile->getResourceDetail(XCMD, rsrcList[i]).name.c_str();
-					g_lingo->openXLib(xlibName, kXObj);
-				}
+			rsrcList = resFile->getResourceIDList(XCMD);
+			for (uint i = 0; i < rsrcList.size(); i++) {
+				xlibName = resFile->getResourceDetail(XCMD, rsrcList[i]).name.c_str();
+				g_lingo->openXLib(xlibName, kXObj);
+			}
 
-				rsrcList = resFile->getResourceIDList(XFCN);
-				for (uint i = 0; i < rsrcList.size(); i++) {
-					xlibName = resFile->getResourceDetail(XFCN, rsrcList[i]).name.c_str();
-					g_lingo->openXLib(xlibName, kXObj);
-				}
-				return;
-			} else {
-				delete resFile;
+			rsrcList = resFile->getResourceIDList(XFCN);
+			for (uint i = 0; i < rsrcList.size(); i++) {
+				xlibName = resFile->getResourceDetail(XFCN, rsrcList[i]).name.c_str();
+				g_lingo->openXLib(xlibName, kXObj);
 			}
+			delete resFile;
+			return;
 		}
+		delete resFile;
 	}
 
 	xlibName = getFileName(d.asString());
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index b58c6be1ae9..07f5fa7b254 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -95,12 +95,7 @@ Movie::Movie(Window *window) {
 }
 
 Movie::~Movie() {
-	// _movieArchive is shared with the cast, so the cast will free it
 	delete _cast;
-
-	if (_sharedCast)
-		g_director->_allOpenResFiles.erase(_sharedCast->getArchive()->getPathName());
-
 	delete _sharedCast;
 	delete _score;
 }
@@ -348,23 +343,18 @@ void Movie::clearSharedCast() {
 	if (!_sharedCast)
 		return;
 
-	g_director->_allOpenResFiles.erase(_sharedCast->getArchive()->getPathName());
-
 	delete _sharedCast;
-
 	_sharedCast = nullptr;
 }
 
 void Movie::loadSharedCastsFrom(Common::String filename) {
 	clearSharedCast();
 
-	Archive *sharedCast = _vm->createArchive();
+	Archive *sharedCast = _vm->openArchive(filename);
 
-	if (!sharedCast->openFile(filename)) {
+	if (!sharedCast) {
 		warning("loadSharedCastsFrom(): No shared cast %s", filename.c_str());
 
-		delete sharedCast;
-
 		return;
 	}
 	sharedCast->setPathName(filename);
@@ -376,29 +366,21 @@ void Movie::loadSharedCastsFrom(Common::String filename) {
 	_sharedCast = new Cast(this, DEFAULT_CAST_LIB, true, false);
 	_sharedCast->setArchive(sharedCast);
 	_sharedCast->loadArchive();
-
-	// Register the resfile so that Cursor::readFromResource can find it
-	g_director->_allOpenResFiles.setVal(sharedCast->getPathName(), sharedCast);
 }
 
 Archive *Movie::loadExternalCastFrom(Common::String filename) {
-	Archive *externalCast = _vm->createArchive();
+	Archive *externalCast = _vm->openArchive(filename);
 
-	if (!externalCast->openFile(filename)) {
+	if (!externalCast) {
 		warning("Movie::loadExternalCastFrom(): Cast file %s not found", filename.c_str());
 
-		delete externalCast;
-
 		return nullptr;
 	}
-	externalCast->setPathName(filename);
 
 	debug(0, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	debug(0, "@@@@   Loading external cast '%s'", filename.c_str());
 	debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
 
-	// Store the archive for later
-	g_director->_allOpenResFiles.setVal(externalCast->getPathName(), externalCast);
 	return externalCast;
 }
 
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 935a02364f7..d2f3d1c7cc7 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -60,12 +60,13 @@ Common::Error Window::loadInitialMovie() {
 		return Common::kPathNotFile;
 
 	loadINIStream();
-	_mainArchive = openArchive(movie);
+	_mainArchive = g_director->openArchive(movie);
 
 	if (!_mainArchive) {
 		warning("Cannot open main movie");
 		return Common::kNoGameDataFoundError;
 	}
+	probeResources(_mainArchive);
 
 	// Load multiple-resources based executable file (Projector)
 	ProjectorArchive *multiArchive = new ProjectorArchive(_vm->getRawEXEName());
@@ -114,20 +115,7 @@ Common::Error Window::loadInitialMovie() {
 	return Common::kNoError;
 }
 
-void Window::probeProjector(const Common::String &movie) {
-	if (g_director->getPlatform() == Common::kPlatformWindows)
-		return;
-
-	MacArchive *archive = new MacArchive();
-	if (!archive->openFile(movie)) {
-		delete archive;
-		return;
-	}
-
-	probeMacBinary(archive);
-}
-
-void Window::probeMacBinary(MacArchive *archive) {
+void Window::probeResources(Archive *archive) {
 	if (archive->hasResource(MKTAG('B', 'N', 'D', 'L'), "Projector")) {
 		warning("Detected Projector file");
 
@@ -169,7 +157,10 @@ void Window::probeMacBinary(MacArchive *archive) {
 					_currentMovie = nullptr;
 				}
 
-				probeProjector(moviePath);
+				Archive *subMovie = g_director->openArchive(moviePath);
+				if (subMovie) {
+					probeResources(subMovie);
+				}
 			} else {
 				warning("Couldn't find score with name: %s", sname.c_str());
 			}
@@ -177,58 +168,67 @@ void Window::probeMacBinary(MacArchive *archive) {
 		}
 	}
 
-	if (archive->hasResource(MKTAG('X', 'C', 'O', 'D'), -1)) {
-		Common::Array<uint16> xcod = archive->getResourceIDList(MKTAG('X', 'C', 'O', 'D'));
-		for (Common::Array<uint16>::iterator iterator = xcod.begin(); iterator != xcod.end(); ++iterator) {
-			Resource res = archive->getResourceDetail(MKTAG('X', 'C', 'O', 'D'), *iterator);
-			debug(0, "Detected XObject '%s'", res.name.c_str());
-			g_lingo->openXLib(res.name, kXObj);
-		}
-	}
-	if (archive->hasResource(MKTAG('X', 'C', 'M', 'D'), -1)) {
-		Common::Array<uint16> xcmd = archive->getResourceIDList(MKTAG('X', 'C', 'M', 'D'));
-		for (Common::Array<uint16>::iterator iterator = xcmd.begin(); iterator != xcmd.end(); ++iterator) {
-			Resource res = archive->getResourceDetail(MKTAG('X', 'C', 'M', 'D'), *iterator);
-			debug(0, "Detected XCMD '%s'", res.name.c_str());
-			g_lingo->openXLib(res.name, kXObj);
-		}
-	}
-	if (archive->hasResource(MKTAG('X', 'F', 'C', 'N'), -1)) {
-		Common::Array<uint16> xfcn = archive->getResourceIDList(MKTAG('X', 'F', 'C', 'N'));
-		for (Common::Array<uint16>::iterator iterator = xfcn.begin(); iterator != xfcn.end(); ++iterator) {
-			Resource res = archive->getResourceDetail(MKTAG('X', 'F', 'C', 'N'), *iterator);
-			debug(0, "Detected XFCN '%s'", res.name.c_str());
-			g_lingo->openXLib(res.name, kXObj);
+	if (g_director->getPlatform() == Common::kPlatformMacintosh) {
+		// On Macintosh, you can add additional chunks to the resource
+		// fork of the file to state which XObject or HyperCard XCMD/XFCNs
+		// need to be loaded in.
+		MacArchive *resFork = new MacArchive();
+		if (resFork->openFile(archive->getPathName())) {
+			if (resFork->hasResource(MKTAG('X', 'C', 'O', 'D'), -1)) {
+				Common::Array<uint16> xcod = resFork->getResourceIDList(MKTAG('X', 'C', 'O', 'D'));
+				for (Common::Array<uint16>::iterator iterator = xcod.begin(); iterator != xcod.end(); ++iterator) {
+					Resource res = resFork->getResourceDetail(MKTAG('X', 'C', 'O', 'D'), *iterator);
+					debug(0, "Detected XObject '%s'", res.name.c_str());
+					g_lingo->openXLib(res.name, kXObj);
+				}
+			}
+			if (resFork->hasResource(MKTAG('X', 'C', 'M', 'D'), -1)) {
+				Common::Array<uint16> xcmd = resFork->getResourceIDList(MKTAG('X', 'C', 'M', 'D'));
+				for (Common::Array<uint16>::iterator iterator = xcmd.begin(); iterator != xcmd.end(); ++iterator) {
+					Resource res = resFork->getResourceDetail(MKTAG('X', 'C', 'M', 'D'), *iterator);
+					debug(0, "Detected XCMD '%s'", res.name.c_str());
+					g_lingo->openXLib(res.name, kXObj);
+				}
+			}
+			if (resFork->hasResource(MKTAG('X', 'F', 'C', 'N'), -1)) {
+				Common::Array<uint16> xfcn = resFork->getResourceIDList(MKTAG('X', 'F', 'C', 'N'));
+				for (Common::Array<uint16>::iterator iterator = xfcn.begin(); iterator != xfcn.end(); ++iterator) {
+					Resource res = resFork->getResourceDetail(MKTAG('X', 'F', 'C', 'N'), *iterator);
+					debug(0, "Detected XFCN '%s'", res.name.c_str());
+					g_lingo->openXLib(res.name, kXObj);
+				}
+			}
 		}
+		delete resFork;
 	}
-	// Register the resfile so that Cursor::readFromResource can find it
-	g_director->_allOpenResFiles.setVal(archive->getPathName(), archive);
 }
 
-Archive *Window::openArchive(const Common::String movie) {
-	debug(1, "openArchive(\"%s\")", movie.c_str());
+Archive *DirectorEngine::openArchive(const Common::String path) {
+	debug(1, "DirectorEngine::openArchive(\"%s\")", path.c_str());
 
 	// If the archive is already open, don't reopen it;
 	// just init from the existing archive. This prevents errors that
 	// can happen when trying to load the same archive more than once.
-	if (g_director->_allOpenResFiles.contains(movie) && SearchMan.hasFile(movie)) {
-		return g_director->_allOpenResFiles.getVal(movie);
+	if (_allOpenResFiles.contains(path)) {
+		return _allOpenResFiles.getVal(path);
 	}
 
 	Archive *result = nullptr;
-	if (g_director->getPlatform() == Common::kPlatformWindows) {
-		result = loadEXE(movie);
+	if (getPlatform() == Common::kPlatformWindows) {
+		result = loadEXE(path);
 	} else {
-		probeProjector(movie);
-		result = loadMac(movie);
+		result = loadMac(path);
 	}
 	if (!result) {
-		result = g_director->createArchive();
-		if (!result->openFile(movie)) {
+		result = createArchive();
+		if (!result->openFile(path)) {
 			delete result;
-			result = nullptr;
+			return nullptr;
 		}
 	}
+	result->setPathName(path);
+	_allOpenResFiles.setVal(path, result);
+
 	return result;
 }
 
@@ -251,11 +251,11 @@ void Window::loadINIStream() {
 	}
 }
 
-Archive *Window::loadEXE(const Common::String movie) {
+Archive *DirectorEngine::loadEXE(const Common::String movie) {
 	Common::Path path(movie, g_director->_dirSeparator);
 	Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(path);
 	if (!exeStream) {
-		warning("Window::loadEXE(): Failed 1 to open EXE '%s'", g_director->getEXEName().c_str());
+		debugC(5, kDebugLoading, "DirectorEngine::loadEXE(): Failed to open file '%s'", movie.c_str());
 		return nullptr;
 	}
 
@@ -269,14 +269,14 @@ Archive *Window::loadEXE(const Common::String movie) {
 		result = new RIFFArchive();
 
 		if (!result->openStream(exeStream, 0)) {
-			warning("Window::loadEXE(): Failed to load RIFF");
+			debugC(5, kDebugLoading, "Window::loadEXE(): Failed to load RIFF from '%s'", movie.c_str());
 			delete result;
 			return nullptr;
 		}
 	} else {
 		Common::WinResources *exe = Common::WinResources::createFromEXE(path.toString());
 		if (!exe) {
-			warning("Window::loadEXE(): Failed 2 to open EXE '%s'", g_director->getEXEName().c_str());
+			debugC(5, kDebugLoading, "DirectorEngine::loadEXE(): Failed to open EXE '%s'", path.toString().c_str());
 			delete exeStream;
 			return nullptr;
 		}
@@ -286,7 +286,7 @@ Archive *Window::loadEXE(const Common::String movie) {
 			Common::WinResources::VersionInfo *info = exe->getVersionResource(versions[i]);
 
 			for (Common::WinResources::VersionHash::const_iterator it = info->hash.begin(); it != info->hash.end(); ++it)
-				warning("Window::loadEXE(): info <%s>: <%s>", it->_key.c_str(), it->_value.encode().c_str());
+				debugC(5, kDebugLoading, "DirectorEngine::loadEXE(): info <%s>: <%s>", it->_key.c_str(), it->_value.encode().c_str());
 
 			delete info;
 
@@ -312,7 +312,7 @@ Archive *Window::loadEXE(const Common::String movie) {
 		} else if (g_director->getVersion() >= 200) {
 			result = loadEXEv3(exeStream);
 		} else {
-			warning("Window::loadEXE(): Unhandled Windows EXE version %d", g_director->getVersion());
+			warning("DirectorEngine::loadEXE(): Unhandled Windows EXE version %d", g_director->getVersion());
 			delete exeStream;
 			return nullptr;
 		}
@@ -331,7 +331,7 @@ Archive *Window::loadEXE(const Common::String movie) {
 	return result;
 }
 
-Archive *Window::loadEXEv3(Common::SeekableReadStream *stream) {
+Archive *DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
 	uint32 mmmSize = 0;
 	Common::String mmmFileName;
 	Common::String directoryName;
@@ -355,12 +355,12 @@ Archive *Window::loadEXEv3(Common::SeekableReadStream *stream) {
 			directoryName = directoryName_;
 		} else {
 			if (!SearchMan.hasFile(Common::Path(mmmFileName_, g_director->_dirSeparator)))
-				warning("Window::loadEXEv3(): Failed to find MMM '%s'", mmmFileName_.c_str());
+				warning("DirectorEngine::loadEXEv3(): Failed to find MMM '%s'", mmmFileName_.c_str());
 			else {
 				Common::SeekableReadStream *const mmmFile_ = SearchMan.createReadStreamForMember(Common::Path(mmmFileName_, g_director->_dirSeparator));
 				uint32 mmmFileSize_ = mmmFile_->size();
 				if (mmmSize_ != mmmFileSize_)
-					warning("Window::loadEXEv3(): File size for '%s' doesn't match. Got %d (0x%x), want %d (0x%x)", mmmFileName_.c_str(), mmmFileSize_, mmmFileSize_, mmmSize_, mmmSize_);
+					warning("DirectorEngine::loadEXEv3(): File size for '%s' doesn't match. Got %d (0x%x), want %d (0x%x)", mmmFileName_.c_str(), mmmFileSize_, mmmFileSize_, mmmSize_, mmmSize_);
 				delete mmmFile_;
 			}
 		}
@@ -383,7 +383,7 @@ Archive *Window::loadEXEv3(Common::SeekableReadStream *stream) {
 
 
 			if (!out.open(fname.c_str(), true)) {
-				warning("Window::loadEXEv3(): Can not open dump file %s", fname.c_str());
+				warning("DirectorEngine::loadEXEv3(): Can not open dump file %s", fname.c_str());
 			} else {
 				out.write(buf, mmmSize);
 
@@ -400,27 +400,27 @@ Archive *Window::loadEXEv3(Common::SeekableReadStream *stream) {
 		if (result->openStream(stream, riffOffset))
 			return result;
 
-		warning("Window::loadEXEv3(): Failed to load RIFF from EXE");
+		warning("DirectorEngine::loadEXEv3(): Failed to load RIFF from EXE");
 		delete result;
 		result = nullptr;
 		delete stream;
 	}
 
-	result = g_director->createArchive();
+	result = createArchive();
 
 	if (!result->openFile(mmmFileName)) {
-		warning("Window::loadEXEv3(): Could not open '%s'", mmmFileName.c_str());
+		warning("DirectorEngine::loadEXEv3(): Could not open '%s'", mmmFileName.c_str());
 		delete result;
 		result = nullptr;
 	}
 	return result;
 }
 
-Archive *Window::loadEXEv4(Common::SeekableReadStream *stream) {
+Archive *DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
 	uint32 ver = stream->readUint32BE();
 
 	if (ver != MKTAG('P', 'J', '9', '3')) {
-		warning("Window::loadEXEv4(): Invalid projector tag found in v4 EXE [%s]", tag2str(ver));
+		warning("DirectorEngine::loadEXEv4(): Invalid projector tag found in v4 EXE [%s]", tag2str(ver));
 		return nullptr;
 	}
 
@@ -433,16 +433,16 @@ Archive *Window::loadEXEv4(Common::SeekableReadStream *stream) {
 	/* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
 	uint32 flags = stream->readUint32LE();
 
-	warning("Window::loadEXEv4(): PJ93 projector flags: %08x", flags);
+	warning("DirectorEngine::loadEXEv4(): PJ93 projector flags: %08x", flags);
 
 	return loadEXERIFX(stream, rifxOffset);
 }
 
-Archive *Window::loadEXEv5(Common::SeekableReadStream *stream) {
+Archive *DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
 	uint32 ver = stream->readUint32LE();
 
 	if (ver != MKTAG('P', 'J', '9', '5')) {
-		warning("Window::loadEXEv5(): Invalid projector tag found in v5 EXE [%s]", tag2str(ver));
+		warning("DirectorEngine::loadEXEv5(): Invalid projector tag found in v5 EXE [%s]", tag2str(ver));
 		return nullptr;
 	}
 
@@ -457,16 +457,16 @@ Archive *Window::loadEXEv5(Common::SeekableReadStream *stream) {
 	stream->readUint32LE(); // number of driver files
 	stream->readUint32LE(); // fontMapOffset
 
-	warning("Window::loadEXEv5(): PJ95 projector pflags: %08x  flags: %08x", pflags, flags);
+	warning("DirectorEngine::loadEXEv5(): PJ95 projector pflags: %08x  flags: %08x", pflags, flags);
 
 	return loadEXERIFX(stream, rifxOffset);
 }
 
-Archive *Window::loadEXEv7(Common::SeekableReadStream *stream) {
+Archive *DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) {
 	uint32 ver = stream->readUint32LE();
 
 	if (ver != MKTAG('P', 'J', '0', '0') && ver != MKTAG('P', 'J', '0', '1')) {
-		warning("Window::loadEXEv7(): Invalid projector tag found in v7 EXE [%s]", tag2str(ver));
+		warning("DirectorEngine::loadEXEv7(): Invalid projector tag found in v7 EXE [%s]", tag2str(ver));
 		return nullptr;
 	}
 
@@ -480,33 +480,33 @@ Archive *Window::loadEXEv7(Common::SeekableReadStream *stream) {
 	return loadEXERIFX(stream, rifxOffset);
 }
 
-Archive *Window::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
+Archive *DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
 	Archive *result = new RIFXArchive();
 
 	if (!result->openStream(stream, offset)) {
-		warning("Window::loadEXERIFX(): Failed to load RIFX from EXE");
+		warning("DirectorEngine::loadEXERIFX(): Failed to load RIFX from EXE");
 		delete result;
 		result = nullptr;
 	}
 	return result;
 }
 
-Archive *Window::loadMac(const Common::String movie) {
+Archive *DirectorEngine::loadMac(const Common::String movie) {
 	Archive *result = nullptr;
 	if (g_director->getVersion() < 400) {
 		// The data is part of the resource fork of the executable
-		result = g_director->createArchive();
+		result = createArchive();
 
 		if (!result->openFile(movie)) {
 			delete result;
 			result = nullptr;
-			warning("Window::loadMac(): Could not open '%s'", movie.c_str());
+			debugC(5, kDebugLoading, "DirectorEngine::loadMac(): Could not open '%s'", movie.c_str());
 		}
 	} else {
 		// The RIFX is located in the data fork of the executable
 		Common::SeekableReadStream *dataFork = Common::MacResManager::openFileOrDataFork(Common::Path(movie, g_director->_dirSeparator));
 		if (!dataFork) {
-			warning("Window::loadMac(): Failed to open Mac binary '%s'", movie.c_str());
+			debugC(5, kDebugLoading, "DirectorEngine::loadMac(): Failed to open Mac binary '%s'", movie.c_str());
 			return nullptr;
 		}
 		result = new RIFXArchive();
@@ -526,13 +526,9 @@ Archive *Window::loadMac(const Common::String movie) {
 		}
 
 		if (!result->openStream(dataFork, startOffset)) {
-			warning("Window::loadMac(): Failed to load RIFX from Mac binary");
+			debugC(5, kDebugLoading, "DirectorEngine::loadMac(): Failed to load RIFX from Mac binary");
 			delete result;
 			result = nullptr;
-			if (_currentMovie) {
-				delete _currentMovie;
-				_currentMovie = nullptr;
-			}
 		}
 	}
 	return result;
@@ -588,7 +584,7 @@ bool ProjectorArchive::loadArchive(Common::SeekableReadStream *stream) {
 
 	// Check whether we got a 'PJ' tag while ignoring the version and accounting for endianness
 	if (((tag & 0xffff0000) != MKTAG('P','J', 0, 0)) && ((tag & 0x0000ffff) != MKTAG(0, 0, 'J','P'))) {
-		warning("ProjectorArchive::loadArchive(): Projector Tag not found");
+		debugC(5, kDebugLoading, "ProjectorArchive::loadArchive(): Projector Tag not found");
 		return false;
 	}
 
diff --git a/engines/director/tests.cpp b/engines/director/tests.cpp
index 86afe336610..5566af5f48f 100644
--- a/engines/director/tests.cpp
+++ b/engines/director/tests.cpp
@@ -190,10 +190,8 @@ Common::HashMap<Common::String, Movie *> *Window::scanMovies(const Common::Strin
 				continue;
 			}
 
-			Archive *arc = _vm->createArchive();
-
 			warning("name: %s", i->getName().c_str());
-			arc->openFile(i->getName());
+			Archive *arc = _vm->openArchive(i->getName());
 			Movie *m = new Movie(this);
 			m->setArchive(arc);
 			nameMap->setVal(m->getMacName(), m);
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 3d76bf9ae35..6cdeb459e19 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -354,8 +354,7 @@ void Window::loadNewSharedCast(Cast *previousSharedCast) {
 	}
 
 	// Clean up the previous sharedCast
-	if (!previousSharedCastPath.empty()) {
-		g_director->_allOpenResFiles.erase(previousSharedCastPath);
+	if (previousSharedCast) {
 		delete previousSharedCast;
 	}
 
@@ -379,11 +378,12 @@ bool Window::loadNextMovie() {
 	delete _currentMovie;
 	_currentMovie = nullptr;
 
-	Archive *mov = openArchive(_currentPath + Common::lastPathComponent(_nextMovie.movie, g_director->_dirSeparator));
+	Archive *mov = g_director->openArchive(_currentPath + Common::lastPathComponent(_nextMovie.movie, g_director->_dirSeparator));
 
 	if (!mov)
 		return false;
 
+	probeResources(mov);
 	_currentMovie = new Movie(this);
 	_currentMovie->setArchive(mov);
 
diff --git a/engines/director/window.h b/engines/director/window.h
index 20ee6da0ee0..69a9965820a 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -171,17 +171,8 @@ public:
 
 	// resource.cpp
 	Common::Error loadInitialMovie();
-	void probeProjector(const Common::String &movie);
-	void probeMacBinary(MacArchive *archive);
+	void probeResources(Archive *archive);
 	void loadINIStream();
-	Archive *openArchive(const Common::String movie);
-	Archive *loadEXE(const Common::String movie);
-	Archive *loadEXEv3(Common::SeekableReadStream *stream);
-	Archive *loadEXEv4(Common::SeekableReadStream *stream);
-	Archive *loadEXEv5(Common::SeekableReadStream *stream);
-	Archive *loadEXEv7(Common::SeekableReadStream *stream);
-	Archive *loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset);
-	Archive *loadMac(const Common::String movie);
 	void loadStartMovieXLibs();
 
 	// lingo/lingo-object.cpp


Commit: dcd897e5c6d5411b8e0b2561d1cd8e3c76513105
    https://github.com/scummvm/scummvm/commit/dcd897e5c6d5411b8e0b2561d1cd8e3c76513105
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Add Object::incRefCount() and Object::decRefCount() helpers

Changed paths:
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-object.h
    engines/director/lingo/lingo.cpp


diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index 1336d241597..13c17f3513c 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -1639,7 +1639,7 @@ void LingoArchive::addCodeV4(Common::SeekableReadStreamEndian &stream, uint16 lc
 	ScriptContext *ctx = g_lingo->_compiler->compileLingoV4(stream, lctxIndex, this, archName, version);
 	if (ctx) {
 		lctxContexts[lctxIndex] = ctx;
-		*ctx->_refCount += 1;
+		ctx->incRefCount();
 	}
 }
 
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 4274a5657aa..d7b1ceba252 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -251,7 +251,7 @@ void Lingo::pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRet
 
 	if (funcSym.ctx) {
 		_state->context = funcSym.ctx;
-		*_state->context->_refCount += 1;
+		_state->context->incRefCount();
 	}
 
 	DatumHash *localvars = new DatumHash;
@@ -343,10 +343,7 @@ void Lingo::popContext(bool aborting) {
 		error("handler %s popped extra %d values", fp->sp.name->c_str(), fp->stackSizeBefore - _stack.size());
 	}
 
-	*_state->context->_refCount -= 1;
-	if (*_state->context->_refCount <= 0) {
-		delete _state->context;
-	}
+	_state->context->decRefCount();
 
 	_state->script = fp->retScript;
 	_state->context = fp->retContext;
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 1393b2d7bab..809fe67696a 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -386,7 +386,7 @@ void LingoCompiler::registerFactory(Common::String &name) {
 			_assemblyArchive->factoryContexts[_assemblyId] = new Common::HashMap<Common::String, ScriptContext *>();
 		}
 		if (!_assemblyArchive->factoryContexts[_assemblyId]->contains(name)) {
-			*_assemblyContext->_refCount += 1;
+			_assemblyContext->incRefCount();
 			(*_assemblyArchive->factoryContexts[_assemblyId])[name] = _assemblyContext;
 		}
 	}
diff --git a/engines/director/lingo/lingo-object.h b/engines/director/lingo/lingo-object.h
index 71e72f29ebc..50d2f723a6e 100644
--- a/engines/director/lingo/lingo-object.h
+++ b/engines/director/lingo/lingo-object.h
@@ -43,6 +43,8 @@ public:
 	virtual ObjectType getObjType() const = 0;
 	virtual bool isDisposed() const = 0;
 	virtual int *getRefCount() const = 0;
+	virtual void incRefCount() const = 0;
+	virtual void decRefCount() const = 0;
 	virtual int getInheritanceLevel() const = 0;
 
 	virtual void setName(const Common::String &name) = 0;
@@ -118,6 +120,12 @@ public:
 	ObjectType getObjType() const override { return _objType; };
 	bool isDisposed() const override { return _disposed; };
 	int *getRefCount() const override { return _refCount; };
+	void incRefCount() const override { *_refCount += 1; };
+	void decRefCount() const override {
+		*_refCount -= 1;
+		if (*_refCount <= 0)
+			delete this;
+	};
 	int getInheritanceLevel() const override { return _inheritanceLevel; };
 
 	void setName(const Common::String &name) override { _name = name; };
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 3839f2bd668..0c9908da5b8 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -157,18 +157,14 @@ LingoState::~LingoState() {
 		if (callstack[i]->retLocalVars)
 			delete callstack[i]->retLocalVars;
 		if (callstack[i]->retContext) {
-			*callstack[i]->retContext->_refCount -= 1;
-			if (*callstack[i]->retContext->_refCount == 0)
-				delete callstack[i]->retContext;
+			callstack[i]->retContext->decRefCount();
 		}
 		delete callstack[i];
 	}
 	if (localVars)
 		delete localVars;
 	if (context) {
-		*context->_refCount -= 1;
-		if (*context->_refCount == 0)
-			delete context;
+		context->decRefCount();
 	}
 
 }
@@ -251,25 +247,19 @@ LingoArchive::~LingoArchive() {
 	for (ScriptContextHash::iterator it = lctxContexts.begin(); it != lctxContexts.end(); ++it){
 		ScriptContext *script = it->_value;
 		if (script->getOnlyInLctxContexts()) {
-			*script->_refCount -= 1;
-			if (*script->_refCount <= 0)
-				delete script;
+			script->decRefCount();
 		}
 	}
 
 	for (int i = 0; i <= kMaxScriptType; i++) {
 		for (ScriptContextHash::iterator it = scriptContexts[i].begin(); it != scriptContexts[i].end(); ++it) {
-			*it->_value->_refCount -= 1;
-			if (*it->_value->_refCount <= 0)
-				delete it->_value;
+			it->_value->decRefCount();
 		}
 	}
 
-	for (auto it : factoryContexts) {
-		for (auto jt : *it._value) {
-			*jt._value->_refCount -= 1;
-			if (*jt._value->_refCount <= 0)
-				delete jt._value;
+	for (auto &it : factoryContexts) {
+		for (auto &jt : *it._value) {
+			jt._value->decRefCount();
 		}
 		delete it._value;
 	}
@@ -373,7 +363,7 @@ void LingoArchive::addCode(const Common::U32String &code, ScriptType type, uint1
 	ScriptContext *sc = g_lingo->_compiler->compileLingo(code, this, type, CastMemberID(id, cast->_castLibID), contextName, false, preprocFlags);
 	if (sc) {
 		scriptContexts[type][id] = sc;
-		*sc->_refCount += 1;
+		sc->incRefCount();
 	}
 }
 
@@ -382,10 +372,7 @@ void LingoArchive::removeCode(ScriptType type, uint16 id) {
 	if (!ctx)
 		return;
 
-	*ctx->_refCount -= 1;
-	if (*ctx->_refCount <= 0) {
-		delete ctx;
-	}
+	ctx->decRefCount();
 	scriptContexts[type].erase(id);
 }
 


Commit: d69dac601604a5cb682c4bb584c25a6dcb3a67a3
    https://github.com/scummvm/scummvm/commit/d69dac601604a5cb682c4bb584c25a6dcb3a67a3
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
COMMON: Fix file handle leak in generateZipSet()

Changed paths:
    common/zip-set.cpp


diff --git a/common/zip-set.cpp b/common/zip-set.cpp
index e76b9888530..8e45e00d1d2 100644
--- a/common/zip-set.cpp
+++ b/common/zip-set.cpp
@@ -85,8 +85,8 @@ bool generateZipSet(SearchSet &searchSet, const char *defaultFile, const char *p
 
 		if (!dat) {
 			warning("generateZipSet: Could not find '%s'", defaultFile);
-			delete file;
 		}
+		delete file;
 	}
 
 	if (dat) {


Commit: 871c1d0907615cdc292fefb00a58ea64010cc4c0
    https://github.com/scummvm/scummvm/commit/871c1d0907615cdc292fefb00a58ea64010cc4c0
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Fix leak in Window::runTests()

Changed paths:
    engines/director/tests.cpp


diff --git a/engines/director/tests.cpp b/engines/director/tests.cpp
index 5566af5f48f..bf851644024 100644
--- a/engines/director/tests.cpp
+++ b/engines/director/tests.cpp
@@ -304,6 +304,7 @@ void Window::runTests() {
 	initGraphics(640, 480);
 
 	_mainArchive = new RIFXArchive();
+	g_director->_allOpenResFiles.setVal("test.dir", _mainArchive);
 	if (!_mainArchive->openStream(stream, 0)) {
 		error("DirectorEngine::runTests(): Bad movie data");
 	}


Commit: 14474ce1292979a8c6382694ffdc22ba67a8bd32
    https://github.com/scummvm/scummvm/commit/14474ce1292979a8c6382694ffdc22ba67a8bd32
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Fix "the number of castMembers"

This figure is supposed to be the highest member ID for a cast member in
the current movie, not the actual count of cast members.

In addition, Lingo only throws an error when querying cast member IDs that
are higher than this figure. If the member ID is lower and the cast
member doesn't exist, "the" queries return a VOID.

Fixes the verify cast table check in Star Trek TNG Episode Guide.

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/lingo/lingo-the.cpp
    engines/director/lingo/lingo.h


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 9cdcd38a72f..9bb9a5192f7 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -179,6 +179,14 @@ int Cast::getCastSize() {
 	return _loadedCast->size();
 }
 
+int Cast::getCastMaxID() {
+	int result = 0;
+	for (auto &it : *_loadedCast) {
+		result = MAX(result, it._key);
+	}
+	return result;
+}
+
 Common::Rect Cast::getCastMemberInitialRect(int castId) {
 	CastMember *cast = _loadedCast->getVal(castId);
 
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 430fff34a26..45d84cc42a0 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -95,6 +95,7 @@ public:
 	void loadSord(Common::SeekableReadStreamEndian &stream);
 
 	int getCastSize();
+	int getCastMaxID();
 	Common::Rect getCastMemberInitialRect(int castId);
 	void setCastMemberModified(int castId);
 	CastMember *setCastMember(CastMemberID castId, CastMember *cast);
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 1e2a1d5be18..e6e75ab4c27 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -397,7 +397,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		d = getCastlibsNum();
 		break;
 	case kTheCastMembers:
-		d = (int)(movie->getCast()->getCastSize() + (movie->_sharedCast ? movie->_sharedCast->getCastSize() : 0));
+		d = getMembersNum();
 		break;
 	case kTheCenterStage:
 		d = g_director->_centerStage;
@@ -1230,6 +1230,12 @@ int Lingo::getCastlibsNum() {
 	return _vm->getCurrentMovie()->getCasts()->size();
 }
 
+int Lingo::getMembersNum() {
+	// FIXME: deal with D5 castlibs
+	Movie *movie = _vm->getCurrentMovie();
+	return (MAX(movie->getCast()->getCastMaxID(), (movie->_sharedCast ? movie->_sharedCast->getCastMaxID() : 0)));
+}
+
 int Lingo::getXtrasNum() {
 	return _openXLibs.size();
 }
@@ -1684,6 +1690,11 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 			d = 0;
 		} else if (field == kTheNumber) {
 			d = -1;
+		} else if (id.member <= getMembersNum()) {
+			// If a cast member with the ID doesn't exist,
+			// but the ID isn't greater than the biggest cast member ID,
+			// Lingo will not crash, and instead return a VOID.
+			return d;
 		} else {
 			g_lingo->lingoError("Lingo::getTheCast(): CastMember %s not found", id1.asString().c_str());
 		}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 46da22f4dce..770b7e8d6d9 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -332,6 +332,7 @@ public:
 	int getMenuItemsNum(Datum &d);
 	int getXtrasNum();
 	int getCastlibsNum();
+	int getMembersNum();
 
 	void executeHandler(const Common::String &name);
 	void executeScript(ScriptType type, CastMemberID id);


Commit: 993c473bb606362ac9c25b5d1d11dd8dc088fe67
    https://github.com/scummvm/scummvm/commit/993c473bb606362ac9c25b5d1d11dd8dc088fe67
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: b_objectp should return 1 for ARRAY and PARRAY

Fixes the constants init loading section of Star Trek TNG
Episode Guide.

Changed paths:
    engines/director/lingo/lingo-builtins.cpp


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 0aa1aa042af..58b44107981 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1745,6 +1745,8 @@ void LB::b_objectp(int nargs) {
 	Datum res;
 	if (d.type == OBJECT) {
 		res = !d.u.obj->isDisposed();
+	} else if (d.type == ARRAY || d.type == PARRAY) {
+		res = 1;
 	} else {
 		res = 0;
 	}


Commit: 9b29fff76c9ad2e9eb76dde25943f76c4ba94a4e
    https://github.com/scummvm/scummvm/commit/9b29fff76c9ad2e9eb76dde25943f76c4ba94a4e
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Make b_sort behaviour more accurate

Fixes the constants init loading section of Star Trek TNG
Episode Guide.

Changed paths:
  A engines/director/lingo/tests/sort.lingo
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 58b44107981..3cb6f794e0c 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1076,26 +1076,57 @@ void LB::b_setProp(int nargs) {
 }
 
 static bool sortArrayHelper(const Datum &lhs, const Datum &rhs) {
-	return lhs.asInt() < rhs.asInt();
+	return lhs.asString() < rhs.asString();
+}
+
+static bool sortNumericArrayHelper(const Datum &lhs, const Datum &rhs) {
+	return lhs.asFloat() < rhs.asFloat();
 }
 
 static bool sortPArrayHelper(const PCell &lhs, const PCell &rhs) {
 	return lhs.p.asString() < rhs.p.asString();
 }
 
+static bool sortNumericPArrayHelper(const PCell &lhs, const PCell &rhs) {
+	return lhs.p.asFloat() < rhs.p.asFloat();
+}
+
 void LB::b_sort(int nargs) {
 	// in D4 manual, p266. linear list is sorted by values
 	// property list is sorted alphabetically by properties
-	// once the list is sorted, it maintains it's sort order even when we add new variables using add command
+	// once the list is sorted, it maintains its sort order even when we add new variables using add command
 	// see b_append to get more details.
 	Datum list = g_lingo->pop();
 
 	if (list.type == ARRAY) {
-		Common::sort(list.u.farr->arr.begin(), list.u.farr->arr.end(), sortArrayHelper);
+		// Check to see if the array is full of numbers
+		bool isNumeric = true;
+		for (const auto &it : list.u.farr->arr) {
+			isNumeric &= it.isNumeric();
+		}
+		if (isNumeric) {
+			// Sorting an array of numbers will use numeric sort order.
+			Common::sort(list.u.farr->arr.begin(), list.u.farr->arr.end(), sortNumericArrayHelper);
+		} else {
+			// Sorting an array of strings will use the string sort order.
+			// Sorting an array of mixed types is undefined behaviour; sometimes the interpreter
+			// will give an answer nearly the same as the string sort order, other times
+			// the interpreter will softlock.
+			Common::sort(list.u.farr->arr.begin(), list.u.farr->arr.end(), sortArrayHelper);
+		}
 		list.u.farr->_sorted = true;
 
 	} else if (list.type == PARRAY) {
-		Common::sort(list.u.parr->arr.begin(), list.u.parr->arr.end(), sortPArrayHelper);
+		// Check to see if the array is full of numbers
+		bool isNumeric = true;
+		for (const auto &it : list.u.parr->arr) {
+			isNumeric &= it.p.isNumeric();
+		}
+		if (isNumeric) {
+			Common::sort(list.u.parr->arr.begin(), list.u.parr->arr.end(), sortNumericPArrayHelper);
+		} else {
+			Common::sort(list.u.parr->arr.begin(), list.u.parr->arr.end(), sortPArrayHelper);
+		}
 		list.u.parr->_sorted = true;
 
 	} else {
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 0c9908da5b8..ecfa2b9283e 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -1197,6 +1197,10 @@ bool Datum::isArray() const {
 	return (type == ARRAY || type == POINT || type == RECT);
 }
 
+bool Datum::isNumeric() const {
+	return (type == INT || type == FLOAT);
+}
+
 const char *Datum::type2str(bool ilk) const {
 	static char res[20];
 
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 770b7e8d6d9..94f0e366830 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -178,6 +178,7 @@ struct Datum {	/* interpreter stack type */
 	bool isVarRef() const;
 	bool isCastRef() const;
 	bool isArray() const;
+	bool isNumeric() const;
 
 	const char *type2str(bool ilk = false) const;
 
diff --git a/engines/director/lingo/tests/sort.lingo b/engines/director/lingo/tests/sort.lingo
new file mode 100644
index 00000000000..171c2c0507c
--- /dev/null
+++ b/engines/director/lingo/tests/sort.lingo
@@ -0,0 +1,24 @@
+
+-- Just ints, use numeric sort
+set test to [200, 100, 25, 4, 3, 2, 1]
+sort(test)
+scummvmAssertEqual(test, [1, 2, 3, 4, 25, 100, 200])
+
+-- Just floats, use numeric sort
+set test to [200.5, 100.5, 25.5, 4.5, 3.5, 2.5, 1.5]
+sort(test)
+scummvmAssertEqual(test, [1.5, 2.5, 3.5, 4.5, 25.5, 100.5, 200.5])
+
+-- ints and floats, use numeric sort
+set test to [200, 100, 25, 4, 3, 2, 1, 2.5]
+sort(test)
+scummvmAssertEqual(test, [1, 2, 2.5, 3, 4, 25, 100, 200])
+
+-- Just strings, use string sort
+set test to ["200", "100", "25", "4", "3", "2", "1", "2.5", "oh no"]
+sort(test)
+scummvmAssertEqual(test, ["1", "100", "2", "2.5", "200", "25", "3", "4", "oh no"])
+
+-- For combined types (e.g. ints and strings), the result is undefined.
+-- The real interpreter will give an answer that's nearly the same as the
+-- string sort order, or softlock.


Commit: 07608d13ec5540dc71e69d08573194aceb135f13
    https://github.com/scummvm/scummvm/commit/07608d13ec5540dc71e69d08573194aceb135f13
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Add stub for Color XObj

Changed paths:
  A engines/director/lingo/xlibs/colorxobj.cpp
  A engines/director/lingo/xlibs/colorxobj.h
    engines/director/lingo/lingo-object.cpp
    engines/director/lingo/xlibs/qtvr.cpp
    engines/director/module.mk


diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 4857b78ba39..cbc4cd49aab 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -39,6 +39,7 @@
 #include "director/lingo/xlibs/batqt.h"
 #include "director/lingo/xlibs/blitpict.h"
 #include "director/lingo/xlibs/cdromxobj.h"
+#include "director/lingo/xlibs/colorxobj.h"
 #include "director/lingo/xlibs/darkenscreen.h"
 #include "director/lingo/xlibs/developerStack.h"
 #include "director/lingo/xlibs/dialogsxobj.h"
@@ -165,6 +166,7 @@ static struct XLibProto {
 	{ BatQT::fileNames,					BatQT::open,				BatQT::close,				kXObj,					400 },	// D4
 	{ BlitPict::fileNames,				BlitPict::open,				BlitPict::close,			kXObj,					400 },	// D4
 	{ CDROMXObj::fileNames,				CDROMXObj::open,			CDROMXObj::close,			kXObj,					200 },	// D2
+	{ ColorXObj::fileNames,				ColorXObj::open,			ColorXObj::close,			kXObj,					400 },	// D4
 	{ DarkenScreen::fileNames,			DarkenScreen::open,			DarkenScreen::close,		kXObj,					300 },	// D3
 	{ DeveloperStack::fileNames,		DeveloperStack::open,		DeveloperStack::close,		kXObj,					300 },	// D3
 	{ DialogsXObj::fileNames,			DialogsXObj::open,			DialogsXObj::close,			kXObj,					400 },	// D4
@@ -182,7 +184,7 @@ static struct XLibProto {
 	{ FlushXObj::fileNames,				FlushXObj::open,			FlushXObj::close,			kXObj,					300 },	// D3
 	{ FPlayXObj::fileNames,				FPlayXObj::open,			FPlayXObj::close,			kXObj,					200 },	// D2
 	{ GpidXObj::fileNames,				GpidXObj::open,				GpidXObj::close,			kXObj,					400 },	// D4
-	{ HitMap::fileNames,				HitMap::open,				HitMap::close,			kXObj,					400 },	// D4
+	{ HitMap::fileNames,				HitMap::open,				HitMap::close,				kXObj,					400 },	// D4
 	{ IsCD::fileNames,					IsCD::open,					IsCD::close,				kXObj,					300 },	// D3
 	{ IsPippin::fileNames,				IsPippin::open,				IsPippin::close,			kXObj,					400 },	// D4
 	{ JITDraw3XObj::fileNames,			JITDraw3XObj::open,			JITDraw3XObj::close,		kXObj,					400 },	// D4
diff --git a/engines/director/lingo/xlibs/colorxobj.cpp b/engines/director/lingo/xlibs/colorxobj.cpp
new file mode 100644
index 00000000000..ac490e16ec3
--- /dev/null
+++ b/engines/director/lingo/xlibs/colorxobj.cpp
@@ -0,0 +1,121 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**********************************************
+ *
+ * USED IN:
+ * Star Trek TNG Episode Guide
+ *
+ **********************************************/
+
+/*
+ * -- Color External Factory. 16Feb93 PTM
+ * Color
+ * I      mNew                --Creates a new instance of the XObject
+ * X      mDispose            --Disposes of XObject instance
+ * X      mSetOurColors       --Set Trek-happy colors
+ * X      mRestoreColors      --Restore real windows colors
+ * S      mName               --Returns the XObject name (Widget)
+ * I      mStatus             --Returns an integer status code
+ * SI     mError, code        --Returns an error string
+ * S      mLastError          --Returns last error string
+ * III    mAdd, arg1, arg2    --Returns arg1+arg2
+ * SSI    mFirst, str, nchars --Return the first nchars of string str
+ * V      mMul, f1, f2        --Returns f1*f2 as floating point
+ * X      mGlobals            --Sample code to Read & Modify globals
+ * X      mSymbols            --Sample code to work with Symbols
+ * X      mSendPerform        --Sample code to show SendPerform call
+ * X      mFactory            --Sample code to find Factory objects
+ * II     mGetSysColor, attrib  -- gets rgb attrib as a long
+ * III    mSetSysColor, attrib, rgbVal    -- sets r,g,b as a long
+ * IIIII  mSetSysColorRGB, attrib, r, g, b    -- sets r,g,b as a 3 longs
+ * III    mSetSysColorIndex, attrib, nIndex    -- sets nth palette entry
+ */
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xlibs/colorxobj.h"
+
+
+namespace Director {
+
+const char *ColorXObj::xlibName = "Color";
+const char *ColorXObj::fileNames[] = {
+	"color",
+	"color.dll",
+	nullptr
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",					ColorXObj::m_new,					1, 1,	400 },	// D4
+	{ "dispose",				ColorXObj::m_dispose,				0, 0,	400 },	// D4
+	{ "setOurColors",			ColorXObj::m_setOurColors,			0, 0,	400 },	// D4
+	{ "restoreColors",			ColorXObj::m_restoreColors,			0, 0,	400 },	// D4
+	{ "getSysColor",			ColorXObj::m_getSysColor,			1, 1,	400 },	// D4
+	{ "setSysColor",			ColorXObj::m_setSysColor,			2, 2,	400 },	// D4
+	{ "setSysColorRGB",			ColorXObj::m_setSysColorRGB,		4, 4,	400 },	// D4
+	{ "setSysColorIndex",		ColorXObj::m_setSysColorIndex,		2, 2,	400 },	// D4
+	{ nullptr,					nullptr,							0, 0,	0 }
+};
+
+ColorXObject::ColorXObject(ObjectType ObjectType) :Object<ColorXObject>("Color") {
+	_objType = ObjectType;
+}
+
+void ColorXObj::open(int type) {
+	if (type == kXObj) {
+		ColorXObject::initMethods(xlibMethods);
+		ColorXObject *xobj = new ColorXObject(kXObj);
+		g_lingo->exposeXObject(xlibName, xobj);
+	} else if (type == kXtraObj) {
+		// TODO - Implement Xtra
+	}
+}
+
+void ColorXObj::close(int type) {
+	if (type == kXObj) {
+		ColorXObject::cleanupMethods();
+		g_lingo->_globalvars[xlibName] = Datum();
+	} else if (type == kXtraObj) {
+		// TODO - Implement Xtra
+	}
+}
+
+
+void ColorXObj::m_new(int nargs) {
+	if (nargs != 0) {
+		warning("ColorXObj::m_new: expected 0 arguments");
+		g_lingo->dropStack(nargs);
+	}
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(ColorXObj::m_dispose, 0);
+XOBJSTUBNR(ColorXObj::m_setOurColors);
+XOBJSTUBNR(ColorXObj::m_restoreColors);
+XOBJSTUB(ColorXObj::m_getSysColor, 0);
+XOBJSTUB(ColorXObj::m_setSysColor, 0);
+XOBJSTUB(ColorXObj::m_setSysColorRGB, 0);
+XOBJSTUB(ColorXObj::m_setSysColorIndex, 0);
+
+} // End of namespace Director
diff --git a/engines/director/lingo/xlibs/colorxobj.h b/engines/director/lingo/xlibs/colorxobj.h
new file mode 100644
index 00000000000..cb3e332f258
--- /dev/null
+++ b/engines/director/lingo/xlibs/colorxobj.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_LINGO_XLIBS_COLORXOBJ_H
+#define DIRECTOR_LINGO_XLIBS_COLORXOBJ_H
+
+namespace Director {
+
+namespace ColorXObj {
+
+extern const char *xlibName;
+extern const char *fileNames[];
+
+void open(int type);
+void close(int type);
+
+void m_new(int nargs);
+void m_dispose(int nargs);
+void m_setOurColors(int nargs);
+void m_restoreColors(int nargs);
+void m_getSysColor(int nargs);
+void m_setSysColor(int nargs);
+void m_setSysColorRGB(int nargs);
+void m_setSysColorIndex(int nargs);
+
+} // End of namespace ColorXObj
+
+class ColorXObject : public Object<ColorXObject> {
+public:
+	ColorXObject(ObjectType objType);
+};
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xlibs/qtvr.cpp b/engines/director/lingo/xlibs/qtvr.cpp
index 71945403935..998f0d8adf0 100644
--- a/engines/director/lingo/xlibs/qtvr.cpp
+++ b/engines/director/lingo/xlibs/qtvr.cpp
@@ -90,6 +90,7 @@ static MethodProto xlibMethods[] = {
 	{ "setVPanAngle",			QTVR::m_setVPanAngle,			1, 1,	400 },	// D4
 	{ "setZoomAngle",			QTVR::m_setZoomAngle,			1, 1,	400 },	// D4
 	{ "update",					QTVR::m_update,					0, 0,	400 },	// D4
+	{ nullptr,					nullptr,						0, 0,	0 }
 };
 
 QTVRXObject::QTVRXObject(ObjectType ObjectType) :Object<QTVRXObject>("QTVR") {
diff --git a/engines/director/module.mk b/engines/director/module.mk
index b0d84c14bb2..4bf6610e510 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -59,6 +59,7 @@ MODULE_OBJS = \
 	lingo/xlibs/batqt.o \
 	lingo/xlibs/blitpict.o \
 	lingo/xlibs/cdromxobj.o \
+	lingo/xlibs/colorxobj.o \
 	lingo/xlibs/darkenscreen.o \
 	lingo/xlibs/developerStack.o \
 	lingo/xlibs/dialogsxobj.o \


Commit: 507a4431a878bc8d5021a74d2decf20e01e108b1
    https://github.com/scummvm/scummvm/commit/507a4431a878bc8d5021a74d2decf20e01e108b1
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Fix b_getAt to support POINT

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-utils.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 3cb6f794e0c..2803afc27b6 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -801,6 +801,7 @@ void LB::b_getAt(int nargs) {
 
 	switch (list.type) {
 	case ARRAY:
+	case POINT:
 	case RECT:
 		ARRBOUNDSCHECK(index, list);
 		g_lingo->push(list.u.farr->arr[index - 1]);
@@ -810,7 +811,7 @@ void LB::b_getAt(int nargs) {
 		g_lingo->push(list.u.parr->arr[index - 1].v);
 		break;
 	default:
-		TYPECHECK3(list, ARRAY, PARRAY, RECT);
+		TYPECHECK4(list, ARRAY, PARRAY, POINT, RECT);
 	}
 }
 
diff --git a/engines/director/lingo/lingo-utils.h b/engines/director/lingo/lingo-utils.h
index 567a84624f3..59ad92b7944 100644
--- a/engines/director/lingo/lingo-utils.h
+++ b/engines/director/lingo/lingo-utils.h
@@ -47,6 +47,12 @@
 		return; \
 	}
 
+#define TYPECHECK4(datum, t1, t2, t3, t4)	\
+	if ((datum).type != (t1) && (datum).type != (t2) && (datum).type != (t3) && (datum).type != (t4)) { \
+		warning("BUILDBOT: %s: %s arg should be of type %s, %s, %s, or %s, not %s", __FUNCTION__, #datum, #t1, #t2, #t3, #t4, (datum).type2str()); \
+		return; \
+	}
+
 #define ARRBOUNDSCHECK(idx,array) \
 	if ((idx)-1 < 0 || (idx) > (int)(array).u.farr->arr.size()) { \
 		warning("BUILDBOT: %s: index out of bounds (%d of %d)", __FUNCTION__, (idx), (array).u.farr->arr.size()); \


Commit: c94f2de32160f00d0caafa3c072c0d58596465d7
    https://github.com/scummvm/scummvm/commit/c94f2de32160f00d0caafa3c072c0d58596465d7
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Add font quirks for two Star Trek games

Changed paths:
    engines/director/game-quirks.cpp
    graphics/macgui/macfontmanager.cpp


diff --git a/engines/director/game-quirks.cpp b/engines/director/game-quirks.cpp
index 3e75f4da65c..37010dee347 100644
--- a/engines/director/game-quirks.cpp
+++ b/engines/director/game-quirks.cpp
@@ -105,6 +105,18 @@ static void quirkMcLuhanWin() {
 	fontMan->loadWindowsFont("MCLUHAN/SYSTEM/MCL1N___.FON");
 }
 
+static void quirkTrekTechWin() {
+	Graphics::MacFontManager *fontMan = g_director->_wm->_fontMan;
+	fontMan->loadWindowsFont("TREKCON4.FON");
+}
+
+static void quirkTrekGuideTNGWin() {
+	Graphics::MacFontManager *fontMan = g_director->_wm->_fontMan;
+	fontMan->loadWindowsFont("OMNI2/TREKENCY.FON");
+	fontMan->loadWindowsFont("OMNI2/TREKOMNI.FON");
+}
+
+
 static void quirkPipCatalog() {
 	// Pippin game that uses Unix path separators rather than Mac
 	g_director->_dirSeparator = '/';
@@ -145,7 +157,7 @@ struct Quirk {
 	void (*quirk)();
 } quirks[] = {
 	// Eastern Mind sets the score to play back at a high frame rate,
-	// however the developers were using slow hardware, so some 
+	// however the developers were using slow hardware, so some
 	// animations play back much faster than intended.
 	// Limit the score framerate to be no higher than 15fps.
 	{ "easternmind", Common::kPlatformMacintosh, &quirkLimit15FPS },
@@ -168,6 +180,9 @@ struct Quirk {
 	{ "mamauta1", Common::kPlatformWindows, &quirk640x480Desktop },
 	{ "mcluhan", Common::kPlatformWindows, &quirkMcLuhanWin },
 	{ "mcluhan", Common::kPlatformMacintosh, &quirkMcLuhanMac },
+	// Star Trek titles install fonts into the system
+	{ "trektech", Common::kPlatformWindows, &quirkTrekTechWin },
+	{ "trekguidetng", Common::kPlatformWindows, &quirkTrekGuideTNGWin },
 	{ "pipcatalog", Common::kPlatformPippin, &quirkPipCatalog },
 	{ nullptr, Common::kPlatformUnknown, nullptr }
 };
diff --git a/graphics/macgui/macfontmanager.cpp b/graphics/macgui/macfontmanager.cpp
index 5110a796391..0aec0141e9d 100644
--- a/graphics/macgui/macfontmanager.cpp
+++ b/graphics/macgui/macfontmanager.cpp
@@ -525,7 +525,7 @@ const Font *MacFontManager::getFont(MacFont *macFont) {
 			const Graphics::WinFont *winfont = (const Graphics::WinFont *)font;
 
 			if (winfont->getFontHeight() != macFont->getSize())
-				warning("MacFontManager::getFont(): For font '%s' windows font '%s' is used of a different size %d", macFont->getName().c_str(), winfont->getName().c_str(), winfont->getFontHeight());
+				debug(5, "MacFontManager::getFont(): For font '%s' windows font '%s' is used of a different size %d", macFont->getName().c_str(), winfont->getName().c_str(), winfont->getFontHeight());
 		}
 	}
 


Commit: 354abe0cc72ff12b39b747276ac02ee07164b88e
    https://github.com/scummvm/scummvm/commit/354abe0cc72ff12b39b747276ac02ee07164b88e
Author: Scott Percival (code at moral.net.au)
Date: 2023-06-08T09:16:30+02:00

Commit Message:
DIRECTOR: Fix ProjectorArchive path lookup

Changed paths:
    engines/director/resource.cpp


diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index d2f3d1c7cc7..d766f796566 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -560,9 +560,10 @@ ProjectorArchive::ProjectorArchive(Common::String path)
 Common::SeekableReadStream *ProjectorArchive::createBufferedReadStream() {
 	const uint32 READ_BUFFER_SIZE = 1024 * 100;
 
-	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(_path);
+	Common::Path path(_path, g_director->_dirSeparator);
+	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(path);
 	if (!stream) {
-		warning("ProjectorArchive::createBufferedReadStream(): Cannot open %s", _path.c_str());
+		warning("ProjectorArchive::createBufferedReadStream(): Cannot open %s", path.toString().c_str());
 		return nullptr;
 	}
 




More information about the Scummvm-git-logs mailing list