[Scummvm-git-logs] scummvm master -> 41ac2b31847622d0662d22c03fe6979e3b43cfbc
neuromancer
noreply at scummvm.org
Sat Sep 5 12:15:15 UTC 2026
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
ee1506a178 SCUMM: RA2: text parser now preserves intentionally empty entries
41ac2b3184 SCUMM: RA2: fixed corrupted frames in L13
Commit: ee1506a178e3c435ecb6ebc7d477ecac844f3fee
https://github.com/scummvm/scummvm/commit/ee1506a178e3c435ecb6ebc7d477ecac844f3fee
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-05T14:02:17+02:00
Commit Message:
SCUMM: RA2: text parser now preserves intentionally empty entries
Changed paths:
engines/scumm/smush/rebel/smush_player_ra2.cpp
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.cpp b/engines/scumm/smush/rebel/smush_player_ra2.cpp
index 8343288cef9..b23dd943e87 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra2.cpp
@@ -543,20 +543,21 @@ public:
data_start++;
char *data_end = data_start;
- while (1) {
+ while (data_end < buffer + length) {
if (data_end[-2] == '\r' && data_end[-1] == '\n' && data_end[0] == '\r' && data_end[1] == '\n') break;
if (data_end[-2] == '\n' && data_end[-1] == '\n') break;
if (data_end[-2] == '\r' && data_end[-1] == '\n' && data_end[0] == '#') break;
data_end++;
- if (data_end >= buffer + length) { data_end = buffer + length; break; }
}
data_end -= 2;
- if (data_end <= data_start) { def_start = strchr(def_end + 1, '#'); continue; }
+ // Retail TRS_DEMO_TEXT is defined but empty. Keep its entry so the
+ // intro's final TRES cue does not resolve to "unknown string".
+ if (data_end < data_start)
+ data_end = data_start;
- if (data_start[0] == '/' && data_start[1] == '/')
+ if (data_end - data_start >= 2 && data_start[0] == '/' && data_start[1] == '/')
data_start += 2;
- if (data_end <= data_start) { def_start = strchr(def_end + 1, '#'); continue; }
char *value = new char[data_end - data_start + 1];
memcpy(value, data_start, data_end - data_start);
@@ -581,7 +582,7 @@ public:
} else {
delete[] value;
}
- def_start = strchr(data_end + 2, '#');
+ def_start = strchr(data_end, '#');
}
return true;
}
Commit: 41ac2b31847622d0662d22c03fe6979e3b43cfbc
https://github.com/scummvm/scummvm/commit/41ac2b31847622d0662d22c03fe6979e3b43cfbc
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-05T14:02:17+02:00
Commit Message:
SCUMM: RA2: fixed corrupted frames in L13
Changed paths:
engines/scumm/insane/rebel2/render.cpp
engines/scumm/smush/rebel/smush_player_ra2.cpp
engines/scumm/smush/rebel/smush_player_ra2.h
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 9fde6727c1b..ab2c7d0c858 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -2476,7 +2476,7 @@ void InsaneRebel2::procPostRendering(byte *renderBitmap, int32 codecparam, int32
// End the looping attack-run segment once the shield/reactor is destroyed.
if (_rebelShieldGateActive) {
// Level 13: the finale (continuation segment, flag 0x40) ends when the last armed
- // group (the reactor) is depleted; the approach segment plays fully.
+ // group (the reactor) is depleted.
if (_rebelReactorMode && _rebelGaugeArmed && _rebelLastArmedSlot >= 0 &&
(_player->_curVideoFlags & 0x40) != 0) {
const int slot = _rebelLastArmedSlot;
@@ -2486,6 +2486,15 @@ void InsaneRebel2::procPostRendering(byte *renderBitmap, int32 codecparam, int32
}
if (_rebelShieldDestroyed)
_vm->_smushVideoShouldFinish = true;
+
+ // The original level 13 switches at frame count - 10. The remaining
+ // nine frames overlap the cached LOAD bridge that precedes 13PLAY_B.
+ if (_rebelReactorMode && maxFrame >= 9 && curFrame == maxFrame - 9 &&
+ !static_cast<SmushPlayerRebel2 *>(_player)->isPlayingLoadBuffer() &&
+ !_vm->_smushVideoShouldFinish) {
+ // Use normal EOF handling so queued audio survives the handoff.
+ _player->_endOfFile = true;
+ }
}
const int hudScale = isHiRes() ? 2 : getRebel2IndicatorScale(width, height);
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.cpp b/engines/scumm/smush/rebel/smush_player_ra2.cpp
index b23dd943e87..a0fd008b0c0 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra2.cpp
@@ -21,6 +21,7 @@
#include "common/config-manager.h"
#include "common/endian.h"
+#include "common/memstream.h"
#include "common/rect.h"
#include "common/system.h"
@@ -158,6 +159,10 @@ void SmushPlayerRebel2::initGamePlayerFields() {
_loadReadOffset = 8;
_lastLoadChunkIdx = -1;
_loadStreamId = 0;
+ _loadPlaybackPending = false;
+ _loadContinuationStream = nullptr;
+ _loadContinuationSize = 0;
+ _loadContinuationFrameCount = 0;
_ra2FrameSourceSkipX = 0;
_ra2FrameSourceSkipY = 0;
_ra2FrameObjectOriginalWidth = 0;
@@ -182,6 +187,8 @@ void SmushPlayerRebel2::initGamePlayerFields() {
}
void SmushPlayerRebel2::destroyGamePlayerFields() {
+ delete _loadContinuationStream;
+ _loadContinuationStream = nullptr;
delete _multiFont;
_multiFont = nullptr;
free(_storedFobjData);
@@ -213,6 +220,7 @@ void SmushPlayerRebel2::ra2InitAudioTrackSizes() {
}
void SmushPlayerRebel2::initGameVideoState() {
+ _loadPlaybackPending = (_curVideoFlags & 0x40) != 0;
_ra2PendingAnimHeaderPalette = false;
_ra2UsingGameplaySurface = false;
_smushAudioTable[100] = 0;
@@ -232,6 +240,9 @@ void SmushPlayerRebel2::initGameVideoState() {
}
void SmushPlayerRebel2::releaseGameVideoState() {
+ delete _loadContinuationStream;
+ _loadContinuationStream = nullptr;
+ _loadPlaybackPending = false;
free(_lastFobjData);
_lastFobjData = nullptr;
_lastFobjDataSize = 0;
@@ -1245,9 +1256,59 @@ void SmushPlayerRebel2::ra2HandleGost(int32 subSize, Common::SeekableReadStream
}
void SmushPlayerRebel2::handleGameParseNextFrame() {
+ if (_loadPlaybackPending) {
+ _loadPlaybackPending = false;
+ ra2StartLoadPlayback();
+ } else if (_loadContinuationStream && _base->pos() >= _baseSize) {
+ delete _base;
+ _base = _loadContinuationStream;
+ _baseSize = _loadContinuationSize;
+ _nbframes = _loadContinuationFrameCount;
+ _loadContinuationStream = nullptr;
+ _frame = 0;
+ _startFrame = 0;
+ _startTime = _vm->_system->getMillis();
+ _pauseTime = 0;
+ }
processDispatches(_smushAudioSampleRate / 12);
}
+void SmushPlayerRebel2::ra2StartLoadPlayback() {
+ // Continuation movies omit the opening frames stored in the preceding
+ // movie's LOAD chunks. Play these first, including their keyframe, and
+ // retain the decoder when returning to the continuation on disk.
+ if (!_loadBuffer || _loadBufferOffset < 22 ||
+ READ_BE_UINT32(_loadBuffer) != MKTAG('A', 'N', 'I', 'M') ||
+ READ_BE_UINT32(_loadBuffer + 8) != MKTAG('A', 'H', 'D', 'R'))
+ return;
+
+ const uint32 animSize = READ_BE_UINT32(_loadBuffer + 4);
+ const uint32 headerSize = READ_BE_UINT32(_loadBuffer + 12);
+ if (animSize > (uint32)_loadBufferOffset - 8 || animSize < 8 ||
+ headerSize < 0x306 || headerSize > animSize - 8) {
+ warning("SmushPlayerRebel2::ra2StartLoadPlayback: incomplete LOAD animation");
+ return;
+ }
+
+ const uint32 frameOffset = 16 + headerSize;
+ const uint16 frameCount = READ_LE_UINT16(_loadBuffer + 18);
+ if (frameCount == 0 || frameOffset >= animSize + 8)
+ return;
+
+ Common::MemoryReadStream loaded(_loadBuffer, animSize + 8);
+ loaded.seek(frameOffset);
+ Common::SeekableReadStream *frames = loaded.readStream(animSize + 8 - frameOffset);
+
+ // The disk AHDR has already been consumed. Keep its palette and resume
+ // at its first FRME after the cached animation, without releasing SMUSH.
+ _loadContinuationStream = _base;
+ _loadContinuationSize = _baseSize;
+ _loadContinuationFrameCount = _nbframes;
+ _base = frames;
+ _baseSize = frames->size();
+ _nbframes = frameCount;
+}
+
bool SmushPlayerRebel2::handleGameFrameBufferSelect(int codec, int width, int height) {
if ((height != _vm->_screenHeight) || (width != _vm->_screenWidth)) {
return ra2SelectFrameBuffer(codec, width, height);
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.h b/engines/scumm/smush/rebel/smush_player_ra2.h
index 28036038f3c..3c8b37568ce 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.h
+++ b/engines/scumm/smush/rebel/smush_player_ra2.h
@@ -32,6 +32,7 @@ public:
~SmushPlayerRebel2() override;
bool ra2PromoteCurrentFrameToHiRes(int scrollX, int scrollY);
bool ra2PromoteHandler7PerspectiveToHiRes(int perspectiveX, int perspectiveY, int viewShift);
+ bool isPlayingLoadBuffer() const { return _loadContinuationStream != nullptr; }
protected:
void initGamePlayerFields() override;
@@ -68,6 +69,7 @@ protected:
private:
void handleLoad(int32 subSize, Common::SeekableReadStream &b);
+ void ra2StartLoadPlayback();
void ra2HandleTextResource(const char *str, int fontId, int color,
int pos_x, int pos_y, int left, int top,
int width, int height, TextStyleFlags flg);
@@ -94,6 +96,10 @@ private:
int32 _loadReadOffset;
int16 _lastLoadChunkIdx;
int16 _loadStreamId;
+ bool _loadPlaybackPending;
+ Common::SeekableReadStream *_loadContinuationStream;
+ uint32 _loadContinuationSize;
+ int32 _loadContinuationFrameCount;
int _ra2FrameSourceSkipX;
int _ra2FrameSourceSkipY;
int _ra2FrameObjectOriginalWidth;
More information about the Scummvm-git-logs
mailing list