[Scummvm-git-logs] scummvm master -> 9bbfdda5adc030de46ed381ecb331aceda288f77

neuromancer noreply at scummvm.org
Sat Jun 6 08:04:16 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:
390947c5b4 SCUMM: RA: restore palette when the player is hit
c741d304f3 SCUMM: RA1: simplify controls using 3DO controls
9bbfdda5ad SCUMM: RA1: added rapid fire following 3do controls


Commit: 390947c5b4e34b2f0920ad8f15f693d39e651feb
    https://github.com/scummvm/scummvm/commit/390947c5b4e34b2f0920ad8f15f693d39e651feb
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T10:04:04+02:00

Commit Message:
SCUMM: RA: restore palette when the player is hit

Changed paths:
    engines/scumm/insane/rebel1/runlevels.cpp
    engines/scumm/insane/rebel2/levels.cpp
    engines/scumm/insane/rebel2/rebel.cpp
    engines/scumm/insane/rebel2/rebel.h
    engines/scumm/insane/rebel2/render.cpp
    engines/scumm/insane/rebel2/runlevels.cpp
    engines/scumm/smush/rebel/smush_player_ra1.cpp
    engines/scumm/smush/rebel/smush_player_ra1.h


diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 29792d1ad45..cb6dd67e766 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -1806,6 +1806,7 @@ void InsaneRebel1::releaseInteractiveVideoInput() {
 
 void InsaneRebel1::playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame) {
 	_vm->_splayer->play(filename, 15, videoOffset, videoStartFrame);
+	restoreScreenFlashPalette();
 	restoreInteractiveVideoAudioState();
 	_interactiveVideoActive = false;
 }
diff --git a/engines/scumm/insane/rebel2/levels.cpp b/engines/scumm/insane/rebel2/levels.cpp
index 062ec934395..f7fd926727e 100644
--- a/engines/scumm/insane/rebel2/levels.cpp
+++ b/engines/scumm/insane/rebel2/levels.cpp
@@ -185,6 +185,7 @@ void InsaneRebel2::playMissionBriefing() {
 // Resets handler to 0 (no HUD) and sets flags to 0x28 (cinematic + buffer preserve).
 // All wrapper functions (FUN_00417168/4171c5/417ab2/417327) add | 8 before calling FUN_0041f4d0.
 void InsaneRebel2::playCinematic(const char *filename) {
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // No status bar during cinematics
@@ -200,6 +201,7 @@ void InsaneRebel2::playCinematic(const char *filename) {
 void InsaneRebel2::playVideoWithText(const char *filename, int textID, int textX, int textY,
                                      int fadeInFrame, int fadeOutFrame) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;
@@ -271,6 +273,7 @@ void InsaneRebel2::playLevelBegin(int levelId) {
 // playLevelEnd -- Level completion video (FUN_00417327).
 void InsaneRebel2::playLevelEnd(int levelId) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // No status bar during end cinematic
@@ -290,6 +293,7 @@ void InsaneRebel2::playLevelEnd(int levelId) {
 // playLevelRetry -- Retry prompt video (LEVXX/XXRETRY.SAN, FUN_00417168).
 void InsaneRebel2::playLevelRetry(int levelId) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // Reset for retry - will be set by IACT opcode 6 if needed
@@ -309,6 +313,7 @@ void InsaneRebel2::playLevelRetry(int levelId) {
 // playLevelGameOver -- Game over video (FUN_00417ab2).
 void InsaneRebel2::playLevelGameOver(int levelId) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // No status bar during game over cinematic
@@ -714,6 +719,7 @@ Common::String InsaneRebel2::selectDeathVideoVariant(int levelId, int phase, int
 // playLevelDeathVariant -- Death video with variant selection.
 void InsaneRebel2::playLevelDeathVariant(int levelId, int phase, int frame) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // No status bar during death cinematic
@@ -741,6 +747,7 @@ void InsaneRebel2::playLevelDeathVariant(int levelId, int phase, int frame) {
 // playLevelRetryVariant -- Phase-specific retry video.
 void InsaneRebel2::playLevelRetryVariant(int levelId, int phase) {
 
+	restoreDamageFlashPalette();
 	_gameplaySectionActive = false;
 	_rebelHandler = 0;
 	_rebelStatusBarSprite = 0;  // Reset for retry - will be set by IACT opcode 6 if needed
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index ae1f86099ac..213e0820411 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -193,6 +193,8 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
 	_damageHighFlashCounter = 0;
 	_damageShakeCounter = 0;
 	memset(_damageSavedPalette, 0, sizeof(_damageSavedPalette));
+	memset(_damageRestorePalette, 0, sizeof(_damageRestorePalette));
+	_damageRestorePaletteValid = false;
 
 	// Text overlay state (FUN_004171c5 chapter title rendering)
 	_textOverlayActive = false;
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 41cdec1c5be..b0bf580ba9b 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -900,11 +900,14 @@ public:
 	void updateDamageFlashPalette();     // FUN_00420562
 	void updateDamageEffect(byte *renderBitmap, int pitch, int width, int height); // FUN_00420754
 	void resetDamageFlash();             // FUN_00420501
+	void restoreDamageFlashPalette();
 
 	int16 _damageFlashCounter;           // DAT_00482404 - palette flash countdown (0..5)
 	int16 _damageHighFlashCounter;       // DAT_00482408 - high-damage red flash (0..16)
 	int16 _damageShakeCounter;           // DAT_0048240c - screen shake countdown (0..10)
 	byte _damageSavedPalette[0x300];     // DAT_00459990 - palette snapshot before flash
+	byte _damageRestorePalette[0x300];   // ScummVM boundary restore snapshot
+	bool _damageRestorePaletteValid;
 
 	// Rebel per-level counters / flags mapped from retail globals
 	bool _rebelOp6Initialized; // Guard: opcode 6 init block (clearBit/links/wave) runs once per video
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 1f821621e41..c0a7e3ab4d7 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -2667,8 +2667,27 @@ void InsaneRebel2::resetDamageFlash() {
 	_damageFlashCounter = 0;
 }
 
+void InsaneRebel2::restoreDamageFlashPalette() {
+	if (_player) {
+		if (_damageRestorePaletteValid)
+			_player->setPalette(_damageRestorePalette);
+		else if (_damageFlashCounter != 0 || _damageHighFlashCounter != 0)
+			_player->setPalette(_damageSavedPalette);
+	}
+
+	_damageFlashCounter = 0;
+	_damageHighFlashCounter = 0;
+	_damageShakeCounter = 0;
+	_damageRestorePaletteValid = false;
+}
+
 // initDamageFlash -- Save palette and initiate 5-frame flash (FUN_00420515).
 void InsaneRebel2::initDamageFlash() {
+	if (!_damageRestorePaletteValid && _player) {
+		memcpy(_damageRestorePalette, _player->_pal, 0x300);
+		_damageRestorePaletteValid = true;
+	}
+
 	if (_damageFlashCounter == 0) {
 		// Save current SMUSH palette before modifying it
 		memcpy(_damageSavedPalette, _player->_pal, 0x300);
@@ -2698,6 +2717,10 @@ void InsaneRebel2::updateDamageFlashPalette() {
 		_damageHighFlashCounter = 0;
 	} else {
 		if (_damageHighFlashCounter == 0) {
+			if (!_damageRestorePaletteValid) {
+				memcpy(_damageRestorePalette, _player->_pal, 0x300);
+				_damageRestorePaletteValid = true;
+			}
 			// Save palette on first frame of high-damage mode
 			memcpy(_damageSavedPalette, _player->_pal, 0x300);
 		}
@@ -2719,6 +2742,8 @@ void InsaneRebel2::updateDamageFlashPalette() {
 					modPal[i] = 0xFF - (((0xFF - _damageSavedPalette[i]) * blend) >> 4);
 				}
 				_player->setPalette(modPal);
+				if (_damageFlashCounter == 0 && _damageHighFlashCounter == 0)
+					_damageRestorePaletteValid = false;
 			}
 		}
 	} else {
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 63dc995ce41..1dd66088685 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -205,6 +205,7 @@ bool InsaneRebel2::playLevelSegment(const char *filename, uint16 flags, bool rec
 	splayer->play(filename, 15);
 	if (recordFrame)
 		_deathFrame = splayer->_frame;
+	restoreDamageFlashPalette();
 	return !_vm->shouldQuit();
 }
 
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index 9b24d8248fa..d6208e7ad8c 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -187,6 +187,13 @@ void SmushPlayerRebel1::resetGameVideoState() {
 	_ra1UseFadeFrame = false;
 }
 
+void SmushPlayerRebel1::initGameVideoState() {
+	// Some RA1 ANMs inherit the current SMUSH palette. SmushPlayer::play()
+	// clears the dirty range before init(), so re-push the palette that was
+	// restored or inherited before this video starts.
+	setDirtyColors(0, 255);
+}
+
 void SmushPlayerRebel1::releaseGameVideoState() {
 	free(_storedFobjData);
 	_storedFobjData = nullptr;
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.h b/engines/scumm/smush/rebel/smush_player_ra1.h
index 2188e206c62..be70db7b950 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.h
+++ b/engines/scumm/smush/rebel/smush_player_ra1.h
@@ -36,6 +36,7 @@ protected:
 	void initGamePlayerFields() override;
 	void destroyGamePlayerFields() override;
 	void resetGameVideoState() override;
+	void initGameVideoState() override;
 	void releaseGameVideoState() override;
 	bool handleGameFetch(int32 subSize, Common::SeekableReadStream &b) override;
 	bool handleGameTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &b) override;


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

Commit Message:
SCUMM: RA1: simplify controls using 3DO controls

Changed paths:
    engines/scumm/insane/rebel1/iact.cpp
    engines/scumm/insane/rebel1/menu.cpp
    engines/scumm/insane/rebel1/rebel.cpp
    engines/scumm/insane/rebel1/rebel.h
    engines/scumm/insane/rebel1/runlevels.cpp


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 4ae3706e857..2a2501402e6 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -50,6 +50,14 @@ inline int16 scaleRebel1CenteredMouseAxis(int16 value, int16 center, int axisMax
 	return (int16)CLIP<int32>(((int32)(value - center) * axisMax) / center, -axisMax, axisMax);
 }
 
+inline int16 stepRebel1Op0BReticleAxis(int axisValue) {
+	if (axisValue >= 0)
+		return (int16)(axisValue >> 4);
+
+	// The 3DO ARM code integrates the standard control-pad path with ASR #4.
+	return (int16)-((-axisValue + 15) >> 4);
+}
+
 int16 shapeRebel1Op0BGamepadAxis(int16 inputValue, int16 axisMax) {
 	const int axis = CLIP<int>(inputValue, -axisMax, axisMax);
 	const int absAxis = ABS(axis);
@@ -75,16 +83,11 @@ int16 shapeRebel1Op0BGamepadAxis(int16 inputValue, int16 axisMax) {
 
 const int16 kRA1Op09AimXScale[5] = { 0, 44, 88, 128, 165 };
 const int16 kRA1Op09AimYScale[5] = { 256, 252, 240, 221, 196 };
-const int kRA1DosMouseCenterX = 0x140;
-const int kRA1DosMouseCenterY = 100;
-const int kRA1DosMouseSafeLeft = 0x0AA;
-const int kRA1DosMouseSafeRight = 0x1D6;
-const int kRA1DosMouseSafeTop = 0x32;
-const int kRA1DosMouseSafeBottom = 0x96;
-const int kRA1DosFlightMouseMaxX = kRA1DosMouseCenterX >> 2;
-const int kRA1DosFlightMouseMaxY = kRA1DosMouseCenterY >> 1;
-const int kRA1EnhancedFlightDirectMaxX = (kRA1DosFlightMouseMaxX * 4) / 5;
-const int kRA1EnhancedFlightDirectMaxY = (kRA1DosFlightMouseMaxY * 4) / 5;
+const int kRA1CenteredAxisMax = 127;
+const int kRA1Op0BVerticalAxisMax = 100;
+const int kRA1EnhancedFlightDirectMaxX = 64;
+const int kRA1EnhancedFlightDirectMaxY = 40;
+const int kRA1ControlPadAxisStep = 0x1E;
 
 // Level 15 final approach 0x5D damage/event codes consumed by
 // RunLevel1GameLoop. The latch stores the raw GAME parameter; no translation is
@@ -834,11 +837,10 @@ void InsaneRebel1::updateFlightVariantCursor() {
 }
 
 // preprocessMouseAxes — FUN_231BE (0x231BE) centered-axis output law, adapted to
-// ScummVM's absolute 320x200 mouse space.
-// Original-input mode preserves the DOS bias/offset persistence and one-frame
-// jump latch from FUN_231BE, plus FUN_23115's DOS mouse recenter behavior.
-// Enhanced controls are ScummVM-only: they bypass the original recentering state
-// and expose a stable absolute centered mouse axis instead.
+// ScummVM's absolute 320x200 mouse space. The old DOS virtual-mouse/recenter
+// control path is intentionally not used. For opcode 0x0B, gamepad input uses
+// the 3DO standard-pad reticle model: axis samples move the reticle, and
+// releasing the pad holds the last reticle position.
 bool InsaneRebel1::isOp0BReticleControlLevel() const {
 	switch (_currentLevel) {
 	case 1:  // Level 2
@@ -859,23 +861,18 @@ bool InsaneRebel1::shouldInvertTouchYSettingForCurrentLevel() const {
 	return isTouchscreenActive() && isOp0BReticleControlLevel();
 }
 
-bool InsaneRebel1::usesRelativeGamepadAimForCurrentLevel() const {
-	return _optEnhancedControls &&
-		(_currentLevel == 3 ||
-		 (_currentLevel == 4 && _levelGameplayPhase == 2) ||
-		 _currentLevel == 9 ||
-		 _currentLevel == 11 ||
-		 _currentLevel == 13);
+bool InsaneRebel1::usesGamepadReticleAimForCurrentFrame() const {
+	return getEffectiveGameOpcode() == 0x0B;
 }
 
-void InsaneRebel1::resetRelativeGamepadAim() {
+void InsaneRebel1::resetGamepadReticleAim() {
 	_gamepadAimAxisX = 0;
 	_gamepadAimAxisY = 0;
 	_gamepadAimActive = false;
 }
 
-bool InsaneRebel1::updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *usedJoystick) {
-	if (!usesRelativeGamepadAimForCurrentLevel())
+bool InsaneRebel1::updateGamepadReticleAim(int16 &inputX, int16 &inputY, bool *usedJoystick) {
+	if (!usesGamepadReticleAimForCurrentFrame())
 		return false;
 
 	const int dpadX =
@@ -887,8 +884,10 @@ bool InsaneRebel1::updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *
 
 	const int16 analogAxisX = applyRebel1AnalogDeadzone(_joystickAxisX);
 	const int16 analogAxisY = applyRebel1AnalogDeadzone(_joystickAxisY);
-	const int analogX = CLIP<int32>(((int32)analogAxisX * 127) / Common::JOYAXIS_MAX, -127, 127);
-	int analogY = CLIP<int32>((-(int32)analogAxisY * 100) / Common::JOYAXIS_MAX, -100, 100);
+	const int analogX = CLIP<int32>(((int32)analogAxisX * kRA1CenteredAxisMax) / Common::JOYAXIS_MAX,
+		-kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+	int analogY = CLIP<int32>((-(int32)analogAxisY * kRA1Op0BVerticalAxisMax) / Common::JOYAXIS_MAX,
+		-kRA1Op0BVerticalAxisMax, kRA1Op0BVerticalAxisMax);
 
 	if (_optControlsYFlip) {
 		dpadY = -dpadY;
@@ -900,24 +899,22 @@ bool InsaneRebel1::updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *
 	bool activeGamepadAim = false;
 
 	if (dpadX || dpadY) {
-		const int kDigitalAimStep = 3;
-		deltaX = dpadX * kDigitalAimStep;
-		deltaY = dpadY * kDigitalAimStep;
+		deltaX = stepRebel1Op0BReticleAxis(dpadX * kRA1ControlPadAxisStep);
+		deltaY = stepRebel1Op0BReticleAxis(dpadY * kRA1ControlPadAxisStep);
 		activeGamepadAim = true;
 	} else if (analogX || analogY) {
-		const int kAnalogAimMaxStep = 8;
-		deltaX = analogX * kAnalogAimMaxStep / 127;
-		deltaY = analogY * kAnalogAimMaxStep / 100;
+		deltaX = stepRebel1Op0BReticleAxis(analogX);
+		deltaY = stepRebel1Op0BReticleAxis(analogY);
 		activeGamepadAim = true;
 	}
 
 	if (activeGamepadAim) {
 		if (!_gamepadAimActive) {
-			_gamepadAimAxisX = CLIP<int16>(_avgInputX, -127, 127);
-			_gamepadAimAxisY = CLIP<int16>((int16)-_avgInputY, -100, 100);
+			_gamepadAimAxisX = CLIP<int16>(_avgInputX, -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+			_gamepadAimAxisY = CLIP<int16>((int16)-_avgInputY, -kRA1Op0BVerticalAxisMax, kRA1Op0BVerticalAxisMax);
 		}
-		_gamepadAimAxisX = CLIP<int16>((int16)(_gamepadAimAxisX + deltaX), -127, 127);
-		_gamepadAimAxisY = CLIP<int16>((int16)(_gamepadAimAxisY + deltaY), -100, 100);
+		_gamepadAimAxisX = CLIP<int16>((int16)(_gamepadAimAxisX + deltaX), -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+		_gamepadAimAxisY = CLIP<int16>((int16)(_gamepadAimAxisY + deltaY), -kRA1Op0BVerticalAxisMax, kRA1Op0BVerticalAxisMax);
 		_gamepadAimActive = true;
 	}
 
@@ -926,8 +923,7 @@ bool InsaneRebel1::updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *
 
 	if (usedJoystick)
 		*usedJoystick = true;
-	_activeInputSource = kInputSourceJoystickRelative;
-	_mouseVirtualValid = false;
+	_activeInputSource = kInputSourceJoystickReticle;
 	inputX = _gamepadAimAxisX;
 	inputY = _gamepadAimAxisY;
 	return true;
@@ -937,11 +933,10 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 	if (usedJoystick)
 		*usedJoystick = false;
 
-	if (_mouseRecentering)
+	if (updateGamepadReticleAim(inputX, inputY, usedJoystick))
 		return;
 
-	if (updateRelativeGamepadAim(inputX, inputY, usedJoystick))
-		return;
+	const bool directFlightInput = getEffectiveGameOpcode() == 0x07;
 
 	const int16 analogAxisX = applyRebel1AnalogDeadzone(_joystickAxisX);
 	const int16 analogAxisY = applyRebel1AnalogDeadzone(_joystickAxisY);
@@ -958,14 +953,12 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		if (usedJoystick)
 			*usedJoystick = true;
 
-		const bool enhancedFlightInput = _optEnhancedControls && getEffectiveGameOpcode() == 0x07;
-		inputX = joyX * (enhancedFlightInput ? kRA1EnhancedFlightDirectMaxX : 127);
-		inputY = joyY * (enhancedFlightInput ? kRA1EnhancedFlightDirectMaxY : 127);
+		inputX = joyX * kRA1ControlPadAxisStep;
+		inputY = joyY * kRA1ControlPadAxisStep;
 
 		if (_optControlsYFlip)
 			inputY = -inputY;
 
-		_mouseVirtualValid = false;
 		return;
 	}
 
@@ -974,9 +967,8 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 			*usedJoystick = true;
 
 		if (analogAxisX != 0 || analogAxisY != 0) {
-			const bool enhancedFlightInput = _optEnhancedControls && getEffectiveGameOpcode() == 0x07;
-			const int axisMaxX = enhancedFlightInput ? kRA1EnhancedFlightDirectMaxX : 127;
-			const int axisMaxY = enhancedFlightInput ? kRA1EnhancedFlightDirectMaxY : 127;
+			const int axisMaxX = directFlightInput ? kRA1EnhancedFlightDirectMaxX : kRA1CenteredAxisMax;
+			const int axisMaxY = directFlightInput ? kRA1EnhancedFlightDirectMaxY : kRA1CenteredAxisMax;
 			inputX = CLIP<int32>(((int32)analogAxisX * axisMaxX) / Common::JOYAXIS_MAX, -axisMaxX, axisMaxX);
 			inputY = CLIP<int32>(((int32)analogAxisY * axisMaxY) / Common::JOYAXIS_MAX, -axisMaxY, axisMaxY);
 		} else {
@@ -987,7 +979,6 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		if (_optControlsYFlip)
 			inputY = -inputY;
 
-		_mouseVirtualValid = false;
 		return;
 	}
 
@@ -1001,156 +992,26 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		if (_optControlsYFlip)
 			inputY = -inputY;
 
-		_mouseVirtualValid = false;
 		return;
 	}
 
 	int16 logicalX = (int16)CLIP<int>(_vm->_mouse.x, 0, 319);
 	int16 logicalY = (int16)CLIP<int>(_vm->_mouse.y, 0, 199);
 
-	// Touchscreens cannot support the DOS recenter/warp model, so use the
-	// non-warping absolute axis path even when original input style is selected.
-	if (_optEnhancedControls || isTouchscreenActive()) {
-		_mouseVirtualValid = false;
-		_mouseBiasLatch = false;
-		_mouseBiasX = 0;
-		_mouseBiasY = 0;
-		_mousePrevBiasX = 0;
-		_mousePrevBiasY = 0;
-
-		if (getEffectiveGameOpcode() == 0x07) {
-			// Direct flight input lacks the DOS recenter path's offset decay, so keep
-			// held-edge steering below the raw DOS full-deflection bias.
-			inputX = scaleRebel1CenteredMouseAxis(logicalX, kRA1CenterX, kRA1EnhancedFlightDirectMaxX);
-			inputY = scaleRebel1CenteredMouseAxis(logicalY, kRA1CenterY, kRA1EnhancedFlightDirectMaxY);
-		} else {
-			inputX = (int16)CLIP<int32>(((int32)(logicalX - kRA1CenterX) * 127) / kRA1CenterX, -127, 127);
-			inputY = (int16)CLIP<int32>(((int32)(logicalY - kRA1CenterY) * 127) / kRA1CenterY, -127, 127);
-		}
-
-		// These handlers negate DAT_756E internally, so direct touch needs the
-		// opposite baseline while the menu option still toggles the result.
-		bool flipY = _optControlsYFlip;
-		if (shouldInvertTouchYSettingForCurrentLevel())
-			flipY = !flipY;
-		if (flipY)
-			inputY = -inputY;
-
-		return;
-	}
-
-	int16 rawX = (int16)(logicalX << 1);
-	int16 rawY = logicalY;
-
-	if (!_mouseVirtualValid) {
-		_mouseVirtualRawX = rawX;
-		_mouseVirtualRawY = rawY;
-		_mouseVirtualValid = true;
+	if (directFlightInput) {
+		inputX = scaleRebel1CenteredMouseAxis(logicalX, kRA1CenterX, kRA1EnhancedFlightDirectMaxX);
+		inputY = scaleRebel1CenteredMouseAxis(logicalY, kRA1CenterY, kRA1EnhancedFlightDirectMaxY);
 	} else {
-		_mouseVirtualRawX = (int16)CLIP<int>(
-			_mouseVirtualRawX + ((logicalX - _mouseVirtualPrevLogicalX) << 1),
-			-32768, 32767);
-		_mouseVirtualRawY = (int16)CLIP<int>(
-			_mouseVirtualRawY + (logicalY - _mouseVirtualPrevLogicalY),
-			-32768, 32767);
-	}
-	_mouseVirtualPrevLogicalX = logicalX;
-	_mouseVirtualPrevLogicalY = logicalY;
-
-	rawX = _mouseVirtualRawX;
-	rawY = _mouseVirtualRawY;
-
-	if (rawX < kRA1DosMouseSafeLeft || rawX > kRA1DosMouseSafeRight ||
-		rawY < kRA1DosMouseSafeTop || rawY > kRA1DosMouseSafeBottom) {
-		_mouseOffsetX = (int16)CLIP<int>(
-			(int)_mouseOffsetX + rawX - kRA1DosMouseCenterX, -32768, 32767);
-		_mouseOffsetY = (int16)CLIP<int>(
-			(int)_mouseOffsetY + rawY - kRA1DosMouseCenterY, -32768, 32767);
-		rawX = kRA1DosMouseCenterX;
-		rawY = kRA1DosMouseCenterY;
-		_mouseVirtualRawX = rawX;
-		_mouseVirtualRawY = rawY;
-		_mouseVirtualPrevLogicalX = kRA1CenterX;
-		_mouseVirtualPrevLogicalY = kRA1CenterY;
-		warpGameplayMouseNow(kRA1CenterX, kRA1CenterY);
-		debug(2, "RA1 original input virtual recenter: offset=(%d,%d) mouse=(%d,%d)",
-			_mouseOffsetX, _mouseOffsetY, logicalX, logicalY);
-	}
-
-	int16 biasX = (int16)((rawX + _mouseOffsetX - kRA1DosMouseCenterX) >> 2);
-	int16 biasY = (int16)((rawY + _mouseOffsetY - kRA1DosMouseCenterY) >> 1);
-
-	if (biasY < 0x65) {
-		const bool largeJump =
-			(_mousePrevBiasX + 0x14 < biasX) ||
-			(_mousePrevBiasY + 0x14 < biasY) ||
-			(biasX < _mousePrevBiasX - 0x14) ||
-			(biasY < _mousePrevBiasY - 0x14);
-		if (largeJump) {
-			if (!_mouseBiasLatch) {
-				biasX = _mousePrevBiasX;
-				biasY = _mousePrevBiasY;
-				_mouseBiasLatch = true;
-			}
-		} else {
-			_mouseBiasLatch = false;
-		}
-	} else {
-		biasX = _mousePrevBiasX;
-		biasY = _mousePrevBiasY;
-		_mouseBiasLatch = true;
-	}
-
-	_mouseBiasX = biasX;
-	_mouseBiasY = biasY;
-	_mousePrevBiasX = biasX;
-	_mousePrevBiasY = biasY;
-
-	int accumX = rawX + _mouseOffsetX;
-	if (accumX < 0xC0)
-		_mouseOffsetX = (int16)(0xC0 - rawX);
-	else if (accumX > 0x1C0)
-		_mouseOffsetX = (int16)(0x1C0 - rawX);
-
-	int accumY = rawY + _mouseOffsetY;
-	if (accumY < -0x1C)
-		_mouseOffsetY = (int16)(-0x1C - rawY);
-	else if (accumY > 0xE4)
-		_mouseOffsetY = (int16)(0xE4 - rawY);
-
-	accumX = rawX + _mouseOffsetX;
-	if (accumX < 0x145) {
-		if (accumX < 0x142) {
-			if (accumX < 0x13C)
-				_mouseOffsetX += 4;
-			else if (accumX < 0x13F)
-				_mouseOffsetX += 1;
-		} else {
-			_mouseOffsetX -= 1;
-		}
-	} else {
-		_mouseOffsetX -= 4;
+		inputX = (int16)CLIP<int32>(((int32)(logicalX - kRA1CenterX) * kRA1CenteredAxisMax) / kRA1CenterX,
+			-kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+		inputY = (int16)CLIP<int32>(((int32)(logicalY - kRA1CenterY) * kRA1CenteredAxisMax) / kRA1CenterY,
+			-kRA1CenteredAxisMax, kRA1CenteredAxisMax);
 	}
 
-	accumY = rawY + _mouseOffsetY;
-	if (accumY < 0x69) {
-		if (accumY < 0x66) {
-			if (accumY < 0x60)
-				_mouseOffsetY += 4;
-			else if (accumY < 99)
-				_mouseOffsetY += 1;
-		} else {
-			_mouseOffsetY -= 1;
-		}
-	} else {
-		_mouseOffsetY -= 4;
-	}
-
-	inputX = CLIP<int16>(biasX, -0xA0, 0xA0);
-	inputY = CLIP<int16>(biasY, -127, 127);
-
-	// Controls Y-flip option (DAT_22be in original)
-	if (_optControlsYFlip)
+	bool flipY = _optControlsYFlip;
+	if (shouldInvertTouchYSettingForCurrentLevel())
+		flipY = !flipY;
+	if (flipY)
 		inputY = -inputY;
 }
 
@@ -1194,8 +1055,8 @@ void InsaneRebel1::updateShipPhysics() {
 	preprocessMouseAxes(inputX, inputY, &usedJoystick);
 	const int16 rawInputX = inputX;
 	const int16 rawInputY = inputY;
-	inputX = CLIP<int16>(inputX, -127, 127);
-	inputY = CLIP<int16>(inputY, -127, 127);
+	inputX = CLIP<int16>(inputX, -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+	inputY = CLIP<int16>(inputY, -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
 	const char *inputSourceName = "mouse";
 	if (_activeInputSource == kInputSourceJoystickAnalog)
 		inputSourceName = "joystick-analog";
@@ -1214,8 +1075,7 @@ void InsaneRebel1::updateShipPhysics() {
 
 	// --- Step 4: Position accumulator deltas ---
 	// X delta: drift + slide coupling - cross-coupling
-	const bool originalTurbulence = !_optEnhancedControls;
-	int32 rng = originalTurbulence ? (int32)_vm->_rnd.getRandomNumber(199) : 100;  // RandScaleByte(200), centered at 100
+	int32 rng = 100;  // RandScaleByte(200), centered at 100
 	int32 crossTermX;
 	if (_liftSmooth < 0)
 		crossTermX = ((int32)_tuning.lift * _liftSmooth * _rollAccum) >> 11;
@@ -1293,7 +1153,7 @@ void InsaneRebel1::updateShipPhysics() {
 
 	debugC(DEBUG_INSANE, "RA1 ship input: frame=%d source=%s controls=%s turbulence=%d usedJoystick=%d raw=(%d,%d) clipped=(%d,%d) storedAxis=(%d,%d) actionState(L,R,U,D)=(%d,%d,%d,%d) roll=%d lift=%d pos=(%d,%d) view=(%d,%d) dir=%d level=%d mode=%d opcode=0x%X",
 		_gameCounter, inputSourceName,
-		_optEnhancedControls ? "enhanced" : "original", originalTurbulence, usedJoystick,
+		"enhanced", 0, usedJoystick,
 		rawInputX, rawInputY, inputX, inputY,
 		_joystickAxisX, _joystickAxisY,
 		_vm->getActionState(kScummActionInsaneLeft),
@@ -1521,12 +1381,12 @@ void InsaneRebel1::updateTurretPhysics() {
 		int16 inputY = 0;
 		bool usedJoystick = false;
 		preprocessMouseAxes(inputX, inputY, &usedJoystick);
-		inputX = CLIP<int16>(inputX, -127, 127);
-		inputY = CLIP<int16>(inputY, -127, 127);
+		inputX = CLIP<int16>(inputX, -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
+		inputY = CLIP<int16>(inputY, -kRA1CenteredAxisMax, kRA1CenteredAxisMax);
 		const int16 rawInputX = inputX;
 		const int16 rawInputY = inputY;
 
-		if (usedJoystick && _optEnhancedControls && _flyControlMode == 2) {
+		if (usedJoystick && _flyControlMode == 2) {
 			// ScummVM-only concession for Level 1 part 2. The original 0x08 handler
 			// uses raw axes directly; do not damp Level 13's surface controls.
 			inputX /= 2;
@@ -1535,7 +1395,7 @@ void InsaneRebel1::updateTurretPhysics() {
 
 		debugC(DEBUG_INSANE, "RA1 turret input: source=%s controls=%s mouse=(%d,%d) actions(L,R,U,D)=(%d,%d,%d,%d) raw=(%d,%d) final=(%d,%d) level=%d mode=%d opcode=0x%X",
 			usedJoystick ? "joystick-actions" : "mouse-path",
-			_optEnhancedControls ? "enhanced" : "original",
+			"enhanced",
 			_vm->_mouse.x, _vm->_mouse.y,
 			_vm->getActionState(kScummActionInsaneLeft),
 			_vm->getActionState(kScummActionInsaneRight),
@@ -1627,9 +1487,9 @@ void InsaneRebel1::updateScreenFlashPalette() {
 // Ship position = averaged input + center offset.
 // Viewport = second history buffer for smooth camera scrolling.
 void InsaneRebel1::updateGameOp0BPhysics() {
-	// Original FUN_1CDA7 uses the full 10-sample history. Enhanced controls keep
-	// the same pipeline but average fewer samples for responsiveness.
-	const int gameOp0BSmoothWindow = _optEnhancedControls ? 2 : kInputHistorySize;
+	// Enhanced controls keep the original 0x0B pipeline but average fewer
+	// samples for responsiveness.
+	const int gameOp0BSmoothWindow = 2;
 
 	// RA1 FUN_1B297-style per-frame latches for 0x0B sections:
 	//   0x5D latch 0xFFFF -> bit 0x40 (scripted obstacle/contact)
@@ -1752,7 +1612,7 @@ void InsaneRebel1::updateGameOp0BPhysics() {
 	bool usedJoystick = false;
 	preprocessMouseAxes(inputX, inputY, &usedJoystick);
 	inputX = CLIP<int16>(inputX, -0xA0, 0xA0);
-	inputY = CLIP<int16>(inputY, -100, 100);
+	inputY = CLIP<int16>(inputY, -kRA1Op0BVerticalAxisMax, kRA1Op0BVerticalAxisMax);
 	const int16 rawInputX = inputX;
 	const int16 rawInputY = inputY;
 	const bool op0BAnalogSmoothing = (_activeInputSource == kInputSourceJoystickAnalog);
@@ -1762,25 +1622,25 @@ void InsaneRebel1::updateGameOp0BPhysics() {
 		inputSourceName = "joystick-analog";
 	else if (_activeInputSource == kInputSourceJoystickDigital)
 		inputSourceName = "joystick-dpad";
-	else if (_activeInputSource == kInputSourceJoystickRelative)
-		inputSourceName = "joystick-relative";
+	else if (_activeInputSource == kInputSourceJoystickReticle)
+		inputSourceName = "joystick-reticle";
 
-	const bool relativeGamepadReticle = usedJoystick && _activeInputSource == kInputSourceJoystickRelative;
-	const bool preciseGamepadReticle = usedJoystick && _optEnhancedControls &&
-		isOp0BReticleControlLevel() && !relativeGamepadReticle;
+	const bool relativeGamepadReticle = usedJoystick && _activeInputSource == kInputSourceJoystickReticle;
+	const bool preciseGamepadReticle = usedJoystick && isOp0BReticleControlLevel() &&
+		!relativeGamepadReticle;
 
-	if (usedJoystick && _optEnhancedControls && !relativeGamepadReticle) {
+	if (usedJoystick && !relativeGamepadReticle) {
 		// The 0x0B first-person handler is shared by multiple RA1 stages. Smooth
 		// analog stick input over time and shape the affected gamepad levels with
 		// a low-gain linear center plus an accelerating outer range.
 		if (op0BAnalogSmoothing) {
 			if (preciseGamepadReticle) {
-				inputX = shapeRebel1Op0BGamepadAxis(inputX, 127);
-				inputY = shapeRebel1Op0BGamepadAxis(inputY, 100);
+				inputX = shapeRebel1Op0BGamepadAxis(inputX, kRA1CenteredAxisMax);
+				inputY = shapeRebel1Op0BGamepadAxis(inputY, kRA1Op0BVerticalAxisMax);
 			}
 			const int analogRampDivisor = preciseGamepadReticle ? 20 : 10;
-			inputX = smoothRebel1Op0BAnalogInput(inputX, _level2JoystickFilteredX, 127, analogRampDivisor);
-			inputY = smoothRebel1Op0BAnalogInput(inputY, _level2JoystickFilteredY, 100, analogRampDivisor);
+			inputX = smoothRebel1Op0BAnalogInput(inputX, _level2JoystickFilteredX, kRA1CenteredAxisMax, analogRampDivisor);
+			inputY = smoothRebel1Op0BAnalogInput(inputY, _level2JoystickFilteredY, kRA1Op0BVerticalAxisMax, analogRampDivisor);
 		} else {
 			_level2JoystickFilteredX = 0;
 			_level2JoystickFilteredY = 0;
@@ -1796,7 +1656,7 @@ void InsaneRebel1::updateGameOp0BPhysics() {
 	debugC(DEBUG_INSANE, "RA1 GAME 0x0B input: frame=%d source=%s controls=%s window=%d precisionPad=%d view=(%d,%d) health=%d prevFlags=0x%02x axis=(%d,%d) mouse=(%d,%d) actions(L,R,U,D)=(%d,%d,%d,%d) raw=(%d,%d) final=(%d,%d) level=%d opcode=0x%X",
 		_gameCounter,
 		inputSourceName,
-		_optEnhancedControls ? "enhanced" : "original",
+		"enhanced",
 		gameOp0BSmoothWindow,
 		preciseGamepadReticle ? 1 : 0,
 		_perspectiveX, _perspectiveY,
@@ -2149,22 +2009,9 @@ void InsaneRebel1::handleGameOpcode5EReset(uint32 param1) {
 	_inputAxisDeltaX = 0;
 	_avgInputX = 0;
 	_avgInputY = 0;
-	_mouseOffsetX = 0;
-	_mouseOffsetY = 0;
-	_mouseBiasX = 0;
-	_mouseBiasY = 0;
-	_mousePrevBiasX = 0;
-	_mousePrevBiasY = 0;
-	_mouseBiasLatch = false;
-	_mouseRecentering = false;
-	_mouseVirtualRawX = kRA1DosMouseCenterX;
-	_mouseVirtualRawY = kRA1DosMouseCenterY;
-	_mouseVirtualPrevLogicalX = kRA1CenterX;
-	_mouseVirtualPrevLogicalY = kRA1CenterY;
-	_mouseVirtualValid = false;
 	_level2JoystickFilteredX = 0;
 	_level2JoystickFilteredY = 0;
-	resetRelativeGamepadAim();
+	resetGamepadReticleAim();
 
 	_playerFired = false;
 	_fireCooldown = 0;
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 9b7f374073e..02be2e39935 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -469,11 +469,11 @@ bool InsaneRebel1::handleMenuCommand(RA1MenuCommand command) {
 			_optionsSel = (_optionsSel + 1) % kOptionsItemCount;
 			return true;
 		case kRA1MenuCommandLeft:
-			if (_optionsSel == 7)
+			if (_optionsSel == 6)
 				setRebel1Volume(_vm, _optVolume, -5);
 			return true;
 		case kRA1MenuCommandRight:
-			if (_optionsSel == 7)
+			if (_optionsSel == 6)
 				setRebel1Volume(_vm, _optVolume, 5);
 			return true;
 		case kRA1MenuCommandCancel:
@@ -674,8 +674,8 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
 		_gameplayMouseSettleUntil = 0;
 	}
 
-	if (event.type == Common::EVENT_MOUSEMOVE && !_mouseRecentering) {
-		if (_gamepadAimActive && usesRelativeGamepadAimForCurrentLevel() &&
+	if (event.type == Common::EVENT_MOUSEMOVE) {
+		if (_gamepadAimActive && usesGamepadReticleAimForCurrentFrame() &&
 				_interactiveVideoActive && !_menuActive &&
 				(event.relMouse.x != 0 || event.relMouse.y != 0))
 			_gamepadAimActive = false;
@@ -685,7 +685,7 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
 	// Android direct touch reports taps as left-clicks. Treat those as mouse input
 	// during gameplay so tap-to-aim-and-fire works even if a joystick event was last.
 	if (isTouchscreenActive() && _interactiveVideoActive && !_menuActive &&
-			event.type == Common::EVENT_LBUTTONDOWN && !_mouseRecentering)
+			event.type == Common::EVENT_LBUTTONDOWN)
 		_activeInputSource = kInputSourceMouse;
 
 	// ScummVM-exclusive feature: mouse navigation/clicking of the RA1 front-end menus.
@@ -1009,8 +1009,7 @@ void InsaneRebel1::renderOptionsOverlay(byte *dst, int pitch, int width, int hei
 		_optRookieOneFemale ? "ROOKIE1 IS FEMALE" : "ROOKIE1 IS MALE",
 		_optMusicEnabled  ? "MUSIC IS ON"             : "MUSIC IS OFF",
 		_optSfxEnabled    ? "SFX AND VOICE ARE ON"    : "SFX AND VOICE ARE OFF",
-		_optTextEnabled   ? "DIALOGUE TEXT IS ON"      : "DIALOGUE TEXT IS OFF",
-		_optEnhancedControls ? "INPUT STYLE ENHANCED" : "INPUT STYLE ORIGINAL",
+		_optTextEnabled   ? "DIALOGUE TEXT IS ON"     : "DIALOGUE TEXT IS OFF",
 		_optControlsYFlip ? "Y AXIS IS INVERTED"      : "Y AXIS IS NORMAL",
 		volLine,
 		diffLine
@@ -1302,15 +1301,12 @@ void InsaneRebel1::runOptionsMenu() {
 				_optTextEnabled = !ConfMan.getBool("subtitles");
 				ConfMan.setBool("subtitles", _optTextEnabled);
 				break;
-			case 5: // Toggle enhanced/original input style
-				_optEnhancedControls = !_optEnhancedControls;
-				break;
-			case 6: // Toggle Y-flip controls
+			case 5: // Toggle Y-flip controls
 				_optControlsYFlip = !_optControlsYFlip;
 				break;
-			case 7: // Volume — adjusted via left/right in notifyEvent
+			case 6: // Volume — adjusted via left/right in notifyEvent
 				break;
-			case 8: // Cycle difficulty
+			case 7: // Cycle difficulty
 				_difficulty = (_difficulty + 1) % 3;
 				loadTuningForLevel(0);
 				break;
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 004840569e1..034d8cb2bfc 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -258,19 +258,6 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	_inputAxisDeltaX = 0;
 	_avgInputX = 0;
 	_avgInputY = 0;
-	_mouseOffsetX = 0;
-	_mouseOffsetY = 0;
-	_mouseBiasX = 0;
-	_mouseBiasY = 0;
-	_mousePrevBiasX = 0;
-	_mousePrevBiasY = 0;
-	_mouseBiasLatch = false;
-	_mouseRecentering = false;
-	_mouseVirtualRawX = 0x140;
-	_mouseVirtualRawY = 100;
-	_mouseVirtualPrevLogicalX = kRA1CenterX;
-	_mouseVirtualPrevLogicalY = kRA1CenterY;
-	_mouseVirtualValid = false;
 	_joystickAxisX = 0;
 	_joystickAxisY = 0;
 	_lastJoystickAxisEventTime = 0;
@@ -365,7 +352,6 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	// game and the in-game DIALOGUE TEXT menu label reflect it. The menu toggle writes the
 	// same "subtitles" key, and ra1HandleText() gates rendering on it.
 	_optTextEnabled = ConfMan.getBool("subtitles");
-	_optEnhancedControls = true;
 	_optControlsYFlip = false;
 	_optVolume = _vm->_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) * 127 / Audio::Mixer::kMaxChannelVolume;
 
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 6622e884873..4d3675ee358 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -227,9 +227,9 @@ private:
 	void getCollisionShipCenter(int16 &x, int16 &y) const;
 	bool isOp0BReticleControlLevel() const;
 	bool shouldInvertTouchYSettingForCurrentLevel() const;
-	bool usesRelativeGamepadAimForCurrentLevel() const;
-	void resetRelativeGamepadAim();
-	bool updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *usedJoystick);
+	bool usesGamepadReticleAimForCurrentFrame() const;
+	void resetGamepadReticleAim();
+	bool updateGamepadReticleAim(int16 &inputX, int16 &inputY, bool *usedJoystick);
 	void preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJoystick = nullptr);
 	void rebuildProjectionTable(int16 curveStep, int16 curveExtent);
 	void resetProjectionTable();
@@ -357,19 +357,6 @@ private:
 	int16 _inputAxisDeltaX; // Current 0x0B horizontal input sample, before history averaging
 	int16 _avgInputX;    // smoothed horizontal input (clamped to [-0xA0, 0xA0])
 	int16 _avgInputY;    // smoothed vertical input (clamped to [-0x46, 0x41])
-	int16 _mouseOffsetX; // 0x9762-style accumulated recenter offset in DOS 640-space
-	int16 _mouseOffsetY; // 0x9760-style accumulated recenter offset in DOS 200-space
-	int16 _mouseBiasX;   // 0x9774: current preprocessed horizontal bias
-	int16 _mouseBiasY;   // 0x9772: current preprocessed vertical bias
-	int16 _mousePrevBiasX; // 0x9770: previous-frame biasX
-	int16 _mousePrevBiasY; // 0x976E: previous-frame biasY
-	bool _mouseBiasLatch;  // 0x4486: one-frame large-jump latch
-	bool _mouseRecentering; // 0x976D: suppress recursive updates during warp
-	int16 _mouseVirtualRawX; // Virtual DOS mouse X used by original-input recentering
-	int16 _mouseVirtualRawY; // Virtual DOS mouse Y used by original-input recentering
-	int16 _mouseVirtualPrevLogicalX;
-	int16 _mouseVirtualPrevLogicalY;
-	bool _mouseVirtualValid;
 	int16 _joystickAxisX;   // Rebel-specific left-stick X captured from keymapper axis events
 	int16 _joystickAxisY;   // Rebel-specific left-stick Y captured from keymapper axis events
 	uint32 _lastJoystickAxisEventTime;
@@ -384,7 +371,7 @@ private:
 		kInputSourceMouse,
 		kInputSourceJoystickAnalog,
 		kInputSourceJoystickDigital,
-		kInputSourceJoystickRelative
+		kInputSourceJoystickReticle
 	};
 	InputSource _activeInputSource;
 
@@ -581,9 +568,9 @@ private:
 	int _menuFrameCounter;
 
 	// Options submenu state — RunGameOptionsMenu (0x14B42)
-	static const int kOptionsItemCount = 9;
+	static const int kOptionsItemCount = 8;
 	bool _optionsActive;     // True when showing options instead of main menu
-	int _optionsSel;         // 0..8 selected option row
+	int _optionsSel;         // 0..7 selected option row
 	bool _levelSelectActive; // True when showing level-select submenu
 	int _levelSelectSel;     // 0=Level1 ... N-1=Back
 	int _startLevel;         // 1-based start level for "Start New Game"
@@ -593,7 +580,6 @@ private:
 	bool _optMusicEnabled;    // DAT_22b7: music on/off
 	bool _optSfxEnabled;      // DAT_22b8: sfx+voice on/off
 	bool _optTextEnabled;     // DAT_22b9: dialogue text on/off
-	bool _optEnhancedControls; // ScummVM option: current responsive controls vs original control law
 	bool _optControlsYFlip;   // DAT_22be: Y-axis inversion
 	int  _optVolume;          // DAT_22c1: master volume 0..127
 
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index cb6dd67e766..2bd976587ad 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -248,7 +248,7 @@ void InsaneRebel1::resetLevelInputHistory(bool resetAxisDeltaX) {
 		_inputAxisDeltaX = 0;
 	_avgInputX = 0;
 	_avgInputY = 0;
-	resetRelativeGamepadAim();
+	resetGamepadReticleAim();
 }
 
 void InsaneRebel1::resetLevelAttemptState(int16 flyControlMode, int16 gameplayPhase,
@@ -1702,7 +1702,7 @@ void InsaneRebel1::setupInteractiveVideoState(int32 startFrame) {
 	if (!preserveRuntimeState) {
 		_onFootInitialized = false;  // Reset so each segment triggers counter==0 init
 		resetFrameObjectState();
-		resetRelativeGamepadAim();
+		resetGamepadReticleAim();
 	}
 	_vm->_smushVideoShouldFinish = false;
 	// Route resumes stay in the same gameplay flow in the original executable.
@@ -1781,11 +1781,6 @@ void InsaneRebel1::captureInteractiveVideoInput() {
 			warpGameplayMouseNow(kRA1CenterX, kRA1CenterY);
 			_gameplayMouseSettleUntil = _vm->_system->getMillis() + kRA1GameplayMouseSettleMs;
 		}
-		_mouseVirtualRawX = 0x140;
-		_mouseVirtualRawY = 100;
-		_mouseVirtualPrevLogicalX = kRA1CenterX;
-		_mouseVirtualPrevLogicalY = kRA1CenterY;
-		_mouseVirtualValid = false;
 	} else {
 		_gameplayMouseSettleUntil = 0;
 	}


Commit: 9bbfdda5adc030de46ed381ecb331aceda288f77
    https://github.com/scummvm/scummvm/commit/9bbfdda5adc030de46ed381ecb331aceda288f77
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T10:04:04+02:00

Commit Message:
SCUMM: RA1: added rapid fire following 3do controls

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


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 2a2501402e6..f4c68f3f53d 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -2015,6 +2015,7 @@ void InsaneRebel1::handleGameOpcode5EReset(uint32 param1) {
 
 	_playerFired = false;
 	_fireCooldown = 0;
+	_rapidFirePhase = 0;
 	memset(_shotSlots, 0, sizeof(_shotSlots));
 	_shotAlternator = 0;
 	_shotSideToggle = false;
@@ -2373,9 +2374,22 @@ void InsaneRebel1::handleGameChunk(int32 subSize, Common::SeekableReadStream &b,
 // processShot — FUN_1CCA0 (0x1CCA0). Spawns shot into explosion slot when fired.
 // Called once per frame during interactive rendering.
 void InsaneRebel1::processShot() {
-	if (!_playerFired || _fireCooldown != 0)
+	if (_optRapidFire) {
+		// 3DO FUN_0000c3a4 advances this before testing fire state; a fresh press
+		// fires immediately, while held repeats are gated to phase 0.
+		_rapidFirePhase++;
+		if (_rapidFirePhase > 2)
+			_rapidFirePhase = 0;
+	}
+
+	if (!_playerFired)
 		return;
 
+	if (_fireCooldown != 0) {
+		if (!_optRapidFire || _rapidFirePhase != 0)
+			return;
+	}
+
 	// On-foot mode: only spawn when in aiming stance (dirIndex 11-19) or flags force it.
 	// Original: if (((10 < g_shipDirIndex) && (g_shipDirIndex < 0x14)) || ((DAT_000075fe & 8) != 0))
 	const uint16 effectiveOpcode = getEffectiveGameOpcode();
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 02be2e39935..a6ac4ebd4bc 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -469,11 +469,11 @@ bool InsaneRebel1::handleMenuCommand(RA1MenuCommand command) {
 			_optionsSel = (_optionsSel + 1) % kOptionsItemCount;
 			return true;
 		case kRA1MenuCommandLeft:
-			if (_optionsSel == 6)
+			if (_optionsSel == 7)
 				setRebel1Volume(_vm, _optVolume, -5);
 			return true;
 		case kRA1MenuCommandRight:
-			if (_optionsSel == 6)
+			if (_optionsSel == 7)
 				setRebel1Volume(_vm, _optVolume, 5);
 			return true;
 		case kRA1MenuCommandCancel:
@@ -1011,6 +1011,7 @@ void InsaneRebel1::renderOptionsOverlay(byte *dst, int pitch, int width, int hei
 		_optSfxEnabled    ? "SFX AND VOICE ARE ON"    : "SFX AND VOICE ARE OFF",
 		_optTextEnabled   ? "DIALOGUE TEXT IS ON"     : "DIALOGUE TEXT IS OFF",
 		_optControlsYFlip ? "Y AXIS IS INVERTED"      : "Y AXIS IS NORMAL",
+		_optRapidFire     ? "RAPID FIRE IS ON"        : "RAPID FIRE IS OFF",
 		volLine,
 		diffLine
 	};
@@ -1304,9 +1305,12 @@ void InsaneRebel1::runOptionsMenu() {
 			case 5: // Toggle Y-flip controls
 				_optControlsYFlip = !_optControlsYFlip;
 				break;
-			case 6: // Volume — adjusted via left/right in notifyEvent
+			case 6: // Toggle held-fire shooting
+				_optRapidFire = !_optRapidFire;
 				break;
-			case 7: // Cycle difficulty
+			case 7: // Volume — adjusted via left/right in notifyEvent
+				break;
+			case 8: // Cycle difficulty
 				_difficulty = (_difficulty + 1) % 3;
 				loadTuningForLevel(0);
 				break;
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 034d8cb2bfc..eb41ddadbe6 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -353,6 +353,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	// same "subtitles" key, and ra1HandleText() gates rendering on it.
 	_optTextEnabled = ConfMan.getBool("subtitles");
 	_optControlsYFlip = false;
+	_optRapidFire = true;
 	_optVolume = _vm->_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) * 127 / Audio::Mixer::kMaxChannelVolume;
 
 	// Default high scores — from DS:0x1D0/0x298/0x2C0
@@ -382,6 +383,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	// Shooting/targeting state
 	_playerFired = false;
 	_fireCooldown = 0;
+	_rapidFirePhase = 0;
 	_gameplayFlags75fe = 0;
 	_gameplayFlags75ff = 0;
 	memset(_shotSlots, 0, sizeof(_shotSlots));
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 4d3675ee358..6a0ad752c99 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -568,9 +568,9 @@ private:
 	int _menuFrameCounter;
 
 	// Options submenu state — RunGameOptionsMenu (0x14B42)
-	static const int kOptionsItemCount = 8;
+	static const int kOptionsItemCount = 9;
 	bool _optionsActive;     // True when showing options instead of main menu
-	int _optionsSel;         // 0..7 selected option row
+	int _optionsSel;         // 0..8 selected option row
 	bool _levelSelectActive; // True when showing level-select submenu
 	int _levelSelectSel;     // 0=Level1 ... N-1=Back
 	int _startLevel;         // 1-based start level for "Start New Game"
@@ -581,6 +581,7 @@ private:
 	bool _optSfxEnabled;      // DAT_22b8: sfx+voice on/off
 	bool _optTextEnabled;     // DAT_22b9: dialogue text on/off
 	bool _optControlsYFlip;   // DAT_22be: Y-axis inversion
+	bool _optRapidFire;       // ScummVM option: held fire keeps shooting
 	int  _optVolume;          // DAT_22c1: master volume 0..127
 
 	// High scores / TOP PILOTS display — data at DS:0x1D0
@@ -616,7 +617,8 @@ private:
 
 	// Shooting state — FUN_1CCA0 (0x1CCA0)
 	bool _playerFired;       // 0x7570: current fire-button state
-	int16 _fireCooldown;     // 0x757C: previous-frame fire-button state (edge gate)
+	int16 _fireCooldown;     // 0x757C: previous-frame fire-button state (edge gate when rapid fire is off)
+	int16 _rapidFirePhase;   // 3DO FUN_0000c3a4: held-fire modulo-3 shot gate
 	uint16 _gameplayFlags75fe; // 0x75FE: gameplay mode flags
 	uint16 _gameplayFlags75ff; // 0x75FF: targeting / shot-style flags
 




More information about the Scummvm-git-logs mailing list