[Scummvm-git-logs] scummvm master -> ee8a663ea20b92fdb3ae1fbef457e8998cb4c60b
neuromancer
noreply at scummvm.org
Sat Jun 6 11:26:25 UTC 2026
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
3d1b55ea84 SCUMM: RA1: accept 3DO passwords
b9c82d2942 SCUMM: RA1: adapt on-foot controls using 3DO controls
10adbd8f94 SCUMM: RA1: disable useless warnings
adc9613698 SCUMM: RA1: fixed some missing voices
ee8a663ea2 SCUMM: RA1: added support for virtual gamepad in ios
Commit: 3d1b55ea84758edc0ca136f4f0f2736cb7985217
https://github.com/scummvm/scummvm/commit/3d1b55ea84758edc0ca136f4f0f2736cb7985217
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T13:26:09+02:00
Commit Message:
SCUMM: RA1: accept 3DO passwords
Changed paths:
engines/scumm/insane/rebel1/menu.cpp
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index a6ac4ebd4bc..a3752286d10 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -163,6 +163,39 @@ static int getRebel1PasscodeStartLevel(int passwordIndex) {
}
}
+// 3DO Launchme_ARMv4 FUN_000092c4 compares the entered passcode against 45
+// XOR-0xAA encoded 20-byte slots at 0x262FC. The caller's Ghidra disassembly at
+// 0x12A58 maps those slots in three-code difficulty groups to the next chapter.
+const char *const kRebel1ThreeDOPasswords[] = {
+ "BOSSK", "BOTHAN", "BORDOK",
+ "ENGRET", "HERGLIC", "SKYNX",
+ "RALRRA", "LEENI", "DEFEL",
+ "FRIJA", "THRAWN", "JEDGAR",
+ "LAFRA", "LWYLL", "MADINE",
+ "DERLIN", "MAZZIC", "TARKIN",
+ "MOLTOK", "JULPA", "MOTHMA",
+ "MORAG", "MORRT", "GLAYYD",
+ "TANTISS", "MUFTAK", "OTTEGA",
+ "OSWAFL", "RASKAR", "RISHII",
+ "KLAATU", "JHOFF", "IZRINA",
+ "IRENEZ", "ITHOR", "KARRDE",
+ "LIANNA", "UMWAK", "VONZEL",
+ "PAKKA", "ORLOK", "OSSUS",
+ "NORVAL", "NKLLON", "MALANI"
+};
+
+int getRebel1ThreeDOPasscodeDifficulty(int passwordIndex) {
+ return (passwordIndex - 1) % 3;
+}
+
+int getRebel1ThreeDOPasscodeStartLevel(int passwordIndex) {
+ const int group = (passwordIndex - 1) / 3;
+ if (group < 0 || group > 14)
+ return 0;
+
+ return group == 14 ? kRA1NumLevels + 1 : group + 2;
+}
+
static char normalizeRebel1PasscodeChar(char c) {
if (c >= 'a' && c <= 'z')
return c - ('a' - 'A');
@@ -1238,6 +1271,22 @@ int InsaneRebel1::runPasscodeEntryDialog() {
}
}
+ for (int i = 1; i <= (int)ARRAYSIZE(kRebel1ThreeDOPasswords); i++) {
+ const char *password = kRebel1ThreeDOPasswords[i - 1];
+ if (!scumm_stricmp(_textEntryBuffer, password)) {
+ const int targetLevel = getRebel1ThreeDOPasscodeStartLevel(i);
+ if (targetLevel == 0)
+ return 0;
+
+ _difficulty = getRebel1ThreeDOPasscodeDifficulty(i);
+ if (targetLevel <= kRA1NumLevels)
+ _startLevel = targetLevel;
+ debugC(DEBUG_INSANE, "RA1 3DO passcode accepted: slot=%d password=%s difficulty=%d target=%d",
+ i, password, _difficulty, targetLevel);
+ return targetLevel;
+ }
+ }
+
debugC(DEBUG_INSANE, "RA1 passcode rejected: '%s'", _textEntryBuffer);
return 0;
}
Commit: b9c82d294254c9bb3c878e27bb88c7ae3b8a478c
https://github.com/scummvm/scummvm/commit/b9c82d294254c9bb3c878e27bb88c7ae3b8a478c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T13:26:09+02:00
Commit Message:
SCUMM: RA1: adapt on-foot controls using 3DO controls
Changed paths:
engines/scumm/insane/rebel1/iact.cpp
engines/scumm/insane/rebel1/menu.cpp
engines/scumm/insane/rebel1/rebel.cpp
engines/scumm/insane/rebel1/rebel.h
engines/scumm/metaengine.cpp
diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index f4c68f3f53d..41232a893bd 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -1886,7 +1886,7 @@ void InsaneRebel1::updateOnFootSequence() {
// Right edge: snap to center, step character right
_shipDirIndex = 15;
_onFootCharX += 0x3A;
- } else if (_onFootAnimCounter < 5 && !(_playerFired && _fireCooldown == 0)) {
+ } else if (_onFootAnimCounter < 5 && !_playerSecondaryHeld) {
// Original calls QuantizeDirection8Way with the cursor and character
// center, but the DOS on-foot axis is mirrored relative to the screen
// coordinates used by this port. Use the visual screen-space vector so
@@ -1897,12 +1897,13 @@ void InsaneRebel1::updateOnFootSequence() {
(int16)ra1ShotDirection(centerX, centerY, _shipPosX, _shipPosY), -4, 4);
_shipDirIndex = aimDir + 15;
} else {
- // Walking based on mouse input direction
+ // Walking based on input direction. The 3DO second held button skips the
+ // early aim-pose branch above and reaches these walk tests immediately.
int16 inputX = 0, inputY = 0;
preprocessMouseAxes(inputX, inputY);
- if (inputX > 0x1E && _onFootCharX < 0x72)
+ if (inputX > 0x1E && _onFootCharX < 0x73)
_shipDirIndex = 6; // Walk right
- else if (inputX < -0x1E && _onFootCharX > -0x72)
+ else if (inputX < -0x1E && _onFootCharX > -0x73)
_shipDirIndex = 4; // Walk left
}
@@ -2014,6 +2015,7 @@ void InsaneRebel1::handleGameOpcode5EReset(uint32 param1) {
resetGamepadReticleAim();
_playerFired = false;
+ _playerSecondaryHeld = false;
_fireCooldown = 0;
_rapidFirePhase = 0;
memset(_shotSlots, 0, sizeof(_shotSlots));
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index a3752286d10..4d34c9a4094 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -830,6 +830,9 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
_activeInputSource = kInputSourceJoystickDigital;
}
+ if (!pressed && event.customType == kScummActionInsaneSwitch)
+ _playerSecondaryHeld = false;
+
if (event.customType == kScummActionInsaneBack) {
if (!pressed)
return true;
@@ -881,6 +884,11 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
_playerFired = pressed;
return true;
}
+
+ if (_interactiveVideoActive && !_menuActive && event.customType == kScummActionInsaneSwitch) {
+ _playerSecondaryHeld = pressed;
+ return true;
+ }
}
if (_menuActive && _textEntryActive && event.type == Common::EVENT_KEYDOWN)
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index eb41ddadbe6..2a90f61f59e 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -382,6 +382,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
// Shooting/targeting state
_playerFired = false;
+ _playerSecondaryHeld = false;
_fireCooldown = 0;
_rapidFirePhase = 0;
_gameplayFlags75fe = 0;
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 6a0ad752c99..0fb7a7e1ebe 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -617,6 +617,8 @@ private:
// Shooting state â FUN_1CCA0 (0x1CCA0)
bool _playerFired; // 0x7570: current fire-button state
+ // 3DO ControlB/second held button used by L9 on-foot controls.
+ bool _playerSecondaryHeld;
int16 _fireCooldown; // 0x757C: previous-frame fire-button state (edge gate when rapid fire is off)
int16 _rapidFirePhase; // 3DO FUN_0000c3a4: held-fire modulo-3 shot gate
uint16 _gameplayFlags75fe; // 0x75FE: gameplay mode flags
diff --git a/engines/scumm/metaengine.cpp b/engines/scumm/metaengine.cpp
index 7a059404df5..1bd84c7d668 100644
--- a/engines/scumm/metaengine.cpp
+++ b/engines/scumm/metaengine.cpp
@@ -1183,14 +1183,14 @@ Common::KeymapArray ScummMetaEngine::initKeymaps(const char *target) const {
act->addDefaultInputMapping("JOY_A");
rebel1Keymap->addAction(act);
- act = new Action("RA1CANCEL", _("Menu back"));
+ act = new Action("RA1CANCEL", _("Walk / menu back"));
act->setCustomEngineActionEvent(kScummActionInsaneSwitch);
- act->addDefaultInputMapping("JOY_X");
+ act->addDefaultInputMapping("JOY_B");
rebel1Keymap->addAction(act);
act = new Action("RA1SKIP", _("Skip / menu back"));
act->setCustomEngineActionEvent(kScummActionInsaneSkip);
- act->addDefaultInputMapping("JOY_B");
+ act->addDefaultInputMapping("JOY_X");
rebel1Keymap->addAction(act);
act = new Action("RA1BACK", _("Menu"));
Commit: 10adbd8f946a2fa8cc93eda2d3b26cb2684edfa9
https://github.com/scummvm/scummvm/commit/10adbd8f946a2fa8cc93eda2d3b26cb2684edfa9
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T13:26:09+02:00
Commit Message:
SCUMM: RA1: disable useless warnings
Changed paths:
engines/scumm/insane/rebel1/levels.cpp
engines/scumm/insane/rebel1/rebel.h
diff --git a/engines/scumm/insane/rebel1/levels.cpp b/engines/scumm/insane/rebel1/levels.cpp
index b24fb5b85d0..aeedbc9e76b 100644
--- a/engines/scumm/insane/rebel1/levels.cpp
+++ b/engines/scumm/insane/rebel1/levels.cpp
@@ -43,13 +43,14 @@ void resetSpriteBank(RA1SpriteBank &bank) {
// RA1 NUTs can have odd-size FOBJ chunks padded to 2-byte alignment within
// FRME containers. This loader handles that padding properly, unlike the
// shared NutRenderer::loadFont which assumes even-size chunks.
-bool InsaneRebel1::loadRA1Nut(const char *filename, RA1SpriteBank &bank) {
+bool InsaneRebel1::loadRA1Nut(const char *filename, RA1SpriteBank &bank, bool warnIfMissing) {
resetSpriteBank(bank);
ScummFile *file = _vm->instantiateScummFile();
_vm->openFile(*file, filename);
if (!file->isOpen()) {
- warning("InsaneRebel1::loadRA1Nut: can't open %s", filename);
+ if (warnIfMissing)
+ warning("InsaneRebel1::loadRA1Nut: can't open %s", filename);
delete file;
return false;
}
@@ -164,18 +165,18 @@ bool InsaneRebel1::loadRA1Nut(const char *filename, RA1SpriteBank &bank) {
void InsaneRebel1::loadLevelSprites(int level) {
// Ship/character direction bank â try BANK1, BANK, then PILOT (Level 9 on-foot)
Common::String bankFile = Common::String::format("LVL%d/L%dBANK1.NUT", level, level);
- if (!loadRA1Nut(bankFile.c_str(), _shipBank)) {
+ if (!loadRA1Nut(bankFile.c_str(), _shipBank, false)) {
Common::String legacyBankFile = Common::String::format("LVL%d/L%dBANK.NUT", level, level);
- if (!loadRA1Nut(legacyBankFile.c_str(), _shipBank)) {
+ if (!loadRA1Nut(legacyBankFile.c_str(), _shipBank, false)) {
Common::String pilotFile = Common::String::format("LVL%d/L%dPILOT.NUT", level, level);
- if (!loadRA1Nut(pilotFile.c_str(), _shipBank))
+ if (!loadRA1Nut(pilotFile.c_str(), _shipBank, false))
debugC(DEBUG_INSANE, "InsaneRebel1::loadLevelSprites: No BANK1/BANK/PILOT for level %d", level);
}
}
// Secondary ship bank used by some level-specific handlers (e.g. LVL1 mode-2).
Common::String bankFileAlt = Common::String::format("LVL%d/L%dBANK2.NUT", level, level);
- if (!loadRA1Nut(bankFileAlt.c_str(), _shipBankAlt)) {
+ if (!loadRA1Nut(bankFileAlt.c_str(), _shipBankAlt, false)) {
debugC(DEBUG_INSANE, "InsaneRebel1::loadLevelSprites: No BANK2 for level %d", level);
}
@@ -183,9 +184,10 @@ void InsaneRebel1::loadLevelSprites(int level) {
// Explosion sprites â try BANG first, then EXPLD
Common::String bangFile = Common::String::format("LVL%d/L%dBANG.NUT", level, level);
- if (!loadRA1Nut(bangFile.c_str(), _bangBank)) {
+ if (!loadRA1Nut(bangFile.c_str(), _bangBank, false)) {
Common::String expldFile = Common::String::format("LVL%d/L%dEXPLD.NUT", level, level);
- loadRA1Nut(expldFile.c_str(), _bangBank);
+ if (!loadRA1Nut(expldFile.c_str(), _bangBank, false))
+ debugC(DEBUG_INSANE, "InsaneRebel1::loadLevelSprites: No BANG/EXPLD for level %d", level);
}
// Laser/shot effect sprites
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 0fb7a7e1ebe..d34ec43f0d1 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -210,7 +210,7 @@ private:
void captureInteractiveVideoInput();
void releaseInteractiveVideoInput();
void playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame);
- bool loadRA1Nut(const char *filename, RA1SpriteBank &bank);
+ bool loadRA1Nut(const char *filename, RA1SpriteBank &bank, bool warnIfMissing = true);
void loadLevelSprites(int level);
void handleGameOpcode5EReset(uint32 param1);
void handleGameOpcode5DLinkLatch(uint32 param1);
Commit: adc961369862b6b05ac7c02939438361280fdd16
https://github.com/scummvm/scummvm/commit/adc961369862b6b05ac7c02939438361280fdd16
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T13:26:09+02:00
Commit Message:
SCUMM: RA1: fixed some missing voices
Changed paths:
engines/scumm/insane/rebel/rebel_audio.cpp
engines/scumm/insane/rebel/rebel_audio.h
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/rebel/rebel_audio.cpp b/engines/scumm/insane/rebel/rebel_audio.cpp
index 6c1f85d4bf2..b7856bcc978 100644
--- a/engines/scumm/insane/rebel/rebel_audio.cpp
+++ b/engines/scumm/insane/rebel/rebel_audio.cpp
@@ -45,7 +45,7 @@ void RebelAudio::init(ScummEngine_v7 *vm, int sampleRate) {
}
}
-void RebelAudio::terminate() {
+void RebelAudio::reset() {
if (!_vm)
return;
@@ -56,11 +56,16 @@ void RebelAudio::terminate() {
}
if (_streams[i]) {
_streams[i]->finish();
+ delete _streams[i];
_streams[i] = nullptr;
}
}
}
+void RebelAudio::terminate() {
+ reset();
+}
+
void RebelAudio::queueData(int trackIdx, const uint8 *data, int32 size, int volume, int pan, int sampleRate) {
if (!_vm || trackIdx < 0 || trackIdx >= kMaxTracks || size <= 0 || !data)
return;
diff --git a/engines/scumm/insane/rebel/rebel_audio.h b/engines/scumm/insane/rebel/rebel_audio.h
index a91ef4f28dc..4b13efe5e06 100644
--- a/engines/scumm/insane/rebel/rebel_audio.h
+++ b/engines/scumm/insane/rebel/rebel_audio.h
@@ -39,6 +39,7 @@ public:
RebelAudio();
void init(ScummEngine_v7 *vm, int sampleRate);
+ void reset();
void terminate();
int sampleRate() const { return _sampleRate; }
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 2bd976587ad..5cdd1704d49 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -155,6 +155,11 @@ void InsaneRebel1::playCinematic(const char *filename, int32 startFrame) {
SmushPlayer *splayer = _vm->_splayer;
_player = splayer;
restoreScreenFlashPalette();
+ // DOS PlayFrontendAnmAndWait keeps pumping until frontend audio clears.
+ // ScummVM's Rebel queues outlive SmushPlayer::play(), so clear stale
+ // passive-cinematic audio before chaining the next ANM.
+ _audio.reset();
+ splayer->resetAudioTracks();
_interactiveVideoActive = false;
_vm->_smushVideoShouldFinish = false;
splayer->setCurVideoFlags(0x420);
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.cpp b/engines/scumm/smush/rebel/smush_player_ra1.cpp
index d6208e7ad8c..c2a9fa8bdbb 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra1.cpp
@@ -149,6 +149,7 @@ void SmushPlayerRebel1::initGamePlayerFields() {
_ra1ViewportOffsetX = 0;
_ra1ViewportOffsetY = 0;
_ra1FrameSourceSkipY = 0;
+ _ra1LastFrameObjectVisible = true;
_ra1FadeFrame = nullptr;
_ra1FadeFrameSize = 0;
_ra1FadeFrameWidth = 0;
@@ -184,6 +185,7 @@ void SmushPlayerRebel1::resetGameVideoState() {
_ra1ObjOverlayHeight = 0;
_ra1ViewportOffsetX = 0;
_ra1ViewportOffsetY = 0;
+ _ra1LastFrameObjectVisible = true;
_ra1UseFadeFrame = false;
}
@@ -649,6 +651,7 @@ void SmushPlayerRebel1::handleFrameObject(int32 subSize, Common::SeekableReadStr
assert(subSize >= 14);
if (_skipNext) {
_skipNext = false;
+ _ra1LastFrameObjectVisible = false;
return;
}
@@ -699,11 +702,13 @@ void SmushPlayerRebel1::handleFrameObject(int32 subSize, Common::SeekableReadStr
InsaneRebel1 *rebel1 = static_cast<InsaneRebel1 *>(_insane);
if (!rebel1->handleFrameObjectTarget((int16)ra1ObjectId, (int16)rawLeft, (int16)rawTop,
(int16)width, (int16)height, codec, ra1Param)) {
+ _ra1LastFrameObjectVisible = false;
free(chunk_buffer);
return;
}
}
+ _ra1LastFrameObjectVisible = true;
decodeFrameObject(codec, chunk_buffer, left, top, width, height, chunk_size, ra1Param, ra1Parm2);
free(chunk_buffer);
}
@@ -850,6 +855,10 @@ bool SmushPlayerRebel1::ra1DispatchFrameChunk(uint32 subType, int32 subSize, int
case MKTAG('P','V','O','C'):
ra1HandleFrameAudioChunk(subSize, b);
break;
+ case MKTAG('P','S','D','2'):
+ if (_ra1LastFrameObjectVisible)
+ ra1HandleFrameAudioChunk(subSize, b);
+ break;
case MKTAG('T','R','E','S'):
case MKTAG('T','E','X','T'):
handleTextResource(subType, subSize, b);
@@ -888,7 +897,6 @@ bool SmushPlayerRebel1::ra1DispatchFrameChunk(uint32 subType, int32 subSize, int
case MKTAG('A','D','L','2'):
case MKTAG('S','B','L',' '):
case MKTAG('S','B','L','2'):
- case MKTAG('P','S','D','2'):
debugC(DEBUG_SMUSH, "SmushPlayerRebel1::handleFrame: skipping chunk %s (%d bytes)", tag2str(subType), subSize);
break;
default:
@@ -905,6 +913,7 @@ bool SmushPlayerRebel1::ra1DispatchFrameChunk(uint32 subType, int32 subSize, int
void SmushPlayerRebel1::handleFrame(int32 frameSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayerRebel1::handleFrame(%d)", _frame);
_skipNext = false;
+ _ra1LastFrameObjectVisible = true;
handleGameFrameStart();
const bool fastForwarding = isFastForwardingCurrentFrame();
diff --git a/engines/scumm/smush/rebel/smush_player_ra1.h b/engines/scumm/smush/rebel/smush_player_ra1.h
index be70db7b950..95ec9485179 100644
--- a/engines/scumm/smush/rebel/smush_player_ra1.h
+++ b/engines/scumm/smush/rebel/smush_player_ra1.h
@@ -94,6 +94,7 @@ private:
int _ra1ViewportOffsetX;
int _ra1ViewportOffsetY;
int _ra1FrameSourceSkipY;
+ bool _ra1LastFrameObjectVisible;
// RA1 FADE chunks update the visible 320x200 screen through a sparse
// copy mask, separate from the decoded frame buffer.
Commit: ee8a663ea20b92fdb3ae1fbef457e8998cb4c60b
https://github.com/scummvm/scummvm/commit/ee8a663ea20b92fdb3ae1fbef457e8998cb4c60b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-06T13:26:09+02:00
Commit Message:
SCUMM: RA1: added support for virtual gamepad in ios
Changed paths:
A engines/scumm/insane/rebel/rebel_gamepad.cpp
A engines/scumm/insane/rebel/rebel_gamepad.h
engines/scumm/insane/rebel1/menu.cpp
engines/scumm/insane/rebel1/rebel.cpp
engines/scumm/insane/rebel1/rebel.h
engines/scumm/insane/rebel1/runlevels.cpp
engines/scumm/insane/rebel2/levels.cpp
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/insane/rebel2/rebel.h
engines/scumm/insane/rebel2/runlevels.cpp
engines/scumm/module.mk
diff --git a/engines/scumm/insane/rebel/rebel_gamepad.cpp b/engines/scumm/insane/rebel/rebel_gamepad.cpp
new file mode 100644
index 00000000000..e25e3e74be4
--- /dev/null
+++ b/engines/scumm/insane/rebel/rebel_gamepad.cpp
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/system.h"
+
+#include "scumm/insane/rebel/rebel_gamepad.h"
+
+namespace Scumm {
+
+namespace {
+
+#ifdef IPHONE
+const char *const kIOSGamepadControllerKey = "gamepad_controller";
+const char *const kIOSGamepadControllerMinimalLayoutKey = "gamepad_controller_minimal_layout";
+const char *const kIOSGamepadControllerDirectionalInputKey = "gamepad_controller_directional_input";
+const int kIOSGamepadControllerDirectionalInputDpad = 1;
+
+void saveDomainSetting(RebelIOSGamepadControllerState::SavedSetting &setting,
+ const Common::ConfigManager::Domain *domain, const char *key) {
+ setting.present = domain && domain->contains(key);
+ setting.value = setting.present ? domain->getVal(key) : Common::String();
+}
+
+void restoreDomainSetting(const RebelIOSGamepadControllerState::SavedSetting &setting,
+ const Common::String &domainName, const char *key) {
+ Common::ConfigManager::Domain *domain = ConfMan.getDomain(domainName);
+ if (!domain)
+ return;
+
+ if (setting.present)
+ ConfMan.set(key, setting.value, domainName);
+ else if (domain->contains(key))
+ ConfMan.removeKey(key, domainName);
+}
+#endif
+
+void clearSavedSetting(RebelIOSGamepadControllerState::SavedSetting &setting) {
+ setting.present = false;
+ setting.value.clear();
+}
+
+} // End of anonymous namespace
+
+RebelIOSGamepadControllerState::RebelIOSGamepadControllerState() :
+ _active(false),
+ _gamepadController(),
+ _gamepadControllerMinimalLayout(),
+ _gamepadControllerDirectionalInput() {
+ clearSavedSetting(_gamepadController);
+ clearSavedSetting(_gamepadControllerMinimalLayout);
+ clearSavedSetting(_gamepadControllerDirectionalInput);
+}
+
+void RebelIOSGamepadControllerState::enable() {
+#ifdef IPHONE
+ if (_active)
+ return;
+
+ _domainName = ConfMan.getActiveDomainName();
+ if (_domainName.empty())
+ return;
+
+ const Common::ConfigManager::Domain *domain = ConfMan.getDomain(_domainName);
+ saveDomainSetting(_gamepadController, domain, kIOSGamepadControllerKey);
+ saveDomainSetting(_gamepadControllerMinimalLayout, domain, kIOSGamepadControllerMinimalLayoutKey);
+ saveDomainSetting(_gamepadControllerDirectionalInput, domain, kIOSGamepadControllerDirectionalInputKey);
+
+ // Same iOS virtual-controller profile used by Freescape: compact d-pad overlay.
+ ConfMan.setBool(kIOSGamepadControllerKey, true, _domainName);
+ ConfMan.setBool(kIOSGamepadControllerMinimalLayoutKey, true, _domainName);
+ ConfMan.setInt(kIOSGamepadControllerDirectionalInputKey, kIOSGamepadControllerDirectionalInputDpad, _domainName);
+ g_system->applyBackendSettings();
+ _active = true;
+#endif
+}
+
+void RebelIOSGamepadControllerState::restore() {
+#ifdef IPHONE
+ if (!_active)
+ return;
+
+ restoreDomainSetting(_gamepadController, _domainName, kIOSGamepadControllerKey);
+ restoreDomainSetting(_gamepadControllerMinimalLayout, _domainName, kIOSGamepadControllerMinimalLayoutKey);
+ restoreDomainSetting(_gamepadControllerDirectionalInput, _domainName, kIOSGamepadControllerDirectionalInputKey);
+ g_system->applyBackendSettings();
+
+ clearSavedSetting(_gamepadController);
+ clearSavedSetting(_gamepadControllerMinimalLayout);
+ clearSavedSetting(_gamepadControllerDirectionalInput);
+ _domainName.clear();
+ _active = false;
+#endif
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/insane/rebel/rebel_gamepad.h b/engines/scumm/insane/rebel/rebel_gamepad.h
new file mode 100644
index 00000000000..3ecca799a42
--- /dev/null
+++ b/engines/scumm/insane/rebel/rebel_gamepad.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef SCUMM_INSANE_REBEL_GAMEPAD_H
+#define SCUMM_INSANE_REBEL_GAMEPAD_H
+
+#include "common/str.h"
+
+namespace Scumm {
+
+class RebelIOSGamepadControllerState {
+public:
+ struct SavedSetting {
+ bool present;
+ Common::String value;
+ };
+
+ RebelIOSGamepadControllerState();
+
+ void enable();
+ void restore();
+
+ bool isEnabled() const { return _active; }
+
+private:
+ bool _active;
+ Common::String _domainName;
+ SavedSetting _gamepadController;
+ SavedSetting _gamepadControllerMinimalLayout;
+ SavedSetting _gamepadControllerDirectionalInput;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 4d34c9a4094..7a67f39b3ac 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -593,6 +593,24 @@ bool InsaneRebel1::handleControllerMenuAxis(int16 oldAxisX, int16 oldAxisY) {
return false;
}
+void InsaneRebel1::openGameplayMainMenu() {
+ if (!_player)
+ return;
+
+ const bool wasPaused = _player->_paused;
+ if (!wasPaused)
+ _player->pause();
+
+ const bool restoreGamepad = _iosGamepadControllerState.isEnabled();
+ restoreIOSGamepadController();
+ _vm->openMainMenuDialog();
+ if (restoreGamepad && _interactiveVideoActive && !_menuActive && !_vm->shouldQuit())
+ enableIOSGamepadController();
+
+ if (!wasPaused)
+ _player->unpause();
+}
+
// ScummVM-exclusive feature (not in the original game): let the player navigate and
// activate the front-end menus with the mouse. Hovering highlights an item and a left
// click activates it (same as pressing accept). The item hit-rectangles mirror the
@@ -841,12 +859,7 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
return true;
}
if (_player) {
- const bool wasPaused = _player->_paused;
- if (!wasPaused)
- _player->pause();
- _vm->openMainMenuDialog();
- if (!wasPaused)
- _player->unpause();
+ openGameplayMainMenu();
}
return true;
}
@@ -942,12 +955,7 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
}
if (_player) {
- const bool wasPaused = _player->_paused;
- if (!wasPaused)
- _player->pause();
- _vm->openMainMenuDialog();
- if (!wasPaused)
- _player->unpause();
+ openGameplayMainMenu();
return true;
}
}
@@ -966,12 +974,7 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
return true;
}
- const bool wasPaused = _player->_paused;
- if (!wasPaused)
- _player->pause();
- _vm->openMainMenuDialog();
- if (!wasPaused)
- _player->unpause();
+ openGameplayMainMenu();
return true;
}
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 2a90f61f59e..4327c5e1703 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -483,7 +483,16 @@ void InsaneRebel1::warpGameplayMouseNow(int x, int y) {
eventMan->purgeMouseEvents();
}
+void InsaneRebel1::enableIOSGamepadController() {
+ _iosGamepadControllerState.enable();
+}
+
+void InsaneRebel1::restoreIOSGamepadController() {
+ _iosGamepadControllerState.restore();
+}
+
InsaneRebel1::~InsaneRebel1() {
+ restoreIOSGamepadController();
_vm->_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
terminateAudio();
freeSfx();
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index d34ec43f0d1..b191854248b 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -27,6 +27,7 @@
#include "common/events.h"
#include "scumm/insane/insane.h"
#include "scumm/insane/rebel/rebel_audio.h"
+#include "scumm/insane/rebel/rebel_gamepad.h"
#include "scumm/smush/rebel/smush_player_ra1.h"
namespace Scumm {
@@ -210,6 +211,9 @@ private:
void captureInteractiveVideoInput();
void releaseInteractiveVideoInput();
void playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame);
+ void enableIOSGamepadController();
+ void restoreIOSGamepadController();
+ void openGameplayMainMenu();
bool loadRA1Nut(const char *filename, RA1SpriteBank &bank, bool warnIfMissing = true);
void loadLevelSprites(int level);
void handleGameOpcode5EReset(uint32 param1);
@@ -521,6 +525,7 @@ private:
bool _interactiveVideoActive;
bool _preserveInteractiveRuntimeState;
bool _interactiveVideoCheatSkipped;
+ RebelIOSGamepadControllerState _iosGamepadControllerState;
// Path branching for levels with left/right alternative videos.
// Original sets nextSceneA/nextSceneB when GAME 0x07 counter == 394 (0x18A).
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 5cdd1704d49..92962e9b931 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -1774,6 +1774,8 @@ void InsaneRebel1::captureInteractiveVideoInput() {
const bool level7RouteSplice = (_currentLevel == 6 && _levelRouteIndex > 0);
const bool preserveInputState = _preserveInteractiveRuntimeState || level7RouteSplice;
+ enableIOSGamepadController();
+
// Center mouse, hide system cursor (we draw our own), lock mouse to window.
// Some replays happen inside one original gameplay loop, so keep the current
// input state instead of recentering between route clips.
@@ -1802,6 +1804,7 @@ void InsaneRebel1::captureInteractiveVideoInput() {
void InsaneRebel1::releaseInteractiveVideoInput() {
_gameplayMouseSettleUntil = 0;
g_system->lockMouse(false);
+ restoreIOSGamepadController();
}
void InsaneRebel1::playInteractiveVideoFile(const char *filename, int32 videoOffset, int32 videoStartFrame) {
diff --git a/engines/scumm/insane/rebel2/levels.cpp b/engines/scumm/insane/rebel2/levels.cpp
index f7fd926727e..a5d34e8b9fa 100644
--- a/engines/scumm/insane/rebel2/levels.cpp
+++ b/engines/scumm/insane/rebel2/levels.cpp
@@ -525,6 +525,7 @@ int InsaneRebel2::runLevel(int levelId) {
}
// Unlock the mouse when returning to menu
+ restoreIOSGamepadController();
g_system->lockMouse(false);
CursorMan.showMouse(true);
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 213e0820411..7b4781a1ffa 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -568,6 +568,7 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
InsaneRebel2::~InsaneRebel2() {
+ restoreIOSGamepadController();
setVirtualKeyboardVisible(false);
// Unregister EventObserver
@@ -625,7 +626,11 @@ void InsaneRebel2::openGameplayMainMenu(SmushPlayer *splayer) {
if (!splayer->_paused)
splayer->pause();
+ const bool restoreGamepad = _iosGamepadControllerState.isEnabled();
+ restoreIOSGamepadController();
_vm->openMainMenuDialog();
+ if (restoreGamepad && _gameState == kStateGameplay && _rebelHandler != 0 && !_vm->shouldQuit())
+ enableIOSGamepadController();
splayer->unpause();
_lastGameplayMenuCloseTime = _vm->_system->getMillis();
}
@@ -641,6 +646,14 @@ void InsaneRebel2::openMenuMainMenu(SmushPlayer *splayer) {
_vm->openMainMenuDialog();
}
+void InsaneRebel2::enableIOSGamepadController() {
+ _iosGamepadControllerState.enable();
+}
+
+void InsaneRebel2::restoreIOSGamepadController() {
+ _iosGamepadControllerState.restore();
+}
+
// notifyEvent -- EventObserver callback for global input dispatch.
// Handles ESC (skip) and SPACE (pause) regardless of menu state.
// Pause behavior matches original FUN_405A21: SPACE pauses, ANY key unpauses.
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index b0bf580ba9b..099add0d6cd 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -28,6 +28,7 @@
#include "scumm/insane/insane.h"
#include "scumm/insane/rebel/rebel_audio.h"
+#include "scumm/insane/rebel/rebel_gamepad.h"
#include "common/keyboard.h"
#include "common/list.h"
@@ -424,6 +425,8 @@ public:
// flags and when to call processWaveEnd(). recordFrame preserves the original
// split between gameplay/wave calls and transition/init-only segments.
bool playLevelSegment(const char *filename, uint16 flags, bool recordFrame = true);
+ void enableIOSGamepadController();
+ void restoreIOSGamepadController();
int calculateAccuracy(int kills, int misses) const;
@@ -470,6 +473,7 @@ public:
void centerGameplayAim();
// Tracks consecutive recorded gameplay SANs so wave-loop videos do not recenter aim.
bool _gameplaySectionActive;
+ RebelIOSGamepadControllerState _iosGamepadControllerState;
// Level state tracking for multi-phase levels
int _currentPhase; // Current gameplay phase (1, 2, 3 for Level 2; 1, 2 for Level 3/6)
diff --git a/engines/scumm/insane/rebel2/runlevels.cpp b/engines/scumm/insane/rebel2/runlevels.cpp
index 1dd66088685..55a0e046ee1 100644
--- a/engines/scumm/insane/rebel2/runlevels.cpp
+++ b/engines/scumm/insane/rebel2/runlevels.cpp
@@ -197,12 +197,16 @@ bool InsaneRebel2::playLevelSegment(const char *filename, uint16 flags, bool rec
if (!_gameplaySectionActive && (flags & 0x40) == 0)
centerGameplayAim();
_gameplaySectionActive = true;
+ enableIOSGamepadController();
} else {
_gameplaySectionActive = false;
+ restoreIOSGamepadController();
}
splayer->setCurVideoFlags(flags);
splayer->play(filename, 15);
+ if (isRecordedGameplay)
+ restoreIOSGamepadController();
if (recordFrame)
_deathFrame = splayer->_frame;
restoreDamageFlashPalette();
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 4f42d417fdc..c85694c0f0b 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -134,6 +134,7 @@ MODULE_OBJS += \
insane/insane_scenes.o \
insane/insane_iact.o \
insane/rebel/rebel_audio.o \
+ insane/rebel/rebel_gamepad.o \
insane/rebel1/rebel.o \
insane/rebel1/audio.o \
insane/rebel1/iact.o \
More information about the Scummvm-git-logs
mailing list