[Scummvm-git-logs] scummvm master -> 27da4fc2a56a6582fd1c410a62cbd76c98e96691

neuromancer noreply at scummvm.org
Sat Jun 6 13:34:46 UTC 2026


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

Summary:
72481cb710 SCUMM: RA1: fix perspective for L11 UI
512a0ea6fa SCUMM: RA1: less permissive target detection
daf7775b63 SCUMM: RA1: make L11 much easier to control with mouse
27da4fc2a5 SCUMM: RA1: reduce crazy oscilation when using the mouse in some levels


Commit: 72481cb7106579b7f5d4303ee50300a2b8dfe04e
    https://github.com/scummvm/scummvm/commit/72481cb7106579b7f5d4303ee50300a2b8dfe04e
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T14:28:34+02:00

Commit Message:
SCUMM: RA1: fix perspective for L11 UI

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


diff --git a/engines/scumm/insane/rebel1/render.cpp b/engines/scumm/insane/rebel1/render.cpp
index 44b888c2cd1..aafe827bde7 100644
--- a/engines/scumm/insane/rebel1/render.cpp
+++ b/engines/scumm/insane/rebel1/render.cpp
@@ -817,7 +817,7 @@ void InsaneRebel1::procPostRendering(byte *renderBitmap, int32 codecparam, int32
 		renderLevelHitsOverlay(renderBitmap, pitch, width, height, 0x04, true);
 
 	if (_currentLevel == 10)
-		renderLevelHitsOverlay(renderBitmap, pitch, width, height, 0x16, false);
+		renderLevelHitsOverlay(renderBitmap, pitch, width, height, 0x16, true);
 
 	// Level 8 (Imperial Walkers) — walker-specific state update + UI overlay.
 	// In the original, RunLevel8Flow runs the walker logic inline in the per-frame


Commit: 512a0ea6fa9b904f26ccbbacca88bf344bd5e04c
    https://github.com/scummvm/scummvm/commit/512a0ea6fa9b904f26ccbbacca88bf344bd5e04c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T15:03:27+02:00

Commit Message:
SCUMM: RA1: less permissive target detection

Changed paths:
    engines/scumm/insane/rebel1/iact.cpp
    engines/scumm/insane/rebel1/rebel.cpp
    engines/scumm/insane/rebel1/rebel.h
    engines/scumm/insane/rebel1/runlevels.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 61b7a30e28e..8346b350b59 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -145,6 +145,25 @@ inline bool ra1DispatcherHudOnlyWhenDisabled(uint32 opcode) {
 	}
 }
 
+inline uint16 ra1PrioritizedFrameOpcode(uint32 opcodeMask) {
+	if (opcodeMask & (1u << 0x1A))
+		return 0x1A;
+	if (opcodeMask & (1u << 0x19))
+		return 0x19;
+	if (opcodeMask & (1u << 0x0B))
+		return 0x0B;
+	if (opcodeMask & (1u << 0x0A))
+		return 0x0A;
+	if (opcodeMask & (1u << 0x09))
+		return 0x09;
+	if (opcodeMask & (1u << 0x08))
+		return 0x08;
+	if (opcodeMask & (1u << 0x07))
+		return 0x07;
+
+	return 0;
+}
+
 bool ra1TargetCursorUsesProjection(uint16 opcode) {
 	switch (opcode) {
 	// FOBJ target chunks can precede the paired 0x0A GAME chunk, leaving 0x08
@@ -783,34 +802,39 @@ void InsaneRebel1::unprojectGameplayPoint(int16 &x, int16 &y) const {
 }
 
 uint16 InsaneRebel1::getEffectiveGameOpcode() const {
-	if (hasFrameGameOpcode(0x1A))
-		return 0x1A;
-	if (hasFrameGameOpcode(0x19))
-		return 0x19;
-	if (hasFrameGameOpcode(0x0B))
-		return 0x0B;
-	if (hasFrameGameOpcode(0x0A))
-		return 0x0A;
-	if (hasFrameGameOpcode(0x09))
-		return 0x09;
-	if (hasFrameGameOpcode(0x08))
-		return 0x08;
-	if (hasFrameGameOpcode(0x07))
-		return 0x07;
+	const uint16 frameOpcode = ra1PrioritizedFrameOpcode(_frameGameOpcodeMask);
+	if (frameOpcode != 0)
+		return frameOpcode;
+
+	return _activeGameOpcode;
+}
+
+uint16 InsaneRebel1::getTargetHitGameOpcode() const {
+	const uint16 frameOpcode = ra1PrioritizedFrameOpcode(_frameGameOpcodeMask | _frameGameOpcodeHintMask);
+	if (frameOpcode != 0)
+		return frameOpcode;
 
 	return _activeGameOpcode;
 }
 
+int16 InsaneRebel1::getGameplayCursorX(uint16 opcode) const {
+	return (opcode == 0x09) ? _flightAimX : _shipPosX;
+}
+
 int16 InsaneRebel1::getGameplayCursorX() const {
-	return (getEffectiveGameOpcode() == 0x09) ? _flightAimX : _shipPosX;
+	return getGameplayCursorX(getEffectiveGameOpcode());
+}
+
+int16 InsaneRebel1::getGameplayCursorY(uint16 opcode) const {
+	return (opcode == 0x09) ? _flightAimY : _shipPosY;
 }
 
 int16 InsaneRebel1::getGameplayCursorY() const {
-	return (getEffectiveGameOpcode() == 0x09) ? _flightAimY : _shipPosY;
+	return getGameplayCursorY(getEffectiveGameOpcode());
 }
 
-void InsaneRebel1::setGameplayCursor(int16 x, int16 y) {
-	if (getEffectiveGameOpcode() == 0x09) {
+void InsaneRebel1::setGameplayCursor(uint16 opcode, int16 x, int16 y) {
+	if (opcode == 0x09) {
 		_flightAimX = x;
 		_flightAimY = y;
 	} else {
@@ -819,6 +843,10 @@ void InsaneRebel1::setGameplayCursor(int16 x, int16 y) {
 	}
 }
 
+void InsaneRebel1::setGameplayCursor(int16 x, int16 y) {
+	setGameplayCursor(getEffectiveGameOpcode(), x, y);
+}
+
 void InsaneRebel1::updateFlightVariantCursor() {
 	if (getEffectiveGameOpcode() != 0x09)
 		return;
@@ -2537,10 +2565,10 @@ void InsaneRebel1::processShot() {
 // zones into gameplay-window screen space before comparing against the ship center.
 void InsaneRebel1::checkTargetHit(int16 targetIdx, int16 left, int16 top, int16 right, int16 bottom) {
 	int16 snap = _tuning.snap;
-	const uint16 effectiveOpcode = getEffectiveGameOpcode();
+	const uint16 effectiveOpcode = getTargetHitGameOpcode();
 	const bool screenSpaceCursor = ra1TargetCursorUsesProjection(effectiveOpcode);
-	const int16 screenCursorX = getGameplayCursorX();
-	const int16 screenCursorY = getGameplayCursorY();
+	const int16 screenCursorX = getGameplayCursorX(effectiveOpcode);
+	const int16 screenCursorY = getGameplayCursorY(effectiveOpcode);
 	int16 curX = screenCursorX;
 	int16 curY = screenCursorY;
 	if (screenSpaceCursor)
@@ -2584,7 +2612,7 @@ void InsaneRebel1::checkTargetHit(int16 targetIdx, int16 left, int16 top, int16
 				int16 snappedY = (top + bottom) / 2;
 				if (screenSpaceCursor)
 					projectGameplayPoint(snappedX, snappedY);
-				setGameplayCursor(snappedX, snappedY);
+				setGameplayCursor(effectiveOpcode, snappedX, snappedY);
 			}
 
 			// DOS uses g_recentKillObjectIdPlus1 as a frame-wide latch. Once one
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 4327c5e1703..4e981793ec0 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -279,6 +279,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	_turretEmitterRightX = 0;
 	_turretEmitterRightY = 0;
 	_activeGameOpcode = 0;
+	_frameGameOpcodeHintMask = 0;
 	_frameGameOpcodeMask = 0;
 	_frameHasGameChunk = false;
 	_frameDispatchFlags = 0;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 041a528e978..a110ab1e295 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -117,9 +117,11 @@ public:
 	int getLevelGameplayPhase() const { return _levelGameplayPhase; }
 	uint16 getActiveGameOpcode() const { return _activeGameOpcode; }
 	uint16 getEffectiveGameOpcode() const;
+	uint16 getTargetHitGameOpcode() const;
 	bool hasFrameGameOpcode(uint16 opcode) const {
 		return opcode < 32 && (_frameGameOpcodeMask & (1u << opcode)) != 0;
 	}
+	void setFrameGameOpcodeHintMask(uint32 opcodeMask) { _frameGameOpcodeHintMask = opcodeMask; }
 	void warpGameplayMouseNow(int x, int y);
 	int16 getPerspectiveX() const { return _perspectiveX; }
 	int16 getPerspectiveY() const { return _perspectiveY; }
@@ -127,7 +129,10 @@ public:
 	void unprojectGameplayPoint(int16 &x, int16 &y) const;
 	int16 getGameplayCursorX() const;
 	int16 getGameplayCursorY() const;
+	int16 getGameplayCursorX(uint16 opcode) const;
+	int16 getGameplayCursorY(uint16 opcode) const;
 	void setGameplayCursor(int16 x, int16 y);
+	void setGameplayCursor(uint16 opcode, int16 x, int16 y);
 	void updateFlightVariantCursor();
 	bool handleFrameObjectTarget(int16 objectId, int16 left, int16 top, int16 width, int16 height,
 		int codec, uint8 &ra1Param);
@@ -441,6 +446,8 @@ private:
 	// Last per-frame GAME opcode observed in the current playback stream.
 	// Kept for legacy call sites; frame-accurate dispatch uses _frameGameOpcodeMask.
 	uint16 _activeGameOpcode;
+	// GAME opcodes pre-scanned from the current frame before FOBJ dispatch.
+	uint32 _frameGameOpcodeHintMask;
 	uint32 _frameGameOpcodeMask;
 	bool _frameHasGameChunk;
 	uint16 _frameDispatchFlags;
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 92962e9b931..02b741f8a74 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -220,6 +220,7 @@ void InsaneRebel1::resetLevelFrameState() {
 	_currentSmushFrame = 0;
 	_gameCounter = 0;
 	_activeGameOpcode = 0;
+	_frameGameOpcodeHintMask = 0;
 	_gameLatch5D = 0;
 	_gameLatch5F = 0;
 }
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index c2a9fa8bdbb..694e947c881 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -717,18 +717,24 @@ void SmushPlayerRebel1::handleFrameObject(int32 subSize, Common::SeekableReadStr
 // handleFrame override — RA1 frame parsing with alignment, OBJ chunks, clean frame
 // ---------------------------------------------------------------------------
 
-static bool ra1FrameHasGameChunk(Common::SeekableReadStream &b, int32 frameSize) {
+static bool ra1ScanFrameGameChunks(Common::SeekableReadStream &b, int32 frameSize, uint32 &opcodeMask) {
+	opcodeMask = 0;
 	const int64 frameStart = b.pos();
 	int32 remaining = frameSize;
 	RA1FrameChunkIterator chunks(b, remaining);
 	RA1AnimChunk chunk;
+	bool hasGameChunk = false;
 	while (chunks.next(chunk)) {
 		if (chunk.tag == MKTAG('F', 'R', 'M', 'E'))
 			break;
 		if (chunk.tag == MKTAG('G', 'A', 'M', 'E') ||
 				chunk.tag == MKTAG('G', 'A', 'M', '2')) {
-			b.seek(frameStart, SEEK_SET);
-			return true;
+			hasGameChunk = true;
+			if (chunks.fits(chunk) && chunk.size >= 4) {
+				const uint32 opcode = b.readUint32BE();
+				if (opcode < 32)
+					opcodeMask |= (1u << opcode);
+			}
 		}
 
 		if (!chunks.fits(chunk))
@@ -737,7 +743,7 @@ static bool ra1FrameHasGameChunk(Common::SeekableReadStream &b, int32 frameSize)
 	}
 
 	b.seek(frameStart, SEEK_SET);
-	return false;
+	return hasGameChunk;
 }
 
 void SmushPlayerRebel1::ra1HandleFrameAudioChunk(int32 subSize, Common::SeekableReadStream &b) {
@@ -922,8 +928,11 @@ void SmushPlayerRebel1::handleFrame(int32 frameSize, Common::SeekableReadStream
 		InsaneRebel1 *rebel1 = static_cast<InsaneRebel1 *>(_insane);
 		rebel1->setCurrentSmushFrame(_frame);
 		bool interactive = rebel1->isInteractiveVideoActive();
-		const bool frameHasGameChunk = interactive && ra1FrameHasGameChunk(b, frameSize);
+		uint32 frameGameOpcodeHintMask = 0;
+		const bool frameHasGameChunk = interactive &&
+			ra1ScanFrameGameChunks(b, frameSize, frameGameOpcodeHintMask);
 		rebel1->setFrameHasGameChunk(frameHasGameChunk);
+		rebel1->setFrameGameOpcodeHintMask(frameGameOpcodeHintMask);
 		const uint16 activeOpcode = rebel1->getActiveGameOpcode();
 		bool forceClear = interactive &&
 			(activeOpcode == 0x0B ||


Commit: daf7775b633de7894716a1f477051951d3f639b4
    https://github.com/scummvm/scummvm/commit/daf7775b633de7894716a1f477051951d3f639b4
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T15:13:27+02:00

Commit Message:
SCUMM: RA1: make L11 much easier to control with mouse

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


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 8346b350b59..2b9b4a70847 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -87,6 +87,7 @@ const int kRA1CenteredAxisMax = 127;
 const int kRA1Op0BVerticalAxisMax = 100;
 const int kRA1EnhancedFlightDirectMaxX = 64;
 const int kRA1EnhancedFlightDirectMaxY = 40;
+const int kRA1Op09MouseRollTargetScale = 16;
 const int kRA1ControlPadAxisStep = 0x1E;
 const int16 kOnFootCenterX = 0xA3;  // g_perspectiveX in HandleGameOp19
 const int16 kOnFootCenterY = 0x82;  // g_perspectiveY in HandleGameOp19
@@ -972,7 +973,9 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 	if (updateGamepadReticleAim(inputX, inputY, usedJoystick))
 		return;
 
-	const bool directFlightInput = getEffectiveGameOpcode() == 0x07;
+	const uint16 effectiveOpcode = getEffectiveGameOpcode();
+	const bool directFlightInput = effectiveOpcode == 0x07;
+	const bool flightVariantInput = effectiveOpcode == 0x09;
 
 	const int16 analogAxisX = applyRebel1AnalogDeadzone(_joystickAxisX);
 	const int16 analogAxisY = applyRebel1AnalogDeadzone(_joystickAxisY);
@@ -1034,7 +1037,7 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 	int16 logicalX = (int16)CLIP<int>(_vm->_mouse.x, 0, 319);
 	int16 logicalY = (int16)CLIP<int>(_vm->_mouse.y, 0, 199);
 
-	if (directFlightInput) {
+	if (directFlightInput || flightVariantInput) {
 		inputX = scaleRebel1CenteredMouseAxis(logicalX, kRA1CenterX, kRA1EnhancedFlightDirectMaxX);
 		inputY = scaleRebel1CenteredMouseAxis(logicalY, kRA1CenterY, kRA1EnhancedFlightDirectMaxY);
 	} else {
@@ -1085,6 +1088,7 @@ void InsaneRebel1::updateShipPhysics() {
 	// --- Step 1: Gameplay axes from FUN_231BE ---
 	// HandleGameOp07_ShipFlight consumes the preprocessed axes in DAT_756C/756E,
 	// not raw mouse coordinates. Reuse the same centered-axis law here.
+	const uint16 effectiveOpcode = getEffectiveGameOpcode();
 	int16 inputX = 0;
 	int16 inputY = 0;
 	bool usedJoystick = false;
@@ -1100,8 +1104,15 @@ void InsaneRebel1::updateShipPhysics() {
 		inputSourceName = "joystick-dpad";
 
 	// --- Step 2: Roll accumulator (_74CA) ---
-	// Normal mode: accumulate; mode 0x10: snap to input
-	_rollAccum += (_tuning.roll * (int32)inputX) >> 5;
+	// Normal mode: accumulate. For ScummVM's absolute mouse in GAME 0x09, steer
+	// toward a bounded roll target so holding the cursor off center does not
+	// continue accelerating the ship until it clamps.
+	if (effectiveOpcode == 0x09 && _activeInputSource == kInputSourceMouse && !usedJoystick) {
+		const int32 targetRoll = (int32)inputX * kRA1Op09MouseRollTargetScale;
+		_rollAccum += (targetRoll - _rollAccum) >> 2;
+	} else {
+		_rollAccum += (_tuning.roll * (int32)inputX) >> 5;
+	}
 	_rollAccum = CLIP<int32>(_rollAccum, -0x47F, 0x47F);
 
 	// --- Step 3: Vertical smoothing (_74CE) ---


Commit: 27da4fc2a56a6582fd1c410a62cbd76c98e96691
    https://github.com/scummvm/scummvm/commit/27da4fc2a56a6582fd1c410a62cbd76c98e96691
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T15:34:32+02:00

Commit Message:
SCUMM: RA1: reduce crazy oscilation when using the mouse in some levels

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


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 2b9b4a70847..9c96d37650a 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -87,7 +87,7 @@ const int kRA1CenteredAxisMax = 127;
 const int kRA1Op0BVerticalAxisMax = 100;
 const int kRA1EnhancedFlightDirectMaxX = 64;
 const int kRA1EnhancedFlightDirectMaxY = 40;
-const int kRA1Op09MouseRollTargetScale = 16;
+const int kRA1MouseFlightRollTargetScale = 16;
 const int kRA1ControlPadAxisStep = 0x1E;
 const int16 kOnFootCenterX = 0xA3;  // g_perspectiveX in HandleGameOp19
 const int16 kOnFootCenterY = 0x82;  // g_perspectiveY in HandleGameOp19
@@ -1104,11 +1104,12 @@ void InsaneRebel1::updateShipPhysics() {
 		inputSourceName = "joystick-dpad";
 
 	// --- Step 2: Roll accumulator (_74CA) ---
-	// Normal mode: accumulate. For ScummVM's absolute mouse in GAME 0x09, steer
-	// toward a bounded roll target so holding the cursor off center does not
-	// continue accelerating the ship until it clamps.
-	if (effectiveOpcode == 0x09 && _activeInputSource == kInputSourceMouse && !usedJoystick) {
-		const int32 targetRoll = (int32)inputX * kRA1Op09MouseRollTargetScale;
+	// Normal mode: accumulate. For ScummVM's absolute mouse in flight handlers,
+	// steer toward a bounded roll target so holding the cursor off center does
+	// not continue accelerating the ship until it clamps.
+	if ((effectiveOpcode == 0x07 || effectiveOpcode == 0x09) &&
+			_activeInputSource == kInputSourceMouse && !usedJoystick) {
+		const int32 targetRoll = (int32)inputX * kRA1MouseFlightRollTargetScale;
 		_rollAccum += (targetRoll - _rollAccum) >> 2;
 	} else {
 		_rollAccum += (_tuning.roll * (int32)inputX) >> 5;




More information about the Scummvm-git-logs mailing list