[Scummvm-git-logs] scummvm master -> 63b9827058128e9fc2990ceca8b30dbb47b7b0b5
neuromancer
noreply at scummvm.org
Thu Jun 4 12:55:14 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:
81517766f8 SCUMM: RA1: properly invert Y axis for some levels
04abb43098 SCUMM: RA1: virtual keyboard support for text inputs
63b9827058 SCUMM: RA1: better gamepad controls for some levels
Commit: 81517766f874af7248778667af06b524b1f8eff8
https://github.com/scummvm/scummvm/commit/81517766f874af7248778667af06b524b1f8eff8
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T14:54:00+02:00
Commit Message:
SCUMM: RA1: properly invert Y axis for some levels
Changed paths:
engines/scumm/insane/rebel1/iact.cpp
engines/scumm/insane/rebel1/rebel.h
diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index fb8e22f4b00..eed59ccdb22 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -807,6 +807,25 @@ void InsaneRebel1::updateFlightVariantCursor() {
// 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.
+bool InsaneRebel1::shouldInvertTouchYSettingForCurrentLevel() const {
+ if (!isTouchscreenActive())
+ return false;
+
+ switch (_currentLevel) {
+ case 1: // Level 2
+ case 3: // Level 4
+ case 7: // Level 8
+ case 8: // Level 9
+ case 9: // Level 10
+ case 11: // Level 12
+ case 13: // Level 14
+ case 14: // Level 15
+ return true;
+ default:
+ return false;
+ }
+}
+
void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJoystick) {
if (usedJoystick)
*usedJoystick = false;
@@ -888,7 +907,12 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
inputX = (int16)CLIP<int32>(((int32)(logicalX - kRA1CenterX) * 127) / kRA1CenterX, -127, 127);
inputY = (int16)CLIP<int32>(((int32)(logicalY - kRA1CenterY) * 127) / kRA1CenterY, -127, 127);
- if (_optControlsYFlip)
+ // 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;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 6081ec18aae..e08e41245a8 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -221,6 +221,7 @@ private:
void updateTurretPhysics();
void updateTurretShipDirection(int16 offsetY);
void getCollisionShipCenter(int16 &x, int16 &y) const;
+ bool shouldInvertTouchYSettingForCurrentLevel() const;
void preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJoystick = nullptr);
void rebuildProjectionTable(int16 curveStep, int16 curveExtent);
void resetProjectionTable();
Commit: 04abb430982dee4a771a8281fb9f237862ae0983
https://github.com/scummvm/scummvm/commit/04abb430982dee4a771a8281fb9f237862ae0983
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T14:54:00+02:00
Commit Message:
SCUMM: RA1: virtual keyboard support for text inputs
Changed paths:
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/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index af7cb44fdaa..15d07ef18c2 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -274,6 +274,17 @@ int InsaneRebel1::getMainMenuResultForSelection(int selection) const {
return selection + 2;
}
+void InsaneRebel1::setVirtualKeyboardVisible(bool visible) {
+ if (!_vm->_system->hasFeature(OSystem::kFeatureVirtualKeyboard))
+ return;
+
+ if (_virtualKeyboardActive == visible)
+ return;
+
+ _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, visible);
+ _virtualKeyboardActive = visible;
+}
+
void InsaneRebel1::beginTextEntry(bool passcodeMode) {
_textEntryActive = true;
_textEntryPasscodeMode = passcodeMode;
@@ -292,6 +303,8 @@ void InsaneRebel1::beginTextEntry(bool passcodeMode) {
_textEntryPickerIndex = 1;
}
}
+
+ setVirtualKeyboardVisible(true);
}
void InsaneRebel1::finishTextEntry(bool canceled) {
@@ -299,6 +312,7 @@ void InsaneRebel1::finishTextEntry(bool canceled) {
if (!canceled)
_textEntryDone = true;
_textEntryActive = false;
+ setVirtualKeyboardVisible(false);
_vm->_smushVideoShouldFinish = true;
}
@@ -1134,6 +1148,7 @@ bool InsaneRebel1::runTextEntryMenuLoop() {
while (!shouldAbortGameFlow() && !_textEntryDone && !_textEntryCanceled)
playMenuBackground();
+ setVirtualKeyboardVisible(false);
return !shouldAbortGameFlow() && !_textEntryCanceled;
}
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index d4b1a7929bc..59a87b0f136 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -378,6 +378,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
_textEntryPasscodeMode = false;
_textEntryDone = false;
_textEntryCanceled = false;
+ _virtualKeyboardActive = false;
_textEntryPickerIndex = 0;
_textEntryPickerOffsetX = 0;
_textEntryMaxChars = 0;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index e08e41245a8..5264989c70c 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -549,6 +549,7 @@ private:
int getMainMenuResultForSelection(int selection) const;
void playMenuBackground();
bool runTextEntryMenuLoop();
+ void setVirtualKeyboardVisible(bool visible);
void beginTextEntry(bool passcodeMode);
void finishTextEntry(bool canceled);
void selectTextEntryChar();
@@ -599,6 +600,7 @@ private:
bool _textEntryPasscodeMode;
bool _textEntryDone;
bool _textEntryCanceled;
+ bool _virtualKeyboardActive;
int _textEntryPickerIndex;
int _textEntryPickerOffsetX;
int _textEntryMaxChars;
Commit: 63b9827058128e9fc2990ceca8b30dbb47b7b0b5
https://github.com/scummvm/scummvm/commit/63b9827058128e9fc2990ceca8b30dbb47b7b0b5
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-04T14:54:00+02:00
Commit Message:
SCUMM: RA1: better gamepad controls for some levels
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 eed59ccdb22..8baa313f60f 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -34,9 +34,10 @@ inline int16 applyRebel1AnalogDeadzone(int16 axisValue) {
return (ABS(axis) <= deadZone) ? 0 : axisValue;
}
-inline int16 smoothRebel1Op0BAnalogInput(int16 inputValue, int16 &filteredValue, int16 axisMax) {
+inline int16 smoothRebel1Op0BAnalogInput(int16 inputValue, int16 &filteredValue,
+ int16 axisMax, int responseDivisor) {
const int delta = (int)inputValue - (int)filteredValue;
- int step = delta / 10;
+ int step = delta / responseDivisor;
if (step == 0 && delta != 0)
step = (delta > 0) ? 1 : -1;
@@ -45,6 +46,29 @@ inline int16 smoothRebel1Op0BAnalogInput(int16 inputValue, int16 &filteredValue,
return filteredValue;
}
+int16 shapeRebel1Op0BGamepadAxis(int16 inputValue, int16 axisMax) {
+ const int axis = CLIP<int>(inputValue, -axisMax, axisMax);
+ const int absAxis = ABS(axis);
+ const int precisionRadius = MAX<int>(1, (axisMax * 2) / 5);
+ const int precisionOutput = MAX<int>(1, precisionRadius / 3);
+ int shaped = 0;
+
+ if (absAxis <= precisionRadius) {
+ shaped = (absAxis * precisionOutput + precisionRadius / 2) / precisionRadius;
+ } else {
+ const int outerInput = absAxis - precisionRadius;
+ const int outerInputRange = axisMax - precisionRadius;
+ const int outerOutputRange = axisMax - precisionOutput;
+ const int linear = outerInput * outerOutputRange / outerInputRange;
+ const int accel = (outerInput * outerInput * outerOutputRange +
+ (outerInputRange * outerInputRange) / 2) /
+ (outerInputRange * outerInputRange);
+ shaped = precisionOutput + (linear + 2 * accel) / 3;
+ }
+
+ return axis < 0 ? -shaped : shaped;
+}
+
const int16 kRA1Op09AimXScale[5] = { 0, 44, 88, 128, 165 };
const int16 kRA1Op09AimYScale[5] = { 256, 252, 240, 221, 196 };
const int kRA1DosMouseCenterX = 0x140;
@@ -807,10 +831,7 @@ void InsaneRebel1::updateFlightVariantCursor() {
// 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.
-bool InsaneRebel1::shouldInvertTouchYSettingForCurrentLevel() const {
- if (!isTouchscreenActive())
- return false;
-
+bool InsaneRebel1::isOp0BReticleControlLevel() const {
switch (_currentLevel) {
case 1: // Level 2
case 3: // Level 4
@@ -826,6 +847,84 @@ bool InsaneRebel1::shouldInvertTouchYSettingForCurrentLevel() const {
}
}
+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);
+}
+
+void InsaneRebel1::resetRelativeGamepadAim() {
+ _gamepadAimAxisX = 0;
+ _gamepadAimAxisY = 0;
+ _gamepadAimActive = false;
+}
+
+bool InsaneRebel1::updateRelativeGamepadAim(int16 &inputX, int16 &inputY, bool *usedJoystick) {
+ if (!usesRelativeGamepadAimForCurrentLevel())
+ return false;
+
+ const int dpadX =
+ (_vm->getActionState(kScummActionInsaneRight) ? 1 : 0) -
+ (_vm->getActionState(kScummActionInsaneLeft) ? 1 : 0);
+ int dpadY =
+ (_vm->getActionState(kScummActionInsaneUp) ? 1 : 0) -
+ (_vm->getActionState(kScummActionInsaneDown) ? 1 : 0);
+
+ 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);
+
+ if (_optControlsYFlip) {
+ dpadY = -dpadY;
+ analogY = -analogY;
+ }
+
+ int deltaX = 0;
+ int deltaY = 0;
+ bool activeGamepadAim = false;
+
+ if (dpadX || dpadY) {
+ const int kDigitalAimStep = 3;
+ deltaX = dpadX * kDigitalAimStep;
+ deltaY = dpadY * kDigitalAimStep;
+ activeGamepadAim = true;
+ } else if (analogX || analogY) {
+ const int kAnalogAimMaxStep = 8;
+ deltaX = analogX * kAnalogAimMaxStep / 127;
+ deltaY = analogY * kAnalogAimMaxStep / 100;
+ activeGamepadAim = true;
+ }
+
+ if (activeGamepadAim) {
+ if (!_gamepadAimActive) {
+ _gamepadAimAxisX = CLIP<int16>(_avgInputX, -127, 127);
+ _gamepadAimAxisY = CLIP<int16>((int16)-_avgInputY, -100, 100);
+ }
+ _gamepadAimAxisX = CLIP<int16>((int16)(_gamepadAimAxisX + deltaX), -127, 127);
+ _gamepadAimAxisY = CLIP<int16>((int16)(_gamepadAimAxisY + deltaY), -100, 100);
+ _gamepadAimActive = true;
+ }
+
+ if (!_gamepadAimActive)
+ return false;
+
+ if (usedJoystick)
+ *usedJoystick = true;
+ _activeInputSource = kInputSourceJoystickRelative;
+ _mouseVirtualValid = false;
+ inputX = _gamepadAimAxisX;
+ inputY = _gamepadAimAxisY;
+ return true;
+}
+
void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJoystick) {
if (usedJoystick)
*usedJoystick = false;
@@ -833,6 +932,9 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
if (_mouseRecentering)
return;
+ if (updateRelativeGamepadAim(inputX, inputY, usedJoystick))
+ return;
+
const int16 analogAxisX = applyRebel1AnalogDeadzone(_joystickAxisX);
const int16 analogAxisY = applyRebel1AnalogDeadzone(_joystickAxisY);
const int joyX =
@@ -1643,14 +1745,25 @@ void InsaneRebel1::updateGameOp0BPhysics() {
inputSourceName = "joystick-analog";
else if (_activeInputSource == kInputSourceJoystickDigital)
inputSourceName = "joystick-dpad";
+ else if (_activeInputSource == kInputSourceJoystickRelative)
+ inputSourceName = "joystick-relative";
- if (usedJoystick && _optEnhancedControls) {
+ const bool relativeGamepadReticle = usedJoystick && _activeInputSource == kInputSourceJoystickRelative;
+ const bool preciseGamepadReticle = usedJoystick && _optEnhancedControls &&
+ isOp0BReticleControlLevel() && !relativeGamepadReticle;
+
+ if (usedJoystick && _optEnhancedControls && !relativeGamepadReticle) {
// The 0x0B first-person handler is shared by multiple RA1 stages. Smooth
- // analog stick input over time so these sections keep full reach without
- // feeling hyper-sensitive, while leaving mouse behavior untouched.
+ // analog stick input over time and shape the affected gamepad levels with
+ // a low-gain linear center plus an accelerating outer range.
if (op0BAnalogSmoothing) {
- inputX = smoothRebel1Op0BAnalogInput(inputX, _level2JoystickFilteredX, 127);
- inputY = smoothRebel1Op0BAnalogInput(inputY, _level2JoystickFilteredY, 100);
+ if (preciseGamepadReticle) {
+ inputX = shapeRebel1Op0BGamepadAxis(inputX, 127);
+ inputY = shapeRebel1Op0BGamepadAxis(inputY, 100);
+ }
+ const int analogRampDivisor = preciseGamepadReticle ? 20 : 10;
+ inputX = smoothRebel1Op0BAnalogInput(inputX, _level2JoystickFilteredX, 127, analogRampDivisor);
+ inputY = smoothRebel1Op0BAnalogInput(inputY, _level2JoystickFilteredY, 100, analogRampDivisor);
} else {
_level2JoystickFilteredX = 0;
_level2JoystickFilteredY = 0;
@@ -1663,11 +1776,12 @@ void InsaneRebel1::updateGameOp0BPhysics() {
}
_inputAxisDeltaX = inputX;
- debugC(DEBUG_INSANE, "RA1 GAME 0x0B input: frame=%d source=%s controls=%s window=%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",
+ 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",
gameOp0BSmoothWindow,
+ preciseGamepadReticle ? 1 : 0,
_perspectiveX, _perspectiveY,
_health, _prevDamageFlags,
_joystickAxisX, _joystickAxisY,
@@ -2031,6 +2145,7 @@ void InsaneRebel1::handleGameOpcode5EReset(uint32 param1) {
_mouseVirtualValid = false;
_level2JoystickFilteredX = 0;
_level2JoystickFilteredY = 0;
+ resetRelativeGamepadAim();
_playerFired = false;
_fireCooldown = 0;
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 15d07ef18c2..7677cf0d985 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -632,8 +632,13 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
return true;
}
- if (event.type == Common::EVENT_MOUSEMOVE && !_mouseRecentering)
+ if (event.type == Common::EVENT_MOUSEMOVE && !_mouseRecentering) {
+ if (_gamepadAimActive && usesRelativeGamepadAimForCurrentLevel() &&
+ _interactiveVideoActive && !_menuActive &&
+ (event.relMouse.x != 0 || event.relMouse.y != 0))
+ _gamepadAimActive = false;
_activeInputSource = kInputSourceMouse;
+ }
// 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.
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 59a87b0f136..248b9ae29c5 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -276,6 +276,9 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
_lastJoystickAxisEventTime = 0;
_level2JoystickFilteredX = 0;
_level2JoystickFilteredY = 0;
+ _gamepadAimAxisX = 0;
+ _gamepadAimAxisY = 0;
+ _gamepadAimActive = false;
_activeInputSource = kInputSourceMouse;
_currentLevel = 0;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 5264989c70c..4d1478e66ae 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -221,7 +221,11 @@ private:
void updateTurretPhysics();
void updateTurretShipDirection(int16 offsetY);
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);
void preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJoystick = nullptr);
void rebuildProjectionTable(int16 curveStep, int16 curveExtent);
void resetProjectionTable();
@@ -364,10 +368,14 @@ private:
uint32 _lastJoystickAxisEventTime;
int16 _level2JoystickFilteredX; // Smoothed Level 2 analog X input
int16 _level2JoystickFilteredY; // Smoothed Level 2 analog Y input
+ int16 _gamepadAimAxisX; // Relative gamepad 0x0B aim in preprocessed input space
+ int16 _gamepadAimAxisY;
+ bool _gamepadAimActive;
enum InputSource {
kInputSourceMouse,
kInputSourceJoystickAnalog,
- kInputSourceJoystickDigital
+ kInputSourceJoystickDigital,
+ kInputSourceJoystickRelative
};
InputSource _activeInputSource;
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 3623029abfb..1b7c05a8a0a 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -246,6 +246,7 @@ void InsaneRebel1::resetLevelInputHistory(bool resetAxisDeltaX) {
_inputAxisDeltaX = 0;
_avgInputX = 0;
_avgInputY = 0;
+ resetRelativeGamepadAim();
}
void InsaneRebel1::resetLevelAttemptState(int16 flyControlMode, int16 gameplayPhase,
@@ -1603,6 +1604,7 @@ void InsaneRebel1::setupInteractiveVideoState(int32 startFrame) {
if (!preserveRuntimeState) {
_onFootInitialized = false; // Reset so each segment triggers counter==0 init
resetFrameObjectState();
+ resetRelativeGamepadAim();
}
_vm->_smushVideoShouldFinish = false;
// Route resumes stay in the same gameplay flow in the original executable.
More information about the Scummvm-git-logs
mailing list