[Scummvm-git-logs] scummvm master -> 9bd7e608b0a40d727173fe58e33eee9a62c00143
neuromancer
noreply at scummvm.org
Thu Jul 2 07:36:13 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:
dcf866ae5e SCUMM: RA2: implemented missing turret shakes
52e384bc91 SCUMM: RA2: fixed swap of BLAST and TBLASH
c5caf2532b SCUMM: RA2: improved death video selection in some levels
9bd7e608b0 SCUMM: RA2: fixed explosions position in high resolution mode for L10
Commit: dcf866ae5e0d9124b4168e96ecba1ad4bdcb0c96
https://github.com/scummvm/scummvm/commit/dcf866ae5e0d9124b4168e96ecba1ad4bdcb0c96
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-02T09:35:53+02:00
Commit Message:
SCUMM: RA2: implemented missing turret shakes
Changed paths:
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/render.cpp
engines/scumm/insane/rebel2/runlevels.cpp
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index aec354ca8de..99d12243603 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -246,6 +246,10 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
_rebelValueCounters[i] = 0;
_rebelGaugeBlink[i] = 0;
}
+ for (int i = 0; i < 15; ++i) {
+ _turretShakeRingX[i] = 0;
+ _turretShakeRingY[i] = 0;
+ }
_rebelLastCounter = 0;
_rebelShieldGateActive = false;
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index edd517494b4..9be6c5d3464 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -698,6 +698,10 @@ public:
short _rebelGaugeBlink[10];
int _rebelLastCounter;
+ // Turret dodge-fail view-shake impulses, ring-filtered into the scroll offset.
+ int16 _turretShakeRingX[15];
+ int16 _turretShakeRingY[15];
+
bool _rebelShieldGateActive;
bool _rebelShieldDestroyed;
bool _rebelReactorMode;
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 23a73c2c0a7..04f2d73238f 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -1587,7 +1587,12 @@ void InsaneRebel2::checkCollisionZones(byte *renderBitmap, int pitch, int width,
}
if (!_noDamage)
initDamageFlash();
- playSfx(1, 127, CLIP(((cx1 + cx2 + cx3 + cx4) / 4) * -4, -127, 127));
+ const int hitAvgX = (cx1 + cx2 + cx3 + cx4) / 4;
+ const int hitAvgY = (cy1 + cy2 + cy3 + cy4) / 4;
+ playSfx(1, 127, CLIP(hitAvgX * -4, -127, 127));
+ // The amplified impulse enters the shake ring and decays over the next 14 frames.
+ _turretShakeRingX[14] = (int16)(CLIP(hitAvgX, -0x2b, 0x2b) * 8);
+ _turretShakeRingY[14] = (int16)(CLIP(hitAvgY, -0x19, 0x19) * 8);
} else {
if (dparams.dodgePoints > 0) {
addScore(dparams.dodgePoints);
@@ -2106,6 +2111,30 @@ void InsaneRebel2::updatePostRenderScroll(int width, int height) {
_viewX = (aimPos.x * maxScrollX) / viewportWidth;
_viewY = (aimPos.y * maxScrollY) / viewportHeight;
+ if (_rebelHandler == 0x26) {
+ // Dodge-fail view shake: the hit impulse travels a 15-slot weighted ring
+ // and nudges the scroll, with a +-5 jitter while the damage flash runs.
+ static const int16 kShakeWeights[14] = { 1, 1, 2, 2, 3, 3, 4, 8, 14, 16, 16, 14, 12, 6 };
+ int shakeX = 0, shakeY = 0, weightSum = 2;
+ for (int i = 0; i < 14; i++) {
+ _turretShakeRingX[i] = _turretShakeRingX[i + 1];
+ _turretShakeRingY[i] = _turretShakeRingY[i + 1];
+ shakeX += _turretShakeRingX[i] * kShakeWeights[i];
+ shakeY += _turretShakeRingY[i] * kShakeWeights[i];
+ weightSum += kShakeWeights[i];
+ }
+ _turretShakeRingX[14] = 0;
+ _turretShakeRingY[14] = 0;
+ shakeX /= weightSum;
+ shakeY /= weightSum;
+ if (_damageFlashCounter > 0) {
+ shakeX += _vm->_rnd.getRandomNumber(9) - 5;
+ shakeY += _vm->_rnd.getRandomNumber(9) - 5;
+ }
+ _viewX = CLIP<int>(_viewX + shakeX, 0, maxScrollX);
+ _viewY = CLIP<int>(_viewY + shakeY, 0, maxScrollY);
+ }
+
_player->setScrollOffset(_viewX, _viewY);
}
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 3789770b50a..973143de9e7 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -298,6 +298,10 @@ void InsaneRebel2::resetShieldGauge() {
_rebelValueCounters[i] = 0;
_rebelGaugeBlink[i] = 0;
}
+ for (int i = 0; i < 15; ++i) {
+ _turretShakeRingX[i] = 0;
+ _turretShakeRingY[i] = 0;
+ }
_rebelLastCounter = -1; // non-zero sentinel: gauge not yet depleted
_rebelShieldDestroyed = false;
_rebelGaugeArmed = false;
Commit: 52e384bc91b2b166293ca3d64bdb9ea82260093b
https://github.com/scummvm/scummvm/commit/52e384bc91b2b166293ca3d64bdb9ea82260093b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-02T09:35:53+02:00
Commit Message:
SCUMM: RA2: fixed swap of BLAST and TBLASH
Changed paths:
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/render.cpp
engines/scumm/insane/rebel2/runlevels.cpp
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 99d12243603..1b63fcff4ae 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -191,6 +191,7 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
_enemies.clear();
_rebelHandler = 0;
_rebelLevelType = 0;
+ _level15SecondHalf = false;
_rebelStatusBarSprite = 0;
_introCursorPushed = false;
@@ -1281,29 +1282,26 @@ const InsaneRebel2::LevelDifficultyParams InsaneRebel2::kDifficultyTable[6][17]
},
};
-InsaneRebel2::LevelDifficultyParams InsaneRebel2::getDifficultyParams() const {
- int diff = CLIP(_difficulty, 0, 5);
- int lvIdx = 0;
-
+int InsaneRebel2::getDifficultyRow() const {
// Index mapping reconstructed from level handlers:
// Lv1->0, Lv2->1, Lv3->2, Lv4->3, Lv5->4,
// Lv6A->5, Lv6B->6, Lv7->7 ... Lv14->14, Lv15A->15, Lv15B->16.
// Our Level 6 phase flow sets _currentPhase to 1/2 accordingly.
- // Level 15 switches to type 0x10 at frame 0x21e (updateLevel15TypeSwitch).
- if (_selectedLevel <= 0) {
- lvIdx = CLIP((int)_rebelLevelType, 0, 16);
- } else if (_selectedLevel <= 5) {
- lvIdx = _selectedLevel - 1;
- } else if (_selectedLevel == 6) {
- lvIdx = (_currentPhase >= 2) ? 6 : 5;
- } else if (_selectedLevel <= 14) {
- lvIdx = _selectedLevel;
- } else { // _selectedLevel == 15
- lvIdx = (_rebelLevelType >= 0x10) ? 16 : 15;
- }
+ // Level 15 hardens at frame 0x21e (updateLevel15TypeSwitch). Do not key on
+ // _rebelLevelType here: the turret opcode-6 overwrites it with the ship type.
+ if (_selectedLevel <= 0)
+ return CLIP((int)_rebelLevelType, 0, 16);
+ if (_selectedLevel <= 5)
+ return _selectedLevel - 1;
+ if (_selectedLevel == 6)
+ return (_currentPhase >= 2) ? 6 : 5;
+ if (_selectedLevel <= 14)
+ return _selectedLevel;
+ return _level15SecondHalf ? 16 : 15; // _selectedLevel == 15
+}
- lvIdx = CLIP(lvIdx, 0, 16);
- return kDifficultyTable[diff][lvIdx];
+InsaneRebel2::LevelDifficultyParams InsaneRebel2::getDifficultyParams() const {
+ return kDifficultyTable[CLIP(_difficulty, 0, 5)][getDifficultyRow()];
}
bool InsaneRebel2::applyPlayerDamage(int damage) {
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 9be6c5d3464..bf3bfe4c275 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -880,8 +880,10 @@ public:
static const LevelDifficultyParams kDifficultyTable[6][17];
+ int getDifficultyRow() const;
LevelDifficultyParams getDifficultyParams() const;
int16 getWaveBudgetBase(int phase) const;
+ bool _level15SecondHalf;
void addScore(int points);
void renderScoreHUD(byte *renderBitmap, int pitch, int width, int height, int statusBarY);
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 04f2d73238f..7746b496701 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -500,7 +500,8 @@ void InsaneRebel2::spawnShot(int x, int y) {
void InsaneRebel2::spawnTurretShot(int x, int y) {
for (int i = 0; i < 2; i++) {
if (_turretShots[i].counter == 0) {
- playSfx((_rebelLevelType == 5) ? 0 : 7, 127, 0);
+ // Ship type 5 (the turbolaser levels 13-15) fires TBLAST, the rest BLAST.
+ playSfx((_rebelLevelType == 5) ? 7 : 0, 127, 0);
_turretShots[i].counter = getShotMaxDuration();
_turretShots[i].seqNum = _turretShotSeqCounter;
@@ -2165,9 +2166,10 @@ void InsaneRebel2::updateLevel7Fork(int32 curFrame) {
}
void InsaneRebel2::updateLevel15TypeSwitch(int32 curFrame) {
- // From frame 0x21e level 15 uses the type-0x10 difficulty column; runLevel15 resets to 0xf per attempt.
+ // From frame 0x21e level 15 uses the type-0x10 difficulty column; runLevel15 resets per attempt.
+ // Tracked as a flag because the turret opcode-6 rewrites _rebelLevelType every frame.
if (_selectedLevel == 15 && curFrame >= 0x21e)
- _rebelLevelType = 0x10;
+ _level15SecondHalf = true;
}
void InsaneRebel2::renderPostRenderMenuCursor(byte *renderBitmap, int pitch, int width, int height) {
@@ -3006,10 +3008,10 @@ void InsaneRebel2::renderStatusBarSprites(byte *renderBitmap, int pitch, int wid
int numSprites = _smush_cockpitNut->getNumChars();
const int statusScale = isHiRes() ? 2 : getRebel2IndicatorScale(width, height);
- // Critical-damage warning beep every 25 gameplay frames; volume depends on the level type.
+ // Critical-damage warning beep every 25 gameplay frames; volume depends on the difficulty row.
if (_rebelHandler != 0 && _playerDamage > 170 && (curFrame % 25) == 0) {
int alertVolume;
- switch (_rebelLevelType) {
+ switch (getDifficultyRow()) {
case 1: case 11: case 12:
alertVolume = 40;
break;
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 973143de9e7..fc04c86d6c7 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -1791,6 +1791,7 @@ int InsaneRebel2::runLevel15() {
_rebelHitCounter = 0;
_rebelLevelType = 0xf;
+ _level15SecondHalf = false;
if (!playLevelSegment("LEV15/15PLAY.SAN", 0x28))
return kLevelQuit;
Commit: c5caf2532bdc4183a476a3ab181ddf9d22abecab
https://github.com/scummvm/scummvm/commit/c5caf2532bdc4183a476a3ab181ddf9d22abecab
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-02T09:35:53+02:00
Commit Message:
SCUMM: RA2: improved death video selection in some levels
Changed paths:
engines/scumm/insane/rebel2/iact.cpp
engines/scumm/insane/rebel2/levels.cpp
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/render.cpp
engines/scumm/insane/rebel2/runlevels.cpp
diff --git a/engines/scumm/insane/rebel2/iact.cpp b/engines/scumm/insane/rebel2/iact.cpp
index c693f280798..377217722cd 100644
--- a/engines/scumm/insane/rebel2/iact.cpp
+++ b/engines/scumm/insane/rebel2/iact.cpp
@@ -396,6 +396,7 @@ void InsaneRebel2::iactRebel2Opcode3(Common::SeekableReadStream &b, int16 par2,
}
if (shouldDamage) {
+ _rebelDeathCause = 1;
if (applyPlayerDamage(directHitDamage)) {
debugC(DEBUG_INSANE, "DIRECT HIT damage from enemy %d. par3=%d par4=%d damage=%d total=%d",
srcId, par3, par4, directHitDamage, _playerDamage);
@@ -419,6 +420,7 @@ void InsaneRebel2::iactRebel2Opcode3(Common::SeekableReadStream &b, int16 par2,
debugC(DEBUG_INSANE, "Opcode3: probability=%d roll=%d (need roll < prob)", probability, roll);
if (roll < probability) {
+ _rebelDeathCause = 0;
int damageAmount = (params.shotDamage >= 0) ? params.shotDamage : 0;
if (applyPlayerDamage(damageAmount)) {
debugC(DEBUG_INSANE, "PROBABILISTIC damage from enemy %d. Damage=%d total=%d",
diff --git a/engines/scumm/insane/rebel2/levels.cpp b/engines/scumm/insane/rebel2/levels.cpp
index 48c4b69ac29..a58012ad465 100644
--- a/engines/scumm/insane/rebel2/levels.cpp
+++ b/engines/scumm/insane/rebel2/levels.cpp
@@ -693,7 +693,10 @@ Common::String InsaneRebel2::selectDeathVideoVariant(int levelId, int phase, int
return (getRandomVariant(2) == 0) ? "B" : "A";
case 9:
- return "A";
+ // Picked by what killed the player: shot -> A, direct hit -> C, collision -> B.
+ if (_rebelDeathCause == 0)
+ return "A";
+ return (_rebelDeathCause == 1) ? "C" : "B";
case 10:
return "";
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 1b63fcff4ae..d2287908bb4 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -560,6 +560,7 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
_currentPhase = 1;
_deathFrame = 0;
+ _rebelDeathCause = 0;
_skipSectionRequested = false;
_vm->_system->getEventManager()->getEventDispatcher()->registerObserver(this, 1, false);
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index bf3bfe4c275..5dd09443b3f 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -363,6 +363,7 @@ public:
int _currentPhase;
int _deathFrame;
+ int _rebelDeathCause; // 0 = enemy shot, 1 = direct hit, 2 = collision; picks the death video
bool _skipSectionRequested;
// Resources and fonts.
@@ -641,6 +642,7 @@ public:
void renderHandler7WarningCues(byte *renderBitmap, int pitch, int width, int height, int32 curFrame, uint16 warningMask);
void updateLevel7Fork(int32 curFrame);
void updateLevel15TypeSwitch(int32 curFrame);
+ void updateLevel9WaveReset(int32 curFrame);
int16 _playerDamage;
int16 _playerShield;
@@ -707,6 +709,7 @@ public:
bool _rebelReactorMode;
bool _rebelGaugeArmed;
int _rebelLastArmedSlot;
+ void resetGaugeCounters();
void resetShieldGauge();
void decrementGaugeGroup(int slot, int targetId);
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 7746b496701..c2a5abd1ff6 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -1580,6 +1580,7 @@ void InsaneRebel2::checkCollisionZones(byte *renderBitmap, int pitch, int width,
}
if (collision) {
+ _rebelDeathCause = 2;
int collisionDamage = (dparams.dodgeDamage >= 0) ? dparams.dodgeDamage : 0;
if (applyPlayerDamage(collisionDamage)) {
@@ -2159,7 +2160,7 @@ void InsaneRebel2::updateLevel7Fork(int32 curFrame) {
return;
_level7ForkActive = false;
- if (_flyShipScreenX > 0xd4) {
+ if (_flyShipScreenX + _smoothedVelocity > 0xd4) {
_level7TookRightFork = true;
_vm->_smushVideoShouldFinish = true;
}
@@ -2172,6 +2173,12 @@ void InsaneRebel2::updateLevel15TypeSwitch(int32 curFrame) {
_level15SecondHalf = true;
}
+void InsaneRebel2::updateLevel9WaveReset(int32 curFrame) {
+ // 09PLAY re-arms its gauge groups per wave; the counters clear between waves.
+ if (_selectedLevel == 9 && (curFrame == 0x19f || curFrame == 0x352))
+ resetGaugeCounters();
+}
+
void InsaneRebel2::renderPostRenderMenuCursor(byte *renderBitmap, int pitch, int width, int height) {
static const byte kRa2MenuCursor[] = {
0, 0, 1, 1, 1, 1, 1,
@@ -2461,6 +2468,7 @@ void InsaneRebel2::procPostRendering(byte *renderBitmap, int32 codecparam, int32
updatePostRenderDeath();
updateLevel7Fork(curFrame);
updateLevel15TypeSwitch(curFrame);
+ updateLevel9WaveReset(curFrame);
// End the looping attack-run segment once the shield/reactor is destroyed.
if (_rebelShieldGateActive) {
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index fc04c86d6c7..960b6689ae3 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -293,16 +293,20 @@ void InsaneRebel2::resetLevelWaveState() {
_rebelWaveState = 0;
}
-void InsaneRebel2::resetShieldGauge() {
+void InsaneRebel2::resetGaugeCounters() {
for (int i = 0; i < 10; ++i) {
_rebelValueCounters[i] = 0;
_rebelGaugeBlink[i] = 0;
}
+ _rebelLastCounter = -1; // non-zero sentinel: gauge not yet depleted
+}
+
+void InsaneRebel2::resetShieldGauge() {
+ resetGaugeCounters();
for (int i = 0; i < 15; ++i) {
_turretShakeRingX[i] = 0;
_turretShakeRingY[i] = 0;
}
- _rebelLastCounter = -1; // non-zero sentinel: gauge not yet depleted
_rebelShieldDestroyed = false;
_rebelGaugeArmed = false;
_rebelLastArmedSlot = -1;
@@ -743,16 +747,18 @@ int InsaneRebel2::runLevel4() {
}
debugC(DEBUG_INSANE, "Level 4 death");
- playLevelDeathVariant(4, 1, _deathFrame);
- if (_vm->shouldQuit())
- return kLevelQuit;
-
+ // The death video only plays on the retry path; the last life goes
+ // straight to the game-over cinematic.
_playerLives--;
if (_playerLives <= 0) {
playLevelGameOver(4);
return kLevelGameOver;
}
+ playLevelDeathVariant(4, 1, _deathFrame);
+ if (_vm->shouldQuit())
+ return kLevelQuit;
+
playLevelRetry(4);
if (_vm->shouldQuit())
return kLevelQuit;
@@ -949,7 +955,7 @@ int InsaneRebel2::runLevel7() {
// Right fork: continue into the alternate corridor segment (0x40 =
// continuation, so the ship position carries over instead of recentering).
if (_level7TookRightFork && _playerShield > 0) {
- if (!playLevelSegment("LEV07/07PLAYB.SAN", 0x68))
+ if (!playLevelSegment("LEV07/07PLAYB.SAN", 0x468))
return kLevelQuit;
}
@@ -963,7 +969,7 @@ int InsaneRebel2::runLevel7() {
// Death cinematic depends on which corridor side the player died on
// (the original keys 07DIE_B/07DIE_A on DAT_0047ab8c), independent of
// the fork frame; taking the right fork implies the right side.
- const bool diedOnRight = _level7TookRightFork || (_flyShipScreenX > 0xd4);
+ const bool diedOnRight = _level7TookRightFork || (_flyShipScreenX + _smoothedVelocity > 0xd4);
debugC(DEBUG_INSANE, "Level 7 death at frame %d, right=%d", _deathFrame, diedOnRight);
if (diedOnRight) {
playCinematic("LEV07/07DIE_B.SAN");
Commit: 9bd7e608b0a40d727173fe58e33eee9a62c00143
https://github.com/scummvm/scummvm/commit/9bd7e608b0a40d727173fe58e33eee9a62c00143
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-02T09:35:53+02:00
Commit Message:
SCUMM: RA2: fixed explosions position in high resolution mode for L10
Changed paths:
engines/scumm/insane/rebel2/iact.cpp
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/render.cpp
engines/scumm/insane/rebel2/runlevels.cpp
diff --git a/engines/scumm/insane/rebel2/iact.cpp b/engines/scumm/insane/rebel2/iact.cpp
index 377217722cd..0a3c2dd89ab 100644
--- a/engines/scumm/insane/rebel2/iact.cpp
+++ b/engines/scumm/insane/rebel2/iact.cpp
@@ -2171,6 +2171,8 @@ void InsaneRebel2::enemyUpdate(byte *renderBitmap, Common::SeekableReadStream &b
Common::List<enemy>::iterator it;
for (it = _enemies.begin(); it != _enemies.end(); ++it) {
if (it->id == enemyId) {
+ it->velX = x - it->rect.left;
+ it->velY = y - it->rect.top;
it->rect = Common::Rect(x, y, x + w, y + h);
it->type = par4;
// IACT bit state is authoritative; clear stale destruction state here.
@@ -2190,6 +2192,8 @@ void InsaneRebel2::initEnemyStruct(int id, int32 x, int32 y, int32 w, int32 h, b
e.id = id;
e.type = type;
e.rect = Common::Rect(x, y, x + w, y + h);
+ e.velX = 0;
+ e.velY = 0;
e.active = active;
e.destroyed = destroyed;
e.explosionFrame = explosionFrame;
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index d2287908bb4..acc4da6582d 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -1597,7 +1597,7 @@ int32 InsaneRebel2::processMouse() {
if (_rebelHandler != 8 && _rebelHandler != 25) {
spawnExplosion((it->rect.left + it->rect.right) / 2,
(it->rect.top + it->rect.bottom) / 2,
- explosionHalfWidth);
+ explosionHalfWidth, it->velX, it->velY);
} else if (_rebelHandler == 8 && it->type == 0) {
spawnExplosion((it->rect.left + it->rect.right) / 2,
(it->rect.top + it->rect.bottom) / 2,
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 5dd09443b3f..580cc74101f 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -538,6 +538,7 @@ public:
int id;
int type;
Common::Rect rect;
+ int velX, velY; // last per-frame motion, feeds the death explosion drift
bool active;
bool destroyed;
int explosionFrame;
@@ -584,6 +585,7 @@ public:
int width, height;
int counter;
int scale;
+ int dx, dy; // carries the victim's last motion (flight buffer space)
bool active;
};
@@ -593,7 +595,7 @@ public:
};
Explosion _explosions[5];
- void spawnExplosion(int x, int y, int objectHalfWidth);
+ void spawnExplosion(int x, int y, int objectHalfWidth, int dx = 0, int dy = 0);
// Collision zones registered by IACT opcode 5.
struct CollisionZone {
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index c2a5abd1ff6..ba1fdc120f2 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -457,7 +457,7 @@ void InsaneRebel2::loadEmbeddedSan(int userId, byte *animData, int32 size, byte
debugC(DEBUG_INSANE, "No FOBJ found in embedded SAN userId=%d", userId);
}
-void InsaneRebel2::spawnExplosion(int x, int y, int objectHalfWidth) {
+void InsaneRebel2::spawnExplosion(int x, int y, int objectHalfWidth, int dx, int dy) {
for (int i = 0; i < 5; i++) {
if (!_explosions[i].active || _explosions[i].counter <= 0) {
_explosions[i].active = true;
@@ -465,6 +465,8 @@ void InsaneRebel2::spawnExplosion(int x, int y, int objectHalfWidth) {
_explosions[i].x = x;
_explosions[i].y = y;
_explosions[i].scale = objectHalfWidth;
+ _explosions[i].dx = dx;
+ _explosions[i].dy = dy;
break;
}
}
@@ -3826,14 +3828,24 @@ void InsaneRebel2::renderSpaceExplosions(byte *renderBitmap, int pitch, int widt
if (!_smush_iconsNut)
return;
+ const bool renderHiRes = isHiRes() && width >= 640 && height >= 400;
+
for (int i = 0; i < 5; i++) {
if (!_explosions[i].active)
continue;
- int screenX = _explosions[i].x;
- int screenY = _explosions[i].y;
+ // Explosions live in raw flight-buffer coordinates: keep them moving
+ // with the victim's last motion and project into the presented window
+ // with the current perspective every frame.
+ _explosions[i].x += _explosions[i].dx;
+ _explosions[i].y += _explosions[i].dy;
+ Common::Point p = getHandler7ProjectedPointFor(_explosions[i].x, _explosions[i].y);
+ if (renderHiRes) {
+ p.x += _hiResPresentationViewX;
+ p.y += _hiResPresentationViewY;
+ }
renderExplosionFrame(renderBitmap, pitch, width, height, _explosions[i],
- screenX, screenY, kExplosionAdvanceAfterDraw, true);
+ p.x, p.y, kExplosionAdvanceBeforeDraw, true);
}
if (_hitCooldown != 0) {
@@ -3841,7 +3853,6 @@ void InsaneRebel2::renderSpaceExplosions(byte *renderBitmap, int pitch, int widt
int numChars = _smush_iconsNut->getNumChars();
int spriteIndex = 0x15 - _hitCooldown;
- const bool renderHiRes = isHiRes() && width >= 640 && height >= 400;
const int nativeViewX = renderHiRes ? _hiResPresentationViewX : _viewX;
const int nativeViewY = renderHiRes ? _hiResPresentationViewY : _viewY;
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 960b6689ae3..f7e62caca15 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -350,6 +350,8 @@ void InsaneRebel2::resetExplosions() {
_explosions[i].width = 0;
_explosions[i].height = 0;
_explosions[i].scale = 0;
+ _explosions[i].dx = 0;
+ _explosions[i].dy = 0;
}
}
More information about the Scummvm-git-logs
mailing list