[Scummvm-git-logs] scummvm master -> 24813e60febcab5da73f870f035b7675e88b1d39
dreammaster
noreply at scummvm.org
Sun Aug 2 06:39:01 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:
7d7c2deb07 MADS: NEBULAR: Implement demo Adlib sound drivers
bec794b52c MADS: NEBULAR: Implement Rex Demo DCL decoder
24813e60fe MADS: NEBULAR: Demo specific restrictions
Commit: 7d7c2deb070ba800336c4eb834805cbb2b649a67
https://github.com/scummvm/scummvm/commit/7d7c2deb070ba800336c4eb834805cbb2b649a67
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-08-02T16:38:49+10:00
Commit Message:
MADS: NEBULAR: Implement demo Adlib sound drivers
Changed paths:
engines/mads/animview/functions.cpp
engines/mads/nebular/nebular.cpp
engines/mads/nebular/sound/asound.cpp
engines/mads/nebular/sound/asound.h
engines/mads/nebular/sound/asound_nebular.cpp
engines/mads/nebular/sound/asound_nebular.h
engines/mads/nebular/sound/sound.cpp
engines/mads/nebular/sound/sound.h
diff --git a/engines/mads/animview/functions.cpp b/engines/mads/animview/functions.cpp
index 86d9bfcd7e5..e4f5fe50190 100644
--- a/engines/mads/animview/functions.cpp
+++ b/engines/mads/animview/functions.cpp
@@ -140,6 +140,11 @@ void flag_parse(const char *param) {
do_not_clear_screen = true;
break;
+ case 'z':
+ // Show stats
+ // Not implemented in ScummVM
+ break;
+
default:
error("Unsupported animview flag - %c", c);
break;
diff --git a/engines/mads/nebular/nebular.cpp b/engines/mads/nebular/nebular.cpp
index b23a4595cd9..807e64f8338 100644
--- a/engines/mads/nebular/nebular.cpp
+++ b/engines/mads/nebular/nebular.cpp
@@ -79,7 +79,7 @@ Common::Error RexNebularEngine::run() {
}
// Set up sound manager
- _soundManager = new Sound::RexSoundManager(_mixer, _soundFlag);
+ _soundManager = new Sound::RexSoundManager(_mixer, _soundFlag, isDemo());
_soundManager->validate();
// Run the game
diff --git a/engines/mads/nebular/sound/asound.cpp b/engines/mads/nebular/sound/asound.cpp
index db19c02ec0c..a55577700a9 100644
--- a/engines/mads/nebular/sound/asound.cpp
+++ b/engines/mads/nebular/sound/asound.cpp
@@ -177,7 +177,7 @@ ASound::~ASound() {
delete _opl;
}
-void ASound::validate() {
+void ASound::validate(bool isDemo) {
Common::File f;
static const char *const MD5[] = {
"205398468de2c8873b7d4d73d5be8ddc",
@@ -191,14 +191,23 @@ void ASound::validate() {
"a31e4783e098f633cbb6689adb41dd4f"
};
+ static const char *const MD5_DEMO[] = {
+ "11aa27a511abdfa905fd290b4d96e9d3",
+ "057c16af3b84b019bf088cb0ef8e6c4f"
+ };
+
for (int i = 1; i <= 9; ++i) {
+ if (isDemo && i != 1 && i != 9)
+ continue;
+ const char *const EXPECTED = isDemo ? MD5_DEMO[i == 1 ? 0 : 1] : MD5[i - 1];
+
Common::Path filename(Common::String::format("ASOUND.00%d", i));
if (!f.open(filename))
error("Could not process - %s", filename.toString().c_str());
Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
f.close();
- if (md5str != MD5[i - 1])
+ if (md5str != EXPECTED)
error("Invalid sound file - %s", filename.toString().c_str());
}
}
diff --git a/engines/mads/nebular/sound/asound.h b/engines/mads/nebular/sound/asound.h
index 3af918b13b9..ffaffd1171b 100644
--- a/engines/mads/nebular/sound/asound.h
+++ b/engines/mads/nebular/sound/asound.h
@@ -328,7 +328,7 @@ public:
/**
* Validates the Adlib sound files
*/
- static void validate();
+ static void validate(bool isDemo);
public:
/**
diff --git a/engines/mads/nebular/sound/asound_nebular.cpp b/engines/mads/nebular/sound/asound_nebular.cpp
index e107f4ccc4c..c2378aeab4d 100644
--- a/engines/mads/nebular/sound/asound_nebular.cpp
+++ b/engines/mads/nebular/sound/asound_nebular.cpp
@@ -326,6 +326,270 @@ int ASound1::command2627293032() {
}
+/*-----------------------------------------------------------------------*/
+
+const ASoundDemo1::CommandPtr ASoundDemo1::_commandList[41] = {
+ &ASoundDemo1::command0, &ASoundDemo1::command1, &ASoundDemo1::command2, &ASoundDemo1::command3,
+ &ASoundDemo1::command4, &ASoundDemo1::command5, &ASoundDemo1::command6, &ASoundDemo1::command7,
+ &ASoundDemo1::command8, &ASoundDemo1::command9, &ASoundDemo1::command10, &ASoundDemo1::command11,
+ &ASoundDemo1::command12, &ASoundDemo1::command13, &ASoundDemo1::command14, &ASoundDemo1::command15,
+ &ASoundDemo1::command16, &ASoundDemo1::command17, &ASoundDemo1::command18, &ASoundDemo1::command19,
+ &ASoundDemo1::command20, &ASoundDemo1::command21, &ASoundDemo1::command22, &ASoundDemo1::command23,
+ &ASoundDemo1::command24, &ASoundDemo1::command25, &ASoundDemo1::command26, &ASoundDemo1::command27,
+ &ASoundDemo1::command28, &ASoundDemo1::command29, &ASoundDemo1::command30, &ASoundDemo1::command31,
+ &ASoundDemo1::command32, &ASoundDemo1::command33, &ASoundDemo1::command34, &ASoundDemo1::command35,
+ &ASoundDemo1::command36, &ASoundDemo1::command37, &ASoundDemo1::command38, &ASoundDemo1::command39,
+ &ASoundDemo1::command40
+};
+
+ASoundDemo1::ASoundDemo1(Audio::Mixer *mixer) : ASound(mixer, "asound.001", 0x1540, 0x24b0) {
+ _cmd23Toggle = false;
+
+ // Load sound samples
+ auto samplesStream = getDataStream(0x50);
+ for (int i = 0; i < 96; ++i)
+ _samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASoundDemo1::command(int commandId, int param) {
+ if (commandId > 40)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASoundDemo1::command9() {
+ playSoundAny(0x2220);
+ return 0;
+}
+
+int ASoundDemo1::command10() {
+ byte *pData1 = loadData(0x1C8C);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ command1();
+ _channels[4].load(pData1);
+ _channels[5].load(loadData(0x1CBC));
+ _channels[6].load(loadData(0x1E3E));
+ _channels[7].load(loadData(0x1E6C));
+ return 0;
+}
+
+int ASoundDemo1::command11() {
+ command111213();
+ _channels[0]._volumeOffset = 0;
+ _channels[1]._volumeOffset = 0;
+ return 0;
+}
+
+int ASoundDemo1::command12() {
+ command111213();
+ _channels[0]._volumeOffset = 40;
+ _channels[1]._volumeOffset = 0;
+ return 0;
+}
+
+int ASoundDemo1::command13() {
+ command111213();
+ _channels[0]._volumeOffset = 40;
+ _channels[1]._volumeOffset = 50;
+ return 0;
+}
+
+int ASoundDemo1::command14() {
+ playSoundAny(0x1C08);
+ return 0;
+}
+
+int ASoundDemo1::command15() {
+ byte *pData1 = loadData(0x1E9C);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ command1();
+ _channels[4].load(pData1);
+ _channels[5].load(loadData(0x1F3A));
+ _channels[6].load(loadData(0x1F92));
+ _channels[7].load(loadData(0x1FEA));
+ _channels[8].load(loadData(0x2014));
+ return 0;
+}
+
+int ASoundDemo1::command16() {
+ playSoundAny(0x222A);
+ return 0;
+}
+
+int ASoundDemo1::command17() {
+ playSoundAny(0x244C);
+ return 0;
+}
+
+int ASoundDemo1::command18() {
+ command1();
+ playSoundAny(0x225A);
+ return 0;
+}
+
+int ASoundDemo1::command19() {
+ command1();
+ playSoundAny(0x226A);
+ return 0;
+}
+
+int ASoundDemo1::command20() {
+ playSoundAny(0x22C6);
+ return 0;
+}
+
+int ASoundDemo1::command21() {
+ playSoundAny(0x22B6);
+ return 0;
+}
+
+int ASoundDemo1::command22() {
+ byte *pData = loadData(0x22E2);
+ pData[6] = (byte)((getRandomNumber() & 7) + 85);
+ playSoundAny(0x22E2);
+ return 0;
+}
+
+int ASoundDemo1::command23() {
+ _cmd23Toggle = !_cmd23Toggle;
+ playSoundAny(_cmd23Toggle ? 0x22EC : 0x22F4);
+ return 0;
+}
+
+int ASoundDemo1::command24() {
+ playSoundAny(0x22FC);
+ playSoundAny(0x230C);
+ playSoundAny(0x231E);
+ return 0;
+}
+
+int ASoundDemo1::command25() {
+ playSoundAny(0x232A);
+ return 0;
+}
+
+int ASoundDemo1::command26() {
+ byte *pData = loadData(0x249E);
+ pData[5] = (byte)((command2627293032() >> 1) + 60);
+ _channels[8].load(pData);
+ return 0;
+}
+
+int ASoundDemo1::command27() {
+ byte *pData = loadData(0x2494);
+ pData[5] = (byte)((command2627293032() >> 1) + 78);
+ _channels[7].load(pData);
+ return 0;
+}
+
+int ASoundDemo1::command28() {
+ playSoundAny(0x233A);
+ return 0;
+}
+
+int ASoundDemo1::command29() {
+ byte *pData = loadData(0x2236);
+ byte v = (byte)((command2627293032() >> 1) + 76);
+ pData[7] = pData[13] = pData[21] = pData[27] = v;
+ isSoundActive(pData); // result unused, matches disassembly quirk
+ playSoundAny(0x2236);
+ return 0;
+}
+
+int ASoundDemo1::command30() {
+ byte *pData = loadData(0x2456);
+ pData[7] = (byte)((command2627293032() >> 1) + 72);
+ isSoundActive(pData); // result unused, matches disassembly quirk
+ playSoundAny(0x2456);
+ return 0;
+}
+
+int ASoundDemo1::command31() {
+ _channels[6].load(loadData(0x23B8));
+ _channels[7].load(loadData(0x2354));
+ return 0;
+}
+
+int ASoundDemo1::command32() {
+ byte *pData = loadData(0x2466);
+ byte base = (byte)command2627293032() >> 1;
+ byte v1 = base + 20;
+ byte v2 = base + 40;
+ pData[9] = pData[17] = pData[25] = pData[33] = v1;
+ pData[11] = pData[19] = pData[27] = pData[35] = v2;
+ isSoundActive(pData); // result unused, matches disassembly quirk
+ playSoundAny(0x2466);
+ return 0;
+}
+
+int ASoundDemo1::command33() {
+ playSoundAny(0x2362);
+ playSoundAny(0x236C);
+ return 0;
+}
+
+int ASoundDemo1::command34() {
+ byte *pData = loadData(0x2376);
+ byte v = (byte)((getRandomNumber() & 12) + 45);
+ pData[9] = v;
+ pData[16] = v + 36;
+ playSoundAny(0x2376);
+ return 0;
+}
+
+int ASoundDemo1::command35() {
+ playSoundAny(0x238A);
+ return 0;
+}
+
+int ASoundDemo1::command36() {
+ playSoundAny(0x23AE);
+ return 0;
+}
+
+int ASoundDemo1::command37() {
+ playSoundAny(0x23C6);
+ return 0;
+}
+
+int ASoundDemo1::command38() {
+ playSoundAny(0x23DA);
+ return 0;
+}
+
+int ASoundDemo1::command39() {
+ byte *pData1 = loadData(0x203E);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ _channels[5].load(pData1);
+ _channels[6].load(loadData(0x20C0));
+ _channels[7].load(loadData(0x20DE));
+ _channels[8].load(loadData(0x2106));
+ return 0;
+}
+
+int ASoundDemo1::command40() {
+ playSoundAny(0x2396);
+ return 0;
+}
+
+void ASoundDemo1::command111213() {
+ byte *pData1 = loadData(0x18E8);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1A80));
+ _channels[2].load(loadData(0x1B8A));
+ _channels[3].load(loadData(0x1BCC));
+}
+
+int ASoundDemo1::command2627293032() {
+ return (_commandParam > 0x40) ? _commandParam - 0x40 : _commandParam & 0xff00;
+}
+
+
/*-----------------------------------------------------------------------*/
const ASound2::CommandPtr ASound2::_commandList[44] = {
@@ -2217,6 +2481,147 @@ int ASound8::command37() {
/*-----------------------------------------------------------------------*/
+const ASoundDemo9::CommandPtr ASoundDemo9::_commandList[39] = {
+ &ASoundDemo9::command0, &ASoundDemo9::command1, &ASoundDemo9::command2, &ASoundDemo9::command3,
+ &ASoundDemo9::command4, &ASoundDemo9::command5, &ASoundDemo9::command6, &ASoundDemo9::command7,
+ &ASoundDemo9::command8, &ASoundDemo9::nullCommand, &ASoundDemo9::nullCommand, &ASoundDemo9::command11,
+ &ASoundDemo9::nullCommand, &ASoundDemo9::nullCommand, &ASoundDemo9::command14, &ASoundDemo9::nullCommand,
+ &ASoundDemo9::nullCommand, &ASoundDemo9::command17, &ASoundDemo9::nullCommand, &ASoundDemo9::nullCommand,
+ &ASoundDemo9::command20, &ASoundDemo9::command21, &ASoundDemo9::command22, &ASoundDemo9::command23,
+ &ASoundDemo9::nullCommand, &ASoundDemo9::nullCommand, &ASoundDemo9::command26, &ASoundDemo9::command27,
+ &ASoundDemo9::command28, &ASoundDemo9::command29, &ASoundDemo9::command30, &ASoundDemo9::command31,
+ &ASoundDemo9::nullCommand, &ASoundDemo9::nullCommand, &ASoundDemo9::command34, &ASoundDemo9::command35,
+ &ASoundDemo9::command36, &ASoundDemo9::nullCommand, &ASoundDemo9::command38
+};
+
+ASoundDemo9::ASoundDemo9(Audio::Mixer *mixer) : ASound(mixer, "asound.009", 0x13f0, 0x3610) {
+ // Load sound samples
+ auto samplesStream = getDataStream(0x50);
+ for (int i = 0; i < 94; ++i)
+ _samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASoundDemo9::command(int commandId, int param) {
+ if (commandId > 38)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASoundDemo9::command11() {
+ playSoundAny(0x320E);
+ playSoundAny(0x32A2);
+ return 0;
+}
+
+int ASoundDemo9::command14() {
+ playSoundAny(0x31D2);
+ return 0;
+}
+
+int ASoundDemo9::command17() {
+ command29();
+ playSoundAny(0x3540);
+ return 0;
+}
+
+int ASoundDemo9::command20() {
+ byte *pData = loadData(0x315E);
+ int v = getRandomNumber();
+ v = (v & 0x10) | 0x4D;
+ pData[4] = (byte)(v & 0x7F);
+ playSoundAny(0x315E);
+ return 0;
+}
+
+int ASoundDemo9::command21() {
+ playSoundAny(0x3176);
+ return 0;
+}
+
+int ASoundDemo9::command22() {
+ playSoundAny(0x3186);
+ return 0;
+}
+
+int ASoundDemo9::command23() {
+ playSoundAny(0x3166);
+ return 0;
+}
+
+int ASoundDemo9::command26() {
+ _channels[6].load(loadData(0x3338));
+ _channels[7].load(loadData(0x33D4));
+ return 0;
+}
+
+int ASoundDemo9::command27() {
+ playSoundAny(0x3474);
+ return 0;
+}
+
+int ASoundDemo9::command28() {
+ _channels[8].load(loadData(0x31A6));
+ return 0;
+}
+
+int ASoundDemo9::command29() {
+ _channels[8].load(loadData(0x31B0));
+ return 0;
+}
+
+int ASoundDemo9::command30() {
+ playSoundAny(0x3196);
+ return 0;
+}
+
+int ASoundDemo9::command31() {
+ playSoundAny(0x31E8);
+ playSoundAny(0x31F6);
+ return 0;
+}
+
+int ASoundDemo9::command34() {
+ byte *pData1 = loadData(0x18FE);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1B10));
+ _channels[2].load(loadData(0x1E4E));
+ _channels[3].load(loadData(0x21EE));
+ _channels[4].load(loadData(0x2804));
+ _channels[5].load(loadData(0x2C72));
+ return 0;
+}
+
+int ASoundDemo9::command35() {
+ playSoundAny(0x3500);
+ return 0;
+}
+
+int ASoundDemo9::command36() {
+ playSoundAny(0x31BA);
+ playSoundAny(0x31C4);
+ return 0;
+}
+
+int ASoundDemo9::command38() {
+ byte *pData1 = loadData(0x307A);
+ isSoundActive(pData1); // result unused, matches disassembly quirk
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x3090));
+ _channels[2].load(loadData(0x30C8));
+ _channels[3].load(loadData(0x3102));
+ _channels[4].load(loadData(0x313A));
+ _channels[5].load(loadData(0x314A));
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
const ASound9::CommandPtr ASound9::_commandList[52] = {
&ASound9::command0, &ASound9::command1, &ASound9::command2, &ASound9::command3,
&ASound9::command4, &ASound9::command5, &ASound9::command6, &ASound9::command7,
diff --git a/engines/mads/nebular/sound/asound_nebular.h b/engines/mads/nebular/sound/asound_nebular.h
index 99d54d09ace..f6d94217c2f 100644
--- a/engines/mads/nebular/sound/asound_nebular.h
+++ b/engines/mads/nebular/sound/asound_nebular.h
@@ -76,6 +76,53 @@ public:
int command(int commandId, int param) override;
};
+class ASoundDemo1 : public ASound {
+private:
+ typedef int (ASoundDemo1:: *CommandPtr)();
+ static const CommandPtr _commandList[41];
+ bool _cmd23Toggle;
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+
+ void command111213();
+ int command2627293032();
+public:
+ ASoundDemo1(Audio::Mixer *mixer);
+
+ int command(int commandId, int param) override;
+};
+
class ASound2 : public ASound {
private:
byte _command12Param;
@@ -376,6 +423,34 @@ public:
int command(int commandId, int param) override;
};
+class ASoundDemo9 : public ASound {
+private:
+ typedef int (ASoundDemo9:: *CommandPtr)();
+ static const CommandPtr _commandList[39];
+
+ int command11();
+ int command14();
+ int command17();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command34();
+ int command35();
+ int command36();
+ int command38();
+public:
+ ASoundDemo9(Audio::Mixer *mixer);
+
+ int command(int commandId, int param) override;
+};
+
class ASound9 : public ASound {
private:
/**
diff --git a/engines/mads/nebular/sound/sound.cpp b/engines/mads/nebular/sound/sound.cpp
index d30cad11815..7d1f9fee054 100644
--- a/engines/mads/nebular/sound/sound.cpp
+++ b/engines/mads/nebular/sound/sound.cpp
@@ -29,6 +29,9 @@ namespace RexNebular {
namespace Sound {
void RexSoundManager::validate() {
+ if (_isDemo)
+ _driverType = SOUND_ADLIB;
+
switch (_driverType) {
case SOUND_MT32:
RSound::validate();
@@ -39,7 +42,7 @@ void RexSoundManager::validate() {
break;
default:
- ASound::validate();
+ ASound::validate(_isDemo);
break;
}
}
@@ -47,6 +50,15 @@ void RexSoundManager::validate() {
void RexSoundManager::loadDriver(int sectionNumber) {
removeDriver();
+ if (_isDemo) {
+ assert(sectionNumber == 1 || sectionNumber == 9);
+ if (sectionNumber == 1)
+ _driver = new ASoundDemo1(_mixer);
+ else
+ _driver = new ASoundDemo9(_mixer);
+ return;
+ }
+
switch (_driverType) {
case SOUND_MT32:
// Roland MT32 drivers
diff --git a/engines/mads/nebular/sound/sound.h b/engines/mads/nebular/sound/sound.h
index 5678bab403d..2854e29b7cf 100644
--- a/engines/mads/nebular/sound/sound.h
+++ b/engines/mads/nebular/sound/sound.h
@@ -29,6 +29,9 @@ namespace RexNebular {
namespace Sound {
class RexSoundManager : public SoundManager {
+private:
+ bool _isDemo;
+
protected:
/**
* Load the particular section sound handler
@@ -37,7 +40,8 @@ protected:
void loadDriver(int sectionNum) override;
public:
- RexSoundManager(Audio::Mixer *mixer, bool &soundFlag) : SoundManager(mixer, soundFlag) {
+ RexSoundManager(Audio::Mixer *mixer, bool &soundFlag, bool isDemo) :
+ SoundManager(mixer, soundFlag), _isDemo(isDemo) {
}
~RexSoundManager() override {
}
Commit: bec794b52cbf9f5f1303e77f476f756f8106632c
https://github.com/scummvm/scummvm/commit/bec794b52cbf9f5f1303e77f476f756f8106632c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-08-02T16:38:50+10:00
Commit Message:
MADS: NEBULAR: Implement Rex Demo DCL decoder
Assisted-by: Claude Code:claude-opus-4.8
Changed paths:
A engines/mads/core/pack_dcl.cpp
A engines/mads/core/pack_dcl.h
engines/mads/core/text.cpp
engines/mads/module.mk
diff --git a/engines/mads/core/pack_dcl.cpp b/engines/mads/core/pack_dcl.cpp
new file mode 100644
index 00000000000..9e4a22c2f0e
--- /dev/null
+++ b/engines/mads/core/pack_dcl.cpp
@@ -0,0 +1,286 @@
+/* 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/textconsole.h"
+#include "mads/core/pack_dcl.h"
+
+namespace MADS {
+
+/*
+ * Format notes (from blast.c):
+ *
+ * - First byte is 0 if literals are uncoded or 1 if they are coded. Second
+ * byte is 4, 5, or 6 for the number of extra bits in the distance code.
+ * This is the base-2 logarithm of the dictionary size minus six.
+ *
+ * - Compressed data is a combination of literals and length/distance pairs
+ * terminated by an end code. Literals are either Huffman coded or
+ * uncoded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - A bit preceding a literal or length/distance pair indicates which comes
+ * next: 0 for literals, 1 for length/distance.
+ *
+ * - If literals are uncoded, the next eight bits are the literal, in normal
+ * bit order (no bit-reversal). Length and distance extra bits are also
+ * read in normal bit order.
+ *
+ * - Bits are packed from the least significant bit to the most significant
+ * bit of each byte.
+ *
+ * - Huffman codes are bit-reversed relative to a simple integer ordering of
+ * codes of the same length, so decode() inverts each bit as it reads it
+ * to recover a naturally-ordered code value for comparison.
+ */
+
+#define DCL_MAXBITS 13
+#define DCL_MAXWIN 4096
+
+struct DclHuffman {
+ short count[DCL_MAXBITS + 1]; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+// Bit lengths of literal codes 0..255, compactly encoded: each byte's low
+// nibble is a code length and high nibble is (repeat count - 1).
+static const byte kLitLenCompact[] = {
+ 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
+ 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
+ 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
+ 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
+ 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
+ 44, 173
+};
+
+// Bit lengths of length codes 0..15 (same compact encoding).
+static const byte kLenLenCompact[] = {2, 35, 36, 53, 38, 23};
+
+// Bit lengths of distance codes 0..63 (same compact encoding).
+static const byte kDistLenCompact[] = {2, 20, 53, 230, 247, 151, 248};
+
+// Base value and extra-bit count for each of the 16 length codes.
+static const short kLenBase[16] = {
+ 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264
+};
+static const byte kLenExtra[16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8
+};
+
+struct DclState {
+ Common::SeekableReadStream *src;
+
+ uint32 bitbuf;
+ int bitcnt;
+ bool inputError;
+
+ // Sliding window: doubles as LZ77 history and the last DCL_MAXWIN
+ // bytes of output. windowPos wraps modulo DCL_MAXWIN, which is
+ // equivalent to blast.c's own block-recycling scheme since distances
+ // never exceed the dictionary size (max 4096).
+ byte window[DCL_MAXWIN];
+ int windowPos;
+ bool first; // true until a full window's worth of output has been produced
+
+ byte *dest;
+ long destSize;
+ long destPos;
+};
+
+/**
+ * Reads need bits from the input stream, least-significant-bit first.
+ * Sets s.inputError and returns 0 if the stream runs out of data.
+ */
+static int dclBits(DclState &s, int need) {
+ uint32 val = s.bitbuf;
+ while (s.bitcnt < need) {
+ byte b;
+ if (s.src->eos() || s.src->read(&b, 1) != 1) {
+ s.inputError = true;
+ return 0;
+ }
+ val |= (uint32)b << s.bitcnt;
+ s.bitcnt += 8;
+ }
+ s.bitbuf = val >> need;
+ s.bitcnt -= need;
+ return (int)(val & ((1u << need) - 1));
+}
+
+/**
+ * Bit-reversed canonical Huffman decode; see the format notes above.
+ */
+static int dclDecode(DclState &s, const DclHuffman &h) {
+ int code = 0, first = 0, index = 0, len = 1;
+ const short *next = h.count + 1;
+
+ for (;;) {
+ int bit = dclBits(s, 1);
+ if (s.inputError)
+ return 0;
+
+ code |= bit ^ 1; // invert to recover natural ordering
+
+ int count = *next++;
+ if (code < first + count)
+ return h.symbol[index + (code - first)];
+
+ index += count;
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+
+ if (len > DCL_MAXBITS) {
+ s.inputError = true;
+ return 0;
+ }
+ }
+}
+
+/**
+ * Expands a compact repeat-count/length byte list into a canonical Huffman
+ * decode table (count[] and symbol[]).
+ *
+ * @param h Huffman table to fill in (h.symbol must already point at
+ * storage large enough for the expanded symbol count).
+ * @param rep Compact repeat-count/length bytes.
+ * @param repLen Number of bytes in rep.
+ * @param scratch Scratch buffer, must hold at least as many entries as the
+ * expanded symbol count (256 is always sufficient).
+ */
+static void dclConstruct(DclHuffman &h, const byte *rep, int repLen, short *scratch) {
+ int symbol = 0;
+ for (int i = 0; i < repLen; ++i) {
+ int len = rep[i] & 15;
+ int left = (rep[i] >> 4) + 1;
+ while (left-- > 0)
+ scratch[symbol++] = len;
+ }
+ int n = symbol;
+
+ for (int len = 0; len <= DCL_MAXBITS; ++len)
+ h.count[len] = 0;
+ for (int i = 0; i < n; ++i)
+ h.count[scratch[i]]++;
+
+ if (h.count[0] == n)
+ return; // empty code; never referenced by a well-formed stream
+
+ short offs[DCL_MAXBITS + 2];
+ offs[1] = 0;
+ for (int len = 1; len < DCL_MAXBITS; ++len)
+ offs[len + 1] = offs[len] + h.count[len];
+
+ for (int i = 0; i < n; ++i) {
+ if (scratch[i] != 0)
+ h.symbol[offs[scratch[i]]++] = i;
+ }
+}
+
+bool pack_dcl_explode(Common::SeekableReadStream *src, byte *dest, long destSize) {
+ DclState s;
+ s.src = src;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+ s.inputError = false;
+ memset(s.window, 0, sizeof(s.window));
+ s.windowPos = 0;
+ s.first = true;
+ s.dest = dest;
+ s.destSize = destSize;
+ s.destPos = 0;
+
+ short litSym[256], lenSym[16], distSym[64];
+ DclHuffman litCode, lenCode, distCode;
+ litCode.symbol = litSym;
+ lenCode.symbol = lenSym;
+ distCode.symbol = distSym;
+
+ short scratch[256];
+ dclConstruct(litCode, kLitLenCompact, sizeof(kLitLenCompact), scratch);
+ dclConstruct(lenCode, kLenLenCompact, sizeof(kLenLenCompact), scratch);
+ dclConstruct(distCode, kDistLenCompact, sizeof(kDistLenCompact), scratch);
+
+ int lit = dclBits(s, 8);
+ if (s.inputError || lit > 1)
+ return false;
+ int dictBits = dclBits(s, 8);
+ if (s.inputError || dictBits < 4 || dictBits > 6)
+ return false;
+
+ while (s.destPos < s.destSize) {
+ int flag = dclBits(s, 1);
+ if (s.inputError)
+ return false;
+
+ if (flag) {
+ // Length/distance pair.
+ int symbol = dclDecode(s, lenCode);
+ if (s.inputError)
+ return false;
+ int len = kLenBase[symbol] + dclBits(s, kLenExtra[symbol]);
+ if (s.inputError)
+ return false;
+ if (len == 519)
+ break; // end code
+
+ int distBits = (len == 2) ? 2 : dictBits;
+ int distSymbol = dclDecode(s, distCode);
+ if (s.inputError)
+ return false;
+ uint32 dist = ((uint32)distSymbol << distBits) + dclBits(s, distBits);
+ if (s.inputError)
+ return false;
+ dist++;
+
+ if (s.first && (long)dist > s.windowPos)
+ return false; // distance points before the start of output
+
+ while (len-- > 0) {
+ byte b = s.window[(s.windowPos - (int)dist) & (DCL_MAXWIN - 1)];
+ s.window[s.windowPos] = b;
+ s.windowPos = (s.windowPos + 1) & (DCL_MAXWIN - 1);
+ if (s.windowPos == 0)
+ s.first = false;
+ if (s.destPos < s.destSize)
+ s.dest[s.destPos++] = b;
+ }
+ } else {
+ // Literal.
+ int symbol = lit ? dclDecode(s, litCode) : dclBits(s, 8);
+ if (s.inputError)
+ return false;
+
+ byte b = (byte)symbol;
+ s.window[s.windowPos] = b;
+ s.windowPos = (s.windowPos + 1) & (DCL_MAXWIN - 1);
+ if (s.windowPos == 0)
+ s.first = false;
+ if (s.destPos < s.destSize)
+ s.dest[s.destPos++] = b;
+ }
+ }
+
+ return s.destPos == s.destSize;
+}
+
+} // namespace MADS
diff --git a/engines/mads/core/pack_dcl.h b/engines/mads/core/pack_dcl.h
new file mode 100644
index 00000000000..f60619a0108
--- /dev/null
+++ b/engines/mads/core/pack_dcl.h
@@ -0,0 +1,61 @@
+/* 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 MADS_CORE_PACK_DCL_H
+#define MADS_CORE_PACK_DCL_H
+
+#include "common/stream.h"
+#include "mads/core/general.h"
+
+namespace MADS {
+
+/*
+ * pack_dcl.cpp -- genuine PKWare Data Compression Library ("explode")
+ * decompressor.
+ *
+ * MADSPACK 1.0 (used by early builds such as the Rex Nebular demo) used
+ * this real PKWare algorithm; MADSPACK 2.0 replaced it with MicroProse's
+ * own "pFAB" compressor (see pfab.cpp). The two formats are unrelated
+ * despite the shared "MADSPACK" branding, and this decoder is deliberately
+ * kept independent of the shared pack_data()/PackList machinery in
+ * pack.cpp (which every other MADS game relies on), so that adding support
+ * for this older format carries no risk of regressing anything else.
+ *
+ * Ported from the public-domain reference implementation "blast.c" by
+ * Mark Adler (zlib contrib/blast), which documents the format originally
+ * described by Ben Rudiak-Gould.
+ */
+
+/**
+ * Decompresses a PKWare DCL "explode" stream.
+ *
+ * @param src Compressed data stream, positioned at the start of the block.
+ * Only as many bytes as the format actually needs are consumed;
+ * the stream is not required to end where the block does.
+ * @param dest Destination buffer; must be at least destSize bytes.
+ * @param destSize Expected number of decompressed bytes.
+ * @return true if exactly destSize bytes were decompressed successfully.
+ */
+extern bool pack_dcl_explode(Common::SeekableReadStream *src, byte *dest, long destSize);
+
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/core/text.cpp b/engines/mads/core/text.cpp
index a348d8043ef..e9419a74da3 100644
--- a/engines/mads/core/text.cpp
+++ b/engines/mads/core/text.cpp
@@ -38,6 +38,7 @@
#include "mads/core/object.h"
#include "mads/core/text.h"
#include "mads/core/global.h"
+#include "mads/core/pack_dcl.h"
#include "mads/mads.h"
namespace MADS {
@@ -134,12 +135,23 @@ TextPtr text_load(long id) {
fileio_setpos(handle, target_offset);
- pack_strategy = PACK_PFAB;
- if (pack_data(PACK_EXPLODE, dir.length,
- FROM_DISK, handle,
- TO_MEMORY, &result->text[0]) != (int)dir.length) {
- mem_free(result);
- result = NULL;
+ // The Rex Nebular demo's messages.dat predates MADSPACK 2.0's switch to
+ // the pFAB compressor and still uses genuine PKWare DCL compression
+ // (MADSPACK 1.0). Route it to a dedicated decoder rather than risking
+ // the shared pack_data() path used by every other game.
+ if (g_engine->getGameID() == GType_RexNebular && g_engine->isDemo()) {
+ if (!pack_dcl_explode(handle, (byte *)&result->text[0], dir.length)) {
+ mem_free(result);
+ result = NULL;
+ }
+ } else {
+ pack_strategy = PACK_PFAB;
+ if (pack_data(PACK_EXPLODE, dir.length,
+ FROM_DISK, handle,
+ TO_MEMORY, &result->text[0]) != (int)dir.length) {
+ mem_free(result);
+ result = NULL;
+ }
}
done:
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 9872184e5b3..b5c1f97d97a 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -45,6 +45,7 @@ MODULE_OBJS := \
core/mps_installer.o \
core/object.o \
core/pack.o \
+ core/pack_dcl.o \
core/pal.o \
core/pfab.o \
core/player.o \
Commit: 24813e60febcab5da73f870f035b7675e88b1d39
https://github.com/scummvm/scummvm/commit/24813e60febcab5da73f870f035b7675e88b1d39
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-08-02T16:38:50+10:00
Commit Message:
MADS: NEBULAR: Demo specific restrictions
Changed paths:
engines/mads/nebular/rooms/room102.cpp
engines/mads/nebular/rooms/room106.cpp
engines/mads/nebular/rooms/room107.cpp
diff --git a/engines/mads/nebular/rooms/room102.cpp b/engines/mads/nebular/rooms/room102.cpp
index 3e6f5ae6356..9173d61e384 100644
--- a/engines/mads/nebular/rooms/room102.cpp
+++ b/engines/mads/nebular/rooms/room102.cpp
@@ -86,7 +86,12 @@ static void room_102_init() {
kernel_seq_range(g_sequence_ids[8], -2, -2);
}
- if (previous_room == 101) {
+ if (g_engine->isDemo() && previous_room == KERNEL_STARTING_GAME) {
+ player.x = 169;
+ player.y = 115;
+ player.facing = FACING_SOUTH;
+ inter_move_object(OBJ_REBREATHER, PLAYER);
+ } else if (previous_room == 101) {
player.x = 229;
player.y = 109;
player.commands_allowed = false;
@@ -217,13 +222,13 @@ static void room_102_pre_parser() {
}
static void room_102_parser() {
+ bool justOpenedFl = false;
+
if (player.look_around) {
text_show(10234);
- player.command_ready = false;
- return;
+ goto handled;
}
- bool justOpenedFl = false;
if (player_said_1(refrigerator) && !local._fridgeOpenedFl) {
switch (kernel.trigger) {
case 0:
@@ -236,8 +241,7 @@ static void room_102_parser() {
}
player.commands_allowed = false;
g_engine->_soundManager->command(20, 0);
- player.command_ready = false;
- return;
+ goto handled;
case 1:
g_sequence_ids[7] = kernel_seq_forward(g_sprite_ids[7], false, 6, 0, 0, 0);
@@ -249,8 +253,7 @@ static void room_102_parser() {
else
delay = 48;
kernel_timing_trigger(delay, 2);
- player.command_ready = false;
- return;
+ goto handled;
case 2:
local._fridgeOpenedFl = true;
@@ -274,8 +277,7 @@ static void room_102_parser() {
text_show(10229);
local._fridgeFirstOpenFl = false;
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(walkto, refrigerator) && justOpenedFl) {
@@ -288,23 +290,26 @@ static void room_102_parser() {
kernel_message_add(curQuote, 210, 60, 0x1110, 120, 73, 0);
kernel_message_add(quote_string(kernel.quotes, 64), 214 + width, 60, 0x1110, 120, 73, 0);
local._activeMsgFl = true;
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(close, refrigerator)) {
text_show(10213);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(take, refrigerator)) {
text_show(8);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(walk_through, door)) {
+ if (g_engine->isDemo()) {
+ // Not available in demo
+ text_show(99);
+ goto handled;
+ }
+
switch (kernel.trigger) {
case 0:
g_sequence_ids[6] = kernel_seq_forward(g_sprite_ids[6], false, 6, 0, 0, 1);
@@ -320,99 +325,87 @@ static void room_102_parser() {
default:
break;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(walkto, engineering_section)) {
- new_room = 103;
- player.command_ready = false;
- return;
+ if (g_engine->isDemo())
+ // Not available in demo
+ text_show(99);
+ else
+ new_room = 103;
+ goto handled;
}
if (player_said_2(walkto, poster) || player_said_2(look, poster) || player_said_2(walkto, binoculars)) {
addRandomMessage();
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, weight_machine)) {
text_show(10212);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, engineering_section)) {
text_show(10205);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, door)) {
text_show(10204);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(stare_at, ceiling) || player_said_2(look, ceiling)) {
text_show(10203);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(stare_at, overhead_lamp) || player_said_2(look, overhead_lamp)) {
text_show(10202);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, robo_kitchen)) {
text_show(10215);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_3(put, burger, robo_kitchen) && player_has(OBJ_BURGER)) {
text_show(10216);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(put, refrigerator) && player_has(object_named(player2.words[1]))) {
text_show(10217);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_3(put, dead_fish, robo_kitchen) || player_said_3(put, stuffed_fish, robo_kitchen)) {
text_show(10230);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(open, robo_kitchen)) {
text_show(10218);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, closet)) {
text_show(10219);
- player.command_ready = false;
- return;
+ goto handled;
}
if ((player_said_1(ladder) || player_said_1(hatchway)) && (player_said_1(look) || player_said_1(climb_up) || player_said_1(climb_through))) {
if (player_has(OBJ_REBREATHER)) {
if (!player_said_1(climb_up) && !player_said_1(climb_through)) {
text_show(10231);
- player.command_ready = false;
- return;
+ goto handled;
}
} else if (player_said_1(look) || (game.difficulty != DIFFICULTY_HARD)) {
text_show(10222);
- player.command_ready = false;
- return;
+ goto handled;
}
}
@@ -442,7 +435,7 @@ static void room_102_parser() {
break;
case 6:
- if (player_has(OBJ_REBREATHER) && !player_has_been_in_room(106))
+ if (player_has(OBJ_REBREATHER) && !player_has_been_in_room(106) && !g_engine->isDemo())
text_show(10237);
new_room = 106;
break;
@@ -450,58 +443,49 @@ static void room_102_parser() {
default:
break;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, power_status_panel)) {
text_show(10226);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, window) || player_said_2(look_through, window)) {
text_show(10227);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, doorway) || player_said_2(walkto, doorway)) {
text_show(10228);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, drawer) || ((player_said_2(close, drawer) || player_said_2(push, drawer)) && !local._drawerDescrFl)) {
text_show(10220);
local._drawerDescrFl = true;
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(close, drawer) || player_said_2(push, drawer)) {
text_show(10221);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(open, drawer)) {
text_show(10236);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, chair) || (player_said_2(sit_in, chair) && !local._chairDescrFl)) {
local._chairDescrFl = true;
text_show(10210);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(sit_in, chair)) {
text_show(10211);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, medicine_cabinet)) {
@@ -510,8 +494,7 @@ static void room_102_parser() {
else
text_show(10206);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(close, medicine_cabinet) && global[kMedicineCabinetOpen]) {
@@ -537,8 +520,7 @@ static void room_102_parser() {
default:
break;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(open, medicine_cabinet) && !global[kMedicineCabinetOpen]) {
@@ -570,8 +552,7 @@ static void room_102_parser() {
default:
break;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(take, binoculars) && object_is_here(OBJ_BINOCULARS)) {
@@ -597,8 +578,7 @@ static void room_102_parser() {
default:
break;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(take, burger) && object_is_here(OBJ_BURGER)) {
@@ -611,38 +591,40 @@ static void room_102_parser() {
player.walker_visible = true;
player.commands_allowed = true;
}
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(take, poster)) {
text_show(10224);
- player.command_ready = false;
- return;
+ goto handled;
}
if ((player_said_1(push) || player_said_1(pull)) && player_said_1(weight_machine)) {
text_show(10225);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, floor)) {
text_show(10232);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, binoculars) && !player_has(OBJ_BINOCULARS)) {
text_show(10233);
- player.command_ready = false;
- return;
+ goto handled;
}
if (player_said_2(look, burger) && (player.main_object_source == STROKE_INTERFACE)) {
text_show(801);
- player.command_ready = false;
+ goto handled;
}
+
+ goto done;
+
+handled:
+ player.command_ready = false;
+done:
+ ;
}
static void room_102_error() {
diff --git a/engines/mads/nebular/rooms/room106.cpp b/engines/mads/nebular/rooms/room106.cpp
index c519b29faeb..59bb1034a76 100644
--- a/engines/mads/nebular/rooms/room106.cpp
+++ b/engines/mads/nebular/rooms/room106.cpp
@@ -95,6 +95,7 @@ static void room_106_init() {
}
static void room_106_daemon() {
+ if (kernel.trigger != 0) warning("%d", kernel.trigger);
if (kernel.trigger == 70) {
g_sequence_ids[0] = kernel_seq_forward(g_sprite_ids[0], false, 6, 0, 0, 0);
kernel_seq_range(g_sequence_ids[0], -2, -2);
@@ -122,6 +123,10 @@ static void room_106_daemon() {
player.prepare_walk_facing = FACING_SOUTHWEST;
local._firstEmergingFl = true;
kernel_run_animation(kernel_full_name(106, 'B', -1, "", KERNEL_AA), 80);
+
+ // FIXME: trigger 80 isn't happening for demo
+ if (g_engine->isDemo())
+ kernel_timing_trigger(100, 87);
}
}
@@ -189,9 +194,14 @@ static void room_106_daemon() {
static void room_106_pre_parser() {
if (player_said_2(swim_towards, sea_cliff) || player_said_2(swim_towards, seaweed_bank)) {
- player.commands_allowed = false;
- series_list[player.series_base + 1]->walker->velocity = 24;
- player.walk_off_edge_to_room = 104;
+ if (g_engine->isDemo()) {
+ text_show(99);
+ player.command_ready = false;
+ } else {
+ player.commands_allowed = false;
+ series_list[player.series_base + 1]->walker->velocity = 24;
+ player.walk_off_edge_to_room = 104;
+ }
}
if (player_said_2(swim_towards, open_area_to_east))
diff --git a/engines/mads/nebular/rooms/room107.cpp b/engines/mads/nebular/rooms/room107.cpp
index c67333a2f59..91a2b449d8b 100644
--- a/engines/mads/nebular/rooms/room107.cpp
+++ b/engines/mads/nebular/rooms/room107.cpp
@@ -102,8 +102,14 @@ static void room_107_pre_parser() {
if (player_said_2(swim_towards, open_area_to_west))
player.walk_off_edge_to_room = 106;
- if (player_said_2(swim_towards, open_area_to_south))
- player.walk_off_edge_to_room = 108;
+ if (player_said_2(swim_towards, open_area_to_south)) {
+ if (g_engine->isDemo()) {
+ text_show(99);
+ player.command_ready = false;
+ } else {
+ player.walk_off_edge_to_room = 108;
+ }
+ }
}
static void room_107_parser() {
@@ -121,7 +127,10 @@ static void room_107_parser() {
object_examine(OBJ_DEAD_FISH, 802, 0);
}
} else if (player_said_2(swim_towards, northern_sea_cliff))
- new_room = 105;
+ if (g_engine->isDemo())
+ text_show(99);
+ else
+ new_room = 105;
else if (player_said_2(look, northern_sea_cliff))
text_show(10701);
else if (player_said_2(look, dead_fish) && (player.main_object_source == STROKE_INTERFACE))
More information about the Scummvm-git-logs
mailing list