[Scummvm-git-logs] scummvm master -> 36bedd9b41f28bcde89ec009407d296ce6f5af69

neuromancer noreply at scummvm.org
Sat Sep 5 11:01:14 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:
a8e95537b4 SCUMM: RA1: allow to select both paths in L8
36bedd9b41 SCUMM: RA1: make sure cutscenes fill the screen


Commit: a8e95537b47613ca620c45eb01a9e9ef5515f3bd
    https://github.com/scummvm/scummvm/commit/a8e95537b47613ca620c45eb01a9e9ef5515f3bd
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-05T12:33:52+02:00

Commit Message:
SCUMM: RA1: allow to select both paths in L8

Changed paths:
    engines/scumm/insane/rebel1/iact.cpp
    engines/scumm/insane/rebel1/render.cpp
    engines/scumm/insane/rebel1/runlevels.cpp


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index e9d38369534..1a799bbbbf7 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -694,8 +694,8 @@ void InsaneRebel1::checkDynamicLevelBranch(int32 curFrame) {
 		return;
 
 	if ((_currentLevel == 6 || _currentLevel == 7) && _pendingRouteIndex >= 0) {
-		const uint32 routeFrame = (_currentLevel == 6 && curFrame >= 0) ?
-			(uint32)curFrame : (uint32)_gameCounter;
+		const uint32 routeFrame = (curFrame >= 0) ?
+			(uint32)curFrame : (uint32)_currentSmushFrame;
 		if (!_vm->_smushVideoShouldFinish &&
 			_pendingRouteCutoverFrame >= 0 &&
 			routeFrame >= (uint32)_pendingRouteCutoverFrame) {
@@ -707,9 +707,8 @@ void InsaneRebel1::checkDynamicLevelBranch(int32 curFrame) {
 			_vm->_smushVideoShouldFinish = true;
 			const int32 resumeFrame = (_currentLevel == 6 && _pendingRouteStartFrame < 0) ?
 				0 : _pendingRouteStartFrame;
-			debugC(DEBUG_INSANE, "L%d cutover: route=%d -> %d at %s=%u (resumeFrame=%d)",
+			debugC(DEBUG_INSANE, "L%d cutover: route=%d -> %d at localFrame=%u (resumeFrame=%d)",
 				_currentLevel + 1, _levelRouteIndex, _pendingRouteIndex,
-				_currentLevel == 6 ? "localFrame" : "frame",
 				(unsigned)routeFrame, (int)resumeFrame);
 		}
 		return;
@@ -1512,7 +1511,7 @@ void InsaneRebel1::updateGameOp0BPhysics() {
 
 	bool level8WalkerPlayerHit = false;
 	if (_currentLevel == 7) {
-		const uint16 walkerFrame = (uint16)_gameCounter;
+		const uint16 walkerFrame = (uint16)_currentSmushFrame;
 		level8WalkerPlayerHit = hasLevel8WalkerPlayerHit(_levelRouteIndex, walkerFrame,
 			_perspectiveX, _perspectiveY);
 		// Player collision and boss damage are tracked separately.
diff --git a/engines/scumm/insane/rebel1/render.cpp b/engines/scumm/insane/rebel1/render.cpp
index db1f6f364f8..957d149ec53 100644
--- a/engines/scumm/insane/rebel1/render.cpp
+++ b/engines/scumm/insane/rebel1/render.cpp
@@ -1773,7 +1773,7 @@ void InsaneRebel1::renderHUD(byte *dst, int pitch, int width, int height) {
 	_hudDirtyFlag = 0xFF;
 }
 
-// Each route has up to 3 attack windows. -2 means disabled.
+// Each route has up to 3 attack windows, indexed by ANM-local frame. -2 means disabled.
 const int16 InsaneRebel1::kWalkerAttackWindow1[3] = { 2588, 2323, 877 };
 const int16 InsaneRebel1::kWalkerAttackWindow2[3] = { 1709, 1444, -2 };
 const int16 InsaneRebel1::kWalkerAttackWindow3[3] = { 262, -2, -2 };
@@ -1781,7 +1781,7 @@ const int16 InsaneRebel1::kWalkerAttackWindow3[3] = { 262, -2, -2 };
 void InsaneRebel1::updateLevel8WalkerState() {
 	if (_walkerHealth >= 11) {
 		_walkerHealth = (int16)(100 - (_killCount + (_killCount >> 2)));
-	} else if (_walkerHealth > 0 && (_gameCounter & 3) == 0) {
+	} else if (_walkerHealth > 0 && (_currentSmushFrame & 3) == 0) {
 		_walkerHealth--;
 	}
 
@@ -1791,7 +1791,7 @@ void InsaneRebel1::updateLevel8WalkerState() {
 	}
 
 	int route = CLIP(_levelRouteIndex, 0, 2);
-	uint16 fc = (uint16)_gameCounter;
+	uint16 fc = (uint16)_currentSmushFrame;
 
 	const int16 *windows[3] = {
 		&kWalkerAttackWindow1[route],
@@ -1831,7 +1831,7 @@ void InsaneRebel1::updateLevel8WalkerState() {
 				_walkerBranchChoice = (_shipPosX < 0xA0) ? 1 : 2;
 			}
 		} else {
-			if ((_gameCounter & 7) == 0)
+			if ((fc & 7) == 0)
 				playSfx(kSfxLockOn, 127, 0);
 		}
 	}
@@ -1853,12 +1853,14 @@ void InsaneRebel1::updateLevel8WalkerState() {
 				newRoute = 2;
 		}
 
-		if (newRoute != 0 && newRoute != route) {
+		if (newRoute != 0) {
 			_pendingRouteIndex = newRoute;
-			_pendingRouteCutoverFrame = _gameCounter + 7;
-			_pendingRouteStartFrame = _pendingRouteCutoverFrame;
-			debugC(DEBUG_INSANE, "L8 branch: route=%d -> %d at frame=%u shipX=%d resumeTimelineFrame=%d cutoverFrame=%d",
-				route, newRoute, (unsigned)_gameCounter, _shipPosX,
+			_pendingRouteCutoverFrame = _currentSmushFrame + 7;
+			// The destination starts at frame 1, advanced by the source tail
+			// already displayed. This also applies when repeating the same route.
+			_pendingRouteStartFrame = 1 + (_pendingRouteCutoverFrame - _currentSmushFrame);
+			debugC(DEBUG_INSANE, "L8 branch: route=%d -> %d at localFrame=%u shipX=%d resumeLocalFrame=%d cutoverFrame=%d",
+				route, newRoute, (unsigned)fc, _shipPosX,
 				(int)_pendingRouteStartFrame, (int)_pendingRouteCutoverFrame);
 		}
 		_walkerBranchChoice = 0;
@@ -1871,7 +1873,7 @@ void InsaneRebel1::renderLevel8Overlay(byte *dst, int pitch, int width, int heig
 	if (_currentLevel != 7)
 		return;
 
-	if (_walkerHealth > 0 && (_walkerHealth >= 16 || (_gameCounter & 2) != 0)) {
+	if (_walkerHealth > 0 && (_walkerHealth >= 16 || (_currentSmushFrame & 2) != 0)) {
 		int16 projX = 0x61, projY = 0x8D;
 		projectGameplayPoint(projX, projY);
 		projX = (int16)(0x61 - ((projX - 0x61) >> 2));
@@ -1889,7 +1891,7 @@ void InsaneRebel1::renderLevel8Overlay(byte *dst, int pitch, int width, int heig
 		&kWalkerAttackWindow2[route],
 		&kWalkerAttackWindow3[route]
 	};
-	int16 frameNum = (int16)(uint16)_gameCounter;
+	int16 frameNum = (int16)(uint16)_currentSmushFrame;
 
 	bool inWindow = false;
 	bool inDirectionalPhase = false;
@@ -1933,7 +1935,7 @@ void InsaneRebel1::renderLevel8Overlay(byte *dst, int pitch, int width, int heig
 				viewportX + 0xA8 - parallaxX, viewportY + 0x93 - parallaxY, "<<u");
 		}
 	} else {
-		if ((_gameCounter & 4) == 0) {
+		if ((frameNum & 4) == 0) {
 			int16 projX = 0, projY = 0;
 			projectGameplayPoint(projX, projY);
 			int16 drawX = (int16)(0xA9 - (projX >> 2));
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 86859ec13b2..14ad794e5ec 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -72,59 +72,6 @@ int32 findAnimFrameChunkOffset(ScummEngine_v7 *vm, const char *filename, int32 t
 	return result;
 }
 
-int32 findAnimFrameChunkOffsetByGameCounter(ScummEngine_v7 *vm, const char *filename, int32 targetCounter, int32 &localFrame) {
-	localFrame = 0;
-	if (targetCounter <= 0)
-		return 0;
-
-	ScummFile *file = vm->instantiateScummFile();
-	if (!vm->openFile(*file, Common::Path(filename))) {
-		delete file;
-		return -1;
-	}
-
-	int32 result = -1;
-	if (file->size() >= 8) {
-		file->readUint32BE();
-		const uint32 animSize = file->readUint32BE();
-		const int64 animEnd = MIN<int64>((int64)file->pos() + animSize, file->size());
-
-		int32 frameIndex = 0;
-		RA1AnimStreamChunkIterator chunks(*file, animEnd);
-		RA1AnimChunk chunk;
-		while (chunks.next(chunk)) {
-			if (chunk.tag == MKTAG('F', 'R', 'M', 'E')) {
-				RA1AnimStreamChunkIterator subChunks(*file, chunk.endOffset);
-				RA1AnimChunk subChunk;
-				while (subChunks.next(subChunk)) {
-					if (subChunk.tag == MKTAG('G', 'A', 'M', 'E') && subChunk.size >= 8) {
-						const uint32 opcode = file->readUint32BE();
-						const int32 counter = (int32)file->readUint32BE();
-						if (opcode == 0x0B && counter >= targetCounter) {
-							localFrame = frameIndex;
-							result = (int32)chunk.offset;
-							break;
-						}
-					}
-
-					subChunks.skip(subChunk);
-				}
-
-				if (result >= 0)
-					break;
-
-				frameIndex++;
-			}
-
-			chunks.skip(chunk);
-		}
-	}
-
-	file->close();
-	delete file;
-	return result;
-}
-
 void InsaneRebel1::formatTargetAccuracy(char *dst, size_t dstSize, int kills, int targetCount, bool perfectText) const {
 	if (perfectText && kills >= targetCount)
 		Common::sprintf_s(dst, dstSize, "%s", uiStr(kR1StrAccuracyPerfect));
@@ -816,7 +763,7 @@ bool InsaneRebel1::runLevel8() {
 			if (_walkerHealth <= 0)
 				break;
 
-			if (_pendingRouteIndex >= 0 && _pendingRouteIndex != route) {
+			if (_pendingRouteIndex >= 0) {
 				// Branch to the next walker route while preserving active state.
 				routeStartFrame = _pendingRouteStartFrame;
 				route = _pendingRouteIndex;
@@ -1597,21 +1544,18 @@ void InsaneRebel1::resolveSeek(const char *filename, int32 startFrame, int32 &vi
 				(int)videoStartFrame, (unsigned)videoOffset);
 		}
 	} else if (_currentLevel == 7 && resumingRoute) {
-		videoOffset = findAnimFrameChunkOffsetByGameCounter(_vm, filename, startFrame, videoStartFrame);
-		if (videoOffset < 0) {
-			debugC(DEBUG_INSANE, "L8 resume: route=%d timelineFrame=%d GAME counter lookup failed",
-				_levelRouteIndex, (int)startFrame);
-			videoStartFrame = startFrame;
-			videoOffset = findAnimFrameChunkOffset(_vm, filename, videoStartFrame);
-		}
+		// Walker routes restart at their own local frame, even when branching
+		// back to the same ANM. Their embedded GAME counters are not seek targets.
+		videoStartFrame = startFrame;
+		videoOffset = findAnimFrameChunkOffset(_vm, filename, videoStartFrame);
 		if (videoOffset < 0) {
-			debugC(DEBUG_INSANE, "L8 resume: route=%d timelineFrame=%d localFrame=%d offset lookup failed",
-				_levelRouteIndex, (int)startFrame, (int)videoStartFrame);
+			debugC(DEBUG_INSANE, "L8 resume: route=%d localFrame=%d offset lookup failed",
+				_levelRouteIndex, (int)videoStartFrame);
 			videoStartFrame = 0;
 			videoOffset = 0;
 		} else {
-			debugC(DEBUG_INSANE, "L8 resume: route=%d timelineFrame=%d -> localFrame=%d offset=0x%x",
-				_levelRouteIndex, (int)startFrame, (int)videoStartFrame, (unsigned)videoOffset);
+			debugC(DEBUG_INSANE, "L8 resume: route=%d localFrame=%d offset=0x%x",
+				_levelRouteIndex, (int)videoStartFrame, (unsigned)videoOffset);
 		}
 	} else if (_currentLevel == 13 && resumingRoute) {
 		// L14PLY2B is already the continuation clip. Preserve state, but do not seek.
@@ -1622,8 +1566,9 @@ void InsaneRebel1::resolveSeek(const char *filename, int32 startFrame, int32 &vi
 
 void InsaneRebel1::captureInteractiveVideoInput() {
 	const bool level7RouteSplice = (_currentLevel == 6 && _levelRouteIndex > 0);
-	const bool walkerRouteReplay = (_currentLevel == 7 && _walkerRoundReplay);
-	const bool preserveInputState = _preserveInteractiveRuntimeState || level7RouteSplice || walkerRouteReplay;
+	const bool walkerRouteContinuation = (_currentLevel == 7 &&
+		(_walkerRoundReplay || _pendingRouteStartFrame > 0));
+	const bool preserveInputState = _preserveInteractiveRuntimeState || level7RouteSplice || walkerRouteContinuation;
 
 	enableIOSGamepadController();
 


Commit: 36bedd9b41f28bcde89ec009407d296ce6f5af69
    https://github.com/scummvm/scummvm/commit/36bedd9b41f28bcde89ec009407d296ce6f5af69
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-05T13:00:59+02:00

Commit Message:
SCUMM: RA1: make sure cutscenes fill the screen

Changed paths:
    engines/scumm/smush/rebel/smush_player_ra1.cpp
    engines/scumm/smush/rebel/smush_player_ra1.h


diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index b2dae0b0a61..d5d7890ac6d 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -1113,8 +1113,7 @@ void SmushPlayerRebel1::handleGameUpdateScreen(const byte *src, int srcPitch, in
 		height = MIN(height, _ra1FadeFrameHeight);
 	}
 
-	if (!_insane || !static_cast<InsaneRebel1 *>(_insane)->isInteractiveVideoActive() ||
-			_vm->_screenWidth != kRA1PresentationScreenWidth ||
+	if (_vm->_screenWidth != kRA1PresentationScreenWidth ||
 			_vm->_screenHeight != kRA1PresentationScreenHeight) {
 		SmushPlayer::handleGameUpdateScreen(src, srcPitch, width, height);
 		ra1RememberDisplayedFrame(_ra1FadeFrame, _ra1FadeFrameSize,
@@ -1124,15 +1123,17 @@ void SmushPlayerRebel1::handleGameUpdateScreen(const byte *src, int srcPitch, in
 		return;
 	}
 
-	int ra1ViewX = _ra1ViewportOffsetX;
-	int ra1ViewY = _ra1ViewportOffsetY;
+	const bool interactive = _insane && static_cast<InsaneRebel1 *>(_insane)->isInteractiveVideoActive();
+	const int ra1ViewX = interactive ? _ra1ViewportOffsetX : 0;
+	const int ra1ViewY = interactive ? _ra1ViewportOffsetY : 0;
 
 	const byte *sourceBase = useFadeFrame ? src : _dst;
 	const int sourcePitch = useFadeFrame ? srcPitch : _width;
 	const int sourceWidth = useFadeFrame ? width : _width;
 	const int sourceHeight = useFadeFrame ? height : _height;
-	const int srcX = useFadeFrame ? 0 : CLIP(_scrollX + ra1ViewX + kRA1PresentationBorder, 0, sourceWidth - 1);
-	const int srcY = useFadeFrame ? 0 : CLIP(_scrollY + ra1ViewY + kRA1PresentationBorder, 0, sourceHeight - 1);
+	// Retained FADE frames already use screen coordinates, including the border.
+	const int srcX = CLIP((useFadeFrame ? 0 : _scrollX + ra1ViewX) + kRA1PresentationBorder, 0, sourceWidth - 1);
+	const int srcY = CLIP((useFadeFrame ? 0 : _scrollY + ra1ViewY) + kRA1PresentationBorder, 0, sourceHeight - 1);
 
 	int frameWidth = MIN<int>(sourceWidth - srcX, kRA1PresentationWidth);
 	int frameHeight = MIN<int>(sourceHeight - srcY, kRA1PresentationHeight);
@@ -1149,7 +1150,8 @@ void SmushPlayerRebel1::handleGameUpdateScreen(const byte *src, int srcPitch, in
 	}
 	memset(_ra1PresentationBuffer, 0, presentationSize);
 
-	// Interactive gameplay draws a 312x192 viewport inside a black 320x200 frame.
+	// RA1 presents a 312x192 viewport inside a black 320x200 frame, including
+	// cinematics. The four-pixel inset keeps scenery outside cockpit overlays hidden.
 	const byte *dst = sourceBase + srcY * sourcePitch + srcX;
 	byte *presentationDst = _ra1PresentationBuffer +
 		kRA1PresentationBorder * kRA1PresentationScreenWidth + kRA1PresentationBorder;
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.h b/engines/scumm/smush/rebel/smush_player_ra1.h
index fbcdfc05650..19c57ffb130 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.h
+++ b/engines/scumm/smush/rebel/smush_player_ra1.h
@@ -85,7 +85,7 @@ private:
 	int32 _ra1CleanFrameSize;
 	bool _ra1HasCleanFrame;
 
-	// Interactive movies present a 312x192 viewport inside a black frame.
+	// Movies present a 312x192 viewport inside a black frame.
 	byte *_ra1PresentationBuffer;
 	int32 _ra1PresentationBufferSize;
 




More information about the Scummvm-git-logs mailing list