[Scummvm-git-logs] scummvm master -> 451d0c195de21201604c63f2ca71c208edc2a296
neuromancer
noreply at scummvm.org
Wed Jun 17 19:46:09 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:
45bacff1fa SCUMM: RA2: start level 2 and level 11 in cover state
451d0c195d SCUMM: RA2: make sure translucid destroyable shields are properly handled
Commit: 45bacff1faa381a812d8a68eb0659a30acf0c5fd
https://github.com/scummvm/scummvm/commit/45bacff1faa381a812d8a68eb0659a30acf0c5fd
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-17T17:03:28+02:00
Commit Message:
SCUMM: RA2: start level 2 and level 11 in cover state
Changed paths:
engines/scumm/insane/rebel2/runlevels.cpp
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 5f1e95858b4..2cb6b634a09 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -312,6 +312,11 @@ void InsaneRebel2::resetLevelPhaseState(bool clearEnemies) {
if (clearEnemies)
_enemies.clear();
+
+ if (_selectedChapter == 1 || _selectedChapter == 10) {
+ _rebelAutopilot = 1;
+ _rebelDamageLevel = 5;
+ }
}
void InsaneRebel2::clearEmbeddedHudFrames() {
Commit: 451d0c195de21201604c63f2ca71c208edc2a296
https://github.com/scummvm/scummvm/commit/451d0c195de21201604c63f2ca71c208edc2a296
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-17T21:41:25+02:00
Commit Message:
SCUMM: RA2: make sure translucid destroyable shields are properly handled
Changed paths:
engines/scumm/insane/rebel2/iact.cpp
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/runlevels.cpp
engines/scumm/smush/rebel/codec_ra2.cpp
engines/scumm/smush/rebel/codec_ra2.h
engines/scumm/smush/rebel/smush_player_ra2.cpp
engines/scumm/smush/rebel/smush_player_ra2.h
diff --git a/engines/scumm/insane/rebel2/iact.cpp b/engines/scumm/insane/rebel2/iact.cpp
index 02493b26fbc..c4d52b41477 100644
--- a/engines/scumm/insane/rebel2/iact.cpp
+++ b/engines/scumm/insane/rebel2/iact.cpp
@@ -2699,6 +2699,18 @@ void InsaneRebel2::enemyUpdate(byte *renderBitmap, Common::SeekableReadStream &b
int16 w = b.readSint16LE(); // Offset +14 (0x0E) - Width
int16 h = b.readSint16LE(); // Offset +16 (0x10) - Height
+ // par3==2 (turret handler) marks a translucent surface / force field (FUN_40A2E0 local_8==2):
+ // never a direct hit target â it is destroyed by clearing the gauge group (par4) it depends
+ // on. Show it while that group still has elements, hide it once the group is cleared.
+ if (par3 == 2 && _rebelHandler == 0x26) {
+ const int surfaceIdx = (par4 >= 100 && par4 < 110) ? (par4 - 100) : -1;
+ if (surfaceIdx >= 0 && _rebelGaugeCleared[surfaceIdx])
+ setBit(enemyId);
+ else
+ clearBit(enemyId);
+ return; // surfaces are not added to the hittable enemy list
+ }
+
// If disabled, stop processing this object
if (disabled) {
// debugC(DEBUG_INSANE, "Skipping Opcode 4 for disabled enemy ID=%d", enemyId);
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 6b574ec9675..02f9442f926 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -246,6 +246,8 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
_rebelReactorMode = false;
_rebelGaugeArmed = false;
_rebelLastArmedSlot = -1;
+ for (int i = 0; i < 10; ++i)
+ _rebelGaugeCleared[i] = false;
_difficulty = 1; // Default to Medium.
_targetLockTimer = 0; // DAT_00443676 equivalent
@@ -1761,11 +1763,15 @@ int32 InsaneRebel2::processMouse() {
if (*counter > 0) {
(*counter)--;
_rebelLastCounter = *counter;
- // Level 6 ends on any group emptying; Level 13's reactor is gated in
- // procPostRendering instead, so early obstacle groups don't complete it.
- if (*counter == 0 && !_rebelReactorMode) {
- _rebelShieldDestroyed = true;
- debugC(DEBUG_INSANE, "Shield destroyed (gauge slot %d depleted by target %d)", slot, it->id);
+ if (*counter == 0) {
+ if (slot < 10)
+ _rebelGaugeCleared[slot] = true; // group emptied â its par3==2 surface can drop
+ // Level 6 ends on any group emptying; Level 13's reactor is gated in
+ // procPostRendering instead, so early obstacle groups don't complete it.
+ if (!_rebelReactorMode) {
+ _rebelShieldDestroyed = true;
+ debugC(DEBUG_INSANE, "Shield destroyed (gauge slot %d depleted by target %d)", slot, it->id);
+ }
}
}
_rebelGaugeSlot[it->id] = -1; // consume: avoid double-counting
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 5fb614c8009..008bb55b591 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -970,6 +970,7 @@ public:
bool _rebelReactorMode; // Level 13: finale ends when the last armed group is cleared
bool _rebelGaugeArmed; // at least one gauge group has been set up this attempt
int _rebelLastArmedSlot; // counter slot of the most recently armed group (-1 = none)
+ bool _rebelGaugeCleared[10]; // value-counter slot fully destroyed (drives par3==2 surfaces)
void resetShieldGauge();
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 2cb6b634a09..15ed6c0e9e3 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -349,6 +349,8 @@ void InsaneRebel2::resetShieldGauge() {
_rebelShieldDestroyed = false;
_rebelGaugeArmed = false;
_rebelLastArmedSlot = -1;
+ for (int i = 0; i < 10; ++i)
+ _rebelGaugeCleared[i] = false;
}
void InsaneRebel2::resetExplosions() {
diff --git a/engines/scumm/smush/rebel/codec_ra2.cpp b/engines/scumm/smush/rebel/codec_ra2.cpp
index e528d51f8a9..cb6100a7e6d 100644
--- a/engines/scumm/smush/rebel/codec_ra2.cpp
+++ b/engines/scumm/smush/rebel/codec_ra2.cpp
@@ -225,6 +225,44 @@ void smushDecodeSkipRLE(byte *dst, const byte *src, int left, int top, int width
}
}
+// Codec 23: a skip/run RLE that tints the background in place (no pixel data). Per line,
+// lineDataSize(2) then [skip(1), run(1)] pairs; each run pixel becomes remap[background]
+// (translucency) or background+addColor.
+void smushDecodeRA2SkipRemap(byte *dst, const byte *src, int left, int top, int width, int height, int pitch, int dataSize, const byte *remap, byte addColor) {
+ dst += top * pitch + left;
+ const byte *srcEnd = src + dataSize;
+
+ for (int row = 0; row < height; row++) {
+ if (src + 2 > srcEnd)
+ break;
+ int lineDataSize = READ_LE_UINT16(src);
+ src += 2;
+ const byte *lineStart = src;
+ const byte *lineEnd = (lineStart + lineDataSize <= srcEnd) ? lineStart + lineDataSize : srcEnd;
+ byte *lineDst = dst;
+ int x = 0;
+
+ while (x < width && src < lineEnd) {
+ x += *src++; // skip (preserve background)
+ if (x >= width || src >= lineEnd)
+ break;
+ int run = *src++;
+ if (run > width - x)
+ run = width - x;
+ if (remap) {
+ for (int i = 0; i < run; i++, x++)
+ lineDst[x] = remap[lineDst[x]];
+ } else {
+ for (int i = 0; i < run; i++, x++)
+ lineDst[x] = (byte)(lineDst[x] + addColor);
+ }
+ }
+
+ src = lineStart + lineDataSize;
+ dst += pitch;
+ }
+}
+
bool smushPrepareRA2BlurData(const byte *src, int dataSize, byte *palette, byte *lookup, const byte *&maskData, int &maskSize) {
maskData = nullptr;
maskSize = 0;
diff --git a/engines/scumm/smush/rebel/codec_ra2.h b/engines/scumm/smush/rebel/codec_ra2.h
index b89797c1a0a..42911065cb0 100644
--- a/engines/scumm/smush/rebel/codec_ra2.h
+++ b/engines/scumm/smush/rebel/codec_ra2.h
@@ -29,6 +29,7 @@ namespace Scumm {
void smushDecodeRLEOpaque(byte *dst, const byte *src, int left, int top, int width, int height, int pitch, int dataSize);
void smushDecodeLineUpdate(byte *dst, const byte *src, int left, int top, int width, int height, int pitch, int dataSize);
void smushDecodeSkipRLE(byte *dst, const byte *src, int left, int top, int width, int height, int pitch, int dataSize);
+void smushDecodeRA2SkipRemap(byte *dst, const byte *src, int left, int top, int width, int height, int pitch, int dataSize, const byte *remap, byte addColor);
void smushDecodeRA2Blur(byte *dst, const byte *src, int left, int top, int dstWidth, int dstHeight, int pitch, int dataSize, byte *palette, byte *lookup);
const byte *smushSkipRLELines(const byte *src, int &dataSize, int lines);
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.cpp b/engines/scumm/smush/rebel/smush_player_ra2.cpp
index 339b2101206..f0455eea3dc 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra2.cpp
@@ -189,6 +189,8 @@ void SmushPlayerRebel2::initGamePlayerFields() {
_ra2PendingAnimHeaderPalette = false;
memset(_ra2Codec45Palette, 0, sizeof(_ra2Codec45Palette));
memset(_ra2Codec45Lookup, 0, sizeof(_ra2Codec45Lookup));
+ memset(_ra2SkipRemapTable, 0, sizeof(_ra2SkipRemapTable));
+ _ra2SkipRemapValid = false;
_scrollX = 0;
_scrollY = 0;
}
@@ -1440,11 +1442,53 @@ bool SmushPlayerRebel2::handleGameCodecDecode(int codec, const uint8 *src, int l
if (isRebel2FullFrameDeltaCodec(codec))
return ra2DecodePlacedDeltaCodec(codec, src, left, top, width, height, pitch, dataSize);
+ // Codec 23 translucent surfaces: parm2 0x100 prefixes a fresh 256-byte remap table, >=0x100
+ // reuses the last one. (Font glyphs call smushDecodeSkipRLE directly and are unaffected.)
+ if (codec == SMUSH_CODEC_SKIP_RLE && parm2 >= 0x100) {
+ if (parm2 == 0x100 && dataSize >= 256) {
+ memcpy(_ra2SkipRemapTable, src, 256);
+ _ra2SkipRemapValid = true;
+ src += 256;
+ dataSize -= 256;
+ }
+ const byte *remap = _ra2SkipRemapValid ? _ra2SkipRemapTable : nullptr;
+ smushDecodeRA2SkipRemap(_dst, src, left, top, width, height, pitch, dataSize, remap, (byte)parm2);
+ return true;
+ }
+
// Handle RA2-specific codecs (21, 23, 44, 45); return false for standard
// codecs (RLE) so the base class decodes them.
return ra2DecodeCodec(codec, src, left, top, width, height, pitch, dataSize);
}
+// Mirrors SmushPlayer::handleFrameObject but forwards the FOBJ parm2 word (base discards it).
+void SmushPlayerRebel2::handleFrameObject(int32 subSize, Common::SeekableReadStream &b) {
+ assert(subSize >= 14);
+ if (_skipNext) {
+ _skipNext = false;
+ return;
+ }
+
+ int codec = b.readUint16LE();
+ int left = (int)b.readSint16LE();
+ int top = (int)b.readSint16LE();
+ int width = b.readUint16LE();
+ int height = b.readUint16LE();
+ b.readUint16LE(); // objectId
+ uint16 parm2 = b.readUint16LE();
+
+ const int32 chunkSize = subSize - 14;
+ handleGameFrameObjectPre(codec, left, top, width, height, chunkSize);
+
+ byte *chunkBuffer = (byte *)malloc(chunkSize);
+ assert(chunkBuffer);
+ b.read(chunkBuffer, chunkSize);
+
+ handleGameFrameObjectPost(codec, chunkBuffer, chunkSize, left, top, width, height);
+ decodeFrameObject(codec, chunkBuffer, left, top, width, height, chunkSize, 0, parm2);
+ free(chunkBuffer);
+}
+
bool SmushPlayerRebel2::handleGameStoreFrame() {
// RA2 handles STOR via ra2StoreFobjData in handleGameFrameObjectPost
return true;
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.h b/engines/scumm/smush/rebel/smush_player_ra2.h
index c3c87e8ea75..b1628a1a302 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.h
+++ b/engines/scumm/smush/rebel/smush_player_ra2.h
@@ -38,6 +38,8 @@ protected:
void initGameVideoState() override;
void releaseGameVideoState() override;
bool shouldPreserveFrameBuffer() const override { return true; }
+ // Override to keep the FOBJ parm2 field (codec 23 marker) the base reader discards.
+ void handleFrameObject(int32 subSize, Common::SeekableReadStream &b) override;
bool handleGameFetch(int32 subSize, Common::SeekableReadStream &b) override;
bool handleGameTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &b) override;
bool handleGameTextRendering(const char *str, int fontId, int color, int pos_x, int pos_y, int left, int top, int width, int height, TextStyleFlags flg) override;
@@ -110,6 +112,8 @@ private:
bool _ra2PendingAnimHeaderPalette;
byte _ra2Codec45Palette[0x300];
byte _ra2Codec45Lookup[0x8000];
+ byte _ra2SkipRemapTable[256]; // codec 23 translucency remap table
+ bool _ra2SkipRemapValid;
};
} // End of namespace Scumm
More information about the Scummvm-git-logs
mailing list