[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