[Scummvm-git-logs] scummvm master -> 12c0e7e2cd6348b67c2faafb0dc3edce1f5dc83c

neuromancer noreply at scummvm.org
Thu Jun 4 17:01:09 UTC 2026


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

Summary:
f0bd302f43 SCUMM: RA1: added missing overlay in level 1 (part 2)
1138603703 SCUMM: RA1: fixed ordering of rendering for indicators, shoots, overlays and cockpit
12c0e7e2cd SCUMM: RA1: correctly render the opening line in the intro


Commit: f0bd302f430d8a741f44258e7de27dc1506e0aa3
    https://github.com/scummvm/scummvm/commit/f0bd302f430d8a741f44258e7de27dc1506e0aa3
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T17:22:54+02:00

Commit Message:
SCUMM: RA1: added missing overlay in level 1 (part 2)

Changed paths:
    engines/scumm/insane/rebel1/rebel.h
    engines/scumm/insane/rebel1/render.cpp


diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 26dc27c6014..5ed007bb059 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -247,7 +247,8 @@ private:
 	void handleLevel14Play2BSplice(int32 curFrame, int32 maxFrame);
 	void renderLevel7RouteOverlays(byte *dst, int pitch, int width, int height);
 	void renderLevel5Part2Overlay(byte *dst, int pitch, int width, int height, int32 curFrame);
-	void renderLevel11HitsOverlay(byte *dst, int pitch, int width, int height);
+	void renderLevelHitsOverlay(byte *dst, int pitch, int width, int height, int y,
+		bool screenSpace);
 	void resetEnemyShotSlots();
 	void renderLevel13EnemyShots(byte *dst, int pitch, int width, int height);
 	void getTurretShipCenter(int16 &x, int16 &y) const;
diff --git a/engines/scumm/insane/rebel1/render.cpp b/engines/scumm/insane/rebel1/render.cpp
index 1a17b10eb9f..e52794dde7d 100644
--- a/engines/scumm/insane/rebel1/render.cpp
+++ b/engines/scumm/insane/rebel1/render.cpp
@@ -800,8 +800,11 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 	if (_currentLevel == 4 && _levelGameplayPhase == 2)
 		renderLevel5Part2Overlay(renderBitmap, pitch, width, height, curFrame);
 
+	if (_currentLevel == 0 && _flyControlMode == 2)
+		renderLevelHitsOverlay(renderBitmap, pitch, width, height, 0x04, true);
+
 	if (_currentLevel == 10)
-		renderLevel11HitsOverlay(renderBitmap, pitch, width, height);
+		renderLevelHitsOverlay(renderBitmap, pitch, width, height, 0x16, false);
 
 	// Level 8 (Imperial Walkers) — walker-specific state update + UI overlay.
 	// In the original, RunLevel8Flow runs the walker logic inline in the per-frame
@@ -1017,16 +1020,23 @@ void InsaneRebel1::renderGostSlots(byte *dst, int pitch, int width, int height)
 	}
 }
 
-// renderLevel11HitsOverlay — RunLevel11Flow (0x19F9F) calls FormatAndDrawText
-// each L11PLAY frame with "<<HITS %02d" at (0x119, 0x16). This helper is a
-// ScummVM-side extraction; the original keeps the draw call inline in the loop.
-void InsaneRebel1::renderLevel11HitsOverlay(byte *dst, int pitch, int width, int height) {
+// renderLevelHitsOverlay — RunLevel1Flow (0x16421-0x16438) and RunLevel11Flow
+// (0x1A07A-0x1A090) call FormatAndDrawText with "<<HITS %02d" at x=0x119.
+void InsaneRebel1::renderLevelHitsOverlay(byte *dst, int pitch, int width, int height, int y,
+		bool screenSpace) {
 	if (_hudFontBank.numSprites <= 0 && _techFontBank.numSprites <= 0)
 		return;
 
+	int drawX = 0x119;
+	int drawY = y;
+	if (screenSpace && _player) {
+		drawX += ra1Player()->_ra1ViewportOffsetX;
+		drawY += ra1Player()->_ra1ViewportOffsetY;
+	}
+
 	char hitsStr[16];
 	Common::sprintf_s(hitsStr, "<<HITS %02d", (int)_killCount);
-	drawFontBankString(dst, pitch, width, height, 0x119, 0x16, hitsStr);
+	drawFontBankString(dst, pitch, width, height, drawX, drawY, hitsStr);
 }
 
 // renderLevel5Part2Overlay — RunLevel5Flow (0x176D0-0x1777E) draws the


Commit: 113860370310e60708cdf42a127f50a851c9b9bd
    https://github.com/scummvm/scummvm/commit/113860370310e60708cdf42a127f50a851c9b9bd
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T17:59:33+02:00

Commit Message:
SCUMM: RA1: fixed ordering of rendering for indicators, shoots, overlays and cockpit

Changed paths:
    engines/scumm/insane/rebel1/iact.cpp
    engines/scumm/insane/rebel1/rebel.cpp
    engines/scumm/insane/rebel1/rebel.h
    engines/scumm/insane/rebel1/render.cpp
    engines/scumm/smush/rebel/smush_player_ra1.cpp


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 48f1ff485ee..71106907a37 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -2433,7 +2433,8 @@ void InsaneRebel1::handleGameCounterOpcode(uint32 opcode, int32 subSize, Common:
 
 // handleGameChunk — FUN_1BE1B (0x1BE1B). Central GAME opcode dispatcher.
 // Reads 7x32-bit BE integers from GAME chunk, routes to per-opcode handlers.
-void InsaneRebel1::handleGameChunk(int32 subSize, Common::SeekableReadStream &b) {
+void InsaneRebel1::handleGameChunk(int32 subSize, Common::SeekableReadStream &b,
+		byte *renderBitmap, int width, int height) {
 	if (subSize < 8)
 		return;
 
@@ -2484,6 +2485,7 @@ void InsaneRebel1::handleGameChunk(int32 subSize, Common::SeekableReadStream &b)
 
 	case 0x0B:
 		handleGameOpcode0BFirstPerson(subSize, b, param1);
+		renderGameOp0BOverlayDuringChunk(renderBitmap, width, width, height);
 		break;
 
 	case 0x5A:
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 4fd79f1c7eb..eb886e24bae 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -295,6 +295,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	_frameHasGameChunk = false;
 	_frameDispatchFlags = 0;
 	_gameOp0BPhysicsUpdatedThisFrame = false;
+	_gameOp0BOverlayRenderedThisFrame = false;
 
 	_health = kMaxHealth;
 	_lives = 3;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 5ed007bb059..1db04a43a5b 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -103,7 +103,8 @@ public:
 		int16 par1, int16 par2, int16 par3, int16 par4) override;
 	void procSKIP(int32 subSize, Common::SeekableReadStream &b) override;
 
-	void handleGameChunk(int32 subSize, Common::SeekableReadStream &b);
+	void handleGameChunk(int32 subSize, Common::SeekableReadStream &b,
+		byte *renderBitmap = nullptr, int width = 0, int height = 0);
 	bool isInteractiveVideoActive() const { return _interactiveVideoActive; }
 	// True on touchscreen devices (e.g. Android). RA1 skips DOS-style cursor
 	// warping/locking there; direct touch uses absolute aiming, while on-screen
@@ -243,7 +244,8 @@ private:
 							  int16 centerX, int16 centerY, int16 frame);
 	void renderLaserShots(byte *dst, int pitch, int width, int height);
 	void renderShotOverlayPipeline(byte *dst, int pitch, int width, int height,
-		bool drawTargetBoxes);
+		bool drawTargetBoxes, bool drawTargeting = true);
+	void renderGameOp0BOverlayDuringChunk(byte *dst, int pitch, int width, int height);
 	void handleLevel14Play2BSplice(int32 curFrame, int32 maxFrame);
 	void renderLevel7RouteOverlays(byte *dst, int pitch, int width, int height);
 	void renderLevel5Part2Overlay(byte *dst, int pitch, int width, int height, int32 curFrame);
@@ -447,6 +449,7 @@ private:
 	bool _frameHasGameChunk;
 	uint16 _frameDispatchFlags;
 	bool _gameOp0BPhysicsUpdatedThisFrame;
+	bool _gameOp0BOverlayRenderedThisFrame;
 
 	// Difficulty (0=easy, 1=normal, 2=hard) — matches original DAT_22BC
 	int _difficulty;
diff --git a/engines/scumm/insane/rebel1/render.cpp b/engines/scumm/insane/rebel1/render.cpp
index e52794dde7d..44b888c2cd1 100644
--- a/engines/scumm/insane/rebel1/render.cpp
+++ b/engines/scumm/insane/rebel1/render.cpp
@@ -524,6 +524,7 @@ void InsaneRebel1::procPreRendering(byte *renderBitmap) {
 	_frameDispatchFlags = 0;
 	_hudRenderFlag = 0;
 	_gameOp0BPhysicsUpdatedThisFrame = false;
+	_gameOp0BOverlayRenderedThisFrame = false;
 	_turretFrameShipCenterValid = false;
 	_frameObjectHitRevealPending = false;
 
@@ -630,6 +631,8 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 		(allowImplicitGameplayMode &&
 			(_activeGameOpcode == 0x07 || _activeGameOpcode == 0x09));
 	bool shotOverlayHandled = false;
+	bool drawShipAfterGameplayOverlays = false;
+	bool drawGameOp0BTargetingAfterFetch = false;
 	if (gameOp0BMode) {
 		// GAME 0x0B scrolling cockpit/surface handler — FUN_1CDA7.
 		if (!_gameOp0BPhysicsUpdatedThisFrame) {
@@ -647,6 +650,9 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 			_vm->_smushVideoShouldFinish = true;
 			return;
 		}
+
+		shotOverlayHandled = _gameOp0BOverlayRenderedThisFrame;
+		drawGameOp0BTargetingAfterFetch = _gameOp0BOverlayRenderedThisFrame;
 	} else if (onFootMode) {
 		// On-foot handler — opcodes 0x19/0x1A (Level 9 Stormtroopers)
 		if (_currentLevel == 8 && onFootAimMode && !onFootSequenceMode && _killCount > 0) {
@@ -721,9 +727,9 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 			return;
 		}
 
-		// Ship sprite is present in both flight (0x07 family) and 0x08 turret path.
-		if (flightMode || turretMode)
-			renderShip(renderBitmap, pitch, width, height);
+		// The paired GAME 0x09/0x0A handlers draw target boxes, shots and
+		// reticles before the 0x07/0x08 ship/cockpit pass.
+		drawShipAfterGameplayOverlays = (flightMode || turretMode);
 	}
 
 	// GAME handlers in the original update FUN_224FD during the same frame that
@@ -795,6 +801,13 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 		renderLevel7RouteOverlays(renderBitmap, pitch, width, height);
 
 	renderExplosions(renderBitmap, pitch, width, height);
+
+	if (drawShipAfterGameplayOverlays)
+		renderShip(renderBitmap, pitch, width, height);
+
+	if (drawGameOp0BTargetingAfterFetch)
+		renderTargeting(renderBitmap, pitch, width, height);
+
 	handleLevel14Play2BSplice(curFrame, maxFrame);
 
 	if (_currentLevel == 4 && _levelGameplayPhase == 2)
@@ -823,9 +836,11 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 
 // ScummVM helper that groups the common shot/lock overlay calls used by the
 // original GAME handlers. GAME 0x1A uses the same pipeline without the target
-// box draw; 0x09/0x0A/0x0B include DrawTargetIndicators first.
+// box draw; 0x09/0x0A/0x0B include DrawTargetIndicators first. GAME 0x0B
+// defers FUN_1CB22 targeting until post-render so FTCH can restore cockpit
+// pixels over shots/boxes while the lock/fire indicator remains visible.
 void InsaneRebel1::renderShotOverlayPipeline(byte *dst, int pitch, int width, int height,
-		bool drawTargetBoxes) {
+		bool drawTargetBoxes, bool drawTargeting) {
 	if (drawTargetBoxes) {
 		renderTargetBoxes(dst, pitch, width, height);
 	} else {
@@ -842,7 +857,16 @@ void InsaneRebel1::renderShotOverlayPipeline(byte *dst, int pitch, int width, in
 			_shotSlots[i].timer--;
 	}
 	renderGostSlots(dst, pitch, width, height);
-	renderTargeting(dst, pitch, width, height);
+	if (drawTargeting)
+		renderTargeting(dst, pitch, width, height);
+}
+
+void InsaneRebel1::renderGameOp0BOverlayDuringChunk(byte *dst, int pitch, int width, int height) {
+	if (_gameOp0BOverlayRenderedThisFrame || !dst || width <= 0 || height <= 0 || _health < 0)
+		return;
+
+	renderShotOverlayPipeline(dst, pitch, width, height, true, false);
+	_gameOp0BOverlayRenderedThisFrame = true;
 }
 
 // renderTargetBoxes — FUN_1C940 (0x1C940). Per-target green box overlays.
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index 19add73b0d5..d3343270d9a 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -740,7 +740,7 @@ void SmushPlayerRebel1::ra1HandleFrameAudioChunk(int32 subSize, Common::Seekable
 void SmushPlayerRebel1::ra1HandleGameFrameChunk(int32 subSize, Common::SeekableReadStream &b, bool fastForwarding) {
 	if (!fastForwarding && _insane) {
 		InsaneRebel1 *rebel1 = (InsaneRebel1 *)_insane;
-		rebel1->handleGameChunk(subSize, b);
+		rebel1->handleGameChunk(subSize, b, _dst, _width, _height);
 	}
 }
 


Commit: 12c0e7e2cd6348b67c2faafb0dc3edce1f5dc83c
    https://github.com/scummvm/scummvm/commit/12c0e7e2cd6348b67c2faafb0dc3edce1f5dc83c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T19:00:49+02:00

Commit Message:
SCUMM: RA1: correctly render the opening line in the intro

Changed paths:
    engines/scumm/insane/rebel1/runlevels.cpp
    engines/scumm/smush/rebel/smush_player_ra1.cpp


diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 215fe75864f..8ef89b85847 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -144,7 +144,6 @@ static int calculateThresholdBonus(int kills, int perfectThreshold, int perKillT
 // ---------------------------------------------------------------------------
 
 // Play a passive cinematic (no game callback, skippable).
-// Reuses RA2's pattern: reset handler, set cinematic flags, play video.
 // startFrame > 0: fast-forward (decode without display/audio) to that frame.
 void InsaneRebel1::playCinematic(const char *filename, int32 startFrame) {
 	debugC(DEBUG_INSANE, "InsaneRebel1::playCinematic('%s', startFrame=%d)", filename, startFrame);
@@ -156,7 +155,7 @@ void InsaneRebel1::playCinematic(const char *filename, int32 startFrame) {
 	restoreScreenFlashPalette();
 	_interactiveVideoActive = false;
 	_vm->_smushVideoShouldFinish = false;
-	splayer->setCurVideoFlags(0x28);  // Cinematic mode + buffer preserve
+	splayer->setCurVideoFlags(0x420);
 	splayer->setFastForwardFromFrame(0);
 	splayer->setFastForwardToFrame(startFrame > 0 ? startFrame : 0);
 	splayer->play(filename, 15);
@@ -320,7 +319,6 @@ void InsaneRebel1::playIntroSequence() {
 	playCinematic("OPEN/O1LOGO.ANM");
 	if (shouldAbortGameFlow())
 		return;
-	clearVideoBuffer();
 
 	// Star Wars opening crawl (original: PUSH 0x5800, CALL FUN_1BA32)
 	playCinematic("OPEN/O1OPEN.ANM");
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index d3343270d9a..54d4f029003 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -41,6 +41,8 @@
 namespace Scumm {
 
 enum {
+	kRA1DecodeWidth = 384,
+	kRA1DecodeHeight = 242,
 	kRA1PresentationBorder = 4,
 	kRA1PresentationScreenWidth = 320,
 	kRA1PresentationScreenHeight = 200,
@@ -326,12 +328,17 @@ bool SmushPlayerRebel1::handleGameTextResource(uint32 subType, int32 subSize, Co
 	if (subType != MKTAG('T','E','X','T'))
 		return false;
 
-	// RA1 dialogue subtitles. Only render them when subtitles are enabled — this honors
-	// both ScummVM's global "subtitles" setting and the in-game DIALOGUE TEXT toggle
-	// (which writes the same ConfMan key). Still return true so the base handler doesn't
-	// try to parse RA1's custom TEXT format. Querying ConfMan per chunk also lets the
-	// setting take effect mid-video.
-	if (ConfMan.getBool("subtitles"))
+	bool forceText = false;
+	if (subSize > 8) {
+		const int64 textStart = b.pos();
+		b.seek(textStart + 8, SEEK_SET);
+		forceText = (b.readByte() == '.');
+		b.seek(textStart, SEEK_SET);
+	}
+
+	// Original FUN_1FDBC draws RA1 TEXT when the text starts with '.' regardless
+	// of the DIALOGUE TEXT option. O1OPEN uses that path for the opening lines.
+	if (forceText || ConfMan.getBool("subtitles"))
 		ra1HandleText(subSize, b);
 	return true;
 }
@@ -479,9 +486,9 @@ void SmushPlayerRebel1::ra1HandleFade(int32 subSize, Common::SeekableReadStream
 
 bool SmushPlayerRebel1::handleGameAnimHeader(byte *headerContent) {
 	(void)headerContent;
-	_width = 0;
-	_height = 0;
-	const int bufSize = 384 * 242;
+	_width = kRA1DecodeWidth;
+	_height = kRA1DecodeHeight;
+	const int bufSize = kRA1DecodeWidth * kRA1DecodeHeight;
 	if (_specialBuffer == nullptr || bufSize > _specialBufferSize) {
 		free(_specialBuffer);
 		_specialBuffer = (byte *)calloc(bufSize, 1);
@@ -499,7 +506,7 @@ void SmushPlayerRebel1::handleGameParseNextFrame() {
 
 bool SmushPlayerRebel1::handleGameFrameBufferSelect(int codec, int width, int height) {
 	// RA1 sub-fullscreen frames render into _specialBuffer at their (left, top) offset position.
-	int bufSize = 384 * 242;
+	int bufSize = kRA1DecodeWidth * kRA1DecodeHeight;
 	if (_specialBuffer == nullptr || bufSize > _specialBufferSize) {
 		free(_specialBuffer);
 		_specialBuffer = (byte *)calloc(bufSize, 1);
@@ -512,10 +519,8 @@ bool SmushPlayerRebel1::handleGameFrameBufferSelect(int codec, int width, int he
 bool SmushPlayerRebel1::handleGameDimensionOverride(int codec, int width, int height) {
 	if (_dst == _specialBuffer) {
 		// RA1: sub-fullscreen FOBJs should not override the 384x242 dimensions.
-		if (_width == 0 || _height == 0) {
-			_width = 384;
-			_height = 242;
-		}
+		_width = kRA1DecodeWidth;
+		_height = kRA1DecodeHeight;
 		return true;
 	}
 	return false;




More information about the Scummvm-git-logs mailing list