[Scummvm-git-logs] scummvm master -> 90490c2792c55d85cbda11825683eca383eceecc
neuromancer
noreply at scummvm.org
Mon Jun 1 19:59:10 UTC 2026
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
bf3a892f5f SCUMM: RA2: improved input handling
5b40d53e96 SCUMM: RA2: fixed a bug in the duplicate/delete pilot code
4dd584d879 SCUMM: RA: make sure music is not interrupted
90490c2792 SCUMM: RA1: improve menu navigation using gamepad
Commit: bf3a892f5fe68a8bda3cc3728ac7da6637a11637
https://github.com/scummvm/scummvm/commit/bf3a892f5fe68a8bda3cc3728ac7da6637a11637
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-01T21:58:55+02:00
Commit Message:
SCUMM: RA2: improved input handling
Changed paths:
engines/scumm/insane/rebel2/iact.cpp
engines/scumm/insane/rebel2/rebel.cpp
diff --git a/engines/scumm/insane/rebel2/iact.cpp b/engines/scumm/insane/rebel2/iact.cpp
index fe30e70a2dc..6fb4ffec57e 100644
--- a/engines/scumm/insane/rebel2/iact.cpp
+++ b/engines/scumm/insane/rebel2/iact.cpp
@@ -801,11 +801,14 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
// -> velocity history averaging -> physics delta (clamped +/-12/frame)
// -> position clamping -> corridor collision -> perspective offsets
//
- // Level data table (DAT_0047e0e8 + level*0x242 + difficulty*0x22):
- // offset 0: smoothing param (>>4 +1 = window size)
+ // Level data table (DAT_0047e0e8 + difficulty*0x242 + levelType*0x22):
// offset 2: Y speed offset 4: X speed (levelSpeed)
- // offset 6: wind multiplier offset 14: corridor damage
- // We don't have the actual level data, so we use calibrated defaults.
+ // offset 6: wind multiplier
+ // Our extracted difficulty table starts at DAT_0047e0f0, so for Handler 7
+ // level types these fields map to lift/slide/drift of the preceding row.
+ const int flightParamIndex = CLIP(_rebelLevelType - 1, 0, 16);
+ const LevelDifficultyParams &flightParams =
+ kDifficultyTable[CLIP(_difficulty, 0, 5)][flightParamIndex];
// Step 1: Mouse input as offset from screen center.
// DAT_0047a7e0 = mouseX - 160, DAT_0047a7e2 = mouseY - 100.
@@ -836,7 +839,6 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
}
_velocityHistory[0] = scaledInputX;
- // Window size = (levelData[0] >> 4) + 1. Calibrated default: 5.
const int smoothWindow = 5;
int velSum = 0;
for (int i = 0; i < smoothWindow; i++) {
@@ -845,8 +847,7 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
_smoothedVelocity = (int16)(velSum / smoothWindow); // DAT_0044370c
// Step 4: Wind history (lines 158-173).
- // Wind multiplier comes from level data[6]. Without data, use 0 (no wind).
- const int16 windMult = 0;
+ const int16 windMult = flightParams.driftRate;
int windSumX = 0, windSumY = 0;
for (int i = 14; i > 0; i--) {
_windHistoryX[i] = _windHistoryX[i - 1];
@@ -863,12 +864,8 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
int16 windEffectY = (int16)((windMult * (windSumY + _windParamY)) / 15);
// Step 5: Position delta (lines 174-242).
- // levelSpeed (offset 4): calibrated so max velocity (127) -> delta 12.
- // 8 = (speed * 127) >> 9 -> speed around 32
- // levelYSpeed (offset 2): calibrated so max input (127) -> delta ~6.
- // 6 = (speed * 127) >> 10 -> speed around 48
- const int16 levelSpeed = 32;
- const int16 levelYSpeed = 48;
+ const int16 levelSpeed = flightParams.slideRate;
+ const int16 levelYSpeed = flightParams.liftRate;
int16 absSmoothVel = ABS(_smoothedVelocity);
int16 positionDeltaX;
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 4c363df1be4..501186e152b 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -1596,7 +1596,12 @@ Common::Point InsaneRebel2::getGameplayAimPoint() {
// Pure getter (queried many times per frame): the aim/reticle follows the virtual
// mouse position. Directional controls pan that position incrementally once per frame
// via updateGameplayAimFromGamepad(), rather than snapping the reticle to a screen edge.
- return Common::Point(_vm->_mouse.x, _vm->_mouse.y);
+ int y = _vm->_mouse.y;
+ if (_optControlsFlipped) {
+ // Original DAT_0047a7fe reverses only the up/down gameplay axis.
+ y = CLIP<int>(200 - y, 0, 199);
+ }
+ return Common::Point(_vm->_mouse.x, y);
}
// Apply the user's configured analog deadzone so a resting stick reports no
Commit: 5b40d53e96ed8200127fcbfea77a98ac16285d9f
https://github.com/scummvm/scummvm/commit/5b40d53e96ed8200127fcbfea77a98ac16285d9f
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-01T21:58:55+02:00
Commit Message:
SCUMM: RA2: fixed a bug in the duplicate/delete pilot code
Changed paths:
engines/scumm/insane/rebel2/menu.cpp
engines/scumm/insane/rebel2/rebel.h
diff --git a/engines/scumm/insane/rebel2/menu.cpp b/engines/scumm/insane/rebel2/menu.cpp
index 8dfdd0cac36..5a7221e3ad1 100644
--- a/engines/scumm/insane/rebel2/menu.cpp
+++ b/engines/scumm/insane/rebel2/menu.cpp
@@ -1239,6 +1239,32 @@ int InsaneRebel2::runLevelSelect() {
continue;
}
+ // --- Pilot operation submenu completed ---
+ if (_pilotMenuMode == kPilotModeCopySelect || _pilotMenuMode == kPilotModeDeleteSelect) {
+ int pilotIndex = _levelSelection;
+ if (pilotIndex >= 0 && pilotIndex < _numPilots) {
+ if (_pilotMenuMode == kPilotModeCopySelect) {
+ copyPilot(pilotIndex);
+ savePilots();
+ _levelSelection = pilotIndex;
+ debug("Rebel2: Copied pilot %d, now %d pilots", pilotIndex, _numPilots);
+ } else {
+ deletePilot(pilotIndex);
+ savePilots();
+ if (_numPilots > 0) {
+ _levelSelection = (pilotIndex != 0) ? pilotIndex - 1 : 0;
+ } else {
+ _levelSelection = 0;
+ }
+ debug("Rebel2: Deleted pilot %d, %d remaining", pilotIndex, _numPilots);
+ }
+ }
+ _pilotMenuMode = kPilotModeSelect;
+ _levelItemCount = _numPilots + 4;
+ _gameState = kStatePilotSelect;
+ continue;
+ }
+
// --- Normal pilot menu selection ---
debug("Rebel2: Pilot selection: %d (numPilots=%d)", _levelSelection, _numPilots);
@@ -1270,27 +1296,22 @@ int InsaneRebel2::runLevelSelect() {
continue;
} else if (_levelSelection == _numPilots + 1) {
- // COPY PILOT
+ // COPY PILOT - original opens a second menu to select the source pilot.
if (_numPilots > 0 && _numPilots < kMaxPilots) {
- // Copy first pilot (slot 0) by default â original swaps with selected
- int srcIdx = (_levelSelection > 0 && _levelSelection <= _numPilots) ? _levelSelection - 1 : 0;
- copyPilot(srcIdx);
- savePilots();
- _levelItemCount = _numPilots + 4;
- debug("Rebel2: Copied pilot %d, now %d pilots", srcIdx, _numPilots);
+ _pilotMenuMode = kPilotModeCopySelect;
+ _levelSelection = 0;
+ _levelItemCount = _numPilots;
+ debug("Rebel2: COPY PILOT - selecting source");
}
continue;
} else if (_levelSelection == _numPilots + 2) {
- // DELETE PILOT
+ // DELETE PILOT - original opens a second menu to select the target pilot.
if (_numPilots > 0) {
- // Delete the first pilot (slot 0) â original has confirm sub-flow
- deletePilot(0);
- savePilots();
- _levelItemCount = _numPilots + 4;
- if (_levelSelection >= _levelItemCount)
- _levelSelection = _levelItemCount - 1;
- debug("Rebel2: Deleted pilot, %d remaining", _numPilots);
+ _pilotMenuMode = kPilotModeDeleteSelect;
+ _levelSelection = 0;
+ _levelItemCount = _numPilots;
+ debug("Rebel2: DELETE PILOT - selecting target");
}
continue;
@@ -1306,8 +1327,8 @@ int InsaneRebel2::runLevelSelect() {
}
int InsaneRebel2::processLevelSelectInput() {
- // Process input for pilot selection and difficulty submenu
- // Handles kPilotModeSelect, kPilotModeNameInput, and kStateDifficultySelect
+ // Process input for pilot selection and difficulty submenu.
+ // Handles pilot list, pilot operation submenus, name input, and difficulty.
// Returns: -1 = no action, 0+ = item selected
int result = -1;
@@ -1364,8 +1385,13 @@ int InsaneRebel2::processLevelSelectInput() {
// Normal menu navigation (pilot select or difficulty submenu)
bool isDifficultyMode = (_gameState == kStateDifficultySelect);
+ bool isPilotOperationMode =
+ (_pilotMenuMode == kPilotModeCopySelect || _pilotMenuMode == kPilotModeDeleteSelect);
int &selection = isDifficultyMode ? _difficultySelection : _levelSelection;
- int itemCount = isDifficultyMode ? 6 : _levelItemCount;
+ int itemCount = isDifficultyMode ? 6 : (isPilotOperationMode ? _numPilots : _levelItemCount);
+ if (itemCount <= 0)
+ return -1;
+
const int itemBaseY = itemCount * -5 + 0x68;
const int itemSpacing = 10;
@@ -1398,6 +1424,11 @@ int InsaneRebel2::processLevelSelectInput() {
case Common::KEYCODE_ESCAPE:
if (isDifficultyMode) {
_gameState = kStatePilotSelect;
+ } else if (isPilotOperationMode) {
+ bool wasCopyMode = (_pilotMenuMode == kPilotModeCopySelect);
+ _pilotMenuMode = kPilotModeSelect;
+ _levelItemCount = _numPilots + 4;
+ _levelSelection = _numPilots + (wasCopyMode ? 1 : 2);
} else {
result = _levelItemCount - 1; // Last item = MAIN MENU
}
@@ -1437,6 +1468,11 @@ int InsaneRebel2::processLevelSelectInput() {
case Common::EVENT_RETURN_TO_LAUNCHER:
if (isDifficultyMode) {
_gameState = kStatePilotSelect;
+ } else if (isPilotOperationMode) {
+ _pilotMenuMode = kPilotModeSelect;
+ _levelItemCount = _numPilots + 4;
+ _levelSelection = _levelItemCount - 1;
+ result = _levelSelection;
} else {
result = _levelItemCount - 1;
}
@@ -1480,6 +1516,30 @@ void InsaneRebel2::drawLevelSelectOverlay(byte *renderBitmap, int pitch, int wid
return;
}
+ if (_pilotMenuMode == kPilotModeCopySelect || _pilotMenuMode == kPilotModeDeleteSelect) {
+ Common::String pilotNameStrs[kMaxPilots];
+ for (int i = 0; i < _numPilots; i++) {
+ pilotNameStrs[i] = Common::String::format("^f01^c005%s^f00", _pilots[i].name);
+ }
+
+ const char *pilotItems[kMaxPilots + 1];
+ int idx = 0;
+ pilotItems[idx++] = splayer->getString(_pilotMenuMode == kPilotModeCopySelect ? 28 : 27);
+
+ for (int i = 0; i < _numPilots; i++) {
+ pilotItems[idx++] = pilotNameStrs[i].c_str();
+ }
+
+ for (int i = 0; i < idx; i++) {
+ if (!pilotItems[i] || !pilotItems[i][0]) {
+ pilotItems[i] = "";
+ }
+ }
+
+ drawMenuItems(renderBitmap, pitch, width, height, pilotItems, _numPilots, _levelSelection);
+ return;
+ }
+
// -------------------------------------------------------------------
// Pilot menu - FUN_0041f5ae(0, &DAT_00457768, N+4, 0)
// -------------------------------------------------------------------
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 926c23d69ab..6f24d48a69f 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -296,7 +296,9 @@ public:
enum PilotMenuMode {
kPilotModeSelect = 0, // Normal pilot list selection
kPilotModeNameInput = 1, // Typing a new pilot name
- kPilotModeDifficulty = 2 // Difficulty submenu
+ kPilotModeDifficulty = 2, // Difficulty submenu
+ kPilotModeCopySelect = 3, // Selecting source pilot to copy
+ kPilotModeDeleteSelect = 4 // Selecting pilot to delete
};
PilotMenuMode _pilotMenuMode;
Common::String _pilotNameInput; // Current name being typed
Commit: 4dd584d879196b8cc1c5306280820abbdcd60f4a
https://github.com/scummvm/scummvm/commit/4dd584d879196b8cc1c5306280820abbdcd60f4a
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-01T21:58:55+02:00
Commit Message:
SCUMM: RA: make sure music is not interrupted
Changed paths:
engines/scumm/insane/rebel/rebel_audio.cpp
engines/scumm/insane/rebel/rebel_audio.h
engines/scumm/insane/rebel1/iact.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/rebel/rebel_audio.cpp b/engines/scumm/insane/rebel/rebel_audio.cpp
index b06a58fd884..07204d4806d 100644
--- a/engines/scumm/insane/rebel/rebel_audio.cpp
+++ b/engines/scumm/insane/rebel/rebel_audio.cpp
@@ -87,10 +87,203 @@ void RebelAudio::queueData(int trackIdx, const uint8 *data, int32 size, int volu
_vm->_mixer->setChannelBalance(_handles[trackIdx], scaledPan);
}
+bool RebelAudio::processAudioCodes(SmushPlayer *player, int idx, int32 &tmpFeedSize, int &mixVolume) {
+ uint8 *code, *buf, subcode, value;
+ int chunk;
+
+ while (tmpFeedSize) {
+ code = player->_smushDispatch[idx].headerPtr;
+
+ switch (code[0]) {
+ case SAUD_OP_INIT:
+ player->_smushDispatch[idx].audioLength = 0;
+ buf = player->_smushDispatch[idx].headerPtr;
+ player->_smushDispatch[idx].audioRemaining = READ_BE_UINT32(buf + 2);
+ player->_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 6);
+ player->_smushDispatch[idx].sampleRate = player->_smushAudioSampleRate;
+ player->_smushDispatch[idx].headerPtr += player->_smushDispatch[idx].headerPtr[1] + 2;
+ if (player->_smushDispatch[idx].audioRemaining < player->_smushTracks[idx].availableSize + (player->_smushTracks[idx].availableSize >= player->_smushTracks[idx].sdatSize ? 0 : 15000) - player->_smushTracks[idx].dataSize) {
+ chunk = player->_smushTracks[idx].availableSize - player->_smushTracks[idx].dataSize - player->_smushDispatch[idx].audioRemaining + 15000;
+ if (chunk > player->_smushDispatch[idx].currentOffset) {
+ player->_smushTracks[idx].state = TRK_STATE_INACTIVE;
+ player->_smushTracks[idx].groupId = GRP_MASTER;
+ tmpFeedSize = 0;
+ break;
+ }
+
+ player->_smushDispatch[idx].audioRemaining += chunk;
+ player->_smushDispatch[idx].currentOffset -= chunk;
+ }
+ break;
+
+ case SAUD_OP_UPDATE_HEADER:
+ case SAUD_OP_COMPARE_GT:
+ case SAUD_OP_COMPARE_LT:
+ case SAUD_OP_COMPARE_EQ:
+ case SAUD_OP_COMPARE_NE:
+ subcode = code[4];
+ switch (subcode) {
+ case SAUD_VALUEID_ALL_VOLS:
+ value = player->_smushTrackVols[0];
+ break;
+ case SAUD_VALUEID_TRK_VOL:
+ value = player->_smushTracks[idx].volume;
+ break;
+ case SAUD_VALUEID_TRK_PAN:
+ value = player->_smushTracks[idx].pan;
+ break;
+ default:
+ value = player->_smushAudioTable[subcode];
+ break;
+ }
+
+ switch (code[0]) {
+ case SAUD_OP_UPDATE_HEADER:
+ value = value || (subcode == 0);
+ break;
+ case SAUD_OP_COMPARE_GT:
+ value = value > code[5];
+ break;
+ case SAUD_OP_COMPARE_LT:
+ value = value < code[5];
+ break;
+ case SAUD_OP_COMPARE_EQ:
+ value = value == code[5];
+ break;
+ case SAUD_OP_COMPARE_NE:
+ value = value != code[5];
+ break;
+ default:
+ break;
+ }
+
+ if (!value) {
+ player->_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+ } else {
+ // Rebel Assault SAUD branch targets are signed relative displacements.
+ player->_smushDispatch[idx].headerPtr = code + READ_BE_INT16(&code[2]);
+ }
+ break;
+
+ case SAUD_OP_SET_PARAM:
+ switch (code[2]) {
+ case SAUD_VALUEID_ALL_VOLS:
+ player->_smushTrackVols[0] = code[3];
+ break;
+ case SAUD_VALUEID_TRK_VOL:
+ player->_smushTracks[idx].volume = code[3];
+ mixVolume = (player->_smushTrackVols[0] * player->_smushTracks[idx].volume) / 127;
+
+ if ((player->_smushTracks[idx].flags & TRK_TYPE_MASK) == IS_BKG_MUSIC && player->isChanActive(CHN_SPEECH))
+ mixVolume = (mixVolume * player->_gainReductionMultiplier) >> 8;
+ break;
+ case SAUD_VALUEID_TRK_PAN:
+ player->_smushTracks[idx].pan = code[3];
+ break;
+ default:
+ player->_smushAudioTable[code[2]] = code[3];
+ break;
+ }
+ player->_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+ break;
+
+ case SAUD_OP_INCR_PARAM:
+ switch (code[2]) {
+ case SAUD_VALUEID_ALL_VOLS:
+ player->_smushTrackVols[0] += code[3];
+ break;
+ case SAUD_VALUEID_TRK_VOL:
+ player->_smushTracks[idx].volume += code[3];
+ break;
+ case SAUD_VALUEID_TRK_PAN:
+ player->_smushTracks[idx].pan += code[3];
+ break;
+ default:
+ player->_smushAudioTable[code[2]] += code[3];
+ break;
+ }
+ player->_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+ break;
+
+ case SAUD_OP_SET_OFFSET:
+ player->_smushDispatch[idx].audioLength = 0;
+ buf = player->_smushDispatch[idx].headerPtr;
+ player->_smushDispatch[idx].audioRemaining = READ_BE_UINT32(buf + 2);
+ player->_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 6);
+ player->_smushDispatch[idx].sampleRate = player->_smushAudioSampleRate;
+
+ player->_smushDispatch[idx].headerPtr += player->_smushDispatch[idx].headerPtr[1] + 2;
+ if (player->_smushDispatch[idx].audioRemaining < player->_smushTracks[idx].availableSize + (player->_smushTracks[idx].availableSize >= player->_smushTracks[idx].sdatSize ? 0 : 15000) - player->_smushTracks[idx].dataSize) {
+ chunk = player->_smushTracks[idx].availableSize - player->_smushTracks[idx].dataSize - player->_smushDispatch[idx].audioRemaining + 15000;
+ if (chunk > player->_smushDispatch[idx].currentOffset) {
+ player->_smushTracks[idx].state = TRK_STATE_INACTIVE;
+ player->_smushTracks[idx].groupId = GRP_MASTER;
+ tmpFeedSize = 0;
+ break;
+ }
+
+ player->_smushDispatch[idx].audioRemaining += chunk;
+ player->_smushDispatch[idx].currentOffset -= chunk;
+ }
+ break;
+
+ case SAUD_OP_SET_LENGTH:
+ if (!player->_smushDispatch[idx].audioLength) {
+ player->_smushDispatch[idx].audioLength = READ_BE_UINT32(&code[6]);
+ player->_smushDispatch[idx].elapsedAudio = 0;
+ }
+
+ buf = player->_smushDispatch[idx].headerPtr;
+ player->_smushDispatch[idx].audioRemaining = player->_smushDispatch[idx].elapsedAudio + READ_BE_UINT32(buf + 2);
+
+ player->_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 14);
+ if (player->_smushDispatch[idx].currentOffset > player->_smushDispatch[idx].audioLength)
+ player->_smushDispatch[idx].currentOffset = player->_smushDispatch[idx].audioLength;
+
+ player->_smushDispatch[idx].sampleRate = player->_smushAudioSampleRate;
+
+ player->_smushDispatch[idx].audioLength -= player->_smushDispatch[idx].currentOffset;
+ player->_smushDispatch[idx].elapsedAudio += player->_smushDispatch[idx].currentOffset;
+
+ if (player->_smushDispatch[idx].audioLength) {
+ player->_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+ } else {
+ player->_smushDispatch[idx].headerPtr = code + READ_BE_INT16(&code[18]);
+ }
+
+ if (player->_smushDispatch[idx].audioRemaining >= player->_smushTracks[idx].availableSize + (player->_smushTracks[idx].availableSize >= player->_smushTracks[idx].sdatSize ? 0 : 15000) - player->_smushTracks[idx].dataSize) {
+ chunk = player->_smushTracks[idx].availableSize - player->_smushTracks[idx].dataSize - player->_smushDispatch[idx].audioRemaining + 15000;
+ if (chunk > player->_smushDispatch[idx].currentOffset) {
+ player->_smushTracks[idx].state = TRK_STATE_INACTIVE;
+ player->_smushTracks[idx].groupId = GRP_MASTER;
+ tmpFeedSize = 0;
+ } else {
+ player->_smushDispatch[idx].audioRemaining += chunk;
+ player->_smushDispatch[idx].currentOffset -= chunk;
+ }
+ }
+ break;
+
+ default:
+ player->_smushTracks[idx].state = TRK_STATE_INACTIVE;
+ player->_smushTracks[idx].groupId = GRP_MASTER;
+ tmpFeedSize = 0;
+ }
+
+ if (player->_smushDispatch[idx].currentOffset > 0)
+ return false;
+ }
+
+ return true;
+}
+
void RebelAudio::processFrame(SmushPlayer *player, int16 feedSize) {
if (!player)
return;
+ if (player->_paused)
+ return;
+
if (player->_smushTracksNeedInit) {
player->_smushTracksNeedInit = false;
for (int i = 0; i < SMUSH_MAX_TRACKS; i++) {
@@ -176,6 +369,7 @@ void RebelAudio::processFrame(SmushPlayer *player, int16 feedSize) {
if (!dispatch.dataBuf || offset < 0 || offset + mixInFrameCount > dispatch.dataSize)
break;
+ track.state = TRK_STATE_PLAYING;
queueData(i, &dispatch.dataBuf[offset], mixInFrameCount, mixVolume, track.pan);
dispatch.currentOffset -= mixInFrameCount;
@@ -191,9 +385,7 @@ void RebelAudio::processFrame(SmushPlayer *player, int16 feedSize) {
}
if (dispatch.currentOffset <= 0) {
- if (!player->processAudioCodes(i, tmpFeedSize, mixVolume))
- break;
- if (dispatch.currentOffset <= 0)
+ if (processAudioCodes(player, i, tmpFeedSize, mixVolume) && tmpFeedSize <= 0)
break;
} else if (tmpFeedSize <= 0) {
break;
diff --git a/engines/scumm/insane/rebel/rebel_audio.h b/engines/scumm/insane/rebel/rebel_audio.h
index c20dace1e5e..10e0548bf71 100644
--- a/engines/scumm/insane/rebel/rebel_audio.h
+++ b/engines/scumm/insane/rebel/rebel_audio.h
@@ -48,6 +48,8 @@ public:
private:
static const int kMaxTracks = 4;
+ bool processAudioCodes(SmushPlayer *player, int idx, int32 &tmpFeedSize, int &mixVolume);
+
ScummEngine_v7 *_vm;
Audio::QueuingAudioStream *_streams[kMaxTracks];
Audio::SoundHandle _handles[kMaxTracks];
diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index f3d2a507789..db4c4593dc9 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -1222,6 +1222,7 @@ void InsaneRebel1::updateShipPhysics() {
if (_pathBranchEnabled && _gameCounter >= kPathBranchCounter) {
if (_shipPosX > kRA1CenterX) {
_rightPathSelected = true;
+ preserveInteractiveVideoAudioState();
_vm->_smushVideoShouldFinish = true;
debugC(DEBUG_INSANE, "RA1: Right path selected (counter=%d, shipX=%d)", _gameCounter, _shipPosX);
} else {
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 8341fa0c1cd..f8efc33a1ea 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -313,6 +313,10 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
_hudDirtyFlag = 0;
_maxChapterUnlocked = 0;
_interactiveVideoActive = false;
+ _restoreInteractiveVideoAudioState = false;
+ memset(_savedInteractiveVideoTrackState, 0, sizeof(_savedInteractiveVideoTrackState));
+ memset(_savedInteractiveVideoTrackGroupId, 0, sizeof(_savedInteractiveVideoTrackGroupId));
+ _savedInteractiveVideoTrackCount = 0;
_gameCounter = 0;
_pathBranchEnabled = false;
_rightPathSelected = false;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 0b7d2da299b..83e8381390c 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -199,6 +199,8 @@ private:
// Play interactive gameplay video (with ship physics + HUD)
void playInteractiveVideo(const char *filename, int32 startFrame = 0);
void resetInteractiveVideoAudio();
+ void preserveInteractiveVideoAudioState();
+ void restoreInteractiveVideoAudioState();
void setupInteractiveVideoState(int32 startFrame);
void resolveSeek(const char *filename, int32 startFrame, int32 &videoOffset, int32 &videoStartFrame);
void captureInteractiveVideoInput();
@@ -488,6 +490,10 @@ private:
// Streamed SMUSH audio
RebelAudio _audio;
+ bool _restoreInteractiveVideoAudioState;
+ int16 _savedInteractiveVideoTrackState[SMUSH_MAX_TRACKS];
+ int _savedInteractiveVideoTrackGroupId[SMUSH_MAX_TRACKS];
+ int _savedInteractiveVideoTrackCount;
static const int kNumSfx = 8;
enum SfxSlot {
kSfxLaserShot = 0,
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index f1d67c8e49b..b1e4303c7f4 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -1552,6 +1552,42 @@ void InsaneRebel1::resetInteractiveVideoAudio() {
initAudio(sampleRate);
}
+void InsaneRebel1::preserveInteractiveVideoAudioState() {
+ SmushPlayer *splayer = _vm->_splayer;
+
+ _restoreInteractiveVideoAudioState = false;
+ _savedInteractiveVideoTrackCount = 0;
+ if (!splayer)
+ return;
+
+ _savedInteractiveVideoTrackCount = MIN<int>(splayer->_smushNumTracks, SMUSH_MAX_TRACKS);
+ for (int i = 0; i < _savedInteractiveVideoTrackCount; i++) {
+ _savedInteractiveVideoTrackState[i] = splayer->_smushTracks[i].state;
+ _savedInteractiveVideoTrackGroupId[i] = splayer->_smushTracks[i].groupId;
+ }
+
+ _restoreInteractiveVideoAudioState = true;
+}
+
+void InsaneRebel1::restoreInteractiveVideoAudioState() {
+ if (!_restoreInteractiveVideoAudioState)
+ return;
+
+ _restoreInteractiveVideoAudioState = false;
+ if (_vm->shouldQuit() || _vm->_saveLoadFlag)
+ return;
+
+ SmushPlayer *splayer = _vm->_splayer;
+ if (!splayer)
+ return;
+
+ const int trackCount = MIN<int>(_savedInteractiveVideoTrackCount, splayer->_smushNumTracks);
+ for (int i = 0; i < trackCount; i++) {
+ splayer->_smushTracks[i].state = _savedInteractiveVideoTrackState[i];
+ splayer->_smushTracks[i].groupId = _savedInteractiveVideoTrackGroupId[i];
+ }
+}
+
void InsaneRebel1::setupInteractiveVideoState(int32 startFrame) {
const bool level7RouteSplice = (_currentLevel == 6 && _levelRouteIndex > 0);
const bool resumingRoute = startFrame > 0;
@@ -1658,6 +1694,7 @@ void InsaneRebel1::releaseInteractiveVideoInput() {
void InsaneRebel1::playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame) {
_vm->_splayer->play(filename, 12, videoOffset, videoStartFrame);
+ restoreInteractiveVideoAudioState();
_interactiveVideoActive = false;
}
@@ -1669,8 +1706,10 @@ void InsaneRebel1::playInteractiveVideo(const char *filename, int32 startFrame)
int32 videoStartFrame = 0;
int32 videoOffset = 0;
+ const bool preserveRuntimeState = (startFrame > 0) || (_currentLevel == 6 && _levelRouteIndex > 0);
- resetInteractiveVideoAudio();
+ if (!preserveRuntimeState)
+ resetInteractiveVideoAudio();
setupInteractiveVideoState(startFrame);
resolveSeek(filename, startFrame, videoOffset, videoStartFrame);
captureInteractiveVideoInput();
Commit: 90490c2792c55d85cbda11825683eca383eceecc
https://github.com/scummvm/scummvm/commit/90490c2792c55d85cbda11825683eca383eceecc
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-01T21:58:55+02:00
Commit Message:
SCUMM: RA1: improve menu navigation using gamepad
Changed paths:
engines/scumm/insane/rebel1/menu.cpp
engines/scumm/metaengine.cpp
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 0dbc31baf07..68bbd4aae9d 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -91,6 +91,10 @@ static const char *getRebel1ActionName(Common::CustomEventType customType) {
return "attack";
case kScummActionInsaneSwitch:
return "switch";
+ case kScummActionInsaneBack:
+ return "back";
+ case kScummActionInsaneSkip:
+ return "skip";
default:
return "other";
}
@@ -171,6 +175,8 @@ static RA1MenuCommand getRebel1MenuCommandFromAction(ScummAction action) {
return kRA1MenuCommandRight;
case kScummActionInsaneAttack:
return kRA1MenuCommandAccept;
+ case kScummActionInsaneSkip:
+ return kRA1MenuCommandCancel;
default:
return kRA1MenuCommandNone;
}
@@ -326,6 +332,10 @@ bool InsaneRebel1::handleTextEntryAction(ScummAction action) {
case kScummActionInsaneAttack:
selectTextEntryChar();
return true;
+ case kScummActionInsaneSwitch:
+ case kScummActionInsaneSkip:
+ finishTextEntry(true);
+ return true;
default:
return false;
}
@@ -482,6 +492,12 @@ bool InsaneRebel1::handleControllerMenuAction(ScummAction action) {
if (_textEntryActive)
return handleTextEntryAction(action);
+ if (action == kScummActionInsaneSwitch || action == kScummActionInsaneSkip) {
+ if (_levelSelectActive || _optionsActive)
+ return handleMenuCommand(kRA1MenuCommandCancel);
+ return true;
+ }
+
return handleMenuCommand(getRebel1MenuCommandFromAction(action));
}
@@ -692,7 +708,24 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
_activeInputSource = kInputSourceJoystickDigital;
}
- if (_highScoresActive && pressed && event.customType == kScummActionInsaneAttack) {
+ if (event.customType == kScummActionInsaneBack) {
+ if (!pressed)
+ return true;
+ if (_player) {
+ const bool wasPaused = _player->_paused;
+ if (!wasPaused)
+ _player->pause();
+ _vm->openMainMenuDialog();
+ if (!wasPaused)
+ _player->unpause();
+ }
+ return true;
+ }
+
+ if (_highScoresActive && pressed &&
+ (event.customType == kScummActionInsaneAttack ||
+ event.customType == kScummActionInsaneSwitch ||
+ event.customType == kScummActionInsaneSkip)) {
_vm->_smushVideoShouldFinish = true;
return true;
}
@@ -700,6 +733,16 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
if (pressed && handleControllerMenuAction((ScummAction)event.customType))
return true;
+ if (event.customType == kScummActionInsaneSkip) {
+ if (!pressed)
+ return true;
+ if (!_interactiveVideoActive) {
+ _vm->_smushVideoShouldFinish = true;
+ return true;
+ }
+ return true;
+ }
+
if (_interactiveVideoActive && !_menuActive && event.customType == kScummActionInsaneAttack) {
_playerFired = pressed;
return true;
@@ -732,14 +775,30 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
return true;
}
- if (event.type == Common::EVENT_MAINMENU && _interactiveVideoActive && !_menuActive) {
+ if (event.type == Common::EVENT_MAINMENU) {
+ if (_menuActive || _highScoresActive)
+ return true;
+
const uint32 now = _vm->_system->getMillis();
const uint32 elapsedSinceAxis = _lastJoystickAxisEventTime ? now - _lastJoystickAxisEventTime : 0xffffffffu;
- debugC(DEBUG_INSANE, "RA1 input mainmenu-event: gameplay=1 elapsedSinceAxis=%u storedAxis=(%d,%d)",
- elapsedSinceAxis, _joystickAxisX, _joystickAxisY);
- if (elapsedSinceAxis <= kRA1JoystickAxisEscGuardMs) {
- debugC(DEBUG_INSANE, "RA1 input ignored mainmenu event after recent joystick axis movement (%u ms)", elapsedSinceAxis);
- return true;
+
+ if (_interactiveVideoActive && !_menuActive) {
+ debugC(DEBUG_INSANE, "RA1 input mainmenu-event: gameplay=1 elapsedSinceAxis=%u storedAxis=(%d,%d)",
+ elapsedSinceAxis, _joystickAxisX, _joystickAxisY);
+ if (elapsedSinceAxis <= kRA1JoystickAxisEscGuardMs) {
+ debugC(DEBUG_INSANE, "RA1 input ignored mainmenu event after recent joystick axis movement (%u ms)", elapsedSinceAxis);
+ return true;
+ }
+
+ if (_player) {
+ const bool wasPaused = _player->_paused;
+ if (!wasPaused)
+ _player->pause();
+ _vm->openMainMenuDialog();
+ if (!wasPaused)
+ _player->unpause();
+ return true;
+ }
}
}
diff --git a/engines/scumm/metaengine.cpp b/engines/scumm/metaengine.cpp
index c43f81ea35d..d0e91a67b89 100644
--- a/engines/scumm/metaengine.cpp
+++ b/engines/scumm/metaengine.cpp
@@ -1019,7 +1019,7 @@ Common::KeymapArray ScummMetaEngine::initKeymaps(const char *target) const {
Common::String gameId = ConfMan.get("gameid", target);
Action *act;
- if (gameId == "rebel2") {
+ if (gameId == "rebel1" || gameId == "rebel2") {
for (uint i = 0; i < keymaps.size(); ++i) {
if (keymaps[i]->getId() == "engine-default") {
delete keymaps.remove_at(i);
@@ -1141,24 +1141,28 @@ Common::KeymapArray ScummMetaEngine::initKeymaps(const char *target) const {
act->setCustomBackendActionAxisEvent(kScummBackendActionRebel1AxisUp);
act->addDefaultInputMapping("JOY_LEFT_STICK_Y-");
act->addDefaultInputMapping("JOY_RIGHT_STICK_Y-");
+ act->addDefaultInputMapping("JOY_HAT_Y-");
rebel1Keymap->addAction(act);
act = new Action("RA1STICKDOWN", _("Stick down"));
act->setCustomBackendActionAxisEvent(kScummBackendActionRebel1AxisDown);
act->addDefaultInputMapping("JOY_LEFT_STICK_Y+");
act->addDefaultInputMapping("JOY_RIGHT_STICK_Y+");
+ act->addDefaultInputMapping("JOY_HAT_Y+");
rebel1Keymap->addAction(act);
act = new Action("RA1STICKLEFT", _("Stick left"));
act->setCustomBackendActionAxisEvent(kScummBackendActionRebel1AxisLeft);
act->addDefaultInputMapping("JOY_LEFT_STICK_X-");
act->addDefaultInputMapping("JOY_RIGHT_STICK_X-");
+ act->addDefaultInputMapping("JOY_HAT_X-");
rebel1Keymap->addAction(act);
act = new Action("RA1STICKRIGHT", _("Stick right"));
act->setCustomBackendActionAxisEvent(kScummBackendActionRebel1AxisRight);
act->addDefaultInputMapping("JOY_LEFT_STICK_X+");
act->addDefaultInputMapping("JOY_RIGHT_STICK_X+");
+ act->addDefaultInputMapping("JOY_HAT_X+");
rebel1Keymap->addAction(act);
act = new Action("RA1FIRE", _("Fire / select"));
@@ -1166,11 +1170,21 @@ Common::KeymapArray ScummMetaEngine::initKeymaps(const char *target) const {
act->addDefaultInputMapping("JOY_A");
rebel1Keymap->addAction(act);
- act = new Action("RA1BACK", _("Back / skip"));
- act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
+ act = new Action("RA1CANCEL", _("Menu back"));
+ act->setCustomEngineActionEvent(kScummActionInsaneSwitch);
+ act->addDefaultInputMapping("JOY_X");
+ rebel1Keymap->addAction(act);
+
+ act = new Action("RA1SKIP", _("Skip / menu back"));
+ act->setCustomEngineActionEvent(kScummActionInsaneSkip);
act->addDefaultInputMapping("JOY_B");
- act->addDefaultInputMapping("JOY_Y");
+ rebel1Keymap->addAction(act);
+
+ act = new Action("RA1BACK", _("Menu"));
+ act->setCustomEngineActionEvent(kScummActionInsaneBack);
+ act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_START");
+ act->addDefaultInputMapping("AC_BACK");
rebel1Keymap->addAction(act);
keymaps.push_back(rebel1Keymap);
More information about the Scummvm-git-logs
mailing list