[Scummvm-git-logs] scummvm master -> 4496a7603ef7a75f0bc43ba8f5892898e3213966

sev- noreply at scummvm.org
Thu Jun 26 11:15:04 UTC 2025


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

Summary:
a74081db69 DIRECTOR: XOBJ: Make FileIO always read from the data fork
4d9b0e8d0a DIRECTOR: LINGO: Move _skipFrameAdvance to Window
e89317fb94 DIRECTOR: LINGO: Improve accuracy of setting the memberNum
f88d432f7f DIRECTOR: LINGO: Fix resolveScriptEvent for mouseEnter/mouseLeave
4496a7603e DIRECTOR: Fix BITDDecoder for 16/24 bit images


Commit: a74081db69f3a88ec24f677a70b9b4ec0e85d23a
    https://github.com/scummvm/scummvm/commit/a74081db69f3a88ec24f677a70b9b4ec0e85d23a
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-26T13:14:58+02:00

Commit Message:
DIRECTOR: XOBJ: Make FileIO always read from the data fork

Fixes loading sequence in Plates are People Too.

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


diff --git a/engines/director/lingo/xlibs/fileio.cpp b/engines/director/lingo/xlibs/fileio.cpp
index 7a5ac3781e1..08a768591b1 100644
--- a/engines/director/lingo/xlibs/fileio.cpp
+++ b/engines/director/lingo/xlibs/fileio.cpp
@@ -122,6 +122,7 @@ delete object me -- deletes the open file
  */
 
 #include "common/file.h"
+#include "common/macresman.h"
 #include "common/memstream.h"
 #include "common/savefile.h"
 #include "image/pict.h"
@@ -264,13 +265,12 @@ FileIOError FileObject::open(const Common::String &origpath, const Common::Strin
 		_inStream = saves->openForLoading(filename);
 		if (!_inStream) {
 			// Maybe we're trying to read one of the game files
-			Common::File *f = new Common::File;
 			Common::Path location = findPath(origpath);
-			if (location.empty() || !f->open(location)) {
-				delete f;
+			Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(location);
+			if (!file) {
 				return saveFileError();
 			}
-			_inStream = f;
+			_inStream = file;
 		}
 	} else if (option.equalsIgnoreCase("write")) {
 		// OutSaveFile is not seekable so create a separate seekable stream
@@ -283,13 +283,12 @@ FileIOError FileObject::open(const Common::String &origpath, const Common::Strin
 	} else if (option.equalsIgnoreCase("append")) {
 		Common::SeekableReadStream *inFile = saves->openForLoading(filename);
 		if (!inFile) {
-			Common::File *f = new Common::File;
-
-			if (!f->open(Common::Path(origpath, g_director->_dirSeparator))) {
-				delete f;
+			Common::Path location = findPath(origpath);
+			Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(location);
+			if (!file) {
 				return saveFileError();
 			}
-			inFile = f;
+			inFile = file;
 		}
 		_outStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
 		byte b = inFile->readByte();


Commit: 4d9b0e8d0a7a1d6c6a0ec61e3c2379b8821f116d
    https://github.com/scummvm/scummvm/commit/4d9b0e8d0a7a1d6c6a0ec61e3c2379b8821f116d
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-26T13:14:58+02:00

Commit Message:
DIRECTOR: LINGO: Move _skipFrameAdvance to Window

It is possible for a script to use c_tell to call "go to X" inside a
child window. The switched window will be preserved, however
_skipFrameAdvance will be intercepted by the original window and miss a
call to exitFrame.

Fixes navigation in Gus Goes to the Megarific Museum.

Changed paths:
    engines/director/director.cpp
    engines/director/director.h
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/score.cpp
    engines/director/window.cpp
    engines/director/window.h


diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 2a75102d985..91d8bb11330 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -156,7 +156,6 @@ DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gam
 	}
 
 	_playbackPaused = false;
-	_skipFrameAdvance = false;
 	_centerStage = true;
 
 	_surface = nullptr;
diff --git a/engines/director/director.h b/engines/director/director.h
index ed4807f129f..4ef8f27c87e 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -266,7 +266,6 @@ public:
 	Common::HashMap<int, int> _KeyCodes;
 	int _machineType;
 	bool _playbackPaused;
-	bool _skipFrameAdvance;
 	bool _centerStage;
 	char _dirSeparator;
 	bool _fixStageSize;
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index c4452e4ea9f..018e6b7406e 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -544,7 +544,7 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
 		if (isInputEvent && !completed) {
 			debugC(5, kDebugEvents, "Lingo::processEvents: context frozen on an input event, stopping");
 			LingoState *state = g_director->getCurrentWindow()->getLastFrozenLingoState();
-			if (state) {
+			if (state && !state->callstack.empty()) {
 				_currentInputEvent = state->callstack.front()->sp;
 			}
 			break;
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 76bedbb6bd2..96b318ef69c 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -49,9 +49,9 @@ void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
 		return;
 
 	Window *stage = _vm->getCurrentWindow();
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Score *score = stage->getCurrentMovie()->getScore();
 
-	_vm->_skipFrameAdvance = true;
+	stage->_skipFrameAdvance = true;
 
 	// If there isn't already frozen Lingo (e.g. from a previous func_goto we haven't yet unfrozen),
 	// freeze this script context. We'll return to it after entering the next frame.
@@ -110,34 +110,37 @@ void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
 void Lingo::func_gotoloop() {
 	if (!_vm->getCurrentMovie())
 		return;
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotoloop(): looping frame %d", score->getCurrentFrameNum());
 
 	score->gotoLoop();
 
-	_vm->_skipFrameAdvance = true;
+	stage->_skipFrameAdvance = true;
 }
 
 void Lingo::func_gotonext() {
 	if (!_vm->getCurrentMovie())
 		return;
 
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
 	score->gotoNext();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotonext(): going to next frame %d", score->getNextFrame());
 
-	_vm->_skipFrameAdvance = true;
+	stage->_skipFrameAdvance = true;
 }
 
 void Lingo::func_gotoprevious() {
 	if (!_vm->getCurrentMovie())
 		return;
 
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
 	score->gotoPrevious();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotoprevious(): going to previous frame %d", score->getNextFrame());
 
-	_vm->_skipFrameAdvance = true;
+	stage->_skipFrameAdvance = true;
 }
 
 void Lingo::func_play(Datum &frame, Datum &movie) {
@@ -198,7 +201,8 @@ void Lingo::func_play(Datum &frame, Datum &movie) {
 }
 
 void Lingo::func_cursor(Datum cursorDatum) {
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
 	if (cursorDatum.type == ARRAY){
 		score->_defaultCursor.readFromCast(cursorDatum);
 	} else {
@@ -219,14 +223,16 @@ int Lingo::func_marker(int m) 	{
 	if (!_vm->getCurrentMovie())
 		return 0;
 
-	int labelNumber = _vm->getCurrentMovie()->getScore()->getCurrentLabelNumber();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
+	int labelNumber = score->getCurrentLabelNumber();
 	if (m != 0) {
 		if (m < 0) {
 			for (int marker = 0; marker > m; marker--)
-				labelNumber = _vm->getCurrentMovie()->getScore()->getPreviousLabelNumber(labelNumber);
+				labelNumber = score->getPreviousLabelNumber(labelNumber);
 		} else {
 			for (int marker = 0; marker < m; marker++)
-				labelNumber = _vm->getCurrentMovie()->getScore()->getNextLabelNumber(labelNumber);
+				labelNumber = score->getNextLabelNumber(labelNumber);
 		}
 	}
 
@@ -234,7 +240,8 @@ int Lingo::func_marker(int m) 	{
 }
 
 uint16 Lingo::func_label(Datum &label) {
-	Score *score = _vm->getCurrentMovie()->getScore();
+	Window *stage = _vm->getCurrentWindow();
+	Score *score = stage->getCurrentMovie()->getScore();
 
 	if (!score->_labels)
 		return 0;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 4e2287bc8aa..b4724186ac9 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -777,9 +777,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 			// TODO: How is this handled with multiple casts in D5?
 			Common::Point pos = g_director->getCurrentWindow()->getMousePos();
 			uint16 spriteId = score->getSpriteIDFromPos(pos);
-			d = score->getSpriteById(spriteId)->_castId.member;
-			if (d.u.i == 0)
-				d = -1;
+			if (spriteId) {
+				d = score->getSpriteById(spriteId)->_castId.toMultiplex();
+			} else {
+				d = 0;
+			}
 		}
 		break;
 	case kTheMouseChar:
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 19d669b198d..5df4c1a6d78 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -138,7 +138,10 @@ bool Score::processFrozenPlayScript() {
 	if (g_lingo->_playDone) {
 		g_lingo->_playDone = false;
 		if (_window->thawLingoPlayState()) {
-			Symbol currentScript = _window->getLingoState()->callstack.front()->sp;
+			Symbol currentScript;
+			LingoState *state = _window->getLingoState();
+			if (state && !state->callstack.empty())
+				currentScript = state->callstack.front()->sp;
 			g_lingo->switchStateFromWindow();
 			bool completed = g_lingo->execute();
 			if (!completed) {
@@ -166,7 +169,9 @@ bool Score::processFrozenScripts(bool recursion, int count) {
 	while (remainCount && (limit ? count > 0 : true)) {
 		_window->thawLingoState();
 		LingoState *state = _window->getLingoState();
-		Symbol currentScript = state->callstack.front()->sp;
+		Symbol currentScript;
+		if (state && !state->callstack.empty())
+			currentScript = state->callstack.front()->sp;
 		g_lingo->switchStateFromWindow();
 		bool completed = g_lingo->execute();
 		if (!completed || (recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount()) >= remainCount) {
@@ -245,7 +250,7 @@ void Score::gotoLoop() {
 		_nextFrame = _currentLabel;
 	}
 
-	_vm->_skipFrameAdvance = true;
+	_window->_skipFrameAdvance = true;
 }
 
 int Score::getCurrentLabelNumber() {
@@ -437,7 +442,7 @@ void Score::updateCurrentFrame() {
 	}
 
 	_nextFrame = 0;
-	_vm->_skipFrameAdvance = false;
+	_window->_skipFrameAdvance = false;
 
 	if (nextFrameNumberToLoad >= getFramesNum()) {
 		Window *window = _vm->getCurrentWindow();
@@ -595,7 +600,7 @@ void Score::update() {
 		// When Lingo::func_goto* is called, _nextFrame is set
 		// and _skipFrameAdvance is set to true.
 		// exitFrame is not called in this case.
-		if (!_vm->_skipFrameAdvance && !_exitFrameCalled) {
+		if (!_window->_skipFrameAdvance && !_exitFrameCalled) {
 			// Exit the current frame. This can include scopeless ScoreScripts.
 			_movie->processEvent(kEventExitFrame);
 			_exitFrameCalled = true;
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index d5ecf6a0c86..940f61ddf3b 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -61,6 +61,7 @@ Window::Window(int id, bool scrollable, bool resizable, bool editable, Graphics:
 
 	_windowType = -1;
 	_isModal = false;
+	_skipFrameAdvance = false;
 
 	updateBorderType();
 
@@ -740,6 +741,8 @@ uint32 Window::frozenLingoRecursionCount() {
 
 	for (int i = (int)_frozenLingoStates.size() - 1; i >= 0; i--) {
 		LingoState *state = _frozenLingoStates[i];
+		if (state->callstack.empty())
+			continue;
 		CFrame *frame = state->callstack.front();
 		if (frame->sp.name->equalsIgnoreCase("enterFrame") ||
 				frame->sp.name->equalsIgnoreCase("stepMovie") ||
diff --git a/engines/director/window.h b/engines/director/window.h
index cc9bf44da54..574a9362cbd 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -205,6 +205,7 @@ public:
 	MovieReference _nextMovie;
 	Common::List<MovieReference> _movieStack;
 	bool _newMovieStarted;
+	bool _skipFrameAdvance;
 
 private:
 	uint32 _stageColor;


Commit: e89317fb944399ce9955ad2264dbbc070b262414
    https://github.com/scummvm/scummvm/commit/e89317fb944399ce9955ad2264dbbc070b262414
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-26T13:14:58+02:00

Commit Message:
DIRECTOR: LINGO: Improve accuracy of setting the memberNum

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


diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index b4724186ac9..3e2d606f8f5 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -1701,9 +1701,11 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		{
 			CastMemberID castId = d.asMemberID();
 			if (field == kTheMemberNum) {
-				// Setting the cast ID as a number will preserve whatever is in castLib
-				// The member part will be demultiplexed if required, and the castLib portion ignored.
-				castId = CastMemberID(castId.member, sprite->_castId.castLib);
+				// If the number is multiplexed with a castLib 2 or higher, the castLib will be used.
+				// Otherwise the existing castLib will be preserved.
+				if (castId.castLib == 1) {
+					castId = CastMemberID(castId.member, sprite->_castId.castLib);
+				}
 			} else if (field == kTheCastLibNum) {
 				castId = CastMemberID(sprite->_castId.member, d.asInt());
 			}


Commit: f88d432f7f2ba82181eee2c8a647d4df7c33e76b
    https://github.com/scummvm/scummvm/commit/f88d432f7f2ba82181eee2c8a647d4df7c33e76b
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-26T13:14:58+02:00

Commit Message:
DIRECTOR: LINGO: Fix resolveScriptEvent for mouseEnter/mouseLeave

A match for CastScript needs to be determined using the passed sprite
ID, not the weird mouseDown cache entry.

Fixes Cracking the Conspiracy from going nuts.

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


diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 018e6b7406e..d71d8afa8db 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -269,8 +269,11 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
 			// call, but it -does- get a mouseUp call.
 			// A bit unhinged, but we have a test that proves Director does this,
 			// so we have to do it too.
+			//
+			// mouseEnter and mouseLeave events should also defer to the value of channelId.
 			CastMemberID targetCast = _currentMouseDownCastID;
-			if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown)) {
+			if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown) ||
+				(event.event == kEventMouseEnter) || (event.event == kEventMouseLeave)) {
 				if (!event.channelId)
 					return;
 				Sprite *sprite = _score->getSpriteById(event.channelId);


Commit: 4496a7603ef7a75f0bc43ba8f5892898e3213966
    https://github.com/scummvm/scummvm/commit/4496a7603ef7a75f0bc43ba8f5892898e3213966
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-26T13:14:58+02:00

Commit Message:
DIRECTOR: Fix BITDDecoder for 16/24 bit images

RLE-compressed BITD images will convert each line of a high-colour image
into multiple 8bpp planes. Presumably because the numbers are more
likely to repeat.

Fixes rendering the switches on the sewer door in Cracking the Conspiracy.

Changed paths:
    engines/director/images.cpp


diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index 11b196eb49a..804d02ed2b2 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -183,7 +183,7 @@ void BITDDecoder::loadPalette(Common::SeekableReadStream &stream) {
 bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 	int x = 0, y = 0;
 
-	Common::Array<uint> pixels;
+	Common::Array<byte> pixels;
 	// Unpacking bodges for D3 and below
 	bool skipCompression = false;
 	uint32 bytesNeed = _pitch * _surface->h;
@@ -201,10 +201,11 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 			skipCompression = stream.size() == bytesNeed;
 		}
 	}
+	skipCompression |= (stream.size() == bytesNeed);
 
 	// If the stream has exactly the required number of bits for this image,
 	// we assume it is uncompressed.
-	if (stream.size() == bytesNeed || skipCompression) {
+	if (skipCompression) {
 		debugC(6, kDebugImages, "Skipping compression");
 		for (int i = 0; i < stream.size(); i++) {
 			pixels.push_back((int)stream.readByte());
@@ -255,6 +256,11 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 	if (offset)
 		offset = _surface->w % 2;
 
+	debugC(5, kDebugImages, "BITDDecoder::loadStream: unpacked %d bytes, width: %d, height: %d, pitch: %d, bitsPerPixel: %d", pixels.size(), _surface->w, _surface->h, _pitch, _bitsPerPixel);
+	if (debugChannelSet(8, kDebugImages)) {
+		Common::hexdump(pixels.data(), (int)pixels.size());
+	}
+
 	uint32 color;
 
 	if (pixels.size() > 0) {
@@ -285,7 +291,7 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 					break;
 
 				case 16:
-					if (_version < kFileVer400) {
+					if (skipCompression) {
 						color = (pixels[((y * _surface->w) * 2) + x * 2]) << 8 |
 							(pixels[((y * _surface->w) * 2) + x * 2 + 1]);
 					} else {
@@ -299,7 +305,7 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 				case 32:
 					// if we have the issue in D3 32bpp images, then the way to fix it should be the same as 16bpp images.
 					// check the code above, there is different behaviour between in D4 and D3. Currently we are only using D4.
-					if (_version < kFileVer400) {
+					if (skipCompression) {
 						color = pixels[(((y * _surface->w * 4)) + (x * 4 + 1))] << 16 |
 							pixels[(((y * _surface->w * 4)) + (x * 4 + 2))] << 8 |
 							pixels[(((y * _surface->w * 4)) + (x * 4 + 3))];




More information about the Scummvm-git-logs mailing list