[Scummvm-git-logs] scummvm master -> 4761d421591c5a64a6f50c9d8dfb0b73a0a046be
neuromancer
noreply at scummvm.org
Sat Aug 15 10:20:48 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:
f3c5c841eb SCUMM: RA1: added missing persective shifts when moving in some levels
e9751c7286 SCUMM: RA1: fixed some music reset in levels 5 and 7
4761d42159 SCUMM: RA1: fixed axis consistency for joystick for some levels
Commit: f3c5c841ebefe7e92f64ecf9c43b0eb9b228b972
https://github.com/scummvm/scummvm/commit/f3c5c841ebefe7e92f64ecf9c43b0eb9b228b972
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-08-15T12:19:11+02:00
Commit Message:
SCUMM: RA1: added missing persective shifts when moving in some levels
Changed paths:
engines/scumm/insane/rebel1/rebel.h
engines/scumm/smush/rebel/smush_player_ra1.cpp
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 3dd4d01e138..d87d30cef86 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -153,7 +153,6 @@ public:
void setFrameHasGameChunk(bool hasGameChunk) { _frameHasGameChunk = hasGameChunk; }
void setCurrentSmushFrame(int32 frame);
int getCurrentLevel() const { return _currentLevel; }
- int getLevelGameplayPhase() const { return _levelGameplayPhase; }
uint16 getActiveGameOpcode() const { return _activeGameOpcode; }
uint16 getEffectiveGameOpcode() const;
uint16 getTargetHitGameOpcode() const;
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index 3c6e27f1ee1..422c69f601a 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -270,23 +270,13 @@ bool SmushPlayerRebel1::handleGameFetch(int32 subSize, Common::SeekableReadStrea
if (_insane) {
InsaneRebel1 *rebel1 = static_cast<InsaneRebel1 *>(_insane);
if (rebel1->isInteractiveVideoActive()) {
- const uint16 gameOp = rebel1->getActiveGameOpcode();
- const bool fullWidthStoredPatch = (_storedFobjWidth == _vm->_screenWidth);
- const bool projectedCockpitPatch = (gameOp == 0x0B &&
- ((rebel1->getCurrentLevel() == 4 && rebel1->getLevelGameplayPhase() == 2) ||
- rebel1->getCurrentLevel() == 7));
- // Most interactive patches follow the viewport directly; selected
- // cockpit patches need projected center placement to keep indicators aligned.
- if (fullWidthStoredPatch || (gameOp == 0x0B && !projectedCockpitPatch) ||
- gameOp == 0x19 || gameOp == 0x1A) {
- left += _ra1ViewportOffsetX;
- top += _ra1ViewportOffsetY;
- } else {
- ra1ApplyCenteredFetchPlacement(rebel1, _storedFobjWidth, _storedFobjHeight, left, top);
- // Convert projected presentation-space placement into the cropped buffer.
- left += _ra1ViewportOffsetX;
- top += _ra1ViewportOffsetY;
- }
+ // DOS routes every FTCH through FUN_28D0A. It sets flag 0x0800
+ // before DispatchFobjCodec, applying quarter-projected placement to
+ // the stored patch regardless of the active GAME opcode or its size.
+ ra1ApplyCenteredFetchPlacement(rebel1, _storedFobjWidth, _storedFobjHeight, left, top);
+ // Convert fixed presentation-space placement into our cropped buffer.
+ left += _ra1ViewportOffsetX;
+ top += _ra1ViewportOffsetY;
}
}
Commit: e9751c728612bdcf9314508b080b2ad4cd979582
https://github.com/scummvm/scummvm/commit/e9751c728612bdcf9314508b080b2ad4cd979582
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-08-15T12:19:11+02:00
Commit Message:
SCUMM: RA1: fixed some music reset in levels 5 and 7
Changed paths:
engines/scumm/insane/rebel1/iact.cpp
engines/scumm/insane/rebel1/rebel.cpp
engines/scumm/insane/rebel1/rebel.h
engines/scumm/insane/rebel1/render.cpp
engines/scumm/insane/rebel1/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/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index d874fca97a2..24ada67a4ac 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -699,8 +699,11 @@ void InsaneRebel1::checkDynamicLevelBranch(int32 curFrame) {
if (!_vm->_smushVideoShouldFinish &&
_pendingRouteCutoverFrame >= 0 &&
routeFrame >= (uint32)_pendingRouteCutoverFrame) {
- if (_player && _currentLevel != 6)
- _player->setPreserveGameVideoStateOnRelease(true);
+ // L7 destinations can contain no audio chunks at all. L8 preservation
+ // is decided by SmushPlayer at the actual stop, after the final frame
+ // has resolved whether the player or walker was destroyed.
+ if (_currentLevel == 6)
+ preserveInteractiveVideoAudioState();
_vm->_smushVideoShouldFinish = true;
const int32 resumeFrame = (_currentLevel == 6 && _pendingRouteStartFrame < 0) ?
0 : _pendingRouteStartFrame;
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 976ba63c5ca..be44fd47b57 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -562,10 +562,6 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
_interactiveVideoActive = false;
_preserveInteractiveRuntimeState = false;
_interactiveVideoCheatSkipped = false;
- _restoreInteractiveVideoAudioState = false;
- memset(_savedInteractiveVideoTrackState, 0, sizeof(_savedInteractiveVideoTrackState));
- memset(_savedInteractiveVideoTrackGroupId, 0, sizeof(_savedInteractiveVideoTrackGroupId));
- _savedInteractiveVideoTrackCount = 0;
_gameCounter = 0;
_pathBranchEnabled = false;
_rightPathSelected = false;
@@ -744,4 +740,8 @@ InsaneRebel1::~InsaneRebel1() {
freeSfx();
}
+bool InsaneRebel1::shouldPreserveWalkerRouteOnStop() const {
+ return _vm->_smushVideoShouldFinish && shouldPreserveWalkerRouteVideoState();
+}
+
} // End of namespace Scumm
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index d87d30cef86..1ccaee5053c 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -148,6 +148,11 @@ public:
void handleGameChunk(int32 subSize, Common::SeekableReadStream &b,
byte *renderBitmap = nullptr, int width = 0, int height = 0);
bool isInteractiveVideoActive() const { return _interactiveVideoActive; }
+ bool shouldPreserveWalkerRouteVideoState() const {
+ return _interactiveVideoActive && _currentLevel == 7 && _health >= 0 &&
+ _walkerHealth > 0 && !_interactiveVideoCheatSkipped;
+ }
+ bool shouldPreserveWalkerRouteOnStop() const;
// Touch devices use absolute aiming instead of cursor locking.
bool isTouchscreenActive() const;
void setFrameHasGameChunk(bool hasGameChunk) { _frameHasGameChunk = hasGameChunk; }
@@ -238,7 +243,6 @@ private:
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();
@@ -528,10 +532,6 @@ 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/render.cpp b/engines/scumm/insane/rebel1/render.cpp
index 4ee2a284189..db1f6f364f8 100644
--- a/engines/scumm/insane/rebel1/render.cpp
+++ b/engines/scumm/insane/rebel1/render.cpp
@@ -908,6 +908,9 @@ void InsaneRebel1::handleLevel14Play2BSplice(int32 curFrame, int32 maxFrame) {
if (_player)
_player->setPreserveGameVideoStateOnRelease(true);
+ // L14PLY2B continues L14PLAY2's audio stream and has no PSAD chunks of
+ // its own, matching the seamless route changes used by levels 7 and 8.
+ preserveInteractiveVideoAudioState();
clearFrameObjectPrimaryBits(1, 0x05);
clearFrameObjectPrimaryBits(2, 0x40);
_vm->_smushVideoShouldFinish = true;
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index a67ae9a8426..86859ec13b2 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -28,7 +28,7 @@
#include "scumm/file.h"
#include "scumm/scumm_v7.h"
#include "scumm/smush/rebel/anim_ra1.h"
-#include "scumm/smush/smush_player.h"
+#include "scumm/smush/rebel/smush_player_ra1.h"
#include "scumm/insane/rebel1/rebel.h"
namespace Scumm {
@@ -1540,45 +1540,20 @@ void InsaneRebel1::resetInteractiveVideoAudio() {
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];
- }
+ // RA1's internal route changes are logical stream ends. Taking the existing
+ // EOF exit avoids the shared SMUSH forced-stop reset without changing it.
+ if (splayer)
+ static_cast<SmushPlayerRebel1 *>(splayer)->markLogicalEndOfStream();
}
void InsaneRebel1::setupInteractiveVideoState(int32 startFrame) {
const bool level7RouteSplice = (_currentLevel == 6 && _levelRouteIndex > 0);
+ const bool walkerRouteReplay = (_currentLevel == 7 && _walkerRoundReplay);
const bool resumingRoute = startFrame > 0;
- const bool preserveRuntimeState = _preserveInteractiveRuntimeState || resumingRoute || level7RouteSplice;
- const bool preserveVideoState = !_preserveInteractiveRuntimeState && resumingRoute && !level7RouteSplice;
+ const bool preserveRuntimeState = _preserveInteractiveRuntimeState || resumingRoute ||
+ level7RouteSplice || walkerRouteReplay;
+ const bool preserveVideoState = walkerRouteReplay ||
+ (!_preserveInteractiveRuntimeState && resumingRoute && !level7RouteSplice);
SmushPlayer *splayer = _vm->_splayer;
_player = splayer;
@@ -1647,7 +1622,8 @@ void InsaneRebel1::resolveSeek(const char *filename, int32 startFrame, int32 &vi
void InsaneRebel1::captureInteractiveVideoInput() {
const bool level7RouteSplice = (_currentLevel == 6 && _levelRouteIndex > 0);
- const bool preserveInputState = _preserveInteractiveRuntimeState || level7RouteSplice;
+ const bool walkerRouteReplay = (_currentLevel == 7 && _walkerRoundReplay);
+ const bool preserveInputState = _preserveInteractiveRuntimeState || level7RouteSplice || walkerRouteReplay;
enableIOSGamepadController();
@@ -1681,7 +1657,6 @@ void InsaneRebel1::releaseInteractiveVideoInput() {
void InsaneRebel1::playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame) {
_vm->_splayer->play(filename, 15, videoOffset, videoStartFrame);
restoreScreenFlashPalette();
- restoreInteractiveVideoAudioState();
_interactiveVideoActive = false;
}
@@ -1696,8 +1671,10 @@ void InsaneRebel1::playInteractiveVideo(const char *filename, int32 startFrame)
_interactiveVideoCheatSkipped = false;
int32 videoStartFrame = 0;
int32 videoOffset = 0;
+ const bool walkerRouteReplay = (_currentLevel == 7 && _walkerRoundReplay);
const bool preserveRuntimeState = _preserveInteractiveRuntimeState ||
- (startFrame > 0) || (_currentLevel == 6 && _levelRouteIndex > 0);
+ (startFrame > 0) || (_currentLevel == 6 && _levelRouteIndex > 0) ||
+ walkerRouteReplay;
if (!preserveRuntimeState)
resetInteractiveVideoAudio();
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index 422c69f601a..b2dae0b0a61 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -217,6 +217,12 @@ void SmushPlayerRebel1::initGameVideoState() {
}
void SmushPlayerRebel1::releaseGameVideoState() {
+ // Walker routes use a logical stream end at their terminal GAME counter.
+ // Retain the same state if a route instead reaches physical EOF.
+ if (_endOfFile && _insane &&
+ static_cast<InsaneRebel1 *>(_insane)->shouldPreserveWalkerRouteVideoState())
+ return;
+
free(_storedFobjData);
_storedFobjData = nullptr;
_storedFobjDataSize = 0;
@@ -520,6 +526,17 @@ bool SmushPlayerRebel1::handleGameAnimHeader(byte *headerContent) {
void SmushPlayerRebel1::handleGameParseNextFrame() {
processDispatches(_smushAudioSampleRate / _speed);
+
+ // The DOS walker loop changes/replays its route without closing the logical
+ // SMUSH stream. Its files request a stop on GAME counter 2629, before physical
+ // EOF. Route this RA1-only continuation through the normal EOF exit, which
+ // leaves audio tracks alive; releaseGameVideoState() retains the STOR object.
+ if (_insane && static_cast<InsaneRebel1 *>(_insane)->shouldPreserveWalkerRouteOnStop())
+ markLogicalEndOfStream();
+}
+
+void SmushPlayerRebel1::markLogicalEndOfStream() {
+ _endOfFile = true;
}
bool SmushPlayerRebel1::handleGameFrameBufferSelect(int codec, int width, int height) {
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.h b/engines/scumm/smush/rebel/smush_player_ra1.h
index d77a9c989d3..fbcdfc05650 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.h
+++ b/engines/scumm/smush/rebel/smush_player_ra1.h
@@ -60,6 +60,7 @@ protected:
void handleGameUpdateScreen(const byte *src, int srcPitch, int width, int height) override;
private:
+ void markLogicalEndOfStream();
void ra1HandleGost(int32 subSize, Common::SeekableReadStream &b);
void ra1HandleDeltaPalette(int32 subSize, Common::SeekableReadStream &b);
void ra1HandleFade(int32 subSize, Common::SeekableReadStream &b);
Commit: 4761d421591c5a64a6f50c9d8dfb0b73a0a046be
https://github.com/scummvm/scummvm/commit/4761d421591c5a64a6f50c9d8dfb0b73a0a046be
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-08-15T12:19:11+02:00
Commit Message:
SCUMM: RA1: fixed axis consistency for joystick for some levels
Changed paths:
engines/scumm/insane/rebel1/iact.cpp
diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 24ada67a4ac..e9d38369534 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -892,14 +892,16 @@ bool InsaneRebel1::updateGamepadReticleAim(int16 &inputX, int16 &inputY, bool *u
(_vm->getActionState(kScummActionInsaneRight) ? 1 : 0) -
(_vm->getActionState(kScummActionInsaneLeft) ? 1 : 0);
int dpadY =
- (_vm->getActionState(kScummActionInsaneUp) ? 1 : 0) -
- (_vm->getActionState(kScummActionInsaneDown) ? 1 : 0);
+ (_vm->getActionState(kScummActionInsaneDown) ? 1 : 0) -
+ (_vm->getActionState(kScummActionInsaneUp) ? 1 : 0);
const int16 analogAxisX = applyRebel1AnalogDeadzone(_joystickAxisX);
const int16 analogAxisY = applyRebel1AnalogDeadzone(_joystickAxisY);
const int analogX = CLIP<int32>(((int32)analogAxisX * kRA1CenteredAxisMax) / Common::JOYAXIS_MAX,
-kRA1CenteredAxisMax, kRA1CenteredAxisMax);
- int analogY = CLIP<int32>((-(int32)analogAxisY * kRA1Op0BVerticalAxisMax) / Common::JOYAXIS_MAX,
+ // DOS FUN_231BE leaves joystick-up negative, and the opcode 0x0B handler
+ // (FUN_1CDA7) negates Y when it computes the on-screen flight position.
+ int analogY = CLIP<int32>(((int32)analogAxisY * kRA1Op0BVerticalAxisMax) / Common::JOYAXIS_MAX,
-kRA1Op0BVerticalAxisMax, kRA1Op0BVerticalAxisMax);
if (_optControlsYFlip) {
More information about the Scummvm-git-logs
mailing list