[Scummvm-git-logs] scummvm master -> d93ff338458e0843212794b96a640efffc3425c9
mduggan
noreply at scummvm.org
Sat Mar 1 21:08:54 UTC 2025
This automated email contains information about 15 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3d9ad76fd7 DGDS: Add starting point for loading Amiga images
eaa2e2a64f DGDS: Fix missing initializer, thanks coverity
4798df4598 DGDS: Small willy beamish sound fixes
e26387ce5f DGDS: Improve Willy Beamish CD head animation
5299435d7d DGDS: Set higher priority on music than sfx
af7636fb19 DGDS: Log segment name if available
a1f21c1a3e DGDS: Reset minutes added on scene change
c81b25bf10 DGDS: Fix crash when sucking babysitter into vacuum cleaner
3568ebb7c3 DGDS: Avoid possible invalid access on shutdown
e205d41bd7 DGDS: Workaround for flashing bug over some Willy Beamish dialogs
ef7e1f034a DGDS: Fix dropping in inventory for Willy Beamish
2d1298c457 DGDS: Fix type 1 dialog rendering in Willy Beamish
82430b3344 DGDS: Also fix dialog artifact on viewin blueprints
800f291143 DGDS: Hold open "head" dialogs with no sound until they are closed
d93ff33845 DGDS: Small fixes for Willy Beamish head rendering
Commit: 3d9ad76fd74a654a8ec68c4da477fcb9bc89d418
https://github.com/scummvm/scummvm/commit/3d9ad76fd74a654a8ec68c4da477fcb9bc89d418
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Add starting point for loading Amiga images
Not working yet.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/ttm.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c9875d36cd3..ab30a94b768 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -397,7 +397,8 @@ void DgdsEngine::loadGameFiles() {
switch (getGameId()) {
case GID_DRAGON:
- _soundPlayer->loadSFX("SOUNDS.SNG");
+ if (getPlatform() == Common::kPlatformDOS)
+ _soundPlayer->loadSFX("SOUNDS.SNG");
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 774277811ca..70eedf4de03 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -35,6 +35,7 @@
#include "dgds/image.h"
#include "dgds/resource.h"
#include "dgds/parser.h"
+#include "dgds/decompress.h"
namespace Dgds {
@@ -76,11 +77,22 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
surface.fillRect(Common::Rect(surface.w, surface.h), 0);
+ if (DgdsEngine::getInstance()->getPlatform() == Common::kPlatformAmiga) {
+ loadAmigaScreen(surface, fileStream, ex);
+ } else {
+ loadPCScreen(surface, fileStream, ex);
+ }
+
+ delete fileStream;
+}
+
+
+void Image::loadPCScreen(Graphics::ManagedSurface &surface, Common::SeekableReadStream *fileStream, DGDS_EX ex) {
uint16 xsize = surface.w;
uint16 ysize = surface.h;
DgdsChunkReader chunk(fileStream);
- while (chunk.readNextHeader(ex, filename)) {
+ while (chunk.readNextHeader(ex, _filename)) {
if (chunk.isContainer()) {
continue;
}
@@ -97,7 +109,7 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
xsize, ysize, surface.w, surface.h);
}
debug(1, "screen file %s dims %d x %d into surface %d x %d",
- filename.c_str(), xsize, ysize, surface.w, surface.h);
+ _filename.c_str(), xsize, ysize, surface.w, surface.h);
} else if (chunk.isSection(ID_VGA)) {
loadBitmap4(&surface, 0, stream, true, xsize, ysize);
} else if (chunk.isSection(ID_MA8)) {
@@ -106,10 +118,22 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
loadVQT(&surface, 0, stream);
}
}
+}
- delete fileStream;
+
+void Image::loadAmigaScreen(Graphics::ManagedSurface &surface, Common::SeekableReadStream *fileStream, DGDS_EX ex) {
+ uint32 magic = fileStream->readUint32BE();
+ if (magic != MKTAG('B', 'A', 'S', 'H'))
+ error("Unexpected magic %08x in Amiga screen %s", magic, _filename.c_str());
+
+ /*
+ uint16 ysize = fileStream->readUint16BE();
+ uint16 xsize = surface.w;
+ uint16 dummy = fileStream->readUint16BE();
+ */
}
+
int Image::frameCount(const Common::String &filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
@@ -154,11 +178,57 @@ void Image::loadBitmap(const Common::String &filename) {
_filename = filename;
+ if (DgdsEngine::getInstance()->getPlatform() == Common::kPlatformAmiga) {
+ loadAmigaBitmap(fileStream, ex);
+ } else {
+ loadPCBitmap(fileStream, ex);
+ }
+ delete fileStream;
+}
+
+void Image::loadAmigaBitmap(Common::SeekableReadStream *fileStream, DGDS_EX ex) {
+ uint16 nframes = fileStream->readUint16BE();
+ if (nframes > 1024)
+ error("Image::loadAmigaBitmap: Unexpectedly large number of frames in image (%d)", nframes);
+ _frames.resize(nframes);
+
+ uint32 size = fileStream->readUint32BE(); // always the same as size below?
+ for (int i = 0; i < nframes; i++) {
+ uint16 width = fileStream->readUint16BE();
+ uint16 height = fileStream->readUint16BE();
+ _frames[i].reset(new Graphics::ManagedSurface(width, height, Graphics::PixelFormat::createFormatCLUT8()));
+ }
+
+ char idstr[13];
+ fileStream->read(idstr, 12);
+ idstr[12] = '\0';
+
+ uint32 size2 = fileStream->readUint32BE();
+ if (size != size2)
+ error("Image::loadAmigaBitmap: Expected sizes to match: %d != %d", size, size2);
+ //uint32 insz = fileStream->size() - fileStream->pos();
+ byte row[200];
+ for (int i = 0; i < nframes; i++) {
+ // round up
+ int bytesPerRow = (_frames[i]->w * 5 + 4) / 8;
+ for (int y = 0; y < _frames[i]->h; y++) {
+ fileStream->read(row, bytesPerRow);
+ for (int x = 0; x < _frames[i]->w; x++) {
+ int offset = x * 5 / 8;
+ uint16 val = READ_LE_INT16(row + offset);
+ val = (val >> (11 - (x * 5 % 8))) & 0x1f;
+ _frames[i]->setPixel(x, y, val);
+ }
+ }
+ }
+}
+
+void Image::loadPCBitmap(Common::SeekableReadStream *fileStream, DGDS_EX ex) {
int64 vqtpos = -1;
int64 scnpos = -1;
DgdsChunkReader chunk(fileStream);
- while (chunk.readNextHeader(ex, filename)) {
+ while (chunk.readNextHeader(ex, _filename)) {
if (chunk.isContainer()) {
continue;
}
@@ -211,7 +281,7 @@ void Image::loadBitmap(const Common::String &filename) {
scnpos = fileStream->pos();
} else if (chunk.isSection(ID_OFF)) {
if (vqtpos == -1 && scnpos == -1)
- error("Expect VQT or SCN chunk before OFF chunk in BMP resource %s", filename.c_str());
+ error("Expect VQT or SCN chunk before OFF chunk in BMP resource %s", _filename.c_str());
// 2 possibilities: A set of offsets (find the one which we need and use it)
// or a single value of 0xffff. If it's only one tile, the offset is always
@@ -252,8 +322,6 @@ void Image::loadBitmap(const Common::String &filename) {
break;
}
}
-
- delete fileStream;
}
void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &destSurf, ImageFlipMode flipMode, int dstWidth, int dstHeight) const {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index c25c2ce4f9c..b26d3eb8562 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -25,6 +25,7 @@
#include <common/ptr.h>
#include <common/rect.h>
#include <graphics/palette.h>
+#include <dgds/resource.h>
namespace Common {
class SeekableReadStream;
@@ -75,6 +76,12 @@ public:
const Common::String &getFilename() const { return _filename; }
private:
+ void loadAmigaBitmap(Common::SeekableReadStream *stream, DGDS_EX ex);
+ void loadPCBitmap(Common::SeekableReadStream *stream, DGDS_EX ex);
+
+ void loadAmigaScreen(Graphics::ManagedSurface &surf, Common::SeekableReadStream *stream, DGDS_EX ex);
+ void loadPCScreen(Graphics::ManagedSurface &surf, Common::SeekableReadStream *stream, DGDS_EX ex);
+
void loadBitmap4(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream, bool highByte, uint16 width, uint16 height);
void loadBitmap8(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream, uint16 width, uint16 height);
uint32 loadVQT(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream);
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index ffdbeff61f3..d022370913a 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -1181,7 +1181,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
if (_vm->getPlatform() == Common::kPlatformAmiga) {
// TODO: remove hard-coded stuff..
- _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
+ _vm->_soundPlayer->playAmigaSfx(sval.c_str(), 0, 255);
} else {
if (_vm->_soundPlayer->loadMusic(sval.c_str()))
_vm->_soundPlayer->playMusic(seq._currentSongId);
Commit: eaa2e2a64f6e564f18dfc47c6b960583087c7e8b
https://github.com/scummvm/scummvm/commit/eaa2e2a64f6e564f18dfc47c6b960583087c7e8b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Fix missing initializer, thanks coverity
Changed paths:
engines/dgds/head.h
diff --git a/engines/dgds/head.h b/engines/dgds/head.h
index 2e5517e122a..556accee2b9 100644
--- a/engines/dgds/head.h
+++ b/engines/dgds/head.h
@@ -139,7 +139,8 @@ public:
/** CDS data from Willy Beamish CD version talkie */
class Conversation {
public:
- Conversation() : _nextExecMs(0), _runTempFrame(0), _tempFrameNum(0), _stopScript(false), _loadState(0), _dlgNum(-1), _dlgFileNum(-1), _subNum(-1), _finished(false), _haveHeadData(false) {}
+ Conversation() : _thisFrameMs(0), _nextExecMs(0), _runTempFrame(0), _tempFrameNum(0), _stopScript(false), _loadState(0),
+ _dlgNum(-1), _dlgFileNum(-1), _subNum(-1), _finished(false), _haveHeadData(false) {}
~Conversation();
void unloadData();
Commit: 4798df45985b0a81f58d3025e53d16f73fe95b16
https://github.com/scummvm/scummvm/commit/4798df45985b0a81f58d3025e53d16f73fe95b16
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Small willy beamish sound fixes
Changed paths:
engines/dgds/image.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 70eedf4de03..68c560a6ee0 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -35,7 +35,6 @@
#include "dgds/image.h"
#include "dgds/resource.h"
#include "dgds/parser.h"
-#include "dgds/decompress.h"
namespace Dgds {
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 4c390240297..793eb2eff3c 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -484,6 +484,25 @@ void Sound::stopMusicOrSFX(int num) {
}
}
+void Sound::pauseMusicOrSFX(int num) {
+ if (_musicIdMap.contains(num)) {
+ // NOTE: We assume there is only ever one music here..
+ _music->pauseMusic();
+ } else {
+ warning("Sound: TODO: Implement pause SFX %d", num);
+ }
+}
+
+void Sound::unpauseMusicOrSFX(int num) {
+ if (_musicIdMap.contains(num)) {
+ // NOTE: We assume there is only ever one music here..
+ _music->resumeMusic();
+ } else {
+ warning("Sound: TODO: Implement unpause SFX %d", num);
+ }
+}
+
+
void Sound::processInitSound(uint32 obj, const SoundData &data, Audio::Mixer::SoundType soundType) {
// Check if a track with the same sound object is already playing
MusicEntry *oldSound = _music->getSlot(obj);
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index f8e1d95904d..22c53f3f8a5 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -65,6 +65,8 @@ public:
void playMusicOrSFX(int num);
void stopMusicOrSFX(int num);
+ void pauseMusicOrSFX(int num);
+ void unpauseMusicOrSFX(int num);
void stopSfxForChannel(byte channel);
void stopSfxByNum(int num);
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index d022370913a..9288149582a 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -1088,29 +1088,61 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
break;
}
case 0xc020: { // LOAD SAMPLE: filename:str
- // Ignore this?
- //_vm->_soundPlayer->loadMusic(sval.c_str());
- //_vm->_soundPlayer->stopMusic();
+ // Ignore this? Tries to load music files which don't exist in Willy
+ // Beamish - everything is integrated into WILLYSND.SX and WILLYMUS.SX
+ // _vm->_soundPlayer->loadMusic(sval.c_str());
+ // _vm->_soundPlayer->stopMusic();
break;
}
case 0xc030: { // SELECT SAMPLE: int: i
- // Do nothing for now?
+ // Often this is just the same number as gets passed to the following
+ // PLAY SAMPLE, but if PLAY SAMPLE gets 0 then this number should be
+ // used.
+ env._lastSelectedSample = ivals[0];
break;
}
+ case 0xc040: { // DESELECT SAMPLE: int: i
+ // This is not quite the same as the original. It looks like:
+ // * 0 is "deselect all samples"
+ // * -1 is "deselect stopped samples"
+ // * -2 is "deselect playing samples"
+ // (-1 and -2 might be the other way around?)
+ // -1 may not be used anywhere? -2 is used in SQ5 demo.
+ if (ivals[0] == 0 || ivals[0] == -2) {
+ _vm->_soundPlayer->stopAllSfx();
+ }
+ env._lastSelectedSample = 0;
+ }
case 0xc050: { // PLAY SAMPLE: int: i
if (seq._executed) // this is a one-shot op
break;
- _vm->_soundPlayer->playMusicOrSFX(ivals[0]);
+ int16 sample = ivals[0] ? ivals[0] : env._lastSelectedSample;
+ if (sample)
+ _vm->_soundPlayer->playMusicOrSFX(sample);
break;
}
case 0xc060: { // STOP SAMPLE: int: i
- _vm->_soundPlayer->stopMusicOrSFX(ivals[0]);
+ if (ivals[0] == -2)
+ _vm->_soundPlayer->stopAllSfx();
+ else if (ivals[0] == -1)
+ // Handled in original but maybe never used?
+ warning("TODO: Implement stop sample for arg -1");
+ else
+ _vm->_soundPlayer->stopMusicOrSFX(ivals[0]);
+ break;
+ }
+ case 0xc070: { // PAUSE SAMPLE: int: i
+ _vm->_soundPlayer->pauseMusicOrSFX(ivals[0]);
+ break;
+ }
+ case 0xc080: { // UNPAUSE SAMPLE: int: i
+ _vm->_soundPlayer->unpauseMusicOrSFX(ivals[0]);
break;
}
case 0xc210: { // LOAD RAW SFX filename:str
if (seq._executed) // this is a one-shot op
break;
- // Stop existing raw sound before we deallocate it.
+ // Stop any existing raw sound before we deallocate it.
if (env._soundRaw)
env._soundRaw->stop();
if (_vm->getResourceManager()->hasResource(sval)) {
@@ -1118,24 +1150,24 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
snd->load(sval);
env._soundRaw.reset(snd);
} else {
- warning("TTM 0xC210: Skip loading RAW %s, not found.", sval.c_str());
+ warning("TTM 0xC21F: Skip loading RAW %s, not found.", sval.c_str());
}
break;
}
case 0xc220: { // PLAY RAW SFX
if (seq._executed) // this is a one-shot op
break;
- if (!env._soundRaw)
- warning("TODO: Trying to play raw SFX but nothing loaded");
- else
+ if (env._soundRaw)
env._soundRaw->play();
+ else
+ warning("TTM 0xC220: Trying to play raw SFX but nothing loaded");
break;
}
case 0xc240: { // STOP RAW SFX
if (env._soundRaw) {
env._soundRaw->stop();
} else {
- warning("TODO: Trying to stop raw SFX but nothing loaded");
+ warning("TTM 0xC240: Trying to stop raw SFX but nothing loaded");
}
break;
}
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index 1aa4b6ae930..7aa4ef206d4 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -41,7 +41,7 @@ class TTMEnviro : public ScriptParserData {
public:
TTMEnviro() : _totalFrames(330), _enviro(0), _creditScrollMeasure(0),
_creditScrollYOffset(0), _xOff(0), _yOff(0), _xScroll(0), _yScroll(0),
- ScriptParserData() {
+ _lastSelectedSample(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
}
@@ -65,6 +65,7 @@ public:
int16 _xScroll;
int16 _yScroll;
Common::SharedPtr<SoundRaw> _soundRaw;
+ int16 _lastSelectedSample;
};
enum TTMRunType {
Commit: e26387ce5fa8c02dc7ab002f170d5889eec87245
https://github.com/scummvm/scummvm/commit/e26387ce5fa8c02dc7ab002f170d5889eec87245
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Improve Willy Beamish CD head animation
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/head.cpp
engines/dgds/head.h
engines/dgds/image.cpp
engines/dgds/sound.cpp
engines/dgds/sound_raw.cpp
engines/dgds/sound_raw.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ab30a94b768..4fa3e1b881b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -620,6 +620,10 @@ void DgdsEngine::dimPalForWillyDialog(bool force) {
}
}
+void DgdsEngine::updateThisFrameMillis() {
+ _thisFrameMs = getTotalPlayTime();
+}
+
Common::Error DgdsEngine::run() {
syncSoundSettings();
_isLoading = true;
@@ -637,7 +641,7 @@ Common::Error DgdsEngine::run() {
uint32 frameCount = 0;
while (!shouldQuit()) {
- _thisFrameMs = getTotalPlayTime();
+ updateThisFrameMillis();
if (_lastMouseEvent == Common::EVENT_INVALID)
pumpMessages();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index af278241892..559baa23613 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -64,6 +64,7 @@ class HocIntro;
class ChinaTank;
class ChinaTrain;
+// This is not actually MS per frame - it's MS per timer tick that is used for delays.
const float MS_PER_FRAME = 16.6667f;
enum DgdsGameId {
@@ -271,6 +272,7 @@ public:
ChinaTank *getChinaTank() { return _chinaTank; }
DragonArcade *getDragonArcade() { return _dragonArcade; }
uint32 getThisFrameMs() const { return _thisFrameMs; }
+ void updateThisFrameMillis();
static DgdsEngine *getInstance() { return static_cast<DgdsEngine *>(g_engine); }
void setFlipMode(bool mode) { _flipMode = mode; }
diff --git a/engines/dgds/head.cpp b/engines/dgds/head.cpp
index 67e02a4193f..3f05003f74c 100644
--- a/engines/dgds/head.cpp
+++ b/engines/dgds/head.cpp
@@ -27,6 +27,7 @@
#include "dgds/drawing.h"
#include "dgds/scene.h"
#include "dgds/dialog.h"
+#include "dgds/ads.h"
#include "graphics/cursorman.h"
@@ -191,8 +192,8 @@ void CDSTTMInterpreter::handleOperation(TTMEnviro &env_, TTMSeq &seq, uint16 op,
case 0x1020: { // SET DELAY: i:int [0..n]
// TODO: Probably should do this accounting (as well as timeCut and dialogs)
// in game frames, not millis.
- int delayMillis = (int)round(ivals[0] * MS_PER_FRAME);
- env._cdsDelay = delayMillis;
+ int16 delayMillis = (int16)round(ivals[0] * MS_PER_FRAME);
+ env._cdsDelay = MAX(env._cdsDelay, delayMillis);
break;
}
case 0x1050: // SELECT BMP: id:int [0]
@@ -256,12 +257,13 @@ void CDSTTMInterpreter::handleOperation(TTMEnviro &env_, TTMSeq &seq, uint16 op,
uint16 hi = (uint16)ivals[1];
uint16 lo = (uint16)ivals[0];
uint32 offset = ((uint32)hi << 16) + lo;
- debug("TODO: 0xC250 Sync raw sfx?? offset %d", offset);
- /*if (env._soundRaw->playedOffset() < offset) {
- // Not played to this point yet.
- env.scr->seek(-6, SEEK_CUR);
- return false;
- }*/
+ // The offset is in bytes of the sample.
+ uint32 playedOffset = env._soundRaw->playedOffset();
+ if (playedOffset < offset) {
+ // Not played to this point yet. Add a delay until that point.
+ env._cdsDelay = MAX(env._cdsDelay, (int16)(1000 * (offset - playedOffset) / 11025));
+ debug(10, "CDS SYNC SFX: played %d wait for %d (%d ms)", playedOffset, offset, env._cdsDelay);
+ }
break;
}
case 0xa100: // DRAW FILLED RECT
@@ -331,7 +333,7 @@ void Conversation::loadData(uint16 dlgFileNum, uint16 dlgNum, int16 sub, bool ha
_dlgFileNum = dlgFileNum;
_subNum = sub;
_nextExecMs = 0;
- _runTempFrame = 0;
+ _runTempFrame = -1;
_tempFrameNum = 0;
_thisFrameMs = 0;
_stopScript = false;
@@ -388,7 +390,8 @@ bool Conversation::runScriptFrame(int16 frameNum) {
TTMSeq *seq = _ttmSeqs[0].get();
seq->_currentFrame = frameNum;
- debug(10, "CDS: Running TTM sequence %d frame %d", seq->_seqNum, seq->_currentFrame);
+ debug(10, "CDS: Running TTM sequence %d frame %d current millis %d", seq->_seqNum,
+ seq->_currentFrame, _thisFrameMs);
seq->_drawWin = _drawRect.toCommonRect();
return _ttmScript->run(_ttmEnv, *seq);
@@ -409,6 +412,7 @@ void Conversation::checkAndRunScript() {
runScriptFrame(_ttmEnv._cdsFrame);
if (_ttmEnv._cdsDelay > 0) {
_nextExecMs = _thisFrameMs + _ttmEnv._cdsDelay;
+ debug(10, "CDS: This fame %d. Next frame will be on or after %d", _thisFrameMs, _nextExecMs);
_ttmEnv._cdsDelay = -1;
} else {
_nextExecMs = 0;
@@ -464,6 +468,37 @@ void Conversation::runScript() {
if (!_ttmScript)
return;
+ //
+ // If we have head data, run the script and don't return until it's
+ // finished - stop all other activity.
+ //
+ // If not, just run the script at the same time as it's supposed to animate over
+ // the top of the other game movements.
+ //
+ if (_haveHeadData)
+ runScriptExclusive();
+ else
+ runScriptStep();
+}
+
+void Conversation::runScriptStep() {
+ DgdsEngine *engine = DgdsEngine::getInstance();
+
+ if (_runTempFrame == -1)
+ _runTempFrame = 2;
+
+ if (!isScriptRunning())
+ return;
+
+ _thisFrameMs = engine->getThisFrameMs();
+ if (!_nextExecMs || _nextExecMs <= _thisFrameMs) {
+ incrementFrame();
+ checkAndRunScript();
+ }
+}
+
+
+void Conversation::runScriptExclusive() {
DgdsEngine *engine = DgdsEngine::getInstance();
engine->disableKeymapper();
diff --git a/engines/dgds/head.h b/engines/dgds/head.h
index 556accee2b9..92a158f7f73 100644
--- a/engines/dgds/head.h
+++ b/engines/dgds/head.h
@@ -139,7 +139,7 @@ public:
/** CDS data from Willy Beamish CD version talkie */
class Conversation {
public:
- Conversation() : _thisFrameMs(0), _nextExecMs(0), _runTempFrame(0), _tempFrameNum(0), _stopScript(false), _loadState(0),
+ Conversation() : _thisFrameMs(0), _nextExecMs(0), _runTempFrame(-1), _tempFrameNum(0), _stopScript(false), _loadState(0),
_dlgNum(-1), _dlgFileNum(-1), _subNum(-1), _finished(false), _haveHeadData(false) {}
~Conversation();
@@ -164,6 +164,9 @@ private:
bool isScriptRunning();
void pumpMessages();
+ void runScriptExclusive();
+ void runScriptStep();
+
int16 _runTempFrame;
int16 _tempFrameNum;
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 68c560a6ee0..1735f0749b6 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -125,6 +125,7 @@ void Image::loadAmigaScreen(Graphics::ManagedSurface &surface, Common::SeekableR
if (magic != MKTAG('B', 'A', 'S', 'H'))
error("Unexpected magic %08x in Amiga screen %s", magic, _filename.c_str());
+ error("Image::loadAmigaScreen: TODO - Finish this.");
/*
uint16 ysize = fileStream->readUint16BE();
uint16 xsize = surface.w;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 793eb2eff3c..42ab8fbb67d 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -37,6 +37,9 @@
#include "dgds/sound/music.h"
#include "dgds/sound/resource/sci_resource.h"
+#include "common/debug.h"
+
+
namespace Dgds {
static const uint16 SIGNAL_OFFSET = 0xffff;
@@ -465,7 +468,7 @@ void Sound::stopSfxByNum(int num) {
void Sound::playMusic(int num) {
int mappedNum = mapMusicNum(num);
debug(1, "Sound: Play music %d (-> %d, %s), have %d entries", num, mappedNum, _currentMusic.c_str(), _musicData.size());
- playPCSound(mappedNum, _musicData, Audio::Mixer::kMusicSoundType);
+ //playPCSound(mappedNum, _musicData, Audio::Mixer::kMusicSoundType);
}
void Sound::playMusicOrSFX(int num) {
@@ -519,8 +522,8 @@ void Sound::processInitSound(uint32 obj, const SoundData &data, Audio::Mixer::So
newSound->volume = MUSIC_VOLUME_DEFAULT;
newSound->reverb = -1; // initialize to SCI invalid, it'll be set correctly in soundInitSnd() below
- debug(10, "processInitSound: %08x number %d, loop %d, prio %d, vol %d", obj,
- obj, newSound->loop, newSound->priority, newSound->volume);
+ //debug(10, "processInitSound: %08x number %d, loop %d, prio %d, vol %d", obj,
+ // obj, newSound->loop, newSound->priority, newSound->volume);
initSoundResource(newSound, data, soundType);
diff --git a/engines/dgds/sound_raw.cpp b/engines/dgds/sound_raw.cpp
index f02b90c6c9a..2d4326f0dc4 100644
--- a/engines/dgds/sound_raw.cpp
+++ b/engines/dgds/sound_raw.cpp
@@ -37,6 +37,9 @@ void SoundRaw::load(const Common::String &filename) {
if (!fileStream)
error("SoundRaw::load: Couldn't get raw resource '%s'", filename.c_str());
+ _filename = filename;
+ _data.clear();
+
DgdsChunkReader chunk(fileStream);
while (chunk.readNextHeader(EX_RAW, filename)) {
chunk.readContent(_decompressor);
@@ -46,6 +49,9 @@ void SoundRaw::load(const Common::String &filename) {
break;
}
}
+
+ if (_data.empty())
+ warning("SoundRaw::load: Didn't load any data from '%s'", filename.c_str());
}
SoundRaw::~SoundRaw() {
@@ -58,6 +64,7 @@ void SoundRaw::loadFromStream(Common::SeekableReadStream *stream, int size) {
}
void SoundRaw::play() {
+ debug(10, "SoundRaw: Play %d bytes from %s", _data.size(), _filename.c_str());
Audio::Mixer *mixer = DgdsEngine::getInstance()->_mixer;
Audio::AudioStream *input = Audio::makeRawStream(_data.data(), _data.size(),
11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
diff --git a/engines/dgds/sound_raw.h b/engines/dgds/sound_raw.h
index e1e423a4824..b24b4a7e18f 100644
--- a/engines/dgds/sound_raw.h
+++ b/engines/dgds/sound_raw.h
@@ -46,13 +46,14 @@ public:
void stop();
bool isPlaying() const;
void loadFromStream(Common::SeekableReadStream *stream, int size);
- uint32 playedOffset() const;
+ uint32 playedOffset() const; //< Current offset into the sample in bytes, or 0xFFFFFFFF if not playing.
private:
Common::Array<byte> _data;
ResourceManager *_resourceMan;
Decompressor *_decompressor;
Audio::SoundHandle _handle;
+ Common::String _filename;
};
} // end namespace Dgds
Commit: 5299435d7d6f803d8ae0644b7316bebe978c70c4
https://github.com/scummvm/scummvm/commit/5299435d7d6f803d8ae0644b7316bebe978c70c4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Set higher priority on music than sfx
It was possible for music to stop when multiple sound effects were played at
once (eg, Willy Beamish FDD intro sequence when SFX 43 and 44 are played in
quick succession). This is a workaround for that issue.
Changed paths:
engines/dgds/sound.cpp
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 42ab8fbb67d..6c1e794947b 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -468,7 +468,7 @@ void Sound::stopSfxByNum(int num) {
void Sound::playMusic(int num) {
int mappedNum = mapMusicNum(num);
debug(1, "Sound: Play music %d (-> %d, %s), have %d entries", num, mappedNum, _currentMusic.c_str(), _musicData.size());
- //playPCSound(mappedNum, _musicData, Audio::Mixer::kMusicSoundType);
+ playPCSound(mappedNum, _musicData, Audio::Mixer::kMusicSoundType);
}
void Sound::playMusicOrSFX(int num) {
@@ -517,7 +517,7 @@ void Sound::processInitSound(uint32 obj, const SoundData &data, Audio::Mixer::So
newSound->resourceId = obj;
newSound->soundObj = obj;
newSound->loop = 0; // set in processPlaySound
- newSound->overridePriority = false;
+ newSound->overridePriority = true;
newSound->priority = 255;
newSound->volume = MUSIC_VOLUME_DEFAULT;
newSound->reverb = -1; // initialize to SCI invalid, it'll be set correctly in soundInitSnd() below
@@ -612,7 +612,8 @@ void Sound::processPlaySound(uint32 obj, bool playBed, bool restoring, const Sou
if (!musicSlot->overridePriority && resourcePriority != 0xFF) {
musicSlot->priority = resourcePriority;
} else {
- musicSlot->priority = 255;
+ // Set higher priority on music than sounds.
+ musicSlot->priority = (musicSlot->soundType == Audio::Mixer::kMusicSoundType ? 255 : 127);
}
// Reset hold when starting a new song. kDoSoundSetHold is always called after
Commit: af7636fb19ff7014d41f47ea6fb7a72b468dc140
https://github.com/scummvm/scummvm/commit/af7636fb19ff7014d41f47ea6fb7a72b468dc140
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Log segment name if available
Changed paths:
engines/dgds/ads.cpp
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index e06eb6d168f..6957e29f165 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -582,6 +582,7 @@ void ADSInterpreter::handleRandomOp(Common::SeekableReadStream *scr) {
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
+ const char *segname; // for debug messages
switch (code) {
case 0x0001:
@@ -776,7 +777,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
case 0xF000:
- debug(10, "ADS 0x%04x: set state 2, current idx (%d)", code, _adsData->_runningSegmentIdx);
+ debug(10, "ADS 0x%04x: set state 2, current segment idx (%d)", code, _adsData->_runningSegmentIdx);
if (_adsData->_runningSegmentIdx != -1)
_adsData->_state[_adsData->_runningSegmentIdx] = 2;
return false;
@@ -786,7 +787,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
int16 idx = _adsData->_runningSegmentIdx;
if (segment >= 0)
idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: set state 2, segment %d (idx %d)", code, segment, idx);
+ segname = _adsData->_tags.contains(segment) ? _adsData->_tags.getVal(segment).c_str() : "";
+ debug(10, "ADS 0x%04x: set state 2, seg %d idx %d %s", code, segment, idx, segname);
if (idx >= 0)
_adsData->_state[idx] = 2;
if (idx == _adsData->_runningSegmentIdx)
@@ -798,7 +800,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xF200: { // RUN_SCRIPT, 1 param
int16 segment = scr->readSint16LE();
int16 idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: run seg %d idx %d", code, segment, idx);
+ segname = _adsData->_tags.contains(segment) ? _adsData->_tags.getVal(segment).c_str() : "";
+ debug(10, "ADS 0x%04x: run seg %d idx %d %s", code, segment, idx, segname);
if (segment >= 0 && idx >= 0) {
int state = (_adsData->_state[idx] & 8) | 4;
_adsData->_state[idx] = state;
@@ -809,7 +812,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xF210: { // RESTART_SCRIPT, 1 param
int16 segment = scr->readSint16LE();
int16 idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: restart seg %d idx %d", code, segment, idx);
+ segname = _adsData->_tags.contains(segment) ? _adsData->_tags.getVal(segment).c_str() : "";
+ debug(10, "ADS 0x%04x: restart seg %d idx %d %s", code, segment, idx, segname);
if (segment >= 0 && idx >= 0) {
int state = (_adsData->_state[idx] & 8) | 3;
_adsData->_state[idx] = state;
@@ -933,7 +937,10 @@ bool ADSInterpreter::run() {
_adsData->_runningSegmentIdx = idx;
if (state == 1) {
_adsData->scr->seek(offset);
- debug(10, "ADS: Run segment %d idx %d/%d", segnum, idx, _adsData->_maxSegments);
+ const char *tag = "";
+ if (_adsData->_tags.contains(segnum))
+ tag = _adsData->_tags[segnum].c_str();
+ debug(10, "ADS: Run segment %d idx %d/%d %s", segnum, idx, _adsData->_maxSegments, tag);
runUntilBranchOpOrEnd();
}
}
Commit: a1f21c1a3ef8a08d48a6055c2b59b37a37b682d0
https://github.com/scummvm/scummvm/commit/a1f21c1a3ef8a08d48a6055c2b59b37a37b682d0
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Reset minutes added on scene change
All game variants do this, somehow I missed it before.
This fixes being able to leave the living room while running away from the
babysitter in Willy Beamish CD version.
Changed paths:
engines/dgds/clock.h
engines/dgds/dgds.cpp
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index 66c9c699491..625806088c8 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -66,6 +66,8 @@ public:
Common::String dump() const;
+ void resetMinsAdded() { _gameMinsAdded = 0; }
+
private:
uint32 _lastPlayTime;
uint32 _millis;
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 4fa3e1b881b..edeac06148b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -253,8 +253,8 @@ bool DgdsEngine::changeScene(int sceneNum) {
debug(1, "%s", _scene->dump("").c_str());
_scene->runEnterSceneOps();
-
_justChangedScene1 = true;
+ _clock.resetMinsAdded();
return true;
}
Commit: c81b25bf107ba57e978772ff5eefcc4c3eebeb6f
https://github.com/scummvm/scummvm/commit/c81b25bf107ba57e978772ff5eefcc4c3eebeb6f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Fix crash when sucking babysitter into vacuum cleaner
In Willy Beamish CD version, the dialog for this moment includes a global scene
op with no arguments. Ignore it as the original game does.
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index ce0a9a3b095..11be1ae75c8 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1959,8 +1959,12 @@ Common::String GDSScene::dump(const Common::String &indent) const {
}
void GDSScene::globalOps(const Common::Array<uint16> &args) {
- if (!args.size())
- error("GDSScene::globalOps: Empty arg list");
+ if (!args.size()) {
+ // This happens in Willy Beamish CD version when vacuuming
+ // up the babysitter (D50.DDS, dialog num 54)
+ warning("GDSScene::globalOps: Empty arg list");
+ return;
+ }
// The arg list should be a first value giving the count of operations,
// then 3 values for each op (num, opcode, val).
Commit: 3568ebb7c312fe9b8c7542b82793a74d1479a6ed
https://github.com/scummvm/scummvm/commit/3568ebb7c312fe9b8c7542b82793a74d1479a6ed
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Avoid possible invalid access on shutdown
Changed paths:
engines/dgds/sound/drivers/midi.cpp
diff --git a/engines/dgds/sound/drivers/midi.cpp b/engines/dgds/sound/drivers/midi.cpp
index 45692e38dfa..56f09a34f9d 100644
--- a/engines/dgds/sound/drivers/midi.cpp
+++ b/engines/dgds/sound/drivers/midi.cpp
@@ -406,6 +406,8 @@ void MidiPlayer_Midi::setReverb(int8 reverb) {
assert(reverb < kReverbConfigNr);
if (_hasReverb && _reverb != reverb) {
+ if (reverb < 0)
+ reverb = 0;
sendMt32SysEx(0x100001, SciSpan<const byte>(_reverbConfig[reverb], 3), true, true);
}
Commit: e205d41bd76e425ad351ec1356aafac9f7c8400d
https://github.com/scummvm/scummvm/commit/e205d41bd76e425ad351ec1356aafac9f7c8400d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Workaround for flashing bug over some Willy Beamish dialogs
Some willy beamish scenes contain hacky 20x20 type 4 dialogs to do some other
action. They appear over the main dialog.
Eg, CD version dlg file D25.DDS dialogs 102 and 103 - one of these is triggered
when Tiffany stands on the scales on day 3.
This causes a flashing artifact over the dialog even in the original. Work
around this issue by not drawing anything if the dialog is too small to
actually contain text.
Changed paths:
engines/dgds/dialog.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index e5c2251c79e..40d59000a24 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -346,11 +346,13 @@ void Dialog::drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
fillbgcolor = _bgColor;
}
+ const DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
if (stage == kDlgDrawStageBackground) {
//int radius = (midy * 5) / 4;
// This is not exactly the same as the original - might need some work to get pixel-perfect
- if (DgdsEngine::getInstance()->getGameId() != GID_HOC) {
+ // Beamish uses 20x20 dialogs of type 4 to have effects without actually drawing anything.
+ if (gameId != GID_HOC && (w > 20 || h > 20)) {
Common::Rect drawRect(x, y, x + w, y + h);
dst->drawRoundRect(drawRect, midy, fillbgcolor, true);
dst->drawRoundRect(drawRect, midy, fillcolor, false);
@@ -361,12 +363,17 @@ void Dialog::drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
drawFindSelectionTxtOffset();
} else {
assert(_state);
- if (DgdsEngine::getInstance()->getGameId() != GID_HOC) {
+ if (gameId != GID_HOC) {
_state->_loc = DgdsRect(x + midy, y + 1, w - midy, h - 1);
} else {
_state->_loc = DgdsRect(x, y, w, h);
fillcolor = 25; // ignore the color??
}
+
+ // WORKAROUND for the Willy Beamish dialogs which are 20x20 - these should not be drawn
+ if (gameId == GID_WILLY && (w <= 20 && h <= 20))
+ return;
+
drawForeground(dst, fillcolor, _str);
}
}
Commit: ef7e1f034a50e9d3d56a7bd709f328aee5a99c93
https://github.com/scummvm/scummvm/commit/ef7e1f034a50e9d3d56a7bd709f328aee5a99c93
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Fix dropping in inventory for Willy Beamish
Changed paths:
engines/dgds/inventory.cpp
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index ed21cf6d6ae..d6507f2f1b5 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -380,13 +380,17 @@ bool Inventory::isItemInInventory(const GameItem &item) {
}
void Inventory::mouseLDown(const Common::Point &pt) {
- RequestData &boxreq = _reqData._requests[0];
+ DgdsEngine *engine = DgdsEngine::getInstance();
- // Ignore this, and close on mouseup.
- if (!boxreq._rect.contains(pt))
+ // In willy beamish, might be clicking to drop a drag item - ignore.
+ GameItem *dragItem = engine->getScene()->getDragItem();
+ if (dragItem)
return;
- DgdsEngine *engine = DgdsEngine::getInstance();
+ // If clicking outside area, ignore mousedown - will close on mouseup.
+ RequestData &boxreq = _reqData._requests[0];
+ if (!boxreq._rect.contains(pt))
+ return;
if (engine->getScene()->hasVisibleDialog() || !_itemBox->containsPoint(pt)) {
return engine->getScene()->mouseLDown(pt);
Commit: 2d1298c457f12daa42a86fbdc0b8c3f4b673f70b
https://github.com/scummvm/scummvm/commit/2d1298c457f12daa42a86fbdc0b8c3f4b673f70b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Fix type 1 dialog rendering in Willy Beamish
Changed paths:
engines/dgds/dialog.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 40d59000a24..77eb23af8b2 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -87,16 +87,26 @@ void Dialog::drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
int w = _rect.width;
int h = _rect.height;
+ DgdsEngine *engine = DgdsEngine::getInstance();
if (stage == kDlgDrawStageBackground) {
- dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
- dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
+ dst->frameRect(Common::Rect(x, y, x + w, y + h), _bgColor);
+ if (engine->getGameId() != GID_WILLY) {
+ dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
+ } else {
+ dst->frameRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
+ dst->fillRect(Common::Rect(x + 2, y + 2, x + w - 2, y + h - 2), _bgColor);
+ }
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
drawFindSelectionTxtOffset();
} else {
- _state->_loc = DgdsRect(x + 3, y + 3, w - 6, h - 6);
- drawForeground(dst, _bgColor, _str);
+ if (engine->getGameId() != GID_WILLY)
+ _state->_loc = DgdsRect(x + 3, y + 3, w - 6, h - 6);
+ else
+ _state->_loc = DgdsRect(x + 5, y + 5, w - 10, h - 10);
+ byte txtCol = (engine->getGameId() == GID_WILLY) ? _fontColor : _bgColor;
+ drawForeground(dst, txtCol, _str);
}
}
Commit: 82430b334427d604b685c6d8753a37e191453fd9
https://github.com/scummvm/scummvm/commit/82430b334427d604b685c6d8753a37e191453fd9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Also fix dialog artifact on viewin blueprints
Changed paths:
engines/dgds/dialog.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 77eb23af8b2..ad5fcfd7672 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -362,7 +362,7 @@ void Dialog::drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
// This is not exactly the same as the original - might need some work to get pixel-perfect
// Beamish uses 20x20 dialogs of type 4 to have effects without actually drawing anything.
- if (gameId != GID_HOC && (w > 20 || h > 20)) {
+ if (gameId != GID_HOC && (w > 22 || h > 22)) {
Common::Rect drawRect(x, y, x + w, y + h);
dst->drawRoundRect(drawRect, midy, fillbgcolor, true);
dst->drawRoundRect(drawRect, midy, fillcolor, false);
Commit: 800f2911432abaf416a7867def9b23c2a669b4df
https://github.com/scummvm/scummvm/commit/800f2911432abaf416a7867def9b23c2a669b4df
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Hold open "head" dialogs with no sound until they are closed
This is used for the Willy Beamish blueprints. Don't close until needed if no
sound is present.
Changed paths:
engines/dgds/head.cpp
engines/dgds/scene.cpp
engines/dgds/sound_raw.h
diff --git a/engines/dgds/head.cpp b/engines/dgds/head.cpp
index 3f05003f74c..c1acec26f71 100644
--- a/engines/dgds/head.cpp
+++ b/engines/dgds/head.cpp
@@ -444,7 +444,7 @@ void Conversation::incrementFrame() {
bool Conversation::isScriptRunning() {
return (_ttmScript &&
- ((_ttmEnv._soundRaw && _ttmEnv._soundRaw->isPlaying())
+ ((_ttmEnv._soundRaw->isEmpty() || _ttmEnv._soundRaw->isPlaying())
||
(_ttmEnv._cdsFrame < _ttmEnv._totalFrames)
));
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 11be1ae75c8..86452af243c 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -2055,13 +2055,6 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
if (item._inSceneNum == currentScene && &item != engine->getScene()->getDragItem()) {
if (!(item._flags & kItemStateDragging)) {
// Dropped item.
- // Update the rect for the icon - Note: original doesn't do this,
- // but then the napent icon is offset??
- /*Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
- if (icon) {
- item._rect.width = MIN((int)icon->w, item._rect.width);
- item._rect.height = MIN((int)icon->h, item._rect.height);
- }*/
if (xoff + item._rect.width > maxx)
xoff = 20;
int yoff = SCREEN_HEIGHT - (item._rect.height + 2);
diff --git a/engines/dgds/sound_raw.h b/engines/dgds/sound_raw.h
index b24b4a7e18f..4cdfda616fe 100644
--- a/engines/dgds/sound_raw.h
+++ b/engines/dgds/sound_raw.h
@@ -45,6 +45,7 @@ public:
void play();
void stop();
bool isPlaying() const;
+ bool isEmpty() const { return _data.empty(); }
void loadFromStream(Common::SeekableReadStream *stream, int size);
uint32 playedOffset() const; //< Current offset into the sample in bytes, or 0xFFFFFFFF if not playing.
Commit: d93ff338458e0843212794b96a640efffc3425c9
https://github.com/scummvm/scummvm/commit/d93ff338458e0843212794b96a640efffc3425c9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2025-03-02T08:02:31+11:00
Commit Message:
DGDS: Small fixes for Willy Beamish head rendering
Correct offset to render location and flipping to be more like original.
Changed paths:
engines/dgds/head.cpp
engines/dgds/head.h
engines/dgds/scene.cpp
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/head.cpp b/engines/dgds/head.cpp
index c1acec26f71..64e5930a324 100644
--- a/engines/dgds/head.cpp
+++ b/engines/dgds/head.cpp
@@ -33,25 +33,30 @@
namespace Dgds {
+ImageFlipMode Conversation::_lastHeadFrameFlipMode = kImageFlipNone;
+int16 Conversation::_lastHeadFrameX = 0;
+int16 Conversation::_lastHeadFrameY = 0;
+
void TalkDataHead::drawHead(Graphics::ManagedSurface &dst, const TalkData &data) const {
uint drawtype = _drawType ? _drawType : 1;
// Use specific head shape if available (eg, in Willy Beamish), if not use talk data shape
Common::SharedPtr<Image> img = _shape;
if (!img)
img = data._shape;
- if (!img)
- return;
+
switch (drawtype) {
case 1:
- drawHeadType1(dst, *img);
+ if (img)
+ drawHeadType1(dst, *img);
break;
case 2:
- drawHeadType2(dst, *img);
+ if (img)
+ drawHeadType2(dst, *img);
break;
case 3:
if (DgdsEngine::getInstance()->getGameId() == GID_WILLY)
drawHeadType3Beamish(dst, data);
- else
+ else if (img)
drawHeadType3(dst, *img);
break;
default:
@@ -86,29 +91,39 @@ void TalkDataHead::drawHeadType2(Graphics::ManagedSurface &dst, const Image &img
void TalkDataHead::drawHeadType3Beamish(Graphics::ManagedSurface &dst, const TalkData &data) const {
const Common::Rect r = _rect.toCommonRect();
-
- // Note: only really need the 1px border here but just fill the box.
- dst.fillRect(r, 8);
-
Common::Rect fillRect(r);
fillRect.grow(-1);
- dst.fillRect(fillRect, _drawCol);
+
+ bool bgDone = false;
for (const auto &frame : _headFrames) {
int frameNo = frame._frameNo & 0x7fff;
bool useHeadShape = frame._frameNo & 0x8000;
Common::SharedPtr<Image> img = useHeadShape ? _shape : data._shape;
- if (!img || !img->isLoaded() || frameNo >= img->loadedFrameCount())
- continue;
+
+ if (!bgDone && img) {
+ dst.frameRect(r, 8);
+ dst.fillRect(fillRect, _drawCol);
+ bgDone = true;
+ }
ImageFlipMode flip = kImageFlipNone;
// Yes, the numerical values are reversed here (1 -> 2 and 2 -> 1).
// The head flip flags are reversed from the image draw flags.
if (frame._flipFlags & 1)
- flip = static_cast<ImageFlipMode>(flip & kImageFlipH);
+ flip = static_cast<ImageFlipMode>(flip | kImageFlipH);
if (frame._flipFlags & 2)
- flip = static_cast<ImageFlipMode>(flip & kImageFlipV);
+ flip = static_cast<ImageFlipMode>(flip | kImageFlipV);
+
+ // Slight hack from original CD version - record the flip mode and offset
+ // for this frame and use it for drawing the head sprites in the script.
+ Conversation::_lastHeadFrameFlipMode = flip;
+ Conversation::_lastHeadFrameX = frame._xoff;
+ Conversation::_lastHeadFrameY = frame._yoff;
+
+ if (!img || !img->isLoaded() || frameNo >= img->loadedFrameCount())
+ continue;
img->drawBitmap(frameNo, r.left + frame._xoff, r.top + frame._yoff, fillRect, dst);
}
@@ -237,12 +252,21 @@ void CDSTTMInterpreter::handleOperation(TTMEnviro &env_, TTMSeq &seq, uint16 op,
env._cdsDidStoreArea = true;
break;
}
- case 0xa500: // DRAW SPRITE: x,y,frameno,bmpno:int [-n,+n]
- case 0xa510: // DRAW SPRITE FLIP V x,y:int
- case 0xa520: // DRAW SPRITE FLIP H: x,y:int
- case 0xa530: // DRAW SPRITE FLIP HV: x,y,frameno,bmpno:int [-n,+n]
- doDrawSpriteOp(env, seq, op, count, ivals, env._xOff, env._yOff);
+ case 0xa500: // DRAW SPRITE: x,y,frameno,bmpno:int [-n,+n]
+ case 0xa510: // DRAW SPRITE FLIP V x,y:int
+ case 0xa520: // DRAW SPRITE FLIP H: x,y:int
+ case 0xa530: { // DRAW SPRITE FLIP HV: x,y,frameno,bmpno:int [-n,+n]
+ ImageFlipMode flip = Conversation::_lastHeadFrameFlipMode;
+ int16 x = ivals[0] + env._xOff;
+ int16 y = ivals[1] + env._yOff;
+ int16 frameno = ivals[2];
+ int16 bmpNo = ivals[3];
+ Common::SharedPtr<Image> img = env._scriptShapes[bmpNo];
+ if (flip & kImageFlipH)
+ x = env._xOff + (env._scriptShapes[0]->width(0) - ivals[0] - img->width(frameno));
+ img->drawBitmap(frameno, x, y, seq._drawWin, _vm->_compositionBuffer, flip, img->width(frameno), img->height(frameno));
break;
+ }
case 0xc220: // PLAY RAW SFX
if (env._cdsPlayedSound) // this is a one-shot op
break;
@@ -304,6 +328,9 @@ void Conversation::unloadData() {
_ttmEnv._soundRaw->stop();
_ttmEnv = CDSTTMEnviro();
_loadState = 0;
+ _lastHeadFrameFlipMode = kImageFlipNone;
+ _lastHeadFrameX = 0;
+ _lastHeadFrameY = 0;
}
void Conversation::clear() {
@@ -503,6 +530,8 @@ void Conversation::runScriptExclusive() {
engine->disableKeymapper();
_nextExecMs = 0;
+ _drawRect.x += _lastHeadFrameX;
+ _drawRect.y += _lastHeadFrameY;
_ttmEnv._xOff = _drawRect.x;
_ttmEnv._yOff = _drawRect.y;
_runTempFrame = 2;
@@ -545,10 +574,14 @@ void Conversation::runScriptExclusive() {
if (!_nextExecMs || _nextExecMs <= _thisFrameMs) {
incrementFrame();
- const Common::Rect r = _drawRect.toCommonRect();
-
checkAndRunScript();
+ // Redraw active dialogs eg to make sure thought bubble dots are
+ // over the moving heads
+ engine->getScene()->drawAndUpdateDialogs(&engine->_compositionBuffer);
+
+ Common::Rect r = _drawRect.toCommonRect();
+ r.clip(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT));
const byte *srcPtr = (const byte *)engine->_compositionBuffer.getPixels() + r.top * SCREEN_WIDTH + r.left;
g_system->copyRectToScreen(srcPtr, SCREEN_WIDTH, r.left, r.top, r.width(), r.height());
}
diff --git a/engines/dgds/head.h b/engines/dgds/head.h
index 92a158f7f73..1e1fdbc3c31 100644
--- a/engines/dgds/head.h
+++ b/engines/dgds/head.h
@@ -30,6 +30,7 @@
#include "graphics/managed_surface.h"
#include "dgds/dgds_rect.h"
+#include "dgds/image.h"
#include "dgds/ttm.h"
// Classes related to talking heads and conversations.
@@ -152,6 +153,10 @@ public:
DgdsRect _drawRect;
+ static enum ImageFlipMode _lastHeadFrameFlipMode;
+ static int16 _lastHeadFrameX;
+ static int16 _lastHeadFrameY;
+
private:
Common::SharedPtr<CDSTTMInterpreter> _ttmScript;
Common::Array<Common::SharedPtr<TTMSeq>> _ttmSeqs;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 86452af243c..e7fe44ed299 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -777,7 +777,8 @@ bool SDSScene::readTalkData(Common::SeekableReadStream *s, TalkData &dst) {
h._shape.reset(new Image(resMan, engine->getDecompressor()));
h._shape->loadBitmap(h._bmpFile);
} else {
- warning("Couldn't load talkdata %d head %d BMP: %s", dst._num, h._num, h._bmpFile.c_str());
+ // This is the default situation in Willy Beamish CD
+ debug("Couldn't load talkdata %d head %d BMP: %s", dst._num, h._num, h._bmpFile.c_str());
}
}
}
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 9288149582a..1c67861a08b 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -558,7 +558,7 @@ void TTMInterpreter::doDrawDialogForStrings(const TTMEnviro &env, const TTMSeq &
}
/// Handle 0xa5xx draw ops
-void TTMInterpreter::doDrawSpriteOp(const TTMEnviro &env, const TTMSeq &seq, uint16 op, byte count, const int16 *ivals, int16 xoff, int16 yoff) {
+void TTMInterpreter::doDrawSpriteOp(const TTMEnviro &env, const TTMSeq &seq, uint16 op, byte count, const int16 *ivals) {
int frameno;
int bmpNo;
int dstWidth = 0;
@@ -586,8 +586,8 @@ void TTMInterpreter::doDrawSpriteOp(const TTMEnviro &env, const TTMSeq &seq, uin
Common::SharedPtr<Image> img = env._scriptShapes[bmpNo];
if (img) {
- int x = ivals[0] + xoff;
- int y = ivals[1] + yoff;
+ int x = ivals[0];
+ int y = ivals[1];
// Use env offset if we are in gosub
if (_stackDepth > 0) {
x += env._xOff;
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index 7aa4ef206d4..81b7467c1e9 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -135,7 +135,7 @@ protected:
int16 doInitCreditScrollOp(const Image *img);
bool doCreditsScrollOp(const Image *img, int16 ygap, int16 ymax, int16 xoff, int16 measuredWidth, const Common::Rect &clipRect);
void doDrawDialogForStrings(const TTMEnviro &env, const TTMSeq &seq, int16 x, int16 y, int16 width, int16 height);
- void doDrawSpriteOp(const TTMEnviro &env, const TTMSeq &seq, uint16 op, byte count, const int16 *ivals, int16 xoff = 0, int16 yoff = 0);
+ void doDrawSpriteOp(const TTMEnviro &env, const TTMSeq &seq, uint16 op, byte count, const int16 *ivals);
void doFadeOutOp(int16 colorno, int16 ncolors, int16 targetcol, int16 speed);
void doFadeInOp(int16 colorno, int16 ncolors, int16 targetcol, int16 speed);
More information about the Scummvm-git-logs
mailing list