[Scummvm-git-logs] scummvm master -> 2602d052aa9e20da4532245b8ee2cf3b96334532

neuromancer noreply at scummvm.org
Wed Oct 14 18:45:47 UTC 2026


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

Summary:
2602d052aa EEM: correctly skip video sections during intro


Commit: 2602d052aa9e20da4532245b8ee2cf3b96334532
    https://github.com/scummvm/scummvm/commit/2602d052aa9e20da4532245b8ee2cf3b96334532
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-10-14T20:43:21+02:00

Commit Message:
EEM: correctly skip video sections during intro

Changed paths:
    engines/eem/eem.cpp
    engines/eem/eem.h
    engines/eem/map_ui.cpp


diff --git a/engines/eem/eem.cpp b/engines/eem/eem.cpp
index 4e51e01c937..d9fca81a890 100644
--- a/engines/eem/eem.cpp
+++ b/engines/eem/eem.cpp
@@ -700,9 +700,9 @@ Common::Error EEMEngine::run() {
 		if (!shouldQuit() && !_skipIntro) {
 			if (_audio)
 				_audio->playVoc(Common::Path("THUNDER.VOC"));
-			playAnm(Common::Path("BOLT.ANM"), 120,
-					/* holdLastFrame= */ false, /* fadeIn= */ true);
-			waitForInput(1800);
+			if (playAnm(Common::Path("BOLT.ANM"), 120,
+						/* holdLastFrame= */ false, /* fadeIn= */ true))
+				waitForInput(1800);
 			fadeCurrentPaletteToBlack();
 			if (_audio)
 				_audio->stopVoice();
@@ -718,10 +718,15 @@ Common::Error EEMEngine::run() {
 				fadeCurrentPaletteToBlack();
 			Common::String name = Common::String::format("ANIM%02d.A", i);
 			playAnm(Common::Path(name), 120,
-					/* holdLastFrame= */ false, fadeIn);
+					/* holdLastFrame= */ false, fadeIn,
+					/* setSkipIntroOnEsc= */ true, /* showLastFrameOnSkip= */ true);
 			if (!shouldQuit() && !_skipIntro && i != 20 && _audio) {
 				_audio->spoolSound((uint)(i - 1));
-				_audio->waitForSpoolDone();
+				while (_audio->isSpoolPlaying() && !shouldQuit()) {
+					if (waitIntroDelay(10))
+						break;
+				}
+				_audio->stopSpool();
 			}
 		}
 		if (_audio)
@@ -1184,13 +1189,13 @@ void EEMEngine::playFlc(const Common::Path &path, bool fadeIn,
 		initGraphics(screenWidth(), screenHeight());
 }
 
-void EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
+bool EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
 						bool holdLastFrame, bool fadeIn,
-						bool setSkipIntroOnEsc) {
+						bool setSkipIntroOnEsc, bool showLastFrameOnSkip) {
 	ANMDecoder anm;
 	if (!anm.open(path)) {
 		warning("playAnm: %s missing", path.toString().c_str());
-		return;
+		return false;
 	}
 
 	byte palette[768];
@@ -1208,6 +1213,7 @@ void EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
 	}
 
 	bool paletteApplied = false;
+	bool aborted = false;
 	while (!shouldQuit()) {
 		const byte *frame = anm.nextFrame();
 		if (!frame)
@@ -1224,7 +1230,6 @@ void EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
 		g_system->updateScreen();
 
 		const uint32 frameStart = g_system->getMillis();
-		bool aborted = false;
 		while (g_system->getMillis() - frameStart < frameDelayMs && !aborted) {
 			Common::Event event;
 			while (g_system->getEventManager()->pollEvent(event)) {
@@ -1248,12 +1253,22 @@ void EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
 			g_system->updateScreen();
 			g_system->delayMillis(5);
 		}
-		if (aborted)
+		if (aborted) {
+			if (showLastFrameOnSkip && !shouldQuit() && !_skipIntro) {
+				// Dialogue may be drawn only in the final frame. Decode all
+				// remaining deltas before starting the accompanying speech.
+				while (const byte *nextFrame = anm.nextFrame())
+					frame = nextFrame;
+				g_system->copyRectToScreen(frame, w, 0, 0, w, h);
+				g_system->updateScreen();
+			}
 			break;
+		}
 	}
 
 	if (holdLastFrame && !shouldQuit() && !_skipIntro) {
-		while (!shouldQuit()) {
+		// A skip during playback also dismisses the final-frame wait.
+		while (!aborted && !shouldQuit()) {
 			Common::Event ev;
 			bool clicked = false;
 			while (g_system->getEventManager()->pollEvent(ev)) {
@@ -1282,6 +1297,7 @@ void EEMEngine::playAnm(const Common::Path &path, uint frameDelayMs,
 		if (_music)
 			_music->stop();
 	}
+	return !aborted && !shouldQuit();
 }
 
 void EEMEngine::blitAt(const Picture &pic, int x, int y) {
@@ -1973,7 +1989,6 @@ void EEMEngine::showMacLondonTitle() {
 }
 
 void EEMEngine::runLondonStartup() {
-	const uint32 kHoldForever = 0xFFFFFFFFu;
 	CursorMan.showMouse(false);
 	_skipIntro = false;
 	debugC(1, kDebugGeneral, "EEM2 (London): opening sequence");
@@ -2031,8 +2046,6 @@ void EEMEngine::runLondonStartup() {
 		if (!shouldQuit() && !_skipIntro)
 			playAnm(Common::Path("WAVE.ANM"), 120, /* holdLastFrame= */ true,
 					/* fadeIn= */ true);
-		if (!shouldQuit() && !_skipIntro)
-			waitForInput(kHoldForever);
 	}
 	if (_music)
 		_music->stop();
diff --git a/engines/eem/eem.h b/engines/eem/eem.h
index de56274edd8..a37c8762eff 100644
--- a/engines/eem/eem.h
+++ b/engines/eem/eem.h
@@ -502,9 +502,11 @@ public:
 	/// until the user clicks or hits a key — used for the title screen.
 	/// If @p fadeIn is true the first decoded frame is copied while the
 	/// palette is black, then ramped in like `_OpenFadeIn`.
-	void playAnm(const Common::Path &path, uint frameDelayMs = 120,
+	/// If @p showLastFrameOnSkip is true, skip to the final frame for dialogue.
+	/// Return false if playback was interrupted or the file could not be opened.
+	bool playAnm(const Common::Path &path, uint frameDelayMs = 120,
 				 bool holdLastFrame = false, bool fadeIn = false,
-				 bool setSkipIntroOnEsc = true);
+				 bool setSkipIntroOnEsc = true, bool showLastFrameOnSkip = false);
 
 	/// Play a Flic (.FLC) movie, centred on the screen or an optional Mac
 	/// London PICT backdrop. Restore the game resolution after the backdrop.
diff --git a/engines/eem/map_ui.cpp b/engines/eem/map_ui.cpp
index 50cb9dfe8e8..30784c09bfd 100644
--- a/engines/eem/map_ui.cpp
+++ b/engines/eem/map_ui.cpp
@@ -848,6 +848,24 @@ void EEMEngine::doBigMap() {
 	}
 }
 
+bool skipLondonApproachVideo(const Common::Event &ev, bool mac, bool &done) {
+	if (ev.type == Common::EVENT_KEYDOWN) {
+		done = ev.kbd.keycode == Common::KEYCODE_ESCAPE ||
+			ev.kbd.keycode == Common::KEYCODE_RETURN ||
+			ev.kbd.keycode == Common::KEYCODE_KP_ENTER;
+		return true;
+	}
+	if (ev.type == Common::EVENT_LBUTTONDOWN) {
+		const Common::Rect doneRect = mac
+			? Common::Rect(kMacLondonApproachDoneLeft, kMacLondonApproachDoneTop,
+						   kMacLondonApproachDoneRight, kMacLondonApproachDoneBottom)
+			: kLondonApproachButtons[0].rect();
+		done = doneRect.contains(ev.mouse);
+		return true;
+	}
+	return false;
+}
+
 bool EEMEngine::doLondonApproach(uint16 approachId) {
 	if (!isLondon())
 		return false;
@@ -967,6 +985,7 @@ bool EEMEngine::doLondonApproach(uint16 approachId) {
 		g_system->updateScreen();
 	};
 
+	bool done = false;
 	auto playVideo = [&](uint page) {
 		if (mac) {
 			Video::FlicDecoder flic;
@@ -1012,8 +1031,7 @@ bool EEMEngine::doLondonApproach(uint16 approachId) {
 						if (ev.type == Common::EVENT_QUIT ||
 							ev.type == Common::EVENT_RETURN_TO_LAUNCHER)
 							return;
-						if (ev.type == Common::EVENT_LBUTTONDOWN ||
-							ev.type == Common::EVENT_KEYDOWN) {
+						if (skipLondonApproachVideo(ev, mac, done)) {
 							skip = true;
 							break;
 						}
@@ -1066,8 +1084,7 @@ bool EEMEngine::doLondonApproach(uint16 approachId) {
 						ev.type == Common::EVENT_RETURN_TO_LAUNCHER) {
 						return;
 					}
-					if (ev.type == Common::EVENT_LBUTTONDOWN ||
-						ev.type == Common::EVENT_KEYDOWN) {
+					if (skipLondonApproachVideo(ev, mac, done)) {
 						skip = true;
 						break;
 					}
@@ -1095,7 +1112,6 @@ bool EEMEngine::doLondonApproach(uint16 approachId) {
 		playVideo(page);
 		drawScreen(page);
 	}
-	bool done = false;
 	uint32 lastShimmer = g_system->getMillis();
 	while (!shouldQuit() && !done) {
 		Common::Event ev;




More information about the Scummvm-git-logs mailing list