[Scummvm-git-logs] scummvm master -> c9add4a24dcab419142e43db4b1c668178c9bbd1

sev- noreply at scummvm.org
Tue Jun 9 17:31:30 UTC 2026


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

Summary:
276f3f2b05 DIRECTOR: LINGO: Fix FileIO appending save file
c9add4a24d DIRECTOR: Move _playbackPaused from engine global to Window


Commit: 276f3f2b05c055eb8d520da1c703536617df902b
    https://github.com/scummvm/scummvm/commit/276f3f2b05c055eb8d520da1c703536617df902b
Author: Zachary Berry (zberry92 at gmail.com)
Date: 2026-06-09T19:31:26+02:00

Commit Message:
DIRECTOR: LINGO: Fix FileIO appending save file

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


diff --git a/engines/director/lingo/xlibs/f/fileio.cpp b/engines/director/lingo/xlibs/f/fileio.cpp
index 71f0645908c..aa612552184 100644
--- a/engines/director/lingo/xlibs/f/fileio.cpp
+++ b/engines/director/lingo/xlibs/f/fileio.cpp
@@ -291,20 +291,19 @@ FileIOError FileObject::open(const Common::String &origpath, const Common::Strin
 	} else if (option.equalsIgnoreCase("append")) {
 		Common::SeekableReadStream *inFile = saves->openForLoading(filename);
 		if (!inFile) {
+			// Create file if it doesn't exist.
 			Common::Path location = findPath(origpath);
-			Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(location);
-			if (!file) {
-				return saveFileError();
-			}
-			inFile = file;
+			inFile = Common::MacResManager::openFileOrDataFork(location);
 		}
 		_outStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
-		byte b = inFile->readByte();
-		while (!inFile->eos() && !inFile->err()) {
-			_outStream->writeByte(b);
-			b = inFile->readByte();
+		if (inFile) {
+			byte b = inFile->readByte();
+			while (!inFile->eos() && !inFile->err()) {
+				_outStream->writeByte(b);
+				b = inFile->readByte();
+			}
+			delete inFile;
 		}
-		delete inFile;
 	} else {
 		error("Unsupported FileIO option: '%s'", option.c_str());
 	}
@@ -393,13 +392,15 @@ void FileIO::m_openFile(int nargs) {
 	int mode = d1.asInt();
 	Common::String option;
 	switch (mode) {
+	case 0:
+		option = "append";
+		break;
 	case 1:
 		option = "read";
 		break;
 	case 2:
 		option = "write";
 		break;
-	case 0:
 	default:
 		warning("FIXME: Mode %d not supported, falling back to read", mode);
 		option = "read";
@@ -565,7 +566,17 @@ void FileIO::m_writeChar(int nargs) {
 		return;
 	}
 
-	me->_outStream->writeByte(d.asInt());
+	// The XObject API passes an integer ASCII code (mWriteChar, charNum),
+	// while the Xtra API passes the character itself as a string (writeChar, theChar).
+	byte ch;
+	if (d.type == STRING) {
+		Common::String s = d.asString();
+		ch = s.empty() ? 0 : (byte)s[0];
+	} else {
+		ch = (byte)d.asInt();
+	}
+
+	me->_outStream->writeByte(ch);
 	g_lingo->push(Datum(kErrorNone));
 }
 


Commit: c9add4a24dcab419142e43db4b1c668178c9bbd1
    https://github.com/scummvm/scummvm/commit/c9add4a24dcab419142e43db4b1c668178c9bbd1
Author: Zachary Berry (zberry92 at gmail.com)
Date: 2026-06-09T19:31:26+02:00

Commit Message:
DIRECTOR: Move _playbackPaused from engine global to Window

Having _playbackPaused in DirectorEngine would pause all windows
on pause(). Moving it to Window allows games to pause one window
and start another one.

This was impacting pulling up the map in Escape from Dimension Q.
The map Window would be created but never start.

Assisted-by: Claude:claude-sonnet-4-6

Changed paths:
    engines/director/director.cpp
    engines/director/director.h
    engines/director/lingo/lingo-builtins.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 bd7afa3ea54..53d167f1331 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -157,7 +157,6 @@ DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gam
 		_machineType = 9;	// Macintosh IIci
 	}
 
-	_playbackPaused = false;
 	_centerStage = true;
 
 	_surface = nullptr;
@@ -225,6 +224,7 @@ void DirectorEngine::forgetWindow(Window *window) {
 			return;
 	}
 	window->setVisible(false, true);
+	window->getSoundManager()->stopSound();
 	_windowsToForget.push_back(window);
 }
 
diff --git a/engines/director/director.h b/engines/director/director.h
index b994db9b77d..9b506c8bd43 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -267,7 +267,6 @@ public:
 	int _colorDepth;
 	Common::HashMap<int, int> _KeyCodes;
 	int _machineType;
-	bool _playbackPaused;
 	bool _centerStage;
 	char _dirSeparator;
 	bool _fixStageSize;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 510e5762ddf..8126a6843e7 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1954,7 +1954,7 @@ void LB::b_cancelIdleLoad(int nargs) {
 }
 
 void LB::b_continue(int nargs) {
-	g_director->_playbackPaused = false;
+	g_director->getCurrentWindow()->_playbackPaused = false;
 }
 
 void LB::b_dontPassEvent(int nargs) {
@@ -2087,7 +2087,7 @@ void LB::b_pass(int nargs) {
 }
 
 void LB::b_pause(int nargs) {
-	g_director->_playbackPaused = true;
+	g_director->getCurrentWindow()->_playbackPaused = true;
 }
 
 void LB::b_play(int nargs) {
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index d905703e130..563125e7346 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -40,7 +40,7 @@
 namespace Director {
 
 void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
-	_vm->_playbackPaused = false;
+	_vm->getCurrentWindow()->_playbackPaused = false;
 
 	if (!_vm->getCurrentMovie())
 		return;
@@ -120,6 +120,7 @@ void Lingo::func_gotoloop() {
 	if (!_vm->getCurrentMovie())
 		return;
 	Window *stage = _vm->getCurrentWindow();
+	stage->_playbackPaused = false;
 	Score *score = stage->getCurrentMovie()->getScore();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotoloop(): looping frame %d", score->getCurrentFrameNum());
 
@@ -133,6 +134,7 @@ void Lingo::func_gotonext() {
 		return;
 
 	Window *stage = _vm->getCurrentWindow();
+	stage->_playbackPaused = false;
 	Score *score = stage->getCurrentMovie()->getScore();
 	score->gotoNext();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotonext(): going to next frame %d", score->getNextFrame());
@@ -145,6 +147,7 @@ void Lingo::func_gotoprevious() {
 		return;
 
 	Window *stage = _vm->getCurrentWindow();
+	stage->_playbackPaused = false;
 	Score *score = stage->getCurrentMovie()->getScore();
 	score->gotoPrevious();
 	debugC(3, kDebugLingoExec, "Lingo::func_gotoprevious(): going to previous frame %d", score->getNextFrame());
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index ad14a527e28..3afd0676ebc 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -961,7 +961,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		d = g_lingo->_state->callstack[g_lingo->_state->callstack.size() - 1]->paramCount;
 		break;
 	case kThePauseState:
-		d = (int) g_director->_playbackPaused;
+		d = (int) g_director->getCurrentWindow()->_playbackPaused;
 		break;
 	case kThePerFrameHook:
 		d = _perFrameHook;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 1465d21b7e6..29dc5cd5d14 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -440,7 +440,7 @@ bool Score::isWaitingForNextFrame() {
 void Score::updateCurrentFrame() {
 	uint32 nextFrameNumberToLoad = _curFrameNumber;
 
-	if (!_vm->_playbackPaused) {
+	if (!_window->_playbackPaused) {
 		if (_nextFrame) {
 			// With the advent of demand loading frames and due to partial updates, we rebuild our channel data
 			// when jumping.
@@ -506,7 +506,7 @@ void Score::updateCurrentFrame() {
 		// Finally, update the channels and buffer any dirty rectangles.
 		// This will ignore any channel data that is overridden with the puppet flag.
 		updateSprites(kRenderModeNormal, true);
-	} else if (!_vm->_playbackPaused) {
+	} else if (!_window->_playbackPaused) {
 		// Loading the same frame; e.g. "go to frame".
 		// This is mostly a no-op, however any sprite changes for
 		// non-puppet sprites will be reverted.
@@ -626,7 +626,7 @@ void Score::update() {
 	}
 
 	// Process timeout events independently of the frame delay
-	if (_haveInteractivity && !_vm->_playbackPaused) {
+	if (_haveInteractivity && !_window->_playbackPaused) {
 		if (_vm->getMacTicks() - _movie->_lastTimeOut >= _movie->_timeOutLength) {
 			_movie->processEvent(kEventTimeout);
 			_movie->_lastTimeOut = _vm->getMacTicks();
@@ -651,7 +651,7 @@ void Score::update() {
 	}
 
 	// For previous frame
-	if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+	if (!_window->_newMovieStarted && !_window->_playbackPaused) {
 		// When Lingo::func_goto* is called, _nextFrame is set
 		// and _skipFrameAdvance is set to true.
 		// exitFrame is not called in this case.
@@ -685,7 +685,7 @@ void Score::update() {
 	}
 
 	// Kill behaviors if they are going to expire next frame
-	if (!_vm->_playbackPaused)
+	if (!_window->_playbackPaused)
 		killScriptInstances(_nextFrame ? _nextFrame : _curFrameNumber + 1);
 
 	CastMemberID oldSound1 = _currentFrame->_mainChannels.sound1;
@@ -716,7 +716,7 @@ void Score::update() {
 		// Director 4 and below will allow infinite recursion via the perFrameHook.
 		if (_version < kFileVer500) {
 			// new frame, first call the perFrameHook (if one exists)
-			if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+			if (!_window->_newMovieStarted && !_window->_playbackPaused) {
 				// Call the perFrameHook as soon as a frame switch is done.
 				// If there is a transition, the perFrameHook is called
 				// after each transition subframe instead of here.
@@ -742,7 +742,7 @@ void Score::update() {
 		// Director 5 and above actually check for recursion for the perFrameHook.
 		if (_version >= kFileVer500) {
 			// new frame, first call the perFrameHook (if one exists)
-			if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+			if (!_window->_newMovieStarted && !_window->_playbackPaused) {
 				// Call the perFrameHook as soon as a frame switch is done.
 				// If there is a transition, the perFrameHook is called
 				// after each transition subframe instead of here.
@@ -796,7 +796,7 @@ void Score::update() {
 	// then call the stepMovie hook (if one exists)
 	// D4 and above only call it if _allowOutdatedLingo is enabled.
 	count = _window->frozenLingoStateCount();
-	if (!_vm->_playbackPaused && (_version < kFileVer400 || _movie->_allowOutdatedLingo)) {
+	if (!_window->_playbackPaused && (_version < kFileVer400 || _movie->_allowOutdatedLingo)) {
 		_movie->processEvent(kEventStepMovie);
 	}
 	// If this stepMovie call is frozen, drop the next enterFrame event
@@ -811,7 +811,7 @@ void Score::update() {
 
 	// then call the enterFrame hook (if one exists)
 	count = _window->frozenLingoStateCount();
-	if (!_vm->_playbackPaused) {
+	if (!_window->_playbackPaused) {
 		_exitFrameCalled = false;
 		if (_version >= kFileVer400) {
 			_movie->processEvent(kEventEnterFrame);
@@ -832,7 +832,7 @@ void Score::update() {
 	if (!_nextFrame && _window->_nextMovie.movie.empty() && !processFrozenScripts())
 		return;
 
-	if (!_vm->_playbackPaused) {
+	if (!_window->_playbackPaused) {
 		if (_movie->_timeOutPlay)
 			_movie->_lastTimeOut = _vm->getMacTicks();
 	}
@@ -853,7 +853,7 @@ void Score::renderFrame(uint16 frameId, RenderMode mode, bool sound1Changed, boo
 		incrementFilmLoops();
 		_window->render();
 		_skipTransition = false;
-	} else if (_vm->_playbackPaused) {
+	} else if (_window->_playbackPaused) {
 		updateSprites(mode);
 		incrementFilmLoops();
 		_window->render();
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 295d262fb48..63d92adc3e2 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -71,6 +71,7 @@ Window::Window(int id, bool scrollable, bool resizable, bool editable, Graphics:
 	_isModal = false;
 	_skipFrameAdvance = false;
 	_resetScreen = false;
+	_playbackPaused = false;
 
 	// Owned by the window manager
 	_window = new Graphics::MacWindow(id, scrollable, resizable, editable, wm);
@@ -473,6 +474,10 @@ void Window::setVisible(bool visible, bool silent) {
 	if (!_currentMovie && !silent)
 		ensureMovieIsLoaded();
 
+	// If a modal window is not visible, release the locks it holds.
+	if (!visible && _isModal)
+		setModal(false);
+
 	_window->setVisible(visible);
 
 	if (visible)
diff --git a/engines/director/window.h b/engines/director/window.h
index 0139e0cb962..57a38c8c529 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -229,6 +229,7 @@ public:
 	bool _newMovieFirstDraw;
 	bool _skipFrameAdvance;
 	bool _resetScreen;
+	bool _playbackPaused;
 
 private:
 	uint32 _stageColor;




More information about the Scummvm-git-logs mailing list