[Scummvm-git-logs] scummvm master -> 585ec558b6f2c73a1212b2fd485bb5dadae34531

sev- noreply at scummvm.org
Mon Mar 6 20:26:40 UTC 2023


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

Summary:
19ade1dba9 DIRECTOR: Fix pathMakeRelative search path resolution
debb6425d4 DIRECTOR: Don't search for absolute paths
6db29a5f23 DIRECTOR: XOBJ: Allow multiple SpaceMgr::m_parseText calls
0a6f33ca97 DIRECTOR: Ignore SND loop bounds if end is before start
2d22879fc9 DIRECTOR: Add debug messages for palette fading
7e1947c039 DIRECTOR: LINGO: Add guardrails to b_do()
e6b4cb56bd DIRECTOR: LINGO: Keep track of factory ScriptContexts in LingoArchive
06eba975b2 DIRECTOR: LINGO: Fix b_go resetting custom event handlers
570bbfb7f1 DIRECTOR: Add "info" command to debugger
82e891d1d3 DIRECTOR: Move palette/transition debugging to images flag
68bcf717df DIRECTOR: Fix palette change for puppet transitions
bbce11c7ed DIRECTOR: Add support for palettes in Macintosh color table format
6bd69381f0 DIRECTOR: Fix palette ID mapping for D3
6abdd4af7c DIRECTOR: Don't dither bitmaps if they have an invalid palette ID
dd43a7d2c4 SURFACESDL: Re-add check for _cursorNeedsRedraw
8eb6cd2ac0 DIRECTOR: Allow for palette changes when seeking to arbitrary frames
04d5d0f59f DIRECTOR: Use the remapPalettesWhenNeeded flag
585ec558b6 GRAPHICS: MACGUI: Move getFont() messages to a higher debug level


Commit: 19ade1dba9a0d8514e77c784c7e42caedb31cf05
    https://github.com/scummvm/scummvm/commit/19ade1dba9a0d8514e77c784c7e42caedb31cf05
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Fix pathMakeRelative search path resolution

pathMakeRelative will attempt to look for files in locations listed in
the search path. This can include directories that don't end with a
separator. As such, ensure that paths being tested have a separator so
they don't get accidentally merged with the target filename.

Fixes the loading sequence in The Dark Eye.

Changed paths:
    engines/director/util.cpp


diff --git a/engines/director/util.cpp b/engines/director/util.cpp
index 630443024a9..f3a50e6261f 100644
--- a/engines/director/util.cpp
+++ b/engines/director/util.cpp
@@ -508,6 +508,11 @@ Common::String pathMakeRelative(Common::String path, bool recursive, bool addext
 	if (searchPath.type == ARRAY && searchPath.u.farr->arr.size() > 0) {
 		for (uint i = 0; i < searchPath.u.farr->arr.size(); i++) {
 			Common::String searchIn = searchPath.u.farr->arr[i].asString();
+			// Ensure there's a trailing directory separator
+			Common::String separator = Common::String::format("%c", g_director->_dirSeparator);
+			if (!searchIn.hasSuffix(separator)) {
+				searchIn += separator;
+			}
 			debugN(9, "%s", recIndent());
 			debug(9, "pathMakeRelative(): searchPath: %s", searchIn.c_str());
 


Commit: debb6425d4c97524a65cad3ad44ede5de05ba1d1
    https://github.com/scummvm/scummvm/commit/debb6425d4c97524a65cad3ad44ede5de05ba1d1
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Don't search for absolute paths

Previously, pathMakeRelative didn't make a distinction between relative
and absolute paths. The input would always be converted to a relative
path, then checked against a number of places (e.g. the current
working directory, all the locations in the search path...).

This causes an issue for functions such as getNthFileNameInFolder. Quite
often, this is used for absolute paths constructed with "the pathName"
as a base. ScummVM assumes the game root is also the root of the volume
(e.g. "C:\"). As such, when you would call getNthFileNameInFolder("C:\",
1), this would be translated to a relative path of "", and then match
with the current directory provided from getCurrentPath; clearly not the
same thing.

To fix this, we detect if the input to pathMakeRelative is an absolute path,
and if so avoid checking every location in the search path and prefixing
the result with getCurrentPath().

Fixes "I am unable to save or retrieve games" error message in The Dark Eye.

Changed paths:
    engines/director/util.cpp
    engines/director/util.h


diff --git a/engines/director/util.cpp b/engines/director/util.cpp
index f3a50e6261f..209d78787a7 100644
--- a/engines/director/util.cpp
+++ b/engines/director/util.cpp
@@ -358,6 +358,19 @@ const char *recIndent() {
 	return tabs[recLevel];
 }
 
+bool isAbsolutePath(Common::String &path) {
+	// Starts with Mac directory notation for the game root
+	if (path.hasPrefix("@:"))
+		return true;
+	// Starts with a Windows drive letter
+	if (path.size() >= 3
+			&& Common::isAlpha(path[0])
+			&& path[1] == ':'
+			&& path[2] == '\\')
+		return true;
+	return false;
+}
+
 Common::String convertPath(Common::String &path) {
 	if (path.empty())
 		return path;
@@ -500,10 +513,16 @@ Common::String pathMakeRelative(Common::String path, bool recursive, bool addext
 
 	debugN(8, "%s", recIndent());
 	debug(8, "pathMakeRelative(\"%s\", recursive: %d, addexts: %d, directory: %d):", path.c_str(), recursive, addexts, directory);
+	bool isAbsolute = isAbsolutePath(path);
 	path = convertPath(path);
 	debugN(9, "%s", recIndent());
 	debug(9, "pathMakeRelative(): converted -> %s", path.c_str());
 
+	// Absolute paths should not be matched against the global search path list
+	if (isAbsolute) {
+		return wrappedPathMakeRelative(path, recursive, addexts, directory, true);
+	}
+
 	Datum searchPath = g_director->getLingo()->_searchPath;
 	if (searchPath.type == ARRAY && searchPath.u.farr->arr.size() > 0) {
 		for (uint i = 0; i < searchPath.u.farr->arr.size(); i++) {
@@ -517,7 +536,7 @@ Common::String pathMakeRelative(Common::String path, bool recursive, bool addext
 			debug(9, "pathMakeRelative(): searchPath: %s", searchIn.c_str());
 
 			recLevel++;
-			foundPath = wrappedPathMakeRelative(searchIn + path, recursive, addexts, directory);
+			foundPath = wrappedPathMakeRelative(searchIn + path, recursive, addexts, directory, false);
 			recLevel--;
 
 			if (testPath(foundPath, directory))
@@ -533,7 +552,7 @@ Common::String pathMakeRelative(Common::String path, bool recursive, bool addext
 		debug(9, "pathMakeRelative(): extraSearchPath: %s", i->c_str());
 
 		recLevel++;
-		foundPath = wrappedPathMakeRelative(*i + path, recursive, addexts, directory);
+		foundPath = wrappedPathMakeRelative(*i + path, recursive, addexts, directory, false);
 		recLevel--;
 
 		if (testPath(foundPath, directory))
@@ -542,15 +561,14 @@ Common::String pathMakeRelative(Common::String path, bool recursive, bool addext
 		debugN(9, "%s", recIndent());
 		debug(9, "pathMakeRelative(): -- extraSearchPath not found: %s", foundPath.c_str());
 	}
-
-	return wrappedPathMakeRelative(path, recursive, addexts, directory);
+	return wrappedPathMakeRelative(path, recursive, addexts, directory, false);
 }
 
 
 // if we are finding the file path, then this func will return exactly the executable file path
 // if we are finding the directory path, then we will get the path relative to the game data dir.
 // e.g. if we have game data dir as SSwarlock, then "A:SSwarlock" -> "", "A:SSwarlock:Nav" -> "Nav"
-Common::String wrappedPathMakeRelative(Common::String path, bool recursive, bool addexts, bool directory) {
+Common::String wrappedPathMakeRelative(Common::String path, bool recursive, bool addexts, bool directory, bool absolute) {
 
 	Common::String initialPath(path);
 
@@ -563,7 +581,11 @@ Common::String wrappedPathMakeRelative(Common::String path, bool recursive, bool
 	debugN(9, "%s", recIndent());
 	debug(9, "wrappedPathMakeRelative(): s1 %s -> %s", path.c_str(), initialPath.c_str());
 
-	initialPath = Common::normalizePath(g_director->getCurrentPath() + initialPath, g_director->_dirSeparator);
+	if (absolute) {
+		initialPath = Common::normalizePath(initialPath, g_director->_dirSeparator);
+	} else {
+		initialPath = Common::normalizePath(g_director->getCurrentPath() + initialPath, g_director->_dirSeparator);
+	}
 	Common::String convPath = initialPath;
 
 	debugN(9, "%s", recIndent());
diff --git a/engines/director/util.h b/engines/director/util.h
index 87a6d01fb97..7b739756006 100644
--- a/engines/director/util.h
+++ b/engines/director/util.h
@@ -31,6 +31,8 @@ namespace Director {
 int castNumToNum(const char *str);
 char *numToCastNum(int num);
 
+bool isAbsolutePath(Common::String &path);
+
 Common::String convertPath(Common::String &path);
 
 Common::String unixToMacPath(const Common::String &path);
@@ -41,7 +43,7 @@ bool testPath(Common::String &path, bool directory = false);
 
 Common::String pathMakeRelative(Common::String path, bool recursive = true, bool addexts = true, bool directory = false);
 
-Common::String wrappedPathMakeRelative(Common::String path, bool recursive = true, bool addexts = true, bool directory = false);
+Common::String wrappedPathMakeRelative(Common::String path, bool recursive = true, bool addexts = true, bool directory = false, bool absolute = false);
 
 bool hasExtension(Common::String filename);
 


Commit: 6db29a5f237b978ab692e772f189a0b9ee857b78
    https://github.com/scummvm/scummvm/commit/6db29a5f237b978ab692e772f189a0b9ee857b78
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: XOBJ: Allow multiple SpaceMgr::m_parseText calls

SpaceMgr::m_parseText can be called multiple times, and assume the context
from the previous call exists. For example, ml.dir in The Dark Eye will
call it twice; the first time with a full hierarchy starting with a
SPACECOLLECTION, the second time with a hierarchy starting with a SPACE
and assuming _curSpaceCollection was set by the previous call.

We should be able to reuse the object's global "_cur" values for this,
as the game will override them soon after loading the model with a
SpaceMgr::m_setCurData call.

Fixes loading the scene graph data in The Dark Eye.

Changed paths:
    engines/director/lingo/xlibs/spacemgr.cpp


diff --git a/engines/director/lingo/xlibs/spacemgr.cpp b/engines/director/lingo/xlibs/spacemgr.cpp
index 8f77883cc67..1612728e2ba 100644
--- a/engines/director/lingo/xlibs/spacemgr.cpp
+++ b/engines/director/lingo/xlibs/spacemgr.cpp
@@ -225,10 +225,15 @@ void SpaceMgr::m_parseText(int nargs) {
 	SpaceMgrXObject *me = static_cast<SpaceMgrXObject *>(g_lingo->_state->me.u.obj);
 
 	Common::String result = *text.u.s;
-	Common::String curSpaceCollection;
-	Common::String curSpace;
-	Common::String curNode;
-	Common::String curView;
+	if (debugLevelSet(5)) {
+		Common::String format = result;
+		for (int i = 0; i < (int)format.size(); i++) {
+			if (format[i] == '\r')
+				format.replace(i, 1, "\n");
+		}
+		debugC(5, kDebugXObj, "SpaceMgr::m_parseText:\n%s", format.c_str());
+	}
+
 	Common::StringTokenizer instructions = Common::StringTokenizer(result, "\r");
 
 	while (!instructions.empty()) {
@@ -236,45 +241,45 @@ void SpaceMgr::m_parseText(int nargs) {
 		Common::StringTokenizer instruction = Common::StringTokenizer(instructionBody, " ");
 		Common::String type = instruction.nextToken();
 		if (type == "SPACECOLLECTION") {
-			curSpaceCollection = instruction.nextToken();
-			curSpace = "";
-			curNode = "";
-			curView = "";
-			if (!(me->_spaceCollections.contains(curSpaceCollection) && me->_checkForDups)) {
-				me->_spaceCollections[curSpaceCollection] = SpaceCollection();
+			me->_curSpaceCollection = instruction.nextToken();
+			me->_curSpace = "";
+			me->_curNode = "";
+			me->_curView = "";
+			if (!(me->_spaceCollections.contains(me->_curSpaceCollection) && me->_checkForDups)) {
+				me->_spaceCollections[me->_curSpaceCollection] = SpaceCollection();
 			}
 		} else if (type == "SPACE") {
-			curSpace = instruction.nextToken();
-			curNode = "";
-			curView = "";
-			SpaceCollection &sc = me->_spaceCollections.getVal(curSpaceCollection);
-			if (!(sc.spaces.contains(curSpaceCollection) && me->_checkForDups)) {
-				sc.spaces[curSpace] = Space();
+			me->_curSpace = instruction.nextToken();
+			me->_curNode = "";
+			me->_curView = "";
+			SpaceCollection &sc = me->_spaceCollections.getVal(me->_curSpaceCollection);
+			if (!(sc.spaces.contains(me->_curSpaceCollection) && me->_checkForDups)) {
+				sc.spaces[me->_curSpace] = Space();
 			}
 		} else if (type == "NODE") {
-			curNode = instruction.nextToken();
-			curView = "";
-			SpaceCollection &sc = me->_spaceCollections.getVal(curSpaceCollection);
-			Space &s = sc.spaces.getVal(curSpace);
-			if (!(s.nodes.contains(curNode) && me->_checkForDups)) {
-				s.nodes[curNode] = Node();
+			me->_curNode = instruction.nextToken();
+			me->_curView = "";
+			SpaceCollection &sc = me->_spaceCollections.getVal(me->_curSpaceCollection);
+			Space &s = sc.spaces.getVal(me->_curSpace);
+			if (!(s.nodes.contains(me->_curNode) && me->_checkForDups)) {
+				s.nodes[me->_curNode] = Node();
 			}
 		} else if (type == "VIEW") {
-			curView = instruction.nextToken();
-			SpaceCollection &sc = me->_spaceCollections.getVal(curSpaceCollection);
-			Space &s = sc.spaces.getVal(curSpace);
-			Node &n = s.nodes.getVal(curNode);
-			if (!(n.views.contains(curView) && me->_checkForDups)) {
-				n.views[curView] = View();
-				n.views[curView].payload = instruction.nextToken();
+			me->_curView = instruction.nextToken();
+			SpaceCollection &sc = me->_spaceCollections.getVal(me->_curSpaceCollection);
+			Space &s = sc.spaces.getVal(me->_curSpace);
+			Node &n = s.nodes.getVal(me->_curNode);
+			if (!(n.views.contains(me->_curView) && me->_checkForDups)) {
+				n.views[me->_curView] = View();
+				n.views[me->_curView].payload = instruction.nextToken();
 			}
 		} else if (type == "LLINK") {
 			Common::String target = instruction.nextToken();
 			Common::String payload = instruction.nextToken();
-			SpaceCollection &sc = me->_spaceCollections.getVal(curSpaceCollection);
-			Space &s = sc.spaces.getVal(curSpace);
-			Node &n = s.nodes.getVal(curNode);
-			View &v = n.views.getVal(curView);
+			SpaceCollection &sc = me->_spaceCollections.getVal(me->_curSpaceCollection);
+			Space &s = sc.spaces.getVal(me->_curSpace);
+			Node &n = s.nodes.getVal(me->_curNode);
+			View &v = n.views.getVal(me->_curView);
 			if (!(v.llinks.contains(target) && me->_checkForDups)) {
 				v.llinks[target] = LLink();
 				v.llinks[target].payload = payload;
@@ -284,15 +289,6 @@ void SpaceMgr::m_parseText(int nargs) {
 		}
 	}
 
-	if (debugLevelSet(5)) {
-		Common::String format = result;
-		for (int i = 0; i < (int)format.size(); i++) {
-			if (format[i] == '\r')
-				format.replace(i, 1, "\n");
-		}
-		debugC(5, kDebugXObj, "SpaceMgr::m_parseText: %s", format.c_str());
-	}
-
 	g_lingo->push(Datum(0));
 }
 


Commit: 0a6f33ca9701b30b5ede436b1de6f25eca04fdb3
    https://github.com/scummvm/scummvm/commit/0a6f33ca9701b30b5ede436b1de6f25eca04fdb3
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Ignore SND loop bounds if end is before start

Fixes visiting Mount Olympus in Wrath of the Gods.

Changed paths:
    engines/director/sound.cpp


diff --git a/engines/director/sound.cpp b/engines/director/sound.cpp
index 4c40fd98331..9865e22ea27 100644
--- a/engines/director/sound.cpp
+++ b/engines/director/sound.cpp
@@ -778,8 +778,14 @@ Audio::AudioStream *SNDDecoder::getAudioStream(bool looping, bool forPuppet, Dis
 
 	if (looping) {
 		if (hasLoopBounds()) {
-			// Return an automatically looping stream.
-			return new Audio::SubLoopingAudioStream(stream, 0, Audio::Timestamp(0, _loopStart, _rate), Audio::Timestamp(0, _loopEnd, _rate));
+			// FIXME: determine the correct behaviour for non-consecutive loop bounds
+			if (_loopEnd < _loopStart) {
+				warning("SNDDecoder::getAudioStream: Looping sound has non-consecutive bounds, using entire sample");
+				return new Audio::LoopingAudioStream(stream, 0);
+			} else {
+				// Return an automatically looping stream.
+				return new Audio::SubLoopingAudioStream(stream, 0, Audio::Timestamp(0, _loopStart, _rate), Audio::Timestamp(0, _loopEnd, _rate));
+			}
 		} else {
 			// Not sure if looping sounds can appear without loop bounds.
 			// Let's just log a warning and loop the entire sound...


Commit: 2d22879fc942657b5f6684c2b64e970ff3585d88
    https://github.com/scummvm/scummvm/commit/2d22879fc942657b5f6684c2b64e970ff3585d88
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Add debug messages for palette fading

Changed paths:
    engines/director/score.cpp


diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index b7c9df7882b..eb585b3c7a9 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -691,6 +691,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 		if (_frames[frameId]->_palette.normal) {
 			// For fade palette transitions, the whole fade happens with
 			// the previous frame's layout.
+			debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
 			for (int i = 0; i < fadeFrames; i++) {
 				lerpPalette(
 					calcPal,
@@ -703,6 +704,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 				g_director->draw();
 				// On click, stop loop and reset palette
 				if (_vm->processEvents(true)) {
+					debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
 					g_director->setPalette(resolvePaletteId(currentPalette));
 					return true;
 				}
@@ -716,9 +718,11 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 			byte *fadePal = nullptr;
 			if (_frames[frameId]->_palette.fadeToBlack) {
 				// Fade everything except color index 0 to black
+				debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to black over %d frames", fadeFrames);
 				fadePal = kBlackPalette;
 			} else if (_frames[frameId]->_palette.fadeToWhite) {
 				// Fade everything except color index 255 to white
+				debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to white over %d frames", fadeFrames);
 				fadePal = kWhitePalette;
 			} else {
 				// Shouldn't reach here
@@ -737,6 +741,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 				g_director->draw();
 				// On click, stop loop and reset palette
 				if (_vm->processEvents(true)) {
+					debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
 					g_director->setPalette(resolvePaletteId(currentPalette));
 					return true;
 				}
@@ -808,6 +813,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 
 		if (_frames[frameId]->_palette.overTime) {
 			// Do a single color step in one frame transition
+			debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): color cycle palette %d by 1 frame", currentPalette);
 			g_director->shiftPalette(firstColor, lastColor, false);
 			g_director->draw();
 		} else {
@@ -819,6 +825,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 
 			// Do a full color cycle in one frame transition
 			int steps = lastColor - firstColor + 1;
+			debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): color cycle palette %d over %d steps %d times", currentPalette, steps, _frames[frameId]->_palette.cycleCount);
 			for (int i = 0; i < _frames[frameId]->_palette.cycleCount; i++) {
 				for (int j = 0; j < steps; j++) {
 					g_director->shiftPalette(firstColor, lastColor, false);
@@ -856,6 +863,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 				// Copy the current palette into the snapshot buffer
 				memset(_paletteSnapshotBuffer, 0, 768);
 				memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
+				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, frameCount);
 			}
 
 			if (_frames[frameId]->_palette.normal) {
@@ -908,6 +916,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 		} else {
 			// Short circuit for fast renderer
 			if (debugChannelSet(-1, kDebugFast)) {
+				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): setting palette to %d", currentPalette);
 				g_director->setPalette(resolvePaletteId(currentPalette));
 				return;
 			}
@@ -940,12 +949,15 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 				for (int i = 0; i < fadeColorWait; i++) {
 					// On click, stop loop and reset palette
 					if (_vm->processEvents(true)) {
+						debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
 						g_director->setPalette(resolvePaletteId(currentPalette));
 						return;
 					}
 					g_director->delayMillis(frameDelay);
 				}
 
+				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
+
 				for (int i = 0; i < fadeFrames; i++) {
 					lerpPalette(
 						calcPal,
@@ -958,6 +970,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 					g_director->draw();
 					// On click, stop loop and reset palette
 					if (_vm->processEvents(true)) {
+						debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
 						g_director->setPalette(resolvePaletteId(currentPalette));
 						return;
 					}
@@ -1460,15 +1473,16 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
 Common::String Score::formatChannelInfo() {
 	Frame &frame = *_frames[_currentFrame];
 	Common::String result;
+	int defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
 	result += Common::String::format("TMPO:   tempo: %d, skipFrameFlag: %d, blend: %d\n",
 		frame._tempo, frame._skipFrameFlag, frame._blend);
 	if (frame._palette.paletteId) {
-		result += Common::String::format("PAL:    paletteId: %d, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d\n",
+		result += Common::String::format("PAL:    paletteId: %d, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, defaultId: %d\n",
 			frame._palette.paletteId, frame._palette.firstColor, frame._palette.lastColor, frame._palette.flags,
 			frame._palette.cycleCount, frame._palette.speed, frame._palette.frameCount,
-			frame._palette.fade, frame._palette.delay, frame._palette.style);
+			frame._palette.fade, frame._palette.delay, frame._palette.style, defaultPalette);
 	} else {
-		result += Common::String::format("PAL:    paletteId: 000\n");
+		result += Common::String::format("PAL:    paletteId: 000, defaultId: %d\n", defaultPalette);
 	}
 	result += Common::String::format("TRAN:   transType: %d, transDuration: %d, transChunkSize: %d\n",
 		frame._transType, frame._transDuration, frame._transChunkSize);


Commit: 7e1947c039aefa94a09f4cba4dd19bf831d35b8f
    https://github.com/scummvm/scummvm/commit/7e1947c039aefa94a09f4cba4dd19bf831d35b8f
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: LINGO: Add guardrails to b_do()

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 0b93d56f72e..ce81990b56a 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1344,6 +1344,13 @@ void LB::b_delay(int nargs) {
 void LB::b_do(int nargs) {
 	Common::String code = g_lingo->pop().asString();
 	ScriptContext *sc = g_lingo->_compiler->compileAnonymous(code);
+	if (!sc) {
+		warning("b_do(): compilation failed, ignoring");
+		return;
+	} else if (!sc->_eventHandlers.contains(kEventGeneric)) {
+		warning("b_do(): compiled code did not return handler, ignoring");
+		return;
+	}
 	Symbol sym = sc->_eventHandlers[kEventGeneric];
 
 	// Check if we have anything to execute


Commit: e6b4cb56bdf79c47fba7edafe6fd08f62254ba5f
    https://github.com/scummvm/scummvm/commit/e6b4cb56bdf79c47fba7edafe6fd08f62254ba5f
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: LINGO: Keep track of factory ScriptContexts in LingoArchive

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


diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index d96f02bf436..88616da98fb 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -1005,9 +1005,9 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 	for (uint32 i = 0; i < 0x4; i++) {
 		stream.readByte();
 	}
-	/* uint16 castId = */ stream.readUint16();
+	/* uint16 _assemblyId = */ stream.readUint16();
 	// The script is coupled with to a Cast via the script ID.
-	// This castId isn't always correct.
+	// This _assemblyId isn't always correct.
 
 	int16 factoryNameId = stream.readSint16();
 
@@ -1039,19 +1039,17 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 	ScriptType scriptType = kCastScript;
 	Common::String castName;
 	CastMember *member = archive->cast->getCastMemberByScriptId(scriptId);
-	int castId;
 	if (member) {
 		if (member->_type == kCastLingoScript)
 			scriptType = ((ScriptCastMember *)member)->_scriptType;
 
-		castId = member->getID();
+		_assemblyId = member->getID();
 		CastMemberInfo *info = member->getInfo();
 		if (info)
 			castName = info->name;
 	} else {
 		warning("Script %d has no associated cast member", scriptId);
 		scriptType = kNoneScript;
-		castId = -1;
 	}
 
 	_assemblyArchive = archive;
@@ -1067,12 +1065,12 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 		}
 		debugC(1, kDebugCompile, "Add V4 script %d: factory '%s'", scriptId, factoryName.c_str());
 
-		sc = _assemblyContext = new ScriptContext(factoryName, scriptType, castId);
+		sc = _assemblyContext = new ScriptContext(factoryName, scriptType, _assemblyId);
 		registerFactory(factoryName);
 	} else {
-		debugC(1, kDebugCompile, "Add V4 script %d: %s %d", scriptId, scriptType2str(scriptType), castId);
+		debugC(1, kDebugCompile, "Add V4 script %d: %s %d", scriptId, scriptType2str(scriptType), _assemblyId);
 
-		sc = _assemblyContext = new ScriptContext(!castName.empty() ? castName : Common::String::format("%d", castId), scriptType, castId);
+		sc = _assemblyContext = new ScriptContext(!castName.empty() ? castName : Common::String::format("%d", _assemblyId), scriptType, _assemblyId);
 	}
 
 	// initialise each property
@@ -1254,7 +1252,7 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 		if (scriptFlags & kScriptFlagFactoryDef) {
 			buf = dumpFactoryName(encodePathForDump(archName).c_str(), factoryName.c_str(), "lscr");
 		} else {
-			buf = dumpScriptName(encodePathForDump(archName).c_str(), scriptType, castId, "lscr");
+			buf = dumpScriptName(encodePathForDump(archName).c_str(), scriptType, _assemblyId, "lscr");
 		}
 
 		if (!out.open(buf, true)) {
@@ -1606,7 +1604,9 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 	}
 
 	free(codeStore);
+	_assemblyArchive = nullptr;
 	_assemblyContext = nullptr;
+	_assemblyId = -1;
 
 	return sc;
 }
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 43be69168a8..a092be38fec 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -95,6 +95,7 @@ LingoCompiler::LingoCompiler() {
 	_assemblyArchive = nullptr;
 	_currentAssembly = nullptr;
 	_assemblyContext = nullptr;
+	_assemblyId = -1;
 
 	_indef = false;
 	_methodVars = nullptr;
@@ -119,7 +120,8 @@ ScriptContext *LingoCompiler::compileAnonymous(const Common::U32String &code) {
 ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoArchive *archive, ScriptType type, CastMemberID id, const Common::String &scriptName, bool anonymous, uint32 preprocFlags) {
 	_assemblyArchive = archive;
 	_assemblyAST = nullptr;
-	ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, type, id.member);
+	_assemblyId = id.member;
+	ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, type, _assemblyId);
 	_currentAssembly = new ScriptData;
 
 	_methodVars = new VarTypeHash;
@@ -136,6 +138,7 @@ ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoA
 		delete _assemblyContext;
 		delete _currentAssembly;
 		delete _methodVars;
+		_assemblyId = -1;
 		return nullptr;
 	}
 
@@ -146,6 +149,7 @@ ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoA
 		delete _currentAssembly;
 		delete _methodVars;
 		delete _assemblyAST;
+		_assemblyId = -1;
 		return nullptr;
 	}
 
@@ -226,6 +230,7 @@ ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoA
 	_assemblyAST = nullptr;
 	_assemblyContext = nullptr;
 	_assemblyArchive = nullptr;
+	_assemblyId = -1;
 	return mainContext;
 }
 
@@ -375,6 +380,16 @@ void LingoCompiler::registerFactory(Common::String &name) {
 	_assemblyContext->setName(name);
 	_assemblyContext->setFactory(true);
 	g_lingo->_globalvars[name] = _assemblyContext;
+	// Add the factory to the list in the archive
+	if (_assemblyArchive) {
+		if (!_assemblyArchive->factoryContexts.contains(_assemblyId)) {
+			_assemblyArchive->factoryContexts[_assemblyId] = new Common::HashMap<Common::String, ScriptContext *>();
+		}
+		if (!_assemblyArchive->factoryContexts[_assemblyId]->contains(name)) {
+			*_assemblyContext->_refCount += 1;
+			(*_assemblyArchive->factoryContexts[_assemblyId])[name] = _assemblyContext;
+		}
+	}
 }
 
 void LingoCompiler::updateLoopJumps(uint nextTargetPos, uint exitTargetPos) {
diff --git a/engines/director/lingo/lingo-codegen.h b/engines/director/lingo/lingo-codegen.h
index f0d5e2ce98c..d70192a4f6b 100644
--- a/engines/director/lingo/lingo-codegen.h
+++ b/engines/director/lingo/lingo-codegen.h
@@ -57,6 +57,7 @@ public:
 	LingoArchive *_assemblyArchive;
 	ScriptContext *_assemblyContext;
 	Node *_assemblyAST;
+	int32 _assemblyId;
 	ScriptData *_currentAssembly;
 	bool _indef;
 	uint _linenumber;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 9af2bd5dd73..0a22e1f49ca 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -248,8 +248,11 @@ LingoArchive::~LingoArchive() {
 	// LctxContexts has a huge overlap with scriptContexts.
 	for (ScriptContextHash::iterator it = lctxContexts.begin(); it != lctxContexts.end(); ++it){
 		ScriptContext *script = it->_value;
-		if (script->getOnlyInLctxContexts())
-			delete script;
+		if (script->getOnlyInLctxContexts()) {
+			*script->_refCount -= 1;
+			if (*script->_refCount <= 0)
+				delete script;
+		}
 	}
 
 	for (int i = 0; i <= kMaxScriptType; i++) {
@@ -259,6 +262,15 @@ LingoArchive::~LingoArchive() {
 				delete it->_value;
 		}
 	}
+
+	for (auto it : factoryContexts) {
+		for (auto jt : *it._value) {
+			*jt._value->_refCount -= 1;
+			if (*jt._value->_refCount <= 0)
+				delete jt._value;
+		}
+		delete it._value;
+	}
 }
 
 ScriptContext *LingoArchive::getScriptContext(ScriptType type, uint16 id) {
@@ -303,6 +315,22 @@ Common::String LingoArchive::formatFunctionList(const char *prefix) {
 			result += (*it->_value).formatFunctionList(Common::String::format("%s    ", prefix).c_str());
 		}
 	}
+	result += Common::String::format("%sFactories:\n", prefix);
+	if (factoryContexts.empty()) {
+		result += Common::String::format("%s  [empty]\n", prefix);
+	} else {
+		for (auto it : factoryContexts) {
+			result += Common::String::format("%s  %d:\n", prefix, it._key);
+			if (it._value->empty()) {
+				result += Common::String::format("%s    [empty]\n", prefix);
+			} else {
+				for (auto jt : *it._value) {
+					result += Common::String::format("%s    %s:\n", prefix, jt._key.c_str());
+					result += jt._value->formatFunctionList(Common::String::format("%s      ", prefix).c_str());
+				}
+			}
+		}
+	}
 	return result;
 }
 
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 0f07759dc74..8f38387c791 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -224,6 +224,7 @@ struct Builtin {
 };
 
 typedef Common::HashMap<int32, ScriptContext *> ScriptContextHash;
+typedef Common::HashMap<int32, Common::HashMap<Common::String, ScriptContext *> *> FactoryContextHash;
 typedef Common::Array<Datum> StackData;
 typedef Common::HashMap<Common::String, Symbol, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SymbolHash;
 typedef Common::HashMap<Common::String, Datum, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DatumHash;
@@ -275,6 +276,7 @@ struct LingoArchive {
 	Cast *cast;
 	ScriptContextHash lctxContexts;
 	ScriptContextHash scriptContexts[kMaxScriptType + 1];
+	FactoryContextHash factoryContexts;
 	Common::Array<Common::String> names;
 	Common::HashMap<uint32, Common::String> primaryEventHandlers;
 	SymbolHash functionHandlers;


Commit: 06eba975b261faff6d7bb48e8476d111c9125970
    https://github.com/scummvm/scummvm/commit/06eba975b261faff6d7bb48e8476d111c9125970
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: LINGO: Fix b_go resetting custom event handlers

b_go() should only reset the custom event handlers when switching
movies, not just frames.

Fixes firing the bow at the dragon in Wrath of the Gods.

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


diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 12f2ddf08d2..cc6f2671ca6 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -199,15 +199,17 @@ void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
 	// freeze this script context. We'll return to it after entering the next frame.
 	g_lingo->_freezeState = true;
 
-	if (calledfromgo)
-		g_lingo->resetLingoGo();
-
 	if (movie.type != VOID) {
 		Common::String movieFilenameRaw = movie.asString();
 
 		if (!stage->setNextMovie(movieFilenameRaw))
 			return;
 
+		// If we reached here from b_go, and the movie is getting swapped out,
+		// reset all of the custom event handlers.
+		if (calledfromgo)
+			g_lingo->resetLingoGo();
+
 		if (g_lingo->_updateMovieEnabled) {
 			// Save the movie when branching to another movie.
 			LB::b_saveMovie(0);


Commit: 570bbfb7f1c7ad8d4a7de1e6139b3fa93fd8ec39
    https://github.com/scummvm/scummvm/commit/570bbfb7f1c7ad8d4a7de1e6139b3fa93fd8ec39
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Add "info" command to debugger

Changed paths:
    engines/director/archive.cpp
    engines/director/archive.h
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/debugger.cpp
    engines/director/debugger.h
    engines/director/movie.cpp
    engines/director/movie.h
    engines/director/types.h


diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index d47bbe3ea23..d7131bb12f1 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -246,6 +246,15 @@ void Archive::dumpChunk(Resource &res, Common::DumpFile &out) {
 	free(data);
 }
 
+Common::String Archive::formatArchiveInfo() {
+	Common::String result = "unknown, ";
+	if (_isBigEndian)
+		result += "big endian,";
+	else
+		result += "little endian, ";
+	return result;
+}
+
 // Mac Archive code
 
 MacArchive::MacArchive() : Archive(), _resFork(nullptr) {
@@ -353,6 +362,15 @@ Common::SeekableReadStreamEndian *MacArchive::getResource(uint32 tag, uint16 id)
 	return new Common::SeekableReadStreamEndianWrapper(stream, true, DisposeAfterUse::YES);
 }
 
+Common::String MacArchive::formatArchiveInfo() {
+	Common::String result = "Mac resource fork, ";
+	if (_isBigEndian)
+		result += "big endian";
+	else
+		result += "little endian";
+	return result;
+}
+
 // RIFF Archive code
 
 bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
@@ -472,6 +490,15 @@ Common::SeekableReadStreamEndian *RIFFArchive::getResource(uint32 tag, uint16 id
 	return new Common::SeekableReadStreamEndianWrapper(stream, true, DisposeAfterUse::YES);
 }
 
+Common::String RIFFArchive::formatArchiveInfo() {
+	Common::String result = "RIFF, ";
+	if (_isBigEndian)
+		result += "big endian";
+	else
+		result += "little endian";
+	return result;
+}
+
 // RIFX Archive code
 
 RIFXArchive::RIFXArchive() : Archive() {
@@ -979,4 +1006,15 @@ Resource RIFXArchive::getResourceDetail(uint32 tag, uint16 id) {
 	return resMap[id];
 }
 
+Common::String RIFXArchive::formatArchiveInfo() {
+	Common::String result = "RIFX, ";
+	if (_isBigEndian)
+		result += "big endian, ";
+	else
+		result += "little endian, ";
+	result += "type ";
+	result += tag2str(_rifxType);
+	return result;
+}
+
 } // End of namespace Director
diff --git a/engines/director/archive.h b/engines/director/archive.h
index 464dab1069c..18fd7c18455 100644
--- a/engines/director/archive.h
+++ b/engines/director/archive.h
@@ -76,6 +76,8 @@ public:
 	bool _isBigEndian;
 	static uint32 convertTagToUppercase(uint32 tag);
 
+	virtual Common::String formatArchiveInfo();
+
 protected:
 	void dumpChunk(Resource &res, Common::DumpFile &out);
 	Common::SeekableReadStream *_stream;
@@ -97,6 +99,7 @@ public:
 	bool openFile(const Common::String &fileName) override;
 	bool openStream(Common::SeekableReadStream *stream, uint32 startOffset = 0) override;
 	Common::SeekableReadStreamEndian *getResource(uint32 tag, uint16 id) override;
+	Common::String formatArchiveInfo() override;
 
 private:
 	Common::MacResManager *_resFork;
@@ -111,6 +114,7 @@ public:
 
 	bool openStream(Common::SeekableReadStream *stream, uint32 startOffset = 0) override;
 	Common::SeekableReadStreamEndian *getResource(uint32 tag, uint16 id) override;
+	Common::String formatArchiveInfo() override;
 
 	uint32 _startOffset;
 };
@@ -126,6 +130,7 @@ public:
 	Common::SeekableReadStreamEndian *getResource(uint32 tag, uint16 id) override;
 	virtual Common::SeekableReadStreamEndian *getResource(uint32 tag, uint16 id, bool fileEndianness);
 	Resource getResourceDetail(uint32 tag, uint16 id) override;
+	Common::String formatArchiveInfo() override;
 
 private:
 	bool readMemoryMap(Common::SeekableReadStreamEndian &stream, uint32 moreOffset, Common::SeekableMemoryWriteStream *dumpStream, uint32 movieStartOffset);
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index d002aad2dab..cc437436308 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -62,6 +62,8 @@ Cast::Cast(Movie *movie, uint16 castLibID, bool isShared) {
 	_version = 0;
 	_platform = Common::kPlatformMacintosh;
 
+	_isProtected = false;
+
 	_stageColor = 0;
 
 	_loadedStxts = nullptr;
@@ -357,6 +359,7 @@ bool Cast::loadConfig() {
 		_platform = platformFromID(platform);
 
 		int16 protection = stream->readSint16();
+		_isProtected = (protection % 23) == 0;
 		/* int32 field29 = */ stream->readSint32();
 		uint32 checksum = stream->readUint32();
 
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 2829e5fc3bc..bd9cf3bb002 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -143,6 +143,8 @@ public:
 	FontXPlatformMap _fontXPlatformMap;
 	FontMap _fontMap;
 
+	bool _isProtected;
+
 	Common::HashMap<int, CastMember *> *_loadedCast;
 	Common::HashMap<int, const Stxt *> *_loadedStxts;
 	uint16 _castIDoffset;
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 1276e0c5701..1fa8b6552fe 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "common/language.h"
+#include "common/platform.h"
 #include "director/director.h"
 #include "director/debugger.h"
 #include "director/cast.h"
@@ -46,6 +47,7 @@ Debugger::Debugger(): GUI::Debugger() {
 	registerCmd("help", WRAP_METHOD(Debugger, cmdHelp));
 
 	registerCmd("version", WRAP_METHOD(Debugger, cmdVersion));
+	registerCmd("info", WRAP_METHOD(Debugger, cmdInfo));
 	registerCmd("movie", WRAP_METHOD(Debugger, cmdMovie));
 	registerCmd("m", WRAP_METHOD(Debugger, cmdMovie));
 	registerCmd("frame", WRAP_METHOD(Debugger, cmdFrame));
@@ -141,8 +143,8 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
 	debugPrintf("--------\n");
 	debugPrintf("Player:\n");
 	debugPrintf(" version - Shows the Director version\n");
+	debugPrintf(" info - Shows information about the current movie\n");
 	debugPrintf(" movie / m [moviePath] - Get or sets the current movie\n");
-	//debugPrintf(" movieinfo / mi - Show information for the current movie\n");
 	debugPrintf(" frame / f [frameNum] - Gets or sets the current score frame\n");
 	debugPrintf(" channels / chan [frameNum] - Shows channel information for a score frame\n");
 	debugPrintf(" cast [castNum] - Shows the cast list or castNum for the current movie\n");
@@ -205,6 +207,32 @@ bool Debugger::cmdVersion(int argc, const char **argv) {
 	return true;
 }
 
+bool Debugger::cmdInfo(int argc, const char **argv) {
+	Movie *movie = g_director->getCurrentMovie();
+	Score *score = movie->getScore();
+	Archive *archive = movie->getArchive();
+	Cast *cast = movie->getCast();
+	debugPrintf("Movie path: %s\n", archive->getPathName().c_str());
+	debugPrintf("Movie file size: %d\n", archive->getFileSize());
+	debugPrintf("Movie archive format: %s\n", archive->formatArchiveInfo().c_str());
+	debugPrintf("Movie platform: %s (%s)\n", Common::getPlatformCode(movie->_platform), Common::getPlatformDescription(movie->_platform));
+	debugPrintf("Movie format version: 0x%x\n", movie->_version);
+
+	debugPrintf("Created by: %s\n", movie->_createdBy.c_str());
+	debugPrintf("Modified by: %s\n", movie->_changedBy.c_str());
+	debugPrintf("Original directory: %s\n", movie->_origDirectory.c_str());
+	debugPrintf("Stage size: %dx%d\n", movie->_movieRect.width(), movie->_movieRect.height());
+	debugPrintf("Default palette ID: %d\n", cast->_defaultPalette);
+	debugPrintf("Default stage color: %d\n", cast->_stageColor);
+	debugPrintf("Copy protected: %d\n", cast->_isProtected);
+	debugPrintf("Remap palettes when needed flag: %d\n", movie->_remapPalettesWhenNeeded);
+	debugPrintf("Allow outdated Lingo flag: %d\n", movie->_allowOutdatedLingo);
+	debugPrintf("Frame count: %d\n", score->_frames.size());
+	debugPrintf("Cast member count: %d\n", cast->getCastSize());
+	debugPrintf("\n");
+	return true;
+}
+
 bool Debugger::cmdFrame(int argc, const char **argv) {
 	Lingo *lingo = g_director->getLingo();
 	Score *score = g_director->getCurrentMovie()->getScore();
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index 1a8153b51c7..447527cee01 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -125,6 +125,7 @@ private:
 	bool cmdHelp(int argc, const char **argv);
 
 	bool cmdVersion(int argc, const char **argv);
+	bool cmdInfo(int argc, const char **argv);
 	bool cmdMovie(int argc, const char **argv);
 	bool cmdFrame(int argc, const char **argv);
 	bool cmdChannels(int argc, const char **argv);
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 29c7e801f43..2a2e7e4450a 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -22,6 +22,7 @@
 #include "common/config-manager.h"
 #include "common/substream.h"
 
+#include "director/types.h"
 #include "engines/util.h"
 
 #include "graphics/macgui/macwindowmanager.h"
@@ -68,6 +69,7 @@ Movie::Movie(Window *window) {
 	_version = 0;
 	_platform = Common::kPlatformMacintosh;
 	_allowOutdatedLingo = false;
+	_remapPalettesWhenNeeded = false;
 
 	_movieArchive = nullptr;
 
@@ -244,6 +246,7 @@ void Movie::loadFileInfo(Common::SeekableReadStreamEndian &stream) {
 	InfoEntries fileInfo = Movie::loadInfoEntries(stream, _version);
 
 	_allowOutdatedLingo = (fileInfo.flags & kMovieFlagAllowOutdatedLingo) != 0;
+	_remapPalettesWhenNeeded = (fileInfo.flags & kMovieFlagRemapPalettesWhenNeeded) != 0;
 
 	_script = fileInfo.strings[0].readString(false);
 
@@ -255,7 +258,7 @@ void Movie::loadFileInfo(Common::SeekableReadStreamEndian &stream) {
 
 	_changedBy = fileInfo.strings[1].readString();
 	_createdBy = fileInfo.strings[2].readString();
-	_createdBy = fileInfo.strings[3].readString();
+	_origDirectory = fileInfo.strings[3].readString();
 
 	uint16 preload = 0;
 	if (fileInfo.strings[4].len) {
@@ -271,7 +274,7 @@ void Movie::loadFileInfo(Common::SeekableReadStreamEndian &stream) {
 		debug("VWFI: script: '%s'", _script.c_str());
 		debug("VWFI: changed by: '%s'", _changedBy.c_str());
 		debug("VWFI: created by: '%s'", _createdBy.c_str());
-		debug("VWFI: directory: '%s'", _createdBy.c_str());
+		debug("VWFI: original directory: '%s'", _origDirectory.c_str());
 		debug("VWFI: preload: %d (0x%x)", preload, preload);
 
 		for (uint i = 5; i < fileInfo.strings.size(); i++) {
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 77af1a8dbc1..345ba71c5cb 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -146,6 +146,10 @@ public:
 	uint32 _stageColor;
 	Cast *_sharedCast;
 	bool _allowOutdatedLingo;
+	bool _remapPalettesWhenNeeded;
+	Common::String _createdBy;
+	Common::String _changedBy;
+	Common::String _origDirectory;
 
 	bool _videoPlayback;
 
@@ -183,10 +187,7 @@ private:
 	uint32 _flags;
 
 	Common::String _macName;
-	Common::String _createdBy;
-	Common::String _changedBy;
 	Common::String _script;
-	Common::String _directory;
 
 	bool _mouseDownWasInButton;
 	Channel *_currentDraggedChannel;
diff --git a/engines/director/types.h b/engines/director/types.h
index 92475859f24..52d0319024c 100644
--- a/engines/director/types.h
+++ b/engines/director/types.h
@@ -33,6 +33,7 @@ enum {
 #define kQuirksCacheArchive "quirks"
 
 enum MovieFlag {
+	kMovieFlagRemapPalettesWhenNeeded =  (1 << 6),
 	kMovieFlagAllowOutdatedLingo	= (1 << 8)
 };
 
@@ -326,7 +327,7 @@ enum ChunkType {
 	kChunkLine
 };
 
-enum {
+enum FileVer {
 	kFileVer300 = 0x404,
 	kFileVer310 = 0x405,
 	kFileVer400 = 0x45B,


Commit: 82e891d1d31e7bcd0405a93c087dd4bbf125472e
    https://github.com/scummvm/scummvm/commit/82e891d1d31e7bcd0405a93c087dd4bbf125472e
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Move palette/transition debugging to images flag

Changed paths:
    engines/director/cast.cpp
    engines/director/castmember.cpp
    engines/director/score.cpp
    engines/director/sprite.cpp
    engines/director/transitions.cpp
    engines/director/window.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index cc437436308..0facb4ab0e5 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -767,7 +767,7 @@ void Cast::loadBitmapData(int key, BitmapCastMember *bitmapCast) {
 
 	delete pic;
 
-	debugC(4, kDebugImages, "Cast::loadBitmapData(): Bitmap: id: %d, w: %d, h: %d, flags1: %x, flags2: %x bytes: %x, bpp: %d clut: %x", imgId, w, h, bitmapCast->_flags1, bitmapCast->_flags2, bitmapCast->_bytes, bitmapCast->_bitsPerPixel, bitmapCast->_clut);
+	debugC(5, kDebugImages, "Cast::loadBitmapData(): Bitmap: id: %d, w: %d, h: %d, flags1: %x, flags2: %x bytes: %x, bpp: %d clut: %x", imgId, w, h, bitmapCast->_flags1, bitmapCast->_flags2, bitmapCast->_bytes, bitmapCast->_bitsPerPixel, bitmapCast->_clut);
 }
 
 void Cast::loadSoundData(int key, SoundCastMember *soundCast) {
diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index cfe53e28aee..40e48a753aa 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -251,6 +251,7 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 	int srcBpp = _img->getSurface()->format.bytesPerPixel;
 
 	const byte *pal = _img->getPalette();
+	bool previouslyDithered = _ditheredImg != nullptr;
 	if (_ditheredImg) {
 		_ditheredImg->free();
 		delete _ditheredImg;
@@ -332,6 +333,7 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 			}
 
 			if (_ditheredImg) {
+				debugC(4, kDebugImages, "BitmapCastMember::createWidget(): Dithering image from source palette %d to target palette %d", _clut, score->getCurrentPalette());
 				// Save the palette ID so we can check if a redraw is required
 				_ditheredTargetClut = currentPaletteId;
 
@@ -346,6 +348,8 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 						}
 					}
 				}
+			} else if (previouslyDithered) {
+				debugC(4, kDebugImages, "BitmapCastMember::createWidget(): Removed dithered image, score palette %d matches cast member", score->getCurrentPalette());
 			}
 
 		}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index eb585b3c7a9..137df76a082 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -285,6 +285,7 @@ void Score::startPlay() {
 	_lastPalette = _frames[_currentFrame]->_palette.paletteId;
 	if (!_lastPalette)
 		_lastPalette = _movie->getCast()->_defaultPalette;
+	debugC(2, kDebugImages, "Score::startPlay(): palette changed to %d", _lastPalette);
 	_vm->setPalette(resolvePaletteId(_lastPalette));
 
 	// All frames in the same movie have the same number of channels
@@ -642,13 +643,13 @@ void Score::renderSprites(uint16 frameId, RenderMode mode) {
 
 			_window->addDirtyRect(channel->getBbox());
 			if (currentSprite) {
-				debugC(2, kDebugImages,
+				debugC(5, kDebugImages,
 					"Score::renderSprites(): CH: %-3d castId: %s [ink: %d, puppet: %d, moveable: %d, visible: %d] [bbox: %d,%d,%d,%d] [type: %d fg: %d bg: %d] [script: %s]",
 					i, currentSprite->_castId.asString().c_str(), currentSprite->_ink, currentSprite->_puppet, currentSprite->_moveable, channel->_visible,
 					PRINT_RECT(channel->getBbox()), currentSprite->_spriteType, currentSprite->_foreColor, currentSprite->_backColor,
 					currentSprite->_scriptId.asString().c_str());
 			} else {
-				debugC(2, kDebugImages, "Score::renderSprites(): CH: %-3d: No sprite", i);
+				debugC(5, kDebugImages, "Score::renderSprites(): CH: %-3d: No sprite", i);
 			}
 		} else {
 			channel->setClean(nextSprite, i, true);
@@ -691,7 +692,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 		if (_frames[frameId]->_palette.normal) {
 			// For fade palette transitions, the whole fade happens with
 			// the previous frame's layout.
-			debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
+			debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
 			for (int i = 0; i < fadeFrames; i++) {
 				lerpPalette(
 					calcPal,
@@ -704,7 +705,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 				g_director->draw();
 				// On click, stop loop and reset palette
 				if (_vm->processEvents(true)) {
-					debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
+					debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
 					g_director->setPalette(resolvePaletteId(currentPalette));
 					return true;
 				}
@@ -718,11 +719,11 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 			byte *fadePal = nullptr;
 			if (_frames[frameId]->_palette.fadeToBlack) {
 				// Fade everything except color index 0 to black
-				debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to black over %d frames", fadeFrames);
+				debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to black over %d frames", fadeFrames);
 				fadePal = kBlackPalette;
 			} else if (_frames[frameId]->_palette.fadeToWhite) {
 				// Fade everything except color index 255 to white
-				debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): fading palette to white over %d frames", fadeFrames);
+				debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to white over %d frames", fadeFrames);
 				fadePal = kWhitePalette;
 			} else {
 				// Shouldn't reach here
@@ -741,7 +742,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 				g_director->draw();
 				// On click, stop loop and reset palette
 				if (_vm->processEvents(true)) {
-					debugC(kDebugLoading, 2, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
+					debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): interrupted, setting palette to %d", currentPalette);
 					g_director->setPalette(resolvePaletteId(currentPalette));
 					return true;
 				}
@@ -764,6 +765,7 @@ void Score::setLastPalette(uint16 frameId) {
 
 	bool paletteChanged = currentPalette != _lastPalette && currentPalette;
 	if (paletteChanged) {
+		debugC(2, kDebugImages, "Score::setLastPalette(): palette changed to %d", currentPalette);
 		_lastPalette = currentPalette;
 		_paletteTransitionIndex = 0;
 
@@ -813,7 +815,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 
 		if (_frames[frameId]->_palette.overTime) {
 			// Do a single color step in one frame transition
-			debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): color cycle palette %d by 1 frame", currentPalette);
+			debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %d, from colors %d to %d, by 1 frame", currentPalette, firstColor, lastColor);
 			g_director->shiftPalette(firstColor, lastColor, false);
 			g_director->draw();
 		} else {
@@ -825,7 +827,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 
 			// Do a full color cycle in one frame transition
 			int steps = lastColor - firstColor + 1;
-			debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): color cycle palette %d over %d steps %d times", currentPalette, steps, _frames[frameId]->_palette.cycleCount);
+			debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %d, from colors %d to %d, over %d steps %d times", currentPalette, firstColor, lastColor, steps, _frames[frameId]->_palette.cycleCount);
 			for (int i = 0; i < _frames[frameId]->_palette.cycleCount; i++) {
 				for (int j = 0; j < steps; j++) {
 					g_director->shiftPalette(firstColor, lastColor, false);
@@ -863,7 +865,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 				// Copy the current palette into the snapshot buffer
 				memset(_paletteSnapshotBuffer, 0, 768);
 				memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
-				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, frameCount);
+				debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, frameCount);
 			}
 
 			if (_frames[frameId]->_palette.normal) {
@@ -916,7 +918,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 		} else {
 			// Short circuit for fast renderer
 			if (debugChannelSet(-1, kDebugFast)) {
-				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): setting palette to %d", currentPalette);
+				debugC(2, kDebugImages, "Score::renderPaletteCycle(): setting palette to %d", currentPalette);
 				g_director->setPalette(resolvePaletteId(currentPalette));
 				return;
 			}
@@ -949,14 +951,14 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 				for (int i = 0; i < fadeColorWait; i++) {
 					// On click, stop loop and reset palette
 					if (_vm->processEvents(true)) {
-						debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
+						debugC(2, kDebugImages, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
 						g_director->setPalette(resolvePaletteId(currentPalette));
 						return;
 					}
 					g_director->delayMillis(frameDelay);
 				}
 
-				debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
+				debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %d over %d frames", currentPalette, fadeFrames);
 
 				for (int i = 0; i < fadeFrames; i++) {
 					lerpPalette(
@@ -970,7 +972,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
 					g_director->draw();
 					// On click, stop loop and reset palette
 					if (_vm->processEvents(true)) {
-						debugC(kDebugLoading, 2, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
+						debugC(2, kDebugImages, "Score::renderPaletteCycle(): interrupted, setting palette to %d", currentPalette);
 						g_director->setPalette(resolvePaletteId(currentPalette));
 						return;
 					}
@@ -1148,7 +1150,7 @@ Channel *Score::getChannelById(uint16 id) {
 void Score::playSoundChannel(uint16 frameId, bool puppetOnly) {
 	Frame *frame = _frames[frameId];
 
-	debugC(5, kDebugLoading, "playSoundChannel(): Sound1 %s Sound2 %s", frame->_sound1.asString().c_str(), frame->_sound2.asString().c_str());
+	debugC(5, kDebugSound, "playSoundChannel(): Sound1 %s Sound2 %s", frame->_sound1.asString().c_str(), frame->_sound2.asString().c_str());
 	DirectorSound *sound = _window->getSoundManager();
 
 	if (sound->isChannelPuppet(1)) {
@@ -1320,7 +1322,7 @@ void Score::setSpriteCasts() {
 		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
 			_frames[i]->_sprites[j]->setCast(_frames[i]->_sprites[j]->_castId);
 
-			debugC(1, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d castId: %s type: %d (%s)",
+			debugC(5, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d castId: %s type: %d (%s)",
 				i, j, _frames[i]->_sprites[j]->_castId.asString().c_str(), _frames[i]->_sprites[j]->_spriteType,
 				spriteType2str(_frames[i]->_sprites[j]->_spriteType));
 		}
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 0ca21723d68..b6e0fbb7f76 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -427,7 +427,7 @@ bool Sprite::checkSpriteType() {
 	// if it doesn't match, then we treat it as transparent
 	// this happens in warlock-mac data/stambul/c up
 	if (_spriteType == kBitmapSprite && _cast->_type != kCastBitmap) {
-		if (debugChannelSet(2, kDebugImages))
+		if (debugChannelSet(4, kDebugImages))
 			warning("Sprite::checkSpriteType: Didn't render sprite due to the sprite type mismatch with cast type");
 		return false;
 	}
@@ -497,7 +497,7 @@ void Sprite::setCast(CastMemberID memberID) {
 		}
 
 	} else {
-		if (_castId.member != 0 && debugChannelSet(kDebugImages, 2))
+		if (_castId.member != 0 && debugChannelSet(kDebugImages, 4))
 			warning("Sprite::setCast(): %s is null", memberID.asString().c_str());
 	}
 }
diff --git a/engines/director/transitions.cpp b/engines/director/transitions.cpp
index 5320aa59383..4fe43bea256 100644
--- a/engines/director/transitions.cpp
+++ b/engines/director/transitions.cpp
@@ -229,7 +229,7 @@ void Window::playTransition(uint frame, uint16 transDuration, uint8 transArea, u
 	Common::Rect rfrom, rto;
 
 	uint32 transStartTime = g_system->getMillis();
-	debugC(2, kDebugLoading, "Window::playTransition(): Playing transition %d", t.type);
+	debugC(2, kDebugImages, "Window::playTransition(): Playing transition %d", t.type);
 
 	initTransParams(t, clipRect);
 
@@ -242,22 +242,22 @@ void Window::playTransition(uint frame, uint16 transDuration, uint8 transArea, u
 			dissolvePatternsTrans(t, clipRect, &nextFrame);
 		else
 			dissolveTrans(t, clipRect, &nextFrame);
-		debugC(2, kDebugLoading, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
-		debugC(2, kDebugLoading, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
+		debugC(2, kDebugImages, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
+		debugC(2, kDebugImages, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
 		return;
 
 	case kTransAlgoChecker:
 	case kTransAlgoStrips:
 	case kTransAlgoBlinds:
 		transMultiPass(t, clipRect, &nextFrame);
-		debugC(2, kDebugLoading, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
-		debugC(2, kDebugLoading, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
+		debugC(2, kDebugImages, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
+		debugC(2, kDebugImages, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
 		return;
 
 	case kTransAlgoZoom:
 		transZoom(t, clipRect, &nextFrame);
-		debugC(2, kDebugLoading, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
-		debugC(2, kDebugLoading, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
+		debugC(2, kDebugImages, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
+		debugC(2, kDebugImages, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
 		return;
 
 	case kTransAlgoCenterOut:
@@ -581,8 +581,8 @@ void Window::playTransition(uint frame, uint16 transDuration, uint8 transArea, u
 	_contentIsDirty = true;
 	g_director->draw();
 
-	debugC(2, kDebugLoading, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
-	debugC(2, kDebugLoading, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
+	debugC(2, kDebugImages, "Window::playTransition(): type: %d, duration: %d, chunkSize: %d, steps: %d, stepDuration: %d, xpos: %d, ypos: %d, xStepSize: %d, yStepSize: %d, stripSize: %d", t.type, t.duration, t.chunkSize, t.steps, t.stepDuration, t.xpos, t.ypos, t.xStepSize, t.yStepSize, t.stripSize);
+	debugC(2, kDebugImages, "Window::playTransition(): Transition %d finished in %d ms", t.type, g_system->getMillis() - transStartTime);
 }
 
 static int getLog2(int n) {
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index aec10bee2ca..45d280f137d 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -228,7 +228,7 @@ void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Mana
 			pd.inkBlitSurface(srcRect, channel->getMask());
 		}
 	} else {
-		if (debugChannelSet(kDebugImages, 2)) {
+		if (debugChannelSet(kDebugImages, 4)) {
 			CastType castType = channel->_sprite->_cast ? channel->_sprite->_cast->_type : kCastTypeNull;
 			warning("Window::inkBlitFrom: No source surface: spriteType: %d (%s), castType: %d (%s), castId: %s",
 				channel->_sprite->_spriteType, spriteType2str(channel->_sprite->_spriteType), castType, castType2str(castType),


Commit: 68bcf717df3f05a02ec592abe7bd0fc0743429d2
    https://github.com/scummvm/scummvm/commit/68bcf717df3f05a02ec592abe7bd0fc0743429d2
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Fix palette change for puppet transitions

Fixes palette glitches when rotating the probe in the Mac version
of Majestic: Part 1.

Changed paths:
    engines/director/score.cpp


diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 137df76a082..cc26e0d6fe3 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -590,8 +590,8 @@ bool Score::renderTransition(uint16 frameId) {
 	TransParams *tp = _window->_puppetTransition;
 
 	if (tp) {
-		_window->playTransition(frameId, tp->duration, tp->area, tp->chunkSize, tp->type, 0);
-
+		setLastPalette(frameId);
+		_window->playTransition(frameId, tp->duration, tp->area, tp->chunkSize, tp->type, resolvePaletteId(currentFrame->_palette.paletteId));
 		delete _window->_puppetTransition;
 		_window->_puppetTransition = nullptr;
 		return true;


Commit: bbce11c7edb08f0e8ce76fc934a89794ecea51d3
    https://github.com/scummvm/scummvm/commit/bbce11c7edb08f0e8ce76fc934a89794ecea51d3
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Add support for palettes in Macintosh color table format

Changed paths:
    engines/director/cast.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 0facb4ab0e5..0a905bdfb2e 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -894,27 +894,53 @@ Common::String Cast::getVideoPath(int castId) {
 }
 
 PaletteV4 Cast::loadPalette(Common::SeekableReadStreamEndian &stream) {
-	uint16 steps = stream.size() / 6;
-	uint16 index = 0;
+	int size = stream.size();
+	debugC(3, kDebugLoading, "Cast::loadPalette(): %d bytes", size);
+	if (debugChannelSet(5, kDebugLoading))
+		stream.hexdump(stream.size());
+
+	bool hasHeader = size != 6 * 256;
+	int steps = 256;
+	if (hasHeader) {
+		stream.skip(6);
+		steps = stream.readUint16();
+		int maxSteps = (size - 8) / 8;
+		if (steps > maxSteps) {
+			warning("Cast::loadPalette(): header says %d steps but there's only enough data for %d, reducing", steps, maxSteps);
+			steps = maxSteps;
+		}
+	}
+	debugC(3, kDebugLoading, "Cast::loadPalette(): %d steps", steps);
+
 	byte *_palette = new byte[steps * 3];
 
-	debugC(3, kDebugLoading, "Cast::loadPalette(): %d steps, %d bytes", steps, (int)stream.size());
 
-	if (steps > 256) {
-		warning("Cast::loadPalette(): steps > 256: %d", steps);
-		steps = 256;
-	}
+	int colorIndex = 0;
 
 	for (int i = 0; i < steps; i++) {
-		_palette[index] = stream.readByte();
+		bool increment = true;
+		if (hasHeader) {
+			int index = stream.readUint16BE();
+			if (index != 0x8000) {
+				colorIndex = index;
+			}
+		}
+
+		if (colorIndex >= steps) {
+			warning("Cast::loadPalette(): attempted to set invalid color index %d, aborting", colorIndex);
+			break;
+		}
+
+		_palette[3 * colorIndex] = stream.readByte();
 		stream.readByte();
 
-		_palette[index + 1] = stream.readByte();
+		_palette[3 * colorIndex + 1] = stream.readByte();
 		stream.readByte();
 
-		_palette[index + 2] = stream.readByte();
+		_palette[3 * colorIndex + 2] = stream.readByte();
 		stream.readByte();
-		index += 3;
+		if (increment)
+			colorIndex += 1;
 	}
 
 	return PaletteV4(0, _palette, steps);


Commit: 6bd69381f0db518ce71479b5d9f44a781330f656
    https://github.com/scummvm/scummvm/commit/6bd69381f0db518ce71479b5d9f44a781330f656
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Fix palette ID mapping for D3

The CLUT in the resource fork can contain palettes unused by Director;
the key is that all of the ones used for cast members have a palette ID
of the cast ID + 1024. This is effectively what the D2 branch was
relying on, so we can clean up the logic and use it for D3 as well.

Fixes the Invictus logo in Over-Ring-Under, the colour cycling in The 7
Colors, and countless others.

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 0a905bdfb2e..f07de9428bd 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -454,11 +454,7 @@ void Cast::loadCast() {
 			debugC(2, kDebugLoading, "****** Loading Palette CLUT, #%d", clutList[i]);
 			PaletteV4 p = loadPalette(*pal);
 
-			// for D2, we are using palette cast member id to resolve palette Id, so we are using lowest 1 bit to represent cast id. see Also loadCastChildren
-			if (_version < kFileVer300)
-				g_director->addPalette(clutList[i] & 0xff, p.palette, p.length);
-			else
-				g_director->addPalette(clutList[i], p.palette, p.length);
+			g_director->addPalette(clutList[i], p.palette, p.length);
 
 			delete pal;
 		}
@@ -619,19 +615,21 @@ void Cast::loadStxtData(int key, TextCastMember *member) {
 	}
 }
 
-void Cast::loadPaletteData(PaletteCastMember *member, Common::HashMap<int, PaletteV4>::iterator &p) {
+void Cast::loadPaletteData(PaletteCastMember *member) {
 	// TODO: Verify how palettes work in >D4 versions
+	int paletteId = 0;
 	if (_version >= kFileVer400 && _version < kFileVer500 && member->_children.size() == 1) {
-		member->_palette = g_director->getPalette(member->_children[0].index);
-	} else if (_version >= kFileVer300 && _version < kFileVer400) {
-		// D3 palettes are always kept in this ascending order
-		member->_palette = g_director->getPalette((++p)->_value.id);
-	} else if (_version < kFileVer300) {
-		// for D2, we shall use the castId to get the palette
-		member->_palette = g_director->getPalette(member->getID());
+		paletteId = member->_children[0].index;
+	} else if (_version < kFileVer400) {
+		// For D3 and below, palette IDs are stored in the CLUT resource as cast ID + 1024
+		paletteId = member->getID() + 1024;
 	} else {
 		warning("Cast::loadPaletteData(): Expected 1 child for palette cast, got %d", member->_children.size());
 	}
+	if (paletteId) {
+		debugC(2, kDebugImages, "Cast::loadPaletteData(): linking palette id %d to cast member %d", paletteId, member->getID());
+		member->_palette = g_director->getPalette(paletteId);
+	}
 }
 
 void Cast::loadFilmLoopData(FilmLoopCastMember *member) {
@@ -817,8 +815,6 @@ void Cast::loadSoundData(int key, SoundCastMember *soundCast) {
 void Cast::loadCastMemberData() {
 	debugC(1, kDebugLoading, "****** Loading casts data: sprite palettes, images, filmloops, sounds and texts.");
 
-	Common::HashMap<int, PaletteV4>::iterator p = _vm->getLoadedPalettes().find(0);
-
 	int idx = 0;
 
 	for (Common::HashMap<int, CastMember *>::iterator c = _loadedCast->begin(); c != _loadedCast->end(); ++c) {
@@ -827,7 +823,7 @@ void Cast::loadCastMemberData() {
 
 		switch (c->_value->_type){
 			case kCastPalette:
-				loadPaletteData((PaletteCastMember *)c->_value, p);
+				loadPaletteData((PaletteCastMember *)c->_value);
 				break;
 			case kCastFilmLoop:
 				loadFilmLoopData((FilmLoopCastMember *)c->_value);
@@ -918,7 +914,6 @@ PaletteV4 Cast::loadPalette(Common::SeekableReadStreamEndian &stream) {
 	int colorIndex = 0;
 
 	for (int i = 0; i < steps; i++) {
-		bool increment = true;
 		if (hasHeader) {
 			int index = stream.readUint16BE();
 			if (index != 0x8000) {
@@ -939,8 +934,7 @@ PaletteV4 Cast::loadPalette(Common::SeekableReadStreamEndian &stream) {
 
 		_palette[3 * colorIndex + 2] = stream.readByte();
 		stream.readByte();
-		if (increment)
-			colorIndex += 1;
+		colorIndex += 1;
 	}
 
 	return PaletteV4(0, _palette, steps);
diff --git a/engines/director/cast.h b/engines/director/cast.h
index bd9cf3bb002..55aa3ed9987 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -95,7 +95,7 @@ public:
 
 	void loadCastMemberData();
 	void loadStxtData(int key, TextCastMember *member);
-	void loadPaletteData(PaletteCastMember *member, Common::HashMap<int, PaletteV4>::iterator &p);
+	void loadPaletteData(PaletteCastMember *member);
 	void loadFilmLoopData(FilmLoopCastMember *member);
 	void loadBitmapData(int key, BitmapCastMember *bitmapCast);
 	void loadSoundData(int key, SoundCastMember *soundCast);


Commit: 6abdd4af7cb9ce99189dc5cb9a75871b932ff397
    https://github.com/scummvm/scummvm/commit/6abdd4af7cb9ce99189dc5cb9a75871b932ff397
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Don't dither bitmaps if they have an invalid palette ID

Fixes the colors in Gahan Wilson's The Ultimate Haunted House.

Changed paths:
    engines/director/castmember.cpp


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 40e48a753aa..a6ecf8ee3c3 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -287,8 +287,10 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 				currentPalette = g_director->getPalette(currentPaletteId);
 			}
 			int castPaletteId = score->resolvePaletteId(_clut);
+			// It is possible for Director to have saved an invalid ID in _clut;
+			// if this is the case, do no dithering.
 			if (!castPaletteId)
-				castPaletteId = cast->_defaultPalette;
+				castPaletteId = currentPaletteId;
 
 			// Check if the palette is in the middle of a color fade event
 			bool isColorCycling = score->isPaletteColorCycling();


Commit: dd43a7d2c4cf1694c3bf81418b233b490ab02579
    https://github.com/scummvm/scummvm/commit/dd43a7d2c4cf1694c3bf81418b233b490ab02579
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
SURFACESDL: Re-add check for _cursorNeedsRedraw

Partially rolls back a change introduced in
2caa338dbddd9429c766a281231c8fb98701d968; Director relies on the notion
of updateScreen() being near-zero cost if there are no changes.
For example, starting director:henachoco05 went from taking a few
milliseconds to taking 11 seconds, and opening the top menu in
director:easternmind only works on 10% of the screens.

Changed paths:
    backends/graphics/surfacesdl/surfacesdl-graphics.cpp


diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index 6ae57e4f35d..3656092838f 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -1260,7 +1260,12 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
 		_needRestoreAfterOverlay = _useOldSrc;
 	}
 
-	undrawMouse();
+	// Add the area covered by the mouse cursor to the list of dirty rects if
+	// we have to redraw the mouse, or if the cursor is alpha-blended since
+	// alpha-blended cursors will happily blend into themselves if the surface
+	// under the cursor is not reset first
+	if (_cursorNeedsRedraw || _cursorFormat.aBits() > 1)
+		undrawMouse();
 
 #ifdef USE_OSD
 	updateOSD();
@@ -1301,7 +1306,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
 	}
 
 	// Only draw anything if necessary
-	if (actualDirtyRects > 0) {
+	if (actualDirtyRects > 0 || _cursorNeedsRedraw) {
 		SDL_Rect *r;
 		SDL_Rect dst;
 		uint32 bpp, srcPitch, dstPitch;


Commit: 8eb6cd2ac0b39f3836611a99ed357cfded5c5ad2
    https://github.com/scummvm/scummvm/commit/8eb6cd2ac0b39f3836611a99ed357cfded5c5ad2
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Allow for palette changes when seeking to arbitrary frames

In Director, palette IDs in the palette channel apply to all subsequent
frames. If we seek to an arbitrary frame, the correct palette
should be applied.

Fixes the introductory cutscene in Majestic: Part 1.

Changed paths:
    engines/director/frame.cpp
    engines/director/frame.h
    engines/director/score.cpp


diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 25663d5ddd9..214b5144bbf 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -38,7 +38,9 @@ Frame::Frame(Score *score, int numChannels) {
 	_transArea = 0;
 	_transChunkSize = 0;
 	_tempo = 0;
+
 	_scoreCachedTempo = 0;
+	_scoreCachedPaletteId = 0;
 
 	_numChannels = numChannels;
 
diff --git a/engines/director/frame.h b/engines/director/frame.h
index ba4901c3dd6..a5b71897d17 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -117,7 +117,9 @@ public:
 	TransitionType _transType;
 	PaletteInfo _palette;
 	uint8 _tempo;
+
 	uint8 _scoreCachedTempo;
+	int _scoreCachedPaletteId;
 
 	CastMemberID _sound1;
 	uint8 _soundType1;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index cc26e0d6fe3..e6dd62a31fc 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -591,13 +591,13 @@ bool Score::renderTransition(uint16 frameId) {
 
 	if (tp) {
 		setLastPalette(frameId);
-		_window->playTransition(frameId, tp->duration, tp->area, tp->chunkSize, tp->type, resolvePaletteId(currentFrame->_palette.paletteId));
+		_window->playTransition(frameId, tp->duration, tp->area, tp->chunkSize, tp->type, resolvePaletteId(currentFrame->_scoreCachedPaletteId));
 		delete _window->_puppetTransition;
 		_window->_puppetTransition = nullptr;
 		return true;
 	} else if (currentFrame->_transType) {
 		setLastPalette(frameId);
-		_window->playTransition(frameId, currentFrame->_transDuration, currentFrame->_transArea, currentFrame->_transChunkSize, currentFrame->_transType, resolvePaletteId(currentFrame->_palette.paletteId));
+		_window->playTransition(frameId, currentFrame->_transDuration, currentFrame->_transArea, currentFrame->_transChunkSize, currentFrame->_transType, resolvePaletteId(currentFrame->_scoreCachedPaletteId));
 		return true;
 	} else {
 		return false;
@@ -666,8 +666,7 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 	if (_puppetPalette)
 		return false;
 
-	// If the palette is defined in the frame and doesn't match
-	// the current one, set it
+	// Skip this if we don't have a palette instruction
 	int currentPalette = _frames[frameId]->_palette.paletteId;
 	if (!currentPalette || !resolvePaletteId(currentPalette))
 		return false;
@@ -675,11 +674,6 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 	if (!_frames[frameId]->_palette.colorCycling &&
 		!_frames[frameId]->_palette.overTime) {
 
-		// Copy the current palette into the snapshot buffer
-		memset(_paletteSnapshotBuffer, 0, 768);
-		memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
-		PaletteV4 *destPal = g_director->getPalette(resolvePaletteId(currentPalette));
-
 		int frameRate = CLIP<int>(_frames[frameId]->_palette.speed, 1, 30);
 
 		if (debugChannelSet(-1, kDebugFast))
@@ -689,6 +683,11 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
 		int fadeFrames = kFadeColorFrames[frameRate - 1];
 		byte calcPal[768];
 
+		// Copy the current palette into the snapshot buffer
+		memset(_paletteSnapshotBuffer, 0, 768);
+		memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
+		PaletteV4 *destPal = g_director->getPalette(resolvePaletteId(currentPalette));
+
 		if (_frames[frameId]->_palette.normal) {
 			// For fade palette transitions, the whole fade happens with
 			// the previous frame's layout.
@@ -757,20 +756,38 @@ void Score::setLastPalette(uint16 frameId) {
 	if (_puppetPalette)
 		return;
 
-	// If the palette is defined in the frame and doesn't match
-	// the current one, set it
+	bool isCachedPalette = false;
 	int currentPalette = _frames[frameId]->_palette.paletteId;
-	if (!currentPalette || !resolvePaletteId(currentPalette))
-		return;
+	// Palette specified in the frame
+	if (currentPalette) {
+		// If for whatever reason the palette index is invalid, skip
+		if (!resolvePaletteId(currentPalette))
+			return;
+	} else {
+		// Use the score cached palette ID
+		isCachedPalette = true;
+		currentPalette = _frames[frameId]->_scoreCachedPaletteId;
+		// The cached ID is created before the cast gets loaded; if it's zero,
+		// this corresponds to the movie default palette.
+		if (!currentPalette)
+			currentPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
+		// If for whatever reason this doesn't resolve, abort.
+		if (!currentPalette || !resolvePaletteId(currentPalette))
+			return;
+	}
 
+	// If the palette is defined in the frame and doesn't match
+	// the current one, set it
 	bool paletteChanged = currentPalette != _lastPalette && currentPalette;
 	if (paletteChanged) {
-		debugC(2, kDebugImages, "Score::setLastPalette(): palette changed to %d", currentPalette);
+		debugC(2, kDebugImages, "Score::setLastPalette(): palette changed to %d, from %s", currentPalette, isCachedPalette ? "cache" :"frame");
 		_lastPalette = currentPalette;
 		_paletteTransitionIndex = 0;
 
-		// For color cycling mode, if there's a new palette, switch to it immediately
-		if (_frames[frameId]->_palette.colorCycling)
+		// Switch to a new palette immediately if:
+		// - this is color cycling mode, or
+		// - the cached palette ID is different (i.e. we jumped in the score)
+		if (_frames[frameId]->_palette.colorCycling || isCachedPalette)
 			g_director->setPalette(resolvePaletteId(_lastPalette));
 	}
 
@@ -1269,6 +1286,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
 	memset(channelData, 0, kChannelDataSize);
 
 	uint8 currentTempo = 0;
+	int currentPaletteId = 0;
 
 	while (size != 0 && !stream.eos()) {
 		uint16 frameSize = stream.readUint16();
@@ -1305,6 +1323,11 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
 			if (frame->_tempo && frame->_tempo <= 120)
 				currentTempo = frame->_tempo;
 			frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : currentTempo;
+			// Precache the current palette ID, as this carries forward to frames to the right
+			// of the instruction.
+			if (frame->_palette.paletteId)
+				currentPaletteId = frame->_palette.paletteId;
+			frame->_scoreCachedPaletteId = currentPaletteId;
 
 			debugC(8, kDebugLoading, "Score::loadFrames(): Frame %d actionId: %s", _frames.size(), frame->_actionId.asString().c_str());
 
@@ -1476,15 +1499,15 @@ Common::String Score::formatChannelInfo() {
 	Frame &frame = *_frames[_currentFrame];
 	Common::String result;
 	int defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
-	result += Common::String::format("TMPO:   tempo: %d, skipFrameFlag: %d, blend: %d\n",
-		frame._tempo, frame._skipFrameFlag, frame._blend);
+	result += Common::String::format("TMPO:   tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d\n",
+		frame._tempo, frame._skipFrameFlag, frame._blend, _currentFrameRate);
 	if (frame._palette.paletteId) {
-		result += Common::String::format("PAL:    paletteId: %d, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, defaultId: %d\n",
-			frame._palette.paletteId, frame._palette.firstColor, frame._palette.lastColor, frame._palette.flags,
+		result += Common::String::format("PAL:    paletteId: %d, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, currentId: %d, defaultId: %d\n",
+			resolvePaletteId(frame._palette.paletteId), frame._palette.firstColor, frame._palette.lastColor, frame._palette.flags,
 			frame._palette.cycleCount, frame._palette.speed, frame._palette.frameCount,
-			frame._palette.fade, frame._palette.delay, frame._palette.style, defaultPalette);
+			frame._palette.fade, frame._palette.delay, frame._palette.style, resolvePaletteId(_lastPalette), defaultPalette);
 	} else {
-		result += Common::String::format("PAL:    paletteId: 000, defaultId: %d\n", defaultPalette);
+		result += Common::String::format("PAL:    paletteId: 000, currentId: %d, defaultId: %d\n", resolvePaletteId(_lastPalette), defaultPalette);
 	}
 	result += Common::String::format("TRAN:   transType: %d, transDuration: %d, transChunkSize: %d\n",
 		frame._transType, frame._transDuration, frame._transChunkSize);


Commit: 04d5d0f59f5f6d02b8c049c44bf0a0cc74e496dd
    https://github.com/scummvm/scummvm/commit/04d5d0f59f5f6d02b8c049c44bf0a0cc74e496dd
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
DIRECTOR: Use the remapPalettesWhenNeeded flag

Changed paths:
    engines/director/castmember.cpp


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index a6ecf8ee3c3..ff1b94adab8 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -320,8 +320,8 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 				break;
 			// 8bpp - if using a different palette, and we're not doing a color cycling operation, convert using nearest colour matching
 			case 8:
-				// Only redither images in Director 4 and up.
-				if (g_director->getVersion() < 400)
+				// Only redither 8-bit images if we have the flag set
+				if (!movie->_remapPalettesWhenNeeded)
 					break;
 				if (castPaletteId != currentPaletteId && !isColorCycling) {
 					const auto pals = g_director->getLoadedPalettes();


Commit: 585ec558b6f2c73a1212b2fd485bb5dadae34531
    https://github.com/scummvm/scummvm/commit/585ec558b6f2c73a1212b2fd485bb5dadae34531
Author: Scott Percival (code at moral.net.au)
Date: 2023-03-06T21:26:28+01:00

Commit Message:
GRAPHICS: MACGUI: Move getFont() messages to a higher debug level

Changed paths:
    graphics/macgui/macfontmanager.cpp


diff --git a/graphics/macgui/macfontmanager.cpp b/graphics/macgui/macfontmanager.cpp
index b1e9770dbc5..5110a796391 100644
--- a/graphics/macgui/macfontmanager.cpp
+++ b/graphics/macgui/macfontmanager.cpp
@@ -461,7 +461,7 @@ const Font *MacFontManager::getFont(MacFont *macFont) {
 	Common::String name;
 	const Font *font = 0;
 
-	debug(3, "getFont(%s), id: %d", getFontName(macFont->getId(), macFont->getSize(), macFont->getSlant(), 0).c_str(), macFont->getId());
+	debug(6, "getFont(%s), id: %d", getFontName(macFont->getId(), macFont->getSize(), macFont->getSlant(), 0).c_str(), macFont->getId());
 
 	int aliasForId = getFontAliasForId(macFont->getId());
 	if (aliasForId > -1) {




More information about the Scummvm-git-logs mailing list